Skip to content

Commit e1b4570

Browse files
authored
Fix/ethernet things connections (#670)
* fix ethernet things and such * feat: Add throttling to DiagnosticsHub::flush_pending to prevent flooding sinks * chore: Add changeset * style: Run pre-commit * this fixes tests * feat(Keep-A-Live): Use tighter keep-a-lives by default (needs a kernel directive to work with a computer connexion)
1 parent 5866c05 commit e1b4570

9 files changed

Lines changed: 133 additions & 33 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
release: minor
2+
summary: Add variable-length TCP orders, diagnostic forwarding, and flush throttling
3+
4+
- `TcpOrderStreamParser` now supports variable-length orders: when an order's `get_size()` returns 0, all remaining stream data is passed to `parse()`, and the post-parse size is used for byte consumption. A `reset_for_receive()` hook is called after consumption so orders can reset state for the next packet.
5+
- `Order` gains a virtual `reset_for_receive()` no-op that subclasses can override.
6+
- `Socket` constructor no longer panics on `ERR_RTE` during `tcp_connect()` — sets `pending_connection_reset` instead, letting the connection retry when the route becomes available.
7+
- `OrderProtocolDiagnosticSink` now accepts a target `OrderProtocol*` via its constructor, so diagnostic records are sent to a single socket instead of broadcasting to all open sockets.
8+
- `DiagnosticTransportOrder` now parses incoming diagnostic orders (IDs 1555, 2555, 3000) and re-publishes them via `Hub::publish_runtime_*()`, enabling forwarding of remote board diagnostics to the control station.
9+
- `Diagnostics::Hub::flush_pending` throttles records to at most one per 100 ms per priority level (urgent and non-urgent tracked separately) to prevent flooding sinks.
10+
- Default TCP keepalive values tightened: 30 ms idle, 20 ms interval, 2 probes (commented out for now since it can't keep connection with the backend).
11+
- `lwipopts.h`: `MEMP_NUM_SYS_TIMEOUT` increased by 10 to avoid pool exhaustion with SNTP and whatever else it may happen, `TCP_TMR_INTERVAL` reduced to 10 ms for faster keepalive response.
12+
- Added `Diagnostics::install_ethernet_sink(OrderProtocol*)` to register the Ethernet sink with a specific target socket.

Inc/HALAL/Models/Packets/Order.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class Order : public Packet {
1616
virtual void set_callback(void (*callback)(void)) = 0;
1717
virtual void process() = 0;
1818
virtual void parse(OrderProtocol* socket, uint8_t* data) = 0;
19+
virtual void reset_for_receive() {}
1920
void store_ip_order(string& ip) { remote_ip = &ip; }
2021
void parse(uint8_t* data) override { parse(nullptr, data); }
2122
static void process_by_id(uint16_t id) {

Inc/HALAL/Services/Communication/Ethernet/LWIP/Ethernet.hpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,13 @@
1919

2020
#define ETHERNET_POOLS_BASE_ADDRESS 0x30000000
2121

22-
#define TCP_INACTIVITY_TIME_UNTIL_KEEPALIVE_MS 500
23-
#define TCP_KEEPALIVE_TRIES_UNTIL_DISCONNECTION 10
24-
#define TCP_SPACE_BETWEEN_KEEPALIVE_TRIES_MS 100
22+
// #define TCP_INACTIVITY_TIME_UNTIL_KEEPALIVE_MS 500
23+
// #define TCP_KEEPALIVE_TRIES_UNTIL_DISCONNECTION 10
24+
// #define TCP_SPACE_BETWEEN_KEEPALIVE_TRIES_MS 100
25+
26+
#define TCP_INACTIVITY_TIME_UNTIL_KEEPALIVE_MS 30
27+
#define TCP_KEEPALIVE_TRIES_UNTIL_DISCONNECTION 2
28+
#define TCP_SPACE_BETWEEN_KEEPALIVE_TRIES_MS 20
2529

2630
class Ethernet {
2731
public:

Inc/HALAL/Services/Communication/Ethernet/LWIP/TCP/TcpOrderStreamParser.hpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,26 @@ inline void process(OrderProtocol* protocol, IPV4& remote_ip, vector<uint8_t>& s
2525
}
2626

2727
const size_t order_size = order_it->second->get_size();
28-
if (order_size < sizeof(uint16_t)) {
29-
parsed_bytes += 1;
30-
continue;
31-
}
32-
if (stream_buffer.size() - parsed_bytes < order_size) {
33-
break;
28+
if (order_size > 0) {
29+
if (order_size < sizeof(uint16_t)) {
30+
parsed_bytes += 1;
31+
continue;
32+
}
33+
if (stream_buffer.size() - parsed_bytes < order_size) {
34+
break;
35+
}
3436
}
3537

3638
order_it->second->store_ip_order(remote_ip.string_address);
3739
Order::process_data(protocol, packet_ptr);
38-
parsed_bytes += order_size;
40+
41+
const size_t consumed = order_it->second->get_size();
42+
if (consumed > 0) {
43+
parsed_bytes += consumed;
44+
} else {
45+
parsed_bytes += sizeof(uint16_t);
46+
}
47+
order_it->second->reset_for_receive();
3948
}
4049

4150
if (parsed_bytes > 0) {

Inc/HALAL/Services/Diagnostics/Diagnostics.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,10 @@ class Hub {
245245
static size_t history_next_index;
246246
static array<PendingRecord, Config::pending_capacity> pending_records;
247247
static size_t pending_count;
248+
#ifdef STLIB_ETH
249+
static uint64_t last_urgent_flush_us;
250+
static uint64_t last_normal_flush_us;
251+
#endif
248252
};
249253

250254
class Runtime {
@@ -258,3 +262,10 @@ class Runtime {
258262
};
259263

260264
} // namespace Diagnostics
265+
266+
#ifdef STLIB_ETH
267+
class OrderProtocol;
268+
namespace Diagnostics {
269+
void install_ethernet_sink(OrderProtocol* target);
270+
}
271+
#endif

LWIP/Target/lwipopts.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@
5151
#define ETH_RX_BUFFER_SIZE 1536
5252
/*----- Value in opt.h for LWIP_TCP_KEEPALIVE: 0 -----*/
5353
#define LWIP_TCP_KEEPALIVE 1
54+
#define MEMP_NUM_SYS_TIMEOUT (LWIP_NUM_SYS_TIMEOUT_INTERNAL + 10) // + 10 just in case
55+
#define TCP_TMR_INTERVAL 10
56+
#define TCP_FAST_INTERVAL 10
57+
#define TCP_SLOW_INTERVAL 20
5458

5559
#define MEMP_NUM_NETCONN 4
5660
/*----- Value in opt.h for NO_SYS: 0 -----*/

Src/HALAL/Services/Communication/Ethernet/LWIP/TCP/Socket.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,7 @@ Socket::Socket(
156156
tcp_connect(connection_control_block, &remote_ip.address, remote_port, connect_callback);
157157
if (connect_error != ERR_OK && connect_error != ERR_ISCONN) {
158158
connecting_sockets.erase(remote_node);
159-
tcp_abort(connection_control_block);
160-
connection_control_block = nullptr;
161-
PANIC("Cannot connect TCP socket. Error code: %d", connect_error);
162-
return;
159+
pending_connection_reset = true;
163160
}
164161

165162
if (std::find(OrderProtocol::sockets.begin(), OrderProtocol::sockets.end(), this) ==

Src/HALAL/Services/Diagnostics/DiagnosticSinks.cpp

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class UartDiagnosticSink final : public DiagnosticSink {
6868
#ifdef STLIB_ETH
6969
class DiagnosticTransportOrder final : public Order {
7070
public:
71+
static inline OrderProtocol* forward_target = nullptr;
7172
DiagnosticTransportOrder() {
7273
Packet::packets[DIAGNOSTIC_FAULT_ORDER_ID] = this;
7374
Packet::packets[DIAGNOSTIC_WARNING_ORDER_ID] = this;
@@ -94,15 +95,48 @@ class DiagnosticTransportOrder final : public Order {
9495

9596
void set_callback(void (*callback)(void)) override { this->callback = callback; }
9697

97-
void process() override {
98-
if (callback != nullptr) {
99-
callback();
100-
}
101-
}
102-
10398
void parse(OrderProtocol* socket, uint8_t* data) override {
10499
(void)socket;
105-
(void)data;
100+
if (data == nullptr)
101+
return;
102+
103+
memcpy(&id, data, sizeof(id));
104+
105+
size_t off = sizeof(id) + sizeof(uint8_t);
106+
kind = data[off++];
107+
108+
size_t len = bounded_strnlen(reinterpret_cast<char*>(data + off), sizeof(origin) - 1);
109+
memcpy(origin, data + off, len);
110+
origin[len] = '\0';
111+
off += len + 1;
112+
113+
len = bounded_strnlen(reinterpret_cast<char*>(data + off), sizeof(message) - 1);
114+
memcpy(message, data + off, len);
115+
message[len] = '\0';
116+
off += len + 1;
117+
118+
memcpy(
119+
&counter,
120+
data + off,
121+
sizeof(counter) + sizeof(second) + sizeof(minute) + sizeof(hour) + sizeof(day) +
122+
sizeof(month) + sizeof(year)
123+
);
124+
size = off + sizeof(counter) + sizeof(second) + sizeof(minute) + sizeof(hour) +
125+
sizeof(day) + sizeof(month) + sizeof(year);
126+
}
127+
128+
void process() override {
129+
switch (id) {
130+
case DIAGNOSTIC_FAULT_ORDER_ID:
131+
Hub::publish_runtime_fault(message, false, 0, origin, "");
132+
break;
133+
case DIAGNOSTIC_WARNING_ORDER_ID:
134+
Hub::publish_runtime_warning(message, false, 0, origin, "");
135+
break;
136+
case DIAGNOSTIC_OK_ORDER_ID:
137+
Hub::publish_runtime_info(message, false, 0, origin, "");
138+
break;
139+
}
106140
}
107141

108142
uint8_t* build() override {
@@ -128,6 +162,8 @@ class DiagnosticTransportOrder final : public Order {
128162

129163
size_t get_size() override { return size; }
130164

165+
void reset_for_receive() { size = 0; }
166+
131167
uint16_t get_id() override { return id; }
132168

133169
void set_pointer(size_t index, void* pointer) override {
@@ -191,22 +227,25 @@ class DiagnosticTransportOrder final : public Order {
191227

192228
class OrderProtocolDiagnosticSink final : public DiagnosticSink {
193229
public:
230+
explicit OrderProtocolDiagnosticSink(OrderProtocol* target = nullptr) : target_socket(target) {
231+
DiagnosticTransportOrder::forward_target = target;
232+
}
233+
194234
bool publish(const DiagnosticRecord& record) override {
235+
if (target_socket == nullptr) {
236+
return false;
237+
}
195238
char description[Config::formatted_message_capacity + 1]{};
196239
DiagnosticFormatter::describe(record, description, sizeof(description));
197240
transport_order.set_record(record, description);
198-
199-
bool delivered = false;
200-
for (OrderProtocol* socket : OrderProtocol::sockets) {
201-
if (socket == nullptr) {
202-
continue;
203-
}
204-
delivered = socket->send_order(transport_order) || delivered;
205-
}
241+
transport_order.build();
242+
bool delivered = target_socket->send_order(transport_order);
243+
transport_order.reset_for_receive();
206244
return delivered;
207245
}
208246

209247
private:
248+
OrderProtocol* target_socket;
210249
DiagnosticTransportOrder transport_order{};
211250
};
212251
#endif
@@ -222,11 +261,13 @@ void Runtime::install_default_sinks() {
222261
(void)Hub::emplace_sink<UartDiagnosticSink>();
223262
#endif
224263

225-
#ifdef STLIB_ETH
226-
(void)Hub::emplace_sink<OrderProtocolDiagnosticSink>();
227-
#endif
228-
229264
defaults_installed = true;
230265
}
231266

267+
#ifdef STLIB_ETH
268+
void install_ethernet_sink(OrderProtocol* target) {
269+
(void)Hub::emplace_sink<OrderProtocolDiagnosticSink>(target);
270+
}
271+
#endif
272+
232273
} // namespace Diagnostics

Src/HALAL/Services/Diagnostics/DiagnosticsHub.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
#include "HALAL/Services/Diagnostics/Diagnostics.hpp"
2+
#ifdef STLIB_ETH
3+
#include "HALAL/Services/Time/Scheduler.hpp"
4+
#endif
25

36
namespace Diagnostics {
47

@@ -10,6 +13,10 @@ size_t Hub::history_count = 0;
1013
size_t Hub::history_next_index = 0;
1114
array<Hub::PendingRecord, Config::pending_capacity> Hub::pending_records = {};
1215
size_t Hub::pending_count = 0;
16+
#ifdef STLIB_ETH
17+
uint64_t Hub::last_urgent_flush_us = 0;
18+
uint64_t Hub::last_normal_flush_us = 0;
19+
#endif
1320
bool Runtime::defaults_installed = false;
1421

1522
namespace {
@@ -297,6 +304,10 @@ void Hub::publish_protection_event(
297304

298305
void Hub::flush_pending(bool urgent_only) {
299306
const uint8_t target_mask = sink_count == 0 ? 0 : static_cast<uint8_t>((1u << sink_count) - 1u);
307+
#ifdef STLIB_ETH
308+
const uint64_t now = Scheduler::get_global_tick();
309+
uint64_t& last_flush = urgent_only ? last_urgent_flush_us : last_normal_flush_us;
310+
#endif
300311

301312
for (size_t record_index = 0; record_index < pending_count;) {
302313
PendingRecord& pending_record = pending_records[record_index];
@@ -305,13 +316,23 @@ void Hub::flush_pending(bool urgent_only) {
305316
continue;
306317
}
307318

319+
#ifdef STLIB_ETH
320+
if (last_flush != 0 && now - last_flush < 100'000) {
321+
record_index++;
322+
continue;
323+
}
324+
#endif
325+
308326
for (size_t sink_index = 0; sink_index < sink_count; ++sink_index) {
309327
const uint8_t sink_mask = static_cast<uint8_t>(1u << sink_index);
310328
if ((pending_record.delivered_mask & sink_mask) != 0u) {
311329
continue;
312330
}
313331
if (sinks[sink_index] != nullptr && sinks[sink_index]->publish(pending_record.record)) {
314332
pending_record.delivered_mask |= sink_mask;
333+
#ifdef STLIB_ETH
334+
last_flush = now;
335+
#endif
315336
}
316337
}
317338

0 commit comments

Comments
 (0)