[FL-1059] T5577 write (#463)

* Api-hal-gpio: extend init functions
* App Lfrfid: separate protocol layer
* App Lfrfid: write EM key scene
* App Lfrfid: syntax fix
This commit is contained in:
SG
2021-05-18 18:37:47 +10:00
committed by GitHub
parent 588480831a
commit 618ddfcd04
28 changed files with 956 additions and 420 deletions

View File

@@ -20,84 +20,13 @@ void DecoderEMMarine::reset_state() {
manchester_saved_state, ManchesterEventReset, &manchester_saved_state, nullptr);
}
void printEM_raw(uint64_t data) {
// header
for(uint8_t i = 0; i < 9; i++) {
printf("%u ", data & (1LLU << 63) ? 1 : 0);
data = data << 1;
}
printf("\r\n");
// nibbles
for(uint8_t r = 0; r < 11; r++) {
printf(" ");
uint8_t value = 0;
for(uint8_t i = 0; i < 5; i++) {
printf("%u ", data & (1LLU << 63) ? 1 : 0);
if(i < 4) value = (value << 1) | (data & (1LLU << 63) ? 1 : 0);
data = data << 1;
}
printf("0x%X", value);
printf("\r\n");
}
}
void printEM_data(uint64_t data) {
printf("EM ");
// header
for(uint8_t i = 0; i < 9; i++) {
data = data << 1;
}
// nibbles
for(uint8_t r = 0; r < EM_ROW_COUNT; r++) {
uint8_t value = 0;
for(uint8_t i = 0; i < 5; i++) {
if(i < 4) value = (value << 1) | (data & (1LLU << 63) ? 1 : 0);
data = data << 1;
}
printf("%X", value);
if(r % 2) printf(" ");
}
printf("\r\n");
}
void copyEM_data(uint64_t data, uint8_t* result, uint8_t result_size) {
furi_assert(result_size >= 5);
uint8_t result_index = 0;
// clean result
memset(result, 0, result_size);
// header
for(uint8_t i = 0; i < 9; i++) {
data = data << 1;
}
// nibbles
uint8_t value = 0;
for(uint8_t r = 0; r < EM_ROW_COUNT; r++) {
uint8_t nibble = 0;
for(uint8_t i = 0; i < 5; i++) {
if(i < 4) nibble = (nibble << 1) | (data & (1LLU << 63) ? 1 : 0);
data = data << 1;
}
value = (value << 4) | nibble;
if(r % 2) {
result[result_index] |= value;
result_index++;
value = 0;
}
}
}
bool DecoderEMMarine::read(uint8_t* data, uint8_t data_size) {
bool result = false;
if(ready) {
result = true;
copyEM_data(readed_data, data, data_size);
em_marine.decode(
reinterpret_cast<const uint8_t*>(&readed_data), sizeof(uint64_t), data, data_size);
ready = false;
}
@@ -132,37 +61,8 @@ void DecoderEMMarine::process_front(bool polarity, uint32_t time) {
if(data_ok) {
readed_data = (readed_data << 1) | data;
// header and stop bit
if((readed_data & EM_HEADER_AND_STOP_MASK) != EM_HEADER_AND_STOP_DATA) return;
// row parity
for(uint8_t i = 0; i < EM_ROW_COUNT; i++) {
uint8_t parity_sum = 0;
for(uint8_t j = 0; j < 5; j++) {
parity_sum += (readed_data >> (EM_FIRST_ROW_POS - i * 5 + j)) & 1;
}
if((parity_sum % 2)) {
return;
}
}
// columns parity
for(uint8_t i = 0; i < 4; i++) {
uint8_t parity_sum = 0;
for(uint8_t j = 0; j < EM_ROW_COUNT + 1; j++) {
parity_sum += (readed_data >> (EM_COLUMN_POS - i + j * 5)) & 1;
}
if((parity_sum % 2)) {
return;
}
}
// checks ok
ready = true;
ready = em_marine.can_be_decoded(
reinterpret_cast<const uint8_t*>(&readed_data), sizeof(uint64_t));
}
}
}

View File

