Procházet zdrojové kódy

Add all current updates

MX před 2 roky
rodič
revize
606389c3dc
6 změnil soubory, kde provedl 799 přidání a 783 odebrání
  1. 2 3
      application.fam
  2. 165 101
      gps.c
  3. 175 189
      gps_uart.c
  4. 30 23
      gps_uart.h
  5. 385 425
      minmea.c
  6. 42 42
      minmea.h

+ 2 - 3
application.fam

@@ -1,9 +1,8 @@
 App(
-    appid="gps",
-    name="GPS",
+    appid="gps_nmea",
+    name="[NMEA] GPS",
     apptype=FlipperAppType.EXTERNAL,
     entry_point="gps_app",
-    cdefines=["APP_GPS"],
     requires=["gui"],
     stack_size=1 * 1024,
     order=35,

+ 165 - 101
gps.c

@@ -4,123 +4,187 @@
 #include <gui/gui.h>
 #include <string.h>
 
-typedef enum
-{
-  EventTypeTick,
-  EventTypeKey,
+typedef enum {
+    EventTypeTick,
+    EventTypeKey,
 } EventType;
 
-typedef struct
-{
-  EventType type;
-  InputEvent input;
+typedef struct {
+    EventType type;
+    InputEvent input;
 } PluginEvent;
 
-static void render_callback(Canvas* const canvas, void* context)
-{
-  const GpsUart* gps_uart = (GpsUart*)context;
-  furi_mutex_acquire(gps_uart->mutex, FuriWaitForever);
-
-  canvas_set_font(canvas, FontPrimary);
-  canvas_draw_str_aligned(canvas, 32, 8, AlignCenter, AlignBottom, "Latitude");
-  canvas_draw_str_aligned(canvas, 96, 8, AlignCenter, AlignBottom, "Longitude");
-  canvas_draw_str_aligned(canvas, 21, 30, AlignCenter, AlignBottom, "Course");
-  canvas_draw_str_aligned(canvas, 64, 30, AlignCenter, AlignBottom, "Speed");
-  canvas_draw_str_aligned(canvas, 107, 30, AlignCenter, AlignBottom, "Altitude");
-  canvas_draw_str_aligned(canvas, 32, 52, AlignCenter, AlignBottom, "Satellites");
-  canvas_draw_str_aligned(canvas, 96, 52, AlignCenter, AlignBottom, "Last Fix");
-
-  canvas_set_font(canvas, FontSecondary);
-  char buffer[64];
-  snprintf(buffer, 64, "%f", (double)gps_uart->status.latitude);
-  canvas_draw_str_aligned(canvas, 32, 18, AlignCenter, AlignBottom, buffer);
-  snprintf(buffer, 64, "%f", (double)gps_uart->status.longitude);
-  canvas_draw_str_aligned(canvas, 96, 18, AlignCenter, AlignBottom, buffer);
-  snprintf(buffer, 64, "%.1f", (double)gps_uart->status.course);
-  canvas_draw_str_aligned(canvas, 21, 40, AlignCenter, AlignBottom, buffer);
-  snprintf(buffer, 64, "%.2f kn", (double)gps_uart->status.speed);
-  canvas_draw_str_aligned(canvas, 64, 40, AlignCenter, AlignBottom, buffer);
-  snprintf(buffer, 64, "%.1f %c", (double)gps_uart->status.altitude, tolower(gps_uart->status.altitude_units));
-  canvas_draw_str_aligned(canvas, 107, 40, AlignCenter, AlignBottom, buffer);
-  snprintf(buffer, 64, "%d", gps_uart->status.satellites_tracked);
-  canvas_draw_str_aligned(canvas, 32, 62, AlignCenter, AlignBottom, buffer);
-  snprintf(buffer, 64, "%02d:%02d:%02d UTC", gps_uart->status.time_hours, gps_uart->status.time_minutes,
-           gps_uart->status.time_seconds);
-  canvas_draw_str_aligned(canvas, 96, 62, AlignCenter, AlignBottom, buffer);
-
-  furi_mutex_release(gps_uart->mutex);
-}
+static void render_callback(Canvas* const canvas, void* context) {
+    furi_assert(context);
+    GpsUart* gps_uart = context;
+    furi_mutex_acquire(gps_uart->mutex, FuriWaitForever);
 
-static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue)
-{
-  furi_assert(event_queue);
+    if(!gps_uart->changing_baudrate) {
+        canvas_set_font(canvas, FontPrimary);
+        canvas_draw_str_aligned(canvas, 32, 8, AlignCenter, AlignBottom, "Latitude");
+        canvas_draw_str_aligned(canvas, 96, 8, AlignCenter, AlignBottom, "Longitude");
+        canvas_draw_str_aligned(canvas, 21, 30, AlignCenter, AlignBottom, "Course");
+        canvas_draw_str_aligned(canvas, 64, 30, AlignCenter, AlignBottom, "Speed");
+        canvas_draw_str_aligned(canvas, 107, 30, AlignCenter, AlignBottom, "Altitude");
+        canvas_draw_str_aligned(canvas, 32, 52, AlignCenter, AlignBottom, "Satellites");
+        canvas_draw_str_aligned(canvas, 96, 52, AlignCenter, AlignBottom, "Last Fix");
+
+        canvas_set_font(canvas, FontSecondary);
+        char buffer[64];
+        snprintf(buffer, 64, "%f", (double)gps_uart->status.latitude);
+        canvas_draw_str_aligned(canvas, 32, 18, AlignCenter, AlignBottom, buffer);
+        snprintf(buffer, 64, "%f", (double)gps_uart->status.longitude);
+        canvas_draw_str_aligned(canvas, 96, 18, AlignCenter, AlignBottom, buffer);
+        snprintf(buffer, 64, "%.1f", (double)gps_uart->status.course);
+        canvas_draw_str_aligned(canvas, 21, 40, AlignCenter, AlignBottom, buffer);
+        if(!gps_uart->speed_in_kms) {
+            snprintf(buffer, 64, "%.2f kn", (double)gps_uart->status.speed);
+        } else {
+            snprintf(buffer, 64, "%.2f km", (double)(gps_uart->status.speed * 1.852));
+        }
+        canvas_draw_str_aligned(canvas, 64, 40, AlignCenter, AlignBottom, buffer);
+        snprintf(
+            buffer,
+            64,
+            "%.1f %c",
+            (double)gps_uart->status.altitude,
+            tolower(gps_uart->status.altitude_units));
+        canvas_draw_str_aligned(canvas, 107, 40, AlignCenter, AlignBottom, buffer);
+        snprintf(buffer, 64, "%d", gps_uart->status.satellites_tracked);
+        canvas_draw_str_aligned(canvas, 32, 62, AlignCenter, AlignBottom, buffer);
+        snprintf(
+            buffer,
+            64,
+            "%02d:%02d:%02d UTC",
+            gps_uart->status.time_hours,
+            gps_uart->status.time_minutes,
+            gps_uart->status.time_seconds);
+        canvas_draw_str_aligned(canvas, 96, 62, AlignCenter, AlignBottom, buffer);
+    } else {
+        char buffer[64];
+        canvas_set_font(canvas, FontPrimary);
+        canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignBottom, "Baudrate set to:");
+
+        snprintf(buffer, 64, "%ld baud", gps_uart->baudrate);
+        canvas_draw_str_aligned(canvas, 64, 47, AlignCenter, AlignBottom, buffer);
+    }
 
-  PluginEvent event = {.type = EventTypeKey, .input = *input_event};
-  furi_message_queue_put(event_queue, &event, FuriWaitForever);
+    furi_mutex_release(gps_uart->mutex);
 }
 
-int32_t gps_app(void* p)
-{
-  UNUSED(p);
-
-  FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
+static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
+    furi_assert(event_queue);
 
-  GpsUart* gps_uart = gps_uart_enable();
-  if (gps_uart == NULL)
-  {
-    return 255;
-  }
+    PluginEvent event = {.type = EventTypeKey, .input = *input_event};
+    furi_message_queue_put(event_queue, &event, FuriWaitForever);
+}
 
-  // set system callbacks
-  ViewPort* view_port = view_port_alloc();
-  view_port_draw_callback_set(view_port, render_callback, gps_uart);
-  view_port_input_callback_set(view_port, input_callback, event_queue);
+int32_t gps_app(void* p) {
+    UNUSED(p);
 
-  // open GUI and register view_port
-  Gui* gui = furi_record_open("gui");
-  gui_add_view_port(gui, view_port, GuiLayerFullscreen);
+    FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
 
-  PluginEvent event;
-  for (bool processing = true; processing;)
-  {
-    FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
+    GpsUart* gps_uart = gps_uart_enable();
 
-    furi_mutex_acquire(gps_uart->mutex, FuriWaitForever);
+    gps_uart->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
+    if(!gps_uart->mutex) {
+        FURI_LOG_E("GPS", "cannot create mutex\r\n");
+        free(gps_uart);
+        return 255;
+    }
 
-    if (event_status == FuriStatusOk)
-    {
-      // press events
-      if (event.type == EventTypeKey)
-      {
-        if (event.input.type == InputTypePress)
-        {
-          switch (event.input.key)
-          {
-            case InputKeyBack:
-              processing = false;
-              break;
-            default:
-              break;
-          }
+    // set system callbacks
+    ViewPort* view_port = view_port_alloc();
+    view_port_draw_callback_set(view_port, render_callback, gps_uart);
+    view_port_input_callback_set(view_port, input_callback, event_queue);
+
+    // open GUI and register view_port
+    Gui* gui = furi_record_open(RECORD_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);
+
+        furi_mutex_acquire(gps_uart->mutex, FuriWaitForever);
+
+        if(event_status == FuriStatusOk) {
+            // press events
+            if(event.type == EventTypeKey) {
+                if(event.input.type == InputTypeShort) {
+                    switch(event.input.key) {
+                    case InputKeyUp:
+                    case InputKeyDown:
+                    case InputKeyRight:
+                    case InputKeyLeft:
+                    case InputKeyBack:
+                        break;
+                    case InputKeyOk:
+                        if(!gps_uart->backlight_on) {
+                            notification_message_block(
+                                gps_uart->notifications, &sequence_display_backlight_enforce_on);
+                            gps_uart->backlight_on = true;
+                        } else {
+                            notification_message_block(
+                                gps_uart->notifications, &sequence_display_backlight_enforce_auto);
+                            notification_message(
+                                gps_uart->notifications, &sequence_display_backlight_off);
+                            gps_uart->backlight_on = false;
+                        }
+                        break;
+                    default:
+                        break;
+                    }
+                } else if(event.input.type == InputTypeLong) {
+                    switch(event.input.key) {
+                    case InputKeyUp:
+                        gps_uart_deinit_thread(gps_uart);
+                        const int baudrate_length =
+                            sizeof(gps_baudrates) / sizeof(gps_baudrates[0]);
+                        current_gps_baudrate++;
+                        if(current_gps_baudrate >= baudrate_length) {
+                            current_gps_baudrate = 0;
+                        }
+                        gps_uart->baudrate = gps_baudrates[current_gps_baudrate];
+
+                        gps_uart_init_thread(gps_uart);
+                        gps_uart->changing_baudrate = true;
+                        view_port_update(view_port);
+                        furi_mutex_release(gps_uart->mutex);
+                        break;
+                    case InputKeyRight:
+                        if(gps_uart->speed_in_kms) {
+                            gps_uart->speed_in_kms = false;
+                        } else {
+                            gps_uart->speed_in_kms = true;
+                        }
+                        break;
+                    case InputKeyBack:
+                        processing = false;
+                        break;
+                    default:
+                        break;
+                    }
+                }
+            }
+        }
+        if(!gps_uart->changing_baudrate) {
+            view_port_update(view_port);
+            furi_mutex_release(gps_uart->mutex);
+        } else {
+            furi_delay_ms(1000);
+            gps_uart->changing_baudrate = false;
         }
-      }
-    } 
-    else
-    {
-      FURI_LOG_D("GPS", "FuriMessageQueue: event timeout");
     }
 
-    view_port_update(view_port);
-    furi_mutex_release(gps_uart->mutex);
-  }
-
-  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);
-  furi_mutex_free(gps_uart->mutex);
-  gps_uart_disable(gps_uart);
+    notification_message_block(gps_uart->notifications, &sequence_display_backlight_enforce_auto);
+    view_port_enabled_set(view_port, false);
+    gui_remove_view_port(gui, view_port);
+    furi_record_close(RECORD_GUI);
+    view_port_free(view_port);
+    furi_message_queue_free(event_queue);
+    furi_mutex_free(gps_uart->mutex);
+    gps_uart_disable(gps_uart);
 
-  return 0;
+    return 0;
 }

+ 175 - 189
gps_uart.c

@@ -3,229 +3,215 @@
 #include "minmea.h"
 #include "gps_uart.h"
 
-typedef enum
-{
-  WorkerEvtStop = (1 << 0),
-  WorkerEvtRxDone = (1 << 1),
+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;
+static void gps_uart_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) {
+    GpsUart* gps_uart = (GpsUart*)context;
 
-  if (ev == UartIrqEventRXNE)
-  {
-    furi_stream_buffer_send(gps_uart->rx_stream, &data, 1, 0);
-    furi_thread_flags_set(furi_thread_get_id(gps_uart->thread), WorkerEvtRxDone);
-  }
+    if(ev == UartIrqEventRXNE) {
+        furi_stream_buffer_send(gps_uart->rx_stream, &data, 1, 0);
+        furi_thread_flags_set(furi_thread_get_id(gps_uart->thread), WorkerEvtRxDone);
+    }
 }
 
-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_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_uart->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_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.valid = frame.valid;
-        gps_uart->status.latitude = minmea_tocoord(&frame.latitude);
-        gps_uart->status.longitude = minmea_tocoord(&frame.longitude);
-        gps_uart->status.speed = minmea_tofloat(&frame.speed);
-        gps_uart->status.course = minmea_tofloat(&frame.course);
-        gps_uart->status.time_hours = frame.time.hours;
-        gps_uart->status.time_minutes = frame.time.minutes;
-        gps_uart->status.time_seconds = frame.time.seconds;
-
-        notification_message_block(gps_uart->notifications, &sequence_blink_green_10);
-      }
+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.valid = frame.valid;
+            gps_uart->status.latitude = minmea_tocoord(&frame.latitude);
+            gps_uart->status.longitude = minmea_tocoord(&frame.longitude);
+            gps_uart->status.speed = minmea_tofloat(&frame.speed);
+            gps_uart->status.course = minmea_tofloat(&frame.course);
+            gps_uart->status.time_hours = frame.time.hours;
+            gps_uart->status.time_minutes = frame.time.minutes;
+            gps_uart->status.time_seconds = frame.time.seconds;
+
+            notification_message_block(gps_uart->notifications, &sequence_blink_green_10);
+        }
     } break;
 
