From e7e4be04d0ab94033dd48b026624686e3410922b Mon Sep 17 00:00:00 2001 From: Philippe Teuwen Date: Wed, 23 Aug 2023 03:55:48 +0200 Subject: [PATCH] translate fw app comments --- firmware/application/src/app_main.c | 16 +- firmware/application/src/app_status.h | 46 +- firmware/application/src/ble_main.c | 42 +- firmware/application/src/bsp/bsp_delay.c | 10 +- firmware/application/src/bsp/bsp_time.c | 44 +- firmware/application/src/bsp/bsp_time.h | 12 +- firmware/application/src/rfid/crc_utils.c | 16 +- firmware/application/src/rfid/hex_utils.c | 18 +- .../src/rfid/nfctag/hf/crypto1_helper.c | 4 +- .../application/src/rfid/nfctag/hf/nfc_14a.c | 260 ++++---- .../application/src/rfid/nfctag/hf/nfc_14a.h | 46 +- .../application/src/rfid/nfctag/hf/nfc_mf1.c | 432 +++++++------- .../application/src/rfid/nfctag/hf/nfc_mf1.h | 64 +- .../application/src/rfid/nfctag/hf/nfc_ntag.c | 30 +- .../application/src/rfid/nfctag/hf/nfc_ntag.h | 2 +- .../src/rfid/nfctag/lf/lf_tag_em.c | 156 ++--- .../src/rfid/nfctag/lf/lf_tag_em.h | 6 +- .../src/rfid/nfctag/tag_base_type.h | 22 +- .../src/rfid/nfctag/tag_emulation.c | 238 ++++---- .../src/rfid/nfctag/tag_emulation.h | 74 +-- .../src/rfid/nfctag/tag_persistence.h | 5 +- .../src/rfid/reader/hf/mf1_toolbox.c | 459 +++++++------- .../src/rfid/reader/hf/mf1_toolbox.h | 18 +- .../application/src/rfid/reader/hf/rc522.c | 562 +++++++++--------- .../application/src/rfid/reader/hf/rc522.h | 226 +++---- .../src/rfid/reader/lf/data_utils.c | 12 +- .../src/rfid/reader/lf/lf_125khz_radio.c | 30 +- .../src/rfid/reader/lf/lf_em410x_data.c | 160 ++--- .../src/rfid/reader/lf/lf_em410x_data.h | 14 +- .../src/rfid/reader/lf/lf_reader_data.c | 16 +- .../src/rfid/reader/lf/lf_reader_data.h | 4 +- .../src/rfid/reader/lf/lf_reader_main.c | 44 +- .../src/rfid/reader/lf/lf_t55xx_data.c | 146 ++--- firmware/application/src/rfid_main.c | 10 +- firmware/application/src/rgb_marquee.c | 186 +++--- firmware/application/src/usb_main.c | 9 +- firmware/application/src/utils/dataframe.c | 24 +- firmware/application/src/utils/fds_util.c | 70 +-- firmware/application/src/utils/syssleep.c | 32 +- firmware/application/src/utils/syssleep.h | 22 +- firmware/application/src/utils/timeslot.c | 68 +-- 41 files changed, 1824 insertions(+), 1831 deletions(-) diff --git a/firmware/application/src/app_main.c b/firmware/application/src/app_main.c index 8988c4a..ec240b0 100644 --- a/firmware/application/src/app_main.c +++ b/firmware/application/src/app_main.c @@ -295,24 +295,24 @@ static void system_off_enter(void) { // Turn off all soft timers app_timer_stop_all(); - // 检查是否存在低频场,解决休眠时有非常强的场信号一直使比较器处于高电平输入状态从而无法产生上升沿而无法唤醒系统的问题。 + // Check whether there are low -frequency fields, solving very strong field signals during dormancy have always caused the comparator to be at a high level input state, so that the problem of uprising the rising edge cannot be awakened. if (lf_is_field_exists()) { - // 关闭比较器 + // Close the comparator nrf_drv_lpcomp_disable(); - // 设置reset原因,重启后需要拿到此原因,避免误判唤醒源 + // Set the reason for Reset. After restarting, you need to get this reason to avoid misjudgment from the source of wake up. sd_power_gpregret_clr(1, GPREGRET_CLEAR_VALUE_DEFAULT); sd_power_gpregret_set(1, RESET_ON_LF_FIELD_EXISTS_Msk); - // 触发reset唤醒系统,重新启动模拟过程 + // Trigger the RESET awakening system, restart the simulation process nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_RESET); return; }; // Go to system-off mode (this function will not return; wakeup will cause a reset). - // 注意,如果插着jlink或者开着debug,进入低功耗的函数可能会报错, - // 开启调试时我们应当禁用低功耗状态值检测,或者干脆不进入低功耗 + // Note that if you insert jlink or drive a Debug, you may report an error when entering the low power consumption. + // When starting debugging, we should disable low power consumption state values, or simply not enter low power consumption ret = sd_power_system_off(); - // OK,此处非常重要,如果开启了日志输出并且使能了RTT,则不去检查低功耗模式的错误 + // OK, here is very important. If you open the log output and enable RTT, you will not check the error of the low power mode #if !(NRF_LOG_ENABLED && NRF_LOG_BACKEND_RTT_ENABLED) APP_ERROR_CHECK(ret); #else @@ -389,7 +389,7 @@ static void check_wakeup_src(void) { } } - // 当前是模拟卡事件唤醒系统,我们可以让场强灯先亮起来 + // It is currently the wake -up system of the simulation card event, we can make the strong lights on the field first TAG_FIELD_LED_ON(); uint8_t animation_config = settings_get_animation_config(); diff --git a/firmware/application/src/app_status.h b/firmware/application/src/app_status.h index aef73d9..ea8d764 100644 --- a/firmware/application/src/app_status.h +++ b/firmware/application/src/app_status.h @@ -5,42 +5,42 @@ ///////////////////////////////////////////////////////////////////// // 14a status ///////////////////////////////////////////////////////////////////// -#define HF_TAG_OK (0x00) // IC卡操作成功 -#define HF_TAG_NO (0x01) // 没有发现IC卡 -#define HF_ERRSTAT (0x02) // IC卡通信异常 -#define HF_ERRCRC (0x03) // IC卡通信校验异常 -#define HF_COLLISION (0x04) // IC卡冲突 -#define HF_ERRBCC (0x05) // IC卡BCC错误 -#define MF_ERRAUTH (0x06) // MF卡验证失败 -#define HF_ERRPARITY (0x07) // IC卡奇偶校验错误 +#define HF_TAG_OK (0x00) // IC card operation successfully +#define HF_TAG_NO (0x01) // No IC card found +#define HF_ERRSTAT (0x02) // IC cartoon letter abnormal +#define HF_ERRCRC (0x03) // IC Card communication verification abnormality +#define HF_COLLISION (0x04) // IC card conflict +#define HF_ERRBCC (0x05) // IC card BCC error +#define MF_ERRAUTH (0x06) // MF card verification failed +#define HF_ERRPARITY (0x07) // ica Kazi even verification error ///////////////////////////////////////////////////////////////////// // MIFARE status ///////////////////////////////////////////////////////////////////// -#define DARKSIDE_CANT_FIXED_NT (0x20) // Darkside,无法固定随机数,这个情况可能出现在UID卡上 -#define DARKSIDE_LUCK_AUTH_OK (0x21) // Darkside,直接验证成功了,可能刚好密钥是空的 -#define DARKSIDE_NACK_NO_SEND (0x22) // Darkside,卡片不响应nack,可能是一张修复了nack逻辑漏洞的卡片 -#define DARKSIDE_TAG_CHANGED (0x23) // Darkside,在运行darkside的过程中出现了卡片切换,可能信号问题,或者真的是两张卡迅速切换了 -#define NESTED_TAG_IS_STATIC (0x24) // Nested,检测到卡片应答的随机数是固定的 -#define NESTED_TAG_IS_HARD (0x25) // Nested,检测到卡片应答的随机数是不可预测的 +#define DARKSIDE_CANT_FIXED_NT (0x20) // Darkside, the random number cannot be fixed, this situation may appear on the UID card +#define DARKSIDE_LUCK_AUTH_OK (0x21) // Darkside, the direct verification is successful, maybe the key is just empty +#define DARKSIDE_NACK_NO_SEND (0x22) // Darkside, the card does not respond to NACK, it may be a card that fixes Nack logic vulnerabilities +#define DARKSIDE_TAG_CHANGED (0x23) // Darkside, card switching in the process of running DARKSIDE, May is the two cards quickly switched +#define NESTED_TAG_IS_STATIC (0x24) // Nested, the random number of the card response is fixed +#define NESTED_TAG_IS_HARD (0x25) // Nested, the random number of the card response is unpredictable ///////////////////////////////////////////////////////////////////// // lf status ///////////////////////////////////////////////////////////////////// -#define LF_TAG_OK (0x40) // 低频卡的一些操作成功! -#define EM410X_TAG_NO_FOUND (0x41) // 无法搜索到有效的EM410X标签 +#define LF_TAG_OK (0x40) // Some of the low -frequency cards are successful! +#define EM410X_TAG_NO_FOUND (0x41) // Can't search for valid EM410X tags ///////////////////////////////////////////////////////////////////// // other status ///////////////////////////////////////////////////////////////////// -#define STATUS_PAR_ERR (0x60) // BLE指令传递的参数错误,或者是调用某些函数传递的参数错误 -#define STATUS_DEVIEC_MODE_ERROR (0x66) // 当前设备所处的模式错误,无法调用对应的API -#define STATUS_INVALID_CMD (0x67) // 无效的指令 -#define STATUS_DEVICE_SUCCESS (0x68) // 设备相关操作成功执行 -#define STATUS_NOT_IMPLEMENTED (0x69) // 调用了某些未实现的操作,属于开发者遗漏的错误 -#define STATUS_FLASH_WRITE_FAIL (0x70) // flash写入失败 -#define STATUS_FLASH_READ_FAIL (0x71) // flash读取失败 +#define STATUS_PAR_ERR (0x60) // The parameter errors transferred by the BLE instruction, or call the parameter error transmitted by certain functions +#define STATUS_DEVIEC_MODE_ERROR (0x66) // The mode of the current device is wrong, and the corresponding API cannot be called +#define STATUS_INVALID_CMD (0x67) // Invalid instruction +#define STATUS_DEVICE_SUCCESS (0x68) // Device -related operations successfully executed +#define STATUS_NOT_IMPLEMENTED (0x69) // Calling some unrealized operations, which belongs to the missed error of the developer +#define STATUS_FLASH_WRITE_FAIL (0x70) // Flash writing failed +#define STATUS_FLASH_READ_FAIL (0x71) // Flash read failed #endif diff --git a/firmware/application/src/ble_main.c b/firmware/application/src/ble_main.c index a5abea5..b7d7f94 100644 --- a/firmware/application/src/ble_main.c +++ b/firmware/application/src/ble_main.c @@ -189,19 +189,19 @@ __INLINE uint32_t map(uint32_t x, uint32_t in_min, uint32_t in_max, uint32_t out return (uint32_t)((x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min); } -//电池电压到百分比计算 +//Battery voltage to percentage calculation uint32_t BATVOL2PERCENT(uint16_t VOL) { //100% 4.20V 1 - //90 % 4.06V 80%-100% 白 + //90 % 4.06V 80%-100% white //80 % 3.98V 1 - //70 % 3.92V 60%-80% 白 + //70 % 3.92V 60%-80% white //60 % 3.87V 1 - //50 % 3.82V 40%-60% 白 + //50 % 3.82V 40%-60% white //40 % 3.79V 1 - //30 % 3.77V 20%-40% 白 + //30 % 3.77V 20%-40% white //20 % 3.74V 1 - //10 % 3.68V 5%-20% 红 - //5 % 3.45V 1 关机 + //10 % 3.68V 5%-20% red + //5 % 3.45V 1 Turn off //0 % 3.00V //#define P100VOL 4200 //#define P80VOL 3980 @@ -211,16 +211,16 @@ uint32_t BATVOL2PERCENT(uint16_t VOL) { //#define P5VOL 3450 //100% 4.20V 1 - //90 % 4.00V 80%-100% 白 + //90 % 4.00V 80%-100% white //80 % 3.89V 1 - //70 % 3.79V 60%-80% 白 + //70 % 3.79V 60%-80% white //60 % 3.70V 1 - //50 % 3.62V 40%-60% 白 + //50 % 3.62V 40%-60% white //40 % 3.57V 1 - //30 % 3.53V 20%-40% 白 + //30 % 3.53V 20%-40% white //20 % 3.51V 1 - //10 % 3.46V 5%-20% 红 - //5 % 3.43V 1 关机 + //10 % 3.46V 5%-20% red + //5 % 3.43V 1 Turn off //0 % 3.00V #define P100VOL 4200 #define P80VOL 3890 @@ -610,12 +610,12 @@ void create_battery_timer(void) { * @brief Function for init ble slave. */ void ble_slave_init(void) { - adc_configure(); // ADC初始化 - create_battery_timer(); // 创建电池电量更新定时器 - ble_stack_init(); // BLE协议栈初始化 - gap_params_init(); // GAP参数初始化 - gatt_init(); // GATT协议初始化 - services_init(); // 服务特征初始化 - advertising_init(); // 广播参数初始化 - conn_params_init(); // 连接参数初始化 + adc_configure(); // ADC initialization + create_battery_timer(); // Create a battery power update timer + ble_stack_init(); // BLE protocol stack initialization + gap_params_init(); // GAP parameter initialization + gatt_init(); // Gatt protocol initialization + services_init(); // Initialization of service characteristics + advertising_init(); // Broadcast parameter initialization + conn_params_init(); // Connection parameter initialization } diff --git a/firmware/application/src/bsp/bsp_delay.c b/firmware/application/src/bsp/bsp_delay.c index 759fb19..07dccf6 100644 --- a/firmware/application/src/bsp/bsp_delay.c +++ b/firmware/application/src/bsp/bsp_delay.c @@ -3,18 +3,18 @@ #include "nrf_delay.h" -//初始化延迟函数 +//Initialized delay function void bsp_delay_init(void) { } -//延时nms -//注意nms的范围 +//Delay NMS +//Pay attention to the range of NMS void bsp_delay_ms(uint16_t nms) { nrf_delay_us(nms * 1000); } -//延时nus -//nus为要延时的us数. +//Delay NUS +//NUS is the number of US numbers to be delayed. void bsp_delay_us(uint32_t nus) { nrf_delay_us(nus); } diff --git a/firmware/application/src/bsp/bsp_time.c b/firmware/application/src/bsp/bsp_time.c index d701147..7b5738d 100644 --- a/firmware/application/src/bsp/bsp_time.c +++ b/firmware/application/src/bsp/bsp_time.c @@ -2,16 +2,16 @@ #include "app_timer.h" -#define TICK_PERIOD APP_TIMER_TICKS(10) // 定时时间 +#define TICK_PERIOD APP_TIMER_TICKS(10) // Timing -// 定义一个软定时器 +// Define a soft timer APP_TIMER_DEF(m_app_timer); -// 定时器池 +// Timer pool autotimer bsptimers[TIMER_BSP_COUNT] = { 0 }; -// 定时器迭代位置 +// Timer iteration position static uint8_t g_timer_fori; -// 当前定时器运行状态 +// The current timer is running status static volatile enum { UNINIT, INIT, @@ -21,9 +21,9 @@ static volatile enum { /* -* 获取一个空闲的定时器,这个定时器 -* 1、会自动跑滴答 -* 2、是空闲的 +* Get a free timer, this timer +* 1. Will run automatically +* 2. It's free */ autotimer *bsp_obtain_timer(uint32_t start_value) { uint8_t i; @@ -38,7 +38,7 @@ autotimer *bsp_obtain_timer(uint32_t start_value) { } /* -* 设置定时器,该操作会操作目标定时器,修改当前值 +* Set the timer, the operation will operate the target timer and modify the current value */ inline uint8_t bsp_set_timer(autotimer *timer, uint32_t start_value) { if (timer->busy == 0) return 0; @@ -47,17 +47,17 @@ inline uint8_t bsp_set_timer(autotimer *timer, uint32_t start_value) { } /* -* 归还定时器,该操作会自动释放定时器 -* 并且对定时器归零 +* Return the timer, the operation will automatically release the timer +* And zero to the timer */ inline void bsp_return_timer(autotimer *timer) { timer->busy = 0; timer->time = 0; } -/** @brief 测试定时器的回调函数 - * @param arg 回调参数 - * @return 无 +/** @brief Test timer callback function + * @param arg Callback parameter + * @return none */ void timer_app_callback(void *arg) { UNUSED_PARAMETER(arg); @@ -68,26 +68,26 @@ void timer_app_callback(void *arg) { } } -// 初始化定时器 +// Initialized timer void bsp_timer_init(void) { if (bsp_timer_state == UNINIT) { bsp_timer_state = INIT; - // 创建定时器 + // Create a timer ret_code_t err_code = app_timer_create(&m_app_timer, APP_TIMER_MODE_REPEATED, timer_app_callback); APP_ERROR_CHECK(err_code); } } -// 反初始化定时器 +// Counter -initialization timer void bsp_timer_uninit(void) { - // 暂时无法反初始化软定时器,只能关闭 + // Can't reverse the initialized soft timer for the time being, it can only be closed bsp_timer_stop(); } -// 启动定时器 +// Start the timer void bsp_timer_start(void) { if (bsp_timer_state != UNINIT) { - // 确保定时器没有被启动过 + // Make sure the timer is not started if (bsp_timer_state != START) { app_timer_start(m_app_timer, TICK_PERIOD, NULL); bsp_timer_state = START; @@ -96,11 +96,11 @@ void bsp_timer_start(void) { } -// 停止定时器 +// Stop timer void bsp_timer_stop(void) { if (bsp_timer_state != UNINIT) { if (bsp_timer_state == START) { - // 停止定时器 + // Stop timer app_timer_stop(m_app_timer); bsp_timer_state = STOP; } diff --git a/firmware/application/src/bsp/bsp_time.h b/firmware/application/src/bsp/bsp_time.h index d2a7101..f14e0d7 100644 --- a/firmware/application/src/bsp/bsp_time.h +++ b/firmware/application/src/bsp/bsp_time.h @@ -6,20 +6,20 @@ #ifndef NULL #define NULL ((void *)0) #endif -//定义可以同时使用的计时器的最多数量 +//Define the maximum number of timer that can be used at the same time #define TIMER_BSP_COUNT 10 -// 定义一个结构体 -// 这个结构体存放了基本的时钟信息 +// Define a structure +// This structure stores basic clock information typedef struct { - // 当前定时器的滴答数 + // The number of ticks of the current timer volatile uint32_t time; - // 是否繁忙 + // Whether it is busy uint8_t busy; } autotimer; -// 实现一个判断超时的宏定义 +// Realize a grand definition of judgment timeout #define NO_TIMEOUT_1MS(timer, count) ((((autotimer*)timer)->time <= (count))? 1: 0) void bsp_timer_init(void); diff --git a/firmware/application/src/rfid/crc_utils.c b/firmware/application/src/rfid/crc_utils.c index 6cc3f48..c3ab104 100644 --- a/firmware/application/src/rfid/crc_utils.c +++ b/firmware/application/src/rfid/crc_utils.c @@ -1,6 +1,6 @@ #include "crc_utils.h" -// CRC查表 +//CRC check table static uint16_t crc_table[256] = { 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, @@ -38,17 +38,17 @@ static uint16_t crc_table[256] = { /** - * @brief 在MCU上使用查表法计算14443a协议专用的CRC(crc16) - * @param data 将被计算的CRC的原始数据 - * @param length 数据的长度,不包括CRC - * @param output 输出缓冲区,长度必须是大于等于两个字节 + * @brief Use the table check method on the MCU to calculate the CRC (CRC16) dedicated to the 144443A protocol. + * @param data The original data of the calculated CRC + * @param length The length of the data does not include CRC + * @param output The output buffer must be greater than or equal to two bytes * */ void calc_14a_crc_lut(uint8_t *data, int length, uint8_t *output) { - // 取巧,强制指针类型转换 + //Take the clever, compulsory pointer type conversion uint16_t *crc = (uint16_t *)output; - // 赋予多项式初始值 + //Give the initial value of polynomial *crc = 0x6363; - // 然后开始对每个字节进行查表 + //Then start checking the table of each byte while (length--) *crc = (*crc >> 8) ^ crc_table[(*crc & 0xFF) ^ *data++]; } diff --git a/firmware/application/src/rfid/hex_utils.c b/firmware/application/src/rfid/hex_utils.c index b535368..108089c 100644 --- a/firmware/application/src/rfid/hex_utils.c +++ b/firmware/application/src/rfid/hex_utils.c @@ -2,11 +2,11 @@ /** -* @brief : 将大数字转换为HEX字节数组 -* @param :n : 将被转换的值 -* @param :len : 存放转换后的数值的字节长度 -* @param :dest : 存放转换结果的缓冲区 -* @retval : 无 +* @brief : Convert the large number to the hex byte array +* @param :n : The value of the conversion +* @param :len : The byte length of the value after the conversion is stored +* @param :dest : Caps that store conversion results +* @retval : none * */ void num_to_bytes(uint64_t n, uint8_t len, uint8_t *dest) { @@ -17,10 +17,10 @@ void num_to_bytes(uint64_t n, uint8_t len, uint8_t *dest) { } /** -* @brief : 将字节数组转换为大数字 -* @param :len : 存放数值的缓冲区的字节长度 -* @param :src : 存放数值的字节缓冲区 -* @retval : 转换结果 +* @brief : Convert byte array to large number +* @param :len : The byte length of the buffer of the value of the value +* @param :src : Byte buffer stored in the numerical +* @retval : Converting result * */ uint64_t bytes_to_num(uint8_t *src, uint8_t len) { diff --git a/firmware/application/src/rfid/nfctag/hf/crypto1_helper.c b/firmware/application/src/rfid/nfctag/hf/crypto1_helper.c index dcbc4e8..3492ecf 100644 --- a/firmware/application/src/rfid/nfctag/hf/crypto1_helper.c +++ b/firmware/application/src/rfid/nfctag/hf/crypto1_helper.c @@ -24,9 +24,9 @@ void mf_crypto1_encryptEx(struct Crypto1State *pcs, uint8_t *data_in, uint8_t *k int i; for (i = 0; i < len; i++) { uint8_t bt = data_in[i]; - // 加密字节流 + // Encrypted bytes data_out[i] = crypto1_byte(pcs, keystream ? keystream[i] : 0x00, 0) ^ data_in[i]; - // 生成奇偶校验位 + // Generate strange school inspection par[i] = filter(pcs->odd) ^ oddparity8(bt); } } diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_14a.c b/firmware/application/src/rfid/nfctag/hf/nfc_14a.c index 7817562..e68b5e5 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_14a.c +++ b/firmware/application/src/rfid/nfctag/hf/nfc_14a.c @@ -23,7 +23,7 @@ NRF_LOG_MODULE_REGISTER(); #define NRF_NFCT_PARITY_FRAMECONFIG 0x04; #endif -// 使用宏定义展开数据的接收使能实现 +//Use macro definition data to receive data enable to achieve #define NRFX_NFCT_RX_BYTES \ do { \ NRF_NFCT->RXD.FRAMECONFIG = NRF_NFCT_PARITY_FRAMECONFIG; \ @@ -36,17 +36,17 @@ NRF_LOG_MODULE_REGISTER(); } while(0); -// 14443a协议状态机 +//14443A protocol status machine nfc_tag_14a_state_t m_tag_state_14a = NFC_TAG_STATE_14A_IDLE; -// 14443a协议处理器 +// 14443A protocol processor nfc_tag_14a_handler_t m_tag_handler = { - .cb_reset = NULL, // 标签重置回调 - .cb_state = NULL, // 标签状态机回调 - .get_coll_res = NULL, // 标签的防冲突资源的获取封装 + .cb_reset = NULL, // Tag Resetback + .cb_state = NULL, // Label status machine callback + .get_coll_res = NULL, // Obtain packaging of anti -conflict resources of labels }; -// 字节镜像 +// Byte mirror const uint8_t ByteMirror[256] = { 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, @@ -82,7 +82,7 @@ const uint8_t ByteMirror[256] = { 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, }; -// RATS FSDI 长度查表 +// RATS FSDI length check table const uint16_t ats_fsdi_table[] = { // 0 - 8 16, 24, 32, 40, 48, 64, 96, 128, 256, @@ -91,20 +91,20 @@ const uint16_t ats_fsdi_table[] = { }; -// 当前是否已经应答 +// Whether it is responding to static volatile bool m_is_responded = false; -// 接收缓冲区 +// Receiving buffer static uint8_t m_nfc_rx_buffer[MAX_NFC_RX_BUFFER_SIZE] = { 0x00 }; static uint8_t m_nfc_tx_buffer[MAX_NFC_TX_BUFFER_SIZE] = { 0x00 }; -// N次级联需要用上的SAK,在SAK中的 '第三个' 比特为1时,标志UID不完整 +// The N -secondary connection needs to use SAK, when the "third 'bit' in SAK is 1 is 1, the logo UID is incomplete static uint8_t m_uid_incomplete_sak[] = { 0x04, 0xda, 0x17 }; /** - * @brief 计算BCC + * @brief Calculate BCC * */ void nfc_tag_14a_create_bcc(uint8_t *pbtData, size_t szLen, uint8_t *pbtBcc) { - // 最好是在使用输出缓冲区时重置其 + // It is best to reset it when using the output buffer *pbtBcc = 0x00; do { *pbtBcc ^= *pbtData++; @@ -112,7 +112,7 @@ void nfc_tag_14a_create_bcc(uint8_t *pbtData, size_t szLen, uint8_t *pbtBcc) { } /** - * @brief 追加BCC到数据流尾部 + * @brief Add BCC to the end of the data streaming * */ inline void nfc_tag_14a_append_bcc(uint8_t *pbtData, size_t szLen) { @@ -120,8 +120,8 @@ inline void nfc_tag_14a_append_bcc(uint8_t *pbtData, size_t szLen) { } /** - * @brief 在数据流尾部追加CRC,记住: - * pbtData一定要有足够的长度去容纳CRC计算结果(两个字节) + * @brief Add CRC at the end of the data flow, remember: + * PBTData must have enough length to accommodate the CRC calculation results (two bytes) * */ inline void nfc_tag_14a_append_crc(uint8_t *pbtData, size_t szLen) { @@ -129,7 +129,7 @@ inline void nfc_tag_14a_append_crc(uint8_t *pbtData, size_t szLen) { } /** - * @brief 检查CRC是否正确 + * @brief Check whether the CRC is correct * */ bool nfc_tag_14a_checks_crc(uint8_t *pbtData, size_t szLen) { @@ -141,17 +141,17 @@ bool nfc_tag_14a_checks_crc(uint8_t *pbtData, size_t szLen) { } /** -* @brief :包装ISO14443A的比特帧 -* 自动进行奇偶校验位与数据的包装合并 -* @param :pbtTx:将要传输的比特流 -* szTxBits:比特流的长度 -* pbtTxPar:奇偶校验位的比特流,这个数据的长度一定是 szTxBits / 8,也就是说 -* 实际上合并之后的比特流的组成结构为: +* @brief : Bit frames for packaging ISO14443A +* Automatically conduct the merger of the parity of the coupling school and the data of the data +* @param pbtTx: Bit flow to be transmitted +* szTxBits: The length of the bandwing +* pbtTxPar: Bit flow of the puppet school inspection, the length of this data must be sztxbits / 8, that is, +* In fact, the composition of the bit flow after the merger is: * data(1byte) - par(1bit) - data(1byte) - par(1bit) ... * 00001000 - 0 - 10101110 - 1 -* 这种类似的数据结构 -* pbtFrame: 最终组装完成的数据的缓冲区 -* @retval :比特流组装结果缓冲区的长度,注意,是比特长度,换算字节请除以8再取模 +* This similar data structure +* pbtFrame: The final assembled data buffer +* @retval :The length of the bit flow assembly results buffer. Note that it is the length of the bit. */ uint8_t nfc_tag_14a_wrap_frame(const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtFrame) { uint8_t btData; @@ -207,13 +207,13 @@ uint8_t nfc_tag_14a_wrap_frame(const uint8_t *pbtTx, const size_t szTxBits, cons } /** -* @brief :解包ISO14443A的比特帧 -* 自动进行奇偶校验位与数据的解包分离 -* @param :pbtFrame:将要解包的比特流 -* szFrameBits:比特流的长度 -* pbtRx:解包后的比特流的存放的缓冲区,数据区 -* pbtRxPar: 解包后的比特流的存放的缓冲区,奇偶校验位区 -* @retval :比特流解包后的数据长度,注意,是数据区的比特流长度,换算字节请 retval / 8 +* @brief :Bit frame of ISO14443A +* Automatically perform the unpacking of the puppet school inspection and the data +* @param :pbtFrame:Bit flow that will be dismissed +* szFrameBits:The length of the bandwing +* pbtRx:Caps, data areas, data areas, data areas, data areas, data areas. +* pbtRxPar: The buffer of the Bitflow Store after the packaging, the coupling school inspection area +* @retval :The data length of the Bit flow packaging, note that the length of the data area is the length of the data area.retval / 8 */ uint8_t nfc_tag_14a_unwrap_frame(const uint8_t *pbtFrame, const size_t szFrameBits, uint8_t *pbtRx, uint8_t *pbtRxPar) { uint8_t btFrame; @@ -288,21 +288,21 @@ uint8_t nfc_tag_14a_unwrap_frame(const uint8_t *pbtFrame, const size_t szFrameBi } while(0); \ -/**@brief 发送字节流的函数实现,此实现自动发送SOF +/**@brief The function of sending the byte flow, this implementation automatically sends SOF * - * @param[in] data 要发送的字节流数据 - * @param[in] bytes 要发送的字节流的长度 - * @param[in] appendCrc 是否在发送完成字节流后,自动追加发送crc16校验 + * @param[in] data The byte flow data to be sent + * @param[in] bytes The length of the byte flow to be sent + * @param[in] appendCrc Whether to send the byte flow, automatically send the CRC16 verification automatically */ void nfc_tag_14a_tx_bytes(uint8_t *data, uint32_t bytes, bool appendCrc) { NFC_14A_TX_BYTE_CORE(data, bytes, appendCrc, NRF_NFCT_FRAME_DELAY_MODE_WINDOW); } -/**@brief 发送字节流的函数实现,此实现自动发送SOF +/**@brief The function of sending the byte flow, this implementation automatically sends SOF * - * @param[in] data 要发送的字节流数据 - * @param[in] bytes 要发送的字节流的长度 - * @param[in] appendCrc 是否在发送完成字节流后,自动追加发送crc16校验 + * @param[in] data The byte flow data to be sent + * @param[in] bytes The length of the byte flow to be sent + * @param[in] appendCrc Whether to send the byte flow, automatically send the CRC16 verification automatically */ void nfc_tag_14a_tx_bytes_delay_freerun(uint8_t *data, uint32_t bytes, bool appendCrc) { NFC_14A_TX_BYTE_CORE(data, bytes, appendCrc, NRF_NFCT_FRAME_DELAY_MODE_FREERUN); @@ -324,10 +324,10 @@ void nfc_tag_14a_tx_bytes_delay_freerun(uint8_t *data, uint32_t bytes, bool appe NRF_NFCT->TASKS_STARTTX = 1; \ } while(0); \ -/**@brief 发送bit流的函数实现,此实现自动发送SOF +/**@brief The function of sending the BIT stream, this implementation automatically sends SOF * - * @param[in] data 要发送的bit流数据 - * @param[in] bits 要发送的bit流的长度 + * @param[in] data BIT stream data to be sent + * @param[in] bits The length of the bit stream to be sent */ void nfc_tag_14a_tx_bits(uint8_t *data, uint32_t bits) { m_is_responded = true; @@ -335,10 +335,10 @@ void nfc_tag_14a_tx_bits(uint8_t *data, uint32_t bits) { NFC_14A_TX_BITS_CORE(bits, NRF_NFCT_FRAME_DELAY_MODE_FREERUN); } -/**@brief 发送N个bit的函数实现,此实现自动发送SOF +/**@brief The function of sending n bits is implemented, and this implementation is automatically sent SOF * - * @param[in] data 要发送的bit数据 - * @param[in] bits 要发送几个bit + * @param[in] data BIT data to be sent + * @param[in] bits To send a few bites */ void nfc_tag_14a_tx_nbit(uint8_t data, uint32_t bits) { m_is_responded = true; @@ -346,10 +346,10 @@ void nfc_tag_14a_tx_nbit(uint8_t data, uint32_t bits) { NFC_14A_TX_BITS_CORE(bits, NRF_NFCT_FRAME_DELAY_MODE_FREERUN); } -/**@brief 发送N个bit的函数实现,此实现自动发送SOF +/**@brief The function of sending n bits is implemented, and this implementation is automatically sent SOF * - * @param[in] data 要发送的bit数据 - * @param[in] bits 要发送几个bit + * @param[in] data BIT data to be sent + * @param[in] bits To send a few bites */ void nfc_tag_14a_tx_nbit_delay_window(uint8_t data, uint32_t bits) { m_is_responded = true; @@ -358,51 +358,51 @@ void nfc_tag_14a_tx_nbit_delay_window(uint8_t data, uint32_t bits) { } /** - * 14a监听到PCD过来的数据处理的封装函数 + * 14A monitoring the packaging function of data processing from PCD */ void nfc_tag_14a_data_process(uint8_t *p_data) { - // 统计一下当前收到的bit数 + // Statistize the number of bit currently received uint16_t szDataBits = (NRF_NFCT->RXD.AMOUNT & (NFCT_RXD_AMOUNT_RXDATABITS_Msk | NFCT_RXD_AMOUNT_RXDATABYTES_Msk)); - // 防冲撞可能要用上的资源 + // The resource that may be used in anti -collision nfc_tag_14a_coll_res_referen_t *auto_coll_res = m_tag_handler.get_coll_res != NULL ? m_tag_handler.get_coll_res() : NULL; - // 我也不知道为什么,这里CPU必须要空跑一段周期,数据才能正常收到。 - // 如果接收数据有任何问题,请尝试恢复此处,这个是2021年发现的问题,但是2022年又消失了 - // 可能是由于更新了SDK版本 + // I don't know why, here the CPU must run empty for a period of time before the data can be received normally. + // If you have any problems with the receiving data, please try to restore this. This is a problem found in 2021, but it disappeared again in 2022 + // It may be due to the update of the SDK version // for (int i = 0; i < 88; i++) __NOP(); - // 一定要确保接收到的数据无误,上限和下限都要判断处理!!! + // Be sure to ensure that the received data is correct.IntersectionIntersection if (0 == szDataBits || (szDataBits > (MAX_NFC_RX_BUFFER_SIZE * 8))) { // NRF_LOG_INFO("Invalid size: %d\n", szDataBits); - // 如果有异常的数据接收到,我们直接跳过,不处理, - // 因为这个有可能干扰导致的错误接收事件 + // If there are abnormal data received, we skip it directly without processing, + // Because of this error receiving event caused by this possible interference return; } - // 手动抽帧,分离数据和奇偶校验位 + // Manually draw frame, separate data and strange school inspection #if !NFC_TAG_14A_RX_PARITY_AUTO_DEL_ENABLE if (szDataBits >= 9) { - // 由于我们暂时不需奇偶校验位,所以取出的时候直接丢弃 + //Since we do not need a strange school test for the time being, discard it directly when we take it out szDataBits = nfc_tag_14a_unwrap_frame(p_data, szDataBits, p_data, NULL); } #endif - // 开始处理接收到的数据,如果是比特帧可以将数据交由此环节处理 + // Start processing the received data, if it is a special frame, you can hand over the data to this link if (szDataBits <= 8) { - // 我们可能收到了一个wupa或者reqa指令,或者其他的特殊指令 + // We may receive a Wupa or REQA instruction, or other special instructions bool isREQA = (p_data[0] == NFC_TAG_14A_CMD_REQA); bool isWUPA = (p_data[0] == NFC_TAG_14A_CMD_WUPA); - // 触发条件为:非halt模式下的REQA响应 - // 暂时全通过:非选择状态下的WUPA响应,现在无论处于何种状态都能用WUPA指令唤醒 + // The trigger conditions are: Reqa response in non -Halt mode + // Temporary through: Wupa response in non -choice state, no matter what state is in the state, you can use the Wupa instruction to wake up if ((szDataBits == 7) && ((isREQA && m_tag_state_14a != NFC_TAG_STATE_14A_HALTED) || isWUPA)) { - // 通知14a通信的接管者们,该重置内部状态机了 + // The receiver of the 14A communication is notified, the internal state machine is reset if (m_tag_handler.cb_reset != NULL) { m_tag_handler.cb_reset(); } - // 仅在能提供防冲撞资源的情况下, + // Only in the case that can provide anti -collision resources, if (auto_coll_res != NULL) { - // 状态机设置为准备状态,下次操作是进入选卡环节 + // The status machine is set to the preparation state, and the next operation is to enter the card selection link m_tag_state_14a = NFC_TAG_STATE_14A_READY; - // 收到了wupa或者reqa指令,此时我们需要回复atqa + // After receiving the WUPA or REQA instruction, we need to reply to ATQA nfc_tag_14a_tx_bytes(auto_coll_res->atqa, 2, false); // NRF_LOG_INFO("ATQA reply."); } else { @@ -411,32 +411,32 @@ void nfc_tag_14a_data_process(uint8_t *p_data) { } return; } else { - // TODO 此处可以匹配一些其他的指令,回调一些注册好的处理函数单独处理此逻辑 - // 正常通信过程不会有N个比特的帧,因为那是14a协议里面用于面向bit的防冲突帧 - // 所以此处可以单独处理这个协议帧,实现类似UID后门卡的标签(chinese magic) - // 注意,我们如果是发现了REQA或者WUPA,就不去重复处理了(只处理特殊比特帧) + // TODOHere you can match some other instructions, call back some registered processing functions to handle this logic separately + // Normal communication process will not have N bits of frames, because it is the anti -conflict frame used in the 14A protocol for BIT + // So you can handle this protocol frame separately here to realize the tag similar to the UID back door card (Chinese Magic) + // Note that if we find Reqa or wupa, we will not repeat the processing (only the special ratio special frame) if ((!isREQA && !isWUPA) && m_tag_handler.cb_state != NULL) { - // 如果7bit的处理器被注册并且成功的处理了此命令,则完成此次状态机更新 + // If the 7bit processor is registered and successfully processed this command, the state machine update is completed m_tag_handler.cb_state(p_data, szDataBits); return; } } return; } - // 根据当前卡片的状态做出相应的处理 + //Make corresponding treatment according to the status of the current card switch (m_tag_state_14a) { - // 空闲状态和休眠状态不处理任何任务,就让来自星星的消息随风而去吧~ + // If you do not handle any tasks in the idle state and the dormant state, let the news from the stars go with the wind ~ case NFC_TAG_STATE_14A_IDLE: case NFC_TAG_STATE_14A_HALTED: { break; } - // 准备状态,处理跟防冲撞有关的消息 + // Preparation status, processing news related to anti -collision case NFC_TAG_STATE_14A_READY: { static uint8_t uid[5] = { 0x00 }; nfc_tag_14a_cascade_level_t level; // Extract cascade level if (szDataBits >= 16) { - // 匹配级联指令 + // Matching grade joint instructions switch (p_data[0]) { case NFC_TAG_14A_CMD_ANTICOLL_OR_SELECT_1: level = NFC_TAG_14A_CASCADE_LEVEL_1; @@ -453,59 +453,59 @@ void nfc_tag_14a_data_process(uint8_t *p_data) { } return; default: { - // 收到了错误的级联指令,直接重置状态机 + // After receiving the wrong level instruction, directly reset the status machine NRF_LOG_INFO("[MFEMUL_SELECT] Incorrect cascade level received: %02x", p_data[0]); m_tag_state_14a = NFC_TAG_STATE_14A_IDLE; return; } } - // 匹配UID长度,为uid的返回数据做准备 + // Match the length of UID and prepare for the return data of UID switch (*auto_coll_res->size) { case NFC_TAG_14A_UID_SINGLE_SIZE: { - if (level == NFC_TAG_14A_CASCADE_LEVEL_1) { // 首次级联,只有一次 - // 4字节的标签最多只能一次级联 + if (level == NFC_TAG_14A_CASCADE_LEVEL_1) { // The first level, only once + // The 4 -byte label can only be connected at most at one time memcpy(uid, auto_coll_res->uid, 4); - } else { // 4字节的卡永远不能进行第二次级联 + } else { // 4 -byte cards can never perform second -level coupons m_tag_state_14a = NFC_TAG_STATE_14A_IDLE; return; } break; } case NFC_TAG_14A_UID_DOUBLE_SIZE: { - if (level == NFC_TAG_14A_CASCADE_LEVEL_1) { // 首次级联,还剩一次 + if (level == NFC_TAG_14A_CASCADE_LEVEL_1) { //At the first time, there is one left uid[0] = NFC_TAG_14A_CASCADE_CT; uid[1] = auto_coll_res->uid[0]; uid[2] = auto_coll_res->uid[1]; uid[3] = auto_coll_res->uid[2]; - } else if (level == NFC_TAG_14A_CASCADE_LEVEL_2) { // 第二次级联已经完整 + } else if (level == NFC_TAG_14A_CASCADE_LEVEL_2) { //The second level is complete memcpy(uid, auto_coll_res->uid + 3, 4); - } else { // 7字节的卡永远不能进行第三次级联 + } else { //The 7 -byte card can never perform the third level m_tag_state_14a = NFC_TAG_STATE_14A_IDLE; return; } break; } case NFC_TAG_14A_UID_TRIPLE_SIZE: { - if (level == NFC_TAG_14A_CASCADE_LEVEL_1) { // 首次级联,还剩两次 + if (level == NFC_TAG_14A_CASCADE_LEVEL_1) { // At the first level, there are two left uid[0] = NFC_TAG_14A_CASCADE_CT; uid[1] = auto_coll_res->uid[0]; uid[2] = auto_coll_res->uid[1]; uid[3] = auto_coll_res->uid[2]; - } else if (level == NFC_TAG_14A_CASCADE_LEVEL_2) { // 第二次级联,还剩余一次级联 + } else if (level == NFC_TAG_14A_CASCADE_LEVEL_2) { // The second level, there is still the remaining first -level joint uid[0] = NFC_TAG_14A_CASCADE_CT; uid[1] = auto_coll_res->uid[3]; uid[2] = auto_coll_res->uid[4]; uid[3] = auto_coll_res->uid[5]; - } else { // 10字节的卡的最后一次级联 + } else { // The last step of the 10 -byte card memcpy(uid, auto_coll_res->uid + 6, 4); } break; } } - // BCC计算,完成最终的防冲撞数据准备 + // BCC calculation, complete the final anti -collision data preparation nfc_tag_14a_append_bcc(uid, 4); } else { - // 收到了错误长度的级联指令,重置状态机 + // Receive the grade joint instructions of the error length, reset the status machine m_tag_state_14a = NFC_TAG_STATE_14A_IDLE; return; } @@ -527,7 +527,7 @@ void nfc_tag_14a_data_process(uint8_t *p_data) { m_tag_state_14a = NFC_TAG_STATE_14A_ACTIVE; nfc_tag_14a_tx_bytes(auto_coll_res->sak, 1, true); } else { - // 此处需要继续级联,因此我们需要回应一个在SAK内标志UID不完整的数据 + // It is necessary to continue the level, so we need to respond to a data that marks the incomplete UID in SAK nfc_tag_14a_tx_bytes(m_uid_incomplete_sak, 3, false); } } else { @@ -542,35 +542,35 @@ void nfc_tag_14a_data_process(uint8_t *p_data) { // NRF_LOG_INFO("[MFEMUL_SELECT] Unknown selection procedure"); break; } - // 激活状态,转发处理任何消息 + // Activation status, repost processing of any message case NFC_TAG_STATE_14A_ACTIVE: { - // 需要判断是否收到了需要直接处理而不转发的指令 + // You need to judge whether you have received instructions that need to be handled directly without forwarding if (szDataBits == 32) { - // HALT指令 + // Halt instruction if (p_data[0] == NFC_TAG_14A_CMD_HALT && p_data[1] == 0x00 && p_data[2] == 0x57 && p_data[3] == 0xCD) { - // 将状态机置为中止态,然后等待下一轮通信 + // Set the status machine to the suspension state, and then wait for the next round of communication m_tag_state_14a = NFC_TAG_STATE_14A_HALTED; return; } - // RATS指令 + // RATS instruction if (p_data[0] == NFC_TAG_14A_CMD_RATS && nfc_tag_14a_checks_crc(p_data, 4)) { - // 确保子封装开启了ATS的支持 + // Make sure the sub -packaging opens the support of ATS if (auto_coll_res->ats->length > 0) { - // 将FSD取出,根据最大FSD进行返回 + // Take out FSD and return according to the maximum FSD uint8_t fsd = ats_fsdi_table[p_data[1] >> 4 & 0x0F] - 2; - // 如果fsd大于设置的ats长度,那么就返回正常的ats数据,否则返回fsd限定长度的数据 + // If the FSD is larger than the set of ATS, then returns normal ATS data, otherwise the data of the FSD limited length will be returned uint8_t len = fsd >= auto_coll_res->ats->length ? auto_coll_res->ats->length : fsd; - // 根据FSD返回ATS数据,FSD是PCD支持的最大帧大小,去掉CRC后才是实际的数据帧大小支持 + // Back to ATS data according to FSD, FSD is the largest frame size supported by PCD. After removing CRC, it is the actual data frame size support nfc_tag_14a_tx_bytes(auto_coll_res->ats->data, len, true); } else { nfc_tag_14a_tx_nbit_delay_window(NAK_INVALID_OPERATION_TBIV, 4); } - // 在外部直接处理了明文发送的RATS指令之后直接等待下一轮通信 + // After handling the explicitly sending RATS instructions outside the outside, wait directly for the next round of communication return; } } - // 没有处理成功,可能是其他的一些数据,需要转发处理 - if (m_tag_handler.cb_state != NULL) { // 激活状态,将消息转由其他被注册的处理器处理 + // No processing is successful, it may be some other data. You need to repost processing + if (m_tag_handler.cb_state != NULL) { //Activation status, transfer the message to other registered processor processing m_tag_handler.cb_state(p_data, szDataBits); break; } @@ -581,7 +581,7 @@ void nfc_tag_14a_data_process(uint8_t *p_data) { extern bool g_usb_led_marquee_enable; /** - * 14a事件回调函数 + * 14A incident callback function */ void nfc_tag_14a_event_callback(nrfx_nfct_evt_t const *p_event) { // Select action to process. @@ -597,8 +597,8 @@ void nfc_tag_14a_event_callback(nrfx_nfct_evt_t const *p_event) { NRF_LOG_INFO("HF FIELD DETECTED"); - // 关闭自动防冲撞,MCU管理所有的交互过程,然后使能NFC外设,使能之后就可以进行IO了 - // 20221108 修复nrf52840与nrf52832不同的使能切换流程 + //Turn off the automatic anti -collision, MCU management all the interaction process, and then enable the NFC peripherals so that Io can be performed after enable + // 20221108 Fix the different enable switching process of NRF52840 and NRF52832 #if defined(NRF52833_XXAA) || defined(NRF52840_XXAA) nrfx_nfct_autocolres_disable(); nrfx_nfct_state_force(NRFX_NFCT_STATE_ACTIVATED); @@ -607,7 +607,7 @@ void nfc_tag_14a_event_callback(nrfx_nfct_evt_t const *p_event) { NRF_NFCT->TASKS_ACTIVATE = 1; #endif - // 直接使能接收 + //Directly enable receiving NRFX_NFCT_RX_BYTES break; } @@ -629,7 +629,7 @@ void nfc_tag_14a_event_callback(nrfx_nfct_evt_t const *p_event) { } case NRFX_NFCT_EVT_TX_FRAMEEND: { // NRF_LOG_INFO("TX end.\n"); - // 传输结束后需要使能接收 + // After the transmission is over, you need to be able to receive it NRFX_NFCT_RX_BYTES break; } @@ -638,26 +638,26 @@ void nfc_tag_14a_event_callback(nrfx_nfct_evt_t const *p_event) { TAG_FIELD_LED_ON() // NRF_LOG_INFO("RX FRAMEEND.\n"); - // TODO 谨记一个BUG,在收到消息后如果不回复消息,就需要手动使能接收 - // 不然上面的 NRFX_NFCT_EVT_TX_FRAMEEND 条件不会触发,不会调用 NRFX_NFCT_RX_BYTES - // 接下来的所有的通信,都将会出问题,出问题了还怎么玩,玩个蛋嘞。 + // TODO Remember a bug, if you do not reply to the message after receiving the message, you need to manually enable you + // Otherwise, the nrfx_nfct_evt_tx_framend conditions above will not be triggered, and nrfx_nfct_rx_bytes will not be called + // All the next communication will have problems. How can I play if there is a problem? Play an egg. m_is_responded = false; - // 多一层压栈,但是似乎对性能影响不大 - // 这个函数处理了读卡器发过来的数据,然后看没有需要回复读卡器,有需要的话就回复 - // 没需要的就不回复,很有道理是吧?这就是科学。 + // One more layer of pressure stack, but it seems to have little effect on performance + // This function processes the data sent by the card reader, and then read that you don't need to reply to the card reader. If you need it, reply + // Don't reply if you don't need it, it makes sense, right?This is science. nfc_tag_14a_data_process(m_nfc_rx_buffer); - // 上面的提示告诉我们,我们在不需要回复读卡器的时候,需要手动使能接收 + // The above prompt tells us that when we do not need to reply to the card reader, we need to manually enable it if (!m_is_responded) { NRFX_NFCT_RX_BYTES } break; } case NRFX_NFCT_EVT_ERROR: { - // 根据错误原因,进行日志打印,以帮助开发时排查可能性的BUG + // According to the error reasons, the log prints to help the development of the possibilities during development switch (p_event->params.error.reason) { case NRFX_NFCT_ERROR_FRAMEDELAYTIMEOUT: { - // 如果我们在通信窗口中回应了标签但是却是没有及时回应,那就需要进行报错打印 - // 如果此错误非常频繁的出现,则可能是MCU处理速度没跟上,此时开发者就需要优化代码了 + //If we respond to the label in the communication window, but we did not respond in time, then we need to make an error printing + // If this error appears very frequently, it may be that the MCU processing speed does not keep up. At this time, the developer needs to optimize the code if (m_is_responded) { NRF_LOG_ERROR("NRFX_NFCT_ERROR_FRAMEDELAYTIMEOUT: %d", m_tag_state_14a); } @@ -678,20 +678,20 @@ void nfc_tag_14a_event_callback(nrfx_nfct_evt_t const *p_event) { } /** - * 14A的状态机更新函数,可将14A标签置为指定的状态 - * @param state 新的状态 + * The 14A status machine update function, which can set the 14A label to the specified state + * @param state New state */ void nfc_tag_14a_set_state(nfc_tag_14a_state_t state) { m_tag_state_14a = state; } /** - * 14A的处理器注册函数 - * @param handler 处理器句柄 + * 14A processor registration function + * @param handler Processor handle */ void nfc_tag_14a_set_handler(nfc_tag_14a_handler_t *handler) { if (handler != NULL) { - // 直接取出传入的实现赋值到我们的全局对象即可 + // Take it directly to the implementation of the introduction to our global object m_tag_handler.cb_reset = handler->cb_reset; m_tag_handler.cb_state = handler->cb_state; m_tag_handler.get_coll_res = handler->get_coll_res; @@ -705,26 +705,26 @@ static enum { } m_nfc_sense_state = NFC_SENSE_STATE_NONE; /** - * 14A的场感应使能和闭能实现函数 - * @param enable 是否使能场感应 + * 14A field sensing enable and closed capacity to implement functions + * @param enable Whether to make the field induction */ void nfc_tag_14a_sense_switch(bool enable) { if (m_nfc_sense_state == NFC_SENSE_STATE_NONE || m_nfc_sense_state == NFC_SENSE_STATE_DISABLE) { if (enable) { m_nfc_sense_state = NFC_SENSE_STATE_ENABLE; - // 初始化中断事件和回调 + // Initialized interrupt event and callback nrfx_nfct_config_t nnct = { .rxtx_int_mask = (uint32_t)0xFFFFFFFF, .cb = nfc_tag_14a_event_callback }; if (nrfx_nfct_init(&nnct) != NRFX_SUCCESS) { NRF_LOG_INFO("Cannot setup NFC!"); } - // 启动场感应 + // Starting field sensing nrfx_nfct_enable(); } } else { if (!enable) { m_nfc_sense_state = NFC_SENSE_STATE_DISABLE; - // 直接反初始化NFC外设即可关闭NFC场感应 - // SDK内部帮我们调用了 nrfx_nfct_disable + //Directly anti -initialization NFC peripherals can turn off NFC field induction + // SDK inside us to call us nrfx_nfct_disable nrfx_nfct_uninit(); } } diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_14a.h b/firmware/application/src/rfid/nfctag/hf/nfc_14a.h index f0056ec..dcac713 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_14a.h +++ b/firmware/application/src/rfid/nfctag/hf/nfc_14a.h @@ -8,7 +8,7 @@ #define NFC_TAG_14A_CRC_LENGTH 2 -// 是否使能自动移除奇偶校验位(硬件移除) +// Whether to automatically remove the coupling school test (hardware removed) #define NFC_TAG_14A_RX_PARITY_AUTO_DEL_ENABLE 0 #define NFC_TAG_14A_CASCADE_CT 0x88 @@ -27,51 +27,51 @@ // TBIV = Transfer Buffer Invalid #define ACK_NAK_FRAME_SIZE 4 /* Bits */ #define ACK_VALUE 0x0A -#define NAK_INVALID_OPERATION_TBV 0x00 // 这个不常用 -#define NAK_CRC_PARITY_ERROR_TBV 0x01 // 这个不常用 +#define NAK_INVALID_OPERATION_TBV 0x00 //This is not commonly used +#define NAK_CRC_PARITY_ERROR_TBV 0x01 //This is not commonly used #define NAK_INVALID_OPERATION_TBIV 0x04 #define NAK_CRC_PARITY_ERROR_TBIV 0x05 -#define NAK_OTHER_ERROR 0x06 // 这个不在手册中定义,属于变色龙特有(可能需要扇区) +#define NAK_OTHER_ERROR 0x06 // This is not defined in the manual, it belongs to the color -changing dragon special (may need the sector) -// ISO14443-A 通用状态机 +// ISO14443-A Universal state machine typedef enum { - NFC_TAG_STATE_14A_IDLE, // 空闲状态,可等待任何指令 - NFC_TAG_STATE_14A_READY, // 选卡状态,当前在进行标准的14A防冲撞 - NFC_TAG_STATE_14A_ACTIVE, // 选卡或者其他指令使其进入工作状态,可接收处理所有的数据 - NFC_TAG_STATE_14A_HALTED, // 标签中止工作状态,只能由halt或者其他特殊指令(非标)唤醒 + NFC_TAG_STATE_14A_IDLE, // Leisure, you can wait for any instructions + NFC_TAG_STATE_14A_READY, // Select card status, currently the standard 14A anti -rushing collision + NFC_TAG_STATE_14A_ACTIVE, // Select cards or other instructions to enter the working status, which can receive all data + NFC_TAG_STATE_14A_HALTED, // The label stops working status and can only be awakened by Halt or other special instructions (non -labels) } nfc_tag_14a_state_t; -// 枚举规范内的长度的UID +//UID of the length in the enumeration specification typedef enum { NFC_TAG_14A_UID_SINGLE_SIZE = 4u, ///< Length of single-size NFCID1. NFC_TAG_14A_UID_DOUBLE_SIZE = 7u, ///< Length of double-size NFCID1. NFC_TAG_14A_UID_TRIPLE_SIZE = 10u, ///< Length of triple-size NFCID1. } nfc_tag_14a_uid_size; -// 枚举规范内的级联等级 +// Extraordinarian level level level level level typedef enum { NFC_TAG_14A_CASCADE_LEVEL_1, NFC_TAG_14A_CASCADE_LEVEL_2, NFC_TAG_14A_CASCADE_LEVEL_3, } nfc_tag_14a_cascade_level_t; -// ats封装结构体 +// ATS packaging structure typedef struct { uint8_t data[0xFF]; uint8_t length; } nfc_14a_ats_t; -// 基于bit的防冲撞需要用上的资源实体,占用空间大 +// Bit -based anti -bumps need to use the resource entity that needs to be used, occupying a large space typedef struct { - nfc_tag_14a_uid_size size; // uid的长度 + nfc_tag_14a_uid_size size; // UID length uint8_t atqa[2]; // atqa uint8_t sak[1]; // sak - uint8_t uid[10]; // uid,最大十个字节 + uint8_t uid[10]; // uid,The largest ten bytes nfc_14a_ats_t ats; } nfc_tag_14a_coll_res_entity_t; -// 防冲突资源的封装引用,纯引用空间占用比较小 +// Calculation of anti -conflict resources, pure quoting space occupation is relatively small typedef struct { nfc_tag_14a_uid_size *size; uint8_t *atqa; @@ -80,31 +80,31 @@ typedef struct { nfc_14a_ats_t *ats; } nfc_tag_14a_coll_res_referen_t; -// 通信接管需要实现的回调函数 +// Communication reception function that needs to be implemented typedef void (*nfc_tag_14a_reset_handler_t)(void); typedef void (*nfc_tag_14a_state_handler_t)(uint8_t *data, uint16_t szBits); typedef nfc_tag_14a_coll_res_referen_t *(*nfc_tag_14a_coll_handler_t)(void); -// 14a通信接管者需要实现的接口 +// The interface that 14A communication receiver needs to be implemented typedef struct { nfc_tag_14a_reset_handler_t cb_reset; nfc_tag_14a_state_handler_t cb_state; nfc_tag_14a_coll_handler_t get_coll_res; } nfc_tag_14a_handler_t; -// 异或校验码 +// Different or verification code void nfc_tag_14a_create_bcc(uint8_t *pbtData, size_t szLen, uint8_t *pbtBcc); void nfc_tag_14a_append_bcc(uint8_t *pbtData, size_t szLen); -// 14a循环冗余校验码 +// 14A cycle redundant school code void nfc_tag_14a_append_crc(uint8_t *pbtData, size_t szLen); bool nfc_tag_14a_checks_crc(uint8_t *pbtData, size_t szLen); -// 14a帧组解 +// 14A frame combination uint8_t nfc_tag_14a_wrap_frame(const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtFrame); uint8_t nfc_tag_14a_unwrap_frame(const uint8_t *pbtFrame, const size_t szFrameBits, uint8_t *pbtRx, uint8_t *pbtRxPar); -// 14a通信控制 +// 14A communication control void nfc_tag_14a_sense_switch(bool enable); void nfc_tag_14a_set_handler(nfc_tag_14a_handler_t *handler); void nfc_tag_14a_set_state(nfc_tag_14a_state_t state); @@ -114,7 +114,7 @@ void nfc_tag_14a_tx_bits(uint8_t *data, uint32_t bits); void nfc_tag_14a_tx_nbit_delay_window(uint8_t data, uint32_t bits); void nfc_tag_14a_tx_nbit(uint8_t data, uint32_t bits); -// 判断是否是有效的uid长度 +// Determine whether it is an effective UID length bool is_valid_uid_size(uint8_t uid_length); #endif diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c index 10110f8..e06f2ff 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c +++ b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c @@ -176,19 +176,19 @@ static const uint8_t abTrailorAccessConditions[8][2] = { }, }; -// 保存当前的MF1标准状态 +// Save the current MF1 standard status static nfc_tag_mf1_std_state_machine_t m_mf1_state = MF1_STATE_UNAUTH; -// 保存当前的GEN1A状态 +// Save the current GEN1A status static nfc_tag_mf1_gen1a_state_machine_t m_gen1a_state = GEN1A_STATE_DISABLE; -// 指向标签信息的数据结构指针 +// Data structure pointer to the label information static nfc_tag_mf1_information_t *m_tag_information = NULL; -// 定义并且使用影子防冲撞资源 +// Define and use shadow anti -collision resources static nfc_tag_14a_coll_res_referen_t m_shadow_coll_res; -// 指向标签扇区中的尾部块(控制数据块) +//Pind to the tail block in the label sector (control data block) static nfc_tag_mf1_trailer_info_t *m_tag_trailer_info = NULL; -// 定义并且使用mf1专用通信缓冲区 +// Define and use MF1 special communication buffer static nfc_tag_mf1_tx_buffer_t m_tag_tx_buffer; -// 保存当前正在模拟的MF1的具体类型 +//Save the specific type of MF1 currently being simulated static tag_specific_type_t m_tag_type; // Fast simulate is enable, we use internal crypto1 instance from 'mf1_crypto1.c' @@ -198,8 +198,8 @@ static struct Crypto1State mpcs = {0, 0}; static struct Crypto1State *pcs = &mpcs; #endif -// 定义指向存放侦测的数据的buffer -// 将此数据放置在休眠保留的RAM中,以节约写入到Flash的时间和空间 +// Define the buffer of the data that stored the detected data +// Place this data in a dormant RAM to save time and space to write into Flash #define MF1_AUTH_LOG_MAX_SIZE 1000 static __attribute__((section(".noinit"))) struct nfc_tag_mf1_auth_log_buffer { uint32_t count; @@ -306,11 +306,11 @@ void ValueToBlock(uint8_t *Block, uint32_t Value) { Block[11] = Block[3]; } -/** @brief mf1获取一个随机数 - * @param nonce 随机数的Buffer +/** @brief MF1 Get a random number + * @param nonce Random number buffer */ void nfc_tag_mf1_random_nonce(uint8_t nonce[4], bool isNested) { - // 使用rand进行快速产生随机数,性能损耗较小 + // Use RAND to quickly generate random numbers, less performance loss // isNested provides more randomness for hardnested attack if (isNested) { nonce[0] = rand() & 0xff; @@ -324,25 +324,25 @@ void nfc_tag_mf1_random_nonce(uint8_t nonce[4], bool isNested) { } /** - * @brief mf1追加验证日志,步骤一,存放基础信息 - * @param isKeyB: 是否是在验证秘钥B - * @param isNested: 是否是在进行嵌套验证 - * @param block: 当前正在验证的块 - * @param nonce: 明文随机数 + * @brief MF1 additional verification log, step 1, store basic information + * @param isKeyB: Are you verifying the secret B + * @param isNested:Whether it is undercover verification + * @param block: The block currently verified + * @param nonce: Brightly random number */ void append_mf1_auth_log_step1(bool isKeyB, bool isNested, uint8_t block, uint8_t *nonce) { - // 首次上电,重置一下缓冲区信息 + // Power up for the first time, reset the buffer information if (m_auth_log.count == 0xFFFFFFFF) { m_auth_log.count = 0; NRF_LOG_INFO("Mifare Classic auth log buffer ready"); } - // 非首次上电,看一下是否记录侦测日志超过大小上限 + // Non -first -time call, see if you record whether the detection log is over the upper limit of the size if (m_auth_log.count > MF1_AUTH_LOG_MAX_SIZE) { - // 超过上限直接跳过此操作。 + // Skill this operation directly over the upper limit. NRF_LOG_INFO("Mifare Classic auth log buffer overflow"); return; } - // 判断这个卡槽是否使能了侦测日志记录 + // Determine whether this card slot enables the detection log record if (m_tag_information->config.detection_enable) { m_auth_log.logs[m_auth_log.count].cmd.is_keyb = isKeyB; m_auth_log.logs[m_auth_log.count].cmd.block = block; @@ -352,46 +352,46 @@ void append_mf1_auth_log_step1(bool isKeyB, bool isNested, uint8_t block, uint8_ } } -/** @brief mf1追加验证日志,步骤二,存放读头回应的加密信息 - * @param nr: 读卡器产生的,用秘钥加密的随机数 - * @param ar: 标签产生的,被读头加密的随机数 +/** @brief MF1 additional verification log, step 2, store the encryption information of the read -ahead response + * @param nr: The card reader is generated, the random number of encryption with the secret key + * @param ar: The random number of the label, the random number of the read -headed head is encrypted */ void append_mf1_auth_log_step2(uint8_t *nr, uint8_t *ar) { - // 判断到超过上限直接跳过此操作,避免覆盖之前的记录 + // Determine to the upper limit and skip this operation directly to avoid covering the previous records if (m_auth_log.count > MF1_AUTH_LOG_MAX_SIZE) { return; } if (m_tag_information->config.detection_enable) { - // 缓存加密信息 + // Cache encryption information memcpy(m_auth_log.logs[m_auth_log.count].nr, nr, 4); memcpy(m_auth_log.logs[m_auth_log.count].ar, ar, 4); } } -/** @brief mf1追加验证日志,步骤三,存放最终验证成功或者失败的日志 - * 此步骤完成了最终的统计个数递增 - * @param is_auth_success: 是否验证成功 +/** @brief MF1 additional verification log, step 3, store the last verification or failure log + * This step has completed the final statistics increase + * @param is_auth_success: Whether to verify success */ void append_mf1_auth_log_step3(bool is_auth_success) { - // 判断到超过上限直接跳过此操作,避免覆盖之前的记录 + // Determine to the upper limit and skip this operation directly to avoid covering the previous records if (m_auth_log.count > MF1_AUTH_LOG_MAX_SIZE) { return; } if (m_tag_information->config.detection_enable) { - // 然后就可以结束本次记录,统计数量递增 + // Then you can end this record, the number of statistics increases m_auth_log.count += 1; - // 打印一下当前记录的日志个数 + // Print the number of logs in the current record NRF_LOG_INFO("Auth log count: %d", m_auth_log.count); } } -/** @brief mf1获得验证日志 - * @param count: 验证日志的统计个数 +/** @brief MF1 obtain verification log + * @param count: The statistics of the verification log */ nfc_tag_mf1_auth_log_t *get_mf1_auth_log(uint32_t *count) { - // 先传递验证的日志条目总数出去 + // First pass the total number of logs verified by verified *count = m_auth_log.count; - // 直接返回日志数组的头部指针就好了 + // Just return to the head pointer of the log number array return m_auth_log.logs; } @@ -428,46 +428,46 @@ void mf1_prng_by_bytes(uint8_t *nonces, uint32_t n) { } #endif -/** @brief mf1状态机 - * @param data 来自读头数据 - * @param szBits 数据的比特流长度 - * @param state 有限状态机 +/** @brief MF1 status machine + * @param data From reading head data + * @param szBits Pittering length of data + * @param state Finite State Machine */ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { - // 处理特殊指令,比如兼容mifare gen1a标签 + //Special instructions, such as compatible with MiFare Gen1a label if (szDataBits <= 8) { - // 只有启用了GEN1A模式的情况下才允许后门指令的响应 + // Only when the Gen1A mode is enabled, the response of the back door instruction is allowed if (m_tag_information->config.mode_gen1a_magic) { if (szDataBits == 7 && p_data[0] == CMD_CHINESE_UNLOCK) { - // 第一步后门卡验证 + // The first step back door card verification // NRF_LOG_INFO("MIFARE_MAGICWUPC1 received.\n"); m_gen1a_state = GEN1A_STATE_UNLOCKING; nfc_tag_14a_tx_nbit_delay_window(ACK_VALUE, 4); } else if (szDataBits == 8 && p_data[0] == CMD_CHINESE_UNLOCK_RW) { - // 第二部后门卡验证 + // The second back door card verification if (m_gen1a_state == GEN1A_STATE_UNLOCKING) { // NRF_LOG_INFO("MIFARE_MAGICWUPC2 received.\n"); - nfc_tag_14a_set_state(NFC_TAG_STATE_14A_ACTIVE); // 更新外部14A的状态机 - m_gen1a_state = GEN1A_STATE_UNLOCKED_RW_WAIT; // 更新GEN1A状态机 - m_mf1_state = MF1_STATE_UNAUTH; // 更新MF1状态机 - nfc_tag_14a_tx_nbit_delay_window(ACK_VALUE, 4); // 回复读卡器gen1a标签解锁后门成功 + nfc_tag_14a_set_state(NFC_TAG_STATE_14A_ACTIVE); //Update the status machine of the external 14A + m_gen1a_state = GEN1A_STATE_UNLOCKED_RW_WAIT; // Update the Gen1A status machine + m_mf1_state = MF1_STATE_UNAUTH; // Update MF1 status machine + nfc_tag_14a_tx_nbit_delay_window(ACK_VALUE, 4); //Reply to the card reader Gen1a label unlock the back door success #ifndef NFC_MF1_FAST_SIM crypto1_deinit(pcs); // Reset crypto1 handler #endif } else { - m_gen1a_state = GEN1A_STATE_DISABLE; // 如果发现并没有走过第一步的话,直接重置gen1a状态机 + m_gen1a_state = GEN1A_STATE_DISABLE; // If you find that you have not taken the first step, directly reset the Gen1a status machine } } } - // 记住,无论如何非字节帧都要在此处处理后直接结束 - // 万万不可将非字节帧转交给下方逻辑处理 + // Remember, no matter what the byte frame is processed here, it will end directly after processing + // Do not transfer non -byte frames to the logic below return; } - // 处理mifare的状态机 + // Processing MiFare's status machine switch (m_mf1_state) { - case MF1_STATE_UNAUTH: { // 未验证状态,通信是开放性的 - if (szDataBits == 32) { // 32位,可能是指令 + case MF1_STATE_UNAUTH: { // Unparalleled state, communication is open + if (szDataBits == 32) { // 32 -bit, may be instructions if (nfc_tag_14a_checks_crc(p_data, 4)) { switch (p_data[0]) { case CMD_AUTH_A: @@ -477,33 +477,33 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { uint8_t BlockStart; uint8_t BlockEnd; - // 获得访问的块对应扇区的起始块,谨记:4K卡有大扇区,以16个block为一个扇区单位 - // 计算思路:x = (y / n) * n,x = 扇区的起始块,y = 验证的块, n = y所在的扇区内的块的数量 - // 思路解析:先做除法获取当前所在扇区,然后再做乘法获取所在扇区的块数量 + // Get the starting block of the corresponding sector that is visited, keep in mind: 4K cards have large sectors, and 16 blocks are used as one sector unit + // Calculate ideas: x = (y / n) * n, x = starting block of the sector, y = verified block, n = y's number of blocks where the sector is located + // Thinking analysis: First do divisions to get the current sector, and then multiply to obtain the number of blocks in the sector if (BlockAuth >= 128) { BlockStart = (BlockAuth / 16) * 16; BlockEnd = BlockStart + 16 - 1; } else { - // 非4K卡,以小扇区步进 + // Non -4K card, step by step with a small sector BlockStart = (BlockAuth / 4) * 4; BlockEnd = BlockStart + 4 - 1; } - // 当前模拟卡的类型,不足以支撑起读卡器的访问 + // The type of current simulation card is not enough to support the access of the card reader if (check_block_max_overflow(BlockAuth)) { break; } - // 将KeyInUse设置为全局使用,以保留有关身份验证的信息 + // Set keyinuse as global use to retain information about identity verification KeyInUse = p_data[0] & 1; - // 获得指定的扇区访问控制字节,此处我们直接取巧,将内存转为结构体,让编译器帮我们维护指针的指向 + // Obtain the specified sector access control bytes. Here we directly take the coincidence, convert the memory into a structure, and let the compiler help us maintain the pointing of the pointer m_tag_trailer_info = (nfc_tag_mf1_trailer_info_t *)m_tag_information->memory[BlockEnd]; - // 生成随机数 + // Generate random number nfc_tag_mf1_random_nonce(CardNonce, false); - // 根据卡随机数预先计算读卡器应答 + // Calculate the card reader in advance according to the card random number for (uint8_t i = 0; i < sizeof(ReaderResponse); i++) { ReaderResponse[i] = CardNonce[i]; } @@ -513,7 +513,7 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { mf1_prng_by_bytes(ReaderResponse, 64); #endif - // 根据读卡器的应答预先计算我们的应答 + // Calculate our response based on the response from the card reader for (uint8_t i = 0; i < sizeof(CardResponse); i++) { CardResponse[i] = ReaderResponse[i]; } @@ -523,13 +523,13 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { mf1_prng_by_bytes(CardResponse, 32); #endif - // 记录验证日志 + // Record verification log append_mf1_auth_log_step1(KeyInUse, false, BlockAuth, CardNonce); - // 使用随机卡随机数进行响应,并期望在下一帧中从读取器获得进一步的身份验证。 + // Use random card random numbers to respond, and hopes to obtain further authentication from the reader in the next frame. m_mf1_state = MF1_STATE_AUTHING; - // 首次验证,回应一个明文的随机数,不带CRC + // The first verification, responding to a clear random number, without CRC m_tag_tx_buffer.tx_raw_buffer[0] = CardNonce[0]; m_tag_tx_buffer.tx_raw_buffer[1] = CardNonce[1]; m_tag_tx_buffer.tx_raw_buffer[2] = CardNonce[2]; @@ -537,30 +537,30 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { #ifdef NFC_MF1_FAST_SIM Crypto1Setup( - // 根据当前的指令类型选择验证A或者B秘钥 + // Select A or B secrets based on the current instruction type KeyInUse ? m_tag_trailer_info->keyb : m_tag_trailer_info->keya, - // 传入当前使用的防冲撞的UID + // Passing the current anti -collision UID UID_BY_CASCADE_LEVEL, - // 传入一个明文的随机数,这个随机数将会被用于解密后续的通信 + // Passing into a clear random number, this random number will be used to decrypt subsequent communication CardNonce ); #else - // 设置crypto1密钥流,丢弃之前的加密状态 + // Set the Crypto1 key flow and discard the previous encryption state crypto1_deinit(pcs); - // 加载密钥流 + // Load key flow crypto1_init(pcs, - // 根据当前的指令类型选择验证A或者B秘钥 + // Select A or B secrets based on the current instruction type bytes_to_num(KeyInUse ? m_tag_trailer_info->keyb : m_tag_trailer_info->keya, 6) ); - // 设置密钥流 + // Set key flow crypto1_word(pcs, bytes_to_num(UID_BY_CASCADE_LEVEL, 4) ^ bytes_to_num(CardNonce, 4), 0); #endif - // 回应明文随机数给读卡器 + // Responsible for clear -scale random number to read the card reader nfc_tag_14a_tx_bytes(m_tag_tx_buffer.tx_raw_buffer, 4, false); break; } case CMD_READ: { - // 在未验证的情况下收到了块相关的读指令,如果后门属于开启状态则直接允许读取 + // I received a block -related reading instruction without verification. if (m_gen1a_state == GEN1A_STATE_UNLOCKED_RW_WAIT) { CurrentAddress = p_data[1]; memcpy(m_tag_tx_buffer.tx_raw_buffer, m_tag_information->memory[CurrentAddress], NFC_TAG_MF1_DATA_SIZE); @@ -571,12 +571,12 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { break; } case CMD_WRITE: { - // 解释同上 + // Explanation if (m_gen1a_state == GEN1A_STATE_UNLOCKED_RW_WAIT) { - // 保存要写入的块和更新状态机 + //Save the block and update status machine to be written CurrentAddress = p_data[1]; m_gen1a_state = GEN1A_STATE_WRITING; - // 响应ACK,让读头继续下一步发块数据过来 + // Responsive ACK, let the read head continue the next step data to come over nfc_tag_14a_tx_nbit_delay_window(ACK_VALUE, 4); } else { nfc_tag_14a_tx_nbit_delay_window(NAK_INVALID_OPERATION_TBIV, 4); @@ -584,34 +584,34 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { break; } default: { - // 未验证状态下,除了在后门模式开启的时候直接读写卡 - // 以及发起验证指令之外,其他的啥也干不了 + // When the state is not verified, read and write cards directly when the back door mode is turned on + // In addition to initiating verification instructions, the others can do nothing nfc_tag_14a_tx_nbit_delay_window(NAK_INVALID_OPERATION_TBIV, 4); break; } } } else { - // crc 校验异常 + // CRC verification abnormal nfc_tag_14a_tx_nbit_delay_window(NAK_CRC_PARITY_ERROR_TBIV, 4); return; } } else { if (szDataBits == 144 && m_gen1a_state == GEN1A_STATE_WRITING) { - // 判断到我们是在GEN1A模式下进行写入block操作 + // Determine that we are written into the block operation under the Gen1a mode if (nfc_tag_14a_checks_crc(p_data, NFC_TAG_MF1_FRAME_SIZE)) { - // 数据校验通过,我们需要把发过来的数据放到RAM里面 + // The data verification passes, we need to put the data sent in RAM memcpy(m_tag_information->memory[CurrentAddress], p_data, NFC_TAG_MF1_DATA_SIZE); - // 恢复GEN1A专用状态机为等待操作状态 + // Restore the Gen1A special state machine for waiting operation status m_gen1a_state = GEN1A_STATE_UNLOCKED_RW_WAIT; - // 回复读头ACK,完成写入操作 + // Reply to read head ACK, complete the writing operation nfc_tag_14a_tx_nbit_delay_window(ACK_VALUE, 4); } else { - // 传输过来的CRC校验异常,不能继续写入 + // The transmitted CRC verification is abnormal, and you cannot continue writing nfc_tag_14a_tx_nbit_delay_window(NAK_CRC_PARITY_ERROR_TBIV, 4); } } else { - // 在等待指令状态如果等到非4BYTE的指令则认为异常 - // 此时需要重置状态机 + // If you wait for the instruction status to the non -4BYTE instruction, it is considered abnormal + // At this time, you need to reset the state machine nfc_tag_14a_set_state(NFC_TAG_STATE_14A_IDLE); } } @@ -620,48 +620,48 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { case MF1_STATE_AUTHING: { if (szDataBits == 64) { - // 拷贝读卡器回应的NR + AR + //NR + AR responded to the card reader append_mf1_auth_log_step2(p_data, &p_data[4]); #ifdef NFC_MF1_FAST_SIM // Reader delivers an encrypted nonce. We use it to setup the crypto1 LFSR in nonlinear feedback mode. Furthermore it delivers an encrypted answer. Decrypt and check it Crypto1Auth(&p_data[0]); Crypto1ByteArray(&p_data[4], 4); #else - // NR,是读卡器生成的随机数 + // NR, a random number generated by a card reader uint32_t nr = bytes_to_num(p_data, 4); - // AR,是卡片加密我们第一步回应的随机数的加密后的数据 + // AR, is the encrypted data that we responded in the first step of the card encryption uint32_t ar = bytes_to_num(&p_data[4], 4); // --- crypto crypto1_word(pcs, nr, 1); num_to_bytes(ar ^ crypto1_word(pcs, 0, 0), 4, &p_data[4]); #endif - // 验证读卡器返回来的随机数是不是我们发送的 + // Was the random number of the return of the card reader was sent by us if ((p_data[4] == ReaderResponse[0]) && (p_data[5] == ReaderResponse[1]) && (p_data[6] == ReaderResponse[2]) && (p_data[7] == ReaderResponse[3])) { - // 读取器已通过身份验证。加密预计算的卡应答数据并生成奇偶校验位。 + // The reader has passed the authentication.The estimated calculation card response data and generating the puppet test position. m_tag_tx_buffer.tx_raw_buffer[0] = CardResponse[0]; m_tag_tx_buffer.tx_raw_buffer[1] = CardResponse[1]; m_tag_tx_buffer.tx_raw_buffer[2] = CardResponse[2]; m_tag_tx_buffer.tx_raw_buffer[3] = CardResponse[3]; - // 加密且计算奇偶校验位 + //Encryption and calculation of the puppet school inspection #ifdef NFC_MF1_FAST_SIM Crypto1ByteArrayWithParity(m_tag_tx_buffer.tx_raw_buffer, m_tag_tx_buffer.tx_bit_parity, 4); #else mf_crypto1_encrypt(pcs, m_tag_tx_buffer.tx_raw_buffer, 4, m_tag_tx_buffer.tx_bit_parity); #endif - // 验证成功了,需要进入已经验证成功的状态 + // The verification is successful, and you need to enter the state that has been successfully verified m_mf1_state = MF1_STATE_AUTHED; - // 进行打包,将奇偶校验位进行拼接后返回 + // Package, stitch the Qiqi school inspection, return m_tag_tx_buffer.tx_frame_bit_size = nfc_tag_14a_wrap_frame(m_tag_tx_buffer.tx_raw_buffer, 32, m_tag_tx_buffer.tx_bit_parity, m_tag_tx_buffer.tx_warp_frame); nfc_tag_14a_tx_bits(m_tag_tx_buffer.tx_warp_frame, m_tag_tx_buffer.tx_frame_bit_size); } else { - // 暂时只存放验证失败的日志 + // Temporary only stored verification failed logs append_mf1_auth_log_step3(false); - // 验证失败,重置状态机 + // Verification failure, reset the status machine nfc_tag_14a_set_state(NFC_TAG_STATE_14A_IDLE); } } else { - // 读头在验证过程中发送过来的数据长度不对,肯定是有问题的 - // 我们只能是重置状态机,等待重新发起操作指令 + // The length of the data sent by the reading head during the verification process is wrong, it must be a problem + // We can only reset the status machine and wait for the operation instructions to re -initiate nfc_tag_14a_set_state(NFC_TAG_STATE_14A_IDLE); } break; @@ -669,75 +669,75 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { case MF1_STATE_AUTHED: { if (szDataBits == 32) { - // 在这种状态下,所有通信都被加密。因此,我们首先必须解密读头发送过来的数据。 + // In this state, all communication is encrypted.Therefore, we must first decrypt the data sent by the read head. #ifdef NFC_MF1_FAST_SIM Crypto1ByteArray(p_data, 4); #else mf_crypto1_decryptEx(pcs, p_data, 4, p_data); #endif - // 解密完成后,检查CRC是否正确,我们必须要确保数据过来的数据无误! + // After the decryption is completed, check whether the CRC is correct, and we must ensure that the data coming over is correct! if (nfc_tag_14a_checks_crc(p_data, 4)) { switch (p_data[0]) { case CMD_READ: { - // 保存当前操作的块地址 + // Save the block address of the current operation CurrentAddress = p_data[1]; - // 生成访问控制,用于下面的数据访问控制 + // Generate access control, for data access control below uint8_t Acc = abTrailorAccessConditions[ GetAccessCondition(CurrentAddress) ][ KeyInUse ]; - // 读取命令。从内存中读取数据并附加CRCA。注意:读取操作受到控制位的限制,但是目前我们只限制控制位的读取 + // Read the command.Read data from memory and add CRCA.Note: Reading operations are limited by the control bit, but at present we only restrict the reading of the control bit if ((CurrentAddress < 128 && (CurrentAddress & 3) == 3) || ((CurrentAddress & 15) == 15)) { - // 清空一下buffer,避免缓存的数据影响到后续操作 + // Clear the buffer to avoid the cache data that affect the follow -up operation memset(m_tag_tx_buffer.tx_raw_buffer, 0x00, sizeof(m_tag_tx_buffer.tx_raw_buffer)); - // 让这块数据区域变成我们需要的尾部块类型 + // Make this data area into the type of tail blocks we need nfc_tag_mf1_trailer_info_t *respTrailerInfo = (nfc_tag_mf1_trailer_info_t *)m_tag_tx_buffer.tx_raw_buffer; - // 尾部块的读取有以下条件限制: - // 1、要始终可以复制GPB(Global Public Byte)也就是控制位最后一个字节 - // 2、秘钥A永远无法被读取! - // 3、根据身份验证期间已读取的访问条件做出控制位读取的本身限制! + // The reading of the tail block has the following conditions: + // 1. Always copy GPB (Global Public Byte), which is the last byte of the control bit + // 2. Secret A can never be read! + // 3. Make the restrictions of the control position reading according to the access conditions of the read during authentication! respTrailerInfo->acs[3] = m_tag_trailer_info->acs[3]; - // 判断控制位本身是否是允许读取的 + // Determine whether the control position itself allows reading if (Acc & ACC_TRAILOR_READ_ACC) { respTrailerInfo->acs[0] = m_tag_trailer_info->acs[0]; respTrailerInfo->acs[1] = m_tag_trailer_info->acs[1]; respTrailerInfo->acs[2] = m_tag_trailer_info->acs[2]; } - // 在少数情况下,秘钥B是可读的 + // In a few cases, the Secret B is readable if (Acc & ACC_TRAILOR_READ_KEYB) { memcpy(respTrailerInfo->keyb, m_tag_trailer_info->keyb, 6); } } else { - // 数据的话,直接返回对应位置的扇区即可 + // For data, just return to the corresponding location sector memcpy(m_tag_tx_buffer.tx_raw_buffer, m_tag_information->memory[CurrentAddress], 16); } - // 无论如何,回复的数据都要计算CRC + // In any case, the data of the reply must be calculated CRC nfc_tag_14a_append_crc(m_tag_tx_buffer.tx_raw_buffer, NFC_TAG_MF1_DATA_SIZE); - // 加密和计算奇偶校验位后回复给读卡器 + // Reply and calculate the coupling school inspection to reply to the card reader #ifdef NFC_MF1_FAST_SIM Crypto1ByteArrayWithParity(m_tag_tx_buffer.tx_raw_buffer, m_tag_tx_buffer.tx_bit_parity, NFC_TAG_MF1_FRAME_SIZE); #else mf_crypto1_encrypt(pcs, m_tag_tx_buffer.tx_raw_buffer, NFC_TAG_MF1_FRAME_SIZE, m_tag_tx_buffer.tx_bit_parity); #endif - // 合并奇偶校验位到数据帧 + // Combined Qiqi School Check Data Frame m_tag_tx_buffer.tx_frame_bit_size = nfc_tag_14a_wrap_frame(m_tag_tx_buffer.tx_raw_buffer, 144, m_tag_tx_buffer.tx_bit_parity, m_tag_tx_buffer.tx_warp_frame); - // 启动发送 + // Start sending nfc_tag_14a_tx_bits(m_tag_tx_buffer.tx_warp_frame, m_tag_tx_buffer.tx_frame_bit_size); return; } case CMD_WRITE: { - // 正常的卡不允许写block0,不然会被CUID防火墙识别到 + // Normal cards are not allowed to write block0, otherwise it will be recognized by CUID firewall if (p_data[1] == 0x00 && !m_tag_information->config.mode_gen2_magic) { - // 直接重置14a的状态机,让标签休眠 + // Reset the 14A state machine directly, let the label sleep nfc_tag_14a_set_state(NFC_TAG_STATE_14A_HALTED); - // 告知一下读头此操作不被允许 + // Tell me to read the head. This operation is not allowed to be allowed #ifdef NFC_MF1_FAST_SIM nfc_tag_14a_tx_nbit(NAK_INVALID_OPERATION_TBIV ^ Crypto1Nibble(), 4); #else nfc_tag_14a_tx_nbit(mf_crypto1_encrypt4bit(pcs, NAK_INVALID_OPERATION_TBIV), 4); #endif } else { - // 正常的写入命令。存储地址并准备接收即将到来的数据。 + // Normally write command.Store the address and prepare to receive the upcoming data. CurrentAddress = p_data[1]; m_mf1_state = MF1_STATE_WRITE; - // 进行ACK响应,告知读头我们已经准备好了 + // Take ACK response, inform the reading head we are ready #ifdef NFC_MF1_FAST_SIM nfc_tag_14a_tx_nbit(ACK_VALUE ^ Crypto1Nibble(), 4); #else @@ -746,7 +746,7 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { } return; } - // 尽管我觉下面的三个case的代码有点蠢,除了设置状态机不同其他的都相同,但是空间换时间吧算是(心理安慰) + // Although I think the following three case code is a bit stupid. Except for the different other ones, the space is the same, but the space is changed (psychological comfort) case CMD_DECREMENT: { CurrentAddress = p_data[1]; m_mf1_state = MF1_STATE_DECREMENT; @@ -779,15 +779,15 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { } case CMD_TRANSFER: { uint8_t status; - // 此处先不判断当前的写入模式,以写入模式控制写入 + // Do not judge the current writing mode here to control the writing mode if (m_tag_information->config.mode_block_write == NFC_TAG_MF1_WRITE_DENIED) { - // 这个模式下直接拒绝操作 + // Under this mode directly reject operation status = NAK_INVALID_OPERATION_TBIV; } else if (m_tag_information->config.mode_block_write == NFC_TAG_MF1_WRITE_DECEIVE) { - // 这个模式下回应ACK,但是不写入到RAM里面 + // This mode responds to ACK, but it is not written in RAM status = ACK_VALUE; } else { - // 将全局块缓冲区写回指令参数指定的块地址 + // Write the block address specified by the global buffer back in the instruction parameter memcpy(m_tag_information->memory[p_data[1]], m_data_block_buffer, MEM_BYTES_PER_BLOCK); status = ACK_VALUE; } @@ -800,39 +800,39 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { } case CMD_AUTH_A: case CMD_AUTH_B: { - // 在已经加密过的情况下发起第二次验证请求,则是嵌套验证的过程 + // The second verification request when it has been encrypted is the process of nested verification uint8_t BlockAuth = p_data[1]; uint8_t CardNonce[4]; uint8_t BlockStart; uint8_t BlockEnd; - // 获得访问的块对应扇区的起始块,谨记:4K卡有大扇区,以16个block为一个扇区单位 - // 计算思路:x = (y / n) * n,x = 扇区的起始块,y = 验证的块, n = y所在的扇区内的块的数量 - // 思路解析:先做除法获取当前所在扇区,然后再做乘法获取所在扇区的块数量 + // The starting block of the corresponding sector that is visited, keep in mind: 4K cards have large sectors, with 16 blocks as one sector unit + // Calculate ideas: x = (y / n) * n, x = starting block of the sector, y = verified block, n = y's number of blocks where the sector is located + // Thinking analysis: First do divisions to get the current sector, and then multiply to obtain the number of blocks in the sector if (BlockAuth >= 128) { BlockStart = (BlockAuth / 16) * 16; BlockEnd = BlockStart + 16 - 1; } else { - // 非4K卡,以小扇区步进 + //Non -4K card, step by step with a small sector BlockStart = (BlockAuth / 4) * 4; BlockEnd = BlockStart + 4 - 1; } - // 当前模拟卡的类型,不足以支撑起读卡器的访问 + // The type of current simulation card is not enough to support the access of the card reader if (check_block_max_overflow(BlockAuth)) { break; } - // 将KeyInUse设置为全局使用,以保留有关身份验证的信息 + // Set keyinuse as global use to retain information about identity verification KeyInUse = p_data[0] & 1; - // 获得指定的扇区访问控制字节,此处我们直接取巧,将内存转为结构体,让编译器帮我们维护指针的指向 + // Obtain the specified sector access control bytes. Here we directly take the coincidence, convert the memory into a structure, and let the compiler help us maintain the pointing of the pointer m_tag_trailer_info = (nfc_tag_mf1_trailer_info_t *)m_tag_information->memory[BlockEnd]; - // 生成随机数 + // Generate random number nfc_tag_mf1_random_nonce(CardNonce, true); - // 根据卡随机数预先计算读卡器响应 + // Calculate the card reader response based on the card random number for (uint8_t i = 0; i < sizeof(ReaderResponse); i++) { ReaderResponse[i] = CardNonce[i]; } @@ -842,7 +842,7 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { mf1_prng_by_bytes(ReaderResponse, 64); #endif - // 根据读卡器的应答预先计算我们的应答 + // Calculate our response based on the response from the card reader for (uint8_t i = 0; i < sizeof(CardResponse); i++) { CardResponse[i] = ReaderResponse[i]; } @@ -852,13 +852,13 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { mf1_prng_by_bytes(CardResponse, 32); #endif - // 记录嵌套验证信息 + // Record nested verification information append_mf1_auth_log_step1(KeyInUse, true, BlockAuth, CardNonce); - // 使用随机卡随机数进行响应,并期望在下一帧中从读取器获得进一步的身份验证。 + //Use random card random numbers to respond, and hopes to obtain further authentication from the reader in the next frame. m_mf1_state = MF1_STATE_AUTHING; - // 复制一份标签的随机数到缓冲区中 + // Copy a random number of a label to the buffer area m_tag_tx_buffer.tx_raw_buffer[0] = CardNonce[0]; m_tag_tx_buffer.tx_raw_buffer[1] = CardNonce[1]; m_tag_tx_buffer.tx_raw_buffer[2] = CardNonce[2]; @@ -867,40 +867,40 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { #ifdef NFC_MF1_FAST_SIM /* Setup crypto1 cipher. Discard in-place encrypted CardNonce. */ Crypto1SetupNested( - // 根据当前的指令类型选择验证A或者B秘钥 + // Select A or B secrets based on the current instruction type KeyInUse ? m_tag_trailer_info->keyb : m_tag_trailer_info->keya, - // 传入当前使用的防冲撞的UID + // Passing the current anti -collision UID UID_BY_CASCADE_LEVEL, - // 传入一个明文的随机数,这个随机数将被加密并通过此缓冲区传出 + // Passing into a clear random number, this random number will be encrypted and passed through this buffer area m_tag_tx_buffer.tx_raw_buffer, - // 传入一个保存随机数的奇偶校验位的缓冲区 + // A buffer that passed into a strange school inspection of random numbers m_tag_tx_buffer.tx_bit_parity, - // 根据函数解释 Use: Decrypt = false for the tag, Decrypt = true for the reader - // 我们目前是标签角色,因此传入false + // Explain the user: Decrypt = false for the tag, decrypt = true for the reader + // We are currently a label character, so we are introduced into false false ); #else - // 设置crypto1密钥流,丢弃之前的加密状态 + // Set the Crypto1 key flow and discard the previous encryption state crypto1_deinit(pcs); - // 加载密钥流 + //Load key flow crypto1_init(pcs, - // 根据当前的指令类型选择验证A或者B秘钥 + // Select A or B secrets based on the current instruction type bytes_to_num(KeyInUse ? m_tag_trailer_info->keyb : m_tag_trailer_info->keya, 6) ); - // 进行随机数加密 + // Random number encryption uint8_t m_auth_nt_keystream[4]; num_to_bytes(bytes_to_num(UID_BY_CASCADE_LEVEL, 4) ^ bytes_to_num(CardNonce, 4), 4, m_auth_nt_keystream); mf_crypto1_encryptEx(pcs, CardNonce, m_auth_nt_keystream, m_tag_tx_buffer.tx_raw_buffer, 4, m_tag_tx_buffer.tx_bit_parity); #endif - // 嵌套验证的情况下,进行组帧后回复一个加密的随机数,带奇偶校验位不带CRC + // In the case of nested verification, after the frame is set up, a encrypted random number is replied, and the puppet school inspection does not bring CRC m_tag_tx_buffer.tx_frame_bit_size = nfc_tag_14a_wrap_frame(m_tag_tx_buffer.tx_raw_buffer, 32, m_tag_tx_buffer.tx_bit_parity, m_tag_tx_buffer.tx_warp_frame); nfc_tag_14a_tx_bits(m_tag_tx_buffer.tx_warp_frame, m_tag_tx_buffer.tx_frame_bit_size); break; } case CMD_HALT: { - // 让标签休眠。根据ISO14443协议规定,第二个字节应该是0。 + // Let the label sleep.According to the ISO14443 agreement, the second byte should be 0. if (p_data[1] == 0x00) { - // 如果一切正常,那么我们应该直接让卡片休眠,而且不能回应任何消息给读头 + // If everything is normal, then we should make the card directly to sleep, and cannot respond to any message to the read head nfc_tag_14a_set_state(NFC_TAG_STATE_14A_HALTED); } else { #ifdef NFC_MF1_FAST_SIM @@ -912,8 +912,8 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { break; } default: { - // 读头发了不知道什么鬼指令,我们没法处理, - // 因此任务此次通信异常,需要将状态重置,并且回应读头我们不支持这个指令 + // If you read your hair, you don't know what ghost instructions, we can't handle it, + // Therefore, the task is abnormal, and the status needs to be reset, and the response to the reading head will not support this instruction nfc_tag_14a_set_state(NFC_TAG_STATE_14A_IDLE); #ifdef NFC_MF1_FAST_SIM nfc_tag_14a_tx_nbit(NAK_INVALID_OPERATION_TBIV ^ Crypto1Nibble(), 4); @@ -924,7 +924,7 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { } } } else { - // crc有误,返回错误码告知 + // CRC is wrong, return the error code notification #ifdef NFC_MF1_FAST_SIM nfc_tag_14a_tx_nbit(NAK_INVALID_OPERATION_TBIV ^ Crypto1Nibble(), 4); #else @@ -933,7 +933,7 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { break; } } else { - // 已验证秘钥空闲状态但是没有收到正常的4BYTE指令,我们需要重置状态机 + // It has been verified that the secrets are idle but did not receive the normal 4BYTE instructions, we need to reset the status machine nfc_tag_14a_set_state(NFC_TAG_STATE_14A_IDLE); break; } @@ -942,25 +942,25 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { case MF1_STATE_WRITE: { uint8_t status; - // 当前处于写入状态机,我们需要确保接收到的数据是足够的长度的 + //It is currently in a state machine, we need to ensure that the received data is sufficient length if (szDataBits == 144) { - // 解密我们接收到的16字节的待写入数据和2字节的CRCA + // Decrypted the 16 -byte to be written in data and 2 -byte CRCA #ifdef NFC_MF1_FAST_SIM Crypto1ByteArray(p_data, NFC_TAG_MF1_FRAME_SIZE); #else mf_crypto1_decryptEx(pcs, p_data, NFC_TAG_MF1_FRAME_SIZE, p_data); #endif - // 校验数据的CRC,再次确保收到的数据无误 + //The CRC that checks the data, ensure that the data received again is correct if (nfc_tag_14a_checks_crc(p_data, NFC_TAG_MF1_FRAME_SIZE)) { - // 此处先不判断当前的写入模式,以写入模式控制写入 + // Do not judge the current writing mode here to control the writing mode if (m_tag_information->config.mode_block_write == NFC_TAG_MF1_WRITE_DENIED) { - // 这个模式下直接拒绝操作 + // Under this mode directly reject operation status = NAK_INVALID_OPERATION_TBIV; } else if (m_tag_information->config.mode_block_write == NFC_TAG_MF1_WRITE_DECEIVE) { - // 这个模式下回应ACK,但是不写入到RAM里面 + // This mode responds to ACK, but it is not written in RAM status = ACK_VALUE; } else { - // 其他剩余的模式都可以更新数据到标签的RAM中 + // Other remaining modes can be updated to the labeled RAM memcpy(m_tag_information->memory[CurrentAddress], p_data, NFC_TAG_MF1_DATA_SIZE); status = ACK_VALUE; } @@ -970,7 +970,7 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { } else { status = NAK_CRC_PARITY_ERROR_TBIV; } - // 无论如何,操作结束后都将让标签回到验证空闲状态 + // In any case, after the operation, the label will be allowed to return to the verification idle state m_mf1_state = MF1_STATE_AUTHED; #ifdef NFC_MF1_FAST_SIM nfc_tag_14a_tx_nbit(status ^ Crypto1Nibble(), 4); @@ -985,47 +985,47 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { case MF1_STATE_RESTORE: { uint8_t status; if (szDataBits == (MEM_VALUE_SIZE + NFC_TAG_14A_CRC_LENGTH) * 8) { - // 当我们到达这里时,前面已经发出了递减、递增或恢复命令,读取器现在正在发送数据。 - // 首先,解密数据并检查CRC。将请求的块地址中的数据读取到全局块缓冲器中,并检查完整性。 - // 然后,如果需要,根据发出的命令进行加或减,并将块存储回全局块缓冲区。 + //When we arrived here, we have issued a decrease, increasing or recovery command, and the reader is now sending data. + // First, decrypt the data and check the CRC.Read the data in the requested block address into the global block buffer and check the integrity. + // Then, if necessary, add or decrease according to the command issued, and store the block back to the global block buffer. #ifdef NFC_MF1_FAST_SIM Crypto1ByteArray(p_data, MEM_VALUE_SIZE + NFC_TAG_14A_CRC_LENGTH); #else mf_crypto1_decryptEx(pcs, p_data, MEM_VALUE_SIZE + NFC_TAG_14A_CRC_LENGTH, p_data); #endif - // 解密后必须要校验CRC,避免使用了出错的数据 + // After decomposition, CRC must be verified to avoid using error data if (nfc_tag_14a_checks_crc(p_data, MEM_VALUE_SIZE + NFC_TAG_14A_CRC_LENGTH)) { - // 先复制一份操作的块数据到全局缓冲区中 + // Copy a piece of data first to the global buffer zone memcpy(m_data_block_buffer, m_tag_information->memory[CurrentAddress], MEM_BYTES_PER_BLOCK); - // 检查值块是否有效 + // Check whether the value block is valid if (CheckValueIntegrity(m_data_block_buffer)) { - // 获取当前的参数值和块中存放的值 + //Get the value stored in the current parameter value and block uint32_t value_param, value_block; ValueFromBlock(&value_param, p_data); ValueFromBlock(&value_block, m_data_block_buffer); - // 进行对应的增减操作 + // Do the corresponding increase or decrease operation if (m_mf1_state == MF1_STATE_DECREMENT) { value_block -= value_param; } else if (m_mf1_state == MF1_STATE_INCREMENT) { value_block += value_param; } else if (m_mf1_state == MF1_STATE_RESTORE) { - // 啥也不做 + // Do nothing } - // 将值转换为block数据 + // Convert the value to Block data ValueToBlock(m_data_block_buffer, value_block); - // 这三个操作的第二步,也就是本步不需要回应读头 - // 因此当程序执行到这一步时,就可以回到已验证可以等待指令的状态了 + // The second step of these three operations is that this step does not need to respond to the reading header + // Therefore, when the program is executed to this step, you can return to the state where the verified instruction can be waited. break; } else { - // 这里的应答码或许是错误的,或许根本不需要应答 + // The answers here may be wrong, or maybe no answer is required at all status = NAK_OTHER_ERROR; } } else { - // CRC错误 + // CRC error status = NAK_CRC_PARITY_ERROR_TBIV; } } else { - // 长度错误,但是也算到CRC错误里面 + // The length is wrong, but it is counted in the CRC error status = NAK_CRC_PARITY_ERROR_TBIV; } m_mf1_state = MF1_STATE_AUTHED; @@ -1038,7 +1038,7 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { } default: { - // 未知状态?这永远不会发生,除非开发者脑子有问题! + // Unknown state?This will never happen, unless the developer has a problem with the brain! NRF_LOG_INFO("Unknown MF1 State"); break; } @@ -1046,32 +1046,32 @@ void nfc_tag_mf1_state_handler(uint8_t *p_data, uint16_t szDataBits) { } /** - * @brief 提供mifare标签必要的防冲突资源(仅提供指针) + * @brief Provide the necessary anti -conflict resources for the MiFare label (only pointer provides pointers) */ nfc_tag_14a_coll_res_referen_t *get_mifare_coll_res() { - // 根据当前的互通配置,选择性的返回其中配置的数据,假设开启了数据互通,那么我们还需要确保当前模拟的卡是4BYTE的 + //According to the current interoperability configuration, selectively return the configuration data to selectively, assuming that the data interoperability is turned on, then we also need to ensure that the current simulation card is 4BYTE if (m_tag_information->config.use_mf1_coll_res && m_tag_information->res_coll.size == NFC_TAG_14A_UID_SINGLE_SIZE) { - // 获得数据区域的厂商信息 + // Manufacturer information obtained by the data area nfc_tag_mf1_factory_info_t *block0_factory_info = (nfc_tag_mf1_factory_info_t *)m_tag_information->memory[0]; - m_shadow_coll_res.sak = block0_factory_info->sak; // 替换sak - m_shadow_coll_res.atqa = block0_factory_info->atqa; // 替换atqa - m_shadow_coll_res.uid = block0_factory_info->uid; // 替换uid - m_shadow_coll_res.size = &(m_tag_information->res_coll.size); // 复用类型 - m_shadow_coll_res.ats = &(m_tag_information->res_coll.ats); // 复用ats + m_shadow_coll_res.sak = block0_factory_info->sak; //Replace SAK + m_shadow_coll_res.atqa = block0_factory_info->atqa; //Replace ATQA + m_shadow_coll_res.uid = block0_factory_info->uid; // Replace UID + m_shadow_coll_res.size = &(m_tag_information->res_coll.size); // Reuse type + m_shadow_coll_res.ats = &(m_tag_information->res_coll.ats); // Reuse ATS } else { - // 使用单独的防冲突信息,而不是使用扇区中的信息 + // Use a separate anti -conflict information instead of using the information in the sector m_shadow_coll_res.sak = m_tag_information->res_coll.sak; m_shadow_coll_res.atqa = m_tag_information->res_coll.atqa; m_shadow_coll_res.uid = m_tag_information->res_coll.uid; m_shadow_coll_res.size = &(m_tag_information->res_coll.size); m_shadow_coll_res.ats = &(m_tag_information->res_coll.ats); } - // 最终返回一个只带引用,不带实体的影子数据结构指针 + // Finally, a shadow data structure pointer with only reference, no physical shadow, return &m_shadow_coll_res; } /** - * @brief 需要重置的参数标签时回调 + * @brief Reconcile when the parameter label needs to be reset */ void nfc_tag_mf1_reset_handler() { m_mf1_state = MF1_STATE_UNAUTH; @@ -1083,10 +1083,10 @@ void nfc_tag_mf1_reset_handler() { #endif } -/** @brief 获得信息结构体存放有效的信息的长度 - * @param type 细化的标签类型 - * @return 假设 type == TAG_TYPE_MIFARE_1024, - * 那么信息的长度应当是防冲撞信息加上配置信息再加上扇区大小的长度 +/** @brief Obtain the length of effective information for the information structure + * @param type Refined label type + * @return Suppose type == tag_type_mifare_1024, + * The length of the information should be the anti -collision information plus the configuration information plus the length of the sector */ static int get_information_size_by_tag_type(tag_specific_type_t type, bool auth_align) { int size_raw = sizeof(nfc_tag_14a_coll_res_entity_t) + sizeof(nfc_tag_mf1_configure_t) + (get_block_max_by_tag_type(type) * NFC_TAG_MF1_DATA_SIZE); @@ -1094,10 +1094,10 @@ static int get_information_size_by_tag_type(tag_specific_type_t type, bool auth_ return auth_align ? size_align : size_raw; } -/** @brief mf1保存数据之前的回调 - * @param type 细化的标签类型 - * @param buffer 数据缓冲区 - * @return 需要保存的数据的长度,为0时表示不保存 +/** @brief MF1's callback before saving data + * @param type Refined label type + * @param buffer Data buffer + * @return The length of the data that needs to be saved is that it does not save when 0 */ int nfc_tag_mf1_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer) { if (m_tag_type != TAG_TYPE_UNKNOWN) { @@ -1105,26 +1105,26 @@ int nfc_tag_mf1_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer) NRF_LOG_INFO("The mf1 is shadow write mode."); return 0; } - // 根据当前标签类型保存对应大小的数据 + // Save the corresponding size data according to the current label type return get_information_size_by_tag_type(type, false); } else { return 0; } } -/** @brief mf1加载数据 - * @param type 细化的标签类型 - * @param buffer 数据缓冲区 +/** @brief MF1 load data + * @param type Refined label type + * @param buffer Data buffer */ int nfc_tag_mf1_data_loadcb(tag_specific_type_t type, tag_data_buffer_t *buffer) { - // 确保外部容量足够转换为信息结构体 + // Make sure that external capacity is enough to convert to an information structure int info_size = get_information_size_by_tag_type(type, false); if (buffer->length >= info_size) { - // 将数据缓冲区强转为mf1结构类型 + //Convert the data buffer to MF1 structure type m_tag_information = (nfc_tag_mf1_information_t *)buffer->buffer; - // 缓存正在模拟的MF1的具体类型 + // The specific type of MF1 that is simulated by the cache m_tag_type = type; - // 注册14a通信管理接口 + // Register 14A communication management interface nfc_tag_14a_handler_t handler_for_14a = { .get_coll_res = get_mifare_coll_res, .cb_state = nfc_tag_mf1_state_handler, @@ -1138,7 +1138,7 @@ int nfc_tag_mf1_data_loadcb(tag_specific_type_t type, tag_data_buffer_t *buffer) return info_size; } -// 初始化mf1的工厂数据 +// Factory data for initialization of MF1 bool nfc_tag_mf1_data_factory(uint8_t slot, tag_specific_type_t tag_type) { // default mf1 data uint8_t default_blk0[] = { 0xDE, 0xAD, 0xBE, 0xFF, 0x32, 0x08, 0x04, 0x00, 0x01, 0x77, 0xA2, 0xCC, 0x35, 0xAF, 0xA5, 0x1D }; @@ -1193,22 +1193,22 @@ bool nfc_tag_mf1_data_factory(uint8_t slot, tag_specific_type_t tag_type) { return ret; } -// 设置是否使能侦测 +// Settling whether it enables detection void nfc_tag_mf1_set_detection_enable(bool enable) { m_tag_information->config.detection_enable = enable; } -// 当前是否使能侦测 +// Whether it can be detected at present bool nfc_tag_mf1_is_detection_enable(void) { return m_tag_information->config.detection_enable; } -// 清除侦测记录 +// Clear detection record void nfc_tag_mf1_detection_log_clear(void) { m_auth_log.count = 0; } -// 获得侦测记录的统计次数 +// The number of statistics of detection records uint32_t nfc_tag_mf1_detection_log_count(void) { return m_auth_log.count; } diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.h b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.h index 9b68627..41399cd 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.h +++ b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.h @@ -12,7 +12,7 @@ #define NFC_TAG_MF1_BLOCK_MAX 256 -// mf1标签写入模式 +//MF1 label writing mode typedef enum { NFC_TAG_MF1_WRITE_NORMAL = 0u, NFC_TAG_MF1_WRITE_DENIED = 1u, @@ -20,7 +20,7 @@ typedef enum { NFC_TAG_MF1_WRITE_SHADOW = 3u, } nfc_tag_mf1_write_mode_t; -// mf1标签gen1a模式状态机 +// MF1 tag Gen1a mode state machine typedef enum { GEN1A_STATE_DISABLE, GEN1A_STATE_UNLOCKING, @@ -28,21 +28,21 @@ typedef enum { GEN1A_STATE_WRITING, } nfc_tag_mf1_gen1a_state_machine_t; -// mf1标签标准模式状态机 +// MF1 label standard mode state machine typedef enum { - // 验证状态机 + // Verification state machine MF1_STATE_UNAUTH, MF1_STATE_AUTHING, MF1_STATE_AUTHED, - // 操作状态机 + // Operating state machine MF1_STATE_WRITE, MF1_STATE_INCREMENT, MF1_STATE_DECREMENT, MF1_STATE_RESTORE } nfc_tag_mf1_std_state_machine_t; -// mf1配置 +// MF1 configuration typedef struct { /** * Normal write mode (write normally according to the current state, affected by the control bit and the back door card) @@ -53,31 +53,31 @@ typedef struct { */ nfc_tag_mf1_write_mode_t mode_block_write; /** - * 互通模式,如果启用了互通模式,将会使用m1扇区数据中的部分信息 - * 否则将会使用防冲撞阶段单独定义的信息,此设置仅限4字节 NFC_TAG_14A_UID_SINGLE_SIZE 的卡有效 - * 除非有任何文档表明7字节和10字节的卡的0块有相关SAK的规范说明 + * In communication mode, if the interoperability mode is enabled, some information in the M1 sector data will be used + * Otherwise, the information defined by the anti -collision phase will be used alone. This setting is limited to 4 bytes NFC_TAG_14A_UID_SINGLE_SIZE. + * Unless there are any documents that indicate 0 blocks of 7 -bytes and 10 -byte cards with relevant SAK specifications */ uint8_t use_mf1_coll_res: 1; /** - * Chinese Gen1A 后门卡模式,此模式权限最高 - * 开启后将响应后门卡操作指令,并且所有的操作直接放行,不受 mode_block_write 和控制位影响 + * Chinese Gen1A back door card mode, the highest permissions of this mode + * After turning on, the response of the back door card operation instruction, and all operations are released directly, not affected by the Mode_block_write and control bit */ uint8_t mode_gen1a_magic: 1; /** - * 使能侦测,将自动记录mf1的验证日志 + * Make detection, it will automatically record the verification log of MF1 */ uint8_t detection_enable: 1; // Allow to write block 0 (CUID/gen2 mode) uint8_t mode_gen2_magic: 1; - // 保留 + // reserve uint8_t reserved1: 4; uint8_t reserved2; uint8_t reserved3; } nfc_tag_mf1_configure_t; /* - * mf1标签信息结构,谨记进行4字节对齐 - * 如果不进行字节对齐,在直接将此结构体申明并且保存到flash时将发生访问越界的异常 + * MF1 label information structure, keep in mind the 4 -byte alignment + * If the byte alignment is not performed, the abnormalities of visiting the cross -border will occur when the structure is directly stated and saved directly to the Flash */ typedef struct __attribute__((aligned(4))) { nfc_tag_14a_coll_res_entity_t res_coll; @@ -86,9 +86,9 @@ typedef struct __attribute__((aligned(4))) { } nfc_tag_mf1_information_t; -// 4Byte卡片的出厂固化的0块结构 +// 4 -earte card's 0 block structure of factory solidification typedef struct { - // 例如: + // For example: // 30928E04 28 08 0400 0177A2CC35AFA51D uint8_t uid[4]; uint8_t bcc[1]; @@ -97,38 +97,38 @@ typedef struct { uint8_t manufacturer[8]; } nfc_tag_mf1_factory_info_t; -// 通用的mf1扇区尾部块数据结构 +// General MF1 sector rear block data structure typedef struct { - uint8_t keya[6]; // 秘钥A - uint8_t acs[4]; // 控制位 - uint8_t keyb[6]; // 秘钥B + uint8_t keya[6]; // Secret A + uint8_t acs[4]; // Control position + uint8_t keyb[6]; // Secret B } nfc_tag_mf1_trailer_info_t; -// 专用于mifare通信的发送缓冲区 +// Send buffer dedicated to miFare communication typedef struct { - // 原始buffer,用于承载任何未经加密的指令 + // Primitive buffer, used to carry any unblocked instructions uint8_t tx_raw_buffer[NFC_TAG_MF1_FRAME_SIZE]; - // 经过crypto1加密后,每个字节的奇偶校验位 + // After Crypto1 encrypted, each byte of the puppet test is uint8_t tx_bit_parity[NFC_TAG_MF1_FRAME_SIZE]; - // 用于承载crypto1加密后的数据与parity合并之后的数据 - // The maximum frame length is 163 bits (16 data bytes + 2 CRC bytes = 16 × 9 + 2 × 9 + 1 start bit). + // Used to carry data after Crypto1 encrypted data and Parity merged data + // The maximum frame length is 163 bits (16 data bytes + 2 CRC bytes = 16 * 9 + 2 * 9 + 1 start bit). uint8_t tx_warp_frame[21]; - // 打包之后的数据的长度,根据上面的消息可知,mf1通信的最大bit数量不超过163个, - // 因此一个字节足够存放长度值 + // The length of the data after packing, according to the above news, it can be seen that the maximum number of BITs of MF1 communication does + // Therefore, a byte is sufficient to store the length value uint8_t tx_frame_bit_size; } nfc_tag_mf1_tx_buffer_t; -// mf1标签验证历史记录 +// MF1 label verification history typedef struct { - // 验证的基础信息 + // Basic information of verification struct { uint8_t block; uint8_t is_keyb: 1; uint8_t is_nested: 1; - // 空域,占位置用的 + // Airspace, occupying positions uint8_t : 6; } cmd; - // mfkey32必要参数 + // MFKEY32 necessary parametersessary parameters uint8_t uid[4]; uint8_t nt[4]; uint8_t nr[4]; diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_ntag.c b/firmware/application/src/rfid/nfctag/hf/nfc_ntag.c index 7244bda..3ffdf99 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_ntag.c +++ b/firmware/application/src/rfid/nfctag/hf/nfc_ntag.c @@ -69,13 +69,13 @@ const uint8_t ntagVersion[8] = {0x00, 0x04, 0x04, 0x02, 0x01, 0x00, 0x11, 0x03}; /* pwd auth for amiibo */ uint8_t ntagPwdOK[2] = {0x80, 0x80}; -// 指向标签信息的数据结构指针 +// Data structure pointer to the label information static nfc_tag_ntag_information_t *m_tag_information = NULL; -// 定义并且使用影子防冲撞资源 +// Define and use shadow anti -collision resources static nfc_tag_14a_coll_res_referen_t m_shadow_coll_res; -// 定义并且使用ntag专用通信缓冲区 +//Define and use NTAG special communication buffer static nfc_tag_ntag_tx_buffer_t m_tag_tx_buffer; -// 保存当前正在模拟的NTAG的具体类型 +// Save the specific type of NTAG currently being simulated static tag_specific_type_t m_tag_type; static int get_block_max_by_tag_type(tag_specific_type_t tag_type) { @@ -190,13 +190,13 @@ void nfc_tag_ntag_state_handler(uint8_t *p_data, uint16_t szDataBits) { } nfc_tag_14a_coll_res_referen_t *get_ntag_coll_res() { - // 使用单独的防冲突信息,而不是使用扇区中的信息 + // Use a separate anti -conflict information instead of using the information in the sector m_shadow_coll_res.sak = m_tag_information->res_coll.sak; m_shadow_coll_res.atqa = m_tag_information->res_coll.atqa; m_shadow_coll_res.uid = m_tag_information->res_coll.uid; m_shadow_coll_res.size = &(m_tag_information->res_coll.size); m_shadow_coll_res.ats = &(m_tag_information->res_coll.ats); - // 最终返回一个只带引用,不带实体的影子数据结构指针 + // Finally, a shadow data structure pointer with only reference, no physical shadow, return &m_shadow_coll_res; } @@ -208,14 +208,14 @@ static int get_information_size_by_tag_type(tag_specific_type_t type) { return sizeof(nfc_tag_14a_coll_res_entity_t) + sizeof(nfc_tag_ntag_configure_t) + (get_block_max_by_tag_type(type) * NFC_TAG_NTAG_DATA_SIZE); } -/** @brief ntag保存数据之前的回调 - * @param type 细化的标签类型 - * @param buffer 数据缓冲区 - * @return 需要保存的数据的长度,为0时表示不保存 +/** @brief ntag's callback before saving data + * @param type detailed label type + * @param buffer data buffer + * @return to be saved, the length of the data that needs to be saved, it means not saved when 0 */ int nfc_tag_ntag_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer) { if (m_tag_type != TAG_TYPE_UNKNOWN) { - // 根据当前标签类型保存对应大小的数据 + // Save the corresponding size data according to the current label type return get_information_size_by_tag_type(type); } else { return 0; @@ -225,11 +225,11 @@ int nfc_tag_ntag_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer int nfc_tag_ntag_data_loadcb(tag_specific_type_t type, tag_data_buffer_t *buffer) { int info_size = get_information_size_by_tag_type(type); if (buffer->length >= info_size) { - // 将数据缓冲区强转为ntag结构类型 + // Convert the data buffer to NTAG structure type m_tag_information = (nfc_tag_ntag_information_t *)buffer->buffer; - // 缓存正在模拟的Ntag的具体类型 + // The specific type of NTAG that is simulated by the cache m_tag_type = type; - // 注册14a通信管理接口 + // Register 14A communication management interface nfc_tag_14a_handler_t handler_for_14a = { .get_coll_res = get_ntag_coll_res, .cb_state = nfc_tag_ntag_state_handler, @@ -243,7 +243,7 @@ int nfc_tag_ntag_data_loadcb(tag_specific_type_t type, tag_data_buffer_t *buffer return info_size; } -// 初始化ntag的工厂数据 +// Initialized NTAG factory data bool nfc_tag_ntag_data_factory(uint8_t slot, tag_specific_type_t tag_type) { // default ntag data uint8_t default_p0[] = { 0x04, 0x68, 0x95, 0x71 }; diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_ntag.h b/firmware/application/src/rfid/nfctag/hf/nfc_ntag.h index c1eea75..c1e76ce 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_ntag.h +++ b/firmware/application/src/rfid/nfctag/hf/nfc_ntag.h @@ -15,7 +15,7 @@ typedef struct { uint8_t mode_uid_magic: 1; uint8_t detection_enable: 1; - // 保留 + // reserve uint8_t reserved1: 5; uint8_t reserved2; uint8_t reserved3; diff --git a/firmware/application/src/rfid/nfctag/lf/lf_tag_em.c b/firmware/application/src/rfid/nfctag/lf/lf_tag_em.c index 891fe5c..d609e2e 100644 --- a/firmware/application/src/rfid/nfctag/lf/lf_tag_em.c +++ b/firmware/application/src/rfid/nfctag/lf/lf_tag_em.c @@ -18,37 +18,37 @@ NRF_LOG_MODULE_REGISTER(); -// 获取指定的位置的bit +// Get the specified position bit #define GETBIT(v, bit) ((v >> bit) & 0x01) -// 天线控制 +// Antenna control #define ANT_TO_MOD() nrf_gpio_pin_set(LF_MOD) #define ANT_NO_MOD() nrf_gpio_pin_clear(LF_MOD) -// usb灯效是否允许使能 +// Whether the USB light effect is allowed to enable extern bool g_usb_led_marquee_enable; -// 承载64位ID号的比特数据 +// Bit data carrying 64 -bit ID number static uint64_t m_id_bit_data = 0; -// 当前发送的卡片ID的bit位置 +// The bit position of the card ID currently sent static uint8_t m_bit_send_position; -// 当前是否在发送第一个沿 +// Whether to send the first edge static bool m_is_send_first_edge; -// 当前广播ID号总计几次 33ms 一次,一秒钟大概能广播30次 +// The current broadcast ID number is 33ms every few times, and can be broadcast about 30 times a second static uint8_t m_send_id_count; -// 当前是否正在广播低频卡号中 +// Whether it is currently in the low -frequency card number of broadcasting static volatile bool m_is_lf_emulating = false; -// 发送卡号的定时器,我们使用定时器 3 +// The timer of the delivery card number, we use the timer 3 const nrfx_timer_t m_timer_send_id = NRFX_TIMER_INSTANCE(3); -// 缓存标签类型 +// Cache label type static tag_specific_type_t m_tag_type = TAG_TYPE_UNKNOWN; /** - * @brief 将EM410X的卡号转为U64的内存布局,计算奇偶校验位 - * 根据手册的说明 EM4100 使用U64足以容纳 + * @brief Convert the card number of EM410X to the memory layout of U64 and calculate the puppet school inspection + * According to the instructions of the manual, EM4100 is sufficient to accommodate U64 */ uint64_t em410x_id_to_memory64(uint8_t id[5]) { - // 联合体,所见即所得 + //Union, what you see is obtained union { uint64_t u64; struct { @@ -123,12 +123,12 @@ uint64_t em410x_id_to_memory64(uint8_t id[5]) { } bit; } memory; - // 好了,到了目前最关键的时候了,现在需要赋值和计算奇偶校验位了 - // 1、先把前导码给赋值了 + // Okay, it's the most critical time at present, and now you need to assign and calculate the Qiqi school inspection + // 1. First assign the front guide code memory.bit.h00 = memory.bit.h01 = memory.bit.h02 = memory.bit.h03 = memory.bit.h04 = memory.bit.h05 = memory.bit.h06 = memory.bit.h07 = memory.bit.h08 = 1; - // 2、把8bit的版本或者自定义ID给赋值了 + //2. Assign the 8bit version or custom ID memory.bit.d00 = GETBIT(id[0], 7); memory.bit.d01 = GETBIT(id[0], 6); memory.bit.d02 = GETBIT(id[0], 5); @@ -139,8 +139,8 @@ uint64_t em410x_id_to_memory64(uint8_t id[5]) { memory.bit.d12 = GETBIT(id[0], 1); memory.bit.d13 = GETBIT(id[0], 0); memory.bit.p1 = memory.bit.d10 ^ memory.bit.d11 ^ memory.bit.d12 ^ memory.bit.d13; - // 3、把32bit的数据给赋值了 - // - byte1 + // 3. Assign the data of 32Bit + // -byte1 memory.bit.d20 = GETBIT(id[1], 7); memory.bit.d21 = GETBIT(id[1], 6); memory.bit.d22 = GETBIT(id[1], 5); @@ -184,85 +184,85 @@ uint64_t em410x_id_to_memory64(uint8_t id[5]) { memory.bit.d92 = GETBIT(id[4], 1); memory.bit.d93 = GETBIT(id[4], 0); memory.bit.p9 = memory.bit.d90 ^ memory.bit.d91 ^ memory.bit.d92 ^ memory.bit.d93; - // 4、计算纵向的偶校验 + // 4. Calculate the vertical puppet verification memory.bit.pc0 = memory.bit.d00 ^ memory.bit.d10 ^ memory.bit.d20 ^ memory.bit.d30 ^ memory.bit.d40 ^ memory.bit.d50 ^ memory.bit.d60 ^ memory.bit.d70 ^ memory.bit.d80 ^ memory.bit.d90; memory.bit.pc1 = memory.bit.d01 ^ memory.bit.d11 ^ memory.bit.d21 ^ memory.bit.d31 ^ memory.bit.d41 ^ memory.bit.d51 ^ memory.bit.d61 ^ memory.bit.d71 ^ memory.bit.d81 ^ memory.bit.d91; memory.bit.pc2 = memory.bit.d02 ^ memory.bit.d12 ^ memory.bit.d22 ^ memory.bit.d32 ^ memory.bit.d42 ^ memory.bit.d52 ^ memory.bit.d62 ^ memory.bit.d72 ^ memory.bit.d82 ^ memory.bit.d92; memory.bit.pc3 = memory.bit.d03 ^ memory.bit.d13 ^ memory.bit.d23 ^ memory.bit.d33 ^ memory.bit.d43 ^ memory.bit.d53 ^ memory.bit.d63 ^ memory.bit.d73 ^ memory.bit.d83 ^ memory.bit.d93; - // 5、设置最后一个EOF的位,这波转换就算是结束了 + //5. Set the position of the last EOF, this wave of conversion is over memory.bit.s0 = 0; - // 返回联合体中的u64数据,这才是我们最终需要的数据, - // 后期模拟卡只需要拿出每个bit去发送就行了 + //Return to the U64 data in the combination, this is the data we finally need, + // In the later stage analog card, just take out each bit to send it return memory.u64; } /** -* @brief 判断场状态 +* @brief Judgment field status */ bool lf_is_field_exists(void) { nrf_drv_lpcomp_enable(); - bsp_delay_us(20); // 延迟一段时间再采样,避免误判 - nrf_lpcomp_task_trigger(NRF_LPCOMP_TASK_SAMPLE); // 触发一次采样 - return nrf_lpcomp_result_get() == 1; // 判断LF场状态的采样结果 + bsp_delay_us(20); // Display for a period of time and sampling to avoid misjudgment + nrf_lpcomp_task_trigger(NRF_LPCOMP_TASK_SAMPLE); //Trigger a sampling + return nrf_lpcomp_result_get() == 1; //Determine the sampling results of the LF field status } void timer_ce_handler(nrf_timer_event_t event_type, void *p_context) { bool mod; switch (event_type) { - // 因为我们配置的是使用CC通道2,所以事件回调 - // 函数中判断NRF_TIMER_EVENT_COMPARE0事件 + // Because we are configured using the CC channel 2, the event recovers + // Detect nrf_timer_event_compare0 event in the function case NRF_TIMER_EVENT_COMPARE2: { if (m_is_send_first_edge) { if (GETBIT(m_id_bit_data, m_bit_send_position)) { - // 发送 1 的第一个沿 + // The first edge of the send 1 ANT_TO_MOD(); mod = true; } else { - // 发送 0 的第一个沿 + // The first edge of the send 0 ANT_NO_MOD(); mod = false; } - m_is_send_first_edge = false; // 下次发送第二个沿 + m_is_send_first_edge = false; //The second edge is sent next time } else { if (GETBIT(m_id_bit_data, m_bit_send_position)) { - // 发送 1 的第二个沿 + // Send the second edge of 1 ANT_NO_MOD(); mod = false; } else { - // 发送 0 的第二个沿 + //The second edge of the send 0 ANT_TO_MOD(); mod = true; } - m_is_send_first_edge = true; // 下次发送第一个沿 + m_is_send_first_edge = true; //The first edge of the next sends next time } // measure field only during no-mod half of last bit of last broadcast if ((! mod) && (m_bit_send_position + 1 >= LF_125KHZ_EM410X_BIT_SIZE) && (m_send_id_count + 1 >= LF_125KHZ_BORADCAST_MAX)) { - nrfx_timer_disable(&m_timer_send_id); // 关闭广播场的定时器 - // 我们不需要任何的事件,仅仅需要检测一下场的状态 + nrfx_timer_disable(&m_timer_send_id); // Close the timer of the broadcast venue + // We don't need any events, but only need to detect the state of the field NRF_LPCOMP->INTENCLR = LPCOMP_INTENCLR_CROSS_Msk | LPCOMP_INTENCLR_UP_Msk | LPCOMP_INTENCLR_DOWN_Msk | LPCOMP_INTENCLR_READY_Msk; if (lf_is_field_exists()) { nrf_drv_lpcomp_disable(); - nrfx_timer_enable(&m_timer_send_id); // 打开广播场的定时器,继续模拟 + nrfx_timer_enable(&m_timer_send_id); // Open the timer of the broadcaster and continue to simulate } else { - // 开启事件中断,让下次场事件可以正常出入 - g_is_tag_emulating = false; // 重设模拟中的标志位 + // Open the incident interruption, so that the next event can be in and out normally + g_is_tag_emulating = false; // Reset the flag in the simulation m_is_lf_emulating = false; - TAG_FIELD_LED_OFF() // 确保关闭LF的场状态的指示灯 + TAG_FIELD_LED_OFF() // Make sure the indicator light of the LF field status NRF_LPCOMP->INTENSET = LPCOMP_INTENCLR_CROSS_Msk | LPCOMP_INTENCLR_UP_Msk | LPCOMP_INTENCLR_DOWN_Msk | LPCOMP_INTENCLR_READY_Msk; // call sleep_timer_start *after* unsetting g_is_tag_emulating - sleep_timer_start(SLEEP_DELAY_MS_FIELD_125KHZ_LOST); // 启动进入休眠的定时器 + sleep_timer_start(SLEEP_DELAY_MS_FIELD_125KHZ_LOST); // Start the timer to enter the sleep NRF_LOG_INFO("LF FIELD LOST"); } } - if (m_is_send_first_edge == true) { // 下次发送第一个沿 + if (m_is_send_first_edge == true) { // The first edge of the next sends next time if (++m_bit_send_position >= LF_125KHZ_EM410X_BIT_SIZE) { - m_bit_send_position = 0; // 广播一次成功,bit位置归零 + m_bit_send_position = 0; // The broadcast is successful once, and the BIT position is zero if (++m_send_id_count >= LF_125KHZ_BORADCAST_MAX) { - m_send_id_count = 0; // 广播次数达到上限,重新识别场状态并且重新统计广播次数 + m_send_id_count = 0; //The number of broadcasts reaches the upper limit, re -identifies the status of the field and re -statistically count the number of broadcast times } } } @@ -284,30 +284,30 @@ void timer_ce_handler(nrf_timer_event_t event_type, void *p_context) { * priority is set to APP_IRQ_PRIORITY_HIGH). */ static void lpcomp_event_handler(nrf_lpcomp_event_t event) { - // 仅限于未启动低频模拟时,并且是上升沿事件才去启动模拟卡 + // Only when the low -frequency simulation is not launched, and the analog card is started if (!m_is_lf_emulating && event == NRF_LPCOMP_EVENT_UP) { - // 关闭休眠延时 + // Turn off dormant delay sleep_timer_stop(); - // 关闭比较器 + // Close the comparator nrf_drv_lpcomp_disable(); - // 设置模拟状态标志位 + // Set the simulation status logo bit m_is_lf_emulating = true; g_is_tag_emulating = true; - // 模拟卡状态应当关闭USB灯效 + // Simulation card status should be turned off the USB light effect g_usb_led_marquee_enable = false; - // LED状态更新 + // LED status update set_slot_light_color(2); TAG_FIELD_LED_ON() - // 无论如何,每次场状态发现变化都需要重置发送的bit位置 + //In any case, every time the state finds changes, you need to reset the BIT location of the sending m_send_id_count = 0; m_bit_send_position = 0; m_is_send_first_edge = true; - // 开启精准的硬件定时器去广播卡号 + // openThePreciseHardwareTimerToTheBroadcastCardNumber nrfx_timer_enable(&m_timer_send_id); NRF_LOG_INFO("LF FIELD DETECTED"); @@ -338,9 +338,9 @@ static void lf_sense_enable(void) { } static void lf_sense_disable(void) { - nrfx_timer_uninit(&m_timer_send_id); // 反初始化定时器 - nrfx_lpcomp_uninit(); // 反初始化比较器 - m_is_lf_emulating = false; // 设置为非模拟中状态 + nrfx_timer_uninit(&m_timer_send_id); //counterInitializationTimer + nrfx_lpcomp_uninit(); //antiInitializationComparator + m_is_lf_emulating = false; //setAsNonSimulatedState } static enum { @@ -350,21 +350,21 @@ static enum { } m_lf_sense_state = LF_SENSE_STATE_NONE; /** - * @brief 切换LF场感应使能状态 + * @brief switchLfFieldInductionToEnableTheState */ void lf_tag_125khz_sense_switch(bool enable) { - // 初始化调制脚为输出 + // initializationModulationFootIsOutput nrf_gpio_cfg_output(LF_MOD); - // 默认不短路天线(短路会导致RSSI无法判断) + //theDefaultIsNotShortCircuitAntenna (shortCircuitWillCauseRssiToBeUnableToJudge) ANT_NO_MOD(); - // 首次执行或者是禁用状态,只允许初始化 + //forTheFirstTimeOrDisabled,OnlyInitializationIsAllowed if (m_lf_sense_state == LF_SENSE_STATE_NONE || m_lf_sense_state == LF_SENSE_STATE_DISABLE) { if (enable) { m_lf_sense_state = LF_SENSE_STATE_ENABLE; lf_sense_enable(); } - } else { // 其他情况只允许反初始化 + } else { // inOtherCases,OnlyAntiInitializationIsAllowed if (!enable) { m_lf_sense_state = LF_SENSE_STATE_DISABLE; lf_sense_disable(); @@ -372,14 +372,14 @@ void lf_tag_125khz_sense_switch(bool enable) { } } -/** @brief em410x加载数据 - * @param type 细化的标签类型 - * @param buffer 数据缓冲区 +/** @brief EM410X load data + * @param type Refined label type + * @param buffer Data buffer */ int lf_tag_em410x_data_loadcb(tag_specific_type_t type, tag_data_buffer_t *buffer) { - // 确保外部容量足够转换为信息结构体 + //Make sure that external capacity is enough to convert to an information structure if (buffer->length >= LF_EM410X_TAG_ID_SIZE) { - // 此处直接转换ID卡号为对应的bit数据流 + // The ID card number is directly converted here as the corresponding BIT data stream m_tag_type = type; m_id_bit_data = em410x_id_to_memory64(buffer->buffer); NRF_LOG_INFO("LF Em410x data load finish."); @@ -389,34 +389,34 @@ int lf_tag_em410x_data_loadcb(tag_specific_type_t type, tag_data_buffer_t *buffe return LF_EM410X_TAG_ID_SIZE; } -/** @brief ID卡保存卡号之前的回调 - * @param type 细化的标签类型 - * @param buffer 数据缓冲区 - * @return 需要保存的数据的长度,为0时表示不保存 +/** @brief Id card deposit card number before callback + * @param type Refined label type + * @param buffer Data buffer + * @return The length of the data that needs to be saved is that it does not save when 0 */ int lf_tag_em410x_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer) { - // 确保加载了此标签才允许保存 + // Make sure to load this label before allowing saving if (m_tag_type != TAG_TYPE_UNKNOWN) { - // 直接保存原本的卡包即可 + // Just save the original card package directly return LF_EM410X_TAG_ID_SIZE; } else { return 0; } } -/** @brief ID卡保存卡号之前的回调 - * @param slot 卡槽号码 - * @param tag_type 细化的标签类型 - * @return 是否格式化成功,如果格式化成功,将返回true,否则返回false +/** @brief Id card deposit card number before callback + * @param slot Card slot number + * @param tag_type Refined label type + * @return Whether the format is successful, if the formatting is successful, it will return to True, otherwise False will be returned */ bool lf_tag_em410x_data_factory(uint8_t slot, tag_specific_type_t tag_type) { // default id, must to align(4), more word... uint8_t tag_id[8] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x88 }; - // 将数据写进去flash + // Write the data in Flash tag_sense_type_t sense_type = get_sense_type_from_tag_type(tag_type); - fds_slot_record_map_t map_info; // 获取专用卡槽FDS记录信息 + fds_slot_record_map_t map_info; // Get the special card slot FDS record information get_fds_map_by_slot_sense_type_for_dump(slot, sense_type, &map_info); - // 调用堵塞式的fds写入函数,将卡槽指定场类型的数据写入到flash中 + //Call the blocked FDS to write the function, and write the data of the specified field type of the card slot into the Flash bool ret = fds_write_sync(map_info.id, map_info.key, sizeof(tag_id) / 4, (uint8_t *)tag_id); if (ret) { NRF_LOG_INFO("Factory slot data success."); diff --git a/firmware/application/src/rfid/nfctag/lf/lf_tag_em.h b/firmware/application/src/rfid/nfctag/lf/lf_tag_em.h index 7117c55..fb443f8 100644 --- a/firmware/application/src/rfid/nfctag/lf/lf_tag_em.h +++ b/firmware/application/src/rfid/nfctag/lf/lf_tag_em.h @@ -7,11 +7,11 @@ /** - * 低频模拟卡调制曼彻斯特信号 - * 封装工具宏定义只需要调制0和1 + * Low -frequency analog card adjustment Manchester signal + * The definition of the packaging tool macro only needs to be modulated 0 and 1 */ #define LF_125KHZ_EM410X_BIT_SIZE 64 -#define LF_125KHZ_BORADCAST_MAX 3 // 32.768ms一次,一秒大概能广播31次 +#define LF_125KHZ_BORADCAST_MAX 3 // 32.768ms once, about 31 times in one second #define LF_125KHZ_EM410X_BIT_CLOCK 256 #define LF_EM410X_TAG_ID_SIZE 5 diff --git a/firmware/application/src/rfid/nfctag/tag_base_type.h b/firmware/application/src/rfid/nfctag/tag_base_type.h index 224b1e2..0e874a1 100644 --- a/firmware/application/src/rfid/nfctag/tag_base_type.h +++ b/firmware/application/src/rfid/nfctag/tag_base_type.h @@ -2,33 +2,33 @@ #define TAG_BASE_TYPE_H -// 场的感应类型 +// Field sensor type typedef enum { - // 无场感应 + //No sense of induction TAG_SENSE_NO, - // 低频125khz场感应 + // Low -frequency 125kHz field induction TAG_SENSE_LF, - // 高频13.56mhz场感应 + // High -frequency 13.56MHz field induction TAG_SENSE_HF, } tag_sense_type_t; /** * - * 所有支持模拟的标签的类型的定义 - * 注意,以下所有定义的标签类型,都是应用层的细化的具体的类型统计 - * 不再区分高低频 + *The definition of all types of labels that support analog + * Note that all the defined label type below is the specific type statistics of the application layer refine + * No longer distinguish between high and low frequencies */ typedef enum { - // 特定的且必须存在的标志不存在的类型 + //Specific and necessary signs do not exist TAG_TYPE_UNKNOWN, - // 125khz(ID卡)系列 + //125kHz (ID card) series TAG_TYPE_EM410X, - // Mifare系列 + // MiFare series TAG_TYPE_MIFARE_Mini, TAG_TYPE_MIFARE_1024, TAG_TYPE_MIFARE_2048, TAG_TYPE_MIFARE_4096, - // NTAG系列 + // NTAG series TAG_TYPE_NTAG_213, TAG_TYPE_NTAG_215, TAG_TYPE_NTAG_216, diff --git a/firmware/application/src/rfid/nfctag/tag_emulation.c b/firmware/application/src/rfid/nfctag/tag_emulation.c index b7217b7..a036878 100644 --- a/firmware/application/src/rfid/nfctag/tag_emulation.c +++ b/firmware/application/src/rfid/nfctag/tag_emulation.c @@ -18,41 +18,41 @@ NRF_LOG_MODULE_REGISTER(); /* - * 一个卡槽最多可以同时模拟两种卡,一张ID 125khz em410x,一张IC 13.56mhz 14a。(以后可能可以支持更多) - * 启动的时候,应当按需启动该启动的场监听器(无数据加载时可不模拟卡,但是需要按需监听场的状态) - * 如果检索到的卡槽的配置拥有指定的类型的卡片,那么应当进行指定类型的数据的加载,初始化必要的参数 - * 检测到场入场出时,除了需要对相关的LED进行操作外,还需要根据当前数据是否加载来开始模拟卡 - * 在模拟卡,所有的操作应当都是基于RAM中加载的数据进行,在模拟卡结束后,应当将修改的数据进行保存更新到flash + * A card slot can simulate up to two cards at the same time, one ID 125kHz EM410X, and one IC 13.56MHz 14A.(May be able to support more in the future) + * When starting, you should start the startup listener on demand (there is no simulatory card when there is no data, but you need to monitor the state on demand) + * If the retrieved card slot configuration has a specified type of card, then loading the specified type of data should be carried out, and the necessary parameters of initialization should be performed. + * When the on -site entry is detected, in addition to the relevant LED, you also need to start the simulation card according to whether the current data is loaded. + * In the simulation card, all operations should be carried out based on the data loaded in RAM. After the analog card is over, the modified data should be preserved to Flash * * * * ...... */ -// 标志当前是否在模拟卡中 +// Is the logo in the analog card? bool g_is_tag_emulating = false; -// ********************** 可持久化参数开始 ********************** +// ********************** Specific parameters start ********************** /** - * 标签数据存在于flash中的信息,总长度必须要 4字节(整字)对齐!!! + * The label data exists in the information in Flash, and the total length must be aligned by 4 bytes (whole words)!IntersectionIntersection */ -static uint8_t m_tag_data_buffer_lf[12]; // 低频卡数据缓冲区 +static uint8_t m_tag_data_buffer_lf[12]; // Low -frequency card data buffer static uint16_t m_tag_data_lf_crc; static tag_data_buffer_t m_tag_data_lf = { sizeof(m_tag_data_buffer_lf), m_tag_data_buffer_lf, &m_tag_data_lf_crc }; -static uint8_t m_tag_data_buffer_hf[4500]; // 高频卡数据缓冲区 +static uint8_t m_tag_data_buffer_hf[4500]; // High -frequency card data buffer static uint16_t m_tag_data_hf_crc; static tag_data_buffer_t m_tag_data_hf = { sizeof(m_tag_data_buffer_hf), m_tag_data_buffer_hf, &m_tag_data_hf_crc }; /** - * 八个卡槽,每个卡槽都有其特有的配置 + * Eight card slots, each card slot has its own unique configuration */ static tag_slot_config_t slotConfig ALIGN_U32 = { - // 配置激活的卡槽,默认激活第0个卡槽(第一张卡) + // Configure activated card slot, default activation of the 0th card slot (the first card) .config = { .activated = 0, .reserved1 = 0, .reserved2 = 0, .reserved3 = 0, }, - // 配置卡槽组 + // Configuration card slot group .group = { { .enable = true, .reserved1 = 0, .reserved2 = 0, .tag_hf = TAG_TYPE_MIFARE_1024, .tag_lf = TAG_TYPE_EM410X, }, // 1 { .enable = true, .reserved1 = 0, .reserved2 = 0, .tag_hf = TAG_TYPE_MIFARE_1024, .tag_lf = TAG_TYPE_UNKNOWN, }, // 2 @@ -64,26 +64,26 @@ static tag_slot_config_t slotConfig ALIGN_U32 = { { .enable = false, .reserved1 = 0, .reserved2 = 0, .tag_hf = TAG_TYPE_UNKNOWN, .tag_lf = TAG_TYPE_UNKNOWN, }, // 8 }, }; -// 卡槽配置特有的CRC,一旦slot配置发生变动,可通过CRC检查出来 +// The card slot configuration unique CRC, once the slot configuration changes, can be checked by CRC static uint16_t m_slot_config_crc; -// ********************** 可持久化参数结束 ********************** +// ********************** Specific parameter ends ********************** /** - * 标签的数据加载到RAM后回调通知的实现操作的映射表, - * 映射结构为: - * 场类型 细化的标签类型 加载数据成功后的通知回调 数据保存前的通知回调 初始化数据的实现函数 卡片数据的缓冲区 + * The data of the label is loaded to the RAM and the mapping table of the operation of the regulating notification, + * The mapping structure is: + * Field -type detailed label type Loading data The notification of the notification of the notification of the notification of the call recovery data before saving the data of the realization data of the function card data */ static tag_base_handler_map_t tag_base_map[] = { - // 低频ID卡模拟 + // Low -frequency ID card simulation { TAG_SENSE_LF, TAG_TYPE_EM410X, lf_tag_em410x_data_loadcb, lf_tag_em410x_data_savecb, lf_tag_em410x_data_factory, &m_tag_data_lf }, - // MF1标签模拟 + // MF1 tag simulation { TAG_SENSE_HF, TAG_TYPE_MIFARE_Mini, nfc_tag_mf1_data_loadcb, nfc_tag_mf1_data_savecb, nfc_tag_mf1_data_factory, &m_tag_data_hf }, { TAG_SENSE_HF, TAG_TYPE_MIFARE_1024, nfc_tag_mf1_data_loadcb, nfc_tag_mf1_data_savecb, nfc_tag_mf1_data_factory, &m_tag_data_hf }, { TAG_SENSE_HF, TAG_TYPE_MIFARE_2048, nfc_tag_mf1_data_loadcb, nfc_tag_mf1_data_savecb, nfc_tag_mf1_data_factory, &m_tag_data_hf }, { TAG_SENSE_HF, TAG_TYPE_MIFARE_4096, nfc_tag_mf1_data_loadcb, nfc_tag_mf1_data_savecb, nfc_tag_mf1_data_factory, &m_tag_data_hf }, - // NTAG标签模拟 + // NTAG tag simulation { TAG_SENSE_HF, TAG_TYPE_NTAG_213, nfc_tag_ntag_data_loadcb, nfc_tag_ntag_data_savecb, nfc_tag_ntag_data_factory, &m_tag_data_hf }, { TAG_SENSE_HF, TAG_TYPE_NTAG_215, nfc_tag_ntag_data_loadcb, nfc_tag_ntag_data_savecb, nfc_tag_ntag_data_factory, &m_tag_data_hf }, { TAG_SENSE_HF, TAG_TYPE_NTAG_216, nfc_tag_ntag_data_loadcb, nfc_tag_ntag_data_savecb, nfc_tag_ntag_data_factory, &m_tag_data_hf }, @@ -91,7 +91,7 @@ static tag_base_handler_map_t tag_base_map[] = { /** - * 根据指定的细化标签类型,获得其处理加载的数据的实现函数 + * accordingToTheSpecifiedDetailedLabelType,ObtainTheImplementationFunctionOfTheDataThatProcessesTheLoadedLoaded */ static tag_datas_loadcb_t get_data_loadcb_from_tag_type(tag_specific_type_t type) { for (int i = 0; i < ARRAY_SIZE(tag_base_map); i++) { @@ -103,7 +103,7 @@ static tag_datas_loadcb_t get_data_loadcb_from_tag_type(tag_specific_type_t type } /** - * 根据指定的细化标签类型,获得其处数据保存前的操作函数 + * accordingToTheSpecifiedDetailedLabelType,ObtainTheOperationFunctionBeforeTheDataPreservationOfTheData */ static tag_datas_savecb_t get_data_savecb_from_tag_type(tag_specific_type_t type) { for (int i = 0; i < ARRAY_SIZE(tag_base_map); i++) { @@ -115,7 +115,7 @@ static tag_datas_savecb_t get_data_savecb_from_tag_type(tag_specific_type_t type } /** - * 根据指定的细化标签类型,获得其处数据工厂初始化的操作函数 + * accordingToTheSpecifiedDetailedLabelType,ObtainTheOperationFunctionOfTheDataFactoryInitialized */ static tag_datas_factory_t get_data_factory_from_tag_type(tag_specific_type_t type) { for (int i = 0; i < ARRAY_SIZE(tag_base_map); i++) { @@ -127,7 +127,7 @@ static tag_datas_factory_t get_data_factory_from_tag_type(tag_specific_type_t ty } /** - * 根据指定的细化标签类型,获得其基础的场感应类型 + * accordingToTheSpecifiedDetailedLabelType,ObtainItsBasicFieldInductionType */ tag_sense_type_t get_sense_type_from_tag_type(tag_specific_type_t type) { for (int i = 0; i < ARRAY_SIZE(tag_base_map); i++) { @@ -139,7 +139,7 @@ tag_sense_type_t get_sense_type_from_tag_type(tag_specific_type_t type) { } /** - * 根据类型获取缓冲区信息 + * obtainTheBufferInformationAccordingToTheType */ tag_data_buffer_t *get_buffer_by_tag_type(tag_specific_type_t type) { for (int i = 0; i < ARRAY_SIZE(tag_base_map); i++) { @@ -151,21 +151,20 @@ tag_data_buffer_t *get_buffer_by_tag_type(tag_specific_type_t type) { } /** -* 从内存中加载数据到模拟卡数据之中 +* loadDataFromMemoryToTheSimulationCardData */ bool tag_emulation_load_by_buffer(tag_specific_type_t tag_type, bool update_crc) { - // 数据已经加载到缓冲区,接下来根据激活的卡槽的配置, - // 将设定的模拟卡类型(高频卡, 低频卡)指向的场感应配备的BUFFER传递给其 + // theDataHasBeenLoadedToTheBufferArea,AndTheConfigurationOfTheActivatedCardSlotIsNext, //PassTheBufferOfTheSettingOfTheSettingSimulationCardType (highFrequencyCard,LowFrequencyCard)ToIt tag_datas_loadcb_t fn_loadcb = get_data_loadcb_from_tag_type(tag_type); - if (fn_loadcb == NULL) { // 确保有实现对应的加载过程 + if (fn_loadcb == NULL) { //makeSureThatThereIsACorrespondingLoadingProcess NRF_LOG_INFO("Tag data loader no impl."); return false; } - // 通知对应的实现,我们加载完成数据了 + //theCorrespondingImplementation,WeHaveLoadedTheData tag_data_buffer_t *buffer = get_buffer_by_tag_type(tag_type); int length = fn_loadcb(tag_type, buffer); if (length > 0 && update_crc) { - // 读取完成后,我们先保存一份当前数据的CRC,后面保存的时候可以作为变动对比的参考 + // afterReadingIsCompleted,WeCanSaveACrcOfTheCurrentDataWhenItIsStoredLater,ItCanBeUsedAsAReferenceForChangesComparison calc_14a_crc_lut(buffer->buffer, length, (uint8_t *)buffer->crc); return true; } @@ -173,25 +172,24 @@ bool tag_emulation_load_by_buffer(tag_specific_type_t tag_type, bool update_crc) } /** - * 根据类型加载数据 + * loadTheDataAccordingToTheType */ static void load_data_by_tag_type(uint8_t slot, tag_specific_type_t tag_type) { - // 可能该卡槽未启用该类型的标签的模拟,直接跳过加载此数据 + // maybeTheCardSlotIsNotEnabledToUseTheSimulationOfThisTypeOfLabel,AndSkipTheDataDirectlyToLoadThisData if (tag_type == TAG_TYPE_UNKNOWN) { return; } - // 获取专用缓冲区信息 + // getTheSpecialBufferInformation tag_data_buffer_t *buffer = get_buffer_by_tag_type(tag_type); if (buffer == NULL) { NRF_LOG_ERROR("No buffer valid!"); return; } tag_sense_type_t sense_type = get_sense_type_from_tag_type(tag_type); - // 获取专用卡槽FDS记录信息 + // getTheSpecialCardSlotFdsRecordInformation fds_slot_record_map_t map_info; get_fds_map_by_slot_sense_type_for_dump(slot, sense_type, &map_info); - // 根据当前激活的卡槽的场类型,加载指定场的数据到缓冲区 - // 提示: 如果数据与buffer长度无法匹配,则可能是固件更新导致,这个时候就要将数据进行删除重建 + // accordingToTheTypeOfTheCardSlotCurrentlyActivated,LoadTheDataOfTheDesignatedFieldToTheBuffer //Tip:IfTheLengthOfTheDataCannotMatchTheLengthOfTheBuffer,ItMayBeCausedByTheFirmwareUpdateAtThisTime,TheDataMustBeDeletedAndRebuilt bool ret = fds_read_sync(map_info.id, map_info.key, buffer->length, buffer->buffer); if (false == ret) { NRF_LOG_INFO("Tag slot data no exists."); @@ -204,10 +202,10 @@ static void load_data_by_tag_type(uint8_t slot, tag_specific_type_t tag_type) { } /** - * 根据类型保存数据 + * Save data according to the type */ static void save_data_by_tag_type(uint8_t slot, tag_specific_type_t tag_type) { - // 可能该卡槽未启用该类型的标签的模拟,直接跳过保存此数据 + // Maybe the card slot is not enabled to use the simulation of this type of label, and skip it directly to save this data if (tag_type == TAG_TYPE_UNKNOWN) { return; } @@ -216,51 +214,51 @@ static void save_data_by_tag_type(uint8_t slot, tag_specific_type_t tag_type) { NRF_LOG_ERROR("No buffer valid!"); return; } - // 获取用户要保存的数据的长度,这个长度不应该超过全局buffer的大小 + // The length of the data to be saved by the user should not exceed the size of the global buffer int data_byte_length = 0; tag_datas_savecb_t fn_savecb = get_data_savecb_from_tag_type(tag_type); - if (fn_savecb == NULL) { // 确保有实现保存过程 + if (fn_savecb == NULL) { //Make sure that there is a real estate process NRF_LOG_INFO("Tag data saver no impl."); return; } else { data_byte_length = fn_savecb(tag_type, buffer); } - // 确保需要保存数据,我们可以通过crc进行判断数据是否发生了变动 + // Make sure to save data, we can judge whether the data has changed through CRC if (data_byte_length <= 0) { NRF_LOG_INFO("Tag type %d data no save.", tag_type); return; } - // 确保要保存的数据不大于目前的缓冲区大小 + // Make sure that the data to be stored is not greater than the size of the current buffer area if (data_byte_length > buffer->length) { NRF_LOG_ERROR("Tag data save length overflow.", tag_type); return; } uint16_t crc; calc_14a_crc_lut(buffer->buffer, data_byte_length, (uint8_t *)&crc); - // 判断数据是否数据发生了变动 + // Determine whether the data has changed if (crc == *buffer->crc) { NRF_LOG_INFO("Tag slot data no change, length = %d", data_byte_length); return; } tag_sense_type_t sense_type = get_sense_type_from_tag_type(tag_type); - // 获取专用卡槽FDS记录信息 + // Get the special card slot FDS record information fds_slot_record_map_t map_info; get_fds_map_by_slot_sense_type_for_dump(slot, sense_type, &map_info); - // 计算要保存的数据的长度(自动填充整字) + // Calculate the length of the data to be saved (automatically fill in the whole word) int data_word_length = (data_byte_length / 4) + (data_byte_length % 4 > 0 ? 1 : 0); - // 调用堵塞式的fds写入函数,将卡槽指定场类型的数据写入到flash中 + // Call the blocked FDS to write the function, and write the data of the specified field type of the card slot into the Flash bool ret = fds_write_sync(map_info.id, map_info.key, data_word_length, buffer->buffer); if (ret) { NRF_LOG_INFO("Save tag slot data success."); } else { NRF_LOG_ERROR("Save tag slot data error."); } - // 保存完成之后,更新对应内存中的buffer的CRC + //After the preservation is completed, the CRC of the BUFFER in the corresponding memory *buffer->crc = crc; } /** - * 根据类型删除数据 + * Delete data according to the type */ static void delete_data_by_tag_type(uint8_t slot, tag_sense_type_t sense_type) { if (sense_type == TAG_SENSE_NO) { @@ -273,8 +271,8 @@ static void delete_data_by_tag_type(uint8_t slot, tag_sense_type_t sense_type) { } /** - * 加载模拟卡卡片数据,注意,加载仅仅是数据操作, - * 启动模拟卡请调用 tag_emulation_sense_run 函数,否则不会感应场事件 + * Load the simulation card data data. Note that loading is just data operation, + * Start the analog card, please call tag_emuration_sense_run function, otherwise you will not sensor the field event */ void tag_emulation_load_data(void) { uint8_t slot = tag_emulation_get_slot(); @@ -283,7 +281,7 @@ void tag_emulation_load_data(void) { } /** - * 保存模拟卡配置数据,在合适的时机,应当调用此函数进行数据的保存 + *Save the simulatory card configuration data. At the right time, this function should be called for data preservation of data */ void tag_emulation_save_data(void) { uint8_t slot = tag_emulation_get_slot(); @@ -292,10 +290,10 @@ void tag_emulation_save_data(void) { } /** - * @brief 获取模拟卡的标签类型,从对应卡槽中。 + * @brief Get the type of labeling of the simulation card from the corresponding card slot. * - * @param slot 卡槽 - * @param tag_type 标签类型 + * @param slot Card slot + * @param tag_type Label */ void tag_emulation_get_specific_type_by_slot(uint8_t slot, tag_specific_type_t tag_type[2]) { tag_type[0] = slotConfig.group[slot].tag_hf; @@ -303,12 +301,12 @@ void tag_emulation_get_specific_type_by_slot(uint8_t slot, tag_specific_type_t t } /** - * 删除某个卡槽指定的场类型的数据,如果是当前的激活的卡槽的数据,我们还需要动态关闭此卡片的模拟 + * Delete the data specified by a card slot, if it is the current activated card slot data, we also need to dynamically close the simulation of this card */ void tag_emulation_delete_data(uint8_t slot, tag_sense_type_t sense_type) { - // 删除数据 + // delete data delete_data_by_tag_type(slot, sense_type); - // 关闭对应的卡槽的模拟卡类型 + //Close the corresponding card type of the corresponding card slot switch (sense_type) { case TAG_SENSE_HF: { slotConfig.group[slot].tag_hf = TAG_TYPE_UNKNOWN; @@ -321,25 +319,25 @@ void tag_emulation_delete_data(uint8_t slot, tag_sense_type_t sense_type) { default: break; } - // 如果删除的卡槽数据是当前激活的卡槽的(正在模拟),我们还需要进行动态关闭 + // If the deleted card slot data is currently activated (being simulated), we also need to make dynamic shutdown if (slotConfig.config.activated == slot) { tag_emulation_sense_switch(sense_type, false); } - // 如果删除了之后,我们发现这个卡槽两个卡都没了,就得把这个卡槽关闭了。 + // If we find that the two cards of this card groove are gone, we have to close this card slot. if (slotConfig.group[slot].tag_hf == TAG_TYPE_UNKNOWN && slotConfig.group[slot].tag_lf == TAG_TYPE_UNKNOWN) { slotConfig.group[slot].enable = false; } } /** - * 将某个卡槽的数据设置为出厂的预置数据 + * Set the data of a card slot to the preset data from the factory */ bool tag_emulation_factory_data(uint8_t slot, tag_specific_type_t tag_type) { tag_datas_factory_t factory = get_data_factory_from_tag_type(tag_type); if (factory != NULL) { - // 执行工厂格式化数据的过程! + // The process of implementing the data formatting data! if (factory(slot, tag_type)) { - // 如果当前设置的初始数据卡槽号是当前激活的卡槽,那么我们需要更新到内存中 + // If the current data card slot number currently set is the current activated card slot, then we need to update to the memory if (tag_emulation_get_slot() == slot) { load_data_by_tag_type(slot, tag_type); } @@ -350,8 +348,8 @@ bool tag_emulation_factory_data(uint8_t slot, tag_specific_type_t tag_type) { } /** - * 切换场感应监听状态 - * @param enable: 是否使能场感应 + * Switch field induction monitoring status + * @param enable: Whether to make the field induction */ static void tag_emulation_sense_switch_all(bool enable) { uint8_t slot = tag_emulation_get_slot(); @@ -369,27 +367,27 @@ static void tag_emulation_sense_switch_all(bool enable) { } /** - * 切换场感应监听状态 - * @param type: 场感应类型 - * @param enable: 是否使能该类型的场感应 + * Switch field induction monitoring status + * @param type: Field sensor type + * @param enable: Whether to enable this type of field induction */ void tag_emulation_sense_switch(tag_sense_type_t type, bool enable) { - // 检查参数,不允许切换非正常场 + // Check the parameters, not allowed to switch non -normal field if (type == TAG_SENSE_NO) APP_ERROR_CHECK(NRF_ERROR_INVALID_PARAM); - // 切换高频 + // Switch high frequency if (type == TAG_SENSE_HF) nfc_tag_14a_sense_switch(enable); - // 切换低频 + // Switch low frequency if (type == TAG_SENSE_LF) lf_tag_125khz_sense_switch(enable); } /** - * 加载模拟卡配置数据,注意,加载仅仅是卡槽配置 + * Load the simulatory card configuration data, note that loading is just a card slot configuration */ void tag_emulation_load_config(void) { - // 读取卡槽配置数据 + // Read the card slot configuration data bool ret = fds_read_sync(FDS_EMULATION_CONFIG_FILE_ID, FDS_EMULATION_CONFIG_RECORD_KEY, sizeof(slotConfig), (uint8_t *)&slotConfig); if (ret) { - // 读取完成后,我们先保存一份当前配置的BCC,后面保存的时候可以作为变动对比的参考 + // After the reading is completed, we will save a BCC of the current configuration. When it is stored later, it can be used as a reference for the contrast between changes. calc_14a_crc_lut((uint8_t *)&slotConfig, sizeof(slotConfig), (uint8_t *)&m_slot_config_crc); NRF_LOG_INFO("Load tag slot config done."); } else { @@ -398,13 +396,13 @@ void tag_emulation_load_config(void) { } /** - * 保存模拟卡配置数据 + *Save the simulatory card configuration data */ void tag_emulation_save_config(void) { - // 我们正在保存卡槽配置,需要先计算当前的卡槽配置的crc码,用于下面的数据是否更新的判断 + // We are configured the card slot configuration, and we need to calculate the current card slot configuration CRC code to judge whether the data below is updated uint16_t new_calc_crc; calc_14a_crc_lut((uint8_t *)&slotConfig, sizeof(slotConfig), (uint8_t *)&new_calc_crc); - if (new_calc_crc != m_slot_config_crc) { // 在保存之前,先确保卡槽配置有变动了 + if (new_calc_crc != m_slot_config_crc) { // Before saving, make sure that the card slot configuration has changed NRF_LOG_INFO("Save tag slot config start."); bool ret = fds_write_sync(FDS_EMULATION_CONFIG_FILE_ID, FDS_EMULATION_CONFIG_RECORD_KEY, sizeof(slotConfig) / 4, (uint8_t *)&slotConfig); if (ret) { @@ -418,15 +416,15 @@ void tag_emulation_save_config(void) { } /** - * 启动标签模拟 + * Start label simulation */ void tag_emulation_sense_run(void) { tag_emulation_sense_switch_all(true); } /** - * 停止标签模拟,注意,此函数会绝对屏蔽NFC相关的事件,包括唤醒MCU - * 如果需要休眠MCU后依旧能通过NFC唤醒,请勿调用此函数 + * Stop the label simulation. Note that this function will absolutely block NFC -related events, including awakening MCU + * If you still need to be awakened by NFC after the MCU is required, please do not call this function */ void tag_emulation_sense_end(void) { TAG_FIELD_LED_OFF(); @@ -434,106 +432,106 @@ void tag_emulation_sense_end(void) { } /** - * 初始化标签模拟 + *Initialized label simulation */ void tag_emulation_init(void) { - tag_emulation_load_config(); // 加载模拟卡的卡槽的配置 - tag_emulation_load_data(); // 加载模拟卡的数据 + tag_emulation_load_config(); // Configuration of loading the card slot of the simulation card + tag_emulation_load_data(); // Load the data of the simulatory card } /** - * 保存标签的数据(从RAM中写入到flash) + *Save the label data (written from RAM to Flash) */ void tag_emulation_save(void) { - tag_emulation_save_config(); // 保存卡槽配置 - tag_emulation_save_data(); // 保存卡槽数据 + tag_emulation_save_config(); // Save the card slot configuration + tag_emulation_save_data(); // Save card slot data } /** - * 获取当前激活的卡槽索引 + * Get the currently activated card slot index */ uint8_t tag_emulation_get_slot(void) { return slotConfig.config.activated; } /** - * 设置当前激活的卡槽索引 + * Set the currently activated card slot index */ void tag_emulation_set_slot(uint8_t index) { - slotConfig.config.activated = index; // 重设到新切换的卡槽上 + slotConfig.config.activated = index; // Re -set to the new switched card slot rgb_marquee_reset(); // force animation color refresh according to new slot } /** - * 切换到指定索引的卡槽上,此函数将自动完成数据加载 + * Switch to the card slot of the specified index, this function will automatically complete the data loading */ void tag_emulation_change_slot(uint8_t index, bool sense_disable) { if (sense_disable) { - // 关闭模拟卡,避免切换卡槽的时候触发模拟 + // Turn off the analog card to avoid triggering the simulation when switching the card slot tag_emulation_sense_end(); } - tag_emulation_save_data(); // 保存当前卡片的数据,如果有变动的情况下 - g_is_tag_emulating = false; // 重设标志位 - tag_emulation_set_slot(index); // 更新激活的卡槽的索引 - tag_emulation_load_data(); // 然后重新加载卡槽的数据 + tag_emulation_save_data(); // Save the data of the current card, if there is a change, if there is a change + g_is_tag_emulating = false; // Reset the logo position + tag_emulation_set_slot(index); // Update the index of the activated card slot + tag_emulation_load_data(); // Then reload the data of the card slot if (sense_disable) { - // 根据新的卡槽的配置,我们更新场的监听状态 + // According to the configuration of the new card slot, the monitoring status of our update tag_emulation_sense_run(); } } /** - * 判断指定卡槽是否启用了 + * Determine whether the specified card slot is enabled */ bool tag_emulation_slot_is_enable(uint8_t slot) { - // 直接返回对应卡槽的使能状态 + //Return to the capacity of the corresponding card slot directly return slotConfig.group[slot].enable; } /** - * 设置指定卡槽是否启用 + * Set whether the specified card slot is enabled */ void tag_emulation_slot_set_enable(uint8_t slot, bool enable) { - // 直接设置对应卡槽的使能状态 + //Set the capacity of the corresponding card slot directly slotConfig.group[slot].enable = enable; } /** - * 寻找下一个有效使能的卡槽 + *Find the next valid card slot */ uint8_t tag_emulation_slot_find_next(uint8_t slot_now) { uint8_t start_slot = (slot_now + 1 >= TAG_MAX_SLOT_NUM) ? 0 : slot_now + 1; for (uint8_t i = start_slot; i < sizeof(slotConfig.group);) { - if (i == slot_now) return slot_now; // 一次轮回之后没有发现其他被激活的卡槽 - if (slotConfig.group[i].enable) return i; // 查看当前遍历的卡槽是否使能,使能则认定当前卡槽为有效使能的卡槽 - if (i + 1 >= TAG_MAX_SLOT_NUM) { // 继续下一个轮回 + if (i == slot_now) return slot_now; // No other activated card slots were found after a reincarnation + if (slotConfig.group[i].enable) return i; // Check whether the card slot that is currently traversed is enabled, so that the capacity determines that the current card slot is the card slot that can effectively enable capacity + if (i + 1 >= TAG_MAX_SLOT_NUM) { // Continue the next cycle i = 0; } else { i += 1; } } - return slot_now; // 无法搜索到的情况下默认返回传入的指定的返回值 + return slot_now; // If you cannot find it, the specified return value of the pass is returned by default } /** - * 寻找上一个有效使能的卡槽 + * Find the previous valid card slot */ uint8_t tag_emulation_slot_find_prev(uint8_t slot_now) { uint8_t start_slot = (slot_now - 1 < 0) ? (TAG_MAX_SLOT_NUM - 1) : slot_now - 1; for (uint8_t i = start_slot; i < sizeof(slotConfig.group);) { - if (i == slot_now) return slot_now; // 一次轮回之后没有发现其他被激活的卡槽 - if (slotConfig.group[i].enable) return i; // 查看当前遍历的卡槽是否使能,使能则认定当前卡槽为有效使能的卡槽 - if (i - 1 < 0) { // 继续下一个轮回 + if (i == slot_now) return slot_now; //No other activated card slots were found after a reincarnation + if (slotConfig.group[i].enable) return i; // Check whether the card slot that is currently traversed is enabled, so that the capacity determines that the current card slot is the card slot that can effectively enable capacity + if (i - 1 < 0) { // Continue the next cycle i = (TAG_MAX_SLOT_NUM - 1); } else { i -= 1; } } - return slot_now; // 无法搜索到的情况下默认返回传入的指定的返回值 + return slot_now; // If you cannot find it, the specified return value of the pass is returned by default } /** - * 将指定的卡槽的卡槽指定的场类型的卡设置为指定的类型 + *Set the card specified by the specified card slot card slot card type card to the specified type */ void tag_emulation_change_type(uint8_t slot, tag_specific_type_t tag_type) { tag_sense_type_t sense_type = get_sense_type_from_tag_type(tag_type); @@ -548,10 +546,10 @@ void tag_emulation_change_type(uint8_t slot, tag_specific_type_t tag_type) { break; } default: - break; // 永远不能发生 + break; //Never happen } NRF_LOG_INFO("tag type = %d", tag_type); - // 更新完成之后,我们需要通知更新内存中的相关数据 + //After the update is completed, we need to notify the relevant data in the update of the memory if (sense_type != TAG_SENSE_NO) { load_data_by_tag_type(slot, tag_type); NRF_LOG_INFO("reload data success."); @@ -559,19 +557,19 @@ void tag_emulation_change_type(uint8_t slot, tag_specific_type_t tag_type) { } /** - * @brief 模拟卡的工厂初始化函数 - * 可用于初始化默认出厂的一些数据 + * @briefThe factory initialization function of the simulation card + * Some data that can be used to initialize the default factory factory */ void tag_emulation_factory_init(void) { fds_slot_record_map_t map_info; if (slotConfig.group[0].enable && slotConfig.group[0].tag_hf != TAG_TYPE_UNKNOWN && slotConfig.group[0].tag_lf != TAG_TYPE_UNKNOWN) { - // 在卡槽一初始化一张双频卡,如果其不存在历史记录,默认其是全新出厂状态。 + // Initialized a dual -frequency card in the card slot, if there is no historical record, it is a new state of factory. get_fds_map_by_slot_sense_type_for_dump(0, TAG_SENSE_HF, &map_info); bool is_slot1_hf_data_exists = fds_is_exists(map_info.id, map_info.key); get_fds_map_by_slot_sense_type_for_dump(0, TAG_SENSE_LF, &map_info); bool is_slot1_lf_data_exists = fds_is_exists(map_info.id, map_info.key); - // 此处判断卡槽1的高频卡和低频卡都不存在 + // Here are no high -frequency cards and low -frequency cards of card slot 1 here. if (!is_slot1_hf_data_exists && !is_slot1_lf_data_exists) { tag_emulation_factory_data(0, slotConfig.group[0].tag_hf); tag_emulation_factory_data(0, slotConfig.group[0].tag_lf); @@ -579,7 +577,7 @@ void tag_emulation_factory_init(void) { } if (slotConfig.group[1].enable && slotConfig.group[1].tag_hf != TAG_TYPE_UNKNOWN) { - // 在卡槽2初始化一张高频m1卡,如果其不存在的话。 + // Initialize a high -frequency M1 card in the card slot 2, if it does not exist. get_fds_map_by_slot_sense_type_for_dump(1, TAG_SENSE_HF, &map_info); bool is_slot2_hf_data_exists = fds_is_exists(map_info.id, map_info.key); if (!is_slot2_hf_data_exists) { @@ -588,7 +586,7 @@ void tag_emulation_factory_init(void) { } if (slotConfig.group[2].enable && slotConfig.group[2].tag_lf != TAG_TYPE_UNKNOWN) { - // 在卡槽3初始化一张低频em410x卡,如果其不存在的话。 + // Initialize a low -frequency EM410X card at Card Glip 3, if it does not exist. get_fds_map_by_slot_sense_type_for_dump(2, TAG_SENSE_LF, &map_info); bool is_slot3_lf_data_exists = fds_is_exists(map_info.id, map_info.key); if (!is_slot3_lf_data_exists) { diff --git a/firmware/application/src/rfid/nfctag/tag_emulation.h b/firmware/application/src/rfid/nfctag/tag_emulation.h index c451f5c..d583cd7 100644 --- a/firmware/application/src/rfid/nfctag/tag_emulation.h +++ b/firmware/application/src/rfid/nfctag/tag_emulation.h @@ -8,28 +8,28 @@ #include "utils.h" #include "tag_base_type.h" -// 最多八张卡槽 +//Up to eight card slots #define TAG_MAX_SLOT_NUM 8 extern bool g_is_tag_emulating; -// 标签的数据缓冲区 +// Label data buffer typedef struct { uint16_t length; uint8_t *buffer; uint16_t *crc; } tag_data_buffer_t; -// 场感应使能与闭能切换函数 +//Farming impact enable and closed energy switching function typedef void (*tag_sense_switch_t)(bool enable); -// flash数据加载到RAM后通知给注册者 +// Flash data is notified to the registrar after loading to RAM typedef int (*tag_datas_loadcb_t)(tag_specific_type_t type, tag_data_buffer_t *buffer); -// 数据要保存到flash之前通知给注册者 +// The data should be saved to the registered person before Flash typedef int (*tag_datas_savecb_t)(tag_specific_type_t type, tag_data_buffer_t *buffer); -// 数据的工厂初始化函数 +// Data factory initialization function typedef bool (*tag_datas_factory_t)(uint8_t slot, tag_specific_type_t type); -// 标签的数据加载与保存事件的回调函数映射表 +// The data of the label data loading and the recovery function of the preservation event mapping table typedef struct { tag_sense_type_t sense_type; tag_specific_type_t tag_type; @@ -40,70 +40,70 @@ typedef struct { } tag_base_handler_map_t; /** - * 卡槽内模拟的卡的类型之类的参数的存放配置 - * 此配置可以被持久化保存到Flash - * 4字节一个Word,谨记进行整字对齐 + * The storage configuration of parameters such as the type of card simulated in the card slot + * This configuration can be preserved by persistently to Flash + * 4 bytes a word, keep in mind the entire word alignment */ typedef struct ALIGN_U32 { - // 基础配置 + //Basic configuration struct { - uint8_t activated; // 当前激活了哪个卡槽(哪个卡槽被使用了) - uint8_t reserved1; // 保留 - uint8_t reserved2; // 保留 - uint8_t reserved3; // 保留 + uint8_t activated; //Which card slot is currently activated (which card slot is used) + uint8_t reserved1; // reserve + uint8_t reserved2; //reserve + uint8_t reserved3; // reserve } config; - // 每个卡槽自身的配置 + // The configuration of each card slot itself struct { - // 基础配置,占用两个字节 - uint8_t enable: 1; // 是否使能该卡槽 - uint8_t reserved1: 7; // 保留 - uint8_t reserved2; // 保留 - // 具体的正在模拟卡的类型 + //Basic configuration, occupying two bytes + uint8_t enable: 1; // Whether to enable the card + uint8_t reserved1: 7; // reserve + uint8_t reserved2; //reserve + // Specific type of simulation card tag_specific_type_t tag_hf; tag_specific_type_t tag_lf; } group[TAG_MAX_SLOT_NUM]; } tag_slot_config_t; -// 最基本的模拟卡初始化程序 +// The most basic simulation card initialization program void tag_emulation_init(void); -// 标签的一些存放在RAM中的数据可以通过此接口持久化保存到flash +//Some of the data stored in RAM can be saved to Flash through this interface void tag_emulation_save(void); -// 模拟卡的启动与结束 +// Starting and ending of the simulation card void tag_emulation_sense_run(void); void tag_emulation_sense_end(void); -// 场感应使能状态切换封装函数 +// Farming response enable state switching package function void tag_emulation_sense_switch(tag_sense_type_t type, bool enable); -// 删除卡槽中指定的场类型的卡片 +// Delete the type of card specified in the card slot void tag_emulation_delete_data(uint8_t slot, tag_sense_type_t sense_type); -// 将指定卡槽初始化为指定类型的卡片的出厂数据 +// Initial data of the factory data of the specified card slot into the factory of the specified type of card bool tag_emulation_factory_data(uint8_t slot, tag_specific_type_t tag_type); -// 更改正在模拟的卡片的类型 +// Change the type of the card that is being simulated void tag_emulation_change_type(uint8_t slot, tag_specific_type_t tag_type); -// 从内存中加载数据到模拟卡缓冲区 +//Load the data from the memory to the simulation card buffer bool tag_emulation_load_by_buffer(tag_specific_type_t tag_type, bool update_crc); tag_sense_type_t get_sense_type_from_tag_type(tag_specific_type_t type); tag_data_buffer_t *get_buffer_by_tag_type(tag_specific_type_t type); -// 设置当前使用的卡槽 +// Set the card slot currently used void tag_emulation_set_slot(uint8_t index); -// 获取当前使用的卡槽 +// Get the card slot currently used uint8_t tag_emulation_get_slot(void); -// 切换卡槽,根据传入参数控制是否在切换期间关闭场监听 +// Switch the card slot to control whether the passing parameter control is closed during the switching period to listen to void tag_emulation_change_slot(uint8_t index, bool sense_disable); -// 获取卡槽使能状态 +// Get the card slot to enable the state bool tag_emulation_slot_is_enable(uint8_t slot); -// 设置卡槽使能 +// Set the card slot to enable void tag_emulation_slot_set_enable(uint8_t slot, bool enable); -// 获取对应卡槽的模拟卡类型 +// Get the simulation card type of the corresponding card slot void tag_emulation_get_specific_type_by_slot(uint8_t slot, tag_specific_type_t tag_type[2]); -// 初始化某些出厂数据 +// Initialize some factory data void tag_emulation_factory_init(void); -// 在某个方向上查询任何一个使能的卡槽 +//In the direction, query any card slot that enable uint8_t tag_emulation_slot_find_next(uint8_t slot_now); uint8_t tag_emulation_slot_find_prev(uint8_t slot_now); diff --git a/firmware/application/src/rfid/nfctag/tag_persistence.h b/firmware/application/src/rfid/nfctag/tag_persistence.h index 7d6a9cb..5ad74f6 100644 --- a/firmware/application/src/rfid/nfctag/tag_persistence.h +++ b/firmware/application/src/rfid/nfctag/tag_persistence.h @@ -11,12 +11,11 @@ typedef struct { } fds_slot_record_map_t; /** - * 根据指定的卡槽和卡片场类型,获得其对应的卡片数据的FDS信息的映射对象 + * According to the specified card slot and card field type, obtain the mapping object of the FDS information of the corresponding card data */ void get_fds_map_by_slot_sense_type_for_dump(uint8_t slot, tag_sense_type_t sense_type, fds_slot_record_map_t *map); - /** - * 根据指定的卡槽和卡片场类型,获得其对应的卡片数据的昵称的FDS信息的映射对象 + *According to the specified card slot and card field type, obtain the mapping object of the FDS information of the nickname of the corresponding card data */ void get_fds_map_by_slot_sense_type_for_nick(uint8_t slot, tag_sense_type_t sense_type, fds_slot_record_map_t *map); diff --git a/firmware/application/src/rfid/reader/hf/mf1_toolbox.c b/firmware/application/src/rfid/reader/hf/mf1_toolbox.c index 25cbb85..d5a05b8 100644 --- a/firmware/application/src/rfid/reader/hf/mf1_toolbox.c +++ b/firmware/application/src/rfid/reader/hf/mf1_toolbox.c @@ -11,20 +11,20 @@ #include "nrf_log_default_backends.h" -// 天线重置的默认延时 +// The default delay of the antenna reset static uint32_t g_ant_reset_delay = 8; -// 全局操作使用的标签的信息 +// Label information used for global operations static picc_14a_tag_t m_tag_info; static picc_14a_tag_t *p_tag_info = &m_tag_info; /** -* @brief : 测算随机数的距离值,根据实时算出来的多项式表 -* 官方注释:x,y valid tag nonces, then prng_successor(x, nonce_distance(x, y)) = y -* @param :msb : 随机数高位,传出结果由此指针完成 -* @param :lsb : 随机数低位,传出结果由此指针完成 -* @retval : 无 +* @brief : Calculate the distance value of the random number, and calculate the multi -type table based on real -time +* Official comment:x,y valid tag nonces, then prng_successor(x, nonce_distance(x, y)) = y +* @param :msb :The random number is high, the result is completed, the pointer is completed +* @param :lsb :The random number is low, and the result is completed +* @retval : none * */ void nonce_distance_notable(uint32_t *msb, uint32_t *lsb) { @@ -32,9 +32,9 @@ void nonce_distance_notable(uint32_t *msb, uint32_t *lsb) { uint8_t calc_ok = 0; for (uint16_t i = 1; i; ++i) { - // 计算坐标,以获得多项式的步进运算结果 + // Calculate coordinates to obtain polynomial step operation results pos = (x & 0xff) << 8 | x >> 8; - // 判断坐标,我们取出对应的值并且设置以取值的标志位 + // To judge the coordinates, we take out the corresponding value and set the logo bit with the value of the value if ((pos == *msb) & !(calc_ok >> 0 & 0x01)) { *msb = i; calc_ok |= 0x01; @@ -43,8 +43,8 @@ void nonce_distance_notable(uint32_t *msb, uint32_t *lsb) { *lsb = i; calc_ok |= 0x02; } - // 最终两个值的测算都完成的话,我们直接结束运算, - // 以减少不必要的后续CPU性能损耗 + // If the calculation of both values is completed, we will end the operation directly, + // to reduce unnecessary subsequent CPU performance loss if (calc_ok == 0x03) { return; } @@ -53,25 +53,25 @@ void nonce_distance_notable(uint32_t *msb, uint32_t *lsb) { } /** -* @brief : 测算PRNG的步进规律,以验证该随机数是否是可预测的 -* 假若该可预测,那么就可能支持 Darkside攻击 -* 并且可能支持 Nested 攻击 -* @param :nonce : 测量的随机数 +* @brief : Calculate the step of PRNG to verify whether the random number is predictable +* If it is predictable, then DarkSide attack may be supported +* And may support Nested attack +* @param :nonce : Measured random number * @retval : true = weak prng * false = hardend prng * */ bool validate_prng_nonce_notable(uint32_t nonce) { - // 给出初始的坐标值 + // Give the initial coordinate value uint32_t msb = nonce >> 16; uint32_t lsb = nonce & 0xffff; - // 传入坐标进行直接运算,并且传出也由传入参数间接传出 + //The coordinates are passed in direct operation, and the rumors are also indirectly spread by the passing parameters. nonce_distance_notable(&msb, &lsb); return ((65535 - msb + lsb) % 65535) == 16; } /** -* @brief : 重置场,在一定的延时之后重启场 +* @brief : Re -set the field, restart the field after a certain delay * */ static inline void ResetRadioFieldWithDelay(void) { @@ -81,18 +81,18 @@ static inline void ResetRadioFieldWithDelay(void) { } /** -* @brief : 发送mifare指令 -* @param :pcs : crypto1句柄 -* @param :crypted : 这批数据是否需要被 crypto1 加密 -* @param :cmd : 将被发送的指令,例如 0x60 表示验证 A 秘钥 -* @param :data : 将被发送的数据,例如 0x03 表示验证 1 扇区 -* @param :answer : 卡片的应答数据存放的数组 -* @param :answer_parity : 卡片的应答数据的奇偶校验位存放的数组 -* @retval : 卡片应答的数据的长度,这个长度是 bit 长度,不是 byte长度 +* @brief : Send the MiFare instruction +* @param :pcs : crypto1st handle +* @param :crypted : Whether these data need to be encrypted by Crypto1 +* @param :cmd : The instructions that will be sent, for example, 0x60 indicates verification A key +* @param :data : The data that will be sent, such as 0x03 indicates verification 1 sector +* @param :answer : Card response data stored array +* @param :answer_parity : Card response data for the stagnant school inspection storage +* @retval : The length of the card response data, this length is the length of the bit, not the length of Byte * */ uint8_t sendcmd(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t *status, uint8_t *answer, uint8_t *answer_parity, uint16_t answer_max_bit) { - // 这里我们直接设置为静态 + // Here we set directly to static static uint8_t pos; static uint16_t len; static uint8_t dcmd[4]; @@ -134,7 +134,7 @@ uint8_t sendcmd(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t ); } - // 通信有问题,不继续接下来的任务 + // There is a problem with communication, do not continue the next task if (*status != HF_TAG_OK) { return len; } @@ -157,22 +157,22 @@ uint8_t sendcmd(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t } /** -* @brief : 高级验证过程 -* @param :pcs : crypto1句柄 -* @param :uid : 卡片的UID号 -* @param :blockNo : 验证的块号 -* @param :keyType : 秘钥类型, 0x60(A秘钥) 或者 0x61(B秘钥) -* @param :ui64Key : 卡片的秘钥的U64值 -* @param :isNested : 当前是否是嵌套验证 -* @param :ntptr : 存放NT的地址,如果传入 NULL ,则不保存NT -* @retval : 验证成功返回 0 ,验证不成功返回非 0 值 +* @brief : Advanced verification process +* @param :pcs : crypto1st handle +* @param :uid : Card's UID number +* @param :blockNo : Verified block number +* @param :keyType : Type type, 0x60 (A key) or 0x61 (B secret) +* @param :ui64Key : The U64 value of the secret of the card +* @param :isNested : Is it currently nested verification? +* @param :ntptr : Store the address of NT, if it is passed into NULL, it will not be saved +* @retval : Verification returns 0, the verification is unsuccessful to return the non -0 value * */ int authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr) { static uint8_t status; // tag resonse status static uint16_t len; // tag resonse length static uint32_t pos, nt, ntpp; // Supplied tag nonce - static const uint8_t nr[] = { 0x12, 0x34, 0x56, 0x78 }; // 使用固定的卡片随机数 NR,也就是Nonce Reader。 + static const uint8_t nr[] = { 0x12, 0x34, 0x56, 0x78 }; // Use a fixed card to random NR, which is Nonce Reader. uint8_t par[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t mf_nr_ar[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t answer[] = { 0x00, 0x00, 0x00, 0x00 }; @@ -223,38 +223,38 @@ int authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyT par[pos] = filter(pcs->odd) ^ oddparity8(nt); } - // 我们不需要status,因为正常的通信会返回 32bit 的数据 + // We don't need Status, because normal communication will return 32bit data pcd_14a_reader_bits_transfer(mf_nr_ar, 64, par, answer, parity, &len, U8ARR_BIT_LEN(answer)); if (len == 32) { ntpp = prng_successor(nt, 32) ^ crypto1_word(pcs, 0, 0); if (ntpp == BYTES4_TO_U32(answer)) { - // 验证成功! + // Successful verification! return HF_TAG_OK; } else { - // 失败 + // fail return MF_ERRAUTH; } } - // 失败! + // fail! return MF_ERRAUTH; } /** -* @brief : 选定出现几率最大的一个NT -* @param :tag : 标签信息结构体,快速选卡需要使用此结构体 -* @param :block : 将被攻击的密钥块 -* @param :keytype : 将被攻击的密钥类型 -* @param :nt : 最终选定的NT,这个NT是出现次数最多,且排名最靠前的 -* @retval 最终确定下来的NT值, 如果无法同步卡片时钟,返回对应的异常码,否则返回 HF_TAG_OK +* @brief : Selected the largest probability of NT +* @param :tag : Label information structure, fast selection card needs to use this structure +* @param :block : The key cubes that will be attacked +* @param :keytype : The type of key to be attacked +* @param :nt : The final selected NT, this NT is the most occurred, and the ranking is the highest. +* @retval The final NT value determined, if the card clock cannot be synchronized, returns the corresponding abnormal code, otherwise return hf_tag_ok * ------------------- -* 为何无法固定随机数? -* 0、卡片天线位置有自由或者非自由移动的偏差导致通信不稳定。 -* 1、所处电磁环境非常复杂,导致卡片上电充能到完成通信的过程无法稳定重放 -* 2、卡片针对重放攻击做了漏洞修复,卡片不再被重放攻击套取相同应答 -* 3、此代码所运行的环境非裸机或中断太频繁,或其他任务调度太频繁, -* 导致 CPU 无法在稳定的相同的时间内完成重放攻击。 -* 此种情况基本无解,建议将此段代码之外的非关键中断以及任务调度关闭 +* Why can't you fix the random number? +* 0. The deviation of free or non -free movement in the card antenna leads to the unstable communication. +* 1. The electromagnetic environment where it is located is very complicated, resulting in the process of getting the power charging of the card to complete the communication. +* 2. The card is repaired for the loopholes for the heavy attack attack, and the card is no longer a replaceable attack set to take the same response +* 3. The environment run by this code is too frequent or interrupt, or other task scheduling is too frequent. +* As a result, the CPU cannot complete the replay attack within the same time. +* There is basically no solution in this situation. It is recommended to close the non -critical interruption and task scheduling outside this code */ uint8_t Darkside_Select_Nonces(picc_14a_tag_t *tag, uint8_t block, uint8_t keytype, uint32_t *nt) { #define NT_COUNT 15 @@ -267,30 +267,30 @@ uint8_t Darkside_Select_Nonces(picc_14a_tag_t *tag, uint8_t block, uint8_t keyty crc_14a_append(tag_auth, 2); - // 进行随机数采集 + //Random number collection for (i = 0; i < NT_COUNT; i++) { - // 在进行天线重置时,我们必须要确保 - // 1、天线断电足够久,以此确保卡片完全断电,否则无法重置卡片的伪随机数生成器 - // 2、断电时间适中,不要太长,会影响效率,也不要太短,会无法无法重置卡片 + //When the antenna is reset, we must make sure + // 1. The antenna is powered off for a long time to ensure that the card is completely powered off, otherwise the pseudo -random number generator of the card cannot be reset + // 2. Moderate power -off time, don't be too long, it will affect efficiency, and don't be too short. ResetRadioFieldWithDelay(); - // 完全断电后,我们进行快速选卡,尽可能的将验证耗时压缩 + // After the power is completely disconnected, we will select the card quickly and compress the verification time as much as possible. if (pcd_14a_reader_scan_auto(tag) != HF_TAG_OK) { NRF_LOG_INFO("Tag can't select!\n"); return HF_TAG_NO; } status = pcd_14a_reader_bytes_transfer(PCD_TRANSCEIVE, tag_auth, 4, tag_resp, &len, U8ARR_BIT_LEN(tag_resp)); - // 在寻找到卡片后,开始采集随机数 + // After finding the card, start collecting random numbers if (status != HF_TAG_OK || len != 32) { NRF_LOG_INFO("Get nt failed.\n"); return HF_ERRSTAT; } - // 转换为u32的类型,并且进行缓存 + // Converted to the type of U32 and cache nt_list[i] = bytes_to_num(tag_resp, 4); - // 转换应答的字节数组为10进制的NT + // The byte array of the conversion response is 10 in NT // NRF_LOG_INFO("Get nt: %"PRIu32"\r\n", nt_list[i]); } - // 对随机数进行取重 + // Take the random number for (i = 0; i < NT_COUNT; i++) { uint32_t nt_a = nt_list[i]; for (m = i + 1; m < NT_COUNT; m++) { @@ -301,7 +301,7 @@ uint8_t Darkside_Select_Nonces(picc_14a_tag_t *tag, uint8_t block, uint8_t keyty } } - // 对取重后的最大次数值进行取值 + // Take the maximum number of times after weighting max = nt_count[0]; m = 0; for (i = 1; i < NT_COUNT; i++) { @@ -311,83 +311,83 @@ uint8_t Darkside_Select_Nonces(picc_14a_tag_t *tag, uint8_t block, uint8_t keyty } } - // 最终,我们判定一下max次数是否大于0, - // 如果不大于0,说明无法同步时钟。 + //In the end, let's determine whether the number of MAX times is greater than 0, + // If it is not greater than 0, it means that the clock cannot be synchronized. if (max == 0) { NRF_LOG_INFO("Can't sync nt.\n"); return DARKSIDE_CANT_FIXED_NT; } - // NT 固定成功,我们取出出现次数最高的那个 + // NT is fixed successfully, the one with the highest number of times we take out // NRF_LOG_INFO("Sync nt: %"PRIu32", max = %d\n", nt_list[m], max); - if (nt) *nt = nt_list[m]; // 只有调用者需要获得NT时才传出 + if (nt) *nt = nt_list[m]; // Only when the caller needs to get NT return HF_TAG_OK; } /** -* @brief : 使用Darkside漏洞破解一个未知的密钥 -* @param :dc : darkside破解的核心应答 -* @param :dp : darkside破解的核心参数 -* @retval : 收集成功返回 HF_TAG_OK ,验证不成功返回对应的异常码 +* @brief : Using darkside vulnerability to crack an unknown key +* @param :dc : DarkSide's core response +* @param :dp : The core parameter of darkside cracking +* @retval : Collect successfully returning hf_tag_ok, verify that the corresponding abnormal code is not successfully returned * */ uint8_t Darkside_Recover_Key(uint8_t targetBlk, uint8_t targetTyp, uint8_t firstRecover, uint8_t ntSyncMax, DarksideCore *dc) { - // 被固定使用的卡片信息 + // Card information for fixed use static uint32_t uid_ori = 0; uint32_t uid_cur = 0; - // 被固定随机数和每次获得的随机数 + // Fixed random number and random number of each time static uint32_t nt_ori = 0; uint32_t nt_cur = 0; - // mr_nr 生成时每次的变化量 + // Mr_nr changes every time static uint8_t par_low = 0; static uint8_t mf_nr_ar3 = 0; - // 卡片交互通信 哇塞,好整齐的变量定义 + // Card interaction communication Wow, so neat variable definition uint8_t tag_auth[4] = { targetTyp, targetBlk, 0x00, 0x00 }; uint8_t par_list[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t ks_list[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t mf_nr_ar[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - // 真正通信的时候,全程8个byte的长度足够容纳所有的数据 + // During the real communication, the length of 8 byte is enough to accommodate all data uint8_t par_byte[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t dat_recv[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - // 控制变量 - uint8_t resync_count = 0x00; // 这个变量负责统计当前同步时钟以同步NT的尝试次数 - uint8_t received_nack = 0x00; // 这个变量负责标志当前是否接收到了NACK的回复 - uint8_t par = 0x00; // 这个变量负责奇偶校验位的递增,以碰撞卡片的回复 - uint8_t status = 0x00; // 这个变量负责保存卡片通信的状态 - uint16_t len = 0x00; // 这个变量负责保存通信过程中卡片的数据应答长度 - uint8_t nt_diff = 0x00; // 这个变量很关键哦,别不初始化,因为下面直接使用了 + // Control variable + uint8_t resync_count = 0x00; // This variable is responsible for counting the current sync clock with the number of attempts of synchronous NT + uint8_t received_nack = 0x00; // This variable is responsible for whether it receives the reply from Nack + uint8_t par = 0x00; // This variable is responsible for increasing the puppet school inspection, and the reply of the collision card + uint8_t status = 0x00; // This variable is responsible for saving card communication status + uint16_t len = 0x00; // This variable is responsible for saving the data of the card in the communication process to respond to the length of the card + uint8_t nt_diff = 0x00; // This variable is critical, don't initialize it, because the following is used directly - // 我们需要先确认使用某一张卡 + // We need to confirm the use of a certain card first if (pcd_14a_reader_scan_auto(p_tag_info) == HF_TAG_OK) { uid_cur = get_u32_tag_uid(p_tag_info); } else { return HF_TAG_NO; } - // 验证指令需要追加CRC16 + // Verification instructions need to add CRC16 crc_14a_append(tag_auth, 2); - // 初始化静态变量如果是第一次发起攻击 + // Initialize the static variable if it is the first attack if (firstRecover) { - // 重置关键变量 + // Reset key variable nt_ori = 0; mf_nr_ar3 = 0; par_low = 0; - // 第一次运行的话,我们需要固定使用一个卡片 + // For the first time, we need to use a card fixed uid_ori = get_u32_tag_uid(p_tag_info); - // 然后还需要固定一个大概率出现的随机数 + // Then you need to fix a random number that may appear status = Darkside_Select_Nonces(p_tag_info, targetBlk, targetTyp, &nt_ori); if (status != HF_TAG_OK) { - // 固定随机数失败,无法进行下一步操作 + //The fixed random number failed, and the next step cannot be performed return status; } } else { @@ -402,17 +402,17 @@ uint8_t Darkside_Recover_Key(uint8_t targetBlk, uint8_t targetTyp, } } - // 在一个大循环里面一直采集不同的nr ar下的nack + // Always collect different NACK under a large cycle do { - // 重置nack的接收标志 + // Reset the receiving sign of NACK received_nack = 0; - // 在进行天线重置时,我们必须要确保 - // 1、天线断电足够久,以此确保卡片完全断电,否则无法重置卡片的伪随机数生成器 - // 2、断电时间适中,不要太长,会影响效率,也不要太短,会无法无法重置卡片 + //When the antenna is reset, we must make sure + // 1. The antenna is powered off for a long time to ensure that the card is completely powered off, otherwise the pseudo -random number generator of the card cannot be reset + // 2. Moderate power -off time, don't be too long, it will affect efficiency, and don't be too short. ResetRadioFieldWithDelay(); - // 完全断电后,我们进行快速选卡,尽可能的将验证耗时压缩 + //After the power is completely disconnected, we will select the card quickly and compress the verification time as much as possible. if (pcd_14a_reader_scan_auto(p_tag_info) != HF_TAG_OK) { NRF_LOG_INFO("Tag can't select!\n"); return HF_TAG_NO; @@ -420,37 +420,37 @@ uint8_t Darkside_Recover_Key(uint8_t targetBlk, uint8_t targetTyp, status = pcd_14a_reader_bytes_transfer(PCD_TRANSCEIVE, tag_auth, 4, dat_recv, &len, U8ARR_BIT_LEN(dat_recv)); - // 在寻找到卡片后,开始采集随机数 + // After finding the card, start collecting random numbers if (status != HF_TAG_OK || len != 32) { NRF_LOG_INFO("Get nt failed.\n"); return HF_ERRSTAT; } - // 转换应答的字节数组为10进制的 NT + //The byte array of the conversion response is 10 in NT nt_cur = bytes_to_num(dat_recv, 4); // NRF_LOG_INFO("Get nt: %"PRIu32"\r\n", nt_cur); - // 判断时钟同步(使NT固定) + //Determine the clock synchronization (fixing NT) if (nt_cur != nt_ori) { - // 随机数不同步,但是我们已经选择过随机数了 - // 并且我们选择的随机数也被成功的重放攻击了 - // 也就说,这种误差,已经没机会修正随机数了 + // The random number is not synchronized, but we have chosen the random number + // And the random number we chose was also successfully attacked + // In other words, this error has no chance to correct the random number if (++resync_count == ntSyncMax) { NRF_LOG_INFO("Can't fix nonce.\r\n"); return DARKSIDE_CANT_FIXED_NT; } - // 时钟不同步的情况下,下面的操作是没意义的 - // 因此直接跳过下面的操作,进入下一轮循环, - // 上帝保佑下一轮循环能同步时钟。。。 + // When the clock is not synchronized, the following operation is meaningless + // So directly skip the following operations, enter the next round of cycle, + // God bless the next cycle to synchronize the clock.EssenceEssence // NRF_LOG_INFO("Sync nt -> nt_fix: %"PRIu32", nt_new: %"PRIu32"\r\n", nt_ori, nt_cur); continue; } - // 本来我们只需要发 par 的,利用其中的每一个Bit当做校验位来的 - // 但是奈何我们实现的发送函数只支持以一个uint8_t,也就是一个字节当做一个bit来用 - // 因此此处我们需要把 PM3 的通信写法换成我们的。 - // 这里反正次数不多,我们直接展开换算的代码 + //Originally, we only need to send PAR, and use every bit of them as a school test. + // But the sending function we implemented only supports one UINT8_T, that is, a byte as a bit + // Therefore, we need to replace the communication writing of PM3 into our. + // There are not many times here anyway, we directly expand the code for conversion par_byte[0] = par >> 0 & 0x1; par_byte[1] = par >> 1 & 0x1; par_byte[2] = par >> 2 & 0x1; @@ -463,7 +463,7 @@ uint8_t Darkside_Recover_Key(uint8_t targetBlk, uint8_t targetTyp, len = 0; pcd_14a_reader_bits_transfer(mf_nr_ar, 64, par_byte, dat_recv, par_byte, &len, U8ARR_BIT_LEN(dat_recv)); - // 重置固定随机数上限计数 + //Reset fixed random number upper limit count resync_count = 0; if (len == 4) { @@ -511,8 +511,8 @@ uint8_t Darkside_Recover_Key(uint8_t targetBlk, uint8_t targetTyp, mf_nr_ar[3] &= 0x1F; - // 没有出现意外情况,本次执行判定为成功! - // 我们需要对结果进行封装返回 + // There is no accident, this execution is judged as success! + // We need to package the result and return get_4byte_tag_uid(p_tag_info, dc->uid); num_to_bytes(nt_cur, 4, dc->nt); @@ -526,11 +526,11 @@ uint8_t Darkside_Recover_Key(uint8_t targetBlk, uint8_t targetTyp, } /** -* @brief : 修改天线重启的中间延时 -* 延时越长,越能重启某些非标卡片, -* 延时越短,越块处理天线重启过程,进而处理后续业务 -* @param :delay_ms : 延时的具体值,单位为毫秒 -* @retval : 无 +* @brief : Modify the middle delay of the antenna restart +* The longer the delay, the more you can restart certain non -standard cards, the more +* The shorter the delay, the more you get the process of processing the antenna restart, and then deal with the follow -up business +* @param :delay_ms : The specific value of the delay, the unit is milliseconds +* @retval : none * */ void Atenna_Switch_Delay(uint32_t delay_ms) { @@ -538,26 +538,26 @@ void Atenna_Switch_Delay(uint32_t delay_ms) { } /** -* @brief : 判断此卡片是否支持Darkside攻击 -* @retval : 如果支持,返回 HF_TAG_OK,如果不支持, -* 返回检测过程中发生异常的结果码: -* 1、DARKSIDE_CANT_FIXED_NT -* 2、DARKSIDE_NACK_NO_SEND -* 3、DARKSIDE_TAG_CHANGED -* 或者其他的卡片相关的通信错误,最常见的是丢失卡片 HF_TAG_NO +* @brief :Determine whether this card supports DARKSIDE attack +* @retval : If support, return hf_tag_ok, if it is not supported, +* Return to the results of abnormal results during the detection process: +* 1. DARKSIDE_CANT_FIXED_NT +* 2. DARKSIDE_NACK_NO_SEND +* 3. DARKSIDE_TAG_CHANGED +* Or other card -related communication errors, the most common is loss card HF_TAG_NO * */ uint8_t Check_Darkside_Support() { - // 实例化参数 + // Instantiated parameter DarksideCore dc; - // 直接判断并且返回结果 + //Determine and return the result directly return Darkside_Recover_Key(0x03, PICC_AUTHENT1A, true, 0x15, &dc); } /** -* @brief : 判断此卡片是否支持M1的验证步骤 -* @retval : 如果支持,将返回HF_TAG_OK, -* 如果不支持,则返回对应的错误码 +* @brief : Determine whether this card supports M1 verification steps +* @retval : If support, it will return hf_tag_ok, +* If it is not supported, returns the corresponding error code * */ uint8_t Check_Tag_Response_NT(picc_14a_tag_t *tag, uint32_t *nt) { @@ -567,16 +567,16 @@ uint8_t Check_Tag_Response_NT(picc_14a_tag_t *tag, uint32_t *nt) { uint8_t dat_recv[4] = { 0x00 }; uint8_t status; - // 重置卡片通信 + // Reset card communication pcd_14a_reader_halt_tag(); - // 我们进行快速选卡,尽可能的将验证耗时压缩 + // We will choose a fast card, and we will be compressed to verify as much as possible if (pcd_14a_reader_scan_auto(tag) != HF_TAG_OK) { NRF_LOG_INFO("Tag can't select\r\n"); return HF_TAG_NO; } - // 发送指令并且获取NT返回 + // Send instructions and get NT return *nt = sendcmd(pcs, AUTH_FIRST, PICC_AUTHENT1A, 0x03, &status, dat_recv, par_recv, U8ARR_BIT_LEN(dat_recv)); if (*nt != 32) { // dbg_block_printf("No 32 data recv on sendcmd: %d\n", *nt); @@ -587,59 +587,58 @@ uint8_t Check_Tag_Response_NT(picc_14a_tag_t *tag, uint32_t *nt) { } /** -* @brief : 判断此卡片是否支持标签MF三次验证协议 -* @retval : 如果支持,返回 HF_TAG_OK,如果不支持, -* 则返回 HF_ERRSTAT -* 或者其他的卡片相关的通信错误,最常见的是 -* 丢失卡片 HF_TAG_NO 和错误的状态 HF_ERRSTAT +* @brief : Determine whether this card supports the label MF three verification protocols +* @retval : If support, return hf_tag_ok, if it is not supported, +* Then return hf_errstat +* Or other card -related communication errors, the most common thing is +* Lost card hf_tag_no and wrong status hf_errstat * */ uint8_t Check_STDMifareNT_Support() { uint32_t nt1 = 0; - // 寻卡,场内搜索 + // Find card, search on the field if (pcd_14a_reader_scan_auto(p_tag_info) != HF_TAG_OK) { return HF_TAG_NO; } - // 获取NT + // Get NT return Check_Tag_Response_NT(p_tag_info, &nt1); } /** -* @brief : 判断此卡片是否支持StaticNested攻击 -* @retval : 如果支持,返回 NESTED_TAG_IS_STATIC,如果不支持, -* 则返回 HF_TAG_OK -* 或者其他的卡片相关的通信错误,最常见的是丢失卡片 HF_TAG_NO +* @brief :Determine whether this card supports StaticNESTED attack +* @retval : If support, return nested_tag_is_static, if it is not supported, if support, return nested_tag_is_static, if it is not supported, if it is not supported, it is not supported, +* If support, return nested_tag_is_static, if not support, * */ uint8_t Check_StaticNested_Support() { uint32_t nt1, nt2; uint8_t status; - // 寻卡,场内搜索 + // Find card, search on the field if (pcd_14a_reader_scan_auto(p_tag_info) != HF_TAG_OK) { return HF_TAG_NO; } - // 第一波获取NT + // Get NT in the first wave status = Check_Tag_Response_NT(p_tag_info, &nt1); if (status != HF_TAG_OK) { return status; } - // 获取完成后谨记重置场 - // 如果不重置场的话,某些卡会在场内维持功能时一直提供一个静态的NT - // 因此此处的重置非常重要。 + // Remember to reset the place after getting completed + // If you do not re -set the field, some cards will always provide a static NT when maintaining the function in the field + // Therefore, resetting here is very important. ResetRadioFieldWithDelay(); - // 第二波获取NT + // Get NT in the second wave status = Check_Tag_Response_NT(p_tag_info, &nt2); if (status != HF_TAG_OK) { return status; } - // 检测随机数是否是静态的 + // Detect whether the random number is static if (nt1 == nt2) { return NESTED_TAG_IS_STATIC; } @@ -648,8 +647,8 @@ uint8_t Check_StaticNested_Support() { } /** -* @brief : 判断此卡片是否支持最普通,最弱,最容易的prng攻击 -* @retval : 判断结果 +* @brief : Determine whether this card supports the most common, weaker, and easiest Prite attack +* @retval : critical result * */ uint8_t Check_WeakNested_Support() { @@ -658,37 +657,37 @@ uint8_t Check_WeakNested_Support() { status = Check_StaticNested_Support(); - // 如果判断的过程中,发现并不能完成staticnested的检测 - // 那就直接返回状态,不需要进行下面的判断逻辑了。 + // If the judgment process is found, it is found that the Staticnested detection cannot be completed + // Then return the state directly, no need to perform the following judgment logic. if (status != HF_TAG_OK) { return status; } - // 非static的卡片,还可以继续往下跑逻辑 + // Non -Static card, you can continue to run down logic // ------------------------------------ - // 每次重新操作前,都尝试休眠标签 - // 以重置其可能有问题的状态机 + // Before you re -operate, try a dormant label + // to reset the state machine where it may have problems pcd_14a_reader_halt_tag(); - // 进行寻卡操作 + // Card search operation if (pcd_14a_reader_scan_auto(p_tag_info) != HF_TAG_OK) { return HF_TAG_NO; } - // 获取NT,只需要获取一次 + //Get NT, just get it once status = Check_Tag_Response_NT(p_tag_info, &nt1); if (status != HF_TAG_OK) { return status; } - // 测算NT的有效性 + //Calculate the effectiveness of NT if (validate_prng_nonce_notable(nt1)) { // NRF_LOG_INFO("The tag support Nested\n"); return HF_TAG_OK; } // NRF_LOG_INFO("The tag support HardNested\n"); - // NT不可预测,无效。 + // NT is unpredictable and invalid. // ------------------------------------ // end @@ -697,26 +696,26 @@ uint8_t Check_WeakNested_Support() { } /** -* @brief : 计算两个随机数的距离 -* @param :from : 从哪个随机数开始 -* @param :to : 到哪个随机数结束 -* @retval : 距离值 +* @brief : Calculate the distance between the two random numbers +* @param :from : From which random number +* @param :to :Which random number is over +* @retval : Distance value * */ uint32_t measure_nonces(uint32_t from, uint32_t to) { - // 给出初始的坐标值 + // Give the initial coordinate value uint32_t msb = from >> 16; uint32_t lsb = to >> 16; - // 传入坐标进行直接运算,并且传出也由传入参数间接传出 + // The coordinates are passed in direct operation, and the rumors are also indirectly spread by the passing parameters. nonce_distance_notable(&msb, &lsb); return (65535 + lsb - msb) % 65535; } /** -* @brief : 中间值测量 -* @param :src : 测量源 -* @param :length : 测量源的个数 -* @retval : 中间值 +* @brief : Intermediate value measurement +* @param :src :Measurement source +* @param :length :The number of measurement sources +* @retval : Median * */ uint32_t measure_medin(uint32_t *src, uint32_t length) { @@ -729,7 +728,7 @@ uint32_t measure_medin(uint32_t *src, uint32_t length) { } for (i = 0; i < len; i++) { - // i是已排列的序列的末尾 + //i is the end of the sequence that has been arranged minIndex = i; for (int j = i + 1; j < len; j++) { if (src[j] < src[minIndex]) { @@ -746,12 +745,12 @@ uint32_t measure_medin(uint32_t *src, uint32_t length) { } /** -* @brief : 进行Nested攻击前要测量距离,如果距离合适,则可以快速破解 -* @param :u64Key : 卡片的秘钥的U64值 -* @param :block : 验证的块号 -* @param :type : 秘钥类型, 0x60(A秘钥) 或者 0x61(B秘钥) -* @param :distance : 最终的距离 -* @retval : 操作结果 +* @brief :The distance should be measured before the Nested attack. If the distance is appropriate, you can quickly crack +* @param :u64Key : The U64 value of the secret of the card +* @param :block :Verified block number +* @param :type :Type type, 0x60 (A key) or 0x61 (B secret) +* @param :distance : Final distance +* @retval : Operating result * */ uint8_t Measure_Distance(uint64_t u64Key, uint8_t block, uint8_t type, uint32_t *distance) { @@ -763,50 +762,50 @@ uint8_t Measure_Distance(uint64_t u64Key, uint8_t block, uint8_t type, uint32_t uint8_t index = 0; do { - // 重置卡片通信 + // Reset card communication pcd_14a_reader_halt_tag(); - // 我们进行快速选卡,尽可能的将验证耗时压缩 + // We will choose a fast card, and we will be compressed to verify as much as possible if (pcd_14a_reader_scan_auto(p_tag_info) != HF_TAG_OK) { NRF_LOG_INFO("Tag can't select\r\n"); return HF_TAG_NO; } - // 进行第一次验证,以便获取未经加密的NT1 + // Perform the first verification in order to obtain the unblocked NT1 if (authex(pcs, uid, block, type, u64Key, AUTH_FIRST, &nt1) != HF_TAG_OK) { NRF_LOG_INFO("Auth failed 1\r\n"); return MF_ERRAUTH; } - // 进行嵌套验证,以便获取经过加密的NT2_ENC + // Met the nested verification to obtain the encrypted NT2_ENC if (authex(pcs, uid, block, type, u64Key, AUTH_NESTED, &nt2) != HF_TAG_OK) { NRF_LOG_INFO("Auth failed 2\r\n"); return MF_ERRAUTH; } - // 判断两个随机数是否是相同的,正常情况下, - // 我们不可能的带相同的随机数,因为PRNG是随时在更新chip的 - // 如果确实遇到了相同的NT,那么只能说明,这张卡是特殊固件的ST卡 + // Determine whether the two random numbers are the same, under normal circumstances, + // We can't bring the same random number, because PRNG is updating chip at any time + // If you really encounter the same NT, then it can only be explained that this card is a ST card for special firmware if (nt1 == nt2) { NRF_LOG_INFO("StaticNested: %08x vs %08x\n", nt1, nt2); return NESTED_TAG_IS_STATIC; } - // 测量完成之后存放到buffer中 + // After the measurement is completed, store in the buffer distances[index++] = measure_nonces(nt1, nt2); // dbg_block_printf("dist = %"PRIu32"\n\n", distances[index - 1]); } while (index < DIST_NR); - // 最终计算两个NT的距离并且直接传出 +//The final calculation of the distance between the two NTs and spread it directly *distance = measure_medin(distances, DIST_NR); - // 需要返回OK值,以标志任务成功 +// You need to return the OK value to successfully log in return HF_TAG_OK; } /** -* @brief : Nested核心,用于收集随机数,此函数只负责收集,不负责转换与解析为KS -* @param :pnc : nested 核心结构体,保存相关的通信数据 -* @param :keyKnown : 卡片的已知秘钥的U64值 -* @param :blkKnown : 卡片的已知秘钥的所属扇区 -* @param :typKnown : 卡片的已知秘钥的类型, 0x60(A秘钥) 或者 0x61(B秘钥) -* @param :targetBlock : 需要nested攻击的目标扇区 -* @param :targetType : 需要nested攻击的目标秘钥类型 -* @retval : 成功返回 HF_TAG_OK ,验证不成功返回非 HF_TAG_OK 值 +* @brief : Nested core, used to collect random numbers. This function is only responsible for collecting, not responsible for conversion and analysis as KS +* @param :pnc :Nested core structure, save related communication data +* @param :keyKnown : The U64 value of the known secret key of the card +* @param :blkKnown :The owner of the known secret key of the card +* @param :typKnown : Types of the known secret key of the card, 0x60 (A secret) or 0x61 (B secret) +* @param :targetBlock : The target sector that requires a Nested attack +* @param :targetType :The target key type requires the Nested attack +* @retval : Successfully return hf_tag_ok, verify the unsuccessful return of the non -hf_tag_ok value * */ uint8_t Nested_Recover_Core(NestedCore *pnc, uint64_t keyKnown, uint8_t blkKnown, uint8_t typKnown, uint8_t targetBlock, uint8_t targetType) { @@ -816,27 +815,27 @@ uint8_t Nested_Recover_Core(NestedCore *pnc, uint64_t keyKnown, uint8_t blkKnown uint8_t parity[4] = {0x00}; uint8_t answer[4] = {0x00}; uint32_t uid, nt1; - // 转换UID为U32类型,后面用得上 + //Convert UID to U32 type, which can be used later uid = get_u32_tag_uid(p_tag_info); - // 重置卡片通信 + // Reset card communication pcd_14a_reader_halt_tag(); - // 快速选卡,以便完成验证步骤收集NT1和NT2_ENC + // Quickly select the card to complete the verification steps to collect NT1 and NT2_ENC if (pcd_14a_reader_scan_auto(p_tag_info) != HF_TAG_OK) { return HF_TAG_NO; } - // 第一步验证,基础验证不需要嵌套加密 + //The first step verification, basic verification does not require nested and encrypted if (authex(pcs, uid, blkKnown, typKnown, keyKnown, AUTH_FIRST, &nt1) != HF_TAG_OK) { return MF_ERRAUTH; } - // 然后就是嵌套验证 + // Then there is nested verification if (sendcmd(pcs, AUTH_NESTED, targetType, targetBlock, &status, answer, parity, U8ARR_BIT_LEN(answer)) != 32) { return HF_ERRSTAT; }; - // 第一次验证的明文随机数 + // The first verified explicitly random number num_to_bytes(nt1, 4, pnc->nt1); - // 嵌套验证的被目标扇区的密码加密的随机数 + // The random number of the password encryption of the nested verification verification memcpy(pnc->nt2, answer, 4); - // 保存3个bit的奇偶校验位 + //Save 3 bit's puppet test seats pnc->par = 0; pnc->par |= ((oddparity8(answer[0]) != parity[0]) << 0); pnc->par |= ((oddparity8(answer[1]) != parity[1]) << 1); @@ -845,24 +844,24 @@ uint8_t Nested_Recover_Core(NestedCore *pnc, uint64_t keyKnown, uint8_t blkKnown } /** -* @brief : Nested默认实现,用于收集 SETS_NR 组随机数,此函数只负责收集,不负责转换与解析为KS -* @param :ncs : nested 核心结构体数组,保存相关的通信数据 -* @param :keyKnown : 卡片的已知秘钥的U64值 -* @param :blkKnown : 卡片的已知秘钥的所属扇区 -* @param :typKnown : 卡片的已知秘钥的类型, 0x60(A秘钥) 或者 0x61(B秘钥) -* @param :targetBlock : 需要nested攻击的目标扇区 -* @param :targetType : 需要nested攻击的目标秘钥类型 -* @retval : 攻击返回 HF_TAG_OK ,攻击不成功返回非 HF_TAG_OK 值 +* @brief :NESTED is implemented by default to collect random numbers of the sets_nr group. This function is only responsible for collecting, not responsible for conversion and analysis as KS +* @param :ncs : Nested core structure array, save related communication data +* @param :keyKnown : The U64 value of the known secret key of the card +* @param :blkKnown :The owner of the known secret key of the card +* @param :typKnown : Types of the known secret key of the card, 0x60 (A secret) or 0x61 (B secret) +* @param :targetBlock : The target sector that requires a Nested attack +* @param :targetType : The target key type requires the Nested attack +* @retval :The attack returns hf_tag_ok, the attack is unsuccessful to return the non -hf_tag_ok value * */ uint8_t Nested_Recover_Key(uint64_t keyKnown, uint8_t blkKnown, uint8_t typKnown, uint8_t targetBlock, uint8_t targetType, NestedCore ncs[SETS_NR]) { uint8_t m, res; - // 先寻卡,所有的操作都要基于有卡的情况 + // Survening card, all operations must be based on the card res = pcd_14a_reader_scan_auto(p_tag_info); if (res != HF_TAG_OK) { return res; } - // 然后采集指定个数的随机数组 + //Then collect the specified number of random array for (m = 0; m < SETS_NR; m++) { res = Nested_Recover_Core( &(ncs[m]), @@ -880,33 +879,33 @@ uint8_t Nested_Recover_Key(uint64_t keyKnown, uint8_t blkKnown, uint8_t typKnown } /** -* @brief : Nested 距离探测实现 -* @param :block : 卡片的已知秘钥的所属扇区 -* @param :type : 卡片的已知秘钥的类型, 0x60(A秘钥) 或者 0x61(B秘钥) -* @param :key : 卡片的已知秘钥的U64值 -* @param :nd : 随机数距离的探测结果 -* @retval : 操作状态值 +* @brief : NestedFollow detection implementation +* @param :block :The owner of the known secret key of the card +* @param :type : Types of the known secret key of the card, 0x60 (A secret) or 0x61 (B secret) +* @param :key : The U64 value of the known secret key of the card +* @param :nd : Random number distance detection results +* @retval : Operating status value * */ uint8_t Nested_Distacne_Detect(uint8_t block, uint8_t type, uint8_t *key, NestedDist *nd) { uint8_t status = HF_TAG_OK; uint32_t distance = 0; - // 必须要确保场内有卡 + //Must ensure that there is a card on the court status = pcd_14a_reader_scan_auto(p_tag_info); if (status != HF_TAG_OK) { return status; } else { - // 至少卡片是存在的,可以先复制UID到缓冲区 + // At least the card exists, you can copy the UID to the buffer first get_4byte_tag_uid(p_tag_info, nd->uid); } - // 获取距离,为接下来的攻击做准备 + // Get distance, prepare for the next attack status = Measure_Distance( bytes_to_num(key, 6), block, type, &distance ); - // 一切正常,我们需要将距离值放入结果中 + // Everything is normal, we need to put the distance value into the result if (status == HF_TAG_OK) { num_to_bytes(distance, 4, nd->distance); } @@ -914,15 +913,15 @@ uint8_t Nested_Distacne_Detect(uint8_t block, uint8_t type, uint8_t *key, Nested } /** -* @brief : 使用基于RC522的M1算法模块去验证密钥 -* @retval : 验证结果 +* @brief : Use the RC522 M1 algorithm module to verify the key +* @retval : validationResults * */ uint8_t auth_key_use_522_hw(uint8_t block, uint8_t type, uint8_t *key) { - // 每次验证一个block都要重新寻卡 + // Each verification of a block must re -find a card if (pcd_14a_reader_scan_auto(p_tag_info) != HF_TAG_OK) { return HF_TAG_NO; } - // 寻到卡后我们开始验证! + // After finding the card, we start to verify! return pcd_14a_reader_mf1_auth(p_tag_info, type, block, key); } diff --git a/firmware/application/src/rfid/reader/hf/mf1_toolbox.h b/firmware/application/src/rfid/reader/hf/mf1_toolbox.h index c5354eb..d32a7dd 100644 --- a/firmware/application/src/rfid/reader/hf/mf1_toolbox.h +++ b/firmware/application/src/rfid/reader/hf/mf1_toolbox.h @@ -8,8 +8,8 @@ #include -#define SETS_NR 2 // 使用几组随机数探针,至少是2个能确保有两组随机数组合进行交集查询,这个值越大越容易成功 -#define DIST_NR 3 // 越多的距离值越能准确判断当前卡片的通信稳定性 +#define SETS_NR 2 // Using several sets of random number probes, at least two can ensure that there are two sets of random number combinations for intersection inquiries. The larger the value, the easier it is to succeed. +#define DIST_NR 3 // The more distance the distance can accurately judge the communication stability of the current card // mifare authentication #define CRYPT_NONE 0 @@ -18,16 +18,16 @@ #define AUTH_FIRST 0 #define AUTH_NESTED 2 -typedef struct { // 应答 nested 攻击需要的 距离参数 - uint8_t uid[4]; // 这个距离数据的所属UID的U32部分 - uint8_t distance[4]; // 未经加密的明文随机数 +typedef struct { //Answer the distance parameters required for Nested attack + uint8_t uid[4]; //The U32 part of the UID part of this distance data + uint8_t distance[4]; //Unblocked explicitly random number } NestedDist; -typedef struct { // 应答 nested 攻击需要的 随机数参数 - uint8_t nt1[4]; // 未经加密的明文随机数 - uint8_t nt2[4]; // 嵌套验证加密的随机数 - uint8_t par; // 嵌套验证加密的通信过程的奇偶校验位,只用到了 '低3位',也就是右3位 +typedef struct { //Answer the random number parameters required for Nested attack + uint8_t nt1[4]; //Unblocked explicitly random number + uint8_t nt2[4]; //Random number of nested verification encryption + uint8_t par; //The puppet test of the communication process of nested verification encryption, only the "low 3 digits', that is, the right 3 } NestedCore; typedef struct { diff --git a/firmware/application/src/rfid/reader/hf/rc522.c b/firmware/application/src/rfid/reader/hf/rc522.c index ee23e56..0ab3b44 100644 --- a/firmware/application/src/rfid/reader/hf/rc522.c +++ b/firmware/application/src/rfid/reader/hf/rc522.c @@ -25,25 +25,25 @@ NRF_LOG_MODULE_REGISTER(); #define RC522_UNSEL nrf_gpio_pin_set(HF_SPI_SELECT) -// CRC 14a计算器,当MCU性能太弱,或者MCU繁忙时,可以使用522计算CRC +//CRC 14A calculator, when the MCU performance is too weak, or when the MCU is busy, you can use 522 to calculate CRC static uint8_t m_crc_computer = 0; -// 当前是否初始化了读卡器 +//Whether it is initialized by the card reader static bool m_reader_is_init = false; -// 通信超时 +// Communication timeout static uint16_t g_com_timeout_ms = DEF_COM_TIMEOUT; static autotimer *g_timeout_auto_timer; -// RC522使用的SPI +// RC522 SPI #define SPI_INSTANCE 0 /**< SPI instance index. */ static const nrf_drv_spi_t s_spiHandle = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE); // SPI instance #define ONCE_OPT __attribute__((optimize("O3"))) /** -* @brief :读寄存器 -* @param :Address:寄存器地址 -* @retval :寄存器内的值 +* @brief :Read register +* @param :Address:Register address +* @retval :Value in the register */ uint8_t read_register_single(uint8_t Address) { RC522_DOSEL; @@ -71,39 +71,39 @@ void read_register_buffer(uint8_t Address, uint8_t *pInBuffer, uint8_t len) { Address = (((Address << 1) & 0x7E) | 0x80); NRF_SPI0->TXD = Address; - while (NRF_SPI0->EVENTS_READY == 0); // 等待传输结束 + while (NRF_SPI0->EVENTS_READY == 0); // Waiting for transmission ends NRF_SPI0->EVENTS_READY = 0; - (void)NRF_SPI0->RXD; // 读取一次,给一个电平 + (void)NRF_SPI0->RXD; //Read once and give a level uint8_t i = 0; do { - // 然后开始收数据 + //Then start receiving data NRF_SPI0->TXD = Address; - while (NRF_SPI0->EVENTS_READY == 0); // 等待传输结束 + while (NRF_SPI0->EVENTS_READY == 0); //Waiting for transmission NRF_SPI0->EVENTS_READY = 0; - pInBuffer[i] = NRF_SPI0->RXD; // 读取一次,给一个电平 + pInBuffer[i] = NRF_SPI0->RXD; // Read once and give a level } while (++i < len); RC522_UNSEL; } /** -* @brief :写寄存器 -* @param :Address:寄存器地址 -* value: 将要写入的值 +* @brief :Write register +* @param :Address:Register address +* value: The value to be written */ void ONCE_OPT write_register_single(uint8_t Address, uint8_t value) { RC522_DOSEL; Address = ((Address << 1) & 0x7E); - // 先传地址 + // First pass the address first pass the address NRF_SPI0->TXD = Address; while (NRF_SPI0->EVENTS_READY == 0); NRF_SPI0->EVENTS_READY = 0; (void)NRF_SPI0->RXD; - // 再传要写的值 + // Passing address NRF_SPI0->TXD = value; while (NRF_SPI0->EVENTS_READY == 0); NRF_SPI0->EVENTS_READY = 0; @@ -124,7 +124,7 @@ void write_register_buffer(uint8_t Address, uint8_t *values, uint8_t len) { uint8_t i = 0; do { - // 然后疯狂发数据 + // Passing address NRF_SPI0->TXD = values[i]; while (NRF_SPI0->EVENTS_READY == 0); NRF_SPI0->EVENTS_READY = 0; @@ -135,91 +135,91 @@ void write_register_buffer(uint8_t Address, uint8_t *values, uint8_t len) { } /** -* @brief :寄存器功能开关 -* @param :reg:寄存器地址 -* mask: 开关范围 +* @brief : Register function switch +* @param : REG: register address +* mask: Switch */ inline void set_register_mask(uint8_t reg, uint8_t mask) { write_register_single(reg, read_register_single(reg) | mask); // set bit mask } /** -* @brief :寄存器功能开关 -* @param :reg:寄存器地址 -* mask: 开关范围 +* @brief : Register function switch +* @param : REG: register address +* mask: Switch */ inline void clear_register_mask(uint8_t reg, uint8_t mask) { write_register_single(reg, read_register_single(reg) & ~mask); // clear bit mask } /** -* @brief 初始化读卡器 -* @retval 无 +* @brief Initialized card reader +* @retval none */ void pcd_14a_reader_init(void) { - // 确保只初始化一次 + // Make sure you only initialize it once if (!m_reader_is_init) { - // 标志为已经初始化状态 + // The logo is the state of initialization m_reader_is_init = true; - // 初始化NSS脚GPIO + // Initialize NSS foot GPIO nrf_gpio_cfg_output(HF_SPI_SELECT); - // 初始化SPI + // Initialize SPI ret_code_t errCode; - nrf_drv_spi_config_t spiConfig = NRF_DRV_SPI_DEFAULT_CONFIG; // 使用SPI默认配置 - // 配置SPI端口,注意CSN不要在这设置,另外用GPIO口控制 + nrf_drv_spi_config_t spiConfig = NRF_DRV_SPI_DEFAULT_CONFIG; // Use SPI default configuration + // Configure the SPI port, pay attention not to set the CSN here, and use the GPIO port control spiConfig.miso_pin = HF_SPI_MISO; spiConfig.mosi_pin = HF_SPI_MOSI; spiConfig.sck_pin = HF_SPI_SCK; spiConfig.mode = NRF_DRV_SPI_MODE_0; spiConfig.frequency = NRF_DRV_SPI_FREQ_8M; - // 配置为堵塞型操作 + // Configure to block operation errCode = nrf_drv_spi_init(&s_spiHandle, &spiConfig, NULL, NULL); APP_ERROR_CHECK(errCode); - // 初始化定时器 - // 这个定时器初始化后就不释放了,始终需要占用着 + // Initialized timer + // This timer is not released after the initialization of the timer, and it always needs to take up g_timeout_auto_timer = bsp_obtain_timer(0); } } /** -* @brief :重置读卡器 -* @retval :状态值HF_TAG_OK,成功 +* @brief : Reset the card reader +* @retval : Status value hf_tag_ok, success */ void pcd_14a_reader_reset(void) { - // 确保已经初始化再进行通信与软重置 + // Make sure you have initialized and then communicate with soft reworting if (m_reader_is_init) { - // 软重置 522 + // Softening 522 write_register_single(CommandReg, PCD_IDLE); write_register_single(CommandReg, PCD_RESET); - // 开关天线 + // Switch antenna clear_register_mask(TxControlReg, 0x03); set_register_mask(TxControlReg, 0x03); - // 禁用522的定时器,使用MCU的定时器超时 + // Disable the timer of 522, use the MCU timer timeout time write_register_single(TModeReg, 0x00); - // 调制发送信号为100%ASK + // The modulation sending signal is 100%ask write_register_single(TxAutoReg, 0x40); - // 定义发送和接收常用模式 和Mifare卡通讯,CRC初始值0x6363 + // Define common mode and receive common mode and receiveMiFare cartoon communication, CRC initial value 0x6363 write_register_single(ModeReg, 0x3D); - // 然后默认不使能天线 - // 请不要持续使能高频的天线 + // Then default does not allow the antenna + // Please don't continue to make high -frequency antennas pcd_14a_reader_antenna_off(); } } /** -* @brief 反初始化读卡器 -* @retval 无 +* @brief Anti -initial starting card reader +* @retval none */ void pcd_14a_reader_uninit(void) { - // 确保已经初始化过设备了,再进行反初始化 + // Make sure that the device has been initialized, and then the anti -initialization if (m_reader_is_init) { m_reader_is_init = false; bsp_return_timer(g_timeout_auto_timer); @@ -228,32 +228,32 @@ void pcd_14a_reader_uninit(void) { } /** -* @brief MF522 通信超时配置 -* @param :timeout_ms:超时值 +* @brief MF522 Communication timeout configuration +* @param : Timeout_ms: timeout value * -* @retval 无 +* @retval none */ void pcd_14a_reader_timeout_set(uint16_t timeout_ms) { g_com_timeout_ms = timeout_ms; } /** -* @brief MF522 通信超时获取 +* @brief MF522 Communication timeout acquisition * -* @retval 超时值 +* @retval Timeout */ uint16_t pcd_14a_reader_timeout_get() { return g_com_timeout_ms; } /** -* @brief :通过RC522和ISO14443卡通讯 -* @param :Command:RC522命令字 -* pIn:通过RC522发送到卡片的数据 -* InLenByte:发送数据的字节长度 -* pOut:接收到的卡片返回数据 -* pOutLenBit:返回数据的位长度 -* @retval :状态值MI_OK,成功 +* @brief : Through RC522 and ISO14443 cartoon communication +* @param : Command: RC522 command word +* PIN: Data sent to the card through RC522 +* Inlenbyte: The byte length of sending the data +* POUT: The receiving card returns the data +* POUTLENBIT: Bit the length of the data +* @retval : Status value mi_ok, successful */ uint8_t pcd_14a_reader_bytes_transfer(uint8_t Command, uint8_t *pIn, uint8_t InLenByte, uint8_t *pOut, uint16_t *pOutLenBit, uint16_t maxOutLenBit) { uint8_t status = HF_ERRSTAT; @@ -262,104 +262,104 @@ uint8_t pcd_14a_reader_bytes_transfer(uint8_t Command, uint8_t *pIn, uint8_t In uint8_t n = 0; uint8_t pcd_err_val = 0; uint8_t not_timeout = 0; - // 重置接收到的数据的长度 + // Reset the length of the received data *pOutLenBit = 0; switch (Command) { - case PCD_AUTHENT: // Mifare认证 - waitFor = 0x10; // 认证寻卡等待时候 查询空闲中断标志位 + case PCD_AUTHENT: // MiFare certification + waitFor = 0x10; // Query the free interrupt logo when the certification card is waiting break; case PCD_TRANSCEIVE: - waitFor = 0x30; // 寻卡等待时候 查询接收中断标志位与 空闲中断标志位 + waitFor = 0x30; // Inquiry the receiving interrupt logo position and Leisure interrupt logo break; } - write_register_single(CommandReg, PCD_IDLE); // 置位FlushBuffer清除内部FIFO的读和写指针以及ErrReg的BufferOvfl标志位被清除 - clear_register_mask(ComIrqReg, 0x80); // Set1该位清零时,CommIRqReg的屏蔽位清零 - set_register_mask(FIFOLevelReg, 0x80); // 写空闲命令 + write_register_single(CommandReg, PCD_IDLE); // Flushbuffer clearing the internal FIFO read and writing pointer and ErRreg's Bufferovfl logo position is cleared + clear_register_mask(ComIrqReg, 0x80); // When Set1 is cleared, the shielding position of commonricqreg is clear zero + set_register_mask(FIFOLevelReg, 0x80); // Write an empty order - write_register_buffer(FIFODataReg, pIn, InLenByte); // 写数据进FIFOdata - write_register_single(CommandReg, Command); // 写命令 + write_register_buffer(FIFODataReg, pIn, InLenByte); // Write data into FIFODATA + write_register_single(CommandReg, Command); // Write command if (Command == PCD_TRANSCEIVE) { - set_register_mask(BitFramingReg, 0x80); // StartSend置位启动数据发送 该位与收发命令使用时才有效 + set_register_mask(BitFramingReg, 0x80); // StartSend places to start the data to send this bit and send and receive commands when it is valid } if (pOut == NULL) { - // 如果开发者不需要接收数据,那么在发送完成后直接返回! + // If the developer does not need to receive data, then return directly after the sending! while ((read_register_single(Status2Reg) & 0x07) == 0x03); return HF_TAG_OK; } - bsp_set_timer(g_timeout_auto_timer, 0); // 在启动操作前先归零超时计数器 + bsp_set_timer(g_timeout_auto_timer, 0); // Before starting the operation, return to zero over time counting do { - n = read_register_single(ComIrqReg); // 读取通信中断寄存器,判断当前的IO任务是否完成! + n = read_register_single(ComIrqReg); // Read the communication interrupt register to determine whether the current IO task is completed! not_timeout = NO_TIMEOUT_1MS(g_timeout_auto_timer, g_com_timeout_ms); - } while (not_timeout && (!(n & waitFor))); // 退出条件:超时中断,与写空闲命令中断 + } while (not_timeout && (!(n & waitFor))); // Exit conditions: timeout interruption, interrupt with empty command commands // NRF_LOG_INFO("N = %02x\n", n); if (Command == PCD_TRANSCEIVE) { - clear_register_mask(BitFramingReg, 0x80); // 清理允许StartSend位与比特长度位 + clear_register_mask(BitFramingReg, 0x80); // Clean up allows the startsend bit and the bit length position } - // 是否接收超时 + // Whether to receive timeout if (not_timeout) { - // 先判断是否有错误寄存器的置位 + // First determine whether there is a place where there is an error register if (n & 0x02) { - // 有错误发生 - // 读错误标志寄存器 BufferOfI CollErr ParityErr ProtocolErr + // Error occur + // Read an error logo register BufferOfI CollErr ParityErr ProtocolErr pcd_err_val = read_register_single(ErrorReg); - // 检测接收是否有异常 - if (pcd_err_val & 0x01) { // ProtocolErr 错误仅在下述两种情况下出现: - if (Command == PCD_AUTHENT) { // 在MFAuthent命令执行期间,若一个数据流收到的字节数错误则该位置位 - // 因此我们需要处理好,假设是验证过程中出现问题,那么我们需要认为此乃正常情况 + // Detect whether there are abnormalities + if (pcd_err_val & 0x01) { // ProtocolErr Error only appears in the following two cases: + if (Command == PCD_AUTHENT) { // During the execution of the MFAUTHENT command, if the number of bytes received by a data stream, the position of the place + // Therefore, we need to deal with it well, assuming that there are problems during the verification process, then we need to think that this is normal status = MF_ERRAUTH; - } else { // 如果SOF出错,则该位置位,接收器启动阶段自动清零,仅在106kBd速率下有效 + } else { // If the SOF is wrong, the position is set up and the receiver is automatically cleared during the start -up stage, which is effective at the rate of 106kbd NRF_LOG_INFO("Protocol error\n"); status = HF_ERRSTAT; } } else if (pcd_err_val & 0x02) { - // 检测是否有奇偶错误 + // Detecting whether there are even strange errors NRF_LOG_INFO("Parity error\n"); status = HF_ERRPARITY; - } else if (pcd_err_val & 0x04) { // 检测是否有CRC错误 + } else if (pcd_err_val & 0x04) { // Detect whether there are CRC errors NRF_LOG_INFO("CRC error\n"); status = HF_ERRCRC; - } else if (pcd_err_val & 0x08) { // 检测标签是否有冲突 + } else if (pcd_err_val & 0x08) { // There is a conflict to detect the label NRF_LOG_INFO("Collision tag\n"); status = HF_COLLISION; - } else { // 有其他的未处理的异常 + } else { // There are other unrepaired abnormalities NRF_LOG_INFO("HF error: 0x%0x2\n", pcd_err_val); status = HF_ERRSTAT; } } else { - // 无错误发生 + // Occasionally occur // NRF_LOG_INFO("COM OK\n"); if (Command == PCD_TRANSCEIVE) { - n = read_register_single(FIFOLevelReg); // 读FIFO中保存的字节数 + n = read_register_single(FIFOLevelReg); // Read the number of bytes saved in FIFO if (n == 0) { n = 1; } - lastBits = read_register_single(Control522Reg) & 0x07; // 最后接收到得字节的有效位数 + lastBits = read_register_single(Control522Reg) & 0x07; // Finally receive the validity of the byte - if (lastBits) { *pOutLenBit = (n - 1) * 8 + lastBits; } // N个字节数减去1(最后一个字节)+ 最后一位的位数 读取到的数据总位数 - else { *pOutLenBit = n * 8; } // 最后接收到的字节整个字节有效 + if (lastBits) { *pOutLenBit = (n - 1) * 8 + lastBits; } // N -byte number minus 1 (last byte)+ the number of bits of the last bit The total number of data readings read + else { *pOutLenBit = n * 8; } // Finally received the entire bytes received by the byte valid if (*pOutLenBit <= maxOutLenBit) { - // 将FIFO中的所有数据读取出来 + // Read all the data in FIFO read_register_buffer(FIFODataReg, pOut, n); - // 传输指令,读到正常的数据才能认为成功! + // Transmission instructions can be considered success when reading normal data! status = HF_TAG_OK; } else { NRF_LOG_INFO("pcd_14a_reader_bytes_transfer receive response overflow: %d, max = %d\n", *pOutLenBit, maxOutLenBit); - // 我们不能把有问题的数据传出去,这暂时没意义 + // We can't pass the problem with problems, which is meaningless for the time being *pOutLenBit = 0; - // 既然数据有问题,那就直接通知上层,告知一下 + // Since there is a problem with the data, let's notify the upper layer and inform me status = HF_ERRSTAT; } } else { - // 非传输指令,执行完成无错误就认为成功! + // Non -transmitted instructions, the execution is completed without errors and considered success! status = HF_TAG_OK; } } @@ -369,9 +369,9 @@ uint8_t pcd_14a_reader_bytes_transfer(uint8_t Command, uint8_t *pIn, uint8_t In } if (status != HF_TAG_OK) { - // 如果有某些操作异常的话, - // 我们可能需要清除 MFCrypto1On 这个寄存器标志, - // 因为可能是因为验证过导致的错误加密的通信 + // If there are certain operations, + // We may need to remove MFCrypto1On This register logo, + // Because it may be because of the error encryption communication caused by verification clear_register_mask(Status2Reg, 0x08); } @@ -380,15 +380,15 @@ uint8_t pcd_14a_reader_bytes_transfer(uint8_t Command, uint8_t *pIn, uint8_t In } /** -* @brief :通过RC522和ISO14443卡通讯 +* @brief : Through RC522 and ISO14443 cartoon communication * @param -* pTx :通过RC522发送到卡片的数据 -* szTxBits :发送数据的比特长度 -* pTxPar : 发送数据的奇偶校验位 -* pRx :存放解包后的卡片回应的数据的缓冲区 -* pRxPar :存放卡片回应的奇偶校验数据的缓冲区 -* @retval :成功的时候返回卡片回应的数据的比特长度, - 失败的时候返回对应的错误码。 +* pTx : Data sent to the card through RC522 +* szTxBits : Bit length of sending data +* pTxPar : The puppet school test of the sending data +* pRx : Caps of the data responding to the card response after storing the packaging +* pRxPar : The buffer of the strange coupling verification data responding to the card +* @retval : Bit the data of the data responding to the card response when successful, + Back the corresponding error code when failed. */ uint8_t pcd_14a_reader_bits_transfer(uint8_t *pTx, uint16_t szTxBits, uint8_t *pTxPar, uint8_t *pRx, uint8_t *pRxPar, uint16_t *pRxLenBit, uint16_t szRxLenBitMax) { @@ -400,10 +400,10 @@ uint8_t pcd_14a_reader_bits_transfer(uint8_t *pTx, uint16_t szTxBits, uint8_t * buffer[0] = pTx[0]; if (szTxBits > 8) { - // 判断到需要合并奇偶校验到数据流中 + // Determine that you need to be merged and you can check the data stream if (pTxPar != NULL) { - // 几个字节就需要几个bit,因此会 - // 多出对应字节个数的bit的数据 + // Several bytes need a few bites, so it will + // Data of BIT with more bytes of the number of bytes modulus = dataLen = szTxBits / 8; buffer[1] = (pTxPar[0] | (pTx[1] << 1)); for (i = 2; i < dataLen; i++) { @@ -418,7 +418,7 @@ uint8_t pcd_14a_reader_bits_transfer(uint8_t *pTx, uint16_t szTxBits, uint8_t * } else { modulus = szTxBits % 8; dataLen = modulus > 0 ? (szTxBits / 8 + 1) : (szTxBits / 8); - // 不需要合并奇偶校验位,就当做是外部已经做好了此处理 + // No need to merge the coupling school inspection, it is treated as the outside that has been done here. for (i = 1; i < dataLen; i++) { buffer[i] = pTx[i]; } @@ -428,22 +428,22 @@ uint8_t pcd_14a_reader_bits_transfer(uint8_t *pTx, uint16_t szTxBits, uint8_t * modulus = szTxBits; } - set_register_mask(BitFramingReg, modulus); // 设置最后一个字节传输N位 - set_register_mask(MfRxReg, 0x10); // 需要关闭奇偶校验位的使能 + set_register_mask(BitFramingReg, modulus); // Set the last byte transmission n bit + set_register_mask(MfRxReg, 0x10); // Need to close the puppet school test to enable status = pcd_14a_reader_bytes_transfer( PCD_TRANSCEIVE, buffer, - dataLen, // 数据的字节计数 - buffer, // 接收缓冲区 - pRxLenBit, // 接收到的数据的长度,注意,是比特流的长度 - U8ARR_BIT_LEN(buffer) // 能收的数据的上限长度 + dataLen, // Data byte count + buffer, // Receiving buffer + pRxLenBit, // The length of the received data, note that it is the length of the special stream + U8ARR_BIT_LEN(buffer) // The upper limit of the data that can be collected ); clear_register_mask(BitFramingReg, modulus); - clear_register_mask(MfRxReg, 0x10); // 使能奇偶校验位 + clear_register_mask(MfRxReg, 0x10); // Enable Qiqi school inspection - // 单纯判断数据传输的长度 + // Simply judge the length of data transmission if (status != HF_TAG_OK) { // NRF_LOG_INFO("pcd_14a_reader_bytes_transfer error status: %d\n", status); return status; @@ -452,22 +452,22 @@ uint8_t pcd_14a_reader_bits_transfer(uint8_t *pTx, uint16_t szTxBits, uint8_t * pRx[0] = buffer[0]; modulus = 0; if (*pRxLenBit > 8) { - // 取余,等下要用来统计字节数 + // Take the remaining, wait for the statistical number of bytes modulus = *pRxLenBit % 8; - // 取字节数,等下要用来解包 + // Take the number of bytes, wait for the packaging dataLen = *pRxLenBit / 8 + (modulus > 0); - // 取比特数,这个是最终的数据的长度 + // Take the Special Number, this is the length of the final data *pRxLenBit = *pRxLenBit - modulus; - // 进一步判断数据解码之后是否会溢出 + // Determine whether the data decoding will overflow if (*pRxLenBit > szRxLenBitMax) { NRF_LOG_INFO("pcd_14a_reader_bits_transfer decode parity data overflow: %d, max = %d\n", *pRxLenBit, szRxLenBitMax); - // 此处也要在出现溢出有,重置有效接收的数据的长度,避免外部调用者以此误判 + // There must be an overflow here, and the length of the data that is valid is reset to avoid misjudgment from external calls. *pRxLenBit = 0; return HF_ERRSTAT; } - // 最终的奇偶校验与数据的分离解包过程 + // The process of the separation and dissection process of the unprecedented verification and the data for (i = 1; i < dataLen - 1; i++) { if (pRxPar != NULL) { pRxPar[i - 1] = (buffer[i] & (1 << (i - 1))) >> (i - 1); @@ -482,20 +482,20 @@ uint8_t pcd_14a_reader_bits_transfer(uint8_t *pTx, uint16_t szTxBits, uint8_t * } /** -* @brief : ISO14443-A 寻找一张卡片,只执行一次! -* @param :tag: 存放卡片信息的buffer -* @retval :状态值HF_TAG_OK,成功 +* @brief : ISO14443-A Find a card, only execute once! +* @param :tag: Buffer that stores card information +* @retval : Status value hf_tag_ok, success */ uint8_t pcd_14a_reader_scan_once(picc_14a_tag_t *tag) { - // 初始化关键的参数 + // The key parameters of initialization if (tag) { tag->uid_len = 0; memset(tag->uid, 0, 10); } else { - return STATUS_PAR_ERR; // 寻卡不允许不传入标签信息结构体 + return STATUS_PAR_ERR; // Finding cards are not allowed to be transmitted to the label information structure } - // 唤醒 + // wake if (pcd_14a_reader_atqa_request(tag->atqa, NULL, U8ARR_BIT_LEN(tag->atqa)) != HF_TAG_OK) { // NRF_LOG_INFO("pcd_14a_reader_atqa_request HF_TAG_NO\r\n"); return HF_TAG_NO; @@ -519,13 +519,13 @@ uint8_t pcd_14a_reader_scan_once(picc_14a_tag_t *tag) { uint8_t uid_resp[5] = {0}; // UID + original BCC sel_uid[0] = sel_all[0] = PICC_ANTICOLL1 + cascade_level * 2; - // 发送防冲撞指令 + // Send anti -collision instruction status = pcd_14a_reader_bytes_transfer(PCD_TRANSCEIVE, sel_all, sizeof(sel_all), resp, &len, U8ARR_BIT_LEN(resp)); - // 出现标签冲撞,我们需要解决冲撞 + // There is a label collision, we need to solve the collision if (status != HF_TAG_OK) { - // 该冲撞还是得冲撞,解密过程中还是不要有这种情况发生 - // 所以暂时不去解决冲撞,而是直接告知用户,让用户保证场内只有一张卡 + // The collision still has to be collided. Do n't have this during the decryption process. + // So do not solve the collision for the time being, but directly inform the user that the user guarantees that there is only one card in the field NRF_LOG_INFO("Err at tag collision.\n"); return status; } else { // no collision, use the response to SELECT_ALL as current uid @@ -534,8 +534,8 @@ uint8_t pcd_14a_reader_scan_once(picc_14a_tag_t *tag) { uint8_t uid_resp_len = 4; - // 永远使用最后的UID段当做u32类型的UID, - // 不管是几字节的UID段 + // Always use the final UID paragraph as U32 type UID, + // No matter how many bytes of UID paragraphs // *u32Uid = bytes_to_num(uid_resp, 4); // Construct SELECT UID command @@ -550,18 +550,18 @@ uint8_t pcd_14a_reader_scan_once(picc_14a_tag_t *tag) { crc_14a_append(sel_uid, 7); // calculate and add CRC - // 发送 9x 70 去选卡 + // send 9x 70 Choose a card status = pcd_14a_reader_bytes_transfer(PCD_TRANSCEIVE, sel_uid, sizeof(sel_uid), resp, &len, U8ARR_BIT_LEN(resp)); if (status != HF_TAG_OK) { NRF_LOG_INFO("Err at sak receive.\n"); return HF_ERRSTAT; } - // 缓冲接收到的SAK + // Sak received by buffer tag->sak = resp[0]; - // 如果UID是以 0X88 的形式开头的,说明UID还不完整 - // 下次循环我们需要进行递增级联,返回结束防冲撞,完成级联 + // If UID is 0X88 The beginning of the form shows that the UID is not complete + // In the next cycle, we need to make an increased level, return to the end of the anti -rushing collision, and complete the level do_cascade = (((tag->sak & 0x04) /* && uid_resp[0] == 0x88 */) > 0); if (do_cascade) { // Remove first byte, 0x88 is not an UID byte, it CT, see page 3 of: @@ -572,45 +572,45 @@ uint8_t pcd_14a_reader_scan_once(picc_14a_tag_t *tag) { uid_resp_len = 3; } - // 拷贝卡片的UID信息到传入的结构体中 + // Copy the UID information of the card to the transmitted structure memcpy(tag->uid + (cascade_level * 3), uid_resp, uid_resp_len); tag->uid_len += uid_resp_len; - // 级联只有 1 2 3 三种,对应 4 7 10 字节的卡号 - // 因此需要在下标为0的基础上 + 1 + // Only 1 2 3 Three types, corresponding 4 7 10 Byte card number + // Therefore + 1 tag->cascade = cascade_level + 1; } return HF_TAG_OK; } /** -* @brief : ISO14443-A 寻找一张卡片 -* @param :tag: 存放卡片信息的buffer -* @retval :状态值HF_TAG_OK,成功 +* @brief : ISO14443-A Find a card +* @param :tag: Buffer that stores card information +* @retval : Status value hf_tag_ok, success */ uint8_t pcd_14a_reader_scan_auto(picc_14a_tag_t *tag) { uint8_t status; - // 第一次寻卡 + // The first card search status = pcd_14a_reader_scan_once(tag); if (status == HF_TAG_OK) { return HF_TAG_OK; } - // 第二次寻卡 + // Second card search status = pcd_14a_reader_scan_once(tag); if (status == HF_TAG_OK) { return HF_TAG_OK; } - // 超过上限次数 + // More than the number of upper limits return status; } /** -* @brief : 获取选择应答 -* @param :pAts:ATS的保存区域 -* @param :szAts:卡片响应的ATS的长度 -* @retval :状态值HF_TAG_OK,成功 +* @brief : Get selection response +* @param : PATS: The preservation area of ATS +* @param : SZATS: The length of the ATS response of the card +* @retval : Status value hf_tag_ok, success */ uint8_t pcd_14a_reader_ats_request(uint8_t *pAts, uint16_t *szAts, uint16_t szAtsBitMax) { uint8_t rats[] = { PICC_RATS, 0x80, 0x31, 0x73 }; // FSD=256, FSDI=8, CID=0 @@ -630,9 +630,9 @@ uint8_t pcd_14a_reader_ats_request(uint8_t *pAts, uint16_t *szAts, uint16_t szAt } /** -* @brief : 获取答复请求,类型A -* @param :pSnr:卡片序列号,N字节 -* @retval :状态值HF_TAG_OK,成功 +* @brief : Get answering request, type A +* @param : PSNR: Card serial number, n -bytes +* @retval : Status value hf_tag_ok, success */ uint8_t pcd_14a_reader_atqa_request(uint8_t *resp, uint8_t *resp_par, uint16_t resp_max_bit) { uint16_t len = 0; @@ -647,35 +647,35 @@ uint8_t pcd_14a_reader_atqa_request(uint8_t *resp, uint8_t *resp_par, uint16_t r // NRF_LOG_INFO("pcd_14a_reader_atqa_request len: %d\n", len); } while (len != 16 && (retry++ < 10)); - // 正常的 ATQA 是2字节,也就是16bit的, - // 我们需要进行判断,收到的数据是否正确 + // normal ATQA It is 2 bytes, that is, 16bit, + // We need to judge whether the data received is correct if (status == HF_TAG_OK && len == 16) { - // 可以确认当前场内存在至少一张14A的卡了 + // You can confirm that at least one 14A card exists in the current field return HF_TAG_OK; } - // 不存在卡片 + // No card return HF_TAG_NO; } /** -* @brief : 解锁GEN1A后门卡以进行非标准M1操作步骤 -* 注意,解锁之后不要halt卡片,后门指令的生命周期只存在于当次解锁后的 -* 数据块读写操作范围内,如果发生场掉电或卡片被halt或者重新防冲撞, -* 将会失去后门权限,需要调用此函数重新启动。 +* @brief : Unlock the Gen1a back door card for non -standard M1 operation steps +* Note that do not have a card after unlocking. +* Within the data block reading and writing operation range, if the field is turned off or the card is halt or the collision is re -anti -collision, +* It will lose the back door authority, and you need to call this function to restart. * -* @retval :状态值 HF_TAG_OK,解锁成功,其他状态值表示解锁失败 +* @retval : Status value Hf_tag_ok, unlocked successfully, other state values indicate unlocking failure */ uint8_t pcd_14a_reader_gen1a_unlock(void) { - // 初始化变量 + // Initialize variables uint8_t unlock, status; uint16_t rx_length = 0; uint8_t recvbuf[1] = { 0x00 }; - // 重启通信(非常重要) + // Restart communication (very important) pcd_14a_reader_halt_tag(); - // 第一步解锁,发送7bit的 0x40 + // Unlock the first step, send 7bit 0x40 unlock = PICC_MAGICWUPC1; status = pcd_14a_reader_bits_transfer(&unlock, 7, NULL, recvbuf, NULL, &rx_length, U8ARR_BIT_LEN(recvbuf)); if (!(status == HF_TAG_OK && rx_length == 4 && recvbuf[0] == 0x0A)) { @@ -683,7 +683,7 @@ uint8_t pcd_14a_reader_gen1a_unlock(void) { return HF_ERRSTAT; } - // 第二步解锁,发送整字节的 0x43 + // Step in the second step, send a complete byte 0x43 unlock = PICC_MAGICWUPC2; status = pcd_14a_reader_bytes_transfer(PCD_TRANSCEIVE, &unlock, 1, recvbuf, &rx_length, U8ARR_BIT_LEN(recvbuf)); if (!(status == HF_TAG_OK && rx_length == 4 && recvbuf[0] == 0x0A)) { @@ -691,24 +691,24 @@ uint8_t pcd_14a_reader_gen1a_unlock(void) { return HF_ERRSTAT; } - // 两次解锁都没问题,我们默认这次解锁操作成功! + // There is no problem with unlocking twice. We default this unlock operation successfully! return HF_TAG_OK; } /** -* @brief : 对UFUID卡进行上锁操作,封锁后门指令,使其成为普通卡,不响应后门指令 -* 这个操作成功的前提是: -* 1、已经调用 pcd_14a_reader_gen1a_unlock() 函数解锁卡片成功 -* 2、卡片具有 UFUID 卡的封后门指令功能 +* @brief : Perform the UFUID card and block the back door instructions to make it a normal card without responding to the back door instruction +* The premise of successful this operation is: +* 1. Has been called pcd_14a_reader_gen1a_unlock() Function unlock card successfully +* 2. The card has UFUID Card sealing door instruction function * -* @retval :状态值 HF_TAG_OK,封卡或者存在封卡后门, - 其他状态值表示封卡失败或者没有封卡后门 +* @retval : Status value Hf_tag_ok, closure card or the back door of the card seal, + Other status values indicate the failure of the card or the back door without a card */ uint8_t pcd_14a_reader_gen1a_uplock(void) { uint8_t status; uint16_t rx_length = 0; - // 我们已知的双层封卡指令 + // Our known dual -layer card sealing instructions uint8_t uplock_1[] = { 0xE1, 0x00, 0xE1, 0xEE }; uint8_t uplock_2[] = { 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -731,19 +731,19 @@ uint8_t pcd_14a_reader_gen1a_uplock(void) { return HF_ERRSTAT; } - // 封卡成功 + // Successful card sealing return HF_TAG_OK; } /** -* @brief :校验M1卡片密码 -* @param :type:密码验证模式 -* = 0x60,验证A密钥 -* = 0x61,验证B密钥 -* ucAddr:块地址 -* pKey:密码 -* pSnr:卡片序列号,4字节 -* @retval :状态值HF_TAG_OK成功,TAG_ERRAUTH失败,其他的返回值表示一些通信错误相关的异常! +* @brief : Check M1 card password +* @param : Type: Password verification mode +* = 0x60, verify the A key +* = 0x61, verify the B key +* ucaddr: block address +* pKEY: password +* PSNR: Card serial number, 4 bytes +* @retval : The status value HF_TAG_OK is successful, tag_errauth fails, and other returns indicate some abnormalities related to communication errors! */ uint8_t pcd_14a_reader_mf1_auth(picc_14a_tag_t *tag, uint8_t type, uint8_t addr, uint8_t *pKey) { uint8_t dat_buff[12] = { type, addr }; @@ -754,29 +754,29 @@ uint8_t pcd_14a_reader_mf1_auth(picc_14a_tag_t *tag, uint8_t type, uint8_t addr, pcd_14a_reader_bytes_transfer(PCD_AUTHENT, dat_buff, 12, dat_buff, &data_len, U8ARR_BIT_LEN(dat_buff)); - // 为了提高兼容性,我们此处直接判断执行完成 PCD_AUTHENT - // 指令之后,Status2Reg中的通信加密位是否被置位就行了。 + // In order to improve compatibility, we directly judge the implementation of the execution PCD_AUTHENT + // After the instruction, whether the communication plus position in Status2reg is placed. if (read_register_single(Status2Reg) & 0x08) { return HF_TAG_OK; } - // 其他的情况都认为失败! + // Other situations are considered failure! return MF_ERRAUTH; } /** -* @brief :取消已经校验的密钥的状态 +* @brief : Cancel the state of the checked key */ void pcd_14a_reader_mf1_unauth(void) { clear_register_mask(Status2Reg, 0x08); } /** -* @brief :读取M1卡的指定块地址的数据 -* @param :cmd : 读块指令 -* addr:块地址 -* p :读出的数据,16字节 -* @retval :状态值HF_TAG_OK,成功 +* @brief : Read the data of the specified block address of the m1 card +* @param :cmd : Read instruction +* addr: block address +* p : Read data, 16 bytes +* @retval : Status value hf_tag_ok, success */ uint8_t pcd_14a_reader_mf1_read_by_cmd(uint8_t cmd, uint8_t addr, uint8_t *p) { uint8_t status; @@ -784,25 +784,25 @@ uint8_t pcd_14a_reader_mf1_read_by_cmd(uint8_t cmd, uint8_t addr, uint8_t *p) { uint8_t dat_buff[MAX_MIFARE_FRAME_SIZE] = { cmd, addr }; uint8_t crc_buff[DEF_CRC_LENGTH] = { 0x00 }; - // 短数据直接让 MCU 计算 + // Short data directly MCU calculate crc_14a_append(dat_buff, 2); - // 然后发起通信 + // Then initiate communication status = pcd_14a_reader_bytes_transfer(PCD_TRANSCEIVE, dat_buff, 4, dat_buff, &len, U8ARR_BIT_LEN(dat_buff)); if (status == HF_TAG_OK) { if (len == 0x90 /* 0x90 = 144bits */) { - // 16字节长度的CRC数据,为了不浪费CPU性能, - // 我们可以让 522 去计算 + // 16 -byte length CRC data, in order not to waste the CPU performance, + // We can let 522 Calculate crc_14a_calculate(dat_buff, 16, crc_buff); - // 校验一下CRC,避免数据出错 + // Check the CRC to avoid data errors if ((crc_buff[0] != dat_buff[16]) || (crc_buff[1] != dat_buff[17])) { status = HF_ERRCRC; } - // 虽然 CRC 校验有毛病,但是我们还是可以回传 - // 读取到的卡片数据,因为开发者有可能有特殊用法 + // Although CRC After checking the problem, but we can still pass back + // Read the card data, because developers may have special usage memcpy(p, dat_buff, 16); } else { - // 传回来的数据有毛病,可能是环境因素或者卡片不遵守规范! - // 又或者是控制位影响到了读取! + // The data passed back is wrong, which may be an environmental factors or cards that do not comply with specifications! + // Or the control bit affects reading! status = HF_ERRSTAT; } } @@ -810,62 +810,62 @@ uint8_t pcd_14a_reader_mf1_read_by_cmd(uint8_t cmd, uint8_t addr, uint8_t *p) { } /** -* @brief :读取M1卡的指定块地址的数据 -* @param :addr:块地址 -* p :读出的数据,16字节 -* @retval :状态值HF_TAG_OK,成功 +* @brief : Read the data of the specified block address of the m1 card +* @param : Addr: block address +* p : Read data, 16 bytes +* @retval : Status value hf_tag_ok, success */ uint8_t pcd_14a_reader_mf1_read(uint8_t addr, uint8_t *p) { - // 标准的M1规范内的读卡 + // Standard M1 Card Reading Card Reading return pcd_14a_reader_mf1_read_by_cmd(PICC_READ, addr, p); } /** -* @brief :在M1卡的指定块地址写入指定数据 -* @param :cmd : 写块指令 -* addr:块地址 -* p :写入的数据,16字节 +* @brief : Write the specified data at the designated block address of the M1 card +* @param :cmd : Writing instruction +* addr: block address +* p : Written data, 16 bytes * -* @retval :状态值HF_TAG_OK,成功 +* @retval : Status value hf_tag_ok, success */ uint8_t pcd_14a_reader_mf1_write_by_cmd(uint8_t cmd, uint8_t addr, uint8_t *p) { uint8_t status; uint16_t dat_len; - // 准备写卡数据,用于发起写卡 + // Prepare to write card data to initiate a card writing card uint8_t dat_buff[18] = { cmd, addr }; crc_14a_append(dat_buff, 2); // NRF_LOG_INFO("0 pcd_14a_reader_mf1_write addr = %d\r\n", addr); - // 请求写卡,此时,卡片应当回复ACK + // Request to write a card, at this time, the card should reply to ACK status = pcd_14a_reader_bytes_transfer(PCD_TRANSCEIVE, dat_buff, 4, dat_buff, &dat_len, U8ARR_BIT_LEN(dat_buff)); - // 通信失败,直接返回原因 + // The communication fails, the reason is returned directly if (status != HF_TAG_OK) { return status; } - // 通信成功,但是操作被卡片拒绝! + // The communication was successful, but the operation was rejected by the card! if ((dat_len != 4) || ((dat_buff[0] & 0x0F) != 0x0A)) { // NRF_LOG_INFO("1 status = %d, datalen = %d, data = %02x\n", status, dat_len, dat_buff[0]); status = HF_ERRSTAT; } - // 通信成功,卡片接受了写卡操作 + // The communication was successful, the card accepted the card writing operation if (status == HF_TAG_OK) { - // 1、拷贝数据并且计算 CRC + // 1. Copy data and calculate CRC memcpy(dat_buff, p, 16); crc_14a_calculate(dat_buff, 16, &dat_buff[16]); // NRF_LOG_INFO_hex("Will send: ", (uint8_t *)p, 16); // NRF_LOG_INFO("\n"); - // 2、传输最终的写卡数据完成写卡 + // 2. Transfer the final card writing data to complete the writing card status = pcd_14a_reader_bytes_transfer(PCD_TRANSCEIVE, dat_buff, 18, dat_buff, &dat_len, U8ARR_BIT_LEN(dat_buff)); - // 通信失败,直接返回原因 + // The communication fails, the reason is returned directly if (status != HF_TAG_OK) { return status; } - // 通信成功,我们需要判断卡片接收到数据后是否成功处理 - // 并且回复ACK + // The communication is successful, we need to determine whether the card is successfully processed after receiving the data + // And reply ACK if ((dat_len != 4) || ((dat_buff[0] & 0x0F) != 0x0A)) { // NRF_LOG_INFO("2 status = %d, datalen = %d, data = %02x\n", status, dat_len, dat_buff[0]); status = HF_ERRSTAT; @@ -875,34 +875,34 @@ uint8_t pcd_14a_reader_mf1_write_by_cmd(uint8_t cmd, uint8_t addr, uint8_t *p) { } /** -* @brief :在M1卡的指定块地址写入指定数据 -* @param :addr:块地址 -* p:写入的数据,16字节 -* @retval :状态值HF_TAG_OK,成功 +* @brief : Write the specified data at the designated block address of the M1 card +* @param : Addr: block address +* P: The written data, 16 bytes +* @retval : Status value hf_tag_ok, success */ uint8_t pcd_14a_reader_mf1_write(uint8_t addr, uint8_t *p) { - // 标准的M1规范内的写卡 + // Standard M1 writing card writing card return pcd_14a_reader_mf1_write_by_cmd(PICC_WRITE, addr, p); } /** -* @brief :让卡片进入休眠模式 -* @param :无 -* @retval :状态值 TAG_NOTAG,成功 +* @brief : Let the card enter the dormant mode +* @param :none +* @retval : Status value Tag_notag, success */ uint8_t pcd_14a_reader_halt_tag(void) { uint8_t status; uint16_t unLen; - // 直接准备好成型的数据了,还计算个鬼的CRC + // Prepare the molding data directly, and calculate a ghost CRC uint8_t data[] = { PICC_HALT, 0x00, 0x57, 0xCD }; status = pcd_14a_reader_bytes_transfer(PCD_TRANSCEIVE, data, 4, data, &unLen, U8ARR_BIT_LEN(data)); return status == HF_TAG_NO && unLen == 0; } /** -* @brief :快速让卡片进入休眠模式 -* @param :无 -* @retval :无 +* @brief : Quickly let the card enter the dormant mode +* @param :none +* @retval :none */ void pcd_14a_reader_fast_halt_tag(void) { uint8_t data[] = { PICC_HALT, 0x00, 0x57, 0xCD }; @@ -910,72 +910,72 @@ void pcd_14a_reader_fast_halt_tag(void) { } /** -* @brief :用RC522计算CRC16(循环冗余校验) -* @param :pIn:计算CRC16的数组 -* len:计算CRC16的数组字节长度 -* pOut:存放计算结果存放的首地址 -* @retval :状态值HF_TAG_OK,成功 +* @brief : Calculate CRC16 with RC522 (cyclic redundant verification) +* @param : PIN: Calculate the array of CRC16 +* Len: Calculate the number of bytes of the CRC16 +* POUT: Storage of the first address of the calculation results +* @retval : Status value hf_tag_ok, success */ void pcd_14a_reader_calc_crc(uint8_t *pbtData, size_t szLen, uint8_t *pbtCrc) { uint8_t i, n; - // 重置状态机 + // Reset state machine clear_register_mask(Status1Reg, 0x20); write_register_single(CommandReg, PCD_IDLE); set_register_mask(FIFOLevelReg, 0x80); - // 向FIFO写入要计算CRC的数据 + // Calculate the data of CRC to write to FIFO write_register_buffer(FIFODataReg, pbtData, szLen); write_register_single(CommandReg, PCD_CALCCRC); - // 等待计算完成 + // Waiting for calculation to complete i = szLen * 2; do { n = read_register_single(Status1Reg); i--; } while ((i != 0) && !(n & 0x20)); - // 获得最终计算出来的CRC数据 + // Get the final calculated CRC data pbtCrc[0] = read_register_single(CRCResultRegL); pbtCrc[1] = read_register_single(CRCResultRegM); } /** -* @brief :开启天线 +* @brief : Open the antenna */ inline void pcd_14a_reader_antenna_on(void) { set_register_mask(TxControlReg, 0x03); } /** -* @brief :关闭天线 +* @brief : Close the antenna */ inline void pcd_14a_reader_antenna_off(void) { clear_register_mask(TxControlReg, 0x03); } /** -* @brief :奇偶校验位启用 +* @brief : Qi Dian school inspection enabled */ inline void pcd_14a_reader_parity_on(void) { clear_register_mask(MfRxReg, 0x10); } /** -* @brief :奇偶校验位关闭 +* @brief : Qi Tong school inspection position closed */ inline void pcd_14a_reader_parity_off(void) { set_register_mask(MfRxReg, 0x10); } /** -* @brief : 获得级联命令,输入只允许存在三种情况 -* 1 表示第一次级联,命令是 PICC_ANTICOLL1 -* 2 表示第二次级联,命令是 PICC_ANTICOLL2 -* 3 表示第三次级联,命令是 PICC_ANTICOLL3 -* @param :len : 存放数值的缓冲区的字节长度 -* @param :src : 存放数值的字节缓冲区 -* @retval : 转换结果 +* @brief : Obtaining a class joint command, input only allows only three cases to exist +* 1 Express the first level, the command is PICC_ANTICOLL1 +* 2 Express the second level, the command is PICC_ANTICOLL2 +* 3 Indicates the third level, the command is PICC_ANTICOLL3 +* @param :len : The byte length of the buffer of the value of the value +* @param :src : Byte buffer stored in the numerical +* @retval : Converting result * */ uint8_t cascade_to_cmd(uint8_t cascade) { @@ -997,15 +997,15 @@ uint8_t cascade_to_cmd(uint8_t cascade) { } /** -* @brief : 获得标签的4字节类型的UID,根据传入的基础卡片信息决定 -* 1 表示一次级联,UID有 4 字节,直接使用全部的 -* 2 表示二次级联,UID有 7 字节,使用后四位 -* 3 表示三次级联,UID有 10 字节,使用后四位 -* @param :tag : 存放卡片信息的结构体 -* @param :pUid : 存放结果的字节缓冲区 -* @retval : 返回实际上我们搜索到的有效UID字节的起始地址, -* 注意:此地址可能是指向栈中的,不保证一定是全局有效的地址, -* 此地址根据 tag 处于的内存位置决定生命周期。 +* @brief : The 4 -byte type UID that obtained the label, determined based on the inlet of the basic card information +* 1 Indicates a one -level joint, uID has a UID 4 Byte, use all of them directly +* 2 Indicates a secondary couple, UID has a 7 Byte, post -four digits +* 3 Express three -time couplet, uid is available 10 Byte, post -four digits +* @param :tag : Structure of storing card information +* @param :pUid : Byte buffer of the result of storage results +* @retval : Return to the starting address of the valid UID bytes we searched, +* Note: This address may refer to the stack, and it is not guaranteed that it must be a global and effective address. +* This address is based on tag The location of the memory determines the life cycle. * */ uint8_t *get_4byte_tag_uid(picc_14a_tag_t *tag, uint8_t *pUid) { @@ -1030,23 +1030,23 @@ uint8_t *get_4byte_tag_uid(picc_14a_tag_t *tag, uint8_t *pUid) { } /** -* @brief : 获得标签的U32类型的UID,根据传入的基础卡片信息决定 -* 1 表示一次级联,UID有 4 字节 -* 2 表示二次级联,UID有 7 字节 -* 3 表示三次级联,UID有 10 字节 -* @param :tag : 存放卡片信息的结构体 -* @retval : 转换结果 +* @brief : UID U32 -type U32 type, determined based on the input basic card information +* 1 Indicates a one -level joint, uID has a UID 4 byte +* 2 Indicates a secondary couple, UID has a 7 byte +* 3 Express three -time couplet, uid is available 10 byte +* @param :tag : Structure of storing card information +* @retval : Converting result * */ uint32_t get_u32_tag_uid(picc_14a_tag_t *tag) { uint8_t uid_buf[4] = { 0x00 }; - // 直接调用封装好的函数拷贝目标值 + // Directly call the encapsulated function copy the target value get_4byte_tag_uid(tag, uid_buf); return bytes_to_num(uid_buf, 4); } /** -* @brief 在选中的平台上上计算CRC +* @brief Calculate CRC on the selected platform * */ inline void crc_14a_calculate(uint8_t *pbtData, size_t szLen, uint8_t *pbtCrc) { @@ -1067,7 +1067,7 @@ inline void crc_14a_calculate(uint8_t *pbtData, size_t szLen, uint8_t *pbtCrc) { /** - * @brief 向数据结尾追加计算后的CRC + * @brief CRC after adding calculation to the end of the data * */ inline void crc_14a_append(uint8_t *pbtData, size_t szLen) { @@ -1087,10 +1087,10 @@ inline void crc_14a_append(uint8_t *pbtData, size_t szLen) { } /** -* @brief 切换CRC的计算源,默认在 MCU 上计算, -* 可以切换到RC522上计算,如果MCU的性能不是很足 -* 如果 MCU 的性能很足,建议放在 MCU 上计算,让计算过程更加的顺畅 -* 如果 MCU 的性能不足,建议放在 522 上计算,缓解MCU的计算压力 +* @brief Switch the calculation source of the CRC, the default is in MCU Calculated above, +* Can be switched to RC522 Calculation, if the performance of the MCU is not enough +* if MCU The performance is sufficient, it is recommended to put it MCU Calculated above to make the calculation process smoother +* if MCU Insufficient performance, it is recommended to put it in 522 Calculated above, alleviate the calculation pressure of MCU * */ inline void pcd_14a_reader_crc_computer(uint8_t use522CalcCRC) { diff --git a/firmware/application/src/rfid/reader/hf/rc522.h b/firmware/application/src/rfid/reader/hf/rc522.h index 1d4f3c1..3540906 100644 --- a/firmware/application/src/rfid/reader/hf/rc522.h +++ b/firmware/application/src/rfid/reader/hf/rc522.h @@ -8,155 +8,155 @@ #include /* -* RC522命令字 +* rC522CommandWord */ -#define PCD_IDLE 0x00 //取消当前命令 -#define PCD_AUTHENT 0x0E //验证密钥 -#define PCD_RECEIVE 0x08 //接收数据 -#define PCD_TRANSMIT 0x04 //发送数据 -#define PCD_TRANSCEIVE 0x0C //发送并接收数据 -#define PCD_RESET 0x0F //复位 -#define PCD_CALCCRC 0x03 //CRC计算 +#define PCD_IDLE 0x00 //Cancel the current command +#define PCD_AUTHENT 0x0E //Verification key +#define PCD_RECEIVE 0x08 //Receive data +#define PCD_TRANSMIT 0x04 //send data +#define PCD_TRANSCEIVE 0x0C //Send and receive numbers according to +#define PCD_RESET 0x0F //Restoration +#define PCD_CALCCRC 0x03 //CRC calculation /* -* ISO14443-A命令字 +* isO14443ACommandWord */ -#define PICC_REQIDL 0x26 //寻天线区内未进入休眠状态 -#define PICC_REQALL 0x52 //寻天线区内全部卡 -#define PICC_ANTICOLL1 0x93 //防冲撞 -#define PICC_ANTICOLL2 0x95 //防冲撞 -#define PICC_ANTICOLL3 0x97 //防冲撞 -#define PICC_RATS 0xE0 //选择应答 +#define PICC_REQIDL 0x26 //Find antenna area Not entering the dormant state +#define PICC_REQALL 0x52 //Find antenna area All card +#define PICC_ANTICOLL1 0x93 //Anti -collision +#define PICC_ANTICOLL2 0x95 //Anti -collision +#define PICC_ANTICOLL3 0x97 //Anti -collision +#define PICC_RATS 0xE0 //Choose to respond /* -* M1卡片命令字 +* m1CardCommandWord */ -#define PICC_AUTHENT1A 0x60 //验证A密钥 -#define PICC_AUTHENT1B 0x61 //验证B密钥 -#define PICC_READ 0x30 //读块 -#define PICC_WRITE 0xA0 //写块 -#define PICC_DECREMENT 0xC0 //扣款 -#define PICC_INCREMENT 0xC1 //充值 -#define PICC_RESTORE 0xC2 //调块数据到缓冲区 -#define PICC_TRANSFER 0xB0 //保存缓冲区中数据 -#define PICC_HALT 0x50 //休眠 +#define PICC_AUTHENT1A 0x60 //Verify A secret key +#define PICC_AUTHENT1B 0x61 //Verify B Secret key +#define PICC_READ 0x30 //Read block +#define PICC_WRITE 0xA0 //Write block +#define PICC_DECREMENT 0xC0 //Deduction +#define PICC_INCREMENT 0xC1 //Recharge +#define PICC_RESTORE 0xC2 //Bonus number According to the buffer +#define PICC_TRANSFER 0xB0 //Save slowly Data in the area +#define PICC_HALT 0x50 //Dormant -// GEN1A标签的命令字 -#define PICC_MAGICWUPC1 0x40 // 后门指令1 -#define PICC_MAGICWUPC2 0x43 // 后门指令2 -#define PICC_MAGICWIPEC 0x41 // 后门清卡指令 +// gen1ATagCommandWord +#define PICC_MAGICWUPC1 0x40 // backDoorInstruction1 +#define PICC_MAGICWUPC2 0x43 // backDoorInstruction2 +#define PICC_MAGICWIPEC 0x41 // BACK qing card incision -/* RC522 FIFO长度定义 */ +/* RC522 fifoLengthDefinition */ #define DEF_FIFO_LENGTH 64 //FIFO size=64byte -// RC522 CRC长度定义 +// RC522 crcLengthDefinition #define DEF_CRC_LENGTH 2 /* - RC522 默认定时器超时配置,这个值可以动态调整,通过 PcdSetTimeout 函数 - 操作标准M1卡最大等待时间 25ms - 我们可以提高超时以兼容一些反应比较迟钝的卡 - 比如某些手环模拟的卡,比如某些其他硬件模拟的卡,例如变色龙 - 如果超时值太小,就有可能没办法读到UID(Gen1A)卡! + RC522 theDefaultTimerTimeoutConfiguration,ThisValueCanBeAdjustedDynamically,Through PcdSetTimeout function + operationStandardM1CardMaximumWaitingTime 25ms + weCanIncreaseTimeoutToCompatibleWithSomeDullCards + forExample,SomeBraceletSimulationCards,SuchAsSomeOtherHardwareSimulationCards,SuchAsColorChangingDragons + ifTheTimeoutValueIsTooSmall,YouMayNotBeAbleToReadTheUid (gen1A)Card! */ #define DEF_COM_TIMEOUT 25 -// 数据IO长度定义 +// dataIoLengthDefinition #define MAX_MIFARE_FRAME_SIZE 18 // biggest Mifare frame is answer to a read (one block = 16 Bytes) + 2 Bytes CRC #define MAX_MIFARE_PARITY_SIZE 3 // need 18 parity bits for the 18 Byte above. 3 Bytes are enough to store these #define CARD_MEMORY_SIZE 4096 ///////////////////////////////////////////////////////////////////// -// MF522 寄存器定义 +// MF522 registerDefinition ///////////////////////////////////////////////////////////////////// // PAGE 0 -#define RFU00 0x00 //保留 -#define CommandReg 0x01 //启动和停止命令的执行 -#define ComIEnReg 0x02 //中断请求传递的使能(Enable/Disable) -#define DivlEnReg 0x03 //中断请求传递的使能 -#define ComIrqReg 0x04 //包含中断请求标志 -#define DivIrqReg 0x05 //包含中断请求标志 -#define ErrorReg 0x06 //错误标志,指示执行的上个命令的错误状态 -#define Status1Reg 0x07 //包含通信的状态标识 -#define Status2Reg 0x08 //包含接收器和发送器的状态标志 -#define FIFODataReg 0x09 //64字节FIFO缓冲区的输入和输出 -#define FIFOLevelReg 0x0A //指示FIFO中存储的字节数 -#define WaterLevelReg 0x0B //定义FIFO下溢和上溢报警的FIFO深度 -#define Control522Reg 0x0C //不同的控制寄存器 -#define BitFramingReg 0x0D //面向位的帧的调节 -#define CollReg 0x0E //RF接口上检测到的第一个位冲突的位的位置 -#define RFU0F 0x0F //保留 +#define RFU00 0x00 //reserve +#define CommandReg 0x01 //Start and stop command execution +#define ComIEnReg 0x02 //Enable/Disable for interrupt request transmission +#define DivlEnReg 0x03 //Interrupt request transmission enable +#define ComIrqReg 0x04 //Including interrupt request signs +#define DivIrqReg 0x05 //Including interrupt request signs +#define ErrorReg 0x06 //Error sign, indicate the error status of the previous command executing +#define Status1Reg 0x07 //Including communication status identification +#define Status2Reg 0x08 //Including the status logo of the receiver and the transmitter +#define FIFODataReg 0x09 //64ByteFifoBufferInputAndOutput +#define FIFOLevelReg 0x0A //Instructed the number of bytes stored in FIFO +#define WaterLevelReg 0x0B //Define the FIFO depth of FIFO overflow and overflow alarm +#define Control522Reg 0x0C //Different control registers +#define BitFramingReg 0x0D //Adjustment of position -oriented frames +#define CollReg 0x0E //The position of the first -bit conflict detected on the RF interface +#define RFU0F 0x0F //reserve // PAGE 1 -#define RFU10 0x10 //保留 -#define ModeReg 0x11 //定义发送和接收的常用模式 -#define TxModeReg 0x12 //定义发送过程的数据传输速率 -#define RxModeReg 0x13 //定义接收过程中的数据传输速率 -#define TxControlReg 0x14 //控制天线驱动器管教TX1和TX2的逻辑特性 -#define TxAutoReg 0x15 //控制天线驱动器的设置 -#define TxSelReg 0x16 //选择天线驱动器的内部源 -#define RxSelReg 0x17 //选择内部的接收器设置 -#define RxThresholdReg 0x18 //选择位译码器的阈值 -#define DemodReg 0x19 //定义解调器的设置 -#define RFU1A 0x1A //保留 -#define RFU1B 0x1B //保留 -#define MfTxReg 0x1C //控制ISO 14443/ MIFARE模式中106kbit/s的通信 (比如奇偶校验位的计算) -#define MfRxReg 0x1D //控制ISO 14443/ MIFARE模式中106kbit/s的通信 (比如奇偶校验位的计算) -#define RFU1E 0x1E //保留 -#define SerialSpeedReg 0x1F //选择串行UART接口的速率 +#define RFU10 0x10 //reserve +#define ModeReg 0x11 //Define common mode of sending and receiving +#define TxModeReg 0x12 //Define the data transmission rate of the sending process +#define RxModeReg 0x13 //Define the data transmission rate during the receiving process +#define TxControlReg 0x14 //controlTheLogicalCharacteristicsOfTheAntennaDriverDisciplinedTX1AndTX2 +#define TxAutoReg 0x15 //Control antenna drive settings +#define TxSelReg 0x16 //Select the internal source of antenna drive +#define RxSelReg 0x17 //Select the internal receiver settings +#define RxThresholdReg 0x18 //Select the threshold of the decoder +#define DemodReg 0x19 //Define the settings of the demodulator +#define RFU1A 0x1A //reserve +#define RFU1B 0x1B //reserve +#define MfTxReg 0x1C //Control ISO 14443/ 106kbit/ SCOMMUNICATIONTHEMIFAREMODE (FOREXAMPLE,TheCalculationOfTheCouplingSchoolTest) +#define MfRxReg 0x1D //Control ISO 14443/ 106kbit/ SCOMMUNICATIONTHEMIFAREMODE (FOREXAMPLE,TheCalculationOfTheCouplingSchoolTest) +#define RFU1E 0x1E //reserve +#define SerialSpeedReg 0x1F //The rate of selecting serial UART interface // PAGE 2 -#define RFU20 0x20 //保留 -#define CRCResultRegM 0x21 //显示CRC计算的实际MSB值 -#define CRCResultRegL 0x22 //显示CRC计算的实际LSB值 -#define RFU23 0x23 //保留 -#define ModWidthReg 0x24 //控制ModWidth的设置 -#define RFU25 0x25 //保留 -#define RFCfgReg 0x26 //配置接收器增益 -#define GsNReg 0x27 //选择天线驱动器管脚(TX1和TX2)的调制电导 -#define CWGsCfgReg 0x28 //选择天线驱动器管脚的调制电导 -#define ModGsCfgReg 0x29 //选择天线驱动器管脚的调制电导 -#define TModeReg 0x2A //定义内部定时器的设置 -#define TPrescalerReg 0x2B //定义内部定时器的设置 -#define TReloadRegH 0x2C //描述16位长的定时器重装值 -#define TReloadRegL 0x2D //描述16位长的定时器重装值 +#define RFU20 0x20 //reserve +#define CRCResultRegM 0x21 //Show the actual MSB value of CRC computing +#define CRCResultRegL 0x22 //Show the actual LSB value of CRC computing +#define RFU23 0x23 //reserve +#define ModWidthReg 0x24 //settingsToControlModWidth +#define RFU25 0x25 //reserve +#define RFCfgReg 0x26 //Configuration receiver gain +#define GsNReg 0x27 //selectTheModulationConductivityOfTheAntennaDriveTube (tX1AndTX2) +#define CWGsCfgReg 0x28 //Select the modulation of the antenna drive tube foot +#define ModGsCfgReg 0x29 //Select the modulation of the antenna drive tube foot +#define TModeReg 0x2A //Define the settings of internal timers +#define TPrescalerReg 0x2B //Define the settings of internal timers +#define TReloadRegH 0x2C //Describe the 16 -bit timer heavy loading value +#define TReloadRegL 0x2D //Describe the 16 -bit timer heavy loading value #define TCounterValueRegH 0x2E -#define TCounterValueRegL 0x2F //显示16位长的实际定时器值 +#define TCounterValueRegL 0x2F //Show the actual timer value of the 16 -bit length // PAGE 3 -#define RFU30 0x30 //保留 -#define TestSel1Reg 0x31 //常用测试信号配置 -#define TestSel2Reg 0x32 //常用测试信号配置和PRBS控制 -#define TestPinEnReg 0x33 //D1-D7输出驱动器的使能管脚(仅用于串行接口) -#define TestPinValueReg 0x34 //定义D1-D7用作I/O总线时的值 -#define TestBusReg 0x35 //显示内部测试总线的状态 -#define AutoTestReg 0x36 //控制数字自测试 -#define VersionReg 0x37 //显示版本 -#define AnalogTestReg 0x38 //控制管脚AUX1和AUX2 -#define TestDAC1Reg 0x39 //定义TestDAC1的测试值 -#define TestDAC2Reg 0x3A //定义TestDAC2的测试值 -#define TestADCReg 0x3B //显示ADCI和Q通道的实际值 -#define RFU3C 0x3C //保留 -#define RFU3D 0x3D //保留 -#define RFU3E 0x3E //保留 -#define RFU3F 0x3F //保留 +#define RFU30 0x30 //reserve +#define TestSel1Reg 0x31 //Common test signal configuration +#define TestSel2Reg 0x32 //Common test signal configuration and PRBS control +#define TestPinEnReg 0x33 //d1D7OutputDrivesEnablePipeTube (onlyForSerialInterface) +#define TestPinValueReg 0x34 //defineTheValueOfTheD1D7AsTheI/oBus +#define TestBusReg 0x35 //Show the status of the internal test bus +#define AutoTestReg 0x36 //Control the number self -test +#define VersionReg 0x37 //Display version +#define AnalogTestReg 0x38 //controlPipeFootAuX1AndAuX2 +#define TestDAC1Reg 0x39 //defineTheTestValueOfTestDaC1 +#define TestDAC2Reg 0x3A //defineTheTestValueOfTestDaC2 +#define TestADCReg 0x3B //Display the actual values of ADCI and Q channels +#define RFU3C 0x3C //reserve +#define RFU3D 0x3D //reserve +#define RFU3E 0x3E //reserve +#define RFU3F 0x3F //reserve ///////////////////////////////////////////////////////////////////// -// 函数和类型定义 +// functionAndTypeDefinition ///////////////////////////////////////////////////////////////////// -// 高效率转换4字节数据为U32类型的数值 +// highEfficiencyConversion4ByteDataIsTheValueOfU32Type #define BYTES4_TO_U32(src) (__REV(*((uint32_t*)src))) -// 获得静态字节数组的比特长度 +// getTheBitLengthOfTheStaticByteArray #define U8ARR_BIT_LEN(src) ((sizeof(src)) * (8)) -// 标签信息的基本结构封装 +// basicStructurePackagingOfLabelInformation typedef struct { - uint8_t uid[10]; // 卡号的字节数组,最长10字节 - uint8_t uid_len; // 卡号的长度 - uint8_t cascade; // 防冲撞等级 值为1表示 4byte,2表示7byte,3表示10byte - uint8_t sak; // 选择确认 - uint8_t atqa[2]; // 请求应答 + uint8_t uid[10]; // theByteArrayOfTheCardNumber,TheLongest10Byte + uint8_t uid_len; // theLengthOfTheCardNumber + uint8_t cascade; // theAntiCollisionLevelValueIs1Representation 4Byte,2Represents7Byte,3Means10Byte + uint8_t sak; // chooseToConfirm + uint8_t atqa[2]; // requestResponse } picc_14a_tag_t; #ifdef __cplusplus @@ -206,13 +206,13 @@ uint8_t pcd_14a_reader_atqa_request(uint8_t *resp, uint8_t *resp_par, uint16_t r // M1 tag operation uint8_t pcd_14a_reader_mf1_auth(picc_14a_tag_t *tag, uint8_t type, uint8_t addr, uint8_t *pKey); void pcd_14a_reader_mf1_unauth(void); -// 写卡操作 +// writeCardOperation uint8_t pcd_14a_reader_mf1_write_by_cmd(uint8_t cmd, uint8_t addr, uint8_t *p); uint8_t pcd_14a_reader_mf1_write(uint8_t addr, uint8_t *pData); -// 读卡操作 +// cardReadingOperation uint8_t pcd_14a_reader_mf1_read_by_cmd(uint8_t cmd, uint8_t addr, uint8_t *p); uint8_t pcd_14a_reader_mf1_read(uint8_t addr, uint8_t *pData); -// 休眠卡操作 +// Formation card operation uint8_t pcd_14a_reader_halt_tag(void); void pcd_14a_reader_fast_halt_tag(void); diff --git a/firmware/application/src/rfid/reader/lf/data_utils.c b/firmware/application/src/rfid/reader/lf/data_utils.c index 927c162..72e4ded 100644 --- a/firmware/application/src/rfid/reader/lf/data_utils.c +++ b/firmware/application/src/rfid/reader/lf/data_utils.c @@ -1,7 +1,7 @@ #include "data_utils.h" #include -//向raw写入2bit数据,datab存0bit,dataa存1bit +//Write2BitDataToRaw,DataBStores0Bit,DataaStores1Bit void writebit(uint8_t *dataa, uint8_t *datab, uint8_t pos, uint8_t adata) { if (adata >= 4) { return; @@ -14,7 +14,7 @@ void writebit(uint8_t *dataa, uint8_t *datab, uint8_t pos, uint8_t adata) { getbit(adata, 0) ? setbit(datab[aimbyte], aimbit) : clrbit(datab[aimbyte], aimbit); } -//输出raw的2bit组合数据 +//OutputRaw's2BitCombinationData uint8_t readbit(uint8_t *dataa, uint8_t *datab, uint8_t pos) { static uint8_t aimbyte = 0; static uint8_t aimbit = 0; @@ -25,7 +25,7 @@ uint8_t readbit(uint8_t *dataa, uint8_t *datab, uint8_t pos) { (getbit(datab[aimbyte], aimbit))); } -//向raw写入2bit数据(大端方法,每个byte的第8位写数据的第1位),datab存0bit,dataa存1bit +// Write 2bit data to RAW (large -end method, 1st place for each Byte's 8th position), datab deposit 0bit, dataa save 1bit 1bit void writebit_msb(uint8_t *dataa, uint8_t *datab, uint8_t pos, uint8_t adata) { if (adata >= 4) { return; @@ -38,7 +38,7 @@ void writebit_msb(uint8_t *dataa, uint8_t *datab, uint8_t pos, uint8_t adata) { getbit(adata, 0) ? setbit(datab[aimbyte], aimbit) : clrbit(datab[aimbyte], aimbit); } -//输出raw的2bit组合数据(大端方法,每个byte的第8位读数据的第1位) +// Output RAW's 2bit combination data (large -end method, No. 1 of the 8th reading data of each byte) uint8_t readbit_msb(uint8_t *dataa, uint8_t *datab, uint8_t pos) { static uint8_t aimbyte = 0; static uint8_t aimbit = 0; @@ -49,7 +49,7 @@ uint8_t readbit_msb(uint8_t *dataa, uint8_t *datab, uint8_t pos) { (getbit(datab[aimbyte], aimbit))); } -//高低位翻转 +//High and low flip uint8_t invert_num(uint8_t num) { uint8_t temp = 0, sh = 0xf; uint8_t i = 0; @@ -63,7 +63,7 @@ uint8_t invert_num(uint8_t num) { return num; } -//原始数据转换为2倍长度的hex字符数组 +//The original data is converted to the HEX character array with a 2x length void ByteToHexStr(uint8_t *source, uint8_t *dest, uint8_t sourceLen) { uint8_t i, highByte, lowByte; diff --git a/firmware/application/src/rfid/reader/lf/lf_125khz_radio.c b/firmware/application/src/rfid/reader/lf/lf_125khz_radio.c index da9da85..c4e781d 100644 --- a/firmware/application/src/rfid/reader/lf/lf_125khz_radio.c +++ b/firmware/application/src/rfid/reader/lf/lf_125khz_radio.c @@ -14,7 +14,7 @@ nrf_drv_pwm_t m_pwm = NRF_DRV_PWM_INSTANCE(0); nrf_ppi_channel_t m_ppi_channel1; nrfx_timer_t m_timer_lf_reader = NRFX_TIMER_INSTANCE(2); -// 目前只用到通道1,因此只配置通道一即可 +// At present, only channel 1 is used, so only one channel can be configured nrf_pwm_values_individual_t m_lf_125khz_pwm_seq_val[] = { { 2, 0, 0, 0}, }; nrf_pwm_sequence_t const m_lf_125khz_pwm_seq_obj = { .values.p_individual = m_lf_125khz_pwm_seq_val, @@ -25,14 +25,14 @@ nrf_pwm_sequence_t const m_lf_125khz_pwm_seq_obj = { static bool m_is_125khz_radio_init = false; -/**@brief 低频读卡下降沿触发采集事件 +/**@brief Low -frequency reading card decrease along the trigger collection event */ static void lf_125khz_gpio_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { - // 直接转交事件过去 + // Directly transfer to the event GPIO_INT0_IRQHandler(); } -// 初始化125khz信号pwm调制 +// Initialize 125kHz signal PWM modulation void lf_125khz_radio_init(void) { nrfx_err_t err_code; @@ -41,7 +41,7 @@ void lf_125khz_radio_init(void) { // ****************************************************************** - // 配置pwm + // Configure pwm nrfx_pwm_config_t config = NRFX_PWM_DEFAULT_CONFIG; config.output_pins[0] = LF_ANT_DRIVER | NRF_DRV_PWM_PIN_INVERTED; for (uint8_t i = 1; i < NRF_PWM_CHANNEL_COUNT; i++) { @@ -54,26 +54,26 @@ void lf_125khz_radio_init(void) { config.load_mode = (nrf_pwm_dec_load_t)NRF_PWM_LOAD_INDIVIDUAL; config.step_mode = (nrf_pwm_dec_step_t)NRF_PWM_STEP_AUTO; - // 初始化pwm + // Initialization PWM err_code = nrfx_pwm_init(&m_pwm, &config, NULL); APP_ERROR_CHECK(err_code); // ****************************************************************** - // 定义定时器配置结构体,并使用默认配置参数初始化结构体 + // Define the timer configuration structure, and use the default configuration parameter to initialize the structure nrfx_timer_config_t timer_cfg = NRFX_TIMER_DEFAULT_CONFIG; - timer_cfg.mode = NRF_TIMER_MODE_COUNTER; // 使用计数器模式 + timer_cfg.mode = NRF_TIMER_MODE_COUNTER; // Use the counter mode - // 初始化定时器 + // Initialized timer err_code = nrfx_timer_init(&m_timer_lf_reader, &timer_cfg, NULL); APP_ERROR_CHECK(err_code); - // 使能定时器 + // Enable timer nrfx_timer_enable(&m_timer_lf_reader); // ****************************************************************** - // 初始化ppi + // Initialized PPI err_code = nrf_drv_ppi_init(); APP_ERROR_CHECK(err_code); @@ -89,7 +89,7 @@ void lf_125khz_radio_init(void) { // ****************************************************************** - // LF采集下降沿中断,默认将gpio下拉,触发方式为下降沿触发 + // The LF collection decline is interrupted, and the GPIO is pulled down by default. The trigger method is triggering nrf_drv_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_LOTOHI(false); err_code = nrf_drv_gpiote_in_init(LF_OA_OUT, &in_config, lf_125khz_gpio_handler); APP_ERROR_CHECK(err_code); @@ -99,7 +99,7 @@ void lf_125khz_radio_init(void) { } } -// 反初始化 +// Anti -initialization void lf_125khz_radio_uninit(void) { if (m_is_125khz_radio_init) { m_is_125khz_radio_init = false; @@ -113,14 +113,14 @@ void lf_125khz_radio_uninit(void) { } /** - * 启动125khz广播 + * Start the 125kHz broadcast */ void start_lf_125khz_radio(void) { nrf_drv_pwm_simple_playback(&m_pwm, &m_lf_125khz_pwm_seq_obj, 1, NRF_DRV_PWM_FLAG_LOOP); } /** - * 关闭125khz射频广播 + * Close 125kHz RF broadcast */ void stop_lf_125khz_radio(void) { nrf_drv_pwm_stop(&m_pwm, true); diff --git a/firmware/application/src/rfid/reader/lf/lf_em410x_data.c b/firmware/application/src/rfid/reader/lf/lf_em410x_data.c index 792a829..8dce11c 100644 --- a/firmware/application/src/rfid/reader/lf/lf_em410x_data.c +++ b/firmware/application/src/rfid/reader/lf/lf_em410x_data.c @@ -16,35 +16,35 @@ NRF_LOG_MODULE_REGISTER(); static RAWBUF_TYPE_S carddata; -static volatile uint8_t dataindex = 0; //记录变化沿次数 -uint8_t cardbufbyte[cardbufbytesize]; //卡片数据 +static volatile uint8_t dataindex = 0; //Record changes along the number of times +uint8_t cardbufbyte[cardbufbytesize]; //Card data #ifdef debug410x uint8_t datatest[256] = { 0x00 }; #endif -//处理卡片数据,输入raw buffer的起始位置2的位置(2111。。。。) -//处理完卡片数据放cardbuf,返回5正常解析 -//Pdata为rawbuffer +//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 mcst(RAWBUF_TYPE_S *Pdata) { - uint8_t sync = 1; //当前间隔处理完后,是否在判定线上 - uint8_t cardindex = 0; //记录变化次数 + 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 < rawbufsize * 8; i++) { uint8_t thisbit = readbit(Pdata->rawa, Pdata->rawb, i); switch (sync) { - case 1: //同步状态 + case 1: //Synchronous state switch (thisbit) { - case 0: //同步状态的1T,添加1位0,依然同步 + case 0: //TheSynchronousState1T,Add1Digit0,StillSynchronize writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 0); cardindex++; break; - case 1: //同步状态的1.5T,添加1位1,切换到非同步状态 + 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: //同步状态的2T,添加2位10,依然同步 + case 2: //Synchronous2T,Add2Digits10,StillSynchronize writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 1); cardindex++; writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 0); @@ -54,20 +54,20 @@ uint8_t mcst(RAWBUF_TYPE_S *Pdata) { return 0; } break; - case 0: //非同步状态 + case 0: //Non -synchronous state switch (thisbit) { - case 0: //非同步状态的1T,添加1位1,依然非同步 + case 0: //1TInNonSynchronousState,Add1Digit1,StillNonSynchronous writebit(Pdata->hexbuf, Pdata->hexbuf, cardindex, 1); cardindex++; break; - case 1: //非同步状态的1.5T,添加2位10,切换到同步状态 + 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: //非同步状态的2T,不可能出现的情况,报错。 + case 2: //The2TOfTheNonSynchronousState,ItIsImpossibleToOccur,ReportAnError return 0; default: return 0; @@ -80,60 +80,60 @@ uint8_t mcst(RAWBUF_TYPE_S *Pdata) { return 1; } -//处理卡片,寻找校验位并且判断是否正常 +//Process card, find school inspection and determine whether it is normal uint8_t em410x_decoder(uint8_t *pData, uint8_t size, uint8_t *pOut) { if (size != 8) { //NRF_LOG_INFO("size err %d!\n", size); return 0; } - // NRF_LOG_INFO("开始解码数据!\n"); + // Nrf_log_info ("Start the decoding data! \ N"); - // 迭代数据的次数,每次 +5 个bit + // The number of iterative data, each time +5 Bit uint8_t iteration = 0; - // 当前合并的数据的存放位置 + // The current merged data storage location uint8_t merge_pos = 0; - // 快速校验头部 + // Quickly check the head uint8_t head_check = 1; for (int i = 0; i < 9; i++) { head_check &= getbit(pData[i / 8], i % 8); } - // 一起快速校验尾部 + // Quickly school to test the tail if ((!head_check) || getbit(pData[7], 7)) { //NRF_LOG_INFO("head or tail err!\n"); return 0; } - // NRF_LOG_INFO("头部与尾部检测通过!\n"); + // Nrf_log_info ("Terrate head and tail detection pass! \ N"); - // 先校验X轴的数据 - // X轴校验,每隔 5个bit 校验一次, - // 校验完成后保存为 半个byte + // Check the data of the X -axis first + // X -axis verification, every separate 5 BIT check once, + // After the verification is completed, it is stored to halfbyte for (int i = 9; i < size * 8 - 5; i += 5) { uint8_t count_bit_x = 0; for (int j = i; j < i + 5; j++) { - // 收集偶数据个数 + // Collect the number of puppet data if (getbit(pData[j / 8], j % 8) == 1) { count_bit_x += 1; } if (j != i + 4) { - // 合并bit数据到 uint8缓冲区中 - // 需要加上左对齐坐标,如果是高位部分 + // Merged bit data to In UINT8 buffer + // You need to add left -left coordinates, if it is a high part uint8_t first_merge_offset = (iteration % 2) ? 0 : 4; uint8_t finally_offset = first_merge_offset + ((i + 5 - 1) - j - 1); - // NRF_LOG_INFO("需要左移 %d 位。\n", finally_offset); + // Nrf_log_info ("need left move %d Bit.\ n ", finally_offset); getbit(pData[j / 8], j % 8) ? (pOut[merge_pos] |= 1 << finally_offset) : (pOut[merge_pos] &= ~(1 << finally_offset)); } - // 如果在第一行,我们还可以直接去校验 Y 轴的校验位 + // If in the first line, we can go directly to the verification Y Verification of the shaft if (iteration == 0 && j != i + 4) { uint8_t count_bit_y = 0; for (int m = j; m < j + 51; m += 5) { - // NRF_LOG_INFO("当前的m坐标是 %d, 数据是 %d\n", m, pData[m]); + // Nrf_log_info ("The current M coordinate is %d, Data is %d\n", m, pData[m]); if (getbit(pData[m / 8], m % 8) == 1) { count_bit_y += 1; } @@ -142,15 +142,15 @@ uint8_t em410x_decoder(uint8_t *pData, uint8_t size, uint8_t *pOut) { //NRF_LOG_INFO("bit even parity err at Y-axis from %d to %d!\n", j, j + 51); return 0; } - } // 否则的话,就直接进入下一轮校验 + } // Otherwise, go directly to the next round of verification } - // 经过一轮校验后,下次就不要校验 Y 轴 + // After a round of verification, don't check it next time Y axis iteration += 1; - // 如果取余数不为0 - // 说明进入了新的数据处理循环 - // 我们需要递增存放合并字节需要的下标 + // If the remaining number is not 0 + // Explain that the new data processing cycle has entered + // We need to increase the bidding required for merging bytes if (!(iteration % 2)) { merge_pos += 1; // NRF_LOG_INFO("\n"); @@ -165,64 +165,64 @@ uint8_t em410x_decoder(uint8_t *pData, uint8_t size, uint8_t *pOut) { } /** -* 对EM410x卡号进行编码 -* @param: pData 卡号 - ID,固定5个长度的byte -* @param: pOut 输出缓冲区,固定8个长度的byte +* Code the EM410X card number +* @param: pData card number - ID, fixed 5 length byte +* @param: pOut Output buffer, fixed 8 -length byte */ void em410x_encoder(uint8_t *pData, uint8_t *pOut) { //#define EM410X_Encoder_NRF_LOG_INFO - // 为了节省代码空间,我们可以在规律内限制死数据长度 - // 也就是说,总体循环次数不可以超过 0 - 127 个bit - // 当然,对于正经的EM410来说,这个循环的次数足够了 + // In order to save code space, we can limit the length of the dead data in the law + // In other words, the overall loop cannot exceed more 0 - 127 Bit + // Of course, for the serious EM410, the number of this cycle is enough int8_t i, j; - // 某些数据其实可以通过时间换空间 - // 但是这点空间太小了,还不如留着换时间 - // 所以就不要改了。 + // Some data can actually change the space through time + // But this space is too small, it is better to keep the time to change time + // So don't change it. uint8_t pos, bit, count1; - pOut[0] = 0xFF; // 前导码有9个1,所以我们先给第一个字节限定为 11111111 - pOut[1] = 0x80; // 没啥好说的,第二个Byte的msb也要是一个 1 ,这样就凑够了 1 * 9 的前导码 + pOut[0] = 0xFF; // There are 9 1 of the front guide code, so we are limited to the first byte first as a 11111111 + pOut[1] = 0x80; // Nothing to say, the second Byte MSB is also one 1 Then it's enough 1 * 9 Code - //重置数据为空 + //Reset the data as empty for (i = 2; i < 8; i++) { pOut[i] = 0x00; } - // bit置位为9,因为有 0 - 8 总共 9 个前导码 ( 1 * 9 ) + // Bit is 9, because there is 0 - 8 In total 9 Ahead ( 1 * 9 ) pos = 9; - // 重置bit计数 + // Reset the BIT count count1 = 0; - // X轴 迭代 5个Byte的卡号,拼凑bit到缓冲区中并且计算奇偶校验位 + // X -aid iteration 5 Byte's card number, put together Bit to the buffer and calculate the puppet school inspection for (i = 0; i < 5; i++) { - // 迭代处理每个bit + // Iteration processing each bit for (j = 7; j >= 0; j--) { - // 取出单个bit + // Take out a single BIT bit = ((pData[i] >> j) & 0x01); #ifdef EM410X_Encoder_NRF_LOG_INFO NRF_LOG_INFO("%d ", bit); #endif // EM410X_Encoder_NRF_LOG_INFO - // 原生数据放入到输出缓冲区 + // Put the native data into the output buffer pOut[pos / 8] |= (bit << (7 - pos % 8)); pos += 1; - // 统计偶校验计数 + // Statistical occasional verification calculation if (bit) { count1 += 1; } - // 奇偶校验位放入到输出缓冲区 + // Putting the inspection of the coupling school into the output buffer if (j == 4 || j == 0) { #ifdef EM410X_Encoder_NRF_LOG_INFO - NRF_LOG_INFO(" <- 比特RAW : 奇偶校验 -> %d\n", count1 % 2); + NRF_LOG_INFO(" <- Bit raw : Qi Dian verification -> %d\n", count1 % 2); #endif // EM410X_Encoder_NRF_LOG_INFO - // 不用说了,肯定是放入一个bit的奇偶校验位啊 + // Needless to say, it must be placed in a bit's strange school test. pOut[pos / 8] |= ((count1 % 2) << (7 - pos % 8)); pos += 1; count1 = 0; @@ -234,23 +234,23 @@ void em410x_encoder(uint8_t *pData, uint8_t *pOut) { NRF_LOG_INFO("\n"); #endif // EM410X_Encoder_NRF_LOG_INFO - // Y轴 迭代 5个byte的卡号,生成4个bit的奇偶校验位 + // Y axis iteration 5 BYTE card numbers, generate 4 BIT's puppet school inspection for (i = 0; i < 4; i++) { count1 = 0; for (j = 0; j < 5; j++) { - // 高位计数 + // High -level count bit = ((pData[j] >> (7 - i)) & 0x01); if (bit) { count1 += 1; } - // 低位计数 + // Low count bit = ((pData[j] >> (3 - i)) & 0x01); if (bit) { count1 += 1; } } - // Y轴计算完成,放到最终的bit输出缓冲区中 + // The y -axis calculation is completed, and placed in the final BIT output buffer pOut[pos / 8] |= ((count1 % 2) << (7 - pos % 8)); pos += 1; @@ -260,11 +260,11 @@ void em410x_encoder(uint8_t *pData, uint8_t *pOut) { } #ifdef EM410X_Encoder_NRF_LOG_INFO - NRF_LOG_INFO(" <- 奇偶校验 : 尾导码 -> 0\n\n"); + NRF_LOG_INFO(" <- Qi Dian verification : Tail code -> 0\n\n"); #endif // EM410X_Encoder_NRF_LOG_INFO } -//读卡函数,需要不停调用,返回0为没读到卡,1为读到了 +// Reading the card function, you need to stop calling, return 0 to read the card, 1 is to read uint8_t em410x_acquire(void) { if (dataindex >= rawbufsize * 8) { #ifdef debug410x @@ -279,7 +279,7 @@ uint8_t em410x_acquire(void) { NRF_LOG_INFO("///time data\r\n"); } #endif - //寻找目标0 1111 1111 + //Looking for goals 0 1111 1111 carddata.startbit = 255; for (int i = 0; i < (rawbufsize * 8) - 8; i++) { if (readbit(carddata.rawa, carddata.rawb, i) == 1) { @@ -295,12 +295,12 @@ uint8_t em410x_acquire(void) { } } } - // 如果找到了合适的开头,进行处理 + // If you find the right beginning to deal with it if (carddata.startbit != 255 && carddata.startbit < (rawbufsize * 8) - 64) { - //保证卡片数据可以完整解析 + //Guarantee card data can be fully analyzed //NRF_LOG_INFO("do mac,start: %d\r\n",startbit); if (mcst(&carddata) == 1) { - //卡片正常解析 + //Card normal analysis #ifdef debug410x { for (int i = 0; i < cardbufsize; i++) { @@ -310,7 +310,7 @@ uint8_t em410x_acquire(void) { } #endif if (em410x_decoder(carddata.hexbuf, cardbufsize, cardbufbyte)) { - //卡片数据检查通过 + //Card data check passes #ifdef debug410x for (int i = 0; i < 5; i++) { NRF_LOG_INFO("%02X", (int)cardbufbyte[i]); @@ -322,13 +322,13 @@ uint8_t em410x_acquire(void) { } } } - // 启动新的一个周期 + // Start a new cycle dataindex = 0; } return 0; } -//gpio中断回调函数,用于检测下降沿 +//GPIO interrupt recovery function is used to detect the descending edge void GPIO_INT0_callback(void) { static uint32_t thistimelen = 0; thistimelen = get_lf_counter_value(); @@ -359,26 +359,26 @@ void GPIO_INT0_callback(void) { } while (counter++ > 1000); } -//启动定时器和初始化相关外设,启动低频读卡 +//Start the timer and initialize related peripherals, start a low -frequency card reading void init_em410x_hw(void) { - //注册读卡器io中断回调 + //Registered card reader IO interrupt recovery register_rio_callback(GPIO_INT0_callback); } /** -* 在指定的超时内读取EM410X卡的卡号 +* Read the card number of the EM410X card within the specified timeout */ uint8_t em410x_read(uint8_t *uid, uint32_t timeout_ms) { uint8_t ret = 0; - init_em410x_hw(); // 初始化下降沿采样回调函数 - start_lf_125khz_radio(); // 启动125khz调制 + init_em410x_hw(); // Initialized decline along the sampling recovery function + start_lf_125khz_radio(); // Start 125kHz modulation - // 在超时中读卡 + // Reading the card during timeout autotimer *p_at = bsp_obtain_timer(0); // NO_TIMEOUT_1MS(p_at, timeout_ms) while (NO_TIMEOUT_1MS(p_at, timeout_ms)) { - //执行读卡,读到就退出 + //Execute the card, exit if you read it if (em410x_acquire()) { stop_lf_125khz_radio(); uid[0] = cardbufbyte[0]; @@ -391,11 +391,11 @@ uint8_t em410x_read(uint8_t *uid, uint32_t timeout_ms) { } } - if (ret != 1) { // 如果没有搜索到卡,说明超时了,我们这里要手动结束读卡器 + if (ret != 1) { // If the card is not searched, it means that the timeout is over. We must manually end the card reader here. stop_lf_125khz_radio(); } - dataindex = 0; // 结束后谨记重置采集的数据的索引 + dataindex = 0; // After the end, keep in mind the index of resetting data bsp_return_timer(p_at); p_at = NULL; diff --git a/firmware/application/src/rfid/reader/lf/lf_em410x_data.h b/firmware/application/src/rfid/reader/lf/lf_em410x_data.h index 1bdf708..36b6abf 100644 --- a/firmware/application/src/rfid/reader/lf/lf_em410x_data.h +++ b/firmware/application/src/rfid/reader/lf/lf_em410x_data.h @@ -10,19 +10,19 @@ extern "C" { #endif -#define cardbufbytesize 5 // 卡片字节buffer大小 +#define cardbufbytesize 5 // Card byte buffer size -#define rawbufsize 24 // 最大记录buffer -#define cardbufsize 8 // 卡片大小 +#define rawbufsize 24 // The maximum record buffer +#define cardbufsize 8 // Card size typedef struct { - uint8_t rawa[rawbufsize]; // 记录变化沿之间的时间差 - uint8_t rawb[rawbufsize]; // 记录变化沿之间的时间差 - uint8_t hexbuf[cardbufsize]; // 解析后的卡数据 + uint8_t rawa[rawbufsize]; // The time difference between recording changes + uint8_t rawb[rawbufsize]; // The time difference between recording changes + uint8_t hexbuf[cardbufsize]; // Patriotic card data uint8_t startbit; } RAWBUF_TYPE_S; -//卡片数据 +//Card data extern uint8_t cardbufbyte[cardbufbytesize]; diff --git a/firmware/application/src/rfid/reader/lf/lf_reader_data.c b/firmware/application/src/rfid/reader/lf/lf_reader_data.c index d524ef9..99449f8 100644 --- a/firmware/application/src/rfid/reader/lf/lf_reader_data.c +++ b/firmware/application/src/rfid/reader/lf/lf_reader_data.c @@ -2,18 +2,18 @@ #include "nrf_drv_timer.h" -RIO_CALLBACK_S RIO_callback; // 创建实例 -uint8_t RIO_callback_state; // 记录状态 +RIO_CALLBACK_S RIO_callback; // Create instance +uint8_t RIO_callback_state; // Record status -void register_rio_callback(RIO_CALLBACK_S P) { // 注册回调函数 +void register_rio_callback(RIO_CALLBACK_S P) { // Register recovery function RIO_callback = P; RIO_callback_state = 1; } void blank_function(void) { - // 这就是一个空的函数, - // 啥都不用做 + // This is an empty function, + // Nothing to do } void unregister_rio_callback(void) { @@ -21,7 +21,7 @@ void unregister_rio_callback(void) { RIO_callback = blank_function; } -// GPIO中断,就是RIO引脚 +// GPIO interrupt is the RIO pin void GPIO_INT0_IRQHandler(void) { if (RIO_callback_state == 1) { RIO_callback(); @@ -31,12 +31,12 @@ void GPIO_INT0_IRQHandler(void) { extern nrfx_timer_t m_timer_lf_reader; -// 获得计数器的值 +// Get the value of the counter uint32_t get_lf_counter_value(void) { return nrfx_timer_capture(&m_timer_lf_reader, NRF_TIMER_CC_CHANNEL1); } -// 清除计数器的值 +// Clear the value of the counter void clear_lf_counter_value(void) { nrfx_timer_clear(&m_timer_lf_reader); } diff --git a/firmware/application/src/rfid/reader/lf/lf_reader_data.h b/firmware/application/src/rfid/reader/lf/lf_reader_data.h index 941874c..f1f33b8 100644 --- a/firmware/application/src/rfid/reader/lf/lf_reader_data.h +++ b/firmware/application/src/rfid/reader/lf/lf_reader_data.h @@ -9,14 +9,14 @@ extern "C" { #endif -typedef void(*RIO_CALLBACK_S)(void); // 调用函数格式 +typedef void(*RIO_CALLBACK_S)(void); // Call the function format void register_rio_callback(RIO_CALLBACK_S P); void blank_function(void); void unregister_rio_callback(void); void GPIO_INT0_IRQHandler(void); -// 计数器操作 +// Counter uint32_t get_lf_counter_value(void); void clear_lf_counter_value(void); 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 7c3e1f3..a4f0b90 100644 --- a/firmware/application/src/rfid/reader/lf/lf_reader_main.c +++ b/firmware/application/src/rfid/reader/lf/lf_reader_main.c @@ -11,12 +11,12 @@ NRF_LOG_MODULE_REGISTER(); -// 默认寻卡有 N 毫秒超时 +// The default card search is available N Millisecond timeout uint32_t g_timeout_readem_ms = 500; /** -* 搜索EM410X标签 +* Search EM410X tag */ uint8_t PcdScanEM410X(uint8_t *uid) { uint8_t ret = EM410X_TAG_NO_FOUND; @@ -28,16 +28,16 @@ uint8_t PcdScanEM410X(uint8_t *uid) { } /** -* 检测当前的场内是否有指定的UID的标签 +* Check whether there is a specified UID tag on the current field */ uint8_t check_write_ok(uint8_t *uid, uint8_t *newuid, uint8_t on_uid_diff_return) { - // 写卡完成后,我们需要进行一次回读, - // 如果回读的数据不正确,说明写入失败 + // After the card is written, we need to read it once, + // If the data I read is incorrect, it means that the writing fails if (PcdScanEM410X(newuid) != LF_TAG_OK) { return EM410X_TAG_NO_FOUND; } - // 如果回读到的卡号一样 - // 说明写入成功了(或许吧) + // If you read the card number the same + // Explanation is successful (maybe) if ( uid[0] == newuid[0] && uid[1] == newuid[1] && @@ -46,13 +46,13 @@ uint8_t check_write_ok(uint8_t *uid, uint8_t *newuid, uint8_t on_uid_diff_return uid[4] == newuid[4]) { return LF_TAG_OK; } - // 如果发现卡,但是卡号不对, - // 那我们就将传入的异常值返回 + // If you find the card, the card number is wrong, + // Then we will return the abnormal value of the inlet return on_uid_diff_return; } /** -* 写T55XX标签 +* Write T55XX tag */ uint8_t PcdWriteT55XX(uint8_t *uid, uint8_t *newkey, uint8_t *old_keys, uint8_t old_key_count) { uint8_t datas[8] = { 255 }; @@ -61,14 +61,14 @@ uint8_t PcdWriteT55XX(uint8_t *uid, uint8_t *newkey, uint8_t *old_keys, uint8_t init_t55xx_hw(); start_lf_125khz_radio(); - bsp_delay_ms(1); // 启动场后延迟一段时间 + bsp_delay_ms(1); // Delays for a while after starting the field - // keys 至少需要两个,一个newkey,一个oldkey - // 一个 key 的长度是 4 个字节 + // keys Need at least two, one newkey, one Oldkey + // one key The length is 4 Byte // uid newkey oldkeys * n - // 迭代传输进来的密钥, - // 进行T55XX标签重置 + // The key transmitted in iterative, + // Reset T55XX tags // printf("The old keys count: %d\r\n", old_key_count); for (i = 0; i < old_key_count; i++) { T55xx_Reset_Passwd(old_keys + (i * 4), newkey); @@ -81,14 +81,14 @@ uint8_t PcdWriteT55XX(uint8_t *uid, uint8_t *newkey, uint8_t *old_keys, uint8_t );*/ } - // 为了避免遇到特殊的控制区的标签, - // 我们这里用新密钥来重置一下控制区 + // In order to avoid the labels of a special control area, + // We use the new key here to reset the control area T55xx_Reset_Passwd(newkey, newkey); - // 编码410x的数据为block数据,为写卡做准备 + // The data encoded 410X is the block data to prepare for the card writing em410x_encoder(uid, datas); - // 密钥重置完成后,进行写卡操作 + // After the key is reset, perform the card writing operation /* printf("newkey is: %02x%02x%02x%02x\r\n", newkey[0], @@ -101,13 +101,13 @@ uint8_t PcdWriteT55XX(uint8_t *uid, uint8_t *newkey, uint8_t *old_keys, uint8_t stop_lf_125khz_radio(); - // 回读验证并且返回写卡结果 - // 此处不回读,由上位机校验 + // Read the verification and return the results of the card writing + // Do not read it here, you can check it by the upper machine return LF_TAG_OK; } /** -* 设置EM卡的寻卡超时的时间值 +* Set the time value of the card search timeout of the EM card */ void SetEMScanTagTimeout(uint32_t ms) { g_timeout_readem_ms = ms; diff --git a/firmware/application/src/rfid/reader/lf/lf_t55xx_data.c b/firmware/application/src/rfid/reader/lf/lf_t55xx_data.c index 654aa43..1af9407 100644 --- a/firmware/application/src/rfid/reader/lf/lf_t55xx_data.c +++ b/firmware/application/src/rfid/reader/lf/lf_t55xx_data.c @@ -20,7 +20,7 @@ NRF_LOG_MODULE_REGISTER(); /* -小机器写卡: +Small machine writing card: 01 00000000000001000010000000010000 0 000 01 1 00010100010010010000110110010010 000 00000000000000000000000000000 000 011 @@ -34,30 +34,30 @@ NRF_LOG_MODULE_REGISTER(); | 70bit Password write found | |--------------------------------------------------------------------------| |OP|PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP|L|DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD|AAA| -|10|01010001001001000011011001001000|0|01010001001001000011011001001000|111| 0区 7块 用当前密码写当前密码(密码) -|10|01010001001001000011011001001000|0|01010001001001000111011001001000|111| 0区 7块 用当前密码写当前密码(密码) -|10|01010001001001000011011001001000|0|00000000000101001000000001010000|000| 0区 0块 用当前密码写00148050(控制区) -|10|01010001001001000011011001001000|0|11111111101001010010000000000100|001| 0区 1块 用当前密码写FFA52004(数据) -|11|01010001001001000011011001001000|0|11111111101001010010000000000100|001| 1区 1块 用当前密码写FFA52004(数据) -|10|01010001001001000011011001001000|0|10100101011100011001011101101010|010| 0区 2块 用当前密码写A571976A(数据) -|11|01010001001001000011011001001000|0|10100101011100011001011101101010|010| 1区 2块 用当前密码写A571976A(数据) -|11|01010001001001000011011001001000|0|01100000000000000000100000000000|011| 1区 3块 用当前密码写60000800(射频参数) +|10|01010001001001000011011001001000|0|01010001001001000011011001001000|111| Zone 0 7 blocks to write the current password (password) +|10|01010001001001000011011001001000|0|01010001001001000111011001001000|111| Zone 0 7 blocks to write the current password (password) +|10|01010001001001000011011001001000|0|00000000000101001000000001010000|000| Zone 0 0 blocks are written in the current password00148050 (control zone) +|10|01010001001001000011011001001000|0|11111111101001010010000000000100|001| Zone 0 1 block is written in the current passwordFFA52004 (data) +|11|01010001001001000011011001001000|0|11111111101001010010000000000100|001| zone 1 1 block is written in the current passwordFFA52004 (data) +|10|01010001001001000011011001001000|0|10100101011100011001011101101010|010| Zone 0 2 are written in the current passwordA571976A (data) +|11|01010001001001000011011001001000|0|10100101011100011001011101101010|010| zone 1 2 are written in the current passwordA571976A (data) +|11|01010001001001000011011001001000|0|01100000000000000000100000000000|011| zone 1 3 blocks are written in the current password60000800 (radio frequency parameter) |--------------------------------------------------------------------------| RESET Pack received |-----------------------------------------| | 38bit regular write found | |OP|L|DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD|AAA| -|10|0|00000000000101001000000001000000|000|0区 0块 写00148050(控制区) -|10|0|11111111101001010010000000000100|001|0区 1块 写FFA52004(数据) -|10|0|10100101011100011001011101101010|010|0区 2块 写A571976A(数据) +| 10 | 0 | 00000000000101001000000000000 | 000 | 0 area 0 block writing00148050 (control zone) +| 10 | 0 | 111111111010010000000000100 | 001 | 0 area 1 pieceFFA52004 (data) +| 10 | 0 | 1010010101100011000101110101010 | 010 | 0 area 2 pieces of writingA571976A (data) |-----------------------------------------| RESET Pack received -拷贝齐写卡: +Copy Qiji Writing Card: |-----------------------------------------| |OP|L|DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD|AAA| -|10|0|00011001100100100000010000100111|111|0区 7块 写19920427(密码) -|10|0|00000000000101001000000001010000|000|0区 0块 写00148050(控制区) +| 10 | 0 | 00011001100100000000100111 | 111 | 0 area 7 pieces19920427 (password) +| 10 | 0 | 000000000001010010000000010000 | 000 | 0 area 0 block writing00148050 (control zone) |-----------------------------------------| |--------------------------------------------------------------------------| |OP|PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP|L|DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD|AAA| @@ -87,20 +87,20 @@ static struct { } t55xx_cmd; -// 空函数,t55xx写卡不需要关心读取的数据 +// Air function, T55XX writing card does not need to care about the data you read void empty_callback() { } -//启动定时器和初始化相关外设,启动低频读卡 +//Start the timer and initialize related peripherals, start a low -frequency card reading void init_t55xx_hw(void) { - //注册读卡器io中断回调 + //Registered card reader IO interrupt recovery register_rio_callback(empty_callback); } void T55xx_SendGap(unsigned int tm) { - stop_lf_125khz_radio(); // 关闭pwm输出 + stop_lf_125khz_radio(); // Turn off PWM output bsp_delay_us(tm); - start_lf_125khz_radio(); // 启动pwm输出 + start_lf_125khz_radio(); // Start PWM output } void TxBitRfid(uint8_t data) { @@ -118,36 +118,36 @@ void TxByteRfid(uint8_t data) { } } -// T55XX高精度时序控制函数 +// T55XX high -precision timing control function void T55XX_Timeslot_Callback() { T55xx_SendGap(30 * 8); // start gap - //先发送指令 + //Send instructions first TxBitRfid(t55xx_cmd.opcode >> 1); TxBitRfid(t55xx_cmd.opcode & 1); - //指令为00时不需要发送后面的东西了 + //The instruction does not need to be sent when it is 00 if (t55xx_cmd.opcode != 0) { - //指令后如果有需要才发密码 + //If you need it after the instruction, you can send the password if (t55xx_cmd.usepassword) { for (uint8_t i = 0; i < 32; i++) { TxBitRfid((t55xx_cmd.password >> (31 - i)) & 1); } } - //处理锁定位 + //Process lock position if (t55xx_cmd.lockBit == 0 || t55xx_cmd.lockBit == 1) { TxBitRfid(t55xx_cmd.lockBit & 1); } - //有需求才发数据 + //Only need to send data if there is a need if (t55xx_cmd.usedata) { for (uint8_t i = 0; i < 32; i++) { TxBitRfid((t55xx_cmd.data >> (31 - i)) & 1); } } - //处理地址位 + //Processing address if (t55xx_cmd.blokAddr != 255) { TxBitRfid(t55xx_cmd.blokAddr >> 2); TxBitRfid(t55xx_cmd.blokAddr >> 1); @@ -157,27 +157,27 @@ void T55XX_Timeslot_Callback() { } /** - * @brief 向5577写入指令,这个指令可以是读写 + * @brief Write to 5577 instructions, this instruction can be read and write * - * @param opcode 操作码,在正常操作模式下一定是1*的格式,只有重置是00 - * @param usepassword 是否使用密码,为1时指令为密码模式 - * @param password 密码,在usepasswd有效的时候发送,32个bit,从下标0开始传输 - * @param lockBit 锁定位,只有可能是1或者0,传入其他值代表不使用lock位(用于密码唤醒模式) - * @param usedata 是否使用数据区域,为1时传输数据 - * @param data 数据,32个bit,从下标0开始传输 - * @param blokAddr 块编号,3个bit 0-7块,输入255代表不使用该位(用于密码唤醒模式) + * @param opcode The operating code must be 1*in normal operation mode, only the reset is 00 + * @param usepassword Whether the password is used, the password is the password mode + * @param password Password, send it when USepAssWD is valid, 32 BIT, start transmission from the bidding 0 + * @param lockBit Locking position may only be 1 or 0. Passing other values means not using LOCK bit (for password awakening mode) + * @param usedata Whether the data area is used to transmit the data for 1 time + * @param data Data, 32 bits, transmitted from the lower bid 0 + * @param blokAddr Block number, 3 bit 0-7 yuan, input 255 means not using this bit (for password wake-up mode) */ void T55xx_Send_Cmd(uint8_t opcode, uint8_t usepassword, uint32_t password, uint8_t lockBit, uint8_t usedata, uint32_t data, uint8_t blokAddr) { - //密码读取模式, 2op(1+bck) 32pw 1(0) 3addr - //密码写入模式, 2op(1+bck) 32pw 1l 32data 3addr - //密码唤醒模式, 2op(1+0) 32pw + //Password reading mode, 2op(1+bck) 32pw 1(0) 3addr + //Password writing mode, 2op(1+bck) 32pw 1l 32data 3addr + //Password wake -up mode, 2op(1+0) 32pw - //直接读取模式, 2op(1+bck) 1(0) 3addr - //标准写入模式, 2op(1+bck) 1l 32data 3addr + //Read the mode directly, 2op(1+bck) 1(0) 3addr + //Standard writing mode, 2op(1+bck) 1l 32data 3addr - //这个不实现//标准读取页模式, 2op(1+bck) + //This will not be implemented // Standard read page mode, 2op(1+bck) - //重置模式, 2op(0+0) + //Reset mode, 2op(0+0) t55xx_cmd.opcode = opcode; t55xx_cmd.usepassword = usepassword; @@ -188,25 +188,25 @@ void T55xx_Send_Cmd(uint8_t opcode, uint8_t usepassword, uint32_t password, uint t55xx_cmd.blokAddr = blokAddr; - // 请求时序,并且等待时序操作完成 + // Request timing, and wait for the order operation to complete request_timeslot(37 * 1000, T55XX_Timeslot_Callback, true); if (opcode != 0) { - bsp_delay_ms(6); // 可能继续下次写卡,需要多等一会儿 + bsp_delay_ms(6); // Maybe continue to write a card next time, you need to wait more for a while } else { bsp_delay_ms(1); } } /** - * @brief T55xx写入EM410x数据 + * @brief T55XX Write into EM410X data * - * @param passwd 用于最后加密的密码(也是卡片当前密码)(是一个指针,4字节宽度小端byte序存储) - * @param datas em410x运算后的数据,需要调用EM410X_Encoder计算 + * @param passwd The password for the final encryption (also the current password of the card) (is a pointer, 4 -byte width small end byte sequence storage) + * @param datas After the data of EM410X, you need to call the EM410X_ENCODER calculation */ void T55xx_Write_data(uint8_t *passwd, uint8_t *datas) { uint32_t blk1data = 0, blk2data = 0, u32passwd = 0; - //提取两个block的数据和密码 + //Extract the data and passwords of two blocks for (uint8_t dataindex = 0; dataindex < 4; dataindex++) { blk1data = blk1data << 8; blk1data |= (uint8_t)datas[dataindex]; @@ -217,36 +217,36 @@ void T55xx_Write_data(uint8_t *passwd, uint8_t *datas) { blk2data = blk2data << 8; blk2data |= (uint8_t)datas[dataindex]; } - //先写入密码区 - T55xx_Send_Cmd(2, 1, u32passwd, 0, 1, u32passwd, 7); //0区 7块 用当前密码写当前密码(密码) - T55xx_Send_Cmd(2, 1, u32passwd, 0, 1, u32passwd, 7); //0区 7块 用当前密码写当前密码(密码) - //然后写入控制区 - T55xx_Send_Cmd(2, 1, u32passwd, 0, 1, 0X00148050, 0); //0区 0块 用当前密码写00148050(控制区) - //然后写入数据 - T55xx_Send_Cmd(2, 1, u32passwd, 0, 1, blk1data, 1); //0区 1块 用当前密码写blk1data(数据) - T55xx_Send_Cmd(3, 1, u32passwd, 0, 1, blk1data, 1); //1区 1块 用当前密码写blk1data(数据) - T55xx_Send_Cmd(2, 1, u32passwd, 0, 1, blk2data, 2); //0区 2块 用当前密码写blk2data(数据) - T55xx_Send_Cmd(3, 1, u32passwd, 0, 1, blk2data, 2); //1区 2块 用当前密码写blk2data(数据) - //然后写入射频参数 - // 2021-12-15 fix:写此数据会导致小卡无法重复写 - // T55xx_Send_Cmd(3, 1, u32passwd, 0, 1, 0X60000800, 3); //1区 3块 用当前密码写60000800(射频参数) + //writeToThePasswordAreaFirst + T55xx_Send_Cmd(2, 1, u32passwd, 0, 1, u32passwd, 7); // 0 area 7 blocks to write the current password (password) + T55xx_Send_Cmd(2, 1, u32passwd, 0, 1, u32passwd, 7); // 0 area 7 blocks to write the current password (password) + //Then write to the control area + T55xx_Send_Cmd(2, 1, u32passwd, 0, 1, 0X00148050, 0); // 0 area 0 blocks are written in the current password00148050 (control zone) + //Then write the data + T55xx_Send_Cmd(2, 1, u32passwd, 0, 1, blk1data, 1); // 0 area 1 block is written in the current passwordblk1data (data) + T55xx_Send_Cmd(3, 1, u32passwd, 0, 1, blk1data, 1); //zone 1 1 block is written in the current passwordblk1data (data) + T55xx_Send_Cmd(2, 1, u32passwd, 0, 1, blk2data, 2); // 0 area 2 are written in the current passwordblk2data (data) + T55xx_Send_Cmd(3, 1, u32passwd, 0, 1, blk2data, 2); //zone 1 2 are written in the current passwordblk2data (data) + //Then write in the radio frequency parameter + // 2021-12-15 FIX: Writing this data will cause the small card to be unable to write repeatedly + // T55xx_Send_Cmd(3, 1, u32passwd, 0, 1, 0X60000800, 3); //zone 1 3 blocks are written in the current password60000800 (radio frequency parameter) - //然后用无密码指令再写一遍 - T55xx_Send_Cmd(2, 0, 0, 0, 1, 0X00148050, 0); //0区 0块 写00148050(控制区) - T55xx_Send_Cmd(2, 0, 0, 0, 1, blk1data, 1); //0区 1块 写blk1data(数据) - T55xx_Send_Cmd(2, 0, 0, 0, 1, blk2data, 2); //0区 2块 写blk2data(数据) - T55xx_Send_Cmd(0, 0, 0, 0, 0, 0, 0); //重启卡片 + //Then write again with non -password instructions + T55xx_Send_Cmd(2, 0, 0, 0, 1, 0X00148050, 0); // 0 area 0 block writing00148050 (control zone) + T55xx_Send_Cmd(2, 0, 0, 0, 1, blk1data, 1); // 0 area 1 pieceblk1data (data) + T55xx_Send_Cmd(2, 0, 0, 0, 1, blk2data, 2); // 0 area 2 pieces of writingblk2data (data) + T55xx_Send_Cmd(0, 0, 0, 0, 0, 0, 0); //Restart card } /** - * @brief 重置密码函数,用于将现有已知密码的卡重置为目标密码 + * @brief Reset the password function to set the card that is used to set the existing known password into a target password * - * @param oldpasswd 卡片当前密码(是一个指针,4字节宽度小端byte序存储) - * @param newpasswd 用于最后加密的密码(是一个指针,4字节宽度小端byte序存储) + * @param oldpasswd The current password of the card (is a pointer, 4 -byte width small end byte sequential storage) + * @param newpasswd The password for the final encryption (is a pointer, 4 -byte width small end byte sequential storage) */ void T55xx_Reset_Passwd(uint8_t *oldpasswd, uint8_t *newpasswd) { uint32_t u32oldpasswd = 0, u32newpasswd = 0; - //提取两个block的数据和密码 + //Extract the data and passwords of two blocks for (uint8_t dataindex = 0; dataindex < 4; dataindex++) { u32oldpasswd = u32oldpasswd << 8; u32oldpasswd |= (uint8_t)oldpasswd[dataindex]; @@ -254,7 +254,7 @@ void T55xx_Reset_Passwd(uint8_t *oldpasswd, uint8_t *newpasswd) { u32newpasswd |= (uint8_t)newpasswd[dataindex]; } - T55xx_Send_Cmd(2, 1, u32oldpasswd, 0, 1, u32newpasswd, 7); //0区 7块 用当前密码写新密码(密码) - T55xx_Send_Cmd(2, 1, u32oldpasswd, 0, 1, u32newpasswd, 7); //0区 7块 用当前密码写新密码(密码) - T55xx_Send_Cmd(0, 0, 0, 0, 0, 0, 0); //重启卡片 + T55xx_Send_Cmd(2, 1, u32oldpasswd, 0, 1, u32newpasswd, 7); // 0 area 7 blocks to write new passwords (passwords) + T55xx_Send_Cmd(2, 1, u32oldpasswd, 0, 1, u32newpasswd, 7); // 0 area 7 blocks to write new passwords (passwords) + T55xx_Send_Cmd(0, 0, 0, 0, 0, 0, 0); //Restart card } diff --git a/firmware/application/src/rfid_main.c b/firmware/application/src/rfid_main.c index 430396e..83fb273 100644 --- a/firmware/application/src/rfid_main.c +++ b/firmware/application/src/rfid_main.c @@ -3,7 +3,7 @@ -// 设备当前处于的模式 +//The current mode of the device device_mode_t rfid_state = DEVICE_MODE_NONE; @@ -69,7 +69,7 @@ void tag_mode_enter(void) { */ void light_up_by_slot(void) { uint32_t *led_pins = hw_get_led_array(); - // 目前的亮灯逻辑并没有非常大的变动,因此我们暂时只需要亮起指定的位置的灯即可 + // The current lighting logic has not changed very much, so we only need to light up the specified lamp for the time being. uint8_t slot = tag_emulation_get_slot(); for (int i = 0; i < RGB_LIST_NUM; i++) { if (i == slot) { @@ -97,10 +97,10 @@ uint8_t get_color_by_slot(uint8_t slot) { tag_specific_type_t tag_type[2]; tag_emulation_get_specific_type_by_slot(slot, tag_type); if (tag_type[0] != TAG_TYPE_UNKNOWN && tag_type[1] != TAG_TYPE_UNKNOWN) { - return 0; // 双频卡模拟,返回R,表示双频卡 - } else if (tag_type[0] != TAG_TYPE_UNKNOWN) { // 高频模拟,返回G + return 0; // Dual -frequency card simulation, return R, indicate a dual -frequency card + } else if (tag_type[0] != TAG_TYPE_UNKNOWN) { //High -frequency simulation, return G return 1; - } else { // 低频模拟,返回B + } else { // Low -frequency simulation, return B return 2; } } diff --git a/firmware/application/src/rgb_marquee.c b/firmware/application/src/rgb_marquee.c index 49a90a5..369d842 100644 --- a/firmware/application/src/rgb_marquee.c +++ b/firmware/application/src/rgb_marquee.c @@ -13,22 +13,22 @@ NRF_LOG_MODULE_REGISTER(); -#define PWM_MAX 1000 // PWM 最大值 -#define LIGHT_LEVEL_MAX 99 // 亮度级别最大值 +#define PWM_MAX 1000 // PWM Maximum +#define LIGHT_LEVEL_MAX 99 // The maximum value of brightness level static nrf_drv_pwm_t pwm0_ins = NRF_DRV_PWM_INSTANCE(1); -nrf_pwm_values_individual_t pwm_sequ_val;//独立模式下的PWM控制4通道的占空比 -nrf_pwm_sequence_t const seq = { //配置pwm输出用的结构体 +nrf_pwm_values_individual_t pwm_sequ_val; // PWM control 4 channels in the independent mode +nrf_pwm_sequence_t const seq = { //Configure the structure of PWM output .values.p_individual = &pwm_sequ_val, .length = 4, .repeats = 0, .end_delay = 0 }; -nrf_drv_pwm_config_t pwm_config = { //PWM配置结构体 +nrf_drv_pwm_config_t pwm_config = {//PWM configuration structure .irq_priority = APP_IRQ_PRIORITY_LOWEST, .base_clock = NRF_PWM_CLK_1MHz, .count_mode = NRF_PWM_MODE_UP, .top_value = PWM_MAX, - .load_mode = NRF_PWM_LOAD_INDIVIDUAL,//4个通道用四个值 + .load_mode = NRF_PWM_LOAD_INDIVIDUAL, // 4 channels for four values .step_mode = NRF_PWM_STEP_AUTO }; static autotimer *timer; @@ -43,7 +43,7 @@ void rgb_marquee_init(void) { void rgb_marquee_stop(void) { nrfx_pwm_stop(&pwm0_ins, true); - nrfx_pwm_uninit(&pwm0_ins); //关闭pwm输出 + nrfx_pwm_uninit(&pwm0_ins);//turn off pwm output ledblink6_step = 0; ledblink1_step = 0; } @@ -54,12 +54,12 @@ void rgb_marquee_reset(void) { ledblink1_step = 0; } -// 亮度转PWM值 +// Brightness to PWM value uint16_t get_pwmduty(uint8_t light_level) { return PWM_MAX - (PWM_MAX * pow(((double)light_level / LIGHT_LEVEL_MAX), 2.2)); } -//4灯同亮度水平移动循环(不返回) +// 4 Lights and the level of brightness levels (no return) //COLOR 0-R,1-G,2-B void ledblink1(uint8_t color, uint8_t dir) { static uint8_t startled = 0; @@ -73,7 +73,7 @@ void ledblink1(uint8_t color, uint8_t dir) { return; } - //处理方向 + //Processing direction if (dir == 0) { led_pins_arr = hw_get_led_array(); } else { @@ -81,7 +81,7 @@ void ledblink1(uint8_t color, uint8_t dir) { } if (ledblink1_step == 0) { - //调整颜色 + //Adjust the color set_slot_light_color(color); pwm_sequ_val.channel_0 = 1; pwm_sequ_val.channel_1 = 1; @@ -90,7 +90,7 @@ void ledblink1(uint8_t color, uint8_t dir) { bsp_set_timer(timer, 0); ledblink1_step = 1; - // 重置USB开启通信时的灯的状态 + // Reset the state of the light when the USB is turned on to open the communication ledblink6_step = 0; } @@ -118,69 +118,69 @@ void ledblink1(uint8_t color, uint8_t dir) { } } -//4灯拖尾水平移动循环(不返回),包含尾部消失和头部缓入 -//dir 0-从1卡槽到8卡槽,1-从8卡槽到1卡槽 (方向,结束点由end参数决定) -//end 要扫描的灯数量,和方向一起决定最终动画区域 +// 4 Lights Dragon Tail horizontal movement cycle (not returning), including the disappearance of the tail and the head of the head slowly +//dir 0-from 1 card slot to 8 card slot, 1-from 8 card slot to 1 card slot (Direction, the end point is determined by the END parameter) +//end To scan the number of lamps, decide the final animation area with the direction void ledblink2(uint8_t color, uint8_t dir, uint8_t end) { uint8_t startled = 0; uint8_t setled = 0; uint8_t leds2turnon = 0; uint8_t i = 0; uint32_t *led_pins_arr; - //处理方向 + //Processing direction if (dir == 0) { led_pins_arr = hw_get_led_array(); } else { led_pins_arr = hw_get_led_reversal_array(); } - //调整颜色 + //Adjust the color set_slot_light_color(color); - pwm_sequ_val.channel_3 = 1; //最亮的 + pwm_sequ_val.channel_3 = 1; //Brightest pwm_sequ_val.channel_2 = 600; pwm_sequ_val.channel_1 = 880; - pwm_sequ_val.channel_0 = 980;//最暗的 + pwm_sequ_val.channel_0 = 980; // The darkest while (1) { - //关闭所有通道 + //Close all channels pwm_config.output_pins[0] = NRF_DRV_PWM_PIN_NOT_USED; pwm_config.output_pins[1] = NRF_DRV_PWM_PIN_NOT_USED; pwm_config.output_pins[2] = NRF_DRV_PWM_PIN_NOT_USED; pwm_config.output_pins[3] = NRF_DRV_PWM_PIN_NOT_USED; setled = startled; - if (setled < 3) { //正向期间,0,1,2的时候只能点亮前几个led - //首先确定能点亮几个灯 - leds2turnon = setled + 1; //1,2,3 - //然后设置pwm输出通道 + if (setled < 3) { //During the positive period, only the first few LEDs can be on during 0, 1, 2 + //First determine that you can light a few lights + leds2turnon = setled + 1; //1,2,3 + //Then set the PWM output channel for (i = 0; i < leds2turnon; i++) { pwm_config.output_pins[3 - i] = led_pins_arr[setled - i]; } - } else if (setled <= 7) { //正向期间,大于4小于8的时候能点亮4个led - //设置pwm输出通道 + } else if (setled <= 7) { //During the positive period, it can light up 4 LEDs when it is greater than 4 less than 4 + // Set the PWM output channel for (i = 0; i < 4; i++) { pwm_config.output_pins[3 - i] = led_pins_arr[setled]; setled--; } - } else if (setled > 7 && setled <= 10) { //正向期间,8.9.10的时候只能点亮后几个led - //首先确定能点亮几个灯 + } else if (setled > 7 && setled <= 10) { // During the positive period, only a few LEDs can be lit at 8.9.10 + //First determine that you can light a few lights leds2turnon = 11 - setled; - //然后设置pwm输出通道 + //Then set the PWM output channel for (i = 0; i < leds2turnon; i++) { pwm_config.output_pins[i] = led_pins_arr[setled - 3 + i]; } - } else { //正向期间,达到11 - //什么都不干 + } else { //During the positive period, reach 11 + // } - //处理停止条件 + //Process stop condition if (startled >= end) { - //计算需要隐藏几个灯 + //Calculation needs to hide a few lights leds2turnon = startled - end; - //把超出去的都隐藏了 + //Hidden all those who go out for (i = 0; i < leds2turnon; i++) { pwm_config.output_pins[3 - i] = NRF_DRV_PWM_PIN_NOT_USED; } - //重新设置指定位置是最亮的 + //Re -setting the specified position is the brightest if (end <= 7) { pwm_config.output_pins[3] = led_pins_arr[end]; } @@ -196,11 +196,11 @@ void ledblink2(uint8_t color, uint8_t dir, uint8_t end) { } } -//切换卡槽动画 -//led_up 要点亮的led -//color_led_up 要点亮的led的颜色 0-R,1-G,2-B -//led_down 要熄灭的led -//color_led_down 要熄灭的led的颜色 0-R,1-G,2-B +//Switch card slot animation +//led_up The LED to be lit +//color_led_up The color of the lit LED 0-R,1-G,2-B +//led_down LED to be extinguished +//color_led_down The color of the LED to be extinguished 0-R,1-G,2-B volatile bool callback_waiting = 0; static void ledblink3_pwm_callback(nrfx_pwm_evt_type_t event_type) { if (event_type == NRF_DRV_PWM_EVT_FINISHED) { @@ -208,19 +208,19 @@ static void ledblink3_pwm_callback(nrfx_pwm_evt_type_t event_type) { } } void ledblink3(uint8_t led_down, uint8_t color_led_down, uint8_t led_up, uint8_t color_led_up) { - int16_t light_level = 99; //led亮度值 + int16_t light_level = 99; //ledBrightnessValue uint32_t *led_pins = hw_get_led_array(); if (led_down >= 0 && led_down <= 7) { - //先处理要熄灭的 + //treatmentFirst pwm_config.output_pins[0] = led_pins[led_down]; pwm_config.output_pins[1] = NRF_DRV_PWM_PIN_NOT_USED; pwm_config.output_pins[2] = NRF_DRV_PWM_PIN_NOT_USED; pwm_config.output_pins[3] = NRF_DRV_PWM_PIN_NOT_USED; while (light_level >= 0) { - //处理亮度 + //processBrightness pwm_sequ_val.channel_0 = get_pwmduty(light_level); - nrfx_pwm_uninit(&pwm0_ins); //关闭pwm输出 + nrfx_pwm_uninit(&pwm0_ins); //turnOffPwmOutput if (led_up >= 0 && led_up <= 7) { nrf_gpio_pin_clear(led_pins[led_up]); @@ -231,24 +231,24 @@ void ledblink3(uint8_t led_down, uint8_t color_led_down, uint8_t led_up, uint8_t nrf_drv_pwm_init(&pwm0_ins, &pwm_config, ledblink3_pwm_callback); nrf_drv_pwm_simple_playback(&pwm0_ins, &seq, 1, NRF_DRV_PWM_FLAG_LOOP); - while (callback_waiting == 0); //等待pwm模块输出完成 + while (callback_waiting == 0); //Waiting for the output of the PWM module to complete bsp_delay_us(1234); callback_waiting = 0; light_level --; } } if (led_up >= 0 && led_up <= 7) { - //处理要点亮的 + //Treatment pwm_config.output_pins[0] = led_pins[led_up]; pwm_config.output_pins[1] = NRF_DRV_PWM_PIN_NOT_USED; pwm_config.output_pins[2] = NRF_DRV_PWM_PIN_NOT_USED; pwm_config.output_pins[3] = NRF_DRV_PWM_PIN_NOT_USED; light_level = 0; while (light_level < 99) { - //处理亮度 + //Process brightness pwm_sequ_val.channel_0 = get_pwmduty(light_level); - nrfx_pwm_uninit(&pwm0_ins); //关闭pwm输出 + nrfx_pwm_uninit(&pwm0_ins); //Turn off PWM output if (led_down >= 0 && led_down <= 7) { nrf_gpio_pin_clear(led_pins[led_down]); @@ -259,7 +259,7 @@ void ledblink3(uint8_t led_down, uint8_t color_led_down, uint8_t led_up, uint8_t nrf_drv_pwm_init(&pwm0_ins, &pwm_config, ledblink3_pwm_callback); nrf_drv_pwm_simple_playback(&pwm0_ins, &seq, 1, NRF_DRV_PWM_FLAG_LOOP); - while (callback_waiting == 0); //等待pwm模块输出完成 + while (callback_waiting == 0); //Waiting for the output of the PWM module to complete bsp_delay_us(1234); callback_waiting = 0; light_level ++; @@ -267,10 +267,10 @@ void ledblink3(uint8_t led_down, uint8_t color_led_down, uint8_t led_up, uint8_t } } -//4灯拖尾水平移动循环(不返回),不包含尾部消失但是包含头部缓入(用于弹球类型动画) -//dir 0-从1卡槽到8卡槽,1-从8卡槽到1卡槽 (方向,结束点由end参数决定) -//end 要扫描的灯数量,和方向一起决定最终动画区域 -//start_light stop_light 0-99 表示渐变亮度 +// 4 Light Tail horizontal movement cycle (not returning), does not include the disappearance of the tail, but includes the head of the head (for the type of playback type animation) +//dir 0-from 1 card slot to 8 card slot, 1-from 8 card slot to 1 card slot (Direction, the end point is determined by the END parameter) +//end To scan the number of lamps, decide the final animation area with the direction +//start_light stop_light 0-99 Indicate gradient brightness void ledblink4(uint8_t color, uint8_t dir, uint8_t end, uint8_t start_light, uint8_t stop_light) { uint8_t startled = 0; uint8_t setled = 0; @@ -278,56 +278,56 @@ void ledblink4(uint8_t color, uint8_t dir, uint8_t end, uint8_t start_light, uin uint8_t i = 0; uint32_t *led_pins_arr; volatile double light_cnd; - //处理方向 + //Processing direction if (dir == 0) { led_pins_arr = hw_get_led_array(); } else { led_pins_arr = hw_get_led_reversal_array(); } - //调整颜色 + //Adjust the color set_slot_light_color(color); while (1) { - //设置亮度 - //当前亮度系数 - //start经过end次数达到stop + //Set the brightness + // The current brightness coefficient + // Start reaches STOP through END times light_cnd = (((double)stop_light - (double)start_light) / end) * startled + start_light; - pwm_sequ_val.channel_3 = get_pwmduty((uint8_t)(0.99 * light_cnd)); //1; //最亮的 + pwm_sequ_val.channel_3 = get_pwmduty((uint8_t)(0.99 * light_cnd)); //1; //Brightest pwm_sequ_val.channel_2 = get_pwmduty((uint8_t)(0.60 * light_cnd)); //600; pwm_sequ_val.channel_1 = get_pwmduty((uint8_t)(0.30 * light_cnd)); //880; - pwm_sequ_val.channel_0 = get_pwmduty((uint8_t)(0.01 * light_cnd)); //980;//最暗的 - //关闭所有通道 + pwm_sequ_val.channel_0 = get_pwmduty((uint8_t)(0.01 * light_cnd)); // 980; // The darkest + //Close all channels pwm_config.output_pins[0] = NRF_DRV_PWM_PIN_NOT_USED; pwm_config.output_pins[1] = NRF_DRV_PWM_PIN_NOT_USED; pwm_config.output_pins[2] = NRF_DRV_PWM_PIN_NOT_USED; pwm_config.output_pins[3] = NRF_DRV_PWM_PIN_NOT_USED; setled = startled; - if (setled < 3) { //正向期间,0,1,2的时候只能点亮前几个led - //首先确定能点亮几个灯 - leds2turnon = setled + 1; //1,2,3 - //然后设置pwm输出通道 + if (setled < 3) { //During the positive period, only the first few LEDs can be on during 0, 1, 2 + //First determine that you can light a few lights + leds2turnon = setled + 1; //1,2,3 + //Then set the PWM output channel for (i = 0; i < leds2turnon; i++) { pwm_config.output_pins[3 - i] = led_pins_arr[setled - i]; } - } else if (setled <= 7) { //正向期间,大于4小于8的时候能点亮4个led - //设置pwm输出通道 + } else if (setled <= 7) { //During the positive period, it can light up 4 LEDs when it is greater than 4 less than 4 + //Set the PWM output channel for (i = 0; i < 4; i++) { pwm_config.output_pins[3 - i] = led_pins_arr[setled]; setled--; } - } else if (setled > 7 && setled <= 10) { //正向期间,8.9.10的时候只能点亮后几个led - //首先确定能点亮几个灯 + } else if (setled > 7 && setled <= 10) { // During the positive period, only a few LEDs can be lit at 8.9.10 + //First determine that you can light a few lights leds2turnon = 11 - setled; - //然后设置pwm输出通道 + //Then set the PWM output channel for (i = 0; i < leds2turnon; i++) { pwm_config.output_pins[i] = led_pins_arr[setled - 3 + i]; } - } else { //正向期间,达到11 - //什么都不干 + } else { //During the positive period, reach 11 + //Nothing } - //处理停止条件 + //Process stop condition if (startled == end) { break; } @@ -341,22 +341,22 @@ void ledblink4(uint8_t color, uint8_t dir, uint8_t end, uint8_t start_light, uin } } -//单灯水平移动 -//color 要点亮的led的颜色 0-R,1-G,2-B -//start 启动灯位 -//stop 停止灯位 +//Single light level movement +//color The color of the lit LED 0-R,1-G,2-B +//start Start the lamp position +//stop Stop lamp position void ledblink5(uint8_t color, uint8_t start, uint8_t stop) { uint8_t setled = start; uint32_t *led_pins = hw_get_led_array(); - //设置亮度 + //Set the brightness pwm_sequ_val.channel_3 = 0; pwm_sequ_val.channel_2 = 0; pwm_sequ_val.channel_1 = 0; pwm_sequ_val.channel_0 = get_pwmduty(99); - //调整颜色 + //Adjust the color set_slot_light_color(color); while (setled < (start < stop ? stop + 1 : stop - 1)) { - //关闭所有通道 + //Close all channels pwm_config.output_pins[0] = NRF_DRV_PWM_PIN_NOT_USED; pwm_config.output_pins[1] = NRF_DRV_PWM_PIN_NOT_USED; pwm_config.output_pins[2] = NRF_DRV_PWM_PIN_NOT_USED; @@ -371,8 +371,8 @@ void ledblink5(uint8_t color, uint8_t start, uint8_t stop) { } -//充电动画 -//perc 电池当前百分比 0-4 4代表满电呼吸灯 +//Charging cartoon +// perc the current percentage of the battery 0-4 4 represents full electric breathing light volatile bool callback_waiting6 = 0; void ledblink6_pwm_callback(nrfx_pwm_evt_type_t event_type) { if (event_type == NRF_DRV_PWM_EVT_FINISHED) { @@ -382,7 +382,7 @@ void ledblink6_pwm_callback(nrfx_pwm_evt_type_t event_type) { void ledblink6(void) { uint32_t *led_array = hw_get_led_array(); const uint16_t delay_time = 25; - static int16_t light_level = 99; //led亮度值 + static int16_t light_level = 99; //LED brightness value if (!g_usb_led_marquee_enable && ledblink6_step != 0) { light_level = 99; @@ -402,7 +402,7 @@ void ledblink6(void) { pwm_config.output_pins[3] = led_array[5]; ledblink6_step = 1; - // 重置USB未开启通信时的灯的状态 + // Reset the state of the lamp when the USB is not turned on ledblink1_step = 0; } @@ -414,18 +414,18 @@ void ledblink6(void) { if (ledblink6_step == 2 || ledblink6_step == 3 || ledblink6_step == 4) { if (light_level <= 99) { if (ledblink6_step == 2) { - //处理亮度 + //Treatment brightness pwm_sequ_val.channel_0 = get_pwmduty(light_level); pwm_sequ_val.channel_1 = pwm_sequ_val.channel_0; pwm_sequ_val.channel_2 = pwm_sequ_val.channel_0; pwm_sequ_val.channel_3 = pwm_sequ_val.channel_0; - nrfx_pwm_uninit(&pwm0_ins); //关闭pwm输出 + nrfx_pwm_uninit(&pwm0_ins); //Close PWM output set_slot_light_color(1); nrf_drv_pwm_init(&pwm0_ins, &pwm_config, ledblink6_pwm_callback); nrf_drv_pwm_simple_playback(&pwm0_ins, &seq, 1, NRF_DRV_PWM_FLAG_LOOP); ledblink6_step = 3; } - if (ledblink6_step == 3) { //等待pwm模块输出完成 + if (ledblink6_step == 3) { //Waiting for the output of the PWM module to complete if (callback_waiting6 != 0) { ledblink6_step = 4; bsp_set_timer(timer, 0); @@ -451,18 +451,18 @@ void ledblink6(void) { if (ledblink6_step == 6 || ledblink6_step == 7 || ledblink6_step == 8) { if (light_level >= 0) { if (ledblink6_step == 6) { - //处理亮度 + //Treatment brightness pwm_sequ_val.channel_0 = get_pwmduty(light_level); pwm_sequ_val.channel_1 = pwm_sequ_val.channel_0; pwm_sequ_val.channel_2 = pwm_sequ_val.channel_0; pwm_sequ_val.channel_3 = pwm_sequ_val.channel_0; - nrfx_pwm_uninit(&pwm0_ins); //关闭pwm输出 + nrfx_pwm_uninit(&pwm0_ins); //Close PWM output set_slot_light_color(1); nrf_drv_pwm_init(&pwm0_ins, &pwm_config, ledblink6_pwm_callback); nrf_drv_pwm_simple_playback(&pwm0_ins, &seq, 1, NRF_DRV_PWM_FLAG_LOOP); ledblink6_step = 7; } - if (ledblink6_step == 7) { //等待pwm模块输出完成 + if (ledblink6_step == 7) { //Waiting for the output of the PWM module to complete if (callback_waiting6 != 0) { ledblink6_step = 8; bsp_set_timer(timer, 0); @@ -482,10 +482,10 @@ void ledblink6(void) { } /** - * @brief 当前的灯效是否使能 + * @brief Whether the current lighting effect enables * - * @return true 使能状态,处于灯效闪烁状态 - * @return false 禁止状态,处于普通卡槽指示灯状态 + * @return true Make the state, flickering in the lighting effect + * @return false The state is prohibited, in the state of ordinary card slot indicator */ bool is_rgb_marquee_enable(void) { return g_usb_led_marquee_enable; diff --git a/firmware/application/src/usb_main.c b/firmware/application/src/usb_main.c index 20a26c4..3cc0d8f 100644 --- a/firmware/application/src/usb_main.c +++ b/firmware/application/src/usb_main.c @@ -49,10 +49,7 @@ static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const *p_inst, app_usb switch (event) { case APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN: { /* - * 整个USB接收数据的大概关键之处就是 app_usbd_cdc_acm_read - * app_usbd_cdc_acm_read函数其实不是正经的接收,是给了一个指针,然后等USB的buffer填充到此处 - * 所以需要在 APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN 时先初始化设置头部指针,达到预先设置接收缓冲区的效果 - * 如果在 APP_USBD_CDC_ACM_USER_EVT_RX_DONE 使用下标 0 去访问缓冲区,将会导致丢失第一个发送过来的字节。。 + *theProbabilityOfTheEntireUsbReceivingDataIsTheAppUsbdCdcAcmRead *AppUsbdCdcAcmReadFunctionIsNotASeriousReception,ItIsGivenAPointer,AndThenWaitForTheUsbBuffer *SoYouNeedToInitializeTheHeadPointerFirstWhenTheAppUsbdCdcAcmUserEvtPortOpenIsInitialized *IfTheAppUsbdCdcAcmUserEvtRxDoneUsesASubscribed0ToAccessTheBuffer,ItWillCauseTheFirstByteToLoseTheFirstSendEssence */ ret_code_t ret = app_usbd_cdc_acm_read(&m_app_cdc_acm, cdc_data_buffer, 1); UNUSED_VARIABLE(ret); @@ -72,12 +69,12 @@ static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const *p_inst, app_usb case APP_USBD_CDC_ACM_USER_EVT_RX_DONE: { ret_code_t ret; - // 先取出第一个字节 + //Take out the first byte first data_frame_receive(cdc_data_buffer, 1); do { ret = app_usbd_cdc_acm_read(&m_app_cdc_acm, cdc_data_buffer, 1); if (ret == NRF_SUCCESS) { - // 成功取到之后的字节 + // The byte after success data_frame_receive(cdc_data_buffer, 1); } } while (ret == NRF_SUCCESS); diff --git a/firmware/application/src/utils/dataframe.c b/firmware/application/src/utils/dataframe.c index 3ee2d77..e2d5d6f 100644 --- a/firmware/application/src/utils/dataframe.c +++ b/firmware/application/src/utils/dataframe.c @@ -44,11 +44,11 @@ static data_frame_tx_t m_frame_tx_buf_info = { /** - * @brief 数据包创建,将创建之后的数据包放到缓冲区中,等待发送完毕之后设置非busy状态 - * @param cmd: 指令应答 - * @param status: 应答状态 - * @param length: 应答数据长度 - * @param data: 应答数据 + * @briefcreateAPacket,PutTheCreatedDataPacketIntoTheBuffer,AndWaitForThePostToSetUpANonBusyState + * @param cmd: instructionResponse + * @param status:responseStatus + * @param length: answerDataLength + * @param data: answerData */ data_frame_tx_t *data_frame_make(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { uint8_t lrc_tx = 0x00; @@ -94,9 +94,9 @@ void data_frame_reset(void) { } /** - * @brief 数据包接收,用于接收发送过来的数据包并且进行拼接处理 - * @param data: 接收到的字节数组 - * @param length: 接收到的字节数组的长度 + * @brief Package receiving, which is used to receive the sent from the data packet and perform splicing processing + * @param data: Receive byte array + * @param length:The length of the receiving byte array */ void data_frame_receive(uint8_t *data, uint16_t length) { // buffer wait process @@ -173,9 +173,9 @@ void data_frame_receive(uint8_t *data, uint16_t length) { } /** - * @brief 数据包处理,当接收到的数据形成了一个完整的帧之后, - * 将会通过此函数分发处理任务,此函数会回调通知数据处理者 - * 如果数据处理是耗时操作,则需要将此函数放在main循环中调用 + * @brief After the data packet processing, when the received data forms a complete frame, + * This function will be distributed processing tasks through this function, which will be adjusted to notify the data processing of the data + * If the data processing is time -consuming operation, you need to put this function in the main loop to call */ void data_frame_process(void) { // check if data frame @@ -191,7 +191,7 @@ void data_frame_process(void) { } /** - * @brief 数据包处理回调注册 + * @brief Package processing registration registration */ void on_data_frame_complete(data_frame_cbk_t callback) { m_frame_process_cbk = callback; diff --git a/firmware/application/src/utils/fds_util.c b/firmware/application/src/utils/fds_util.c index 586ede7..af8e1de 100644 --- a/firmware/application/src/utils/fds_util.c +++ b/firmware/application/src/utils/fds_util.c @@ -19,11 +19,11 @@ static struct { /** - * 查询记录是否存在,并且获得记录的句柄 + *The query record exists, and get the handle of the record */ static bool fds_find_record(uint16_t id, uint16_t key, fds_record_desc_t *desc) { fds_find_token_t ftok; - memset(&ftok, 0x00, sizeof(fds_find_token_t)); // 使用之前需要先清空 + memset(&ftok, 0x00, sizeof(fds_find_token_t)); // You need to be empty before use if (fds_record_find(id, key, desc, &ftok) == NRF_SUCCESS) { return true; } @@ -48,48 +48,48 @@ bool fds_is_exists(uint16_t id, uint16_t key) { /** - * 读取记录 + *Read record */ bool fds_read_sync(uint16_t id, uint16_t key, uint16_t max_length, uint8_t *buffer) { - ret_code_t err_code; // 操作的结果码 - fds_flash_record_t flash_record; // 指向flash中的实际信息 - fds_record_desc_t record_desc; // 记录的句柄 + ret_code_t err_code; //The results of the operation + fds_flash_record_t flash_record; // Pointing to the actual information in Flash + fds_record_desc_t record_desc; // Recorded handle if (fds_find_record(id, key, &record_desc)) { - err_code = fds_record_open(&record_desc, &flash_record); // 打开记录,使之被标记为打开状态 + err_code = fds_record_open(&record_desc, &flash_record); //Open the record so that it is marked as the open state APP_ERROR_CHECK(err_code); - if (flash_record.p_header->length_words * 4 <= max_length) { // 在此处将flash中的数据读取到给定的RAM中 - // 确保缓冲区不会溢出后,读出此记录 + if (flash_record.p_header->length_words * 4 <= max_length) { // Read the data in Flash here to the given RAM + // Make sure that the buffer will not overflow, read this record memcpy(buffer, flash_record.p_data, flash_record.p_header->length_words * 4); NRF_LOG_INFO("FDS read success."); return true; } else { NRF_LOG_INFO("FDS buffer too small, can't run memcpy, fds size = %d, buffer size = %d", flash_record.p_header->length_words * 4, max_length); } - err_code = fds_record_close(&record_desc); // 操作完成后关闭文件 + err_code = fds_record_close(&record_desc); // Close the file after the operation is completed APP_ERROR_CHECK(err_code); } - // 加载不到正确的数据,可能是不存在这个记录 + //If the correct data is not loaded, this record may not exist return false; } /** - * 没有GC过程的写入操作函数的实现 + * There is no realization of the writing operation function of the GC process */ static ret_code_t fds_write_record_nogc(uint16_t id, uint16_t key, uint16_t data_length_words, void *buffer) { - ret_code_t err_code; // 操作的结果码 - fds_record_desc_t record_desc; // 记录的句柄 - fds_record_t record = { // 记录的实体,写和更新操作时用的上 + ret_code_t err_code; // The results of the operation + fds_record_desc_t record_desc; // Recorded handle + fds_record_t record = { // The entity of the record is used for writing and updating the operation. .file_id = id, .key = key, .data = { .p_data = buffer, .length_words = data_length_words, } }; - if (fds_find_record(id, key, &record_desc)) { // 查找具有指定特征的记录 - // 能找得到这个记录,我们可以进行update操作 + if (fds_find_record(id, key, &record_desc)) { // Find a record with specified characteristics + //If you can find this record, we can perform the update operation err_code = fds_record_update(&record_desc, &record); if (err_code == NRF_SUCCESS) { NRF_LOG_INFO("Search FileID: 0x%04x, FileKey: 0x%04x is found, will update.", id, key); } } else { - // 无法找到有效的记录,我们进行第一次写入操作 + // Unable to find effective records, we will write for the first time err_code = fds_record_write(&record_desc, &record); if (err_code == NRF_SUCCESS) { NRF_LOG_INFO("Search FileID: 0x%04x, FileKey: 0x%04x no found, will create.", id, key); @@ -99,7 +99,7 @@ static ret_code_t fds_write_record_nogc(uint16_t id, uint16_t key, uint16_t data } /** - * 写入记录 + * Write record */ bool fds_write_sync(uint16_t id, uint16_t key, uint16_t data_length_words, void *buffer) { // Make only one task running @@ -112,35 +112,35 @@ bool fds_write_sync(uint16_t id, uint16_t key, uint16_t data_length_words, void fds_operation_info.success = false; fds_operation_info.waiting = true; - // 调用无自动GC的写实现函数 + // Call the real function of the realistic unmnled GC ret_code_t err_code = fds_write_record_nogc(id, key, data_length_words, buffer); if (err_code == NRF_SUCCESS) { while (!fds_operation_info.success) { __NOP(); - }; // 等待操作完成 - } else if (err_code == FDS_ERR_NO_SPACE_IN_FLASH) { // 确保还有空间可以操作,否则需要GC - // 当前报错是属于空间不足的报错,可能我们需要进行GC + }; // Waiting for operation to complete + } else if (err_code == FDS_ERR_NO_SPACE_IN_FLASH) { //Make sure there is space to operate, otherwise GC will be required + // The current error is an error with insufficient space. Maybe we need GC NRF_LOG_INFO("FDS no space, gc auto start."); fds_gc_sync(); - // gc完成后,可以重新进行相应的操作了 + // After the GC is completed, it can be re -operated NRF_LOG_INFO("FDS auto gc success, write record continue."); fds_operation_info.success = false; err_code = fds_write_record_nogc(id, key, data_length_words, buffer); if (err_code == NRF_SUCCESS) { while (!fds_operation_info.success) { __NOP(); - }; // 等待操作完成 + }; // Waiting for operation to complete } else if (err_code == FDS_ERR_NO_SPACE_IN_FLASH) { - // gc了一次之后,发现还是没有空间,那么可能是开发者没有考虑好空间分配导致溢出了 + //After gc once, I found that there is still no space, so it may be that the developer did not consider the space distribution and caused overflow NRF_LOG_ERROR("FDS no space to write."); ret = false; } else { - // 如果不是空间不足的报错,那么我们就需要catch这个错误,开发时就解决 + //If it is not an error with insufficient space, then we need Catch the error, and we solve it during development APP_ERROR_CHECK(err_code); } } else { - // 同上 + // Above APP_ERROR_CHECK(err_code); } @@ -150,7 +150,7 @@ bool fds_write_sync(uint16_t id, uint16_t key, uint16_t data_length_words, void } /* - * 删除记录 + * Delete Record */ int fds_delete_sync(uint16_t id, uint16_t key) { int delete_count = 0; @@ -164,13 +164,13 @@ int fds_delete_sync(uint16_t id, uint16_t key) { delete_count++; while (!fds_operation_info.success) { __NOP(); - }; // 等待操作完成 + }; //Waiting for operation to complete } return delete_count; } /** - * FDS事件回调 + *FDS event callback */ static void fds_evt_handler(fds_evt_t const *p_evt) { // To process fds event @@ -188,7 +188,7 @@ static void fds_evt_handler(fds_evt_t const *p_evt) { if (p_evt->result == NRF_SUCCESS) { NRF_LOG_INFO("Record change: FileID 0x%04x, RecordKey 0x%04x", p_evt->write.file_id, p_evt->write.record_key); if (p_evt->write.file_id == fds_operation_info.id && p_evt->write.record_key == fds_operation_info.key) { - // 上面的逻辑已经确保是我们当前正在写的任务完成了! + // The logic above has ensured that the task we are currently writing is completed! fds_operation_info.success = true; } } else { @@ -227,15 +227,15 @@ static void fds_evt_handler(fds_evt_t const *p_evt) { } /** - * 初始化nrf52的fds库 + *Initialize the FDS library of NRF52 */ void fds_util_init() { // reset waiting flag fds_operation_info.waiting = false; - // 先注册事件回调 + //Register the incident first ret_code_t err_code = fds_register(fds_evt_handler); APP_ERROR_CHECK(err_code); - // 开始初始化fds库 + //Start the initialization FDS library err_code = fds_init(); APP_ERROR_CHECK(err_code); } diff --git a/firmware/application/src/utils/syssleep.c b/firmware/application/src/utils/syssleep.c index b94adba..5c68670 100644 --- a/firmware/application/src/utils/syssleep.c +++ b/firmware/application/src/utils/syssleep.c @@ -7,33 +7,33 @@ #include "nrf_log_default_backends.h" -APP_TIMER_DEF(m_app_sleep_timer); // 用于设备休眠的定时器 +APP_TIMER_DEF(m_app_sleep_timer); //The timer for equipment dormant static volatile bool m_system_off_enter = false; -extern bool g_is_ble_connected; // 标志BLE的链接状态 -extern bool g_is_tag_emulating; // 标志模拟卡的状态 +extern bool g_is_ble_connected; //Link to log in BLE +extern bool g_is_tag_emulating; //The status of the logo simulation card -/** @brief 设备休眠定时器事件 - * @param 无 - * @return 无 +/** @brief Equipment dormant timer event + * @param none + * @return none */ static void timer_sleep_event_handle(void *arg) { - // 休眠条件达到,设置标志位,让main中处理即可 + // The dormant conditions are achieved, set the logo bit, so that the processing in the main m_system_off_enter = true; } -/**@brief 休眠软定时器初始化 +/**@brief Sleep soft timer initialization */ void sleep_timer_init(void) { ret_code_t err_code; - // 创建软定时器,等待一段时间后进行休眠 + // Create a soft timer and wait for a period of time to sleep err_code = app_timer_create(&m_app_sleep_timer, APP_TIMER_MODE_SINGLE_SHOT, timer_sleep_event_handle); APP_ERROR_CHECK(err_code); } -/**@brief 休眠软定时器停止 +/**@brief Sleeping soft timer stop */ void sleep_timer_stop() { m_system_off_enter = false; @@ -41,16 +41,16 @@ void sleep_timer_stop() { APP_ERROR_CHECK(err_code); } -/**@brief 休眠软定时器启动 +/**@brief Sleep soft timer startup */ void sleep_timer_start(uint32_t time_ms) { - // 先关闭之前的休眠定时器 + // Close the previous dormant timer first sleep_timer_stop(); - // 非USB供电状态 + // Non -USB power supply status if (nrfx_power_usbstatus_get() == NRFX_POWER_USB_STATE_DISCONNECTED) { - // 如果蓝牙还连接着,或者还在模拟卡状态,就不需要启动休眠 + // If Bluetooth is still connected, or is still in the state of simulation card, you don't need to start dormant if (g_is_ble_connected == false && g_is_tag_emulating == false) { - // 启动定时器 + // Start the timer ret_code_t err_code = app_timer_start(m_app_sleep_timer, APP_TIMER_TICKS(time_ms), NULL); APP_ERROR_CHECK(err_code); } @@ -58,7 +58,7 @@ void sleep_timer_start(uint32_t time_ms) { } /** - *@brief 运行休眠的具体实现 + *@brief Specific implementation of dormant *@param sysOff: The system off function implment. */ void sleep_system_run(void (*sysOffSleep)(), void (*sysOnSleep)()) { diff --git a/firmware/application/src/utils/syssleep.h b/firmware/application/src/utils/syssleep.h index 6a44619..b307eb3 100644 --- a/firmware/application/src/utils/syssleep.h +++ b/firmware/application/src/utils/syssleep.h @@ -3,18 +3,18 @@ #include -// 休眠态唤醒设备 -#define SLEEP_DELAY_MS_BUTTON_WAKEUP 4000 // 按钮唤醒的休眠延迟 -#define SLEEP_DELAY_MS_FIELD_WAKEUP 4000 // 场唤醒的休眠延迟(包括高低频) -#define SLEEP_DELAY_MS_FRIST_POWER 1000 // 首次供电的休眠延迟(接入电池) +// Wake up equipment +#define SLEEP_DELAY_MS_BUTTON_WAKEUP 4000 // The dormant delay of the button awakened +#define SLEEP_DELAY_MS_FIELD_WAKEUP 4000 // The dormant delay (including high and low frequencies) of the field wake -up (including high and low frequency) +#define SLEEP_DELAY_MS_FRIST_POWER 1000 // The dormant delay of the first power supply (access to the battery) -// 运行态重新延迟 -#define SLEEP_DELAY_MS_BUTTON_CLICK 4000 // 按钮点击的休眠延迟 -#define SLEEP_DELAY_MS_FIELD_NFC_LOST 3000 // 高频模拟卡离开场后的休眠延迟 -#define SLEEP_DELAY_MS_FIELD_125KHZ_LOST 3000 // 低频模拟卡离开场后的休眠延迟 -#define SLEEP_DELAY_MS_BLE_DISCONNECTED 4000 // BLE断开后的休眠延迟 -#define SLEEP_DELAY_MS_USB_POWER_DISCONNECTED 3000 // USB供电断开后的休眠延迟 -#define SLEEP_NO_BATTERY_SHUTDOWN 1 // 低电量关机 +// The operating state is delayed +#define SLEEP_DELAY_MS_BUTTON_CLICK 4000 //The dormant delay of the button click +#define SLEEP_DELAY_MS_FIELD_NFC_LOST 3000 //High -frequency analog card after leaving the field +#define SLEEP_DELAY_MS_FIELD_125KHZ_LOST 3000 // Dormation delay after leaving the field after leaving the field +#define SLEEP_DELAY_MS_BLE_DISCONNECTED 4000 //BLE's dormant delay after disconnection +#define SLEEP_DELAY_MS_USB_POWER_DISCONNECTED 3000 //The dormant delay after the USB power supply is broken +#define SLEEP_NO_BATTERY_SHUTDOWN 1 //Turn off at a low volume void sleep_timer_init(void); diff --git a/firmware/application/src/utils/timeslot.c b/firmware/application/src/utils/timeslot.c index 5af2a72..e92c23c 100644 --- a/firmware/application/src/utils/timeslot.c +++ b/firmware/application/src/utils/timeslot.c @@ -24,11 +24,11 @@ static volatile bool m_is_timeslot_working = false; /**@brief Configure next timeslot event in earliest configuration */ void configure_next_event_earliest(void) { - m_timeslot_request.request_type = NRF_RADIO_REQ_TYPE_EARLIEST; // 首次请求timeslot必须要 - m_timeslot_request.params.earliest.hfclk = NRF_RADIO_HFCLK_CFG_NO_GUARANTEE; // 不必自动使能外部高频晶振 - m_timeslot_request.params.earliest.priority = NRF_RADIO_PRIORITY_HIGH; // 必须使用高优先级 - m_timeslot_request.params.earliest.length_us = m_slot_length; // timeslot时长 - m_timeslot_request.params.earliest.timeout_us = NRF_RADIO_EARLIEST_TIMEOUT_MAX_US; // 等待timeslot超时 + m_timeslot_request.request_type = NRF_RADIO_REQ_TYPE_EARLIEST; // The first request to ask TimesLot must + m_timeslot_request.params.earliest.hfclk = NRF_RADIO_HFCLK_CFG_NO_GUARANTEE; // No need to automatically enable external high -frequency crystals + m_timeslot_request.params.earliest.priority = NRF_RADIO_PRIORITY_HIGH; // Must use high priority + m_timeslot_request.params.earliest.length_us = m_slot_length; // Timeslot duration + m_timeslot_request.params.earliest.timeout_us = NRF_RADIO_EARLIEST_TIMEOUT_MAX_US; // Waiting for Timeslot timeout } /**@brief Request next timeslot event in earliest configuration @@ -48,10 +48,10 @@ static void t55xx_soc_evt_handler(uint32_t evt_id, void *p_context) { case NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN: // No implementation needed break; - case NRF_EVT_RADIO_SESSION_IDLE: // 会话空闲,没有时序需要穿插处理 + case NRF_EVT_RADIO_SESSION_IDLE: //The session is idle, there is no time order to be interspersed //NRF_LOG_INFO("NRF_EVT_RADIO_SESSION_IDLE"); break; - case NRF_EVT_RADIO_SESSION_CLOSED: // 会话被关闭 + case NRF_EVT_RADIO_SESSION_CLOSED: // The session is closed // No implementation needed, session ended //NRF_LOG_INFO("NRF_EVT_RADIO_SESSION_CLOSED"); m_is_timeslot_working = false; @@ -78,7 +78,7 @@ nrf_radio_signal_callback_return_param_t *radio_callback(uint8_t signal_type) { signal_callback_return_param.params.request.p_next = NULL; signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE; - // 请求成功,设置一下标志位 + // Successful request, set the logo position m_is_timeslot_working = true; break; @@ -90,32 +90,32 @@ nrf_radio_signal_callback_return_param_t *radio_callback(uint8_t signal_type) { } /** - * 请求一段时序进行高精度操作 + * Request a sequence for high -precision operation */ void request_timeslot(uint32_t time_us, timeslot_callback_t callback, bool wait_end) { ret_code_t err_code; - // 确保同一时间只有一个 + // Make sure there is only one at the same time APP_ERROR_CHECK_BOOL(!m_is_timeslot_running); m_is_timeslot_running = true; - m_slot_length = time_us; // 配置申请的时间 - m_callback = callback; // 配置时间申请到之后执行的操作 + m_slot_length = time_us; //The time for configuration application + m_callback = callback; // The configuration time application is applied to the operation after execution - // 打开会话 + // Open the session err_code = sd_radio_session_open(radio_callback); APP_ERROR_CHECK(err_code); - // 请求时序 + // Request timing err_code = request_next_event_earliest(); APP_ERROR_CHECK(err_code); - // 堵塞等待时序请求成功 + // The sequence request is successful while (!m_is_timeslot_working) { NRF_LOG_PROCESS(); } - // 进入临界点 + // Enter the critical point NVIC_DisableIRQ(RADIO_IRQn); NVIC_DisableIRQ(TIMER0_IRQn); NVIC_DisableIRQ(TIMER2_IRQn); @@ -123,56 +123,56 @@ void request_timeslot(uint32_t time_us, timeslot_callback_t callback, bool wait_ NVIC_DisableIRQ(MWU_IRQn); NVIC_DisableIRQ(RTC1_IRQn); - // 请求时序成功,快处理任务 + // The request timing is successful, handle the task quickly if (m_callback != NULL) { - m_callback(); // 执行任务 - m_callback = NULL; // 销毁记录 + m_callback(); // Execute task + m_callback = NULL; // Destruction record } - // 退出临界点 + // Exit critical point NVIC_EnableIRQ(GPIOTE_IRQn); NVIC_EnableIRQ(RTC1_IRQn); NVIC_EnableIRQ(MWU_IRQn); - // 关闭会话并且等待关闭完成 + //Close the session and wait for the closure to complete err_code = sd_radio_session_close(); APP_ERROR_CHECK(err_code); while (m_is_timeslot_working) { __NOP(); } - // 任务处理完成,进行收尾工作 + // The task process is completed and the ending work m_is_timeslot_running = false; //NRF_LOG_INFO("request timeslot done."); } /** - * 开始进行高精度操作 + * Start performing high -precision operations */ void timeslot_start(uint32_t time_us) { ret_code_t err_code; - // 确保同一时间只有一个 + // Make sure there is only one at the same time APP_ERROR_CHECK_BOOL(!m_is_timeslot_running); m_is_timeslot_running = true; - m_slot_length = time_us * 1000; // 配置申请的时间 + m_slot_length = time_us * 1000; //The time for configuration application - // 打开会话 + // Open the session err_code = sd_radio_session_open(radio_callback); APP_ERROR_CHECK(err_code); - // 请求时序 + // Request timing err_code = request_next_event_earliest(); APP_ERROR_CHECK(err_code); - // 堵塞等待时序请求成功 + // The sequence request is successful while (!m_is_timeslot_working) { NRF_LOG_PROCESS(); } - // 进入临界点 + // Enter the critical point NVIC_DisableIRQ(RADIO_IRQn); NVIC_DisableIRQ(TIMER0_IRQn); NVIC_DisableIRQ(TIMER2_IRQn); @@ -183,28 +183,28 @@ void timeslot_start(uint32_t time_us) { } /** - * 停止高精度操作 + * Stop high -precision operation */ void timeslot_stop(void) { ret_code_t err_code; - // 确保已经有一个timeslot运行 + // Make sure that there is already a timeSlot running APP_ERROR_CHECK_BOOL(m_is_timeslot_running); m_is_timeslot_running = false; - // 退出临界点 + // Exit critical point //NVIC_EnableIRQ(GPIOTE_IRQn); NVIC_EnableIRQ(RTC1_IRQn); NVIC_EnableIRQ(MWU_IRQn); - // 关闭会话并且等待关闭完成 + // Close the session and wait for the closure to complete err_code = sd_radio_session_close(); APP_ERROR_CHECK(err_code); while (m_is_timeslot_working) { __NOP(); } - // 任务处理完成,进行收尾工作 + // The task process is completed and the ending work m_is_timeslot_running = false; //NRF_LOG_INFO("timeslot stop."); }