Fit RAK4631 Full OTA image by reusing regulator recovery code

This commit is contained in:
mikecarper committed 2026-10-18 23:48:07 -07:00
1 parent e8d1e537e4
commit f7b5c40c3b
5 files changed
+32 -16

No files matched your search

+2 -2
View File
@@ -19,7 +19,7 @@ jobs:
- name: Qualify RAK4631 Full Companion with linked Meshtext support
run: >-
bash build.sh build-firmware RAK_4631_companion_radio_full
--firmware-version v1.17.1.10-halo-keymind-cascade-dev
--firmware-version v1.18.0.1-halo-keymind-cascade-dev
--radio-preset usa-cascade-fixed --profile cascade --require-ota
- name: Verify linked Companion crypto, retained Reader and ARM stack use
@@ -33,7 +33,7 @@ jobs:
# This configuration has no Meshtext/Ethernet application callbacks.
run: >-
bash build.sh build-firmware Xiao_nrf52_companion_radio_full
--firmware-version v1.17.1.10-halo-keymind-cascade-dev
--firmware-version v1.18.0.1-halo-keymind-cascade-dev
--radio-preset usa-cascade-fixed --profile cascade --require-ota
- name: Qualify unified T114 Full Companion with automatic screen detection
+6 -8
View File
@@ -2,6 +2,7 @@
#include <stddef.h>
#include <stdint.h>
#include "PersistentStoreFormat.h"
namespace mesh { namespace power {
@@ -143,14 +144,11 @@ class RecoveryPolicy {
static uint32_t elapsed(uint32_t now, uint32_t then) { return now - then; }
static uint32_t checksum(const RecoveryRecord& record) {
uint32_t crc = 0xffffffff;
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&record);
for (size_t i = 0; i < offsetof(RecoveryRecord, crc); ++i) {
crc ^= bytes[i];
for (uint8_t bit = 0; bit < 8; ++bit)
crc = (crc >> 1) ^ (0xedb88320u & (0u - (crc & 1u)));
}
return ~crc;
// Retained records use the same IEEE polynomial as persistent storage,
// with a final complement. Reuse its already-linked implementation while
// preserving the record layout and checksum across firmware updates.
return ~storage::updateCRC32(0xffffffffUL,
reinterpret_cast<const uint8_t*>(&record), offsetof(RecoveryRecord, crc));
}
static bool isValid(const RecoveryRecord& record) {
+4 -6
View File
@@ -300,12 +300,10 @@ bool handleRegulatorCommand(const char* command, char* reply, size_t capacity) {
}
void markRegulatorCleanReset() {
if (initialized) recovery().markCleanReset();
else {
RecoveryPolicy policy(platformRecoveryRecord());
policy.begin(ResetKind::Intentional, 0);
policy.markCleanReset();
}
// Early resets still initialize the retained record, using the same policy
// object as normal startup instead of constructing another on the stack.
if (!initialized) recovery().begin(ResetKind::Intentional, 0);
recovery().markCleanReset();
}
void resumeRegulatorRecovery() {
+1
View File
@@ -25,6 +25,7 @@ class CompanionOtaIncludeTest(unittest.TestCase):
with tempfile.TemporaryDirectory(prefix="meshcore-companion-includes-") as temp:
directory = Path(temp)
for header in (
"helpers/RegulatorSettings.h",
"helpers/ui/StartupScreen.h", "helpers/ui/DisplayPowerSettings.h",
"helpers/UsbLoggingWatchdog.h", "helpers/UsbLoggingClientActivity.h",
"Mesh.h", "helpers/BluetoothMac.h", "CompanionBluetooth.h",
+19
View File
@@ -212,6 +212,24 @@ int main(int argc, char** argv) {
// A sample apparently newer than the last heartbeat is conservative until
// that heartbeat catches up; subtraction cannot turn it into a fresh age.
{ RecoveryPolicy p(r); p.begin(ResetKind::Crash, 0); assertCounts(p, 0, 0); }
} else if (scenario == 16) {
// Frozen retained record with two MCU crashes and one radio crash. Its CRC
// and the fresh-record CRC below were independently calculated by zlib.
const uint8_t legacy[] = {
0x52, 0x47, 0x50, 0x52, 0x01, 0x00, 0x20, 0x00,
0xbc, 0xcc, 0x5b, 0x07, 0x15, 0xcd, 0x5b, 0x07,
0x0c, 0xcd, 0x5b, 0x07, 0x03, 0x00, 0x02, 0x01,
0x4b, 0x05, 0x00, 0x00, 0x6b, 0x64, 0x72, 0xa2,
};
static_assert(sizeof(legacy) == sizeof(r), "frozen retained format");
std::memcpy(&r, legacy, sizeof(r));
{ RecoveryPolicy p(r); p.begin(ResetKind::Crash, 0);
assertCounts(p, 3, 2, RECOVERY_MCU); }
// Losing the final complement, seed or payload extent must fail this
// compatibility check even if newly written records remain self-consistent.
std::memset(&r, 0, sizeof(r));
initial(r, RECOVERY_DOMAINS, 75, true, 123456789);
assert(r.crc == 0x1d384636u);
} else assert(false);
std::cout << "PASS: regulator recovery " << scenario << '\n';
}
@@ -256,6 +274,7 @@ class RegulatorRecoveryTests(unittest.TestCase):
"a boot is disarmed until the actual modes are selected",
"saved and retained fallback masks merge",
"future sample is ineligible until heartbeat catches up",
"retained CRC remains compatible with independently encoded records",
)
for number, scenario in enumerate(scenarios):
with self.subTest(scenario=scenario):