From 6926cf8b7e73c16e22c66b62ec89be8b88b76e0a Mon Sep 17 00:00:00 2001 From: SG Date: Mon, 2 Aug 2021 08:11:18 +1000 Subject: [PATCH] [FL-1449] Indala reading and writing (#616) * Rfid: indala 40134 validation and decoding * Rfid: show indala info * Rfid: decoder to output comparator signal on gpio pins * Rfid: working indala 40134 decoder * HAL: added function to change rfid timer parameters on the fly * RFID: Indala reading, card detection, card verification * Rfid: indala writing --- .../lfrfid/helpers/decoder-gpio-out.cpp | 15 ++ .../lfrfid/helpers/decoder-gpio-out.h | 14 ++ .../lfrfid/helpers/decoder-indala.cpp | 190 +++++------------- applications/lfrfid/helpers/decoder-indala.h | 17 +- .../protocols/protocol-indala-40134.cpp | 116 ++++++++++- applications/lfrfid/helpers/rfid-reader.cpp | 153 +++++++++----- applications/lfrfid/helpers/rfid-reader.h | 26 ++- applications/lfrfid/helpers/rfid-worker.cpp | 65 +++--- applications/lfrfid/helpers/rfid-worker.h | 2 + applications/lfrfid/helpers/rfid-writer.cpp | 19 +- applications/lfrfid/helpers/rfid-writer.h | 1 + applications/lfrfid/lfrfid-cli.cpp | 2 +- .../scene/lfrfid-app-scene-read-success.cpp | 4 +- .../lfrfid/scene/lfrfid-app-scene-read.cpp | 8 +- .../targets/api-hal-include/api-hal-rfid.h | 7 + firmware/targets/f6/api-hal/api-hal-rfid.c | 6 + 16 files changed, 406 insertions(+), 239 deletions(-) create mode 100644 applications/lfrfid/helpers/decoder-gpio-out.cpp create mode 100644 applications/lfrfid/helpers/decoder-gpio-out.h diff --git a/applications/lfrfid/helpers/decoder-gpio-out.cpp b/applications/lfrfid/helpers/decoder-gpio-out.cpp new file mode 100644 index 00000000..50cec34d --- /dev/null +++ b/applications/lfrfid/helpers/decoder-gpio-out.cpp @@ -0,0 +1,15 @@ +#include "decoder-gpio-out.h" +#include +#include + +void DecoderGpioOut::process_front(bool polarity, uint32_t time) { + hal_gpio_write(&gpio_ext_pa7, polarity); +} + +DecoderGpioOut::DecoderGpioOut() { + hal_gpio_init_simple(&gpio_ext_pa7, GpioModeOutputPushPull); +} + +DecoderGpioOut::~DecoderGpioOut() { + hal_gpio_init_simple(&gpio_ext_pa7, GpioModeAnalog); +} diff --git a/applications/lfrfid/helpers/decoder-gpio-out.h b/applications/lfrfid/helpers/decoder-gpio-out.h new file mode 100644 index 00000000..087720df --- /dev/null +++ b/applications/lfrfid/helpers/decoder-gpio-out.h @@ -0,0 +1,14 @@ +#pragma once +#include +#include + +class DecoderGpioOut { +public: + void process_front(bool polarity, uint32_t time); + + DecoderGpioOut(); + ~DecoderGpioOut(); + +private: + void reset_state(); +}; diff --git a/applications/lfrfid/helpers/decoder-indala.cpp b/applications/lfrfid/helpers/decoder-indala.cpp index 9b82a176..2103a180 100644 --- a/applications/lfrfid/helpers/decoder-indala.cpp +++ b/applications/lfrfid/helpers/decoder-indala.cpp @@ -2,18 +2,24 @@ #include constexpr uint32_t clocks_in_us = 64; - -constexpr uint32_t min_time_us = 25 * clocks_in_us; -constexpr uint32_t mid_time_us = 45 * clocks_in_us; -constexpr uint32_t max_time_us = 90 * clocks_in_us; +constexpr uint32_t us_per_bit = 255; bool DecoderIndala::read(uint8_t* data, uint8_t data_size) { bool result = false; if(ready) { result = true; - printf("IND %02X %02X %02X\r\n", facility, (uint8_t)(number >> 8), (uint8_t)number); - ready = false; + if(cursed_data_valid) { + indala.decode( + reinterpret_cast(&cursed_raw_data), + sizeof(uint64_t), + data, + data_size); + } else { + indala.decode( + reinterpret_cast(&raw_data), sizeof(uint64_t), data, data_size); + } + reset_state(); } return result; @@ -22,149 +28,49 @@ bool DecoderIndala::read(uint8_t* data, uint8_t data_size) { void DecoderIndala::process_front(bool polarity, uint32_t time) { if(ready) return; - if(polarity == false) { - last_pulse_time = time; - } else { - last_pulse_time += time; - pulse_count++; + process_internal(polarity, time, &raw_data); + if(ready) return; - if(last_pulse_time > min_time_us && last_pulse_time < max_time_us) { - if(last_pulse_time > mid_time_us) { - bool last_data = !(readed_data & 1); - pulse_count = 0; - readed_data = (readed_data << 1) | last_data; - verify(); - } else if((pulse_count % 16) == 0) { - bool last_data = readed_data & 1; - pulse_count = 0; - readed_data = (readed_data << 1) | last_data; - verify(); + if(polarity) { + time = time + 110; + } else { + time = time - 110; + } + + process_internal(!polarity, time, &cursed_raw_data); + if(ready) { + cursed_data_valid = true; + } +} + +void DecoderIndala::process_internal(bool polarity, uint32_t time, uint64_t* data) { + time /= clocks_in_us; + time += (us_per_bit / 2); + + uint32_t bit_count = (time / us_per_bit); + + if(bit_count < 64) { + for(uint32_t i = 0; i < bit_count; i++) { + *data = (*data << 1) | polarity; + + if((*data >> 32) == 0xa0000000ULL) { + if(indala.can_be_decoded( + reinterpret_cast(data), sizeof(uint64_t))) { + ready = true; + break; + } } } } } DecoderIndala::DecoderIndala() { + reset_state(); } void DecoderIndala::reset_state() { -} - -void DecoderIndala::verify() { - // verify inverse - readed_data = ~readed_data; - verify_inner(); - - // verify normal - readed_data = ~readed_data; - verify_inner(); -} - -typedef union { - uint64_t raw; - struct __attribute__((packed)) { - uint8_t static0 : 3; - uint8_t checksum : 2; - uint8_t static1 : 2; - uint8_t y14 : 1; - - uint8_t x8 : 1; - uint8_t x1 : 1; - uint8_t y13 : 1; - uint8_t static2 : 1; - uint8_t y12 : 1; - uint8_t x6 : 1; - uint8_t y5 : 1; - uint8_t y8 : 1; - - uint8_t y15 : 1; - uint8_t x2 : 1; - uint8_t x5 : 1; - uint8_t x4 : 1; - uint8_t y9 : 1; - uint8_t y2 : 1; - uint8_t x3 : 1; - uint8_t y3 : 1; - - uint8_t y1 : 1; - uint8_t y16 : 1; - uint8_t y4 : 1; - uint8_t x7 : 1; - uint8_t p2 : 1; - uint8_t y11 : 1; - uint8_t y6 : 1; - uint8_t y7 : 1; - - uint8_t p1 : 1; - uint8_t y10 : 1; - uint32_t preamble : 30; - }; -} IndalaFormat; - -void DecoderIndala::verify_inner() { - IndalaFormat id; - id.raw = readed_data; - - // preamble - //if((data >> 34) != 0b000000000000000000000000000001) return; - if(id.preamble != 1) return; - - // static data bits - //if((data & 0b100001100111) != 0b101) return; - if(id.static2 != 0 && id.static1 != 0 && id.static0 != 0b101) return; - - // Indala checksum - uint8_t sum_to_check = id.y2 + id.y4 + id.y7 + id.y8 + id.y10 + id.y11 + id.y14 + id.y16; - - if(sum_to_check % 2 == 0) { - if(id.checksum != 0b10) return; - } else { - if(id.checksum != 0b01) return; - } - - // read facility number - facility = (id.x1 << 7) + (id.x2 << 6) + (id.x3 << 5) + (id.x4 << 4) + (id.x5 << 3) + - (id.x6 << 2) + (id.x7 << 1) + (id.x8 << 0); - - // read serial number - number = (id.y1 << 15) + (id.y2 << 14) + (id.y3 << 13) + (id.y4 << 12) + (id.y5 << 11) + - (id.y6 << 10) + (id.y7 << 9) + (id.y8 << 8) + (id.y9 << 7) + (id.y10 << 6) + - (id.y11 << 5) + (id.y12 << 4) + (id.y13 << 3) + (id.y14 << 2) + (id.y15 << 1) + - (id.y16 << 0); - - // Wiegand checksum left - sum_to_check = 0; - for(int8_t i = 0; i < 8; i--) { - if((facility >> i) & 1) { - sum_to_check += 1; - } - } - - for(int8_t i = 0; i < 4; i--) { - if((number >> i) & 1) { - sum_to_check += 1; - } - } - - if(id.p1) { - sum_to_check += 1; - } - - if((sum_to_check % 2) == 1) return; - - // Wiegand checksum right - sum_to_check = 0; - for(int8_t i = 0; i < 12; i--) { - if((number >> (i + 4)) & 1) { - sum_to_check += 1; - } - } - - if(id.p2) { - sum_to_check += 1; - } - - if((sum_to_check % 2) != 1) return; - - ready = true; -} + raw_data = 0; + cursed_raw_data = 0; + ready = false; + cursed_data_valid = false; +} \ No newline at end of file diff --git a/applications/lfrfid/helpers/decoder-indala.h b/applications/lfrfid/helpers/decoder-indala.h index fd3043d5..1bd0cf0f 100644 --- a/applications/lfrfid/helpers/decoder-indala.h +++ b/applications/lfrfid/helpers/decoder-indala.h @@ -2,27 +2,24 @@ #include #include #include +#include "protocols/protocol-indala-40134.h" class DecoderIndala { public: bool read(uint8_t* data, uint8_t data_size); void process_front(bool polarity, uint32_t time); + void process_internal(bool polarity, uint32_t time, uint64_t* data); + DecoderIndala(); private: void reset_state(); - void verify(); - void verify_inner(); - - uint32_t last_pulse_time = 0; - uint32_t pulse_count = 0; - uint32_t overall_pulse_count = 0; - - uint64_t readed_data = 0; + uint64_t raw_data; + uint64_t cursed_raw_data; std::atomic ready; - uint8_t facility = 0; - uint16_t number = 0; + std::atomic cursed_data_valid; + ProtocolIndala40134 indala; }; \ No newline at end of file diff --git a/applications/lfrfid/helpers/protocols/protocol-indala-40134.cpp b/applications/lfrfid/helpers/protocols/protocol-indala-40134.cpp index 5873e0bd..8aae62e7 100644 --- a/applications/lfrfid/helpers/protocols/protocol-indala-40134.cpp +++ b/applications/lfrfid/helpers/protocols/protocol-indala-40134.cpp @@ -12,6 +12,11 @@ static void set_bit(bool bit, uint8_t position, Indala40134CardData* card_data) } } +static bool get_bit(uint8_t position, const Indala40134CardData* card_data) { + position = (sizeof(Indala40134CardData) * 8) - 1 - position; + return (*card_data >> position) & 1; +} + uint8_t ProtocolIndala40134::get_encoded_data_size() { return sizeof(Indala40134CardData); } @@ -110,6 +115,46 @@ void ProtocolIndala40134::encode( memcpy(encoded_data, &card_data, get_encoded_data_size()); } +// factory code +static uint8_t get_fc(const Indala40134CardData* card_data) { + uint8_t fc = 0; + + fc = fc << 1 | get_bit(57, card_data); + fc = fc << 1 | get_bit(49, card_data); + fc = fc << 1 | get_bit(44, card_data); + fc = fc << 1 | get_bit(47, card_data); + fc = fc << 1 | get_bit(48, card_data); + fc = fc << 1 | get_bit(53, card_data); + fc = fc << 1 | get_bit(39, card_data); + fc = fc << 1 | get_bit(58, card_data); + + return fc; +} + +// card number +static uint16_t get_cn(const Indala40134CardData* card_data) { + uint16_t cn = 0; + + cn = cn << 1 | get_bit(42, card_data); + cn = cn << 1 | get_bit(45, card_data); + cn = cn << 1 | get_bit(43, card_data); + cn = cn << 1 | get_bit(40, card_data); + cn = cn << 1 | get_bit(52, card_data); + cn = cn << 1 | get_bit(36, card_data); + cn = cn << 1 | get_bit(35, card_data); + cn = cn << 1 | get_bit(51, card_data); + cn = cn << 1 | get_bit(46, card_data); + cn = cn << 1 | get_bit(33, card_data); + cn = cn << 1 | get_bit(37, card_data); + cn = cn << 1 | get_bit(54, card_data); + cn = cn << 1 | get_bit(56, card_data); + cn = cn << 1 | get_bit(59, card_data); + cn = cn << 1 | get_bit(50, card_data); + cn = cn << 1 | get_bit(41, card_data); + + return cn; +} + void ProtocolIndala40134::decode( const uint8_t* encoded_data, const uint8_t encoded_data_size, @@ -117,15 +162,76 @@ void ProtocolIndala40134::decode( 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); + + const Indala40134CardData* card_data = + reinterpret_cast(encoded_data); + + uint8_t fc = get_fc(card_data); + uint16_t card = get_cn(card_data); + + decoded_data[0] = fc; + decoded_data[1] = card >> 8; + decoded_data[2] = card; } 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; + bool can_be_decoded = false; + + const Indala40134CardData* card_data = + reinterpret_cast(encoded_data); + + do { + // preambula + if((*card_data >> 32) != 0xa0000000UL) break; + + // data + const uint32_t fc_and_card = get_fc(card_data) << 16 | get_cn(card_data); + + // checksum + const uint8_t checksum = get_bit(62, card_data) << 1 | get_bit(63, card_data); + uint8_t checksum_sum = 0; + checksum_sum += ((fc_and_card >> 14) & 1); + checksum_sum += ((fc_and_card >> 12) & 1); + checksum_sum += ((fc_and_card >> 9) & 1); + checksum_sum += ((fc_and_card >> 8) & 1); + checksum_sum += ((fc_and_card >> 6) & 1); + checksum_sum += ((fc_and_card >> 5) & 1); + checksum_sum += ((fc_and_card >> 2) & 1); + checksum_sum += ((fc_and_card >> 0) & 1); + checksum_sum = checksum_sum & 0b1; + + if(checksum_sum == 1 && checksum == 0b01) { + } else if(checksum_sum == 0 && checksum == 0b10) { + } else { + break; + } + + // wiegand parity bits + // even parity sum calculation (high 12 bits of data) + const bool even_parity = get_bit(34, card_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++; + } + } + if(even_parity_sum % 2 != even_parity) break; + + // odd parity sum calculation (low 12 bits of data) + const bool odd_parity = get_bit(38, card_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++; + } + } + if(odd_parity_sum % 2 != odd_parity) break; + + can_be_decoded = true; + } while(false); + + return can_be_decoded; } \ No newline at end of file diff --git a/applications/lfrfid/helpers/rfid-reader.cpp b/applications/lfrfid/helpers/rfid-reader.cpp index 12b37acf..dae887d0 100644 --- a/applications/lfrfid/helpers/rfid-reader.cpp +++ b/applications/lfrfid/helpers/rfid-reader.cpp @@ -17,19 +17,47 @@ struct RfidReaderAccessor { void RfidReader::decode(bool polarity) { uint32_t current_dwt_value = DWT->CYCCNT; + uint32_t period = current_dwt_value - last_dwt_value; + last_dwt_value = current_dwt_value; + //decoder_gpio_out.process_front(polarity, period); switch(type) { case Type::Normal: - decoder_em.process_front(polarity, current_dwt_value - last_dwt_value); - decoder_hid26.process_front(polarity, current_dwt_value - last_dwt_value); - //decoder_indala.process_front(polarity, current_dwt_value - last_dwt_value); - //decoder_analyzer.process_front(polarity, current_dwt_value - last_dwt_value); - - last_dwt_value = current_dwt_value; + decoder_em.process_front(polarity, period); + decoder_hid26.process_front(polarity, period); break; case Type::Indala: + decoder_em.process_front(polarity, period); + decoder_hid26.process_front(polarity, period); + decoder_indala.process_front(polarity, period); break; } + + detect_ticks++; +} + +bool RfidReader::switch_timer_elapsed() { + const uint32_t seconds_to_switch = osKernelGetTickFreq() * 2.0f; + return (osKernelGetTickCount() - switch_os_tick_last) > seconds_to_switch; +} + +void RfidReader::switch_timer_reset() { + switch_os_tick_last = osKernelGetTickCount(); +} + +void RfidReader::switch_mode() { + switch(type) { + case Type::Normal: + type = Type::Indala; + api_hal_rfid_change_read_config(62500.0f, 0.25f); + break; + case Type::Indala: + type = Type::Normal; + api_hal_rfid_change_read_config(125000.0f, 0.5f); + break; + } + + switch_timer_reset(); } static void comparator_trigger_callback(void* hcomp, void* comp_ctx) { @@ -45,47 +73,103 @@ static void comparator_trigger_callback(void* hcomp, void* comp_ctx) { RfidReader::RfidReader() { } -void RfidReader::start(Type _type) { - type = _type; +void RfidReader::start() { + type = Type::Normal; - start_gpio(); + api_hal_rfid_pins_read(); + api_hal_rfid_tim_read(125000, 0.5); + api_hal_rfid_tim_read_start(); + start_comparator(); + + switch_timer_reset(); + last_readed_count = 0; +} + +void RfidReader::start_forced(RfidReader::Type _type) { + type = _type; switch(type) { case Type::Normal: - start_timer(); + start(); break; case Type::Indala: - start_timer_indala(); + api_hal_rfid_pins_read(); + api_hal_rfid_tim_read(62500.0f, 0.25f); + api_hal_rfid_tim_read_start(); + start_comparator(); + + switch_timer_reset(); + last_readed_count = 0; break; } - - start_comparator(); } void RfidReader::stop() { - stop_gpio(); - stop_timer(); + api_hal_rfid_pins_reset(); + api_hal_rfid_tim_read_stop(); + api_hal_rfid_tim_reset(); stop_comparator(); } -bool RfidReader::read(LfrfidKeyType* type, uint8_t* data, uint8_t data_size) { +bool RfidReader::read(LfrfidKeyType* _type, uint8_t* data, uint8_t data_size) { bool result = false; + bool something_readed = false; + // reading if(decoder_em.read(data, data_size)) { - *type = LfrfidKeyType::KeyEM4100; - result = true; + *_type = LfrfidKeyType::KeyEM4100; + something_readed = true; } if(decoder_hid26.read(data, data_size)) { - *type = LfrfidKeyType::KeyH10301; - result = true; + *_type = LfrfidKeyType::KeyH10301; + something_readed = true; } - //decoder_indala.read(NULL, 0); - //decoder_analyzer.read(NULL, 0); + if(decoder_indala.read(data, data_size)) { + *_type = LfrfidKeyType::KeyI40134; + something_readed = true; + } + + // validation + if(something_readed) { + switch_timer_reset(); + + if(last_readed_type == *_type && memcmp(last_readed_data, data, data_size) == 0) { + last_readed_count = last_readed_count + 1; + + if(last_readed_count > 2) { + result = true; + } + } else { + last_readed_type = *_type; + memcpy(last_readed_data, data, data_size); + last_readed_count = 0; + } + } + + // mode switching + if(switch_timer_elapsed()) { + switch_mode(); + last_readed_count = 0; + } return result; } +bool RfidReader::detect() { + bool detected = false; + if(detect_ticks > 10) { + detected = true; + } + detect_ticks = 0; + + return detected; +} + +bool RfidReader::any_read() { + return last_readed_count > 0; +} + void RfidReader::start_comparator(void) { api_interrupt_add(comparator_trigger_callback, InterruptTypeComparatorTrigger, this); last_dwt_value = DWT->CYCCNT; @@ -93,7 +177,7 @@ void RfidReader::start_comparator(void) { hcomp1.Init.InputMinus = COMP_INPUT_MINUS_1_2VREFINT; hcomp1.Init.InputPlus = COMP_INPUT_PLUS_IO1; hcomp1.Init.OutputPol = COMP_OUTPUTPOL_NONINVERTED; - hcomp1.Init.Hysteresis = COMP_HYSTERESIS_LOW; + hcomp1.Init.Hysteresis = COMP_HYSTERESIS_HIGH; hcomp1.Init.BlankingSrce = COMP_BLANKINGSRC_NONE; hcomp1.Init.Mode = COMP_POWERMODE_MEDIUMSPEED; hcomp1.Init.WindowMode = COMP_WINDOWMODE_DISABLE; @@ -105,30 +189,7 @@ void RfidReader::start_comparator(void) { HAL_COMP_Start(&hcomp1); } -void RfidReader::start_timer(void) { - api_hal_rfid_tim_read(125000, 0.5); - api_hal_rfid_tim_read_start(); -} - -void RfidReader::start_timer_indala(void) { - api_hal_rfid_tim_read(62500, 0.25); - api_hal_rfid_tim_read_start(); -} - -void RfidReader::start_gpio(void) { - api_hal_rfid_pins_read(); -} - void RfidReader::stop_comparator(void) { HAL_COMP_Stop(&hcomp1); api_interrupt_remove(comparator_trigger_callback, InterruptTypeComparatorTrigger); -} - -void RfidReader::stop_timer(void) { - api_hal_rfid_tim_read_stop(); - api_hal_rfid_tim_reset(); -} - -void RfidReader::stop_gpio(void) { - api_hal_rfid_pins_reset(); } \ No newline at end of file diff --git a/applications/lfrfid/helpers/rfid-reader.h b/applications/lfrfid/helpers/rfid-reader.h index 6fc4ffd9..3e6acacd 100644 --- a/applications/lfrfid/helpers/rfid-reader.h +++ b/applications/lfrfid/helpers/rfid-reader.h @@ -1,5 +1,6 @@ #pragma once -#include "decoder-analyzer.h" +//#include "decoder-analyzer.h" +#include "decoder-gpio-out.h" #include "decoder-emmarine.h" #include "decoder-hid26.h" #include "decoder-indala.h" @@ -13,14 +14,19 @@ public: }; RfidReader(); - void start(Type type); + void start(); + void start_forced(RfidReader::Type type); void stop(); bool read(LfrfidKeyType* type, uint8_t* data, uint8_t data_size); + bool detect(); + bool any_read(); + private: friend struct RfidReaderAccessor; //DecoderAnalyzer decoder_analyzer; + //DecoderGpioOut decoder_gpio_out; DecoderEMMarine decoder_em; DecoderHID26 decoder_hid26; DecoderIndala decoder_indala; @@ -28,14 +34,20 @@ private: uint32_t last_dwt_value; void start_comparator(void); - void start_timer(void); - void start_timer_indala(void); - void start_gpio(void); void stop_comparator(void); - void stop_timer(void); - void stop_gpio(void); void decode(bool polarity); + uint32_t detect_ticks; + + uint32_t switch_os_tick_last; + bool switch_timer_elapsed(); + void switch_timer_reset(); + void switch_mode(); + + LfrfidKeyType last_readed_type; + uint8_t last_readed_data[LFRFID_KEY_SIZE]; + uint8_t last_readed_count; + Type type = Type::Normal; }; diff --git a/applications/lfrfid/helpers/rfid-worker.cpp b/applications/lfrfid/helpers/rfid-worker.cpp index 24dbbece..df39d312 100644 --- a/applications/lfrfid/helpers/rfid-worker.cpp +++ b/applications/lfrfid/helpers/rfid-worker.cpp @@ -7,7 +7,7 @@ RfidWorker::~RfidWorker() { } void RfidWorker::start_read() { - reader.start(RfidReader::Type::Normal); + reader.start(); } bool RfidWorker::read() { @@ -25,6 +25,14 @@ bool RfidWorker::read() { return result; } +bool RfidWorker::detect() { + return reader.detect(); +} + +bool RfidWorker::any_read() { + return reader.any_read(); +} + void RfidWorker::stop_read() { reader.stop(); } @@ -36,7 +44,7 @@ void RfidWorker::start_write() { write_sequence->do_every_tick(1, std::bind(&RfidWorker::sq_write, this)); write_sequence->do_after_tick(2, std::bind(&RfidWorker::sq_write_start_validate, this)); - write_sequence->do_after_tick(15, std::bind(&RfidWorker::sq_write_validate, this)); + write_sequence->do_every_tick(30, std::bind(&RfidWorker::sq_write_validate, this)); write_sequence->do_every_tick(1, std::bind(&RfidWorker::sq_write_stop_validate, this)); } @@ -59,26 +67,37 @@ void RfidWorker::stop_emulate() { } void RfidWorker::sq_write() { - // TODO expand this - switch(key.get_type()) { - case LfrfidKeyType::KeyEM4100: - writer.start(); - writer.write_em(key.get_data()); - writer.stop(); - break; - case LfrfidKeyType::KeyH10301: - writer.start(); - writer.write_hid(key.get_data()); - writer.stop(); - break; - - default: - break; + for(size_t i = 0; i < 5; i++) { + switch(key.get_type()) { + case LfrfidKeyType::KeyEM4100: + writer.start(); + writer.write_em(key.get_data()); + writer.stop(); + break; + case LfrfidKeyType::KeyH10301: + writer.start(); + writer.write_hid(key.get_data()); + writer.stop(); + break; + case LfrfidKeyType::KeyI40134: + writer.start(); + writer.write_indala(key.get_data()); + writer.stop(); + break; + } } } void RfidWorker::sq_write_start_validate() { - reader.start(RfidReader::Type::Normal); + switch(key.get_type()) { + case LfrfidKeyType::KeyEM4100: + case LfrfidKeyType::KeyH10301: + reader.start_forced(RfidReader::Type::Normal); + break; + case LfrfidKeyType::KeyI40134: + reader.start_forced(RfidReader::Type::Indala); + break; + } } void RfidWorker::sq_write_validate() { @@ -88,7 +107,11 @@ void RfidWorker::sq_write_validate() { bool result = reader.read(&type, data, data_size); - if(result) { + if(result && (write_result != WriteResult::Ok)) { + if(validate_counts > (5 * 60)) { + write_result = WriteResult::NotWritable; + } + if(type == key.get_type()) { if(memcmp(data, key.get_data(), key.get_type_data_count()) == 0) { write_result = WriteResult::Ok; @@ -99,10 +122,6 @@ void RfidWorker::sq_write_validate() { } else { validate_counts++; } - - if(validate_counts > 5) { - write_result = WriteResult::NotWritable; - } }; } diff --git a/applications/lfrfid/helpers/rfid-worker.h b/applications/lfrfid/helpers/rfid-worker.h index 4254b90d..c2533a23 100644 --- a/applications/lfrfid/helpers/rfid-worker.h +++ b/applications/lfrfid/helpers/rfid-worker.h @@ -13,6 +13,8 @@ public: void start_read(); bool read(); + bool detect(); + bool any_read(); void stop_read(); enum class WriteResult : uint8_t { diff --git a/applications/lfrfid/helpers/rfid-writer.cpp b/applications/lfrfid/helpers/rfid-writer.cpp index f9a6ad68..9df81d53 100644 --- a/applications/lfrfid/helpers/rfid-writer.cpp +++ b/applications/lfrfid/helpers/rfid-writer.cpp @@ -2,6 +2,7 @@ #include #include "protocols/protocol-emmarin.h" #include "protocols/protocol-hid-h10301.h" +#include "protocols/protocol-indala-40134.h" extern COMP_HandleTypeDef hcomp1; @@ -115,7 +116,7 @@ void RfidWriter::write_em(const 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)); - const uint32_t em_config_block_data = 0b01100000000101001000000001000000; + const uint32_t em_config_block_data = 0b00000000000101001000000001000000; __disable_irq(); write_block(0, 0, false, em_config_block_data); @@ -140,3 +141,19 @@ void RfidWriter::write_hid(const uint8_t hid_data[3]) { write_reset(); __enable_irq(); } + +void RfidWriter::write_indala(const uint8_t indala_data[3]) { + ProtocolIndala40134 indala_card; + uint32_t card_data[2]; + indala_card.encode( + indala_data, 3, reinterpret_cast(&card_data), sizeof(card_data) * 2); + + const uint32_t indala_config_block_data = 0b00000000000010000001000001000000; + + __disable_irq(); + write_block(0, 0, false, indala_config_block_data); + write_block(0, 1, false, card_data[0]); + write_block(0, 2, false, card_data[1]); + write_reset(); + __enable_irq(); +} diff --git a/applications/lfrfid/helpers/rfid-writer.h b/applications/lfrfid/helpers/rfid-writer.h index cfbc1c5d..3ec3c1dd 100644 --- a/applications/lfrfid/helpers/rfid-writer.h +++ b/applications/lfrfid/helpers/rfid-writer.h @@ -9,6 +9,7 @@ public: void stop(); void write_em(const uint8_t em_data[5]); void write_hid(const uint8_t hid_data[3]); + void write_indala(const uint8_t indala_data[3]); private: void write_gap(uint32_t gap_time); diff --git a/applications/lfrfid/lfrfid-cli.cpp b/applications/lfrfid/lfrfid-cli.cpp index 1a047fcb..d0ae56da 100644 --- a/applications/lfrfid/lfrfid-cli.cpp +++ b/applications/lfrfid/lfrfid-cli.cpp @@ -46,7 +46,7 @@ bool lfrfid_cli_get_key_type(string_t data, LfrfidKeyType* type) { void lfrfid_cli_read(Cli* cli) { RfidReader reader; - reader.start(RfidReader::Type::Normal); + reader.start(); static const uint8_t data_size = LFRFID_KEY_SIZE; uint8_t data[data_size] = {0}; diff --git a/applications/lfrfid/scene/lfrfid-app-scene-read-success.cpp b/applications/lfrfid/scene/lfrfid-app-scene-read-success.cpp index 088d6ede..7d0e8638 100644 --- a/applications/lfrfid/scene/lfrfid-app-scene-read-success.cpp +++ b/applications/lfrfid/scene/lfrfid-app-scene-read-success.cpp @@ -55,6 +55,7 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool need_restore) { string_get_cstr(string[2]), 68, 47, AlignLeft, AlignBottom, FontSecondary); break; case LfrfidKeyType::KeyH10301: + case LfrfidKeyType::KeyI40134: line_1_text->set_text("HEX:", 65, 23, AlignRight, AlignBottom, FontSecondary); line_2_text->set_text("FC:", 65, 35, AlignRight, AlignBottom, FontSecondary); line_3_text->set_text("Card:", 65, 47, AlignRight, AlignBottom, FontSecondary); @@ -73,9 +74,6 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool need_restore) { line_3_value->set_text( string_get_cstr(string[2]), 68, 47, AlignLeft, AlignBottom, FontSecondary); break; - case LfrfidKeyType::KeyI40134: - //TODO implement when we can read Indala - break; } app->view_controller.switch_to(); diff --git a/applications/lfrfid/scene/lfrfid-app-scene-read.cpp b/applications/lfrfid/scene/lfrfid-app-scene-read.cpp index 82ef42bc..15875dcd 100644 --- a/applications/lfrfid/scene/lfrfid-app-scene-read.cpp +++ b/applications/lfrfid/scene/lfrfid-app-scene-read.cpp @@ -18,7 +18,13 @@ bool LfRfidAppSceneRead::on_event(LfRfidApp* app, LfRfidApp::Event* event) { notification_message(app->notification, &sequence_success); app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadSuccess); } else { - notification_message(app->notification, &sequence_blink_red_10); + if(app->worker.any_read()) { + notification_message(app->notification, &sequence_blink_green_10); + } else if(app->worker.detect()) { + notification_message(app->notification, &sequence_blink_blue_10); + } else { + notification_message(app->notification, &sequence_blink_red_10); + } } } diff --git a/firmware/targets/api-hal-include/api-hal-rfid.h b/firmware/targets/api-hal-include/api-hal-rfid.h index aad36a82..7f2870b0 100644 --- a/firmware/targets/api-hal-include/api-hal-rfid.h +++ b/firmware/targets/api-hal-include/api-hal-rfid.h @@ -105,6 +105,13 @@ void api_hal_rfid_set_read_period(uint32_t period); */ void api_hal_rfid_set_read_pulse(uint32_t pulse); +/** + * Сhanges the configuration of the RFID timer "on a fly" + * @param freq new frequency + * @param duty_cycle new duty cycle + */ +void api_hal_rfid_change_read_config(float freq, float duty_cycle); + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/firmware/targets/f6/api-hal/api-hal-rfid.c b/firmware/targets/f6/api-hal/api-hal-rfid.c index 2d823cd5..be8e3c5f 100644 --- a/firmware/targets/f6/api-hal/api-hal-rfid.c +++ b/firmware/targets/f6/api-hal/api-hal-rfid.c @@ -269,4 +269,10 @@ void api_hal_rfid_set_read_pulse(uint32_t pulse) { furi_check(0); break; } +} + +void api_hal_rfid_change_read_config(float freq, float duty_cycle) { + uint32_t period = (uint32_t)((SystemCoreClock) / freq) - 1; + api_hal_rfid_set_read_period(period); + api_hal_rfid_set_read_pulse(period * duty_cycle); } \ No newline at end of file