mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-23 13:03:13 +00:00
[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
This commit is contained in:
parent
fb80f9537f
commit
6926cf8b7e
16 changed files with 406 additions and 239 deletions
15
applications/lfrfid/helpers/decoder-gpio-out.cpp
Normal file
15
applications/lfrfid/helpers/decoder-gpio-out.cpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include "decoder-gpio-out.h"
|
||||
#include <furi.h>
|
||||
#include <api-hal.h>
|
||||
|
||||
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);
|
||||
}
|
14
applications/lfrfid/helpers/decoder-gpio-out.h
Normal file
14
applications/lfrfid/helpers/decoder-gpio-out.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <atomic>
|
||||
|
||||
class DecoderGpioOut {
|
||||
public:
|
||||
void process_front(bool polarity, uint32_t time);
|
||||
|
||||
DecoderGpioOut();
|
||||
~DecoderGpioOut();
|
||||
|
||||
private:
|
||||
void reset_state();
|
||||
};
|
|
@ -2,18 +2,24 @@
|
|||
#include <api-hal.h>
|
||||
|
||||
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<const uint8_t*>(&cursed_raw_data),
|
||||
sizeof(uint64_t),
|
||||
data,
|
||||
data_size);
|
||||
} else {
|
||||
indala.decode(
|
||||
reinterpret_cast<const uint8_t*>(&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<const uint8_t*>(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;
|
||||
}
|
|
@ -2,27 +2,24 @@
|
|||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <atomic>
|
||||
#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<bool> ready;
|
||||
uint8_t facility = 0;
|
||||
uint16_t number = 0;
|
||||
std::atomic<bool> cursed_data_valid;
|
||||
ProtocolIndala40134 indala;
|
||||
};
|
|
@ -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<const Indala40134CardData*>(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<const Indala40134CardData*>(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;
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ public:
|
|||
|
||||
void start_read();
|
||||
bool read();
|
||||
bool detect();
|
||||
bool any_read();
|
||||
void stop_read();
|
||||
|
||||
enum class WriteResult : uint8_t {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <api-hal.h>
|
||||
#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<uint8_t*>(&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<uint8_t*>(&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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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<ContainerVM>();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
Loading…
Reference in a new issue