def send_command(self, command, args): command_template = self.dictionaries.command_id[command] cmd_data = CmdData(tuple(args), command_template) self.histories.commands.data_callback(cmd_data) for hist in self.coders.command_subscribers: hist.data_callback(cmd_data) ev_temp = self.dictionaries.event_name["CommandReceived"] event = EventData((U32Type(cmd_data.get_id()), ), self.t0 + time.time(), ev_temp) self.enqueue_event(event) ev_temp = self.dictionaries.event_name["HistorySizeUpdate"] evr_size = U32Type(len(self.histories.events.retrieve())) cmd_size = U32Type(len(self.histories.commands.retrieve())) ch_size = U32Type(len(self.histories.channels.retrieve())) event = EventData((evr_size, cmd_size, ch_size), self.t0 + time.time(), ev_temp) self.enqueue_event(event) self.command_count += 1 ch_temp = self.dictionaries.channel_name["CommandCounter"] update = ChData(U32Type(self.command_count), self.t0 + time.time(), ch_temp) self.enqueue_telemetry(update)
def encode_api(self, data): """ Encodes the given CmdData object as binary data and returns the result. Args: data: CmdData object to encode Returns: Encoded version of the data argument as binary data """ assert isinstance(data, CmdData), "Encoder handling incorrect type" cmd_temp = data.get_template() desc = U32Type(0x5A5A5A5A).serialize() descriptor = U32Type( DataDescType["FW_PACKET_COMMAND"].value).serialize() op_code = U32Type(cmd_temp.get_op_code()).serialize() arg_data = b"" for arg in data.get_args(): arg_data += arg.serialize() length_val = len(descriptor) + len(op_code) + len(arg_data) self.len_obj.val = length_val length = self.len_obj.serialize() binary_data = desc + length + descriptor + op_code + arg_data return binary_data
def encode_api(self, data): """ Encodes specific file packets. This will allow the data to be sent out. :param data: FilePacket type to send. :return: encoded bytes data """ out_data = struct.pack(">BI", int(data.packetType.value), data.seqID) # Packet Type determines the variables following the seqID if data.packetType == FilePacketType.START: file_src_enc = data.sourcePath.encode(DATA_ENCODING) file_dst_enc = data.destPath.encode(DATA_ENCODING) out_data += struct.pack(">IB", data.size, len(file_src_enc)) out_data += file_src_enc out_data += struct.pack(">B", len(file_dst_enc)) out_data += file_dst_enc elif data.packetType == FilePacketType.DATA: out_data += struct.pack(">IH", data.offset, data.length) out_data += data.dataVar elif data.packetType == FilePacketType.END: out_data += struct.pack(">I", data.hashValue) elif data.packetType != FilePacketType.CANCEL: raise Exception( "Invalid packet type found while encoding: {}".format(data.packetType) ) descriptor = U32Type(DataDescType["FW_PACKET_FILE"].value).serialize() length_obj = self.config.get_type("msg_len") length_obj.val = len(descriptor) + len(out_data) header = U32Type(0x5A5A5A5A).serialize() + length_obj.serialize() + descriptor return header + out_data
def __command(cmd_obj): command = U32Type(0).serialize( ) # serialize combuffer type enum: FW_PACKET_COMMAND command += U32Type( cmd_obj.getOpCode()).serialize() # serialize opcode # Command arguments for arg in cmd_obj.getArgs(): command += arg[2].serialize() return command
def __time_tag(cmd_obj): """ TODO: support a timebase in the cmd obj? This is mission specific, so it is tough to handle. For now I am hardcoding this to 2 which is TB_NONE """ # return TimeType(timeBase=2, seconds=cmd_obj.getSeconds(), useconds=cmd_obj.getUseconds()).serialize() # TKC - new command time format return (U32Type(cmd_obj.getSeconds()).serialize() + U32Type(cmd_obj.getUseconds()).serialize())
def test_pkt_encoder(): """ Tests the encoding of the packet encoder """ config = ConfigManager() config.set("types", "msg_len", "U16") enc = PktEncoder() enc_config = PktEncoder(config) ch_temp_1 = ChTemplate(101, "test_ch", "test_comp", U32Type()) ch_temp_2 = ChTemplate(102, "test_ch2", "test_comp2", U8Type()) ch_temp_3 = ChTemplate(103, "test_ch3", "test_comp3", U16Type()) pkt_temp = PktTemplate(64, "test_pkt", [ch_temp_1, ch_temp_2, ch_temp_3]) time_obj = TimeType(2, 0, 1533758629, 123456) ch_obj_1 = ChData(U32Type(1356), time_obj, ch_temp_1) ch_obj_2 = ChData(U8Type(143), time_obj, ch_temp_2) ch_obj_3 = ChData(U16Type(1509), time_obj, ch_temp_3) pkt_obj = PktData([ch_obj_1, ch_obj_2, ch_obj_3], time_obj, pkt_temp) desc_bin = b"\x00\x00\x00\x04" id_bin = b"\x00\x40" time_bin = b"\x00\x02\x00\x5b\x6b\x4c\xa5\x00\x01\xe2\x40" ch_bin = b"\x00\x00\x05\x4c\x8F\x05\xe5" long_len_bin = b"\x00\x00\x00\x18" short_len_bin = b"\x00\x18" reg_expected = long_len_bin + desc_bin + id_bin + time_bin + ch_bin config_expected = short_len_bin + desc_bin + id_bin + time_bin + ch_bin reg_output = enc.encode_api(pkt_obj) assert (reg_output == reg_expected ), "FAIL: expected regular output to be %s, but found %s" % ( list(reg_expected), list(reg_output), ) config_output = enc_config.encode_api(pkt_obj) assert (config_output == config_expected ), "FAIL: expected configured output to be %s, but found %s" % ( list(config_expected), list(config_output), )
def serialize(self): """ Serializes command arguments """ ## first, serialize opcode opcode = U32Type(self.__opcode) ser_data = opcode.serialize() ## then, serialize arguments for (arg_name, arg_desc, arg_type) in self.__arguments: ser_data += arg_type.serialize() return ser_data
def get_handshake(packet: bytes) -> bytes: """Gets a handshake raw frame from the last packet Creates a handshake raw-frame by repeating the contents of the last packet with a handshake descriptor at the front. Args: packet: packet to repeat back out as handshake Returns: handshake packet """ return U32Type( DataDescType["FW_PACKET_HAND"].value).serialize() + packet
def write(self, seq_cmds_list): """ Write out each command record """ num_records = len(seq_cmds_list) sequence = b"" for cmd in seq_cmds_list: sequence += self.__binaryCmdRecord(cmd) size = len(sequence) if self.__timebase == 0xFFFF: tb_txt = b"ANY" else: tb_txt = bytes(self.__timebase) print("Sequence is %d bytes with timebase %s" % (size, tb_txt)) header = b"" header += U32Type( size + 4).serialize() # Write out size of the sequence file in bytes here header += U32Type(num_records).serialize() # Write number of records header += U16Type(self.__timebase).serialize() # Write time base header += U8Type(0xFF).serialize() # write time context sequence = header + sequence # Write the list of command records here # compute CRC. Ported from Utils/Hassh/libcrc/libcrc.h (update_crc_32) crc = self.computeCrc(sequence) print("CRC: %d (0x%04X)" % (crc, crc)) try: sequence += U32Type(crc).serialize() except TypeMismatchException as typeErr: print("Exception: %s" % typeErr.getMsg()) raise # Write the list of command records here self.__fd.write(sequence)
def test_serializable_type(): """ Tests the SerializableType serialization and deserialization """ u32Mem = U32Type(1000000) stringMem = StringType("something to say") members = {"MEMB1": 0, "MEMB2": 6, "MEMB3": 9} enumMem = EnumType("SomeEnum", members, "MEMB3") memList = [ ("mem1", u32Mem, ">i"), ("mem2", stringMem, ">H"), ("mem3", enumMem, ">i"), ] serType1 = SerializableType("ASerType", memList) buff = serType1.serialize() serType2 = SerializableType("ASerType", memList) serType2.deserialize(buff, 0) check_cloned_member_list(serType1.mem_list, serType2.mem_list) assert serType1.val == serType2.val i32Mem = I32Type(-1000000) stringMem = StringType("something else to say") members = {"MEMB1": 4, "MEMB2": 2, "MEMB3": 0} enumMem = EnumType("SomeEnum", members, "MEMB3") memList = [ ("mem1", i32Mem, ">i"), ("mem2", stringMem, ">H"), ("mem3", enumMem, ">i"), ] serType1 = SerializableType("ASerType", memList) buff = serType1.serialize() serType2 = SerializableType("ASerType", memList) serType2.deserialize(buff, 0) check_cloned_member_list(serType1.mem_list, serType2.mem_list) value_dict = {"mem1": 3, "mem2": "abc 123", "mem3": "MEMB1"} serType1.val = value_dict assert serType1.val == value_dict mem_list = serType1.mem_list memList = [(a, b, c, None) for a, b, c in memList] check_cloned_member_list(mem_list, memList)
def get_type(self, name): """ Retrieve a type from the config file for parsing It is assumed the setting is in the types section Args: name (string): Name of the type to retrieve Returns: If the name is valid, returns an object of a type derived from TypeBase. Otherwise, raises ConfigBadTypeException """ type_str = self.get("types", name) if type_str == "U8": return U8Type() elif type_str == "U16": return U16Type() elif type_str == "U32": return U32Type() elif type_str == "u64": return U64Type() elif type_str == "I8": return I8Type() elif type_str == "I16": return I16Type() elif type_str == "I32": return I32Type() elif type_str == "I64": return I64Type() elif type_str == "F32": return F32Type() elif type_str == "F64": return F64Type() else: # These are types for parsing, so they need to be number types # Other types can be added later raise ConfigBadTypeException(name, type_str)
def decode_api(self, data): """ Decodes the given data and returns the result. This function allows for non-registered code to call the same decoding code as is used to parse data passed to the data_callback function. Args: data: Binary telemetry channel data to decode Returns: Parsed version of the channel telemetry data in the form of a ChData object or None if the data is not decodable """ ptr = 0 # Decode Ch ID here... id_obj = U32Type() id_obj.deserialize(data, ptr) ptr += id_obj.getSize() ch_id = id_obj.val # Decode time... ch_time = TimeType() ch_time.deserialize(data, ptr) ptr += ch_time.getSize() if ch_id in self.__dict: # Retrieve the template instance for this channel ch_temp = self.__dict[ch_id] val_obj = self.decode_ch_val(data, ptr, ch_temp) return ChData(val_obj, ch_time, ch_temp) else: print("Channel decode error: id %d not in dictionary" % ch_id) return None
len(values)) # Set the new arguments by converting each value to an type: new_arg_list = list() for value, (arg_name, arg_desc, arg_value) in zip(values, self.__arguments): new_value = copy.deepcopy(arg_value) new_value.val = value new_arg_list.append((arg_name, arg_desc, new_value)) self.__arguments = new_arg_list if __name__ == "__main__": arglist = [ ("arg1", "some test argument", U32Type(0)), ("arg2", "some test argument2", F32Type(0.0)), ] try: testCommand = Command("SomeComponent", "TEST_CMD", 0x123, "Test Command", arglist) except TypeException as e: print("Exception: %s" % e.getMsg()) t = U32Type(3) t2 = F32Type(123.456) try: testCommand.setArg("arg1", t) testCommand.setArg("arg2", t2) except TypeException as e: print("Exception: %s" % e.getMsg())
def test_event_encoder(): """ Tests the encoding of the event encoder """ config = ConfigManager() config.set("types", "msg_len", "U16") enc = EventEncoder() enc_config = EventEncoder(config) temp = EventTemplate( 101, "test_ch", "test_comp", [("a1", "a1", U32Type()), ("a2", "a2", U32Type())], EventSeverity["DIAGNOSTIC"], "%d %d", ) time_obj = TimeType(2, 0, 1533758629, 123456) event_obj = EventData((U32Type(42), U32Type(10)), time_obj, temp) desc_bin = b"\x00\x00\x00\x02" id_bin = b"\x00\x00\x00\x65" time_bin = b"\x00\x02\x00\x5b\x6b\x4c\xa5\x00\x01\xe2\x40" arg_bin = b"\x00\x00\x00\x2a\x00\x00\x00\x0a" long_len_bin = b"\x00\x00\x00\x1b" short_len_bin = b"\x00\x1b" reg_expected = long_len_bin + desc_bin + id_bin + time_bin + arg_bin config_expected = short_len_bin + desc_bin + id_bin + time_bin + arg_bin reg_output = enc.encode_api(event_obj) assert (reg_output == reg_expected ), "FAIL: expected regular output to be %s, but found %s" % ( list(reg_expected), list(reg_output), ) config_output = enc_config.encode_api(event_obj) assert (config_output == config_expected ), "FAIL: expected configured output to be %s, but found %s" % ( list(config_expected), list(config_output), ) temp = EventTemplate( 102, "test_ch2", "test_comp2", [("a1", "a1", U8Type()), ("a2", "a2", U16Type())], EventSeverity["DIAGNOSTIC"], "%d %d", ) time_obj = TimeType(2, 0, 1533758628, 123457) event_obj = EventData((U8Type(128), U16Type(40)), time_obj, temp) desc_bin = b"\x00\x00\x00\x02" id_bin = b"\x00\x00\x00\x66" time_bin = b"\x00\x02\x00\x5b\x6b\x4c\xa4\x00\x01\xe2\x41" arg_bin = b"\x80\x00\x28" long_len_bin = b"\x00\x00\x00\x16" short_len_bin = b"\x00\x16" reg_expected = long_len_bin + desc_bin + id_bin + time_bin + arg_bin config_expected = short_len_bin + desc_bin + id_bin + time_bin + arg_bin reg_output = enc.encode_api(event_obj) assert (reg_output == reg_expected ), "FAIL: expected regular output to be %s, but found %s" % ( list(reg_expected), list(reg_output), ) config_output = enc_config.encode_api(event_obj) assert (config_output == config_expected ), "FAIL: expected configured output to be %s, but found %s" % ( list(config_expected), list(config_output), )
def test_ch_encoder(): """ Tests the encoding of the channel encoder """ config = ConfigManager() config.set("types", "msg_len", "U16") enc = ChEncoder() enc_config = ChEncoder(config) temp = ChTemplate(101, "test_ch", "test_comp", U32Type()) time_obj = TimeType(2, 0, 1533758629, 123456) ch_obj = ChData(U32Type(42), time_obj, temp) desc_bin = b"\x00\x00\x00\x01" id_bin = b"\x00\x00\x00\x65" time_bin = b"\x00\x02\x00\x5b\x6b\x4c\xa5\x00\x01\xe2\x40" val_bin = b"\x00\x00\x00\x2a" long_len_bin = b"\x00\x00\x00\x17" short_len_bin = b"\x00\x17" reg_expected = long_len_bin + desc_bin + id_bin + time_bin + val_bin config_expected = short_len_bin + desc_bin + id_bin + time_bin + val_bin reg_output = enc.encode_api(ch_obj) assert (reg_output == reg_expected ), "FAIL: expected regular output to be %s, but found %s" % ( list(reg_expected), list(reg_output), ) config_output = enc_config.encode_api(ch_obj) assert (config_output == config_expected ), "FAIL: expected configured output to be %s, but found %s" % ( list(config_expected), list(config_output), ) temp = ChTemplate(102, "test_ch2", "test_comp2", U16Type()) time_obj = TimeType(2, 0, 1533758628, 123457) ch_obj = ChData(U16Type(40), time_obj, temp) desc_bin = b"\x00\x00\x00\x01" id_bin = b"\x00\x00\x00\x66" time_bin = b"\x00\x02\x00\x5b\x6b\x4c\xa4\x00\x01\xe2\x41" val_bin = b"\x00\x28" long_len_bin = b"\x00\x00\x00\x15" short_len_bin = b"\x00\x15" reg_expected = long_len_bin + desc_bin + id_bin + time_bin + val_bin config_expected = short_len_bin + desc_bin + id_bin + time_bin + val_bin reg_output = enc.encode_api(ch_obj) assert (reg_output == reg_expected ), "FAIL: expected regular output to be %s, but found %s" % ( list(reg_expected), list(reg_output), ) config_output = enc_config.encode_api(ch_obj) assert (config_output == config_expected ), "FAIL: expected configured output to be %s, but found %s" % ( list(config_expected), list(config_output), )
def __length(command): return U32Type(len(command)).serialize()
def get_counter_sequence(self, length): seq = [] for i in range(0, length): ch_temp = self.pipeline.dictionaries.channel_name["Counter"] seq.append(ChData(U32Type(i), TimeType(), ch_temp)) return seq
def parse_type(self, type_name, xml_item, xml_tree): """ Parses the given type string and returns a type object. Args: type_name (string): Name of the type in the xml xml_item (lxml etree root): Parsed xml object for the item containing the type name being parsed. This is used to get meta data such as string lenght. xml_tree (lxml etree root): Parsed Xml object containing enum and serializable type info (may not be used) Returns: Object of a class derived from the TypeBase class if successful, Raises an exception if the parsing fails. The caller will hold the only reference to the object. """ if type_name == "I8": return I8Type() elif type_name == "I16": return I16Type() elif type_name == "I32": return I32Type() elif type_name == "I64": return I64Type() elif type_name == "U8": return U8Type() elif type_name == "U16": return U16Type() elif type_name == "U32": return U32Type() elif type_name == "U64": return U64Type() elif type_name == "F32": return F32Type() elif type_name == "F64": return F64Type() elif type_name == "bool": return BoolType() elif type_name == "string": if self.STR_LEN_TAG not in xml_item.attrib: print( "Trying to parse string type, but found %s field" % self.STR_LEN_TAG ) return None return StringType(max_string_len=int(xml_item.get(self.STR_LEN_TAG), 0)) else: # First try Serialized types: result = self.get_serializable_type(type_name, xml_tree) if result is not None: return result # Now try enums: result = self.get_enum_type(type_name, xml_tree) if result is not None: return result # Now try arrays: result = self.get_array_type(type_name, xml_tree) if result is not None: return result # Abandon all hope raise exceptions.GseControllerParsingException( "Could not find type %s" % type_name )