[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:
SG
2022-08-24 01:57:39 +10:00
committed by GitHub
parent f92127c0a7
commit 9bfb641d3e
179 changed files with 10234 additions and 4804 deletions

View File

@@ -0,0 +1,22 @@
#include "lfrfid_protocols.h"
#include "protocol_em4100.h"
#include "protocol_h10301.h"
#include "protocol_indala26.h"
#include "protocol_io_prox_xsf.h"
#include "protocol_awid.h"
#include "protocol_fdx_a.h"
#include "protocol_fdx_b.h"
#include "protocol_hid_generic.h"
#include "protocol_hid_ex_generic.h"
const ProtocolBase* lfrfid_protocols[] = {
[LFRFIDProtocolEM4100] = &protocol_em4100,
[LFRFIDProtocolH10301] = &protocol_h10301,
[LFRFIDProtocolIndala26] = &protocol_indala26,
[LFRFIDProtocolIOProxXSF] = &protocol_io_prox_xsf,
[LFRFIDProtocolAwid] = &protocol_awid,
[LFRFIDProtocolFDXA] = &protocol_fdx_a,
[LFRFIDProtocolFDXB] = &protocol_fdx_b,
[LFRFIDProtocolHidGeneric] = &protocol_hid_generic,
[LFRFIDProtocolHidExGeneric] = &protocol_hid_ex_generic,
};

View File

@@ -0,0 +1,35 @@
#pragma once
#include <toolbox/protocols/protocol.h>
#include "../tools/t5577.h"
typedef enum {
LFRFIDFeatureASK = 1 << 0, /** ASK Demodulation */
LFRFIDFeaturePSK = 1 << 1, /** PSK Demodulation */
} LFRFIDFeature;
typedef enum {
LFRFIDProtocolEM4100,
LFRFIDProtocolH10301,
LFRFIDProtocolIndala26,
LFRFIDProtocolIOProxXSF,
LFRFIDProtocolAwid,
LFRFIDProtocolFDXA,
LFRFIDProtocolFDXB,
LFRFIDProtocolHidGeneric,
LFRFIDProtocolHidExGeneric,
LFRFIDProtocolMax,
} LFRFIDProtocol;
extern const ProtocolBase* lfrfid_protocols[];
typedef enum {
LFRFIDWriteTypeT5577,
} LFRFIDWriteType;
typedef struct {
LFRFIDWriteType write_type;
union {
LFRFIDT5577 t5577;
};
} LFRFIDWriteRequest;

View File

@@ -0,0 +1,239 @@
#include <furi.h>
#include <toolbox/protocols/protocol.h>
#include <lfrfid/tools/fsk_demod.h>
#include <lfrfid/tools/fsk_osc.h>
#include <lfrfid/tools/bit_lib.h>
#include "lfrfid_protocols.h"
#define JITTER_TIME (20)
#define MIN_TIME (64 - JITTER_TIME)
#define MAX_TIME (80 + JITTER_TIME)
#define AWID_DECODED_DATA_SIZE (9)
#define AWID_ENCODED_BIT_SIZE (96)
#define AWID_ENCODED_DATA_SIZE (((AWID_ENCODED_BIT_SIZE) / 8) + 1)
#define AWID_ENCODED_DATA_LAST (AWID_ENCODED_DATA_SIZE - 1)
typedef struct {
FSKDemod* fsk_demod;
} ProtocolAwidDecoder;
typedef struct {
FSKOsc* fsk_osc;
uint8_t encoded_index;
} ProtocolAwidEncoder;
typedef struct {
ProtocolAwidDecoder decoder;
ProtocolAwidEncoder encoder;
uint8_t encoded_data[AWID_ENCODED_DATA_SIZE];
uint8_t data[AWID_DECODED_DATA_SIZE];
} ProtocolAwid;
ProtocolAwid* protocol_awid_alloc(void) {
ProtocolAwid* protocol = malloc(sizeof(ProtocolAwid));
protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 6, MAX_TIME, 5);
protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 50);
return protocol;
};
void protocol_awid_free(ProtocolAwid* protocol) {
fsk_demod_free(protocol->decoder.fsk_demod);
fsk_osc_free(protocol->encoder.fsk_osc);
free(protocol);
};
uint8_t* protocol_awid_get_data(ProtocolAwid* protocol) {
return protocol->data;
};
void protocol_awid_decoder_start(ProtocolAwid* protocol) {
memset(protocol->encoded_data, 0, AWID_ENCODED_DATA_SIZE);
};
static bool protocol_awid_can_be_decoded(const uint8_t* data) {
bool result = false;
// Index map
// 0 10 20 30 40 50 60
// | | | | | | |
// 01234567 890 1 234 5 678 9 012 3 456 7 890 1 234 5 678 9 012 3 456 7 890 1 234 5 678 9 012 3 - to 96
// -----------------------------------------------------------------------------
// 00000001 000 1 110 1 101 1 011 1 101 1 010 0 000 1 000 1 010 0 001 0 110 1 100 0 000 1 000 1
// preamble bbb o bbb o bbw o fff o fff o ffc o ccc o ccc o ccc o ccc o ccc o wxx o xxx o xxx o - to 96
// |---26 bit---| |-----117----||-------------142-------------|
// b = format bit len, o = odd parity of last 3 bits
// f = facility code, c = card number
// w = wiegand parity
// (26 bit format shown)
do {
// check preamble and spacing
if(data[0] != 0b00000001 || data[AWID_ENCODED_DATA_LAST] != 0b00000001) break;
// check odd parity for every 4 bits starting from the second byte
bool parity_error = bit_lib_test_parity(data, 8, 88, BitLibParityOdd, 4);
if(parity_error) break;
result = true;
} while(false);
return result;
}
static void protocol_awid_decode(uint8_t* encoded_data, uint8_t* decoded_data) {
bit_lib_remove_bit_every_nth(encoded_data, 8, 88, 4);
bit_lib_copy_bits(decoded_data, 0, 66, encoded_data, 8);
}
bool protocol_awid_decoder_feed(ProtocolAwid* protocol, bool level, uint32_t duration) {
bool value;
uint32_t count;
bool result = false;
fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count);
if(count > 0) {
for(size_t i = 0; i < count; i++) {
bit_lib_push_bit(protocol->encoded_data, AWID_ENCODED_DATA_SIZE, value);
if(protocol_awid_can_be_decoded(protocol->encoded_data)) {
protocol_awid_decode(protocol->encoded_data, protocol->data);
result = true;
break;
}
}
}
return result;
};
static void protocol_awid_encode(const uint8_t* decoded_data, uint8_t* encoded_data) {
memset(encoded_data, 0, AWID_ENCODED_DATA_SIZE);
// preamble
bit_lib_set_bits(encoded_data, 0, 0b00000001, 8);
for(size_t i = 0; i < 88 / 4; i++) {
uint8_t value = bit_lib_get_bits(decoded_data, i * 3, 3) << 1;
value |= bit_lib_test_parity_32(value, BitLibParityOdd);
bit_lib_set_bits(encoded_data, 8 + i * 4, value, 4);
}
};
bool protocol_awid_encoder_start(ProtocolAwid* protocol) {
protocol_awid_encode(protocol->data, (uint8_t*)protocol->encoded_data);
protocol->encoder.encoded_index = 0;
fsk_osc_reset(protocol->encoder.fsk_osc);
return true;
};
LevelDuration protocol_awid_encoder_yield(ProtocolAwid* protocol) {
bool level;
uint32_t duration;
bool bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoder.encoded_index);
bool advance = fsk_osc_next_half(protocol->encoder.fsk_osc, bit, &level, &duration);
if(advance) {
bit_lib_increment_index(protocol->encoder.encoded_index, AWID_ENCODED_BIT_SIZE);
}
return level_duration_make(level, duration);
};
void protocol_awid_render_data(ProtocolAwid* protocol, string_t result) {
// Index map
// 0 10 20 30 40 50 60
// | | | | | | |
// 01234567 8 90123456 7890123456789012 3 456789012345678901234567890123456
// ------------------------------------------------------------------------
// 00011010 1 01110101 0000000010001110 1 000000000000000000000000000000000
// bbbbbbbb w ffffffff cccccccccccccccc w xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// |26 bit| |-117--| |-----142------|
// b = format bit len, o = odd parity of last 3 bits
// f = facility code, c = card number
// w = wiegand parity
// (26 bit format shown)
uint8_t* decoded_data = protocol->data;
uint8_t format_length = decoded_data[0];
string_cat_printf(result, "Format: %d\r\n", format_length);
if(format_length == 26) {
uint8_t facility;
bit_lib_copy_bits(&facility, 0, 8, decoded_data, 9);
uint16_t card_id;
bit_lib_copy_bits((uint8_t*)&card_id, 8, 8, decoded_data, 17);
bit_lib_copy_bits((uint8_t*)&card_id, 0, 8, decoded_data, 25);
string_cat_printf(result, "Facility: %d\r\n", facility);
string_cat_printf(result, "Card: %d", card_id);
} else {
// print 66 bits as hex
string_cat_printf(result, "Data: ");
for(size_t i = 0; i < AWID_DECODED_DATA_SIZE; i++) {
string_cat_printf(result, "%02X", decoded_data[i]);
}
}
};
void protocol_awid_render_brief_data(ProtocolAwid* protocol, string_t result) {
uint8_t* decoded_data = protocol->data;
uint8_t format_length = decoded_data[0];
string_cat_printf(result, "Format: %d\r\n", format_length);
if(format_length == 26) {
uint8_t facility;
bit_lib_copy_bits(&facility, 0, 8, decoded_data, 9);
uint16_t card_id;
bit_lib_copy_bits((uint8_t*)&card_id, 8, 8, decoded_data, 17);
bit_lib_copy_bits((uint8_t*)&card_id, 0, 8, decoded_data, 25);
string_cat_printf(result, "ID: %03u,%05u", facility, card_id);
} else {
string_cat_printf(result, "Data: unknown");
}
};
bool protocol_awid_write_data(ProtocolAwid* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;
protocol_awid_encode(protocol->data, (uint8_t*)protocol->encoded_data);
if(request->write_type == LFRFIDWriteTypeT5577) {
request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_50 |
(3 << LFRFID_T5577_MAXBLOCK_SHIFT);
request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32);
request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32);
request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32);
request->t5577.blocks_to_write = 4;
result = true;
}
return result;
};
const ProtocolBase protocol_awid = {
.name = "AWID",
.manufacturer = "AWIG",
.data_size = AWID_DECODED_DATA_SIZE,
.features = LFRFIDFeatureASK,
.validate_count = 3,
.alloc = (ProtocolAlloc)protocol_awid_alloc,
.free = (ProtocolFree)protocol_awid_free,
.get_data = (ProtocolGetData)protocol_awid_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_awid_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_awid_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_awid_encoder_start,
.yield = (ProtocolEncoderYield)protocol_awid_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_awid_render_data,
.render_brief_data = (ProtocolRenderData)protocol_awid_render_brief_data,
.write_data = (ProtocolWriteData)protocol_awid_write_data,
};

View File

@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>
extern const ProtocolBase protocol_awid;

View File

