Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,730 changes: 2,444 additions & 286 deletions Buildscripts/TactilitySDK/Tools/ui.py

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions Devices/cl32-v04/source/cl32_v4_display.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include <driver/gpio.h>
#include <driver/spi_master.h>
#include <esp_private/esp_gpio_reserve.h>

#include <cstring>

Expand Down Expand Up @@ -71,14 +72,13 @@ static bool detect_ssd16xx(Device* spi1) {
}

gpio_config_t outputs = {
.pin_bit_mask = (1ULL << PIN_CS) | (1ULL << PIN_DC) | (1ULL << PIN_RESET),
.pin_bit_mask = (1ULL << PIN_DC) | (1ULL << PIN_RESET),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&outputs);
gpio_set_level(PIN_CS, 1);

gpio_config_t input = {
.pin_bit_mask = 1ULL << PIN_BUSY,
Expand All @@ -101,6 +101,8 @@ static bool detect_ssd16xx(Device* spi1) {

spi_bus_remove_device(spi);
gpio_reset_pin(PIN_BUSY);
// The display driver configures these pins again
esp_gpio_revoke((1ULL << PIN_DC) | (1ULL << PIN_RESET));
return busy;
}

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions Documentation/ideas.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

## Medium Priority

- Update timezones.csv wrt 2026e, write tests for related code
- Try https://github.com/bootdsc/Fastwave-Eink-Driver with CL-32 e-paper.
- Pick different font to improve monochrome screen readability (or change the weight).
- Use GPS time to set/update the current time: when enabled, at boot, when wifi is not enabled, start the gps device and wait until a lock is acquired, then get the time and sync it. Then stop the GPS device.
Expand Down
8 changes: 6 additions & 2 deletions LICENSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ 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.

## Logo
## Tactility Logo

The Tactility logo copyrights are owned by Ken Van Hoeylandt.

Expand All @@ -99,11 +99,15 @@ Practical examples:
- A blog post about Tactility can use screenshots and the logo itself when writing about Tactility
- A developer who forked Tactility to merge new features or fixes to the official Tactility repository is allowed to make builds with the logo, as long as these builds are not re-distributed to end-users.

## Vendor Logos

The copyright and/or trademark of the vendor logos are owned by the related vendors.

## Third Party Notices

Third-party licenses and copyrights are listed in [THIRD-PARTY-NOTICES.md](THIRD-PARTY-NOTICES.md).

## FAQ

- Q: Can I build closed source applications?
- A: If the applications were built with the Tactility SDK, then they can have a proprietary license. Applications inside the Tactility firmware can't be released with a proprietary license.
- A: If the applications were built with the Tactility SDK, then they can have a proprietary license. Applications inside the Tactility firmware can't be released with a proprietary license.
2 changes: 1 addition & 1 deletion Modules/lodepng-module/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ add_executable(LodePngModuleTests EXCLUDE_FROM_ALL ${TEST_SOURCES})
target_include_directories(LodePngModuleTests PRIVATE ${DOCTESTINC})

target_compile_definitions(LodePngModuleTests PRIVATE
"LODEPNG_TEST_LOGO=\"${CMAKE_SOURCE_DIR}/Data/system/app/Boot/assets/logo.png\""
"LODEPNG_TEST_LOGO=\"${CMAKE_SOURCE_DIR}/Data/system/boot/logo_medium.png\""
)

add_test(NAME LodePngModuleTests COMMAND LodePngModuleTests)
Expand Down
3 changes: 3 additions & 0 deletions Modules/lvgl-module/source/symbols.c
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,9 @@ const struct ModuleSymbol lvgl_module_symbols[] = {
DEFINE_MODULE_SYMBOL(lv_display_trigger_activity),
DEFINE_MODULE_SYMBOL(lv_display_add_event_cb),
DEFINE_MODULE_SYMBOL(lv_display_remove_event_cb_with_user_data),
DEFINE_MODULE_SYMBOL(lv_display_get_screen_active),
DEFINE_MODULE_SYMBOL(lv_display_get_next),
DEFINE_MODULE_SYMBOL(lv_display_get_driver_data),
// lv_pct
DEFINE_MODULE_SYMBOL(lv_pct),
DEFINE_MODULE_SYMBOL(lv_pct_to_px),
Expand Down
9 changes: 9 additions & 0 deletions Modules/lvgl-module/source/themes/lv_theme_material_mono.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ extern const lv_obj_class_t lvgl_text_button_class;
#define FOCUS_OFFSET (theme->config.is_compact ? LINE_THIN : LINE_MEDIUM)
#define EDIT_WIDTH (theme->config.is_compact ? LINE_MEDIUM : LINE_THICK)
#define FOCUS_INSET_WIDTH (theme->config.is_compact ? LINE_THIN : LINE_MEDIUM)
#define FOCUS_INVERTED_GAP (theme->config.is_compact ? 1 : LV_DPX_CALC(theme->disp_dpi, 2))
#define MOTION_DURATION_SHORT (theme->config.animations_enabled ? DURATION_SHORT : 0)
#define MOTION_DURATION_MEDIUM (theme->config.animations_enabled ? DURATION_MEDIUM : 0)
#define MOTION_DURATION_LONG (theme->config.animations_enabled ? DURATION_LONG : 0)
Expand Down Expand Up @@ -223,6 +224,7 @@ typedef struct {
lv_style_t focus_ring;
lv_style_t edit_ring;
lv_style_t focus_ring_inset;
lv_style_t focus_ring_inset_inverted;
lv_style_t edit_ring_inset;
lv_style_t inverted;
lv_style_t disabled;
Expand Down Expand Up @@ -502,6 +504,11 @@ static void style_init(my_theme_t * theme)
lv_style_set_outline_pad(&theme->styles.focus_ring_inset, -FOCUS_INSET_WIDTH);
lv_style_set_outline_opa(&theme->styles.focus_ring_inset, LV_OPA_COVER);

style_init_reset(&theme->styles.focus_ring_inset_inverted);
lv_style_set_border_color(&theme->styles.focus_ring_inset_inverted, BUTTON_INVERTED_LABEL_COLOR);
lv_style_set_border_width(&theme->styles.focus_ring_inset_inverted, FOCUS_INSET_WIDTH + FOCUS_INVERTED_GAP);
lv_style_set_border_opa(&theme->styles.focus_ring_inset_inverted, LV_OPA_COVER);

style_init_reset(&theme->styles.edit_ring_inset);
lv_style_set_outline_color(&theme->styles.edit_ring_inset, FOCUS_RING_COLOR);
lv_style_set_outline_width(&theme->styles.edit_ring_inset, EDIT_RING_WIDTH);
Expand Down Expand Up @@ -1417,6 +1424,8 @@ static void theme_apply(lv_theme_t * th, lv_obj_t * obj)
lv_obj_add_style(obj, &theme->styles.inverted, LV_STATE_PRESSED);
lv_obj_add_style(obj, &theme->styles.inverted, LV_STATE_CHECKED);
lv_obj_add_style(obj, &theme->styles.focus_ring_inset, LV_STATE_FOCUS_KEY);
lv_obj_add_style(obj, &theme->styles.focus_ring_inset_inverted, LV_STATE_FOCUS_KEY | LV_STATE_CHECKED);
lv_obj_add_style(obj, &theme->styles.focus_ring_inset_inverted, LV_STATE_FOCUS_KEY | LV_STATE_PRESSED);
lv_obj_add_style(obj, &theme->styles.edit_ring_inset, LV_STATE_EDITED);
lv_obj_add_style(obj, &theme->styles.disabled, LV_STATE_DISABLED);
return;
Expand Down
10 changes: 10 additions & 0 deletions Modules/lvgl-module/themes/material_mono.lss
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@
@edit-width: if($isCompact, @line-medium, @line-thick);
// Drawn inside the widget, for widgets with little room around them (icon buttons)
@focus-inset-width: if($isCompact, @line-thin, @line-medium);
@focus-inverted-gap: if($isCompact, 1, 2dp);

// Motion
@motion-duration-short: if($animationsEnabled, @duration-short, 0);
Expand Down Expand Up @@ -337,6 +338,13 @@ focus_ring_inset {
outlineOpa: cover;
}

// The tile is ink while inverted. A paper border under the ring leaves a gap, so the ink fill looks smaller than the ring.
focus_ring_inset_inverted {
borderColor: @button-inverted-label-color;
borderWidth: @focus-inset-width + @focus-inverted-gap;
borderOpa: cover;
}

edit_ring_inset {
outlineColor: @focus-ring-color;
outlineWidth: @edit-ring-width;
Expand Down Expand Up @@ -1075,6 +1083,8 @@ apply(icon_button) {
inverted: state.pressed;
inverted: state.checked;
focus_ring_inset: state.focusKey;
focus_ring_inset_inverted: state.focusKey, state.checked;
focus_ring_inset_inverted: state.focusKey, state.pressed;
edit_ring_inset: state.edited;
disabled: state.disabled;
}
Expand Down
82 changes: 76 additions & 6 deletions Modules/mesh-module/source/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,101 @@

#include <tactility/error.h>
#include <tactility/module.h>
#include <tactility/concurrent/mutex.h>
#include <tactility/log.h>
#include <tactility/system_event.h>

#include <atomic>

constexpr auto* TAG = "mesh";

// Kept across module restarts, as the boot event is only emitted once
static std::atomic<bool> boot_completed = false;

struct LifecycleMutex {
Mutex handle {};
LifecycleMutex() { mutex_construct(&handle); }
~LifecycleMutex() { mutex_destruct(&handle); }
};

// Serializes the boot callback with starting and stopping the module. A callback that was already
// dispatched can still run after the subscription was removed, so it checks module_active under the lock.
static LifecycleMutex lifecycle_mutex;
static bool module_active = false;

extern "C" {

// Radios can start after this module does, so the service only starts once all devices are up
static void start_service_if_enabled() {
if (mesh_service_should_auto_start() && service_manager_start(mesh_service_manifest.id) != ERROR_NONE) {
LOG_E(TAG, "Failed to start the service");
}
}

static void on_boot_completed(SystemEvent* event, void* context) {
(void)event;
(void)context;
boot_completed = true;
mutex_lock(&lifecycle_mutex.handle);
if (module_active) {
start_service_if_enabled();
}
mutex_unlock(&lifecycle_mutex.handle);
}

static error_t start() {
mutex_lock(&lifecycle_mutex.handle);
error_t error = app_manager_add(&mesh_command_manifest);
if (error != ERROR_NONE) {
mutex_unlock(&lifecycle_mutex.handle);
return error;
}
error = service_manager_add(&mesh_service_manifest, false);
if (error != ERROR_NONE) {
app_manager_remove(mesh_command_manifest.id);
mutex_unlock(&lifecycle_mutex.handle);
return error;
}
error = service_manager_add(&mesh_service_manifest, mesh_service_should_auto_start());
error = system_event_callback_add(KERNEL_EVENT_BOOT_COMPLETED, on_boot_completed, nullptr);
Comment thread
KenVanHoeylandt marked this conversation as resolved.
Resolved
if (error != ERROR_NONE) {
service_manager_remove(mesh_service_manifest.id);
app_manager_remove(mesh_command_manifest.id);
mutex_unlock(&lifecycle_mutex.handle);
return error;
}
module_active = true;
// A restart after boot misses the event
if (boot_completed) {
start_service_if_enabled();
}
return error;
mutex_unlock(&lifecycle_mutex.handle);
return ERROR_NONE;
}

static error_t stop() {
// Waits for a callback that is running, and makes one that is still pending do nothing
mutex_lock(&lifecycle_mutex.handle);
module_active = false;
error_t error = service_manager_stop(mesh_service_manifest.id);
if (error != ERROR_NONE && error != ERROR_NOT_FOUND) {
return error;
if (error == ERROR_NONE || error == ERROR_NOT_FOUND) {
error = service_manager_remove(mesh_service_manifest.id);
}
if (error == ERROR_NONE) {
error = app_manager_remove(mesh_command_manifest.id);
}
error = service_manager_remove(mesh_service_manifest.id);
if (error != ERROR_NONE) {
// The module stays started, so it keeps its callback and the service that may have been stopped runs again
module_active = true;
if (boot_completed) {
start_service_if_enabled();
}
mutex_unlock(&lifecycle_mutex.handle);
return error;
}
return app_manager_remove(mesh_command_manifest.id);
mutex_unlock(&lifecycle_mutex.handle);

system_event_callback_remove(KERNEL_EVENT_BOOT_COMPLETED, on_boot_completed);
return ERROR_NONE;
}

static const ModuleSymbol mesh_module_symbols[] = {
Expand Down
Loading
Loading