def test_default_constructor(self): c = EngineeringModeFile() self.assertEqual(c.mode, EngineeringModeMode.ENGINEERING_MODE_MODE_OFF) self.assertEqual(c.flags, 0) self.assertEqual(c.timeout, 0) self.assertEqual(c.channel_id.channel_header, ChannelHeader(ChannelCoding.PN9, ChannelClass.LO_RATE, ChannelBand.BAND_868)) self.assertEqual(c.channel_id.channel_index, 0) self.assertEqual(c.eirp, 0)
def test_byte_generation(self): bytes = bytearray(EngineeringModeFile()) self.assertEqual(len(bytes), 9) self.assertEqual(bytes[0], 0) self.assertEqual(bytes[1], 0) self.assertEqual(bytes[2], 0) self.assertEqual(bytes[3], 0x30) self.assertEqual(bytes[4], 0) self.assertEqual(bytes[5], 0) self.assertEqual(bytes[6], 0) self.assertEqual(bytes[7], 0) self.assertEqual(bytes[8], 0) bytes = bytearray(EngineeringModeFile(mode=EngineeringModeMode.ENGINEERING_MODE_MODE_PER_RX, flags=9, timeout=8, channel_id=ChannelID(channel_header=ChannelHeader(ChannelCoding.CW,ChannelClass.HI_RATE,ChannelBand.BAND_868), channel_index=7), eirp=6)) self.assertEqual(len(bytes), 9) self.assertEqual(bytes[0], 3) self.assertEqual(bytes[1], 9) self.assertEqual(bytes[2], 8) self.assertEqual(bytes[3], 0x3F) self.assertEqual(bytes[4], 0) self.assertEqual(bytes[5], 7) self.assertEqual(bytes[6], 6) self.assertEqual(bytes[7], 0) self.assertEqual(bytes[8], 0) bytes = bytearray(EngineeringModeFile(mode=EngineeringModeMode.ENGINEERING_MODE_MODE_PER_RX, flags=9, timeout=8, channel_id=ChannelID( channel_header=ChannelHeader(ChannelCoding.CW, ChannelClass.HI_RATE, ChannelBand.BAND_868), channel_index=7), eirp=-6)) self.assertEqual(len(bytes), 9) self.assertEqual(bytes[0], 3) self.assertEqual(bytes[1], 9) self.assertEqual(bytes[2], 8) self.assertEqual(bytes[3], 0x3F) self.assertEqual(bytes[4], 0) self.assertEqual(bytes[5], 7) self.assertEqual(bytes[6], 0xFA) self.assertEqual(bytes[7], 0) self.assertEqual(bytes[8], 0)
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() configure_default_logger(self.config.verbose) 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) 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.execute_command(write_ap_cmd, timeout_seconds=1) 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) self.receiver_modem.execute_command(Command.create_with_write_file_action_system_file(DllConfigFile(active_access_class=0x01)), timeout_seconds=1) print("Receiver scanning on Access Class = 0x01")
def test_generate_channel_id_string(self): ch = ChannelID( channel_header=ChannelHeader( channel_class=ChannelClass.NORMAL_RATE, channel_coding=ChannelCoding.PN9, channel_band=ChannelBand.BAND_433 ), channel_index=16 ) self.assertEqual(str(ch), "433NP016")
def test_byte_generation(self): expected = [0b00101000] channel_header = ChannelHeader(channel_coding=ChannelCoding.PN9, channel_class=ChannelClass.NORMAL_RATE, channel_band=ChannelBand.BAND_433) bytes = bytearray(channel_header) for i in xrange(len(bytes)): self.assertEqual(expected[i], bytes[i]) self.assertEqual(len(expected), len(bytes))
def __init__(self, last_rx_packet_level=0, last_rx_packet_link_budget=0, noise_floor=0, channel_header=ChannelHeader(channel_coding=ChannelCoding.FEC_PN9, channel_band=ChannelBand.BAND_868, channel_class=ChannelClass.LO_RATE), channel_index=0, scan_timeout_ratio=0, scan_count=0, scan_timeout_count=0): self.last_rx_packet_level=last_rx_packet_level self.last_rx_packet_link_budget=last_rx_packet_link_budget self.noise_floor=noise_floor self.channel_header=channel_header self.channel_index=channel_index self.scan_timeout_ratio=scan_timeout_ratio self.scan_count=scan_count self.scan_timeout_count=scan_timeout_count File.__init__(self, SystemFileIds.DLL_STATUS.value, 16) Validatable.__init__(self)
def test_parse_channel_id_string(self): s = "868LF048" expected_ch = ChannelID( channel_header=ChannelHeader( channel_class=ChannelClass.LO_RATE, channel_coding=ChannelCoding.FEC_PN9, channel_band=ChannelBand.BAND_868 ), channel_index=48 ) ch = ChannelID.from_string(s) self.assertEqual(ch.channel_header, expected_ch.channel_header) self.assertEqual(ch.channel_index, expected_ch.channel_index)
def __init__(self, mode=EngineeringModeMode.ENGINEERING_MODE_MODE_OFF, flags=0, timeout=0, channel_id=ChannelID(channel_header=ChannelHeader( ChannelCoding.PN9, ChannelClass.LO_RATE, ChannelBand.BAND_868), channel_index=0), eirp=0): self.mode = mode self.flags = flags self.timeout = timeout self.channel_id = channel_id self.eirp = eirp File.__init__(self, SystemFileIds.ENGINEERING_MODE, 9) Validatable.__init__(self)
def test_parsing(self): file_contents = [ 1, # Engineeringmode mode 0x01, # flags 0x02, # timeout 0x4a, 0x00, 0x09, # ChannelID 0x04, # eirp ] config = EngineeringModeFile.parse(ConstBitStream(bytes=file_contents)) self.assertEqual(config.mode, EngineeringModeMode.ENGINEERING_MODE_MODE_CONT_TX) self.assertEqual(config.flags, 1) self.assertEqual(config.timeout, 2) self.assertEqual(config.channel_id.channel_header.channel_coding, ChannelCoding.FEC_PN9) self.assertEqual(config.channel_id.channel_header, ChannelHeader(ChannelCoding.FEC_PN9, ChannelClass.NORMAL_RATE, ChannelBand.BAND_915)) self.assertEqual(config.channel_id.channel_index, 9) self.assertEqual(config.eirp, 4)
class TestStatus(unittest.TestCase): valid_channel_header = ChannelHeader( channel_class=ChannelClass.NORMAL_RATE, channel_coding=ChannelCoding.PN9, channel_band=ChannelBand.BAND_433 ) def test_byte_generation(self): expected = [ 40, # channel_header 16, 0, # channel_id 70, # rxlevel (- dBm) 80, # link budget 80, # target rx level 0, # status 100, # fifo token 0, # seq 20, # response timeout 16, # addressee ctrl (NOID) 0 # access class ] bytes = bytearray(Status( channel_header=self.valid_channel_header, channel_index=16, rx_level=70, link_budget=80, target_rx_level=80, nls=False, missed=False, retry=False, unicast=False, fifo_token=100, seq_nr=0, response_to=CT(0, 20), addressee=Addressee() )) self.assertEqual(len(bytes), 12) for i in xrange(10): self.assertEqual(expected[i], bytes[i]) bytes = bytearray(Status( channel_header=self.valid_channel_header, channel_index=16, rx_level=70, link_budget=80, target_rx_level=80, unicast=False, fifo_token=100, seq_nr=0, response_to=CT(0, 20), addressee=Addressee(), nls=True, missed=True, retry=True)) expected[6] = int('11100000', 2) # nls, missed, retry, ucast self.assertEqual(len(bytes), 12) for i in xrange(10): self.assertEqual(expected[i], bytes[i])
def test_simple_received_return_file_data_command(self): cmd = Command( generate_tag_request_action=False, actions=[ RegularAction(operation=ReturnFileData( operand=Data(data=list(bytearray("Hello world")), offset=Offset(id=0x51)))), StatusAction( status_operand_extension=StatusActionOperandExtensions. INTERFACE_STATUS, operation=InterfaceStatus(operand=InterfaceStatusOperand( interface_id=0xD7, interface_status=D7ASpStatus(channel_id=ChannelID( channel_header=ChannelHeader( channel_band=ChannelBand.BAND_433, channel_class=ChannelClass.LO_RATE, channel_coding=ChannelCoding.PN9), channel_index=16), rx_level=70, link_budget=80, target_rx_level=80, nls=False, missed=False, retry=False, unicast=False, fifo_token=200, seq_nr=0, response_to=CT(mant=20), addressee=Addressee())))) ]) expected = [ 0x62, # Interface Status action 0xD7, # D7ASP interface 32, # channel header 0, 16, # channel_id 70, # rxlevel (- dBm) 80, # link budget 80, # target rx level 0, # status 200, # fifo token 0, # seq 20, # response timeout 0x10, # addressee ctrl (NOID) 0, # access class 0x20, # action=32/ReturnFileData 0x51, # File ID 0x00, # offset 0x0b, # length 0x48, 0x65, 0x6c, 0x6c, 0x6f, # Hello 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64 # World ] bytes = bytearray(cmd) self.assertEqual(len(bytes), len(expected)) for i in xrange(len(expected)): self.assertEqual(bytes[i], expected[i])
def test_validation_ok(self): ch = ChannelHeader(channel_coding=ChannelCoding.PN9, channel_class=ChannelClass.NORMAL_RATE, channel_band=ChannelBand.BAND_433)
def bad(): ch = ChannelHeader(channel_coding=ChannelCoding.PN9, channel_class=ChannelClass.NORMAL_RATE, channel_band="wrong")
def bad(): ch = ChannelHeader(channel_coding=ChannelCoding.PN9, channel_class="wrong", channel_band=ChannelBand.BAND_433)
def bad(): ch = ChannelHeader(channel_coding="wrong", channel_class=ChannelClass.NORMAL_RATE, channel_band=ChannelBand.BAND_433)
class TestAccessProfile(unittest.TestCase): valid_channel_header = ChannelHeader( channel_class=ChannelClass.NORMAL_RATE, channel_coding=ChannelCoding.PN9, channel_band=ChannelBand.BAND_433) valid_sub_bands = [ SubBand(), SubBand(), SubBand(), SubBand(), SubBand(), SubBand(), SubBand(), SubBand() ] valid_sub_profiles = [ SubProfile(), SubProfile(), SubProfile(), SubProfile() ] def test_validation_ok(self): ap = AccessProfile(channel_header=self.valid_channel_header, sub_profiles=self.valid_sub_profiles, sub_bands=self.valid_sub_bands) def test_validation_sub_profiles(self): def bad(): ap = AccessProfile(channel_header=self.valid_channel_header, sub_profiles=[], sub_bands=self.valid_sub_bands) self.assertRaises(ValueError, bad) def test_validation_sub_profiles_count(self): def bad(): sub_profiles = [SubProfile() for _ in range(10)] # too many ... ap = AccessProfile(channel_header=self.valid_channel_header, sub_profiles=sub_profiles, sub_bands=self.valid_sub_bands) self.assertRaises(ValueError, bad) def test_validation_sub_bands_type(self): def bad(): ap = AccessProfile(channel_header=self.valid_channel_header, sub_profiles=self.valid_sub_profiles, sub_bands=[None]) self.assertRaises(ValueError, bad) def test_validation_sub_bands_count(self): def bad(): sub_bands = [SubBand() for _ in range(10)] # too many ... ap = AccessProfile(channel_header=self.valid_channel_header, sub_profiles=self.valid_sub_profiles, sub_bands=sub_bands) self.assertRaises(ValueError, bad) def test_byte_generation(self): expected = [ 0b00101000, # channel header ] for _ in xrange(AccessProfile.NUMBER_OF_SUB_PROFILES): expected.extend(list(bytearray(SubProfile()))) expected.extend(list(bytearray(SubBand()))) # only one sub_band ap = AccessProfile(channel_header=self.valid_channel_header, sub_bands=[SubBand()], sub_profiles=self.valid_sub_profiles) bytes = bytearray(ap) for i in xrange(len(bytes)): self.assertEqual(expected[i], bytes[i]) self.assertEqual(len(expected), len(bytes)) def test_parse(self): bytes = list(bytearray(self.valid_channel_header)) for _ in xrange(AccessProfile.NUMBER_OF_SUB_PROFILES): bytes.extend(list(bytearray(SubProfile()))) for _ in range(AccessProfile.MAX_NUMBER_OF_SUB_BANDS): bytes.extend(list(bytearray(SubBand()))) ap = AccessProfile.parse(ConstBitStream(bytes=bytes)) self.assertEqual(ap.channel_header.channel_band, self.valid_channel_header.channel_band) self.assertEqual(ap.channel_header.channel_coding, self.valid_channel_header.channel_coding) self.assertEqual(ap.channel_header.channel_class, self.valid_channel_header.channel_class) self.assertEqual(len(ap.sub_bands), AccessProfile.MAX_NUMBER_OF_SUB_BANDS) for sb in ap.sub_bands: self.assertEqual(sb.channel_index_start, SubBand().channel_index_start) self.assertEqual(sb.channel_index_end, SubBand().channel_index_end) self.assertEqual(sb.cca, SubBand().cca) self.assertEqual(sb.duty, SubBand().duty) self.assertEqual(sb.eirp, SubBand().eirp) for sp in ap.sub_profiles: self.assertEqual(sp.subband_bitmap, SubProfile().subband_bitmap) self.assertEqual(sp.scan_automation_period.exp, SubProfile().scan_automation_period.exp) self.assertEqual(sp.scan_automation_period.mant, SubProfile().scan_automation_period.mant) self.assertEqual(len(ap.sub_profiles), AccessProfile.NUMBER_OF_SUB_PROFILES)
argparser.add_argument("-c", "--channel-id", help="for example 868LP000 ; format FFFRCIII where FFF={433, 868, 915}, R={L, N, H, R (LORA)}, C={P (PN9), F (FEC), C (CW)} III=000...280", default="868LP000") argparser.add_argument("-e", "--eirp", help="EIRP in dBm", type=int, default=14) argparser.add_argument("-s", "--specifier", help="specifier for access profile. Default 0 is continuous scan, 1 is bg scan, 2+ is no scan", type=int, default=0) argparser.add_argument("-sp", "--scan_automation_period", help="period in ms of scanning (786 ~ total 1 sec), 0 is continuous scan ", type=int, default=0) argparser.add_argument("-sb", "--subband_bitmap", help="subband bitmap of subprofiles, 0 is default, 1 is scanning", type=int, default=0) config = argparser.parse_args() configure_default_logger(config.verbose) ch = ChannelID.from_string(config.channel_id) modem = Modem(config.device, config.rate, unsolicited_response_received_callback=received_command_callback) modem.connect() channel_header = ChannelHeader( channel_class=ch.channel_header.channel_class, channel_coding=ch.channel_header.channel_coding, channel_band=ch.channel_header.channel_band ) access_profile = AccessProfile( channel_header=channel_header, sub_profiles=[SubProfile(subband_bitmap=config.subband_bitmap, scan_automation_period=CT.compress(config.scan_automation_period))] * 4, sub_bands=[SubBand(eirp=config.eirp, channel_index_start=ch.channel_index, channel_index_end=ch.channel_index)] * 8 ) modem.execute_command( alp_command=Command.create_with_write_file_action_system_file( file=AccessProfileFile(access_profile=access_profile, access_specifier=config.specifier) ) )