UART write example (#53)
* Rename test functions * rewrite furi API, segfault * make fixes in FURI, log through FURI * add uart write example blank * implement fuprintf instead of fopencookie * add gif, blank page * UART write example description Co-authored-by: Vadim Kaushan <admin@disasm.info>
This commit is contained in:
@@ -4,10 +4,16 @@
|
||||
extern "C" {
|
||||
#include "startup.h"
|
||||
#include "furi.h"
|
||||
#include "debug.h"
|
||||
#include "log.h"
|
||||
#include "tty_uart.h"
|
||||
}
|
||||
|
||||
extern "C" void app() {
|
||||
register_tty_uart();
|
||||
|
||||
FuriRecordSubscriber* log = get_default_log();
|
||||
fuprintf(log, "\n=== Welcome to Flipper Zero! ===\n\n");
|
||||
|
||||
// FURI startup
|
||||
FuriApp* handlers[sizeof(FLIPPER_STARTUP)/sizeof(FLIPPER_STARTUP[0])];
|
||||
|
||||
|
31
core/debug.c
31
core/debug.c
@@ -1,31 +0,0 @@
|
||||
#define _GNU_SOURCE
|
||||
#include "main.h"
|
||||
#include <stdio.h>
|
||||
|
||||
extern UART_HandleTypeDef DEBUG_UART;
|
||||
|
||||
ssize_t uart_write(void* cookie, const char * buffer, size_t size) {
|
||||
if (buffer == 0) {
|
||||
/*
|
||||
* This means that we should flush internal buffers. Since we
|
||||
* don't we just return. (Remember, "handle" == -1 means that all
|
||||
* handles should be flushed.)
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (ssize_t)HAL_UART_Transmit(&DEBUG_UART, (uint8_t*)buffer, (uint16_t)size, HAL_MAX_DELAY);
|
||||
}
|
||||
|
||||
FILE* get_debug() {
|
||||
FILE* fp = fopencookie(NULL, "w+", (cookie_io_functions_t){
|
||||
.read = NULL,
|
||||
.write = uart_write,
|
||||
.seek = NULL,
|
||||
.close = NULL
|
||||
});
|
||||
|
||||
setvbuf(fp, NULL, _IONBF, 0);
|
||||
|
||||
return fp;
|
||||
}
|
@@ -1 +0,0 @@
|
||||
FILE* get_debug();
|
81
core/furi.c
81
core/furi.c
@@ -35,7 +35,7 @@ bool furi_create(const char* name, void* value, size_t size) {
|
||||
if(current_buffer_idx >= MAX_RECORD_COUNT) {
|
||||
// max record count exceed
|
||||
#ifdef FURI_DEBUG
|
||||
printf("[FURI] max record count exceed\n");
|
||||
printf("[FURI] create: max record count exceed\n");
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
@@ -52,10 +52,12 @@ bool furi_create(const char* name, void* value, size_t size) {
|
||||
records[current_buffer_idx].subscribers[i].allocated = false;
|
||||
}
|
||||
|
||||
current_buffer_idx++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FuriRecordHandler furi_open(
|
||||
FuriRecordSubscriber* furi_open(
|
||||
const char* name,
|
||||
bool solo,
|
||||
bool no_mute,
|
||||
@@ -75,16 +77,15 @@ FuriRecordHandler furi_open(
|
||||
printf("[FURI] cannot find record %s\n", name);
|
||||
#endif
|
||||
|
||||
FuriRecordHandler res = {.record = NULL, .subscriber = NULL};
|
||||
return res;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// allocate subscriber
|
||||
FuriRecordSubscriber* subscriber = NULL;
|
||||
|
||||
for(size_t i = 0; i < MAX_RECORD_SUBSCRIBERS; i++) {
|
||||
if(!records[current_buffer_idx].subscribers[i].allocated) {
|
||||
subscriber = &records[current_buffer_idx].subscribers[i];
|
||||
if(!record->subscribers[i].allocated) {
|
||||
subscriber = &record->subscribers[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -92,11 +93,10 @@ FuriRecordHandler furi_open(
|
||||
if(subscriber == NULL) {
|
||||
// cannot add subscriber (full)
|
||||
#ifdef FURI_DEBUG
|
||||
printf("[FURI] cannot add subscriber (full)\n");
|
||||
printf("[FURI] open: cannot add subscriber (full)\n");
|
||||
#endif
|
||||
|
||||
FuriRecordHandler res = {.record = NULL, .subscriber = NULL};
|
||||
return res;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// increase mute_counter
|
||||
@@ -110,25 +110,31 @@ FuriRecordHandler furi_open(
|
||||
subscriber->no_mute = no_mute;
|
||||
subscriber->cb = value_callback;
|
||||
subscriber->state_cb = state_callback;
|
||||
subscriber->record = record;
|
||||
|
||||
// register record in application
|
||||
FuriApp* current_task = find_task(xTaskGetCurrentTaskHandle());
|
||||
|
||||
current_task->records[current_task->records_count] = record;
|
||||
current_task->records_count++;
|
||||
if(current_task != NULL) {
|
||||
current_task->records[current_task->records_count] = record;
|
||||
current_task->records_count++;
|
||||
} else {
|
||||
#ifdef FURI_DEBUG
|
||||
printf("[FURI] open: no current task\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
FuriRecordHandler res = {.record = record, .subscriber = subscriber};
|
||||
return res;
|
||||
return subscriber;
|
||||
}
|
||||
|
||||
|
||||
void furi_close(FuriRecordHandler* handler) {
|
||||
void furi_close(FuriRecordSubscriber* handler) {
|
||||
#ifdef FURI_DEBUG
|
||||
printf("[FURI] closing %s record\n", handler->record->name);
|
||||
#endif
|
||||
|
||||
// deallocate subscriber
|
||||
handler->subscriber->allocated = false;
|
||||
handler->allocated = false;
|
||||
|
||||
// set mute counter to next max value
|
||||
uint8_t max_mute_counter = 0;
|
||||
@@ -142,7 +148,7 @@ void furi_close(FuriRecordHandler* handler) {
|
||||
handler->record->mute_counter = max_mute_counter;
|
||||
}
|
||||
|
||||
static void furi_notify(FuriRecordHandler* handler, const void* value, size_t size) {
|
||||
static void furi_notify(FuriRecordSubscriber* handler, const void* value, size_t size) {
|
||||
for(size_t i = 0; i < MAX_RECORD_SUBSCRIBERS; i++) {
|
||||
if(handler->record->subscribers[i].allocated) {
|
||||
if(handler->record->subscribers[i].cb != NULL) {
|
||||
@@ -152,17 +158,17 @@ static void furi_notify(FuriRecordHandler* handler, const void* value, size_t si
|
||||
}
|
||||
}
|
||||
|
||||
void* furi_take(FuriRecordHandler* handler) {
|
||||
void* furi_take(FuriRecordSubscriber* handler) {
|
||||
// take mutex
|
||||
|
||||
return handler->record->value;
|
||||
}
|
||||
|
||||
void furi_give(FuriRecordHandler* handler) {
|
||||
void furi_give(FuriRecordSubscriber* handler) {
|
||||
// release mutex
|
||||
}
|
||||
|
||||
bool furi_read(FuriRecordHandler* handler, void* value, size_t size) {
|
||||
bool furi_read(FuriRecordSubscriber* handler, void* value, size_t size) {
|
||||
#ifdef FURI_DEBUG
|
||||
printf("[FURI] read from %s\n", handler->record->name);
|
||||
#endif
|
||||
@@ -182,23 +188,44 @@ bool furi_read(FuriRecordHandler* handler, void* value, size_t size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool furi_write(FuriRecordHandler* handler, const void* value, size_t size) {
|
||||
bool furi_write(FuriRecordSubscriber* handler, const void* value, size_t size) {
|
||||
#ifdef FURI_DEBUG
|
||||
printf("[FURI] write to %s\n", handler->record->name);
|
||||
#endif
|
||||
|
||||
if(handler == NULL || handler->record == NULL || value == NULL) return false;
|
||||
if(handler == NULL || handler->record == NULL || value == NULL) {
|
||||
#ifdef FURI_DEBUG
|
||||
printf("[FURI] write: null param %x %x\n", (uint32_t)(size_t)handler, (uint32_t)(size_t)value);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if closed
|
||||
if(!handler->subscriber->allocated) return false;
|
||||
if(!handler->allocated) {
|
||||
#ifdef FURI_DEBUG
|
||||
printf("[FURI] write: handler closed\n");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
if(handler->record->value != NULL && size > handler->record->size) return false;
|
||||
if(handler->record->value != NULL && size > handler->record->size) {
|
||||
#ifdef FURI_DEBUG
|
||||
printf("[FURI] write: wrong size %d\n", (uint32_t)size);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
// check mute
|
||||
if(
|
||||
handler->record->mute_counter != handler->subscriber->mute_counter
|
||||
&& !handler->subscriber->no_mute
|
||||
) return false;
|
||||
handler->record->mute_counter != handler->mute_counter
|
||||
&& !handler->no_mute
|
||||
) {
|
||||
#ifdef FURI_DEBUG
|
||||
printf("[FURI] write: muted\n");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
if(handler->record->value != NULL) {
|
||||
// real write to value
|
||||
|
25
core/furi.h
25
core/furi.h
@@ -22,16 +22,19 @@ typedef enum {
|
||||
/// pointer to state callback function
|
||||
typedef void(*FlipperRecordStateCallback)(FlipperRecordState);
|
||||
|
||||
struct _FuriRecord;
|
||||
|
||||
typedef struct {
|
||||
bool allocated;
|
||||
FlipperRecordCallback cb; ///< value cb
|
||||
FlipperRecordStateCallback state_cb; ///< state cb
|
||||
uint8_t mute_counter; ///< see "wiki/FURI#mute-algorithm"
|
||||
bool no_mute;
|
||||
struct _FuriRecord* record; ///< parent record
|
||||
} FuriRecordSubscriber;
|
||||
|
||||
/// FURI record handler
|
||||
typedef struct {
|
||||
struct _FuriRecord {
|
||||
const char* name;
|
||||
void* value;
|
||||
size_t size;
|
||||
@@ -39,13 +42,9 @@ typedef struct {
|
||||
SemaphoreHandle_t mutex;
|
||||
uint8_t mute_counter;
|
||||
FuriRecordSubscriber subscribers[MAX_RECORD_SUBSCRIBERS];
|
||||
} FuriRecord;
|
||||
};
|
||||
|
||||
/// FURI record handler for use after open
|
||||
typedef struct {
|
||||
FuriRecord* record; ///< full record (for read/write/take/give value)
|
||||
FuriRecordSubscriber* subscriber; ///< current handler info
|
||||
} FuriRecordHandler;
|
||||
typedef struct _FuriRecord FuriRecord;
|
||||
|
||||
/// store info about active task
|
||||
typedef struct {
|
||||
@@ -110,7 +109,7 @@ When appication has exited or record has closed, all handlers is unmuted.
|
||||
It may be useful for concurrently acces to resources like framebuffer or beeper.
|
||||
\param[in] no_mute if true, another applications cannot mute this handler.
|
||||
*/
|
||||
FuriRecordHandler furi_open(
|
||||
FuriRecordSubscriber* furi_open(
|
||||
const char* name,
|
||||
bool solo,
|
||||
bool no_mute,
|
||||
@@ -121,7 +120,7 @@ FuriRecordHandler furi_open(
|
||||
/*!
|
||||
|
||||
*/
|
||||
void furi_close(FuriRecordHandler* handler);
|
||||
void furi_close(FuriRecordSubscriber* handler);
|
||||
|
||||
/*!
|
||||
read message from record.
|
||||
@@ -130,7 +129,7 @@ Also return false if you try to read from FURI pipe
|
||||
|
||||
TODO: enum return value with execution status
|
||||
*/
|
||||
bool furi_read(FuriRecordHandler* record, void* data, size_t size);
|
||||
bool furi_read(FuriRecordSubscriber* record, void* data, size_t size);
|
||||
|
||||
/*!
|
||||
write message to record.
|
||||
@@ -138,7 +137,7 @@ Returns true if success, false otherwise (closed/non-existent record or muted).
|
||||
|
||||
TODO: enum return value with execution status
|
||||
*/
|
||||
bool furi_write(FuriRecordHandler* record, const void* data, size_t size);
|
||||
bool furi_write(FuriRecordSubscriber* record, const void* data, size_t size);
|
||||
|
||||
/*!
|
||||
lock value mutex.
|
||||
@@ -150,9 +149,9 @@ Returns pointer to data, NULL if closed/non-existent record or muted
|
||||
|
||||
TODO: enum return value with execution status
|
||||
*/
|
||||
void* furi_take(FuriRecordHandler* record);
|
||||
void* furi_take(FuriRecordSubscriber* record);
|
||||
|
||||
/*!
|
||||
unlock value mutex.
|
||||
*/
|
||||
void furi_give(FuriRecordHandler* record);
|
||||
void furi_give(FuriRecordSubscriber* record);
|
||||
|
25
core/log.c
Normal file
25
core/log.c
Normal file
@@ -0,0 +1,25 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "furi.h"
|
||||
|
||||
#define PRINT_STR_SIZE 64
|
||||
|
||||
void fuprintf(FuriRecordSubscriber* f, const char * format, ...) {
|
||||
char buffer[PRINT_STR_SIZE];
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsprintf(buffer, format, args);
|
||||
va_end(args);
|
||||
|
||||
furi_write(f, buffer, strlen(buffer));
|
||||
}
|
||||
|
||||
FuriRecordSubscriber* get_default_log() {
|
||||
return furi_open("tty", false, false, NULL, NULL);
|
||||
}
|
6
core/log.h
Normal file
6
core/log.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "furi.h"
|
||||
|
||||
FuriRecordSubscriber* get_default_log();
|
||||
void fuprintf(FuriRecordSubscriber* f, const char * format, ...);
|
20
core/tty_uart.c
Normal file
20
core/tty_uart.c
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "furi.h"
|
||||
#include "main.h"
|
||||
|
||||
extern UART_HandleTypeDef DEBUG_UART;
|
||||
|
||||
void handle_uart_write(const void* data, size_t size) {
|
||||
HAL_UART_Transmit(&DEBUG_UART, (uint8_t*)data, (uint16_t)size, HAL_MAX_DELAY);
|
||||
}
|
||||
|
||||
bool register_tty_uart() {
|
||||
if(!furi_create("tty", NULL, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(furi_open("tty", false, false, handle_uart_write, NULL) == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
5
core/tty_uart.h
Normal file
5
core/tty_uart.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
bool register_tty_uart();
|
Reference in New Issue
Block a user