From ba52fd2c530a397b83a23a99ed2465844a5d1d8f Mon Sep 17 00:00:00 2001
From: kjunge <kai.junge@epfl.ch>
Date: Fri, 15 Apr 2022 10:57:44 +0200
Subject: [PATCH] Windows solution did not work on ubutntu. Testing to see if
 python->arduino works fine on both machines.

---
 comms_wrapper.py                |   2 -
 comms_wrapper_new.py            |  10 +-
 comms_wrapper_original.py       | 273 ++++++++++++++++++++++++++++++++
 test_original.py                |  40 +++++
 test_original/pyCommsLib.cpp    |  78 +++++++++
 test_original/pyCommsLib.h      |  17 ++
 test_original/test_original.ino |  37 +++++
 test_windows.py                 |  23 +--
 test_windows/pyCommsLib.cpp     |  12 +-
 test_windows/test_windows.ino   |  13 +-
 10 files changed, 466 insertions(+), 39 deletions(-)
 create mode 100644 comms_wrapper_original.py
 create mode 100644 test_original.py
 create mode 100644 test_original/pyCommsLib.cpp
 create mode 100644 test_original/pyCommsLib.h
 create mode 100644 test_original/test_original.ino

diff --git a/comms_wrapper.py b/comms_wrapper.py
index 5377bf2..978bf14 100644
--- a/comms_wrapper.py
+++ b/comms_wrapper.py
@@ -66,8 +66,6 @@ class Arduino:
             self.arduino.dtr = False
 
             self.connectionStatus = True
-
-            self.arduino.set_buffer_size(rx_size = 1280000, tx_size = 1280000)
         
             print("Successfully connected to " + self.descriptiveDeviceName)
             return True
diff --git a/comms_wrapper_new.py b/comms_wrapper_new.py
index 463e158..afcf9cb 100644
--- a/comms_wrapper_new.py
+++ b/comms_wrapper_new.py
@@ -76,8 +76,6 @@ class Arduino:
 
             self.connectionStatus = True
 
-            self.arduino.set_buffer_size(rx_size = 1280000, tx_size = 1280000)
-
             print("Successfully connected to " + self.descriptiveDeviceName)
             return True
         except:
@@ -110,7 +108,7 @@ class Arduino:
         # Conduct handshake
         while time.time() - timeoutTimer < handshakeTimeoutSec:
             self._serial_write("handshake1\n")
-            time.sleep(0.1)
+            #time.sleep(0.1)
 
             if self._rawReceivedMessage == "handshake2":
                 self.handshakeStatus = True
@@ -137,13 +135,11 @@ class Arduino:
                 payload += str(msg)
                 payload += "@"
 
-            payload = "#####" + payload[:-1] + "%"
+            payload = "#####" + payload[:-1] + "\n"
             
             if payload != self._prev_payload:
                 self._prev_payload = payload
-                for i in range(2):
-                    self._serial_write(payload)
-                    time.sleep(0.1)
+                self._serial_write(payload)
 
     def receive_message(self, printOutput = False, verbose = False):
         if not self.handshakeStatus:
