diff --git a/.gitignore b/.gitignore
index 39fb081..2c41655 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,8 @@
*.iml
.gradle
/local.properties
-/.idea/workspace.xml
-/.idea/libraries
.DS_Store
/build
/captures
.externalNativeBuild
+.idea
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
deleted file mode 100644
index 96cc43e..0000000
--- a/.idea/compiler.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
deleted file mode 100644
index e7bedf3..0000000
--- a/.idea/copyright/profiles_settings.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
deleted file mode 100644
index 97626ba..0000000
--- a/.idea/encodings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
deleted file mode 100644
index 7ac24c7..0000000
--- a/.idea/gradle.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 5d19981..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..0595d93
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,23 @@
+language: android
+jdk: oraclejdk8
+
+android:
+ components:
+ - tools
+ - platform-tools
+ - build-tools-25.0.0
+ - android-25
+ - extra-android-m2repository
+ - sys-img-armeabi-v7a-android-16
+
+before_install:
+ - mkdir "$ANDROID_HOME/licenses" || true
+ - echo -e "\n8933bad161af4178b1185d1a37fbf41ea5269c55" > "$ANDROID_HOME/licenses/android-sdk-license"
+ - echo -e "\n84831b9409646a918e30573bab4c9c91346d8abd" > "$ANDROID_HOME/licenses/android-sdk-preview-license"
+
+before_script:
+ - echo no | android create avd --force -n test -t android-16 --abi armeabi-v7a
+ - emulator -avd test -no-skin -no-audio -no-window &
+ - android-wait-for-emulator
+ - sleep 10
+ - adb shell input keyevent 82
\ No newline at end of file
diff --git a/README.md b/README.md
index d42bfc7..61c27e7 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,11 @@
-#  Android RC Car(In Progress)
+**BlueBot**
+
+A **Blue**tooth Android app that controls an Arduino based Ro**bot**.
+#  Android BlueBot
## Wiki Contents
1. [**Assemble the RC Car**](https://github.com/fouliex/AndroidRcCar/wiki/Assemble-the-RC-Car)
-2. [**DC Motor Construction**](https://github.com/fouliex/AndroidRcCar/wiki/RC-DC-Motor-Construction)
\ No newline at end of file
+2. [**DC Motor Construction**](https://github.com/fouliex/AndroidRcCar/wiki/RC-DC-Motor-Construction)
+
+You can get the Arduino Smart Robot Car Kit from [**Amazon**](https://www.amazon.com/gp/product/B01DPH0SWY/ref=oh_aui_detailpage_o00_s00?ie=UTF8&psc=1)
+
+[](https://travis-ci.org/fouliex/BlueBot)
diff --git a/app/build.gradle b/app/build.gradle
index f0589e1..9030c2b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -2,9 +2,9 @@ apply plugin: 'com.android.application'
android {
compileSdkVersion 25
- buildToolsVersion "25.0.2"
+ buildToolsVersion "25.0.0"
defaultConfig {
- applicationId "com.car.rc.example.fouliex.rccar"
+ applicationId "com.bluebot"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
@@ -19,13 +19,21 @@ android {
}
}
+ext {
+ supportVersion = '25.3.1'
+ espressoVersion = '2.2.2'
+}
dependencies {
- compile fileTree(dir: 'libs', include: ['*.jar'])
- androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
+ compile fileTree(include: ['*.jar'], dir: 'libs')
+ compile "com.android.support:appcompat-v7:$supportVersion"
+ compile "com.android.support.constraint:constraint-layout:1.0.2"
+ compile "com.akexorcist:bluetoothspp:1.0.0"
+ compile "com.android.support:support-v4:$supportVersion"
+ compile project(':bluebotruntimelib')
+ testCompile 'junit:junit:4.12'
+ androidTestCompile "com.android.support:support-v4:$supportVersion"
+ androidTestCompile("com.android.support.test.espresso:espresso-core:$espressoVersion", {
exclude group: 'com.android.support', module: 'support-annotations'
})
- compile 'com.android.support:appcompat-v7:25.2.0'
- compile 'com.android.support.constraint:constraint-layout:1.0.2'
- compile 'com.akexorcist:bluetoothspp:1.0.0'
- testCompile 'junit:junit:4.12'
+ androidTestCompile "com.android.support.test.espresso:espresso-intents:$espressoVersion"
}
diff --git a/app/src/androidTest/java/com/bluebot/MainActivitySpec.java b/app/src/androidTest/java/com/bluebot/MainActivitySpec.java
new file mode 100644
index 0000000..24e7539
--- /dev/null
+++ b/app/src/androidTest/java/com/bluebot/MainActivitySpec.java
@@ -0,0 +1,56 @@
+package com.bluebot;
+
+import android.support.test.espresso.intent.Intents;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.bluebot.droid.ide.BlueBotIDEActivity;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.intent.Intents.intended;
+import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
+import static android.support.test.espresso.matcher.ViewMatchers.isClickable;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
+/**
+ * Created by Clifton Craig on 4/12/17.
+ */
+@Ignore
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class MainActivitySpec {
+ @Rule
+ public ActivityTestRule activityTestRule = new ActivityTestRule<>(MainActivity.class);
+
+ @Before
+ public void setUp() throws Exception {
+ Intents.init();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ Intents.release();
+
+ }
+
+ @Test
+ public void shouldHaveAnIDEButton() throws Exception {
+ onView(withText("IDE")).check(matches(isClickable()));
+ }
+
+ @Test
+ public void clickingTheIDEButtonShouldLaunchTheIDEActivity() throws Exception {
+ onView(withText("IDE")).perform(click());
+ intended(hasComponent(BlueBotIDEActivity.class.getName()));
+ }
+}
diff --git a/app/src/androidTest/java/com/bluebot/droid/ide/BlueBotIDESpec.java b/app/src/androidTest/java/com/bluebot/droid/ide/BlueBotIDESpec.java
new file mode 100644
index 0000000..7b21b5b
--- /dev/null
+++ b/app/src/androidTest/java/com/bluebot/droid/ide/BlueBotIDESpec.java
@@ -0,0 +1,132 @@
+package com.bluebot.droid.ide;
+
+import android.support.test.espresso.action.ViewActions;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.bluebot.ui.RequestProcessor;
+import com.bluebot.ui.ResponseHandler;
+import com.bluebot.ui.UIRequestTypes;
+import com.bluebot.ui.UIResponseType;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Created by Clifton Craig on 4/8/17.
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class BlueBotIDESpec implements RequestProcessor {
+ @Rule
+ public final ActivityTestRule activityTestRule = new ActivityTestRule<>(BlueBotIDEActivity.class);
+ private String dataPassedToRequestProcessor;
+ private String requestTypePassedToRequestProcessor;
+ private ResponseHandler responseHandlerPassedToBind;
+
+ @Test
+ public void shouldIncludeWindowTitleOnScreen() {
+ onView(withText("BlueBot IDE")).check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void shouldHaveAPlaceToEnterCode() throws Exception {
+ onView(withContentDescription("Code Entry")).check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void shouldHaveAButtonToRunCode() throws Exception {
+ onView(withContentDescription("Run")).check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void theIDEShouldDependOnARequestProcessor() throws Exception {
+ activityTestRule.getActivity().setRequestProcessor(this);
+ }
+
+ @Override
+ public void bind(ResponseHandler responseHandler) {
+ this.responseHandlerPassedToBind = responseHandler;
+ }
+
+ @Test
+ public void theIDEActivityShouldBindTheRequestProcessorWhenSet() throws Exception {
+ activityTestRule.getActivity().setRequestProcessor(this);
+ assertNotNull(responseHandlerPassedToBind);
+ }
+
+ @Test
+ public void boundResponseHandlerShouldShowErrorMEssageInTheUI() throws Exception {
+ //Given
+ theIDEActivityShouldBindTheRequestProcessorWhenSet();
+ //When we have an error response
+ Map response = new HashMap() {{
+ put(UIResponseType.ERROR, "Stupidity Error!");
+ }};
+ //And we send it to the responseHandler...
+ responseHandlerPassedToBind.responseForRequest(UIRequestTypes.EXECUTE_CODE, response);
+ //Then the UI should light up with the error
+ onView(withContentDescription("Error message")).check(matches(isDisplayed()));
+ }
+
+ @Test
+ public void boundResponseHandlerShouldNotShowErrorOnSuccess() throws Exception {
+ //Given
+ theIDEActivityShouldBindTheRequestProcessorWhenSet();
+ //When we have an error response
+ Map response = new HashMap() {{
+ put(UIResponseType.SUCCESS, "");
+ }};
+ //And we send it to the responseHandler...
+ responseHandlerPassedToBind.responseForRequest(UIRequestTypes.EXECUTE_CODE, response);
+ //Then the UI should **NOT** light up with the error
+ onView(withContentDescription("Error message")).check(matches(not(isDisplayed())));
+ }
+
+ @Test
+ public void theIDEActivityShouldNotShowErrorMessagesByDefault() throws Exception {
+ onView(withContentDescription("Error message")).check(matches(not(isDisplayed())));
+ }
+
+ @Override
+ public void processRequest(String requestType, Object data) {
+ this.requestTypePassedToRequestProcessor = requestType;
+ this.dataPassedToRequestProcessor = String.valueOf(data);
+ }
+
+ @Test
+ public void enteringCodeAndPressingRunShouldInvokeCodeExecutor() throws Exception {
+ //Given this test case pretends to be a code executor
+ activityTestRule.getActivity().setRequestProcessor(this);
+ //And some BlueBot code...
+ String someBlueBotCode = "wake up bot\n" +
+ "spin around\n" +
+ "say hello";
+
+ //When we type the code in...
+ onView(withContentDescription("Code Entry"))
+ .perform(ViewActions.typeText(someBlueBotCode));
+
+ //And click the run button
+ onView(withContentDescription("Run")).perform(ViewActions.click());
+
+ //Then our Code Executor should be asked to execute someBlueBotCode
+ assertEquals("An EXECUTE_CODE request should be given.", UIRequestTypes.EXECUTE_CODE, requestTypePassedToRequestProcessor);
+ //And our Code Executor should be asked to execute someBlueBotCode
+ assertEquals("The given code should be executed.", someBlueBotCode, dataPassedToRequestProcessor);
+ }
+}
diff --git a/app/src/androidTest/java/com/car/rc/example/fouliex/rccar/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/car/rc/example/fouliex/rccar/ExampleInstrumentedTest.java
deleted file mode 100644
index b328ce6..0000000
--- a/app/src/androidTest/java/com/car/rc/example/fouliex/rccar/ExampleInstrumentedTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.car.rc.example.fouliex.rccar;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.*;
-
-/**
- * Instrumentation test, which will execute on an Android device.
- *
- * @see Testing documentation
- */
-@RunWith(AndroidJUnit4.class)
-public class ExampleInstrumentedTest {
- @Test
- public void useAppContext() throws Exception {
- // Context of the app under test.
- Context appContext = InstrumentationRegistry.getTargetContext();
-
- assertEquals("com.car.rc.example.fouliex.rccar", appContext.getPackageName());
- }
-}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 621bb03..dcf56b5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,17 +1,19 @@
+ package="com.bluebot">
-
+
+ android:theme="@style/AppTheme"
+ android:fullBackupContent="true">
@@ -19,6 +21,14 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/bluebot/BlueBotApplication.java b/app/src/main/java/com/bluebot/BlueBotApplication.java
new file mode 100644
index 0000000..e8b305d
--- /dev/null
+++ b/app/src/main/java/com/bluebot/BlueBotApplication.java
@@ -0,0 +1,54 @@
+package com.bluebot;
+
+import android.app.Activity;
+import android.app.Application;
+import android.os.Bundle;
+
+import com.bluebot.injection.Injector;
+
+/**
+ * Created by Clifton Craig on 4/12/17.
+ */
+
+public class BlueBotApplication extends Application {
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
+ @Override
+ public void onActivityCreated(Activity activity, Bundle bundle) {
+ Injector.injectEach(activity);
+ }
+
+ @Override
+ public void onActivityStarted(Activity activity) {
+
+ }
+
+ @Override
+ public void onActivityResumed(Activity activity) {
+
+ }
+
+ @Override
+ public void onActivityPaused(Activity activity) {
+
+ }
+
+ @Override
+ public void onActivityStopped(Activity activity) {
+
+ }
+
+ @Override
+ public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
+
+ }
+
+ @Override
+ public void onActivityDestroyed(Activity activity) {
+
+ }
+ });
+ }
+}
diff --git a/app/src/main/java/com/bluebot/BluetoothControl.java b/app/src/main/java/com/bluebot/BluetoothControl.java
new file mode 100644
index 0000000..c01f1e3
--- /dev/null
+++ b/app/src/main/java/com/bluebot/BluetoothControl.java
@@ -0,0 +1,35 @@
+package com.bluebot;
+
+import android.content.Intent;
+
+/**
+ * Created by Clifton Craig on 6/30/17.
+ * Copyright GE 6/30/17
+ */
+
+public interface BluetoothControl {
+ void stopService();
+
+ boolean isBluetoothEnabled();
+
+ void enable();
+
+ boolean isServiceAvailable();
+
+ void setupService();
+
+ void startService(boolean deviceOther);
+
+ void connect(Intent data);
+
+ int getServiceState();
+
+ void disconnect();
+
+
+ void setBluetoothConnectionListener(BluetoothControllerConnectionListener bluetoothControllerConnectionListener);
+
+ void send(String command, boolean crLF);
+
+ boolean isBluetoothAvailable();
+}
diff --git a/app/src/main/java/com/bluebot/BluetoothControllerConnectionListener.java b/app/src/main/java/com/bluebot/BluetoothControllerConnectionListener.java
new file mode 100644
index 0000000..eba7560
--- /dev/null
+++ b/app/src/main/java/com/bluebot/BluetoothControllerConnectionListener.java
@@ -0,0 +1,15 @@
+package com.bluebot;
+
+/**
+ * Created by Clifton Craig on 6/30/17.
+ * Copyright GE 6/30/17
+ */
+
+public interface BluetoothControllerConnectionListener {
+
+ void onDeviceConnected(String name, String address);
+
+ void onDeviceDisconnected();
+
+ void onDeviceConnectionFailed();
+}
diff --git a/app/src/main/java/com/car/rc/example/fouliex/rccar/MainActivity.java b/app/src/main/java/com/bluebot/MainActivity.java
similarity index 64%
rename from app/src/main/java/com/car/rc/example/fouliex/rccar/MainActivity.java
rename to app/src/main/java/com/bluebot/MainActivity.java
index 6e278af..a633953 100644
--- a/app/src/main/java/com/car/rc/example/fouliex/rccar/MainActivity.java
+++ b/app/src/main/java/com/bluebot/MainActivity.java
@@ -1,52 +1,65 @@
-package com.car.rc.example.fouliex.rccar;
+package com.bluebot;
import android.app.Activity;
import android.content.Intent;
-import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
+import com.bluebot.droid.ide.BlueBotIDEActivity;
+
import app.akexorcist.bluetotohspp.library.BluetoothSPP;
import app.akexorcist.bluetotohspp.library.BluetoothState;
import app.akexorcist.bluetotohspp.library.DeviceList;
+import static com.bluebot.runtime.bluetooth.BluetoothCodes.AUTONOMOUS;
+import static com.bluebot.runtime.bluetooth.BluetoothCodes.BACKWARD;
+import static com.bluebot.runtime.bluetooth.BluetoothCodes.FORWARD;
+import static com.bluebot.runtime.bluetooth.BluetoothCodes.LEFT;
+import static com.bluebot.runtime.bluetooth.BluetoothCodes.LEFTBACK;
+import static com.bluebot.runtime.bluetooth.BluetoothCodes.LOOKLEFT;
+import static com.bluebot.runtime.bluetooth.BluetoothCodes.LOOKRIGHT;
+import static com.bluebot.runtime.bluetooth.BluetoothCodes.LOOKSTRAIGHT;
+import static com.bluebot.runtime.bluetooth.BluetoothCodes.RIGHT;
+import static com.bluebot.runtime.bluetooth.BluetoothCodes.RIGHTBACK;
+import static com.bluebot.runtime.bluetooth.BluetoothCodes.STOP;
+
+/**
+ * Created by George Fouche on 4/5/2017.
+ */
public class MainActivity extends AppCompatActivity implements View.OnTouchListener {
- final String FORWARD = "f";
- final String BACKWARD = "b";
- final String LEFT = "l";
- final String RIGHT = "r";
- final String STOP = "s";
- final String LEFTBACK = "L";
- final String RIGHTBACK = "R";
- final String AUTOPILOT = "a";
-
- boolean forward = false;
- boolean backward = false;
- boolean left = false;
- boolean right = false;
- boolean auto = false;
- boolean stop = false;
-
- BluetoothSPP bluetooth;
- Button connect;
+ private boolean forward = false;
+ private boolean backward = false;
+ private boolean left = false;
+ private boolean right = false;
+ private boolean stop = false;
+
+ //Servo
+ private boolean lookRight = false;
+ private boolean lookLeft = false;
+ private boolean lookStraight = false;
+
+
+ private BluetoothControl bluetooth;
+ private Button connect;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
- bluetooth = new BluetoothSPP(this);
connect = (Button) findViewById(R.id.connect);
- if (!bluetooth.isBluetoothAvailable()) {
- Toast.makeText(getApplicationContext(), "Bluetooth is not available", Toast.LENGTH_SHORT).show();
- //close the Activity
- finish();
- }
- setBluetoothListener();
+ findViewById(R.id.ideButton).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ final Intent intent = new Intent(getApplicationContext(), BlueBotIDEActivity.class);
+ startActivity(intent);
+ }
+ });
setConnectListener();
setButtonsOnTouchListener();
@@ -75,7 +88,7 @@ protected void onStart() {
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == BluetoothState.REQUEST_CONNECT_DEVICE) {
if (resultCode == Activity.RESULT_OK && data != null) {
- connect.setText("Connecting...");
+ connect.setText(R.string.connecting);
connect.setEnabled(false);
bluetooth.connect(data);
}
@@ -89,20 +102,19 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
}
}
- /**
- * Set buttons on touch listener
- */
private void setButtonsOnTouchListener() {
findViewById(R.id.forward).setOnTouchListener(this);
findViewById(R.id.backward).setOnTouchListener(this);
findViewById(R.id.left).setOnTouchListener(this);
findViewById(R.id.right).setOnTouchListener(this);
- findViewById(R.id.auto).setOnTouchListener(this);
+ findViewById(R.id.autonomous).setOnTouchListener(this);
+ //Servo
+ findViewById(R.id.sensroRight).setOnTouchListener(this);
+ findViewById(R.id.sensorLeft).setOnTouchListener(this);
+ findViewById(R.id.sensorCenter).setOnTouchListener(this);
+
}
- /**
- * Set connection to phone listener
- */
private void setConnectListener() {
connect.setOnClickListener(new View.OnClickListener() {
@Override
@@ -117,27 +129,24 @@ public void onClick(View v) {
});
}
- /**
- * Set Bluetooth Listener
- */
private void setBluetoothListener() {
- bluetooth.setBluetoothConnectionListener(new BluetoothSPP.BluetoothConnectionListener() {
+ bluetooth.setBluetoothConnectionListener(new BluetoothControllerConnectionListener() {
@Override
public void onDeviceConnected(String name, String address) {
connect.setEnabled(true);
- connect.setText("Connected to " + name);
+ connect.setText(getString(R.string.connected_to, name));
}
@Override
public void onDeviceDisconnected() {
connect.setEnabled(true);
- connect.setText("Connection lost");
+ connect.setText(R.string.connection_lost);
}
@Override
public void onDeviceConnectionFailed() {
connect.setEnabled(true);
- connect.setText("Unable to connect");
+ connect.setText(R.string.unable_to_connect);
}
});
}
@@ -161,9 +170,17 @@ public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) right = true;
else if (event.getAction() == MotionEvent.ACTION_UP) right = false;
break;
- case R.id.auto:
- if (event.getAction() == MotionEvent.ACTION_DOWN) auto = true;
- else if (event.getAction() == MotionEvent.ACTION_UP) auto = false;
+ case R.id.sensroRight:
+ if (event.getAction() == MotionEvent.ACTION_DOWN) lookRight = true;
+ else if (event.getAction() == MotionEvent.ACTION_UP) lookRight = false;
+ break;
+ case R.id.sensorLeft:
+ if (event.getAction() == MotionEvent.ACTION_DOWN) lookLeft = true;
+ else if (event.getAction() == MotionEvent.ACTION_UP) lookLeft = false;
+ break;
+ case R.id.sensorCenter:
+ if (event.getAction() == MotionEvent.ACTION_DOWN)lookStraight = true;
+ else if (event.getAction() == MotionEvent.ACTION_UP) lookStraight = false;
break;
}
@@ -188,12 +205,22 @@ private void command() {
else send(STOP);
} else if (left && !right) send(LEFT);
else if (right) send(RIGHT);
- else if(auto)send(AUTOPILOT);
+ else if (lookRight) send(LOOKRIGHT);
+ else if (lookLeft) send(LOOKLEFT);
+ else if (lookStraight)send(LOOKSTRAIGHT);
else send(STOP);
}
private void send(String command) {
- bluetooth.send(command,true);
+ bluetooth.send(command, true);
+ }
+
+ public void setBluetooth(BluetoothControl bluetooth) {
+ this.bluetooth = bluetooth;
+ if (!bluetooth.isBluetoothAvailable()) {
+ Toast.makeText(getApplicationContext(), "Bluetooth is not available", Toast.LENGTH_SHORT).show();
+ }
+ setBluetoothListener();
}
}
diff --git a/app/src/main/java/com/bluebot/droid/ide/BlueBotIDEActivity.java b/app/src/main/java/com/bluebot/droid/ide/BlueBotIDEActivity.java
new file mode 100644
index 0000000..ce60890
--- /dev/null
+++ b/app/src/main/java/com/bluebot/droid/ide/BlueBotIDEActivity.java
@@ -0,0 +1,65 @@
+package com.bluebot.droid.ide;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.text.Editable;
+import android.util.Log;
+import android.view.View;
+import android.widget.EditText;
+
+import com.bluebot.R;
+import com.bluebot.ui.RequestProcessor;
+import com.bluebot.ui.ResponseHandler;
+import com.bluebot.ui.UIRequestTypes;
+import com.bluebot.ui.UIResponseType;
+
+import java.util.Map;
+
+import static android.view.View.INVISIBLE;
+import static android.view.View.VISIBLE;
+
+
+public class BlueBotIDEActivity extends AppCompatActivity implements ResponseHandler {
+
+ private RequestProcessor requestProcessor;
+ private View errorMessage;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getIntentData();
+ setContentView(R.layout.activity_blue_bot_ide);
+ findViewById(R.id.runButton).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ final Editable code = ((EditText) findViewById(R.id.codeEntry)).getText();
+ requestProcessor.processRequest(UIRequestTypes.EXECUTE_CODE, code.toString());
+ }
+ });
+ errorMessage = findViewById(R.id.errorMessage);
+ errorMessage.setVisibility(INVISIBLE);
+ }
+
+ private void getIntentData() {
+ if (getIntent().getAction()!=null && getIntent().getAction().equals(Intent.ACTION_VIEW)) {
+ Log.d(getLocalClassName(), "Intent data: " + getIntent().getData());
+ }
+ }
+
+ public void setRequestProcessor(RequestProcessor requestProcessor) {
+ this.requestProcessor = requestProcessor;
+ requestProcessor.bind(this);
+ }
+
+ @Override
+ public void responseForRequest(String requestType, final Map response) {
+ runOnUiThread(new Runnable() {
+ public void run() {
+ if (response.containsKey(UIResponseType.ERROR)) {
+ errorMessage.setVisibility(VISIBLE);
+ }
+ }
+ });
+ }
+}
diff --git a/app/src/main/java/com/bluebot/injection/BlueBotIDEActivityModule.java b/app/src/main/java/com/bluebot/injection/BlueBotIDEActivityModule.java
new file mode 100644
index 0000000..ebf7c5c
--- /dev/null
+++ b/app/src/main/java/com/bluebot/injection/BlueBotIDEActivityModule.java
@@ -0,0 +1,44 @@
+package com.bluebot.injection;
+
+import com.bluebot.droid.ide.BlueBotIDEActivity;
+import com.bluebot.runtime.bluetooth.BluetoothCommandSink;
+import com.bluebot.runtime.runner.BlueCodeRunner;
+import com.bluebot.ui.CodeRunnerRequestProcessor;
+
+import app.akexorcist.bluetotohspp.library.BluetoothSPP;
+
+/**
+ * Created by Clifton Craig on 4/12/17.
+ */
+
+class BlueBotIDEActivityModule implements InjectionModule{
+ private SharedComponents sharedComponents;
+
+ @Override
+ public void inject(Object object) {
+ injectActivity((BlueBotIDEActivity)object);
+ }
+
+ @Override
+ public void setSharedComponents(SharedComponents sharedComponents) {
+ this.sharedComponents = sharedComponents;
+ }
+
+ private void injectActivity(final BlueBotIDEActivity blueBotIDEActivity) {
+ final CodeRunnerRequestProcessor requestProcessor = new CodeRunnerRequestProcessor(new BlueCodeRunner(new BluetoothCommandSink() {
+ private final BluetoothSPP bluetooth = sharedComponents.get(BluetoothSPP.class);
+
+ @Override
+ public void send(String command) {
+ bluetooth.send(command, true);
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }));
+ requestProcessor.setRunIndefinitely(true);
+ blueBotIDEActivity.setRequestProcessor(requestProcessor);
+ }
+}
diff --git a/app/src/main/java/com/bluebot/injection/InjectionModule.java b/app/src/main/java/com/bluebot/injection/InjectionModule.java
new file mode 100644
index 0000000..d68abd0
--- /dev/null
+++ b/app/src/main/java/com/bluebot/injection/InjectionModule.java
@@ -0,0 +1,11 @@
+package com.bluebot.injection;
+
+/**
+ * Created by Clifton Craig on 4/12/17.
+ */
+
+interface InjectionModule {
+ void inject(Object object);
+
+ void setSharedComponents(SharedComponents sharedComponents);
+}
diff --git a/app/src/main/java/com/bluebot/injection/Injector.java b/app/src/main/java/com/bluebot/injection/Injector.java
new file mode 100644
index 0000000..27219b9
--- /dev/null
+++ b/app/src/main/java/com/bluebot/injection/Injector.java
@@ -0,0 +1,46 @@
+package com.bluebot.injection;
+
+import android.app.Activity;
+import android.content.Context;
+
+import com.bluebot.MainActivity;
+import com.bluebot.droid.ide.BlueBotIDEActivity;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by Clifton Craig on 4/12/17.
+ */
+
+public class Injector {
+ private static final SharedComponents share = new InjectorSharedComponents();
+
+ private static final MapmoduleMap = new HashMap(){{
+ put(BlueBotIDEActivity.class, BlueBotIDEActivityModule.class);
+ put(MainActivity.class, MainActivityModule.class);
+ }};
+ public static void injectEach(Activity activity) {
+ if(share.doesNotHave(Context.class)) {
+ share.put(Context.class, activity.getApplicationContext());
+ }
+ if(moduleMap.containsKey(activity.getClass())) {
+ InjectionModule module = inflate(moduleMap.get(activity.getClass()));
+ module.setSharedComponents(share);
+ module.inject(activity);
+ }
+ }
+
+ private static InjectionModule inflate(Class aClass) {
+ Object instance = null;
+ try {
+ instance = aClass.newInstance();
+ } catch (InstantiationException e) {
+ throw new RuntimeException("Cannot instantiate " + aClass, e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException("Cannot access " + aClass, e);
+ }
+ return (InjectionModule) instance;
+ }
+
+}
diff --git a/app/src/main/java/com/bluebot/injection/InjectorSharedComponents.java b/app/src/main/java/com/bluebot/injection/InjectorSharedComponents.java
new file mode 100644
index 0000000..2750cf3
--- /dev/null
+++ b/app/src/main/java/com/bluebot/injection/InjectorSharedComponents.java
@@ -0,0 +1,26 @@
+package com.bluebot.injection;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by Clifton Craig on 4/13/17.
+ */
+class InjectorSharedComponents implements SharedComponents {
+ private Map internalShare = new HashMap<>();
+
+ @Override
+ public boolean doesNotHave(Class aClass) {
+ return !internalShare.containsKey(aClass);
+ }
+
+ @Override
+ public T get(Class aClass) {
+ return (T) internalShare.get(aClass);
+ }
+
+ @Override
+ public void put(Class aClass, T instance) {
+ internalShare.put(aClass, instance);
+ }
+}
diff --git a/app/src/main/java/com/bluebot/injection/MainActivityModule.java b/app/src/main/java/com/bluebot/injection/MainActivityModule.java
new file mode 100644
index 0000000..33a3263
--- /dev/null
+++ b/app/src/main/java/com/bluebot/injection/MainActivityModule.java
@@ -0,0 +1,39 @@
+package com.bluebot.injection;
+
+import android.content.Context;
+
+import com.bluebot.BluetoothControl;
+import com.bluebot.MainActivity;
+import com.bluebot.wrappers.BluetoothControlWrapper;
+
+import app.akexorcist.bluetotohspp.library.BluetoothSPP;
+
+/**
+ * Created by Clifton Craig on 4/13/17.
+ */
+
+class MainActivityModule implements InjectionModule{
+ private SharedComponents sharedComponents;
+
+ @Override
+ public void inject(Object object) {
+ injectActivity((MainActivity)object);
+ }
+
+ private void injectActivity(MainActivity mainActivity) {
+ mainActivity.setBluetooth(lazyGetBluetoothControl());
+ }
+
+ private BluetoothControl lazyGetBluetoothControl() {
+ if(sharedComponents.doesNotHave(BluetoothSPP.class)) {
+ final BluetoothSPP bluetoothSPP = new BluetoothSPP(sharedComponents.get(Context.class));
+ sharedComponents.put(BluetoothControl.class, new BluetoothControlWrapper(bluetoothSPP));
+ }
+ return sharedComponents.get(BluetoothControl.class);
+ }
+
+ @Override
+ public void setSharedComponents(SharedComponents sharedComponents) {
+ this.sharedComponents = sharedComponents;
+ }
+}
diff --git a/app/src/main/java/com/bluebot/injection/SharedComponents.java b/app/src/main/java/com/bluebot/injection/SharedComponents.java
new file mode 100644
index 0000000..56abfe9
--- /dev/null
+++ b/app/src/main/java/com/bluebot/injection/SharedComponents.java
@@ -0,0 +1,13 @@
+package com.bluebot.injection;
+
+/**
+ * Created by Clifton Craig on 4/13/17.
+ */
+
+interface SharedComponents {
+ boolean doesNotHave(Class aClass);
+
+ void put(Class aClass, T instance);
+
+ T get(Class aClass);
+}
diff --git a/app/src/main/java/com/bluebot/wrappers/BluetoothConnectionListenerWrapper.java b/app/src/main/java/com/bluebot/wrappers/BluetoothConnectionListenerWrapper.java
new file mode 100644
index 0000000..5214d3e
--- /dev/null
+++ b/app/src/main/java/com/bluebot/wrappers/BluetoothConnectionListenerWrapper.java
@@ -0,0 +1,32 @@
+package com.bluebot.wrappers;
+
+import com.bluebot.BluetoothControllerConnectionListener;
+
+import app.akexorcist.bluetotohspp.library.BluetoothSPP;
+
+/**
+ * Created by Clifton Craig on 7/6/17.
+ * Copyright GE 7/6/17
+ */
+class BluetoothConnectionListenerWrapper implements BluetoothSPP.BluetoothConnectionListener {
+ private final BluetoothControllerConnectionListener bluetoothControllerConnectionListener;
+
+ public BluetoothConnectionListenerWrapper(BluetoothControllerConnectionListener bluetoothControllerConnectionListener) {
+ this.bluetoothControllerConnectionListener = bluetoothControllerConnectionListener;
+ }
+
+ @Override
+ public void onDeviceConnected(String name, String address) {
+ bluetoothControllerConnectionListener.onDeviceConnected(name, address);
+ }
+
+ @Override
+ public void onDeviceDisconnected() {
+ bluetoothControllerConnectionListener.onDeviceDisconnected();
+ }
+
+ @Override
+ public void onDeviceConnectionFailed() {
+ bluetoothControllerConnectionListener.onDeviceConnectionFailed();
+ }
+}
diff --git a/app/src/main/java/com/bluebot/wrappers/BluetoothControlWrapper.java b/app/src/main/java/com/bluebot/wrappers/BluetoothControlWrapper.java
new file mode 100644
index 0000000..037995a
--- /dev/null
+++ b/app/src/main/java/com/bluebot/wrappers/BluetoothControlWrapper.java
@@ -0,0 +1,82 @@
+package com.bluebot.wrappers;
+
+import android.content.Intent;
+
+import com.bluebot.BluetoothControl;
+import com.bluebot.BluetoothControllerConnectionListener;
+
+import app.akexorcist.bluetotohspp.library.BluetoothSPP;
+
+/**
+ * Created by Clifton Craig on 6/30/17.
+ * Copyright GE 6/30/17
+ */
+
+public class BluetoothControlWrapper implements BluetoothControl {
+ private final BluetoothSPP bluetoothSPP;
+
+ public BluetoothControlWrapper(BluetoothSPP bluetoothSPP) {
+ this.bluetoothSPP = bluetoothSPP;
+ }
+
+ @Override
+ public boolean isBluetoothAvailable() {
+ return bluetoothSPP.isBluetoothAvailable();
+ }
+
+ @Override
+ public boolean isBluetoothEnabled() {
+ return bluetoothSPP.isBluetoothEnabled();
+ }
+
+ @Override
+ public boolean isServiceAvailable() {
+ return bluetoothSPP.isServiceAvailable();
+ }
+
+ @Override
+ public void setupService() {
+ bluetoothSPP.setupService();
+ }
+
+ @Override
+ public int getServiceState() {
+ return bluetoothSPP.getServiceState();
+ }
+
+ @Override
+ public void startService(boolean isAndroid) {
+ bluetoothSPP.startService(isAndroid);
+ }
+
+ @Override
+ public void stopService() {
+ bluetoothSPP.stopService();
+ }
+
+ @Override
+ public void connect(Intent data) {
+ bluetoothSPP.connect(data);
+ }
+
+ @Override
+ public void disconnect() {
+ bluetoothSPP.disconnect();
+ }
+
+ @Override
+ public void setBluetoothConnectionListener(final BluetoothControllerConnectionListener bluetoothControllerConnectionListener) {
+ bluetoothSPP.setBluetoothConnectionListener(new BluetoothConnectionListenerWrapper(bluetoothControllerConnectionListener));
+ }
+
+ @Override
+ public void enable() {
+ bluetoothSPP.enable();
+ }
+
+ @Override
+ public void send(String data, boolean CRLF) {
+ bluetoothSPP.send(data, CRLF);
+ }
+
+}
diff --git a/app/src/main/res/layout/activity_blue_bot_ide.xml b/app/src/main/res/layout/activity_blue_bot_ide.xml
new file mode 100644
index 0000000..60e0064
--- /dev/null
+++ b/app/src/main/res/layout/activity_blue_bot_ide.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 48be819..f68d33f 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -12,57 +12,102 @@
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
- android:text="Connect"
+ android:text="@string/connect"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="0dp" />
+ android:text="@string/auto" />
+ android:text="@string/right" />
+ android:layout_toStartOf="@+id/backward" />
+ android:text="@string/backward" />
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
index c133a0c..7eba8ac 100644
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f37477b..1f7b3b6 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,3 +1,21 @@
- RcCar
+ BlueBot
+ BlueBot IDE
+ Code Entry
+ Run
+ Run
+ Error message
+ Error!
+ Connect
+ Auto
+ Right
+ Left
+ Forward
+ backward
+ IDE
+ Connecting…
+ Connected to %1$s
+ Connection lost
+ Unable to connect
+ Center
diff --git a/app/src/test/java/com/car/rc/example/fouliex/rccar/ExampleUnitTest.java b/app/src/test/java/com/car/rc/example/fouliex/rccar/ExampleUnitTest.java
deleted file mode 100644
index 9d914c7..0000000
--- a/app/src/test/java/com/car/rc/example/fouliex/rccar/ExampleUnitTest.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.car.rc.example.fouliex.rccar;
-
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * @see Testing documentation
- */
-public class ExampleUnitTest {
- @Test
- public void addition_isCorrect() throws Exception {
- assertEquals(4, 2 + 2);
- }
-}
\ No newline at end of file
diff --git a/arduino/SmartRobotRcCarWithServo/SmartRobotRcCarWithServo.ino b/arduino/SmartRobotRcCarWithServo/SmartRobotRcCarWithServo.ino
index 7e45a15..4369c4f 100644
--- a/arduino/SmartRobotRcCarWithServo/SmartRobotRcCarWithServo.ino
+++ b/arduino/SmartRobotRcCarWithServo/SmartRobotRcCarWithServo.ino
@@ -1,4 +1,6 @@
-
+/**
+ * Created by George Fouche
+ */
#include
//create servo object to control servo
Servo myservo;
@@ -24,8 +26,23 @@ void setup()
}
+void lookRight(){
+ servo(40);
+}
+
+void lookLeft(){
+ servo(140);
+}
+
+
+void lookStraight(){
+ servo(90);
+}
+
+void servo(int angle){
+ myservo.write(angle);
+}
void forward(){
- myservo.write(90);
digitalWrite(IN1,HIGH);
digitalWrite(IN3,HIGH);
digitalWrite(IN2,LOW);
@@ -34,14 +51,12 @@ void forward(){
}
void leftForward(){
- myservo.write(140);
digitalWrite(IN3,LOW);
digitalWrite(IN2,LOW);
digitalWrite(IN4,LOW);
digitalWrite(IN1,HIGH);
}
void rightForward(){
- myservo.write(40);
digitalWrite(IN1,LOW);
digitalWrite(IN2,LOW);
digitalWrite(IN4,LOW);
@@ -86,6 +101,9 @@ void loop()
else if (command =='r') rightForward();
else if (command == 'L') leftBackward();
else if (command == 'R')rightBackward();
+ else if (command == '1')lookRight();
+ else if (command == '2') lookLeft();
+ else if (command == '3') lookStraight();
else if (command == 's') stop();
}
}
diff --git a/bluebot.ino b/bluebot.ino
new file mode 100644
index 0000000..b77940c
--- /dev/null
+++ b/bluebot.ino
@@ -0,0 +1,293 @@
+//BlueBot V1.0
+//2017.05.03
+//Clifton C. Craig
+
+#include //servo library
+Servo myservo; // create servo object to control servo
+char getstr;
+int AUTONOMOUS = 1;
+int MANUAL = 0;
+int state = 0;
+int Echo = A4;
+int Trig = A5;
+//Right wheel
+int ENA = 11;
+int in1 = 9;
+int in2 = 8;
+
+//Left wheel
+int ENB = 5;
+int in3 = 7;
+int in4 = 6;
+
+int ABS = 150;
+int rightDistance = 0,leftDistance = 0,middleDistance = 0;
+int THRESHOLD = 30;
+
+void _mForward()
+{
+ analogWrite(ENA,ABS);
+ analogWrite(ENB,ABS);
+ digitalWrite(in1,LOW);
+ digitalWrite(in2,HIGH);
+ digitalWrite(in3,LOW);
+ digitalWrite(in4,HIGH);
+ Serial.println("go forward!");
+}
+
+void _mBack()
+{
+ analogWrite(ENA,ABS);
+ analogWrite(ENB,ABS);
+ digitalWrite(in1,HIGH);
+ digitalWrite(in2,LOW);
+ digitalWrite(in3,HIGH);
+ digitalWrite(in4,LOW);
+ Serial.println("go back!");
+}
+
+void _mleft()
+{
+ analogWrite(ENA,ABS);
+ analogWrite(ENB,ABS);
+ digitalWrite(in1,LOW);
+ digitalWrite(in2,HIGH);
+ digitalWrite(in3,HIGH);
+ digitalWrite(in4,LOW);
+ Serial.println("go left!");
+}
+
+void _mright()
+{
+ analogWrite(ENA,ABS);
+ analogWrite(ENB,ABS);
+ digitalWrite(in1,HIGH);
+ digitalWrite(in2,LOW);
+ digitalWrite(in3,LOW);
+ digitalWrite(in4,HIGH);
+ Serial.println("go right!");
+}
+void _mStop()
+{
+ digitalWrite(ENA,LOW);
+ digitalWrite(ENB,LOW);
+ Serial.println("Stop!");
+}
+ /*Ultrasonic distance measurement Sub function*/
+int Distance_test()
+{
+ delay(90);
+ digitalWrite(Trig, LOW);
+ delayMicroseconds(2);
+ digitalWrite(Trig, HIGH);
+ delayMicroseconds(30);
+ digitalWrite(Trig, LOW);
+ float Fdistance = pulseIn(Echo, HIGH);
+ Fdistance= Fdistance/58;
+ return (int)Fdistance;
+}
+
+void setup()
+{
+ myservo.attach(3);// attach servo on pin 3 to servo object
+ Serial.begin(9600);
+ pinMode(Echo, INPUT);
+ pinMode(Trig, OUTPUT);
+ pinMode(in1,OUTPUT);
+ pinMode(in2,OUTPUT);
+ pinMode(in3,OUTPUT);
+ pinMode(in4,OUTPUT);
+ pinMode(ENA,OUTPUT);
+ pinMode(ENB,OUTPUT);
+ _mStop();
+ lookAhead();
+ #ifdef debug
+ debug();
+ #endif
+}
+
+int lookNScan(int pos)
+{
+ myservo.write(pos);//setservo position according to scaled value
+ delay(500);
+ return Distance_test();
+}
+
+void lookAhead()
+{
+ //setservo position according to scaled value
+ middleDistance = lookNScan(90);
+ #ifdef send
+ Serial.print("middleDistance=");
+ Serial.println(middleDistance);
+ #endif
+}
+
+int lookOffRight()
+{
+ int offRight = lookNScan(65);
+
+ #ifdef send
+ Serial.print("offRight=");
+ Serial.println(offRight);
+ #endif
+ return offRight;
+}
+
+int lookOffLeft()
+{
+ int offLeft = lookNScan(115);
+
+ #ifdef send
+ Serial.print("offLeft=");
+ Serial.println(offLeft);
+ #endif
+ return offLeft;
+}
+
+void loop()
+{
+ getstr=Serial.read();
+ if(getstr=='A') {
+ stateChange();
+ } else if(state == AUTONOMOUS) {
+ autonomous();
+ } else if(state == MANUAL) {
+ processCmd();
+ }
+
+}
+
+void processCmd()
+{
+ if(getstr=='f')
+ {
+ _mForward();
+ }
+ else if(getstr=='b')
+ {
+ _mBack();
+ delay(200);
+ }
+ else if(getstr=='l')
+ {
+ _mleft();
+ delay(200);
+ }
+ else if(getstr=='r')
+ {
+ _mright();
+ delay(200);
+ }
+ else if(getstr=='s')
+ {
+ _mStop();
+ }
+}
+
+void stateChange()
+{
+ if(state == MANUAL)
+ state = AUTONOMOUS;
+ else if(state == AUTONOMOUS)
+ state = MANUAL;
+}
+
+void autonomous()
+{
+ lookAhead();
+ int r = lookOffRight();
+ int l = lookOffLeft();
+
+ Serial.print("offRight=");
+ Serial.print(r);
+ Serial.print(" offLeft=");
+ Serial.println(l);
+ if(middleDistance<=THRESHOLD || l<=THRESHOLD || r<=THRESHOLD)
+ {
+ handleCollision();
+ }
+ else
+ _mForward();
+}
+
+void handleCollision()
+{
+ _mStop();
+ rightDistance = lookNScan(5);
+ delay(1000);
+
+ #ifdef send
+ Serial.print("rightDistance=");
+ Serial.println(rightDistance);
+ #endif
+
+ leftDistance = lookNScan(180);
+ delay(1000);
+
+ #ifdef send
+ Serial.print("leftDistance=");
+ Serial.println(leftDistance);
+ #endif
+
+ lookAhead();
+ delay(500);
+ if(rightDistance>leftDistance)
+ {
+ _mBack();
+ delay(500);
+ _mright();
+ delay(500);
+ }
+ else if(rightDistance 0)
+ last = Serial.read();
+ switch(last)
+ {
+ case 'l':
+ _mleft();
+ break;
+ case 'r':
+ _mright();
+ break;
+ case 'f':
+ _mForward();
+ break;
+ case 'b':
+ _mBack();
+ break;
+ case 'x':
+ Serial.print("Done Debugging!");
+ return;
+ break;
+ }
+ delay(500);
+ _mStop();
+ last = ' ';
+ }
+}
+
diff --git a/bluebotruntimelib/.gitignore b/bluebotruntimelib/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/bluebotruntimelib/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/bluebotruntimelib/build.gradle b/bluebotruntimelib/build.gradle
new file mode 100644
index 0000000..edb6429
--- /dev/null
+++ b/bluebotruntimelib/build.gradle
@@ -0,0 +1,9 @@
+apply plugin: 'java'
+
+dependencies {
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+ compile 'junit:junit:4.12'
+}
+
+sourceCompatibility = "1.7"
+targetCompatibility = "1.7"
diff --git a/bluebotruntimelib/src/main/java/com/bluebot/runtime/bluetooth/BluetoothCodes.java b/bluebotruntimelib/src/main/java/com/bluebot/runtime/bluetooth/BluetoothCodes.java
new file mode 100644
index 0000000..06288d5
--- /dev/null
+++ b/bluebotruntimelib/src/main/java/com/bluebot/runtime/bluetooth/BluetoothCodes.java
@@ -0,0 +1,22 @@
+package com.bluebot.runtime.bluetooth;
+
+/**
+ * Created by Clifton Craig on 4/9/17.
+ */
+
+public class BluetoothCodes {
+ // Motor Control
+ public static final String AUTONOMOUS = "A";
+ public static final String FORWARD = "f";
+ public static final String BACKWARD = "b";
+ public static final String LEFT = "l";
+ public static final String RIGHT = "r";
+ public static final String STOP = "s";
+ public static final String LEFTBACK = "L";
+ public static final String RIGHTBACK = "R";
+
+ // Servo Control
+ public static final String LOOKRIGHT = "1";
+ public static final String LOOKLEFT= "2";
+ public static final String LOOKSTRAIGHT = "3";
+}
diff --git a/bluebotruntimelib/src/main/java/com/bluebot/runtime/bluetooth/BluetoothCommandSink.java b/bluebotruntimelib/src/main/java/com/bluebot/runtime/bluetooth/BluetoothCommandSink.java
new file mode 100644
index 0000000..7b9a3b1
--- /dev/null
+++ b/bluebotruntimelib/src/main/java/com/bluebot/runtime/bluetooth/BluetoothCommandSink.java
@@ -0,0 +1,9 @@
+package com.bluebot.runtime.bluetooth;
+
+/**
+ * Created by Clifton Craig on 4/9/17.
+ */
+
+public interface BluetoothCommandSink {
+ void send(String command);
+}
diff --git a/bluebotruntimelib/src/main/java/com/bluebot/runtime/runner/BlueCodeRunner.java b/bluebotruntimelib/src/main/java/com/bluebot/runtime/runner/BlueCodeRunner.java
new file mode 100644
index 0000000..26897ea
--- /dev/null
+++ b/bluebotruntimelib/src/main/java/com/bluebot/runtime/runner/BlueCodeRunner.java
@@ -0,0 +1,64 @@
+package com.bluebot.runtime.runner;
+
+import com.bluebot.runtime.bluetooth.BluetoothCodes;
+import com.bluebot.runtime.bluetooth.BluetoothCommandSink;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+public class BlueCodeRunner {
+ private static final List VALID_COMMANDS = Collections.singletonList("move");
+ private final BluetoothCommandSink bluetoothCommandSink;
+
+ public BlueCodeRunner(BluetoothCommandSink bluetoothCommandSink) {
+ this.bluetoothCommandSink = bluetoothCommandSink;
+ }
+
+ public void run(String blueCode) {
+ final String[] sourceLines = blueCode.split("\n");
+ Map sourceCode = parseSourceCode(sourceLines);
+ for(String command : sourceCode.values()) {
+ bluetoothCommandSink.send(xLate(command));
+ }
+ bluetoothCommandSink.send(BluetoothCodes.STOP);
+ }
+
+ private Map parseSourceCode(String[] sourceLines) {
+ Map sortedSource= new TreeMap<>();
+ for (String eachLine : sourceLines) {
+ final String[] tokens = eachLine.split(" ");
+ final int lineNumber;
+ try { lineNumber = Integer.parseInt(tokens[0]); }
+ catch (NumberFormatException e) {
+ throw new IllegalArgumentException("BlueCode should start with a line number.",e);
+ }
+ if(!isValidCommand(tokens[1]))
+ throw new IllegalArgumentException("A valid command should follow the line number.");
+ if(tokens.length > 3)
+ throw new IllegalArgumentException("Line " + tokens[0] + ": Unexpected command or text [" + tokens[3] + "] after [" + tokens[2] + "]");
+ sortedSource.put(lineNumber, tokens[2]);
+ }
+ return sortedSource;
+ }
+
+ private boolean isValidCommand(String command) {
+ return VALID_COMMANDS.contains(command);
+ }
+
+ private String xLate(String command) {
+ switch (command) {
+ case "forward":
+ return BluetoothCodes.FORWARD;
+ case "backward":
+ return BluetoothCodes.BACKWARD;
+ case "left":
+ return BluetoothCodes.LEFT;
+ case "right":
+ return BluetoothCodes.RIGHT;
+ default:
+ return "?";
+ }
+ }
+}
diff --git a/bluebotruntimelib/src/main/java/com/bluebot/ui/CodeRunnerRequestProcessor.java b/bluebotruntimelib/src/main/java/com/bluebot/ui/CodeRunnerRequestProcessor.java
new file mode 100644
index 0000000..9be24de
--- /dev/null
+++ b/bluebotruntimelib/src/main/java/com/bluebot/ui/CodeRunnerRequestProcessor.java
@@ -0,0 +1,77 @@
+package com.bluebot.ui;
+
+import com.bluebot.runtime.runner.BlueCodeRunner;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+/**
+ * Created by Clifton Craig on 4/11/17.
+ */
+
+public class CodeRunnerRequestProcessor implements RequestProcessor, Runnable {
+ private final Queue