-    case MINMEA_SENTENCE_GGA:
-    {
-      struct minmea_sentence_gga frame;
-      if (minmea_parse_gga(&frame, line))
-      {
-        gps_uart->status.latitude = minmea_tocoord(&frame.latitude);
-        gps_uart->status.longitude = minmea_tocoord(&frame.longitude);
-        gps_uart->status.altitude = minmea_tofloat(&frame.altitude);
-        gps_uart->status.altitude_units = frame.altitude_units;
-        gps_uart->status.fix_quality = frame.fix_quality;
-        gps_uart->status.satellites_tracked = frame.satellites_tracked;
-        gps_uart->status.time_hours = frame.time.hours;
-        gps_uart->status.time_minutes = frame.time.minutes;
-        gps_uart->status.time_seconds = frame.time.seconds;
-
-        notification_message_block(gps_uart->notifications, &sequence_blink_magenta_10);
-      }
+    case MINMEA_SENTENCE_GGA: {
+        struct minmea_sentence_gga frame;
+        if(minmea_parse_gga(&frame, line)) {
+            gps_uart->status.latitude = minmea_tocoord(&frame.latitude);
+            gps_uart->status.longitude = minmea_tocoord(&frame.longitude);
+            gps_uart->status.altitude = minmea_tofloat(&frame.altitude);
+            gps_uart->status.altitude_units = frame.altitude_units;
+            gps_uart->status.fix_quality = frame.fix_quality;
+            gps_uart->status.satellites_tracked = frame.satellites_tracked;
+            gps_uart->status.time_hours = frame.time.hours;
+            gps_uart->status.time_minutes = frame.time.minutes;
+            gps_uart->status.time_seconds = frame.time.seconds;
+
+            notification_message_block(gps_uart->notifications, &sequence_blink_magenta_10);
+        }
     } break;
 
-    case MINMEA_SENTENCE_GLL:
-    {
-      struct minmea_sentence_gll frame;
-      if (minmea_parse_gll(&frame, line))
-      {
-        gps_uart->status.latitude = minmea_tocoord(&frame.latitude);
-        gps_uart->status.longitude = minmea_tocoord(&frame.longitude);
-        gps_uart->status.time_hours = frame.time.hours;
-        gps_uart->status.time_minutes = frame.time.minutes;
-        gps_uart->status.time_seconds = frame.time.seconds;
-
-        notification_message_block(gps_uart->notifications, &sequence_blink_red_10);
-      }
+    case MINMEA_SENTENCE_GLL: {
+        struct minmea_sentence_gll frame;
+        if(minmea_parse_gll(&frame, line)) {
+            gps_uart->status.latitude = minmea_tocoord(&frame.latitude);
+            gps_uart->status.longitude = minmea_tocoord(&frame.longitude);
+            gps_uart->status.time_hours = frame.time.hours;
+            gps_uart->status.time_minutes = frame.time.minutes;
+            gps_uart->status.time_seconds = frame.time.seconds;
+
+            notification_message_block(gps_uart->notifications, &sequence_blink_red_10);
+        }
     } break;
 
     default:
-      break;
-  }
+        break;
+    }
 }
 
