Compare commits

...

3 Commits

Author SHA1 Message Date
Ken Van Hoeylandt
0dc2ccf47c License updates 2026-07-28 23:47:15 +02:00
Ken Van Hoeylandt
d0e8978078 Merge branch 'main' into device-license-updates 2026-07-28 23:12:22 +02:00
Ken Van Hoeylandt
bd108cc3c4
Improvements and fixes (#595)
- Fix BluetoothSettings app not updating when toggling on Bluetooth on
- Fix BluetoothSettings app crash when closing while scanning
- Fix BluetoothSettings app crash when turning BT off while scanning
- WebServer doesn't save config anymore as a side-effect of reading the config
- Add missing license headers
- Use TactilityKernel's time and delay functions instead of TactilityFreeRtos ones
2026-07-28 18:38:23 +02:00
39 changed files with 1042 additions and 129 deletions

View File

@ -1,4 +1,5 @@
#include <tactility/module.h>
#include <tactility/delay.h>
#include <tactility/error.h>
#include <tactility/log.h>
@ -42,7 +43,7 @@ static error_t start() {
}
// Avoids crash when no SD card is inserted. It's unknown why, but likely is related to power draw.
tt::kernel::delayMillis(100);
delay_millis(100);
subscribe_events();

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
#include "unphone_nav_buttons.h"
#include <tactility/delay.h>
#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/drivers/gpio_controller.h>
@ -76,9 +77,9 @@ static int32_t nav_buttons_thread_main(UnphoneNavButtonsInternal* internal) {
// Debounce all events for a short period of time
// This is easier than keeping track when each button was last pressed
tt::kernel::delayMillis(50);
delay_millis(50);
xQueueReset(internal->event_queue);
tt::kernel::delayMillis(50);
delay_millis(50);
xQueueReset(internal->event_queue);
}
}

View File

@ -2,7 +2,6 @@
## Before release
- WebServer service shouldn't save webserver.properties at start, it slows the boot process
- Remove incubating flag from various devices
- Add `// SPDX-License-Identifier: GPL-3.0-only` and `// SPDX-License-Identifier: Apache-2.0` to individual files in the project
- Elecrow Basic & Advance 3.5" memory issue: not enough memory for App Hub
@ -13,7 +12,6 @@
## Higher Priority
- Bluetooth app: when toggling BT on, it doesn't update the UI with discovered devices. It only works after re-opening the app.
- display.h API: get_backlight does not change ref counting, but it should
- bluetooth: various getters for child devices do not change ref counting, but they should
- Improve kernel_init.cpp (and other modules): create driver_ensure_added() and driver_ensure_destructed()

View File

