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
ipc-request-reply-example.c
Go to the documentation of this file.
1
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <unistd.h>
20#include <signal.h>
21
22#include "rte/status.h"
23#include "rte/log.h"
24#include "rte/ipc/rte_ipc_request_reply.h"
25
26/* ============================================================================
27 * Message Definitions (Shared between client and server)
28 * ========================================================================== */
29
33typedef struct {
34 uint32_t train_id;
35 uint32_t location_m;
37
41typedef struct {
43 uint8_t signal_state;
45 char description[32];
47
48#define SIGNAL_RED 0
49#define SIGNAL_YELLOW 1
50#define SIGNAL_GREEN 2
51
52/* ============================================================================
53 * SIGNAL SERVER (Responder)
54 * ========================================================================== */
55
63 signal_reply_t *reply)
64{
65 RTE_LOG_DEBUG("Database query: train=%u, location=%u m",
66 query->train_id, query->location_m);
67
68 /* Simple rules based on location */
69 if (query->location_m < 1000) {
70 reply->signal_state = SIGNAL_GREEN;
71 reply->track_speed_limit = 100;
72 strcpy(reply->description, "Clear ahead");
73 } else if (query->location_m < 5000) {
74 reply->signal_state = SIGNAL_YELLOW;
75 reply->track_speed_limit = 50;
76 strcpy(reply->description, "Caution");
77 } else {
78 reply->signal_state = SIGNAL_RED;
79 reply->track_speed_limit = 0;
80 strcpy(reply->description, "Stop");
81 }
82
83 reply->status = RTE_STATUS_OK;
84 return RTE_STATUS_OK;
85}
86
92static int run_signal_server(void)
93{
96 rte_status_t status;
97
98 printf("\n");
99 printf("═══════════════════════════════════════════════════════════════\n");
100 printf("Signal Database Server (Request-Reply)\n");
101 printf("═══════════════════════════════════════════════════════════════\n");
102 printf("\n");
103
104 RTE_LOG_INFO("Starting signal server");
105
106 /* Create server channel */
107 rte_ipc_rr_server_config_t server_config = {
108 .name = "signal-database",
109 .request_size = sizeof(signal_query_t),
110 .reply_size = sizeof(signal_reply_t),
111 .queue_depth = 10
112 };
113
114 status = rte_ipc_rr_server_create(&server, &server_config);
115 if (status != RTE_STATUS_OK) {
116 RTE_LOG_ERROR("Failed to create server: %d", status);
117 return EXIT_FAILURE;
118 }
119
120 RTE_LOG_INFO("Server ready, waiting for queries...");
121
122 /* Process 10 queries then shutdown */
123 for (int i = 0; i < 10; i++) {
124 /* Wait for query (5 second timeout) */
125 status = rte_ipc_rr_receive_request(&server, &request, 5000);
126
127 if (status == RTE_STATUS_TIMEOUT) {
128 RTE_LOG_WARN("No query received (timeout)");
129 continue;
130 }
131
132 if (status != RTE_STATUS_OK) {
133 RTE_LOG_ERROR("Failed to receive request: %d", status);
134 break;
135 }
136
137 /* Process query */
138 signal_query_t *query = (signal_query_t *)request.request_data;
139 signal_reply_t reply = {0};
140
141 RTE_LOG_INFO("Received query #%d from train %u (location=%u m)",
142 i + 1, query->train_id, query->location_m);
143
144 /* Query database */
145 query_signal_database(query, &reply);
146
147 /* Send reply */
148 status = rte_ipc_rr_send_reply(&server, request.request_id,
149 &reply, sizeof(reply));
150
151 if (status == RTE_STATUS_OK) {
152 RTE_LOG_INFO("Replied: signal=%u, speed=%u km/h, \"%s\"",
153 reply.signal_state, reply.track_speed_limit,
154 reply.description);
155 } else {
156 RTE_LOG_ERROR("Failed to send reply: %d", status);
157 }
158 }
159
160 /* Cleanup */
162
163 printf("\n");
164 printf("═══════════════════════════════════════════════════════════════\n");
165 printf("Signal Server shutdown\n");
166 printf("═══════════════════════════════════════════════════════════════\n");
167 printf("\n");
168
169 return EXIT_SUCCESS;
170}
171
172/* ============================================================================
173 * TRAIN CONTROLLER CLIENT (Requester)
174 * ========================================================================== */
175
179static int run_train_controller(void)
180{
181 rte_ipc_rr_client_t client;
182 rte_status_t status;
183
184 printf("\n");
185 printf("═══════════════════════════════════════════════════════════════\n");
186 printf("Train Controller (Request-Reply Client)\n");
187 printf("═══════════════════════════════════════════════════════════════\n");
188 printf("\n");
189
190 RTE_LOG_INFO("Starting train controller");
191
192 /* Connect to signal server */
193 rte_ipc_rr_client_config_t client_config = {
194 .server_name = "signal-database",
195 .request_size = sizeof(signal_query_t),
196 .reply_size = sizeof(signal_reply_t)
197 };
198
199 status = rte_ipc_rr_client_create(&client, &client_config);
200 if (status != RTE_STATUS_OK) {
201 RTE_LOG_ERROR("Failed to connect to signal server: %d", status);
202 return EXIT_FAILURE;
203 }
204
205 RTE_LOG_INFO("Connected to signal server");
206
207 /* Simulate train moving and querying signal state */
208 uint32_t train_id = 42;
209 uint32_t position = 0;
210
211 for (int i = 0; i < 10; i++) {
212 /* Move train */
213 position += 500;
214
215 /* Query signal state */
216 signal_query_t query = {
217 .train_id = train_id,
218 .location_m = position
219 };
220
221 signal_reply_t reply = {0};
222
223 RTE_LOG_INFO("Query #%d: Train %u at location %u m",
224 i + 1, query.train_id, query.location_m);
225
226 /* Send request and wait for reply (5 second timeout) */
227 status = rte_ipc_rr_request(&client,
228 &query, sizeof(query),
229 &reply, sizeof(reply),
230 5000);
231
232 if (status == RTE_STATUS_OK) {
233 const char *signal_names[] = {"RED", "YELLOW", "GREEN"};
234 RTE_LOG_INFO("Reply: signal=%s, speed=%u km/h (\"%s\")",
235 signal_names[reply.signal_state],
236 reply.track_speed_limit,
237 reply.description);
238
239 /* React to signal state */
240 switch (reply.signal_state) {
241 case SIGNAL_GREEN:
242 printf(" → Train accelerating to %u km/h\n",
243 reply.track_speed_limit);
244 break;
245 case SIGNAL_YELLOW:
246 printf(" → Train preparing to stop\n");
247 break;
248 case SIGNAL_RED:
249 printf(" → Train EMERGENCY STOP\n");
250 break;
251 }
252 } else if (status == RTE_STATUS_TIMEOUT) {
253 RTE_LOG_ERROR("Server did not reply in time!");
254 return EXIT_FAILURE;
255 } else {
256 RTE_LOG_ERROR("RPC failed: %d", status);
257 return EXIT_FAILURE;
258 }
259
260 /* Simulate travel time */
261 usleep(500000); /* 500ms */
262 }
263
264 /* Cleanup */
266
267 printf("\n");
268 printf("═══════════════════════════════════════════════════════════════\n");
269 printf("Train Controller shutdown\n");
270 printf("═══════════════════════════════════════════════════════════════\n");
271 printf("\n");
272
273 return EXIT_SUCCESS;
274}
275
276/* ============================================================================
277 * Main Entry Point
278 * ========================================================================== */
279
280int main(int argc, char *argv[])
281{
282 if (argc < 2) {
283 printf("Usage: %s <server|client>\n", argv[0]);
284 printf(" server - Run as signal database server\n");
285 printf(" client - Run as train controller client\n");
286 printf("\nExample:\n");
287 printf(" Terminal 1: %s server\n", argv[0]);
288 printf(" Terminal 2: %s client\n", argv[0]);
289 return EXIT_FAILURE;
290 }
291
292 rte_log_initialize();
293
294 if (strcmp(argv[1], "server") == 0) {
295 return run_signal_server();
296 } else if (strcmp(argv[1], "client") == 0) {
297 return run_train_controller();
298 } else {
299 printf("Unknown mode: %s\n", argv[1]);
300 return EXIT_FAILURE;
301 }
302}
rte_status_t
Common result/status codes.
Definition rte_status.h:27
@ RTE_STATUS_OK
Definition rte_status.h:28
@ RTE_STATUS_TIMEOUT
Definition rte_status.h:32
static rte_status_t query_signal_database(const signal_query_t *query, signal_reply_t *reply)
Signal database query logic.
static int run_train_controller(void)
Simulate train moving and querying signal state.
static int run_signal_server(void)
Run signal server (responder).
rte_status_t rte_ipc_rr_client_destroy(rte_ipc_rr_client_t client)
Destroy request-reply client connection.
rte_status_t rte_ipc_rr_send_reply(rte_ipc_rr_server_t server, uint32_t request_id, const void *reply_data, size_t reply_size)
Send reply to a request.
rte_status_t rte_ipc_rr_server_destroy(rte_ipc_rr_server_t server)
Destroy request-reply server.
rte_status_t rte_ipc_rr_server_create(rte_ipc_rr_server_t *handle_out, const rte_ipc_rr_server_config_t *config)
Create a request-reply server channel.
rte_status_t rte_ipc_rr_receive_request(rte_ipc_rr_server_t server, rte_ipc_rr_request_t *request_out, rte_duration_ms_t timeout_ms)
Receive a request (blocking with timeout).
struct rte_ipc_rr_server_s * rte_ipc_rr_server_t
Request-Reply server channel handle.
struct rte_ipc_rr_client_s * rte_ipc_rr_client_t
Request-reply client handle.
rte_status_t rte_ipc_rr_request(rte_ipc_rr_client_t client, const void *request_data, size_t request_size, void *reply_out, size_t reply_size, rte_duration_ms_t timeout_ms)
Send request and wait for reply (blocking with timeout).
rte_status_t rte_ipc_rr_client_create(rte_ipc_rr_client_t *handle_out, const rte_ipc_rr_client_config_t *config)
Create a request-reply client connection.
Configuration for request-reply client.
Incoming request with context for sending reply.
Configuration for request-reply server.
Query message: Train asks for signal state.
Reply message: Signal state and limits.