diff --git a/CHANGELOG.md b/CHANGELOG.md index be488871..8764245b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 1.0.0 / Unreleased +* #413 Engine: Add run-time test methods and change required API version to 6 * GUI: Fix image alignment and placement of limit lines in graphical scene * #395 GUI: Check for new release on startup * #393 Documentation: Add forthcoming features to CHANGELOG diff --git a/README.md b/README.md index 04a496d7..dcb0cd2a 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,8 @@ The Python module dependencies can be found in *requirements.txt*. To be able to communicate with your Arduino, it might be necessary to add the rights for USB communication by adding your user to some groups. - sudo usermod -a -G tty [userName] - sudo usermod -a -G dialout [userName] + sudo usermod -aG tty [userName] + sudo usermod -aG dialout [userName] To install the development version you can checkout the git repository. diff --git a/src/main/python/ayab/engine/communication.py b/src/main/python/ayab/engine/communication.py index d4c1363d..47e24b3a 100644 --- a/src/main/python/ayab/engine/communication.py +++ b/src/main/python/ayab/engine/communication.py @@ -44,13 +44,14 @@ class MessageToken(Enum): reqLine = 0x82 cnfLine = 0x42 indState = 0x84 + slipFrameEnd = 0xc0 class AyabCommunication(object): """Class Handling the serial communication protocol.""" def __init__(self, serial=None): - """Creates an AyabCommunication object, - with an optional serial-like object.""" + """Create an AyabCommunication object, + with an optional serial communication object.""" logging.basicConfig(level=logging.DEBUG) self.__logger = logging.getLogger(type(self).__name__) self.__ser = serial @@ -58,7 +59,7 @@ def __init__(self, serial=None): self.__rx_msg_list = list() def __del__(self): - """Handles on delete behaviour closing serial port object.""" + """Handle behaviour on deletion by closing the serial port connection.""" self.close_serial() def is_open(self): @@ -69,7 +70,7 @@ def is_open(self): return False def open_serial(self, portname=None): - """Opens serial port communication with a portName.""" + """Open serial port communication.""" if not self.__ser: self.__portname = portname try: @@ -83,7 +84,7 @@ def open_serial(self, portname=None): return True def close_serial(self): - """Closes serial port.""" + """Close the serial port.""" if self.__ser is not None and self.__ser.is_open is True: try: self.__ser.close() @@ -96,17 +97,19 @@ def close_serial(self): # NB this method must be the same for all API versions def req_info(self): - """Sends a request for information to controller.""" + """Send a request for information to the device.""" data = self.__driver.send(bytes([MessageToken.reqInfo.value])) self.__ser.write(data) - def req_test_API6(self): - """""" - data = self.__driver.send(bytes([MessageToken.reqTest.value])) + def req_test_API6(self, machine_val): + """Send a request for testing to the device.""" + data = self.__driver.send( + bytes([MessageToken.reqTest.value, machine_val])) self.__ser.write(data) - def req_start_API6(self, machine_val, start_needle, stop_needle, continuous_reporting): - """Sends a start message to the controller.""" + def req_start_API6(self, machine_val, start_needle, stop_needle, + continuous_reporting): + """Send a start message to the device.""" data = bytearray() data.append(MessageToken.reqStart.value) data.append(machine_val) @@ -120,9 +123,9 @@ def req_start_API6(self, machine_val, start_needle, stop_needle, continuous_repo self.__ser.write(data) def cnf_line_API6(self, line_number, color, flags, line_data): - """Sends a line of data via the serial port. + """Send a line of data via the serial port. - Sends a line of data to the serial port, all arguments are mandatory. + Send a line of data to the serial port. All arguments are mandatory. The data sent here is parsed by the Arduino controller which sets the knitting needles accordingly. @@ -146,7 +149,7 @@ def cnf_line_API6(self, line_number, color, flags, line_data): self.__ser.write(data) def update_API6(self): - """Reads data from serial and tries to parse as SLIP packet.""" + """Read data from serial and parse as SLIP packet.""" if self.__ser: data = self.__ser.read(1000) if len(data) > 0: diff --git a/src/main/python/ayab/engine/communication_mockup.py b/src/main/python/ayab/engine/communication_mockup.py index 56a081ad..9d2d07f7 100644 --- a/src/main/python/ayab/engine/communication_mockup.py +++ b/src/main/python/ayab/engine/communication_mockup.py @@ -62,14 +62,17 @@ def open_serial(self, portname=None) -> bool: def req_info(self) -> None: cnfInfo = bytearray([MessageToken.cnfInfo.value, 0x5, 0xFF, 0xFF]) self.__rx_msg_list.append(cnfInfo) - indState = bytearray([MessageToken.indState.value, 0x1, 0xFF, 0xFF, 0xFF, 0xFF, 0x1, 0x7F]) + indState = bytearray([ + MessageToken.indState.value, 0x1, 0xFF, 0xFF, 0xFF, 0xFF, 0x1, 0x7F + ]) self.__rx_msg_list.append(indState) - def req_test_API6(self) -> None: + def req_test_API6(self, machine_val) -> None: cnfTest = bytearray([MessageToken.cnfTest.value, 0x1]) self.__rx_msg_list.append(cnfTest) - def req_start_API6(self, machine_val, start_needle, stop_needle, continuous_reporting) -> None: + def req_start_API6(self, machine_val, start_needle, stop_needle, + continuous_reporting) -> None: self.__is_started = True cnfStart = bytearray([MessageToken.cnfStart.value, 0x1]) self.__rx_msg_list.append(cnfStart) @@ -79,7 +82,8 @@ def cnf_line_API6(self, line_number, color, flags, line_data) -> bool: def update_API6(self) -> tuple: if self.__is_open and self.__is_started: - reqLine = bytearray([MessageToken.reqLine.value, self.__line_count]) + reqLine = bytearray( + [MessageToken.reqLine.value, self.__line_count]) self.__line_count += 1 self.__line_count %= 256 self.__rx_msg_list.append(reqLine) diff --git a/src/main/python/ayab/engine/control.py b/src/main/python/ayab/engine/control.py index af8f3f3a..5db310e1 100644 --- a/src/main/python/ayab/engine/control.py +++ b/src/main/python/ayab/engine/control.py @@ -106,7 +106,7 @@ def cnf_line_API6(self, line_number): self.logger.error("Requested line number out of range") return True # stop knitting # else - # TODO some better algorithm for block wrapping + # TODO: some better algorithm for block wrapping if self.former_request == self.BLOCK_LENGTH - 1 and line_number == 0: # wrap to next block of lines self.line_block += 1 @@ -128,7 +128,7 @@ def cnf_line_API6(self, line_number): self.com.cnf_line_API6(requested_line, color, flag, bits.tobytes()) # screen output - # TODO tidy up this code + # TODO: tidy up this code msg = str(self.line_block) + " " + str(line_number) + " reqLine: " + \ str(requested_line) + " pat_row: " + str(self.pat_row) if blank_line: @@ -187,12 +187,11 @@ def select_needles_API6(self, color, row_index, blank_line): self.__last_needle = last_needle return bits - def knit(self, pattern, options): + def operate(self, pattern, options, operation, API_version=6): """Finite State Machine governing serial communication""" - method = "_knit_" + self.state.name.lower() + method = "_API" + str(API_version) + "_" + self.state.name.lower() if not hasattr(KnitStateMachine, method): - # NONE, FINISHED return KnitOutput.NONE dispatch = getattr(KnitStateMachine, method) - result = dispatch(self, pattern, options) + result = dispatch(self, pattern, options, operation) return result diff --git a/src/main/python/ayab/engine/engine.py b/src/main/python/ayab/engine/engine.py index 566cd9f5..42d96272 100644 --- a/src/main/python/ayab/engine/engine.py +++ b/src/main/python/ayab/engine/engine.py @@ -28,6 +28,7 @@ from ayab import utils from ayab.observable import Observable from .control import KnitControl +from .state import KnitOperation from .pattern import Pattern from .options import OptionsTab, Alignment, NeedleColor from .status import Status, StatusTab @@ -75,6 +76,7 @@ def setup_ui(self): # activate UI elements self.__activate_ui() + # def __activate_status_tab(self): # self.ui.tab_widget.setTabEnabled(1, True) # self.ui.tab_widget.setCurrentIndex(1) @@ -123,7 +125,8 @@ def knit_config(self, image): # TODO: detect if previous conf had the same # image to avoid re-generating. - self.__pattern = Pattern(image, self.config.machine, self.config.num_colors) + self.__pattern = Pattern(image, self.config.machine, + self.config.num_colors) # validate configuration options valid, msg = self.validate() @@ -133,7 +136,9 @@ def knit_config(self, image): # update pattern if self.config.start_needle and self.config.stop_needle: - self.__pattern.set_knit_needles(self.config.start_needle, self.config.stop_needle, self.config.machine) + self.__pattern.set_knit_needles(self.config.start_needle, + self.config.stop_needle, + self.config.machine) self.__pattern.alignment = self.config.alignment # update progress bar @@ -165,7 +170,8 @@ def knit(self): # FIXME pattern and config are only used by KnitControl.knit() # in the KnitState.SETUP step and do not need to be sent otherwise. - result = self.__control.knit(self.__pattern, self.config) + result = self.__control.operate(self.__pattern, self.config, + KnitOperation.KNIT) self.__feedback.handle(result) self.__status_handler() if self.__canceled or result is KnitOutput.FINISHED: diff --git a/src/main/python/ayab/engine/state.py b/src/main/python/ayab/engine/state.py index 9de20faa..c2de6bac 100644 --- a/src/main/python/ayab/engine/state.py +++ b/src/main/python/ayab/engine/state.py @@ -27,15 +27,20 @@ from .output import KnitOutput -# NB no test states +class KnitOperation(Enum): + KNIT = auto() + TEST = auto() + + class KnitState(Enum): - # NONE = auto() SETUP = auto() INIT = auto() - WAIT_FOR_INIT = auto() - START = auto() - OPERATE = auto() - # FINISHED = auto() + REQUEST_START = auto() + CONFIRM_START = auto() + RUN_KNIT = auto() + REQUEST_TEST = auto() + CONFIRM_TEST = auto() + RUN_TEST = auto() class KnitStateMachine(object): @@ -46,7 +51,7 @@ class KnitStateMachine(object): @author Tom Price @date June 2020 """ - def _knit_setup(control, pattern, options): + def _API6_setup(control, pattern, options, operation): control.logger.debug("KnitState SETUP") control.former_request = 0 control.line_block = 0 @@ -58,7 +63,8 @@ def _knit_setup(control, pattern, options): control.mode = options.mode control.inf_repeat = options.inf_repeat control.len_pat_expanded = control.pat_height * control.num_colors - control.passes_per_row = control.mode.row_multiplier(control.num_colors) + control.passes_per_row = control.mode.row_multiplier( + control.num_colors) control.reset_status() if not control.func_selector(): return KnitOutput.ERROR_INVALID_SETTINGS @@ -77,26 +83,28 @@ def _knit_setup(control, pattern, options): control.state = KnitState.INIT return KnitOutput.NONE - # NB this communication sequence must be the same for every API version - def _knit_init(control, pattern, options): + def _API6_init(control, pattern, options, operation): control.logger.debug("KnitState INIT") rcvMsg, rcvParam = control.check_serial() if rcvMsg == MessageToken.cnfInfo: if rcvParam >= control.FIRST_SUPPORTED_API_VERSION: control.api_version = rcvParam - control.state = KnitState.WAIT_FOR_INIT + if operation == KnitOperation.TEST: + control.state = KnitState.REQUEST_TEST + else: + control.state = KnitState.REQUEST_START return KnitOutput.WAIT_FOR_INIT else: control.logger.error("Wrong API version: " + str(rcvParam) + - ", expected >= " + str(control.FIRST_SUPPORTED_API_VERSION)) + ", expected >= " + + str(control.FIRST_SUPPORTED_API_VERSION)) return KnitOutput.ERROR_WRONG_API # else control.com.req_info() return KnitOutput.CONNECTING_TO_MACHINE - # TODO: polymorphic dispatch on control.api_version to ensure backwards compatibility - def _knit_wait_for_init(control, pattern, options): - control.logger.debug("KnitState WAIT_FOR_INIT") + def _API6_request_start(control, pattern, options, operation): + control.logger.debug("KnitState REQUEST_START") rcvMsg, rcvParam = control.check_serial() if rcvMsg == MessageToken.indState: if rcvParam == 1: @@ -104,21 +112,20 @@ def _knit_wait_for_init(control, pattern, options): control.pattern.knit_start_needle, control.pattern.knit_stop_needle, options.continuous_reporting) - control.state = KnitState.START + control.state = KnitState.CONFIRM_START else: # any value of rcvParam other than 1 is some kind of error code - control.logger.debug("Init failed") + control.logger.debug("Knit init failed") # TODO: more output to describe error # fallthrough return KnitOutput.NONE - # TODO: polymorphic dispatch on control.api_version to ensure backwards compatibility - def _knit_start(control, pattern, options): - control.logger.debug("KnitState START") + def _API6_confirm_start(control, pattern, options, operation): + control.logger.debug("KnitState CONFIRM_START") rcvMsg, rcvParam = control.check_serial() if rcvMsg == MessageToken.cnfStart: if rcvParam == 1: - control.state = KnitState.OPERATE + control.state = KnitState.RUN_KNIT return KnitOutput.PLEASE_KNIT else: # any value of rcvParam other than 1 is some kind of error code @@ -128,9 +135,8 @@ def _knit_start(control, pattern, options): # fallthrough return KnitOutput.NONE - # TODO: polymorphic dispatch on control.api_version to ensure backwards compatibility - def _knit_operate(control, pattern, options): - control.logger.debug("KnitState OPERATE") + def _API6_run_knit(control, pattern, options, operation): + control.logger.debug("KnitState RUN_KNIT") rcvMsg, rcvParam = control.check_serial() if rcvMsg == MessageToken.reqLine: pattern_finished = control.cnf_line_API6(rcvParam) @@ -141,3 +147,37 @@ def _knit_operate(control, pattern, options): return KnitOutput.NEXT_LINE # fallthrough return KnitOutput.NONE + + def _API6_request_test(control, pattern, options, operation): + control.logger.debug("KnitState REQUEST_TEST") + rcvMsg, rcvParam = control.check_serial() + if rcvMsg == MessageToken.indState: + if rcvParam == 1: + control.com.req_test_API6(options.machine.value) + control.state = KnitState.CONFIRM_TEST + else: + # any value of rcvParam other than 1 is some kind of error code + control.logger.debug("Test init failed") + # TODO: more output to describe error + # fallthrough + return KnitOutput.NONE + + def _API6_confirm_test(control, pattern, options, operation): + control.logger.debug("KnitState CONFIRM_TEST") + rcvMsg, rcvParam = control.check_serial() + if rcvMsg == MessageToken.cnfTest: + if rcvParam == 1: + control.state = KnitState.RUN_TEST + return KnitOutput.NONE + else: + # any value of rcvParam other than 1 is some kind of error code + control.logger.error("Device not ready") + # TODO: more output to describe error + return KnitOutput.DEVICE_NOT_READY + # fallthrough + return KnitOutput.NONE + + def _API6_run_test(control, pattern, options, operation): + control.logger.debug("KnitState RUN_TEST") + # TODO: open serial monitor + return KnitOutput.NONE diff --git a/src/main/python/ayab/fsm.py b/src/main/python/ayab/fsm.py index 011b84b0..378b1915 100644 --- a/src/main/python/ayab/fsm.py +++ b/src/main/python/ayab/fsm.py @@ -42,6 +42,7 @@ def __init__(self): self.CONFIGURING = QState(self.machine) self.CHECKING = QState(self.machine) self.KNITTING = QState(self.machine) + # self.TESTING = QState(self.machine) # Set machine states self.machine.setInitialState(self.NO_IMAGE) @@ -54,6 +55,8 @@ def set_transitions(self, parent): self.CONFIGURING) self.CONFIGURING.addTransition(parent.ui.knit_button.clicked, self.CHECKING) + # self.CONFIGURING.addTransition(parent.ui.test_button.clicked, + # self.TESTING) self.CHECKING.addTransition(parent.seer.got_image_flag, self.CONFIGURING) self.CHECKING.addTransition(parent.seer.new_image_flag, @@ -74,6 +77,8 @@ def set_transitions(self, parent): lambda: logging.debug("Entered state CHECKING")) self.KNITTING.entered.connect( lambda: logging.debug("Entered state KNITTING")) + # self.TESTING.entered.connect( + # lambda: logging.debug("Entered state TESTING")) self.NO_IMAGE.exited.connect(parent.engine.config.refresh) self.CONFIGURING.entered.connect(parent.menu.add_image_actions) @@ -91,22 +96,28 @@ def set_properties(self, parent): self.NO_IMAGE.assignProperty(parent.engine, "enabled", "False") self.CONFIGURING.assignProperty(parent.engine, "enabled", "True") self.KNITTING.assignProperty(parent.engine, "enabled", "False") + # self.TESTING.assignProperty(parent.engine, "enabled", "False") # Status tab in options dock should be activated only when knitting # self.NO_IMAGE.assignProperty(ui.status_tab, "enabled", "False") # self.CONFIGURING.assignProperty(ui.status_tab, "enabled", "False") # self.KNITTING.assignProperty(ui.status_tab, "enabled", "True") + # self.TESTING.assignProperty(ui.status_tab, "enabled", "False") # ? # Knit button self.NO_IMAGE.assignProperty(parent.ui.knit_button, "enabled", "False") - self.CONFIGURING.assignProperty(parent.ui.knit_button, "enabled", - "True") + self.CONFIGURING.assignProperty(parent.ui.knit_button, "enabled", "True") self.KNITTING.assignProperty(parent.ui.knit_button, "enabled", "False") + # self.TESTING.assignProperty(parent.ui.knit_button, "enabled", "False") + + # Test button + # self.NO_IMAGE.assignProperty(parent.ui.test_button, "enabled", "True") + # self.CONFIGURING.assignProperty(parent.ui.test_button, "enabled", "True") + # self.KNITTING.assignProperty(parent.ui.knit_button, "enabled", "False") + # self.TESTING.assignProperty(parent.ui.knit_button, "enabled", "False") # Cancel button - self.NO_IMAGE.assignProperty(parent.ui.cancel_button, "enabled", - "False") - self.CONFIGURING.assignProperty(parent.ui.cancel_button, "enabled", - "False") - self.KNITTING.assignProperty(parent.ui.cancel_button, "enabled", - "True") + self.NO_IMAGE.assignProperty(parent.ui.cancel_button, "enabled", "False") + self.CONFIGURING.assignProperty(parent.ui.cancel_button, "enabled", "False") + self.KNITTING.assignProperty(parent.ui.cancel_button, "enabled", "True") + # self.TESTING.assignProperty(parent.ui.cancel_button, "enabled", "True") diff --git a/src/main/python/ayab/tests/test_communication.py b/src/main/python/ayab/tests/test_communication.py index c8ced7e4..754383d8 100644 --- a/src/main/python/ayab/tests/test_communication.py +++ b/src/main/python/ayab/tests/test_communication.py @@ -24,11 +24,13 @@ from mock import patch from ayab.engine.communication import AyabCommunication, MessageToken +from ayab.machine import Machine class TestCommunication(unittest.TestCase): def setUp(self): - self.dummy_serial = serial.serial_for_url("loop://logging=debug", timeout=0.1) + self.dummy_serial = serial.serial_for_url("loop://logging=debug", + timeout=0.1) self.comm_dummy = AyabCommunication(self.dummy_serial) def test_close_serial(self): @@ -59,29 +61,41 @@ def test_open_serial(self): timeout=0.1) def test_update_API6(self): - byte_array = bytearray([0xc0, 0xc1, 0x01, 0xc0]) + byte_array = bytearray([0xc0, MessageToken.cnfStart.value, 1, 0xc0]) self.dummy_serial.write(byte_array) result = self.comm_dummy.update_API6() - expected_result = (b'\xc1\x01', MessageToken.cnfStart, 1) + expected_result = (bytes([MessageToken.cnfStart.value, + 1]), MessageToken.cnfStart, 1) assert result == expected_result def test_req_start_API6(self): machine_val, start_val, end_val, continuous_reporting, crc8 = 0, 0, 10, True, 0x74 - self.comm_dummy.req_start_API6(machine_val, start_val, end_val, continuous_reporting) - byte_array = bytearray( - [0xc0, 0x01, machine_val, start_val, end_val, continuous_reporting, crc8, 0xc0]) + self.comm_dummy.req_start_API6(machine_val, start_val, end_val, + continuous_reporting) + byte_array = bytearray([ + MessageToken.slipFrameEnd.value, MessageToken.reqStart.value, + machine_val, start_val, end_val, continuous_reporting, crc8, + MessageToken.slipFrameEnd.value + ]) bytes_read = self.dummy_serial.read(len(byte_array)) self.assertEqual(bytes_read, byte_array) def test_req_info(self): self.comm_dummy.req_info() - byte_array = bytearray([0xc0, 0x03, 0xc0]) + byte_array = bytearray([ + MessageToken.slipFrameEnd.value, MessageToken.reqInfo.value, + MessageToken.slipFrameEnd.value + ]) bytes_read = self.dummy_serial.read(len(byte_array)) assert bytes_read == byte_array def test_req_test_API6(self): - self.comm_dummy.req_test_API6() - byte_array = bytearray([0xc0, 0x04, 0xc0]) + machine_val = Machine.KH910_KH950.value + self.comm_dummy.req_test_API6(machine_val) + byte_array = bytearray([ + MessageToken.slipFrameEnd.value, MessageToken.reqTest.value, + machine_val, MessageToken.slipFrameEnd.value + ]) bytes_read = self.dummy_serial.read(len(byte_array)) assert bytes_read == byte_array @@ -92,12 +106,11 @@ def test_cnf_line_API6(self): line_data = b'\xde\xad\xbe\xef\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0' crc8 = 0xa7 self.comm_dummy.cnf_line_API6(line_number, color, flags, line_data) - byte_array = bytearray([0xc0, 0x42]) - byte_array.append(line_number) - byte_array.append(color) - byte_array.append(flags) + byte_array = bytearray([ + MessageToken.slipFrameEnd.value, MessageToken.cnfLine.value, + line_number, color, flags + ]) byte_array.extend(line_data) - byte_array.append(crc8) - byte_array.append(0xc0) + byte_array.extend(bytes([crc8, MessageToken.slipFrameEnd.value])) bytes_read = self.dummy_serial.read(len(byte_array)) assert bytes_read == byte_array diff --git a/src/main/python/ayab/tests/test_communication_mockup.py b/src/main/python/ayab/tests/test_communication_mockup.py index 810fc85a..eeaf66c4 100644 --- a/src/main/python/ayab/tests/test_communication_mockup.py +++ b/src/main/python/ayab/tests/test_communication_mockup.py @@ -22,6 +22,7 @@ from ayab.engine.communication import MessageToken from ayab.engine.communication_mockup import AyabCommunicationMockup +from ayab.machine import Machine class TestAyabCommunicationMockup(unittest.TestCase): @@ -42,26 +43,31 @@ def test_update_API6(self): def test_req_start_API6(self): machine_val, start_val, end_val, continuous_reporting, crc8 = 0, 0, 10, True, 0xb9 - expected_result = (b'\xc1\x01', MessageToken.cnfStart, 1) - self.comm_dummy.req_start_API6(machine_val, start_val, end_val, continuous_reporting) + expected_result = (bytes([MessageToken.cnfStart.value, + 1]), MessageToken.cnfStart, 1) + self.comm_dummy.req_start_API6(machine_val, start_val, end_val, + continuous_reporting) bytes_read = self.comm_dummy.update_API6() assert bytes_read == expected_result def test_req_info(self): - expected_result = (b'\xc3\x05\xff\xff', MessageToken.cnfInfo, 5) + expected_result = (bytes([MessageToken.cnfInfo.value, 5, 0xff, + 0xff]), MessageToken.cnfInfo, 5) self.comm_dummy.req_info() bytes_read = self.comm_dummy.update_API6() assert bytes_read == expected_result # indState shall be sent automatically, also - expected_result = (b'\x84\x01\xff\xff\xff\xff\x01\x7f', - MessageToken.indState, 1) + expected_result = (bytes( + [MessageToken.indState.value, 1, 0xff, 0xff, 0xff, 0xff, 1, + 0x7f]), MessageToken.indState, 1) bytes_read = self.comm_dummy.update_API6() assert bytes_read == expected_result def test_req_test_API6(self): - expected_result = (b'\xc4\x01', MessageToken.cnfTest, 1) - self.comm_dummy.req_test_API6() + expected_result = (bytes([MessageToken.cnfTest.value, + 1]), MessageToken.cnfTest, 1) + self.comm_dummy.req_test_API6(Machine.KH910_KH950) bytes_read = self.comm_dummy.update_API6() assert bytes_read == expected_result @@ -71,14 +77,17 @@ def test_cnf_line_API6(self): flags = 0x12 lineData = [0x23, 0x24] crc8 = 0x24 - assert self.comm_dummy.cnf_line_API6(lineNumber, color, flags, lineData) + assert self.comm_dummy.cnf_line_API6(lineNumber, color, flags, + lineData) def test_req_line_API6(self): self.comm_dummy.open_serial() machine_val, start_val, end_val, continuous_reporting = 0, 0, 10, True - self.comm_dummy.req_start_API6(machine_val, start_val, end_val, continuous_reporting) + self.comm_dummy.req_start_API6(machine_val, start_val, end_val, + continuous_reporting) self.comm_dummy.update_API6() # cnfStart for i in range(0, 256): bytes_read = self.comm_dummy.update_API6() - assert bytes_read == (bytearray([0x82, i]), MessageToken.reqLine, i) + assert bytes_read == (bytearray([MessageToken.reqLine.value, + i]), MessageToken.reqLine, i)