Add SenseCAP Indicator N16R2 profile

This commit is contained in:
mikecarper
2026-08-31 18:29:38 -07:00
parent 6a52d132b7
commit 8f413b0610
9 changed files with 108 additions and 9 deletions
+15 -2
View File
@@ -480,6 +480,7 @@ for section, options in data:
'Heltec_T190_companion_radio_usb_ble_|Heltec_T190_companion_radio_full_'
'SenseCapIndicator-ESPNow_comp_radio_usb|SenseCapIndicator-ESPNow_companion_radio_full'
'SenseCapIndicator-LoRa_comp_radio_usb_wifi|SenseCapIndicator-LoRa_companion_radio_full'
'SenseCapIndicator-LoRa-N16R2_comp_radio_usb_wifi|SenseCapIndicator-LoRa-N16R2_companion_radio_full'
)
local -a qualified_nrf52_full_companion_bases=(
GAT562_Mesh_Watch13_companion_radio_ble
@@ -3420,6 +3421,13 @@ apply_companion_radio_full_profile() {
# than to whichever historical USB/WiFi environment supplies the recipe.
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DINDICATOR_WIFI_FONT_RECOVERY=1"
;;
sensecapindicator-lora-n16r2_companion_radio_full)
export MESHCORE_ESP32_FULL_PARTITION_TABLE="variants/sensecap_indicator-espnow/dual_ota_6400k_preserve_spiffs.csv"
# Both physical Indicator radio layouts gain ordinary WiFi in their Full
# overlay. Keep font recovery tied to that effective capability rather
# than to whichever historical USB/WiFi environment supplies the recipe.
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DINDICATOR_WIFI_FONT_RECOVERY=1"
;;
esac
# Both Indicator Full layouts select exactly one secondary Companion
@@ -3428,7 +3436,8 @@ apply_companion_radio_full_profile() {
# mode can release Bluetooth memory without disturbing ESP-NOW.
case "${env_name,,}" in
sensecapindicator-espnow_companion_radio_full|\
sensecapindicator-lora_companion_radio_full)
sensecapindicator-lora_companion_radio_full|\
sensecapindicator-lora-n16r2_companion_radio_full)
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DCOMPANION_EXCLUSIVE_WIFI_BLE=1 -DINDICATOR_TRANSPORT_RENDER_PROFILE=1 -DUI_WIFI_SETUP_HOME_PAGE=1 -DWEBCONFIG_AP_PREFIX='\"MC-Set\"'"
;;
esac
@@ -3438,7 +3447,8 @@ apply_companion_radio_full_profile() {
# every other combination retains native 480x480 rendering.
case "${env_name,,}" in
sensecapindicator-espnow_companion_radio_full|\
sensecapindicator-lora_companion_radio_full)
sensecapindicator-lora_companion_radio_full|\
sensecapindicator-lora-n16r2_companion_radio_full)
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -UUI_ZOOM -DUI_ZOOM=1.0f -UUI_COORD_SCALE -DUI_COORD_SCALE=3"
;;
esac
@@ -4166,6 +4176,9 @@ get_esp32_full_companion_replacement() {
sensecapindicator-espnow_comp_radio_*)
full_env=SenseCapIndicator-ESPNow_companion_radio_full
;;
sensecapindicator-lora-n16r2_comp_radio_*)
full_env=SenseCapIndicator-LoRa-N16R2_companion_radio_full
;;
sensecapindicator-lora_comp_radio_*)
full_env=SenseCapIndicator-LoRa_companion_radio_full
;;
+1
View File
@@ -9,6 +9,7 @@ import os
# board's persistent data.
PRESERVED_FULL_PARTITION_TABLES = {
"variants/sensecap_indicator-espnow/dual_ota_2560k_preserve_spiffs.csv",
"variants/sensecap_indicator-espnow/dual_ota_6400k_preserve_spiffs.csv",
}
+8
View File
@@ -339,6 +339,7 @@ Heltec_E290_companion_usb_ble|Heltec_E290_companion_radio_full|Heltec_E290_compa
Heltec_T190_companion_radio_usb_ble_|Heltec_T190_companion_radio_full_|Heltec_T190_companion_radio_usb_ble_
SenseCapIndicator-ESPNow_comp_radio_usb|SenseCapIndicator-ESPNow_companion_radio_full|SenseCapIndicator-ESPNow_comp_radio_usb
SenseCapIndicator-LoRa_comp_radio_usb_wifi|SenseCapIndicator-LoRa_companion_radio_full|SenseCapIndicator-LoRa_comp_radio_usb_wifi
SenseCapIndicator-LoRa-N16R2_comp_radio_usb_wifi|SenseCapIndicator-LoRa-N16R2_companion_radio_full|SenseCapIndicator-LoRa-N16R2_comp_radio_usb_wifi
FULL_COMPANION_SPECS
# The Full overlay, not the historical transport used as its build base, owns
@@ -378,6 +379,13 @@ for full_env in "${SUPPORTED_PIO_ENVS[@]}"; do
[[ "$PLATFORMIO_BUILD_FLAGS" == *"INDICATOR_WIFI_FONT_RECOVERY=1"* ]] \
|| fail "$full_env omitted WiFi font recovery"
;;
sensecapindicator-lora-n16r2_companion_radio_full)
[ "${MESHCORE_ESP32_FULL_PARTITION_TABLE:-}" \
= "variants/sensecap_indicator-espnow/dual_ota_6400k_preserve_spiffs.csv" ] \
|| fail "$full_env omitted the N16R2 preserve-SPIFFS table"
[[ "$PLATFORMIO_BUILD_FLAGS" == *"INDICATOR_WIFI_FONT_RECOVERY=1"* ]] \
|| fail "$full_env omitted WiFi font recovery"
;;
*)
[ -z "${MESHCORE_ESP32_FULL_PARTITION_TABLE:-}" ] \
|| fail "$full_env inherited another board's required partition table"
+25
View File
@@ -18,6 +18,10 @@ INDICATOR_PARTITIONS = (
"variants/sensecap_indicator-espnow/"
"dual_ota_2560k_preserve_spiffs.csv"
)
INDICATOR_N16R2_PARTITIONS = (
"variants/sensecap_indicator-espnow/"
"dual_ota_6400k_preserve_spiffs.csv"
)
class FakeBoardConfig:
@@ -90,6 +94,27 @@ class Esp32FullPartitionTest(unittest.TestCase):
self.assertEqual(board.values["build.flash_mode"], "dio")
self.assertIn(INDICATOR_PARTITIONS, output)
def test_n16r2_retains_factory_six_megabyte_ota_slots(self):
profile = INDICATOR_PROFILE.read_text()
self.assertIn(
f"board_build.partitions = {INDICATOR_N16R2_PARTITIONS}", profile
)
table = (ROOT / INDICATOR_N16R2_PARTITIONS).read_text()
self.assertIn("app0, app, ota_0, 0x10000, 0x640000", table)
self.assertIn("app1, app, ota_1, 0x650000, 0x640000", table)
self.assertIn("spiffs, data, spiffs, 0xc90000, 0x360000", table)
board, output = apply_policy(
{
"upload.flash_size": "16MB",
"build.mcu": "esp32s3",
"build.partitions": INDICATOR_N16R2_PARTITIONS,
}
)
self.assertEqual(
board.values["build.partitions"], INDICATOR_N16R2_PARTITIONS
)
self.assertIn(INDICATOR_N16R2_PARTITIONS, output)
def test_absolute_indicator_partition_path_is_also_preserved(self):
absolute = str(ROOT / INDICATOR_PARTITIONS)
board, _output = apply_policy(
+18
View File
@@ -36,6 +36,24 @@ def numeric_flag(name: str) -> float:
class IndicatorDisplayProfileTest(unittest.TestCase):
def test_preserves_original_indicator_memory_profile(self):
profile = base_profile()
self.assertIn("board_build.arduino.memory_type = qio_opi", profile)
self.assertIn("board_build.psram_type = opi", profile)
self.assertIn("board_upload.flash_size = 8MB", profile)
def test_n16r2_profile_uses_quad_psram_and_full_flash(self):
profile = PROFILE.read_text()
start = profile.index(
"[env:SenseCapIndicator-LoRa-N16R2_comp_radio_usb_wifi]"
)
n16r2 = profile[start:]
self.assertIn("board_build.arduino.memory_type = qio_qspi", n16r2)
self.assertIn("board_build.psram_type = qspi", n16r2)
self.assertIn("board_upload.flash_size = 16MB", n16r2)
self.assertIn("board_upload.maximum_size = 16777216", n16r2)
self.assertIn("dual_ota_6400k_preserve_spiffs.csv", n16r2)
def test_preserves_logical_ui_and_fills_panel(self):
panel_size = 480
zoom = numeric_flag("UI_ZOOM")
+5
View File
@@ -318,6 +318,11 @@ printf '%s\n' "$PLATFORMIO_BUILD_FLAGS"
"SenseCapIndicator-LoRa_companion_radio_full'",
build,
)
self.assertIn(
"'SenseCapIndicator-LoRa-N16R2_comp_radio_usb_wifi|"
"SenseCapIndicator-LoRa-N16R2_companion_radio_full'",
build,
)
if __name__ == "__main__":
+14 -7
View File
@@ -178,10 +178,17 @@ agreeing sources from signed adverts or authenticated Public-channel messages;
one repeated sender cannot set the clock alone. A successful Companion or
local CLI time update always wins and disables the LoRa fallback until reboot.
The combined image uses two 2.5 MiB OTA application slots. Its partition map
keeps the prior NVS and SPIFFS addresses, so installing the partition table and
application over an existing Indicator preserves identity, channels, radio
settings, and saved WiFi credentials.
The original combined image uses two 2.5 MiB OTA application slots. Its
partition map keeps the prior NVS and SPIFFS addresses, so installing the
partition table and application over an existing Indicator preserves identity,
channels, radio settings, and saved WiFi credentials.
Some later LoRa units, including Mercer, report an ESP32-S3-WROOM-1-N16R2:
16 MiB flash with 2 MiB quad PSRAM. Use
`SenseCapIndicator-LoRa-N16R2_companion_radio_full` for those boards. Its
factory-compatible map provides two 6.25 MiB OTA slots while retaining the
NVS, SPIFFS, and coredump offsets. Do not install this image on the original
8 MiB/octal-PSRAM Indicator; PSRAM line mode cannot be runtime-detected.
## SD-backed font
@@ -194,9 +201,9 @@ per second. See
[`../../tools/sensecap_indicator_rp2040/README.md`](../../tools/sensecap_indicator_rp2040/README.md)
for installation and diagnostics.
Both Full Companion layouts, `SenseCapIndicator-LoRa_companion_radio_full` and
`SenseCapIndicator-ESPNow_companion_radio_full`, can repair a missing, corrupt,
or older font after station WiFi connects. The LoRa USB/WiFi base profile has
All Indicator Full Companion layouts, including the N16R2 variant, can repair
a missing, corrupt, or older font after station WiFi connects. The LoRa
USB/WiFi base profile has
the same recovery support; USB-only images omit it. Startup never waits for the
network: the UI uses its built-in font while a bounded background task fetches
the 1,302,608-byte asset from GitHub's official, content-addressed Git Blob REST
@@ -0,0 +1,9 @@
# Factory-compatible 16 MiB SenseCAP Indicator layout.
# Keep every offset stable across application and merged-image updates.
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x640000,
app1, app, ota_1, 0x650000, 0x640000,
spiffs, data, spiffs, 0xc90000, 0x360000,
coredump, data, coredump,0xff0000, 0x10000,
1 # Factory-compatible 16 MiB SenseCAP Indicator layout.
2 # Keep every offset stable across application and merged-image updates.
3 # Name, Type, SubType, Offset, Size, Flags
4 nvs, data, nvs, 0x9000, 0x5000,
5 otadata, data, ota, 0xe000, 0x2000,
6 app0, app, ota_0, 0x10000, 0x640000,
7 app1, app, ota_1, 0x650000, 0x640000,
8 spiffs, data, spiffs, 0xc90000, 0x360000,
9 coredump, data, coredump,0xff0000, 0x10000,
@@ -169,3 +169,16 @@ build_src_filter =
+<helpers/esp32/*.cpp>
lib_deps =
${env:SenseCapIndicator-LoRa_comp_radio_usb.lib_deps}
; Later Indicator LoRa boards can carry an ESP32-S3-WROOM-1-N16R2 instead of
; the original 8 MiB flash / 8 MiB octal-PSRAM arrangement. Keep this as an
; explicit image: PSRAM line mode is selected before application startup and
; cannot be safely auto-detected by one binary.
[env:SenseCapIndicator-LoRa-N16R2_comp_radio_usb_wifi]
extends = env:SenseCapIndicator-LoRa_comp_radio_usb_wifi
board_build.arduino.memory_type = qio_qspi
board_build.flash_mode = qio
board_build.psram_type = qspi
board_upload.flash_size = 16MB
board_upload.maximum_size = 16777216
board_build.partitions = variants/sensecap_indicator-espnow/dual_ota_6400k_preserve_spiffs.csv