Add kernel drivers for SPI and UART and make locking APIs more consistent (#489)
- Add kernel support for SPI driver - Add kernel support for UART driver - Implemented ESP32 UART kernel driver - Update existing UART-related code in Tactility to use new kernel driver - Remove UART from tt::hal::Configuration - Remove tt_hal_uart functionality but keep functions for now - Update devicetrees for UART changes - Kernel mutex and recursive mutex: improved locking API design - Other kernel improvements - Added device_exists_of_type() and device_find_by_name()
This commit is contained in:
committed by
GitHub
parent
7e24105d0c
commit
74127a5f6c
@@ -0,0 +1 @@
|
||||
description: UART controller
|
||||
@@ -32,12 +32,7 @@ inline static void mutex_lock(struct Mutex* mutex) {
|
||||
xSemaphoreTake(mutex->handle, portMAX_DELAY);
|
||||
}
|
||||
|
||||
inline static bool mutex_try_lock(struct Mutex* mutex) {
|
||||
check(xPortInIsrContext() != pdTRUE);
|
||||
return xSemaphoreTake(mutex->handle, 0) == pdTRUE;
|
||||
}
|
||||
|
||||
inline static bool mutex_try_lock_timed(struct Mutex* mutex, TickType_t timeout) {
|
||||
inline static bool mutex_try_lock(struct Mutex* mutex, TickType_t timeout) {
|
||||
check(xPortInIsrContext() != pdTRUE);
|
||||
return xSemaphoreTake(mutex->handle, timeout) == pdTRUE;
|
||||
}
|
||||
|
||||
@@ -39,12 +39,7 @@ inline static bool recursive_mutex_is_locked(struct RecursiveMutex* mutex) {
|
||||
}
|
||||
}
|
||||
|
||||
inline static bool recursive_mutex_try_lock(struct RecursiveMutex* mutex) {
|
||||
check(xPortInIsrContext() != pdTRUE);
|
||||
return xSemaphoreTakeRecursive(mutex->handle, 0) == pdTRUE;
|
||||
}
|
||||
|
||||
inline static bool recursive_mutex_try_lock_timed(struct RecursiveMutex* mutex, TickType_t timeout) {
|
||||
inline static bool recursive_mutex_try_lock(struct RecursiveMutex* mutex, TickType_t timeout) {
|
||||
check(xPortInIsrContext() != pdTRUE);
|
||||
return xSemaphoreTakeRecursive(mutex->handle, timeout) == pdTRUE;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <tactility/concurrent/mutex.h>
|
||||
#include <tactility/freertos/freertos.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -212,9 +213,10 @@ 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);
|
||||
bool device_try_lock(struct Device* device, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* Unlock the device.
|
||||
@@ -257,6 +259,22 @@ void device_for_each_child(struct Device* device, void* callback_context, bool(*
|
||||
*/
|
||||
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
|
||||
|
||||
@@ -9,6 +9,8 @@ extern "C" {
|
||||
#include "gpio.h"
|
||||
#include <tactility/error.h>
|
||||
|
||||
struct Device;
|
||||
|
||||
struct GpioControllerApi {
|
||||
/**
|
||||
* @brief Sets the logical level of a GPIO pin.
|
||||
|
||||
@@ -13,6 +13,8 @@ extern "C" {
|
||||
#include <tactility/freertos/freertos.h>
|
||||
#include <tactility/error.h>
|
||||
|
||||
struct Device;
|
||||
|
||||
/**
|
||||
* @brief API for I2C controller drivers.
|
||||
*/
|
||||
|
||||
@@ -14,6 +14,8 @@ extern "C" {
|
||||
#include <tactility/freertos/freertos.h>
|
||||
#include <tactility/error.h>
|
||||
|
||||
struct Device;
|
||||
|
||||
/**
|
||||
* @brief I2S communication format
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
@@ -58,7 +58,7 @@ error_t dispatcher_dispatch_timed(DispatcherHandle_t dispatcher, void* callbackC
|
||||
auto* data = dispatcher_data(dispatcher);
|
||||
|
||||
// Mutate
|
||||
if (!mutex_try_lock_timed(&data->mutex, timeout)) {
|
||||
if (!mutex_try_lock(&data->mutex, timeout)) {
|
||||
#ifdef ESP_PLATFORM
|
||||
LOG_E(TAG, "Mutex acquisition timeout");
|
||||
#endif
|
||||
@@ -115,7 +115,7 @@ error_t dispatcher_consume_timed(DispatcherHandle_t dispatcher, TickType_t timeo
|
||||
// Mutate
|
||||
bool processing = true;
|
||||
do {
|
||||
if (mutex_try_lock_timed(&data->mutex, 10)) {
|
||||
if (mutex_try_lock(&data->mutex, 10)) {
|
||||
if (!data->queue.empty()) {
|
||||
// Make a copy, so it's thread-safe when we unlock
|
||||
auto entry = data->queue.front();
|
||||
|
||||
@@ -293,8 +293,8 @@ void device_lock(struct Device* device) {
|
||||
mutex_lock(&device->internal->mutex);
|
||||
}
|
||||
|
||||
bool device_try_lock(struct Device* device) {
|
||||
return mutex_try_lock(&device->internal->mutex);
|
||||
bool device_try_lock(struct Device* device, TickType_t timeout) {
|
||||
return mutex_try_lock(&device->internal->mutex, timeout);
|
||||
}
|
||||
|
||||
void device_unlock(struct Device* device) {
|
||||
@@ -338,4 +338,31 @@ void device_for_each_of_type(const DeviceType* type, void* callbackContext, bool
|
||||
ledger_unlock();
|
||||
}
|
||||
|
||||
bool device_exists_of_type(const DeviceType* type) {
|
||||
bool found = false;
|
||||
ledger_lock();
|
||||
for (auto* device : ledger.devices) {
|
||||
auto* driver = device->internal->driver;
|
||||
if (driver != nullptr && driver->device_type == type) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ledger_unlock();
|
||||
return found;
|
||||
}
|
||||
|
||||
Device* device_find_by_name(const char* name) {
|
||||
Device* found = nullptr;
|
||||
ledger_lock();
|
||||
for (auto* device : ledger.devices) {
|
||||
if (device->name != nullptr && std::strcmp(device->name, name) == 0) {
|
||||
found = device;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ledger_unlock();
|
||||
return found;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -32,7 +32,7 @@ error_t gpio_controller_get_pin_count(struct Device* device, uint32_t* count) {
|
||||
return GPIO_DRIVER_API(driver)->get_pin_count(device, count);
|
||||
}
|
||||
|
||||
extern const struct DeviceType GPIO_CONTROLLER_TYPE {
|
||||
const struct DeviceType GPIO_CONTROLLER_TYPE {
|
||||
.name = "gpio-controller"
|
||||
};
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ error_t i2c_controller_has_device_at_address(Device* device, uint8_t address, Ti
|
||||
return I2C_DRIVER_API(driver)->write(device, address, message, 2, timeout);
|
||||
}
|
||||
|
||||
extern const struct DeviceType I2C_CONTROLLER_TYPE {
|
||||
const struct DeviceType I2C_CONTROLLER_TYPE {
|
||||
.name = "i2c-controller"
|
||||
};
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ error_t i2s_controller_reset(struct Device* device) {
|
||||
return I2S_DRIVER_API(driver)->reset(device);
|
||||
}
|
||||
|
||||
extern const struct DeviceType I2S_CONTROLLER_TYPE {
|
||||
const struct DeviceType I2S_CONTROLLER_TYPE {
|
||||
.name = "i2s-controller"
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <tactility/drivers/spi_controller.h>
|
||||
#include <tactility/error.h>
|
||||
#include <tactility/device.h>
|
||||
|
||||
#define SPI_DRIVER_API(driver) ((struct SpiControllerApi*)driver->api)
|
||||
|
||||
extern "C" {
|
||||
|
||||
error_t spi_controller_lock(struct Device* device) {
|
||||
const auto* driver = device_get_driver(device);
|
||||
return SPI_DRIVER_API(driver)->lock(device);
|
||||
}
|
||||
|
||||
error_t spi_controller_try_lock(struct Device* device, TickType_t timeout) {
|
||||
const auto* driver = device_get_driver(device);
|
||||
return SPI_DRIVER_API(driver)->try_lock(device, timeout);
|
||||
}
|
||||
|
||||
error_t spi_controller_unlock(struct Device* device) {
|
||||
const auto* driver = device_get_driver(device);
|
||||
return SPI_DRIVER_API(driver)->unlock(device);
|
||||
}
|
||||
|
||||
const struct DeviceType SPI_CONTROLLER_TYPE {
|
||||
.name = "spi-controller"
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <tactility/drivers/uart_controller.h>
|
||||
#include <tactility/error.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/time.h>
|
||||
|
||||
#define UART_DRIVER_API(driver) ((struct UartControllerApi*)driver->api)
|
||||
|
||||
extern "C" {
|
||||
|
||||
error_t uart_controller_read_byte(struct Device* device, uint8_t* out, TickType_t timeout) {
|
||||
const auto* driver = device_get_driver(device);
|
||||
return UART_DRIVER_API(driver)->read_byte(device, out, timeout);
|
||||
}
|
||||
|
||||
error_t uart_controller_write_byte(struct Device* device, uint8_t out, TickType_t timeout) {
|
||||
const auto* driver = device_get_driver(device);
|
||||
return UART_DRIVER_API(driver)->write_byte(device, out, timeout);
|
||||
}
|
||||
|
||||
error_t uart_controller_write_bytes(struct Device* device, const uint8_t* buffer, size_t buffer_size, TickType_t timeout) {
|
||||
const auto* driver = device_get_driver(device);
|
||||
return UART_DRIVER_API(driver)->write_bytes(device, buffer, buffer_size, timeout);
|
||||
}
|
||||
|
||||
error_t uart_controller_read_bytes(struct Device* device, uint8_t* buffer, size_t buffer_size, TickType_t timeout) {
|
||||
const auto* driver = device_get_driver(device);
|
||||
return UART_DRIVER_API(driver)->read_bytes(device, buffer, buffer_size, timeout);
|
||||
}
|
||||
|
||||
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) {
|
||||
size_t read_count = 0;
|
||||
TickType_t start_time = get_ticks();
|
||||
uint8_t* buffer_write_ptr = buffer;
|
||||
uint8_t* buffer_limit = buffer + buffer_size;
|
||||
if (add_null_terminator) {
|
||||
buffer_limit--;
|
||||
}
|
||||
TickType_t timeout_left = timeout;
|
||||
error_t result = ERROR_NONE;
|
||||
|
||||
while (buffer_write_ptr < buffer_limit) {
|
||||
result = uart_controller_read_byte(device, buffer_write_ptr, timeout_left);
|
||||
if (result != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
|
||||
read_count++;
|
||||
|
||||
if (*buffer_write_ptr == until_byte) {
|
||||
if (add_null_terminator) {
|
||||
buffer_write_ptr++;
|
||||
*buffer_write_ptr = 0x00U;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
buffer_write_ptr++;
|
||||
|
||||
TickType_t now = get_ticks();
|
||||
if (now > (start_time + timeout)) {
|
||||
result = ERROR_TIMEOUT;
|
||||
break;
|
||||
} else {
|
||||
timeout_left = timeout - (now - start_time);
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes_read != nullptr) {
|
||||
*bytes_read = read_count;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
error_t uart_controller_get_available(struct Device* device, size_t* available) {
|
||||
const auto* driver = device_get_driver(device);
|
||||
return UART_DRIVER_API(driver)->get_available(device, available);
|
||||
}
|
||||
|
||||
error_t uart_controller_set_config(struct Device* device, const struct UartConfig* config) {
|
||||
const auto* driver = device_get_driver(device);
|
||||
return UART_DRIVER_API(driver)->set_config(device, config);
|
||||
}
|
||||
|
||||
error_t uart_controller_get_config(struct Device* device, struct UartConfig* config) {
|
||||
const auto* driver = device_get_driver(device);
|
||||
return UART_DRIVER_API(driver)->get_config(device, config);
|
||||
}
|
||||
|
||||
error_t uart_controller_open(struct Device* device) {
|
||||
const auto* driver = device_get_driver(device);
|
||||
return UART_DRIVER_API(driver)->open(device);
|
||||
}
|
||||
|
||||
error_t uart_controller_close(struct Device* device) {
|
||||
const auto* driver = device_get_driver(device);
|
||||
return UART_DRIVER_API(driver)->close(device);
|
||||
}
|
||||
|
||||
bool uart_controller_is_open(struct Device* device) {
|
||||
const auto* driver = device_get_driver(device);
|
||||
return UART_DRIVER_API(driver)->is_open(device);
|
||||
}
|
||||
|
||||
error_t uart_controller_flush_input(struct Device* device) {
|
||||
const auto* driver = device_get_driver(device);
|
||||
return UART_DRIVER_API(driver)->flush_input(device);
|
||||
}
|
||||
|
||||
const struct DeviceType UART_CONTROLLER_TYPE {
|
||||
.name = "uart-controller"
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/drivers/gpio_controller.h>
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
#include <tactility/drivers/i2s_controller.h>
|
||||
#include <tactility/drivers/gpio_controller.h>
|
||||
#include <tactility/drivers/spi_controller.h>
|
||||
#include <tactility/drivers/uart_controller.h>
|
||||
#include <tactility/concurrent/dispatcher.h>
|
||||
#include <tactility/concurrent/event_group.h>
|
||||
#include <tactility/concurrent/thread.h>
|
||||
@@ -41,6 +43,7 @@ const struct ModuleSymbol KERNEL_SYMBOLS[] = {
|
||||
DEFINE_MODULE_SYMBOL(device_for_each),
|
||||
DEFINE_MODULE_SYMBOL(device_for_each_child),
|
||||
DEFINE_MODULE_SYMBOL(device_for_each_of_type),
|
||||
DEFINE_MODULE_SYMBOL(device_exists_of_type),
|
||||
// driver
|
||||
DEFINE_MODULE_SYMBOL(driver_construct),
|
||||
DEFINE_MODULE_SYMBOL(driver_destruct),
|
||||
@@ -76,6 +79,24 @@ const struct ModuleSymbol KERNEL_SYMBOLS[] = {
|
||||
DEFINE_MODULE_SYMBOL(i2s_controller_get_config),
|
||||
DEFINE_MODULE_SYMBOL(i2s_controller_reset),
|
||||
DEFINE_MODULE_SYMBOL(I2S_CONTROLLER_TYPE),
|
||||
// drivers/spi_controller
|
||||
DEFINE_MODULE_SYMBOL(spi_controller_lock),
|
||||
DEFINE_MODULE_SYMBOL(spi_controller_try_lock),
|
||||
DEFINE_MODULE_SYMBOL(spi_controller_unlock),
|
||||
// drivers/uart_controller
|
||||
DEFINE_MODULE_SYMBOL(uart_controller_open),
|
||||
DEFINE_MODULE_SYMBOL(uart_controller_close),
|
||||
DEFINE_MODULE_SYMBOL(uart_controller_is_open),
|
||||
DEFINE_MODULE_SYMBOL(uart_controller_read_byte),
|
||||
DEFINE_MODULE_SYMBOL(uart_controller_read_bytes),
|
||||
DEFINE_MODULE_SYMBOL(uart_controller_read_until),
|
||||
DEFINE_MODULE_SYMBOL(uart_controller_write_byte),
|
||||
DEFINE_MODULE_SYMBOL(uart_controller_write_bytes),
|
||||
DEFINE_MODULE_SYMBOL(uart_controller_set_config),
|
||||
DEFINE_MODULE_SYMBOL(uart_controller_get_config),
|
||||
DEFINE_MODULE_SYMBOL(uart_controller_get_available),
|
||||
DEFINE_MODULE_SYMBOL(uart_controller_flush_input),
|
||||
DEFINE_MODULE_SYMBOL(UART_CONTROLLER_TYPE),
|
||||
// concurrent/dispatcher
|
||||
DEFINE_MODULE_SYMBOL(dispatcher_alloc),
|
||||
DEFINE_MODULE_SYMBOL(dispatcher_free),
|
||||
|
||||
Reference in New Issue
Block a user