@@ -0,0 +1,292 @@
#include <furi.h>
#include <toolbox/protocols/protocol.h>
#include <toolbox/manchester_decoder.h>
#include "lfrfid_protocols.h"
typedef uint64_t EM4100DecodedData;
#define EM_HEADER_POS (55)
#define EM_HEADER_MASK (0x1FFLLU << EM_HEADER_POS)
#define EM_FIRST_ROW_POS (50)
#define EM_ROW_COUNT (10)
#define EM_COLUMN_COUNT (4)
#define EM_BITS_PER_ROW_COUNT (EM_COLUMN_COUNT + 1)
#define EM_COLUMN_POS (4)
#define EM_STOP_POS (0)
#define EM_STOP_MASK (0x1LLU << EM_STOP_POS)
#define EM_HEADER_AND_STOP_MASK (EM_HEADER_MASK | EM_STOP_MASK)
#define EM_HEADER_AND_STOP_DATA (EM_HEADER_MASK)
#define EM4100_DECODED_DATA_SIZE (5)
#define EM4100_ENCODED_DATA_SIZE (sizeof(EM4100DecodedData))
#define EM4100_CLOCK_PER_BIT (64)
#define EM_READ_SHORT_TIME (256)
#define EM_READ_LONG_TIME (512)
#define EM_READ_JITTER_TIME (100)
#define EM_READ_SHORT_TIME_LOW (EM_READ_SHORT_TIME - EM_READ_JITTER_TIME)
#define EM_READ_SHORT_TIME_HIGH (EM_READ_SHORT_TIME + EM_READ_JITTER_TIME)
#define EM_READ_LONG_TIME_LOW (EM_READ_LONG_TIME - EM_READ_JITTER_TIME)
#define EM_READ_LONG_TIME_HIGH (EM_READ_LONG_TIME + EM_READ_JITTER_TIME)
typedef struct {
uint8_t data[EM4100_DECODED_DATA_SIZE];
EM4100DecodedData encoded_data;
uint8_t encoded_data_index;
bool encoded_polarity;
ManchesterState decoder_manchester_state;
} ProtocolEM4100;
ProtocolEM4100* protocol_em4100_alloc(void) {
ProtocolEM4100* proto = malloc(sizeof(ProtocolEM4100));
return (void*)proto;
};
void protocol_em4100_free(ProtocolEM4100* proto) {
free(proto);
};
uint8_t* protocol_em4100_get_data(ProtocolEM4100* proto) {
return proto->data;
};
static void em4100_decode(
const uint8_t* encoded_data,
const uint8_t encoded_data_size,
uint8_t* decoded_data,
const uint8_t decoded_data_size) {
furi_check(decoded_data_size >= EM4100_DECODED_DATA_SIZE);
furi_check(encoded_data_size >= EM4100_ENCODED_DATA_SIZE);
uint8_t decoded_data_index = 0;
EM4100DecodedData card_data = *((EM4100DecodedData*)(encoded_data));
// clean result
memset(decoded_data, 0, decoded_data_size);
// header
for(uint8_t i = 0; i < 9; i++) {
card_data = card_data << 1;
}
// nibbles
uint8_t value = 0;
for(uint8_t r = 0; r < EM_ROW_COUNT; r++) {
uint8_t nibble = 0;
for(uint8_t i = 0; i < 5; i++) {
if(i < 4) nibble = (nibble << 1) | (card_data & (1LLU << 63) ? 1 : 0);
card_data = card_data << 1;
}
value = (value << 4) | nibble;
if(r % 2) {
decoded_data[decoded_data_index] |= value;
decoded_data_index++;
value = 0;
}
}
}
static bool em4100_can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) {
furi_check(encoded_data_size >= EM4100_ENCODED_DATA_SIZE);
const EM4100DecodedData* card_data = (EM4100DecodedData*)encoded_data;
// check header and stop bit
if((*card_data & EM_HEADER_AND_STOP_MASK) != EM_HEADER_AND_STOP_DATA) return false;
// check row parity
for(uint8_t i = 0; i < EM_ROW_COUNT; i++) {
uint8_t parity_sum = 0;
for(uint8_t j = 0; j < EM_BITS_PER_ROW_COUNT; j++) {
parity_sum += (*card_data >> (EM_FIRST_ROW_POS - i * EM_BITS_PER_ROW_COUNT + j)) & 1;
}
if((parity_sum % 2)) {
return false;
}
}
// check columns parity
for(uint8_t i = 0; i < EM_COLUMN_COUNT; i++) {
uint8_t parity_sum = 0;
for(uint8_t j = 0; j < EM_ROW_COUNT + 1; j++) {
parity_sum += (*card_data >> (EM_COLUMN_POS - i + j * EM_BITS_PER_ROW_COUNT)) & 1;
}
if((parity_sum % 2)) {
return false;
}
}
return true;
}
void protocol_em4100_decoder_start(ProtocolEM4100* proto) {
memset(proto->data, 0, EM4100_DECODED_DATA_SIZE);
proto->encoded_data = 0;
manchester_advance(
proto->decoder_manchester_state,
ManchesterEventReset,
&proto->decoder_manchester_state,
NULL);
};
bool protocol_em4100_decoder_feed(ProtocolEM4100* proto, bool level, uint32_t duration) {
bool result = false;
ManchesterEvent event = ManchesterEventReset;
if(duration > EM_READ_SHORT_TIME_LOW && duration < EM_READ_SHORT_TIME_HIGH) {
if(!level) {
event = ManchesterEventShortHigh;
} else {
event = ManchesterEventShortLow;
}
} else if(duration > EM_READ_LONG_TIME_LOW && duration < EM_READ_LONG_TIME_HIGH) {
if(!level) {
event = ManchesterEventLongHigh;
} else {
event = ManchesterEventLongLow;
}
}
if(event != ManchesterEventReset) {
bool data;
bool data_ok = manchester_advance(
proto->decoder_manchester_state, event, &proto->decoder_manchester_state, &data);
if(data_ok) {
proto->encoded_data = (proto->encoded_data << 1) | data;
if(em4100_can_be_decoded((uint8_t*)&proto->encoded_data, sizeof(EM4100DecodedData))) {
em4100_decode(
(uint8_t*)&proto->encoded_data,
sizeof(EM4100DecodedData),
proto->data,
EM4100_DECODED_DATA_SIZE);
result = true;
}
}
}
return result;
};
static void em4100_write_nibble(bool low_nibble, uint8_t data, EM4100DecodedData* encoded_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;
*encoded_data = (*encoded_data << 1) | ((data >> i) & 1);
}
*encoded_data = (*encoded_data << 1) | ((parity_sum % 2) & 1);
}
bool protocol_em4100_encoder_start(ProtocolEM4100* proto) {
// header
proto->encoded_data = 0b111111111;
// data
for(uint8_t i = 0; i < EM4100_DECODED_DATA_SIZE; i++) {
em4100_write_nibble(false, proto->data[i], &proto->encoded_data);
em4100_write_nibble(true, proto->data[i], &proto->encoded_data);
}
// column parity and stop bit
uint8_t parity_sum;
for(uint8_t c = 0; c < EM_COLUMN_COUNT; c++) {
parity_sum = 0;
for(uint8_t i = 1; i <= EM_ROW_COUNT; i++) {
uint8_t parity_bit = (proto->encoded_data >> (i * EM_BITS_PER_ROW_COUNT - 1)) & 1;
parity_sum += parity_bit;
}
proto->encoded_data = (proto->encoded_data << 1) | ((parity_sum % 2) & 1);
}
// stop bit
proto->encoded_data = (proto->encoded_data << 1) | 0;
proto->encoded_data_index = 0;
proto->encoded_polarity = true;
return true;
};
LevelDuration protocol_em4100_encoder_yield(ProtocolEM4100* proto) {
bool level = (proto->encoded_data >> (63 - proto->encoded_data_index)) & 1;
uint32_t duration = EM4100_CLOCK_PER_BIT / 2;
if(proto->encoded_polarity) {
proto->encoded_polarity = false;
} else {
level = !level;
proto->encoded_polarity = true;
proto->encoded_data_index++;
if(proto->encoded_data_index >= 64) {
proto->encoded_data_index = 0;
}
}
return level_duration_make(level, duration);
};
bool protocol_em4100_write_data(ProtocolEM4100* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;
protocol_em4100_encoder_start(protocol);
if(request->write_type == LFRFIDWriteTypeT5577) {
request->t5577.block[0] =
(LFRFID_T5577_MODULATION_MANCHESTER | LFRFID_T5577_BITRATE_RF_64 |
(2 << LFRFID_T5577_MAXBLOCK_SHIFT));
request->t5577.block[1] = protocol->encoded_data;
request->t5577.block[2] = protocol->encoded_data >> 32;
request->t5577.blocks_to_write = 3;
result = true;
}
return result;
};
void protocol_em4100_render_data(ProtocolEM4100* protocol, string_t result) {
uint8_t* data = protocol->data;
string_printf(result, "ID: %03u,%05u", data[2], (uint16_t)((data[3] << 8) | (data[4])));
};
const ProtocolBase protocol_em4100 = {
.name = "EM4100",
.manufacturer = "EM-Micro",
.data_size = EM4100_DECODED_DATA_SIZE,
.features = LFRFIDFeatureASK | LFRFIDFeaturePSK,
.validate_count = 3,
.alloc = (ProtocolAlloc)protocol_em4100_alloc,
.free = (ProtocolFree)protocol_em4100_free,
.get_data = (ProtocolGetData)protocol_em4100_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_em4100_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_em4100_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_em4100_encoder_start,
.yield = (ProtocolEncoderYield)protocol_em4100_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_em4100_render_data,
.render_brief_data = (ProtocolRenderData)protocol_em4100_render_data,
.write_data = (ProtocolWriteData)protocol_em4100_write_data,
};

View File

@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>
extern const ProtocolBase protocol_em4100;

View File

