Example #1
0
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")
Example #2
0
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")
Example #3
0
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
Example #4
0
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")
Example #5
0
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