From 87c6e47d895ef7a400bf937ba5bf4df7d68a559f Mon Sep 17 00:00:00 2001 From: Guo-Rong <5484552+gkoh@users.noreply.github.com> Date: Sun, 5 Jan 2025 13:50:48 +1030 Subject: [PATCH] Add support for v1.1 GPS unit. (#156) * Add support for v1.1 GPS unit. Add a setting for the GPS unit baud rate, defaults to 9600 (the old EOL) unit. The new (v1.1) unit runs at 115200. Also, add the GPS time age to the 'GPS Data' output. Update the GPS service interval to 50ms, to support the faster unit (may need to convert this to a FreeRTOS task/queue). Whilst here, refactor a bit of GPS handling. * Update README for GPS baud setting. --- README.md | 10 +++++++--- include/FurbleGPS.h | 9 +++++++-- include/FurbleSettings.h | 4 ++++ include/FurbleUI.h | 1 + src/FurbleGPS.cpp | 18 ++++++++++++++---- src/FurbleSettings.cpp | 24 +++++++++++++++++++++++ src/FurbleUI.cpp | 41 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 98 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 0cdbb63..41ff32b 100644 --- a/README.md +++ b/README.md @@ -217,14 +217,18 @@ Connection to mobile devices is a little iffy: ### GPS Location Tagging -> [!WARNING] -> This unit is EOL, support for the replacement is pending (see #141). - For Fujifilm cameras, location tagging is supported with the M5Stack GPS unit: +- [GPS/BDS Unit v1.1 (AT6668)](https://shop.m5stack.com/products/gps-bds-unit-v1-1-at6668) + +The previous unit is now EOL: - [Mini GPS/BDS Unit](https://shop.m5stack.com/products/mini-gps-bds-unit) GPS support can be enabled in `furble` in `Settings->GPS`, the camera must also be configured to request location data. +The default baud rate for the GPS unit is 9600. +The new v1.1 unit runs at a higher baud rate and must be configured under +`Settings->GPS->GPS baud 115200` for correct operation. + ### Intervalometer The intervalometer can be configured via three settings in `Settings->Intervalometer`: diff --git a/include/FurbleGPS.h b/include/FurbleGPS.h index 333db69..7b9751f 100644 --- a/include/FurbleGPS.h +++ b/include/FurbleGPS.h @@ -1,6 +1,8 @@ #ifndef FURBLE_GPS_H #define FURBLE_GPS_H +#include + #include #include @@ -28,7 +30,8 @@ class GPS { private: GPS() {}; - static constexpr const uint32_t BAUD = 9600; + static constexpr const size_t BUFFER_SIZE = 64; + #if FURBLE_GROVE_CORE static constexpr const int8_t RX = 22; static constexpr const int8_t TX = 21; @@ -36,11 +39,13 @@ class GPS { static constexpr const int8_t RX = 33; static constexpr const int8_t TX = 32; #endif - static constexpr const uint16_t SERVICE_MS = 250; + static constexpr const uint16_t SERVICE_MS = 25; static constexpr const uint32_t MAX_AGE_MS = 60 * 1000; void serviceSerial(void); + HardwareSerial m_SerialPort = HardwareSerial(2); + lv_obj_t *m_Icon = NULL; lv_timer_t *m_Timer = NULL; diff --git a/include/FurbleSettings.h b/include/FurbleSettings.h index bc6c442..b8022da 100644 --- a/include/FurbleSettings.h +++ b/include/FurbleSettings.h @@ -19,6 +19,7 @@ class Settings { THEME, TX_POWER, GPS, + GPS_BAUD, INTERVAL, MULTICONNECT, RECONNECT, @@ -32,6 +33,9 @@ class Settings { const char *nvs_namespace; } setting_t; + static const uint32_t BAUD_9600 = 9600; + static const uint32_t BAUD_115200 = 115200; + static void init(void); static const setting_t &get(type_t); diff --git a/include/FurbleUI.h b/include/FurbleUI.h index 1552105..e9fa300 100644 --- a/include/FurbleUI.h +++ b/include/FurbleUI.h @@ -62,6 +62,7 @@ class UI { lv_obj_t *gpsIcon; lv_obj_t *batteryIcon; lv_obj_t *reconnectIcon; + lv_obj_t *gpsBaud; lv_obj_t *gpsData; bool screenLocked; } status_t; diff --git a/src/FurbleGPS.cpp b/src/FurbleGPS.cpp index 8d5fc16..bc25583 100644 --- a/src/FurbleGPS.cpp +++ b/src/FurbleGPS.cpp @@ -15,8 +15,6 @@ GPS &GPS::getInstance() { } void GPS::init(void) { - Serial2.begin(BAUD, SERIAL_8N1, RX, TX); - getInstance().reloadSetting(); } @@ -27,6 +25,10 @@ void GPS::setIcon(lv_obj_t *icon) { /** Refresh the setting from NVS. */ void GPS::reloadSetting(void) { m_Enabled = Settings::load(Settings::GPS); + if (m_Enabled) { + uint32_t baud = Settings::load(Settings::GPS_BAUD); + m_SerialPort.begin(baud, SERIAL_8N1, RX, TX); + } } /** Is GPS enabled? */ @@ -69,12 +71,20 @@ void GPS::update(void) { /** Read and decode the GPS data from serial port. */ void GPS::serviceSerial(void) { + static std::array buffer; + if (!m_Enabled) { return; } - while (Serial2.available() > 0) { - m_GPS.encode(Serial2.read()); + size_t available = m_SerialPort.available(); + if (available > 0) { + size_t bytes = m_SerialPort.readBytes(buffer.data(), std::min(buffer.size(), available)); + ESP_LOGI("gps", "bytes = %u", bytes); + + for (size_t i = 0; i < bytes; i++) { + m_GPS.encode(buffer[i]); + } } if ((m_GPS.location.age() < MAX_AGE_MS) && m_GPS.location.isValid() diff --git a/src/FurbleSettings.cpp b/src/FurbleSettings.cpp index 8989bed..29c06ec 100644 --- a/src/FurbleSettings.cpp +++ b/src/FurbleSettings.cpp @@ -7,12 +7,15 @@ namespace Furble { Preferences Settings::m_Prefs; +const uint32_t Settings::BAUD_9600; + const std::unordered_map Settings::m_Setting = { {BRIGHTNESS, {BRIGHTNESS, "Brightness", "brightness", "M5ez"} }, {INACTIVITY, {INACTIVITY, "Inactivity", "inactivity", "M5ez"} }, {THEME, {THEME, "Theme", "theme", "M5ez"} }, {TX_POWER, {TX_POWER, "TX Power", "tx_power", FURBLE_STR} }, {GPS, {GPS, "GPS", "gps", FURBLE_STR} }, + {GPS_BAUD, {GPS_BAUD, "GPS Baud", "gps_baud", FURBLE_STR} }, {INTERVAL, {INTERVAL, "Interval", "interval", FURBLE_STR} }, {MULTICONNECT, {MULTICONNECT, "Multi-Connect", "multiconnect", FURBLE_STR}}, {RECONNECT, {RECONNECT, "Infinite-ReConnect", "reconnect", FURBLE_STR} }, @@ -43,6 +46,16 @@ uint8_t Settings::load(type_t type) { return value; } +template <> +uint32_t Settings::load(type_t type) { + const auto &setting = get(type); + m_Prefs.begin(setting.nvs_namespace, true); + uint32_t value = m_Prefs.getUInt(setting.key); + m_Prefs.end(); + + return value; +} + template <> std::string Settings::load(type_t type) { const auto &setting = get(type); @@ -106,6 +119,14 @@ void Settings::save(const type_t type, const uint8_t &value) { m_Prefs.end(); } +template <> +void Settings::save(const type_t type, const uint32_t &value) { + const auto &setting = get(type); + m_Prefs.begin(setting.nvs_namespace, false); + m_Prefs.putUInt(setting.key, value); + m_Prefs.end(); +} + template <> void Settings::save(const type_t type, const interval_t &value) { const auto &setting = get(type); @@ -155,6 +176,9 @@ void Settings::init(void) { case FAUXNY: save(setting.type, false); break; + case GPS_BAUD: + save(setting.type, BAUD_9600); + break; } } m_Prefs.end(); diff --git a/src/FurbleUI.cpp b/src/FurbleUI.cpp index 57649eb..84e7a10 100644 --- a/src/FurbleUI.cpp +++ b/src/FurbleUI.cpp @@ -669,8 +669,10 @@ void UI::addSettingItem(lv_obj_t *page, const char *symbol, Settings::type_t set auto *status = static_cast(lv_event_get_user_data(e)); status->gps->reloadSetting(); if (status->gps->isEnabled()) { + lv_obj_clear_flag(status->gpsBaud, LV_OBJ_FLAG_HIDDEN); lv_obj_clear_flag(status->gpsData, LV_OBJ_FLAG_HIDDEN); } else { + lv_obj_add_flag(status->gpsBaud, LV_OBJ_FLAG_HIDDEN); lv_obj_add_flag(status->gpsData, LV_OBJ_FLAG_HIDDEN); } }, @@ -1294,9 +1296,38 @@ void UI::addGPSMenu(const menu_t &parent) { addSettingItem(menu.page, NULL, Settings::GPS); lv_menu_set_load_page_event(menu.main, menu.button, menu.page); + // add GPS baud control + m_Status.gpsBaud = lv_menu_cont_create(menu.page); + lv_obj_set_flex_flow(m_Status.gpsBaud, LV_FLEX_FLOW_ROW_WRAP); + lv_obj_t *label = lv_label_create(m_Status.gpsBaud); + lv_label_set_text(label, "GPS baud 115200"); + lv_label_set_long_mode(label, LV_LABEL_LONG_SCROLL_CIRCULAR); + lv_obj_set_flex_grow(label, 1); + + lv_obj_t *baud_sw = lv_switch_create(m_Status.gpsBaud); + uint32_t baud = Settings::load(Settings::GPS_BAUD); + lv_obj_add_state(baud_sw, baud == Settings::BAUD_115200 ? LV_STATE_CHECKED : 0); + lv_obj_add_event_cb( + baud_sw, + [](lv_event_t *e) { + auto *status = static_cast(lv_event_get_user_data(e)); + lv_obj_t *baud_sw = static_cast(lv_event_get_target(e)); + uint32_t baud; + + if (lv_obj_has_state(baud_sw, LV_STATE_CHECKED)) { + baud = Settings::BAUD_115200; + } else { + baud = Settings::BAUD_9600; + } + Settings::save(Settings::GPS_BAUD, baud); + status->gps->reloadSetting(); + }, + LV_EVENT_VALUE_CHANGED, &m_Status); + menu_t &gpsData = addMenu(m_GPSDataStr, NULL, true, menu); m_Status.gpsData = gpsData.button; if (!m_Status.gps->isEnabled()) { + lv_obj_add_flag(m_Status.gpsBaud, LV_OBJ_FLAG_HIDDEN); lv_obj_add_flag(m_Status.gpsData, LV_OBJ_FLAG_HIDDEN); } @@ -1308,6 +1339,9 @@ void UI::addGPSMenu(const menu_t &parent) { lv_label_set_text_fmt(valid, "%s (%u)", gps.location.isValid() ? "Valid" : "Invalid", gps.satellites.value()); + static lv_obj_t *age = lv_label_create(gpsData->page); + lv_label_set_text_fmt(age, "%us ago", gps.time.age() / 1000); + static lv_obj_t *lat = lv_label_create(gpsData->page); lv_label_set_text_fmt(lat, "%.2f°", gps.location.lat()); @@ -1317,12 +1351,19 @@ void UI::addGPSMenu(const menu_t &parent) { static lv_obj_t *alt = lv_label_create(gpsData->page); lv_label_set_text_fmt(alt, "%.2f m", gps.altitude.meters()); +#if defined(FURBLE_M5COREX) + static lv_obj_t *datetime = lv_label_create(gpsData->page); + lv_label_set_text_fmt(datetime, "%4u-%02u-%02u %02u:%02u:%02u", gps.date.year(), + gps.date.month(), gps.date.day(), gps.time.hour(), gps.time.minute(), + gps.time.second()); +#else static lv_obj_t *date = lv_label_create(gpsData->page); lv_label_set_text_fmt(date, "%4u-%02u-%02u", gps.date.year(), gps.date.month(), gps.date.day()); static lv_obj_t *time = lv_label_create(gpsData->page); lv_label_set_text_fmt(time, "%02u:%02u:%02u", gps.time.hour(), gps.time.minute(), gps.time.second()); +#endif }, 1000, &gpsData); lv_timer_pause(timer);