diff --git a/comms_wrapper_original.py b/comms_wrapper_original.py
new file mode 100644
index 0000000..978bf14
--- /dev/null
+++ b/comms_wrapper_original.py
@@ -0,0 +1,273 @@
+import serial
+import serial.tools.list_ports
+from threading import Thread
+import time
+from pynput import keyboard
+import copy
+
+########
+### Arduino communication
+########
+
+class Arduino: 
+    def __init__(self, descriptiveDeviceName, portName, baudrate): 
+        # About the device
+        self.descriptiveDeviceName = descriptiveDeviceName
+        self.portName = portName
+        self.baudrate = baudrate
+        
+        # Communication
+        self._rawReceivedMessage = None
+        self.receivedMessages = {}
+        self.messageNames = None
+        self.arduino = None
+        self.handshakeStatus = False
+        self.connectionStatus = False
+        self._echo_python_msg = None
+        self.newMsgRecieved = False
+
+        # Threading
+        self.__thread = None
+
+    # Private methods
+    def _serial_readline(self):
+        while 1:
+            try:
+                self._rawReceivedMessage = self.arduino.readline().decode('utf-8')[:-2]
+            except:
+                time.sleep(0.000001)
+
+    def _startReadingThread(self):
+        self.__thread = Thread(target=self._serial_readline)
+        self.__thread.daemon = True
+        self.__thread.start()
+
+
+    def _serial_write(self, msg):
+        if self.arduino is not None:
+            self.arduino.write(bytes(msg, 'utf-8'))
+
+
+    def _add_new_message_name(self, msgName):
+        if msgName in self.receivedMessages:
+            print("!! Message name ", msgName, " already exists so it cannot be added. !!")
+        else:
+            self.receivedMessages[msgName] = None
+            self.messageNames = list(self.receivedMessages.keys())
+
+
+    def _connect_to_arduino(self):
+        # Connect to the arduino device
+        try: 
+            self.arduino = serial.Serial(port=self.portName, baudrate=self.baudrate)
+
+            # toggle dtr to reset the arduino
+            self.arduino.dtr = True
+            self.arduino.dtr = False
+
+            self.connectionStatus = True
+        
+            print("Successfully connected to " + self.descriptiveDeviceName)
+            return True
+        except:
+            print("!! Cannot connect to " + self.descriptiveDeviceName + " !!")
+            return False
+        
+
+    def _disect_and_save_message(self, msg):
+        receivedMessageTemp = copy.deepcopy(self.receivedMessages)
+
+        if msg[-2] != ":":
+            return False
+
+        msg = msg[1:-2]
+        splitMsg = msg.split(":")
+        for singleMsg in splitMsg:
+            if len(singleMsg.split(";")) == 2:
+                msgName = singleMsg.split(";")[0]
+                msgPayload = singleMsg.split(";")[1]
+
+                if msgName == "e*p":
+                        self._echo_python_msg = msgPayload
+                else:
+                    if msgName not in self.messageNames:
+                        return False
+                    
+                    receivedMessageTemp[msgName] = msgPayload
+
+            else:
+                return False
+        
+        if receivedMessageTemp == self.receivedMessages: 
+            self.newMsgRecieved = False
+        else: 
+            self.newMsgRecieved = True
+        
+        self.receivedMessages = receivedMessageTemp
+        return True
+
+        
+    # Public methods
+    def define_message_names(self, msgNames):
+        if type(msgNames) == list:
+            for msg in msgNames:
+                self._add_new_message_name(msg) 
+        else: 
+            print("Argument should be of type 'list'")
+
+
+    def connect_and_handshake(self): 
+        # Connect to the arduino device
+
+        if self._connect_to_arduino():
+            pass
+        else:
+            return False
+
+        # Start the reading thread
+        self._startReadingThread()
+        
+        # Wait for a bit for the arduino to initialise nicely
+        time.sleep(0.5)
+
+        # Conduct the handshake process
+        timeoutTimer = time.time()
+        handshakeTimeoutSec = 5
+
+        self.arduino.reset_input_buffer()
+        self.arduino.reset_output_buffer()
+
+
+        while time.time() - timeoutTimer < handshakeTimeoutSec:
+            self._serial_write("handshake1\n")
+            time.sleep(0.1)
+
+            if self._rawReceivedMessage == "handshake2":
+                self.handshakeStatus = True
+                break
+
+        if self.handshakeStatus: 
+            # while 1: 
+            #     self.receive_message()
+            #     if self._echo_python_msg == "NO_PYTHON_MESSAGE":
+            #         break
+            print("Successfull handshake with " + self.descriptiveDeviceName)
+            time.sleep(1)
+        else:
+            print("!! Handshake failed with " + self.descriptiveDeviceName + " !!")
+
+        return self.handshakeStatus
+
+
+    def disconnect_arduino(self):
+        self.arduino.close()
+
+
+    def send_message(self, msg):
+        self._serial_write( msg + "\n")
+
+
+    def receive_message(self, printOutput = False, verbose = False):
+        if not self.handshakeStatus:
+            print("!! Handshake not completed !!")
+            return False
+        else:
+            isMessageValid = True
+            msg = self._rawReceivedMessage
+            # sanity check 1: check if ends of the message are < and >
+            try:
+                if msg[0] == "<" and msg[-1] == ">":
+                    pass
+                else:
+                    isMessageValid = False
+            except:
+                isMessageValid = False
+            if isMessageValid:
+                isMessageValid = self._disect_and_save_message(msg)
+            else:
+                pass
+            
+            if printOutput: 
+                if verbose: 
+                    print("----------------------")
+                    print("Raw message received on python side: ", self._rawReceivedMessage)
+                    print("Messege received from the arduino: ", self.receivedMessages)
+                    print("Python message stored on", self.descriptiveDeviceName, ": ", self._echo_python_msg, "\n")
+
+                else:
+                    print("Messege received from the arduino: ", self.receivedMessages)
+
+            time.sleep(0.0001)
+            return True
+
+
+    def current_status(self):
+        status = {
+            "Device name" : self.descriptiveDeviceName, 
+            "Baudrate: ": self.baudrate,
+            "Portname: ": self.portName, 
+            "Connection: ": self.connectionStatus, 
+            "Handshake: ": self.handshakeStatus, 
+            "Message names: ": self.messageNames
+            }
+
+        return status
+    
+
+    def debug(self, verbose = False):
+        if verbose:   
+            self.receive_message(printOutput=True, verbose = True)
+
+            print("Current status of this device:")
+            print(self.current_status())
+            
+        else:
+            print("----------------------")
+            self.receive_message(printOutput=True)
+            print("Python message stored on", self.descriptiveDeviceName, ": ", self._echo_python_msg, "\n")
+            
+
+        for key, value in self.receivedMessages.items():
+            if value is None: 
+                print("Check if message names: ", key, " agrees with the arduino side")
+
+
+########
+### Key commands
+########
+
+class Key():
+    def __init__(self):                
+        self.keyPressLatching = None
+        self._keyReleaseLatching = None
+        self.keyPress = None
+        self._start_keyboard_listener()
+
+    def _on_press(self, key):
+        try:
+            self.keyPressLatching = key.char
+            self.keyPress = key.char
+            
+        except AttributeError:
+            self.keyPressLatching = key
+            self.keyPress = key
+            
+
+    def _on_release(self, key):
+        try:
+            self._keyReleaseLatching = key.char
+
+            if self._keyReleaseLatching == self.keyPress: 
+                self.keyPress = None
+
+        except AttributeError:
+            self._keyReleaseLatching = key
+
+            if self._keyReleaseLatching == self.keyPress: 
+                self.keyPress = None
+
+
+    def _start_keyboard_listener(self):  
+        listener = keyboard.Listener(on_press=self._on_press, on_release=self._on_release)
+        listener.start()
+        print("keyboard listener started")
\ No newline at end of file
diff --git a/test_original.py b/test_original.py
new file mode 100644
index 0000000..848ac76
--- /dev/null
+++ b/test_original.py
@@ -0,0 +1,40 @@
+from comms_wrapper_original import *
+from time import sleep, time
+
+def main():
+    key = Key()
+
+
+    ad = Arduino(descriptiveDeviceName="myArduino", portName="/dev/ttyACM0", baudrate=115200)
+
+    #ad.define_message_names(["msgA", "msgB"])
+
+    ad.connect_and_handshake()
+
+    timer = time()
+    while 1: 
+    
+        # ad.receive_message()
+        # print(ad.receivedMessages)
+
+        if key.keyPress == "f": 
+            ad.send_message("apples")
+            #arduino2.send_message("oranges")
+
+        if key.keyPress == "g":
+            ad.send_message("bananas")
+            #arduino2.send_message("grapes")
+        t = str(round(time() - timer, 5))
+        while 1: 
+            if len(t) < 5:
+                t += "0"
+            elif len(t) > 5: 
+                t = t[:-1]
+            else: 
+                break
+        ad.send_message(str(t))
+
+        print(ad._rawReceivedMessage)
+
+if __name__ == '__main__':
+    main()
\ No newline at end of file
diff --git a/test_original/pyCommsLib.cpp b/test_original/pyCommsLib.cpp
new file mode 100644
index 0000000..cb2d4b3
--- /dev/null
+++ b/test_original/pyCommsLib.cpp
@@ -0,0 +1,78 @@
+#include "pyCommsLib.h"
+#include "Arduino.h"
+
+
+#define size_of_array(arr) sizeof(arr) / sizeof(*arr)
+
+
+String rawMsgFromPython = "NO_PYTHON_MESSAGE";
+String payload = "";
+
+
+void load_msg_to_python(String* msgName, String* msg, int numOfMsg) {
+  // If we have the same number of data compared to the message
+  payload = "";
+  
+  for (int i = 0; i < numOfMsg; i++) {
+    payload.concat(msgName[i]);
+    payload.concat(";");
+    payload.concat(msg[i]);
+    payload.concat(":");
+  }
+}
+
+
+void receive_msg_from_python() {
+
+  String msg = "";
+
+  while (Serial.available()) {
+    if (Serial.available()) {
+      msg = Serial.readStringUntil('\n');
+    }
+  }
+
+  if (msg != "") {
+    rawMsgFromPython = msg;
+  }
+
+}
+
+
+String latest_received_msg() { 
+  return rawMsgFromPython;
+}
+
+void init_python_communication() {
+
+  while (true) {
+    // if the python side sent a message
+    if (Serial.available() > 0) {
+      String rawMsgFromPython = Serial.readStringUntil('\n');
+      if (rawMsgFromPython == "handshake1") {
+        break;
+      }
+    }
+  }
+
+  long timer = millis();
+  while (millis() - timer < 1000) {
+    Serial.println("handshake2");
+  }
+
+
+  while (Serial.available()) {
+    Serial.read();
+  }
+}
+
+
+void sync() { 
+  receive_msg_from_python();
+  String final_payload = "<echo_python;";
+  final_payload.concat(latest_received_msg());
+  final_payload.concat(":");
+  final_payload.concat(payload); 
+  final_payload.concat(">");
+  Serial.println(final_payload);
+}
diff --git a/test_original/pyCommsLib.h b/test_original/pyCommsLib.h
new file mode 100644
index 0000000..75ee2f4
--- /dev/null
+++ b/test_original/pyCommsLib.h
@@ -0,0 +1,17 @@
+#ifndef PYCOMMSLIB_H
+#define PYCOMMSLIB_H
+
+#define size_of_array(arr) sizeof(arr) / sizeof(*arr)
+
+
+#include <Arduino.h>
+
+void load_msg_to_python(String* msgName, String* msg, int numOfMsg);
+
+String latest_received_msg();
+
+void init_python_communication();
+
+void sync();
+
+#endif
diff --git a/test_original/test_original.ino b/test_original/test_original.ino
new file mode 100644
index 0000000..b7964ac
--- /dev/null
+++ b/test_original/test_original.ino
@@ -0,0 +1,37 @@
+#include "pyCommsLib.h"
+
+
+String msgName[] = {"msgA", "msgB"};
+
+
+String dataCarrier[2];
+
+
+void setup() {
+  // Start the serial communication. The baudrate is arbiturary.
+  Serial.begin(115200);
+
+  // Connect with the Python side
+  init_python_communication();
+}
+
+void loop() {
+  
+  // This is how you access the latest received message from the Python side
+  String received_message = latest_received_msg();
+
+  
+  dataCarrier[0] = "Some message";
+  dataCarrier[1] = String(3);
+
+
+
+  //load_msg_to_python(msgName, dataCarrier, size_of_array(msgName));
+
+
+
+  sync();
+
+
+  //delay(100);
+}
diff --git a/test_windows.py b/test_windows.py
index e44463f..54998e7 100644
--- a/test_windows.py
+++ b/test_windows.py
@@ -1,30 +1,16 @@
 from comms_wrapper_new import *
 from time import sleep, time
 
