fix multithread logic in template app, update gpio HAL (#250)

* fix multithread logic
* more buffer for dallas id string
* update apps to use new logic
* delay_us small speedup
* add consant qualifier to gpio records and some core api
* fix some apps to use simpler method of getting gpio record
* fix ibutton app, stupid stack problem
This commit is contained in:
DrZlo13 2020-11-19 15:25:32 +03:00 committed by GitHub
parent ccd40497eb
commit a96f23af9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 137 additions and 88 deletions

View File

@ -7,11 +7,8 @@ static void event_cb(const void* value, void* ctx) {
const uint32_t BACKLIGHT_TIME = 10000; const uint32_t BACKLIGHT_TIME = 10000;
void backlight_control(void* p) { void backlight_control(void* p) {
// create pin
GpioPin backlight = backlight_gpio;
// TODO open record // TODO open record
GpioPin* backlight_record = &backlight; const GpioPin* backlight_record = &backlight_gpio;
// configure pin // configure pin
gpio_init(backlight_record, GpioModeOutputPushPull); gpio_init(backlight_record, GpioModeOutputPushPull);

View File

@ -1,21 +1,22 @@
#include "flipper_v2.h" #include "flipper_v2.h"
void rgb_set(bool r, bool g, bool b, GpioPin* led_r, GpioPin* led_g, GpioPin* led_b) { void rgb_set(
bool r,
bool g,
bool b,
const GpioPin* led_r,
const GpioPin* led_g,
const GpioPin* led_b) {
gpio_write(led_r, !r); gpio_write(led_r, !r);
gpio_write(led_g, !g); gpio_write(led_g, !g);
gpio_write(led_b, !b); gpio_write(led_b, !b);
} }
void application_blink(void* p) { void application_blink(void* p) {
// create pin
GpioPin led_r = led_gpio[0];
GpioPin led_g = led_gpio[1];
GpioPin led_b = led_gpio[2];
// TODO open record // TODO open record
GpioPin* led_r_record = &led_r; const GpioPin* led_r_record = &led_gpio[0];
GpioPin* led_g_record = &led_g; const GpioPin* led_g_record = &led_gpio[1];
GpioPin* led_b_record = &led_b; const GpioPin* led_b_record = &led_gpio[2];
// configure pin // configure pin
gpio_init(led_r_record, GpioModeOutputOpenDrain); gpio_init(led_r_record, GpioModeOutputOpenDrain);

View File

@ -4,25 +4,21 @@
// start app // start app
void AppiButton::run() { void AppiButton::run() {
acquire_state();
mode[0] = new AppiButtonModeDallasRead(this); mode[0] = new AppiButtonModeDallasRead(this);
mode[1] = new AppiButtonModeDallasEmulate(this); mode[1] = new AppiButtonModeDallasEmulate(this);
release_state();
switch_to_mode(0); switch_to_mode(0);
// create pin
GpioPin red_led = led_gpio[0];
GpioPin green_led = led_gpio[1];
// TODO open record // TODO open record
red_led_record = &red_led; red_led_record = &led_gpio[0];
green_led_record = &green_led; green_led_record = &led_gpio[1];
// configure pin // configure pin
gpio_init(red_led_record, GpioModeOutputOpenDrain); gpio_init(red_led_record, GpioModeOutputOpenDrain);
gpio_init(green_led_record, GpioModeOutputOpenDrain); gpio_init(green_led_record, GpioModeOutputOpenDrain);
app_ready();
AppiButtonEvent event; AppiButtonEvent event;
while(1) { while(1) {
if(get_event(&event, 100)) { if(get_event(&event, 100)) {
@ -61,9 +57,7 @@ void AppiButton::render(CanvasApi* canvas) {
canvas->set_font(canvas, FontPrimary); canvas->set_font(canvas, FontPrimary);
canvas->draw_str(canvas, 2, 12, "iButton"); canvas->draw_str(canvas, 2, 12, "iButton");
if(mode[state.mode_index] != NULL) { mode[state.mode_index]->render(canvas, &state);
mode[state.mode_index]->render(canvas, &state);
}
} }
void AppiButton::blink_red() { void AppiButton::blink_red() {

View File

@ -38,11 +38,11 @@ public:
// with template variables <state, events> // with template variables <state, events>
class AppiButton : public AppTemplate<AppiButtonState, AppiButtonEvent> { class AppiButton : public AppTemplate<AppiButtonState, AppiButtonEvent> {
public: public:
GpioPin* red_led_record; const GpioPin* red_led_record;
GpioPin* green_led_record; const GpioPin* green_led_record;
static const uint8_t modes_count = 2; static const uint8_t modes_count = 2;
AppTemplateMode<AppiButtonState, AppiButtonEvent>* mode[modes_count] = {NULL, NULL}; AppTemplateMode<AppiButtonState, AppiButtonEvent>* mode[modes_count];
void run(); void run();
void render(CanvasApi* canvas); void render(CanvasApi* canvas);

View File

@ -17,8 +17,7 @@ public:
app = parent_app; app = parent_app;
// TODO open record // TODO open record
GpioPin one_wire_pin = ibutton_gpio; const GpioPin* one_wire_pin_record = &ibutton_gpio;
GpioPin* one_wire_pin_record = &one_wire_pin;
onewire_slave = new OneWireGpioSlave(one_wire_pin_record); onewire_slave = new OneWireGpioSlave(one_wire_pin_record);
}; };
}; };
@ -39,9 +38,11 @@ void AppiButtonModeDallasEmulate::render(CanvasApi* canvas, AppiButtonState* sta
canvas->draw_str(canvas, 2, 25, "< dallas emulate"); canvas->draw_str(canvas, 2, 25, "< dallas emulate");
canvas->draw_str(canvas, 2, 37, "unimplemented"); canvas->draw_str(canvas, 2, 37, "unimplemented");
{ {
char buf[24]; const uint8_t buffer_size = 32;
sprintf( char buf[buffer_size];
snprintf(
buf, buf,
buffer_size,
"%x:%x:%x:%x:%x:%x:%x:%x", "%x:%x:%x:%x:%x:%x:%x:%x",
state->dallas_address[0], state->dallas_address[0],
state->dallas_address[1], state->dallas_address[1],

View File

@ -17,8 +17,7 @@ public:
app = parent_app; app = parent_app;
// TODO open record // TODO open record
GpioPin one_wire_pin = ibutton_gpio; const GpioPin* one_wire_pin_record = &ibutton_gpio;
GpioPin* one_wire_pin_record = &one_wire_pin;
onewire = new OneWireGpio(one_wire_pin_record); onewire = new OneWireGpio(one_wire_pin_record);
}; };
@ -68,9 +67,11 @@ void AppiButtonModeDallasRead::render(CanvasApi* canvas, AppiButtonState* state)
canvas->draw_str(canvas, 2, 25, "dallas read >"); canvas->draw_str(canvas, 2, 25, "dallas read >");
canvas->draw_str(canvas, 2, 37, "touch me, iButton"); canvas->draw_str(canvas, 2, 37, "touch me, iButton");
{ {
char buf[24]; const uint8_t buffer_size = 32;
sprintf( char buf[buffer_size];
snprintf(
buf, buf,
buffer_size,
"%x:%x:%x:%x:%x:%x:%x:%x", "%x:%x:%x:%x:%x:%x:%x:%x",
state->dallas_address[0], state->dallas_address[0],
state->dallas_address[1], state->dallas_address[1],

View File

@ -5,10 +5,10 @@
class OneWireGpio { class OneWireGpio {
private: private:
GpioPin* gpio; const GpioPin* gpio;
public: public:
OneWireGpio(GpioPin* one_wire_gpio); OneWireGpio(const GpioPin* one_wire_gpio);
~OneWireGpio(); ~OneWireGpio();
bool reset(void); bool reset(void);
bool read_bit(void); bool read_bit(void);
@ -20,7 +20,7 @@ public:
void stop(void); void stop(void);
}; };
OneWireGpio::OneWireGpio(GpioPin* one_wire_gpio) { OneWireGpio::OneWireGpio(const GpioPin* one_wire_gpio) {
gpio = one_wire_gpio; gpio = one_wire_gpio;
} }

View File

@ -5,10 +5,10 @@
class OneWireGpioSlave { class OneWireGpioSlave {
private: private:
GpioPin* gpio; const GpioPin* gpio;
public: public:
OneWireGpioSlave(GpioPin* one_wire_gpio); OneWireGpioSlave(const GpioPin* one_wire_gpio);
~OneWireGpioSlave(); ~OneWireGpioSlave();
void start(void); void start(void);
void stop(void); void stop(void);
@ -25,7 +25,7 @@ public:
OneWiteTimeType wait_while_gpio(volatile OneWiteTimeType retries, const bool pin_value); OneWiteTimeType wait_while_gpio(volatile OneWiteTimeType retries, const bool pin_value);
}; };
OneWireGpioSlave::OneWireGpioSlave(GpioPin* one_wire_gpio) { OneWireGpioSlave::OneWireGpioSlave(const GpioPin* one_wire_gpio) {
gpio = one_wire_gpio; gpio = one_wire_gpio;
} }

View File

@ -264,11 +264,8 @@ void irda(void* p) {
gui->add_widget(gui, widget, GuiLayerFullscreen); gui->add_widget(gui, widget, GuiLayerFullscreen);
// Red LED // Red LED
// create pin
GpioPin led = led_gpio[0];
// TODO open record // TODO open record
GpioPin* led_record = &led; const GpioPin* led_record = &led_gpio[0];
// configure pin // configure pin
gpio_init(led_record, GpioModeOutputOpenDrain); gpio_init(led_record, GpioModeOutputOpenDrain);

View File

@ -95,6 +95,8 @@ void SdTest::run() {
gpio_init(red_led_record, GpioModeOutputOpenDrain); gpio_init(red_led_record, GpioModeOutputOpenDrain);
gpio_init(green_led_record, GpioModeOutputOpenDrain); gpio_init(green_led_record, GpioModeOutputOpenDrain);
app_ready();
detect_sd_card(); detect_sd_card();
show_warning(); show_warning();
init_sd_card(); init_sd_card();

View File

@ -77,6 +77,8 @@ void AppSdNFC::run() {
gpio_init(red_led_record, GpioModeOutputOpenDrain); gpio_init(red_led_record, GpioModeOutputOpenDrain);
gpio_init(green_led_record, GpioModeOutputOpenDrain); gpio_init(green_led_record, GpioModeOutputOpenDrain);
app_ready();
uint8_t rfal_result = rfalNfcInitialize(); uint8_t rfal_result = rfalNfcInitialize();
if(rfal_result) { if(rfal_result) {
set_text("rfal init fail"); set_text("rfal init fail");

View File

@ -33,7 +33,7 @@ void* acquire_mutex(ValueMutex* valuemutex, uint32_t timeout) {
} }
} }
bool release_mutex(ValueMutex* valuemutex, void* value) { bool release_mutex(ValueMutex* valuemutex, const void* value) {
if(value != valuemutex->value) return false; if(value != valuemutex->value) return false;
if(osMutexRelease(valuemutex->mutex) != osOK) return false; if(osMutexRelease(valuemutex->mutex) != osOK) return false;

View File

@ -58,7 +58,7 @@ static inline void* acquire_mutex_block(ValueMutex* valuemutex) {
Release mutex after end of work with data. Release mutex after end of work with data.
Call `release_mutex` and pass ValueData instance and pointer to data. Call `release_mutex` and pass ValueData instance and pointer to data.
*/ */
bool release_mutex(ValueMutex* valuemutex, void* value); bool release_mutex(ValueMutex* valuemutex, const void* value);
/* /*
Instead of take-access-give sequence you can use `read_mutex` and `write_mutex` functions. Instead of take-access-give sequence you can use `read_mutex` and `write_mutex` functions.

View File

@ -9,7 +9,7 @@ bool gpio_api_init(void) {
} }
// init GPIO // init GPIO
void gpio_init(GpioPin* gpio, GpioMode mode) { void gpio_init(const GpioPin* gpio, const GpioMode mode) {
if(osMutexAcquire(gpioInitMutex, osWaitForever) == osOK) { if(osMutexAcquire(gpioInitMutex, osWaitForever) == osOK) {
hal_gpio_init(gpio, mode, GpioPullNo, GpioSpeedLow); hal_gpio_init(gpio, mode, GpioPullNo, GpioSpeedLow);
osMutexRelease(gpioInitMutex); osMutexRelease(gpioInitMutex);
@ -17,13 +17,17 @@ void gpio_init(GpioPin* gpio, GpioMode mode) {
} }
// init GPIO, extended version // init GPIO, extended version
void gpio_init_ex(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed) { void gpio_init_ex(
const GpioPin* gpio,
const GpioMode mode,
const GpioPull pull,
const GpioSpeed speed) {
hal_gpio_init(gpio, mode, pull, speed); hal_gpio_init(gpio, mode, pull, speed);
} }
// put GPIO to Z-state // put GPIO to Z-state
void gpio_disable(GpioDisableRecord* gpio_record) { void gpio_disable(GpioDisableRecord* gpio_record) {
GpioPin* gpio_pin = acquire_mutex(gpio_record->gpio_mutex, 0); const GpioPin* gpio_pin = acquire_mutex(gpio_record->gpio_mutex, 0);
if(gpio_pin == NULL) { if(gpio_pin == NULL) {
gpio_pin = gpio_record->gpio; gpio_pin = gpio_record->gpio;
} }

View File

@ -12,13 +12,17 @@ typedef struct {
bool gpio_api_init(); bool gpio_api_init();
// init GPIO // init GPIO
void gpio_init(GpioPin* gpio, GpioMode mode); void gpio_init(const GpioPin* gpio, const GpioMode mode);
// init GPIO, extended version // init GPIO, extended version
void gpio_init_ex(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed); void gpio_init_ex(
const GpioPin* gpio,
const GpioMode mode,
const GpioPull pull,
const GpioSpeed speed);
// write value to GPIO, false = LOW, true = HIGH // write value to GPIO, false = LOW, true = HIGH
static inline void gpio_write(GpioPin* gpio, bool state) { static inline void gpio_write(const GpioPin* gpio, const bool state) {
hal_gpio_write(gpio, state); hal_gpio_write(gpio, state);
} }

View File

@ -1,7 +1,11 @@
#include "api-hal-gpio.h" #include "api-hal-gpio.h"
// init GPIO // init GPIO
void hal_gpio_init(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed) { void hal_gpio_init(
const GpioPin* gpio,
const GpioMode mode,
const GpioPull pull,
const GpioSpeed speed) {
// TODO: Alternate Functions // TODO: Alternate Functions
GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitTypeDef GPIO_InitStruct = {0};

View File

@ -39,10 +39,14 @@ typedef struct {
} GpioPin; } GpioPin;
// init GPIO // init GPIO
void hal_gpio_init(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed); void hal_gpio_init(
const GpioPin* gpio,
const GpioMode mode,
const GpioPull pull,
const GpioSpeed speed);
// write value to GPIO, false = LOW, true = HIGH // write value to GPIO, false = LOW, true = HIGH
static inline void hal_gpio_write(GpioPin* gpio, bool state) { static inline void hal_gpio_write(const GpioPin* gpio, const bool state) {
// writing to BSSR is an atomic operation // writing to BSSR is an atomic operation
if(state == true) { if(state == true) {
gpio->port->BSRR = gpio->pin; gpio->port->BSRR = gpio->pin;

View File

@ -2,15 +2,18 @@
#include "assert.h" #include "assert.h"
#include "cmsis_os2.h" #include "cmsis_os2.h"
static uint32_t clk_per_microsecond;
void delay_us_init_DWT(void) { void delay_us_init_DWT(void) {
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
DWT->CYCCNT = 0U; DWT->CYCCNT = 0U;
clk_per_microsecond = SystemCoreClock / 1000000.0f;
} }
void delay_us(float microseconds) { void delay_us(float microseconds) {
uint32_t start = DWT->CYCCNT; uint32_t start = DWT->CYCCNT;
uint32_t time_ticks = microseconds * (SystemCoreClock / 1000000.0f); uint32_t time_ticks = microseconds * clk_per_microsecond;
while((DWT->CYCCNT - start) < time_ticks) { while((DWT->CYCCNT - start) < time_ticks) {
}; };
} }

View File

@ -2,7 +2,11 @@
#include "api-hal-resources.h" #include "api-hal-resources.h"
// init GPIO // init GPIO
void hal_gpio_init(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed) { void hal_gpio_init(
const GpioPin* gpio,
const GpioMode mode,
const GpioPull pull,
const GpioSpeed speed) {
// TODO: Alternate Functions // TODO: Alternate Functions
GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitTypeDef GPIO_InitStruct = {0};
@ -16,10 +20,9 @@ void hal_gpio_init(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed)
bool hal_gpio_read_sd_detect(void) { bool hal_gpio_read_sd_detect(void) {
bool result = false; bool result = false;
// create pin
GpioPin sd_cs_pin = sd_cs_gpio;
// TODO open record // TODO open record
GpioPin* sd_cs_record = &sd_cs_pin; const GpioPin* sd_cs_record = &sd_cs_gpio;
// configure pin as input // configure pin as input
gpio_init_ex(sd_cs_record, GpioModeInput, GpioPullUp, GpioSpeedVeryHigh); gpio_init_ex(sd_cs_record, GpioModeInput, GpioPullUp, GpioSpeedVeryHigh);

View File

@ -39,10 +39,14 @@ typedef struct {
} GpioPin; } GpioPin;
// init GPIO // init GPIO
void hal_gpio_init(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed); void hal_gpio_init(
const GpioPin* gpio,
const GpioMode mode,
const GpioPull pull,
const GpioSpeed speed);
// write value to GPIO, false = LOW, true = HIGH // write value to GPIO, false = LOW, true = HIGH
static inline void hal_gpio_write(GpioPin* gpio, bool state) { static inline void hal_gpio_write(const GpioPin* gpio, const bool state) {
// writing to BSSR is an atomic operation // writing to BSSR is an atomic operation
if(state == true) { if(state == true) {
gpio->port->BSRR = gpio->pin; gpio->port->BSRR = gpio->pin;

View File

@ -2,7 +2,11 @@
#include <stdio.h> #include <stdio.h>
// init GPIO // init GPIO
void hal_gpio_init(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed){ void hal_gpio_init(
const GpioPin* gpio,
const GpioMode mode,
const GpioPull pull,
const GpioSpeed speed) {
// TODO more mode // TODO more mode
if(gpio->pin != 0) { if(gpio->pin != 0) {
switch(mode) { switch(mode) {
@ -17,7 +21,7 @@ void hal_gpio_init(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed)
case GpioModeOutputOpenDrain: case GpioModeOutputOpenDrain:
printf("[GPIO] %s%d open drain\n", gpio->port, gpio->pin); printf("[GPIO] %s%d open drain\n", gpio->port, gpio->pin);
break; break;
default: default:
printf("[GPIO] %s%d mode %d unsupported\n", gpio->port, gpio->pin, mode); printf("[GPIO] %s%d mode %d unsupported\n", gpio->port, gpio->pin, mode);
break; break;
@ -28,7 +32,7 @@ void hal_gpio_init(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed)
} }
// write value to GPIO, false = LOW, true = HIGH // write value to GPIO, false = LOW, true = HIGH
void hal_gpio_write(GpioPin* gpio, bool state){ void hal_gpio_write(const GpioPin* gpio, const bool state) {
if(gpio->pin != 0) { if(gpio->pin != 0) {
if(state) { if(state) {
printf("[GPIO] %s%d on\n", gpio->port, gpio->pin); printf("[GPIO] %s%d on\n", gpio->port, gpio->pin);
@ -41,7 +45,7 @@ void hal_gpio_write(GpioPin* gpio, bool state){
} }
// read value from GPIO, false = LOW, true = HIGH // read value from GPIO, false = LOW, true = HIGH
bool hal_gpio_read(const GpioPin* gpio){ bool hal_gpio_read(const GpioPin* gpio) {
// TODO emulate pin state? // TODO emulate pin state?
return false; return false;
} }

View File

@ -40,10 +40,14 @@ typedef struct {
} GpioPin; } GpioPin;
// init GPIO // init GPIO
void hal_gpio_init(GpioPin* gpio, GpioMode mode, GpioPull pull, GpioSpeed speed); void hal_gpio_init(
const GpioPin* gpio,
const GpioMode mode,
const GpioPull pull,
const GpioSpeed speed);
// write value to GPIO, false = LOW, true = HIGH // write value to GPIO, false = LOW, true = HIGH
void hal_gpio_write(GpioPin* gpio, bool state); void hal_gpio_write(const GpioPin* gpio, const bool state);
// read value from GPIO, false = LOW, true = HIGH // read value from GPIO, false = LOW, true = HIGH
bool hal_gpio_read(const GpioPin* gpio); bool hal_gpio_read(const GpioPin* gpio);

View File

@ -21,7 +21,7 @@ public:
// state initializer // state initializer
AppExampleState() { AppExampleState() {
example_data = 12; example_data = 0;
} }
}; };
@ -51,6 +51,16 @@ public:
// start app // start app
void AppExample::run() { void AppExample::run() {
// here we dont need to acquire or release state
// because before we call app_ready our application is "single threaded"
state.example_data = 12;
// signal that we ready to render and ipc
app_ready();
// from here, any data that pass in render function must be guarded
// by calling acquire_state and release_state
AppExampleEvent event; AppExampleEvent event;
while(1) { while(1) {
if(get_event(&event, 1000)) { if(get_event(&event, 1000)) {

View File

@ -6,20 +6,21 @@
// simple app class with template variables <state, events> // simple app class with template variables <state, events>
template <class TState, class TEvent> class AppTemplate { template <class TState, class TEvent> class AppTemplate {
public: public:
AppTemplate();
~AppTemplate();
void input_callback(InputEvent* input_event, void* ctx);
void draw_callback(CanvasApi* canvas, void* ctx);
virtual void render(CanvasApi* canvas) = 0;
Widget* widget; Widget* widget;
osMessageQueueId_t event_queue; osMessageQueueId_t event_queue;
TState state; TState state;
ValueMutex state_mutex; ValueMutex state_mutex;
GuiApi* gui; GuiApi* gui;
AppTemplate();
~AppTemplate();
void input_callback(InputEvent* input_event, void* ctx);
void draw_callback(CanvasApi* canvas, void* ctx);
virtual void render(CanvasApi* canvas) = 0;
void acquire_state(void); void acquire_state(void);
void release_state(void); void release_state(void);
bool get_event(TEvent* event, uint32_t timeout); bool get_event(TEvent* event, uint32_t timeout);
void app_ready(void);
void exit(void); void exit(void);
void update_gui(void); void update_gui(void);
}; };
@ -35,24 +36,15 @@ template <class TState, class TEvent> AppTemplate<TState, TEvent>::AppTemplate()
furiac_exit(NULL); furiac_exit(NULL);
} }
// allocate widget // open gui
widget = widget_alloc();
// connect widget with input callback
auto input_cb_ref = cbc::obtain_connector(this, &AppTemplate::input_callback);
widget_input_callback_set(widget, input_cb_ref, this);
// connect widget with draw callback
auto draw_cb_ref = cbc::obtain_connector(this, &AppTemplate::draw_callback);
widget_draw_callback_set(widget, draw_cb_ref, this);
// open gui and add widget
gui = (GuiApi*)furi_open("gui"); gui = (GuiApi*)furi_open("gui");
if(gui == NULL) { if(gui == NULL) {
printf("gui is not available\n"); printf("gui is not available\n");
furiac_exit(NULL); furiac_exit(NULL);
} }
gui->add_widget(gui, widget, GuiLayerFullscreen);
// allocate widget
widget = widget_alloc();
} }
template <class TState, class TEvent> AppTemplate<TState, TEvent>::~AppTemplate() { template <class TState, class TEvent> AppTemplate<TState, TEvent>::~AppTemplate() {
@ -96,6 +88,24 @@ bool AppTemplate<TState, TEvent>::get_event(TEvent* event, uint32_t timeout) {
return (event_status == osOK); return (event_status == osOK);
} }
// signal that app is ready, and we can render something
// also unblock dependent tasks
template <class TState, class TEvent> void AppTemplate<TState, TEvent>::app_ready(void) {
// connect widget with input callback
auto input_cb_ref = cbc::obtain_connector(this, &AppTemplate::input_callback);
widget_input_callback_set(widget, input_cb_ref, this);
// connect widget with draw callback
auto draw_cb_ref = cbc::obtain_connector(this, &AppTemplate::draw_callback);
widget_draw_callback_set(widget, draw_cb_ref, this);
// add widget
gui->add_widget(gui, widget, GuiLayerFullscreen);
// signal that our app ready to work
furiac_ready();
}
template <class TState, class TEvent> void AppTemplate<TState, TEvent>::exit(void) { template <class TState, class TEvent> void AppTemplate<TState, TEvent>::exit(void) {
// TODO remove all widgets create by app // TODO remove all widgets create by app
widget_enabled_set(widget, false); widget_enabled_set(widget, false);