Compare Sensor subscription deltas in exact LPP units

This commit is contained in:
mikecarper committed 2026-10-16 05:03:22 -07:00
1 parent 56a2918f9f
commit 277f6d174b
3 files changed
+183 -5

No files matched your search

@@ -323,6 +323,133 @@ static void snapshot_checks() {
}
std::cout << "Raw LPP snapshot samples checked: " << samples << '\n';
}
static void store_raw(uint8_t* data, uint8_t size, int64_t value) {
uint64_t raw = uint64_t(value);
for (unsigned i = size; i > 0; --i) {
data[i - 1] = uint8_t(raw);
raw >>= 8;
}
}
static void expect_delta(uint8_t type, int64_t previous, int64_t current,
int64_t threshold, bool expected) {
SensorMesh target;
ClientInfo client;
const uint8_t size = LPPData::getDataSize(type);
assert(subscribe(target, client, type, size) == 12);
store_raw(client.extra.sensor.min_deltas + 2, size, threshold);
target.telemetry.bytes.resize(2 + size);
target.telemetry.bytes[0] = 1;
target.telemetry.bytes[1] = type;
store_raw(target.telemetry.getBuffer() + 2, size, previous);
target.snapshotTelemetry(&client);
const auto baseline = target.telemetry.bytes;
store_raw(target.telemetry.getBuffer() + 2, size, current);
for (unsigned repeat = 0; repeat < 2; ++repeat) {
assert(target.telemHasChanged(&client) == expected
&& "raw LPP delta must use the exact strict threshold");
assert(!memcmp(client.extra.sensor.prev_telem, baseline.data(), baseline.size()));
}
}
static void delta_checks() {
for (unsigned type = 0; type < 256; ++type) {
if (!LPPData::isScalarType(type)) continue;
// Equal, smaller, and larger positive thresholds in both directions.
for (int64_t step : {0, 1, 2, 3}) {
expect_delta(type, 10, 10 + step, 2, step > 2);
expect_delta(type, 10 + step, 10, 2, step > 2);
expect_delta(type, 10, 10 + step, 0, step != 0);
}
const uint8_t size = LPPData::getDataSize(type);
if (LPPData::isSigned(type)) {
const int64_t minimum = -(int64_t(1) << (8 * size - 1));
const int64_t maximum = -minimum - 1;
expect_delta(type, minimum, maximum, maximum, true);
expect_delta(type, maximum, minimum, maximum, true);
expect_delta(type, minimum, minimum + 1, 1, false);
expect_delta(type, -2, 1, 3, false);
expect_delta(type, 1, -2, 2, true);
// Negative signed thresholds retain their existing always-trigger behavior.
expect_delta(type, -2, -2, -1, true);
expect_delta(type, 0, 0, minimum, true);
}
SensorMesh target;
ClientInfo client;
assert(subscribe(target, client, type, size) == 12);
target.telemetry.bytes.resize(2 + size);
target.telemetry.bytes[0] = 1;
target.telemetry.bytes[1] = type;
store_raw(target.telemetry.getBuffer() + 2, size, 10);
target.snapshotTelemetry(&client);
store_raw(client.extra.sensor.min_deltas + 2, size, 10);
const auto complete = target.telemetry.bytes;
// Each truncated current record continues to use the zero default.
for (unsigned length = 0; length < complete.size(); ++length) {
target.telemetry.bytes.assign(complete.begin(), complete.begin() + length);
assert(!target.telemHasChanged(&client));
store_raw(client.extra.sensor.min_deltas + 2, size, 9);
assert(target.telemHasChanged(&client));
store_raw(client.extra.sensor.min_deltas + 2, size, 10);
}
target.telemetry.bytes = complete;
store_raw(client.extra.sensor.min_deltas + 2, size, -1);
client.extra.sensor.min_deltas_len = 1 + size;
assert(!target.telemHasChanged(&client)); // Truncated thresholds stay rejected.
}
// Ordinary scaled readings emitted exactly by the production scalar writer.
const struct { uint8_t type; int64_t previous, current; } ordinary[] = {
{LPP_CURRENT, 1234, 1235}, {LPP_TEMPERATURE, 201, 202}
};
for (const auto& entry : ordinary) {
const uint32_t multiplier = LPPData::getMultiplier(entry.type);
for (int64_t raw : {entry.previous, entry.current}) {
uint8_t bytes[4] = {};
LPPWriter writer(bytes, sizeof(bytes));
assert(writer.writeData(1, entry.type, float(raw) / multiplier));
assert((uint32_t(bytes[2]) * 256 + bytes[3]) == raw);
}
expect_delta(entry.type, entry.previous, entry.current, 1, false);
expect_delta(entry.type, entry.previous, entry.current + 1, 1, true);
}
}
static void wide_delta_checks() {
for (uint8_t type : {LPP_GENERIC_SENSOR, LPP_FREQUENCY, LPP_DISTANCE, LPP_ENERGY, LPP_UNIXTIME}) {
assert(LPPData::getDataSize(type) == 4 && !LPPData::isSigned(type));
for (uint32_t raw : {0x1000000U, 0x7fffffffU, 1700000000U, 0xfffffffeU}) {
expect_delta(type, raw, uint64_t(raw) + 1, 0, true);
expect_delta(type, uint64_t(raw) + 1, raw, 0, true);
expect_delta(type, raw, uint64_t(raw) + 1, 1, false);
}
expect_delta(type, 16777219, 16777221, 1, true);
expect_delta(type, 16777221, 16777219, 1, true);
expect_delta(type, 0, UINT32_MAX, UINT32_MAX, false);
expect_delta(type, UINT32_MAX, 0, UINT32_MAX - 1, true);
expect_delta(type, UINT32_MAX, 1, UINT32_MAX - 1, false);
}
// Decoder sign extension covers every scalar width, including signed32.
for (uint8_t size = 1; size <= 4; ++size) {
const int64_t sign_bit = int64_t(1) << (8 * size - 1);
for (int64_t value : {-sign_bit, -sign_bit + 1, int64_t(-1), int64_t(0), sign_bit - 1}) {
uint8_t bytes[4] = {};
store_raw(bytes, size, value);
assert(readTelemRawValue(bytes, size, true) == value);
}
}
assert(readTelemRawValue(nullptr, 4, false) == 0);
uint8_t bytes[5] = {};
assert(readTelemRawValue(bytes, 0, false) == 0);
assert(readTelemRawValue(bytes, 5, false) == 0);
}
static void signed_wide_delta_checks() {
// The runner supplies signed metadata for this normally unsigned scalar.
const uint8_t type = LPP_GENERIC_SENSOR;
assert(LPPData::getDataSize(type) == 4 && LPPData::isSigned(type));
expect_delta(type, INT32_MIN, INT32_MAX, INT32_MAX, true);
expect_delta(type, INT32_MAX, INT32_MIN, INT32_MAX, true);
expect_delta(type, INT32_MIN, INT32_MIN + 1, 0, true);
expect_delta(type, INT32_MAX - 1, INT32_MAX, 1, false);
expect_delta(type, -16777217, -16777216, 0, true);
expect_delta(type, 0, 0, INT32_MIN, true);
}
static void writer_checks() {
uint8_t buffer[16];
memset(buffer, 0xAA, sizeof(buffer));
@@ -432,6 +559,9 @@ int main(int argc, char** argv) {
else if (!strcmp(argv[1], "writer")) writer_checks();
else if (!strcmp(argv[1], "tracker")) tracker_mode_checks();
else if (!strcmp(argv[1], "snapshot")) snapshot_checks();
else if (!strcmp(argv[1], "delta")) delta_checks();
else if (!strcmp(argv[1], "wide-delta")) wide_delta_checks();
else if (!strcmp(argv[1], "signed-wide-delta")) signed_wide_delta_checks();
else assert(false);
std::cout << "Sensor subscription checks passed\n";
}