Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Anupama-nambiar committed Oct 31, 2024
2 parents 1f62a94 + c7028c1 commit 87f81b0
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 0 deletions.
46 changes: 46 additions & 0 deletions backend_arduino.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// #include <USB.h>

// void setup() {
// Serial.begin(9600);
// }

// void loop() {
// Serial.println("Hello, World!");
// delay(1000);
// }

const int LED { 17 };

// add these
const char S_OK { 0xaa };
const char S_ERR { 0xff };

void on_receive(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
// read one byte
char state { Serial.read() };
// guard byte is valid LED state
if (!(state == LOW || state == HIGH)) {
// invalid byte received
// report error
Serial.write(S_ERR);
return;
}
// update LED with valid state
digitalWrite(LED, state);
Serial.write(S_OK);
}



void setup() {
pinMode(LED, OUTPUT);

// register "on_receive" as callback for RX event
Serial.onEvent(ARDUINO_HW_CDC_RX_EVENT, on_receive);
Serial.begin(9600);
}

void loop() {
// Serial.println("Hello, World!");
// delay(1000);
}
20 changes: 20 additions & 0 deletions serialread.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from serial import Serial, SerialException

# with Serial('/dev/cu.usbmodem14101', 9600) as ser:
# while True:
# print(ser.readline().decode())

with Serial('/dev/cu.usbmodem14301', 9600) as ser:
ser.write(bytes([0x0]))
input() # keep port open to see the LED turn on


# with Serial('/dev/cu.usbmodem14301', 9600) as ser:
# ser.write(bytes([0x1]))
# assert ser.read() == bytes([0xaa])

# ser.write(bytes([0x0]))
# assert ser.read() == bytes([0xaa])

# ser.write(bytes([0x2]))
# assert ser.read() == bytes([0xff])
89 changes: 89 additions & 0 deletions ui.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import tkinter as tk
import tkinter.ttk as ttk
from tkinter.messagebox import showerror
from serial import Serial, SerialException
from serial.tools.list_ports import comports

from threading import Thread, Lock # we'll use Lock later ;)
def detached_callback(f):
return lambda *args, **kwargs: Thread(target=f, args=args, kwargs=kwargs).start()


S_OK: int = 0xaa
S_ERR: int = 0xff

class LockedSerial(Serial):
_lock: Lock = Lock()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def read(self, size=1) -> bytes:
with self._lock:
return super().read(size)
def write(self, b: bytes, /) -> int | None:
with self._lock:
super().write(b)
def close(self):
with self._lock:
super().close()


class App(tk.Tk):
def __init__(self):
super().__init__()

self.title("LED Blinker")
self.led = tk.BooleanVar()
self.port = tk.StringVar() # add this

ttk.Checkbutton(self, text='Toggle LED', variable=self.led, command=self.update_led).pack()
ttk.Button(self, text='Send Invalid', command=self.send_invalid).pack()
ttk.Button(self, text='Disconnect',command=self.disconnect, default='active').pack()
SerialPortal(self) # and this

def connect(self):
self.ser = LockedSerial(self.port.get())

def disconnect(self):
self.ser.close()
SerialPortal(self) # display portal to reconnect

def write(self, b: bytes):
try:
self.ser.write(b)
if int.from_bytes(self.ser.read(), 'big') == S_ERR:
showerror('Device Error', 'The device reported an invalid command.')
except SerialException:
showerror('Serial Error', 'Write failed.')

@detached_callback
def update_led(self):
self.write(bytes([self.led.get()]))
def send_invalid(self):
self.write(bytes([0x10]))

def __enter__(self):
return self
def __exit__(self, *_):
self.disconnect()





class SerialPortal(tk.Toplevel):
def __init__(self, parent: App):
super().__init__(parent)
self.parent = parent
self.parent.withdraw() # hide App until connected
ttk.OptionMenu(self, parent.port, '', *[d.device for d in comports()]).pack()
ttk.Button(self, text='Connect', command=self.connect, default='active').pack()
def connect(self):
self.parent.connect()
self.destroy()
self.parent.deiconify() # reveal App



if __name__ == '__main__':
with App() as app:
app.mainloop()

0 comments on commit 87f81b0

Please sign in to comment.