-static int32_t gps_uart_worker(void* context)
-{
-  GpsUart* gps_uart = (GpsUart*)context;
+static int32_t gps_uart_worker(void* context) {
+    GpsUart* gps_uart = (GpsUart*)context;
 
-  gps_uart->rx_stream = furi_stream_buffer_alloc(RX_BUF_SIZE * 5, 1);
-  size_t rx_offset = 0;
+    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);
 
-  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 & WorkerEvtStop)
-    {
-      break;
-    }
-    
-    if (events & WorkerEvtRxDone)
-    {
-      size_t len = 0;
-      do 
-      {
-        // receive serial bytes into rx_buf, starting at rx_offset from the start of the buffer
-        // the maximum we can receive is RX_BUF_SIZE - 1 - rx_offset
-        len = furi_stream_buffer_receive(gps_uart->rx_stream, gps_uart->rx_buf + rx_offset, RX_BUF_SIZE - 1 - rx_offset,
-                                         0);
-        if (len > 0)
-        {
-          // increase rx_offset by the number of bytes received, and null-terminate rx_buf
-          rx_offset += len;
-          gps_uart->rx_buf[rx_offset] = '\0';
-
-          // look for strings ending in newlines, starting at the start of rx_buf
-          char * line_current = (char *)gps_uart->rx_buf;
-          while (1)
-          {
-            // skip null characters
-            while (*line_current == '\0' && line_current < (char *)gps_uart->rx_buf + rx_offset - 1)
-            {
-              line_current++;
-            }
-
-            // find the next newline
-            char * newline = strchr(line_current, '\n');
-            if (newline)  // newline found
-            {
-              // put a null terminator in place of the newline, to delimit the line string
-              *newline = '\0';
-
-              // attempt to parse the line as a NMEA sentence
-              gps_uart_parse_nmea(gps_uart, line_current);
-
-              // move the cursor to the character after the newline
-              line_current = newline + 1;
-            }
-            else  // no more newlines found
-            {
-              if (line_current > (char *)gps_uart->rx_buf)  // at least one line was found
-              {
-                // clear parsed lines, and move any leftover bytes to the start of rx_buf
-                rx_offset = 0;
-                while (*line_current)  // stop when the original rx_offset terminator is reached
-                {
-                  gps_uart->rx_buf[rx_offset++] = *(line_current++);
+        if(events & WorkerEvtRxDone) {
+            size_t len = 0;
+            do {
+                // receive serial bytes into rx_buf, starting at rx_offset from the start of the buffer
+                // the maximum we can receive is RX_BUF_SIZE - 1 - rx_offset
+                len = furi_stream_buffer_receive(
+                    gps_uart->rx_stream,
+                    gps_uart->rx_buf + rx_offset,
+                    RX_BUF_SIZE - 1 - rx_offset,
+                    0);
+                if(len > 0) {
+                    // increase rx_offset by the number of bytes received, and null-terminate rx_buf
+                    rx_offset += len;
+                    gps_uart->rx_buf[rx_offset] = '\0';
+
+                    // look for strings ending in newlines, starting at the start of rx_buf
+                    char* line_current = (char*)gps_uart->rx_buf;
+                    while(1) {
+                        // skip null characters
+                        while(*line_current == '\0' &&
+                              line_current < (char*)gps_uart->rx_buf + rx_offset - 1) {
+                            line_current++;
+                        }
+
+                        // find the next newline
+                        char* newline = strchr(line_current, '\n');
+                        if(newline) // newline found
+                        {
+                            // put a null terminator in place of the newline, to delimit the line string
+                            *newline = '\0';
+
+                            // attempt to parse the line as a NMEA sentence
+                            gps_uart_parse_nmea(gps_uart, line_current);
+
+                            // move the cursor to the character after the newline
+                            line_current = newline + 1;
+                        } else // no more newlines found
+                        {
+                            if(line_current >
+                               (char*)gps_uart->rx_buf) // at least one line was found
+                            {
+                                // clear parsed lines, and move any leftover bytes to the start of rx_buf
+                                rx_offset = 0;
+                                while(
+                                    *line_current) // stop when the original rx_offset terminator is reached
+                                {
+                                    gps_uart->rx_buf[rx_offset++] = *(line_current++);
+                                }
+                            }
+                            break; // go back to receiving bytes from the serial stream
+                        }
+                    }
                 }
-              }
-              break;  // go back to receiving bytes from the serial stream
-            }
-          }
+            } while(len > 0);
         }
-      }
-      while (len > 0);
     }
-  }
 
-  gps_uart_serial_deinit(gps_uart);
-  furi_stream_buffer_free(gps_uart->rx_stream);
+    gps_uart_serial_deinit(gps_uart);
+    furi_stream_buffer_free(gps_uart->rx_stream);
 
-  return 0;
+    return 0;
 }
 
