#pragma once // Saved GPS waypoints — small fixed table persisted to /waypoints. Unlike the // trail (a RAM ring), waypoints are long-lived: loaded at boot, rewritten on // every add / delete / rename. Used by the navigation feature to mark a spot // (car, camp, water…) and later get bearing + distance back to it. #include #include #include "Persist.h" static const uint8_t WAYPOINT_LABEL_LEN = 12; // incl. NUL → 11 visible chars struct Waypoint { int32_t lat_1e6, lon_1e6; uint32_t ts; // RTC time when marked char label[WAYPOINT_LABEL_LEN]; }; class WaypointStore { public: static const int CAPACITY = 16; int count() const { return _count; } bool full() const { return _count >= CAPACITY; } const Waypoint& at(int i) const { return _wp[i]; } // Add a waypoint; label may be empty (caller can auto-name). Returns false // if the table is full. Trims/copies the label safely. bool add(int32_t lat, int32_t lon, uint32_t ts, const char* label) { if (_count >= CAPACITY) return false; Waypoint& w = _wp[_count++]; w.lat_1e6 = lat; w.lon_1e6 = lon; w.ts = ts; setLabel(w, label); return true; } void remove(int i) { if (i < 0 || i >= _count) return; for (int j = i; j < _count - 1; j++) _wp[j] = _wp[j + 1]; _count--; } void rename(int i, const char* label) { if (i < 0 || i >= _count) return; setLabel(_wp[i], label); } void clear() { _count = 0; } // ── persistence ────────────────────────────────────────────────────────── // Layout: 4-byte magic "WYPT", uint8 version, uint8 reserved, uint16 count, // then `count` raw Waypoint records. static const uint32_t SAVE_MAGIC = 0x54505957; // "WYPT" little-endian static const uint8_t SAVE_VERSION = 1; template bool writeTo(F& file) { if (!persist::writeHeader(file, SAVE_MAGIC, SAVE_VERSION, (uint16_t)_count)) return false; for (int i = 0; i < _count; i++) { if (file.write((uint8_t*)&_wp[i], sizeof(Waypoint)) != sizeof(Waypoint)) return false; } return true; } template bool readFrom(F& file) { uint16_t cnt = 0; if (!persist::readHeader(file, SAVE_MAGIC, SAVE_VERSION, cnt)) return false; if (cnt > CAPACITY) cnt = CAPACITY; _count = 0; for (uint16_t i = 0; i < cnt; i++) { Waypoint w; if (file.read((uint8_t*)&w, sizeof(Waypoint)) != (int)sizeof(Waypoint)) break; w.label[WAYPOINT_LABEL_LEN - 1] = '\0'; // defensive _wp[_count++] = w; } return true; } private: Waypoint _wp[CAPACITY]; int _count = 0; static void setLabel(Waypoint& w, const char* label) { if (label && label[0]) { strncpy(w.label, label, WAYPOINT_LABEL_LEN - 1); w.label[WAYPOINT_LABEL_LEN - 1] = '\0'; } else { w.label[0] = '\0'; } } };