[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:
gornekich 2021-09-30 23:03:28 +03:00 committed by GitHub
parent 7a89791b2b
commit 638f276308
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 574 additions and 155 deletions

View File

@ -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
}; };

View File

@ -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

View File

@ -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
View 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;
}

View File

@ -0,0 +1,11 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
typedef struct GpioApp GpioApp;
#ifdef __cplusplus
}
#endif

View 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;

View 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;
}
}

View 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);

View 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,
};

View 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

View File

@ -0,0 +1,2 @@
ADD_SCENE(gpio, start, Start)
ADD_SCENE(gpio, test, Test)

View 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);
}

View 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);
}

View 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;
});
}

View 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
View 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
View 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

View File

@ -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();
} }

View File

@ -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();
} }

View File

@ -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();

View File

@ -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) {

View File

@ -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();