API reference

Public functions, types and macros of bedrock[RTOS] 0.0.3.

The application API is declared in include/bedrock/bedrock.h, which includes br_types.h, br_hal.h and br_assert.h. The pool allocator is declared separately in lib/br_pool.h.

Stability

Each declaration in bedrock.h carries one of three markers.

Marker Meaning
BR_STABLE Signature does not change within a minor version series.
BR_EXPERIMENTAL May change or be removed in a later minor version. Define BR_WARN_EXPERIMENTAL to get compiler warnings on use.
BR_INTERNAL Called by the kernel or a port. Not for application code. Define BR_WARN_INTERNAL to get warnings.

Version

#define BEDROCK_VERSION_MAJOR  0
#define BEDROCK_VERSION_MINOR  0
#define BEDROCK_VERSION_PATCH  3

#define BEDROCK_VERSION \
    ((BEDROCK_VERSION_MAJOR << 16) | \
     (BEDROCK_VERSION_MINOR <<  8) | \
      BEDROCK_VERSION_PATCH)

Types

br_time_t

typedef uint64_t br_time_t;

Time in microseconds.

Name Value
BR_TIME_INFINITE UINT64_MAX. Wait without a timeout.
BR_USEC(us) us as br_time_t
BR_MSEC(ms) ms * 1000
BR_SEC(s) s * 1000000

br_err_t

Value Code Meaning
BR_OK 0 Success
BR_ERR_INVALID -1 Invalid argument or object state
BR_ERR_NOMEM -2 No free TCB slot
BR_ERR_TIMEOUT -3 Timeout expired, or the call would block with timeout 0
BR_ERR_BUSY -4 Defined, not returned by the kernel in 0.0.3
BR_ERR_ISR -5 Blocking call or mutex call from interrupt context
BR_ERR_OVERFLOW -6 Semaphore already at its maximum
BR_ERR_STACK_OVF -7 Defined. Stack overflow currently panics instead of returning this code.

Tasks

typedef uint8_t br_tid_t;
typedef void (*br_task_entry_t)(void *arg);

br_tid_t is the index of the TCB slot, from 0 to CONFIG_MAX_TASKS - 1.

IPC objects

br_sem_t, br_mutex_t and br_mqueue_t are plain structs defined in br_types.h. The caller allocates them and passes a pointer to the matching init function.

Kernel

br_kernel_init

void br_kernel_init(void);

Initializes the TCB array, the board, the timer and the scheduler, and creates the idle task. Call it before any other kernel function.

br_kernel_start

void br_kernel_start(void) __attribute__((noreturn));

Starts the highest-priority ready task. Does not return.

Tasks

br_task_create

br_err_t br_task_create(br_tid_t *tid, const char *name,
                        br_task_entry_t entry, void *arg,
                        uint8_t priority,
                        void *stack, size_t stack_size);
Parameter Description
tid Receives the task ID. May be NULL.
name Stored as a pointer, not copied.
entry Entry function. It must not return.
arg Passed to entry.
priority 0 to CONFIG_NUM_PRIORITIES - 1. 0 is the highest.
stack Caller buffer. Must stay valid while the task exists.
stack_size Size of stack in bytes.

Returns BR_ERR_INVALID if entry or stack is NULL, stack_size is 0 or priority is out of range. Returns BR_ERR_NOMEM if all TCB slots are in use.

The new task is added to its ready queue. No reschedule happens inside this call.

br_task_suspend

br_err_t br_task_suspend(br_tid_t tid);

Removes the task from scheduling until br_task_resume(). A task may suspend itself, in which case the call reschedules. Returns BR_ERR_INVALID if tid is out of range or the slot is inactive.

br_task_resume

br_err_t br_task_resume(br_tid_t tid);

Makes a suspended task ready and reschedules. Returns BR_ERR_INVALID if tid is out of range or the task is not suspended.

br_task_yield

void br_task_yield(void);

Runs the scheduler. If another task is ready at a higher priority, or at the same priority, it runs next.

br_task_self

br_tid_t br_task_self(void);

Returns the ID of the running task, or 0 before the scheduler starts.

br_task_delete

BR_EXPERIMENTAL br_err_t br_task_delete(br_tid_t tid);

Clears the TCB and returns the slot to the pool. The stack buffer is not touched and can be reused.

Returns BR_ERR_INVALID if tid is out of range, the slot is already inactive, or tid is the running task. A task cannot delete itself.

