mirror of
https://github.com/rstrouse/ESPSomfy-RTS.git
synced 2026-10-31 13:52:15 +01:00
fix: send socket events only from loop()
Every socket event is formatted into one static buffer by one shared formatter. setConnected() runs on the WiFi/Ethernet event task and sent memStatus, wifiStrength and ethernet, then ran sockEmit.loop(), while loop() could be building its own event. _safecat() checks the room and then writes at _len, so another task moving _len in between could write past the end of g_response. setConnected() now sends nothing. loop() broadcasts the status every STATUS_EMIT_MS (30 s): memStatus, then ethernet, or wifiStrength when it moved 3 dBm or changed channel. A client that connects still gets all of it at once from initClients(), so needsBroadcast and the 1.5 s tick go, and so does the 1.5 s memStatus for the config panel. SocketEmitter records loop()'s task in begin(). Off it, beginEmit() logs and hands out a formatter that writes nothing, and endEmit(), endEmitRoom() and loop() do nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
474c7c0f42
commit
25d548ef07
11 changed files with 153 additions and 117 deletions
|
|
@ -195,6 +195,39 @@ static void test_setBuffer_resets_length() {
|
|||
TEST_ASSERT_EQUAL_STRING("", storage);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* discard
|
||||
********************************************************************/
|
||||
static void test_discard_writes_nothing() {
|
||||
// What a socket event built off loop() goes into. The buffer the formatter
|
||||
// had before must not see a byte of it.
|
||||
fmt.beginObject();
|
||||
fmt.addElem("kept", true);
|
||||
char before[STORAGE_SIZE];
|
||||
memcpy(before, storage, sizeof(before));
|
||||
fmt.discard();
|
||||
fmt.beginObject();
|
||||
fmt.addElem("ssid", "Home \"WiFi\"");
|
||||
fmt.addElem("strength", (int32_t)-70);
|
||||
fmt.beginArray("pulses");
|
||||
fmt.addElem((uint32_t)2416);
|
||||
fmt.endArray();
|
||||
fmt.addElem("big", (uint64_t)18446744073709551615ULL);
|
||||
fmt.endObject();
|
||||
TEST_ASSERT_EQUAL_MEMORY(before, storage, sizeof(before));
|
||||
TEST_ASSERT_EQUAL_UINT32(0, fmt.length());
|
||||
TEST_ASSERT_TRUE(fmt.overflowed());
|
||||
}
|
||||
static void test_setBuffer_after_discard_writes_again() {
|
||||
fmt.discard();
|
||||
fmt.addElem("dropped");
|
||||
useBuffer(BUFF_SIZE);
|
||||
fmt.beginObject();
|
||||
fmt.endObject();
|
||||
TEST_ASSERT_FALSE(fmt.overflowed());
|
||||
TEST_ASSERT_EQUAL_STRING("{}", storage);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
|
@ -216,5 +249,7 @@ int main(int argc, char **argv) {
|
|||
RUN_TEST(test_length_matches_what_was_written);
|
||||
RUN_TEST(test_refused_append_leaves_length_alone);
|
||||
RUN_TEST(test_setBuffer_resets_length);
|
||||
RUN_TEST(test_discard_writes_nothing);
|
||||
RUN_TEST(test_setBuffer_after_discard_writes_again);
|
||||
return UNITY_END();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -181,63 +181,73 @@ static void test_parseUTCTime_ignores_local_zone() {
|
|||
* rssiNeedsEmit
|
||||
********************************************************************/
|
||||
static void test_rssiNeedsEmit_channel_change_always_emits() {
|
||||
TEST_ASSERT_TRUE(rssiNeedsEmit(-70, -70, 6, 11, 0, 3, 10000));
|
||||
TEST_ASSERT_TRUE(rssiNeedsEmit(-70, -70, 6, 11, 3));
|
||||
}
|
||||
static void test_rssiNeedsEmit_small_change_is_ignored() {
|
||||
TEST_ASSERT_FALSE(rssiNeedsEmit(-72, -70, 6, 6, 60000, 3, 10000));
|
||||
TEST_ASSERT_FALSE(rssiNeedsEmit(-72, -70, 6, 6, 3));
|
||||
}
|
||||
static void test_rssiNeedsEmit_real_change_after_interval_emits() {
|
||||
TEST_ASSERT_TRUE(rssiNeedsEmit(-73, -70, 6, 6, 10000, 3, 10000));
|
||||
}
|
||||
static void test_rssiNeedsEmit_real_change_too_soon_waits() {
|
||||
TEST_ASSERT_FALSE(rssiNeedsEmit(-73, -70, 6, 6, 5000, 3, 10000));
|
||||
static void test_rssiNeedsEmit_real_change_emits() {
|
||||
TEST_ASSERT_TRUE(rssiNeedsEmit(-73, -70, 6, 6, 3));
|
||||
}
|
||||
static void test_rssiNeedsEmit_either_direction() {
|
||||
TEST_ASSERT_TRUE(rssiNeedsEmit(-67, -70, 6, 6, 10000, 3, 10000));
|
||||
TEST_ASSERT_TRUE(rssiNeedsEmit(-73, -70, 6, 6, 10000, 3, 10000));
|
||||
TEST_ASSERT_TRUE(rssiNeedsEmit(-67, -70, 6, 6, 3));
|
||||
TEST_ASSERT_TRUE(rssiNeedsEmit(-73, -70, 6, 6, 3));
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* RssiBroadcast
|
||||
********************************************************************/
|
||||
static RssiBroadcast broadcastAt(int rssi, int channel, uint32_t at) {
|
||||
static RssiBroadcast broadcastOf(int rssi, int channel) {
|
||||
RssiBroadcast b;
|
||||
b.sent(true, rssi, channel, at);
|
||||
b.sent(true, rssi, channel);
|
||||
return b;
|
||||
}
|
||||
static void test_rssiBroadcast_first_status_is_due() {
|
||||
// Nothing broadcast since boot, so the first status tick after connecting
|
||||
// sends the signal.
|
||||
RssiBroadcast b;
|
||||
TEST_ASSERT_TRUE(b.due(-60, 6, 3));
|
||||
}
|
||||
static void test_rssiBroadcast_client_emit_keeps_baseline() {
|
||||
// A new client gets the current RSSI right as it drops 5 dBm. The clients
|
||||
// already connected must still get the change.
|
||||
RssiBroadcast b = broadcastAt(-60, 6, 0);
|
||||
b.sent(false, -65, 6, 20000);
|
||||
RssiBroadcast b = broadcastOf(-60, 6);
|
||||
b.sent(false, -65, 6);
|
||||
TEST_ASSERT_EQUAL_INT(-60, b.rssi);
|
||||
TEST_ASSERT_EQUAL_UINT32(0, b.at);
|
||||
TEST_ASSERT_TRUE(b.due(-65, 6, 20000, 3, 10000));
|
||||
TEST_ASSERT_TRUE(b.due(-65, 6, 3));
|
||||
}
|
||||
static void test_rssiBroadcast_broadcast_moves_baseline() {
|
||||
RssiBroadcast b = broadcastAt(-60, 6, 0);
|
||||
b.sent(true, -65, 6, 20000);
|
||||
RssiBroadcast b = broadcastOf(-60, 6);
|
||||
b.sent(true, -65, 6);
|
||||
TEST_ASSERT_EQUAL_INT(-65, b.rssi);
|
||||
TEST_ASSERT_EQUAL_UINT32(20000, b.at);
|
||||
// Measured from the new baseline and too soon after it.
|
||||
TEST_ASSERT_FALSE(b.due(-66, 6, 40000, 3, 10000));
|
||||
TEST_ASSERT_FALSE(b.due(-70, 6, 25000, 3, 10000));
|
||||
TEST_ASSERT_TRUE(b.due(-70, 6, 30000, 3, 10000));
|
||||
// Measured from the new baseline.
|
||||
TEST_ASSERT_FALSE(b.due(-66, 6, 3));
|
||||
TEST_ASSERT_TRUE(b.due(-70, 6, 3));
|
||||
}
|
||||
static void test_rssiBroadcast_channel_change_is_due() {
|
||||
RssiBroadcast b = broadcastAt(-60, 6, 1000);
|
||||
TEST_ASSERT_TRUE(b.due(-60, 11, 1000, 3, 10000));
|
||||
RssiBroadcast b = broadcastOf(-60, 6);
|
||||
TEST_ASSERT_TRUE(b.due(-60, 11, 3));
|
||||
}
|
||||
static void test_rssiBroadcast_client_emit_on_disconnect_keeps_baseline() {
|
||||
RssiBroadcast b = broadcastAt(-60, 6, 0);
|
||||
b.sent(false, -100, -1, 5000);
|
||||
RssiBroadcast b = broadcastOf(-60, 6);
|
||||
b.sent(false, -100, -1);
|
||||
TEST_ASSERT_EQUAL_INT(6, b.channel);
|
||||
TEST_ASSERT_FALSE(b.due(-60, 6, 5000, 3, 10000));
|
||||
TEST_ASSERT_FALSE(b.due(-60, 6, 3));
|
||||
}
|
||||
static void test_rssiBroadcast_hold_off_across_millis_wrap() {
|
||||
RssiBroadcast b = broadcastAt(-60, 6, 0xFFFFF000u);
|
||||
TEST_ASSERT_FALSE(b.due(-70, 6, 0x00001000u, 3, 10000)); // 8192ms later
|
||||
TEST_ASSERT_TRUE(b.due(-70, 6, 0x00002000u, 3, 10000)); // 12288ms later
|
||||
|
||||
/*********************************************************************
|
||||
* emitAllowed
|
||||
********************************************************************/
|
||||
static int loopTask, wifiEventTask;
|
||||
static void test_emitAllowed_on_the_loop_task() {
|
||||
TEST_ASSERT_TRUE(emitAllowed(&loopTask, &loopTask));
|
||||
}
|
||||
static void test_emitAllowed_refuses_another_task() {
|
||||
TEST_ASSERT_FALSE(emitAllowed(&wifiEventTask, &loopTask));
|
||||
}
|
||||
static void test_emitAllowed_before_the_owner_is_known() {
|
||||
// setup() before SocketEmitter::begin(), which is loop()'s task anyway.
|
||||
TEST_ASSERT_TRUE(emitAllowed(&loopTask, nullptr));
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
|
|
@ -336,22 +346,6 @@ static void test_wifiAuthModeName_unknown_past_the_shared_values() {
|
|||
TEST_ASSERT_EQUAL_STRING("UNKNOWN", wifiAuthModeName(255));
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* heapEmitTarget
|
||||
********************************************************************/
|
||||
static void test_heapEmitTarget_one_client_always_gets_it() {
|
||||
TEST_ASSERT_TRUE(heap_emit_t::client == heapEmitTarget(3, 0, 30000, false));
|
||||
TEST_ASSERT_TRUE(heap_emit_t::client == heapEmitTarget(3, 60000, 30000, true));
|
||||
}
|
||||
static void test_heapEmitTarget_broadcasts_once_per_interval() {
|
||||
TEST_ASSERT_TRUE(heap_emit_t::broadcast == heapEmitTarget(255, 30000, 30000, false));
|
||||
TEST_ASSERT_TRUE(heap_emit_t::broadcast == heapEmitTarget(255, 30000, 30000, true));
|
||||
TEST_ASSERT_TRUE(heap_emit_t::none == heapEmitTarget(255, 29999, 30000, false));
|
||||
}
|
||||
static void test_heapEmitTarget_room_in_between() {
|
||||
TEST_ASSERT_TRUE(heap_emit_t::room == heapEmitTarget(255, 1000, 30000, true));
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* LoopStats
|
||||
********************************************************************/
|
||||
|
|
@ -437,14 +431,16 @@ int main(int argc, char **argv) {
|
|||
RUN_TEST(test_parseUTCTime_ignores_local_zone);
|
||||
RUN_TEST(test_rssiNeedsEmit_channel_change_always_emits);
|
||||
RUN_TEST(test_rssiNeedsEmit_small_change_is_ignored);
|
||||
RUN_TEST(test_rssiNeedsEmit_real_change_after_interval_emits);
|
||||
RUN_TEST(test_rssiNeedsEmit_real_change_too_soon_waits);
|
||||
RUN_TEST(test_rssiNeedsEmit_real_change_emits);
|
||||
RUN_TEST(test_rssiNeedsEmit_either_direction);
|
||||
RUN_TEST(test_rssiBroadcast_first_status_is_due);
|
||||
RUN_TEST(test_rssiBroadcast_client_emit_keeps_baseline);
|
||||
RUN_TEST(test_rssiBroadcast_broadcast_moves_baseline);
|
||||
RUN_TEST(test_rssiBroadcast_channel_change_is_due);
|
||||
RUN_TEST(test_rssiBroadcast_client_emit_on_disconnect_keeps_baseline);
|
||||
RUN_TEST(test_rssiBroadcast_hold_off_across_millis_wrap);
|
||||
RUN_TEST(test_emitAllowed_on_the_loop_task);
|
||||
RUN_TEST(test_emitAllowed_refuses_another_task);
|
||||
RUN_TEST(test_emitAllowed_before_the_owner_is_known);
|
||||
RUN_TEST(test_worthRoaming_needs_the_full_gain);
|
||||
RUN_TEST(test_worthRoaming_never_to_a_weaker_ap);
|
||||
RUN_TEST(test_worthRoaming_any_ap_while_disconnected);
|
||||
|
|
@ -458,9 +454,6 @@ int main(int argc, char **argv) {
|
|||
RUN_TEST(test_formatBacktrace_stops_when_the_buffer_is_full);
|
||||
RUN_TEST(test_wifiAuthModeName_matches_the_idf_enum);
|
||||
RUN_TEST(test_wifiAuthModeName_unknown_past_the_shared_values);
|
||||
RUN_TEST(test_heapEmitTarget_one_client_always_gets_it);
|
||||
RUN_TEST(test_heapEmitTarget_broadcasts_once_per_interval);
|
||||
RUN_TEST(test_heapEmitTarget_room_in_between);
|
||||
RUN_TEST(test_loopStats_rate_is_passes_per_second);
|
||||
RUN_TEST(test_loopStats_empty_window_has_no_rate);
|
||||
RUN_TEST(test_loopStats_keeps_the_longest_pass);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue