[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 archive_app(void* p);
|
||||||
extern int32_t blink_test_app(void* p);
|
extern int32_t blink_test_app(void* p);
|
||||||
extern int32_t flipper_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 ibutton_app(void* p);
|
||||||
extern int32_t irda_app(void* p);
|
extern int32_t irda_app(void* p);
|
||||||
extern int32_t irda_monitor_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},
|
{.app = ibutton_app, .name = "iButton", .stack_size = 2048, .icon = &A_iButton_14},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef APP_GPIO_TEST
|
#ifdef APP_GPIO
|
||||||
{.app = gpio_test_app, .name = "GPIO", .stack_size = 1024, .icon = &A_GPIO_14},
|
{.app = gpio_app, .name = "GPIO", .stack_size = 1024, .icon = &A_GPIO_14},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -24,7 +24,7 @@ SRV_STORAGE = 1
|
|||||||
# Apps
|
# Apps
|
||||||
SRV_DESKTOP = 1
|
SRV_DESKTOP = 1
|
||||||
APP_ARCHIVE = 1
|
APP_ARCHIVE = 1
|
||||||
APP_GPIO_TEST = 1
|
APP_GPIO = 1
|
||||||
APP_IBUTTON = 1
|
APP_IBUTTON = 1
|
||||||
APP_IRDA = 1
|
APP_IRDA = 1
|
||||||
APP_LF_RFID = 1
|
APP_LF_RFID = 1
|
||||||
@ -135,9 +135,9 @@ SRV_GUI = 1
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
APP_GPIO_TEST ?= 0
|
APP_GPIO ?= 0
|
||||||
ifeq ($(APP_GPIO_TEST), 1)
|
ifeq ($(APP_GPIO), 1)
|
||||||
CFLAGS += -DAPP_GPIO_TEST
|
CFLAGS += -DAPP_GPIO
|
||||||
SRV_GUI = 1
|
SRV_GUI = 1
|
||||||
endif
|
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 {
|
struct VariableItemList {
|
||||||
View* view;
|
View* view;
|
||||||
|
VariableItemListEnterCallback callback;
|
||||||
|
void* context;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
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_down(VariableItemList* variable_item_list);
|
||||||
static void variable_item_list_process_left(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_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) {
|
static void variable_item_list_draw_callback(Canvas* canvas, void* _model) {
|
||||||
VariableItemListModel* model = _model;
|
VariableItemListModel* model = _model;
|
||||||
@ -104,6 +107,9 @@ static bool variable_item_list_input_callback(InputEvent* event, void* context)
|
|||||||
consumed = true;
|
consumed = true;
|
||||||
variable_item_list_process_right(variable_item_list);
|
variable_item_list_process_right(variable_item_list);
|
||||||
break;
|
break;
|
||||||
|
case InputKeyOk:
|
||||||
|
variable_item_list_process_ok(variable_item_list);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
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_alloc() {
|
||||||
VariableItemList* variable_item_list = furi_alloc(sizeof(VariableItemList));
|
VariableItemList* variable_item_list = furi_alloc(sizeof(VariableItemList));
|
||||||
variable_item_list->view = view_alloc();
|
variable_item_list->view = view_alloc();
|
||||||
@ -280,6 +296,19 @@ VariableItem* variable_item_list_add(
|
|||||||
return item;
|
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) {
|
void variable_item_set_current_value_index(VariableItem* item, uint8_t current_value_index) {
|
||||||
item->current_value_index = 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 VariableItemList VariableItemList;
|
||||||
typedef struct VariableItem VariableItem;
|
typedef struct VariableItem VariableItem;
|
||||||
typedef void (*VariableItemChangeCallback)(VariableItem* item);
|
typedef void (*VariableItemChangeCallback)(VariableItem* item);
|
||||||
|
typedef void (*VariableItemListEnterCallback)(void* context, uint32_t index);
|
||||||
|
|
||||||
/** Allocate and initialize VariableItemList
|
/** Allocate and initialize VariableItemList
|
||||||
* @return VariableItemList*
|
* @return VariableItemList*
|
||||||
@ -19,6 +20,9 @@ VariableItemList* variable_item_list_alloc();
|
|||||||
*/
|
*/
|
||||||
void variable_item_list_free(VariableItemList* variable_item_list);
|
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);
|
void variable_item_list_clean(VariableItemList* variable_item_list);
|
||||||
|
|
||||||
View* variable_item_list_get_view(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,
|
VariableItemChangeCallback change_callback,
|
||||||
void* context);
|
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
|
/** Set item current selected index
|
||||||
* @param item VariableItem* instance
|
* @param item VariableItem* instance
|
||||||
* @param current_value_index
|
* @param current_value_index
|
||||||
|
@ -180,6 +180,10 @@ void furi_hal_power_disable_otg() {
|
|||||||
bq25896_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() {
|
uint32_t furi_hal_power_get_battery_remaining_capacity() {
|
||||||
return bq27220_get_remaining_capacity();
|
return bq27220_get_remaining_capacity();
|
||||||
}
|
}
|
||||||
|
@ -180,6 +180,10 @@ void furi_hal_power_disable_otg() {
|
|||||||
bq25896_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() {
|
uint32_t furi_hal_power_get_battery_remaining_capacity() {
|
||||||
return bq27220_get_remaining_capacity();
|
return bq27220_get_remaining_capacity();
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,9 @@ void furi_hal_power_enable_otg();
|
|||||||
/** OTG disable */
|
/** OTG disable */
|
||||||
void furi_hal_power_disable_otg();
|
void furi_hal_power_disable_otg();
|
||||||
|
|
||||||
|
/** Get OTG status */
|
||||||
|
bool furi_hal_power_is_otg_enabled();
|
||||||
|
|
||||||
/** Get remaining battery battery capacity in mAh */
|
/** Get remaining battery battery capacity in mAh */
|
||||||
uint32_t furi_hal_power_get_battery_remaining_capacity();
|
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);
|
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() {
|
uint16_t bq25896_get_vbus_voltage() {
|
||||||
bq25896_read_reg(0x11, (uint8_t*)&bq25896_regs.r11);
|
bq25896_read_reg(0x11, (uint8_t*)&bq25896_regs.r11);
|
||||||
if(bq25896_regs.r11.VBUS_GD) {
|
if(bq25896_regs.r11.VBUS_GD) {
|
||||||
|
@ -18,6 +18,9 @@ void bq25896_enable_otg();
|
|||||||
/** Disable otg */
|
/** Disable otg */
|
||||||
void bq25896_disable_otg();
|
void bq25896_disable_otg();
|
||||||
|
|
||||||
|
/** Is otg enabled */
|
||||||
|
bool bq25896_is_otg_enabled();
|
||||||
|
|
||||||
/** Get VBUS Voltage in mV */
|
/** Get VBUS Voltage in mV */
|
||||||
uint16_t bq25896_get_vbus_voltage();
|
uint16_t bq25896_get_vbus_voltage();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user