mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-14 07:21:30 +10:00
1037 lines
31 KiB
C
1037 lines
31 KiB
C
/*
|
|
* Copyright 2021-2023 Morse Micro
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/**
|
|
* @defgroup MMOSAL Morse Micro Operating System Abstraction Layer (mmosal) API
|
|
*
|
|
* This API provides a layer of abstraction from the underlying operation system. Functionality
|
|
* is provided for typical RTOS features.
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "mmport.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/**
|
|
* @defgroup MMOSAL_MAIN Main loop
|
|
*
|
|
* Provides the "main" function that runs the operating system scheduler.
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
/** Application initialization callback (see @ref mmosal_main for details). */
|
|
typedef void (*mmosal_app_init_cb_t)(void);
|
|
|
|
/**
|
|
* OS main function.
|
|
*
|
|
* This should be invoked after early initialization. If further initialization is required after
|
|
* the scheduler is started an optional @p app_init_cb argument can be provided and the given
|
|
* function with be executed in a thread that will subsequently be destroyed if it returns.
|
|
*
|
|
* @param app_init_cb Application initialization callback that will be invoked after the
|
|
* scheduler has been started. This optional (may be NULL). If specified,
|
|
* the function will run in its own thread and may or may not return.
|
|
*
|
|
* @returns an error code if something goes wrong, otherwise does not return.
|
|
*/
|
|
int mmosal_main(mmosal_app_init_cb_t app_init_cb);
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/*
|
|
* ---------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* @defgroup MMOSAL_MEMMGMT Memory management
|
|
*
|
|
* Provides memory management functionality (allocation and free).
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Allocate memory of the given size and return a pointer to it (malloc).
|
|
*
|
|
* No guarantees made about initialization.
|
|
*
|
|
* @warning This function should not be used directly. Instead use @ref mmosal_malloc().
|
|
*
|
|
* @param size The amount of memory to allocate (in bytes).
|
|
*
|
|
* @returns pointer to the allocated memory on success, or NULL on failure.
|
|
*/
|
|
void *mmosal_malloc_(size_t size);
|
|
|
|
/**
|
|
* Allocate memory of the given size and return a pointer to it (malloc) -- debug version.
|
|
*
|
|
* No guarantees made about initialization.
|
|
*
|
|
* @warning This function should not be used directly. Instead use @ref mmosal_malloc().
|
|
*
|
|
* @param size The amount of memory to allocate (in bytes).
|
|
* @param name Name of the function that allocated the memory.
|
|
* @param line_number The line number at which the allocation happened.
|
|
*
|
|
* @returns pointer to the allocated memory on success, or NULL on failure.
|
|
*/
|
|
void *mmosal_malloc_dbg(size_t size, const char *name, unsigned line_number);
|
|
|
|
/**
|
|
* Free the given memory allocation.
|
|
*
|
|
* @param p The memory to free.
|
|
*/
|
|
void mmosal_free(void *p);
|
|
|
|
/**
|
|
* Equivalent of standard library realloc().
|
|
*
|
|
* @param ptr Previously allocated memory block to resize.
|
|
* @param size The new size.
|
|
*
|
|
* @returns pointer to the resized block of memory, or @c NULL.
|
|
*/
|
|
void *mmosal_realloc(void *ptr, size_t size);
|
|
|
|
/**
|
|
* Equivalent of standard library calloc().
|
|
*
|
|
* @param nitems Number of blocks to allocate
|
|
* @param size Size of each block.
|
|
*
|
|
* @returns pointer to the allocated memory on success, or NULL on failure.
|
|
*/
|
|
void *mmosal_calloc(size_t nitems, size_t size);
|
|
|
|
#ifndef MMOSAL_TRACK_ALLOCATIONS
|
|
/**
|
|
* Allocate memory of the given size and return a pointer to it (malloc).
|
|
*
|
|
* No guarantees made about initialization.
|
|
*
|
|
* @param size The amount of memory to allocate (in bytes).
|
|
*
|
|
* @returns pointer to the allocated memory on success, or NULL on failure.
|
|
*/
|
|
#define mmosal_malloc(size) mmosal_malloc_(size)
|
|
#else
|
|
/* Note: we use function name because it should be shorter than the full filename path. */
|
|
/**
|
|
* Allocate memory of the given size and return a pointer to it (malloc).
|
|
*
|
|
* No guarantees made about initialization.
|
|
*
|
|
* @param size The amount of memory to allocate (in bytes).
|
|
*
|
|
* @returns pointer to the allocated memory on success, or NULL on failure.
|
|
*/
|
|
#define mmosal_malloc(size) mmosal_malloc_dbg(size, __FUNCTION__, __LINE__)
|
|
#endif
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/*
|
|
* ---------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* @defgroup MMOSAL_TASKS Task (thread) management
|
|
*
|
|
* Provides memory management functionality managing tasks (create, destroy, yield, etc.).
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Type definition for task main functions.
|
|
*
|
|
* @param arg Opaque argument passed in at task creation.
|
|
*/
|
|
typedef void (*mmosal_task_fn_t)(void *arg);
|
|
|
|
/** Enumeration of task priorities (ordered lowest to highest). */
|
|
enum mmosal_task_priority {
|
|
/** Idle task priority. */
|
|
MMOSAL_TASK_PRI_IDLE,
|
|
/** Minimum priority. */
|
|
MMOSAL_TASK_PRI_MIN,
|
|
/** Low priority. */
|
|
MMOSAL_TASK_PRI_LOW,
|
|
/** Normal priority. */
|
|
MMOSAL_TASK_PRI_NORM,
|
|
/** High priority. */
|
|
MMOSAL_TASK_PRI_HIGH,
|
|
};
|
|
|
|
/**
|
|
* Create a new task.
|
|
*
|
|
* @param task_fn Task main function.
|
|
* @param argument Argument to pass to main function.
|
|
* @param priority Task priority.
|
|
* @param stack_size_u32 Size of stack to allocate for task (in units of 32 bit words).
|
|
* @param name Name to give the task.
|
|
*
|
|
* @returns an opaque task handle, or @c NULL on failure.
|
|
*/
|
|
struct mmosal_task *mmosal_task_create(mmosal_task_fn_t task_fn, void *argument, enum mmosal_task_priority priority,
|
|
unsigned stack_size_u32, const char *name);
|
|
|
|
/**
|
|
* Delete the given task.
|
|
*
|
|
* @param task Handle of the task to delete (or NULL to delete the current task).
|
|
*
|
|
* @note With FreeRTOS deleted tasks will not be cleaned up until the idle task runs.
|
|
*/
|
|
void mmosal_task_delete(struct mmosal_task *task);
|
|
|
|
/**
|
|
* Block until the given task has terminated.
|
|
*
|
|
* @param task Handle of the task to wait for.
|
|
*
|
|
* @note With FreeRTOS deleted tasks will not be cleaned up until the idle task runs.
|
|
*
|
|
* @deprecated Do not invoke this function because it is deprecated and will be removed from
|
|
* the mmosal API in a future release.
|
|
*/
|
|
void mmosal_task_join(struct mmosal_task *task);
|
|
|
|
/**
|
|
* Get the handle of the active task.
|
|
*
|
|
* @returns the handle of the active task.
|
|
*/
|
|
struct mmosal_task *mmosal_task_get_active(void);
|
|
|
|
/**
|
|
* Yield the active task.
|
|
*/
|
|
void mmosal_task_yield(void);
|
|
|
|
/**
|
|
* Sleep for a period of time, yielding during that time.
|
|
*
|
|
* @param duration_ms Sleep duration, in milliseconds.
|
|
*/
|
|
void mmosal_task_sleep(uint32_t duration_ms);
|
|
|
|
/**
|
|
* Enter critical section.
|
|
*
|
|
* This may result in interrupts being disabled so critical sections must be kept short.
|
|
* Each entry to a critical section must be matched to a corresponding exit
|
|
* (@ref MMOSAL_TASK_EXIT_CRITICAL()).
|
|
*/
|
|
#define MMOSAL_TASK_ENTER_CRITICAL() \
|
|
do { \
|
|
MMPORT_MEM_SYNC(); \
|
|
mmosal_task_enter_critical(); \
|
|
} while (0)
|
|
|
|
/**
|
|
* Exit critical section.
|
|
*
|
|
* Used to exit a critical section previously entered with @ref MMOSAL_TASK_ENTER_CRITICAL()).
|
|
*/
|
|
#define MMOSAL_TASK_EXIT_CRITICAL() \
|
|
do { \
|
|
MMPORT_MEM_SYNC(); \
|
|
mmosal_task_exit_critical(); \
|
|
} while (0)
|
|
|
|
/**
|
|
* Enter critical section.
|
|
*
|
|
* This may result in interrupts being disabled so critical sections must be kept short.
|
|
* Each entry to a critical section must be matched to a corresponding exit
|
|
* (@ref mmosal_task_exit_critical()).
|
|
*
|
|
* @note This function should not be invoked directly. Use @ref MMOSAL_TASK_ENTER_CRITICAL().
|
|
*/
|
|
void mmosal_task_enter_critical(void);
|
|
|
|
/**
|
|
* Exit critical section.
|
|
*
|
|
* Used to exit a critical section previously entered with @ref mmosal_task_enter_critical()).
|
|
*
|
|
* @note This function should not be invoked directly. Use @ref MMOSAL_TASK_EXIT_CRITICAL().
|
|
*/
|
|
void mmosal_task_exit_critical(void);
|
|
|
|
/**
|
|
* Disable interrupts.
|
|
*
|
|
* @warning This function should generally not be used. Use @ref mmosal_task_enter_critical()
|
|
* instead.
|
|
*/
|
|
void mmosal_disable_interrupts(void);
|
|
|
|
/**
|
|
* Enable interrupts.
|
|
*
|
|
* @warning This function should generally not be used. Use @ref mmosal_task_exit_critical()
|
|
* instead.
|
|
*/
|
|
void mmosal_enable_interrupts(void);
|
|
|
|
/**
|
|
* Get the name of the running task.
|
|
*
|
|
* @returns the name of the running task.
|
|
*/
|
|
const char *mmosal_task_name(void);
|
|
|
|
/**
|
|
* Blocks the current task until a notification is received.
|
|
*
|
|
* Notifications can be sent using @ref mmosal_task_notify() or @ref mmosal_task_notify_from_isr().
|
|
*
|
|
* @param timeout_ms The time to wait before giving up (or @c UINT32_MAX to wait forever).
|
|
*
|
|
* @returns @c true of a notification was received or @c false if it timed out.
|
|
*
|
|
* @see mmosal_task_notify()
|
|
* @see mmosal_task_notify_from_isr()
|
|
*/
|
|
bool mmosal_task_wait_for_notification(uint32_t timeout_ms);
|
|
|
|
/**
|
|
* Notifies a waiting task (@ref mmosal_task_wait_for_notification()) that it can continue.
|
|
*
|
|
* @warning Must not be called from ISR context.
|
|
*
|
|
* @param task Handle of the task to notify.
|
|
*
|
|
* @see mmosal_task_wait_for_notification()
|
|
*/
|
|
void mmosal_task_notify(struct mmosal_task *task);
|
|
|
|
/**
|
|
* Notifies a waiting task (@ref mmosal_task_wait_for_notification()) that it can continue.
|
|
*
|
|
* @warning Must only be called from ISR context.
|
|
*
|
|
* @param task Handle of the task to notify.
|
|
*
|
|
* @see mmosal_task_wait_for_notification()
|
|
*/
|
|
void mmosal_task_notify_from_isr(struct mmosal_task *task);
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/*
|
|
* ---------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* @defgroup MMOSAL_MUTEX Mutex
|
|
*
|
|
* Provides mutex support for mutual exclusion.
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Create a new mutex.
|
|
*
|
|
* @param name The name for the mutex.
|
|
*
|
|
* @returns an opaque handle to the mutex, or @c NULL on failure.
|
|
*/
|
|
struct mmosal_mutex *mmosal_mutex_create(const char *name);
|
|
|
|
/**
|
|
* Delete a mutex.
|
|
*
|
|
* @param mutex Handle of mutex to delete
|
|
*/
|
|
void mmosal_mutex_delete(struct mmosal_mutex *mutex);
|
|
|
|
/**
|
|
* Acquire a mutex.
|
|
*
|
|
* @param mutex Handle of mutex to acquire.
|
|
* @param timeout_ms Timeout after which to give up. To wait infinitely use @c UINT32_MAX.
|
|
*
|
|
* @returns @c true if the mutex was acquired successfully otherwise @c false.
|
|
*/
|
|
bool mmosal_mutex_get(struct mmosal_mutex *mutex, uint32_t timeout_ms);
|
|
|
|
/**
|
|
* Release a mutex.
|
|
*
|
|
* @param mutex Handle of mutex to release.
|
|
*
|
|
* @returns @c true if the mutex was released successfully otherwise @c false.
|
|
*/
|
|
bool mmosal_mutex_release(struct mmosal_mutex *mutex);
|
|
|
|
/**
|
|
* Attempt to get a mutex, waiting infinitely long for it. Panics on failure.
|
|
*/
|
|
#define MMOSAL_MUTEX_GET_INF(_mutex) \
|
|
do { \
|
|
bool ok__ = mmosal_mutex_get((_mutex), UINT32_MAX); \
|
|
MMOSAL_ASSERT(ok__); \
|
|
} while (0)
|
|
|
|
/**
|
|
* Same as @ref mmosal_mutex_release() except it panics on failure.
|
|
*/
|
|
#define MMOSAL_MUTEX_RELEASE(_mutex) \
|
|
do { \
|
|
bool ok__ = mmosal_mutex_release(_mutex); \
|
|
MMOSAL_ASSERT(ok__); \
|
|
} while (0)
|
|
|
|
/**
|
|
* Check whether the given mutex is held by the active thread.
|
|
*
|
|
* @param mutex Handle of the mutex to check.
|
|
*
|
|
* @returns @c true if the mutex is held by the active thread, else @c false.
|
|
*/
|
|
bool mmosal_mutex_is_held_by_active_task(struct mmosal_mutex *mutex);
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/*
|
|
* ---------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* @defgroup MMOSAL_SEM Counting semaphores
|
|
*
|
|
* Provides counting semaphore support for task synchronization.
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Create a new counting semaphore.
|
|
*
|
|
* @param max_count The maximum count (i.e., number of times the semaphore can be given).
|
|
* @param initial_count The initial count (i.e., number of times the semaphore is implicitly
|
|
* given when it is created).
|
|
* @param name The name of the semaphore.
|
|
*
|
|
* @returns an opaque handle to the semaphore, or @c NULL on failure.
|
|
*/
|
|
struct mmosal_sem *mmosal_sem_create(unsigned max_count, unsigned initial_count, const char *name);
|
|
|
|
/**
|
|
* Delete the given counting semaphore.
|
|
*
|
|
* @param sem Semaphore to delete.
|
|
*/
|
|
void mmosal_sem_delete(struct mmosal_sem *sem);
|
|
|
|
/**
|
|
* Give a counting semaphore.
|
|
*
|
|
* @warning May not be invoked from an ISR.
|
|
*
|
|
* @param sem The semaphore to give.
|
|
*
|
|
* @returns @c true on success, else @c false.
|
|
*/
|
|
bool mmosal_sem_give(struct mmosal_sem *sem);
|
|
|
|
/**
|
|
* Give a counting semaphore (from ISR context).
|
|
*
|
|
* @warning May only be invoked from an ISR.
|
|
*
|
|
* @param sem The semaphore to give.
|
|
*
|
|
* @returns @c true on success, else @c false.
|
|
*/
|
|
bool mmosal_sem_give_from_isr(struct mmosal_sem *sem);
|
|
|
|
/**
|
|
* Wait for a counting semaphore.
|
|
*
|
|
* @param sem The semaphore to wait for.
|
|
* @param timeout_ms Timeout after which to give up waiting (in milliseconds).
|
|
*
|
|
* @returns @c true if the the semaphore was taken successfully, else @c false.
|
|
*/
|
|
bool mmosal_sem_wait(struct mmosal_sem *sem, uint32_t timeout_ms);
|
|
|
|
/**
|
|
* Returns the current count of the semaphore.
|
|
*
|
|
* @param sem The semaphore being queried.
|
|
*
|
|
* @returns The count of the semaphore being queried.
|
|
*/
|
|
uint32_t mmosal_sem_get_count(struct mmosal_sem *sem);
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/*
|
|
* ---------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* @defgroup MMOSAL_SEMB Binary semaphores
|
|
*
|
|
* Provides binary semaphore support for task synchronization.
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Create a new binary semaphore.
|
|
*
|
|
* @param name The name of the semaphore.
|
|
*
|
|
* @returns an opaque handle to the semaphore, or @c NULL on failure.
|
|
*/
|
|
struct mmosal_semb *mmosal_semb_create(const char *name);
|
|
|
|
/**
|
|
* Delete the given binary semaphore.
|
|
*
|
|
* @param semb Semaphore to delete.
|
|
*/
|
|
void mmosal_semb_delete(struct mmosal_semb *semb);
|
|
|
|
/**
|
|
* Give a binary semaphore.
|
|
*
|
|
* @warning May not be invoked from an ISR.
|
|
*
|
|
* @param semb The semaphore to give.
|
|
*
|
|
* @returns @c true on success, else @c false.
|
|
*/
|
|
bool mmosal_semb_give(struct mmosal_semb *semb);
|
|
|
|
/**
|
|
* Give a binary semaphore (from ISR context).
|
|
*
|
|
* @warning May only be invoked from an ISR.
|
|
*
|
|
* @param semb The semaphore to give.
|
|
*
|
|
* @returns @c true on success, else @c false.
|
|
*/
|
|
bool mmosal_semb_give_from_isr(struct mmosal_semb *semb);
|
|
|
|
/**
|
|
* Wait for a counting semaphore.
|
|
*
|
|
* @param semb The semaphore to wait for.
|
|
* @param timeout_ms Timeout after which to give up waiting (in milliseconds).
|
|
*
|
|
* @returns @c true if the the semaphore was taken successfully, else @c false.
|
|
*/
|
|
bool mmosal_semb_wait(struct mmosal_semb *semb, uint32_t timeout_ms);
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/*
|
|
* ---------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* @defgroup MMOSAL_QUEUE Queues (aka pipes)
|
|
*
|
|
* Provides queue support for inter-task communication.
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Create a new queue.
|
|
*
|
|
* @param num_items The maximum number of items that may be in the queue at a time.
|
|
* @param item_size The size of each item in the queue.
|
|
* @param name The name of the queue.
|
|
*
|
|
* @returns an opaque handle to the queue, or @c NULL on failure.
|
|
*/
|
|
struct mmosal_queue *mmosal_queue_create(size_t num_items, size_t item_size, const char *name);
|
|
|
|
/**
|
|
* Delete a queue.
|
|
*
|
|
* @param queue handle of the queue to delete.
|
|
*/
|
|
void mmosal_queue_delete(struct mmosal_queue *queue);
|
|
|
|
/**
|
|
* Pop an item from the queue.
|
|
*
|
|
* @warning May not be invoked from an ISR.
|
|
*
|
|
* @param queue The queue to pop from.
|
|
* @param item Pointer to memory to receive the popped item. The item will be copied into
|
|
* this memory. The memory size must match the @c item_size given at creation.
|
|
* @param timeout_ms Timeout after which to give up waiting for an item if the queue is empty
|
|
* (in milliseconds).
|
|
*
|
|
* @returns @c true if an item was successfully popped, else @c false.
|
|
*/
|
|
bool mmosal_queue_pop(struct mmosal_queue *queue, void *item, uint32_t timeout_ms);
|
|
|
|
/**
|
|
* Push an item into the queue.
|
|
*
|
|
* @warning May not be invoked from an ISR.
|
|
*
|
|
* @param queue The queue to push to.
|
|
* @param item Pointer to the item to push. This item will be copied into the queue.
|
|
* The size of the item must match the @c item_size given at creation.
|
|
* @param timeout_ms Timeout after which to give up waiting for space if the queue is full
|
|
* (in milliseconds).
|
|
*
|
|
* @returns @c true if an item was successfully pushed, else @c false.
|
|
*/
|
|
bool mmosal_queue_push(struct mmosal_queue *queue, const void *item, uint32_t timeout_ms);
|
|
|
|
/**
|
|
* Pop an item from the queue (from ISR context).
|
|
*
|
|
* @warning May only be invoked from an ISR.
|
|
*
|
|
* @param queue The queue to pop from.
|
|
* @param item Pointer to memory to receive the popped item. The item will be copied into
|
|
* this memory. The memory size must match the @c item_size given at creation.
|
|
*
|
|
* @returns @c true if an item was successfully popped, else @c false.
|
|
*/
|
|
bool mmosal_queue_pop_from_isr(struct mmosal_queue *queue, void *item);
|
|
|
|
/**
|
|
* Push an item into the queue (from ISR context).
|
|
*
|
|
* @warning May only be invoked from an ISR.
|
|
*
|
|
* @param queue The queue to push to.
|
|
* @param item Pointer to the item to push. This item will be copied into the queue.
|
|
* The size of the item must match the @c item_size given at creation.
|
|
*
|
|
* @returns @c true if an item was successfully pushed, else @c false.
|
|
*/
|
|
bool mmosal_queue_push_from_isr(struct mmosal_queue *queue, const void *item);
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/*
|
|
* ---------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* @defgroup MMOSAL_TIME Time
|
|
*
|
|
* Provides support for reading the system time.
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Get the system time in milliseconds.
|
|
*
|
|
* @returns the system time in milliseconds.
|
|
*/
|
|
uint32_t mmosal_get_time_ms(void);
|
|
|
|
/**
|
|
* Get the system time in ticks.
|
|
*
|
|
* @returns the system time in ticks.
|
|
*/
|
|
uint32_t mmosal_get_time_ticks(void);
|
|
|
|
/**
|
|
* Get the number of ticks in a second.
|
|
*
|
|
* @returns the number of ticks in a second.
|
|
*/
|
|
uint32_t mmosal_ticks_per_second(void);
|
|
|
|
/**
|
|
* Check if time a is less than time b, taking into account wrapping.
|
|
*
|
|
* | a | b | return |
|
|
* |---------------|---------------|--------|
|
|
* | 0 | 0 | false |
|
|
* | 0 | 1 | true |
|
|
* | 1 | 0 | false |
|
|
* | @c 0xffffffff | 0 | true |
|
|
* | 0 | @c 0xffffffff | false |
|
|
*
|
|
*
|
|
* @param a time a
|
|
* @param b time b
|
|
*
|
|
* @returns true if time a < time b.
|
|
*/
|
|
static inline bool mmosal_time_lt(uint32_t a, uint32_t b)
|
|
{
|
|
return ((int32_t)(a - b)) < 0;
|
|
}
|
|
|
|
/**
|
|
* Check if time a is less than or equal to time b, taking into account wrapping.
|
|
*
|
|
* | a | b | return |
|
|
* |---------------|---------------|--------|
|
|
* | 0 | 0 | true |
|
|
* | 0 | 1 | true |
|
|
* | 1 | 0 | false |
|
|
* | @c 0xffffffff | 0 | true |
|
|
* | 0 | @c 0xffffffff | false |
|
|
*
|
|
*
|
|
* @param a time a
|
|
* @param b time b
|
|
*
|
|
* @returns true if time a <= time b.
|
|
*/
|
|
static inline bool mmosal_time_le(uint32_t a, uint32_t b)
|
|
{
|
|
return ((int32_t)(a - b)) <= 0;
|
|
}
|
|
|
|
/**
|
|
* Given two times, return the one that is greatest (taking into account wrapping).
|
|
*
|
|
* | a | b | return |
|
|
* |---------------|---------------|--------|
|
|
* | 0 | 0 | 0 |
|
|
* | 0 | 1 | 1 |
|
|
* | 1 | 0 | 1 |
|
|
* | @c 0xffffffff | 0 | 0 |
|
|
* | 0 | @c 0xffffffff | 0 |
|
|
*
|
|
* @param a time a
|
|
* @param b time b
|
|
*
|
|
* @returns a if time a >= time b else b.
|
|
*/
|
|
static inline uint32_t mmosal_time_max(uint32_t a, uint32_t b)
|
|
{
|
|
if (mmosal_time_lt(a, b)) {
|
|
return b;
|
|
} else {
|
|
return a;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if the given time has already passed. i.e the system time is greater than the given time.
|
|
*
|
|
* @param t The time to check.
|
|
*
|
|
* @return @c true if the given time has passed, else @c false.
|
|
*/
|
|
static inline bool mmosal_time_has_passed(uint32_t t)
|
|
{
|
|
return mmosal_time_le(t, mmosal_get_time_ms());
|
|
}
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/*
|
|
* ---------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* @defgroup MMOSAL_TIMER Timers
|
|
*
|
|
* Provides support for RTOS timers.
|
|
*
|
|
* @note The timer service must have a priority higher than @ref MMOSAL_TASK_PRI_HIGH. This is
|
|
* because tasks may yield to allow the timer service to execute. In some RTOS implementations
|
|
* if there are no other tasks at a higher or equal priority to the task that calls @ref
|
|
* mmosal_task_yield() then the RTOS scheduler will simply select the task that called
|
|
* @ref mmosal_task_yield() to run again.
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
/** Timer opaque handler data type. */
|
|
struct mmosal_timer;
|
|
|
|
/**
|
|
* Function type definition for timer callbacks.
|
|
*
|
|
* @param timer The timer that triggered the callback.
|
|
*/
|
|
typedef void (*timer_callback_t)(struct mmosal_timer *timer);
|
|
|
|
/**
|
|
* Create a new timer.
|
|
*
|
|
* @param name The name of the timer.
|
|
* @param timer_period_ms The period of the timer in milliseconds.
|
|
* @param auto_reload If @c true then the timer will automatically be reloaded when
|
|
* it expires.
|
|
* @param arg Void pointer that can be used to store a value for the timer callback.
|
|
* Pass NULL if unused.
|
|
* @param callback Callback to be triggered when the timer expires.
|
|
*
|
|
* @returns an opaque handle to the timer, or @c NULL on failure.
|
|
*
|
|
* @warning Ensure that the timer callback function does not block or cause the calling task to
|
|
* be placed in a blocked state.
|
|
*/
|
|
struct mmosal_timer *mmosal_timer_create(const char *name, uint32_t timer_period_ms, bool auto_reload, void *arg,
|
|
timer_callback_t callback);
|
|
|
|
/**
|
|
* Delete a timer.
|
|
*
|
|
* @param timer The timer to delete.
|
|
*/
|
|
void mmosal_timer_delete(struct mmosal_timer *timer);
|
|
|
|
/**
|
|
* Start a timer.
|
|
*
|
|
* @param timer The timer to start.
|
|
*
|
|
* @returns @c true if the timer was started successfully, else @c false.
|
|
*/
|
|
bool mmosal_timer_start(struct mmosal_timer *timer);
|
|
|
|
/**
|
|
* Stop a timer.
|
|
*
|
|
* @param timer The timer to stop.
|
|
*
|
|
* @returns @c true if the timer was stopped successfully, else @c false.
|
|
*/
|
|
bool mmosal_timer_stop(struct mmosal_timer *timer);
|
|
|
|
/**
|
|
* Change timer period.
|
|
*
|
|
* @warning May not be invoked from an ISR.
|
|
*
|
|
* @param timer The timer to assign the new period.
|
|
* @param new_period Period to assign to the timer.
|
|
*
|
|
* @returns @c true if the timer period was stopped change, else @c false.
|
|
*/
|
|
bool mmosal_timer_change_period(struct mmosal_timer *timer, uint32_t new_period);
|
|
|
|
/**
|
|
* Get the opaque argument associated with a given timer.
|
|
*
|
|
* @param timer The timer to retrieve the argument from.
|
|
*
|
|
* @returns void pointer to the argument.
|
|
*/
|
|
void *mmosal_timer_get_arg(struct mmosal_timer *timer);
|
|
|
|
/**
|
|
* Queries the timer to determine if it running.
|
|
*
|
|
* @param timer The timer to retrieve the argument from.
|
|
*
|
|
* @returns @c true if the timer is running, else @c false.
|
|
*/
|
|
bool mmosal_is_timer_active(struct mmosal_timer *timer);
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/*
|
|
* ---------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* @defgroup MMOSAL_ASSERT Assertions and failure handling
|
|
*
|
|
* Provides support for assertions and logging failure data.
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
#ifndef MMOSAL_FILEID
|
|
/** File identifier: if not provided by compiler then define to zero. */
|
|
#define MMOSAL_FILEID 0
|
|
#endif
|
|
|
|
/** Data structure used to store information about a failure that can be preserved across reset. */
|
|
struct mmosal_failure_info {
|
|
/** Content of the PC register at assertion. */
|
|
uint32_t pc;
|
|
/** Content of the LR register at assertion. */
|
|
uint32_t lr;
|
|
/** File identifier. */
|
|
uint32_t fileid;
|
|
/** Source code line at which the assertion was triggered. */
|
|
uint32_t line;
|
|
/** Arbitrary platform-specific failure info.
|
|
* Will be zeroes in the case of assertion failure. */
|
|
uint32_t platform_info[4];
|
|
};
|
|
|
|
/**
|
|
* Log failure information in a way that it is preserved across reboots so that it can be
|
|
* available for postmortem analysis.
|
|
*
|
|
* @param info Failure information to log.
|
|
*/
|
|
void mmosal_log_failure_info(const struct mmosal_failure_info *info);
|
|
|
|
#ifdef MMOSAL_NO_DEBUGLOG
|
|
/** Empty logging handler. */
|
|
#define MMOSAL_LOG_FAILURE_INFO(...)
|
|
#else
|
|
/** Initialize a mmosal_failure_info struct based on current state and invoke
|
|
* mmosal_log_failure_info(). */
|
|
#define MMOSAL_LOG_FAILURE_INFO(...) \
|
|
do { \
|
|
void *pc; \
|
|
struct mmosal_failure_info info = { \
|
|
.lr = (uint32_t)MMPORT_GET_LR(), \
|
|
.fileid = MMOSAL_FILEID, \
|
|
.line = __LINE__, \
|
|
.platform_info = {__VA_ARGS__}, \
|
|
}; \
|
|
MMPORT_GET_PC(pc); \
|
|
info.pc = (uint32_t)pc; \
|
|
mmosal_log_failure_info(&info); \
|
|
} while (0)
|
|
#endif
|
|
|
|
/**
|
|
* Assertion handler implementation.
|
|
*
|
|
* @note This function does not return.
|
|
*/
|
|
void mmosal_impl_assert(void);
|
|
|
|
#ifndef MMOSAL_NOASSERT
|
|
/**
|
|
* Assert that the given expression evaluates to true and abort execution if not.
|
|
*
|
|
* @param expr Expression to evaluation. If it evaluates to @c false then the assertion handler
|
|
* will be triggered.
|
|
*/
|
|
#ifndef MMOSAL_ASSERT
|
|
#define MMOSAL_ASSERT(expr) \
|
|
do { \
|
|
if (!(expr)) { \
|
|
MMOSAL_LOG_FAILURE_INFO(0); \
|
|
mmosal_impl_assert(); \
|
|
while (1) { \
|
|
} \
|
|
} \
|
|
} while (0)
|
|
#endif
|
|
|
|
/**
|
|
* Assert that the given expression evaluates to true and abort execution if not.
|
|
*
|
|
* @param expr Expression to evaluation. If it evaluates to @c false then the assertion handler
|
|
* will be triggered.
|
|
* @param ... Up to 4 32-bit unsigned integers to log.
|
|
*/
|
|
#ifndef MMOSAL_ASSERT_LOG_DATA
|
|
#define MMOSAL_ASSERT_LOG_DATA(expr, ...) \
|
|
do { \
|
|
if (!(expr)) { \
|
|
MMOSAL_LOG_FAILURE_INFO(__VA_ARGS__); \
|
|
mmosal_impl_assert(); \
|
|
while (1) { \
|
|
} \
|
|
} \
|
|
} while (0)
|
|
#endif
|
|
#else
|
|
/** Empty assertion handler. */
|
|
#define MMOSAL_ASSERT(expr) (void)(expr)
|
|
/** Empty assertion handler. */
|
|
#define MMOSAL_ASSERT_LOG_DATA(expre, ...) (void)(expr)
|
|
#endif
|
|
|
|
/** @} */
|
|
|
|
/**
|
|
* @defgroup MMOSAL_MISC Miscellaneous functions
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* A safer version of @c strncpy.
|
|
*
|
|
* Up to `size - 1` bytes will be copied from @p src to @p dst and the result will be
|
|
* null-terminated.
|
|
*
|
|
* @param dst The buffer to copy the string into.
|
|
* @param src The source string. This must be null-terminated.
|
|
* @param size The size of the @p dst buffer.
|
|
*
|
|
* @returns true if the string was truncated else false (note that a size of 0 will always result
|
|
* this function returning true).
|
|
*/
|
|
static inline bool mmosal_safer_strcpy(char *dst, const char *src, size_t size)
|
|
{
|
|
bool ret;
|
|
|
|
if (size == 0) {
|
|
return true;
|
|
}
|
|
|
|
strncpy(dst, src, size);
|
|
|
|
ret = dst[size - 1] != '\0';
|
|
dst[size - 1] = '\0';
|
|
return ret;
|
|
}
|
|
|
|
/** @} */
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
/** @} */
|