def test_with_given_preamble_and_sync(self): preamble = "10101010" sync = "10011" pg = self.build_protocol_generator(preamble_syncs=[(preamble, sync)], num_messages=(20, ), data=(lambda i: 10 * i, )) # If we have a odd preamble length, the last bit of the preamble is counted to the sync preprocessor = Preprocessor( [ np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages ], existing_message_types={ i: msg.message_type for i, msg in enumerate(pg.protocol.messages) }) preamble_starts, preamble_lengths, sync_len = preprocessor.preprocess() #self.save_protocol("given_preamble", pg) self.assertTrue( all(preamble_start == 0 for preamble_start in preamble_starts)) self.assertTrue( all(preamble_length == len(preamble) for preamble_length in preamble_lengths)) self.assertEqual(sync_len, len(sync))
def test_sync_word_finding_common_prefix(self): """ Messages are very similar (odd and even ones are the same) However, they do not have two different sync words! The algorithm needs to check for a common prefix of the two found sync words :return: """ sync = "0x1337" num_messages = 10 alice = Participant("Alice", address_hex="dead01") bob = Participant("Bob", address_hex="beef24") mb = MessageTypeBuilder("protocol_with_one_message_type") mb.add_label(FieldType.Function.PREAMBLE, 72) mb.add_label(FieldType.Function.SYNC, 16) mb.add_label(FieldType.Function.LENGTH, 8) mb.add_label(FieldType.Function.SRC_ADDRESS, 24) mb.add_label(FieldType.Function.DST_ADDRESS, 24) mb.add_label(FieldType.Function.SEQUENCE_NUMBER, 16) pg = ProtocolGenerator([mb.message_type], syncs_by_mt={mb.message_type: "0x1337"}, preambles_by_mt={mb.message_type: "10" * 36}, participants=[alice, bob]) random.seed(0) for i in range(num_messages): if i % 2 == 0: source, destination = alice, bob data_length = 8 else: source, destination = bob, alice data_length = 16 pg.generate_message(data=pg.decimal_to_bits( random.randint(0, 2**(data_length - 1)), data_length), source=source, destination=destination) preprocessor = Preprocessor([ np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages ]) possible_syncs = preprocessor.find_possible_syncs() #self.save_protocol("sync_by_common_prefix", pg) self.assertEqual(len(possible_syncs), 1) # +0000 is okay, because this will get fixed by correction in FormatFinder self.assertIn(possible_syncs[0], [ ProtocolGenerator.to_bits(sync), ProtocolGenerator.to_bits(sync) + "0000" ])
def test_format_finding_rwe(self): ff, messages = self.get_format_finder_from_protocol_file("rwe.proto.xml", return_messages=True) ff.run() sync1, sync2 = "0x9a7d9a7d", "0x67686768" preprocessor = Preprocessor([np.array(msg.plain_bits, dtype=np.uint8) for msg in messages]) possible_syncs = preprocessor.find_possible_syncs() self.assertIn(ProtocolGenerator.to_bits(sync1), possible_syncs) self.assertIn(ProtocolGenerator.to_bits(sync2), possible_syncs) ack_messages = (3, 5, 7, 9, 11, 13, 15, 17, 20) ack_message_type = next(mt for mt, messages in ff.existing_message_types.items() if ack_messages[0] in messages) self.assertTrue(all(ack_msg in ff.existing_message_types[ack_message_type] for ack_msg in ack_messages)) for mt in ff.message_types: preamble = mt.get_first_label_with_type(FieldType.Function.PREAMBLE) self.assertEqual(preamble.start, 0) self.assertEqual(preamble.length, 32) sync = mt.get_first_label_with_type(FieldType.Function.SYNC) self.assertEqual(sync.start, 32) self.assertEqual(sync.length, 32) length = mt.get_first_label_with_type(FieldType.Function.LENGTH) self.assertEqual(length.start, 64) self.assertEqual(length.length, 8) dst = mt.get_first_label_with_type(FieldType.Function.DST_ADDRESS) self.assertEqual(dst.length, 24) if mt == ack_message_type or 1 in ff.existing_message_types[mt]: self.assertEqual(dst.start, 72) else: self.assertEqual(dst.start, 88) if mt != ack_message_type and 1 not in ff.existing_message_types[mt]: src = mt.get_first_label_with_type(FieldType.Function.SRC_ADDRESS) self.assertEqual(src.start, 112) self.assertEqual(src.length, 24) elif 1 in ff.existing_message_types[mt]: # long ack src = mt.get_first_label_with_type(FieldType.Function.SRC_ADDRESS) self.assertEqual(src.start, 96) self.assertEqual(src.length, 24) crc = mt.get_first_label_with_type(FieldType.Function.CHECKSUM) self.assertIsNotNone(crc)
def test_with_three_syncs_different_preamble_lengths(self): ff, messages = self.get_format_finder_from_protocol_file( "three_syncs.proto.xml", return_messages=True) preprocessor = Preprocessor(ff.get_bitvectors_from_messages(messages)) sync_words = preprocessor.find_possible_syncs() self.assertIn("0000010000100000", sync_words, msg="Sync 1") self.assertIn("0010001000100010", sync_words, msg="Sync 2") self.assertIn("0110011101100111", sync_words, msg="Sync 3") ff.run() expected_sync_ends = [ 32, 24, 40, 24, 32, 24, 40, 24, 32, 24, 40, 24, 32, 24, 40, 24 ] for i, (s1, s2) in enumerate(zip(expected_sync_ends, ff.sync_ends)): self.assertEqual(s1, s2, msg=str(i))
def test_very_simple_sync_word_finding(self): preamble = "10101010" sync = "1101" pg = self.build_protocol_generator(preamble_syncs=[(preamble, sync)], num_messages=(20, ), data=(lambda i: 10 * i, )) preprocessor = Preprocessor([ np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages ]) possible_syncs = preprocessor.find_possible_syncs() #self.save_protocol("very_simple_sync_test", pg) self.assertGreaterEqual(len(possible_syncs), 1) self.assertEqual(preprocessor.find_possible_syncs()[0], sync)
def test_sync_word_finding_with_two_sync_words(self): preamble = "0xaaaa" sync1, sync2 = "0x1234", "0xcafe" pg = self.build_protocol_generator(preamble_syncs=[(preamble, sync1), (preamble, sync2)], num_messages=(15, 10), data=(lambda i: 12 * i, lambda i: 16 * i)) preprocessor = Preprocessor([ np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages ]) possible_syncs = preprocessor.find_possible_syncs() #self.save_protocol("two_syncs", pg) self.assertGreaterEqual(len(possible_syncs), 2) self.assertIn(ProtocolGenerator.to_bits(sync1), possible_syncs) self.assertIn(ProtocolGenerator.to_bits(sync2), possible_syncs)
def test_sync_word_finding_errored_preamble(self): preamble = "00010101010" # first bits are wrong sync = "0110" pg = self.build_protocol_generator(preamble_syncs=[(preamble, sync), (preamble + "10", sync)], num_messages=(20, 5), data=(lambda i: 10 * i, lambda i: i)) # If we have a odd preamble length, the last bit of the preamble is counted to the sync preprocessor = Preprocessor([ np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages ]) possible_syncs = preprocessor.find_possible_syncs() #self.save_protocol("errored_preamble", pg) self.assertIn(preamble[-1] + sync[:-1], possible_syncs)
def test_sync_word_finding_special_preamble(self): preamble = "111001110011100" sync = "0110" pg = self.build_protocol_generator(preamble_syncs=[(preamble, sync), (preamble + "10", sync)], num_messages=(20, 5), data=(lambda i: 10 * i, lambda i: i)) # If we have a odd preamble length, the last bit of the preamble is counted to the sync preprocessor = Preprocessor([ np.array(msg.plain_bits, dtype=np.uint8) for msg in pg.protocol.messages ]) possible_syncs = preprocessor.find_possible_syncs() #self.save_protocol("special_preamble", pg) self.assertEqual(sync, possible_syncs[0])
def __init__(self, messages, participants=None, shortest_field_length=None): """ :type messages: list of Message :param participants: """ if participants is not None: AutoAssigner.auto_assign_participants(messages, participants) existing_message_types_by_msg = { i: msg.message_type for i, msg in enumerate(messages) } self.existing_message_types = defaultdict(list) for i, message_type in existing_message_types_by_msg.items(): self.existing_message_types[message_type].append(i) preprocessor = Preprocessor( self.get_bitvectors_from_messages(messages), existing_message_types_by_msg) self.preamble_starts, self.preamble_lengths, sync_len = preprocessor.preprocess( ) self.sync_ends = self.preamble_starts + self.preamble_lengths + sync_len n = shortest_field_length if n is None: # 0 = no sync found n = 8 if sync_len >= 8 else 4 if sync_len >= 4 else 1 if sync_len >= 1 else 0 for i, value in enumerate(self.sync_ends): # In doubt it is better to under estimate the sync end if n > 0: self.sync_ends[i] = n * max(int(math.floor((value - self.preamble_starts[i]) / n)), 1) + \ self.preamble_starts[i] else: self.sync_ends[i] = self.preamble_starts[i] if self.sync_ends[i] - self.preamble_starts[ i] < self.preamble_lengths[i]: self.preamble_lengths[ i] = self.sync_ends[i] - self.preamble_starts[i] self.bitvectors = self.get_bitvectors_from_messages( messages, self.sync_ends) self.hexvectors = self.get_hexvectors(self.bitvectors) self.current_iteration = 0 participants = list( sorted( set(msg.participant for msg in messages if msg.participant is not None))) self.participant_indices = [ participants.index(msg.participant) if msg.participant is not None else -1 for msg in messages ] self.known_participant_addresses = { participants.index(p): np.array([int(h, 16) for h in p.address_hex], dtype=np.uint8) for p in participants if p and p.address_hex }