Fix settings persistence and GNSS UI behavior

This commit is contained in:
liu weikai committed 2026-03-23 17:49:19 +08:00
1 parent 8ccb1732f2
commit 3cb2841b1f
6 files changed
+500 -40

No files matched your search

+387 -13
View File
@@ -13,7 +13,10 @@
#include <time.h>
#include <algorithm>
#include <array>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <limits>
@@ -67,6 +70,11 @@ struct GpsRuntimeState
TinyGPSPlus parser{};
::gps::GpsState data{};
::gps::GnssStatus status{};
struct GsvCollector
{
std::array<::gps::GnssSatInfo, ::gps::kMaxGnssSats> sats{};
std::size_t count = 0;
};
uint32_t last_motion_ms = 0;
uint32_t collection_interval_ms = 60000;
uint32_t motion_idle_timeout_ms = 0;
@@ -82,6 +90,13 @@ struct GpsRuntimeState
uint32_t last_time_sync_log_ms = 0;
uint32_t last_time_sync_epoch_logged = 0;
uint32_t last_status_log_ms = 0;
std::array<GsvCollector, 5> gsv{};
std::array<::gps::GnssSatInfo, ::gps::kMaxGnssSats> sats{};
std::array<uint16_t, ::gps::kMaxGnssSats> used_sat_ids{};
char nmea_line[96] = {};
std::size_t sat_count = 0;
std::size_t used_sat_count = 0;
std::size_t nmea_line_len = 0;
bool enabled = true;
bool powered = false;
bool initialized = false;
@@ -90,6 +105,16 @@ struct GpsRuntimeState
} s_gps;
constexpr uint32_t kMinValidEpochSeconds = 1700000000UL;
constexpr std::size_t kNmeaFieldMax = 24;
enum class CollectorSlot : uint8_t
{
GPS = 0,
GLN = 1,
GAL = 2,
BD = 3,
UNKNOWN = 4,
};
uint32_t readSystemEpochSeconds()
{
@@ -106,6 +131,327 @@ void syncSystemClockFromEpoch(uint32_t epoch_s)
(void)epoch_s;
}
CollectorSlot collectorSlotForTalker(const char* talker)
{
if (!talker || talker[0] == '\0' || talker[1] == '\0')
{
return CollectorSlot::UNKNOWN;
}
if (talker[0] == 'G' && talker[1] == 'P')
{
return CollectorSlot::GPS;
}
if (talker[0] == 'G' && talker[1] == 'L')
{
return CollectorSlot::GLN;
}
if (talker[0] == 'G' && talker[1] == 'A')
{
return CollectorSlot::GAL;
}
if ((talker[0] == 'G' && talker[1] == 'B') || (talker[0] == 'B' && talker[1] == 'D'))
{
return CollectorSlot::BD;
}
return CollectorSlot::UNKNOWN;
}
::gps::GnssSystem systemForSlot(CollectorSlot slot)
{
switch (slot)
{
case CollectorSlot::GPS:
return ::gps::GnssSystem::GPS;
case CollectorSlot::GLN:
return ::gps::GnssSystem::GLN;
case CollectorSlot::GAL:
return ::gps::GnssSystem::GAL;
case CollectorSlot::BD:
return ::gps::GnssSystem::BD;
default:
return ::gps::GnssSystem::UNKNOWN;
}
}
bool parseUint(const char* text, uint32_t* out)
{
if (!text || !*text || !out)
{
return false;
}
char* end = nullptr;
unsigned long value = std::strtoul(text, &end, 10);
if (end == text)
{
return false;
}
*out = static_cast<uint32_t>(value);
return true;
}
bool parseInt(const char* text, int* out)
{
if (!text || !*text || !out)
{
return false;
}
char* end = nullptr;
long value = std::strtol(text, &end, 10);
if (end == text)
{
return false;
}
*out = static_cast<int>(value);
return true;
}
bool verifyChecksum(const char* line)
{
if (!line || line[0] != '$')
{
return false;
}
const char* star = std::strchr(line, '*');
if (!star || !star[1] || !star[2])
{
return true;
}
uint8_t checksum = 0;
for (const char* cursor = line + 1; cursor < star; ++cursor)
{
checksum ^= static_cast<uint8_t>(*cursor);
}
char checksum_text[3] = {star[1], star[2], '\0'};
char* end = nullptr;
long expected = std::strtol(checksum_text, &end, 16);
return end != checksum_text && checksum == static_cast<uint8_t>(expected & 0xFF);
}
std::size_t splitFields(char* sentence, std::array<char*, kNmeaFieldMax>& fields)
{
fields.fill(nullptr);
std::size_t count = 0;
char* cursor = sentence;
while (cursor && *cursor && count < fields.size())
{
fields[count++] = cursor;
char* comma = std::strchr(cursor, ',');
if (!comma)
{
break;
}
*comma = '\0';
cursor = comma + 1;
}
return count;
}
bool usedSat(uint16_t sat_id)
{
for (std::size_t i = 0; i < s_gps.used_sat_count; ++i)
{
if (s_gps.used_sat_ids[i] == sat_id)
{
return true;
}
}
return false;
}
void mergeGnssSatellites()
{
s_gps.sat_count = 0;
for (std::size_t collector_index = 0; collector_index < s_gps.gsv.size(); ++collector_index)
{
auto& collector = s_gps.gsv[collector_index];
for (std::size_t sat_index = 0;
sat_index < collector.count && s_gps.sat_count < s_gps.sats.size();
++sat_index)
{
auto sat = collector.sats[sat_index];
sat.used = usedSat(sat.id);
s_gps.sats[s_gps.sat_count++] = sat;
}
}
s_gps.status.sats_in_view = static_cast<uint8_t>(std::min<std::size_t>(s_gps.sat_count, 255U));
if (s_gps.used_sat_count > 0)
{
s_gps.status.sats_in_use = static_cast<uint8_t>(std::min<std::size_t>(s_gps.used_sat_count, 255U));
}
}
void clearGpsObservations()
{
s_gps.parser = TinyGPSPlus{};
s_gps.data = ::gps::GpsState{};
s_gps.status = ::gps::GnssStatus{};
s_gps.sats.fill(::gps::GnssSatInfo{});
s_gps.used_sat_ids.fill(0);
s_gps.gsv.fill(GpsRuntimeState::GsvCollector{});
s_gps.sat_count = 0;
s_gps.used_sat_count = 0;
s_gps.last_nmea_ms = 0;
s_gps.nmea_line_len = 0;
s_gps.nmea_line[0] = '\0';
s_gps.nmea_seen = false;
}
void parseGsaSentence(const std::array<char*, kNmeaFieldMax>& fields, std::size_t count)
{
if (count < 4)
{
return;
}
s_gps.used_sat_count = 0;
for (std::size_t i = 3; i <= 14 && i < count; ++i)
{
uint32_t sat_id = 0;
if (!parseUint(fields[i], &sat_id) || sat_id == 0 || s_gps.used_sat_count >= s_gps.used_sat_ids.size())
{
continue;
}
s_gps.used_sat_ids[s_gps.used_sat_count++] = static_cast<uint16_t>(sat_id);
}
mergeGnssSatellites();
}
void parseGsvSentence(const char* talker, const std::array<char*, kNmeaFieldMax>& fields, std::size_t count)
{
if (count < 4)
{
return;
}
const CollectorSlot slot = collectorSlotForTalker(talker);
auto& collector = s_gps.gsv[static_cast<std::size_t>(slot)];
uint32_t msg_num = 0;
if (!parseUint(fields[2], &msg_num))
{
return;
}
uint32_t sats_in_view = 0;
if (parseUint(fields[3], &sats_in_view))
{
s_gps.status.sats_in_view = static_cast<uint8_t>(std::min<uint32_t>(sats_in_view, 255U));
}
if (msg_num == 1)
{
collector.count = 0;
}
for (std::size_t base = 4; base + 3 < count && collector.count < collector.sats.size(); base += 4)
{
uint32_t sat_id = 0;
if (!parseUint(fields[base], &sat_id) || sat_id == 0)
{
continue;
}
::gps::GnssSatInfo sat{};
sat.id = static_cast<uint16_t>(sat_id);
sat.sys = systemForSlot(slot);
uint32_t elevation = 0;
if (parseUint(fields[base + 1], &elevation))
{
sat.elevation = static_cast<uint8_t>(std::min<uint32_t>(elevation, 90U));
}
uint32_t azimuth = 0;
if (parseUint(fields[base + 2], &azimuth))
{
sat.azimuth = static_cast<uint16_t>(std::min<uint32_t>(azimuth, 359U));
}
int snr = -1;
if (parseInt(fields[base + 3], &snr))
{
sat.snr = static_cast<int8_t>(std::clamp(snr, -1, 99));
}
collector.sats[collector.count++] = sat;
}
mergeGnssSatellites();
}
void parseNmeaSentence(char* sentence)
{
if (!sentence || sentence[0] != '$' || !verifyChecksum(sentence))
{
return;
}
char* payload = sentence + 1;
char* star = std::strchr(payload, '*');
if (star)
{
*star = '\0';
}
std::array<char*, kNmeaFieldMax> fields{};
const std::size_t count = splitFields(payload, fields);
if (count == 0 || !fields[0] || std::strlen(fields[0]) < 5)
{
return;
}
char talker[3] = {fields[0][0], fields[0][1], '\0'};
const char* type = fields[0] + std::strlen(fields[0]) - 3;
if (std::strcmp(type, "GSA") == 0)
{
parseGsaSentence(fields, count);
}
else if (std::strcmp(type, "GSV") == 0)
{
parseGsvSentence(talker, fields, count);
}
}
void processGpsNmeaChar(char ch)
{
if (ch == '$')
{
s_gps.nmea_line_len = 0;
s_gps.nmea_line[s_gps.nmea_line_len++] = ch;
return;
}
if (s_gps.nmea_line_len == 0)
{
return;
}
if (ch == '\r' || ch == '\n')
{
if (s_gps.nmea_line_len > 0)
{
s_gps.nmea_line[s_gps.nmea_line_len] = '\0';
parseNmeaSentence(s_gps.nmea_line);
s_gps.nmea_line_len = 0;
}
return;
}
if (s_gps.nmea_line_len + 1 < sizeof(s_gps.nmea_line))
{
s_gps.nmea_line[s_gps.nmea_line_len++] = ch;
}
else
{
s_gps.nmea_line_len = 0;
}
}
uint8_t daysInMonth(int year, uint8_t month)
{
static constexpr uint8_t kDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
@@ -363,8 +709,12 @@ void refreshGpsFix()
? static_cast<uint32_t>(s_gps.parser.location.age())
: 0xFFFFFFFFUL;
s_gps.status.sats_in_use = s_gps.data.satellites;
s_gps.status.sats_in_view = s_gps.data.satellites;
s_gps.status.sats_in_use = s_gps.used_sat_count > 0
? static_cast<uint8_t>(std::min<std::size_t>(s_gps.used_sat_count, 255U))
: s_gps.data.satellites;
s_gps.status.sats_in_view = s_gps.sat_count > 0
? static_cast<uint8_t>(std::min<std::size_t>(s_gps.sat_count, 255U))
: s_gps.data.satellites;
s_gps.status.hdop = s_gps.parser.hdop.isValid()
? static_cast<float>(s_gps.parser.hdop.hdop())
: 0.0f;
@@ -957,7 +1307,11 @@ void Gat562Board::applyGpsConfig(const app::AppConfig& config)
s_gps.nmea_sentence_mask = config.privacy_nmea_sentence;
s_gps.motion_idle_timeout_ms = config.motion_config.idle_timeout_ms;
s_gps.motion_sensor_id = config.motion_config.sensor_id;
s_gps.enabled = true;
s_gps.enabled = (config.gps_mode != 0);
if (!s_gps.enabled)
{
clearGpsObservations();
}
Serial.printf(
"[gat562][gps] config enabled=%u interval_ms=%lu strategy=%u mode=%u sat_mask=0x%02X nmea_hz=%u nmea_mask=0x%02X motion_idle_ms=%lu motion_sensor=%u\n",
static_cast<unsigned>(s_gps.enabled ? 1 : 0),
@@ -982,7 +1336,9 @@ void Gat562Board::tickGps()
{
s_gps.nmea_seen = true;
s_gps.last_nmea_ms = millis();
s_gps.parser.encode(static_cast<char>(Serial1.read()));
const char ch = static_cast<char>(Serial1.read());
s_gps.parser.encode(ch);
processGpsNmeaChar(ch);
}
applyGpsTimeIfValid();
refreshGpsFix();
@@ -1027,19 +1383,20 @@ bool Gat562Board::gpsGnssSnapshot(::gps::GnssSatInfo* out,
{
*status = s_gps.status;
}
if (out && max > 0 && s_gps.data.satellites > 0)
if (out && max > 0 && s_gps.sat_count > 0)
{
out[0].id = 0;
out[0].sys = ::gps::GnssSystem::GPS;
out[0].snr = -1;
out[0].used = s_gps.data.valid;
const std::size_t copy_count = std::min<std::size_t>(max, s_gps.sat_count);
for (std::size_t index = 0; index < copy_count; ++index)
{
out[index] = s_gps.sats[index];
}
if (out_count)
{
*out_count = 1;
*out_count = copy_count;
}
return true;
}
return s_gps.data.valid || s_gps.data.satellites > 0;
return s_gps.data.valid || s_gps.data.satellites > 0 || s_gps.sat_count > 0;
}
void Gat562Board::setGpsCollectionInterval(uint32_t interval_ms) { s_gps.collection_interval_ms = interval_ms; }
@@ -1048,6 +1405,11 @@ void Gat562Board::setGpsConfig(uint8_t mode, uint8_t sat_mask)
{
s_gps.gnss_mode = mode;
s_gps.sat_mask = sat_mask;
s_gps.enabled = (mode != 0);
if (!s_gps.enabled)
{
clearGpsObservations();
}
}
void Gat562Board::setGpsNmeaConfig(uint8_t output_hz, uint8_t sentence_mask)
{
@@ -1056,8 +1418,20 @@ void Gat562Board::setGpsNmeaConfig(uint8_t output_hz, uint8_t sentence_mask)
}
void Gat562Board::setGpsMotionIdleTimeout(uint32_t timeout_ms) { s_gps.motion_idle_timeout_ms = timeout_ms; }
void Gat562Board::setGpsMotionSensorId(uint8_t sensor_id) { s_gps.motion_sensor_id = sensor_id; }
void Gat562Board::suspendGps() { s_gps.enabled = false; }
void Gat562Board::resumeGps() { s_gps.enabled = true; }
void Gat562Board::suspendGps()
{
s_gps.enabled = false;
clearGpsObservations();
}
void Gat562Board::resumeGps()
{
s_gps.enabled = (s_gps.gnss_mode != 0);
if (!s_gps.enabled)
{
clearGpsObservations();
}
}
void Gat562Board::setCurrentEpochSeconds(uint32_t epoch_s)
{
if (epoch_s < kMinValidEpochSeconds)
@@ -11,6 +11,7 @@
#include <cstddef>
#include <cstdint>
#include <ctime>
#include <array>
namespace ui::mono_128x64
{
@@ -200,6 +201,7 @@ class Runtime : public chat::ChatService::IncomingTextObserver
void drawMenuList(const char* title, const char* const* items, size_t count, size_t selected);
void drawFooterHint(const char* hint);
void drawTextClipped(int x, int y, int w, const char* text, bool inverse = false);
void refreshGnssSnapshot(bool force = false);
bool editUsesHexCharset() const;
bool usesSmartCompose() const;
@@ -303,6 +305,12 @@ class Runtime : public chat::ChatService::IncomingTextObserver
char compose_candidates_[kComposeCandidateMax][kComposeCandidateWidth] = {};
size_t compose_candidate_count_ = 0;
size_t compose_candidate_index_ = 0;
platform::ui::gps::GpsState gnss_snapshot_state_{};
platform::ui::gps::GnssStatus gnss_snapshot_status_{};
std::array<platform::ui::gps::GnssSatInfo, ::gps::kMaxGnssSats> gnss_snapshot_sats_{};
size_t gnss_snapshot_count_ = 0;
uint32_t gnss_snapshot_updated_ms_ = 0;
bool gnss_snapshot_valid_ = false;
};
} // namespace ui::mono_128x64
+48 -14
View File
@@ -8,7 +8,6 @@
#include "chat/runtime/self_identity_policy.h"
#include "chat/usecase/chat_service.h"
#include "chat/usecase/contact_service.h"
#include <algorithm>
#include <array>
#include <cctype>
@@ -135,6 +134,7 @@ constexpr size_t kNodeInfoPageSize = 6;
constexpr size_t kInfoPageSize = 6;
constexpr size_t kGnssSummaryPageSize = 6;
constexpr size_t kGnssSatPageSize = 5;
constexpr uint32_t kGnssSnapshotRefreshMs = 5000;
constexpr int kTimezoneMin = -12 * 60;
constexpr int kTimezoneMax = 14 * 60;
constexpr int kTimezoneStep = 60;
@@ -1701,6 +1701,29 @@ void Runtime::renderBootLog()
}
}
void Runtime::refreshGnssSnapshot(bool force)
{
const uint32_t now = nowMs();
const bool stale = !gnss_snapshot_valid_ ||
now < gnss_snapshot_updated_ms_ ||
(now - gnss_snapshot_updated_ms_) >= kGnssSnapshotRefreshMs;
if (!force && !stale)
{
return;
}
gnss_snapshot_state_ = host_.gps_data_fn ? host_.gps_data_fn() : platform::ui::gps::GpsState{};
gnss_snapshot_status_ = platform::ui::gps::GnssStatus{};
gnss_snapshot_count_ = 0;
gnss_snapshot_sats_.fill(platform::ui::gps::GnssSatInfo{});
(void)platform::ui::gps::get_gnss_snapshot(gnss_snapshot_sats_.data(),
gnss_snapshot_sats_.size(),
&gnss_snapshot_count_,
&gnss_snapshot_status_);
gnss_snapshot_updated_ms_ = now;
gnss_snapshot_valid_ = true;
}
void Runtime::renderScreensaver()
{
char protocol[8] = {};
@@ -1731,8 +1754,10 @@ void Runtime::renderScreensaver()
sizeof(freq));
}
refreshGnssSnapshot();
const auto battery = host_.battery_info_fn ? host_.battery_info_fn() : platform::ui::device::BatteryInfo{};
const auto gps = host_.gps_data_fn ? host_.gps_data_fn() : platform::ui::gps::GpsState{};
const auto& gps = gnss_snapshot_state_;
const auto& gnss_status = gnss_snapshot_status_;
const int unread = app() ? app()->getChatService().getTotalUnread() : 0;
const bool gps_enabled = host_.gps_enabled_fn && host_.gps_enabled_fn();
const bool ble_enabled = app() && app()->isBleEnabled();
@@ -1745,9 +1770,14 @@ void Runtime::renderScreensaver()
{
std::snprintf(bat_pct_buf, sizeof(bat_pct_buf), "BAT:--");
}
if (gps.satellites > 0)
const unsigned satellite_count = gnss_status.sats_in_view > 0
? static_cast<unsigned>(gnss_status.sats_in_view)
: (gnss_snapshot_count_ > 0
? static_cast<unsigned>(gnss_snapshot_count_)
: static_cast<unsigned>(gps.satellites));
if (satellite_count > 0)
{
std::snprintf(sat_buf, sizeof(sat_buf), "SAT %u", static_cast<unsigned>(gps.satellites));
std::snprintf(sat_buf, sizeof(sat_buf), "SAT %u", satellite_count);
}
else if (gps_enabled)
{
@@ -2386,16 +2416,16 @@ void Runtime::renderSettingPopup()
formatSettingPopupValue(value, sizeof(value));
constexpr int kBoxX = 8;
constexpr int kBoxY = 18;
constexpr int kBoxY = 14;
constexpr int kBoxW = 112;
constexpr int kBoxH = 28;
constexpr int kBoxH = 36;
display_.fillRect(kBoxX, kBoxY, kBoxW, kBoxH, false);
drawFrame(display_, kBoxX, kBoxY, kBoxW, kBoxH);
const int title_w = text_renderer_.measureTextWidth(title);
text_renderer_.drawText(display_, kBoxX + std::max(2, (kBoxW - title_w) / 2), kBoxY + 3, title);
const int value_w = text_renderer_.measureTextWidth(value);
text_renderer_.drawText(display_, kBoxX + std::max(2, (kBoxW - value_w) / 2), kBoxY + 13, value);
drawTextClipped(kBoxX + 2, kBoxY + 21, kBoxW - 4, "ADJ ARROWS SEL OK BACK ESC");
text_renderer_.drawText(display_, kBoxX + std::max(2, (kBoxW - value_w) / 2), kBoxY + 14, value);
drawTextClipped(kBoxX + 2, kBoxY + 25, kBoxW - 4, "ADJ ARROWS SEL OK BACK ESC");
}
void Runtime::renderInfoPage()
@@ -2587,11 +2617,11 @@ void Runtime::renderInfoPage()
void Runtime::renderGnssPage()
{
const auto state = host_.gps_data_fn ? host_.gps_data_fn() : platform::ui::gps::GpsState{};
platform::ui::gps::GnssStatus status{};
std::size_t sat_count = 0;
platform::ui::gps::GnssSatInfo sats[::gps::kMaxGnssSats] = {};
(void)platform::ui::gps::get_gnss_snapshot(sats, ::gps::kMaxGnssSats, &sat_count, &status);
refreshGnssSnapshot();
const auto& state = gnss_snapshot_state_;
const auto& status = gnss_snapshot_status_;
const std::size_t sat_count = gnss_snapshot_count_;
const auto* sats = gnss_snapshot_sats_.data();
char summary_lines[14][40] = {};
size_t summary_count = 0;
@@ -2706,7 +2736,7 @@ void Runtime::renderGnssPage()
const size_t sat_visible = std::min(kGnssSatPageSize, sat_count - std::min(sat_start, sat_count));
if (sat_visible == 0)
{
text_renderer_.drawText(display_, 0, 22, "NO SAT DATA");
text_renderer_.drawText(display_, 0, 22, "NO SATELLITE DATA");
return;
}
@@ -2736,6 +2766,10 @@ void Runtime::enterPage(Page page)
{
page_ = page;
page_entered_ms_ = nowMs();
if (page == Page::Screensaver || page == Page::GnssPage)
{
refreshGnssSnapshot(true);
}
if (page == Page::ChatList)
{
rebuildConversationList();
@@ -200,10 +200,15 @@ void ensureLoaded()
{
return;
}
loadedFlag() = true;
clearAllStores();
if (!ensureFs() || !InternalFS.exists(kSettingsPath))
if (!ensureFs())
{
return;
}
loadedFlag() = true;
if (!InternalFS.exists(kSettingsPath))
{
return;
}
@@ -221,18 +226,25 @@ void ensureLoaded()
return;
}
std::map<std::string, int> loaded_ints;
std::map<std::string, bool> loaded_bools;
std::map<std::string, uint32_t> loaded_uints;
std::map<std::string, std::vector<uint8_t>> loaded_blobs;
for (uint32_t i = 0; i < header.record_count; ++i)
{
RecordHeader rec{};
if (!readPod(file, &rec))
{
break;
file.close();
return;
}
std::string key(rec.key_len, '\0');
if (rec.key_len > 0 && file.read(&key[0], rec.key_len) != rec.key_len)
{
break;
file.close();
return;
}
switch (static_cast<ValueType>(rec.type))
@@ -242,9 +254,10 @@ void ensureLoaded()
int32_t value = 0;
if (rec.value_len != sizeof(value) || !readPod(file, &value))
{
file.close();
return;
}
intStore()[key] = value;
loaded_ints[key] = value;
break;
}
case ValueType::Bool:
@@ -252,9 +265,10 @@ void ensureLoaded()
uint8_t value = 0;
if (rec.value_len != sizeof(value) || !readPod(file, &value))
{
file.close();
return;
}
boolStore()[key] = (value != 0);
loaded_bools[key] = (value != 0);
break;
}
case ValueType::Uint:
@@ -262,9 +276,10 @@ void ensureLoaded()
uint32_t value = 0;
if (rec.value_len != sizeof(value) || !readPod(file, &value))
{
file.close();
return;
}
uintStore()[key] = value;
loaded_uints[key] = value;
break;
}
case ValueType::Blob:
@@ -272,9 +287,10 @@ void ensureLoaded()
std::vector<uint8_t> value(rec.value_len, 0);
if (rec.value_len > 0 && file.read(value.data(), rec.value_len) != rec.value_len)
{
file.close();
return;
}
blobStore()[key] = value;
loaded_blobs[key] = std::move(value);
break;
}
default:
@@ -282,6 +298,7 @@ void ensureLoaded()
std::vector<uint8_t> skip(rec.value_len, 0);
if (rec.value_len > 0 && file.read(skip.data(), rec.value_len) != rec.value_len)
{
file.close();
return;
}
break;
@@ -290,6 +307,10 @@ void ensureLoaded()
}
file.close();
intStore() = std::move(loaded_ints);
boolStore() = std::move(loaded_bools);
uintStore() = std::move(loaded_uints);
blobStore() = std::move(loaded_blobs);
}
} // namespace
@@ -12,22 +12,20 @@ namespace
constexpr const char* kSettingsNs = "settings";
constexpr const char* kTimezoneKey = "timezone_offset";
int& timezoneOffsetStorage()
int stored_timezone_offset_min()
{
static int s_offset_min = ::platform::ui::settings_store::get_int(kSettingsNs, kTimezoneKey, 0);
return s_offset_min;
return ::platform::ui::settings_store::get_int(kSettingsNs, kTimezoneKey, 0);
}
} // namespace
int timezone_offset_min()
{
return timezoneOffsetStorage();
return stored_timezone_offset_min();
}
void set_timezone_offset_min(int offset_min)
{
timezoneOffsetStorage() = offset_min;
::platform::ui::settings_store::put_int(kSettingsNs, kTimezoneKey, offset_min);
}
+25
View File
@@ -19,6 +19,31 @@ env.Append(CPPDEFINES=["LV_CONF_INCLUDE_SIMPLE"])
print(f"[pio] pre: Added LVGL config include path: {ui_dir}")
# On nordicnrf52/Windows builds, `${platformio.packages_dir}` inside `build_flags`
# can be rewritten into an invalid builder-local include path. Inject the
# TinyUSB framework paths here using the resolved absolute package location so
# framework libraries like `Wire` can include `<Adafruit_TinyUSB.h>`.
platform = env.PioPlatform()
framework_dir = platform.get_package_dir("framework-arduinoadafruitnrf52")
if framework_dir:
framework_include_candidates = [
os.path.join(framework_dir, "libraries", "Adafruit_TinyUSB_Arduino", "src"),
os.path.join(framework_dir, "libraries", "Adafruit_TinyUSB_Arduino", "src", "arduino"),
os.path.join(framework_dir, "libraries", "SPI"),
os.path.join(framework_dir, "libraries", "Wire"),
os.path.join(framework_dir, "libraries", "Bluefruit52Lib", "src"),
os.path.join(framework_dir, "libraries", "Bluefruit52Lib", "src", "services"),
os.path.join(framework_dir, "libraries", "Adafruit_nRFCrypto", "src"),
os.path.join(framework_dir, "libraries", "Adafruit_LittleFS", "src"),
os.path.join(framework_dir, "libraries", "InternalFileSytem", "src"),
]
existing_cpppath = set(env.get("CPPPATH", []))
include_paths = [path for path in framework_include_candidates if os.path.isdir(path)]
missing_paths = [path for path in include_paths if path not in existing_cpppath]
if missing_paths:
env.Append(CPPPATH=missing_paths)
print(f"[pio] pre: Added nRF52 framework include paths: {', '.join(missing_paths)}")
# Generate protobuf files if .proto files exist
proto_dir = os.path.join(project_dir, "lib", "meshtastic_protobufs")
generate_script = os.path.join(project_dir, "scripts", "generate_protobuf.py")