mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-10-23 21:33:53 +00:00
Keep compact contacts within the STM32 flash boundary
This commit is contained in:
1 parent
036661e7e4
commit
025eadb39f
4 files changed
+66
-13
No files matched your search
@@ -34,26 +34,21 @@ inline uint32_t morseSettingsCRC(const uint8_t* data, size_t size) {
|
||||
inline void encodeMorseSettings(const MorseSettings& prefs,
|
||||
uint8_t (&image)[MorseSettingsImageSize]) {
|
||||
image[0] = 'M'; image[1] = 'C'; image[2] = 1; image[3] = prefs.wpm;
|
||||
for (unsigned i = 0; i < 4; ++i)
|
||||
image[4 + i] = uint8_t(prefs.frequency_khz >> (i * 8));
|
||||
storage::writeLE32(image + 4, prefs.frequency_khz);
|
||||
const uint32_t crc = morseSettingsCRC(image, 8);
|
||||
for (unsigned i = 0; i < 4; ++i) image[8 + i] = uint8_t(crc >> (i * 8));
|
||||
storage::writeLE32(image + 8, crc);
|
||||
}
|
||||
|
||||
inline bool decodeMorseSettings(const uint8_t* image, size_t size,
|
||||
MorseSettings& prefs) {
|
||||
if (!image || size != MorseSettingsImageSize || image[0] != 'M'
|
||||
|| image[1] != 'C' || image[2] != 1) return false;
|
||||
uint32_t frequency = 0, crc = 0;
|
||||
for (unsigned i = 0; i < 4; ++i) {
|
||||
frequency |= uint32_t(image[4 + i]) << (i * 8);
|
||||
crc |= uint32_t(image[8 + i]) << (i * 8);
|
||||
}
|
||||
const uint32_t crc = morseSettingsCRC(image, 8);
|
||||
if (crc != storage::readLE32(image + 8)) return false;
|
||||
MorseSettings candidate;
|
||||
candidate.frequency_khz = frequency;
|
||||
candidate.frequency_khz = storage::readLE32(image + 4);
|
||||
candidate.wpm = image[3];
|
||||
if (crc != morseSettingsCRC(image, 8) || !validMorseSettings(candidate))
|
||||
return false;
|
||||
if (!validMorseSettings(candidate)) return false;
|
||||
prefs = candidate;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -131,8 +131,8 @@ inline void writeLE32(uint8_t* dest, uint32_t value) {
|
||||
inline uint32_t updateCRC32(uint32_t crc, const uint8_t* data, size_t len) {
|
||||
while (len-- > 0) {
|
||||
crc ^= *data++;
|
||||
for (uint8_t bit = 0; bit < 8; bit++) {
|
||||
crc = (crc >> 1) ^ ((crc & 1) ? 0xEDB88320UL : 0);
|
||||
for (unsigned bit = 0; bit < 8; bit++) {
|
||||
crc = (crc >> 1) ^ (0xEDB88320UL & (0U - (crc & 1U)));
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
|
||||
@@ -11,6 +11,37 @@ ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
class MorseCLITests(unittest.TestCase):
|
||||
def test_settings_codec_matches_independent_images_and_unaligned_input(self):
|
||||
cases = []
|
||||
for frequency in (100000, 0x020304, 902321, 1000000):
|
||||
for speed in (1, 25, 60):
|
||||
prefix = b"MC\x01" + bytes([speed]) + frequency.to_bytes(4, "little")
|
||||
golden = prefix + (zlib.crc32(prefix) ^ 0xffffffff).to_bytes(4, "little")
|
||||
cases.append("{%d,%d,{%s}}" % (
|
||||
frequency, speed, ",".join(str(byte) for byte in golden)))
|
||||
code = r'''
|
||||
#include <helpers/MorseSettings.h>
|
||||
#include <cassert>
|
||||
struct Case { uint32_t frequency; uint8_t speed; uint8_t expected[12]; };
|
||||
int main() {
|
||||
const Case cases[] = {@CASES@};
|
||||
for (const auto& item : cases) {
|
||||
mesh::MorseSettings prefs;
|
||||
prefs.frequency_khz = item.frequency; prefs.wpm = item.speed;
|
||||
uint8_t encoded[mesh::MorseSettingsImageSize];
|
||||
mesh::encodeMorseSettings(prefs, encoded);
|
||||
assert(memcmp(encoded, item.expected, sizeof(encoded)) == 0);
|
||||
alignas(4) uint8_t unaligned[13];
|
||||
memcpy(unaligned + 1, item.expected, sizeof(item.expected));
|
||||
mesh::MorseSettings decoded;
|
||||
assert(mesh::decodeMorseSettings(unaligned + 1, sizeof(item.expected), decoded));
|
||||
assert(decoded.frequency_khz == item.frequency && decoded.wpm == item.speed);
|
||||
}
|
||||
}
|
||||
'''.replace("@CASES@", ",".join(cases))
|
||||
fs_mock = (ROOT / "test/fixtures/radio_profiles/mocks/helpers/IdentityStore.h").read_text(encoding="ascii")
|
||||
compile_run(self, code, headers={"helpers/IdentityStore.h": fs_mock})
|
||||
|
||||
def test_exact_shared_handler_strict_arguments_bounded_replies_and_rollback(self):
|
||||
code = (ROOT / "test/fixtures/morse_cli.cpp").read_text(encoding="ascii")
|
||||
fs_mock = (ROOT / "test/fixtures/radio_profiles/mocks/helpers/IdentityStore.h").read_text(encoding="ascii")
|
||||
|
||||
@@ -36,6 +36,33 @@ TEST(PersistentStoreFormat, CRCDetectsPayloadChanges) {
|
||||
EXPECT_EQ(split, expected);
|
||||
}
|
||||
|
||||
TEST(PersistentStoreFormat, CRCMatchesIndependentVectorsAndEverySplit) {
|
||||
EXPECT_EQ(updateCRC32(0xFFFFFFFFUL, nullptr, 0), 0xFFFFFFFFUL);
|
||||
EXPECT_EQ(updateCRC32(0x12345678UL, nullptr, 0), 0x12345678UL);
|
||||
const uint8_t check[] = "123456789";
|
||||
EXPECT_EQ(updateCRC32(0xFFFFFFFFUL, check, sizeof(check) - 1),
|
||||
0x340BC6D9UL);
|
||||
|
||||
uint8_t payload[256];
|
||||
for (unsigned i = 0; i < sizeof(payload); ++i) payload[i] = uint8_t(i);
|
||||
// Independent Python zlib vectors, converted to the store's no-final-xor
|
||||
// convention: zlib.crc32(payload, seed ^ 0xffffffff) ^ 0xffffffff.
|
||||
const struct { uint32_t seed, expected; } vectors[] = {
|
||||
{0xFFFFFFFFUL, 0xD6FA738CUL},
|
||||
{0x00000000UL, 0x2493092BUL},
|
||||
{0x12345678UL, 0x8906DCD5UL},
|
||||
};
|
||||
for (const auto& vector : vectors) {
|
||||
EXPECT_EQ(updateCRC32(vector.seed, payload, sizeof(payload)),
|
||||
vector.expected);
|
||||
for (size_t split = 0; split <= sizeof(payload); ++split) {
|
||||
uint32_t crc = updateCRC32(vector.seed, payload, split);
|
||||
crc = updateCRC32(crc, payload + split, sizeof(payload) - split);
|
||||
EXPECT_EQ(crc, vector.expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PersistentStoreFormat, OccupancyCanBeDerivedFromCrcProtectedRecords) {
|
||||
uint8_t empty[CONTACT_RECORD_SIZE] = {};
|
||||
EXPECT_FALSE(contactRecordHasData(empty));
|
||||
|
||||
Reference in new issue
Block a user