Subversion Repositories Code-Repo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
103 Kevin 1
package IEEERobotics.IOIOAI.VT;
2
 
3
import ioio.lib.api.IOIO;
4
import ioio.lib.api.IOIOFactory;
5
import ioio.lib.api.exception.ConnectionLostException;
6
import ioio.lib.api.exception.IncompatibilityException;
7
 
8
import java.text.SimpleDateFormat;
9
import java.util.Date;
10
import java.util.LinkedList;
11
import java.util.List;
12
import com.viewpagerindicator.TitlePageIndicator;
13
import android.app.Activity;
14
import android.content.Context;
15
import android.content.Intent;
16
import android.os.Bundle;
17
import android.os.Handler;
18
import android.preference.PreferenceManager;
19
import android.support.v4.view.ViewPager;
20
import android.view.Menu;
21
import android.view.MenuItem;
22
import android.view.View;
23
import android.widget.LinearLayout;
24
import android.widget.ProgressBar;
25
import android.widget.ScrollView;
26
import android.widget.TextView;
27
import android.widget.TableRow.LayoutParams;
28
 
29
public class IOIORoboticsActivity extends Activity {
30
	// Static IOIO instance so other activities can access it
31
	public static IOIO IOIOInstance_;
32
	public static Context context_;
33
 
34
	public static List<String> subTitles_ = new LinkedList<String>();
35
	public static List<View> subViews_ = new LinkedList<View>();
36
 
37
	// Connection and activity related variables
38
	private static Boolean _connected = false;
39
	private static Handler _handler = new Handler();
40
	private Boolean _connectionReset = true;
41
	private Thread _connectionMonitor;
42
 
43
	private TextView _statusText;
44
	private ProgressBar _statusProgressBar;
45
	private LinearLayout _logLayout;
46
 
47
	private ViewPagerAdapter _pageAdapter;
48
	private ViewPager _pager;
49
	private TitlePageIndicator _pageIndicator;
50
 
51
	// Debugging stuff
52
	private Boolean _debugMode;
53
	private DebugCode _debuggingCode;
54
 
55
	// AI stuff
56
	private AICode _AICode;
57
 
58
	// Motor Control class
59
	private MotorControl _motorControl;
60
 
61
	// Item ID for custom menu items
62
	private static int menuToggleDebugMonitoring = Menu.FIRST;
63
	private static int menuOpenSettings = Menu.FIRST+1;
64
	private static int menuReset = Menu.FIRST+2;
65
	private static int menuClearLog = Menu.FIRST+3;
66
 
67
	private static int _connectionCheckInterval = 500;	// in ms
68
 
69
//	/** Called when the menu button is first pressed (creates the blank menu) */
70
//	@Override
71
//	public boolean onCreateOptionsMenu(Menu menu) {
72
//		MenuInflater inflater = getMenuInflater();
73
//		// Inflate a blank menu as we will populate it ourselves
74
//	    inflater.inflate(R.menu.mainmenu, menu);
75
//	    return true;
76
//	}
77
 
78
	/** Called when the menu button is pressed, populates the menu with options */
79
	@Override
80
	public boolean onPrepareOptionsMenu(Menu menu) {
81
		// Clear existing menus and create a new one based on current state
82
		menu.clear();
83
 
84
		if (_debugMode)
85
			menu.add(0, menuToggleDebugMonitoring, 0, "Turn On Robotics AI");
86
		else
87
			menu.add(0, menuToggleDebugMonitoring, 0, "Turn On Debug Mode");
88
 
89
		if (_connected)
90
			menu.add(0, menuReset, 0, "Reset IOIO Board");
91
		else
92
			menu.add(0, menuReset, 0, "Remove Debug Tabs");
93
 
94
		menu.add(0, menuClearLog, 0, "Clear Logs");
95
		menu.add(0, menuOpenSettings, 0, "Settings");
96
 
97
		return super.onPrepareOptionsMenu(menu);
98
	}
99
 
100
	/** Handles what to do when a menu item is selected */
101
	@Override
102
	public boolean onOptionsItemSelected(MenuItem item) {
103
//		// Disable certain menu options if IOIO board is not connected
104
//		if (item.getItemId() == menuReset && 
105
//				!_connected) {
106
//			Toast.makeText(this, "IOIO board not connected", Toast.LENGTH_SHORT).show();
107
//			return true;
108
//		};
109
 
110
		// Otherwise handle menu selections
111
		if (item.getItemId() == menuToggleDebugMonitoring) {
112
			if (_debugMode) {
113
				_debugMode = false;
114
				logMessage("Operating mode changed to AI");
115
				if (_connected)
116
					hardReset();
117
			} else {
118
				_debugMode = true;
119
				logMessage("Operating mode changed to Debug");
120
				if (_connected)
121
					hardReset();
122
			}
123
			return true;
124
		} else if (item.getItemId() == menuOpenSettings) {
125
			startActivity(new Intent(this, GlobalPreferenceActivity.class));
126
			return true;
127
		} else if (item.getItemId() == menuReset) {
128
			if (_connected)
129
				hardReset();
130
			else {
131
				if (_debuggingCode != null) {
132
					removeDebugView();
133
				}
134
			}
135
			return true;
136
		} else if (item.getItemId() == menuClearLog) {
137
			_logLayout.removeAllViews();
138
			return true;
139
		} else {
140
			return super.onOptionsItemSelected(item);
141
		}
142
	}
143
 
144
	/** Called when the application is started */
145
    @Override
146
    public void onCreate(Bundle savedInstanceState) {
147
        super.onCreate(savedInstanceState);
148
        setContentView(R.layout.main);
149
 
150
        // Grab the local context so other classes can use it to create views
151
        context_ = this.getApplicationContext();
152
 
153
        // Get local pointers to views
154
        _pageAdapter = new ViewPagerAdapter(this);
155
        _pager = (ViewPager)findViewById(R.id.viewpager);
156
        _pageIndicator = (TitlePageIndicator)findViewById(R.id.indicator);
157
        _statusText = (TextView)findViewById(R.id.statusText);
158
        _statusProgressBar = (ProgressBar)findViewById(R.id.progressBar);
159
 
160
        _pager.setAdapter(_pageAdapter);
161
        _pageIndicator.setViewPager(_pager);
162
 
163
        createLogView();
164
 
165
        // Get default/saved debug mode
166
        if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("pref_StartInDebug", true))
167
        	_debugMode = true;
168
        else
169
        	_debugMode = false;
170
 
171
        // Print out current debug status
172
        if (_debugMode)
173
        	logMessage("Debug mode is currently on");
174
        else
175
        	logMessage("Debug mode is currently off");
176
 
177
        // Start connection monitoring thread for the IOIO board
178
        connectToIOIOBoard();        
179
    }
