Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Paradox tags #1655

Merged
merged 6 commits into from
Aug 29, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/lfrfid/protocols/lfrfid_protocols.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "protocol_fdx_b.h"
#include "protocol_hid_generic.h"
#include "protocol_hid_ex_generic.h"
#include "protocol_paradox.h"

const ProtocolBase* lfrfid_protocols[] = {
[LFRFIDProtocolEM4100] = &protocol_em4100,
Expand All @@ -19,4 +20,5 @@ const ProtocolBase* lfrfid_protocols[] = {
[LFRFIDProtocolFDXB] = &protocol_fdx_b,
[LFRFIDProtocolHidGeneric] = &protocol_hid_generic,
[LFRFIDProtocolHidExGeneric] = &protocol_hid_ex_generic,
[LFRFIDProtocolParadox] = &protocol_paradox,
};
1 change: 1 addition & 0 deletions lib/lfrfid/protocols/lfrfid_protocols.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ typedef enum {
LFRFIDProtocolFDXB,
LFRFIDProtocolHidGeneric,
LFRFIDProtocolHidExGeneric,
LFRFIDProtocolParadox,

LFRFIDProtocolMax,
} LFRFIDProtocol;
Expand Down
211 changes: 211 additions & 0 deletions lib/lfrfid/protocols/protocol_paradox.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
#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 PARADOX_DECODED_DATA_SIZE (6)

#define PARADOX_PREAMBLE_LENGTH (8)
#define PARADOX_ENCODED_BIT_SIZE (96)
#define PARADOX_ENCODED_DATA_SIZE (((PARADOX_ENCODED_BIT_SIZE) / 8) + 1)
#define PARADOX_ENCODED_DATA_LAST (PARADOX_ENCODED_DATA_SIZE - 1)

typedef struct {
FSKDemod* fsk_demod;
} ProtocolParadoxDecoder;

typedef struct {
FSKOsc* fsk_osc;
uint8_t encoded_index;
} ProtocolParadoxEncoder;

typedef struct {
ProtocolParadoxDecoder decoder;
ProtocolParadoxEncoder encoder;
uint8_t encoded_data[PARADOX_ENCODED_DATA_SIZE];
uint8_t data[PARADOX_DECODED_DATA_SIZE];
} ProtocolParadox;

ProtocolParadox* protocol_paradox_alloc(void) {
ProtocolParadox* protocol = malloc(sizeof(ProtocolParadox));
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_paradox_free(ProtocolParadox* protocol) {
fsk_demod_free(protocol->decoder.fsk_demod);
fsk_osc_free(protocol->encoder.fsk_osc);
free(protocol);
};

uint8_t* protocol_paradox_get_data(ProtocolParadox* protocol) {
return protocol->data;
};

void protocol_paradox_decoder_start(ProtocolParadox* protocol) {
memset(protocol->encoded_data, 0, PARADOX_ENCODED_DATA_SIZE);
};

static bool protocol_paradox_can_be_decoded(ProtocolParadox* protocol) {
bool result = false;

do {
// check preamble
if(protocol->encoded_data[0] != 0b00001111 ||
protocol->encoded_data[PARADOX_ENCODED_DATA_LAST] != 0b00001111)
break;

for(uint32_t i = PARADOX_PREAMBLE_LENGTH; i < 96; i += 2) {
if(bit_lib_get_bit(protocol->encoded_data, i) ==
bit_lib_get_bit(protocol->encoded_data, i + 1)) {
return false;
}
}

result = true;
} while(false);

return result;
}

static void protocol_paradox_decode(uint8_t* encoded_data, uint8_t* decoded_data) {
for(uint32_t i = PARADOX_PREAMBLE_LENGTH; i < 96; i += 2) {
if(bit_lib_get_bits(encoded_data, i, 2) == 0b01) {
bit_lib_push_bit(decoded_data, PARADOX_DECODED_DATA_SIZE, 0);
} else if(bit_lib_get_bits(encoded_data, i, 2) == 0b10) {
bit_lib_push_bit(decoded_data, PARADOX_DECODED_DATA_SIZE, 1);
}
}
bit_lib_push_bit(decoded_data, PARADOX_DECODED_DATA_SIZE, 0);
bit_lib_push_bit(decoded_data, PARADOX_DECODED_DATA_SIZE, 0);
bit_lib_push_bit(decoded_data, PARADOX_DECODED_DATA_SIZE, 0);
bit_lib_push_bit(decoded_data, PARADOX_DECODED_DATA_SIZE, 0);
}

bool protocol_paradox_decoder_feed(ProtocolParadox* 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, PARADOX_ENCODED_DATA_SIZE, value);
if(protocol_paradox_can_be_decoded(protocol)) {
protocol_paradox_decode(protocol->encoded_data, protocol->data);

result = true;
break;
}
}
}

