[FL-1972], [FL-1920] Mifare Ultralight and NTAG separation (#918)
* nfc: rename read mifare ultralight menu * nfc: separate ntag and mifare ultralight * nfc: save Mifare Ultralight type * nfc: add valid ack and nack messages * nfc: add compatible write command implementation * nfc: support f6 target
This commit is contained in:
		
							parent
							
								
									439fb9c18d
								
							
						
					
					
						commit
						b0f582df99
					
				| @ -1,4 +1,5 @@ | |||||||
| #include "nfc_device.h" | #include "nfc_device.h" | ||||||
|  | #include "nfc_types.h" | ||||||
| 
 | 
 | ||||||
| #include <lib/toolbox/path.h> | #include <lib/toolbox/path.h> | ||||||
| #include <lib/flipper_file/flipper_file.h> | #include <lib/flipper_file/flipper_file.h> | ||||||
| @ -29,7 +30,7 @@ void nfc_device_prepare_format_string(NfcDevice* dev, string_t format_string) { | |||||||
|     } else if(dev->format == NfcDeviceSaveFormatBankCard) { |     } else if(dev->format == NfcDeviceSaveFormatBankCard) { | ||||||
|         string_set_str(format_string, "Bank card"); |         string_set_str(format_string, "Bank card"); | ||||||
|     } else if(dev->format == NfcDeviceSaveFormatMifareUl) { |     } else if(dev->format == NfcDeviceSaveFormatMifareUl) { | ||||||
|         string_set_str(format_string, "Mifare Ultralight"); |         string_set_str(format_string, nfc_mf_ul_type(dev->dev_data.mf_ul_data.type, true)); | ||||||
|     } else { |     } else { | ||||||
|         string_set_str(format_string, "Unknown"); |         string_set_str(format_string, "Unknown"); | ||||||
|     } |     } | ||||||
| @ -40,14 +41,20 @@ bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) { | |||||||
|         dev->format = NfcDeviceSaveFormatUid; |         dev->format = NfcDeviceSaveFormatUid; | ||||||
|         dev->dev_data.nfc_data.protocol = NfcDeviceProtocolUnknown; |         dev->dev_data.nfc_data.protocol = NfcDeviceProtocolUnknown; | ||||||
|         return true; |         return true; | ||||||
|     } else if(string_start_with_str_p(format_string, "Bank card")) { |     } | ||||||
|  |     if(string_start_with_str_p(format_string, "Bank card")) { | ||||||
|         dev->format = NfcDeviceSaveFormatBankCard; |         dev->format = NfcDeviceSaveFormatBankCard; | ||||||
|         dev->dev_data.nfc_data.protocol = NfcDeviceProtocolEMV; |         dev->dev_data.nfc_data.protocol = NfcDeviceProtocolEMV; | ||||||
|         return true; |         return true; | ||||||
|     } else if(string_start_with_str_p(format_string, "Mifare Ultralight")) { |     } | ||||||
|         dev->format = NfcDeviceSaveFormatMifareUl; |     // Check Mifare Ultralight types
 | ||||||
