|
|
|
@ -8,6 +8,8 @@ from threading import Thread
@@ -8,6 +8,8 @@ from threading import Thread
|
|
|
|
|
import time |
|
|
|
|
import binascii |
|
|
|
|
from base64 import b64decode, b64encode |
|
|
|
|
from PyCRC.CRC32 import CRC32 |
|
|
|
|
import struct |
|
|
|
|
|
|
|
|
|
import messages_pb2 as messages |
|
|
|
|
from google.protobuf.message import Message |
|
|
|
@ -29,9 +31,13 @@ class UGVComms:
@@ -29,9 +31,13 @@ class UGVComms:
|
|
|
|
|
self.last_status_time = None |
|
|
|
|
self.rx_thread = None |
|
|
|
|
self.is_running = False |
|
|
|
|
self.log_file = None |
|
|
|
|
|
|
|
|
|
def write_base64(self, data: bytes): |
|
|
|
|
encoded = b64encode(data) |
|
|
|
|
crc = CRC32().calculate(data) |
|
|
|
|
data_with_checksum = bytearray(data) |
|
|
|
|
data_with_checksum.extend(struct.pack('<L', crc)) |
|
|
|
|
encoded = b64encode(data_with_checksum) |
|
|
|
|
self.ser.write(encoded) |
|
|
|
|
self.ser.write(b'\n') |
|
|
|
|
|
|
|
|
@ -80,8 +86,16 @@ class UGVComms:
@@ -80,8 +86,16 @@ class UGVComms:
|
|
|
|
|
log.warning("read bad data: %s", data) |
|
|
|
|
self.ser.flush() |
|
|
|
|
return None |
|
|
|
|
if len(decoded) < 4: |
|
|
|
|
log.warning('Message too short ({} bytes)'.format(len(decoded))) |
|
|
|
|
return None |
|
|
|
|
msgcrc, = struct.unpack('<L', decoded[-4:]) |
|
|
|
|
calccrc = CRC32().calculate(decoded[:-4]) |
|
|
|
|
if msgcrc != calccrc: |
|
|
|
|
log.warning('Checksum did not match ({} != {})'.format(msgcrc, calccrc)) |
|
|
|
|
return None |
|
|
|
|
msg = messages.UGV_Message() |
|
|
|
|
msg.ParseFromString(decoded) |
|
|
|
|
msg.ParseFromString(decoded[:-4]) |
|
|
|
|
return msg |
|
|
|
|
|
|
|
|
|
def process_message(self, msg: messages.UGV_Message): |
|
|
|
@ -90,6 +104,8 @@ class UGVComms:
@@ -90,6 +104,8 @@ class UGVComms:
|
|
|
|
|
log.debug("received UGV message: %s", msg) |
|
|
|
|
if self.on_msg_received: |
|
|
|
|
self.on_msg_received(msg) |
|
|
|
|
if self.log_file: |
|
|
|
|
print('[{}] UGV_Message: {}'.format(time.strftime('%Y-%b-%d %H:%M:%S'), msg), file=self.log_file) |
|
|
|
|
if msg.HasField("command_ack"): |
|
|
|
|
with self.ack_cv: |
|
|
|
|
self.msg_acks.append(msg.command_ack) |
|
|
|
@ -98,7 +114,7 @@ class UGVComms:
@@ -98,7 +114,7 @@ class UGVComms:
|
|
|
|
|
self.last_status = msg.status |
|
|
|
|
self.last_status_time = time.time() |
|
|
|
|
else: |
|
|
|
|
log.warn("unknown UGV message: %s", msg) |
|
|
|
|
log.warning("unknown UGV message: %s", msg) |
|
|
|
|
|
|
|
|
|
def start(self): |
|
|
|
|
if self.is_running: |
|
|
|
@ -118,19 +134,26 @@ class UGVComms:
@@ -118,19 +134,26 @@ class UGVComms:
|
|
|
|
|
self.rx_thread.join() |
|
|
|
|
return True |
|
|
|
|
|
|
|
|
|
def save_logs(self, file): |
|
|
|
|
self.log_file = open(file, mode='a') |
|
|
|
|
|
|
|
|
|
def __rx_thread_entry(self): |
|
|
|
|
while self.is_running and self.ser.is_open: |
|
|
|
|
try: |
|
|
|
|
msg = self.read_message() |
|
|
|
|
self.process_message(msg) |
|
|
|
|
except serial.SerialException: |
|
|
|
|
if not self.ser.is_open or not self.is_running: # port was probably just closed |
|
|
|
|
try: |
|
|
|
|
while self.is_running and self.ser.is_open: |
|
|
|
|
try: |
|
|
|
|
msg = self.read_message() |
|
|
|
|
self.process_message(msg) |
|
|
|
|
except serial.SerialException: |
|
|
|
|
if not self.ser.is_open or not self.is_running: # port was probably just closed |
|
|
|
|
return |
|
|
|
|
log.error("serial error", exc_info=True) |
|
|
|
|
return |
|
|
|
|
log.error("serial error", exc_info=True) |
|
|
|
|
return |
|
|
|
|
except Exception: |
|
|
|
|
log.error("error reading message", exc_info=True) |
|
|
|
|
continue |
|
|
|
|
except Exception: |
|
|
|
|
log.error("error reading message", exc_info=True) |
|
|
|
|
continue |
|
|
|
|
finally: |
|
|
|
|
if self.log_file: |
|
|
|
|
self.log_file.close() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main(): |
|
|
|
|