@@ -0,0 +1,239 @@
#include <furi.h>
#include <toolbox/protocols/protocol.h>
#include <lfrfid/tools/fsk_demod.h>
#include <lfrfid/tools/fsk_osc.h>
#include "lfrfid_protocols.h"
#include <lfrfid/tools/bit_lib.h>
#define JITTER_TIME (20)
#define MIN_TIME (64 - JITTER_TIME)
#define MAX_TIME (80 + JITTER_TIME)
#define FDXA_DATA_SIZE 10
#define FDXA_PREAMBLE_SIZE 2
#define FDXA_ENCODED_DATA_SIZE (FDXA_PREAMBLE_SIZE + FDXA_DATA_SIZE + FDXA_PREAMBLE_SIZE)
#define FDXA_ENCODED_BIT_SIZE ((FDXA_PREAMBLE_SIZE + FDXA_DATA_SIZE) * 8)
#define FDXA_DECODED_DATA_SIZE (5)
#define FDXA_DECODED_BIT_SIZE ((FDXA_ENCODED_BIT_SIZE - FDXA_PREAMBLE_SIZE * 8) / 2)
#define FDXA_PREAMBLE_0 0x55
#define FDXA_PREAMBLE_1 0x1D
typedef struct {
FSKDemod* fsk_demod;
} ProtocolFDXADecoder;
typedef struct {
FSKOsc* fsk_osc;
uint8_t encoded_index;
uint32_t pulse;
} ProtocolFDXAEncoder;
typedef struct {
ProtocolFDXADecoder decoder;
ProtocolFDXAEncoder encoder;
uint8_t encoded_data[FDXA_ENCODED_DATA_SIZE];
uint8_t data[FDXA_DECODED_DATA_SIZE];
size_t protocol_size;
} ProtocolFDXA;
ProtocolFDXA* protocol_fdx_a_alloc(void) {
ProtocolFDXA* protocol = malloc(sizeof(ProtocolFDXA));
protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 6, MAX_TIME, 5);
protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 50);
return protocol;
};
void protocol_fdx_a_free(ProtocolFDXA* protocol) {
fsk_demod_free(protocol->decoder.fsk_demod);
fsk_osc_free(protocol->encoder.fsk_osc);
free(protocol);
};
uint8_t* protocol_fdx_a_get_data(ProtocolFDXA* protocol) {
return protocol->data;
};
void protocol_fdx_a_decoder_start(ProtocolFDXA* protocol) {
memset(protocol->encoded_data, 0, FDXA_ENCODED_DATA_SIZE);
};
static bool protocol_fdx_a_decode(const uint8_t* from, uint8_t* to) {
size_t bit_index = 0;
for(size_t i = FDXA_PREAMBLE_SIZE; i < (FDXA_PREAMBLE_SIZE + FDXA_DATA_SIZE); i++) {
for(size_t n = 0; n < 4; n++) {
uint8_t bit_pair = (from[i] >> (6 - (n * 2))) & 0b11;
if(bit_pair == 0b01) {
bit_lib_set_bit(to, bit_index, 0);
} else if(bit_pair == 0b10) {
bit_lib_set_bit(to, bit_index, 1);
} else {
return false;
}
bit_index++;
}
}
return true;
}
static bool protocol_fdx_a_can_be_decoded(const uint8_t* data) {
// check preamble
if(data[0] != FDXA_PREAMBLE_0 || data[1] != FDXA_PREAMBLE_1 || data[12] != FDXA_PREAMBLE_0 ||
data[13] != FDXA_PREAMBLE_1) {
return false;
}
// check for manchester encoding
uint8_t decoded_data[FDXA_DECODED_DATA_SIZE];
if(!protocol_fdx_a_decode(data, decoded_data)) return false;
uint8_t parity_sum = 0;
for(size_t i = 0; i < FDXA_DECODED_DATA_SIZE; i++) {
parity_sum += bit_lib_test_parity_32(decoded_data[i], BitLibParityOdd);
decoded_data[i] &= 0x7F;
}
return (parity_sum == 0);
}
bool protocol_fdx_a_decoder_feed(ProtocolFDXA* protocol, bool level, uint32_t duration) {
bool value;
uint32_t count;
bool result = false;
fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count);
if(count > 0) {
for(size_t i = 0; i < count; i++) {
bit_lib_push_bit(protocol->encoded_data, FDXA_ENCODED_DATA_SIZE, value);
if(protocol_fdx_a_can_be_decoded(protocol->encoded_data)) {
protocol_fdx_a_decode(protocol->encoded_data, protocol->data);
result = true;
}
}
}
return result;
};
static void protocol_fdx_a_encode(ProtocolFDXA* protocol) {
protocol->encoded_data[0] = FDXA_PREAMBLE_0;
protocol->encoded_data[1] = FDXA_PREAMBLE_1;
size_t bit_index = 0;
for(size_t i = 0; i < FDXA_DECODED_BIT_SIZE; i++) {
bool bit = bit_lib_get_bit(protocol->data, i);
if(bit) {
bit_lib_set_bit(protocol->encoded_data, 16 + bit_index, 1);
bit_lib_set_bit(protocol->encoded_data, 16 + bit_index + 1, 0);
} else {
bit_lib_set_bit(protocol->encoded_data, 16 + bit_index, 0);
bit_lib_set_bit(protocol->encoded_data, 16 + bit_index + 1, 1);
}
bit_index += 2;
}
}
bool protocol_fdx_a_encoder_start(ProtocolFDXA* protocol) {
protocol->encoder.encoded_index = 0;
protocol->encoder.pulse = 0;
protocol_fdx_a_encode(protocol);
return true;
};
LevelDuration protocol_fdx_a_encoder_yield(ProtocolFDXA* protocol) {
bool level = 0;
uint32_t duration = 0;
// if pulse is zero, we need to output high, otherwise we need to output low
if(protocol->encoder.pulse == 0) {
// get bit
uint8_t bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoder.encoded_index);
// get pulse from oscillator
bool advance = fsk_osc_next(protocol->encoder.fsk_osc, bit, &duration);
if(advance) {
bit_lib_increment_index(protocol->encoder.encoded_index, FDXA_ENCODED_BIT_SIZE);
}
// duration diveded by 2 because we need to output high and low
duration = duration / 2;
protocol->encoder.pulse = duration;
level = true;
} else {
// output low half and reset pulse
duration = protocol->encoder.pulse;
protocol->encoder.pulse = 0;
level = false;
}
return level_duration_make(level, duration);
};
bool protocol_fdx_a_write_data(ProtocolFDXA* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;
protocol_fdx_a_encoder_start(protocol);
if(request->write_type == LFRFIDWriteTypeT5577) {
request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_50 |
(3 << LFRFID_T5577_MAXBLOCK_SHIFT);
request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32);
request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32);
request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32);
request->t5577.blocks_to_write = 4;
result = true;
}
return result;
};
void protocol_fdx_a_render_data(ProtocolFDXA* protocol, string_t result) {
uint8_t data[FDXA_DECODED_DATA_SIZE];
memcpy(data, protocol->data, FDXA_DECODED_DATA_SIZE);
uint8_t parity_sum = 0;
for(size_t i = 0; i < FDXA_DECODED_DATA_SIZE; i++) {
parity_sum += bit_lib_test_parity_32(data[i], BitLibParityOdd);
data[i] &= 0x7F;
}
string_printf(
result,
"ID: %02X%02X%02X%02X%02X\r\n"
"Parity: %s",
data[0],
data[1],
data[2],
data[3],
data[4],
parity_sum == 0 ? "+" : "-");
};
const ProtocolBase protocol_fdx_a = {
.name = "FDX-A",
.manufacturer = "FECAVA",
.data_size = FDXA_DECODED_DATA_SIZE,
.features = LFRFIDFeatureASK,
.validate_count = 3,
.alloc = (ProtocolAlloc)protocol_fdx_a_alloc,
.free = (ProtocolFree)protocol_fdx_a_free,
.get_data = (ProtocolGetData)protocol_fdx_a_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_fdx_a_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_fdx_a_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_fdx_a_encoder_start,
.yield = (ProtocolEncoderYield)protocol_fdx_a_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_fdx_a_render_data,
.render_brief_data = (ProtocolRenderData)protocol_fdx_a_render_data,
.write_data = (ProtocolWriteData)protocol_fdx_a_write_data,
};

View File

@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>
extern const ProtocolBase protocol_fdx_a;

View File

@@ -0,0 +1,374 @@
#include <furi.h>
#include "toolbox/level_duration.h"
#include "protocol_fdx_b.h"
#include <toolbox/manchester_decoder.h>
#include <lfrfid/tools/bit_lib.h>
#include "lfrfid_protocols.h"
#define FDX_B_ENCODED_BIT_SIZE (128)
#define FDX_B_ENCODED_BYTE_SIZE (((FDX_B_ENCODED_BIT_SIZE) / 8))
#define FDX_B_PREAMBLE_BIT_SIZE (11)
#define FDX_B_PREAMBLE_BYTE_SIZE (2)
#define FDX_B_ENCODED_BYTE_FULL_SIZE (FDX_B_ENCODED_BYTE_SIZE + FDX_B_PREAMBLE_BYTE_SIZE)
#define FDXB_DECODED_DATA_SIZE (11)
#define FDX_B_SHORT_TIME (128)
#define FDX_B_LONG_TIME (256)
#define FDX_B_JITTER_TIME (60)
#define FDX_B_SHORT_TIME_LOW (FDX_B_SHORT_TIME - FDX_B_JITTER_TIME)
#define FDX_B_SHORT_TIME_HIGH (FDX_B_SHORT_TIME + FDX_B_JITTER_TIME)
#define FDX_B_LONG_TIME_LOW (FDX_B_LONG_TIME - FDX_B_JITTER_TIME)
#define FDX_B_LONG_TIME_HIGH (FDX_B_LONG_TIME + FDX_B_JITTER_TIME)
typedef struct {
bool last_short;
bool last_level;
size_t encoded_index;
uint8_t encoded_data[FDX_B_ENCODED_BYTE_FULL_SIZE];
uint8_t data[FDXB_DECODED_DATA_SIZE];
} ProtocolFDXB;
ProtocolFDXB* protocol_fdx_b_alloc(void) {
ProtocolFDXB* protocol = malloc(sizeof(ProtocolFDXB));
return protocol;
};
void protocol_fdx_b_free(ProtocolFDXB* protocol) {
free(protocol);
};
uint8_t* protocol_fdx_b_get_data(ProtocolFDXB* proto) {
return proto->data;
};
void protocol_fdx_b_decoder_start(ProtocolFDXB* protocol) {
memset(protocol->encoded_data, 0, FDX_B_ENCODED_BYTE_FULL_SIZE);
protocol->last_short = false;
};
static bool protocol_fdx_b_can_be_decoded(ProtocolFDXB* protocol) {
bool result = false;
/*
msb lsb
0 10000000000 Header pattern. 11 bits.
11 1nnnnnnnn
20 1nnnnnnnn 38 bit (12 digit) National code.
29 1nnnnnnnn eg. 000000001008 (decimal).
38 1nnnnnnnn
47 1nnnnnncc 10 bit (3 digit) Country code.
56 1cccccccc eg. 999 (decimal).
65 1s------- 1 bit data block status flag.
74 1-------a 1 bit animal application indicator.
83 1xxxxxxxx 16 bit checksum.
92 1xxxxxxxx
101 1eeeeeeee 24 bits of extra data if present.
110 1eeeeeeee eg. $123456.
119 1eeeeeeee
*/
do {
// check 11 bits preamble
if(bit_lib_get_bits_16(protocol->encoded_data, 0, 11) != 0b10000000000) break;
// check next 11 bits preamble
if(bit_lib_get_bits_16(protocol->encoded_data, 128, 11) != 0b10000000000) break;
// check control bits
if(!bit_lib_test_parity(protocol->encoded_data, 3, 13 * 9, BitLibParityAlways1, 9)) break;
// compute checksum
uint8_t crc_data[8];
for(size_t i = 0; i < 8; i++) {
bit_lib_copy_bits(crc_data, i * 8, 8, protocol->encoded_data, 12 + 9 * i);
}
uint16_t crc_res = bit_lib_crc16(crc_data, 8, 0x1021, 0x0000, false, false, 0x0000);
// read checksum
uint16_t crc_ex = 0;
bit_lib_copy_bits((uint8_t*)&crc_ex, 8, 8, protocol->encoded_data, 84);
bit_lib_copy_bits((uint8_t*)&crc_ex, 0, 8, protocol->encoded_data, 93);
// compare checksum
if(crc_res != crc_ex) break;
result = true;
} while(false);
return result;
}
void protocol_fdx_b_decode(ProtocolFDXB* protocol) {
// remove parity
bit_lib_remove_bit_every_nth(protocol->encoded_data, 3, 13 * 9, 9);
// remove header pattern
for(size_t i = 0; i < 11; i++)
bit_lib_push_bit(protocol->encoded_data, FDX_B_ENCODED_BYTE_FULL_SIZE, 0);
// 0 nnnnnnnn
// 8 nnnnnnnn 38 bit (12 digit) National code.
// 16 nnnnnnnn eg. 000000001008 (decimal).
// 24 nnnnnnnn
// 32 nnnnnncc 10 bit (3 digit) Country code.
// 40 cccccccc eg. 999 (decimal).
// 48 s------- 1 bit data block status flag.
// 56 -------a 1 bit animal application indicator.
// 64 xxxxxxxx 16 bit checksum.
// 72 xxxxxxxx
// 80 eeeeeeee 24 bits of extra data if present.
// 88 eeeeeeee eg. $123456.
// 92 eeeeeeee
// copy data without checksum
bit_lib_copy_bits(protocol->data, 0, 64, protocol->encoded_data, 0);
bit_lib_copy_bits(protocol->data, 64, 24, protocol->encoded_data, 80);
// const BitLibRegion regions_encoded[] = {
// {'n', 0, 38},
// {'c', 38, 10},
// {'b', 48, 16},
// {'x', 64, 16},
// {'e', 80, 24},
// };
// bit_lib_print_regions(regions_encoded, 5, protocol->encoded_data, FDX_B_ENCODED_BIT_SIZE);
// const BitLibRegion regions_decoded[] = {
// {'n', 0, 38},
// {'c', 38, 10},
// {'b', 48, 16},
// {'e', 64, 24},
// };
// bit_lib_print_regions(regions_decoded, 4, protocol->data, FDXB_DECODED_DATA_SIZE * 8);
}
bool protocol_fdx_b_decoder_feed(ProtocolFDXB* protocol, bool level, uint32_t duration) {
bool result = false;
UNUSED(level);
bool pushed = false;
// Bi-Phase Manchester decoding
if(duration >= FDX_B_SHORT_TIME_LOW && duration <= FDX_B_SHORT_TIME_HIGH) {
if(protocol->last_short == false) {
protocol->last_short = true;
} else {
pushed = true;
bit_lib_push_bit(protocol->encoded_data, FDX_B_ENCODED_BYTE_FULL_SIZE, false);
protocol->last_short = false;
}
} else if(duration >= FDX_B_LONG_TIME_LOW && duration <= FDX_B_LONG_TIME_HIGH) {
if(protocol->last_short == false) {
pushed = true;
bit_lib_push_bit(protocol->encoded_data, FDX_B_ENCODED_BYTE_FULL_SIZE, true);
} else {
// reset
protocol->last_short = false;
}
} else {
// reset
protocol->last_short = false;
}
if(pushed && protocol_fdx_b_can_be_decoded(protocol)) {
protocol_fdx_b_decode(protocol);
result = true;
}
return result;
};
bool protocol_fdx_b_encoder_start(ProtocolFDXB* protocol) {
memset(protocol->encoded_data, 0, FDX_B_ENCODED_BYTE_FULL_SIZE);
bit_lib_set_bit(protocol->encoded_data, 0, 1);
for(size_t i = 0; i < 13; i++) {
bit_lib_set_bit(protocol->encoded_data, 11 + 9 * i, 1);
if(i == 8 || i == 9) continue;
if(i < 8) {
bit_lib_copy_bits(protocol->encoded_data, 12 + 9 * i, 8, protocol->data, i * 8);
} else {
bit_lib_copy_bits(protocol->encoded_data, 12 + 9 * i, 8, protocol->data, (i - 2) * 8);
}
}
uint16_t crc_res = bit_lib_crc16(protocol->data, 8, 0x1021, 0x0000, false, false, 0x0000);
bit_lib_copy_bits(protocol->encoded_data, 84, 8, (uint8_t*)&crc_res, 8);
bit_lib_copy_bits(protocol->encoded_data, 93, 8, (uint8_t*)&crc_res, 0);
protocol->encoded_index = 0;
protocol->last_short = false;
protocol->last_level = false;
return true;
};
LevelDuration protocol_fdx_b_encoder_yield(ProtocolFDXB* protocol) {
uint32_t duration;
protocol->last_level = !protocol->last_level;
bool bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoded_index);
// Bi-Phase Manchester encoder
if(bit) {
// one long pulse for 1
duration = FDX_B_LONG_TIME / 8;
bit_lib_increment_index(protocol->encoded_index, FDX_B_ENCODED_BIT_SIZE);
} else {
// two short pulses for 0
duration = FDX_B_SHORT_TIME / 8;
if(protocol->last_short) {
bit_lib_increment_index(protocol->encoded_index, FDX_B_ENCODED_BIT_SIZE);
protocol->last_short = false;
} else {
protocol->last_short = true;
}
}
return level_duration_make(protocol->last_level, duration);
};
// 0 nnnnnnnn
// 8 nnnnnnnn 38 bit (12 digit) National code.
// 16 nnnnnnnn eg. 000000001008 (decimal).
// 24 nnnnnnnn
// 32 nnnnnnnn 10 bit (3 digit) Country code.
// 40 cccccccc eg. 999 (decimal).
// 48 s------- 1 bit data block status flag.
// 56 -------a 1 bit animal application indicator.
// 64 eeeeeeee 24 bits of extra data if present.
// 72 eeeeeeee eg. $123456.
// 80 eeeeeeee
static uint64_t protocol_fdx_b_get_national_code(const uint8_t* data) {
uint64_t national_code = bit_lib_get_bits_32(data, 0, 32);
national_code = national_code << 32;
national_code |= bit_lib_get_bits_32(data, 32, 6) << (32 - 6);
bit_lib_reverse_bits((uint8_t*)&national_code, 0, 64);
return national_code;
}
static uint16_t protocol_fdx_b_get_country_code(const uint8_t* data) {
uint16_t country_code = bit_lib_get_bits_16(data, 38, 10) << 6;
bit_lib_reverse_bits((uint8_t*)&country_code, 0, 16);
return country_code;
}
static bool protocol_fdx_b_get_temp(const uint8_t* data, float* temp) {
uint32_t extended = bit_lib_get_bits_32(data, 64, 24) << 8;
bit_lib_reverse_bits((uint8_t*)&extended, 0, 32);
uint8_t ex_parity = (extended & 0x100) >> 8;
uint8_t ex_temperature = extended & 0xff;
uint8_t ex_calc_parity = bit_lib_test_parity_32(ex_temperature, BitLibParityOdd);
bool ex_temperature_present = (ex_calc_parity == ex_parity) && !(extended & 0xe00);
if(ex_temperature_present) {
float temperature_f = 74 + ex_temperature * 0.2;
*temp = temperature_f;
return true;
} else {
return false;
}
}
void protocol_fdx_b_render_data(ProtocolFDXB* protocol, string_t result) {
// 38 bits of national code
uint64_t national_code = protocol_fdx_b_get_national_code(protocol->data);
// 10 bit of country code
uint16_t country_code = protocol_fdx_b_get_country_code(protocol->data);
bool block_status = bit_lib_get_bit(protocol->data, 48);
bool rudi_bit = bit_lib_get_bit(protocol->data, 49);
uint8_t reserved = bit_lib_get_bits(protocol->data, 50, 5);
uint8_t user_info = bit_lib_get_bits(protocol->data, 55, 5);
uint8_t replacement_number = bit_lib_get_bits(protocol->data, 60, 3);
bool animal_flag = bit_lib_get_bit(protocol->data, 63);
string_printf(result, "ID: %03u-%012llu\r\n", country_code, national_code);
string_cat_printf(result, "Animal: %s, ", animal_flag ? "Yes" : "No");
float temperature;
if(protocol_fdx_b_get_temp(protocol->data, &temperature)) {
float temperature_c = (temperature - 32) / 1.8;
string_cat_printf(
result, "T: %.2fF, %.2fC\r\n", (double)temperature, (double)temperature_c);
} else {
string_cat_printf(result, "T: ---\r\n");
}
string_cat_printf(
result,
"Bits: %X-%X-%X-%X-%X",
block_status,
rudi_bit,
reserved,
user_info,
replacement_number);
};
void protocol_fdx_b_render_brief_data(ProtocolFDXB* protocol, string_t result) {
// 38 bits of national code
uint64_t national_code = protocol_fdx_b_get_national_code(protocol->data);
// 10 bit of country code
uint16_t country_code = protocol_fdx_b_get_country_code(protocol->data);
bool animal_flag = bit_lib_get_bit(protocol->data, 63);
string_printf(result, "ID: %03u-%012llu\r\n", country_code, national_code);
string_cat_printf(result, "Animal: %s, ", animal_flag ? "Yes" : "No");
float temperature;
if(protocol_fdx_b_get_temp(protocol->data, &temperature)) {
float temperature_c = (temperature - 32) / 1.8;
string_cat_printf(result, "T: %.2fC", (double)temperature_c);
} else {
string_cat_printf(result, "T: ---");
}
};
bool protocol_fdx_b_write_data(ProtocolFDXB* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;
protocol_fdx_b_encoder_start(protocol);
if(request->write_type == LFRFIDWriteTypeT5577) {
request->t5577.block[0] = LFRFID_T5577_MODULATION_DIPHASE | LFRFID_T5577_BITRATE_RF_32 |
(4 << LFRFID_T5577_MAXBLOCK_SHIFT);
request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32);
request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32);
request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32);
request->t5577.block[4] = bit_lib_get_bits_32(protocol->encoded_data, 96, 32);
request->t5577.blocks_to_write = 5;
result = true;
}
return result;
};
const ProtocolBase protocol_fdx_b = {
.name = "FDX-B",
.manufacturer = "ISO",
.data_size = FDXB_DECODED_DATA_SIZE,
.features = LFRFIDFeatureASK,
.validate_count = 3,
.alloc = (ProtocolAlloc)protocol_fdx_b_alloc,
.free = (ProtocolFree)protocol_fdx_b_free,
.get_data = (ProtocolGetData)protocol_fdx_b_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_fdx_b_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_fdx_b_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_fdx_b_encoder_start,
.yield = (ProtocolEncoderYield)protocol_fdx_b_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_fdx_b_render_data,
.render_brief_data = (ProtocolRenderData)protocol_fdx_b_render_brief_data,
.write_data = (ProtocolWriteData)protocol_fdx_b_write_data,
};

