Merge develop into main (#365)

### TactilityC
- Create UART HAL
- Refactor locking APIs
- Bind new C++ functionality
- Bind new LVGL functionality

### Apps
- Remove Serial Console as it has been ported as an external app
This commit is contained in:
Ken Van Hoeylandt 2025-10-08 23:16:45 +02:00 committed by GitHub
parent 17b4fc6a47
commit d25603166a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 391 additions and 702 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 432 B

View File

@ -28,8 +28,6 @@ enum class Status {
class Uart { class Uart {
private:
uint32_t id; uint32_t id;
public: public:
@ -37,7 +35,7 @@ public:
Uart(); Uart();
virtual ~Uart(); virtual ~Uart();
inline uint32_t getId() const { return id; } uint32_t getId() const { return id; }
virtual bool start() = 0; virtual bool start() = 0;
virtual bool isStarted() const = 0; virtual bool isStarted() const = 0;
@ -60,11 +58,11 @@ public:
/** Read a single byte */ /** Read a single byte */
virtual bool readByte(std::byte* output, TickType_t timeout = defaultTimeout) = 0; virtual bool readByte(std::byte* output, TickType_t timeout = defaultTimeout) = 0;
inline bool readByte(char* output, TickType_t timeout = defaultTimeout) { bool readByte(char* output, TickType_t timeout = defaultTimeout) {
return readByte(reinterpret_cast<std::byte*>(output), timeout); return readByte(reinterpret_cast<std::byte*>(output), timeout);
} }
inline bool readByte(uint8_t* output, TickType_t timeout = defaultTimeout) { bool readByte(uint8_t* output, TickType_t timeout = defaultTimeout) {
return readByte(reinterpret_cast<std::byte*>(output), timeout); return readByte(reinterpret_cast<std::byte*>(output), timeout);
} }
@ -77,7 +75,7 @@ public:
*/ */
virtual size_t writeBytes(const std::byte* buffer, size_t bufferSize, TickType_t timeout = defaultTimeout) = 0; virtual size_t writeBytes(const std::byte* buffer, size_t bufferSize, TickType_t timeout = defaultTimeout) = 0;
inline size_t writeBytes(const std::uint8_t* buffer, size_t bufferSize, TickType_t timeout = defaultTimeout) { size_t writeBytes(const std::uint8_t* buffer, size_t bufferSize, TickType_t timeout = defaultTimeout) {
return writeBytes(reinterpret_cast<const std::byte*>(buffer), bufferSize, timeout); return writeBytes(reinterpret_cast<const std::byte*>(buffer), bufferSize, timeout);
} }

View File

@ -1,159 +0,0 @@
#pragma once
#include "View.h"
#include <Tactility/Preferences.h>
#include <Tactility/Tactility.h>
#include <Tactility/app/alertdialog/AlertDialog.h>
#include <Tactility/hal/uart/Uart.h>
#include <Tactility/lvgl/LvglSync.h>
#include <Tactility/lvgl/Style.h>
#include <Tactility/StringUtils.h>
#include <string>
namespace tt::app::serialconsole {
class ConnectView final : public View {
public:
typedef std::function<void(std::unique_ptr<hal::uart::Uart>)> OnConnectedFunction;
std::vector<std::string> uartNames;
Preferences preferences = Preferences("SerialConsole");
private:
OnConnectedFunction onConnected;
lv_obj_t* busDropdown = nullptr;
lv_obj_t* speedTextarea = nullptr;
int32_t getSpeedInput() const {
auto* speed_text = lv_textarea_get_text(speedTextarea);
return std::stoi(speed_text);
}
void onConnect() {
auto lock = lvgl::getSyncLock()->asScopedLock();
if (!lock.lock(lvgl::defaultLockTime)) {
return;
}
auto selected_uart_index = lv_dropdown_get_selected(busDropdown);
if (selected_uart_index >= uartNames.size()) {
alertdialog::start("Error", "No UART selected");
return;
}
auto uart_name = uartNames[selected_uart_index];
auto uart = hal::uart::open(uart_name);
if (uart == nullptr) {
alertdialog::start("Error", "Failed to connect to UART");
return;
}
int speed = getSpeedInput();
if (speed <= 0) {
alertdialog::start("Error", "Invalid speed");
return;
}
if (!uart->start()) {
alertdialog::start("Error", "Failed to initialize");
return;
}
if (!uart->setBaudRate(speed)) {
uart->stop();
alertdialog::start("Error", "Failed to set baud rate");
return;
}
onConnected(std::move(uart));
}
static void onConnectCallback(lv_event_t* event) {
auto* view = (ConnectView*)lv_event_get_user_data(event);
view->onConnect();
}
static lv_obj_t* createRowWrapper(lv_obj_t* parent) {
auto* wrapper = lv_obj_create(parent);
lv_obj_set_size(wrapper, LV_PCT(100), LV_SIZE_CONTENT);
lv_obj_set_style_border_width(wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_pad_all(wrapper, 0, LV_STATE_DEFAULT);
return wrapper;
}
public:
explicit ConnectView(OnConnectedFunction onConnected) : onConnected(std::move(onConnected)) {}
void onStart(lv_obj_t* parent) {
uartNames = hal::uart::getNames();
auto* wrapper = lv_obj_create(parent);
lv_obj_set_flex_flow(wrapper, LV_FLEX_FLOW_COLUMN);
lv_obj_set_size(wrapper, LV_PCT(100), LV_SIZE_CONTENT);
lv_obj_set_style_border_width(wrapper, 0, LV_STATE_DEFAULT);
lvgl::obj_set_style_bg_invisible(wrapper);
// Bus selection
auto* bus_wrapper = createRowWrapper(wrapper);
busDropdown = lv_dropdown_create(bus_wrapper);
auto bus_options = string::join(uartNames, "\n");
lv_dropdown_set_options(busDropdown, bus_options.c_str());
lv_obj_align(busDropdown, LV_ALIGN_RIGHT_MID, 0, 0);
lv_obj_set_width(busDropdown, LV_PCT(50));
int32_t bus_index = 0;
preferences.optInt32("bus", bus_index);
if (bus_index < uartNames.size()) {
lv_dropdown_set_selected(busDropdown, bus_index);
}
auto* bus_label = lv_label_create(bus_wrapper);
lv_obj_align(bus_label, LV_ALIGN_LEFT_MID, 0, 0);
lv_label_set_text(bus_label, "Bus");
// Baud rate selection
auto* baud_wrapper = createRowWrapper(wrapper);
int32_t speed = 115200;
preferences.optInt32("speed", speed);
speedTextarea = lv_textarea_create(baud_wrapper);
lv_textarea_set_text(speedTextarea, std::to_string(speed).c_str());
lv_textarea_set_one_line(speedTextarea, true);
lv_obj_set_width(speedTextarea, LV_PCT(50));
lv_obj_align(speedTextarea, LV_ALIGN_TOP_RIGHT, 0, 0);
auto* baud_rate_label = lv_label_create(baud_wrapper);
lv_obj_align(baud_rate_label, LV_ALIGN_TOP_LEFT, 0, 0);
lv_label_set_text(baud_rate_label, "Baud");
// Connect
auto* connect_wrapper = createRowWrapper(wrapper);
auto* connect_button = lv_button_create(connect_wrapper);
lv_obj_align(connect_button, LV_ALIGN_CENTER, 0, 0);
lv_obj_add_event_cb(connect_button, onConnectCallback, LV_EVENT_SHORT_CLICKED, this);
auto* connect_label = lv_label_create(connect_button);
lv_label_set_text(connect_label, "Connect");
}
void onStop() override {
int speed = getSpeedInput();
if (speed > 0) {
preferences.putInt32("speed", speed);
}
auto bus_index = (int32_t)lv_dropdown_get_selected(busDropdown);
preferences.putInt32("bus", bus_index);
}
};
} // namespace tt::app::serialconsole

View File

@ -1,283 +0,0 @@
#pragma once
#include <Tactility/app/serialconsole/View.h>
#include <Tactility/Timer.h>
#include <cstring>
#include <sstream>
namespace tt::app::serialconsole {
constexpr auto* TAG = "SerialConsole";
constexpr size_t receiveBufferSize = 512;
constexpr size_t renderBufferSize = receiveBufferSize + 2; // Leave space for newline at split and null terminator at the end
class ConsoleView final : public View {
lv_obj_t* _Nullable parent = nullptr;
lv_obj_t* _Nullable logTextarea = nullptr;
lv_obj_t* _Nullable inputTextarea = nullptr;
std::unique_ptr<hal::uart::Uart> _Nullable uart = nullptr;
std::shared_ptr<Thread> uartThread _Nullable = nullptr;
bool uartThreadInterrupted = false;
std::shared_ptr<Thread> viewThread _Nullable = nullptr;
bool viewThreadInterrupted = false;
Mutex mutex = Mutex(Mutex::Type::Recursive);
uint8_t receiveBuffer[receiveBufferSize];
uint8_t renderBuffer[renderBufferSize];
size_t receiveBufferPosition = 0;
std::string terminatorString = "\n";
bool isUartThreadInterrupted() const {
auto lock = mutex.asScopedLock();
lock.lock();
return uartThreadInterrupted;
}
bool isViewThreadInterrupted() const {
auto lock = mutex.asScopedLock();
lock.lock();
return viewThreadInterrupted;
}
void updateViews() {
auto lvgl_lock = lvgl::getSyncLock()->asScopedLock();
if (!lvgl_lock.lock(lvgl::defaultLockTime)) {
return;
}
if (parent == nullptr) {
return;
}
// Updating the view is expensive, so we only want to set the text once:
// Gather all the lines in a single buffer
if (mutex.lock()) {
size_t first_part_size = receiveBufferSize - receiveBufferPosition;
memcpy(renderBuffer, receiveBuffer + receiveBufferPosition, first_part_size);
renderBuffer[receiveBufferPosition] = '\n';
if (receiveBufferPosition > 0) {
memcpy(renderBuffer + first_part_size + 1, receiveBuffer, (receiveBufferSize - first_part_size));
renderBuffer[receiveBufferSize - 1] = 0x00;
}
mutex.unlock();
}
if (lvgl::lock(lvgl::defaultLockTime)) {
lv_textarea_set_text(logTextarea, (const char*)renderBuffer);
lvgl::unlock();
}
}
int32_t viewThreadMain() {
while (!isViewThreadInterrupted()) {
auto start_time = kernel::getTicks();
updateViews();
auto end_time = kernel::getTicks();
auto time_diff = end_time - start_time;
if (time_diff < 500U) {
kernel::delayTicks((500U - time_diff) / portTICK_PERIOD_MS);
}
}
return 0;
}
int32_t uartThreadMain() {
uint8_t byte;
while (!isUartThreadInterrupted()) {
assert(uart != nullptr);
bool success = uart->readByte(&byte, 50 / portTICK_PERIOD_MS);
// Thread might've been interrupted in the meanwhile
if (isUartThreadInterrupted()) {
break;
}
if (success) {
mutex.lock();
receiveBuffer[receiveBufferPosition++] = byte;
if (receiveBufferPosition == receiveBufferSize) {
receiveBufferPosition = 0;
}
mutex.unlock();
}
}
return 0;
}
static void onSendClickedCallback(lv_event_t* event) {
auto* view = (ConsoleView*)lv_event_get_user_data(event);
view->onSendClicked();
}
static void onTerminatorDropdownValueChangedCallback(lv_event_t* event) {
auto* view = (ConsoleView*)lv_event_get_user_data(event);
view->onTerminatorDropDownValueChanged(event);
}
void onTerminatorDropDownValueChanged(lv_event_t* event) {
auto* dropdown = static_cast<lv_obj_t*>(lv_event_get_target(event));
mutex.lock();
switch (lv_dropdown_get_selected(dropdown)) {
case 0:
terminatorString = "\n";
break;
case 1:
terminatorString = "\r\n";
break;
}
mutex.unlock();
}
void onSendClicked() {
mutex.lock();
std::string input_text = lv_textarea_get_text(inputTextarea);
std::string to_send = input_text + terminatorString;
mutex.unlock();
auto* safe_uart = uart.get();
if (safe_uart != nullptr) {
if (!safe_uart->writeString(to_send.c_str(), 100 / portTICK_PERIOD_MS)) {
TT_LOG_E(TAG, "Failed to send \"%s\"", input_text.c_str());
}
}
lv_textarea_set_text(inputTextarea, "");
}
public:
void startLogic(std::unique_ptr<hal::uart::Uart> newUart) {
memset(receiveBuffer, 0, receiveBufferSize);
assert(uartThread == nullptr);
assert(uart == nullptr);
uart = std::move(newUart);
uartThreadInterrupted = false;
uartThread = std::make_unique<Thread>(
"SerConsUart",
4096,
[this]() {
return this->uartThreadMain();
}
);
uartThread->setPriority(tt::Thread::Priority::High);
uartThread->start();
}
void startViews(lv_obj_t* parent) {
this->parent = parent;
lv_obj_set_style_pad_gap(parent, 2, 0);
logTextarea = lv_textarea_create(parent);
lv_textarea_set_placeholder_text(logTextarea, "Waiting for data...");
lv_obj_set_flex_grow(logTextarea, 1);
lv_obj_set_width(logTextarea, LV_PCT(100));
lv_obj_add_state(logTextarea, LV_STATE_DISABLED);
lv_obj_set_style_margin_ver(logTextarea, 0, 0);
auto* input_wrapper = lv_obj_create(parent);
lv_obj_set_size(input_wrapper, LV_PCT(100), LV_SIZE_CONTENT);
lv_obj_set_style_pad_all(input_wrapper, 0, 0);
lv_obj_set_style_border_width(input_wrapper, 0, 0);
lv_obj_set_width(input_wrapper, LV_PCT(100));
lv_obj_set_flex_flow(input_wrapper, LV_FLEX_FLOW_ROW);
inputTextarea = lv_textarea_create(input_wrapper);
lv_textarea_set_one_line(inputTextarea, true);
lv_textarea_set_placeholder_text(inputTextarea, "Text to send");
lv_obj_set_width(inputTextarea, LV_PCT(100));
lv_obj_set_flex_grow(inputTextarea, 1);
auto* terminator_dropdown = lv_dropdown_create(input_wrapper);
lv_dropdown_set_options(terminator_dropdown, "\\n\n\\r\\n");
lv_obj_set_width(terminator_dropdown, 70);
lv_obj_add_event_cb(terminator_dropdown, onTerminatorDropdownValueChangedCallback, LV_EVENT_VALUE_CHANGED, this);
auto* button = lv_button_create(input_wrapper);
auto* button_label = lv_label_create(button);
lv_label_set_text(button_label, "Send");
lv_obj_add_event_cb(button, onSendClickedCallback, LV_EVENT_SHORT_CLICKED, this);
viewThreadInterrupted = false;
viewThread = std::make_unique<Thread>(
"SerConsView",
4096,
[this] {
return this->viewThreadMain();
}
);
viewThread->setPriority(THREAD_PRIORITY_RENDER);
viewThread->start();
}
void stopLogic() {
auto lock = mutex.asScopedLock();
lock.lock();
uartThreadInterrupted = true;
// Detach thread, it will auto-delete when leaving the current scope
auto old_uart_thread = std::move(uartThread);
// Unlock so thread can lock
lock.unlock();
if (old_uart_thread->getState() != Thread::State::Stopped) {
// Wait for thread to finish
old_uart_thread->join();
}
}
void stopViews() {
auto lock = mutex.asScopedLock();
lock.lock();
viewThreadInterrupted = true;
// Detach thread, it will auto-delete when leaving the current scope
auto old_view_thread = std::move(viewThread);
// Unlock so thread can lock
lock.unlock();
if (old_view_thread->getState() != Thread::State::Stopped) {
// Wait for thread to finish
old_view_thread->join();
}
}
void stopUart() {
auto lock = mutex.asScopedLock();
lock.lock();
if (uart != nullptr && uart->isStarted()) {
uart->stop();
uart = nullptr;
}
}
void onStart(lv_obj_t* parent, std::unique_ptr<hal::uart::Uart> newUart) {
auto lock = mutex.asScopedLock();
lock.lock();
startLogic(std::move(newUart));
startViews(parent);
}
void onStop() override {
stopViews();
stopLogic();
stopUart();
}
};
} // namespace tt::app::serialconsole

View File

@ -1,10 +0,0 @@
#pragma once
namespace tt::app::serialconsole {
class View {
public:
virtual void onStop() = 0;
};
}

View File

@ -9,8 +9,6 @@ namespace tt::hal::uart {
class UartEsp final : public Uart { class UartEsp final : public Uart {
private:
Mutex mutex; Mutex mutex;
const Configuration& configuration; const Configuration& configuration;
bool started = false; bool started = false;
@ -19,16 +17,16 @@ public:
explicit UartEsp(const Configuration& configuration) : configuration(configuration) {} explicit UartEsp(const Configuration& configuration) : configuration(configuration) {}
bool start() final; bool start() override;
bool isStarted() const final; bool isStarted() const override;
bool stop() final; bool stop() override;
size_t readBytes(std::byte* buffer, size_t bufferSize, TickType_t timeout) final; size_t readBytes(std::byte* buffer, size_t bufferSize, TickType_t timeout) override;
bool readByte(std::byte* output, TickType_t timeout) final; bool readByte(std::byte* output, TickType_t timeout) override;
size_t writeBytes(const std::byte* buffer, size_t bufferSize, TickType_t timeout) final; size_t writeBytes(const std::byte* buffer, size_t bufferSize, TickType_t timeout) override;
size_t available(TickType_t timeout) final; size_t available(TickType_t timeout) override;
bool setBaudRate(uint32_t baudRate, TickType_t timeout) final; bool setBaudRate(uint32_t baudRate, TickType_t timeout) override;
uint32_t getBaudRate() final; uint32_t getBaudRate() override;
void flushInput() final; void flushInput() override;
}; };
std::unique_ptr<Uart> create(const Configuration& configuration); std::unique_ptr<Uart> create(const Configuration& configuration);

View File

@ -76,7 +76,6 @@ namespace app {
namespace notes { extern const AppManifest manifest; } namespace notes { extern const AppManifest manifest; }
namespace power { extern const AppManifest manifest; } namespace power { extern const AppManifest manifest; }
namespace selectiondialog { extern const AppManifest manifest; } namespace selectiondialog { extern const AppManifest manifest; }
namespace serialconsole { extern const AppManifest manifest; }
namespace settings { extern const AppManifest manifest; } namespace settings { extern const AppManifest manifest; }
namespace systeminfo { extern const AppManifest manifest; } namespace systeminfo { extern const AppManifest manifest; }
namespace timedatesettings { extern const AppManifest manifest; } namespace timedatesettings { extern const AppManifest manifest; }
@ -143,7 +142,6 @@ static void registerInternalApps() {
if (!hal::getConfiguration()->uart.empty()) { if (!hal::getConfiguration()->uart.empty()) {
addApp(app::addgps::manifest); addApp(app::addgps::manifest);
addApp(app::gpssettings::manifest); addApp(app::gpssettings::manifest);
addApp(app::serialconsole::manifest);
} }
if (hal::hasDevice(hal::Device::Type::Power)) { if (hal::hasDevice(hal::Device::Type::Power)) {

View File

@ -1,95 +0,0 @@
#include "../../../Private/Tactility/app/serialconsole/ConnectView.h"
#include "Tactility/app/serialconsole/ConsoleView.h"
#include "Tactility/lvgl/Style.h"
#include "Tactility/lvgl/Toolbar.h"
#include "Tactility/service/loader/Loader.h"
#include <Tactility/hal/uart/Uart.h>
#include <lvgl.h>
namespace tt::app::serialconsole {
class SerialConsoleApp final : public App {
private:
lv_obj_t* disconnectButton = nullptr;
lv_obj_t* wrapperWidget = nullptr;
ConnectView connectView = ConnectView([this](auto uart){
showConsoleView(std::move(uart));
});
ConsoleView consoleView;
View* activeView = nullptr;
void stopActiveView() {
if (activeView != nullptr) {
activeView->onStop();
lv_obj_clean(wrapperWidget);
activeView = nullptr;
}
}
void showConsoleView(std::unique_ptr<hal::uart::Uart> uart) {
stopActiveView();
activeView = &consoleView;
consoleView.onStart(wrapperWidget, std::move(uart));
lv_obj_remove_flag(disconnectButton, LV_OBJ_FLAG_HIDDEN);
}
void showConnectView() {
stopActiveView();
activeView = &connectView;
connectView.onStart(wrapperWidget);
lv_obj_add_flag(disconnectButton, LV_OBJ_FLAG_HIDDEN);
}
void onDisconnect() {
// Changing views (calling ConsoleView::stop()) also disconnects the UART
showConnectView();
}
static void onDisconnectPressed(lv_event_t* event) {
auto* app = (SerialConsoleApp*)lv_event_get_user_data(event);
app->onDisconnect();
}
public:
SerialConsoleApp() = default;
void onShow(AppContext& app, lv_obj_t* parent) final {
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_pad_row(parent, 0, LV_STATE_DEFAULT);
auto* toolbar = lvgl::toolbar_create(parent, app);
disconnectButton = lvgl::toolbar_add_image_button_action(toolbar, LV_SYMBOL_POWER, onDisconnectPressed, this);
lv_obj_add_flag(disconnectButton, LV_OBJ_FLAG_HIDDEN);
wrapperWidget = lv_obj_create(parent);
lv_obj_set_width(wrapperWidget, LV_PCT(100));
lv_obj_set_flex_grow(wrapperWidget, 1);
lv_obj_set_flex_flow(wrapperWidget, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_pad_all(wrapperWidget, 0, 0);
lv_obj_set_style_border_width(wrapperWidget, 0, 0);
lvgl::obj_set_style_bg_invisible(wrapperWidget);
showConnectView();
}
void onHide(AppContext& app) final {
stopActiveView();
}
};
extern const AppManifest manifest = {
.appId = "SerialConsole",
.appName = "Serial Console",
.appIcon = LV_SYMBOL_LIST,
.appCategory = Category::System,
.createApp = create<SerialConsoleApp>
};
} // namespace

View File

@ -1,13 +0,0 @@
#pragma once
#include "tt_lock.h"
#ifdef __cplusplus
extern "C" {
#endif
LockHandle tt_lock_alloc_for_file(const char* path);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,152 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <tt_kernel.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file tt_hal_uart.h
* @brief C HAL interface for UART devices used by Tactility C modules.
*
* This header exposes a minimal, C-compatible UART API that mirrors the higher-level
* C++ UART interface (see Tactility/hal/uart).
*
* General notes:
* - Start the UART before I/O using tt_hal_uart_start(); stop it with tt_hal_uart_stop().
*/
typedef void* UartHandle; /**< Opaque handle to an underlying UART instance. */
/**
* @brief Get the number of UART devices available on this platform.
* @return Count of discoverable UARTs (0 if none).
*/
size_t tt_hal_uart_get_count();
/**
* @brief Get the user-friendly name of a UART by index.
* @param index Zero-based UART index in the range [0, tt_hal_uart_get_count()).
* @param[out] name Destination buffer to receive a null-terminated name.
* @param nameSizeLimit Size in bytes of the destination buffer. The name will be
* truncated to fit and always null-terminated if the size
* is greater than 0.
* @return true if a name was written to the buffer; false if the index is out of range
* or on other failure.
*/
bool tt_hal_uart_get_name(size_t index, char* name, size_t nameSizeLimit);
/**
* @brief Allocate an opaque UART handle by index.
*
* Allocation does not start the hardware; call tt_hal_uart_start() to begin I/O.
*
* @param index Zero-based UART index.
* @return A valid UartHandle on success; NULL on failure (e.g., invalid index or already in use).
*/
UartHandle tt_hal_uart_alloc(size_t index);
/**
* @brief Release a previously allocated UART handle and any associated resources.
* @param handle Handle returned by tt_hal_uart_alloc()
*/
void tt_hal_uart_free(UartHandle handle);
/**
* @brief Start the UART so it can perform I/O.
* @param handle A valid UART handle.
* @return true on success; false on failure.
*/
bool tt_hal_uart_start(UartHandle handle);
/**
* @brief Query whether the UART has been started.
* @param handle A valid UART handle.
* @return true if started; false otherwise.
*/
bool tt_hal_uart_is_started(UartHandle handle);
/**
* @brief Stop the UART
* @param handle A valid UART handle.
* @return true on success; false on failure.
*/
bool tt_hal_uart_stop(UartHandle handle);
/**
* @brief Read up to bufferSize bytes into buffer.
*
* This call may block up to timeout ticks waiting for data. It returns the actual
* number of bytes placed into the buffer, which can be less than bufferSize if
* fewer bytes became available before the timeout expired.
*
* @param handle A valid UART handle.
* @param[out] buffer Destination buffer.
* @param bufferSize Capacity of the destination buffer in bytes.
* @param timeout Maximum time to wait in ticks. Use 0 for non-blocking; use TT_MAX_TICKS
* to wait indefinitely.
* @return The number of bytes read (0 on timeout with no data). Never exceeds bufferSize.
*/
size_t tt_hal_uart_read_bytes(UartHandle handle, char* buffer, size_t bufferSize, TickType timeout);
/**
* @brief Read a single byte.
*
* @param handle A valid UART handle.
* @param[out] output Where to store the read byte.
* @param timeout Maximum time to wait in ticks. Use 0 for non-blocking; use TT_MAX_TICKS
* to wait indefinitely.
* @return true if a byte was read and stored in output; false on timeout or failure.
*/
bool tt_hal_uart_read_byte(UartHandle handle, char* output, TickType timeout);
/**
* @brief Write up to bufferSize bytes from buffer.
*
* This call may block up to timeout ticks waiting for transmit queue space. It returns
* the number of bytes accepted for transmission.
*
* @param handle A valid UART handle.
* @param[in] buffer Source buffer containing bytes to write.
* @param bufferSize Number of bytes to write from buffer.
* @param timeout Maximum time to wait in ticks. Use 0 for non-blocking; use TT_MAX_TICKS
* to wait indefinitely.
* @return The number of bytes written (may be less than bufferSize on timeout).
*/
size_t tt_hal_uart_write_bytes(UartHandle handle, const char* buffer, size_t bufferSize, TickType timeout);
/**
* @brief Get the number of bytes currently available to read without blocking.
* @param handle A valid UART handle.
* @return The count of bytes available in the receive buffer.
*/
size_t tt_hal_uart_available(UartHandle handle);
/**
* @brief Set the UART baud rate.
* @param handle A valid UART handle.
* @param baud_rate Desired baud rate in bits per second (e.g., 115200).
* @return true on success; false if the rate is unsupported or on error.
*/
bool tt_hal_uart_set_baud_rate(UartHandle handle, size_t baud_rate);
/**
* @brief Get the current UART baud rate.
* @param handle A valid UART handle.
* @return The configured baud rate in bits per second.
*/
uint32_t tt_hal_uart_get_baud_rate(UartHandle handle);
/**
* @brief Flush the UART input (receive) buffer, discarding any unread data.
* @param handle A valid UART handle.
*/
void tt_hal_uart_flush_input(UartHandle handle);
#ifdef __cplusplus
}
#endif

View File

@ -10,6 +10,26 @@ extern "C" {
/** A handle that represents a lock instance. A lock could be a Mutex or similar construct */ /** A handle that represents a lock instance. A lock could be a Mutex or similar construct */
typedef void* LockHandle; typedef void* LockHandle;
enum TtMutexType {
MutexTypeNormal,
MutexTypeRecursive
};
/**
* Allocate a new mutex instance
* @param[in] type specify if the mutex is either a normal one, or whether it can recursively (re)lock
* @return the allocated lock handle
*/
LockHandle tt_lock_alloc_mutex(enum TtMutexType type);
/**
* Allocate a lock for a file or folder.
* Locking is required before reading files for filesystems that are on a shared bus (e.g. SPI SD card sharing the bus with the display)
* @param path the path to create the lock for
* @return the allocated lock handle
*/
LockHandle tt_lock_alloc_for_path(const char* path);
/** /**
* Attempt to lock the lock. * Attempt to lock the lock.
* @param[in] handle the handle that represents the mutex instance * @param[in] handle the handle that represents the mutex instance
@ -26,6 +46,7 @@ bool tt_lock_acquire(LockHandle handle, TickType timeout);
bool tt_lock_release(LockHandle handle); bool tt_lock_release(LockHandle handle);
/** Free the memory for this lock /** Free the memory for this lock
* This does not auto-release the lock.
* @param[in] handle the handle that represents the mutex instance * @param[in] handle the handle that represents the mutex instance
*/ */
void tt_lock_free(LockHandle handle); void tt_lock_free(LockHandle handle);

View File

@ -6,6 +6,8 @@
extern "C" { extern "C" {
#endif #endif
#define TT_LVGL_DEFAULT_LOCK_TIME 500 // 500 ticks = 500 ms
/** @return true if LVGL is started and active */ /** @return true if LVGL is started and active */
bool tt_lvgl_is_started(); bool tt_lvgl_is_started();
@ -16,7 +18,7 @@ void tt_lvgl_start();
void tt_lvgl_stop(); void tt_lvgl_stop();
/** Lock the LVGL context. Call this before doing LVGL-related operations from a non-LVLG thread */ /** Lock the LVGL context. Call this before doing LVGL-related operations from a non-LVLG thread */
void tt_lvgl_lock(); bool tt_lvgl_lock(TickType timeout);
/** Unlock the LVGL context */ /** Unlock the LVGL context */
void tt_lvgl_unlock(); void tt_lvgl_unlock();

View File

@ -1,48 +0,0 @@
#pragma once
#include "tt_kernel.h"
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
/** A handle that represents a mutex instance */
typedef void* MutexHandle;
enum TtMutexType {
MUTEX_TYPE_NORMAL,
MUTEX_TYPE_RECURSIVE
};
/**
* Allocate a new mutex instance
* @param[in] type specify if the mutex is either a normal one, or whether it can recursively (re)lock
* @return the allocated instance
*/
MutexHandle tt_mutex_alloc(enum TtMutexType type);
/** Free up the memory of the specified mutex instance. */
void tt_mutex_free(MutexHandle handle);
/**
* Attempt to lock a mutex.
* @param[in] handle the handle that represents the mutex instance
* @param[in] timeout the maximum amount of ticks to wait when trying to lock
* @return true when the lock was acquired
*/
bool tt_mutex_lock(MutexHandle handle, TickType timeout);
/**
* Attempt to unlock a mutex.
* @param[in] handle the handle that represents the mutex instance
* @param[in] timeout the maximum amount of ticks to wait when trying to unlock
* @return true when the lock was unlocked
*/
bool tt_mutex_unlock(MutexHandle handle);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,5 @@
#pragma once
#include <private/elf_symbol.h>
extern const esp_elfsym cplusplus_symbols[];

View File

@ -0,0 +1,18 @@
#include <private/elf_symbol.h>
#include <cstddef>
#include <symbols/cplusplus.h>
extern "C" {
extern void* _Znwj(uint32_t size); // operator new(unsigned int)
extern void _ZdlPvj(void* p, uint64_t size); // operator delete(void*, unsigned int)
extern void __cxa_pure_virtual();
}
const esp_elfsym cplusplus_symbols[] = {
ESP_ELFSYM_EXPORT(_Znwj), // operator new(unsigned int)
ESP_ELFSYM_EXPORT(_ZdlPvj), // operator delete(void*, unsigned int)
ESP_ELFSYM_EXPORT(__cxa_pure_virtual), // class-related, see https://arobenko.github.io/bare_metal_cpp/
// delimiter
ESP_ELFSYM_END
};

View File

@ -1,4 +1,8 @@
#include <private/elf_symbol.h>
#include <cstddef>
#include <symbols/esp_event.h> #include <symbols/esp_event.h>
#include <esp_event.h> #include <esp_event.h>
const esp_elfsym esp_event_symbols[] = { const esp_elfsym esp_event_symbols[] = {
@ -19,4 +23,6 @@ const esp_elfsym esp_event_symbols[] = {
ESP_ELFSYM_EXPORT(esp_event_post_to), ESP_ELFSYM_EXPORT(esp_event_post_to),
ESP_ELFSYM_EXPORT(esp_event_isr_post), ESP_ELFSYM_EXPORT(esp_event_isr_post),
ESP_ELFSYM_EXPORT(esp_event_isr_post_to), ESP_ELFSYM_EXPORT(esp_event_isr_post_to),
// delimiter
ESP_ELFSYM_END
}; };

View File

@ -1,4 +1,8 @@
#include <private/elf_symbol.h>
#include <cstddef>
#include <symbols/esp_http_client.h> #include <symbols/esp_http_client.h>
#include <esp_http_client.h> #include <esp_http_client.h>
const esp_elfsym esp_http_client_symbols[] = { const esp_elfsym esp_http_client_symbols[] = {
@ -43,4 +47,6 @@ const esp_elfsym esp_http_client_symbols[] = {
ESP_ELFSYM_EXPORT(esp_http_client_flush_response), ESP_ELFSYM_EXPORT(esp_http_client_flush_response),
ESP_ELFSYM_EXPORT(esp_http_client_get_url), ESP_ELFSYM_EXPORT(esp_http_client_get_url),
ESP_ELFSYM_EXPORT(esp_http_client_get_chunk_length), ESP_ELFSYM_EXPORT(esp_http_client_get_chunk_length),
// delimiter
ESP_ELFSYM_END
}; };

View File

@ -1,6 +1,10 @@
#include <cstdlib> #include <private/elf_symbol.h>
#include <cstddef>
#include <symbols/gcc_soft_float.h> #include <symbols/gcc_soft_float.h>
#include <cstdlib>
// Reference: https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html // Reference: https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html
extern "C" { extern "C" {
@ -139,7 +143,7 @@ int __gtsf2(float a, float b);
int __gtdf2(double a, double b); int __gtdf2(double a, double b);
// int __gttf2(long double a, long double b); // int __gttf2(long double a, long double b);
} } // extern "C"
const esp_elfsym gcc_soft_float_symbols[] = { const esp_elfsym gcc_soft_float_symbols[] = {
ESP_ELFSYM_EXPORT(__addsf3), ESP_ELFSYM_EXPORT(__addsf3),

View File

@ -1,4 +1,8 @@
#include <private/elf_symbol.h>
#include <cstddef>
#include <symbols/pthread.h> #include <symbols/pthread.h>
#include <pthread.h> #include <pthread.h>
const esp_elfsym pthread_symbols[] = { const esp_elfsym pthread_symbols[] = {
@ -8,4 +12,6 @@ const esp_elfsym pthread_symbols[] = {
ESP_ELFSYM_EXPORT(pthread_detach), ESP_ELFSYM_EXPORT(pthread_detach),
ESP_ELFSYM_EXPORT(pthread_join), ESP_ELFSYM_EXPORT(pthread_join),
ESP_ELFSYM_EXPORT(pthread_exit), ESP_ELFSYM_EXPORT(pthread_exit),
// delimiter
ESP_ELFSYM_END
}; };

View File

@ -1,18 +1,17 @@
#include <private/elf_symbol.h>
#include <cstddef>
#include <symbols/stl.h> #include <symbols/stl.h>
#include <bits/functexcept.h> #include <bits/functexcept.h>
extern "C" {
extern void* _Znwj(uint32_t size); // operator new(unsigned int)
extern void _ZdlPvj(void* p, uint64_t size); // operator delete(void*, unsigned int)
}
const esp_elfsym stl_symbols[] = { const esp_elfsym stl_symbols[] = {
ESP_ELFSYM_EXPORT(_Znwj), // operator new(unsigned int)
ESP_ELFSYM_EXPORT(_ZdlPvj), // operator delete(void*, unsigned int)
// Note: You have to use the mangled names here // Note: You have to use the mangled names here
{ "_ZSt20__throw_length_errorPKc", (void*)&(std::__throw_length_error) }, { "_ZSt17__throw_bad_allocv", (void*)&(std::__throw_bad_alloc) },
{ "_ZSt28__throw_bad_array_new_lengthv", (void*)&(std::__throw_bad_array_new_length) }, { "_ZSt28__throw_bad_array_new_lengthv", (void*)&(std::__throw_bad_array_new_length) },
{ "_ZSt17__throw_bad_allocv", (void*)&(std::__throw_bad_alloc) } { "_ZSt25__throw_bad_function_callv", (void*)&(std::__throw_bad_function_call) },
{ "_ZSt20__throw_length_errorPKc", (void*)&(std::__throw_length_error) },
// { "", (void*)&(std::) }, // { "", (void*)&(std::) },
// delimiter
ESP_ELFSYM_END
}; };

View File

@ -1,13 +0,0 @@
#include <tt_file.h>
#include <tt_lock_private.h>
#include <Tactility/file/File.h>
extern "C" {
LockHandle tt_lock_alloc_for_file(const char* path) {
auto lock = tt::file::getLock(path);
auto holder = new LockHolder(lock);
return holder;
}
}

View File

@ -0,0 +1,82 @@
#include "tt_hal_uart.h"
#include <Tactility/hal/uart/Uart.h>
using namespace tt::hal;
struct UartWrapper {
std::shared_ptr<uart::Uart> uart;
};
#define HANDLE_AS_UART(handle) static_cast<UartWrapper*>(handle)->uart
extern "C" {
size_t tt_hal_uart_get_count() {
return uart::getNames().size();
}
bool tt_hal_uart_get_name(size_t index, char* name, size_t nameSizeLimit) {
assert(index < uart::getNames().size());
auto source_name = uart::getNames()[index];
return strncpy(name, source_name.c_str(), nameSizeLimit) != nullptr;
}
UartHandle tt_hal_uart_alloc(size_t index) {
assert(index < uart::getNames().size());
auto* wrapper = new UartWrapper();
auto name = uart::getNames()[index];
wrapper->uart = uart::open(name);
assert(wrapper->uart != nullptr);
return wrapper;
}
void tt_hal_uart_free(UartHandle handle) {
auto* wrapper = static_cast<UartWrapper*>(handle);
assert(wrapper->uart != nullptr);
if (wrapper->uart->isStarted()) {
wrapper->uart->stop();
}
delete wrapper;
}
bool tt_hal_uart_start(UartHandle handle) {
return HANDLE_AS_UART(handle)->start();
}
bool tt_hal_uart_is_started(UartHandle handle) {
return HANDLE_AS_UART(handle)->isStarted();
}
bool tt_hal_uart_stop(UartHandle handle) {
return HANDLE_AS_UART(handle)->stop();
}
size_t tt_hal_uart_read_bytes(UartHandle handle, char* buffer, size_t bufferSize, TickType timeout) {
return HANDLE_AS_UART(handle)->readBytes(reinterpret_cast<std::byte*>(buffer), bufferSize, timeout);
}
bool tt_hal_uart_read_byte(UartHandle handle, char* output, TickType timeout) {
return HANDLE_AS_UART(handle)->readByte(reinterpret_cast<std::byte*>(output), timeout);
}
size_t tt_hal_uart_write_bytes(UartHandle handle, const char* buffer, size_t bufferSize, TickType timeout) {
return HANDLE_AS_UART(handle)->writeBytes(reinterpret_cast<const std::byte*>(buffer), bufferSize, timeout);
}
size_t tt_hal_uart_available(UartHandle handle) {
return HANDLE_AS_UART(handle)->available();
}
bool tt_hal_uart_set_baud_rate(UartHandle handle, size_t baud_rate) {
return HANDLE_AS_UART(handle)->setBaudRate(baud_rate);
}
uint32_t tt_hal_uart_get_baud_rate(UartHandle handle) {
return HANDLE_AS_UART(handle)->getBaudRate();
}
void tt_hal_uart_flush_input(UartHandle handle) {
HANDLE_AS_UART(handle)->flushInput();
}
}

View File

@ -4,7 +4,6 @@
#include "tt_app_alertdialog.h" #include "tt_app_alertdialog.h"
#include "tt_app_selectiondialog.h" #include "tt_app_selectiondialog.h"
#include "tt_bundle.h" #include "tt_bundle.h"
#include "tt_file.h"
#include "tt_gps.h" #include "tt_gps.h"
#include "tt_hal.h" #include "tt_hal.h"
#include "tt_hal_device.h" #include "tt_hal_device.h"
@ -12,13 +11,14 @@
#include "tt_hal_gpio.h" #include "tt_hal_gpio.h"
#include "tt_hal_i2c.h" #include "tt_hal_i2c.h"
#include "tt_hal_touch.h" #include "tt_hal_touch.h"
#include "tt_hal_uart.h"
#include "tt_kernel.h" #include "tt_kernel.h"
#include <tt_lock.h>
#include "tt_lvgl.h" #include "tt_lvgl.h"
#include "tt_lvgl_keyboard.h" #include "tt_lvgl_keyboard.h"
#include "tt_lvgl_spinner.h" #include "tt_lvgl_spinner.h"
#include "tt_lvgl_toolbar.h" #include "tt_lvgl_toolbar.h"
#include "tt_message_queue.h" #include "tt_message_queue.h"
#include "tt_mutex.h"
#include "tt_preferences.h" #include "tt_preferences.h"
#include "tt_semaphore.h" #include "tt_semaphore.h"
#include "tt_thread.h" #include "tt_thread.h"
@ -31,6 +31,7 @@
#include "symbols/gcc_soft_float.h" #include "symbols/gcc_soft_float.h"
#include "symbols/pthread.h" #include "symbols/pthread.h"
#include "symbols/stl.h" #include "symbols/stl.h"
#include "symbols/cplusplus.h"
#include <cstring> #include <cstring>
#include <ctype.h> #include <ctype.h>
@ -57,6 +58,8 @@ const esp_elfsym main_symbols[] {
ESP_ELFSYM_EXPORT(rand), ESP_ELFSYM_EXPORT(rand),
ESP_ELFSYM_EXPORT(srand), ESP_ELFSYM_EXPORT(srand),
ESP_ELFSYM_EXPORT(rand_r), ESP_ELFSYM_EXPORT(rand_r),
ESP_ELFSYM_EXPORT(atoi),
ESP_ELFSYM_EXPORT(atol),
// esp random // esp random
ESP_ELFSYM_EXPORT(esp_random), ESP_ELFSYM_EXPORT(esp_random),
ESP_ELFSYM_EXPORT(esp_fill_random), ESP_ELFSYM_EXPORT(esp_fill_random),
@ -169,7 +172,8 @@ const esp_elfsym main_symbols[] {
ESP_ELFSYM_EXPORT(tt_app_get_user_data_child_path), ESP_ELFSYM_EXPORT(tt_app_get_user_data_child_path),
ESP_ELFSYM_EXPORT(tt_app_get_assets_path), ESP_ELFSYM_EXPORT(tt_app_get_assets_path),
ESP_ELFSYM_EXPORT(tt_app_get_assets_child_path), ESP_ELFSYM_EXPORT(tt_app_get_assets_child_path),
ESP_ELFSYM_EXPORT(tt_lock_alloc_for_file), ESP_ELFSYM_EXPORT(tt_lock_alloc_mutex),
ESP_ELFSYM_EXPORT(tt_lock_alloc_for_path),
ESP_ELFSYM_EXPORT(tt_lock_acquire), ESP_ELFSYM_EXPORT(tt_lock_acquire),
ESP_ELFSYM_EXPORT(tt_lock_release), ESP_ELFSYM_EXPORT(tt_lock_release),
ESP_ELFSYM_EXPORT(tt_lock_free), ESP_ELFSYM_EXPORT(tt_lock_free),
@ -215,6 +219,20 @@ const esp_elfsym main_symbols[] {
ESP_ELFSYM_EXPORT(tt_hal_touch_driver_alloc), ESP_ELFSYM_EXPORT(tt_hal_touch_driver_alloc),
ESP_ELFSYM_EXPORT(tt_hal_touch_driver_free), ESP_ELFSYM_EXPORT(tt_hal_touch_driver_free),
ESP_ELFSYM_EXPORT(tt_hal_touch_driver_get_touched_points), ESP_ELFSYM_EXPORT(tt_hal_touch_driver_get_touched_points),
ESP_ELFSYM_EXPORT(tt_hal_uart_get_count),
ESP_ELFSYM_EXPORT(tt_hal_uart_get_name),
ESP_ELFSYM_EXPORT(tt_hal_uart_alloc),
ESP_ELFSYM_EXPORT(tt_hal_uart_free),
ESP_ELFSYM_EXPORT(tt_hal_uart_start),
ESP_ELFSYM_EXPORT(tt_hal_uart_is_started),
ESP_ELFSYM_EXPORT(tt_hal_uart_stop),
ESP_ELFSYM_EXPORT(tt_hal_uart_read_bytes),
ESP_ELFSYM_EXPORT(tt_hal_uart_read_byte),
ESP_ELFSYM_EXPORT(tt_hal_uart_write_bytes),
ESP_ELFSYM_EXPORT(tt_hal_uart_available),
ESP_ELFSYM_EXPORT(tt_hal_uart_set_baud_rate),
ESP_ELFSYM_EXPORT(tt_hal_uart_get_baud_rate),
ESP_ELFSYM_EXPORT(tt_hal_uart_flush_input),
ESP_ELFSYM_EXPORT(tt_kernel_delay_millis), ESP_ELFSYM_EXPORT(tt_kernel_delay_millis),
ESP_ELFSYM_EXPORT(tt_kernel_delay_micros), ESP_ELFSYM_EXPORT(tt_kernel_delay_micros),
ESP_ELFSYM_EXPORT(tt_kernel_delay_ticks), ESP_ELFSYM_EXPORT(tt_kernel_delay_ticks),
@ -252,10 +270,6 @@ const esp_elfsym main_symbols[] {
ESP_ELFSYM_EXPORT(tt_message_queue_get_message_size), ESP_ELFSYM_EXPORT(tt_message_queue_get_message_size),
ESP_ELFSYM_EXPORT(tt_message_queue_get_count), ESP_ELFSYM_EXPORT(tt_message_queue_get_count),
ESP_ELFSYM_EXPORT(tt_message_queue_reset), ESP_ELFSYM_EXPORT(tt_message_queue_reset),
ESP_ELFSYM_EXPORT(tt_mutex_alloc),
ESP_ELFSYM_EXPORT(tt_mutex_free),
ESP_ELFSYM_EXPORT(tt_mutex_lock),
ESP_ELFSYM_EXPORT(tt_mutex_unlock),
ESP_ELFSYM_EXPORT(tt_preferences_alloc), ESP_ELFSYM_EXPORT(tt_preferences_alloc),
ESP_ELFSYM_EXPORT(tt_preferences_free), ESP_ELFSYM_EXPORT(tt_preferences_free),
ESP_ELFSYM_EXPORT(tt_preferences_opt_bool), ESP_ELFSYM_EXPORT(tt_preferences_opt_bool),
@ -322,9 +336,12 @@ const esp_elfsym main_symbols[] {
// lv_obj // lv_obj
ESP_ELFSYM_EXPORT(lv_color_hex), ESP_ELFSYM_EXPORT(lv_color_hex),
ESP_ELFSYM_EXPORT(lv_color_make), ESP_ELFSYM_EXPORT(lv_color_make),
ESP_ELFSYM_EXPORT(lv_obj_clean),
ESP_ELFSYM_EXPORT(lv_obj_create), ESP_ELFSYM_EXPORT(lv_obj_create),
ESP_ELFSYM_EXPORT(lv_obj_delete), ESP_ELFSYM_EXPORT(lv_obj_delete),
ESP_ELFSYM_EXPORT(lv_obj_add_event_cb), ESP_ELFSYM_EXPORT(lv_obj_add_event_cb),
ESP_ELFSYM_EXPORT(lv_obj_add_flag),
ESP_ELFSYM_EXPORT(lv_obj_add_state),
ESP_ELFSYM_EXPORT(lv_obj_align), ESP_ELFSYM_EXPORT(lv_obj_align),
ESP_ELFSYM_EXPORT(lv_obj_align_to), ESP_ELFSYM_EXPORT(lv_obj_align_to),
ESP_ELFSYM_EXPORT(lv_obj_get_parent), ESP_ELFSYM_EXPORT(lv_obj_get_parent),
@ -337,11 +354,11 @@ const esp_elfsym main_symbols[] {
ESP_ELFSYM_EXPORT(lv_obj_get_content_width), ESP_ELFSYM_EXPORT(lv_obj_get_content_width),
ESP_ELFSYM_EXPORT(lv_obj_get_content_height), ESP_ELFSYM_EXPORT(lv_obj_get_content_height),
ESP_ELFSYM_EXPORT(lv_obj_center), ESP_ELFSYM_EXPORT(lv_obj_center),
ESP_ELFSYM_EXPORT(lv_obj_remove_event_cb),
ESP_ELFSYM_EXPORT(lv_obj_get_user_data), ESP_ELFSYM_EXPORT(lv_obj_get_user_data),
ESP_ELFSYM_EXPORT(lv_obj_set_user_data), ESP_ELFSYM_EXPORT(lv_obj_set_user_data),
ESP_ELFSYM_EXPORT(lv_obj_remove_event_cb),
ESP_ELFSYM_EXPORT(lv_obj_remove_flag), ESP_ELFSYM_EXPORT(lv_obj_remove_flag),
ESP_ELFSYM_EXPORT(lv_obj_add_flag), ESP_ELFSYM_EXPORT(lv_obj_remove_state),
ESP_ELFSYM_EXPORT(lv_obj_set_pos), ESP_ELFSYM_EXPORT(lv_obj_set_pos),
ESP_ELFSYM_EXPORT(lv_obj_set_flex_align), ESP_ELFSYM_EXPORT(lv_obj_set_flex_align),
ESP_ELFSYM_EXPORT(lv_obj_set_flex_flow), ESP_ELFSYM_EXPORT(lv_obj_set_flex_flow),
@ -442,6 +459,9 @@ const esp_elfsym main_symbols[] {
ESP_ELFSYM_EXPORT(lv_dropdown_get_option_count), ESP_ELFSYM_EXPORT(lv_dropdown_get_option_count),
ESP_ELFSYM_EXPORT(lv_dropdown_get_option_index), ESP_ELFSYM_EXPORT(lv_dropdown_get_option_index),
ESP_ELFSYM_EXPORT(lv_dropdown_get_options), ESP_ELFSYM_EXPORT(lv_dropdown_get_options),
ESP_ELFSYM_EXPORT(lv_dropdown_get_selected),
ESP_ELFSYM_EXPORT(lv_dropdown_get_selected_str),
ESP_ELFSYM_EXPORT(lv_dropdown_get_selected_highlight),
ESP_ELFSYM_EXPORT(lv_dropdown_set_dir), ESP_ELFSYM_EXPORT(lv_dropdown_set_dir),
ESP_ELFSYM_EXPORT(lv_dropdown_set_options), ESP_ELFSYM_EXPORT(lv_dropdown_set_options),
ESP_ELFSYM_EXPORT(lv_dropdown_set_options_static), ESP_ELFSYM_EXPORT(lv_dropdown_set_options_static),
@ -462,6 +482,8 @@ const esp_elfsym main_symbols[] {
ESP_ELFSYM_EXPORT(lv_textarea_get_label), ESP_ELFSYM_EXPORT(lv_textarea_get_label),
ESP_ELFSYM_EXPORT(lv_textarea_get_max_length), ESP_ELFSYM_EXPORT(lv_textarea_get_max_length),
ESP_ELFSYM_EXPORT(lv_textarea_get_one_line), ESP_ELFSYM_EXPORT(lv_textarea_get_one_line),
ESP_ELFSYM_EXPORT(lv_textarea_get_text),
ESP_ELFSYM_EXPORT(lv_textarea_get_text_selection),
ESP_ELFSYM_EXPORT(lv_textarea_set_one_line), ESP_ELFSYM_EXPORT(lv_textarea_set_one_line),
ESP_ELFSYM_EXPORT(lv_textarea_set_accepted_chars), ESP_ELFSYM_EXPORT(lv_textarea_set_accepted_chars),
ESP_ELFSYM_EXPORT(lv_textarea_set_align), ESP_ELFSYM_EXPORT(lv_textarea_set_align),
@ -526,9 +548,10 @@ uintptr_t tt_symbol_resolver(const char* symbolName) {
main_symbols, main_symbols,
gcc_soft_float_symbols, gcc_soft_float_symbols,
stl_symbols, stl_symbols,
cplusplus_symbols,
esp_event_symbols, esp_event_symbols,
esp_http_client_symbols, esp_http_client_symbols,
pthread_symbols pthread_symbols,
}; };
for (const auto* symbols : all_symbols) { for (const auto* symbols : all_symbols) {
@ -545,7 +568,7 @@ void tt_init_tactility_c() {
elf_set_symbol_resolver(tt_symbol_resolver); elf_set_symbol_resolver(tt_symbol_resolver);
} }
} } // extern "C"
#else // Simulator #else // Simulator

View File

@ -1,20 +1,42 @@
#include <tt_lock.h> #include <tt_lock.h>
#include <tt_lock_private.h> #include <tt_lock_private.h>
#include <Tactility/Mutex.h>
#include <Tactility/file/File.h>
#define HANDLE_AS_LOCK(handle) (static_cast<LockHolder*>(handle)->lock)
extern "C" { extern "C" {
LockHandle tt_lock_alloc_mutex(TtMutexType type) {
auto* lock_holder = new LockHolder();
switch (type) {
case MutexTypeNormal:
lock_holder->lock = std::make_shared<tt::Mutex>(tt::Mutex::Type::Normal);
break;
case MutexTypeRecursive:
lock_holder->lock = std::make_shared<tt::Mutex>(tt::Mutex::Type::Recursive);
break;
default:
tt_crash("Type not supported");
}
return lock_holder;
}
LockHandle tt_lock_alloc_for_path(const char* path) {
const auto lock = tt::file::getLock(path);
return new LockHolder(lock);
}
bool tt_lock_acquire(LockHandle handle, TickType timeout) { bool tt_lock_acquire(LockHandle handle, TickType timeout) {
auto holder = static_cast<LockHolder*>(handle); return HANDLE_AS_LOCK(handle)->lock(timeout);
return holder->lock->lock(timeout);
} }
bool tt_lock_release(LockHandle handle) { bool tt_lock_release(LockHandle handle) {
auto holder = static_cast<LockHolder*>(handle); return HANDLE_AS_LOCK(handle)->unlock();
return holder->lock->unlock();
} }
void tt_lock_free(LockHandle handle) { void tt_lock_free(LockHandle handle) {
auto holder = static_cast<LockHolder*>(handle); const auto holder = static_cast<LockHolder*>(handle);
delete holder; delete holder;
} }

View File

@ -1,3 +1,4 @@
#include <tt_kernel.h>
#include <Tactility/lvgl/Lvgl.h> #include <Tactility/lvgl/Lvgl.h>
#include <Tactility/lvgl/LvglSync.h> #include <Tactility/lvgl/LvglSync.h>
@ -15,8 +16,8 @@ void tt_lvgl_stop() {
tt::lvgl::stop(); tt::lvgl::stop();
} }
void tt_lvgl_lock() { void tt_lvgl_lock(TickType timeout) {
tt::lvgl::getSyncLock()->lock(); tt::lvgl::getSyncLock()->lock(timeout);
} }
void tt_lvgl_unlock() { void tt_lvgl_unlock() {

View File

@ -1,31 +0,0 @@
#include "tt_mutex.h"
#include <Tactility/Mutex.h>
extern "C" {
#define HANDLE_AS_MUTEX(handle) ((tt::Mutex*)(handle))
MutexHandle tt_mutex_alloc(TtMutexType type) {
switch (type) {
case MUTEX_TYPE_NORMAL:
return new tt::Mutex(tt::Mutex::Type::Normal);
case MUTEX_TYPE_RECURSIVE:
return new tt::Mutex(tt::Mutex::Type::Recursive);
default:
tt_crash("Type not supported");
}
}
void tt_mutex_free(MutexHandle handle) {
delete HANDLE_AS_MUTEX(handle);
}
bool tt_mutex_lock(MutexHandle handle, TickType timeout) {
return HANDLE_AS_MUTEX(handle)->lock(timeout);
}
bool tt_mutex_unlock(MutexHandle handle) {
return HANDLE_AS_MUTEX(handle)->unlock();
}
}