-import msvcrt
-def getch():
-    return msvcrt.getch().decode()
-
 def main():
     key = Key()
 
-    arduino1 = Arduino(descriptiveDeviceName="myArduino", portName="COM7", baudrate=2000000)
-    arduino1.define_number_of_messages(2, 2)
+    arduino1 = Arduino(descriptiveDeviceName="myArduino", portName="/dev/ttyACM0", baudrate=115200)
+    arduino1.define_number_of_messages(0, 1)
     arduino1.connect_and_handshake()
     
-    prev = ""
     timer = time()
     while 1: 
 
-        arduino1.receive_message() 
-        # if arduino1._rawReceivedMessage != prev:
-        #     print("REC:", arduino1._rawReceivedMessage)
-        #     prev = arduino1._rawReceivedMessage
-
-        if arduino1.newMsgRecieved:
-            #print(arduino1.receivedMessages) 
-            print(arduino1._rawOrganizedMessages)
-
         #arduino1.send_message([str(round(time() - timer, 2)) ])
         t = str(round(time() - timer, 5))
         while 1: 
@@ -34,10 +20,9 @@ def main():
                 t = t[:-1]
             else: 
                 break
-        arduino1.send_message([t,"m"])
+        arduino1.send_message([t])
 
-            
-        sleep(0.001)
+        print(arduino1._rawReceivedMessage, arduino1._rawOrganizedMessages)
 
 if __name__ == '__main__':
     main()