View File

@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>
extern const ProtocolBase protocol_fdx_b;

View File

@@ -0,0 +1,386 @@
#include <furi.h>
#include <toolbox/protocols/protocol.h>
#include <lfrfid/tools/fsk_demod.h>
#include <lfrfid/tools/fsk_osc.h>
#include "lfrfid_protocols.h"
#define JITTER_TIME (20)
#define MIN_TIME (64 - JITTER_TIME)
#define MAX_TIME (80 + JITTER_TIME)
#define H10301_DECODED_DATA_SIZE (3)
#define H10301_ENCODED_DATA_SIZE_U32 (3)
#define H10301_ENCODED_DATA_SIZE (sizeof(uint32_t) * H10301_ENCODED_DATA_SIZE_U32)
#define H10301_BIT_SIZE (sizeof(uint32_t) * 8)
#define H10301_BIT_MAX_SIZE (H10301_BIT_SIZE * H10301_DECODED_DATA_SIZE)
typedef struct {
FSKDemod* fsk_demod;
} ProtocolH10301Decoder;
typedef struct {
FSKOsc* fsk_osc;
uint8_t encoded_index;
uint32_t pulse;
} ProtocolH10301Encoder;
typedef struct {
ProtocolH10301Decoder decoder;
ProtocolH10301Encoder encoder;
uint32_t encoded_data[H10301_ENCODED_DATA_SIZE_U32];
uint8_t data[H10301_DECODED_DATA_SIZE];
} ProtocolH10301;
ProtocolH10301* protocol_h10301_alloc(void) {
ProtocolH10301* protocol = malloc(sizeof(ProtocolH10301));
protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 6, MAX_TIME, 5);
protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 50);
return protocol;
};
void protocol_h10301_free(ProtocolH10301* protocol) {
fsk_demod_free(protocol->decoder.fsk_demod);
fsk_osc_free(protocol->encoder.fsk_osc);
free(protocol);
};
uint8_t* protocol_h10301_get_data(ProtocolH10301* protocol) {
return protocol->data;
};
void protocol_h10301_decoder_start(ProtocolH10301* protocol) {
memset(protocol->encoded_data, 0, sizeof(uint32_t) * 3);
};
static void protocol_h10301_decoder_store_data(ProtocolH10301* protocol, bool data) {
protocol->encoded_data[0] = (protocol->encoded_data[0] << 1) |
((protocol->encoded_data[1] >> 31) & 1);
protocol->encoded_data[1] = (protocol->encoded_data[1] << 1) |
((protocol->encoded_data[2] >> 31) & 1);
protocol->encoded_data[2] = (protocol->encoded_data[2] << 1) | data;
}
static bool protocol_h10301_can_be_decoded(const uint32_t* card_data) {
const uint8_t* encoded_data = (const uint8_t*)card_data;
// packet preamble
// raw data
if(*(encoded_data + 3) != 0x1D) {
return false;
}
// encoded company/oem
// coded with 01 = 0, 10 = 1 transitions
// stored in word 0
if((*card_data >> 10 & 0x3FFF) != 0x1556) {
return false;
}
// encoded format/length
// coded with 01 = 0, 10 = 1 transitions
// stored in word 0 and word 1
if((((*card_data & 0x3FF) << 12) | ((*(card_data + 1) >> 20) & 0xFFF)) != 0x155556) {
return false;
}
// data decoding
uint32_t result = 0;
// decode from word 1
// coded with 01 = 0, 10 = 1 transitions
for(int8_t i = 9; i >= 0; i--) {
switch((*(card_data + 1) >> (2 * i)) & 0b11) {
case 0b01:
result = (result << 1) | 0;
break;
case 0b10:
result = (result << 1) | 1;
break;
default:
return false;
break;
}
}
// decode from word 2
// coded with 01 = 0, 10 = 1 transitions
for(int8_t i = 15; i >= 0; i--) {
switch((*(card_data + 2) >> (2 * i)) & 0b11) {
case 0b01:
result = (result << 1) | 0;
break;
case 0b10:
result = (result << 1) | 1;
break;
default:
return false;
break;
}
}
// trailing parity (odd) test
uint8_t parity_sum = 0;
for(int8_t i = 0; i < 13; i++) {
if(((result >> i) & 1) == 1) {
parity_sum++;
}
}
if((parity_sum % 2) != 1) {
return false;
}
// leading parity (even) test
parity_sum = 0;
for(int8_t i = 13; i < 26; i++) {
if(((result >> i) & 1) == 1) {
parity_sum++;
}
}
if((parity_sum % 2) == 1) {
return false;
}
return true;
}
static void protocol_h10301_decode(const uint32_t* card_data, uint8_t* decoded_data) {
// data decoding
uint32_t result = 0;
// decode from word 1
// coded with 01 = 0, 10 = 1 transitions
for(int8_t i = 9; i >= 0; i--) {
switch((*(card_data + 1) >> (2 * i)) & 0b11) {
case 0b01:
result = (result << 1) | 0;
break;
case 0b10:
result = (result << 1) | 1;
break;
default:
break;
}
}
// decode from word 2
// coded with 01 = 0, 10 = 1 transitions
for(int8_t i = 15; i >= 0; i--) {
switch((*(card_data + 2) >> (2 * i)) & 0b11) {
case 0b01:
result = (result << 1) | 0;
break;
case 0b10:
result = (result << 1) | 1;
break;
default:
break;
}
}
uint8_t data[H10301_DECODED_DATA_SIZE] = {
(uint8_t)(result >> 17), (uint8_t)(result >> 9), (uint8_t)(result >> 1)};
memcpy(decoded_data, &data, H10301_DECODED_DATA_SIZE);
}
bool protocol_h10301_decoder_feed(ProtocolH10301* protocol, bool level, uint32_t duration) {
bool value;
uint32_t count;
bool result = false;
fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count);
if(count > 0) {
for(size_t i = 0; i < count; i++) {
protocol_h10301_decoder_store_data(protocol, value);
if(protocol_h10301_can_be_decoded(protocol->encoded_data)) {
protocol_h10301_decode(protocol->encoded_data, protocol->data);
result = true;
break;
}
}
}
return result;
};
static void protocol_h10301_write_raw_bit(bool bit, uint8_t position, uint32_t* card_data) {
if(bit) {
card_data[position / H10301_BIT_SIZE] |=
1UL << (H10301_BIT_SIZE - (position % H10301_BIT_SIZE) - 1);
} else {
card_data[position / H10301_BIT_SIZE] &=
~(1UL << (H10301_BIT_SIZE - (position % H10301_BIT_SIZE) - 1));
}
}
static void protocol_h10301_write_bit(bool bit, uint8_t position, uint32_t* card_data) {
protocol_h10301_write_raw_bit(bit, position + 0, card_data);
protocol_h10301_write_raw_bit(!bit, position + 1, card_data);
}
void protocol_h10301_encode(const uint8_t* decoded_data, uint8_t* encoded_data) {
uint32_t card_data[H10301_DECODED_DATA_SIZE] = {0, 0, 0};
uint32_t fc_cn = (decoded_data[0] << 16) | (decoded_data[1] << 8) | decoded_data[2];
// even parity sum calculation (high 12 bits of data)
uint8_t even_parity_sum = 0;
for(int8_t i = 12; i < 24; i++) {
if(((fc_cn >> i) & 1) == 1) {
even_parity_sum++;
}
}
// odd parity sum calculation (low 12 bits of data)
uint8_t odd_parity_sum = 1;
for(int8_t i = 0; i < 12; i++) {
if(((fc_cn >> i) & 1) == 1) {
odd_parity_sum++;
}
}
// 0x1D preamble
protocol_h10301_write_raw_bit(0, 0, card_data);
protocol_h10301_write_raw_bit(0, 1, card_data);
protocol_h10301_write_raw_bit(0, 2, card_data);
protocol_h10301_write_raw_bit(1, 3, card_data);
protocol_h10301_write_raw_bit(1, 4, card_data);
protocol_h10301_write_raw_bit(1, 5, card_data);
protocol_h10301_write_raw_bit(0, 6, card_data);
protocol_h10301_write_raw_bit(1, 7, card_data);
// company / OEM code 1
protocol_h10301_write_bit(0, 8, card_data);
protocol_h10301_write_bit(0, 10, card_data);
protocol_h10301_write_bit(0, 12, card_data);
protocol_h10301_write_bit(0, 14, card_data);
protocol_h10301_write_bit(0, 16, card_data);
protocol_h10301_write_bit(0, 18, card_data);
protocol_h10301_write_bit(1, 20, card_data);
// card format / length 1
protocol_h10301_write_bit(0, 22, card_data);
protocol_h10301_write_bit(0, 24, card_data);
protocol_h10301_write_bit(0, 26, card_data);
protocol_h10301_write_bit(0, 28, card_data);
protocol_h10301_write_bit(0, 30, card_data);
protocol_h10301_write_bit(0, 32, card_data);
protocol_h10301_write_bit(0, 34, card_data);
protocol_h10301_write_bit(0, 36, card_data);
protocol_h10301_write_bit(0, 38, card_data);
protocol_h10301_write_bit(0, 40, card_data);
protocol_h10301_write_bit(1, 42, card_data);
// even parity bit
protocol_h10301_write_bit((even_parity_sum % 2), 44, card_data);
// data
for(uint8_t i = 0; i < 24; i++) {
protocol_h10301_write_bit((fc_cn >> (23 - i)) & 1, 46 + (i * 2), card_data);
}
// odd parity bit
protocol_h10301_write_bit((odd_parity_sum % 2), 94, card_data);
memcpy(encoded_data, &card_data, H10301_ENCODED_DATA_SIZE);
}
bool protocol_h10301_encoder_start(ProtocolH10301* protocol) {
protocol_h10301_encode(protocol->data, (uint8_t*)protocol->encoded_data);
protocol->encoder.encoded_index = 0;
protocol->encoder.pulse = 0;
return true;
};
LevelDuration protocol_h10301_encoder_yield(ProtocolH10301* protocol) {
bool level = 0;
uint32_t duration = 0;
// if pulse is zero, we need to output high, otherwise we need to output low
if(protocol->encoder.pulse == 0) {
// get bit
uint8_t bit =
(protocol->encoded_data[protocol->encoder.encoded_index / H10301_BIT_SIZE] >>
((H10301_BIT_SIZE - 1) - (protocol->encoder.encoded_index % H10301_BIT_SIZE))) &
1;
// get pulse from oscillator
bool advance = fsk_osc_next(protocol->encoder.fsk_osc, bit, &duration);
if(advance) {
protocol->encoder.encoded_index++;
if(protocol->encoder.encoded_index >= (H10301_BIT_MAX_SIZE)) {
protocol->encoder.encoded_index = 0;
}
}
// duration diveded by 2 because we need to output high and low
duration = duration / 2;
protocol->encoder.pulse = duration;
level = true;
} else {
// output low half and reset pulse
duration = protocol->encoder.pulse;
protocol->encoder.pulse = 0;
level = false;
}
return level_duration_make(level, duration);
};
bool protocol_h10301_write_data(ProtocolH10301* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;
protocol_h10301_encoder_start(protocol);
if(request->write_type == LFRFIDWriteTypeT5577) {
request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_50 |
(3 << LFRFID_T5577_MAXBLOCK_SHIFT);
request->t5577.block[1] = protocol->encoded_data[0];
request->t5577.block[2] = protocol->encoded_data[1];
request->t5577.block[3] = protocol->encoded_data[2];
request->t5577.blocks_to_write = 4;
result = true;
}
return result;
};
void protocol_h10301_render_data(ProtocolH10301* protocol, string_t result) {
uint8_t* data = protocol->data;
string_printf(
result,
"FC: %u\r\n"
"Card: %u",
data[0],
(uint16_t)((data[1] << 8) | (data[2])));
};
const ProtocolBase protocol_h10301 = {
.name = "H10301",
.manufacturer = "HID",
.data_size = H10301_DECODED_DATA_SIZE,
.features = LFRFIDFeatureASK,
.validate_count = 3,
.alloc = (ProtocolAlloc)protocol_h10301_alloc,
.free = (ProtocolFree)protocol_h10301_free,
.get_data = (ProtocolGetData)protocol_h10301_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_h10301_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_h10301_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_h10301_encoder_start,
.yield = (ProtocolEncoderYield)protocol_h10301_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_h10301_render_data,
.render_brief_data = (ProtocolRenderData)protocol_h10301_render_data,
.write_data = (ProtocolWriteData)protocol_h10301_write_data,
};

