diff --git a/Devices/lilygo-tdeck/Source/Init.cpp b/Devices/lilygo-tdeck/Source/Init.cpp index 5646dac6a..416bf8301 100644 --- a/Devices/lilygo-tdeck/Source/Init.cpp +++ b/Devices/lilygo-tdeck/Source/Init.cpp @@ -3,6 +3,7 @@ #include "devices/TrackballDevice.h" #include +#include #include #include #include @@ -30,6 +31,9 @@ static bool powerOn() { return false; } + // Avoids crash when no SD card is inserted. It's unknown why, but likely is related to power draw. + tt::kernel::delayMillis(100); + return true; } diff --git a/Devices/lilygo-tlora-pager/Source/drivers/TloraPager.cpp b/Devices/lilygo-tlora-pager/Source/drivers/TloraPager.cpp index d1786e5ad..9b2fea736 100644 --- a/Devices/lilygo-tlora-pager/Source/drivers/TloraPager.cpp +++ b/Devices/lilygo-tlora-pager/Source/drivers/TloraPager.cpp @@ -17,10 +17,10 @@ static int stop(Device* device) { Driver tlora_pager_driver = { .name = "T-Lora Pager", .compatible = (const char*[]) { "lilygo,tlora-pager", nullptr }, - .start_device = start, - .stop_device = stop, + .startDevice = start, + .stopDevice = stop, .api = nullptr, - .device_type = nullptr, + .deviceType = nullptr, .internal = { 0 } }; diff --git a/Platforms/PlatformEsp32/Include/Tactility/ErrorEsp32.h b/Platforms/PlatformEsp32/Include/Tactility/ErrorEsp32.h new file mode 100644 index 000000000..425478c8b --- /dev/null +++ b/Platforms/PlatformEsp32/Include/Tactility/ErrorEsp32.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include + +error_t esp_err_to_error(esp_err_t error); diff --git a/Platforms/PlatformEsp32/Include/Tactility/drivers/Esp32Gpio.h b/Platforms/PlatformEsp32/Include/Tactility/drivers/Esp32Gpio.h index 43b03a4cd..aa134c2e8 100644 --- a/Platforms/PlatformEsp32/Include/Tactility/drivers/Esp32Gpio.h +++ b/Platforms/PlatformEsp32/Include/Tactility/drivers/Esp32Gpio.h @@ -8,7 +8,7 @@ extern "C" { #include struct Esp32GpioConfig { - uint8_t gpio_count; + uint8_t gpioCount; }; #ifdef __cplusplus diff --git a/Platforms/PlatformEsp32/Include/Tactility/drivers/Esp32I2c.h b/Platforms/PlatformEsp32/Include/Tactility/drivers/Esp32I2c.h index 2e7de1c1d..c30a8325d 100644 --- a/Platforms/PlatformEsp32/Include/Tactility/drivers/Esp32I2c.h +++ b/Platforms/PlatformEsp32/Include/Tactility/drivers/Esp32I2c.h @@ -9,9 +9,9 @@ extern "C" { #endif struct Esp32I2cConfig { - uint32_t clock_frequency; - struct GpioPinConfig pin_sda; - struct GpioPinConfig pin_scl; + uint32_t clockFrequency; + struct GpioPinConfig pinSda; + struct GpioPinConfig pinScl; const i2c_port_t port; }; diff --git a/Platforms/PlatformEsp32/Source/ErrorEsp32.cpp b/Platforms/PlatformEsp32/Source/ErrorEsp32.cpp new file mode 100644 index 000000000..5264fd594 --- /dev/null +++ b/Platforms/PlatformEsp32/Source/ErrorEsp32.cpp @@ -0,0 +1,16 @@ +#include + +error_t esp_err_to_error(esp_err_t error) { + switch (error) { + case ESP_OK: + return ERROR_NONE; + case ESP_ERR_INVALID_ARG: + return ERROR_INVALID_ARGUMENT; + case ESP_ERR_INVALID_STATE: + return ERROR_INVALID_STATE; + case ESP_ERR_TIMEOUT: + return ERROR_TIMEOUT; + default: + return ERROR_UNDEFINED; + } +} diff --git a/Platforms/PlatformEsp32/Source/Esp32Gpio.cpp b/Platforms/PlatformEsp32/Source/drivers/Esp32Gpio.cpp similarity index 68% rename from Platforms/PlatformEsp32/Source/Esp32Gpio.cpp rename to Platforms/PlatformEsp32/Source/drivers/Esp32Gpio.cpp index adc4fa922..119fc7127 100644 --- a/Platforms/PlatformEsp32/Source/Esp32Gpio.cpp +++ b/Platforms/PlatformEsp32/Source/drivers/Esp32Gpio.cpp @@ -3,9 +3,11 @@ #include #include -#include -#include + +#include #include +#include +#include #define TAG LOG_TAG(esp32_gpio) @@ -13,20 +15,21 @@ extern "C" { -static bool set_level(Device* device, gpio_pin_t pin, bool high) { - return gpio_set_level(static_cast(pin), high) == ESP_OK; +static error_t set_level(Device* device, gpio_pin_t pin, bool high) { + auto esp_error = gpio_set_level(static_cast(pin), high); + return esp_err_to_error(esp_error); } -static bool get_level(Device* device, gpio_pin_t pin, bool* high) { +static error_t get_level(Device* device, gpio_pin_t pin, bool* high) { *high = gpio_get_level(static_cast(pin)) != 0; - return true; + return ERROR_NONE; } -static bool set_options(Device* device, gpio_pin_t pin, gpio_flags_t options) { +static error_t set_options(Device* device, gpio_pin_t pin, gpio_flags_t options) { const Esp32GpioConfig* config = GET_CONFIG(device); - if (pin >= config->gpio_count) { - return false; + if (pin >= config->gpioCount) { + return ERROR_INVALID_ARGUMENT; } gpio_mode_t mode; @@ -37,8 +40,7 @@ static bool set_options(Device* device, gpio_pin_t pin, gpio_flags_t options) { } else if (options & GPIO_DIRECTION_OUTPUT) { mode = GPIO_MODE_OUTPUT; } else { - ESP_LOGE(TAG, "set_options: no direction flag specified for pin %d", pin); - return false; + return ERROR_INVALID_ARGUMENT; } const gpio_config_t esp_config = { @@ -52,13 +54,14 @@ static bool set_options(Device* device, gpio_pin_t pin, gpio_flags_t options) { #endif }; - return gpio_config(&esp_config) == ESP_OK; + auto esp_error = gpio_config(&esp_config); + return esp_err_to_error(esp_error); } -static bool get_options(Device* device, gpio_pin_t pin, gpio_flags_t* options) { +static int get_options(Device* device, gpio_pin_t pin, gpio_flags_t* options) { gpio_io_config_t esp_config; - if (gpio_get_io_config((gpio_num_t)pin, &esp_config) != ESP_OK) { - return false; + if (gpio_get_io_config(static_cast(pin), &esp_config) != ESP_OK) { + return ERROR_RESOURCE; } gpio_flags_t output = 0; @@ -84,17 +87,17 @@ static bool get_options(Device* device, gpio_pin_t pin, gpio_flags_t* options) { } *options = output; - return true; + return ERROR_NONE; } -static int start(Device* device) { +static error_t start(Device* device) { ESP_LOGI(TAG, "start %s", device->name); - return 0; + return ERROR_NONE; } -static int stop(Device* device) { +static error_t stop(Device* device) { ESP_LOGI(TAG, "stop %s", device->name); - return 0; + return ERROR_NONE; } const static GpioControllerApi esp32_gpio_api = { @@ -107,10 +110,10 @@ const static GpioControllerApi esp32_gpio_api = { Driver esp32_gpio_driver = { .name = "esp32_gpio", .compatible = (const char*[]) { "espressif,esp32-gpio", nullptr }, - .start_device = start, - .stop_device = stop, + .startDevice = start, + .stopDevice = stop, .api = (void*)&esp32_gpio_api, - .device_type = nullptr, + .deviceType = nullptr, .internal = { 0 } }; diff --git a/Platforms/PlatformEsp32/Source/Esp32I2c.cpp b/Platforms/PlatformEsp32/Source/drivers/Esp32I2c.cpp similarity index 56% rename from Platforms/PlatformEsp32/Source/Esp32I2c.cpp rename to Platforms/PlatformEsp32/Source/drivers/Esp32I2c.cpp index b8948e8fc..d8f0f19a4 100644 --- a/Platforms/PlatformEsp32/Source/Esp32I2c.cpp +++ b/Platforms/PlatformEsp32/Source/drivers/Esp32I2c.cpp @@ -3,8 +3,11 @@ #include #include -#include + +#include "Tactility/ErrorEsp32.h" + #include +#include #define TAG LOG_TAG(esp32_i2c) @@ -28,41 +31,41 @@ struct InternalData { extern "C" { -static bool read(Device* device, uint8_t address, uint8_t* data, size_t data_size, TickType_t timeout) { +static int read(Device* device, uint8_t address, uint8_t* data, size_t data_size, TickType_t timeout) { vPortAssertIfInISR(); auto* driver_data = GET_DATA(device); lock(driver_data); - const esp_err_t result = i2c_master_read_from_device(GET_CONFIG(device)->port, address, data, data_size, timeout); + const esp_err_t esp_error = i2c_master_read_from_device(GET_CONFIG(device)->port, address, data, data_size, timeout); unlock(driver_data); - ESP_ERROR_CHECK_WITHOUT_ABORT(result); - return result == ESP_OK; + ESP_ERROR_CHECK_WITHOUT_ABORT(esp_error); + return esp_err_to_error(esp_error); } -static bool write(Device* device, uint8_t address, const uint8_t* data, uint16_t dataSize, TickType_t timeout) { +static int write(Device* device, uint8_t address, const uint8_t* data, uint16_t dataSize, TickType_t timeout) { vPortAssertIfInISR(); auto* driver_data = GET_DATA(device); lock(driver_data); - const esp_err_t result = i2c_master_write_to_device(GET_CONFIG(device)->port, address, data, dataSize, timeout); + const esp_err_t esp_error = i2c_master_write_to_device(GET_CONFIG(device)->port, address, data, dataSize, timeout); unlock(driver_data); - ESP_ERROR_CHECK_WITHOUT_ABORT(result); - return result == ESP_OK; + ESP_ERROR_CHECK_WITHOUT_ABORT(esp_error); + return esp_err_to_error(esp_error); } -static bool write_read(Device* device, uint8_t address, const uint8_t* write_data, size_t write_data_size, uint8_t* read_data, size_t read_data_size, TickType_t timeout) { +static int write_read(Device* device, uint8_t address, const uint8_t* write_data, size_t write_data_size, uint8_t* read_data, size_t read_data_size, TickType_t timeout) { vPortAssertIfInISR(); auto* driver_data = GET_DATA(device); lock(driver_data); - const esp_err_t result = i2c_master_write_read_device(GET_CONFIG(device)->port, address, write_data, write_data_size, read_data, read_data_size, timeout); + const esp_err_t esp_error = i2c_master_write_read_device(GET_CONFIG(device)->port, address, write_data, write_data_size, read_data, read_data_size, timeout); unlock(driver_data); - ESP_ERROR_CHECK_WITHOUT_ABORT(result); - return result == ESP_OK; + ESP_ERROR_CHECK_WITHOUT_ABORT(esp_error); + return esp_err_to_error(esp_error); } static int start(Device* device) { ESP_LOGI(TAG, "start %s", device->name); auto* data = new InternalData(); device_set_driver_data(device, data); - return 0; + return ERROR_NONE; } static int stop(Device* device) { @@ -70,10 +73,10 @@ static int stop(Device* device) { auto* driver_data = static_cast(device_get_driver_data(device)); device_set_driver_data(device, nullptr); delete driver_data; - return 0; + return ERROR_NONE; } -const I2cControllerApi esp32_i2c_api = { +const static I2cControllerApi esp32_i2c_api = { .read = read, .write = write, .write_read = write_read @@ -82,10 +85,10 @@ const I2cControllerApi esp32_i2c_api = { Driver esp32_i2c_driver = { .name = "esp32_i2c", .compatible = (const char*[]) { "espressif,esp32-i2c", nullptr }, - .start_device = start, - .stop_device = stop, + .startDevice = start, + .stopDevice = stop, .api = (void*)&esp32_i2c_api, - .device_type = &I2C_CONTROLLER_TYPE, + .deviceType = &I2C_CONTROLLER_TYPE, .internal = { 0 } }; diff --git a/Platforms/PlatformEsp32/Source/Register.cpp b/Platforms/PlatformEsp32/Source/drivers/Register.cpp similarity index 100% rename from Platforms/PlatformEsp32/Source/Register.cpp rename to Platforms/PlatformEsp32/Source/drivers/Register.cpp diff --git a/Tactility/Source/service/gui/GuiService.cpp b/Tactility/Source/service/gui/GuiService.cpp index 2a98df34a..525c007e8 100644 --- a/Tactility/Source/service/gui/GuiService.cpp +++ b/Tactility/Source/service/gui/GuiService.cpp @@ -31,7 +31,7 @@ int32_t GuiService::guiMain() { while (true) { uint32_t flags = 0; - if (service->threadFlags.wait(GUI_THREAD_FLAG_ALL, false, true, portMAX_DELAY, &flags)) { + if (service->threadFlags.wait(GUI_THREAD_FLAG_ALL, false, true, &flags, portMAX_DELAY)) { // When service not started or starting -> exit State service_state = getState(manifest.id); if (service_state != State::Started && service_state != State::Starting) { diff --git a/Tactility/Source/service/wifi/WifiEsp.cpp b/Tactility/Source/service/wifi/WifiEsp.cpp index 34c7d9dc4..211bdb726 100644 --- a/Tactility/Source/service/wifi/WifiEsp.cpp +++ b/Tactility/Source/service/wifi/WifiEsp.cpp @@ -799,11 +799,11 @@ static void dispatchConnect(std::shared_ptr wifi) { /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) * or connection failed for the maximum number of re-tries (WIFI_FAIL_BIT). * The bits are set by wifi_event_handler() */ - uint32_t bits; - if (wifi_singleton->connection_wait_flags.wait(WIFI_FAIL_BIT | WIFI_CONNECTED_BIT, false, true, kernel::MAX_TICKS, &bits)) { + uint32_t flags; + if (wifi_singleton->connection_wait_flags.wait(WIFI_FAIL_BIT | WIFI_CONNECTED_BIT, false, true, &flags, kernel::MAX_TICKS)) { LOGGER.info("Waiting for EventGroup by event_handler()"); - if (bits & WIFI_CONNECTED_BIT) { + if (flags & WIFI_CONNECTED_BIT) { wifi->setSecureConnection(config.sta.password[0] != 0x00U); wifi->setRadioState(RadioState::ConnectionActive); publish_event(wifi, WifiEvent::ConnectionSuccess); @@ -815,7 +815,7 @@ static void dispatchConnect(std::shared_ptr wifi) { LOGGER.info("Stored credentials"); } } - } else if (bits & WIFI_FAIL_BIT) { + } else if (flags & WIFI_FAIL_BIT) { wifi->setRadioState(RadioState::On); publish_event(wifi, WifiEvent::ConnectionFailed); LOGGER.info("Failed to connect to {}", wifi->connection_target.ssid.c_str()); diff --git a/TactilityFreeRtos/Include/Tactility/Dispatcher.h b/TactilityFreeRtos/Include/Tactility/Dispatcher.h index 076acff09..1fe6cbb27 100644 --- a/TactilityFreeRtos/Include/Tactility/Dispatcher.h +++ b/TactilityFreeRtos/Include/Tactility/Dispatcher.h @@ -67,6 +67,7 @@ class Dispatcher final { } if (shutdown) { + mutex.unlock(); return false; } @@ -86,14 +87,14 @@ class Dispatcher final { } /** - * Consume 1 or more dispatched function (if any) until the queue is empty. + * 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 * @return the amount of messages that were consumed */ uint32_t consume(TickType_t timeout = kernel::MAX_TICKS) { // Wait for signal - if (!eventFlag.wait(WAIT_FLAG, false, true, timeout)) { + if (!eventFlag.wait(WAIT_FLAG, false, true, nullptr, timeout)) { return 0; } diff --git a/TactilityFreeRtos/Include/Tactility/EventGroup.h b/TactilityFreeRtos/Include/Tactility/EventGroup.h index c016d5aaa..4b919a0a6 100644 --- a/TactilityFreeRtos/Include/Tactility/EventGroup.h +++ b/TactilityFreeRtos/Include/Tactility/EventGroup.h @@ -33,42 +33,27 @@ class EventGroup final { } enum class Error { - Unknown, Timeout, - Resource, - Parameter, - IsrStatus + Resource }; /** * Set the flags. * @param[in] flags the flags to set - * @param[out] outFlags optional resulting flags: this is set when the return value is true - * @param[out] outError optional error output: this is set when the return value is false * @return true on success */ - bool set(uint32_t flags, uint32_t* outFlags = nullptr, Error* outError = nullptr) const { + bool set(uint32_t flags) const { assert(handle); if (xPortInIsrContext() == pdTRUE) { - uint32_t result; BaseType_t yield = pdFALSE; if (xEventGroupSetBitsFromISR(handle.get(), flags, &yield) == pdFAIL) { - if (outError != nullptr) { - *outError = Error::Resource; - } return false; } else { - if (outFlags != nullptr) { - *outFlags = flags; - } portYIELD_FROM_ISR(yield); return true; } } else { - auto result = xEventGroupSetBits(handle.get(), flags); - if (outFlags != nullptr) { - *outFlags = result; - } + xEventGroupSetBits(handle.get(), flags); return true; } } @@ -76,31 +61,19 @@ class EventGroup final { /** * Clear flags * @param[in] flags the flags to clear - * @param[out] outFlags optional resulting flags: this is set when the return value is true - * @param[out] outError optional error output: this is set when the return value is false * @return true on success */ - bool clear(uint32_t flags, uint32_t* outFlags = nullptr, Error* outError = nullptr) const { + bool clear(uint32_t flags) const { if (xPortInIsrContext() == pdTRUE) { uint32_t result = xEventGroupGetBitsFromISR(handle.get()); if (xEventGroupClearBitsFromISR(handle.get(), flags) == pdFAIL) { - if (outError != nullptr) { - *outError = Error::Resource; - } return false; } - if (outFlags != nullptr) { - *outFlags = result; - } portYIELD_FROM_ISR(pdTRUE); - return true; } else { - auto result = xEventGroupClearBits(handle.get(), flags); - if (outFlags != nullptr) { - *outFlags = result; - } - return true; + xEventGroupClearBits(handle.get(), flags); } + return true; } /** @@ -120,16 +93,14 @@ class EventGroup final { * @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[in] timeout the maximum amount of ticks to wait for flags to be set - * @param[out] outFlags optional resulting flags: this is set when the return value is true - * @param[out] outError optional error output: this is set when the return value is false + * @param[out] outFlags optional resulting flags: this is set when the return value is true. Only set when return value is true. */ bool wait( uint32_t flags, bool awaitAll = false, bool clearOnExit = true, - TickType_t timeout = kernel::MAX_TICKS, uint32_t* outFlags = nullptr, - Error* outError = nullptr + TickType_t timeout = kernel::MAX_TICKS ) const { assert(xPortInIsrContext() == pdFALSE); @@ -144,14 +115,8 @@ class EventGroup final { auto invalid_flags = awaitAll ? ((flags & result_flags) != flags) // await all : ((flags & result_flags) == 0U); // await any + if (invalid_flags) { - if (outError != nullptr) { - if (timeout > 0U) { // assume time-out - *outError = Error::Timeout; - } else { - *outError = Error::Resource; - } - } return false; } diff --git a/TactilityKernel/Include/Tactility/Device.h b/TactilityKernel/Include/Tactility/Device.h index 0b0983e6d..cb6104b46 100644 --- a/TactilityKernel/Include/Tactility/Device.h +++ b/TactilityKernel/Include/Tactility/Device.h @@ -8,12 +8,13 @@ extern "C" { #endif -#include - #include #include #include +#include "Error.h" +#include + struct Driver; /** Enables discovering devices of the same type */ @@ -52,24 +53,26 @@ struct Device { /** * Initialize the properties of a device. * - * @param[in] dev a device with all non-internal properties set - * @return the result code (0 for success) + * @param[in] device a device with all non-internal properties set + * @retval ERROR_OUT_OF_MEMORY + * @retval ERROR_NONE */ -int device_construct(struct Device* device); +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] dev - * @return the result code (0 for success) + * @param[in] device + * @retval ERROR_INVALID_STATE + * @retval ERROR_NONE */ -int device_destruct(struct Device* device); +error_t device_destruct(struct Device* device); /** * Indicates whether the device is in a state where its API is available * - * @param[in] dev non-null device pointer + * @param[in] device non-null device pointer * @return true if the device is ready for use */ static inline bool device_is_ready(const struct Device* device) { @@ -83,9 +86,10 @@ static inline bool device_is_ready(const struct Device* device) { * - a bus (if any) * * @param[in] device non-null device pointer - * @return 0 on success + * @retval ERROR_INVALID_STATE + * @retval ERROR_NONE */ -int device_add(struct Device* device); +error_t device_add(struct Device* device); /** * Deregister a device. Remove it from all relevant systems: @@ -94,26 +98,32 @@ int device_add(struct Device* device); * - a bus (if any) * * @param[in] device non-null device pointer - * @return 0 on success + * @retval ERROR_INVALID_STATE + * @retval ERROR_NOT_FOUND + * @retval ERROR_NONE */ -int device_remove(struct Device* device); +error_t device_remove(struct Device* device); /** * Attach the driver. * * @warning must call device_construct() and device_add() first * @param device - * @return ERROR_INVALID_STATE or otherwise the value of the driver binding result (0 on success) + * @retval ERROR_INVALID_STATE + * @retval ERROR_RESOURCE when driver binding fails + * @retval ERROR_NONE */ -int device_start(struct Device* device); +error_t device_start(struct Device* device); /** * Detach the driver. * * @param device - * @return ERROR_INVALID_STATE or otherwise the value of the driver unbinding result (0 on success) + * @retval ERROR_INVALID_STATE + * @retval ERROR_RESOURCE when driver unbinding fails + * @retval ERROR_NONE */ -int device_stop(struct Device* device); +error_t device_stop(struct Device* device); /** * Set or unset a parent. @@ -147,7 +157,7 @@ static inline void device_lock(struct Device* device) { mutex_lock(&device->internal.mutex); } -static inline int device_try_lock(struct Device* device) { +static inline bool device_try_lock(struct Device* device) { return mutex_try_lock(&device->internal.mutex); } @@ -156,7 +166,7 @@ static inline void device_unlock(struct Device* device) { } static inline const struct DeviceType* device_get_type(struct Device* device) { - return device->internal.driver ? device->internal.driver->device_type : NULL; + return device->internal.driver ? device->internal.driver->deviceType : NULL; } /** * Iterate through all the known devices @@ -167,18 +177,18 @@ void for_each_device(void* callback_context, bool(*on_device)(struct Device* dev /** * Iterate through all the child devices of the specified device - * @param callback_context the parameter to pass to the callback. NULL is valid. + * @param callbackContext the parameter to pass to the callback. NULL is valid. * @param on_device the function to call for each filtered device. return true to continue iterating or false to stop. */ -void for_each_device_child(struct Device* device, void* callback_context, bool(*on_device)(struct Device* device, void* context)); +void for_each_device_child(struct Device* device, void* callbackContext, bool(*on_device)(struct Device* device, void* context)); /** * Iterate through all the known devices of a specific type * @param type the type to filter - * @param callback_context the parameter to pass to the callback. NULL is valid. + * @param callbackContext the parameter to pass to the callback. NULL is valid. * @param on_device the function to call for each filtered device. return true to continue iterating or false to stop. */ -void for_each_device_of_type(const struct DeviceType* type, void* callback_context, bool(*on_device)(struct Device* device, void* context)); +void for_each_device_of_type(const struct DeviceType* type, void* callbackContext, bool(*on_device)(struct Device* device, void* context)); #ifdef __cplusplus } diff --git a/TactilityKernel/Include/Tactility/Driver.h b/TactilityKernel/Include/Tactility/Driver.h index 937f9f5d3..341def6fa 100644 --- a/TactilityKernel/Include/Tactility/Driver.h +++ b/TactilityKernel/Include/Tactility/Driver.h @@ -7,6 +7,7 @@ extern "C" { #endif #include +#include "Error.h" struct Device; struct DeviceType; @@ -17,13 +18,13 @@ struct Driver { /** Array of const char*, terminated by NULL */ const char**compatible; /** Function to initialize the driver for a device */ - int (*start_device)(struct Device* dev); + error_t (*startDevice)(struct Device* dev); /** Function to deinitialize the driver for a device */ - int (*stop_device)(struct Device* dev); + error_t (*stopDevice)(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; + const struct DeviceType* deviceType; /** Internal data */ struct { /** Contains private data */ @@ -31,20 +32,20 @@ struct Driver { } internal; }; -int driver_construct(struct Driver* driver); +error_t driver_construct(struct Driver* driver); -int driver_destruct(struct Driver* driver); +error_t driver_destruct(struct Driver* driver); -int driver_bind(struct Driver* driver, struct Device* device); +error_t driver_bind(struct Driver* driver, struct Device* device); -int driver_unbind(struct Driver* driver, struct Device* device); +error_t driver_unbind(struct Driver* driver, struct Device* device); bool driver_is_compatible(struct Driver* driver, const char* compatible); struct Driver* driver_find_compatible(const char* compatible); static inline const struct DeviceType* driver_get_device_type(struct Driver* driver) { - return driver->device_type; + return driver->deviceType; } #ifdef __cplusplus diff --git a/TactilityKernel/Include/Tactility/Error.h b/TactilityKernel/Include/Tactility/Error.h index 81ccc5899..000dba6ca 100644 --- a/TactilityKernel/Include/Tactility/Error.h +++ b/TactilityKernel/Include/Tactility/Error.h @@ -2,9 +2,18 @@ #pragma once +// 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 diff --git a/TactilityKernel/Include/Tactility/concurrent/Dispatcher.h b/TactilityKernel/Include/Tactility/concurrent/Dispatcher.h new file mode 100644 index 000000000..81fd014b8 --- /dev/null +++ b/TactilityKernel/Include/Tactility/concurrent/Dispatcher.h @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: Apache-2.0 + +/** +* Dispatcher is a thread-safe code execution queue. +*/ +#pragma once + +#include +#include + +#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 diff --git a/TactilityKernel/Include/Tactility/concurrent/EventGroup.h b/TactilityKernel/Include/Tactility/concurrent/EventGroup.h new file mode 100644 index 000000000..c5cd124f8 --- /dev/null +++ b/TactilityKernel/Include/Tactility/concurrent/EventGroup.h @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#include +#include + +static inline void event_group_construct(EventGroupHandle_t* eventGroup) { + assert(xPortInIsrContext() == pdFALSE); + *eventGroup = xEventGroupCreate(); +} + +static inline void event_group_destruct(EventGroupHandle_t* eventGroup) { + assert(xPortInIsrContext() == pdFALSE); + assert(*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 diff --git a/TactilityKernel/Include/Tactility/concurrent/Mutex.h b/TactilityKernel/Include/Tactility/concurrent/Mutex.h index 55b2d51c5..eddc4e690 100644 --- a/TactilityKernel/Include/Tactility/concurrent/Mutex.h +++ b/TactilityKernel/Include/Tactility/concurrent/Mutex.h @@ -12,6 +12,7 @@ extern "C" { struct Mutex { QueueHandle_t handle; + // TODO: Debugging functionality }; inline static void mutex_construct(struct Mutex* mutex) { @@ -27,18 +28,30 @@ inline static void mutex_destruct(struct Mutex* mutex) { } inline static void mutex_lock(struct Mutex* mutex) { + assert(xPortInIsrContext() != pdTRUE); xSemaphoreTake(mutex->handle, portMAX_DELAY); } inline static bool mutex_try_lock(struct Mutex* mutex) { + assert(xPortInIsrContext() != pdTRUE); return xSemaphoreTake(mutex->handle, 0) == pdTRUE; } +inline static bool mutex_try_lock_timed(struct Mutex* mutex, TickType_t timeout) { + assert(xPortInIsrContext() != pdTRUE); + return xSemaphoreTake(mutex->handle, timeout) == pdTRUE; +} + inline static bool mutex_is_locked(struct Mutex* mutex) { - return xSemaphoreGetMutexHolder(mutex->handle) != NULL; + if (xPortInIsrContext() == pdTRUE) { + return xSemaphoreGetMutexHolderFromISR(mutex->handle) != NULL; + } else { + return xSemaphoreGetMutexHolder(mutex->handle) != NULL; + } } inline static void mutex_unlock(struct Mutex* mutex) { + assert(xPortInIsrContext() != pdTRUE); xSemaphoreGive(mutex->handle); } diff --git a/TactilityKernel/Include/Tactility/concurrent/RecursiveMutex.h b/TactilityKernel/Include/Tactility/concurrent/RecursiveMutex.h index 09dd9a9e3..b2e451c49 100644 --- a/TactilityKernel/Include/Tactility/concurrent/RecursiveMutex.h +++ b/TactilityKernel/Include/Tactility/concurrent/RecursiveMutex.h @@ -26,18 +26,30 @@ inline static void recursive_mutex_destruct(struct RecursiveMutex* mutex) { } inline static void recursive_mutex_lock(struct RecursiveMutex* mutex) { + assert(xPortInIsrContext() != pdTRUE); xSemaphoreTakeRecursive(mutex->handle, portMAX_DELAY); } inline static bool recursive_mutex_is_locked(struct RecursiveMutex* mutex) { - return xSemaphoreGetMutexHolder(mutex->handle) != NULL; + if (xPortInIsrContext() == pdTRUE) { + return xSemaphoreGetMutexHolderFromISR(mutex->handle) != NULL; + } else { + return xSemaphoreGetMutexHolder(mutex->handle) != NULL; + } } inline static bool recursive_mutex_try_lock(struct RecursiveMutex* mutex) { + assert(xPortInIsrContext() != pdTRUE); return xSemaphoreTakeRecursive(mutex->handle, 0) == pdTRUE; } +inline static bool recursive_mutex_try_lock_timed(struct RecursiveMutex* mutex, TickType_t timeout) { + assert(xPortInIsrContext() != pdTRUE); + return xSemaphoreTakeRecursive(mutex->handle, timeout) == pdTRUE; +} + inline static void recursive_mutex_unlock(struct RecursiveMutex* mutex) { + assert(xPortInIsrContext() != pdTRUE); xSemaphoreGiveRecursive(mutex->handle); } diff --git a/TactilityKernel/Include/Tactility/drivers/Gpio.h b/TactilityKernel/Include/Tactility/drivers/Gpio.h index 8aa08b356..1e26ce1b8 100644 --- a/TactilityKernel/Include/Tactility/drivers/Gpio.h +++ b/TactilityKernel/Include/Tactility/drivers/Gpio.h @@ -6,6 +6,8 @@ extern "C" { #endif +#include +#include #include #define GPIO_OPTIONS_MASK 0x1f @@ -34,57 +36,30 @@ typedef enum { GPIO__MAX, } GpioInterruptType; -/** - * @brief Provides a type to hold a GPIO pin index. - * - * This reduced-size type is sufficient to record a pin number, - * e.g. from a devicetree GPIOS property. - */ +/** The index of a GPIO pin on a GPIO Controller */ typedef uint8_t gpio_pin_t; -/** - * @brief Identifies a set of pins associated with a port. - * - * The pin with index n is present in the set if and only if the bit - * identified by (1U << n) is set. - */ -typedef uint32_t gpio_pinset_t; - -/** - * @brief Provides a type to hold GPIO devicetree flags. - * - * All GPIO flags that can be expressed in devicetree fit in the low 16 - * bits of the full flags field, so use a reduced-size type to record - * that part of a GPIOS property. - * - * The lower 8 bits are used for standard flags. The upper 8 bits are reserved - * for SoC specific flags. - */ +/** Specifies the configuration flags for a GPIO pin (or set of pins) */ typedef uint16_t gpio_flags_t; -/** - * @brief Container for GPIO pin information specified in dts files - * - * This type contains a pointer to a GPIO device, pin identifier for a pin - * controlled by that device, and the subset of pin configuration - * flags which may be given in devicetree. - */ +/** A configuration for a single GPIO pin */ struct GpioPinConfig { /** GPIO device controlling the pin */ const struct Device* port; /** The pin's number on the device */ gpio_pin_t pin; /** The pin's configuration flags as specified in devicetree */ - gpio_flags_t dt_flags; + gpio_flags_t flags; }; /** * Check if the pin is ready to be used. - * @param pin_config the specifications of the pin + * + * @param pinConfig the specifications of the pin * @return true if the pin is ready to be used */ -static inline bool gpio_is_ready(const struct GpioPinConfig* pin_config) { - return device_is_ready(pin_config->port); +static inline bool gpio_is_ready(const struct GpioPinConfig* pinConfig) { + return device_is_ready(pinConfig->port); } #ifdef __cplusplus diff --git a/TactilityKernel/Include/Tactility/drivers/GpioController.h b/TactilityKernel/Include/Tactility/drivers/GpioController.h index 149e601a5..6b3e31ce7 100644 --- a/TactilityKernel/Include/Tactility/drivers/GpioController.h +++ b/TactilityKernel/Include/Tactility/drivers/GpioController.h @@ -7,22 +7,22 @@ extern "C" { #endif #include "Gpio.h" -#include +#include struct GpioControllerApi { - bool (*set_level)(struct Device* device, gpio_pin_t pin, bool high); - bool (*get_level)(struct Device* device, gpio_pin_t pin, bool* high); - bool (*set_options)(struct Device* device, gpio_pin_t pin, gpio_flags_t options); - bool (*get_options)(struct Device* device, gpio_pin_t pin, gpio_flags_t* options); + error_t (*set_level)(struct Device* device, gpio_pin_t pin, bool high); + error_t (*get_level)(struct Device* device, gpio_pin_t pin, bool* high); + error_t (*set_options)(struct Device* device, gpio_pin_t pin, gpio_flags_t options); + error_t (*get_options)(struct Device* device, gpio_pin_t pin, gpio_flags_t* options); }; -bool gpio_controller_set_level(struct Device* device, gpio_pin_t pin, bool high); -bool gpio_controller_get_level(struct Device* device, gpio_pin_t pin, bool* high); -bool gpio_controller_set_options(struct Device* device, gpio_pin_t pin, gpio_flags_t options); -bool gpio_controller_get_options(struct Device* device, gpio_pin_t pin, gpio_flags_t* options); +error_t gpio_controller_set_level(struct Device* device, gpio_pin_t pin, bool high); +error_t gpio_controller_get_level(struct Device* device, gpio_pin_t pin, bool* high); +error_t gpio_controller_set_options(struct Device* device, gpio_pin_t pin, gpio_flags_t options); +error_t gpio_controller_get_options(struct Device* device, gpio_pin_t pin, gpio_flags_t* options); -inline bool gpio_set_options_config(struct Device* device, struct GpioPinConfig* config) { - return gpio_controller_set_options(device, config->pin, config->dt_flags); +static inline error_t gpio_set_options_config(struct Device* device, const struct GpioPinConfig* config) { + return gpio_controller_set_options(device, config->pin, config->flags); } #ifdef __cplusplus diff --git a/TactilityKernel/Include/Tactility/drivers/I2cController.h b/TactilityKernel/Include/Tactility/drivers/I2cController.h index d2b79cff9..c33a8d2f5 100644 --- a/TactilityKernel/Include/Tactility/drivers/I2cController.h +++ b/TactilityKernel/Include/Tactility/drivers/I2cController.h @@ -6,22 +6,24 @@ extern "C" { #endif +#include + #include "Gpio.h" + #include -#include -#include +#include struct I2cControllerApi { - bool (*read)(struct Device* device, uint8_t address, uint8_t* data, size_t dataSize, TickType_t timeout); - bool (*write)(struct Device* device, uint8_t address, const uint8_t* data, uint16_t dataSize, TickType_t timeout); - bool (*write_read)(struct Device* device, uint8_t address, const uint8_t* write_data, size_t write_data_size, uint8_t* read_data, size_t read_data_size, TickType_t timeout); + error_t (*read)(struct Device* device, uint8_t address, uint8_t* data, size_t dataSize, TickType_t timeout); + error_t (*write)(struct Device* device, uint8_t address, const uint8_t* data, uint16_t dataSize, TickType_t timeout); + 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); }; -bool i2c_controller_read(struct Device* device, uint8_t address, uint8_t* data, size_t dataSize, TickType_t timeout); +error_t i2c_controller_read(struct Device* device, uint8_t address, uint8_t* data, size_t dataSize, TickType_t timeout); -bool i2c_controller_write(struct Device* device, uint8_t address, const uint8_t* data, uint16_t dataSize, TickType_t timeout); +error_t i2c_controller_write(struct Device* device, uint8_t address, const uint8_t* data, uint16_t dataSize, TickType_t timeout); -bool i2c_controller_write_read(struct Device* device, uint8_t address, const uint8_t* write_data, size_t write_data_size, uint8_t* read_data, size_t read_data_size, TickType_t timeout); +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); extern const struct DeviceType I2C_CONTROLLER_TYPE; diff --git a/TactilityKernel/Source/Device.cpp b/TactilityKernel/Source/Device.cpp index ef8495cc6..d90e393d3 100644 --- a/TactilityKernel/Source/Device.cpp +++ b/TactilityKernel/Source/Device.cpp @@ -44,17 +44,17 @@ extern "C" { #define get_device_data(device) static_cast(device->internal.data) -int device_construct(Device* device) { +error_t device_construct(Device* device) { device->internal.data = new(std::nothrow) DeviceData; if (device->internal.data == nullptr) { - return ENOMEM; + return ERROR_OUT_OF_MEMORY; } LOG_I(TAG, "construct %s", device->name); mutex_construct(&device->internal.mutex); - return 0; + return ERROR_NONE; } -int device_destruct(Device* device) { +error_t device_destruct(Device* device) { if (device->internal.state.started || device->internal.state.added) { return ERROR_INVALID_STATE; } @@ -65,7 +65,7 @@ int device_destruct(Device* device) { mutex_destruct(&device->internal.mutex); delete get_device_data(device); device->internal.data = nullptr; - return 0; + return ERROR_NONE; } /** Add a child to the list of children */ @@ -87,7 +87,7 @@ static void device_remove_child(struct Device* device, struct Device* child) { device_unlock(device); } -int device_add(Device* device) { +error_t device_add(Device* device) { LOG_I(TAG, "add %s", device->name); // Already added @@ -107,10 +107,10 @@ int device_add(Device* device) { } device->internal.state.added = true; - return 0; + return ERROR_NONE; } -int device_remove(Device* device) { +error_t device_remove(Device* device) { LOG_I(TAG, "remove %s", device->name); if (device->internal.state.started || !device->internal.state.added) { @@ -133,7 +133,7 @@ int device_remove(Device* device) { ledger_unlock(); device->internal.state.added = false; - return 0; + return ERROR_NONE; failed_ledger_lookup: @@ -145,7 +145,7 @@ int device_remove(Device* device) { return ERROR_NOT_FOUND; } -int device_start(Device* device) { +error_t device_start(Device* device) { if (!device->internal.state.added) { return ERROR_INVALID_STATE; } @@ -156,33 +156,31 @@ int device_start(Device* device) { // Already started if (device->internal.state.started) { - return 0; + return ERROR_NONE; } - int result = driver_bind(device->internal.driver, device); - device->internal.state.started = (result == 0); - device->internal.state.start_result = result; - return result; + error_t bind_error = driver_bind(device->internal.driver, device); + device->internal.state.started = (bind_error == ERROR_NONE); + device->internal.state.start_result = bind_error; + return bind_error == ERROR_NONE ? ERROR_NONE : ERROR_RESOURCE; } -int device_stop(struct Device* device) { +error_t device_stop(struct Device* device) { if (!device->internal.state.added) { return ERROR_INVALID_STATE; } - // Not started if (!device->internal.state.started) { - return 0; + return ERROR_NONE; } - int result = driver_unbind(device->internal.driver, device); - if (result != 0) { - return result; + if (driver_unbind(device->internal.driver, device) != ERROR_NONE) { + return ERROR_RESOURCE; } device->internal.state.started = false; device->internal.state.start_result = 0; - return 0; + return ERROR_NONE; } void device_set_parent(Device* device, Device* parent) { @@ -200,22 +198,22 @@ void for_each_device(void* callback_context, bool(*on_device)(Device* device, vo ledger_unlock(); } -void for_each_device_child(Device* device, void* callback_context, bool(*on_device)(struct Device* device, void* context)) { +void for_each_device_child(Device* device, void* callbackContext, bool(*on_device)(struct Device* device, void* context)) { auto* data = get_device_data(device); for (auto* child_device : data->children) { - if (!on_device(child_device, callback_context)) { + if (!on_device(child_device, callbackContext)) { break; } } } -void for_each_device_of_type(const DeviceType* type, void* callback_context, bool(*on_device)(Device* device, void* context)) { +void for_each_device_of_type(const DeviceType* type, void* callbackContext, bool(*on_device)(Device* device, void* context)) { ledger_lock(); for (auto* device : ledger.devices) { auto* driver = device->internal.driver; if (driver != nullptr) { - if (driver->device_type == type) { - if (!on_device(device, callback_context)) { + if (driver->deviceType == type) { + if (!on_device(device, callbackContext)) { break; } } diff --git a/TactilityKernel/Source/Driver.cpp b/TactilityKernel/Source/Driver.cpp index 52fd334a8..217eac3f6 100644 --- a/TactilityKernel/Source/Driver.cpp +++ b/TactilityKernel/Source/Driver.cpp @@ -15,6 +15,7 @@ struct DriverInternalData { Mutex mutex { 0 }; int use_count = 0; + bool destroying = false; DriverInternalData() { mutex_construct(&mutex); @@ -64,7 +65,7 @@ static void driver_add(Driver* driver) { ledger.unlock(); } -static bool driver_remove(Driver* driver) { +static error_t driver_remove(Driver* driver) { LOG_I(TAG, "remove %s", driver->name); ledger.lock(); @@ -72,35 +73,41 @@ static bool driver_remove(Driver* driver) { // check that there actually is a 3 in our vector if (iterator == ledger.drivers.end()) { ledger.unlock(); - return false; + return ERROR_NOT_FOUND; } ledger.drivers.erase(iterator); ledger.unlock(); - return true; + return ERROR_NONE; } extern "C" { -int driver_construct(Driver* driver) { +error_t driver_construct(Driver* driver) { driver->internal.data = new(std::nothrow) DriverInternalData; if (driver->internal.data == nullptr) { - return ENOMEM; + return ERROR_OUT_OF_MEMORY; } driver_add(driver); - return 0; + return ERROR_NONE; } -int driver_destruct(Driver* driver) { - // Check if in use - if (driver_internal_data(driver)->use_count != 0) { +error_t driver_destruct(Driver* driver) { + driver_lock(driver); + if (driver_internal_data(driver)->use_count != 0 || driver_internal_data(driver)->destroying) { + driver_unlock(driver); return ERROR_INVALID_STATE; } + driver_internal_data(driver)->destroying = true; + driver_unlock(driver); + + if (driver_remove(driver) != ERROR_NONE) { + LOG_W(TAG, "Failed to remove driver from ledger: %s", driver->name); + } - driver_remove(driver); delete driver_internal_data(driver); driver->internal.data = nullptr; - return 0; + return ERROR_NONE; } bool driver_is_compatible(Driver* driver, const char* compatible) { @@ -130,18 +137,18 @@ Driver* driver_find_compatible(const char* compatible) { return result; } -int driver_bind(Driver* driver, Device* device) { +error_t driver_bind(Driver* driver, Device* device) { driver_lock(driver); - int err = 0; - if (!device_is_added(device)) { - err = ERROR_INVALID_STATE; + error_t error = ERROR_NONE; + if (driver_internal_data(driver)->destroying || !device_is_added(device)) { + error = ERROR_INVALID_STATE; goto error; } - if (driver->start_device != nullptr) { - err = driver->start_device(device); - if (err != 0) { + if (driver->startDevice != nullptr) { + error = driver->startDevice(device); + if (error != ERROR_NONE) { goto error; } } @@ -150,26 +157,26 @@ int driver_bind(Driver* driver, Device* device) { driver_unlock(driver); LOG_I(TAG, "bound %s to %s", driver->name, device->name); - return 0; + return ERROR_NONE; error: driver_unlock(driver); - return err; + return error; } -int driver_unbind(Driver* driver, Device* device) { +error_t driver_unbind(Driver* driver, Device* device) { driver_lock(driver); - int err = 0; - if (!device_is_added(device)) { - err = ERROR_INVALID_STATE; + error_t error = ERROR_NONE; + if (driver_internal_data(driver)->destroying || !device_is_added(device)) { + error = ERROR_INVALID_STATE; goto error; } - if (driver->stop_device != nullptr) { - err = driver->stop_device(device); - if (err != 0) { + if (driver->stopDevice != nullptr) { + error = driver->stopDevice(device); + if (error != ERROR_NONE) { goto error; } } @@ -179,12 +186,12 @@ int driver_unbind(Driver* driver, Device* device) { LOG_I(TAG, "unbound %s to %s", driver->name, device->name); - return 0; + return ERROR_NONE; error: driver_unlock(driver); - return err; + return error; } } // extern "C" diff --git a/TactilityKernel/Source/concurrent/Dispatcher.cpp b/TactilityKernel/Source/concurrent/Dispatcher.cpp new file mode 100644 index 000000000..ae72fb9d0 --- /dev/null +++ b/TactilityKernel/Source/concurrent/Dispatcher.cpp @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: Apache-2.0 + +#include + +#include + +#include "Tactility/Error.h" + +#include +#include +#include +#include + +#define TAG LOG_TAG("Dispatcher") + +static constexpr EventBits_t BACKPRESSURE_WARNING_COUNT = 100U; +static constexpr EventBits_t WAIT_FLAG = 1U; + +struct QueuedItem { + DispatcherCallback callback; + void* context; +}; + +struct DispatcherData { + Mutex mutex = { 0 }; + std::queue queue = {}; + EventGroupHandle_t eventGroup = nullptr; + std::atomic shutdown{false}; // TODO: Use EventGroup + + DispatcherData() { + event_group_construct(&eventGroup); + mutex_construct(&mutex); + } + + ~DispatcherData() { + event_group_destruct(&eventGroup); + mutex_destruct(&mutex); + } +}; + +#define dispatcher_data(handle) static_cast(handle) + +extern "C" { + +DispatcherHandle_t dispatcher_alloc(void) { + return new DispatcherData(); +} + +void dispatcher_free(DispatcherHandle_t dispatcher) { + auto* data = dispatcher_data(dispatcher); + data->shutdown.store(true, std::memory_order_release); + mutex_lock(&data->mutex); + mutex_unlock(&data->mutex); + delete data; +} + +error_t dispatcher_dispatch_timed(DispatcherHandle_t dispatcher, void* callbackContext, DispatcherCallback callback, TickType_t timeout) { + auto* data = dispatcher_data(dispatcher); + + // Mutate + if (!mutex_try_lock_timed(&data->mutex, timeout)) { +#ifdef ESP_PLATFORM + LOG_E(TAG, "Mutex acquisition timeout"); +#endif + return ERROR_TIMEOUT; + } + + if (data->shutdown.load(std::memory_order_acquire)) { + mutex_unlock(&data->mutex); + return ERROR_INVALID_STATE; + } + + data->queue.push({ + .callback = callback, + .context = callbackContext + }); + + if (data->queue.size() == BACKPRESSURE_WARNING_COUNT) { +#ifdef ESP_PLATFORM + LOG_W(TAG, "Backpressure: You're not consuming fast enough (100 queued)"); +#endif + } + + mutex_unlock(&data->mutex); + + if (event_group_set(data->eventGroup, WAIT_FLAG) != ERROR_NONE) { +#ifdef ESP_PLATFORM + LOG_E(TAG, "Failed to set flag"); +#endif + return ERROR_RESOURCE; + } + + return ERROR_NONE; +} + +error_t dispatcher_consume_timed(DispatcherHandle_t dispatcher, TickType_t timeout) { + auto* data = dispatcher_data(dispatcher); + + // TODO: keep track of time and consider the timeout input as total timeout + + // Wait for signal + error_t error = event_group_wait(data->eventGroup, WAIT_FLAG, false, true, nullptr, timeout); + if (error != ERROR_NONE) { + if (error == ERROR_TIMEOUT) { + return ERROR_TIMEOUT; + } else { + return ERROR_RESOURCE; + } + } + + if (data->shutdown.load(std::memory_order_acquire)) { + return ERROR_INVALID_STATE; + } + + // Mutate + bool processing = true; + do { + if (mutex_try_lock_timed(&data->mutex, 10)) { + if (!data->queue.empty()) { + // Make a copy, so it's thread-safe when we unlock + auto entry = data->queue.front(); + data->queue.pop(); + processing = !data->queue.empty(); + // Don't keep lock as callback might be slow and we want to allow dispatch in the meanwhile + mutex_unlock(&data->mutex); + entry.callback(entry.context); + } else { + processing = false; + mutex_unlock(&data->mutex); + } + } else { +#ifdef ESP_PLATFORM + LOG_W(TAG, "Mutex acquisition timeout"); +#endif + } + + } while (processing && !data->shutdown.load(std::memory_order_acquire)); + + return ERROR_NONE; +} + +} \ No newline at end of file diff --git a/TactilityKernel/Source/concurrent/EventGroup.cpp b/TactilityKernel/Source/concurrent/EventGroup.cpp new file mode 100644 index 000000000..cab2f1fd7 --- /dev/null +++ b/TactilityKernel/Source/concurrent/EventGroup.cpp @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: Apache-2.0 + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +error_t event_group_set(EventGroupHandle_t eventGroup, uint32_t inFlags) { + if (xPortInIsrContext() == pdTRUE) { + BaseType_t yield = pdFALSE; + if (xEventGroupSetBitsFromISR(eventGroup, inFlags, &yield) == pdFAIL) { + return ERROR_RESOURCE; + } + portYIELD_FROM_ISR(yield); + } else { + xEventGroupSetBits(eventGroup, inFlags); + } + return ERROR_NONE; +} + +error_t event_group_clear(EventGroupHandle_t eventGroup, uint32_t flags) { + if (xPortInIsrContext() == pdTRUE) { + if (xEventGroupClearBitsFromISR(eventGroup, flags) == pdFAIL) { + return ERROR_RESOURCE; + } + portYIELD_FROM_ISR(pdTRUE); + } else { + xEventGroupClearBits(eventGroup, flags); + } + return ERROR_NONE; +} + +uint32_t event_group_get(EventGroupHandle_t eventGroup) { + if (xPortInIsrContext() == pdTRUE) { + return xEventGroupGetBitsFromISR(eventGroup); + } else { + return xEventGroupGetBits(eventGroup); + } +} + +error_t event_group_wait( + EventGroupHandle_t eventGroup, + uint32_t inFlags, + bool awaitAll, + bool clearOnExit, + uint32_t* outFlags, + TickType_t timeout +) { + if (xPortInIsrContext()) { + return ERROR_ISR_STATUS; + } + + uint32_t result_flags = xEventGroupWaitBits( + eventGroup, + inFlags, + clearOnExit ? pdTRUE : pdFALSE, + awaitAll ? pdTRUE : pdFALSE, + timeout + ); + + auto invalid_flags = awaitAll + ? ((inFlags & result_flags) != inFlags) // await all + : ((inFlags & result_flags) == 0U); // await any + + if (invalid_flags) { + const uint32_t matched = inFlags & result_flags; + if (matched == 0U) { + return ERROR_TIMEOUT; + } + return ERROR_RESOURCE; + } + + if (outFlags != nullptr) { + *outFlags = result_flags; + } + + return ERROR_NONE; +} + +#ifdef __cplusplus +} +#endif diff --git a/TactilityKernel/Source/drivers/GpioController.cpp b/TactilityKernel/Source/drivers/GpioController.cpp index d97481dd9..4fbbd4d74 100644 --- a/TactilityKernel/Source/drivers/GpioController.cpp +++ b/TactilityKernel/Source/drivers/GpioController.cpp @@ -7,22 +7,22 @@ extern "C" { -bool gpio_controller_set_level(Device* device, gpio_pin_t pin, bool high) { +error_t gpio_controller_set_level(Device* device, gpio_pin_t pin, bool high) { const auto* driver = device_get_driver(device); return GPIO_DRIVER_API(driver)->set_level(device, pin, high); } -bool gpio_controller_get_level(Device* device, gpio_pin_t pin, bool* high) { +error_t gpio_controller_get_level(Device* device, gpio_pin_t pin, bool* high) { const auto* driver = device_get_driver(device); return GPIO_DRIVER_API(driver)->get_level(device, pin, high); } -bool gpio_controller_set_options(Device* device, gpio_pin_t pin, gpio_flags_t options) { +error_t gpio_controller_set_options(Device* device, gpio_pin_t pin, gpio_flags_t options) { const auto* driver = device_get_driver(device); return GPIO_DRIVER_API(driver)->set_options(device, pin, options); } -bool gpio_controller_get_options(Device* device, gpio_pin_t pin, gpio_flags_t* options) { +error_t gpio_controller_get_options(Device* device, gpio_pin_t pin, gpio_flags_t* options) { const auto* driver = device_get_driver(device); return GPIO_DRIVER_API(driver)->get_options(device, pin, options); } diff --git a/TactilityKernel/Source/drivers/I2cController.cpp b/TactilityKernel/Source/drivers/I2cController.cpp index 4dc16ce3d..28a507f61 100644 --- a/TactilityKernel/Source/drivers/I2cController.cpp +++ b/TactilityKernel/Source/drivers/I2cController.cpp @@ -2,24 +2,25 @@ #include #include +#include #define I2C_DRIVER_API(driver) ((struct I2cControllerApi*)driver->api) extern "C" { -bool i2c_controller_read(Device* device, uint8_t address, uint8_t* data, size_t dataSize, TickType_t timeout) { +error_t i2c_controller_read(Device* device, uint8_t address, uint8_t* data, size_t dataSize, TickType_t timeout) { const auto* driver = device_get_driver(device); return I2C_DRIVER_API(driver)->read(device, address, data, dataSize, timeout); } -bool i2c_controller_write(Device* device, uint8_t address, const uint8_t* data, uint16_t dataSize, TickType_t timeout) { +error_t i2c_controller_write(Device* device, uint8_t address, const uint8_t* data, uint16_t dataSize, TickType_t timeout) { const auto* driver = device_get_driver(device); return I2C_DRIVER_API(driver)->write(device, address, data, dataSize, timeout); } -bool i2c_controller_write_read(Device* device, uint8_t address, const uint8_t* write_data, size_t write_data_size, uint8_t* read_data, size_t read_data_size, TickType_t timeout) { +error_t i2c_controller_write_read(Device* device, uint8_t address, const uint8_t* writeData, size_t writeDataSize, uint8_t* readData, size_t readDataSize, TickType_t timeout) { const auto* driver = device_get_driver(device); - return I2C_DRIVER_API(driver)->write_read(device, address, write_data, write_data_size, read_data, read_data_size, timeout); + return I2C_DRIVER_API(driver)->write_read(device, address, writeData, writeDataSize, readData, readDataSize, timeout); } const struct DeviceType I2C_CONTROLLER_TYPE { 0 }; diff --git a/TactilityKernel/Source/drivers/Root.cpp b/TactilityKernel/Source/drivers/Root.cpp index 035c1f917..7229b6403 100644 --- a/TactilityKernel/Source/drivers/Root.cpp +++ b/TactilityKernel/Source/drivers/Root.cpp @@ -8,10 +8,10 @@ extern "C" { Driver root_driver = { .name = "root", .compatible = (const char*[]) { "root", nullptr }, - .start_device = nullptr, - .stop_device = nullptr, + .startDevice = nullptr, + .stopDevice = nullptr, .api = nullptr, - .device_type = nullptr, + .deviceType = nullptr, .internal = { 0 } }; diff --git a/Tests/TactilityKernel/DeviceTest.cpp b/Tests/TactilityKernel/DeviceTest.cpp index 247af86df..922066ad7 100644 --- a/Tests/TactilityKernel/DeviceTest.cpp +++ b/Tests/TactilityKernel/DeviceTest.cpp @@ -8,14 +8,13 @@ TEST_CASE("device_construct and device_destruct should set and unset the correct fields") { Device device = { 0 }; - int error = device_construct(&device); - CHECK_EQ(error, 0); + error_t error = device_construct(&device); + CHECK_EQ(error, ERROR_NONE); CHECK_NE(device.internal.data, nullptr); CHECK_NE(device.internal.mutex.handle, nullptr); - error = device_destruct(&device); - CHECK_EQ(error, 0); + CHECK_EQ(device_destruct(&device), ERROR_NONE); CHECK_EQ(device.internal.data, nullptr); CHECK_EQ(device.internal.mutex.handle, nullptr); @@ -30,13 +29,13 @@ TEST_CASE("device_construct and device_destruct should set and unset the correct TEST_CASE("device_add should add the device to the list of all devices") { Device device = { 0 }; - CHECK_EQ(device_construct(&device), 0); - CHECK_EQ(device_add(&device), 0); + CHECK_EQ(device_construct(&device), ERROR_NONE); + CHECK_EQ(device_add(&device), ERROR_NONE); // Gather all devices std::vector devices; for_each_device(&devices, [](auto* device, auto* context) { - auto* devices_ptr = (std::vector*)context; + auto* devices_ptr = static_cast*>(context); devices_ptr->push_back(device); return true; }); @@ -44,8 +43,8 @@ TEST_CASE("device_add should add the device to the list of all devices") { CHECK_EQ(devices.size(), 1); CHECK_EQ(devices[0], &device); - CHECK_EQ(device_remove(&device), 0); - CHECK_EQ(device_destruct(&device), 0); + CHECK_EQ(device_remove(&device), ERROR_NONE); + CHECK_EQ(device_destruct(&device), ERROR_NONE); } TEST_CASE("device_add should add the device to its parent") { @@ -57,11 +56,11 @@ TEST_CASE("device_add should add the device to its parent") { .parent = &parent }; - CHECK_EQ(device_construct(&parent), 0); - CHECK_EQ(device_add(&parent), 0); + CHECK_EQ(device_construct(&parent), ERROR_NONE); + CHECK_EQ(device_add(&parent), ERROR_NONE); - CHECK_EQ(device_construct(&child), 0); - CHECK_EQ(device_add(&child), 0); + CHECK_EQ(device_construct(&child), ERROR_NONE); + CHECK_EQ(device_add(&child), ERROR_NONE); // Gather all child devices std::vector children; @@ -74,30 +73,30 @@ TEST_CASE("device_add should add the device to its parent") { CHECK_EQ(children.size(), 1); CHECK_EQ(children[0], &child); - CHECK_EQ(device_remove(&child), 0); - CHECK_EQ(device_destruct(&child), 0); + CHECK_EQ(device_remove(&child), ERROR_NONE); + CHECK_EQ(device_destruct(&child), ERROR_NONE); - CHECK_EQ(device_remove(&parent), 0); - CHECK_EQ(device_destruct(&parent), 0); + CHECK_EQ(device_remove(&parent), ERROR_NONE); + CHECK_EQ(device_destruct(&parent), ERROR_NONE); } TEST_CASE("device_add should set the state to 'added'") { Device device = { 0 }; - CHECK_EQ(device_construct(&device), 0); + CHECK_EQ(device_construct(&device), ERROR_NONE); CHECK_EQ(device.internal.state.added, false); - CHECK_EQ(device_add(&device), 0); + CHECK_EQ(device_add(&device), ERROR_NONE); CHECK_EQ(device.internal.state.added, true); - CHECK_EQ(device_remove(&device), 0); - CHECK_EQ(device_destruct(&device), 0); + CHECK_EQ(device_remove(&device), ERROR_NONE); + CHECK_EQ(device_destruct(&device), ERROR_NONE); } TEST_CASE("device_remove should remove it from the list of all devices") { Device device = { 0 }; - CHECK_EQ(device_construct(&device), 0); - CHECK_EQ(device_add(&device), 0); - CHECK_EQ(device_remove(&device), 0); + CHECK_EQ(device_construct(&device), ERROR_NONE); + CHECK_EQ(device_add(&device), ERROR_NONE); + CHECK_EQ(device_remove(&device), ERROR_NONE); // Gather all devices std::vector devices; @@ -109,7 +108,7 @@ TEST_CASE("device_remove should remove it from the list of all devices") { CHECK_EQ(devices.size(), 0); - CHECK_EQ(device_destruct(&device), 0); + CHECK_EQ(device_destruct(&device), ERROR_NONE); } TEST_CASE("device_remove should remove the device from its parent") { @@ -121,12 +120,12 @@ TEST_CASE("device_remove should remove the device from its parent") { .parent = &parent }; - CHECK_EQ(device_construct(&parent), 0); - CHECK_EQ(device_add(&parent), 0); + CHECK_EQ(device_construct(&parent), ERROR_NONE); + CHECK_EQ(device_add(&parent), ERROR_NONE); - CHECK_EQ(device_construct(&child), 0); - CHECK_EQ(device_add(&child), 0); - CHECK_EQ(device_remove(&child), 0); + CHECK_EQ(device_construct(&child), ERROR_NONE); + CHECK_EQ(device_add(&child), ERROR_NONE); + CHECK_EQ(device_remove(&child), ERROR_NONE); // Gather all child devices std::vector children; @@ -138,22 +137,22 @@ TEST_CASE("device_remove should remove the device from its parent") { CHECK_EQ(children.size(), 0); - CHECK_EQ(device_destruct(&child), 0); + CHECK_EQ(device_destruct(&child), ERROR_NONE); - CHECK_EQ(device_remove(&parent), 0); - CHECK_EQ(device_destruct(&parent), 0); + CHECK_EQ(device_remove(&parent), ERROR_NONE); + CHECK_EQ(device_destruct(&parent), ERROR_NONE); } TEST_CASE("device_remove should clear the state 'added'") { Device device = { 0 }; - CHECK_EQ(device_construct(&device), 0); + CHECK_EQ(device_construct(&device), ERROR_NONE); - CHECK_EQ(device_add(&device), 0); + CHECK_EQ(device_add(&device), ERROR_NONE); CHECK_EQ(device.internal.state.added, true); - CHECK_EQ(device_remove(&device), 0); + CHECK_EQ(device_remove(&device), ERROR_NONE); CHECK_EQ(device.internal.state.added, false); - CHECK_EQ(device_destruct(&device), 0); + CHECK_EQ(device_destruct(&device), ERROR_NONE); } TEST_CASE("device_is_ready should return true only when it is started") { @@ -161,30 +160,30 @@ TEST_CASE("device_is_ready should return true only when it is started") { Driver driver = { .name = "test_driver", .compatible = compatible, - .start_device = nullptr, - .stop_device = nullptr, + .startDevice = nullptr, + .stopDevice = nullptr, .api = nullptr, - .device_type = nullptr, + .deviceType = nullptr, .internal = { 0 } }; Device device = { 0 }; - CHECK_EQ(driver_construct(&driver), 0); - CHECK_EQ(device_construct(&device), 0); + CHECK_EQ(driver_construct(&driver), ERROR_NONE); + CHECK_EQ(device_construct(&device), ERROR_NONE); CHECK_EQ(device.internal.state.started, false); device_set_driver(&device, &driver); CHECK_EQ(device.internal.state.started, false); - CHECK_EQ(device_add(&device), 0); + CHECK_EQ(device_add(&device), ERROR_NONE); CHECK_EQ(device.internal.state.started, false); - CHECK_EQ(device_start(&device), 0); + CHECK_EQ(device_start(&device), ERROR_NONE); CHECK_EQ(device.internal.state.started, true); - CHECK_EQ(device_stop(&device), 0); + CHECK_EQ(device_stop(&device), ERROR_NONE); CHECK_EQ(device.internal.state.started, false); - CHECK_EQ(device_remove(&device), 0); + CHECK_EQ(device_remove(&device), ERROR_NONE); CHECK_EQ(device.internal.state.started, false); - CHECK_EQ(driver_destruct(&driver), 0); - CHECK_EQ(device_destruct(&device), 0); + CHECK_EQ(driver_destruct(&driver), ERROR_NONE); + CHECK_EQ(device_destruct(&device), ERROR_NONE); } diff --git a/Tests/TactilityKernel/DispatcherTest.cpp b/Tests/TactilityKernel/DispatcherTest.cpp new file mode 100644 index 000000000..8270e8d78 --- /dev/null +++ b/Tests/TactilityKernel/DispatcherTest.cpp @@ -0,0 +1,25 @@ +#include "doctest.h" +#include +#include + +TEST_CASE("dispatcher test") { + DispatcherHandle_t dispatcher = dispatcher_alloc(); + CHECK_NE(dispatcher, nullptr); + + int count = 0; + auto error = dispatcher_dispatch(dispatcher, &count, [](void* context) { + int* count_ptr = static_cast(context); + (*count_ptr)++; + }); + + CHECK_EQ(error, ERROR_NONE); + vTaskDelay(1); + + CHECK_EQ(count, 0); + + CHECK_EQ(dispatcher_consume(dispatcher), ERROR_NONE); + CHECK_EQ(count, 1); + + dispatcher_free(dispatcher); +} + diff --git a/Tests/TactilityKernel/DriverIntegrationTest.cpp b/Tests/TactilityKernel/DriverIntegrationTest.cpp index f648cfffb..c97cfd759 100644 --- a/Tests/TactilityKernel/DriverIntegrationTest.cpp +++ b/Tests/TactilityKernel/DriverIntegrationTest.cpp @@ -26,10 +26,10 @@ static int stop(Device* device) { static Driver integration_driver = { .name = "integration_test_driver", .compatible = (const char*[]) { "integration", nullptr }, - .start_device = start, - .stop_device = stop, + .startDevice = start, + .stopDevice = stop, .api = nullptr, - .device_type = nullptr, + .deviceType = nullptr, .internal = { 0 } }; @@ -47,18 +47,18 @@ TEST_CASE("driver with with start success and stop success should start and stop .parent = nullptr, }; - CHECK_EQ(driver_construct(&integration_driver), 0); + CHECK_EQ(driver_construct(&integration_driver), ERROR_NONE); - CHECK_EQ(device_construct(&integration_device), 0); + CHECK_EQ(device_construct(&integration_device), ERROR_NONE); device_add(&integration_device); CHECK_EQ(startCalled, 0); - CHECK_EQ(driver_bind(&integration_driver, &integration_device), 0); + CHECK_EQ(driver_bind(&integration_driver, &integration_device), ERROR_NONE); CHECK_EQ(startCalled, 1); CHECK_EQ(stopCalled, 0); - CHECK_EQ(driver_unbind(&integration_driver, &integration_device), 0); + CHECK_EQ(driver_unbind(&integration_driver, &integration_device), ERROR_NONE); CHECK_EQ(stopCalled, 1); - CHECK_EQ(device_remove(&integration_device), 0); - CHECK_EQ(device_destruct(&integration_device), 0); + CHECK_EQ(device_remove(&integration_device), ERROR_NONE); + CHECK_EQ(device_destruct(&integration_device), ERROR_NONE); - CHECK_EQ(driver_destruct(&integration_driver), 0); + CHECK_EQ(driver_destruct(&integration_driver), ERROR_NONE); } diff --git a/Tests/TactilityKernel/DriverTest.cpp b/Tests/TactilityKernel/DriverTest.cpp index b85506a69..c5201b5c3 100644 --- a/Tests/TactilityKernel/DriverTest.cpp +++ b/Tests/TactilityKernel/DriverTest.cpp @@ -4,12 +4,9 @@ TEST_CASE("driver_construct and driver_destruct should set and unset the correct fields") { Driver driver = { 0 }; - int error = driver_construct(&driver); - CHECK_EQ(error, 0); + CHECK_EQ(driver_construct(&driver), ERROR_NONE); CHECK_NE(driver.internal.data, nullptr); - - error = driver_destruct(&driver); - CHECK_EQ(error, 0); + CHECK_EQ(driver_destruct(&driver), ERROR_NONE); CHECK_EQ(driver.internal.data, nullptr); } @@ -18,10 +15,10 @@ TEST_CASE("driver_is_compatible should return true if a compatible value is foun Driver driver = { .name = "test_driver", .compatible = compatible, - .start_device = nullptr, - .stop_device = nullptr, + .startDevice = nullptr, + .stopDevice = nullptr, .api = nullptr, - .device_type = nullptr, + .deviceType = nullptr, .internal = { 0 } }; CHECK_EQ(driver_is_compatible(&driver, "test_compatible"), true); @@ -34,24 +31,22 @@ TEST_CASE("driver_find should only find a compatible driver when the driver was Driver driver = { .name = "test_driver", .compatible = compatible, - .start_device = nullptr, - .stop_device = nullptr, + .startDevice = nullptr, + .stopDevice = nullptr, .api = nullptr, - .device_type = nullptr, + .deviceType = nullptr, .internal = { 0 } }; Driver* found_driver = driver_find_compatible("test_compatible"); CHECK_EQ(found_driver, nullptr); - int error = driver_construct(&driver); - CHECK_EQ(error, 0); + CHECK_EQ(driver_construct(&driver), ERROR_NONE); found_driver = driver_find_compatible("test_compatible"); CHECK_EQ(found_driver, &driver); - error = driver_destruct(&driver); - CHECK_EQ(error, 0); + CHECK_EQ(driver_destruct(&driver), ERROR_NONE); found_driver = driver_find_compatible("test_compatible"); CHECK_EQ(found_driver, nullptr); diff --git a/Tests/TactilityKernel/MutexTest.cpp b/Tests/TactilityKernel/MutexTest.cpp index d84d10d45..a5eb8a1bc 100644 --- a/Tests/TactilityKernel/MutexTest.cpp +++ b/Tests/TactilityKernel/MutexTest.cpp @@ -60,7 +60,7 @@ TEST_CASE("mutex_lock in another task should block when a lock is active") { CHECK_EQ(task_lock_counter, 0); mutex_unlock(&mutex); - vTaskDelay(1); + vTaskDelay(2); // 1 is sufficient most of the time, but not always CHECK_EQ(task_lock_counter, 1); mutex_destruct(&mutex); } diff --git a/Tests/TactilityKernel/RecursiveMutexTest.cpp b/Tests/TactilityKernel/RecursiveMutexTest.cpp index 17c2d319f..1eda5a651 100644 --- a/Tests/TactilityKernel/RecursiveMutexTest.cpp +++ b/Tests/TactilityKernel/RecursiveMutexTest.cpp @@ -80,7 +80,7 @@ TEST_CASE("recursive_mutex_lock in another task should block when a lock is acti CHECK_EQ(task_lock_counter, 0); recursive_mutex_unlock(&mutex); - vTaskDelay(1); + vTaskDelay(2); // 1 is sufficient most of the time, but not always CHECK_EQ(task_lock_counter, 1); recursive_mutex_destruct(&mutex); }