Various fixes and improvements (#269)

- Bump version for next release
- Fix default gamma for CYD 2432S032C
- Remember gamma curve setting from Display settings app
- Add UART to Core2 (still has no voltage on Grove port, though)
- LVGL performance improvements: pin to second core and set task priority to "critical"
- Fix build warnings, including deprecations
- Removed deprecated `Thread` constructor
- Fix WaveShare S3 display: Some displays would show a white screen at 12MHz, so I'm putting it back to the
official config values.
This commit is contained in:
Ken Van Hoeylandt 2025-04-01 23:42:56 +02:00 committed by GitHub
parent eb4e9f9649
commit 08029a84dd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 203 additions and 145 deletions

View File

@ -3,12 +3,26 @@
#include "hal/CydDisplay.h"
#include "hal/CydSdCard.h"
#include <Tactility/kernel/SystemEvents.h>
#include <PwmBacklight.h>
#define CYD_SPI_TRANSFER_SIZE_LIMIT (TWODOTFOUR_LCD_DRAW_BUFFER_SIZE * LV_COLOR_DEPTH / 8)
bool initBoot() {
return driver::pwmbacklight::init(GPIO_NUM_27);
if (!driver::pwmbacklight::init(GPIO_NUM_27)) {
return false;
}
// This display has a weird glitch with gamma during boot, which results in uneven dark gray colours.
// Setting gamma curve index to 0 doesn't work at boot for an unknown reason, so we set the curve index to 1:
tt::kernel::subscribeSystemEvent(tt::kernel::SystemEvent::BootInitLvglEnd, [](auto event) {
auto display = tt::hal::findFirstDevice<tt::hal::display::DisplayDevice>(tt::hal::Device::Type::Display);
assert(display != nullptr);
tt::lvgl::lock(portMAX_DELAY);
display->setGammaCurve(1U);
tt::lvgl::unlock();
});
return true;
}
const tt::hal::Configuration cyd_2432S032c_config = {

View File

@ -9,6 +9,8 @@
#define CORE2_SPI_TRANSFER_SIZE_LIMIT (CORE2_LCD_DRAW_BUFFER_SIZE * LV_COLOR_DEPTH / 8)
using namespace tt::hal;
extern const tt::hal::Configuration m5stack_core2 = {
.initBoot = initBoot,
.createDisplay = createDisplay,
@ -74,5 +76,30 @@ extern const tt::hal::Configuration m5stack_core2 = {
.isMutable = false,
.lock = tt::lvgl::getSyncLock() // esp_lvgl_port owns the lock for the display
}
},
.uart {
uart::Configuration {
.name = "Grove",
.port = UART_NUM_1,
.rxPin = GPIO_NUM_32,
.txPin = GPIO_NUM_33,
.rtsPin = GPIO_NUM_NC,
.ctsPin = GPIO_NUM_NC,
.rxBufferSize = 1024,
.txBufferSize = 1024,
.config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.rx_flow_ctrl_thresh = 0,
.source_clk = UART_SCLK_DEFAULT,
.flags = {
.allow_pd = 0,
.backup_before_sleep = 0,
}
}
},
}
};

View File