View File

@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>
extern const ProtocolBase protocol_h10301;

View File

@@ -0,0 +1,219 @@
#include <furi.h>
#include <toolbox/protocols/protocol.h>
#include <lfrfid/tools/fsk_demod.h>
#include <lfrfid/tools/fsk_osc.h>
#include "lfrfid_protocols.h"
#include <lfrfid/tools/bit_lib.h>
#define JITTER_TIME (20)
#define MIN_TIME (64 - JITTER_TIME)
#define MAX_TIME (80 + JITTER_TIME)
#define HID_DATA_SIZE 23
#define HID_PREAMBLE_SIZE 1
#define HID_ENCODED_DATA_SIZE (HID_PREAMBLE_SIZE + HID_DATA_SIZE + HID_PREAMBLE_SIZE)
#define HID_ENCODED_BIT_SIZE ((HID_PREAMBLE_SIZE + HID_DATA_SIZE) * 8)
#define HID_DECODED_DATA_SIZE (12)
#define HID_DECODED_BIT_SIZE ((HID_ENCODED_BIT_SIZE - HID_PREAMBLE_SIZE * 8) / 2)
#define HID_PREAMBLE 0x1D
typedef struct {
FSKDemod* fsk_demod;
} ProtocolHIDExDecoder;
typedef struct {
FSKOsc* fsk_osc;
uint8_t encoded_index;
uint32_t pulse;
} ProtocolHIDExEncoder;
typedef struct {
ProtocolHIDExDecoder decoder;
ProtocolHIDExEncoder encoder;
uint8_t encoded_data[HID_ENCODED_DATA_SIZE];
uint8_t data[HID_DECODED_DATA_SIZE];
size_t protocol_size;
} ProtocolHIDEx;
ProtocolHIDEx* protocol_hid_ex_generic_alloc(void) {
ProtocolHIDEx* protocol = malloc(sizeof(ProtocolHIDEx));
protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 6, MAX_TIME, 5);
protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 50);
return protocol;
};
void protocol_hid_ex_generic_free(ProtocolHIDEx* protocol) {
fsk_demod_free(protocol->decoder.fsk_demod);
fsk_osc_free(protocol->encoder.fsk_osc);
free(protocol);
};
uint8_t* protocol_hid_ex_generic_get_data(ProtocolHIDEx* protocol) {
return protocol->data;
};
void protocol_hid_ex_generic_decoder_start(ProtocolHIDEx* protocol) {
memset(protocol->encoded_data, 0, HID_ENCODED_DATA_SIZE);
};
static bool protocol_hid_ex_generic_can_be_decoded(const uint8_t* data) {
// check preamble
if(data[0] != HID_PREAMBLE || data[HID_PREAMBLE_SIZE + HID_DATA_SIZE] != HID_PREAMBLE) {
return false;
}
// check for manchester encoding
for(size_t i = HID_PREAMBLE_SIZE; i < (HID_PREAMBLE_SIZE + HID_DATA_SIZE); i++) {
for(size_t n = 0; n < 4; n++) {
uint8_t bit_pair = (data[i] >> (n * 2)) & 0b11;
if(bit_pair == 0b11 || bit_pair == 0b00) {
return false;
}
}
}
return true;
}
static void protocol_hid_ex_generic_decode(const uint8_t* from, uint8_t* to) {
size_t bit_index = 0;
for(size_t i = HID_PREAMBLE_SIZE; i < (HID_PREAMBLE_SIZE + HID_DATA_SIZE); i++) {
for(size_t n = 0; n < 4; n++) {
uint8_t bit_pair = (from[i] >> (6 - (n * 2))) & 0b11;
if(bit_pair == 0b01) {
bit_lib_set_bit(to, bit_index, 0);
} else if(bit_pair == 0b10) {
bit_lib_set_bit(to, bit_index, 1);
}
bit_index++;
}
}
}
bool protocol_hid_ex_generic_decoder_feed(ProtocolHIDEx* protocol, bool level, uint32_t duration) {
bool value;
uint32_t count;
bool result = false;
fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count);
if(count > 0) {
for(size_t i = 0; i < count; i++) {
bit_lib_push_bit(protocol->encoded_data, HID_ENCODED_DATA_SIZE, value);
if(protocol_hid_ex_generic_can_be_decoded(protocol->encoded_data)) {
protocol_hid_ex_generic_decode(protocol->encoded_data, protocol->data);
result = true;
}
}
}
return result;
};
static void protocol_hid_ex_generic_encode(ProtocolHIDEx* protocol) {
protocol->encoded_data[0] = HID_PREAMBLE;
size_t bit_index = 0;
for(size_t i = 0; i < HID_DECODED_BIT_SIZE; i++) {
bool bit = bit_lib_get_bit(protocol->data, i);
if(bit) {
bit_lib_set_bit(protocol->encoded_data, 8 + bit_index, 1);
bit_lib_set_bit(protocol->encoded_data, 8 + bit_index + 1, 0);
} else {
bit_lib_set_bit(protocol->encoded_data, 8 + bit_index, 0);
bit_lib_set_bit(protocol->encoded_data, 8 + bit_index + 1, 1);
}
bit_index += 2;
}
}
bool protocol_hid_ex_generic_encoder_start(ProtocolHIDEx* protocol) {
protocol->encoder.encoded_index = 0;
protocol->encoder.pulse = 0;
protocol_hid_ex_generic_encode(protocol);
return true;
};
LevelDuration protocol_hid_ex_generic_encoder_yield(ProtocolHIDEx* protocol) {
bool level = 0;
uint32_t duration = 0;
// if pulse is zero, we need to output high, otherwise we need to output low
if(protocol->encoder.pulse == 0) {
// get bit
uint8_t bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoder.encoded_index);
// get pulse from oscillator
bool advance = fsk_osc_next(protocol->encoder.fsk_osc, bit, &duration);
if(advance) {
bit_lib_increment_index(protocol->encoder.encoded_index, HID_ENCODED_BIT_SIZE);
}
// duration diveded by 2 because we need to output high and low
duration = duration / 2;
protocol->encoder.pulse = duration;
level = true;
} else {
// output low half and reset pulse
duration = protocol->encoder.pulse;
protocol->encoder.pulse = 0;
level = false;
}
return level_duration_make(level, duration);
};
bool protocol_hid_ex_generic_write_data(ProtocolHIDEx* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;
protocol_hid_ex_generic_encoder_start(protocol);
if(request->write_type == LFRFIDWriteTypeT5577) {
request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_50 |
(6 << LFRFID_T5577_MAXBLOCK_SHIFT);
request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32);
request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32);
request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32);
request->t5577.block[4] = bit_lib_get_bits_32(protocol->encoded_data, 96, 32);
request->t5577.block[5] = bit_lib_get_bits_32(protocol->encoded_data, 128, 32);
request->t5577.block[6] = bit_lib_get_bits_32(protocol->encoded_data, 160, 32);
request->t5577.blocks_to_write = 7;
result = true;
}
return result;
};
void protocol_hid_ex_generic_render_data(ProtocolHIDEx* protocol, string_t result) {
// TODO: parser and render functions
UNUSED(protocol);
string_printf(result, "Generic HID Extended\r\nData: Unknown");
};
const ProtocolBase protocol_hid_ex_generic = {
.name = "HIDExt",
.manufacturer = "Generic",
.data_size = HID_DECODED_DATA_SIZE,
.features = LFRFIDFeatureASK,
.validate_count = 3,
.alloc = (ProtocolAlloc)protocol_hid_ex_generic_alloc,
.free = (ProtocolFree)protocol_hid_ex_generic_free,
.get_data = (ProtocolGetData)protocol_hid_ex_generic_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_hid_ex_generic_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_hid_ex_generic_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_hid_ex_generic_encoder_start,
.yield = (ProtocolEncoderYield)protocol_hid_ex_generic_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_hid_ex_generic_render_data,
.render_brief_data = (ProtocolRenderData)protocol_hid_ex_generic_render_data,
.write_data = (ProtocolWriteData)protocol_hid_ex_generic_write_data,
};

