Railway Message Processor (Linux POSIX)
A simple but realistic railway communication application demonstrating RteFramework on Linux with POSIX OAL.
Overview
Application: Train message processor with periodic heartbeats
Platform: Linux (any Linux system with gcc/clang)
Use case: Simple train communication and state monitoring
Purpose: Learn framework basics
What It Does
- Receives simulated train messages:
- Heartbeats (0x01)
- Position updates (0x02)
- Command acknowledgments (0x03)
- Processes messages with validation and error handling
- Generates heartbeats every 10 iterations (simulates timer callback)
- Logs all operations with structured logging
- Tracks statistics:
- Messages processed
- Heartbeats sent
- Errors encountered
Building
Prerequisites
# Ubuntu/Debian
sudo apt-get install cmake build-essential
# macOS
brew install cmake
Quick Build
From the project root:
# Option 1: Build script (easiest)
./examples/build-linux-native.sh
# Option 2: CMake preset
cmake --preset linux-native
cmake --build --preset linux-native
Manual Build
# Build framework for Linux
mkdir -p build/linux
cd build/linux
cmake -S . -B . -DCMAKE_TOOLCHAIN_FILE=cmake/Toolchain-Linux.cmake
cmake --build .
cd ../..
# Build the example
cd examples/linux-posix-app
mkdir build && cd build
cmake -S ../../.. -B .
cmake --build .
Running
# From project root
build/linux-native/examples/linux-posix-app/railway-processor
# Or from example directory
cd examples/linux-posix-app/build
./railway-processor
Example Output
═══════════════════════════════════════════════════════════════
railway-message-processor Summary
═══════════════════════════════════════════════════════════════
Messages processed: 50
Heartbeats sent: 5
Errors encountered: 0
Final state: SHUTDOWN
═══════════════════════════════════════════════════════════════
Code Structure
main.c
├── Includes
│ ├── Framework headers (rte/*)
│ ├── Standard C library
│ └── POSIX headers
│
├── Configuration
│ ├── Message types enum
│ ├── Application states
│ └── Global context
│
├── Core Functions
│ ├── app_init() — Initialize application
│ ├── process_message() — Parse and handle message
│ ├── heartbeat_callback() — Periodic callback simulation
│ ├── simulate_train_message() — Generate test message
│ └── transition_to_state() — Safe state management
│
└── Main Loop
├── Initialize framework
├── Process messages
├── Generate heartbeats
└── Graceful shutdown
Framework Features Demonstrated
1. Status Codes (No Exceptions)
RTE_LOG_ERROR("Processing failed: %d", status);
}
rte_status_t
Common result/status codes.
2. Structured Logging
RTE_LOG_INFO("Train %u at position %u", train_id, position);
RTE_LOG_WARN("Invalid message (len=%zu)", len);
RTE_LOG_DEBUG("Processing message [%zu bytes]", len);
3. Safe Assertions
#define RTE_ASSERT(cond)
Checked assertion. Always active in every build configuration, including production (ADR-004 section ...
4. Safe State Management
static rte_status_t transition_to_state(app_state_t new_state)
{
g_app.state = new_state;
}
5. Fixed-Width Types
uint32_t message_count;
uint8_t msg_type;
Message Flow
simulate_train_message()
↓
process_message()
↓
(Parse message type)
↓
├─→ HEARTBEAT: Log "received from train"
├─→ POSITION_UPDATE: Validate & log position
├─→ COMMAND_ACK: Log acknowledgment
└─→ Unknown: Log warning, return error
↓
Update statistics
↓
Return status code
Extending the Example
Add New Message Type
- Add type to message handling:
case 0x04:
RTE_LOG_INFO("Received NEW_MESSAGE_TYPE");
break;
- Add to simulator:
uint8_t sequence[] = {0x01, 0x02, 0x03, 0x04};
Add Real Timer
Replace simulation with rte::timer:
rte_timer_t timer;
rte_status_t rte_timer_stop(rte_timer_handle_t handle)
Stops a running timer; safe to call on an already-stopped timer.
rte_status_t rte_timer_start(rte_timer_handle_t handle)
Starts (or restarts) a created timer.
rte_status_t rte_timer_create(rte_timer_storage_t *storage, const rte_timer_config_t *config, rte_timer_handle_t *out_handle)
Creates a timer bound to caller-owned storage. Does not start it.
rte_status_t rte_timer_destroy(rte_timer_handle_t handle)
Destroys a timer, releasing any OSAdapter resources bound to it.
Add Task Pool
Extend with rte::task (when available):
rte_task_t task1, task2;
rte_status_t rte_task_create(rte_task_storage_t *storage, const rte_task_config_t *config, rte_task_handle_t *out_handle)
Creates a task in the suspended state.
Add Network I/O
Add socket communication:
#include <sys/socket.h>
int sock = socket(AF_INET, SOCK_DGRAM, 0);
Safety Considerations
Memory Safety
- No dynamic allocation after startup
- Fixed-size buffers with bounds checking
- No pointers beyond necessity
Type Safety
- Explicit status codes (no exceptions)
- Fixed-width integer types
- Enum for state machine
Error Handling
- Every function returns rte_status_t
- Errors logged before propagation
- Statistics tracked for analysis
State Management
- Safe transitions between states
- State validation before operations
- Clear state diagram in code
Performance Notes
- Message throughput: ~10k messages/sec (on modern CPU)
- Memory footprint: ~1 MB
- CPU usage: Minimal (100ms sleep between iterations)
- Latency: <1ms per message (no real-time guarantee on Linux)
For hard real-time performance, see the QNX RTOS example.
Next Steps
- ✅ Build and run this example
- Modify message types (see "Extending")
- Add real timer support
- Explore QNX version for real-time (in ../qnx-rtos-app/)
- Integrate into your application
Related Examples
References