@ -137,7 +137,7 @@ static void updatePowerSwitch() {
}
}
static int32_t powerSwitchMain(void*) { // check power switch every 10th of sec
static int32_t powerSwitchMain() { // check power switch every 10th of sec
while (true) {
updatePowerSwitch();
tt::kernel::delayMillis(200);
@ -148,8 +148,7 @@ static void startPowerSwitchThread() {
powerThread = std::make_unique<tt::Thread>(
"unphone_power_switch",
4096,
powerSwitchMain,
nullptr
[]() { return powerSwitchMain(); }
);
powerThread->start();
}

View File

@ -23,15 +23,15 @@ std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
esp_lcd_rgb_panel_config_t rgb_panel_config = {
.clk_src = LCD_CLK_SRC_DEFAULT,
.timings = {
.pclk_hz = 12'000'000, // NOTE: original was 14MHz, but we had to slow it down with PSRAM frame buffer,
.pclk_hz = 16'000'000,
.h_res = 800,
.v_res = 480,
.hsync_pulse_width = 10,
.hsync_back_porch = 10,
.hsync_front_porch = 20,
.vsync_pulse_width = 10,
.vsync_back_porch = 10,
.vsync_front_porch = 10,
.hsync_pulse_width = 4,
.hsync_back_porch = 8,
.hsync_front_porch = 8,
.vsync_pulse_width = 4,
.vsync_back_porch = 8,
.vsync_front_porch = 8,
.flags = {
.hsync_idle_low = false,
.vsync_idle_low = false,

View File

@ -1,4 +1,8 @@
# TODOs
- Add a Keyboard setting app to override the behaviour of soft keyboard hiding (e.g. keyboard hardware is present, but user wants soft keyboard)
- HAL for display touch calibration
- Display app: hide controls for unsupported features, instead of disabling them
- Split up boot stages, so the last stage can be done from the splash screen
- Start using non_null (either via MS GSL, or custom)
- `hal/Configuration.h` defines C function types: Use C++ std::function instead
@ -38,6 +42,7 @@
- Remove flex_flow from app_container in Gui.cpp
# Nice-to-haves
- Give external app a different icon. Allow an external app update their id, icon, type and name once they are running(and persist that info?). Loader will need to be able to find app by (external) location.
- Audio player app
- Audio recording app
@ -52,8 +57,9 @@
- Files app: copy/paste actions
- On crash, try to save current log to flash or SD card? (this is risky, though, so ask in Discord first)
- Support more than 1 hardware keyboard (see lvgl::hardware_keyboard_set_indev()). LVGL init currently calls keyboard init, but that part should probably be done from the KeyboardDevice base class.
# App Ideas
- Map widget:
https://github.com/portapack-mayhem/mayhem-firmware/blob/b66d8b1aa178d8a9cd06436fea788d5d58cb4c8d/firmware/application/ui/ui_geomap.cpp
https://github.com/portapack-mayhem/mayhem-firmware/blob/b66d8b1aa178d8a9cd06436fea788d5d58cb4c8d/firmware/tools/generate_world_map.bin.py

View File

@ -12,15 +12,12 @@ static void touchReadCallback(lv_indev_t* indev, lv_indev_data_t* data) {
touch->readLast(data);
}
static int32_t threadCallback(void* context) {
auto* touch = (Ft6x36Touch*)context;
touch->driverThreadMain();
return 0;
}
Ft6x36Touch::Ft6x36Touch(std::unique_ptr<Configuration> inConfiguration) :
configuration(std::move(inConfiguration)),
driverThread(tt::Thread("ft6x36", 4096, threadCallback, this))
driverThread(tt::Thread("ft6x36", 4096, [this]() {
driverThreadMain();
return 0;
}))
{}
Ft6x36Touch::~Ft6x36Touch() {

View File

@ -5,8 +5,15 @@
namespace tt::app::display {
void setBacklightDuty(uint8_t value);
uint8_t getBacklightDuty();
bool getBacklightDuty(uint8_t& duty);
void setGammaCurve(uint8_t curveIndex);
bool getGammaCurve(uint8_t& curveIndex);
void setRotation(lv_display_rotation_t rotation);
lv_display_rotation_t getRotation();
} // namespace

View File

@ -32,9 +32,9 @@ class BootApp : public App {
private:
Thread thread = Thread("boot", 4096, bootThreadCallback, this);
Thread thread = Thread("boot", 4096, [this]() { return bootThreadCallback(); });
static int32_t bootThreadCallback(TT_UNUSED void* context) {
int32_t bootThreadCallback() {
TickType_t start_time = kernel::getTicks();
kernel::publishSystemEvent(kernel::SystemEvent::BootSplash);
@ -42,14 +42,22 @@ private:
auto hal_display = getHalDisplay();
assert(hal_display != nullptr);
if (hal_display->supportsBacklightDuty()) {
int32_t backlight_duty = app::display::getBacklightDuty();
TT_LOG_I(TAG, "backlight %ld", backlight_duty);
uint8_t backlight_duty = 200;
app::display::getBacklightDuty(backlight_duty);
TT_LOG_I(TAG, "backlight %du", backlight_duty);
hal_display->setBacklightDuty(backlight_duty);
} else {
TT_LOG_I(TAG, "no backlight");
}
if (hal_display->getGammaCurveCount() > 0) {
uint8_t gamma_curve;
if (app::display::getGammaCurve(gamma_curve)) {
hal_display->setGammaCurve(gamma_curve);
TT_LOG_I(TAG, "gamma %du", gamma_curve);
}
}
if (hal::usb::isUsbBootMode()) {
TT_LOG_I(TAG, "Rebooting into mass storage device mode");
hal::usb::resetUsbBootMode();

View File

@ -55,6 +55,7 @@ static void onGammaSliderEvent(lv_event_t* event) {
gamma = (uint8_t)slider_value;
hal_display->setGammaCurve(gamma);
tt::app::display::setGammaCurve(gamma);
}
}
@ -136,11 +137,25 @@ class DisplayApp : public App {
lv_slider_set_value(brightness_slider, 255, LV_ANIM_OFF);
lv_obj_add_state(brightness_slider, LV_STATE_DISABLED);
} else {
uint8_t value = getBacklightDuty();
lv_slider_set_value(brightness_slider, value, LV_ANIM_OFF);
uint8_t value;
if (getBacklightDuty(value)) {
lv_slider_set_value(brightness_slider, value, LV_ANIM_OFF);
} else {
lv_slider_set_value(brightness_slider, 0, LV_ANIM_OFF);
}
}
lv_slider_set_value(gamma_slider, 128, LV_ANIM_OFF);
if (hal_display->getGammaCurveCount() == 0) {
lv_slider_set_value(gamma_slider, 0, LV_ANIM_OFF);
lv_obj_add_state(gamma_slider, LV_STATE_DISABLED);
} else {
uint8_t curve_index;
if (getGammaCurve(curve_index)) {
lv_slider_set_value(gamma_slider, curve_index, LV_ANIM_OFF);
} else {
lv_slider_set_value(gamma_slider, 0, LV_ANIM_OFF);
}
}
auto* orientation_label = lv_label_create(wrapper);
lv_label_set_text(orientation_label, "Orientation");

View File

@ -6,19 +6,21 @@ namespace tt::app::display {
tt::Preferences preferences("display");
#define BACKLIGHT_DUTY_KEY "backlight_duty"
#define ROTATION_KEY "rotation"
constexpr const char* BACKLIGHT_DUTY_KEY = "backlight_duty";
constexpr const char* GAMMA_CURVE_KEY = "gamma";
constexpr const char* ROTATION_KEY = "rotation";
void setBacklightDuty(uint8_t value) {
preferences.putInt32(BACKLIGHT_DUTY_KEY, (int32_t)value);
}
uint8_t getBacklightDuty() {
bool getBacklightDuty(uint8_t& duty) {
int32_t result;
if (preferences.optInt32(BACKLIGHT_DUTY_KEY, result)) {
return (uint8_t)(result % 256);
duty = (uint8_t)(result % 256);
return true;
} else {
return 200;
return false;
}
}
@ -35,4 +37,18 @@ lv_display_rotation_t getRotation() {
}
}
void setGammaCurve(uint8_t curveIndex) {
preferences.putInt32(GAMMA_CURVE_KEY, (int32_t)curveIndex);
}
bool getGammaCurve(uint8_t& curveIndex) {
int32_t result;
if (preferences.optInt32(GAMMA_CURVE_KEY, result)) {
curveIndex = (uint8_t)(result % 256);
return true;
} else {
return false;
}
}
} // namespace

View File

@ -228,8 +228,8 @@ void View::showActionsForFile() {
}
void View::update() {
auto scoped_lockable = lvgl::getSyncLock()->scoped();
if (scoped_lockable->lock(100 / portTICK_PERIOD_MS)) {
auto scoped_lockable = lvgl::getSyncLock()->asScopedLock();
if (scoped_lockable.lock(lvgl::defaultLockTime)) {
lv_obj_clean(dir_entry_list);
state->withEntries([this](const std::vector<dirent>& entries) {
@ -277,15 +277,15 @@ void View::init(lv_obj_t* parent) {
}
void View::onDirEntryListScrollBegin() {
auto scoped_lockable = lvgl::getSyncLock()->scoped();
if (scoped_lockable->lock(100 / portTICK_PERIOD_MS)) {
auto scoped_lockable = lvgl::getSyncLock()->asScopedLock();
if (scoped_lockable.lock(lvgl::defaultLockTime)) {
lv_obj_add_flag(action_list, LV_OBJ_FLAG_HIDDEN);
}
}
void View::onNavigate() {
auto scoped_lockable = lvgl::getSyncLock()->scoped();
if (scoped_lockable->lock(100 / portTICK_PERIOD_MS)) {
auto scoped_lockable = lvgl::getSyncLock()->asScopedLock();
if (scoped_lockable.lock(lvgl::defaultLockTime)) {
lv_obj_add_flag(action_list, LV_OBJ_FLAG_HIDDEN);
}
}

View File

@ -57,8 +57,8 @@ void GpioApp::updatePinWidgets() {
lv_obj_t* label = lvPins[j];
void* label_user_data = lv_obj_get_user_data(label);
// The user data stores the state, so we can avoid unnecessary updates
if ((void*)level != label_user_data) {
lv_obj_set_user_data(label, (void*)level);
if (reinterpret_cast<void*>(level) != label_user_data) {
lv_obj_set_user_data(label, reinterpret_cast<void*>(level));
if (level == 0) {
lv_obj_set_style_text_color(label, lv_color_black(), 0);
} else {

View File

@ -20,7 +20,8 @@ class ImageViewerApp : public App {
auto wrapper = lv_obj_create(parent);
lv_obj_set_size(wrapper, LV_PCT(100), LV_PCT(100));
lv_obj_set_style_border_width(wrapper, 0, 0);
lvgl::obj_set_style_no_padding(wrapper);
lv_obj_set_style_pad_all(wrapper, 0, 0);
lv_obj_set_style_pad_gap(wrapper, 0, 0);
auto toolbar = lvgl::toolbar_create(wrapper, app);
lv_obj_align(toolbar, LV_ALIGN_TOP_MID, 0, 0);
@ -32,7 +33,8 @@ class ImageViewerApp : public App {
lv_obj_set_height(image_wrapper, parent_height - TOOLBAR_HEIGHT);
lv_obj_set_flex_flow(image_wrapper, LV_FLEX_FLOW_COLUMN);
lv_obj_set_flex_align(image_wrapper, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lvgl::obj_set_style_no_padding(image_wrapper);
lv_obj_set_style_pad_all(image_wrapper, 0, 0);
lv_obj_set_style_pad_gap(image_wrapper, 0, 0);
lvgl::obj_set_style_bg_invisible(image_wrapper);
auto* image = lv_image_create(image_wrapper);

View File

@ -81,7 +81,8 @@ public:
lv_obj_set_width(wrapper, LV_PCT(100));
lv_obj_set_flex_grow(wrapper, 1);
lv_obj_set_flex_flow(wrapper, LV_FLEX_FLOW_COLUMN);
lvgl::obj_set_style_no_padding(wrapper);
lv_obj_set_style_pad_all(wrapper, 0, 0);
lv_obj_set_style_pad_gap(wrapper, 0, 0);
lvgl::obj_set_style_bg_invisible(wrapper);
labelWidget = lv_label_create(wrapper);

View File

@ -161,7 +161,8 @@ public:
lv_obj_t* switch_container = lv_obj_create(wrapper);
lv_obj_set_width(switch_container, LV_PCT(100));
lv_obj_set_height(switch_container, LV_SIZE_CONTENT);
lvgl::obj_set_style_no_padding(switch_container);
lv_obj_set_style_pad_all(switch_container, 0, 0);
lv_obj_set_style_pad_gap(switch_container, 0, 0);
lvgl::obj_set_style_bg_invisible(switch_container);
enableLabel = lv_label_create(switch_container);

View File

@ -78,7 +78,8 @@ class WifiApSettings : public App {
auto* auto_connect_wrapper = lv_obj_create(wrapper);
lv_obj_set_size(auto_connect_wrapper, LV_PCT(100), LV_SIZE_CONTENT);
lvgl::obj_set_style_no_padding(auto_connect_wrapper);
lv_obj_set_style_pad_all(auto_connect_wrapper, 0, 0);
lv_obj_set_style_pad_gap(auto_connect_wrapper, 0, 0);
lv_obj_set_style_border_width(auto_connect_wrapper, 0, 0);
auto* auto_connect_label = lv_label_create(auto_connect_wrapper);

View File

@ -16,8 +16,6 @@ namespace tt::app::wificonnect {
#define TAG "wifi_connect"
std::shared_ptr<WifiConnect> _Nullable optWifiConnect();
void View::resetErrors() {
lv_obj_add_flag(password_error, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(ssid_error, LV_OBJ_FLAG_HIDDEN);
@ -87,7 +85,8 @@ void View::createBottomButtons(lv_obj_t* parent) {
auto* button_container = lv_obj_create(parent);
lv_obj_set_width(button_container, LV_PCT(100));
lv_obj_set_height(button_container, LV_SIZE_CONTENT);
lvgl::obj_set_style_no_padding(button_container);
lv_obj_set_style_pad_all(button_container, 0, 0);
lv_obj_set_style_pad_gap(button_container, 0, 0);
lv_obj_set_style_border_width(button_container, 0, 0);
remember_switch = lv_switch_create(button_container);
@ -126,7 +125,8 @@ void View::init(AppContext& app, lv_obj_t* parent) {
auto* ssid_wrapper = lv_obj_create(wrapper);
lv_obj_set_width(ssid_wrapper, LV_PCT(100));
lv_obj_set_height(ssid_wrapper, LV_SIZE_CONTENT);
lvgl::obj_set_style_no_padding(ssid_wrapper);
lv_obj_set_style_pad_all(ssid_wrapper, 0, 0);
lv_obj_set_style_pad_gap(ssid_wrapper, 0, 0);
lv_obj_set_style_border_width(ssid_wrapper, 0, 0);
auto* ssid_label_wrapper = lv_obj_create(ssid_wrapper);
@ -154,7 +154,8 @@ void View::init(AppContext& app, lv_obj_t* parent) {
auto* password_wrapper = lv_obj_create(wrapper);
lv_obj_set_width(password_wrapper, LV_PCT(100));
lv_obj_set_height(password_wrapper, LV_SIZE_CONTENT);
lvgl::obj_set_style_no_padding(password_wrapper);
lv_obj_set_style_pad_all(password_wrapper, 0, 0);
lv_obj_set_style_pad_gap(password_wrapper, 0, 0);
lv_obj_set_style_border_width(password_wrapper, 0, 0);
auto* password_label_wrapper = lv_obj_create(password_wrapper);

View File

@ -93,7 +93,8 @@ void View::createSsidListItem(const service::wifi::ApRecord& record, bool isConn
lv_obj_add_event_cb(wrapper, &connect, LV_EVENT_SHORT_CLICKED, bindings);
lv_obj_set_user_data(wrapper, bindings);
lv_obj_set_size(wrapper, LV_PCT(100), LV_SIZE_CONTENT);
lvgl::obj_set_style_no_padding(wrapper);
lv_obj_set_style_pad_all(wrapper, 0, 0);
lv_obj_set_style_pad_gap(wrapper, 0, 0);
lv_obj_set_style_margin_all(wrapper, 0, 0);
lv_obj_set_style_border_width(wrapper, 0, 0);
@ -285,7 +286,8 @@ void View::init(const AppContext& app, lv_obj_t* parent) {
lv_obj_set_flex_grow(secondary_flex, 1);
lv_obj_set_flex_flow(secondary_flex, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_border_width(secondary_flex, 0, 0);
lvgl::obj_set_style_no_padding(secondary_flex);
lv_obj_set_style_pad_all(secondary_flex, 0, 0);
lv_obj_set_style_pad_gap(secondary_flex, 0, 0);
lvgl::obj_set_style_bg_invisible(secondary_flex);
// align() methods don't work on flex, so we need this extra wrapper

View File

@ -16,9 +16,9 @@ bool initEspLvglPort() {
TT_LOG_D(TAG, "Port init");
static lv_disp_t* display = nullptr;
const lvgl_port_cfg_t lvgl_cfg = {
.task_priority = static_cast<UBaseType_t>(tt::THREAD_PRIORITY_RENDER),
.task_priority = static_cast<UBaseType_t>(Thread::Priority::Critical),
.task_stack = TDECK_LVGL_TASK_STACK_DEPTH,
.task_affinity = -1, // core pinning
.task_affinity = 1, // -1 = disabled, 0 = core 1, 1 = core 2
.task_max_sleep_ms = 500,
.timer_period_ms = 5
};

View File

@ -22,7 +22,7 @@ void syncSet(LvglLock lock, LvglUnlock unlock) {
auto old_unlock = unlock_singleton;
// Ensure the old lock is not engaged when changing locks
old_lock(portMAX_DELAY);
old_lock((uint32_t)portMAX_DELAY);
lock_singleton = lock;
unlock_singleton = unlock;
old_unlock();

View File

@ -112,7 +112,8 @@ lv_obj_t* toolbar_add_button_action(lv_obj_t* obj, const char* icon, lv_event_cb
lv_obj_t* action_button = lv_button_create(toolbar->action_container);
lv_obj_set_size(action_button, TOOLBAR_HEIGHT - 4, TOOLBAR_HEIGHT - 4);
obj_set_style_no_padding(action_button);
lv_obj_set_style_pad_all(action_button, 0, 0);
lv_obj_set_style_pad_gap(action_button, 0, 0);
lv_obj_add_event_cb(action_button, callback, LV_EVENT_SHORT_CLICKED, user_data);
lv_obj_t* action_button_image = lv_image_create(action_button);
lv_image_set_src(action_button_image, icon);

View File

@ -13,7 +13,7 @@ namespace tt::service::gui {
// Forward declarations
void redraw(Gui*);
static int32_t guiMain(TT_UNUSED void* p);
static int32_t guiMain();
Gui* gui = nullptr;
@ -33,8 +33,7 @@ Gui* gui_alloc() {
instance->thread = new Thread(
"gui",
4096, // Last known minimum was 2800 for launching desktop
&guiMain,
nullptr
[]() { return guiMain(); }
);
instance->loader_pubsub_subscription = loader::getPubsub()->subscribe(&onLoaderMessage, instance);
tt_check(lvgl::lock(1000 / portTICK_PERIOD_MS));
@ -118,7 +117,7 @@ void hideApp() {
unlock();
}
static int32_t guiMain(TT_UNUSED void* p) {
static int32_t guiMain() {
tt_check(gui);
Gui* local_gui = gui;

View File

@ -59,13 +59,6 @@ static void makeScreenshot(const std::string& filename) {
}
}
static int32_t screenshotTaskCallback(void* context) {
auto* data = static_cast<ScreenshotTask*>(context);
assert(data != nullptr);
data->taskMain();
return 0;
}
void ScreenshotTask::taskMain() {
uint8_t screenshots_taken = 0;
std::string last_app_id;
@ -116,8 +109,10 @@ void ScreenshotTask::taskStart() {
thread = new Thread(
"screenshot",
8192,
&screenshotTaskCallback,
this
[this]() {
this->taskMain();
return 0;
}
);
thread->start();
}

View File

@ -18,8 +18,9 @@ ThreadHandle tt_thread_alloc_ext(
return new tt::Thread(
name,
stackSize,
callback,
callbackContext
[callback, callbackContext]() {
return callback(callbackContext);
}
);
}
@ -36,7 +37,9 @@ void tt_thread_set_stack_size(ThreadHandle handle, size_t size) {
}
void tt_thread_set_callback(ThreadHandle handle, ThreadCallback callback, void* _Nullable callbackContext) {
HANDLE_AS_THREAD(handle)->setCallback(callback, callbackContext);
HANDLE_AS_THREAD(handle)->setMainFunction([callback, callbackContext]() {
return callback(callbackContext);
});
}
void tt_thread_set_priority(ThreadHandle handle, ThreadPriority priority) {

View File

@ -73,22 +73,6 @@ public:
Thread() = default;
/** Allocate Thread, shortcut version
* @param[in] name the name of the thread
* @param[in] stackSize in bytes
* @param[in] callback
* @param[in] callbackContext
* @param[in] affinity Which CPU core to pin this task to, -1 means unpinned (only works on ESP32)
*/
[[deprecated("Use constructor variant with std::function")]]
Thread(
std::string name,
configSTACK_DEPTH_TYPE stackSize,
Callback callback,
_Nullable void* callbackContext,
portBASE_TYPE affinity = -1
);
/** Allocate Thread, shortcut version
* @param[in] name the name of the thread
* @param[in] stackSize in bytes
@ -200,7 +184,6 @@ public:
static uint32_t awaitFlags(uint32_t flags, uint32_t options, uint32_t timeout);
};
#define THREAD_PRIORITY_APP Thread::PriorityNormal
#define THREAD_PRIORITY_SERVICE Thread::Priority::High
#define THREAD_PRIORITY_RENDER Thread::Priority::Higher
#define THREAD_PRIORITY_ISR Thread::Priority::Critical

View File

@ -24,6 +24,8 @@ static char toPrefix(LogLevel level) {
return 'D';
case Verbose:
return 'V';
default:
return ' ';
}
}

View File

@ -66,21 +66,6 @@ void Thread::mainBody(void* context) {
threadCatch();
}
Thread::Thread(
std::string name,
configSTACK_DEPTH_TYPE stackSize,
Callback callback,
_Nullable void* callbackContext,
portBASE_TYPE affinity
) :
mainFunction([callback, callbackContext]() {
return callback(callbackContext);
}),
name(std::move(name)),
stackSize(stackSize),
affinity(affinity)
{}
Thread::Thread(
std::string name,
configSTACK_DEPTH_TYPE stackSize,

View File

@ -4,12 +4,6 @@
using namespace tt;
static int32_t thread_with_mutex_parameter(void* parameter) {
auto* mutex = (Mutex*)parameter;
mutex->lock(portMAX_DELAY);
return 0;
}
TEST_CASE("a mutex can block a thread") {
auto mutex = Mutex(Mutex::Type::Normal);
mutex.lock(portMAX_DELAY);
@ -17,8 +11,10 @@ TEST_CASE("a mutex can block a thread") {
Thread thread = Thread(
"thread",
1024,
&thread_with_mutex_parameter,
&mutex
[&mutex]() {
mutex.lock(portMAX_DELAY);
return 0;
}
);
thread.start();

View File

@ -4,33 +4,17 @@
using namespace tt;
static int interruptable_thread(void* parameter) {
bool* interrupted = (bool*)parameter;
while (!*interrupted) {
kernel::delayMillis(5);
}
return 0;
}
static int immediate_return_thread(void* parameter) {
bool* has_called = (bool*)parameter;
*has_called = true;
return 0;
}
static int thread_with_return_code(void* parameter) {
int* code = (int*)parameter;
return *code;
}
TEST_CASE("when a thread is started then its callback should be called") {
bool has_called = false;
auto* thread = new Thread(
"immediate return task",
4096,
&immediate_return_thread,
&has_called
[&has_called]() {
has_called = true;
return 0;
}
);
CHECK(!has_called);
thread->start();
thread->join();
@ -43,9 +27,14 @@ TEST_CASE("a thread can be started and stopped") {
auto* thread = new Thread(
"interruptable thread",
4096,
&interruptable_thread,
&interrupted
[&interrupted]() {
while (!interrupted) {
kernel::delayMillis(5);
}
return 0;
}
);
CHECK(thread);
thread->start();
interrupted = true;
@ -58,8 +47,12 @@ TEST_CASE("thread id should only be set at when thread is started") {
auto* thread = new Thread(
"interruptable thread",
4096,
&interruptable_thread,
&interrupted
[&interrupted]() {
while (!interrupted) {
kernel::delayMillis(5);
}
return 0;
}
);
CHECK_EQ(thread->getId(), nullptr);
thread->start();
@ -75,8 +68,13 @@ TEST_CASE("thread state should be correct") {
auto* thread = new Thread(
"interruptable thread",
4096,
&interruptable_thread,
&interrupted
[&interrupted]() {
while (!interrupted) {
kernel::delayMillis(5);
}
return 0;
}
);
CHECK_EQ(thread->getState(), Thread::State::Stopped);
thread->start();
@ -93,8 +91,7 @@ TEST_CASE("thread id should only be set at when thread is started") {
auto* thread = new Thread(
"return code",
4096,
&thread_with_return_code,
&code
[&code]() { return code; }
);
thread->start();
thread->join();

View File

@ -1 +1 @@
0.3.0
0.4.0