View File

@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>
extern const ProtocolBase protocol_hid_ex_generic;

View File

@@ -0,0 +1,280 @@
#include <furi.h>
#include <toolbox/protocols/protocol.h>
#include <lfrfid/tools/fsk_demod.h>
#include <lfrfid/tools/fsk_osc.h>
#include "lfrfid_protocols.h"
#include <lfrfid/tools/bit_lib.h>
#define JITTER_TIME (20)
#define MIN_TIME (64 - JITTER_TIME)
#define MAX_TIME (80 + JITTER_TIME)
#define HID_DATA_SIZE 11
#define HID_PREAMBLE_SIZE 1
#define HID_PROTOCOL_SIZE_UNKNOWN 0
#define HID_ENCODED_DATA_SIZE (HID_PREAMBLE_SIZE + HID_DATA_SIZE + HID_PREAMBLE_SIZE)
#define HID_ENCODED_BIT_SIZE ((HID_PREAMBLE_SIZE + HID_DATA_SIZE) * 8)
#define HID_DECODED_DATA_SIZE (6)
#define HID_DECODED_BIT_SIZE ((HID_ENCODED_BIT_SIZE - HID_PREAMBLE_SIZE * 8) / 2)
#define HID_PREAMBLE 0x1D
typedef struct {
FSKDemod* fsk_demod;
} ProtocolHIDDecoder;
typedef struct {
FSKOsc* fsk_osc;
uint8_t encoded_index;
uint32_t pulse;
} ProtocolHIDEncoder;
typedef struct {
ProtocolHIDDecoder decoder;
ProtocolHIDEncoder encoder;
uint8_t encoded_data[HID_ENCODED_DATA_SIZE];
uint8_t data[HID_DECODED_DATA_SIZE];
} ProtocolHID;
ProtocolHID* protocol_hid_generic_alloc(void) {
ProtocolHID* protocol = malloc(sizeof(ProtocolHID));
protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 6, MAX_TIME, 5);
protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 50);
return protocol;
};
void protocol_hid_generic_free(ProtocolHID* protocol) {
fsk_demod_free(protocol->decoder.fsk_demod);
fsk_osc_free(protocol->encoder.fsk_osc);
free(protocol);
};
uint8_t* protocol_hid_generic_get_data(ProtocolHID* protocol) {
return protocol->data;
};
void protocol_hid_generic_decoder_start(ProtocolHID* protocol) {
memset(protocol->encoded_data, 0, HID_ENCODED_DATA_SIZE);
};
static bool protocol_hid_generic_can_be_decoded(const uint8_t* data) {
// check preamble
if(data[0] != HID_PREAMBLE || data[HID_PREAMBLE_SIZE + HID_DATA_SIZE] != HID_PREAMBLE) {
return false;
}
// check for manchester encoding
for(size_t i = HID_PREAMBLE_SIZE; i < (HID_PREAMBLE_SIZE + HID_DATA_SIZE); i++) {
for(size_t n = 0; n < 4; n++) {
uint8_t bit_pair = (data[i] >> (n * 2)) & 0b11;
if(bit_pair == 0b11 || bit_pair == 0b00) {
return false;
}
}
}
return true;
}
static void protocol_hid_generic_decode(const uint8_t* from, uint8_t* to) {
size_t bit_index = 0;
for(size_t i = HID_PREAMBLE_SIZE; i < (HID_PREAMBLE_SIZE + HID_DATA_SIZE); i++) {
for(size_t n = 0; n < 4; n++) {
uint8_t bit_pair = (from[i] >> (6 - (n * 2))) & 0b11;
if(bit_pair == 0b01) {
bit_lib_set_bit(to, bit_index, 0);
} else if(bit_pair == 0b10) {
bit_lib_set_bit(to, bit_index, 1);
}
bit_index++;
}
}
}
/**
* Decodes size from the HID Proximity header:
* - If any of the first six bits is 1, the key is composed of the bits
* following the first 1
* - Otherwise, if the first six bits are 0:
* - If the seventh bit is 0, the key is composed of the remaining 37 bits.
* - If the seventh bit is 1, the size header continues until the next 1 bit,
* and the key is composed of however many bits remain.
*
* HID Proximity keys are 26 bits at minimum. If the header implies a key size
* under 26 bits, this function returns HID_PROTOCOL_SIZE_UNKNOWN.
*/
static uint8_t protocol_hid_generic_decode_protocol_size(ProtocolHID* protocol) {
for(size_t bit_index = 0; bit_index < 6; bit_index++) {
if(bit_lib_get_bit(protocol->data, bit_index)) {
return HID_DECODED_BIT_SIZE - bit_index - 1;
}
}
if(!bit_lib_get_bit(protocol->data, 6)) {
return 37;
}
size_t bit_index = 7;
uint8_t size = 36;
while(!bit_lib_get_bit(protocol->data, bit_index) && size >= 26) {
size--;
bit_index++;
}
return size < 26 ? HID_PROTOCOL_SIZE_UNKNOWN : size;
}
bool protocol_hid_generic_decoder_feed(ProtocolHID* protocol, bool level, uint32_t duration) {
bool value;
uint32_t count;
bool result = false;
fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count);
if(count > 0) {
for(size_t i = 0; i < count; i++) {
bit_lib_push_bit(protocol->encoded_data, HID_ENCODED_DATA_SIZE, value);
if(protocol_hid_generic_can_be_decoded(protocol->encoded_data)) {
protocol_hid_generic_decode(protocol->encoded_data, protocol->data);
result = true;
}
}
}
return result;
};
static void protocol_hid_generic_encode(ProtocolHID* protocol) {
protocol->encoded_data[0] = HID_PREAMBLE;
size_t bit_index = 0;
for(size_t i = 0; i < HID_DECODED_BIT_SIZE; i++) {
bool bit = bit_lib_get_bit(protocol->data, i);
if(bit) {
bit_lib_set_bit(protocol->encoded_data, 8 + bit_index, 1);
bit_lib_set_bit(protocol->encoded_data, 8 + bit_index + 1, 0);
} else {
bit_lib_set_bit(protocol->encoded_data, 8 + bit_index, 0);
bit_lib_set_bit(protocol->encoded_data, 8 + bit_index + 1, 1);
}
bit_index += 2;
}
}
bool protocol_hid_generic_encoder_start(ProtocolHID* protocol) {
protocol->encoder.encoded_index = 0;
protocol->encoder.pulse = 0;
protocol_hid_generic_encode(protocol);
return true;
};
LevelDuration protocol_hid_generic_encoder_yield(ProtocolHID* protocol) {
bool level = 0;
uint32_t duration = 0;
// if pulse is zero, we need to output high, otherwise we need to output low
if(protocol->encoder.pulse == 0) {
// get bit
uint8_t bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoder.encoded_index);
// get pulse from oscillator
bool advance = fsk_osc_next(protocol->encoder.fsk_osc, bit, &duration);
if(advance) {
bit_lib_increment_index(protocol->encoder.encoded_index, HID_ENCODED_BIT_SIZE);
}
// duration diveded by 2 because we need to output high and low
duration = duration / 2;
protocol->encoder.pulse = duration;
level = true;
} else {
// output low half and reset pulse
duration = protocol->encoder.pulse;
protocol->encoder.pulse = 0;
level = false;
}
return level_duration_make(level, duration);
};
bool protocol_hid_generic_write_data(ProtocolHID* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;
protocol_hid_generic_encoder_start(protocol);
if(request->write_type == LFRFIDWriteTypeT5577) {
request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_50 |
(3 << LFRFID_T5577_MAXBLOCK_SHIFT);
request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32);
request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32);
request->t5577.block[3] = bit_lib_get_bits_32(protocol->encoded_data, 64, 32);
request->t5577.blocks_to_write = 4;
result = true;
}
return result;
};
static void protocol_hid_generic_string_cat_protocol_bits(ProtocolHID* protocol, uint8_t protocol_size, string_t result) {
// round up to the nearest nibble
const uint8_t hex_character_count = (protocol_size + 3) / 4;
const uint8_t protocol_bit_index = HID_DECODED_BIT_SIZE - protocol_size;
for(size_t i = 0; i < hex_character_count; i++) {
uint8_t nibble =
i == 0 ? bit_lib_get_bits(
protocol->data, protocol_bit_index, protocol_size % 4 == 0 ? 4 : protocol_size % 4) :
bit_lib_get_bits(protocol->data, protocol_bit_index + i * 4, 4);
string_cat_printf(result, "%X", nibble & 0xF);
}
}
void protocol_hid_generic_render_data(ProtocolHID* protocol, string_t result) {
const uint8_t protocol_size = protocol_hid_generic_decode_protocol_size(protocol);
if(protocol_size == HID_PROTOCOL_SIZE_UNKNOWN) {
string_printf(
result,
"Generic HID Proximity\r\n"
"Data: %02X%02X%02X%02X%02X%X",
protocol->data[0],
protocol->data[1],
protocol->data[2],
protocol->data[3],
protocol->data[4],
protocol->data[5] >> 4);
} else {
string_printf(
result,
"%hhu-bit HID Proximity\r\n"
"Data: ",
protocol_size);
protocol_hid_generic_string_cat_protocol_bits(protocol, protocol_size, result);
}
};
const ProtocolBase protocol_hid_generic = {
.name = "HIDProx",
.manufacturer = "Generic",
.data_size = HID_DECODED_DATA_SIZE,
.features = LFRFIDFeatureASK,
.validate_count = 6,
.alloc = (ProtocolAlloc)protocol_hid_generic_alloc,
.free = (ProtocolFree)protocol_hid_generic_free,
.get_data = (ProtocolGetData)protocol_hid_generic_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_hid_generic_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_hid_generic_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_hid_generic_encoder_start,
.yield = (ProtocolEncoderYield)protocol_hid_generic_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_hid_generic_render_data,
.render_brief_data = (ProtocolRenderData)protocol_hid_generic_render_data,
.write_data = (ProtocolWriteData)protocol_hid_generic_write_data,
};

