Low frequency RFID app [Read stage] (#385)
* App Lfrfid: init * HAL-resources: add external gpios * HAL-pwm: fix frequency calculation * App LFRFID: generic manchester decoder * App LFRFID: em-marine decoder * App iButton: fix dwt timing acquire * App LFRFID: rfid reader * App LFRFID: temporary read keys on read scene * App LFRFID: remove atomic bool init. * App LFRFID: add *.c to build * App LFRFID: unstable HID decoder * App LFRFID: HID-26 reading * HAL OS: disable sleep * App LFRFID: HID-26 reader: remove debug * App LFRFID: static data decoder-analyzer * App LFRFID: very raw Indala decoder * App LFRFID: multiprotocol reader * App LFRFID: more reliable HID decoder * App LFRFID: syntax fix * App LFRFID: simple read scene * Gui: force redraw on screen stream connect * HAL-OS: allow sleep * App LFRFID: notify api, tune view, tune scene * App LFRFID: simple rfid emulator * App LFRFID: more scenes, more reliable EM decoder. * App LFRFID: format fix * App LFRFID: warning fix * Api-hal-resources: add rfid pins, rename external pins * App LFRFID: remove unused emulator * App LFRFID: use new gpio hal api * App accessor: use new ext gpio name * App LFRFID: remove unused emulator * App LFRFID: remove debug gpio * Api-hal-resources: alternate functions init * Api-hal-rfid: new api * Api-hal-ibutton: new api * Api-hal: new headers * App LFRFID: use new api in reader subroutines * App LFRFID: use new api in emulator subroutines * App LFRFID: remove old app * App LFRFID, App iButton: fix memleak * Api-hal-rfid: comments * App LFRFID: pulse joiner helper, it combines pulses of different polarity into one pulse suitable for a timer * App LFRFID: pulse joiner, now can accept only ne pulse * App LFRFID: pulse joiner, fixes * App LFRFID: EM encoder and emulation * App LFRFID: format fixes * App LFRFID: emmarine encoder cleanup * App LFRFID: HID Encoder blank * App LFRFID: Indala Encoder blank
This commit is contained in:
parent
dd9bd224be
commit
46bc515c6a
@ -40,11 +40,11 @@ void input_isr(void* _pin, void* _ctx) {
|
||||
uint32_t pin = (uint32_t)_pin;
|
||||
WIEGAND* _this = static_cast<WIEGAND*>(_ctx);
|
||||
|
||||
if(pin == ext_pa6_gpio.pin) {
|
||||
if(pin == gpio_ext_pa6.pin) {
|
||||
_this->ReadD0();
|
||||
}
|
||||
|
||||
if(pin == ext_pa7_gpio.pin) {
|
||||
if(pin == gpio_ext_pa7.pin) {
|
||||
_this->ReadD1();
|
||||
}
|
||||
}
|
||||
@ -57,8 +57,8 @@ void WIEGAND::begin() {
|
||||
_wiegandType = 0;
|
||||
_bitCount = 0;
|
||||
|
||||
const GpioPin* pinD0 = &ext_pa6_gpio;
|
||||
const GpioPin* pinD1 = &ext_pa7_gpio;
|
||||
const GpioPin* pinD0 = &gpio_ext_pa6;
|
||||
const GpioPin* pinD1 = &gpio_ext_pa7;
|
||||
|
||||
hal_gpio_init(pinD0, GpioModeInterruptFall, GpioPullNo, GpioSpeedLow); // Set D0 pin as input
|
||||
hal_gpio_init(pinD1, GpioModeInterruptFall, GpioPullNo, GpioSpeedLow); // Set D1 pin as input
|
||||
|
@ -13,7 +13,7 @@ int32_t gui_task(void* p);
|
||||
int32_t backlight_control(void* p);
|
||||
int32_t irda(void* p);
|
||||
int32_t app_loader(void* p);
|
||||
int32_t lf_rfid_workaround(void* p);
|
||||
int32_t app_lfrfid(void* p);
|
||||
int32_t nfc_task(void* p);
|
||||
int32_t dolphin_task(void* p);
|
||||
int32_t power_task(void* p);
|
||||
@ -82,10 +82,7 @@ const FlipperApplication FLIPPER_SERVICES[] = {
|
||||
#endif
|
||||
|
||||
#ifdef SRV_LF_RFID
|
||||
{.app = lf_rfid_workaround,
|
||||
.name = "lf rfid workaround",
|
||||
.stack_size = 1024,
|
||||
.icon = A_Plugins_14},
|
||||
{.app = app_lfrfid, .name = "125 kHz RFID", .stack_size = 1024, .icon = A_Plugins_14},
|
||||
#endif
|
||||
|
||||
#ifdef SRV_IRDA
|
||||
@ -158,7 +155,7 @@ const FlipperApplication FLIPPER_APPS[] = {
|
||||
#endif
|
||||
|
||||
#ifdef APP_LF_RFID
|
||||
{.app = lf_rfid_workaround, .name = "125 kHz RFID", .stack_size = 1024, .icon = A_125khz_14},
|
||||
{.app = app_lfrfid, .name = "125 kHz RFID", .stack_size = 1024, .icon = A_125khz_14},
|
||||
#endif
|
||||
|
||||
#ifdef APP_IRDA
|
||||
|
@ -218,6 +218,7 @@ void gui_cli_screen_stream(string_t args, void* context) {
|
||||
Gui* gui = context;
|
||||
gui_set_framebuffer_callback_context(gui, gui);
|
||||
gui_set_framebuffer_callback(gui, gui_cli_screen_stream_callback);
|
||||
gui_redraw(gui);
|
||||
cli_getc(gui->cli);
|
||||
gui_set_framebuffer_callback(gui, NULL);
|
||||
gui_set_framebuffer_callback_context(gui, NULL);
|
||||
|
@ -140,11 +140,10 @@ void KeyReader::comparator_trigger_callback(void* hcomp, void* comp_ctx) {
|
||||
KeyReader* _this = static_cast<KeyReader*>(comp_ctx);
|
||||
|
||||
if(hcomp == &hcomp1) {
|
||||
_this->cyfral_decoder.process_front(
|
||||
hal_gpio_get_rfid_in_level(), DWT->CYCCNT - last_dwt_value);
|
||||
uint32_t current_dwt_value = DWT->CYCCNT;
|
||||
|
||||
_this->metakom_decoder.process_front(
|
||||
hal_gpio_get_rfid_in_level(), DWT->CYCCNT - last_dwt_value);
|
||||
_this->cyfral_decoder.process_front(hal_gpio_get_rfid_in_level(), current_dwt_value);
|
||||
_this->metakom_decoder.process_front(hal_gpio_get_rfid_in_level(), current_dwt_value);
|
||||
|
||||
last_dwt_value = DWT->CYCCNT;
|
||||
}
|
||||
|
@ -197,6 +197,12 @@ iButtonApp::~iButtonApp() {
|
||||
cli_delete_command(cli, "tm");
|
||||
furi_record_close("cli");
|
||||
osMessageQueueDelete(cli_event_result);
|
||||
|
||||
for(std::map<Scene, iButtonScene*>::iterator it = scenes.begin(); it != scenes.end(); ++it) {
|
||||
delete it->second;
|
||||
scenes.erase(it);
|
||||
}
|
||||
|
||||
api_hal_power_insomnia_exit();
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ public:
|
||||
virtual void on_enter(iButtonApp* app) = 0;
|
||||
virtual bool on_event(iButtonApp* app, iButtonEvent* event) = 0;
|
||||
virtual void on_exit(iButtonApp* app) = 0;
|
||||
virtual ~iButtonScene(){};
|
||||
|
||||
private:
|
||||
};
|
||||
|
48
applications/lf-rfid/helpers/decoder-analyzer.cpp
Normal file
48
applications/lf-rfid/helpers/decoder-analyzer.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
#include "decoder-analyzer.h"
|
||||
#include <furi.h>
|
||||
#include <api-hal.h>
|
||||
|
||||
bool DecoderAnalyzer::read(uint8_t* _data, uint8_t _data_size) {
|
||||
bool result = false;
|
||||
|
||||
if(ready) {
|
||||
result = true;
|
||||
|
||||
for(size_t i = 0; i < data_size; i++) {
|
||||
printf("%lu ", data[i]);
|
||||
if((i + 1) % 8 == 0) printf("\r\n");
|
||||
}
|
||||
printf("\r\n--------\r\n");
|
||||
|
||||
ready = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void DecoderAnalyzer::process_front(bool polarity, uint32_t time) {
|
||||
if(ready) return;
|
||||
|
||||
data[data_index] = time;
|
||||
|
||||
if(data_index < data_size) {
|
||||
data_index++;
|
||||
} else {
|
||||
data_index = 0;
|
||||
ready = true;
|
||||
}
|
||||
}
|
||||
|
||||
DecoderAnalyzer::DecoderAnalyzer() {
|
||||
data = reinterpret_cast<uint32_t*>(calloc(data_size, sizeof(uint32_t)));
|
||||
furi_check(data);
|
||||
data_index = 0;
|
||||
ready = false;
|
||||
}
|
||||
|
||||
DecoderAnalyzer::~DecoderAnalyzer() {
|
||||
free(data);
|
||||
}
|
||||
|
||||
void DecoderAnalyzer::reset_state() {
|
||||
}
|
21
applications/lf-rfid/helpers/decoder-analyzer.h
Normal file
21
applications/lf-rfid/helpers/decoder-analyzer.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <atomic>
|
||||
|
||||
class DecoderAnalyzer {
|
||||
public:
|
||||
bool read(uint8_t* data, uint8_t data_size);
|
||||
void process_front(bool polarity, uint32_t time);
|
||||
|
||||
DecoderAnalyzer();
|
||||
~DecoderAnalyzer();
|
||||
|
||||
private:
|
||||
void reset_state();
|
||||
|
||||
std::atomic<bool> ready;
|
||||
|
||||
static const uint32_t data_size = 2048;
|
||||
uint32_t data_index = 0;
|
||||
uint32_t* data;
|
||||
};
|
172
applications/lf-rfid/helpers/decoder-emmarine.cpp
Normal file
172
applications/lf-rfid/helpers/decoder-emmarine.cpp
Normal file
@ -0,0 +1,172 @@
|
||||
#include "emmarine.h"
|
||||
#include "decoder-emmarine.h"
|
||||
#include <furi.h>
|
||||
#include <api-hal.h>
|
||||
|
||||
constexpr uint32_t clocks_in_us = 64;
|
||||
constexpr uint32_t short_time = 255 * clocks_in_us;
|
||||
constexpr uint32_t long_time = 510 * clocks_in_us;
|
||||
constexpr uint32_t jitter_time = 100 * clocks_in_us;
|
||||
|
||||
constexpr uint32_t short_time_low = short_time - jitter_time;
|
||||
constexpr uint32_t short_time_high = short_time + jitter_time;
|
||||
constexpr uint32_t long_time_low = long_time - jitter_time;
|
||||
constexpr uint32_t long_time_high = long_time + jitter_time;
|
||||
|
||||
void DecoderEMMarine::reset_state() {
|
||||
ready = false;
|
||||
readed_data = 0;
|
||||
manchester_advance(
|
||||
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);
|
||||
ready = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void DecoderEMMarine::process_front(bool polarity, uint32_t time) {
|
||||
if(ready) return;
|
||||
if(time < short_time_low) return;
|
||||
|
||||
ManchesterEvent event = ManchesterEventReset;
|
||||
|
||||
if(time > short_time_low && time < short_time_high) {
|
||||
if(polarity) {
|
||||
event = ManchesterEventShortHigh;
|
||||
} else {
|
||||
event = ManchesterEventShortLow;
|
||||
}
|
||||
} else if(time > long_time_low && time < long_time_high) {
|
||||
if(polarity) {
|
||||
event = ManchesterEventLongHigh;
|
||||
} else {
|
||||
event = ManchesterEventLongLow;
|
||||
}
|
||||
}
|
||||
|
||||
if(event != ManchesterEventReset) {
|
||||
bool data;
|
||||
bool data_ok =
|
||||
manchester_advance(manchester_saved_state, event, &manchester_saved_state, &data);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DecoderEMMarine::DecoderEMMarine() {
|
||||
reset_state();
|
||||
}
|
20
applications/lf-rfid/helpers/decoder-emmarine.h
Normal file
20
applications/lf-rfid/helpers/decoder-emmarine.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <atomic>
|
||||
#include "manchester-decoder.h"
|
||||
|
||||
class DecoderEMMarine {
|
||||
public:
|
||||
bool read(uint8_t* data, uint8_t data_size);
|
||||
void process_front(bool polarity, uint32_t time);
|
||||
|
||||
DecoderEMMarine();
|
||||
|
||||
private:
|
||||
void reset_state();
|
||||
|
||||
uint64_t readed_data = 0;
|
||||
std::atomic<bool> ready;
|
||||
|
||||
ManchesterState manchester_saved_state;
|
||||
};
|
185
applications/lf-rfid/helpers/decoder-hid26.cpp
Normal file
185
applications/lf-rfid/helpers/decoder-hid26.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
#include "decoder-hid26.h"
|
||||
#include <api-hal.h>
|
||||
|
||||
constexpr uint32_t clocks_in_us = 64;
|
||||
|
||||
constexpr uint32_t jitter_time_us = 20;
|
||||
constexpr uint32_t min_time_us = 64;
|
||||
constexpr uint32_t max_time_us = 80;
|
||||
|
||||
constexpr uint32_t min_time = (min_time_us - jitter_time_us) * clocks_in_us;
|
||||
constexpr uint32_t mid_time = ((max_time_us - min_time_us) / 2 + min_time_us) * clocks_in_us;
|
||||
constexpr uint32_t max_time = (max_time_us + jitter_time_us) * clocks_in_us;
|
||||
|
||||
bool DecoderHID26::read(uint8_t* data, uint8_t data_size) {
|
||||
bool result = false;
|
||||
furi_assert(data_size >= 3);
|
||||
|
||||
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);
|
||||
ready = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void DecoderHID26::process_front(bool polarity, uint32_t time) {
|
||||
if(ready) return;
|
||||
|
||||
if(polarity == true) {
|
||||
last_pulse_time = time;
|
||||
} else {
|
||||
last_pulse_time += time;
|
||||
|
||||
if(last_pulse_time > min_time && last_pulse_time < max_time) {
|
||||
bool pulse;
|
||||
|
||||
if(last_pulse_time < mid_time) {
|
||||
// 6 pulses
|
||||
pulse = false;
|
||||
} else {
|
||||
// 5 pulses
|
||||
pulse = true;
|
||||
}
|
||||
|
||||
if(last_pulse == pulse) {
|
||||
pulse_count++;
|
||||
|
||||
if(pulse) {
|
||||
if(pulse_count > 4) {
|
||||
pulse_count = 0;
|
||||
store_data(1);
|
||||
}
|
||||
} else {
|
||||
if(pulse_count > 5) {
|
||||
pulse_count = 0;
|
||||
store_data(0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(last_pulse) {
|
||||
if(pulse_count > 2) {
|
||||
store_data(1);
|
||||
}
|
||||
} else {
|
||||
if(pulse_count > 3) {
|
||||
store_data(0);
|
||||
}
|
||||
}
|
||||
|
||||
pulse_count = 0;
|
||||
last_pulse = pulse;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DecoderHID26::DecoderHID26() {
|
||||
reset_state();
|
||||
}
|
||||
|
||||
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<uint8_t*>(stored_data) + 3) != 0x1D) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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() {
|
||||
last_pulse = false;
|
||||
pulse_count = 0;
|
||||
ready = false;
|
||||
last_pulse_time = 0;
|
||||
}
|
26
applications/lf-rfid/helpers/decoder-hid26.h
Normal file
26
applications/lf-rfid/helpers/decoder-hid26.h
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <atomic>
|
||||
|
||||
class DecoderHID26 {
|
||||
public:
|
||||
bool read(uint8_t* data, uint8_t data_size);
|
||||
void process_front(bool polarity, uint32_t time);
|
||||
DecoderHID26();
|
||||
|
||||
private:
|
||||
uint32_t last_pulse_time = 0;
|
||||
bool last_pulse;
|
||||
uint8_t pulse_count;
|
||||
|
||||
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<bool> ready;
|
||||
|
||||
void reset_state();
|
||||
};
|
170
applications/lf-rfid/helpers/decoder-indala.cpp
Normal file
170
applications/lf-rfid/helpers/decoder-indala.cpp
Normal file
@ -0,0 +1,170 @@
|
||||
#include "decoder-indala.h"
|
||||
#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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
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++;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DecoderIndala::DecoderIndala() {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
28
applications/lf-rfid/helpers/decoder-indala.h
Normal file
28
applications/lf-rfid/helpers/decoder-indala.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <atomic>
|
||||
|
||||
class DecoderIndala {
|
||||
public:
|
||||
bool read(uint8_t* data, uint8_t data_size);
|
||||
void process_front(bool polarity, uint32_t time);
|
||||
|
||||
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;
|
||||
|
||||
std::atomic<bool> ready;
|
||||
uint8_t facility = 0;
|
||||
uint16_t number = 0;
|
||||
};
|
15
applications/lf-rfid/helpers/emmarine.h
Normal file
15
applications/lf-rfid/helpers/emmarine.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#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_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)
|
58
applications/lf-rfid/helpers/encoder-emmarine.cpp
Normal file
58
applications/lf-rfid/helpers/encoder-emmarine.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
#include "encoder-emmarine.h"
|
||||
#include <furi.h>
|
||||
|
||||
void EncoderEM::init(const uint8_t* data, const uint8_t data_size) {
|
||||
furi_check(data_size == 5);
|
||||
|
||||
// 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
|
||||
void EncoderEM::get_next(bool* polarity, uint16_t* period, uint16_t* pulse) {
|
||||
*period = clocks_per_bit;
|
||||
*pulse = clocks_per_bit / 2;
|
||||
*polarity = (card_data >> (63 - card_data_index)) & 1;
|
||||
|
||||
card_data_index++;
|
||||
if(card_data_index >= 64) {
|
||||
card_data_index = 0;
|
||||
}
|
||||
}
|
23
applications/lf-rfid/helpers/encoder-emmarine.h
Normal file
23
applications/lf-rfid/helpers/encoder-emmarine.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include "encoder-generic.h"
|
||||
|
||||
class EncoderEM : public EncoderGeneric {
|
||||
public:
|
||||
/**
|
||||
* @brief init data to emulate
|
||||
*
|
||||
* @param data 1 byte FC, next 4 byte SN
|
||||
* @param data_size must be 5
|
||||
*/
|
||||
void init(const uint8_t* data, const uint8_t data_size) final;
|
||||
|
||||
void get_next(bool* polarity, uint16_t* period, uint16_t* pulse) final;
|
||||
|
||||
private:
|
||||
// clock pulses per bit
|
||||
static const uint8_t clocks_per_bit = 64;
|
||||
|
||||
uint64_t card_data;
|
||||
uint8_t card_data_index;
|
||||
void write_nibble(bool low_nibble, uint8_t data);
|
||||
};
|
27
applications/lf-rfid/helpers/encoder-generic.h
Normal file
27
applications/lf-rfid/helpers/encoder-generic.h
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
class EncoderGeneric {
|
||||
public:
|
||||
/**
|
||||
* @brief init encoder
|
||||
*
|
||||
* @param data data array
|
||||
* @param data_size data array size
|
||||
*/
|
||||
virtual void init(const uint8_t* data, const uint8_t data_size) = 0;
|
||||
|
||||
/**
|
||||
* @brief Get the next timer pulse
|
||||
*
|
||||
* @param polarity pulse polarity true = high2low, false = low2high
|
||||
* @param period overall period time in timer clicks
|
||||
* @param pulse pulse time in timer clicks
|
||||
*/
|
||||
virtual void get_next(bool* polarity, uint16_t* period, uint16_t* pulse) = 0;
|
||||
|
||||
virtual ~EncoderGeneric(){};
|
||||
|
||||
private:
|
||||
};
|
13
applications/lf-rfid/helpers/encoder-hid.cpp
Normal file
13
applications/lf-rfid/helpers/encoder-hid.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include "encoder-hid.h"
|
||||
#include <furi.h>
|
||||
|
||||
void EncoderHID::init(const uint8_t* data, const uint8_t data_size) {
|
||||
card_data = 0b1010000000000000000000000000000010011101111110011001001001010010;
|
||||
card_data_index = 0;
|
||||
}
|
||||
|
||||
void EncoderHID::get_next(bool* polarity, uint16_t* period, uint16_t* pulse) {
|
||||
*period = 100;
|
||||
*pulse = 50;
|
||||
*polarity = true;
|
||||
}
|
19
applications/lf-rfid/helpers/encoder-hid.h
Normal file
19
applications/lf-rfid/helpers/encoder-hid.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "encoder-generic.h"
|
||||
|
||||
class EncoderHID : public EncoderGeneric {
|
||||
public:
|
||||
/**
|
||||
* @brief init data to emulate
|
||||
*
|
||||
* @param data 1 byte FC, next 2 byte SN
|
||||
* @param data_size must be 3
|
||||
*/
|
||||
void init(const uint8_t* data, const uint8_t data_size) final;
|
||||
|
||||
void get_next(bool* polarity, uint16_t* period, uint16_t* pulse) final;
|
||||
|
||||
private:
|
||||
uint64_t card_data;
|
||||
uint8_t card_data_index;
|
||||
};
|
27
applications/lf-rfid/helpers/encoder-indala.cpp
Normal file
27
applications/lf-rfid/helpers/encoder-indala.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include "encoder-indala.h"
|
||||
#include <furi.h>
|
||||
|
||||
void EncoderIndala::init(const uint8_t* data, const uint8_t data_size) {
|
||||
card_data = 0b1010000000000000000000000000000010011101111110011001001001010010;
|
||||
last_polarity = card_data & 1;
|
||||
card_data_index = 0;
|
||||
}
|
||||
|
||||
void EncoderIndala::get_next(bool* polarity, uint16_t* period, uint16_t* pulse) {
|
||||
bool new_bit = (card_data >> (63 - card_data_index)) & 1;
|
||||
|
||||
*period = 2;
|
||||
*pulse = 1;
|
||||
*polarity = (new_bit != last_polarity);
|
||||
|
||||
bit_clock_index++;
|
||||
if(bit_clock_index >= clock_per_bit) {
|
||||
bit_clock_index = 0;
|
||||
last_polarity = *polarity;
|
||||
|
||||
card_data_index++;
|
||||
if(card_data_index >= 64) {
|
||||
card_data_index = 0;
|
||||
}
|
||||
}
|
||||
}
|
22
applications/lf-rfid/helpers/encoder-indala.h
Normal file
22
applications/lf-rfid/helpers/encoder-indala.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
#include "encoder-generic.h"
|
||||
|
||||
class EncoderIndala : public EncoderGeneric {
|
||||
public:
|
||||
/**
|
||||
* @brief init data to emulate
|
||||
*
|
||||
* @param data indala raw data
|
||||
* @param data_size must be 5
|
||||
*/
|
||||
void init(const uint8_t* data, const uint8_t data_size) final;
|
||||
|
||||
void get_next(bool* polarity, uint16_t* period, uint16_t* pulse) final;
|
||||
|
||||
private:
|
||||
uint64_t card_data;
|
||||
uint8_t card_data_index;
|
||||
uint8_t bit_clock_index;
|
||||
bool last_polarity;
|
||||
static const uint8_t clock_per_bit = 16;
|
||||
};
|
9
applications/lf-rfid/helpers/key-info.h
Normal file
9
applications/lf-rfid/helpers/key-info.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
static const uint8_t LFRFID_KEY_SIZE = 8;
|
||||
|
||||
enum class LfrfidKeyType : uint8_t {
|
||||
KeyEmarine,
|
||||
KeyHID,
|
||||
};
|
34
applications/lf-rfid/helpers/manchester-decoder.c
Normal file
34
applications/lf-rfid/helpers/manchester-decoder.c
Normal file
@ -0,0 +1,34 @@
|
||||
#include "manchester-decoder.h"
|
||||
#include <stdint.h>
|
||||
|
||||
static const uint8_t transitions[] = {0b00000001, 0b10010001, 0b10011011, 0b11111011};
|
||||
static const ManchesterState manchester_reset_state = ManchesterStateMid1;
|
||||
|
||||
bool manchester_advance(
|
||||
ManchesterState state,
|
||||
ManchesterEvent event,
|
||||
ManchesterState* next_state,
|
||||
bool* data) {
|
||||
bool result = false;
|
||||
ManchesterState new_state;
|
||||
|
||||
if(event == ManchesterEventReset) {
|
||||
new_state = manchester_reset_state;
|
||||
} else {
|
||||
new_state = transitions[state] >> event & 0x3;
|
||||
if(new_state == state) {
|
||||
new_state = manchester_reset_state;
|
||||
} else {
|
||||
if(new_state == ManchesterStateMid0) {
|
||||
*data = false;
|
||||
result = true;
|
||||
} else if(new_state == ManchesterStateMid1) {
|
||||
*data = true;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*next_state = new_state;
|
||||
return result;
|
||||
}
|
31
applications/lf-rfid/helpers/manchester-decoder.h
Normal file
31
applications/lf-rfid/helpers/manchester-decoder.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
ManchesterEventShortLow = 0,
|
||||
ManchesterEventShortHigh = 2,
|
||||
ManchesterEventLongLow = 4,
|
||||
ManchesterEventLongHigh = 6,
|
||||
ManchesterEventReset = 8
|
||||
} ManchesterEvent;
|
||||
|
||||
typedef enum {
|
||||
ManchesterStateStart1 = 0,
|
||||
ManchesterStateMid1 = 1,
|
||||
ManchesterStateMid0 = 2,
|
||||
ManchesterStateStart0 = 3
|
||||
} ManchesterState;
|
||||
|
||||
bool manchester_advance(
|
||||
ManchesterState state,
|
||||
ManchesterEvent event,
|
||||
ManchesterState* next_state,
|
||||
bool* data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
95
applications/lf-rfid/helpers/pulse-joiner.cpp
Normal file
95
applications/lf-rfid/helpers/pulse-joiner.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
#include "pulse-joiner.h"
|
||||
#include <furi.h>
|
||||
|
||||
bool PulseJoiner::push_pulse(bool polarity, uint16_t period, uint16_t pulse) {
|
||||
bool result = false;
|
||||
furi_check((pulse_index + 1) < pulse_max);
|
||||
|
||||
if(polarity == false && pulse_index == 0) {
|
||||
// first negative pulse is ommited
|
||||
|
||||
} else {
|
||||
pulses[pulse_index].polarity = polarity;
|
||||
pulses[pulse_index].time = pulse;
|
||||
pulse_index++;
|
||||
}
|
||||
|
||||
if(period > pulse) {
|
||||
pulses[pulse_index].polarity = !polarity;
|
||||
pulses[pulse_index].time = period - pulse;
|
||||
pulse_index++;
|
||||
}
|
||||
|
||||
if(pulse_index >= 4) {
|
||||
// we know that first pulse is always high
|
||||
// so we wait 2 edges, hi2low and next low2hi
|
||||
|
||||
uint8_t edges_count = 0;
|
||||
bool last_polarity = pulses[0].polarity;
|
||||
|
||||
for(uint8_t i = 1; i < pulse_index; i++) {
|
||||
if(pulses[i].polarity != last_polarity) {
|
||||
edges_count++;
|
||||
last_polarity = pulses[i].polarity;
|
||||
}
|
||||
}
|
||||
|
||||
if(edges_count >= 2) {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void PulseJoiner::pop_pulse(uint16_t* period, uint16_t* pulse) {
|
||||
furi_check(pulse_index <= (pulse_max + 1));
|
||||
|
||||
uint16_t tmp_period = 0;
|
||||
uint16_t tmp_pulse = 0;
|
||||
uint8_t edges_count = 0;
|
||||
bool last_polarity = pulses[0].polarity;
|
||||
uint8_t next_fist_pulse = 0;
|
||||
|
||||
for(uint8_t i = 0; i < pulse_max; i++) {
|
||||
// count edges
|
||||
if(pulses[i].polarity != last_polarity) {
|
||||
edges_count++;
|
||||
last_polarity = pulses[i].polarity;
|
||||
}
|
||||
|
||||
// wait for 2 edges
|
||||
if(edges_count == 2) {
|
||||
next_fist_pulse = i;
|
||||
break;
|
||||
}
|
||||
|
||||
// sum pulse time
|
||||
if(pulses[i].polarity) {
|
||||
tmp_period += pulses[i].time;
|
||||
tmp_pulse += pulses[i].time;
|
||||
} else {
|
||||
tmp_period += pulses[i].time;
|
||||
}
|
||||
pulse_index--;
|
||||
}
|
||||
|
||||
*period = tmp_period;
|
||||
*pulse = tmp_pulse;
|
||||
|
||||
// remove counted periods and shift data
|
||||
for(uint8_t i = 0; i < pulse_max; i++) {
|
||||
if((next_fist_pulse + i) < pulse_max) {
|
||||
pulses[i].polarity = pulses[next_fist_pulse + i].polarity;
|
||||
pulses[i].time = pulses[next_fist_pulse + i].time;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PulseJoiner::PulseJoiner() {
|
||||
for(uint8_t i = 0; i < pulse_max; i++) {
|
||||
pulses[i] = {false, 0};
|
||||
}
|
||||
}
|
36
applications/lf-rfid/helpers/pulse-joiner.h
Normal file
36
applications/lf-rfid/helpers/pulse-joiner.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include "stdint.h"
|
||||
|
||||
class PulseJoiner {
|
||||
public:
|
||||
/**
|
||||
* @brief Push timer pulse. First negative pulse is ommited.
|
||||
*
|
||||
* @param polarity pulse polarity: true = high2low, false = low2high
|
||||
* @param period overall period time in timer clicks
|
||||
* @param pulse pulse time in timer clicks
|
||||
*
|
||||
* @return true - next pulse can and must be popped immediatly
|
||||
*/
|
||||
bool push_pulse(bool polarity, uint16_t period, uint16_t pulse);
|
||||
|
||||
/**
|
||||
* @brief Get the next timer pulse. Call only if push_pulse returns true.
|
||||
*
|
||||
* @param period overall period time in timer clicks
|
||||
* @param pulse pulse time in timer clicks
|
||||
*/
|
||||
void pop_pulse(uint16_t* period, uint16_t* pulse);
|
||||
|
||||
PulseJoiner();
|
||||
|
||||
private:
|
||||
struct Pulse {
|
||||
bool polarity;
|
||||
uint16_t time;
|
||||
};
|
||||
|
||||
uint8_t pulse_index = 0;
|
||||
static const uint8_t pulse_max = 6;
|
||||
Pulse pulses[pulse_max];
|
||||
};
|
134
applications/lf-rfid/helpers/rfid-reader.cpp
Normal file
134
applications/lf-rfid/helpers/rfid-reader.cpp
Normal file
@ -0,0 +1,134 @@
|
||||
#include "rfid-reader.h"
|
||||
#include <furi.h>
|
||||
#include <api-hal.h>
|
||||
#include <stm32wbxx_ll_cortex.h>
|
||||
#include <tim.h>
|
||||
|
||||
extern COMP_HandleTypeDef hcomp1;
|
||||
|
||||
/**
|
||||
* @brief private violation assistant for RfidReader
|
||||
*/
|
||||
struct RfidReaderAccessor {
|
||||
static void decode(RfidReader& rfid_reader, bool polarity) {
|
||||
rfid_reader.decode(polarity);
|
||||
}
|
||||
};
|
||||
|
||||
void RfidReader::decode(bool polarity) {
|
||||
uint32_t current_dwt_value = DWT->CYCCNT;
|
||||
|
||||
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;
|
||||
break;
|
||||
case Type::Indala:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void comparator_trigger_callback(void* hcomp, void* comp_ctx) {
|
||||
COMP_HandleTypeDef* _hcomp = static_cast<COMP_HandleTypeDef*>(hcomp);
|
||||
RfidReader* _this = static_cast<RfidReader*>(comp_ctx);
|
||||
|
||||
if(hcomp == &hcomp1) {
|
||||
RfidReaderAccessor::decode(
|
||||
*_this, (HAL_COMP_GetOutputLevel(_hcomp) == COMP_OUTPUT_LEVEL_HIGH));
|
||||
}
|
||||
}
|
||||
|
||||
RfidReader::RfidReader() {
|
||||
}
|
||||
|
||||
void RfidReader::start(Type _type) {
|
||||
type = _type;
|
||||
|
||||
start_gpio();
|
||||
switch(type) {
|
||||
case Type::Normal:
|
||||
start_timer();
|
||||
break;
|
||||
case Type::Indala:
|
||||
start_timer_indala();
|
||||
break;
|
||||
}
|
||||
|
||||
start_comparator();
|
||||
}
|
||||
|
||||
void RfidReader::stop() {
|
||||
stop_gpio();
|
||||
stop_timer();
|
||||
stop_comparator();
|
||||
}
|
||||
|
||||
bool RfidReader::read(LfrfidKeyType* type, uint8_t* data, uint8_t data_size) {
|
||||
bool result = false;
|
||||
|
||||
if(decoder_em.read(data, data_size)) {
|
||||
*type = LfrfidKeyType::KeyEmarine;
|
||||
result = true;
|
||||
}
|
||||
|
||||
if(decoder_hid26.read(data, data_size)) {
|
||||
*type = LfrfidKeyType::KeyHID;
|
||||
result = true;
|
||||
}
|
||||
|
||||
//decoder_indala.read(NULL, 0);
|
||||
//decoder_analyzer.read(NULL, 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void RfidReader::start_comparator(void) {
|
||||
api_interrupt_add(comparator_trigger_callback, InterruptTypeComparatorTrigger, this);
|
||||
last_dwt_value = DWT->CYCCNT;
|
||||
|
||||
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.BlankingSrce = COMP_BLANKINGSRC_NONE;
|
||||
hcomp1.Init.Mode = COMP_POWERMODE_MEDIUMSPEED;
|
||||
hcomp1.Init.WindowMode = COMP_WINDOWMODE_DISABLE;
|
||||
hcomp1.Init.TriggerMode = COMP_TRIGGERMODE_IT_RISING_FALLING;
|
||||
if(HAL_COMP_Init(&hcomp1) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
41
applications/lf-rfid/helpers/rfid-reader.h
Normal file
41
applications/lf-rfid/helpers/rfid-reader.h
Normal file
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
#include "decoder-analyzer.h"
|
||||
#include "decoder-emmarine.h"
|
||||
#include "decoder-hid26.h"
|
||||
#include "decoder-indala.h"
|
||||
#include "key-info.h"
|
||||
|
||||
class RfidReader {
|
||||
public:
|
||||
enum class Type : uint8_t {
|
||||
Normal,
|
||||
Indala,
|
||||
};
|
||||
|
||||
RfidReader();
|
||||
void start(Type type);
|
||||
void stop();
|
||||
bool read(LfrfidKeyType* type, uint8_t* data, uint8_t data_size);
|
||||
|
||||
private:
|
||||
friend struct RfidReaderAccessor;
|
||||
|
||||
//DecoderAnalyzer decoder_analyzer;
|
||||
DecoderEMMarine decoder_em;
|
||||
DecoderHID26 decoder_hid26;
|
||||
DecoderIndala decoder_indala;
|
||||
|
||||
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);
|
||||
|
||||
Type type = Type::Normal;
|
||||
};
|
404
applications/lf-rfid/helpers/rfid-timer-emulator.cpp
Normal file
404
applications/lf-rfid/helpers/rfid-timer-emulator.cpp
Normal file
@ -0,0 +1,404 @@
|
||||
#include "rfid-timer-emulator.h"
|
||||
|
||||
extern TIM_HandleTypeDef htim1;
|
||||
/*
|
||||
static uint16_t times_index = 0;
|
||||
|
||||
constexpr uint16_t hid_237_34672_count = 528;
|
||||
constexpr uint8_t hid_237_34672[hid_237_34672_count] = {
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 8, 8, 8, 8,
|
||||
8, 8, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8,
|
||||
10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 10, 10,
|
||||
10, 10, 10, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8,
|
||||
8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 8,
|
||||
8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 8, 8, 8,
|
||||
8, 8, 8, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8,
|
||||
8, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 10,
|
||||
10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 8, 8, 8, 8,
|
||||
8, 8, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8,
|
||||
10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10,
|
||||
10, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 8,
|
||||
8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10,
|
||||
10, 10, 10, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10,
|
||||
10, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 10,
|
||||
10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10,
|
||||
8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 10,
|
||||
10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8, 10, 10, 10,
|
||||
10, 10, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, 8,
|
||||
};
|
||||
|
||||
static void callback_hid(void* _hw, void* ctx) {
|
||||
//RfidTimerEmulator* _this = static_cast<RfidTimerEmulator*>(ctx);
|
||||
TIM_HandleTypeDef* hw = static_cast<TIM_HandleTypeDef*>(_hw);
|
||||
|
||||
if(hw == &htim1) {
|
||||
hw->Instance->ARR = hid_237_34672[times_index] - 1;
|
||||
hw->Instance->CCR1 = hid_237_34672[times_index] / 2; // - 1
|
||||
|
||||
times_index++;
|
||||
if(times_index >= hid_237_34672_count) {
|
||||
times_index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint8_t arr;
|
||||
uint8_t ccr;
|
||||
} TimerTick;
|
||||
|
||||
constexpr TimerTick indala_data[] = {
|
||||
{.arr = 3, .ccr = 2}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 3, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 3, .ccr = 2},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 3, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 3, .ccr = 2}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 3, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 3, .ccr = 2}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 3, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 3, .ccr = 2}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 3, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 3, .ccr = 2},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 3, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 3, .ccr = 2}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 3, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 3, .ccr = 2}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 3, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 3, .ccr = 2}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 3, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 3, .ccr = 2},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 3, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1}, {.arr = 2, .ccr = 1},
|
||||
{.arr = 2, .ccr = 1},
|
||||
};
|
||||
|
||||
constexpr uint16_t indala_size = sizeof(indala_data) / sizeof(TimerTick);
|
||||
|
||||
static void callback_indala(void* _hw, void* ctx) {
|
||||
//RfidTimerEmulator* _this = static_cast<RfidTimerEmulator*>(ctx);
|
||||
TIM_HandleTypeDef* hw = static_cast<TIM_HandleTypeDef*>(_hw);
|
||||
|
||||
if(hw == &htim1) {
|
||||
hw->Instance->ARR = indala_data[times_index].arr - 1;
|
||||
hw->Instance->CCR1 = indala_data[times_index].ccr;
|
||||
|
||||
times_index++;
|
||||
if(times_index >= indala_size) {
|
||||
times_index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
RfidTimerEmulator::RfidTimerEmulator() {
|
||||
}
|
||||
|
||||
RfidTimerEmulator::~RfidTimerEmulator() {
|
||||
std::map<Type, EncoderGeneric*>::iterator it;
|
||||
|
||||
for(it = encoders.begin(); it != encoders.end(); ++it) {
|
||||
delete it->second;
|
||||
encoders.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void RfidTimerEmulator::start(Type type) {
|
||||
if(encoders.count(type)) {
|
||||
current_encoder = encoders.find(type)->second;
|
||||
uint8_t em_data[5] = {0x53, 0x00, 0x5F, 0xB3, 0xC2};
|
||||
|
||||
switch(type) {
|
||||
case Type::EM:
|
||||
current_encoder->init(em_data, 5);
|
||||
break;
|
||||
case Type::HID:
|
||||
current_encoder->init(nullptr, 3);
|
||||
break;
|
||||
case Type::Indala:
|
||||
current_encoder->init(nullptr, 5);
|
||||
break;
|
||||
}
|
||||
|
||||
api_hal_rfid_tim_emulate(125000);
|
||||
api_hal_rfid_pins_emulate();
|
||||
|
||||
api_interrupt_add(timer_update_callback, InterruptTypeTimerUpdate, this);
|
||||
|
||||
for(size_t i = WWDG_IRQn; i <= DMAMUX1_OVR_IRQn; i++) {
|
||||
HAL_NVIC_SetPriority(static_cast<IRQn_Type>(i), 15, 0);
|
||||
}
|
||||
|
||||
HAL_NVIC_SetPriority(TIM1_UP_TIM16_IRQn, 5, 0);
|
||||
HAL_NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn);
|
||||
|
||||
api_hal_rfid_tim_emulate_start();
|
||||
} else {
|
||||
// not found
|
||||
}
|
||||
}
|
||||
|
||||
void RfidTimerEmulator::stop() {
|
||||
api_hal_rfid_tim_emulate_stop();
|
||||
|
||||
api_interrupt_remove(timer_update_callback, InterruptTypeTimerUpdate);
|
||||
}
|
||||
|
||||
void RfidTimerEmulator::emulate() {
|
||||
}
|
||||
|
||||
void RfidTimerEmulator::timer_update_callback(void* _hw, void* ctx) {
|
||||
RfidTimerEmulator* _this = static_cast<RfidTimerEmulator*>(ctx);
|
||||
TIM_HandleTypeDef* hw = static_cast<TIM_HandleTypeDef*>(_hw);
|
||||
|
||||
if(hw == &LFRFID_TIM) {
|
||||
bool result;
|
||||
bool polarity;
|
||||
uint16_t period;
|
||||
uint16_t pulse;
|
||||
|
||||
do {
|
||||
_this->current_encoder->get_next(&polarity, &period, &pulse);
|
||||
result = _this->pulse_joiner.push_pulse(polarity, period, pulse);
|
||||
} while(result == false);
|
||||
|
||||
_this->pulse_joiner.pop_pulse(&period, &pulse);
|
||||
|
||||
hw->Instance->ARR = period - 1;
|
||||
hw->Instance->CCR1 = pulse;
|
||||
}
|
||||
}
|
36
applications/lf-rfid/helpers/rfid-timer-emulator.h
Normal file
36
applications/lf-rfid/helpers/rfid-timer-emulator.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include <api-hal.h>
|
||||
#include "key-info.h"
|
||||
#include "encoder-generic.h"
|
||||
#include "encoder-emmarine.h"
|
||||
#include "encoder-hid.h"
|
||||
#include "encoder-indala.h"
|
||||
#include "pulse-joiner.h"
|
||||
#include <map>
|
||||
|
||||
class RfidTimerEmulator {
|
||||
public:
|
||||
enum class Type : uint8_t {
|
||||
EM,
|
||||
HID,
|
||||
Indala,
|
||||
};
|
||||
|
||||
RfidTimerEmulator();
|
||||
~RfidTimerEmulator();
|
||||
void start(Type type);
|
||||
void stop();
|
||||
void emulate();
|
||||
|
||||
private:
|
||||
EncoderGeneric* current_encoder = nullptr;
|
||||
|
||||
std::map<Type, EncoderGeneric*> encoders = {
|
||||
{Type::EM, new EncoderEM()},
|
||||
{Type::HID, new EncoderHID()},
|
||||
{Type::Indala, new EncoderIndala()},
|
||||
};
|
||||
|
||||
PulseJoiner pulse_joiner;
|
||||
static void timer_update_callback(void* _hw, void* ctx);
|
||||
};
|
146
applications/lf-rfid/lf-rfid-app.cpp
Normal file
146
applications/lf-rfid/lf-rfid-app.cpp
Normal file
@ -0,0 +1,146 @@
|
||||
#include "lf-rfid-app.h"
|
||||
#include <furi.h>
|
||||
#include <api-hal.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
void LfrfidApp::run(void) {
|
||||
LfrfidEvent event;
|
||||
bool consumed;
|
||||
bool exit = false;
|
||||
|
||||
scenes[current_scene]->on_enter(this);
|
||||
|
||||
while(!exit) {
|
||||
view.receive_event(&event);
|
||||
|
||||
consumed = scenes[current_scene]->on_event(this, &event);
|
||||
|
||||
if(!consumed) {
|
||||
if(event.type == LfrfidEvent::Type::Back) {
|
||||
exit = switch_to_previous_scene();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
scenes[current_scene]->on_exit(this);
|
||||
}
|
||||
|
||||
LfrfidApp::LfrfidApp() {
|
||||
api_hal_power_insomnia_enter();
|
||||
}
|
||||
|
||||
LfrfidApp::~LfrfidApp() {
|
||||
for(std::map<Scene, LfrfidScene*>::iterator it = scenes.begin(); it != scenes.end(); ++it) {
|
||||
delete it->second;
|
||||
scenes.erase(it);
|
||||
}
|
||||
|
||||
api_hal_power_insomnia_exit();
|
||||
}
|
||||
|
||||
LfrfidAppViewManager* LfrfidApp::get_view_manager() {
|
||||
return &view;
|
||||
}
|
||||
|
||||
void LfrfidApp::switch_to_next_scene(Scene next_scene) {
|
||||
previous_scenes_list.push_front(current_scene);
|
||||
|
||||
if(next_scene != Scene::Exit) {
|
||||
scenes[current_scene]->on_exit(this);
|
||||
current_scene = next_scene;
|
||||
scenes[current_scene]->on_enter(this);
|
||||
}
|
||||
}
|
||||
|
||||
void LfrfidApp::search_and_switch_to_previous_scene(std::initializer_list<Scene> scenes_list) {
|
||||
Scene previous_scene = Scene::Start;
|
||||
bool scene_found = false;
|
||||
|
||||
while(!scene_found) {
|
||||
previous_scene = get_previous_scene();
|
||||
for(Scene element : scenes_list) {
|
||||
if(previous_scene == element || previous_scene == Scene::Start) {
|
||||
scene_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scenes[current_scene]->on_exit(this);
|
||||
current_scene = previous_scene;
|
||||
scenes[current_scene]->on_enter(this);
|
||||
}
|
||||
|
||||
bool LfrfidApp::switch_to_previous_scene(uint8_t count) {
|
||||
Scene previous_scene = Scene::Start;
|
||||
|
||||
for(uint8_t i = 0; i < count; i++) {
|
||||
previous_scene = get_previous_scene();
|
||||
if(previous_scene == Scene::Exit) break;
|
||||
}
|
||||
|
||||
if(previous_scene == Scene::Exit) {
|
||||
return true;
|
||||
} else {
|
||||
scenes[current_scene]->on_exit(this);
|
||||
current_scene = previous_scene;
|
||||
scenes[current_scene]->on_enter(this);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
LfrfidApp::Scene LfrfidApp::get_previous_scene() {
|
||||
Scene scene = previous_scenes_list.front();
|
||||
previous_scenes_list.pop_front();
|
||||
return scene;
|
||||
}
|
||||
|
||||
/***************************** NOTIFY *******************************/
|
||||
|
||||
void LfrfidApp::notify_init() {
|
||||
// TODO open record
|
||||
const GpioPin* vibro_record = &vibro_gpio;
|
||||
hal_gpio_init(vibro_record, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
hal_gpio_write(vibro_record, false);
|
||||
}
|
||||
|
||||
void LfrfidApp::notify_green_blink() {
|
||||
api_hal_light_set(LightGreen, 0xFF);
|
||||
delay(10);
|
||||
api_hal_light_set(LightGreen, 0x00);
|
||||
}
|
||||
|
||||
void LfrfidApp::notify_green_on() {
|
||||
api_hal_light_set(LightGreen, 0xFF);
|
||||
}
|
||||
|
||||
void LfrfidApp::notify_green_off() {
|
||||
api_hal_light_set(LightGreen, 0x00);
|
||||
}
|
||||
|
||||
/*************************** TEXT STORE *****************************/
|
||||
|
||||
char* LfrfidApp::get_text_store() {
|
||||
return text_store;
|
||||
}
|
||||
|
||||
uint8_t LfrfidApp::get_text_store_size() {
|
||||
return text_store_size;
|
||||
}
|
||||
|
||||
void LfrfidApp::set_text_store(const char* text...) {
|
||||
va_list args;
|
||||
va_start(args, text);
|
||||
|
||||
vsnprintf(text_store, text_store_size, text, args);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
RfidReader* LfrfidApp::get_reader() {
|
||||
return &reader;
|
||||
}
|
||||
|
||||
RfidTimerEmulator* LfrfidApp::get_emulator() {
|
||||
return &emulator;
|
||||
}
|
73
applications/lf-rfid/lf-rfid-app.h
Normal file
73
applications/lf-rfid/lf-rfid-app.h
Normal file
@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include "lf-rfid-view-manager.h"
|
||||
|
||||
#include "scene/lf-rfid-scene-start.h"
|
||||
#include "scene/lf-rfid-scene-emulate-indala.h"
|
||||
#include "scene/lf-rfid-scene-emulate-hid.h"
|
||||
#include "scene/lf-rfid-scene-emulate-emmarine.h"
|
||||
#include "scene/lf-rfid-scene-read-normal.h"
|
||||
#include "scene/lf-rfid-scene-read-indala.h"
|
||||
#include "scene/lf-rfid-scene-tune.h"
|
||||
|
||||
#include "helpers/rfid-reader.h"
|
||||
#include "helpers/rfid-timer-emulator.h"
|
||||
|
||||
class LfrfidApp {
|
||||
public:
|
||||
void run(void);
|
||||
|
||||
LfrfidApp();
|
||||
~LfrfidApp();
|
||||
|
||||
enum class Scene : uint8_t {
|
||||
Exit,
|
||||
Start,
|
||||
ReadNormal,
|
||||
ReadIndala,
|
||||
EmulateIndala,
|
||||
EmulateHID,
|
||||
EmulateEM,
|
||||
Tune,
|
||||
};
|
||||
|
||||
LfrfidAppViewManager* get_view_manager();
|
||||
void switch_to_next_scene(Scene index);
|
||||
void search_and_switch_to_previous_scene(std::initializer_list<Scene> scenes_list);
|
||||
bool switch_to_previous_scene(uint8_t count = 1);
|
||||
Scene get_previous_scene();
|
||||
|
||||
void notify_init();
|
||||
void notify_green_blink();
|
||||
void notify_green_on();
|
||||
void notify_green_off();
|
||||
|
||||
char* get_text_store();
|
||||
uint8_t get_text_store_size();
|
||||
void set_text_store(const char* text...);
|
||||
|
||||
RfidReader* get_reader();
|
||||
RfidTimerEmulator* get_emulator();
|
||||
|
||||
private:
|
||||
std::list<Scene> previous_scenes_list = {Scene::Exit};
|
||||
Scene current_scene = Scene::Start;
|
||||
LfrfidAppViewManager view;
|
||||
|
||||
std::map<Scene, LfrfidScene*> scenes = {
|
||||
{Scene::Start, new LfrfidSceneStart()},
|
||||
{Scene::ReadNormal, new LfrfidSceneReadNormal()},
|
||||
{Scene::ReadIndala, new LfrfidSceneReadIndala()},
|
||||
{Scene::EmulateIndala, new LfrfidSceneEmulateIndala()},
|
||||
{Scene::EmulateHID, new LfrfidSceneEmulateHID()},
|
||||
{Scene::EmulateEM, new LfrfidSceneEmulateEMMarine()},
|
||||
{Scene::Tune, new LfrfidSceneTune()},
|
||||
};
|
||||
|
||||
static const uint8_t text_store_size = 128;
|
||||
char text_store[text_store_size + 1];
|
||||
|
||||
RfidReader reader;
|
||||
RfidTimerEmulator emulator;
|
||||
};
|
21
applications/lf-rfid/lf-rfid-event.h
Normal file
21
applications/lf-rfid/lf-rfid-event.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
class LfrfidEvent {
|
||||
public:
|
||||
// events enum
|
||||
enum class Type : uint8_t {
|
||||
Tick,
|
||||
Back,
|
||||
MenuSelected,
|
||||
NextScene,
|
||||
};
|
||||
|
||||
// payload
|
||||
union {
|
||||
uint32_t menu_index;
|
||||
} payload;
|
||||
|
||||
// event type
|
||||
Type type;
|
||||
};
|
90
applications/lf-rfid/lf-rfid-view-manager.cpp
Normal file
90
applications/lf-rfid/lf-rfid-view-manager.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
#include "lf-rfid-view-manager.h"
|
||||
#include "lf-rfid-event.h"
|
||||
#include <callback-connector.h>
|
||||
|
||||
LfrfidAppViewManager::LfrfidAppViewManager() {
|
||||
event_queue = osMessageQueueNew(10, sizeof(LfrfidEvent), NULL);
|
||||
|
||||
view_dispatcher = view_dispatcher_alloc();
|
||||
auto callback = cbc::obtain_connector(this, &LfrfidAppViewManager::previous_view_callback);
|
||||
|
||||
// allocate views
|
||||
submenu = submenu_alloc();
|
||||
add_view(ViewType::Submenu, submenu_get_view(submenu));
|
||||
|
||||
popup = popup_alloc();
|
||||
add_view(ViewType::Popup, popup_get_view(popup));
|
||||
|
||||
tune = new LfRfidViewTune();
|
||||
add_view(ViewType::Tune, tune->get_view());
|
||||
|
||||
gui = static_cast<Gui*>(furi_record_open("gui"));
|
||||
view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
// set previous view callback for all views
|
||||
view_set_previous_callback(submenu_get_view(submenu), callback);
|
||||
view_set_previous_callback(popup_get_view(popup), callback);
|
||||
view_set_previous_callback(tune->get_view(), callback);
|
||||
}
|
||||
|
||||
LfrfidAppViewManager::~LfrfidAppViewManager() {
|
||||
// remove views
|
||||
view_dispatcher_remove_view(
|
||||
view_dispatcher, static_cast<uint32_t>(LfrfidAppViewManager::ViewType::Submenu));
|
||||
view_dispatcher_remove_view(
|
||||
view_dispatcher, static_cast<uint32_t>(LfrfidAppViewManager::ViewType::Popup));
|
||||
view_dispatcher_remove_view(
|
||||
view_dispatcher, static_cast<uint32_t>(LfrfidAppViewManager::ViewType::Tune));
|
||||
|
||||
// free view modules
|
||||
submenu_free(submenu);
|
||||
popup_free(popup);
|
||||
delete tune;
|
||||
|
||||
// free dispatcher
|
||||
view_dispatcher_free(view_dispatcher);
|
||||
|
||||
// free event queue
|
||||
osMessageQueueDelete(event_queue);
|
||||
}
|
||||
|
||||
void LfrfidAppViewManager::switch_to(ViewType type) {
|
||||
view_dispatcher_switch_to_view(view_dispatcher, static_cast<uint32_t>(type));
|
||||
}
|
||||
|
||||
Submenu* LfrfidAppViewManager::get_submenu() {
|
||||
return submenu;
|
||||
}
|
||||
|
||||
Popup* LfrfidAppViewManager::get_popup() {
|
||||
return popup;
|
||||
}
|
||||
|
||||
LfRfidViewTune* LfrfidAppViewManager::get_tune() {
|
||||
return tune;
|
||||
}
|
||||
|
||||
void LfrfidAppViewManager::receive_event(LfrfidEvent* event) {
|
||||
if(osMessageQueueGet(event_queue, event, NULL, 100) != osOK) {
|
||||
event->type = LfrfidEvent::Type::Tick;
|
||||
}
|
||||
}
|
||||
|
||||
void LfrfidAppViewManager::send_event(LfrfidEvent* event) {
|
||||
osStatus_t result = osMessageQueuePut(event_queue, event, 0, 0);
|
||||
furi_check(result == osOK);
|
||||
}
|
||||
|
||||
uint32_t LfrfidAppViewManager::previous_view_callback(void* context) {
|
||||
if(event_queue != NULL) {
|
||||
LfrfidEvent event;
|
||||
event.type = LfrfidEvent::Type::Back;
|
||||
send_event(&event);
|
||||
}
|
||||
|
||||
return VIEW_IGNORE;
|
||||
}
|
||||
|
||||
void LfrfidAppViewManager::add_view(ViewType view_type, View* view) {
|
||||
view_dispatcher_add_view(view_dispatcher, static_cast<uint32_t>(view_type), view);
|
||||
}
|
42
applications/lf-rfid/lf-rfid-view-manager.h
Normal file
42
applications/lf-rfid/lf-rfid-view-manager.h
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
#include <furi.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/popup.h>
|
||||
#include "lf-rfid-event.h"
|
||||
#include "view/lf-rfid-view-tune.h"
|
||||
|
||||
class LfrfidAppViewManager {
|
||||
public:
|
||||
enum class ViewType : uint8_t {
|
||||
Submenu,
|
||||
Popup,
|
||||
Tune,
|
||||
};
|
||||
|
||||
osMessageQueueId_t event_queue;
|
||||
|
||||
LfrfidAppViewManager();
|
||||
~LfrfidAppViewManager();
|
||||
|
||||
void switch_to(ViewType type);
|
||||
|
||||
void receive_event(LfrfidEvent* event);
|
||||
void send_event(LfrfidEvent* event);
|
||||
|
||||
Submenu* get_submenu();
|
||||
Popup* get_popup();
|
||||
LfRfidViewTune* get_tune();
|
||||
|
||||
private:
|
||||
ViewDispatcher* view_dispatcher;
|
||||
Gui* gui;
|
||||
|
||||
uint32_t previous_view_callback(void* context);
|
||||
void add_view(ViewType view_type, View* view);
|
||||
|
||||
// view elements
|
||||
Submenu* submenu;
|
||||
Popup* popup;
|
||||
LfRfidViewTune* tune;
|
||||
};
|
@ -1,421 +0,0 @@
|
||||
#include <furi.h>
|
||||
#include <api-hal.h>
|
||||
#include <gui/gui.h>
|
||||
#include <stream_buffer.h>
|
||||
|
||||
typedef enum { EventTypeTick, EventTypeKey, EventTypeRx } EventType;
|
||||
|
||||
typedef struct {
|
||||
uint8_t dummy;
|
||||
} RxEvent;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
InputEvent input;
|
||||
RxEvent rx;
|
||||
} value;
|
||||
EventType type;
|
||||
} AppEvent;
|
||||
|
||||
typedef struct {
|
||||
uint32_t freq_khz;
|
||||
bool on;
|
||||
uint8_t customer_id;
|
||||
uint32_t em_data;
|
||||
bool dirty;
|
||||
bool dirty_freq;
|
||||
} State;
|
||||
|
||||
static void render_callback(Canvas* canvas, void* ctx) {
|
||||
State* state = (State*)acquire_mutex((ValueMutex*)ctx, 25);
|
||||
|
||||
canvas_clear(canvas);
|
||||
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 2, 12, "LF RFID");
|
||||
|
||||
canvas_draw_str(canvas, 2, 24, state->on ? "Reading" : "Emulating");
|
||||
|
||||
char buf[30];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%d kHz", (int)state->freq_khz);
|
||||
canvas_draw_str(canvas, 2, 36, buf);
|
||||
|
||||
snprintf(buf, sizeof(buf), "%02d:%010ld", state->customer_id, state->em_data);
|
||||
canvas_draw_str(canvas, 2, 45, buf);
|
||||
|
||||
release_mutex((ValueMutex*)ctx, state);
|
||||
}
|
||||
|
||||
static void input_callback(InputEvent* input_event, void* ctx) {
|
||||
osMessageQueueId_t event_queue = ctx;
|
||||
|
||||
if(input_event->type != InputTypeShort) return;
|
||||
|
||||
AppEvent event;
|
||||
event.type = EventTypeKey;
|
||||
event.value.input = *input_event;
|
||||
osMessageQueuePut(event_queue, &event, 1, osWaitForever);
|
||||
}
|
||||
|
||||
extern TIM_HandleTypeDef TIM_C;
|
||||
void em4100_emulation(uint8_t* data, GpioPin* pin);
|
||||
void prepare_data(uint32_t ID, uint32_t VENDOR, uint8_t* data);
|
||||
|
||||
GpioPin debug_0 = {.pin = GPIO_PIN_2, .port = GPIOB};
|
||||
GpioPin debug_1 = {.pin = GPIO_PIN_3, .port = GPIOC};
|
||||
|
||||
extern COMP_HandleTypeDef hcomp1;
|
||||
|
||||
typedef struct {
|
||||
osMessageQueueId_t event_queue;
|
||||
uint32_t prev_dwt;
|
||||
int8_t symbol;
|
||||
bool center;
|
||||
size_t symbol_cnt;
|
||||
StreamBufferHandle_t stream_buffer;
|
||||
uint8_t* int_buffer;
|
||||
} ComparatorCtx;
|
||||
|
||||
void init_comp_ctx(ComparatorCtx* ctx) {
|
||||
ctx->prev_dwt = 0;
|
||||
ctx->symbol = -1; // init state
|
||||
ctx->center = false;
|
||||
ctx->symbol_cnt = 0;
|
||||
xStreamBufferReset(ctx->stream_buffer);
|
||||
|
||||
for(size_t i = 0; i < 64; i++) {
|
||||
ctx->int_buffer[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void comparator_trigger_callback(void* hcomp, void* comp_ctx) {
|
||||
ComparatorCtx* ctx = (ComparatorCtx*)comp_ctx;
|
||||
|
||||
uint32_t dt = (DWT->CYCCNT - ctx->prev_dwt) / (SystemCoreClock / 1000000.0f);
|
||||
ctx->prev_dwt = DWT->CYCCNT;
|
||||
|
||||
if(dt < 150) return; // supress noise
|
||||
|
||||
// wait message will be consumed
|
||||
if(xStreamBufferBytesAvailable(ctx->stream_buffer) == 64) return;
|
||||
|
||||
hal_gpio_write(&debug_0, true);
|
||||
|
||||
// TOOD F4 and F5 differ
|
||||
bool rx_value = hal_gpio_get_rfid_in_level();
|
||||
|
||||
if(dt > 384) {
|
||||
// change symbol 0->1 or 1->0
|
||||
ctx->symbol = rx_value;
|
||||
ctx->center = true;
|
||||
} else {
|
||||
// same symbol as prev or center
|
||||
ctx->center = !ctx->center;
|
||||
}
|
||||
|
||||
/*
|
||||
hal_gpio_write(&debug_1, true);
|
||||
delay_us(center ? 10 : 30);
|
||||
hal_gpio_write(&debug_1, false);
|
||||
*/
|
||||
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
if(ctx->center && ctx->symbol != -1) {
|
||||
/*
|
||||
hal_gpio_write(&debug_0, true);
|
||||
delay_us(symbol ? 10 : 30);
|
||||
hal_gpio_write(&debug_0, false);
|
||||
*/
|
||||
|
||||
ctx->int_buffer[ctx->symbol_cnt] = ctx->symbol;
|
||||
ctx->symbol_cnt++;
|
||||
}
|
||||
|
||||
// check preamble
|
||||
if(ctx->symbol_cnt <= 9 && ctx->symbol == 0) {
|
||||
ctx->symbol_cnt = 0;
|
||||
ctx->symbol = -1;
|
||||
}
|
||||
|
||||
// check stop bit
|
||||
if(ctx->symbol_cnt == 64 && ctx->symbol == 1) {
|
||||
ctx->symbol_cnt = 0;
|
||||
ctx->symbol = -1;
|
||||
}
|
||||
|
||||
// TODO
|
||||
// write only 9..64 symbols directly to streambuffer
|
||||
|
||||
if(ctx->symbol_cnt == 64) {
|
||||
if(xStreamBufferSendFromISR(
|
||||
ctx->stream_buffer, ctx->int_buffer, 64, &xHigherPriorityTaskWoken) == 64) {
|
||||
AppEvent event;
|
||||
event.type = EventTypeRx;
|
||||
osMessageQueuePut(ctx->event_queue, &event, 0, 0);
|
||||
}
|
||||
|
||||
ctx->symbol_cnt = 0;
|
||||
}
|
||||
|
||||
hal_gpio_write(&debug_0, false);
|
||||
|
||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||
}
|
||||
|
||||
const uint8_t ROW_SIZE = 4;
|
||||
const uint8_t LINE_SIZE = 10;
|
||||
|
||||
static bool even_check(uint8_t* buf) {
|
||||
uint8_t col_parity_sum[ROW_SIZE];
|
||||
for(uint8_t col = 0; col < ROW_SIZE; col++) {
|
||||
col_parity_sum[col] = 0;
|
||||
}
|
||||
|
||||
// line parity
|
||||
for(uint8_t line = 0; line < LINE_SIZE; line++) {
|
||||
printf("%d: ", line);
|
||||
uint8_t parity_sum = 0;
|
||||
for(uint8_t col = 0; col < ROW_SIZE; col++) {
|
||||
parity_sum += buf[line * (ROW_SIZE + 1) + col];
|
||||
col_parity_sum[col] += buf[line * (ROW_SIZE + 1) + col];
|
||||
printf("%d ", buf[line * (ROW_SIZE + 1) + col]);
|
||||
}
|
||||
if((1 & parity_sum) != buf[line * (ROW_SIZE + 1) + ROW_SIZE]) {
|
||||
printf(
|
||||
"line parity fail at %d (%d : %d)\n",
|
||||
line,
|
||||
parity_sum,
|
||||
buf[line * (ROW_SIZE + 1) + ROW_SIZE]);
|
||||
return false;
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
|
||||
for(uint8_t col = 0; col < ROW_SIZE; col++) {
|
||||
if((1 & col_parity_sum[col]) != buf[LINE_SIZE * (ROW_SIZE + 1) + col]) {
|
||||
printf(
|
||||
"col parity fail at %d (%d : %d)\n",
|
||||
col,
|
||||
col_parity_sum[col],
|
||||
buf[LINE_SIZE * (ROW_SIZE + 1) + col]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void extract_data(uint8_t* buf, uint8_t* customer, uint32_t* em_data) {
|
||||
uint32_t data = 0;
|
||||
uint8_t offset = 0;
|
||||
|
||||
printf("customer: ");
|
||||
for(uint8_t line = 0; line < 2; line++) {
|
||||
for(uint8_t col = 0; col < ROW_SIZE; col++) {
|
||||
uint32_t bit = buf[line * (ROW_SIZE + 1) + col];
|
||||
|
||||
data |= bit << (7 - offset);
|
||||
printf("%ld ", bit);
|
||||
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
printf("\r\n");
|
||||
|
||||
*customer = data;
|
||||
|
||||
data = 0;
|
||||
offset = 0;
|
||||
printf("data: ");
|
||||
for(uint8_t line = 2; line < LINE_SIZE; line++) {
|
||||
for(uint8_t col = 0; col < ROW_SIZE; col++) {
|
||||
uint32_t bit = buf[line * (ROW_SIZE + 1) + col];
|
||||
|
||||
data |= bit << (31 - offset);
|
||||
printf("%ld ", bit);
|
||||
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
printf("\r\n");
|
||||
|
||||
*em_data = data;
|
||||
}
|
||||
|
||||
int32_t lf_rfid_workaround(void* p) {
|
||||
osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(AppEvent), NULL);
|
||||
|
||||
// create pin
|
||||
GpioPin pull_pin = {.pin = RFID_PULL_Pin, .port = RFID_PULL_GPIO_Port};
|
||||
// TODO open record
|
||||
GpioPin* pull_pin_record = &pull_pin;
|
||||
|
||||
hal_gpio_init(pull_pin_record, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
hal_gpio_init(&debug_0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
hal_gpio_init(&debug_1, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
// pulldown iBtn pin to prevent interference from ibutton
|
||||
hal_gpio_init((GpioPin*)&ibutton_gpio, GpioModeOutputOpenDrain, GpioPullNo, GpioSpeedLow);
|
||||
hal_gpio_write((GpioPin*)&ibutton_gpio, false);
|
||||
|
||||
// init ctx
|
||||
ComparatorCtx comp_ctx;
|
||||
|
||||
// internal buffer
|
||||
uint8_t int_bufer[64];
|
||||
|
||||
comp_ctx.stream_buffer = xStreamBufferCreate(64, 64);
|
||||
comp_ctx.int_buffer = int_bufer;
|
||||
comp_ctx.event_queue = event_queue;
|
||||
init_comp_ctx(&comp_ctx);
|
||||
|
||||
if(comp_ctx.stream_buffer == NULL) {
|
||||
printf("cannot create stream buffer\r\n");
|
||||
return 255;
|
||||
}
|
||||
|
||||
// start comp
|
||||
HAL_COMP_Start(&hcomp1);
|
||||
|
||||
uint8_t raw_data[64];
|
||||
for(size_t i = 0; i < 64; i++) {
|
||||
raw_data[i] = 0;
|
||||
}
|
||||
|
||||
State _state;
|
||||
_state.freq_khz = 125;
|
||||
_state.on = false;
|
||||
_state.customer_id = 00;
|
||||
_state.em_data = 4378151;
|
||||
_state.dirty = true;
|
||||
_state.dirty_freq = true;
|
||||
|
||||
ValueMutex state_mutex;
|
||||
if(!init_mutex(&state_mutex, &_state, sizeof(State))) {
|
||||
printf("cannot create mutex\r\n");
|
||||
return 255;
|
||||
}
|
||||
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
|
||||
view_port_draw_callback_set(view_port, render_callback, &state_mutex);
|
||||
view_port_input_callback_set(view_port, input_callback, event_queue);
|
||||
|
||||
// Open GUI and register view_port
|
||||
Gui* gui = furi_record_open("gui");
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
AppEvent event;
|
||||
|
||||
while(1) {
|
||||
osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, 1024 / 8);
|
||||
|
||||
if(event.type == EventTypeRx && event_status == osOK) {
|
||||
size_t received = xStreamBufferReceive(comp_ctx.stream_buffer, raw_data, 64, 0);
|
||||
printf("received: %d\r\n", received);
|
||||
if(received == 64) {
|
||||
if(even_check(&raw_data[9])) {
|
||||
State* state = (State*)acquire_mutex_block(&state_mutex);
|
||||
extract_data(&raw_data[9], &state->customer_id, &state->em_data);
|
||||
|
||||
printf("customer: %02d, data: %010lu\n", state->customer_id, state->em_data);
|
||||
|
||||
release_mutex(&state_mutex, state);
|
||||
|
||||
view_port_update(view_port);
|
||||
|
||||
api_hal_light_set(LightGreen, 0xFF);
|
||||
osDelay(50);
|
||||
api_hal_light_set(LightGreen, 0x00);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
State* state = (State*)acquire_mutex_block(&state_mutex);
|
||||
|
||||
if(event_status == osOK) {
|
||||
if(event.type == EventTypeKey) {
|
||||
// press events
|
||||
if(event.value.input.key == InputKeyBack) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(event.value.input.key == InputKeyUp) {
|
||||
state->dirty_freq = true;
|
||||
state->freq_khz += 10;
|
||||
}
|
||||
|
||||
if(event.value.input.key == InputKeyDown) {
|
||||
state->dirty_freq = true;
|
||||
state->freq_khz -= 10;
|
||||
}
|
||||
|
||||
if(event.value.input.key == InputKeyLeft) {
|
||||
}
|
||||
|
||||
if(event.value.input.key == InputKeyRight) {
|
||||
}
|
||||
|
||||
if(event.value.input.key == InputKeyOk) {
|
||||
state->dirty = true;
|
||||
state->on = !state->on;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// event timeout
|
||||
}
|
||||
|
||||
if(state->dirty) {
|
||||
if(state->on) {
|
||||
hal_gpio_write(pull_pin_record, false);
|
||||
init_comp_ctx(&comp_ctx);
|
||||
api_interrupt_add(
|
||||
comparator_trigger_callback, InterruptTypeComparatorTrigger, &comp_ctx);
|
||||
} else {
|
||||
prepare_data(state->em_data, state->customer_id, raw_data);
|
||||
api_interrupt_remove(
|
||||
comparator_trigger_callback, InterruptTypeComparatorTrigger);
|
||||
}
|
||||
|
||||
state->dirty_freq = true; // config new PWM next
|
||||
|
||||
state->dirty = false;
|
||||
}
|
||||
|
||||
if(state->dirty_freq) {
|
||||
hal_pwmn_set(
|
||||
state->on ? 0.5 : 0.0, (float)(state->freq_khz * 1000), &LFRFID_TIM, LFRFID_CH);
|
||||
|
||||
state->dirty_freq = false;
|
||||
}
|
||||
|
||||
if(!state->on) {
|
||||
em4100_emulation(raw_data, pull_pin_record);
|
||||
}
|
||||
release_mutex(&state_mutex, state);
|
||||
view_port_update(view_port);
|
||||
}
|
||||
}
|
||||
|
||||
hal_pwmn_stop(&TIM_C, TIM_CHANNEL_1); // TODO: move to furiac_onexit
|
||||
api_interrupt_remove(comparator_trigger_callback, InterruptTypeComparatorTrigger);
|
||||
|
||||
hal_gpio_init(pull_pin_record, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||
hal_gpio_init((GpioPin*)&ibutton_gpio, GpioModeInput, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
// TODO remove all view_ports create by app
|
||||
view_port_enabled_set(view_port, false);
|
||||
gui_remove_view_port(gui, view_port);
|
||||
view_port_free(view_port);
|
||||
|
||||
HAL_COMP_Stop(&hcomp1);
|
||||
|
||||
vStreamBufferDelete(comp_ctx.stream_buffer);
|
||||
|
||||
osMessageQueueDelete(event_queue);
|
||||
|
||||
return 0;
|
||||
}
|
10
applications/lf-rfid/lf-rfid.cpp
Normal file
10
applications/lf-rfid/lf-rfid.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
#include "lf-rfid-app.h"
|
||||
|
||||
// app enter function
|
||||
extern "C" int32_t app_lfrfid(void* p) {
|
||||
LfrfidApp* app = new LfrfidApp();
|
||||
app->run();
|
||||
delete app;
|
||||
|
||||
return 255;
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
#include "lf-rfid-scene-emulate-emmarine.h"
|
||||
|
||||
#include "../lf-rfid-app.h"
|
||||
#include "../lf-rfid-view-manager.h"
|
||||
#include "../lf-rfid-event.h"
|
||||
#include "../helpers/key-info.h"
|
||||
|
||||
void LfrfidSceneEmulateEMMarine::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("EM emulation");
|
||||
popup_set_text(popup, app->get_text_store(), 64, 22, AlignCenter, AlignTop);
|
||||
|
||||
view_manager->switch_to(LfrfidAppViewManager::ViewType::Popup);
|
||||
app->get_emulator()->start(RfidTimerEmulator::Type::EM);
|
||||
}
|
||||
|
||||
bool LfrfidSceneEmulateEMMarine::on_event(LfrfidApp* app, LfrfidEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfrfidSceneEmulateEMMarine::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);
|
||||
|
||||
app->get_emulator()->stop();
|
||||
}
|
12
applications/lf-rfid/scene/lf-rfid-scene-emulate-emmarine.h
Normal file
12
applications/lf-rfid/scene/lf-rfid-scene-emulate-emmarine.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "lf-rfid-scene-generic.h"
|
||||
#include "../helpers/key-info.h"
|
||||
|
||||
class LfrfidSceneEmulateEMMarine : public LfrfidScene {
|
||||
public:
|
||||
void on_enter(LfrfidApp* app) final;
|
||||
bool on_event(LfrfidApp* app, LfrfidEvent* event) final;
|
||||
void on_exit(LfrfidApp* app) final;
|
||||
|
||||
private:
|
||||
};
|
34
applications/lf-rfid/scene/lf-rfid-scene-emulate-hid.cpp
Normal file
34
applications/lf-rfid/scene/lf-rfid-scene-emulate-hid.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#include "lf-rfid-scene-emulate-hid.h"
|
||||
|
||||
#include "../lf-rfid-app.h"
|
||||
#include "../lf-rfid-view-manager.h"
|
||||
#include "../lf-rfid-event.h"
|
||||
#include "../helpers/key-info.h"
|
||||
|
||||
void LfrfidSceneEmulateHID::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("HID emulation");
|
||||
popup_set_text(popup, app->get_text_store(), 64, 22, AlignCenter, AlignTop);
|
||||
|
||||
view_manager->switch_to(LfrfidAppViewManager::ViewType::Popup);
|
||||
app->get_emulator()->start(RfidTimerEmulator::Type::HID);
|
||||
}
|
||||
|
||||
bool LfrfidSceneEmulateHID::on_event(LfrfidApp* app, LfrfidEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfrfidSceneEmulateHID::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);
|
||||
|
||||
app->get_emulator()->stop();
|
||||
}
|
12
applications/lf-rfid/scene/lf-rfid-scene-emulate-hid.h
Normal file
12
applications/lf-rfid/scene/lf-rfid-scene-emulate-hid.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "lf-rfid-scene-generic.h"
|
||||
#include "../helpers/key-info.h"
|
||||
|
||||
class LfrfidSceneEmulateHID : public LfrfidScene {
|
||||
public:
|
||||
void on_enter(LfrfidApp* app) final;
|
||||
bool on_event(LfrfidApp* app, LfrfidEvent* event) final;
|
||||
void on_exit(LfrfidApp* app) final;
|
||||
|
||||
private:
|
||||
};
|
34
applications/lf-rfid/scene/lf-rfid-scene-emulate-indala.cpp
Normal file
34
applications/lf-rfid/scene/lf-rfid-scene-emulate-indala.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#include "lf-rfid-scene-emulate-indala.h"
|
||||
|
||||
#include "../lf-rfid-app.h"
|
||||
#include "../lf-rfid-view-manager.h"
|
||||
#include "../lf-rfid-event.h"
|
||||
#include "../helpers/key-info.h"
|
||||
|
||||
void LfrfidSceneEmulateIndala::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("Indala emulation");
|
||||
popup_set_text(popup, app->get_text_store(), 64, 22, AlignCenter, AlignTop);
|
||||
|
||||
view_manager->switch_to(LfrfidAppViewManager::ViewType::Popup);
|
||||
app->get_emulator()->start(RfidTimerEmulator::Type::Indala);
|
||||
}
|
||||
|
||||
bool LfrfidSceneEmulateIndala::on_event(LfrfidApp* app, LfrfidEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfrfidSceneEmulateIndala::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);
|
||||
|
||||
app->get_emulator()->stop();
|
||||
}
|
12
applications/lf-rfid/scene/lf-rfid-scene-emulate-indala.h
Normal file
12
applications/lf-rfid/scene/lf-rfid-scene-emulate-indala.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "lf-rfid-scene-generic.h"
|
||||
#include "../helpers/key-info.h"
|
||||
|
||||
class LfrfidSceneEmulateIndala : public LfrfidScene {
|
||||
public:
|
||||
void on_enter(LfrfidApp* app) final;
|
||||
bool on_event(LfrfidApp* app, LfrfidEvent* event) final;
|
||||
void on_exit(LfrfidApp* app) final;
|
||||
|
||||
private:
|
||||
};
|
14
applications/lf-rfid/scene/lf-rfid-scene-generic.h
Normal file
14
applications/lf-rfid/scene/lf-rfid-scene-generic.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include "../lf-rfid-event.h"
|
||||
|
||||
class LfrfidApp;
|
||||
|
||||
class LfrfidScene {
|
||||
public:
|
||||
virtual void on_enter(LfrfidApp* app) = 0;
|
||||
virtual bool on_event(LfrfidApp* app, LfrfidEvent* event) = 0;
|
||||
virtual void on_exit(LfrfidApp* app) = 0;
|
||||
virtual ~LfrfidScene(){};
|
||||
|
||||
private:
|
||||
};
|
34
applications/lf-rfid/scene/lf-rfid-scene-read-indala.cpp
Normal file
34
applications/lf-rfid/scene/lf-rfid-scene-read-indala.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#include "lf-rfid-scene-read-indala.h"
|
||||
|
||||
#include "../lf-rfid-app.h"
|
||||
#include "../lf-rfid-view-manager.h"
|
||||
#include "../lf-rfid-event.h"
|
||||
#include "../helpers/key-info.h"
|
||||
|
||||
void LfrfidSceneReadIndala::on_enter(LfrfidApp* app) {
|
||||
LfrfidAppViewManager* view_manager = app->get_view_manager();
|
||||
|
||||
Popup* popup = view_manager->get_popup();
|
||||
popup_set_header(popup, "LF-RFID read Indala", 64, 16, AlignCenter, AlignBottom);
|
||||
app->set_text_store("[decoder not implemented]");
|
||||
popup_set_text(popup, app->get_text_store(), 64, 22, AlignCenter, AlignTop);
|
||||
|
||||
view_manager->switch_to(LfrfidAppViewManager::ViewType::Popup);
|
||||
app->get_reader()->start(RfidReader::Type::Indala);
|
||||
}
|
||||
|
||||
bool LfrfidSceneReadIndala::on_event(LfrfidApp* app, LfrfidEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfrfidSceneReadIndala::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);
|
||||
|
||||
app->get_reader()->stop();
|
||||
}
|
15
applications/lf-rfid/scene/lf-rfid-scene-read-indala.h
Normal file
15
applications/lf-rfid/scene/lf-rfid-scene-read-indala.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include "lf-rfid-scene-generic.h"
|
||||
#include "../helpers/key-info.h"
|
||||
|
||||
class LfrfidSceneReadIndala : public LfrfidScene {
|
||||
public:
|
||||
void on_enter(LfrfidApp* app) final;
|
||||
bool on_event(LfrfidApp* app, LfrfidEvent* event) final;
|
||||
void on_exit(LfrfidApp* app) final;
|
||||
|
||||
private:
|
||||
uint32_t success_reads = 0;
|
||||
static const uint8_t data_size = LFRFID_KEY_SIZE;
|
||||
uint8_t last_data[data_size] = {0};
|
||||
};
|
80
applications/lf-rfid/scene/lf-rfid-scene-read-normal.cpp
Normal file
80
applications/lf-rfid/scene/lf-rfid-scene-read-normal.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
#include "lf-rfid-scene-read-normal.h"
|
||||
|
||||
#include "../lf-rfid-app.h"
|
||||
#include "../lf-rfid-view-manager.h"
|
||||
#include "../lf-rfid-event.h"
|
||||
#include "../helpers/key-info.h"
|
||||
|
||||
void LfrfidSceneReadNormal::on_enter(LfrfidApp* app) {
|
||||
LfrfidAppViewManager* view_manager = app->get_view_manager();
|
||||
|
||||
Popup* popup = view_manager->get_popup();
|
||||
popup_set_header(popup, "LF-RFID read EM & HID", 64, 16, AlignCenter, AlignBottom);
|
||||
app->set_text_store("waiting...");
|
||||
popup_set_text(popup, app->get_text_store(), 64, 22, AlignCenter, AlignTop);
|
||||
|
||||
view_manager->switch_to(LfrfidAppViewManager::ViewType::Popup);
|
||||
app->get_reader()->start(RfidReader::Type::Normal);
|
||||
}
|
||||
|
||||
bool LfrfidSceneReadNormal::on_event(LfrfidApp* app, LfrfidEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == LfrfidEvent::Type::Tick) {
|
||||
uint8_t data[data_size];
|
||||
LfrfidKeyType type;
|
||||
|
||||
if(app->get_reader()->read(&type, data, data_size)) {
|
||||
app->notify_green_blink();
|
||||
|
||||
if(memcmp(last_data, data, data_size) == 0) {
|
||||
success_reads++;
|
||||
} else {
|
||||
success_reads = 1;
|
||||
memcpy(last_data, data, data_size);
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
case LfrfidKeyType::KeyEmarine:
|
||||
app->set_text_store(
|
||||
"[EM] %02X %02X %02X %02X %02X\n"
|
||||
"count: %u",
|
||||
data[0],
|
||||
data[1],
|
||||
data[2],
|
||||
data[3],
|
||||
data[4],
|
||||
success_reads);
|
||||
break;
|
||||
case LfrfidKeyType::KeyHID:
|
||||
app->set_text_store(
|
||||
"[HID26] %02X %02X %02X\n"
|
||||
"count: %u",
|
||||
data[0],
|
||||
data[1],
|
||||
data[2],
|
||||
success_reads);
|
||||
break;
|
||||
}
|
||||
popup_set_text(
|
||||
app->get_view_manager()->get_popup(),
|
||||
app->get_text_store(),
|
||||
64,
|
||||
22,
|
||||
AlignCenter,
|
||||
AlignTop);
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfrfidSceneReadNormal::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);
|
||||
|
||||
app->get_reader()->stop();
|
||||
}
|
15
applications/lf-rfid/scene/lf-rfid-scene-read-normal.h
Normal file
15
applications/lf-rfid/scene/lf-rfid-scene-read-normal.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include "lf-rfid-scene-generic.h"
|
||||
#include "../helpers/key-info.h"
|
||||
|
||||
class LfrfidSceneReadNormal : public LfrfidScene {
|
||||
public:
|
||||
void on_enter(LfrfidApp* app) final;
|
||||
bool on_event(LfrfidApp* app, LfrfidEvent* event) final;
|
||||
void on_exit(LfrfidApp* app) final;
|
||||
|
||||
private:
|
||||
uint32_t success_reads = 0;
|
||||
static const uint8_t data_size = LFRFID_KEY_SIZE;
|
||||
uint8_t last_data[data_size] = {0};
|
||||
};
|
77
applications/lf-rfid/scene/lf-rfid-scene-start.cpp
Normal file
77
applications/lf-rfid/scene/lf-rfid-scene-start.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
#include "lf-rfid-scene-start.h"
|
||||
#include "../lf-rfid-app.h"
|
||||
#include "../lf-rfid-view-manager.h"
|
||||
#include "../lf-rfid-event.h"
|
||||
#include <callback-connector.h>
|
||||
|
||||
typedef enum {
|
||||
SubmenuIndexReadNormal,
|
||||
SubmenuIndexReadIndala,
|
||||
SubmenuIndexEmulateEM,
|
||||
SubmenuIndexEmulateHID,
|
||||
SubmenuIndexEmulateIndala,
|
||||
SubmenuIndexTune
|
||||
} SubmenuIndex;
|
||||
|
||||
void LfrfidSceneStart::on_enter(LfrfidApp* app) {
|
||||
LfrfidAppViewManager* view_manager = app->get_view_manager();
|
||||
Submenu* submenu = view_manager->get_submenu();
|
||||
auto callback = cbc::obtain_connector(this, &LfrfidSceneStart::submenu_callback);
|
||||
|
||||
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);
|
||||
submenu_add_item(submenu, "Emulate HID", SubmenuIndexEmulateHID, callback, app);
|
||||
submenu_add_item(submenu, "Emulate Indala", SubmenuIndexEmulateIndala, callback, app);
|
||||
submenu_add_item(submenu, "Tune", SubmenuIndexTune, callback, app);
|
||||
|
||||
view_manager->switch_to(LfrfidAppViewManager::ViewType::Submenu);
|
||||
}
|
||||
|
||||
bool LfrfidSceneStart::on_event(LfrfidApp* app, LfrfidEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == LfrfidEvent::Type::MenuSelected) {
|
||||
switch(event->payload.menu_index) {
|
||||
case SubmenuIndexReadNormal:
|
||||
app->switch_to_next_scene(LfrfidApp::Scene::ReadNormal);
|
||||
break;
|
||||
case SubmenuIndexReadIndala:
|
||||
app->switch_to_next_scene(LfrfidApp::Scene::ReadIndala);
|
||||
break;
|
||||
case SubmenuIndexEmulateEM:
|
||||
app->switch_to_next_scene(LfrfidApp::Scene::EmulateEM);
|
||||
break;
|
||||
break;
|
||||
case SubmenuIndexEmulateHID:
|
||||
app->switch_to_next_scene(LfrfidApp::Scene::EmulateHID);
|
||||
break;
|
||||
case SubmenuIndexEmulateIndala:
|
||||
app->switch_to_next_scene(LfrfidApp::Scene::EmulateIndala);
|
||||
break;
|
||||
case SubmenuIndexTune:
|
||||
app->switch_to_next_scene(LfrfidApp::Scene::Tune);
|
||||
break;
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfrfidSceneStart::on_exit(LfrfidApp* app) {
|
||||
LfrfidAppViewManager* view_manager = app->get_view_manager();
|
||||
Submenu* submenu = view_manager->get_submenu();
|
||||
|
||||
submenu_clean(submenu);
|
||||
}
|
||||
|
||||
void LfrfidSceneStart::submenu_callback(void* context, uint32_t index) {
|
||||
LfrfidApp* app = static_cast<LfrfidApp*>(context);
|
||||
LfrfidEvent event;
|
||||
|
||||
event.type = LfrfidEvent::Type::MenuSelected;
|
||||
event.payload.menu_index = index;
|
||||
|
||||
app->get_view_manager()->send_event(&event);
|
||||
}
|
13
applications/lf-rfid/scene/lf-rfid-scene-start.h
Normal file
13
applications/lf-rfid/scene/lf-rfid-scene-start.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "lf-rfid-scene-generic.h"
|
||||
#include "../helpers/rfid-timer-emulator.h"
|
||||
|
||||
class LfrfidSceneStart : public LfrfidScene {
|
||||
public:
|
||||
void on_enter(LfrfidApp* app) final;
|
||||
bool on_event(LfrfidApp* app, LfrfidEvent* event) final;
|
||||
void on_exit(LfrfidApp* app) final;
|
||||
|
||||
private:
|
||||
void submenu_callback(void* context, uint32_t index);
|
||||
};
|
35
applications/lf-rfid/scene/lf-rfid-scene-tune.cpp
Normal file
35
applications/lf-rfid/scene/lf-rfid-scene-tune.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
#include "lf-rfid-scene-tune.h"
|
||||
#include "../lf-rfid-app.h"
|
||||
#include "../lf-rfid-view-manager.h"
|
||||
#include "../lf-rfid-event.h"
|
||||
#include <callback-connector.h>
|
||||
|
||||
void LfrfidSceneTune::on_enter(LfrfidApp* app) {
|
||||
LfrfidAppViewManager* view_manager = app->get_view_manager();
|
||||
//LfRfidViewTune* tune = view_manager->get_tune();
|
||||
|
||||
view_manager->switch_to(LfrfidAppViewManager::ViewType::Tune);
|
||||
|
||||
reader.start(RfidReader::Type::Indala);
|
||||
}
|
||||
|
||||
bool LfrfidSceneTune::on_event(LfrfidApp* app, LfrfidEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == LfrfidEvent::Type::Tick) {
|
||||
LfRfidViewTune* tune = app->get_view_manager()->get_tune();
|
||||
|
||||
if(tune->is_dirty()) {
|
||||
LFRFID_TIM.Instance->ARR = tune->get_ARR();
|
||||
LFRFID_TIM.Instance->CCR1 = tune->get_CCR();
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfrfidSceneTune::on_exit(LfrfidApp* app) {
|
||||
//LfRfidViewTune* tune = app->get_view_manager()->get_tune();
|
||||
|
||||
reader.stop();
|
||||
}
|
13
applications/lf-rfid/scene/lf-rfid-scene-tune.h
Normal file
13
applications/lf-rfid/scene/lf-rfid-scene-tune.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "lf-rfid-scene-generic.h"
|
||||
#include "../helpers/rfid-reader.h"
|
||||
|
||||
class LfrfidSceneTune : public LfrfidScene {
|
||||
public:
|
||||
void on_enter(LfrfidApp* app) final;
|
||||
bool on_event(LfrfidApp* app, LfrfidEvent* event) final;
|
||||
void on_exit(LfrfidApp* app) final;
|
||||
|
||||
private:
|
||||
RfidReader reader;
|
||||
};
|
202
applications/lf-rfid/view/lf-rfid-view-tune.cpp
Normal file
202
applications/lf-rfid/view/lf-rfid-view-tune.cpp
Normal file
@ -0,0 +1,202 @@
|
||||
#include "lf-rfid-view-tune.h"
|
||||
#include <callback-connector.h>
|
||||
#include <gui/elements.h>
|
||||
#include <variant>
|
||||
#include <list>
|
||||
|
||||
struct LfRfidViewTuneModel {
|
||||
bool dirty;
|
||||
bool fine;
|
||||
uint32_t ARR;
|
||||
uint32_t CCR;
|
||||
int pos;
|
||||
};
|
||||
|
||||
void LfRfidViewTune::view_draw_callback(Canvas* canvas, void* _model) {
|
||||
LfRfidViewTuneModel* model = reinterpret_cast<LfRfidViewTuneModel*>(_model);
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
if(model->fine) {
|
||||
canvas_draw_box(
|
||||
canvas,
|
||||
128 - canvas_string_width(canvas, "Fine") - 4,
|
||||
0,
|
||||
canvas_string_width(canvas, "Fine") + 4,
|
||||
canvas_current_font_height(canvas) + 1);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
}
|
||||
canvas_draw_str_aligned(canvas, 128 - 2, 2, AlignRight, AlignTop, "Fine");
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
constexpr uint8_t buffer_size = 128;
|
||||
char buffer[buffer_size + 1];
|
||||
snprintf(
|
||||
buffer,
|
||||
buffer_size,
|
||||
"%sARR: %lu\n"
|
||||
"freq = %.4f\n"
|
||||
"%sCCR: %lu\n"
|
||||
"duty = %.4f",
|
||||
model->pos == 0 ? ">" : "",
|
||||
model->ARR,
|
||||
(float)SystemCoreClock / ((float)model->ARR + 1),
|
||||
model->pos == 1 ? ">" : "",
|
||||
model->CCR,
|
||||
((float)model->CCR + 1) / ((float)model->ARR + 1) * 100.0f);
|
||||
elements_multiline_text_aligned(canvas, 2, 2, AlignLeft, AlignTop, buffer);
|
||||
}
|
||||
|
||||
bool LfRfidViewTune::view_input_callback(InputEvent* event, void* context) {
|
||||
LfRfidViewTune* _this = reinterpret_cast<LfRfidViewTune*>(context);
|
||||
bool consumed = false;
|
||||
|
||||
// Process key presses only
|
||||
if(event->type == InputTypeShort || event->type == InputTypeRepeat) {
|
||||
consumed = true;
|
||||
|
||||
switch(event->key) {
|
||||
case InputKeyLeft:
|
||||
_this->button_left();
|
||||
break;
|
||||
case InputKeyRight:
|
||||
_this->button_right();
|
||||
break;
|
||||
case InputKeyUp:
|
||||
_this->button_up();
|
||||
break;
|
||||
case InputKeyDown:
|
||||
_this->button_down();
|
||||
break;
|
||||
case InputKeyOk:
|
||||
_this->button_ok();
|
||||
break;
|
||||
default:
|
||||
consumed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void LfRfidViewTune::button_up() {
|
||||
with_view_model_cpp(view, LfRfidViewTuneModel, model, {
|
||||
if(model->pos > 0) model->pos--;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void LfRfidViewTune::button_down() {
|
||||
with_view_model_cpp(view, LfRfidViewTuneModel, model, {
|
||||
if(model->pos < 1) model->pos++;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void LfRfidViewTune::button_left() {
|
||||
with_view_model_cpp(view, LfRfidViewTuneModel, model, {
|
||||
if(model->pos == 0) {
|
||||
if(model->fine) {
|
||||
model->ARR -= 1;
|
||||
} else {
|
||||
model->ARR -= 10;
|
||||
}
|
||||
} else if(model->pos == 1) {
|
||||
if(model->fine) {
|
||||
model->CCR -= 1;
|
||||
} else {
|
||||
model->CCR -= 10;
|
||||
}
|
||||
}
|
||||
|
||||
model->dirty = true;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void LfRfidViewTune::button_right() {
|
||||
with_view_model_cpp(view, LfRfidViewTuneModel, model, {
|
||||
if(model->pos == 0) {
|
||||
if(model->fine) {
|
||||
model->ARR += 1;
|
||||
} else {
|
||||
model->ARR += 10;
|
||||
}
|
||||
} else if(model->pos == 1) {
|
||||
if(model->fine) {
|
||||
model->CCR += 1;
|
||||
} else {
|
||||
model->CCR += 10;
|
||||
}
|
||||
}
|
||||
|
||||
model->dirty = true;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void LfRfidViewTune::button_ok() {
|
||||
with_view_model_cpp(view, LfRfidViewTuneModel, model, {
|
||||
model->fine = !model->fine;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
LfRfidViewTune::LfRfidViewTune() {
|
||||
view = view_alloc();
|
||||
view_set_context(view, this);
|
||||
view_allocate_model(view, ViewModelTypeLocking, sizeof(LfRfidViewTuneModel));
|
||||
|
||||
with_view_model_cpp(view, LfRfidViewTuneModel, model, {
|
||||
model->dirty = true;
|
||||
model->fine = false;
|
||||
model->ARR = 511;
|
||||
model->CCR = 255;
|
||||
model->pos = 0;
|
||||
return true;
|
||||
});
|
||||
|
||||
view_set_draw_callback(view, cbc::obtain_connector(this, &LfRfidViewTune::view_draw_callback));
|
||||
view_set_input_callback(
|
||||
view, cbc::obtain_connector(this, &LfRfidViewTune::view_input_callback));
|
||||
}
|
||||
|
||||
LfRfidViewTune::~LfRfidViewTune() {
|
||||
view_free(view);
|
||||
}
|
||||
|
||||
View* LfRfidViewTune::get_view() {
|
||||
return view;
|
||||
}
|
||||
|
||||
bool LfRfidViewTune::is_dirty() {
|
||||
bool result;
|
||||
with_view_model_cpp(view, LfRfidViewTuneModel, model, {
|
||||
result = model->dirty;
|
||||
model->dirty = false;
|
||||
return false;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t LfRfidViewTune::get_ARR() {
|
||||
uint32_t result;
|
||||
with_view_model_cpp(view, LfRfidViewTuneModel, model, {
|
||||
result = model->ARR;
|
||||
return false;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t LfRfidViewTune::get_CCR() {
|
||||
uint32_t result;
|
||||
with_view_model_cpp(view, LfRfidViewTuneModel, model, {
|
||||
result = model->CCR;
|
||||
return false;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
25
applications/lf-rfid/view/lf-rfid-view-tune.h
Normal file
25
applications/lf-rfid/view/lf-rfid-view-tune.h
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include <gui/view.h>
|
||||
|
||||
class LfRfidViewTune {
|
||||
public:
|
||||
LfRfidViewTune();
|
||||
~LfRfidViewTune();
|
||||
|
||||
View* get_view();
|
||||
|
||||
bool is_dirty();
|
||||
uint32_t get_ARR();
|
||||
uint32_t get_CCR();
|
||||
|
||||
private:
|
||||
View* view;
|
||||
void view_draw_callback(Canvas* canvas, void* _model);
|
||||
bool view_input_callback(InputEvent* event, void* context);
|
||||
|
||||
void button_up();
|
||||
void button_down();
|
||||
void button_left();
|
||||
void button_right();
|
||||
void button_ok();
|
||||
};
|
20
firmware/targets/api-hal-include/api-hal-ibutton.h
Normal file
20
firmware/targets/api-hal-include/api-hal-ibutton.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void api_hal_ibutton_start();
|
||||
|
||||
void api_hal_ibutton_stop();
|
||||
|
||||
void api_hal_ibutton_pin_low();
|
||||
|
||||
void api_hal_ibutton_pin_high();
|
||||
|
||||
bool api_hal_ibutton_pin_get_level();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
73
firmware/targets/api-hal-include/api-hal-rfid.h
Normal file
73
firmware/targets/api-hal-include/api-hal-rfid.h
Normal file
@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief config rfid pins to reset state
|
||||
*
|
||||
*/
|
||||
void api_hal_rfid_pins_reset();
|
||||
|
||||
/**
|
||||
* @brief config rfid pins to emulate state
|
||||
*
|
||||
*/
|
||||
void api_hal_rfid_pins_emulate();
|
||||
|
||||
/**
|
||||
* @brief config rfid pins to read state
|
||||
*
|
||||
*/
|
||||
void api_hal_rfid_pins_read();
|
||||
|
||||
/**
|
||||
* @brief config rfid timer to read state
|
||||
*
|
||||
* @param freq timer frequency
|
||||
* @param duty_cycle timer duty cycle, 0.0-1.0
|
||||
*/
|
||||
void api_hal_rfid_tim_read(float freq, float duty_cycle);
|
||||
|
||||
/**
|
||||
* @brief start read timer
|
||||
*
|
||||
*/
|
||||
void api_hal_rfid_tim_read_start();
|
||||
|
||||
/**
|
||||
* @brief stop read timer
|
||||
*
|
||||
*/
|
||||
void api_hal_rfid_tim_read_stop();
|
||||
|
||||
/**
|
||||
* @brief config rfid timer to emulate state
|
||||
*
|
||||
* @param freq timer frequency
|
||||
*/
|
||||
void api_hal_rfid_tim_emulate(float freq);
|
||||
|
||||
/**
|
||||
* @brief start emulation timer
|
||||
*
|
||||
*/
|
||||
void api_hal_rfid_tim_emulate_start();
|
||||
|
||||
/**
|
||||
* @brief stop emulation timer
|
||||
*
|
||||
*/
|
||||
void api_hal_rfid_tim_emulate_stop();
|
||||
|
||||
/**
|
||||
* @brief config rfid timers to reset state
|
||||
*
|
||||
*/
|
||||
void api_hal_rfid_tim_reset();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -23,6 +23,8 @@ template <unsigned int N> struct STOP_EXTERNING_ME {};
|
||||
#include "api-hal-flash.h"
|
||||
#include "api-hal-subghz.h"
|
||||
#include "api-hal-vibro.h"
|
||||
#include "api-hal-ibutton.h"
|
||||
#include "api-hal-rfid.h"
|
||||
|
||||
/** Init api-hal */
|
||||
void api_hal_init();
|
||||
|
@ -2,13 +2,16 @@
|
||||
#include <api-hal-gpio.h>
|
||||
#include <api-hal-version.h>
|
||||
|
||||
#define GET_SYSCFG_EXTI_PORT(gpio) (((gpio) == (GPIOA)) ? LL_SYSCFG_EXTI_PORTA :\
|
||||
#define GET_SYSCFG_EXTI_PORT(gpio) \
|
||||
(((gpio) == (GPIOA)) ? LL_SYSCFG_EXTI_PORTA : \
|
||||
((gpio) == (GPIOB)) ? LL_SYSCFG_EXTI_PORTB : \
|
||||
((gpio) == (GPIOC)) ? LL_SYSCFG_EXTI_PORTC : \
|
||||
((gpio) == (GPIOD)) ? LL_SYSCFG_EXTI_PORTD : \
|
||||
((gpio) == (GPIOE)) ? LL_SYSCFG_EXTI_PORTE : LL_SYSCFG_EXTI_PORTH)
|
||||
((gpio) == (GPIOE)) ? LL_SYSCFG_EXTI_PORTE : \
|
||||
LL_SYSCFG_EXTI_PORTH)
|
||||
|
||||
#define GPIO_PIN_MAP(pin, prefix) (((pin) == (LL_GPIO_PIN_0)) ? prefix##0 :\
|
||||
#define GPIO_PIN_MAP(pin, prefix) \
|
||||
(((pin) == (LL_GPIO_PIN_0)) ? prefix##0 : \
|
||||
((pin) == (LL_GPIO_PIN_1)) ? prefix##1 : \
|
||||
((pin) == (LL_GPIO_PIN_2)) ? prefix##2 : \
|
||||
((pin) == (LL_GPIO_PIN_3)) ? prefix##3 : \
|
||||
@ -22,7 +25,8 @@
|
||||
((pin) == (LL_GPIO_PIN_11)) ? prefix##11 : \
|
||||
((pin) == (LL_GPIO_PIN_12)) ? prefix##12 : \
|
||||
((pin) == (LL_GPIO_PIN_13)) ? prefix##13 : \
|
||||
((pin) == (LL_GPIO_PIN_14)) ? prefix##14 : prefix##15)
|
||||
((pin) == (LL_GPIO_PIN_14)) ? prefix##14 : \
|
||||
prefix##15)
|
||||
|
||||
#define GET_SYSCFG_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_SYSCFG_EXTI_LINE)
|
||||
#define GET_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_EXTI_LINE_)
|
||||
@ -34,7 +38,6 @@ void hal_gpio_init(
|
||||
const GpioMode mode,
|
||||
const GpioPull pull,
|
||||
const GpioSpeed speed) {
|
||||
|
||||
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);
|
||||
@ -104,11 +107,31 @@ void hal_gpio_init(
|
||||
__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);
|
||||
|
||||
__disable_irq();
|
||||
// enable alternate mode
|
||||
LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ALTERNATE);
|
||||
|
||||
// set alternate function
|
||||
if(gpio->pin < 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();
|
||||
}
|
||||
|
||||
static uint8_t hal_gpio_get_pin_num(const GpioPin* gpio) {
|
||||
uint8_t pin_num = 0;
|
||||
for(pin_num = 0; pin_num < GPIO_NUMBER; pin_num++) {
|
||||
if(gpio->pin & (1 << pin_num))
|
||||
break;
|
||||
if(gpio->pin & (1 << pin_num)) break;
|
||||
}
|
||||
return pin_num;
|
||||
}
|
||||
|
@ -65,6 +65,96 @@ typedef enum {
|
||||
GpioSpeedVeryHigh,
|
||||
} GpioSpeed;
|
||||
|
||||
/**
|
||||
* Gpio alternate functions
|
||||
*/
|
||||
typedef enum {
|
||||
GpioAltFn0MCO = 0, /*!< MCO Alternate Function mapping */
|
||||
GpioAltFn0LSCO = 0, /*!< LSCO Alternate Function mapping */
|
||||
GpioAltFn0JTMS_SWDIO = 0, /*!< JTMS-SWDIO Alternate Function mapping */
|
||||
GpioAltFn0JTCK_SWCLK = 0, /*!< JTCK-SWCLK Alternate Function mapping */
|
||||
GpioAltFn0JTDI = 0, /*!< JTDI Alternate Function mapping */
|
||||
GpioAltFn0RTC_OUT = 0, /*!< RCT_OUT Alternate Function mapping */
|
||||
GpioAltFn0JTD_TRACE = 0, /*!< JTDO-TRACESWO Alternate Function mapping */
|
||||
GpioAltFn0NJTRST = 0, /*!< NJTRST Alternate Function mapping */
|
||||
GpioAltFn0RTC_REFIN = 0, /*!< RTC_REFIN Alternate Function mapping */
|
||||
GpioAltFn0TRACED0 = 0, /*!< TRACED0 Alternate Function mapping */
|
||||
GpioAltFn0TRACED1 = 0, /*!< TRACED1 Alternate Function mapping */
|
||||
GpioAltFn0TRACED2 = 0, /*!< TRACED2 Alternate Function mapping */
|
||||
GpioAltFn0TRACED3 = 0, /*!< TRACED3 Alternate Function mapping */
|
||||
GpioAltFn0TRIG_INOUT = 0, /*!< TRIG_INOUT Alternate Function mapping */
|
||||
GpioAltFn0TRACECK = 0, /*!< TRACECK Alternate Function mapping */
|
||||
GpioAltFn0SYS = 0, /*!< System Function mapping */
|
||||
|
||||
GpioAltFn1TIM1 = 1, /*!< TIM1 Alternate Function mapping */
|
||||
GpioAltFn1TIM2 = 1, /*!< TIM2 Alternate Function mapping */
|
||||
GpioAltFn1LPTIM1 = 1, /*!< LPTIM1 Alternate Function mapping */
|
||||
|
||||
GpioAltFn2TIM2 = 2, /*!< TIM2 Alternate Function mapping */
|
||||
GpioAltFn2TIM1 = 2, /*!< TIM1 Alternate Function mapping */
|
||||
|
||||
GpioAltFn3SAI1 = 3, /*!< SAI1_CK1 Alternate Function mapping */
|
||||
GpioAltFn3SPI2 = 3, /*!< SPI2 Alternate Function mapping */
|
||||
GpioAltFn3TIM1 = 3, /*!< TIM1 Alternate Function mapping */
|
||||
|
||||
GpioAltFn4I2C1 = 4, /*!< I2C1 Alternate Function mapping */
|
||||
GpioAltFn4I2C3 = 4, /*!< I2C3 Alternate Function mapping */
|
||||
|
||||
GpioAltFn5SPI1 = 5, /*!< SPI1 Alternate Function mapping */
|
||||
GpioAltFn5SPI2 = 5, /*!< SPI2 Alternate Function mapping */
|
||||
|
||||
GpioAltFn6MCO = 6, /*!< MCO Alternate Function mapping */
|
||||
GpioAltFn6LSCO = 6, /*!< LSCO Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB0 = 6, /*!< RF_DTB0 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB1 = 6, /*!< RF_DTB1 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB2 = 6, /*!< RF_DTB2 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB3 = 6, /*!< RF_DTB3 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB4 = 6, /*!< RF_DTB4 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB5 = 6, /*!< RF_DTB5 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB6 = 6, /*!< RF_DTB6 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB7 = 6, /*!< RF_DTB7 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB8 = 6, /*!< RF_DTB8 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB9 = 6, /*!< RF_DTB9 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB10 = 6, /*!< RF_DTB10 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB11 = 6, /*!< RF_DTB11 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB12 = 6, /*!< RF_DTB12 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB13 = 6, /*!< RF_DTB13 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB14 = 6, /*!< RF_DTB14 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB15 = 6, /*!< RF_DTB15 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB16 = 6, /*!< RF_DTB16 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB17 = 6, /*!< RF_DTB17 Alternate Function mapping */
|
||||
GpioAltFn6RF_DTB18 = 6, /*!< RF_DTB18 Alternate Function mapping */
|
||||
GpioAltFn6RF_MISO = 6, /*!< RF_MISO Alternate Function mapping */
|
||||
GpioAltFn6RF_MOSI = 6, /*!< RF_MOSI Alternate Function mapping */
|
||||
GpioAltFn6RF_SCK = 6, /*!< RF_SCK Alternate Function mapping */
|
||||
GpioAltFn6RF_NSS = 6, /*!< RF_NSS Alternate Function mapping */
|
||||
|
||||
GpioAltFn7USART1 = 7, /*!< USART1 Alternate Function mapping */
|
||||
|
||||
GpioAltFn8LPUART1 = 8, /*!< LPUART1 Alternate Function mapping */
|
||||
GpioAltFn8IR = 8, /*!< IR Alternate Function mapping */
|
||||
|
||||
GpioAltFn9TSC = 9, /*!< TSC Alternate Function mapping */
|
||||
|
||||
GpioAltFn10QUADSPI = 10, /*!< QUADSPI Alternate Function mapping */
|
||||
GpioAltFn10USB = 10, /*!< USB Alternate Function mapping */
|
||||
|
||||
GpioAltFn11LCD = 11, /*!< LCD Alternate Function mapping */
|
||||
|
||||
GpioAltFn12COMP1 = 12, /*!< COMP1 Alternate Function mapping */
|
||||
GpioAltFn12COMP2 = 12, /*!< COMP2 Alternate Function mapping */
|
||||
GpioAltFn12TIM1 = 12, /*!< TIM1 Alternate Function mapping */
|
||||
|
||||
GpioAltFn13SAI1 = 13, /*!< SAI1 Alternate Function mapping */
|
||||
|
||||
GpioAltFn14TIM2 = 14, /*!< TIM2 Alternate Function mapping */
|
||||
GpioAltFn14TIM16 = 14, /*!< TIM16 Alternate Function mapping */
|
||||
GpioAltFn14TIM17 = 14, /*!< TIM17 Alternate Function mapping */
|
||||
GpioAltFn14LPTIM2 = 14, /*!< LPTIM2 Alternate Function mapping */
|
||||
|
||||
GpioAltFn15EVENTOUT = 15, /*!< EVENTOUT Alternate Function mapping */
|
||||
} GpioAltFn;
|
||||
|
||||
/**
|
||||
* Gpio structure
|
||||
*/
|
||||
@ -86,6 +176,21 @@ void hal_gpio_init(
|
||||
const GpioPull pull,
|
||||
const GpioSpeed speed);
|
||||
|
||||
/**
|
||||
* GPIO initialization with alternative function
|
||||
* @param gpio GpioPin
|
||||
* @param mode GpioMode
|
||||
* @param pull GpioPull
|
||||
* @param speed GpioSpeed
|
||||
* @param alt_fn GpioAltFn
|
||||
*/
|
||||
void hal_gpio_init_alt(
|
||||
const GpioPin* gpio,
|
||||
const GpioMode mode,
|
||||
const GpioPull pull,
|
||||
const GpioSpeed speed,
|
||||
const GpioAltFn alt_fn);
|
||||
|
||||
/**
|
||||
* Add and enable interrupt
|
||||
* @param gpio GpioPin
|
||||
|
24
firmware/targets/f5/api-hal/api-hal-ibutton.c
Normal file
24
firmware/targets/f5/api-hal/api-hal-ibutton.c
Normal file
@ -0,0 +1,24 @@
|
||||
#include <api-hal-ibutton.h>
|
||||
#include <api-hal-resources.h>
|
||||
|
||||
void api_hal_ibutton_start() {
|
||||
api_hal_ibutton_pin_high();
|
||||
hal_gpio_init(&ibutton_gpio, GpioModeOutputOpenDrain, GpioSpeedLow, GpioPullNo);
|
||||
}
|
||||
|
||||
void api_hal_ibutton_stop() {
|
||||
api_hal_ibutton_pin_high();
|
||||
hal_gpio_init(&ibutton_gpio, GpioModeAnalog, GpioSpeedLow, GpioPullNo);
|
||||
}
|
||||
|
||||
void api_hal_ibutton_pin_low() {
|
||||
hal_gpio_write(&ibutton_gpio, false);
|
||||
}
|
||||
|
||||
void api_hal_ibutton_pin_high() {
|
||||
hal_gpio_write(&ibutton_gpio, true);
|
||||
}
|
||||
|
||||
bool api_hal_ibutton_pin_get_level() {
|
||||
return hal_gpio_read(&ibutton_gpio);
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
void hal_pwm_set(float value, float freq, TIM_HandleTypeDef* tim, uint32_t channel) {
|
||||
tim->Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||
tim->Init.Period = (uint32_t)((SystemCoreClock / (tim->Init.Prescaler + 1)) / freq);
|
||||
tim->Init.Period = (uint32_t)((SystemCoreClock / (tim->Init.Prescaler + 1)) / freq) - 1;
|
||||
tim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||
tim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
|
||||
HAL_TIM_PWM_Init(tim);
|
||||
@ -22,7 +22,7 @@ void hal_pwm_set(float value, float freq, TIM_HandleTypeDef* tim, uint32_t chann
|
||||
|
||||
void hal_pwmn_set(float value, float freq, TIM_HandleTypeDef* tim, uint32_t channel) {
|
||||
tim->Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||
tim->Init.Period = (uint32_t)((SystemCoreClock / (tim->Init.Prescaler + 1)) / freq - 1);
|
||||
tim->Init.Period = (uint32_t)((SystemCoreClock / (tim->Init.Prescaler + 1)) / freq) - 1;
|
||||
tim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||
tim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
|
||||
HAL_TIM_PWM_Init(tim);
|
||||
|
@ -4,30 +4,21 @@
|
||||
|
||||
const InputPin input_pins[] = {
|
||||
{.port = BUTTON_UP_GPIO_Port, .pin = BUTTON_UP_Pin, .key = InputKeyUp, .inverted = true},
|
||||
{.port = BUTTON_DOWN_GPIO_Port,
|
||||
.pin = BUTTON_DOWN_Pin,
|
||||
.key = InputKeyDown,
|
||||
.inverted = true},
|
||||
{.port = BUTTON_DOWN_GPIO_Port, .pin = BUTTON_DOWN_Pin, .key = InputKeyDown, .inverted = true},
|
||||
{.port = BUTTON_RIGHT_GPIO_Port,
|
||||
.pin = BUTTON_RIGHT_Pin,
|
||||
.key = InputKeyRight,
|
||||
.inverted = true},
|
||||
{.port = BUTTON_LEFT_GPIO_Port,
|
||||
.pin = BUTTON_LEFT_Pin,
|
||||
.key = InputKeyLeft,
|
||||
.inverted = true},
|
||||
{.port = BUTTON_LEFT_GPIO_Port, .pin = BUTTON_LEFT_Pin, .key = InputKeyLeft, .inverted = true},
|
||||
{.port = BUTTON_OK_GPIO_Port, .pin = BUTTON_OK_Pin, .key = InputKeyOk, .inverted = false},
|
||||
{.port = BUTTON_BACK_GPIO_Port,
|
||||
.pin = BUTTON_BACK_Pin,
|
||||
.key = InputKeyBack,
|
||||
.inverted = true},
|
||||
{.port = BUTTON_BACK_GPIO_Port, .pin = BUTTON_BACK_Pin, .key = InputKeyBack, .inverted = true},
|
||||
};
|
||||
|
||||
const size_t input_pins_count = sizeof(input_pins) / sizeof(InputPin);
|
||||
|
||||
const GpioPin vibro_gpio = {VIBRO_GPIO_Port, VIBRO_Pin};
|
||||
const GpioPin ibutton_gpio = {iBTN_GPIO_Port, iBTN_Pin};
|
||||
const GpioPin cc1101_g0_gpio = {CC1101_G0_GPIO_Port, CC1101_G0_Pin};
|
||||
const GpioPin vibro_gpio = {.port = VIBRO_GPIO_Port, .pin = VIBRO_Pin};
|
||||
const GpioPin ibutton_gpio = {.port = iBTN_GPIO_Port, .pin = iBTN_Pin};
|
||||
const GpioPin cc1101_g0_gpio = {.port = CC1101_G0_GPIO_Port, .pin = CC1101_G0_Pin};
|
||||
|
||||
const GpioPin gpio_subghz_cs = {.port = CC1101_CS_GPIO_Port, .pin = CC1101_CS_Pin};
|
||||
const GpioPin gpio_display_cs = {.port = DISPLAY_CS_GPIO_Port, .pin = DISPLAY_CS_Pin};
|
||||
@ -43,12 +34,15 @@ const GpioPin gpio_spi_r_miso = { .port=SPI_R_MISO_GPIO_Port, .pin=SPI_R_MISO_Pi
|
||||
const GpioPin gpio_spi_r_mosi = {.port = SPI_R_MOSI_GPIO_Port, .pin = SPI_R_MOSI_Pin};
|
||||
const GpioPin gpio_spi_r_sck = {.port = SPI_R_SCK_GPIO_Port, .pin = SPI_R_SCK_Pin};
|
||||
|
||||
// external gpio's
|
||||
const GpioPin ext_pc0_gpio = {.port = GPIOC, .pin = GPIO_PIN_0};
|
||||
const GpioPin ext_pc1_gpio = {.port = GPIOC, .pin = GPIO_PIN_1};
|
||||
const GpioPin ext_pc3_gpio = {.port = GPIOC, .pin = GPIO_PIN_3};
|
||||
const GpioPin ext_pb2_gpio = {.port = GPIOB, .pin = GPIO_PIN_2};
|
||||
const GpioPin ext_pb3_gpio = {.port = GPIOB, .pin = GPIO_PIN_3};
|
||||
const GpioPin ext_pa4_gpio = {.port = GPIOA, .pin = GPIO_PIN_4};
|
||||
const GpioPin ext_pa6_gpio = {.port = GPIOA, .pin = GPIO_PIN_6};
|
||||
const GpioPin ext_pa7_gpio = {.port = GPIOA, .pin = GPIO_PIN_7};
|
||||
const GpioPin gpio_ext_pc0 = {.port = GPIOC, .pin = GPIO_PIN_0};
|
||||
const GpioPin gpio_ext_pc1 = {.port = GPIOC, .pin = GPIO_PIN_1};
|
||||
const GpioPin gpio_ext_pc3 = {.port = GPIOC, .pin = GPIO_PIN_3};
|
||||
const GpioPin gpio_ext_pb2 = {.port = GPIOB, .pin = GPIO_PIN_2};
|
||||
const GpioPin gpio_ext_pb3 = {.port = GPIOB, .pin = GPIO_PIN_3};
|
||||
const GpioPin gpio_ext_pa4 = {.port = GPIOA, .pin = GPIO_PIN_4};
|
||||
const GpioPin gpio_ext_pa6 = {.port = GPIOA, .pin = GPIO_PIN_6};
|
||||
const GpioPin gpio_ext_pa7 = {.port = GPIOA, .pin = GPIO_PIN_7};
|
||||
|
||||
const GpioPin gpio_rfid_pull = {.port = RFID_PULL_GPIO_Port, .pin = RFID_PULL_Pin};
|
||||
const GpioPin gpio_rfid_carrier_out = {.port = RFID_OUT_GPIO_Port, .pin = RFID_OUT_Pin};
|
||||
const GpioPin gpio_rfid_data_in = {.port = RFID_RF_IN_GPIO_Port, .pin = RFID_RF_IN_Pin};
|
@ -57,9 +57,6 @@ extern const GpioPin vibro_gpio;
|
||||
extern const GpioPin ibutton_gpio;
|
||||
extern const GpioPin cc1101_g0_gpio;
|
||||
|
||||
extern const GpioPin gpio_subghz_cs;
|
||||
extern const GpioPin gpio_display_cs;
|
||||
|
||||
extern const GpioPin gpio_subghz_cs;
|
||||
extern const GpioPin gpio_display_cs;
|
||||
extern const GpioPin gpio_display_rst;
|
||||
@ -74,14 +71,18 @@ extern const GpioPin gpio_spi_r_miso;
|
||||
extern const GpioPin gpio_spi_r_mosi;
|
||||
extern const GpioPin gpio_spi_r_sck;
|
||||
|
||||
extern const GpioPin ext_pc0_gpio;
|
||||
extern const GpioPin ext_pc1_gpio;
|
||||
extern const GpioPin ext_pc3_gpio;
|
||||
extern const GpioPin ext_pb2_gpio;
|
||||
extern const GpioPin ext_pb3_gpio;
|
||||
extern const GpioPin ext_pa4_gpio;
|
||||
extern const GpioPin ext_pa6_gpio;
|
||||
extern const GpioPin ext_pa7_gpio;
|
||||
extern const GpioPin gpio_ext_pc0;
|
||||
extern const GpioPin gpio_ext_pc1;
|
||||
extern const GpioPin gpio_ext_pc3;
|
||||
extern const GpioPin gpio_ext_pb2;
|
||||
extern const GpioPin gpio_ext_pb3;
|
||||
extern const GpioPin gpio_ext_pa4;
|
||||
extern const GpioPin gpio_ext_pa6;
|
||||
extern const GpioPin gpio_ext_pa7;
|
||||
|
||||
extern const GpioPin gpio_rfid_pull;
|
||||
extern const GpioPin gpio_rfid_carrier_out;
|
||||
extern const GpioPin gpio_rfid_data_in;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
202
firmware/targets/f5/api-hal/api-hal-rfid.c
Normal file
202
firmware/targets/f5/api-hal/api-hal-rfid.c
Normal file
@ -0,0 +1,202 @@
|
||||
#include <api-hal-rfid.h>
|
||||
#include <api-hal-ibutton.h>
|
||||
#include <api-hal-resources.h>
|
||||
|
||||
void api_hal_rfid_pins_reset() {
|
||||
// ibutton bus disable
|
||||
api_hal_ibutton_stop();
|
||||
|
||||
// pulldown rfid antenna
|
||||
hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo);
|
||||
hal_gpio_write(&gpio_rfid_carrier_out, true);
|
||||
|
||||
// from both sides
|
||||
hal_gpio_init(&gpio_rfid_pull, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo);
|
||||
hal_gpio_write(&gpio_rfid_pull, true);
|
||||
}
|
||||
|
||||
void api_hal_rfid_pins_emulate() {
|
||||
// ibutton low
|
||||
api_hal_ibutton_start();
|
||||
api_hal_ibutton_pin_low();
|
||||
|
||||
// pull pin to timer out
|
||||
hal_gpio_init_alt(
|
||||
&gpio_rfid_pull, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo, GpioAltFn1TIM1);
|
||||
|
||||
// pull rfid antenna from carrier side
|
||||
hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo);
|
||||
hal_gpio_write(&gpio_rfid_carrier_out, true);
|
||||
}
|
||||
|
||||
void api_hal_rfid_pins_read() {
|
||||
// ibutton low
|
||||
api_hal_ibutton_start();
|
||||
api_hal_ibutton_pin_low();
|
||||
|
||||
// dont pull rfid antenna
|
||||
hal_gpio_init(&gpio_rfid_pull, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo);
|
||||
hal_gpio_write(&gpio_rfid_pull, false);
|
||||
|
||||
// carrier pin to timer out
|
||||
hal_gpio_init_alt(
|
||||
&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo, GpioAltFn1TIM1);
|
||||
|
||||
// comparator in
|
||||
hal_gpio_init(&gpio_rfid_data_in, GpioModeAnalog, GpioSpeedLow, GpioPullNo);
|
||||
}
|
||||
|
||||
void api_hal_rfid_tim_read(float freq, float duty_cycle) {
|
||||
// TODO LL init
|
||||
uint32_t period = (uint32_t)((SystemCoreClock) / freq) - 1;
|
||||
|
||||
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
|
||||
TIM_MasterConfigTypeDef sMasterConfig = {0};
|
||||
TIM_OC_InitTypeDef sConfigOC = {0};
|
||||
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
|
||||
|
||||
// basic PWM setup with needed freq and internal clock
|
||||
LFRFID_TIM.Instance = TIM1;
|
||||
LFRFID_TIM.Init.Prescaler = 0;
|
||||
LFRFID_TIM.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||
LFRFID_TIM.Init.Period = period;
|
||||
LFRFID_TIM.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||
LFRFID_TIM.Init.RepetitionCounter = 0;
|
||||
LFRFID_TIM.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
|
||||
if(HAL_TIM_Base_Init(&LFRFID_TIM) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
|
||||
if(HAL_TIM_ConfigClockSource(&LFRFID_TIM, &sClockSourceConfig) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
if(HAL_TIM_PWM_Init(&LFRFID_TIM) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
// no master-slave mode
|
||||
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
|
||||
sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
|
||||
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
|
||||
if(HAL_TIMEx_MasterConfigSynchronization(&LFRFID_TIM, &sMasterConfig) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
// pwm config
|
||||
sConfigOC.OCMode = TIM_OCMODE_PWM1;
|
||||
sConfigOC.Pulse = (uint32_t)(LFRFID_TIM.Init.Period * duty_cycle);
|
||||
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
|
||||
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
|
||||
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
|
||||
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
|
||||
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
|
||||
if(HAL_TIM_OC_ConfigChannel(&LFRFID_TIM, &sConfigOC, LFRFID_CH) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
// no deadtime
|
||||
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
|
||||
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
|
||||
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
|
||||
sBreakDeadTimeConfig.DeadTime = 0;
|
||||
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
|
||||
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
|
||||
sBreakDeadTimeConfig.BreakFilter = 0;
|
||||
sBreakDeadTimeConfig.BreakAFMode = TIM_BREAK_AFMODE_INPUT;
|
||||
sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE;
|
||||
sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH;
|
||||
sBreakDeadTimeConfig.Break2Filter = 0;
|
||||
sBreakDeadTimeConfig.Break2AFMode = TIM_BREAK_AFMODE_INPUT;
|
||||
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
|
||||
if(HAL_TIMEx_ConfigBreakDeadTime(&LFRFID_TIM, &sBreakDeadTimeConfig) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
}
|
||||
|
||||
void api_hal_rfid_tim_read_start() {
|
||||
HAL_TIMEx_PWMN_Start(&LFRFID_TIM, LFRFID_CH);
|
||||
}
|
||||
|
||||
void api_hal_rfid_tim_read_stop() {
|
||||
HAL_TIMEx_PWMN_Stop(&LFRFID_TIM, LFRFID_CH);
|
||||
}
|
||||
|
||||
void api_hal_rfid_tim_emulate(float freq) {
|
||||
// TODO LL init
|
||||
uint32_t prescaler = (uint32_t)((SystemCoreClock) / freq) - 1;
|
||||
|
||||
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
|
||||
TIM_MasterConfigTypeDef sMasterConfig = {0};
|
||||
TIM_OC_InitTypeDef sConfigOC = {0};
|
||||
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
|
||||
|
||||
// basic PWM setup with needed freq and internal clock
|
||||
LFRFID_TIM.Instance = TIM1;
|
||||
LFRFID_TIM.Init.Prescaler = prescaler;
|
||||
LFRFID_TIM.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||
LFRFID_TIM.Init.Period = 1;
|
||||
LFRFID_TIM.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||
LFRFID_TIM.Init.RepetitionCounter = 0;
|
||||
LFRFID_TIM.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
|
||||
if(HAL_TIM_Base_Init(&LFRFID_TIM) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
|
||||
if(HAL_TIM_ConfigClockSource(&LFRFID_TIM, &sClockSourceConfig) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
if(HAL_TIM_PWM_Init(&LFRFID_TIM) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
// no master-slave mode
|
||||
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
|
||||
sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
|
||||
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
|
||||
if(HAL_TIMEx_MasterConfigSynchronization(&LFRFID_TIM, &sMasterConfig) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
// pwm config
|
||||
sConfigOC.OCMode = TIM_OCMODE_PWM1;
|
||||
sConfigOC.Pulse = 1;
|
||||
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
|
||||
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
|
||||
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
|
||||
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
|
||||
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
|
||||
if(HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, LFRFID_CH) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
// no deadtime
|
||||
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
|
||||
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
|
||||
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
|
||||
sBreakDeadTimeConfig.DeadTime = 0;
|
||||
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
|
||||
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
|
||||
sBreakDeadTimeConfig.BreakFilter = 0;
|
||||
sBreakDeadTimeConfig.BreakAFMode = TIM_BREAK_AFMODE_INPUT;
|
||||
sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE;
|
||||
sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH;
|
||||
sBreakDeadTimeConfig.Break2Filter = 0;
|
||||
sBreakDeadTimeConfig.Break2AFMode = TIM_BREAK_AFMODE_INPUT;
|
||||
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
|
||||
if(HAL_TIMEx_ConfigBreakDeadTime(&LFRFID_TIM, &sBreakDeadTimeConfig) != HAL_OK) {
|
||||
Error_Handler();
|
||||
}
|
||||
}
|
||||
|
||||
void api_hal_rfid_tim_emulate_start() {
|
||||
HAL_TIM_PWM_Start_IT(&LFRFID_TIM, LFRFID_CH);
|
||||
HAL_TIM_Base_Start_IT(&LFRFID_TIM);
|
||||
}
|
||||
|
||||
void api_hal_rfid_tim_emulate_stop() {
|
||||
HAL_TIM_Base_Stop(&LFRFID_TIM);
|
||||
HAL_TIM_PWM_Stop(&LFRFID_TIM, LFRFID_CH);
|
||||
}
|
||||
|
||||
void api_hal_rfid_tim_reset() {
|
||||
}
|
Loading…
Reference in New Issue
Block a user