Example ipc (#60)

* add blank example

* add ipc example code, need to change FURI API

* add ipc example code, need to change FURI API

* change core API, add context

* check handler at take

* fix important bugs in furi

* drawing example

* add posix mq

* fix unsigned demo counter

* create at open

* working local demo

* russian version of IPC example

* english version

* add gif
This commit is contained in:
coreglitch
2020-09-01 16:34:23 +06:00
committed by GitHub
parent f7882dbff4
commit 5b6ab7faf3
16 changed files with 538 additions and 33 deletions

158
applications/examples/ipc.c Normal file
View File

@@ -0,0 +1,158 @@
#include "flipper.h"
#include <string.h>
#define FB_WIDTH 10
#define FB_HEIGHT 3
#define FB_SIZE (FB_WIDTH * FB_HEIGHT)
// context structure used for pass some object from app thread to callback
typedef struct {
SemaphoreHandle_t events; // queue to pass events from callback to app thread
FuriRecordSubscriber* log; // app logger
} IpcCtx;
static void handle_fb_change(const void* fb, size_t fb_size, void* raw_ctx) {
IpcCtx* ctx = (IpcCtx*)raw_ctx; // make right type
fuprintf(ctx->log, "[cb] framebuffer updated\n");
// send event to app thread
xSemaphoreGive(ctx->events);
// Attention! Please, do not make blocking operation like IO and waits inside callback
// Remember that callback execute in calling thread/context
}
static void print_fb(char* fb, FuriRecordSubscriber* log) {
if(fb == NULL) return;
/* draw framebuffer like this:
+==========+
| |
| |
| |
+==========+
*/
char row_buffer[FB_WIDTH + 1];
row_buffer[FB_WIDTH] = '\0';
// FB layout is hardcoded here
fuprintf(log, "+==========+\n");
for(uint8_t i = 0; i < FB_HEIGHT; i++) {
strncpy(row_buffer, &fb[FB_WIDTH * i], FB_WIDTH);
fuprintf(log, "|%s|\n", row_buffer);
}
fuprintf(log, "+==========+\n");
}
void application_ipc_display(void* p) {
// get logger
FuriRecordSubscriber* log = get_default_log();
// create ASCII "framebuffer"
// FB_WIDTH x FB_HEIGHT char buffer
char _framebuffer[FB_SIZE];
// init framebuffer by spaces
for(size_t i = 0; i < FB_SIZE; i++) {
_framebuffer[i] = ' ';
}
// create record
if(!furi_create("test_fb", (void*)_framebuffer, FB_SIZE)) {
fuprintf(log, "[display] cannot create fb record\n");
furiac_exit(NULL);
}
StaticSemaphore_t event_descriptor;
// create stack-based counting semaphore
SemaphoreHandle_t events = xSemaphoreCreateCountingStatic(255, 0, &event_descriptor);
if(events == NULL) {
fuprintf(log, "[display] cannot create event semaphore\n");
furiac_exit(NULL);
}
// save log and event queue in context structure
IpcCtx ctx = {.events = events, .log = log};
// subscribe to record. ctx will be passed to handle_fb_change
FuriRecordSubscriber* fb_record = furi_open(
"test_fb", false, false, handle_fb_change, NULL, &ctx
);
if(fb_record == NULL) {
fuprintf(log, "[display] cannot open fb record\n");
furiac_exit(NULL);
}
#ifdef HW_DISPLAY
// on Flipper target -- open screen
// draw border
#else
// on Local target -- print "blank screen"
{
void* fb = furi_take(fb_record);
print_fb((char*)fb, log);
furi_give(fb_record);
}
#endif
while(1) {
// wait for event
if(xSemaphoreTake(events, portMAX_DELAY) == pdTRUE) {
fuprintf(log, "[display] get fb update\n\n");
#ifdef HW_DISPLAY
// on Flipper target draw the screen
#else
// on local target just print
{
void* fb = furi_take(fb_record);
print_fb((char*)fb, log);
furi_give(fb_record);
}
#endif
}
}
}
// Widget application
void application_ipc_widget(void* p) {
FuriRecordSubscriber* log = get_default_log();
// open record
FuriRecordSubscriber* fb_record = furi_open(
"test_fb", false, false, NULL, NULL, NULL
);
if(fb_record == NULL) {
fuprintf(log, "[widget] cannot create fb record\n");
furiac_exit(NULL);
}
uint8_t counter = 0;
while(1) {
delay(120);
// write some ascii demo here: '#'' symbol run on overall screen
char* fb = (char*)furi_take(fb_record);
if(fb == NULL) furiac_exit(NULL);
for(size_t i = 0; i < FB_SIZE; i++) {
fb[i] = ' ';
}
fb[counter % FB_SIZE] = '#';
furi_commit(fb_record);
counter++;
}
}

View File

@@ -13,6 +13,8 @@ void flipper_test_app(void* p);
void application_blink(void* p);
void application_uart_write(void* p);
void application_ipc_display(void* p);
void application_ipc_widget(void* p);
const FlipperStartupApp FLIPPER_STARTUP[] = {
#ifdef TEST
@@ -25,4 +27,8 @@ const FlipperStartupApp FLIPPER_STARTUP[] = {
#ifdef EXAMPLE_UART_WRITE
{.app = application_uart_write, .name = "uart write"},
#endif
#ifdef EXAMPLE_IPC
{.app = application_ipc_display, .name = "ipc display"},
{.app = application_ipc_widget, .name = "ipc widget"},
#endif
};

View File

@@ -17,7 +17,7 @@ TEST: pipe record
static uint8_t pipe_record_value = 0;
void pipe_record_cb(const void* value, size_t size) {
void pipe_record_cb(const void* value, size_t size, void* ctx) {
// hold value to static var
pipe_record_value = *((uint8_t*)value);
}
@@ -31,7 +31,7 @@ bool test_furi_pipe_record(FuriRecordSubscriber* log) {
// 2. Open/subscribe to it
FuriRecordSubscriber* pipe_record = furi_open(
"test/pipe", false, false, pipe_record_cb, NULL
"test/pipe", false, false, pipe_record_cb, NULL, NULL
);
if(pipe_record == NULL) {
fuprintf(log, "cannot open record\n");
@@ -83,7 +83,7 @@ TEST: holding data
static uint8_t holding_record_value = 0;
void holding_record_cb(const void* value, size_t size) {
void holding_record_cb(const void* value, size_t size, void* ctx) {
// hold value to static var
holding_record_value = *((uint8_t*)value);
}
@@ -98,7 +98,7 @@ bool test_furi_holding_data(FuriRecordSubscriber* log) {
// 2. Open/Subscribe on it
FuriRecordSubscriber* holding_record = furi_open(
"test/holding", false, false, holding_record_cb, NULL
"test/holding", false, false, holding_record_cb, NULL, NULL
);
if(holding_record == NULL) {
fuprintf(log, "cannot open record\n");
@@ -164,7 +164,7 @@ void furi_concurent_app(void* p) {
FuriRecordSubscriber* log = (FuriRecordSubscriber*)p;
FuriRecordSubscriber* holding_record = furi_open(
"test/concurrent", false, false, NULL, NULL
"test/concurrent", false, false, NULL, NULL, NULL
);
if(holding_record == NULL) {
fuprintf(log, "cannot open record\n");
@@ -203,7 +203,7 @@ bool test_furi_concurrent_access(FuriRecordSubscriber* log) {
// 2. Open it
FuriRecordSubscriber* holding_record = furi_open(
"test/concurrent", false, false, NULL, NULL
"test/concurrent", false, false, NULL, NULL, NULL
);
if(holding_record == NULL) {
fuprintf(log, "cannot open record\n");
@@ -307,12 +307,12 @@ TODO: test 7 not pass beacuse cleanup is not implemented
static uint8_t mute_last_value = 0;
static FlipperRecordState mute_last_state = 255;
void mute_record_cb(const void* value, size_t size) {
void mute_record_cb(const void* value, size_t size, void* ctx) {
// hold value to static var
mute_last_value = *((uint8_t*)value);
}
void mute_record_state_cb(FlipperRecordState state) {
void mute_record_state_cb(FlipperRecordState state, void* ctx) {
mute_last_state = state;
}
@@ -327,7 +327,7 @@ void furi_mute_parent_app(void* p) {
// 2. Open watch handler: solo=false, no_mute=false, subscribe to data
FuriRecordSubscriber* watch_handler = furi_open(
"test/mute", false, false, mute_record_cb, NULL
"test/mute", false, false, mute_record_cb, NULL, NULL
);
if(watch_handler == NULL) {
fuprintf(log, "cannot open watch handler\n");
@@ -350,7 +350,7 @@ bool test_furi_mute_algorithm(FuriRecordSubscriber* log) {
// 2. Open handler A: solo=false, no_mute=false, NULL subscriber. Subscribe to state.
FuriRecordSubscriber* handler_a = furi_open(
"test/mute", false, false, NULL, mute_record_state_cb
"test/mute", false, false, NULL, mute_record_state_cb, NULL
);
if(handler_a == NULL) {
fuprintf(log, "cannot open handler A\n");
@@ -372,7 +372,7 @@ bool test_furi_mute_algorithm(FuriRecordSubscriber* log) {
// 3. Open handler B: solo=true, no_mute=true, NULL subscriber.
FuriRecordSubscriber* handler_b = furi_open(
"test/mute", true, true, NULL, NULL
"test/mute", true, true, NULL, NULL, NULL
);
if(handler_b == NULL) {
fuprintf(log, "cannot open handler B\n");
@@ -415,7 +415,7 @@ bool test_furi_mute_algorithm(FuriRecordSubscriber* log) {
// 4. Open hadler C: solo=true, no_mute=false, NULL subscriber.
FuriRecordSubscriber* handler_c = furi_open(
"test/mute", true, false, NULL, NULL
"test/mute", true, false, NULL, NULL, NULL
);
if(handler_c == NULL) {
fuprintf(log, "cannot open handler C\n");
@@ -428,7 +428,7 @@ bool test_furi_mute_algorithm(FuriRecordSubscriber* log) {
// 5. Open handler D: solo=false, no_mute=false, NULL subscriber.
FuriRecordSubscriber* handler_d = furi_open(
"test/mute", false, false, NULL, NULL
"test/mute", false, false, NULL, NULL, NULL
);
if(handler_d == NULL) {
fuprintf(log, "cannot open handler D\n");