Implement UI scaling and more (#501)
**New Features** * Runtime font accessors and new symbol fonts for text, launcher, statusbar, and shared icons. * Added font height base setting to device.properties * Text fonts now have 3 sizes: small, default, large **Improvements** * Renamed `UiScale` to `UiDensity` * Statusbar, toolbar and many UI components now compute heights and spacing from fonts/density. * SSD1306 initialization sequence refined for more stable startup. * Multiple image assets replaced by symbol-font rendering. * Many layout improvements related to density, font scaling and icon scaling * Updated folder name capitalization for newer style
This commit is contained in:
committed by
GitHub
parent
72c9b2b113
commit
9a11e6f47b
@@ -0,0 +1,10 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Creates required aliases for the devicetree generation.
|
||||
* @param compatible_name the "compatible" value for the related driver
|
||||
* @param config_type the internal configuration type for a device
|
||||
*/
|
||||
#define DEFINE_DEVICETREE(compatible_name, config_type) typedef config_type compatible_name##_config_dt;
|
||||
@@ -0,0 +1,5 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <tactility/drivers/gpio.h>
|
||||
@@ -0,0 +1,9 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <tactility/bindings/bindings.h>
|
||||
#include <tactility/drivers/root.h>
|
||||
|
||||
DEFINE_DEVICETREE(root, struct RootConfig)
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <tactility/log.h>
|
||||
|
||||
__attribute__((noreturn)) extern void __crash(void);
|
||||
|
||||
#define CHECK_GET_MACRO(_1, _2, NAME, ...) NAME
|
||||
#define check(...) CHECK_GET_MACRO(__VA_ARGS__, CHECK_MSG, CHECK_NO_MSG)(__VA_ARGS__)
|
||||
|
||||
#define CHECK_NO_MSG(condition) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
LOG_E("Error", "Check failed: %s\n\tat %s:%d", #condition, __FILE__, __LINE__); \
|
||||
__crash(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_MSG(condition, message) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
LOG_E("Error", "Check failed: %s\n\tat %s:%d", message, __FILE__, __LINE__); \
|
||||
__crash(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,78 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/**
|
||||
* Dispatcher is a thread-safe code execution queue.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <tactility/freertos/freertos.h>
|
||||
#include <tactility/error.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*DispatcherCallback)(void* context);
|
||||
typedef void* DispatcherHandle_t;
|
||||
|
||||
DispatcherHandle_t dispatcher_alloc(void);
|
||||
|
||||
void dispatcher_free(DispatcherHandle_t dispatcher);
|
||||
|
||||
/**
|
||||
* Queue a function to be consumed elsewhere.
|
||||
*
|
||||
* @param[in] callbackContext the data to pass to the function upon execution
|
||||
* @param[in] callback the function to execute elsewhere
|
||||
* @param[in] timeout lock acquisition timeout
|
||||
* @retval ERROR_TIMEOUT
|
||||
* @retval ERROR_RESOURCE when failing to set event
|
||||
* @retval ERROR_INVALID_STATE when the dispatcher is in the process of shutting down
|
||||
* @retval ERROR_NONE
|
||||
*/
|
||||
error_t dispatcher_dispatch_timed(DispatcherHandle_t dispatcher, void* callbackContext, DispatcherCallback callback, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* Queue a function to be consumed elsewhere.
|
||||
*
|
||||
* @param[in] callbackContext the data to pass to the function upon execution
|
||||
* @param[in] callback the function to execute elsewhere
|
||||
* @retval ERROR_RESOURCE when failing to set event
|
||||
* @retval ERROR_TIMEOUT unlikely to occur unless there's an issue with the internal mutex
|
||||
* @retval ERROR_INVALID_STATE when the dispatcher is in the process of shutting down
|
||||
* @retval ERROR_NONE
|
||||
*/
|
||||
static inline error_t dispatcher_dispatch(DispatcherHandle_t dispatcher, void* callbackContext, DispatcherCallback callback) {
|
||||
return dispatcher_dispatch_timed(dispatcher, callbackContext, callback, portMAX_DELAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume 1 or more dispatched functions (if any) until the queue is empty.
|
||||
*
|
||||
* @warning The timeout is only the wait time before consuming the message! It is not a limit to the total execution time when calling this method.
|
||||
*
|
||||
* @param[in] timeout the ticks to wait for a message
|
||||
* @retval ERROR_TIMEOUT
|
||||
* @retval ERROR_RESOURCE failed to wait for event
|
||||
* @retval ERROR_INVALID_STATE when the dispatcher is in the process of shutting down
|
||||
* @retval ERROR_NONE
|
||||
*/
|
||||
error_t dispatcher_consume_timed(DispatcherHandle_t dispatcher, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* Consume 1 or more dispatched functions (if any) until the queue is empty.
|
||||
*
|
||||
* @warning The timeout is only the wait time before consuming the message! It is not a limit to the total execution time when calling this method.
|
||||
*
|
||||
* @retval ERROR_TIMEOUT unlikely to occur unless there's an issue with the internal mutex
|
||||
* @retval ERROR_RESOURCE failed to wait for event
|
||||
* @retval ERROR_INVALID_STATE when the dispatcher is in the process of shutting down
|
||||
* @retval ERROR_NONE
|
||||
*/
|
||||
static inline error_t dispatcher_consume(DispatcherHandle_t dispatcher) {
|
||||
return dispatcher_consume_timed(dispatcher, portMAX_DELAY);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,78 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <tactility/freertos/event_groups.h>
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/error.h>
|
||||
|
||||
static inline void event_group_construct(EventGroupHandle_t* eventGroup) {
|
||||
check(xPortInIsrContext() == pdFALSE);
|
||||
*eventGroup = xEventGroupCreate();
|
||||
}
|
||||
|
||||
static inline void event_group_destruct(EventGroupHandle_t* eventGroup) {
|
||||
check(xPortInIsrContext() == pdFALSE);
|
||||
check(*eventGroup != NULL);
|
||||
vEventGroupDelete(*eventGroup);
|
||||
*eventGroup = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the flags.
|
||||
*
|
||||
* @param[in] eventGroup the event group
|
||||
* @param[in] flags the flags to set
|
||||
* @retval ERROR_RESOURCE when setting failed
|
||||
* @retval ERROR_NONE
|
||||
*/
|
||||
error_t event_group_set(EventGroupHandle_t eventGroup, uint32_t flags);
|
||||
|
||||
/**
|
||||
* Clear flags
|
||||
*
|
||||
* @param[in] eventGroup the event group
|
||||
* @param[in] flags the flags to clear
|
||||
* @retval ERROR_RESOURCE when clearing failed
|
||||
* @retval ERROR_NONE
|
||||
*/
|
||||
error_t event_group_clear(EventGroupHandle_t eventGroup, uint32_t flags);
|
||||
|
||||
/**
|
||||
* @param[in] eventGroup the event group
|
||||
* @return the bitset (always succeeds)
|
||||
*/
|
||||
uint32_t event_group_get(EventGroupHandle_t eventGroup);
|
||||
|
||||
/**
|
||||
* Wait for flags to be set
|
||||
*
|
||||
* @param[in] eventGroup the event group
|
||||
* @param[in] inFlags the flags to await
|
||||
* @param[in] awaitAll If true, await for all bits to be set. Otherwise, await for any.
|
||||
* @param[in] clearOnExit If true, clears all the bits on exit, otherwise don't clear.
|
||||
* @param[out] outFlags If set to non-NULL value, this will hold the resulting flags. Only set when return value is ERROR_NONE
|
||||
* @param[in] timeout the maximum amount of ticks to wait for flags to be set
|
||||
* @retval ERROR_ISR_STATUS when the function was called from an ISR context
|
||||
* @retval ERROR_TIMEOUT
|
||||
* @retval ERROR_RESOURCE when flags were triggered, but not in a way that was expected (e.g. waiting for all flags, but was only partially set)
|
||||
* @retval ERROR_NONE
|
||||
*/
|
||||
error_t event_group_wait(
|
||||
EventGroupHandle_t eventGroup,
|
||||
uint32_t inFlags,
|
||||
bool awaitAll,
|
||||
bool clearOnExit,
|
||||
uint32_t* outFlags,
|
||||
TickType_t timeout
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,55 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <tactility/freertos/semphr.h>
|
||||
#include <tactility/check.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Mutex {
|
||||
QueueHandle_t handle;
|
||||
// TODO: Debugging functionality
|
||||
};
|
||||
|
||||
inline static void mutex_construct(struct Mutex* mutex) {
|
||||
mutex->handle = xSemaphoreCreateMutex();
|
||||
}
|
||||
|
||||
inline static void mutex_destruct(struct Mutex* mutex) {
|
||||
vPortAssertIfInISR();
|
||||
vSemaphoreDelete(mutex->handle);
|
||||
mutex->handle = NULL;
|
||||
}
|
||||
|
||||
inline static void mutex_lock(struct Mutex* mutex) {
|
||||
check(xPortInIsrContext() != pdTRUE);
|
||||
xSemaphoreTake(mutex->handle, portMAX_DELAY);
|
||||
}
|
||||
|
||||
inline static bool mutex_try_lock(struct Mutex* mutex, TickType_t timeout) {
|
||||
check(xPortInIsrContext() != pdTRUE);
|
||||
return xSemaphoreTake(mutex->handle, timeout) == pdTRUE;
|
||||
}
|
||||
|
||||
inline static bool mutex_is_locked(struct Mutex* mutex) {
|
||||
if (xPortInIsrContext() == pdTRUE) {
|
||||
return xSemaphoreGetMutexHolderFromISR(mutex->handle) != NULL;
|
||||
} else {
|
||||
return xSemaphoreGetMutexHolder(mutex->handle) != NULL;
|
||||
}
|
||||
}
|
||||
|
||||
inline static void mutex_unlock(struct Mutex* mutex) {
|
||||
check(xPortInIsrContext() != pdTRUE);
|
||||
xSemaphoreGive(mutex->handle);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <tactility/freertos/semphr.h>
|
||||
#include <tactility/check.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct RecursiveMutex {
|
||||
QueueHandle_t handle;
|
||||
// TODO: Debugging functionality
|
||||
};
|
||||
|
||||
inline static void recursive_mutex_construct(struct RecursiveMutex* mutex) {
|
||||
mutex->handle = xSemaphoreCreateRecursiveMutex();
|
||||
}
|
||||
|
||||
inline static void recursive_mutex_destruct(struct RecursiveMutex* mutex) {
|
||||
check(xPortInIsrContext() != pdTRUE);
|
||||
vSemaphoreDelete(mutex->handle);
|
||||
mutex->handle = NULL;
|
||||
}
|
||||
|
||||
inline static void recursive_mutex_lock(struct RecursiveMutex* mutex) {
|
||||
check(xPortInIsrContext() != pdTRUE);
|
||||
xSemaphoreTakeRecursive(mutex->handle, portMAX_DELAY);
|
||||
}
|
||||
|
||||
inline static bool recursive_mutex_is_locked(struct RecursiveMutex* mutex) {
|
||||
if (xPortInIsrContext() == pdTRUE) {
|
||||
return xSemaphoreGetMutexHolderFromISR(mutex->handle) != NULL;
|
||||
} else {
|
||||
return xSemaphoreGetMutexHolder(mutex->handle) != NULL;
|
||||
}
|
||||
}
|
||||
|
||||
inline static bool recursive_mutex_try_lock(struct RecursiveMutex* mutex, TickType_t timeout) {
|
||||
check(xPortInIsrContext() != pdTRUE);
|
||||
return xSemaphoreTakeRecursive(mutex->handle, timeout) == pdTRUE;
|
||||
}
|
||||
|
||||
inline static void recursive_mutex_unlock(struct RecursiveMutex* mutex) {
|
||||
check(xPortInIsrContext() != pdTRUE);
|
||||
xSemaphoreGiveRecursive(mutex->handle);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,182 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include "tactility/error.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <esp_log.h>
|
||||
#endif
|
||||
|
||||
#include <tactility/freertos/task.h>
|
||||
#include <tactility/concurrent/mutex.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum {
|
||||
THREAD_STATE_STOPPED,
|
||||
THREAD_STATE_STARTING,
|
||||
THREAD_STATE_RUNNING,
|
||||
} ThreadState;
|
||||
|
||||
/** ThreadPriority */
|
||||
enum ThreadPriority {
|
||||
THREAD_PRIORITY_NONE = 0U,
|
||||
THREAD_PRIORITY_IDLE = 1U,
|
||||
THREAD_PRIORITY_LOWER = 2U,
|
||||
THREAD_PRIORITY_LOW = 3U,
|
||||
THREAD_PRIORITY_NORMAL = 4U,
|
||||
THREAD_PRIORITY_HIGH = 5U,
|
||||
THREAD_PRIORITY_HIGHER = 6U,
|
||||
THREAD_PRIORITY_CRITICAL = 7U
|
||||
};
|
||||
|
||||
typedef int32_t (*thread_main_fn_t)(void* context);
|
||||
typedef void (*thread_state_callback_t)(ThreadState state, void* context);
|
||||
|
||||
struct Thread;
|
||||
typedef struct Thread Thread;
|
||||
|
||||
/**
|
||||
* @brief Creates a new thread instance with default settings.
|
||||
* @return A pointer to the created Thread instance, or NULL if allocation failed.
|
||||
*/
|
||||
Thread* thread_alloc(void);
|
||||
|
||||
/**
|
||||
* @brief Creates a new thread instance with specified parameters.
|
||||
* @param[in] name The name of the thread.
|
||||
* @param[in] stack_size The size of the thread stack in bytes.
|
||||
* @param[in] function The main function to be executed by the thread.
|
||||
* @param[in] function_context A pointer to the context to be passed to the main function.
|
||||
* @param[in] affinity The CPU core affinity for the thread (e.g., tskNO_AFFINITY).
|
||||
* @return A pointer to the created Thread instance, or NULL if allocation failed.
|
||||
*/
|
||||
Thread* thread_alloc_full(
|
||||
const char* name,
|
||||
configSTACK_DEPTH_TYPE stack_size,
|
||||
thread_main_fn_t function,
|
||||
void* function_context,
|
||||
portBASE_TYPE affinity
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Destroys a thread instance.
|
||||
* @param[in] thread The thread instance to destroy.
|
||||
* @note The thread must be in the STOPPED state.
|
||||
*/
|
||||
void thread_free(Thread* thread);
|
||||
|
||||
/**
|
||||
* @brief Sets the name of the thread.
|
||||
* @param[in] thread The thread instance.
|
||||
* @param[in] name The new name for the thread.
|
||||
* @note Can only be called when the thread is in the STOPPED state.
|
||||
*/
|
||||
void thread_set_name(Thread* thread, const char* name);
|
||||
|
||||
/**
|
||||
* @brief Sets the stack size for the thread.
|
||||
* @param[in] thread The thread instance.
|
||||
* @param[in] stack_size The stack size in bytes. Must be a multiple of 4.
|
||||
* @note Can only be called when the thread is in the STOPPED state.
|
||||
*/
|
||||
void thread_set_stack_size(Thread* thread, size_t stack_size);
|
||||
|
||||
/**
|
||||
* @brief Sets the CPU core affinity for the thread.
|
||||
* @param[in] thread The thread instance.
|
||||
* @param[in] affinity The CPU core affinity.
|
||||
* @note Can only be called when the thread is in the STOPPED state.
|
||||
*/
|
||||
void thread_set_affinity(Thread* thread, portBASE_TYPE affinity);
|
||||
|
||||
/**
|
||||
* @brief Sets the main function and context for the thread.
|
||||
* @param[in] thread The thread instance.
|
||||
* @param[in] function The main function to be executed.
|
||||
* @param[in] context A pointer to the context to be passed to the main function.
|
||||
* @note Can only be called when the thread is in the STOPPED state.
|
||||
*/
|
||||
void thread_set_main_function(Thread* thread, thread_main_fn_t function, void* context);
|
||||
|
||||
/**
|
||||
* @brief Sets the priority for the thread.
|
||||
* @param[in] thread The thread instance.
|
||||
* @param[in] priority The thread priority.
|
||||
* @note Can only be called when the thread is in the STOPPED state.
|
||||
*/
|
||||
void thread_set_priority(Thread* thread, enum ThreadPriority priority);
|
||||
|
||||
/**
|
||||
* @brief Sets a callback to be invoked when the thread state changes.
|
||||
* @param[in] thread The thread instance.
|
||||
* @param[in] callback The callback function.
|
||||
* @param[in] context A pointer to the context to be passed to the callback function.
|
||||
* @note Can only be called when the thread is in the STOPPED state.
|
||||
*/
|
||||
void thread_set_state_callback(Thread* thread, thread_state_callback_t callback, void* context);
|
||||
|
||||
/**
|
||||
* @brief Gets the current state of the thread.
|
||||
* @param[in] thread The thread instance.
|
||||
* @return The current ThreadState.
|
||||
*/
|
||||
ThreadState thread_get_state(Thread* thread);
|
||||
|
||||
/**
|
||||
* @brief Starts the thread execution.
|
||||
* @param[in] thread The thread instance.
|
||||
* @note The thread must be in the STOPPED state and have a main function set.
|
||||
* @retval ERROR_NONE when the thread was started
|
||||
* @retval ERROR_UNDEFINED when the thread failed to start
|
||||
*/
|
||||
error_t thread_start(Thread* thread);
|
||||
|
||||
/**
|
||||
* @brief Waits for the thread to finish execution.
|
||||
* @param[in] thread The thread instance.
|
||||
* @param[in] timeout The maximum time to wait in ticks.
|
||||
* @param[in] poll_interval The interval between status checks in ticks.
|
||||
* @retval ERROR_NONE when the thread was stopped
|
||||
* @retval ERROR_TIMEOUT when the thread was not stopped because the timeout has passed
|
||||
* @note Cannot be called from the thread being joined.
|
||||
*/
|
||||
error_t thread_join(Thread* thread, TickType_t timeout, TickType_t poll_interval);
|
||||
|
||||
/**
|
||||
* @brief Gets the FreeRTOS task handle associated with the thread.
|
||||
* @param[in] thread The thread instance.
|
||||
* @return The TaskHandle_t, or NULL if the thread is not running.
|
||||
*/
|
||||
TaskHandle_t thread_get_task_handle(Thread* thread);
|
||||
|
||||
/**
|
||||
* @brief Gets the return code from the thread's main function.
|
||||
* @param[in] thread The thread instance.
|
||||
* @return The return code of the thread's main function.
|
||||
* @note The thread must be in the STOPPED state.
|
||||
*/
|
||||
int32_t thread_get_return_code(Thread* thread);
|
||||
|
||||
/**
|
||||
* @brief Gets the minimum remaining stack space for the thread since it started.
|
||||
* @param[in] thread The thread instance.
|
||||
* @return The minimum remaining stack space in bytes.
|
||||
* @note The thread must be in the RUNNING state.
|
||||
*/
|
||||
uint32_t thread_get_stack_space(Thread* thread);
|
||||
|
||||
/**
|
||||
* @brief Gets the current thread instance.
|
||||
* @return A pointer to the current Thread instance, or NULL if not called from a thread created by this module.
|
||||
*/
|
||||
Thread* thread_get_current(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,104 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include "tactility/error.h"
|
||||
#include "tactility/freertos/timers.h"
|
||||
#include "tactility/concurrent/thread.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum TimerType {
|
||||
TIMER_TYPE_ONCE = 0, // Timer triggers once after time has passed
|
||||
TIMER_TYPE_PERIODIC = 1 // Timer triggers repeatedly after time has passed
|
||||
};
|
||||
|
||||
typedef void (*timer_callback_t)(void* context);
|
||||
typedef void (*timer_pending_callback_t)(void* context, uint32_t arg);
|
||||
|
||||
struct Timer;
|
||||
|
||||
/**
|
||||
* @brief Creates a new timer instance.
|
||||
* @param[in] type The timer type.
|
||||
* @param[in] ticks The timer period in ticks.
|
||||
* @param[in] callback The callback function.
|
||||
* @param[in] context The context to pass to the callback function.
|
||||
* @return A pointer to the created timer instance, or NULL if allocation failed.
|
||||
*/
|
||||
struct Timer* timer_alloc(enum TimerType type, TickType_t ticks, timer_callback_t callback, void* context);
|
||||
|
||||
/**
|
||||
* @brief Destroys a timer instance.
|
||||
* @param[in] timer The timer instance to destroy.
|
||||
*/
|
||||
void timer_free(struct Timer* timer);
|
||||
|
||||
/**
|
||||
* @brief Starts the timer.
|
||||
* @param[in] timer The timer instance.
|
||||
* @return ERROR_NONE on success, ERROR_TIMEOUT if the command queue was full.
|
||||
*/
|
||||
error_t timer_start(struct Timer* timer);
|
||||
|
||||
/**
|
||||
* @brief Stops the timer.
|
||||
* @param[in] timer The timer instance.
|
||||
* @return ERROR_NONE on success, ERROR_TIMEOUT if the command queue was full.
|
||||
*/
|
||||
error_t timer_stop(struct Timer* timer);
|
||||
|
||||
/**
|
||||
* @brief Set a new interval and reset the timer.
|
||||
* @param[in] timer The timer instance.
|
||||
* @param[in] interval The new timer interval in ticks.
|
||||
* @return ERROR_NONE on success, ERROR_TIMEOUT if the command queue was full.
|
||||
*/
|
||||
error_t timer_reset_with_interval(struct Timer* timer, TickType_t interval);
|
||||
|
||||
/**
|
||||
* @brief Reset the timer.
|
||||
* @param[in] timer The timer instance.
|
||||
* @return ERROR_NONE on success, ERROR_TIMEOUT if the command queue was full.
|
||||
*/
|
||||
error_t timer_reset(struct Timer* timer);
|
||||
|
||||
/**
|
||||
* @brief Check if the timer is running.
|
||||
* @param[in] timer The timer instance.
|
||||
* @return true when the timer is running.
|
||||
*/
|
||||
bool timer_is_running(struct Timer* timer);
|
||||
|
||||
/**
|
||||
* @brief Gets the expiry time of the timer.
|
||||
* @param[in] timer The timer instance.
|
||||
* @return The expiry time in ticks.
|
||||
*/
|
||||
TickType_t timer_get_expiry_time(struct Timer* timer);
|
||||
|
||||
/**
|
||||
* @brief Calls xTimerPendFunctionCall internally.
|
||||
* @param[in] timer The timer instance.
|
||||
* @param[in] callback the function to call
|
||||
* @param[in] context the first function argument
|
||||
* @param[in] arg the second function argument
|
||||
* @param[in] timeout the function timeout (must set to 0 in ISR mode)
|
||||
* @return ERROR_NONE on success, ERROR_TIMEOUT if the command queue was full.
|
||||
*/
|
||||
error_t timer_set_pending_callback(struct Timer* timer, timer_pending_callback_t callback, void* context, uint32_t arg, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Set callback priority (priority of the timer daemon task).
|
||||
* @param[in] timer The timer instance.
|
||||
* @param[in] priority The priority.
|
||||
*/
|
||||
void timer_set_callback_priority(struct Timer* timer, enum ThreadPriority priority);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/**
|
||||
* @brief Contains various unsorted defines
|
||||
* @note Preprocessor defines with potentially clashing names implement an #ifdef check.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifndef MIN
|
||||
/** @brief Get the minimum value of 2 values */
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
/** @brief Get the maximum value of 2 values */
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef CLAMP
|
||||
/** @brief Clamp a value between the provided minimum and maximum */
|
||||
#define CLAMP(min, max, value) (((value) < (min)) ? (min) : (((value) > (max)) ? (max) : (value)))
|
||||
#endif
|
||||
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include "time.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <rom/ets_sys.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <tactility/freertos/freertos.h>
|
||||
#include <tactility/check.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Delay the current task for the specified amount of ticks
|
||||
* @warning Does not work in ISR context
|
||||
*/
|
||||
static inline void delay_ticks(TickType_t ticks) {
|
||||
check(xPortInIsrContext() == pdFALSE);
|
||||
if (ticks == 0U) {
|
||||
taskYIELD();
|
||||
} else {
|
||||
vTaskDelay(ticks);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delay the current task for the specified amount of milliseconds
|
||||
* @warning Does not work in ISR context
|
||||
*/
|
||||
static inline void delay_millis(uint32_t milliSeconds) {
|
||||
delay_ticks(millis_to_ticks(milliSeconds));
|
||||
}
|
||||
|
||||
/**
|
||||
* Stall the currently active CPU core for the specified amount of microseconds.
|
||||
* This does not allow other tasks to run on the stalled CPU core.
|
||||
*/
|
||||
static inline void delay_micros(uint32_t microseconds) {
|
||||
#ifdef ESP_PLATFORM
|
||||
ets_delay_us(microseconds);
|
||||
#else
|
||||
usleep(microseconds);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,278 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "driver.h"
|
||||
#include "error.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <tactility/concurrent/mutex.h>
|
||||
#include <tactility/freertos/freertos.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Driver;
|
||||
struct DeviceInternal;
|
||||
|
||||
/** Enables discovering devices of the same type */
|
||||
struct DeviceType {
|
||||
const char* name;
|
||||
};
|
||||
|
||||
/** Represents a piece of hardware */
|
||||
struct Device {
|
||||
/** The name of the device. Valid characters: a-z a-Z 0-9 - _ . */
|
||||
const char* name;
|
||||
|
||||
/** The configuration data for the device's driver */
|
||||
const void* config;
|
||||
|
||||
/** The parent device that this device belongs to. Can be NULL, but only the root device should have a NULL parent. */
|
||||
struct Device* parent;
|
||||
|
||||
/**
|
||||
* Internal state managed by the kernel.
|
||||
* Device implementers should initialize this to NULL.
|
||||
* Do not access or modify directly; use device_* functions.
|
||||
*/
|
||||
struct DeviceInternal* internal;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize the properties of a device.
|
||||
*
|
||||
* @param[in,out] device a device with all non-internal properties set
|
||||
* @retval ERROR_OUT_OF_MEMORY if internal data allocation failed
|
||||
* @retval ERROR_NONE on success
|
||||
*/
|
||||
error_t device_construct(struct Device* device);
|
||||
|
||||
/**
|
||||
* Deinitialize the properties of a device.
|
||||
* This fails when a device is busy or has children.
|
||||
*
|
||||
* @param[in,out] device non-null device pointer
|
||||
* @retval ERROR_INVALID_STATE if the device is busy or has children
|
||||
* @retval ERROR_NONE on success
|
||||
*/
|
||||
error_t device_destruct(struct Device* device);
|
||||
|
||||
/**
|
||||
* Register a device to all relevant systems:
|
||||
* - the global ledger
|
||||
* - its parent (if any)
|
||||
*
|
||||
* @param[in,out] device non-null device pointer
|
||||
* @retval ERROR_INVALID_STATE if the device is already added
|
||||
* @retval ERROR_NONE on success
|
||||
*/
|
||||
error_t device_add(struct Device* device);
|
||||
|
||||
/**
|
||||
* Deregister a device. Remove it from all relevant systems:
|
||||
* - the global ledger
|
||||
* - its parent (if any)
|
||||
*
|
||||
* @param[in,out] device non-null device pointer
|
||||
* @retval ERROR_INVALID_STATE if the device is still started
|
||||
* @retval ERROR_NOT_FOUND if the device was not found in the system
|
||||
* @retval ERROR_NONE on success
|
||||
*/
|
||||
error_t device_remove(struct Device* device);
|
||||
|
||||
/**
|
||||
* Attach the driver.
|
||||
*
|
||||
* @warning must call device_construct() and device_add() first
|
||||
* @param[in,out] device non-null device pointer
|
||||
* @retval ERROR_INVALID_STATE if the device is already started or not added
|
||||
* @retval ERROR_RESOURCE when driver binding fails
|
||||
* @retval ERROR_NONE on success
|
||||
*/
|
||||
error_t device_start(struct Device* device);
|
||||
|
||||
/**
|
||||
* Detach the driver.
|
||||
*
|
||||
* @param[in,out] device non-null device pointer
|
||||
* @retval ERROR_INVALID_STATE if the device is not started
|
||||
* @retval ERROR_RESOURCE when driver unbinding fails
|
||||
* @retval ERROR_NONE on success
|
||||
*/
|
||||
error_t device_stop(struct Device* device);
|
||||
|
||||
/**
|
||||
* Construct and add a device with the given compatible string.
|
||||
*
|
||||
* @param[in,out] device non-NULL device
|
||||
* @param[in] compatible compatible string
|
||||
* @retval ERROR_NONE on success
|
||||
* @retval error_t error code on failure
|
||||
*/
|
||||
error_t device_construct_add_start(struct Device* device, const char* compatible);
|
||||
|
||||
/**
|
||||
* Construct and add a device with the given compatible string.
|
||||
*
|
||||
* @param[in,out] device non-NULL device
|
||||
* @param[in] compatible compatible string
|
||||
* @retval ERROR_NONE on success
|
||||
* @retval error_t error code on failure
|
||||
*/
|
||||
error_t device_construct_add(struct Device* device, const char* compatible);
|
||||
|
||||
/**
|
||||
* Set or unset a parent.
|
||||
*
|
||||
* @warning must call before device_add()
|
||||
* @param[in,out] device non-NULL device
|
||||
* @param[in] parent nullable parent device
|
||||
*/
|
||||
void device_set_parent(struct Device* device, struct Device* parent);
|
||||
|
||||
/**
|
||||
* Set the driver for a device.
|
||||
*
|
||||
* @warning must call before device_add()
|
||||
* @param[in,out] device non-NULL device
|
||||
* @param[in] driver nullable driver
|
||||
*/
|
||||
void device_set_driver(struct Device* device, struct Driver* driver);
|
||||
|
||||
/**
|
||||
* Get the driver for a device.
|
||||
*
|
||||
* @param[in] device non-null device pointer
|
||||
* @return the driver, or NULL if the device has no driver
|
||||
*/
|
||||
struct Driver* device_get_driver(struct Device* device);
|
||||
|
||||
/**
|
||||
* Get the parent device of a device.
|
||||
*
|
||||
* @param[in] device non-null device pointer
|
||||
* @return the parent device, or NULL if the device has no parent
|
||||
*/
|
||||
struct Device* device_get_parent(struct Device* device);
|
||||
|
||||
/**
|
||||
* Indicates whether the device is in a state where its API is available
|
||||
*
|
||||
* @param[in] device non-null device pointer
|
||||
* @return true if the device is ready for use
|
||||
*/
|
||||
bool device_is_ready(const struct Device* device);
|
||||
|
||||
/**
|
||||
* Indicates whether the device is compatible with the given compatible string.
|
||||
* @param[in] device non-null device pointer
|
||||
* @param[in] compatible compatible string
|
||||
* @return true if the device is compatible
|
||||
*/
|
||||
bool device_is_compatible(const struct Device* device, const char* compatible);
|
||||
|
||||
/**
|
||||
* Set the driver data for a device.
|
||||
*
|
||||
* @param[in,out] device non-null device pointer
|
||||
* @param[in] driver_data the driver data
|
||||
*/
|
||||
void device_set_driver_data(struct Device* device, void* driver_data);
|
||||
|
||||
/**
|
||||
* Get the driver data for a device.
|
||||
*
|
||||
* @param[in] device non-null device pointer
|
||||
* @return the driver data
|
||||
*/
|
||||
void* device_get_driver_data(struct Device* device);
|
||||
|
||||
/**
|
||||
* Indicates whether the device has been added to the system.
|
||||
*
|
||||
* @param[in] device non-null device pointer
|
||||
* @return true if the device has been added
|
||||
*/
|
||||
bool device_is_added(const struct Device* device);
|
||||
|
||||
/**
|
||||
* Lock the device for exclusive access.
|
||||
*
|
||||
* @param[in,out] device non-null device pointer
|
||||
*/
|
||||
void device_lock(struct Device* device);
|
||||
|
||||
/**
|
||||
* Try to lock the device for exclusive access.
|
||||
*
|
||||
* @param[in,out] device non-null device pointer
|
||||
* @param[in] timeout how long to wait for the lock
|
||||
* @return true if the device was locked successfully
|
||||
*/
|
||||
bool device_try_lock(struct Device* device, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* Unlock the device.
|
||||
*
|
||||
* @param[in,out] device non-null device pointer
|
||||
*/
|
||||
void device_unlock(struct Device* device);
|
||||
|
||||
/**
|
||||
* Get the type of a device.
|
||||
*
|
||||
* @param[in] device non-null device pointer
|
||||
* @return the device type
|
||||
*/
|
||||
const struct DeviceType* device_get_type(struct Device* device);
|
||||
|
||||
/**
|
||||
* Iterate through all the known devices
|
||||
*
|
||||
* @param[in] callback_context the parameter to pass to the callback. NULL is valid.
|
||||
* @param[in] on_device the function to call for each filtered device. return true to continue iterating or false to stop.
|
||||
*/
|
||||
void device_for_each(void* callback_context, bool(*on_device)(struct Device* device, void* context));
|
||||
|
||||
/**
|
||||
* Iterate through all the child devices of the specified device
|
||||
*
|
||||
* @param[in] device non-null device pointer
|
||||
* @param[in] callback_context the parameter to pass to the callback. NULL is valid.
|
||||
* @param[in] on_device the function to call for each filtered device. return true to continue iterating or false to stop.
|
||||
*/
|
||||
void device_for_each_child(struct Device* device, void* callback_context, bool(*on_device)(struct Device* device, void* context));
|
||||
|
||||
/**
|
||||
* Iterate through all the known devices of a specific type
|
||||
*
|
||||
* @param[in] type the type to filter
|
||||
* @param[in] callback_context the parameter to pass to the callback. NULL is valid.
|
||||
* @param[in] on_device the function to call for each filtered device. return true to continue iterating or false to stop.
|
||||
*/
|
||||
void device_for_each_of_type(const struct DeviceType* type, void* callback_context, bool(*on_device)(struct Device* device, void* context));
|
||||
|
||||
/**
|
||||
* Check if a device of the specified type exists.
|
||||
*
|
||||
* @param[in] type the type to check
|
||||
* @return true if a device of the specified type exists
|
||||
*/
|
||||
bool device_exists_of_type(const struct DeviceType* type);
|
||||
|
||||
/**
|
||||
* Find a device by its name.
|
||||
*
|
||||
* @param[in] name non-null device name to look up
|
||||
* @return the device pointer if found, or NULL if not found
|
||||
*/
|
||||
struct Device* device_find_by_name(const char* name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,145 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "error.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
struct Device;
|
||||
struct DeviceType;
|
||||
struct Module;
|
||||
struct DriverInternal;
|
||||
|
||||
struct Driver {
|
||||
/** The driver name */
|
||||
const char* name;
|
||||
/** Array of const char*, terminated by NULL */
|
||||
const char**compatible;
|
||||
/** Function to initialize the driver for a device */
|
||||
error_t (*start_device)(struct Device* dev);
|
||||
/** Function to deinitialize the driver for a device */
|
||||
error_t (*stop_device)(struct Device* dev);
|
||||
/** Contains the driver's functions */
|
||||
const void* api;
|
||||
/** Which type of devices this driver creates (can be NULL) */
|
||||
const struct DeviceType* device_type;
|
||||
/** The module that owns this driver. When it is NULL, the system owns the driver and it cannot be removed from registration. */
|
||||
const struct Module* owner;
|
||||
/**
|
||||
* Internal state managed by the kernel.
|
||||
* Driver implementers should initialize this to NULL.
|
||||
* Do not access or modify directly; use driver_* functions.
|
||||
*/
|
||||
struct DriverInternal* internal;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Construct a driver.
|
||||
*
|
||||
* This initializes the internal state of the driver.
|
||||
*
|
||||
* @param driver The driver to construct.
|
||||
* @return ERROR_NONE if successful, or an error code otherwise.
|
||||
*/
|
||||
error_t driver_construct(struct Driver* driver);
|
||||
|
||||
/**
|
||||
* @brief Destruct a driver.
|
||||
*
|
||||
* This cleans up the internal state of the driver.
|
||||
*
|
||||
* @param driver The driver to destruct.
|
||||
* @return ERROR_NONE if successful, or an error code otherwise.
|
||||
*/
|
||||
error_t driver_destruct(struct Driver* driver);
|
||||
|
||||
/**
|
||||
* @brief Add a driver to the system.
|
||||
*
|
||||
* This registers the driver so it can be used to bind to devices.
|
||||
*
|
||||
* @param driver The driver to add.
|
||||
* @return ERROR_NONE if successful, or an error code otherwise.
|
||||
*/
|
||||
error_t driver_add(struct Driver* driver);
|
||||
|
||||
/**
|
||||
* @brief Remove a driver from the system.
|
||||
*
|
||||
* This unregisters the driver.
|
||||
*
|
||||
* @param driver The driver to remove.
|
||||
* @return ERROR_NONE if successful, or an error code otherwise.
|
||||
*/
|
||||
error_t driver_remove(struct Driver* driver);
|
||||
|
||||
/**
|
||||
* @brief Construct and add a driver to the system.
|
||||
*
|
||||
* @param driver The driver to construct and add.
|
||||
* @return ERROR_NONE if successful, or an error code otherwise.
|
||||
*/
|
||||
error_t driver_construct_add(struct Driver* driver);
|
||||
|
||||
/**
|
||||
* @brief Remove and destruct a driver.
|
||||
*
|
||||
* @param driver The driver to remove and destruct.
|
||||
* @return ERROR_NONE if successful, or an error code otherwise.
|
||||
*/
|
||||
error_t driver_remove_destruct(struct Driver* driver);
|
||||
|
||||
/**
|
||||
* @brief Bind a driver to a device.
|
||||
*
|
||||
* This calls the driver's start_device function and increments the driver's use count.
|
||||
*
|
||||
* @param driver The driver to bind.
|
||||
* @param device The device to bind to.
|
||||
* @return ERROR_NONE if successful, or an error code otherwise.
|
||||
*/
|
||||
error_t driver_bind(struct Driver* driver, struct Device* device);
|
||||
|
||||
/**
|
||||
* @brief Unbind a driver from a device.
|
||||
*
|
||||
* This calls the driver's stop_device function and decrements the driver's use count.
|
||||
*
|
||||
* @param driver The driver to unbind.
|
||||
* @param device The device to unbind from.
|
||||
* @return ERROR_NONE if successful, or an error code otherwise.
|
||||
*/
|
||||
error_t driver_unbind(struct Driver* driver, struct Device* device);
|
||||
|
||||
/**
|
||||
* @brief Check if a driver is compatible with a given string.
|
||||
*
|
||||
* @param driver The driver to check.
|
||||
* @param compatible The compatibility string to check.
|
||||
* @return true if compatible, false otherwise.
|
||||
*/
|
||||
bool driver_is_compatible(struct Driver* driver, const char* compatible);
|
||||
|
||||
/**
|
||||
* @brief Find a driver compatible with a given string.
|
||||
*
|
||||
* @param compatible The compatibility string to find.
|
||||
* @return The compatible driver, or NULL if not found.
|
||||
*/
|
||||
struct Driver* driver_find_compatible(const char* compatible);
|
||||
|
||||
/**
|
||||
* @brief Get the device type of a driver.
|
||||
*
|
||||
* @param driver The driver to get the device type from.
|
||||
* @return The device type of the driver.
|
||||
*/
|
||||
const struct DeviceType* driver_get_device_type(struct Driver* driver);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,73 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <tactility/device.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define GPIO_FLAGS_MASK 0x1f
|
||||
|
||||
#define GPIO_PIN_NONE -1
|
||||
|
||||
#define GPIO_PIN_SPEC_NONE ((struct GpioPinSpec) { NULL, 0, GPIO_FLAG_NONE })
|
||||
|
||||
#define GPIO_FLAG_NONE 0
|
||||
#define GPIO_FLAG_ACTIVE_HIGH (0 << 0)
|
||||
#define GPIO_FLAG_ACTIVE_LOW (1 << 0)
|
||||
#define GPIO_FLAG_DIRECTION_INPUT (1 << 1)
|
||||
#define GPIO_FLAG_DIRECTION_OUTPUT (1 << 2)
|
||||
#define GPIO_FLAG_DIRECTION_INPUT_OUTPUT (GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_DIRECTION_OUTPUT)
|
||||
#define GPIO_FLAG_PULL_UP (0 << 3)
|
||||
#define GPIO_FLAG_PULL_DOWN (1 << 4)
|
||||
#define GPIO_FLAG_INTERRUPT_BITMASK (0b111 << 5) // 3 bits to hold the values [0, 5]
|
||||
#define GPIO_FLAG_INTERRUPT_FROM_OPTIONS(options) (gpio_int_type_t)((options & GPIO_FLAG_INTERRUPT_BITMASK) >> 5)
|
||||
#define GPIO_FLAG_INTERRUPT_TO_OPTIONS(options, interrupt) (options | (interrupt << 5))
|
||||
|
||||
typedef enum {
|
||||
GPIO_INTERRUPT_DISABLE = 0,
|
||||
GPIO_INTERRUPT_POS_EDGE = 1,
|
||||
GPIO_INTERRUPT_NEG_EDGE = 2,
|
||||
GPIO_INTERRUPT_ANY_EDGE = 3,
|
||||
GPIO_INTERRUPT_LOW_LEVEL = 4,
|
||||
GPIO_INTERRUPT_HIGH_LEVEL = 5,
|
||||
GPIO_MAX,
|
||||
} GpioInterruptType;
|
||||
|
||||
enum GpioOwnerType {
|
||||
/** @brief Pin is unclaimed/free */
|
||||
GPIO_OWNER_NONE,
|
||||
/** @brief Pin is owned by a hog */
|
||||
GPIO_OWNER_HOG,
|
||||
/** @brief Pin is claimed by a regular consumer */
|
||||
GPIO_OWNER_GPIO,
|
||||
/** @brief Pin is owned by SPI. This is a special case because of CS pin transfer from hog to SPI controller. */
|
||||
GPIO_OWNER_SPI
|
||||
};
|
||||
|
||||
/** The index of a GPIO pin on a GPIO Controller */
|
||||
typedef uint8_t gpio_pin_t;
|
||||
|
||||
/** Specifies the configuration flags for a GPIO pin (or set of pins) */
|
||||
typedef uint16_t gpio_flags_t;
|
||||
|
||||
/**
|
||||
* Specifies a pin and its properties for a specific GPIO controller.
|
||||
* Used by the devicetree, drivers and application code to refer to GPIO pins and acquire them via the gpio_controller API.
|
||||
*/
|
||||
struct GpioPinSpec {
|
||||
/** GPIO device controlling the pin */
|
||||
struct Device* gpio_controller;
|
||||
/** The pin's number on the device */
|
||||
gpio_pin_t pin;
|
||||
/** The pin's configuration flags as specified in devicetree */
|
||||
gpio_flags_t flags;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,148 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "gpio.h"
|
||||
#include <tactility/error.h>
|
||||
|
||||
struct Device;
|
||||
struct GpioDescriptor;
|
||||
|
||||
struct GpioControllerApi {
|
||||
/**
|
||||
* @brief Sets the logical level of a GPIO pin.
|
||||
* @param[in,out] descriptor the pin descriptor
|
||||
* @param[in] high true to set the pin high, false to set it low
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t (*set_level)(struct GpioDescriptor* descriptor, bool high);
|
||||
|
||||
/**
|
||||
* @brief Gets the logical level of a GPIO pin.
|
||||
* @param[in] descriptor the pin descriptor
|
||||
* @param[out] high pointer to store the pin level
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t (*get_level)(struct GpioDescriptor* descriptor, bool* high);
|
||||
|
||||
/**
|
||||
* @brief Configures the options for a GPIO pin.
|
||||
* @param[in,out] descriptor the pin descriptor
|
||||
* @param[in] flags configuration flags (direction, pull-up/down, etc.)
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t (*set_flags)(struct GpioDescriptor* descriptor, gpio_flags_t flags);
|
||||
|
||||
/**
|
||||
* @brief Gets the configuration options for a GPIO pin.
|
||||
* @param[in] descriptor the pin descriptor
|
||||
* @param[out] flags pointer to store the configuration flags
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t (*get_flags)(struct GpioDescriptor* descriptor, gpio_flags_t* flags);
|
||||
|
||||
/**
|
||||
* @brief Gets the native pin number associated with a descriptor.
|
||||
* @param[in] descriptor the pin descriptor
|
||||
* @param[out] pin_number pointer to store the pin number
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t (*get_native_pin_number)(struct GpioDescriptor* descriptor, void* pin_number);
|
||||
};
|
||||
|
||||
struct GpioDescriptor* gpio_descriptor_acquire(
|
||||
struct Device* controller,
|
||||
gpio_pin_t pin_number,
|
||||
enum GpioOwnerType owner
|
||||
);
|
||||
|
||||
error_t gpio_descriptor_release(struct GpioDescriptor* descriptor);
|
||||
|
||||
/**
|
||||
* @brief Gets the pin number associated with a descriptor.
|
||||
* @param[in] descriptor the pin descriptor
|
||||
* @param[out] pin pointer to store the pin number
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t gpio_descriptor_get_pin_number(struct GpioDescriptor* descriptor, gpio_pin_t* pin);
|
||||
|
||||
/**
|
||||
* @brief Gets the pin owner type associated with a descriptor.
|
||||
* @param[in] descriptor the pin descriptor
|
||||
* @param[out] owner_type pointer to output owner type
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t gpio_descriptor_get_owner_type(struct GpioDescriptor* descriptor, enum GpioOwnerType* owner_type);
|
||||
|
||||
/**
|
||||
* @brief Sets the logical level of a GPIO pin.
|
||||
* @param[in] descriptor the pin descriptor
|
||||
* @param[in] high true to set the pin high, false to set it low
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t gpio_descriptor_set_level(struct GpioDescriptor* descriptor, bool high);
|
||||
|
||||
/**
|
||||
* @brief Gets the logical level of a GPIO pin.
|
||||
* @param[in] descriptor the pin descriptor
|
||||
* @param[out] high pointer to store the pin level
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t gpio_descriptor_get_level(struct GpioDescriptor* descriptor, bool* high);
|
||||
|
||||
/**
|
||||
* @brief Configures the options for a GPIO pin.
|
||||
* @param[in] descriptor the pin descriptor
|
||||
* @param[in] flags configuration flags (direction, pull-up/down, etc.)
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t gpio_descriptor_set_flags(struct GpioDescriptor* descriptor, gpio_flags_t flags);
|
||||
|
||||
/**
|
||||
* @brief Gets the configuration options for a GPIO pin.
|
||||
* @param[in] descriptor the pin descriptor
|
||||
* @param[out] flags pointer to store the configuration flags
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t gpio_descriptor_get_flags(struct GpioDescriptor* descriptor, gpio_flags_t* flags);
|
||||
|
||||
/**
|
||||
* @brief Gets the native pin number associated with a descriptor.
|
||||
* @param[in] descriptor the pin descriptor
|
||||
* @param[out] pin_number pointer to store the pin number
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t gpio_descriptor_get_native_pin_number(struct GpioDescriptor* descriptor, void* pin_number);
|
||||
|
||||
/**
|
||||
* @brief Gets the number of pins supported by the controller.
|
||||
* @param[in] device the GPIO controller device
|
||||
* @param[out] count pointer to store the number of pins
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t gpio_controller_get_pin_count(struct Device* device, uint32_t* count);
|
||||
|
||||
/**
|
||||
* @brief Initializes GPIO descriptors for a controller.
|
||||
* @param[in,out] device the GPIO controller device
|
||||
* @param[in] controller_context pointer to store in the controller's internal data
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t gpio_controller_init_descriptors(struct Device* device, uint32_t pin_count, void* controller_context);
|
||||
|
||||
/**
|
||||
* @brief Deinitializes GPIO descriptors for a controller.
|
||||
* @param[in,out] device the GPIO controller device
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t gpio_controller_deinit_descriptors(struct Device* device);
|
||||
|
||||
extern const struct DeviceType GPIO_CONTROLLER_TYPE;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "gpio.h"
|
||||
|
||||
struct Device;
|
||||
|
||||
struct GpioDescriptor {
|
||||
/** @brief The controller that owns this pin */
|
||||
struct Device* controller;
|
||||
/** @brief Physical pin number */
|
||||
gpio_pin_t pin;
|
||||
/** @brief Current owner */
|
||||
enum GpioOwnerType owner_type;
|
||||
/** @brief Implementation-specific context (e.g. from esp32 controller internally) */
|
||||
void* controller_context;
|
||||
};
|
||||
@@ -0,0 +1,170 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "gpio.h"
|
||||
|
||||
#include <tactility/freertos/freertos.h>
|
||||
#include <tactility/error.h>
|
||||
|
||||
struct Device;
|
||||
|
||||
/**
|
||||
* @brief API for I2C controller drivers.
|
||||
*/
|
||||
struct I2cControllerApi {
|
||||
/**
|
||||
* @brief Reads data from an I2C device.
|
||||
* @param[in] device the I2C controller device
|
||||
* @param[in] address the 7-bit I2C address of the slave device
|
||||
* @param[out] data the buffer to store the read data
|
||||
* @param[in] dataSize the number of bytes to read
|
||||
* @param[in] timeout the maximum time to wait for the operation to complete
|
||||
* @retval ERROR_NONE when the read operation was successful
|
||||
* @retval ERROR_TIMEOUT when the operation timed out
|
||||
*/
|
||||
error_t (*read)(struct Device* device, uint8_t address, uint8_t* data, size_t dataSize, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Writes data to an I2C device.
|
||||
* @param[in] device the I2C controller device
|
||||
* @param[in] address the 7-bit I2C address of the slave device
|
||||
* @param[in] data the buffer containing the data to write
|
||||
* @param[in] dataSize the number of bytes to write
|
||||
* @param[in] timeout the maximum time to wait for the operation to complete
|
||||
* @retval ERROR_NONE when the write operation was successful
|
||||
* @retval ERROR_TIMEOUT when the operation timed out
|
||||
*/
|
||||
error_t (*write)(struct Device* device, uint8_t address, const uint8_t* data, uint16_t dataSize, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Writes data to then reads data from an I2C device.
|
||||
* @param[in] device the I2C controller device
|
||||
* @param[in] address the 7-bit I2C address of the slave device
|
||||
* @param[in] writeData the buffer containing the data to write
|
||||
* @param[in] writeDataSize the number of bytes to write
|
||||
* @param[out] readData the buffer to store the read data
|
||||
* @param[in] readDataSize the number of bytes to read
|
||||
* @param[in] timeout the maximum time to wait for the operation to complete
|
||||
* @retval ERROR_NONE when the operation was successful
|
||||
* @retval ERROR_TIMEOUT when the operation timed out
|
||||
*/
|
||||
error_t (*write_read)(struct Device* device, uint8_t address, const uint8_t* writeData, size_t writeDataSize, uint8_t* readData, size_t readDataSize, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Reads data from a register of an I2C device.
|
||||
* @param[in] device the I2C controller device
|
||||
* @param[in] address the 7-bit I2C address of the slave device
|
||||
* @param[in] reg the register address to read from
|
||||
* @param[out] data the buffer to store the read data
|
||||
* @param[in] dataSize the number of bytes to read
|
||||
* @param[in] timeout the maximum time to wait for the operation to complete
|
||||
* @retval ERROR_NONE when the read operation was successful
|
||||
* @retval ERROR_TIMEOUT when the operation timed out
|
||||
*/
|
||||
error_t (*read_register)(struct Device* device, uint8_t address, uint8_t reg, uint8_t* data, size_t dataSize, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Writes data to a register of an I2C device.
|
||||
* @param[in] device the I2C controller device
|
||||
* @param[in] address the 7-bit I2C address of the slave device
|
||||
* @param[in] reg the register address to write to
|
||||
* @param[in] data the buffer containing the data to write
|
||||
* @param[in] dataSize the number of bytes to write
|
||||
* @param[in] timeout the maximum time to wait for the operation to complete
|
||||
* @retval ERROR_NONE when the write operation was successful
|
||||
* @retval ERROR_TIMEOUT when the operation timed out
|
||||
*/
|
||||
error_t (*write_register)(struct Device* device, uint8_t address, uint8_t reg, const uint8_t* data, uint16_t dataSize, TickType_t timeout);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Reads data from an I2C device using the specified controller.
|
||||
* @param[in] device the I2C controller device
|
||||
* @param[in] address the 7-bit I2C address of the slave device
|
||||
* @param[out] data the buffer to store the read data
|
||||
* @param[in] dataSize the number of bytes to read
|
||||
* @param[in] timeout the maximum time to wait for the operation to complete
|
||||
* @retval ERROR_NONE when the read operation was successful
|
||||
*/
|
||||
error_t i2c_controller_read(struct Device* device, uint8_t address, uint8_t* data, size_t dataSize, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Writes data to an I2C device using the specified controller.
|
||||
* @param[in] device the I2C controller device
|
||||
* @param[in] address the 7-bit I2C address of the slave device
|
||||
* @param[in] data the buffer containing the data to write
|
||||
* @param[in] dataSize the number of bytes to write
|
||||
* @param[in] timeout the maximum time to wait for the operation to complete
|
||||
* @retval ERROR_NONE when the write operation was successful
|
||||
*/
|
||||
error_t i2c_controller_write(struct Device* device, uint8_t address, const uint8_t* data, uint16_t dataSize, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Writes data to then reads data from an I2C device using the specified controller.
|
||||
* @param[in] device the I2C controller device
|
||||
* @param[in] address the 7-bit I2C address of the slave device
|
||||
* @param[in] writeData the buffer containing the data to write
|
||||
* @param[in] writeDataSize the number of bytes to write
|
||||
* @param[out] readData the buffer to store the read data
|
||||
* @param[in] readDataSize the number of bytes to read
|
||||
* @param[in] timeout the maximum time to wait for the operation to complete
|
||||
* @retval ERROR_NONE when the operation was successful
|
||||
*/
|
||||
error_t i2c_controller_write_read(struct Device* device, uint8_t address, const uint8_t* writeData, size_t writeDataSize, uint8_t* readData, size_t readDataSize, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Reads data from a register of an I2C device using the specified controller.
|
||||
* @param[in] device the I2C controller device
|
||||
* @param[in] address the 7-bit I2C address of the slave device
|
||||
* @param[in] reg the register address to read from
|
||||
* @param[out] data the buffer to store the read data
|
||||
* @param[in] dataSize the number of bytes to read
|
||||
* @param[in] timeout the maximum time to wait for the operation to complete
|
||||
* @retval ERROR_NONE when the read operation was successful
|
||||
*/
|
||||
error_t i2c_controller_read_register(struct Device* device, uint8_t address, uint8_t reg, uint8_t* data, size_t dataSize, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Writes data to a register of an I2C device using the specified controller.
|
||||
* @param[in] device the I2C controller device
|
||||
* @param[in] address the 7-bit I2C address of the slave device
|
||||
* @param[in] reg the register address to write to
|
||||
* @param[in] data the buffer containing the data to write
|
||||
* @param[in] dataSize the number of bytes to write
|
||||
* @param[in] timeout the maximum time to wait for the operation to complete
|
||||
* @retval ERROR_NONE when the write operation was successful
|
||||
*/
|
||||
error_t i2c_controller_write_register(struct Device* device, uint8_t address, uint8_t reg, const uint8_t* data, uint16_t dataSize, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Writes an array of register-value pairs to an I2C device.
|
||||
* @param[in] device the I2C controller device
|
||||
* @param[in] address the 7-bit I2C address of the slave device
|
||||
* @param[in] data an array of bytes where even indices are register addresses and odd indices are values
|
||||
* @param[in] dataSize the number of bytes in the data array (must be even)
|
||||
* @param[in] timeout the maximum time to wait for each operation to complete
|
||||
* @retval ERROR_NONE when all write operations were successful
|
||||
*/
|
||||
error_t i2c_controller_write_register_array(struct Device* device, uint8_t address, const uint8_t* data, uint16_t dataSize, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Checks if an I2C device is present at the specified address.
|
||||
* @param[in] device the I2C controller device
|
||||
* @param[in] address the 7-bit I2C address to check
|
||||
* @param[in] timeout the maximum time to wait for the check to complete
|
||||
* @retval ERROR_NONE when a device responded at the address
|
||||
*/
|
||||
error_t i2c_controller_has_device_at_address(struct Device* device, uint8_t address, TickType_t timeout);
|
||||
|
||||
extern const struct DeviceType I2C_CONTROLLER_TYPE;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,143 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "gpio.h"
|
||||
|
||||
#include <tactility/freertos/freertos.h>
|
||||
#include <tactility/error.h>
|
||||
|
||||
struct Device;
|
||||
|
||||
/**
|
||||
* @brief I2S communication format
|
||||
*/
|
||||
enum I2sCommunicationFormat {
|
||||
I2S_FORMAT_STAND_I2S = 0x01,
|
||||
I2S_FORMAT_STAND_MSB = 0x02,
|
||||
I2S_FORMAT_STAND_PCM_SHORT = 0x04,
|
||||
I2S_FORMAT_STAND_PCM_LONG = 0x08,
|
||||
};
|
||||
|
||||
#define I2S_CHANNEL_NONE -1
|
||||
|
||||
/**
|
||||
* @brief I2S Config
|
||||
*/
|
||||
struct I2sConfig {
|
||||
enum I2sCommunicationFormat communication_format;
|
||||
uint32_t sample_rate;
|
||||
uint8_t bits_per_sample; // 16, 24, 32
|
||||
int8_t channel_left; // I2S_CHANNEL_NONE to disable
|
||||
int8_t channel_right; // I2S_CHANNEL_NONE to disable
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief API for I2S controller drivers.
|
||||
*/
|
||||
struct I2sControllerApi {
|
||||
/**
|
||||
* @brief Reads data from I2S.
|
||||
* @param[in] device the I2S controller device
|
||||
* @param[out] data the buffer to store the read data
|
||||
* @param[in] data_size the number of bytes to read
|
||||
* @param[out] bytes_read the number of bytes actually read
|
||||
* @param[in] timeout the maximum time to wait for the operation to complete
|
||||
* @retval ERROR_NONE when the read operation was successful
|
||||
* @retval ERROR_TIMEOUT when the operation timed out
|
||||
*/
|
||||
error_t (*read)(struct Device* device, void* data, size_t data_size, size_t* bytes_read, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Writes data to I2S.
|
||||
* @param[in] device the I2S controller device
|
||||
* @param[in] data the buffer containing the data to write
|
||||
* @param[in] data_size the number of bytes to write
|
||||
* @param[out] bytes_written the number of bytes actually written
|
||||
* @param[in] timeout the maximum time to wait for the operation to complete
|
||||
* @retval ERROR_NONE when the write operation was successful
|
||||
* @retval ERROR_TIMEOUT when the operation timed out
|
||||
*/
|
||||
error_t (*write)(struct Device* device, const void* data, size_t data_size, size_t* bytes_written, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Sets the I2S configuration.
|
||||
* @param[in] device the I2S controller device
|
||||
* @param[in] config the new configuration
|
||||
* @retval ERROR_NONE when the operation was successful
|
||||
*/
|
||||
error_t (*set_config)(struct Device* device, const struct I2sConfig* config);
|
||||
|
||||
/**
|
||||
* @brief Gets the current I2S configuration.
|
||||
* @param[in] device the I2S controller device
|
||||
* @param[out] config the buffer to store the current configuration
|
||||
* @retval ERROR_NONE when the operation was successful
|
||||
*/
|
||||
error_t (*get_config)(struct Device* device, struct I2sConfig* config);
|
||||
|
||||
/**
|
||||
* @brief Resets the I2S controller. Must configure it again before it can be used.
|
||||
* @param[in] device the I2S controller device
|
||||
* @retval ERROR_NONE when the operation was successful
|
||||
*/
|
||||
error_t (*reset)(struct Device* device);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Reads data from I2S using the specified controller.
|
||||
* @param[in] device the I2S controller device
|
||||
* @param[out] data the buffer to store the read data
|
||||
* @param[in] data_size the number of bytes to read
|
||||
* @param[out] bytes_read the number of bytes actually read
|
||||
* @param[in] timeout the maximum time to wait for the operation to complete
|
||||
* @retval ERROR_NONE when the read operation was successful
|
||||
*/
|
||||
error_t i2s_controller_read(struct Device* device, void* data, size_t data_size, size_t* bytes_read, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Writes data to I2S using the specified controller.
|
||||
* @param[in] device the I2S controller device
|
||||
* @param[in] data the buffer containing the data to write
|
||||
* @param[in] data_size the number of bytes to write
|
||||
* @param[out] bytes_written the number of bytes actually written
|
||||
* @param[in] timeout the maximum time to wait for the operation to complete
|
||||
* @retval ERROR_NONE when the write operation was successful
|
||||
*/
|
||||
error_t i2s_controller_write(struct Device* device, const void* data, size_t data_size, size_t* bytes_written, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Sets the I2S configuration using the specified controller.
|
||||
* @param[in] device the I2S controller device
|
||||
* @param[in] config the new configuration
|
||||
* @retval ERROR_NONE when the operation was successful
|
||||
*/
|
||||
error_t i2s_controller_set_config(struct Device* device, const struct I2sConfig* config);
|
||||
|
||||
/**
|
||||
* @brief Gets the current I2S configuration using the specified controller.
|
||||
* @param[in] device the I2S controller device
|
||||
* @param[out] config the buffer to store the current configuration
|
||||
* @retval ERROR_NONE when the operation was successful
|
||||
*/
|
||||
error_t i2s_controller_get_config(struct Device* device, struct I2sConfig* config);
|
||||
|
||||
/**
|
||||
* @brief Resets the I2S controller. Must configure it again before it can be used.
|
||||
* @param[in] device the I2S controller device
|
||||
* @retval ERROR_NONE when the operation was successful
|
||||
*/
|
||||
error_t i2s_controller_reset(struct Device* device);
|
||||
|
||||
extern const struct DeviceType I2S_CONTROLLER_TYPE;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct RootConfig {
|
||||
const char* model;
|
||||
};
|
||||
|
||||
/**
|
||||
* Indicates whether the device's model matches the specified model.
|
||||
* @param[in] device the device to check (non-null)
|
||||
* @param[in] model the model to check against
|
||||
* @return true if the device's model matches the specified model
|
||||
*/
|
||||
bool root_is_model(const struct Device* device, const char* model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,72 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <tactility/freertos/freertos.h>
|
||||
#include <tactility/error.h>
|
||||
|
||||
struct Device;
|
||||
|
||||
/**
|
||||
* @brief API for SPI controller drivers.
|
||||
*/
|
||||
struct SpiControllerApi {
|
||||
/**
|
||||
* @brief Locks the SPI controller.
|
||||
* @param[in] device the SPI controller device
|
||||
* @retval ERROR_NONE when the operation was successful
|
||||
*/
|
||||
error_t (*lock)(struct Device* device);
|
||||
|
||||
/**
|
||||
* @brief Tries to lock the SPI controller.
|
||||
* @param[in] device the SPI controller device
|
||||
* @param[in] timeout the maximum time to wait for the lock
|
||||
* @retval ERROR_NONE when the operation was successful
|
||||
* @retval ERROR_TIMEOUT when the operation timed out
|
||||
*/
|
||||
error_t (*try_lock)(struct Device* device, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Unlocks the SPI controller.
|
||||
* @param[in] device the SPI controller device
|
||||
* @retval ERROR_NONE when the operation was successful
|
||||
*/
|
||||
error_t (*unlock)(struct Device* device);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Locks the SPI controller using the specified controller.
|
||||
* @param[in] device the SPI controller device
|
||||
* @retval ERROR_NONE when the operation was successful
|
||||
*/
|
||||
error_t spi_controller_lock(struct Device* device);
|
||||
|
||||
/**
|
||||
* @brief Tries to lock the SPI controller using the specified controller.
|
||||
* @param[in] device the SPI controller device
|
||||
* @param[in] timeout the maximum ticks to wait for the lock
|
||||
* @retval ERROR_NONE when the operation was successful
|
||||
* @retval ERROR_TIMEOUT when the operation timed out
|
||||
*/
|
||||
error_t spi_controller_try_lock(struct Device* device, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Unlocks the SPI controller using the specified controller.
|
||||
* @param[in] device the SPI controller device
|
||||
* @retval ERROR_NONE when the operation was successful
|
||||
*/
|
||||
error_t spi_controller_unlock(struct Device* device);
|
||||
|
||||
extern const struct DeviceType SPI_CONTROLLER_TYPE;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,227 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <tactility/freertos/freertos.h>
|
||||
#include <tactility/error.h>
|
||||
|
||||
struct Device;
|
||||
|
||||
/**
|
||||
* @brief UART parity modes
|
||||
*/
|
||||
enum UartParity {
|
||||
UART_CONTROLLER_PARITY_DISABLE = 0x0,
|
||||
UART_CONTROLLER_PARITY_EVEN = 0x1,
|
||||
UART_CONTROLLER_PARITY_ODD = 0x2,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief UART data bits
|
||||
*/
|
||||
enum UartDataBits {
|
||||
UART_CONTROLLER_DATA_5_BITS = 0x0,
|
||||
UART_CONTROLLER_DATA_6_BITS = 0x1,
|
||||
UART_CONTROLLER_DATA_7_BITS = 0x2,
|
||||
UART_CONTROLLER_DATA_8_BITS = 0x3,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief UART stop bits
|
||||
*/
|
||||
enum UartStopBits {
|
||||
UART_CONTROLLER_STOP_BITS_1 = 0x1,
|
||||
UART_CONTROLLER_STOP_BITS_1_5 = 0x2,
|
||||
UART_CONTROLLER_STOP_BITS_2 = 0x3,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief UART Config
|
||||
*/
|
||||
struct UartConfig {
|
||||
uint32_t baud_rate;
|
||||
enum UartDataBits data_bits;
|
||||
enum UartParity parity;
|
||||
enum UartStopBits stop_bits;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief API for UART controller drivers.
|
||||
*/
|
||||
struct UartControllerApi {
|
||||
/**
|
||||
* @brief Reads a single byte from UART.
|
||||
* @param[in] device the UART controller device
|
||||
* @param[out] out the buffer to store the read byte
|
||||
* @param[in] timeout the maximum time to wait for the operation to complete
|
||||
* @retval ERROR_NONE when the read operation was successful
|
||||
* @retval ERROR_TIMEOUT when the operation timed out
|
||||
*/
|
||||
error_t (*read_byte)(struct Device* device, uint8_t* out, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Writes a single byte to UART.
|
||||
* @param[in] device the UART controller device
|
||||
* @param[in] out the byte to write
|
||||
* @param[in] timeout the maximum time to wait for the operation to complete
|
||||
* @retval ERROR_NONE when the write operation was successful
|
||||
* @retval ERROR_TIMEOUT when the operation timed out
|
||||
*/
|
||||
error_t (*write_byte)(struct Device* device, uint8_t out, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Writes multiple bytes to UART.
|
||||
* @param[in] device the UART controller device
|
||||
* @param[in] buffer the buffer containing the data to write
|
||||
* @param[in] buffer_size the number of bytes to write
|
||||
* @param[in] timeout the maximum time to wait for the operation to complete
|
||||
* @retval ERROR_NONE when the write operation was successful
|
||||
* @retval ERROR_TIMEOUT when the operation timed out
|
||||
*/
|
||||
error_t (*write_bytes)(struct Device* device, const uint8_t* buffer, size_t buffer_size, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Reads multiple bytes from UART.
|
||||
* @param[in] device the UART controller device
|
||||
* @param[out] buffer the buffer to store the read data
|
||||
* @param[in] buffer_size the number of bytes to read
|
||||
* @param[in] timeout the maximum time to wait for the operation to complete
|
||||
* @retval ERROR_NONE when the read operation was successful
|
||||
* @retval ERROR_TIMEOUT when the operation timed out
|
||||
*/
|
||||
error_t (*read_bytes)(struct Device* device, uint8_t* buffer, size_t buffer_size, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Returns the number of bytes available for reading.
|
||||
* @param[in] device the UART controller device
|
||||
* @param[out] available the number of bytes available
|
||||
* @return ERROR_NONE on success
|
||||
*/
|
||||
error_t (*get_available)(struct Device* device, size_t* available);
|
||||
|
||||
/**
|
||||
* @brief Sets the UART configuration.
|
||||
* @param[in] device the UART controller device
|
||||
* @param[in] config the new configuration
|
||||
* @retval ERROR_NONE when the operation was successful
|
||||
*/
|
||||
error_t (*set_config)(struct Device* device, const struct UartConfig* config);
|
||||
|
||||
/**
|
||||
* @brief Gets the current UART configuration.
|
||||
* @param[in] device the UART controller device
|
||||
* @param[out] config the buffer to store the current configuration
|
||||
* @retval ERROR_NONE when the operation was successful
|
||||
*/
|
||||
error_t (*get_config)(struct Device* device, struct UartConfig* config);
|
||||
|
||||
/**
|
||||
* @brief Opens the UART controller.
|
||||
* @param[in] device the UART controller device
|
||||
* @retval ERROR_NONE when the operation was successful
|
||||
*/
|
||||
error_t (*open)(struct Device* device);
|
||||
|
||||
/**
|
||||
* @brief Closes the UART controller.
|
||||
* @param[in] device the UART controller device
|
||||
* @retval ERROR_NONE when the operation was successful
|
||||
*/
|
||||
error_t (*close)(struct Device* device);
|
||||
|
||||
/**
|
||||
* @brief Checks if the UART controller is open.
|
||||
* @param[in] device the UART controller device
|
||||
* @return true if open, false otherwise
|
||||
*/
|
||||
bool (*is_open)(struct Device* device);
|
||||
|
||||
/**
|
||||
* @brief Flushes the UART input buffer.
|
||||
* @param[in] device the UART controller device
|
||||
* @retval ERROR_NONE when the operation was successful
|
||||
*/
|
||||
error_t (*flush_input)(struct Device* device);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Reads a single byte from UART using the specified controller.
|
||||
*/
|
||||
error_t uart_controller_read_byte(struct Device* device, uint8_t* out, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Writes a single byte to UART using the specified controller.
|
||||
*/
|
||||
error_t uart_controller_write_byte(struct Device* device, uint8_t out, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Writes multiple bytes to UART using the specified controller.
|
||||
*/
|
||||
error_t uart_controller_write_bytes(struct Device* device, const uint8_t* buffer, size_t buffer_size, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Reads multiple bytes from UART using the specified controller.
|
||||
*/
|
||||
error_t uart_controller_read_bytes(struct Device* device, uint8_t* buffer, size_t buffer_size, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Reads from UART until a specific byte is encountered.
|
||||
* @param[in] device the UART controller device
|
||||
* @param[out] buffer the buffer to store the read data
|
||||
* @param[in] buffer_size the size of the buffer
|
||||
* @param[in] until_byte the byte to look for
|
||||
* @param[in] timeout the maximum time to wait for the operation to complete
|
||||
* @param[in] add_null_terminator whether to add a null terminator after the until_byte
|
||||
* @param[out] bytes_read the number of bytes read (excluding null terminator if added)
|
||||
* @retval ERROR_NONE when the operation was successful
|
||||
* @retval ERROR_TIMEOUT when the operation timed out
|
||||
*/
|
||||
error_t uart_controller_read_until(struct Device* device, uint8_t* buffer, size_t buffer_size, uint8_t until_byte, bool add_null_terminator, size_t* bytes_read, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Get the number of bytes available for reading using the specified controller.
|
||||
*/
|
||||
error_t uart_controller_get_available(struct Device* device, size_t* available);
|
||||
|
||||
/**
|
||||
* @brief Sets the UART configuration using the specified controller.
|
||||
*/
|
||||
error_t uart_controller_set_config(struct Device* device, const struct UartConfig* config);
|
||||
|
||||
/**
|
||||
* @brief Gets the current UART configuration using the specified controller.
|
||||
*/
|
||||
error_t uart_controller_get_config(struct Device* device, struct UartConfig* config);
|
||||
|
||||
/**
|
||||
* @brief Opens the UART controller using the specified controller.
|
||||
*/
|
||||
error_t uart_controller_open(struct Device* device);
|
||||
|
||||
/**
|
||||
* @brief Closes the UART controller using the specified controller.
|
||||
*/
|
||||
error_t uart_controller_close(struct Device* device);
|
||||
|
||||
/**
|
||||
* @brief Checks if the UART controller is open using the specified controller.
|
||||
*/
|
||||
bool uart_controller_is_open(struct Device* device);
|
||||
|
||||
/**
|
||||
* @brief Flushes the UART input buffer using the specified controller.
|
||||
*/
|
||||
error_t uart_controller_flush_input(struct Device* device);
|
||||
|
||||
extern const struct DeviceType UART_CONTROLLER_TYPE;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
struct Device;
|
||||
|
||||
/** Signals the intended state of a device. */
|
||||
enum DtsDeviceStatus {
|
||||
/** Device should be constructed, added and started. */
|
||||
DTS_DEVICE_STATUS_OKAY,
|
||||
/** Device should be constructed and added, but not started. */
|
||||
DTS_DEVICE_STATUS_DISABLED
|
||||
};
|
||||
|
||||
/**
|
||||
* Holds a device pointer and a compatible string.
|
||||
* The device must not be constructed, added or started yet.
|
||||
* This is used by the devicetree code generator and the application init sequence.
|
||||
*/
|
||||
struct DtsDevice {
|
||||
/** A pointer to a device. */
|
||||
struct Device* device;
|
||||
/** The compatible string contains the identifier of the driver that this device is compatible with. */
|
||||
const char* compatible;
|
||||
/** The intended state of the device. */
|
||||
const enum DtsDeviceStatus status;
|
||||
};
|
||||
|
||||
/** Signals the end of the device array in the generated dts code. */
|
||||
#define DTS_DEVICE_TERMINATOR { NULL, NULL, DTS_DEVICE_STATUS_DISABLED }
|
||||
@@ -0,0 +1,33 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Avoid potential clash with bits/types/error_t.h
|
||||
#ifndef __error_t_defined
|
||||
typedef int error_t;
|
||||
#endif
|
||||
|
||||
#define ERROR_NONE 0
|
||||
#define ERROR_UNDEFINED 1
|
||||
#define ERROR_INVALID_STATE 2
|
||||
#define ERROR_INVALID_ARGUMENT 3
|
||||
#define ERROR_MISSING_PARAMETER 4
|
||||
#define ERROR_NOT_FOUND 5
|
||||
#define ERROR_ISR_STATUS 6
|
||||
#define ERROR_RESOURCE 7 // A problem with a resource/dependency
|
||||
#define ERROR_TIMEOUT 8
|
||||
#define ERROR_OUT_OF_MEMORY 9
|
||||
#define ERROR_NOT_SUPPORTED 10
|
||||
#define ERROR_NOT_ALLOWED 11
|
||||
#define ERROR_BUFFER_OVERFLOW 12
|
||||
|
||||
/** Convert an error_t to a human-readable text. Useful for logging. */
|
||||
const char* error_to_string(error_t error);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
Compatibility include files for FreeRTOS.
|
||||
Custom FreeRTOS from ESP-IDF prefixes paths with "freertos/",
|
||||
but this isn't the normal behaviour for the regular FreeRTOS project.
|
||||
@@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "freertos.h"
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <freertos/event_groups.h>
|
||||
#else
|
||||
#include <event_groups.h>
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#else
|
||||
#include <FreeRTOS.h>
|
||||
#endif
|
||||
|
||||
// Custom port compatibility definitins, mainly for PC compatibility
|
||||
#include "port.h"
|
||||
@@ -0,0 +1,19 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "freertos.h"
|
||||
|
||||
#ifndef ESP_PLATFORM
|
||||
|
||||
// TactilityFreeRTOS co-existence check
|
||||
#ifndef xPortInIsrContext
|
||||
#define xPortInIsrContext() (pdFALSE)
|
||||
#endif
|
||||
|
||||
// TactilityFreeRTOS co-existence check
|
||||
#ifndef vPortAssertIfInISR
|
||||
#define vPortAssertIfInISR()
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "freertos.h"
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <freertos/queue.h>
|
||||
#else
|
||||
#include <queue.h>
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "freertos.h"
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <freertos/semphr.h>
|
||||
#else
|
||||
#include <semphr.h>
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "freertos.h"
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <freertos/task.h>
|
||||
#else
|
||||
#include <task.h>
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "freertos.h"
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <freertos/timers.h>
|
||||
#else
|
||||
#include <timers.h>
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/error.h>
|
||||
#include <tactility/module.h>
|
||||
|
||||
/**
|
||||
* Initialize the kernel with platform and device modules, and a device tree.
|
||||
* @param platform_module The platform module to start. This module should not be constructed yet.
|
||||
* @param device_module The device module to start. This module should not be constructed yet. This parameter can be NULL.
|
||||
* @param dts_devices The list of generated devices from the devicetree. The array must be terminated with DTS_DEVICE_TERMINATOR. This parameter can be NULL.
|
||||
* @return ERROR_NONE on success, otherwise an error code
|
||||
*/
|
||||
error_t kernel_init(struct Module* platform_module, struct Module* device_module, struct DtsDevice dts_devices[]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <esp_log.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Used for log output filtering */
|
||||
enum LogLevel {
|
||||
LOG_LEVEL_ERROR, /*!< Critical errors, software module can not recover on its own */
|
||||
LOG_LEVEL_WARNING, /*!< Error conditions from which recovery measures have been taken */
|
||||
LOG_LEVEL_INFO, /*!< Information messages which describe normal flow of events */
|
||||
LOG_LEVEL_DEBUG, /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */
|
||||
LOG_LEVEL_VERBOSE /*!< Bigger chunks of debugging information, or frequent messages which can potentially flood the output. */
|
||||
};
|
||||
|
||||
#ifndef ESP_PLATFORM
|
||||
|
||||
void log_generic(enum LogLevel level, const char* tag, const char* format, ...);
|
||||
|
||||
#define LOG_E(tag, ...) log_generic(LOG_LEVEL_ERROR, tag, ##__VA_ARGS__)
|
||||
#define LOG_W(tag, ...) log_generic(LOG_LEVEL_WARNING, tag, ##__VA_ARGS__)
|
||||
#define LOG_I(tag, ...) log_generic(LOG_LEVEL_INFO, tag, ##__VA_ARGS__)
|
||||
#define LOG_D(tag, ...) log_generic(LOG_LEVEL_DEBUG, tag, ##__VA_ARGS__)
|
||||
#define LOG_V(tag, ...) log_generic(LOG_LEVEL_VERBOSE, tag, ##__VA_ARGS__)
|
||||
|
||||
#else
|
||||
|
||||
#define LOG_E(tag, ...) ESP_LOGE(tag, ##__VA_ARGS__)
|
||||
#define LOG_W(tag, ...) ESP_LOGW(tag, ##__VA_ARGS__)
|
||||
#define LOG_I(tag, ...) ESP_LOGI(tag, ##__VA_ARGS__)
|
||||
#define LOG_D(tag, ...) ESP_LOGD(tag, ##__VA_ARGS__)
|
||||
#define LOG_V(tag, ...) ESP_LOGV(tag, ##__VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,146 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include "error.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define MODULE_SYMBOL_TERMINATOR { nullptr, nullptr }
|
||||
#else
|
||||
#define MODULE_SYMBOL_TERMINATOR { NULL, NULL }
|
||||
#endif
|
||||
|
||||
#define DEFINE_MODULE_SYMBOL(symbol) { #symbol, (void*)&symbol }
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** A binary symbol like a function or a variable. */
|
||||
struct ModuleSymbol {
|
||||
/** The name of the symbol. */
|
||||
const char* name;
|
||||
/** The address of the symbol. */
|
||||
const void* symbol;
|
||||
};
|
||||
|
||||
struct ModuleInternal;
|
||||
|
||||
/**
|
||||
* A module is a collection of drivers or other functionality that can be loaded and unloaded at runtime.
|
||||
*/
|
||||
struct Module {
|
||||
/**
|
||||
* The name of the module, for logging/debugging purposes
|
||||
* Should never be NULL.
|
||||
* Characters allowed: a-z A-Z 0-9 - _ .
|
||||
* Desirable format "platform-esp32", "lilygo-tdeck", etc.
|
||||
*/
|
||||
const char* name;
|
||||
/**
|
||||
* A function to initialize the module.
|
||||
* Should never be NULL.
|
||||
* This can be used to load drivers, initialize hardware, etc.
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t (*start)(void);
|
||||
/**
|
||||
* Deinitializes the module.
|
||||
* Should never be NULL.
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t (*stop)(void);
|
||||
/**
|
||||
* A list of symbols exported by the module.
|
||||
* Should be terminated by MODULE_SYMBOL_TERMINATOR.
|
||||
* Can be a NULL value.
|
||||
*/
|
||||
const struct ModuleSymbol* symbols;
|
||||
/**
|
||||
* Internal state managed by the kernel.
|
||||
* Module implementers should initialize this to NULL.
|
||||
* Do not access or modify directly; use module_* functions.
|
||||
*/
|
||||
struct ModuleInternal* internal;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Construct a module instance.
|
||||
* @param module module instance to construct
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t module_construct(struct Module* module);
|
||||
|
||||
/**
|
||||
* @brief Destruct a module instance.
|
||||
* @param module module instance to destruct
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t module_destruct(struct Module* module);
|
||||
|
||||
/**
|
||||
* @brief Add a module to the system.
|
||||
* @warning Only call this once. This function does not check if it was added before.
|
||||
* @param module module to add
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t module_add(struct Module* module);
|
||||
|
||||
/**
|
||||
* @brief Remove a module from the system.
|
||||
* @param module module to remove
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t module_remove(struct Module* module);
|
||||
|
||||
/**
|
||||
* @brief Start the module.
|
||||
* @param module module
|
||||
* @return ERROR_NONE if already started, or otherwise it returns the result of the module's start function
|
||||
*/
|
||||
error_t module_start(struct Module* module);
|
||||
|
||||
/**
|
||||
* @brief Stop the module.
|
||||
* @param module module
|
||||
* @return ERROR_NONE if successful or if the module wasn't started, or otherwise it returns the result of the module's stop function
|
||||
*/
|
||||
error_t module_stop(struct Module* module);
|
||||
|
||||
/**
|
||||
* @brief Construct, add and start a module.
|
||||
* @param module module
|
||||
* @return ERROR_NONE if successful
|
||||
*/
|
||||
error_t module_construct_add_start(struct Module* module);
|
||||
|
||||
/**
|
||||
* @brief Check if the module is started.
|
||||
* @param module module to check
|
||||
* @return true if the module is started, false otherwise
|
||||
*/
|
||||
bool module_is_started(struct Module* module);
|
||||
|
||||
/**
|
||||
* @brief Resolve a symbol from the module.
|
||||
* @details The module must be started for symbol resolution to succeed.
|
||||
* @param module module
|
||||
* @param symbol_name name of the symbol to resolve
|
||||
* @param symbol_address pointer to store the address of the resolved symbol
|
||||
* @return true if the symbol was found and the module is started, false otherwise
|
||||
*/
|
||||
bool module_resolve_symbol(struct Module* module, const char* symbol_name, uintptr_t* symbol_address);
|
||||
|
||||
/**
|
||||
* @brief Resolve a symbol from any module
|
||||
* @details This function iterates through all started modules in the parent and attempts to resolve the symbol.
|
||||
* @param symbol_name name of the symbol to resolve
|
||||
* @param symbol_address pointer to store the address of the resolved symbol
|
||||
* @return true if the symbol was found, false otherwise
|
||||
*/
|
||||
bool module_resolve_symbol_global(const char* symbol_name, uintptr_t* symbol_address);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
/**
|
||||
* Time-keeping related functionality.
|
||||
* This includes functionality for both ticks and seconds.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <assert.h>
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
|
||||
#include "defines.h"
|
||||
#include "tactility/freertos/task.h"
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <esp_timer.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Projects that include this header must align with Tactility's frequency (e.g. apps)
|
||||
#ifdef __cplusplus
|
||||
static_assert(configTICK_RATE_HZ == 1000);
|
||||
#else
|
||||
static_assert(configTICK_RATE_HZ == 1000, "configTICK_RATE_HZ must be 1000");
|
||||
#endif
|
||||
|
||||
static inline uint32_t get_tick_frequency() {
|
||||
return configTICK_RATE_HZ;
|
||||
}
|
||||
|
||||
/** @return the amount of ticks that have passed since FreeRTOS' main task started */
|
||||
static inline TickType_t get_ticks() {
|
||||
if (xPortInIsrContext() == pdTRUE) {
|
||||
return xTaskGetTickCountFromISR();
|
||||
} else {
|
||||
return xTaskGetTickCount();
|
||||
}
|
||||
}
|
||||
|
||||
/** @return the milliseconds that have passed since FreeRTOS' main task started */
|
||||
static inline size_t get_millis() {
|
||||
return get_ticks() * portTICK_PERIOD_MS;
|
||||
}
|
||||
|
||||
static inline TickType_t get_timeout_remaining_ticks(TickType_t timeout, TickType_t start_time) {
|
||||
TickType_t ticks_passed = get_ticks() - start_time;
|
||||
if (ticks_passed >= timeout) {
|
||||
return 0;
|
||||
}
|
||||
return timeout - ticks_passed;
|
||||
}
|
||||
|
||||
/** @return the frequency at which the kernel task schedulers operate */
|
||||
uint32_t kernel_get_tick_frequency();
|
||||
|
||||
/** @return the microseconds that have passed since boot */
|
||||
static inline int64_t get_micros_since_boot() {
|
||||
#ifdef ESP_PLATFORM
|
||||
return esp_timer_get_time();
|
||||
#else
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
|
||||
return ((int64_t)ts.tv_sec * 1000000LL) + (ts.tv_nsec / 1000);
|
||||
}
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return ((int64_t)tv.tv_sec * 1000000LL) + tv.tv_usec;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Convert seconds to ticks */
|
||||
static inline TickType_t seconds_to_ticks(uint32_t seconds) {
|
||||
return (uint64_t)seconds * 1000U / portTICK_PERIOD_MS;
|
||||
}
|
||||
|
||||
/** Convert milliseconds to ticks */
|
||||
static inline TickType_t millis_to_ticks(uint32_t milliSeconds) {
|
||||
#if configTICK_RATE_HZ == 1000
|
||||
return (TickType_t)milliSeconds;
|
||||
#else
|
||||
return static_cast<TickType_t>(((float)configTICK_RATE_HZ) / 1000.0f * (float)milliSeconds);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user