@@ -2,7 +2,7 @@
#include <stdint.h>
#include <atomic>
#include "manchester-decoder.h"
#include "protocols/protocol-emmarin.h"
class DecoderEMMarine {
public:
bool read(uint8_t* data, uint8_t data_size);
@@ -17,4 +17,5 @@ private:
std::atomic<bool> ready;
ManchesterState manchester_saved_state;
ProtocolEMMarin em_marine;
};

View File

@@ -17,11 +17,8 @@ bool DecoderHID26::read(uint8_t* data, uint8_t data_size) {
if(ready) {
result = true;
data[0] = facility;
data[1] = (uint8_t)(number >> 8);
data[2] = (uint8_t)number;
//printf("HID %02X %02X %02X\r\n", facility, (uint8_t)(number >> 8), (uint8_t)number);
hid.decode(
reinterpret_cast<const uint8_t*>(&stored_data), sizeof(uint32_t) * 3, data, data_size);
ready = false;
}
@@ -87,94 +84,10 @@ void DecoderHID26::store_data(bool data) {
stored_data[0] = (stored_data[0] << 1) | ((stored_data[1] >> 31) & 1);
stored_data[1] = (stored_data[1] << 1) | ((stored_data[2] >> 31) & 1);
stored_data[2] = (stored_data[2] << 1) | data;
validate_stored_data();
}
void DecoderHID26::validate_stored_data() {
// packet preamble
// raw data
if(*(reinterpret_cast<uint8_t*>(stored_data) + 3) != 0x1D) {
return;
if(hid.can_be_decoded(reinterpret_cast<const uint8_t*>(&stored_data), sizeof(uint32_t) * 3)) {
ready = true;
}
// encoded company/oem
// coded with 01 = 0, 10 = 1 transitions
// stored in word 0
if((*stored_data >> 10 & 0x3FFF) != 0x1556) {
return;
}
// encoded format/length
// coded with 01 = 0, 10 = 1 transitions
// stored in word 0 and word 1
if((((*stored_data & 0x3FF) << 12) | ((*(stored_data + 1) >> 20) & 0xFFF)) != 0x155556) {
return;
}
// data decoding
uint32_t result = 0;
// decode from word 1
// coded with 01 = 0, 10 = 1 transitions
for(int8_t i = 9; i >= 0; i--) {
switch((*(stored_data + 1) >> (2 * i)) & 0b11) {
case 0b01:
result = (result << 1) | 0;
break;
case 0b10:
result = (result << 1) | 1;
break;
default:
return;
break;
}
}
// decode from word 2
// coded with 01 = 0, 10 = 1 transitions
for(int8_t i = 15; i >= 0; i--) {
switch((*(stored_data + 2) >> (2 * i)) & 0b11) {
case 0b01:
result = (result << 1) | 0;
break;
case 0b10:
result = (result << 1) | 1;
break;
default:
return;
break;
}
}
// store decoded data
facility = result >> 17;
number = result >> 1;
// trailing parity (odd) test
uint8_t parity_sum = 0;
for(int8_t i = 0; i < 13; i++) {
if(((result >> i) & 1) == 1) {
parity_sum++;
}
}
if((parity_sum % 2) != 1) {
return;
}
// leading parity (even) test
parity_sum = 0;
for(int8_t i = 13; i < 26; i++) {
if(((result >> i) & 1) == 1) {
parity_sum++;
}
}
if((parity_sum % 2) == 1) {
return;
}
ready = true;
}
void DecoderHID26::reset_state() {

View File

@@ -1,6 +1,7 @@
#pragma once
#include <stdint.h>
#include <atomic>
#include "protocols/protocol-hid-h10301.h"
class DecoderHID26 {
public:
@@ -15,12 +16,9 @@ private:
uint32_t stored_data[3] = {0, 0, 0};
void store_data(bool data);
void validate_stored_data();
uint8_t facility = 0;
uint16_t number = 0;
std::atomic<bool> ready;
void reset_state();
ProtocolHID10301 hid;
};

View File

@@ -1,48 +1,14 @@
#include "encoder-emmarine.h"
#include "protocols/protocol-emmarin.h"
#include <furi.h>
void EncoderEM::init(const uint8_t* data, const uint8_t data_size) {
furi_check(data_size == 5);
ProtocolEMMarin em_marin;
em_marin.encode(data, data_size, reinterpret_cast<uint8_t*>(&card_data), sizeof(uint64_t));
// header
card_data = 0b111111111;
// data
for(uint8_t i = 0; i < 5; i++) {
write_nibble(false, data[i]);
write_nibble(true, data[i]);
}
// column parity and stop bit
uint8_t parity_sum;
for(uint8_t c = 0; c < 4; c++) {
parity_sum = 0;
for(uint8_t i = 1; i <= 10; i++) {
uint8_t parity_bit = (card_data >> (i * 5 - 1)) & 1;
parity_sum += parity_bit;
}
card_data = (card_data << 1) | ((parity_sum % 2) & 1);
}
// stop bit
card_data = (card_data << 1) | 0;
card_data_index = 0;
}
void EncoderEM::write_nibble(bool low_nibble, uint8_t data) {
uint8_t parity_sum = 0;
uint8_t start = 0;
if(!low_nibble) start = 4;
for(int8_t i = (start + 3); i >= start; i--) {
parity_sum += (data >> i) & 1;
card_data = (card_data << 1) | ((data >> i) & 1);
}
card_data = (card_data << 1) | ((parity_sum % 2) & 1);
}
// data transmitted as manchester encoding
// 0 - high2low
// 1 - low2high

View File

@@ -19,5 +19,4 @@ private:
uint64_t card_data;
uint8_t card_data_index;
void write_nibble(bool low_nibble, uint8_t data);
};

View File

@@ -1,73 +1,10 @@
#include "encoder-hid-h10301.h"
#include "protocols/protocol-hid-h10301.h"
#include <furi.h>
void EncoderHID_H10301::init(const uint8_t* data, const uint8_t data_size) {
furi_check(data_size == 3);
card_data[0] = 0;
card_data[1] = 0;
card_data[2] = 0;
uint32_t fc_cn = (data[0] << 16) | (data[1] << 8) | 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
write_raw_bit(0, 0);
write_raw_bit(0, 1);
write_raw_bit(0, 2);
write_raw_bit(1, 3);
write_raw_bit(1, 4);
write_raw_bit(1, 5);
write_raw_bit(0, 6);
write_raw_bit(1, 7);
// company / OEM code 1
write_bit(0, 8);
write_bit(0, 10);
write_bit(0, 12);
write_bit(0, 14);
write_bit(0, 16);
write_bit(0, 18);
write_bit(1, 20);
// card format / length 1
write_bit(0, 22);
write_bit(0, 24);
write_bit(0, 26);
write_bit(0, 28);
write_bit(0, 30);
write_bit(0, 32);
write_bit(0, 34);
write_bit(0, 36);
write_bit(0, 38);
write_bit(0, 40);
write_bit(1, 42);
// even parity bit
write_bit((even_parity_sum % 2), 44);
// data
for(uint8_t i = 0; i < 24; i++) {
write_bit((fc_cn >> (23 - i)) & 1, 46 + (i * 2));
}
// odd parity bit
write_bit((odd_parity_sum % 2), 94);
ProtocolHID10301 hid;
hid.encode(data, data_size, reinterpret_cast<uint8_t*>(&card_data), sizeof(card_data) * 3);
card_data_index = 0;
bit_index = 0;

View File

@@ -1,102 +1,16 @@
#include "encoder-indala-40134.h"
#include "protocols/protocol-indala-40134.h"
#include <furi.h>
void EncoderIndala_40134::init(const uint8_t* data, const uint8_t data_size) {
furi_check(data_size == 3);
uint32_t fc_and_card = (data[0] << 16) | (data[1] << 8) | data[2];
card_data = 0;
// preamble
set_bit(1, 0);
set_bit(1, 2);
set_bit(1, 32);
// factory code
set_bit(((fc_and_card >> 23) & 1), 57);
set_bit(((fc_and_card >> 22) & 1), 49);
set_bit(((fc_and_card >> 21) & 1), 44);
set_bit(((fc_and_card >> 20) & 1), 47);
set_bit(((fc_and_card >> 19) & 1), 48);
set_bit(((fc_and_card >> 18) & 1), 53);
set_bit(((fc_and_card >> 17) & 1), 39);
set_bit(((fc_and_card >> 16) & 1), 58);
// card number
set_bit(((fc_and_card >> 15) & 1), 42);
set_bit(((fc_and_card >> 14) & 1), 45);
set_bit(((fc_and_card >> 13) & 1), 43);
set_bit(((fc_and_card >> 12) & 1), 40);
set_bit(((fc_and_card >> 11) & 1), 52);
set_bit(((fc_and_card >> 10) & 1), 36);
set_bit(((fc_and_card >> 9) & 1), 35);
set_bit(((fc_and_card >> 8) & 1), 51);
set_bit(((fc_and_card >> 7) & 1), 46);
set_bit(((fc_and_card >> 6) & 1), 33);
set_bit(((fc_and_card >> 5) & 1), 37);
set_bit(((fc_and_card >> 4) & 1), 54);
set_bit(((fc_and_card >> 3) & 1), 56);
set_bit(((fc_and_card >> 2) & 1), 59);
set_bit(((fc_and_card >> 1) & 1), 50);
set_bit(((fc_and_card >> 0) & 1), 41);
// checksum
uint8_t checksum = 0;
checksum += ((fc_and_card >> 14) & 1);
checksum += ((fc_and_card >> 12) & 1);
checksum += ((fc_and_card >> 9) & 1);
checksum += ((fc_and_card >> 8) & 1);
checksum += ((fc_and_card >> 6) & 1);
checksum += ((fc_and_card >> 5) & 1);
checksum += ((fc_and_card >> 2) & 1);
checksum += ((fc_and_card >> 0) & 1);
// wiegand parity bits
// 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_and_card >> 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_and_card >> i) & 1) == 1) {
odd_parity_sum++;
}
}
// even parity bit
set_bit((even_parity_sum % 2), 34);
// odd parity bit
set_bit((odd_parity_sum % 2), 38);
// checksum
if((checksum & 1) == 1) {
set_bit(0, 62);
set_bit(1, 63);
} else {
set_bit(1, 62);
set_bit(0, 63);
}
ProtocolIndala40134 indala;
indala.encode(data, data_size, reinterpret_cast<uint8_t*>(&card_data), sizeof(card_data));
last_bit = card_data & 1;
card_data_index = 0;
current_polarity = true;
}
void EncoderIndala_40134::set_bit(bool bit, uint8_t position) {
position = 63 - position;
if(bit) {
card_data |= 1ull << position;
} else {
card_data &= ~(1ull << position);
}
}
void EncoderIndala_40134::get_next(bool* polarity, uint16_t* period, uint16_t* pulse) {
*period = 2;
*pulse = 1;

View File

@@ -20,6 +20,4 @@ private:
bool last_bit;
bool current_polarity;
static const uint8_t clock_per_bit = 16;
void set_bit(bool bit, uint8_t position);
};

View File

@@ -6,4 +6,5 @@ static const uint8_t LFRFID_KEY_SIZE = 8;
enum class LfrfidKeyType : uint8_t {
KeyEmarine,
KeyHID,
KeyIndala,
};

View File

@@ -0,0 +1,150 @@
#include "protocol-emmarin.h"
#include <furi.h>
#define EM_HEADER_POS 55
#define EM_HEADER_MASK (0x1FFLLU << EM_HEADER_POS)
#define EM_FIRST_ROW_POS 50
#define EM_ROW_COUNT 10
#define EM_COLUMN_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)
typedef uint64_t EMMarinCardData;
void write_nibble(bool low_nibble, uint8_t data, EMMarinCardData* card_data) {
uint8_t parity_sum = 0;
uint8_t start = 0;
if(!low_nibble) start = 4;
for(int8_t i = (start + 3); i >= start; i--) {
parity_sum += (data >> i) & 1;
*card_data = (*card_data << 1) | ((data >> i) & 1);
}
*card_data = (*card_data << 1) | ((parity_sum % 2) & 1);
}
uint8_t ProtocolEMMarin::get_encoded_data_size() {
return sizeof(EMMarinCardData);
}
uint8_t ProtocolEMMarin::get_decoded_data_size() {
return 5;
}
void ProtocolEMMarin::encode(
const uint8_t* decoded_data,
const uint8_t decoded_data_size,
uint8_t* encoded_data,
const uint8_t encoded_data_size) {
furi_check(decoded_data_size >= get_decoded_data_size());
furi_check(encoded_data_size >= get_encoded_data_size());
EMMarinCardData card_data;
// header
card_data = 0b111111111;
// data
for(uint8_t i = 0; i < get_decoded_data_size(); i++) {
write_nibble(false, decoded_data[i], &card_data);
write_nibble(true, decoded_data[i], &card_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 = (card_data >> (i * EM_BITS_PER_ROW_COUNT - 1)) & 1;
parity_sum += parity_bit;
}
card_data = (card_data << 1) | ((parity_sum % 2) & 1);
}
// stop bit
card_data = (card_data << 1) | 0;
memcpy(encoded_data, &card_data, get_encoded_data_size());
}
void ProtocolEMMarin::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 >= get_decoded_data_size());
furi_check(encoded_data_size >= get_encoded_data_size());
uint8_t decoded_data_index = 0;
EMMarinCardData card_data = *(reinterpret_cast<const EMMarinCardData*>(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;
}
}
}
bool ProtocolEMMarin::can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) {
furi_check(encoded_data_size >= get_encoded_data_size());
const EMMarinCardData* card_data = reinterpret_cast<const EMMarinCardData*>(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;
}

View File

@@ -0,0 +1,22 @@
#pragma once
#include "protocol-generic.h"
class ProtocolEMMarin : public ProtocolGeneric {
public:
uint8_t get_encoded_data_size() final;
uint8_t get_decoded_data_size() final;
void encode(
const uint8_t* decoded_data,
const uint8_t decoded_data_size,
uint8_t* encoded_data,
const uint8_t encoded_data_size) final;
void decode(
const uint8_t* encoded_data,
const uint8_t encoded_data_size,
uint8_t* decoded_data,
const uint8_t decoded_data_size) final;
bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) final;
};

