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
Go to the documentation of this file.
1
8
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <stdint.h>
13#include <unistd.h>
14#include <time.h>
15
16typedef struct {
17 uint32_t train_id;
18 uint32_t position;
19 uint8_t signal_state;
20 uint8_t emergency_stop;
21 uint16_t speed_limit;
22 uint32_t timestamp_ms;
23 uint32_t checksum;
24 uint32_t sequence_number;
26
27typedef struct {
28 train_command_t cmd_a;
29 train_command_t cmd_b;
30 uint32_t process_a_seq;
31 uint32_t process_b_seq;
32 volatile uint8_t ready_a;
33 volatile uint8_t ready_b;
34 volatile uint8_t process_a_healthy;
35 volatile uint8_t process_b_healthy;
36 uint32_t timestamp_ms;
38
39__attribute__((aligned(64)))
40extern shared_state_t shared_mem;
41
42typedef struct {
43 uint32_t train_id;
44 uint32_t position;
46
47static train_db_entry_t trains[] = {
48 { .train_id = 101, .position = 500 },
49 { .train_id = 102, .position = 2500 },
50 { .train_id = 103, .position = 7500 },
51};
52
53#define TRAIN_COUNT (sizeof(trains) / sizeof(trains[0]))
54
55static uint32_t crc32_checksum(const uint8_t *data, uint32_t len)
56{
57 uint32_t crc = 0xffffffff;
58 for (uint32_t i = 0; i < len; i++) {
59 uint8_t byte = data[i];
60 crc = (crc >> 8) ^ (uint32_t)(crc ^ byte);
61 }
62 return crc ^ 0xffffffff;
63}
64
65static train_command_t compute_train_command(uint32_t train_id, uint32_t position)
66{
67 train_command_t cmd = {
68 .train_id = train_id,
69 .position = position,
70 .emergency_stop = 0,
71 .timestamp_ms = (uint32_t)(time(NULL) * 1000) & 0xffffffff,
72 .sequence_number = 0,
73 };
74
75 if (position < 1000) {
76 cmd.signal_state = 2;
77 cmd.speed_limit = 80;
78 } else if (position < 5000) {
79 cmd.signal_state = 1;
80 cmd.speed_limit = 40;
81 } else if (position < 9000) {
82 cmd.signal_state = 0;
83 cmd.speed_limit = 0;
84 } else {
85 cmd.emergency_stop = 1;
86 cmd.signal_state = 0;
87 cmd.speed_limit = 0;
88 }
89
90 uint8_t *cmd_bytes = (uint8_t *)&cmd;
91 cmd.checksum = crc32_checksum(cmd_bytes, sizeof(cmd) - sizeof(cmd.checksum));
92 return cmd;
93}
94
95int main(int argc, char *argv[])
96{
97 (void)argc;
98 (void)argv;
99
100 uint32_t cycle_count = 0;
101 uint32_t process_b_seq = 0;
102 uint32_t mismatch_count = 0;
103
104 fprintf(stderr, "[EAST:B] Process B (Standby Channel B) starting\n");
105 fprintf(stderr, "[EAST:B] Verifying commands in STANDBY mode\n");
106
107 while (1) {
108 cycle_count++;
109 process_b_seq++;
110
111 for (uint32_t i = 0; i < TRAIN_COUNT; i++) {
112 trains[i].position += (i + 1) * 3;
113 if (trains[i].position > 10000) {
114 trains[i].position = 10000;
115 }
116 }
117
118 for (uint32_t i = 0; i < TRAIN_COUNT; i++) {
119 train_command_t cmd = compute_train_command(
120 trains[i].train_id,
121 trains[i].position
122 );
123 cmd.sequence_number = process_b_seq;
124
125 shared_mem.cmd_b = cmd;
126 shared_mem.process_b_seq = process_b_seq;
127 __sync_synchronize();
128 shared_mem.ready_b = 1;
129
130 if (shared_mem.ready_a && shared_mem.process_a_seq == process_b_seq) {
131 if (shared_mem.cmd_a.signal_state != cmd.signal_state ||
132 shared_mem.cmd_a.speed_limit != cmd.speed_limit) {
133 mismatch_count++;
134 fprintf(stderr, "[EAST:B] MISMATCH: A(sig=%u,spd=%u) vs B(sig=%u,spd=%u)\n",
135 shared_mem.cmd_a.signal_state,
136 shared_mem.cmd_a.speed_limit,
137 cmd.signal_state, cmd.speed_limit);
138 }
139 }
140
141 if (cycle_count % 10 == 0) {
142 fprintf(stderr,
143 "[EAST:B] Cycle %u (STANDBY): train=%u, pos=%u, sig=%u, speed=%u\n",
144 cycle_count, cmd.train_id, cmd.position,
145 cmd.signal_state, cmd.speed_limit);
146 }
147 }
148
149 shared_mem.process_b_healthy = 1;
150 usleep(25000);
151 }
152
153 return EXIT_SUCCESS;
154}
Definition process_a.c:64