View File

@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>
extern const ProtocolBase protocol_hid_generic;

View File

@@ -0,0 +1,353 @@
#include <furi.h>
#include <toolbox/protocols/protocol.h>
#include <lfrfid/tools/bit_lib.h>
#include "lfrfid_protocols.h"
#define INDALA26_PREAMBLE_BIT_SIZE (33)
#define INDALA26_PREAMBLE_DATA_SIZE (5)
#define INDALA26_ENCODED_BIT_SIZE (64)
#define INDALA26_ENCODED_DATA_SIZE \
(((INDALA26_ENCODED_BIT_SIZE) / 8) + INDALA26_PREAMBLE_DATA_SIZE)
#define INDALA26_ENCODED_DATA_LAST ((INDALA26_ENCODED_BIT_SIZE) / 8)
#define INDALA26_DECODED_BIT_SIZE (28)
#define INDALA26_DECODED_DATA_SIZE (4)
#define INDALA26_US_PER_BIT (255)
#define INDALA26_ENCODER_PULSES_PER_BIT (16)
typedef struct {
uint8_t data_index;
uint8_t bit_clock_index;
bool last_bit;
bool current_polarity;
bool pulse_phase;
} ProtocolIndalaEncoder;
typedef struct {
uint8_t encoded_data[INDALA26_ENCODED_DATA_SIZE];
uint8_t negative_encoded_data[INDALA26_ENCODED_DATA_SIZE];
uint8_t corrupted_encoded_data[INDALA26_ENCODED_DATA_SIZE];
uint8_t corrupted_negative_encoded_data[INDALA26_ENCODED_DATA_SIZE];
uint8_t data[INDALA26_DECODED_DATA_SIZE];
ProtocolIndalaEncoder encoder;
} ProtocolIndala;
ProtocolIndala* protocol_indala26_alloc(void) {
ProtocolIndala* protocol = malloc(sizeof(ProtocolIndala));
return protocol;
};
void protocol_indala26_free(ProtocolIndala* protocol) {
free(protocol);
};
uint8_t* protocol_indala26_get_data(ProtocolIndala* protocol) {
return protocol->data;
};
void protocol_indala26_decoder_start(ProtocolIndala* protocol) {
memset(protocol->encoded_data, 0, INDALA26_ENCODED_DATA_SIZE);
memset(protocol->negative_encoded_data, 0, INDALA26_ENCODED_DATA_SIZE);
memset(protocol->corrupted_encoded_data, 0, INDALA26_ENCODED_DATA_SIZE);
memset(protocol->corrupted_negative_encoded_data, 0, INDALA26_ENCODED_DATA_SIZE);
};
static bool protocol_indala26_check_preamble(uint8_t* data, size_t bit_index) {
// Preamble 10100000 00000000 00000000 00000000 1
if(*(uint32_t*)&data[bit_index / 8] != 0b00000000000000000000000010100000) return false;
if(bit_lib_get_bit(data, bit_index + 32) != 1) return false;
return true;
}
static bool protocol_indala26_can_be_decoded(uint8_t* data) {
if(!protocol_indala26_check_preamble(data, 0)) return false;
if(!protocol_indala26_check_preamble(data, 64)) return false;
if(bit_lib_get_bit(data, 61) != 0) return false;
if(bit_lib_get_bit(data, 60) != 0) return false;
return true;
}
static bool protocol_indala26_decoder_feed_internal(bool polarity, uint32_t time, uint8_t* data) {
time += (INDALA26_US_PER_BIT / 2);
size_t bit_count = (time / INDALA26_US_PER_BIT);
bool result = false;
if(bit_count < INDALA26_ENCODED_BIT_SIZE) {
for(size_t i = 0; i < bit_count; i++) {
bit_lib_push_bit(data, INDALA26_ENCODED_DATA_SIZE, polarity);
if(protocol_indala26_can_be_decoded(data)) {
result = true;
break;
}
}
}
return result;
}
static void protocol_indala26_decoder_save(uint8_t* data_to, const uint8_t* data_from) {
bit_lib_copy_bits(data_to, 0, 22, data_from, 33);
bit_lib_copy_bits(data_to, 22, 5, data_from, 55);
bit_lib_copy_bits(data_to, 27, 2, data_from, 62);
}
bool protocol_indala26_decoder_feed(ProtocolIndala* protocol, bool level, uint32_t duration) {
bool result = false;
if(duration > (INDALA26_US_PER_BIT / 2)) {
if(protocol_indala26_decoder_feed_internal(level, duration, protocol->encoded_data)) {
protocol_indala26_decoder_save(protocol->data, protocol->encoded_data);
FURI_LOG_D("Indala26", "Positive");
result = true;
return result;
}
if(protocol_indala26_decoder_feed_internal(
!level, duration, protocol->negative_encoded_data)) {
protocol_indala26_decoder_save(protocol->data, protocol->negative_encoded_data);
FURI_LOG_D("Indala26", "Negative");
result = true;
return result;
}
}
if(duration > (INDALA26_US_PER_BIT / 4)) {
// Try to decode wrong phase synced data
if(level) {
duration += 120;
} else {
if(duration > 120) {
duration -= 120;
}
}
if(protocol_indala26_decoder_feed_internal(
level, duration, protocol->corrupted_encoded_data)) {
protocol_indala26_decoder_save(protocol->data, protocol->corrupted_encoded_data);
FURI_LOG_D("Indala26", "Positive Corrupted");
result = true;
return result;
}
if(protocol_indala26_decoder_feed_internal(
!level, duration, protocol->corrupted_negative_encoded_data)) {
protocol_indala26_decoder_save(
protocol->data, protocol->corrupted_negative_encoded_data);
FURI_LOG_D("Indala26", "Negative Corrupted");
result = true;
return result;
}
}
return result;
};
bool protocol_indala26_encoder_start(ProtocolIndala* protocol) {
memset(protocol->encoded_data, 0, INDALA26_ENCODED_DATA_SIZE);
*(uint32_t*)&protocol->encoded_data[0] = 0b00000000000000000000000010100000;
bit_lib_set_bit(protocol->encoded_data, 32, 1);
bit_lib_copy_bits(protocol->encoded_data, 33, 22, protocol->data, 0);
bit_lib_copy_bits(protocol->encoded_data, 55, 5, protocol->data, 22);
bit_lib_copy_bits(protocol->encoded_data, 62, 2, protocol->data, 27);
protocol->encoder.last_bit =
bit_lib_get_bit(protocol->encoded_data, INDALA26_ENCODED_BIT_SIZE - 1);
protocol->encoder.data_index = 0;
protocol->encoder.current_polarity = true;
protocol->encoder.pulse_phase = true;
protocol->encoder.bit_clock_index = 0;
return true;
};
LevelDuration protocol_indala26_encoder_yield(ProtocolIndala* protocol) {
LevelDuration level_duration;
ProtocolIndalaEncoder* encoder = &protocol->encoder;
if(encoder->pulse_phase) {
level_duration = level_duration_make(encoder->current_polarity, 1);
encoder->pulse_phase = false;
} else {
level_duration = level_duration_make(!encoder->current_polarity, 1);
encoder->pulse_phase = true;
encoder->bit_clock_index++;
if(encoder->bit_clock_index >= INDALA26_ENCODER_PULSES_PER_BIT) {
encoder->bit_clock_index = 0;
bool current_bit = bit_lib_get_bit(protocol->encoded_data, encoder->data_index);
if(current_bit != encoder->last_bit) {
encoder->current_polarity = !encoder->current_polarity;
}
encoder->last_bit = current_bit;
bit_lib_increment_index(encoder->data_index, INDALA26_ENCODED_BIT_SIZE);
}
}
return level_duration;
};
// factory code
static uint8_t get_fc(const uint8_t* data) {
uint8_t fc = 0;
fc = fc << 1 | bit_lib_get_bit(data, 24);
fc = fc << 1 | bit_lib_get_bit(data, 16);
fc = fc << 1 | bit_lib_get_bit(data, 11);
fc = fc << 1 | bit_lib_get_bit(data, 14);
fc = fc << 1 | bit_lib_get_bit(data, 15);
fc = fc << 1 | bit_lib_get_bit(data, 20);
fc = fc << 1 | bit_lib_get_bit(data, 6);
fc = fc << 1 | bit_lib_get_bit(data, 25);
return fc;
}
// card number
static uint16_t get_cn(const uint8_t* data) {
uint16_t cn = 0;
cn = cn << 1 | bit_lib_get_bit(data, 9);
cn = cn << 1 | bit_lib_get_bit(data, 12);
cn = cn << 1 | bit_lib_get_bit(data, 10);
cn = cn << 1 | bit_lib_get_bit(data, 7);
cn = cn << 1 | bit_lib_get_bit(data, 19);
cn = cn << 1 | bit_lib_get_bit(data, 3);
cn = cn << 1 | bit_lib_get_bit(data, 2);
cn = cn << 1 | bit_lib_get_bit(data, 18);
cn = cn << 1 | bit_lib_get_bit(data, 13);
cn = cn << 1 | bit_lib_get_bit(data, 0);
cn = cn << 1 | bit_lib_get_bit(data, 4);
cn = cn << 1 | bit_lib_get_bit(data, 21);
cn = cn << 1 | bit_lib_get_bit(data, 23);
cn = cn << 1 | bit_lib_get_bit(data, 26);
cn = cn << 1 | bit_lib_get_bit(data, 17);
cn = cn << 1 | bit_lib_get_bit(data, 8);
return cn;
}
void protocol_indala26_render_data_internal(ProtocolIndala* protocol, string_t result, bool brief) {
bool wiegand_correct = true;
bool checksum_correct = true;
const uint8_t fc = get_fc(protocol->data);
const uint16_t card = get_cn(protocol->data);
const uint32_t fc_and_card = fc << 16 | card;
const uint8_t checksum = bit_lib_get_bit(protocol->data, 27) << 1 |
bit_lib_get_bit(protocol->data, 28);
const bool even_parity = bit_lib_get_bit(protocol->data, 1);
const bool odd_parity = bit_lib_get_bit(protocol->data, 5);
// indala checksum
uint8_t checksum_sum = 0;
checksum_sum += ((fc_and_card >> 14) & 1);
checksum_sum += ((fc_and_card >> 12) & 1);
checksum_sum += ((fc_and_card >> 9) & 1);
checksum_sum += ((fc_and_card >> 8) & 1);
checksum_sum += ((fc_and_card >> 6) & 1);
checksum_sum += ((fc_and_card >> 5) & 1);
checksum_sum += ((fc_and_card >> 2) & 1);
checksum_sum += ((fc_and_card >> 0) & 1);
checksum_sum = checksum_sum & 0b1;
if(checksum_sum == 1 && checksum == 0b01) {
} else if(checksum_sum == 0 && checksum == 0b10) {
} else {
checksum_correct = false;
}
// wiegand parity
uint8_t even_parity_sum = 0;
for(int8_t i = 12; i < 24; i++) {
if(((fc_and_card >> i) & 1) == 1) {
even_parity_sum++;
}
}
if(even_parity_sum % 2 != even_parity) wiegand_correct = false;
uint8_t odd_parity_sum = 1;
for(int8_t i = 0; i < 12; i++) {
if(((fc_and_card >> i) & 1) == 1) {
odd_parity_sum++;
}
}
if(odd_parity_sum % 2 != odd_parity) wiegand_correct = false;
if(brief) {
string_printf(
result,
"FC: %u\r\nCard: %u, Parity:%s%s",
fc,
card,
(checksum_correct ? "+" : "-"),
(wiegand_correct ? "+" : "-"));
} else {
string_printf(
result,
"FC: %u\r\n"
"Card: %u\r\n"
"Checksum: %s\r\n"
"W26 Parity: %s",
fc,
card,
(checksum_correct ? "+" : "-"),
(wiegand_correct ? "+" : "-"));
}
}
void protocol_indala26_render_data(ProtocolIndala* protocol, string_t result) {
protocol_indala26_render_data_internal(protocol, result, false);
}
void protocol_indala26_render_brief_data(ProtocolIndala* protocol, string_t result) {
protocol_indala26_render_data_internal(protocol, result, true);
}
bool protocol_indala26_write_data(ProtocolIndala* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;
protocol_indala26_encoder_start(protocol);
if(request->write_type == LFRFIDWriteTypeT5577) {
request->t5577.block[0] = LFRFID_T5577_BITRATE_RF_32 | LFRFID_T5577_MODULATION_PSK1 |
(2 << LFRFID_T5577_MAXBLOCK_SHIFT);
request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32);
request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32);
request->t5577.blocks_to_write = 3;
result = true;
}
return result;
};
const ProtocolBase protocol_indala26 = {
.name = "Indala26",
.manufacturer = "Motorola",
.data_size = INDALA26_DECODED_DATA_SIZE,
.features = LFRFIDFeaturePSK,
.validate_count = 6,
.alloc = (ProtocolAlloc)protocol_indala26_alloc,
.free = (ProtocolFree)protocol_indala26_free,
.get_data = (ProtocolGetData)protocol_indala26_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_indala26_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_indala26_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_indala26_encoder_start,
.yield = (ProtocolEncoderYield)protocol_indala26_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_indala26_render_data,
.render_brief_data = (ProtocolRenderData)protocol_indala26_render_brief_data,
.write_data = (ProtocolWriteData)protocol_indala26_write_data,
};

