Files
espnav-display/include/Config.h
T

330 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
/**
* @file Config.h
* @brief Central configuration constants, data structures and enumerations
* for the Marine Navigation Display.
*
* All hardware pin assignments, BLE UUIDs, display layout parameters and
* application-level structs are defined here so that every module shares a
* single source of truth.
*/
#include <Arduino.h>
#include <stdint.h>
// =============================================================================
// Firmware version
// =============================================================================
#ifndef APP_VERSION
#define APP_VERSION "1.0.0"
#endif
// =============================================================================
// Hardware — SPI pins for the 4.2" GxEPD2 e-ink display
// Waveshare ESP32-S3-Zero default SPI wiring
// =============================================================================
namespace Pins {
// ── E-Ink display ─────────────────────────────────────────────────────────
constexpr uint8_t EPD_CS = 7; ///< Chip Select
constexpr uint8_t EPD_DC = 6; ///< Data/Command
constexpr uint8_t EPD_RST = 5; ///< Reset
constexpr uint8_t EPD_BUSY = 4; ///< Busy signal (active LOW)
constexpr uint8_t EPD_SCK = 12; ///< SPI clock (HSPI SCK)
constexpr uint8_t EPD_MOSI = 11; ///< SPI MOSI (HSPI MOSI)
// ── Capacitive touch buttons (ESP32-S3 native touch) ─────────────────────
// Override via platformio.ini build_flags if needed.
constexpr uint8_t TOUCH_NEXT = TOUCH_PIN_NEXT; ///< Next page / +
constexpr uint8_t TOUCH_PREV = TOUCH_PIN_PREV; ///< Previous page / -
constexpr uint8_t TOUCH_ACTION = TOUCH_PIN_ACTION; ///< Action / full refresh
// ── NeoPixel RGB status LED ───────────────────────────────────────────────
constexpr uint8_t LED = STATUS_LED_PIN;
}
// =============================================================================
// Touch input parameters
// =============================================================================
namespace Touch {
constexpr uint16_t THRESHOLD = 40; ///< Raw touch value below = touched
constexpr uint32_t DEBOUNCE_MS = 50; ///< Minimum ms between events
constexpr uint32_t LONG_PRESS_MS = 1500; ///< Hold duration for long-press
constexpr uint32_t AP_COMBO_MS = 3000; ///< Hold NEXT+PREV to enter AP mode
}
// =============================================================================
// BLE — Marine Gateway protocol UUIDs
// Base: 4D475743-xxxx-4E41-5649-474154494F4E
// =============================================================================
namespace BleUUID {
// ── Services ──────────────────────────────────────────────────────────────
constexpr const char* NAV_SVC = "4d475743-0001-4e41-5649-474154494f4e";
constexpr const char* WIND_SVC = "4d475743-0002-4e41-5649-474154494f4e";
constexpr const char* AUTOPILOT_SVC = "4d475743-0003-4e41-5649-474154494f4e";
constexpr const char* PERF_SVC = "4d475743-0004-4e41-5649-474154494f4e";
constexpr const char* ADMIN_SVC = "4d475743-0005-4e41-5649-474154494f4e";
// ── Characteristics (read / notify) ───────────────────────────────────────
constexpr const char* NAV_DATA = "4d475743-0101-4e41-5649-474154494f4e";
constexpr const char* WIND_DATA = "4d475743-0201-4e41-5649-474154494f4e";
constexpr const char* AUTOPILOT_DATA = "4d475743-0301-4e41-5649-474154494f4e";
constexpr const char* AUTOPILOT_CMD = "4d475743-0302-4e41-5649-474154494f4e";
constexpr const char* PERF_DATA = "4d475743-0401-4e41-5649-474154494f4e";
constexpr const char* ADMIN_DATA = "4d475743-0501-4e41-5649-474154494f4e";
constexpr const char* ADMIN_CMD = "4d475743-0502-4e41-5649-474154494f4e";
}
// =============================================================================
// BLE runtime parameters
// =============================================================================
namespace BleConfig {
constexpr const char* DEVICE_NAME = BLE_DEVICE_NAME;
// Optional fixed BLE address ("aa:bb:cc:dd:ee:ff"). Keep empty to disable.
constexpr const char* TARGET_ADDR = "";
// Fallback name fragment (case-insensitive) for peripherals that do not
// expose the full local name in every advertisement packet.
constexpr const char* NAME_FALLBACK = "MarineGateway";
// Some firmwares expose only a 16-bit service UUID in advertising payload.
// 0xFE9F observed in field logs.
constexpr uint16_t FALLBACK_SVC16 = 0xFE9F;
constexpr uint32_t DEFAULT_PASSKEY = 123456; ///< default pairing PIN used if UI has not overridden it
constexpr uint32_t SCAN_DURATION = 10000; ///< scan window in milliseconds
constexpr uint32_t RECONNECT_MS = 5000; ///< delay before reconnect attempt
constexpr uint32_t STALE_TIMEOUT = 15; ///< seconds before data is marked stale
}
// =============================================================================
// Display layout
// 400×300 px divided into a 2×2 grid → 4 tiles
// =============================================================================
namespace Display {
constexpr uint16_t WIDTH = 400;
constexpr uint16_t HEIGHT = 300;
constexpr uint8_t TILE_COLS = 2;
constexpr uint8_t TILE_ROWS = 2;
constexpr uint8_t TILE_COUNT = TILE_COLS * TILE_ROWS;
constexpr uint16_t TILE_W = WIDTH / TILE_COLS; // 200 px
constexpr uint16_t TILE_H = HEIGHT / TILE_ROWS; // 150 px
constexpr uint8_t BORDER_PX = 2; ///< separator line width
constexpr uint8_t LABEL_H = 22; ///< px reserved for the tile label
constexpr uint32_t FULL_REFRESH_INTERVAL_MS = 300000; ///< forced full refresh every 5 min
}
// =============================================================================
// Available data fields that can be assigned to a tile
// =============================================================================
enum class DataField : uint8_t {
NONE = 0,
// Navigation
LAT, ///< GPS Latitude
LON, ///< GPS Longitude
SOG, ///< Speed Over Ground (kn)
COG, ///< Course Over Ground (°)
STW, ///< Speed Through Water (kn)
HDG_MAG, ///< Magnetic Heading (°)
DEPTH, ///< Depth (m)
// Wind
AWS, ///< Apparent Wind Speed (kn)
AWA, ///< Apparent Wind Angle (°)
TWS, ///< True Wind Speed (kn)
TWA, ///< True Wind Angle (°)
TWD, ///< True Wind Direction (°)
// Autopilot
AP_MODE, ///< Autopilot mode string
AP_TARGET, ///< Autopilot target heading (°)
AP_RUDDER, ///< Rudder angle (°)
// Performance
VMG, ///< Velocity Made Good (kn)
POLAR_PCT, ///< Polar efficiency (%)
TARGET_STW, ///< Polar target speed (kn)
// Admin / System
UPTIME, ///< Device uptime (s)
WIFI_MODE, ///< WiFi mode string
FREE_HEAP, ///< Free heap (bytes)
_COUNT ///< Sentinel — keep last
};
// =============================================================================
// Tile configuration (persisted in NVS / LittleFS)
// =============================================================================
struct TileConfig {
DataField field = DataField::NONE;
char label[16] = ""; ///< User-defined label override (empty = auto)
};
// =============================================================================
// Page: a set of 4 tiles
// =============================================================================
constexpr uint8_t MAX_PAGES = 8;
struct PageConfig {
char name[24] = "";
TileConfig tiles[Display::TILE_COUNT];
};
// =============================================================================
// Application-wide configuration (serialised to LittleFS as JSON)
// =============================================================================
struct AppConfig {
uint8_t pageCount = 1;
uint8_t activePage = 0;
PageConfig pages[MAX_PAGES];
// WiFi AP credentials (used when the display itself opens an AP)
char apSSID[32] = "MarineDisplay";
char apPassword[32] = "marine123";
};
// =============================================================================
// Live data snapshot — filled by BleManager, read by DisplayManager
// =============================================================================
struct NavData {
float lat = NAN;
float lon = NAN;
float sog = NAN;
float cog = NAN;
float stw = NAN;
float hdgMag = NAN;
float depth = NAN;
uint32_t updatedAt = 0; ///< millis() of last valid update
};
struct WindData {
float aws = NAN;
float awa = NAN;
float tws = NAN;
float twa = NAN;
float twd = NAN;
uint32_t updatedAt = 0;
};
struct AutopilotData {
char mode[16] = "";
char status[16] = "";
float headingTarget = NAN;
float windTarget = NAN;
float rudder = NAN;
float lockedHeading = NAN;
uint32_t updatedAt = 0;
};
struct PerfData {
float vmg = NAN;
float polarPct = NAN;
float targetStw = NAN;
bool polarLoaded = false;
uint32_t updatedAt = 0;
};
struct AdminData {
uint32_t uptimeS = 0;
uint64_t datetimeUtc = 0;
char wifiMode[8] = "";
char wifiSSID[33] = "";
char ip[16] = "";
uint32_t freeHeap = 0;
uint32_t updatedAt = 0;
};
/**
* @brief Aggregated snapshot of all BLE-received data.
* Access must be guarded by the SemaphoreHandle in AppState.
*/
struct BoatState {
NavData nav;
WindData wind;
AutopilotData autopilot;
PerfData perf;
AdminData admin;
};
// =============================================================================
// Application state — shared between all modules (extern in AppState.cpp)
// =============================================================================
namespace AppState {
enum class BleStatus : uint8_t {
IDLE,
SCANNING,
CONNECTING,
CONNECTED,
DISCONNECTED,
ERROR
};
enum class WifiStatus : uint8_t {
OFF,
AP_ACTIVE,
STA_CONNECTING,
STA_CONNECTED
};
}
// =============================================================================
// NeoPixel LED colour palette for status indication
// =============================================================================
namespace LedColor {
constexpr uint32_t OFF = 0x000000;
constexpr uint32_t BLE_SCANNING = 0x0000FF; ///< Blue pulsing
constexpr uint32_t BLE_CONNECTED= 0x00FF00; ///< Solid green
constexpr uint32_t BLE_ERROR = 0xFF0000; ///< Red
constexpr uint32_t WIFI_AP = 0xFF8800; ///< Amber
constexpr uint32_t WIFI_STA = 0x00FFFF; ///< Cyan
constexpr uint32_t OTA = 0xFF00FF; ///< Magenta pulsing
}
// =============================================================================
// Utility: readable name for a DataField
// =============================================================================
inline const char* fieldName(DataField f) {
switch (f) {
case DataField::LAT: return "Latitude";
case DataField::LON: return "Longitude";
case DataField::SOG: return "SOG";
case DataField::COG: return "COG";
case DataField::STW: return "STW";
case DataField::HDG_MAG: return "Heading";
case DataField::DEPTH: return "Depth";
case DataField::AWS: return "AWS";
case DataField::AWA: return "AWA";
case DataField::TWS: return "TWS";
case DataField::TWA: return "TWA";
case DataField::TWD: return "TWD";
case DataField::AP_MODE: return "AP Mode";
case DataField::AP_TARGET: return "AP Target";
case DataField::AP_RUDDER: return "Rudder";
case DataField::VMG: return "VMG";
case DataField::POLAR_PCT: return "Polar %";
case DataField::TARGET_STW:return "Tgt STW";
case DataField::UPTIME: return "Uptime";
case DataField::WIFI_MODE: return "WiFi Mode";
case DataField::FREE_HEAP: return "Free Heap";
default: return "---";
}
}
inline const char* fieldUnit(DataField f) {
switch (f) {
case DataField::LAT:
case DataField::LON:
case DataField::COG:
case DataField::HDG_MAG:
case DataField::TWD:
case DataField::AP_TARGET:
case DataField::AP_RUDDER:
case DataField::AWA:
case DataField::TWA: return "°";
case DataField::SOG:
case DataField::STW:
case DataField::AWS:
case DataField::TWS:
case DataField::VMG:
case DataField::TARGET_STW:return "kn";
case DataField::DEPTH: return "m";
case DataField::POLAR_PCT: return "%";
case DataField::UPTIME: return "s";
case DataField::FREE_HEAP: return "B";
default: return "";
}
}