\ No newline at end of file
diff --git a/test_windows/pyCommsLib.cpp b/test_windows/pyCommsLib.cpp
index 03716b1..6a38394 100644
--- a/test_windows/pyCommsLib.cpp
+++ b/test_windows/pyCommsLib.cpp
@@ -29,20 +29,22 @@ void receive_msg_from_python() {
 
   String msg = "";
 
-  while (Serial.available()>5) {
-      msg = Serial.readStringUntil('%');
-      msg.remove(0,5);
-      break;
+  while (Serial.available()) {
+      msg = Serial.readStringUntil('\n');
+      //msg.remove(0,5);
+      //break;
   }
   
   while (Serial.available()) {
       Serial.read();
   }
   
-  
+
   if (msg != "") {
     rawMsgFromPython = msg;
   }
+
+//Serial.println(rawMsgFromPython);  
 }
 
 
diff --git a/test_windows/test_windows.ino b/test_windows/test_windows.ino
index ccab4de..a010cb5 100644
--- a/test_windows/test_windows.ino
+++ b/test_windows/test_windows.ino
@@ -1,11 +1,11 @@
 #include "pyCommsLib.h"
 
-String msgName[] = {"pot", "msg2"};
-String dataCarrier[2];
+String msgName[] = {};
+String dataCarrier[0];
 
 void setup() {
   // Start the serial communication. The baudrate is arbiturary.
-  Serial.begin(2000000);
+  Serial.begin(115200);
 
   // Connect with the Python side
   init_python_communication();
@@ -16,9 +16,10 @@ void loop() {
   
   int pot = analogRead(A0);
   //Serial.println(pot);
-  
-  dataCarrier[0] = String(pot);
-  dataCarrier[1] = "ddddd";
 
+  //dataCarrier[0] = String(pot);
+  //dataCarrier[1] = "ddddd";
+
+//receive_msg_from_python();
   send_msg_to_python(msgName, dataCarrier, size_of_array(msgName));
 }
-- 
GitLab