return result;
};

static void protocol_paradox_encode(const uint8_t* decoded_data, uint8_t* encoded_data) {
memset(encoded_data, 0, PARADOX_ENCODED_DATA_SIZE);

// preamble
bit_lib_set_bits(encoded_data, 0, 0b00001111, 8);

for(size_t i = 0; i < 44; i++) {
if(bit_lib_get_bit(decoded_data, i)) {
bit_lib_set_bits(encoded_data, PARADOX_PREAMBLE_LENGTH + i * 2, 0b10, 2);
} else {
bit_lib_set_bits(encoded_data, PARADOX_PREAMBLE_LENGTH + i * 2, 0b01, 2);
}
}
};

bool protocol_paradox_encoder_start(ProtocolParadox* protocol) {
protocol_paradox_encode(protocol->data, (uint8_t*)protocol->encoded_data);
protocol->encoder.encoded_index = 0;
fsk_osc_reset(protocol->encoder.fsk_osc);
return true;
};

LevelDuration protocol_paradox_encoder_yield(ProtocolParadox* 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, PARADOX_ENCODED_BIT_SIZE);
}
return level_duration_make(level, duration);
};

void protocol_paradox_render_data(ProtocolParadox* protocol, string_t result) {
uint8_t* decoded_data = protocol->data;
uint8_t fc = bit_lib_get_bits(decoded_data, 10, 8);
uint16_t card_id = bit_lib_get_bits_16(decoded_data, 18, 16);

string_cat_printf(result, "Facility: %u\r\n", fc);
string_cat_printf(result, "Card: %lu\r\n", card_id);
string_cat_printf(result, "Data: ");
for(size_t i = 0; i < PARADOX_DECODED_DATA_SIZE; i++) {
string_cat_printf(result, "%02X", decoded_data[i]);
}
};

void protocol_paradox_render_brief_data(ProtocolParadox* protocol, string_t result) {
uint8_t* decoded_data = protocol->data;

uint8_t fc = bit_lib_get_bits(decoded_data, 10, 8);
uint16_t card_id = bit_lib_get_bits_16(decoded_data, 18, 16);

string_cat_printf(result, "ID: %03u,%05u", fc, card_id);
};

bool protocol_paradox_write_data(ProtocolParadox* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;

protocol_paradox_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_paradox = {
.name = "Paradox",
.manufacturer = "Paradox",
.data_size = PARADOX_DECODED_DATA_SIZE,
.features = LFRFIDFeatureASK,
.validate_count = 3,
.alloc = (ProtocolAlloc)protocol_paradox_alloc,
.free = (ProtocolFree)protocol_paradox_free,
.get_data = (ProtocolGetData)protocol_paradox_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_paradox_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_paradox_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_paradox_encoder_start,
.yield = (ProtocolEncoderYield)protocol_paradox_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_paradox_render_data,
.render_brief_data = (ProtocolRenderData)protocol_paradox_render_brief_data,
.write_data = (ProtocolWriteData)protocol_paradox_write_data,
};
4 changes: 4 additions & 0 deletions lib/lfrfid/protocols/protocol_paradox.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>

extern const ProtocolBase protocol_paradox;