|         dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareUl; |     for(MfUltralightType type = MfUltralightTypeUnknown; type < MfUltralightTypeNum; type++) { | ||||||
|         return true; |         if(string_start_with_str_p(format_string, nfc_mf_ul_type(type, true))) { | ||||||
|  |             dev->format = NfcDeviceSaveFormatMifareUl; | ||||||
|  |             dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareUl; | ||||||
|  |             dev->dev_data.mf_ul_data.type = type; | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
|  | |||||||
| @ -54,12 +54,28 @@ static inline const char* nfc_get_nfca_type(rfalNfcaListenDeviceType type) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline const char* nfc_get_protocol(NfcProtocol protocol) { | static inline const char* nfc_guess_protocol(NfcProtocol protocol) { | ||||||
|     if(protocol == NfcDeviceProtocolEMV) { |     if(protocol == NfcDeviceProtocolEMV) { | ||||||
|         return "EMV bank card"; |         return "EMV bank card"; | ||||||
|     } else if(protocol == NfcDeviceProtocolMifareUl) { |     } else if(protocol == NfcDeviceProtocolMifareUl) { | ||||||
|         return "Mifare Ultralight"; |         return "Mifare Ultral/NTAG"; | ||||||
|     } else { |     } else { | ||||||
|         return "Unrecognized"; |         return "Unrecognized"; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | static inline const char* nfc_mf_ul_type(MfUltralightType type, bool full_name) { | ||||||
|  |     if(type == MfUltralightTypeNTAG213) { | ||||||
|  |         return "NTAG213"; | ||||||
|  |     } else if(type == MfUltralightTypeNTAG215) { | ||||||
|  |         return "NTAG215"; | ||||||
|  |     } else if(type == MfUltralightTypeNTAG216) { | ||||||
|  |         return "NTAG216"; | ||||||
|  |     } else if(type == MfUltralightTypeUL11 && full_name) { | ||||||
|  |         return "Mifare Ultralight 11"; | ||||||
|  |     } else if(type == MfUltralightTypeUL21 && full_name) { | ||||||
|  |         return "Mifare Ultralight 21"; | ||||||
|  |     } else { | ||||||
|  |         return "Mifare Ultralight"; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
							
								
								
									
										13
									
								
								applications/nfc/nfc_worker.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										13
									
								
								applications/nfc/nfc_worker.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -503,7 +503,7 @@ void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker) { | |||||||
|                     FURI_LOG_D( |                     FURI_LOG_D( | ||||||
|                         TAG, |                         TAG, | ||||||
|                         "Mifare Ultralight Type: %d, Pages: %d", |                         "Mifare Ultralight Type: %d, Pages: %d", | ||||||
|                         mf_ul_read.type, |                         mf_ul_read.data.type, | ||||||
|                         mf_ul_read.pages_to_read); |                         mf_ul_read.pages_to_read); | ||||||
|                     FURI_LOG_D(TAG, "Reading signature ..."); |                     FURI_LOG_D(TAG, "Reading signature ..."); | ||||||
|                     tx_len = mf_ul_prepare_read_signature(tx_buff); |                     tx_len = mf_ul_prepare_read_signature(tx_buff); | ||||||
| @ -629,8 +629,14 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { | |||||||
|                     tx_len = mf_ul_prepare_emulation_response( |                     tx_len = mf_ul_prepare_emulation_response( | ||||||
|                         rx_buff, *rx_len, tx_buff, &mf_ul_emulate); |                         rx_buff, *rx_len, tx_buff, &mf_ul_emulate); | ||||||
|                     if(tx_len > 0) { |                     if(tx_len > 0) { | ||||||
|                         err = |                         if(tx_len < 8) { | ||||||
|                             furi_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false); |                             err = furi_hal_nfc_raw_bitstream_exchange( | ||||||
|  |                                 tx_buff, tx_len, &rx_buff, &rx_len, false); | ||||||
|  |                             *rx_len /= 8; | ||||||
|  |                         } else { | ||||||
|  |                             err = furi_hal_nfc_data_exchange( | ||||||
|  |                                 tx_buff, tx_len / 8, &rx_buff, &rx_len, false); | ||||||
|  |                         } | ||||||
|                         if(err == ERR_NONE) { |                         if(err == ERR_NONE) { | ||||||
|                             continue; |                             continue; | ||||||
|                         } else { |                         } else { | ||||||
| @ -638,7 +644,6 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { | |||||||
|                             break; |                             break; | ||||||
|                         } |                         } | ||||||
|                     } else { |                     } else { | ||||||
|                         FURI_LOG_D(TAG, "Not valid command: %02X", rx_buff[0]); |  | ||||||
|                         furi_hal_nfc_deactivate(); |                         furi_hal_nfc_deactivate(); | ||||||
|                         break; |                         break; | ||||||
|                     } |                     } | ||||||
|  | |||||||
| @ -44,15 +44,15 @@ void nfc_scene_delete_on_enter(void* context) { | |||||||
|     } |     } | ||||||
|     widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, uid_str); |     widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, uid_str); | ||||||
| 
 | 
 | ||||||
|     if(data->protocol > NfcDeviceProtocolUnknown) { |     const char* protocol_name = NULL; | ||||||
|  |     if(data->protocol == NfcDeviceProtocolEMV) { | ||||||
|  |         protocol_name = nfc_guess_protocol(data->protocol); | ||||||
|  |     } else if(data->protocol == NfcDeviceProtocolMifareUl) { | ||||||
|  |         protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false); | ||||||
|  |     } | ||||||
|  |     if(protocol_name) { | ||||||
|         widget_add_string_element( |         widget_add_string_element( | ||||||
|             nfc->widget, |             nfc->widget, 10, 32, AlignLeft, AlignTop, FontSecondary, protocol_name); | ||||||
|             10, |  | ||||||
|             32, |  | ||||||
|             AlignLeft, |  | ||||||
|             AlignTop, |  | ||||||
|             FontSecondary, |  | ||||||
|             nfc_get_protocol(data->protocol)); |  | ||||||
|     } |     } | ||||||
|     // TODO change dinamically
 |     // TODO change dinamically
 | ||||||
|     widget_add_string_element(nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A"); |     widget_add_string_element(nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A"); | ||||||
|  | |||||||
| @ -68,15 +68,15 @@ void nfc_scene_device_info_on_enter(void* context) { | |||||||
|     } |     } | ||||||
|     widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, uid_str); |     widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, uid_str); | ||||||
| 
 | 
 | ||||||
|     if(data->protocol > NfcDeviceProtocolUnknown) { |     const char* protocol_name = NULL; | ||||||
|  |     if(data->protocol == NfcDeviceProtocolEMV) { | ||||||
|  |         protocol_name = nfc_guess_protocol(data->protocol); | ||||||
|  |     } else if(data->protocol == NfcDeviceProtocolMifareUl) { | ||||||
|  |         protocol_name = nfc_mf_ul_type(nfc->dev->dev_data.mf_ul_data.type, false); | ||||||
|  |     } | ||||||
|  |     if(protocol_name) { | ||||||
|         widget_add_string_element( |         widget_add_string_element( | ||||||
|             nfc->widget, |             nfc->widget, 10, 32, AlignLeft, AlignTop, FontSecondary, protocol_name); | ||||||
|             10, |  | ||||||
|             32, |  | ||||||
|             AlignLeft, |  | ||||||
|             AlignTop, |  | ||||||
|             FontSecondary, |  | ||||||
|             nfc_get_protocol(data->protocol)); |  | ||||||
|     } |     } | ||||||
|     // TODO change dinamically
 |     // TODO change dinamically
 | ||||||
|     widget_add_string_element(nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A"); |     widget_add_string_element(nfc->widget, 118, 32, AlignRight, AlignTop, FontSecondary, "NFC-A"); | ||||||
|  | |||||||
| @ -27,7 +27,7 @@ void nfc_scene_read_card_success_on_enter(void* context) { | |||||||
|             nfc, |             nfc, | ||||||
|             NFC_SCENE_READ_SUCCESS_SHIFT "%s\n" NFC_SCENE_READ_SUCCESS_SHIFT |             NFC_SCENE_READ_SUCCESS_SHIFT "%s\n" NFC_SCENE_READ_SUCCESS_SHIFT | ||||||
|                                          "ATQA: %02X%02X SAK: %02X\nUID: %02X %02X %02X %02X", |                                          "ATQA: %02X%02X SAK: %02X\nUID: %02X %02X %02X %02X", | ||||||
|             nfc_get_protocol(data->protocol), |             nfc_guess_protocol(data->protocol), | ||||||
|             data->atqa[0], |             data->atqa[0], | ||||||
|             data->atqa[1], |             data->atqa[1], | ||||||
|             data->sak, |             data->sak, | ||||||
| @ -41,7 +41,7 @@ void nfc_scene_read_card_success_on_enter(void* context) { | |||||||
|             NFC_SCENE_READ_SUCCESS_SHIFT |             NFC_SCENE_READ_SUCCESS_SHIFT | ||||||
|             "%s\n" NFC_SCENE_READ_SUCCESS_SHIFT |             "%s\n" NFC_SCENE_READ_SUCCESS_SHIFT | ||||||
|             "ATQA: %02X%02X SAK: %02X\nUID: %02X %02X %02X %02X %02X %02X %02X", |             "ATQA: %02X%02X SAK: %02X\nUID: %02X %02X %02X %02X %02X %02X %02X", | ||||||
|             nfc_get_protocol(data->protocol), |             nfc_guess_protocol(data->protocol), | ||||||
|             data->atqa[0], |             data->atqa[0], | ||||||
|             data->atqa[1], |             data->atqa[1], | ||||||
|             data->sak, |             data->sak, | ||||||
|  | |||||||
| @ -28,11 +28,13 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) { | |||||||
| 
 | 
 | ||||||
|     // Setup dialog view
 |     // Setup dialog view
 | ||||||
|     NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; |     NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; | ||||||
|  |     MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; | ||||||
|     DialogEx* dialog_ex = nfc->dialog_ex; |     DialogEx* dialog_ex = nfc->dialog_ex; | ||||||
|     dialog_ex_set_left_button_text(dialog_ex, "Retry"); |     dialog_ex_set_left_button_text(dialog_ex, "Retry"); | ||||||
|     dialog_ex_set_right_button_text(dialog_ex, "More"); |     dialog_ex_set_right_button_text(dialog_ex, "More"); | ||||||
|     dialog_ex_set_center_button_text(dialog_ex, "Data"); |     dialog_ex_set_center_button_text(dialog_ex, "Data"); | ||||||
|     dialog_ex_set_header(dialog_ex, "Mifare Ultralight", 22, 8, AlignLeft, AlignCenter); |     dialog_ex_set_header( | ||||||
|  |         dialog_ex, nfc_mf_ul_type(mf_ul_data->type, true), 64, 8, AlignCenter, AlignCenter); | ||||||
|     dialog_ex_set_icon(dialog_ex, 8, 13, &I_Medium_chip_22x21); |     dialog_ex_set_icon(dialog_ex, 8, 13, &I_Medium_chip_22x21); | ||||||
|     // Display UID
 |     // Display UID
 | ||||||
|     nfc_text_store_set( |     nfc_text_store_set( | ||||||
| @ -54,7 +56,6 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) { | |||||||
|     dialog_ex_set_result_callback(dialog_ex, nfc_scene_read_mifare_ul_success_dialog_callback); |     dialog_ex_set_result_callback(dialog_ex, nfc_scene_read_mifare_ul_success_dialog_callback); | ||||||
| 
 | 
 | ||||||
|     // Setup TextBox view
 |     // Setup TextBox view
 | ||||||
|     MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data; |  | ||||||
|     TextBox* text_box = nfc->text_box; |     TextBox* text_box = nfc->text_box; | ||||||
|     text_box_set_context(text_box, nfc); |     text_box_set_context(text_box, nfc); | ||||||
|     text_box_set_exit_callback(text_box, nfc_scene_read_mifare_ul_success_text_box_callback); |     text_box_set_exit_callback(text_box, nfc_scene_read_mifare_ul_success_text_box_callback); | ||||||
|  | |||||||
| @ -23,7 +23,7 @@ void nfc_scene_scripts_menu_on_enter(void* context) { | |||||||
|         nfc); |         nfc); | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         submenu, |         submenu, | ||||||
|         "Read Mifare Ultralight", |         "Read Mifare Ultral/Ntag", | ||||||
|         SubmenuIndexMifareUltralight, |         SubmenuIndexMifareUltralight, | ||||||
|         nfc_scene_scripts_menu_submenu_callback, |         nfc_scene_scripts_menu_submenu_callback, | ||||||
|         nfc); |         nfc); | ||||||
|  | |||||||
| @ -131,7 +131,7 @@ bool furi_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t s | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len) { | bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len) { | ||||||
|     ReturnCode ret = rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0); |     ReturnCode ret = rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT); | ||||||
|     return ret == ERR_NONE; |     return ret == ERR_NONE; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -141,7 +141,42 @@ ReturnCode furi_hal_nfc_data_exchange(uint8_t* tx_buff, uint16_t tx_len, uint8_t | |||||||
| 
 | 
 | ||||||
|     ReturnCode ret; |     ReturnCode ret; | ||||||
|     rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; |     rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; | ||||||
|     ret = rfalNfcDataExchangeStart(tx_buff, tx_len, rx_buff, rx_len, 0); |     ret = rfalNfcDataExchangeStart(tx_buff, tx_len, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT); | ||||||
|  |     if(ret != ERR_NONE) { | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |     uint32_t start = DWT->CYCCNT; | ||||||
|  |     while(state != RFAL_NFC_STATE_DATAEXCHANGE_DONE) { | ||||||
|  |         rfalNfcWorker(); | ||||||
|  |         state = rfalNfcGetState(); | ||||||
|  |         ret = rfalNfcDataExchangeGetStatus(); | ||||||
|  |         if(ret > ERR_SLEEP_REQ) { | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  |         if(ret == ERR_BUSY) { | ||||||
|  |             if(DWT->CYCCNT - start > 1000 * clocks_in_ms) { | ||||||
|  |                 return ERR_TIMEOUT; | ||||||
|  |             } | ||||||
|  |             continue; | ||||||
|  |         } else { | ||||||
|  |             start = DWT->CYCCNT; | ||||||
|  |         } | ||||||
|  |         taskYIELD(); | ||||||
|  |     } | ||||||
|  |     if(deactivate) { | ||||||
|  |         rfalNfcDeactivate(false); | ||||||
|  |         rfalLowPowerModeStart(); | ||||||
|  |     } | ||||||
|  |     return ERR_NONE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ReturnCode furi_hal_nfc_raw_bitstream_exchange(uint8_t* tx_buff, uint16_t tx_bit_len, uint8_t** rx_buff, uint16_t** rx_bit_len, bool deactivate) { | ||||||
|  |     furi_assert(rx_buff); | ||||||
|  |     furi_assert(rx_bit_len); | ||||||
|  | 
 | ||||||
|  |     ReturnCode ret; | ||||||
|  |     rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; | ||||||
|  |     ret = rfalNfcDataExchangeStart(tx_buff, tx_bit_len, rx_buff, rx_bit_len, 0, RFAL_TXRX_FLAGS_RAW); | ||||||
|     if(ret != ERR_NONE) { |     if(ret != ERR_NONE) { | ||||||
|         return ret; |         return ret; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -131,7 +131,7 @@ bool furi_hal_nfc_listen(uint8_t* uid, uint8_t uid_len, uint8_t* atqa, uint8_t s | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len) { | bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len) { | ||||||
|     ReturnCode ret = rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0); |     ReturnCode ret = rfalNfcDataExchangeStart(NULL, 0, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT); | ||||||
|     return ret == ERR_NONE; |     return ret == ERR_NONE; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -141,7 +141,42 @@ ReturnCode furi_hal_nfc_data_exchange(uint8_t* tx_buff, uint16_t tx_len, uint8_t | |||||||
| 
 | 
 | ||||||
|     ReturnCode ret; |     ReturnCode ret; | ||||||
|     rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; |     rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; | ||||||
|     ret = rfalNfcDataExchangeStart(tx_buff, tx_len, rx_buff, rx_len, 0); |     ret = rfalNfcDataExchangeStart(tx_buff, tx_len, rx_buff, rx_len, 0, RFAL_TXRX_FLAGS_DEFAULT); | ||||||
|  |     if(ret != ERR_NONE) { | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  |     uint32_t start = DWT->CYCCNT; | ||||||
|  |     while(state != RFAL_NFC_STATE_DATAEXCHANGE_DONE) { | ||||||
|  |         rfalNfcWorker(); | ||||||
|  |         state = rfalNfcGetState(); | ||||||
|  |         ret = rfalNfcDataExchangeGetStatus(); | ||||||
|  |         if(ret > ERR_SLEEP_REQ) { | ||||||
|  |             return ret; | ||||||
|  |         } | ||||||
|  |         if(ret == ERR_BUSY) { | ||||||
|  |             if(DWT->CYCCNT - start > 1000 * clocks_in_ms) { | ||||||
|  |                 return ERR_TIMEOUT; | ||||||
|  |             } | ||||||
|  |             continue; | ||||||
|  |         } else { | ||||||
|  |             start = DWT->CYCCNT; | ||||||
|  |         } | ||||||
|  |         taskYIELD(); | ||||||
|  |     } | ||||||
|  |     if(deactivate) { | ||||||
|  |         rfalNfcDeactivate(false); | ||||||
|  |         rfalLowPowerModeStart(); | ||||||
|  |     } | ||||||
|  |     return ERR_NONE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ReturnCode furi_hal_nfc_raw_bitstream_exchange(uint8_t* tx_buff, uint16_t tx_bit_len, uint8_t** rx_buff, uint16_t** rx_bit_len, bool deactivate) { | ||||||
|  |     furi_assert(rx_buff); | ||||||
|  |     furi_assert(rx_bit_len); | ||||||
|  | 
 | ||||||
|  |     ReturnCode ret; | ||||||
|  |     rfalNfcState state = RFAL_NFC_STATE_ACTIVATED; | ||||||
|  |     ret = rfalNfcDataExchangeStart(tx_buff, tx_bit_len, rx_buff, rx_bit_len, 0, RFAL_TXRX_FLAGS_RAW); | ||||||
|     if(ret != ERR_NONE) { |     if(ret != ERR_NONE) { | ||||||
|         return ret; |         return ret; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -87,6 +87,8 @@ bool furi_hal_nfc_get_first_frame(uint8_t** rx_buff, uint16_t** rx_len); | |||||||
|  */ |  */ | ||||||
| ReturnCode furi_hal_nfc_data_exchange(uint8_t* tx_buff, uint16_t tx_len, uint8_t** rx_buff, uint16_t** rx_len, bool deactivate); | ReturnCode furi_hal_nfc_data_exchange(uint8_t* tx_buff, uint16_t tx_len, uint8_t** rx_buff, uint16_t** rx_len, bool deactivate); | ||||||
| 
 | 
 | ||||||
|  | ReturnCode furi_hal_nfc_raw_bitstream_exchange(uint8_t* tx_buff, uint16_t tx_bit_len, uint8_t** rx_buff, uint16_t** rx_bit_len, bool deactivate); | ||||||
|  | 
 | ||||||
| /** NFC deactivate and start sleep
 | /** NFC deactivate and start sleep
 | ||||||
|  */ |  */ | ||||||
| void furi_hal_nfc_deactivate(); | void furi_hal_nfc_deactivate(); | ||||||
|  | |||||||
| @ -364,7 +364,7 @@ ReturnCode rfalNfcSelect( uint8_t devIdx ); | |||||||
|  * \return ERR_NONE         : No error |  * \return ERR_NONE         : No error | ||||||
|  ***************************************************************************** |  ***************************************************************************** | ||||||
|  */ |  */ | ||||||
| ReturnCode rfalNfcDataExchangeStart( uint8_t *txData, uint16_t txDataLen, uint8_t **rxData, uint16_t **rvdLen, uint32_t fwt ); | ReturnCode rfalNfcDataExchangeStart( uint8_t *txData, uint16_t txDataLen, uint8_t **rxData, uint16_t **rvdLen, uint32_t fwt, uint32_t tx_flag); | ||||||
| 
 | 
 | ||||||
| /*! 
 | /*! 
 | ||||||
|  ***************************************************************************** |  ***************************************************************************** | ||||||
|  | |||||||
| @ -110,7 +110,7 @@ | |||||||
| 
 | 
 | ||||||
| /*! Default TxRx flags: Tx CRC automatic, Rx CRC removed, NFCIP1 mode off, AGC On, Tx Parity automatic, Rx Parity removed */ | /*! Default TxRx flags: Tx CRC automatic, Rx CRC removed, NFCIP1 mode off, AGC On, Tx Parity automatic, Rx Parity removed */ | ||||||
| #define RFAL_TXRX_FLAGS_DEFAULT                    ( (uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO) | #define RFAL_TXRX_FLAGS_DEFAULT                    ( (uint32_t)RFAL_TXRX_FLAGS_CRC_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_AUTO | (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO) | ||||||
| 
 | #define RFAL_TXRX_FLAGS_RAW                        ( (uint32_t)RFAL_TXRX_FLAGS_CRC_TX_MANUAL | (uint32_t)RFAL_TXRX_FLAGS_CRC_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_NFCIP1_OFF | (uint32_t)RFAL_TXRX_FLAGS_AGC_ON | (uint32_t)RFAL_TXRX_FLAGS_PAR_RX_REMV | (uint32_t)RFAL_TXRX_FLAGS_PAR_TX_NONE| (uint32_t)RFAL_TXRX_FLAGS_NFCV_FLAG_AUTO) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #define RFAL_LM_MASK_NFCA                          ((uint32_t)1U<<(uint8_t)RFAL_MODE_LISTEN_NFCA)        /*!< Bitmask for Listen Mode enabling NFCA    */ | #define RFAL_LM_MASK_NFCA                          ((uint32_t)1U<<(uint8_t)RFAL_MODE_LISTEN_NFCA)        /*!< Bitmask for Listen Mode enabling NFCA    */ | ||||||
|  | |||||||
| @ -550,7 +550,7 @@ void rfalNfcWorker( void ) | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /*******************************************************************************/ | /*******************************************************************************/ | ||||||
| ReturnCode rfalNfcDataExchangeStart( uint8_t *txData, uint16_t txDataLen, uint8_t **rxData, uint16_t **rvdLen, uint32_t fwt ) | ReturnCode rfalNfcDataExchangeStart( uint8_t *txData, uint16_t txDataLen, uint8_t **rxData, uint16_t **rvdLen, uint32_t fwt, uint32_t flags) | ||||||
| { | { | ||||||
|     ReturnCode            err; |     ReturnCode            err; | ||||||
|     rfalTransceiveContext ctx; |     rfalTransceiveContext ctx; | ||||||
| @ -588,7 +588,10 @@ ReturnCode rfalNfcDataExchangeStart( uint8_t *txData, uint16_t txDataLen, uint8_ | |||||||
|             /*******************************************************************************/ |             /*******************************************************************************/ | ||||||
|             case RFAL_NFC_INTERFACE_RF: |             case RFAL_NFC_INTERFACE_RF: | ||||||
|      |      | ||||||
|                 rfalCreateByteFlagsTxRxContext( ctx, (uint8_t*)txData, txDataLen, gNfcDev.rxBuf.rfBuf, sizeof(gNfcDev.rxBuf.rfBuf), &gNfcDev.rxLen, RFAL_TXRX_FLAGS_DEFAULT, fwt ); |                 rfalCreateByteFlagsTxRxContext( ctx, (uint8_t*)txData, txDataLen, gNfcDev.rxBuf.rfBuf, sizeof(gNfcDev.rxBuf.rfBuf), &gNfcDev.rxLen, flags, fwt ); | ||||||
|  |                 if(flags == RFAL_TXRX_FLAGS_RAW) { | ||||||
|  |                     ctx.txBufLen = txDataLen; | ||||||
|  |                 } | ||||||
|                 *rxData = (uint8_t*)gNfcDev.rxBuf.rfBuf; |                 *rxData = (uint8_t*)gNfcDev.rxBuf.rfBuf; | ||||||
|                 *rvdLen = (uint16_t*)&gNfcDev.rxLen; |                 *rvdLen = (uint16_t*)&gNfcDev.rxLen; | ||||||
|                 err = rfalStartTransceive( &ctx ); |                 err = rfalStartTransceive( &ctx ); | ||||||
|  | |||||||
| @ -16,23 +16,23 @@ void mf_ul_parse_get_version_response(uint8_t* buff, MifareUlDevice* mf_ul_read) | |||||||
|     MfUltralightVersion* version = (MfUltralightVersion*) buff; |     MfUltralightVersion* version = (MfUltralightVersion*) buff; | ||||||
|     memcpy(&mf_ul_read->data.version, version, sizeof(MfUltralightVersion)); |     memcpy(&mf_ul_read->data.version, version, sizeof(MfUltralightVersion)); | ||||||
|     if(version->storage_size == 0x0B || version->storage_size == 0x00) { |     if(version->storage_size == 0x0B || version->storage_size == 0x00) { | ||||||
|         mf_ul_read->type = MfUltralightTypeUL11; |         mf_ul_read->data.type = MfUltralightTypeUL11; | ||||||
|         mf_ul_read->pages_to_read = 20; |         mf_ul_read->pages_to_read = 20; | ||||||
|         mf_ul_read->support_fast_read = true; |         mf_ul_read->support_fast_read = true; | ||||||
|     } else if(version->storage_size == 0x0E) { |     } else if(version->storage_size == 0x0E) { | ||||||
|         mf_ul_read->type = MfUltralightTypeUL21; |         mf_ul_read->data.type = MfUltralightTypeUL21; | ||||||
|         mf_ul_read->pages_to_read = 41; |         mf_ul_read->pages_to_read = 41; | ||||||
|         mf_ul_read->support_fast_read = true; |         mf_ul_read->support_fast_read = true; | ||||||
|     } else if(version->storage_size == 0x0F) { |     } else if(version->storage_size == 0x0F) { | ||||||
|         mf_ul_read->type = MfUltralightTypeNTAG213; |         mf_ul_read->data.type = MfUltralightTypeNTAG213; | ||||||
|         mf_ul_read->pages_to_read = 45; |         mf_ul_read->pages_to_read = 45; | ||||||
|         mf_ul_read->support_fast_read = false; |         mf_ul_read->support_fast_read = false; | ||||||
|     } else if(version->storage_size == 0x11) { |     } else if(version->storage_size == 0x11) { | ||||||
|         mf_ul_read->type = MfUltralightTypeNTAG215; |         mf_ul_read->data.type = MfUltralightTypeNTAG215; | ||||||
|         mf_ul_read->pages_to_read = 135; |         mf_ul_read->pages_to_read = 135; | ||||||
|         mf_ul_read->support_fast_read = false; |         mf_ul_read->support_fast_read = false; | ||||||
|     } else if(version->storage_size == 0x13) { |     } else if(version->storage_size == 0x13) { | ||||||
|         mf_ul_read->type = MfUltralightTypeNTAG216; |         mf_ul_read->data.type = MfUltralightTypeNTAG216; | ||||||
|         mf_ul_read->pages_to_read = 231; |         mf_ul_read->pages_to_read = 231; | ||||||
|         mf_ul_read->support_fast_read = false; |         mf_ul_read->support_fast_read = false; | ||||||
|     } else { |     } else { | ||||||
| @ -41,7 +41,7 @@ void mf_ul_parse_get_version_response(uint8_t* buff, MifareUlDevice* mf_ul_read) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void mf_ul_set_default_version(MifareUlDevice* mf_ul_read) { | void mf_ul_set_default_version(MifareUlDevice* mf_ul_read) { | ||||||
|     mf_ul_read->type = MfUltralightTypeUnknown; |     mf_ul_read->data.type = MfUltralightTypeUnknown; | ||||||
|     mf_ul_read->pages_to_read = 16; |     mf_ul_read->pages_to_read = 16; | ||||||
|     mf_ul_read->support_fast_read = false; |     mf_ul_read->support_fast_read = false; | ||||||
| } | } | ||||||
| @ -148,26 +148,26 @@ void mf_ul_prepare_emulation(MifareUlDevice* mf_ul_emulate, MifareUlData* data) | |||||||
|     mf_ul_emulate->auth_data = NULL; |     mf_ul_emulate->auth_data = NULL; | ||||||
|     mf_ul_emulate->data_changed = false; |     mf_ul_emulate->data_changed = false; | ||||||
|     if(data->version.storage_size == 0) { |     if(data->version.storage_size == 0) { | ||||||
|         mf_ul_emulate->type = MfUltralightTypeUnknown; |         mf_ul_emulate->data.type = MfUltralightTypeUnknown; | ||||||
|         mf_ul_emulate->support_fast_read = false; |         mf_ul_emulate->support_fast_read = false; | ||||||
|     } else if(data->version.storage_size == 0x0B) { |     } else if(data->version.storage_size == 0x0B) { | ||||||
|         mf_ul_emulate->type = MfUltralightTypeUL11; |         mf_ul_emulate->data.type = MfUltralightTypeUL11; | ||||||
|         mf_ul_emulate->support_fast_read = true; |         mf_ul_emulate->support_fast_read = true; | ||||||
|     } else if(data->version.storage_size == 0x0E) { |     } else if(data->version.storage_size == 0x0E) { | ||||||
|         mf_ul_emulate->type = MfUltralightTypeUL21; |         mf_ul_emulate->data.type = MfUltralightTypeUL21; | ||||||
|         mf_ul_emulate->support_fast_read = true; |         mf_ul_emulate->support_fast_read = true; | ||||||
|     } else if(data->version.storage_size == 0x0F) { |     } else if(data->version.storage_size == 0x0F) { | ||||||
|         mf_ul_emulate->type = MfUltralightTypeNTAG213; |         mf_ul_emulate->data.type = MfUltralightTypeNTAG213; | ||||||
|         mf_ul_emulate->support_fast_read = true; |         mf_ul_emulate->support_fast_read = true; | ||||||
|     } else if(data->version.storage_size == 0x11) { |     } else if(data->version.storage_size == 0x11) { | ||||||
|         mf_ul_emulate->type = MfUltralightTypeNTAG215; |         mf_ul_emulate->data.type = MfUltralightTypeNTAG215; | ||||||
|         mf_ul_emulate->support_fast_read = true; |         mf_ul_emulate->support_fast_read = true; | ||||||
|     } else if(data->version.storage_size == 0x13) { |     } else if(data->version.storage_size == 0x13) { | ||||||
|         mf_ul_emulate->type = MfUltralightTypeNTAG216; |         mf_ul_emulate->data.type = MfUltralightTypeNTAG216; | ||||||
|         mf_ul_emulate->support_fast_read = true; |         mf_ul_emulate->support_fast_read = true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(mf_ul_emulate->type >= MfUltralightTypeNTAG213) { |     if(mf_ul_emulate->data.type >= MfUltralightTypeNTAG213) { | ||||||
|         uint16_t pwd_page = (data->data_size / 4) - 2; |         uint16_t pwd_page = (data->data_size / 4) - 2; | ||||||
|         mf_ul_emulate->auth_data = (MifareUlAuthData*)&data->data[pwd_page * 4]; |         mf_ul_emulate->auth_data = (MifareUlAuthData*)&data->data[pwd_page * 4]; | ||||||
|     } |     } | ||||||
| @ -178,7 +178,7 @@ void mf_ul_protect_auth_data_on_read_command( | |||||||
|     uint8_t start_page, |     uint8_t start_page, | ||||||
|     uint8_t end_page, |     uint8_t end_page, | ||||||
|     MifareUlDevice* mf_ul_emulate) { |     MifareUlDevice* mf_ul_emulate) { | ||||||
|     if(mf_ul_emulate->type >= MfUltralightTypeNTAG213) { |     if(mf_ul_emulate->data.type >= MfUltralightTypeNTAG213) { | ||||||
|         uint8_t pwd_page = (mf_ul_emulate->data.data_size / 4) - 2; |         uint8_t pwd_page = (mf_ul_emulate->data.data_size / 4) - 2; | ||||||
|         uint8_t pack_page = pwd_page + 1; |         uint8_t pack_page = pwd_page + 1; | ||||||
|         if((start_page <= pwd_page) && (end_page >= pwd_page)) { |         if((start_page <= pwd_page) && (end_page >= pwd_page)) { | ||||||
| @ -193,27 +193,43 @@ void mf_ul_protect_auth_data_on_read_command( | |||||||
| uint16_t mf_ul_prepare_emulation_response(uint8_t* buff_rx, uint16_t len_rx, uint8_t* buff_tx, MifareUlDevice* mf_ul_emulate) { | uint16_t mf_ul_prepare_emulation_response(uint8_t* buff_rx, uint16_t len_rx, uint8_t* buff_tx, MifareUlDevice* mf_ul_emulate) { | ||||||
|     uint8_t cmd = buff_rx[0]; |     uint8_t cmd = buff_rx[0]; | ||||||
|     uint16_t page_num = mf_ul_emulate->data.data_size / 4; |     uint16_t page_num = mf_ul_emulate->data.data_size / 4; | ||||||
|     uint16_t tx_len = 0; |     uint16_t tx_bytes = 0; | ||||||
|  |     uint16_t tx_bits = 0; | ||||||
|  |     bool command_parsed = false; | ||||||
| 
 | 
 | ||||||
|     if(cmd == MF_UL_GET_VERSION_CMD) { |     // Check composite commands
 | ||||||
|         if(mf_ul_emulate->type != MfUltralightTypeUnknown) { |     if(mf_ul_emulate->comp_write_cmd_started) { | ||||||
|             tx_len = sizeof(mf_ul_emulate->data.version); |         // Compatibility write is the only one composit command
 | ||||||
|             memcpy(buff_tx, &mf_ul_emulate->data.version, tx_len); |         if(len_rx == 16) { | ||||||
|  |             memcpy(&mf_ul_emulate->data.data[mf_ul_emulate->comp_write_page_addr * 4], buff_rx, 4); | ||||||
|  |             mf_ul_emulate->data_changed = true; | ||||||
|  |             // Send ACK message
 | ||||||
|  |             buff_tx[0] = 0x0A; | ||||||
|  |             tx_bits = 4; | ||||||
|  |             command_parsed = true; | ||||||
|  |         } | ||||||
|  |         mf_ul_emulate->comp_write_cmd_started = false; | ||||||
|  |     } else if(cmd == MF_UL_GET_VERSION_CMD) { | ||||||
|  |         if(mf_ul_emulate->data.type != MfUltralightTypeUnknown) { | ||||||
|  |             tx_bytes = sizeof(mf_ul_emulate->data.version); | ||||||
|  |             memcpy(buff_tx, &mf_ul_emulate->data.version, tx_bytes); | ||||||
|  |             command_parsed = true; | ||||||
|         } |         } | ||||||
|     } else if(cmd == MF_UL_READ_CMD) { |     } else if(cmd == MF_UL_READ_CMD) { | ||||||
|         uint8_t start_page = buff_rx[1]; |         uint8_t start_page = buff_rx[1]; | ||||||
|         if(start_page < page_num) { |         if(start_page < page_num) { | ||||||
|             tx_len = 16; |             tx_bytes = 16; | ||||||
|             if(start_page + 4 > page_num) { |             if(start_page + 4 > page_num) { | ||||||
|                 // Handle roll-over mechanism
 |                 // Handle roll-over mechanism
 | ||||||
|                 uint8_t end_pages_num = page_num - start_page; |                 uint8_t end_pages_num = page_num - start_page; | ||||||
|                 memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], end_pages_num * 4); |                 memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], end_pages_num * 4); | ||||||
|                 memcpy(&buff_tx[end_pages_num * 4], mf_ul_emulate->data.data, (4 - end_pages_num) * 4); |                 memcpy(&buff_tx[end_pages_num * 4], mf_ul_emulate->data.data, (4 - end_pages_num) * 4); | ||||||
|             } else { |             } else { | ||||||
|                 memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_len); |                 memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_bytes); | ||||||
|             } |             } | ||||||
|             mf_ul_protect_auth_data_on_read_command( |             mf_ul_protect_auth_data_on_read_command( | ||||||
|                 buff_tx, start_page, (start_page + 4), mf_ul_emulate); |                 buff_tx, start_page, (start_page + 4), mf_ul_emulate); | ||||||
|  |             command_parsed = true; | ||||||
|         } |         } | ||||||
|     } else if(cmd == MF_UL_FAST_READ_CMD) { |     } else if(cmd == MF_UL_FAST_READ_CMD) { | ||||||
|         if(mf_ul_emulate->support_fast_read) { |         if(mf_ul_emulate->support_fast_read) { | ||||||
| @ -221,14 +237,11 @@ uint16_t mf_ul_prepare_emulation_response(uint8_t* buff_rx, uint16_t len_rx, uin | |||||||
|             uint8_t end_page = buff_rx[2]; |             uint8_t end_page = buff_rx[2]; | ||||||
|             if((start_page < page_num) && |             if((start_page < page_num) && | ||||||
|                (end_page < page_num) && (start_page < (end_page + 1))) { |                (end_page < page_num) && (start_page < (end_page + 1))) { | ||||||
|                 tx_len = ((end_page + 1) - start_page) * 4; |                 tx_bytes = ((end_page + 1) - start_page) * 4; | ||||||
|                 memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_len); |                 memcpy(buff_tx, &mf_ul_emulate->data.data[start_page * 4], tx_bytes); | ||||||
|                 mf_ul_protect_auth_data_on_read_command( |                 mf_ul_protect_auth_data_on_read_command( | ||||||
|                     buff_tx, start_page, end_page, mf_ul_emulate); |                     buff_tx, start_page, end_page, mf_ul_emulate); | ||||||
|             } else { |                 command_parsed = true; | ||||||
|                 // TODO make 4-bit NAK
 |  | ||||||
|                 buff_tx[0] = 0x0; |  | ||||||
|                 tx_len = 1; |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } else if(cmd == MF_UL_WRITE) { |     } else if(cmd == MF_UL_WRITE) { | ||||||
| @ -236,9 +249,20 @@ uint16_t mf_ul_prepare_emulation_response(uint8_t* buff_rx, uint16_t len_rx, uin | |||||||
|         if((write_page > 1) && (write_page < page_num - 2)) { |         if((write_page > 1) && (write_page < page_num - 2)) { | ||||||
|             memcpy(&mf_ul_emulate->data.data[write_page * 4], &buff_rx[2], 4); |             memcpy(&mf_ul_emulate->data.data[write_page * 4], &buff_rx[2], 4); | ||||||
|             mf_ul_emulate->data_changed = true; |             mf_ul_emulate->data_changed = true; | ||||||
|             // TODO make 4-bit ACK
 |             // ACK
 | ||||||
|             buff_tx[0] = 0x0A; |             buff_tx[0] = 0x0A; | ||||||
|             tx_len = 1; |             tx_bits = 4; | ||||||
|  |             command_parsed = true; | ||||||
|  |         } | ||||||
|  |     } else if(cmd == MF_UL_COMP_WRITE) { | ||||||
|  |         uint8_t write_page = buff_rx[1]; | ||||||
|  |         if((write_page > 1) && (write_page < page_num - 2)) { | ||||||
|  |             mf_ul_emulate->comp_write_cmd_started = true; | ||||||
|  |             mf_ul_emulate->comp_write_page_addr = write_page; | ||||||
|  |             // ACK
 | ||||||
|  |             buff_tx[0] = 0x0A; | ||||||
|  |             tx_bits = 4; | ||||||
|  |             command_parsed = true; | ||||||
|         } |         } | ||||||
|     } else if(cmd == MF_UL_READ_CNT) { |     } else if(cmd == MF_UL_READ_CNT) { | ||||||
|         uint8_t cnt_num = buff_rx[1]; |         uint8_t cnt_num = buff_rx[1]; | ||||||
| @ -246,7 +270,8 @@ uint16_t mf_ul_prepare_emulation_response(uint8_t* buff_rx, uint16_t len_rx, uin | |||||||
|             buff_tx[0] = mf_ul_emulate->data.counter[cnt_num] >> 16; |             buff_tx[0] = mf_ul_emulate->data.counter[cnt_num] >> 16; | ||||||
|             buff_tx[1] = mf_ul_emulate->data.counter[cnt_num] >> 8; |             buff_tx[1] = mf_ul_emulate->data.counter[cnt_num] >> 8; | ||||||
|             buff_tx[2] = mf_ul_emulate->data.counter[cnt_num]; |             buff_tx[2] = mf_ul_emulate->data.counter[cnt_num]; | ||||||
|             tx_len = 3; |             tx_bytes = 3; | ||||||
|  |             command_parsed = true; | ||||||
|         } |         } | ||||||
|     } else if(cmd == MF_UL_INC_CNT) { |     } else if(cmd == MF_UL_INC_CNT) { | ||||||
|         uint8_t cnt_num = buff_rx[1]; |         uint8_t cnt_num = buff_rx[1]; | ||||||
| @ -254,38 +279,52 @@ uint16_t mf_ul_prepare_emulation_response(uint8_t* buff_rx, uint16_t len_rx, uin | |||||||
|         if((cnt_num < 3) && (mf_ul_emulate->data.counter[cnt_num] + inc < 0x00FFFFFF)) { |         if((cnt_num < 3) && (mf_ul_emulate->data.counter[cnt_num] + inc < 0x00FFFFFF)) { | ||||||
|             mf_ul_emulate->data.counter[cnt_num] += inc; |             mf_ul_emulate->data.counter[cnt_num] += inc; | ||||||
|             mf_ul_emulate->data_changed = true; |             mf_ul_emulate->data_changed = true; | ||||||
|             // TODO make 4-bit ACK
 |             // ACK
 | ||||||
|             buff_tx[0] = 0x0A; |             buff_tx[0] = 0x0A; | ||||||
|             tx_len = 1; |             tx_bits = 4; | ||||||
|  |             command_parsed = true; | ||||||
|         } |         } | ||||||
|     } else if(cmd == MF_UL_AUTH) { |     } else if(cmd == MF_UL_AUTH) { | ||||||
|         if(mf_ul_emulate->type >= MfUltralightTypeNTAG213) { |         if(mf_ul_emulate->data.type >= MfUltralightTypeNTAG213) { | ||||||
|             if(memcmp(&buff_rx[1], mf_ul_emulate->auth_data->pwd, 4) == 0) { |             if(memcmp(&buff_rx[1], mf_ul_emulate->auth_data->pwd, 4) == 0) { | ||||||
|                 buff_tx[0] = mf_ul_emulate->auth_data->pack.raw[0]; |                 buff_tx[0] = mf_ul_emulate->auth_data->pack.raw[0]; | ||||||
|                 buff_tx[1] = mf_ul_emulate->auth_data->pack.raw[1]; |                 buff_tx[1] = mf_ul_emulate->auth_data->pack.raw[1]; | ||||||
|                 tx_len = 2; |                 tx_bytes = 2; | ||||||
|  |                 command_parsed = true; | ||||||
|             } else if(!mf_ul_emulate->auth_data->pack.value) { |             } else if(!mf_ul_emulate->auth_data->pack.value) { | ||||||
|                 buff_tx[0] = 0x80; |                 buff_tx[0] = 0x80; | ||||||
|                 buff_tx[1] = 0x80; |                 buff_tx[1] = 0x80; | ||||||
|                 tx_len = 2; |                 tx_bytes = 2; | ||||||
|             } else { |                 command_parsed = true; | ||||||
|                 // TODO make 4-bit NAK
 |  | ||||||
|                 buff_tx[0] = 0x0; |  | ||||||
|                 tx_len = 1; |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } else if(cmd == MF_UL_READ_SIG) { |     } else if(cmd == MF_UL_READ_SIG) { | ||||||
|         // Check 2nd byte = 0x00 - RFU
 |         // Check 2nd byte = 0x00 - RFU
 | ||||||
|         if(buff_rx[1] == 0x00) { |         if(buff_rx[1] == 0x00) { | ||||||
|             tx_len = sizeof(mf_ul_emulate->data.signature); |             tx_bytes = sizeof(mf_ul_emulate->data.signature); | ||||||
|             memcpy(buff_tx, mf_ul_emulate->data.signature, tx_len); |             memcpy(buff_tx, mf_ul_emulate->data.signature, tx_bytes); | ||||||
|  |             command_parsed = true; | ||||||
|         } |         } | ||||||
|     } else if(cmd == MF_UL_CHECK_TEARING) { |     } else if(cmd == MF_UL_CHECK_TEARING) { | ||||||
|         uint8_t cnt_num = buff_rx[1]; |         uint8_t cnt_num = buff_rx[1]; | ||||||
|         if(cnt_num < 3) { |         if(cnt_num < 3) { | ||||||
|             buff_tx[0] = mf_ul_emulate->data.tearing[cnt_num]; |             buff_tx[0] = mf_ul_emulate->data.tearing[cnt_num]; | ||||||
|             tx_len = 1; |             tx_bytes = 1; | ||||||
|  |             command_parsed = true; | ||||||
|         } |         } | ||||||
|  |     } else if(cmd == MF_UL_HALT_START) { | ||||||
|  |         tx_bits = 0; | ||||||
|  |         command_parsed = true; | ||||||
|     } |     } | ||||||
|     return tx_len; | 
 | ||||||
|  |     if(!command_parsed) { | ||||||
|  |         // Send NACK
 | ||||||
|  |         buff_tx[0] = 0x00; | ||||||
|  |         tx_bits = 4; | ||||||
|  |     } | ||||||
|  |     // Return tx buffer size in bits
 | ||||||
|  |     if(tx_bytes) { | ||||||
|  |         tx_bits = tx_bytes * 8; | ||||||
|  |     } | ||||||
|  |     return tx_bits; | ||||||
| } | } | ||||||
|  | |||||||
| @ -8,6 +8,7 @@ | |||||||
| 
 | 
 | ||||||
| #define MF_UL_TEARING_FLAG_DEFAULT (0xBD) | #define MF_UL_TEARING_FLAG_DEFAULT (0xBD) | ||||||
| 
 | 
 | ||||||
|  | #define MF_UL_HALT_START (0x50) | ||||||
| #define MF_UL_GET_VERSION_CMD (0x60) | #define MF_UL_GET_VERSION_CMD (0x60) | ||||||
| #define MF_UL_READ_CMD (0x30) | #define MF_UL_READ_CMD (0x30) | ||||||
| #define MF_UL_FAST_READ_CMD (0x3A) | #define MF_UL_FAST_READ_CMD (0x3A) | ||||||
| @ -28,6 +29,9 @@ typedef enum { | |||||||
|     MfUltralightTypeNTAG213, |     MfUltralightTypeNTAG213, | ||||||
|     MfUltralightTypeNTAG215, |     MfUltralightTypeNTAG215, | ||||||
|     MfUltralightTypeNTAG216, |     MfUltralightTypeNTAG216, | ||||||
|  | 
 | ||||||
|  |     // Keep last for number of types calculation
 | ||||||
|  |     MfUltralightTypeNum, | ||||||
| } MfUltralightType; | } MfUltralightType; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
| @ -52,6 +56,7 @@ typedef struct { | |||||||
| } MfUltralightManufacturerBlock; | } MfUltralightManufacturerBlock; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|  |     MfUltralightType type; | ||||||
|     MfUltralightVersion version; |     MfUltralightVersion version; | ||||||
|     uint8_t signature[32]; |     uint8_t signature[32]; | ||||||
|     uint32_t counter[3]; |     uint32_t counter[3]; | ||||||
| @ -69,13 +74,14 @@ typedef struct { | |||||||
| } MifareUlAuthData; | } MifareUlAuthData; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     MfUltralightType type; |  | ||||||
|     uint8_t pages_to_read; |     uint8_t pages_to_read; | ||||||
|     uint8_t pages_readed; |     uint8_t pages_readed; | ||||||
|     bool support_fast_read; |     bool support_fast_read; | ||||||
|     bool data_changed; |     bool data_changed; | ||||||
|     MifareUlData data; |     MifareUlData data; | ||||||
|     MifareUlAuthData* auth_data; |     MifareUlAuthData* auth_data; | ||||||
|  |     bool comp_write_cmd_started; | ||||||
|  |     uint8_t comp_write_page_addr; | ||||||
| } MifareUlDevice; | } MifareUlDevice; | ||||||
| 
 | 
 | ||||||
| bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); | bool mf_ul_check_card_type(uint8_t ATQA0, uint8_t ATQA1, uint8_t SAK); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 gornekich
						gornekich