[FL-1884] GPIO application (#732)
* gpio: rename gpio application * bq25896: add reading OTG config * furi-hal-power: add is_otg_enabled API * gpio: introduce new GPIO app, add OTG enable / disable * variable-item-list: add enter callback * gpio: add output test view and scene * gpio app: fix GpioItemTester -> GpioItemTest Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									7a89791b2b
								
							
						
					
					
						commit
						638f276308
					
				| @ -20,7 +20,7 @@ extern int32_t accessor_app(void* p); | ||||
| extern int32_t archive_app(void* p); | ||||
| extern int32_t blink_test_app(void* p); | ||||
| extern int32_t flipper_test_app(void* p); | ||||
| extern int32_t gpio_test_app(void* p); | ||||
| extern int32_t gpio_app(void* p); | ||||
| extern int32_t ibutton_app(void* p); | ||||
| extern int32_t irda_app(void* p); | ||||
| extern int32_t irda_monitor_app(void* p); | ||||
| @ -132,8 +132,8 @@ const FlipperApplication FLIPPER_APPS[] = { | ||||
|     {.app = ibutton_app, .name = "iButton", .stack_size = 2048, .icon = &A_iButton_14}, | ||||
| #endif | ||||
| 
 | ||||
| #ifdef APP_GPIO_TEST | ||||
|     {.app = gpio_test_app, .name = "GPIO", .stack_size = 1024, .icon = &A_GPIO_14}, | ||||
| #ifdef APP_GPIO | ||||
|     {.app = gpio_app, .name = "GPIO", .stack_size = 1024, .icon = &A_GPIO_14}, | ||||
| #endif | ||||
| 
 | ||||
| }; | ||||
|  | ||||
| @ -24,7 +24,7 @@ SRV_STORAGE	= 1 | ||||
| # Apps
 | ||||
| SRV_DESKTOP	= 1 | ||||
| APP_ARCHIVE	= 1 | ||||
| APP_GPIO_TEST = 1 | ||||
| APP_GPIO = 1 | ||||
| APP_IBUTTON	= 1 | ||||
| APP_IRDA	= 1 | ||||
| APP_LF_RFID	= 1 | ||||
| @ -135,9 +135,9 @@ SRV_GUI		= 1 | ||||
| endif | ||||
| 
 | ||||
| 
 | ||||
| APP_GPIO_TEST ?= 0 | ||||
| ifeq ($(APP_GPIO_TEST), 1) | ||||
| CFLAGS		+= -DAPP_GPIO_TEST | ||||
| APP_GPIO ?= 0 | ||||
| ifeq ($(APP_GPIO), 1) | ||||
| CFLAGS		+= -DAPP_GPIO | ||||
| SRV_GUI		= 1 | ||||
| endif | ||||
| 
 | ||||
|  | ||||
| @ -1,148 +0,0 @@ | ||||
| #include <furi.h> | ||||
| #include <furi-hal.h> | ||||
| 
 | ||||
| #include <gui/gui.h> | ||||
| #include <notification/notification-messages.h> | ||||
| 
 | ||||
| typedef struct { | ||||
|     const char* name; | ||||
|     const GpioPin* pin; | ||||
| } GpioItem; | ||||
| 
 | ||||
| static const GpioItem GPIO_PINS[] = { | ||||
|     {"1.2: PA7", &gpio_ext_pa7}, | ||||
|     {"1.3: PA6", &gpio_ext_pa6}, | ||||
|     {"1.4: PA4", &gpio_ext_pa4}, | ||||
|     {"1.5: PB3", &gpio_ext_pb3}, | ||||
|     {"1.6: PB2", &gpio_ext_pb2}, | ||||
|     {"1.7: PC3", &gpio_ext_pc3}, | ||||
|     {"2.7: PC1", &gpio_ext_pc1}, | ||||
|     {"2.8: PC0", &gpio_ext_pc0}, | ||||
|     {"*.*: ALL", NULL}, | ||||
| }; | ||||
| 
 | ||||
| static const size_t GPIO_PINS_COUNT = sizeof(GPIO_PINS) / sizeof(GPIO_PINS[0]); | ||||
| 
 | ||||
| typedef struct { | ||||
|     osMessageQueueId_t input_queue; | ||||
|     uint8_t gpio_index; | ||||
|     ViewPort* view_port; | ||||
|     Gui* gui; | ||||
|     NotificationApp* notification; | ||||
| } GpioTest; | ||||
| 
 | ||||
| static void gpio_test_render_callback(Canvas* canvas, void* ctx) { | ||||
|     GpioTest* gpio_test = ctx; | ||||
| 
 | ||||
|     canvas_clear(canvas); | ||||
|     canvas_set_color(canvas, ColorBlack); | ||||
|     canvas_set_font(canvas, FontPrimary); | ||||
|     canvas_draw_str(canvas, 2, 10, "GPIO Control"); | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
|     canvas_draw_str(canvas, 2, 25, GPIO_PINS[gpio_test->gpio_index].name); | ||||
| } | ||||
| 
 | ||||
| static void gpio_test_input_callback(InputEvent* input_event, void* ctx) { | ||||
|     GpioTest* gpio_test = ctx; | ||||
| 
 | ||||
|     osMessageQueuePut(gpio_test->input_queue, input_event, 0, 0); | ||||
| } | ||||
| 
 | ||||
| static void gpio_test_configure_pins(GpioMode mode) { | ||||
|     for(size_t i = 0; i < GPIO_PINS_COUNT; i++) { | ||||
|         if(!GPIO_PINS[i].pin) continue; | ||||
|         hal_gpio_write(GPIO_PINS[i].pin, false); | ||||
|         hal_gpio_init(GPIO_PINS[i].pin, mode, GpioPullNo, GpioSpeedVeryHigh); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void gpio_test_set_pin(uint8_t index, bool level) { | ||||
|     if(GPIO_PINS[index].pin) { | ||||
|         hal_gpio_write(GPIO_PINS[index].pin, level); | ||||
|     } else { | ||||
|         for(size_t i = 0; i < GPIO_PINS_COUNT; i++) { | ||||
|             if(!GPIO_PINS[i].pin) continue; | ||||
|             hal_gpio_write(GPIO_PINS[i].pin, level); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| GpioTest* gpio_test_alloc() { | ||||
|     GpioTest* instance = furi_alloc(sizeof(GpioTest)); | ||||
| 
 | ||||
|     gpio_test_configure_pins(GpioModeOutputPushPull); | ||||
| 
 | ||||
|     instance->input_queue = osMessageQueueNew(8, sizeof(InputEvent), NULL); | ||||
|     furi_check(instance->input_queue); | ||||
| 
 | ||||
|     instance->view_port = view_port_alloc(); | ||||
|     view_port_draw_callback_set(instance->view_port, gpio_test_render_callback, instance); | ||||
|     view_port_input_callback_set(instance->view_port, gpio_test_input_callback, instance); | ||||
| 
 | ||||
|     instance->gui = furi_record_open("gui"); | ||||
|     gui_add_view_port(instance->gui, instance->view_port, GuiLayerFullscreen); | ||||
| 
 | ||||
|     instance->notification = furi_record_open("notification"); | ||||
| 
 | ||||
|     return instance; | ||||
| } | ||||
| 
 | ||||
| void gpio_test_free(GpioTest* instance) { | ||||
|     furi_assert(instance); | ||||
| 
 | ||||
|     furi_record_close("notification"); | ||||
| 
 | ||||
|     view_port_enabled_set(instance->view_port, false); | ||||
|     gui_remove_view_port(instance->gui, instance->view_port); | ||||
|     furi_record_close("gui"); | ||||
| 
 | ||||
|     view_port_free(instance->view_port); | ||||
| 
 | ||||
|     osMessageQueueDelete(instance->input_queue); | ||||
| 
 | ||||
|     gpio_test_configure_pins(GpioModeAnalog); | ||||
| 
 | ||||
|     free(instance); | ||||
| } | ||||
| 
 | ||||
| int32_t gpio_test_app(void* p) { | ||||
|     GpioTest* gpio_test = gpio_test_alloc(); | ||||
| 
 | ||||
|     InputEvent event; | ||||
|     while(osMessageQueueGet(gpio_test->input_queue, &event, NULL, osWaitForever) == osOK) { | ||||
|         if(event.type == InputTypeShort) { | ||||
|             if(event.key == InputKeyBack) { | ||||
|                 notification_message(gpio_test->notification, &sequence_reset_green); | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|             if(event.key == InputKeyRight) { | ||||
|                 if(gpio_test->gpio_index < (GPIO_PINS_COUNT - 1)) { | ||||
|                     gpio_test->gpio_index++; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if(event.key == InputKeyLeft) { | ||||
|                 if(gpio_test->gpio_index > 0) { | ||||
|                     gpio_test->gpio_index--; | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             if(event.key == InputKeyOk) { | ||||
|                 if(event.type == InputTypePress) { | ||||
|                     gpio_test_set_pin(gpio_test->gpio_index, true); | ||||
|                     notification_message(gpio_test->notification, &sequence_set_green_255); | ||||
|                 } else if(event.type == InputTypeRelease) { | ||||
|                     gpio_test_set_pin(gpio_test->gpio_index, false); | ||||
|                     notification_message(gpio_test->notification, &sequence_reset_green); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         view_port_update(gpio_test->view_port); | ||||
|     } | ||||
| 
 | ||||
|     gpio_test_free(gpio_test); | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										76
									
								
								applications/gpio/gpio_app.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										76
									
								
								applications/gpio/gpio_app.c
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,76 @@ | ||||
| #include "gpio_app_i.h" | ||||
| 
 | ||||
| #include <furi.h> | ||||
| #include <furi-hal.h> | ||||
| 
 | ||||
| static bool gpio_app_custom_event_callback(void* context, uint32_t event) { | ||||
|     furi_assert(context); | ||||
|     GpioApp* app = context; | ||||
|     return scene_manager_handle_custom_event(app->scene_manager, event); | ||||
| } | ||||
| 
 | ||||
| static bool gpio_app_back_event_callback(void* context) { | ||||
|     furi_assert(context); | ||||
|     GpioApp* app = context; | ||||
|     return scene_manager_handle_back_event(app->scene_manager); | ||||
| } | ||||
| 
 | ||||
| GpioApp* gpio_app_alloc() { | ||||
|     GpioApp* app = furi_alloc(sizeof(GpioApp)); | ||||
| 
 | ||||
|     app->gui = furi_record_open("gui"); | ||||
|     app->notifications = furi_record_open("notification"); | ||||
| 
 | ||||
|     app->view_dispatcher = view_dispatcher_alloc(); | ||||
|     app->scene_manager = scene_manager_alloc(&gpio_scene_handlers, app); | ||||
|     view_dispatcher_enable_queue(app->view_dispatcher); | ||||
|     view_dispatcher_set_event_callback_context(app->view_dispatcher, app); | ||||
| 
 | ||||
|     view_dispatcher_set_custom_event_callback( | ||||
|         app->view_dispatcher, gpio_app_custom_event_callback); | ||||
|     view_dispatcher_set_navigation_event_callback( | ||||
|         app->view_dispatcher, gpio_app_back_event_callback); | ||||
| 
 | ||||
|     view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); | ||||
| 
 | ||||
|     app->var_item_list = variable_item_list_alloc(); | ||||
|     view_dispatcher_add_view( | ||||
|         app->view_dispatcher, | ||||
|         GpioAppViewVarItemList, | ||||
|         variable_item_list_get_view(app->var_item_list)); | ||||
|     app->gpio_test = gpio_test_alloc(); | ||||
|     view_dispatcher_add_view( | ||||
|         app->view_dispatcher, GpioAppViewGpioTest, gpio_test_get_view(app->gpio_test)); | ||||
| 
 | ||||
|     scene_manager_next_scene(app->scene_manager, GpioSceneStart); | ||||
| 
 | ||||
|     return app; | ||||
| } | ||||
| 
 | ||||
| void gpio_app_free(GpioApp* app) { | ||||
|     furi_assert(app); | ||||
| 
 | ||||
|     // Views
 | ||||
|     view_dispatcher_remove_view(app->view_dispatcher, GpioAppViewVarItemList); | ||||
|     variable_item_list_free(app->var_item_list); | ||||
|     view_dispatcher_remove_view(app->view_dispatcher, GpioAppViewGpioTest); | ||||
|     gpio_test_free(app->gpio_test); | ||||
|     // View dispatcher
 | ||||
|     view_dispatcher_free(app->view_dispatcher); | ||||
|     scene_manager_free(app->scene_manager); | ||||
|     // Close records
 | ||||
|     furi_record_close("gui"); | ||||
|     furi_record_close("notification"); | ||||
| 
 | ||||
|     free(app); | ||||
| } | ||||
| 
 | ||||
| int32_t gpio_app(void* p) { | ||||
|     GpioApp* gpio_app = gpio_app_alloc(); | ||||
| 
 | ||||
|     view_dispatcher_run(gpio_app->view_dispatcher); | ||||
| 
 | ||||
|     gpio_app_free(gpio_app); | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										11
									
								
								applications/gpio/gpio_app.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								applications/gpio/gpio_app.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| typedef struct GpioApp GpioApp; | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										28
									
								
								applications/gpio/gpio_app_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								applications/gpio/gpio_app_i.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "gpio_app.h" | ||||
| #include "gpio_item.h" | ||||
| #include "scenes/gpio_scene.h" | ||||
| 
 | ||||
| #include <gui/gui.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| #include <gui/scene_manager.h> | ||||
| #include <notification/notification-messages.h> | ||||
| 
 | ||||
| #include <gui/modules/variable-item-list.h> | ||||
| #include "views/gpio_test.h" | ||||
| 
 | ||||
| struct GpioApp { | ||||
|     Gui* gui; | ||||
|     ViewDispatcher* view_dispatcher; | ||||
|     SceneManager* scene_manager; | ||||
|     NotificationApp* notifications; | ||||
| 
 | ||||
|     VariableItemList* var_item_list; | ||||
|     GpioTest* gpio_test; | ||||
| }; | ||||
| 
 | ||||
| typedef enum { | ||||
|     GpioAppViewVarItemList, | ||||
|     GpioAppViewGpioTest, | ||||
| } GpioAppView; | ||||
							
								
								
									
										51
									
								
								applications/gpio/gpio_item.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								applications/gpio/gpio_item.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | ||||
| #include "gpio_item.h" | ||||
| 
 | ||||
| #include <furi-hal-resources.h> | ||||
| 
 | ||||
| typedef struct { | ||||
|     const char* name; | ||||
|     const GpioPin* pin; | ||||
| } GpioItem; | ||||
| 
 | ||||
| static const GpioItem gpio_item[GPIO_ITEM_COUNT] = { | ||||
|     {"1.2: PA7", &gpio_ext_pa7}, | ||||
|     {"1.3: PA6", &gpio_ext_pa6}, | ||||
|     {"1.4: PA4", &gpio_ext_pa4}, | ||||
|     {"1.5: PB3", &gpio_ext_pb3}, | ||||
|     {"1.6: PB2", &gpio_ext_pb2}, | ||||
|     {"1.7: PC3", &gpio_ext_pc3}, | ||||
|     {"2.7: PC1", &gpio_ext_pc1}, | ||||
|     {"2.8: PC0", &gpio_ext_pc0}, | ||||
| }; | ||||
| 
 | ||||
| void gpio_item_configure_pin(uint8_t index, GpioMode mode) { | ||||
|     furi_assert(index < GPIO_ITEM_COUNT); | ||||
|     hal_gpio_write(gpio_item[index].pin, false); | ||||
|     hal_gpio_init(gpio_item[index].pin, mode, GpioPullNo, GpioSpeedVeryHigh); | ||||
| } | ||||
| 
 | ||||
| void gpio_item_configure_all_pins(GpioMode mode) { | ||||
|     for(uint8_t i = 0; i < GPIO_ITEM_COUNT; i++) { | ||||
|         gpio_item_configure_pin(i, mode); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void gpio_item_set_pin(uint8_t index, bool level) { | ||||
|     furi_assert(index < GPIO_ITEM_COUNT); | ||||
|     hal_gpio_write(gpio_item[index].pin, level); | ||||
| } | ||||
| 
 | ||||
| void gpio_item_set_all_pins(bool level) { | ||||
|     for(uint8_t i = 0; i < GPIO_ITEM_COUNT; i++) { | ||||
|         gpio_item_set_pin(i, level); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| const char* gpio_item_get_pin_name(uint8_t index) { | ||||
|     furi_assert(index < GPIO_ITEM_COUNT + 1); | ||||
|     if(index == GPIO_ITEM_COUNT) { | ||||
|         return "ALL"; | ||||
|     } else { | ||||
|         return gpio_item[index].name; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										15
									
								
								applications/gpio/gpio_item.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								applications/gpio/gpio_item.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <furi-hal-gpio.h> | ||||
| 
 | ||||
| #define GPIO_ITEM_COUNT 8 | ||||
| 
 | ||||
| void gpio_item_configure_pin(uint8_t index, GpioMode mode); | ||||
| 
 | ||||
| void gpio_item_configure_all_pins(GpioMode mode); | ||||
| 
 | ||||
| void gpio_item_set_pin(uint8_t index, bool level); | ||||
| 
 | ||||
| void gpio_item_set_all_pins(bool level); | ||||
| 
 | ||||
| const char* gpio_item_get_pin_name(uint8_t index); | ||||
							
								
								
									
										30
									
								
								applications/gpio/scenes/gpio_scene.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								applications/gpio/scenes/gpio_scene.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | ||||
| #include "gpio_scene.h" | ||||
| 
 | ||||
| // Generate scene on_enter handlers array
 | ||||
| #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, | ||||
| void (*const gpio_scene_on_enter_handlers[])(void*) = { | ||||
| #include "gpio_scene_config.h" | ||||
| }; | ||||
| #undef ADD_SCENE | ||||
| 
 | ||||
| // Generate scene on_event handlers array
 | ||||
| #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, | ||||
| bool (*const gpio_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = { | ||||
| #include "gpio_scene_config.h" | ||||
| }; | ||||
| #undef ADD_SCENE | ||||
| 
 | ||||
| // Generate scene on_exit handlers array
 | ||||
| #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, | ||||
| void (*const gpio_scene_on_exit_handlers[])(void* context) = { | ||||
| #include "gpio_scene_config.h" | ||||
| }; | ||||
| #undef ADD_SCENE | ||||
| 
 | ||||
| // Initialize scene handlers configuration structure
 | ||||
| const SceneManagerHandlers gpio_scene_handlers = { | ||||
|     .on_enter_handlers = gpio_scene_on_enter_handlers, | ||||
|     .on_event_handlers = gpio_scene_on_event_handlers, | ||||
|     .on_exit_handlers = gpio_scene_on_exit_handlers, | ||||
|     .scene_num = GpioSceneNum, | ||||
| }; | ||||
							
								
								
									
										29
									
								
								applications/gpio/scenes/gpio_scene.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								applications/gpio/scenes/gpio_scene.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <gui/scene_manager.h> | ||||
| 
 | ||||
| // Generate scene id and total number
 | ||||
| #define ADD_SCENE(prefix, name, id) GpioScene##id, | ||||
| typedef enum { | ||||
| #include "gpio_scene_config.h" | ||||
|     GpioSceneNum, | ||||
| } GpioScene; | ||||
| #undef ADD_SCENE | ||||
| 
 | ||||
| extern const SceneManagerHandlers gpio_scene_handlers; | ||||
| 
 | ||||
| // Generate scene on_enter handlers declaration
 | ||||
| #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); | ||||
| #include "gpio_scene_config.h" | ||||
| #undef ADD_SCENE | ||||
| 
 | ||||
| // Generate scene on_event handlers declaration
 | ||||
| #define ADD_SCENE(prefix, name, id) \ | ||||
|     bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); | ||||
| #include "gpio_scene_config.h" | ||||
| #undef ADD_SCENE | ||||
| 
 | ||||
| // Generate scene on_exit handlers declaration
 | ||||
| #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); | ||||
| #include "gpio_scene_config.h" | ||||
| #undef ADD_SCENE | ||||
							
								
								
									
										2
									
								
								applications/gpio/scenes/gpio_scene_config.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								applications/gpio/scenes/gpio_scene_config.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| ADD_SCENE(gpio, start, Start) | ||||
| ADD_SCENE(gpio, test, Test) | ||||
							
								
								
									
										92
									
								
								applications/gpio/scenes/gpio_scene_start.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										92
									
								
								applications/gpio/scenes/gpio_scene_start.c
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,92 @@ | ||||
| #include "../gpio_app_i.h" | ||||
| #include "furi-hal-power.h" | ||||
| 
 | ||||
| #define GPIO_SCENE_START_CUSTOM_EVENT_OTG_OFF (0UL) | ||||
| #define GPIO_SCENE_START_CUSTOM_EVENT_OTG_ON (1UL) | ||||
| #define GPIO_SCENE_START_CUSTOM_EVENT_TEST (2UL) | ||||
| 
 | ||||
| enum GpioItem { | ||||
|     GpioItemOtg, | ||||
|     GpioItemTest, | ||||
| }; | ||||
| 
 | ||||
| enum GpioOtg { | ||||
|     GpioOtgOff, | ||||
|     GpioOtgOn, | ||||
|     GpioOtgSettingsNum, | ||||
| }; | ||||
| 
 | ||||
| const char* const gpio_otg_text[GpioOtgSettingsNum] = { | ||||
|     "Off", | ||||
|     "On", | ||||
| }; | ||||
| 
 | ||||
| static void gpio_scene_start_var_list_enter_callback(void* context, uint32_t index) { | ||||
|     furi_assert(context); | ||||
|     GpioApp* app = context; | ||||
|     if(index == GpioItemTest) { | ||||
|         view_dispatcher_send_custom_event( | ||||
|             app->view_dispatcher, GPIO_SCENE_START_CUSTOM_EVENT_TEST); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void gpio_scene_start_var_list_change_callback(VariableItem* item) { | ||||
|     GpioApp* app = variable_item_get_context(item); | ||||
|     uint8_t index = variable_item_get_current_value_index(item); | ||||
| 
 | ||||
|     variable_item_set_current_value_text(item, gpio_otg_text[index]); | ||||
|     if(index == GpioOtgOff) { | ||||
|         view_dispatcher_send_custom_event( | ||||
|             app->view_dispatcher, GPIO_SCENE_START_CUSTOM_EVENT_OTG_OFF); | ||||
|     } else if(index == GpioOtgOn) { | ||||
|         view_dispatcher_send_custom_event( | ||||
|             app->view_dispatcher, GPIO_SCENE_START_CUSTOM_EVENT_OTG_ON); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void gpio_scene_start_on_enter(void* context) { | ||||
|     GpioApp* app = context; | ||||
|     VariableItemList* var_item_list = app->var_item_list; | ||||
| 
 | ||||
|     VariableItem* item; | ||||
|     variable_item_list_set_enter_callback( | ||||
|         var_item_list, gpio_scene_start_var_list_enter_callback, app); | ||||
|     item = variable_item_list_add( | ||||
|         var_item_list, | ||||
|         "5V on GPIO", | ||||
|         GpioOtgSettingsNum, | ||||
|         gpio_scene_start_var_list_change_callback, | ||||
|         app); | ||||
|     if(furi_hal_power_is_otg_enabled()) { | ||||
|         variable_item_set_current_value_index(item, GpioOtgOn); | ||||
|         variable_item_set_current_value_text(item, gpio_otg_text[GpioOtgOn]); | ||||
|     } else { | ||||
|         variable_item_set_current_value_index(item, GpioOtgOff); | ||||
|         variable_item_set_current_value_text(item, gpio_otg_text[GpioOtgOff]); | ||||
|     } | ||||
|     variable_item_list_add(var_item_list, "GPIO tester", 0, NULL, NULL); | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewVarItemList); | ||||
| } | ||||
| 
 | ||||
| bool gpio_scene_start_on_event(void* context, SceneManagerEvent event) { | ||||
|     GpioApp* app = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == GPIO_SCENE_START_CUSTOM_EVENT_OTG_ON) { | ||||
|             furi_hal_power_enable_otg(); | ||||
|         } else if(event.event == GPIO_SCENE_START_CUSTOM_EVENT_OTG_OFF) { | ||||
|             furi_hal_power_disable_otg(); | ||||
|         } else if(event.event == GPIO_SCENE_START_CUSTOM_EVENT_TEST) { | ||||
|             scene_manager_next_scene(app->scene_manager, GpioSceneTest); | ||||
|         } | ||||
|         consumed = true; | ||||
|     } | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void gpio_scene_start_on_exit(void* context) { | ||||
|     GpioApp* app = context; | ||||
|     variable_item_list_clean(app->var_item_list); | ||||
| } | ||||
							
								
								
									
										27
									
								
								applications/gpio/scenes/gpio_scene_test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								applications/gpio/scenes/gpio_scene_test.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| #include "../gpio_app_i.h" | ||||
| 
 | ||||
| void gpio_scene_test_ok_callback(InputType type, void* context) { | ||||
|     furi_assert(context); | ||||
|     GpioApp* app = context; | ||||
| 
 | ||||
|     if(type == InputTypePress) { | ||||
|         notification_message(app->notifications, &sequence_set_green_255); | ||||
|     } else if(type == InputTypeRelease) { | ||||
|         notification_message(app->notifications, &sequence_reset_green); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void gpio_scene_test_on_enter(void* context) { | ||||
|     GpioApp* app = context; | ||||
|     gpio_item_configure_all_pins(GpioModeOutputPushPull); | ||||
|     gpio_test_set_ok_callback(app->gpio_test, gpio_scene_test_ok_callback, app); | ||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewGpioTest); | ||||
| } | ||||
| 
 | ||||
| bool gpio_scene_test_on_event(void* context, SceneManagerEvent event) { | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| void gpio_scene_test_on_exit(void* context) { | ||||
|     gpio_item_configure_all_pins(GpioModeAnalog); | ||||
| } | ||||
							
								
								
									
										130
									
								
								applications/gpio/views/gpio_test.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										130
									
								
								applications/gpio/views/gpio_test.c
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,130 @@ | ||||
| #include "gpio_test.h" | ||||
| #include "../gpio_item.h" | ||||
| 
 | ||||
| #include <gui/elements.h> | ||||
| 
 | ||||
| struct GpioTest { | ||||
|     View* view; | ||||
|     GpioTestOkCallback callback; | ||||
|     void* context; | ||||
| }; | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint8_t pin_idx; | ||||
| } GpioTestModel; | ||||
| 
 | ||||
| static bool gpio_test_process_left(GpioTest* gpio_test); | ||||
| static bool gpio_test_process_right(GpioTest* gpio_test); | ||||
| static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event); | ||||
| 
 | ||||
| static void gpio_test_draw_callback(Canvas* canvas, void* _model) { | ||||
|     GpioTestModel* model = _model; | ||||
|     canvas_set_font(canvas, FontPrimary); | ||||
|     elements_multiline_text_aligned(canvas, 64, 2, AlignCenter, AlignTop, "Gpio Output mode test"); | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
|     elements_multiline_text_aligned( | ||||
|         canvas, 64, 16, AlignCenter, AlignTop, "Press < or > to change pin"); | ||||
|     elements_multiline_text_aligned( | ||||
|         canvas, 64, 32, AlignCenter, AlignTop, gpio_item_get_pin_name(model->pin_idx)); | ||||
| } | ||||
| 
 | ||||
| static bool gpio_test_input_callback(InputEvent* event, void* context) { | ||||
|     furi_assert(context); | ||||
|     GpioTest* gpio_test = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event->type == InputTypeShort) { | ||||
|         if(event->key == InputKeyRight) { | ||||
|             consumed = gpio_test_process_right(gpio_test); | ||||
|         } else if(event->key == InputKeyLeft) { | ||||
|             consumed = gpio_test_process_left(gpio_test); | ||||
|         } | ||||
|     } else if(event->key == InputKeyOk) { | ||||
|         consumed = gpio_test_process_ok(gpio_test, event); | ||||
|     } | ||||
| 
 | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| static bool gpio_test_process_left(GpioTest* gpio_test) { | ||||
|     with_view_model( | ||||
|         gpio_test->view, (GpioTestModel * model) { | ||||
|             if(model->pin_idx) { | ||||
|                 model->pin_idx--; | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| static bool gpio_test_process_right(GpioTest* gpio_test) { | ||||
|     with_view_model( | ||||
|         gpio_test->view, (GpioTestModel * model) { | ||||
|             if(model->pin_idx < GPIO_ITEM_COUNT) { | ||||
|                 model->pin_idx++; | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event) { | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     with_view_model( | ||||
|         gpio_test->view, (GpioTestModel * model) { | ||||
|             if(event->type == InputTypePress) { | ||||
|                 if(model->pin_idx < GPIO_ITEM_COUNT) { | ||||
|                     gpio_item_set_pin(model->pin_idx, true); | ||||
|                 } else { | ||||
|                     gpio_item_set_all_pins(true); | ||||
|                 } | ||||
|                 consumed = true; | ||||
|             } else if(event->type == InputTypeRelease) { | ||||
|                 if(model->pin_idx < GPIO_ITEM_COUNT) { | ||||
|                     gpio_item_set_pin(model->pin_idx, false); | ||||
|                 } else { | ||||
|                     gpio_item_set_all_pins(false); | ||||
|                 } | ||||
|                 consumed = true; | ||||
|             } | ||||
|             gpio_test->callback(event->type, gpio_test->context); | ||||
|             return true; | ||||
|         }); | ||||
| 
 | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| GpioTest* gpio_test_alloc() { | ||||
|     GpioTest* gpio_test = furi_alloc(sizeof(GpioTest)); | ||||
| 
 | ||||
|     gpio_test->view = view_alloc(); | ||||
|     view_allocate_model(gpio_test->view, ViewModelTypeLocking, sizeof(GpioTestModel)); | ||||
|     view_set_context(gpio_test->view, gpio_test); | ||||
|     view_set_draw_callback(gpio_test->view, gpio_test_draw_callback); | ||||
|     view_set_input_callback(gpio_test->view, gpio_test_input_callback); | ||||
| 
 | ||||
|     return gpio_test; | ||||
| } | ||||
| 
 | ||||
| void gpio_test_free(GpioTest* gpio_test) { | ||||
|     furi_assert(gpio_test); | ||||
|     view_free(gpio_test->view); | ||||
|     free(gpio_test); | ||||
| } | ||||
| 
 | ||||
| View* gpio_test_get_view(GpioTest* gpio_test) { | ||||
|     furi_assert(gpio_test); | ||||
|     return gpio_test->view; | ||||
| } | ||||
| 
 | ||||
| void gpio_test_set_ok_callback(GpioTest* gpio_test, GpioTestOkCallback callback, void* context) { | ||||
|     furi_assert(gpio_test); | ||||
|     furi_assert(callback); | ||||
|     with_view_model( | ||||
|         gpio_test->view, (GpioTestModel * model) { | ||||
|             gpio_test->callback = callback; | ||||
|             gpio_test->context = context; | ||||
|             return false; | ||||
|         }); | ||||
| } | ||||
							
								
								
									
										14
									
								
								applications/gpio/views/gpio_test.h
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										14
									
								
								applications/gpio/views/gpio_test.h
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,14 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <gui/view.h> | ||||
| 
 | ||||
| typedef struct GpioTest GpioTest; | ||||
| typedef void (*GpioTestOkCallback)(InputType type, void* context); | ||||
| 
 | ||||
| GpioTest* gpio_test_alloc(); | ||||
| 
 | ||||
| void gpio_test_free(GpioTest* gpio_test); | ||||
| 
 | ||||
| View* gpio_test_get_view(GpioTest* gpio_test); | ||||
| 
 | ||||
| void gpio_test_set_ok_callback(GpioTest* gpio_test, GpioTestOkCallback callback, void* context); | ||||
							
								
								
									
										29
									
								
								applications/gui/modules/variable-item-list.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										29
									
								
								applications/gui/modules/variable-item-list.c
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -18,6 +18,8 @@ ARRAY_DEF(VariableItemArray, VariableItem, M_POD_OPLIST); | ||||
| 
 | ||||
| struct VariableItemList { | ||||
|     View* view; | ||||
|     VariableItemListEnterCallback callback; | ||||
|     void* context; | ||||
| }; | ||||
| 
 | ||||
| typedef struct { | ||||
| @ -30,6 +32,7 @@ static void variable_item_list_process_up(VariableItemList* variable_item_list); | ||||
| static void variable_item_list_process_down(VariableItemList* variable_item_list); | ||||
| static void variable_item_list_process_left(VariableItemList* variable_item_list); | ||||
| static void variable_item_list_process_right(VariableItemList* variable_item_list); | ||||
| static void variable_item_list_process_ok(VariableItemList* variable_item_list); | ||||
| 
 | ||||
| static void variable_item_list_draw_callback(Canvas* canvas, void* _model) { | ||||
|     VariableItemListModel* model = _model; | ||||
| @ -104,6 +107,9 @@ static bool variable_item_list_input_callback(InputEvent* event, void* context) | ||||
|             consumed = true; | ||||
|             variable_item_list_process_right(variable_item_list); | ||||
|             break; | ||||
|         case InputKeyOk: | ||||
|             variable_item_list_process_ok(variable_item_list); | ||||
|             break; | ||||
|         default: | ||||
|             break; | ||||
|         } | ||||
| @ -198,6 +204,16 @@ void variable_item_list_process_right(VariableItemList* variable_item_list) { | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| void variable_item_list_process_ok(VariableItemList* variable_item_list) { | ||||
|     with_view_model( | ||||
|         variable_item_list->view, (VariableItemListModel * model) { | ||||
|             if(variable_item_list->callback) { | ||||
|                 variable_item_list->callback(variable_item_list->context, model->position); | ||||
|             } | ||||
|             return false; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| VariableItemList* variable_item_list_alloc() { | ||||
|     VariableItemList* variable_item_list = furi_alloc(sizeof(VariableItemList)); | ||||
|     variable_item_list->view = view_alloc(); | ||||
| @ -280,6 +296,19 @@ VariableItem* variable_item_list_add( | ||||
|     return item; | ||||
| } | ||||
| 
 | ||||
| void variable_item_list_set_enter_callback( | ||||
|     VariableItemList* variable_item_list, | ||||
|     VariableItemListEnterCallback callback, | ||||
|     void* context) { | ||||
|     furi_assert(callback); | ||||
|     with_view_model( | ||||
|         variable_item_list->view, (VariableItemListModel * model) { | ||||
|             variable_item_list->callback = callback; | ||||
|             variable_item_list->context = context; | ||||
|             return false; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| void variable_item_set_current_value_index(VariableItem* item, uint8_t current_value_index) { | ||||
|     item->current_value_index = current_value_index; | ||||
| } | ||||
|  | ||||
							
								
								
									
										14
									
								
								applications/gui/modules/variable-item-list.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										14
									
								
								applications/gui/modules/variable-item-list.h
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -8,6 +8,7 @@ extern "C" { | ||||
| typedef struct VariableItemList VariableItemList; | ||||
| typedef struct VariableItem VariableItem; | ||||
| typedef void (*VariableItemChangeCallback)(VariableItem* item); | ||||
| typedef void (*VariableItemListEnterCallback)(void* context, uint32_t index); | ||||
| 
 | ||||
| /** Allocate and initialize VariableItemList
 | ||||
|  * @return VariableItemList*  | ||||
| @ -19,6 +20,9 @@ VariableItemList* variable_item_list_alloc(); | ||||
|  */ | ||||
| void variable_item_list_free(VariableItemList* variable_item_list); | ||||
| 
 | ||||
| /** Clear all elements from list
 | ||||
|  * @param variable_item_list VariableItemList instance | ||||
|  */ | ||||
| void variable_item_list_clean(VariableItemList* variable_item_list); | ||||
| 
 | ||||
| View* variable_item_list_get_view(VariableItemList* variable_item_list); | ||||
| @ -38,6 +42,16 @@ VariableItem* variable_item_list_add( | ||||
|     VariableItemChangeCallback change_callback, | ||||
|     void* context); | ||||
| 
 | ||||
| /** Set enter callback
 | ||||
|  * @param variable_item_list VariableItemList instance | ||||
|  * @param calback VariableItemListEnterCallback instance | ||||
|  * @param context pointer to context | ||||
|  */ | ||||
| void variable_item_list_set_enter_callback( | ||||
|     VariableItemList* variable_item_list, | ||||
|     VariableItemListEnterCallback callback, | ||||
|     void* context); | ||||
| 
 | ||||
| /** Set item current selected index
 | ||||
|  * @param item VariableItem* instance | ||||
|  * @param current_value_index  | ||||
|  | ||||
| @ -180,6 +180,10 @@ void furi_hal_power_disable_otg() { | ||||
|     bq25896_disable_otg(); | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_power_is_otg_enabled() { | ||||
|     return bq25896_is_otg_enabled(); | ||||
| } | ||||
| 
 | ||||
| uint32_t furi_hal_power_get_battery_remaining_capacity() { | ||||
|     return bq27220_get_remaining_capacity(); | ||||
| } | ||||
|  | ||||
| @ -180,6 +180,10 @@ void furi_hal_power_disable_otg() { | ||||
|     bq25896_disable_otg(); | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_power_is_otg_enabled() { | ||||
|     return bq25896_is_otg_enabled(); | ||||
| } | ||||
| 
 | ||||
| uint32_t furi_hal_power_get_battery_remaining_capacity() { | ||||
|     return bq27220_get_remaining_capacity(); | ||||
| } | ||||
|  | ||||
| @ -69,6 +69,9 @@ void furi_hal_power_enable_otg(); | ||||
| /** OTG disable */ | ||||
| void furi_hal_power_disable_otg(); | ||||
| 
 | ||||
| /** Get OTG status */ | ||||
| bool furi_hal_power_is_otg_enabled(); | ||||
| 
 | ||||
| /** Get remaining battery battery capacity in mAh */ | ||||
| uint32_t furi_hal_power_get_battery_remaining_capacity(); | ||||
| 
 | ||||
|  | ||||
| @ -101,6 +101,11 @@ void bq25896_disable_otg() { | ||||
|     bq25896_write_reg(0x03, (uint8_t*)&bq25896_regs.r03); | ||||
| } | ||||
| 
 | ||||
| bool bq25896_is_otg_enabled() { | ||||
|     bq25896_read_reg(0x03, (uint8_t*)&bq25896_regs.r03); | ||||
|     return bq25896_regs.r03.OTG_CONFIG; | ||||
| } | ||||
| 
 | ||||
| uint16_t bq25896_get_vbus_voltage() { | ||||
|     bq25896_read_reg(0x11, (uint8_t*)&bq25896_regs.r11); | ||||
|     if(bq25896_regs.r11.VBUS_GD) { | ||||
|  | ||||
| @ -18,6 +18,9 @@ void bq25896_enable_otg(); | ||||
| /** Disable otg */ | ||||
| void bq25896_disable_otg(); | ||||
| 
 | ||||
| /** Is otg enabled */ | ||||
| bool bq25896_is_otg_enabled(); | ||||
| 
 | ||||
| /** Get VBUS Voltage in mV */ | ||||
| uint16_t bq25896_get_vbus_voltage(); | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user