@ -7,31 +7,61 @@ These applications are not part of the Tactility operating system's main firmwar
"end-users" refers to people who install and/or use Tactility software on their devices.
## Summary
"subproject" refers to a child project of the parent Tactility project.
The main firmware projects (`Firmware/`, `Tactility/`) are licensed under `GPL v3.0`.
## License texts
Most devices are implemented as `Apache License v2.0` while some are implemented as `GPL v3.0`.
New devices implementations be `Apache License v2.0`.
Most drivers have an `Apache License v2.0`, with exceptions such as `Drivers/gps-generic-module/`.
Licensing may also differ for subprojects intended for use in external applications.
Specific aren't generally used directly in external app projects, but if they are, make sure to check their licenses.
All projects under `Modules/` have an `Apache License v2.0`.
License texts:
The license texts that are relevant to this document:
- [Apache License v2.0](Documentation/LICENSE-Apache-2.0.md).
- [GPL v3.0](Documentation/LICENSE-GPL-3.0.md).
## GPL v3.0 to Apache Licensev2.0
## Summary
The main firmware projects (`Firmware/`, `Tactility/`) are licensed under `GPL v3.0`.
Most devices are licensed with `Apache License v2.0` while some are implemented as `GPL v3.0` until author consent is given to change the license.
New device implementations should be licensed under `Apache License v2.0`.
Most drivers have an `Apache License v2.0`, with exceptions such as `Drivers/gps-generic-module/`.
Licensing may also differ for subprojects intended for use in external applications.
Driver subprojects aren't generally used directly in external app projects, but if they are, make sure to check their licenses.
All projects under `Modules/` have an `Apache License v2.0`.
## GPL v3.0 to Apache License v2.0
Some code has changed license from GPL to Apache due to one or more of:
- Author(s) consent
- Rewriting the code
### 1. Consent of Authors
Consent of all authors involved in a specific subproject.
This consent is confirmed in writing.
### 2. Rewriting the code entirely
Some projects were rewritten entirely. Some examples:
- Drivers that were written for the `Tactility/` subproject (C++ interface, GPL) and were rewritten from scratch based on `TactilityKernel/` (C interface, Apache)
- Device subprojects were rewritten from a purely code-focused configuration project to an empty module declaration (can't really copyright this) and a DTS file.
## Device project considerations
Some device projects are provided with an Apache license, but might refer to subprojects containing GPL code.
These projects are required to be licensed with GPL as soon as they are compiled.
Their non-binary form is their non-combined form (they don't include GPL code yet), so the project retains its Apache license until it is compiled.
This allows for derivates that cut out GPL dependencies.
For example: `LilyGO T-Deck Plus` and `LilyGO T-Lora Pager`:
The projects themselves have a `module.cpp` and a `.dts` file. As long as the code is not compiled with the `gps-generic-module` drivers,
the project is not forced into a GPS license. This allows someone to copy the subproject's files into a closed-source project, remove the GPS driver from the DTS file and the `devicetree.yaml`,
and then use that in a project that is compatible with the Apache license.
In other words: If you intend to use parts Tactility in a closed-source application, make sure you check the license of the device project
and all the driver projects that it depends on.
## Overview
@ -43,7 +73,7 @@ Below is an overview of the licenses of some of the subprojects.
| TactilityC | Apache License v2.0 |
| TactilityFreeRTOS | Apache License v2.0 |
| TactilityKernel | Apache License v2.0 |
| Tests | GNU Public License v3.0 |
| Tests | (varies) |
| Devices/* | (varies) |
| Drivers/* | (varies) |
| Modules/* | Apache License v2.0 |

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: Apache-2.0
#pragma once
#define LVGL_ICON_LAUNCHER_APPS "\xEE\x97\x83"

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: Apache-2.0
#pragma once
#define LVGL_ICON_SHARED_ADD "\xEE\x85\x85"

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: Apache-2.0
#pragma once
#define LVGL_ICON_STATUSBAR_LOCATION_ON "\xEF\x87\x9B"

View File

@ -194,10 +194,22 @@ void ble_resolve_next_unnamed_peer(struct Device* device, size_t start_idx) {
size_t i = start_idx;
while (true) {
ble_addr_t addr = {};
bool found = false;
{
xSemaphoreTake(ctx->scan_mutex, portMAX_DELAY);
ble_addr_t addr = {};
bool found = false;
bool radio_on = false;
int rc = -1;
// Don't start (or chain into) a new GAP connection once the radio is going down
// (or is already off) — ble_gap_connect() racing nimble_port_stop() can block the
// NimBLE host task and hang the stop, same class of bug as the OFF_PENDING guard
// on advertising restart in gap_event_handler's BLE_GAP_EVENT_DISCONNECT case.
// The check must be re-done on every iteration (not just once on entry) since a
// failed ble_gap_connect() loops back for the next peer, and it must happen under
// scan_mutex together with the connect call itself so a concurrent dispatch_disable()
// can't flip radio_state between the check and the call.
xSemaphoreTake(ctx->scan_mutex, portMAX_DELAY);
radio_on = ctx->radio_state.load() == BT_RADIO_STATE_ON;
if (radio_on) {
while (i < ctx->scan_count) {
if (ctx->scan_results[i].name[0] == '\0') {
addr = ctx->scan_addrs[i];
@ -206,7 +218,23 @@ void ble_resolve_next_unnamed_peer(struct Device* device, size_t start_idx) {
}
++i;
}
xSemaphoreGive(ctx->scan_mutex);
if (found) {
uint8_t own_addr_type;
ble_hs_id_infer_auto(0, &own_addr_type);
void* idx_arg = (void*)(uintptr_t)i;
rc = ble_gap_connect(own_addr_type, &addr, 1500, nullptr,
name_res_gap_callback, idx_arg);
}
}
xSemaphoreGive(ctx->scan_mutex);
if (!radio_on) {
LOG_I(TAG, "Name resolution: aborting (radio not on)");
ble_set_scan_active(device, false);
struct BtEvent e = {};
e.type = BT_EVENT_SCAN_FINISHED;
ble_publish_event(device, e);
return;
}
if (!found) {
@ -218,12 +246,6 @@ void ble_resolve_next_unnamed_peer(struct Device* device, size_t start_idx) {
return;
}
uint8_t own_addr_type;
ble_hs_id_infer_auto(0, &own_addr_type);
void* idx_arg = (void*)(uintptr_t)i;
int rc = ble_gap_connect(own_addr_type, &addr, 1500, nullptr,
name_res_gap_callback, idx_arg);
if (rc == 0) {
return; // name_res_gap_callback continues the chain
}

View File

@ -8,6 +8,9 @@
#include <Tactility/bluetooth/Bluetooth.h>
#include <tactility/drivers/bluetooth.h>
#include <atomic>
#include <memory>
namespace tt::app::btmanage {
class BtManage final : public App {
@ -18,6 +21,15 @@ class BtManage final : public App {
View view = View(&bindings, &state);
bool isViewEnabled = false;
Device* btDevice = nullptr;
bool callbackRegistered = false;
// Bumped by onHide() to invalidate any BT event already dispatched to the main
// task for this show/hide session (BtManage is reused across hide/show cycles -
// e.g. launching BtPeerSettings pushes it on top and hides this instance without
// destroying it). Kept in its own heap allocation, independent of BtManage's
// lifetime, so a dispatched callback can check it without touching a possibly
// already-destroyed `this`.
std::shared_ptr<std::atomic<int>> generation = std::make_shared<std::atomic<int>>(0);
public:
@ -35,6 +47,20 @@ public:
State& getState() { return state; }
void requestViewUpdate();
std::shared_ptr<std::atomic<int>> getGeneration() const { return generation; }
// Re-attempts registering the device event callback. Needed because the BLE driver
// only allocates its callback list while the device is started/on: a registration
// attempted while the radio is off silently no-ops, so this must be called again
// right after a successful bluetooth::start(). Idempotent: no-ops if already
// registered for this device, so it's safe to call from both onShow() and here.
void registerDeviceCallback(Device* dev);
// Call after bluetooth::stop(): the driver frees its callback list on stop, so the
// registration state must be cleared here too, without touching the (now-dangling)
// driver-side list.
void forgetCallbackRegistration();
};
} // namespace tt::app::btmanage

View File

@ -1,10 +1,11 @@
#include <Tactility/CoreDefines.h>
#include <Tactility/Mutex.h>
#include <Tactility/SystemEvents.h>
#include <Tactility/Mutex.h>
#include <tactility/check.h>
#include <tactility/log.h>
#include <tactility/time.h>
#include <Tactility/CoreDefines.h>
#include <list>
namespace tt::kernel {

View File

@ -1,13 +1,13 @@
#include "Tactility/app/alertdialog/AlertDialog.h"
#include <lvgl/widgets/toolbar.h>
#include "Tactility/service/loader/Loader.h"
#include <Tactility/service/loader/Loader.h>
#include <Tactility/StringUtils.h>
#include <lvgl.h>
#include <tactility/log.h>
#include <lvgl.h>
#include <lvgl/widgets/toolbar.h>
namespace tt::app::alertdialog {
#define PARAMETER_BUNDLE_KEY_TITLE "title"

View File

@ -1,6 +1,8 @@
#include "Tactility/lvgl/Lvgl.h"
#include "tactility/drivers/backlight.h"
#include "tactility/drivers/display.h"
#include <tactility/delay.h>
#include <tactility/drivers/backlight.h>
#include <tactility/drivers/display.h>
#include <tactility/log.h>
#include <tactility/time.h>
#include <Tactility/CpuAffinity.h>
#include <Tactility/Paths.h>
@ -10,13 +12,13 @@
#include <Tactility/app/AppPaths.h>
#include <Tactility/app/alertdialog/AlertDialog.h>
#include <Tactility/hal/usb/Usb.h>
#include <Tactility/lvgl/Lvgl.h>
#include <Tactility/lvgl/Style.h>
#include <Tactility/service/loader/Loader.h>
#include <Tactility/settings/BootSettings.h>
#include <Tactility/settings/DisplaySettings.h>
#include <lvgl.h>
#include <tactility/log.h>
#include <atomic>
@ -108,23 +110,23 @@ class BootApp : public App {
}
static void waitForMinimalSplashDuration(TickType_t startTime) {
const auto end_time = kernel::getTicks();
const auto end_time = get_ticks();
const auto ticks_passed = end_time - startTime;
constexpr auto minimum_ticks = (CONFIG_TT_SPLASH_DURATION / portTICK_PERIOD_MS);
if (minimum_ticks > ticks_passed) {
kernel::delayTicks(minimum_ticks - ticks_passed);
delay_ticks(minimum_ticks - ticks_passed);
}
}
static int32_t bootThreadCallback() {
LOG_I(TAG, "Starting boot thread");
const auto start_time = kernel::getTicks();
const auto start_time = get_ticks();
// Give the UI some time to redraw
// If we don't do this, various init calls will read files and block SPI IO for the display
// This would result in a blank/black screen being shown during this phase of the boot process
// This works with 5 ms on a T-Lora Pager, so we give it 10 ms to be safe
kernel::delayMillis(10);
delay_millis(10);
// TODO: Support for multiple displays
LOG_I(TAG, "Setup display");

View File

@ -23,10 +23,20 @@ static void onBtToggled(bool requestOn) {
bool radio_on = bluetooth::isRadioOnOrPending(dev);
if (requestOn && !radio_on) {
LOG_I(TAG, "Turning on");
bluetooth::start(dev);
if (bluetooth::start(dev)) {
// The driver only allocates its callback list once the device is started,
// so the registration attempted in onShow() (while radio was off) was a
// no-op. Register again now that the device is actually up.
auto bt = std::static_pointer_cast<BtManage>(getCurrentApp());
bt->registerDeviceCallback(dev);
}
} else if (!requestOn && radio_on) {
LOG_I(TAG, "Turning off");
bluetooth::stop(dev);
if (bluetooth::stop(dev)) {
// A completed stop frees the driver's callback list.
auto bt = std::static_pointer_cast<BtManage>(getCurrentApp());
bt->forgetCallbackRegistration();
}
}
device_put(dev);
} else {
@ -90,13 +100,19 @@ void BtManage::unlock() {
}
void BtManage::requestViewUpdate() {
// Lock order must match onShow()/onHide(): both run under GuiService's lvgl_lock()
// and then take `mutex` internally. Taking `mutex` before lvgl_lock() here would
// invert that order and deadlock against a concurrent onHide()/onShow() (GUI task
// holding LVGL lock, waiting on `mutex`; this task holding `mutex`, waiting on LVGL
// lock) - exactly what happens when BT events fire rapidly (e.g. during scanning)
// while the app is being hidden.
lvgl_lock();
lock();
if (isViewEnabled) {
lvgl_lock();
view.update();
lvgl_unlock();
}
unlock();
lvgl_unlock();
}
void BtManage::onBtEvent(const BtEvent& event) {
@ -148,17 +164,45 @@ static void onKernelBtEvent(Device* /*device*/, void* context, BtEvent event) {
// nimble_port_stop), creating a permanent deadlock. Dispatch to the main task so
// the NimBLE host task is never blocked by BtManage's state updates or LVGL lock.
auto* self = static_cast<BtManage*>(context);
getMainDispatcher().dispatch([self, event] {
// Captured while `self` is still guaranteed valid (the callback is only invoked
// while registered, i.e. before onHide() removes it). Comparing this later - without
// dereferencing `self` - lets the dispatched lambda detect a stale event from a
// session that has since been hidden (and possibly destroyed) without a UAF.
auto generation = self->getGeneration();
int expectedGeneration = generation->load();
getMainDispatcher().dispatch([self, generation, expectedGeneration, event] {
if (generation->load() != expectedGeneration) {
return;
}
self->onBtEvent(event);
});
}
void BtManage::registerDeviceCallback(Device* dev) {
lock();
if (btDevice == dev && !callbackRegistered) {
// Only latch the flag on success: while the radio is off the driver has no
// callback list yet, so this add is a silent no-op and must be retried once
// bluetooth::start() actually brings the device up.
if (bluetooth_add_event_callback(dev, this, onKernelBtEvent) == ERROR_NONE) {
callbackRegistered = true;
}
}
unlock();
}
void BtManage::forgetCallbackRegistration() {
lock();
callbackRegistered = false;
unlock();
}
void BtManage::onShow(AppContext& app, lv_obj_t* parent) {
// Initialise state and view before subscribing to avoid incoming events
// racing with state initialisation.
state.setRadioState(bluetooth::getRadioState());
Device* dev = nullptr;
device_get_first_active_by_type(&BLUETOOTH_TYPE, &dev);
device_get_first_by_type(&BLUETOOTH_TYPE, &dev);
state.setScanning(dev ? bluetooth_is_scanning(dev) : false);
state.updateScanResults();
@ -177,7 +221,7 @@ void BtManage::onShow(AppContext& app, lv_obj_t* parent) {
btDevice = dev;
if (btDevice) {
bluetooth_add_event_callback(btDevice, this, onKernelBtEvent);
registerDeviceCallback(btDevice);
}
auto radio_state = bluetooth::getRadioState();
@ -192,9 +236,17 @@ void BtManage::onShow(AppContext& app, lv_obj_t* parent) {
}
void BtManage::onHide(AppContext& app) {
// Invalidate any BT event dispatched-but-not-yet-run for this session before doing
// anything else, so it can't race a subsequent destruction of this instance (see
// onKernelBtEvent()/getGeneration()).
generation->fetch_add(1);
lock();
if (btDevice) {
bluetooth_remove_event_callback(btDevice, onKernelBtEvent);
if (callbackRegistered) {
bluetooth_remove_event_callback(btDevice, onKernelBtEvent);
callbackRegistered = false;
}
device_put(btDevice);
btDevice = nullptr;
}

View File

@ -8,6 +8,7 @@
#include <Tactility/lvgl/Toolbar.h>
#include <tactility/device.h>
#include <tactility/time.h>
#include <atomic>
#include <cstring>
@ -211,7 +212,7 @@ public:
GpsSettingsApp() {
// Runs while the screen is shown - there's no push notification for GPS device state
// changes, so this is the only way this screen finds out about them.
timer = std::make_unique<Timer>(Timer::Type::Periodic, kernel::secondsToTicks(1), [this] {
timer = std::make_unique<Timer>(Timer::Type::Periodic, seconds_to_ticks(1), [this] {
updateDeviceStates();
});
}

View File

@ -6,6 +6,7 @@
#include <tactility/device.h>
#include <tactility/drivers/power_supply.h>
#include <tactility/time.h>
#include <lvgl/lvgl.h>
#include <lvgl/icons/shared.h>
@ -53,7 +54,7 @@ struct DeviceEntry {
class PowerApp : public App {
Timer update_timer = Timer(Timer::Type::Periodic, kernel::millisToTicks(1000),[]() { onTimer(); });
Timer update_timer = Timer(Timer::Type::Periodic, millis_to_ticks(1000),[]() { onTimer(); });
std::vector<DeviceEntry> entries;

View File

@ -1,8 +1,11 @@
#include <Tactility/TactilityConfig.h>
#include <Tactility/lvgl/Toolbar.h>
#include <Tactility/Tactility.h>
#include <Tactility/Timer.h>
#include "tactility/time.h"
#include <Tactility/Paths.h>
#include <Tactility/Tactility.h>
#include <Tactility/TactilityConfig.h>
#include <Tactility/Timer.h>
#include <Tactility/lvgl/Toolbar.h>
#include <algorithm>
#include <cstring>
@ -242,7 +245,7 @@ static std::shared_ptr<SystemInfoApp> optApp() {
}
class SystemInfoApp final : public App {
Timer memoryTimer = Timer(Timer::Type::Periodic, kernel::millisToTicks(10000), [] {
Timer memoryTimer = Timer(Timer::Type::Periodic, millis_to_ticks(10000), [] {
auto app = optApp();
if (app) {
lvgl_lock();
@ -251,7 +254,7 @@ class SystemInfoApp final : public App {
}
});
Timer tasksTimer = Timer(Timer::Type::Periodic, kernel::millisToTicks(15000), [] {
Timer tasksTimer = Timer(Timer::Type::Periodic, millis_to_ticks(15000), [] {
auto app = optApp();
if (app) {
lvgl_lock();

View File

@ -11,6 +11,7 @@
#include <tactility/check.h>
#include <tactility/log.h>
#include <tactility/time.h>
#include <lvgl/fonts.h>
#include <lvgl/lvgl.h>
@ -182,7 +183,7 @@ lv_obj_t* statusbar_create(lv_obj_t* parent) {
obj_set_style_bg_invisible(left_spacer);
lv_obj_set_flex_grow(left_spacer, 1);
statusbar_data.mutex.lock(kernel::MAX_TICKS);
statusbar_data.mutex.lock(MAX_TICKS);
for (int i = 0; i < STATUSBAR_ICON_LIMIT; ++i) {
auto* image = lv_image_create(obj);
lv_obj_set_size(image, icon_size, icon_size); // regular padding doesn't work

View File

@ -1,6 +1,8 @@
#ifdef ESP_PLATFORM
#include <Tactility/service/displayidle/DisplayIdleService.h>
#include <Tactility/service/ServiceManifest.h>
#include <Tactility/service/ServiceRegistration.h>
#include "BouncingBallsScreensaver.h"
#include "MatrixRainScreensaver.h"
@ -8,14 +10,14 @@
#include "Screensaver.h"
#include "StackChanScreensaver.h"
#include <Tactility/service/ServiceManifest.h>
#include <Tactility/service/ServiceRegistration.h>
#include <cstdlib>
#include <ctime>
#include <tactility/delay.h>
#include <tactility/log.h>
#include <tactility/drivers/display.h>
#include <tactility/drivers/backlight.h>
#include <lvgl/lvgl.h>
namespace tt::service::displayidle {
@ -221,7 +223,7 @@ bool DisplayIdleService::onStart(ServiceContext& service) {
cachedDisplaySettings = settings::display::loadOrGetDefault();
timer = std::make_unique<Timer>(Timer::Type::Periodic, kernel::millisToTicks(TICK_INTERVAL_MS), [this]{ this->tick(); });
timer = std::make_unique<Timer>(Timer::Type::Periodic, millis_to_ticks(TICK_INTERVAL_MS), [this]{ this->tick(); });
timer->setCallbackPriority(Thread::Priority::Lower);
timer->start();
return true;
@ -238,7 +240,7 @@ void DisplayIdleService::onStop(ServiceContext& service) {
for (int i = 0; i < maxRetries && screensaverOverlay; ++i) {
stopScreensaver();
if (screensaverOverlay && i < maxRetries - 1) {
kernel::delayMillis(50); // Brief delay before retry
delay_millis(50); // Brief delay before retry
}
}
if (screensaverOverlay) {

View File

@ -2,6 +2,7 @@
#include <display/lv_display.h>
#include <lvgl/lvgl.h>
#include <Tactility/Timer.h>
#include <Tactility/service/ServiceContext.h>
@ -9,10 +10,10 @@
#include <Tactility/service/ServiceRegistration.h>
#include <Tactility/settings/KeyboardSettings.h>
#include <lvgl/lvgl.h>
#include <tactility/device.h>
#include <tactility/drivers/backlight.h>
#include <tactility/drivers/keyboard.h>
#include <tactility/time.h>
namespace tt::service::keyboardidle {
@ -92,7 +93,7 @@ public:
// Note: Settings changes require service restart to take effect
// TODO: Add KeyboardSettingsChanged events for dynamic updates
timer = std::make_unique<Timer>(Timer::Type::Periodic, kernel::millisToTicks(250), [this]{ this->tick(); });
timer = std::make_unique<Timer>(Timer::Type::Periodic, millis_to_ticks(250), [this]{ this->tick(); });
timer->setCallbackPriority(Thread::Priority::Lower);
timer->start();
return true;

View File

@ -8,6 +8,7 @@
#include <Tactility/service/loader/Loader.h>
#include <Tactility/service/screenshot/ScreenshotTask.h>
#include <tactility/delay.h>
#include <tactility/log.h>
#include <lvgl/lvgl.h>
@ -71,7 +72,7 @@ void ScreenshotTask::taskMain() {
if (work.type == TASK_WORK_TYPE_DELAY) {
// Splitting up the delays makes it easier to stop the service
for (int i = 0; i < (work.delay_in_seconds * 10) && !isInterrupted(); ++i){
kernel::delayMillis(100);
delay_millis(100);
}
if (!isInterrupted()) {
@ -88,14 +89,14 @@ void ScreenshotTask::taskMain() {
if (appContext != nullptr) {
const app::AppManifest& manifest = appContext->getManifest();
if (manifest.appId != last_app_id) {
kernel::delayMillis(100);
delay_millis(100);
last_app_id = manifest.appId;
auto filename = std::format("{}/screenshot-{}.png", work.path, manifest.appId);
makeScreenshot(filename);
}
}
// Ensure the LVGL widgets are rendered as the app just started
kernel::delayMillis(250);
delay_millis(250);
}
}

View File

@ -11,12 +11,12 @@
#include <Tactility/service/ServiceRegistration.h>
#include <Tactility/service/wifi/WifiBootSplashInit.h>
#include <Tactility/service/wifi/WifiGlobals.h>
#include <Tactility/service/wifi/WifiSettings.h>
#include <tactility/check.h>
#include <tactility/device.h>
#include <tactility/drivers/wifi.h>
#include <tactility/log.h>
#include <tactility/time.h>
#include <tactility/wifi_auto_scan.h>
#include <algorithm>
@ -76,7 +76,7 @@ struct WifiServiceState {
bool connectionTargetRemember = false;
settings::WifiApSettings connectionTarget;
uint16_t scanRecordLimit = TT_WIFI_SCAN_RECORD_LIMIT;
TickType_t lastScanTime = kernel::MAX_TICKS;
TickType_t lastScanTime = MAX_TICKS;
std::unique_ptr<Timer> autoConnectTimer;
kernel::SystemEventSubscription bootEventSubscription = kernel::NoSystemEventSubscription;
};
@ -165,7 +165,7 @@ void dispatchScan() {
LOG_I(TAG, "dispatchScan()");
if (!started || state.device == nullptr || !device_is_ready(state.device)) return;
state.lastScanTime = kernel::getTicks();
state.lastScanTime = get_ticks();
error_t result = wifi_scan(state.device);
if (result != ERROR_NONE) {
@ -263,7 +263,7 @@ bool shouldScanForAutoConnect() {
!state.pauseAutoConnect && !state.externalScanPause.load();
if (!radio_scannable) return false;
TickType_t current_time = kernel::getTicks();
TickType_t current_time = get_ticks();
bool scan_time_has_looped = current_time < state.lastScanTime;
bool no_recent_scan = (current_time - state.lastScanTime) > (AUTO_SCAN_INTERVAL / portTICK_PERIOD_MS);
return scan_time_has_looped || no_recent_scan;

View File

@ -144,23 +144,17 @@ bool load(WebServerSettings& settings) {
? static_cast<uint8_t>(parseInt(ap_channel->second, 1, 13, 1))
: 1;
// Security: If AP password is empty, generate a strong random password.
// Security: If AP password is empty, generate a strong random password in memory.
// Skip this if user explicitly wants an open network.
// Note: We only auto-generate for EMPTY passwords, not user-set ones.
// This is a read-only function: the generated password is NOT persisted here —
// callers that want it saved must call save() explicitly.
if (!settings.apOpenNetwork && isEmptyCredential(settings.apPassword)) {
LOG_I(TAG, "AP password is empty - generating secure random password");
LOG_I(TAG, "AP password is empty - generating secure random password (not persisted)");
// Generate 12-character random password (alphanumeric, ~71 bits of entropy)
// WPA2 requires 8-63 characters, so 12 is well within range
settings.apPassword = generateRandomCredential(12);
// Persist the generated password immediately
map[KEY_AP_PASSWORD] = settings.apPassword;
if (file::savePropertiesFile(getSettingsFilePath(), map)) {
LOG_I(TAG, "Generated and saved new secure AP password");
} else {
LOG_E(TAG, "Failed to save generated AP password");
}
}
// Web server settings
@ -181,27 +175,20 @@ bool load(WebServerSettings& settings) {
settings.webServerUsername = (webserver_username != map.end()) ? webserver_username->second : "";
settings.webServerPassword = (webserver_password != map.end()) ? webserver_password->second : "";
// Security: If auth is enabled but credentials are empty,
// generate strong random credentials and persist them immediately.
// Note: We only auto-generate for EMPTY credentials, allowing users to set their own.
// Security: If auth is enabled but credentials are empty, generate strong random
// credentials in memory. Note: We only auto-generate for EMPTY credentials, allowing
// users to set their own.
// This is a read-only function: the generated credentials are NOT persisted here —
// callers that want them saved (so they're consistent across reboots) must call
// save() explicitly.
if (settings.webServerAuthEnabled &&
(isEmptyCredential(settings.webServerUsername) || isEmptyCredential(settings.webServerPassword))) {
LOG_I(TAG, "Auth enabled with empty credentials - generating secure random credentials");
LOG_I(TAG, "Auth enabled with empty credentials - generating secure random credentials (not persisted)");
// Generate 12-character random credentials (alphanumeric, ~71 bits of entropy each)
settings.webServerUsername = generateRandomCredential(12);
settings.webServerPassword = generateRandomCredential(12);
// Persist the generated credentials immediately
// We need to save these to the file so they're consistent across reboots
map[KEY_WEBSERVER_USERNAME] = settings.webServerUsername;
map[KEY_WEBSERVER_PASSWORD] = settings.webServerPassword;
if (file::savePropertiesFile(getSettingsFilePath(), map)) {
LOG_I(TAG, "Generated and saved new secure credentials");
} else {
LOG_E(TAG, "Failed to save generated credentials - auth may be inconsistent across reboots");
}
}
return true;
@ -228,14 +215,10 @@ WebServerSettings loadOrGetDefault() {
bool loadedFromFlash = load(settings);
if (!loadedFromFlash) {
// First boot - use defaults (WiFi OFF, WebServer OFF)
// No properties file yet (e.g. first boot) - use defaults in memory (WiFi OFF,
// WebServer OFF). Read-only function: does NOT persist these defaults — callers
// that want them saved must call save() explicitly.
settings = getDefault();
// Save defaults to flash so toggle states persist
if (save(settings)) {
LOG_I(TAG, "First boot - saved default settings (WiFi OFF WebServer OFF)");
} else {
LOG_W(TAG, "First boot - failed to save default settings to flash");
}
}
return settings;

View File

@ -57,7 +57,7 @@ public:
* @param[in] timeout lock acquisition timeout
* @return true if dispatching was successful (timeout not reached)
*/
bool dispatch(Function function, TickType_t timeout = kernel::MAX_TICKS) {
bool dispatch(Function function, TickType_t timeout = kernel::FREERTOS_MAX_TICKS) {
// Mutate
if (!mutex.lock(timeout)) {
#ifdef ESP_PLATFORM
@ -92,7 +92,7 @@ public:
* @param[in] timeout the ticks to wait for a message
* @return the amount of messages that were consumed
*/
uint32_t consume(TickType_t timeout = kernel::MAX_TICKS) {
uint32_t consume(TickType_t timeout = kernel::FREERTOS_MAX_TICKS) {
// Wait for signal
if (!eventFlag.wait(WAIT_FLAG, false, true, nullptr, timeout)) {
return 0;

View File

@ -46,7 +46,7 @@ public:
/**
* Dispatch a message.
*/
bool dispatch(const Dispatcher::Function& function, TickType_t timeout = kernel::MAX_TICKS) {
bool dispatch(const Dispatcher::Function& function, TickType_t timeout = kernel::FREERTOS_MAX_TICKS) {
return dispatcher.dispatch(function, timeout);
}

View File

@ -100,7 +100,7 @@ public:
bool awaitAll = false,
bool clearOnExit = true,
uint32_t* outFlags = nullptr,
TickType_t timeout = kernel::MAX_TICKS
TickType_t timeout = kernel::FREERTOS_MAX_TICKS
) const {
assert(xPortInIsrContext() == pdFALSE);

View File

@ -20,7 +20,7 @@ public:
virtual bool lock(TickType_t timeout) const = 0;
bool lock() const { return lock(kernel::MAX_TICKS); }
bool lock() const { return lock(kernel::FREERTOS_MAX_TICKS); }
virtual void unlock() const = 0;
@ -40,9 +40,9 @@ public:
}
}
void withLock(const std::function<void()>& onLockAcquired) const { withLock(kernel::MAX_TICKS, onLockAcquired); }
void withLock(const std::function<void()>& onLockAcquired) const { withLock(kernel::FREERTOS_MAX_TICKS, onLockAcquired); }
void withLock(const std::function<void()>& onLockAcquired, const std::function<void()>& onLockFailed) const { withLock(kernel::MAX_TICKS, onLockAcquired, onLockFailed); }
void withLock(const std::function<void()>& onLockAcquired, const std::function<void()>& onLockFailed) const { withLock(kernel::FREERTOS_MAX_TICKS, onLockAcquired, onLockFailed); }
ScopedLock asScopedLock() const;
};

View File

@ -43,7 +43,7 @@ public:
}
// Wait for Mutex usage
if (mutex.lock(kernel::MAX_TICKS)) {
if (mutex.lock(kernel::FREERTOS_MAX_TICKS)) {
// TODO: Fix the case where the mutex might be immediately locked after this point and then crashes when deleted
mutex.unlock();
}

View File

@ -224,7 +224,7 @@ public:
/**
* @warning If this blocks forever, it might be because of the Thread, but it could also be because another task is blocking the CPU.
*/
bool join(TickType_t timeout = kernel::MAX_TICKS, TickType_t pollInterval = 10) {
bool join(TickType_t timeout = kernel::FREERTOS_MAX_TICKS, TickType_t pollInterval = 10) {
assert(getCurrent() != this);
TickType_t start_ticks = kernel::getTicks();

View File

@ -29,7 +29,7 @@ private:
struct TimerHandleDeleter {
void operator()(TimerHandle_t handleToDelete) const {
xTimerDelete(handleToDelete, kernel::MAX_TICKS);
xTimerDelete(handleToDelete, kernel::FREERTOS_MAX_TICKS);
}
};
@ -75,7 +75,7 @@ public:
*/
bool start() const {
assert(xPortInIsrContext() == pdFALSE);
return xTimerStart(handle.get(), kernel::MAX_TICKS) == pdPASS;
return xTimerStart(handle.get(), kernel::FREERTOS_MAX_TICKS) == pdPASS;
}
/** Stop the timer
@ -84,7 +84,7 @@ public:
*/
bool stop() const {
assert(xPortInIsrContext() == pdFALSE);
return xTimerStop(handle.get(), kernel::MAX_TICKS) == pdPASS;
return xTimerStop(handle.get(), kernel::FREERTOS_MAX_TICKS) == pdPASS;
}
/**
@ -94,8 +94,8 @@ public:
*/
bool reset(TickType_t interval) const {
assert(xPortInIsrContext() == pdFALSE);
return xTimerChangePeriod(handle.get(), interval, kernel::MAX_TICKS) == pdPASS &&
xTimerReset(handle.get(), kernel::MAX_TICKS) == pdPASS;
return xTimerChangePeriod(handle.get(), interval, kernel::FREERTOS_MAX_TICKS) == pdPASS &&
xTimerReset(handle.get(), kernel::FREERTOS_MAX_TICKS) == pdPASS;
}
/**
@ -104,7 +104,7 @@ public:
*/
bool reset() const {
assert(xPortInIsrContext() == pdFALSE);
return xTimerReset(handle.get(), kernel::MAX_TICKS) == pdPASS;
return xTimerReset(handle.get(), kernel::FREERTOS_MAX_TICKS) == pdPASS;
}
/** @return true when the timer is running */

View File

@ -17,7 +17,7 @@
namespace tt::kernel {
constexpr TickType_t MAX_TICKS = ~static_cast<TickType_t>(0);
constexpr TickType_t FREERTOS_MAX_TICKS = ~static_cast<TickType_t>(0);
/** @return the frequency at which the kernel task schedulers operate */
constexpr uint32_t getTickFrequency() {

View File

@ -10,6 +10,7 @@
#endif
#include <tactility/freertos/freertos.h>
#include <tactility/freertos/task.h>
#include <tactility/check.h>
#ifdef __cplusplus

View File

@ -11,7 +11,8 @@
#include <stdint.h>
#include "defines.h"
#include "tactility/freertos/task.h"
#include <tactility/freertos/port.h>
#include <tactility/freertos/task.h>
#ifdef ESP_PLATFORM
#include <esp_timer.h>
@ -31,6 +32,8 @@ static_assert(configTICK_RATE_HZ == 1000);
static_assert(configTICK_RATE_HZ == 1000, "configTICK_RATE_HZ must be 1000");
#endif
#define MAX_TICKS (~(TickType_t)0)
static inline uint32_t get_tick_frequency() {
return configTICK_RATE_HZ;
}

View File

@ -0,0 +1,195 @@
Apache License
==============
_Version 2.0, January 2004_
_&lt;<http://www.apache.org/licenses/>&gt;_
### 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.

View File

@ -0,0 +1,195 @@
Apache License
==============
_Version 2.0, January 2004_
_&lt;<http://www.apache.org/licenses/>&gt;_
### 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.

View File

@ -7,13 +7,13 @@ using namespace tt;
TEST_CASE("a Mutex can block a thread") {
auto mutex = Mutex();
CHECK_EQ(mutex.lock(kernel::MAX_TICKS), true);
CHECK_EQ(mutex.lock(kernel::FREERTOS_MAX_TICKS), true);
Thread thread = Thread(
"thread",
1024,
[&mutex] {
mutex.lock(kernel::MAX_TICKS);
mutex.lock(kernel::FREERTOS_MAX_TICKS);
return 0;
}
);

View File

@ -7,13 +7,13 @@ using namespace tt;
TEST_CASE("a RecursiveMutex can block a thread") {
auto mutex = RecursiveMutex();
CHECK_EQ(mutex.lock(kernel::MAX_TICKS), true);
CHECK_EQ(mutex.lock(kernel::FREERTOS_MAX_TICKS), true);
Thread thread = Thread(
"thread",
1024,
[&mutex] {
mutex.lock(kernel::MAX_TICKS);
mutex.lock(kernel::FREERTOS_MAX_TICKS);
return 0;
}
);

View File

@ -0,0 +1,195 @@
Apache License
==============
_Version 2.0, January 2004_
_&lt;<http://www.apache.org/licenses/>&gt;_
### 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.

View File

@ -0,0 +1,195 @@
Apache License
==============
_Version 2.0, January 2004_
_&lt;<http://www.apache.org/licenses/>&gt;_
### 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.