-
Notifications
You must be signed in to change notification settings - Fork 0
LFRFID: Indala 224 (resolves #2386) #339
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
08cc5f3
48a8395
896d8f2
c08acaa
4459330
fcb6f09
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,348 @@ | ||
| #include <furi.h> | ||
| #include <toolbox/protocols/protocol.h> | ||
| #include <lfrfid/tools/bit_lib.h> | ||
| #include "lfrfid_protocols.h" | ||
|
|
||
| //---------------------------------------------------------------- | ||
| // Parameter Definitions | ||
| //---------------------------------------------------------------- | ||
|
|
||
| #define INDALA224_PREAMBLE_BIT_SIZE (32) | ||
| #define INDALA224_PREAMBLE_DATA_SIZE (4) | ||
|
|
||
| #define INDALA224_ENCODED_BIT_SIZE (224) | ||
| #define INDALA224_ENCODED_DATA_SIZE \ | ||
| (((INDALA224_ENCODED_BIT_SIZE) / 8) + INDALA224_PREAMBLE_DATA_SIZE) | ||
| #define INDALA224_ENCODED_DATA_LAST ((INDALA224_ENCODED_BIT_SIZE) / 8) | ||
|
|
||
| #define INDALA224_DECODED_BIT_SIZE (224) | ||
| #define INDALA224_DECODED_DATA_SIZE (28) | ||
|
|
||
| #define INDALA224_US_PER_BIT (255) | ||
| #define INDALA224_ENCODER_PULSES_PER_BIT (16) | ||
|
|
||
| //---------------------------------------------------------------- | ||
| // Struct Definitions | ||
| //---------------------------------------------------------------- | ||
|
|
||
| typedef struct { | ||
| uint8_t data_index; | ||
| uint8_t bit_clock_index; | ||
| bool last_bit; | ||
| bool current_polarity; | ||
| bool pulse_phase; | ||
| } ProtocolIndala224Encoder; | ||
|
|
||
| typedef struct { | ||
| uint8_t encoded_data[INDALA224_ENCODED_DATA_SIZE]; | ||
| uint8_t negative_encoded_data[INDALA224_ENCODED_DATA_SIZE]; | ||
| uint8_t corrupted_encoded_data[INDALA224_ENCODED_DATA_SIZE]; | ||
| uint8_t corrupted_negative_encoded_data[INDALA224_ENCODED_DATA_SIZE]; | ||
|
|
||
| uint8_t data[INDALA224_DECODED_DATA_SIZE]; | ||
| ProtocolIndala224Encoder encoder; | ||
| } ProtocolIndala224; | ||
|
|
||
| //---------------------------------------------------------------- | ||
| // Utility Functions | ||
| //---------------------------------------------------------------- | ||
|
|
||
| // Neater aliases for getting and setting bits | ||
|
|
||
| bool gb(const uint8_t* data, size_t position) { | ||
| return bit_lib_get_bit(data, position); | ||
| } | ||
|
|
||
| void sb(uint8_t* data, size_t position, bool bit) { | ||
| bit_lib_set_bit(data, position, bit); | ||
| } | ||
|
|
||
| void psk1_to_psk2(uint8_t* data, size_t size) { | ||
| bool lastbit = gb(data, 0); | ||
| size_t num_bits = size * 8; | ||
|
|
||
| for(size_t i = 1; i < num_bits; i++) { | ||
| if(lastbit != gb(data, i)) { | ||
| lastbit = gb(data, i); | ||
| sb(data, i, 1); | ||
| } else { | ||
| sb(data, i, 0); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void psk2_to_psk1(uint8_t* data, size_t size) { | ||
| bool phase = 0; | ||
| size_t num_bits = size * 8; | ||
|
|
||
| for(size_t i = 0; i < num_bits; i++) { | ||
| if(gb(data, i) == 1) { | ||
| phase ^= 1; | ||
| } | ||
| sb(data, i, phase); | ||
| } | ||
| } | ||
|
|
||
| //---------------------------------------------------------------- | ||
| // Indala 224 Functions | ||
| //---------------------------------------------------------------- | ||
|
|
||
| ProtocolIndala224* protocol_indala224_alloc(void) { | ||
| ProtocolIndala224* protocol = malloc(sizeof(ProtocolIndala224)); | ||
| return protocol; | ||
| }; | ||
|
|
||
| void protocol_indala224_free(ProtocolIndala224* protocol) { | ||
| free(protocol); | ||
| }; | ||
|
|
||
| uint8_t* protocol_indala224_get_data(ProtocolIndala224* protocol) { | ||
| return protocol->data; | ||
| }; | ||
|
|
||
| void protocol_indala224_decoder_start(ProtocolIndala224* protocol) { | ||
| memset(protocol->encoded_data, 0, INDALA224_ENCODED_DATA_SIZE); | ||
| memset(protocol->negative_encoded_data, 0, INDALA224_ENCODED_DATA_SIZE); | ||
| memset(protocol->corrupted_encoded_data, 0, INDALA224_ENCODED_DATA_SIZE); | ||
| memset(protocol->corrupted_negative_encoded_data, 0, INDALA224_ENCODED_DATA_SIZE); | ||
| }; | ||
|
|
||
| static bool protocol_indala224_check_preamble(uint8_t* data, size_t bit_index) { | ||
| // Preamble 10000000__00000000__00000000__00000001 | ||
| if(data[bit_index / 8] != 0b10000000) return false; | ||
| if(data[(bit_index + 1) / 8] != 0b00000000) return false; | ||
| if(data[(bit_index + 2) / 8] != 0b00000000) return false; | ||
| if(data[(bit_index + 3) / 8] != 0b00000001) return false; | ||
|
Comment on lines
+110
to
+115
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
In Useful? React with 👍 / 👎. |
||
| return true; | ||
| } | ||
|
|
||
| static bool protocol_indala224_can_be_decoded(uint8_t* data) { | ||
| // Use PSK2 Demodulated version | ||
| uint8_t temp_data[INDALA224_ENCODED_DATA_SIZE]; | ||
| memcpy(temp_data, data, INDALA224_ENCODED_DATA_SIZE); | ||
| psk1_to_psk2(temp_data, INDALA224_ENCODED_DATA_SIZE); | ||
|
|
||
| if(!protocol_indala224_check_preamble(temp_data, 0)) return false; | ||
| if(!protocol_indala224_check_preamble(temp_data, 224)) return false; | ||
| return true; | ||
| } | ||
|
|
||
| static bool protocol_indala224_decoder_feed_internal(bool polarity, uint32_t time, uint8_t* data) { | ||
| time += (INDALA224_US_PER_BIT / 2); | ||
|
|
||
| size_t bit_count = (time / INDALA224_US_PER_BIT); | ||
| bool result = false; | ||
|
|
||
| if(bit_count < INDALA224_ENCODED_BIT_SIZE) { | ||
| for(size_t i = 0; i < bit_count; i++) { | ||
| bit_lib_push_bit(data, INDALA224_ENCODED_DATA_SIZE, polarity); | ||
| if(protocol_indala224_can_be_decoded(data)) { | ||
| result = true; | ||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| static void protocol_indala224_decoder_save(uint8_t* data_to, const uint8_t* data_from) { | ||
| bit_lib_copy_bits(data_to, 0, 32, data_from, 0); // UID 1 | ||
| bit_lib_copy_bits(data_to, 32, 32, data_from, 0 + 32); // UID 2 | ||
| bit_lib_copy_bits(data_to, 64, 32, data_from, 0 + 64); // UID 3 | ||
| bit_lib_copy_bits(data_to, 96, 32, data_from, 0 + 96); // UID 4 | ||
| bit_lib_copy_bits(data_to, 128, 32, data_from, 0 + 128); // UID 5 | ||
| bit_lib_copy_bits(data_to, 160, 32, data_from, 0 + 160); // UID 6 | ||
| bit_lib_copy_bits(data_to, 192, 32, data_from, 0 + 192); // UID 7 | ||
|
Comment on lines
+150
to
+156
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| // Convert from PSK1 demodulation to PSK2 demodulation | ||
| psk1_to_psk2(data_to, INDALA224_DECODED_DATA_SIZE); | ||
| } | ||
|
|
||
| bool protocol_indala224_decoder_feed(ProtocolIndala224* protocol, bool level, uint32_t duration) { | ||
| bool result = false; | ||
|
|
||
| if(duration > (INDALA224_US_PER_BIT / 2)) { | ||
| if(protocol_indala224_decoder_feed_internal(level, duration, protocol->encoded_data)) { | ||
| protocol_indala224_decoder_save(protocol->data, protocol->encoded_data); | ||
| FURI_LOG_D("Indala224", "Positive"); | ||
| result = true; | ||
| return result; | ||
| } | ||
|
|
||
| if(protocol_indala224_decoder_feed_internal( | ||
| !level, duration, protocol->negative_encoded_data)) { | ||
| protocol_indala224_decoder_save(protocol->data, protocol->negative_encoded_data); | ||
| FURI_LOG_D("Indala224", "Negative"); | ||
| result = true; | ||
| return result; | ||
| } | ||
| } | ||
|
|
||
| if(duration > (INDALA224_US_PER_BIT / 4)) { | ||
| // Try to decode wrong phase synced data | ||
| if(level) { | ||
| duration += 120; | ||
| } else { | ||
| if(duration > 120) { | ||
| duration -= 120; | ||
| } | ||
| } | ||
|
Comment on lines
+184
to
+190
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| if(protocol_indala224_decoder_feed_internal( | ||
| level, duration, protocol->corrupted_encoded_data)) { | ||
| protocol_indala224_decoder_save(protocol->data, protocol->corrupted_encoded_data); | ||
| FURI_LOG_D("Indala224", "Positive Corrupted"); | ||
|
|
||
| result = true; | ||
| return result; | ||
| } | ||
|
|
||
| if(protocol_indala224_decoder_feed_internal( | ||
| !level, duration, protocol->corrupted_negative_encoded_data)) { | ||
| protocol_indala224_decoder_save( | ||
| protocol->data, protocol->corrupted_negative_encoded_data); | ||
| FURI_LOG_D("Indala224", "Negative Corrupted"); | ||
|
|
||
| result = true; | ||
| return result; | ||
| } | ||
| } | ||
|
|
||
| return result; | ||
| }; | ||
|
|
||
| bool protocol_indala224_encoder_start(ProtocolIndala224* protocol) { | ||
| memset(protocol->encoded_data, 0, INDALA224_ENCODED_DATA_SIZE); | ||
| bit_lib_copy_bits(protocol->encoded_data, 0, 32, protocol->data, 0); // UID 1 | ||
| bit_lib_copy_bits(protocol->encoded_data, 0 + 32, 32, protocol->data, 32); // UID 2 | ||
| bit_lib_copy_bits(protocol->encoded_data, 0 + 64, 32, protocol->data, 64); // UID 3 | ||
| bit_lib_copy_bits(protocol->encoded_data, 0 + 96, 32, protocol->data, 96); // UID 4 | ||
| bit_lib_copy_bits(protocol->encoded_data, 0 + 128, 32, protocol->data, 128); // UID 5 | ||
| bit_lib_copy_bits(protocol->encoded_data, 0 + 160, 32, protocol->data, 160); // UID 6 | ||
| bit_lib_copy_bits(protocol->encoded_data, 0 + 192, 32, protocol->data, 192); // UID 7 | ||
|
Comment on lines
+217
to
+223
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| // Convert from PSK2 Demodulation to PSK1 Demodulation | ||
| psk2_to_psk1(protocol->encoded_data, INDALA224_ENCODED_DATA_SIZE); | ||
|
|
||
| protocol->encoder.last_bit = | ||
| bit_lib_get_bit(protocol->encoded_data, INDALA224_ENCODED_BIT_SIZE - 1); | ||
| protocol->encoder.data_index = 0; | ||
| protocol->encoder.current_polarity = true; | ||
| protocol->encoder.pulse_phase = true; | ||
| protocol->encoder.bit_clock_index = 0; | ||
|
|
||
| return true; | ||
| }; | ||
|
|
||
| LevelDuration protocol_indala224_encoder_yield(ProtocolIndala224* protocol) { | ||
| LevelDuration level_duration; | ||
| ProtocolIndala224Encoder* encoder = &protocol->encoder; | ||
|
|
||
| if(encoder->pulse_phase) { | ||
| level_duration = level_duration_make(encoder->current_polarity, 1); | ||
| encoder->pulse_phase = false; | ||
| } else { | ||
| level_duration = level_duration_make(!encoder->current_polarity, 1); | ||
| encoder->pulse_phase = true; | ||
|
|
||
| encoder->bit_clock_index++; | ||
| if(encoder->bit_clock_index >= INDALA224_ENCODER_PULSES_PER_BIT) { | ||
| encoder->bit_clock_index = 0; | ||
|
|
||
| bool current_bit = bit_lib_get_bit(protocol->encoded_data, encoder->data_index); | ||
|
|
||
| if(current_bit != encoder->last_bit) { | ||
| encoder->current_polarity = !encoder->current_polarity; | ||
| } | ||
|
|
||
| encoder->last_bit = current_bit; | ||
|
|
||
| bit_lib_increment_index(encoder->data_index, INDALA224_ENCODED_BIT_SIZE); | ||
| } | ||
| } | ||
|
|
||
| return level_duration; | ||
| }; | ||
|
|
||
| void protocol_indala224_render_data_internal( | ||
| ProtocolIndala224* protocol, | ||
| FuriString* result, | ||
| bool brief) { | ||
| const uint32_t uid1 = bit_lib_get_bits_32(protocol->data, 0, 32); | ||
| const uint32_t uid2 = bit_lib_get_bits_32(protocol->data, 32, 32); | ||
| const uint32_t uid3 = bit_lib_get_bits_32(protocol->data, 64, 32); | ||
| const uint32_t uid4 = bit_lib_get_bits_32(protocol->data, 96, 32); | ||
| const uint32_t uid5 = bit_lib_get_bits_32(protocol->data, 128, 32); | ||
| const uint32_t uid6 = bit_lib_get_bits_32(protocol->data, 160, 32); | ||
| const uint32_t uid7 = bit_lib_get_bits_32(protocol->data, 192, 32); | ||
|
|
||
| if(brief) { | ||
| furi_string_printf(result, "UID: %u%u...", (unsigned int)uid1, (unsigned int)uid2); | ||
| } else { | ||
| furi_string_printf( | ||
| result, | ||
| "UID: %u%u%u%u%u%u%u", | ||
| (unsigned int)uid1, | ||
| (unsigned int)uid2, | ||
| (unsigned int)uid3, | ||
| (unsigned int)uid4, | ||
| (unsigned int)uid5, | ||
| (unsigned int)uid6, | ||
| (unsigned int)uid7); | ||
| } | ||
|
Comment on lines
+280
to
+293
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The UID is 224 bits long. Printing it as a concatenated decimal string will result in a very large, unreadable number. It's standard practice to display long identifiers like this in hexadecimal format. Other Indala protocols in this codebase also use hex. Additionally, using if(brief) {
furi_string_printf(
result, "UID: %08lX%08lX...", (unsigned long)uid1, (unsigned long)uid2);
} else {
furi_string_printf(
result,
"UID: %08lX%08lX%08lX%08lX%08lX%08lX%08lX",
(unsigned long)uid1,
(unsigned long)uid2,
(unsigned long)uid3,
(unsigned long)uid4,
(unsigned long)uid5,
(unsigned long)uid6,
(unsigned long)uid7);
} |
||
| } | ||
| void protocol_indala224_render_data(ProtocolIndala224* protocol, FuriString* result) { | ||
| protocol_indala224_render_data_internal(protocol, result, false); | ||
| } | ||
| void protocol_indala224_render_brief_data(ProtocolIndala224* protocol, FuriString* result) { | ||
| protocol_indala224_render_data_internal(protocol, result, true); | ||
| } | ||
|
|
||
| bool protocol_indala224_write_data(ProtocolIndala224* protocol, void* data) { | ||
| LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; | ||
| bool result = false; | ||
|
|
||
| if(request->write_type == LFRFIDWriteTypeT5577) { | ||
| request->t5577.block[0] = LFRFID_T5577_BITRATE_RF_32 | LFRFID_T5577_MODULATION_PSK2 | | ||
| (7 << LFRFID_T5577_MAXBLOCK_SHIFT); | ||
| request->t5577.block[1] = bit_lib_get_bits_32(protocol->data, 0, 32); | ||
| request->t5577.block[2] = bit_lib_get_bits_32(protocol->data, 32, 32); | ||
| request->t5577.block[3] = bit_lib_get_bits_32(protocol->data, 32, 32); | ||
| request->t5577.block[4] = bit_lib_get_bits_32(protocol->data, 32, 32); | ||
| request->t5577.block[5] = bit_lib_get_bits_32(protocol->data, 32, 32); | ||
| request->t5577.block[6] = bit_lib_get_bits_32(protocol->data, 32, 32); | ||
| request->t5577.block[7] = bit_lib_get_bits_32(protocol->data, 32, 32); | ||
|
Comment on lines
+311
to
+315
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There seems to be a copy-paste error here. Blocks 3 through 7 are all reading data from the same offset request->t5577.block[3] = bit_lib_get_bits_32(protocol->data, 64, 32);
request->t5577.block[4] = bit_lib_get_bits_32(protocol->data, 96, 32);
request->t5577.block[5] = bit_lib_get_bits_32(protocol->data, 128, 32);
request->t5577.block[6] = bit_lib_get_bits_32(protocol->data, 160, 32);
request->t5577.block[7] = bit_lib_get_bits_32(protocol->data, 192, 32);
Comment on lines
+309
to
+315
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When writing an Indala224 tag to a T5577 ( Useful? React with 👍 / 👎. |
||
| request->t5577.blocks_to_write = 8; | ||
| result = true; | ||
| } | ||
| return result; | ||
| }; | ||
|
|
||
| //---------------------------------------------------------------- | ||
| // Indala 224 Protocol | ||
| //---------------------------------------------------------------- | ||
|
|
||
| const ProtocolBase protocol_indala224 = { | ||
| .name = "Indala224", | ||
| .manufacturer = "Motorola", | ||
| .data_size = INDALA224_DECODED_DATA_SIZE, | ||
| .features = LFRFIDFeaturePSK, | ||
| .validate_count = 6, | ||
| .alloc = (ProtocolAlloc)protocol_indala224_alloc, | ||
| .free = (ProtocolFree)protocol_indala224_free, | ||
| .get_data = (ProtocolGetData)protocol_indala224_get_data, | ||
| .decoder = | ||
| { | ||
| .start = (ProtocolDecoderStart)protocol_indala224_decoder_start, | ||
| .feed = (ProtocolDecoderFeed)protocol_indala224_decoder_feed, | ||
| }, | ||
| .encoder = | ||
| { | ||
| .start = (ProtocolEncoderStart)protocol_indala224_encoder_start, | ||
| .yield = (ProtocolEncoderYield)protocol_indala224_encoder_yield, | ||
| }, | ||
| .render_data = (ProtocolRenderData)protocol_indala224_render_data, | ||
| .render_brief_data = (ProtocolRenderData)protocol_indala224_render_brief_data, | ||
| .write_data = (ProtocolWriteData)protocol_indala224_write_data, | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| #pragma once | ||
| #include <toolbox/protocols/protocol.h> | ||
|
|
||
| extern const ProtocolBase protocol_indala224; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a bug in how byte indices are calculated for the preamble check.
(bit_index + 1) / 8will not give you the next byte index ifbit_indexis a multiple of 8. For example, ifbit_indexis 0,(0+1)/8is 0,(0+2)/8is 0, etc. You are checkingdata[0]multiple times against different values. You should calculate the base byte index and then add offsets to check subsequent bytes.