aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoy Ben Shabat <roy@twine-s.com>2017-11-08 21:47:25 +0200
committerRoy Ben-Shabat <Roy@Twine-s.com>2017-11-08 21:47:25 +0200
commit6626d0227c28c0a9f990e08c431e8b80739ea58d (patch)
tree23e5fe5d6b258618d7ae2fe7a23b4762e0750534
parentd615c26b41af480dae0bf478133c9333c319a6ce (diff)
downloadTango-6626d0227c28c0a9f990e08c431e8b80739ea58d.tar.gz
Tango-6626d0227c28c0a9f990e08c431e8b80739ea58d.zip
Working on integration !!
-rw-r--r--Software/Android-Studio/Tango.Integration/.gitignore1
-rw-r--r--Software/Android-Studio/Tango.Integration/build.gradle46
-rw-r--r--Software/Android-Studio/Tango.Integration/proguard-rules.pro25
-rw-r--r--Software/Android-Studio/Tango.Integration/src/androidTest/java/com/twine/tango/integration/ExampleInstrumentedTest.java26
-rw-r--r--Software/Android-Studio/Tango.Integration/src/main/AndroidManifest.xml6
-rw-r--r--Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/adapters/SerialAdapter.java20
-rw-r--r--Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/adapters/TcpAdapter.java92
-rw-r--r--Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/machine/MachineOperator.java244
-rw-r--r--Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/machine/MachineOperatorInterface.java19
-rw-r--r--Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/machine/MessageBase.java24
-rw-r--r--Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/machine/RequestMessage.java59
-rw-r--r--Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/machine/ResponseMessage.java37
-rw-r--r--Software/Android-Studio/Tango.Integration/src/main/res/values/strings.xml3
-rw-r--r--Software/Android-Studio/Tango.Integration/src/test/java/com/twine/tango/integration/ExampleUnitTest.java17
-rw-r--r--Software/Android-Studio/Tango.Models/src/main/java/com/twine/tango/models/stubs/Stub.java35
-rw-r--r--Software/Android-Studio/Tango.PMR/src/main/java/com/twine/tango/pmr/MessageFactory.java3
-rw-r--r--Software/Android-Studio/Tango.PMR/src/main/java/com/twine/tango/pmr/common/MessageContainerOuterClass.java161
-rw-r--r--Software/Android-Studio/Tango.Stubs.UI/build.gradle6
-rw-r--r--Software/Android-Studio/Tango.Stubs.UI/src/main/AndroidManifest.xml2
-rw-r--r--Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/App.java44
-rw-r--r--Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/Events/StubSelectedEvent.java2
-rw-r--r--Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/dagger/ApplicationComponent.java2
-rw-r--r--Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/dagger/IntegrationModule.java28
-rw-r--r--Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/dagger/ViewModelsModule.java5
-rw-r--r--Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/views/stub/StubActivityVM.java19
-rw-r--r--Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/views/stubs/StubsActivityContract.java1
-rw-r--r--Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/views/stubs/StubsActivityVM.java11
-rw-r--r--Software/Android-Studio/Tango.Stubs.UI/src/main/res/layout/activity_stub.xml7
-rw-r--r--Software/Android-Studio/Tango.Stubs.UI/src/main/res/layout/activity_stubs.xml2
-rw-r--r--Software/Android-Studio/Tango.Stubs.UI/src/main/res/layout/stubs_listview_item.xml2
-rw-r--r--Software/Android-Studio/Tango.Stubs/.gitignore1
-rw-r--r--Software/Android-Studio/Tango.Stubs/build.gradle43
-rw-r--r--Software/Android-Studio/Tango.Stubs/proguard-rules.pro25
-rw-r--r--Software/Android-Studio/Tango.Stubs/src/androidTest/java/com/twine/tango/stubs/ExampleInstrumentedTest.java26
-rw-r--r--Software/Android-Studio/Tango.Stubs/src/main/AndroidManifest.xml2
-rw-r--r--Software/Android-Studio/Tango.Stubs/src/main/java/com/twine/tango/stubs/Stub.java55
-rw-r--r--Software/Android-Studio/Tango.Stubs/src/main/java/com/twine/tango/stubs/machine/basic_communication.java35
-rw-r--r--Software/Android-Studio/Tango.Stubs/src/main/res/values/strings.xml3
-rw-r--r--Software/Android-Studio/Tango.Stubs/src/test/java/com/twine/tango/stubs/ExampleUnitTest.java17
-rw-r--r--Software/Android-Studio/build.gradle13
-rw-r--r--Software/Android-Studio/settings.gradle2
-rw-r--r--Software/Graphics/database.pngbin0 -> 2304 bytes
-rw-r--r--Software/Graphics/database.svg74
-rw-r--r--Software/Graphics/stubs.pngbin0 -> 2543 bytes
-rw-r--r--Software/Graphics/stubs.svg67
-rw-r--r--Software/PMR/Messages/Common/MessageContainer.proto3
46 files changed, 1233 insertions, 82 deletions
diff --git a/Software/Android-Studio/Tango.Integration/.gitignore b/Software/Android-Studio/Tango.Integration/.gitignore
new file mode 100644
index 000000000..796b96d1c
--- /dev/null
+++ b/Software/Android-Studio/Tango.Integration/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/Software/Android-Studio/Tango.Integration/build.gradle b/Software/Android-Studio/Tango.Integration/build.gradle
new file mode 100644
index 000000000..dc482d641
--- /dev/null
+++ b/Software/Android-Studio/Tango.Integration/build.gradle
@@ -0,0 +1,46 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 26
+ buildToolsVersion "26.0.1"
+
+
+ defaultConfig {
+ minSdkVersion 22
+ targetSdkVersion 26
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ dexOptions {
+ preDexLibraries = false
+ }
+}
+
+dependencies {
+ implementation fileTree(include: ['*.jar'], dir: 'libs')
+ implementation 'com.android.support:appcompat-v7:26.1.0'
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'com.android.support.test:runner:1.0.1'
+ androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
+ compile globalDependencies.rxJavaAndroid
+ compile globalDependencies.rxJava
+ compile globalDependencies.logging
+ compile globalDependencies.dagger
+ compile globalDependencies.daggerAndroid
+ implementation project(':Tango.PMR')
+}
diff --git a/Software/Android-Studio/Tango.Integration/proguard-rules.pro b/Software/Android-Studio/Tango.Integration/proguard-rules.pro
new file mode 100644
index 000000000..a0eef131a
--- /dev/null
+++ b/Software/Android-Studio/Tango.Integration/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in C:\Users\Roy\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/Software/Android-Studio/Tango.Integration/src/androidTest/java/com/twine/tango/integration/ExampleInstrumentedTest.java b/Software/Android-Studio/Tango.Integration/src/androidTest/java/com/twine/tango/integration/ExampleInstrumentedTest.java
new file mode 100644
index 000000000..52db49c5f
--- /dev/null
+++ b/Software/Android-Studio/Tango.Integration/src/androidTest/java/com/twine/tango/integration/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.twine.tango.integration;
+
+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.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() throws Exception {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("com.twine.tango.integration.test", appContext.getPackageName());
+ }
+}
diff --git a/Software/Android-Studio/Tango.Integration/src/main/AndroidManifest.xml b/Software/Android-Studio/Tango.Integration/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..b57dcb665
--- /dev/null
+++ b/Software/Android-Studio/Tango.Integration/src/main/AndroidManifest.xml
@@ -0,0 +1,6 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.twine.tango.integration">
+
+ <uses-permission android:name="android.permission.INTERNET"/>
+
+</manifest>
diff --git a/Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/adapters/SerialAdapter.java b/Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/adapters/SerialAdapter.java
new file mode 100644
index 000000000..5224a0729
--- /dev/null
+++ b/Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/adapters/SerialAdapter.java
@@ -0,0 +1,20 @@
+package com.twine.tango.integration.adapters;
+
+import java.io.IOException;
+
+import io.reactivex.Observable;
+
+/**
+ * Created by Roy on 11/8/2017.
+ */
+
+public interface SerialAdapter {
+
+ void setAddress(String address);
+ String getAddress();
+ void open() throws IOException;
+ void close() throws IOException;
+ void write(byte[] data) throws IOException;
+ Observable<byte[]> registerReceiveListener();
+ boolean getIsOpen();
+}
diff --git a/Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/adapters/TcpAdapter.java b/Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/adapters/TcpAdapter.java
new file mode 100644
index 000000000..3858b2c5f
--- /dev/null
+++ b/Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/adapters/TcpAdapter.java
@@ -0,0 +1,92 @@
+package com.twine.tango.integration.adapters;
+
+import android.os.SystemClock;
+import com.elvishew.xlog.XLog;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.Socket;
+import io.reactivex.Observable;
+import io.reactivex.schedulers.Schedulers;
+import io.reactivex.subjects.PublishSubject;
+
+/**
+ * Created by Roy on 11/8/2017.
+ */
+
+public class TcpAdapter implements SerialAdapter {
+
+ private Socket socket;
+ private String address;
+ private boolean isOpen;
+ private static final int port = 9999;
+ private Thread receiveThread;
+ private PublishSubject<byte[]> subject;
+
+ public TcpAdapter(String address) {
+ this.address = address;
+ }
+
+ @Override
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ @Override
+ public String getAddress() {
+ return this.address;
+ }
+
+ @Override
+ public void open() throws IOException {
+ socket = new Socket(address, port);
+ isOpen = true;
+ receiveThread = new Thread(this::receiveThreadMethod);
+ receiveThread.start();
+ }
+
+ @Override
+ public void close() throws IOException {
+ socket.close();
+ isOpen = false;
+ }
+
+ @Override
+ public void write(byte[] data) throws IOException {
+ socket.getOutputStream().write(data);
+ }
+
+ @Override
+ public Observable<byte[]> registerReceiveListener() {
+ subject = PublishSubject.create();
+ return subject.observeOn(Schedulers.io());
+ }
+
+ @Override
+ public boolean getIsOpen() {
+ return isOpen;
+ }
+
+ private void receiveThreadMethod() {
+ while (isOpen) {
+
+ try {
+
+ InputStream stream = socket.getInputStream();
+
+ if (stream.available() > 0)
+ {
+ byte[] data = new byte[stream.available()];
+ int read = stream.read(data);
+ if (subject != null && read > 0) subject.onNext(data);
+ }
+
+ } catch (Exception e) {
+ isOpen = false;
+ XLog.e(e);
+ if (subject != null) subject.onError(e);
+ }
+
+ SystemClock.sleep(10);
+ }
+ }
+}
diff --git a/Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/machine/MachineOperator.java b/Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/machine/MachineOperator.java
new file mode 100644
index 000000000..826a7a476
--- /dev/null
+++ b/Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/machine/MachineOperator.java
@@ -0,0 +1,244 @@
+package com.twine.tango.integration.machine;
+
+import android.os.SystemClock;
+import com.elvishew.xlog.XLog;
+import com.google.protobuf.GeneratedMessageV3;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.twine.tango.integration.adapters.SerialAdapter;
+import com.twine.tango.pmr.MessageFactory;
+import com.twine.tango.pmr.TangoMessage;
+import com.twine.tango.pmr.common.MessageContainerOuterClass.MessageContainer;
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+import java.util.Locale;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import javax.inject.Inject;
+
+import io.reactivex.Observable;
+import io.reactivex.Scheduler;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+import io.reactivex.subjects.PublishSubject;
+
+/**
+ * Created by Roy on 11/8/2017.
+ */
+
+public class MachineOperator implements MachineOperatorInterface {
+
+ private SerialAdapter channel;
+ private Calendar calendar;
+ private DateFormat dateFormatter;
+ private ConcurrentLinkedQueue<RequestMessage> requestsQueue;
+ private List<RequestMessage> pendingRequests;
+ private ConcurrentLinkedQueue<ResponseMessage> responsesQueue;
+ private PublishSubject<byte[]> receiveDataSubject;
+ private Thread pushThread;
+ private Thread pullThread;
+ private boolean isConnected;
+ private Scheduler ioScheduler;
+ private Scheduler uiScheduler;
+
+ @Inject
+ public MachineOperator(SerialAdapter channel) {
+
+ ioScheduler = Schedulers.io();
+ uiScheduler = AndroidSchedulers.mainThread();
+ calendar = Calendar.getInstance();
+ dateFormatter = new SimpleDateFormat("HH:mm:ss.SSS", Locale.US);
+ requestsQueue = new ConcurrentLinkedQueue<>();
+ pendingRequests = new ArrayList<>();
+ responsesQueue = new ConcurrentLinkedQueue<>();
+
+ setCommunicationChannel(channel);
+
+ connect().subscribe();
+ }
+
+ private void setCommunicationChannel(SerialAdapter channel) {
+ if (channel.getIsOpen()) {
+ try {
+ channel.close();
+ } catch (IOException e) {
+ XLog.e(e);
+ }
+ }
+
+ boolean reconnect = false;
+
+ if (isConnected) {
+ reconnect = true;
+ disconnect();
+ }
+
+ this.channel = channel;
+ this.channel.registerReceiveListener().subscribe((data) ->
+ {
+
+ try {
+ MessageContainer container = MessageContainer.parseFrom(data);
+
+ RequestMessage pendingRequest = Observable.fromIterable(pendingRequests).filter(x -> x.getToken().equals(container.getToken())).blockingFirst(null);
+
+ if (pendingRequest != null) {
+ pendingRequests.remove(pendingRequest);
+ responsesQueue.add(new ResponseMessage(pendingRequest.getSubject(), pendingRequest.getResponseClass(), data));
+ } else {
+ XLog.w("Could not find matching request for response: %s", container.getType().toString());
+ }
+ } catch (InvalidProtocolBufferException e) {
+ XLog.e(e);
+ }
+
+ if (receiveDataSubject != null)
+ {
+ receiveDataSubject.onNext(data);
+ }
+
+ });
+
+ if (reconnect) {
+ connect();
+ }
+ }
+
+ public <Request extends GeneratedMessageV3, Response extends GeneratedMessageV3> Observable<Response> send(TangoMessage<Request> message, Class<Response> className) {
+
+ PublishSubject<Response> subject = PublishSubject.create();
+ requestsQueue.add(new RequestMessage<>(subject, message, className, UUID.randomUUID().toString(), calendar.getTime()));
+ return subject.subscribeOn(ioScheduler).observeOn(uiScheduler);
+ }
+
+
+ @Override
+ public Observable connect() {
+
+ return Observable.create((x) ->
+ {
+ try {
+ channel.open();
+ isConnected = true;
+ startThreads();
+ x.onComplete();
+ } catch (Exception e) {
+ XLog.e("Could not connect to Tango machine.", e);
+ x.onError(e);
+ }
+
+ }).subscribeOn(ioScheduler).observeOn(uiScheduler);
+
+ }
+
+ @Override
+ public Observable disconnect() {
+
+ return Observable.create((x) ->
+ {
+ try {
+ channel.close();
+ isConnected = false;
+ x.onComplete();
+ stopThreads();
+ } catch (Exception e) {
+ XLog.e("Could not disconnect from Tango machine.", e);
+ x.onError(e);
+ }
+
+ }).subscribeOn(ioScheduler).observeOn(uiScheduler);
+
+ }
+
+ private void startThreads() {
+ pushThread = new Thread(this::pushThreadMethod, "Push Thread");
+ pushThread.start();
+
+ pullThread = new Thread(this::pullThreadMethod, "Pull Thread");
+ pullThread.start();
+ }
+
+ private void stopThreads() {
+ isConnected = false;
+ pullThread.interrupt();
+ pushThread.interrupt();
+ }
+
+ public void writeData(byte[] data)
+ {
+ try {
+ channel.write(data);
+ } catch (IOException e) {
+ XLog.e(e);
+ }
+ }
+
+ @Override
+ public Observable<byte[]> receiveData() {
+ receiveDataSubject = PublishSubject.create();
+ return receiveDataSubject.observeOn(uiScheduler).subscribeOn(ioScheduler);
+ }
+
+ private void pushThreadMethod() {
+
+ while (isConnected) {
+
+ if (requestsQueue.size() > 0) {
+ RequestMessage request = requestsQueue.poll();
+ if (request != null) {
+ pendingRequests.add(request);
+ try {
+ channel.write(request.getMessage().toBytes());
+ } catch (IOException e) {
+ isConnected = false;
+ XLog.e(e);
+ }
+ }
+ }
+
+ SystemClock.sleep(10);
+ }
+ }
+
+ private void pullThreadMethod() {
+ while (isConnected) {
+
+ if (responsesQueue.size() > 0) {
+ ResponseMessage response = responsesQueue.poll();
+ if (response != null) {
+
+ try {
+ TangoMessage message = MessageFactory.parseContainer(response.getData(), response.getResponseClass());
+ response.getSubject().onNext(message);
+ response.getSubject().onComplete();
+ } catch (Exception e) {
+ response.getSubject().onError(e);
+ XLog.e("Could not parse response.", e);
+ }
+
+ }
+ }
+
+ SystemClock.sleep(10);
+ }
+ }
+
+ private void postRequest(RequestMessage request) {
+
+// SystemClock.sleep(5000);
+//
+// TangoMessage<Job> jobTangoMessage = MessageFactory.createContainer(Job.class);
+//
+// jobTangoMessage.setMessage(Job.newBuilder().setName("Result Job").build());
+//
+// XLog.d("Posting result for request: %s TIME: %s", request.token, dateFormatter.format(request.dateTime));
+//
+// request.subject.onNext(jobTangoMessage.getMessage());
+//
+// request.subject.onComplete();
+ }
+}
diff --git a/Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/machine/MachineOperatorInterface.java b/Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/machine/MachineOperatorInterface.java
new file mode 100644
index 000000000..39e7e31d7
--- /dev/null
+++ b/Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/machine/MachineOperatorInterface.java
@@ -0,0 +1,19 @@
+package com.twine.tango.integration.machine;
+
+import com.google.protobuf.GeneratedMessageV3;
+import com.twine.tango.pmr.TangoMessage;
+
+import io.reactivex.Observable;
+
+/**
+ * Created by Roy on 11/8/2017.
+ */
+
+public interface MachineOperatorInterface {
+
+ <Request extends GeneratedMessageV3, Response extends GeneratedMessageV3> Observable<Response> send(TangoMessage<Request> message,Class<Response> className);
+ Observable connect();
+ Observable disconnect();
+ void writeData(byte[] data);
+ Observable<byte[]> receiveData();
+}
diff --git a/Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/machine/MessageBase.java b/Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/machine/MessageBase.java
new file mode 100644
index 000000000..c34e3653a
--- /dev/null
+++ b/Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/machine/MessageBase.java
@@ -0,0 +1,24 @@
+package com.twine.tango.integration.machine;
+
+import io.reactivex.subjects.PublishSubject;
+
+/**
+ * Created by Roy on 11/8/2017.
+ */
+
+public class MessageBase {
+
+ private PublishSubject subject;
+
+ public PublishSubject getSubject() {
+ return subject;
+ }
+
+ public void setSubject(PublishSubject subject) {
+ this.subject = subject;
+ }
+
+ public MessageBase(PublishSubject subject) {
+ this.subject = subject;
+ }
+}
diff --git a/Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/machine/RequestMessage.java b/Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/machine/RequestMessage.java
new file mode 100644
index 000000000..dde1ff765
--- /dev/null
+++ b/Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/machine/RequestMessage.java
@@ -0,0 +1,59 @@
+package com.twine.tango.integration.machine;
+
+import com.google.protobuf.GeneratedMessageV3;
+import com.twine.tango.pmr.TangoMessage;
+
+import java.util.Date;
+
+import io.reactivex.subjects.PublishSubject;
+
+/**
+ * Created by Roy on 11/8/2017.
+ */
+public class RequestMessage<T extends GeneratedMessageV3,Response extends GeneratedMessageV3> extends MessageBase {
+
+ private String token;
+ private Date dateTime;
+ private TangoMessage<T> message;
+ private Class<Response> responseClass;
+
+ public String getToken() {
+ return token;
+ }
+
+ public void setToken(String token) {
+ this.token = token;
+ }
+
+ public Date getDateTime() {
+ return dateTime;
+ }
+
+ public void setDateTime(Date dateTime) {
+ this.dateTime = dateTime;
+ }
+
+ public TangoMessage<T> getMessage() {
+ return message;
+ }
+
+ public void setMessage(TangoMessage<T> message) {
+ this.message = message;
+ }
+
+ public Class<Response> getResponseClass() {
+ return responseClass;
+ }
+
+ public void setResponseClass(Class<Response> responseClass) {
+ this.responseClass = responseClass;
+ }
+
+ public RequestMessage(PublishSubject subject, TangoMessage<T> message, Class<Response> responseClass, String token, Date time) {
+ super(subject);
+ this.message = message;
+ this.token = token;
+ this.dateTime = time;
+ this.responseClass = responseClass;
+ }
+}
diff --git a/Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/machine/ResponseMessage.java b/Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/machine/ResponseMessage.java
new file mode 100644
index 000000000..13de24286
--- /dev/null
+++ b/Software/Android-Studio/Tango.Integration/src/main/java/com/twine/tango/integration/machine/ResponseMessage.java
@@ -0,0 +1,37 @@
+package com.twine.tango.integration.machine;
+
+import com.twine.tango.pmr.TangoMessage;
+
+import io.reactivex.subjects.PublishSubject;
+
+/**
+ * Created by Roy on 11/8/2017.
+ */
+
+public class ResponseMessage extends MessageBase {
+
+ private byte[] data;
+ private Class<?> responseClass;
+
+ public byte[] getData() {
+ return data;
+ }
+
+ public void setData(byte[] data) {
+ this.data = data;
+ }
+
+ public Class<?> getResponseClass() {
+ return responseClass;
+ }
+
+ public void setResponseClass(Class<?> responseClass) {
+ this.responseClass = responseClass;
+ }
+
+ public ResponseMessage(PublishSubject subject, Class<?> responseClass, byte[] data) {
+ super(subject);
+ this.data = data;
+ this.responseClass = responseClass;
+ }
+}
diff --git a/Software/Android-Studio/Tango.Integration/src/main/res/values/strings.xml b/Software/Android-Studio/Tango.Integration/src/main/res/values/strings.xml
new file mode 100644
index 000000000..58ea29ec7
--- /dev/null
+++ b/Software/Android-Studio/Tango.Integration/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+ <string name="app_name">Tango.Integration</string>
+</resources>
diff --git a/Software/Android-Studio/Tango.Integration/src/test/java/com/twine/tango/integration/ExampleUnitTest.java b/Software/Android-Studio/Tango.Integration/src/test/java/com/twine/tango/integration/ExampleUnitTest.java
new file mode 100644
index 000000000..3bba564e2
--- /dev/null
+++ b/Software/Android-Studio/Tango.Integration/src/test/java/com/twine/tango/integration/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.twine.tango.integration;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() throws Exception {
+ assertEquals(4, 2 + 2);
+ }
+} \ No newline at end of file
diff --git a/Software/Android-Studio/Tango.Models/src/main/java/com/twine/tango/models/stubs/Stub.java b/Software/Android-Studio/Tango.Models/src/main/java/com/twine/tango/models/stubs/Stub.java
deleted file mode 100644
index 397c4b4e4..000000000
--- a/Software/Android-Studio/Tango.Models/src/main/java/com/twine/tango/models/stubs/Stub.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.twine.tango.models.stubs;
-
-import android.databinding.BaseObservable;
-import android.databinding.Bindable;
-import com.twine.tango.models.BR;
-
-/**
- * Created by Roy on 11/7/2017.
- */
-
-public class Stub extends BaseObservable {
-
- private String name;
- private String description;
-
- @Bindable
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- notifyPropertyChanged(BR.name);
- }
-
- @Bindable
- public String getDescription() {
- return description;
- }
-
- public void setDescription(String description) {
- this.description = description;
- notifyPropertyChanged(BR.description);
- }
-}
diff --git a/Software/Android-Studio/Tango.PMR/src/main/java/com/twine/tango/pmr/MessageFactory.java b/Software/Android-Studio/Tango.PMR/src/main/java/com/twine/tango/pmr/MessageFactory.java
index 2d33ed4db..f8f49c010 100644
--- a/Software/Android-Studio/Tango.PMR/src/main/java/com/twine/tango/pmr/MessageFactory.java
+++ b/Software/Android-Studio/Tango.PMR/src/main/java/com/twine/tango/pmr/MessageFactory.java
@@ -44,7 +44,8 @@ public class MessageFactory {
* @param <T> Type of expected inner message.
* @return New instance of {@link TangoMessage}.
*/
- public static <T extends com.google.protobuf.GeneratedMessageV3> TangoMessage<T> parseContainer(byte[] data, Class<T> typeName) {
+ @SuppressWarnings("unchecked")
+ public static <T extends com.google.protobuf.GeneratedMessageV3> TangoMessage<T> parseContainer(byte[] data, Class<?> typeName) {
try {
MessageContainer container = MessageContainer.parseFrom(data);
Parser<T> parser = (Parser<T>) typeName.getMethod("parser").invoke(null);
diff --git a/Software/Android-Studio/Tango.PMR/src/main/java/com/twine/tango/pmr/common/MessageContainerOuterClass.java b/Software/Android-Studio/Tango.PMR/src/main/java/com/twine/tango/pmr/common/MessageContainerOuterClass.java
index 6e6a3df01..24e2fc7f9 100644
--- a/Software/Android-Studio/Tango.PMR/src/main/java/com/twine/tango/pmr/common/MessageContainerOuterClass.java
+++ b/Software/Android-Studio/Tango.PMR/src/main/java/com/twine/tango/pmr/common/MessageContainerOuterClass.java
@@ -28,7 +28,17 @@ public final class MessageContainerOuterClass {
com.twine.tango.pmr.common.MessageTypeOuterClass.MessageType getType();
/**
- * <code>bytes Data = 2;</code>
+ * <code>string Token = 2;</code>
+ */
+ java.lang.String getToken();
+ /**
+ * <code>string Token = 2;</code>
+ */
+ com.google.protobuf.ByteString
+ getTokenBytes();
+
+ /**
+ * <code>bytes Data = 3;</code>
*/
com.google.protobuf.ByteString getData();
}
@@ -46,6 +56,7 @@ public final class MessageContainerOuterClass {
}
private MessageContainer() {
type_ = 0;
+ token_ = "";
data_ = com.google.protobuf.ByteString.EMPTY;
}
@@ -84,6 +95,12 @@ public final class MessageContainerOuterClass {
break;
}
case 18: {
+ java.lang.String s = input.readStringRequireUtf8();
+
+ token_ = s;
+ break;
+ }
+ case 26: {
data_ = input.readBytes();
break;
@@ -128,10 +145,44 @@ public final class MessageContainerOuterClass {
return result == null ? com.twine.tango.pmr.common.MessageTypeOuterClass.MessageType.UNRECOGNIZED : result;
}
- public static final int DATA_FIELD_NUMBER = 2;
+ public static final int TOKEN_FIELD_NUMBER = 2;
+ private volatile java.lang.Object token_;
+ /**
+ * <code>string Token = 2;</code>
+ */
+ public java.lang.String getToken() {
+ java.lang.Object ref = token_;
+ if (ref instanceof java.lang.String) {
+ return (java.lang.String) ref;
+ } else {
+ com.google.protobuf.ByteString bs =
+ (com.google.protobuf.ByteString) ref;
+ java.lang.String s = bs.toStringUtf8();
+ token_ = s;
+ return s;
+ }
+ }
+ /**
+ * <code>string Token = 2;</code>
+ */
+ public com.google.protobuf.ByteString
+ getTokenBytes() {
+ java.lang.Object ref = token_;
+ if (ref instanceof java.lang.String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ token_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+
+ public static final int DATA_FIELD_NUMBER = 3;
private com.google.protobuf.ByteString data_;
/**
- * <code>bytes Data = 2;</code>
+ * <code>bytes Data = 3;</code>
*/
public com.google.protobuf.ByteString getData() {
return data_;
@@ -152,8 +203,11 @@ public final class MessageContainerOuterClass {
if (type_ != com.twine.tango.pmr.common.MessageTypeOuterClass.MessageType.RGB.getNumber()) {
output.writeEnum(1, type_);
}
+ if (!getTokenBytes().isEmpty()) {
+ com.google.protobuf.GeneratedMessageV3.writeString(output, 2, token_);
+ }
if (!data_.isEmpty()) {
- output.writeBytes(2, data_);
+ output.writeBytes(3, data_);
}
unknownFields.writeTo(output);
}
@@ -167,9 +221,12 @@ public final class MessageContainerOuterClass {
size += com.google.protobuf.CodedOutputStream
.computeEnumSize(1, type_);
}
+ if (!getTokenBytes().isEmpty()) {
+ size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, token_);
+ }
if (!data_.isEmpty()) {
size += com.google.protobuf.CodedOutputStream
- .computeBytesSize(2, data_);
+ .computeBytesSize(3, data_);
}
size += unknownFields.getSerializedSize();
memoizedSize = size;
@@ -188,6 +245,8 @@ public final class MessageContainerOuterClass {
boolean result = true;
result = result && type_ == other.type_;
+ result = result && getToken()
+ .equals(other.getToken());
result = result && getData()
.equals(other.getData());
result = result && unknownFields.equals(other.unknownFields);
@@ -203,6 +262,8 @@ public final class MessageContainerOuterClass {
hash = (19 * hash) + getDescriptor().hashCode();
hash = (37 * hash) + TYPE_FIELD_NUMBER;
hash = (53 * hash) + type_;
+ hash = (37 * hash) + TOKEN_FIELD_NUMBER;
+ hash = (53 * hash) + getToken().hashCode();
hash = (37 * hash) + DATA_FIELD_NUMBER;
hash = (53 * hash) + getData().hashCode();
hash = (29 * hash) + unknownFields.hashCode();
@@ -336,6 +397,8 @@ public final class MessageContainerOuterClass {
super.clear();
type_ = 0;
+ token_ = "";
+
data_ = com.google.protobuf.ByteString.EMPTY;
return this;
@@ -361,6 +424,7 @@ public final class MessageContainerOuterClass {
public com.twine.tango.pmr.common.MessageContainerOuterClass.MessageContainer buildPartial() {
com.twine.tango.pmr.common.MessageContainerOuterClass.MessageContainer result = new com.twine.tango.pmr.common.MessageContainerOuterClass.MessageContainer(this);
result.type_ = type_;
+ result.token_ = token_;
result.data_ = data_;
onBuilt();
return result;
@@ -406,6 +470,10 @@ public final class MessageContainerOuterClass {
if (other.type_ != 0) {
setTypeValue(other.getTypeValue());
}
+ if (!other.getToken().isEmpty()) {
+ token_ = other.token_;
+ onChanged();
+ }
if (other.getData() != com.google.protobuf.ByteString.EMPTY) {
setData(other.getData());
}
@@ -480,15 +548,84 @@ public final class MessageContainerOuterClass {
return this;
}
+ private java.lang.Object token_ = "";
+ /**
+ * <code>string Token = 2;</code>
+ */
+ public java.lang.String getToken() {
+ java.lang.Object ref = token_;
+ if (!(ref instanceof java.lang.String)) {
+ com.google.protobuf.ByteString bs =
+ (com.google.protobuf.ByteString) ref;
+ java.lang.String s = bs.toStringUtf8();
+ token_ = s;
+ return s;
+ } else {
+ return (java.lang.String) ref;
+ }
+ }
+ /**
+ * <code>string Token = 2;</code>
+ */
+ public com.google.protobuf.ByteString
+ getTokenBytes() {
+ java.lang.Object ref = token_;
+ if (ref instanceof String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ token_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+ /**
+ * <code>string Token = 2;</code>
+ */
+ public Builder setToken(
+ java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+
+ token_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>string Token = 2;</code>
+ */
+ public Builder clearToken() {
+
+ token_ = getDefaultInstance().getToken();
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>string Token = 2;</code>
+ */
+ public Builder setTokenBytes(
+ com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ checkByteStringIsUtf8(value);
+
+ token_ = value;
+ onChanged();
+ return this;
+ }
+
private com.google.protobuf.ByteString data_ = com.google.protobuf.ByteString.EMPTY;
/**
- * <code>bytes Data = 2;</code>
+ * <code>bytes Data = 3;</code>
*/
public com.google.protobuf.ByteString getData() {
return data_;
}
/**
- * <code>bytes Data = 2;</code>
+ * <code>bytes Data = 3;</code>
*/
public Builder setData(com.google.protobuf.ByteString value) {
if (value == null) {
@@ -500,7 +637,7 @@ public final class MessageContainerOuterClass {
return this;
}
/**
- * <code>bytes Data = 2;</code>
+ * <code>bytes Data = 3;</code>
*/
public Builder clearData() {
@@ -572,10 +709,10 @@ public final class MessageContainerOuterClass {
static {
java.lang.String[] descriptorData = {
"\n\026MessageContainer.proto\022\020Tango.PMR.Comm" +
- "on\032\021MessageType.proto\"M\n\020MessageContaine" +
+ "on\032\021MessageType.proto\"\\\n\020MessageContaine" +
"r\022+\n\004Type\030\001 \001(\0162\035.Tango.PMR.Common.Messa" +
- "geType\022\014\n\004Data\030\002 \001(\014B\034\n\032com.twine.tango." +
- "pmr.commonb\006proto3"
+ "geType\022\r\n\005Token\030\002 \001(\t\022\014\n\004Data\030\003 \001(\014B\034\n\032c" +
+ "om.twine.tango.pmr.commonb\006proto3"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
@@ -595,7 +732,7 @@ public final class MessageContainerOuterClass {
internal_static_Tango_PMR_Common_MessageContainer_fieldAccessorTable = new
com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
internal_static_Tango_PMR_Common_MessageContainer_descriptor,
- new java.lang.String[] { "Type", "Data", });
+ new java.lang.String[] { "Type", "Token", "Data", });
com.twine.tango.pmr.common.MessageTypeOuterClass.getDescriptor();
}
diff --git a/Software/Android-Studio/Tango.Stubs.UI/build.gradle b/Software/Android-Studio/Tango.Stubs.UI/build.gradle
index 3dbe0dcd8..880cbd631 100644
--- a/Software/Android-Studio/Tango.Stubs.UI/build.gradle
+++ b/Software/Android-Studio/Tango.Stubs.UI/build.gradle
@@ -48,8 +48,8 @@ dependencies {
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
//Extensions
compile 'io.reactivex.rxjava2:rxjava:2.1.2'
- compile 'com.google.dagger:dagger:2.11'
- compile 'com.google.dagger:dagger-android:2.11'
+ compile globalDependencies.dagger
+ compile globalDependencies.daggerAndroid
compile 'com.squareup:otto:1.3.8'
compile 'me.tatarka.bindingcollectionadapter2:bindingcollectionadapter:2.2.0'
compile 'me.tatarka.bindingcollectionadapter2:bindingcollectionadapter-recyclerview:2.2.0'
@@ -60,4 +60,6 @@ dependencies {
annotationProcessor 'com.jakewharton:butterknife-compiler:8.7.0'
compile project(path: ':Tango.SharedUI')
implementation project(':Tango.Models')
+ implementation project(':Tango.Stubs')
+ implementation project(':Tango.Integration')
}
diff --git a/Software/Android-Studio/Tango.Stubs.UI/src/main/AndroidManifest.xml b/Software/Android-Studio/Tango.Stubs.UI/src/main/AndroidManifest.xml
index 172ff0b37..d609ad25d 100644
--- a/Software/Android-Studio/Tango.Stubs.UI/src/main/AndroidManifest.xml
+++ b/Software/Android-Studio/Tango.Stubs.UI/src/main/AndroidManifest.xml
@@ -2,6 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.twine.tango.stubs.ui">
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
<application
android:name=".App"
android:allowBackup="true"
diff --git a/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/App.java b/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/App.java
index 95363bd4c..e01ccf695 100644
--- a/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/App.java
+++ b/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/App.java
@@ -2,11 +2,24 @@ package com.twine.tango.stubs.ui;
import android.app.Application;
import android.content.Context;
+import android.os.Environment;
+import com.elvishew.xlog.LogConfiguration;
+import com.elvishew.xlog.LogLevel;
+import com.elvishew.xlog.XLog;
+import com.elvishew.xlog.formatter.message.object.ObjectFormatter;
+import com.elvishew.xlog.printer.AndroidPrinter;
+import com.elvishew.xlog.printer.Printer;
+import com.elvishew.xlog.printer.file.FilePrinter;
+import com.elvishew.xlog.printer.file.backup.FileSizeBackupStrategy;
+import com.elvishew.xlog.printer.file.naming.DateFileNameGenerator;
+import com.google.protobuf.GeneratedMessageV3;
import com.twine.tango.stubs.ui.dagger.ApplicationComponent;
import com.twine.tango.stubs.ui.dagger.ApplicationModule;
import com.twine.tango.stubs.ui.dagger.DaggerApplicationComponent;
+import java.io.File;
+
/**
* Created by Roy on 11/6/2017.
*/
@@ -20,8 +33,7 @@ public class App extends Application {
return appComponent;
}
- protected ApplicationComponent initDagger(App application)
- {
+ protected ApplicationComponent initDagger(App application) {
return DaggerApplicationComponent.builder().applicationModule(new ApplicationModule(application)).build();
}
@@ -30,15 +42,33 @@ public class App extends Application {
super.onCreate();
appComponent = initDagger(this);
context = getApplicationContext();
+
+ LogConfiguration config = new LogConfiguration.Builder()
+ .logLevel(LogLevel.ALL)
+ .tag("Tango")
+ .t()
+ .st(2)
+ .b()
+ .addObjectFormatter(GeneratedMessageV3.class, msg -> msg.toString()).build();
+
+ File sdcard = Environment.getExternalStorageDirectory();
+ File dir = new File(sdcard.getAbsolutePath() + "/twine/tango/logs");
+ boolean b = dir.mkdirs();
+
+ Printer androidPrinter = new AndroidPrinter();
+ Printer filePrinter = new FilePrinter.Builder(dir.getPath())
+ .fileNameGenerator(new DateFileNameGenerator())
+ .backupStrategy(new FileSizeBackupStrategy(1024 * 1024))
+ .build();
+
+ XLog.init(config, androidPrinter, filePrinter);
}
- public static ApplicationComponent getComponent()
- {
- return ((App)context).getAppComponent();
+ public static ApplicationComponent getComponent() {
+ return ((App) context).getAppComponent();
}
- public static Context getContext()
- {
+ public static Context getContext() {
return context;
}
}
diff --git a/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/Events/StubSelectedEvent.java b/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/Events/StubSelectedEvent.java
index 095971534..349251dd4 100644
--- a/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/Events/StubSelectedEvent.java
+++ b/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/Events/StubSelectedEvent.java
@@ -1,6 +1,6 @@
package com.twine.tango.stubs.ui.Events;
-import com.twine.tango.models.stubs.Stub;
+import com.twine.tango.stubs.Stub;
/**
* Created by Roy on 11/7/2017.
diff --git a/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/dagger/ApplicationComponent.java b/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/dagger/ApplicationComponent.java
index 70eb8d8c3..f567591e5 100644
--- a/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/dagger/ApplicationComponent.java
+++ b/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/dagger/ApplicationComponent.java
@@ -16,7 +16,7 @@ import dagger.Component;
*/
@Singleton
-@Component(modules = {ApplicationModule.class, ViewModelsModule.class, EventBusModule.class, NotificationModule.class})
+@Component(modules = {ApplicationModule.class, ViewModelsModule.class, EventBusModule.class, NotificationModule.class, IntegrationModule.class})
public interface ApplicationComponent {
void inject(MainActivity view);
diff --git a/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/dagger/IntegrationModule.java b/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/dagger/IntegrationModule.java
new file mode 100644
index 000000000..130c5661c
--- /dev/null
+++ b/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/dagger/IntegrationModule.java
@@ -0,0 +1,28 @@
+package com.twine.tango.stubs.ui.dagger;
+
+import com.twine.tango.integration.adapters.SerialAdapter;
+import com.twine.tango.integration.adapters.TcpAdapter;
+import com.twine.tango.integration.machine.MachineOperator;
+import com.twine.tango.integration.machine.MachineOperatorInterface;
+import javax.inject.Singleton;
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Created by Roy on 11/8/2017.
+ */
+
+@Module
+public class IntegrationModule {
+
+ @Provides
+ @Singleton
+ public MachineOperatorInterface provideMachineOperator(SerialAdapter serialAdapter) {
+ return new MachineOperator(serialAdapter);
+ }
+
+ @Provides
+ public SerialAdapter provideSerialAdapter() {
+ return new TcpAdapter("10.0.2.2");
+ }
+}
diff --git a/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/dagger/ViewModelsModule.java b/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/dagger/ViewModelsModule.java
index f684e2015..b146db02d 100644
--- a/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/dagger/ViewModelsModule.java
+++ b/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/dagger/ViewModelsModule.java
@@ -1,6 +1,7 @@
package com.twine.tango.stubs.ui.dagger;
import com.squareup.otto.Bus;
+import com.twine.tango.integration.machine.MachineOperatorInterface;
import com.twine.tango.sharedui.notifications.NotificationProvider;
import com.twine.tango.stubs.ui.views.login.LoginFragment;
import com.twine.tango.stubs.ui.views.login.LoginFragmentVM;
@@ -47,7 +48,7 @@ public class ViewModelsModule {
@Provides
@Singleton
- public StubActivityVM provideStubActivityVM(Bus eventBus, NotificationProvider notificationProvider) {
- return new StubActivityVM(eventBus, notificationProvider);
+ public StubActivityVM provideStubActivityVM(Bus eventBus, NotificationProvider notificationProvider, MachineOperatorInterface machineOperator) {
+ return new StubActivityVM(eventBus, notificationProvider, machineOperator);
}
}
diff --git a/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/views/stub/StubActivityVM.java b/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/views/stub/StubActivityVM.java
index 16fc1eafc..428cbc045 100644
--- a/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/views/stub/StubActivityVM.java
+++ b/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/views/stub/StubActivityVM.java
@@ -2,7 +2,9 @@ package com.twine.tango.stubs.ui.views.stub;
import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe;
-import com.twine.tango.models.stubs.Stub;
+import com.twine.tango.integration.machine.MachineOperatorInterface;
+import com.twine.tango.sharedui.mvvm.RelayCommand;
+import com.twine.tango.stubs.Stub;
import com.twine.tango.sharedui.mvvm.DependencyProperty;
import com.twine.tango.sharedui.mvvm.ViewModelBase;
import com.twine.tango.sharedui.notifications.NotificationProvider;
@@ -18,18 +20,21 @@ public class StubActivityVM extends ViewModelBase<StubActivityContract>
{
private Bus eventBus;
private NotificationProvider notificationProvider;
+ private MachineOperatorInterface machineOperator;
public DependencyProperty<Stub> stub;
- public DependencyProperty<String> ss;
+ public RelayCommand runCommand;
@Inject
- public StubActivityVM(Bus eventBus, NotificationProvider notificationProvider) {
+ public StubActivityVM(Bus eventBus, NotificationProvider notificationProvider, MachineOperatorInterface machineOperator) {
stub = new DependencyProperty<>();
- ss = new DependencyProperty<>("Hi ROy");
this.eventBus = eventBus;
+ this.machineOperator = machineOperator;
this.notificationProvider = notificationProvider;
this.eventBus.register(this);
+
+ runCommand = new RelayCommand(this::runSelectedStub);
}
@Subscribe
@@ -37,4 +42,10 @@ public class StubActivityVM extends ViewModelBase<StubActivityContract>
{
stub.set(e.getStub());
}
+
+ private void runSelectedStub()
+ {
+ stub.get().setMachineOperator(machineOperator);
+ stub.get().run();
+ }
}
diff --git a/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/views/stubs/StubsActivityContract.java b/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/views/stubs/StubsActivityContract.java
index fb189be32..52bfaa36f 100644
--- a/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/views/stubs/StubsActivityContract.java
+++ b/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/views/stubs/StubsActivityContract.java
@@ -1,6 +1,5 @@
package com.twine.tango.stubs.ui.views.stubs;
-import com.twine.tango.models.stubs.Stub;
import com.twine.tango.sharedui.mvvm.ViewContract;
/**
diff --git a/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/views/stubs/StubsActivityVM.java b/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/views/stubs/StubsActivityVM.java
index a22684698..ac4a8d6a9 100644
--- a/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/views/stubs/StubsActivityVM.java
+++ b/Software/Android-Studio/Tango.Stubs.UI/src/main/java/com/twine/tango/stubs/ui/views/stubs/StubsActivityVM.java
@@ -8,8 +8,8 @@ import android.view.View;
import android.widget.AdapterView;
import com.squareup.otto.Bus;
-import com.squareup.otto.Subscribe;
-import com.twine.tango.models.stubs.Stub;
+import com.twine.tango.sharedui.mvvm.RelayCommand;
+import com.twine.tango.stubs.Stub;
import com.twine.tango.sharedui.mvvm.FieldUtils;
import com.twine.tango.sharedui.mvvm.ViewModelBase;
import com.twine.tango.stubs.ui.BR;
@@ -43,12 +43,7 @@ public class StubsActivityVM extends ViewModelBase<StubsActivityContract> {
selectedStub = new ObservableField<>();
selectedStubIndex = FieldUtils.toField(FieldUtils.toObservable(selectedStub).map(stub -> stubs.indexOf(stub)));
- for (int i = 0; i < 20; i++) {
- Stub s = new Stub();
- s.setName("Stub " + i);
- s.setDescription("Description " + i);
- stubs.add(s);
- }
+ stubs.addAll(Stub.getAllStubs());
}
public void onStubSelected(AdapterView<?> adapterView, View view, int i, long l) {
diff --git a/Software/Android-Studio/Tango.Stubs.UI/src/main/res/layout/activity_stub.xml b/Software/Android-Studio/Tango.Stubs.UI/src/main/res/layout/activity_stub.xml
index fb9891f69..0db72ee5b 100644
--- a/Software/Android-Studio/Tango.Stubs.UI/src/main/res/layout/activity_stub.xml
+++ b/Software/Android-Studio/Tango.Stubs.UI/src/main/res/layout/activity_stub.xml
@@ -45,14 +45,14 @@
android:id="@+id/textView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="Stub Name"
+ android:text="@{vm.stub.name}"
android:textSize="18sp" />
<TextView
android:id="@+id/textView4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="Description" />
+ android:text="@{vm.stub.description}" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
@@ -129,7 +129,8 @@
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:tint="@color/colorPlay"
- bind:srcCompat="@drawable/ic_play" />
+ bind:srcCompat="@drawable/ic_play"
+ android:command="@{vm.runCommand}" />
<ImageButton
android:id="@+id/imageButton2"
diff --git a/Software/Android-Studio/Tango.Stubs.UI/src/main/res/layout/activity_stubs.xml b/Software/Android-Studio/Tango.Stubs.UI/src/main/res/layout/activity_stubs.xml
index bb0598073..20fc4aae7 100644
--- a/Software/Android-Studio/Tango.Stubs.UI/src/main/res/layout/activity_stubs.xml
+++ b/Software/Android-Studio/Tango.Stubs.UI/src/main/res/layout/activity_stubs.xml
@@ -22,7 +22,7 @@
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:onItemClick="@{vm::onStubSelected}"
- android:selectedItemPosition="@{vm.selectedStubIndex}"
+ android:selectedItemPosition="@{safeUnbox(vm.selectedStubIndex)}"
android:choiceMode="singleChoice"
app:items="@{vm.stubs}"
app:itemBinding="@{vm.stubBinding}"/>
diff --git a/Software/Android-Studio/Tango.Stubs.UI/src/main/res/layout/stubs_listview_item.xml b/Software/Android-Studio/Tango.Stubs.UI/src/main/res/layout/stubs_listview_item.xml
index 62edcb607..5696acdf3 100644
--- a/Software/Android-Studio/Tango.Stubs.UI/src/main/res/layout/stubs_listview_item.xml
+++ b/Software/Android-Studio/Tango.Stubs.UI/src/main/res/layout/stubs_listview_item.xml
@@ -5,7 +5,7 @@
<data>
<variable
name="stub"
- type="com.twine.tango.models.stubs.Stub"/>
+ type="com.twine.tango.stubs.Stub"/>
</data>
<LinearLayout
diff --git a/Software/Android-Studio/Tango.Stubs/.gitignore b/Software/Android-Studio/Tango.Stubs/.gitignore
new file mode 100644
index 000000000..796b96d1c
--- /dev/null
+++ b/Software/Android-Studio/Tango.Stubs/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/Software/Android-Studio/Tango.Stubs/build.gradle b/Software/Android-Studio/Tango.Stubs/build.gradle
new file mode 100644
index 000000000..05d5c6962
--- /dev/null
+++ b/Software/Android-Studio/Tango.Stubs/build.gradle
@@ -0,0 +1,43 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 26
+ buildToolsVersion "26.0.1"
+
+
+ defaultConfig {
+ minSdkVersion 22
+ targetSdkVersion 26
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ dataBinding {
+ enabled = true
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+dependencies {
+ implementation fileTree(include: ['*.jar'], dir: 'libs')
+ implementation 'com.android.support:appcompat-v7:26.1.0'
+ compile globalDependencies.logging
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'com.android.support.test:runner:1.0.1'
+ androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
+ implementation project(':Tango.Integration')
+ compile project(path: ':Tango.PMR')
+}
diff --git a/Software/Android-Studio/Tango.Stubs/proguard-rules.pro b/Software/Android-Studio/Tango.Stubs/proguard-rules.pro
new file mode 100644
index 000000000..a0eef131a
--- /dev/null
+++ b/Software/Android-Studio/Tango.Stubs/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in C:\Users\Roy\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/Software/Android-Studio/Tango.Stubs/src/androidTest/java/com/twine/tango/stubs/ExampleInstrumentedTest.java b/Software/Android-Studio/Tango.Stubs/src/androidTest/java/com/twine/tango/stubs/ExampleInstrumentedTest.java
new file mode 100644
index 000000000..b8283f5e3
--- /dev/null
+++ b/Software/Android-Studio/Tango.Stubs/src/androidTest/java/com/twine/tango/stubs/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.twine.tango.stubs;
+
+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.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() throws Exception {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("com.twine.tango.stubs.test", appContext.getPackageName());
+ }
+}
diff --git a/Software/Android-Studio/Tango.Stubs/src/main/AndroidManifest.xml b/Software/Android-Studio/Tango.Stubs/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..9e51ae77e
--- /dev/null
+++ b/Software/Android-Studio/Tango.Stubs/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.twine.tango.stubs" />
diff --git a/Software/Android-Studio/Tango.Stubs/src/main/java/com/twine/tango/stubs/Stub.java b/Software/Android-Studio/Tango.Stubs/src/main/java/com/twine/tango/stubs/Stub.java
new file mode 100644
index 000000000..329114e50
--- /dev/null
+++ b/Software/Android-Studio/Tango.Stubs/src/main/java/com/twine/tango/stubs/Stub.java
@@ -0,0 +1,55 @@
+package com.twine.tango.stubs;
+
+import android.databinding.BaseObservable;
+import android.databinding.Bindable;
+
+import com.twine.tango.integration.machine.MachineOperatorInterface;
+import com.twine.tango.stubs.machine.basic_communication;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by Roy on 11/7/2017.
+ */
+
+public abstract class Stub extends BaseObservable {
+
+ private String name;
+ private String description;
+ private MachineOperatorInterface machineOperator;
+
+ public MachineOperatorInterface getMachineOperator() {
+ return machineOperator;
+ }
+
+ public void setMachineOperator(MachineOperatorInterface machineOperator) {
+ this.machineOperator = machineOperator;
+ }
+
+ @Bindable
+ public String getName() {
+ return name;
+ }
+
+ @Bindable
+ public String getDescription() {
+ return description;
+ }
+
+ public Stub(String name, String description) {
+ this.name = name;
+ this.description = description;
+ }
+
+ public abstract void run();
+
+
+ public static List<Stub> getAllStubs()
+ {
+ List<Stub> stubs = new ArrayList<>();
+
+ stubs.add(new basic_communication());
+
+ return stubs;
+ }
+}
diff --git a/Software/Android-Studio/Tango.Stubs/src/main/java/com/twine/tango/stubs/machine/basic_communication.java b/Software/Android-Studio/Tango.Stubs/src/main/java/com/twine/tango/stubs/machine/basic_communication.java
new file mode 100644
index 000000000..4633421de
--- /dev/null
+++ b/Software/Android-Studio/Tango.Stubs/src/main/java/com/twine/tango/stubs/machine/basic_communication.java
@@ -0,0 +1,35 @@
+package com.twine.tango.stubs.machine;
+
+import com.elvishew.xlog.XLog;
+import com.twine.tango.stubs.Stub;
+
+/**
+ * Created by Roy on 11/8/2017.
+ */
+
+public class basic_communication extends Stub {
+
+
+ public basic_communication() {
+ super("Basic Communication", "Open the serial port and send a test string");
+ }
+
+ @Override
+ public void run() {
+
+// for (int i = 0; i < 20; i++) {
+// machine.send(MessageFactory.createContainer(Job.class), Job.class).subscribe((job) ->
+// {
+// String name = job.getName();
+// });
+// }
+
+ getMachineOperator().receiveData().subscribe((data) ->
+ {
+ XLog.i(new String(data));
+ });
+
+ String test = "This is a test...";
+ getMachineOperator().writeData(test.getBytes());
+ }
+}
diff --git a/Software/Android-Studio/Tango.Stubs/src/main/res/values/strings.xml b/Software/Android-Studio/Tango.Stubs/src/main/res/values/strings.xml
new file mode 100644
index 000000000..62b1a5fd0
--- /dev/null
+++ b/Software/Android-Studio/Tango.Stubs/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+ <string name="app_name">Tango.Stubs</string>
+</resources>
diff --git a/Software/Android-Studio/Tango.Stubs/src/test/java/com/twine/tango/stubs/ExampleUnitTest.java b/Software/Android-Studio/Tango.Stubs/src/test/java/com/twine/tango/stubs/ExampleUnitTest.java
new file mode 100644
index 000000000..d111c04aa
--- /dev/null
+++ b/Software/Android-Studio/Tango.Stubs/src/test/java/com/twine/tango/stubs/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.twine.tango.stubs;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() throws Exception {
+ assertEquals(4, 2 + 2);
+ }
+} \ No newline at end of file
diff --git a/Software/Android-Studio/build.gradle b/Software/Android-Studio/build.gradle
index 0e2d08bbb..81ab73c7f 100644
--- a/Software/Android-Studio/build.gradle
+++ b/Software/Android-Studio/build.gradle
@@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
-
+
repositories {
google()
jcenter()
@@ -22,6 +22,17 @@ allprojects {
}
}
+ext {
+ //Support Libraries dependencies
+ globalDependencies = [
+ logging : 'com.elvishew:xlog:1.4.0',
+ rxJavaAndroid: 'io.reactivex.rxjava2:rxandroid:2.0.1',
+ rxJava : 'io.reactivex.rxjava2:rxjava:2.1.5',
+ dagger : 'com.google.dagger:dagger:2.11',
+ daggerAndroid: 'com.google.dagger:dagger-android:2.11',
+ ]
+}
+
task clean(type: Delete) {
delete rootProject.buildDir
}
diff --git a/Software/Android-Studio/settings.gradle b/Software/Android-Studio/settings.gradle
index 4a207ac0e..741bbf8c1 100644
--- a/Software/Android-Studio/settings.gradle
+++ b/Software/Android-Studio/settings.gradle
@@ -1 +1 @@
-include ':app', ':Tango.PMR', ':Tango.BL', ':Tango.Stubs.UI', ':Tango.Core', ':Tango.SharedUI', ':Tango.DAL', ':Tango.Models'
+include ':app', ':Tango.PMR', ':Tango.BL', ':Tango.Stubs.UI', ':Tango.Core', ':Tango.SharedUI', ':Tango.DAL', ':Tango.Models', ':Tango.Stubs', ':Tango.Integration'
diff --git a/Software/Graphics/database.png b/Software/Graphics/database.png
new file mode 100644
index 000000000..4263288e8
--- /dev/null
+++ b/Software/Graphics/database.png
Binary files differ
diff --git a/Software/Graphics/database.svg b/Software/Graphics/database.svg
new file mode 100644
index 000000000..6dfb37069
--- /dev/null
+++ b/Software/Graphics/database.svg
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 57 57" style="enable-background:new 0 0 57 57;" xml:space="preserve">
+<g>
+ <g>
+ <path style="fill:#545E73;" d="M49.455,8L49.455,8C48.724,3.538,38.281,0,25.5,0S2.276,3.538,1.545,8l0,0H1.5v0.5V20v0.5V21v11
+ v0.5V33v12h0.045c0.731,4.461,11.175,8,23.955,8s23.224-3.539,23.955-8H49.5V33v-0.5V32V21v-0.5V20V8.5V8H49.455z"/>
+ <g>
+ <path style="fill:#38454F;" d="M25.5,41c-13.255,0-24-3.806-24-8.5V45h0.045c0.731,4.461,11.175,8,23.955,8
+ s23.224-3.539,23.955-8H49.5V32.5C49.5,37.194,38.755,41,25.5,41z"/>
+ <path style="fill:#38454F;" d="M1.5,32v0.5c0-0.168,0.018-0.334,0.045-0.5H1.5z"/>
+ <path style="fill:#38454F;" d="M49.455,32c0.027,0.166,0.045,0.332,0.045,0.5V32H49.455z"/>
+ </g>
+ <g>
+ <path style="fill:#556080;" d="M25.5,29c-13.255,0-24-3.806-24-8.5V33h0.045c0.731,4.461,11.175,8,23.955,8
+ s23.224-3.539,23.955-8H49.5V20.5C49.5,25.194,38.755,29,25.5,29z"/>
+ <path style="fill:#556080;" d="M1.5,20v0.5c0-0.168,0.018-0.334,0.045-0.5H1.5z"/>
+ <path style="fill:#556080;" d="M49.455,20c0.027,0.166,0.045,0.332,0.045,0.5V20H49.455z"/>
+ </g>
+ <ellipse style="fill:#91BAE1;" cx="25.5" cy="8.5" rx="24" ry="8.5"/>
+ <g>
+ <path style="fill:#8697CB;" d="M25.5,17c-13.255,0-24-3.806-24-8.5V21h0.045c0.731,4.461,11.175,8,23.955,8
+ s23.224-3.539,23.955-8H49.5V8.5C49.5,13.194,38.755,17,25.5,17z"/>
+ <path style="fill:#8697CB;" d="M1.5,8v0.5c0-0.168,0.018-0.334,0.045-0.5H1.5z"/>
+ <path style="fill:#8697CB;" d="M49.455,8C49.482,8.166,49.5,8.332,49.5,8.5V8H49.455z"/>
+ </g>
+ </g>
+ <g>
+ <path style="fill:#BDC3C7;" d="M55.5,43.846l-1.444-0.278c-2.143-0.412-3.125-2.916-1.835-4.675l0.907-1.236l-1.958-1.958
+ l-1.217,0.825c-1.806,1.224-4.272,0.148-4.604-2.008L45.115,33h-2.769l-0.359,1.865c-0.403,2.096-2.818,3.096-4.585,1.899
+ l-1.572-1.065l-1.958,1.958l0.907,1.236c1.29,1.76,0.308,4.263-1.835,4.675L31.5,43.846v2.769l1.515,0.233
+ c2.157,0.332,3.232,2.797,2.008,4.604l-0.825,1.217l1.958,1.958l1.236-0.907c1.76-1.29,4.263-0.308,4.675,1.835L42.346,57h2.769
+ l0.164-1.066c0.339-2.204,2.896-3.263,4.694-1.944l0.869,0.638l1.958-1.958l-0.825-1.217c-1.224-1.806-0.148-4.272,2.008-4.604
+ l1.515-0.233V43.846z"/>
+ <g>
+ <circle style="fill:#FFFFFF;" cx="43.5" cy="45" r="4"/>
+ <path style="fill:#ECF0F1;" d="M43.5,50c-2.757,0-5-2.243-5-5s2.243-5,5-5s5,2.243,5,5S46.257,50,43.5,50z M43.5,42
+ c-1.654,0-3,1.346-3,3s1.346,3,3,3s3-1.346,3-3S45.154,42,43.5,42z"/>
+ </g>
+ </g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>
diff --git a/Software/Graphics/stubs.png b/Software/Graphics/stubs.png
new file mode 100644
index 000000000..5d6249d61
--- /dev/null
+++ b/Software/Graphics/stubs.png
Binary files differ
diff --git a/Software/Graphics/stubs.svg b/Software/Graphics/stubs.svg
new file mode 100644
index 000000000..800acead5
--- /dev/null
+++ b/Software/Graphics/stubs.svg
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 504.123 504.123" style="enable-background:new 0 0 504.123 504.123;" xml:space="preserve">
+<path style="fill:#415F6F;" d="M486.006,355.446l18.117-10.24c-1.182-6.695-2.757-13.391-5.12-20.086h-20.874l-11.422-20.086
+ l10.634-18.117c-4.332-5.12-9.058-10.24-14.572-14.572l-18.117,10.24l-20.086-11.815v-20.874c-0.394,0-0.788-0.394-1.575-0.394
+ c-5.908-1.969-12.209-3.938-18.511-5.12l-10.634,18.117h-23.237l-10.24-18.117c-6.695,1.182-13.391,2.757-20.086,5.12v20.874
+ l-20.086,11.422l-18.117-10.634c-5.12,4.332-10.24,9.058-14.572,14.572l10.24,18.117l-11.815,20.086h-20.874
+ c-2.363,6.695-4.332,12.997-5.514,19.692l18.117,10.634v23.237l-18.117,10.24c1.182,6.695,2.757,13.391,5.12,20.086h20.874
+ l11.422,20.086l-10.634,18.117c4.332,5.12,9.058,10.24,14.572,14.572l18.117-10.24l20.086,11.815v20.874
+ c0.394,0,0.788,0.394,1.575,0.394c5.908,1.969,12.209,3.938,18.511,5.12l10.634-18.117h23.237l10.24,18.117
+ c6.695-1.182,13.391-2.757,20.086-5.12v-20.874l20.086-11.422l18.117,10.634c5.12-4.332,10.24-9.058,14.572-14.572l-10.24-18.117
+ l11.815-20.086h20.874c2.363-6.695,4.332-12.997,5.514-19.692l-18.117-10.634V355.446z M382.031,435.003
+ c-37.809,0-68.923-30.72-68.923-68.529s30.72-68.923,68.923-68.923c37.809,0,68.923,30.72,68.923,68.529
+ S419.84,435.003,382.031,435.003z"/>
+<path style="fill:#26A6D1;" d="M274.905,240.049c0-7.483-0.394-15.36-1.575-22.843l-22.449-4.726l-8.271-24.418l15.36-17.329
+ c-3.545-6.695-7.877-12.997-12.603-18.905l-22.055,7.483l-19.298-16.935l4.726-22.843c-6.695-3.938-13.391-7.483-20.48-10.24
+ l-14.966,17.329l-25.206-5.12l-7.483-22.055c-7.483,0-15.36,0.394-22.843,1.575l-4.726,22.449l-24.418,8.271l-17.329-15.36
+ c-6.695,3.545-12.997,7.877-18.905,12.603l7.483,22.055l-16.935,19.298l-22.843-4.726c-3.938,6.695-7.483,13.391-10.24,20.48
+ l17.329,15.36l-5.12,25.206L0,233.748c0,7.483,0.394,15.36,1.575,22.843l22.843,4.726l8.271,24.418l-15.36,17.329
+ c3.545,6.695,7.877,12.997,12.603,18.905l22.055-7.483l19.298,16.935l-5.12,22.843c6.695,3.938,13.391,7.483,20.48,10.24
+ l15.36-17.329l25.206,5.12l7.483,22.055c7.483,0,15.36-0.394,22.843-1.575l4.726-22.449l24.418-8.271l17.329,15.36
+ c6.695-3.545,12.997-7.877,18.905-12.603l-7.483-22.055l16.935-19.298l22.843,4.726c3.938-6.695,7.483-13.391,10.24-20.48
+ l-17.329-15.36l5.12-25.206L274.905,240.049L274.905,240.049z M137.452,312.911c-42.142,0-76.406-34.265-76.406-76.406
+ s34.265-76.406,76.406-76.406s76.406,34.265,76.406,76.406S179.594,312.911,137.452,312.911z"/>
+<path style="fill:#638090;" d="M456.862,125.046l16.542-6.695c-0.394-5.908-1.182-11.815-2.363-17.723l-17.723-2.363l-7.483-18.511
+ l11.028-14.178c-3.151-5.12-6.695-9.846-10.634-14.178l-16.542,6.695l-15.754-12.209l2.363-17.723l-1.182-0.788
+ c-5.12-2.363-10.24-4.726-15.36-6.302l-11.028,14.178l-19.692-2.757l-6.695-16.935c-5.908,0.394-11.815,0.788-17.723,1.969
+ l-2.363,17.723l-18.905,7.877L309.17,32.098c-5.12,3.151-9.846,6.695-14.178,10.634l6.695,16.542l-12.209,15.754l-17.723-2.363
+ c-2.757,5.12-5.12,10.634-7.089,16.542l14.178,11.028l-2.757,19.692l-16.542,6.695c0.394,5.908,1.182,11.815,2.363,17.723
+ l17.723,2.363l7.483,18.511l-11.028,14.178c3.151,5.12,6.695,9.846,10.634,14.178l16.542-6.695l15.754,12.209l-2.363,17.723
+ l1.182,0.788c5.12,2.363,10.24,4.726,15.36,6.302l11.028-14.178l19.692,2.757l6.695,16.542c5.908-0.394,11.815-0.788,17.723-2.363
+ l2.363-17.723l18.511-7.483l14.178,11.028c5.12-3.151,9.846-6.695,14.178-10.634l-6.695-16.542l12.209-15.754l17.723,2.363
+ c2.757-5.12,5.12-10.634,7.089-16.542l-14.178-11.028C453.711,144.345,456.862,125.046,456.862,125.046z M366.671,183.335
+ c-33.871,0-61.046-27.175-61.046-61.046s27.175-61.046,61.046-61.046s61.046,27.175,61.046,61.046S400.542,183.335,366.671,183.335z
+ "/>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>
diff --git a/Software/PMR/Messages/Common/MessageContainer.proto b/Software/PMR/Messages/Common/MessageContainer.proto
index ac76d28dd..ae507822f 100644
--- a/Software/PMR/Messages/Common/MessageContainer.proto
+++ b/Software/PMR/Messages/Common/MessageContainer.proto
@@ -8,6 +8,7 @@ import "MessageType.proto";
message MessageContainer
{
MessageType Type = 1;
- bytes Data = 2;
+ string Token = 2;
+ bytes Data = 3;
}