180
 
181
    /** Called when the application is stopped */
182
	@Override
183
	public void onDestroy() {
184
		super.onDestroy();
185
		connectionReset();
186
		if (_debuggingCode != null) {
187
			removeDebugView();
188
		}
189
		_connectionMonitor.interrupt();
190
		IOIOInstance_.disconnect();
191
		_connected = false;
192
	}
193
 
194
	/** Starts the thread that monitors the connection to the IOIO board */
195
    private void connectToIOIOBoard() {
196
    	// Create a new thread to monitor the connection status to the IOIO board
197
    	_connectionMonitor = new Thread(new Runnable() {
198
			@Override
199
			public void run() {
200
				while (true) {
201
					try {
202
						// Check if a new instance of IOIO needs to be created
203
						// Reset is only triggered when a disconnect happens
204
						if (_connectionReset) {
205
							updateStatus("Waiting to connect to the IOIO board...");
206
							toggleProgressOn();
207
							IOIOInstance_ = IOIOFactory.create();
208
							_connectionReset = false;
209
						}
210
						// Check if thread should keep running
211
						if (Thread.currentThread().isInterrupted()) {
212
							break;
213
						}
214
						// Attempt to connect to the IOIO board
215
						// If the board was disconnected, ConnectionLostException is thrown while waiting
216
						IOIOInstance_.waitForConnect();
217
						// Do stuff when the first connection to the board is made
218
						if (!_connected) {
219
							updateStatus("Connected to the IOIO board");
220
							Thread.sleep(200);
221
							connectionSuccess();
222
						}
223
						_connected = true;
224
						toggleProgressOff();
225
						Thread.sleep(_connectionCheckInterval);
226
					} catch (ConnectionLostException e) {
227
						// Reset the connection so reconnection attempts can be made
228
						_connected = false;
229
						_connectionReset = true;
230
						connectionReset();
231
						updateStatus("Connection to the IOIO board has be lost");
232
					} catch (IncompatibilityException e) {
233
						// Throw error and quit
234
						_connected = false;
235
						_connectionReset = true;
236
						connectionReset();
237
						updateStatus("Connected IOIO board is incompatible");
238
					} catch (InterruptedException e) {
239
						break;
240
					}
241
				}
242
			}
243
		});
244
    	_connectionMonitor.start();
245
    }