A ready task is removed from its ready queue. A blocked task is removed from the sleep list, but not from an IPC wait queue, and mutexes it owns are not released. The API is marked experimental because these cleanup rules are not final.

Time

br_sleep_us, br_sleep_ms, br_sleep_s

void br_sleep_us(br_time_t us);
static inline void br_sleep_ms(uint32_t ms);
static inline void br_sleep_s(uint32_t s);

Blocks the calling task for at least the given time. br_sleep_us(0) is the same as br_task_yield().

br_uptime_us

br_time_t br_uptime_us(void);

Microseconds since br_hal_timer_init().

Semaphore

br_err_t br_sem_init(br_sem_t *sem, int32_t initial, int32_t max);
br_err_t br_sem_take(br_sem_t *sem, br_time_t timeout);
br_err_t br_sem_give(br_sem_t *sem);

br_sem_init returns BR_ERR_INVALID unless 0 <= initial <= max and max >= 1.

br_sem_take decrements the count if it is above zero. Otherwise it returns BR_ERR_TIMEOUT when timeout is 0, BR_ERR_ISR when called from an interrupt, or blocks. After a timed wait it returns BR_OK or BR_ERR_TIMEOUT.

br_sem_give wakes the highest-priority waiter if there is one. Otherwise it increments the count, or returns BR_ERR_OVERFLOW if the count is already max. It does not check for interrupt context.

Mutex

br_err_t br_mutex_init(br_mutex_t *mtx);
br_err_t br_mutex_lock(br_mutex_t *mtx, br_time_t timeout);
br_err_t br_mutex_unlock(br_mutex_t *mtx);

Lock and unlock return BR_ERR_ISR when called from an interrupt.

br_mutex_lock takes a free mutex immediately. If it is held, it returns BR_ERR_TIMEOUT when timeout is 0. Otherwise, if the caller has a higher priority than the owner, the owner is raised to the caller’s priority, and the caller blocks.

br_mutex_unlock returns BR_ERR_INVALID if the caller is not the owner. It restores the owner’s priority and hands the mutex to the highest-priority waiter, if any. The mutex is not recursive.

Message queue

br_err_t br_mqueue_init(br_mqueue_t *mq, void *buffer,
                        size_t msg_size, size_t max_msgs);
br_err_t br_mqueue_send(br_mqueue_t *mq, const void *msg, br_time_t timeout);
br_err_t br_mqueue_recv(br_mqueue_t *mq, void *msg, br_time_t timeout);

buffer must hold msg_size * max_msgs bytes. Messages are copied in and out with memcpy.

br_mqueue_init returns BR_ERR_INVALID if any pointer is NULL or a size is 0.

send on a full queue and recv on an empty queue return BR_ERR_TIMEOUT when timeout is 0, BR_ERR_ISR from an interrupt, or block. Non-blocking calls work from an interrupt.

Panic and assertions

typedef void (*br_panic_handler_t)(const char *msg, const char *file, int line);

void br_set_panic_handler(br_panic_handler_t handler);

#define BR_PANIC(msg)
#define br_assert(expr)

BR_PANIC(msg) passes the message, __FILE__ and __LINE__ to the registered handler. The handler must not return. If no handler is set, or the handler returns, the port’s br_hal_panic() halts the system. Pass NULL to remove a handler.

br_assert(expr) calls BR_PANIC("assert failed: expr") when expr is false and CONFIG_ASSERT is enabled.

Stack overflow detection calls br_hal_panic() directly and does not go through the registered handler.

Pool allocator

lib/br_pool.h

typedef void *br_pool_handle_t;

br_pool_handle_t br_pool_create(void *buffer, size_t buf_size, size_t block_size);
void  *br_pool_alloc(br_pool_handle_t handle);
void   br_pool_free(br_pool_handle_t handle, void *block);
size_t br_pool_available(br_pool_handle_t handle);
size_t br_pool_total(br_pool_handle_t handle);

br_pool_create rounds block_size up for alignment, to at least sizeof(void *). It returns NULL if buffer is NULL, block_size is 0, the buffer holds no blocks or more than BR_POOL_MAX_BLOCKS, or all BR_POOL_MAX_POOLS descriptors are used. Pools cannot be destroyed.

br_pool_alloc returns a zeroed block, or NULL when the pool is empty.

br_pool_free ignores NULL, blocks outside the pool and blocks that are already free.

The pool functions do not disable interrupts. Callers that share a pool between tasks must lock it themselves.