Save picopass as picopass or, for 26bit, as lfrfid (#1380)
This commit is contained in:
		
							parent
							
								
									f46ae5a704
								
							
						
					
					
						commit
						41bd1fb9a5
					
				| @ -56,6 +56,13 @@ Picopass* picopass_alloc() { | |||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         picopass->view_dispatcher, PicopassViewPopup, popup_get_view(picopass->popup)); |         picopass->view_dispatcher, PicopassViewPopup, popup_get_view(picopass->popup)); | ||||||
| 
 | 
 | ||||||
|  |     // Text Input
 | ||||||
|  |     picopass->text_input = text_input_alloc(); | ||||||
|  |     view_dispatcher_add_view( | ||||||
|  |         picopass->view_dispatcher, | ||||||
|  |         PicopassViewTextInput, | ||||||
|  |         text_input_get_view(picopass->text_input)); | ||||||
|  | 
 | ||||||
|     // Custom Widget
 |     // Custom Widget
 | ||||||
|     picopass->widget = widget_alloc(); |     picopass->widget = widget_alloc(); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
| @ -67,6 +74,10 @@ Picopass* picopass_alloc() { | |||||||
| void picopass_free(Picopass* picopass) { | void picopass_free(Picopass* picopass) { | ||||||
|     furi_assert(picopass); |     furi_assert(picopass); | ||||||
| 
 | 
 | ||||||
|  |     // Picopass device
 | ||||||
|  |     picopass_device_free(picopass->dev); | ||||||
|  |     picopass->dev = NULL; | ||||||
|  | 
 | ||||||
|     // Submenu
 |     // Submenu
 | ||||||
|     view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewMenu); |     view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewMenu); | ||||||
|     submenu_free(picopass->submenu); |     submenu_free(picopass->submenu); | ||||||
| @ -75,6 +86,10 @@ void picopass_free(Picopass* picopass) { | |||||||
|     view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewPopup); |     view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewPopup); | ||||||
|     popup_free(picopass->popup); |     popup_free(picopass->popup); | ||||||
| 
 | 
 | ||||||
|  |     // TextInput
 | ||||||
|  |     view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewTextInput); | ||||||
|  |     text_input_free(picopass->text_input); | ||||||
|  | 
 | ||||||
|     // Custom Widget
 |     // Custom Widget
 | ||||||
