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
29 changes: 11 additions & 18 deletions Buildscripts/logo.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ get_filename_component(VERSION_TEXT_FILE version.txt ABSOLUTE)
file(READ ${VERSION_TEXT_FILE} TACTILITY_VERSION)

if (DEFINED ENV{ESP_IDF_VERSION})
set(TACTILITY_TARGET " @ ESP-IDF")
set(TACTILITY_TARGET "ESP-IDF")
else ()
set(TACTILITY_TARGET " @ Simulator")
set(TACTILITY_TARGET "Simulator")
endif ()

string(ASCII 27 Esc)
Expand All @@ -18,19 +18,12 @@ set(White "${Esc}[1;37m")
# Some terminals (e.g. GitHub Actions) reset colour for every in a multiline message(),
# so we add the colour to each line instead of assuming it would automatically be re-used.
message("\n\n\
${LightPurple}@@\n\
${LightPurple}@@@\n\
${LightPurple}@@@\n\
${LightPurple}@@@\n\
${LightPurple}@@@\n\
${Cyan}@@@@@@@@@@@@@@@@${LightPurple}@@@\n\
${Cyan}@@@@@@@@@@@@@@@@@${LightPurple}@@@\n\
${Cyan}@@@ ${LightPurple}@@@ ${White}Tactility ${TACTILITY_VERSION}\n\
${Cyan}@@@ ${LightPurple}@@@ ${Grey}${TACTILITY_TARGET}\n\
${Cyan}@@@${LightPurple}@@@@@@@@@@@@@@@@@\n\
${Cyan}@@@${LightPurple}@@@@@@@@@@@@@@@@\n\
${Cyan}@@@\n\
${Cyan}@@@\n\
${Cyan}@@@\n\
${Cyan}@@@\n\
${Cyan}@@\n\n${ColorReset}")
${LightPurple}▙\n\
${LightPurple}█\n\
${LightPurple}█\n\
${Cyan}▂▄▄▄▄▄▄▄▄▄${LightPurple}█\n\
${Cyan}█ ${LightPurple}█ ${White}Tactility ${Cyan}${TACTILITY_VERSION}${Grey} with ${Cyan}${TACTILITY_TARGET}\n\
${Cyan}█${LightPurple}▀▀▀▀▀▀▀▀▀🮂\n\
${Cyan}█\n\
${Cyan}█\n\
${Cyan}▜${ColorReset}\n")
2 changes: 1 addition & 1 deletion Devices/cl32-v04/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ file(GLOB_RECURSE SOURCE_FILES source/*.c*)
idf_component_register(
SRCS ${SOURCE_FILES}
INCLUDE_DIRS "source"
REQUIRES TactilityKernel
REQUIRES TactilityKernel platform-esp32 ssd16xx-module st7305-module driver
)
13 changes: 2 additions & 11 deletions Devices/cl32-v04/cl32-v04.dts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
#include <bindings/cl32_v4_light.h>
#include <bindings/cl32_v4_keyboard.h>
#include <bindings/cl32_v4_power.h>
#include <bindings/st7305.h>
#include <bindings/sx1262.h>

/ {
Expand Down Expand Up @@ -93,6 +92,8 @@
i2cClockFrequency = <100000>;
};

// The display is either an ST7305 reflective LCD or an SSD16xx e-paper panel. It is created
// dynamically based on hardware detection, see cl32_v4_display.cpp.
spi1 {
compatible = "espressif,esp32-spi";
host = <SPI2_HOST>;
Expand All @@ -107,16 +108,6 @@
compatible = "espressif,esp32-sdspi";
frequency-khz = <20000>;
};

display@1 {
compatible = "sitronix,st7305";
pin-dc = <&gpio0 13 GPIO_FLAG_NONE>;
pin-reset = <&gpio0 12 GPIO_FLAG_NONE>;
pixel-clock-hz = <80000000>;
mirror-x;
mirror-y;
backlight = <&back_light>;
};
};

// Optional Mesh Card with a Seeed Wio-SX1262 module, detected at runtime.
Expand Down
2 changes: 1 addition & 1 deletion Devices/cl32-v04/device.properties
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ lvgl.colorDepth=8
lvgl.theme=Mono
lvgl.uiDensity=compact

cdn.infoMessage=This variant supports hardware revision v0.4 with the reflective LCD.
cdn.infoMessage=This variant supports hardware revision v0.4 with the reflective LCD or e-paper display.
1 change: 1 addition & 0 deletions Devices/cl32-v04/module.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
dependencies:
- Platforms/platform-esp32
- Drivers/bm8563-module
- Drivers/ssd16xx-module
- Drivers/st7305-module
- Drivers/sx126x-module
bindings: bindings
Expand Down
223 changes: 223 additions & 0 deletions Devices/cl32-v04/source/cl32_v4_display.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
// SPDX-License-Identifier: Apache-2.0
#include "cl32_v4_display.h"

#include <drivers/ssd16xx.h>
#include <drivers/st7305.h>

#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/device_listener.h>
#include <tactility/drivers/esp32_spi.h>
#include <tactility/drivers/spi_controller.h>
#include <tactility/log.h>

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

#include <cstring>

constexpr auto* TAG = "cl32-v4-display";

constexpr gpio_num_t PIN_CS = GPIO_NUM_6;
constexpr gpio_num_t PIN_RESET = GPIO_NUM_12;
constexpr gpio_num_t PIN_DC = GPIO_NUM_13;
constexpr gpio_num_t PIN_BUSY = GPIO_NUM_14;
constexpr uint32_t DISPLAY_CS_INDEX = 1;

static St7305Config st7305_config {};
static Ssd16xxConfig ssd16xx_config {};
static Device display_device {};
Comment thread
KenVanHoeylandt marked this conversation as resolved.
Resolved
static bool display_created = false;

// The probe-once latch for on_spi1_started(). File-scope so the teardown can reset it for a later start/probe cycle.
static bool did_probe = false;

static void send_command(spi_device_handle_t spi, uint8_t command) {
spi_transaction_t transaction = {};
transaction.flags = SPI_TRANS_USE_TXDATA;
transaction.length = 8;
transaction.tx_data[0] = command;
gpio_set_level(PIN_CS, 0);
gpio_set_level(PIN_DC, 0);
spi_device_polling_transmit(spi, &transaction);
gpio_set_level(PIN_CS, 1);
}

static bool wait_for_busy_high(TickType_t timeout) {
const TickType_t start = xTaskGetTickCount();
while (xTaskGetTickCount() - start <= timeout) {
if (gpio_get_level(PIN_BUSY)) {
return true;
}
vTaskDelay(1);
}
return false;
}

// Only the SSD16xx drives the BUSY line: it goes high during the software reset.
// The pin is pulled down so it stays low when an ST7305 is connected.
static bool detect_ssd16xx(Device* spi1) {
const auto* spi_config = static_cast<const Esp32SpiConfig*>(spi1->config);

spi_device_interface_config_t device_config = {};
device_config.clock_speed_hz = 4000000;
device_config.mode = 0;
device_config.spics_io_num = -1;
device_config.queue_size = 1;
spi_device_handle_t spi;
if (spi_bus_add_device(spi_config->host, &device_config, &spi) != ESP_OK) {
LOG_E(TAG, "Failed to add SPI device for detection");
return false;
}
Comment thread
KenVanHoeylandt marked this conversation as resolved.
Resolved

gpio_config_t outputs = {
.pin_bit_mask = (1ULL << PIN_CS) | (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,
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_ENABLE,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&input);

gpio_set_level(PIN_RESET, 0);
vTaskDelay(pdMS_TO_TICKS(10));
gpio_set_level(PIN_RESET, 1);
vTaskDelay(pdMS_TO_TICKS(10));

spi_controller_lock(spi1);
send_command(spi, 0x12);
const bool busy = wait_for_busy_high(pdMS_TO_TICKS(20));
spi_controller_unlock(spi1);

spi_bus_remove_device(spi);
gpio_reset_pin(PIN_BUSY);
return busy;
}

static bool create_display(Device* spi1, bool is_ssd16xx) {
Device* gpio0 = nullptr;
if (device_get_by_name("gpio0", &gpio0) != ERROR_NONE) {
LOG_E(TAG, "gpio0 not found");
return false;
}

const char* compatible;
void* config;
if (is_ssd16xx) {
ssd16xx_config = Ssd16xxConfig {
.pin_dc = { gpio0, PIN_DC, GPIO_FLAG_NONE },
.pin_reset = { gpio0, PIN_RESET, GPIO_FLAG_NONE },
.pin_busy = { gpio0, PIN_BUSY, GPIO_FLAG_NONE },
.pin_cs = { gpio0, PIN_CS, GPIO_FLAG_NONE },
.clock_speed_hz = 4000000,
.panel_type = "gdey029t71h",
.rotation = 1,
};
compatible = "solomon-systech,ssd16xx";
config = &ssd16xx_config;
} else {
Device* backlight = nullptr;
if (device_get_by_name("back_light", &backlight) != ERROR_NONE) {
LOG_W(TAG, "back_light not found");
}
st7305_config = St7305Config {
.horizontal_resolution = 384,
.vertical_resolution = 168,
.column_offset = 23,
.mirror_x = true,
.mirror_y = true,
.invert_color = false,
.pixel_clock_hz = 80000000,
.pin_dc = { gpio0, PIN_DC, GPIO_FLAG_NONE },
.pin_reset = { gpio0, PIN_RESET, GPIO_FLAG_NONE },
.backlight = backlight,
};
compatible = "sitronix,st7305";
config = &st7305_config;
}

display_device = Device {
.address = DISPLAY_CS_INDEX,
.name = "display",
.config = config,
.parent = nullptr,
.flags = 0,
.internal = nullptr,
};

error_t error = device_construct(&display_device);
if (error != ERROR_NONE) {
LOG_E(TAG, "Failed to construct display: %s", error_to_string(error));
return false;
}

device_set_parent(&display_device, spi1);

Driver* driver = driver_find_compatible(compatible);
if (driver == nullptr) {
LOG_E(TAG, "No driver registered for %s", compatible);
device_destruct(&display_device);
return false;
}
device_set_driver(&display_device, driver);

error = device_add(&display_device);
if (error != ERROR_NONE) {
LOG_E(TAG, "Failed to add display: %s", error_to_string(error));
device_destruct(&display_device);
return false;
}

error = device_start(&display_device);
if (error != ERROR_NONE) {
LOG_E(TAG, "Failed to start display: %s", error_to_string(error));
device_remove(&display_device);
device_destruct(&display_device);
return false;
}

display_created = true;
return true;
}

// Fires for every device's start/stop in the system.
static void on_spi1_started(Device* device, DeviceEvent event, void* context) {
(void)context;

if (did_probe || event != DEVICE_EVENT_STARTED || strcmp(device->name, "spi1") != 0) {
return;
}
did_probe = true;

const bool is_ssd16xx = detect_ssd16xx(device);
LOG_I(TAG, "Detected %s display", is_ssd16xx ? "SSD16xx e-paper" : "ST7305 LCD");
create_display(device, is_ssd16xx);
}

void cl32_v4_display_detect_start() {
device_listener_add(on_spi1_started, nullptr);
}

void cl32_v4_display_detect_stop() {
device_listener_remove(on_spi1_started, nullptr);
}

void cl32_v4_display_teardown() {
if (display_created) {
device_stop(&display_device);
device_remove(&display_device);
device_destruct(&display_device);
display_created = false;
Comment thread
KenVanHoeylandt marked this conversation as resolved.
Resolved
}
did_probe = false;
}
7 changes: 7 additions & 0 deletions Devices/cl32-v04/source/cl32_v4_display.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once

void cl32_v4_display_detect_start();
void cl32_v4_display_detect_stop();

/** Stops, removes and destructs the detected display device. */
void cl32_v4_display_teardown();
16 changes: 14 additions & 2 deletions Devices/cl32-v04/source/module.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
#include <tactility/module.h>

#include "cl32_v4_display.h"
#include "cl32_v4_light.h"
#include "cl32_v4_keyboard.h"
#include "cl32_v4_power.h"

extern "C" {

static error_t start() {
cl32_v4_display_detect_start();
return ERROR_NONE;
}

static error_t stop() {
cl32_v4_display_detect_stop();
cl32_v4_display_teardown();
return ERROR_NONE;
}

static Driver* const cl32_drivers[] = {
&cl32_v4_power_driver,
&cl32_v4_power_supply_driver,
Expand All @@ -16,8 +28,8 @@ static Driver* const cl32_drivers[] = {

Module cl32_v04_module = {
.name = "cl32",
.start = nullptr,
.stop = nullptr,
.start = start,
.stop = stop,
.drivers = cl32_drivers,
.symbols = nullptr,
.internal = nullptr
Expand Down
8 changes: 2 additions & 6 deletions Documentation/ideas.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

## Higher Priority

- Fix system icon selection on mono display
- Find out why the first build of an app with a clean build cache folder always fails
- Improve posix support: use user home path and system /tmp folder.
- Drivers/audio-codec-module is not a module. Move it somewhere else. Or make it an actual module.
Expand All @@ -19,16 +20,12 @@

## Medium Priority

- 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.
- Try https://github.com/bootdsc/Fastwave-Eink-Driver with CL-32 e-paper.
- Power Off with e-paper should trigger full refresh before power off.
- Inspect code for memory improvements: replace `std::*` with `tt::std::*`
- Tactility/Source/bluetooth move into bluetooth module, make it work generically for all bluetooth apis
- DisplayApi: resolution x/y shouldn't be functions but struct values
- Tactility/Source/app/imageviewer/ImageViewer.cpp: Limit memory used to open an image.
loadFile() now resizes fileData to the entire file size before displaying the image. start accepts a file path without a size limit, so opening a large image can exhaust memory on an embedded device before LVGL decodes it. Reject files above a supported limit or retain a bounded file-backed decoding path.
- A device profile selection screen for Simulator: select device profiles such as T-Lora Pager, T-Deck Plus, CL-32, Cardputer and T-Embed which changes the resolution and theming defaults after restarting.
- A fullscreen tiny keyboard that works with single stroke gestures (similar to Palm OS Graffiti)
- Move more window management code from Tactility/ to window-manager
- Implement signal/raise for terminal apps (for CTRL+C and window resize signals)
Expand All @@ -47,7 +44,6 @@
Create some kind of "intent" handler like on Android.
The intent can have an action (e.g. view), a URL and an optional bundle.
The manifest can provide the intent handler
- LilyGO T-Dongle S3: 1 button control, stop auto-launching web server
- Core2: support power off via software
- Try out speed optimizations: https://docs.espressif.com/projects/esp-faq/en/latest/software-framework/peripherals/lcd.html
(relates to CONFIG_ESP32S3_DATA_CACHE_LINE_64B that is in use for RGB displays via the `device.properties` fix/workaround)
Expand Down
Loading
Loading