View File

@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>
extern const ProtocolBase protocol_indala26;

View File

@@ -0,0 +1,297 @@
#include <furi.h>
#include <toolbox/protocols/protocol.h>
#include <lfrfid/tools/fsk_demod.h>
#include <lfrfid/tools/fsk_osc.h>
#include <lfrfid/tools/bit_lib.h>
#include "lfrfid_protocols.h"
#define JITTER_TIME (20)
#define MIN_TIME (64 - JITTER_TIME)
#define MAX_TIME (80 + JITTER_TIME)
#define IOPROXXSF_DECODED_DATA_SIZE (4)
#define IOPROXXSF_ENCODED_DATA_SIZE (8)
#define IOPROXXSF_BIT_SIZE (8)
#define IOPROXXSF_BIT_MAX_SIZE (IOPROXXSF_BIT_SIZE * IOPROXXSF_ENCODED_DATA_SIZE)
typedef struct {
FSKDemod* fsk_demod;
} ProtocolIOProxXSFDecoder;
typedef struct {
FSKOsc* fsk_osc;
uint8_t encoded_index;
} ProtocolIOProxXSFEncoder;
typedef struct {
ProtocolIOProxXSFEncoder encoder;
ProtocolIOProxXSFDecoder decoder;
uint8_t encoded_data[IOPROXXSF_ENCODED_DATA_SIZE];
uint8_t data[IOPROXXSF_DECODED_DATA_SIZE];
} ProtocolIOProxXSF;
ProtocolIOProxXSF* protocol_io_prox_xsf_alloc(void) {
ProtocolIOProxXSF* protocol = malloc(sizeof(ProtocolIOProxXSF));
protocol->decoder.fsk_demod = fsk_demod_alloc(MIN_TIME, 8, MAX_TIME, 6);
protocol->encoder.fsk_osc = fsk_osc_alloc(8, 10, 64);
return protocol;
};
void protocol_io_prox_xsf_free(ProtocolIOProxXSF* protocol) {
fsk_demod_free(protocol->decoder.fsk_demod);
fsk_osc_free(protocol->encoder.fsk_osc);
free(protocol);
};
uint8_t* protocol_io_prox_xsf_get_data(ProtocolIOProxXSF* protocol) {
return protocol->data;
};
void protocol_io_prox_xsf_decoder_start(ProtocolIOProxXSF* protocol) {
memset(protocol->encoded_data, 0, IOPROXXSF_ENCODED_DATA_SIZE);
};
static uint8_t protocol_io_prox_xsf_compute_checksum(const uint8_t* data) {
// Packet structure:
//
//0 1 2 3 4 5 6 7
//v v v v v v v v
//01234567 8 9ABCDEF0 1 23456789 A BCDEF012 3 456789AB C DEF01234 5 6789ABCD EF
//00000000 0 VVVVVVVV 1 WWWWWWWW 1 XXXXXXXX 1 YYYYYYYY 1 ZZZZZZZZ 1 CHECKSUM 11
//
// algorithm as observed by the proxmark3 folks
// CHECKSUM == 0xFF - (V + W + X + Y + Z)
uint8_t checksum = 0;
for(size_t i = 1; i <= 5; i++) {
checksum += bit_lib_get_bits(data, 9 * i, 8);
}
return 0xFF - checksum;
}
static bool protocol_io_prox_xsf_can_be_decoded(const uint8_t* encoded_data) {
// Packet framing
//
//0 1 2 3 4 5 6 7
//v v v v v v v v
//01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF
//-----------------------------------------------------------------------
//00000000 01______ _1______ __1_____ ___1____ ____1___ _____1XX XXXXXX11
//
// _ = variable data
// 0 = preamble 0
// 1 = framing 1
// X = checksum
// Validate the packet preamble is there...
if(encoded_data[0] != 0b00000000) {
return false;
}
if((encoded_data[1] >> 6) != 0b01) {
return false;
}
// ... check for known ones...
if(bit_lib_bit_is_not_set(encoded_data[2], 6)) {
return false;
}
if(bit_lib_bit_is_not_set(encoded_data[3], 5)) {
return false;
}
if(bit_lib_bit_is_not_set(encoded_data[4], 4)) {
return false;
}
if(bit_lib_bit_is_not_set(encoded_data[5], 3)) {
return false;
}
if(bit_lib_bit_is_not_set(encoded_data[6], 2)) {
return false;
}
if(bit_lib_bit_is_not_set(encoded_data[7], 1)) {
return false;
}
if(bit_lib_bit_is_not_set(encoded_data[7], 0)) {
return false;
}
// ... and validate our checksums.
uint8_t checksum = protocol_io_prox_xsf_compute_checksum(encoded_data);
uint8_t checkval = bit_lib_get_bits(encoded_data, 54, 8);
if(checksum != checkval) {
return false;
}
return true;
}
void protocol_io_prox_xsf_decode(const uint8_t* encoded_data, uint8_t* decoded_data) {
// Packet structure:
// (Note: the second word seems fixed; but this may not be a guarantee;
// it currently has no meaning.)
//
//0 1 2 3 4 5 6 7
//v v v v v v v v
//01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF 01234567 89ABCDEF
//-----------------------------------------------------------------------
//00000000 01111000 01FFFFFF FF1VVVVV VVV1CCCC CCCC1CCC CCCCC1XX XXXXXX11
//
// F = facility code
// V = version
// C = code
// X = checksum
// Facility code
decoded_data[0] = bit_lib_get_bits(encoded_data, 18, 8);
// Version code.
decoded_data[1] = bit_lib_get_bits(encoded_data, 27, 8);
// Code bytes.
decoded_data[2] = bit_lib_get_bits(encoded_data, 36, 8);
decoded_data[3] = bit_lib_get_bits(encoded_data, 45, 8);
}
bool protocol_io_prox_xsf_decoder_feed(ProtocolIOProxXSF* protocol, bool level, uint32_t duration) {
bool result = false;
uint32_t count;
bool value;
fsk_demod_feed(protocol->decoder.fsk_demod, level, duration, &value, &count);
for(size_t i = 0; i < count; i++) {
bit_lib_push_bit(protocol->encoded_data, IOPROXXSF_ENCODED_DATA_SIZE, value);
if(protocol_io_prox_xsf_can_be_decoded(protocol->encoded_data)) {
protocol_io_prox_xsf_decode(protocol->encoded_data, protocol->data);
result = true;
break;
}
}
return result;
};
static void protocol_io_prox_xsf_encode(const uint8_t* decoded_data, uint8_t* encoded_data) {
// Packet to transmit:
//
// 0 10 20 30 40 50 60
// v v v v v v v
// 01234567 8 90123456 7 89012345 6 78901234 5 67890123 4 56789012 3 45678901 23
// -----------------------------------------------------------------------------
// 00000000 0 11110000 1 facility 1 version_ 1 code-one 1 code-two 1 checksum 11
// Preamble.
bit_lib_set_bits(encoded_data, 0, 0b00000000, 8);
bit_lib_set_bit(encoded_data, 8, 0);
bit_lib_set_bits(encoded_data, 9, 0b11110000, 8);
bit_lib_set_bit(encoded_data, 17, 1);
// Facility code.
bit_lib_set_bits(encoded_data, 18, decoded_data[0], 8);
bit_lib_set_bit(encoded_data, 26, 1);
// Version
bit_lib_set_bits(encoded_data, 27, decoded_data[1], 8);
bit_lib_set_bit(encoded_data, 35, 1);
// Code one
bit_lib_set_bits(encoded_data, 36, decoded_data[2], 8);
bit_lib_set_bit(encoded_data, 44, 1);
// Code two
bit_lib_set_bits(encoded_data, 45, decoded_data[3], 8);
bit_lib_set_bit(encoded_data, 53, 1);
// Checksum
bit_lib_set_bits(encoded_data, 54, protocol_io_prox_xsf_compute_checksum(encoded_data), 8);
bit_lib_set_bit(encoded_data, 62, 1);
bit_lib_set_bit(encoded_data, 63, 1);
}
bool protocol_io_prox_xsf_encoder_start(ProtocolIOProxXSF* protocol) {
protocol_io_prox_xsf_encode(protocol->data, protocol->encoded_data);
protocol->encoder.encoded_index = 0;
fsk_osc_reset(protocol->encoder.fsk_osc);
return true;
};
LevelDuration protocol_io_prox_xsf_encoder_yield(ProtocolIOProxXSF* protocol) {
bool level;
uint32_t duration;
bool bit = bit_lib_get_bit(protocol->encoded_data, protocol->encoder.encoded_index);
bool advance = fsk_osc_next_half(protocol->encoder.fsk_osc, bit, &level, &duration);
if(advance) {
bit_lib_increment_index(protocol->encoder.encoded_index, IOPROXXSF_BIT_MAX_SIZE);
}
return level_duration_make(level, duration);
};
void protocol_io_prox_xsf_render_data(ProtocolIOProxXSF* protocol, string_t result) {
uint8_t* data = protocol->data;
string_printf(
result,
"FC: %u\r\n"
"VС: %u\r\n"
"Card: %u",
data[0],
data[1],
(uint16_t)((data[2] << 8) | (data[3])));
}
void protocol_io_prox_xsf_render_brief_data(ProtocolIOProxXSF* protocol, string_t result) {
uint8_t* data = protocol->data;
string_printf(
result,
"FC: %u, VС: %u\r\n"
"Card: %u",
data[0],
data[1],
(uint16_t)((data[2] << 8) | (data[3])));
}
bool protocol_io_prox_xsf_write_data(ProtocolIOProxXSF* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;
protocol_io_prox_xsf_encode(protocol->data, protocol->encoded_data);
if(request->write_type == LFRFIDWriteTypeT5577) {
request->t5577.block[0] = LFRFID_T5577_MODULATION_FSK2a | LFRFID_T5577_BITRATE_RF_64 |
(2 << LFRFID_T5577_MAXBLOCK_SHIFT);
request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32);
request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32);
request->t5577.blocks_to_write = 3;
result = true;
}
return result;
};
const ProtocolBase protocol_io_prox_xsf = {
.name = "IoProxXSF",
.manufacturer = "Kantech",
.data_size = IOPROXXSF_DECODED_DATA_SIZE,
.features = LFRFIDFeatureASK,
.validate_count = 3,
.alloc = (ProtocolAlloc)protocol_io_prox_xsf_alloc,
.free = (ProtocolFree)protocol_io_prox_xsf_free,
.get_data = (ProtocolGetData)protocol_io_prox_xsf_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_io_prox_xsf_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_io_prox_xsf_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_io_prox_xsf_encoder_start,
.yield = (ProtocolEncoderYield)protocol_io_prox_xsf_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_io_prox_xsf_render_data,
.render_brief_data = (ProtocolRenderData)protocol_io_prox_xsf_render_brief_data,
.write_data = (ProtocolWriteData)protocol_io_prox_xsf_write_data,
};

View File

@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>
extern const ProtocolBase protocol_io_prox_xsf;