-GpsUart* gps_uart_enable()
-{
-  GpsUart* gps_uart = malloc(sizeof(GpsUart));
+void gps_uart_init_thread(GpsUart* gps_uart) {
+    furi_assert(gps_uart);
+    gps_uart->status.valid = false;
+    gps_uart->status.latitude = 0.0;
+    gps_uart->status.longitude = 0.0;
+    gps_uart->status.speed = 0.0;
+    gps_uart->status.course = 0.0;
+    gps_uart->status.altitude = 0.0;
+    gps_uart->status.altitude_units = ' ';
+    gps_uart->status.fix_quality = 0;
+    gps_uart->status.satellites_tracked = 0;
+    gps_uart->status.time_hours = 0;
+    gps_uart->status.time_minutes = 0;
+    gps_uart->status.time_seconds = 0;
+
+    gps_uart->rx_stream = furi_stream_buffer_alloc(RX_BUF_SIZE * 5, 1);
+
+    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);
+
+    gps_uart_serial_init(gps_uart);
+}
 
-  gps_uart->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
-  if (!gps_uart->mutex)
-  {
-    FURI_LOG_E("GPS", "cannot create mutex\r\n");
-    free(gps_uart);
-    return NULL;
-  }
-
-  gps_uart->status.valid = false;
-  gps_uart->status.latitude = 0.0;
-  gps_uart->status.longitude = 0.0;
-  gps_uart->status.speed = 0.0;
-  gps_uart->status.course = 0.0;
-  gps_uart->status.altitude = 0.0;
-  gps_uart->status.altitude_units = ' ';
-  gps_uart->status.fix_quality = 0;
-  gps_uart->status.satellites_tracked = 0;
-  gps_uart->status.time_hours = 0;
-  gps_uart->status.time_minutes = 0;
-  gps_uart->status.time_seconds = 0;
-
-  gps_uart->notifications = furi_record_open(RECORD_NOTIFICATION);
-
-  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_deinit_thread(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);
 }
 
