Merge branch 'dev' into release-candidate
This commit is contained in:
		
						commit
						c02d8beed9
					
				
							
								
								
									
										2
									
								
								.github/pull_request_template.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/pull_request_template.md
									
									
									
									
										vendored
									
									
								
							| @ -6,7 +6,7 @@ | ||||
| 
 | ||||
| - [ Describe how to verify changes ] | ||||
| 
 | ||||
| # Checklist (do not modify) | ||||
| # Checklist (For Reviewer) | ||||
| 
 | ||||
| - [ ] PR has description of feature/bug or link to Confluence/Jira task | ||||
| - [ ] Description contains actions to verify feature/bugfix | ||||
|  | ||||
							
								
								
									
										2
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							| @ -10,7 +10,7 @@ on: | ||||
|   pull_request: | ||||
| 
 | ||||
| env: | ||||
|   TARGETS: f6 f7 | ||||
|   TARGETS: f7 | ||||
|   DEFAULT_TARGET: f7 | ||||
| 
 | ||||
| jobs: | ||||
|  | ||||
							
								
								
									
										2
									
								
								.github/workflows/lint_c.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/lint_c.yml
									
									
									
									
										vendored
									
									
								
							| @ -10,7 +10,7 @@ on: | ||||
|   pull_request: | ||||
| 
 | ||||
| env: | ||||
|   TARGETS: f6 f7 | ||||
|   TARGETS: f7 | ||||
| 
 | ||||
| jobs: | ||||
|   lint_c_cpp: | ||||
|  | ||||
							
								
								
									
										3
									
								
								Brewfile
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								Brewfile
									
									
									
									
									
								
							| @ -1,7 +1,8 @@ | ||||
| cask "gcc-arm-embedded" | ||||
| brew "protobuf" | ||||
| brew "gdb" | ||||
| brew "heatshrink" | ||||
| brew "open-ocd" | ||||
| brew "clang-format" | ||||
| brew "dfu-util" | ||||
| brew "imagemagick" | ||||
| brew "imagemagick" | ||||
|  | ||||
| @ -115,15 +115,10 @@ void bad_usb_app_free(BadUsbApp* app) { | ||||
| } | ||||
| 
 | ||||
| int32_t bad_usb_app(void* p) { | ||||
|     FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); | ||||
|     furi_hal_usb_set_config(&usb_hid); | ||||
| 
 | ||||
|     BadUsbApp* bad_usb_app = bad_usb_app_alloc((char*)p); | ||||
| 
 | ||||
|     view_dispatcher_run(bad_usb_app->view_dispatcher); | ||||
| 
 | ||||
|     furi_hal_usb_set_config(usb_mode_prev); | ||||
|     bad_usb_app_free(bad_usb_app); | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| @ -24,6 +24,7 @@ typedef enum { | ||||
| } WorkerEvtFlags; | ||||
| 
 | ||||
| struct BadUsbScript { | ||||
|     FuriHalUsbHidConfig hid_cfg; | ||||
|     BadUsbState st; | ||||
|     string_t file_path; | ||||
|     uint32_t defdelay; | ||||
| @ -101,6 +102,7 @@ static const DuckyKey ducky_keys[] = { | ||||
| }; | ||||
| 
 | ||||
| static const char ducky_cmd_comment[] = {"REM"}; | ||||
| static const char ducky_cmd_id[] = {"ID"}; | ||||
| static const char ducky_cmd_delay[] = {"DELAY "}; | ||||
| static const char ducky_cmd_string[] = {"STRING "}; | ||||
| static const char ducky_cmd_defdelay_1[] = {"DEFAULT_DELAY "}; | ||||
| @ -240,12 +242,15 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) { | ||||
|         if(i == line_len - 1) return SCRIPT_STATE_NEXT_LINE; // Skip empty lines
 | ||||
|     } | ||||
| 
 | ||||
|     FURI_LOG_I(WORKER_TAG, "line:%s", line_tmp); | ||||
|     FURI_LOG_D(WORKER_TAG, "line:%s", line_tmp); | ||||
| 
 | ||||
|     // General commands
 | ||||
|     if(strncmp(line_tmp, ducky_cmd_comment, strlen(ducky_cmd_comment)) == 0) { | ||||
|         // REM - comment line
 | ||||
|         return (0); | ||||
|     } else if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) { | ||||
|         // ID - executed in ducky_script_preload
 | ||||
|         return (0); | ||||
|     } else if(strncmp(line_tmp, ducky_cmd_delay, strlen(ducky_cmd_delay)) == 0) { | ||||
|         // DELAY
 | ||||
|         line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||
| @ -302,10 +307,37 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) { | ||||
|     return SCRIPT_STATE_ERROR; | ||||
| } | ||||
| 
 | ||||
| static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) { | ||||
|     if(sscanf(line, "%lX:%lX", &bad_usb->hid_cfg.vid, &bad_usb->hid_cfg.pid) == 2) { | ||||
|         bad_usb->hid_cfg.manuf[0] = '\0'; | ||||
|         bad_usb->hid_cfg.product[0] = '\0'; | ||||
| 
 | ||||
|         uint8_t id_len = ducky_get_command_len(line); | ||||
|         if(!ducky_is_line_end(line[id_len + 1])) { | ||||
|             sscanf( | ||||
|                 &line[id_len + 1], | ||||
|                 "%31[^\r\n:]:%31[^\r\n]", | ||||
|                 bad_usb->hid_cfg.manuf, | ||||
|                 bad_usb->hid_cfg.product); | ||||
|         } | ||||
|         FURI_LOG_D( | ||||
|             WORKER_TAG, | ||||
|             "set id: %04X:%04X mfr:%s product:%s", | ||||
|             bad_usb->hid_cfg.vid, | ||||
|             bad_usb->hid_cfg.pid, | ||||
|             bad_usb->hid_cfg.manuf, | ||||
|             bad_usb->hid_cfg.product); | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) { | ||||
|     uint8_t ret = 0; | ||||
|     uint32_t line_len = 0; | ||||
| 
 | ||||
|     string_reset(bad_usb->line); | ||||
| 
 | ||||
|     do { | ||||
|         ret = storage_file_read(script_file, bad_usb->file_buf, FILE_BUFFER_LEN); | ||||
|         for(uint16_t i = 0; i < ret; i++) { | ||||
| @ -313,6 +345,9 @@ static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) { | ||||
|                 bad_usb->st.line_nb++; | ||||
|                 line_len = 0; | ||||
|             } else { | ||||
|                 if(bad_usb->st.line_nb == 0) { // Save first line
 | ||||
|                     string_push_back(bad_usb->line, bad_usb->file_buf[i]); | ||||
|                 } | ||||
|                 line_len++; | ||||
|             } | ||||
|         } | ||||
| @ -324,7 +359,20 @@ static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) { | ||||
|         } | ||||
|     } while(ret > 0); | ||||
| 
 | ||||
|     const char* line_tmp = string_get_cstr(bad_usb->line); | ||||
|     bool id_set = false; // Looking for ID command at first line
 | ||||
|     if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) { | ||||
|         id_set = ducky_set_usb_id(bad_usb, &line_tmp[strlen(ducky_cmd_id) + 1]); | ||||
|     } | ||||
| 
 | ||||
|     if(id_set) { | ||||
|         furi_hal_usb_set_config(&usb_hid, &bad_usb->hid_cfg); | ||||
|     } else { | ||||
|         furi_hal_usb_set_config(&usb_hid, NULL); | ||||
|     } | ||||
| 
 | ||||
|     storage_file_seek(script_file, 0, true); | ||||
|     string_reset(bad_usb->line); | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| @ -403,6 +451,8 @@ static int32_t bad_usb_worker(void* context) { | ||||
|     BadUsbWorkerState worker_state = BadUsbStateInit; | ||||
|     int32_t delay_val = 0; | ||||
| 
 | ||||
|     FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); | ||||
| 
 | ||||
|     FURI_LOG_I(WORKER_TAG, "Init"); | ||||
|     File* script_file = storage_file_alloc(furi_record_open("storage")); | ||||
|     string_init(bad_usb->line); | ||||
| @ -522,6 +572,8 @@ static int32_t bad_usb_worker(void* context) { | ||||
| 
 | ||||
|     furi_hal_hid_set_state_callback(NULL, NULL); | ||||
| 
 | ||||
|     furi_hal_usb_set_config(usb_mode_prev, NULL); | ||||
| 
 | ||||
|     storage_file_close(script_file); | ||||
|     storage_file_free(script_file); | ||||
|     string_clear(bad_usb->line); | ||||
|  | ||||
| @ -42,7 +42,7 @@ int32_t usb_mouse_app(void* p) { | ||||
|     ViewPort* view_port = view_port_alloc(); | ||||
| 
 | ||||
|     FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); | ||||
|     furi_hal_usb_set_config(&usb_hid); | ||||
|     furi_hal_usb_set_config(&usb_hid, NULL); | ||||
| 
 | ||||
|     view_port_draw_callback_set(view_port, usb_mouse_render_callback, NULL); | ||||
|     view_port_input_callback_set(view_port, usb_mouse_input_callback, event_queue); | ||||
| @ -110,7 +110,7 @@ int32_t usb_mouse_app(void* p) { | ||||
|         view_port_update(view_port); | ||||
|     } | ||||
| 
 | ||||
|     furi_hal_usb_set_config(usb_mode_prev); | ||||
|     furi_hal_usb_set_config(usb_mode_prev, NULL); | ||||
| 
 | ||||
|     // remove & free all stuff created by app
 | ||||
|     gui_remove_view_port(gui, view_port); | ||||
|  | ||||
| @ -10,6 +10,7 @@ typedef struct { | ||||
|     Gui* gui; | ||||
|     ViewDispatcher* view_dispatcher; | ||||
|     Submenu* submenu; | ||||
|     FuriHalUsbHidConfig hid_cfg; | ||||
| } UsbTestApp; | ||||
| 
 | ||||
| typedef enum { | ||||
| @ -19,12 +20,13 @@ typedef enum { | ||||
|     UsbTestSubmenuIndexVcpSingle, | ||||
|     UsbTestSubmenuIndexVcpDual, | ||||
|     UsbTestSubmenuIndexHid, | ||||
|     UsbTestSubmenuIndexHidWithParams, | ||||
|     UsbTestSubmenuIndexHidU2F, | ||||
| } SubmenuIndex; | ||||
| 
 | ||||
| void usb_test_submenu_callback(void* context, uint32_t index) { | ||||
|     furi_assert(context); | ||||
|     //UsbTestApp* app = context;
 | ||||
|     UsbTestApp* app = context; | ||||
|     if(index == UsbTestSubmenuIndexEnable) { | ||||
|         furi_hal_usb_enable(); | ||||
|     } else if(index == UsbTestSubmenuIndexDisable) { | ||||
| @ -32,13 +34,19 @@ void usb_test_submenu_callback(void* context, uint32_t index) { | ||||
|     } else if(index == UsbTestSubmenuIndexRestart) { | ||||
|         furi_hal_usb_reinit(); | ||||
|     } else if(index == UsbTestSubmenuIndexVcpSingle) { | ||||
|         furi_hal_usb_set_config(&usb_cdc_single); | ||||
|         furi_hal_usb_set_config(&usb_cdc_single, NULL); | ||||
|     } else if(index == UsbTestSubmenuIndexVcpDual) { | ||||
|         furi_hal_usb_set_config(&usb_cdc_dual); | ||||
|         furi_hal_usb_set_config(&usb_cdc_dual, NULL); | ||||
|     } else if(index == UsbTestSubmenuIndexHid) { | ||||
|         furi_hal_usb_set_config(&usb_hid); | ||||
|         furi_hal_usb_set_config(&usb_hid, NULL); | ||||
|     } else if(index == UsbTestSubmenuIndexHidWithParams) { | ||||
|         app->hid_cfg.vid = 0x1234; | ||||
|         app->hid_cfg.pid = 0xabcd; | ||||
|         strncpy(app->hid_cfg.manuf, "WEN", sizeof(app->hid_cfg.manuf)); | ||||
|         strncpy(app->hid_cfg.product, "FLIP", sizeof(app->hid_cfg.product)); | ||||
|         furi_hal_usb_set_config(&usb_hid, &app->hid_cfg); | ||||
|     } else if(index == UsbTestSubmenuIndexHidU2F) { | ||||
|         furi_hal_usb_set_config(&usb_hid_u2f); | ||||
|         furi_hal_usb_set_config(&usb_hid_u2f, NULL); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -71,6 +79,12 @@ UsbTestApp* usb_test_app_alloc() { | ||||
|         app->submenu, "Dual VCP", UsbTestSubmenuIndexVcpDual, usb_test_submenu_callback, app); | ||||
|     submenu_add_item( | ||||
|         app->submenu, "HID KB+Mouse", UsbTestSubmenuIndexHid, usb_test_submenu_callback, app); | ||||
|     submenu_add_item( | ||||
|         app->submenu, | ||||
|         "HID KB+Mouse custom ID", | ||||
|         UsbTestSubmenuIndexHidWithParams, | ||||
|         usb_test_submenu_callback, | ||||
|         app); | ||||
|     submenu_add_item( | ||||
|         app->submenu, "HID U2F", UsbTestSubmenuIndexHidU2F, usb_test_submenu_callback, app); | ||||
|     view_set_previous_callback(submenu_get_view(app->submenu), usb_test_exit); | ||||
|  | ||||
| @ -48,6 +48,7 @@ static void desktop_scene_main_interact_animation_callback(void* context) { | ||||
|         desktop->view_dispatcher, DesktopAnimationEventInteractAnimation); | ||||
| } | ||||
| 
 | ||||
| #ifdef APP_ARCHIVE | ||||
| static void desktop_switch_to_app(Desktop* desktop, const FlipperApplication* flipper_app) { | ||||
|     furi_assert(desktop); | ||||
|     furi_assert(flipper_app); | ||||
| @ -65,6 +66,7 @@ static void desktop_switch_to_app(Desktop* desktop, const FlipperApplication* fl | ||||
| 
 | ||||
|     furi_thread_start(desktop->scene_thread); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| void desktop_scene_main_callback(DesktopEvent event, void* context) { | ||||
|     Desktop* desktop = (Desktop*)context; | ||||
|  | ||||
| @ -84,10 +84,10 @@ static void usb_uart_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) { | ||||
| 
 | ||||
| static void usb_uart_vcp_init(UsbUartBridge* usb_uart, uint8_t vcp_ch) { | ||||
|     if(vcp_ch == 0) { | ||||
|         furi_hal_usb_set_config(&usb_cdc_single); | ||||
|         furi_hal_usb_set_config(&usb_cdc_single, NULL); | ||||
|         furi_hal_vcp_disable(); | ||||
|     } else { | ||||
|         furi_hal_usb_set_config(&usb_cdc_dual); | ||||
|         furi_hal_usb_set_config(&usb_cdc_dual, NULL); | ||||
|     } | ||||
|     furi_hal_cdc_set_callbacks(vcp_ch, (CdcCallbacks*)&cdc_cb, usb_uart); | ||||
| } | ||||
| @ -247,7 +247,7 @@ static int32_t usb_uart_worker(void* context) { | ||||
| 
 | ||||
|     usb_uart_vcp_deinit(usb_uart, usb_uart->cfg.vcp_ch); | ||||
|     usb_uart_serial_deinit(usb_uart, usb_uart->cfg.uart_ch); | ||||
|     furi_hal_usb_set_config(usb_mode_prev); | ||||
|     furi_hal_usb_set_config(usb_mode_prev, NULL); | ||||
|     if(usb_uart->cfg.flow_pins != 0) { | ||||
|         hal_gpio_init_simple(flow_pins[usb_uart->cfg.flow_pins - 1][0], GpioModeAnalog); | ||||
|         hal_gpio_init_simple(flow_pins[usb_uart->cfg.flow_pins - 1][1], GpioModeAnalog); | ||||
|  | ||||
| @ -57,17 +57,18 @@ static void text_box_insert_endline(Canvas* canvas, TextBoxModel* model) { | ||||
|     const char* str = model->text; | ||||
|     size_t line_num = 0; | ||||
| 
 | ||||
|     const size_t text_width = 140; | ||||
|     const size_t text_width = 120; | ||||
| 
 | ||||
|     while(str[i] != '\0') { | ||||
|         char symb = str[i++]; | ||||
|         if(symb != '\n') { | ||||
|             line_width += canvas_glyph_width(canvas, symb) + 1; | ||||
|             if(line_width > text_width) { | ||||
|             size_t glyph_width = canvas_glyph_width(canvas, symb); | ||||
|             if(line_width + glyph_width > text_width) { | ||||
|                 line_num++; | ||||
|                 line_width = 0; | ||||
|                 string_push_back(model->text_formatted, '\n'); | ||||
|             } | ||||
|             line_width += glyph_width; | ||||
|         } else { | ||||
|             line_num++; | ||||
|             line_width = 0; | ||||
| @ -94,18 +95,19 @@ static void text_box_insert_endline(Canvas* canvas, TextBoxModel* model) { | ||||
| static void text_box_view_draw_callback(Canvas* canvas, void* _model) { | ||||
|     TextBoxModel* model = _model; | ||||
| 
 | ||||
|     if(!model->formatted) { | ||||
|         text_box_insert_endline(canvas, model); | ||||
|         model->formatted = true; | ||||
|     } | ||||
| 
 | ||||
|     canvas_clear(canvas); | ||||
|     elements_slightly_rounded_frame(canvas, 0, 0, 124, 64); | ||||
|     if(model->font == TextBoxFontText) { | ||||
|         canvas_set_font(canvas, FontSecondary); | ||||
|     } else if(model->font == TextBoxFontHex) { | ||||
|         canvas_set_font(canvas, FontKeyboard); | ||||
|     } | ||||
| 
 | ||||
|     if(!model->formatted) { | ||||
|         text_box_insert_endline(canvas, model); | ||||
|         model->formatted = true; | ||||
|     } | ||||
| 
 | ||||
|     elements_slightly_rounded_frame(canvas, 0, 0, 124, 64); | ||||
|     elements_multiline_text(canvas, 3, 11, model->text_pos); | ||||
|     elements_scrollbar(canvas, model->scroll_pos, model->scroll_num); | ||||
| } | ||||
|  | ||||
							
								
								
									
										233
									
								
								applications/gui/modules/text_input.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										233
									
								
								applications/gui/modules/text_input.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @ -131,7 +131,11 @@ static const bool char_is_lowercase(char letter) { | ||||
| } | ||||
| 
 | ||||
| static const char char_to_uppercase(const char letter) { | ||||
|     return (letter - 0x20); | ||||
|     if(isalpha(letter)) { | ||||
|         return (letter - 0x20); | ||||
|     } else { | ||||
|         return letter; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void text_input_backspace_cb(TextInputModel* model) { | ||||
| @ -255,145 +259,158 @@ static void text_input_view_draw_callback(Canvas* canvas, void* _model) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void text_input_handle_up(TextInput* text_input) { | ||||
|     with_view_model( | ||||
|         text_input->view, (TextInputModel * model) { | ||||
|             if(model->selected_row > 0) { | ||||
|                 model->selected_row--; | ||||
|                 if(model->selected_column > get_row_size(model->selected_row) - 6) { | ||||
|                     model->selected_column = model->selected_column + 1; | ||||
|                 } | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
| static void text_input_handle_up(TextInput* text_input, TextInputModel* model) { | ||||
|     if(model->selected_row > 0) { | ||||
|         model->selected_row--; | ||||
|         if(model->selected_column > get_row_size(model->selected_row) - 6) { | ||||
|             model->selected_column = model->selected_column + 1; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void text_input_handle_down(TextInput* text_input) { | ||||
|     with_view_model( | ||||
|         text_input->view, (TextInputModel * model) { | ||||
|             if(model->selected_row < keyboard_row_count - 1) { | ||||
|                 model->selected_row++; | ||||
|                 if(model->selected_column > get_row_size(model->selected_row) - 4) { | ||||
|                     model->selected_column = model->selected_column - 1; | ||||
|                 } | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
| static void text_input_handle_down(TextInput* text_input, TextInputModel* model) { | ||||
|     if(model->selected_row < keyboard_row_count - 1) { | ||||
|         model->selected_row++; | ||||
|         if(model->selected_column > get_row_size(model->selected_row) - 4) { | ||||
|             model->selected_column = model->selected_column - 1; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void text_input_handle_left(TextInput* text_input) { | ||||
|     with_view_model( | ||||
|         text_input->view, (TextInputModel * model) { | ||||
|             if(model->selected_column > 0) { | ||||
|                 model->selected_column--; | ||||
|             } else { | ||||
|                 model->selected_column = get_row_size(model->selected_row) - 1; | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
| static void text_input_handle_left(TextInput* text_input, TextInputModel* model) { | ||||
|     if(model->selected_column > 0) { | ||||
|         model->selected_column--; | ||||
|     } else { | ||||
|         model->selected_column = get_row_size(model->selected_row) - 1; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void text_input_handle_right(TextInput* text_input) { | ||||
|     with_view_model( | ||||
|         text_input->view, (TextInputModel * model) { | ||||
|             if(model->selected_column < get_row_size(model->selected_row) - 1) { | ||||
|                 model->selected_column++; | ||||
|             } else { | ||||
|                 model->selected_column = 0; | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
| static void text_input_handle_right(TextInput* text_input, TextInputModel* model) { | ||||
|     if(model->selected_column < get_row_size(model->selected_row) - 1) { | ||||
|         model->selected_column++; | ||||
|     } else { | ||||
|         model->selected_column = 0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void text_input_handle_ok(TextInput* text_input) { | ||||
|     with_view_model( | ||||
|         text_input->view, (TextInputModel * model) { | ||||
|             char selected = get_selected_char(model); | ||||
|             uint8_t text_length = strlen(model->text_buffer); | ||||
| static void text_input_handle_ok(TextInput* text_input, TextInputModel* model, bool shift) { | ||||
|     char selected = get_selected_char(model); | ||||
|     uint8_t text_length = strlen(model->text_buffer); | ||||
| 
 | ||||
|             if(selected == ENTER_KEY) { | ||||
|                 if(model->validator_callback && (!model->validator_callback( | ||||
|                                                     model->text_buffer, | ||||
|                                                     model->validator_text, | ||||
|                                                     model->validator_callback_context))) { | ||||
|                     model->valadator_message_visible = true; | ||||
|                     osTimerStart(text_input->timer, osKernelGetTickFreq() * 4); | ||||
|                 } else if(model->callback != 0 && text_length > 0) { | ||||
|                     model->callback(model->callback_context); | ||||
|                 } | ||||
|             } else if(selected == BACKSPACE_KEY) { | ||||
|                 text_input_backspace_cb(model); | ||||
|             } else if(text_length < (model->text_buffer_size - 1)) { | ||||
|                 if(model->clear_default_text) { | ||||
|                     text_length = 0; | ||||
|                 } | ||||
|                 if(text_length == 0 && char_is_lowercase(selected)) { | ||||
|                     selected = char_to_uppercase(selected); | ||||
|                 } | ||||
|                 model->text_buffer[text_length] = selected; | ||||
|                 model->text_buffer[text_length + 1] = 0; | ||||
|             } | ||||
|             model->clear_default_text = false; | ||||
|             return true; | ||||
|         }); | ||||
|     if(shift) { | ||||
|         selected = char_to_uppercase(selected); | ||||
|     } | ||||
| 
 | ||||
|     if(selected == ENTER_KEY) { | ||||
|         if(model->validator_callback && | ||||
|            (!model->validator_callback( | ||||
|                model->text_buffer, model->validator_text, model->validator_callback_context))) { | ||||
|             model->valadator_message_visible = true; | ||||
|             osTimerStart(text_input->timer, osKernelGetTickFreq() * 4); | ||||
|         } else if(model->callback != 0 && text_length > 0) { | ||||
|             model->callback(model->callback_context); | ||||
|         } | ||||
|     } else if(selected == BACKSPACE_KEY) { | ||||
|         text_input_backspace_cb(model); | ||||
|     } else if(text_length < (model->text_buffer_size - 1)) { | ||||
|         if(model->clear_default_text) { | ||||
|             text_length = 0; | ||||
|         } | ||||
|         if(text_length == 0 && char_is_lowercase(selected)) { | ||||
|             selected = char_to_uppercase(selected); | ||||
|         } | ||||
|         model->text_buffer[text_length] = selected; | ||||
|         model->text_buffer[text_length + 1] = 0; | ||||
|     } | ||||
|     model->clear_default_text = false; | ||||
| } | ||||
| 
 | ||||
| static bool text_input_view_input_callback(InputEvent* event, void* context) { | ||||
|     TextInput* text_input = context; | ||||
|     furi_assert(text_input); | ||||
| 
 | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event->type == InputTypeShort || event->type == InputTypeRepeat) { | ||||
|         with_view_model( | ||||
|             text_input->view, (TextInputModel * model) { | ||||
|                 if(model->valadator_message_visible) { | ||||
|                     if(event->key == InputKeyBack) { | ||||
|                         consumed = true; | ||||
|                     } | ||||
|                 } | ||||
|                 model->valadator_message_visible = false; | ||||
|                 return false; | ||||
|             }); | ||||
|     // Acquire model
 | ||||
|     TextInputModel* model = view_get_model(text_input->view); | ||||
| 
 | ||||
|     if((!(event->type == InputTypePress) && !(event->type == InputTypeRelease)) && | ||||
|        model->valadator_message_visible) { | ||||
|         model->valadator_message_visible = false; | ||||
|         consumed = true; | ||||
|     } else if(event->type == InputTypeShort) { | ||||
|         consumed = true; | ||||
|         switch(event->key) { | ||||
|         case InputKeyUp: | ||||
|             text_input_handle_up(text_input); | ||||
|             consumed = true; | ||||
|             text_input_handle_up(text_input, model); | ||||
|             break; | ||||
|         case InputKeyDown: | ||||
|             text_input_handle_down(text_input); | ||||
|             consumed = true; | ||||
|             text_input_handle_down(text_input, model); | ||||
|             break; | ||||
|         case InputKeyLeft: | ||||
|             text_input_handle_left(text_input); | ||||
|             consumed = true; | ||||
|             text_input_handle_left(text_input, model); | ||||
|             break; | ||||
|         case InputKeyRight: | ||||
|             text_input_handle_right(text_input); | ||||
|             consumed = true; | ||||
|             text_input_handle_right(text_input, model); | ||||
|             break; | ||||
|         case InputKeyOk: | ||||
|             text_input_handle_ok(text_input); | ||||
|             consumed = true; | ||||
|             text_input_handle_ok(text_input, model, false); | ||||
|             break; | ||||
|         default: | ||||
|             consumed = false; | ||||
|             break; | ||||
|         } | ||||
|     } else if(event->type == InputTypeLong) { | ||||
|         consumed = true; | ||||
|         switch(event->key) { | ||||
|         case InputKeyUp: | ||||
|             text_input_handle_up(text_input, model); | ||||
|             break; | ||||
|         case InputKeyDown: | ||||
|             text_input_handle_down(text_input, model); | ||||
|             break; | ||||
|         case InputKeyLeft: | ||||
|             text_input_handle_left(text_input, model); | ||||
|             break; | ||||
|         case InputKeyRight: | ||||
|             text_input_handle_right(text_input, model); | ||||
|             break; | ||||
|         case InputKeyOk: | ||||
|             text_input_handle_ok(text_input, model, true); | ||||
|             break; | ||||
|         case InputKeyBack: | ||||
|             text_input_backspace_cb(model); | ||||
|             break; | ||||
|         default: | ||||
|             consumed = false; | ||||
|             break; | ||||
|         } | ||||
|     } else if(event->type == InputTypeRepeat) { | ||||
|         consumed = true; | ||||
|         switch(event->key) { | ||||
|         case InputKeyUp: | ||||
|             text_input_handle_up(text_input, model); | ||||
|             break; | ||||
|         case InputKeyDown: | ||||
|             text_input_handle_down(text_input, model); | ||||
|             break; | ||||
|         case InputKeyLeft: | ||||
|             text_input_handle_left(text_input, model); | ||||
|             break; | ||||
|         case InputKeyRight: | ||||
|             text_input_handle_right(text_input, model); | ||||
|             break; | ||||
|         case InputKeyBack: | ||||
|             text_input_backspace_cb(model); | ||||
|             break; | ||||
|         default: | ||||
|             consumed = false; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if((event->type == InputTypeLong || event->type == InputTypeRepeat) && | ||||
|        event->key == InputKeyBack) { | ||||
|         with_view_model( | ||||
|             text_input->view, (TextInputModel * model) { | ||||
|                 if(model->valadator_message_visible) { | ||||
|                     model->valadator_message_visible = false; | ||||
|                 } else { | ||||
|                     text_input_backspace_cb(model); | ||||
|                 } | ||||
|                 return true; | ||||
|             }); | ||||
| 
 | ||||
|         consumed = true; | ||||
|     } | ||||
|     // Commit model
 | ||||
|     view_commit_model(text_input->view, consumed); | ||||
| 
 | ||||
|     return consumed; | ||||
| } | ||||
|  | ||||
| @ -3,8 +3,6 @@ | ||||
| #include <callback-connector.h> | ||||
| #include <maxim_crc.h> | ||||
| 
 | ||||
| extern COMP_HandleTypeDef hcomp1; | ||||
| 
 | ||||
| KeyReader::Error KeyReader::read(iButtonKey* key) { | ||||
|     uint8_t tmp_key_data[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | ||||
|     iButtonKeyType key_type; | ||||
| @ -116,9 +114,9 @@ void KeyReader::start_comaparator(void) { | ||||
| 
 | ||||
|     comparator_callback_pointer = | ||||
|         cbc::obtain_connector(this, &KeyReader::comparator_trigger_callback); | ||||
|     api_interrupt_add(comparator_callback_pointer, InterruptTypeComparatorTrigger, this); | ||||
|     furi_hal_rfid_comp_set_callback(comparator_callback_pointer, this); | ||||
|     last_dwt_value = DWT->CYCCNT; | ||||
|     HAL_COMP_Start(&hcomp1); | ||||
|     furi_hal_rfid_comp_start(); | ||||
| } | ||||
| 
 | ||||
| void KeyReader::stop_comaparator(void) { | ||||
| @ -127,23 +125,19 @@ void KeyReader::stop_comaparator(void) { | ||||
|     // rfid_pins_reset will disable ibutton pin
 | ||||
|     furi_hal_ibutton_start(); | ||||
| 
 | ||||
|     HAL_COMP_Stop(&hcomp1); | ||||
|     api_interrupt_remove(comparator_callback_pointer, InterruptTypeComparatorTrigger); | ||||
|     furi_hal_rfid_comp_stop(); | ||||
|     furi_hal_rfid_comp_set_callback(NULL, NULL); | ||||
| } | ||||
| 
 | ||||
| void KeyReader::comparator_trigger_callback(void* hcomp, void* comp_ctx) { | ||||
| void KeyReader::comparator_trigger_callback(bool level, void* comp_ctx) { | ||||
|     KeyReader* _this = static_cast<KeyReader*>(comp_ctx); | ||||
| 
 | ||||
|     if(hcomp == &hcomp1) { | ||||
|         uint32_t current_dwt_value = DWT->CYCCNT; | ||||
|     uint32_t current_dwt_value = DWT->CYCCNT; | ||||
| 
 | ||||
|         _this->cyfral_decoder.process_front( | ||||
|             hal_gpio_get_rfid_in_level(), current_dwt_value - last_dwt_value); | ||||
|         _this->metakom_decoder.process_front( | ||||
|             hal_gpio_get_rfid_in_level(), current_dwt_value - last_dwt_value); | ||||
|     _this->cyfral_decoder.process_front(level, current_dwt_value - last_dwt_value); | ||||
|     _this->metakom_decoder.process_front(level, current_dwt_value - last_dwt_value); | ||||
| 
 | ||||
|         last_dwt_value = current_dwt_value; | ||||
|     } | ||||
|     last_dwt_value = current_dwt_value; | ||||
| } | ||||
| 
 | ||||
| void KeyReader::switch_to(ReadMode mode) { | ||||
|  | ||||
| @ -28,8 +28,8 @@ private: | ||||
|     bool verify_key(iButtonKeyType key_type, const uint8_t* const data, uint8_t data_size); | ||||
| 
 | ||||
|     // cyfral and metakom readers data
 | ||||
|     void comparator_trigger_callback(void* hcomp, void* comp_ctx); | ||||
|     void (*comparator_callback_pointer)(void* hcomp, void* comp_ctx); | ||||
|     void comparator_trigger_callback(bool level, void* comp_ctx); | ||||
|     void (*comparator_callback_pointer)(bool level, void* comp_ctx); | ||||
| 
 | ||||
|     void start_comaparator(void); | ||||
|     void stop_comaparator(void); | ||||
| @ -51,4 +51,4 @@ private: | ||||
| 
 | ||||
|     void switch_to(ReadMode mode); | ||||
|     void switch_mode_if_needed(); | ||||
| }; | ||||
| }; | ||||
|  | ||||
| @ -2,8 +2,6 @@ | ||||
| #include <callback-connector.h> | ||||
| #include <maxim_crc.h> | ||||
| 
 | ||||
| extern COMP_HandleTypeDef hcomp1; | ||||
| 
 | ||||
| KeyReader::Error KeyWorker::read(iButtonKey* key) { | ||||
|     KeyReader::Error result = key_reader.read(key); | ||||
| 
 | ||||
| @ -51,4 +49,4 @@ KeyWorker::KeyWorker(const GpioPin* one_wire_gpio) | ||||
| } | ||||
| 
 | ||||
| KeyWorker::~KeyWorker() { | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -12,10 +12,11 @@ int32_t InfraredApp::run(void* args) { | ||||
|     bool exit = false; | ||||
| 
 | ||||
|     if(args) { | ||||
|         std::string full_name = static_cast<const char*>(args); | ||||
|         std::string remote_name(full_name, full_name.find_last_of('/') + 1, full_name.size()); | ||||
|         std::string path = static_cast<const char*>(args); | ||||
|         std::string remote_name(path, path.find_last_of('/') + 1, path.size()); | ||||
|         remote_name.erase(remote_name.find_last_of('.')); | ||||
|         bool result = remote_manager.load(remote_name); | ||||
|         path.erase(path.find_last_of('/')); | ||||
|         bool result = remote_manager.load(path, remote_name); | ||||
|         if(result) { | ||||
|             current_scene = InfraredApp::Scene::Remote; | ||||
|         } else { | ||||
|  | ||||
| @ -15,16 +15,18 @@ | ||||
| 
 | ||||
| static const std::string default_remote_name = "remote"; | ||||
| 
 | ||||
| std::string InfraredAppRemoteManager::make_full_name(const std::string& remote_name) const { | ||||
|     return std::string("") + InfraredApp::infrared_directory + "/" + remote_name + | ||||
|            InfraredApp::infrared_extension; | ||||
| std::string InfraredAppRemoteManager::make_full_name( | ||||
|     const std::string& path, | ||||
|     const std::string& remote_name) const { | ||||
|     return std::string("") + path + "/" + remote_name + InfraredApp::infrared_extension; | ||||
| } | ||||
| 
 | ||||
| std::string InfraredAppRemoteManager::find_vacant_remote_name(const std::string& name) { | ||||
|     bool exist = true; | ||||
|     FileWorkerCpp file_worker; | ||||
| 
 | ||||
|     if(!file_worker.is_file_exist(make_full_name(name).c_str(), &exist)) { | ||||
|     if(!file_worker.is_file_exist( | ||||
|            make_full_name(InfraredApp::infrared_directory, name).c_str(), &exist)) { | ||||
|         return std::string(); | ||||
|     } else if(!exist) { | ||||
|         return name; | ||||
| @ -35,7 +37,7 @@ std::string InfraredAppRemoteManager::find_vacant_remote_name(const std::string& | ||||
|     bool file_worker_result = false; | ||||
|     std::string new_name; | ||||
|     do { | ||||
|         new_name = make_full_name(name + std::to_string(++i)); | ||||
|         new_name = make_full_name(InfraredApp::infrared_directory, name + std::to_string(++i)); | ||||
|         file_worker_result = file_worker.is_file_exist(new_name.c_str(), &exist); | ||||
|     } while(file_worker_result && exist); | ||||
| 
 | ||||
| @ -57,7 +59,7 @@ bool InfraredAppRemoteManager::add_remote_with_button( | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     remote = std::make_unique<InfraredAppRemote>(new_name); | ||||
|     remote = std::make_unique<InfraredAppRemote>(InfraredApp::infrared_directory, new_name); | ||||
|     return add_button(button_name, signal); | ||||
| } | ||||
| 
 | ||||
| @ -84,7 +86,7 @@ const InfraredAppSignal& InfraredAppRemoteManager::get_button_data(size_t index) | ||||
| bool InfraredAppRemoteManager::delete_remote() { | ||||
|     bool result; | ||||
|     FileWorkerCpp file_worker; | ||||
|     result = file_worker.remove(make_full_name(remote->name).c_str()); | ||||
|     result = file_worker.remove(make_full_name(remote->path, remote->name).c_str()); | ||||
| 
 | ||||
|     reset_remote(); | ||||
|     return result; | ||||
| @ -128,8 +130,8 @@ bool InfraredAppRemoteManager::rename_remote(const char* str) { | ||||
|     } | ||||
| 
 | ||||
|     FileWorkerCpp file_worker; | ||||
|     std::string old_filename = make_full_name(remote->name); | ||||
|     std::string new_filename = make_full_name(new_name); | ||||
|     std::string old_filename = make_full_name(remote->path, remote->name); | ||||
|     std::string new_filename = make_full_name(remote->path, new_name); | ||||
|     bool result = file_worker.rename(old_filename.c_str(), new_filename.c_str()); | ||||
| 
 | ||||
|     remote->name = new_name; | ||||
| @ -160,8 +162,10 @@ bool InfraredAppRemoteManager::store(void) { | ||||
|     Storage* storage = static_cast<Storage*>(furi_record_open("storage")); | ||||
|     FlipperFormat* ff = flipper_format_file_alloc(storage); | ||||
| 
 | ||||
|     FURI_LOG_I("RemoteManager", "store file: \'%s\'", make_full_name(remote->name).c_str()); | ||||
|     result = flipper_format_file_open_always(ff, make_full_name(remote->name).c_str()); | ||||
|     FURI_LOG_I( | ||||
|         "RemoteManager", "store file: \'%s\'", make_full_name(remote->path, remote->name).c_str()); | ||||
|     result = | ||||
|         flipper_format_file_open_always(ff, make_full_name(remote->path, remote->name).c_str()); | ||||
|     if(result) { | ||||
|         result = flipper_format_write_header_cstr(ff, "IR signals file", 1); | ||||
|     } | ||||
| @ -179,13 +183,13 @@ bool InfraredAppRemoteManager::store(void) { | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| bool InfraredAppRemoteManager::load(const std::string& remote_name) { | ||||
| bool InfraredAppRemoteManager::load(const std::string& path, const std::string& remote_name) { | ||||
|     bool result = false; | ||||
|     Storage* storage = static_cast<Storage*>(furi_record_open("storage")); | ||||
|     FlipperFormat* ff = flipper_format_file_alloc(storage); | ||||
| 
 | ||||
|     FURI_LOG_I("RemoteManager", "load file: \'%s\'", make_full_name(remote_name).c_str()); | ||||
|     result = flipper_format_file_open_existing(ff, make_full_name(remote_name).c_str()); | ||||
|     FURI_LOG_I("RemoteManager", "load file: \'%s\'", make_full_name(path, remote_name).c_str()); | ||||
|     result = flipper_format_file_open_existing(ff, make_full_name(path, remote_name).c_str()); | ||||
|     if(result) { | ||||
|         string_t header; | ||||
|         string_init(header); | ||||
| @ -197,7 +201,7 @@ bool InfraredAppRemoteManager::load(const std::string& remote_name) { | ||||
|         string_clear(header); | ||||
|     } | ||||
|     if(result) { | ||||
|         remote = std::make_unique<InfraredAppRemote>(remote_name); | ||||
|         remote = std::make_unique<InfraredAppRemote>(path, remote_name); | ||||
|         InfraredAppSignal signal; | ||||
|         std::string signal_name; | ||||
|         while(infrared_parser_read_signal(ff, signal, signal_name)) { | ||||
|  | ||||
| @ -59,14 +59,18 @@ class InfraredAppRemote { | ||||
|     std::vector<InfraredAppRemoteButton> buttons; | ||||
|     /** Name of remote */ | ||||
|     std::string name; | ||||
|     /** Path to remote file */ | ||||
|     std::string path; | ||||
| 
 | ||||
| public: | ||||
|     /** Initialize new remote
 | ||||
|      * | ||||
|      *  | ||||
|      * @param path - remote file path | ||||
|      * @param name - new remote name | ||||
|      */ | ||||
|     InfraredAppRemote(const std::string& name) | ||||
|         : name(name) { | ||||
|     InfraredAppRemote(const std::string& path, const std::string& name) | ||||
|         : name(name) | ||||
|         , path(path) { | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| @ -79,7 +83,7 @@ class InfraredAppRemoteManager { | ||||
|      * @param remote_name name of remote | ||||
|      * @retval full name of remote on disk | ||||
|      */ | ||||
|     std::string make_full_name(const std::string& remote_name) const; | ||||
|     std::string make_full_name(const std::string& path, const std::string& remote_name) const; | ||||
| 
 | ||||
| public: | ||||
|     /** Restriction to button name length. Buttons larger are ignored. */ | ||||
| @ -184,5 +188,5 @@ public: | ||||
|      * @param name - name of remote to load | ||||
|      * @retval true if success, false otherwise | ||||
|      */ | ||||
|     bool load(const std::string& name); | ||||
|     bool load(const std::string& path, const std::string& name); | ||||
| }; | ||||
|  | ||||
| @ -29,7 +29,7 @@ void InfraredAppSceneRemoteList::on_enter(InfraredApp* app) { | ||||
|         last_selected_remote_name); | ||||
| 
 | ||||
|     if(file_select_result) { | ||||
|         if(remote_manager->load(std::string(filename_ts->text))) { | ||||
|         if(remote_manager->load(InfraredApp::infrared_directory, std::string(filename_ts->text))) { | ||||
|             app->switch_to_next_scene(InfraredApp::Scene::Remote); | ||||
|             result = true; | ||||
|         } | ||||
|  | ||||
| @ -4,8 +4,6 @@ | ||||
| #include <stm32wbxx_ll_cortex.h> | ||||
| #include <tim.h> | ||||
| 
 | ||||
| extern COMP_HandleTypeDef hcomp1; | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief private violation assistant for RfidReader | ||||
|  */ | ||||
| @ -63,14 +61,10 @@ void RfidReader::switch_mode() { | ||||
|     switch_timer_reset(); | ||||
| } | ||||
| 
 | ||||
| static void comparator_trigger_callback(void* hcomp, void* comp_ctx) { | ||||
|     COMP_HandleTypeDef* _hcomp = static_cast<COMP_HandleTypeDef*>(hcomp); | ||||
| static void comparator_trigger_callback(bool level, void* comp_ctx) { | ||||
|     RfidReader* _this = static_cast<RfidReader*>(comp_ctx); | ||||
| 
 | ||||
|     if(hcomp == &hcomp1) { | ||||
|         RfidReaderAccessor::decode( | ||||
|             *_this, (HAL_COMP_GetOutputLevel(_hcomp) == COMP_OUTPUT_LEVEL_HIGH)); | ||||
|     } | ||||
|     RfidReaderAccessor::decode(*_this, !level); | ||||
| } | ||||
| 
 | ||||
| RfidReader::RfidReader() { | ||||
| @ -163,25 +157,13 @@ bool RfidReader::any_read() { | ||||
| } | ||||
| 
 | ||||
| void RfidReader::start_comparator(void) { | ||||
|     api_interrupt_add(comparator_trigger_callback, InterruptTypeComparatorTrigger, this); | ||||
|     furi_hal_rfid_comp_set_callback(comparator_trigger_callback, this); | ||||
|     last_dwt_value = DWT->CYCCNT; | ||||
| 
 | ||||
|     hcomp1.Init.InputMinus = COMP_INPUT_MINUS_1_2VREFINT; | ||||
|     hcomp1.Init.InputPlus = COMP_INPUT_PLUS_IO1; | ||||
|     hcomp1.Init.OutputPol = COMP_OUTPUTPOL_NONINVERTED; | ||||
|     hcomp1.Init.Hysteresis = COMP_HYSTERESIS_HIGH; | ||||
|     hcomp1.Init.BlankingSrce = COMP_BLANKINGSRC_NONE; | ||||
|     hcomp1.Init.Mode = COMP_POWERMODE_MEDIUMSPEED; | ||||
|     hcomp1.Init.WindowMode = COMP_WINDOWMODE_DISABLE; | ||||
|     hcomp1.Init.TriggerMode = COMP_TRIGGERMODE_IT_RISING_FALLING; | ||||
|     if(HAL_COMP_Init(&hcomp1) != HAL_OK) { | ||||
|         Error_Handler(); | ||||
|     } | ||||
| 
 | ||||
|     HAL_COMP_Start(&hcomp1); | ||||
|     furi_hal_rfid_comp_start(); | ||||
| } | ||||
| 
 | ||||
| void RfidReader::stop_comparator(void) { | ||||
|     HAL_COMP_Stop(&hcomp1); | ||||
|     api_interrupt_remove(comparator_trigger_callback, InterruptTypeComparatorTrigger); | ||||
| } | ||||
|     furi_hal_rfid_comp_stop(); | ||||
|     furi_hal_rfid_comp_set_callback(NULL, NULL); | ||||
| } | ||||
|  | ||||
| @ -4,8 +4,6 @@ | ||||
| #include "protocols/protocol_hid_h10301.h" | ||||
| #include "protocols/protocol_indala_40134.h" | ||||
| 
 | ||||
| extern COMP_HandleTypeDef hcomp1; | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief all timings are specified in field clocks (field clock = 125 kHz, 8 us) | ||||
|  *  | ||||
|  | ||||
| @ -1,35 +1,16 @@ | ||||
| #include "lfrfid_debug_app_scene_tune.h" | ||||
| #include <furi_hal.h> | ||||
| 
 | ||||
| extern COMP_HandleTypeDef hcomp1; | ||||
| 
 | ||||
| static void comparator_trigger_callback(void* hcomp, void* comp_ctx) { | ||||
|     COMP_HandleTypeDef* _hcomp = static_cast<COMP_HandleTypeDef*>(hcomp); | ||||
| 
 | ||||
|     if(hcomp == &hcomp1) { | ||||
|         hal_gpio_write(&gpio_ext_pa7, HAL_COMP_GetOutputLevel(_hcomp) == COMP_OUTPUT_LEVEL_HIGH); | ||||
|     } | ||||
| static void comparator_trigger_callback(bool level, void* comp_ctx) { | ||||
|     hal_gpio_write(&gpio_ext_pa7, !level); | ||||
| } | ||||
| 
 | ||||
| void LfRfidDebugAppSceneTune::on_enter(LfRfidDebugApp* app, bool need_restore) { | ||||
|     app->view_controller.switch_to<LfRfidViewTuneVM>(); | ||||
|     hal_gpio_init_simple(&gpio_ext_pa7, GpioModeOutputPushPull); | ||||
| 
 | ||||
|     api_interrupt_add(comparator_trigger_callback, InterruptTypeComparatorTrigger, this); | ||||
| 
 | ||||
|     hcomp1.Init.InputMinus = COMP_INPUT_MINUS_1_2VREFINT; | ||||
|     hcomp1.Init.InputPlus = COMP_INPUT_PLUS_IO1; | ||||
|     hcomp1.Init.OutputPol = COMP_OUTPUTPOL_NONINVERTED; | ||||
|     hcomp1.Init.Hysteresis = COMP_HYSTERESIS_HIGH; | ||||
|     hcomp1.Init.BlankingSrce = COMP_BLANKINGSRC_NONE; | ||||
|     hcomp1.Init.Mode = COMP_POWERMODE_MEDIUMSPEED; | ||||
|     hcomp1.Init.WindowMode = COMP_WINDOWMODE_DISABLE; | ||||
|     hcomp1.Init.TriggerMode = COMP_TRIGGERMODE_IT_RISING_FALLING; | ||||
|     if(HAL_COMP_Init(&hcomp1) != HAL_OK) { | ||||
|         Error_Handler(); | ||||
|     } | ||||
| 
 | ||||
|     HAL_COMP_Start(&hcomp1); | ||||
|     furi_hal_rfid_comp_set_callback(comparator_trigger_callback, this); | ||||
|     furi_hal_rfid_comp_start(); | ||||
| 
 | ||||
|     furi_hal_rfid_pins_read(); | ||||
|     furi_hal_rfid_tim_read(125000, 0.5); | ||||
| @ -50,11 +31,11 @@ bool LfRfidDebugAppSceneTune::on_event(LfRfidDebugApp* app, LfRfidDebugApp::Even | ||||
| } | ||||
| 
 | ||||
| void LfRfidDebugAppSceneTune::on_exit(LfRfidDebugApp* app) { | ||||
|     HAL_COMP_Stop(&hcomp1); | ||||
|     api_interrupt_remove(comparator_trigger_callback, InterruptTypeComparatorTrigger); | ||||
|     furi_hal_rfid_comp_stop(); | ||||
|     furi_hal_rfid_comp_set_callback(NULL, NULL); | ||||
| 
 | ||||
|     hal_gpio_init_simple(&gpio_ext_pa7, GpioModeAnalog); | ||||
|     furi_hal_rfid_tim_read_stop(); | ||||
|     furi_hal_rfid_tim_reset(); | ||||
|     furi_hal_rfid_pins_reset(); | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -102,7 +102,7 @@ typedef struct { | ||||
|     uint8_t volume_id_max; | ||||
| } State; | ||||
| 
 | ||||
| const float volumes[] = {0, 0.02, 0.05, 0.1, 0.5}; | ||||
| const float volumes[] = {0, .25, .5, .75, 1}; | ||||
| 
 | ||||
| bool is_white_note(const MelodyEventRecord* note_record, uint8_t id) { | ||||
|     if(note_record == NULL) return false; | ||||
| @ -332,10 +332,10 @@ void process_note( | ||||
|     // play note
 | ||||
|     float note_delay = bar_length_ms / (float)note_record->length; | ||||
|     if(note_record->note != N) { | ||||
|         hal_pwm_set(volume, note_record->note, &SPEAKER_TIM, SPEAKER_CH); | ||||
|         furi_hal_speaker_start(note_record->note, volume); | ||||
|     } | ||||
|     delay(note_delay); | ||||
|     hal_pwm_stop(&SPEAKER_TIM, SPEAKER_CH); | ||||
|     furi_hal_speaker_stop(); | ||||
| } | ||||
| 
 | ||||
| void music_player_thread(void* p) { | ||||
| @ -447,7 +447,7 @@ int32_t music_player_app(void* p) { | ||||
|     } | ||||
| 
 | ||||
|     osThreadTerminate(player); | ||||
|     hal_pwm_stop(&SPEAKER_TIM, SPEAKER_CH); | ||||
|     furi_hal_speaker_stop(); | ||||
|     view_port_enabled_set(view_port, false); | ||||
|     gui_remove_view_port(gui, view_port); | ||||
|     furi_record_close("gui"); | ||||
|  | ||||
| @ -8,4 +8,5 @@ enum NfcCustomEvent { | ||||
|     NfcCustomEventWorkerExit, | ||||
|     NfcCustomEventByteInputDone, | ||||
|     NfcCustomEventTextInputDone, | ||||
|     NfcCustomEventDictAttackDone, | ||||
| }; | ||||
							
								
								
									
										53
									
								
								applications/nfc/helpers/nfc_mf_classic_dict.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								applications/nfc/helpers/nfc_mf_classic_dict.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| #include "nfc_mf_classic_dict.h" | ||||
| 
 | ||||
| #include <flipper_format/flipper_format.h> | ||||
| #include <lib/toolbox/args.h> | ||||
| 
 | ||||
| #define NFC_MF_CLASSIC_DICT_PATH "/ext/nfc/assets/mf_classic_dict.nfc" | ||||
| 
 | ||||
| #define NFC_MF_CLASSIC_KEY_LEN (13) | ||||
| 
 | ||||
| bool nfc_mf_classic_dict_check_presence(Storage* storage) { | ||||
|     furi_assert(storage); | ||||
|     return storage_common_stat(storage, NFC_MF_CLASSIC_DICT_PATH, NULL) == FSE_OK; | ||||
| } | ||||
| 
 | ||||
| bool nfc_mf_classic_dict_open_file(Stream* stream) { | ||||
|     furi_assert(stream); | ||||
|     return file_stream_open(stream, NFC_MF_CLASSIC_DICT_PATH, FSAM_READ, FSOM_OPEN_EXISTING); | ||||
| } | ||||
| 
 | ||||
| void nfc_mf_classic_dict_close_file(Stream* stream) { | ||||
|     furi_assert(stream); | ||||
|     file_stream_close(stream); | ||||
| } | ||||
| 
 | ||||
| bool nfc_mf_classic_dict_get_next_key(Stream* stream, uint64_t* key) { | ||||
|     furi_assert(stream); | ||||
|     furi_assert(key); | ||||
|     uint8_t key_byte_tmp = 0; | ||||
|     string_t next_line; | ||||
|     string_init(next_line); | ||||
|     *key = 0; | ||||
| 
 | ||||
|     bool next_key_read = false; | ||||
|     while(!next_key_read) { | ||||
|         if(stream_read_line(stream, next_line)) break; | ||||
|         if(string_get_char(next_line, 0) == '#') continue; | ||||
|         if(string_size(next_line) != NFC_MF_CLASSIC_KEY_LEN) continue; | ||||
|         for(uint8_t i = 0; i < 12; i += 2) { | ||||
|             args_char_to_hex( | ||||
|                 string_get_char(next_line, i), string_get_char(next_line, i + 1), &key_byte_tmp); | ||||
|             *key |= (uint64_t)key_byte_tmp << 8 * (5 - i / 2); | ||||
|         } | ||||
|         next_key_read = true; | ||||
|     } | ||||
| 
 | ||||
|     string_clear(next_line); | ||||
|     return next_key_read; | ||||
| } | ||||
| 
 | ||||
| void nfc_mf_classic_dict_reset(Stream* stream) { | ||||
|     furi_assert(stream); | ||||
|     stream_rewind(stream); | ||||
| } | ||||
							
								
								
									
										15
									
								
								applications/nfc/helpers/nfc_mf_classic_dict.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								applications/nfc/helpers/nfc_mf_classic_dict.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| #include <storage/storage.h> | ||||
| #include <lib/toolbox/stream/file_stream.h> | ||||
| 
 | ||||
| bool nfc_mf_classic_dict_check_presence(Storage* storage); | ||||
| 
 | ||||
| bool nfc_mf_classic_dict_open_file(Stream* stream); | ||||
| 
 | ||||
| void nfc_mf_classic_dict_close_file(Stream* stream); | ||||
| 
 | ||||
| bool nfc_mf_classic_dict_get_next_key(Stream* stream, uint64_t* key); | ||||
| 
 | ||||
| void nfc_mf_classic_dict_reset(Stream* stream); | ||||
| @ -79,6 +79,11 @@ Nfc* nfc_alloc() { | ||||
|     view_dispatcher_add_view( | ||||
|         nfc->view_dispatcher, NfcViewBankCard, bank_card_get_view(nfc->bank_card)); | ||||
| 
 | ||||
|     // Dict Attack
 | ||||
|     nfc->dict_attack = dict_attack_alloc(); | ||||
|     view_dispatcher_add_view( | ||||
|         nfc->view_dispatcher, NfcViewDictAttack, dict_attack_get_view(nfc->dict_attack)); | ||||
| 
 | ||||
|     return nfc; | ||||
| } | ||||
| 
 | ||||
| @ -121,6 +126,10 @@ void nfc_free(Nfc* nfc) { | ||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewBankCard); | ||||
|     bank_card_free(nfc->bank_card); | ||||
| 
 | ||||
|     // Dict Attack
 | ||||
|     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewDictAttack); | ||||
|     dict_attack_free(nfc->dict_attack); | ||||
| 
 | ||||
|     // Worker
 | ||||
|     nfc_worker_stop(nfc->worker); | ||||
|     nfc_worker_free(nfc->worker); | ||||
|  | ||||
							
								
								
									
										486
									
								
								applications/nfc/nfc_device.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										486
									
								
								applications/nfc/nfc_device.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @ -16,24 +16,29 @@ NfcDevice* nfc_device_alloc() { | ||||
| 
 | ||||
| void nfc_device_free(NfcDevice* nfc_dev) { | ||||
|     furi_assert(nfc_dev); | ||||
|     nfc_device_clear(nfc_dev); | ||||
|     furi_record_close("storage"); | ||||
|     furi_record_close("dialogs"); | ||||
|     free(nfc_dev); | ||||
| } | ||||
| 
 | ||||
| void nfc_device_prepare_format_string(NfcDevice* dev, string_t format_string) { | ||||
| static void nfc_device_prepare_format_string(NfcDevice* dev, string_t format_string) { | ||||
|     if(dev->format == NfcDeviceSaveFormatUid) { | ||||
|         string_set_str(format_string, "UID"); | ||||
|     } else if(dev->format == NfcDeviceSaveFormatBankCard) { | ||||
|         string_set_str(format_string, "Bank card"); | ||||
|     } else if(dev->format == NfcDeviceSaveFormatMifareUl) { | ||||
|         string_set_str(format_string, nfc_mf_ul_type(dev->dev_data.mf_ul_data.type, true)); | ||||
|     } else if(dev->format == NfcDeviceSaveFormatMifareClassic) { | ||||
|         string_set_str(format_string, "Mifare Classic"); | ||||
|     } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) { | ||||
|         string_set_str(format_string, "Mifare DESFire"); | ||||
|     } else { | ||||
|         string_set_str(format_string, "Unknown"); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) { | ||||
| static bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) { | ||||
|     if(string_start_with_str_p(format_string, "UID")) { | ||||
|         dev->format = NfcDeviceSaveFormatUid; | ||||
|         dev->dev_data.nfc_data.protocol = NfcDeviceProtocolUnknown; | ||||
| @ -53,6 +58,16 @@ bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) { | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
|     if(string_start_with_str_p(format_string, "Mifare Classic")) { | ||||
|         dev->format = NfcDeviceSaveFormatMifareClassic; | ||||
|         dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareClassic; | ||||
|         return true; | ||||
|     } | ||||
|     if(string_start_with_str_p(format_string, "Mifare DESFire")) { | ||||
|         dev->format = NfcDeviceSaveFormatMifareDesfire; | ||||
|         dev->dev_data.nfc_data.protocol = NfcDeviceProtocolMifareDesfire; | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| @ -154,6 +169,383 @@ bool nfc_device_load_mifare_ul_data(FlipperFormat* file, NfcDevice* dev) { | ||||
|     return parsed; | ||||
| } | ||||
| 
 | ||||
| static bool nfc_device_save_mifare_df_key_settings( | ||||
|     FlipperFormat* file, | ||||
|     MifareDesfireKeySettings* ks, | ||||
|     const char* prefix) { | ||||
|     bool saved = false; | ||||
|     string_t key; | ||||
|     string_init(key); | ||||
| 
 | ||||
|     do { | ||||
|         string_printf(key, "%s Change Key ID", prefix); | ||||
|         if(!flipper_format_write_hex(file, string_get_cstr(key), &ks->change_key_id, 1)) break; | ||||
|         string_printf(key, "%s Config Changeable", prefix); | ||||
|         if(!flipper_format_write_bool(file, string_get_cstr(key), &ks->config_changeable, 1)) | ||||
|             break; | ||||
|         string_printf(key, "%s Free Create Delete", prefix); | ||||
|         if(!flipper_format_write_bool(file, string_get_cstr(key), &ks->free_create_delete, 1)) | ||||
|             break; | ||||
|         string_printf(key, "%s Free Directory List", prefix); | ||||
|         if(!flipper_format_write_bool(file, string_get_cstr(key), &ks->free_directory_list, 1)) | ||||
|             break; | ||||
|         string_printf(key, "%s Key Changeable", prefix); | ||||
|         if(!flipper_format_write_bool(file, string_get_cstr(key), &ks->master_key_changeable, 1)) | ||||
|             break; | ||||
|         string_printf(key, "%s Max Keys", prefix); | ||||
|         if(!flipper_format_write_hex(file, string_get_cstr(key), &ks->max_keys, 1)) break; | ||||
|         for(MifareDesfireKeyVersion* kv = ks->key_version_head; kv; kv = kv->next) { | ||||
|             string_printf(key, "%s Key %d Version", prefix, kv->id); | ||||
|             if(!flipper_format_write_hex(file, string_get_cstr(key), &kv->version, 1)) break; | ||||
|         } | ||||
|         saved = true; | ||||
|     } while(false); | ||||
| 
 | ||||
|     string_clear(key); | ||||
|     return saved; | ||||
| } | ||||
| 
 | ||||
| bool nfc_device_load_mifare_df_key_settings( | ||||
|     FlipperFormat* file, | ||||
|     MifareDesfireKeySettings* ks, | ||||
|     const char* prefix) { | ||||
|     bool parsed = false; | ||||
|     string_t key; | ||||
|     string_init(key); | ||||
| 
 | ||||
|     do { | ||||
|         string_printf(key, "%s Change Key ID", prefix); | ||||
|         if(!flipper_format_read_hex(file, string_get_cstr(key), &ks->change_key_id, 1)) break; | ||||
|         string_printf(key, "%s Config Changeable", prefix); | ||||
|         if(!flipper_format_read_bool(file, string_get_cstr(key), &ks->config_changeable, 1)) break; | ||||
|         string_printf(key, "%s Free Create Delete", prefix); | ||||
|         if(!flipper_format_read_bool(file, string_get_cstr(key), &ks->free_create_delete, 1)) | ||||
|             break; | ||||
|         string_printf(key, "%s Free Directory List", prefix); | ||||
|         if(!flipper_format_read_bool(file, string_get_cstr(key), &ks->free_directory_list, 1)) | ||||
|             break; | ||||
|         string_printf(key, "%s Key Changeable", prefix); | ||||
|         if(!flipper_format_read_bool(file, string_get_cstr(key), &ks->master_key_changeable, 1)) | ||||
|             break; | ||||
|         string_printf(key, "%s Max Keys", prefix); | ||||
|         if(!flipper_format_read_hex(file, string_get_cstr(key), &ks->max_keys, 1)) break; | ||||
|         MifareDesfireKeyVersion** kv_head = &ks->key_version_head; | ||||
|         for(int key_id = 0; key_id < ks->max_keys; key_id++) { | ||||
|             string_printf(key, "%s Key %d Version", prefix, key_id); | ||||
|             uint8_t version; | ||||
|             if(flipper_format_read_hex(file, string_get_cstr(key), &version, 1)) { | ||||
|                 MifareDesfireKeyVersion* kv = malloc(sizeof(MifareDesfireKeyVersion)); | ||||
|                 memset(kv, 0, sizeof(MifareDesfireKeyVersion)); | ||||
|                 kv->id = key_id; | ||||
|                 kv->version = version; | ||||
|                 *kv_head = kv; | ||||
|                 kv_head = &kv->next; | ||||
|             } | ||||
|         } | ||||
|         parsed = true; | ||||
|     } while(false); | ||||
| 
 | ||||
|     string_clear(key); | ||||
|     return parsed; | ||||
| } | ||||
| 
 | ||||
| static bool nfc_device_save_mifare_df_app(FlipperFormat* file, MifareDesfireApplication* app) { | ||||
|     bool saved = false; | ||||
|     string_t prefix, key; | ||||
|     string_init_printf(prefix, "Application %02x%02x%02x", app->id[0], app->id[1], app->id[2]); | ||||
|     string_init(key); | ||||
|     uint8_t* tmp = NULL; | ||||
| 
 | ||||
|     do { | ||||
|         if(app->key_settings) { | ||||
|             if(!nfc_device_save_mifare_df_key_settings( | ||||
|                    file, app->key_settings, string_get_cstr(prefix))) | ||||
|                 break; | ||||
|         } | ||||
|         uint32_t n_files = 0; | ||||
|         for(MifareDesfireFile* f = app->file_head; f; f = f->next) { | ||||
|             n_files++; | ||||
|         } | ||||
|         tmp = malloc(n_files); | ||||
|         int i = 0; | ||||
|         for(MifareDesfireFile* f = app->file_head; f; f = f->next) { | ||||
|             tmp[i++] = f->id; | ||||
|         } | ||||
|         string_printf(key, "%s File IDs", string_get_cstr(prefix)); | ||||
|         if(!flipper_format_write_hex(file, string_get_cstr(key), tmp, n_files)) break; | ||||
|         bool saved_files = true; | ||||
|         for(MifareDesfireFile* f = app->file_head; f; f = f->next) { | ||||
|             saved_files = false; | ||||
|             string_printf(key, "%s File %d Type", string_get_cstr(prefix), f->id); | ||||
|             if(!flipper_format_write_hex(file, string_get_cstr(key), &f->type, 1)) break; | ||||
|             string_printf( | ||||
|                 key, "%s File %d Communication Settings", string_get_cstr(prefix), f->id); | ||||
|             if(!flipper_format_write_hex(file, string_get_cstr(key), &f->comm, 1)) break; | ||||
|             string_printf(key, "%s File %d Access Rights", string_get_cstr(prefix), f->id); | ||||
|             if(!flipper_format_write_hex( | ||||
|                    file, string_get_cstr(key), (uint8_t*)&f->access_rights, 2)) | ||||
|                 break; | ||||
|             uint16_t size = 0; | ||||
|             if(f->type == MifareDesfireFileTypeStandard || | ||||
|                f->type == MifareDesfireFileTypeBackup) { | ||||
|                 size = f->settings.data.size; | ||||
|                 string_printf(key, "%s File %d Size", string_get_cstr(prefix), f->id); | ||||
|                 if(!flipper_format_write_uint32( | ||||
|                        file, string_get_cstr(key), &f->settings.data.size, 1)) | ||||
|                     break; | ||||
|             } else if(f->type == MifareDesfireFileTypeValue) { | ||||
|                 string_printf(key, "%s File %d Hi Limit", string_get_cstr(prefix), f->id); | ||||
|                 if(!flipper_format_write_uint32( | ||||
|                        file, string_get_cstr(key), &f->settings.value.hi_limit, 1)) | ||||
|                     break; | ||||
|                 string_printf(key, "%s File %d Lo Limit", string_get_cstr(prefix), f->id); | ||||
|                 if(!flipper_format_write_uint32( | ||||
|                        file, string_get_cstr(key), &f->settings.value.lo_limit, 1)) | ||||
|                     break; | ||||
|                 string_printf( | ||||
|                     key, "%s File %d Limited Credit Value", string_get_cstr(prefix), f->id); | ||||
|                 if(!flipper_format_write_uint32( | ||||
|                        file, string_get_cstr(key), &f->settings.value.limited_credit_value, 1)) | ||||
|                     break; | ||||
|                 string_printf( | ||||
|                     key, "%s File %d Limited Credit Enabled", string_get_cstr(prefix), f->id); | ||||
|                 if(!flipper_format_write_bool( | ||||
|                        file, string_get_cstr(key), &f->settings.value.limited_credit_enabled, 1)) | ||||
|                     break; | ||||
|                 size = 4; | ||||
|             } else if( | ||||
|                 f->type == MifareDesfireFileTypeLinearRecord || | ||||
|                 f->type == MifareDesfireFileTypeCyclicRecord) { | ||||
|                 string_printf(key, "%s File %d Size", string_get_cstr(prefix), f->id); | ||||
|                 if(!flipper_format_write_uint32( | ||||
|                        file, string_get_cstr(key), &f->settings.record.size, 1)) | ||||
|                     break; | ||||
|                 string_printf(key, "%s File %d Max", string_get_cstr(prefix), f->id); | ||||
|                 if(!flipper_format_write_uint32( | ||||
|                        file, string_get_cstr(key), &f->settings.record.max, 1)) | ||||
|                     break; | ||||
|                 string_printf(key, "%s File %d Cur", string_get_cstr(prefix), f->id); | ||||
|                 if(!flipper_format_write_uint32( | ||||
|                        file, string_get_cstr(key), &f->settings.record.cur, 1)) | ||||
|                     break; | ||||
|                 size = f->settings.record.size * f->settings.record.cur; | ||||
|             } | ||||
|             if(f->contents) { | ||||
|                 string_printf(key, "%s File %d", string_get_cstr(prefix), f->id); | ||||
|                 if(!flipper_format_write_hex(file, string_get_cstr(key), f->contents, size)) break; | ||||
|             } | ||||
|             saved_files = true; | ||||
|         } | ||||
|         if(!saved_files) { | ||||
|             break; | ||||
|         } | ||||
|         saved = true; | ||||
|     } while(false); | ||||
| 
 | ||||
|     free(tmp); | ||||
|     string_clear(prefix); | ||||
|     string_clear(key); | ||||
|     return saved; | ||||
| } | ||||
| 
 | ||||
| bool nfc_device_load_mifare_df_app(FlipperFormat* file, MifareDesfireApplication* app) { | ||||
|     bool parsed = false; | ||||
|     string_t prefix, key; | ||||
|     string_init_printf(prefix, "Application %02x%02x%02x", app->id[0], app->id[1], app->id[2]); | ||||
|     string_init(key); | ||||
|     uint8_t* tmp = NULL; | ||||
|     MifareDesfireFile* f = NULL; | ||||
| 
 | ||||
|     do { | ||||
|         app->key_settings = malloc(sizeof(MifareDesfireKeySettings)); | ||||
|         memset(app->key_settings, 0, sizeof(MifareDesfireKeySettings)); | ||||
|         if(!nfc_device_load_mifare_df_key_settings( | ||||
|                file, app->key_settings, string_get_cstr(prefix))) { | ||||
|             free(app->key_settings); | ||||
|             app->key_settings = NULL; | ||||
|             break; | ||||
|         } | ||||
|         string_printf(key, "%s File IDs", string_get_cstr(prefix)); | ||||
|         uint32_t n_files; | ||||
|         if(!flipper_format_get_value_count(file, string_get_cstr(key), &n_files)) break; | ||||
|         tmp = malloc(n_files); | ||||
|         if(!flipper_format_read_hex(file, string_get_cstr(key), tmp, n_files)) break; | ||||
|         MifareDesfireFile** file_head = &app->file_head; | ||||
|         bool parsed_files = true; | ||||
|         for(int i = 0; i < n_files; i++) { | ||||
|             parsed_files = false; | ||||
|             f = malloc(sizeof(MifareDesfireFile)); | ||||
|             memset(f, 0, sizeof(MifareDesfireFile)); | ||||
|             f->id = tmp[i]; | ||||
|             string_printf(key, "%s File %d Type", string_get_cstr(prefix), f->id); | ||||
|             if(!flipper_format_read_hex(file, string_get_cstr(key), &f->type, 1)) break; | ||||
|             string_printf( | ||||
|                 key, "%s File %d Communication Settings", string_get_cstr(prefix), f->id); | ||||
|             if(!flipper_format_read_hex(file, string_get_cstr(key), &f->comm, 1)) break; | ||||
|             string_printf(key, "%s File %d Access Rights", string_get_cstr(prefix), f->id); | ||||
|             if(!flipper_format_read_hex(file, string_get_cstr(key), (uint8_t*)&f->access_rights, 2)) | ||||
|                 break; | ||||
|             if(f->type == MifareDesfireFileTypeStandard || | ||||
|                f->type == MifareDesfireFileTypeBackup) { | ||||
|                 string_printf(key, "%s File %d Size", string_get_cstr(prefix), f->id); | ||||
|                 if(!flipper_format_read_uint32( | ||||
|                        file, string_get_cstr(key), &f->settings.data.size, 1)) | ||||
|                     break; | ||||
|             } else if(f->type == MifareDesfireFileTypeValue) { | ||||
|                 string_printf(key, "%s File %d Hi Limit", string_get_cstr(prefix), f->id); | ||||
|                 if(!flipper_format_read_uint32( | ||||
|                        file, string_get_cstr(key), &f->settings.value.hi_limit, 1)) | ||||
|                     break; | ||||
|                 string_printf(key, "%s File %d Lo Limit", string_get_cstr(prefix), f->id); | ||||
|                 if(!flipper_format_read_uint32( | ||||
|                        file, string_get_cstr(key), &f->settings.value.lo_limit, 1)) | ||||
|                     break; | ||||
|                 string_printf( | ||||
|                     key, "%s File %d Limited Credit Value", string_get_cstr(prefix), f->id); | ||||
|                 if(!flipper_format_read_uint32( | ||||
|                        file, string_get_cstr(key), &f->settings.value.limited_credit_value, 1)) | ||||
|                     break; | ||||
|                 string_printf( | ||||
|                     key, "%s File %d Limited Credit Enabled", string_get_cstr(prefix), f->id); | ||||
|                 if(!flipper_format_read_bool( | ||||
|                        file, string_get_cstr(key), &f->settings.value.limited_credit_enabled, 1)) | ||||
|                     break; | ||||
|             } else if( | ||||
|                 f->type == MifareDesfireFileTypeLinearRecord || | ||||
|                 f->type == MifareDesfireFileTypeCyclicRecord) { | ||||
|                 string_printf(key, "%s File %d Size", string_get_cstr(prefix), f->id); | ||||
|                 if(!flipper_format_read_uint32( | ||||
|                        file, string_get_cstr(key), &f->settings.record.size, 1)) | ||||
|                     break; | ||||
|                 string_printf(key, "%s File %d Max", string_get_cstr(prefix), f->id); | ||||
|                 if(!flipper_format_read_uint32( | ||||
|                        file, string_get_cstr(key), &f->settings.record.max, 1)) | ||||
|                     break; | ||||
|                 string_printf(key, "%s File %d Cur", string_get_cstr(prefix), f->id); | ||||
|                 if(!flipper_format_read_uint32( | ||||
|                        file, string_get_cstr(key), &f->settings.record.cur, 1)) | ||||
|                     break; | ||||
|             } | ||||
|             string_printf(key, "%s File %d", string_get_cstr(prefix), f->id); | ||||
|             if(flipper_format_key_exist(file, string_get_cstr(key))) { | ||||
|                 uint32_t size; | ||||
|                 if(!flipper_format_get_value_count(file, string_get_cstr(key), &size)) break; | ||||
|                 f->contents = malloc(size); | ||||
|                 if(!flipper_format_read_hex(file, string_get_cstr(key), f->contents, size)) break; | ||||
|             } | ||||
|             *file_head = f; | ||||
|             file_head = &f->next; | ||||
|             f = NULL; | ||||
|             parsed_files = true; | ||||
|         } | ||||
|         if(!parsed_files) { | ||||
|             break; | ||||
|         } | ||||
|         parsed = true; | ||||
|     } while(false); | ||||
| 
 | ||||
|     if(f) { | ||||
|         free(f->contents); | ||||
|         free(f); | ||||
|     } | ||||
|     free(tmp); | ||||
|     string_clear(prefix); | ||||
|     string_clear(key); | ||||
|     return parsed; | ||||
| } | ||||
| 
 | ||||
| static bool nfc_device_save_mifare_df_data(FlipperFormat* file, NfcDevice* dev) { | ||||
|     bool saved = false; | ||||
|     MifareDesfireData* data = &dev->dev_data.mf_df_data; | ||||
|     uint8_t* tmp = NULL; | ||||
| 
 | ||||
|     do { | ||||
|         if(!flipper_format_write_comment_cstr(file, "Mifare DESFire specific data")) break; | ||||
|         if(!flipper_format_write_hex( | ||||
|                file, "PICC Version", (uint8_t*)&data->version, sizeof(data->version))) | ||||
|             break; | ||||
|         if(data->free_memory) { | ||||
|             if(!flipper_format_write_uint32(file, "PICC Free Memory", &data->free_memory->bytes, 1)) | ||||
|                 break; | ||||
|         } | ||||
|         if(data->master_key_settings) { | ||||
|             if(!nfc_device_save_mifare_df_key_settings(file, data->master_key_settings, "PICC")) | ||||
|                 break; | ||||
|         } | ||||
|         uint32_t n_apps = 0; | ||||
|         for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { | ||||
|             n_apps++; | ||||
|         } | ||||
|         if(!flipper_format_write_uint32(file, "Application Count", &n_apps, 1)) break; | ||||
|         tmp = malloc(n_apps * 3); | ||||
|         int i = 0; | ||||
|         for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { | ||||
|             memcpy(tmp + i, app->id, 3); | ||||
|             i += 3; | ||||
|         } | ||||
|         if(!flipper_format_write_hex(file, "Application IDs", tmp, n_apps * 3)) break; | ||||
|         for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { | ||||
|             if(!nfc_device_save_mifare_df_app(file, app)) break; | ||||
|         } | ||||
|         saved = true; | ||||
|     } while(false); | ||||
| 
 | ||||
|     free(tmp); | ||||
|     return saved; | ||||
| } | ||||
| 
 | ||||
| bool nfc_device_load_mifare_df_data(FlipperFormat* file, NfcDevice* dev) { | ||||
|     bool parsed = false; | ||||
|     MifareDesfireData* data = &dev->dev_data.mf_df_data; | ||||
|     memset(data, 0, sizeof(MifareDesfireData)); | ||||
|     uint8_t* tmp = NULL; | ||||
| 
 | ||||
|     do { | ||||
|         if(!flipper_format_read_hex( | ||||
|                file, "PICC Version", (uint8_t*)&data->version, sizeof(data->version))) | ||||
|             break; | ||||
|         if(flipper_format_key_exist(file, "PICC Free Memory")) { | ||||
|             data->free_memory = malloc(sizeof(MifareDesfireFreeMemory)); | ||||
|             memset(data->free_memory, 0, sizeof(MifareDesfireFreeMemory)); | ||||
|             if(!flipper_format_read_uint32( | ||||
|                    file, "PICC Free Memory", &data->free_memory->bytes, 1)) { | ||||
|                 free(data->free_memory); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         data->master_key_settings = malloc(sizeof(MifareDesfireKeySettings)); | ||||
|         memset(data->master_key_settings, 0, sizeof(MifareDesfireKeySettings)); | ||||
|         if(!nfc_device_load_mifare_df_key_settings(file, data->master_key_settings, "PICC")) { | ||||
|             free(data->master_key_settings); | ||||
|             data->master_key_settings = NULL; | ||||
|             break; | ||||
|         } | ||||
|         uint32_t n_apps; | ||||
|         if(!flipper_format_read_uint32(file, "Application Count", &n_apps, 1)) break; | ||||
|         tmp = malloc(n_apps * 3); | ||||
|         if(!flipper_format_read_hex(file, "Application IDs", tmp, n_apps * 3)) break; | ||||
|         bool parsed_apps = true; | ||||
|         MifareDesfireApplication** app_head = &data->app_head; | ||||
|         for(int i = 0; i < n_apps; i++) { | ||||
|             MifareDesfireApplication* app = malloc(sizeof(MifareDesfireApplication)); | ||||
|             memset(app, 0, sizeof(MifareDesfireApplication)); | ||||
|             memcpy(app->id, &tmp[i * 3], 3); | ||||
|             if(!nfc_device_load_mifare_df_app(file, app)) { | ||||
|                 free(app); | ||||
|                 parsed_apps = false; | ||||
|                 break; | ||||
|             } | ||||
|             *app_head = app; | ||||
|             app_head = &app->next; | ||||
|         } | ||||
|         if(!parsed_apps) break; | ||||
|         parsed = true; | ||||
|     } while(false); | ||||
| 
 | ||||
|     free(tmp); | ||||
|     return parsed; | ||||
| } | ||||
| 
 | ||||
| static bool nfc_device_save_bank_card_data(FlipperFormat* file, NfcDevice* dev) { | ||||
|     bool saved = false; | ||||
|     NfcEmvData* data = &dev->dev_data.emv_data; | ||||
| @ -220,6 +612,79 @@ bool nfc_device_load_bank_card_data(FlipperFormat* file, NfcDevice* dev) { | ||||
|     return parsed; | ||||
| } | ||||
| 
 | ||||
| static bool nfc_device_save_mifare_classic_data(FlipperFormat* file, NfcDevice* dev) { | ||||
|     bool saved = false; | ||||
|     MfClassicData* data = &dev->dev_data.mf_classic_data; | ||||
|     string_t temp_str; | ||||
|     string_init(temp_str); | ||||
|     uint16_t blocks = 0; | ||||
| 
 | ||||
|     // Save Mifare Classic specific data
 | ||||
|     do { | ||||
|         if(!flipper_format_write_comment_cstr(file, "Mifare Classic specific data")) break; | ||||
|         if(data->type == MfClassicType1k) { | ||||
|             if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "1K")) break; | ||||
|             blocks = 64; | ||||
|         } else if(data->type == MfClassicType4k) { | ||||
|             if(!flipper_format_write_string_cstr(file, "Mifare Classic type", "4K")) break; | ||||
|             blocks = 256; | ||||
|         } | ||||
|         if(!flipper_format_write_comment_cstr(file, "Mifare Classic blocks")) break; | ||||
| 
 | ||||
|         bool block_saved = true; | ||||
|         for(size_t i = 0; i < blocks; i++) { | ||||
|             string_printf(temp_str, "Block %d", i); | ||||
|             if(!flipper_format_write_hex( | ||||
|                    file, string_get_cstr(temp_str), data->block[i].value, 16)) { | ||||
|                 block_saved = false; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         if(!block_saved) break; | ||||
|         saved = true; | ||||
|     } while(false); | ||||
| 
 | ||||
|     string_clear(temp_str); | ||||
|     return saved; | ||||
| } | ||||
| 
 | ||||
| static bool nfc_device_load_mifare_classic_data(FlipperFormat* file, NfcDevice* dev) { | ||||
|     bool parsed = false; | ||||
|     MfClassicData* data = &dev->dev_data.mf_classic_data; | ||||
|     string_t temp_str; | ||||
|     string_init(temp_str); | ||||
|     uint16_t data_blocks = 0; | ||||
| 
 | ||||
|     do { | ||||
|         // Read Mifare Classic type
 | ||||
|         if(!flipper_format_read_string(file, "Mifare Classic type", temp_str)) break; | ||||
|         if(!string_cmp_str(temp_str, "1K")) { | ||||
|             data->type = MfClassicType1k; | ||||
|             data_blocks = 64; | ||||
|         } else if(!string_cmp_str(temp_str, "4K")) { | ||||
|             data->type = MfClassicType4k; | ||||
|             data_blocks = 256; | ||||
|         } else { | ||||
|             break; | ||||
|         } | ||||
|         // Read Mifare Classic blocks
 | ||||
|         bool block_read = true; | ||||
|         for(size_t i = 0; i < data_blocks; i++) { | ||||
|             string_printf(temp_str, "Block %d", i); | ||||
|             if(!flipper_format_read_hex( | ||||
|                    file, string_get_cstr(temp_str), data->block[i].value, 16)) { | ||||
|                 block_read = false; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         if(!block_read) break; | ||||
|         parsed = true; | ||||
|     } while(false); | ||||
| 
 | ||||
|     string_clear(temp_str); | ||||
|     return parsed; | ||||
| } | ||||
| 
 | ||||
| void nfc_device_set_name(NfcDevice* dev, const char* name) { | ||||
|     furi_assert(dev); | ||||
| 
 | ||||
| @ -250,7 +715,7 @@ static bool nfc_device_save_file( | ||||
|         if(!flipper_format_write_header_cstr(file, nfc_file_header, nfc_file_version)) break; | ||||
|         // Write nfc device type
 | ||||
|         if(!flipper_format_write_comment_cstr( | ||||
|                file, "Nfc device type can be UID, Mifare Ultralight, Bank card")) | ||||
|                file, "Nfc device type can be UID, Mifare Ultralight, Mifare Classic, Bank card")) | ||||
|             break; | ||||
|         nfc_device_prepare_format_string(dev, temp_str); | ||||
|         if(!flipper_format_write_string(file, "Device type", temp_str)) break; | ||||
| @ -263,8 +728,12 @@ static bool nfc_device_save_file( | ||||
|         // Save more data if necessary
 | ||||
|         if(dev->format == NfcDeviceSaveFormatMifareUl) { | ||||
|             if(!nfc_device_save_mifare_ul_data(file, dev)) break; | ||||
|         } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) { | ||||
|             if(!nfc_device_save_mifare_df_data(file, dev)) break; | ||||
|         } else if(dev->format == NfcDeviceSaveFormatBankCard) { | ||||
|             if(!nfc_device_save_bank_card_data(file, dev)) break; | ||||
|         } else if(dev->format == NfcDeviceSaveFormatMifareClassic) { | ||||
|             if(!nfc_device_save_mifare_classic_data(file, dev)) break; | ||||
|         } | ||||
|         saved = true; | ||||
|     } while(0); | ||||
| @ -327,6 +796,10 @@ static bool nfc_device_load_data(NfcDevice* dev, string_t path) { | ||||
|         // Parse other data
 | ||||
|         if(dev->format == NfcDeviceSaveFormatMifareUl) { | ||||
|             if(!nfc_device_load_mifare_ul_data(file, dev)) break; | ||||
|         } else if(dev->format == NfcDeviceSaveFormatMifareClassic) { | ||||
|             if(!nfc_device_load_mifare_classic_data(file, dev)) break; | ||||
|         } else if(dev->format == NfcDeviceSaveFormatMifareDesfire) { | ||||
|             if(!nfc_device_load_mifare_df_data(file, dev)) break; | ||||
|         } else if(dev->format == NfcDeviceSaveFormatBankCard) { | ||||
|             if(!nfc_device_load_bank_card_data(file, dev)) break; | ||||
|         } | ||||
| @ -389,9 +862,16 @@ bool nfc_file_select(NfcDevice* dev) { | ||||
|     return res; | ||||
| } | ||||
| 
 | ||||
| void nfc_device_data_clear(NfcDeviceData* dev_data) { | ||||
|     if(dev_data->nfc_data.protocol == NfcDeviceProtocolMifareDesfire) { | ||||
|         mf_df_clear(&dev_data->mf_df_data); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void nfc_device_clear(NfcDevice* dev) { | ||||
|     furi_assert(dev); | ||||
| 
 | ||||
|     nfc_device_data_clear(&dev->dev_data); | ||||
|     memset(&dev->dev_data, 0, sizeof(dev->dev_data)); | ||||
|     dev->format = NfcDeviceSaveFormatUid; | ||||
| } | ||||
|  | ||||
| @ -5,7 +5,9 @@ | ||||
| #include <storage/storage.h> | ||||
| #include <dialogs/dialogs.h> | ||||
| 
 | ||||
| #include "mifare_ultralight.h" | ||||
| #include <lib/nfc_protocols/mifare_ultralight.h> | ||||
| #include <lib/nfc_protocols/mifare_classic.h> | ||||
| #include <lib/nfc_protocols/mifare_desfire.h> | ||||
| 
 | ||||
| #define NFC_DEV_NAME_MAX_LEN 22 | ||||
| #define NFC_FILE_NAME_MAX_LEN 120 | ||||
| @ -26,12 +28,16 @@ typedef enum { | ||||
|     NfcDeviceProtocolUnknown, | ||||
|     NfcDeviceProtocolEMV, | ||||
|     NfcDeviceProtocolMifareUl, | ||||
|     NfcDeviceProtocolMifareClassic, | ||||
|     NfcDeviceProtocolMifareDesfire, | ||||
| } NfcProtocol; | ||||
| 
 | ||||
| typedef enum { | ||||
|     NfcDeviceSaveFormatUid, | ||||
|     NfcDeviceSaveFormatBankCard, | ||||
|     NfcDeviceSaveFormatMifareUl, | ||||
|     NfcDeviceSaveFormatMifareClassic, | ||||
|     NfcDeviceSaveFormatMifareDesfire, | ||||
| } NfcDeviceSaveFormat; | ||||
| 
 | ||||
| typedef struct { | ||||
| @ -62,10 +68,12 @@ typedef struct { | ||||
| 
 | ||||
| typedef struct { | ||||
|     NfcDeviceCommonData nfc_data; | ||||
|     NfcReaderRequestData reader_data; | ||||
|     union { | ||||
|         NfcEmvData emv_data; | ||||
|         MifareUlData mf_ul_data; | ||||
|         NfcReaderRequestData reader_data; | ||||
|         MfClassicData mf_classic_data; | ||||
|         MifareDesfireData mf_df_data; | ||||
|     }; | ||||
| } NfcDeviceData; | ||||
| 
 | ||||
| @ -93,6 +101,8 @@ bool nfc_device_load(NfcDevice* dev, const char* file_path); | ||||
| 
 | ||||
| bool nfc_file_select(NfcDevice* dev); | ||||
| 
 | ||||
| void nfc_device_data_clear(NfcDeviceData* dev); | ||||
| 
 | ||||
| void nfc_device_clear(NfcDevice* dev); | ||||
| 
 | ||||
| bool nfc_device_delete(NfcDevice* dev); | ||||
|  | ||||
| @ -24,6 +24,7 @@ | ||||
| #include <gui/modules/widget.h> | ||||
| 
 | ||||
| #include "views/bank_card.h" | ||||
| #include "views/dict_attack.h" | ||||
| 
 | ||||
| #include <nfc/scenes/nfc_scene.h> | ||||
| #include <nfc/helpers/nfc_custom_event.h> | ||||
| @ -53,6 +54,7 @@ struct Nfc { | ||||
|     TextBox* text_box; | ||||
|     Widget* widget; | ||||
|     BankCard* bank_card; | ||||
|     DictAttack* dict_attack; | ||||
| }; | ||||
| 
 | ||||
| typedef enum { | ||||
| @ -64,6 +66,7 @@ typedef enum { | ||||
|     NfcViewTextBox, | ||||
|     NfcViewWidget, | ||||
|     NfcViewBankCard, | ||||
|     NfcViewDictAttack, | ||||
| } NfcView; | ||||
| 
 | ||||
| Nfc* nfc_alloc(); | ||||
|  | ||||
| @ -53,6 +53,10 @@ const char* nfc_guess_protocol(NfcProtocol protocol) { | ||||
|         return "EMV bank card"; | ||||
|     } else if(protocol == NfcDeviceProtocolMifareUl) { | ||||
|         return "Mifare Ultral/NTAG"; | ||||
|     } else if(protocol == NfcDeviceProtocolMifareClassic) { | ||||
|         return "Mifare Classic"; | ||||
|     } else if(protocol == NfcDeviceProtocolMifareDesfire) { | ||||
|         return "Mifare DESFire"; | ||||
|     } else { | ||||
|         return "Unrecognized"; | ||||
|     } | ||||
| @ -73,3 +77,13 @@ const char* nfc_mf_ul_type(MfUltralightType type, bool full_name) { | ||||
|         return "Mifare Ultralight"; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| const char* nfc_mf_classic_type(MfClassicType type) { | ||||
|     if(type == MfClassicType1k) { | ||||
|         return "Mifare Classic 1K"; | ||||
|     } else if(type == MfClassicType4k) { | ||||
|         return "Mifare Classic 4K"; | ||||
|     } else { | ||||
|         return "Mifare Classic"; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -15,3 +15,5 @@ const char* nfc_get_nfca_type(rfalNfcaListenDeviceType type); | ||||
| const char* nfc_guess_protocol(NfcProtocol protocol); | ||||
| 
 | ||||
| const char* nfc_mf_ul_type(MfUltralightType type, bool full_name); | ||||
| 
 | ||||
| const char* nfc_mf_classic_type(MfClassicType type); | ||||
|  | ||||
							
								
								
									
										433
									
								
								applications/nfc/nfc_worker.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										433
									
								
								applications/nfc/nfc_worker.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @ -1,7 +1,13 @@ | ||||
| #include "nfc_worker_i.h" | ||||
| #include <furi_hal.h> | ||||
| #include "nfc_protocols/emv_decoder.h" | ||||
| #include "nfc_protocols/mifare_ultralight.h" | ||||
| 
 | ||||
| #include <lib/nfc_protocols/nfc_util.h> | ||||
| #include <lib/nfc_protocols/emv_decoder.h> | ||||
| #include <lib/nfc_protocols/mifare_ultralight.h> | ||||
| #include <lib/nfc_protocols/mifare_classic.h> | ||||
| #include <lib/nfc_protocols/mifare_desfire.h> | ||||
| 
 | ||||
| #include "helpers/nfc_mf_classic_dict.h" | ||||
| 
 | ||||
| #define TAG "NfcWorker" | ||||
| 
 | ||||
| @ -19,6 +25,7 @@ NfcWorker* nfc_worker_alloc() { | ||||
| 
 | ||||
|     nfc_worker->callback = NULL; | ||||
|     nfc_worker->context = NULL; | ||||
|     nfc_worker->storage = furi_record_open("storage"); | ||||
| 
 | ||||
|     // Initialize rfal
 | ||||
|     while(furi_hal_nfc_is_busy()) { | ||||
| @ -32,6 +39,7 @@ NfcWorker* nfc_worker_alloc() { | ||||
| void nfc_worker_free(NfcWorker* nfc_worker) { | ||||
|     furi_assert(nfc_worker); | ||||
|     furi_thread_free(nfc_worker->thread); | ||||
|     furi_record_close("storage"); | ||||
|     free(nfc_worker); | ||||
| } | ||||
| 
 | ||||
| @ -94,6 +102,10 @@ int32_t nfc_worker_task(void* context) { | ||||
|         nfc_worker_read_mifare_ul(nfc_worker); | ||||
|     } else if(nfc_worker->state == NfcWorkerStateEmulateMifareUl) { | ||||
|         nfc_worker_emulate_mifare_ul(nfc_worker); | ||||
|     } else if(nfc_worker->state == NfcWorkerStateReadMifareClassic) { | ||||
|         nfc_worker_mifare_classic_dict_attack(nfc_worker); | ||||
|     } else if(nfc_worker->state == NfcWorkerStateReadMifareDesfire) { | ||||
|         nfc_worker_read_mifare_desfire(nfc_worker); | ||||
|     } else if(nfc_worker->state == NfcWorkerStateField) { | ||||
|         nfc_worker_field(nfc_worker); | ||||
|     } | ||||
| @ -108,6 +120,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker) { | ||||
|     rfalNfcDevice* dev_list; | ||||
|     rfalNfcDevice* dev; | ||||
|     uint8_t dev_cnt; | ||||
|     nfc_device_data_clear(nfc_worker->dev_data); | ||||
|     NfcDeviceCommonData* result = &nfc_worker->dev_data->nfc_data; | ||||
| 
 | ||||
|     while(nfc_worker->state == NfcWorkerStateDetect) { | ||||
| @ -126,6 +139,16 @@ void nfc_worker_detect(NfcWorker* nfc_worker) { | ||||
|                        dev->dev.nfca.sensRes.platformInfo, | ||||
|                        dev->dev.nfca.selRes.sak)) { | ||||
|                     result->protocol = NfcDeviceProtocolMifareUl; | ||||
|                 } else if(mf_classic_check_card_type( | ||||
|                               dev->dev.nfca.sensRes.anticollisionInfo, | ||||
|                               dev->dev.nfca.sensRes.platformInfo, | ||||
|                               dev->dev.nfca.selRes.sak)) { | ||||
|                     result->protocol = NfcDeviceProtocolMifareClassic; | ||||
|                 } else if(mf_df_check_card_type( | ||||
|                               dev->dev.nfca.sensRes.anticollisionInfo, | ||||
|                               dev->dev.nfca.sensRes.platformInfo, | ||||
|                               dev->dev.nfca.selRes.sak)) { | ||||
|                     result->protocol = NfcDeviceProtocolMifareDesfire; | ||||
|                 } else if(dev->rfInterface == RFAL_NFC_INTERFACE_ISODEP) { | ||||
|                     result->protocol = NfcDeviceProtocolEMV; | ||||
|                 } else { | ||||
| @ -140,7 +163,7 @@ void nfc_worker_detect(NfcWorker* nfc_worker) { | ||||
|             } | ||||
|             // Notify caller and exit
 | ||||
|             if(nfc_worker->callback) { | ||||
|                 nfc_worker->callback(nfc_worker->context); | ||||
|                 nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
| @ -162,7 +185,7 @@ bool nfc_worker_emulate_uid_callback( | ||||
|     if(reader_data->size > 0) { | ||||
|         memcpy(reader_data->data, buff_rx, reader_data->size); | ||||
|         if(nfc_worker->callback) { | ||||
|             nfc_worker->callback(nfc_worker->context); | ||||
|             nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); | ||||
|         } | ||||
|     } | ||||
|     return true; | ||||
| @ -192,6 +215,7 @@ void nfc_worker_read_emv_app(NfcWorker* nfc_worker) { | ||||
|     uint8_t* rx_buff; | ||||
|     uint16_t* rx_len; | ||||
|     NfcDeviceData* result = nfc_worker->dev_data; | ||||
|     nfc_device_data_clear(result); | ||||
| 
 | ||||
|     while(nfc_worker->state == NfcWorkerStateReadEMVApp) { | ||||
|         memset(&emv_app, 0, sizeof(emv_app)); | ||||
| @ -221,7 +245,7 @@ void nfc_worker_read_emv_app(NfcWorker* nfc_worker) { | ||||
|                     result->emv_data.aid_len = emv_app.aid_len; | ||||
|                     memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len); | ||||
|                     if(nfc_worker->callback) { | ||||
|                         nfc_worker->callback(nfc_worker->context); | ||||
|                         nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); | ||||
|                     } | ||||
|                     break; | ||||
|                 } else { | ||||
| @ -253,6 +277,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | ||||
|     uint8_t* rx_buff; | ||||
|     uint16_t* rx_len; | ||||
|     NfcDeviceData* result = nfc_worker->dev_data; | ||||
|     nfc_device_data_clear(result); | ||||
| 
 | ||||
|     while(nfc_worker->state == NfcWorkerStateReadEMV) { | ||||
|         memset(&emv_app, 0, sizeof(emv_app)); | ||||
| @ -318,7 +343,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | ||||
|                     memcpy(result->emv_data.number, emv_app.card_number, emv_app.card_number_len); | ||||
|                     // Notify caller and exit
 | ||||
|                     if(nfc_worker->callback) { | ||||
|                         nfc_worker->callback(nfc_worker->context); | ||||
|                         nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); | ||||
|                     } | ||||
|                     break; | ||||
|                 } else { | ||||
| @ -367,7 +392,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) { | ||||
|                         } | ||||
|                         // Notify caller and exit
 | ||||
|                         if(nfc_worker->callback) { | ||||
|                             nfc_worker->callback(nfc_worker->context); | ||||
|                             nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); | ||||
|                         } | ||||
|                         break; | ||||
|                     } else { | ||||
| @ -516,6 +541,7 @@ void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker) { | ||||
|     uint16_t* rx_len; | ||||
|     MifareUlDevice mf_ul_read; | ||||
|     NfcDeviceData* result = nfc_worker->dev_data; | ||||
|     nfc_device_data_clear(result); | ||||
| 
 | ||||
|     while(nfc_worker->state == NfcWorkerStateReadMifareUl) { | ||||
|         furi_hal_nfc_deactivate(); | ||||
| @ -621,7 +647,7 @@ void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker) { | ||||
| 
 | ||||
|                 // Notify caller and exit
 | ||||
|                 if(nfc_worker->callback) { | ||||
|                     nfc_worker->callback(nfc_worker->context); | ||||
|                     nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); | ||||
|                 } | ||||
|                 break; | ||||
|             } else { | ||||
| @ -651,13 +677,402 @@ void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker) { | ||||
|         if(mf_ul_emulate.data_changed) { | ||||
|             nfc_worker->dev_data->mf_ul_data = mf_ul_emulate.data; | ||||
|             if(nfc_worker->callback) { | ||||
|                 nfc_worker->callback(nfc_worker->context); | ||||
|                 nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); | ||||
|             } | ||||
|             mf_ul_emulate.data_changed = false; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker) { | ||||
|     furi_assert(nfc_worker->callback); | ||||
|     rfalNfcDevice* dev_list; | ||||
|     rfalNfcDevice* dev; | ||||
|     NfcDeviceCommonData* nfc_common; | ||||
|     uint8_t dev_cnt = 0; | ||||
|     FuriHalNfcTxRxContext tx_rx_ctx = {}; | ||||
|     MfClassicAuthContext auth_ctx = {}; | ||||
|     MfClassicReader reader = {}; | ||||
|     uint64_t curr_key = 0; | ||||
|     uint16_t curr_sector = 0; | ||||
|     uint8_t total_sectors = 0; | ||||
|     NfcWorkerEvent event; | ||||
| 
 | ||||
|     // Open dictionary
 | ||||
|     nfc_worker->dict_stream = file_stream_alloc(nfc_worker->storage); | ||||
|     if(!nfc_mf_classic_dict_open_file(nfc_worker->dict_stream)) { | ||||
|         event = NfcWorkerEventNoDictFound; | ||||
|         nfc_worker->callback(event, nfc_worker->context); | ||||
|         nfc_mf_classic_dict_close_file(nfc_worker->dict_stream); | ||||
|         stream_free(nfc_worker->dict_stream); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     // Detect Mifare Classic card
 | ||||
|     while(nfc_worker->state == NfcWorkerStateReadMifareClassic) { | ||||
|         if(furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) { | ||||
|             dev = &dev_list[0]; | ||||
|             if(mf_classic_get_type( | ||||
|                    dev->nfcid, | ||||
|                    dev->nfcidLen, | ||||
|                    dev->dev.nfca.sensRes.anticollisionInfo, | ||||
|                    dev->dev.nfca.sensRes.platformInfo, | ||||
|                    dev->dev.nfca.selRes.sak, | ||||
|                    &reader)) { | ||||
|                 total_sectors = mf_classic_get_total_sectors_num(&reader); | ||||
|                 if(reader.type == MfClassicType1k) { | ||||
|                     event = NfcWorkerEventDetectedClassic1k; | ||||
|                 } else { | ||||
|                     event = NfcWorkerEventDetectedClassic4k; | ||||
|                 } | ||||
|                 nfc_worker->callback(event, nfc_worker->context); | ||||
|                 break; | ||||
|             } | ||||
|         } else { | ||||
|             event = NfcWorkerEventNoCardDetected; | ||||
|             nfc_worker->callback(event, nfc_worker->context); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if(nfc_worker->state == NfcWorkerStateReadMifareClassic) { | ||||
|         bool card_removed_notified = false; | ||||
|         bool card_found_notified = false; | ||||
|         // Seek for mifare classic keys
 | ||||
|         for(curr_sector = 0; curr_sector < total_sectors; curr_sector++) { | ||||
|             FURI_LOG_I(TAG, "Sector: %d ...", curr_sector); | ||||
|             event = NfcWorkerEventNewSector; | ||||
|             nfc_worker->callback(event, nfc_worker->context); | ||||
|             mf_classic_auth_init_context(&auth_ctx, reader.cuid, curr_sector); | ||||
|             bool sector_key_found = false; | ||||
|             while(nfc_mf_classic_dict_get_next_key(nfc_worker->dict_stream, &curr_key)) { | ||||
|                 furi_hal_nfc_deactivate(); | ||||
|                 if(furi_hal_nfc_activate_nfca(300, &reader.cuid)) { | ||||
|                     if(!card_found_notified) { | ||||
|                         if(reader.type == MfClassicType1k) { | ||||
|                             event = NfcWorkerEventDetectedClassic1k; | ||||
|                         } else { | ||||
|                             event = NfcWorkerEventDetectedClassic4k; | ||||
|                         } | ||||
|                         nfc_worker->callback(event, nfc_worker->context); | ||||
|                         card_found_notified = true; | ||||
|                         card_removed_notified = false; | ||||
|                     } | ||||
|                     FURI_LOG_D( | ||||
|                         TAG, | ||||
|                         "Try to auth to sector %d with key %04lx%08lx", | ||||
|                         curr_sector, | ||||
|                         (uint32_t)(curr_key >> 32), | ||||
|                         (uint32_t)curr_key); | ||||
|                     if(mf_classic_auth_attempt(&tx_rx_ctx, &auth_ctx, curr_key)) { | ||||
|                         sector_key_found = true; | ||||
|                         if((auth_ctx.key_a != MF_CLASSIC_NO_KEY) && | ||||
|                            (auth_ctx.key_b != MF_CLASSIC_NO_KEY)) | ||||
|                             break; | ||||
|                     } | ||||
|                 } else { | ||||
|                     // Notify that no tag is availalble
 | ||||
|                     FURI_LOG_D(TAG, "Can't find tags"); | ||||
|                     if(!card_removed_notified) { | ||||
|                         event = NfcWorkerEventNoCardDetected; | ||||
|                         nfc_worker->callback(event, nfc_worker->context); | ||||
|                         card_removed_notified = true; | ||||
|                         card_found_notified = false; | ||||
|                     } | ||||
|                 } | ||||
|                 if(nfc_worker->state != NfcWorkerStateReadMifareClassic) break; | ||||
|             } | ||||
|             if(nfc_worker->state != NfcWorkerStateReadMifareClassic) break; | ||||
|             if(sector_key_found) { | ||||
|                 // Notify that keys were found
 | ||||
|                 if(auth_ctx.key_a != MF_CLASSIC_NO_KEY) { | ||||
|                     FURI_LOG_I( | ||||
|                         TAG, | ||||
|                         "Sector %d key A: %04lx%08lx", | ||||
|                         curr_sector, | ||||
|                         (uint32_t)(auth_ctx.key_a >> 32), | ||||
|                         (uint32_t)auth_ctx.key_a); | ||||
|                     event = NfcWorkerEventFoundKeyA; | ||||
|                     nfc_worker->callback(event, nfc_worker->context); | ||||
|                 } | ||||
|                 if(auth_ctx.key_b != MF_CLASSIC_NO_KEY) { | ||||
|                     FURI_LOG_I( | ||||
|                         TAG, | ||||
|                         "Sector %d key B: %04lx%08lx", | ||||
|                         curr_sector, | ||||
|                         (uint32_t)(auth_ctx.key_b >> 32), | ||||
|                         (uint32_t)auth_ctx.key_b); | ||||
|                     event = NfcWorkerEventFoundKeyB; | ||||
|                     nfc_worker->callback(event, nfc_worker->context); | ||||
|                 } | ||||
|                 // Add sectors to read sequence
 | ||||
|                 mf_classic_reader_add_sector(&reader, curr_sector, auth_ctx.key_a, auth_ctx.key_b); | ||||
|             } | ||||
|             nfc_mf_classic_dict_reset(nfc_worker->dict_stream); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if(nfc_worker->state == NfcWorkerStateReadMifareClassic) { | ||||
|         FURI_LOG_I(TAG, "Found keys to %d sectors. Start reading sectors", reader.sectors_to_read); | ||||
|         uint8_t sectors_read = | ||||
|             mf_classic_read_card(&tx_rx_ctx, &reader, &nfc_worker->dev_data->mf_classic_data); | ||||
|         if(sectors_read) { | ||||
|             dev = &dev_list[0]; | ||||
|             nfc_common = &nfc_worker->dev_data->nfc_data; | ||||
|             nfc_common->uid_len = dev->dev.nfca.nfcId1Len; | ||||
|             nfc_common->atqa[0] = dev->dev.nfca.sensRes.anticollisionInfo; | ||||
|             nfc_common->atqa[1] = dev->dev.nfca.sensRes.platformInfo; | ||||
|             nfc_common->sak = dev->dev.nfca.selRes.sak; | ||||
|             nfc_common->protocol = NfcDeviceProtocolMifareClassic; | ||||
|             memcpy(nfc_common->uid, dev->dev.nfca.nfcId1, nfc_common->uid_len); | ||||
|             event = NfcWorkerEventSuccess; | ||||
|             FURI_LOG_I(TAG, "Successfully read %d sectors", sectors_read); | ||||
|         } else { | ||||
|             event = NfcWorkerEventFail; | ||||
|             FURI_LOG_W(TAG, "Failed to read any sector"); | ||||
|         } | ||||
|         nfc_worker->callback(event, nfc_worker->context); | ||||
|     } | ||||
| 
 | ||||
|     nfc_mf_classic_dict_close_file(nfc_worker->dict_stream); | ||||
|     stream_free(nfc_worker->dict_stream); | ||||
| } | ||||
| 
 | ||||
| ReturnCode nfc_exchange_full( | ||||
|     uint8_t* tx_buff, | ||||
|     uint16_t tx_len, | ||||
|     uint8_t* rx_buff, | ||||
|     uint16_t rx_cap, | ||||
|     uint16_t* rx_len) { | ||||
|     ReturnCode err; | ||||
|     uint8_t* part_buff; | ||||
|     uint16_t* part_len; | ||||
| 
 | ||||
|     err = furi_hal_nfc_data_exchange(tx_buff, tx_len, &part_buff, &part_len, false); | ||||
|     if(*part_len > rx_cap) { | ||||
|         return ERR_OVERRUN; | ||||
|     } | ||||
|     memcpy(rx_buff, part_buff, *part_len); | ||||
|     *rx_len = *part_len; | ||||
|     while(err == ERR_NONE && rx_buff[0] == 0xAF) { | ||||
|         err = furi_hal_nfc_data_exchange(rx_buff, 1, &part_buff, &part_len, false); | ||||
|         if(*part_len > rx_cap - *rx_len) { | ||||
|             return ERR_OVERRUN; | ||||
|         } | ||||
|         if(*part_len == 0) { | ||||
|             return ERR_PROTO; | ||||
|         } | ||||
|         memcpy(rx_buff + *rx_len, part_buff + 1, *part_len - 1); | ||||
|         *rx_buff = *part_buff; | ||||
|         *rx_len += *part_len - 1; | ||||
|     } | ||||
| 
 | ||||
|     return err; | ||||
| } | ||||
| 
 | ||||
| void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker) { | ||||
|     ReturnCode err; | ||||
|     rfalNfcDevice* dev_list; | ||||
|     uint8_t dev_cnt = 0; | ||||
|     uint8_t tx_buff[64] = {}; | ||||
|     uint16_t tx_len = 0; | ||||
|     uint8_t rx_buff[512] = {}; | ||||
|     uint16_t rx_len; | ||||
|     NfcDeviceData* result = nfc_worker->dev_data; | ||||
|     nfc_device_data_clear(result); | ||||
|     MifareDesfireData* data = &result->mf_df_data; | ||||
| 
 | ||||
|     while(nfc_worker->state == NfcWorkerStateReadMifareDesfire) { | ||||
|         furi_hal_nfc_deactivate(); | ||||
|         if(!furi_hal_nfc_detect(&dev_list, &dev_cnt, 300, false)) { | ||||
|             osDelay(100); | ||||
|             continue; | ||||
|         } | ||||
|         memset(data, 0, sizeof(MifareDesfireData)); | ||||
|         if(dev_list[0].type != RFAL_NFC_LISTEN_TYPE_NFCA || | ||||
|            !mf_df_check_card_type( | ||||
|                dev_list[0].dev.nfca.sensRes.anticollisionInfo, | ||||
|                dev_list[0].dev.nfca.sensRes.platformInfo, | ||||
|                dev_list[0].dev.nfca.selRes.sak)) { | ||||
|             FURI_LOG_D(TAG, "Tag is not DESFire"); | ||||
|             osDelay(100); | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         FURI_LOG_D(TAG, "Found DESFire tag"); | ||||
| 
 | ||||
|         // Fill non-DESFire result data
 | ||||
|         result->nfc_data.uid_len = dev_list[0].dev.nfca.nfcId1Len; | ||||
|         result->nfc_data.atqa[0] = dev_list[0].dev.nfca.sensRes.anticollisionInfo; | ||||
|         result->nfc_data.atqa[1] = dev_list[0].dev.nfca.sensRes.platformInfo; | ||||
|         result->nfc_data.sak = dev_list[0].dev.nfca.selRes.sak; | ||||
|         result->nfc_data.device = NfcDeviceNfca; | ||||
|         result->nfc_data.protocol = NfcDeviceProtocolMifareDesfire; | ||||
|         memcpy(result->nfc_data.uid, dev_list[0].dev.nfca.nfcId1, result->nfc_data.uid_len); | ||||
| 
 | ||||
|         // Get DESFire version
 | ||||
|         tx_len = mf_df_prepare_get_version(tx_buff); | ||||
|         err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|         if(err != ERR_NONE) { | ||||
|             FURI_LOG_W(TAG, "Bad exchange getting version, err: %d", err); | ||||
|             continue; | ||||
|         } | ||||
|         if(!mf_df_parse_get_version_response(rx_buff, rx_len, &data->version)) { | ||||
|             FURI_LOG_W(TAG, "Bad DESFire GET_VERSION response"); | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         tx_len = mf_df_prepare_get_free_memory(tx_buff); | ||||
|         err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|         if(err == ERR_NONE) { | ||||
|             data->free_memory = malloc(sizeof(MifareDesfireFreeMemory)); | ||||
|             memset(data->free_memory, 0, sizeof(MifareDesfireFreeMemory)); | ||||
|             if(!mf_df_parse_get_free_memory_response(rx_buff, rx_len, data->free_memory)) { | ||||
|                 FURI_LOG_D(TAG, "Bad DESFire GET_FREE_MEMORY response (normal for pre-EV1 cards)"); | ||||
|                 free(data->free_memory); | ||||
|                 data->free_memory = NULL; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         tx_len = mf_df_prepare_get_key_settings(tx_buff); | ||||
|         err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|         if(err != ERR_NONE) { | ||||
|             FURI_LOG_D(TAG, "Bad exchange getting key settings, err: %d", err); | ||||
|         } else { | ||||
|             data->master_key_settings = malloc(sizeof(MifareDesfireKeySettings)); | ||||
|             memset(data->master_key_settings, 0, sizeof(MifareDesfireKeySettings)); | ||||
|             if(!mf_df_parse_get_key_settings_response(rx_buff, rx_len, data->master_key_settings)) { | ||||
|                 FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response"); | ||||
|                 free(data->master_key_settings); | ||||
|                 data->master_key_settings = NULL; | ||||
|             } | ||||
| 
 | ||||
|             MifareDesfireKeyVersion** key_version_head = | ||||
|                 &data->master_key_settings->key_version_head; | ||||
|             for(uint8_t key_id = 0; key_id < data->master_key_settings->max_keys; key_id++) { | ||||
|                 tx_len = mf_df_prepare_get_key_version(tx_buff, key_id); | ||||
|                 err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|                 if(err != ERR_NONE) { | ||||
|                     FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err); | ||||
|                     continue; | ||||
|                 } | ||||
|                 MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion)); | ||||
|                 memset(key_version, 0, sizeof(MifareDesfireKeyVersion)); | ||||
|                 key_version->id = key_id; | ||||
|                 if(!mf_df_parse_get_key_version_response(rx_buff, rx_len, key_version)) { | ||||
|                     FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response"); | ||||
|                     free(key_version); | ||||
|                     continue; | ||||
|                 } | ||||
|                 *key_version_head = key_version; | ||||
|                 key_version_head = &key_version->next; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         tx_len = mf_df_prepare_get_application_ids(tx_buff); | ||||
|         err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|         if(err != ERR_NONE) { | ||||
|             FURI_LOG_W(TAG, "Bad exchange getting application IDs, err: %d", err); | ||||
|         } else { | ||||
|             if(!mf_df_parse_get_application_ids_response(rx_buff, rx_len, &data->app_head)) { | ||||
|                 FURI_LOG_W(TAG, "Bad DESFire GET_APPLICATION_IDS response"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { | ||||
|             tx_len = mf_df_prepare_select_application(tx_buff, app->id); | ||||
|             err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|             if(!mf_df_parse_select_application_response(rx_buff, rx_len)) { | ||||
|                 FURI_LOG_W(TAG, "Bad exchange selecting application, err: %d", err); | ||||
|                 continue; | ||||
|             } | ||||
|             tx_len = mf_df_prepare_get_key_settings(tx_buff); | ||||
|             err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|             if(err != ERR_NONE) { | ||||
|                 FURI_LOG_W(TAG, "Bad exchange getting key settings, err: %d", err); | ||||
|             } else { | ||||
|                 app->key_settings = malloc(sizeof(MifareDesfireKeySettings)); | ||||
|                 memset(app->key_settings, 0, sizeof(MifareDesfireKeySettings)); | ||||
|                 if(!mf_df_parse_get_key_settings_response(rx_buff, rx_len, app->key_settings)) { | ||||
|                     FURI_LOG_W(TAG, "Bad DESFire GET_KEY_SETTINGS response"); | ||||
|                     free(app->key_settings); | ||||
|                     app->key_settings = NULL; | ||||
|                 } | ||||
| 
 | ||||
|                 MifareDesfireKeyVersion** key_version_head = &app->key_settings->key_version_head; | ||||
|                 for(uint8_t key_id = 0; key_id < app->key_settings->max_keys; key_id++) { | ||||
|                     tx_len = mf_df_prepare_get_key_version(tx_buff, key_id); | ||||
|                     err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|                     if(err != ERR_NONE) { | ||||
|                         FURI_LOG_W(TAG, "Bad exchange getting key version, err: %d", err); | ||||
|                         continue; | ||||
|                     } | ||||
|                     MifareDesfireKeyVersion* key_version = malloc(sizeof(MifareDesfireKeyVersion)); | ||||
|                     memset(key_version, 0, sizeof(MifareDesfireKeyVersion)); | ||||
|                     key_version->id = key_id; | ||||
|                     if(!mf_df_parse_get_key_version_response(rx_buff, rx_len, key_version)) { | ||||
|                         FURI_LOG_W(TAG, "Bad DESFire GET_KEY_VERSION response"); | ||||
|                         free(key_version); | ||||
|                         continue; | ||||
|                     } | ||||
|                     *key_version_head = key_version; | ||||
|                     key_version_head = &key_version->next; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             tx_len = mf_df_prepare_get_file_ids(tx_buff); | ||||
|             err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|             if(err != ERR_NONE) { | ||||
|                 FURI_LOG_W(TAG, "Bad exchange getting file IDs, err: %d", err); | ||||
|             } else { | ||||
|                 if(!mf_df_parse_get_file_ids_response(rx_buff, rx_len, &app->file_head)) { | ||||
|                     FURI_LOG_W(TAG, "Bad DESFire GET_FILE_IDS response"); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             for(MifareDesfireFile* file = app->file_head; file; file = file->next) { | ||||
|                 tx_len = mf_df_prepare_get_file_settings(tx_buff, file->id); | ||||
|                 err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|                 if(err != ERR_NONE) { | ||||
|                     FURI_LOG_W(TAG, "Bad exchange getting file settings, err: %d", err); | ||||
|                     continue; | ||||
|                 } | ||||
|                 if(!mf_df_parse_get_file_settings_response(rx_buff, rx_len, file)) { | ||||
|                     FURI_LOG_W(TAG, "Bad DESFire GET_FILE_SETTINGS response"); | ||||
|                     continue; | ||||
|                 } | ||||
|                 switch(file->type) { | ||||
|                 case MifareDesfireFileTypeStandard: | ||||
|                 case MifareDesfireFileTypeBackup: | ||||
|                     tx_len = mf_df_prepare_read_data(tx_buff, file->id, 0, 0); | ||||
|                     break; | ||||
|                 case MifareDesfireFileTypeValue: | ||||
|                     tx_len = mf_df_prepare_get_value(tx_buff, file->id); | ||||
|                     break; | ||||
|                 case MifareDesfireFileTypeLinearRecord: | ||||
|                 case MifareDesfireFileTypeCyclicRecord: | ||||
|                     tx_len = mf_df_prepare_read_records(tx_buff, file->id, 0, 0); | ||||
|                     break; | ||||
|                 } | ||||
|                 err = nfc_exchange_full(tx_buff, tx_len, rx_buff, sizeof(rx_buff), &rx_len); | ||||
|                 if(err != ERR_NONE) { | ||||
|                     FURI_LOG_W(TAG, "Bad exchange reading file %d, err: %d", file->id, err); | ||||
|                     continue; | ||||
|                 } | ||||
|                 if(!mf_df_parse_read_data_response(rx_buff, rx_len, file)) { | ||||
|                     FURI_LOG_W(TAG, "Bad response reading file %d", file->id); | ||||
|                     continue; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Notify caller and exit
 | ||||
|         if(nfc_worker->callback) { | ||||
|             nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void nfc_worker_field(NfcWorker* nfc_worker) { | ||||
|     furi_hal_nfc_field_on(); | ||||
|     while(nfc_worker->state == NfcWorkerStateField) { | ||||
|  | ||||
| @ -18,11 +18,27 @@ typedef enum { | ||||
|     NfcWorkerStateField, | ||||
|     NfcWorkerStateReadMifareUl, | ||||
|     NfcWorkerStateEmulateMifareUl, | ||||
|     NfcWorkerStateReadMifareClassic, | ||||
|     NfcWorkerStateReadMifareDesfire, | ||||
|     // Transition
 | ||||
|     NfcWorkerStateStop, | ||||
| } NfcWorkerState; | ||||
| 
 | ||||
| typedef void (*NfcWorkerCallback)(void* context); | ||||
| typedef enum { | ||||
|     NfcWorkerEventSuccess, | ||||
|     NfcWorkerEventFail, | ||||
|     NfcWorkerEventNoCardDetected, | ||||
|     // Mifare Classic events
 | ||||
|     NfcWorkerEventNoDictFound, | ||||
|     NfcWorkerEventDetectedClassic1k, | ||||
|     NfcWorkerEventDetectedClassic4k, | ||||
|     NfcWorkerEventNewSector, | ||||
|     NfcWorkerEventFoundKeyA, | ||||
|     NfcWorkerEventFoundKeyB, | ||||
|     NfcWorkerEventStartReading, | ||||
| } NfcWorkerEvent; | ||||
| 
 | ||||
| typedef void (*NfcWorkerCallback)(NfcWorkerEvent event, void* context); | ||||
| 
 | ||||
| NfcWorker* nfc_worker_alloc(); | ||||
| 
 | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| 
 | ||||
| #include <furi.h> | ||||
| #include <stdbool.h> | ||||
| #include <lib/toolbox/stream/file_stream.h> | ||||
| 
 | ||||
| #include <rfal_analogConfig.h> | ||||
| #include <rfal_rf.h> | ||||
| @ -18,6 +19,8 @@ | ||||
| 
 | ||||
| struct NfcWorker { | ||||
|     FuriThread* thread; | ||||
|     Storage* storage; | ||||
|     Stream* dict_stream; | ||||
| 
 | ||||
|     NfcDeviceData* dev_data; | ||||
| 
 | ||||
| @ -45,4 +48,10 @@ void nfc_worker_field(NfcWorker* nfc_worker); | ||||
| 
 | ||||
| void nfc_worker_read_mifare_ul(NfcWorker* nfc_worker); | ||||
| 
 | ||||
| void nfc_worker_mifare_classic_dict_attack(NfcWorker* nfc_worker); | ||||
| 
 | ||||
| void nfc_worker_read_mifare_desfire(NfcWorker* nfc_worker); | ||||
| 
 | ||||
| void nfc_worker_emulate_mifare_ul(NfcWorker* nfc_worker); | ||||
| 
 | ||||
| void nfc_worker_emulate_mifare_classic(NfcWorker* nfc_worker); | ||||
|  | ||||
| @ -8,13 +8,13 @@ enum SubmenuIndex { | ||||
| }; | ||||
| 
 | ||||
| void nfc_scene_card_menu_submenu_callback(void* context, uint32_t index) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     Nfc* nfc = context; | ||||
| 
 | ||||
|     view_dispatcher_send_custom_event(nfc->view_dispatcher, index); | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_card_menu_on_enter(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     Nfc* nfc = context; | ||||
|     Submenu* submenu = nfc->submenu; | ||||
| 
 | ||||
|     if(nfc->dev->dev_data.nfc_data.protocol > NfcDeviceProtocolUnknown) { | ||||
| @ -42,7 +42,8 @@ void nfc_scene_card_menu_on_enter(void* context) { | ||||
| } | ||||
| 
 | ||||
| bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     Nfc* nfc = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == SubmenuIndexRunApp) { | ||||
| @ -50,36 +51,40 @@ bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) { | ||||
|                 nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexRunApp); | ||||
|             if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolMifareUl) { | ||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUl); | ||||
|             } else if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolMifareDesfire) { | ||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfire); | ||||
|             } else if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolEMV) { | ||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp); | ||||
|             } else if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolMifareClassic) { | ||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareClassic); | ||||
|             } | ||||
|             return true; | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexChooseScript) { | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexChooseScript); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneScriptsMenu); | ||||
|             return true; | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexEmulate) { | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexEmulate); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid); | ||||
|             return true; | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexSave) { | ||||
|             scene_manager_set_scene_state(nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexSave); | ||||
|             nfc->dev->format = NfcDeviceSaveFormatUid; | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); | ||||
|             return true; | ||||
|             consumed = true; | ||||
|         } | ||||
|     } else if(event.type == SceneManagerEventTypeBack) { | ||||
|         return scene_manager_search_and_switch_to_previous_scene( | ||||
|             nfc->scene_manager, NfcSceneStart); | ||||
|         consumed = | ||||
|             scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart); | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_card_menu_on_exit(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     Nfc* nfc = context; | ||||
| 
 | ||||
|     submenu_reset(nfc->submenu); | ||||
| } | ||||
|  | ||||
| @ -19,6 +19,11 @@ ADD_SCENE(nfc, mifare_ul_menu, MifareUlMenu) | ||||
| ADD_SCENE(nfc, emulate_mifare_ul, EmulateMifareUl) | ||||
| ADD_SCENE(nfc, read_emv_app, ReadEmvApp) | ||||
| ADD_SCENE(nfc, read_emv_app_success, ReadEmvAppSuccess) | ||||
| ADD_SCENE(nfc, read_mifare_desfire, ReadMifareDesfire) | ||||
| ADD_SCENE(nfc, read_mifare_desfire_success, ReadMifareDesfireSuccess) | ||||
| ADD_SCENE(nfc, mifare_desfire_menu, MifareDesfireMenu) | ||||
| ADD_SCENE(nfc, mifare_desfire_data, MifareDesfireData) | ||||
| ADD_SCENE(nfc, mifare_desfire_app, MifareDesfireApp) | ||||
| ADD_SCENE(nfc, device_info, DeviceInfo) | ||||
| ADD_SCENE(nfc, delete, Delete) | ||||
| ADD_SCENE(nfc, delete_success, DeleteSuccess) | ||||
| @ -29,3 +34,5 @@ ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence) | ||||
| ADD_SCENE(nfc, restore_original, RestoreOriginal) | ||||
| ADD_SCENE(nfc, debug, Debug) | ||||
| ADD_SCENE(nfc, field, Field) | ||||
| ADD_SCENE(nfc, read_mifare_classic, ReadMifareClassic) | ||||
| ADD_SCENE(nfc, dict_not_found, DictNotFound) | ||||
|  | ||||
							
								
								
									
										39
									
								
								applications/nfc/scenes/nfc_scene_device_info.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										39
									
								
								applications/nfc/scenes/nfc_scene_device_info.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @ -30,13 +30,19 @@ void nfc_scene_device_info_bank_card_callback(GuiButtonType result, InputType ty | ||||
| void nfc_scene_device_info_on_enter(void* context) { | ||||
|     Nfc* nfc = context; | ||||
| 
 | ||||
|     bool data_display_supported = (nfc->dev->format == NfcDeviceSaveFormatUid) || | ||||
|                                   (nfc->dev->format == NfcDeviceSaveFormatMifareUl) || | ||||
|                                   (nfc->dev->format == NfcDeviceSaveFormatMifareDesfire) || | ||||
|                                   (nfc->dev->format == NfcDeviceSaveFormatBankCard); | ||||
|     // Setup Custom Widget view
 | ||||
|     widget_add_text_box_element( | ||||
|         nfc->widget, 0, 0, 128, 22, AlignCenter, AlignCenter, nfc->dev->dev_name); | ||||
|         nfc->widget, 0, 0, 128, 22, AlignCenter, AlignTop, nfc->dev->dev_name); | ||||
|     widget_add_button_element( | ||||
|         nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_device_info_widget_callback, nfc); | ||||
|     widget_add_button_element( | ||||
|         nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc); | ||||
|     if(data_display_supported) { | ||||
|         widget_add_button_element( | ||||
|             nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc); | ||||
|     } | ||||
|     char uid_str[32]; | ||||
|     NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data; | ||||
|     if(data->uid_len == 4) { | ||||
| @ -64,10 +70,13 @@ void nfc_scene_device_info_on_enter(void* context) { | ||||
|     widget_add_string_element(nfc->widget, 64, 21, AlignCenter, AlignTop, FontSecondary, uid_str); | ||||
| 
 | ||||
|     const char* protocol_name = NULL; | ||||
|     if(data->protocol == NfcDeviceProtocolEMV) { | ||||
|     if(data->protocol == NfcDeviceProtocolEMV || | ||||
|        data->protocol == NfcDeviceProtocolMifareDesfire) { | ||||
|         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); | ||||
|     } else if(data->protocol == NfcDeviceProtocolMifareClassic) { | ||||
|         protocol_name = nfc_mf_classic_type(nfc->dev->dev_data.mf_classic_data.type); | ||||
|     } | ||||
|     if(protocol_name) { | ||||
|         widget_add_string_element( | ||||
| @ -101,6 +110,25 @@ void nfc_scene_device_info_on_enter(void* context) { | ||||
|                 nfc->text_box_store, "%02X%02X ", mf_ul_data->data[i], mf_ul_data->data[i + 1]); | ||||
|         } | ||||
|         text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); | ||||
|     } else if(nfc->dev->format == NfcDeviceSaveFormatMifareDesfire) { | ||||
|         MifareDesfireData* mf_df_data = &nfc->dev->dev_data.mf_df_data; | ||||
|         uint16_t n_apps = 0; | ||||
|         uint16_t n_files = 0; | ||||
|         for(MifareDesfireApplication* app = mf_df_data->app_head; app; app = app->next) { | ||||
|             n_apps++; | ||||
|             for(MifareDesfireFile* file = app->file_head; file; file = file->next) { | ||||
|                 n_files++; | ||||
|             } | ||||
|         } | ||||
|         nfc_text_store_set( | ||||
|             nfc, | ||||
|             "%d application%s, %d file%s", | ||||
|             n_apps, | ||||
|             n_apps == 1 ? "" : "s", | ||||
|             n_files, | ||||
|             n_files == 1 ? "" : "s"); | ||||
|         widget_add_string_element( | ||||
|             nfc->widget, 64, 17, AlignCenter, AlignBottom, FontSecondary, nfc->text_store); | ||||
|     } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) { | ||||
|         NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data; | ||||
|         BankCard* bank_card = nfc->bank_card; | ||||
| @ -162,6 +190,9 @@ bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) { | ||||
|                     nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData); | ||||
|                 view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewBankCard); | ||||
|                 consumed = true; | ||||
|             } else if(nfc->dev->format == NfcDeviceSaveFormatMifareDesfire) { | ||||
|                 scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireData); | ||||
|                 consumed = true; | ||||
|             } | ||||
|         } else if(state == NfcSceneDeviceInfoData && event.event == NfcCustomEventViewExit) { | ||||
|             scene_manager_set_scene_state( | ||||
|  | ||||
							
								
								
									
										52
									
								
								applications/nfc/scenes/nfc_scene_dict_not_found.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								applications/nfc/scenes/nfc_scene_dict_not_found.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,52 @@ | ||||
| #include "../nfc_i.h" | ||||
| 
 | ||||
| void nfc_scene_dict_not_found_popup_callback(void* context) { | ||||
|     Nfc* nfc = context; | ||||
|     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_dict_not_found_on_enter(void* context) { | ||||
|     Nfc* nfc = context; | ||||
| 
 | ||||
|     // Setup view
 | ||||
|     Popup* popup = nfc->popup; | ||||
|     popup_set_text( | ||||
|         popup, | ||||
|         "Function requires\nan SD card with\nfresh databases.", | ||||
|         82, | ||||
|         24, | ||||
|         AlignCenter, | ||||
|         AlignCenter); | ||||
|     popup_set_icon(popup, 6, 10, &I_SDQuestion_35x43); | ||||
|     popup_set_timeout(popup, 2500); | ||||
|     popup_set_context(popup, nfc); | ||||
|     popup_set_callback(popup, nfc_scene_dict_not_found_popup_callback); | ||||
|     popup_enable_timeout(popup); | ||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); | ||||
| } | ||||
| 
 | ||||
| bool nfc_scene_dict_not_found_on_event(void* context, SceneManagerEvent event) { | ||||
|     Nfc* nfc = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == NfcCustomEventViewExit) { | ||||
|             if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneScriptsMenu)) { | ||||
|                 consumed = scene_manager_search_and_switch_to_previous_scene( | ||||
|                     nfc->scene_manager, NfcSceneScriptsMenu); | ||||
|             } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneCardMenu)) { | ||||
|                 consumed = scene_manager_search_and_switch_to_previous_scene( | ||||
|                     nfc->scene_manager, NfcSceneCardMenu); | ||||
|             } else { | ||||
|                 consumed = scene_manager_search_and_switch_to_previous_scene( | ||||
|                     nfc->scene_manager, NfcSceneStart); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_dict_not_found_on_exit(void* context) { | ||||
|     Nfc* nfc = context; | ||||
|     popup_reset(nfc->popup); | ||||
| } | ||||
| @ -4,7 +4,7 @@ | ||||
| #define NFC_MF_UL_DATA_NOT_CHANGED (0UL) | ||||
| #define NFC_MF_UL_DATA_CHANGED (1UL) | ||||
| 
 | ||||
| void nfc_emulate_mifare_ul_worker_callback(void* context) { | ||||
| void nfc_emulate_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     scene_manager_set_scene_state( | ||||
|         nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_CHANGED); | ||||
|  | ||||
| @ -6,7 +6,7 @@ enum { | ||||
|     NfcSceneEmulateUidStateTextBox, | ||||
| }; | ||||
| 
 | ||||
| void nfc_emulate_uid_worker_callback(void* context) { | ||||
| void nfc_emulate_uid_worker_callback(NfcWorkerEvent event, void* context) { | ||||
|     furi_assert(context); | ||||
|     Nfc* nfc = context; | ||||
|     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); | ||||
|  | ||||
							
								
								
									
										119
									
								
								applications/nfc/scenes/nfc_scene_mifare_desfire_app.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								applications/nfc/scenes/nfc_scene_mifare_desfire_app.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,119 @@ | ||||
| #include "../nfc_i.h" | ||||
| 
 | ||||
| #define TAG "NfcSceneMifareDesfireApp" | ||||
| 
 | ||||
| enum SubmenuIndex { | ||||
|     SubmenuIndexAppInfo, | ||||
|     SubmenuIndexDynamic, // dynamic indexes start here
 | ||||
| }; | ||||
| 
 | ||||
| MifareDesfireApplication* nfc_scene_mifare_desfire_app_get_app(Nfc* nfc) { | ||||
|     uint32_t app_idx = | ||||
|         scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp) >> 1; | ||||
|     MifareDesfireApplication* app = nfc->dev->dev_data.mf_df_data.app_head; | ||||
|     for(int i = 0; i < app_idx && app; i++) { | ||||
|         app = app->next; | ||||
|     } | ||||
|     return app; | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_mifare_desfire_app_submenu_callback(void* context, uint32_t index) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
| 
 | ||||
|     view_dispatcher_send_custom_event(nfc->view_dispatcher, index); | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_mifare_desfire_app_on_enter(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     Submenu* submenu = nfc->submenu; | ||||
|     MifareDesfireApplication* app = nfc_scene_mifare_desfire_app_get_app(nfc); | ||||
|     if(!app) { | ||||
|         popup_set_icon(nfc->popup, 5, 5, &I_WarningDolphin_45x42); | ||||
|         popup_set_header(nfc->popup, "Internal Error!", 55, 12, AlignLeft, AlignBottom); | ||||
|         popup_set_text( | ||||
|             nfc->popup, | ||||
|             "No app selected.\nThis should\nnever happen,\nplease file a bug.", | ||||
|             55, | ||||
|             15, | ||||
|             AlignLeft, | ||||
|             AlignTop); | ||||
|         view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); | ||||
|         FURI_LOG_E(TAG, "Bad state. No app selected?"); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     text_box_set_font(nfc->text_box, TextBoxFontHex); | ||||
| 
 | ||||
|     submenu_add_item( | ||||
|         submenu, | ||||
|         "App info", | ||||
|         SubmenuIndexAppInfo, | ||||
|         nfc_scene_mifare_desfire_app_submenu_callback, | ||||
|         nfc); | ||||
| 
 | ||||
|     uint16_t cap = NFC_TEXT_STORE_SIZE; | ||||
|     char* buf = nfc->text_store; | ||||
|     int idx = SubmenuIndexDynamic; | ||||
|     for(MifareDesfireFile* file = app->file_head; file; file = file->next) { | ||||
|         int size = snprintf(buf, cap, "File %d", file->id); | ||||
|         if(size < 0 || size >= cap) { | ||||
|             FURI_LOG_W( | ||||
|                 TAG, | ||||
|                 "Exceeded NFC_TEXT_STORE_SIZE when preparing file id strings; menu truncated"); | ||||
|             break; | ||||
|         } | ||||
|         char* label = buf; | ||||
|         cap -= size + 1; | ||||
|         buf += size + 1; | ||||
|         submenu_add_item( | ||||
|             submenu, label, idx++, nfc_scene_mifare_desfire_app_submenu_callback, nfc); | ||||
|     } | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); | ||||
| } | ||||
| 
 | ||||
| bool nfc_scene_mifare_desfire_app_on_event(void* context, SceneManagerEvent event) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp); | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         MifareDesfireApplication* app = nfc_scene_mifare_desfire_app_get_app(nfc); | ||||
|         TextBox* text_box = nfc->text_box; | ||||
|         string_reset(nfc->text_box_store); | ||||
|         if(event.event == SubmenuIndexAppInfo) { | ||||
|             mf_df_cat_application_info(app, nfc->text_box_store); | ||||
|         } else { | ||||
|             uint16_t index = event.event - SubmenuIndexDynamic; | ||||
|             MifareDesfireFile* file = app->file_head; | ||||
|             for(int i = 0; file && i < index; i++) { | ||||
|                 file = file->next; | ||||
|             } | ||||
|             if(!file) { | ||||
|                 return false; | ||||
|             } | ||||
|             mf_df_cat_file(file, nfc->text_box_store); | ||||
|         } | ||||
|         text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); | ||||
|         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMifareDesfireApp, state | 1); | ||||
|         view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); | ||||
|         return true; | ||||
|     } else if(event.type == SceneManagerEventTypeBack) { | ||||
|         if(state & 1) { | ||||
|             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, NfcSceneMifareDesfireApp, state & ~1); | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_mifare_desfire_app_on_exit(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
| 
 | ||||
|     text_box_reset(nfc->text_box); | ||||
|     string_reset(nfc->text_box_store); | ||||
| 
 | ||||
|     submenu_reset(nfc->submenu); | ||||
| } | ||||
							
								
								
									
										108
									
								
								applications/nfc/scenes/nfc_scene_mifare_desfire_data.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								applications/nfc/scenes/nfc_scene_mifare_desfire_data.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,108 @@ | ||||
| #include "../nfc_i.h" | ||||
| 
 | ||||
| #define TAG "NfcSceneMifareDesfireData" | ||||
| 
 | ||||
| enum { | ||||
|     MifareDesfireDataStateMenu, | ||||
|     MifareDesfireDataStateItem, // MUST be last, states >= this correspond with submenu index
 | ||||
| }; | ||||
| 
 | ||||
| enum SubmenuIndex { | ||||
|     SubmenuIndexCardInfo, | ||||
|     SubmenuIndexDynamic, // dynamic indexes start here
 | ||||
| }; | ||||
| 
 | ||||
| void nfc_scene_mifare_desfire_data_submenu_callback(void* context, uint32_t index) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
| 
 | ||||
|     view_dispatcher_send_custom_event(nfc->view_dispatcher, index); | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_mifare_desfire_data_on_enter(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     Submenu* submenu = nfc->submenu; | ||||
|     uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData); | ||||
|     MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; | ||||
| 
 | ||||
|     text_box_set_font(nfc->text_box, TextBoxFontHex); | ||||
| 
 | ||||
|     submenu_add_item( | ||||
|         submenu, | ||||
|         "Card info", | ||||
|         SubmenuIndexCardInfo, | ||||
|         nfc_scene_mifare_desfire_data_submenu_callback, | ||||
|         nfc); | ||||
| 
 | ||||
|     uint16_t cap = NFC_TEXT_STORE_SIZE; | ||||
|     char* buf = nfc->text_store; | ||||
|     int idx = SubmenuIndexDynamic; | ||||
|     for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { | ||||
|         int size = snprintf(buf, cap, "App %02x%02x%02x", app->id[0], app->id[1], app->id[2]); | ||||
|         if(size < 0 || size >= cap) { | ||||
|             FURI_LOG_W( | ||||
|                 TAG, "Exceeded NFC_TEXT_STORE_SIZE when preparing app id strings; menu truncated"); | ||||
|             break; | ||||
|         } | ||||
|         char* label = buf; | ||||
|         cap -= size + 1; | ||||
|         buf += size + 1; | ||||
|         submenu_add_item( | ||||
|             submenu, label, idx++, nfc_scene_mifare_desfire_data_submenu_callback, nfc); | ||||
|     } | ||||
| 
 | ||||
|     if(state >= MifareDesfireDataStateItem) { | ||||
|         submenu_set_selected_item( | ||||
|             nfc->submenu, state - MifareDesfireDataStateItem + SubmenuIndexDynamic); | ||||
|         scene_manager_set_scene_state( | ||||
|             nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateMenu); | ||||
|     } | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); | ||||
| } | ||||
| 
 | ||||
| bool nfc_scene_mifare_desfire_data_on_event(void* context, SceneManagerEvent event) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireData); | ||||
|     MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         TextBox* text_box = nfc->text_box; | ||||
|         string_reset(nfc->text_box_store); | ||||
|         if(event.event == SubmenuIndexCardInfo) { | ||||
|             mf_df_cat_card_info(data, nfc->text_box_store); | ||||
|             text_box_set_text(text_box, string_get_cstr(nfc->text_box_store)); | ||||
|             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, | ||||
|                 NfcSceneMifareDesfireData, | ||||
|                 MifareDesfireDataStateItem + SubmenuIndexCardInfo); | ||||
|             return true; | ||||
|         } else { | ||||
|             uint16_t index = event.event - SubmenuIndexDynamic; | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateItem + index); | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, NfcSceneMifareDesfireApp, index << 1); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireApp); | ||||
|             return true; | ||||
|         } | ||||
|     } else if(event.type == SceneManagerEventTypeBack) { | ||||
|         if(state >= MifareDesfireDataStateItem) { | ||||
|             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, NfcSceneMifareDesfireData, MifareDesfireDataStateMenu); | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_mifare_desfire_data_on_exit(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
| 
 | ||||
|     text_box_reset(nfc->text_box); | ||||
|     string_reset(nfc->text_box_store); | ||||
| 
 | ||||
|     submenu_reset(nfc->submenu); | ||||
| } | ||||
							
								
								
									
										52
									
								
								applications/nfc/scenes/nfc_scene_mifare_desfire_menu.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								applications/nfc/scenes/nfc_scene_mifare_desfire_menu.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,52 @@ | ||||
| #include "../nfc_i.h" | ||||
| 
 | ||||
| enum SubmenuIndex { | ||||
|     SubmenuIndexSave, | ||||
| }; | ||||
| 
 | ||||
| void nfc_scene_mifare_desfire_menu_submenu_callback(void* context, uint32_t index) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
| 
 | ||||
|     view_dispatcher_send_custom_event(nfc->view_dispatcher, index); | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_mifare_desfire_menu_on_enter(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     Submenu* submenu = nfc->submenu; | ||||
| 
 | ||||
|     submenu_add_item( | ||||
|         submenu, | ||||
|         "Name and save", | ||||
|         SubmenuIndexSave, | ||||
|         nfc_scene_mifare_desfire_menu_submenu_callback, | ||||
|         nfc); | ||||
|     submenu_set_selected_item( | ||||
|         nfc->submenu, | ||||
|         scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMifareDesfireMenu)); | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); | ||||
| } | ||||
| 
 | ||||
| bool nfc_scene_mifare_desfire_menu_on_event(void* context, SceneManagerEvent event) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == SubmenuIndexSave) { | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, NfcSceneMifareDesfireMenu, SubmenuIndexSave); | ||||
|             nfc->dev->format = NfcDeviceSaveFormatMifareDesfire; | ||||
|             // Clear device name
 | ||||
|             nfc_device_set_name(nfc->dev, ""); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_mifare_desfire_menu_on_exit(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
| 
 | ||||
|     submenu_reset(nfc->submenu); | ||||
| } | ||||
| @ -1,7 +1,7 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void nfc_read_card_worker_callback(void* context) { | ||||
| void nfc_read_card_worker_callback(NfcWorkerEvent event, void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); | ||||
| } | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void nfc_read_emv_app_worker_callback(void* context) { | ||||
| void nfc_read_emv_app_worker_callback(NfcWorkerEvent event, void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); | ||||
| } | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void nfc_read_emv_data_worker_callback(void* context) { | ||||
| void nfc_read_emv_data_worker_callback(NfcWorkerEvent event, void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); | ||||
| } | ||||
|  | ||||
							
								
								
									
										95
									
								
								applications/nfc/scenes/nfc_scene_read_mifare_classic.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								applications/nfc/scenes/nfc_scene_read_mifare_classic.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,95 @@ | ||||
| #include "../nfc_i.h" | ||||
| 
 | ||||
| enum { | ||||
|     NfcSceneReadMifareClassicStateInProgress, | ||||
|     NfcSceneReadMifareClassicStateDone, | ||||
| }; | ||||
| 
 | ||||
| void nfc_read_mifare_classic_worker_callback(NfcWorkerEvent event, void* context) { | ||||
|     furi_assert(context); | ||||
|     Nfc* nfc = context; | ||||
|     view_dispatcher_send_custom_event(nfc->view_dispatcher, event); | ||||
| } | ||||
| 
 | ||||
| void nfc_read_mifare_classic_dict_attack_result_callback(void* context) { | ||||
|     furi_assert(context); | ||||
|     Nfc* nfc = context; | ||||
|     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventDictAttackDone); | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_read_mifare_classic_on_enter(void* context) { | ||||
|     Nfc* nfc = context; | ||||
| 
 | ||||
|     // Setup and start worker
 | ||||
|     memset(&nfc->dev->dev_data.mf_classic_data, 0, sizeof(MfClassicData)); | ||||
|     dict_attack_set_result_callback( | ||||
|         nfc->dict_attack, nfc_read_mifare_classic_dict_attack_result_callback, nfc); | ||||
|     scene_manager_set_scene_state( | ||||
|         nfc->scene_manager, NfcSceneReadMifareClassic, NfcSceneReadMifareClassicStateInProgress); | ||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDictAttack); | ||||
|     nfc_worker_start( | ||||
|         nfc->worker, | ||||
|         NfcWorkerStateReadMifareClassic, | ||||
|         &nfc->dev->dev_data, | ||||
|         nfc_read_mifare_classic_worker_callback, | ||||
|         nfc); | ||||
| } | ||||
| 
 | ||||
| bool nfc_scene_read_mifare_classic_on_event(void* context, SceneManagerEvent event) { | ||||
|     Nfc* nfc = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareClassic); | ||||
|     if(event.type == SceneManagerEventTypeTick) { | ||||
|         if(state == NfcSceneReadMifareClassicStateInProgress) { | ||||
|             notification_message(nfc->notifications, &sequence_blink_blue_10); | ||||
|         } | ||||
|         consumed = true; | ||||
|     } else if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == NfcCustomEventDictAttackDone) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName); | ||||
|             consumed = true; | ||||
|         } else if(event.event == NfcWorkerEventDetectedClassic1k) { | ||||
|             dict_attack_card_detected(nfc->dict_attack, MfClassicType1k); | ||||
|             consumed = true; | ||||
|         } else if(event.event == NfcWorkerEventDetectedClassic4k) { | ||||
|             dict_attack_card_detected(nfc->dict_attack, MfClassicType4k); | ||||
|             consumed = true; | ||||
|         } else if(event.event == NfcWorkerEventNewSector) { | ||||
|             dict_attack_inc_curr_sector(nfc->dict_attack); | ||||
|             consumed = true; | ||||
|         } else if(event.event == NfcWorkerEventFoundKeyA) { | ||||
|             dict_attack_inc_found_key(nfc->dict_attack, MfClassicKeyA); | ||||
|             consumed = true; | ||||
|         } else if(event.event == NfcWorkerEventFoundKeyB) { | ||||
|             dict_attack_inc_found_key(nfc->dict_attack, MfClassicKeyB); | ||||
|             consumed = true; | ||||
|         } else if(event.event == NfcWorkerEventNoCardDetected) { | ||||
|             dict_attack_card_removed(nfc->dict_attack); | ||||
|             consumed = true; | ||||
|         } else if(event.event == NfcWorkerEventSuccess) { | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, NfcSceneReadMifareClassic, NfcSceneReadMifareClassicStateDone); | ||||
|             notification_message(nfc->notifications, &sequence_success); | ||||
|             nfc->dev->format = NfcDeviceSaveFormatMifareClassic; | ||||
|             dict_attack_set_result(nfc->dict_attack, true); | ||||
|             consumed = true; | ||||
|         } else if(event.event == NfcWorkerEventFail) { | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, NfcSceneReadMifareClassic, NfcSceneReadMifareClassicStateDone); | ||||
|             dict_attack_set_result(nfc->dict_attack, false); | ||||
|             consumed = true; | ||||
|         } else if(event.event == NfcWorkerEventNoDictFound) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneDictNotFound); | ||||
|             consumed = true; | ||||
|         } | ||||
|     } | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_read_mifare_classic_on_exit(void* context) { | ||||
|     Nfc* nfc = context; | ||||
|     // Stop worker
 | ||||
|     nfc_worker_stop(nfc->worker); | ||||
|     dict_attack_reset(nfc->dict_attack); | ||||
| } | ||||
							
								
								
									
										56
									
								
								applications/nfc/scenes/nfc_scene_read_mifare_desfire.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								applications/nfc/scenes/nfc_scene_read_mifare_desfire.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void nfc_read_mifare_desfire_worker_callback(NfcWorkerEvent event, void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_read_mifare_desfire_on_enter(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     DOLPHIN_DEED(DolphinDeedNfcRead); | ||||
| 
 | ||||
|     // Setup view
 | ||||
|     Popup* popup = nfc->popup; | ||||
|     popup_set_header(popup, "Reading\nDESFire", 70, 34, AlignLeft, AlignTop); | ||||
|     popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61); | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup); | ||||
|     // Start worker
 | ||||
|     nfc_worker_start( | ||||
|         nfc->worker, | ||||
|         NfcWorkerStateReadMifareDesfire, | ||||
|         &nfc->dev->dev_data, | ||||
|         nfc_read_mifare_desfire_worker_callback, | ||||
|         nfc); | ||||
| } | ||||
| 
 | ||||
| bool nfc_scene_read_mifare_desfire_on_event(void* context, SceneManagerEvent event) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == NfcCustomEventWorkerExit) { | ||||
|             notification_message(nfc->notifications, &sequence_success); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess); | ||||
|             return true; | ||||
|         } | ||||
|     } else if(event.type == SceneManagerEventTypeTick) { | ||||
|         notification_message(nfc->notifications, &sequence_blink_blue_10); | ||||
|         DOLPHIN_DEED(DolphinDeedNfcReadSuccess); | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_read_mifare_desfire_on_exit(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
| 
 | ||||
|     // Stop worker
 | ||||
|     nfc_worker_stop(nfc->worker); | ||||
| 
 | ||||
|     // Clear view
 | ||||
|     Popup* popup = nfc->popup; | ||||
|     popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); | ||||
|     popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); | ||||
|     popup_set_icon(popup, 0, 0, NULL); | ||||
| } | ||||
							
								
								
									
										106
									
								
								applications/nfc/scenes/nfc_scene_read_mifare_desfire_success.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								applications/nfc/scenes/nfc_scene_read_mifare_desfire_success.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,106 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| #define NFC_SCENE_READ_SUCCESS_SHIFT "              " | ||||
| 
 | ||||
| enum { | ||||
|     ReadMifareDesfireSuccessStateShowUID, | ||||
|     ReadMifareDesfireSuccessStateShowData, | ||||
| }; | ||||
| 
 | ||||
| void nfc_scene_read_mifare_desfire_success_dialog_callback(DialogExResult result, void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
| 
 | ||||
|     view_dispatcher_send_custom_event(nfc->view_dispatcher, result); | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_read_mifare_desfire_success_on_enter(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
| 
 | ||||
|     MifareDesfireData* data = &nfc->dev->dev_data.mf_df_data; | ||||
|     DialogEx* dialog_ex = nfc->dialog_ex; | ||||
|     dialog_ex_set_left_button_text(dialog_ex, "Back"); | ||||
|     dialog_ex_set_center_button_text(dialog_ex, "Data"); | ||||
|     dialog_ex_set_right_button_text(dialog_ex, "More"); | ||||
|     dialog_ex_set_icon(dialog_ex, 8, 16, &I_Medium_chip_22x21); | ||||
| 
 | ||||
|     uint16_t n_apps = 0; | ||||
|     uint16_t n_files = 0; | ||||
| 
 | ||||
|     for(MifareDesfireApplication* app = data->app_head; app; app = app->next) { | ||||
|         n_apps++; | ||||
|         for(MifareDesfireFile* file = app->file_head; file; file = file->next) { | ||||
|             n_files++; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     nfc_text_store_set( | ||||
|         nfc, | ||||
|         "UID: %02X %02X %02X %02X %02X %02X %02X\n" NFC_SCENE_READ_SUCCESS_SHIFT | ||||
|         "%d%s bytes\n" NFC_SCENE_READ_SUCCESS_SHIFT "%d bytes free\n" | ||||
|         "%d application%s, %d file%s", | ||||
|         data->version.uid[0], | ||||
|         data->version.uid[1], | ||||
|         data->version.uid[2], | ||||
|         data->version.uid[3], | ||||
|         data->version.uid[4], | ||||
|         data->version.uid[5], | ||||
|         data->version.uid[6], | ||||
|         1 << (data->version.sw_storage >> 1), | ||||
|         (data->version.sw_storage & 1) ? "+" : "", | ||||
|         data->free_memory ? data->free_memory->bytes : 0, | ||||
|         n_apps, | ||||
|         n_apps == 1 ? "" : "s", | ||||
|         n_files, | ||||
|         n_files == 1 ? "" : "s"); | ||||
|     dialog_ex_set_text(dialog_ex, nfc->text_store, 8, 6, AlignLeft, AlignTop); | ||||
|     dialog_ex_set_context(dialog_ex, nfc); | ||||
|     dialog_ex_set_result_callback( | ||||
|         dialog_ex, nfc_scene_read_mifare_desfire_success_dialog_callback); | ||||
| 
 | ||||
|     scene_manager_set_scene_state( | ||||
|         nfc->scene_manager, | ||||
|         NfcSceneReadMifareDesfireSuccess, | ||||
|         ReadMifareDesfireSuccessStateShowUID); | ||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); | ||||
| } | ||||
| 
 | ||||
| bool nfc_scene_read_mifare_desfire_success_on_event(void* context, SceneManagerEvent event) { | ||||
|     Nfc* nfc = context; | ||||
|     uint32_t state = | ||||
|         scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadMifareDesfireSuccess); | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(state == ReadMifareDesfireSuccessStateShowUID && event.event == DialogExResultLeft) { | ||||
|             scene_manager_previous_scene(nfc->scene_manager); | ||||
|             consumed = true; | ||||
|         } else if( | ||||
|             state == ReadMifareDesfireSuccessStateShowUID && event.event == DialogExResultCenter) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireData); | ||||
|             consumed = true; | ||||
|         } else if(state == ReadMifareDesfireSuccessStateShowUID && event.event == DialogExResultRight) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneMifareDesfireMenu); | ||||
|             consumed = true; | ||||
|         } | ||||
|     } else if(event.type == SceneManagerEventTypeBack) { | ||||
|         if(state == ReadMifareDesfireSuccessStateShowData) { | ||||
|             view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx); | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, | ||||
|                 NfcSceneReadMifareDesfireSuccess, | ||||
|                 ReadMifareDesfireSuccessStateShowUID); | ||||
|             consumed = true; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_read_mifare_desfire_success_on_exit(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
| 
 | ||||
|     // Clean dialog
 | ||||
|     DialogEx* dialog_ex = nfc->dialog_ex; | ||||
|     dialog_ex_reset(dialog_ex); | ||||
| } | ||||
| @ -1,13 +1,13 @@ | ||||
| #include "../nfc_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void nfc_read_mifare_ul_worker_callback(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
| void nfc_read_mifare_ul_worker_callback(NfcWorkerEvent event, void* context) { | ||||
|     Nfc* nfc = context; | ||||
|     view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventWorkerExit); | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_read_mifare_ul_on_enter(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     Nfc* nfc = context; | ||||
|     DOLPHIN_DEED(DolphinDeedNfcRead); | ||||
| 
 | ||||
|     // Setup view
 | ||||
| @ -26,29 +26,25 @@ void nfc_scene_read_mifare_ul_on_enter(void* context) { | ||||
| } | ||||
| 
 | ||||
| bool nfc_scene_read_mifare_ul_on_event(void* context, SceneManagerEvent event) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     Nfc* nfc = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == NfcCustomEventWorkerExit) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUlSuccess); | ||||
|             return true; | ||||
|             consumed = true; | ||||
|         } | ||||
|     } else if(event.type == SceneManagerEventTypeTick) { | ||||
|         notification_message(nfc->notifications, &sequence_blink_blue_10); | ||||
|         return true; | ||||
|         consumed = true; | ||||
|     } | ||||
|     return false; | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_read_mifare_ul_on_exit(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
| 
 | ||||
|     Nfc* nfc = context; | ||||
|     // Stop worker
 | ||||
|     nfc_worker_stop(nfc->worker); | ||||
| 
 | ||||
|     // Clear view
 | ||||
|     Popup* popup = nfc->popup; | ||||
|     popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); | ||||
|     popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop); | ||||
|     popup_set_icon(popup, 0, 0, NULL); | ||||
|     popup_reset(nfc->popup); | ||||
| } | ||||
|  | ||||
							
								
								
									
										4
									
								
								applications/nfc/scenes/nfc_scene_save_success.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										4
									
								
								applications/nfc/scenes/nfc_scene_save_success.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @ -33,6 +33,10 @@ bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) { | ||||
|             } else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) { | ||||
|                 consumed = scene_manager_search_and_switch_to_another_scene( | ||||
|                     nfc->scene_manager, NfcSceneFileSelect); | ||||
|             } else if(scene_manager_has_previous_scene( | ||||
|                           nfc->scene_manager, NfcSceneMifareDesfireMenu)) { | ||||
|                 consumed = scene_manager_search_and_switch_to_previous_scene( | ||||
|                     nfc->scene_manager, NfcSceneMifareDesfireMenu); | ||||
|             } else { | ||||
|                 consumed = scene_manager_search_and_switch_to_previous_scene( | ||||
|                     nfc->scene_manager, NfcSceneStart); | ||||
|  | ||||
							
								
								
									
										17
									
								
								applications/nfc/scenes/nfc_scene_saved_menu.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										17
									
								
								applications/nfc/scenes/nfc_scene_saved_menu.c
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							| @ -18,9 +18,22 @@ void nfc_scene_saved_menu_on_enter(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     Submenu* submenu = nfc->submenu; | ||||
| 
 | ||||
|     if(nfc->dev->format != NfcDeviceSaveFormatBankCard) { | ||||
|     if(nfc->dev->format == NfcDeviceSaveFormatUid || | ||||
|        nfc->dev->format == NfcDeviceSaveFormatMifareDesfire || | ||||
|        nfc->dev->format == NfcDeviceSaveFormatBankCard) { | ||||
|         submenu_add_item( | ||||
|             submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc); | ||||
|             submenu, | ||||
|             "Emulate UID", | ||||
|             SubmenuIndexEmulate, | ||||
|             nfc_scene_saved_menu_submenu_callback, | ||||
|             nfc); | ||||
|     } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { | ||||
|         submenu_add_item( | ||||
|             submenu, | ||||
|             "Emulate Ultralight", | ||||
|             SubmenuIndexEmulate, | ||||
|             nfc_scene_saved_menu_submenu_callback, | ||||
|             nfc); | ||||
|     } | ||||
|     submenu_add_item( | ||||
|         submenu, "Edit UID and name", SubmenuIndexEdit, nfc_scene_saved_menu_submenu_callback, nfc); | ||||
|  | ||||
| @ -3,16 +3,17 @@ | ||||
| enum SubmenuIndex { | ||||
|     SubmenuIndexBankCard, | ||||
|     SubmenuIndexMifareUltralight, | ||||
|     SubmenuIdexReadMfClassic, | ||||
|     SubmenuIndexMifareDesfire, | ||||
| }; | ||||
| 
 | ||||
| void nfc_scene_scripts_menu_submenu_callback(void* context, uint32_t index) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
| 
 | ||||
|     Nfc* nfc = context; | ||||
|     view_dispatcher_send_custom_event(nfc->view_dispatcher, index); | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_scripts_menu_on_enter(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     Nfc* nfc = context; | ||||
|     Submenu* submenu = nfc->submenu; | ||||
| 
 | ||||
|     submenu_add_item( | ||||
| @ -27,33 +28,55 @@ void nfc_scene_scripts_menu_on_enter(void* context) { | ||||
|         SubmenuIndexMifareUltralight, | ||||
|         nfc_scene_scripts_menu_submenu_callback, | ||||
|         nfc); | ||||
|     submenu_add_item( | ||||
|         submenu, | ||||
|         "Read Mifare Classic", | ||||
|         SubmenuIdexReadMfClassic, | ||||
|         nfc_scene_scripts_menu_submenu_callback, | ||||
|         nfc); | ||||
|     submenu_add_item( | ||||
|         submenu, | ||||
|         "Read Mifare DESFire", | ||||
|         SubmenuIndexMifareDesfire, | ||||
|         nfc_scene_scripts_menu_submenu_callback, | ||||
|         nfc); | ||||
|     submenu_set_selected_item( | ||||
|         nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneScriptsMenu)); | ||||
|     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu); | ||||
| } | ||||
| 
 | ||||
| bool nfc_scene_scripts_menu_on_event(void* context, SceneManagerEvent event) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
|     Nfc* nfc = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == SubmenuIndexBankCard) { | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, NfcSceneScriptsMenu, SubmenuIndexBankCard); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp); | ||||
|             return true; | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexMifareUltralight) { | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, NfcSceneScriptsMenu, SubmenuIndexMifareUltralight); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUl); | ||||
|             return true; | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIdexReadMfClassic) { | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, NfcSceneScriptsMenu, SubmenuIdexReadMfClassic); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareClassic); | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexMifareDesfire) { | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, NfcSceneScriptsMenu, SubmenuIndexMifareDesfire); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareDesfire); | ||||
|             consumed = true; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void nfc_scene_scripts_menu_on_exit(void* context) { | ||||
|     Nfc* nfc = (Nfc*)context; | ||||
| 
 | ||||
|     Nfc* nfc = context; | ||||
|     submenu_reset(nfc->submenu); | ||||
| } | ||||
|  | ||||
| @ -49,21 +49,15 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == SubmenuIndexRead) { | ||||
|             scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexRead); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCard); | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexRunScript) { | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, NfcSceneStart, SubmenuIndexRunScript); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneScriptsMenu); | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexSaved) { | ||||
|             scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexSaved); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneFileSelect); | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexAddManualy) { | ||||
|             scene_manager_set_scene_state( | ||||
|                 nfc->scene_manager, NfcSceneStart, SubmenuIndexAddManualy); | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType); | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexDebug) { | ||||
| @ -71,6 +65,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) { | ||||
|             scene_manager_next_scene(nfc->scene_manager, NfcSceneDebug); | ||||
|             consumed = true; | ||||
|         } | ||||
|         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, event.event); | ||||
|     } | ||||
|     return consumed; | ||||
| } | ||||
|  | ||||
							
								
								
									
										194
									
								
								applications/nfc/views/dict_attack.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								applications/nfc/views/dict_attack.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,194 @@ | ||||
| #include "dict_attack.h" | ||||
| #include <m-string.h> | ||||
| 
 | ||||
| #include <gui/elements.h> | ||||
| 
 | ||||
| typedef enum { | ||||
|     DictAttackStateSearchCard, | ||||
|     DictAttackStateSearchKeys, | ||||
|     DictAttackStateCardRemoved, | ||||
|     DictAttackStateSuccess, | ||||
|     DictAttackStateFail, | ||||
| } DictAttackState; | ||||
| 
 | ||||
| struct DictAttack { | ||||
|     View* view; | ||||
|     DictAttackResultCallback callback; | ||||
|     void* context; | ||||
| }; | ||||
| 
 | ||||
| typedef struct { | ||||
|     DictAttackState state; | ||||
|     MfClassicType type; | ||||
|     uint8_t current_sector; | ||||
|     uint8_t total_sectors; | ||||
|     uint8_t keys_a_found; | ||||
|     uint8_t keys_a_total; | ||||
|     uint8_t keys_b_found; | ||||
|     uint8_t keys_b_total; | ||||
| } DictAttackViewModel; | ||||
| 
 | ||||
| static void dict_attack_draw_callback(Canvas* canvas, void* model) { | ||||
|     DictAttackViewModel* m = model; | ||||
|     if(m->state == DictAttackStateSearchCard) { | ||||
|         canvas_set_font(canvas, FontPrimary); | ||||
|         canvas_draw_str_aligned( | ||||
|             canvas, 64, 32, AlignCenter, AlignCenter, "Detecting Mifare Classic"); | ||||
|     } else if(m->state == DictAttackStateCardRemoved) { | ||||
|         canvas_set_font(canvas, FontPrimary); | ||||
|         canvas_draw_str_aligned( | ||||
|             canvas, 64, 32, AlignCenter, AlignTop, "Place card back to flipper"); | ||||
|     } else { | ||||
|         char draw_str[32]; | ||||
|         if(m->state == DictAttackStateSearchKeys) { | ||||
|             snprintf( | ||||
|                 draw_str, sizeof(draw_str), "Searching keys for sector %d", m->current_sector); | ||||
|             canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, draw_str); | ||||
|         } else if(m->state == DictAttackStateSuccess) { | ||||
|             canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, "Complete!"); | ||||
|             elements_button_right(canvas, "Save"); | ||||
|         } else if(m->state == DictAttackStateFail) { | ||||
|             canvas_draw_str_aligned( | ||||
|                 canvas, 64, 2, AlignCenter, AlignTop, "Failed to read any sector"); | ||||
|         } | ||||
|         uint16_t keys_found = m->keys_a_found + m->keys_b_found; | ||||
|         uint16_t keys_total = m->keys_a_total + m->keys_b_total; | ||||
|         float progress = (float)(m->current_sector) / (float)(m->total_sectors); | ||||
|         elements_progress_bar(canvas, 5, 12, 120, progress); | ||||
|         canvas_set_font(canvas, FontSecondary); | ||||
|         snprintf(draw_str, sizeof(draw_str), "Total keys found: %d/%d", keys_found, keys_total); | ||||
|         canvas_draw_str_aligned(canvas, 1, 23, AlignLeft, AlignTop, draw_str); | ||||
|         snprintf( | ||||
|             draw_str, sizeof(draw_str), "A keys found: %d/%d", m->keys_a_found, m->keys_a_total); | ||||
|         canvas_draw_str_aligned(canvas, 1, 34, AlignLeft, AlignTop, draw_str); | ||||
|         snprintf( | ||||
|             draw_str, sizeof(draw_str), "B keys found: %d/%d", m->keys_b_found, m->keys_b_total); | ||||
|         canvas_draw_str_aligned(canvas, 1, 45, AlignLeft, AlignTop, draw_str); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static bool dict_attack_input_callback(InputEvent* event, void* context) { | ||||
|     DictAttack* dict_attack = context; | ||||
|     bool consumed = false; | ||||
|     DictAttackState state; | ||||
|     with_view_model( | ||||
|         dict_attack->view, (DictAttackViewModel * model) { | ||||
|             state = model->state; | ||||
|             return false; | ||||
|         }); | ||||
|     if(state == DictAttackStateSuccess && event->type == InputTypeShort && | ||||
|        event->key == InputKeyRight) { | ||||
|         if(dict_attack->callback) { | ||||
|             dict_attack->callback(dict_attack->context); | ||||
|         } | ||||
|         consumed = true; | ||||
|     } | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| DictAttack* dict_attack_alloc() { | ||||
|     DictAttack* dict_attack = malloc(sizeof(DictAttack)); | ||||
|     dict_attack->view = view_alloc(); | ||||
|     view_allocate_model(dict_attack->view, ViewModelTypeLocking, sizeof(DictAttackViewModel)); | ||||
|     view_set_draw_callback(dict_attack->view, dict_attack_draw_callback); | ||||
|     view_set_input_callback(dict_attack->view, dict_attack_input_callback); | ||||
|     view_set_context(dict_attack->view, dict_attack); | ||||
|     return dict_attack; | ||||
| } | ||||
| 
 | ||||
| void dict_attack_free(DictAttack* dict_attack) { | ||||
|     furi_assert(dict_attack); | ||||
|     view_free(dict_attack->view); | ||||
|     free(dict_attack); | ||||
| } | ||||
| 
 | ||||
| void dict_attack_reset(DictAttack* dict_attack) { | ||||
|     furi_assert(dict_attack); | ||||
|     with_view_model( | ||||
|         dict_attack->view, (DictAttackViewModel * model) { | ||||
|             memset(model, 0, sizeof(DictAttackViewModel)); | ||||
|             return true; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| View* dict_attack_get_view(DictAttack* dict_attack) { | ||||
|     furi_assert(dict_attack); | ||||
|     return dict_attack->view; | ||||
| } | ||||
| 
 | ||||
| void dict_attack_set_result_callback( | ||||
|     DictAttack* dict_attack, | ||||
|     DictAttackResultCallback callback, | ||||
|     void* context) { | ||||
|     furi_assert(dict_attack); | ||||
|     furi_assert(callback); | ||||
|     dict_attack->callback = callback; | ||||
|     dict_attack->context = context; | ||||
| } | ||||
| 
 | ||||
| void dict_attack_card_detected(DictAttack* dict_attack, MfClassicType type) { | ||||
|     furi_assert(dict_attack); | ||||
|     with_view_model( | ||||
|         dict_attack->view, (DictAttackViewModel * model) { | ||||
|             model->state = DictAttackStateSearchKeys; | ||||
|             if(type == MfClassicType1k) { | ||||
|                 model->total_sectors = 16; | ||||
|                 model->keys_a_total = 16; | ||||
|                 model->keys_b_total = 16; | ||||
|             } else if(type == MfClassicType4k) { | ||||
|                 model->total_sectors = 40; | ||||
|                 model->keys_a_total = 40; | ||||
|                 model->keys_b_total = 40; | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| void dict_attack_card_removed(DictAttack* dict_attack) { | ||||
|     furi_assert(dict_attack); | ||||
|     with_view_model( | ||||
|         dict_attack->view, (DictAttackViewModel * model) { | ||||
|             if(model->state == DictAttackStateSearchKeys) { | ||||
|                 model->state = DictAttackStateCardRemoved; | ||||
|             } else { | ||||
|                 model->state = DictAttackStateSearchCard; | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| void dict_attack_inc_curr_sector(DictAttack* dict_attack) { | ||||
|     furi_assert(dict_attack); | ||||
|     with_view_model( | ||||
|         dict_attack->view, (DictAttackViewModel * model) { | ||||
|             model->current_sector++; | ||||
|             return true; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| void dict_attack_inc_found_key(DictAttack* dict_attack, MfClassicKey key) { | ||||
|     furi_assert(dict_attack); | ||||
|     with_view_model( | ||||
|         dict_attack->view, (DictAttackViewModel * model) { | ||||
|             model->state = DictAttackStateSearchKeys; | ||||
|             if(key == MfClassicKeyA) { | ||||
|                 model->keys_a_found++; | ||||
|             } else if(key == MfClassicKeyB) { | ||||
|                 model->keys_b_found++; | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| void dict_attack_set_result(DictAttack* dict_attack, bool success) { | ||||
|     furi_assert(dict_attack); | ||||
|     with_view_model( | ||||
|         dict_attack->view, (DictAttackViewModel * model) { | ||||
|             if(success) { | ||||
|                 model->state = DictAttackStateSuccess; | ||||
|             } else { | ||||
|                 model->state = DictAttackStateFail; | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
| } | ||||
							
								
								
									
										33
									
								
								applications/nfc/views/dict_attack.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								applications/nfc/views/dict_attack.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | ||||
| #pragma once | ||||
| #include <stdint.h> | ||||
| #include <gui/view.h> | ||||
| #include <gui/modules/widget.h> | ||||
| 
 | ||||
| #include <lib/nfc_protocols/mifare_classic.h> | ||||
| 
 | ||||
| typedef struct DictAttack DictAttack; | ||||
| 
 | ||||
| typedef void (*DictAttackResultCallback)(void* context); | ||||
| 
 | ||||
| DictAttack* dict_attack_alloc(); | ||||
| 
 | ||||
| void dict_attack_free(DictAttack* dict_attack); | ||||
| 
 | ||||
| void dict_attack_reset(DictAttack* dict_attack); | ||||
| 
 | ||||
| View* dict_attack_get_view(DictAttack* dict_attack); | ||||
| 
 | ||||
| void dict_attack_set_result_callback( | ||||
|     DictAttack* dict_attack, | ||||
|     DictAttackResultCallback callback, | ||||
|     void* context); | ||||
| 
 | ||||
| void dict_attack_card_detected(DictAttack* dict_attack, MfClassicType type); | ||||
| 
 | ||||
| void dict_attack_card_removed(DictAttack* dict_attack); | ||||
| 
 | ||||
| void dict_attack_inc_curr_sector(DictAttack* dict_attack); | ||||
| 
 | ||||
| void dict_attack_inc_found_key(DictAttack* dict_attack, MfClassicKey key); | ||||
| 
 | ||||
| void dict_attack_set_result(DictAttack* dict_attack, bool success); | ||||
| @ -9,7 +9,7 @@ extern "C" { | ||||
| typedef struct NotificationApp NotificationApp; | ||||
| typedef struct { | ||||
|     float frequency; | ||||
|     float pwm; | ||||
|     float volume; | ||||
| } NotificationMessageDataSound; | ||||
| 
 | ||||
| typedef struct { | ||||
|  | ||||
| @ -139,12 +139,12 @@ void notification_vibro_off() { | ||||
|     furi_hal_vibro_on(false); | ||||
| } | ||||
| 
 | ||||
| void notification_sound_on(float pwm, float freq) { | ||||
|     hal_pwm_set(pwm, freq, &SPEAKER_TIM, SPEAKER_CH); | ||||
| void notification_sound_on(float freq, float volume) { | ||||
|     furi_hal_speaker_start(freq, volume); | ||||
| } | ||||
| 
 | ||||
| void notification_sound_off() { | ||||
|     hal_pwm_stop(&SPEAKER_TIM, SPEAKER_CH); | ||||
|     furi_hal_speaker_stop(); | ||||
| } | ||||
| 
 | ||||
| // display timer
 | ||||
| @ -236,8 +236,8 @@ void notification_process_notification_message( | ||||
|             break; | ||||
|         case NotificationMessageTypeSoundOn: | ||||
|             notification_sound_on( | ||||
|                 notification_message->data.sound.pwm * speaker_volume_setting, | ||||
|                 notification_message->data.sound.frequency); | ||||
|                 notification_message->data.sound.frequency, | ||||
|                 notification_message->data.sound.volume * speaker_volume_setting); | ||||
|             reset_mask |= reset_sound_mask; | ||||
|             break; | ||||
|         case NotificationMessageTypeSoundOff: | ||||
|  | ||||
| @ -17,7 +17,7 @@ for octave in range(9): | ||||
|         print(f"const NotificationMessage message_note_{name}{octave}" + " = {\n" | ||||
|               "\t.type = NotificationMessageTypeSoundOn,\n" | ||||
|               f"\t.data.sound.frequency = {round(note, 2)}f,\n" | ||||
|               "\t.data.sound.pwm = 0.5f,\n" | ||||
|               "\t.data.sound.volume = 1.0f,\n" | ||||
|               "};") | ||||
|         note = note * cf | ||||
| 
 | ||||
| @ -29,545 +29,545 @@ for octave in range(9): | ||||
| const NotificationMessage message_click = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 1.0f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_c0 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 16.35f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_cs0 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 17.32f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_d0 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 18.35f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_ds0 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 19.45f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_e0 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 20.6f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_f0 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 21.83f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_fs0 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 23.12f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_g0 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 24.5f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_gs0 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 25.96f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_a0 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 27.5f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_as0 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 29.14f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_b0 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 30.87f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_c1 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 32.7f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_cs1 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 34.65f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_d1 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 36.71f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_ds1 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 38.89f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_e1 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 41.2f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_f1 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 43.65f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_fs1 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 46.25f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_g1 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 49.0f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_gs1 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 51.91f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_a1 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 55.0f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_as1 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 58.27f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_b1 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 61.74f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_c2 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 65.41f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_cs2 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 69.3f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_d2 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 73.42f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_ds2 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 77.78f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_e2 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 82.41f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_f2 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 87.31f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_fs2 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 92.5f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_g2 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 98.0f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_gs2 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 103.83f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_a2 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 110.0f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_as2 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 116.54f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_b2 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 123.47f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_c3 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 130.81f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_cs3 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 138.59f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_d3 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 146.83f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_ds3 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 155.56f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_e3 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 164.81f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_f3 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 174.61f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_fs3 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 185.0f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_g3 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 196.0f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_gs3 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 207.65f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_a3 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 220.0f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_as3 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 233.08f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_b3 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 246.94f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_c4 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 261.63f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_cs4 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 277.18f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_d4 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 293.66f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_ds4 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 311.13f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_e4 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 329.63f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_f4 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 349.23f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_fs4 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 369.99f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_g4 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 392.0f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_gs4 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 415.3f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_a4 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 440.0f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_as4 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 466.16f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_b4 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 493.88f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_c5 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 523.25f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_cs5 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 554.37f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_d5 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 587.33f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_ds5 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 622.25f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_e5 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 659.26f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_f5 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 698.46f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_fs5 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 739.99f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_g5 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 783.99f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_gs5 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 830.61f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_a5 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 880.0f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_as5 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 932.33f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_b5 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 987.77f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_c6 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 1046.5f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_cs6 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 1108.73f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_d6 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 1174.66f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_ds6 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 1244.51f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_e6 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 1318.51f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_f6 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 1396.91f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_fs6 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 1479.98f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_g6 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 1567.98f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_gs6 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 1661.22f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_a6 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 1760.0f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_as6 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 1864.66f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_b6 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 1975.53f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_c7 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 2093.0f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_cs7 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 2217.46f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_d7 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 2349.32f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_ds7 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 2489.02f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_e7 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 2637.02f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_f7 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 2793.83f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_fs7 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 2959.96f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_g7 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 3135.96f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_gs7 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 3322.44f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_a7 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 3520.0f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_as7 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 3729.31f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_b7 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 3951.07f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_c8 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 4186.01f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_cs8 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 4434.92f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_d8 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 4698.64f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_ds8 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 4978.03f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_e8 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 5274.04f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_f8 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 5587.65f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_fs8 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 5919.91f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_g8 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 6271.93f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_gs8 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 6644.88f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_a8 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 7040.0f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_as8 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 7458.62f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
| const NotificationMessage message_note_b8 = { | ||||
|     .type = NotificationMessageTypeSoundOn, | ||||
|     .data.sound.frequency = 7902.13f, | ||||
|     .data.sound.pwm = 0.5f, | ||||
|     .data.sound.volume = 1.0f, | ||||
| }; | ||||
|  | ||||
| @ -43,7 +43,7 @@ const char* const volume_text[VOLUME_COUNT] = { | ||||
|     "75%", | ||||
|     "100%", | ||||
| }; | ||||
| const float volume_value[VOLUME_COUNT] = {0.0f, 0.04f, 0.1f, 0.2f, 1.0f}; | ||||
| const float volume_value[VOLUME_COUNT] = {0.0f, 0.25f, 0.5f, 0.75f, 1.0f}; | ||||
| 
 | ||||
| #define DELAY_COUNT 6 | ||||
| const char* const delay_text[DELAY_COUNT] = { | ||||
|  | ||||
| @ -26,6 +26,10 @@ static const char* test_float_key = "Float data"; | ||||
| static const float test_float_data[] = {1.5f, 1000.0f}; | ||||
| static const float test_float_updated_data[] = {1.2f}; | ||||
| 
 | ||||
| static const char* test_bool_key = "Bool data"; | ||||
| static const bool test_bool_data[] = {true, false}; | ||||
| static const bool test_bool_updated_data[] = {false, true, true}; | ||||
| 
 | ||||
| static const char* test_hex_key = "Hex data"; | ||||
| static const uint8_t test_hex_data[] = {0xDE, 0xAD, 0xBE}; | ||||
| static const uint8_t test_hex_updated_data[] = {0xFE, 0xCA}; | ||||
| @ -38,6 +42,7 @@ static const char* test_data_nix = "Filetype: Flipper File test\n" | ||||
|                                    "Int32 data: 1234 -6345 7813 0\n" | ||||
|                                    "Uint32 data: 1234 0 5678 9098 7654321\n" | ||||
|                                    "Float data: 1.5 1000.0\n" | ||||
|                                    "Bool data: true false\n" | ||||
|                                    "Hex data: DE AD BE"; | ||||
| 
 | ||||
| #define READ_TEST_WIN "ff_win.test" | ||||
| @ -48,6 +53,7 @@ static const char* test_data_win = "Filetype: Flipper File test\r\n" | ||||
|                                    "Int32 data: 1234 -6345 7813 0\r\n" | ||||
|                                    "Uint32 data: 1234 0 5678 9098 7654321\r\n" | ||||
|                                    "Float data: 1.5 1000.0\r\n" | ||||
|                                    "Bool data: true false\r\n" | ||||
|                                    "Hex data: DE AD BE"; | ||||
| 
 | ||||
| #define READ_TEST_FLP "ff_flp.test" | ||||
| @ -129,6 +135,11 @@ static bool test_read(const char* file_name) { | ||||
|         if(memcmp(scratchpad, test_float_data, sizeof(float) * COUNT_OF(test_float_data)) != 0) | ||||
|             break; | ||||
| 
 | ||||
|         if(!flipper_format_get_value_count(file, test_bool_key, &uint32_value)) break; | ||||
|         if(uint32_value != COUNT_OF(test_bool_data)) break; | ||||
|         if(!flipper_format_read_bool(file, test_bool_key, scratchpad, uint32_value)) break; | ||||
|         if(memcmp(scratchpad, test_bool_data, sizeof(bool) * COUNT_OF(test_bool_data)) != 0) break; | ||||
| 
 | ||||
|         if(!flipper_format_get_value_count(file, test_hex_key, &uint32_value)) break; | ||||
|         if(uint32_value != COUNT_OF(test_hex_data)) break; | ||||
|         if(!flipper_format_read_hex(file, test_hex_key, scratchpad, uint32_value)) break; | ||||
| @ -195,6 +206,15 @@ static bool test_read_updated(const char* file_name) { | ||||
|                sizeof(float) * COUNT_OF(test_float_updated_data)) != 0) | ||||
|             break; | ||||
| 
 | ||||
|         if(!flipper_format_get_value_count(file, test_bool_key, &uint32_value)) break; | ||||
|         if(uint32_value != COUNT_OF(test_bool_updated_data)) break; | ||||
|         if(!flipper_format_read_bool(file, test_bool_key, scratchpad, uint32_value)) break; | ||||
|         if(memcmp( | ||||
|                scratchpad, | ||||
|                test_bool_updated_data, | ||||
|                sizeof(bool) * COUNT_OF(test_bool_updated_data)) != 0) | ||||
|             break; | ||||
| 
 | ||||
|         if(!flipper_format_get_value_count(file, test_hex_key, &uint32_value)) break; | ||||
|         if(uint32_value != COUNT_OF(test_hex_updated_data)) break; | ||||
|         if(!flipper_format_read_hex(file, test_hex_key, scratchpad, uint32_value)) break; | ||||
| @ -235,6 +255,9 @@ static bool test_write(const char* file_name) { | ||||
|         if(!flipper_format_write_float( | ||||
|                file, test_float_key, test_float_data, COUNT_OF(test_float_data))) | ||||
|             break; | ||||
|         if(!flipper_format_write_bool( | ||||
|                file, test_bool_key, test_bool_data, COUNT_OF(test_bool_data))) | ||||
|             break; | ||||
|         if(!flipper_format_write_hex(file, test_hex_key, test_hex_data, COUNT_OF(test_hex_data))) | ||||
|             break; | ||||
|         result = true; | ||||
| @ -299,6 +322,9 @@ static bool test_update(const char* file_name) { | ||||
|         if(!flipper_format_update_float( | ||||
|                file, test_float_key, test_float_updated_data, COUNT_OF(test_float_updated_data))) | ||||
|             break; | ||||
|         if(!flipper_format_update_bool( | ||||
|                file, test_bool_key, test_bool_updated_data, COUNT_OF(test_bool_updated_data))) | ||||
|             break; | ||||
|         if(!flipper_format_update_hex( | ||||
|                file, test_hex_key, test_hex_updated_data, COUNT_OF(test_hex_updated_data))) | ||||
|             break; | ||||
| @ -328,6 +354,9 @@ static bool test_update_backward(const char* file_name) { | ||||
|         if(!flipper_format_update_float( | ||||
|                file, test_float_key, test_float_data, COUNT_OF(test_float_data))) | ||||
|             break; | ||||
|         if(!flipper_format_update_bool( | ||||
|                file, test_bool_key, test_bool_data, COUNT_OF(test_bool_data))) | ||||
|             break; | ||||
|         if(!flipper_format_update_hex(file, test_hex_key, test_hex_data, COUNT_OF(test_hex_data))) | ||||
|             break; | ||||
| 
 | ||||
|  | ||||
| @ -191,7 +191,7 @@ static int32_t u2f_hid_worker(void* context) { | ||||
|     FURI_LOG_D(WORKER_TAG, "Init"); | ||||
| 
 | ||||
|     FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); | ||||
|     furi_hal_usb_set_config(&usb_hid_u2f); | ||||
|     furi_hal_usb_set_config(&usb_hid_u2f, NULL); | ||||
| 
 | ||||
|     u2f_hid->lock_timer = osTimerNew(u2f_hid_lock_timeout_callback, osTimerOnce, u2f_hid, NULL); | ||||
| 
 | ||||
| @ -270,7 +270,7 @@ static int32_t u2f_hid_worker(void* context) { | ||||
|     osTimerDelete(u2f_hid->lock_timer); | ||||
| 
 | ||||
|     furi_hal_hid_u2f_set_callback(NULL, NULL); | ||||
|     furi_hal_usb_set_config(usb_mode_prev); | ||||
|     furi_hal_usb_set_config(usb_mode_prev, NULL); | ||||
|     FURI_LOG_D(WORKER_TAG, "End"); | ||||
| 
 | ||||
|     return 0; | ||||
|  | ||||
| @ -1,3 +1,3 @@ | ||||
| #pragma once | ||||
| #define PROTOBUF_MAJOR_VERSION 0 | ||||
| #define PROTOBUF_MINOR_VERSION 1 | ||||
| #define PROTOBUF_MINOR_VERSION 2 | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| Subproject commit 93b9cf3af76664a27646494341a63281a9022740 | ||||
| Subproject commit 232e7e9a50b12a95f950fabb515204775e51b04a | ||||
| @ -1,3 +1,7 @@ | ||||
| ID 1234:5678 Apple:Keyboard | ||||
| REM You can change these values to VID/PID of original Apple keyboard | ||||
| REM to bypass Keyboard Setup Assistant | ||||
| 
 | ||||
| REM This is BadUSB demo script for macOS | ||||
| 
 | ||||
| REM Open terminal window | ||||
|  | ||||
							
								
								
									
										1311
									
								
								assets/resources/nfc/assets/mf_classic_dict.nfc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1311
									
								
								assets/resources/nfc/assets/mf_classic_dict.nfc
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,21 +0,0 @@ | ||||
| #include <furi_hal.h> | ||||
| #include <stm32wbxx_ll_utils.h> | ||||
| 
 | ||||
| void furi_hal_init() { | ||||
|     furi_hal_i2c_init(); | ||||
|     furi_hal_light_init(); | ||||
|     furi_hal_spi_init(); | ||||
|     furi_hal_version_init(); | ||||
| } | ||||
| 
 | ||||
| void delay(float milliseconds) { | ||||
|     LL_mDelay((uint32_t)milliseconds); | ||||
| } | ||||
| 
 | ||||
| void delay_us(float microseconds) { | ||||
|     microseconds = microseconds / 1000; | ||||
|     if(microseconds < 1) { | ||||
|         microseconds = 1; | ||||
|     } | ||||
|     LL_mDelay((uint32_t)microseconds); | ||||
| } | ||||
| @ -1,215 +0,0 @@ | ||||
| #include <furi_hal_gpio.h> | ||||
| #include <stddef.h> | ||||
| #include <assert.h> | ||||
| 
 | ||||
| #define GET_SYSCFG_EXTI_PORT(gpio)                \ | ||||
|     (((gpio) == (GPIOA)) ? LL_SYSCFG_EXTI_PORTA : \ | ||||
|      ((gpio) == (GPIOB)) ? LL_SYSCFG_EXTI_PORTB : \ | ||||
|      ((gpio) == (GPIOC)) ? LL_SYSCFG_EXTI_PORTC : \ | ||||
|      ((gpio) == (GPIOD)) ? LL_SYSCFG_EXTI_PORTD : \ | ||||
|      ((gpio) == (GPIOE)) ? LL_SYSCFG_EXTI_PORTE : \ | ||||
|                            LL_SYSCFG_EXTI_PORTH) | ||||
| 
 | ||||
| #define GPIO_PIN_MAP(pin, prefix)               \ | ||||
|     (((pin) == (LL_GPIO_PIN_0))  ? prefix##0 :  \ | ||||
|      ((pin) == (LL_GPIO_PIN_1))  ? prefix##1 :  \ | ||||
|      ((pin) == (LL_GPIO_PIN_2))  ? prefix##2 :  \ | ||||
|      ((pin) == (LL_GPIO_PIN_3))  ? prefix##3 :  \ | ||||
|      ((pin) == (LL_GPIO_PIN_4))  ? prefix##4 :  \ | ||||
|      ((pin) == (LL_GPIO_PIN_5))  ? prefix##5 :  \ | ||||
|      ((pin) == (LL_GPIO_PIN_6))  ? prefix##6 :  \ | ||||
|      ((pin) == (LL_GPIO_PIN_7))  ? prefix##7 :  \ | ||||
|      ((pin) == (LL_GPIO_PIN_8))  ? prefix##8 :  \ | ||||
|      ((pin) == (LL_GPIO_PIN_9))  ? prefix##9 :  \ | ||||
|      ((pin) == (LL_GPIO_PIN_10)) ? prefix##10 : \ | ||||
|      ((pin) == (LL_GPIO_PIN_11)) ? prefix##11 : \ | ||||
|      ((pin) == (LL_GPIO_PIN_12)) ? prefix##12 : \ | ||||
|      ((pin) == (LL_GPIO_PIN_13)) ? prefix##13 : \ | ||||
|      ((pin) == (LL_GPIO_PIN_14)) ? prefix##14 : \ | ||||
|                                    prefix##15) | ||||
| 
 | ||||
| #define GET_SYSCFG_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_SYSCFG_EXTI_LINE) | ||||
| #define GET_EXTI_LINE(pin) GPIO_PIN_MAP(pin, LL_EXTI_LINE_) | ||||
| 
 | ||||
| static volatile GpioInterrupt gpio_interrupt[GPIO_NUMBER]; | ||||
| 
 | ||||
| static uint8_t hal_gpio_get_pin_num(const GpioPin* gpio) { | ||||
|     uint8_t pin_num = 0; | ||||
|     for(pin_num = 0; pin_num < GPIO_NUMBER; pin_num++) { | ||||
|         if(gpio->pin & (1 << pin_num)) break; | ||||
|     } | ||||
|     return pin_num; | ||||
| } | ||||
| 
 | ||||
| void hal_gpio_init_simple(const GpioPin* gpio, const GpioMode mode) { | ||||
|     hal_gpio_init(gpio, mode, GpioPullNo, GpioSpeedLow); | ||||
| } | ||||
| 
 | ||||
| void hal_gpio_init( | ||||
|     const GpioPin* gpio, | ||||
|     const GpioMode mode, | ||||
|     const GpioPull pull, | ||||
|     const GpioSpeed speed) { | ||||
|     // we cannot set alternate mode in this function
 | ||||
|     assert(mode != GpioModeAltFunctionPushPull); | ||||
|     assert(mode != GpioModeAltFunctionOpenDrain); | ||||
| 
 | ||||
|     hal_gpio_init_ex(gpio, mode, pull, speed, GpioAltFnUnused); | ||||
| } | ||||
| 
 | ||||
| void hal_gpio_init_ex( | ||||
|     const GpioPin* gpio, | ||||
|     const GpioMode mode, | ||||
|     const GpioPull pull, | ||||
|     const GpioSpeed speed, | ||||
|     const GpioAltFn alt_fn) { | ||||
|     uint32_t sys_exti_port = GET_SYSCFG_EXTI_PORT(gpio->port); | ||||
|     uint32_t sys_exti_line = GET_SYSCFG_EXTI_LINE(gpio->pin); | ||||
|     uint32_t exti_line = GET_EXTI_LINE(gpio->pin); | ||||
| 
 | ||||
|     // Configure gpio with interrupts disabled
 | ||||
|     __disable_irq(); | ||||
| 
 | ||||
|     // Set gpio speed
 | ||||
|     switch(speed) { | ||||
|     case GpioSpeedLow: | ||||
|         LL_GPIO_SetPinSpeed(gpio->port, gpio->pin, LL_GPIO_SPEED_FREQ_LOW); | ||||
|         break; | ||||
|     case GpioSpeedMedium: | ||||
|         LL_GPIO_SetPinSpeed(gpio->port, gpio->pin, LL_GPIO_SPEED_FREQ_MEDIUM); | ||||
|         break; | ||||
|     case GpioSpeedHigh: | ||||
|         LL_GPIO_SetPinSpeed(gpio->port, gpio->pin, LL_GPIO_SPEED_FREQ_HIGH); | ||||
|         break; | ||||
|     case GpioSpeedVeryHigh: | ||||
|         LL_GPIO_SetPinSpeed(gpio->port, gpio->pin, LL_GPIO_SPEED_FREQ_VERY_HIGH); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     // Set gpio pull mode
 | ||||
|     switch(pull) { | ||||
|     case GpioPullNo: | ||||
|         LL_GPIO_SetPinPull(gpio->port, gpio->pin, LL_GPIO_PULL_NO); | ||||
|         break; | ||||
|     case GpioPullUp: | ||||
|         LL_GPIO_SetPinPull(gpio->port, gpio->pin, LL_GPIO_PULL_UP); | ||||
|         break; | ||||
|     case GpioPullDown: | ||||
|         LL_GPIO_SetPinPull(gpio->port, gpio->pin, LL_GPIO_PULL_DOWN); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     // Set gpio mode
 | ||||
|     if(mode >= GpioModeInterruptRise) { | ||||
|         // Set pin in interrupt mode
 | ||||
|         LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_INPUT); | ||||
|         LL_SYSCFG_SetEXTISource(sys_exti_port, sys_exti_line); | ||||
|         if(mode == GpioModeInterruptRise || mode == GpioModeInterruptRiseFall) { | ||||
|             LL_EXTI_EnableIT_0_31(exti_line); | ||||
|             LL_EXTI_EnableRisingTrig_0_31(exti_line); | ||||
|         } | ||||
|         if(mode == GpioModeInterruptFall || mode == GpioModeInterruptRiseFall) { | ||||
|             LL_EXTI_EnableIT_0_31(exti_line); | ||||
|             LL_EXTI_EnableFallingTrig_0_31(exti_line); | ||||
|         } | ||||
|         if(mode == GpioModeEventRise || mode == GpioModeEventRiseFall) { | ||||
|             LL_EXTI_EnableEvent_0_31(exti_line); | ||||
|             LL_EXTI_EnableRisingTrig_0_31(exti_line); | ||||
|         } | ||||
|         if(mode == GpioModeEventFall || mode == GpioModeEventRiseFall) { | ||||
|             LL_EXTI_EnableEvent_0_31(exti_line); | ||||
|             LL_EXTI_EnableFallingTrig_0_31(exti_line); | ||||
|         } | ||||
|     } else { | ||||
|         // Disable interrupts if set
 | ||||
|         if(LL_SYSCFG_GetEXTISource(sys_exti_line) == sys_exti_port && | ||||
|            LL_EXTI_IsEnabledIT_0_31(exti_line)) { | ||||
|             LL_EXTI_DisableIT_0_31(exti_line); | ||||
|             LL_EXTI_DisableRisingTrig_0_31(exti_line); | ||||
|             LL_EXTI_DisableFallingTrig_0_31(exti_line); | ||||
|         } | ||||
| 
 | ||||
|         // Prepare alternative part if any
 | ||||
|         if(mode == GpioModeAltFunctionPushPull || mode == GpioModeAltFunctionOpenDrain) { | ||||
|             // set alternate function
 | ||||
|             if(hal_gpio_get_pin_num(gpio) < 8) { | ||||
|                 LL_GPIO_SetAFPin_0_7(gpio->port, gpio->pin, alt_fn); | ||||
|             } else { | ||||
|                 LL_GPIO_SetAFPin_8_15(gpio->port, gpio->pin, alt_fn); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Set not interrupt pin modes
 | ||||
|         switch(mode) { | ||||
|         case GpioModeInput: | ||||
|             LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_INPUT); | ||||
|             break; | ||||
|         case GpioModeOutputPushPull: | ||||
|             LL_GPIO_SetPinOutputType(gpio->port, gpio->pin, LL_GPIO_OUTPUT_PUSHPULL); | ||||
|             LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_OUTPUT); | ||||
|             break; | ||||
|         case GpioModeAltFunctionPushPull: | ||||
|             LL_GPIO_SetPinOutputType(gpio->port, gpio->pin, LL_GPIO_OUTPUT_PUSHPULL); | ||||
|             LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ALTERNATE); | ||||
|             break; | ||||
|         case GpioModeOutputOpenDrain: | ||||
|             LL_GPIO_SetPinOutputType(gpio->port, gpio->pin, LL_GPIO_OUTPUT_OPENDRAIN); | ||||
|             LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_OUTPUT); | ||||
|             break; | ||||
|         case GpioModeAltFunctionOpenDrain: | ||||
|             LL_GPIO_SetPinOutputType(gpio->port, gpio->pin, LL_GPIO_OUTPUT_OPENDRAIN); | ||||
|             LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ALTERNATE); | ||||
|             break; | ||||
|         case GpioModeAnalog: | ||||
|             LL_GPIO_SetPinMode(gpio->port, gpio->pin, LL_GPIO_MODE_ANALOG); | ||||
|             break; | ||||
|         default: | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     __enable_irq(); | ||||
| } | ||||
| 
 | ||||
| void hal_gpio_add_int_callback(const GpioPin* gpio, GpioExtiCallback cb, void* ctx) { | ||||
|     assert(gpio); | ||||
|     assert(cb); | ||||
| 
 | ||||
|     __disable_irq(); | ||||
|     uint8_t pin_num = hal_gpio_get_pin_num(gpio); | ||||
|     gpio_interrupt[pin_num].callback = cb; | ||||
|     gpio_interrupt[pin_num].context = ctx; | ||||
|     gpio_interrupt[pin_num].ready = true; | ||||
|     __enable_irq(); | ||||
| } | ||||
| 
 | ||||
| void hal_gpio_enable_int_callback(const GpioPin* gpio) { | ||||
|     assert(gpio); | ||||
| 
 | ||||
|     __disable_irq(); | ||||
|     uint8_t pin_num = hal_gpio_get_pin_num(gpio); | ||||
|     if(gpio_interrupt[pin_num].callback) { | ||||
|         gpio_interrupt[pin_num].ready = true; | ||||
|     } | ||||
|     __enable_irq(); | ||||
| } | ||||
| 
 | ||||
| void hal_gpio_disable_int_callback(const GpioPin* gpio) { | ||||
|     assert(gpio); | ||||
| 
 | ||||
|     __disable_irq(); | ||||
|     uint8_t pin_num = hal_gpio_get_pin_num(gpio); | ||||
|     gpio_interrupt[pin_num].ready = false; | ||||
|     __enable_irq(); | ||||
| } | ||||
| 
 | ||||
| void hal_gpio_remove_int_callback(const GpioPin* gpio) { | ||||
|     assert(gpio); | ||||
| 
 | ||||
|     __disable_irq(); | ||||
|     uint8_t pin_num = hal_gpio_get_pin_num(gpio); | ||||
|     gpio_interrupt[pin_num].callback = NULL; | ||||
|     gpio_interrupt[pin_num].context = NULL; | ||||
|     gpio_interrupt[pin_num].ready = false; | ||||
|     __enable_irq(); | ||||
| } | ||||
| @ -1,264 +0,0 @@ | ||||
| #pragma once | ||||
| #include "main.h" | ||||
| #include "stdbool.h" | ||||
| #include <stm32wbxx_ll_gpio.h> | ||||
| #include <stm32wbxx_ll_system.h> | ||||
| #include <stm32wbxx_ll_exti.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /**
 | ||||
|  * Number of gpio on one port | ||||
|  */ | ||||
| #define GPIO_NUMBER (16U) | ||||
| 
 | ||||
| /**
 | ||||
|  * Interrupt callback prototype | ||||
|  */ | ||||
| typedef void (*GpioExtiCallback)(void* ctx); | ||||
| 
 | ||||
| /**
 | ||||
|  * Gpio interrupt type | ||||
|  */ | ||||
| typedef struct { | ||||
|     GpioExtiCallback callback; | ||||
|     void* context; | ||||
|     volatile bool ready; | ||||
| } GpioInterrupt; | ||||
| 
 | ||||
| /**
 | ||||
|  * Gpio modes | ||||
|  */ | ||||
| typedef enum { | ||||
|     GpioModeInput, | ||||
|     GpioModeOutputPushPull, | ||||
|     GpioModeOutputOpenDrain, | ||||
|     GpioModeAltFunctionPushPull, | ||||
|     GpioModeAltFunctionOpenDrain, | ||||
|     GpioModeAnalog, | ||||
|     GpioModeInterruptRise, | ||||
|     GpioModeInterruptFall, | ||||
|     GpioModeInterruptRiseFall, | ||||
|     GpioModeEventRise, | ||||
|     GpioModeEventFall, | ||||
|     GpioModeEventRiseFall, | ||||
| } GpioMode; | ||||
| 
 | ||||
| /**
 | ||||
|  * Gpio pull modes | ||||
|  */ | ||||
| typedef enum { | ||||
|     GpioPullNo, | ||||
|     GpioPullUp, | ||||
|     GpioPullDown, | ||||
| } GpioPull; | ||||
| 
 | ||||
| /**
 | ||||
|  * Gpio speed modes | ||||
|  */ | ||||
| typedef enum { | ||||
|     GpioSpeedLow, | ||||
|     GpioSpeedMedium, | ||||
|     GpioSpeedHigh, | ||||
|     GpioSpeedVeryHigh, | ||||
| } GpioSpeed; | ||||
| 
 | ||||
| /**
 | ||||
|  * Gpio alternate functions | ||||
|  */ | ||||
| typedef enum { | ||||
|     GpioAltFn0MCO = 0, /*!< MCO Alternate Function mapping */ | ||||
|     GpioAltFn0LSCO = 0, /*!< LSCO Alternate Function mapping */ | ||||
|     GpioAltFn0JTMS_SWDIO = 0, /*!< JTMS-SWDIO Alternate Function mapping */ | ||||
|     GpioAltFn0JTCK_SWCLK = 0, /*!< JTCK-SWCLK Alternate Function mapping */ | ||||
|     GpioAltFn0JTDI = 0, /*!< JTDI Alternate Function mapping */ | ||||
|     GpioAltFn0RTC_OUT = 0, /*!< RCT_OUT Alternate Function mapping */ | ||||
|     GpioAltFn0JTD_TRACE = 0, /*!< JTDO-TRACESWO Alternate Function mapping */ | ||||
|     GpioAltFn0NJTRST = 0, /*!< NJTRST Alternate Function mapping */ | ||||
|     GpioAltFn0RTC_REFIN = 0, /*!< RTC_REFIN Alternate Function mapping */ | ||||
|     GpioAltFn0TRACED0 = 0, /*!< TRACED0 Alternate Function mapping */ | ||||
|     GpioAltFn0TRACED1 = 0, /*!< TRACED1 Alternate Function mapping */ | ||||
|     GpioAltFn0TRACED2 = 0, /*!< TRACED2 Alternate Function mapping */ | ||||
|     GpioAltFn0TRACED3 = 0, /*!< TRACED3 Alternate Function mapping */ | ||||
|     GpioAltFn0TRIG_INOUT = 0, /*!< TRIG_INOUT Alternate Function mapping */ | ||||
|     GpioAltFn0TRACECK = 0, /*!< TRACECK Alternate Function mapping */ | ||||
|     GpioAltFn0SYS = 0, /*!< System Function mapping */ | ||||
| 
 | ||||
|     GpioAltFn1TIM1 = 1, /*!< TIM1 Alternate Function mapping */ | ||||
|     GpioAltFn1TIM2 = 1, /*!< TIM2 Alternate Function mapping */ | ||||
|     GpioAltFn1LPTIM1 = 1, /*!< LPTIM1 Alternate Function mapping */ | ||||
| 
 | ||||
|     GpioAltFn2TIM2 = 2, /*!< TIM2 Alternate Function mapping */ | ||||
|     GpioAltFn2TIM1 = 2, /*!< TIM1 Alternate Function mapping */ | ||||
| 
 | ||||
|     GpioAltFn3SAI1 = 3, /*!< SAI1_CK1 Alternate Function mapping */ | ||||
|     GpioAltFn3SPI2 = 3, /*!< SPI2 Alternate Function mapping */ | ||||
|     GpioAltFn3TIM1 = 3, /*!< TIM1 Alternate Function mapping */ | ||||
| 
 | ||||
|     GpioAltFn4I2C1 = 4, /*!< I2C1 Alternate Function mapping */ | ||||
|     GpioAltFn4I2C3 = 4, /*!< I2C3 Alternate Function mapping */ | ||||
| 
 | ||||
|     GpioAltFn5SPI1 = 5, /*!< SPI1 Alternate Function mapping */ | ||||
|     GpioAltFn5SPI2 = 5, /*!< SPI2 Alternate Function mapping */ | ||||
| 
 | ||||
|     GpioAltFn6MCO = 6, /*!< MCO Alternate Function mapping */ | ||||
|     GpioAltFn6LSCO = 6, /*!< LSCO Alternate Function mapping */ | ||||
|     GpioAltFn6RF_DTB0 = 6, /*!< RF_DTB0 Alternate Function mapping */ | ||||
|     GpioAltFn6RF_DTB1 = 6, /*!< RF_DTB1 Alternate Function mapping */ | ||||
|     GpioAltFn6RF_DTB2 = 6, /*!< RF_DTB2 Alternate Function mapping */ | ||||
|     GpioAltFn6RF_DTB3 = 6, /*!< RF_DTB3 Alternate Function mapping */ | ||||
|     GpioAltFn6RF_DTB4 = 6, /*!< RF_DTB4 Alternate Function mapping */ | ||||
|     GpioAltFn6RF_DTB5 = 6, /*!< RF_DTB5 Alternate Function mapping */ | ||||
|     GpioAltFn6RF_DTB6 = 6, /*!< RF_DTB6 Alternate Function mapping */ | ||||
|     GpioAltFn6RF_DTB7 = 6, /*!< RF_DTB7 Alternate Function mapping */ | ||||
|     GpioAltFn6RF_DTB8 = 6, /*!< RF_DTB8 Alternate Function mapping */ | ||||
|     GpioAltFn6RF_DTB9 = 6, /*!< RF_DTB9 Alternate Function mapping */ | ||||
|     GpioAltFn6RF_DTB10 = 6, /*!< RF_DTB10 Alternate Function mapping */ | ||||
|     GpioAltFn6RF_DTB11 = 6, /*!< RF_DTB11 Alternate Function mapping */ | ||||
|     GpioAltFn6RF_DTB12 = 6, /*!< RF_DTB12 Alternate Function mapping */ | ||||
|     GpioAltFn6RF_DTB13 = 6, /*!< RF_DTB13 Alternate Function mapping */ | ||||
|     GpioAltFn6RF_DTB14 = 6, /*!< RF_DTB14 Alternate Function mapping */ | ||||
|     GpioAltFn6RF_DTB15 = 6, /*!< RF_DTB15 Alternate Function mapping */ | ||||
|     GpioAltFn6RF_DTB16 = 6, /*!< RF_DTB16 Alternate Function mapping */ | ||||
|     GpioAltFn6RF_DTB17 = 6, /*!< RF_DTB17 Alternate Function mapping */ | ||||
|     GpioAltFn6RF_DTB18 = 6, /*!< RF_DTB18 Alternate Function mapping */ | ||||
|     GpioAltFn6RF_MISO = 6, /*!< RF_MISO Alternate Function mapping */ | ||||
|     GpioAltFn6RF_MOSI = 6, /*!< RF_MOSI Alternate Function mapping */ | ||||
|     GpioAltFn6RF_SCK = 6, /*!< RF_SCK Alternate Function mapping */ | ||||
|     GpioAltFn6RF_NSS = 6, /*!< RF_NSS Alternate Function mapping */ | ||||
| 
 | ||||
|     GpioAltFn7USART1 = 7, /*!< USART1 Alternate Function mapping */ | ||||
| 
 | ||||
|     GpioAltFn8LPUART1 = 8, /*!< LPUART1 Alternate Function mapping */ | ||||
|     GpioAltFn8IR = 8, /*!< IR Alternate Function mapping */ | ||||
| 
 | ||||
|     GpioAltFn9TSC = 9, /*!< TSC Alternate Function mapping */ | ||||
| 
 | ||||
|     GpioAltFn10QUADSPI = 10, /*!< QUADSPI Alternate Function mapping */ | ||||
|     GpioAltFn10USB = 10, /*!< USB Alternate Function mapping */ | ||||
| 
 | ||||
|     GpioAltFn11LCD = 11, /*!< LCD Alternate Function mapping */ | ||||
| 
 | ||||
|     GpioAltFn12COMP1 = 12, /*!< COMP1 Alternate Function mapping */ | ||||
|     GpioAltFn12COMP2 = 12, /*!< COMP2 Alternate Function mapping */ | ||||
|     GpioAltFn12TIM1 = 12, /*!< TIM1 Alternate Function mapping */ | ||||
| 
 | ||||
|     GpioAltFn13SAI1 = 13, /*!< SAI1 Alternate Function mapping */ | ||||
| 
 | ||||
|     GpioAltFn14TIM2 = 14, /*!< TIM2 Alternate Function mapping */ | ||||
|     GpioAltFn14TIM16 = 14, /*!< TIM16 Alternate Function mapping */ | ||||
|     GpioAltFn14TIM17 = 14, /*!< TIM17 Alternate Function mapping */ | ||||
|     GpioAltFn14LPTIM2 = 14, /*!< LPTIM2 Alternate Function mapping */ | ||||
| 
 | ||||
|     GpioAltFn15EVENTOUT = 15, /*!< EVENTOUT Alternate Function mapping */ | ||||
| 
 | ||||
|     GpioAltFnUnused = 16, /*!< just dummy value */ | ||||
| } GpioAltFn; | ||||
| 
 | ||||
| /**
 | ||||
|  * Gpio structure | ||||
|  */ | ||||
| typedef struct { | ||||
|     GPIO_TypeDef* port; | ||||
|     uint16_t pin; | ||||
| } GpioPin; | ||||
| 
 | ||||
| /**
 | ||||
|  * GPIO initialization function, simple version | ||||
|  * @param gpio  GpioPin | ||||
|  * @param mode  GpioMode | ||||
|  */ | ||||
| void hal_gpio_init_simple(const GpioPin* gpio, const GpioMode mode); | ||||
| 
 | ||||
| /**
 | ||||
|  * GPIO initialization function, normal version | ||||
|  * @param gpio  GpioPin | ||||
|  * @param mode  GpioMode | ||||
|  * @param pull  GpioPull | ||||
|  * @param speed GpioSpeed | ||||
|  */ | ||||
| void hal_gpio_init( | ||||
|     const GpioPin* gpio, | ||||
|     const GpioMode mode, | ||||
|     const GpioPull pull, | ||||
|     const GpioSpeed speed); | ||||
| 
 | ||||
| /**
 | ||||
|  * GPIO initialization function, extended version | ||||
|  * @param gpio  GpioPin | ||||
|  * @param mode  GpioMode | ||||
|  * @param pull  GpioPull | ||||
|  * @param speed GpioSpeed | ||||
|  * @param alt_fn GpioAltFn | ||||
|  */ | ||||
| void hal_gpio_init_ex( | ||||
|     const GpioPin* gpio, | ||||
|     const GpioMode mode, | ||||
|     const GpioPull pull, | ||||
|     const GpioSpeed speed, | ||||
|     const GpioAltFn alt_fn); | ||||
| 
 | ||||
| /**
 | ||||
|  * Add and enable interrupt | ||||
|  * @param gpio GpioPin | ||||
|  * @param cb   GpioExtiCallback | ||||
|  * @param ctx  context for callback | ||||
|  */ | ||||
| void hal_gpio_add_int_callback(const GpioPin* gpio, GpioExtiCallback cb, void* ctx); | ||||
| 
 | ||||
| /**
 | ||||
|  * Enable interrupt | ||||
|  * @param gpio GpioPin | ||||
|  */ | ||||
| void hal_gpio_enable_int_callback(const GpioPin* gpio); | ||||
| 
 | ||||
| /**
 | ||||
|  * Disable interrupt | ||||
|  * @param gpio GpioPin | ||||
|  */ | ||||
| void hal_gpio_disable_int_callback(const GpioPin* gpio); | ||||
| 
 | ||||
| /**
 | ||||
|  * Remove interrupt | ||||
|  * @param gpio GpioPin | ||||
|  */ | ||||
| void hal_gpio_remove_int_callback(const GpioPin* gpio); | ||||
| 
 | ||||
| /**
 | ||||
|  * GPIO write pin | ||||
|  * @param gpio  GpioPin | ||||
|  * @param state true / false | ||||
|  */ | ||||
| static inline void hal_gpio_write(const GpioPin* gpio, const bool state) { | ||||
|     // writing to BSSR is an atomic operation
 | ||||
|     if(state == true) { | ||||
|         gpio->port->BSRR = gpio->pin; | ||||
|     } else { | ||||
|         gpio->port->BSRR = (uint32_t)gpio->pin << GPIO_NUMBER; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * GPIO read pin | ||||
|  * @param gpio GpioPin | ||||
|  * @return true / false | ||||
|  */ | ||||
| static inline bool hal_gpio_read(const GpioPin* gpio) { | ||||
|     if((gpio->port->IDR & gpio->pin) != 0x00U) { | ||||
|         return true; | ||||
|     } else { | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Get RFID IN level | ||||
|  * @return false = LOW, true = HIGH | ||||
|  */ | ||||
| bool hal_gpio_get_rfid_in_level(); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -1,205 +0,0 @@ | ||||
| #include <furi_hal_i2c.h> | ||||
| #include <furi_hal_version.h> | ||||
| 
 | ||||
| #include <stm32wbxx_ll_i2c.h> | ||||
| #include <stm32wbxx_ll_gpio.h> | ||||
| #include <stm32wbxx_ll_cortex.h> | ||||
| 
 | ||||
| #include <assert.h> | ||||
| 
 | ||||
| void furi_hal_i2c_init() { | ||||
|     furi_hal_i2c_bus_power.callback(&furi_hal_i2c_bus_power, FuriHalI2cBusEventInit); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle) { | ||||
|     handle->bus->callback(handle->bus, FuriHalI2cBusEventLock); | ||||
| 
 | ||||
|     assert(handle->bus->current_handle == NULL); | ||||
| 
 | ||||
|     handle->bus->current_handle = handle; | ||||
| 
 | ||||
|     handle->bus->callback(handle->bus, FuriHalI2cBusEventActivate); | ||||
| 
 | ||||
|     handle->callback(handle, FuriHalI2cBusHandleEventActivate); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_i2c_release(FuriHalI2cBusHandle* handle) { | ||||
|     assert(handle->bus->current_handle == handle); | ||||
| 
 | ||||
|     handle->callback(handle, FuriHalI2cBusHandleEventDeactivate); | ||||
| 
 | ||||
|     handle->bus->callback(handle->bus, FuriHalI2cBusEventDeactivate); | ||||
| 
 | ||||
|     handle->bus->current_handle = NULL; | ||||
| 
 | ||||
|     handle->bus->callback(handle->bus, FuriHalI2cBusEventUnlock); | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_i2c_tx( | ||||
|     FuriHalI2cBusHandle* handle, | ||||
|     uint8_t address, | ||||
|     const uint8_t* data, | ||||
|     uint8_t size, | ||||
|     uint32_t timeout) { | ||||
|     assert(handle->bus->current_handle == handle); | ||||
|     uint32_t time_left = timeout; | ||||
|     bool ret = true; | ||||
| 
 | ||||
|     while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) | ||||
|         ; | ||||
| 
 | ||||
|     LL_I2C_HandleTransfer( | ||||
|         handle->bus->i2c, | ||||
|         address, | ||||
|         LL_I2C_ADDRSLAVE_7BIT, | ||||
|         size, | ||||
|         LL_I2C_MODE_AUTOEND, | ||||
|         LL_I2C_GENERATE_START_WRITE); | ||||
| 
 | ||||
|     while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) { | ||||
|         if(LL_I2C_IsActiveFlag_TXIS(handle->bus->i2c)) { | ||||
|             LL_I2C_TransmitData8(handle->bus->i2c, (*data)); | ||||
|             data++; | ||||
|             size--; | ||||
|             time_left = timeout; | ||||
|         } | ||||
| 
 | ||||
|         if(LL_SYSTICK_IsActiveCounterFlag()) { | ||||
|             if(--time_left == 0) { | ||||
|                 ret = false; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     LL_I2C_ClearFlag_STOP(handle->bus->i2c); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_i2c_rx( | ||||
|     FuriHalI2cBusHandle* handle, | ||||
|     uint8_t address, | ||||
|     uint8_t* data, | ||||
|     uint8_t size, | ||||
|     uint32_t timeout) { | ||||
|     assert(handle->bus->current_handle == handle); | ||||
|     uint32_t time_left = timeout; | ||||
|     bool ret = true; | ||||
| 
 | ||||
|     while(LL_I2C_IsActiveFlag_BUSY(handle->bus->i2c)) | ||||
|         ; | ||||
| 
 | ||||
|     LL_I2C_HandleTransfer( | ||||
|         handle->bus->i2c, | ||||
|         address, | ||||
|         LL_I2C_ADDRSLAVE_7BIT, | ||||
|         size, | ||||
|         LL_I2C_MODE_AUTOEND, | ||||
|         LL_I2C_GENERATE_START_READ); | ||||
| 
 | ||||
|     while(!LL_I2C_IsActiveFlag_STOP(handle->bus->i2c) || size > 0) { | ||||
|         if(LL_I2C_IsActiveFlag_RXNE(handle->bus->i2c)) { | ||||
|             *data = LL_I2C_ReceiveData8(handle->bus->i2c); | ||||
|             data++; | ||||
|             size--; | ||||
|             time_left = timeout; | ||||
|         } | ||||
| 
 | ||||
|         if(LL_SYSTICK_IsActiveCounterFlag()) { | ||||
|             if(--time_left == 0) { | ||||
|                 ret = false; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     LL_I2C_ClearFlag_STOP(handle->bus->i2c); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_i2c_trx( | ||||
|     FuriHalI2cBusHandle* handle, | ||||
|     uint8_t address, | ||||
|     const uint8_t* tx_data, | ||||
|     uint8_t tx_size, | ||||
|     uint8_t* rx_data, | ||||
|     uint8_t rx_size, | ||||
|     uint32_t timeout) { | ||||
|     if(furi_hal_i2c_tx(handle, address, tx_data, tx_size, timeout) && | ||||
|        furi_hal_i2c_rx(handle, address, rx_data, rx_size, timeout)) { | ||||
|         return true; | ||||
|     } else { | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_i2c_read_reg_8( | ||||
|     FuriHalI2cBusHandle* handle, | ||||
|     uint8_t i2c_addr, | ||||
|     uint8_t reg_addr, | ||||
|     uint8_t* data, | ||||
|     uint32_t timeout) { | ||||
|     assert(handle); | ||||
| 
 | ||||
|     return furi_hal_i2c_trx(handle, i2c_addr, ®_addr, 1, data, 1, timeout); | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_i2c_read_reg_16( | ||||
|     FuriHalI2cBusHandle* handle, | ||||
|     uint8_t i2c_addr, | ||||
|     uint8_t reg_addr, | ||||
|     uint16_t* data, | ||||
|     uint32_t timeout) { | ||||
|     assert(handle); | ||||
| 
 | ||||
|     uint8_t reg_data[2]; | ||||
|     bool ret = furi_hal_i2c_trx(handle, i2c_addr, ®_addr, 1, reg_data, 2, timeout); | ||||
|     *data = (reg_data[0] << 8) | (reg_data[1]); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_i2c_read_mem( | ||||
|     FuriHalI2cBusHandle* handle, | ||||
|     uint8_t i2c_addr, | ||||
|     uint8_t mem_addr, | ||||
|     uint8_t* data, | ||||
|     uint8_t len, | ||||
|     uint32_t timeout) { | ||||
|     assert(handle); | ||||
| 
 | ||||
|     return furi_hal_i2c_trx(handle, i2c_addr, &mem_addr, 1, data, len, timeout); | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_i2c_write_reg_8( | ||||
|     FuriHalI2cBusHandle* handle, | ||||
|     uint8_t i2c_addr, | ||||
|     uint8_t reg_addr, | ||||
|     uint8_t data, | ||||
|     uint32_t timeout) { | ||||
|     assert(handle); | ||||
| 
 | ||||
|     uint8_t tx_data[2]; | ||||
|     tx_data[0] = reg_addr; | ||||
|     tx_data[1] = data; | ||||
| 
 | ||||
|     return furi_hal_i2c_tx(handle, i2c_addr, (const uint8_t*)&tx_data, 2, timeout); | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_i2c_write_reg_16( | ||||
|     FuriHalI2cBusHandle* handle, | ||||
|     uint8_t i2c_addr, | ||||
|     uint8_t reg_addr, | ||||
|     uint16_t data, | ||||
|     uint32_t timeout) { | ||||
|     assert(handle); | ||||
| 
 | ||||
|     uint8_t tx_data[3]; | ||||
|     tx_data[0] = reg_addr; | ||||
|     tx_data[1] = (data >> 8) & 0xFF; | ||||
|     tx_data[2] = data & 0xFF; | ||||
| 
 | ||||
|     return furi_hal_i2c_tx(handle, i2c_addr, (const uint8_t*)&tx_data, 3, timeout); | ||||
| } | ||||
| @ -1,195 +0,0 @@ | ||||
| /**
 | ||||
|  * @file furi_hal_i2c.h | ||||
|  * I2C HAL API | ||||
|  */ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| #include <stdint.h> | ||||
| #include <furi_hal_i2c_config.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /** Init I2C
 | ||||
|  */ | ||||
| void furi_hal_i2c_init(); | ||||
| 
 | ||||
| /** Acquire i2c bus handle
 | ||||
|  * | ||||
|  * @return     Instance of FuriHalI2cBus | ||||
|  */ | ||||
| void furi_hal_i2c_acquire(FuriHalI2cBusHandle* handle); | ||||
| 
 | ||||
| /** Release i2c bus handle
 | ||||
|  * | ||||
|  * @param      bus   instance of FuriHalI2cBus aquired in `furi_hal_i2c_acquire` | ||||
|  */ | ||||
| void furi_hal_i2c_release(FuriHalI2cBusHandle* handle); | ||||
| 
 | ||||
| /** Perform I2C tx transfer
 | ||||
|  * | ||||
|  * @param      handle   pointer to FuriHalI2cBusHandle instance | ||||
|  * @param      address  I2C slave address | ||||
|  * @param      data     pointer to data buffer | ||||
|  * @param      size     size of data buffer | ||||
|  * @param      timeout  timeout in ticks | ||||
|  * | ||||
|  * @return     true on successful transfer, false otherwise | ||||
|  */ | ||||
| bool furi_hal_i2c_tx( | ||||
|     FuriHalI2cBusHandle* handle, | ||||
|     const uint8_t address, | ||||
|     const uint8_t* data, | ||||
|     const uint8_t size, | ||||
|     uint32_t timeout); | ||||
| 
 | ||||
| /** Perform I2C rx transfer
 | ||||
|  * | ||||
|  * @param      handle   pointer to FuriHalI2cBusHandle instance | ||||
|  * @param      address  I2C slave address | ||||
|  * @param      data     pointer to data buffer | ||||
|  * @param      size     size of data buffer | ||||
|  * @param      timeout  timeout in ticks | ||||
|  * | ||||
|  * @return     true on successful transfer, false otherwise | ||||
|  */ | ||||
| bool furi_hal_i2c_rx( | ||||
|     FuriHalI2cBusHandle* handle, | ||||
|     const uint8_t address, | ||||
|     uint8_t* data, | ||||
|     const uint8_t size, | ||||
|     uint32_t timeout); | ||||
| 
 | ||||
| /** Perform I2C tx and rx transfers
 | ||||
|  * | ||||
|  * @param      handle   pointer to FuriHalI2cBusHandle instance | ||||
|  * @param      address  I2C slave address | ||||
|  * @param      tx_data  pointer to tx data buffer | ||||
|  * @param      tx_size  size of tx data buffer | ||||
|  * @param      rx_data  pointer to rx data buffer | ||||
|  * @param      rx_size  size of rx data buffer | ||||
|  * @param      timeout  timeout in ticks | ||||
|  * | ||||
|  * @return     true on successful transfer, false otherwise | ||||
|  */ | ||||
| bool furi_hal_i2c_trx( | ||||
|     FuriHalI2cBusHandle* handle, | ||||
|     const uint8_t address, | ||||
|     const uint8_t* tx_data, | ||||
|     const uint8_t tx_size, | ||||
|     uint8_t* rx_data, | ||||
|     const uint8_t rx_size, | ||||
|     uint32_t timeout); | ||||
| 
 | ||||
| /** Perform I2C device register read (8-bit)
 | ||||
|  * | ||||
|  * @param      handle   pointer to FuriHalI2cBusHandle instance | ||||
|  * @param      i2c_addr I2C slave address | ||||
|  * @param      reg_addr register address | ||||
|  * @param      data     pointer to register value | ||||
|  * @param      timeout  timeout in ticks | ||||
|  * | ||||
|  * @return     true on successful transfer, false otherwise | ||||
|  */ | ||||
| bool furi_hal_i2c_read_reg_8( | ||||
|     FuriHalI2cBusHandle* handle, | ||||
|     uint8_t i2c_addr, | ||||
|     uint8_t reg_addr, | ||||
|     uint8_t* data, | ||||
|     uint32_t timeout); | ||||
| 
 | ||||
| /** Perform I2C device register read (16-bit)
 | ||||
|  * | ||||
|  * @param      handle   pointer to FuriHalI2cBusHandle instance | ||||
|  * @param      i2c_addr I2C slave address | ||||
|  * @param      reg_addr register address | ||||
|  * @param      data     pointer to register value | ||||
|  * @param      timeout  timeout in ticks | ||||
|  * | ||||
|  * @return     true on successful transfer, false otherwise | ||||
|  */ | ||||
| bool furi_hal_i2c_read_reg_16( | ||||
|     FuriHalI2cBusHandle* handle, | ||||
|     uint8_t i2c_addr, | ||||
|     uint8_t reg_addr, | ||||
|     uint16_t* data, | ||||
|     uint32_t timeout); | ||||
| 
 | ||||
| /** Perform I2C device memory read
 | ||||
|  * | ||||
|  * @param      handle   pointer to FuriHalI2cBusHandle instance | ||||
|  * @param      i2c_addr I2C slave address | ||||
|  * @param      mem_addr memory start address | ||||
|  * @param      data     pointer to data buffer | ||||
|  * @param      len      size of data buffer | ||||
|  * @param      timeout  timeout in ticks | ||||
|  * | ||||
|  * @return     true on successful transfer, false otherwise | ||||
|  */ | ||||
| bool furi_hal_i2c_read_mem( | ||||
|     FuriHalI2cBusHandle* handle, | ||||
|     uint8_t i2c_addr, | ||||
|     uint8_t mem_addr, | ||||
|     uint8_t* data, | ||||
|     uint8_t len, | ||||
|     uint32_t timeout); | ||||
| 
 | ||||
| /** Perform I2C device register write (8-bit)
 | ||||
|  * | ||||
|  * @param      handle   pointer to FuriHalI2cBusHandle instance | ||||
|  * @param      i2c_addr I2C slave address | ||||
|  * @param      reg_addr register address | ||||
|  * @param      data     register value | ||||
|  * @param      timeout  timeout in ticks | ||||
|  * | ||||
|  * @return     true on successful transfer, false otherwise | ||||
|  */ | ||||
| bool furi_hal_i2c_write_reg_8( | ||||
|     FuriHalI2cBusHandle* handle, | ||||
|     uint8_t i2c_addr, | ||||
|     uint8_t reg_addr, | ||||
|     uint8_t data, | ||||
|     uint32_t timeout); | ||||
| 
 | ||||
| /** Perform I2C device register write (16-bit)
 | ||||
|  * | ||||
|  * @param      handle   pointer to FuriHalI2cBusHandle instance | ||||
|  * @param      i2c_addr I2C slave address | ||||
|  * @param      reg_addr register address | ||||
|  * @param      data     register value | ||||
|  * @param      timeout  timeout in ticks | ||||
|  * | ||||
|  * @return     true on successful transfer, false otherwise | ||||
|  */ | ||||
| bool furi_hal_i2c_write_reg_16( | ||||
|     FuriHalI2cBusHandle* handle, | ||||
|     uint8_t i2c_addr, | ||||
|     uint8_t reg_addr, | ||||
|     uint16_t data, | ||||
|     uint32_t timeout); | ||||
| 
 | ||||
| /** Perform I2C device memory
 | ||||
|  * | ||||
|  * @param      handle   pointer to FuriHalI2cBusHandle instance | ||||
|  * @param      i2c_addr I2C slave address | ||||
|  * @param      mem_addr memory start address | ||||
|  * @param      data     pointer to data buffer | ||||
|  * @param      len      size of data buffer | ||||
|  * @param      timeout  timeout in ticks | ||||
|  * | ||||
|  * @return     true on successful transfer, false otherwise | ||||
|  */ | ||||
| bool furi_hal_i2c_write_mem( | ||||
|     FuriHalI2cBusHandle* handle, | ||||
|     uint8_t i2c_addr, | ||||
|     uint8_t mem_addr, | ||||
|     uint8_t* data, | ||||
|     uint8_t len, | ||||
|     uint32_t timeout); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -1,149 +0,0 @@ | ||||
| #include "furi_hal_i2c_config.h" | ||||
| #include <furi_hal_resources.h> | ||||
| #include <furi_hal_version.h> | ||||
| 
 | ||||
| #include <stm32wbxx_ll_rcc.h> | ||||
| #include <stm32wbxx_ll_bus.h> | ||||
| 
 | ||||
| /** Timing register value is computed with the STM32CubeMX Tool,
 | ||||
|   * Standard Mode @100kHz with I2CCLK = 64 MHz, | ||||
|   * rise time = 0ns, fall time = 0ns | ||||
|   */ | ||||
| #define FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100 0x10707DBC | ||||
| 
 | ||||
| /** Timing register value is computed with the STM32CubeMX Tool,
 | ||||
|   * Fast Mode @400kHz with I2CCLK = 64 MHz, | ||||
|   * rise time = 0ns, fall time = 0ns | ||||
|   */ | ||||
| #define FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_400 0x00602173 | ||||
| 
 | ||||
| static void furi_hal_i2c_bus_power_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) { | ||||
|     if(event == FuriHalI2cBusEventInit) { | ||||
|         LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); | ||||
|         LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1); | ||||
|         LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1); | ||||
|         bus->current_handle = NULL; | ||||
|     } else if(event == FuriHalI2cBusEventDeinit) { | ||||
|     } else if(event == FuriHalI2cBusEventLock) { | ||||
|     } else if(event == FuriHalI2cBusEventUnlock) { | ||||
|     } else if(event == FuriHalI2cBusEventActivate) { | ||||
|         LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C1); | ||||
|     } else if(event == FuriHalI2cBusEventDeactivate) { | ||||
|         LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C1); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| FuriHalI2cBus furi_hal_i2c_bus_power = { | ||||
|     .i2c = I2C1, | ||||
|     .current_handle = NULL, | ||||
|     .callback = furi_hal_i2c_bus_power_event, | ||||
| }; | ||||
| 
 | ||||
| static void furi_hal_i2c_bus_external_event(FuriHalI2cBus* bus, FuriHalI2cBusEvent event) { | ||||
|     if(event == FuriHalI2cBusEventActivate) { | ||||
|         LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C3); | ||||
|         LL_RCC_SetI2CClockSource(LL_RCC_I2C3_CLKSOURCE_PCLK1); | ||||
|         LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I2C3); | ||||
|     } else if(event == FuriHalI2cBusEventDeactivate) { | ||||
|         LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I2C3); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| FuriHalI2cBus furi_hal_i2c_bus_external = { | ||||
|     .i2c = I2C3, | ||||
|     .current_handle = NULL, | ||||
|     .callback = furi_hal_i2c_bus_external_event, | ||||
| }; | ||||
| 
 | ||||
| void furi_hal_i2c_bus_handle_power_event( | ||||
|     FuriHalI2cBusHandle* handle, | ||||
|     FuriHalI2cBusHandleEvent event) { | ||||
|     if(event == FuriHalI2cBusHandleEventActivate) { | ||||
|         LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); | ||||
|         hal_gpio_init_ex( | ||||
|             &gpio_i2c_power_sda, | ||||
|             GpioModeAltFunctionOpenDrain, | ||||
|             GpioPullNo, | ||||
|             GpioSpeedLow, | ||||
|             GpioAltFn4I2C1); | ||||
|         hal_gpio_init_ex( | ||||
|             &gpio_i2c_power_scl, | ||||
|             GpioModeAltFunctionOpenDrain, | ||||
|             GpioPullNo, | ||||
|             GpioSpeedLow, | ||||
|             GpioAltFn4I2C1); | ||||
| 
 | ||||
|         LL_I2C_InitTypeDef I2C_InitStruct = {0}; | ||||
|         I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C; | ||||
|         I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE; | ||||
|         I2C_InitStruct.DigitalFilter = 0; | ||||
|         I2C_InitStruct.OwnAddress1 = 0; | ||||
|         I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK; | ||||
|         I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT; | ||||
|         if(furi_hal_version_get_hw_version() > 10) { | ||||
|             I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_400; | ||||
|         } else { | ||||
|             I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100; | ||||
|         } | ||||
|         LL_I2C_Init(handle->bus->i2c, &I2C_InitStruct); | ||||
| 
 | ||||
|         LL_I2C_EnableAutoEndMode(handle->bus->i2c); | ||||
|         LL_I2C_SetOwnAddress2(handle->bus->i2c, 0, LL_I2C_OWNADDRESS2_NOMASK); | ||||
|         LL_I2C_DisableOwnAddress2(handle->bus->i2c); | ||||
|         LL_I2C_DisableGeneralCall(handle->bus->i2c); | ||||
|         LL_I2C_EnableClockStretching(handle->bus->i2c); | ||||
|         LL_I2C_Enable(handle->bus->i2c); | ||||
|     } else if(event == FuriHalI2cBusHandleEventDeactivate) { | ||||
|         LL_I2C_Disable(handle->bus->i2c); | ||||
|         hal_gpio_write(&gpio_i2c_power_sda, 1); | ||||
|         hal_gpio_write(&gpio_i2c_power_scl, 1); | ||||
|         hal_gpio_init_ex( | ||||
|             &gpio_i2c_power_sda, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused); | ||||
|         hal_gpio_init_ex( | ||||
|             &gpio_i2c_power_scl, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| FuriHalI2cBusHandle furi_hal_i2c_handle_power = { | ||||
|     .bus = &furi_hal_i2c_bus_power, | ||||
|     .callback = furi_hal_i2c_bus_handle_power_event, | ||||
| }; | ||||
| 
 | ||||
| void furi_hal_i2c_bus_handle_external_event( | ||||
|     FuriHalI2cBusHandle* handle, | ||||
|     FuriHalI2cBusHandleEvent event) { | ||||
|     if(event == FuriHalI2cBusHandleEventActivate) { | ||||
|         hal_gpio_init_ex( | ||||
|             &gpio_ext_pc0, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C3); | ||||
|         hal_gpio_init_ex( | ||||
|             &gpio_ext_pc1, GpioModeAltFunctionOpenDrain, GpioPullNo, GpioSpeedLow, GpioAltFn4I2C3); | ||||
| 
 | ||||
|         LL_I2C_InitTypeDef I2C_InitStruct = {0}; | ||||
|         I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C; | ||||
|         I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE; | ||||
|         I2C_InitStruct.DigitalFilter = 0; | ||||
|         I2C_InitStruct.OwnAddress1 = 0; | ||||
|         I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK; | ||||
|         I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT; | ||||
|         I2C_InitStruct.Timing = FURI_HAL_I2C_CONFIG_POWER_I2C_TIMINGS_100; | ||||
|         LL_I2C_Init(handle->bus->i2c, &I2C_InitStruct); | ||||
| 
 | ||||
|         LL_I2C_EnableAutoEndMode(handle->bus->i2c); | ||||
|         LL_I2C_SetOwnAddress2(handle->bus->i2c, 0, LL_I2C_OWNADDRESS2_NOMASK); | ||||
|         LL_I2C_DisableOwnAddress2(handle->bus->i2c); | ||||
|         LL_I2C_DisableGeneralCall(handle->bus->i2c); | ||||
|         LL_I2C_EnableClockStretching(handle->bus->i2c); | ||||
|         LL_I2C_Enable(handle->bus->i2c); | ||||
|     } else if(event == FuriHalI2cBusHandleEventDeactivate) { | ||||
|         LL_I2C_Disable(handle->bus->i2c); | ||||
|         hal_gpio_write(&gpio_ext_pc0, 1); | ||||
|         hal_gpio_write(&gpio_ext_pc1, 1); | ||||
|         hal_gpio_init_ex(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused); | ||||
|         hal_gpio_init_ex(&gpio_ext_pc1, GpioModeAnalog, GpioPullNo, GpioSpeedLow, GpioAltFnUnused); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| FuriHalI2cBusHandle furi_hal_i2c_handle_external = { | ||||
|     .bus = &furi_hal_i2c_bus_external, | ||||
|     .callback = furi_hal_i2c_bus_handle_external_event, | ||||
| }; | ||||
| @ -1,31 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <furi_hal_i2c_types.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /** Internal(power) i2c bus, I2C1, under reset when not used */ | ||||
| extern FuriHalI2cBus furi_hal_i2c_bus_power; | ||||
| 
 | ||||
| /** External i2c bus, I2C3, under reset when not used */ | ||||
| extern FuriHalI2cBus furi_hal_i2c_bus_external; | ||||
| 
 | ||||
| /** Handle for internal(power) i2c bus
 | ||||
|  * Bus: furi_hal_i2c_bus_external | ||||
|  * Pins: PA9(SCL) / PA10(SDA), float on release | ||||
|  * Params: 400khz | ||||
|  */ | ||||
| extern FuriHalI2cBusHandle furi_hal_i2c_handle_power; | ||||
| 
 | ||||
| /** Handle for external i2c bus
 | ||||
|  * Bus: furi_hal_i2c_bus_external | ||||
|  * Pins: PC0(SCL) / PC1(SDA), float on release | ||||
|  * Params: 100khz | ||||
|  */ | ||||
| extern FuriHalI2cBusHandle furi_hal_i2c_handle_external; | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -1,51 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stm32wbxx_ll_i2c.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| typedef struct FuriHalI2cBus FuriHalI2cBus; | ||||
| typedef struct FuriHalI2cBusHandle FuriHalI2cBusHandle; | ||||
| 
 | ||||
| /** FuriHal i2c bus states */ | ||||
| typedef enum { | ||||
|     FuriHalI2cBusEventInit, /**< Bus initialization event, called on system start */ | ||||
|     FuriHalI2cBusEventDeinit, /**< Bus deinitialization event, called on system stop */ | ||||
|     FuriHalI2cBusEventLock, /**< Bus lock event, called before activation */ | ||||
|     FuriHalI2cBusEventUnlock, /**< Bus unlock event, called after deactivation */ | ||||
|     FuriHalI2cBusEventActivate, /**< Bus activation event, called before handle activation */ | ||||
|     FuriHalI2cBusEventDeactivate, /**< Bus deactivation event, called after handle deactivation  */ | ||||
| } FuriHalI2cBusEvent; | ||||
| 
 | ||||
| /** FuriHal i2c bus event callback */ | ||||
| typedef void (*FuriHalI2cBusEventCallback)(FuriHalI2cBus* bus, FuriHalI2cBusEvent event); | ||||
| 
 | ||||
| /** FuriHal i2c bus */ | ||||
| struct FuriHalI2cBus { | ||||
|     I2C_TypeDef* i2c; | ||||
|     FuriHalI2cBusHandle* current_handle; | ||||
|     FuriHalI2cBusEventCallback callback; | ||||
| }; | ||||
| 
 | ||||
| /** FuriHal i2c handle states */ | ||||
| typedef enum { | ||||
|     FuriHalI2cBusHandleEventActivate, /**< Handle activate: connect gpio and apply bus config */ | ||||
|     FuriHalI2cBusHandleEventDeactivate, /**< Handle deactivate: disconnect gpio and reset bus config */ | ||||
| } FuriHalI2cBusHandleEvent; | ||||
| 
 | ||||
| /** FuriHal i2c handle event callback */ | ||||
| typedef void (*FuriHalI2cBusHandleEventCallback)( | ||||
|     FuriHalI2cBusHandle* handle, | ||||
|     FuriHalI2cBusHandleEvent event); | ||||
| 
 | ||||
| /** FuriHal i2c handle */ | ||||
| struct FuriHalI2cBusHandle { | ||||
|     FuriHalI2cBus* bus; | ||||
|     FuriHalI2cBusHandleEventCallback callback; | ||||
| }; | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -1,49 +0,0 @@ | ||||
| #include <furi_hal_light.h> | ||||
| #include <lp5562.h> | ||||
| 
 | ||||
| #define LED_CURRENT_RED 50 | ||||
| #define LED_CURRENT_GREEN 50 | ||||
| #define LED_CURRENT_BLUE 50 | ||||
| #define LED_CURRENT_WHITE 150 | ||||
| 
 | ||||
| void furi_hal_light_init() { | ||||
|     furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); | ||||
| 
 | ||||
|     lp5562_reset(&furi_hal_i2c_handle_power); | ||||
| 
 | ||||
|     lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelRed, LED_CURRENT_RED); | ||||
|     lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelGreen, LED_CURRENT_GREEN); | ||||
|     lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelBlue, LED_CURRENT_BLUE); | ||||
|     lp5562_set_channel_current(&furi_hal_i2c_handle_power, LP5562ChannelWhite, LED_CURRENT_WHITE); | ||||
| 
 | ||||
|     lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, 0x00); | ||||
|     lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, 0x00); | ||||
|     lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, 0x00); | ||||
|     lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, 0x00); | ||||
| 
 | ||||
|     lp5562_enable(&furi_hal_i2c_handle_power); | ||||
|     lp5562_configure(&furi_hal_i2c_handle_power); | ||||
| 
 | ||||
|     furi_hal_i2c_release(&furi_hal_i2c_handle_power); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_light_set(Light light, uint8_t value) { | ||||
|     furi_hal_i2c_acquire(&furi_hal_i2c_handle_power); | ||||
|     switch(light) { | ||||
|     case LightRed: | ||||
|         lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelRed, value); | ||||
|         break; | ||||
|     case LightGreen: | ||||
|         lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelGreen, value); | ||||
|         break; | ||||
|     case LightBlue: | ||||
|         lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelBlue, value); | ||||
|         break; | ||||
|     case LightBacklight: | ||||
|         lp5562_set_channel_value(&furi_hal_i2c_handle_power, LP5562ChannelWhite, value); | ||||
|         break; | ||||
|     default: | ||||
|         break; | ||||
|     } | ||||
|     furi_hal_i2c_release(&furi_hal_i2c_handle_power); | ||||
| } | ||||
| @ -1,17 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| #include <stdint.h> | ||||
| #include <furi_hal_resources.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| void furi_hal_light_init(); | ||||
| 
 | ||||
| void furi_hal_light_set(Light light, uint8_t value); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -1,44 +0,0 @@ | ||||
| #include "furi_hal_resources.h" | ||||
| #include "main.h" | ||||
| 
 | ||||
| const GpioPin vibro_gpio = {.port = VIBRO_GPIO_Port, .pin = VIBRO_Pin}; | ||||
| const GpioPin ibutton_gpio = {.port = iBTN_GPIO_Port, .pin = iBTN_Pin}; | ||||
| 
 | ||||
| const GpioPin gpio_cc1101_g0 = {.port = CC1101_G0_GPIO_Port, .pin = CC1101_G0_Pin}; | ||||
| const GpioPin gpio_rf_sw_0 = {.port = RF_SW_0_GPIO_Port, .pin = RF_SW_0_Pin}; | ||||
| 
 | ||||
| const GpioPin gpio_subghz_cs = {.port = CC1101_CS_GPIO_Port, .pin = CC1101_CS_Pin}; | ||||
| const GpioPin gpio_display_cs = {.port = DISPLAY_CS_GPIO_Port, .pin = DISPLAY_CS_Pin}; | ||||
| const GpioPin gpio_display_rst = {.port = DISPLAY_RST_GPIO_Port, .pin = DISPLAY_RST_Pin}; | ||||
| const GpioPin gpio_display_di = {.port = DISPLAY_DI_GPIO_Port, .pin = DISPLAY_DI_Pin}; | ||||
| const GpioPin gpio_sdcard_cs = {.port = SD_CS_GPIO_Port, .pin = SD_CS_Pin}; | ||||
| const GpioPin gpio_nfc_cs = {.port = NFC_CS_GPIO_Port, .pin = NFC_CS_Pin}; | ||||
| 
 | ||||
| const GpioPin gpio_spi_d_miso = {.port = SPI_D_MISO_GPIO_Port, .pin = SPI_D_MISO_Pin}; | ||||
| const GpioPin gpio_spi_d_mosi = {.port = SPI_D_MOSI_GPIO_Port, .pin = SPI_D_MOSI_Pin}; | ||||
| const GpioPin gpio_spi_d_sck = {.port = SPI_D_SCK_GPIO_Port, .pin = SPI_D_SCK_Pin}; | ||||
| const GpioPin gpio_spi_r_miso = {.port = SPI_R_MISO_GPIO_Port, .pin = SPI_R_MISO_Pin}; | ||||
| const GpioPin gpio_spi_r_mosi = {.port = SPI_R_MOSI_GPIO_Port, .pin = SPI_R_MOSI_Pin}; | ||||
| const GpioPin gpio_spi_r_sck = {.port = SPI_R_SCK_GPIO_Port, .pin = SPI_R_SCK_Pin}; | ||||
| 
 | ||||
| const GpioPin gpio_ext_pc0 = {.port = GPIOC, .pin = LL_GPIO_PIN_0}; | ||||
| const GpioPin gpio_ext_pc1 = {.port = GPIOC, .pin = LL_GPIO_PIN_1}; | ||||
| const GpioPin gpio_ext_pc3 = {.port = GPIOC, .pin = LL_GPIO_PIN_3}; | ||||
| const GpioPin gpio_ext_pb2 = {.port = GPIOB, .pin = LL_GPIO_PIN_2}; | ||||
| const GpioPin gpio_ext_pb3 = {.port = GPIOB, .pin = LL_GPIO_PIN_3}; | ||||
| const GpioPin gpio_ext_pa4 = {.port = GPIOA, .pin = LL_GPIO_PIN_4}; | ||||
| const GpioPin gpio_ext_pa6 = {.port = GPIOA, .pin = LL_GPIO_PIN_6}; | ||||
| const GpioPin gpio_ext_pa7 = {.port = GPIOA, .pin = LL_GPIO_PIN_7}; | ||||
| 
 | ||||
| const GpioPin gpio_rfid_pull = {.port = RFID_PULL_GPIO_Port, .pin = RFID_PULL_Pin}; | ||||
| const GpioPin gpio_rfid_carrier_out = {.port = RFID_OUT_GPIO_Port, .pin = RFID_OUT_Pin}; | ||||
| const GpioPin gpio_rfid_data_in = {.port = RFID_RF_IN_GPIO_Port, .pin = RFID_RF_IN_Pin}; | ||||
| 
 | ||||
| const GpioPin gpio_infrared_rx = {.port = IR_RX_GPIO_Port, .pin = IR_RX_Pin}; | ||||
| const GpioPin gpio_infrared_tx = {.port = IR_TX_GPIO_Port, .pin = IR_TX_Pin}; | ||||
| 
 | ||||
| const GpioPin gpio_usart_tx = {.port = USART1_TX_Port, .pin = USART1_TX_Pin}; | ||||
| const GpioPin gpio_usart_rx = {.port = USART1_RX_Port, .pin = USART1_RX_Pin}; | ||||
| 
 | ||||
| const GpioPin gpio_i2c_power_sda = {.port = GPIOA, .pin = LL_GPIO_PIN_10}; | ||||
| const GpioPin gpio_i2c_power_scl = {.port = GPIOA, .pin = LL_GPIO_PIN_9}; | ||||
| @ -1,73 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stm32wbxx.h> | ||||
| #include <stm32wbxx_ll_gpio.h> | ||||
| #include <furi_hal_gpio.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /* Input Keys */ | ||||
| typedef enum { | ||||
|     InputKeyUp, | ||||
|     InputKeyDown, | ||||
|     InputKeyRight, | ||||
|     InputKeyLeft, | ||||
|     InputKeyOk, | ||||
|     InputKeyBack, | ||||
| } InputKey; | ||||
| 
 | ||||
| /* Light */ | ||||
| typedef enum { | ||||
|     LightRed, | ||||
|     LightGreen, | ||||
|     LightBlue, | ||||
|     LightBacklight, | ||||
| } Light; | ||||
| 
 | ||||
| extern const GpioPin vibro_gpio; | ||||
| extern const GpioPin ibutton_gpio; | ||||
| 
 | ||||
| extern const GpioPin gpio_cc1101_g0; | ||||
| extern const GpioPin gpio_rf_sw_0; | ||||
| 
 | ||||
| extern const GpioPin gpio_subghz_cs; | ||||
| extern const GpioPin gpio_display_cs; | ||||
| extern const GpioPin gpio_display_rst; | ||||
| extern const GpioPin gpio_display_di; | ||||
| extern const GpioPin gpio_sdcard_cs; | ||||
| extern const GpioPin gpio_nfc_cs; | ||||
| 
 | ||||
| extern const GpioPin gpio_spi_d_miso; | ||||
| extern const GpioPin gpio_spi_d_mosi; | ||||
| extern const GpioPin gpio_spi_d_sck; | ||||
| extern const GpioPin gpio_spi_r_miso; | ||||
| extern const GpioPin gpio_spi_r_mosi; | ||||
| extern const GpioPin gpio_spi_r_sck; | ||||
| 
 | ||||
| extern const GpioPin gpio_ext_pc0; | ||||
| extern const GpioPin gpio_ext_pc1; | ||||
| extern const GpioPin gpio_ext_pc3; | ||||
| extern const GpioPin gpio_ext_pb2; | ||||
| extern const GpioPin gpio_ext_pb3; | ||||
| extern const GpioPin gpio_ext_pa4; | ||||
| extern const GpioPin gpio_ext_pa6; | ||||
| extern const GpioPin gpio_ext_pa7; | ||||
| 
 | ||||
| extern const GpioPin gpio_rfid_pull; | ||||
| extern const GpioPin gpio_rfid_carrier_out; | ||||
| extern const GpioPin gpio_rfid_data_in; | ||||
| 
 | ||||
| extern const GpioPin gpio_infrared_rx; | ||||
| extern const GpioPin gpio_infrared_tx; | ||||
| 
 | ||||
| extern const GpioPin gpio_usart_tx; | ||||
| extern const GpioPin gpio_usart_rx; | ||||
| 
 | ||||
| extern const GpioPin gpio_i2c_power_sda; | ||||
| extern const GpioPin gpio_i2c_power_scl; | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -1,151 +0,0 @@ | ||||
| #include "furi_hal_spi.h" | ||||
| #include "furi_hal_resources.h" | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| #include <string.h> | ||||
| #include <assert.h> | ||||
| 
 | ||||
| #include <stm32wbxx_ll_spi.h> | ||||
| #include <stm32wbxx_ll_utils.h> | ||||
| #include <stm32wbxx_ll_cortex.h> | ||||
| 
 | ||||
| void furi_hal_spi_init() { | ||||
|     furi_hal_spi_bus_init(&furi_hal_spi_bus_r); | ||||
|     furi_hal_spi_bus_init(&furi_hal_spi_bus_d); | ||||
| 
 | ||||
|     furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_subghz); | ||||
|     furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc); | ||||
|     furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_display); | ||||
|     furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_sd_fast); | ||||
|     furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_sd_slow); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_spi_bus_init(FuriHalSpiBus* bus) { | ||||
|     assert(bus); | ||||
|     bus->callback(bus, FuriHalSpiBusEventInit); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_spi_bus_deinit(FuriHalSpiBus* bus) { | ||||
|     assert(bus); | ||||
|     bus->callback(bus, FuriHalSpiBusEventDeinit); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_spi_bus_handle_init(FuriHalSpiBusHandle* handle) { | ||||
|     assert(handle); | ||||
|     handle->callback(handle, FuriHalSpiBusHandleEventInit); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_spi_bus_handle_deinit(FuriHalSpiBusHandle* handle) { | ||||
|     assert(handle); | ||||
|     handle->callback(handle, FuriHalSpiBusHandleEventDeinit); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_spi_acquire(FuriHalSpiBusHandle* handle) { | ||||
|     assert(handle); | ||||
| 
 | ||||
|     handle->bus->callback(handle->bus, FuriHalSpiBusEventLock); | ||||
|     handle->bus->callback(handle->bus, FuriHalSpiBusEventActivate); | ||||
| 
 | ||||
|     assert(handle->bus->current_handle == NULL); | ||||
| 
 | ||||
|     handle->bus->current_handle = handle; | ||||
|     handle->callback(handle, FuriHalSpiBusHandleEventActivate); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_spi_release(FuriHalSpiBusHandle* handle) { | ||||
|     assert(handle); | ||||
|     assert(handle->bus->current_handle == handle); | ||||
| 
 | ||||
|     // Handle event and unset handle
 | ||||
|     handle->callback(handle, FuriHalSpiBusHandleEventDeactivate); | ||||
|     handle->bus->current_handle = NULL; | ||||
| 
 | ||||
|     // Bus events
 | ||||
|     handle->bus->callback(handle->bus, FuriHalSpiBusEventDeactivate); | ||||
|     handle->bus->callback(handle->bus, FuriHalSpiBusEventUnlock); | ||||
| } | ||||
| 
 | ||||
| static void furi_hal_spi_bus_end_txrx(FuriHalSpiBusHandle* handle, uint32_t timeout) { | ||||
|     while(LL_SPI_GetTxFIFOLevel(handle->bus->spi) != LL_SPI_TX_FIFO_EMPTY) | ||||
|         ; | ||||
|     while(LL_SPI_IsActiveFlag_BSY(handle->bus->spi)) | ||||
|         ; | ||||
|     while(LL_SPI_GetRxFIFOLevel(handle->bus->spi) != LL_SPI_RX_FIFO_EMPTY) { | ||||
|         LL_SPI_ReceiveData8(handle->bus->spi); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_spi_bus_rx( | ||||
|     FuriHalSpiBusHandle* handle, | ||||
|     uint8_t* buffer, | ||||
|     size_t size, | ||||
|     uint32_t timeout) { | ||||
|     assert(handle); | ||||
|     assert(handle->bus->current_handle == handle); | ||||
|     assert(buffer); | ||||
|     assert(size > 0); | ||||
| 
 | ||||
|     return furi_hal_spi_bus_trx(handle, buffer, buffer, size, timeout); | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_spi_bus_tx( | ||||
|     FuriHalSpiBusHandle* handle, | ||||
|     uint8_t* buffer, | ||||
|     size_t size, | ||||
|     uint32_t timeout) { | ||||
|     assert(handle); | ||||
|     assert(handle->bus->current_handle == handle); | ||||
|     assert(buffer); | ||||
|     assert(size > 0); | ||||
|     bool ret = true; | ||||
| 
 | ||||
|     while(size > 0) { | ||||
|         if(LL_SPI_IsActiveFlag_TXE(handle->bus->spi)) { | ||||
|             LL_SPI_TransmitData8(handle->bus->spi, *buffer); | ||||
|             buffer++; | ||||
|             size--; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     furi_hal_spi_bus_end_txrx(handle, timeout); | ||||
|     LL_SPI_ClearFlag_OVR(handle->bus->spi); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_spi_bus_trx( | ||||
|     FuriHalSpiBusHandle* handle, | ||||
|     uint8_t* tx_buffer, | ||||
|     uint8_t* rx_buffer, | ||||
|     size_t size, | ||||
|     uint32_t timeout) { | ||||
|     assert(handle); | ||||
|     assert(handle->bus->current_handle == handle); | ||||
|     assert(tx_buffer); | ||||
|     assert(rx_buffer); | ||||
|     assert(size > 0); | ||||
| 
 | ||||
|     bool ret = true; | ||||
|     size_t tx_size = size; | ||||
|     bool tx_allowed = true; | ||||
| 
 | ||||
|     while(size > 0) { | ||||
|         if(tx_size > 0 && LL_SPI_IsActiveFlag_TXE(handle->bus->spi) && tx_allowed) { | ||||
|             LL_SPI_TransmitData8(handle->bus->spi, *tx_buffer); | ||||
|             tx_buffer++; | ||||
|             tx_size--; | ||||
|             tx_allowed = false; | ||||
|         } | ||||
| 
 | ||||
|         if(LL_SPI_IsActiveFlag_RXNE(handle->bus->spi)) { | ||||
|             *rx_buffer = LL_SPI_ReceiveData8(handle->bus->spi); | ||||
|             rx_buffer++; | ||||
|             size--; | ||||
|             tx_allowed = true; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     furi_hal_spi_bus_end_txrx(handle, timeout); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| @ -1,290 +0,0 @@ | ||||
| #include <furi_hal_spi_config.h> | ||||
| #include <furi_hal_resources.h> | ||||
| 
 | ||||
| /* SPI Presets */ | ||||
| 
 | ||||
| const LL_SPI_InitTypeDef furi_hal_spi_preset_2edge_low_8m = { | ||||
|     .Mode = LL_SPI_MODE_MASTER, | ||||
|     .TransferDirection = LL_SPI_FULL_DUPLEX, | ||||
|     .DataWidth = LL_SPI_DATAWIDTH_8BIT, | ||||
|     .ClockPolarity = LL_SPI_POLARITY_LOW, | ||||
|     .ClockPhase = LL_SPI_PHASE_2EDGE, | ||||
|     .NSS = LL_SPI_NSS_SOFT, | ||||
|     .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8, | ||||
|     .BitOrder = LL_SPI_MSB_FIRST, | ||||
|     .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE, | ||||
|     .CRCPoly = 7, | ||||
| }; | ||||
| 
 | ||||
| const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_8m = { | ||||
|     .Mode = LL_SPI_MODE_MASTER, | ||||
|     .TransferDirection = LL_SPI_FULL_DUPLEX, | ||||
|     .DataWidth = LL_SPI_DATAWIDTH_8BIT, | ||||
|     .ClockPolarity = LL_SPI_POLARITY_LOW, | ||||
|     .ClockPhase = LL_SPI_PHASE_1EDGE, | ||||
|     .NSS = LL_SPI_NSS_SOFT, | ||||
|     .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8, | ||||
|     .BitOrder = LL_SPI_MSB_FIRST, | ||||
|     .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE, | ||||
|     .CRCPoly = 7, | ||||
| }; | ||||
| 
 | ||||
| const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_4m = { | ||||
|     .Mode = LL_SPI_MODE_MASTER, | ||||
|     .TransferDirection = LL_SPI_FULL_DUPLEX, | ||||
|     .DataWidth = LL_SPI_DATAWIDTH_8BIT, | ||||
|     .ClockPolarity = LL_SPI_POLARITY_LOW, | ||||
|     .ClockPhase = LL_SPI_PHASE_1EDGE, | ||||
|     .NSS = LL_SPI_NSS_SOFT, | ||||
|     .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV16, | ||||
|     .BitOrder = LL_SPI_MSB_FIRST, | ||||
|     .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE, | ||||
|     .CRCPoly = 7, | ||||
| }; | ||||
| 
 | ||||
| const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_16m = { | ||||
|     .Mode = LL_SPI_MODE_MASTER, | ||||
|     .TransferDirection = LL_SPI_FULL_DUPLEX, | ||||
|     .DataWidth = LL_SPI_DATAWIDTH_8BIT, | ||||
|     .ClockPolarity = LL_SPI_POLARITY_LOW, | ||||
|     .ClockPhase = LL_SPI_PHASE_1EDGE, | ||||
|     .NSS = LL_SPI_NSS_SOFT, | ||||
|     .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV2, | ||||
|     .BitOrder = LL_SPI_MSB_FIRST, | ||||
|     .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE, | ||||
|     .CRCPoly = 7, | ||||
| }; | ||||
| 
 | ||||
| const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_2m = { | ||||
|     .Mode = LL_SPI_MODE_MASTER, | ||||
|     .TransferDirection = LL_SPI_FULL_DUPLEX, | ||||
|     .DataWidth = LL_SPI_DATAWIDTH_8BIT, | ||||
|     .ClockPolarity = LL_SPI_POLARITY_LOW, | ||||
|     .ClockPhase = LL_SPI_PHASE_1EDGE, | ||||
|     .NSS = LL_SPI_NSS_SOFT, | ||||
|     .BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV32, | ||||
|     .BitOrder = LL_SPI_MSB_FIRST, | ||||
|     .CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE, | ||||
|     .CRCPoly = 7, | ||||
| }; | ||||
| 
 | ||||
| /* SPI Buses */ | ||||
| 
 | ||||
| static void furi_hal_spi_bus_r_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) { | ||||
|     if(event == FuriHalSpiBusEventInit) { | ||||
|         LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1); | ||||
|         LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); | ||||
|         bus->current_handle = NULL; | ||||
|     } else if(event == FuriHalSpiBusEventDeinit) { | ||||
|     } else if(event == FuriHalSpiBusEventLock) { | ||||
|     } else if(event == FuriHalSpiBusEventUnlock) { | ||||
|     } else if(event == FuriHalSpiBusEventActivate) { | ||||
|         LL_APB2_GRP1_ReleaseReset(LL_APB2_GRP1_PERIPH_SPI1); | ||||
|     } else if(event == FuriHalSpiBusEventDeactivate) { | ||||
|         LL_APB2_GRP1_ForceReset(LL_APB2_GRP1_PERIPH_SPI1); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| FuriHalSpiBus furi_hal_spi_bus_r = { | ||||
|     .spi = SPI1, | ||||
|     .callback = furi_hal_spi_bus_r_event_callback, | ||||
| }; | ||||
| 
 | ||||
| static void furi_hal_spi_bus_d_event_callback(FuriHalSpiBus* bus, FuriHalSpiBusEvent event) { | ||||
|     if(event == FuriHalSpiBusEventInit) { | ||||
|         LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2); | ||||
|         LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); | ||||
|         bus->current_handle = NULL; | ||||
|     } else if(event == FuriHalSpiBusEventDeinit) { | ||||
|     } else if(event == FuriHalSpiBusEventLock) { | ||||
|     } else if(event == FuriHalSpiBusEventUnlock) { | ||||
|     } else if(event == FuriHalSpiBusEventActivate) { | ||||
|         LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_SPI2); | ||||
|     } else if(event == FuriHalSpiBusEventDeactivate) { | ||||
|         LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_SPI2); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| FuriHalSpiBus furi_hal_spi_bus_d = { | ||||
|     .spi = SPI2, | ||||
|     .callback = furi_hal_spi_bus_d_event_callback, | ||||
| }; | ||||
| 
 | ||||
| /* SPI Bus Handles */ | ||||
| 
 | ||||
| inline static void furi_hal_spi_bus_r_handle_event_callback( | ||||
|     FuriHalSpiBusHandle* handle, | ||||
|     FuriHalSpiBusHandleEvent event, | ||||
|     const LL_SPI_InitTypeDef* preset) { | ||||
|     if(event == FuriHalSpiBusHandleEventInit) { | ||||
|         hal_gpio_write(handle->cs, true); | ||||
|         hal_gpio_init(handle->cs, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); | ||||
|     } else if(event == FuriHalSpiBusHandleEventDeinit) { | ||||
|         hal_gpio_write(handle->cs, true); | ||||
|         hal_gpio_init(handle->cs, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||
|     } else if(event == FuriHalSpiBusHandleEventActivate) { | ||||
|         LL_SPI_Init(handle->bus->spi, (LL_SPI_InitTypeDef*)preset); | ||||
|         LL_SPI_SetRxFIFOThreshold(handle->bus->spi, LL_SPI_RX_FIFO_TH_QUARTER); | ||||
|         LL_SPI_Enable(handle->bus->spi); | ||||
| 
 | ||||
|         hal_gpio_init_ex( | ||||
|             handle->miso, | ||||
|             GpioModeAltFunctionPushPull, | ||||
|             GpioPullNo, | ||||
|             GpioSpeedVeryHigh, | ||||
|             GpioAltFn5SPI1); | ||||
|         hal_gpio_init_ex( | ||||
|             handle->mosi, | ||||
|             GpioModeAltFunctionPushPull, | ||||
|             GpioPullNo, | ||||
|             GpioSpeedVeryHigh, | ||||
|             GpioAltFn5SPI1); | ||||
|         hal_gpio_init_ex( | ||||
|             handle->sck, | ||||
|             GpioModeAltFunctionPushPull, | ||||
|             GpioPullNo, | ||||
|             GpioSpeedVeryHigh, | ||||
|             GpioAltFn5SPI1); | ||||
| 
 | ||||
|         hal_gpio_write(handle->cs, false); | ||||
|     } else if(event == FuriHalSpiBusHandleEventDeactivate) { | ||||
|         hal_gpio_write(handle->cs, true); | ||||
| 
 | ||||
|         hal_gpio_init(handle->miso, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||
|         hal_gpio_init(handle->mosi, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||
|         hal_gpio_init(handle->sck, GpioModeAnalog, GpioPullNo, GpioSpeedLow); | ||||
| 
 | ||||
|         LL_SPI_Disable(handle->bus->spi); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void furi_hal_spi_bus_handle_subghz_event_callback( | ||||
|     FuriHalSpiBusHandle* handle, | ||||
|     FuriHalSpiBusHandleEvent event) { | ||||
|     furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_8m); | ||||
| } | ||||
| 
 | ||||
| FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz = { | ||||
|     .bus = &furi_hal_spi_bus_r, | ||||
|     .callback = furi_hal_spi_bus_handle_subghz_event_callback, | ||||
|     .miso = &gpio_spi_r_miso, | ||||
|     .mosi = &gpio_spi_r_mosi, | ||||
|     .sck = &gpio_spi_r_sck, | ||||
|     .cs = &gpio_subghz_cs, | ||||
| }; | ||||
| 
 | ||||
| static void furi_hal_spi_bus_handle_nfc_event_callback( | ||||
|     FuriHalSpiBusHandle* handle, | ||||
|     FuriHalSpiBusHandleEvent event) { | ||||
|     furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_2edge_low_8m); | ||||
| } | ||||
| 
 | ||||
| FuriHalSpiBusHandle furi_hal_spi_bus_handle_nfc = { | ||||
|     .bus = &furi_hal_spi_bus_r, | ||||
|     .callback = furi_hal_spi_bus_handle_nfc_event_callback, | ||||
|     .miso = &gpio_spi_r_miso, | ||||
|     .mosi = &gpio_spi_r_mosi, | ||||
|     .sck = &gpio_spi_r_sck, | ||||
|     .cs = &gpio_nfc_cs, | ||||
| }; | ||||
| 
 | ||||
| static void furi_hal_spi_bus_handle_external_event_callback( | ||||
|     FuriHalSpiBusHandle* handle, | ||||
|     FuriHalSpiBusHandleEvent event) { | ||||
|     furi_hal_spi_bus_r_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_2m); | ||||
| } | ||||
| 
 | ||||
| FuriHalSpiBusHandle furi_hal_spi_bus_handle_external = { | ||||
|     .bus = &furi_hal_spi_bus_r, | ||||
|     .callback = furi_hal_spi_bus_handle_external_event_callback, | ||||
|     .miso = &gpio_ext_pa6, | ||||
|     .mosi = &gpio_ext_pa7, | ||||
|     .sck = &gpio_ext_pb3, | ||||
|     .cs = &gpio_ext_pa4, | ||||
| }; | ||||
| 
 | ||||
| inline static void furi_hal_spi_bus_d_handle_event_callback( | ||||
|     FuriHalSpiBusHandle* handle, | ||||
|     FuriHalSpiBusHandleEvent event, | ||||
|     const LL_SPI_InitTypeDef* preset) { | ||||
|     if(event == FuriHalSpiBusHandleEventInit) { | ||||
|         hal_gpio_write(handle->cs, true); | ||||
|         hal_gpio_init(handle->cs, GpioModeOutputPushPull, GpioPullUp, GpioSpeedVeryHigh); | ||||
| 
 | ||||
|         hal_gpio_init_ex( | ||||
|             handle->miso, | ||||
|             GpioModeAltFunctionPushPull, | ||||
|             GpioPullNo, | ||||
|             GpioSpeedVeryHigh, | ||||
|             GpioAltFn5SPI2); | ||||
|         hal_gpio_init_ex( | ||||
|             handle->mosi, | ||||
|             GpioModeAltFunctionPushPull, | ||||
|             GpioPullNo, | ||||
|             GpioSpeedVeryHigh, | ||||
|             GpioAltFn5SPI2); | ||||
|         hal_gpio_init_ex( | ||||
|             handle->sck, | ||||
|             GpioModeAltFunctionPushPull, | ||||
|             GpioPullNo, | ||||
|             GpioSpeedVeryHigh, | ||||
|             GpioAltFn5SPI2); | ||||
| 
 | ||||
|     } else if(event == FuriHalSpiBusHandleEventDeinit) { | ||||
|         hal_gpio_write(handle->cs, true); | ||||
|         hal_gpio_init(handle->cs, GpioModeAnalog, GpioPullUp, GpioSpeedLow); | ||||
|     } else if(event == FuriHalSpiBusHandleEventActivate) { | ||||
|         LL_SPI_Init(handle->bus->spi, (LL_SPI_InitTypeDef*)preset); | ||||
|         LL_SPI_SetRxFIFOThreshold(handle->bus->spi, LL_SPI_RX_FIFO_TH_QUARTER); | ||||
|         LL_SPI_Enable(handle->bus->spi); | ||||
|         hal_gpio_write(handle->cs, false); | ||||
|     } else if(event == FuriHalSpiBusHandleEventDeactivate) { | ||||
|         hal_gpio_write(handle->cs, true); | ||||
|         LL_SPI_Disable(handle->bus->spi); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void furi_hal_spi_bus_handle_display_event_callback( | ||||
|     FuriHalSpiBusHandle* handle, | ||||
|     FuriHalSpiBusHandleEvent event) { | ||||
|     furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_4m); | ||||
| } | ||||
| 
 | ||||
| FuriHalSpiBusHandle furi_hal_spi_bus_handle_display = { | ||||
|     .bus = &furi_hal_spi_bus_d, | ||||
|     .callback = furi_hal_spi_bus_handle_display_event_callback, | ||||
|     .miso = &gpio_spi_d_miso, | ||||
|     .mosi = &gpio_spi_d_mosi, | ||||
|     .sck = &gpio_spi_d_sck, | ||||
|     .cs = &gpio_display_cs, | ||||
| }; | ||||
| 
 | ||||
| static void furi_hal_spi_bus_handle_sd_fast_event_callback( | ||||
|     FuriHalSpiBusHandle* handle, | ||||
|     FuriHalSpiBusHandleEvent event) { | ||||
|     furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_16m); | ||||
| } | ||||
| 
 | ||||
| FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_fast = { | ||||
|     .bus = &furi_hal_spi_bus_d, | ||||
|     .callback = furi_hal_spi_bus_handle_sd_fast_event_callback, | ||||
|     .miso = &gpio_spi_d_miso, | ||||
|     .mosi = &gpio_spi_d_mosi, | ||||
|     .sck = &gpio_spi_d_sck, | ||||
|     .cs = &gpio_sdcard_cs, | ||||
| }; | ||||
| 
 | ||||
| static void furi_hal_spi_bus_handle_sd_slow_event_callback( | ||||
|     FuriHalSpiBusHandle* handle, | ||||
|     FuriHalSpiBusHandleEvent event) { | ||||
|     furi_hal_spi_bus_d_handle_event_callback(handle, event, &furi_hal_spi_preset_1edge_low_2m); | ||||
| } | ||||
| 
 | ||||
| FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_slow = { | ||||
|     .bus = &furi_hal_spi_bus_d, | ||||
|     .callback = furi_hal_spi_bus_handle_sd_slow_event_callback, | ||||
|     .miso = &gpio_spi_d_miso, | ||||
|     .mosi = &gpio_spi_d_mosi, | ||||
|     .sck = &gpio_spi_d_sck, | ||||
|     .cs = &gpio_sdcard_cs, | ||||
| }; | ||||
| @ -1,61 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <furi_hal_spi_types.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /** Preset for ST25R916 */ | ||||
| extern const LL_SPI_InitTypeDef furi_hal_spi_preset_2edge_low_8m; | ||||
| 
 | ||||
| /** Preset for CC1101 */ | ||||
| extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_8m; | ||||
| 
 | ||||
| /** Preset for ST7567 (Display) */ | ||||
| extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_4m; | ||||
| 
 | ||||
| /** Preset for SdCard in fast mode */ | ||||
| extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_16m; | ||||
| 
 | ||||
| /** Preset for SdCard in slow mode */ | ||||
| extern const LL_SPI_InitTypeDef furi_hal_spi_preset_1edge_low_2m; | ||||
| 
 | ||||
| /** Furi Hal Spi Bus R (Radio: CC1101, Nfc, External)*/ | ||||
| extern FuriHalSpiBus furi_hal_spi_bus_r; | ||||
| 
 | ||||
| /** Furi Hal Spi Bus D (Display, SdCard) */ | ||||
| extern FuriHalSpiBus furi_hal_spi_bus_d; | ||||
| 
 | ||||
| /** CC1101 on `furi_hal_spi_bus_r` */ | ||||
| extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_subghz; | ||||
| 
 | ||||
| /** ST25R3916 on `furi_hal_spi_bus_r` */ | ||||
| extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_nfc; | ||||
| 
 | ||||
| /** External on `furi_hal_spi_bus_r`
 | ||||
|  * Preset: `furi_hal_spi_preset_1edge_low_2m` | ||||
|  *  | ||||
|  * miso: pa6 | ||||
|  * mosi: pa7 | ||||
|  * sck: pb3 | ||||
|  * cs:  pa4 (software controlled) | ||||
|  *  | ||||
|  * @warning not initialized by default, call `furi_hal_spi_bus_handle_init` to initialize | ||||
|  * Bus pins are floating on inactive state, CS high after initialization | ||||
|  *  | ||||
|  */ | ||||
| extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_external; | ||||
| 
 | ||||
| /** ST7567(Display) on `furi_hal_spi_bus_d` */ | ||||
| extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_display; | ||||
| 
 | ||||
| /** SdCard in fast mode on `furi_hal_spi_bus_d` */ | ||||
| extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_fast; | ||||
| 
 | ||||
| /** SdCard in slow mode on `furi_hal_spi_bus_d` */ | ||||
| extern FuriHalSpiBusHandle furi_hal_spi_bus_handle_sd_slow; | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -1,64 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <stddef.h> | ||||
| 
 | ||||
| #include <furi_hal_gpio.h> | ||||
| 
 | ||||
| #include <stm32wbxx_ll_spi.h> | ||||
| #include <stm32wbxx_ll_rcc.h> | ||||
| #include <stm32wbxx_ll_bus.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| typedef struct FuriHalSpiBus FuriHalSpiBus; | ||||
| typedef struct FuriHalSpiBusHandle FuriHalSpiBusHandle; | ||||
| 
 | ||||
| /** FuriHal spi bus states */ | ||||
| typedef enum { | ||||
|     FuriHalSpiBusEventInit, /**< Bus initialization event, called on system start */ | ||||
|     FuriHalSpiBusEventDeinit, /**< Bus deinitialization event, called on system stop */ | ||||
|     FuriHalSpiBusEventLock, /**< Bus lock event, called before activation */ | ||||
|     FuriHalSpiBusEventUnlock, /**< Bus unlock event, called after deactivation */ | ||||
|     FuriHalSpiBusEventActivate, /**< Bus activation event, called before handle activation */ | ||||
|     FuriHalSpiBusEventDeactivate, /**< Bus deactivation event, called after handle deactivation  */ | ||||
| } FuriHalSpiBusEvent; | ||||
| 
 | ||||
| /** FuriHal spi bus event callback */ | ||||
| typedef void (*FuriHalSpiBusEventCallback)(FuriHalSpiBus* bus, FuriHalSpiBusEvent event); | ||||
| 
 | ||||
| /** FuriHal spi bus */ | ||||
| struct FuriHalSpiBus { | ||||
|     SPI_TypeDef* spi; | ||||
|     FuriHalSpiBusEventCallback callback; | ||||
|     FuriHalSpiBusHandle* current_handle; | ||||
| }; | ||||
| 
 | ||||
| /** FuriHal spi handle states */ | ||||
| typedef enum { | ||||
|     FuriHalSpiBusHandleEventInit, /**< Handle init, called on system start, initialize gpio for idle state */ | ||||
|     FuriHalSpiBusHandleEventDeinit, /**< Handle deinit, called on system stop, deinitialize gpio for default state */ | ||||
|     FuriHalSpiBusHandleEventActivate, /**< Handle activate: connect gpio and apply bus config */ | ||||
|     FuriHalSpiBusHandleEventDeactivate, /**< Handle deactivate: disconnect gpio and reset bus config */ | ||||
| } FuriHalSpiBusHandleEvent; | ||||
| 
 | ||||
| /** FuriHal spi handle event callback */ | ||||
| typedef void (*FuriHalSpiBusHandleEventCallback)( | ||||
|     FuriHalSpiBusHandle* handle, | ||||
|     FuriHalSpiBusHandleEvent event); | ||||
| 
 | ||||
| /** FuriHal spi handle */ | ||||
| struct FuriHalSpiBusHandle { | ||||
|     FuriHalSpiBus* bus; | ||||
|     FuriHalSpiBusHandleEventCallback callback; | ||||
|     const GpioPin* miso; | ||||
|     const GpioPin* mosi; | ||||
|     const GpioPin* sck; | ||||
|     const GpioPin* cs; | ||||
| }; | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -1,268 +0,0 @@ | ||||
| #include <furi_hal_version.h> | ||||
| 
 | ||||
| #include <stm32wbxx.h> | ||||
| #include <stm32wbxx_ll_rtc.h> | ||||
| #include <stm32wbxx_ll_system.h> | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| #define FURI_HAL_VERSION_OTP_HEADER_MAGIC 0xBABE | ||||
| #define FURI_HAL_VERSION_OTP_ADDRESS OTP_AREA_BASE | ||||
| 
 | ||||
| /** OTP V0 Structure: prototypes and early EVT */ | ||||
| typedef struct { | ||||
|     uint8_t board_version; | ||||
|     uint8_t board_target; | ||||
|     uint8_t board_body; | ||||
|     uint8_t board_connect; | ||||
|     uint32_t header_timestamp; | ||||
|     char name[FURI_HAL_VERSION_NAME_LENGTH]; | ||||
| } FuriHalVersionOTPv0; | ||||
| 
 | ||||
| /** OTP V1 Structure: late EVT, DVT */ | ||||
| typedef struct { | ||||
|     /* First 64 bits: header */ | ||||
|     uint16_t header_magic; | ||||
|     uint8_t header_version; | ||||
|     uint8_t header_reserved; | ||||
|     uint32_t header_timestamp; | ||||
| 
 | ||||
|     /* Second 64 bits: board info */ | ||||
|     uint8_t board_version; /** Board version */ | ||||
|     uint8_t board_target; /** Board target firmware */ | ||||
|     uint8_t board_body; /** Board body */ | ||||
|     uint8_t board_connect; /** Board interconnect */ | ||||
|     uint8_t board_color; /** Board color */ | ||||
|     uint8_t board_region; /** Board region */ | ||||
|     uint16_t board_reserved; /** Reserved for future use, 0x0000 */ | ||||
| 
 | ||||
|     /* Third 64 bits: Unique Device Name */ | ||||
|     char name[FURI_HAL_VERSION_NAME_LENGTH]; /** Unique Device Name */ | ||||
| } FuriHalVersionOTPv1; | ||||
| 
 | ||||
| /** OTP V2 Structure: DVT2, PVT, Production */ | ||||
| typedef struct { | ||||
|     /* Early First 64 bits: header */ | ||||
|     uint16_t header_magic; | ||||
|     uint8_t header_version; | ||||
|     uint8_t header_reserved; | ||||
|     uint32_t header_timestamp; | ||||
| 
 | ||||
|     /* Early Second 64 bits: board info */ | ||||
|     uint8_t board_version; /** Board version */ | ||||
|     uint8_t board_target; /** Board target firmware */ | ||||
|     uint8_t board_body; /** Board body */ | ||||
|     uint8_t board_connect; /** Board interconnect */ | ||||
|     uint8_t board_display; /** Board display */ | ||||
|     uint8_t board_reserved2_0; /** Reserved for future use, 0x00 */ | ||||
|     uint16_t board_reserved2_1; /** Reserved for future use, 0x0000 */ | ||||
| 
 | ||||
|     /* Late Third 64 bits: device info */ | ||||
|     uint8_t board_color; /** Board color */ | ||||
|     uint8_t board_region; /** Board region */ | ||||
|     uint16_t board_reserved3_0; /** Reserved for future use, 0x0000 */ | ||||
|     uint32_t board_reserved3_1; /** Reserved for future use, 0x00000000 */ | ||||
| 
 | ||||
|     /* Late Fourth 64 bits: Unique Device Name */ | ||||
|     char name[FURI_HAL_VERSION_NAME_LENGTH]; /** Unique Device Name */ | ||||
| } FuriHalVersionOTPv2; | ||||
| 
 | ||||
| /** Represenation Model: */ | ||||
| typedef struct { | ||||
|     uint32_t timestamp; | ||||
| 
 | ||||
|     uint8_t board_version; /** Board version */ | ||||
|     uint8_t board_target; /** Board target firmware */ | ||||
|     uint8_t board_body; /** Board body */ | ||||
|     uint8_t board_connect; /** Board interconnect */ | ||||
|     uint8_t board_color; /** Board color */ | ||||
|     uint8_t board_region; /** Board region */ | ||||
|     uint8_t board_display; /** Board display */ | ||||
| 
 | ||||
|     char name[FURI_HAL_VERSION_ARRAY_NAME_LENGTH]; /** \0 terminated name */ | ||||
|     char device_name[FURI_HAL_VERSION_DEVICE_NAME_LENGTH]; /** device name for special needs */ | ||||
|     uint8_t ble_mac[6]; | ||||
| } FuriHalVersion; | ||||
| 
 | ||||
| static FuriHalVersion furi_hal_version = {0}; | ||||
| 
 | ||||
| static void furi_hal_version_set_name(const char* name) { | ||||
|     furi_hal_version.device_name[0] = 0; | ||||
| } | ||||
| 
 | ||||
| static void furi_hal_version_load_otp_default() { | ||||
|     furi_hal_version_set_name(NULL); | ||||
| } | ||||
| 
 | ||||
| static void furi_hal_version_load_otp_v0() { | ||||
|     const FuriHalVersionOTPv0* otp = (FuriHalVersionOTPv0*)FURI_HAL_VERSION_OTP_ADDRESS; | ||||
| 
 | ||||
|     furi_hal_version.timestamp = otp->header_timestamp; | ||||
|     furi_hal_version.board_version = otp->board_version; | ||||
|     furi_hal_version.board_target = otp->board_target; | ||||
|     furi_hal_version.board_body = otp->board_body; | ||||
|     furi_hal_version.board_connect = otp->board_connect; | ||||
| 
 | ||||
|     furi_hal_version_set_name(otp->name); | ||||
| } | ||||
| 
 | ||||
| static void furi_hal_version_load_otp_v1() { | ||||
|     const FuriHalVersionOTPv1* otp = (FuriHalVersionOTPv1*)FURI_HAL_VERSION_OTP_ADDRESS; | ||||
| 
 | ||||
|     furi_hal_version.timestamp = otp->header_timestamp; | ||||
|     furi_hal_version.board_version = otp->board_version; | ||||
|     furi_hal_version.board_target = otp->board_target; | ||||
|     furi_hal_version.board_body = otp->board_body; | ||||
|     furi_hal_version.board_connect = otp->board_connect; | ||||
|     furi_hal_version.board_color = otp->board_color; | ||||
|     furi_hal_version.board_region = otp->board_region; | ||||
| 
 | ||||
|     furi_hal_version_set_name(otp->name); | ||||
| } | ||||
| 
 | ||||
| static void furi_hal_version_load_otp_v2() { | ||||
|     const FuriHalVersionOTPv2* otp = (FuriHalVersionOTPv2*)FURI_HAL_VERSION_OTP_ADDRESS; | ||||
| 
 | ||||
|     // 1st block, programmed afer baking
 | ||||
|     furi_hal_version.timestamp = otp->header_timestamp; | ||||
| 
 | ||||
|     // 2nd block, programmed afer baking
 | ||||
|     furi_hal_version.board_version = otp->board_version; | ||||
|     furi_hal_version.board_target = otp->board_target; | ||||
|     furi_hal_version.board_body = otp->board_body; | ||||
|     furi_hal_version.board_connect = otp->board_connect; | ||||
|     furi_hal_version.board_display = otp->board_display; | ||||
| 
 | ||||
|     // 3rd and 4th blocks, programmed on FATP stage
 | ||||
|     if(otp->board_color != 0xFF) { | ||||
|         furi_hal_version.board_color = otp->board_color; | ||||
|         furi_hal_version.board_region = otp->board_region; | ||||
|         furi_hal_version_set_name(otp->name); | ||||
|     } else { | ||||
|         furi_hal_version.board_color = 0; | ||||
|         furi_hal_version.board_region = 0; | ||||
|         furi_hal_version_set_name(NULL); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void furi_hal_version_init() { | ||||
|     switch(furi_hal_version_get_otp_version()) { | ||||
|     case FuriHalVersionOtpVersionUnknown: | ||||
|         furi_hal_version_load_otp_default(); | ||||
|         break; | ||||
|     case FuriHalVersionOtpVersionEmpty: | ||||
|         furi_hal_version_load_otp_default(); | ||||
|         break; | ||||
|     case FuriHalVersionOtpVersion0: | ||||
|         furi_hal_version_load_otp_v0(); | ||||
|         break; | ||||
|     case FuriHalVersionOtpVersion1: | ||||
|         furi_hal_version_load_otp_v1(); | ||||
|         break; | ||||
|     case FuriHalVersionOtpVersion2: | ||||
|         furi_hal_version_load_otp_v2(); | ||||
|         break; | ||||
|     default: | ||||
|         furi_hal_version_load_otp_default(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_version_do_i_belong_here() { | ||||
|     return furi_hal_version_get_hw_target() == 7; | ||||
| } | ||||
| 
 | ||||
| const char* furi_hal_version_get_model_name() { | ||||
|     return "Flipper Zero"; | ||||
| } | ||||
| 
 | ||||
| const FuriHalVersionOtpVersion furi_hal_version_get_otp_version() { | ||||
|     if(*(uint64_t*)FURI_HAL_VERSION_OTP_ADDRESS == 0xFFFFFFFF) { | ||||
|         return FuriHalVersionOtpVersionEmpty; | ||||
|     } else { | ||||
|         if(((FuriHalVersionOTPv1*)FURI_HAL_VERSION_OTP_ADDRESS)->header_magic == | ||||
|            FURI_HAL_VERSION_OTP_HEADER_MAGIC) { | ||||
|             // Version 1+
 | ||||
|             uint8_t version = ((FuriHalVersionOTPv1*)FURI_HAL_VERSION_OTP_ADDRESS)->header_version; | ||||
|             if(version >= FuriHalVersionOtpVersion1 && version <= FuriHalVersionOtpVersion2) { | ||||
|                 return version; | ||||
|             } else { | ||||
|                 return FuriHalVersionOtpVersionUnknown; | ||||
|             } | ||||
|         } else if(((FuriHalVersionOTPv0*)FURI_HAL_VERSION_OTP_ADDRESS)->board_version <= 10) { | ||||
|             // Version 0
 | ||||
|             return FuriHalVersionOtpVersion0; | ||||
|         } else { | ||||
|             // Version Unknown
 | ||||
|             return FuriHalVersionOtpVersionUnknown; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| const uint8_t furi_hal_version_get_hw_version() { | ||||
|     return furi_hal_version.board_version; | ||||
| } | ||||
| 
 | ||||
| const uint8_t furi_hal_version_get_hw_target() { | ||||
|     return furi_hal_version.board_target; | ||||
| } | ||||
| 
 | ||||
| const uint8_t furi_hal_version_get_hw_body() { | ||||
|     return furi_hal_version.board_body; | ||||
| } | ||||
| 
 | ||||
| const FuriHalVersionColor furi_hal_version_get_hw_color() { | ||||
|     return furi_hal_version.board_color; | ||||
| } | ||||
| 
 | ||||
| const uint8_t furi_hal_version_get_hw_connect() { | ||||
|     return furi_hal_version.board_connect; | ||||
| } | ||||
| 
 | ||||
| const FuriHalVersionRegion furi_hal_version_get_hw_region() { | ||||
|     return furi_hal_version.board_region; | ||||
| } | ||||
| 
 | ||||
| const FuriHalVersionDisplay furi_hal_version_get_hw_display() { | ||||
|     return furi_hal_version.board_display; | ||||
| } | ||||
| 
 | ||||
| const uint32_t furi_hal_version_get_hw_timestamp() { | ||||
|     return furi_hal_version.timestamp; | ||||
| } | ||||
| 
 | ||||
| const char* furi_hal_version_get_name_ptr() { | ||||
|     return *furi_hal_version.name == 0x00 ? NULL : furi_hal_version.name; | ||||
| } | ||||
| 
 | ||||
| const char* furi_hal_version_get_device_name_ptr() { | ||||
|     return furi_hal_version.device_name + 1; | ||||
| } | ||||
| 
 | ||||
| const char* furi_hal_version_get_ble_local_device_name_ptr() { | ||||
|     return furi_hal_version.device_name; | ||||
| } | ||||
| 
 | ||||
| const uint8_t* furi_hal_version_get_ble_mac() { | ||||
|     return furi_hal_version.ble_mac; | ||||
| } | ||||
| 
 | ||||
| const struct Version* furi_hal_version_get_firmware_version(void) { | ||||
|     return version_get(); | ||||
| } | ||||
| 
 | ||||
| const struct Version* furi_hal_version_get_bootloader_version(void) { | ||||
| #ifdef NO_BOOTLOADER | ||||
|     return 0; | ||||
| #else | ||||
|     /* Backup register which points to structure in flash memory */ | ||||
|     return (const struct Version*)LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR1); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| size_t furi_hal_version_uid_size() { | ||||
|     return 64 / 8; | ||||
| } | ||||
| 
 | ||||
| const uint8_t* furi_hal_version_uid() { | ||||
|     return (const uint8_t*)UID64_BASE; | ||||
| } | ||||
| @ -1,108 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stm32wbxx.h> | ||||
| #include <stm32wbxx_ll_gpio.h> | ||||
| #include <stm32wbxx_ll_spi.h> | ||||
| 
 | ||||
| #define BUTTON_BACK_GPIO_Port GPIOC | ||||
| #define BUTTON_BACK_Pin LL_GPIO_PIN_13 | ||||
| #define BUTTON_DOWN_GPIO_Port GPIOC | ||||
| #define BUTTON_DOWN_Pin LL_GPIO_PIN_6 | ||||
| #define BUTTON_LEFT_GPIO_Port GPIOB | ||||
| #define BUTTON_LEFT_Pin LL_GPIO_PIN_11 | ||||
| #define BUTTON_OK_GPIO_Port GPIOH | ||||
| #define BUTTON_OK_Pin LL_GPIO_PIN_3 | ||||
| #define BUTTON_RIGHT_GPIO_Port GPIOB | ||||
| #define BUTTON_RIGHT_Pin LL_GPIO_PIN_12 | ||||
| #define BUTTON_UP_GPIO_Port GPIOB | ||||
| #define BUTTON_UP_Pin LL_GPIO_PIN_10 | ||||
| 
 | ||||
| #define CC1101_CS_GPIO_Port GPIOD | ||||
| #define CC1101_CS_Pin LL_GPIO_PIN_0 | ||||
| #define CC1101_G0_GPIO_Port GPIOA | ||||
| #define CC1101_G0_Pin LL_GPIO_PIN_1 | ||||
| 
 | ||||
| #define DISPLAY_CS_GPIO_Port GPIOC | ||||
| #define DISPLAY_CS_Pin LL_GPIO_PIN_11 | ||||
| #define DISPLAY_DI_GPIO_Port GPIOB | ||||
| #define DISPLAY_DI_Pin LL_GPIO_PIN_1 | ||||
| #define DISPLAY_RST_GPIO_Port GPIOB | ||||
| #define DISPLAY_RST_Pin LL_GPIO_PIN_0 | ||||
| 
 | ||||
| #define IR_RX_GPIO_Port GPIOA | ||||
| #define IR_RX_Pin LL_GPIO_PIN_0 | ||||
| #define IR_TX_GPIO_Port GPIOB | ||||
| #define IR_TX_Pin LL_GPIO_PIN_9 | ||||
| 
 | ||||
| #define NFC_CS_GPIO_Port GPIOE | ||||
| #define NFC_CS_Pin LL_GPIO_PIN_4 | ||||
| 
 | ||||
| #define PA4_GPIO_Port GPIOA | ||||
| #define PA4_Pin LL_GPIO_PIN_4 | ||||
| #define PA6_GPIO_Port GPIOA | ||||
| #define PA6_Pin LL_GPIO_PIN_6 | ||||
| #define PA7_GPIO_Port GPIOA | ||||
| #define PA7_Pin LL_GPIO_PIN_7 | ||||
| #define PB2_GPIO_Port GPIOB | ||||
| #define PB2_Pin LL_GPIO_PIN_2 | ||||
| #define PB3_GPIO_Port GPIOB | ||||
| #define PB3_Pin LL_GPIO_PIN_3 | ||||
| #define PC0_GPIO_Port GPIOC | ||||
| #define PC0_Pin LL_GPIO_PIN_0 | ||||
| #define PC1_GPIO_Port GPIOC | ||||
| #define PC1_Pin LL_GPIO_PIN_1 | ||||
| #define PC3_GPIO_Port GPIOC | ||||
| #define PC3_Pin LL_GPIO_PIN_3 | ||||
| 
 | ||||
| #define PERIPH_POWER_GPIO_Port GPIOA | ||||
| #define PERIPH_POWER_Pin LL_GPIO_PIN_3 | ||||
| 
 | ||||
| #define QUARTZ_32MHZ_IN_GPIO_Port GPIOC | ||||
| #define QUARTZ_32MHZ_IN_Pin LL_GPIO_PIN_14 | ||||
| #define QUARTZ_32MHZ_OUT_GPIO_Port GPIOC | ||||
| #define QUARTZ_32MHZ_OUT_Pin LL_GPIO_PIN_15 | ||||
| 
 | ||||
| #define RFID_OUT_GPIO_Port GPIOB | ||||
| #define RFID_OUT_Pin LL_GPIO_PIN_13 | ||||
| #define RFID_PULL_GPIO_Port GPIOA | ||||
| #define RFID_PULL_Pin LL_GPIO_PIN_2 | ||||
| #define RFID_RF_IN_GPIO_Port GPIOC | ||||
| #define RFID_RF_IN_Pin LL_GPIO_PIN_5 | ||||
| #define RFID_TUNE_GPIO_Port GPIOA | ||||
| #define RFID_TUNE_Pin LL_GPIO_PIN_8 | ||||
| 
 | ||||
| #define RF_SW_0_GPIO_Port GPIOC | ||||
| #define RF_SW_0_Pin LL_GPIO_PIN_4 | ||||
| 
 | ||||
| #define SD_CD_GPIO_Port GPIOC | ||||
| #define SD_CD_Pin LL_GPIO_PIN_10 | ||||
| #define SD_CS_GPIO_Port GPIOC | ||||
| #define SD_CS_Pin LL_GPIO_PIN_12 | ||||
| 
 | ||||
| #define SPEAKER_GPIO_Port GPIOB | ||||
| #define SPEAKER_Pin LL_GPIO_PIN_8 | ||||
| 
 | ||||
| #define VIBRO_GPIO_Port GPIOA | ||||
| #define VIBRO_Pin LL_GPIO_PIN_15 | ||||
| 
 | ||||
| #define iBTN_GPIO_Port GPIOB | ||||
| #define iBTN_Pin LL_GPIO_PIN_14 | ||||
| 
 | ||||
| #define USART1_TX_Pin LL_GPIO_PIN_6 | ||||
| #define USART1_TX_Port GPIOB | ||||
| #define USART1_RX_Pin LL_GPIO_PIN_7 | ||||
| #define USART1_RX_Port GPIOB | ||||
| 
 | ||||
| #define SPI_D_MISO_GPIO_Port GPIOC | ||||
| #define SPI_D_MISO_Pin LL_GPIO_PIN_2 | ||||
| #define SPI_D_MOSI_GPIO_Port GPIOB | ||||
| #define SPI_D_MOSI_Pin LL_GPIO_PIN_15 | ||||
| #define SPI_D_SCK_GPIO_Port GPIOD | ||||
| #define SPI_D_SCK_Pin LL_GPIO_PIN_1 | ||||
| 
 | ||||
| #define SPI_R_MISO_GPIO_Port GPIOB | ||||
| #define SPI_R_MISO_Pin LL_GPIO_PIN_4 | ||||
| #define SPI_R_MOSI_GPIO_Port GPIOB | ||||
| #define SPI_R_MOSI_Pin LL_GPIO_PIN_5 | ||||
| #define SPI_R_SCK_GPIO_Port GPIOA | ||||
| #define SPI_R_SCK_Pin LL_GPIO_PIN_5 | ||||
| @ -1,187 +0,0 @@ | ||||
| /** | ||||
| ***************************************************************************** | ||||
| ** | ||||
| **  File        : stm32wb55xx_flash_cm4.ld | ||||
| ** | ||||
| **  Abstract    : System Workbench Minimal System calls file | ||||
| ** | ||||
| ** 		          For more information about which c-functions | ||||
| **                need which of these lowlevel functions | ||||
| **                please consult the Newlib libc-manual | ||||
| ** | ||||
| **  Environment : System Workbench for MCU | ||||
| ** | ||||
| **  Distribution: The file is distributed “as is,” without any warranty | ||||
| **                of any kind. | ||||
| ** | ||||
| ***************************************************************************** | ||||
| ** | ||||
| ** <h2><center>© COPYRIGHT(c) 2019 Ac6</center></h2> | ||||
| ** | ||||
| ** Redistribution and use in source and binary forms, with or without modification, | ||||
| ** are permitted provided that the following conditions are met: | ||||
| **   1. Redistributions of source code must retain the above copyright notice, | ||||
| **      this list of conditions and the following disclaimer. | ||||
| **   2. Redistributions in binary form must reproduce the above copyright notice, | ||||
| **      this list of conditions and the following disclaimer in the documentation | ||||
| **      and/or other materials provided with the distribution. | ||||
| **   3. Neither the name of Ac6 nor the names of its contributors | ||||
| **      may be used to endorse or promote products derived from this software | ||||
| **      without specific prior written permission. | ||||
| ** | ||||
| ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||
| ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||
| ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||||
| ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
| ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||
| ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||
| ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
| ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| ** | ||||
| ***************************************************************************** | ||||
| */ | ||||
| 
 | ||||
| /* Entry Point */ | ||||
| ENTRY(Reset_Handler) | ||||
| 
 | ||||
| /* Highest address of the user mode stack */ | ||||
| _estack = 0x20030000;    /* end of RAM */ | ||||
| /* Generate a link error if heap and stack don't fit into RAM */ | ||||
| _Min_Heap_Size = 0x200;      /* required amount of heap  */ | ||||
| _Min_Stack_Size = 0x400; /* required amount of stack */ | ||||
| 
 | ||||
| /* Specify the memory areas */ | ||||
| MEMORY | ||||
| { | ||||
| FLASH (rx)                 : ORIGIN = 0x08000000, LENGTH = 32K | ||||
| RAM1 (xrw)                 : ORIGIN = 0x20000008, LENGTH = 0x2FFF8 | ||||
| RAM_SHARED (xrw)           : ORIGIN = 0x20030000, LENGTH = 10K | ||||
| } | ||||
| 
 | ||||
| /* Define output sections */ | ||||
| SECTIONS | ||||
| { | ||||
|   /* The startup code goes first into FLASH */ | ||||
|   .isr_vector : | ||||
|   { | ||||
|     . = ALIGN(4); | ||||
|     KEEP(*(.isr_vector)) /* Startup code */ | ||||
|     . = ALIGN(4); | ||||
|   } >FLASH | ||||
| 
 | ||||
|   /* The program code and other data goes into FLASH */ | ||||
|   .text : | ||||
|   { | ||||
|     . = ALIGN(4); | ||||
|     *(.text)           /* .text sections (code) */ | ||||
|     *(.text*)          /* .text* sections (code) */ | ||||
|     *(.glue_7)         /* glue arm to thumb code */ | ||||
|     *(.glue_7t)        /* glue thumb to arm code */ | ||||
|     *(.eh_frame) | ||||
| 
 | ||||
|     KEEP (*(.init)) | ||||
|     KEEP (*(.fini)) | ||||
| 
 | ||||
|     . = ALIGN(4); | ||||
|     _etext = .;        /* define a global symbols at end of code */ | ||||
|   } >FLASH | ||||
| 
 | ||||
|   /* Constant data goes into FLASH */ | ||||
|   .rodata : | ||||
|   { | ||||
|     . = ALIGN(4); | ||||
|     *(.rodata)         /* .rodata sections (constants, strings, etc.) */ | ||||
|     *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */ | ||||
|     . = ALIGN(4); | ||||
|   } >FLASH | ||||
| 
 | ||||
|   .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH | ||||
|   .ARM : { | ||||
|     __exidx_start = .; | ||||
|     *(.ARM.exidx*) | ||||
|     __exidx_end = .; | ||||
|   } >FLASH | ||||
| 
 | ||||
|   .preinit_array     : | ||||
|   { | ||||
|     PROVIDE_HIDDEN (__preinit_array_start = .); | ||||
|     KEEP (*(.preinit_array*)) | ||||
|     PROVIDE_HIDDEN (__preinit_array_end = .); | ||||
|   } >FLASH | ||||
|   .init_array : | ||||
|   { | ||||
|     PROVIDE_HIDDEN (__init_array_start = .); | ||||
|     KEEP (*(SORT(.init_array.*))) | ||||
|     KEEP (*(.init_array*)) | ||||
|     PROVIDE_HIDDEN (__init_array_end = .); | ||||
|   } >FLASH | ||||
|   .fini_array : | ||||
|   { | ||||
|     PROVIDE_HIDDEN (__fini_array_start = .); | ||||
|     KEEP (*(SORT(.fini_array.*))) | ||||
|     KEEP (*(.fini_array*)) | ||||
|     PROVIDE_HIDDEN (__fini_array_end = .); | ||||
|   } >FLASH | ||||
| 
 | ||||
|   /* used by the startup to initialize data */ | ||||
|   _sidata = LOADADDR(.data); | ||||
| 
 | ||||
|   /* Initialized data sections goes into RAM, load LMA copy after code */ | ||||
|   .data :  | ||||
|   { | ||||
|     . = ALIGN(4); | ||||
|     _sdata = .;        /* create a global symbol at data start */ | ||||
|     *(.data)           /* .data sections */ | ||||
|     *(.data*)          /* .data* sections */ | ||||
| 
 | ||||
|     . = ALIGN(4); | ||||
|     _edata = .;        /* define a global symbol at data end */ | ||||
|   } >RAM1 AT> FLASH | ||||
| 
 | ||||
|    | ||||
|   /* Uninitialized data section */ | ||||
|   . = ALIGN(4); | ||||
|   .bss : | ||||
|   { | ||||
|     /* This is used by the startup in order to initialize the .bss secion */ | ||||
|     _sbss = .;         /* define a global symbol at bss start */ | ||||
|     __bss_start__ = _sbss; | ||||
|     *(.bss) | ||||
|     *(.bss*) | ||||
|     *(COMMON) | ||||
| 
 | ||||
|     . = ALIGN(4); | ||||
|     _ebss = .;         /* define a global symbol at bss end */ | ||||
|     __bss_end__ = _ebss; | ||||
|   } >RAM1 | ||||
| 
 | ||||
|   /* User_heap_stack section, used to check that there is enough RAM left */ | ||||
|   ._user_heap_stack : | ||||
|   { | ||||
|     . = ALIGN(8); | ||||
|     PROVIDE ( end = . ); | ||||
|     PROVIDE ( _end = . ); | ||||
|     . = . + _Min_Heap_Size; | ||||
|     . = . + _Min_Stack_Size; | ||||
|     . = ALIGN(8); | ||||
|   } >RAM1 | ||||
| 
 | ||||
|    | ||||
| 
 | ||||
|   /* Remove information from the standard libraries */ | ||||
|   /DISCARD/ : | ||||
|   { | ||||
|     libc.a ( * ) | ||||
|     libm.a ( * ) | ||||
|     libgcc.a ( * ) | ||||
|   } | ||||
| 
 | ||||
|   .ARM.attributes 0       : { *(.ARM.attributes) } | ||||
|    MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED | ||||
|    MB_MEM1 (NOLOAD)       : { *(MB_MEM1) } >RAM_SHARED | ||||
|    MB_MEM2 (NOLOAD)       : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -1,264 +0,0 @@ | ||||
| #include <target.h> | ||||
| #include <stm32wbxx.h> | ||||
| #include <stm32wbxx_ll_system.h> | ||||
| #include <stm32wbxx_ll_bus.h> | ||||
| #include <stm32wbxx_ll_utils.h> | ||||
| #include <stm32wbxx_ll_rcc.h> | ||||
| #include <stm32wbxx_ll_rtc.h> | ||||
| #include <stm32wbxx_ll_pwr.h> | ||||
| #include <stm32wbxx_ll_gpio.h> | ||||
| #include <stm32wbxx_hal_flash.h> | ||||
| 
 | ||||
| #include <lib/toolbox/version.h> | ||||
| #include <furi_hal.h> | ||||
| 
 | ||||
| #include <u8g2.h> | ||||
| #include <u8g2_glue.h> | ||||
| 
 | ||||
| const uint8_t I_DFU_128x50[] = { | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x00, 0x00, | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x38, 0x00, 0x00, 0x00, | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0xC0, 0x00, 0x00, 0x00, | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x75, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x0A, 0x00, 0x00, 0x0F, 0x60, 0x00, 0x00, | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xE0, 0x0F, 0x00, 0xC0, 0xE0, 0x4F, 0x00, 0x00, | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x30, 0x1E, 0x90, 0x00, 0x00, | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x18, 0x00, 0x8C, 0x01, 0xA0, 0x00, 0x00, | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x81, 0xFF, 0x19, 0x00, 0x63, 0x00, 0xC0, 0xF0, 0x07, | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x60, 0x5E, 0x1F, 0x80, 0x18, 0x00, 0xE0, 0x0E, 0x18, | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x18, 0xAF, 0x0F, 0x40, 0x06, 0x00, 0xF8, 0x01, 0x20, | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x06, 0x57, 0x01, 0x20, 0x01, 0x00, 0x78, 0x00, 0x3E, | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x81, 0xAF, 0x02, 0x90, 0x00, 0x00, 0x38, 0x80, 0x41, | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x80, 0x57, 0x01, 0x48, 0x00, 0x00, 0x10, 0x60, 0x40, | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x10, 0x80, 0xAB, 0x00, 0x24, 0x00, 0x00, 0x08, 0x10, 0x40, | ||||
|     0x3F, 0x00, 0x00, 0x00, 0x00, 0x38, 0x0C, 0xC0, 0x57, 0x01, 0x12, 0x00, 0x00, 0x04, 0x08, 0x40, | ||||
|     0xC0, 0x0F, 0x00, 0x00, 0xC0, 0x07, 0x03, 0xF0, 0xAB, 0x00, 0x0A, 0x00, 0x00, 0x02, 0x04, 0x40, | ||||
|     0x00, 0xF0, 0x1F, 0x80, 0x3F, 0xC0, 0x00, 0xFC, 0x55, 0x01, 0x05, 0xE0, 0x00, 0x01, 0x04, 0x40, | ||||
|     0x00, 0x00, 0xE0, 0x7F, 0x00, 0x30, 0x00, 0xFF, 0xAB, 0x00, 0x05, 0xE0, 0x80, 0x00, 0x02, 0x40, | ||||
|     0x0F, 0x00, 0x00, 0x00, 0x80, 0x0F, 0xE0, 0xCF, 0x55, 0x81, 0x02, 0xF0, 0x40, 0x00, 0x02, 0x40, | ||||
|     0xF0, 0x0F, 0x00, 0x00, 0x7F, 0x00, 0xFE, 0xC3, 0xAB, 0x80, 0x02, 0x78, 0x20, 0x00, 0x01, 0x40, | ||||
|     0x00, 0xF0, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xC0, 0xD5, 0x81, 0x01, 0x7E, 0x10, 0x80, 0x00, 0x20, | ||||
|     0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x0F, 0xE0, 0xFA, 0x83, 0xC1, 0x3F, 0x08, 0x80, 0x00, 0x20, | ||||
|     0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0xD8, 0x07, 0x83, 0xF1, 0x1F, 0x04, 0x40, 0x00, 0x20, | ||||
|     0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0x0F, 0x80, 0xC7, 0x01, 0x83, 0xF1, 0x0F, 0x00, 0x20, 0x00, 0x10, | ||||
|     0xE0, 0xFF, 0xFF, 0xFF, 0x3F, 0xC0, 0x7F, 0x40, 0x80, 0x83, 0xE1, 0x01, 0x00, 0x20, 0x00, 0x18, | ||||
|     0xFC, 0xFF, 0xFF, 0xFF, 0x03, 0x3F, 0x00, 0x20, 0xFC, 0x83, 0x01, 0x00, 0x00, 0x10, 0x00, 0x18, | ||||
|     0xFF, 0xFF, 0xFF, 0x3F, 0xF0, 0x00, 0x00, 0x10, 0xD7, 0x01, 0x03, 0x00, 0x00, 0x08, 0x00, 0x1C, | ||||
|     0xFF, 0xFF, 0x01, 0x00, 0x0F, 0x00, 0x00, 0x88, 0xAB, 0x02, 0xE3, 0x01, 0x00, 0x08, 0x00, 0x0C, | ||||
|     0xFF, 0x07, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xC4, 0x55, 0x05, 0x1E, 0x00, 0x00, 0x04, 0x00, 0x0E, | ||||
|     0x7F, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xA3, 0xAB, 0x02, 0x06, 0x00, 0x00, 0x02, 0x00, 0x0F, | ||||
|     0x0F, 0x00, 0x80, 0x03, 0x00, 0x00, 0xC0, 0x10, 0x57, 0x05, 0x02, 0x00, 0x00, 0x01, 0x80, 0x07, | ||||
|     0x03, 0x00, 0x70, 0x00, 0x00, 0x00, 0x30, 0x08, 0xAB, 0x0A, 0x02, 0x00, 0xC0, 0x00, 0xC0, 0x07, | ||||
|     0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x84, 0x57, 0x15, 0x01, 0x00, 0x30, 0x00, 0xE0, 0x07, | ||||
|     0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0xC3, 0xFF, 0x2A, 0x01, 0x00, 0x0C, 0x00, 0xF0, 0x0F, | ||||
|     0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0xC0, 0xE0, 0xFE, 0x55, 0x01, 0x82, 0x03, 0x00, 0xF8, 0x15, | ||||
|     0x00, 0x30, 0x00, 0x00, 0x00, 0x1C, 0x30, 0x78, 0xFE, 0xAA, 0x01, 0x7C, 0x00, 0x00, 0xFC, 0x23, | ||||
|     0x00, 0x0E, 0x00, 0x00, 0xC0, 0x03, 0x0C, 0x3C, 0x7F, 0x5D, 0x01, 0x00, 0x00, 0x00, 0xFF, 0x45, | ||||
|     0xC0, 0x01, 0x00, 0x00, 0x3E, 0x00, 0x02, 0x8F, 0xBF, 0xAE, 0x03, 0x00, 0x00, 0xC0, 0xFF, 0x82, | ||||
|     0x30, 0x00, 0x00, 0xC0, 0x01, 0x80, 0xC1, 0x43, 0xFE, 0x5D, 0x01, 0x00, 0x00, 0xF0, 0xFF, 0x05, | ||||
|     0x0F, 0x00, 0x80, 0x3F, 0x00, 0x60, 0xF0, 0x31, 0xF6, 0xAE, 0x03, 0x00, 0x00, 0xFA, 0xAF, 0x02, | ||||
|     0xFC, 0xFF, 0x7F, 0x00, 0x00, 0x18, 0x7C, 0x08, 0x23, 0xFF, 0x05, 0x00, 0x00, 0xFD, 0x55, 0x01, | ||||
|     0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x1F, 0x84, 0x30, 0xFE, 0x0A, 0x00, 0x00, 0xAA, 0xAA, 0x00, | ||||
|     0x00, 0x00, 0x00, 0x00, 0x80, 0xF1, 0x07, 0x43, 0x18, 0xFF, 0x15, 0x00, 0x00, 0x54, 0x15, 0x00, | ||||
|     0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x80, 0x20, 0x8C, 0xFF, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||
| }; | ||||
| 
 | ||||
| // Boot request enum
 | ||||
| #define BOOT_REQUEST_TAINTED 0x00000000 | ||||
| #define BOOT_REQUEST_CLEAN 0xDADEDADE | ||||
| #define BOOT_REQUEST_DFU 0xDF00B000 | ||||
| // Boot to DFU pin
 | ||||
| #define BOOT_DFU_PORT GPIOB | ||||
| #define BOOT_DFU_PIN LL_GPIO_PIN_11 | ||||
| // USB pins
 | ||||
| #define BOOT_USB_PORT GPIOA | ||||
| #define BOOT_USB_DM_PIN LL_GPIO_PIN_11 | ||||
| #define BOOT_USB_DP_PIN LL_GPIO_PIN_12 | ||||
| #define BOOT_USB_PIN (BOOT_USB_DM_PIN | BOOT_USB_DP_PIN) | ||||
| 
 | ||||
| #define RTC_CLOCK_IS_READY() (LL_RCC_LSE_IsReady() && LL_RCC_LSI1_IsReady()) | ||||
| 
 | ||||
| void target_led_control(char* c) { | ||||
|     furi_hal_light_set(LightRed, 0x00); | ||||
|     furi_hal_light_set(LightGreen, 0x00); | ||||
|     furi_hal_light_set(LightBlue, 0x00); | ||||
|     do { | ||||
|         if(*c == 'R') { | ||||
|             furi_hal_light_set(LightRed, 0xFF); | ||||
|         } else if(*c == 'G') { | ||||
|             furi_hal_light_set(LightGreen, 0xFF); | ||||
|         } else if(*c == 'B') { | ||||
|             furi_hal_light_set(LightBlue, 0xFF); | ||||
|         } else if(*c == '.') { | ||||
|             LL_mDelay(125); | ||||
|             furi_hal_light_set(LightRed, 0x00); | ||||
|             furi_hal_light_set(LightGreen, 0x00); | ||||
|             furi_hal_light_set(LightBlue, 0x00); | ||||
|             LL_mDelay(125); | ||||
|         } else if(*c == '-') { | ||||
|             LL_mDelay(250); | ||||
|             furi_hal_light_set(LightRed, 0x00); | ||||
|             furi_hal_light_set(LightGreen, 0x00); | ||||
|             furi_hal_light_set(LightBlue, 0x00); | ||||
|             LL_mDelay(250); | ||||
|         } else if(*c == '|') { | ||||
|             furi_hal_light_set(LightRed, 0x00); | ||||
|             furi_hal_light_set(LightGreen, 0x00); | ||||
|             furi_hal_light_set(LightBlue, 0x00); | ||||
|         } | ||||
|         c++; | ||||
|     } while(*c != 0); | ||||
| } | ||||
| 
 | ||||
| void target_clock_init() { | ||||
|     LL_Init1msTick(4000000); | ||||
|     LL_SetSystemCoreClock(4000000); | ||||
| 
 | ||||
|     LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); | ||||
|     LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB); | ||||
|     LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC); | ||||
|     LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOD); | ||||
|     LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOE); | ||||
|     LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOH); | ||||
| 
 | ||||
|     LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1); | ||||
|     LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2); | ||||
| } | ||||
| 
 | ||||
| void target_gpio_init() { | ||||
|     // USB D+
 | ||||
|     LL_GPIO_SetPinMode(BOOT_USB_PORT, BOOT_USB_DP_PIN, LL_GPIO_MODE_OUTPUT); | ||||
|     LL_GPIO_SetPinSpeed(BOOT_USB_PORT, BOOT_USB_DP_PIN, LL_GPIO_SPEED_FREQ_VERY_HIGH); | ||||
|     LL_GPIO_SetPinOutputType(BOOT_USB_PORT, BOOT_USB_DP_PIN, LL_GPIO_OUTPUT_OPENDRAIN); | ||||
|     // USB D-
 | ||||
|     LL_GPIO_SetPinMode(BOOT_USB_PORT, BOOT_USB_DM_PIN, LL_GPIO_MODE_OUTPUT); | ||||
|     LL_GPIO_SetPinSpeed(BOOT_USB_PORT, BOOT_USB_DM_PIN, LL_GPIO_SPEED_FREQ_VERY_HIGH); | ||||
|     LL_GPIO_SetPinOutputType(BOOT_USB_PORT, BOOT_USB_DM_PIN, LL_GPIO_OUTPUT_OPENDRAIN); | ||||
|     // Button: back
 | ||||
|     LL_GPIO_SetPinMode(BOOT_DFU_PORT, BOOT_DFU_PIN, LL_GPIO_MODE_INPUT); | ||||
|     LL_GPIO_SetPinPull(BOOT_DFU_PORT, BOOT_DFU_PIN, LL_GPIO_PULL_UP); | ||||
| } | ||||
| 
 | ||||
| void target_rtc_init() { | ||||
|     // LSE and RTC
 | ||||
|     LL_PWR_EnableBkUpAccess(); | ||||
|     if(!RTC_CLOCK_IS_READY()) { | ||||
|         // Start LSI1 needed for CSS
 | ||||
|         LL_RCC_LSI1_Enable(); | ||||
|         // Try to start LSE normal way
 | ||||
|         LL_RCC_LSE_SetDriveCapability(LL_RCC_LSEDRIVE_HIGH); | ||||
|         LL_RCC_LSE_Enable(); | ||||
|         uint32_t c = 0; | ||||
|         while(!RTC_CLOCK_IS_READY() && c < 200) { | ||||
|             LL_mDelay(10); | ||||
|             c++; | ||||
|         } | ||||
|         // Plan B: reset backup domain
 | ||||
|         if(!RTC_CLOCK_IS_READY()) { | ||||
|             target_led_control("-R.R.R."); | ||||
|             LL_RCC_ForceBackupDomainReset(); | ||||
|             LL_RCC_ReleaseBackupDomainReset(); | ||||
|             NVIC_SystemReset(); | ||||
|         } | ||||
|         // Set RTC domain clock to LSE
 | ||||
|         LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSE); | ||||
|         // Enable LSE CSS
 | ||||
|         LL_RCC_LSE_EnableCSS(); | ||||
|     } | ||||
|     // Enable clocking
 | ||||
|     LL_RCC_EnableRTC(); | ||||
|     LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_RTCAPB); | ||||
| } | ||||
| 
 | ||||
| void target_version_save(void) { | ||||
|     LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR1, (uint32_t)version_get()); | ||||
| } | ||||
| 
 | ||||
| void target_usb_wire_reset() { | ||||
|     LL_GPIO_ResetOutputPin(BOOT_USB_PORT, BOOT_USB_PIN); | ||||
| } | ||||
| 
 | ||||
| void target_display_init() { | ||||
|     // Prepare gpio
 | ||||
|     hal_gpio_init_simple(&gpio_display_rst, GpioModeOutputPushPull); | ||||
|     hal_gpio_init_simple(&gpio_display_di, GpioModeOutputPushPull); | ||||
|     // Initialize
 | ||||
|     u8g2_t fb; | ||||
|     u8g2_Setup_st756x_flipper(&fb, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32); | ||||
|     u8g2_InitDisplay(&fb); | ||||
|     // Create payload
 | ||||
|     u8g2_ClearBuffer(&fb); | ||||
|     u8g2_SetDrawColor(&fb, 0x01); | ||||
|     u8g2_DrawXBM(&fb, 0, 64 - 50, 128, 50, I_DFU_128x50); | ||||
| #ifndef SLIM_BOOTLOADER | ||||
|     u8g2_SetFont(&fb, u8g2_font_helvB08_tf); | ||||
|     u8g2_DrawStr(&fb, 2, 8, "Update & Recovery Mode"); | ||||
|     u8g2_DrawStr(&fb, 2, 21, "DFU started"); | ||||
| #endif | ||||
|     // Send buffer
 | ||||
|     u8g2_SetPowerSave(&fb, 0); | ||||
|     u8g2_SendBuffer(&fb); | ||||
| } | ||||
| 
 | ||||
| void target_init() { | ||||
|     target_clock_init(); | ||||
|     target_gpio_init(); | ||||
|     furi_hal_init(); | ||||
|     target_led_control("RGB"); | ||||
|     target_rtc_init(); | ||||
|     target_version_save(); | ||||
|     target_usb_wire_reset(); | ||||
| 
 | ||||
|     // Errata 2.2.9, Flash OPTVERR flag is always set after system reset
 | ||||
|     __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS); | ||||
| } | ||||
| 
 | ||||
| int target_is_dfu_requested() { | ||||
|     if(LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR0) == BOOT_REQUEST_TAINTED) { | ||||
|         // Default system state is tainted
 | ||||
|         // We must ensure that MCU is cleanly booted
 | ||||
|         LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_CLEAN); | ||||
|         NVIC_SystemReset(); | ||||
|     } else if(LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR0) == BOOT_REQUEST_DFU) { | ||||
|         return 1; | ||||
|     } | ||||
|     LL_mDelay(100); | ||||
|     if(!LL_GPIO_IsInputPinSet(BOOT_DFU_PORT, BOOT_DFU_PIN)) { | ||||
|         return 1; | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| void target_switch(void* offset) { | ||||
|     asm volatile("ldr    r3, [%0]    \n" | ||||
|                  "msr    msp, r3     \n" | ||||
|                  "ldr    r3, [%1]    \n" | ||||
|                  "mov    pc, r3      \n" | ||||
|                  : | ||||
|                  : "r"(offset), "r"(offset + 0x4) | ||||
|                  : "r3"); | ||||
| } | ||||
| 
 | ||||
| void target_switch2dfu() { | ||||
|     target_led_control("B"); | ||||
|     furi_hal_light_set(LightBacklight, 0xFF); | ||||
|     target_display_init(); | ||||
|     // Mark system as tainted, it will be soon
 | ||||
|     LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_TAINTED); | ||||
|     // Remap memory to system bootloader
 | ||||
|     LL_SYSCFG_SetRemapMemory(LL_SYSCFG_REMAP_SYSTEMFLASH); | ||||
|     // Jump
 | ||||
|     target_switch(0x0); | ||||
| } | ||||
| 
 | ||||
| void target_switch2os() { | ||||
|     target_led_control("G"); | ||||
|     SCB->VTOR = OS_OFFSET; | ||||
|     target_switch((void*)(BOOT_ADDRESS + OS_OFFSET)); | ||||
| } | ||||
| @ -1,50 +0,0 @@ | ||||
| TOOLCHAIN = arm | ||||
| 
 | ||||
| BOOT_ADDRESS	= 0x08000000 | ||||
| FW_ADDRESS		= 0x08008000 | ||||
| OS_OFFSET		= 0x00008000 | ||||
| FLASH_ADDRESS	= 0x08000000 | ||||
| 
 | ||||
| OPENOCD_OPTS	= -f interface/stlink.cfg -c "transport select hla_swd" -f ../debug/stm32wbx.cfg -c "init" | ||||
| BOOT_CFLAGS		= -DBOOT_ADDRESS=$(BOOT_ADDRESS) -DFW_ADDRESS=$(FW_ADDRESS) -DOS_OFFSET=$(OS_OFFSET) | ||||
| MCU_FLAGS		= -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard | ||||
| 
 | ||||
| CFLAGS			+= $(MCU_FLAGS) $(BOOT_CFLAGS) -DSTM32WB55xx -Wall -fdata-sections -ffunction-sections | ||||
| LDFLAGS			+= $(MCU_FLAGS) -specs=nosys.specs -specs=nano.specs  | ||||
| 
 | ||||
| HARDWARE_TARGET = 6 | ||||
| 
 | ||||
| CUBE_DIR		= $(PROJECT_ROOT)/lib/STM32CubeWB | ||||
| 
 | ||||
| # ST HAL
 | ||||
| CFLAGS			+=  -DUSE_FULL_LL_DRIVER | ||||
| ASM_SOURCES		+= $(CUBE_DIR)/Drivers/CMSIS/Device/ST/STM32WBxx/Source/Templates/gcc/startup_stm32wb55xx_cm4.s | ||||
| C_SOURCES		+= $(CUBE_DIR)/Drivers/CMSIS/Device/ST/STM32WBxx/Source/Templates/system_stm32wbxx.c | ||||
| C_SOURCES		+= $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_utils.c | ||||
| C_SOURCES		+= $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_gpio.c | ||||
| C_SOURCES		+= $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_i2c.c | ||||
| C_SOURCES		+= $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_spi.c | ||||
| 
 | ||||
| CFLAGS			+= -I$(CUBE_DIR)/Drivers/CMSIS/Include | ||||
| CFLAGS			+= -I$(CUBE_DIR)/Drivers/CMSIS/Device/ST/STM32WBxx/Include | ||||
| CFLAGS			+= -I$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Inc | ||||
| 
 | ||||
| LDFLAGS			+= -T$(TARGET_DIR)/stm32wb55xx_flash_cm4.ld | ||||
| 
 | ||||
| # Drivers
 | ||||
| DRIVERS_DIR		= $(PROJECT_ROOT)//lib/drivers | ||||
| CFLAGS			+= -I$(DRIVERS_DIR) | ||||
| C_SOURCES		+= $(DRIVERS_DIR)/lp5562.c | ||||
| 
 | ||||
| # API-HAL
 | ||||
| CFLAGS			+= -I$(TARGET_DIR)/furi_hal | ||||
| C_SOURCES		+= $(wildcard $(TARGET_DIR)/furi_hal/*.c) | ||||
| 
 | ||||
| # Version generation
 | ||||
| C_SOURCES		+= $(PROJECT_ROOT)/lib/toolbox/version.c | ||||
| 
 | ||||
| ASM_SOURCES		+= $(wildcard $(TARGET_DIR)/*.s) | ||||
| C_SOURCES		+= $(wildcard $(TARGET_DIR)/*.c) | ||||
| CPP_SOURCES		+= $(wildcard $(TARGET_DIR)/*.cpp) | ||||
| 
 | ||||
| SVD_FILE		= $(PROJECT_ROOT)/debug/STM32WB55_CM4.svd | ||||
							
								
								
									
										5
									
								
								core/furi/common_defines.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										5
									
								
								core/furi/common_defines.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -1,7 +1,6 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #ifndef MAX | ||||
| 
 | ||||
| #define MAX(a, b)               \ | ||||
|     ({                          \ | ||||
|         __typeof__(a) _a = (a); \ | ||||
| @ -72,6 +71,10 @@ | ||||
|      (((x)&0xFF000000) >> 24)) | ||||
| #endif | ||||
| 
 | ||||
| #ifndef FURI_BIT | ||||
| #define FURI_BIT(x, n) ((x) >> (n)&1) | ||||
| #endif | ||||
| 
 | ||||
| #ifndef FURI_CRITICAL_ENTER | ||||
| #define FURI_CRITICAL_ENTER()               \ | ||||
|     uint32_t primask_bit = __get_PRIMASK(); \ | ||||
|  | ||||
| @ -16,7 +16,6 @@ typedef void (*InterruptCallback)(void*, void*); | ||||
| 
 | ||||
| /** Interupt type */ | ||||
| typedef enum { | ||||
|     InterruptTypeComparatorTrigger, | ||||
|     InterruptTypeTimerUpdate, | ||||
|     InterruptTypeLast, | ||||
| } InterruptType; | ||||
|  | ||||
| @ -1,138 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__) | ||||
| #include <stdint.h> | ||||
| extern uint32_t SystemCoreClock; | ||||
| #endif | ||||
| 
 | ||||
| #ifndef CMSIS_device_header | ||||
| #define CMSIS_device_header "stm32wbxx.h" | ||||
| #endif /* CMSIS_device_header */ | ||||
| 
 | ||||
| #define configENABLE_FPU 1 | ||||
| #define configENABLE_MPU 0 | ||||
| 
 | ||||
| #define configUSE_PREEMPTION 1 | ||||
| #define configSUPPORT_STATIC_ALLOCATION 0 | ||||
| #define configSUPPORT_DYNAMIC_ALLOCATION 1 | ||||
| #define configUSE_IDLE_HOOK 0 | ||||
| #define configUSE_TICK_HOOK 0 | ||||
| #define configCPU_CLOCK_HZ (SystemCoreClock) | ||||
| #define configTICK_RATE_HZ ((TickType_t)1024) | ||||
| #define configMAX_PRIORITIES (56) | ||||
| #define configMINIMAL_STACK_SIZE ((uint16_t)128) | ||||
| 
 | ||||
| /* Heap size determined automatically by linker */ | ||||
| // #define configTOTAL_HEAP_SIZE                    ((size_t)0)
 | ||||
| #define configMAX_TASK_NAME_LEN (16) | ||||
| #define configGENERATE_RUN_TIME_STATS 0 | ||||
| #define configUSE_TRACE_FACILITY 1 | ||||
| #define configUSE_16_BIT_TICKS 0 | ||||
| #define configUSE_MUTEXES 1 | ||||
| #define configQUEUE_REGISTRY_SIZE 8 | ||||
| #define configCHECK_FOR_STACK_OVERFLOW 1 | ||||
| #define configUSE_RECURSIVE_MUTEXES 1 | ||||
| #define configUSE_COUNTING_SEMAPHORES 1 | ||||
| #define configENABLE_BACKWARD_COMPATIBILITY 0 | ||||
| #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 | ||||
| #define configUSE_TICKLESS_IDLE 2 | ||||
| #define configRECORD_STACK_HIGH_ADDRESS 1 | ||||
| #define configUSE_NEWLIB_REENTRANT 0 | ||||
| 
 | ||||
| /* Defaults to size_t for backward compatibility, but can be changed
 | ||||
|    if lengths will always be less than the number of bytes in a size_t. */ | ||||
| #define configMESSAGE_BUFFER_LENGTH_TYPE size_t | ||||
| #define configNUM_THREAD_LOCAL_STORAGE_POINTERS 1 | ||||
| #define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 4 | ||||
| 
 | ||||
| /* Co-routine definitions. */ | ||||
| #define configUSE_CO_ROUTINES 0 | ||||
| 
 | ||||
| /* Software timer definitions. */ | ||||
| #define configUSE_TIMERS 1 | ||||
| #define configTIMER_TASK_PRIORITY (2) | ||||
| #define configTIMER_QUEUE_LENGTH 32 | ||||
| #define configTIMER_TASK_STACK_DEPTH 256 | ||||
| #define configTIMER_SERVICE_TASK_NAME "TimersSrv" | ||||
| 
 | ||||
| #define configIDLE_TASK_NAME "(-_-)" | ||||
| 
 | ||||
| /* Set the following definitions to 1 to include the API function, or zero
 | ||||
| to exclude the API function. */ | ||||
| #define INCLUDE_xTaskGetHandle 1 | ||||
| #define INCLUDE_eTaskGetState 1 | ||||
| #define INCLUDE_uxTaskGetStackHighWaterMark 1 | ||||
| #define INCLUDE_uxTaskPriorityGet 1 | ||||
| #define INCLUDE_vTaskCleanUpResources 0 | ||||
| #define INCLUDE_vTaskDelay 1 | ||||
| #define INCLUDE_vTaskDelayUntil 1 | ||||
| #define INCLUDE_vTaskDelete 1 | ||||
| #define INCLUDE_vTaskPrioritySet 1 | ||||
| #define INCLUDE_vTaskSuspend 1 | ||||
| #define INCLUDE_xQueueGetMutexHolder 1 | ||||
| #define INCLUDE_xTaskGetCurrentTaskHandle 1 | ||||
| #define INCLUDE_xTaskGetSchedulerState 1 | ||||
| #define INCLUDE_xTimerPendFunctionCall 1 | ||||
| 
 | ||||
| /* CMSIS-RTOS V2 flags */ | ||||
| #define configUSE_OS2_THREAD_SUSPEND_RESUME 1 | ||||
| #define configUSE_OS2_THREAD_ENUMERATE 1 | ||||
| #define configUSE_OS2_EVENTFLAGS_FROM_ISR 1 | ||||
| #define configUSE_OS2_THREAD_FLAGS 1 | ||||
| #define configUSE_OS2_TIMER 1 | ||||
| #define configUSE_OS2_MUTEX 1 | ||||
| 
 | ||||
| /* CMSIS-RTOS */ | ||||
| #define configTASK_NOTIFICATION_ARRAY_ENTRIES 2 | ||||
| #define CMSIS_TASK_NOTIFY_INDEX 1 | ||||
| 
 | ||||
| /*
 | ||||
|  * The CMSIS-RTOS V2 FreeRTOS wrapper is dependent on the heap implementation used | ||||
|  * by the application thus the correct define need to be enabled below | ||||
|  */ | ||||
| #define USE_FreeRTOS_HEAP_4 | ||||
| 
 | ||||
| /* Cortex-M specific definitions. */ | ||||
| #ifdef __NVIC_PRIO_BITS | ||||
| /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */ | ||||
| #define configPRIO_BITS __NVIC_PRIO_BITS | ||||
| #else | ||||
| #define configPRIO_BITS 4 | ||||
| #endif | ||||
| 
 | ||||
| /* The lowest interrupt priority that can be used in a call to a "set priority"
 | ||||
| function. */ | ||||
| #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 | ||||
| 
 | ||||
| /* The highest interrupt priority that can be used by any interrupt service
 | ||||
| routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL | ||||
| INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER | ||||
| PRIORITY THAN THIS! (higher priorities are lower numeric values. */ | ||||
| #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 | ||||
| 
 | ||||
| /* Interrupt priorities used by the kernel port layer itself.  These are generic
 | ||||
| to all Cortex-M ports, and do not rely on any particular library functions. */ | ||||
| #define configKERNEL_INTERRUPT_PRIORITY \ | ||||
|     (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS)) | ||||
| 
 | ||||
| /* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
 | ||||
| See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
 | ||||
| #define configMAX_SYSCALL_INTERRUPT_PRIORITY \ | ||||
|     (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS)) | ||||
| 
 | ||||
| /* Normal assert() semantics without relying on the provision of an assert.h
 | ||||
| header file. */ | ||||
| #include <furi/check.h> | ||||
| #define configASSERT(x)                \ | ||||
|     if((x) == 0) {                     \ | ||||
|         furi_crash("FreeRTOS Assert"); \ | ||||
|     } | ||||
| 
 | ||||
| /* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
 | ||||
| standard names. */ | ||||
| #define vPortSVCHandler SVC_Handler | ||||
| #define xPortPendSVHandler PendSV_Handler | ||||
| 
 | ||||
| #define USE_CUSTOM_SYSTICK_HANDLER_IMPLEMENTATION 1 | ||||
| #define configOVERRIDE_DEFAULT_TICK_CONFIGURATION \ | ||||
|     1 /* required only for Keil but does not hurt otherwise */ | ||||
| @ -1,52 +0,0 @@ | ||||
| /**
 | ||||
|   ****************************************************************************** | ||||
|   * @file    comp.h | ||||
|   * @brief   This file contains all the function prototypes for | ||||
|   *          the comp.c file | ||||
|   ****************************************************************************** | ||||
|   * @attention | ||||
|   * | ||||
|   * <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
|   * All rights reserved.</center></h2> | ||||
|   * | ||||
|   * This software component is licensed by ST under Ultimate Liberty license | ||||
|   * SLA0044, the "License"; You may not use this file except in compliance with | ||||
|   * the License. You may obtain a copy of the License at: | ||||
|   *                             www.st.com/SLA0044 | ||||
|   * | ||||
|   ****************************************************************************** | ||||
|   */ | ||||
| /* Define to prevent recursive inclusion -------------------------------------*/ | ||||
| #ifndef __COMP_H__ | ||||
| #define __COMP_H__ | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /* Includes ------------------------------------------------------------------*/ | ||||
| #include "main.h" | ||||
| 
 | ||||
| /* USER CODE BEGIN Includes */ | ||||
| 
 | ||||
| /* USER CODE END Includes */ | ||||
| 
 | ||||
| extern COMP_HandleTypeDef hcomp1; | ||||
| 
 | ||||
| /* USER CODE BEGIN Private defines */ | ||||
| 
 | ||||
| /* USER CODE END Private defines */ | ||||
| 
 | ||||
| void MX_COMP1_Init(void); | ||||
| 
 | ||||
| /* USER CODE BEGIN Prototypes */ | ||||
| 
 | ||||
| /* USER CODE END Prototypes */ | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif /* __COMP_H__ */ | ||||
| 
 | ||||
| /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ | ||||
| @ -1,49 +0,0 @@ | ||||
| /**
 | ||||
|   ****************************************************************************** | ||||
|   * @file    gpio.h | ||||
|   * @brief   This file contains all the function prototypes for | ||||
|   *          the gpio.c file | ||||
|   ****************************************************************************** | ||||
|   * @attention | ||||
|   * | ||||
|   * <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
|   * All rights reserved.</center></h2> | ||||
|   * | ||||
|   * This software component is licensed by ST under Ultimate Liberty license | ||||
|   * SLA0044, the "License"; You may not use this file except in compliance with | ||||
|   * the License. You may obtain a copy of the License at: | ||||
|   *                             www.st.com/SLA0044 | ||||
|   * | ||||
|   ****************************************************************************** | ||||
|   */ | ||||
| /* Define to prevent recursive inclusion -------------------------------------*/ | ||||
| #ifndef __GPIO_H__ | ||||
| #define __GPIO_H__ | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /* Includes ------------------------------------------------------------------*/ | ||||
| #include "main.h" | ||||
| 
 | ||||
| /* USER CODE BEGIN Includes */ | ||||
| 
 | ||||
| /* USER CODE END Includes */ | ||||
| 
 | ||||
| /* USER CODE BEGIN Private defines */ | ||||
| 
 | ||||
| /* USER CODE END Private defines */ | ||||
| 
 | ||||
| void MX_GPIO_Init(void); | ||||
| 
 | ||||
| /* USER CODE BEGIN Prototypes */ | ||||
| 
 | ||||
| /* USER CODE END Prototypes */ | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| #endif /*__ GPIO_H__ */ | ||||
| 
 | ||||
| /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ | ||||
| @ -1,149 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| #include "stm32wbxx_hal.h" | ||||
| 
 | ||||
| void Error_Handler(void); | ||||
| 
 | ||||
| #define BUTTON_BACK_EXTI_IRQn EXTI15_10_IRQn | ||||
| #define BUTTON_BACK_GPIO_Port GPIOC | ||||
| #define BUTTON_BACK_Pin GPIO_PIN_13 | ||||
| #define BUTTON_DOWN_EXTI_IRQn EXTI6_IRQn | ||||
| #define BUTTON_DOWN_GPIO_Port GPIOC | ||||
| #define BUTTON_DOWN_Pin GPIO_PIN_6 | ||||
| #define BUTTON_LEFT_EXTI_IRQn EXTI15_10_IRQn | ||||
| #define BUTTON_LEFT_GPIO_Port GPIOB | ||||
| #define BUTTON_LEFT_Pin GPIO_PIN_11 | ||||
| #define BUTTON_OK_EXTI_IRQn EXTI3_IRQn | ||||
| #define BUTTON_OK_GPIO_Port GPIOH | ||||
| #define BUTTON_OK_Pin GPIO_PIN_3 | ||||
| #define BUTTON_RIGHT_EXTI_IRQn EXTI15_10_IRQn | ||||
| #define BUTTON_RIGHT_GPIO_Port GPIOB | ||||
| #define BUTTON_RIGHT_Pin GPIO_PIN_12 | ||||
| #define BUTTON_UP_EXTI_IRQn EXTI15_10_IRQn | ||||
| #define BUTTON_UP_GPIO_Port GPIOB | ||||
| #define BUTTON_UP_Pin GPIO_PIN_10 | ||||
| 
 | ||||
| #define CC1101_CS_GPIO_Port GPIOD | ||||
| #define CC1101_CS_Pin GPIO_PIN_0 | ||||
| #define CC1101_G0_GPIO_Port GPIOA | ||||
| #define CC1101_G0_Pin GPIO_PIN_1 | ||||
| 
 | ||||
| #define DISPLAY_CS_GPIO_Port GPIOC | ||||
| #define DISPLAY_CS_Pin GPIO_PIN_11 | ||||
| #define DISPLAY_DI_GPIO_Port GPIOB | ||||
| #define DISPLAY_DI_Pin GPIO_PIN_1 | ||||
| #define DISPLAY_RST_GPIO_Port GPIOB | ||||
| #define DISPLAY_RST_Pin GPIO_PIN_0 | ||||
| 
 | ||||
| #define IR_RX_GPIO_Port GPIOA | ||||
| #define IR_RX_Pin GPIO_PIN_0 | ||||
| #define IR_TX_GPIO_Port GPIOB | ||||
| #define IR_TX_Pin GPIO_PIN_9 | ||||
| 
 | ||||
| #define NFC_CS_GPIO_Port GPIOE | ||||
| #define NFC_CS_Pin GPIO_PIN_4 | ||||
| 
 | ||||
| #define PA4_GPIO_Port GPIOA | ||||
| #define PA4_Pin GPIO_PIN_4 | ||||
| #define PA6_GPIO_Port GPIOA | ||||
| #define PA6_Pin GPIO_PIN_6 | ||||
| #define PA7_GPIO_Port GPIOA | ||||
| #define PA7_Pin GPIO_PIN_7 | ||||
| #define PB2_GPIO_Port GPIOB | ||||
| #define PB2_Pin GPIO_PIN_2 | ||||
| #define PB3_GPIO_Port GPIOB | ||||
| #define PB3_Pin GPIO_PIN_3 | ||||
| #define PC0_GPIO_Port GPIOC | ||||
| #define PC0_Pin GPIO_PIN_0 | ||||
| #define PC1_GPIO_Port GPIOC | ||||
| #define PC1_Pin GPIO_PIN_1 | ||||
| #define PC3_GPIO_Port GPIOC | ||||
| #define PC3_Pin GPIO_PIN_3 | ||||
| 
 | ||||
| #define PERIPH_POWER_GPIO_Port GPIOA | ||||
| #define PERIPH_POWER_Pin GPIO_PIN_3 | ||||
| 
 | ||||
| #define QUARTZ_32MHZ_IN_GPIO_Port GPIOC | ||||
| #define QUARTZ_32MHZ_IN_Pin GPIO_PIN_14 | ||||
| #define QUARTZ_32MHZ_OUT_GPIO_Port GPIOC | ||||
| #define QUARTZ_32MHZ_OUT_Pin GPIO_PIN_15 | ||||
| 
 | ||||
| #define RFID_OUT_GPIO_Port GPIOB | ||||
| #define RFID_OUT_Pin GPIO_PIN_13 | ||||
| #define RFID_PULL_GPIO_Port GPIOA | ||||
| #define RFID_PULL_Pin GPIO_PIN_2 | ||||
| #define RFID_RF_IN_GPIO_Port GPIOC | ||||
| #define RFID_RF_IN_Pin GPIO_PIN_5 | ||||
| #define RFID_TUNE_GPIO_Port GPIOA | ||||
| #define RFID_TUNE_Pin GPIO_PIN_8 | ||||
| 
 | ||||
| #define RF_SW_0_GPIO_Port GPIOC | ||||
| #define RF_SW_0_Pin GPIO_PIN_4 | ||||
| 
 | ||||
| #define SD_CD_GPIO_Port GPIOC | ||||
| #define SD_CD_Pin GPIO_PIN_10 | ||||
| #define SD_CS_GPIO_Port GPIOC | ||||
| #define SD_CS_Pin GPIO_PIN_12 | ||||
| 
 | ||||
| #define SPEAKER_GPIO_Port GPIOB | ||||
| #define SPEAKER_Pin GPIO_PIN_8 | ||||
| 
 | ||||
| #define VIBRO_GPIO_Port GPIOA | ||||
| #define VIBRO_Pin GPIO_PIN_15 | ||||
| 
 | ||||
| #define iBTN_GPIO_Port GPIOB | ||||
| #define iBTN_Pin GPIO_PIN_14 | ||||
| 
 | ||||
| #define USART1_TX_Pin GPIO_PIN_6 | ||||
| #define USART1_TX_Port GPIOB | ||||
| #define USART1_RX_Pin GPIO_PIN_7 | ||||
| #define USART1_RX_Port GPIOB | ||||
| 
 | ||||
| #define SPI_D_MISO_GPIO_Port GPIOC | ||||
| #define SPI_D_MISO_Pin GPIO_PIN_2 | ||||
| #define SPI_D_MOSI_GPIO_Port GPIOB | ||||
| #define SPI_D_MOSI_Pin GPIO_PIN_15 | ||||
| #define SPI_D_SCK_GPIO_Port GPIOD | ||||
| #define SPI_D_SCK_Pin GPIO_PIN_1 | ||||
| 
 | ||||
| #define SPI_R_MISO_GPIO_Port GPIOB | ||||
| #define SPI_R_MISO_Pin GPIO_PIN_4 | ||||
| #define SPI_R_MOSI_GPIO_Port GPIOB | ||||
| #define SPI_R_MOSI_Pin GPIO_PIN_5 | ||||
| #define SPI_R_SCK_GPIO_Port GPIOA | ||||
| #define SPI_R_SCK_Pin GPIO_PIN_5 | ||||
| 
 | ||||
| extern TIM_HandleTypeDef htim1; | ||||
| extern TIM_HandleTypeDef htim2; | ||||
| extern TIM_HandleTypeDef htim16; | ||||
| 
 | ||||
| #define TIM_A htim1 | ||||
| #define TIM_B htim2 | ||||
| #define TIM_C htim16 | ||||
| 
 | ||||
| #define SPEAKER_TIM htim16 | ||||
| #define SPEAKER_CH TIM_CHANNEL_1 | ||||
| 
 | ||||
| #define LFRFID_TIM htim1 | ||||
| #define LFRFID_CH TIM_CHANNEL_1 | ||||
| 
 | ||||
| #define INFRARED_TX_TIM htim1 | ||||
| #define INFRARED_TX_CH TIM_CHANNEL_3 | ||||
| 
 | ||||
| // only for reference
 | ||||
| // INFRARED RX timer dont exist in F2
 | ||||
| // and timer need more data to init (NVIC IRQn to set priority)
 | ||||
| #define INFRARED_RX_TIM htim2 | ||||
| #define INFRARED_RX_FALLING_CH TIM_CHANNEL_1 | ||||
| #define INFRARED_RX_RISING_CH TIM_CHANNEL_2 | ||||
| 
 | ||||
| #define NFC_IRQ_Pin RFID_PULL_Pin | ||||
| #define NFC_IRQ_GPIO_Port RFID_PULL_GPIO_Port | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -1,51 +0,0 @@ | ||||
| #ifndef _STM32_H_ | ||||
| #define _STM32_H_ | ||||
| 
 | ||||
| /* modify bitfield */ | ||||
| #define _BMD(reg, msk, val) (reg) = (((reg) & ~(msk)) | (val)) | ||||
| /* set bitfield */ | ||||
| #define _BST(reg, bits) (reg) = ((reg) | (bits)) | ||||
| /* clear bitfield */ | ||||
| #define _BCL(reg, bits) (reg) = ((reg) & ~(bits)) | ||||
| /* wait until bitfield set */ | ||||
| #define _WBS(reg, bits) while(((reg) & (bits)) == 0) | ||||
| /* wait until bitfield clear */ | ||||
| #define _WBC(reg, bits) while(((reg) & (bits)) != 0) | ||||
| /* wait for bitfield value */ | ||||
| #define _WVL(reg, msk, val) while(((reg) & (msk)) != (val)) | ||||
| /* bit value */ | ||||
| #define _BV(bit) (0x01 << (bit)) | ||||
| 
 | ||||
| #if defined(STM32F0) | ||||
| #include "STM32F0xx/Include/stm32f0xx.h" | ||||
| #elif defined(STM32F1) | ||||
| #include "STM32F1xx/Include/stm32f1xx.h" | ||||
| #elif defined(STM32F2) | ||||
| #include "STM32F2xx/Include/stm32f2xx.h" | ||||
| #elif defined(STM32F3) | ||||
| #include "STM32F3xx/Include/stm32f3xx.h" | ||||
| #elif defined(STM32F4) | ||||
| #include "STM32F4xx/Include/stm32f4xx.h" | ||||
| #elif defined(STM32F7) | ||||
| #include "STM32F7xx/Include/stm32f7xx.h" | ||||
| #elif defined(STM32H7) | ||||
| #include "STM32H7xx/Include/stm32h7xx.h" | ||||
| #elif defined(STM32L0) | ||||
| #include "STM32L0xx/Include/stm32l0xx.h" | ||||
| #elif defined(STM32L1) | ||||
| #include "STM32L1xx/Include/stm32l1xx.h" | ||||
| #elif defined(STM32L4) | ||||
| #include "STM32L4xx/Include/stm32l4xx.h" | ||||
| #elif defined(STM32L5) | ||||
| #include "STM32L5xx/Include/stm32l5xx.h" | ||||
| #elif defined(STM32G0) | ||||
| #include "STM32G0xx/Include/stm32g0xx.h" | ||||
| #elif defined(STM32G4) | ||||
| #include "STM32G4xx/Include/stm32g4xx.h" | ||||
| #elif defined(STM32WB) | ||||
| #include "STM32WBxx/Include/stm32wbxx.h" | ||||
| #else | ||||
| #error "STM32 family not defined" | ||||
| #endif | ||||
| 
 | ||||
| #endif // _STM32_H_
 | ||||
| @ -1,40 +0,0 @@ | ||||
| /**
 | ||||
|   ****************************************************************************** | ||||
|   * @file    stm32_assert.h | ||||
|   * @brief   STM32 assert file. | ||||
|   ****************************************************************************** | ||||
|   * @attention | ||||
|   * | ||||
|   * <h2><center>© Copyright (c) 2019 STMicroelectronics. | ||||
|   * All rights reserved.</center></h2> | ||||
|   * | ||||
|   * This software component is licensed by ST under BSD 3-Clause license, | ||||
|   * the "License"; You may not use this file except in compliance with the | ||||
|   * License. You may obtain a copy of the License at: | ||||
|   *                        opensource.org/licenses/BSD-3-Clause | ||||
|   * | ||||
|   ****************************************************************************** | ||||
|   */ | ||||
| 
 | ||||
| /* Define to prevent recursive inclusion -------------------------------------*/ | ||||
| #ifndef __STM32_ASSERT_H | ||||
| #define __STM32_ASSERT_H | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| #ifdef USE_FULL_ASSERT | ||||
| #define assert_param(expr) ((expr) ? (void)0U : assert_failed()) | ||||
| void assert_failed(); | ||||
| #else | ||||
| #define assert_param(expr) ((void)0U) | ||||
| #endif /* USE_FULL_ASSERT */ | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif /* __STM32_ASSERT_H */ | ||||
| 
 | ||||
| /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ | ||||
| @ -1,345 +0,0 @@ | ||||
| /**
 | ||||
|   ****************************************************************************** | ||||
|   * @file    stm32wbxx_hal_conf.h | ||||
|   * @author  MCD Application Team | ||||
|   * @brief   HAL configuration file. | ||||
|   ****************************************************************************** | ||||
|   * @attention | ||||
|   * | ||||
|   * <h2><center>© Copyright (c) 2019 STMicroelectronics. | ||||
|   * All rights reserved.</center></h2> | ||||
|   * | ||||
|   * This software component is licensed by ST under BSD 3-Clause license, | ||||
|   * the "License"; You may not use this file except in compliance with the | ||||
|   * License. You may obtain a copy of the License at: | ||||
|   *                        opensource.org/licenses/BSD-3-Clause | ||||
|   * | ||||
|   ****************************************************************************** | ||||
|   */ | ||||
| 
 | ||||
| /* Define to prevent recursive inclusion -------------------------------------*/ | ||||
| #ifndef __STM32WBxx_HAL_CONF_H | ||||
| #define __STM32WBxx_HAL_CONF_H | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /* Exported types ------------------------------------------------------------*/ | ||||
| /* Exported constants --------------------------------------------------------*/ | ||||
| 
 | ||||
| /* ########################## Module Selection ############################## */ | ||||
| /**
 | ||||
|   * @brief This is the list of modules to be used in the HAL driver | ||||
|   */ | ||||
| #define HAL_MODULE_ENABLED | ||||
| /*#define HAL_ADC_MODULE_ENABLED    */ | ||||
| #define HAL_CRYP_MODULE_ENABLED | ||||
| #define HAL_COMP_MODULE_ENABLED | ||||
| /*#define HAL_CRC_MODULE_ENABLED    */ | ||||
| #define HAL_HSEM_MODULE_ENABLED | ||||
| /*#define HAL_I2C_MODULE_ENABLED    */ | ||||
| /*#define HAL_IPCC_MODULE_ENABLED   */ | ||||
| /*#define HAL_IRDA_MODULE_ENABLED   */ | ||||
| /*#define HAL_IWDG_MODULE_ENABLED   */ | ||||
| /*#define HAL_LCD_MODULE_ENABLED    */ | ||||
| /*#define HAL_LPTIM_MODULE_ENABLED  */ | ||||
| #define HAL_PCD_MODULE_ENABLED | ||||
| #define HAL_PKA_MODULE_ENABLED | ||||
| /*#define HAL_QSPI_MODULE_ENABLED   */ | ||||
| #define HAL_RNG_MODULE_ENABLED | ||||
| /*#define HAL_RTC_MODULE_ENABLED    */ | ||||
| /*#define HAL_SAI_MODULE_ENABLED    */ | ||||
| /*#define HAL_SMBUS_MODULE_ENABLED  */ | ||||
| /*#define HAL_SMARTCARD_MODULE_ENABLED   */ | ||||
| /*#define HAL_SPI_MODULE_ENABLED    */ | ||||
| #define HAL_TIM_MODULE_ENABLED | ||||
| /*#define HAL_TSC_MODULE_ENABLED    */ | ||||
| /*#define HAL_UART_MODULE_ENABLED   */ | ||||
| /*#define HAL_USART_MODULE_ENABLED  */ | ||||
| /*#define HAL_WWDG_MODULE_ENABLED   */ | ||||
| #define HAL_EXTI_MODULE_ENABLED | ||||
| #define HAL_CORTEX_MODULE_ENABLED | ||||
| #define HAL_DMA_MODULE_ENABLED | ||||
| #define HAL_FLASH_MODULE_ENABLED | ||||
| #define HAL_GPIO_MODULE_ENABLED | ||||
| #define HAL_PWR_MODULE_ENABLED | ||||
| #define HAL_RCC_MODULE_ENABLED | ||||
| 
 | ||||
| #define USE_HAL_ADC_REGISTER_CALLBACKS 0u | ||||
| #define USE_HAL_COMP_REGISTER_CALLBACKS 0u | ||||
| #define USE_HAL_CRYP_REGISTER_CALLBACKS 0u | ||||
| #define USE_HAL_I2C_REGISTER_CALLBACKS 0u | ||||
| #define USE_HAL_IRDA_REGISTER_CALLBACKS 0u | ||||
| #define USE_HAL_LPTIM_REGISTER_CALLBACKS 0u | ||||
| #define USE_HAL_PCD_REGISTER_CALLBACKS 0u | ||||
| #define USE_HAL_PKA_REGISTER_CALLBACKS 0u | ||||
| #define USE_HAL_QSPI_REGISTER_CALLBACKS 0u | ||||
| #define USE_HAL_RNG_REGISTER_CALLBACKS 0u | ||||
| #define USE_HAL_RTC_REGISTER_CALLBACKS 0u | ||||
| #define USE_HAL_SAI_REGISTER_CALLBACKS 0u | ||||
| #define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0u | ||||
| #define USE_HAL_SMBUS_REGISTER_CALLBACKS 0u | ||||
| #define USE_HAL_SPI_REGISTER_CALLBACKS 0u | ||||
| #define USE_HAL_TIM_REGISTER_CALLBACKS 0u | ||||
| #define USE_HAL_TSC_REGISTER_CALLBACKS 0u | ||||
| #define USE_HAL_UART_REGISTER_CALLBACKS 0u | ||||
| #define USE_HAL_USART_REGISTER_CALLBACKS 0u | ||||
| #define USE_HAL_WWDG_REGISTER_CALLBACKS 0u | ||||
| 
 | ||||
| /* ########################## Oscillator Values adaptation ####################*/ | ||||
| /**
 | ||||
|   * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. | ||||
|   *        This value is used by the RCC HAL module to compute the system frequency | ||||
|   *        (when HSE is used as system clock source, directly or through the PLL). | ||||
|   */ | ||||
| #if !defined(HSE_VALUE) | ||||
| #define HSE_VALUE 32000000U /*!< Value of the External oscillator in Hz */ | ||||
| #endif /* HSE_VALUE */ | ||||
| 
 | ||||
| #if !defined(HSE_STARTUP_TIMEOUT) | ||||
| #define HSE_STARTUP_TIMEOUT ((uint32_t)100) /*!< Time out for HSE start up, in ms */ | ||||
| #endif /* HSE_STARTUP_TIMEOUT */ | ||||
| 
 | ||||
| /**
 | ||||
|   * @brief Internal Multiple Speed oscillator (MSI) default value. | ||||
|   *        This value is the default MSI range value after Reset. | ||||
|   */ | ||||
| #if !defined(MSI_VALUE) | ||||
| #define MSI_VALUE ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/ | ||||
| #endif /* MSI_VALUE */ | ||||
| 
 | ||||
| /**
 | ||||
|   * @brief Internal High Speed oscillator (HSI) value. | ||||
|   *        This value is used by the RCC HAL module to compute the system frequency | ||||
|   *        (when HSI is used as system clock source, directly or through the PLL). | ||||
|   */ | ||||
| #if !defined(HSI_VALUE) | ||||
| #define HSI_VALUE 16000000U /*!< Value of the Internal oscillator in Hz*/ | ||||
| #endif /* HSI_VALUE */ | ||||
| 
 | ||||
| /**
 | ||||
|   * @brief Internal Low Speed oscillator (LSI1) value. | ||||
|   */ | ||||
| #if !defined(LSI1_VALUE) | ||||
| #define LSI1_VALUE ((uint32_t)32000) /*!< LSI1 Typical Value in Hz*/ | ||||
| #endif /* LSI1_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz | ||||
|                                              The real value may vary depending on the variations | ||||
|                                              in voltage and temperature.*/ | ||||
| /**
 | ||||
|   * @brief Internal Low Speed oscillator (LSI2) value. | ||||
|   */ | ||||
| #if !defined(LSI2_VALUE) | ||||
| #define LSI2_VALUE ((uint32_t)32000) /*!< LSI2 Typical Value in Hz*/ | ||||
| #endif /* LSI2_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz | ||||
|                                              The real value may vary depending on the variations | ||||
|                                              in voltage and temperature.*/ | ||||
| 
 | ||||
| /**
 | ||||
|   * @brief External Low Speed oscillator (LSE) value. | ||||
|   *        This value is used by the UART, RTC HAL module to compute the system frequency | ||||
|   */ | ||||
| #if !defined(LSE_VALUE) | ||||
| #define LSE_VALUE 32768U /*!< Value of the External oscillator in Hz*/ | ||||
| #endif /* LSE_VALUE */ | ||||
| 
 | ||||
| /**
 | ||||
|   * @brief Internal Multiple Speed oscillator (HSI48) default value. | ||||
|   *        This value is the default HSI48 range value after Reset. | ||||
|   */ | ||||
| #if !defined(HSI48_VALUE) | ||||
| #define HSI48_VALUE ((uint32_t)48000000) /*!< Value of the Internal oscillator in Hz*/ | ||||
| #endif /* HSI48_VALUE */ | ||||
| 
 | ||||
| #if !defined(LSE_STARTUP_TIMEOUT) | ||||
| #define LSE_STARTUP_TIMEOUT 1000U /*!< Time out for LSE start up, in ms */ | ||||
| #endif /* HSE_STARTUP_TIMEOUT */ | ||||
| 
 | ||||
| /**
 | ||||
|   * @brief External clock source for SAI1 peripheral | ||||
|   *        This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source | ||||
|   *        frequency. | ||||
|   */ | ||||
| #if !defined(EXTERNAL_SAI1_CLOCK_VALUE) | ||||
| #define EXTERNAL_SAI1_CLOCK_VALUE \ | ||||
|     ((uint32_t)2097000) /*!< Value of the SAI1 External clock source in Hz*/ | ||||
| #endif /* EXTERNAL_SAI1_CLOCK_VALUE */ | ||||
| 
 | ||||
| /* Tip: To avoid modifying this file each time you need to use different HSE,
 | ||||
|    ===  you can define the HSE value in your toolchain compiler preprocessor. */ | ||||
| 
 | ||||
| /* ########################### System Configuration ######################### */ | ||||
| /**
 | ||||
|   * @brief This is the HAL system configuration section | ||||
|   */ | ||||
| 
 | ||||
| #define VDD_VALUE 3300U /*!< Value of VDD in mv */ | ||||
| #define TICK_INT_PRIORITY 0U /*!< tick interrupt priority */ | ||||
| #define USE_RTOS 0U | ||||
| #define PREFETCH_ENABLE 1U | ||||
| #define INSTRUCTION_CACHE_ENABLE 1U | ||||
| #define DATA_CACHE_ENABLE 1U | ||||
| 
 | ||||
| /* ########################## Assert Selection ############################## */ | ||||
| /**
 | ||||
|   * @brief Uncomment the line below to expanse the "assert_param" macro in the | ||||
|   *        HAL drivers code | ||||
|   */ | ||||
| #define USE_FULL_ASSERT 1U | ||||
| 
 | ||||
| /* ################## SPI peripheral configuration ########################## */ | ||||
| 
 | ||||
| /* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver
 | ||||
|  * Activated: CRC code is present inside driver | ||||
|  * Deactivated: CRC code cleaned from driver | ||||
|  */ | ||||
| 
 | ||||
| #define USE_SPI_CRC 0U | ||||
| 
 | ||||
| /* Includes ------------------------------------------------------------------*/ | ||||
| /**
 | ||||
|   * @brief Include module's header file | ||||
|   */ | ||||
| #ifdef HAL_DMA_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_dma.h" | ||||
| #endif /* HAL_DMA_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_ADC_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_adc.h" | ||||
| #endif /* HAL_ADC_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_COMP_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_comp.h" | ||||
| #endif /* HAL_COMP_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_CORTEX_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_cortex.h" | ||||
| #endif /* HAL_CORTEX_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_CRC_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_crc.h" | ||||
| #endif /* HAL_CRC_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_CRYP_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_cryp.h" | ||||
| #endif /* HAL_CRYP_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_EXTI_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_exti.h" | ||||
| #endif /* HAL_EXTI_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_FLASH_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_flash.h" | ||||
| #endif /* HAL_FLASH_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_GPIO_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_gpio.h" | ||||
| #endif /* HAL_GPIO_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_HSEM_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_hsem.h" | ||||
| #endif /* HAL_HSEM_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_I2C_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_i2c.h" | ||||
| #endif /* HAL_I2C_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_IPCC_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_ipcc.h" | ||||
| #endif /* HAL_IPCC_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_IRDA_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_irda.h" | ||||
| #endif /* HAL_IRDA_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_IWDG_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_iwdg.h" | ||||
| #endif /* HAL_IWDG_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_LCD_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_lcd.h" | ||||
| #endif /* HAL_LCD_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_LPTIM_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_lptim.h" | ||||
| #endif /* HAL_LPTIM_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_PCD_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_pcd.h" | ||||
| #endif /* HAL_PCD_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_PKA_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_pka.h" | ||||
| #endif /* HAL_PKA_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_PWR_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_pwr.h" | ||||
| #endif /* HAL_PWR_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_QSPI_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_qspi.h" | ||||
| #endif /* HAL_QSPI_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_RCC_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_rcc.h" | ||||
| #endif /* HAL_RCC_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_RNG_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_rng.h" | ||||
| #endif /* HAL_RNG_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_RTC_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_rtc.h" | ||||
| #endif /* HAL_RTC_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_SAI_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_sai.h" | ||||
| #endif /* HAL_SAI_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_SMARTCARD_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_smartcard.h" | ||||
| #endif /* HAL_SMARTCARD_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_SMBUS_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_smbus.h" | ||||
| #endif /* HAL_SMBUS_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_SPI_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_spi.h" | ||||
| #endif /* HAL_SPI_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_TIM_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_tim.h" | ||||
| #endif /* HAL_TIM_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_TSC_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_tsc.h" | ||||
| #endif /* HAL_TSC_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_UART_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_uart.h" | ||||
| #endif /* HAL_UART_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_USART_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_usart.h" | ||||
| #endif /* HAL_USART_MODULE_ENABLED */ | ||||
| 
 | ||||
| #ifdef HAL_WWDG_MODULE_ENABLED | ||||
| #include "stm32wbxx_hal_wwdg.h" | ||||
| #endif /* HAL_WWDG_MODULE_ENABLED */ | ||||
| 
 | ||||
| /* Exported macro ------------------------------------------------------------*/ | ||||
| #ifdef USE_FULL_ASSERT | ||||
| #define assert_param(expr) ((expr) ? (void)0U : assert_failed()) | ||||
| void assert_failed(); | ||||
| #else | ||||
| #define assert_param(expr) ((void)0U) | ||||
| #endif /* USE_FULL_ASSERT */ | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif /* __STM32WBxx_HAL_CONF_H */ | ||||
| 
 | ||||
| /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ | ||||
| @ -1,69 +0,0 @@ | ||||
| /* USER CODE BEGIN Header */ | ||||
| /**
 | ||||
|   ****************************************************************************** | ||||
|   * @file    stm32wbxx_it.h | ||||
|   * @brief   This file contains the headers of the interrupt handlers. | ||||
|   ****************************************************************************** | ||||
|   * @attention | ||||
|   * | ||||
|   * <h2><center>© Copyright (c) 2020 STMicroelectronics. | ||||
|   * All rights reserved.</center></h2> | ||||
|   * | ||||
|   * This software component is licensed by ST under Ultimate Liberty license | ||||
|   * SLA0044, the "License"; You may not use this file except in compliance with | ||||
|   * the License. You may obtain a copy of the License at: | ||||
|   *                             www.st.com/SLA0044 | ||||
|   * | ||||
|  ****************************************************************************** | ||||
|   */ | ||||
| /* USER CODE END Header */ | ||||
| 
 | ||||
| /* Define to prevent recursive inclusion -------------------------------------*/ | ||||
| #ifndef __STM32WBxx_IT_H | ||||
| #define __STM32WBxx_IT_H | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /* Private includes ----------------------------------------------------------*/ | ||||
| /* USER CODE BEGIN Includes */ | ||||
| 
 | ||||
| /* USER CODE END Includes */ | ||||
| 
 | ||||
| /* Exported types ------------------------------------------------------------*/ | ||||
| /* USER CODE BEGIN ET */ | ||||
| 
 | ||||
| /* USER CODE END ET */ | ||||
| 
 | ||||
| /* Exported constants --------------------------------------------------------*/ | ||||
| /* USER CODE BEGIN EC */ | ||||
| 
 | ||||
| /* USER CODE END EC */ | ||||
| 
 | ||||
| /* Exported macro ------------------------------------------------------------*/ | ||||
| /* USER CODE BEGIN EM */ | ||||
| 
 | ||||
| /* USER CODE END EM */ | ||||
| 
 | ||||
| /* Exported functions prototypes ---------------------------------------------*/ | ||||
| void SysTick_Handler(void); | ||||
| void ADC1_IRQHandler(void); | ||||
| void USB_LP_IRQHandler(void); | ||||
| void COMP_IRQHandler(void); | ||||
| void TIM1_UP_TIM16_IRQHandler(void); | ||||
| void TIM1_TRG_COM_TIM17_IRQHandler(void); | ||||
| void TIM1_CC_IRQHandler(void); | ||||
| void TIM2_IRQHandler(void); | ||||
| void HSEM_IRQHandler(void); | ||||
| /* USER CODE BEGIN EFP */ | ||||
| 
 | ||||
| /* USER CODE END EFP */ | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif /* __STM32WBxx_IT_H */ | ||||
| 
 | ||||
| /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ | ||||
| @ -1,58 +0,0 @@ | ||||
| /**
 | ||||
|   ****************************************************************************** | ||||
|   * @file    tim.h | ||||
|   * @brief   This file contains all the function prototypes for | ||||
|   *          the tim.c file | ||||
|   ****************************************************************************** | ||||
|   * @attention | ||||
|   * | ||||
|   * <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
|   * All rights reserved.</center></h2> | ||||
|   * | ||||
|   * This software component is licensed by ST under Ultimate Liberty license | ||||
|   * SLA0044, the "License"; You may not use this file except in compliance with | ||||
|   * the License. You may obtain a copy of the License at: | ||||
|   *                             www.st.com/SLA0044 | ||||
|   * | ||||
|   ****************************************************************************** | ||||
|   */ | ||||
| /* Define to prevent recursive inclusion -------------------------------------*/ | ||||
| #ifndef __TIM_H__ | ||||
| #define __TIM_H__ | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /* Includes ------------------------------------------------------------------*/ | ||||
| #include "main.h" | ||||
| 
 | ||||
| /* USER CODE BEGIN Includes */ | ||||
| 
 | ||||
| /* USER CODE END Includes */ | ||||
| 
 | ||||
| extern TIM_HandleTypeDef htim1; | ||||
| extern TIM_HandleTypeDef htim2; | ||||
| extern TIM_HandleTypeDef htim16; | ||||
| 
 | ||||
| /* USER CODE BEGIN Private defines */ | ||||
| 
 | ||||
| /* USER CODE END Private defines */ | ||||
| 
 | ||||
| void MX_TIM1_Init(void); | ||||
| void MX_TIM2_Init(void); | ||||
| void MX_TIM16_Init(void); | ||||
| 
 | ||||
| void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim); | ||||
| 
 | ||||
| /* USER CODE BEGIN Prototypes */ | ||||
| 
 | ||||
| /* USER CODE END Prototypes */ | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif /* __TIM_H__ */ | ||||
| 
 | ||||
| /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ | ||||
| @ -1,93 +0,0 @@ | ||||
| /**
 | ||||
|   ****************************************************************************** | ||||
|   * @file    comp.c | ||||
|   * @brief   This file provides code for the configuration | ||||
|   *          of the COMP instances. | ||||
|   ****************************************************************************** | ||||
|   * @attention | ||||
|   * | ||||
|   * <h2><center>© Copyright (c) 2021 STMicroelectronics. | ||||
|   * All rights reserved.</center></h2> | ||||
|   * | ||||
|   * This software component is licensed by ST under Ultimate Liberty license | ||||
|   * SLA0044, the "License"; You may not use this file except in compliance with | ||||
|   * the License. You may obtain a copy of the License at: | ||||
|   *                             www.st.com/SLA0044 | ||||
|   * | ||||
|   ****************************************************************************** | ||||
|   */ | ||||
| 
 | ||||
| /* Includes ------------------------------------------------------------------*/ | ||||
| #include "comp.h" | ||||
| 
 | ||||
| /* USER CODE BEGIN 0 */ | ||||
| 
 | ||||
| /* USER CODE END 0 */ | ||||
| 
 | ||||
| COMP_HandleTypeDef hcomp1; | ||||
| 
 | ||||
| /* COMP1 init function */ | ||||
| void MX_COMP1_Init(void) { | ||||
|     hcomp1.Instance = COMP1; | ||||
|     hcomp1.Init.InputMinus = COMP_INPUT_MINUS_1_4VREFINT; | ||||
|     hcomp1.Init.InputPlus = COMP_INPUT_PLUS_IO1; | ||||
|     hcomp1.Init.OutputPol = COMP_OUTPUTPOL_NONINVERTED; | ||||
|     hcomp1.Init.Hysteresis = COMP_HYSTERESIS_HIGH; | ||||
|     hcomp1.Init.BlankingSrce = COMP_BLANKINGSRC_NONE; | ||||
|     hcomp1.Init.Mode = COMP_POWERMODE_MEDIUMSPEED; | ||||
|     hcomp1.Init.WindowMode = COMP_WINDOWMODE_DISABLE; | ||||
|     hcomp1.Init.TriggerMode = COMP_TRIGGERMODE_IT_RISING_FALLING; | ||||
|     if(HAL_COMP_Init(&hcomp1) != HAL_OK) { | ||||
|         Error_Handler(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void HAL_COMP_MspInit(COMP_HandleTypeDef* compHandle) { | ||||
|     GPIO_InitTypeDef GPIO_InitStruct = {0}; | ||||
|     if(compHandle->Instance == COMP1) { | ||||
|         /* USER CODE BEGIN COMP1_MspInit 0 */ | ||||
| 
 | ||||
|         /* USER CODE END COMP1_MspInit 0 */ | ||||
| 
 | ||||
|         __HAL_RCC_GPIOC_CLK_ENABLE(); | ||||
|         /**COMP1 GPIO Configuration
 | ||||
|     PC5     ------> COMP1_INP | ||||
|     */ | ||||
|         GPIO_InitStruct.Pin = RFID_RF_IN_Pin; | ||||
|         GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; | ||||
|         GPIO_InitStruct.Pull = GPIO_NOPULL; | ||||
|         HAL_GPIO_Init(RFID_RF_IN_GPIO_Port, &GPIO_InitStruct); | ||||
| 
 | ||||
|         /* COMP1 interrupt Init */ | ||||
|         HAL_NVIC_SetPriority(COMP_IRQn, 5, 0); | ||||
|         HAL_NVIC_EnableIRQ(COMP_IRQn); | ||||
|         /* USER CODE BEGIN COMP1_MspInit 1 */ | ||||
| 
 | ||||
|         /* USER CODE END COMP1_MspInit 1 */ | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void HAL_COMP_MspDeInit(COMP_HandleTypeDef* compHandle) { | ||||
|     if(compHandle->Instance == COMP1) { | ||||
|         /* USER CODE BEGIN COMP1_MspDeInit 0 */ | ||||
| 
 | ||||
|         /* USER CODE END COMP1_MspDeInit 0 */ | ||||
| 
 | ||||
|         /**COMP1 GPIO Configuration
 | ||||
|     PC5     ------> COMP1_INP | ||||
|     */ | ||||
|         HAL_GPIO_DeInit(RFID_RF_IN_GPIO_Port, RFID_RF_IN_Pin); | ||||
| 
 | ||||
|         /* COMP1 interrupt Deinit */ | ||||
|         HAL_NVIC_DisableIRQ(COMP_IRQn); | ||||
|         /* USER CODE BEGIN COMP1_MspDeInit 1 */ | ||||
| 
 | ||||
|         /* USER CODE END COMP1_MspDeInit 1 */ | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* USER CODE BEGIN 1 */ | ||||
| 
 | ||||
| /* USER CODE END 1 */ | ||||
| 
 | ||||
| /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Aleksandr Kutuzov
						Aleksandr Kutuzov