Improve Com class, continue writing test

This commit is contained in:
2025-05-09 11:03:49 +02:00
parent e71f9e6d02
commit a8ad40148f
10 changed files with 125 additions and 52 deletions

View File

@@ -1,10 +1,11 @@
from abc import ABC, abstractmethod
from typing import Optional
import serial
import struct
import serial.tools.list_ports
class Com:
class ComSuperClass(ABC):
def __init__(self, baudrate: int = 19200, filters: Optional[list[str]] = None) -> None:
self._serial: Optional[serial.Serial] = None
self._filters = filters if filters != None else [ 'USB-Serial Controller', 'Prolific USB-Serial Controller' ]
@@ -19,6 +20,32 @@ class Com:
def get_error(self) -> serial.SerialException | None:
return self._err
@abstractmethod
def get_comport(self) -> str:
pass
@abstractmethod
def connect(self) -> bool:
pass
@abstractmethod
def close(self) -> None:
pass
@abstractmethod
def receive(self, byte_count: int) -> bytes:
pass
@abstractmethod
def send(self, msg: str) -> None:
pass
@abstractmethod
def send_float(self, msg: float) -> None:
pass
class Com(ComSuperClass):
def _connection_check(self) -> bool:
if self._serial == None:
return self._open()

View File

@@ -1,4 +1,4 @@
from lib.com import Com
from lib.com import ComSuperClass
import lib.decoder
import time
@@ -9,7 +9,7 @@ decoder = lib.decoder.Decoder()
# Class that supports sending instructions to the microcontroller,
# as well as hooking to data stream according to protocol
class Instructions:
def __init__(self, com: Com) -> None:
def __init__(self, com: ComSuperClass) -> None:
self._com = com
# Set a port override (to use a specific COM port)

View File

@@ -6,33 +6,55 @@ It simulates the behviour of an actual microcontroller being connected
from typing import Optional
import queue
import random
import serial
from lib.com import ComSuperClass
# This file contains a Com class that can be used to test the functionality
# even without a microcontroller. It is not documented in a particularly
# beginner-friendly way, nor is the code written with beginner-friendliness
# in mind. It is the most complicated piece of code of the entire application
# All double __ prefixed properties are not available in the actual one
# All double __ prefixed properties and methods are not available in the actual one
instruction_lut = {
"PR": "\nPR\n",
"PT": "\nPT\n",
"RD": "\nRD\n",
"NM": "\nNM\n",
"FM": "\nFM\n",
}
class Com:
def __init__(self) -> None:
# Initialize queue with values to be sent on call of recieve (add like three or so at a time)
self._port_override = ""
self.__mode = ""
self.__simulated_data = queue.Queue()
class Com(ComSuperClass):
def __init__(self, baudrate: int = 19200, filters: Optional[list[str]] = None) -> None:
# Calling the constructor of the super class to assign defaults
print("WARNING: Using testing library for communication!")
super().__init__(baudrate, filters);
# Initialize queue with values to be sent on call of recieve
self.__simulated_data: queue.Queue[int] = queue.Queue()
# Keep track of the number of bytes sent to fulfil protocol
self.__bytes_sent: int = 0
# Initially, we are in normal mode (which leads to slower data intervals)
self.__mode = "NM"
def set_port_override(self, override: str) -> None:
"""Set the port override, to disable port search"""
self._port_override = override
def get_error(self) -> serial.SerialException | None:
pass
def get_comport(self) -> str:
return "test" if self._port_override != "" else self._port_override
def connect(self) -> bool:
# TODO: For testing, make cases where there is no successful connection, i.e. we return false
# Randomly return false
if random.randint(0, 20):
# Randomly return false in 1 in 20 ish cases
if random.randint(0, 20) == 1:
print("Simulating error to connect")
return False
return True
@@ -41,6 +63,9 @@ class Com:
def receive(self, byte_count: int) -> bytes:
# TODO: Make it return simulated data
data = []
for i in range(byte_count):
data.append(self.__simulated_data.get_nowait())
return bytes("A", "ascii")
def send(self, msg: str) -> None:
@@ -51,5 +76,5 @@ class Com:
def send_float(self, msg: float) -> None:
pass
def _generate_random_value(self, precision: int) -> bytes:
def __generate_random_value(self, precision: int) -> bytes:
return bytes(str(round(random.random() * precision) / precision), "ascii")