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
Vital Channel Module - User Guide

What is Vital Channel?

Vital Channel provides redundant communication with automatic voting/arbitration. Wraps multiple underlying IPC channels with:

  • 2oo2 (dual-channel): Both must agree
  • 2oo3 (triple-channel): Majority vote, tolerates 1 fault
  • NMR (N-modular): Arbitrary N channels, majority vote

Safety-critical systems use vital channels for hardware redundancy to detect and recover from single-point failures (e.g., CPU faults in dual-core systems).

Quick Start: 2oo2 Dual-Redundant CPU

// 1. Create two underlying IPC channels (one per CPU)
rte_buffer_t channel_a_buf, channel_b_buf;
rte_buffer_init(&channel_a_buf, storage_a, capacity_a);
rte_buffer_init(&channel_b_buf, storage_b, capacity_b);
// 2. Create vital channel that wraps both with 2oo2 voting
rte_buffer_t channels[2] = {channel_a_buf, channel_b_buf};
.name = "dual_redundant_signal",
.strategy = RTE_VOTING_2OO2,
.channels = channels,
.num_channels = 2,
.on_disagreement = handle_cpu_fault,
.timeout_ms = 100
};
rte_channel_t vital_ch;
rte_vital_channel_create(&vital_ch, &config);
// 3. Send command to both CPUs
signal_command_t cmd = {.signal_id = 5, .state = SIGNAL_RED};
rte_status_t status = rte_vital_send(vital_ch, &cmd, sizeof(cmd), 100);
if (status != RTE_STATUS_OK) {
rte_log_error("Send failed: %d", status);
}
// 4. Receive reply from both CPUs (voting ensures agreement)
status = rte_vital_receive(vital_ch, &reply, sizeof(reply), 100);
if (status == RTE_STATUS_OK) {
// Both CPUs agreed - safe to use reply
printf("Signal update confirmed by both CPUs\n");
} else {
// CPUs disagreed - likely a CPU fault
rte_log_error("CPU disagreement detected!");
}
// 5. Check health
rte_vital_get_health(vital_ch, &health);
printf("Messages: %u sent, %u received, %u disagreements\n",
health.messages_sent, health.messages_received, health.disagreements);
rte_status_t rte_buffer_init(rte_buffer_t *buf, void *storage, size_t capacity)
Binds a buffer view to caller-owned storage. Initial length is 0.
Definition rte_buffer.c:9
void rte_safestate_enter(rte_safestate_level_t level, rte_safestate_reason_t reason, const char *file, int32_t line, const char *message)
Enters a safe-state level: invokes the registered handler (if any), then, for RTE_SAFESTATE_LEVEL_SAF...
@ RTE_SAFESTATE_LEVEL_SAFE
rte_status_t
Common result/status codes.
Definition rte_status.h:27
@ RTE_STATUS_OK
Definition rte_status.h:28
@ RTE_VOTING_2OO2
Definition rte_voter.h:44
Mutable, bounds-tracked view over caller-owned storage.
Definition rte_buffer.h:36
Configuration for rte_channel_init().
Definition rte_channel.h:90
Health statistics for one vital channel.
Definition rte_channel.h:39
Reply message: Signal state and limits.

Voting Strategies

2oo2 (Dual-Channel)

Both channels must agree; any disagreement triggers fault.

Input A ────┐
           ├──→ Voting Logic ──→ Output
Input B ────┤
           └─ EQUAL? YES → Output OK
                         NO  → FAULT
  • Use case: Dual-core processors
  • Fault tolerance: 0 (any disagreement fails)
  • Safety: Detects all single-point failures via disagreement

2oo3 (Triple-Channel)

Majority vote (≥2 channels agree); tolerates 1 channel fault.

Input A ────┐
           ├──→ Voting Logic ──→ Output
Input B ────┤
           │  (majority vote)
Input C ────┘
           └─ ≥2 EQUAL? YES → Output (from majority)
                            NO  → FAULT
  • Use case: Triple-core processors, higher availability
  • Fault tolerance: 1 channel
  • Safety: Can detect and isolate single channel failure

NMR (N-Modular)

N channels with majority vote; tolerates N/2 faults.

  • Use case: 4+ redundant processors
  • Fault tolerance: N/2 channels
  • Scalable redundancy: Use with any N (1-4 supported)

Common Patterns

Fault Handling Callback

void handle_cpu_fault(void *context) {
// Called when voting fails
rte_log_error("CPU fault detected!");
// Trigger safe state
}

Health Monitoring

// Periodic health check (e.g., in watchdog callback)
void monitor_vital_channels(void) {
rte_vital_get_health(vital_ch, &health);
if (health.disagreements > 0) {
rte_log_warning("Disagreements detected: %u", health.disagreements);
}
if (health.errors > 0) {
rte_log_warning("Communication errors: %u", health.errors);
}
}

Best Practices

  1. Always register disagreement callback for vital channels
    • Ensures safe-state transition on any fault
  2. Validate timeout_ms carefully
    • Must be longer than worst-case channel latency
    • Shorter timeouts detect faults faster but risk false positives
  3. Monitor health regularly
    • Check disagreement and error counts
    • Log trends to detect degradation
  4. Use 2oo2 only when CPU faults are rare
    • Any disagreement triggers safe state
    • Consider 2oo3 for higher availability
  5. Test fault scenarios
    • Simulate channel faults to verify safe-state transitions
    • Verify disagreement callback is invoked

See Also