-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);
+GpsUart* gps_uart_enable() {
+    GpsUart* gps_uart = malloc(sizeof(GpsUart));
+
+    gps_uart->notifications = furi_record_open(RECORD_NOTIFICATION);
+
+    gps_uart->baudrate = gps_baudrates[current_gps_baudrate];
 
-  furi_record_close(RECORD_NOTIFICATION);
+    gps_uart_init_thread(gps_uart);
 
-  free(gps_uart);
+    return gps_uart;
+}
+
+void gps_uart_disable(GpsUart* gps_uart) {
+    furi_assert(gps_uart);
+    gps_uart_deinit_thread(gps_uart);
+    furi_record_close(RECORD_NOTIFICATION);
+
+    free(gps_uart);
 }

+ 30 - 23
gps_uart.h

@@ -3,37 +3,44 @@
 #include <furi_hal.h>
 #include <notification/notification_messages.h>
 
-#define GPS_BAUDRATE 9600
 #define RX_BUF_SIZE 1024
 
-typedef struct
-{
-  bool valid;
-  float latitude;
-  float longitude;
-  float speed;
-  float course;
-  float altitude;
-  char altitude_units;
-  int fix_quality;
-  int satellites_tracked;
-  int time_hours;
-  int time_minutes;
-  int time_seconds;
+static const int gps_baudrates[5] = {9600, 19200, 38400, 57600, 115200};
+static int current_gps_baudrate = 3;
+
+typedef struct {
+    bool valid;
+    float latitude;
+    float longitude;
+    float speed;
+    float course;
+    float altitude;
+    char altitude_units;
+    int fix_quality;
+    int satellites_tracked;
+    int time_hours;
+    int time_minutes;
+    int time_seconds;
 } GpsStatus;
 
-typedef struct
-{
-  FuriMutex* mutex;
-  FuriThread* thread;
-  FuriStreamBuffer* rx_stream;
-  uint8_t rx_buf[RX_BUF_SIZE];
+typedef struct {
+    FuriMutex* mutex;
+    FuriThread* thread;
+    FuriStreamBuffer* rx_stream;
+    uint8_t rx_buf[RX_BUF_SIZE];
 
-  NotificationApp* notifications;
+    NotificationApp* notifications;
+    uint32_t baudrate;
+    bool changing_baudrate;
+    bool backlight_on;
+    bool speed_in_kms;
 
-  GpsStatus status;
+    GpsStatus status;
 } GpsUart;
 
+void gps_uart_init_thread(GpsUart* gps_uart);
+void gps_uart_deinit_thread(GpsUart* gps_uart);
+
 GpsUart* gps_uart_enable();
 
 void gps_uart_disable(GpsUart* gps_uart);

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 385 - 425
minmea.c


+ 42 - 42
minmea.h

@@ -87,8 +87,10 @@ struct minmea_sentence_gga {
     int fix_quality;
     int satellites_tracked;
     struct minmea_float hdop;
-    struct minmea_float altitude; char altitude_units;
-    struct minmea_float height; char height_units;
+    struct minmea_float altitude;
+    char altitude_units;
+    struct minmea_float height;
+    char height_units;
     struct minmea_float dgps_age;
 };
 
@@ -179,22 +181,22 @@ struct minmea_sentence_zda {
 /**
  * Calculate raw sentence checksum. Does not check sentence integrity.
  */
-uint8_t minmea_checksum(const char *sentence);
+uint8_t minmea_checksum(const char* sentence);
 
 /**
  * Check sentence validity and checksum. Returns true for valid sentences.
  */
-bool minmea_check(const char *sentence, bool strict);
+bool minmea_check(const char* sentence, bool strict);
 
 /**
  * Determine talker identifier.
  */
-bool minmea_talker_id(char talker[3], const char *sentence);
+bool minmea_talker_id(char talker[3], const char* sentence);
 
 /**
  * Determine sentence identifier.
  */
-enum minmea_sentence_id minmea_sentence_id(const char *sentence, bool strict);
+enum minmea_sentence_id minmea_sentence_id(const char* sentence, bool strict);
 
 /**
  * Scanf-like processor for NMEA sentences. Supports the following formats:
@@ -210,72 +212,70 @@ enum minmea_sentence_id minmea_sentence_id(const char *sentence, bool strict);
  * ; - following fields are optional
  * Returns true on success. See library source code for details.
  */
-bool minmea_scan(const char *sentence, const char *format, ...);
+bool minmea_scan(const char* sentence, const char* format, ...);
 
 /*
  * Parse a specific type of sentence. Return true on success.
  */
-bool minmea_parse_gbs(struct minmea_sentence_gbs *frame, const char *sentence);
-bool minmea_parse_rmc(struct minmea_sentence_rmc *frame, const char *sentence);
-bool minmea_parse_gga(struct minmea_sentence_gga *frame, const char *sentence);
-bool minmea_parse_gsa(struct minmea_sentence_gsa *frame, const char *sentence);
-bool minmea_parse_gll(struct minmea_sentence_gll *frame, const char *sentence);
-bool minmea_parse_gst(struct minmea_sentence_gst *frame, const char *sentence);
-bool minmea_parse_gsv(struct minmea_sentence_gsv *frame, const char *sentence);
-bool minmea_parse_vtg(struct minmea_sentence_vtg *frame, const char *sentence);
-bool minmea_parse_zda(struct minmea_sentence_zda *frame, const char *sentence);
+bool minmea_parse_gbs(struct minmea_sentence_gbs* frame, const char* sentence);
+bool minmea_parse_rmc(struct minmea_sentence_rmc* frame, const char* sentence);
+bool minmea_parse_gga(struct minmea_sentence_gga* frame, const char* sentence);
+bool minmea_parse_gsa(struct minmea_sentence_gsa* frame, const char* sentence);
+bool minmea_parse_gll(struct minmea_sentence_gll* frame, const char* sentence);
+bool minmea_parse_gst(struct minmea_sentence_gst* frame, const char* sentence);
+bool minmea_parse_gsv(struct minmea_sentence_gsv* frame, const char* sentence);
+bool minmea_parse_vtg(struct minmea_sentence_vtg* frame, const char* sentence);
+bool minmea_parse_zda(struct minmea_sentence_zda* frame, const char* sentence);
 
 /**
  * Convert GPS UTC date/time representation to a UNIX calendar time.
  */
-int minmea_getdatetime(struct tm *tm, const struct minmea_date *date, const struct minmea_time *time_);
+int minmea_getdatetime(
+    struct tm* tm,
+    const struct minmea_date* date,
+    const struct minmea_time* time_);
 
 /**
  * Convert GPS UTC date/time representation to a UNIX timestamp.
  */
-int minmea_gettime(struct timespec *ts, const struct minmea_date *date, const struct minmea_time *time_);
+int minmea_gettime(
+    struct timespec* ts,
+    const struct minmea_date* date,
+    const struct minmea_time* time_);
 
 /**
  * Rescale a fixed-point value to a different scale. Rounds towards zero.
  */
-static inline int_least32_t minmea_rescale(const struct minmea_float *f, int_least32_t new_scale)
-{
-    if (f->scale == 0)
-        return 0;
-    if (f->scale == new_scale)
-        return f->value;
-    if (f->scale > new_scale)
-        return (f->value + ((f->value > 0) - (f->value < 0)) * f->scale/new_scale/2) / (f->scale/new_scale);
+static inline int_least32_t minmea_rescale(const struct minmea_float* f, int_least32_t new_scale) {
+    if(f->scale == 0) return 0;
+    if(f->scale == new_scale) return f->value;
+    if(f->scale > new_scale)
+        return (f->value + ((f->value > 0) - (f->value < 0)) * f->scale / new_scale / 2) /
+               (f->scale / new_scale);
     else
-        return f->value * (new_scale/f->scale);
+        return f->value * (new_scale / f->scale);
 }
 
 /**
  * Convert a fixed-point value to a floating-point value.
  * Returns NaN for "unknown" values.
  */
-static inline float minmea_tofloat(const struct minmea_float *f)
-{
-    if (f->scale == 0)
-        return NAN;
-    return (float) f->value / (float) f->scale;
+static inline float minmea_tofloat(const struct minmea_float* f) {
+    if(f->scale == 0) return NAN;
+    return (float)f->value / (float)f->scale;
 }
 
 /**
  * Convert a raw coordinate to a floating point DD.DDD... value.
  * Returns NaN for "unknown" values.
  */
-static inline float minmea_tocoord(const struct minmea_float *f)
-{
-    if (f->scale == 0)
-        return NAN;
-    if (f->scale  > (INT_LEAST32_MAX / 100))
-        return NAN;
-    if (f->scale < (INT_LEAST32_MIN / 100))
-        return NAN;
+static inline float minmea_tocoord(const struct minmea_float* f) {
+    if(f->scale == 0) return NAN;
+    if(f->scale > (INT_LEAST32_MAX / 100)) return NAN;
+    if(f->scale < (INT_LEAST32_MIN / 100)) return NAN;
     int_least32_t degrees = f->value / (f->scale * 100);
     int_least32_t minutes = f->value % (f->scale * 100);
-    return (float) degrees + (float) minutes / (60 * f->scale);
+    return (float)degrees + (float)minutes / (60 * f->scale);
 }
 
 /**
@@ -283,7 +283,7 @@ static inline float minmea_tocoord(const struct minmea_float *f)
  * sentence data field.
  */
 static inline bool minmea_isfield(char c) {
-    return isprint((unsigned char) c) && c != ',' && c != '*';
+    return isprint((unsigned char)c) && c != ',' && c != '*';
 }
 
 #ifdef __cplusplus

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů