Safe API Framework
Layered API framework for safety-related applications (ERTMS RBC reference targeting CENELEC EN 50128 SIL 4)
Loading...
Searching...
No Matches
Status Module - Architecture

Design Overview

  • The Status module defines a unified error handling system across the entire
  • framework. Every operation returns a sapi_status_t code that indicates
  • success or the specific failure reason.
  • Design principle: Consistency. All modules use the same status codes,
  • making error handling predictable and consistent.

Status Code Definitions

Code Allocation Strategy

  • 0: SAPI_STATUS_OK (success - no error)
  • 1-6: Framework core status codes (parameter, timeout, hardware, etc.)
  • 7-999: Reserved for framework expansion
  • 1000+: Application-specific error codes (user can extend)

Design Rationale

  • ### Why Unified Status Codes?
  • Without framework status codes:
  • c
  • int timer_result = sapi_timer_create(...); // What does -1 mean?
  • bool buffer_result = sapi_buffer_write(...); // What does false mean?
  • errno = ...; // Different modules use different mechanisms
  • Problem: Inconsistent error handling across modules.
  • With framework status codes:
  • c
  • sapi_status_t timer_rc = sapi_timer_create(...);
  • sapi_status_t buffer_rc = sapi_buffer_write(...);
  • // Both return the SAME code type
  • // Same error handling everywhere
  • ### Why Not Use errno?
  • - errno is thread-unsafe (global state)
  • - errno is platform-specific (POSIX assumption)
  • - errno values vary by system
  • - MISRA-compliant systems avoid global state

Application-Specific Codes

  • Applications can define their own status codes:
  • c
  • // In application header
  • typedef enum {
  • SAPI_STATUS_OK = 0,
  • // ... framework codes ...
  • SAPI_STATUS_NOT_SUPPORTED = 6,
  • // Application-specific (starting from 1000)
  • APP_STATUS_TRAIN_SPEED_LIMIT_EXCEEDED = 1000,
  • APP_STATUS_TRACK_INTEGRITY_CHECK_FAILED = 1001,
  • APP_STATUS_SIGNAL_ASPECT_UNKNOWN = 1002,
  • } app_status_t;

String Conversion

Usage Patterns in Framework

  • ### Pattern 1: Initialization Check
  • Every module follows this pattern:
  • c
  • sapi_status_t sapi_module_init(config_t *config) {
  • // Validate input
  • if (config == NULL) {
  • return SAPI_STATUS_INVALID_PARAM;
  • }
  • // Check if already initialized
  • if (is_initialized) {
  • return SAPI_STATUS_NOT_INITIALIZED;
  • }
  • // Perform initialization
  • // ...
  • return SAPI_STATUS_OK;
  • }
  • ### Pattern 2: Operation with Timeout
  • Operations that can timeout:
  • c
  • sapi_status_t sapi_channel_recv(handle, buffer, size, timeout) {
  • // Try to receive data within timeout
  • // ...
  • if (no_data_within_timeout) {
  • return SAPI_STATUS_TIMEOUT; // Caller knows why
  • }
  • // ...
  • return SAPI_STATUS_OK;
  • }
  • ### Pattern 3: Resource Exhaustion
  • Operations that can fail due to capacity:
  • c
  • sapi_status_t sapi_buffer_write(handle, data, size, written) {
  • // Check buffer capacity
  • if (buffer_remaining < size) {
  • return SAPI_STATUS_RESOURCE_EXHAUSTED;
  • }
  • // ...
  • return SAPI_STATUS_OK;
  • }

Integration with Safe-State

MISRA Compliance

  • The status module supports MISRA C:2012:
  • - ✓ Fixed return type (sapi_status_t enum)
  • - ✓ No implicit conversions (explicit enum values)
  • - ✓ No global state (errno-free)
  • - ✓ Deterministic (same code always means same error)
  • - ✓ Thread-safe (no shared state)

Implementation Details

  • ### Files
  • - include/safeapi/status/sapi_status.h — Public API
  • - src/status/sapi_status.c — String conversion table
  • ### String Conversion Table
  • To keep binaries small, string conversion uses a lookup table:
  • c
  • static const char *status_strings[] = {
  • [SAPI_STATUS_OK] = "SAPI_STATUS_OK",
  • [SAPI_STATUS_INVALID_PARAM] = "SAPI_STATUS_INVALID_PARAM",
  • // ...
  • };
  • Pros: O(1) lookup, small code size
  • Cons: Must maintain both enum and table (kept in sync via static checks)

Testing Strategy

  • ### Unit Tests
  • c
  • void test_status_to_string(void) {
  • // Test all known codes
  • assert(strcmp(sapi_status_to_string(SAPI_STATUS_OK), "SAPI_STATUS_OK") == 0);
  • assert(strcmp(sapi_status_to_string(SAPI_STATUS_TIMEOUT), "SAPI_STATUS_TIMEOUT") == 0);
  • // ...
  • // Test unknown code
  • assert(strcmp(sapi_status_to_string(9999), "SAPI_STATUS_UNKNOWN") == 0);
  • }

Future Extensions

  • Possible extensions (reserved code space):
  • - Additional timeout types (READ_TIMEOUT vs WRITE_TIMEOUT)
  • - Buffer-specific codes (BUFFER_EMPTY, BUFFER_FULL)
  • - Network codes (CONNECTION_REFUSED, CONNECTION_RESET)
  • - All would fit within 1000+ application-specific range
  • */