[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:
parent
588480831a
commit
618ddfcd04
@ -20,84 +20,13 @@ void DecoderEMMarine::reset_state() {
|
|||||||
manchester_saved_state, ManchesterEventReset, &manchester_saved_state, nullptr);
|
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 DecoderEMMarine::read(uint8_t* data, uint8_t data_size) {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
if(ready) {
|
if(ready) {
|
||||||
result = true;
|
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;
|
ready = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,37 +61,8 @@ void DecoderEMMarine::process_front(bool polarity, uint32_t time) {
|
|||||||
if(data_ok) {
|
if(data_ok) {
|
||||||
readed_data = (readed_data << 1) | data;
|
readed_data = (readed_data << 1) | data;
|
||||||
|
|
||||||
// header and stop bit
|
ready = em_marine.can_be_decoded(
|
||||||
if((readed_data & EM_HEADER_AND_STOP_MASK) != EM_HEADER_AND_STOP_DATA) return;
|
reinterpret_cast<const uint8_t*>(&readed_data), sizeof(uint64_t));
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include "manchester-decoder.h"
|
#include "manchester-decoder.h"
|
||||||
|
#include "protocols/protocol-emmarin.h"
|
||||||
class DecoderEMMarine {
|
class DecoderEMMarine {
|
||||||
public:
|
public:
|
||||||
bool read(uint8_t* data, uint8_t data_size);
|
bool read(uint8_t* data, uint8_t data_size);
|
||||||
@ -17,4 +17,5 @@ private:
|
|||||||
std::atomic<bool> ready;
|
std::atomic<bool> ready;
|
||||||
|
|
||||||
ManchesterState manchester_saved_state;
|
ManchesterState manchester_saved_state;
|
||||||
|
ProtocolEMMarin em_marine;
|
||||||
};
|
};
|
||||||
|
@ -17,11 +17,8 @@ bool DecoderHID26::read(uint8_t* data, uint8_t data_size) {
|
|||||||
|
|
||||||
if(ready) {
|
if(ready) {
|
||||||
result = true;
|
result = true;
|
||||||
data[0] = facility;
|
hid.decode(
|
||||||
data[1] = (uint8_t)(number >> 8);
|
reinterpret_cast<const uint8_t*>(&stored_data), sizeof(uint32_t) * 3, data, data_size);
|
||||||
data[2] = (uint8_t)number;
|
|
||||||
|
|
||||||
//printf("HID %02X %02X %02X\r\n", facility, (uint8_t)(number >> 8), (uint8_t)number);
|
|
||||||
ready = false;
|
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[0] = (stored_data[0] << 1) | ((stored_data[1] >> 31) & 1);
|
||||||
stored_data[1] = (stored_data[1] << 1) | ((stored_data[2] >> 31) & 1);
|
stored_data[1] = (stored_data[1] << 1) | ((stored_data[2] >> 31) & 1);
|
||||||
stored_data[2] = (stored_data[2] << 1) | data;
|
stored_data[2] = (stored_data[2] << 1) | data;
|
||||||
validate_stored_data();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DecoderHID26::validate_stored_data() {
|
if(hid.can_be_decoded(reinterpret_cast<const uint8_t*>(&stored_data), sizeof(uint32_t) * 3)) {
|
||||||
// packet preamble
|
ready = true;
|
||||||
// raw data
|
|
||||||
if(*(reinterpret_cast<uint8_t*>(stored_data) + 3) != 0x1D) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// encoded company/oem
|
|
||||||
// coded with 01 = 0, 10 = 1 transitions
|
|
||||||
// stored in word 0
|
|
||||||
if((*stored_data >> 10 & 0x3FFF) != 0x1556) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// encoded format/length
|
|
||||||
// coded with 01 = 0, 10 = 1 transitions
|
|
||||||
// stored in word 0 and word 1
|
|
||||||
if((((*stored_data & 0x3FF) << 12) | ((*(stored_data + 1) >> 20) & 0xFFF)) != 0x155556) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// data decoding
|
|
||||||
uint32_t result = 0;
|
|
||||||
|
|
||||||
// decode from word 1
|
|
||||||
// coded with 01 = 0, 10 = 1 transitions
|
|
||||||
for(int8_t i = 9; i >= 0; i--) {
|
|
||||||
switch((*(stored_data + 1) >> (2 * i)) & 0b11) {
|
|
||||||
case 0b01:
|
|
||||||
result = (result << 1) | 0;
|
|
||||||
break;
|
|
||||||
case 0b10:
|
|
||||||
result = (result << 1) | 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// decode from word 2
|
|
||||||
// coded with 01 = 0, 10 = 1 transitions
|
|
||||||
for(int8_t i = 15; i >= 0; i--) {
|
|
||||||
switch((*(stored_data + 2) >> (2 * i)) & 0b11) {
|
|
||||||
case 0b01:
|
|
||||||
result = (result << 1) | 0;
|
|
||||||
break;
|
|
||||||
case 0b10:
|
|
||||||
result = (result << 1) | 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// store decoded data
|
|
||||||
facility = result >> 17;
|
|
||||||
number = result >> 1;
|
|
||||||
|
|
||||||
// trailing parity (odd) test
|
|
||||||
uint8_t parity_sum = 0;
|
|
||||||
for(int8_t i = 0; i < 13; i++) {
|
|
||||||
if(((result >> i) & 1) == 1) {
|
|
||||||
parity_sum++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if((parity_sum % 2) != 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// leading parity (even) test
|
|
||||||
parity_sum = 0;
|
|
||||||
for(int8_t i = 13; i < 26; i++) {
|
|
||||||
if(((result >> i) & 1) == 1) {
|
|
||||||
parity_sum++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if((parity_sum % 2) == 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ready = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecoderHID26::reset_state() {
|
void DecoderHID26::reset_state() {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include "protocols/protocol-hid-h10301.h"
|
||||||
|
|
||||||
class DecoderHID26 {
|
class DecoderHID26 {
|
||||||
public:
|
public:
|
||||||
@ -15,12 +16,9 @@ private:
|
|||||||
|
|
||||||
uint32_t stored_data[3] = {0, 0, 0};
|
uint32_t stored_data[3] = {0, 0, 0};
|
||||||
void store_data(bool data);
|
void store_data(bool data);
|
||||||
void validate_stored_data();
|
|
||||||
|
|
||||||
uint8_t facility = 0;
|
|
||||||
uint16_t number = 0;
|
|
||||||
|
|
||||||
std::atomic<bool> ready;
|
std::atomic<bool> ready;
|
||||||
|
|
||||||
void reset_state();
|
void reset_state();
|
||||||
|
ProtocolHID10301 hid;
|
||||||
};
|
};
|
@ -1,48 +1,14 @@
|
|||||||
#include "encoder-emmarine.h"
|
#include "encoder-emmarine.h"
|
||||||
|
#include "protocols/protocol-emmarin.h"
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
|
|
||||||
void EncoderEM::init(const uint8_t* data, const uint8_t data_size) {
|
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;
|
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
|
// data transmitted as manchester encoding
|
||||||
// 0 - high2low
|
// 0 - high2low
|
||||||
// 1 - low2high
|
// 1 - low2high
|
||||||
|
@ -19,5 +19,4 @@ private:
|
|||||||
|
|
||||||
uint64_t card_data;
|
uint64_t card_data;
|
||||||
uint8_t card_data_index;
|
uint8_t card_data_index;
|
||||||
void write_nibble(bool low_nibble, uint8_t data);
|
|
||||||
};
|
};
|
@ -1,73 +1,10 @@
|
|||||||
#include "encoder-hid-h10301.h"
|
#include "encoder-hid-h10301.h"
|
||||||
|
#include "protocols/protocol-hid-h10301.h"
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
|
|
||||||
void EncoderHID_H10301::init(const uint8_t* data, const uint8_t data_size) {
|
void EncoderHID_H10301::init(const uint8_t* data, const uint8_t data_size) {
|
||||||
furi_check(data_size == 3);
|
ProtocolHID10301 hid;
|
||||||
|
hid.encode(data, data_size, reinterpret_cast<uint8_t*>(&card_data), sizeof(card_data) * 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);
|
|
||||||
|
|
||||||
card_data_index = 0;
|
card_data_index = 0;
|
||||||
bit_index = 0;
|
bit_index = 0;
|
||||||
|
@ -1,102 +1,16 @@
|
|||||||
#include "encoder-indala-40134.h"
|
#include "encoder-indala-40134.h"
|
||||||
|
#include "protocols/protocol-indala-40134.h"
|
||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
|
|
||||||
void EncoderIndala_40134::init(const uint8_t* data, const uint8_t data_size) {
|
void EncoderIndala_40134::init(const uint8_t* data, const uint8_t data_size) {
|
||||||
furi_check(data_size == 3);
|
ProtocolIndala40134 indala;
|
||||||
uint32_t fc_and_card = (data[0] << 16) | (data[1] << 8) | data[2];
|
indala.encode(data, data_size, reinterpret_cast<uint8_t*>(&card_data), sizeof(card_data));
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
last_bit = card_data & 1;
|
last_bit = card_data & 1;
|
||||||
card_data_index = 0;
|
card_data_index = 0;
|
||||||
current_polarity = true;
|
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) {
|
void EncoderIndala_40134::get_next(bool* polarity, uint16_t* period, uint16_t* pulse) {
|
||||||
*period = 2;
|
*period = 2;
|
||||||
*pulse = 1;
|
*pulse = 1;
|
||||||
|
@ -20,6 +20,4 @@ private:
|
|||||||
bool last_bit;
|
bool last_bit;
|
||||||
bool current_polarity;
|
bool current_polarity;
|
||||||
static const uint8_t clock_per_bit = 16;
|
static const uint8_t clock_per_bit = 16;
|
||||||
|
|
||||||
void set_bit(bool bit, uint8_t position);
|
|
||||||
};
|
};
|
@ -6,4 +6,5 @@ static const uint8_t LFRFID_KEY_SIZE = 8;
|
|||||||
enum class LfrfidKeyType : uint8_t {
|
enum class LfrfidKeyType : uint8_t {
|
||||||
KeyEmarine,
|
KeyEmarine,
|
||||||
KeyHID,
|
KeyHID,
|
||||||
|
KeyIndala,
|
||||||
};
|
};
|
150
applications/lf-rfid/helpers/protocols/protocol-emmarin.cpp
Normal file
150
applications/lf-rfid/helpers/protocols/protocol-emmarin.cpp
Normal 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;
|
||||||
|
}
|
22
applications/lf-rfid/helpers/protocols/protocol-emmarin.h
Normal file
22
applications/lf-rfid/helpers/protocols/protocol-emmarin.h
Normal 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;
|
||||||
|
};
|
60
applications/lf-rfid/helpers/protocols/protocol-generic.h
Normal file
60
applications/lf-rfid/helpers/protocols/protocol-generic.h
Normal 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(){};
|
||||||
|
};
|
238
applications/lf-rfid/helpers/protocols/protocol-hid-h10301.cpp
Normal file
238
applications/lf-rfid/helpers/protocols/protocol-hid-h10301.cpp
Normal 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;
|
||||||
|
}
|
22
applications/lf-rfid/helpers/protocols/protocol-hid-h10301.h
Normal file
22
applications/lf-rfid/helpers/protocols/protocol-hid-h10301.h
Normal 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;
|
||||||
|
};
|
131
applications/lf-rfid/helpers/protocols/protocol-indala-40134.cpp
Normal file
131
applications/lf-rfid/helpers/protocols/protocol-indala-40134.cpp
Normal 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;
|
||||||
|
}
|
@ -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;
|
||||||
|
};
|
118
applications/lf-rfid/helpers/rfid-writer.cpp
Normal file
118
applications/lf-rfid/helpers/rfid-writer.cpp
Normal 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();
|
||||||
|
}
|
17
applications/lf-rfid/helpers/rfid-writer.h
Normal file
17
applications/lf-rfid/helpers/rfid-writer.h
Normal 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);
|
||||||
|
};
|
@ -143,4 +143,8 @@ RfidReader* LfrfidApp::get_reader() {
|
|||||||
|
|
||||||
RfidTimerEmulator* LfrfidApp::get_emulator() {
|
RfidTimerEmulator* LfrfidApp::get_emulator() {
|
||||||
return &emulator;
|
return &emulator;
|
||||||
|
}
|
||||||
|
|
||||||
|
RfidWriter* LfrfidApp::get_writer() {
|
||||||
|
return &writer;
|
||||||
}
|
}
|
@ -10,6 +10,7 @@
|
|||||||
#include "scene/lf-rfid-scene-read-normal.h"
|
#include "scene/lf-rfid-scene-read-normal.h"
|
||||||
#include "scene/lf-rfid-scene-read-indala.h"
|
#include "scene/lf-rfid-scene-read-indala.h"
|
||||||
#include "scene/lf-rfid-scene-tune.h"
|
#include "scene/lf-rfid-scene-tune.h"
|
||||||
|
#include "scene/lf-rfid-scene-write.h"
|
||||||
|
|
||||||
#include "helpers/rfid-reader.h"
|
#include "helpers/rfid-reader.h"
|
||||||
#include "helpers/rfid-timer-emulator.h"
|
#include "helpers/rfid-timer-emulator.h"
|
||||||
@ -30,6 +31,7 @@ public:
|
|||||||
EmulateHID,
|
EmulateHID,
|
||||||
EmulateEM,
|
EmulateEM,
|
||||||
Tune,
|
Tune,
|
||||||
|
Write,
|
||||||
};
|
};
|
||||||
|
|
||||||
LfrfidAppViewManager* get_view_manager();
|
LfrfidAppViewManager* get_view_manager();
|
||||||
@ -49,6 +51,7 @@ public:
|
|||||||
|
|
||||||
RfidReader* get_reader();
|
RfidReader* get_reader();
|
||||||
RfidTimerEmulator* get_emulator();
|
RfidTimerEmulator* get_emulator();
|
||||||
|
RfidWriter* get_writer();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::list<Scene> previous_scenes_list = {Scene::Exit};
|
std::list<Scene> previous_scenes_list = {Scene::Exit};
|
||||||
@ -63,6 +66,7 @@ private:
|
|||||||
{Scene::EmulateHID, new LfrfidSceneEmulateHID()},
|
{Scene::EmulateHID, new LfrfidSceneEmulateHID()},
|
||||||
{Scene::EmulateEM, new LfrfidSceneEmulateEMMarine()},
|
{Scene::EmulateEM, new LfrfidSceneEmulateEMMarine()},
|
||||||
{Scene::Tune, new LfrfidSceneTune()},
|
{Scene::Tune, new LfrfidSceneTune()},
|
||||||
|
{Scene::Write, new LfrfidSceneWrite()},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint8_t text_store_size = 128;
|
static const uint8_t text_store_size = 128;
|
||||||
@ -70,4 +74,5 @@ private:
|
|||||||
|
|
||||||
RfidReader reader;
|
RfidReader reader;
|
||||||
RfidTimerEmulator emulator;
|
RfidTimerEmulator emulator;
|
||||||
|
RfidWriter writer;
|
||||||
};
|
};
|
@ -55,6 +55,15 @@ bool LfrfidSceneReadNormal::on_event(LfrfidApp* app, LfrfidEvent* event) {
|
|||||||
data[2],
|
data[2],
|
||||||
success_reads);
|
success_reads);
|
||||||
break;
|
break;
|
||||||
|
case LfrfidKeyType::KeyIndala:
|
||||||
|
app->set_text_store(
|
||||||
|
"[IND] %02X %02X %02X\n"
|
||||||
|
"count: %u",
|
||||||
|
data[0],
|
||||||
|
data[1],
|
||||||
|
data[2],
|
||||||
|
success_reads);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
popup_set_text(
|
popup_set_text(
|
||||||
app->get_view_manager()->get_popup(),
|
app->get_view_manager()->get_popup(),
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <callback-connector.h>
|
#include <callback-connector.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
SubmenuIndexWrite,
|
||||||
SubmenuIndexReadNormal,
|
SubmenuIndexReadNormal,
|
||||||
SubmenuIndexReadIndala,
|
SubmenuIndexReadIndala,
|
||||||
SubmenuIndexEmulateEM,
|
SubmenuIndexEmulateEM,
|
||||||
@ -18,6 +19,7 @@ void LfrfidSceneStart::on_enter(LfrfidApp* app) {
|
|||||||
Submenu* submenu = view_manager->get_submenu();
|
Submenu* submenu = view_manager->get_submenu();
|
||||||
auto callback = cbc::obtain_connector(this, &LfrfidSceneStart::submenu_callback);
|
auto callback = cbc::obtain_connector(this, &LfrfidSceneStart::submenu_callback);
|
||||||
|
|
||||||
|
submenu_add_item(submenu, "Write T5577", SubmenuIndexWrite, callback, app);
|
||||||
submenu_add_item(submenu, "Read Normal", SubmenuIndexReadNormal, callback, app);
|
submenu_add_item(submenu, "Read Normal", SubmenuIndexReadNormal, callback, app);
|
||||||
submenu_add_item(submenu, "Read Indala", SubmenuIndexReadIndala, callback, app);
|
submenu_add_item(submenu, "Read Indala", SubmenuIndexReadIndala, callback, app);
|
||||||
submenu_add_item(submenu, "Emulate EM", SubmenuIndexEmulateEM, callback, app);
|
submenu_add_item(submenu, "Emulate EM", SubmenuIndexEmulateEM, callback, app);
|
||||||
@ -33,6 +35,9 @@ bool LfrfidSceneStart::on_event(LfrfidApp* app, LfrfidEvent* event) {
|
|||||||
|
|
||||||
if(event->type == LfrfidEvent::Type::MenuSelected) {
|
if(event->type == LfrfidEvent::Type::MenuSelected) {
|
||||||
switch(event->payload.menu_index) {
|
switch(event->payload.menu_index) {
|
||||||
|
case SubmenuIndexWrite:
|
||||||
|
app->switch_to_next_scene(LfrfidApp::Scene::Write);
|
||||||
|
break;
|
||||||
case SubmenuIndexReadNormal:
|
case SubmenuIndexReadNormal:
|
||||||
app->switch_to_next_scene(LfrfidApp::Scene::ReadNormal);
|
app->switch_to_next_scene(LfrfidApp::Scene::ReadNormal);
|
||||||
break;
|
break;
|
||||||
|
70
applications/lf-rfid/scene/lf-rfid-scene-write.cpp
Normal file
70
applications/lf-rfid/scene/lf-rfid-scene-write.cpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#include "lf-rfid-scene-write.h"
|
||||||
|
|
||||||
|
#include "../lf-rfid-app.h"
|
||||||
|
#include "../lf-rfid-view-manager.h"
|
||||||
|
#include "../lf-rfid-event.h"
|
||||||
|
#include "../helpers/key-info.h"
|
||||||
|
|
||||||
|
void LfrfidSceneWrite::on_enter(LfrfidApp* app) {
|
||||||
|
LfrfidAppViewManager* view_manager = app->get_view_manager();
|
||||||
|
|
||||||
|
Popup* popup = view_manager->get_popup();
|
||||||
|
popup_set_header(popup, "LF-RFID", 64, 16, AlignCenter, AlignBottom);
|
||||||
|
app->set_text_store("Writing...");
|
||||||
|
popup_set_text(popup, app->get_text_store(), 64, 22, AlignCenter, AlignTop);
|
||||||
|
|
||||||
|
view_manager->switch_to(LfrfidAppViewManager::ViewType::Popup);
|
||||||
|
|
||||||
|
timing_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LfrfidSceneWrite::on_event(LfrfidApp* app, LfrfidEvent* event) {
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
|
// TODO move read\write logic to key worker
|
||||||
|
|
||||||
|
bool readed = false;
|
||||||
|
uint8_t em_data[5] = {0x1A, 0x2B, 0xC3, 0xD4, 0xE5};
|
||||||
|
|
||||||
|
if(timing_index == 0) {
|
||||||
|
app->get_reader()->stop();
|
||||||
|
app->get_writer()->start();
|
||||||
|
app->get_writer()->write_em(em_data);
|
||||||
|
app->get_writer()->stop();
|
||||||
|
delay(100);
|
||||||
|
app->get_reader()->start(RfidReader::Type::Normal);
|
||||||
|
} else {
|
||||||
|
uint8_t data[LFRFID_KEY_SIZE];
|
||||||
|
LfrfidKeyType type;
|
||||||
|
|
||||||
|
app->get_reader()->read(&type, data, LFRFID_KEY_SIZE);
|
||||||
|
if(type == LfrfidKeyType::KeyEmarine) {
|
||||||
|
if(memcmp(em_data, data, 5) == 0) {
|
||||||
|
readed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(readed) {
|
||||||
|
app->set_text_store("Writed!");
|
||||||
|
app->notify_green_blink();
|
||||||
|
} else {
|
||||||
|
app->set_text_store("Writing [1A 2B C3 D4 E5]");
|
||||||
|
timing_index++;
|
||||||
|
if(timing_index == 4) {
|
||||||
|
timing_index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
popup_set_text(
|
||||||
|
app->get_view_manager()->get_popup(), app->get_text_store(), 64, 22, AlignCenter, AlignTop);
|
||||||
|
|
||||||
|
return consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LfrfidSceneWrite::on_exit(LfrfidApp* app) {
|
||||||
|
LfrfidAppViewManager* view_manager = app->get_view_manager();
|
||||||
|
|
||||||
|
Popup* popup = view_manager->get_popup();
|
||||||
|
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
|
||||||
|
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
|
||||||
|
}
|
14
applications/lf-rfid/scene/lf-rfid-scene-write.h
Normal file
14
applications/lf-rfid/scene/lf-rfid-scene-write.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "lf-rfid-scene-generic.h"
|
||||||
|
#include "../helpers/key-info.h"
|
||||||
|
#include "../helpers/rfid-writer.h"
|
||||||
|
|
||||||
|
class LfrfidSceneWrite : public LfrfidScene {
|
||||||
|
public:
|
||||||
|
void on_enter(LfrfidApp* app) final;
|
||||||
|
bool on_event(LfrfidApp* app, LfrfidEvent* event) final;
|
||||||
|
void on_exit(LfrfidApp* app) final;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t timing_index;
|
||||||
|
};
|
@ -41,11 +41,28 @@ static uint8_t hal_gpio_get_pin_num(const GpioPin* gpio) {
|
|||||||
return pin_num;
|
return pin_num;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hal_gpio_init_simple(const GpioPin* gpio, const GpioMode mode) {
|
||||||
|
hal_gpio_init(gpio, mode, GpioPullNo, GpioSpeedLow);
|
||||||
|
}
|
||||||
|
|
||||||
void hal_gpio_init(
|
void hal_gpio_init(
|
||||||
const GpioPin* gpio,
|
const GpioPin* gpio,
|
||||||
const GpioMode mode,
|
const GpioMode mode,
|
||||||
const GpioPull pull,
|
const GpioPull pull,
|
||||||
const GpioSpeed speed) {
|
const GpioSpeed speed) {
|
||||||
|
// we cannot set alternate mode in this function
|
||||||
|
furi_assert(mode != GpioModeAltFunctionPushPull);
|
||||||
|
furi_assert(mode != GpioModeAltFunctionOpenDrain);
|
||||||
|
|
||||||
|
hal_gpio_init_ex(gpio, mode, GpioPullNo, GpioSpeedLow, GpioAltFnUnused);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hal_gpio_init_ex(
|
||||||
|
const GpioPin* gpio,
|
||||||
|
const GpioMode mode,
|
||||||
|
const GpioPull pull,
|
||||||
|
const GpioSpeed speed,
|
||||||
|
const GpioAltFn alt_fn) {
|
||||||
uint32_t sys_exti_port = GET_SYSCFG_EXTI_PORT(gpio->port);
|
uint32_t sys_exti_port = GET_SYSCFG_EXTI_PORT(gpio->port);
|
||||||
uint32_t sys_exti_line = GET_SYSCFG_EXTI_LINE(gpio->pin);
|
uint32_t sys_exti_line = GET_SYSCFG_EXTI_LINE(gpio->pin);
|
||||||
uint32_t exti_line = GET_EXTI_LINE(gpio->pin);
|
uint32_t exti_line = GET_EXTI_LINE(gpio->pin);
|
||||||
@ -112,27 +129,19 @@ void hal_gpio_init(
|
|||||||
LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ANALOG);
|
LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ANALOG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
__enable_irq();
|
|
||||||
}
|
|
||||||
|
|
||||||
void hal_gpio_init_alt(
|
if(mode == GpioModeAltFunctionPushPull || mode == GpioModeAltFunctionOpenDrain) {
|
||||||
const GpioPin* gpio,
|
// enable alternate mode
|
||||||
const GpioMode mode,
|
LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ALTERNATE);
|
||||||
const GpioPull pull,
|
|
||||||
const GpioSpeed speed,
|
|
||||||
const GpioAltFn alt_fn) {
|
|
||||||
hal_gpio_init(gpio, mode, pull, speed);
|
|
||||||
|
|
||||||
__disable_irq();
|
// set alternate function
|
||||||
// enable alternate mode
|
if(hal_gpio_get_pin_num(gpio) < 8) {
|
||||||
LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ALTERNATE);
|
LL_GPIO_SetAFPin_0_7(gpio->port, gpio->pin, alt_fn);
|
||||||
|
} else {
|
||||||
// set alternate function
|
LL_GPIO_SetAFPin_8_15(gpio->port, gpio->pin, alt_fn);
|
||||||
if(hal_gpio_get_pin_num(gpio) < 8) {
|
}
|
||||||
LL_GPIO_SetAFPin_0_7(gpio->port, gpio->pin, alt_fn);
|
|
||||||
} else {
|
|
||||||
LL_GPIO_SetAFPin_8_15(gpio->port, gpio->pin, alt_fn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,6 +153,8 @@ typedef enum {
|
|||||||
GpioAltFn14LPTIM2 = 14, /*!< LPTIM2 Alternate Function mapping */
|
GpioAltFn14LPTIM2 = 14, /*!< LPTIM2 Alternate Function mapping */
|
||||||
|
|
||||||
GpioAltFn15EVENTOUT = 15, /*!< EVENTOUT Alternate Function mapping */
|
GpioAltFn15EVENTOUT = 15, /*!< EVENTOUT Alternate Function mapping */
|
||||||
|
|
||||||
|
GpioAltFnUnused = 16, /*!< just dummy value */
|
||||||
} GpioAltFn;
|
} GpioAltFn;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -164,7 +166,14 @@ typedef struct {
|
|||||||
} GpioPin;
|
} GpioPin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GPIO initialization function
|
* GPIO initialization function, simple version
|
||||||
|
* @param gpio GpioPin
|
||||||
|
* @param mode GpioMode
|
||||||
|
*/
|
||||||
|
void hal_gpio_init_simple(const GpioPin* gpio, const GpioMode mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GPIO initialization function, normal version
|
||||||
* @param gpio GpioPin
|
* @param gpio GpioPin
|
||||||
* @param mode GpioMode
|
* @param mode GpioMode
|
||||||
* @param pull GpioPull
|
* @param pull GpioPull
|
||||||
@ -177,14 +186,14 @@ void hal_gpio_init(
|
|||||||
const GpioSpeed speed);
|
const GpioSpeed speed);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GPIO initialization with alternative function
|
* GPIO initialization function, extended version
|
||||||
* @param gpio GpioPin
|
* @param gpio GpioPin
|
||||||
* @param mode GpioMode
|
* @param mode GpioMode
|
||||||
* @param pull GpioPull
|
* @param pull GpioPull
|
||||||
* @param speed GpioSpeed
|
* @param speed GpioSpeed
|
||||||
* @param alt_fn GpioAltFn
|
* @param alt_fn GpioAltFn
|
||||||
*/
|
*/
|
||||||
void hal_gpio_init_alt(
|
void hal_gpio_init_ex(
|
||||||
const GpioPin* gpio,
|
const GpioPin* gpio,
|
||||||
const GpioMode mode,
|
const GpioMode mode,
|
||||||
const GpioPull pull,
|
const GpioPull pull,
|
||||||
|
@ -21,8 +21,8 @@ void api_hal_rfid_pins_emulate() {
|
|||||||
api_hal_ibutton_pin_low();
|
api_hal_ibutton_pin_low();
|
||||||
|
|
||||||
// pull pin to timer out
|
// pull pin to timer out
|
||||||
hal_gpio_init_alt(
|
hal_gpio_init_ex(
|
||||||
&gpio_rfid_pull, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo, GpioAltFn1TIM1);
|
&gpio_rfid_pull, GpioModeAltFunctionPushPull, GpioSpeedLow, GpioPullNo, GpioAltFn1TIM1);
|
||||||
|
|
||||||
// pull rfid antenna from carrier side
|
// pull rfid antenna from carrier side
|
||||||
hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo);
|
hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo);
|
||||||
@ -39,8 +39,12 @@ void api_hal_rfid_pins_read() {
|
|||||||
hal_gpio_write(&gpio_rfid_pull, false);
|
hal_gpio_write(&gpio_rfid_pull, false);
|
||||||
|
|
||||||
// carrier pin to timer out
|
// carrier pin to timer out
|
||||||
hal_gpio_init_alt(
|
hal_gpio_init_ex(
|
||||||
&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioSpeedLow, GpioPullNo, GpioAltFn1TIM1);
|
&gpio_rfid_carrier_out,
|
||||||
|
GpioModeAltFunctionPushPull,
|
||||||
|
GpioSpeedLow,
|
||||||
|
GpioPullNo,
|
||||||
|
GpioAltFn1TIM1);
|
||||||
|
|
||||||
// comparator in
|
// comparator in
|
||||||
hal_gpio_init(&gpio_rfid_data_in, GpioModeAnalog, GpioSpeedLow, GpioPullNo);
|
hal_gpio_init(&gpio_rfid_data_in, GpioModeAnalog, GpioSpeedLow, GpioPullNo);
|
||||||
|
Loading…
Reference in New Issue
Block a user