|     view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewWidget); |     view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewWidget); | ||||||
|     widget_free(picopass->widget); |     widget_free(picopass->widget); | ||||||
| @ -97,12 +112,22 @@ void picopass_free(Picopass* picopass) { | |||||||
|     furi_record_close("notification"); |     furi_record_close("notification"); | ||||||
|     picopass->notifications = NULL; |     picopass->notifications = NULL; | ||||||
| 
 | 
 | ||||||
|     picopass_device_free(picopass->dev); |  | ||||||
|     picopass->dev = NULL; |  | ||||||
| 
 |  | ||||||
|     free(picopass); |     free(picopass); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void picopass_text_store_set(Picopass* picopass, const char* text, ...) { | ||||||
|  |     va_list args; | ||||||
|  |     va_start(args, text); | ||||||
|  | 
 | ||||||
|  |     vsnprintf(picopass->text_store, sizeof(picopass->text_store), text, args); | ||||||
|  | 
 | ||||||
|  |     va_end(args); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void picopass_text_store_clear(Picopass* picopass) { | ||||||
|  |     memset(picopass->text_store, 0, sizeof(picopass->text_store)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static const NotificationSequence picopass_sequence_blink_start_blue = { | static const NotificationSequence picopass_sequence_blink_start_blue = { | ||||||
|     &message_blink_start_10, |     &message_blink_start_10, | ||||||
|     &message_blink_set_color_blue, |     &message_blink_set_color_blue, | ||||||
|  | |||||||
| @ -5,6 +5,9 @@ | |||||||
| 
 | 
 | ||||||
| #define TAG "PicopassDevice" | #define TAG "PicopassDevice" | ||||||
| 
 | 
 | ||||||
|  | static const char* picopass_file_header = "Flipper Picopass device"; | ||||||
|  | static const uint32_t picopass_file_version = 1; | ||||||
|  | 
 | ||||||
| PicopassDevice* picopass_device_alloc() { | PicopassDevice* picopass_device_alloc() { | ||||||
|     PicopassDevice* picopass_dev = malloc(sizeof(PicopassDevice)); |     PicopassDevice* picopass_dev = malloc(sizeof(PicopassDevice)); | ||||||
|     picopass_dev->storage = furi_record_open("storage"); |     picopass_dev->storage = furi_record_open("storage"); | ||||||
| @ -12,6 +15,116 @@ PicopassDevice* picopass_device_alloc() { | |||||||
|     return picopass_dev; |     return picopass_dev; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void picopass_device_set_name(PicopassDevice* dev, const char* name) { | ||||||
|  |     furi_assert(dev); | ||||||
|  | 
 | ||||||
|  |     strlcpy(dev->dev_name, name, PICOPASS_DEV_NAME_MAX_LEN); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool picopass_device_save_file( | ||||||
|  |     PicopassDevice* dev, | ||||||
|  |     const char* dev_name, | ||||||
|  |     const char* folder, | ||||||
|  |     const char* extension, | ||||||
|  |     bool use_load_path) { | ||||||
|  |     furi_assert(dev); | ||||||
|  | 
 | ||||||
|  |     bool saved = false; | ||||||
|  |     FlipperFormat* file = flipper_format_file_alloc(dev->storage); | ||||||
|  |     PicopassPacs* pacs = &dev->dev_data.pacs; | ||||||
|  |     ApplicationArea* AA1 = &dev->dev_data.AA1; | ||||||
|  |     string_t temp_str; | ||||||
|  |     string_init(temp_str); | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         if(use_load_path && !string_empty_p(dev->load_path)) { | ||||||
|  |             // Get directory name
 | ||||||
|  |             path_extract_dirname(string_get_cstr(dev->load_path), temp_str); | ||||||
|  |             // Create picopass directory if necessary
 | ||||||
|  |             if(!storage_simply_mkdir(dev->storage, string_get_cstr(temp_str))) break; | ||||||
|  |             // Make path to file to save
 | ||||||
|  |             string_cat_printf(temp_str, "/%s%s", dev_name, extension); | ||||||
|  |         } else { | ||||||
|  |             // Create picopass directory if necessary
 | ||||||
|  |             if(!storage_simply_mkdir(dev->storage, PICOPASS_APP_FOLDER)) break; | ||||||
|  |             // First remove picopass device file if it was saved
 | ||||||
|  |             string_printf(temp_str, "%s/%s%s", folder, dev_name, extension); | ||||||
|  |         } | ||||||
|  |         // Open file
 | ||||||
|  |         if(!flipper_format_file_open_always(file, string_get_cstr(temp_str))) break; | ||||||
|  | 
 | ||||||
|  |         if(dev->format == PicopassDeviceSaveFormatHF) { | ||||||
|  |             // Write header
 | ||||||
|  |             if(!flipper_format_write_header_cstr(file, picopass_file_header, picopass_file_version)) | ||||||
|  |                 break; | ||||||
|  |             if(pacs->record.valid) { | ||||||
|  |                 if(!flipper_format_write_uint32( | ||||||
|  |                        file, "Facility Code", (uint32_t*)&pacs->record.FacilityCode, 1)) | ||||||
|  |                     break; | ||||||
|  |                 if(!flipper_format_write_uint32( | ||||||
|  |                        file, "Card Number", (uint32_t*)&pacs->record.CardNumber, 1)) | ||||||
|  |                     break; | ||||||
|  |                 if(!flipper_format_write_hex( | ||||||
|  |                        file, "Credential", pacs->credential, PICOPASS_BLOCK_LEN)) | ||||||
|  |                     break; | ||||||
|  |                 if(!flipper_format_write_hex(file, "PIN", pacs->pin0, PICOPASS_BLOCK_LEN)) break; | ||||||
|  |                 if(!flipper_format_write_hex(file, "PIN(cont.)", pacs->pin1, PICOPASS_BLOCK_LEN)) | ||||||
|  |                     break; | ||||||
|  | 
 | ||||||
|  |                 if(!flipper_format_write_comment_cstr(file, "Picopass blocks")) break; | ||||||
|  |                 // TODO: Save CSN, CFG, AA1, etc
 | ||||||
|  |                 bool block_saved = true; | ||||||
|  |                 for(size_t i = 0; i < 4; i++) { | ||||||
|  |                     string_printf(temp_str, "Block %d", i + 6); | ||||||
|  |                     if(!flipper_format_write_hex( | ||||||
|  |                            file, | ||||||
|  |                            string_get_cstr(temp_str), | ||||||
|  |                            AA1->block[i].data, | ||||||
|  |                            PICOPASS_BLOCK_LEN)) { | ||||||
|  |                         block_saved = false; | ||||||
|  |                         break; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 if(!block_saved) break; | ||||||
|  |                 if(!flipper_format_write_comment_cstr(file, "This is currently incomplete")) break; | ||||||
|  |             } | ||||||
|  |         } else if(dev->format == PicopassDeviceSaveFormatLF) { | ||||||
|  |             const char* lf_header = "Flipper RFID key"; | ||||||
|  |             // Write header
 | ||||||
|  |             if(!flipper_format_write_header_cstr(file, lf_header, 1)) break; | ||||||
|  |             if(!flipper_format_write_comment_cstr( | ||||||
|  |                    file, | ||||||
|  |                    "This was generated from the Picopass plugin and may not match current lfrfid")) | ||||||
|  |                 break; | ||||||
|  |             // When lfrfid supports more formats, update this
 | ||||||
|  |             if(!flipper_format_write_string_cstr(file, "Key type", "H10301")) break; | ||||||
|  |             uint8_t H10301[3] = {0}; | ||||||
|  |             H10301[0] = pacs->record.FacilityCode; | ||||||
|  |             H10301[1] = pacs->record.CardNumber >> 8; | ||||||
|  |             H10301[2] = pacs->record.CardNumber & 0x00FF; | ||||||
|  |             if(!flipper_format_write_hex(file, "Data", H10301, 3)) break; | ||||||
|  |         } | ||||||
|  |         saved = true; | ||||||
|  |     } while(0); | ||||||
|  | 
 | ||||||
|  |     if(!saved) { | ||||||
|  |         dialog_message_show_storage_error(dev->dialogs, "Can not save\nkey file"); | ||||||
|  |     } | ||||||
|  |     string_clear(temp_str); | ||||||
|  |     flipper_format_free(file); | ||||||
|  |     return saved; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool picopass_device_save(PicopassDevice* dev, const char* dev_name) { | ||||||
|  |     if(dev->format == PicopassDeviceSaveFormatHF) { | ||||||
|  |         return picopass_device_save_file( | ||||||
|  |             dev, dev_name, PICOPASS_APP_FOLDER, PICOPASS_APP_EXTENSION, true); | ||||||
|  |     } else if(dev->format == PicopassDeviceSaveFormatLF) { | ||||||
|  |         return picopass_device_save_file(dev, dev_name, "/any/lfrfid", ".rfid", true); | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void picopass_device_clear(PicopassDevice* dev) { | void picopass_device_clear(PicopassDevice* dev) { | ||||||
|     furi_assert(dev); |     furi_assert(dev); | ||||||
| 
 | 
 | ||||||
| @ -24,10 +137,10 @@ void picopass_device_free(PicopassDevice* picopass_dev) { | |||||||
|     picopass_device_clear(picopass_dev); |     picopass_device_clear(picopass_dev); | ||||||
|     furi_record_close("storage"); |     furi_record_close("storage"); | ||||||
|     furi_record_close("dialogs"); |     furi_record_close("dialogs"); | ||||||
|  |     string_clear(picopass_dev->load_path); | ||||||
|     free(picopass_dev); |     free(picopass_dev); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void picopass_device_data_clear(PicopassDeviceData* dev_data) { | void picopass_device_data_clear(PicopassDeviceData* dev_data) { | ||||||
|     FURI_LOG_D(TAG, "picopass_device_data_clear"); |  | ||||||
|     memset(&dev_data->AA1, 0, sizeof(ApplicationArea)); |     memset(&dev_data->AA1, 0, sizeof(ApplicationArea)); | ||||||
| } | } | ||||||
|  | |||||||
| @ -7,6 +7,26 @@ | |||||||
| 
 | 
 | ||||||
| #include <rfal_picopass.h> | #include <rfal_picopass.h> | ||||||
| 
 | 
 | ||||||
|  | #define PICOPASS_DEV_NAME_MAX_LEN 22 | ||||||
|  | #define PICOPASS_READER_DATA_MAX_SIZE 64 | ||||||
|  | #define PICOPASS_BLOCK_LEN 8 | ||||||
|  | 
 | ||||||
|  | #define PICOPASS_APP_FOLDER "/any/picopass" | ||||||
|  | #define PICOPASS_APP_EXTENSION ".picopass" | ||||||
|  | #define PICOPASS_APP_SHADOW_EXTENSION ".pas" | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     PicopassDeviceEncryptionUnknown = 0, | ||||||
|  |     PicopassDeviceEncryptionNone = 0x14, | ||||||
|  |     PicopassDeviceEncryptionDES = 0x15, | ||||||
|  |     PicopassDeviceEncryption3DES = 0x17, | ||||||
|  | } PicopassEncryption; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     PicopassDeviceSaveFormatHF, | ||||||
|  |     PicopassDeviceSaveFormatLF, | ||||||
|  | } PicopassDeviceSaveFormat; | ||||||
|  | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     bool valid; |     bool valid; | ||||||
|     uint8_t bitLength; |     uint8_t bitLength; | ||||||
| @ -16,7 +36,7 @@ typedef struct { | |||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     bool biometrics; |     bool biometrics; | ||||||
|     uint8_t encryption; |     PicopassEncryption encryption; | ||||||
|     uint8_t credential[8]; |     uint8_t credential[8]; | ||||||
|     uint8_t pin0[8]; |     uint8_t pin0[8]; | ||||||
|     uint8_t pin1[8]; |     uint8_t pin1[8]; | ||||||
| @ -32,12 +52,19 @@ typedef struct { | |||||||
|     Storage* storage; |     Storage* storage; | ||||||
|     DialogsApp* dialogs; |     DialogsApp* dialogs; | ||||||
|     PicopassDeviceData dev_data; |     PicopassDeviceData dev_data; | ||||||
|  |     char dev_name[PICOPASS_DEV_NAME_MAX_LEN + 1]; | ||||||
|  |     string_t load_path; | ||||||
|  |     PicopassDeviceSaveFormat format; | ||||||
| } PicopassDevice; | } PicopassDevice; | ||||||
| 
 | 
 | ||||||
| PicopassDevice* picopass_device_alloc(); | PicopassDevice* picopass_device_alloc(); | ||||||
| 
 | 
 | ||||||
| void picopass_device_free(PicopassDevice* picopass_dev); | void picopass_device_free(PicopassDevice* picopass_dev); | ||||||
| 
 | 
 | ||||||
|  | void picopass_device_set_name(PicopassDevice* dev, const char* name); | ||||||
|  | 
 | ||||||
|  | bool picopass_device_save(PicopassDevice* dev, const char* dev_name); | ||||||
|  | 
 | ||||||
| void picopass_device_data_clear(PicopassDeviceData* dev_data); | void picopass_device_data_clear(PicopassDeviceData* dev_data); | ||||||
| 
 | 
 | ||||||
| void picopass_device_clear(PicopassDevice* dev); | void picopass_device_clear(PicopassDevice* dev); | ||||||
|  | |||||||
| @ -14,6 +14,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <gui/modules/submenu.h> | #include <gui/modules/submenu.h> | ||||||
| #include <gui/modules/popup.h> | #include <gui/modules/popup.h> | ||||||
|  | #include <gui/modules/text_input.h> | ||||||
| #include <gui/modules/widget.h> | #include <gui/modules/widget.h> | ||||||
| 
 | 
 | ||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| @ -23,6 +24,8 @@ | |||||||
| #include <storage/storage.h> | #include <storage/storage.h> | ||||||
| #include <lib/toolbox/path.h> | #include <lib/toolbox/path.h> | ||||||
| 
 | 
 | ||||||
|  | #define PICOPASS_TEXT_STORE_SIZE 128 | ||||||
|  | 
 | ||||||
| enum PicopassCustomEvent { | enum PicopassCustomEvent { | ||||||
|     // Reserve first 100 events for button types and indexes, starting from 0
 |     // Reserve first 100 events for button types and indexes, starting from 0
 | ||||||
|     PicopassCustomEventReserved = 100, |     PicopassCustomEventReserved = 100, | ||||||
| @ -31,7 +34,6 @@ enum PicopassCustomEvent { | |||||||
|     PicopassCustomEventWorkerExit, |     PicopassCustomEventWorkerExit, | ||||||
|     PicopassCustomEventByteInputDone, |     PicopassCustomEventByteInputDone, | ||||||
|     PicopassCustomEventTextInputDone, |     PicopassCustomEventTextInputDone, | ||||||
|     PicopassCustomEventDictAttackDone, |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
| @ -47,20 +49,29 @@ struct Picopass { | |||||||
|     SceneManager* scene_manager; |     SceneManager* scene_manager; | ||||||
|     PicopassDevice* dev; |     PicopassDevice* dev; | ||||||
| 
 | 
 | ||||||
|  |     char text_store[PICOPASS_TEXT_STORE_SIZE + 1]; | ||||||
|  |     string_t text_box_store; | ||||||
|  | 
 | ||||||
|     // Common Views
 |     // Common Views
 | ||||||
|     Submenu* submenu; |     Submenu* submenu; | ||||||
|     Popup* popup; |     Popup* popup; | ||||||
|  |     TextInput* text_input; | ||||||
|     Widget* widget; |     Widget* widget; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     PicopassViewMenu, |     PicopassViewMenu, | ||||||
|     PicopassViewPopup, |     PicopassViewPopup, | ||||||
|  |     PicopassViewTextInput, | ||||||
|     PicopassViewWidget, |     PicopassViewWidget, | ||||||
| } PicopassView; | } PicopassView; | ||||||
| 
 | 
 | ||||||
| Picopass* picopass_alloc(); | Picopass* picopass_alloc(); | ||||||
| 
 | 
 | ||||||
|  | void picopass_text_store_set(Picopass* picopass, const char* text, ...); | ||||||
|  | 
 | ||||||
|  | void picopass_text_store_clear(Picopass* picopass); | ||||||
|  | 
 | ||||||
| void picopass_blink_start(Picopass* picopass); | void picopass_blink_start(Picopass* picopass); | ||||||
| 
 | 
 | ||||||
| void picopass_blink_stop(Picopass* picopass); | void picopass_blink_stop(Picopass* picopass); | ||||||
|  | |||||||
| @ -114,8 +114,6 @@ void picopass_worker_start( | |||||||
|     furi_assert(picopass_worker); |     furi_assert(picopass_worker); | ||||||
|     furi_assert(dev_data); |     furi_assert(dev_data); | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_D(TAG, "picopass_worker_start"); |  | ||||||
| 
 |  | ||||||
|     picopass_worker->callback = callback; |     picopass_worker->callback = callback; | ||||||
|     picopass_worker->context = context; |     picopass_worker->context = context; | ||||||
|     picopass_worker->dev_data = dev_data; |     picopass_worker->dev_data = dev_data; | ||||||
| @ -258,10 +256,8 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) { | |||||||
|     ReturnCode err; |     ReturnCode err; | ||||||
| 
 | 
 | ||||||
|     while(picopass_worker->state == PicopassWorkerStateDetect) { |     while(picopass_worker->state == PicopassWorkerStateDetect) { | ||||||
|         FURI_LOG_D(TAG, "PicopassWorkerStateDetect"); |  | ||||||
|         if(picopass_detect_card(1000) == ERR_NONE) { |         if(picopass_detect_card(1000) == ERR_NONE) { | ||||||
|             // Process first found device
 |             // Process first found device
 | ||||||
|             FURI_LOG_D(TAG, "picopass_read_card"); |  | ||||||
|             err = picopass_read_card(AA1); |             err = picopass_read_card(AA1); | ||||||
|             if(err != ERR_NONE) { |             if(err != ERR_NONE) { | ||||||
|                 FURI_LOG_E(TAG, "picopass_read_card error %d", err); |                 FURI_LOG_E(TAG, "picopass_read_card error %d", err); | ||||||
| @ -277,21 +273,18 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) { | |||||||
|                     FURI_LOG_E(TAG, "decrypt error %d", err); |                     FURI_LOG_E(TAG, "decrypt error %d", err); | ||||||
|                     break; |                     break; | ||||||
|                 } |                 } | ||||||
|                 FURI_LOG_D(TAG, "Decrypted 7"); |  | ||||||
| 
 | 
 | ||||||
|                 err = picopass_worker_decrypt(AA1->block[2].data, pacs->pin0); |                 err = picopass_worker_decrypt(AA1->block[2].data, pacs->pin0); | ||||||
|                 if(err != ERR_NONE) { |                 if(err != ERR_NONE) { | ||||||
|                     FURI_LOG_E(TAG, "decrypt error %d", err); |                     FURI_LOG_E(TAG, "decrypt error %d", err); | ||||||
|                     break; |                     break; | ||||||
|                 } |                 } | ||||||
|                 FURI_LOG_D(TAG, "Decrypted 8"); |  | ||||||
| 
 | 
 | ||||||
|                 err = picopass_worker_decrypt(AA1->block[3].data, pacs->pin1); |                 err = picopass_worker_decrypt(AA1->block[3].data, pacs->pin1); | ||||||
|                 if(err != ERR_NONE) { |                 if(err != ERR_NONE) { | ||||||
|                     FURI_LOG_E(TAG, "decrypt error %d", err); |                     FURI_LOG_E(TAG, "decrypt error %d", err); | ||||||
|                     break; |                     break; | ||||||
|                 } |                 } | ||||||
|                 FURI_LOG_D(TAG, "Decrypted 9"); |  | ||||||
|             } else if(pacs->encryption == 0x14) { |             } else if(pacs->encryption == 0x14) { | ||||||
|                 FURI_LOG_D(TAG, "No Encryption"); |                 FURI_LOG_D(TAG, "No Encryption"); | ||||||
|                 memcpy(pacs->credential, AA1->block[1].data, RFAL_PICOPASS_MAX_BLOCK_LEN); |                 memcpy(pacs->credential, AA1->block[1].data, RFAL_PICOPASS_MAX_BLOCK_LEN); | ||||||
|  | |||||||
							
								
								
									
										65
									
								
								applications/picopass/scenes/picopass_scene_card_menu.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								applications/picopass/scenes/picopass_scene_card_menu.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,65 @@ | |||||||
|  | #include "../picopass_i.h" | ||||||
|  | 
 | ||||||
|  | enum SubmenuIndex { | ||||||
|  |     SubmenuIndexSave, | ||||||
|  |     SubmenuIndexSaveAsLF, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void picopass_scene_card_menu_submenu_callback(void* context, uint32_t index) { | ||||||
|  |     Picopass* picopass = context; | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_send_custom_event(picopass->view_dispatcher, index); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void picopass_scene_card_menu_on_enter(void* context) { | ||||||
|  |     Picopass* picopass = context; | ||||||
|  |     Submenu* submenu = picopass->submenu; | ||||||
|  | 
 | ||||||
|  |     submenu_add_item( | ||||||
|  |         submenu, "Save", SubmenuIndexSave, picopass_scene_card_menu_submenu_callback, picopass); | ||||||
|  |     if(picopass->dev->dev_data.pacs.record.valid) { | ||||||
|  |         submenu_add_item( | ||||||
|  |             submenu, | ||||||
|  |             "Save as LF", | ||||||
|  |             SubmenuIndexSaveAsLF, | ||||||
|  |             picopass_scene_card_menu_submenu_callback, | ||||||
|  |             picopass); | ||||||
|  |     } | ||||||
|  |     submenu_set_selected_item( | ||||||
|  |         picopass->submenu, | ||||||
|  |         scene_manager_get_scene_state(picopass->scene_manager, PicopassSceneCardMenu)); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewMenu); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool picopass_scene_card_menu_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     Picopass* picopass = context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         if(event.event == SubmenuIndexSave) { | ||||||
|  |             scene_manager_set_scene_state( | ||||||
|  |                 picopass->scene_manager, PicopassSceneCardMenu, SubmenuIndexSave); | ||||||
|  |             scene_manager_next_scene(picopass->scene_manager, PicopassSceneSaveName); | ||||||
|  |             picopass->dev->format = PicopassDeviceSaveFormatHF; | ||||||
|  |             consumed = true; | ||||||
|  |         } else if(event.event == SubmenuIndexSaveAsLF) { | ||||||
|  |             scene_manager_set_scene_state( | ||||||
|  |                 picopass->scene_manager, PicopassSceneCardMenu, SubmenuIndexSaveAsLF); | ||||||
|  |             picopass->dev->format = PicopassDeviceSaveFormatLF; | ||||||
|  |             scene_manager_next_scene(picopass->scene_manager, PicopassSceneSaveName); | ||||||
|  |             consumed = true; | ||||||
|  |         } | ||||||
|  |     } else if(event.type == SceneManagerEventTypeBack) { | ||||||
|  |         consumed = scene_manager_search_and_switch_to_previous_scene( | ||||||
|  |             picopass->scene_manager, PicopassSceneStart); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void picopass_scene_card_menu_on_exit(void* context) { | ||||||
|  |     Picopass* picopass = context; | ||||||
|  | 
 | ||||||
|  |     submenu_reset(picopass->submenu); | ||||||
|  | } | ||||||
| @ -1,3 +1,7 @@ | |||||||
| ADD_SCENE(picopass, start, Start) | ADD_SCENE(picopass, start, Start) | ||||||
| ADD_SCENE(picopass, read_card, ReadCard) | ADD_SCENE(picopass, read_card, ReadCard) | ||||||
| ADD_SCENE(picopass, read_card_success, ReadCardSuccess) | ADD_SCENE(picopass, read_card_success, ReadCardSuccess) | ||||||
|  | ADD_SCENE(picopass, card_menu, CardMenu) | ||||||
|  | ADD_SCENE(picopass, save_name, SaveName) | ||||||
|  | ADD_SCENE(picopass, save_success, SaveSuccess) | ||||||
|  | ADD_SCENE(picopass, saved_menu, SavedMenu) | ||||||
|  | |||||||
| @ -45,6 +45,14 @@ void picopass_scene_read_card_success_on_enter(void* context) { | |||||||
|         "Retry", |         "Retry", | ||||||
|         picopass_scene_read_card_success_widget_callback, |         picopass_scene_read_card_success_widget_callback, | ||||||
|         picopass); |         picopass); | ||||||
|  | 
 | ||||||
|  |     widget_add_button_element( | ||||||
|  |         widget, | ||||||
|  |         GuiButtonTypeRight, | ||||||
|  |         "More", | ||||||
|  |         picopass_scene_read_card_success_widget_callback, | ||||||
|  |         picopass); | ||||||
|  | 
 | ||||||
|     if(pacs->record.valid) { |     if(pacs->record.valid) { | ||||||
|         widget_add_string_element( |         widget_add_string_element( | ||||||
|             widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, string_get_cstr(wiegand_str)); |             widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, string_get_cstr(wiegand_str)); | ||||||
| @ -65,6 +73,11 @@ bool picopass_scene_read_card_success_on_event(void* context, SceneManagerEvent | |||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         if(event.event == GuiButtonTypeLeft) { |         if(event.event == GuiButtonTypeLeft) { | ||||||
|             consumed = scene_manager_previous_scene(picopass->scene_manager); |             consumed = scene_manager_previous_scene(picopass->scene_manager); | ||||||
|  |         } else if(event.event == GuiButtonTypeRight) { | ||||||
|  |             // Clear device name
 | ||||||
|  |             picopass_device_set_name(picopass->dev, ""); | ||||||
|  |             scene_manager_next_scene(picopass->scene_manager, PicopassSceneCardMenu); | ||||||
|  |             consumed = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return consumed; |     return consumed; | ||||||
|  | |||||||
							
								
								
									
										84
									
								
								applications/picopass/scenes/picopass_scene_save_name.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								applications/picopass/scenes/picopass_scene_save_name.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,84 @@ | |||||||
|  | #include "../picopass_i.h" | ||||||
|  | #include "m-string.h" | ||||||
|  | #include <lib/toolbox/random_name.h> | ||||||
|  | #include <gui/modules/validators.h> | ||||||
|  | #include <toolbox/path.h> | ||||||
|  | 
 | ||||||
|  | void picopass_scene_save_name_text_input_callback(void* context) { | ||||||
|  |     Picopass* picopass = context; | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_send_custom_event(picopass->view_dispatcher, PicopassCustomEventTextInputDone); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void picopass_scene_save_name_on_enter(void* context) { | ||||||
|  |     Picopass* picopass = context; | ||||||
|  | 
 | ||||||
|  |     // Setup view
 | ||||||
|  |     TextInput* text_input = picopass->text_input; | ||||||
|  |     bool dev_name_empty = false; | ||||||
|  |     if(!strcmp(picopass->dev->dev_name, "")) { | ||||||
|  |         set_random_name(picopass->text_store, sizeof(picopass->text_store)); | ||||||
|  |         dev_name_empty = true; | ||||||
|  |     } else { | ||||||
|  |         picopass_text_store_set(picopass, picopass->dev->dev_name); | ||||||
|  |     } | ||||||
|  |     text_input_set_header_text(text_input, "Name the card"); | ||||||
|  |     text_input_set_result_callback( | ||||||
|  |         text_input, | ||||||
|  |         picopass_scene_save_name_text_input_callback, | ||||||
|  |         picopass, | ||||||
|  |         picopass->text_store, | ||||||
|  |         PICOPASS_DEV_NAME_MAX_LEN, | ||||||
|  |         dev_name_empty); | ||||||
|  | 
 | ||||||
|  |     string_t folder_path; | ||||||
|  |     string_init(folder_path); | ||||||
|  | 
 | ||||||
|  |     if(string_end_with_str_p(picopass->dev->load_path, PICOPASS_APP_EXTENSION)) { | ||||||
|  |         path_extract_dirname(string_get_cstr(picopass->dev->load_path), folder_path); | ||||||
|  |     } else { | ||||||
|  |         string_set_str(folder_path, PICOPASS_APP_FOLDER); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( | ||||||
|  |         string_get_cstr(folder_path), PICOPASS_APP_EXTENSION, picopass->dev->dev_name); | ||||||
|  |     text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewTextInput); | ||||||
|  | 
 | ||||||
|  |     string_clear(folder_path); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool picopass_scene_save_name_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     Picopass* picopass = context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         if(event.event == PicopassCustomEventTextInputDone) { | ||||||
|  |             if(strcmp(picopass->dev->dev_name, "")) { | ||||||
|  |                 // picopass_device_delete(picopass->dev, true);
 | ||||||
|  |             } | ||||||
|  |             strlcpy( | ||||||
|  |                 picopass->dev->dev_name, picopass->text_store, strlen(picopass->text_store) + 1); | ||||||
|  |             if(picopass_device_save(picopass->dev, picopass->text_store)) { | ||||||
|  |                 scene_manager_next_scene(picopass->scene_manager, PicopassSceneSaveSuccess); | ||||||
|  |                 consumed = true; | ||||||
|  |             } else { | ||||||
|  |                 consumed = scene_manager_search_and_switch_to_previous_scene( | ||||||
|  |                     picopass->scene_manager, PicopassSceneStart); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void picopass_scene_save_name_on_exit(void* context) { | ||||||
|  |     Picopass* picopass = context; | ||||||
|  | 
 | ||||||
|  |     // Clear view
 | ||||||
|  |     void* validator_context = text_input_get_validator_callback_context(picopass->text_input); | ||||||
|  |     text_input_set_validator(picopass->text_input, NULL, NULL); | ||||||
|  |     validator_is_file_free(validator_context); | ||||||
|  | 
 | ||||||
|  |     text_input_reset(picopass->text_input); | ||||||
|  | } | ||||||
							
								
								
									
										47
									
								
								applications/picopass/scenes/picopass_scene_save_success.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								applications/picopass/scenes/picopass_scene_save_success.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,47 @@ | |||||||
|  | #include "../picopass_i.h" | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
|  | 
 | ||||||
|  | void picopass_scene_save_success_popup_callback(void* context) { | ||||||
|  |     Picopass* picopass = context; | ||||||
|  |     view_dispatcher_send_custom_event(picopass->view_dispatcher, PicopassCustomEventViewExit); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void picopass_scene_save_success_on_enter(void* context) { | ||||||
|  |     Picopass* picopass = context; | ||||||
|  |     DOLPHIN_DEED(DolphinDeedNfcSave); | ||||||
|  | 
 | ||||||
|  |     // Setup view
 | ||||||
|  |     Popup* popup = picopass->popup; | ||||||
|  |     popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); | ||||||
|  |     popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom); | ||||||
|  |     popup_set_timeout(popup, 1500); | ||||||
|  |     popup_set_context(popup, picopass); | ||||||
|  |     popup_set_callback(popup, picopass_scene_save_success_popup_callback); | ||||||
|  |     popup_enable_timeout(popup); | ||||||
|  |     view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewPopup); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool picopass_scene_save_success_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     Picopass* picopass = context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         if(event.event == PicopassCustomEventViewExit) { | ||||||
|  |             if(scene_manager_has_previous_scene(picopass->scene_manager, PicopassSceneCardMenu)) { | ||||||
|  |                 consumed = scene_manager_search_and_switch_to_previous_scene( | ||||||
|  |                     picopass->scene_manager, PicopassSceneCardMenu); | ||||||
|  |             } else { | ||||||
|  |                 consumed = scene_manager_search_and_switch_to_previous_scene( | ||||||
|  |                     picopass->scene_manager, PicopassSceneStart); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void picopass_scene_save_success_on_exit(void* context) { | ||||||
|  |     Picopass* picopass = context; | ||||||
|  | 
 | ||||||
|  |     // Clear view
 | ||||||
|  |     popup_reset(picopass->popup); | ||||||
|  | } | ||||||
							
								
								
									
										35
									
								
								applications/picopass/scenes/picopass_scene_saved_menu.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								applications/picopass/scenes/picopass_scene_saved_menu.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | |||||||
|  | #include "../picopass_i.h" | ||||||
|  | 
 | ||||||
|  | void picopass_scene_saved_menu_submenu_callback(void* context, uint32_t index) { | ||||||
|  |     Picopass* picopass = context; | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_send_custom_event(picopass->view_dispatcher, index); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void picopass_scene_saved_menu_on_enter(void* context) { | ||||||
|  |     Picopass* picopass = context; | ||||||
|  | 
 | ||||||
|  |     submenu_set_selected_item( | ||||||
|  |         picopass->submenu, | ||||||
|  |         scene_manager_get_scene_state(picopass->scene_manager, PicopassSceneSavedMenu)); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewMenu); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool picopass_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     Picopass* picopass = context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         scene_manager_set_scene_state( | ||||||
|  |             picopass->scene_manager, PicopassSceneSavedMenu, event.event); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void picopass_scene_saved_menu_on_exit(void* context) { | ||||||
|  |     Picopass* picopass = context; | ||||||
|  | 
 | ||||||
|  |     submenu_reset(picopass->submenu); | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Eric Betts
						Eric Betts