View File

@@ -0,0 +1,60 @@
#pragma once
#include "stdint.h"
#include "stdbool.h"
class ProtocolGeneric {
public:
/**
* @brief Get the encoded data size
*
* @return uint8_t size of encoded data in bytes
*/
virtual uint8_t get_encoded_data_size() = 0;
/**
* @brief Get the decoded data size
*
* @return uint8_t size of decoded data in bytes
*/
virtual uint8_t get_decoded_data_size() = 0;
/**
* @brief encode decoded data
*
* @param decoded_data
* @param decoded_data_size
* @param encoded_data
* @param encoded_data_size
*/
virtual void encode(
const uint8_t* decoded_data,
const uint8_t decoded_data_size,
uint8_t* encoded_data,
const uint8_t encoded_data_size) = 0;
/**
* @brief decode encoded data
*
* @param encoded_data
* @param encoded_data_size
* @param decoded_data
* @param decoded_data_size
*/
virtual void decode(
const uint8_t* encoded_data,
const uint8_t encoded_data_size,
uint8_t* decoded_data,
const uint8_t decoded_data_size) = 0;
/**
* @brief fast check that data can be correctly decoded
*
* @param encoded_data
* @param encoded_data_size
* @return true - can be correctly decoded
* @return false - cannot be correctly decoded
*/
virtual bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) = 0;
virtual ~ProtocolGeneric(){};
};

