Unify RAK repeater storage firmware and bootloader handoff

This commit is contained in:
mikecarper committed 2026-09-25 10:35:04 -07:00
1 parent 7a8bddda53
commit fca10471c3
27 files changed
+723 -29

No files matched your search

+1
View File
@@ -221,6 +221,7 @@ class FirmwareCapabilityCheckerTest(unittest.TestCase):
for flags, storage, types in [(16, "internal_flash_and_retained_ram", ["in_place_delta"]),
(0, "internal_flash", ["in_place_delta"]),
(4, "external_qspi", ["full", "in_place_delta"]),
(48, "adaptive_internal_or_external_qspi", ["full", "in_place_delta"]),
(1, "external_sd", ["full", "in_place_delta"])]:
result, manifest = self.run_checker(
b"dfu invalid in-place patch geometry", "--platform", "NRF52_PLATFORM",
+27
View File
@@ -895,6 +895,33 @@ assert.strictEqual(
picker.humanizeVariant("rak13302-w25q16-lora-ota"),
"RAK13302 + External storage board (W25Q16) LoRa OTA"
);
const rakStorageTargets = [
"RAK_4631_repeater_unified_lora_ota",
"RAK_4631_repeater_lora_ota_no_external_sensors",
"RAK_4631_repeater_rak15001_slot_c_lora_ota",
"RAK_4631_repeater_w25q16_lora_ota",
"RAK_3401_repeater_unified_lora_ota",
"RAK_3401_repeater_lora_ota_no_external_sensors",
"RAK_3401_repeater_rak13302_w25q16_lora_ota",
];
const rakStorageAssets = rakStorageTargets.map(function (target) {
return asset(target + "-ota-" + family + ".uf2");
});
const rakUnifiedCatalog = picker.buildCatalog([
release(family, "2026-09-25T00:00:00Z", rakStorageAssets),
]);
assert.deepStrictEqual(
rakUnifiedCatalog.profiles.map(function (item) { return item.target; }).sort(),
["RAK_3401_repeater_unified_lora_ota", "RAK_4631_repeater_unified_lora_ota"].sort()
);
assert(rakUnifiedCatalog.profiles.every(function (item) {
return item.variant === "default" && item.ota === "lora-receiver";
}));
assert.strictEqual(rakUnifiedCatalog.rows.length, rakStorageTargets.length);
const rakLegacyCatalog = picker.buildCatalog([
release(family, "2026-09-25T00:00:00Z", rakStorageAssets.slice(1, 4).concat(rakStorageAssets.slice(5))),
]);
assert.strictEqual(rakLegacyCatalog.profiles.length, 5);
assert.strictEqual(picker.formatBytes(2097152), "2.00 MiB");
assert.strictEqual(
picker.parseFirmwareAsset(
+64
View File
@@ -0,0 +1,64 @@
"""Host regression for the RAK internal/QSPI store selection boundary."""
from pathlib import Path
import shutil
import subprocess
import tempfile
import unittest
ROOT = Path(__file__).resolve().parents[1]
class RakStoragePolicyTest(unittest.TestCase):
def test_exact_bootloader_and_nor_pairing(self):
compiler = shutil.which("c++")
if compiler is None:
self.skipTest("C++ compiler unavailable")
source = r'''
#include "src/helpers/ota/OtaRakStoragePolicy.h"
#include <assert.h>
using mesh::ota::RakStorageChoice;
using mesh::ota::rak_storage_choice;
int main() {
const auto I = RakStorageChoice::Internal;
const auto Q = RakStorageChoice::Qspi;
const auto U = RakStorageChoice::Unsafe;
for (bool rak3401 : {false, true}) {
assert(rak_storage_choice(0, false, false, nullptr, rak3401) == I);
assert(rak_storage_choice(0, true, false, nullptr, rak3401) == U);
assert(rak_storage_choice(0, true, true,
rak3401 ? "3401_AUTO_DFU" : "4631_AUTO_DFU", rak3401) == I);
assert(rak_storage_choice(2, false, false, nullptr, rak3401) == I);
assert(rak_storage_choice(3, false, false, nullptr, rak3401) == U);
assert(rak_storage_choice(3, true, true, "3401_W25Q16_DFU", rak3401) == U);
assert(rak_storage_choice(4, true, true, "3401_W25Q16_DFU", rak3401) == U);
assert(rak_storage_choice(2, true, false, nullptr, rak3401) == U);
assert(rak_storage_choice(2, true, true, "4631_15001C_DFU", rak3401) == U);
}
assert(rak_storage_choice(1, false, false, nullptr, false) == I);
assert(rak_storage_choice(1, true, true, "4631_15001C_DFU", false) == Q);
assert(rak_storage_choice(2, true, true, "4631_W25Q16_DFU", false) == Q);
assert(rak_storage_choice(1, true, true, "4631_AUTO_DFU", false) == Q);
assert(rak_storage_choice(2, true, true, "4631_AUTO_DFU", false) == Q);
assert(rak_storage_choice(2, true, true, "3401_AUTO_DFU", false) == U);
assert(rak_storage_choice(1, true, true, "4631_W25Q16_DFU", false) == U);
assert(rak_storage_choice(1, true, true, "4631_15001C_DFU", true) == U);
assert(rak_storage_choice(2, true, true, "3401_W25Q16_DFU", true) == Q);
assert(rak_storage_choice(2, true, true, "3401_AUTO_DFU", true) == Q);
assert(rak_storage_choice(1, true, true, "3401_AUTO_DFU", true) == U);
assert(rak_storage_choice(2, true, true, "4631_W25Q16_DFU", true) == U);
}
'''
source = '#include <initializer_list>\n' + source
with tempfile.TemporaryDirectory() as directory:
src = Path(directory) / "policy.cpp"
exe = Path(directory) / "policy"
src.write_text(source)
subprocess.run([compiler, "-std=c++11", "-Wall", "-Wextra", "-Werror",
"-I", str(ROOT), str(src), "-o", str(exe)], check=True)
subprocess.run([str(exe)], check=True)
if __name__ == "__main__":
unittest.main()