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
main.c
Go to the documentation of this file.
1
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <unistd.h>
27
28#include <sys/neutrino.h>
29#include <sys/netmgr.h>
30#include <sys/siginfo.h>
31
32#include "rte/status.h"
33#include "rte/types.h"
34#include "rte/log.h"
35#include "rte/safestate.h"
36
37/* ============================================================================
38 * QNX Configuration
39 * ========================================================================== */
40
41#define SERVER_NAME "railway-server"
42#define CHANNEL_NAME "/railway/cmd"
43#define MESSAGE_BUFFER_SIZE 256
44
45/* Application state */
46typedef enum {
47 STATE_INIT = 0,
48 STATE_LISTENING = 1,
49 STATE_PROCESSING = 2,
50 STATE_ERROR = 3,
51 STATE_SHUTDOWN = 4
52} app_state_t;
53
54typedef struct {
55 int chid; /* Channel ID for message passing */
56 int coid; /* Connection ID */
57 app_state_t state;
58 uint32_t messages_received;
59 uint32_t messages_processed;
60 uint32_t errors;
61 volatile int running;
63
64static app_context_t g_app = {
65 .chid = -1,
66 .coid = -1,
67 .state = STATE_INIT,
68 .messages_received = 0,
69 .messages_processed = 0,
70 .errors = 0,
71 .running = 1
72};
73
74/* Message types */
75typedef enum {
76 MSG_TYPE_PING = 1,
77 MSG_TYPE_TRAIN_UPDATE = 2,
78 MSG_TYPE_SIGNAL_QUERY = 3,
79 MSG_TYPE_SHUTDOWN = 99
80} msg_type_t;
81
82/* Message structure */
83typedef struct {
84 uint32_t type;
85 uint32_t train_id;
86 uint32_t position;
87 uint8_t data[MESSAGE_BUFFER_SIZE - 12];
89
90/* Reply structure */
91typedef struct {
92 rte_status_t status;
93 uint32_t signal_state;
94 uint32_t track_speed_limit;
96
97/* ============================================================================
98 * QNX Message Handling
99 * ========================================================================== */
100
105{
106 /* Create a channel for receiving messages */
107 g_app.chid = ChannelCreate(0);
108 if (g_app.chid == -1) {
109 RTE_LOG_ERROR("Failed to create QNX channel: %d", errno);
110 return RTE_STATUS_ERROR;
111 }
112
113 RTE_LOG_INFO("QNX channel created: %d", g_app.chid);
114
115 /* Register the channel in the name space */
116 /* In production, would attach to well-known name */
117 RTE_LOG_INFO("Message channel ready (PID=%d, CHID=%d)", getpid(), g_app.chid);
118
119 return RTE_STATUS_OK;
120}
121
126 cmd_reply_t *reply)
127{
128 RTE_ASSERT(msg != NULL);
129 RTE_ASSERT(reply != NULL);
130
131 RTE_LOG_DEBUG("Train update: ID=%u, Position=%u", msg->train_id, msg->position);
132
133 /* Validate train position */
134 if (msg->position > 10000) {
135 RTE_LOG_WARN("Train position out of valid range: %u", msg->position);
136 reply->status = RTE_STATUS_ERROR;
137 reply->signal_state = 0; /* Red signal - stop */
138 return RTE_STATUS_ERROR;
139 }
140
141 /* Determine signal state based on position */
142 if (msg->position < 1000) {
143 reply->signal_state = 1; /* Green - go */
144 reply->track_speed_limit = 80;
145 } else if (msg->position < 5000) {
146 reply->signal_state = 2; /* Yellow - caution */
147 reply->track_speed_limit = 40;
148 } else {
149 reply->signal_state = 0; /* Red - stop */
150 reply->track_speed_limit = 0;
151 }
152
153 reply->status = RTE_STATUS_OK;
154
155 RTE_LOG_INFO("Train %u: signal=%u, speed_limit=%u",
156 msg->train_id,
157 reply->signal_state,
158 reply->track_speed_limit);
159
160 g_app.messages_processed++;
161 return RTE_STATUS_OK;
162}
163
168{
169 cmd_reply_t reply = {
170 .status = RTE_STATUS_OK,
171 .signal_state = 0,
172 .track_speed_limit = 0
173 };
174
175 g_app.messages_received++;
176
177 /* Dispatch based on message type */
178 switch (msg->type) {
179 case MSG_TYPE_PING:
180 RTE_LOG_DEBUG("Received PING from client");
181 reply.status = RTE_STATUS_OK;
182 break;
183
184 case MSG_TYPE_TRAIN_UPDATE:
185 RTE_LOG_DEBUG("Processing TRAIN_UPDATE message");
186 process_train_update(msg, &reply);
187 break;
188
189 case MSG_TYPE_SIGNAL_QUERY:
190 RTE_LOG_DEBUG("Received SIGNAL_QUERY");
191 reply.signal_state = 1; /* Default: green */
192 reply.track_speed_limit = 80;
193 reply.status = RTE_STATUS_OK;
194 break;
195
196 case MSG_TYPE_SHUTDOWN:
197 RTE_LOG_INFO("Received SHUTDOWN request");
198 g_app.running = 0;
199 reply.status = RTE_STATUS_OK;
200 break;
201
202 default:
203 RTE_LOG_WARN("Unknown message type: %u", msg->type);
204 reply.status = RTE_STATUS_ERROR;
205 break;
206 }
207
208 /* Send reply back to client */
209 MsgReply(rcvid, EOK, &reply, sizeof(reply));
210
211 return reply.status;
212}
213
218{
219 int rcvid;
220 train_message_t msg;
221 int rc;
222
223 RTE_LOG_INFO("Starting QNX server loop");
224 g_app.state = STATE_LISTENING;
225
226 while (g_app.running) {
227 /* Block waiting for a message */
228 rcvid = MsgReceive(g_app.chid, &msg, sizeof(msg), NULL);
229
230 if (rcvid == -1) {
231 /* Error receiving message */
232 RTE_LOG_ERROR("MsgReceive failed: %d", errno);
233 g_app.errors++;
234 continue;
235 }
236
237 if (rcvid == 0) {
238 /* Pulse or special case */
239 RTE_LOG_DEBUG("Received pulse or special message");
240 continue;
241 }
242
243 /* Process the message */
244 g_app.state = STATE_PROCESSING;
245 rc = handle_message(&msg, rcvid);
246 g_app.state = STATE_LISTENING;
247
248 if (rc != RTE_STATUS_OK) {
249 g_app.errors++;
250 }
251
252 /* Log statistics every 10 messages */
253 if ((g_app.messages_received % 10) == 0) {
254 RTE_LOG_INFO("Stats: received=%u, processed=%u, errors=%u",
255 g_app.messages_received,
256 g_app.messages_processed,
257 g_app.errors);
258 }
259 }
260
261 return RTE_STATUS_OK;
262}
263
268{
269 RTE_LOG_INFO("Shutting down railway server");
270
271 g_app.state = STATE_SHUTDOWN;
272
273 /* Destroy channel */
274 if (g_app.chid != -1) {
275 ChannelDestroy(g_app.chid);
276 g_app.chid = -1;
277 }
278
279 return RTE_STATUS_OK;
280}
281
282/* ============================================================================
283 * Main Entry Point
284 * ========================================================================== */
285
286int main(int argc, char *argv[])
287{
288 (void)argc;
289 (void)argv;
290
291 rte_status_t status;
292
293 printf("\n");
294 printf("═══════════════════════════════════════════════════════════════\n");
295 printf("Railway Control Server (QNX RTOS)\n");
296 printf("═══════════════════════════════════════════════════════════════\n");
297 printf("PID: %d\n", getpid());
298
299 /* Initialize logging */
300 status = rte_log_initialize();
301 if (status != RTE_STATUS_OK) {
302 fprintf(stderr, "Failed to initialize logging\n");
303 return EXIT_FAILURE;
304 }
305
306 RTE_LOG_INFO("Railway Control Server starting (QNX RTOS)");
307
308 /* Initialize QNX message channel */
309 status = qnx_init_channel();
310 if (status != RTE_STATUS_OK) {
311 RTE_LOG_ERROR("Failed to initialize QNX channel");
312 return EXIT_FAILURE;
313 }
314
315 /* Run server loop */
316 status = server_loop();
317 if (status != RTE_STATUS_OK) {
318 RTE_LOG_ERROR("Server loop exited with error: %d", status);
319 }
320
321 /* Shutdown */
322 app_shutdown();
323
324 /* Print summary */
325 printf("\n");
326 printf("═══════════════════════════════════════════════════════════════\n");
327 printf("Railway Server Summary\n");
328 printf("═══════════════════════════════════════════════════════════════\n");
329 printf("Messages received: %u\n", g_app.messages_received);
330 printf("Messages processed: %u\n", g_app.messages_processed);
331 printf("Errors: %u\n", g_app.errors);
332 printf("═══════════════════════════════════════════════════════════════\n");
333 printf("\n");
334
335 rte_log_shutdown();
336 return EXIT_SUCCESS;
337}
#define RTE_ASSERT(cond)
Checked assertion. Always active in every build configuration, including production (ADR-004 section ...
rte_status_t
Common result/status codes.
Definition rte_status.h:27
@ RTE_STATUS_OK
Definition rte_status.h:28
static rte_status_t handle_message(train_message_t *msg, int rcvid)
Handle incoming message.
Definition main.c:167
static rte_status_t qnx_init_channel(void)
Initialize QNX message channel.
Definition main.c:104
static rte_status_t app_shutdown(void)
Shutdown application.
Definition main.c:267
static rte_status_t server_loop(void)
Main server loop.
Definition main.c:217
static rte_status_t process_train_update(const train_message_t *msg, cmd_reply_t *reply)
Process train update message.
Definition main.c:125