View File

@@ -0,0 +1,238 @@
#include "protocol-hid-h10301.h"
#include <furi.h>
typedef uint32_t HID10301CardData;
constexpr uint8_t HID10301Count = 3;
constexpr uint8_t HID10301BitSize = sizeof(HID10301CardData) * 8;
static void write_raw_bit(bool bit, uint8_t position, HID10301CardData* card_data) {
if(bit) {
card_data[position / HID10301BitSize] |=
1UL << (HID10301BitSize - (position % HID10301BitSize) - 1);
} else {
card_data[position / (sizeof(HID10301CardData) * 8)] &=
~(1UL << (HID10301BitSize - (position % HID10301BitSize) - 1));
}
}
static void write_bit(bool bit, uint8_t position, HID10301CardData* card_data) {
write_raw_bit(bit, position + 0, card_data);
write_raw_bit(!bit, position + 1, card_data);
}
uint8_t ProtocolHID10301::get_encoded_data_size() {
return sizeof(HID10301CardData) * HID10301Count;
}
uint8_t ProtocolHID10301::get_decoded_data_size() {
return 3;
}
void ProtocolHID10301::encode(
const uint8_t* decoded_data,
const uint8_t decoded_data_size,
uint8_t* encoded_data,
const uint8_t encoded_data_size) {
furi_check(decoded_data_size >= get_decoded_data_size());
furi_check(encoded_data_size >= get_encoded_data_size());
HID10301CardData card_data[HID10301Count] = {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
write_raw_bit(0, 0, card_data);
write_raw_bit(0, 1, card_data);
write_raw_bit(0, 2, card_data);
write_raw_bit(1, 3, card_data);
write_raw_bit(1, 4, card_data);
write_raw_bit(1, 5, card_data);
write_raw_bit(0, 6, card_data);
write_raw_bit(1, 7, card_data);
// company / OEM code 1
write_bit(0, 8, card_data);
write_bit(0, 10, card_data);
write_bit(0, 12, card_data);
write_bit(0, 14, card_data);
write_bit(0, 16, card_data);
write_bit(0, 18, card_data);
write_bit(1, 20, card_data);
// card format / length 1
write_bit(0, 22, card_data);
write_bit(0, 24, card_data);
write_bit(0, 26, card_data);
write_bit(0, 28, card_data);
write_bit(0, 30, card_data);
write_bit(0, 32, card_data);
write_bit(0, 34, card_data);
write_bit(0, 36, card_data);
write_bit(0, 38, card_data);
write_bit(0, 40, card_data);
write_bit(1, 42, card_data);
// even parity bit
write_bit((even_parity_sum % 2), 44, card_data);
// data
for(uint8_t i = 0; i < 24; i++) {
write_bit((fc_cn >> (23 - i)) & 1, 46 + (i * 2), card_data);
}
// odd parity bit
write_bit((odd_parity_sum % 2), 94, card_data);
memcpy(encoded_data, &card_data, get_encoded_data_size());
}
void ProtocolHID10301::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 >= get_decoded_data_size());
furi_check(encoded_data_size >= get_encoded_data_size());
const HID10301CardData* card_data = reinterpret_cast<const HID10301CardData*>(encoded_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[3] = {(uint8_t)(result >> 17), (uint8_t)(result >> 9), (uint8_t)(result >> 1)};
memcpy(decoded_data, &data, get_decoded_data_size());
}
bool ProtocolHID10301::can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) {
furi_check(encoded_data_size >= get_encoded_data_size());
const HID10301CardData* card_data = reinterpret_cast<const HID10301CardData*>(encoded_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;
}

View File

@@ -0,0 +1,22 @@
#pragma once
#include "protocol-generic.h"
class ProtocolHID10301 : public ProtocolGeneric {
public:
uint8_t get_encoded_data_size() final;
uint8_t get_decoded_data_size() final;
void encode(
const uint8_t* decoded_data,
const uint8_t decoded_data_size,
uint8_t* encoded_data,
const uint8_t encoded_data_size) final;
void decode(
const uint8_t* encoded_data,
const uint8_t encoded_data_size,
uint8_t* decoded_data,
const uint8_t decoded_data_size) final;
bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) final;
};

