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
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <stdint.h>
22#include <unistd.h>
23#include <time.h>
24
25/* ============================================================================
26 * Shared Memory (Same as Process A)
27 * ========================================================================== */
28
29typedef struct {
30 uint32_t train_id;
31 uint32_t position;
32 uint8_t signal_state;
33 uint8_t emergency_stop;
34 uint16_t speed_limit;
35 uint32_t timestamp_ms;
36 uint32_t checksum;
37 uint32_t sequence_number;
39
40typedef struct {
41 train_command_t cmd_a;
42 train_command_t cmd_b;
43 uint32_t process_a_seq;
44 uint32_t process_b_seq;
45 volatile uint8_t ready_a;
46 volatile uint8_t ready_b;
47 volatile uint8_t process_a_healthy;
48 volatile uint8_t process_b_healthy;
49 uint32_t timestamp_ms;
51
52__attribute__((aligned(64)))
53extern shared_state_t shared_mem;
54
55/* ============================================================================
56 * Train Database (Independent copy)
57 * ========================================================================== */
58
59typedef struct {
60 uint32_t train_id;
61 uint32_t position;
63
64static train_db_entry_t trains[] = {
65 { .train_id = 101, .position = 500 },
66 { .train_id = 102, .position = 2500 },
67 { .train_id = 103, .position = 7500 },
68};
69
70#define TRAIN_COUNT (sizeof(trains) / sizeof(trains[0]))
71
72/* ============================================================================
73 * CRC32
74 * ========================================================================== */
75
76static uint32_t crc32_checksum(const uint8_t *data, uint32_t len)
77{
78 uint32_t crc = 0xffffffff;
79 for (uint32_t i = 0; i < len; i++) {
80 uint8_t byte = data[i];
81 crc = (crc >> 8) ^ (uint32_t)(crc ^ byte);
82 }
83 return crc ^ 0xffffffff;
84}
85
86/* ============================================================================
87 * Process B: Verify/Vote (Vital Channel)
88 * ========================================================================== */
89
90static train_command_t compute_train_command(uint32_t train_id, uint32_t position)
91{
92 train_command_t cmd = {
93 .train_id = train_id,
94 .position = position,
95 .emergency_stop = 0,
96 .timestamp_ms = (uint32_t)(time(NULL) * 1000) & 0xffffffff,
97 .sequence_number = 0,
98 };
99
100 /* Same logic as Process A (independent verification) */
101 if (position < 1000) {
102 cmd.signal_state = 2;
103 cmd.speed_limit = 80;
104 } else if (position < 5000) {
105 cmd.signal_state = 1;
106 cmd.speed_limit = 40;
107 } else if (position < 9000) {
108 cmd.signal_state = 0;
109 cmd.speed_limit = 0;
110 } else {
111 cmd.emergency_stop = 1;
112 cmd.signal_state = 0;
113 cmd.speed_limit = 0;
114 }
115
116 uint8_t *cmd_bytes = (uint8_t *)&cmd;
117 cmd.checksum = crc32_checksum(cmd_bytes,
118 sizeof(cmd) - sizeof(cmd.checksum));
119
120 return cmd;
121}
122
123/* ============================================================================
124 * Main Loop
125 * ========================================================================== */
126
127int main(int argc, char *argv[])
128{
129 (void)argc;
130 (void)argv;
131
132 uint32_t cycle_count = 0;
133 uint32_t process_b_seq = 0;
134 uint32_t mismatch_count = 0;
135
136 fprintf(stderr, "[WEST:B] Process B (Vital Channel B) starting\n");
137 fprintf(stderr, "[WEST:B] Verifying commands every 25ms\n");
138
139 while (1) {
140 cycle_count++;
141 process_b_seq++;
142
143 /* Simulate train movement (independently) */
144 for (uint32_t i = 0; i < TRAIN_COUNT; i++) {
145 trains[i].position += (i + 1) * 3;
146 if (trains[i].position > 10000) {
147 trains[i].position = 10000;
148 }
149 }
150
151 /* Compute verification commands */
152 for (uint32_t i = 0; i < TRAIN_COUNT; i++) {
153 train_command_t cmd = compute_train_command(
154 trains[i].train_id,
155 trains[i].position
156 );
157 cmd.sequence_number = process_b_seq;
158
159 /* Write to shared memory */
160 shared_mem.cmd_b = cmd;
161 shared_mem.process_b_seq = process_b_seq;
162 __sync_synchronize();
163 shared_mem.ready_b = 1;
164
165 /* Compare with Process A for early mismatch detection */
166 if (shared_mem.ready_a &&
167 shared_mem.process_a_seq == process_b_seq) {
168
169 if (shared_mem.cmd_a.signal_state != cmd.signal_state ||
170 shared_mem.cmd_a.speed_limit != cmd.speed_limit) {
171
172 mismatch_count++;
173 fprintf(stderr,
174 "[WEST:B] MISMATCH detected cycle %u: "
175 "A(sig=%u,spd=%u) vs B(sig=%u,spd=%u)\n",
176 cycle_count,
177 shared_mem.cmd_a.signal_state,
178 shared_mem.cmd_a.speed_limit,
179 cmd.signal_state, cmd.speed_limit);
180 }
181 }
182
183 if (cycle_count % 10 == 0) {
184 fprintf(stderr,
185 "[WEST:B] Cycle %u: train=%u, pos=%u, sig=%u, speed=%u "
186 "(mismatches=%u)\n",
187 cycle_count, cmd.train_id, cmd.position,
188 cmd.signal_state, cmd.speed_limit, mismatch_count);
189 }
190 }
191
192 /* Mark as healthy */
193 shared_mem.process_b_healthy = 1;
194
195 /* Sleep 25ms */
196 usleep(25000);
197 }
198
199 return EXIT_SUCCESS;
200}
Definition process_a.c:64