class FileHeader(Validatable): SCHEMA = [{ "permissions": Types.OBJECT(FilePermissions), "properties": Types.OBJECT(FileProperties), "alp_command_file_id": Types.BYTE(), "interface_file_id": Types.BYTE(), "file_size": Types.INTEGER(min=0, max=0xFFFFFFFF), "allocated_size": Types.INTEGER(min=0, max=0xFFFFFFFF) }] def __init__(self, permissions, properties, alp_command_file_id, interface_file_id, file_size, allocated_size): self.permissions = permissions self.properties = properties self.alp_command_file_id = alp_command_file_id self.interface_file_id = interface_file_id self.file_size = file_size self.allocated_size = allocated_size Validatable.__init__(self) @staticmethod def parse(s): permissions = FilePermissions.parse(s) properties = FileProperties.parse(s) alp_command_file_id = s.read("uint:8") interface_file_id = s.read("uint:8") file_size = s.read("uint:32") allocated_size = s.read("uint:32") return FileHeader(permissions, properties, alp_command_file_id, interface_file_id, file_size, allocated_size) def __iter__(self): for byte in self.permissions: yield byte for byte in self.properties: yield byte yield self.alp_command_file_id yield self.interface_file_id for byte in bytearray(struct.pack(">I", self.file_size)): yield byte for byte in bytearray(struct.pack(">I", self.allocated_size)): yield byte def __eq__(self, other): if isinstance(other, FileHeader): return self.__dict__ == other.__dict__ return False def __ne__(self, other): return not self.__eq__(other) def __str__(self): return "permissions={}, properties=({}), alp_command_file_id={}, interface_file_id={}, file_size={}, allocated_size={}".format( self.permissions, self.properties, self.alp_command_file_id, self.interface_file_id, self.file_size, self.allocated_size)
class Offset(Validatable): SCHEMA = [{ "id": Types.BYTE(), "size": Types.INTEGER([1]), "offset": Types.INTEGER(min=0, max=0xFF) }, { "id": Types.BYTE(), "size": Types.INTEGER([2]), "offset": Types.INTEGER(min=0, max=0xFFFF) }, { "id": Types.BYTE(), "size": Types.INTEGER([3]), "offset": Types.INTEGER(min=0, max=0xFFFFFF) }, { "id": Types.BYTE(), "size": Types.INTEGER([4]), "offset": Types.INTEGER(min=0, max=0xFFFFFFFF) }] def __init__(self, id=0, size=1, offset=0): self.id = id self.size = size self.offset = offset super(Offset, self).__init__() def __iter__(self): yield chr(self.id) byte = 0 byte += (self.size - 1) << 6 if self.size == 1: byte += self.offset yield byte else: offset = bytearray(struct.pack(">I", self.offset)) if self.size == 2: offset = offset[2:] elif self.size == 3: offset = offset[1:] byte += offset[0] yield byte for byte in offset[1:]: yield byte def __str__(self): return "file-id={}, size={}, offset={}".format(self.id, self.size, self.offset)
class FileHeaderOperand(Validatable): SCHEMA = [{ "file_id": Types.BYTE(), "file_header": Types.OBJECT(FileHeader) }] def __init__(self, file_id, file_header): self.file_id = file_id self.file_header = file_header super(FileHeaderOperand, self).__init__() def __iter__(self): yield self.file_id for byte in self.file_header: yield byte @staticmethod def parse(s): file_id = s.read("uint:8") file_header = FileHeader.parse(s) return FileHeaderOperand(file_id=file_id, file_header=file_header) def __str__(self): return "file-id={}, header={}".format(self.file_id, self.file_header)
class Data(Validatable): SCHEMA = [{ "offset": Types.OBJECT(Offset), "length": Types.BYTE(), "data": Types.BYTES() }] def __init__(self, data=[], offset=Offset()): self.offset = offset self.data = data super(Data, self).__init__() # for consistency with schema, e.g. if using generic attribute conversion, etc @property def length(self): return len(self.data) # the Python way ;-) def __len__(self): return self.length def __iter__(self): for byte in self.offset: yield byte yield chr(self.length) for byte in self.data: yield chr(byte) def __str__(self): return "{}, length={}, data={}".format(self.offset, self.length, self.data)
class Offset(Validatable): SCHEMA = [ { "id" : Types.BYTE(), "offset": Types.OBJECT(Length) } ] def __init__(self, id=0, offset=Length()): self.id = id self.offset = offset super(Offset, self).__init__() @staticmethod def parse(s): id = s.read("uint:8") offset = Length.parse(s) return Offset(id=id, offset=offset) def __iter__(self): yield self.id for byte in self.offset: yield byte def __str__(self): return "file-id={}, offset={}".format(self.id, self.offset)
class SubProfile(Validatable): SCHEMA = [{ "subband_bitmap": Types.BYTE(), "scan_automation_period": Types.OBJECT(CT) }] def __init__(self, subband_bitmap=0, scan_automation_period=CT()): self.subband_bitmap = subband_bitmap self.scan_automation_period = scan_automation_period super(SubProfile, self).__init__() @staticmethod def parse(s): subband_bitmap = s.read("uint:8") scan_automation_period = CT.parse(s) return SubProfile(subband_bitmap=subband_bitmap, scan_automation_period=scan_automation_period) def __iter__(self): yield self.subband_bitmap for byte in self.scan_automation_period: yield byte def __str__(self): return pprint.PrettyPrinter().pformat(self.as_dict())
class Frame(Validatable): SCHEMA = [{ "length": Types.BYTE(), "subnet": Types.BYTE(), "control": Types.OBJECT(Control), "target_address": Types.BYTES(), # TODO max size? "d7anp_frame": Types.OBJECT(D7anpFrame), # TODO assuming foreground frames for now "crc16": Types.BITS( 16 ) # TODO does not work, look into this later {'validator': validate_crc } }] def __init__(self, length, subnet, control, target_address, d7anp_frame, crc16): self.length = length self.subnet = subnet self.control = control self.target_address = target_address self.d7anp_frame = d7anp_frame self.crc16 = crc16 # TODO validate CRC super(Frame, self).__init__() # def validate_crc(self, value, error): # raw_data = [] # raw_data.append(self.length) # raw_data.append(self.subnet) # raw_data.append(self.control) # raw_data.append(self.target_address) # raw_data.append(self.payload) # crc = CRCCCITT().calculate(raw_data) def __iter__(self): yield self.length yield self.subnet for byte in self.control: yield byte for byte in self.target_address: yield byte for byte in self.d7anp_frame: yield byte yield self.crc16
class FileIdOperand(Validatable): SCHEMA = [{"file_id": Types.BYTE()}] def __init__(self, file_id): self.file_id = file_id super(FileIdOperand, self).__init__() def __iter__(self): yield self.file_id def __str__(self): return "file-id={}".format(self.file_id)
class BackgroundFrame(Validatable): SCHEMA = [{ "subnet": Types.BYTE(), "control": Types.OBJECT(BackgroundFrameControl), "payload": Types.BITS(16), "crc16": Types.BITS( 16 ) # TODO does not work, look into this later {'validator': validate_crc } }] def __init__(self, subnet, control, payload, crc16): self.subnet = subnet self.control = control self.payload = payload self.crc16 = crc16 # TODO validate CRC super(BackgroundFrame, self).__init__() # def validate_crc(self, value, error): # raw_data = [] # raw_data.append(self.length) # raw_data.append(self.subnet) # raw_data.append(self.control) # raw_data.append(self.target_address) # raw_data.append(self.payload) # crc = CRCCCITT().calculate(raw_data) @staticmethod def parse(s): subnet = s.read("int:8") control = BackgroundFrameControl.parse(s) payload = s.read("uint:16") crc = s.read("uint:16") return BackgroundFrame(subnet=subnet, control=control, payload=payload, crc16=crc) def __iter__(self): yield self.subnet for byte in self.control: yield byte for byte in self.payload: yield byte yield self.crc16 def __str__(self): return pprint.PrettyPrinter().pformat(self.as_dict())
class TagId(Validatable): SCHEMA = [{ "tag_id": Types.BYTE(), }] def __init__(self, tag_id): self.tag_id = tag_id super(TagId, self).__init__() def __iter__(self): yield self.tag_id def __str__(self): return "tag_id={}".format(self.tag_id)
class Frame(Validatable): SCHEMA = [{ "control": Types.OBJECT(Control), "origin_access_class": Types.BYTE(), "origin_access_id": Types.BYTES(), # TODO refactor to use OriginAddressee (subclass of addressee containing control and access_id) "d7atp_frame": Types.OBJECT(D7atpFrame) }] def __init__(self, control, origin_access_class, origin_access_id, d7atp_frame): self.control = control self.origin_access_class = origin_access_class self.origin_access_id = origin_access_id self.d7atp_frame = d7atp_frame # TODO super(Frame, self).__init__() @staticmethod def parse(bitstream, payload_length): control = Control.parse(bitstream) payload_length -= 1 # substract control origin_access_class = bitstream.read("uint:8") payload_length -= 1 assert control.has_hopping == False, "Not implemented yet" assert control.nls_method == NlsMethod.NONE, "Not implemented yet" if not control.has_no_origin_access_id: if control.origin_id_type == IdType.VID: origin_access_id = map(ord, bitstream.read("bytes:2")) payload_length = payload_length - 2 elif control.origin_id_type == IdType.UID: origin_access_id = map(ord, bitstream.read("bytes:8")) payload_length = payload_length - 8 else: assert False else: origin_access_id = [] #payload=map(ord,bitstream.read("bytes:" + str(payload_length))) d7atp_frame = D7atpFrame.parse(bitstream, payload_length) return Frame(control=control, origin_access_class=origin_access_class, origin_access_id=origin_access_id, d7atp_frame=d7atp_frame) def __iter__(self): for byte in self.control: yield byte yield self.origin_access_class for byte in self.origin_access_id: yield byte for byte in self.d7atp_frame: yield byte
class DataRequest(Validatable): SCHEMA = [{"offset": Types.OBJECT(Offset), "length": Types.BYTE()}] def __init__(self, length, offset=Offset()): self.offset = offset self.length = length super(DataRequest, self).__init__() def __iter__(self): for byte in self.offset: yield byte yield chr(self.length) def __str__(self): return "{}, length={}".format(self.offset, self.length)
class FileHeaderOperand(Validatable): SCHEMA = [{ "file_id": Types.BYTE(), "file_header": Types.OBJECT(FileHeader) }] def __init__(self, file_id, file_header): self.file_id = file_id self.file_header = file_header super(FileHeaderOperand, self).__init__() def __iter__(self): yield self.file_id for byte in self.file_header: yield byte def __str__(self): return "file-id={}, header={}".format(self.file_id, self.file_header)
class InterfaceStatusOperand(Validatable): SCHEMA = [{ "interface_id": Types.BYTE(), "interface_status": Types.OBJECT(Status, nullable=True) }] def __init__(self, interface_id, interface_status): self.interface_id = interface_id self.interface_status = interface_status super(InterfaceStatusOperand, self).__init__() def __iter__(self): yield self.interface_id for byte in self.interface_status: yield byte def __str__(self): return "interface-id={}, status={}".format(self.interface_id, self.interface_status)
class InterfaceConfiguration(Validatable): SCHEMA = [{ "interface_id": Types.BYTE(), "interface_configuration": Types.OBJECT(Configuration) }] def __init__(self, interface_id, interface_configuration): self.interface_id = interface_id self.interface_configuration = interface_configuration super(InterfaceConfiguration, self).__init__() def __iter__(self): yield self.interface_id for byte in self.interface_configuration: yield byte def __str__(self): return "interface-id={}, status={}".format( self.interface_id, self.interface_configuration)
class Status(Validatable): SCHEMA = [{ "channel_header": Types.OBJECT(ChannelHeader), "channel_index": Types.INTEGER(), "rx_level": Types.BYTE(), "link_budget": Types.BYTE(), "target_rx_level": Types.BYTE(), "nls": Types.BOOLEAN(), "missed": Types.BOOLEAN(), "retry": Types.BOOLEAN(), "ucast": Types.BOOLEAN(), "fifo_token": Types.BYTE(), "seq_nr": Types.BYTE(), "response_to": Types.OBJECT(CT), "addressee": Types.OBJECT(Addressee) }] def __init__(self, channel_header, channel_index, rx_level, link_budget, target_rx_level, nls, missed, retry, unicast, fifo_token, seq_nr, response_to, addressee): self.channel_header = channel_header self.channel_index = channel_index self.rx_level = rx_level self.link_budget = link_budget self.target_rx_level = target_rx_level self.nls = nls self.missed = missed self.retry = retry self.unicast = unicast self.fifo_token = fifo_token self.seq_nr = seq_nr self.response_to = response_to self.addressee = addressee super(Status, self).__init__() @staticmethod def parse(s): channel_header = ChannelHeader.parse(s) channel_index = s.read("uint:16") rx_level = s.read("int:8") link_budget = s.read("uint:8") target_rx_level = s.read("uint:8") nls = s.read("bool") missed = s.read("bool") retry = s.read("bool") unicast = s.read("bool") _ = s.read("pad:4") fifo_token = s.read("uint:8") seq_nr = s.read("uint:8") response_to = CT.parse(s) addressee = Addressee.parse(s) return Status(channel_header=channel_header, channel_index=channel_index, rx_level=rx_level, link_budget=link_budget, target_rx_level=target_rx_level, nls=nls, missed=missed, retry=retry, unicast=unicast, fifo_token=fifo_token, seq_nr=seq_nr, response_to=response_to, addressee=addressee) def __iter__(self): for byte in self.channel_header: yield byte for byte in bytearray(struct.pack("<h", self.channel_index)): yield byte yield self.rx_level yield self.link_budget yield self.target_rx_level byte = 0 if self.nls: byte |= 1 << 7 if self.missed: byte |= 1 << 6 if self.retry: byte |= 1 << 5 if self.unicast: byte |= 1 << 4 yield byte yield chr(self.fifo_token) yield chr(self.seq_nr) for byte in self.response_to: yield byte for byte in self.addressee: yield byte def __str__(self): return "unicast={}, nls={}, retry={}, missed={}, fifo_token={}, rx_level={}, seq_nr={}, target_rx_level={}, " \ "addressee={}, response_to={}, link_budget={}, channel_header={}, channel_index={}".format( self.unicast, self.nls, self.retry, self.missed, self.fifo_token, self.rx_level, self.seq_nr, self.target_rx_level, self.addressee, self.response_to, self.link_budget, self.channel_header, self.channel_index )
class Frame(Validatable): SCHEMA = [{ "length": Types.BYTE(), "subnet": Types.BYTE(), "control": Types.OBJECT(Control), "target_address": Types.BYTES(), # TODO max size? "d7anp_frame": Types.OBJECT(D7anpFrame), # TODO assuming foreground frames for now "crc16": Types.BITS( 16 ) # TODO does not work, look into this later {'validator': validate_crc } }] def __init__(self, length, subnet, control, target_address, d7anp_frame, crc16): self.length = length self.subnet = subnet self.control = control self.target_address = target_address self.d7anp_frame = d7anp_frame self.crc16 = crc16 # TODO validate CRC super(Frame, self).__init__() # def validate_crc(self, value, error): # raw_data = [] # raw_data.append(self.length) # raw_data.append(self.subnet) # raw_data.append(self.control) # raw_data.append(self.target_address) # raw_data.append(self.payload) # crc = CRCCCITT().calculate(raw_data) @staticmethod def parse(s): length = s.read("int:8") subnet = s.read("int:8") control = Control.parse(s) payload_length = length - 4 # substract subnet, control, crc if control.id_type == IdType.VID: target_address = map(ord, s.read("bytes:2")) payload_length = payload_length - 2 elif control.id_type == IdType.UID: target_address = map(ord, s.read("bytes:8")) payload_length = payload_length - 8 else: target_address = [] return Frame(length=length, subnet=subnet, control=control, target_address=target_address, d7anp_frame=D7anpFrame.parse(s, payload_length), crc16=s.read("uint:16")) def __iter__(self): yield self.length yield self.subnet for byte in self.control: yield byte for byte in self.target_address: yield byte for byte in self.d7anp_frame: yield byte yield self.crc16
class Addressee(Validatable): # addressee ID length ID_LENGTH_NBID = 1 ID_LENGTH_NOID = 0 ID_LENGTH_VID = 2 ID_LENGTH_UID = 8 SCHEMA = [ { # void identifier with reached devices estimation "id_type": Types.ENUM(IdType, allowedvalues=[IdType.NBID]), "nls_method": Types.ENUM(NlsMethod), "access_class": Types.BYTE(), "id": Types.OBJECT(CT) }, { # void identifier without reached devices estimation "id_type": Types.ENUM(IdType, allowedvalues=[IdType.NOID]), "nls_method": Types.ENUM(NlsMethod), "access_class": Types.BYTE(), "id": Types.INTEGER([None]) }, { # virtual "id_type": Types.ENUM(IdType, allowedvalues=[IdType.VID]), "nls_method": Types.ENUM(NlsMethod), "access_class": Types.BYTE(), "id": Types.INTEGER(min=0, max=0xFFFF) }, { # unicast "id_type": Types.ENUM(IdType, allowedvalues=[IdType.UID]), "nls_method": Types.ENUM(NlsMethod), "access_class": Types.BYTE(), "id": Types.INTEGER(min=0, max=0xFFFFFFFFFFFFFFFF) } ] # SCHEMA = [ # { # "id_type" : Types.INTEGER(IdType.ALL), # "cl" : Types.BITS(4), # "id_length" : Types.INTEGER([0, 2, 8]), # "id" : Types.INTEGER(min=0, max=0xFFFFFFFFFFFFFFFF) # } # ] def __init__(self, access_class=0, id_type=IdType.NOID, id=None, nls_method=NlsMethod.NONE): self.id_type = id_type self.access_class = access_class self.id = id self.nls_method = nls_method super(Addressee, self).__init__() @property def id_length(self): return Addressee.length_for(id_type=self.id_type) @classmethod def length_for(self, id_type): if id_type == IdType.NBID: return Addressee.ID_LENGTH_NBID if id_type == IdType.NOID: return Addressee.ID_LENGTH_NOID if id_type == IdType.VID: return Addressee.ID_LENGTH_VID if id_type == IdType.UID: return Addressee.ID_LENGTH_UID @staticmethod def parse(s): _ = s.read("pad:2") id_type = IdType(s.read("uint:2")) nls_method = NlsMethod(s.read("uint:4")) cl = s.read("uint:8") l = Addressee.length_for(id_type) id = s.read("uint:" + str(l * 8)) if l > 0 else None if id_type == IdType.NBID: id = CT(id) return Addressee(id_type=id_type, access_class=cl, id=id, nls_method=nls_method) def __iter__(self): byte = 0 # pad 2 << 7 << 6 byte |= self.id_type.value << 4 byte += self.nls_method.value yield byte yield self.access_class if self.id_length > 0: id_value = self.id if self.id_type == IdType.NBID: # self.id is a CT id_value = self.id.compressed_value() id = bytearray(struct.pack(">Q", id_value))[8 - self.id_length:] for byte in id: yield byte def __str__(self): return "ac={}, id_type={}, id={}".format(self.access_class, self.id_type, self.id)
class Status(Validatable): SCHEMA = [{ "channel_header": Types.BYTE(), # TODO parse "channel_index": Types.INTEGER(), "rx_level": Types.BYTE(), "link_budget": Types.BYTE(), "target_rx_level": Types.BYTE(), "nls": Types.BOOLEAN(), "missed": Types.BOOLEAN(), "retry": Types.BOOLEAN(), "ucast": Types.BOOLEAN(), "fifo_token": Types.BYTE(), "seq_nr": Types.BYTE(), "response_to": Types.OBJECT(CT), "addressee": Types.OBJECT(Addressee) }] def __init__(self, channel_header, channel_index, rx_level, link_budget, target_rx_level, nls, missed, retry, unicast, fifo_token, seq_nr, response_to, addressee): self.channel_header = channel_header self.channel_index = channel_index self.rx_level = rx_level self.link_budget = link_budget self.target_rx_level = target_rx_level self.nls = nls self.missed = missed self.retry = retry self.unicast = unicast self.fifo_token = fifo_token self.seq_nr = seq_nr self.response_to = response_to self.addressee = addressee super(Status, self).__init__() def __iter__(self): yield self.channel_header for byte in bytearray(struct.pack("<h", self.channel_index)): yield byte yield self.rx_level yield self.link_budget yield self.target_rx_level byte = 0 if self.nls: byte |= 1 << 7 if self.missed: byte |= 1 << 6 if self.retry: byte |= 1 << 5 if self.unicast: byte |= 1 << 4 yield byte yield chr(self.fifo_token) yield chr(self.seq_nr) for byte in self.response_to: yield byte for byte in self.addressee: yield byte def __str__(self): return "unicast={}, nls={}, retry={}, missed={}, fifo_token={}, rx_level={}, " \ "seq_nr={}, target_rx_level={}, addressee={}, response_to={}, link_budget={}, channel_header={}".format( self.unicast, self.nls, self.retry, self.missed, self.fifo_token, self.rx_level, self.seq_nr, self.target_rx_level, self.addressee, self.response_to, self.link_budget, self.channel_header )