View File

@@ -0,0 +1,131 @@
#include "protocol-indala-40134.h"
#include <furi.h>
typedef uint64_t Indala40134CardData;
static void set_bit(bool bit, uint8_t position, Indala40134CardData* card_data) {
position = (sizeof(Indala40134CardData) * 8) - 1 - position;
if(bit) {
*card_data |= 1ull << position;
} else {
*card_data &= ~(1ull << position);
}
}
uint8_t ProtocolIndala40134::get_encoded_data_size() {
return sizeof(Indala40134CardData);
}
uint8_t ProtocolIndala40134::get_decoded_data_size() {
return 3;
}
void ProtocolIndala40134::encode(
const uint8_t* decoded_data,
const uint8_t decoded_data_size,
uint8_t* encoded_data,
const uint8_t encoded_data_size) {
furi_check(decoded_data_size >= get_decoded_data_size());
furi_check(encoded_data_size >= get_encoded_data_size());
uint32_t fc_and_card = (decoded_data[0] << 16) | (decoded_data[1] << 8) | decoded_data[2];
Indala40134CardData card_data = 0;
// preamble
set_bit(1, 0, &card_data);
set_bit(1, 2, &card_data);
set_bit(1, 32, &card_data);
// factory code
set_bit(((fc_and_card >> 23) & 1), 57, &card_data);
set_bit(((fc_and_card >> 22) & 1), 49, &card_data);
set_bit(((fc_and_card >> 21) & 1), 44, &card_data);
set_bit(((fc_and_card >> 20) & 1), 47, &card_data);
set_bit(((fc_and_card >> 19) & 1), 48, &card_data);
set_bit(((fc_and_card >> 18) & 1), 53, &card_data);
set_bit(((fc_and_card >> 17) & 1), 39, &card_data);
set_bit(((fc_and_card >> 16) & 1), 58, &card_data);
// card number
set_bit(((fc_and_card >> 15) & 1), 42, &card_data);
set_bit(((fc_and_card >> 14) & 1), 45, &card_data);
set_bit(((fc_and_card >> 13) & 1), 43, &card_data);
set_bit(((fc_and_card >> 12) & 1), 40, &card_data);
set_bit(((fc_and_card >> 11) & 1), 52, &card_data);
set_bit(((fc_and_card >> 10) & 1), 36, &card_data);
set_bit(((fc_and_card >> 9) & 1), 35, &card_data);
set_bit(((fc_and_card >> 8) & 1), 51, &card_data);
set_bit(((fc_and_card >> 7) & 1), 46, &card_data);
set_bit(((fc_and_card >> 6) & 1), 33, &card_data);
set_bit(((fc_and_card >> 5) & 1), 37, &card_data);
set_bit(((fc_and_card >> 4) & 1), 54, &card_data);
set_bit(((fc_and_card >> 3) & 1), 56, &card_data);
set_bit(((fc_and_card >> 2) & 1), 59, &card_data);
set_bit(((fc_and_card >> 1) & 1), 50, &card_data);
set_bit(((fc_and_card >> 0) & 1), 41, &card_data);
// checksum
uint8_t checksum = 0;
checksum += ((fc_and_card >> 14) & 1);
checksum += ((fc_and_card >> 12) & 1);
checksum += ((fc_and_card >> 9) & 1);
checksum += ((fc_and_card >> 8) & 1);
checksum += ((fc_and_card >> 6) & 1);
checksum += ((fc_and_card >> 5) & 1);
checksum += ((fc_and_card >> 2) & 1);
checksum += ((fc_and_card >> 0) & 1);
// wiegand parity bits
// 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_and_card >> 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_and_card >> i) & 1) == 1) {
odd_parity_sum++;
}
}
// even parity bit
set_bit((even_parity_sum % 2), 34, &card_data);
// odd parity bit
set_bit((odd_parity_sum % 2), 38, &card_data);
// checksum
if((checksum & 1) == 1) {
set_bit(0, 62, &card_data);
set_bit(1, 63, &card_data);
} else {
set_bit(1, 62, &card_data);
set_bit(0, 63, &card_data);
}
memcpy(encoded_data, &card_data, get_encoded_data_size());
}
void ProtocolIndala40134::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 >= get_decoded_data_size());
furi_check(encoded_data_size >= get_encoded_data_size());
// TODO implement decoding
furi_check(0);
}
bool ProtocolIndala40134::can_be_decoded(
const uint8_t* encoded_data,
const uint8_t encoded_data_size) {
furi_check(encoded_data_size >= get_encoded_data_size());
// TODO implement decoding
furi_check(0);
return false;
}

