[FL-2529][FL-1628] New LF-RFID subsystem (#1601)
* Makefile: unit tests pack * RFID: pulse joiner and its unit test * Move pulse protocol helpers to appropriate place * Drop pulse_joiner tests * Generic protocol, protocols dictionary, unit test * Protocol dict unit test * iButton: protocols dictionary * Lib: varint * Lib: profiler * Unit test: varint * rfid: worker mockup * LFRFID: em4100 unit test * Storage: file_exist function * rfid: fsk osc * rfid: generic fsk demodulator * rfid: protocol em4100 * rfid: protocol h10301 * rfid: protocol io prox xsf * Unit test: rfid protocols * rfid: new hal * rfid: raw worker * Unit test: fix error output * rfid: worker * rfid: plain c cli * fw: migrate to scons * lfrfid: full io prox support * unit test: io prox protocol * SubGHZ: move bit defines to source * FSK oscillator: level duration compability * libs: bit manipulation library * lfrfid: ioprox protocol, use bit library and new level duration method of FSK ocillator * bit lib: unit tests * Bit lib: parity tests, remove every nth bit, copy bits * Lfrfid: awid protocol * bit lib: uint16 and uint32 getters, unit tests * lfrfid: FDX-B read, draft version * Minunit: better memeq assert * bit lib: reverse, print, print regions * Protocol dict: get protocol features, get protocol validate count * lfrfid worker: improved read * lfrfid raw worker: psk support * Cli: rfid plain C cli * protocol AWID: render * protocol em4100: render * protocol h10301: render * protocol indala26: support every indala 26 scramble * Protocol IO Prox: render * Protocol FDX-B: advanced read * lfrfid: remove unused test function * lfrfid: fix os primitives * bit lib: crc16 and unit tests * FDX-B: save data * lfrfid worker: increase stream size. Alloc raw worker only when needed. * lfrfid: indala26 emulation * lfrfid: prepare to write * lfrfid: fdx-b emulation * lfrfid: awid, ioprox write * lfrfid: write t55xx w\o validation * lfrfid: better t55xx block0 handling * lfrfid: use new t5577 functions in worker * lfrfid: improve protocol description * lfrfid: write and verify * lfrfid: delete cpp cli * lfrfid: improve worker usage * lfrfid-app: step to new worker * lfrfid: old indala (I40134) load fallback * lfrfid: indala26, recover wrong synced data * lfrfid: remove old worker * lfrfid app: dummy read screen * lfrfid app: less dummy read screen * lfrfid: generic 96-bit HID protocol (covers up to HID 37-bit) * rename * lfrfid: improve indala26 read * lfrfid: generic 192-bit HID protocol (covers all HID extended) * lfrfid: TODO about HID render * lfrfid: new protocol FDX-A * lfrfid-app: correct worker stop on exit * misc fixes * lfrfid: FDX-A and HID distinguishability has been fixed. * lfrfid: decode HID size header and render it (#1612) * lfrfid: rename HID96 and HID192 to HIDProx and HIDExt * lfrfid: extra actions scene * lfrfid: decode generic HID Proximity size lazily (#1618) * lib: stream of data buffers concept * lfrfid: raw file helper * lfrfid: changed raw worker api * lfrfid: packed varint pair * lfrfid: read stream speedup * lfrfid app: show read mode * Documentation * lfrfid app: raw read gui * lfrfid app: storage check for raw read * memleak fix * review fixes * lfrfid app: read blink color * lfrfid app: reset key name after read * review fixes * lfrfid app: fix copypasted text * review fixes * lfrfid: disable debug gpio * lfrfid: card detection events * lfrfid: change validation color from magenta to green * Update core_defines. * lfrfid: prefix fdx-b id by zeroes * lfrfid: parse up to 43-bit HID Proximity keys (#1640) * Fbt: downgrade toolchain and fix PS1 * lfrfid: fix unit tests * lfrfid app: remove printf * lfrfid: indala26, use bit 55 as data * lfrfid: indala26, better brief format * lfrfid: indala26, loading fallback * lfrfid: read timing tuning Co-authored-by: James Ide <ide@users.noreply.github.com> Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
@@ -1,126 +0,0 @@
|
||||
#include "encoder_cyfral.h"
|
||||
#include <furi_hal.h>
|
||||
|
||||
#define CYFRAL_DATA_SIZE sizeof(uint16_t)
|
||||
#define CYFRAL_PERIOD (125 * furi_hal_cortex_instructions_per_microsecond())
|
||||
#define CYFRAL_0_LOW (CYFRAL_PERIOD * 0.66f)
|
||||
#define CYFRAL_0_HI (CYFRAL_PERIOD * 0.33f)
|
||||
#define CYFRAL_1_LOW (CYFRAL_PERIOD * 0.33f)
|
||||
#define CYFRAL_1_HI (CYFRAL_PERIOD * 0.66f)
|
||||
|
||||
#define CYFRAL_SET_DATA(level, len) \
|
||||
*polarity = level; \
|
||||
*length = len;
|
||||
|
||||
struct EncoderCyfral {
|
||||
uint32_t data;
|
||||
uint32_t index;
|
||||
};
|
||||
|
||||
EncoderCyfral* encoder_cyfral_alloc() {
|
||||
EncoderCyfral* cyfral = malloc(sizeof(EncoderCyfral));
|
||||
encoder_cyfral_reset(cyfral);
|
||||
return cyfral;
|
||||
}
|
||||
|
||||
void encoder_cyfral_free(EncoderCyfral* cyfral) {
|
||||
free(cyfral);
|
||||
}
|
||||
|
||||
void encoder_cyfral_reset(EncoderCyfral* cyfral) {
|
||||
cyfral->data = 0;
|
||||
cyfral->index = 0;
|
||||
}
|
||||
|
||||
uint32_t cyfral_encoder_encode(const uint16_t data) {
|
||||
uint32_t value = 0;
|
||||
for(int8_t i = 0; i <= 7; i++) {
|
||||
switch((data >> (i * 2)) & 0b00000011) {
|
||||
case 0b11:
|
||||
value = value << 4;
|
||||
value += 0b00000111;
|
||||
break;
|
||||
case 0b10:
|
||||
value = value << 4;
|
||||
value += 0b00001011;
|
||||
break;
|
||||
case 0b01:
|
||||
value = value << 4;
|
||||
value += 0b00001101;
|
||||
break;
|
||||
case 0b00:
|
||||
value = value << 4;
|
||||
value += 0b00001110;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void encoder_cyfral_set_data(EncoderCyfral* cyfral, const uint8_t* data, size_t data_size) {
|
||||
furi_assert(cyfral);
|
||||
furi_check(data_size >= CYFRAL_DATA_SIZE);
|
||||
uint16_t intermediate;
|
||||
memcpy(&intermediate, data, CYFRAL_DATA_SIZE);
|
||||
cyfral->data = cyfral_encoder_encode(intermediate);
|
||||
}
|
||||
|
||||
void encoder_cyfral_get_pulse(EncoderCyfral* cyfral, bool* polarity, uint32_t* length) {
|
||||
if(cyfral->index < 8) {
|
||||
// start word (0b0001)
|
||||
switch(cyfral->index) {
|
||||
case 0:
|
||||
CYFRAL_SET_DATA(false, CYFRAL_0_LOW);
|
||||
break;
|
||||
case 1:
|
||||
CYFRAL_SET_DATA(true, CYFRAL_0_HI);
|
||||
break;
|
||||
case 2:
|
||||
CYFRAL_SET_DATA(false, CYFRAL_0_LOW);
|
||||
break;
|
||||
case 3:
|
||||
CYFRAL_SET_DATA(true, CYFRAL_0_HI);
|
||||
break;
|
||||
case 4:
|
||||
CYFRAL_SET_DATA(false, CYFRAL_0_LOW);
|
||||
break;
|
||||
case 5:
|
||||
CYFRAL_SET_DATA(true, CYFRAL_0_HI);
|
||||
break;
|
||||
case 6:
|
||||
CYFRAL_SET_DATA(false, CYFRAL_1_LOW);
|
||||
break;
|
||||
case 7:
|
||||
CYFRAL_SET_DATA(true, CYFRAL_1_HI);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// data
|
||||
uint8_t data_start_index = cyfral->index - 8;
|
||||
bool clock_polarity = (data_start_index) % 2;
|
||||
uint8_t bit_index = (data_start_index) / 2;
|
||||
bool bit_value = ((cyfral->data >> bit_index) & 1);
|
||||
|
||||
if(!clock_polarity) {
|
||||
if(bit_value) {
|
||||
CYFRAL_SET_DATA(false, CYFRAL_1_LOW);
|
||||
} else {
|
||||
CYFRAL_SET_DATA(false, CYFRAL_0_LOW);
|
||||
}
|
||||
} else {
|
||||
if(bit_value) {
|
||||
CYFRAL_SET_DATA(true, CYFRAL_1_HI);
|
||||
} else {
|
||||
CYFRAL_SET_DATA(true, CYFRAL_0_HI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cyfral->index++;
|
||||
if(cyfral->index >= (9 * 4 * 2)) {
|
||||
cyfral->index = 0;
|
||||
}
|
||||
}
|
@@ -1,54 +0,0 @@
|
||||
/**
|
||||
* @file encoder_cyfral.h
|
||||
*
|
||||
* Cyfral pulse format encoder
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct EncoderCyfral EncoderCyfral;
|
||||
|
||||
/**
|
||||
* Allocate Cyfral encoder
|
||||
* @return EncoderCyfral*
|
||||
*/
|
||||
EncoderCyfral* encoder_cyfral_alloc();
|
||||
|
||||
/**
|
||||
* Deallocate Cyfral encoder
|
||||
* @param cyfral
|
||||
*/
|
||||
void encoder_cyfral_free(EncoderCyfral* cyfral);
|
||||
|
||||
/**
|
||||
* Reset Cyfral encoder
|
||||
* @param cyfral
|
||||
*/
|
||||
void encoder_cyfral_reset(EncoderCyfral* cyfral);
|
||||
|
||||
/**
|
||||
* Set data to be encoded to Cyfral pulse format, 2 bytes
|
||||
* @param cyfral
|
||||
* @param data
|
||||
* @param data_size
|
||||
*/
|
||||
void encoder_cyfral_set_data(EncoderCyfral* cyfral, const uint8_t* data, size_t data_size);
|
||||
|
||||
/**
|
||||
* Pop pulse from Cyfral encoder
|
||||
* @param cyfral
|
||||
* @param polarity
|
||||
* @param length
|
||||
*/
|
||||
void encoder_cyfral_get_pulse(EncoderCyfral* cyfral, bool* polarity, uint32_t* length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -1,93 +0,0 @@
|
||||
#include "encoder_metakom.h"
|
||||
#include <furi_hal.h>
|
||||
|
||||
#define METAKOM_DATA_SIZE sizeof(uint32_t)
|
||||
#define METAKOM_PERIOD (125 * furi_hal_cortex_instructions_per_microsecond())
|
||||
#define METAKOM_0_LOW (METAKOM_PERIOD * 0.33f)
|
||||
#define METAKOM_0_HI (METAKOM_PERIOD * 0.66f)
|
||||
#define METAKOM_1_LOW (METAKOM_PERIOD * 0.66f)
|
||||
#define METAKOM_1_HI (METAKOM_PERIOD * 0.33f)
|
||||
|
||||
#define METAKOM_SET_DATA(level, len) \
|
||||
*polarity = !level; \
|
||||
*length = len;
|
||||
|
||||
struct EncoderMetakom {
|
||||
uint32_t data;
|
||||
uint32_t index;
|
||||
};
|
||||
|
||||
EncoderMetakom* encoder_metakom_alloc() {
|
||||
EncoderMetakom* metakom = malloc(sizeof(EncoderMetakom));
|
||||
encoder_metakom_reset(metakom);
|
||||
return metakom;
|
||||
}
|
||||
|
||||
void encoder_metakom_free(EncoderMetakom* metakom) {
|
||||
free(metakom);
|
||||
}
|
||||
|
||||
void encoder_metakom_reset(EncoderMetakom* metakom) {
|
||||
metakom->data = 0;
|
||||
metakom->index = 0;
|
||||
}
|
||||
|
||||
void encoder_metakom_set_data(EncoderMetakom* metakom, const uint8_t* data, size_t data_size) {
|
||||
furi_assert(metakom);
|
||||
furi_check(data_size >= METAKOM_DATA_SIZE);
|
||||
memcpy(&metakom->data, data, METAKOM_DATA_SIZE);
|
||||
}
|
||||
|
||||
void encoder_metakom_get_pulse(EncoderMetakom* metakom, bool* polarity, uint32_t* length) {
|
||||
if(metakom->index == 0) {
|
||||
// sync bit
|
||||
METAKOM_SET_DATA(true, METAKOM_PERIOD);
|
||||
} else if(metakom->index >= 1 && metakom->index <= 6) {
|
||||
// start word (0b010)
|
||||
switch(metakom->index) {
|
||||
case 1:
|
||||
METAKOM_SET_DATA(false, METAKOM_0_LOW);
|
||||
break;
|
||||
case 2:
|
||||
METAKOM_SET_DATA(true, METAKOM_0_HI);
|
||||
break;
|
||||
case 3:
|
||||
METAKOM_SET_DATA(false, METAKOM_1_LOW);
|
||||
break;
|
||||
case 4:
|
||||
METAKOM_SET_DATA(true, METAKOM_1_HI);
|
||||
break;
|
||||
case 5:
|
||||
METAKOM_SET_DATA(false, METAKOM_0_LOW);
|
||||
break;
|
||||
case 6:
|
||||
METAKOM_SET_DATA(true, METAKOM_0_HI);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// data
|
||||
uint8_t data_start_index = metakom->index - 7;
|
||||
bool clock_polarity = (data_start_index) % 2;
|
||||
uint8_t bit_index = (data_start_index) / 2;
|
||||
bool bit_value = (metakom->data >> (32 - 1 - bit_index)) & 1;
|
||||
|
||||
if(!clock_polarity) {
|
||||
if(bit_value) {
|
||||
METAKOM_SET_DATA(false, METAKOM_1_LOW);
|
||||
} else {
|
||||
METAKOM_SET_DATA(false, METAKOM_0_LOW);
|
||||
}
|
||||
} else {
|
||||
if(bit_value) {
|
||||
METAKOM_SET_DATA(true, METAKOM_1_HI);
|
||||
} else {
|
||||
METAKOM_SET_DATA(true, METAKOM_0_HI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
metakom->index++;
|
||||
if(metakom->index >= (1 + 3 * 2 + 32 * 2)) {
|
||||
metakom->index = 0;
|
||||
}
|
||||
}
|
@@ -1,54 +0,0 @@
|
||||
/**
|
||||
* @file encoder_metakom.h
|
||||
*
|
||||
* Metakom pulse format encoder
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct EncoderMetakom EncoderMetakom;
|
||||
|
||||
/**
|
||||
* Allocate Metakom encoder
|
||||
* @return EncoderMetakom*
|
||||
*/
|
||||
EncoderMetakom* encoder_metakom_alloc();
|
||||
|
||||
/**
|
||||
* Deallocate Metakom encoder
|
||||
* @param metakom
|
||||
*/
|
||||
void encoder_metakom_free(EncoderMetakom* metakom);
|
||||
|
||||
/**
|
||||
* Reset Metakom encoder
|
||||
* @param metakom
|
||||
*/
|
||||
void encoder_metakom_reset(EncoderMetakom* metakom);
|
||||
|
||||
/**
|
||||
* Set data to be encoded to Metakom pulse format, 4 bytes
|
||||
* @param metakom
|
||||
* @param data
|
||||
* @param data_size
|
||||
*/
|
||||
void encoder_metakom_set_data(EncoderMetakom* metakom, const uint8_t* data, size_t data_size);
|
||||
|
||||
/**
|
||||
* Pop pulse from Metakom encoder
|
||||
* @param cyfral
|
||||
* @param polarity
|
||||
* @param length
|
||||
*/
|
||||
void encoder_metakom_get_pulse(EncoderMetakom* metakom, bool* polarity, uint32_t* length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@@ -29,34 +29,21 @@ iButtonWorker* ibutton_worker_alloc() {
|
||||
worker->slave = onewire_slave_alloc();
|
||||
worker->writer = ibutton_writer_alloc(worker->host);
|
||||
worker->device = onewire_device_alloc(0, 0, 0, 0, 0, 0, 0, 0);
|
||||
worker->pulse_decoder = pulse_decoder_alloc();
|
||||
worker->protocol_cyfral = protocol_cyfral_alloc();
|
||||
worker->protocol_metakom = protocol_metakom_alloc();
|
||||
worker->messages = furi_message_queue_alloc(1, sizeof(iButtonMessage));
|
||||
|
||||
worker->mode_index = iButtonWorkerIdle;
|
||||
worker->last_dwt_value = 0;
|
||||
worker->read_cb = NULL;
|
||||
worker->write_cb = NULL;
|
||||
worker->emulate_cb = NULL;
|
||||
worker->cb_ctx = NULL;
|
||||
|
||||
worker->encoder_cyfral = encoder_cyfral_alloc();
|
||||
worker->encoder_metakom = encoder_metakom_alloc();
|
||||
|
||||
worker->thread = furi_thread_alloc();
|
||||
furi_thread_set_name(worker->thread, "ibutton_worker");
|
||||
furi_thread_set_callback(worker->thread, ibutton_worker_thread);
|
||||
furi_thread_set_context(worker->thread, worker);
|
||||
furi_thread_set_stack_size(worker->thread, 2048);
|
||||
|
||||
pulse_decoder_add_protocol(
|
||||
worker->pulse_decoder,
|
||||
protocol_cyfral_get_protocol(worker->protocol_cyfral),
|
||||
PulseProtocolCyfral);
|
||||
pulse_decoder_add_protocol(
|
||||
worker->pulse_decoder,
|
||||
protocol_metakom_get_protocol(worker->protocol_metakom),
|
||||
PulseProtocolMetakom);
|
||||
worker->protocols = protocol_dict_alloc(ibutton_protocols, iButtonProtocolMax);
|
||||
|
||||
return worker;
|
||||
}
|
||||
@@ -113,10 +100,6 @@ void ibutton_worker_stop(iButtonWorker* worker) {
|
||||
}
|
||||
|
||||
void ibutton_worker_free(iButtonWorker* worker) {
|
||||
pulse_decoder_free(worker->pulse_decoder);
|
||||
protocol_metakom_free(worker->protocol_metakom);
|
||||
protocol_cyfral_free(worker->protocol_cyfral);
|
||||
|
||||
ibutton_writer_free(worker->writer);
|
||||
|
||||
onewire_slave_free(worker->slave);
|
||||
@@ -124,8 +107,7 @@ void ibutton_worker_free(iButtonWorker* worker) {
|
||||
onewire_host_free(worker->host);
|
||||
onewire_device_free(worker->device);
|
||||
|
||||
encoder_cyfral_free(worker->encoder_cyfral);
|
||||
encoder_metakom_free(worker->encoder_metakom);
|
||||
protocol_dict_free(worker->protocols);
|
||||
|
||||
furi_message_queue_free(worker->messages);
|
||||
|
||||
|
@@ -10,21 +10,13 @@
|
||||
#include "../one_wire_host.h"
|
||||
#include "../one_wire_slave.h"
|
||||
#include "../one_wire_device.h"
|
||||
#include "../pulse_protocols/pulse_decoder.h"
|
||||
#include "pulse_protocols/protocol_cyfral.h"
|
||||
#include "pulse_protocols/protocol_metakom.h"
|
||||
#include "encoder/encoder_cyfral.h"
|
||||
#include "encoder/encoder_metakom.h"
|
||||
#include <toolbox/protocols/protocol_dict.h>
|
||||
#include "protocols/ibutton_protocols.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
PulseProtocolCyfral,
|
||||
PulseProtocolMetakom,
|
||||
} PulseProtocols;
|
||||
|
||||
typedef struct {
|
||||
const uint32_t quant;
|
||||
void (*const start)(iButtonWorker* worker);
|
||||
@@ -39,11 +31,6 @@ typedef enum {
|
||||
iButtonWorkerEmulate = 3,
|
||||
} iButtonWorkerMode;
|
||||
|
||||
typedef enum {
|
||||
iButtonEmulateModeCyfral,
|
||||
iButtonEmulateModeMetakom,
|
||||
} iButtonEmulateMode;
|
||||
|
||||
struct iButtonWorker {
|
||||
iButtonKey* key_p;
|
||||
uint8_t* key_data;
|
||||
@@ -55,19 +42,13 @@ struct iButtonWorker {
|
||||
FuriMessageQueue* messages;
|
||||
FuriThread* thread;
|
||||
|
||||
PulseDecoder* pulse_decoder;
|
||||
ProtocolCyfral* protocol_cyfral;
|
||||
ProtocolMetakom* protocol_metakom;
|
||||
uint32_t last_dwt_value;
|
||||
|
||||
iButtonWorkerReadCallback read_cb;
|
||||
iButtonWorkerWriteCallback write_cb;
|
||||
iButtonWorkerEmulateCallback emulate_cb;
|
||||
void* cb_ctx;
|
||||
|
||||
EncoderCyfral* encoder_cyfral;
|
||||
EncoderMetakom* encoder_metakom;
|
||||
iButtonEmulateMode emulate_mode;
|
||||
ProtocolDict* protocols;
|
||||
iButtonProtocol protocol_to_encode;
|
||||
};
|
||||
|
||||
extern const iButtonWorkerModeType ibutton_worker_modes[];
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#include <furi_hal.h>
|
||||
#include "ibutton_worker_i.h"
|
||||
#include "ibutton_key_command.h"
|
||||
#include <stream_buffer.h>
|
||||
|
||||
void ibutton_worker_mode_idle_start(iButtonWorker* worker);
|
||||
void ibutton_worker_mode_idle_tick(iButtonWorker* worker);
|
||||
@@ -62,59 +63,86 @@ void ibutton_worker_mode_idle_stop(iButtonWorker* worker) {
|
||||
|
||||
/*********************** READ ***********************/
|
||||
|
||||
typedef struct {
|
||||
uint32_t last_dwt_value;
|
||||
StreamBufferHandle_t stream;
|
||||
} iButtonReadContext;
|
||||
|
||||
void ibutton_worker_comparator_callback(bool level, void* context) {
|
||||
iButtonWorker* worker = context;
|
||||
iButtonReadContext* read_context = context;
|
||||
|
||||
uint32_t current_dwt_value = DWT->CYCCNT;
|
||||
|
||||
pulse_decoder_process_pulse(
|
||||
worker->pulse_decoder, level, current_dwt_value - worker->last_dwt_value);
|
||||
LevelDuration data =
|
||||
level_duration_make(level, current_dwt_value - read_context->last_dwt_value);
|
||||
xStreamBufferSend(read_context->stream, &data, sizeof(LevelDuration), 0);
|
||||
|
||||
worker->last_dwt_value = current_dwt_value;
|
||||
read_context->last_dwt_value = current_dwt_value;
|
||||
}
|
||||
|
||||
bool ibutton_worker_read_comparator(iButtonWorker* worker) {
|
||||
bool result = false;
|
||||
|
||||
pulse_decoder_reset(worker->pulse_decoder);
|
||||
protocol_dict_decoders_start(worker->protocols);
|
||||
|
||||
furi_hal_rfid_pins_reset();
|
||||
// pulldown pull pin, we sense the signal through the analog part of the RFID schematic
|
||||
furi_hal_rfid_pin_pull_pulldown();
|
||||
furi_hal_rfid_comp_set_callback(ibutton_worker_comparator_callback, worker);
|
||||
worker->last_dwt_value = DWT->CYCCNT;
|
||||
|
||||
iButtonReadContext read_context = {
|
||||
.last_dwt_value = DWT->CYCCNT,
|
||||
.stream = xStreamBufferCreate(sizeof(LevelDuration) * 512, 1),
|
||||
};
|
||||
|
||||
furi_hal_rfid_comp_set_callback(ibutton_worker_comparator_callback, &read_context);
|
||||
furi_hal_rfid_comp_start();
|
||||
|
||||
// TODO: rework with thread events, "pulse_decoder_get_decoded_index_with_timeout"
|
||||
furi_delay_ms(100);
|
||||
int32_t decoded_index = pulse_decoder_get_decoded_index(worker->pulse_decoder);
|
||||
if(decoded_index >= 0) {
|
||||
pulse_decoder_get_data(
|
||||
worker->pulse_decoder, decoded_index, worker->key_data, ibutton_key_get_max_size());
|
||||
}
|
||||
uint32_t tick_start = furi_get_tick();
|
||||
while(true) {
|
||||
LevelDuration level;
|
||||
size_t ret = xStreamBufferReceive(read_context.stream, &level, sizeof(LevelDuration), 100);
|
||||
|
||||
switch(decoded_index) {
|
||||
case PulseProtocolCyfral:
|
||||
furi_check(worker->key_p != NULL);
|
||||
ibutton_key_set_type(worker->key_p, iButtonKeyCyfral);
|
||||
ibutton_key_set_data(worker->key_p, worker->key_data, ibutton_key_get_max_size());
|
||||
result = true;
|
||||
break;
|
||||
case PulseProtocolMetakom:
|
||||
furi_check(worker->key_p != NULL);
|
||||
ibutton_key_set_type(worker->key_p, iButtonKeyMetakom);
|
||||
ibutton_key_set_data(worker->key_p, worker->key_data, ibutton_key_get_max_size());
|
||||
result = true;
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if((furi_get_tick() - tick_start) > 100) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(ret > 0) {
|
||||
ProtocolId decoded_index = protocol_dict_decoders_feed(
|
||||
worker->protocols,
|
||||
level_duration_get_level(level),
|
||||
level_duration_get_duration(level));
|
||||
|
||||
if(decoded_index == PROTOCOL_NO) continue;
|
||||
|
||||
protocol_dict_get_data(
|
||||
worker->protocols, decoded_index, worker->key_data, ibutton_key_get_max_size());
|
||||
|
||||
switch(decoded_index) {
|
||||
case iButtonProtocolCyfral:
|
||||
furi_check(worker->key_p != NULL);
|
||||
ibutton_key_set_type(worker->key_p, iButtonKeyCyfral);
|
||||
ibutton_key_set_data(worker->key_p, worker->key_data, ibutton_key_get_max_size());
|
||||
result = true;
|
||||
break;
|
||||
case iButtonProtocolMetakom:
|
||||
furi_check(worker->key_p != NULL);
|
||||
ibutton_key_set_type(worker->key_p, iButtonKeyMetakom);
|
||||
ibutton_key_set_data(worker->key_p, worker->key_data, ibutton_key_get_max_size());
|
||||
result = true;
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
furi_hal_rfid_comp_stop();
|
||||
furi_hal_rfid_comp_set_callback(NULL, NULL);
|
||||
furi_hal_rfid_pins_reset();
|
||||
|
||||
vStreamBufferDelete(read_context.stream);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -207,21 +235,12 @@ void ibutton_worker_emulate_timer_cb(void* context) {
|
||||
furi_assert(context);
|
||||
iButtonWorker* worker = context;
|
||||
|
||||
bool polarity;
|
||||
uint32_t length;
|
||||
LevelDuration level =
|
||||
protocol_dict_encoder_yield(worker->protocols, worker->protocol_to_encode);
|
||||
|
||||
switch(worker->emulate_mode) {
|
||||
case iButtonEmulateModeCyfral:
|
||||
encoder_cyfral_get_pulse(worker->encoder_cyfral, &polarity, &length);
|
||||
break;
|
||||
case iButtonEmulateModeMetakom:
|
||||
encoder_metakom_get_pulse(worker->encoder_metakom, &polarity, &length);
|
||||
break;
|
||||
}
|
||||
furi_hal_ibutton_emulate_set_next(level_duration_get_duration(level));
|
||||
|
||||
furi_hal_ibutton_emulate_set_next(length);
|
||||
|
||||
if(polarity) {
|
||||
if(level_duration_get_level(level)) {
|
||||
furi_hal_ibutton_pin_high();
|
||||
} else {
|
||||
furi_hal_ibutton_pin_low();
|
||||
@@ -238,17 +257,16 @@ void ibutton_worker_emulate_timer_start(iButtonWorker* worker) {
|
||||
return;
|
||||
break;
|
||||
case iButtonKeyCyfral:
|
||||
worker->emulate_mode = iButtonEmulateModeCyfral;
|
||||
encoder_cyfral_reset(worker->encoder_cyfral);
|
||||
encoder_cyfral_set_data(worker->encoder_cyfral, key_id, key_size);
|
||||
worker->protocol_to_encode = iButtonProtocolCyfral;
|
||||
break;
|
||||
case iButtonKeyMetakom:
|
||||
worker->emulate_mode = iButtonEmulateModeMetakom;
|
||||
encoder_metakom_reset(worker->encoder_metakom);
|
||||
encoder_metakom_set_data(worker->encoder_metakom, key_id, key_size);
|
||||
worker->protocol_to_encode = iButtonProtocolMetakom;
|
||||
break;
|
||||
}
|
||||
|
||||
protocol_dict_set_data(worker->protocols, worker->protocol_to_encode, key_id, key_size);
|
||||
protocol_dict_encoder_start(worker->protocols, worker->protocol_to_encode);
|
||||
|
||||
furi_hal_ibutton_start_drive();
|
||||
furi_hal_ibutton_emulate_start(0, ibutton_worker_emulate_timer_cb, worker);
|
||||
}
|
||||
|
8
lib/one_wire/ibutton/protocols/ibutton_protocols.c
Normal file
8
lib/one_wire/ibutton/protocols/ibutton_protocols.c
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "ibutton_protocols.h"
|
||||
#include "protocol_cyfral.h"
|
||||
#include "protocol_metakom.h"
|
||||
|
||||
const ProtocolBase* ibutton_protocols[] = {
|
||||
[iButtonProtocolCyfral] = &protocol_cyfral,
|
||||
[iButtonProtocolMetakom] = &protocol_metakom,
|
||||
};
|
11
lib/one_wire/ibutton/protocols/ibutton_protocols.h
Normal file
11
lib/one_wire/ibutton/protocols/ibutton_protocols.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include "toolbox/protocols/protocol.h"
|
||||
|
||||
typedef enum {
|
||||
iButtonProtocolCyfral,
|
||||
iButtonProtocolMetakom,
|
||||
|
||||
iButtonProtocolMax,
|
||||
} iButtonProtocol;
|
||||
|
||||
extern const ProtocolBase* ibutton_protocols[];
|
344
lib/one_wire/ibutton/protocols/protocol_cyfral.c
Normal file
344
lib/one_wire/ibutton/protocols/protocol_cyfral.c
Normal file
@@ -0,0 +1,344 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include "protocol_cyfral.h"
|
||||
|
||||
#define CYFRAL_DATA_SIZE sizeof(uint16_t)
|
||||
#define CYFRAL_PERIOD (125 * furi_hal_cortex_instructions_per_microsecond())
|
||||
#define CYFRAL_0_LOW (CYFRAL_PERIOD * 0.66f)
|
||||
#define CYFRAL_0_HI (CYFRAL_PERIOD * 0.33f)
|
||||
#define CYFRAL_1_LOW (CYFRAL_PERIOD * 0.33f)
|
||||
#define CYFRAL_1_HI (CYFRAL_PERIOD * 0.66f)
|
||||
|
||||
#define CYFRAL_MAX_PERIOD_US 230
|
||||
|
||||
typedef enum {
|
||||
CYFRAL_BIT_WAIT_FRONT_HIGH,
|
||||
CYFRAL_BIT_WAIT_FRONT_LOW,
|
||||
} CyfralBitState;
|
||||
|
||||
typedef enum {
|
||||
CYFRAL_WAIT_START_NIBBLE,
|
||||
CYFRAL_READ_NIBBLE,
|
||||
CYFRAL_READ_STOP_NIBBLE,
|
||||
} CyfralState;
|
||||
|
||||
typedef struct {
|
||||
CyfralState state;
|
||||
CyfralBitState bit_state;
|
||||
|
||||
// high + low period time
|
||||
uint32_t period_time;
|
||||
// temporary nibble storage
|
||||
uint8_t nibble;
|
||||
// data valid flag
|
||||
// MUST be checked only in READ_STOP_NIBBLE state
|
||||
bool data_valid;
|
||||
// nibble index, we expect 8 nibbles
|
||||
uint8_t index;
|
||||
// bit index in nibble, 4 bit per nibble
|
||||
uint8_t bit_index;
|
||||
// max period, 230us x clock per us
|
||||
uint32_t max_period;
|
||||
} ProtocolCyfralDecoder;
|
||||
|
||||
typedef struct {
|
||||
uint32_t data;
|
||||
uint32_t index;
|
||||
} ProtocolCyfralEncoder;
|
||||
|
||||
typedef struct {
|
||||
uint16_t data;
|
||||
|
||||
ProtocolCyfralDecoder decoder;
|
||||
ProtocolCyfralEncoder encoder;
|
||||
} ProtocolCyfral;
|
||||
|
||||
static void* protocol_cyfral_alloc(void) {
|
||||
ProtocolCyfral* proto = malloc(sizeof(ProtocolCyfral));
|
||||
return (void*)proto;
|
||||
}
|
||||
|
||||
static void protocol_cyfral_free(ProtocolCyfral* proto) {
|
||||
free(proto);
|
||||
}
|
||||
|
||||
static uint8_t* protocol_cyfral_get_data(ProtocolCyfral* proto) {
|
||||
return (uint8_t*)&proto->data;
|
||||
}
|
||||
|
||||
static void protocol_cyfral_decoder_start(ProtocolCyfral* proto) {
|
||||
ProtocolCyfralDecoder* cyfral = &proto->decoder;
|
||||
|
||||
cyfral->state = CYFRAL_WAIT_START_NIBBLE;
|
||||
cyfral->bit_state = CYFRAL_BIT_WAIT_FRONT_LOW;
|
||||
cyfral->period_time = 0;
|
||||
cyfral->bit_index = 0;
|
||||
cyfral->index = 0;
|
||||
cyfral->nibble = 0;
|
||||
cyfral->data_valid = true;
|
||||
cyfral->max_period = CYFRAL_MAX_PERIOD_US * furi_hal_cortex_instructions_per_microsecond();
|
||||
|
||||
proto->data = 0;
|
||||
}
|
||||
|
||||
static bool protocol_cyfral_decoder_process_bit(
|
||||
ProtocolCyfralDecoder* cyfral,
|
||||
bool polarity,
|
||||
uint32_t length,
|
||||
bool* bit_ready,
|
||||
bool* bit_value) {
|
||||
bool result = true;
|
||||
*bit_ready = false;
|
||||
|
||||
// bit start from low
|
||||
switch(cyfral->bit_state) {
|
||||
case CYFRAL_BIT_WAIT_FRONT_LOW:
|
||||
if(polarity == true) {
|
||||
cyfral->period_time += length;
|
||||
|
||||
*bit_ready = true;
|
||||
if(cyfral->period_time <= cyfral->max_period) {
|
||||
if((cyfral->period_time / 2) > length) {
|
||||
*bit_value = false;
|
||||
} else {
|
||||
*bit_value = true;
|
||||
}
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
|
||||
cyfral->bit_state = CYFRAL_BIT_WAIT_FRONT_HIGH;
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
break;
|
||||
case CYFRAL_BIT_WAIT_FRONT_HIGH:
|
||||
if(polarity == false) {
|
||||
cyfral->period_time = length;
|
||||
cyfral->bit_state = CYFRAL_BIT_WAIT_FRONT_LOW;
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool protocol_cyfral_decoder_feed(ProtocolCyfral* proto, bool level, uint32_t duration) {
|
||||
ProtocolCyfralDecoder* cyfral = &proto->decoder;
|
||||
|
||||
bool bit_ready;
|
||||
bool bit_value;
|
||||
bool decoded = false;
|
||||
|
||||
switch(cyfral->state) {
|
||||
case CYFRAL_WAIT_START_NIBBLE:
|
||||
// wait for start word
|
||||
if(protocol_cyfral_decoder_process_bit(cyfral, level, duration, &bit_ready, &bit_value)) {
|
||||
if(bit_ready) {
|
||||
cyfral->nibble = ((cyfral->nibble << 1) | bit_value) & 0x0F;
|
||||
if(cyfral->nibble == 0b0001) {
|
||||
cyfral->nibble = 0;
|
||||
cyfral->state = CYFRAL_READ_NIBBLE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
protocol_cyfral_decoder_start(proto);
|
||||
}
|
||||
|
||||
break;
|
||||
case CYFRAL_READ_NIBBLE:
|
||||
// read nibbles
|
||||
if(protocol_cyfral_decoder_process_bit(cyfral, level, duration, &bit_ready, &bit_value)) {
|
||||
if(bit_ready) {
|
||||
cyfral->nibble = (cyfral->nibble << 1) | bit_value;
|
||||
|
||||
cyfral->bit_index++;
|
||||
|
||||
//convert every nibble to 2-bit index
|
||||
if(cyfral->bit_index == 4) {
|
||||
switch(cyfral->nibble) {
|
||||
case 0b1110:
|
||||
proto->data = (proto->data << 2) | 0b11;
|
||||
break;
|
||||
case 0b1101:
|
||||
proto->data = (proto->data << 2) | 0b10;
|
||||
break;
|
||||
case 0b1011:
|
||||
proto->data = (proto->data << 2) | 0b01;
|
||||
break;
|
||||
case 0b0111:
|
||||
proto->data = (proto->data << 2) | 0b00;
|
||||
break;
|
||||
default:
|
||||
cyfral->data_valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
cyfral->nibble = 0;
|
||||
cyfral->bit_index = 0;
|
||||
cyfral->index++;
|
||||
}
|
||||
|
||||
// succefully read 8 nibbles
|
||||
if(cyfral->index == 8) {
|
||||
cyfral->state = CYFRAL_READ_STOP_NIBBLE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
protocol_cyfral_decoder_start(proto);
|
||||
}
|
||||
break;
|
||||
case CYFRAL_READ_STOP_NIBBLE:
|
||||
// read stop nibble
|
||||
if(protocol_cyfral_decoder_process_bit(cyfral, level, duration, &bit_ready, &bit_value)) {
|
||||
if(bit_ready) {
|
||||
cyfral->nibble = ((cyfral->nibble << 1) | bit_value) & 0x0F;
|
||||
cyfral->bit_index++;
|
||||
|
||||
switch(cyfral->bit_index) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
break;
|
||||
case 4:
|
||||
if(cyfral->nibble == 0b0001) {
|
||||
// validate data
|
||||
if(cyfral->data_valid) {
|
||||
decoded = true;
|
||||
} else {
|
||||
protocol_cyfral_decoder_start(proto);
|
||||
}
|
||||
} else {
|
||||
protocol_cyfral_decoder_start(proto);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
protocol_cyfral_decoder_start(proto);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
protocol_cyfral_decoder_start(proto);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return decoded;
|
||||
}
|
||||
|
||||
static uint32_t protocol_cyfral_encoder_encode(const uint16_t data) {
|
||||
uint32_t value = 0;
|
||||
for(int8_t i = 0; i <= 7; i++) {
|
||||
switch((data >> (i * 2)) & 0b00000011) {
|
||||
case 0b11:
|
||||
value = value << 4;
|
||||
value += 0b00000111;
|
||||
break;
|
||||
case 0b10:
|
||||
value = value << 4;
|
||||
value += 0b00001011;
|
||||
break;
|
||||
case 0b01:
|
||||
value = value << 4;
|
||||
value += 0b00001101;
|
||||
break;
|
||||
case 0b00:
|
||||
value = value << 4;
|
||||
value += 0b00001110;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static bool protocol_cyfral_encoder_start(ProtocolCyfral* proto) {
|
||||
proto->encoder.index = 0;
|
||||
proto->encoder.data = protocol_cyfral_encoder_encode(proto->data);
|
||||
return true;
|
||||
}
|
||||
|
||||
static LevelDuration protocol_cyfral_encoder_yield(ProtocolCyfral* proto) {
|
||||
LevelDuration result;
|
||||
|
||||
if(proto->encoder.index < 8) {
|
||||
// start word (0b0001)
|
||||
switch(proto->encoder.index) {
|
||||
case 0:
|
||||
result = level_duration_make(false, CYFRAL_0_LOW);
|
||||
break;
|
||||
case 1:
|
||||
result = level_duration_make(true, CYFRAL_0_HI);
|
||||
break;
|
||||
case 2:
|
||||
result = level_duration_make(false, CYFRAL_0_LOW);
|
||||
break;
|
||||
case 3:
|
||||
result = level_duration_make(true, CYFRAL_0_HI);
|
||||
break;
|
||||
case 4:
|
||||
result = level_duration_make(false, CYFRAL_0_LOW);
|
||||
break;
|
||||
case 5:
|
||||
result = level_duration_make(true, CYFRAL_0_HI);
|
||||
break;
|
||||
case 6:
|
||||
result = level_duration_make(false, CYFRAL_1_LOW);
|
||||
break;
|
||||
case 7:
|
||||
result = level_duration_make(true, CYFRAL_1_HI);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// data
|
||||
uint8_t data_start_index = proto->encoder.index - 8;
|
||||
bool clock_polarity = (data_start_index) % 2;
|
||||
uint8_t bit_index = (data_start_index) / 2;
|
||||
bool bit_value = ((proto->encoder.data >> bit_index) & 1);
|
||||
|
||||
if(!clock_polarity) {
|
||||
if(bit_value) {
|
||||
result = level_duration_make(false, CYFRAL_1_LOW);
|
||||
} else {
|
||||
result = level_duration_make(false, CYFRAL_0_LOW);
|
||||
}
|
||||
} else {
|
||||
if(bit_value) {
|
||||
result = level_duration_make(true, CYFRAL_1_HI);
|
||||
} else {
|
||||
result = level_duration_make(true, CYFRAL_0_HI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proto->encoder.index++;
|
||||
if(proto->encoder.index >= (9 * 4 * 2)) {
|
||||
proto->encoder.index = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const ProtocolBase protocol_cyfral = {
|
||||
.name = "Cyfral",
|
||||
.manufacturer = "Cyfral",
|
||||
.data_size = CYFRAL_DATA_SIZE,
|
||||
.alloc = (ProtocolAlloc)protocol_cyfral_alloc,
|
||||
.free = (ProtocolFree)protocol_cyfral_free,
|
||||
.get_data = (ProtocolGetData)protocol_cyfral_get_data,
|
||||
.decoder =
|
||||
{
|
||||
.start = (ProtocolDecoderStart)protocol_cyfral_decoder_start,
|
||||
.feed = (ProtocolDecoderFeed)protocol_cyfral_decoder_feed,
|
||||
},
|
||||
.encoder =
|
||||
{
|
||||
.start = (ProtocolEncoderStart)protocol_cyfral_encoder_start,
|
||||
.yield = (ProtocolEncoderYield)protocol_cyfral_encoder_yield,
|
||||
},
|
||||
};
|
4
lib/one_wire/ibutton/protocols/protocol_cyfral.h
Normal file
4
lib/one_wire/ibutton/protocols/protocol_cyfral.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include "toolbox/protocols/protocol.h"
|
||||
|
||||
extern const ProtocolBase protocol_cyfral;
|
@@ -1,9 +1,14 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include "protocol_metakom.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <core/check.h>
|
||||
|
||||
#define METAKOM_DATA_SIZE 4
|
||||
#define METAKOM_DATA_SIZE sizeof(uint32_t)
|
||||
#define METAKOM_PERIOD (125 * furi_hal_cortex_instructions_per_microsecond())
|
||||
#define METAKOM_0_LOW (METAKOM_PERIOD * 0.33f)
|
||||
#define METAKOM_0_HI (METAKOM_PERIOD * 0.66f)
|
||||
#define METAKOM_1_LOW (METAKOM_PERIOD * 0.66f)
|
||||
#define METAKOM_1_HI (METAKOM_PERIOD * 0.33f)
|
||||
|
||||
#define METAKOM_PERIOD_SAMPLE_COUNT 10
|
||||
|
||||
typedef enum {
|
||||
@@ -19,79 +24,49 @@ typedef enum {
|
||||
METAKOM_BIT_WAIT_FRONT_LOW,
|
||||
} MetakomBitState;
|
||||
|
||||
struct ProtocolMetakom {
|
||||
PulseProtocol* protocol;
|
||||
|
||||
typedef struct {
|
||||
// high + low period time
|
||||
uint32_t period_time;
|
||||
uint32_t low_time_storage;
|
||||
uint8_t period_sample_index;
|
||||
uint32_t period_sample_data[METAKOM_PERIOD_SAMPLE_COUNT];
|
||||
|
||||
// ready flag
|
||||
// TODO: atomic access
|
||||
bool ready;
|
||||
|
||||
uint8_t tmp_data;
|
||||
uint8_t tmp_counter;
|
||||
|
||||
uint32_t key_data;
|
||||
uint8_t key_data_index;
|
||||
|
||||
MetakomBitState bit_state;
|
||||
MetakomState state;
|
||||
};
|
||||
} ProtocolMetakomDecoder;
|
||||
|
||||
static void metakom_pulse(void* context, bool polarity, uint32_t length);
|
||||
static void metakom_reset(void* context);
|
||||
static void metakom_get_data(void* context, uint8_t* data, size_t length);
|
||||
static bool metakom_decoded(void* context);
|
||||
typedef struct {
|
||||
uint32_t index;
|
||||
} ProtocolMetakomEncoder;
|
||||
|
||||
ProtocolMetakom* protocol_metakom_alloc() {
|
||||
ProtocolMetakom* metakom = malloc(sizeof(ProtocolMetakom));
|
||||
metakom_reset(metakom);
|
||||
typedef struct {
|
||||
uint32_t data;
|
||||
|
||||
metakom->protocol = pulse_protocol_alloc();
|
||||
ProtocolMetakomDecoder decoder;
|
||||
ProtocolMetakomEncoder encoder;
|
||||
} ProtocolMetakom;
|
||||
|
||||
pulse_protocol_set_context(metakom->protocol, metakom);
|
||||
pulse_protocol_set_pulse_cb(metakom->protocol, metakom_pulse);
|
||||
pulse_protocol_set_reset_cb(metakom->protocol, metakom_reset);
|
||||
pulse_protocol_set_get_data_cb(metakom->protocol, metakom_get_data);
|
||||
pulse_protocol_set_decoded_cb(metakom->protocol, metakom_decoded);
|
||||
|
||||
return metakom;
|
||||
static ProtocolMetakom* protocol_metakom_alloc(void) {
|
||||
ProtocolMetakom* proto = malloc(sizeof(ProtocolMetakom));
|
||||
return (void*)proto;
|
||||
}
|
||||
|
||||
void protocol_metakom_free(ProtocolMetakom* metakom) {
|
||||
furi_assert(metakom);
|
||||
pulse_protocol_free(metakom->protocol);
|
||||
free(metakom);
|
||||
static void protocol_metakom_free(ProtocolMetakom* proto) {
|
||||
free(proto);
|
||||
}
|
||||
|
||||
PulseProtocol* protocol_metakom_get_protocol(ProtocolMetakom* metakom) {
|
||||
furi_assert(metakom);
|
||||
return metakom->protocol;
|
||||
static uint8_t* protocol_metakom_get_data(ProtocolMetakom* proto) {
|
||||
return (uint8_t*)&proto->data;
|
||||
}
|
||||
|
||||
static void metakom_get_data(void* context, uint8_t* data, size_t length) {
|
||||
furi_assert(context);
|
||||
furi_check(length >= METAKOM_DATA_SIZE);
|
||||
ProtocolMetakom* metakom = context;
|
||||
memcpy(data, &metakom->key_data, METAKOM_DATA_SIZE);
|
||||
}
|
||||
static void protocol_metakom_decoder_start(ProtocolMetakom* proto) {
|
||||
ProtocolMetakomDecoder* metakom = &proto->decoder;
|
||||
|
||||
static bool metakom_decoded(void* context) {
|
||||
furi_assert(context);
|
||||
ProtocolMetakom* metakom = context;
|
||||
bool decoded = metakom->ready;
|
||||
return decoded;
|
||||
}
|
||||
|
||||
static void metakom_reset(void* context) {
|
||||
furi_assert(context);
|
||||
ProtocolMetakom* metakom = context;
|
||||
|
||||
metakom->ready = false;
|
||||
metakom->period_sample_index = 0;
|
||||
metakom->period_time = 0;
|
||||
metakom->tmp_counter = 0;
|
||||
@@ -101,9 +76,10 @@ static void metakom_reset(void* context) {
|
||||
};
|
||||
metakom->state = METAKOM_WAIT_PERIOD_SYNC;
|
||||
metakom->bit_state = METAKOM_BIT_WAIT_FRONT_LOW;
|
||||
metakom->key_data = 0;
|
||||
metakom->key_data_index = 0;
|
||||
metakom->low_time_storage = 0;
|
||||
|
||||
proto->data = 0;
|
||||
}
|
||||
|
||||
static bool metakom_parity_check(uint8_t data) {
|
||||
@@ -122,7 +98,7 @@ static bool metakom_parity_check(uint8_t data) {
|
||||
}
|
||||
|
||||
static bool metakom_process_bit(
|
||||
ProtocolMetakom* metakom,
|
||||
ProtocolMetakomDecoder* metakom,
|
||||
bool polarity,
|
||||
uint32_t time,
|
||||
uint32_t* high_time,
|
||||
@@ -149,18 +125,17 @@ static bool metakom_process_bit(
|
||||
return result;
|
||||
}
|
||||
|
||||
static void metakom_pulse(void* context, bool polarity, uint32_t time) {
|
||||
furi_assert(context);
|
||||
ProtocolMetakom* metakom = context;
|
||||
static bool protocol_metakom_decoder_feed(ProtocolMetakom* proto, bool level, uint32_t duration) {
|
||||
ProtocolMetakomDecoder* metakom = &proto->decoder;
|
||||
|
||||
if(metakom->ready) return;
|
||||
bool ready = false;
|
||||
|
||||
uint32_t high_time = 0;
|
||||
uint32_t low_time = 0;
|
||||
|
||||
switch(metakom->state) {
|
||||
case METAKOM_WAIT_PERIOD_SYNC:
|
||||
if(metakom_process_bit(metakom, polarity, time, &high_time, &low_time)) {
|
||||
if(metakom_process_bit(metakom, level, duration, &high_time, &low_time)) {
|
||||
metakom->period_sample_data[metakom->period_sample_index] = high_time + low_time;
|
||||
metakom->period_sample_index++;
|
||||
|
||||
@@ -176,7 +151,7 @@ static void metakom_pulse(void* context, bool polarity, uint32_t time) {
|
||||
|
||||
break;
|
||||
case METAKOM_WAIT_START_BIT:
|
||||
if(metakom_process_bit(metakom, polarity, time, &high_time, &low_time)) {
|
||||
if(metakom_process_bit(metakom, level, duration, &high_time, &low_time)) {
|
||||
metakom->tmp_counter++;
|
||||
if(high_time > metakom->period_time) {
|
||||
metakom->tmp_counter = 0;
|
||||
@@ -184,13 +159,13 @@ static void metakom_pulse(void* context, bool polarity, uint32_t time) {
|
||||
}
|
||||
|
||||
if(metakom->tmp_counter > 40) {
|
||||
metakom_reset(metakom);
|
||||
protocol_metakom_decoder_start(proto);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case METAKOM_WAIT_START_WORD:
|
||||
if(metakom_process_bit(metakom, polarity, time, &high_time, &low_time)) {
|
||||
if(metakom_process_bit(metakom, level, duration, &high_time, &low_time)) {
|
||||
if(low_time < (metakom->period_time / 2)) {
|
||||
metakom->tmp_data = (metakom->tmp_data << 1) | 0b0;
|
||||
} else {
|
||||
@@ -204,13 +179,13 @@ static void metakom_pulse(void* context, bool polarity, uint32_t time) {
|
||||
metakom->tmp_data = 0;
|
||||
metakom->state = METAKOM_READ_WORD;
|
||||
} else {
|
||||
metakom_reset(metakom);
|
||||
protocol_metakom_decoder_start(proto);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case METAKOM_READ_WORD:
|
||||
if(metakom_process_bit(metakom, polarity, time, &high_time, &low_time)) {
|
||||
if(metakom_process_bit(metakom, level, duration, &high_time, &low_time)) {
|
||||
if(low_time < (metakom->period_time / 2)) {
|
||||
metakom->tmp_data = (metakom->tmp_data << 1) | 0b0;
|
||||
} else {
|
||||
@@ -220,7 +195,7 @@ static void metakom_pulse(void* context, bool polarity, uint32_t time) {
|
||||
|
||||
if(metakom->tmp_counter == 8) {
|
||||
if(metakom_parity_check(metakom->tmp_data)) {
|
||||
metakom->key_data = (metakom->key_data << 8) | metakom->tmp_data;
|
||||
proto->data = (proto->data << 8) | metakom->tmp_data;
|
||||
metakom->key_data_index++;
|
||||
metakom->tmp_data = 0;
|
||||
metakom->tmp_counter = 0;
|
||||
@@ -230,17 +205,17 @@ static void metakom_pulse(void* context, bool polarity, uint32_t time) {
|
||||
if(high_time > metakom->period_time) {
|
||||
metakom->state = METAKOM_READ_STOP_WORD;
|
||||
} else {
|
||||
metakom_reset(metakom);
|
||||
protocol_metakom_decoder_start(proto);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
metakom_reset(metakom);
|
||||
protocol_metakom_decoder_start(proto);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case METAKOM_READ_STOP_WORD:
|
||||
if(metakom_process_bit(metakom, polarity, time, &high_time, &low_time)) {
|
||||
if(metakom_process_bit(metakom, level, duration, &high_time, &low_time)) {
|
||||
if(low_time < (metakom->period_time / 2)) {
|
||||
metakom->tmp_data = (metakom->tmp_data << 1) | 0b0;
|
||||
} else {
|
||||
@@ -250,12 +225,96 @@ static void metakom_pulse(void* context, bool polarity, uint32_t time) {
|
||||
|
||||
if(metakom->tmp_counter == 3) {
|
||||
if(metakom->tmp_data == 0b010) {
|
||||
metakom->ready = true;
|
||||
ready = true;
|
||||
} else {
|
||||
metakom_reset(metakom);
|
||||
protocol_metakom_decoder_start(proto);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ready;
|
||||
}
|
||||
|
||||
static bool protocol_metakom_encoder_start(ProtocolMetakom* proto) {
|
||||
proto->encoder.index = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static LevelDuration protocol_metakom_encoder_yield(ProtocolMetakom* proto) {
|
||||
LevelDuration result;
|
||||
|
||||
if(proto->encoder.index == 0) {
|
||||
// sync bit
|
||||
result = level_duration_make(false, METAKOM_PERIOD);
|
||||
} else if(proto->encoder.index >= 1 && proto->encoder.index <= 6) {
|
||||
// start word (0b010)
|
||||
switch(proto->encoder.index) {
|
||||
case 1:
|
||||
result = level_duration_make(true, METAKOM_0_LOW);
|
||||
break;
|
||||
case 2:
|
||||
result = level_duration_make(false, METAKOM_0_HI);
|
||||
break;
|
||||
case 3:
|
||||
result = level_duration_make(true, METAKOM_1_LOW);
|
||||
break;
|
||||
case 4:
|
||||
result = level_duration_make(false, METAKOM_1_HI);
|
||||
break;
|
||||
case 5:
|
||||
result = level_duration_make(true, METAKOM_0_LOW);
|
||||
break;
|
||||
case 6:
|
||||
result = level_duration_make(false, METAKOM_0_HI);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// data
|
||||
uint8_t data_start_index = proto->encoder.index - 7;
|
||||
bool clock_polarity = (data_start_index) % 2;
|
||||
uint8_t bit_index = (data_start_index) / 2;
|
||||
bool bit_value = (proto->data >> (32 - 1 - bit_index)) & 1;
|
||||
|
||||
if(!clock_polarity) {
|
||||
if(bit_value) {
|
||||
result = level_duration_make(true, METAKOM_1_LOW);
|
||||
} else {
|
||||
result = level_duration_make(true, METAKOM_0_LOW);
|
||||
}
|
||||
} else {
|
||||
if(bit_value) {
|
||||
result = level_duration_make(false, METAKOM_1_HI);
|
||||
} else {
|
||||
result = level_duration_make(false, METAKOM_0_HI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proto->encoder.index++;
|
||||
if(proto->encoder.index >= (1 + 3 * 2 + 32 * 2)) {
|
||||
proto->encoder.index = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const ProtocolBase protocol_metakom = {
|
||||
.name = "Metakom",
|
||||
.manufacturer = "Metakom",
|
||||
.data_size = METAKOM_DATA_SIZE,
|
||||
.alloc = (ProtocolAlloc)protocol_metakom_alloc,
|
||||
.free = (ProtocolFree)protocol_metakom_free,
|
||||
.get_data = (ProtocolGetData)protocol_metakom_get_data,
|
||||
.decoder =
|
||||
{
|
||||
.start = (ProtocolDecoderStart)protocol_metakom_decoder_start,
|
||||
.feed = (ProtocolDecoderFeed)protocol_metakom_decoder_feed,
|
||||
},
|
||||
.encoder =
|
||||
{
|
||||
.start = (ProtocolEncoderStart)protocol_metakom_encoder_start,
|
||||
.yield = (ProtocolEncoderYield)protocol_metakom_encoder_yield,
|
||||
},
|
||||
};
|
4
lib/one_wire/ibutton/protocols/protocol_metakom.h
Normal file
4
lib/one_wire/ibutton/protocols/protocol_metakom.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include "toolbox/protocols/protocol.h"
|
||||
|
||||
extern const ProtocolBase protocol_metakom;
|
@@ -1,256 +0,0 @@
|
||||
#include "protocol_cyfral.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#define CYFRAL_DATA_SIZE 2
|
||||
#define CYFRAL_MAX_PERIOD_US 230
|
||||
|
||||
typedef enum {
|
||||
CYFRAL_BIT_WAIT_FRONT_HIGH,
|
||||
CYFRAL_BIT_WAIT_FRONT_LOW,
|
||||
} CyfralBitState;
|
||||
|
||||
typedef enum {
|
||||
CYFRAL_WAIT_START_NIBBLE,
|
||||
CYFRAL_READ_NIBBLE,
|
||||
CYFRAL_READ_STOP_NIBBLE,
|
||||
} CyfralState;
|
||||
|
||||
struct ProtocolCyfral {
|
||||
PulseProtocol* protocol;
|
||||
|
||||
CyfralState state;
|
||||
CyfralBitState bit_state;
|
||||
|
||||
// ready flag, key is read and valid
|
||||
// TODO: atomic access
|
||||
bool ready;
|
||||
// key data storage
|
||||
uint16_t key_data;
|
||||
// high + low period time
|
||||
uint32_t period_time;
|
||||
// temporary nibble storage
|
||||
uint8_t nibble;
|
||||
// data valid flag
|
||||
// MUST be checked only in READ_STOP_NIBBLE state
|
||||
bool data_valid;
|
||||
// nibble index, we expect 8 nibbles
|
||||
uint8_t index;
|
||||
// bit index in nibble, 4 bit per nibble
|
||||
uint8_t bit_index;
|
||||
// max period, 230us x clock per us
|
||||
uint32_t max_period;
|
||||
};
|
||||
|
||||
static void cyfral_pulse(void* context, bool polarity, uint32_t length);
|
||||
static void cyfral_reset(void* context);
|
||||
static void cyfral_get_data(void* context, uint8_t* data, size_t length);
|
||||
static bool cyfral_decoded(void* context);
|
||||
|
||||
ProtocolCyfral* protocol_cyfral_alloc() {
|
||||
ProtocolCyfral* cyfral = malloc(sizeof(ProtocolCyfral));
|
||||
cyfral_reset(cyfral);
|
||||
|
||||
cyfral->protocol = pulse_protocol_alloc();
|
||||
|
||||
pulse_protocol_set_context(cyfral->protocol, cyfral);
|
||||
pulse_protocol_set_pulse_cb(cyfral->protocol, cyfral_pulse);
|
||||
pulse_protocol_set_reset_cb(cyfral->protocol, cyfral_reset);
|
||||
pulse_protocol_set_get_data_cb(cyfral->protocol, cyfral_get_data);
|
||||
pulse_protocol_set_decoded_cb(cyfral->protocol, cyfral_decoded);
|
||||
|
||||
return cyfral;
|
||||
}
|
||||
|
||||
void protocol_cyfral_free(ProtocolCyfral* cyfral) {
|
||||
furi_assert(cyfral);
|
||||
pulse_protocol_free(cyfral->protocol);
|
||||
free(cyfral);
|
||||
}
|
||||
|
||||
PulseProtocol* protocol_cyfral_get_protocol(ProtocolCyfral* cyfral) {
|
||||
furi_assert(cyfral);
|
||||
return cyfral->protocol;
|
||||
}
|
||||
|
||||
static void cyfral_get_data(void* context, uint8_t* data, size_t length) {
|
||||
furi_assert(context);
|
||||
furi_check(length >= CYFRAL_DATA_SIZE);
|
||||
ProtocolCyfral* cyfral = context;
|
||||
memcpy(data, &cyfral->key_data, CYFRAL_DATA_SIZE);
|
||||
}
|
||||
|
||||
static bool cyfral_decoded(void* context) {
|
||||
furi_assert(context);
|
||||
ProtocolCyfral* cyfral = context;
|
||||
bool decoded = cyfral->ready;
|
||||
return decoded;
|
||||
}
|
||||
|
||||
static void cyfral_reset(void* context) {
|
||||
furi_assert(context);
|
||||
ProtocolCyfral* cyfral = context;
|
||||
cyfral->state = CYFRAL_WAIT_START_NIBBLE;
|
||||
cyfral->bit_state = CYFRAL_BIT_WAIT_FRONT_LOW;
|
||||
|
||||
cyfral->period_time = 0;
|
||||
cyfral->bit_index = 0;
|
||||
cyfral->ready = false;
|
||||
cyfral->index = 0;
|
||||
|
||||
cyfral->key_data = 0;
|
||||
cyfral->nibble = 0;
|
||||
cyfral->data_valid = true;
|
||||
|
||||
cyfral->max_period = CYFRAL_MAX_PERIOD_US * furi_hal_cortex_instructions_per_microsecond();
|
||||
}
|
||||
|
||||
static bool cyfral_process_bit(
|
||||
ProtocolCyfral* cyfral,
|
||||
bool polarity,
|
||||
uint32_t length,
|
||||
bool* bit_ready,
|
||||
bool* bit_value) {
|
||||
bool result = true;
|
||||
*bit_ready = false;
|
||||
|
||||
// bit start from low
|
||||
switch(cyfral->bit_state) {
|
||||
case CYFRAL_BIT_WAIT_FRONT_LOW:
|
||||
if(polarity == true) {
|
||||
cyfral->period_time += length;
|
||||
|
||||
*bit_ready = true;
|
||||
if(cyfral->period_time <= cyfral->max_period) {
|
||||
if((cyfral->period_time / 2) > length) {
|
||||
*bit_value = false;
|
||||
} else {
|
||||
*bit_value = true;
|
||||
}
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
|
||||
cyfral->bit_state = CYFRAL_BIT_WAIT_FRONT_HIGH;
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
break;
|
||||
case CYFRAL_BIT_WAIT_FRONT_HIGH:
|
||||
if(polarity == false) {
|
||||
cyfral->period_time = length;
|
||||
cyfral->bit_state = CYFRAL_BIT_WAIT_FRONT_LOW;
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void cyfral_pulse(void* context, bool polarity, uint32_t length) {
|
||||
furi_assert(context);
|
||||
ProtocolCyfral* cyfral = context;
|
||||
|
||||
bool bit_ready;
|
||||
bool bit_value;
|
||||
|
||||
if(cyfral->ready) return;
|
||||
|
||||
switch(cyfral->state) {
|
||||
case CYFRAL_WAIT_START_NIBBLE:
|
||||
// wait for start word
|
||||
if(cyfral_process_bit(cyfral, polarity, length, &bit_ready, &bit_value)) {
|
||||
if(bit_ready) {
|
||||
cyfral->nibble = ((cyfral->nibble << 1) | bit_value) & 0x0F;
|
||||
if(cyfral->nibble == 0b0001) {
|
||||
cyfral->nibble = 0;
|
||||
cyfral->state = CYFRAL_READ_NIBBLE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cyfral_reset(cyfral);
|
||||
}
|
||||
|
||||
break;
|
||||
case CYFRAL_READ_NIBBLE:
|
||||
// read nibbles
|
||||
if(cyfral_process_bit(cyfral, polarity, length, &bit_ready, &bit_value)) {
|
||||
if(bit_ready) {
|
||||
cyfral->nibble = (cyfral->nibble << 1) | bit_value;
|
||||
|
||||
cyfral->bit_index++;
|
||||
|
||||
//convert every nibble to 2-bit index
|
||||
if(cyfral->bit_index == 4) {
|
||||
switch(cyfral->nibble) {
|
||||
case 0b1110:
|
||||
cyfral->key_data = (cyfral->key_data << 2) | 0b11;
|
||||
break;
|
||||
case 0b1101:
|
||||
cyfral->key_data = (cyfral->key_data << 2) | 0b10;
|
||||
break;
|
||||
case 0b1011:
|
||||
cyfral->key_data = (cyfral->key_data << 2) | 0b01;
|
||||
break;
|
||||
case 0b0111:
|
||||
cyfral->key_data = (cyfral->key_data << 2) | 0b00;
|
||||
break;
|
||||
default:
|
||||
cyfral->data_valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
cyfral->nibble = 0;
|
||||
cyfral->bit_index = 0;
|
||||
cyfral->index++;
|
||||
}
|
||||
|
||||
// succefully read 8 nibbles
|
||||
if(cyfral->index == 8) {
|
||||
cyfral->state = CYFRAL_READ_STOP_NIBBLE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cyfral_reset(cyfral);
|
||||
}
|
||||
break;
|
||||
case CYFRAL_READ_STOP_NIBBLE:
|
||||
// read stop nibble
|
||||
if(cyfral_process_bit(cyfral, polarity, length, &bit_ready, &bit_value)) {
|
||||
if(bit_ready) {
|
||||
cyfral->nibble = ((cyfral->nibble << 1) | bit_value) & 0x0F;
|
||||
cyfral->bit_index++;
|
||||
|
||||
switch(cyfral->bit_index) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
break;
|
||||
case 4:
|
||||
if(cyfral->nibble == 0b0001) {
|
||||
// validate data
|
||||
if(cyfral->data_valid) {
|
||||
cyfral->ready = true;
|
||||
} else {
|
||||
cyfral_reset(cyfral);
|
||||
}
|
||||
} else {
|
||||
cyfral_reset(cyfral);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cyfral_reset(cyfral);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cyfral_reset(cyfral);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
/**
|
||||
* @file protocol_cyfral.h
|
||||
*
|
||||
* Cyfral pulse format decoder
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "../../pulse_protocols/pulse_protocol.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct ProtocolCyfral ProtocolCyfral;
|
||||
|
||||
/**
|
||||
* Allocate decoder
|
||||
* @return ProtocolCyfral*
|
||||
*/
|
||||
ProtocolCyfral* protocol_cyfral_alloc();
|
||||
|
||||
/**
|
||||
* Deallocate decoder
|
||||
* @param cyfral
|
||||
*/
|
||||
void protocol_cyfral_free(ProtocolCyfral* cyfral);
|
||||
|
||||
/**
|
||||
* Get protocol interface
|
||||
* @param cyfral
|
||||
* @return PulseProtocol*
|
||||
*/
|
||||
PulseProtocol* protocol_cyfral_get_protocol(ProtocolCyfral* cyfral);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -1,38 +0,0 @@
|
||||
/**
|
||||
* @file protocol_metakom.h
|
||||
*
|
||||
* Metakom pulse format decoder
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "../../pulse_protocols/pulse_protocol.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct ProtocolMetakom ProtocolMetakom;
|
||||
|
||||
/**
|
||||
* Allocate decoder
|
||||
* @return ProtocolMetakom*
|
||||
*/
|
||||
ProtocolMetakom* protocol_metakom_alloc();
|
||||
|
||||
/**
|
||||
* Free decoder
|
||||
* @param metakom
|
||||
*/
|
||||
void protocol_metakom_free(ProtocolMetakom* metakom);
|
||||
|
||||
/**
|
||||
* Get protocol interface
|
||||
* @param metakom
|
||||
* @return PulseProtocol*
|
||||
*/
|
||||
PulseProtocol* protocol_metakom_get_protocol(ProtocolMetakom* metakom);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -1,66 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include "pulse_decoder.h"
|
||||
#include <string.h>
|
||||
#include <core/check.h>
|
||||
|
||||
#define MAX_PROTOCOL 5
|
||||
|
||||
struct PulseDecoder {
|
||||
PulseProtocol* protocols[MAX_PROTOCOL];
|
||||
};
|
||||
|
||||
PulseDecoder* pulse_decoder_alloc() {
|
||||
PulseDecoder* decoder = malloc(sizeof(PulseDecoder));
|
||||
memset(decoder, 0, sizeof(PulseDecoder));
|
||||
return decoder;
|
||||
}
|
||||
|
||||
void pulse_decoder_free(PulseDecoder* reader) {
|
||||
furi_assert(reader);
|
||||
free(reader);
|
||||
}
|
||||
|
||||
void pulse_decoder_add_protocol(PulseDecoder* reader, PulseProtocol* protocol, int32_t index) {
|
||||
furi_check(index < MAX_PROTOCOL);
|
||||
furi_check(reader->protocols[index] == NULL);
|
||||
reader->protocols[index] = protocol;
|
||||
}
|
||||
|
||||
void pulse_decoder_process_pulse(PulseDecoder* reader, bool polarity, uint32_t length) {
|
||||
furi_assert(reader);
|
||||
for(size_t index = 0; index < MAX_PROTOCOL; index++) {
|
||||
if(reader->protocols[index] != NULL) {
|
||||
pulse_protocol_process_pulse(reader->protocols[index], polarity, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t pulse_decoder_get_decoded_index(PulseDecoder* reader) {
|
||||
furi_assert(reader);
|
||||
int32_t decoded = -1;
|
||||
for(size_t index = 0; index < MAX_PROTOCOL; index++) {
|
||||
if(reader->protocols[index] != NULL) {
|
||||
if(pulse_protocol_decoded(reader->protocols[index])) {
|
||||
decoded = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return decoded;
|
||||
}
|
||||
|
||||
void pulse_decoder_reset(PulseDecoder* reader) {
|
||||
furi_assert(reader);
|
||||
for(size_t index = 0; index < MAX_PROTOCOL; index++) {
|
||||
if(reader->protocols[index] != NULL) {
|
||||
pulse_protocol_reset(reader->protocols[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pulse_decoder_get_data(PulseDecoder* reader, int32_t index, uint8_t* data, size_t length) {
|
||||
furi_assert(reader);
|
||||
furi_check(reader->protocols[index] != NULL);
|
||||
pulse_protocol_get_data(reader->protocols[index], data, length);
|
||||
}
|
@@ -1,70 +0,0 @@
|
||||
/**
|
||||
* @file pulse_decoder.h
|
||||
*
|
||||
* Generic pulse protocol decoder library
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "pulse_protocol.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct PulseDecoder PulseDecoder;
|
||||
|
||||
/**
|
||||
* Allocate decoder
|
||||
* @return PulseDecoder*
|
||||
*/
|
||||
PulseDecoder* pulse_decoder_alloc();
|
||||
|
||||
/**
|
||||
* Deallocate decoder
|
||||
* @param decoder
|
||||
*/
|
||||
void pulse_decoder_free(PulseDecoder* decoder);
|
||||
|
||||
/**
|
||||
* Add protocol to decoder
|
||||
* @param decoder
|
||||
* @param protocol protocol implementation
|
||||
* @param index protocol index, should not be repeated
|
||||
*/
|
||||
void pulse_decoder_add_protocol(PulseDecoder* decoder, PulseProtocol* protocol, int32_t index);
|
||||
|
||||
/**
|
||||
* Push and process pulse with decoder
|
||||
* @param decoder
|
||||
* @param polarity
|
||||
* @param length
|
||||
*/
|
||||
void pulse_decoder_process_pulse(PulseDecoder* decoder, bool polarity, uint32_t length);
|
||||
|
||||
/**
|
||||
* Get indec of decoded protocol
|
||||
* @param decoder
|
||||
* @return int32_t, -1 if nothing decoded, or index of decoded protocol
|
||||
*/
|
||||
int32_t pulse_decoder_get_decoded_index(PulseDecoder* decoder);
|
||||
|
||||
/**
|
||||
* Reset all protocols in decoder
|
||||
* @param decoder
|
||||
*/
|
||||
void pulse_decoder_reset(PulseDecoder* decoder);
|
||||
|
||||
/**
|
||||
* Get decoded data from protocol
|
||||
* @param decoder
|
||||
* @param index
|
||||
* @param data
|
||||
* @param length
|
||||
*/
|
||||
void pulse_decoder_get_data(PulseDecoder* decoder, int32_t index, uint8_t* data, size_t length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -1,55 +0,0 @@
|
||||
#include "pulse_glue.h"
|
||||
|
||||
struct PulseGlue {
|
||||
int32_t hi_period;
|
||||
int32_t low_period;
|
||||
int32_t next_hi_period;
|
||||
};
|
||||
|
||||
PulseGlue* pulse_glue_alloc() {
|
||||
PulseGlue* pulse_glue = malloc(sizeof(PulseGlue));
|
||||
pulse_glue_reset(pulse_glue);
|
||||
return pulse_glue;
|
||||
}
|
||||
|
||||
void pulse_glue_free(PulseGlue* pulse_glue) {
|
||||
free(pulse_glue);
|
||||
}
|
||||
|
||||
void pulse_glue_reset(PulseGlue* pulse_glue) {
|
||||
pulse_glue->hi_period = 0;
|
||||
pulse_glue->low_period = 0;
|
||||
pulse_glue->next_hi_period = 0;
|
||||
}
|
||||
|
||||
bool pulse_glue_push(PulseGlue* pulse_glue, bool polarity, uint32_t length) {
|
||||
bool pop_ready = false;
|
||||
if(polarity) {
|
||||
if(pulse_glue->low_period == 0) {
|
||||
// stage 1, accumulate hi period
|
||||
pulse_glue->hi_period += length;
|
||||
} else {
|
||||
// stage 3, accumulate next hi period and be ready for pulse_glue_pop
|
||||
pulse_glue->next_hi_period = length;
|
||||
|
||||
// data is ready
|
||||
pop_ready = true;
|
||||
}
|
||||
} else {
|
||||
if(pulse_glue->hi_period != 0) {
|
||||
// stage 2, accumulate low period
|
||||
pulse_glue->low_period += length;
|
||||
}
|
||||
}
|
||||
|
||||
return pop_ready;
|
||||
}
|
||||
|
||||
void pulse_glue_pop(PulseGlue* pulse_glue, uint32_t* length, uint32_t* period) {
|
||||
*length = pulse_glue->hi_period + pulse_glue->low_period;
|
||||
*period = pulse_glue->hi_period;
|
||||
|
||||
pulse_glue->hi_period = pulse_glue->next_hi_period;
|
||||
pulse_glue->low_period = 0;
|
||||
pulse_glue->next_hi_period = 0;
|
||||
}
|
@@ -1,26 +0,0 @@
|
||||
/**
|
||||
* @file pulse_glue.h
|
||||
*
|
||||
* Simple tool to glue separated pulses to corret
|
||||
*/
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct PulseGlue PulseGlue;
|
||||
|
||||
PulseGlue* pulse_glue_alloc();
|
||||
void pulse_glue_free(PulseGlue* pulse_glue);
|
||||
void pulse_glue_reset(PulseGlue* pulse_glue);
|
||||
|
||||
bool pulse_glue_push(PulseGlue* pulse_glue, bool polarity, uint32_t length);
|
||||
void pulse_glue_pop(PulseGlue* pulse_glue, uint32_t* length, uint32_t* period);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -1,67 +0,0 @@
|
||||
#include "pulse_protocol.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct PulseProtocol {
|
||||
void* context;
|
||||
PulseProtocolPulseCallback pulse_cb;
|
||||
PulseProtocolResetCallback reset_cb;
|
||||
PulseProtocolGetDataCallback get_data_cb;
|
||||
PulseProtocolDecodedCallback decoded_cb;
|
||||
};
|
||||
|
||||
PulseProtocol* pulse_protocol_alloc() {
|
||||
PulseProtocol* protocol = malloc(sizeof(PulseProtocol));
|
||||
memset(protocol, 0, sizeof(PulseProtocol));
|
||||
return protocol;
|
||||
}
|
||||
|
||||
void pulse_protocol_set_context(PulseProtocol* protocol, void* context) {
|
||||
protocol->context = context;
|
||||
}
|
||||
|
||||
void pulse_protocol_set_pulse_cb(PulseProtocol* protocol, PulseProtocolPulseCallback callback) {
|
||||
protocol->pulse_cb = callback;
|
||||
}
|
||||
|
||||
void pulse_protocol_set_reset_cb(PulseProtocol* protocol, PulseProtocolResetCallback callback) {
|
||||
protocol->reset_cb = callback;
|
||||
}
|
||||
|
||||
void pulse_protocol_set_get_data_cb(PulseProtocol* protocol, PulseProtocolGetDataCallback callback) {
|
||||
protocol->get_data_cb = callback;
|
||||
}
|
||||
|
||||
void pulse_protocol_set_decoded_cb(PulseProtocol* protocol, PulseProtocolDecodedCallback callback) {
|
||||
protocol->decoded_cb = callback;
|
||||
}
|
||||
|
||||
void pulse_protocol_free(PulseProtocol* protocol) {
|
||||
free(protocol);
|
||||
}
|
||||
|
||||
void pulse_protocol_process_pulse(PulseProtocol* protocol, bool polarity, uint32_t length) {
|
||||
if(protocol->pulse_cb != NULL) {
|
||||
protocol->pulse_cb(protocol->context, polarity, length);
|
||||
}
|
||||
}
|
||||
|
||||
void pulse_protocol_reset(PulseProtocol* protocol) {
|
||||
if(protocol->reset_cb != NULL) {
|
||||
protocol->reset_cb(protocol->context);
|
||||
}
|
||||
}
|
||||
|
||||
bool pulse_protocol_decoded(PulseProtocol* protocol) {
|
||||
bool result = false;
|
||||
if(protocol->decoded_cb != NULL) {
|
||||
result = protocol->decoded_cb(protocol->context);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void pulse_protocol_get_data(PulseProtocol* protocol, uint8_t* data, size_t length) {
|
||||
if(protocol->get_data_cb != NULL) {
|
||||
protocol->get_data_cb(protocol->context, data, length);
|
||||
}
|
||||
}
|
@@ -1,122 +0,0 @@
|
||||
/**
|
||||
* @file pulse_protocol.h
|
||||
*
|
||||
* Generic pulse protocol decoder library, protocol interface
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Anonymous PulseProtocol struct
|
||||
*/
|
||||
typedef struct PulseProtocol PulseProtocol;
|
||||
|
||||
/**
|
||||
* Process pulse callback
|
||||
*/
|
||||
typedef void (*PulseProtocolPulseCallback)(void* context, bool polarity, uint32_t length);
|
||||
|
||||
/**
|
||||
* Reset protocol callback
|
||||
*/
|
||||
typedef void (*PulseProtocolResetCallback)(void* context);
|
||||
|
||||
/**
|
||||
* Get decoded data callback
|
||||
*/
|
||||
typedef void (*PulseProtocolGetDataCallback)(void* context, uint8_t* data, size_t length);
|
||||
|
||||
/**
|
||||
* Is protocol decoded callback
|
||||
*/
|
||||
typedef bool (*PulseProtocolDecodedCallback)(void* context);
|
||||
|
||||
/**
|
||||
* Allocate protocol
|
||||
* @return PulseProtocol*
|
||||
*/
|
||||
PulseProtocol* pulse_protocol_alloc();
|
||||
|
||||
/**
|
||||
* Deallocate protocol
|
||||
* @param protocol
|
||||
*/
|
||||
void pulse_protocol_free(PulseProtocol* protocol);
|
||||
|
||||
/**
|
||||
* Set context for callbacks
|
||||
* @param protocol
|
||||
* @param context
|
||||
*/
|
||||
void pulse_protocol_set_context(PulseProtocol* protocol, void* context);
|
||||
|
||||
/**
|
||||
* Set "Process pulse" callback. Called from the decoder when a new pulse is received.
|
||||
* @param protocol
|
||||
* @param callback
|
||||
*/
|
||||
void pulse_protocol_set_pulse_cb(PulseProtocol* protocol, PulseProtocolPulseCallback callback);
|
||||
|
||||
/**
|
||||
* Set "Reset protocol" callback. Called from the decoder when the decoder is reset.
|
||||
* @param protocol
|
||||
* @param callback
|
||||
*/
|
||||
void pulse_protocol_set_reset_cb(PulseProtocol* protocol, PulseProtocolResetCallback callback);
|
||||
|
||||
/**
|
||||
* Set "Get decoded data" callback. Called from the decoder when the decoder wants to get decoded data.
|
||||
* @param protocol
|
||||
* @param callback
|
||||
*/
|
||||
void pulse_protocol_set_get_data_cb(PulseProtocol* protocol, PulseProtocolGetDataCallback callback);
|
||||
|
||||
/**
|
||||
* Set "Is protocol decoded" callback. Called from the decoder when the decoder wants to know if a protocol has been decoded.
|
||||
* @param protocol
|
||||
* @param callback
|
||||
*/
|
||||
void pulse_protocol_set_decoded_cb(PulseProtocol* protocol, PulseProtocolDecodedCallback callback);
|
||||
|
||||
/**
|
||||
* Part of decoder interface.
|
||||
* @param protocol
|
||||
* @param polarity
|
||||
* @param length
|
||||
*/
|
||||
void pulse_protocol_process_pulse(PulseProtocol* protocol, bool polarity, uint32_t length);
|
||||
|
||||
/**
|
||||
* Part of decoder interface.
|
||||
* @param protocol
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool pulse_protocol_decoded(PulseProtocol* protocol);
|
||||
|
||||
/**
|
||||
* Part of decoder interface.
|
||||
* @param protocol
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
void pulse_protocol_get_data(PulseProtocol* protocol, uint8_t* data, size_t length);
|
||||
|
||||
/**
|
||||
* Part of decoder interface.
|
||||
* @param protocol
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
void pulse_protocol_reset(PulseProtocol* protocol);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user