def test_byte_generation(self): bytes = bytearray(DllConfigFile()) self.assertEqual(len(bytes), 7) self.assertEqual(bytes[0], 0) self.assertEqual(bytes[1], 0) self.assertEqual(bytes[2], 0) self.assertEqual(bytes[3], 0) self.assertEqual(bytes[4], 0) self.assertEqual(bytes[5], 0) self.assertEqual(bytes[6], 0) bytes = bytearray( DllConfigFile(active_access_class=5, lq_filter=1, nf_ctrl=2, rx_nf_method_parameter=3, tx_nf_method_parameter=4)) self.assertEqual(len(bytes), 7) self.assertEqual(bytes[0], 5) self.assertEqual(bytes[1], 0) self.assertEqual(bytes[2], 0) self.assertEqual(bytes[3], 1) self.assertEqual(bytes[4], 2) self.assertEqual(bytes[5], 3) self.assertEqual(bytes[6], 4)
def test_byte_generation(self): bytes = bytearray(DllConfigFile()) self.assertEqual(len(bytes), 3) self.assertEqual(bytes[0], 0) self.assertEqual(bytes[1], 0xFF) self.assertEqual(bytes[2], 0xFF) bytes = bytearray(DllConfigFile(active_access_class=5, vid=100)) self.assertEqual(len(bytes), 3) self.assertEqual(bytes[0], 5) self.assertEqual(bytes[1], 0) self.assertEqual(bytes[2], 100)
class SystemFiles: files = { SystemFileIds.UID: UidFile(), SystemFileIds.FIRMWARE_VERSION: FirmwareVersionFile(), SystemFileIds.DLL_CONFIG: DllConfigFile(), SystemFileIds.ACCESS_PROFILE_0: AccessProfileFile(access_specifier=0), SystemFileIds.ACCESS_PROFILE_1: AccessProfileFile(access_specifier=1), SystemFileIds.ACCESS_PROFILE_2: AccessProfileFile(access_specifier=2), SystemFileIds.ACCESS_PROFILE_3: AccessProfileFile(access_specifier=3), SystemFileIds.ACCESS_PROFILE_4: AccessProfileFile(access_specifier=4), SystemFileIds.ACCESS_PROFILE_5: AccessProfileFile(access_specifier=5), SystemFileIds.ACCESS_PROFILE_6: AccessProfileFile(access_specifier=6), SystemFileIds.ACCESS_PROFILE_7: AccessProfileFile(access_specifier=7), SystemFileIds.ACCESS_PROFILE_8: AccessProfileFile(access_specifier=8), SystemFileIds.ACCESS_PROFILE_9: AccessProfileFile(access_specifier=9), SystemFileIds.ACCESS_PROFILE_10: AccessProfileFile(access_specifier=10), SystemFileIds.ACCESS_PROFILE_11: AccessProfileFile(access_specifier=11), SystemFileIds.ACCESS_PROFILE_12: AccessProfileFile(access_specifier=12), SystemFileIds.ACCESS_PROFILE_13: AccessProfileFile(access_specifier=13), SystemFileIds.ACCESS_PROFILE_14: AccessProfileFile(access_specifier=14), } def get_all_system_files(self): return sorted(self.files, key=lambda t: t.value)
def test_default_constructor(self): c = DllConfigFile() self.assertEqual(c.active_access_class, 0) self.assertEqual(c.lq_filter, 0) self.assertEqual(c.nf_ctrl, 0) self.assertEqual(c.rx_nf_method_parameter, 0) self.assertEqual(c.tx_nf_method_parameter, 0)
def test_parsing(self): file_contents = [ 5, # active access class 0x00, 0x09 # VID ] config = DllConfigFile.parse(ConstBitStream(bytes=file_contents)) self.assertEqual(config.active_access_class, 5) self.assertEqual(config.vid, 9)
def test_parsing(self): file_contents = [ 5, # active access class 0x00, 0x00, # RFU 0x01, # LQ filter 0x02, # NF CTRL 0x03, # RX NF Method Parameter 0x04, # TX NF Method Parameter ] config = DllConfigFile.parse(ConstBitStream(bytes=file_contents)) self.assertEqual(config.active_access_class, 5) self.assertEqual(config.lq_filter, 1) self.assertEqual(config.nf_ctrl, 2) self.assertEqual(config.rx_nf_method_parameter, 3) self.assertEqual(config.tx_nf_method_parameter, 4)
def __init__(self): self.argparser = argparse.ArgumentParser( fromfile_prefix_chars="@", description="Test throughput over 2 serial D7 modems") self.argparser.add_argument("-n", "--msg-count", help="number of messages to transmit", type=int, default=10) self.argparser.add_argument( "-p", "--payload-size", help="number of bytes of (appl level) payload to transmit", type=int, default=50) self.argparser.add_argument( "-sw", "--serial-transmitter", help="serial device /dev file transmitter node", default=None) self.argparser.add_argument( "-sr", "--serial-receiver", help="serial device /dev file receiver node", default=None) self.argparser.add_argument("-r", "--rate", help="baudrate for serial device", type=int, default=115200) self.argparser.add_argument( "-uid", "--unicast-uid", help="UID to use for unicast transmission, " "when not using receiver " "(in hexstring, for example 0xb57000009151d)", default=None) self.argparser.add_argument( "-to", "--receiver-timeout", help="timeout for the receiver (in seconds)", type=int, default=10) self.argparser.add_argument("-v", "--verbose", help="verbose", default=False, action="store_true") self.config = self.argparser.parse_args() if self.config.serial_transmitter == None and self.config.serial_receiver == None: self.argparser.error( "At least a transmitter or receiver is required.") if self.config.serial_receiver == None and self.config.unicast_uid == None: self.argparser.error( "When running without receiver a --unicast-uid parameter is required." ) if self.config.serial_transmitter == None: self.transmitter_modem = None print("Running without transmitter") else: self.transmitter_modem = Modem(self.config.serial_transmitter, self.config.rate, None, show_logging=self.config.verbose) access_profile = AccessProfile( channel_header=ChannelHeader( channel_band=ChannelBand.BAND_868, channel_coding=ChannelCoding.PN9, channel_class=ChannelClass.NORMAL_RATE), sub_profiles=[ SubProfile(subband_bitmap=0x01, scan_automation_period=CT(exp=0, mant=0)), SubProfile(), SubProfile(), SubProfile() ], sub_bands=[ SubBand( channel_index_start=0, channel_index_end=0, eirp=10, cca=86 # TODO ) ]) print("Write Access Profile") write_ap_cmd = Command.create_with_write_file_action_system_file( file=AccessProfileFile(access_profile=access_profile, access_specifier=0)) self.transmitter_modem.send_command(write_ap_cmd) if self.config.serial_receiver == None: self.receiver_modem = None print("Running without receiver") else: self.receiver_modem = Modem(self.config.serial_receiver, self.config.rate, self.receiver_cmd_callback, show_logging=self.config.verbose) self.receiver_modem.send_command( Command.create_with_write_file_action_system_file( DllConfigFile(active_access_class=0x01))) print("Receiver scanning on Access Class = 0x01")
def start(self): self.received_commands = defaultdict(list) payload = range(self.config.payload_size) if self.receiver_modem != None: addressee_id = int(self.receiver_modem.uid, 16) else: addressee_id = int(self.config.unicast_uid, 16) if self.transmitter_modem != None: print( "\n==> broadcast, with QoS, transmitter active access class = 0x01 ====" ) self.transmitter_modem.send_command( Command.create_with_write_file_action_system_file( DllConfigFile(active_access_class=0x01))) interface_configuration = Configuration( qos=QoS(resp_mod=ResponseMode.RESP_MODE_ANY), addressee=Addressee( access_class=0x01, id_type=IdType.NBID, id=CT(exp=0, mant=1) # we expect one responder )) self.start_transmitting( interface_configuration=interface_configuration, payload=payload) self.wait_for_receiver(payload) print( "\n==> broadcast, no QoS, transmitter active access class = 0x01 ====" ) self.transmitter_modem.send_command( Command.create_with_write_file_action_system_file( DllConfigFile(active_access_class=0x01))) interface_configuration = Configuration( qos=QoS(resp_mod=ResponseMode.RESP_MODE_NO), addressee=Addressee(access_class=0x01, id_type=IdType.NOID)) self.start_transmitting( interface_configuration=interface_configuration, payload=payload) self.wait_for_receiver(payload) print( "\n==> unicast, with QoS, transmitter active access class = 0x01" ) interface_configuration = Configuration( qos=QoS(resp_mod=ResponseMode.RESP_MODE_ANY), addressee=Addressee(access_class=0x01, id_type=IdType.UID, id=addressee_id)) self.start_transmitting( interface_configuration=interface_configuration, payload=payload) self.wait_for_receiver(payload) print( "\n==> unicast, no QoS, transmitter active access class = 0x01" ) interface_configuration = Configuration( qos=QoS(resp_mod=ResponseMode.RESP_MODE_NO), addressee=Addressee(access_class=0x01, id_type=IdType.UID, id=addressee_id)) self.start_transmitting( interface_configuration=interface_configuration, payload=payload) self.wait_for_receiver(payload) else: # receive only self.receiver_modem.start_reading() self.wait_for_receiver(payload)
def run(self): # in this example we will instruct the modem in the GW to switch to another active class cmd = Command.create_with_write_file_action_system_file( DllConfigFile(active_access_class=self.config.active_access_class)) self.execute_rpc_command(self.config.device, cmd)
class SystemFiles: files = { SystemFileIds.UID: UidFile(), SystemFileIds.FACTORY_SETTINGS: FactorySettingsFile(), SystemFileIds.FIRMWARE_VERSION: FirmwareVersionFile(), SystemFileIds.DEVICE_CAPACITY: NotImplementedFile(SystemFileIds.DEVICE_CAPACITY.value, 19), SystemFileIds.DEVICE_STATUS: NotImplementedFile(SystemFileIds.DEVICE_STATUS, 9), SystemFileIds.ENGINEERING_MODE: EngineeringModeFile(), SystemFileIds.VID: VidFile(), SystemFileIds.RFU_07: NotImplementedFile(SystemFileIds.RFU_07, 0), SystemFileIds.PHY_CONFIG: NotImplementedFile(SystemFileIds.PHY_CONFIG, 9), SystemFileIds.PHY_STATUS: NotImplementedFile(SystemFileIds.PHY_STATUS, 24), # TODO assuming 3 channels for now SystemFileIds.DLL_CONFIG: DllConfigFile(), SystemFileIds.DLL_STATUS: NotImplementedFile(SystemFileIds.DLL_STATUS, 12), SystemFileIds.NWL_ROUTING: NotImplementedFile(SystemFileIds.NWL_ROUTING, 1), # TODO variable routing table SystemFileIds.NWL_SECURITY: NotImplementedFile(SystemFileIds.NWL_SECURITY, 5), SystemFileIds.NWL_SECURITY_KEY: SecurityKeyFile(), SystemFileIds.NWL_SSR: NotImplementedFile(SystemFileIds.NWL_SSR, 4), # TODO 0 recorded devices SystemFileIds.NWL_STATUS: NotImplementedFile(SystemFileIds.NWL_STATUS, 20), SystemFileIds.TRL_STATUS: NotImplementedFile(SystemFileIds.TRL_STATUS, 1), # TODO 0 TRL records SystemFileIds.SEL_CONFIG: NotImplementedFile(SystemFileIds.SEL_CONFIG, 6), SystemFileIds.FOF_STATUS: NotImplementedFile(SystemFileIds.FOF_STATUS, 10), SystemFileIds.RFU_14: NotImplementedFile(SystemFileIds.RFU_14, 0), SystemFileIds.RFU_15: NotImplementedFile(SystemFileIds.RFU_15, 0), SystemFileIds.RFU_16: NotImplementedFile(SystemFileIds.RFU_16, 0), SystemFileIds.LOCATION_DATA: NotImplementedFile(SystemFileIds.LOCATION_DATA, 1), # TODO 0 recorded locations SystemFileIds.D7AALP_RFU_18: NotImplementedFile(SystemFileIds.D7AALP_RFU_18, 0), SystemFileIds.D7AALP_RFU_19: NotImplementedFile(SystemFileIds.D7AALP_RFU_19, 0), SystemFileIds.D7AALP_RFU_1A: NotImplementedFile(SystemFileIds.D7AALP_RFU_1A, 0), SystemFileIds.D7AALP_RFU_1B: NotImplementedFile(SystemFileIds.D7AALP_RFU_1B, 0), SystemFileIds.D7AALP_RFU_1C: NotImplementedFile(SystemFileIds.D7AALP_RFU_1C, 0), SystemFileIds.D7AALP_RFU_1D: NotImplementedFile(SystemFileIds.D7AALP_RFU_1D, 0), SystemFileIds.D7AALP_RFU_1E: NotImplementedFile(SystemFileIds.D7AALP_RFU_1E, 0), SystemFileIds.D7AALP_RFU_1F: NotImplementedFile(SystemFileIds.D7AALP_RFU_1F, 0), SystemFileIds.ACCESS_PROFILE_0: AccessProfileFile(access_specifier=0), SystemFileIds.ACCESS_PROFILE_1: AccessProfileFile(access_specifier=1), SystemFileIds.ACCESS_PROFILE_2: AccessProfileFile(access_specifier=2), SystemFileIds.ACCESS_PROFILE_3: AccessProfileFile(access_specifier=3), SystemFileIds.ACCESS_PROFILE_4: AccessProfileFile(access_specifier=4), SystemFileIds.ACCESS_PROFILE_5: AccessProfileFile(access_specifier=5), SystemFileIds.ACCESS_PROFILE_6: AccessProfileFile(access_specifier=6), SystemFileIds.ACCESS_PROFILE_7: AccessProfileFile(access_specifier=7), SystemFileIds.ACCESS_PROFILE_8: AccessProfileFile(access_specifier=8), SystemFileIds.ACCESS_PROFILE_9: AccessProfileFile(access_specifier=9), SystemFileIds.ACCESS_PROFILE_10: AccessProfileFile(access_specifier=10), SystemFileIds.ACCESS_PROFILE_11: AccessProfileFile(access_specifier=11), SystemFileIds.ACCESS_PROFILE_12: AccessProfileFile(access_specifier=12), SystemFileIds.ACCESS_PROFILE_13: AccessProfileFile(access_specifier=13), SystemFileIds.ACCESS_PROFILE_14: AccessProfileFile(access_specifier=14) } def get_all_system_files(self): return sorted(self.files, key=lambda t: t.value)
def __init__(self): argparser = argparse.ArgumentParser() argparser.add_argument("-d", "--device", help="serial device /dev file modem", default="/dev/ttyACM0") argparser.add_argument("-r", "--rate", help="baudrate for serial device", type=int, default=115200) argparser.add_argument("-v", "--verbose", help="verbose", default=False, action="store_true") argparser.add_argument("-t", "--token", help="Access token for the TB gateway", required=True) argparser.add_argument("-tb", "--thingsboard", help="Thingsboard hostname/IP", default="localhost") argparser.add_argument("-p", "--plugin-path", help="path where plugins are stored", default="") argparser.add_argument("-bp", "--broker-port", help="mqtt broker port", default="1883") argparser.add_argument( "-l", "--logfile", help="specify path if you want to log to file instead of to stdout", default="") argparser.add_argument( "-k", "--keep-data", help= "Save data locally when Thingsboard is disconnected and send it when connection is restored.", default=True) argparser.add_argument( "-b", "--save-bandwidth", help="Send data in binary format to save bandwidth", action="store_true") argparser.add_argument("-sf", "--skip-system-files", help="Do not read system files on boot", action="store_true") self.bridge_count = 0 self.next_report = 0 self.config = argparser.parse_args() self.log = logging.getLogger() formatter = logging.Formatter( '%(asctime)s %(name)-12s %(levelname)-8s %(message)s') if self.config.logfile == "": handler = logging.StreamHandler() else: handler = logging.FileHandler(self.config.logfile) handler.setFormatter(formatter) self.log.addHandler(handler) self.log.setLevel(logging.INFO) if self.config.verbose: self.log.setLevel(logging.DEBUG) self.tb = Thingsboard(self.config.thingsboard, self.config.token, self.on_mqtt_message, persistData=self.config.keep_data) if self.config.plugin_path != "": self.load_plugins(self.config.plugin_path) self.modem = Modem(self.config.device, self.config.rate, self.on_command_received, self.config.save_bandwidth) connected = self.modem.connect() while not connected: try: self.log.warning("Not connected to modem, retrying ...") time.sleep(1) connected = self.modem.connect() except KeyboardInterrupt: self.log.info("received KeyboardInterrupt... stopping") self.tb.disconnect() exit(-1) except: exc_type, exc_value, exc_traceback = sys.exc_info() lines = traceback.format_exception(exc_type, exc_value, exc_traceback) trace = "".join(lines) self.log.error( "Exception while connecting modem: \n{}".format(trace)) # switch to continuous foreground scan access profile self.modem.execute_command( Command.create_with_write_file_action_system_file( DllConfigFile(active_access_class=0x01)), timeout_seconds=1) if self.config.save_bandwidth: self.log.info("Running in save bandwidth mode") if self.config.plugin_path is not "": self.log.warning( "Save bandwidth mode is enabled, plugin files will not be used" ) # update attribute containing git rev so we can track revision at TB platform git_sha = subprocess.check_output(["git", "describe", "--always"]).strip() ip = self.get_ip() self.tb.sendGwAttributes({ 'UID': self.modem.uid, 'git-rev': git_sha, 'IP': ip, 'save bw': str(self.config.save_bandwidth) }) self.log.info("Running on {} with git rev {} using modem {}".format( ip, git_sha, self.modem.uid)) # read all system files on the local node to store as attributes on TB if not self.config.skip_system_files: self.log.info("Reading all system files ...") for file in SystemFiles().files.values(): self.modem.execute_command_async( Command.create_with_read_file_action_system_file(file))
def test_default_constructor(self): c = DllConfigFile() self.assertEqual(c.active_access_class, 0) self.assertEqual(c.vid, 0xFFFF)
def bad(): DllConfigFile(active_access_class=0xFF01) # can be max 0xFF