246
 
247
    /** Called when the connection to the IOIO board succeeds */
248
    private void connectionSuccess() {
249
    	_handler.post(new Runnable() {
250
			@Override
251
			public void run() {
252
				// If debug mode is enabled, run the debug code to create graphs
253
				if (_debugMode) {
254
		    		startDebugMode();
255
		    	} else {
256
		    		startAIMode();
257
		    	}
258
			}
259
		});
260
    }
261
 
262
    /** Called when the connection to the IOIO board has been reset */
263
    private void connectionReset() {
264
    	_handler.post(new Runnable() {
265
			@Override
266
			public void run() {
267
				// If the debugger code was running, stop the updating thread
268
				if (_debuggingCode != null)
269
					_debuggingCode.stopPollingThread();
270
				if (_AICode != null)
271
					_AICode.stopPollingThread();
272
				if (_motorControl != null) {
273
		    		_motorControl.disconnect();
274
		    	}
275
			}
276
		});
277
    }
278
 
279
    /** Creates the first layout for the ViewPager */
280
    private void createLogView() {
281
    	if (subTitles_.contains("Logger")) {
282
    		removeView(subViews_.get(subTitles_.indexOf("Logger")));
283
    		subTitles_.remove("Logger");
284
    	}
285
 
286
		_logLayout = new LinearLayout(this);
287
		_logLayout.setOrientation(LinearLayout.VERTICAL);
288
		_logLayout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
289
 
290
		ScrollView scroller = new ScrollView(this);
291
		scroller.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
292
		scroller.addView(_logLayout);
293
 
294
		addView("Logger", scroller);
295
	}
296
 
297
    /** Creates a new page in the ViewPager */
298
	private void addView(String name, View view) {
299
		// Add the view and label to the lists
300
		subTitles_.add(subTitles_.size(), name);
301
		subViews_.add(subViews_.size(), view);
302
 
303
		// Update the screen with the new views
304
		_pageAdapter.notifyDataSetChanged();
305
		_pageIndicator.notifyDataSetChanged();
306
	}
307
 
308
	/** Removes a page in the ViewPager */
309
	private void removeView(View view) {
310
		if (subViews_.contains(view)) {
311
			// Change the main view to the first one (logger)
312
			_pager.setCurrentItem(0);
313
 
314
			// Remove the view and label from the lists
315
	    	subTitles_.remove(subViews_.indexOf(view));
316
			subViews_.remove(view);
317
 
318
			// Update the screen with the new views
319
			_pageAdapter.notifyDataSetChanged();
320
			_pageIndicator.notifyDataSetChanged();
321
		}
322
	}
