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
.name = "dual_redundant_signal",
.channels = channels,
.num_channels = 2,
.on_disagreement = handle_cpu_fault,
.timeout_ms = 100
};
rte_vital_channel_create(&vital_ch, &config);
signal_command_t cmd = {.signal_id = 5, .state = SIGNAL_RED};
rte_status_t status = rte_vital_send(vital_ch, &cmd,
sizeof(cmd), 100);
rte_log_error("Send failed: %d", status);
}
status = rte_vital_receive(vital_ch, &reply, sizeof(reply), 100);
printf("Signal update confirmed by both CPUs\n");
} else {
rte_log_error("CPU disagreement detected!");
}
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.
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.
rte_channel_storage_t rte_channel_t
Opaque handle to a vital channel instance.
Mutable, bounds-tracked view over caller-owned storage.
Configuration for rte_channel_init().
Health statistics for one vital channel.
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) {
rte_log_error("CPU fault detected!");
}
Health Monitoring
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
- Always register disagreement callback for vital channels
- Ensures safe-state transition on any fault
- Validate timeout_ms carefully
- Must be longer than worst-case channel latency
- Shorter timeouts detect faults faster but risk false positives
- Monitor health regularly
- Check disagreement and error counts
- Log trends to detect degradation
- Use 2oo2 only when CPU faults are rare
- Any disagreement triggers safe state
- Consider 2oo3 for higher availability
- Test fault scenarios
- Simulate channel faults to verify safe-state transitions
- Verify disagreement callback is invoked
See Also