From 618ddfcd042c6a65ad7182493558f63caabf1e7c Mon Sep 17 00:00:00 2001 From: SG Date: Tue, 18 May 2021 18:37:47 +1000 Subject: [PATCH] [FL-1059] T5577 write (#463) * Api-hal-gpio: extend init functions * App Lfrfid: separate protocol layer * App Lfrfid: write EM key scene * App Lfrfid: syntax fix --- .../lf-rfid/helpers/decoder-emmarine.cpp | 108 +------- .../lf-rfid/helpers/decoder-emmarine.h | 3 +- .../lf-rfid/helpers/decoder-hid26.cpp | 95 +------ applications/lf-rfid/helpers/decoder-hid26.h | 6 +- .../lf-rfid/helpers/encoder-emmarine.cpp | 40 +-- .../lf-rfid/helpers/encoder-emmarine.h | 1 - .../lf-rfid/helpers/encoder-hid-h10301.cpp | 69 +---- .../lf-rfid/helpers/encoder-indala-40134.cpp | 92 +------ .../lf-rfid/helpers/encoder-indala-40134.h | 2 - applications/lf-rfid/helpers/key-info.h | 1 + .../helpers/protocols/protocol-emmarin.cpp | 150 +++++++++++ .../helpers/protocols/protocol-emmarin.h | 22 ++ .../helpers/protocols/protocol-generic.h | 60 +++++ .../helpers/protocols/protocol-hid-h10301.cpp | 238 ++++++++++++++++++ .../helpers/protocols/protocol-hid-h10301.h | 22 ++ .../protocols/protocol-indala-40134.cpp | 131 ++++++++++ .../helpers/protocols/protocol-indala-40134.h | 22 ++ applications/lf-rfid/helpers/rfid-writer.cpp | 118 +++++++++ applications/lf-rfid/helpers/rfid-writer.h | 17 ++ applications/lf-rfid/lf-rfid-app.cpp | 4 + applications/lf-rfid/lf-rfid-app.h | 5 + .../scene/lf-rfid-scene-read-normal.cpp | 9 + .../lf-rfid/scene/lf-rfid-scene-start.cpp | 5 + .../lf-rfid/scene/lf-rfid-scene-write.cpp | 70 ++++++ .../lf-rfid/scene/lf-rfid-scene-write.h | 14 ++ firmware/targets/f5/api-hal/api-hal-gpio.c | 45 ++-- firmware/targets/f5/api-hal/api-hal-gpio.h | 15 +- firmware/targets/f5/api-hal/api-hal-rfid.c | 12 +- 28 files changed, 956 insertions(+), 420 deletions(-) create mode 100644 applications/lf-rfid/helpers/protocols/protocol-emmarin.cpp create mode 100644 applications/lf-rfid/helpers/protocols/protocol-emmarin.h create mode 100644 applications/lf-rfid/helpers/protocols/protocol-generic.h create mode 100644 applications/lf-rfid/helpers/protocols/protocol-hid-h10301.cpp create mode 100644 applications/lf-rfid/helpers/protocols/protocol-hid-h10301.h create mode 100644 applications/lf-rfid/helpers/protocols/protocol-indala-40134.cpp create mode 100644 applications/lf-rfid/helpers/protocols/protocol-indala-40134.h create mode 100644 applications/lf-rfid/helpers/rfid-writer.cpp create mode 100644 applications/lf-rfid/helpers/rfid-writer.h create mode 100644 applications/lf-rfid/scene/lf-rfid-scene-write.cpp create mode 100644 applications/lf-rfid/scene/lf-rfid-scene-write.h diff --git a/applications/lf-rfid/helpers/decoder-emmarine.cpp b/applications/lf-rfid/helpers/decoder-emmarine.cpp index aa00f9d5..74648980 100644 --- a/applications/lf-rfid/helpers/decoder-emmarine.cpp +++ b/applications/lf-rfid/helpers/decoder-emmarine.cpp @@ -20,84 +20,13 @@ void DecoderEMMarine::reset_state() { manchester_saved_state, ManchesterEventReset, &manchester_saved_state, nullptr); } -void printEM_raw(uint64_t data) { - // header - for(uint8_t i = 0; i < 9; i++) { - printf("%u ", data & (1LLU << 63) ? 1 : 0); - data = data << 1; - } - printf("\r\n"); - - // nibbles - for(uint8_t r = 0; r < 11; r++) { - printf(" "); - uint8_t value = 0; - for(uint8_t i = 0; i < 5; i++) { - printf("%u ", data & (1LLU << 63) ? 1 : 0); - if(i < 4) value = (value << 1) | (data & (1LLU << 63) ? 1 : 0); - data = data << 1; - } - printf("0x%X", value); - printf("\r\n"); - } -} - -void printEM_data(uint64_t data) { - printf("EM "); - - // header - for(uint8_t i = 0; i < 9; i++) { - data = data << 1; - } - - // nibbles - for(uint8_t r = 0; r < EM_ROW_COUNT; r++) { - uint8_t value = 0; - for(uint8_t i = 0; i < 5; i++) { - if(i < 4) value = (value << 1) | (data & (1LLU << 63) ? 1 : 0); - data = data << 1; - } - printf("%X", value); - if(r % 2) printf(" "); - } - printf("\r\n"); -} - -void copyEM_data(uint64_t data, uint8_t* result, uint8_t result_size) { - furi_assert(result_size >= 5); - uint8_t result_index = 0; - - // clean result - memset(result, 0, result_size); - - // header - for(uint8_t i = 0; i < 9; i++) { - data = data << 1; - } - - // nibbles - uint8_t value = 0; - for(uint8_t r = 0; r < EM_ROW_COUNT; r++) { - uint8_t nibble = 0; - for(uint8_t i = 0; i < 5; i++) { - if(i < 4) nibble = (nibble << 1) | (data & (1LLU << 63) ? 1 : 0); - data = data << 1; - } - value = (value << 4) | nibble; - if(r % 2) { - result[result_index] |= value; - result_index++; - value = 0; - } - } -} - bool DecoderEMMarine::read(uint8_t* data, uint8_t data_size) { bool result = false; if(ready) { result = true; - copyEM_data(readed_data, data, data_size); + em_marine.decode( + reinterpret_cast(&readed_data), sizeof(uint64_t), data, data_size); ready = false; } @@ -132,37 +61,8 @@ void DecoderEMMarine::process_front(bool polarity, uint32_t time) { if(data_ok) { readed_data = (readed_data << 1) | data; - // header and stop bit - if((readed_data & EM_HEADER_AND_STOP_MASK) != EM_HEADER_AND_STOP_DATA) return; - - // row parity - for(uint8_t i = 0; i < EM_ROW_COUNT; i++) { - uint8_t parity_sum = 0; - - for(uint8_t j = 0; j < 5; j++) { - parity_sum += (readed_data >> (EM_FIRST_ROW_POS - i * 5 + j)) & 1; - } - - if((parity_sum % 2)) { - return; - } - } - - // columns parity - for(uint8_t i = 0; i < 4; i++) { - uint8_t parity_sum = 0; - - for(uint8_t j = 0; j < EM_ROW_COUNT + 1; j++) { - parity_sum += (readed_data >> (EM_COLUMN_POS - i + j * 5)) & 1; - } - - if((parity_sum % 2)) { - return; - } - } - - // checks ok - ready = true; + ready = em_marine.can_be_decoded( + reinterpret_cast(&readed_data), sizeof(uint64_t)); } } } diff --git a/applications/lf-rfid/helpers/decoder-emmarine.h b/applications/lf-rfid/helpers/decoder-emmarine.h index e3356d15..014e3f3e 100644 --- a/applications/lf-rfid/helpers/decoder-emmarine.h +++ b/applications/lf-rfid/helpers/decoder-emmarine.h @@ -2,7 +2,7 @@ #include #include #include "manchester-decoder.h" - +#include "protocols/protocol-emmarin.h" class DecoderEMMarine { public: bool read(uint8_t* data, uint8_t data_size); @@ -17,4 +17,5 @@ private: std::atomic ready; ManchesterState manchester_saved_state; + ProtocolEMMarin em_marine; }; diff --git a/applications/lf-rfid/helpers/decoder-hid26.cpp b/applications/lf-rfid/helpers/decoder-hid26.cpp index 534eebb7..94f52493 100644 --- a/applications/lf-rfid/helpers/decoder-hid26.cpp +++ b/applications/lf-rfid/helpers/decoder-hid26.cpp @@ -17,11 +17,8 @@ bool DecoderHID26::read(uint8_t* data, uint8_t data_size) { if(ready) { result = true; - data[0] = facility; - data[1] = (uint8_t)(number >> 8); - data[2] = (uint8_t)number; - - //printf("HID %02X %02X %02X\r\n", facility, (uint8_t)(number >> 8), (uint8_t)number); + hid.decode( + reinterpret_cast(&stored_data), sizeof(uint32_t) * 3, data, data_size); ready = false; } @@ -87,94 +84,10 @@ void DecoderHID26::store_data(bool data) { stored_data[0] = (stored_data[0] << 1) | ((stored_data[1] >> 31) & 1); stored_data[1] = (stored_data[1] << 1) | ((stored_data[2] >> 31) & 1); stored_data[2] = (stored_data[2] << 1) | data; - validate_stored_data(); -} -void DecoderHID26::validate_stored_data() { - // packet preamble - // raw data - if(*(reinterpret_cast(stored_data) + 3) != 0x1D) { - return; + if(hid.can_be_decoded(reinterpret_cast(&stored_data), sizeof(uint32_t) * 3)) { + ready = true; } - - // encoded company/oem - // coded with 01 = 0, 10 = 1 transitions - // stored in word 0 - if((*stored_data >> 10 & 0x3FFF) != 0x1556) { - return; - } - - // encoded format/length - // coded with 01 = 0, 10 = 1 transitions - // stored in word 0 and word 1 - if((((*stored_data & 0x3FF) << 12) | ((*(stored_data + 1) >> 20) & 0xFFF)) != 0x155556) { - return; - } - - // data decoding - uint32_t result = 0; - - // decode from word 1 - // coded with 01 = 0, 10 = 1 transitions - for(int8_t i = 9; i >= 0; i--) { - switch((*(stored_data + 1) >> (2 * i)) & 0b11) { - case 0b01: - result = (result << 1) | 0; - break; - case 0b10: - result = (result << 1) | 1; - break; - default: - return; - break; - } - } - - // decode from word 2 - // coded with 01 = 0, 10 = 1 transitions - for(int8_t i = 15; i >= 0; i--) { - switch((*(stored_data + 2) >> (2 * i)) & 0b11) { - case 0b01: - result = (result << 1) | 0; - break; - case 0b10: - result = (result << 1) | 1; - break; - default: - return; - break; - } - } - - // store decoded data - facility = result >> 17; - number = result >> 1; - - // trailing parity (odd) test - uint8_t parity_sum = 0; - for(int8_t i = 0; i < 13; i++) { - if(((result >> i) & 1) == 1) { - parity_sum++; - } - } - - if((parity_sum % 2) != 1) { - return; - } - - // leading parity (even) test - parity_sum = 0; - for(int8_t i = 13; i < 26; i++) { - if(((result >> i) & 1) == 1) { - parity_sum++; - } - } - - if((parity_sum % 2) == 1) { - return; - } - - ready = true; } void DecoderHID26::reset_state() { diff --git a/applications/lf-rfid/helpers/decoder-hid26.h b/applications/lf-rfid/helpers/decoder-hid26.h index cd4859e5..1e90752d 100644 --- a/applications/lf-rfid/helpers/decoder-hid26.h +++ b/applications/lf-rfid/helpers/decoder-hid26.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include "protocols/protocol-hid-h10301.h" class DecoderHID26 { public: @@ -15,12 +16,9 @@ private: uint32_t stored_data[3] = {0, 0, 0}; void store_data(bool data); - void validate_stored_data(); - - uint8_t facility = 0; - uint16_t number = 0; std::atomic ready; void reset_state(); + ProtocolHID10301 hid; }; \ No newline at end of file diff --git a/applications/lf-rfid/helpers/encoder-emmarine.cpp b/applications/lf-rfid/helpers/encoder-emmarine.cpp index 204144c4..44eea5bb 100644 --- a/applications/lf-rfid/helpers/encoder-emmarine.cpp +++ b/applications/lf-rfid/helpers/encoder-emmarine.cpp @@ -1,48 +1,14 @@ #include "encoder-emmarine.h" +#include "protocols/protocol-emmarin.h" #include void EncoderEM::init(const uint8_t* data, const uint8_t data_size) { - furi_check(data_size == 5); + ProtocolEMMarin em_marin; + em_marin.encode(data, data_size, reinterpret_cast(&card_data), sizeof(uint64_t)); - // header - card_data = 0b111111111; - - // data - for(uint8_t i = 0; i < 5; i++) { - write_nibble(false, data[i]); - write_nibble(true, data[i]); - } - - // column parity and stop bit - uint8_t parity_sum; - - for(uint8_t c = 0; c < 4; c++) { - parity_sum = 0; - for(uint8_t i = 1; i <= 10; i++) { - uint8_t parity_bit = (card_data >> (i * 5 - 1)) & 1; - parity_sum += parity_bit; - } - card_data = (card_data << 1) | ((parity_sum % 2) & 1); - } - - // stop bit - card_data = (card_data << 1) | 0; card_data_index = 0; } -void EncoderEM::write_nibble(bool low_nibble, uint8_t data) { - uint8_t parity_sum = 0; - uint8_t start = 0; - if(!low_nibble) start = 4; - - for(int8_t i = (start + 3); i >= start; i--) { - parity_sum += (data >> i) & 1; - card_data = (card_data << 1) | ((data >> i) & 1); - } - - card_data = (card_data << 1) | ((parity_sum % 2) & 1); -} - // data transmitted as manchester encoding // 0 - high2low // 1 - low2high diff --git a/applications/lf-rfid/helpers/encoder-emmarine.h b/applications/lf-rfid/helpers/encoder-emmarine.h index 49605fd9..605eea78 100644 --- a/applications/lf-rfid/helpers/encoder-emmarine.h +++ b/applications/lf-rfid/helpers/encoder-emmarine.h @@ -19,5 +19,4 @@ private: uint64_t card_data; uint8_t card_data_index; - void write_nibble(bool low_nibble, uint8_t data); }; \ No newline at end of file diff --git a/applications/lf-rfid/helpers/encoder-hid-h10301.cpp b/applications/lf-rfid/helpers/encoder-hid-h10301.cpp index 61144e3f..f4c87ce7 100644 --- a/applications/lf-rfid/helpers/encoder-hid-h10301.cpp +++ b/applications/lf-rfid/helpers/encoder-hid-h10301.cpp @@ -1,73 +1,10 @@ #include "encoder-hid-h10301.h" +#include "protocols/protocol-hid-h10301.h" #include void EncoderHID_H10301::init(const uint8_t* data, const uint8_t data_size) { - furi_check(data_size == 3); - - card_data[0] = 0; - card_data[1] = 0; - card_data[2] = 0; - - uint32_t fc_cn = (data[0] << 16) | (data[1] << 8) | data[2]; - - // even parity sum calculation (high 12 bits of data) - uint8_t even_parity_sum = 0; - for(int8_t i = 12; i < 24; i++) { - if(((fc_cn >> i) & 1) == 1) { - even_parity_sum++; - } - } - - // odd parity sum calculation (low 12 bits of data) - uint8_t odd_parity_sum = 1; - for(int8_t i = 0; i < 12; i++) { - if(((fc_cn >> i) & 1) == 1) { - odd_parity_sum++; - } - } - - // 0x1D preamble - write_raw_bit(0, 0); - write_raw_bit(0, 1); - write_raw_bit(0, 2); - write_raw_bit(1, 3); - write_raw_bit(1, 4); - write_raw_bit(1, 5); - write_raw_bit(0, 6); - write_raw_bit(1, 7); - - // company / OEM code 1 - write_bit(0, 8); - write_bit(0, 10); - write_bit(0, 12); - write_bit(0, 14); - write_bit(0, 16); - write_bit(0, 18); - write_bit(1, 20); - - // card format / length 1 - write_bit(0, 22); - write_bit(0, 24); - write_bit(0, 26); - write_bit(0, 28); - write_bit(0, 30); - write_bit(0, 32); - write_bit(0, 34); - write_bit(0, 36); - write_bit(0, 38); - write_bit(0, 40); - write_bit(1, 42); - - // even parity bit - write_bit((even_parity_sum % 2), 44); - - // data - for(uint8_t i = 0; i < 24; i++) { - write_bit((fc_cn >> (23 - i)) & 1, 46 + (i * 2)); - } - - // odd parity bit - write_bit((odd_parity_sum % 2), 94); + ProtocolHID10301 hid; + hid.encode(data, data_size, reinterpret_cast(&card_data), sizeof(card_data) * 3); card_data_index = 0; bit_index = 0; diff --git a/applications/lf-rfid/helpers/encoder-indala-40134.cpp b/applications/lf-rfid/helpers/encoder-indala-40134.cpp index dfa12a96..20a72422 100644 --- a/applications/lf-rfid/helpers/encoder-indala-40134.cpp +++ b/applications/lf-rfid/helpers/encoder-indala-40134.cpp @@ -1,102 +1,16 @@ #include "encoder-indala-40134.h" +#include "protocols/protocol-indala-40134.h" #include void EncoderIndala_40134::init(const uint8_t* data, const uint8_t data_size) { - furi_check(data_size == 3); - uint32_t fc_and_card = (data[0] << 16) | (data[1] << 8) | data[2]; - - card_data = 0; - - // preamble - set_bit(1, 0); - set_bit(1, 2); - set_bit(1, 32); - - // factory code - set_bit(((fc_and_card >> 23) & 1), 57); - set_bit(((fc_and_card >> 22) & 1), 49); - set_bit(((fc_and_card >> 21) & 1), 44); - set_bit(((fc_and_card >> 20) & 1), 47); - set_bit(((fc_and_card >> 19) & 1), 48); - set_bit(((fc_and_card >> 18) & 1), 53); - set_bit(((fc_and_card >> 17) & 1), 39); - set_bit(((fc_and_card >> 16) & 1), 58); - - // card number - set_bit(((fc_and_card >> 15) & 1), 42); - set_bit(((fc_and_card >> 14) & 1), 45); - set_bit(((fc_and_card >> 13) & 1), 43); - set_bit(((fc_and_card >> 12) & 1), 40); - set_bit(((fc_and_card >> 11) & 1), 52); - set_bit(((fc_and_card >> 10) & 1), 36); - set_bit(((fc_and_card >> 9) & 1), 35); - set_bit(((fc_and_card >> 8) & 1), 51); - set_bit(((fc_and_card >> 7) & 1), 46); - set_bit(((fc_and_card >> 6) & 1), 33); - set_bit(((fc_and_card >> 5) & 1), 37); - set_bit(((fc_and_card >> 4) & 1), 54); - set_bit(((fc_and_card >> 3) & 1), 56); - set_bit(((fc_and_card >> 2) & 1), 59); - set_bit(((fc_and_card >> 1) & 1), 50); - set_bit(((fc_and_card >> 0) & 1), 41); - - // checksum - uint8_t checksum = 0; - checksum += ((fc_and_card >> 14) & 1); - checksum += ((fc_and_card >> 12) & 1); - checksum += ((fc_and_card >> 9) & 1); - checksum += ((fc_and_card >> 8) & 1); - checksum += ((fc_and_card >> 6) & 1); - checksum += ((fc_and_card >> 5) & 1); - checksum += ((fc_and_card >> 2) & 1); - checksum += ((fc_and_card >> 0) & 1); - - // wiegand parity bits - // even parity sum calculation (high 12 bits of data) - uint8_t even_parity_sum = 0; - for(int8_t i = 12; i < 24; i++) { - if(((fc_and_card >> i) & 1) == 1) { - even_parity_sum++; - } - } - - // odd parity sum calculation (low 12 bits of data) - uint8_t odd_parity_sum = 1; - for(int8_t i = 0; i < 12; i++) { - if(((fc_and_card >> i) & 1) == 1) { - odd_parity_sum++; - } - } - - // even parity bit - set_bit((even_parity_sum % 2), 34); - - // odd parity bit - set_bit((odd_parity_sum % 2), 38); - - // checksum - if((checksum & 1) == 1) { - set_bit(0, 62); - set_bit(1, 63); - } else { - set_bit(1, 62); - set_bit(0, 63); - } + ProtocolIndala40134 indala; + indala.encode(data, data_size, reinterpret_cast(&card_data), sizeof(card_data)); last_bit = card_data & 1; card_data_index = 0; current_polarity = true; } -void EncoderIndala_40134::set_bit(bool bit, uint8_t position) { - position = 63 - position; - if(bit) { - card_data |= 1ull << position; - } else { - card_data &= ~(1ull << position); - } -} - void EncoderIndala_40134::get_next(bool* polarity, uint16_t* period, uint16_t* pulse) { *period = 2; *pulse = 1; diff --git a/applications/lf-rfid/helpers/encoder-indala-40134.h b/applications/lf-rfid/helpers/encoder-indala-40134.h index ef69784c..55c4905f 100644 --- a/applications/lf-rfid/helpers/encoder-indala-40134.h +++ b/applications/lf-rfid/helpers/encoder-indala-40134.h @@ -20,6 +20,4 @@ private: bool last_bit; bool current_polarity; static const uint8_t clock_per_bit = 16; - - void set_bit(bool bit, uint8_t position); }; \ No newline at end of file diff --git a/applications/lf-rfid/helpers/key-info.h b/applications/lf-rfid/helpers/key-info.h index c8e69caf..093bc93c 100644 --- a/applications/lf-rfid/helpers/key-info.h +++ b/applications/lf-rfid/helpers/key-info.h @@ -6,4 +6,5 @@ static const uint8_t LFRFID_KEY_SIZE = 8; enum class LfrfidKeyType : uint8_t { KeyEmarine, KeyHID, + KeyIndala, }; \ No newline at end of file diff --git a/applications/lf-rfid/helpers/protocols/protocol-emmarin.cpp b/applications/lf-rfid/helpers/protocols/protocol-emmarin.cpp new file mode 100644 index 00000000..020eb631 --- /dev/null +++ b/applications/lf-rfid/helpers/protocols/protocol-emmarin.cpp @@ -0,0 +1,150 @@ +#include "protocol-emmarin.h" +#include + +#define EM_HEADER_POS 55 +#define EM_HEADER_MASK (0x1FFLLU << EM_HEADER_POS) + +#define EM_FIRST_ROW_POS 50 + +#define EM_ROW_COUNT 10 +#define EM_COLUMN_COUNT 4 +#define EM_BITS_PER_ROW_COUNT (EM_COLUMN_COUNT + 1) + +#define EM_COLUMN_POS 4 +#define EM_STOP_POS 0 +#define EM_STOP_MASK (0x1LLU << EM_STOP_POS) + +#define EM_HEADER_AND_STOP_MASK (EM_HEADER_MASK | EM_STOP_MASK) +#define EM_HEADER_AND_STOP_DATA (EM_HEADER_MASK) + +typedef uint64_t EMMarinCardData; + +void write_nibble(bool low_nibble, uint8_t data, EMMarinCardData* card_data) { + uint8_t parity_sum = 0; + uint8_t start = 0; + if(!low_nibble) start = 4; + + for(int8_t i = (start + 3); i >= start; i--) { + parity_sum += (data >> i) & 1; + *card_data = (*card_data << 1) | ((data >> i) & 1); + } + + *card_data = (*card_data << 1) | ((parity_sum % 2) & 1); +} + +uint8_t ProtocolEMMarin::get_encoded_data_size() { + return sizeof(EMMarinCardData); +} + +uint8_t ProtocolEMMarin::get_decoded_data_size() { + return 5; +} + +void ProtocolEMMarin::encode( + const uint8_t* decoded_data, + const uint8_t decoded_data_size, + uint8_t* encoded_data, + const uint8_t encoded_data_size) { + furi_check(decoded_data_size >= get_decoded_data_size()); + furi_check(encoded_data_size >= get_encoded_data_size()); + + EMMarinCardData card_data; + + // header + card_data = 0b111111111; + + // data + for(uint8_t i = 0; i < get_decoded_data_size(); i++) { + write_nibble(false, decoded_data[i], &card_data); + write_nibble(true, decoded_data[i], &card_data); + } + + // column parity and stop bit + uint8_t parity_sum; + + for(uint8_t c = 0; c < EM_COLUMN_COUNT; c++) { + parity_sum = 0; + for(uint8_t i = 1; i <= EM_ROW_COUNT; i++) { + uint8_t parity_bit = (card_data >> (i * EM_BITS_PER_ROW_COUNT - 1)) & 1; + parity_sum += parity_bit; + } + card_data = (card_data << 1) | ((parity_sum % 2) & 1); + } + + // stop bit + card_data = (card_data << 1) | 0; + + memcpy(encoded_data, &card_data, get_encoded_data_size()); +} + +void ProtocolEMMarin::decode( + const uint8_t* encoded_data, + const uint8_t encoded_data_size, + uint8_t* decoded_data, + const uint8_t decoded_data_size) { + furi_check(decoded_data_size >= get_decoded_data_size()); + furi_check(encoded_data_size >= get_encoded_data_size()); + + uint8_t decoded_data_index = 0; + EMMarinCardData card_data = *(reinterpret_cast(encoded_data)); + + // clean result + memset(decoded_data, 0, decoded_data_size); + + // header + for(uint8_t i = 0; i < 9; i++) { + card_data = card_data << 1; + } + + // nibbles + uint8_t value = 0; + for(uint8_t r = 0; r < EM_ROW_COUNT; r++) { + uint8_t nibble = 0; + for(uint8_t i = 0; i < 5; i++) { + if(i < 4) nibble = (nibble << 1) | (card_data & (1LLU << 63) ? 1 : 0); + card_data = card_data << 1; + } + value = (value << 4) | nibble; + if(r % 2) { + decoded_data[decoded_data_index] |= value; + decoded_data_index++; + value = 0; + } + } +} + +bool ProtocolEMMarin::can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) { + furi_check(encoded_data_size >= get_encoded_data_size()); + const EMMarinCardData* card_data = reinterpret_cast(encoded_data); + + // check header and stop bit + if((*card_data & EM_HEADER_AND_STOP_MASK) != EM_HEADER_AND_STOP_DATA) return false; + + // check row parity + for(uint8_t i = 0; i < EM_ROW_COUNT; i++) { + uint8_t parity_sum = 0; + + for(uint8_t j = 0; j < EM_BITS_PER_ROW_COUNT; j++) { + parity_sum += (*card_data >> (EM_FIRST_ROW_POS - i * EM_BITS_PER_ROW_COUNT + j)) & 1; + } + + if((parity_sum % 2)) { + return false; + } + } + + // check columns parity + for(uint8_t i = 0; i < EM_COLUMN_COUNT; i++) { + uint8_t parity_sum = 0; + + for(uint8_t j = 0; j < EM_ROW_COUNT + 1; j++) { + parity_sum += (*card_data >> (EM_COLUMN_POS - i + j * EM_BITS_PER_ROW_COUNT)) & 1; + } + + if((parity_sum % 2)) { + return false; + } + } + + return true; +} diff --git a/applications/lf-rfid/helpers/protocols/protocol-emmarin.h b/applications/lf-rfid/helpers/protocols/protocol-emmarin.h new file mode 100644 index 00000000..215f7524 --- /dev/null +++ b/applications/lf-rfid/helpers/protocols/protocol-emmarin.h @@ -0,0 +1,22 @@ +#pragma once +#include "protocol-generic.h" + +class ProtocolEMMarin : public ProtocolGeneric { +public: + uint8_t get_encoded_data_size() final; + uint8_t get_decoded_data_size() final; + + void encode( + const uint8_t* decoded_data, + const uint8_t decoded_data_size, + uint8_t* encoded_data, + const uint8_t encoded_data_size) final; + + void decode( + const uint8_t* encoded_data, + const uint8_t encoded_data_size, + uint8_t* decoded_data, + const uint8_t decoded_data_size) final; + + bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) final; +}; diff --git a/applications/lf-rfid/helpers/protocols/protocol-generic.h b/applications/lf-rfid/helpers/protocols/protocol-generic.h new file mode 100644 index 00000000..8d8edfb2 --- /dev/null +++ b/applications/lf-rfid/helpers/protocols/protocol-generic.h @@ -0,0 +1,60 @@ +#pragma once +#include "stdint.h" +#include "stdbool.h" + +class ProtocolGeneric { +public: + /** + * @brief Get the encoded data size + * + * @return uint8_t size of encoded data in bytes + */ + virtual uint8_t get_encoded_data_size() = 0; + + /** + * @brief Get the decoded data size + * + * @return uint8_t size of decoded data in bytes + */ + virtual uint8_t get_decoded_data_size() = 0; + + /** + * @brief encode decoded data + * + * @param decoded_data + * @param decoded_data_size + * @param encoded_data + * @param encoded_data_size + */ + virtual void encode( + const uint8_t* decoded_data, + const uint8_t decoded_data_size, + uint8_t* encoded_data, + const uint8_t encoded_data_size) = 0; + + /** + * @brief decode encoded data + * + * @param encoded_data + * @param encoded_data_size + * @param decoded_data + * @param decoded_data_size + */ + virtual void decode( + const uint8_t* encoded_data, + const uint8_t encoded_data_size, + uint8_t* decoded_data, + const uint8_t decoded_data_size) = 0; + + /** + * @brief fast check that data can be correctly decoded + * + * @param encoded_data + * @param encoded_data_size + * @return true - can be correctly decoded + * @return false - cannot be correctly decoded + */ + virtual bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) = 0; + + virtual ~ProtocolGeneric(){}; +}; \ No newline at end of file diff --git a/applications/lf-rfid/helpers/protocols/protocol-hid-h10301.cpp b/applications/lf-rfid/helpers/protocols/protocol-hid-h10301.cpp new file mode 100644 index 00000000..760ec022 --- /dev/null +++ b/applications/lf-rfid/helpers/protocols/protocol-hid-h10301.cpp @@ -0,0 +1,238 @@ +#include "protocol-hid-h10301.h" +#include + +typedef uint32_t HID10301CardData; +constexpr uint8_t HID10301Count = 3; +constexpr uint8_t HID10301BitSize = sizeof(HID10301CardData) * 8; + +static void write_raw_bit(bool bit, uint8_t position, HID10301CardData* card_data) { + if(bit) { + card_data[position / HID10301BitSize] |= + 1UL << (HID10301BitSize - (position % HID10301BitSize) - 1); + } else { + card_data[position / (sizeof(HID10301CardData) * 8)] &= + ~(1UL << (HID10301BitSize - (position % HID10301BitSize) - 1)); + } +} + +static void write_bit(bool bit, uint8_t position, HID10301CardData* card_data) { + write_raw_bit(bit, position + 0, card_data); + write_raw_bit(!bit, position + 1, card_data); +} + +uint8_t ProtocolHID10301::get_encoded_data_size() { + return sizeof(HID10301CardData) * HID10301Count; +} + +uint8_t ProtocolHID10301::get_decoded_data_size() { + return 3; +} + +void ProtocolHID10301::encode( + const uint8_t* decoded_data, + const uint8_t decoded_data_size, + uint8_t* encoded_data, + const uint8_t encoded_data_size) { + furi_check(decoded_data_size >= get_decoded_data_size()); + furi_check(encoded_data_size >= get_encoded_data_size()); + + HID10301CardData card_data[HID10301Count] = {0, 0, 0}; + + uint32_t fc_cn = (decoded_data[0] << 16) | (decoded_data[1] << 8) | decoded_data[2]; + + // even parity sum calculation (high 12 bits of data) + uint8_t even_parity_sum = 0; + for(int8_t i = 12; i < 24; i++) { + if(((fc_cn >> i) & 1) == 1) { + even_parity_sum++; + } + } + + // odd parity sum calculation (low 12 bits of data) + uint8_t odd_parity_sum = 1; + for(int8_t i = 0; i < 12; i++) { + if(((fc_cn >> i) & 1) == 1) { + odd_parity_sum++; + } + } + + // 0x1D preamble + write_raw_bit(0, 0, card_data); + write_raw_bit(0, 1, card_data); + write_raw_bit(0, 2, card_data); + write_raw_bit(1, 3, card_data); + write_raw_bit(1, 4, card_data); + write_raw_bit(1, 5, card_data); + write_raw_bit(0, 6, card_data); + write_raw_bit(1, 7, card_data); + + // company / OEM code 1 + write_bit(0, 8, card_data); + write_bit(0, 10, card_data); + write_bit(0, 12, card_data); + write_bit(0, 14, card_data); + write_bit(0, 16, card_data); + write_bit(0, 18, card_data); + write_bit(1, 20, card_data); + + // card format / length 1 + write_bit(0, 22, card_data); + write_bit(0, 24, card_data); + write_bit(0, 26, card_data); + write_bit(0, 28, card_data); + write_bit(0, 30, card_data); + write_bit(0, 32, card_data); + write_bit(0, 34, card_data); + write_bit(0, 36, card_data); + write_bit(0, 38, card_data); + write_bit(0, 40, card_data); + write_bit(1, 42, card_data); + + // even parity bit + write_bit((even_parity_sum % 2), 44, card_data); + + // data + for(uint8_t i = 0; i < 24; i++) { + write_bit((fc_cn >> (23 - i)) & 1, 46 + (i * 2), card_data); + } + + // odd parity bit + write_bit((odd_parity_sum % 2), 94, card_data); + + memcpy(encoded_data, &card_data, get_encoded_data_size()); +} + +void ProtocolHID10301::decode( + const uint8_t* encoded_data, + const uint8_t encoded_data_size, + uint8_t* decoded_data, + const uint8_t decoded_data_size) { + furi_check(decoded_data_size >= get_decoded_data_size()); + furi_check(encoded_data_size >= get_encoded_data_size()); + + const HID10301CardData* card_data = reinterpret_cast(encoded_data); + + // data decoding + uint32_t result = 0; + + // decode from word 1 + // coded with 01 = 0, 10 = 1 transitions + for(int8_t i = 9; i >= 0; i--) { + switch((*(card_data + 1) >> (2 * i)) & 0b11) { + case 0b01: + result = (result << 1) | 0; + break; + case 0b10: + result = (result << 1) | 1; + break; + default: + break; + } + } + + // decode from word 2 + // coded with 01 = 0, 10 = 1 transitions + for(int8_t i = 15; i >= 0; i--) { + switch((*(card_data + 2) >> (2 * i)) & 0b11) { + case 0b01: + result = (result << 1) | 0; + break; + case 0b10: + result = (result << 1) | 1; + break; + default: + break; + } + } + + uint8_t data[3] = {(uint8_t)(result >> 17), (uint8_t)(result >> 9), (uint8_t)(result >> 1)}; + + memcpy(decoded_data, &data, get_decoded_data_size()); +} + +bool ProtocolHID10301::can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) { + furi_check(encoded_data_size >= get_encoded_data_size()); + + const HID10301CardData* card_data = reinterpret_cast(encoded_data); + + // packet preamble + // raw data + if(*(encoded_data + 3) != 0x1D) { + return false; + } + + // encoded company/oem + // coded with 01 = 0, 10 = 1 transitions + // stored in word 0 + if((*card_data >> 10 & 0x3FFF) != 0x1556) { + return false; + } + + // encoded format/length + // coded with 01 = 0, 10 = 1 transitions + // stored in word 0 and word 1 + if((((*card_data & 0x3FF) << 12) | ((*(card_data + 1) >> 20) & 0xFFF)) != 0x155556) { + return false; + } + + // data decoding + uint32_t result = 0; + + // decode from word 1 + // coded with 01 = 0, 10 = 1 transitions + for(int8_t i = 9; i >= 0; i--) { + switch((*(card_data + 1) >> (2 * i)) & 0b11) { + case 0b01: + result = (result << 1) | 0; + break; + case 0b10: + result = (result << 1) | 1; + break; + default: + return false; + break; + } + } + + // decode from word 2 + // coded with 01 = 0, 10 = 1 transitions + for(int8_t i = 15; i >= 0; i--) { + switch((*(card_data + 2) >> (2 * i)) & 0b11) { + case 0b01: + result = (result << 1) | 0; + break; + case 0b10: + result = (result << 1) | 1; + break; + default: + return false; + break; + } + } + + // trailing parity (odd) test + uint8_t parity_sum = 0; + for(int8_t i = 0; i < 13; i++) { + if(((result >> i) & 1) == 1) { + parity_sum++; + } + } + + if((parity_sum % 2) != 1) { + return false; + } + + // leading parity (even) test + parity_sum = 0; + for(int8_t i = 13; i < 26; i++) { + if(((result >> i) & 1) == 1) { + parity_sum++; + } + } + + if((parity_sum % 2) == 1) { + return false; + } + + return true; +} diff --git a/applications/lf-rfid/helpers/protocols/protocol-hid-h10301.h b/applications/lf-rfid/helpers/protocols/protocol-hid-h10301.h new file mode 100644 index 00000000..4fdf6520 --- /dev/null +++ b/applications/lf-rfid/helpers/protocols/protocol-hid-h10301.h @@ -0,0 +1,22 @@ +#pragma once +#include "protocol-generic.h" + +class ProtocolHID10301 : public ProtocolGeneric { +public: + uint8_t get_encoded_data_size() final; + uint8_t get_decoded_data_size() final; + + void encode( + const uint8_t* decoded_data, + const uint8_t decoded_data_size, + uint8_t* encoded_data, + const uint8_t encoded_data_size) final; + + void decode( + const uint8_t* encoded_data, + const uint8_t encoded_data_size, + uint8_t* decoded_data, + const uint8_t decoded_data_size) final; + + bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) final; +}; \ No newline at end of file diff --git a/applications/lf-rfid/helpers/protocols/protocol-indala-40134.cpp b/applications/lf-rfid/helpers/protocols/protocol-indala-40134.cpp new file mode 100644 index 00000000..5873e0bd --- /dev/null +++ b/applications/lf-rfid/helpers/protocols/protocol-indala-40134.cpp @@ -0,0 +1,131 @@ +#include "protocol-indala-40134.h" +#include + +typedef uint64_t Indala40134CardData; + +static void set_bit(bool bit, uint8_t position, Indala40134CardData* card_data) { + position = (sizeof(Indala40134CardData) * 8) - 1 - position; + if(bit) { + *card_data |= 1ull << position; + } else { + *card_data &= ~(1ull << position); + } +} + +uint8_t ProtocolIndala40134::get_encoded_data_size() { + return sizeof(Indala40134CardData); +} + +uint8_t ProtocolIndala40134::get_decoded_data_size() { + return 3; +} + +void ProtocolIndala40134::encode( + const uint8_t* decoded_data, + const uint8_t decoded_data_size, + uint8_t* encoded_data, + const uint8_t encoded_data_size) { + furi_check(decoded_data_size >= get_decoded_data_size()); + furi_check(encoded_data_size >= get_encoded_data_size()); + + uint32_t fc_and_card = (decoded_data[0] << 16) | (decoded_data[1] << 8) | decoded_data[2]; + Indala40134CardData card_data = 0; + + // preamble + set_bit(1, 0, &card_data); + set_bit(1, 2, &card_data); + set_bit(1, 32, &card_data); + + // factory code + set_bit(((fc_and_card >> 23) & 1), 57, &card_data); + set_bit(((fc_and_card >> 22) & 1), 49, &card_data); + set_bit(((fc_and_card >> 21) & 1), 44, &card_data); + set_bit(((fc_and_card >> 20) & 1), 47, &card_data); + set_bit(((fc_and_card >> 19) & 1), 48, &card_data); + set_bit(((fc_and_card >> 18) & 1), 53, &card_data); + set_bit(((fc_and_card >> 17) & 1), 39, &card_data); + set_bit(((fc_and_card >> 16) & 1), 58, &card_data); + + // card number + set_bit(((fc_and_card >> 15) & 1), 42, &card_data); + set_bit(((fc_and_card >> 14) & 1), 45, &card_data); + set_bit(((fc_and_card >> 13) & 1), 43, &card_data); + set_bit(((fc_and_card >> 12) & 1), 40, &card_data); + set_bit(((fc_and_card >> 11) & 1), 52, &card_data); + set_bit(((fc_and_card >> 10) & 1), 36, &card_data); + set_bit(((fc_and_card >> 9) & 1), 35, &card_data); + set_bit(((fc_and_card >> 8) & 1), 51, &card_data); + set_bit(((fc_and_card >> 7) & 1), 46, &card_data); + set_bit(((fc_and_card >> 6) & 1), 33, &card_data); + set_bit(((fc_and_card >> 5) & 1), 37, &card_data); + set_bit(((fc_and_card >> 4) & 1), 54, &card_data); + set_bit(((fc_and_card >> 3) & 1), 56, &card_data); + set_bit(((fc_and_card >> 2) & 1), 59, &card_data); + set_bit(((fc_and_card >> 1) & 1), 50, &card_data); + set_bit(((fc_and_card >> 0) & 1), 41, &card_data); + + // checksum + uint8_t checksum = 0; + checksum += ((fc_and_card >> 14) & 1); + checksum += ((fc_and_card >> 12) & 1); + checksum += ((fc_and_card >> 9) & 1); + checksum += ((fc_and_card >> 8) & 1); + checksum += ((fc_and_card >> 6) & 1); + checksum += ((fc_and_card >> 5) & 1); + checksum += ((fc_and_card >> 2) & 1); + checksum += ((fc_and_card >> 0) & 1); + + // wiegand parity bits + // even parity sum calculation (high 12 bits of data) + uint8_t even_parity_sum = 0; + for(int8_t i = 12; i < 24; i++) { + if(((fc_and_card >> i) & 1) == 1) { + even_parity_sum++; + } + } + + // odd parity sum calculation (low 12 bits of data) + uint8_t odd_parity_sum = 1; + for(int8_t i = 0; i < 12; i++) { + if(((fc_and_card >> i) & 1) == 1) { + odd_parity_sum++; + } + } + + // even parity bit + set_bit((even_parity_sum % 2), 34, &card_data); + + // odd parity bit + set_bit((odd_parity_sum % 2), 38, &card_data); + + // checksum + if((checksum & 1) == 1) { + set_bit(0, 62, &card_data); + set_bit(1, 63, &card_data); + } else { + set_bit(1, 62, &card_data); + set_bit(0, 63, &card_data); + } + + memcpy(encoded_data, &card_data, get_encoded_data_size()); +} + +void ProtocolIndala40134::decode( + const uint8_t* encoded_data, + const uint8_t encoded_data_size, + uint8_t* decoded_data, + const uint8_t decoded_data_size) { + furi_check(decoded_data_size >= get_decoded_data_size()); + furi_check(encoded_data_size >= get_encoded_data_size()); + // TODO implement decoding + furi_check(0); +} + +bool ProtocolIndala40134::can_be_decoded( + const uint8_t* encoded_data, + const uint8_t encoded_data_size) { + furi_check(encoded_data_size >= get_encoded_data_size()); + // TODO implement decoding + furi_check(0); + return false; +} \ No newline at end of file diff --git a/applications/lf-rfid/helpers/protocols/protocol-indala-40134.h b/applications/lf-rfid/helpers/protocols/protocol-indala-40134.h new file mode 100644 index 00000000..1b11fb2a --- /dev/null +++ b/applications/lf-rfid/helpers/protocols/protocol-indala-40134.h @@ -0,0 +1,22 @@ +#pragma once +#include "protocol-generic.h" + +class ProtocolIndala40134 : public ProtocolGeneric { +public: + uint8_t get_encoded_data_size() final; + uint8_t get_decoded_data_size() final; + + void encode( + const uint8_t* decoded_data, + const uint8_t decoded_data_size, + uint8_t* encoded_data, + const uint8_t encoded_data_size) final; + + void decode( + const uint8_t* encoded_data, + const uint8_t encoded_data_size, + uint8_t* decoded_data, + const uint8_t decoded_data_size) final; + + bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) final; +}; diff --git a/applications/lf-rfid/helpers/rfid-writer.cpp b/applications/lf-rfid/helpers/rfid-writer.cpp new file mode 100644 index 00000000..91597075 --- /dev/null +++ b/applications/lf-rfid/helpers/rfid-writer.cpp @@ -0,0 +1,118 @@ +#include "rfid-writer.h" +#include +#include "protocols/protocol-emmarin.h" + +extern COMP_HandleTypeDef hcomp1; + +/** + * @brief all timings are specified in field clocks (field clock = 125 kHz, 8 us) + * + */ +class T55xxTiming { +public: + constexpr static const uint16_t wait_time = 400; + constexpr static const uint8_t start_gap = 15; + constexpr static const uint8_t write_gap = 10; + constexpr static const uint8_t data_0 = 24; + constexpr static const uint8_t data_1 = 56; + constexpr static const uint16_t program = 700; +}; + +class T55xxCmd { +public: + constexpr static const uint8_t opcode_page_0 = 0b10; + constexpr static const uint8_t opcode_page_1 = 0b11; + constexpr static const uint8_t opcode_reset = 0b00; +}; + +RfidWriter::RfidWriter() { +} + +RfidWriter::~RfidWriter() { +} + +void RfidWriter::start() { + api_hal_rfid_tim_read(125000, 0.5); + api_hal_rfid_pins_read(); +} + +void RfidWriter::stop() { + api_hal_rfid_tim_read_stop(); + api_hal_rfid_tim_reset(); + api_hal_rfid_pins_reset(); +} + +void RfidWriter::write_gap(uint32_t gap_time) { + api_hal_rfid_tim_read_stop(); + delay_us(gap_time * 8); + api_hal_rfid_tim_read_start(); +} + +void RfidWriter::write_bit(bool value) { + if(value) { + delay_us(T55xxTiming::data_1 * 8); + } else { + delay_us(T55xxTiming::data_0 * 8); + } + write_gap(T55xxTiming::write_gap); +} + +void RfidWriter::write_byte(uint8_t value) { + for(uint8_t i = 0; i < 8; i++) { + write_bit((value >> i) & 1); + } +} + +void RfidWriter::write_block(uint8_t page, uint8_t block, bool lock_bit, uint32_t data) { + // wait to power card + api_hal_rfid_tim_read_start(); + delay_us(T55xxTiming::wait_time * 8); + + // start gap + write_gap(T55xxTiming::start_gap); + + // opcode + switch(page) { + case 0: + write_bit(1); + write_bit(0); + break; + case 1: + write_bit(1); + write_bit(1); + break; + default: + furi_check(false); + break; + } + + // lock bit + write_bit(lock_bit); + + // data + for(uint8_t i = 0; i < 32; i++) { + write_bit((data >> (31 - i)) & 1); + } + + // block address + write_bit((block >> 2) & 1); + write_bit((block >> 1) & 1); + write_bit((block >> 0) & 1); + + delay_us(T55xxTiming::program * 8); + + api_hal_rfid_tim_read_stop(); +} + +void RfidWriter::write_em(uint8_t em_data[5]) { + ProtocolEMMarin em_card; + uint64_t em_encoded_data; + em_card.encode(em_data, 5, reinterpret_cast(&em_encoded_data), sizeof(uint64_t)); + uint32_t em_config_block_data = 0b01100000000101001000000001000000; + + __disable_irq(); + write_block(0, 0, false, em_config_block_data); + write_block(0, 1, false, em_encoded_data); + write_block(0, 2, false, em_encoded_data >> 32); + __enable_irq(); +} diff --git a/applications/lf-rfid/helpers/rfid-writer.h b/applications/lf-rfid/helpers/rfid-writer.h new file mode 100644 index 00000000..5da163f1 --- /dev/null +++ b/applications/lf-rfid/helpers/rfid-writer.h @@ -0,0 +1,17 @@ +#pragma once +#include "stdint.h" + +class RfidWriter { +public: + RfidWriter(); + ~RfidWriter(); + void start(); + void stop(); + void write_em(uint8_t em_data[5]); + +private: + void write_gap(uint32_t gap_time); + void write_bit(bool value); + void write_byte(uint8_t value); + void write_block(uint8_t page, uint8_t block, bool lock_bit, uint32_t data); +}; \ No newline at end of file diff --git a/applications/lf-rfid/lf-rfid-app.cpp b/applications/lf-rfid/lf-rfid-app.cpp index 8e994c55..a9f5c7b2 100644 --- a/applications/lf-rfid/lf-rfid-app.cpp +++ b/applications/lf-rfid/lf-rfid-app.cpp @@ -143,4 +143,8 @@ RfidReader* LfrfidApp::get_reader() { RfidTimerEmulator* LfrfidApp::get_emulator() { return &emulator; +} + +RfidWriter* LfrfidApp::get_writer() { + return &writer; } \ No newline at end of file diff --git a/applications/lf-rfid/lf-rfid-app.h b/applications/lf-rfid/lf-rfid-app.h index 8bafb05a..1bd7c677 100644 --- a/applications/lf-rfid/lf-rfid-app.h +++ b/applications/lf-rfid/lf-rfid-app.h @@ -10,6 +10,7 @@ #include "scene/lf-rfid-scene-read-normal.h" #include "scene/lf-rfid-scene-read-indala.h" #include "scene/lf-rfid-scene-tune.h" +#include "scene/lf-rfid-scene-write.h" #include "helpers/rfid-reader.h" #include "helpers/rfid-timer-emulator.h" @@ -30,6 +31,7 @@ public: EmulateHID, EmulateEM, Tune, + Write, }; LfrfidAppViewManager* get_view_manager(); @@ -49,6 +51,7 @@ public: RfidReader* get_reader(); RfidTimerEmulator* get_emulator(); + RfidWriter* get_writer(); private: std::list previous_scenes_list = {Scene::Exit}; @@ -63,6 +66,7 @@ private: {Scene::EmulateHID, new LfrfidSceneEmulateHID()}, {Scene::EmulateEM, new LfrfidSceneEmulateEMMarine()}, {Scene::Tune, new LfrfidSceneTune()}, + {Scene::Write, new LfrfidSceneWrite()}, }; static const uint8_t text_store_size = 128; @@ -70,4 +74,5 @@ private: RfidReader reader; RfidTimerEmulator emulator; + RfidWriter writer; }; \ No newline at end of file diff --git a/applications/lf-rfid/scene/lf-rfid-scene-read-normal.cpp b/applications/lf-rfid/scene/lf-rfid-scene-read-normal.cpp index 10e6bdef..ca080627 100644 --- a/applications/lf-rfid/scene/lf-rfid-scene-read-normal.cpp +++ b/applications/lf-rfid/scene/lf-rfid-scene-read-normal.cpp @@ -55,6 +55,15 @@ bool LfrfidSceneReadNormal::on_event(LfrfidApp* app, LfrfidEvent* event) { data[2], success_reads); break; + case LfrfidKeyType::KeyIndala: + app->set_text_store( + "[IND] %02X %02X %02X\n" + "count: %u", + data[0], + data[1], + data[2], + success_reads); + break; } popup_set_text( app->get_view_manager()->get_popup(), diff --git a/applications/lf-rfid/scene/lf-rfid-scene-start.cpp b/applications/lf-rfid/scene/lf-rfid-scene-start.cpp index d5e5a30b..7f8c0644 100644 --- a/applications/lf-rfid/scene/lf-rfid-scene-start.cpp +++ b/applications/lf-rfid/scene/lf-rfid-scene-start.cpp @@ -5,6 +5,7 @@ #include typedef enum { + SubmenuIndexWrite, SubmenuIndexReadNormal, SubmenuIndexReadIndala, SubmenuIndexEmulateEM, @@ -18,6 +19,7 @@ void LfrfidSceneStart::on_enter(LfrfidApp* app) { Submenu* submenu = view_manager->get_submenu(); auto callback = cbc::obtain_connector(this, &LfrfidSceneStart::submenu_callback); + submenu_add_item(submenu, "Write T5577", SubmenuIndexWrite, callback, app); submenu_add_item(submenu, "Read Normal", SubmenuIndexReadNormal, callback, app); submenu_add_item(submenu, "Read Indala", SubmenuIndexReadIndala, callback, app); submenu_add_item(submenu, "Emulate EM", SubmenuIndexEmulateEM, callback, app); @@ -33,6 +35,9 @@ bool LfrfidSceneStart::on_event(LfrfidApp* app, LfrfidEvent* event) { if(event->type == LfrfidEvent::Type::MenuSelected) { switch(event->payload.menu_index) { + case SubmenuIndexWrite: + app->switch_to_next_scene(LfrfidApp::Scene::Write); + break; case SubmenuIndexReadNormal: app->switch_to_next_scene(LfrfidApp::Scene::ReadNormal); break; diff --git a/applications/lf-rfid/scene/lf-rfid-scene-write.cpp b/applications/lf-rfid/scene/lf-rfid-scene-write.cpp new file mode 100644 index 00000000..48de9154 --- /dev/null +++ b/applications/lf-rfid/scene/lf-rfid-scene-write.cpp @@ -0,0 +1,70 @@ +#include "lf-rfid-scene-write.h" + +#include "../lf-rfid-app.h" +#include "../lf-rfid-view-manager.h" +#include "../lf-rfid-event.h" +#include "../helpers/key-info.h" + +void LfrfidSceneWrite::on_enter(LfrfidApp* app) { + LfrfidAppViewManager* view_manager = app->get_view_manager(); + + Popup* popup = view_manager->get_popup(); + popup_set_header(popup, "LF-RFID", 64, 16, AlignCenter, AlignBottom); + app->set_text_store("Writing..."); + popup_set_text(popup, app->get_text_store(), 64, 22, AlignCenter, AlignTop); + + view_manager->switch_to(LfrfidAppViewManager::ViewType::Popup); + + timing_index = 0; +} + +bool LfrfidSceneWrite::on_event(LfrfidApp* app, LfrfidEvent* event) { + bool consumed = false; + + // TODO move read\write logic to key worker + + bool readed = false; + uint8_t em_data[5] = {0x1A, 0x2B, 0xC3, 0xD4, 0xE5}; + + if(timing_index == 0) { + app->get_reader()->stop(); + app->get_writer()->start(); + app->get_writer()->write_em(em_data); + app->get_writer()->stop(); + delay(100); + app->get_reader()->start(RfidReader::Type::Normal); + } else { + uint8_t data[LFRFID_KEY_SIZE]; + LfrfidKeyType type; + + app->get_reader()->read(&type, data, LFRFID_KEY_SIZE); + if(type == LfrfidKeyType::KeyEmarine) { + if(memcmp(em_data, data, 5) == 0) { + readed = true; + } + } + } + + if(readed) { + app->set_text_store("Writed!"); + app->notify_green_blink(); + } else { + app->set_text_store("Writing [1A 2B C3 D4 E5]"); + timing_index++; + if(timing_index == 4) { + timing_index = 0; + } + } + popup_set_text( + app->get_view_manager()->get_popup(), app->get_text_store(), 64, 22, AlignCenter, AlignTop); + + return consumed; +} + +void LfrfidSceneWrite::on_exit(LfrfidApp* app) { + LfrfidAppViewManager* view_manager = app->get_view_manager(); + + Popup* popup = view_manager->get_popup(); + popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); + popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); +} \ No newline at end of file diff --git a/applications/lf-rfid/scene/lf-rfid-scene-write.h b/applications/lf-rfid/scene/lf-rfid-scene-write.h new file mode 100644 index 00000000..274fa7e0 --- /dev/null +++ b/applications/lf-rfid/scene/lf-rfid-scene-write.h @@ -0,0 +1,14 @@ +#pragma once +#include "lf-rfid-scene-generic.h" +#include "../helpers/key-info.h" +#include "../helpers/rfid-writer.h" + +class LfrfidSceneWrite : public LfrfidScene { +public: + void on_enter(LfrfidApp* app) final; + bool on_event(LfrfidApp* app, LfrfidEvent* event) final; + void on_exit(LfrfidApp* app) final; + +private: + uint8_t timing_index; +}; \ No newline at end of file diff --git a/firmware/targets/f5/api-hal/api-hal-gpio.c b/firmware/targets/f5/api-hal/api-hal-gpio.c index bceba009..03d79d4c 100644 --- a/firmware/targets/f5/api-hal/api-hal-gpio.c +++ b/firmware/targets/f5/api-hal/api-hal-gpio.c @@ -41,11 +41,28 @@ static uint8_t hal_gpio_get_pin_num(const GpioPin* gpio) { return pin_num; } +void hal_gpio_init_simple(const GpioPin* gpio, const GpioMode mode) { + hal_gpio_init(gpio, mode, GpioPullNo, GpioSpeedLow); +} + void hal_gpio_init( const GpioPin* gpio, const GpioMode mode, const GpioPull pull, const GpioSpeed speed) { + // we cannot set alternate mode in this function + furi_assert(mode != GpioModeAltFunctionPushPull); + furi_assert(mode != GpioModeAltFunctionOpenDrain); + + hal_gpio_init_ex(gpio, mode, GpioPullNo, GpioSpeedLow, GpioAltFnUnused); +} + +void hal_gpio_init_ex( + const GpioPin* gpio, + const GpioMode mode, + const GpioPull pull, + const GpioSpeed speed, + const GpioAltFn alt_fn) { uint32_t sys_exti_port = GET_SYSCFG_EXTI_PORT(gpio->port); uint32_t sys_exti_line = GET_SYSCFG_EXTI_LINE(gpio->pin); uint32_t exti_line = GET_EXTI_LINE(gpio->pin); @@ -112,27 +129,19 @@ void hal_gpio_init( LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ANALOG); } } - __enable_irq(); -} -void hal_gpio_init_alt( - const GpioPin* gpio, - const GpioMode mode, - const GpioPull pull, - const GpioSpeed speed, - const GpioAltFn alt_fn) { - hal_gpio_init(gpio, mode, pull, speed); + if(mode == GpioModeAltFunctionPushPull || mode == GpioModeAltFunctionOpenDrain) { + // enable alternate mode + LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ALTERNATE); - __disable_irq(); - // enable alternate mode - LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ALTERNATE); - - // set alternate function - if(hal_gpio_get_pin_num(gpio) < 8) { - LL_GPIO_SetAFPin_0_7(gpio->port, gpio->pin, alt_fn); - } else { - LL_GPIO_SetAFPin_8_15(gpio->port, gpio->pin, alt_fn); + // set alternate function + if(hal_gpio_get_pin_num(gpio) < 8) { + LL_GPIO_SetAFPin_0_7(gpio->port, gpio->pin, alt_fn); + } else { + LL_GPIO_SetAFPin_8_15(gpio->port, gpio->pin, alt_fn); + } } + __enable_irq(); } diff --git a/firmware/targets/f5/api-hal/api-hal-gpio.h b/firmware/targets/f5/api-hal/api-hal-gpio.h index 7bed0572..a81afb39 100644 --- a/firmware/targets/f5/api-hal/api-hal-gpio.h +++ b/firmware/targets/f5/api-hal/api-hal-gpio.h @@ -153,6 +153,8 @@ typedef enum { GpioAltFn14LPTIM2 = 14, /*!< LPTIM2 Alternate Function mapping */ GpioAltFn15EVENTOUT = 15, /*!< EVENTOUT Alternate Function mapping */ + + GpioAltFnUnused = 16, /*!< just dummy value */ } GpioAltFn; /** @@ -164,7 +166,14 @@ typedef struct { } GpioPin; /** - * GPIO initialization function + * GPIO initialization function, simple version + * @param gpio GpioPin + * @param mode GpioMode + */ +void hal_gpio_init_simple(const GpioPin* gpio, const GpioMode mode); + +/** + * GPIO initialization function, normal version * @param gpio GpioPin * @param mode GpioMode * @param pull GpioPull @@ -177,14 +186,14 @@ void hal_gpio_init( const GpioSpeed speed); /** - * GPIO initialization with alternative function + * GPIO initialization function, extended version * @param gpio GpioPin * @param mode GpioMode * @param pull GpioPull * @param speed GpioSpeed * @param alt_fn GpioAltFn */ -void hal_gpio_init_alt( +void hal_gpio_init_ex( const GpioPin* gpio, const GpioMode mode, const GpioPull pull, diff --git a/firmware/targets/f5/api-hal/api-hal-rfid.c b/firmware/targets/f5/api-hal/api-hal-rfid.c index 95e2fdc9..84d7619e 100644 --- a/firmware/targets/f5/api-hal/api-hal-rfid.c +++ b/firmware/targets/f5/api-hal/api-hal-rfid.c @@ -21,8 +21,8 @@ void api_hal_rfid_pins_emulate() { api_hal_ibutton_pin_low(); // pull pin to timer out - hal_gpio_init_alt( - &gpio_rfid_pull, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo, GpioAltFn1TIM1); + hal_gpio_init_ex( + &gpio_rfid_pull, GpioModeAltFunctionPushPull, GpioSpeedLow, GpioPullNo, GpioAltFn1TIM1); // pull rfid antenna from carrier side hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo); @@ -39,8 +39,12 @@ void api_hal_rfid_pins_read() { hal_gpio_write(&gpio_rfid_pull, false); // carrier pin to timer out - hal_gpio_init_alt( - &gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo, GpioAltFn1TIM1); + hal_gpio_init_ex( + &gpio_rfid_carrier_out, + GpioModeAltFunctionPushPull, + GpioSpeedLow, + GpioPullNo, + GpioAltFn1TIM1); // comparator in hal_gpio_init(&gpio_rfid_data_in, GpioModeAnalog, GpioSpeedLow, GpioPullNo);