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")
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, 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")
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