class AccessProfile(Validatable): NUMBER_OF_SUB_PROFILES = 4 MAX_NUMBER_OF_SUB_BANDS = 8 # TODO update to D7AP v1.1 SCHEMA = [{ "channel_header": Types.OBJECT(ChannelHeader), "sub_profiles": Types.LIST(SubProfile, minlength=4, maxlength=4), "sub_bands": Types.LIST(SubBand, minlength=0, maxlength=8) }] def __init__(self, channel_header, sub_profiles, sub_bands): self.channel_header = channel_header self.sub_profiles = sub_profiles self.sub_bands = sub_bands super(AccessProfile, self).__init__() @staticmethod def parse(s): channel_header = ChannelHeader.parse(s) sub_profiles = [] for _ in range(AccessProfile.NUMBER_OF_SUB_PROFILES): sub_profiles.append(SubProfile.parse(s)) sub_bands = [] for _ in range(AccessProfile.MAX_NUMBER_OF_SUB_BANDS): sub_bands.append(SubBand.parse(s)) return AccessProfile(channel_header=channel_header, sub_bands=sub_bands, sub_profiles=sub_profiles) def __iter__(self): for byte in self.channel_header: yield byte for sp in self.sub_profiles: for byte in sp: yield byte for sb in self.sub_bands: for byte in sb: yield byte def __str__(self): subprofiles_string = "" for subprofile in self.sub_profiles: subprofiles_string = subprofiles_string + str(subprofile) subbands_string = "" for subband in self.sub_bands: subbands_string = subbands_string + str(subband) return "channel_header={}, sub_profiles={}, sub_bands={}".format( self.channel_header, subprofiles_string, subbands_string)
class PhyStatusFile(File, Validatable): SCHEMA = [{ "up_time": Types.INTEGER(min=0, max=0xFFFFFFFF), "rx_time": Types.INTEGER(min=0, max=0xFFFFFFFF), "tx_time": Types.INTEGER(min=0, max=0xFFFFFFFF), "tx_duty_cycle": Types.INTEGER(min=0, max=1000), "channel_status_list_length": Types.INTEGER(min=0, max=0xFF), "channel_status_identifier": Types.LIST(ChannelStatusIdentifier, minlength=0, maxlength=0xFF), "channel_noise_floor": Types.LIST(minlength=0, maxlength=0xFF) }] def __init__(self, up_time=0, rx_time=0, tx_time=0, tx_duty_cycle=0, channel_status_list_length=0, channel_status_identifier=[], channel_noise_floor=[]): self.up_time = up_time self.rx_time = rx_time self.tx_time = tx_time self.tx_duty_cycle = tx_duty_cycle self.channel_status_list_length = channel_status_list_length self.channel_status_identifier = channel_status_identifier if len(channel_status_identifier) != channel_status_list_length: self.channel_status_identifier.extend( [ChannelStatusIdentifier()] * (channel_status_list_length - len(channel_status_identifier))) self.channel_noise_floor = channel_noise_floor if len(channel_noise_floor) != channel_status_list_length: self.channel_noise_floor.extend( [0] * (channel_status_list_length - len(channel_noise_floor))) File.__init__(self, SystemFileIds.PHY_STATUS.value, 15 + (3 * 10)) # allocate enough space for 20 channels Validatable.__init__(self) @staticmethod def parse(s): up_time = s.read("uint:32") rx_time = s.read("uint:32") tx_time = s.read("uint:32") tx_duty_cycle = s.read("uint:16") channel_status_list_length = s.read("uint:8") channel_status_identifier = [] channel_noise_floor = [] for counter in range(channel_status_list_length): channel_status_identifier.append( ChannelStatusIdentifier().parse(s)) channel_noise_floor.append(s.read("uint:8")) return PhyStatusFile( up_time=up_time, rx_time=rx_time, tx_time=tx_time, tx_duty_cycle=tx_duty_cycle, channel_status_list_length=channel_status_list_length, channel_status_identifier=channel_status_identifier, channel_noise_floor=channel_noise_floor) def __iter__(self): for byte in bytearray(struct.pack(">I", self.up_time)): yield byte for byte in bytearray(struct.pack(">I", self.rx_time)): yield byte for byte in bytearray(struct.pack(">I", self.tx_time)): yield byte for byte in bytearray(struct.pack(">H", self.tx_duty_cycle)): yield byte yield self.channel_status_list_length for counter in range(self.channel_status_list_length): for byte in self.channel_status_identifier[counter]: yield byte yield self.channel_noise_floor[counter] def __str__(self): channel_status = "" for counter in range(self.channel_status_list_length): channel_status = channel_status + "identifier={}, noise_floor={}; ".format( str(self.channel_status_identifier[counter]), self.channel_noise_floor[counter]) channel_status = "[{}]".format(channel_status[:-2]) return "up_time={}, rx_time={}, tx_time={}, tx_duty_cycle={}, channel_status_list_length={}, list={}".format( self.up_time, self.rx_time, self.tx_time, self.tx_duty_cycle, self.channel_status_list_length, channel_status)
class Command(Validatable): SCHEMA = [{ "actions": Types.LIST(Action), "interface_status": Types.OBJECT( StatusAction, nullable=True) # can be null for example when parsing DLL frames }] def __init__(self, actions=[], generate_tag_request_action=True, tag_id=None, send_tag_response_when_completed=True): self.actions = [] self.interface_status = None self.generate_tag_request_action = generate_tag_request_action self.tag_id = tag_id self.send_tag_response_when_completed = send_tag_response_when_completed self.execution_completed = False for action in actions: if type( action ) == StatusAction and action.status_operand_extension == StatusActionOperandExtensions.INTERFACE_STATUS: if self.interface_status != None: raise ParseError( "An ALP command can contain one and only one Interface Status action" ) self.interface_status = action elif type(action) == TagRequestAction: if self.tag_id != None: raise ParseError( "An ALP command can contain one and only one Tag Request Action" ) self.tag_id = action.operand.tag_id self.send_tag_response_when_completed = action.respond_when_completed # we don't add this to self.actions but prepend it on serializing elif type(action) == TagResponseAction: if self.tag_id != None: raise ParseError( "An ALP command can contain one and only one Tag Response Action" ) self.tag_id = action.operand.tag_id self.completed_with_error = action.error # TODO distinguish between commands and responses? self.execution_completed = action.eop else: self.actions.append(action) if self.generate_tag_request_action and self.tag_id == None: self.tag_id = random.randint(0, 255) super(Command, self).__init__() def add_action(self, action): self.actions.append(action) def add_forward_action(self, interface_type=InterfaceType.HOST, interface_configuration=None): if interface_configuration is not None and interface_type == InterfaceType.HOST: raise ValueError( "interface_configuration is not supported for interface_type HOST" ) if interface_type == InterfaceType.D7ASP: if interface_configuration is None: interface_configuration = Configuration() self.actions.append( RegularAction(operation=Forward(operand=InterfaceConfiguration( interface_id=InterfaceType.D7ASP, interface_configuration=interface_configuration)))) @staticmethod def create_with_read_file_action_system_file( file, interface_type=InterfaceType.HOST, interface_configuration=None): # default to host interface, when D7ASP interface is used prepend with Forward action cmd = Command() cmd.add_forward_action(interface_type, interface_configuration) cmd.add_action( RegularAction(operation=ReadFileData(operand=DataRequest( offset=Offset(id=file.id, offset=0), # TODO offset size length=file.length)))) return cmd @staticmethod def create_with_read_file_action(file_id, length, offset=0, interface_type=InterfaceType.HOST, interface_configuration=None): # default to host interface, when D7ASP interface is used prepend with Forward action cmd = Command() cmd.add_forward_action(interface_type, interface_configuration) cmd.add_action( RegularAction(operation=ReadFileData(operand=DataRequest( offset=Offset(id=file_id, offset=offset), # TODO offset size length=length)))) return cmd @staticmethod def create_with_write_file_action(file_id, data, offset=0, interface_type=InterfaceType.HOST, interface_configuration=None): # default to host interface, when D7ASP interface is used prepend with Forward action cmd = Command() cmd.add_forward_action(interface_type, interface_configuration) cmd.add_action( RegularAction(operation=WriteFileData(operand=Data( offset=Offset(id=file_id, offset=offset), # TODO offset size data=data)))) return cmd @staticmethod def create_with_write_file_action_system_file( file, interface_type=InterfaceType.HOST, interface_configuration=None): # default to host interface, when D7ASP interface is used prepend with Forward action cmd = Command() cmd.add_forward_action(interface_type, interface_configuration) cmd.add_action( RegularAction(operation=WriteFileData(operand=Data( offset=Offset(id=file.id, offset=0), # TODO offset size data=list(file))))) return cmd @staticmethod def create_with_return_file_data_action(file_id, data, interface_type=InterfaceType.HOST, interface_configuration=None): # default to host interface, when D7ASP interface is used prepend with Forward action cmd = Command() cmd.add_forward_action(interface_type, interface_configuration) cmd.add_action( RegularAction(operation=ReturnFileData( operand=Data(data=data, offset=Offset(id=file_id))))) return cmd def __iter__(self): if self.generate_tag_request_action: tag_request_action = TagRequestAction( respond_when_completed=self.send_tag_response_when_completed, operation=TagRequest(operand=TagId(tag_id=self.tag_id))) for byte in tag_request_action: yield byte if self.interface_status is not None: for byte in self.interface_status: yield byte for action in self.actions: for byte in action: yield byte def describe_actions(self): description = "" for action in self.actions: description = description + "{}, ".format(action) return description.strip(", ") def get_d7asp_interface_status(self): if self.interface_status is None or self.interface_status.operand.interface_id != 0xD7: return None return self.interface_status.operation.operand.interface_status def __str__(self): output = "Command with tag {} ".format(self.tag_id) if (self.execution_completed): status = "completed" if (self.completed_with_error): status += ", with error" else: status += ", without error" else: status = "executing" output += "({})".format(status) if (len(self.actions) > 0): output += "\n\tactions:\n" for action in self.actions: output += "\t\taction: {}\n".format(action) if self.interface_status is not None: output += "\tinterface status: {}\n".format(self.interface_status) return output