2020-09-01 10:34:23 +00:00
|
|
|
#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;
|
2020-09-29 23:18:30 +00:00
|
|
|
|
2020-09-01 10:34:23 +00:00
|
|
|
/* 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
|
2020-10-13 08:22:43 +00:00
|
|
|
if(!furi_create_deprecated("test_fb", (void*)_framebuffer, FB_SIZE)) {
|
2020-09-01 10:34:23 +00:00
|
|
|
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
|
2020-09-29 23:18:30 +00:00
|
|
|
FuriRecordSubscriber* fb_record =
|
2020-10-13 08:22:43 +00:00
|
|
|
furi_open_deprecated("test_fb", false, false, handle_fb_change, NULL, &ctx);
|
2020-09-01 10:34:23 +00:00
|
|
|
|
|
|
|
if(fb_record == NULL) {
|
|
|
|
fuprintf(log, "[display] cannot open fb record\n");
|
|
|
|
furiac_exit(NULL);
|
|
|
|
}
|
|
|
|
|
2020-09-29 23:18:30 +00:00
|
|
|
#ifdef HW_DISPLAY
|
2020-09-01 10:34:23 +00:00
|
|
|
// on Flipper target -- open screen
|
|
|
|
|
|
|
|
// draw border
|
|
|
|
|
2020-09-29 23:18:30 +00:00
|
|
|
#else
|
2020-09-01 10:34:23 +00:00
|
|
|
// on Local target -- print "blank screen"
|
|
|
|
{
|
|
|
|
void* fb = furi_take(fb_record);
|
|
|
|
print_fb((char*)fb, log);
|
|
|
|
furi_give(fb_record);
|
|
|
|
}
|
2020-09-29 23:18:30 +00:00
|
|
|
#endif
|
2020-09-01 10:34:23 +00:00
|
|
|
|
|
|
|
while(1) {
|
|
|
|
// wait for event
|
|
|
|
if(xSemaphoreTake(events, portMAX_DELAY) == pdTRUE) {
|
|
|
|
fuprintf(log, "[display] get fb update\n\n");
|
|
|
|
|
2020-09-29 23:18:30 +00:00
|
|
|
#ifdef HW_DISPLAY
|
|
|
|
// on Flipper target draw the screen
|
|
|
|
#else
|
2020-09-01 10:34:23 +00:00
|
|
|
// on local target just print
|
|
|
|
{
|
|
|
|
void* fb = furi_take(fb_record);
|
|
|
|
print_fb((char*)fb, log);
|
|
|
|
furi_give(fb_record);
|
|
|
|
}
|
2020-09-29 23:18:30 +00:00
|
|
|
#endif
|
2020-09-01 10:34:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Widget application
|
|
|
|
void application_ipc_widget(void* p) {
|
|
|
|
FuriRecordSubscriber* log = get_default_log();
|
|
|
|
|
|
|
|
// open record
|
2020-10-13 08:22:43 +00:00
|
|
|
FuriRecordSubscriber* fb_record =
|
|
|
|
furi_open_deprecated("test_fb", false, false, NULL, NULL, NULL);
|
2020-09-01 10:34:23 +00:00
|
|
|
|
|
|
|
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++;
|
|
|
|
}
|
|
|
|
}
|