#include #include #include #include /* Magic happens here -- this file is generated by fbt. * Just set fap_icon_assets in application.fam and #include {APPID}_icons.h */ #include "gpio_controller_icons.h" #include "gpio_items.h" typedef struct { int selected; GPIOItems* gpio_items; int wiggle_frame; } ViewerState; // 5V A7 A6 A4 B3 B2 C3 GND SET // // // 3V SWC GND SIO TX RX C1 C0 1W GND typedef enum { PIN_5V = 0, PIN_A7, PIN_A6, PIN_A4, PIN_B3, PIN_B2, PIN_C3, GEARIC, PIN_3V, PIN_SWC, PIN_SIO, PIN_TX, PIN_RX, PIN_C1, PIN_C0, PIN_1W, PIN_GND_08, PIN_GND_11, PIN_GND_18, NONE }enum_view_element; typedef struct { enum_view_element element; enum_view_element opposite; bool selectable; bool editable; bool top_row; bool pull_out; int gp_idx; uint8_t x_pos; uint8_t y_pos; const char* name; Icon* icon; Icon* selected_icon; }ViewElement; static ViewerState vstate = {.selected = PIN_A7,.gpio_items = NULL,.wiggle_frame=-1}; static int wiggle[] = {-1,1,-1,1}; static ViewElement elements[] = { {PIN_5V, PIN_3V, true, false, true, true, -1, 0, 0, "5V" , (Icon*)&I_5v_pin, NULL}, {PIN_A7, PIN_SWC, true, true, true, true, 0, 14, 0, "A7", (Icon*)&I_a7_pin, NULL}, {PIN_A6, NONE, true, true, true, true, 1, 28, 0, "A6", (Icon*)&I_a6_pin, NULL}, {PIN_A4, PIN_SIO, true, true, true, true, 2, 42, 0, "A4", (Icon*)&I_a4_pin, NULL}, {PIN_B3, PIN_TX, true, true, true, true, 3, 56, 0, "B3", (Icon*)&I_b3_pin, NULL}, {PIN_B2, PIN_RX, true, true, true, true, 4, 70, 0, "B2", (Icon*)&I_b2_pin, NULL}, {PIN_C3, PIN_C1, true, true, true, true, 5, 84, 0, "C3", (Icon*)&I_c3_pin, NULL}, {GEARIC, PIN_1W, true, true, true, false, -1, 112, 0, "Settings", (Icon*)&I_gear_unhighlighted, (Icon*)&I_gear_highlighted}, {PIN_3V, PIN_5V, true, false, false, true, -1, 0, 48, "3.3V", (Icon*)&I_3v_pin, NULL}, {PIN_SWC, PIN_A7, true, false, false, true, -1, 14, 48, "Serial Wire Clock", (Icon*)&I_swc_pin, NULL}, {PIN_SIO, PIN_A4, true, false, false, true, -1, 42, 48, "Serial IO", (Icon*)&I_sio_pin, NULL}, {PIN_TX, PIN_B3, true, false, false, true, -1, 56, 48, "UART - Transmit", (Icon*)&I_tx_pin, NULL}, {PIN_RX, PIN_B2, true, false, false, true, -1, 70, 48, "UART - Receive", (Icon*)&I_rx_pin, NULL}, {PIN_C1, PIN_C3, true, true, false, true, 6, 84, 48, "C1", (Icon*)&I_c1_pin, NULL}, {PIN_C0, NONE, true, true, false, true, 7, 98, 48, "C0", (Icon*)&I_c0_pin, NULL}, {PIN_1W, GEARIC, true, true, false, true, -1, 112, 48, "1-Wire", (Icon*)&I_1w_pin, NULL}, {PIN_GND_08, NONE, false, false, true, false, -1, 98, -1, "GND (Ground)", (Icon*)&I_gnd_pin, NULL}, {PIN_GND_11, NONE, false, false, false, false, -1, 28, 48, "GND (Ground)", (Icon*)&I_gnd_pin, NULL}, {PIN_GND_18, NONE, false, false, false, false, -1, 126, 48, "GND (Ground)", (Icon*)&I_gnd_pin, NULL}, }; static int element_count = NONE; // Screen is 128x64 px static void app_draw_callback(Canvas* canvas, void* ctx) { UNUSED(ctx); canvas_clear(canvas); for(int i = 0; i < element_count; i++) { ViewElement e = elements[i]; int x = e.x_pos; int y = e.y_pos + (e.top_row && e.pull_out ? -3 : 0); Icon* icon = e.icon; if( vstate.selected == i ) { if( e.pull_out ) { y += e.top_row ? 3 : -3; } if( e.selected_icon != NULL ) { icon = e.selected_icon; } if(vstate.wiggle_frame >= 0) { x += wiggle[vstate.wiggle_frame/2]; vstate.wiggle_frame++; if ((unsigned int)(vstate.wiggle_frame/2) >= (sizeof(wiggle)/sizeof(int))) { vstate.wiggle_frame = -1; } } } canvas_draw_icon(canvas, x, y, icon); } canvas_set_font(canvas, FontSecondary); canvas_draw_str(canvas, 0, 40, elements[vstate.selected].name); } static void app_input_callback(InputEvent* input_event, void* ctx) { furi_assert(ctx); FuriMessageQueue* event_queue = ctx; furi_message_queue_put(event_queue, input_event, FuriWaitForever); } int32_t gpio_controller_main(void* p) { UNUSED(p); FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); // Configure view port ViewPort* view_port = view_port_alloc(); view_port_draw_callback_set(view_port, app_draw_callback, view_port); view_port_input_callback_set(view_port, app_input_callback, event_queue); // Register view port in GUI Gui* gui = furi_record_open(RECORD_GUI); gui_add_view_port(gui, view_port, GuiLayerFullscreen); InputEvent event; vstate.gpio_items = gpio_items_alloc(); gpio_items_configure_all_pins(vstate.gpio_items, GpioModeOutputPushPull); bool running = true; while(running) { if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) { if( vstate.wiggle_frame < 0 ) { if( (event.type == InputTypePress || event.type == InputTypeRelease) && event.key == InputKeyOk ) { if( event.type == InputTypePress && elements[vstate.selected].gp_idx < 0 ) { vstate.wiggle_frame = 0; } else if( elements[vstate.selected].gp_idx >= 0 && (event.type == InputTypePress || event.type == InputTypeRelease) ) { gpio_items_set_pin(vstate.gpio_items, elements[vstate.selected].gp_idx, event.type == InputTypePress); } } else if(event.type == InputTypePress || event.type == InputTypeRepeat) { switch(event.key) { case InputKeyLeft: vstate.selected--; if(vstate.selected == GEARIC) vstate.selected = PIN_1W; else if(vstate.selected < 0) vstate.selected = GEARIC; break; case InputKeyRight: if(vstate.selected <= GEARIC) { vstate.selected++; vstate.selected = vstate.selected > GEARIC ? PIN_5V : vstate.selected; } else { vstate.selected++; vstate.selected = vstate.selected > PIN_1W ? PIN_3V : vstate.selected; } break; case InputKeyUp: case InputKeyDown: if (elements[vstate.selected].opposite != NONE) vstate.selected = elements[vstate.selected].opposite; break; case InputKeyBack: running = false; break; default: break; } } } } view_port_update(view_port); } gpio_items_free(vstate.gpio_items); view_port_enabled_set(view_port, false); gui_remove_view_port(gui, view_port); view_port_free(view_port); furi_message_queue_free(event_queue); furi_record_close(RECORD_GUI); return 0; }