Safe API Framework 0.1.0 build 384e6ae
Layered API framework for safety-related applications (ERTMS RBC reference targeting CENELEC EN 50128 SIL 4)
Loading...
Searching...
No Matches
channel_configuration_example.c
Go to the documentation of this file.
1
16
17#include <stdint.h>
18#include <stdbool.h>
19#include <string.h>
20#include <stdio.h>
21
22#include "rte/channel_link/rte_channel.h"
23#include "rte/voter/rte_voter.h"
24#include "rte/status/rte_status.h"
25
26/* ============================================================================
27 * Channel Configuration Structures (User fills these in)
28 * ========================================================================== */
29
34typedef struct {
35 const char *name;
36 const char *remote_ip; // e.g., "192.168.1.100"
37 uint16_t remote_port; // e.g., 5000
38 size_t message_size; // e.g., 256
39 uint32_t timeout_ms; // e.g., 1000
40 bool server_mode; // true = listen, false = connect
42
47typedef struct {
48 const char *name;
49 const char *local_ip; // e.g., "192.168.1.50"
50 uint16_t local_port; // e.g., 5001
51 const char *remote_ip; // e.g., "192.168.1.100"
52 uint16_t remote_port; // e.g., 5001
53 size_t message_size; // e.g., 256
54 uint32_t timeout_ms; // e.g., 500
56
61typedef struct {
62 const char *name;
63 const char *descriptor_path; // e.g., "/dev/shm/rte_channel"
64 size_t message_size; // e.g., 256
65 size_t queue_depth; // e.g., 10
66 uint32_t timeout_ms; // e.g., 100
68
73typedef struct {
74 const char *name;
75 const char *fifo_path; // e.g., "/tmp/rte_channel_fifo"
76 size_t message_size; // e.g., 256
77 uint32_t timeout_ms; // e.g., 500
78 bool blocking; // true = blocking, false = non-blocking
80
81/* ============================================================================
82 * Channel Type Identification (for dispatcher)
83 * ========================================================================== */
84
85typedef enum {
86 CHANNEL_TYPE_TCP,
87 CHANNEL_TYPE_UDP,
88 CHANNEL_TYPE_SHM,
89 CHANNEL_TYPE_FIFO,
90} channel_type_t;
91
96typedef struct {
97 channel_type_t type;
98 void *impl; // Opaque pointer to actual channel (TCP/UDP/SHM/FIFO)
99 uint32_t timeout_ms;
101
102/* ============================================================================
103 * Dispatcher Callbacks (User implements these)
104 * ========================================================================== */
105
110static rte_status_t app_backend_send(void *channel, const void *data, size_t size)
111{
112 channel_wrapper_t *wrapper = (channel_wrapper_t *)channel;
113
114 if (wrapper == NULL) {
116 }
117
118 switch (wrapper->type) {
119 case CHANNEL_TYPE_TCP:
120 // TODO: Call actual TCP send
121 // return tcp_send(wrapper->impl, data, size, wrapper->timeout_ms);
122 printf("[TCP] Sending %zu bytes\n", size);
123 return RTE_STATUS_OK;
124
125 case CHANNEL_TYPE_UDP:
126 // TODO: Call actual UDP send
127 // return udp_send(wrapper->impl, data, size, wrapper->timeout_ms);
128 printf("[UDP] Sending %zu bytes\n", size);
129 return RTE_STATUS_OK;
130
131 case CHANNEL_TYPE_SHM:
132 // TODO: Call actual SHM send
133 // return shm_send(wrapper->impl, data, size, wrapper->timeout_ms);
134 printf("[SHM] Sending %zu bytes\n", size);
135 return RTE_STATUS_OK;
136
137 case CHANNEL_TYPE_FIFO:
138 // TODO: Call actual FIFO send
139 // return fifo_send(wrapper->impl, data, size, wrapper->timeout_ms);
140 printf("[FIFO] Sending %zu bytes\n", size);
141 return RTE_STATUS_OK;
142
143 default:
145 }
146}
147
152static rte_status_t app_backend_recv(void *channel, void *data, size_t size,
153 uint32_t timeout_ms)
154{
155 channel_wrapper_t *wrapper = (channel_wrapper_t *)channel;
156
157 if (wrapper == NULL) {
159 }
160
161 switch (wrapper->type) {
162 case CHANNEL_TYPE_TCP:
163 // TODO: Call actual TCP recv
164 // return tcp_recv(wrapper->impl, data, size, timeout_ms);
165 printf("[TCP] Receiving up to %zu bytes (timeout %ums)\n", size, timeout_ms);
166 return RTE_STATUS_OK;
167
168 case CHANNEL_TYPE_UDP:
169 // TODO: Call actual UDP recv
170 // return udp_recv(wrapper->impl, data, size, timeout_ms);
171 printf("[UDP] Receiving up to %zu bytes (timeout %ums)\n", size, timeout_ms);
172 return RTE_STATUS_OK;
173
174 case CHANNEL_TYPE_SHM:
175 // TODO: Call actual SHM recv
176 // return shm_recv(wrapper->impl, data, size, timeout_ms);
177 printf("[SHM] Receiving up to %zu bytes (timeout %ums)\n", size, timeout_ms);
178 return RTE_STATUS_OK;
179
180 case CHANNEL_TYPE_FIFO:
181 // TODO: Call actual FIFO recv
182 // return fifo_recv(wrapper->impl, data, size, timeout_ms);
183 printf("[FIFO] Receiving up to %zu bytes (timeout %ums)\n", size, timeout_ms);
184 return RTE_STATUS_OK;
185
186 default:
188 }
189}
190
191/* ============================================================================
192 * Example 1: Online/Standby with TCP/IP (Primary Use Case)
193 * ========================================================================== */
194
195void example_tcp_based_redundancy(void)
196{
197 printf("\n=== Example 1: TCP/IP Based Online/Standby ===\n");
198
199 /* ========================================================================
200 * ONLINE HOST CONFIGURATION
201 * ======================================================================== */
202
203 printf("\n[ONLINE HOST] Configuration:\n");
204
205 // User specifies TCP configuration for online host
206 tcp_channel_config_t tcp_config_online = {
207 .name = "online_to_standby_tcp",
208 .remote_ip = "192.168.1.100", // User provides standby IP
209 .remote_port = 5000, // User chooses port
210 .message_size = 256,
211 .timeout_ms = 1000,
212 .server_mode = false, // Connect to standby (client)
213 };
214
215 printf(" ✓ TCP Config: %s → %s:%u\n", tcp_config_online.name,
216 tcp_config_online.remote_ip, tcp_config_online.remote_port);
217 printf(" Timeout: %ums\n", tcp_config_online.timeout_ms);
218
219 // Optional: Add UDP for fast heartbeat
220 udp_channel_config_t udp_config_online = {
221 .name = "online_heartbeat_udp",
222 .local_ip = "192.168.1.50", // Online host IP
223 .local_port = 5001,
224 .remote_ip = "192.168.1.100", // Standby host IP
225 .remote_port = 5001,
226 .message_size = 256,
227 .timeout_ms = 500,
228 };
229
230 printf(" ✓ UDP Config: %s (heartbeat)\n", udp_config_online.name);
231 printf(" Local: %s:%u\n", udp_config_online.local_ip, udp_config_online.local_port);
232 printf(" Remote: %s:%u\n", udp_config_online.remote_ip, udp_config_online.remote_port);
233
234 // Create wrapper channels, one rte_channel_t per transport (ADR-025:
235 // a single "vital channel" type used to bundle N transports plus
236 // voting; that split into one rte_channel_t per link registered
237 // into a separate rte_voter_t for the voting itself).
238 static channel_wrapper_t online_ch0 = {
239 .type = CHANNEL_TYPE_TCP,
240 .impl = (void *)0x1000, // Placeholder (actual handle from OS OSAdapter)
241 .timeout_ms = 1000,
242 };
243
244 static channel_wrapper_t online_ch1 = {
245 .type = CHANNEL_TYPE_UDP,
246 .impl = (void *)0x2000, // Placeholder
247 .timeout_ms = 500,
248 };
249
250 // Configure a voter for 2oo2 voting (both must agree)
251 rte_voter_config_t voter_cfg_online = {
252 .voting_strategy = RTE_VOTING_2OO2,
253 .channel_timeout_ms = 1000,
254 .log_disagreements = true,
255 .on_disagreement = NULL,
256 .disagreement_context = NULL,
257 };
258
259 static rte_channel_t online_channels[2];
260 static rte_voter_t voter_online;
261
262 rte_status_t rc = rte_voter_init(&voter_online, &voter_cfg_online);
263 if (rc == RTE_STATUS_OK) {
264 rte_channel_config_t chan_cfg0 = {
265 .channel_handle = &online_ch0,
266 .send = app_backend_send, // User's dispatcher
267 .recv = app_backend_recv,
268 };
269 rte_channel_config_t chan_cfg1 = {
270 .channel_handle = &online_ch1,
271 .send = app_backend_send,
272 .recv = app_backend_recv,
273 };
274
275 rc = rte_channel_init(&online_channels[0], &chan_cfg0);
276 if (rc == RTE_STATUS_OK) {
277 rc = rte_voter_register_channel(&voter_online, &online_channels[0]);
278 }
279 if (rc == RTE_STATUS_OK) {
280 rc = rte_channel_init(&online_channels[1], &chan_cfg1);
281 }
282 if (rc == RTE_STATUS_OK) {
283 rc = rte_voter_register_channel(&voter_online, &online_channels[1]);
284 }
285 }
286 if (rc == RTE_STATUS_OK) {
287 printf(" ✓ Voter (2oo2) initialized over 2 channels\n");
288 } else {
289 printf(" ✗ Failed to initialize channels/voter\n");
290 return;
291 }
292
293 /* ========================================================================
294 * STANDBY HOST CONFIGURATION
295 * ======================================================================== */
296
297 printf("\n[STANDBY HOST] Configuration:\n");
298
299 // Standby listens for TCP connections
300 tcp_channel_config_t tcp_config_standby = {
301 .name = "standby_listen_tcp",
302 .remote_ip = "0.0.0.0", // Listen on all interfaces
303 .remote_port = 5000, // Same port as online's target
304 .message_size = 256,
305 .timeout_ms = 1000,
306 .server_mode = true, // Listen (server mode)
307 };
308
309 printf(" ✓ TCP Config: %s (listening)\n", tcp_config_standby.name);
310 printf(" Listen: %s:%u\n", tcp_config_standby.remote_ip, tcp_config_standby.remote_port);
311
312 // Standby also receives UDP
313 udp_channel_config_t udp_config_standby = {
314 .name = "standby_heartbeat_udp",
315 .local_ip = "192.168.1.100", // Standby IP
316 .local_port = 5001,
317 .remote_ip = "192.168.1.50", // Online IP (for feedback)
318 .remote_port = 5001,
319 .message_size = 256,
320 .timeout_ms = 500,
321 };
322
323 printf(" ✓ UDP Config: %s (receiving)\n", udp_config_standby.name);
324 printf(" Listen: %s:%u\n", udp_config_standby.local_ip, udp_config_standby.local_port);
325
326 // Create channels with same configuration
327 static channel_wrapper_t standby_ch0 = {
328 .type = CHANNEL_TYPE_TCP,
329 .impl = (void *)0x3000,
330 .timeout_ms = 1000,
331 };
332
333 static channel_wrapper_t standby_ch1 = {
334 .type = CHANNEL_TYPE_UDP,
335 .impl = (void *)0x4000,
336 .timeout_ms = 500,
337 };
338
339 static rte_channel_t standby_channels[2];
340 static rte_voter_t voter_standby;
341
342 rc = rte_voter_init(&voter_standby, &voter_cfg_online);
343 if (rc == RTE_STATUS_OK) {
344 rte_channel_config_t chan_cfg0 = {
345 .channel_handle = &standby_ch0,
346 .send = app_backend_send,
347 .recv = app_backend_recv,
348 };
349 rte_channel_config_t chan_cfg1 = {
350 .channel_handle = &standby_ch1,
351 .send = app_backend_send,
352 .recv = app_backend_recv,
353 };
354
355 rc = rte_channel_init(&standby_channels[0], &chan_cfg0);
356 if (rc == RTE_STATUS_OK) {
357 rc = rte_voter_register_channel(&voter_standby, &standby_channels[0]);
358 }
359 if (rc == RTE_STATUS_OK) {
360 rc = rte_channel_init(&standby_channels[1], &chan_cfg1);
361 }
362 if (rc == RTE_STATUS_OK) {
363 rc = rte_voter_register_channel(&voter_standby, &standby_channels[1]);
364 }
365 }
366 if (rc == RTE_STATUS_OK) {
367 printf(" ✓ Voter (2oo2) initialized over 2 channels\n");
368 }
369
370 /* ========================================================================
371 * SIMULATION: Voting Communication
372 * ======================================================================== */
373
374 printf("\n[COMMUNICATION] Simulated voting:\n");
375
376 uint8_t command[256] = {0x42}; // Dummy command
377
378 printf(" 1. Online broadcasts command via the voter...\n");
379 rc = rte_voter_send(&voter_online, command, 256);
380 printf(" Result: %d (broadcasts via TCP + UDP)\n", rc);
381
382 printf(" 2. Standby receives and votes...\n");
383 uint8_t received[256] = {0};
385 size_t bytes_received = 0;
386 rc = rte_voter_receive(&voter_standby, received, 256, &vote, &bytes_received);
387 printf(" Result: %d, Voting: %d\n", rc, vote);
388
389 printf(" 3. Check health...\n");
391 rc = rte_channel_get_health(&online_channels[0], &health);
392 printf(" Channel 0 health: sends=%u, errors=%u\n",
393 health.send_count, health.send_error_count);
394}
395
396/* ============================================================================
397 * Example 2: Local Shared Memory Channels (Optional)
398 * ========================================================================== */
399
400void example_local_redundancy(void)
401{
402 printf("\n=== Example 2: Local Shared Memory (Optional For Same-Board) ===\n");
403
404 // For same-board redundancy: Online A and Standby B on same CPU
405 shm_channel_config_t shm_config = {
406 .name = "vital_ab_shared",
407 .descriptor_path = "/dev/shm/rail_vital_ab", // User specifies path
408 .message_size = 256,
409 .queue_depth = 10,
410 .timeout_ms = 100, // Much tighter for local
411 };
412
413 printf(" Shared Memory Config:\n");
414 printf(" Path: %s\n", shm_config.descriptor_path);
415 printf(" Queue: %zu messages × %zu bytes\n",
416 shm_config.queue_depth, shm_config.message_size);
417 printf(" Timeout: %ums\n", shm_config.timeout_ms);
418
419 static channel_wrapper_t shm_ch = {
420 .type = CHANNEL_TYPE_SHM,
421 .impl = (void *)0x5000,
422 .timeout_ms = 100,
423 };
424
425 printf(" ✓ Channel created\n");
426}
427
428/* ============================================================================
429 * Example 3: Hybrid Configuration
430 * ========================================================================== */
431
432void example_hybrid_configuration(void)
433{
434 printf("\n=== Example 3: Hybrid (TCP Primary, Local SHM Fallback) ===\n");
435 printf(" For maximum flexibility: use TCP for remote, SHM for local\n");
436 printf(" Dispatcher handles both transparently\n");
437
438 // This allows:
439 // - Channel 0: TCP to remote standby (50-100ms)
440 // - Channel 1: SHM to local standby (< 1µs)
441 // - Vital channel votes on both
442 // - If TCP times out, still have SHM
443 // - If both fail, safe-state triggered
444}
445
446int main(void)
447{
448 printf("========================================\n");
449 printf("Channel Configuration Examples\n");
450 printf("========================================\n");
451
452 example_tcp_based_redundancy();
453 example_local_redundancy();
454 example_hybrid_configuration();
455
456 printf("\n========================================\n");
457 printf("Configuration Complete\n");
458 printf("========================================\n");
459 printf("\nKey Points:\n");
460 printf(" ✓ User provides configuration values (IPs, ports, paths)\n");
461 printf(" ✓ Framework handles voting and health tracking\n");
462 printf(" ✓ OS integrator implements actual I/O (send/recv)\n");
463 printf(" ✓ Dispatcher routes to correct transport\n");
464 printf(" ✓ Same channel/voter code works with ANY transport\n");
465
466 return 0;
467}
static rte_status_t app_backend_send(void *channel, const void *data, size_t size)
Dispatcher send callback Routes to appropriate transport based on channel type.
static rte_status_t app_backend_recv(void *channel, void *data, size_t size, uint32_t timeout_ms)
Dispatcher receive callback Routes to appropriate transport based on channel type.
rte_status_t
Common result/status codes.
Definition rte_status.h:27
@ RTE_STATUS_OK
Definition rte_status.h:28
@ RTE_STATUS_INVALID_PARAM
Definition rte_status.h:29
rte_voter_storage_t rte_voter_t
Opaque handle to a voter instance.
Definition rte_voter.h:149
rte_status_t rte_voter_register_channel(rte_voter_t *voter, rte_channel_t *channel)
Registers one already-initialized channel with this voter.
Definition rte_voter.c:240
rte_voting_result_t
Outcome of one rte_voter_receive() call.
Definition rte_voter.h:54
rte_status_t rte_voter_send(rte_voter_t *voter, const void *data, size_t data_size)
Broadcasts data to every registered, healthy channel.
Definition rte_voter.c:269
rte_status_t rte_voter_init(rte_voter_storage_t *storage, const rte_voter_config_t *config)
Initializes a voter with zero registered channels.
Definition rte_voter.c:201
rte_status_t rte_voter_receive(rte_voter_t *voter, void *data, size_t data_size, rte_voting_result_t *result, size_t *bytes_received)
Receives from every registered, healthy channel and votes.
Definition rte_voter.c:331
@ RTE_VOTING_2OO2
Definition rte_voter.h:44
@ RTE_VOTING_AGREED
Definition rte_voter.h:56
Configuration for rte_channel_init().
Definition rte_channel.h:90
Health statistics for one vital channel.
Definition rte_channel.h:39
uint32_t send_error_count
Definition rte_channel.h:43
Configuration for rte_voter_init().
Definition rte_voter.h:87