def __init__(self, device, baudrate, unsolicited_response_received_callback=None, skip_alp_parsing=False): self.log = logging.getLogger(__name__) self.parser = Parser(skip_alp_parsing) self.config = {"device": device, "baudrate": baudrate} self.uid = None self.firmware_version = None self.skip_alp_parsing = skip_alp_parsing self._sync_execution_response_cmds = [] self._sync_execution_tag_id = None self._sync_execution_completed = False self._unsolicited_responses_received = [] self._read_async_active = False self.unsolicited_response_received_callback = unsolicited_response_received_callback self.connected = False self.dev = serial.Serial( port=self.config["device"], baudrate=self.config["baudrate"], timeout=None, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS, xonxoff=False, rtscts=False, dsrdtr=False, exclusive=True, ) self.dev.flush() # ignore possible buffered data self.start_reading()
def __init__(self, device, baudrate, unsolicited_response_received_callback): self.log = logging.getLogger(__name__) self.parser = Parser() self.config = {"device": device, "baudrate": baudrate} self.uid = None self.firmware_version = None self._sync_execution_response_cmds = [] self._sync_execution_tag_id = None self._sync_execution_completed = False self._unsolicited_responses_received = [] self._read_async_active = False self.unsolicited_response_received_callback = unsolicited_response_received_callback connected = self._connect_serial_modem() if connected: self.log.info( "connected to {}, node UID {} running D7AP v{}, application \"{}\" with git sha1 {}" .format(self.config["device"], self.uid, self.firmware_version.d7ap_version, self.firmware_version.application_name, self.firmware_version.git_sha1)) else: raise ModemConnectionError
def __init__(self, device, baudrate, show_logging=True): self.show_logging = show_logging self.parser = Parser() self.config = { "device" : device, "baudrate" : baudrate } self.setup_serial_device()
def __init__(self, device, baudrate, receive_callback, show_logging=True): self.show_logging = show_logging self.parser = Parser() self.config = {"device": device, "baudrate": baudrate} self.uid = None self.firmware_version = None connected = self._connect_serial_modem() if connected: print( "connected to {}, node UID {} running D7AP v{}, application \"{}\" with git sha1 {}" .format(self.config["device"], self.uid, self.firmware_version.d7ap_version, self.firmware_version.application_name, self.firmware_version.git_sha1)) else: raise ModemConnectionError self.read_async_active = False self.receive_callback = receive_callback
def __init__(self, device, baudrate, receive_callback, show_logging=True): self.show_logging = show_logging self.parser = Parser() self.config = { "device" : device, "baudrate" : baudrate } self.uid = None self.firmware_version = None connected = self._connect_serial_modem() if connected: print("connected to {}, node UID {} running D7AP v{}, application \"{}\" with git sha1 {}".format( self.config["device"], hex(self.uid), self.firmware_version.d7ap_version, self.firmware_version.application_name, self.firmware_version.git_sha1) ) else: raise ModemConnectionError self.read_async_active = False self.receive_callback = receive_callback
class Modem: def __init__(self, device, baudrate, receive_callback, show_logging=True): self.show_logging = show_logging self.parser = Parser() self.config = { "device" : device, "baudrate" : baudrate } self.uid = None self.firmware_version = None connected = self._connect_serial_modem() if connected: print("connected to {}, node UID {} running D7AP v{}, application \"{}\" with git sha1 {}".format( self.config["device"], hex(self.uid), self.firmware_version.d7ap_version, self.firmware_version.application_name, self.firmware_version.git_sha1) ) else: raise ModemConnectionError self.read_async_active = False self.receive_callback = receive_callback def _connect_serial_modem(self): self.dev = serial.Serial( port = self.config["device"], baudrate = self.config["baudrate"], timeout = 0.5, ) read_modem_info_action = Command.create_with_read_file_action_system_file(UidFile()) read_modem_info_action.add_action( RegularAction( operation=ReadFileData( operand=DataRequest( offset=Offset(id=FirmwareVersionFile().id, offset=0), # TODO offset size length=FirmwareVersionFile().length ) ) ) ) self.send_command(read_modem_info_action) # read thread not yet running here, read sync start_time = datetime.now() timeout = False while not timeout: commands, info = self.read() for command in commands: for action in command.actions: if type(action) is RegularAction and type(action.operation) is ReturnFileData: if action.operand.offset.id == SystemFileIds.UID.value: self.uid = struct.unpack(">Q", bytearray(action.operand.data))[0] if action.operand.offset.id == SystemFileIds.FIRMWARE_VERSION.value: self.firmware_version = FirmwareVersionFile.parse(ConstBitStream(bytearray(action.operand.data))) if self.uid and self.firmware_version: return True if (datetime.now() - start_time).total_seconds() > 2: timeout = True self.log("Timed out reading node information") return False def log(self, *msg): if self.show_logging: print " ".join(map(str, msg)) def send_command(self, alp_command): data = self.parser.build_serial_frame(alp_command) self.dev.write(data) self.dev.flush() self.log("Sending command of size ", len(data)) self.log("> " + " ".join(map(lambda b: format(b, "02x"), data))) def d7asp_fifo_flush(self, alp_command): self.send_command(alp_command) flush_done = False should_restart_async_read = False if self.read_async_active: self.log("stopping read thread") should_restart_async_read = True self.read_async_active = False self.read_thread.shutdown = True self.read_thread.join() self.log("read thread stopped") start_time = datetime.now() timeout = False self.log("flush start of command with tag {}".format(alp_command.tag_id)) while not flush_done and not timeout: data_received = self.dev.read() self.log("< " + " ".join(map(lambda b: format(b, "02x"), bytearray(data_received)))) if len(data_received) > 0: (cmds, info) = self.parser.parse(data_received) for cmd in cmds: if cmd.tag_id == alp_command.tag_id: flush_done = True if cmd.completed_with_error: self.log("Flushing cmd with tag {} done, with error".format(cmd.tag_id)) else: self.log("Flushing cmd with tag {} done, without error".format(cmd.tag_id)) break for error in info["errors"]: error["buffer"] = " ".join(["0x{:02x}".format(ord(b)) for b in error["buffer"]]) print error if (datetime.now() - start_time).total_seconds() > 2: timeout = True self.log("Flush timed out, skipping") if should_restart_async_read: self.start_reading() def read(self): try: data = self.dev.read_all() if len(data) > 0: self.log("< " + " ".join(map(lambda b: format(b, "02x"), bytearray(data)))) except serial.SerialException: time.sleep(5) self.setup_serial_device() data = "" return self.parser.parse(data) def cancel_read(self): if self.read_async_active: self.read_async_active = False self.read_thread.shutdown = True self.read_thread.join() def start_reading(self): self.read_async_active = True self.read_thread = Thread(target=self.read_async) self.read_thread.daemon = True self.read_thread.start() def read_async(self): self.log("starting read thread") while self.read_async_active: data_received = self.dev.read() if len(data_received) > 0: self.log("< " + " ".join(map(lambda b: format(b, "02x"), bytearray(data_received)))) (cmds, info) = self.parser.parse(data_received) for error in info["errors"]: error["buffer"] = " ".join(["0x{:02x}".format(ord(b)) for b in error["buffer"]]) self.log("Parser error: {}".format(error)) for cmd in cmds: if self.receive_callback != None: self.receive_callback(cmd) self.log("end read thread")
class Modem: def __init__(self, device, baudrate, unsolicited_response_received_callback): self.log = logging.getLogger(__name__) self.parser = Parser() self.config = {"device": device, "baudrate": baudrate} self.uid = None self.firmware_version = None self._sync_execution_response_cmds = [] self._sync_execution_tag_id = None self._sync_execution_completed = False self._unsolicited_responses_received = [] self._read_async_active = False self.unsolicited_response_received_callback = unsolicited_response_received_callback connected = self._connect_serial_modem() if connected: self.log.info( "connected to {}, node UID {} running D7AP v{}, application \"{}\" with git sha1 {}" .format(self.config["device"], self.uid, self.firmware_version.d7ap_version, self.firmware_version.application_name, self.firmware_version.git_sha1)) else: raise ModemConnectionError def _connect_serial_modem(self): self.dev = serial.Serial( port=self.config["device"], baudrate=self.config["baudrate"], timeout=None, ) self.dev.flush() # ignore possible buffered data self.start_reading() read_modem_info_action = Command.create_with_read_file_action_system_file( UidFile()) read_modem_info_action.add_action( RegularAction(operation=ReadFileData(operand=DataRequest( offset=Offset(id=FirmwareVersionFile().id, offset=0), # TODO offset size length=FirmwareVersionFile().length)))) resp_cmd = self.execute_command(read_modem_info_action, timeout_seconds=60) if len(resp_cmd) == 0: self.log.warning("Timed out reading node information") return False for action in resp_cmd[0].actions: if type(action) is RegularAction and type( action.operation) is ReturnFileData: if action.operand.offset.id == SystemFileIds.UID.value: self.uid = '{:x}'.format( struct.unpack(">Q", bytearray(action.operand.data))[0]) if action.operand.offset.id == SystemFileIds.FIRMWARE_VERSION.value: self.firmware_version = FirmwareVersionFile.parse( ConstBitStream(bytearray(action.operand.data))) if self.uid and self.firmware_version: return True return False def execute_command_async(self, alp_command): self.execute_command(alp_command, timeout_seconds=0) def execute_command(self, alp_command, timeout_seconds=10): data = self.parser.build_serial_frame(alp_command) self._sync_execution_response_cmds = [] self._sync_execution_tag_id = None self._sync_execution_completed = False if (timeout_seconds > 0): assert self._sync_execution_tag_id is None self._sync_execution_tag_id = alp_command.tag_id self.dev.write(data) self.dev.flush() self.log.info("Sending command of size %s" % len(data)) self.log.debug("> " + " ".join(map(lambda b: format(b, "02x"), data))) if timeout_seconds == 0: return [] self.log.info( "Waiting for response (max {} s)".format(timeout_seconds)) start_time = datetime.now() while not self._sync_execution_completed and ( datetime.now() - start_time).total_seconds() < timeout_seconds: time.sleep(0.05) if not self._sync_execution_completed: self.log.info("Command timeout (tag {})".format( alp_command.tag_id)) return [] return self._sync_execution_response_cmds def start_reading(self): self._read_async_active = True self.read_thread = Thread(target=self._read_async) self.read_thread.daemon = True self.read_thread.start() def stop_reading(self): self._read_async_active = False self.dev.cancel_read() self.read_thread.join() def get_unsolicited_responses_received(self): return self._unsolicited_responses_received def clear_unsolicited_responses_received(self): self._unsolicited_responses_received = [] def _read_async(self): self.log.info("starting read thread") data_received = bytearray() while self._read_async_active: try: data_received = self.dev.read() except serial.SerialException: self.log.warning( "SerialException received, trying to reconnect") self.dev.close() time.sleep(5) self._connect_serial_modem() if len(data_received) > 0: self.log.debug("< " + " ".join( map(lambda b: format(b, "02x"), bytearray(data_received)))) (cmds, info) = self.parser.parse(data_received) for error in info["errors"]: error["buffer"] = " ".join( map(lambda b: format(b, "02x"), bytearray(data_received))) self.log.warning("Parser error: {}".format(error)) for cmd in cmds: if self._sync_execution_tag_id == cmd.tag_id: self.log.info("Received response for sync execution") self._sync_execution_response_cmds.append(cmd) if cmd.execution_completed: self.log.info("cmd with tag {} done".format( cmd.tag_id)) self._sync_execution_completed = True else: self.log.info( "cmd with tag {} not done yet, expecting more responses" .format(cmd.tag_id)) elif self.unsolicited_response_received_callback != None: self.unsolicited_response_received_callback(cmd) else: self.log.info( "Received a response which was not requested synchronously or no async callback provided" ) self._unsolicited_responses_received.append(cmd) self.log.info("end read thread")
import fileinput from d7a.serial_console_interface.parser import Parser parser = Parser() for hexstring in fileinput.input(): hexstring = hexstring.strip().replace(' ', '') cmds, info = parser.parse(bytearray(hexstring.decode("hex"))) for cmd in cmds: print cmd print info
#!/usr/bin/env python from d7a.serial_console_interface.parser import Parser from pprint import pprint cmd = [ 0x20, # action=32/ReturnFileData 0x40, # File ID 0x00, # offset 0x04, # length 0x00, 0xf3, 0x00, 0x00 # data ] frame = [ 0xC0, # interface sync byte 0, # interface version len(cmd), # ALP cmd length ] + cmd (cmds, info) = Parser().parse(frame) pprint(cmds[0].as_dict()) print(["0x{:02x}".format(b) for b in bytearray(cmds[0])])
def setUp(self): self.parser = Parser()
class Modem: def __init__(self, device, baudrate, receive_callback, show_logging=True): self.show_logging = show_logging self.parser = Parser() self.config = {"device": device, "baudrate": baudrate} self.uid = None self.firmware_version = None connected = self._connect_serial_modem() if connected: print( "connected to {}, node UID {} running D7AP v{}, application \"{}\" with git sha1 {}" .format(self.config["device"], self.uid, self.firmware_version.d7ap_version, self.firmware_version.application_name, self.firmware_version.git_sha1)) else: raise ModemConnectionError self.read_async_active = False self.receive_callback = receive_callback def _connect_serial_modem(self): self.dev = serial.Serial( port=self.config["device"], baudrate=self.config["baudrate"], timeout=0.5, ) read_modem_info_action = Command.create_with_read_file_action_system_file( UidFile()) read_modem_info_action.add_action( RegularAction(operation=ReadFileData(operand=DataRequest( offset=Offset(id=FirmwareVersionFile().id, offset=0), # TODO offset size length=FirmwareVersionFile().length)))) self.send_command(read_modem_info_action) # read thread not yet running here, read sync start_time = datetime.now() timeout = False while not timeout: commands, info = self.read() for command in commands: for action in command.actions: if type(action) is RegularAction and type( action.operation) is ReturnFileData: if action.operand.offset.id == SystemFileIds.UID.value: self.uid = '{:x}'.format( struct.unpack(">Q", bytearray( action.operand.data))[0]) if action.operand.offset.id == SystemFileIds.FIRMWARE_VERSION.value: self.firmware_version = FirmwareVersionFile.parse( ConstBitStream(bytearray(action.operand.data))) if self.uid and self.firmware_version: return True if (datetime.now() - start_time).total_seconds() > 2: timeout = True self.log("Timed out reading node information") return False def log(self, *msg): if self.show_logging: print " ".join(map(str, msg)) def send_command(self, alp_command): data = self.parser.build_serial_frame(alp_command) self.dev.write(data) self.dev.flush() self.log("Sending command of size ", len(data)) self.log("> " + " ".join(map(lambda b: format(b, "02x"), data))) def d7asp_fifo_flush(self, alp_command): self.send_command(alp_command) flush_done = False should_restart_async_read = False if self.read_async_active: self.log("stopping read thread") should_restart_async_read = True self.read_async_active = False self.read_thread.shutdown = True self.read_thread.join() self.log("read thread stopped") start_time = datetime.now() timeout = False self.log("flush start of command with tag {}".format( alp_command.tag_id)) while not flush_done and not timeout: data_received = self.dev.read() self.log("< " + " ".join( map(lambda b: format(b, "02x"), bytearray(data_received)))) if len(data_received) > 0: (cmds, info) = self.parser.parse(data_received) for cmd in cmds: self.log(cmd) if cmd.tag_id == alp_command.tag_id and cmd.execution_completed: flush_done = True if cmd.completed_with_error: self.log( "Flushing cmd with tag {} done, with error". format(cmd.tag_id)) else: self.log( "Flushing cmd with tag {} done, without error". format(cmd.tag_id)) break for error in info["errors"]: error["buffer"] = " ".join( ["0x{:02x}".format(ord(b)) for b in error["buffer"]]) print error if (datetime.now() - start_time).total_seconds() > 10: timeout = True self.log("Flush timed out, skipping") if should_restart_async_read: self.start_reading() def read(self): try: data = self.dev.read(self.dev.inWaiting()) if len(data) > 0: self.log( "< " + " ".join(map(lambda b: format(b, "02x"), bytearray(data)))) except serial.SerialException: time.sleep(5) self.setup_serial_device() data = "" return self.parser.parse(data) def cancel_read(self): if self.read_async_active: self.read_async_active = False self.read_thread.shutdown = True self.read_thread.join() def start_reading(self): self.read_async_active = True self.read_thread = Thread(target=self.read_async) self.read_thread.daemon = True self.read_thread.start() def read_async(self): self.log("starting read thread") while self.read_async_active: data_received = self.dev.read() if len(data_received) > 0: self.log("< " + " ".join( map(lambda b: format(b, "02x"), bytearray(data_received)))) (cmds, info) = self.parser.parse(data_received) for error in info["errors"]: error["buffer"] = " ".join( ["0x{:02x}".format(ord(b)) for b in error["buffer"]]) self.log("Parser error: {}".format(error)) for cmd in cmds: if self.receive_callback != None: self.receive_callback(cmd) self.log("end read thread")
def __init__(self, serial_device, serial_rate): self.parser = Parser() self.setup_serial_device(serial_device, serial_rate)
class Modem: def __init__(self, serial_device, serial_rate): self.parser = Parser() self.setup_serial_device(serial_device, serial_rate) def setup_serial_device(self, serial_device, serial_rate): self.dev = serial.Serial( port=serial_device, baudrate=serial_rate, timeout=0.5, ) self.uid = self.read_uid() print("connected to {}, node UID {}".format(serial_device, hex(self.uid))) def read_uid(self): self.send_command( Command.create_with_read_file_action_system_file(UidFile())) while True: # TODO timeout commands, info = self.read() for command in commands: for action in command.actions: if type(action) is RegularAction \ and type(action.operation) is ReturnFileData \ and action.operand.offset.id == SystemFileIds.UID: return struct.unpack(">Q", bytearray(action.operand.data))[0] def log(self, *msg): pass # print " ".join(map(str, msg)) def send_command(self, alp_command): data = self.parser.build_serial_frame(alp_command) self.dev.write(data) self.dev.flushOutput() self.log("Sending command of size", len(data)) def d7asp_fifo_flush(self, alp_command): self.send_command(alp_command) flush_done = False start_time = datetime.now() timeout = False while not flush_done and not timeout: data_received = self.dev.read() if len(data_received) > 0: (cmds, info) = self.parser.parse(data_received) for cmd in cmds: if cmd.flush_result != None: flush_done = True self.log( "Flushing fifo {} done, success_bitmap={}".format( cmd.flush_result.operand.fifo_token, cmd.flush_result.operand.success_bitmap)) break for error in info["errors"]: error["buffer"] = " ".join( ["0x{:02x}".format(ord(b)) for b in error["buffer"]]) print error if (datetime.now() - start_time).total_seconds() > 2: timeout = True self.log("Flush timed out, skipping") def read(self): # self.log("Bytes in serial buffer: {}".format(self.dev.inWaiting())) data_received = self.dev.read_all() return self.parser.parse(data_received) def cancel_read(self): self.stop_reading = True def read_async(self): self.stop_reading = False while not self.stop_reading: data_received = self.dev.read() if len(data_received) > 0: (cmds, info) = self.parser.parse(data_received) for error in info["errors"]: error["buffer"] = " ".join( ["0x{:02x}".format(ord(b)) for b in error["buffer"]]) print error for cmd in cmds: yield cmd
class Modem: def __init__(self, device, baudrate, show_logging=True): self.show_logging = show_logging self.parser = Parser() self.config = { "device" : device, "baudrate" : baudrate } self.setup_serial_device() def setup_serial_device(self): self.dev = serial.Serial( port = self.config["device"], baudrate = self.config["baudrate"], timeout = 0.5, ) # FIXME: this seems to fail sometimes ?! # self.uid = self.read_uid() # print("connected to {}, node UID {}".format(serial_device, hex(self.uid))) def read_uid(self): self.send_command(Command.create_with_read_file_action_system_file(UidFile())) while True: # TODO timeout commands, info = self.read() for command in commands: for action in command.actions: if type(action) is RegularAction \ and type(action.operation) is ReturnFileData \ and action.operand.offset.id == SystemFileIds.UID: return struct.unpack(">Q", bytearray(action.operand.data))[0] def log(self, *msg): if self.show_logging: print " ".join(map(str, msg)) def send_command(self, alp_command): data = self.parser.build_serial_frame(alp_command) self.dev.write(data) self.dev.flush() self.log("Sending command of size", len(data)) def d7asp_fifo_flush(self, alp_command): self.send_command(alp_command) flush_done = False start_time = datetime.now() timeout = False self.log("flush start of command with tag {}".format(alp_command.tag_id)) while not flush_done and not timeout: data_received = self.dev.read() if len(data_received) > 0: (cmds, info) = self.parser.parse(data_received) for cmd in cmds: if cmd.tag_id == alp_command.tag_id: flush_done = True if cmd.completed_with_error: self.log("Flushing cmd with tag {} done, with error".format(cmd.tag_id)) else: self.log("Flushing cmd with tag {} done, without error".format(cmd.tag_id)) break for error in info["errors"]: error["buffer"] = " ".join(["0x{:02x}".format(ord(b)) for b in error["buffer"]]) print error if (datetime.now() - start_time).total_seconds() > 2: timeout = True self.log("Flush timed out, skipping") def read(self): try: data = self.dev.read_all() except serial.SerialException: time.sleep(5) self.setup_serial_device() data = "" return self.parser.parse(data) def cancel_read(self): self.stop_reading = True def read_async(self): self.stop_reading = False while not self.stop_reading: data_received = self.dev.read() if len(data_received) > 0: (cmds, info) = self.parser.parse(data_received) for error in info["errors"]: error["buffer"] = " ".join(["0x{:02x}".format(ord(b)) for b in error["buffer"]]) print error for cmd in cmds: yield cmd
class TestParser(unittest.TestCase): def setUp(self): self.parser = Parser() def test_basic_valid_message(self): alp_cmd_bytes = [ 0x20, # action=32/ReturnFileData 0x40, # File ID 0x00, # offset 0x04, # length 0x00, 0xf3, 0x00, 0x00 # data ] frame = [ 0xC0, # interface sync byte 0, # interface version len(alp_cmd_bytes), # ALP cmd length ] + alp_cmd_bytes (cmds, info) = self.parser.parse(frame) self.assertEqual(cmds[0].actions[0].operation.op, 32) self.assertEqual(cmds[0].actions[0].operation.operand.length.value, 4) def test_bad_identifier(self): (cmds, info) = self.parser.parse([ 0x0c, # that's 0c not c0 ! ;-) 0x04, 0x00, 0x00, 0x00, 0x20, 0x24, 0x8a, 0xb6, 0x00, 0x52, 0x0b, 0x35, 0x2c, 0x20, 0x40, 0x00, 0x00 ]) self.assertEquals(len(cmds), 0) self.assertEquals(len(info["errors"]), 1) def test_buffer_skipping(self): self.parser.buffer = bytearray( [0x10, 0x20, 0x30, 0xc0, 0x10, 0x20, 0x30]) skipped = self.parser.skip_bad_buffer_content() self.assertEquals(skipped, 3) self.assertEquals(self.parser.buffer, bytearray([0xc0, 0x10, 0x20, 0x30])) def test_entire_buffer_skipping(self): self.parser.buffer = [0x10, 0x20, 0x30, 0x10, 0x20, 0x30] skipped = self.parser.skip_bad_buffer_content() self.assertEquals(skipped, 6) self.assertEquals(self.parser.buffer, bytearray()) def test_empty_buffer_skipping(self): self.parser.buffer = [] skipped = self.parser.skip_bad_buffer_content() self.assertEquals(skipped, 0) self.assertEquals(self.parser.buffer, []) def test_buffer_skipping_with_first_item_the_id(self): self.parser.buffer = [0xc0, 0x10, 0x20, 0x30] skipped = self.parser.skip_bad_buffer_content() self.assertEquals(skipped, 4) self.assertEquals(self.parser.buffer, bytearray()) def test_buffer_skipping_with_first_and_second_item_the_id(self): self.parser.buffer = bytearray([0xc0, 0xc0, 0x10, 0x20, 0x30]) skipped = self.parser.skip_bad_buffer_content() self.assertEquals(skipped, 1) self.assertEquals(self.parser.buffer, bytearray([0xc0, 0x10, 0x20, 0x30])) def test_bad_identifier_with_identifier_in_body(self): (cmds, info) = self.parser.parse( bytearray([ 0x0c, # that's 0c not c0 ! ;-) 0x04, 0x00, 0x00, 0x00, 0x20, 0x24, 0x8a, 0xc0, 0x00, 7, 0x0b, 0x35, 0x2c, 0x7d, # ^ here's another one 0x40, 0x00, 0x00 ])) self.assertEquals(len(cmds), 0) self.assertEquals(len(info["errors"]), 2) self.assertEquals(info["errors"][0]["skipped"], 8) def test_partial_command(self): alp_action_bytes = bytearray([ 0x20, # action=32/ReturnFileData 0x40, # File ID 0x00, # offset 0x04, # length 0x00, 0xf3, 0x00, 0x00 # data ]) (cmds, info) = self.parser.parse( bytearray([ 0xc0, # interface start 0, 2 * len(alp_action_bytes ) # expect 2 ALP actions but only one in buffer ]) + alp_action_bytes) self.assertEquals(len(cmds), 0) self.assertEquals(len(info["errors"]), 0) self.assertEquals(info["parsed"], 0) def test_continue_partial_command(self): self.test_partial_command( ) # incomplete command, add second ALP action to complete it ... (cmds, info) = self.parser.parse( bytearray([ 0x20, # action=32/ReturnFileData 0x40, # File ID 0x00, # offset 0x04, # length 0x00, 0xf3, 0x00, 0x00 # data ])) self.assertEquals(len(info["errors"]), 0) self.assertEqual(len(cmds[0].actions), 2) def test_continue_from_bad_buffer(self): self.test_bad_identifier_with_identifier_in_body() # buffer is bad now self.test_basic_valid_message() # cont. with valid msg def test_continue_partial_second_frame(self): alp_cmd_bytes = [ 0x20, # action=32/ReturnFileData 0x40, # File ID 0x00, # offset 0x04, # length 0x00, 0xf3, 0x00, 0x00 # data ] frame = [ 0xC0, # interface sync byte 0, # interface version len(alp_cmd_bytes), # ALP cmd length ] + alp_cmd_bytes + [ # second, partial frame 0xC0, 0, len(alp_cmd_bytes) ] # first frame should parse (cmds, info) = self.parser.parse(frame) self.assertEqual(cmds[0].actions[0].operation.op, 32) self.assertEqual(cmds[0].actions[0].operation.operand.length.value, 4) # and now complete the second frame and check this is parsed as well (cmds, info) = self.parser.parse( alp_cmd_bytes) # the missing bytes only, without the frame header self.assertEqual(cmds[0].actions[0].operation.op, 32) self.assertEqual(cmds[0].actions[0].operation.operand.length.value, 4)
argparser.add_argument("-t", "--type", choices=parser_types, required=True) argparser.add_argument("-f", "--file-id", help="the ID of the system file to parse", type=int) argparser.add_argument('data', help="The data to be parsed, input as an hexstring") args = argparser.parse_args() hexstring = args.data.strip().replace(' ', '') data = bytearray(hexstring.decode("hex")) if args.type == "alp": print AlpParser().parse(ConstBitStream(data), len(data)) exit(0) if args.type == "serial": parser = SerialParser() if args.type == "fg": parser = DllFrameParser(frame_type=FrameType.FOREGROUND) if args.type == "bg": parser = DllFrameParser(frame_type=FrameType.BACKGROUND) if args.type == "systemfile": file = SystemFileIds(args.file_id) file_type = SystemFiles().files[file] print(file_type.parse(ConstBitStream(data))) exit(0) cmds, info = parser.parse(data) for cmd in cmds: print cmd print info
class TestParser(unittest.TestCase): def setUp(self): self.parser = Parser() def test_basic_valid_message(self): alp_cmd_bytes = [ 0x20, # action=32/ReturnFileData 0x40, # File ID 0x00, # offset 0x04, # length 0x00, 0xF3, 0x00, 0x00, # data ] frame = [ 0xC0, # interface sync byte 0, # interface version len(alp_cmd_bytes), # ALP cmd length ] + alp_cmd_bytes (cmds, info) = self.parser.parse(frame) self.assertEqual(cmds[0].actions[0].operation.op, 32) self.assertEqual(cmds[0].actions[0].operation.operand.length, 4) def test_bad_identifier(self): (cmds, info) = self.parser.parse( [ 0x0C, # that's 0c not c0 ! ;-) 0x04, 0x00, 0x00, 0x00, 0x20, 0x24, 0x8A, 0xB6, 0x00, 0x52, 0x0B, 0x35, 0x2C, 0x20, 0x40, 0x00, 0x00, ] ) self.assertEquals(len(cmds), 0) self.assertEquals(len(info["errors"]), 1) def test_buffer_skipping(self): self.parser.buffer = [0x10, 0x20, 0x30, 0xC0, 0x10, 0x20, 0x30] skipped = self.parser.skip_bad_buffer_content() self.assertEquals(skipped, 3) self.assertEquals(self.parser.buffer, [0xC0, 0x10, 0x20, 0x30]) def test_entire_buffer_skipping(self): self.parser.buffer = [0x10, 0x20, 0x30, 0x10, 0x20, 0x30] skipped = self.parser.skip_bad_buffer_content() self.assertEquals(skipped, 6) self.assertEquals(self.parser.buffer, []) def test_empty_buffer_skipping(self): self.parser.buffer = [] skipped = self.parser.skip_bad_buffer_content() self.assertEquals(skipped, 0) self.assertEquals(self.parser.buffer, []) def test_buffer_skipping_with_first_item_the_id(self): self.parser.buffer = [0xC0, 0x10, 0x20, 0x30] skipped = self.parser.skip_bad_buffer_content() self.assertEquals(skipped, 4) self.assertEquals(self.parser.buffer, []) def test_buffer_skipping_with_first_and_second_item_the_id(self): self.parser.buffer = [0xC0, 0xC0, 0x10, 0x20, 0x30] skipped = self.parser.skip_bad_buffer_content() self.assertEquals(skipped, 1) self.assertEquals(self.parser.buffer, [0xC0, 0x10, 0x20, 0x30]) def test_bad_identifier_with_identifier_in_body(self): (cmds, info) = self.parser.parse( [ 0x0C, # that's 0c not c0 ! ;-) 0x04, 0x00, 0x00, 0x00, 0x20, 0x24, 0x8A, 0xC0, 0x00, 7, 0x0B, 0x35, 0x2C, 0x7D, # ^ here's another one 0x40, 0x00, 0x00, ] ) self.assertEquals(len(cmds), 0) self.assertEquals(len(info["errors"]), 2) self.assertEquals(info["errors"][0]["skipped"], 8) def test_partial_command(self): alp_action_bytes = [ 0x20, # action=32/ReturnFileData 0x40, # File ID 0x00, # offset 0x04, # length 0x00, 0xF3, 0x00, 0x00, # data ] (cmds, info) = self.parser.parse( [0xC0, 0, 2 * len(alp_action_bytes)] # interface start # expect 2 ALP actions but only one in buffer + alp_action_bytes ) self.assertEquals(len(cmds), 0) self.assertEquals(len(info["errors"]), 0) self.assertEquals(info["parsed"], 0) def test_continue_partial_command(self): self.test_partial_command() # incomplete command, add second ALP action to complete it ... (cmds, info) = self.parser.parse( [ 0x20, # action=32/ReturnFileData 0x40, # File ID 0x00, # offset 0x04, # length 0x00, 0xF3, 0x00, 0x00, # data ] ) self.assertEquals(len(info["errors"]), 0) self.assertEqual(len(cmds[0].actions), 2) def test_continue_from_bad_buffer(self): self.test_bad_identifier_with_identifier_in_body() # buffer is bad now self.test_basic_valid_message() # cont. with valid msg