From 04dfe1dd5b811fb36893183cae7db461f0c3a16d Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Sat, 31 Jan 2026 18:40:17 +0100 Subject: [PATCH 1/8] Create hal-devices module --- CMakeLists.txt | 2 + .../Source/Configuration.cpp | 2 +- Devices/lilygo-tdeck/Source/Configuration.cpp | 2 +- .../Source/devices/KeyboardBacklight.h | 2 +- .../Source/devices/TdeckKeyboard.cpp | 2 +- .../Source/devices/TrackballDevice.h | 2 +- .../Source/Configuration.cpp | 2 +- .../lilygo-tdisplay/Source/Configuration.cpp | 2 +- .../Source/Configuration.cpp | 2 +- Devices/simulator/Source/Simulator.cpp | 2 +- .../Source/Configuration.cpp | 2 +- Drivers/XPT2046/Source/Xpt2046Power.cpp | 2 +- Modules/hal-device/CMakeLists.txt | 46 +++++ .../Include/tactility/drivers/hal_device.h | 28 +++ .../Include/tactility/drivers/hal_device.hpp | 21 ++ .../Include/tactility}/hal/Device.h | 19 ++ .../Include/tactility/hal_device_module.h | 12 ++ Modules/hal-device/LICENSE-Apache-2.0.md | 195 ++++++++++++++++++ Modules/hal-device/README.md | 8 + .../hal-device/Source/drivers/hal_device.cpp | 122 +++++++++++ .../hal-device}/Source/hal/Device.cpp | 37 +++- Modules/hal-device/Source/module.cpp | 30 +++ .../Source/drivers/esp32_gpio.cpp | 2 +- Platforms/PlatformEsp32/Source/module.cpp | 2 +- Platforms/PlatformPosix/Source/module.cpp | 2 +- Tactility/CMakeLists.txt | 2 + .../Tactility/hal/display/DisplayDevice.h | 2 +- .../Tactility/hal/encoder/EncoderDevice.h | 2 +- .../Include/Tactility/hal/gps/GpsDevice.h | 2 +- .../Include/Tactility/hal/i2c/I2cDevice.h | 2 +- .../Tactility/hal/keyboard/KeyboardDevice.h | 2 +- .../Include/Tactility/hal/power/PowerDevice.h | 2 +- .../Tactility/hal/sdcard/SdCardDevice.h | 2 +- .../Tactility/hal/sdcard/SdmmcDevice.h | 2 +- .../Include/Tactility/hal/touch/TouchDevice.h | 2 +- Tactility/Source/MountPoints.cpp | 2 +- Tactility/Source/Tactility.cpp | 11 + Tactility/Source/app/AppInstall.cpp | 2 +- .../app/crashdiagnostics/CrashDiagnostics.cpp | 2 +- Tactility/Source/app/power/Power.cpp | 2 +- .../Source/app/systeminfo/SystemInfo.cpp | 2 +- Tactility/Source/hal/Hal.cpp | 2 +- Tactility/Source/hal/sdcard/SdCard.cpp | 2 +- .../service/webserver/WebServerService.cpp | 2 +- Tactility/Source/settings/DisplaySettings.cpp | 2 +- TactilityC/Include/tt_hal_device.h | 4 +- TactilityC/Source/tt_hal_device.cpp | 6 +- TactilityC/Source/tt_hal_display.cpp | 2 +- TactilityC/Source/tt_hal_touch.cpp | 2 +- TactilityKernel/Include/tactility/module.h | 2 + TactilityKernel/Source/device.cpp | 8 +- TactilityKernel/Source/module.cpp | 6 + Tests/Tactility/HalDeviceTest.cpp | 2 +- 53 files changed, 584 insertions(+), 45 deletions(-) create mode 100644 Modules/hal-device/CMakeLists.txt create mode 100644 Modules/hal-device/Include/tactility/drivers/hal_device.h create mode 100644 Modules/hal-device/Include/tactility/drivers/hal_device.hpp rename {Tactility/Include/Tactility => Modules/hal-device/Include/tactility}/hal/Device.h (83%) create mode 100644 Modules/hal-device/Include/tactility/hal_device_module.h create mode 100644 Modules/hal-device/LICENSE-Apache-2.0.md create mode 100644 Modules/hal-device/README.md create mode 100644 Modules/hal-device/Source/drivers/hal_device.cpp rename {Tactility => Modules/hal-device}/Source/hal/Device.cpp (66%) create mode 100644 Modules/hal-device/Source/module.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f34cba512..06cf2decc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ if (DEFINED ENV{ESP_IDF_VERSION}) "Firmware" "Devices/${TACTILITY_DEVICE_PROJECT}" "Drivers" + "Modules" "Platforms/PlatformEsp32" "TactilityKernel" "Tactility" @@ -84,6 +85,7 @@ if (NOT DEFINED ENV{ESP_IDF_VERSION}) add_subdirectory(Libraries/QRCode) add_subdirectory(Libraries/minitar) add_subdirectory(Libraries/minmea) + add_subdirectory(Modules/hal-device) # FreeRTOS set(FREERTOS_CONFIG_FILE_DIRECTORY ${PROJECT_SOURCE_DIR}/Devices/simulator/Source CACHE STRING "") diff --git a/Devices/heltec-wifi-lora-32-v3/Source/Configuration.cpp b/Devices/heltec-wifi-lora-32-v3/Source/Configuration.cpp index fc020c7fd..48eca3ddb 100644 --- a/Devices/heltec-wifi-lora-32-v3/Source/Configuration.cpp +++ b/Devices/heltec-wifi-lora-32-v3/Source/Configuration.cpp @@ -36,7 +36,7 @@ static bool initBoot() { using namespace tt::hal; -static std::vector> createDevices() { +static std::vector> createDevices() { return { createPower(), ButtonControl::createOneButtonControl(0), diff --git a/Devices/lilygo-tdeck/Source/Configuration.cpp b/Devices/lilygo-tdeck/Source/Configuration.cpp index 8ca075363..b01785fe6 100644 --- a/Devices/lilygo-tdeck/Source/Configuration.cpp +++ b/Devices/lilygo-tdeck/Source/Configuration.cpp @@ -12,7 +12,7 @@ bool initBoot(); using namespace tt::hal; -static std::vector> createDevices() { +static std::vector> createDevices() { return { createPower(), createDisplay(), diff --git a/Devices/lilygo-tdeck/Source/devices/KeyboardBacklight.h b/Devices/lilygo-tdeck/Source/devices/KeyboardBacklight.h index 0827e93d8..e3deb858a 100644 --- a/Devices/lilygo-tdeck/Source/devices/KeyboardBacklight.h +++ b/Devices/lilygo-tdeck/Source/devices/KeyboardBacklight.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include class KeyboardBacklightDevice final : public tt::hal::Device { diff --git a/Devices/lilygo-tdeck/Source/devices/TdeckKeyboard.cpp b/Devices/lilygo-tdeck/Source/devices/TdeckKeyboard.cpp index 65357b149..7254acc65 100644 --- a/Devices/lilygo-tdeck/Source/devices/TdeckKeyboard.cpp +++ b/Devices/lilygo-tdeck/Source/devices/TdeckKeyboard.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include diff --git a/Devices/lilygo-tdeck/Source/devices/TrackballDevice.h b/Devices/lilygo-tdeck/Source/devices/TrackballDevice.h index 76e9d88a5..7a2492f73 100644 --- a/Devices/lilygo-tdeck/Source/devices/TrackballDevice.h +++ b/Devices/lilygo-tdeck/Source/devices/TrackballDevice.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include class TrackballDevice : public tt::hal::Device { diff --git a/Devices/lilygo-tdisplay-s3/Source/Configuration.cpp b/Devices/lilygo-tdisplay-s3/Source/Configuration.cpp index 021fca93e..c6a629aca 100644 --- a/Devices/lilygo-tdisplay-s3/Source/Configuration.cpp +++ b/Devices/lilygo-tdisplay-s3/Source/Configuration.cpp @@ -9,7 +9,7 @@ bool initBoot(); using namespace tt::hal; -static std::vector> createDevices() { +static std::vector> createDevices() { return { createPower(), createDisplay(), diff --git a/Devices/lilygo-tdisplay/Source/Configuration.cpp b/Devices/lilygo-tdisplay/Source/Configuration.cpp index 996a5b125..ee5b51794 100644 --- a/Devices/lilygo-tdisplay/Source/Configuration.cpp +++ b/Devices/lilygo-tdisplay/Source/Configuration.cpp @@ -11,7 +11,7 @@ static bool initBoot() { return driver::pwmbacklight::init(LCD_PIN_BACKLIGHT); } -static std::vector> createDevices() { +static std::vector> createDevices() { return { createDisplay(), ButtonControl::createTwoButtonControl(35, 0) diff --git a/Devices/lilygo-tdongle-s3/Source/Configuration.cpp b/Devices/lilygo-tdongle-s3/Source/Configuration.cpp index 1882d2566..be584bd9a 100644 --- a/Devices/lilygo-tdongle-s3/Source/Configuration.cpp +++ b/Devices/lilygo-tdongle-s3/Source/Configuration.cpp @@ -10,7 +10,7 @@ bool initBoot(); using namespace tt::hal; -static std::vector> createDevices() { +static std::vector> createDevices() { return { createDisplay(), createSdCard() diff --git a/Devices/simulator/Source/Simulator.cpp b/Devices/simulator/Source/Simulator.cpp index be0ac9200..02ceac97f 100644 --- a/Devices/simulator/Source/Simulator.cpp +++ b/Devices/simulator/Source/Simulator.cpp @@ -28,7 +28,7 @@ static void deinitPower() { #endif } -static std::vector> createDevices() { +static std::vector> createDevices() { return { std::make_shared(), std::make_shared(), diff --git a/Devices/waveshare-s3-touch-lcd-147/Source/Configuration.cpp b/Devices/waveshare-s3-touch-lcd-147/Source/Configuration.cpp index 086bb5648..164cb66cf 100644 --- a/Devices/waveshare-s3-touch-lcd-147/Source/Configuration.cpp +++ b/Devices/waveshare-s3-touch-lcd-147/Source/Configuration.cpp @@ -10,7 +10,7 @@ bool initBoot(); using namespace tt::hal; -static std::vector> createDevices() { +static std::vector> createDevices() { return { createDisplay(), createSdCard() diff --git a/Drivers/XPT2046/Source/Xpt2046Power.cpp b/Drivers/XPT2046/Source/Xpt2046Power.cpp index ebf040f61..a68668aa3 100644 --- a/Drivers/XPT2046/Source/Xpt2046Power.cpp +++ b/Drivers/XPT2046/Source/Xpt2046Power.cpp @@ -2,7 +2,7 @@ #include "Xpt2046Touch.h" #include -#include +#include static const auto LOGGER = tt::Logger("Xpt2046Power"); diff --git a/Modules/hal-device/CMakeLists.txt b/Modules/hal-device/CMakeLists.txt new file mode 100644 index 000000000..c242467f7 --- /dev/null +++ b/Modules/hal-device/CMakeLists.txt @@ -0,0 +1,46 @@ +cmake_minimum_required(VERSION 3.20) + +if (DEFINED ENV{ESP_IDF_VERSION}) + file(GLOB_RECURSE SOURCE_FILES Source/*.c*) + + list(APPEND REQUIRES_LIST + TactilityKernel + TactilityCore + TactilityFreeRtos + ) + + idf_component_register( + SRCS ${SOURCE_FILES} + INCLUDE_DIRS "Include/" + REQUIRES ${REQUIRES_LIST} + ) + + if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(${COMPONENT_LIB} PUBLIC -Wno-unused-variable) + endif () + +else () + + file(GLOB_RECURSE SOURCES "Source/*.c*") + + add_library(hal-device OBJECT) + + target_sources(hal-device PRIVATE ${SOURCES}) + + target_include_directories(hal-device + PRIVATE Private/ + PUBLIC Include/ + ) + + add_definitions(-D_Nullable=) + add_definitions(-D_Nonnull=) + + target_link_libraries(hal-device PUBLIC + TactilityFreeRtos + TactilityCore + TactilityKernel + freertos_kernel + ) + +endif () + diff --git a/Modules/hal-device/Include/tactility/drivers/hal_device.h b/Modules/hal-device/Include/tactility/drivers/hal_device.h new file mode 100644 index 000000000..6dadcb805 --- /dev/null +++ b/Modules/hal-device/Include/tactility/drivers/hal_device.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +enum class HalDeviceType { + HAL_DEVICE_TYPE_I2C, + HAL_DEVICE_TYPE_DISPLAY, + HAL_DEVICE_TYPE_TOUCH, + HAL_DEVICE_TYPE_SDCARD, + HAL_DEVICE_TYPE_KEYBOARD, + HAL_DEVICE_TYPE_ENCODER, + HAL_DEVICE_TYPE_POWER, + HAL_DEVICE_TYPE_GPS, + HAL_DEVICE_TYPE_OTHER +}; + +HalDeviceType hal_device_get_type(struct Device* device); + +void hal_device_for_each_of_type(HalDeviceType type, void* context, bool(*onDevice)(struct Device* device, void* context)); + +extern const struct DeviceType HAL_DEVICE_TYPE; + +#ifdef __cplusplus +} +#endif diff --git a/Modules/hal-device/Include/tactility/drivers/hal_device.hpp b/Modules/hal-device/Include/tactility/drivers/hal_device.hpp new file mode 100644 index 000000000..9b19e5b53 --- /dev/null +++ b/Modules/hal-device/Include/tactility/drivers/hal_device.hpp @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include "hal_device.h" + +#include +#include + +namespace tt::hal { + +/** + * @brief Get a tt::hal::Device object from a Kernel device. + * @warning The input device must be of type HAL_DEVICE_TYPE + * @param kernelDevice The kernel device + * @return std::shared_ptr + */ +std::shared_ptr hal_device_get_device(::Device* kernelDevice); + +void hal_device_set_device(::Device* kernelDevice, std::shared_ptr halDevice); + +} diff --git a/Tactility/Include/Tactility/hal/Device.h b/Modules/hal-device/Include/tactility/hal/Device.h similarity index 83% rename from Tactility/Include/Tactility/hal/Device.h rename to Modules/hal-device/Include/tactility/hal/Device.h index 4504d062e..a33f86239 100644 --- a/Tactility/Include/Tactility/hal/Device.h +++ b/Modules/hal-device/Include/tactility/hal/Device.h @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: Apache-2.0 #pragma once #include @@ -7,6 +8,10 @@ #include #include +#include + +typedef ::Device KernelDevice; + namespace tt::hal { /** Base class for HAL-related devices. */ class Device { @@ -27,9 +32,19 @@ class Device { typedef uint32_t Id; + struct KernelDeviceHolder { + std::string name = {}; + std::shared_ptr device = std::make_shared(); + + explicit KernelDeviceHolder(std::string name) : name(name) { + device->name = this->name.c_str(); + } + }; + private: Id id; + std::shared_ptr kernelDeviceHolder; public: @@ -49,6 +64,10 @@ class Device { * e.g. "USB charging controller with I2C interface." */ virtual std::string getDescription() const = 0; + + void setKernelDeviceHolder(std::shared_ptr kernelDeviceHolder) { this->kernelDeviceHolder = kernelDeviceHolder; } + + std::shared_ptr getKernelDeviceHolder() const { return kernelDeviceHolder; } }; /** diff --git a/Modules/hal-device/Include/tactility/hal_device_module.h b/Modules/hal-device/Include/tactility/hal_device_module.h new file mode 100644 index 000000000..8efca3909 --- /dev/null +++ b/Modules/hal-device/Include/tactility/hal_device_module.h @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct Module hal_device_module; + +#ifdef __cplusplus +} +#endif diff --git a/Modules/hal-device/LICENSE-Apache-2.0.md b/Modules/hal-device/LICENSE-Apache-2.0.md new file mode 100644 index 000000000..f5f4b8b5e --- /dev/null +++ b/Modules/hal-device/LICENSE-Apache-2.0.md @@ -0,0 +1,195 @@ +Apache License +============== + +_Version 2.0, January 2004_ +_<>_ + +### Terms and Conditions for use, reproduction, and distribution + +#### 1. Definitions + +“License” shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +“Licensor” shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +“Legal Entity” shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, “control” means **(i)** the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the +outstanding shares, or **(iii)** beneficial ownership of such entity. + +“You” (or “Your”) shall mean an individual or Legal Entity exercising +permissions granted by this License. + +“Source” form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +“Object” form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +“Work” shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +“Derivative Works” shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +“Contribution” shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +“submitted” means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as “Not a Contribution.” + +“Contributor” shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +#### 2. Grant of Copyright License + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +#### 3. Grant of Patent License + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +#### 4. Redistribution + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +* **(a)** You must give any other recipients of the Work or Derivative Works a copy of +this License; and +* **(b)** You must cause any modified files to carry prominent notices stating that You +changed the files; and +* **(c)** You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. + +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +#### 5. Submission of Contributions + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +#### 6. Trademarks + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +#### 7. Disclaimer of Warranty + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an “AS IS” BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +#### 8. Limitation of Liability + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +#### 9. Accepting Warranty or Additional Liability + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +_END OF TERMS AND CONDITIONS_ + +### APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets `[]` replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same “printed page” as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/Modules/hal-device/README.md b/Modules/hal-device/README.md new file mode 100644 index 000000000..183590a8d --- /dev/null +++ b/Modules/hal-device/README.md @@ -0,0 +1,8 @@ +**WARNING: This module contains deprecated code** + +This module is the basis for the old Tactility HAL. +This HAL existed before TactilityKernel. + +The C++ `tt::hal::Device` class is replaced by `struct Device` from TactilityKernel. + +License: Apache v2.0 \ No newline at end of file diff --git a/Modules/hal-device/Source/drivers/hal_device.cpp b/Modules/hal-device/Source/drivers/hal_device.cpp new file mode 100644 index 000000000..7e82bfddf --- /dev/null +++ b/Modules/hal-device/Source/drivers/hal_device.cpp @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: Apache-2.0 +#include +#include +#include + +#include +#include +#include +#include + +#define TAG LOG_TAG(HalDevice) + +struct HalDevicePrivate { + std::shared_ptr halDevice; +}; + +#define GET_DATA(device) ((struct HalDevicePrivate*)device->internal.driver_data) + +static enum HalDeviceType getHalDeviceType(tt::hal::Device::Type type) { + switch (type) { + case tt::hal::Device::Type::I2c: + return HalDeviceType::HAL_DEVICE_TYPE_I2C; + case tt::hal::Device::Type::Display: + return HalDeviceType::HAL_DEVICE_TYPE_DISPLAY; + case tt::hal::Device::Type::Touch: + return HalDeviceType::HAL_DEVICE_TYPE_TOUCH; + case tt::hal::Device::Type::SdCard: + return HalDeviceType::HAL_DEVICE_TYPE_SDCARD; + case tt::hal::Device::Type::Keyboard: + return HalDeviceType::HAL_DEVICE_TYPE_KEYBOARD; + case tt::hal::Device::Type::Encoder: + return HalDeviceType::HAL_DEVICE_TYPE_ENCODER; + case tt::hal::Device::Type::Power: + return HalDeviceType::HAL_DEVICE_TYPE_POWER; + case tt::hal::Device::Type::Gps: + return HalDeviceType::HAL_DEVICE_TYPE_GPS; + case tt::hal::Device::Type::Other: + return HalDeviceType::HAL_DEVICE_TYPE_OTHER; + default: + LOG_W(TAG, "Device type %d is not implemented", static_cast(type)); + return HalDeviceType::HAL_DEVICE_TYPE_OTHER; + } +} + +HalDeviceType hal_device_get_type(struct Device* device) { + auto type = GET_DATA(device)->halDevice->getType(); + return getHalDeviceType(type); +} + +void hal_device_for_each_of_type(HalDeviceType type, void* context, bool(*onDevice)(struct Device* device, void* context)) { + struct InternalContext { + HalDeviceType typeParam; + void* contextParam; + bool(*onDeviceParam)(struct Device* device, void* context); + }; + + InternalContext internal_context = { + .typeParam = type, + .contextParam = context, + .onDeviceParam = onDevice + }; + + for_each_device_of_type(&HAL_DEVICE_TYPE, &internal_context, [](Device* device, void* context){ + auto* hal_device_private = GET_DATA(device); + auto* internal_context = static_cast(context); + auto hal_device_type = getHalDeviceType(hal_device_private->halDevice->getType()); + if (hal_device_type == internal_context->typeParam) { + if (!internal_context->onDeviceParam(device, context)) { + return false; + } + } + return true; + }); +} + +namespace tt::hal { + +std::shared_ptr hal_device_get_device(::Device* device) { + auto* hal_device_private = GET_DATA(device); + return hal_device_private->halDevice; +} + +void hal_device_set_device(::Device* kernelDevice, std::shared_ptr halDevice) { + GET_DATA(kernelDevice)->halDevice = std::move(halDevice); +} + +} + +#pragma region Lifecycle + +static error_t start(Device* device) { + ESP_LOGI(TAG, "start %s", device->name); + device->internal.driver_data = new HalDevicePrivate(); + return ERROR_NONE; +} + +static error_t stop(Device* device) { + ESP_LOGI(TAG, "stop %s", device->name); + delete GET_DATA(device); + return ERROR_NONE; +} + +#pragma endregion + +extern "C" { + +const struct DeviceType HAL_DEVICE_TYPE {0}; + +extern struct Module hal_device_module; + +Driver hal_device_driver = { + .name = "hal-device", + .compatible = (const char*[]) {"hal-device", nullptr}, + .startDevice = start, + .stopDevice = stop, + .api = nullptr, + .deviceType = &HAL_DEVICE_TYPE, + .owner = &hal_device_module, + .driver_private = nullptr +}; + +} \ No newline at end of file diff --git a/Tactility/Source/hal/Device.cpp b/Modules/hal-device/Source/hal/Device.cpp similarity index 66% rename from Tactility/Source/hal/Device.cpp rename to Modules/hal-device/Source/hal/Device.cpp index 069058878..2667494b9 100644 --- a/Tactility/Source/hal/Device.cpp +++ b/Modules/hal-device/Source/hal/Device.cpp @@ -1,4 +1,7 @@ -#include +// SPDX-License-Identifier: Apache-2.0 +#include +#include +#include #include #include @@ -20,6 +23,28 @@ auto toVector(RangeType&& range) { return std::vector(view.begin(), view.end()); } +static std::shared_ptr createKernelDeviceHolder(const std::shared_ptr& device) { + auto kernel_device_holder = std::make_shared(device->getName()); + auto* kernel_device = kernel_device_holder->device.get(); + check(device_construct(kernel_device) == ERROR_NONE); + check(device_add(kernel_device) == ERROR_NONE); + auto* driver = driver_find_compatible("hal-device"); + check(driver); + device_set_driver(kernel_device, driver); + check(device_start(kernel_device) == ERROR_NONE); + hal_device_set_device(kernel_device, device); + return kernel_device_holder; +} + +static void destroyKernelDeviceHolder(std::shared_ptr& holder) { + auto kernel_device = holder->device.get(); + hal_device_set_device(kernel_device, nullptr); + check(device_stop(kernel_device) == ERROR_NONE); + check(device_remove(kernel_device) == ERROR_NONE); + check(device_destruct(kernel_device) == ERROR_NONE); + holder->device = nullptr; +} + void registerDevice(const std::shared_ptr& device) { auto scoped_mutex = mutex.asScopedLock(); scoped_mutex.lock(); @@ -27,6 +52,9 @@ void registerDevice(const std::shared_ptr& device) { if (findDevice(device->getId()) == nullptr) { devices.push_back(device); LOGGER.info("Registered {} with id {}", device->getName(), device->getId()); + // Kernel device + auto kernel_device_holder = createKernelDeviceHolder(device); + device->setKernelDeviceHolder(kernel_device_holder); } else { LOGGER.warn("Device {} with id {} was already registered", device->getName(), device->getId()); } @@ -36,6 +64,13 @@ void deregisterDevice(const std::shared_ptr& device) { auto scoped_mutex = mutex.asScopedLock(); scoped_mutex.lock(); + // Kernel device + auto kernel_device_holder = device->getKernelDeviceHolder(); + if (kernel_device_holder) { + destroyKernelDeviceHolder(kernel_device_holder); + device->setKernelDeviceHolder(nullptr); + } + auto id_to_remove = device->getId(); auto remove_iterator = std::remove_if(devices.begin(), devices.end(), [id_to_remove](const auto& device) { return device->getId() == id_to_remove; diff --git a/Modules/hal-device/Source/module.cpp b/Modules/hal-device/Source/module.cpp new file mode 100644 index 000000000..cfca2fb43 --- /dev/null +++ b/Modules/hal-device/Source/module.cpp @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: Apache-2.0 +#include +#include +#include + +extern "C" { + +extern Driver hal_device_driver; + +static error_t start() { + /* We crash when construct fails, because if a single driver fails to construct, + * there is no guarantee that the previously constructed drivers can be destroyed */ + check(driver_construct(&hal_device_driver) == ERROR_NONE); + return ERROR_NONE; +} + +static error_t stop() { + /* We crash when destruct fails, because if a single driver fails to destruct, + * there is no guarantee that the previously destroyed drivers can be recovered */ + check(driver_destruct(&hal_device_driver) == ERROR_NONE); + return ERROR_NONE; +} + +struct Module hal_device_module = { + .name = "hal-device", + .start = start, + .stop = stop +}; + +} diff --git a/Platforms/PlatformEsp32/Source/drivers/esp32_gpio.cpp b/Platforms/PlatformEsp32/Source/drivers/esp32_gpio.cpp index b58f51eb8..3e3c1dd19 100644 --- a/Platforms/PlatformEsp32/Source/drivers/esp32_gpio.cpp +++ b/Platforms/PlatformEsp32/Source/drivers/esp32_gpio.cpp @@ -11,7 +11,7 @@ #define TAG LOG_TAG(esp32_gpio) -#define GET_CONFIG(device) ((struct Esp32GpioConfig*)device->internal.driver_data) +#define GET_CONFIG(device) ((struct Esp32GpioConfig*)device->config) extern "C" { diff --git a/Platforms/PlatformEsp32/Source/module.cpp b/Platforms/PlatformEsp32/Source/module.cpp index 13f47c343..eeb473a95 100644 --- a/Platforms/PlatformEsp32/Source/module.cpp +++ b/Platforms/PlatformEsp32/Source/module.cpp @@ -25,7 +25,7 @@ static error_t stop() { // The name must be exactly "platform_module" struct Module platform_module = { - .name = "ESP32 Platform", + .name = "platform-esp32", .start = start, .stop = stop }; diff --git a/Platforms/PlatformPosix/Source/module.cpp b/Platforms/PlatformPosix/Source/module.cpp index 3bdd3795e..c199b7b60 100644 --- a/Platforms/PlatformPosix/Source/module.cpp +++ b/Platforms/PlatformPosix/Source/module.cpp @@ -14,7 +14,7 @@ static error_t stop() { // The name must be exactly "platform_module" struct Module platform_module = { - .name = "POSIX Platform", + .name = "platform-posix", .start = start, .stop = stop }; diff --git a/Tactility/CMakeLists.txt b/Tactility/CMakeLists.txt index 540d81635..ab506210b 100644 --- a/Tactility/CMakeLists.txt +++ b/Tactility/CMakeLists.txt @@ -8,6 +8,7 @@ if (DEFINED ENV{ESP_IDF_VERSION}) PlatformEsp32 TactilityCore TactilityFreeRtos + hal-device lvgl driver elf_loader @@ -71,6 +72,7 @@ else() TactilityCore TactilityKernel PlatformPosix + hal-device freertos_kernel lvgl lv_screenshot diff --git a/Tactility/Include/Tactility/hal/display/DisplayDevice.h b/Tactility/Include/Tactility/hal/display/DisplayDevice.h index 8d14d1308..d7da87161 100644 --- a/Tactility/Include/Tactility/hal/display/DisplayDevice.h +++ b/Tactility/Include/Tactility/hal/display/DisplayDevice.h @@ -1,6 +1,6 @@ #pragma once -#include "../Device.h" +#include #include diff --git a/Tactility/Include/Tactility/hal/encoder/EncoderDevice.h b/Tactility/Include/Tactility/hal/encoder/EncoderDevice.h index 82e8395e0..14e6e7a82 100644 --- a/Tactility/Include/Tactility/hal/encoder/EncoderDevice.h +++ b/Tactility/Include/Tactility/hal/encoder/EncoderDevice.h @@ -1,6 +1,6 @@ #pragma once -#include "../Device.h" +#include #include diff --git a/Tactility/Include/Tactility/hal/gps/GpsDevice.h b/Tactility/Include/Tactility/hal/gps/GpsDevice.h index 673665879..91af671b8 100644 --- a/Tactility/Include/Tactility/hal/gps/GpsDevice.h +++ b/Tactility/Include/Tactility/hal/gps/GpsDevice.h @@ -1,6 +1,6 @@ #pragma once -#include "../Device.h" +#include #include "GpsConfiguration.h" #include "Satellites.h" diff --git a/Tactility/Include/Tactility/hal/i2c/I2cDevice.h b/Tactility/Include/Tactility/hal/i2c/I2cDevice.h index 0d4c2e7e6..0f7474faa 100644 --- a/Tactility/Include/Tactility/hal/i2c/I2cDevice.h +++ b/Tactility/Include/Tactility/hal/i2c/I2cDevice.h @@ -1,6 +1,6 @@ #pragma once -#include "../Device.h" +#include #include "I2c.h" namespace tt::hal::i2c { diff --git a/Tactility/Include/Tactility/hal/keyboard/KeyboardDevice.h b/Tactility/Include/Tactility/hal/keyboard/KeyboardDevice.h index 17defe108..71630a093 100644 --- a/Tactility/Include/Tactility/hal/keyboard/KeyboardDevice.h +++ b/Tactility/Include/Tactility/hal/keyboard/KeyboardDevice.h @@ -1,6 +1,6 @@ #pragma once -#include "../Device.h" +#include #include diff --git a/Tactility/Include/Tactility/hal/power/PowerDevice.h b/Tactility/Include/Tactility/hal/power/PowerDevice.h index 392f971eb..68246aee2 100644 --- a/Tactility/Include/Tactility/hal/power/PowerDevice.h +++ b/Tactility/Include/Tactility/hal/power/PowerDevice.h @@ -1,6 +1,6 @@ #pragma once -#include "../Device.h" +#include #include namespace tt::hal::power { diff --git a/Tactility/Include/Tactility/hal/sdcard/SdCardDevice.h b/Tactility/Include/Tactility/hal/sdcard/SdCardDevice.h index f93082f3d..208be2d7c 100644 --- a/Tactility/Include/Tactility/hal/sdcard/SdCardDevice.h +++ b/Tactility/Include/Tactility/hal/sdcard/SdCardDevice.h @@ -1,6 +1,6 @@ #pragma once -#include "../Device.h" +#include #include #include diff --git a/Tactility/Include/Tactility/hal/sdcard/SdmmcDevice.h b/Tactility/Include/Tactility/hal/sdcard/SdmmcDevice.h index 01dc79f8d..113b60bb0 100644 --- a/Tactility/Include/Tactility/hal/sdcard/SdmmcDevice.h +++ b/Tactility/Include/Tactility/hal/sdcard/SdmmcDevice.h @@ -5,7 +5,7 @@ #include "SdCardDevice.h" #include -#include +#include #include #include #include diff --git a/Tactility/Include/Tactility/hal/touch/TouchDevice.h b/Tactility/Include/Tactility/hal/touch/TouchDevice.h index 35e9827e0..9616aab6e 100644 --- a/Tactility/Include/Tactility/hal/touch/TouchDevice.h +++ b/Tactility/Include/Tactility/hal/touch/TouchDevice.h @@ -1,6 +1,6 @@ #pragma once -#include "../Device.h" +#include #include "TouchDriver.h" #include diff --git a/Tactility/Source/MountPoints.cpp b/Tactility/Source/MountPoints.cpp index c354df782..ac298fbc2 100644 --- a/Tactility/Source/MountPoints.cpp +++ b/Tactility/Source/MountPoints.cpp @@ -1,7 +1,7 @@ #include "Tactility/MountPoints.h" #include "Tactility/TactilityConfig.h" -#include "Tactility/hal/Device.h" +#include #include "Tactility/hal/sdcard/SdCardDevice.h" #include diff --git a/Tactility/Source/Tactility.cpp b/Tactility/Source/Tactility.cpp index 365ad8394..e628fbdce 100644 --- a/Tactility/Source/Tactility.cpp +++ b/Tactility/Source/Tactility.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -38,6 +39,11 @@ static auto LOGGER = Logger("Tactility"); static const Configuration* config_instance = nullptr; static Dispatcher mainDispatcher; +struct ModuleParent tactility_module_parent { + "tactility", + nullptr +}; + // region Default services namespace service { // Primary @@ -330,6 +336,11 @@ void run(const Configuration& config, Module* platformModule, Module* deviceModu return; } + // HAL compatibility module: it creates kernel driver wrappers for tt::hal::Device + check(module_parent_construct(&tactility_module_parent) == ERROR_NONE); + check(module_set_parent(&hal_device_module, &tactility_module_parent) == ERROR_NONE); + check(module_start(&hal_device_module) == ERROR_NONE); + const hal::Configuration& hardware = *config.hardware; // Assign early so starting services can use it diff --git a/Tactility/Source/app/AppInstall.cpp b/Tactility/Source/app/AppInstall.cpp index f3b87815c..4e4402e87 100644 --- a/Tactility/Source/app/AppInstall.cpp +++ b/Tactility/Source/app/AppInstall.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include diff --git a/Tactility/Source/app/crashdiagnostics/CrashDiagnostics.cpp b/Tactility/Source/app/crashdiagnostics/CrashDiagnostics.cpp index 64a53ed30..f5637ed5f 100644 --- a/Tactility/Source/app/crashdiagnostics/CrashDiagnostics.cpp +++ b/Tactility/Source/app/crashdiagnostics/CrashDiagnostics.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Tactility/Source/app/power/Power.cpp b/Tactility/Source/app/power/Power.cpp index 95f39a61a..571b7e210 100644 --- a/Tactility/Source/app/power/Power.cpp +++ b/Tactility/Source/app/power/Power.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include diff --git a/Tactility/Source/app/systeminfo/SystemInfo.cpp b/Tactility/Source/app/systeminfo/SystemInfo.cpp index bc90d3fdd..e46d20b01 100644 --- a/Tactility/Source/app/systeminfo/SystemInfo.cpp +++ b/Tactility/Source/app/systeminfo/SystemInfo.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include diff --git a/Tactility/Source/hal/Hal.cpp b/Tactility/Source/hal/Hal.cpp index 11d192169..9b1ed1cf9 100644 --- a/Tactility/Source/hal/Hal.cpp +++ b/Tactility/Source/hal/Hal.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/Tactility/Source/hal/sdcard/SdCard.cpp b/Tactility/Source/hal/sdcard/SdCard.cpp index c5e16c9cc..78e75e215 100644 --- a/Tactility/Source/hal/sdcard/SdCard.cpp +++ b/Tactility/Source/hal/sdcard/SdCard.cpp @@ -1,4 +1,4 @@ -#include "Tactility/hal/Device.h" +#include #include "Tactility/hal/sdcard/SdCardDevice.h" namespace tt::hal::sdcard { diff --git a/Tactility/Source/service/webserver/WebServerService.cpp b/Tactility/Source/service/webserver/WebServerService.cpp index f6bca3270..f70396824 100644 --- a/Tactility/Source/service/webserver/WebServerService.cpp +++ b/Tactility/Source/service/webserver/WebServerService.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include #include diff --git a/Tactility/Source/settings/DisplaySettings.cpp b/Tactility/Source/settings/DisplaySettings.cpp index e3fc89ea3..815cbc0ac 100644 --- a/Tactility/Source/settings/DisplaySettings.cpp +++ b/Tactility/Source/settings/DisplaySettings.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include #include diff --git a/TactilityC/Include/tt_hal_device.h b/TactilityC/Include/tt_hal_device.h index 5fcb0f297..e41e17e77 100644 --- a/TactilityC/Include/tt_hal_device.h +++ b/TactilityC/Include/tt_hal_device.h @@ -15,7 +15,7 @@ typedef enum { DEVICE_TYPE_KEYBOARD, DEVICE_TYPE_POWER, DEVICE_TYPE_GPS -} DeviceType; +} TtDeviceType; typedef uint32_t DeviceId; @@ -27,7 +27,7 @@ typedef uint32_t DeviceId; * @param[in] maxCount the maximum number of items that the "deviceIds" output can contain (minimum value is 1) * @return true if one or more devices were found */ -bool tt_hal_device_find(DeviceType type, DeviceId* deviceIds, uint16_t* count, uint16_t maxCount); +bool tt_hal_device_find(TtDeviceType type, DeviceId* deviceIds, uint16_t* count, uint16_t maxCount); #ifdef __cplusplus } diff --git a/TactilityC/Source/tt_hal_device.cpp b/TactilityC/Source/tt_hal_device.cpp index eefc1b374..6a5ad1f46 100644 --- a/TactilityC/Source/tt_hal_device.cpp +++ b/TactilityC/Source/tt_hal_device.cpp @@ -2,9 +2,9 @@ #include -#include +#include -static tt::hal::Device::Type toTactilityDeviceType(DeviceType type) { +static tt::hal::Device::Type toTactilityDeviceType(TtDeviceType type) { switch (type) { case DEVICE_TYPE_I2C: return tt::hal::Device::Type::I2c; @@ -27,7 +27,7 @@ static tt::hal::Device::Type toTactilityDeviceType(DeviceType type) { extern "C" { -bool tt_hal_device_find(DeviceType type, DeviceId* deviceIds, uint16_t* count, uint16_t maxCount) { +bool tt_hal_device_find(TtDeviceType type, DeviceId* deviceIds, uint16_t* count, uint16_t maxCount) { assert(maxCount > 0); int16_t currentIndex = -1; diff --git a/TactilityC/Source/tt_hal_display.cpp b/TactilityC/Source/tt_hal_display.cpp index fbe533a21..d8e4b375e 100644 --- a/TactilityC/Source/tt_hal_display.cpp +++ b/TactilityC/Source/tt_hal_display.cpp @@ -2,7 +2,7 @@ #include -#include +#include #include #include diff --git a/TactilityC/Source/tt_hal_touch.cpp b/TactilityC/Source/tt_hal_touch.cpp index d28089f82..fd1055539 100644 --- a/TactilityC/Source/tt_hal_touch.cpp +++ b/TactilityC/Source/tt_hal_touch.cpp @@ -1,6 +1,6 @@ #include "tt_hal_touch.h" -#include "Tactility/hal/Device.h" +#include #include "Tactility/hal/touch/TouchDevice.h" #include "Tactility/hal/touch/TouchDriver.h" diff --git a/TactilityKernel/Include/tactility/module.h b/TactilityKernel/Include/tactility/module.h index b94db3bb1..ff555bc14 100644 --- a/TactilityKernel/Include/tactility/module.h +++ b/TactilityKernel/Include/tactility/module.h @@ -17,6 +17,8 @@ struct Module { /** * The name of the module, for logging/debugging purposes * Should never be NULL. + * Characters allowed: a-z A-Z 0-9 - _ . + * Desirable format "platform-esp32", "lilygo-tdeck", etc. */ const char* name; diff --git a/TactilityKernel/Source/device.cpp b/TactilityKernel/Source/device.cpp index 5860165aa..8a02d4a10 100644 --- a/TactilityKernel/Source/device.cpp +++ b/TactilityKernel/Source/device.cpp @@ -49,7 +49,7 @@ error_t device_construct(Device* device) { if (device->internal.device_private == nullptr) { return ERROR_OUT_OF_MEMORY; } - LOG_I(TAG, "construct %s", device->name); + LOG_D(TAG, "construct %s", device->name); mutex_construct(&device->internal.mutex); return ERROR_NONE; } @@ -61,7 +61,7 @@ error_t device_destruct(Device* device) { if (!get_device_private(device)->children.empty()) { return ERROR_INVALID_STATE; } - LOG_I(TAG, "destruct %s", device->name); + LOG_D(TAG, "destruct %s", device->name); mutex_destruct(&device->internal.mutex); delete get_device_private(device); device->internal.device_private = nullptr; @@ -88,7 +88,7 @@ static void device_remove_child(struct Device* device, struct Device* child) { } error_t device_add(Device* device) { - LOG_I(TAG, "add %s", device->name); + LOG_D(TAG, "add %s", device->name); // Already added if (device->internal.state.started || device->internal.state.added) { @@ -111,7 +111,7 @@ error_t device_add(Device* device) { } error_t device_remove(Device* device) { - LOG_I(TAG, "remove %s", device->name); + LOG_D(TAG, "remove %s", device->name); if (device->internal.state.started || !device->internal.state.added) { return ERROR_INVALID_STATE; diff --git a/TactilityKernel/Source/module.cpp b/TactilityKernel/Source/module.cpp index 92f347af2..0cde2b3d2 100644 --- a/TactilityKernel/Source/module.cpp +++ b/TactilityKernel/Source/module.cpp @@ -3,6 +3,8 @@ #include #include +#define TAG LOG_TAG(module) + struct ModuleParentPrivate { std::vector modules; struct Mutex mutex = { 0 }; @@ -72,6 +74,8 @@ error_t module_set_parent(struct Module* module, struct ModuleParent* parent) { } error_t module_start(struct Module* module) { + LOG_I(TAG, "start %s", module->name); + if (module->internal.started) return ERROR_NONE; if (!module->internal.parent) return ERROR_INVALID_STATE; @@ -85,6 +89,8 @@ bool module_is_started(struct Module* module) { } error_t module_stop(struct Module* module) { + LOG_I(TAG, "stop %s", module->name); + if (!module->internal.started) return ERROR_NONE; error_t error = module->stop(); diff --git a/Tests/Tactility/HalDeviceTest.cpp b/Tests/Tactility/HalDeviceTest.cpp index 702439475..015323d25 100644 --- a/Tests/Tactility/HalDeviceTest.cpp +++ b/Tests/Tactility/HalDeviceTest.cpp @@ -1,5 +1,5 @@ #include "doctest.h" -#include +#include #include From c8330d87a3ada91c03879c9dbb2ade858a59b4b5 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Sat, 31 Jan 2026 22:39:29 +0100 Subject: [PATCH 2/8] Created hal-devices module, fix GPIO --- Devices/lilygo-tlora-pager/Source/module.cpp | 4 +- .../hal-device/Source/drivers/hal_device.cpp | 2 +- Modules/hal-device/Source/hal/Device.cpp | 48 +++++++------- Modules/hal-device/Source/module.cpp | 3 +- Platforms/PlatformEsp32/Source/module.cpp | 8 +-- TactilityC/Source/tt_hal_gpio.cpp | 4 +- TactilityKernel/Include/tactility/driver.h | 8 +++ TactilityKernel/Source/driver.cpp | 62 +++++++++++-------- TactilityKernel/Source/kernel_init.cpp | 2 +- Tests/TactilityKernel/DeviceTest.cpp | 4 +- .../TactilityKernel/DriverIntegrationTest.cpp | 4 +- Tests/TactilityKernel/DriverTest.cpp | 4 ++ 12 files changed, 88 insertions(+), 65 deletions(-) diff --git a/Devices/lilygo-tlora-pager/Source/module.cpp b/Devices/lilygo-tlora-pager/Source/module.cpp index 9e4a11640..1e1f91600 100644 --- a/Devices/lilygo-tlora-pager/Source/module.cpp +++ b/Devices/lilygo-tlora-pager/Source/module.cpp @@ -9,14 +9,14 @@ extern Driver tlora_pager_driver; static error_t start() { /* We crash when construct fails, because if a single driver fails to construct, * there is no guarantee that the previously constructed drivers can be destroyed */ - check(driver_construct(&tlora_pager_driver) == ERROR_NONE); + check(driver_construct_add(&tlora_pager_driver) == ERROR_NONE); return ERROR_NONE; } static error_t stop() { /* We crash when destruct fails, because if a single driver fails to destruct, * there is no guarantee that the previously destroyed drivers can be recovered */ - check(driver_destruct(&tlora_pager_driver) == ERROR_NONE); + check(driver_remove_destruct(&tlora_pager_driver) == ERROR_NONE); return ERROR_NONE; } diff --git a/Modules/hal-device/Source/drivers/hal_device.cpp b/Modules/hal-device/Source/drivers/hal_device.cpp index 7e82bfddf..e5ac9a40d 100644 --- a/Modules/hal-device/Source/drivers/hal_device.cpp +++ b/Modules/hal-device/Source/drivers/hal_device.cpp @@ -65,7 +65,7 @@ void hal_device_for_each_of_type(HalDeviceType type, void* context, bool(*onDevi auto* internal_context = static_cast(context); auto hal_device_type = getHalDeviceType(hal_device_private->halDevice->getType()); if (hal_device_type == internal_context->typeParam) { - if (!internal_context->onDeviceParam(device, context)) { + if (!internal_context->onDeviceParam(device, internal_context->contextParam)) { return false; } } diff --git a/Modules/hal-device/Source/hal/Device.cpp b/Modules/hal-device/Source/hal/Device.cpp index 2667494b9..2aab71b07 100644 --- a/Modules/hal-device/Source/hal/Device.cpp +++ b/Modules/hal-device/Source/hal/Device.cpp @@ -9,7 +9,6 @@ namespace tt::hal { -std::vector> devices; RecursiveMutex mutex; static Device::Id nextId = 0; @@ -17,14 +16,10 @@ static const auto LOGGER = Logger("Devices"); Device::Device() : id(nextId++) {} -template -auto toVector(RangeType&& range) { - auto view = range | std::views::common; - return std::vector(view.begin(), view.end()); -} - static std::shared_ptr createKernelDeviceHolder(const std::shared_ptr& device) { - auto kernel_device_holder = std::make_shared(device->getName()); + auto kernel_device_name = std::format("hal-device-{}", device->getId()); + LOGGER.info("Registering {} with id {} as kernel device {}", device->getName(), device->getId(), kernel_device_name); + auto kernel_device_holder = std::make_shared(kernel_device_name); auto* kernel_device = kernel_device_holder->device.get(); check(device_construct(kernel_device) == ERROR_NONE); check(device_add(kernel_device) == ERROR_NONE); @@ -49,9 +44,7 @@ void registerDevice(const std::shared_ptr& device) { auto scoped_mutex = mutex.asScopedLock(); scoped_mutex.lock(); - if (findDevice(device->getId()) == nullptr) { - devices.push_back(device); - LOGGER.info("Registered {} with id {}", device->getName(), device->getId()); + if (device->getKernelDeviceHolder() == nullptr) { // Kernel device auto kernel_device_holder = createKernelDeviceHolder(device); device->setKernelDeviceHolder(kernel_device_holder); @@ -69,25 +62,27 @@ void deregisterDevice(const std::shared_ptr& device) { if (kernel_device_holder) { destroyKernelDeviceHolder(kernel_device_holder); device->setKernelDeviceHolder(nullptr); + } else { + LOGGER.warn("Device {} with id {} was not registered", device->getName(), device->getId()); } +} - auto id_to_remove = device->getId(); - auto remove_iterator = std::remove_if(devices.begin(), devices.end(), [id_to_remove](const auto& device) { - return device->getId() == id_to_remove; - }); - if (remove_iterator != devices.end()) { - LOGGER.info("Deregistering {} with id {}", device->getName(), device->getId()); - devices.erase(remove_iterator); - } else { - LOGGER.warn("Deregistering {} with id {} failed: not found", device->getName(), device->getId()); +template +auto toVector(R&& range) { + using T = std::ranges::range_value_t; + std::vector result; + if constexpr (std::ranges::common_range) { + result.reserve(std::ranges::distance(range)); } + std::ranges::copy(range, std::back_inserter(result)); + return result; } std::vector> findDevices(const std::function&)>& filterFunction) { auto scoped_mutex = mutex.asScopedLock(); scoped_mutex.lock(); - auto devices_view = devices | std::views::filter([&filterFunction](auto& device) { + auto devices_view = getDevices() | std::views::filter([&filterFunction](auto& device) { return filterFunction(device); }); return toVector(devices_view); @@ -97,7 +92,7 @@ std::shared_ptr _Nullable findDevice(const std::function> findDevices(Device::Type type) { } std::vector> getDevices() { + std::vector> devices; + for_each_device_of_type(&HAL_DEVICE_TYPE, &devices ,[](auto* kernelDevice, auto* context) { + auto devices_ptr = static_cast>*>(context); + auto hal_device = hal_device_get_device(kernelDevice); + (*devices_ptr).push_back(hal_device); + return true; + }); return devices; } bool hasDevice(Device::Type type) { auto scoped_mutex = mutex.asScopedLock(); scoped_mutex.lock(); - auto result_set = devices | std::views::filter([&type](auto& device) { + auto result_set = getDevices() | std::views::filter([&type](auto& device) { return device->getType() == type; }); return !result_set.empty(); diff --git a/Modules/hal-device/Source/module.cpp b/Modules/hal-device/Source/module.cpp index cfca2fb43..73802337a 100644 --- a/Modules/hal-device/Source/module.cpp +++ b/Modules/hal-device/Source/module.cpp @@ -10,13 +10,14 @@ extern Driver hal_device_driver; static error_t start() { /* We crash when construct fails, because if a single driver fails to construct, * there is no guarantee that the previously constructed drivers can be destroyed */ - check(driver_construct(&hal_device_driver) == ERROR_NONE); + check(driver_construct_add(&hal_device_driver) == ERROR_NONE); return ERROR_NONE; } static error_t stop() { /* We crash when destruct fails, because if a single driver fails to destruct, * there is no guarantee that the previously destroyed drivers can be recovered */ + check(driver_remove(&hal_device_driver) == ERROR_NONE); check(driver_destruct(&hal_device_driver) == ERROR_NONE); return ERROR_NONE; } diff --git a/Platforms/PlatformEsp32/Source/module.cpp b/Platforms/PlatformEsp32/Source/module.cpp index eeb473a95..4c4ad3f34 100644 --- a/Platforms/PlatformEsp32/Source/module.cpp +++ b/Platforms/PlatformEsp32/Source/module.cpp @@ -10,16 +10,16 @@ extern Driver esp32_i2c_driver; static error_t start() { /* We crash when construct fails, because if a single driver fails to construct, * there is no guarantee that the previously constructed drivers can be destroyed */ - check(driver_construct(&esp32_gpio_driver) == ERROR_NONE); - check(driver_construct(&esp32_i2c_driver) == ERROR_NONE); + check(driver_construct_add(&esp32_gpio_driver) == ERROR_NONE); + check(driver_construct_add(&esp32_i2c_driver) == ERROR_NONE); return ERROR_NONE; } static error_t stop() { /* We crash when destruct fails, because if a single driver fails to destruct, * there is no guarantee that the previously destroyed drivers can be recovered */ - check(driver_destruct(&esp32_gpio_driver) == ERROR_NONE); - check(driver_destruct(&esp32_i2c_driver) == ERROR_NONE); + check(driver_remove_destruct(&esp32_gpio_driver) == ERROR_NONE); + check(driver_remove_destruct(&esp32_i2c_driver) == ERROR_NONE); return ERROR_NONE; } diff --git a/TactilityC/Source/tt_hal_gpio.cpp b/TactilityC/Source/tt_hal_gpio.cpp index 6b3dc414b..cc4323d71 100644 --- a/TactilityC/Source/tt_hal_gpio.cpp +++ b/TactilityC/Source/tt_hal_gpio.cpp @@ -24,7 +24,7 @@ bool tt_hal_gpio_get_level(GpioPin pin) { Device* device_result = find_first_gpio_controller(); if (device_result == nullptr) return false; bool pin_state = false; - if (!gpio_controller_get_level(device_result, pin, &pin_state)) return false; + if (gpio_controller_get_level(device_result, pin, &pin_state) != ERROR_NONE) return false; return pin_state; } @@ -32,7 +32,7 @@ int tt_hal_gpio_get_pin_count() { Device* device_result = find_first_gpio_controller(); if (device_result == nullptr) return 0; uint32_t pin_count = 0; - if (!gpio_controller_get_pin_count(device_result, &pin_count)) return 0; + if (gpio_controller_get_pin_count(device_result, &pin_count) != ERROR_NONE) return 0; return (int)pin_count; } diff --git a/TactilityKernel/Include/tactility/driver.h b/TactilityKernel/Include/tactility/driver.h index 92a1bcffb..478252d58 100644 --- a/TactilityKernel/Include/tactility/driver.h +++ b/TactilityKernel/Include/tactility/driver.h @@ -37,6 +37,14 @@ error_t driver_construct(struct Driver* driver); error_t driver_destruct(struct Driver* driver); +error_t driver_add(struct Driver* driver); + +error_t driver_remove(struct Driver* driver); + +error_t driver_construct_add(struct Driver* driver); + +error_t driver_remove_destruct(struct Driver* driver); + error_t driver_bind(struct Driver* driver, struct Device* device); error_t driver_unbind(struct Driver* driver, struct Device* device); diff --git a/TactilityKernel/Source/driver.cpp b/TactilityKernel/Source/driver.cpp index 17da77fef..0bba72992 100644 --- a/TactilityKernel/Source/driver.cpp +++ b/TactilityKernel/Source/driver.cpp @@ -58,28 +58,6 @@ static DriverLedger& get_ledger() { #define driver_lock(driver) mutex_lock(&get_driver_private(driver)->mutex); #define driver_unlock(driver) mutex_unlock(&get_driver_private(driver)->mutex); -static void driver_add(Driver* driver) { - LOG_I(TAG, "add %s", driver->name); - ledger.lock(); - ledger.drivers.push_back(driver); - ledger.unlock(); -} - -static error_t driver_remove(Driver* driver) { - LOG_I(TAG, "remove %s", driver->name); - - ledger.lock(); - const auto iterator = std::ranges::find(ledger.drivers, driver); - if (iterator == ledger.drivers.end()) { - ledger.unlock(); - return ERROR_NOT_FOUND; - } - ledger.drivers.erase(iterator); - ledger.unlock(); - - return ERROR_NONE; -} - extern "C" { error_t driver_construct(Driver* driver) { @@ -87,7 +65,6 @@ error_t driver_construct(Driver* driver) { if (driver->driver_private == nullptr) { return ERROR_OUT_OF_MEMORY; } - driver_add(driver); return ERROR_NONE; } @@ -104,10 +81,6 @@ error_t driver_destruct(Driver* driver) { } get_driver_private(driver)->destroying = true; - if (driver_remove(driver) != ERROR_NONE) { - LOG_W(TAG, "Failed to remove driver from ledger: %s", driver->name); - } - driver_unlock(driver); delete get_driver_private(driver); driver->driver_private = nullptr; @@ -115,6 +88,41 @@ error_t driver_destruct(Driver* driver) { return ERROR_NONE; } +error_t driver_add(Driver* driver) { + LOG_I(TAG, "add %s", driver->name); + ledger.lock(); + ledger.drivers.push_back(driver); + ledger.unlock(); + return ERROR_NONE; +} + +error_t driver_remove(Driver* driver) { + LOG_I(TAG, "remove %s", driver->name); + + ledger.lock(); + const auto iterator = std::ranges::find(ledger.drivers, driver); + if (iterator == ledger.drivers.end()) { + ledger.unlock(); + return ERROR_NOT_FOUND; + } + ledger.drivers.erase(iterator); + ledger.unlock(); + + return ERROR_NONE; +} + +error_t driver_construct_add(struct Driver* driver) { + if (driver_construct(driver) != ERROR_NONE) return ERROR_RESOURCE; + if (driver_add(driver) != ERROR_NONE) return ERROR_RESOURCE; + return ERROR_NONE; +} + +error_t driver_remove_destruct(struct Driver* driver) { + if (driver_remove(driver) != ERROR_NONE) return ERROR_RESOURCE; + if (driver_destruct(driver) != ERROR_NONE) return ERROR_RESOURCE; + return ERROR_NONE; +} + bool driver_is_compatible(Driver* driver, const char* compatible) { if (compatible == nullptr || driver->compatible == nullptr) { return false; diff --git a/TactilityKernel/Source/kernel_init.cpp b/TactilityKernel/Source/kernel_init.cpp index 083926e92..589efedbd 100644 --- a/TactilityKernel/Source/kernel_init.cpp +++ b/TactilityKernel/Source/kernel_init.cpp @@ -14,7 +14,7 @@ struct ModuleParent kernel_module_parent = { static error_t init_kernel_drivers() { extern Driver root_driver; - if (driver_construct(&root_driver) != ERROR_NONE) return ERROR_RESOURCE; + if (driver_construct_add(&root_driver) != ERROR_NONE) return ERROR_RESOURCE; return ERROR_NONE; } diff --git a/Tests/TactilityKernel/DeviceTest.cpp b/Tests/TactilityKernel/DeviceTest.cpp index c53633a12..e1f661957 100644 --- a/Tests/TactilityKernel/DeviceTest.cpp +++ b/Tests/TactilityKernel/DeviceTest.cpp @@ -177,7 +177,7 @@ TEST_CASE("device_is_ready should return true only when it is started") { Device device = { 0 }; - CHECK_EQ(driver_construct(&driver), ERROR_NONE); + CHECK_EQ(driver_construct_add(&driver), ERROR_NONE); CHECK_EQ(device_construct(&device), ERROR_NONE); CHECK_EQ(device.internal.state.started, false); @@ -192,6 +192,6 @@ TEST_CASE("device_is_ready should return true only when it is started") { CHECK_EQ(device_remove(&device), ERROR_NONE); CHECK_EQ(device.internal.state.started, false); - CHECK_EQ(driver_destruct(&driver), ERROR_NONE); CHECK_EQ(device_destruct(&device), ERROR_NONE); + CHECK_EQ(driver_remove_destruct(&driver), ERROR_NONE); } diff --git a/Tests/TactilityKernel/DriverIntegrationTest.cpp b/Tests/TactilityKernel/DriverIntegrationTest.cpp index fd54bd07d..6e7fb6fad 100644 --- a/Tests/TactilityKernel/DriverIntegrationTest.cpp +++ b/Tests/TactilityKernel/DriverIntegrationTest.cpp @@ -55,7 +55,7 @@ TEST_CASE("driver with with start success and stop success should start and stop .parent = nullptr, }; - CHECK_EQ(driver_construct(&integration_driver), ERROR_NONE); + CHECK_EQ(driver_construct_add(&integration_driver), ERROR_NONE); CHECK_EQ(device_construct(&integration_device), ERROR_NONE); device_add(&integration_device); @@ -68,5 +68,5 @@ TEST_CASE("driver with with start success and stop success should start and stop CHECK_EQ(device_remove(&integration_device), ERROR_NONE); CHECK_EQ(device_destruct(&integration_device), ERROR_NONE); - CHECK_EQ(driver_destruct(&integration_driver), ERROR_NONE); + CHECK_EQ(driver_remove_destruct(&integration_driver), ERROR_NONE); } diff --git a/Tests/TactilityKernel/DriverTest.cpp b/Tests/TactilityKernel/DriverTest.cpp index 0876f4c63..93184afd2 100644 --- a/Tests/TactilityKernel/DriverTest.cpp +++ b/Tests/TactilityKernel/DriverTest.cpp @@ -14,7 +14,9 @@ TEST_CASE("driver_construct and driver_destruct should set and unset the correct driver.owner = &module; CHECK_EQ(driver_construct(&driver), ERROR_NONE); + CHECK_EQ(driver_add(&driver), ERROR_NONE); CHECK_NE(driver.driver_private, nullptr); + CHECK_EQ(driver_remove(&driver), ERROR_NONE); CHECK_EQ(driver_destruct(&driver), ERROR_NONE); CHECK_EQ(driver.driver_private, nullptr); } @@ -62,10 +64,12 @@ TEST_CASE("driver_find should only find a compatible driver when the driver was CHECK_EQ(found_driver, nullptr); CHECK_EQ(driver_construct(&driver), ERROR_NONE); + CHECK_EQ(driver_add(&driver), ERROR_NONE); found_driver = driver_find_compatible("test_compatible"); CHECK_EQ(found_driver, &driver); + CHECK_EQ(driver_remove(&driver), ERROR_NONE); CHECK_EQ(driver_destruct(&driver), ERROR_NONE); found_driver = driver_find_compatible("test_compatible"); From 901b38673163b6e274533d36ed7115ab0c682a0b Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Sat, 31 Jan 2026 22:45:03 +0100 Subject: [PATCH 3/8] Fixes --- Modules/hal-device/Include/tactility/hal/Device.h | 2 +- Modules/hal-device/Source/drivers/hal_device.cpp | 8 ++++++-- Tactility/Include/Tactility/hal/gps/GpsDevice.h | 2 +- Tactility/Include/Tactility/hal/power/PowerDevice.h | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Modules/hal-device/Include/tactility/hal/Device.h b/Modules/hal-device/Include/tactility/hal/Device.h index a33f86239..455482c50 100644 --- a/Modules/hal-device/Include/tactility/hal/Device.h +++ b/Modules/hal-device/Include/tactility/hal/Device.h @@ -33,7 +33,7 @@ class Device { typedef uint32_t Id; struct KernelDeviceHolder { - std::string name = {}; + const std::string name; std::shared_ptr device = std::make_shared(); explicit KernelDeviceHolder(std::string name) : name(name) { diff --git a/Modules/hal-device/Source/drivers/hal_device.cpp b/Modules/hal-device/Source/drivers/hal_device.cpp index e5ac9a40d..7b37198f0 100644 --- a/Modules/hal-device/Source/drivers/hal_device.cpp +++ b/Modules/hal-device/Source/drivers/hal_device.cpp @@ -42,6 +42,8 @@ static enum HalDeviceType getHalDeviceType(tt::hal::Device::Type type) { } } +extern "C" { + HalDeviceType hal_device_get_type(struct Device* device) { auto type = GET_DATA(device)->halDevice->getType(); return getHalDeviceType(type); @@ -73,6 +75,8 @@ void hal_device_for_each_of_type(HalDeviceType type, void* context, bool(*onDevi }); } +} + namespace tt::hal { std::shared_ptr hal_device_get_device(::Device* device) { @@ -89,13 +93,13 @@ void hal_device_set_device(::Device* kernelDevice, std::shared_ptr halDe #pragma region Lifecycle static error_t start(Device* device) { - ESP_LOGI(TAG, "start %s", device->name); + LOG_I(TAG, "start %s", device->name); device->internal.driver_data = new HalDevicePrivate(); return ERROR_NONE; } static error_t stop(Device* device) { - ESP_LOGI(TAG, "stop %s", device->name); + LOG_I(TAG, "stop %s", device->name); delete GET_DATA(device); return ERROR_NONE; } diff --git a/Tactility/Include/Tactility/hal/gps/GpsDevice.h b/Tactility/Include/Tactility/hal/gps/GpsDevice.h index 91af671b8..74b5b2ea6 100644 --- a/Tactility/Include/Tactility/hal/gps/GpsDevice.h +++ b/Tactility/Include/Tactility/hal/gps/GpsDevice.h @@ -110,7 +110,7 @@ class GpsDevice : public Device { return lastRmcSubscriptionId; } - void unsubscribeRmc(GgaSubscriptionId subscriptionId) { + void unsubscribeRmc(RmcSubscriptionId subscriptionId) { auto lock = mutex.asScopedLock(); lock.lock(); std::erase_if(rmcSubscriptions, [subscriptionId](auto& subscription) { return subscription.id == subscriptionId; }); diff --git a/Tactility/Include/Tactility/hal/power/PowerDevice.h b/Tactility/Include/Tactility/hal/power/PowerDevice.h index 68246aee2..2177f46af 100644 --- a/Tactility/Include/Tactility/hal/power/PowerDevice.h +++ b/Tactility/Include/Tactility/hal/power/PowerDevice.h @@ -44,4 +44,4 @@ class PowerDevice : public Device { virtual void powerOff() { /* NO-OP*/ } }; -} // namespace tt +} From 9c3d42d1994e4b025929ffa466bb879a07efc1c7 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Sat, 31 Jan 2026 22:54:50 +0100 Subject: [PATCH 4/8] Fixes --- Firmware/CMakeLists.txt | 1 + .../Include/Tactility/freertoscompat/PortCompat.h | 5 +++++ TactilityKernel/Include/tactility/freertos/port.h | 9 +++++++++ 3 files changed, 15 insertions(+) diff --git a/Firmware/CMakeLists.txt b/Firmware/CMakeLists.txt index f570aa52f..8d18c49bf 100644 --- a/Firmware/CMakeLists.txt +++ b/Firmware/CMakeLists.txt @@ -36,6 +36,7 @@ else () TactilityCore TactilityFreeRtos TactilityKernel + hal-device Simulator PlatformPosix SDL2::SDL2-static SDL2-static diff --git a/TactilityFreeRtos/Include/Tactility/freertoscompat/PortCompat.h b/TactilityFreeRtos/Include/Tactility/freertoscompat/PortCompat.h index 3a3de3a34..5b8226738 100644 --- a/TactilityFreeRtos/Include/Tactility/freertoscompat/PortCompat.h +++ b/TactilityFreeRtos/Include/Tactility/freertoscompat/PortCompat.h @@ -4,5 +4,10 @@ #include "RTOS.h" #ifndef ESP_PLATFORM + +// TactilityKernel co-existence check +#ifndef xPortInIsrContext #define xPortInIsrContext(x) (false) #endif + +#endif diff --git a/TactilityKernel/Include/tactility/freertos/port.h b/TactilityKernel/Include/tactility/freertos/port.h index 7618269c8..2f8705e99 100644 --- a/TactilityKernel/Include/tactility/freertos/port.h +++ b/TactilityKernel/Include/tactility/freertos/port.h @@ -5,6 +5,15 @@ #include "freertos.h" #ifndef ESP_PLATFORM + +// TactilityFreeRTGOS co-existence check +#ifndef xPortInIsrContext #define xPortInIsrContext() (pdFALSE) +#endif + +// TactilityFreeRTGOS co-existence check +#ifndef vPortAssertIfInISR #define vPortAssertIfInISR() #endif + +#endif From 6b0c21dbf6c35e868b351a0bde8f3a6fa7a303cf Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Sat, 31 Jan 2026 23:03:49 +0100 Subject: [PATCH 5/8] Fixes --- Modules/hal-device/Include/tactility/hal/Device.h | 2 +- .../Include/Tactility/freertoscompat/PortCompat.h | 2 +- TactilityKernel/Include/tactility/freertos/port.h | 4 ++-- Tests/Tactility/CMakeLists.txt | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Modules/hal-device/Include/tactility/hal/Device.h b/Modules/hal-device/Include/tactility/hal/Device.h index 455482c50..d25dfa230 100644 --- a/Modules/hal-device/Include/tactility/hal/Device.h +++ b/Modules/hal-device/Include/tactility/hal/Device.h @@ -111,7 +111,7 @@ std::vector> findDevices(Device::Type type) { assert(target_device != nullptr); result.push_back(target_device); } - return std::move(result); + return result; } } diff --git a/TactilityFreeRtos/Include/Tactility/freertoscompat/PortCompat.h b/TactilityFreeRtos/Include/Tactility/freertoscompat/PortCompat.h index 5b8226738..ac6a8a2c7 100644 --- a/TactilityFreeRtos/Include/Tactility/freertoscompat/PortCompat.h +++ b/TactilityFreeRtos/Include/Tactility/freertoscompat/PortCompat.h @@ -7,7 +7,7 @@ // TactilityKernel co-existence check #ifndef xPortInIsrContext -#define xPortInIsrContext(x) (false) +#define xPortInIsrContext() (false) #endif #endif diff --git a/TactilityKernel/Include/tactility/freertos/port.h b/TactilityKernel/Include/tactility/freertos/port.h index 2f8705e99..1aa02ba16 100644 --- a/TactilityKernel/Include/tactility/freertos/port.h +++ b/TactilityKernel/Include/tactility/freertos/port.h @@ -6,12 +6,12 @@ #ifndef ESP_PLATFORM -// TactilityFreeRTGOS co-existence check +// TactilityFreeRTOS co-existence check #ifndef xPortInIsrContext #define xPortInIsrContext() (pdFALSE) #endif -// TactilityFreeRTGOS co-existence check +// TactilityFreeRTOS co-existence check #ifndef vPortAssertIfInISR #define vPortAssertIfInISR() #endif diff --git a/Tests/Tactility/CMakeLists.txt b/Tests/Tactility/CMakeLists.txt index 87c29eea2..c8d0167ce 100644 --- a/Tests/Tactility/CMakeLists.txt +++ b/Tests/Tactility/CMakeLists.txt @@ -22,6 +22,7 @@ target_link_libraries(TactilityTests PRIVATE Tactility TactilityCore TactilityKernel + hal-device Simulator SDL2::SDL2-static SDL2-static ) From 16393494803bf31da61d2b855179dd8e77b1f4bc Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Sat, 31 Jan 2026 23:58:26 +0100 Subject: [PATCH 6/8] Fixes --- Tactility/Source/file/ObjectFileWriter.cpp | 2 +- .../Include/tactility/kernel_init.h | 2 +- TactilityKernel/Source/crash.cpp | 5 +++- TactilityKernel/Source/kernel_init.cpp | 14 ++++++----- Tests/Tactility/CMakeLists.txt | 1 + Tests/Tactility/Main.cpp | 24 +++++++++++++++++++ Tests/Tactility/ObjectFileTest.cpp | 2 ++ 7 files changed, 41 insertions(+), 9 deletions(-) diff --git a/Tactility/Source/file/ObjectFileWriter.cpp b/Tactility/Source/file/ObjectFileWriter.cpp index c94a34eba..471d72c81 100644 --- a/Tactility/Source/file/ObjectFileWriter.cpp +++ b/Tactility/Source/file/ObjectFileWriter.cpp @@ -16,7 +16,7 @@ bool ObjectFileWriter::open() { } // Edit existing or create a new file - auto opening_file = std::unique_ptr(std::fopen(filePath.c_str(), "wb")); + auto opening_file = std::unique_ptr(std::fopen(filePath.c_str(), edit_existing ? "rb+" : "wb")); if (opening_file == nullptr) { LOGGER.error("Failed to open file {}", filePath); return false; diff --git a/TactilityKernel/Include/tactility/kernel_init.h b/TactilityKernel/Include/tactility/kernel_init.h index 8f6ad705f..4f4e372be 100644 --- a/TactilityKernel/Include/tactility/kernel_init.h +++ b/TactilityKernel/Include/tactility/kernel_init.h @@ -12,7 +12,7 @@ extern "C" { * Initialize the kernel with platform and device modules, and a device tree. * @param platform_module The platform module to start. This module should not be constructed yet. * @param device_module The device module to start. This module should not be constructed yet. - * @param devicetree_devices The list of generated devices from the devicetree. The array must be terminated by an entry { NULL, NULL } + * @param devicetree_devices The list of generated devices from the devicetree. The array must be terminated by an entry { NULL, NULL }. This parameter can be NULL. * @return ERROR_NONE on success, otherwise an error code */ error_t kernel_init(struct Module* platform_module, struct Module* device_module, struct CompatibleDevice devicetree_devices[]); diff --git a/TactilityKernel/Source/crash.cpp b/TactilityKernel/Source/crash.cpp index 846383ca2..3948d5326 100644 --- a/TactilityKernel/Source/crash.cpp +++ b/TactilityKernel/Source/crash.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -31,7 +32,9 @@ __attribute__((noreturn)) void __crash(void) { #ifdef ESP_PLATFORM esp_system_abort("System halted. Connect debugger for more info."); #else - while (true) { /* Indefinite lock-up */ } + while (true) { + exit(-1); + } #endif __builtin_unreachable(); } diff --git a/TactilityKernel/Source/kernel_init.cpp b/TactilityKernel/Source/kernel_init.cpp index 589efedbd..2f4ac20fd 100644 --- a/TactilityKernel/Source/kernel_init.cpp +++ b/TactilityKernel/Source/kernel_init.cpp @@ -43,13 +43,15 @@ error_t kernel_init(struct Module* platform_module, struct Module* device_module return ERROR_RESOURCE; } - CompatibleDevice* compatible_device = devicetree_devices; - while (compatible_device->device != nullptr) { - if (device_construct_add_start(compatible_device->device, compatible_device->compatible) != ERROR_NONE) { - LOG_E(TAG, "kernel_init failed to construct device: %s (%s)", compatible_device->device->name, compatible_device->compatible); - return ERROR_RESOURCE; + if (devicetree_devices) { + CompatibleDevice* compatible_device = devicetree_devices; + while (compatible_device->device != nullptr) { + if (device_construct_add_start(compatible_device->device, compatible_device->compatible) != ERROR_NONE) { + LOG_E(TAG, "kernel_init failed to construct device: %s (%s)", compatible_device->device->name, compatible_device->compatible); + return ERROR_RESOURCE; + } + compatible_device++; } - compatible_device++; } LOG_I(TAG, "init done"); diff --git a/Tests/Tactility/CMakeLists.txt b/Tests/Tactility/CMakeLists.txt index c8d0167ce..8cc860ec4 100644 --- a/Tests/Tactility/CMakeLists.txt +++ b/Tests/Tactility/CMakeLists.txt @@ -22,6 +22,7 @@ target_link_libraries(TactilityTests PRIVATE Tactility TactilityCore TactilityKernel + PlatformPosix hal-device Simulator SDL2::SDL2-static SDL2-static diff --git a/Tests/Tactility/Main.cpp b/Tests/Tactility/Main.cpp index 89eadd144..27571d1ed 100644 --- a/Tests/Tactility/Main.cpp +++ b/Tests/Tactility/Main.cpp @@ -5,12 +5,27 @@ #include "FreeRTOS.h" #include "task.h" +#include +#include + typedef struct { int argc; char** argv; int result; } TestTaskData; +extern "C" { +// From the relevant platform +extern struct Module platform_module; +// From the relevant device +extern struct Module device_module; +} + +struct ModuleParent tactility_tests_module_parent { + "tactility-tests", + nullptr +}; + void test_task(void* parameter) { auto* data = (TestTaskData*)parameter; @@ -21,6 +36,15 @@ void test_task(void* parameter) { // overrides context.setOption("no-breaks", true); // don't break in the debugger when assertions fail + if (kernel_init(&platform_module, &device_module, nullptr) != ERROR_NONE) { + return; + } + + // HAL compatibility module: it creates kernel driver wrappers for tt::hal::Device + check(module_parent_construct(&tactility_tests_module_parent) == ERROR_NONE); + check(module_set_parent(&hal_device_module, &tactility_tests_module_parent) == ERROR_NONE); + check(module_start(&hal_device_module) == ERROR_NONE); + data->result = context.run(); vTaskEndScheduler(); diff --git a/Tests/Tactility/ObjectFileTest.cpp b/Tests/Tactility/ObjectFileTest.cpp index c07cf78a4..5334649b4 100644 --- a/Tests/Tactility/ObjectFileTest.cpp +++ b/Tests/Tactility/ObjectFileTest.cpp @@ -56,8 +56,10 @@ TEST_CASE("Appending records to a file") { CHECK_EQ(reader.open(), true); CHECK_EQ(reader.hasNext(), true); CHECK_EQ(reader.readNext(&record_in), true); + CHECK_EQ(record_in.value, 0xAAAAAAAA); CHECK_EQ(reader.hasNext(), true); CHECK_EQ(reader.readNext(&record_in), true); + CHECK_EQ(record_in.value, 0xBBBBBBBB); CHECK_EQ(reader.hasNext(), false); reader.close(); From f7b0dbaeca241c59b0ef989486c7520e8bd7f632 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Sun, 1 Feb 2026 00:17:01 +0100 Subject: [PATCH 7/8] Fix for tests --- TactilityKernel/Include/tactility/kernel_init.h | 2 +- TactilityKernel/Source/crash.cpp | 4 +--- TactilityKernel/Source/kernel_init.cpp | 10 ++++++---- Tests/Tactility/Main.cpp | 7 +++---- Tests/TactilityKernel/CMakeLists.txt | 6 +++++- Tests/TactilityKernel/Main.cpp | 8 ++++++++ 6 files changed, 24 insertions(+), 13 deletions(-) diff --git a/TactilityKernel/Include/tactility/kernel_init.h b/TactilityKernel/Include/tactility/kernel_init.h index 4f4e372be..1f3c19bb0 100644 --- a/TactilityKernel/Include/tactility/kernel_init.h +++ b/TactilityKernel/Include/tactility/kernel_init.h @@ -11,7 +11,7 @@ extern "C" { /** * Initialize the kernel with platform and device modules, and a device tree. * @param platform_module The platform module to start. This module should not be constructed yet. - * @param device_module The device module to start. This module should not be constructed yet. + * @param device_module The device module to start. This module should not be constructed yet. This parameter can be NULL. * @param devicetree_devices The list of generated devices from the devicetree. The array must be terminated by an entry { NULL, NULL }. This parameter can be NULL. * @return ERROR_NONE on success, otherwise an error code */ diff --git a/TactilityKernel/Source/crash.cpp b/TactilityKernel/Source/crash.cpp index 3948d5326..dbeeb8a4a 100644 --- a/TactilityKernel/Source/crash.cpp +++ b/TactilityKernel/Source/crash.cpp @@ -32,9 +32,7 @@ __attribute__((noreturn)) void __crash(void) { #ifdef ESP_PLATFORM esp_system_abort("System halted. Connect debugger for more info."); #else - while (true) { - exit(-1); - } + exit(1); #endif __builtin_unreachable(); } diff --git a/TactilityKernel/Source/kernel_init.cpp b/TactilityKernel/Source/kernel_init.cpp index 2f4ac20fd..1877d7fb6 100644 --- a/TactilityKernel/Source/kernel_init.cpp +++ b/TactilityKernel/Source/kernel_init.cpp @@ -37,10 +37,12 @@ error_t kernel_init(struct Module* platform_module, struct Module* device_module return ERROR_RESOURCE; } - module_set_parent(device_module, &kernel_module_parent); - if (module_start(device_module) != ERROR_NONE) { - LOG_E(TAG, "init failed to start device module"); - return ERROR_RESOURCE; + if (device_module != nullptr) { + module_set_parent(device_module, &kernel_module_parent); + if (module_start(device_module) != ERROR_NONE) { + LOG_E(TAG, "init failed to start device module"); + return ERROR_RESOURCE; + } } if (devicetree_devices) { diff --git a/Tests/Tactility/Main.cpp b/Tests/Tactility/Main.cpp index 27571d1ed..b31ff550f 100644 --- a/Tests/Tactility/Main.cpp +++ b/Tests/Tactility/Main.cpp @@ -36,10 +36,7 @@ void test_task(void* parameter) { // overrides context.setOption("no-breaks", true); // don't break in the debugger when assertions fail - if (kernel_init(&platform_module, &device_module, nullptr) != ERROR_NONE) { - return; - } - + check(kernel_init(&platform_module, &device_module, nullptr) == ERROR_NONE); // HAL compatibility module: it creates kernel driver wrappers for tt::hal::Device check(module_parent_construct(&tactility_tests_module_parent) == ERROR_NONE); check(module_set_parent(&hal_device_module, &tactility_tests_module_parent) == ERROR_NONE); @@ -70,4 +67,6 @@ int main(int argc, char** argv) { assert(task_result == pdPASS); vTaskStartScheduler(); + + return data.result; } diff --git a/Tests/TactilityKernel/CMakeLists.txt b/Tests/TactilityKernel/CMakeLists.txt index 8c257f611..620fee5c7 100644 --- a/Tests/TactilityKernel/CMakeLists.txt +++ b/Tests/TactilityKernel/CMakeLists.txt @@ -11,4 +11,8 @@ target_include_directories(TactilityKernelTests PRIVATE ${DOCTESTINC}) add_test(NAME TactilityKernelTests COMMAND TactilityKernelTests) -target_link_libraries(TactilityKernelTests PUBLIC TactilityKernel) +target_link_libraries(TactilityKernelTests PUBLIC + TactilityKernel + PlatformPosix + hal-device +) diff --git a/Tests/TactilityKernel/Main.cpp b/Tests/TactilityKernel/Main.cpp index 6adf361fa..3026b3014 100644 --- a/Tests/TactilityKernel/Main.cpp +++ b/Tests/TactilityKernel/Main.cpp @@ -3,6 +3,7 @@ #include #include +#include typedef struct { int argc; @@ -10,6 +11,11 @@ typedef struct { int result; } TestTaskData; +extern "C" { +// From the relevant platform +extern struct Module platform_module; +} + void test_task(void* parameter) { auto* data = (TestTaskData*)parameter; @@ -20,6 +26,8 @@ void test_task(void* parameter) { // overrides context.setOption("no-breaks", true); // don't break in the debugger when assertions fail + check(kernel_init(&platform_module, nullptr, nullptr) == ERROR_NONE); + data->result = context.run(); vTaskEndScheduler(); From 32cb599fb666f883b50da92d4dd78990ffb4c40d Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Sun, 1 Feb 2026 00:40:03 +0100 Subject: [PATCH 8/8] Fix --- Devices/lilygo-tlora-pager/Source/Configuration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Devices/lilygo-tlora-pager/Source/Configuration.cpp b/Devices/lilygo-tlora-pager/Source/Configuration.cpp index fd025898f..f34d5ade4 100644 --- a/Devices/lilygo-tlora-pager/Source/Configuration.cpp +++ b/Devices/lilygo-tlora-pager/Source/Configuration.cpp @@ -22,7 +22,7 @@ static DeviceVector createDevices() { auto tca8418 = std::make_shared(I2C_NUM_0); auto keyboard = std::make_shared(tca8418); - return std::vector> { + return std::vector> { tca8418, std::make_shared(I2C_NUM_0), bq27220,