View File

@@ -0,0 +1,22 @@
#pragma once
#include "protocol-generic.h"
class ProtocolIndala40134 : public ProtocolGeneric {
public:
uint8_t get_encoded_data_size() final;
uint8_t get_decoded_data_size() final;
void encode(
const uint8_t* decoded_data,
const uint8_t decoded_data_size,
uint8_t* encoded_data,
const uint8_t encoded_data_size) final;
void decode(
const uint8_t* encoded_data,
const uint8_t encoded_data_size,
uint8_t* decoded_data,
const uint8_t decoded_data_size) final;
bool can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) final;
};

View File

@@ -0,0 +1,118 @@
#include "rfid-writer.h"
#include <api-hal.h>
#include "protocols/protocol-emmarin.h"
extern COMP_HandleTypeDef hcomp1;
/**
* @brief all timings are specified in field clocks (field clock = 125 kHz, 8 us)
*
*/
class T55xxTiming {
public:
constexpr static const uint16_t wait_time = 400;
constexpr static const uint8_t start_gap = 15;
constexpr static const uint8_t write_gap = 10;
constexpr static const uint8_t data_0 = 24;
constexpr static const uint8_t data_1 = 56;
constexpr static const uint16_t program = 700;
};
class T55xxCmd {
public:
constexpr static const uint8_t opcode_page_0 = 0b10;
constexpr static const uint8_t opcode_page_1 = 0b11;
constexpr static const uint8_t opcode_reset = 0b00;
};
RfidWriter::RfidWriter() {
}
RfidWriter::~RfidWriter() {
}
void RfidWriter::start() {
api_hal_rfid_tim_read(125000, 0.5);
api_hal_rfid_pins_read();
}
void RfidWriter::stop() {
api_hal_rfid_tim_read_stop();
api_hal_rfid_tim_reset();
api_hal_rfid_pins_reset();
}
void RfidWriter::write_gap(uint32_t gap_time) {
api_hal_rfid_tim_read_stop();
delay_us(gap_time * 8);
api_hal_rfid_tim_read_start();
}
void RfidWriter::write_bit(bool value) {
if(value) {
delay_us(T55xxTiming::data_1 * 8);
} else {
delay_us(T55xxTiming::data_0 * 8);
}
write_gap(T55xxTiming::write_gap);
}
void RfidWriter::write_byte(uint8_t value) {
for(uint8_t i = 0; i < 8; i++) {
write_bit((value >> i) & 1);
}
}
void RfidWriter::write_block(uint8_t page, uint8_t block, bool lock_bit, uint32_t data) {
// wait to power card
api_hal_rfid_tim_read_start();
delay_us(T55xxTiming::wait_time * 8);
// start gap
write_gap(T55xxTiming::start_gap);
// opcode
switch(page) {
case 0:
write_bit(1);
write_bit(0);
break;
case 1:
write_bit(1);
write_bit(1);
break;
default:
furi_check(false);
break;
}
// lock bit
write_bit(lock_bit);
// data
for(uint8_t i = 0; i < 32; i++) {
write_bit((data >> (31 - i)) & 1);
}
// block address
write_bit((block >> 2) & 1);
write_bit((block >> 1) & 1);
write_bit((block >> 0) & 1);
delay_us(T55xxTiming::program * 8);
api_hal_rfid_tim_read_stop();
}
void RfidWriter::write_em(uint8_t em_data[5]) {
ProtocolEMMarin em_card;
uint64_t em_encoded_data;
em_card.encode(em_data, 5, reinterpret_cast<uint8_t*>(&em_encoded_data), sizeof(uint64_t));
uint32_t em_config_block_data = 0b01100000000101001000000001000000;
__disable_irq();
write_block(0, 0, false, em_config_block_data);
write_block(0, 1, false, em_encoded_data);
write_block(0, 2, false, em_encoded_data >> 32);
__enable_irq();
}

View File

@@ -0,0 +1,17 @@
#pragma once
#include "stdint.h"
class RfidWriter {
public:
RfidWriter();
~RfidWriter();
void start();
void stop();
void write_em(uint8_t em_data[5]);
private:
void write_gap(uint32_t gap_time);
void write_bit(bool value);
void write_byte(uint8_t value);
void write_block(uint8_t page, uint8_t block, bool lock_bit, uint32_t data);
};