#include #include #include "loratap.h" using namespace roro::lora; void setUp() {} void tearDown() {} static uint32_t le32(const std::vector& b, size_t at) { return b[at] | b[at + 1] << 8 | b[at + 2] << 16 | (uint32_t)b[at + 3] << 24; } void test_pcap_global_header() { std::vector out; appendPcapHeader(out); TEST_ASSERT_EQUAL_size_t(24, out.size()); TEST_ASSERT_EQUAL_HEX32(0xA1B2C3D4, le32(out, 0)); // microsecond timestamps, little-endian file TEST_ASSERT_EQUAL_UINT8(2, out[4]); // version 2.4 TEST_ASSERT_EQUAL_UINT8(4, out[6]); TEST_ASSERT_EQUAL_UINT32(65535, le32(out, 16)); // snap length TEST_ASSERT_EQUAL_UINT32(270, le32(out, 20)); // LINKTYPE_LORATAP } void test_record_with_loratap_v0() { RxInfo rx; rx.frequencyHz = 869525000; rx.bandwidthKHz = 250; rx.spreadingFactor = 11; rx.rssi = -97.0f; rx.snr = 6.25f; rx.noiseFloor = -110.0f; rx.syncWord = 0x2B; const uint8_t payload[] = {1, 2, 3}; std::vector out; appendRecord(out, 1791230400u, 250000u, rx, payload, sizeof payload); TEST_ASSERT_EQUAL_size_t(16 + 15 + 3, out.size()); TEST_ASSERT_EQUAL_UINT32(1791230400u, le32(out, 0)); TEST_ASSERT_EQUAL_UINT32(250000u, le32(out, 4)); TEST_ASSERT_EQUAL_UINT32(18, le32(out, 8)); // captured: LoRaTap header + payload TEST_ASSERT_EQUAL_UINT32(18, le32(out, 12)); const uint8_t* t = out.data() + 16; // LoRaTap v0, big-endian TEST_ASSERT_EQUAL_UINT8(0, t[0]); // version TEST_ASSERT_EQUAL_UINT8(0, t[1]); // padding TEST_ASSERT_EQUAL_UINT16(15, t[2] << 8 | t[3]); TEST_ASSERT_EQUAL_UINT32(869525000u, (uint32_t)t[4] << 24 | t[5] << 16 | t[6] << 8 | t[7]); TEST_ASSERT_EQUAL_UINT8(2, t[8]); // bandwidth in 125 kHz steps TEST_ASSERT_EQUAL_UINT8(11, t[9]); TEST_ASSERT_EQUAL_UINT8(42, t[10]); // packet RSSI: -139 + 42 = -97 dBm (SNR >= 0) TEST_ASSERT_EQUAL_UINT8(42, t[11]); // max RSSI: the packet's TEST_ASSERT_EQUAL_UINT8(29, t[12]); // current RSSI: the noise floor, -139 + 29 = -110 dBm TEST_ASSERT_EQUAL_UINT8(25, t[13]); // SNR in quarter dB TEST_ASSERT_EQUAL_HEX8(0x2B, t[14]); TEST_ASSERT_EQUAL_UINT8(3, t[17]); } // Below 0 dB SNR the spec says quarter dB, but Wireshark (checked with tshark 4.2) reads plain dBm. void test_negative_snr() { RxInfo rx; rx.bandwidthKHz = 125; rx.rssi = -120.5f; rx.snr = -7.5f; std::vector out; appendRecord(out, 0, 0, rx, nullptr, 0); const uint8_t* t = out.data() + 16; TEST_ASSERT_EQUAL_UINT8(1, t[8]); TEST_ASSERT_EQUAL_UINT8(19, t[10]); // -139 + 19 = -120 dBm (rounded half away) TEST_ASSERT_EQUAL_INT8(-30, static_cast(t[13])); // -7.5 dB } void test_rssi_clamped() { RxInfo rx; rx.rssi = -150.0f; // below what LoRaTap can say rx.snr = 1.0f; rx.noiseFloor = 20.0f; std::vector out; appendRecord(out, 0, 0, rx, nullptr, 0); TEST_ASSERT_EQUAL_UINT8(0, out[16 + 10]); TEST_ASSERT_EQUAL_UINT8(159, out[16 + 12]); } void test_capture_path() { TEST_ASSERT_EQUAL_STRING("/captures/lora/20261005-200000.pcap", capturePath(1791230400).c_str()); } int main() { UNITY_BEGIN(); RUN_TEST(test_pcap_global_header); RUN_TEST(test_record_with_loratap_v0); RUN_TEST(test_negative_snr); RUN_TEST(test_rssi_clamped); RUN_TEST(test_capture_path); return UNITY_END(); }