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:
Ken Van Hoeylandt
2026-02-07 21:28:11 +01:00
committed by GitHub
parent 7e24105d0c
commit 74127a5f6c
119 changed files with 1679 additions and 1792 deletions
@@ -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();
+29 -2
View File
@@ -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"
};
}
+22 -1
View File
@@ -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),