diff --git a/firmware/application/Makefile b/firmware/application/Makefile index b6596afd..fbe5b63d 100644 --- a/firmware/application/Makefile +++ b/firmware/application/Makefile @@ -335,11 +335,20 @@ ifeq (${CURRENT_DEVICE_TYPE}, ${CHAMELEON_ULTRA}) $(PROJ_DIR)/rfid/reader/lf/lf_reader_data.c \ $(PROJ_DIR)/rfid/reader/lf/lf_reader_main.c \ $(PROJ_DIR)/rfid/reader/lf/lf_t55xx_data.c \ + $(PROJ_DIR)/rfid/reader/lf/lf_read.c \ + $(PROJ_DIR)/rfid/reader/lf/utils/bitarray.c \ + $(PROJ_DIR)/rfid/reader/lf/utils/bit_buffer.c \ + $(PROJ_DIR)/rfid/reader/lf/utils/spstring.c \ + $(PROJ_DIR)/rfid/reader/lf/utils/t5577.c \ + $(PROJ_DIR)/rfid/reader/lf/utils/manchester_decoder.c \ + $(PROJ_DIR)/rfid/reader/lf/protocols/lfrfid_protocols.c \ + $(PROJ_DIR)/rfid/reader/lf/protocols/protocol_em4100.c \ INC_FOLDERS +=\ ${PROJ_DIR}/rfid/reader/ \ ${PROJ_DIR}/rfid/reader/hf \ ${PROJ_DIR}/rfid/reader/lf \ + ${PROJ_DIR}/rfid/reader/lf/utils \ CFLAGS += -DPROJECT_CHAMELEON_ULTRA diff --git a/firmware/application/src/app_cmd.c b/firmware/application/src/app_cmd.c index cff94f1f..9f917c59 100644 --- a/firmware/application/src/app_cmd.c +++ b/firmware/application/src/app_cmd.c @@ -539,6 +539,15 @@ static data_frame_tx_t *cmd_processor_em410x_write_to_t55XX(uint16_t cmd, uint16 return data_frame_make(cmd, status, 0, NULL); } +static data_frame_tx_t *cmd_processor_lf_read(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + uint8_t card_buffer[64] = { 0x00 }; + status = lf_reader_read(card_buffer, sizeof(card_buffer)); + if (status != STATUS_LF_TAG_OK) { + return data_frame_make(cmd, status, 0, NULL); + } + return data_frame_make(cmd, STATUS_LF_TAG_OK, sizeof(card_buffer), card_buffer); +} + #endif @@ -1298,6 +1307,7 @@ static cmd_data_map_t m_data_cmd_map[] = { { DATA_CMD_EM410X_SCAN, before_reader_run, cmd_processor_em410x_scan, NULL }, { DATA_CMD_EM410X_WRITE_TO_T55XX, before_reader_run, cmd_processor_em410x_write_to_t55XX, NULL }, + { DATA_CMD_LF_READ, before_reader_run, cmd_processor_lf_read, NULL }, #endif diff --git a/firmware/application/src/app_status.h b/firmware/application/src/app_status.h index 0716dbf5..98add2bc 100644 --- a/firmware/application/src/app_status.h +++ b/firmware/application/src/app_status.h @@ -20,6 +20,7 @@ ///////////////////////////////////////////////////////////////////// #define STATUS_LF_TAG_OK (0x40) // Some of the low -frequency cards are successful! #define STATUS_EM410X_TAG_NO_FOUND (0x41) // Can't search for valid EM410X tags +#define STATUS_LF_TAG_NO_FOUND (0x42) // Can't search for valid LF tag ///////////////////////////////////////////////////////////////////// diff --git a/firmware/application/src/data_cmd.h b/firmware/application/src/data_cmd.h index 6b0ff588..fc2aa4f1 100644 --- a/firmware/application/src/data_cmd.h +++ b/firmware/application/src/data_cmd.h @@ -80,6 +80,7 @@ // #define DATA_CMD_EM410X_SCAN (3000) #define DATA_CMD_EM410X_WRITE_TO_T55XX (3001) +#define DATA_CMD_LF_READ (3010) // // ****************************************************************** diff --git a/firmware/application/src/rfid/reader/lf/lf_read.c b/firmware/application/src/rfid/reader/lf/lf_read.c new file mode 100644 index 00000000..367c3734 --- /dev/null +++ b/firmware/application/src/rfid/reader/lf/lf_read.c @@ -0,0 +1,218 @@ +#ifdef debug410x +#include +#endif + +#include "lf_read.h" + +#include "bsp_time.h" +#include "bsp_delay.h" +#include "lf_reader_data.h" +#include "lf_em410x_data.h" +#include "lf_125khz_radio.h" +#include "protocols/lfrfid_protocols.h" + +#define NRF_LOG_MODULE_NAME lf_read +#include "nrf_log.h" +#include "nrf_log_ctrl.h" +#include "nrf_log_default_backends.h" +NRF_LOG_MODULE_REGISTER(); + + +static RAWBUF_TYPE_S carddata; +uint8_t lf_cardbuf[LF_CARD_BUF_SIZE]; + +static volatile uint32_t dataindex = 0; +uint8_t databuf[512] = { 0x00 }; + + +//Process card data, enter raw Buffer's starting position 2 position (21111 ...) +//After processing the card data, put cardbuf, return 5 normal analysis +//pdata is rawbuffer +uint8_t mcst2(RAWBUF_TYPE_S *Pdata) { + uint8_t sync = 1; //After the current interval process is processed, is it on the judgment line + uint8_t cardindex = 0; //Record change number + for (int i = Pdata->startbit; i < RAW_BUF_SIZE * 8; i++) { + uint8_t thisbit = readbit(Pdata->rawa, Pdata->rawb, i); + switch (sync) { + case 1: //Synchronous state + switch (thisbit) { + case 0: //TheSynchronousState1T,Add1Digit0,StillSynchronize + writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 0); + cardindex++; + break; + case 1: // Synchronous status 1.5T, add 1 digit 1, switch to non -synchronized state + writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 1); + cardindex++; + sync = 0; + break; + case 2: //Synchronous2T,Add2Digits10,StillSynchronize + writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 1); + cardindex++; + writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 0); + cardindex++; + break; + default: + return 0; + } + break; + case 0: //Non -synchronous state + switch (thisbit) { + case 0: //1TInNonSynchronousState,Add1Digit1,StillNonSynchronous + writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 1); + cardindex++; + break; + case 1: // In non -synchronous status 1.5T, add 2 digits 10, switch to the synchronous state + writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 1); + cardindex++; + writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 0); + cardindex++; + sync = 1; + break; + case 2: //The2TOfTheNonSynchronousState,ItIsImpossibleToOccur,ReportAnError + return 0; + default: + return 0; + } + break; + } + if (cardindex >= CARD_BUF_SIZE * 8) + break; + } + return 1; +} + +uint8_t lf_read_decoder(uint8_t *pData, uint8_t size, uint8_t *pOut) { + return 0; +} + +void lf_read_encoder(uint8_t *pData, uint8_t *pOut) { +#ifdef EM410X_Encoder_NRF_LOG_INFO + NRF_LOG_INFO("%d ", count1 % 2); + NRF_LOG_INFO(" <- Qi Dian verification : Tail code -> 0\n\n"); +#endif // EM410X_Encoder_NRF_LOG_INFO +} + +// Reading the card function, you need to stop calling, return 0 to read the card, 1 is to read +uint8_t em410x_acquire2(void) { + if (dataindex >= RAW_BUF_SIZE * 8) { +#ifdef debug410x + { + for (int i = 0; i < RAW_BUF_SIZE * 8; i++) { + NRF_LOG_INFO("%d ", readbit(carddata.rawa, carddata.rawb, i)); + } + NRF_LOG_INFO("///raw data\r\n"); + for (int i = 0; i < RAW_BUF_SIZE * 8; i++) { + NRF_LOG_INFO("%d ", databuf[i]); + } + NRF_LOG_INFO("///time data\r\n"); + } +#endif + //Looking for goals 0 1111 1111 + carddata.startbit = 255; + for (int i = 0; i < (RAW_BUF_SIZE * 8) - 8; i++) { + if (readbit(carddata.rawa, carddata.rawb, i) == 1) { + carddata.startbit = 0; + for (int j = 1; j < 8; j++) { + carddata.startbit += (uint8_t)readbit(carddata.rawa, carddata.rawb, i + j); + } + if (carddata.startbit == 0) { + carddata.startbit = i; + break; + } else { + carddata.startbit = 255; + } + } + } + // If you find the right beginning to deal with it + if (carddata.startbit != 255 && carddata.startbit < (RAW_BUF_SIZE * 8) - 64) { + //Guarantee card data can be fully analyzed + //NRF_LOG_INFO("do mac,start: %d\r\n",startbit); + if (mcst2(&carddata) == 1) { + //Card normal analysis +#ifdef debug410x + { + for (int i = 0; i < CARD_BUF_SIZE; i++) { + NRF_LOG_INFO("%02X", carddata.hexbuf[i]); + } + NRF_LOG_INFO("///card data\r\n"); + } +#endif + if (em410x_decoder(carddata.hexbuf, CARD_BUF_SIZE, lf_cardbuf)) { + //Card data check passes +#ifdef debug410x + for (int i = 0; i < 5; i++) { + NRF_LOG_INFO("%02X", (int)lf_cardbuf[i]); + } + NRF_LOG_INFO("///card dataBYTE\r\n"); +#endif + dataindex = 0; + return 1; + } + } + } + // Start a new cycle + dataindex = 0; + } + return 0; +} + +//GPIO interrupt recovery function is used to detect the descending edge +void GPIO_INT0_cb(void) { + if (dataindex < sizeof(databuf)) { + uint32_t cntr = get_lf_counter_value(); + if (cntr > 0xff) + databuf[dataindex] = 0xff; + else + databuf[dataindex] = cntr & 0xff; + dataindex++; + } + + clear_lf_counter_value(); +} + +void lf_read_init_hw(void) { + register_rio_callback(GPIO_INT0_cb); +} + +uint8_t lf_read_reader(uint8_t *uid, uint32_t timeout_ms) { + dataindex = 0; + memset(databuf, 0, sizeof(databuf)); + + lf_read_init_hw(); + start_lf_125khz_radio(); + + autotimer *p_at = bsp_obtain_timer(0); + while (NO_TIMEOUT_1MS(p_at, 500)) { + if (dataindex >= sizeof(databuf)) { + + break; + } + + } + + stop_lf_125khz_radio(); + + bsp_return_timer(p_at); + p_at = NULL; + + if (dataindex > 0) { + NRF_LOG_INFO("--> data [%d]", dataindex); + NRF_LOG_HEXDUMP_INFO(databuf, dataindex - 1); + } else { + NRF_LOG_INFO("--> data empty"); + } + + NRF_LOG_INFO("--> protocols count: %d", lfrfid_protocols_size); + for (int i = 0; i < lfrfid_protocols_size; i++) { + void* data = lfrfid_protocols[i]->alloc(); + NRF_LOG_INFO("-- protocol: %s %s", lfrfid_protocols[i]->manufacturer, lfrfid_protocols[i]->name); + + lfrfid_protocols[i]->decoder.decode(data, databuf, dataindex - 1); + + lfrfid_protocols[i]->free(data); + } + + NRF_LOG_INFO("--> read done."); + + return 0; +} diff --git a/firmware/application/src/rfid/reader/lf/lf_read.h b/firmware/application/src/rfid/reader/lf/lf_read.h new file mode 100644 index 00000000..d9577fe6 --- /dev/null +++ b/firmware/application/src/rfid/reader/lf/lf_read.h @@ -0,0 +1,25 @@ +#ifndef __LF_READ_H__ +#define __LF_READ_H__ + + +#include "data_utils.h" +#include "bsp_time.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define LF_CARD_BUF_SIZE (512) + +void lf_read_init_hw(void); +void lf_read_encoder(uint8_t *pData, uint8_t *pOut); +uint8_t lf_read_decoder(uint8_t *pData, uint8_t size, uint8_t *pOut); +uint8_t lf_read_reader(uint8_t *uid, uint32_t timeout_ms); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/firmware/application/src/rfid/reader/lf/lf_reader_main.c b/firmware/application/src/rfid/reader/lf/lf_reader_main.c index cf37c3be..8b145f5f 100644 --- a/firmware/application/src/rfid/reader/lf/lf_reader_main.c +++ b/firmware/application/src/rfid/reader/lf/lf_reader_main.c @@ -2,6 +2,7 @@ #include "bsp_delay.h" #include "lf_reader_main.h" #include "lf_125khz_radio.h" +#include "lf_read.h" #define NRF_LOG_MODULE_NAME lf_main @@ -105,6 +106,14 @@ uint8_t PcdWriteT55XX(uint8_t *uid, uint8_t *newkey, uint8_t *old_keys, uint8_t return STATUS_LF_TAG_OK; } +uint8_t lf_reader_read(uint8_t *data, size_t buffer_len) { + uint8_t ret = STATUS_LF_TAG_NO_FOUND; + if (lf_read_reader(data, g_timeout_readem_ms) == 1) { + ret = STATUS_LF_TAG_OK; + } + return ret; +} + /** * Set the time value of the card search timeout of the EM card */ diff --git a/firmware/application/src/rfid/reader/lf/lf_reader_main.h b/firmware/application/src/rfid/reader/lf/lf_reader_main.h index d7fe118d..7f8c0743 100644 --- a/firmware/application/src/rfid/reader/lf/lf_reader_main.h +++ b/firmware/application/src/rfid/reader/lf/lf_reader_main.h @@ -2,6 +2,7 @@ #define _LFCOPIER_H_ #include +#include #include "lf_em410x_data.h" @@ -15,4 +16,6 @@ void SetEMScanTagTimeout(uint32_t ms); uint8_t PcdScanEM410X(uint8_t *uid); uint8_t PcdWriteT55XX(uint8_t *uid, uint8_t *newkey, uint8_t *old_keys, uint8_t old_key_count); +uint8_t lf_reader_read(uint8_t *data, size_t buffer_len); + #endif diff --git a/firmware/application/src/rfid/reader/lf/protocols/lfrfid_protocols.c b/firmware/application/src/rfid/reader/lf/protocols/lfrfid_protocols.c new file mode 100644 index 00000000..0dbc6fa7 --- /dev/null +++ b/firmware/application/src/rfid/reader/lf/protocols/lfrfid_protocols.c @@ -0,0 +1,45 @@ +#include +#include "lfrfid_protocols.h" +#include "protocol_em4100.h" +/*#include "protocol_h10301.h" +#include "protocol_idteck.h" +#include "protocol_indala26.h" +#include "protocol_io_prox_xsf.h" +#include "protocol_awid.h" +#include "protocol_fdx_a.h" +#include "protocol_fdx_b.h" +#include "protocol_hid_generic.h" +#include "protocol_hid_ex_generic.h" +#include "protocol_pyramid.h" +#include "protocol_viking.h" +#include "protocol_jablotron.h" +#include "protocol_paradox.h" +#include "protocol_pac_stanley.h" +#include "protocol_keri.h" +#include "protocol_gallagher.h" +#include "protocol_nexwatch.h"*/ + +const ProtocolBase* lfrfid_protocols[] = { + [LFRFIDProtocolEM4100] = &protocol_em4100, + [LFRFIDProtocolEM410032] = &protocol_em4100_32, + [LFRFIDProtocolEM410016] = &protocol_em4100_16, +/* [LFRFIDProtocolH10301] = &protocol_h10301, + [LFRFIDProtocolIdteck] = &protocol_idteck, + [LFRFIDProtocolIndala26] = &protocol_indala26, + [LFRFIDProtocolIOProxXSF] = &protocol_io_prox_xsf, + [LFRFIDProtocolAwid] = &protocol_awid, + [LFRFIDProtocolFDXA] = &protocol_fdx_a, + [LFRFIDProtocolFDXB] = &protocol_fdx_b, + [LFRFIDProtocolHidGeneric] = &protocol_hid_generic, + [LFRFIDProtocolHidExGeneric] = &protocol_hid_ex_generic, + [LFRFIDProtocolPyramid] = &protocol_pyramid, + [LFRFIDProtocolViking] = &protocol_viking, + [LFRFIDProtocolJablotron] = &protocol_jablotron, + [LFRFIDProtocolParadox] = &protocol_paradox, + [LFRFIDProtocolPACStanley] = &protocol_pac_stanley, + [LFRFIDProtocolKeri] = &protocol_keri, + [LFRFIDProtocolGallagher] = &protocol_gallagher, + [LFRFIDProtocolNexwatch] = &protocol_nexwatch,*/ +}; + +size_t lfrfid_protocols_size = ARRAY_SIZE(lfrfid_protocols); diff --git a/firmware/application/src/rfid/reader/lf/protocols/lfrfid_protocols.h b/firmware/application/src/rfid/reader/lf/protocols/lfrfid_protocols.h new file mode 100644 index 00000000..51c88b59 --- /dev/null +++ b/firmware/application/src/rfid/reader/lf/protocols/lfrfid_protocols.h @@ -0,0 +1,46 @@ +#pragma once +#include "protocol.h" +#include "utils/t5577.h" + +typedef enum { + LFRFIDFeatureASK = 1 << 0, /** ASK Demodulation */ + LFRFIDFeaturePSK = 1 << 1, /** PSK Demodulation */ +} LFRFIDFeature; + +typedef enum { + LFRFIDProtocolEM4100, + LFRFIDProtocolEM410032, + LFRFIDProtocolEM410016, + LFRFIDProtocolH10301, + LFRFIDProtocolIdteck, + LFRFIDProtocolIndala26, + LFRFIDProtocolIOProxXSF, + LFRFIDProtocolAwid, + LFRFIDProtocolFDXA, + LFRFIDProtocolFDXB, + LFRFIDProtocolHidGeneric, + LFRFIDProtocolHidExGeneric, + LFRFIDProtocolPyramid, + LFRFIDProtocolViking, + LFRFIDProtocolJablotron, + LFRFIDProtocolParadox, + LFRFIDProtocolPACStanley, + LFRFIDProtocolKeri, + LFRFIDProtocolGallagher, + LFRFIDProtocolNexwatch, + LFRFIDProtocolMax, +} LFRFIDProtocol; + +extern const ProtocolBase* lfrfid_protocols[]; +extern size_t lfrfid_protocols_size; + +typedef enum { + LFRFIDWriteTypeT5577, +} LFRFIDWriteType; + +typedef struct { + LFRFIDWriteType write_type; + union { + LFRFIDT5577 t5577; + }; +} LFRFIDWriteRequest; diff --git a/firmware/application/src/rfid/reader/lf/protocols/protocol.h b/firmware/application/src/rfid/reader/lf/protocols/protocol.h new file mode 100644 index 00000000..0e3cf84c --- /dev/null +++ b/firmware/application/src/rfid/reader/lf/protocols/protocol.h @@ -0,0 +1,48 @@ +#pragma once +#include +#include +#include +#include +#include + +typedef void* (*ProtocolAlloc)(void); +typedef void (*ProtocolFree)(void* protocol); +typedef uint8_t* (*ProtocolGetData)(void* protocol); + +typedef void (*ProtocolDecoderDecode)(void* protocol, uint8_t* data, size_t datalen); +typedef void (*ProtocolDecoderStart)(void* protocol); +typedef bool (*ProtocolDecoderFeed)(void* protocol, bool level, uint32_t duration); + +typedef bool (*ProtocolEncoderStart)(void* protocol); +typedef LevelDuration (*ProtocolEncoderYield)(void* protocol); + +typedef void (*ProtocolRenderData)(void* protocol, String* result); +typedef bool (*ProtocolWriteData)(void* protocol, void* data); + +typedef struct { + ProtocolDecoderDecode decode; + ProtocolDecoderStart start; + ProtocolDecoderFeed feed; +} ProtocolDecoder; + +typedef struct { + ProtocolEncoderStart start; + ProtocolEncoderYield yield; +} ProtocolEncoder; + +typedef struct { + const size_t data_size; + const char* name; + const char* manufacturer; + const uint32_t features; + const uint8_t validate_count; + + ProtocolAlloc alloc; + ProtocolFree free; + ProtocolGetData get_data; + ProtocolDecoder decoder; + ProtocolEncoder encoder; + ProtocolRenderData render_data; + ProtocolRenderData render_brief_data; + ProtocolWriteData write_data; +} ProtocolBase; \ No newline at end of file diff --git a/firmware/application/src/rfid/reader/lf/protocols/protocol_em4100.c b/firmware/application/src/rfid/reader/lf/protocols/protocol_em4100.c new file mode 100644 index 00000000..06860e73 --- /dev/null +++ b/firmware/application/src/rfid/reader/lf/protocols/protocol_em4100.c @@ -0,0 +1,546 @@ +#include +#include +#include +#include +#include +#include "lfrfid_protocols.h" + +typedef uint64_t EM4100DecodedData; + +#define EM_HEADER_POS (55) +#define EM_HEADER_MASK (0x1FFLLU << EM_HEADER_POS) + +#define EM_FIRST_ROW_POS (50) + +#define EM_ROW_COUNT (10) +#define EM_COLUMN_COUNT (4) +#define EM_BITS_PER_ROW_COUNT (EM_COLUMN_COUNT + 1) + +#define EM_COLUMN_POS (4) +#define EM_STOP_POS (0) +#define EM_STOP_MASK (0x1LLU << EM_STOP_POS) + +#define EM_HEADER_AND_STOP_MASK (EM_HEADER_MASK | EM_STOP_MASK) +#define EM_HEADER_AND_STOP_DATA (EM_HEADER_MASK) + +#define EM4100_DECODED_DATA_SIZE (5) +#define EM4100_ENCODED_DATA_SIZE (sizeof(EM4100DecodedData)) + +#define EM4100_RAW_DATA_SIZE (50) + +#define EM_READ_TIME1_BASE (0x40) +#define EM_READ_TIME2_BASE (0x60) +#define EM_READ_TIME3_BASE (0x80) +#define EM_READ_JITTER_TIME_BASE (0x10) + +#define NRF_LOG_MODULE_NAME em4100 +#include "nrf_log.h" +#include "nrf_log_ctrl.h" +#include "nrf_log_default_backends.h" +NRF_LOG_MODULE_REGISTER(); + +typedef struct { + + uint8_t data[EM4100_DECODED_DATA_SIZE]; + EM4100DecodedData encoded_data; + uint8_t encoded_data_index; + bool encoded_polarity; + + ManchesterState decoder_manchester_state; + uint8_t clock_per_bit; +} ProtocolEM4100; + +uint16_t protocol_em4100_get_time_divisor(ProtocolEM4100* proto) { + switch(proto->clock_per_bit) { + case 64: + return 1; + case 32: + return 2; + case 16: + return 4; + default: + return 1; + } +} + +uint32_t protocol_em4100_get_t5577_bitrate(ProtocolEM4100* proto) { + switch(proto->clock_per_bit) { + case 64: + return LFRFID_T5577_BITRATE_RF_64; + case 32: + return LFRFID_T5577_BITRATE_RF_32; + case 16: + return LFRFID_T5577_BITRATE_RF_16; + default: + return LFRFID_T5577_BITRATE_RF_64; + } +} + +uint8_t protocol_em4100_get_time1_low(ProtocolEM4100* proto) { + return EM_READ_TIME1_BASE / protocol_em4100_get_time_divisor(proto) - + EM_READ_JITTER_TIME_BASE / protocol_em4100_get_time_divisor(proto); +} + +uint8_t protocol_em4100_get_time1_high(ProtocolEM4100* proto) { + return EM_READ_TIME1_BASE / protocol_em4100_get_time_divisor(proto) + + EM_READ_JITTER_TIME_BASE / protocol_em4100_get_time_divisor(proto); +} + +bool protocol_em4100_get_time1(ProtocolEM4100* proto, uint8_t interval) { + return + interval >= protocol_em4100_get_time1_low(proto) && + interval <= protocol_em4100_get_time1_high(proto); +} + +uint8_t protocol_em4100_get_time2_low(ProtocolEM4100* proto) { + return EM_READ_TIME2_BASE / protocol_em4100_get_time_divisor(proto) - + EM_READ_JITTER_TIME_BASE / protocol_em4100_get_time_divisor(proto); +} + +uint8_t protocol_em4100_get_time2_high(ProtocolEM4100* proto) { + return EM_READ_TIME2_BASE / protocol_em4100_get_time_divisor(proto) + + EM_READ_JITTER_TIME_BASE / protocol_em4100_get_time_divisor(proto); +} + +bool protocol_em4100_get_time2(ProtocolEM4100* proto, uint8_t interval) { + return + interval >= protocol_em4100_get_time2_low(proto) && + interval <= protocol_em4100_get_time2_high(proto); +} + +uint8_t protocol_em4100_get_time3_low(ProtocolEM4100* proto) { + return EM_READ_TIME3_BASE / protocol_em4100_get_time_divisor(proto) - + EM_READ_JITTER_TIME_BASE / protocol_em4100_get_time_divisor(proto); +} + +uint8_t protocol_em4100_get_time3_high(ProtocolEM4100* proto) { + return EM_READ_TIME3_BASE / protocol_em4100_get_time_divisor(proto) + + EM_READ_JITTER_TIME_BASE / protocol_em4100_get_time_divisor(proto); +} + +bool protocol_em4100_get_time3(ProtocolEM4100* proto, uint8_t interval) { + return + interval >= protocol_em4100_get_time3_low(proto) && + interval <= protocol_em4100_get_time3_high(proto); +} + +ProtocolEM4100* protocol_em4100_alloc(void) { + ProtocolEM4100* proto = malloc(sizeof(ProtocolEM4100)); + proto->clock_per_bit = 64; + return (void*)proto; +}; + +ProtocolEM4100* protocol_em4100_16_alloc(void) { + ProtocolEM4100* proto = malloc(sizeof(ProtocolEM4100)); + proto->clock_per_bit = 16; + return (void*)proto; +}; + +ProtocolEM4100* protocol_em4100_32_alloc(void) { + ProtocolEM4100* proto = malloc(sizeof(ProtocolEM4100)); + proto->clock_per_bit = 32; + return (void*)proto; +}; + +void protocol_em4100_free(ProtocolEM4100* proto) { + free(proto); +}; + +uint8_t* protocol_em4100_get_data(ProtocolEM4100* proto) { + return proto->data; +}; + +static void em4100_decode( + const uint8_t* encoded_data, + const uint8_t encoded_data_size, + uint8_t* decoded_data, + const uint8_t decoded_data_size) { + if (decoded_data_size >= EM4100_DECODED_DATA_SIZE || + encoded_data_size >= EM4100_ENCODED_DATA_SIZE) + return; + + uint8_t decoded_data_index = 0; + EM4100DecodedData card_data = *((EM4100DecodedData*)(encoded_data)); + + // clean result + memset(decoded_data, 0, decoded_data_size); + + // header + for(uint8_t i = 0; i < 9; i++) { + card_data = card_data << 1; + } + + // nibbles + uint8_t value = 0; + for(uint8_t r = 0; r < EM_ROW_COUNT; r++) { + uint8_t nibble = 0; + for(uint8_t i = 0; i < 5; i++) { + if(i < 4) nibble = (nibble << 1) | (card_data & (1LLU << 63) ? 1 : 0); + card_data = card_data << 1; + } + value = (value << 4) | nibble; + if(r % 2) { + decoded_data[decoded_data_index] |= value; + decoded_data_index++; + value = 0; + } + } +} + +/*static bool em4100_can_be_decoded(const uint8_t* encoded_data, const uint8_t encoded_data_size) { + if (encoded_data_size >= EM4100_ENCODED_DATA_SIZE) + return false; + const EM4100DecodedData* card_data = (EM4100DecodedData*)encoded_data; + + // check header and stop bit + if((*card_data & EM_HEADER_AND_STOP_MASK) != EM_HEADER_AND_STOP_DATA) return false; + + // check row parity + for(uint8_t i = 0; i < EM_ROW_COUNT; i++) { + uint8_t parity_sum = 0; + + for(uint8_t j = 0; j < EM_BITS_PER_ROW_COUNT; j++) { + parity_sum += (*card_data >> (EM_FIRST_ROW_POS - i * EM_BITS_PER_ROW_COUNT + j)) & 1; + } + + if((parity_sum % 2)) { + return false; + } + } + + // check columns parity + for(uint8_t i = 0; i < EM_COLUMN_COUNT; i++) { + uint8_t parity_sum = 0; + + for(uint8_t j = 0; j < EM_ROW_COUNT + 1; j++) { + parity_sum += (*card_data >> (EM_COLUMN_POS - i + j * EM_BITS_PER_ROW_COUNT)) & 1; + } + + if((parity_sum % 2)) { + return false; + } + } + + return true; +}*/ + +void protocol_em4100_decoder_start(ProtocolEM4100* proto) { + memset(proto->data, 0, EM4100_DECODED_DATA_SIZE); + proto->encoded_data = 0; +/* manchester_advance( + proto->decoder_manchester_state, + ManchesterEventReset, + &proto->decoder_manchester_state, + NULL); */ +}; + +bool protocol_em4100_decoder_feed(ProtocolEM4100* proto, bool level, uint32_t duration) { + bool result = false; + + /* ManchesterEvent event = ManchesterEventReset; + + if(duration > protocol_em4100_get_short_time_low(proto) && + duration < protocol_em4100_get_short_time_high(proto)) { + if(!level) { + event = ManchesterEventShortHigh; + } else { + event = ManchesterEventShortLow; + } + } else if( + duration > protocol_em4100_get_long_time_low(proto) && + duration < protocol_em4100_get_long_time_high(proto)) { + if(!level) { + event = ManchesterEventLongHigh; + } else { + event = ManchesterEventLongLow; + } + } +*/ + /* if(event != ManchesterEventReset) { + bool data; + bool data_ok = manchester_advance( + proto->decoder_manchester_state, event, &proto->decoder_manchester_state, &data); + + if(data_ok) { + proto->encoded_data = (proto->encoded_data << 1) | data; + + if(em4100_can_be_decoded((uint8_t*)&proto->encoded_data, sizeof(EM4100DecodedData))) { + em4100_decode( + (uint8_t*)&proto->encoded_data, + sizeof(EM4100DecodedData), + proto->data, + EM4100_DECODED_DATA_SIZE); + result = true; + } + } + } +*/ + return result; +}; + +uint8_t read_bit_interval(ProtocolEM4100* proto, uint8_t interval) { + if (protocol_em4100_get_time1(proto, interval)) + return 1; + + if (protocol_em4100_get_time2(proto, interval)) + return 2; + + if (protocol_em4100_get_time3(proto, interval)) + return 3; + + return 0; +} + + +uint8_t decode(ProtocolEM4100* proto, uint8_t* data, size_t datalen) { + BitBuffer* bit_buffer = bit_buffer_alloc(EM4100_RAW_DATA_SIZE); + + uint8_t sync = 1; //After the current interval process is processed, is it on the judgment line + uint8_t cardindex = 0; //Record change number + bool error = false; + for (int i = 0; i < datalen; i++) { + uint8_t bit_interval = read_bit_interval(proto, data[i]); + + NRF_LOG_INFO("-->[%d] %x %d", protocol_em4100_get_time_divisor(proto), data[i], bit_interval); + + if (bit_interval == 0) { + bit_buffer_reset(bit_buffer); + cardindex = 0; + continue; + } + + switch (sync) { + case 1: //Synchronous state + switch (bit_interval) { + case 0: //TheSynchronousState1T,Add1Digit0,StillSynchronize + bit_buffer_append_bit(bit_buffer, 0); + cardindex++; + break; + case 1: // Synchronous status 1.5T, add 1 digit 1, switch to non -synchronized state + bit_buffer_append_bit(bit_buffer, 1); + cardindex++; + sync = 0; + break; + case 2: //Synchronous2T,Add2Digits10,StillSynchronize + bit_buffer_append_bit(bit_buffer, 1); + cardindex++; + bit_buffer_append_bit(bit_buffer, 0); + cardindex++; + break; + default: + error = true; + break; + } + break; + case 0: //Non -synchronous state + switch (bit_interval) { + case 0: //1TInNonSynchronousState,Add1Digit1,StillNonSynchronous + bit_buffer_append_bit(bit_buffer, 1); + cardindex++; + break; + case 1: // In non -synchronous status 1.5T, add 2 digits 10, switch to the synchronous state + bit_buffer_append_bit(bit_buffer, 1); + cardindex++; + bit_buffer_append_bit(bit_buffer, 0); + cardindex++; + sync = 1; + break; + case 2: //The2TOfTheNonSynchronousState,ItIsImpossibleToOccur,ReportAnError + error = true; + break; + default: + error = true; + break; + } + break; + } + if (bit_buffer_get_size(bit_buffer) >= EM4100_RAW_DATA_SIZE * 8 || error) + break; + } + + bit_buffer_dump(bit_buffer); + + bit_buffer_free(bit_buffer); + + return 1; +} + +void protocol_em4100_decoder_decode(ProtocolEM4100* proto, uint8_t* data, size_t datalen) { + protocol_em4100_decoder_start(proto); + + decode(proto, data, datalen); +} + +static void em4100_write_nibble(bool low_nibble, uint8_t data, EM4100DecodedData* encoded_data) { + uint8_t parity_sum = 0; + uint8_t start = 0; + if(!low_nibble) start = 4; + + for(int8_t i = (start + 3); i >= start; i--) { + parity_sum += (data >> i) & 1; + *encoded_data = (*encoded_data << 1) | ((data >> i) & 1); + } + + *encoded_data = (*encoded_data << 1) | ((parity_sum % 2) & 1); +} + +bool protocol_em4100_encoder_start(ProtocolEM4100* proto) { + // header + proto->encoded_data = 0b111111111; + + // data + for(uint8_t i = 0; i < EM4100_DECODED_DATA_SIZE; i++) { + em4100_write_nibble(false, proto->data[i], &proto->encoded_data); + em4100_write_nibble(true, proto->data[i], &proto->encoded_data); + } + + // column parity and stop bit + uint8_t parity_sum; + + for(uint8_t c = 0; c < EM_COLUMN_COUNT; c++) { + parity_sum = 0; + for(uint8_t i = 1; i <= EM_ROW_COUNT; i++) { + uint8_t parity_bit = (proto->encoded_data >> (i * EM_BITS_PER_ROW_COUNT - 1)) & 1; + parity_sum += parity_bit; + } + proto->encoded_data = (proto->encoded_data << 1) | ((parity_sum % 2) & 1); + } + + // stop bit + proto->encoded_data = (proto->encoded_data << 1) | 0; + + proto->encoded_data_index = 0; + proto->encoded_polarity = true; + + return true; +}; + +LevelDuration protocol_em4100_encoder_yield(ProtocolEM4100* proto) { + bool level = (proto->encoded_data >> (63 - proto->encoded_data_index)) & 1; + uint32_t duration = proto->clock_per_bit / 2; + + if(proto->encoded_polarity) { + proto->encoded_polarity = false; + } else { + level = !level; + + proto->encoded_polarity = true; + proto->encoded_data_index++; + if(proto->encoded_data_index >= 64) { + proto->encoded_data_index = 0; + } + } + + return level_duration_make(level, duration); +}; + +bool protocol_em4100_write_data(ProtocolEM4100* protocol, void* data) { + LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data; + bool result = false; + + // Correct protocol data by redecoding + protocol_em4100_encoder_start(protocol); + em4100_decode( + (uint8_t*)&protocol->encoded_data, + sizeof(EM4100DecodedData), + protocol->data, + EM4100_DECODED_DATA_SIZE); + + protocol_em4100_encoder_start(protocol); + + if(request->write_type == LFRFIDWriteTypeT5577) { + request->t5577.block[0] = + (LFRFID_T5577_MODULATION_MANCHESTER | protocol_em4100_get_t5577_bitrate(protocol) | + (2 << LFRFID_T5577_MAXBLOCK_SHIFT)); + request->t5577.block[1] = protocol->encoded_data; + request->t5577.block[2] = protocol->encoded_data >> 32; + request->t5577.blocks_to_write = 3; + result = true; + } + return result; +}; + +void protocol_em4100_render_data(ProtocolEM4100* protocol, String* result) { + uint8_t* data = protocol->data; + stringprintf( + result, + "FC: %03u, Card: %05u (RF/%u)", + data[2], + (uint16_t)((data[3] << 8) | (data[4])), + protocol->clock_per_bit); +}; + +const ProtocolBase protocol_em4100 = { + .name = "EM4100/64(std)", + .manufacturer = "EM-Micro", + .data_size = EM4100_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK | LFRFIDFeaturePSK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_em4100_alloc, + .free = (ProtocolFree)protocol_em4100_free, + .get_data = (ProtocolGetData)protocol_em4100_get_data, + .decoder = + { + .decode = (ProtocolDecoderDecode)protocol_em4100_decoder_decode, + .start = (ProtocolDecoderStart)protocol_em4100_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_em4100_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_em4100_encoder_start, + .yield = (ProtocolEncoderYield)protocol_em4100_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_em4100_render_data, + .render_brief_data = (ProtocolRenderData)protocol_em4100_render_data, + .write_data = (ProtocolWriteData)protocol_em4100_write_data, +}; + +const ProtocolBase protocol_em4100_32 = { + .name = "EM4100/32", + .manufacturer = "EM-Micro", + .data_size = EM4100_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK | LFRFIDFeaturePSK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_em4100_32_alloc, + .free = (ProtocolFree)protocol_em4100_free, + .get_data = (ProtocolGetData)protocol_em4100_get_data, + .decoder = + { + .decode = (ProtocolDecoderDecode)protocol_em4100_decoder_decode, + .start = (ProtocolDecoderStart)protocol_em4100_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_em4100_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_em4100_encoder_start, + .yield = (ProtocolEncoderYield)protocol_em4100_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_em4100_render_data, + .render_brief_data = (ProtocolRenderData)protocol_em4100_render_data, + .write_data = (ProtocolWriteData)protocol_em4100_write_data, +}; + +const ProtocolBase protocol_em4100_16 = { + .name = "EM4100/16", + .manufacturer = "EM-Micro", + .data_size = EM4100_DECODED_DATA_SIZE, + .features = LFRFIDFeatureASK | LFRFIDFeaturePSK, + .validate_count = 3, + .alloc = (ProtocolAlloc)protocol_em4100_16_alloc, + .free = (ProtocolFree)protocol_em4100_free, + .get_data = (ProtocolGetData)protocol_em4100_get_data, + .decoder = + { + .decode = (ProtocolDecoderDecode)protocol_em4100_decoder_decode, + .start = (ProtocolDecoderStart)protocol_em4100_decoder_start, + .feed = (ProtocolDecoderFeed)protocol_em4100_decoder_feed, + }, + .encoder = + { + .start = (ProtocolEncoderStart)protocol_em4100_encoder_start, + .yield = (ProtocolEncoderYield)protocol_em4100_encoder_yield, + }, + .render_data = (ProtocolRenderData)protocol_em4100_render_data, + .render_brief_data = (ProtocolRenderData)protocol_em4100_render_data, + .write_data = (ProtocolWriteData)protocol_em4100_write_data, +}; diff --git a/firmware/application/src/rfid/reader/lf/protocols/protocol_em4100.h b/firmware/application/src/rfid/reader/lf/protocols/protocol_em4100.h new file mode 100644 index 00000000..02129e25 --- /dev/null +++ b/firmware/application/src/rfid/reader/lf/protocols/protocol_em4100.h @@ -0,0 +1,8 @@ +#pragma once +#include + +extern const ProtocolBase protocol_em4100; + +extern const ProtocolBase protocol_em4100_32; + +extern const ProtocolBase protocol_em4100_16; diff --git a/firmware/application/src/rfid/reader/lf/utils/bit_buffer.c b/firmware/application/src/rfid/reader/lf/utils/bit_buffer.c new file mode 100644 index 00000000..2f318499 --- /dev/null +++ b/firmware/application/src/rfid/reader/lf/utils/bit_buffer.c @@ -0,0 +1,376 @@ +#include "bit_buffer.h" + +#include + +#define BITS_IN_BYTE (8) + +#define NRF_LOG_MODULE_NAME bit_buffer +#include "nrf_log.h" +#include "nrf_log_ctrl.h" +#include "nrf_log_default_backends.h" +NRF_LOG_MODULE_REGISTER(); + +struct BitBuffer { + uint8_t* data; + uint8_t* parity; + size_t capacity_bytes; + size_t size_bits; +}; + +#define x_assert(x) if((x) == 0) return; + +#ifndef X_BIT +#define X_BIT(x, n) (((x) >> (n)) & 1) +#endif + +#ifndef X_BIT_SET +#define X_BIT_SET(x, n) \ + ({ \ + __typeof__(x) _x = (1); \ + (x) |= (_x << (n)); \ + }) +#endif + +#ifndef X_BIT_CLEAR +#define X_BIT_CLEAR(x, n) ((x) &= ~(1 << (n))) +#endif + + +BitBuffer* bit_buffer_alloc(size_t capacity_bytes) { + if (capacity_bytes == 0) + return NULL; + + BitBuffer* buf = malloc(sizeof(BitBuffer)); + + buf->data = malloc(capacity_bytes); + size_t parity_buf_size = (capacity_bytes + BITS_IN_BYTE - 1) / BITS_IN_BYTE; + buf->parity = malloc(parity_buf_size); + buf->capacity_bytes = capacity_bytes; + buf->size_bits = 0; + + bit_buffer_reset(buf); + + return buf; +} + +void bit_buffer_free(BitBuffer* buf) { + x_assert(buf); + + free(buf->data); + free(buf->parity); + free(buf); +} + +void bit_buffer_reset(BitBuffer* buf) { + x_assert(buf); + + memset(buf->data, 0, buf->capacity_bytes); + size_t parity_buf_size = (buf->capacity_bytes + BITS_IN_BYTE - 1) / BITS_IN_BYTE; + memset(buf->parity, 0, parity_buf_size); + buf->size_bits = 0; +} + +void bit_buffer_copy(BitBuffer* buf, const BitBuffer* other) { + x_assert(buf); + x_assert(other); + + if(buf == other) return; + + x_assert(buf->capacity_bytes * BITS_IN_BYTE >= other->size_bits); + + memcpy(buf->data, other->data, bit_buffer_get_size_bytes(other)); + buf->size_bits = other->size_bits; +} + +void bit_buffer_copy_right(BitBuffer* buf, const BitBuffer* other, size_t start_index) { + x_assert(buf); + x_assert(other); + x_assert(bit_buffer_get_size_bytes(other) > start_index); + x_assert(buf->capacity_bytes >= bit_buffer_get_size_bytes(other) - start_index); + + memcpy(buf->data, other->data + start_index, bit_buffer_get_size_bytes(other) - start_index); + buf->size_bits = other->size_bits - start_index * BITS_IN_BYTE; +} + +void bit_buffer_copy_left(BitBuffer* buf, const BitBuffer* other, size_t end_index) { + x_assert(buf); + x_assert(other); + x_assert(bit_buffer_get_capacity_bytes(buf) >= end_index); + x_assert(bit_buffer_get_size_bytes(other) >= end_index); + + memcpy(buf->data, other->data, end_index); + buf->size_bits = end_index * BITS_IN_BYTE; +} + +void bit_buffer_copy_bytes(BitBuffer* buf, const uint8_t* data, size_t size_bytes) { + x_assert(buf); + x_assert(data); + x_assert(buf->capacity_bytes >= size_bytes); + + memcpy(buf->data, data, size_bytes); + buf->size_bits = size_bytes * BITS_IN_BYTE; +} + +void bit_buffer_copy_bits(BitBuffer* buf, const uint8_t* data, size_t size_bits) { + x_assert(buf); + x_assert(data); + x_assert(buf->capacity_bytes * BITS_IN_BYTE >= size_bits); + + size_t size_bytes = (size_bits + BITS_IN_BYTE - 1) / BITS_IN_BYTE; + memcpy(buf->data, data, size_bytes); + buf->size_bits = size_bits; +} + +void bit_buffer_copy_bytes_with_parity(BitBuffer* buf, const uint8_t* data, size_t size_bits) { + x_assert(buf); + x_assert(data); + + size_t bits_processed = 0; + size_t curr_byte = 0; + + if(size_bits < BITS_IN_BYTE + 1) { + buf->size_bits = size_bits; + buf->data[0] = data[0]; + } else { + x_assert(size_bits % (BITS_IN_BYTE + 1) == 0); + while(bits_processed < size_bits) { + buf->data[curr_byte] = data[bits_processed / BITS_IN_BYTE] >> + (bits_processed % BITS_IN_BYTE); + buf->data[curr_byte] |= data[bits_processed / BITS_IN_BYTE + 1] + << (BITS_IN_BYTE - bits_processed % BITS_IN_BYTE); + uint8_t bit = + X_BIT(data[bits_processed / BITS_IN_BYTE + 1], bits_processed % BITS_IN_BYTE); + + if(bits_processed % BITS_IN_BYTE) { + buf->parity[curr_byte / BITS_IN_BYTE] = bit; + } else { + buf->parity[curr_byte / BITS_IN_BYTE] |= bit << (bits_processed % BITS_IN_BYTE); + } + bits_processed += BITS_IN_BYTE + 1; + curr_byte++; + } + buf->size_bits = curr_byte * BITS_IN_BYTE; + } +} + +void bit_buffer_write_bytes(const BitBuffer* buf, void* dest, size_t size_bytes) { + x_assert(buf); + x_assert(dest); + x_assert(bit_buffer_get_size_bytes(buf) <= size_bytes); + + memcpy(dest, buf->data, bit_buffer_get_size_bytes(buf)); +} + +void bit_buffer_write_bytes_with_parity( + const BitBuffer* buf, + void* dest, + size_t size_bytes, + size_t* bits_written) { + x_assert(buf); + x_assert(dest); + x_assert(bits_written); + + size_t buf_size_bytes = bit_buffer_get_size_bytes(buf); + size_t buf_size_with_parity_bytes = + (buf_size_bytes * (BITS_IN_BYTE + 1) + BITS_IN_BYTE) / BITS_IN_BYTE; + x_assert(buf_size_with_parity_bytes <= size_bytes); + + uint8_t next_par_bit = 0; + uint16_t curr_bit_pos = 0; + uint8_t* bitstream = dest; + + for(size_t i = 0; i < buf_size_bytes; i++) { + next_par_bit = X_BIT(buf->parity[i / BITS_IN_BYTE], i % BITS_IN_BYTE); + if(curr_bit_pos % BITS_IN_BYTE == 0) { + bitstream[curr_bit_pos / BITS_IN_BYTE] = buf->data[i]; + curr_bit_pos += BITS_IN_BYTE; + bitstream[curr_bit_pos / BITS_IN_BYTE] = next_par_bit; + curr_bit_pos++; + } else { + bitstream[curr_bit_pos / BITS_IN_BYTE] |= buf->data[i] + << (curr_bit_pos % BITS_IN_BYTE); + bitstream[curr_bit_pos / BITS_IN_BYTE + 1] = + buf->data[i] >> (BITS_IN_BYTE - curr_bit_pos % BITS_IN_BYTE); + bitstream[curr_bit_pos / BITS_IN_BYTE + 1] |= next_par_bit + << (curr_bit_pos % BITS_IN_BYTE); + curr_bit_pos += BITS_IN_BYTE + 1; + } + } + + *bits_written = curr_bit_pos; +} + +void bit_buffer_write_bytes_mid( + const BitBuffer* buf, + void* dest, + size_t start_index, + size_t size_bytes) { + x_assert(buf); + x_assert(dest); + x_assert(start_index + size_bytes <= bit_buffer_get_size_bytes(buf)); + + memcpy(dest, buf->data + start_index, size_bytes); +} + +bool bit_buffer_has_partial_byte(const BitBuffer* buf) { + if (buf == NULL) + return false; + + return (buf->size_bits % BITS_IN_BYTE) != 0; +} + +bool bit_buffer_starts_with_byte(const BitBuffer* buf, uint8_t byte) { + if (buf == NULL) + return false; + + return bit_buffer_get_size_bytes(buf) && (buf->data[0] == byte); +} + +size_t bit_buffer_get_capacity_bytes(const BitBuffer* buf) { + if (buf == NULL) + return 0; + + return buf->capacity_bytes; +} + +size_t bit_buffer_get_size(const BitBuffer* buf) { + if (buf == NULL) + return 0; + + return buf->size_bits; +} + +size_t bit_buffer_get_size_bytes(const BitBuffer* buf) { + if (buf == NULL) + return 0; + + return (buf->size_bits / BITS_IN_BYTE) + (buf->size_bits % BITS_IN_BYTE ? 1 : 0); +} + +uint8_t bit_buffer_get_byte(const BitBuffer* buf, size_t index) { + if (buf == NULL || buf->capacity_bytes > index) + return 0; + + return buf->data[index]; +} + +uint8_t bit_buffer_get_byte_from_bit(const BitBuffer* buf, size_t index_bits) { + if (buf == NULL || buf->capacity_bytes * BITS_IN_BYTE > index_bits) + return 0; + + const size_t byte_index = index_bits / BITS_IN_BYTE; + const size_t bit_offset = index_bits % BITS_IN_BYTE; + + const uint8_t lo = buf->data[byte_index] >> bit_offset; + const uint8_t hi = buf->data[byte_index + 1] << (BITS_IN_BYTE - bit_offset); + + return lo | hi; +} + +const uint8_t* bit_buffer_get_data(const BitBuffer* buf) { + if (buf == NULL) + return NULL; + + return buf->data; +} + +const uint8_t* bit_buffer_get_parity(const BitBuffer* buf) { + if (buf == NULL) + return NULL; + + return buf->parity; +} + +void bit_buffer_set_byte(BitBuffer* buf, size_t index, uint8_t byte) { + x_assert(buf); + + const size_t size_bytes = bit_buffer_get_size_bytes(buf); + x_assert(size_bytes > index); + + buf->data[index] = byte; +} + +void bit_buffer_set_byte_with_parity(BitBuffer* buff, size_t index, uint8_t byte, bool parity) { + x_assert(buff); + x_assert(buff->size_bits / BITS_IN_BYTE > index); + + buff->data[index] = byte; + if((index % BITS_IN_BYTE) == 0) { + buff->parity[index / BITS_IN_BYTE] = parity; + } else { + buff->parity[index / BITS_IN_BYTE] |= parity << (index % BITS_IN_BYTE); + } +} + +void bit_buffer_set_size(BitBuffer* buf, size_t new_size) { + x_assert(buf); + x_assert(buf->capacity_bytes * BITS_IN_BYTE >= new_size); + + buf->size_bits = new_size; +} + +void bit_buffer_set_size_bytes(BitBuffer* buf, size_t new_size_bytes) { + x_assert(buf); + x_assert(buf->capacity_bytes >= new_size_bytes); + + buf->size_bits = new_size_bytes * BITS_IN_BYTE; +} + +void bit_buffer_append(BitBuffer* buf, const BitBuffer* other) { + bit_buffer_append_right(buf, other, 0); +} + +void bit_buffer_append_right(BitBuffer* buf, const BitBuffer* other, size_t start_index) { + x_assert(buf); + x_assert(other); + + const size_t size_bytes = bit_buffer_get_size_bytes(buf); + const size_t other_size_bytes = bit_buffer_get_size_bytes(other) - start_index; + + x_assert(buf->capacity_bytes >= size_bytes + other_size_bytes); + + memcpy(buf->data + size_bytes, other->data + start_index, other_size_bytes); + buf->size_bits += other->size_bits - start_index * BITS_IN_BYTE; +} + +void bit_buffer_append_byte(BitBuffer* buf, uint8_t byte) { + x_assert(buf); + + const size_t data_size_bytes = bit_buffer_get_size_bytes(buf); + const size_t new_data_size_bytes = data_size_bytes + 1; + x_assert(new_data_size_bytes <= buf->capacity_bytes); + + buf->data[data_size_bytes] = byte; + buf->size_bits = new_data_size_bytes * BITS_IN_BYTE; +} + +void bit_buffer_append_bytes(BitBuffer* buf, const uint8_t* data, size_t size_bytes) { + x_assert(buf); + x_assert(data); + + const size_t buf_size_bytes = bit_buffer_get_size_bytes(buf); + x_assert(buf->capacity_bytes >= buf_size_bytes + size_bytes); + + memcpy(&buf->data[buf_size_bytes], data, size_bytes); + buf->size_bits += size_bytes * BITS_IN_BYTE; +} + +void bit_buffer_append_bit(BitBuffer* buf, bool bit) { + x_assert(buf); + x_assert( + bit_buffer_get_size_bytes(buf) <= + (buf->capacity_bytes - (bit_buffer_has_partial_byte(buf) ? 0 : 1))); + + if(bit) { + const size_t byte_index = buf->size_bits / BITS_IN_BYTE; + const size_t bit_offset = (buf->size_bits % BITS_IN_BYTE); + buf->data[byte_index] |= 1U << bit_offset; + } + + buf->size_bits++; +} + +void bit_buffer_dump(BitBuffer* buf) { + NRF_LOG_INFO("--> bit buffer len: %d bits", buf->size_bits); + NRF_LOG_HEXDUMP_INFO(buf->data, bit_buffer_get_size_bytes(buf)); +} diff --git a/firmware/application/src/rfid/reader/lf/utils/bit_buffer.h b/firmware/application/src/rfid/reader/lf/utils/bit_buffer.h new file mode 100644 index 00000000..67fff22f --- /dev/null +++ b/firmware/application/src/rfid/reader/lf/utils/bit_buffer.h @@ -0,0 +1,328 @@ +#pragma once + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct BitBuffer BitBuffer; + +// Construction, deletion, reset + +/** + * Allocate a BitBuffer instance. + * + * @param [in] capacity_bytes maximum buffer capacity, in bytes + * @return pointer to the allocated BitBuffer instance + */ +BitBuffer* bit_buffer_alloc(size_t capacity_bytes); + +/** + * Delete a BitBuffer instance. + * + * @param [in,out] buf pointer to a BitBuffer instance + */ +void bit_buffer_free(BitBuffer* buf); + +/** + * Clear all data from a BitBuffer instance. + * + * @param [in,out] buf pointer to a BitBuffer instance + */ +void bit_buffer_reset(BitBuffer* buf); + +// Copy and write + +/** + * Copy another BitBuffer instance's contents to this one, replacing + * all of the original data. + * The destination capacity must be no less than the source data size. + * + * @param [in,out] buf pointer to a BitBuffer instance to copy into + * @param [in] other pointer to a BitBuffer instance to copy from + * @note + */ +void bit_buffer_copy(BitBuffer* buf, const BitBuffer* other); + +/** + * Copy all BitBuffer instance's contents to this one, starting from start_index, + * replacing all of the original data. + * The destination capacity must be no less than the source data size + * counting from start_index. + * + * @param [in,out] buf pointer to a BitBuffer instance to copy into + * @param [in] other pointer to a BitBuffer instance to copy from + * @param [in] start_index index to begin copying source data from + */ +void bit_buffer_copy_right(BitBuffer* buf, const BitBuffer* other, size_t start_index); + +/** + * Copy all BitBuffer instance's contents to this one, ending with end_index, + * replacing all of the original data. + * The destination capacity must be no less than the source data size + * counting to end_index. + * + * @param [in,out] buf pointer to a BitBuffer instance to copy into + * @param [in] other pointer to a BitBuffer instance to copy from + * @param [in] end_index index to end copying source data at + */ +void bit_buffer_copy_left(BitBuffer* buf, const BitBuffer* other, size_t end_index); + +/** + * Copy a byte array to a BitBuffer instance, replacing all of the original data. + * The destination capacity must be no less than the source data size. + * + * @param [in,out] buf pointer to a BitBuffer instance to copy into + * @param [in] data pointer to the byte array to be copied + * @param [in] size_bytes size of the data to be copied, in bytes + */ +void bit_buffer_copy_bytes(BitBuffer* buf, const uint8_t* data, size_t size_bytes); + +/** + * Copy a byte array to a BitBuffer instance, replacing all of the original data. + * The destination capacity must be no less than the source data size. + * + * @param [in,out] buf pointer to a BitBuffer instance to copy into + * @param [in] data pointer to the byte array to be copied + * @param [in] size_bits size of the data to be copied, in bits + */ +void bit_buffer_copy_bits(BitBuffer* buf, const uint8_t* data, size_t size_bits); + +/** + * Copy a byte with parity array to a BitBuffer instance, replacing all of the original data. + * The destination capacity must be no less than the source data size. + * + * @param [in,out] buf pointer to a BitBuffer instance to copy into + * @param [in] data pointer to the byte array to be copied + * @param [in] size_bitss size of the data to be copied, in bits + */ +void bit_buffer_copy_bytes_with_parity(BitBuffer* buf, const uint8_t* data, size_t size_bits); + +/** + * Write a BitBuffer instance's entire contents to an arbitrary memory location. + * The destination memory must be allocated. Additionally, the destination + * capacity must be no less than the source data size. + * + * @param [in] buf pointer to a BitBuffer instance to write from + * @param [out] dest pointer to the destination memory location + * @param [in] size_bytes maximum destination data size, in bytes + */ +void bit_buffer_write_bytes(const BitBuffer* buf, void* dest, size_t size_bytes); + +/** + * Write a BitBuffer instance's entire contents to an arbitrary memory location. + * Additionally, place a parity bit after each byte. + * The destination memory must be allocated. Additionally, the destination + * capacity must be no less than the source data size plus parity. + * + * @param [in] buf pointer to a BitBuffer instance to write from + * @param [out] dest pointer to the destination memory location + * @param [in] size_bytes maximum destination data size, in bytes + * @param [out] bits_written actual number of bits writen, in bits + */ +void bit_buffer_write_bytes_with_parity( + const BitBuffer* buf, + void* dest, + size_t size_bytes, + size_t* bits_written); + +/** + * Write a slice of BitBuffer instance's contents to an arbitrary memory location. + * The destination memory must be allocated. Additionally, the destination + * capacity must be no less than the requested slice size. + * + * @param [in] buf pointer to a BitBuffer instance to write from + * @param [out] dest pointer to the destination memory location + * @param [in] start_index index to begin copying source data from + * @param [in] size_bytes data slice size, in bytes + */ +void bit_buffer_write_bytes_mid( + const BitBuffer* buf, + void* dest, + size_t start_index, + size_t size_bytes); + +// Checks + +/** + * Check whether a BitBuffer instance contains a partial byte (i.e. the bit count + * is not divisible by 8). + * + * @param [in] buf pointer to a BitBuffer instance to be checked + * @return true if the instance contains a partial byte, false otherwise + */ +bool bit_buffer_has_partial_byte(const BitBuffer* buf); + +/** + * Check whether a BitBuffer instance's contents start with the designated byte. + * + * @param [in] buf pointer to a BitBuffer instance to be checked + * @param [in] byte byte value to be checked against + * @return true if data starts with designated byte, false otherwise + */ +bool bit_buffer_starts_with_byte(const BitBuffer* buf, uint8_t byte); + +// Getters + +/** + * Get a BitBuffer instance's capacity (i.e. the maximum possible amount of data), in bytes. + * + * @param [in] buf pointer to a BitBuffer instance to be queried + * @return capacity, in bytes + */ +size_t bit_buffer_get_capacity_bytes(const BitBuffer* buf); + +/** + * Get a BitBuffer instance's data size (i.e. the amount of stored data), in bits. + * Might be not divisible by 8 (see bit_buffer_is_partial_byte). + * + * @param [in] buf pointer to a BitBuffer instance to be queried + * @return data size, in bits. + */ +size_t bit_buffer_get_size(const BitBuffer* buf); + +/** + * Get a BitBuffer instance's data size (i.e. the amount of stored data), in bytes. + * If a partial byte is present, it is also counted. + * + * @param [in] buf pointer to a BitBuffer instance to be queried + * @return data size, in bytes. + */ +size_t bit_buffer_get_size_bytes(const BitBuffer* buf); + +/** + * Get a byte value at a specified index in a BitBuffer instance. + * The index must be valid (i.e. less than the instance's data size in bytes). + * + * @param [in] buf pointer to a BitBuffer instance to be queried + * @param [in] index index of the byte in question + */ +uint8_t bit_buffer_get_byte(const BitBuffer* buf, size_t index); + +/** + * Get a byte value starting from the specified bit index in a BitBuffer instance. + * The resulting byte might correspond to a single byte (if the index is a multiple + * of 8), or two overlapping bytes combined. + * The index must be valid (i.e. less than the instance's data size in bits). + * + * @param [in] buf pointer to a BitBuffer instance to be queried + * @param [in] index bit index of the byte in question + */ +uint8_t bit_buffer_get_byte_from_bit(const BitBuffer* buf, size_t index_bits); + +/** + * Get the pointer to a BitBuffer instance's underlying data. + * + * @param [in] buf pointer to a BitBuffer instance to be queried + * @return pointer to the underlying data + */ +const uint8_t* bit_buffer_get_data(const BitBuffer* buf); + +/** + * Get the pointer to a BitBuffer instance's underlying data. + * + * @param [in] buf pointer to a BitBuffer instance to be queried + * @return pointer to the underlying data + */ +const uint8_t* bit_buffer_get_parity(const BitBuffer* buf); + +// Setters + +/** + * Set byte value at a specified index in a BitBuffer instance. + * The index must be valid (i.e. less than the instance's data size in bytes). + * + * @param [in,out] buf pointer to a BitBuffer instance to be modified + * @param [in] index index of the byte in question + * @param [in] byte byte value to be set at index + */ +void bit_buffer_set_byte(BitBuffer* buf, size_t index, uint8_t byte); + +/** + * Set byte and parity bit value at a specified index in a BitBuffer instance. + * The index must be valid (i.e. less than the instance's data size in bytes). + * + * @param [in,out] buf pointer to a BitBuffer instance to be modified + * @param [in] index index of the byte in question + * @param [in] byte byte value to be set at index + * @param [in] parity parity bit value to be set at index + */ +void bit_buffer_set_byte_with_parity(BitBuffer* buff, size_t index, uint8_t byte, bool parity); + +/** + * Resize a BitBuffer instance to a new size, in bits. + * @warning May cause bugs. Use only if absolutely necessary. + * + * @param [in,out] buf pointer to a BitBuffer instance to be resized + * @param [in] new_size the new size of the buffer, in bits + */ +void bit_buffer_set_size(BitBuffer* buf, size_t new_size); + +/** + * Resize a BitBuffer instance to a new size, in bytes. + * @warning May cause bugs. Use only if absolutely necessary. + * + * @param [in,out] buf pointer to a BitBuffer instance to be resized + * @param [in] new_size_bytes the new size of the buffer, in bytes + */ +void bit_buffer_set_size_bytes(BitBuffer* buf, size_t new_size_bytes); + +// Modification + +/** + * Append all BitBuffer's instance contents to this one. The destination capacity + * must be no less than its original data size plus source data size. + * + * @param [in,out] buf pointer to a BitBuffer instance to be appended to + * @param [in] other pointer to a BitBuffer instance to be appended + */ +void bit_buffer_append(BitBuffer* buf, const BitBuffer* other); + +/** + * Append a BitBuffer's instance contents to this one, starting from start_index. + * The destination capacity must be no less than the source data size + * counting from start_index. + * + * @param [in,out] buf pointer to a BitBuffer instance to be appended to + * @param [in] other pointer to a BitBuffer instance to be appended + * @param [in] start_index index to begin copying source data from + */ +void bit_buffer_append_right(BitBuffer* buf, const BitBuffer* other, size_t start_index); + +/** + * Append a byte to a BitBuffer instance. + * The destination capacity must be no less its original data size plus one. + * + * @param [in,out] buf pointer to a BitBuffer instance to be appended to + * @param [in] byte byte value to be appended + */ +void bit_buffer_append_byte(BitBuffer* buf, uint8_t byte); + +/** + * Append a byte array to a BitBuffer instance. + * The destination capacity must be no less its original data size plus source data size. + * + * @param [in,out] buf pointer to a BitBuffer instance to be appended to + * @param [in] data pointer to the byte array to be appended + * @param [in] size_bytes size of the data to be appended, in bytes + */ +void bit_buffer_append_bytes(BitBuffer* buf, const uint8_t* data, size_t size_bytes); + +/** + * Append a bit to a BitBuffer instance. + * The destination capacity must be sufficient to accomodate the additional bit. + * + * @param [in,out] buf pointer to a BitBuffer instance to be appended to + * @param [in] bit bit value to be appended + */ +void bit_buffer_append_bit(BitBuffer* buf, bool bit); + +void bit_buffer_dump(BitBuffer* buf); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/application/src/rfid/reader/lf/utils/bitarray.c b/firmware/application/src/rfid/reader/lf/utils/bitarray.c new file mode 100644 index 00000000..d2925927 --- /dev/null +++ b/firmware/application/src/rfid/reader/lf/utils/bitarray.c @@ -0,0 +1,39 @@ +#include "bitarray.h" + +void bitarray_clear(BitArray* b) { + b->count = 0; + b->value = 0; +} + +bool bitarray_get_bit(BitArray b, uint8_t bit_num, bool* bit) { + if (bit == NULL || b.count < bit_num + 1) + return false; + + *bit = (b.value & (1 << bit_num)) != 0; + return true; +} + +bool bitarray_set_bit(BitArray* b, uint8_t bit_num, bool bit) { + if (b == NULL || b->count < bit_num + 1) + return false; + + uint8_t t = (b->value | (1 << bit_num)); + if (!bit) + t = t ^ (1 << bit_num); + + return true; +} + +bool bitarray_add_bit(BitArray* b, bool bit) { + if (b == NULL || b->count == 4) + return false; + + uint8_t t = b->value << 1 | bit; + b->value = t; + b->count++; + return true; +} + +uint8_t bitarray_count(BitArray b) { + return b.count; +} diff --git a/firmware/application/src/rfid/reader/lf/utils/bitarray.h b/firmware/application/src/rfid/reader/lf/utils/bitarray.h new file mode 100644 index 00000000..1c86baf0 --- /dev/null +++ b/firmware/application/src/rfid/reader/lf/utils/bitarray.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + uint8_t count : 2; + uint32_t value : 6; +} BitArray; + +void bitarray_clear(BitArray* b); +bool bitarray_set_bit(BitArray* b, uint8_t bit_num, bool bit); +bool bitarray_add_bit(BitArray* b, bool bit); +uint8_t bitarray_count(BitArray b); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/application/src/rfid/reader/lf/utils/level_duration.h b/firmware/application/src/rfid/reader/lf/utils/level_duration.h new file mode 100644 index 00000000..7618344a --- /dev/null +++ b/firmware/application/src/rfid/reader/lf/utils/level_duration.h @@ -0,0 +1,82 @@ +#pragma once + +#include + +#define LEVEL_DURATION_BIG + +#ifdef LEVEL_DURATION_BIG + +#define LEVEL_DURATION_RESET 0U +#define LEVEL_DURATION_LEVEL_LOW 1U +#define LEVEL_DURATION_LEVEL_HIGH 2U +#define LEVEL_DURATION_WAIT 3U +#define LEVEL_DURATION_RESERVED 0x800000U + +typedef struct { + uint32_t duration : 30; + uint8_t level : 2; +} LevelDuration; + +static inline LevelDuration level_duration_make(bool level, uint32_t duration) { + LevelDuration level_duration; + level_duration.level = level ? LEVEL_DURATION_LEVEL_HIGH : LEVEL_DURATION_LEVEL_LOW; + level_duration.duration = duration; + return level_duration; +} + +static inline LevelDuration level_duration_reset() { + LevelDuration level_duration; + level_duration.level = LEVEL_DURATION_RESET; + return level_duration; +} + +static inline LevelDuration level_duration_wait() { + LevelDuration level_duration; + level_duration.level = LEVEL_DURATION_WAIT; + return level_duration; +} + +static inline bool level_duration_is_reset(LevelDuration level_duration) { + return level_duration.level == LEVEL_DURATION_RESET; +} + +static inline bool level_duration_is_wait(LevelDuration level_duration) { + return level_duration.level == LEVEL_DURATION_WAIT; +} + +static inline bool level_duration_get_level(LevelDuration level_duration) { + return level_duration.level == LEVEL_DURATION_LEVEL_HIGH; +} + +static inline uint32_t level_duration_get_duration(LevelDuration level_duration) { + return level_duration.duration; +} + +#else + +#define LEVEL_DURATION_RESET 0U +#define LEVEL_DURATION_RESERVED 0x800000U + +typedef int32_t LevelDuration; + +static inline LevelDuration level_duration(bool level, uint32_t duration) { + return level ? duration : -(int32_t)duration; +} + +static inline LevelDuration level_duration_reset() { + return LEVEL_DURATION_RESET; +} + +static inline bool level_duration_is_reset(LevelDuration level_duration) { + return (level_duration == LEVEL_DURATION_RESET); +} + +static inline bool level_duration_get_level(LevelDuration level_duration) { + return (level_duration > 0); +} + +static inline uint32_t level_duration_get_duration(LevelDuration level_duration) { + return (level_duration >= 0) ? level_duration : -level_duration; +} + +#endif diff --git a/firmware/application/src/rfid/reader/lf/utils/manchester_decoder.c b/firmware/application/src/rfid/reader/lf/utils/manchester_decoder.c new file mode 100644 index 00000000..3de31e56 --- /dev/null +++ b/firmware/application/src/rfid/reader/lf/utils/manchester_decoder.c @@ -0,0 +1,80 @@ +#include "manchester_decoder.h" +#include + +//static const uint8_t transitions[] = {0b00000001, 0b10010001, 0b10011011, 0b11111011}; +static const ManchesterState manchester_reset_state = ManchesterResetState; + +bool manchester_advance( + ManchesterState state, + ManchesterEvent event, + ManchesterState* next_state, + BitArray* data) { + bool result = false; + ManchesterState new_state; + bitarray_clear(data); + + if(event == ManchesterEventReset) { + new_state = manchester_reset_state; + } else { + + + + } + + *next_state = new_state; + return result; +} +/* +uint8_t mcst(RAWBUF_TYPE_S *Pdata) { + uint8_t sync = 1; //After the current interval process is processed, is it on the judgment line + uint8_t cardindex = 0; //Record change number + for (int i = Pdata->startbit; i < RAW_BUF_SIZE * 8; i++) { + uint8_t thisbit = readbit(Pdata->rawa, Pdata->rawb, i); + switch (sync) { + case 1: //Synchronous state + switch (thisbit) { + case 0: //TheSynchronousState1T,Add1Digit0,StillSynchronize + writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 0); + cardindex++; + break; + case 1: // Synchronous status 1.5T, add 1 digit 1, switch to non -synchronized state + writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 1); + cardindex++; + sync = 0; + break; + case 2: //Synchronous2T,Add2Digits10,StillSynchronize + writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 1); + cardindex++; + writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 0); + cardindex++; + break; + default: + return 0; + } + break; + case 0: //Non -synchronous state + switch (thisbit) { + case 0: //1TInNonSynchronousState,Add1Digit1,StillNonSynchronous + writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 1); + cardindex++; + break; + case 1: // In non -synchronous status 1.5T, add 2 digits 10, switch to the synchronous state + writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 1); + cardindex++; + writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 0); + cardindex++; + sync = 1; + break; + case 2: //The2TOfTheNonSynchronousState,ItIsImpossibleToOccur,ReportAnError + return 0; + default: + return 0; + } + break; + } + if (cardindex >= CARD_BUF_SIZE * 8) + break; + } + return 1; +} +*/ diff --git a/firmware/application/src/rfid/reader/lf/utils/manchester_decoder.h b/firmware/application/src/rfid/reader/lf/utils/manchester_decoder.h new file mode 100644 index 00000000..d11b6439 --- /dev/null +++ b/firmware/application/src/rfid/reader/lf/utils/manchester_decoder.h @@ -0,0 +1,36 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include "bitarray.h" + +typedef enum { + ManchesterEvent1T = 0, + ManchesterEvent15T = 2, + ManchesterEvent2T = 4, + ManchesterEventReset = 8 +} ManchesterEvent; + +typedef enum { + ManchesterStateSync = 0, + ManchesterStateNoSync = 1, + ManchesterResetState = 2, +} ManchesterState; + +ManchesterEvent manchester_length_decode(int interval_length, int _1t_length, int _deviation); + +bool manchester_advance( + ManchesterState state, + ManchesterEvent event, + ManchesterState* next_state, + BitArray* data); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/application/src/rfid/reader/lf/utils/spstring.c b/firmware/application/src/rfid/reader/lf/utils/spstring.c new file mode 100644 index 00000000..7b60eb2d --- /dev/null +++ b/firmware/application/src/rfid/reader/lf/utils/spstring.c @@ -0,0 +1,568 @@ +/* +* C Implementation: SPString +* +* Description: +* This class provides a safe and convenient, albeit slower, alternative +* to C character chains. +* +* One can easily create a String from a C string with newString(char *). +* String.str always returns a null-terminated C chain, and String.len +* returns its length. +* One should always avoid to manipulate the String structure members +* directly in order to prevent corruption (i.e incorrect sz and len values). +* +* Most functions mirror standard C functions. +* stringcpy and stringcat can increase their buffer size if necessary in +* order to prevent buffer overflow. +* +* Author: Nicolas Janin <>, (C) 2009 +* +* Published under MIT License +* strlcpy copyrghted by its author +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "spstring.h" + +#undef TIDY /* Tidy up buffers by filling them with zeroes */ + /* Slows things down a little, so uncomment this */ + /* only if needed. */ + +/* private (internal mechanics) */ +static int ST_ERR = ST_NO_ERR; +static int incsz ( String *string, size_t len ); +size_t strlcpy(char *dst, const char *src, size_t siz); + +char *sp_strdup(const char *s1) +{ + char *str; + size_t size = strlen(s1) + 1; + + str = malloc(size); + if (str) { + memcpy(str, s1, size); + } + return str; +} + +/* --- Dynamic allocation + + String can dynamically increase in size as necessary. */ +String * newString ( const char *chars ) +{ + String *newS = NULL; + + if ( chars != NULL ) + { + size_t len = strlen ( chars ); + newS = ( String * ) malloc ( sizeof ( String ) ); + if ( newS != NULL ) + { + newS->len = len; + newS->sz = len + 1; + newS->str = sp_strdup ( chars ); + if ( newS->str == NULL ) + { + ST_ERR = ST_ALLOC_ERR; + } + } + else + { + ST_ERR = ST_ALLOC_ERR; + } + } + else + { + ST_ERR = ST_NULLPARAM_ERR; + } + return newS; +} + +void delString ( String *string ) +{ +#ifdef NDEBUG + stringcheck ( string, __FILE__, __LINE__ ); +#endif + if ( string != NULL ) + { + if ( string->str != NULL ) + { + free ( string->str ); + string->str = NULL; + } + else + { + ST_ERR = ST_NULLSTR_ERR; + } + free ( string ); + string = NULL; + } + else + { + ST_ERR = ST_NULLPARAM_ERR; + } +} + +/* Copy - Will increase dst allocation if src is too large */ +size_t stringcpy ( String *dst, const String *src ) +{ +#ifdef NDEBUG + stringcheck ( src, __FILE__, __LINE__ ); + stringcheck ( dst, __FILE__, __LINE__ ); +#endif + size_t len = src->len; + if ( dst->sz <= len ) + { + if ( incsz ( dst, len + 1 ) == ST_ALLOC_ERR ) + { + return ST_ALLOC_ERR; + } + } + + dst->len = len; +#ifdef TIDY + strlcpy ( dst->str, src->str, len + 1 ); +#else + strcpy ( dst->str, src->str ); +#endif + return len; +} + +/* Copy - Will increase dst allocation if src is too large */ +size_t stringchcpy ( String *dst, const char *src ) +{ +#ifdef NDEBUG + stringcheck ( dst, __FILE__, __LINE__ ); +#endif + if ( src == NULL ) + { + ST_ERR = ST_NULLPARAM_ERR; + return ST_NULLPARAM_ERR; + } + size_t len = strlen ( src ); + if ( dst->sz <= len ) + { + if ( incsz ( dst, len + 1 ) == ST_ALLOC_ERR ) + { + return ST_ALLOC_ERR; + } + } + + dst->len = len; +#ifdef TIDY + strlcpy ( dst->str, src, len + 1 ); +#else + strcpy ( dst->str, src ); +#endif + return len; +} + +/* Concatenation - Will increase dst allocation when necessary */ +size_t stringcat ( String *dst, const String *src ) +{ +#ifdef NDEBUG + stringcheck ( src, __FILE__, __LINE__ ); + stringcheck ( dst, __FILE__, __LINE__ ); +#endif + size_t len = src->len; + size_t finallen = dst->len + len; + if ( dst->sz <= finallen ) + { + if ( incsz ( dst, finallen + 1 ) == ST_ALLOC_ERR ) + { + return ST_ALLOC_ERR; + } + } + + dst->len = finallen; + strcat ( dst->str, src->str ); +#ifdef TIDY + size_t l = dst->len; + char * end = dst->str + l; + for ( ; l < dst->sz; l++ ) *end++ = 0; +#endif + return len; +} + +/* Concatenation - Will increase dst allocation when necessary */ +size_t stringchcat ( String *dst, const char *src ) +{ +#ifdef NDEBUG + stringcheck ( dst, __FILE__, __LINE__ ); +#endif + if ( src == NULL ) + { + ST_ERR = ST_NULLPARAM_ERR; + return ST_NULLPARAM_ERR; + } + size_t len = strlen ( src ); + size_t finallen = dst->len + len; + if ( dst->sz <= finallen ) + { + if ( incsz ( dst, finallen + 1 ) == ST_ALLOC_ERR ) + { + return ST_ALLOC_ERR; + } + } + + dst->len = finallen; + strcat ( dst->str, src ); +#ifdef TIDY + size_t l = dst->len; + char * end = dst->str + l; + for ( ; l < dst->sz; l++ ) *end++ = 0; +#endif + + return len; +} + +/* Duplication - allocate a new String */ +String * stringdup ( const String *src ) +{ +#ifdef NDEBUG + stringcheck ( src, __FILE__, __LINE__ ); +#endif + String *string = NULL; + if ( src != NULL ) + { + string = newString ( src->str ); + } + else + { + ST_ERR = ST_NULLPARAM_ERR; + } + return string; +} + + +/* ---- Allocation on the stack (non dynamic) */ + +/* + Allocation on the stack + Here, szMax is a maximum size of the buffer, which is allocated + once and for all, and cannot be increased at runtime. + Furthermore, the chars array must not be deallocated before the release + of the LString (else mangling pointer). + If you need fully extensible Strings, use dynamic allocation instead. +*/ +LString localString ( char *chars, size_t szMax ) +{ + LString newS; + if ( chars != NULL ) + { + newS = ( LString ) {szMax, strlen ( chars ), chars}; +#ifdef TIDY + size_t l = newS.len; + char * end = chars + l; + for ( ; l < szMax; l++ ) *end++ = 0; +#endif + } + else + { + ST_ERR = ST_NULLPARAM_ERR; + newS = ( LString ) {0, 0, NULL}; + } + return newS; +} + +/* Copy of LString - checks that there is no buffer overflow */ +size_t lstringcpy ( LString *dst, const LString *src ) +{ +#ifdef NDEBUG + stringcheck ( ( String * ) src, __FILE__, __LINE__ ); + stringcheck ( ( String * ) dst, __FILE__, __LINE__ ); +#endif + size_t len = src->len; + if ( dst->sz <= len ) + { + ST_ERR = ST_OVERWRITE_ERR; + return ST_OVERWRITE_ERR; + } + dst->len = len; +#ifdef TIDY + strlcpy ( dst->str, src->str, dst->sz + 1 ); +#else + strcpy ( dst->str, src->str ); +#endif + return len; +} + +/* Copy of a fixed character chain in a LString + * checks that there is no buffer overflow + */ +size_t lstringchcpy ( LString *dst, const char *src ) +{ +#ifdef NDEBUG + stringcheck ( ( String * ) dst, __FILE__, __LINE__ ); +#endif + if ( src == NULL ) + { + ST_ERR = ST_NULLPARAM_ERR; + return ST_NULLPARAM_ERR; + } + size_t len = strlen ( src ); + if ( dst->sz <= len ) + { + ST_ERR = ST_OVERWRITE_ERR; + return ST_OVERWRITE_ERR; + } + dst->len = len; +#ifdef TIDY + strlcpy ( dst->str, src, dst->sz + 1 ); +#else + strcpy ( dst->str, src ); +#endif + return len; +} + +size_t lstringcat ( LString *dst, const LString *src ) +{ +#ifdef NDEBUG + stringcheck ( ( String * ) src, __FILE__, __LINE__ ); + stringcheck ( ( String * ) dst, __FILE__, __LINE__ ); +#endif + size_t len = src->len; + size_t finallen = dst->len + len; + if ( finallen >= dst->sz ) + { + ST_ERR = ST_OVERWRITE_ERR; + return ST_OVERWRITE_ERR; + } + dst->len = finallen; + strcat ( dst->str, src->str ); +#ifdef TIDY + size_t l = dst->len; + char * end = dst->str + l; + for ( ; l < dst->sz; l++ ) *end++ = 0; +#endif + return len; +} + +/* Cooncatenation of a fixed character chain to a LString */ +size_t lstringchcat ( LString *dst, const char *src ) +{ +#ifdef NDEBUG + stringcheck ( ( String * ) dst, __FILE__, __LINE__ ); +#endif + if ( src == NULL ) + { + ST_ERR = ST_NULLPARAM_ERR; + return ST_NULLPARAM_ERR; + } + size_t len = strlen ( src ); + size_t finallen = dst->len + len; + if ( finallen >= dst->sz ) + { + ST_ERR = ST_OVERWRITE_ERR; + return ST_OVERWRITE_ERR; + } + dst->len = finallen; + strcat ( dst->str, src ); +#ifdef TIDY + size_t l = dst->len; + char * end = dst->str + l; + for ( ; l < dst->sz; l++ ) *end++ = 0; +#endif + return len; +} + + +/* The following functions apply both on String and LString */ + +size_t stringlen ( const String *string ) +{ + return string->len; +} + +/* + Check for an internal inconsistency in a LString. + You can use this in a debugging session. +*/ +int stringcheck ( const String *string, char *file, int line ) +{ +#ifdef NDEBUG + #define ASSERT(cond) if ( !(cond) ) { \ + printf("stringcheck error %s line %d:String(%zu/%zu)=\"%s\"\n", \ + file, line, string->len, string->sz, string->str); \ + assert( string != NULL ); } + ASSERT ( string != NULL ); + ASSERT ( string->str != NULL ); + ASSERT ( string->len < string->sz ); + ASSERT ( string->len == strlen ( string->str ) ); + return 0; + #undef ASSERT +#else + if ( string == NULL ) + return ST_NULLPARAM_ERR; + if ( string->str == NULL ) + return ST_NULLSTR_ERR; + if ( string->len >= string->sz ) + return ST_INCONSISTENTSZ_ERR; + if ( string->len != strlen ( string->str ) ) + return ST_INCONSISTENTLEN_ERR; + return 0; +#endif +} + +/* String comparison */ +int stringcmp ( const String *st1, const String *st2 ) +{ +#ifdef NDEBUG + stringcheck ( ( String * ) st1, __FILE__, __LINE__ ); + stringcheck ( ( String * ) st2, __FILE__, __LINE__ ); +#endif + if ( st1->len != st2->len ) + { + return ( int ) ( st2->len - st1->len ); + } + + return strcmp ( st1->str, st2->str ); +} + +/* Comparison with a C chain */ +int stringchcmp ( const String *st1, const char *st2 ) +{ +#ifdef NDEBUG + stringcheck ( ( String * ) st1, __FILE__, __LINE__ ); +#endif + size_t lt2 = strlen ( st2 ); + if ( st1->len != lt2 ) + { + return ( int ) ( lt2 - st1->len ); + } + + return strcmp ( st1->str, st2 ); +} + +/* Truncation to the Nth character */ +String * stringtrunc ( String *string, size_t N ) +{ +#ifdef NDEBUG + stringcheck ( string, __FILE__, __LINE__ ); +#endif + string->len = N-1; + string->str[N-1] = '\0'; +#ifdef TIDY + size_t l = string->len; + char * end = string->str + l; + for ( ; l < string->sz; l++ ) *end++ = 0; +#endif + return string; +} + + +/* Formatting */ +void stringprintf ( String *dst, const char * format, ... ) +{ +#ifdef NDEBUG + stringcheck ( dst, __FILE__, __LINE__ ); +#endif + va_list argp; + va_start ( argp, format ); + dst->len = vsnprintf ( dst->str, dst->sz, format, argp ) ; + va_end ( argp ) ; +} + +/* Returns error type and resets ST_ERR */ +int get_stringerr() +{ + int err = ST_ERR; + ST_ERR = ST_NO_ERR; + return err; +} + +/************************************************* +* PRIVATE +**************************************************/ + +/* Increase string.sz to desired size */ +static int incsz ( String *string, size_t size ) +{ + ST_ERR = ST_NO_ERR; + + if ( string->sz < size ) + { + /* double as necessary */ + size_t newsz = string->sz; + do + { + newsz *= 2; + } while (newsz < size); + + char *tmp = realloc ( string->str, (size_t)newsz ); + + if ( tmp != NULL ) + { +#ifdef TIDY + size_t l = string->len; + char * end = tmp + l; + for ( ; l < size; l++ ) *end++ = 0; +#endif + string->str = tmp; + string->sz = newsz; + } + else + { + ST_ERR = ST_ALLOC_ERR; + } + } + return ST_ERR; +} + +/* + * Copyright (c) 1998 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t strlcpy(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0) + { + while (--n != 0) + { + if ((*d++ = *s++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) + { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return (s - src - 1); /* count does not include NUL */ + } + +#undef TIDY diff --git a/firmware/application/src/rfid/reader/lf/utils/spstring.h b/firmware/application/src/rfid/reader/lf/utils/spstring.h new file mode 100644 index 00000000..3062335d --- /dev/null +++ b/firmware/application/src/rfid/reader/lf/utils/spstring.h @@ -0,0 +1,125 @@ +/* +* C Interface: SPString +* +* Description: simple String structure and manipulation +* +* This class provides a safe and convenient, albeit slower, alternative +* to C character chains. +* +* There are two types of strings: +* 1. String is a fully dynamic string, that is be resized automatically +* at runtime when calling stringcpy and similar functions. +* One doesn't have to worry about buffer length. +* 2. LString (Local String) has a fixed buffer size. +* lstringcpy and the like will check that the buffer size is respected +* and raise an error if it's not the case. +* +* One can easily create a String from a C string with +* newString(const char *). +* String.str always returns a null-terminated C chain, and String.len +* returns its length. +* One should always avoid to manipulate the String structure members +* directly in order to prevent corruption (i.e mainly incorrect sz and +* len values). +* +* Most functions mirror the standard C functions. +*/ + +#ifndef SPSTRING_H +#define SPSTRING_H + +#include + +/* ========================================================================= + Allocation on the stack (non dynamic) + + The size sz is fixed once and for all at creation and must be the maximum + size of the buffer holding the string, not the length of the C character + string passed at initialization. Anything past will be truncated. + + Example Usage: + { + #define SIZE 40 <--- the LString can never grow longer than 39 chars + static char buff[SIZE] = "Hello"; + LString *hello = localString(buff, SIZE); + ... + lstringchcat(hello, " World !"); + } <--- automatic deallocation at the end of the scope + + Warning: The following does not work (because localString does + not allocate memory): + LString *hello = localString("Hello World", SIZE); +*/ + +typedef struct { + size_t sz; /* max buffer size, fixed, always > len */ + size_t len; /*length (final '\0' excluded) */ + char *str; /* null terminated character chain */ +} LString; + +/* Create a local String */ +LString localString ( char *chars, size_t szMax ); + +size_t lstringcpy ( LString *dst, const LString *src ); +size_t lstringchcpy ( LString *dst, const char *src ); +size_t lstringcat ( LString *dst, const LString *src ); +size_t lstringchcat ( LString *dst, const char *src ); + + +/* =================== Dynamic allocation on the Heap ======================= + The size is automatically adjusted at runtime. + + Usage example: + LString *hello = newString("Hello "); + ... + stringchcat(hello, " world !"); + ... + delString(myString); +*/ + +typedef struct{ + size_t sz; /* max buffer size, dynamic(always > len) */ + size_t len; /* length (final '\0' excluded) */ + char *str; /* null terminated character chain */ +} String; + +/* Allocate a new String object. + * The source buffer passed as argument is copied, so it must be + * freed manually. */ +String * newString(const char *); +void delString(String *); + +size_t stringcpy(String *dst, const String *src); +size_t stringchcpy(String *dst, const char *src); +size_t stringcat(String *dst, const String *src); +size_t stringchcat(String *dst, const char *src); +String * stringdup(const String *); + +/* ========== The following functions apply both + ========== on String and LString ===================*/ + +size_t stringlen(const String *); +int stringcmp(const String *st1, const String *st2); +int stringchcmp(const String *st1, const char *st2); +/* Truncation of length to Nth character */ +String * stringtrunc(String *string, size_t N); +void stringprintf ( String *dst, const char * format, ... ); + +/* Verification of internal consistency of a String/LString + Can be useful in a debugging session */ +int stringcheck(const String *string, char *file, int line); + +/* Use this function to get the error code */ +/* if (get_stringerr() != ST_NO_ERR) --> error */ +int get_stringerr(); + +/* Possible errors */ +#define ST_NO_ERR -1000 +#define ST_OVERWRITE_ERR -1001 +#define ST_ALLOC_ERR -1002 +#define ST_NULLPARAM_ERR -1003 +#define ST_NULLSTR_ERR -1004 +#define ST_INCONSISTENTSZ_ERR -1005 +#define ST_INCONSISTENTLEN_ERR -1006 + +#endif diff --git a/firmware/application/src/rfid/reader/lf/utils/t5577.c b/firmware/application/src/rfid/reader/lf/utils/t5577.c new file mode 100644 index 00000000..ef1ac4db --- /dev/null +++ b/firmware/application/src/rfid/reader/lf/utils/t5577.c @@ -0,0 +1,10 @@ +#include "t5577.h" + +void t5577_write(LFRFIDT5577* data) { +} + +void t5577_write_with_pass(LFRFIDT5577* data, uint32_t password) { +} + +void t5577_write_with_mask(LFRFIDT5577* data, uint8_t page, bool with_pass, uint32_t password) { +} diff --git a/firmware/application/src/rfid/reader/lf/utils/t5577.h b/firmware/application/src/rfid/reader/lf/utils/t5577.h new file mode 100644 index 00000000..f7b5cc4f --- /dev/null +++ b/firmware/application/src/rfid/reader/lf/utils/t5577.h @@ -0,0 +1,61 @@ +#pragma once +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define LFRFID_T5577_BLOCK_COUNT 8 + +// T5577 block 0 definitions, thanks proxmark3! +#define LFRFID_T5577_POR_DELAY 0x00000001 +#define LFRFID_T5577_ST_TERMINATOR 0x00000008 +#define LFRFID_T5577_PWD 0x00000010 +#define LFRFID_T5577_MAXBLOCK_SHIFT 5 +#define LFRFID_T5577_AOR 0x00000200 +#define LFRFID_T5577_PSKCF_RF_2 0 +#define LFRFID_T5577_PSKCF_RF_4 0x00000400 +#define LFRFID_T5577_PSKCF_RF_8 0x00000800 +#define LFRFID_T5577_MODULATION_DIRECT 0 +#define LFRFID_T5577_MODULATION_PSK1 0x00001000 +#define LFRFID_T5577_MODULATION_PSK2 0x00002000 +#define LFRFID_T5577_MODULATION_PSK3 0x00003000 +#define LFRFID_T5577_MODULATION_FSK1 0x00004000 +#define LFRFID_T5577_MODULATION_FSK2 0x00005000 +#define LFRFID_T5577_MODULATION_FSK1a 0x00006000 +#define LFRFID_T5577_MODULATION_FSK2a 0x00007000 +#define LFRFID_T5577_MODULATION_MANCHESTER 0x00008000 +#define LFRFID_T5577_MODULATION_BIPHASE 0x00010000 +#define LFRFID_T5577_MODULATION_DIPHASE 0x00018000 +#define LFRFID_T5577_X_MODE 0x00020000 +#define LFRFID_T5577_BITRATE_RF_8 0 +#define LFRFID_T5577_BITRATE_RF_16 0x00040000 +#define LFRFID_T5577_BITRATE_RF_32 0x00080000 +#define LFRFID_T5577_BITRATE_RF_40 0x000C0000 +#define LFRFID_T5577_BITRATE_RF_50 0x00100000 +#define LFRFID_T5577_BITRATE_RF_64 0x00140000 +#define LFRFID_T5577_BITRATE_RF_100 0x00180000 +#define LFRFID_T5577_BITRATE_RF_128 0x001C0000 +#define LFRFID_T5577_TESTMODE_DISABLED 0x60000000 + +typedef struct { + uint32_t block[LFRFID_T5577_BLOCK_COUNT]; + uint32_t blocks_to_write; + uint8_t mask; +} LFRFIDT5577; + +/** + * @brief Write T5577 tag data to tag + * + * @param data + */ +void t5577_write(LFRFIDT5577* data); + +void t5577_write_with_pass(LFRFIDT5577* data, uint32_t password); + +void t5577_write_with_mask(LFRFIDT5577* data, uint8_t page, bool with_pass, uint32_t password); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/software/script/chameleon_cli_unit.py b/software/script/chameleon_cli_unit.py index 6bcf9e9b..e823829f 100644 --- a/software/script/chameleon_cli_unit.py +++ b/software/script/chameleon_cli_unit.py @@ -2436,6 +2436,17 @@ def on_exec(self, args: argparse.Namespace): print(f" - EM410x ID(10H): {id_hex} write done.") +@lf.command('read') +class LFRead(ReaderRequiredUnit): + def args_parser(self) -> ArgumentParserNoExit: + parser = ArgumentParserNoExit() + parser.description = 'Scan lf tag and print data' + return parser + + def on_exec(self, args: argparse.Namespace): + data = self.cmd.lf_read() + print(f" - LF card dump: {CG}{data.hex()}{C0}") + @hw_slot.command('list') class HWSlotList(DeviceRequiredUnit): def args_parser(self) -> ArgumentParserNoExit: diff --git a/software/script/chameleon_cmd.py b/software/script/chameleon_cmd.py index 9c9f2c22..82d7aa3e 100644 --- a/software/script/chameleon_cmd.py +++ b/software/script/chameleon_cmd.py @@ -385,6 +385,17 @@ def em410x_write_to_t55xx(self, id_bytes: bytes): data = struct.pack(f'!5s4s{4*len(old_keys)}s', id_bytes, new_key, b''.join(old_keys)) return self.device.send_cmd_sync(Command.EM410X_WRITE_TO_T55XX, data) + @expect_response(Status.LF_TAG_OK) + def lf_read(self): + """ + Read the lf card. + + :return: + """ + resp = self.device.send_cmd_sync(Command.DATA_CMD_LF_READ) + resp.parsed = resp.data + return resp + @expect_response(Status.SUCCESS) def get_slot_info(self): """ diff --git a/software/script/chameleon_enum.py b/software/script/chameleon_enum.py index 3bb9868e..03aa614c 100644 --- a/software/script/chameleon_enum.py +++ b/software/script/chameleon_enum.py @@ -72,6 +72,7 @@ class Command(enum.IntEnum): EM410X_SCAN = 3000 EM410X_WRITE_TO_T55XX = 3001 + DATA_CMD_LF_READ = 3010 MF1_WRITE_EMU_BLOCK_DATA = 4000 HF14A_SET_ANTI_COLL_DATA = 4001 @@ -128,6 +129,8 @@ class Status(enum.IntEnum): LF_TAG_OK = 0x40 # Unable to search for a valid EM410X label EM410X_TAG_NO_FOUND = 0x41 + # Unable to search for a valid LF tag + LF_TAG_NO_FOUND = 0x42 # The parameters passed by the BLE instruction are wrong, or the parameters passed # by calling some functions are wrong @@ -164,6 +167,8 @@ def __str__(self): return "LF tag operation succeeded" elif self == Status.EM410X_TAG_NO_FOUND: return "EM410x tag no found" + elif self == Status.LF_TAG_NO_FOUND: + return "LF tag not found" elif self == Status.PAR_ERR: return "API request fail, param error" elif self == Status.DEVICE_MODE_ERROR: