UART communication
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
# shared/uart_comm.py
|
||||
import _thread
|
||||
from machine import UART
|
||||
import time
|
||||
|
||||
class SafeUART:
|
||||
def __init__(self, uart_id, tx_pin, rx_pin, baudrate=115200):
|
||||
# Initialize the hardware UART channel
|
||||
self.uart = UART(uart_id, baudrate=baudrate, tx=tx_pin, rx=rx_pin, timeout=10)
|
||||
|
||||
# Core thread-safety assets
|
||||
self.lock = _thread.allocate_lock()
|
||||
self.rx_queue = []
|
||||
self.buffer = b""
|
||||
|
||||
# Start the background data worker thread
|
||||
_thread.stack_size(4096) # Cap the stack size for the UART listener
|
||||
_thread.start_new_thread(self._listener_worker, ())
|
||||
_thread.stack_size(0)
|
||||
|
||||
print(f"[UART] Thread initialized on UART{uart_id} (TX:{tx_pin}, RX:{rx_pin})")
|
||||
|
||||
def _listener_worker(self):
|
||||
"""Asynchronous internal loop parsing incoming stream lines into the queue."""
|
||||
while True:
|
||||
try:
|
||||
if self.uart.any():
|
||||
with self.lock:
|
||||
# Pull all raw bytes waiting in the hardware ring buffer
|
||||
chunk = self.uart.read(self.uart.any())
|
||||
if chunk:
|
||||
self.buffer += chunk
|
||||
|
||||
# Process complete lines terminated by a newline character
|
||||
while b'\n' in self.buffer:
|
||||
line, self.buffer = self.buffer.split(b'\n', 1)
|
||||
try:
|
||||
decoded_line = line.decode('utf-8').strip()
|
||||
if decoded_line:
|
||||
self.rx_queue.append(decoded_line)
|
||||
except Exception:
|
||||
pass # Discard corrupt data frames safely
|
||||
except Exception as e:
|
||||
print("[UART Thread Error]:", e)
|
||||
|
||||
time.sleep_ms(20) # Give other background threads breathing room
|
||||
|
||||
def send(self, message):
|
||||
"""Safely pushes strings across the serial wire from any thread context."""
|
||||
if not message.endswith('\n'):
|
||||
message += '\n'
|
||||
|
||||
with self.lock:
|
||||
self.uart.write(message.encode('utf-8'))
|
||||
|
||||
def any(self):
|
||||
"""Checks if any complete messages are waiting to be read."""
|
||||
with self.lock:
|
||||
return len(self.rx_queue) > 0
|
||||
|
||||
def read(self):
|
||||
"""Pulls the oldest unread string from the queue. Returns None if empty."""
|
||||
with self.lock:
|
||||
if self.rx_queue:
|
||||
return self.rx_queue.pop(0)
|
||||
return None
|
||||
Reference in New Issue
Block a user