Complete IoT monitoring platform for Acuvim II power meters via ESP32. Firmware (Phases 1-7): - ESP32-WROVER-B (TTGO T-Call v1.4) with RS485 Modbus RTU - WiFi STA+AP concurrent mode with GSM/GPRS failover - Transport abstraction layer with 4 priority modes - MQTT protocol with 20 commands, LWT, QoS, exponential backoff - SD card offline buffering with JSONL rotation and non-blocking drain - OTA firmware updates with dual partition rollback protection - Watchdog timer, crash loop detection, Acuvim health monitoring - Captive portal provisioning with AP mode Console backend (Phase 8): - .NET 10 minimal API with PostgreSQL + EF Core - JWT authentication, SignalR real-time updates - MQTTnet 5.x bridge service with health monitoring - Device, telemetry, firmware, alert, group management - Rate limiting, security headers, Swagger/OpenAPI Frontend (Phase 9): - React 18 + TypeScript + Vite with Ant Design 5 - ECharts telemetry visualization, TanStack Query - SignalR live updates, device management UI - Dashboard, fleet management, firmware deployment Testing & Production (Phase 10): - 28 firmware unit tests (Modbus, JSON, config, version) - 23 xUnit backend tests (device, telemetry, command, alert) - Docker Compose with nginx, TLS MQTT, PostgreSQL - Production deployment, commissioning, and troubleshooting docs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
77 lines
2.1 KiB
C++
77 lines
2.1 KiB
C++
#include <unity.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
static float registersToFloat(uint16_t highWord, uint16_t lowWord) {
|
|
uint32_t combined = ((uint32_t)highWord << 16) | lowWord;
|
|
float result;
|
|
memcpy(&result, &combined, sizeof(float));
|
|
return result;
|
|
}
|
|
|
|
void test_float32_positive() {
|
|
// IEEE 754: 230.0 = 0x43660000
|
|
float val = registersToFloat(0x4366, 0x0000);
|
|
TEST_ASSERT_FLOAT_WITHIN(0.1, 230.0, val);
|
|
}
|
|
|
|
void test_float32_with_decimal() {
|
|
// IEEE 754: 50.01 ≈ 0x42480148
|
|
float val = registersToFloat(0x4248, 0x0148);
|
|
TEST_ASSERT_FLOAT_WITHIN(0.01, 50.01, val);
|
|
}
|
|
|
|
void test_float32_zero() {
|
|
float val = registersToFloat(0x0000, 0x0000);
|
|
TEST_ASSERT_FLOAT_WITHIN(0.001, 0.0, val);
|
|
}
|
|
|
|
void test_float32_negative() {
|
|
// IEEE 754: -15.5 = 0xC1780000
|
|
float val = registersToFloat(0xC178, 0x0000);
|
|
TEST_ASSERT_FLOAT_WITHIN(0.1, -15.5, val);
|
|
}
|
|
|
|
void test_float32_large_value() {
|
|
// IEEE 754: 12345.6 ≈ 0x4640E666
|
|
float val = registersToFloat(0x4640, 0xE666);
|
|
TEST_ASSERT_FLOAT_WITHIN(0.1, 12345.6, val);
|
|
}
|
|
|
|
void test_float32_small_value() {
|
|
// IEEE 754: 0.98 ≈ 0x3F7AE148
|
|
float val = registersToFloat(0x3F7A, 0xE148);
|
|
TEST_ASSERT_FLOAT_WITHIN(0.001, 0.98, val);
|
|
}
|
|
|
|
void test_register_array_conversion() {
|
|
uint16_t registers[6] = {
|
|
0x4366, 0x0000, // Va = 230.0
|
|
0x4367, 0x999A, // Vb = 231.6
|
|
0x4365, 0xCCCD, // Vc = 229.8
|
|
};
|
|
|
|
float va = registersToFloat(registers[0], registers[1]);
|
|
float vb = registersToFloat(registers[2], registers[3]);
|
|
float vc = registersToFloat(registers[4], registers[5]);
|
|
|
|
TEST_ASSERT_FLOAT_WITHIN(0.1, 230.0, va);
|
|
TEST_ASSERT_FLOAT_WITHIN(0.1, 231.6, vb);
|
|
TEST_ASSERT_FLOAT_WITHIN(0.1, 229.8, vc);
|
|
}
|
|
|
|
void setup() {
|
|
delay(2000);
|
|
UNITY_BEGIN();
|
|
RUN_TEST(test_float32_positive);
|
|
RUN_TEST(test_float32_with_decimal);
|
|
RUN_TEST(test_float32_zero);
|
|
RUN_TEST(test_float32_negative);
|
|
RUN_TEST(test_float32_large_value);
|
|
RUN_TEST(test_float32_small_value);
|
|
RUN_TEST(test_register_array_conversion);
|
|
UNITY_END();
|
|
}
|
|
|
|
void loop() {}
|