diff --git a/firmware/application/src/app_cmd.c b/firmware/application/src/app_cmd.c index 2a1e6a5..6243a18 100644 --- a/firmware/application/src/app_cmd.c +++ b/firmware/application/src/app_cmd.c @@ -117,6 +117,19 @@ data_frame_tx_t *cmd_processor_reset_settings(uint16_t cmd, uint16_t status, uin return data_frame_make(cmd, status, 0, NULL); } +data_frame_tx_t *cmd_processor_get_settings(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + uint8_t settings[6 + BLE_CONNECT_KEY_LEN_MAX] = {}; + settings[0] = SETTINGS_CURRENT_VERSION; // current version + settings[1] = settings_get_animation_config(); // animation mode + settings[2] = settings_get_button_press_config('A'); // short A button press mode + settings[3] = settings_get_button_press_config('B'); // short B button press mode + settings[4] = settings_get_long_button_press_config('A'); // long A button press mode + settings[5] = settings_get_long_button_press_config('B'); // long B button press mode + memcpy(settings + 6, settings_get_ble_connect_key(), BLE_CONNECT_KEY_LEN_MAX); + return data_frame_make(cmd, STATUS_DEVICE_SUCCESS, 6 + BLE_CONNECT_KEY_LEN_MAX, settings); +} + + data_frame_tx_t *cmd_processor_set_animation_mode(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { if (length == 1) { status = STATUS_DEVICE_SUCCESS; @@ -446,11 +459,30 @@ data_frame_tx_t *cmd_processor_set_em410x_emu_id(uint16_t cmd, uint16_t status, } data_frame_tx_t *cmd_processor_get_em410x_emu_id(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + tag_specific_type_t tag_type[2]; + tag_emulation_get_specific_type_by_slot(tag_emulation_get_slot(), tag_type); + if (tag_type[1] == TAG_TYPE_UNKNOWN) { + return data_frame_make(cmd, STATUS_PAR_ERR, 0, data); // no data in slot, don't send garbage + } tag_data_buffer_t *buffer = get_buffer_by_tag_type(TAG_TYPE_EM410X); uint8_t responseData[LF_EM410X_TAG_ID_SIZE]; memcpy(responseData, buffer->buffer, LF_EM410X_TAG_ID_SIZE); - status = STATUS_DEVICE_SUCCESS; - return data_frame_make(cmd, status, LF_EM410X_TAG_ID_SIZE, responseData); + return data_frame_make(cmd, STATUS_DEVICE_SUCCESS, LF_EM410X_TAG_ID_SIZE, responseData); +} + +data_frame_tx_t *cmd_processor_get_mf1_anti_coll_data(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + tag_specific_type_t tag_type[2]; + tag_emulation_get_specific_type_by_slot(tag_emulation_get_slot(), tag_type); + if (tag_type[0] == TAG_TYPE_UNKNOWN) { + return data_frame_make(cmd, STATUS_PAR_ERR, 0, data); // no data in slot, don't send garbage + } + uint8_t responseData[sizeof(picc_14a_tag_t)] = {}; + nfc_tag_14a_coll_res_reference_t *info = get_saved_mifare_coll_res(); + memcpy(responseData, info->uid, *info->size); + responseData[10] = *info->size; // size is 2 byte len, but... + responseData[12] = info->sak[0]; + memcpy(&responseData[13], info->atqa, 2); + return data_frame_make(cmd, STATUS_DEVICE_SUCCESS, sizeof(picc_14a_tag_t), responseData); } data_frame_tx_t *cmd_processor_set_mf1_detection_enable(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { @@ -855,7 +887,7 @@ static cmd_data_map_t m_data_cmd_map[] = { { DATA_CMD_SET_BLE_CONNECT_KEY_CONFIG, NULL, cmd_processor_set_ble_connect_key, NULL }, { DATA_CMD_DELETE_ALL_BLE_BONDS, NULL, cmd_processor_del_ble_all_bonds, NULL }, { DATA_CMD_GET_DEVICE, NULL, cmd_processor_get_device, NULL }, - // { DATA_CMD_GET_SETTINGS, NULL, NULL, NULL }, + { DATA_CMD_GET_SETTINGS, NULL, cmd_processor_get_settings, NULL }, { DATA_CMD_GET_DEVICE_CAPABILITIES, NULL, NULL, NULL }, #if defined(PROJECT_CHAMELEON_ULTRA) @@ -910,6 +942,7 @@ static cmd_data_map_t m_data_cmd_map[] = { { DATA_CMD_SET_MF1_USE_FIRST_BLOCK_COLL, NULL, cmd_processor_set_mf1_use_coll_res, NULL }, { DATA_CMD_GET_MF1_WRITE_MODE, NULL, cmd_processor_get_mf1_write_mode, NULL }, { DATA_CMD_SET_MF1_WRITE_MODE, NULL, cmd_processor_set_mf1_write_mode, NULL }, + { DATA_CMD_GET_MF1_ANTI_COLL_DATA, NULL, cmd_processor_get_mf1_anti_coll_data, NULL }, { DATA_CMD_SET_SLOT_TAG_NICK, NULL, cmd_processor_set_slot_tag_nick_name, NULL }, { DATA_CMD_GET_SLOT_TAG_NICK, NULL, cmd_processor_get_slot_tag_nick_name, NULL }, diff --git a/firmware/application/src/data_cmd.h b/firmware/application/src/data_cmd.h index c44723d..3d6976c 100644 --- a/firmware/application/src/data_cmd.h +++ b/firmware/application/src/data_cmd.h @@ -100,6 +100,7 @@ #define DATA_CMD_SET_MF1_USE_FIRST_BLOCK_COLL (4015) #define DATA_CMD_GET_MF1_WRITE_MODE (4016) #define DATA_CMD_SET_MF1_WRITE_MODE (4017) +#define DATA_CMD_GET_MF1_ANTI_COLL_DATA (4018) // // ****************************************************************** diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c index 1939531..129e7b9 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c +++ b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c @@ -1070,6 +1070,17 @@ nfc_tag_14a_coll_res_reference_t *get_mifare_coll_res() { return &m_shadow_coll_res; } + +nfc_tag_14a_coll_res_reference_t *get_saved_mifare_coll_res() { + // Always give saved data, not from block 0 + 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); + return &m_shadow_coll_res; +} + /** * @brief Reconcile when the parameter label needs to be reset */ diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.h b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.h index 97041dc..f07d0e4 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.h +++ b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.h @@ -145,6 +145,7 @@ bool nfc_tag_mf1_is_detection_enable(void); void nfc_tag_mf1_detection_log_clear(void); uint32_t nfc_tag_mf1_detection_log_count(void); nfc_tag_14a_coll_res_reference_t *get_mifare_coll_res(void); +nfc_tag_14a_coll_res_reference_t *get_saved_mifare_coll_res(void); void nfc_tag_mf1_set_gen1a_magic_mode(bool enable); bool nfc_tag_mf1_is_gen1a_magic_mode(void); void nfc_tag_mf1_set_gen2_magic_mode(bool enable); diff --git a/software/script/chameleon_cli_unit.py b/software/script/chameleon_cli_unit.py index b45d626..0a6b190 100644 --- a/software/script/chameleon_cli_unit.py +++ b/software/script/chameleon_cli_unit.py @@ -841,6 +841,28 @@ class HFMFSim(DeviceRequiredUnit): print(" - Set anti-collision resources success") +@hf_mf.command('info', 'Get information about current slot (UID/SAK/ATQA)') +class HFMFInfo(DeviceRequiredUnit): + def args_parser(self) -> ArgumentParserNoExit or None: + pass + + def scan(self): + resp: chameleon_com.Response = self.cmd.get_mf1_anti_coll_data() + if resp.status == chameleon_status.Device.STATUS_DEVICE_SUCCESS: + info = chameleon_cstruct.parse_14a_scan_tag_result(resp.data) + print(f"- UID Size: {info['uid_size']}") + print(f"- UID Hex : {info['uid_hex'].upper()}") + print(f"- SAK Hex : {info['sak_hex'].upper()}") + print(f"- ATQA Hex : {info['atqa_hex'].upper()}") + return True + else: + print("No data loaded in slot") + return False + + def on_exec(self, args: argparse.Namespace): + return self.scan() + + @lf_em.command('read', 'Scan em410x tag and print id') class LFEMRead(ReaderRequiredUnit): def args_parser(self) -> ArgumentParserNoExit or None: @@ -1354,15 +1376,13 @@ class HWSettingsBLEKeySet(DeviceRequiredUnit): def on_exec(self, args: argparse.Namespace): if len(args.key) != 6: - print( - f" - {colorama.Fore.RED}The ble connect key length must be 6{colorama.Style.RESET_ALL}") + print(f" - {colorama.Fore.RED}The ble connect key length must be 6{colorama.Style.RESET_ALL}") return if re.match(r'[0-9]{6}', args.key): self.cmd.set_ble_connect_key(args.key) print(" - Successfully set ble connect key to settings") else: - print( - f" - {colorama.Fore.RED}Only 6 ASCII characters from 0 to 9 are supported.{colorama.Style.RESET_ALL}") + print(f" - {colorama.Fore.RED}Only 6 ASCII characters from 0 to 9 are supported.{colorama.Style.RESET_ALL}") @hw_settings_ble_key.command('get', 'Get the ble connect key') diff --git a/software/script/chameleon_cmd.py b/software/script/chameleon_cmd.py index 1e5c124..b7a5ca7 100644 --- a/software/script/chameleon_cmd.py +++ b/software/script/chameleon_cmd.py @@ -5,6 +5,8 @@ import chameleon_com import chameleon_status from chameleon_utils import expect_response +CURRENT_VERSION_SETTINGS = 4 + DATA_CMD_GET_APP_VERSION = 1000 DATA_CMD_CHANGE_MODE = 1001 DATA_CMD_GET_DEVICE_MODE = 1002 @@ -86,6 +88,7 @@ DATA_CMD_GET_MF1_USE_FIRST_BLOCK_COLL = 4014 DATA_CMD_SET_MF1_USE_FIRST_BLOCK_COLL = 4015 DATA_CMD_GET_MF1_WRITE_MODE = 4016 DATA_CMD_SET_MF1_WRITE_MODE = 4017 +DATA_CMD_GET_MF1_ANTI_COLL_DATA = 4018 DATA_CMD_SET_EM410X_EMU_ID = 5000 DATA_CMD_GET_EM410X_EMU_ID = 5001 @@ -272,8 +275,8 @@ class ButtonPressFunction(enum.IntEnum): elif self == ButtonPressFunction.SettingsButtonCycleSlotDec: return "Card slot number sequence decreases after pressing" elif self == ButtonPressFunction.SettingsButtonCloneIcUid: - return "Read the UID card number immediately after pressing, continue searching," + \ - "and simulate immediately after reading the card" + return ("Read the UID card number immediately after pressing, continue searching," + + "and simulate immediately after reading the card") return "Unknown" @@ -407,10 +410,7 @@ class ChameleonCMD: data.append(sync_max) return self.device.send_cmd_sync(DATA_CMD_MF1_DARKSIDE_ACQUIRE, 0x00, data, timeout=sync_max + 5) - @expect_response([ - chameleon_status.Device.HF_TAG_OK, - chameleon_status.Device.MF_ERR_AUTH, - ]) + @expect_response([chameleon_status.Device.HF_TAG_OK, chameleon_status.Device.MF_ERR_AUTH]) def auth_mf1_key(self, block, type_value, key): """ Verify the mf1 key, only verify the specified type of key for a single sector @@ -533,10 +533,8 @@ class ChameleonCMD: :param sense_type: Sense type to disable :return: """ - return self.device.send_cmd_sync(DATA_CMD_DELETE_SLOT_SENSE_TYPE, 0x00, bytearray([ - SlotNumber.to_fw(slot_index), - sense_type, - ])) + return self.device.send_cmd_sync(DATA_CMD_DELETE_SLOT_SENSE_TYPE, 0x00, + bytearray([SlotNumber.to_fw(slot_index), sense_type])) @expect_response(chameleon_status.Device.STATUS_DEVICE_SUCCESS) def set_slot_data_default(self, slot_index: SlotNumber, tag_type: TagSpecificType): @@ -784,11 +782,7 @@ class ChameleonCMD: """ Set config of button press function """ - return self.device.send_cmd_sync( - DATA_CMD_SET_BUTTON_PRESS_CONFIG, - 0x00, - bytearray([button, function]) - ) + return self.device.send_cmd_sync(DATA_CMD_SET_BUTTON_PRESS_CONFIG, 0x00, bytearray([button, function])) @expect_response(chameleon_status.Device.STATUS_DEVICE_SUCCESS) def get_long_button_press_fun(self, button: ButtonType): @@ -802,11 +796,7 @@ class ChameleonCMD: """ Set config of button press function """ - return self.device.send_cmd_sync( - DATA_CMD_SET_LONG_BUTTON_PRESS_CONFIG, - 0x00, - bytearray([button, function]) - ) + return self.device.send_cmd_sync(DATA_CMD_SET_LONG_BUTTON_PRESS_CONFIG, 0x00, bytearray([button, function])) @expect_response(chameleon_status.Device.STATUS_DEVICE_SUCCESS) def set_ble_connect_key(self, key: str): @@ -819,11 +809,7 @@ class ChameleonCMD: if len(data_bytes) != 6: raise ValueError("The ble connect key length must be 6") - return self.device.send_cmd_sync( - DATA_CMD_SET_BLE_CONNECT_KEY_CONFIG, - 0x00, - data_bytes - ) + return self.device.send_cmd_sync(DATA_CMD_SET_BLE_CONNECT_KEY_CONFIG, 0x00, data_bytes) def get_ble_connect_key(self): """ @@ -852,6 +838,41 @@ class ChameleonCMD: return commands + def get_device_type(self): + """ + Get device type + 0 - Chameleon Ultra + 1 - Chameleon Lite + """ + + return self.device.send_cmd_sync(DATA_CMD_GET_DEVICE, 0x00).data[0] + + def get_device_settings(self): + """ + Get all possible settings + For version 4: + settings[0] = SETTINGS_CURRENT_VERSION; // current version + settings[1] = settings_get_animation_config(); // animation mode + settings[2] = settings_get_button_press_config('A'); // short A button press mode + settings[3] = settings_get_button_press_config('B'); // short B button press mode + settings[4] = settings_get_long_button_press_config('A'); // long A button press mode + settings[5] = settings_get_long_button_press_config('B'); // long B button press mode + settings[6:12] = settings_get_ble_connect_key(); // BLE connection key + """ + data = self.device.send_cmd_sync(DATA_CMD_GET_SETTINGS, 0x00).data + if data[0] != CURRENT_VERSION_SETTINGS: + raise ValueError("Settings version in app doesn't match Chameleon response. Upgrade client or Chameleon " + "firmware") + return data + + def get_mf1_anti_coll_data(self): + """ + Get data from current slot (UID/SAK/ATQA) + :return: + """ + return self.device.send_cmd_sync(DATA_CMD_GET_MF1_ANTI_COLL_DATA, 0x00) + + if __name__ == '__main__': # connect to chameleon dev = chameleon_com.ChameleonCom()