Blame | Last modification | View Log | RSS feed
package IEEERobotics.IOIOAI.VT;
import ioio.lib.api.IOIO;
import ioio.lib.api.IOIOFactory;
import ioio.lib.api.exception.ConnectionLostException;
import ioio.lib.api.exception.IncompatibilityException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import com.viewpagerindicator.TitlePageIndicator;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.view.ViewPager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.TableRow.LayoutParams;
public class IOIORoboticsActivity extends Activity {
// Static IOIO instance so other activities can access it
public static IOIO IOIOInstance_;
public static Context context_;
public static List<String> subTitles_ = new LinkedList<String>();
public static List<View> subViews_ = new LinkedList<View>();
// Connection and activity related variables
private static Boolean _connected = false;
private static Handler _handler = new Handler();
private Boolean _connectionReset = true;
private Thread _connectionMonitor;
private TextView _statusText;
private ProgressBar _statusProgressBar;
private LinearLayout _logLayout;
private ViewPagerAdapter _pageAdapter;
private ViewPager _pager;
private TitlePageIndicator _pageIndicator;
// Debugging stuff
private Boolean _debugMode;
private DebugCode _debuggingCode;
// AI stuff
private AICode _AICode;
// Motor Control class
private MotorControl _motorControl;
// Item ID for custom menu items
private static int menuToggleDebugMonitoring = Menu.FIRST;
private static int menuOpenSettings = Menu.FIRST+1;
private static int menuReset = Menu.FIRST+2;
private static int menuClearLog = Menu.FIRST+3;
private static int _connectionCheckInterval = 500; // in ms
// /** Called when the menu button is first pressed (creates the blank menu) */
// @Override
// public boolean onCreateOptionsMenu(Menu menu) {
// MenuInflater inflater = getMenuInflater();
// // Inflate a blank menu as we will populate it ourselves
// inflater.inflate(R.menu.mainmenu, menu);
// return true;
// }
/** Called when the menu button is pressed, populates the menu with options */
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// Clear existing menus and create a new one based on current state
menu.clear();
if (_debugMode)
menu.add(0, menuToggleDebugMonitoring, 0, "Turn On Robotics AI");
else
menu.add(0, menuToggleDebugMonitoring, 0, "Turn On Debug Mode");
if (_connected)
menu.add(0, menuReset, 0, "Reset IOIO Board");
else
menu.add(0, menuReset, 0, "Remove Debug Tabs");
menu.add(0, menuClearLog, 0, "Clear Logs");
menu.add(0, menuOpenSettings, 0, "Settings");
return super.onPrepareOptionsMenu(menu);
}
/** Handles what to do when a menu item is selected */
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// // Disable certain menu options if IOIO board is not connected
// if (item.getItemId() == menuReset &&
// !_connected) {
// Toast.makeText(this, "IOIO board not connected", Toast.LENGTH_SHORT).show();
// return true;
// };
// Otherwise handle menu selections
if (item.getItemId() == menuToggleDebugMonitoring) {
if (_debugMode) {
_debugMode = false;
logMessage("Operating mode changed to AI");
if (_connected)
hardReset();
} else {
_debugMode = true;
logMessage("Operating mode changed to Debug");
if (_connected)
hardReset();
}
return true;
} else if (item.getItemId() == menuOpenSettings) {
startActivity(new Intent(this, GlobalPreferenceActivity.class));
return true;
} else if (item.getItemId() == menuReset) {
if (_connected)
hardReset();
else {
if (_debuggingCode != null) {
removeDebugView();
}
}
return true;
} else if (item.getItemId() == menuClearLog) {
_logLayout.removeAllViews();
return true;
} else {
return super.onOptionsItemSelected(item);
}
}
/** Called when the application is started */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Grab the local context so other classes can use it to create views
context_ = this.getApplicationContext();
// Get local pointers to views
_pageAdapter = new ViewPagerAdapter(this);
_pager = (ViewPager)findViewById(R.id.viewpager);
_pageIndicator = (TitlePageIndicator)findViewById(R.id.indicator);
_statusText = (TextView)findViewById(R.id.statusText);
_statusProgressBar = (ProgressBar)findViewById(R.id.progressBar);
_pager.setAdapter(_pageAdapter);
_pageIndicator.setViewPager(_pager);
createLogView();
// Get default/saved debug mode
if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("pref_StartInDebug", true))
_debugMode = true;
else
_debugMode = false;
// Print out current debug status
if (_debugMode)
logMessage("Debug mode is currently on");
else
logMessage("Debug mode is currently off");
// Start connection monitoring thread for the IOIO board
connectToIOIOBoard();
}
/** Called when the application is stopped */
@Override
public void onDestroy() {
super.onDestroy();
connectionReset();
if (_debuggingCode != null) {
removeDebugView();
}
_connectionMonitor.interrupt();
IOIOInstance_.disconnect();
_connected = false;
}
/** Starts the thread that monitors the connection to the IOIO board */
private void connectToIOIOBoard() {
// Create a new thread to monitor the connection status to the IOIO board
_connectionMonitor = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
// Check if a new instance of IOIO needs to be created
// Reset is only triggered when a disconnect happens
if (_connectionReset) {
updateStatus("Waiting to connect to the IOIO board...");
toggleProgressOn();
IOIOInstance_ = IOIOFactory.create();
_connectionReset = false;
}
// Check if thread should keep running
if (Thread.currentThread().isInterrupted()) {
break;
}
// Attempt to connect to the IOIO board
// If the board was disconnected, ConnectionLostException is thrown while waiting
IOIOInstance_.waitForConnect();
// Do stuff when the first connection to the board is made
if (!_connected) {
updateStatus("Connected to the IOIO board");
Thread.sleep(200);
connectionSuccess();
}
_connected = true;
toggleProgressOff();
Thread.sleep(_connectionCheckInterval);
} catch (ConnectionLostException e) {
// Reset the connection so reconnection attempts can be made
_connected = false;
_connectionReset = true;
connectionReset();
updateStatus("Connection to the IOIO board has be lost");
} catch (IncompatibilityException e) {
// Throw error and quit
_connected = false;
_connectionReset = true;
connectionReset();
updateStatus("Connected IOIO board is incompatible");
} catch (InterruptedException e) {
break;
}
}
}
});
_connectionMonitor.start();
}
/** Called when the connection to the IOIO board succeeds */
private void connectionSuccess() {
_handler.post(new Runnable() {
@Override
public void run() {
// If debug mode is enabled, run the debug code to create graphs
if (_debugMode) {
startDebugMode();
} else {
startAIMode();
}
}
});
}
/** Called when the connection to the IOIO board has been reset */
private void connectionReset() {
_handler.post(new Runnable() {
@Override
public void run() {
// If the debugger code was running, stop the updating thread
if (_debuggingCode != null)
_debuggingCode.stopPollingThread();
if (_AICode != null)
_AICode.stopPollingThread();
if (_motorControl != null) {
_motorControl.disconnect();
}
}
});
}
/** Creates the first layout for the ViewPager */
private void createLogView() {
if (subTitles_.contains("Logger")) {
removeView(subViews_.get(subTitles_.indexOf("Logger")));
subTitles_.remove("Logger");
}
_logLayout = new LinearLayout(this);
_logLayout.setOrientation(LinearLayout.VERTICAL);
_logLayout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
ScrollView scroller = new ScrollView(this);
scroller.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
scroller.addView(_logLayout);
addView("Logger", scroller);
}
/** Creates a new page in the ViewPager */
private void addView(String name, View view) {
// Add the view and label to the lists
subTitles_.add(subTitles_.size(), name);
subViews_.add(subViews_.size(), view);
// Update the screen with the new views
_pageAdapter.notifyDataSetChanged();
_pageIndicator.notifyDataSetChanged();
}
/** Removes a page in the ViewPager */
private void removeView(View view) {
if (subViews_.contains(view)) {
// Change the main view to the first one (logger)
_pager.setCurrentItem(0);
// Remove the view and label from the lists
subTitles_.remove(subViews_.indexOf(view));
subViews_.remove(view);
// Update the screen with the new views
_pageAdapter.notifyDataSetChanged();
_pageIndicator.notifyDataSetChanged();
}
}
/** Start point for code to execute in Debug Mode */
private void startDebugMode() {
// Run debug code to create graphs
logMessage("Executing Debug Mode");
// On first run, create inputs and views
if (_debuggingCode == null) {
_debuggingCode = new DebugCode(this);
addView("Graphs", _debuggingCode.getView());
}
if (_motorControl == null) {
_motorControl = new MotorControl(this);
addView("Motor", _motorControl.getDebugView());
}
_debuggingCode.Run();
// _motorControl.Run();
}
/** Call to stop the debug code and remove all associated views */
private void removeDebugView() {
removeView(_debuggingCode.getView());
removeView(_motorControl.getDebugView());
if (_debuggingCode != null) {
// _debuggingCode.stopPollingThread();
_debuggingCode = null;
}
if (_motorControl != null) {
_motorControl = null;
}
}
/** Start point for code to execut`e in AI Mode */
private void startAIMode() {
// Remove the debug views if they exist
if (_debuggingCode != null) {
removeDebugView();
}
logMessage("Executing AI Mode");
_AICode = new AICode(this);
_AICode.Run();
}
/**
* A hard reset is exactly like physically powering off the IOIO
* board and powering it back on. As a result, the connection
* with the IOIO will drop and the IOIO instance will become
* disconnected and unusable. The board will perform a full reboot,
* including going through the bootloader sequence, i.e. an attempt
* to update the board's firmware will be made.
*/
private void hardReset() {
try {
IOIOInstance_.hardReset();
} catch (ConnectionLostException e) {
_connected = false;
_connectionReset = true;
connectionReset();
updateStatus("Hard reset executed on the IOIO board");
}
}
/** Sets the status TextView to the provided message */
private void updateStatus(final String message) {
_handler.post(new Runnable() {
@Override
public void run() {
logMessage(message);
_statusText.setText("Status: " + message);
}
});
}
/** Appends the provided message to the beginning of the log TextView */
public void logMessage(final String message) {
_handler.post(new Runnable() {
@Override
public void run() {
// Get the current time
SimpleDateFormat dateFormat = new SimpleDateFormat("[HH:mm:ss]");
Date now = new Date();
String currentTime = dateFormat.format(now);
// Log message with the current time appended to the front
String msg = currentTime + " " + message;
TextView tv = new TextView(context_);
tv.setText(msg);
_logLayout.addView(tv,0);
}
});
}
/** Returns the current connection state */
public Boolean getConnected() {
return _connected;
}
/** Toggles the visibility of the status ProgressBar */
private void toggleProgressOn() {
_handler.post(new Runnable() {
@Override
public void run() {
_statusProgressBar.setVisibility(View.VISIBLE);
}
});
}
/** Toggles the visibility of the status ProgressBar */
private void toggleProgressOff() {
_handler.post(new Runnable() {
@Override
public void run() {
_statusProgressBar.setVisibility(View.GONE);
}
});
}
}