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
process_b.c
1
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <stdint.h>
19#include <unistd.h>
20#include <time.h>
21
22typedef struct {
23 uint32_t train_id;
24 uint32_t position;
25 uint8_t signal_state;
26 uint8_t emergency_stop;
27 uint16_t speed_limit;
28 uint32_t timestamp_ms;
29 uint32_t checksum;
30 uint32_t sequence_number;
32
33typedef struct {
34 train_command_t cmd_a;
35 train_command_t cmd_b;
36 train_command_t cmd_a_out;
37 train_command_t cmd_b_out;
38 volatile uint32_t a_ready;
39 volatile uint32_t b_ready;
40 volatile uint32_t a_compared;
41 volatile uint32_t b_compared;
42 volatile uint8_t outputs_match;
43 uint32_t mismatch_count;
44 uint32_t sequence;
45 uint32_t timestamp_ms;
47
48__attribute__((aligned(64)))
49extern shared_state_t shared_mem;
50
51typedef struct {
52 uint32_t train_id;
53 uint32_t position;
55
56static train_db_entry_t trains[] = {
57 { .train_id = 101, .position = 500 },
58 { .train_id = 102, .position = 2500 },
59 { .train_id = 103, .position = 7500 },
60};
61
62#define TRAIN_COUNT (sizeof(trains) / sizeof(trains[0]))
63
64static uint32_t crc32(const uint8_t *data, uint32_t len)
65{
66 uint32_t crc = 0xffffffff;
67 for (uint32_t i = 0; i < len; i++) {
68 uint8_t byte = data[i];
69 crc = (crc >> 8) ^ (uint32_t)(crc ^ byte);
70 }
71 return crc ^ 0xffffffff;
72}
73
74static train_command_t compute_command(uint32_t train_id, uint32_t position)
75{
76 train_command_t cmd = {
77 .train_id = train_id,
78 .position = position,
79 .emergency_stop = 0,
80 .timestamp_ms = (uint32_t)(time(NULL) * 1000) & 0xffffffff,
81 .sequence_number = 0,
82 };
83
84 if (position < 1000) {
85 cmd.signal_state = 2;
86 cmd.speed_limit = 80;
87 } else if (position < 5000) {
88 cmd.signal_state = 1;
89 cmd.speed_limit = 40;
90 } else if (position < 9000) {
91 cmd.signal_state = 0;
92 cmd.speed_limit = 0;
93 } else {
94 cmd.emergency_stop = 1;
95 cmd.signal_state = 0;
96 cmd.speed_limit = 0;
97 }
98
99 uint8_t *cmd_bytes = (uint8_t *)&cmd;
100 cmd.checksum = crc32(cmd_bytes, sizeof(cmd) - sizeof(cmd.checksum));
101 return cmd;
102}
103
104static train_command_t safe_state(uint32_t train_id)
105{
106 train_command_t safe = {
107 .train_id = train_id,
108 .position = 0,
109 .signal_state = 0,
110 .emergency_stop = 1,
111 .speed_limit = 0,
112 .timestamp_ms = 0,
113 .checksum = 0,
114 .sequence_number = 0,
115 };
116 return safe;
117}
118
119static void compare_and_decide(const train_command_t *my_cmd,
120 const train_command_t *other_cmd,
121 train_command_t *output,
122 uint8_t *match_status)
123{
124 /* IDENTICAL logic to Process A */
125 if (my_cmd->train_id == other_cmd->train_id &&
126 my_cmd->position == other_cmd->position &&
127 my_cmd->signal_state == other_cmd->signal_state &&
128 my_cmd->speed_limit == other_cmd->speed_limit) {
129
130 *output = *my_cmd;
131 *match_status = 1;
132
133 } else {
134
135 *output = safe_state(my_cmd->train_id);
136 *match_status = 0;
137 }
138}
139
140int main(int argc, char *argv[])
141{
142 (void)argc;
143 (void)argv;
144
145 uint32_t cycle_count = 0;
146 uint32_t sequence = 0;
147
148 fprintf(stderr,
149 "┌────────────────────────────────────────────────────────┐\n");
150 fprintf(stderr,
151 "│ Process B - Cross-Comparison (Peer-to-Peer 2oo2) │\n");
152 fprintf(stderr,
153 "│ Mirrors Process A, independent comparison │\n");
154 fprintf(stderr,
155 "└────────────────────────────────────────────────────────┘\n");
156 fprintf(stderr, "\n");
157
158 while (1) {
159 cycle_count++;
160 sequence++;
161
162 /* PHASE 1: Compute independently */
163 for (uint32_t i = 0; i < TRAIN_COUNT; i++) {
164 trains[i].position += (i + 1) * 3;
165 if (trains[i].position > 10000) {
166 trains[i].position = 10000;
167 }
168 }
169
170 for (uint32_t i = 0; i < TRAIN_COUNT; i++) {
171 train_command_t cmd = compute_command(
172 trains[i].train_id,
173 trains[i].position
174 );
175 cmd.sequence_number = sequence;
176
177 shared_mem.cmd_b = cmd;
178 __sync_synchronize();
179 shared_mem.b_ready = 1;
180
181 if (cycle_count % 10 == 0) {
182 fprintf(stderr,
183 "[WEST:B] Cycle %u: Computed train=%u, pos=%u, sig=%u, speed=%u\n",
184 cycle_count, cmd.train_id, cmd.position,
185 cmd.signal_state, cmd.speed_limit);
186 }
187 }
188
189 /* PHASE 2: Wait for A's computation */
190 uint32_t timeout_ms = 0;
191 while (!shared_mem.a_ready && timeout_ms < 25) {
192 usleep(1000);
193 timeout_ms++;
194 }
195
196 if (!shared_mem.a_ready) {
197 fprintf(stderr, "[WEST:B] ERROR: Process A timeout\n");
198 continue;
199 }
200
201 /* PHASE 3: Cross-comparison (identical logic to A) */
202 train_command_t output;
203 uint8_t match_status;
204
205 compare_and_decide(
206 &shared_mem.cmd_b,
207 &shared_mem.cmd_a,
208 &output,
209 &match_status
210 );
211
212 shared_mem.cmd_b_out = output;
213 __sync_synchronize();
214 shared_mem.b_compared = 1;
215
216 if (cycle_count % 10 == 0) {
217 fprintf(stderr,
218 "[WEST:B] Received A's: train=%u, sig=%u, speed=%u\n",
219 shared_mem.cmd_a.train_id,
220 shared_mem.cmd_a.signal_state,
221 shared_mem.cmd_a.speed_limit);
222
223 fprintf(stderr,
224 "[WEST:B] Comparison: %s\n",
225 match_status ? "MATCH ✓" : "MISMATCH ✗");
226
227 fprintf(stderr,
228 "[WEST:B] Output: sig=%u, speed=%u\n",
229 output.signal_state, output.speed_limit);
230 }
231
232 /* PHASE 4: Verify A reached same decision */
233 timeout_ms = 0;
234 while (!shared_mem.a_compared && timeout_ms < 10) {
235 usleep(1000);
236 timeout_ms++;
237 }
238
239 if (shared_mem.a_compared) {
240 if (shared_mem.cmd_a_out.signal_state == shared_mem.cmd_b_out.signal_state &&
241 shared_mem.cmd_a_out.speed_limit == shared_mem.cmd_b_out.speed_limit) {
242
243 shared_mem.outputs_match = 1;
244
245 } else {
246
247 shared_mem.outputs_match = 0;
248 shared_mem.mismatch_count++;
249
250 fprintf(stderr,
251 "[WEST:B] ⚠️ ALERT: A's output differs!\n");
252 fprintf(stderr,
253 " A output: sig=%u, speed=%u\n",
254 shared_mem.cmd_a_out.signal_state,
255 shared_mem.cmd_a_out.speed_limit);
256 fprintf(stderr,
257 " B output: sig=%u, speed=%u\n",
258 shared_mem.cmd_b_out.signal_state,
259 shared_mem.cmd_b_out.speed_limit);
260 }
261 }
262
263 /* Reset for next cycle */
264 shared_mem.b_ready = 0;
265 shared_mem.b_compared = 0;
266
267 usleep(25000);
268 }
269
270 return EXIT_SUCCESS;
271}
Definition process_a.c:64