forked from flipperdevices/flipperzero-firmware
-
-
Notifications
You must be signed in to change notification settings - Fork 552
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Import and FAP conversion of GPS plugin from flipperzero-firmware for…
…k. Does not build yet as stream_buffer.h API is not yet available for FAP.
- Loading branch information
Showing
6 changed files
with
1,240 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
App( | ||
appid="gps", | ||
name="GPS", | ||
apptype=FlipperAppType.EXTERNAL, | ||
entry_point="gps_app", | ||
cdefines=["APP_GPS"], | ||
requires=[ | ||
"gui", | ||
], | ||
stack_size=1 * 1024, | ||
order=20, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
#include "gps_uart.h" | ||
|
||
#include <furi.h> | ||
#include <gui/gui.h> | ||
#include <string.h> | ||
|
||
typedef enum { | ||
EventTypeTick, | ||
EventTypeKey, | ||
} EventType; | ||
|
||
typedef struct { | ||
EventType type; | ||
InputEvent input; | ||
} PluginEvent; | ||
|
||
static void render_callback(Canvas* const canvas, void* context) { | ||
const GpsUart* gps_uart = acquire_mutex((ValueMutex*)context, 25); | ||
if(gps_uart == NULL) { | ||
return; | ||
} | ||
|
||
canvas_set_font(canvas, FontSecondary); | ||
char buffer[64]; | ||
snprintf(buffer, 64, "LAT: %f", (double)gps_uart->status.latitude); | ||
canvas_draw_str_aligned(canvas, 10, 10, AlignLeft, AlignBottom, buffer); | ||
snprintf(buffer, 64, "LON: %f", (double)gps_uart->status.longitude); | ||
canvas_draw_str_aligned(canvas, 10, 30, AlignLeft, AlignBottom, buffer); | ||
|
||
release_mutex((ValueMutex*)context, gps_uart); | ||
} | ||
|
||
static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { | ||
furi_assert(event_queue); | ||
|
||
PluginEvent event = {.type = EventTypeKey, .input = *input_event}; | ||
furi_message_queue_put(event_queue, &event, FuriWaitForever); | ||
} | ||
|
||
int32_t gps_app(void* p) { | ||
UNUSED(p); | ||
|
||
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); | ||
|
||
GpsUart* gps_uart = gps_uart_enable(); | ||
|
||
ValueMutex gps_uart_mutex; | ||
if(!init_mutex(&gps_uart_mutex, gps_uart, sizeof(GpsUart))) { | ||
FURI_LOG_E("GPS", "cannot create mutex\r\n"); | ||
free(gps_uart); | ||
return 255; | ||
} | ||
|
||
// set system callbacks | ||
ViewPort* view_port = view_port_alloc(); | ||
view_port_draw_callback_set(view_port, render_callback, &gps_uart_mutex); | ||
view_port_input_callback_set(view_port, input_callback, event_queue); | ||
|
||
// open GUI and register view_port | ||
Gui* gui = furi_record_open("gui"); | ||
gui_add_view_port(gui, view_port, GuiLayerFullscreen); | ||
|
||
PluginEvent event; | ||
for(bool processing = true; processing;) { | ||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); | ||
|
||
GpsUart* gps_uart = (GpsUart*)acquire_mutex_block(&gps_uart_mutex); | ||
|
||
if(event_status == FuriStatusOk) { | ||
// press events | ||
if(event.type == EventTypeKey) { | ||
if(event.input.type == InputTypePress) { | ||
switch(event.input.key) { | ||
case InputKeyUp: | ||
case InputKeyDown: | ||
case InputKeyRight: | ||
case InputKeyLeft: | ||
case InputKeyOk: | ||
break; | ||
case InputKeyBack: | ||
processing = false; | ||
break; | ||
} | ||
} | ||
} | ||
} else { | ||
FURI_LOG_D("GPS", "FuriMessageQueue: event timeout"); | ||
} | ||
|
||
view_port_update(view_port); | ||
release_mutex(&gps_uart_mutex, gps_uart); | ||
} | ||
|
||
view_port_enabled_set(view_port, false); | ||
gui_remove_view_port(gui, view_port); | ||
furi_record_close("gui"); | ||
view_port_free(view_port); | ||
furi_message_queue_free(event_queue); | ||
delete_mutex(&gps_uart_mutex); | ||
gps_uart_disable(gps_uart); | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
#include <string.h> | ||
|
||
#include "minmea.h" | ||
#include "gps_uart.h" | ||
|
||
typedef enum { | ||
WorkerEvtStop = (1 << 0), | ||
WorkerEvtRxDone = (1 << 1), | ||
} WorkerEvtFlags; | ||
|
||
#define WORKER_ALL_RX_EVENTS \ | ||
(WorkerEvtStop | WorkerEvtRxDone) | ||
|
||
static void gps_uart_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) { | ||
GpsUart* gps_uart = (GpsUart*)context; | ||
BaseType_t xHigherPriorityTaskWoken = pdFALSE; | ||
|
||
if(ev == UartIrqEventRXNE) { | ||
xStreamBufferSendFromISR(gps_uart->rx_stream, &data, 1, &xHigherPriorityTaskWoken); | ||
furi_thread_flags_set(furi_thread_get_id(gps_uart->thread), WorkerEvtRxDone); | ||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken); | ||
} | ||
} | ||
|
||
static void gps_uart_serial_init(GpsUart* gps_uart) { | ||
furi_hal_console_disable(); | ||
furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, gps_uart_on_irq_cb, gps_uart); | ||
furi_hal_uart_set_br(FuriHalUartIdUSART1, GPS_BAUDRATE); | ||
} | ||
|
||
static void gps_uart_serial_deinit(GpsUart* gps_uart) { | ||
UNUSED(gps_uart); | ||
furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, NULL, NULL); | ||
furi_hal_console_enable(); | ||
} | ||
|
||
static void gps_uart_parse_nmea(GpsUart* gps_uart, char* line) | ||
{ | ||
switch(minmea_sentence_id(line, false)) { | ||
case MINMEA_SENTENCE_RMC: { | ||
struct minmea_sentence_rmc frame; | ||
if (minmea_parse_rmc(&frame, line)) { | ||
gps_uart->status.latitude = minmea_tocoord(&frame.latitude); | ||
gps_uart->status.longitude = minmea_tocoord(&frame.longitude); | ||
} | ||
} break; | ||
|
||
default: break; | ||
} | ||
} | ||
|
||
static int32_t gps_uart_worker(void* context) { | ||
GpsUart* gps_uart = (GpsUart*)context; | ||
|
||
gps_uart->rx_stream = xStreamBufferCreate(RX_BUF_SIZE * 5, 1); | ||
size_t rx_offset = 0; | ||
|
||
gps_uart_serial_init(gps_uart); | ||
|
||
while(1) { | ||
uint32_t events = | ||
furi_thread_flags_wait(WORKER_ALL_RX_EVENTS, FuriFlagWaitAny, FuriWaitForever); | ||
furi_check((events & FuriFlagError) == 0); | ||
if(events & WorkerEvtStop) break; | ||
if(events & WorkerEvtRxDone) { | ||
size_t len = 0; | ||
do { | ||
len = xStreamBufferReceive(gps_uart->rx_stream, gps_uart->rx_buf + rx_offset, | ||
RX_BUF_SIZE - 1 - rx_offset, 0); | ||
if(len > 0) { | ||
rx_offset += len; | ||
gps_uart->rx_buf[rx_offset] = '\0'; | ||
|
||
char * line_current = (char *)gps_uart->rx_buf; | ||
while(1) { | ||
while (*line_current == '\0' && line_current < (char *)gps_uart->rx_buf + rx_offset - 1) | ||
line_current++; | ||
char * newline = strchr(line_current, '\n'); | ||
if(newline) { | ||
*newline = '\0'; | ||
gps_uart_parse_nmea(gps_uart, line_current); | ||
line_current = newline + 1; | ||
} else { | ||
if(line_current > (char *)gps_uart->rx_buf) { | ||
rx_offset = 0; | ||
while(*line_current) { | ||
gps_uart->rx_buf[rx_offset++] = *(line_current++); | ||
} | ||
} | ||
break; | ||
} | ||
} | ||
} | ||
} while(len > 0); | ||
} | ||
} | ||
|
||
gps_uart_serial_deinit(gps_uart); | ||
|
||
vStreamBufferDelete(gps_uart->rx_stream); | ||
|
||
return 0; | ||
} | ||
|
||
GpsUart* gps_uart_enable() { | ||
GpsUart* gps_uart = malloc(sizeof(GpsUart)); | ||
|
||
gps_uart->status.latitude = 0.0; | ||
gps_uart->status.longitude = 0.0; | ||
|
||
gps_uart->thread = furi_thread_alloc(); | ||
furi_thread_set_name(gps_uart->thread, "GpsUartWorker"); | ||
furi_thread_set_stack_size(gps_uart->thread, 1024); | ||
furi_thread_set_context(gps_uart->thread, gps_uart); | ||
furi_thread_set_callback(gps_uart->thread, gps_uart_worker); | ||
|
||
furi_thread_start(gps_uart->thread); | ||
return gps_uart; | ||
} | ||
|
||
void gps_uart_disable(GpsUart* gps_uart) { | ||
furi_assert(gps_uart); | ||
furi_thread_flags_set(furi_thread_get_id(gps_uart->thread), WorkerEvtStop); | ||
furi_thread_join(gps_uart->thread); | ||
furi_thread_free(gps_uart->thread); | ||
free(gps_uart); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#pragma once | ||
|
||
#include <furi_hal.h> | ||
#include <stream_buffer.h> | ||
|
||
#define GPS_BAUDRATE 9600 | ||
#define RX_BUF_SIZE 1024 | ||
|
||
typedef struct { | ||
float latitude; | ||
float longitude; | ||
} GpsStatus; | ||
|
||
typedef struct { | ||
FuriThread* thread; | ||
StreamBufferHandle_t rx_stream; | ||
uint8_t rx_buf[RX_BUF_SIZE]; | ||
|
||
GpsStatus status; | ||
} GpsUart; | ||
|
||
GpsUart* gps_uart_enable(); | ||
|
||
void gps_uart_disable(GpsUart* gps_uart); |
Oops, something went wrong.