diff --git a/firmware/application/src/app_cmd.c b/firmware/application/src/app_cmd.c index 092d57e..a48b27e 100644 --- a/firmware/application/src/app_cmd.c +++ b/firmware/application/src/app_cmd.c @@ -488,6 +488,35 @@ static data_frame_tx_t *cmd_processor_mf1_write_one_block(uint16_t cmd, uint16_t return data_frame_make(cmd, status, 0, NULL); } +#if defined(PROJECT_CHAMELEON_ULTRA) + +static data_frame_tx_t *cmd_processor_hf14a_set_field_on(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + device_mode_t mode = get_device_mode(); + if (mode != DEVICE_MODE_READER) { + return data_frame_make(cmd, STATUS_DEVICE_MODE_ERROR, 0, NULL); + } + + // Reset and turn on the antenna + pcd_14a_reader_reset(); + pcd_14a_reader_antenna_on(); + + return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL); +} + +static data_frame_tx_t *cmd_processor_hf14a_set_field_off(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + device_mode_t mode = get_device_mode(); + if (mode != DEVICE_MODE_READER) { + return data_frame_make(cmd, STATUS_DEVICE_MODE_ERROR, 0, NULL); + } + + // Turn off the antenna + pcd_14a_reader_antenna_off(); + + return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL); +} + +#endif + static data_frame_tx_t *cmd_processor_hf14a_raw(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { // Response Buffer uint8_t resp[DEF_FIFO_LENGTH] = { 0x00 }; @@ -1578,6 +1607,9 @@ static cmd_data_map_t m_data_cmd_map[] = { { DATA_CMD_VIKING_SCAN, before_reader_run, cmd_processor_viking_scan, NULL }, { DATA_CMD_VIKING_WRITE_TO_T55XX, before_reader_run, cmd_processor_viking_write_to_t55xx, NULL }, + { DATA_CMD_HF14A_SET_FIELD_ON, before_reader_run, cmd_processor_hf14a_set_field_on, NULL }, + { DATA_CMD_HF14A_SET_FIELD_OFF, before_reader_run, cmd_processor_hf14a_set_field_off, NULL }, + #endif { DATA_CMD_HF14A_GET_ANTI_COLL_DATA, NULL, cmd_processor_hf14a_get_anti_coll_data, NULL }, diff --git a/firmware/application/src/app_main.c b/firmware/application/src/app_main.c index 87a3efc..77ee76f 100644 --- a/firmware/application/src/app_main.c +++ b/firmware/application/src/app_main.c @@ -41,6 +41,10 @@ NRF_LOG_MODULE_REGISTER(); #include "tag_persistence.h" #include "settings.h" +#if defined(PROJECT_CHAMELEON_ULTRA) +#include "rc522.h" +#endif + // Defining soft timers APP_TIMER_DEF(m_button_check_timer); // Timer for button debounce @@ -56,6 +60,9 @@ static bool m_is_a_btn_release = false; static bool m_system_off_processing = false; +// NFC field generator state +volatile bool m_is_field_on = false; + // cpu reset reason static uint32_t m_reset_source; static uint32_t m_gpregret_val; @@ -139,6 +146,35 @@ static void gpio_te_init(void) { APP_ERROR_CHECK(err_code); } +#if defined(PROJECT_CHAMELEON_ULTRA) +static void field_generator_rainbow_loop(void) { + static uint8_t color_index = 0; + static uint32_t last_update = 0; + + if (!m_is_field_on) return; + + uint32_t now = app_timer_cnt_get(); + + if (app_timer_cnt_diff_compute(now, last_update) < APP_TIMER_TICKS(100)) { + return; + } + last_update = now; + + // Rainbow colors + const uint8_t colors[] = {RGB_RED, RGB_YELLOW, RGB_GREEN, RGB_CYAN, RGB_BLUE, RGB_MAGENTA}; + + set_slot_light_color(colors[color_index]); + uint32_t *led_pins = hw_get_led_array(); + + // Light up all LEDs with current color + for (int i = 0; i < RGB_LIST_NUM; i++) { + nrf_gpio_pin_set(led_pins[i]); + } + + color_index = (color_index + 1) % 6; +} +#endif + /**@brief Button Matrix Events */ static void button_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { @@ -162,7 +198,9 @@ static void timer_button_event_handle(void *arg) { NRF_LOG_INFO("BUTTON press during shutdown"); return; } + nrf_drv_gpiote_pin_t pin = *(nrf_drv_gpiote_pin_t *)arg; + // Check here if the current GPIO is at the pressed level if (nrf_gpio_pin_read(pin) == 1) { if (pin == BUTTON_1) { @@ -757,13 +795,67 @@ static void run_button_function_by_settings(settings_button_function_t sbf) { case SettingsButtonCloneIcUid: btn_fn_copy_ic_uid(); break; + case SettingsButtonNfcFieldGenerator: + if (!m_is_field_on) { + // Initialize reader hardware if not already in reader mode + device_mode_t current_mode = get_device_mode(); + if (current_mode != DEVICE_MODE_READER) { + // Temporarily init reader hardware just for the field + nrf_gpio_cfg_output(READER_POWER); + nrf_gpio_pin_set(READER_POWER); // reader power enable + nrf_gpio_cfg_output(HF_ANT_SEL); + nrf_gpio_pin_clear(HF_ANT_SEL); // hf ant switch to reader mode + + pcd_14a_reader_init(); + bsp_delay_ms(10); + } + + pcd_14a_reader_reset(); + pcd_14a_reader_antenna_on(); + m_is_field_on = true; + NRF_LOG_INFO("NFC field ON"); + + // Set initial rainbow state + set_slot_light_color(RGB_RED); + uint32_t *led_pins = hw_get_led_array(); + for (int i = 0; i < RGB_LIST_NUM; i++) { + nrf_gpio_pin_set(led_pins[i]); + } + + // Stop sleep timer while field is active + NRF_LOG_INFO("Stopping sleep timer for field generator"); + sleep_timer_stop(); + NRF_LOG_INFO("Sleep timer stopped"); + } else { + pcd_14a_reader_antenna_off(); + m_is_field_on = false; + NRF_LOG_INFO("NFC field OFF"); + + // If we're not in reader mode, clean up the hardware + device_mode_t current_mode = get_device_mode(); + if (current_mode != DEVICE_MODE_READER) { + pcd_14a_reader_uninit(); + nrf_gpio_pin_clear(READER_POWER); // reader power disable + nrf_gpio_pin_set(HF_ANT_SEL); // hf ant switch back to tag mode + } + + // Restore normal LED + light_up_by_slot(); + + // Restart sleep timer + NRF_LOG_INFO("Field off, restarting sleep timer"); + sleep_timer_start(SLEEP_DELAY_MS_BUTTON_CLICK); + NRF_LOG_INFO("Sleep timer restarted"); + } + break; #endif case SettingsButtonShowBattery: show_battery(); + break; default: - NRF_LOG_ERROR("Unsupported button function") + NRF_LOG_ERROR("Unsupported button function"); break; } } @@ -792,8 +884,10 @@ static void button_press_process(void) { } // Disable led marquee for usb at button pressed. g_usb_led_marquee_enable = false; - // Re-delay into hibernation - sleep_timer_start(SLEEP_DELAY_MS_BUTTON_CLICK); + // Re-delay into hibernation (unless field is on) + if (!m_is_field_on) { + sleep_timer_start(SLEEP_DELAY_MS_BUTTON_CLICK); + } } } @@ -887,8 +981,17 @@ int main(void) { lesc_event_process(); // Button event process button_press_process(); - // Led blink at usb status - blink_usb_led_status(); + +#if defined(PROJECT_CHAMELEON_ULTRA) + // Field generator rainbow animation + field_generator_rainbow_loop(); +#endif + + // Led blink at usb status (only if field generator is off) + if (!m_is_field_on) { + blink_usb_led_status(); + } + // Data pack process data_frame_process(); // Log print process @@ -902,4 +1005,4 @@ int main(void) { // Some task process done, we can enter cpu sleep state. sleep_system_run(system_off_enter, nrf_pwr_mgmt_run); } -} +} \ No newline at end of file diff --git a/firmware/application/src/data_cmd.h b/firmware/application/src/data_cmd.h index e0bf70c..3aa1c82 100644 --- a/firmware/application/src/data_cmd.h +++ b/firmware/application/src/data_cmd.h @@ -73,6 +73,9 @@ #define DATA_CMD_MF1_ENC_NESTED_ACQUIRE (2014) #define DATA_CMD_MF1_CHECK_KEYS_ON_BLOCK (2015) +#define DATA_CMD_HF14A_SET_FIELD_ON (2100) +#define DATA_CMD_HF14A_SET_FIELD_OFF (2101) + // // ****************************************************************** diff --git a/firmware/application/src/rfid_main.c b/firmware/application/src/rfid_main.c index 8899b8a..f93d448 100644 --- a/firmware/application/src/rfid_main.c +++ b/firmware/application/src/rfid_main.c @@ -2,11 +2,11 @@ #include "rfid_main.h" #include "rgb_marquee.h" - - //The current mode of the device device_mode_t rfid_state = DEVICE_MODE_NONE; +// External declaration for field state +extern bool m_is_field_on; /** * @brief Function for enter tag reader mode @@ -42,6 +42,12 @@ void tag_mode_enter(void) { rfid_state = DEVICE_MODE_TAG; #if defined(PROJECT_CHAMELEON_ULTRA) + // Safety check: turn off field if it's on + if (m_is_field_on) { + pcd_14a_reader_antenna_off(); + m_is_field_on = false; + } + // uninit reader lf_125khz_radio_uninit(); pcd_14a_reader_uninit(); @@ -116,4 +122,4 @@ uint8_t get_color_by_slot(uint8_t slot) { } else { // Low -frequency emulation, return B return 2; } -} +} \ No newline at end of file diff --git a/firmware/application/src/settings.h b/firmware/application/src/settings.h index 4231733..a690ea4 100644 --- a/firmware/application/src/settings.h +++ b/firmware/application/src/settings.h @@ -26,6 +26,8 @@ typedef enum { // Read the UID card number immediately after pressing, continue searching, and simulate immediately after reading the card SettingsButtonCloneIcUid = 3U, SettingsButtonShowBattery = 4U, + // Toggle NFC field generator on/off (Ultra only, must be in reader mode) + SettingsButtonNfcFieldGenerator = 5U, } settings_button_function_t; typedef struct ALIGN_U32 { @@ -74,4 +76,4 @@ void settings_set_ble_connect_key(uint8_t *key); void settings_set_ble_pairing_enable(bool enable); bool settings_get_ble_pairing_enable(void); bool settings_get_ble_pairing_enable_first_load(void); -#endif +#endif \ No newline at end of file diff --git a/firmware/application/src/utils/syssleep.c b/firmware/application/src/utils/syssleep.c index eaebf8d..69f8d2a 100644 --- a/firmware/application/src/utils/syssleep.c +++ b/firmware/application/src/utils/syssleep.c @@ -12,6 +12,7 @@ static volatile bool m_system_off_enter = false; extern bool g_is_ble_connected; //Link to log in BLE extern bool g_is_tag_emulating; //The status of the logo emulation card +extern volatile bool m_is_field_on; //NFC field generator state from app_main.c /** @brief Equipment sleep timer event @@ -48,8 +49,8 @@ void sleep_timer_start(uint32_t time_ms) { sleep_timer_stop(); // 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 emulation card, you don't need to start sleep - if (g_is_ble_connected == false && g_is_tag_emulating == false) { + // If Bluetooth is still connected, or is still in the state of emulation card, or field generator is on, you don't need to start sleep + if (g_is_ble_connected == false && g_is_tag_emulating == false && m_is_field_on == 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); @@ -72,4 +73,4 @@ void sleep_system_run(void (*sysOffSleep)(), void (*sysOnSleep)()) { // If no task can to process, we can sleep cpu sometime. sysOnSleep(); } -} +} \ No newline at end of file diff --git a/software/script/chameleon_enum.py b/software/script/chameleon_enum.py index f6b72ed..a66ebca 100644 --- a/software/script/chameleon_enum.py +++ b/software/script/chameleon_enum.py @@ -533,6 +533,7 @@ class ButtonPressFunction(enum.IntEnum): PREVSLOT = 2 CLONE = 3 BATTERY = 4 + FIELDGEN = 5 def __str__(self): if self == ButtonPressFunction.NONE: @@ -545,9 +546,10 @@ class ButtonPressFunction(enum.IntEnum): return "Read then simulate the ID/UID card number" elif self == ButtonPressFunction.BATTERY: return "Show Battery Level" + elif self == ButtonPressFunction.FIELDGEN: + return "Toggle NFC Field Generator" return "None" - @enum.unique class MfcValueBlockOperator(enum.IntEnum): DECREMENT = 0xC0