Safe API Framework
Layered API framework for safety-related applications (ERTMS RBC reference targeting CENELEC EN 50128 SIL 4)
Toggle main menu visibility
Loading...
Searching...
No Matches
Buffer Module - User Guide
What is a Buffer?
A Buffer is a lightweight, bounds-tracked view over caller-owned storage.
You provide the backing storage (static array, stack buffer), and the buffer
tracks how much data is currently valid. No allocation, no freeing - just
state tracking.
Key concept: Buffer is a VIEW, not the owner of storage.
Quick Start
1. Allocate Backing Storage
* // Static buffer for 256 bytes
* static uint8_t buffer_storage[256];
*
2. Bind Buffer View
* sapi_buffer_t buf;
*
* sapi_status_t rc = sapi_buffer_init(&buf, buffer_storage, sizeof(buffer_storage));
* if (rc != SAPI_STATUS_OK) {
* printf("Buffer init failed\n");
* return rc;
* }
*
* // buf now has: data=buffer_storage, capacity=256, length=0
*
3. Use Buffer
* // Write data into storage (caller manages writes to data pointer)
* memcpy(buf.data, input, input_len);
*
* // Mark data as valid
* sapi_buffer_set_length(&buf, input_len);
*
* // Read data
* printf("Buffer contains %zu bytes\n", buf.length);
*
* // Clear for reuse
* sapi_buffer_clear(&buf); // Sets length=0, keeps data/capacity
*
Key Structures
* typedef struct {
* void *data; // Pointer to backing storage (caller-owned)
* size_t capacity; // Total bytes available in storage
* size_t length; // Bytes currently holding valid data
* } sapi_buffer_t;
*
* typedef struct {
* const void *data; // Read-only view of data
* size_t length; // Bytes of valid data
* } sapi_const_buffer_t;
*
Invariant: length <= capacity
Practical Examples
Example 1: Fixed-Size Message Buffer
* typedef struct {
* uint32_t command_id;
* uint32_t seq_num;
* uint8_t payload[128];
* } message_t;
*
* message_t msg = {0};
* sapi_buffer_t buf;
*
* // Bind buffer to message payload
* sapi_buffer_init(&buf, msg.payload, sizeof(msg.payload));
*
* // Receive data into payload
* receive_from_network(&buf.data[0], 64);
* sapi_buffer_set_length(&buf, 64);
*
* // Send message
* msg.command_id = 1;
* msg.seq_num = seq++;
* send_message(&msg);
*
* // Clear for next use
* sapi_buffer_clear(&buf);
*
Example 2: Read-Only View
* sapi_buffer_t mutable_buf = {...};
*
* // Create read-only view
* sapi_const_buffer_t view = {
* .data = mutable_buf.data,
* .length = mutable_buf.length
* };
*
* // Pass to function that should not modify
* process_read_only(&view);
*
Buffer Operations
Initialize
* sapi_buffer_init(&buf, storage, capacity);
*
- Sets buf.data = storage
- Sets buf.capacity = capacity
- Sets buf.length = 0
- Returns INVALID_PARAM if storage==NULL or capacity==0
Write Data
* // Caller writes to buf.data
* memcpy(buf.data + offset, input, size);
*
* // Mark data as valid
* sapi_buffer_set_length(&buf, new_length);
*
sapi_buffer_set_length()
fails if new_length > capacity.
Read Data
* // Caller reads from buf.data
* size_t n = buf.length; // How much valid data
* memcpy(output, buf.data, n);
*
Clear
* sapi_buffer_clear(&buf); // Sets length=0, keeps capacity/data
*
Best Practices
1. Caller owns storage lifetime
- Buffer just tracks state
- Storage must outlive buffer
- Static or stack allocation recommended
2. Check capacity before writing
- Caller responsible for bounds checking
- Buffer tracks length, not write protection
-
sapi_buffer_set_length()
validates
3. Use
sapi_buffer_set_length()
for bounds checking
- Always call after writing
- Returns error if length > capacity
- Prevents out-of-bounds bugs
4. Use const_buffer_t for read-only access
- Pass to functions that should not modify
- Type-safe read-only contract
5. Clear when done
- Reset length to 0 for reuse
- Resets valid-data range, not storage
See Also
-
Buffer Module - Architecture
for internal design
-
Memory Module - User Guide
for allocation strategies
*/
Generated by
1.18.0