diff --git a/applications/applications.h b/applications/applications.h index 673ed461..0759eb6c 100644 --- a/applications/applications.h +++ b/applications/applications.h @@ -33,6 +33,7 @@ void nfc_task(void* p); void irukagotchi_task(void* p); void power_task(void* p); void application_vibro(void* p); +void app_gpio_test(void* p); const FlipperStartupApp FLIPPER_STARTUP[] = { #ifdef APP_DISPLAY @@ -109,7 +110,14 @@ const FlipperStartupApp FLIPPER_STARTUP[] = { #ifdef APP_SPEAKER_DEMO {.app = coreglitch_demo_0, .name = "coreglitch_demo_0", .libs = {0}}, #endif -}; + +#ifdef APP_GPIO_DEMO + { + .app = app_gpio_test, + .name = "gpio test", + .libs = {1, FURI_LIB{"gui_task"}}, +#endif + }; const FlipperStartupApp FLIPPER_APPS[] = { #ifdef BUILD_EXAMPLE_BLINK @@ -143,4 +151,8 @@ const FlipperStartupApp FLIPPER_APPS[] = { #ifdef BUILD_VIBRO_DEMO {.app = application_vibro, .name = "application_vibro", .libs = {1, FURI_LIB{"input_task"}}}, #endif + +#ifdef BUILD_GPIO_DEMO + {.app = app_gpio_test, .name = "gpio test", .libs = {1, FURI_LIB{"gui_task"}}}, +#endif }; \ No newline at end of file diff --git a/applications/applications.mk b/applications/applications.mk index 2bd65f9c..16a20cc0 100644 --- a/applications/applications.mk +++ b/applications/applications.mk @@ -20,6 +20,7 @@ BUILD_CC1101 = 1 BUILD_LF_RFID = 1 BUILD_SPEAKER_DEMO = 1 BUILD_VIBRO_DEMO = 1 +BUILD_GPIO_DEMO = 1 endif APP_NFC ?= 0 @@ -212,6 +213,17 @@ C_SOURCES += $(wildcard $(APP_DIR)/examples/vibro.c) APP_INPUT = 1 endif +APP_GPIO_DEMO ?= 0 +ifeq ($(APP_GPIO_DEMO), 1) +CFLAGS += -DAPP_GPIO_DEMO +BUILD_GPIO_DEMO = 1 +endif +BUILD_GPIO_DEMO ?= 0 +ifeq ($(BUILD_GPIO_DEMO), 1) +CFLAGS += -DBUILD_GPIO_DEMO +C_SOURCES += $(wildcard $(APP_DIR)/gpio-tester/*.c) +endif + # device drivers APP_GUI ?= 0 diff --git a/applications/gpio-tester/gpio-tester.c b/applications/gpio-tester/gpio-tester.c new file mode 100644 index 00000000..8fad7ade --- /dev/null +++ b/applications/gpio-tester/gpio-tester.c @@ -0,0 +1,128 @@ +#include "flipper_v2.h" + +typedef struct { + const char* name; + GpioPin pin; +} GpioItem; + +const GpioItem GPIO_PINS[] = { + {"1.2: PA7", {GPIOA, GPIO_PIN_7}}, + {"1.3: PA6", {GPIOA, GPIO_PIN_6}}, + {"1.4: PA5", {GPIOA, GPIO_PIN_5}}, + {"1.5: PA4", {GPIOA, GPIO_PIN_4}}, + {"1.6: PB2", {GPIOB, GPIO_PIN_2}}, + {"1.7: PC3", {GPIOC, GPIO_PIN_3}}, + + {"2.7: PC1", {GPIOC, GPIO_PIN_1}}, + {"2.8: PC0", {GPIOC, GPIO_PIN_0}}, +}; + +typedef enum { + EventTypeTick, + EventTypeKey, +} EventType; + +typedef struct { + union { + InputEvent input; + } value; + EventType type; +} AppEvent; + +typedef struct { + uint8_t gpio_index; +} State; + +static void render_callback(CanvasApi* canvas, void* ctx) { + State* state = (State*)acquire_mutex((ValueMutex*)ctx, 25); + + canvas->clear(canvas); + canvas->set_color(canvas, ColorBlack); + canvas->set_font(canvas, FontPrimary); + canvas->draw_str(canvas, 2, 10, "GPIO demo"); + canvas->set_font(canvas, FontSecondary); + canvas->draw_str(canvas, 2, 25, GPIO_PINS[state->gpio_index].name); + + release_mutex((ValueMutex*)ctx, state); +} + +static void input_callback(InputEvent* input_event, void* ctx) { + osMessageQueueId_t event_queue = (QueueHandle_t)ctx; + + AppEvent event; + event.type = EventTypeKey; + event.value.input = *input_event; + osMessageQueuePut(event_queue, &event, 0, 0); +} + +void app_gpio_test(void* p) { + osMessageQueueId_t event_queue = osMessageQueueNew(1, sizeof(AppEvent), NULL); + furi_check(event_queue); + + State _state; + _state.gpio_index = 0; + + ValueMutex state_mutex; + if(!init_mutex(&state_mutex, &_state, sizeof(State))) { + printf("[gpio-tester] cannot create mutex\n"); + furiac_exit(NULL); + } + + Widget* widget = widget_alloc(); + + widget_draw_callback_set(widget, render_callback, &state_mutex); + widget_input_callback_set(widget, input_callback, event_queue); + + // Open GUI and register widget + GuiApi* gui = (GuiApi*)furi_open("gui"); + if(gui == NULL) { + printf("[gpio-tester] gui is not available\n"); + furiac_exit(NULL); + } + gui->add_widget(gui, widget, GuiLayerFullscreen); + + // configure pin + for(uint8_t i = 0; i < sizeof(GPIO_PINS) / sizeof(GPIO_PINS[0]); i++) { + gpio_init((GpioPin*)&GPIO_PINS[i].pin, GpioModeOutputPushPull); + } + + gpio_init((GpioPin*)&led_gpio[1], GpioModeOutputOpenDrain); + + AppEvent event; + while(1) { + osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, 150); + State* state = (State*)acquire_mutex_block(&state_mutex); + + if(event_status == osOK) { + if(event.type == EventTypeKey) { + if(event.value.input.state && event.value.input.input == InputBack) { + printf("[gpio-tester] bye!\n"); + // TODO remove all widgets create by app + widget_enabled_set(widget, false); + furiac_exit(NULL); + } + + if(event.value.input.state && event.value.input.input == InputRight) { + if(state->gpio_index < (sizeof(GPIO_PINS) / sizeof(GPIO_PINS[0]) - 1)) { + state->gpio_index++; + } + } + + if(event.value.input.state && event.value.input.input == InputLeft) { + if(state->gpio_index > 0) { + state->gpio_index--; + } + } + + if(event.value.input.input == InputOk) { + gpio_write( + (GpioPin*)&GPIO_PINS[state->gpio_index].pin, event.value.input.state); + gpio_write((GpioPin*)&led_gpio[1], !event.value.input.state); + } + } + } + + release_mutex(&state_mutex, state); + widget_update(widget); + } +}