323
 
324
	/** Start point for code to execute in Debug Mode */
325
    private void startDebugMode() {
326
    	// Run debug code to create graphs
327
		logMessage("Executing Debug Mode");
328
 
329
		// On first run, create inputs and views
330
		if (_debuggingCode == null) {
331
			_debuggingCode = new DebugCode(this);
332
			addView("Graphs", _debuggingCode.getView());
333
		}
334
		if (_motorControl == null) {
335
			_motorControl = new MotorControl(this);
336
			addView("Motor", _motorControl.getDebugView());
337
		}
338
 
339
		_debuggingCode.Run();
340
//		_motorControl.Run();
341
    }
342
 
343
    /** Call to stop the debug code and remove all associated views */
344
    private void removeDebugView() {
345
    	removeView(_debuggingCode.getView());
346
    	removeView(_motorControl.getDebugView());
347
 
348
    	if (_debuggingCode != null) {
349
//			_debuggingCode.stopPollingThread();
350
    		_debuggingCode = null;
351
    	}
352
    	if (_motorControl != null) {
353
			_motorControl = null;
354
		}
355
    }
356
 
357
    /** Start point for code to execut`e in AI Mode */
358
    private void startAIMode() {
359
    	// Remove the debug views if they exist
360
    	if (_debuggingCode != null) {
361
    		removeDebugView();
362
    	}
363
 
364
    	logMessage("Executing AI Mode");
365
    	_AICode = new AICode(this);
366
    	_AICode.Run();
367
    }
368
 
369
    /**
370
     * A hard reset is exactly like physically powering off the IOIO 
371
     * board and powering it back on. As a result, the connection 
372
     * with the IOIO will drop and the IOIO instance will become 
373
     * disconnected and unusable. The board will perform a full reboot, 
374
     * including going through the bootloader sequence, i.e. an attempt 
375
     * to update the board's firmware will be made.
376
     */
377
    private void hardReset() {
378
		try {
379
			IOIOInstance_.hardReset();
380
		} catch (ConnectionLostException e) {
381
			_connected = false;
382
			_connectionReset = true;
383
			connectionReset();
384
			updateStatus("Hard reset executed on the IOIO board");
385
		}
386
    }
387
 
388
    /** Sets the status TextView to the provided message */
389
    private void updateStatus(final String message) {
390
    	_handler.post(new Runnable() {
391
			@Override
392
			public void run() {
393
				logMessage(message);
394
				_statusText.setText("Status: " + message);
395
			}
396
		});
397
    }
398
 
399
    /** Appends the provided message to the beginning of the log TextView */
400
    public void logMessage(final String message) {
401
    	_handler.post(new Runnable() {
402
			@Override
403
			public void run() {
404
				// Get the current time
405
				SimpleDateFormat dateFormat = new SimpleDateFormat("[HH:mm:ss]");
406
				Date now = new Date();
407
				String currentTime = dateFormat.format(now);
408
				// Log message with the current time appended to the front
409
				String msg = currentTime + " " + message;
410
				TextView tv = new TextView(context_);
411
				tv.setText(msg);
412
				_logLayout.addView(tv,0);
413
			}
414
		});
415
    }
416
 
417
    /** Returns the current connection state */
418
    public Boolean getConnected() {
419
    	return _connected;
420
    }
421
 
422
    /** Toggles the visibility of the status ProgressBar */
423
    private void toggleProgressOn() {
424
    	_handler.post(new Runnable() {
425
			@Override
426
			public void run() {
427
				_statusProgressBar.setVisibility(View.VISIBLE);
428
			}
429
		});
430
    }
431
 
432
    /** Toggles the visibility of the status ProgressBar */
433
    private void toggleProgressOff() {
434
    	_handler.post(new Runnable() {
435
			@Override
436
			public void run() {
437
				_statusProgressBar.setVisibility(View.GONE);
438
			}
439
		});
440
    }
441
}