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
6 changes: 6 additions & 0 deletions Buildscripts/TactilitySDK/TactilitySDK.esp32.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ macro(tactility_project_post project_name)
idf_build_set_property(COMPILE_OPTIONS "-fno-omit-frame-pointer" APPEND)
endif()

# ESP-IDF's own <sys/ioctl.h> (esp_libc/platform_include) is found before app-module's, which adds
# the terminal ioctls (TIOCGWINSZ) Tactility's ioctl() supports for app fds.
# C and C++ only: assembly sources can't include a C header.
idf_build_set_property(C_COMPILE_OPTIONS "SHELL:-include ${TACTILITY_SDK_PATH}/Modules/app-module/include/sys/ioctl.h" APPEND)
idf_build_set_property(CXX_COMPILE_OPTIONS "SHELL:-include ${TACTILITY_SDK_PATH}/Modules/app-module/include/sys/ioctl.h" APPEND)

include("${TACTILITY_SDK_PATH}/Libraries/elf_loader/elf_loader.cmake")
project_elf($project_name)

Expand Down
6 changes: 6 additions & 0 deletions Buildscripts/TactilitySDK/TactilitySDK.posix.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ macro(tactility_project_post project_name)
${TACTILITY_SDK_PATH}/Libraries/FreeRTOS-Kernel/portable/ThirdParty/GCC/Posix/utils
)
target_compile_definitions(TactilitySDK INTERFACE LV_LVGL_H_INCLUDE_SIMPLE)
# An app's references to its own functions must bind to its own definitions, not to a same-named
# libc function already loaded in the Tactility process (e.g. an app shipping its own regcomp()).
# ESP32 apps get the same through -fvisibility=hidden. Mach-O binds within the image by default.
if (NOT APPLE)
target_link_options(TactilitySDK INTERFACE -Wl,-Bsymbolic)
endif ()

# ESP-IDF's project() auto-discovers the "main" component; plain CMake doesn't.
add_subdirectory(main)
Expand Down
9 changes: 8 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ if (DEFINED ENV{ESP_IDF_VERSION})
# Wraps newlib's reentrant syscall stubs, not the plain read()/write()/close() newlib itself.
# Implements as thin wrappers around them. newlib's own stdio (fflush()'s buffer-flush path in particular)
# calls these _r stubs directly, bypassing the plain names entirely.
# See Modules/app-module/source/stdio_wrap_esp32.cpp's own comment for the exact call chain.
# See Modules/app-esp32-module/source/stdio_wrap.cpp's own comment for the exact call chain.
idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=_read_r" APPEND)
idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=_write_r" APPEND)
idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=_close_r" APPEND)
Expand All @@ -82,6 +82,13 @@ if (DEFINED ENV{ESP_IDF_VERSION})
idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=tcgetattr" APPEND)
idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=tcsetattr" APPEND)

# elf_loader's full D-cache write-back must not run concurrently with a cache operation on the other core.
# See Modules/app-esp32-module/source/elf_cache.cpp.
idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=esp_elf_arch_flush" APPEND)

# elf_loader's Xtensa relocation drops GLOB_DAT/JMP_SLOT addends. See Modules/app-esp32-module/source/elf_relocate.cpp.
idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=esp_elf_arch_relocate" APPEND)

# exit() from an app ends only that app (see app_scheduler_exit_current()) instead of aborting.
idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=exit" APPEND)

Expand Down
12 changes: 6 additions & 6 deletions Devices/cl32/source/cl32_v2_keyboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,31 @@ static constexpr uint32_t KEYMAP_LC[80] = {
37, 49, 50, 51, 52, 53, 54, 55, 56, 0, // % 1 2 3 4 5 6 7 8
57, 48, 8, 91, 93, 43, 34, 39, 27, 0, // 9 0 BKSP [ ] + " ' EXIT
9, 113, 119, 101, 114, 116, 121, 117, 105, 0, // TAB q w e r t y u i
111, 112, 13, 40, 41, 45, 59, 58, 3, 0, // o p ENTER ( ) - ; : STOP
111, 112, 10, 40, 41, 45, 59, 58, 3, 0, // o p ENTER ( ) - ; : STOP
0, 97, 115, 100, 102, 103, 104, 106, 107, 0, // a s d f g h j k
108, 17, 35, 123, 125, 42, 44, 46, 2, 0, // l UP # { } * , . MENU
122, 120, 99, 118, 98, 32, 32, 110, 109, 0, // z x c v b n m
CODEPOINT_ARROW_LEFT, CODEPOINT_ARROW_DOWN, CODEPOINT_ARROW_RIGHT, 60, 62, 47, 92, 61, 13, 0, // LEFT DOWN RIGHT < > / \ = RUN
CODEPOINT_ARROW_LEFT, CODEPOINT_ARROW_DOWN, CODEPOINT_ARROW_RIGHT, 60, 62, 47, 92, 61, 10, 0, // LEFT DOWN RIGHT < > / \ = RUN
};
static constexpr uint32_t KEYMAP_UC[80] = {
37, 49, 50, 51, 52, 53, 54, 55, 56, 0, // % 1 2 3 4 5 6 7 8
57, 48, 8, 91, 93, 43, 34, 39, 27, 0, // 9 0 BKSP [ ] + " ' EXIT
9, 81, 87, 69, 82, 84, 89, 85, 73, 0, // TAB Q W E R T Y U I
79, 80, 13, 40, 41, 45, 59, 58, 3, 0, // O P ENTER ( ) - ; : STOP
79, 80, 10, 40, 41, 45, 59, 58, 3, 0, // O P ENTER ( ) - ; : STOP
0, 65, 83, 68, 70, 71, 72, 74, 75, 0, // A S D F G H J K
76, 17, 35, 123, 125, 42, 44, 46, 2, 0, // L UP # { } * , . MENU
90, 88, 67, 86, 66, 32, 32, 78, 77, 0, // Z X C V B N M
CODEPOINT_ARROW_LEFT, CODEPOINT_ARROW_DOWN, CODEPOINT_ARROW_RIGHT, 60, 62, 47, 92, 61, 13, 0, // LEFT DOWN RIGHT < > / \ = RUN
CODEPOINT_ARROW_LEFT, CODEPOINT_ARROW_DOWN, CODEPOINT_ARROW_RIGHT, 60, 62, 47, 92, 61, 10, 0, // LEFT DOWN RIGHT < > / \ = RUN
};
static constexpr uint32_t KEYMAP_SY[80] = {
37, 49, 50, 51, 52, 53, 54, 55, 56, 0, // % 1 2 3 4 5 6 7 8
57, 48, 8, 91, 93, 43, 34, 39, 27, 0, // 9 0 BKSP [ ] + " ' EXIT
9, 113, 119, 101, 114, 116, 121, 117, 105, 0, // TAB q w e r t y u i
111, 112, 13, 40, 41, 45, 59, 58, 3, 0, // o p ENTER ( ) - ; : STOP
111, 112, 10, 40, 41, 45, 59, 58, 3, 0, // o p ENTER ( ) - ; : STOP
0, 97, 115, 100, 102, 103, 104, 106, 107, 0, // a s d f g h j k
108, 17, 35, 123, 125, 42, 44, 46, 2, 0, // l UP # { } * , . MENU
122, 120, 99, 118, 98, 32, 32, 110, 109, 0, // z x c v b n m
CODEPOINT_ARROW_LEFT, CODEPOINT_ARROW_DOWN, CODEPOINT_ARROW_RIGHT, 60, 62, 47, 92, 61, 13, 0, // LEFT DOWN RIGHT < > / \ = RUN
CODEPOINT_ARROW_LEFT, CODEPOINT_ARROW_DOWN, CODEPOINT_ARROW_RIGHT, 60, 62, 47, 92, 61, 10, 0, // LEFT DOWN RIGHT < > / \ = RUN
};

static Tca8418Config cl32_keyboard_config {};
Expand Down
6 changes: 3 additions & 3 deletions Devices/lilygo-tdeck-max/lilygo,tdeck-max.dts
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,19 @@
keymap-lc = [
113 119 101 114 116 121 117 105 111 112 // q w e r t y u i o p
97 115 100 102 103 104 106 107 108 8 // a s d f g h j k l BACKSPACE
0 122 120 99 118 98 110 109 36 13 // z x c v b n m $ ENTER
0 122 120 99 118 98 110 109 36 10 // z x c v b n m $ ENTER
0 0 0 0 0 11 48 32 0 9 // PREV 0 SPC NEXT
];
keymap-uc = [
81 87 69 82 84 89 85 73 79 80 // Q W E R T Y U I O P
65 83 68 70 71 72 74 75 76 8 // A S D F G H J K L BACKSPACE
0 90 88 67 86 66 78 77 36 13 // Z X C V B N M $ ENTER
0 90 88 67 86 66 78 77 36 10 // Z X C V B N M $ ENTER
0 0 0 0 0 11 48 32 0 9 // PREV 0 SPC NEXT
];
keymap-sy = [
49 50 51 52 53 54 55 56 57 48 // 1 2 3 4 5 6 7 8 9 0
64 35 43 45 42 47 40 41 95 8 // @ # + - * / ( ) _ BACKSPACE
0 33 63 59 58 39 34 44 46 13 // ! ? ; : ' " , . ENTER
0 33 63 59 58 39 34 44 46 10 // ! ? ; : ' " , . ENTER
0 0 0 0 0 11 48 32 0 9 // PREV 0 SPC NEXT
];
shift-row = <2>;
Expand Down
6 changes: 3 additions & 3 deletions Devices/lilygo-tdeck-pro/lilygo,tdeck-pro.dts
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,19 @@
keymap-lc = [
113 119 101 114 116 121 117 105 111 112 // q w e r t y u i o p
97 115 100 102 103 104 106 107 108 8 // a s d f g h j k l BACKSPACE
0 122 120 99 118 98 110 109 36 13 // z x c v b n m $ ENTER
0 122 120 99 118 98 110 109 36 10 // z x c v b n m $ ENTER
0 0 0 0 0 11 48 32 0 9 // PREV 0 SPC NEXT
];
keymap-uc = [
81 87 69 82 84 89 85 73 79 80 // Q W E R T Y U I O P
65 83 68 70 71 72 74 75 76 8 // A S D F G H J K L BACKSPACE
0 90 88 67 86 66 78 77 36 13 // Z X C V B N M $ ENTER
0 90 88 67 86 66 78 77 36 10 // Z X C V B N M $ ENTER
0 0 0 0 0 11 48 32 0 9 // PREV 0 SPC NEXT
];
keymap-sy = [
49 50 51 52 53 54 55 56 57 48 // 1 2 3 4 5 6 7 8 9 0
64 35 43 45 42 47 40 41 95 8 // @ # + - * / ( ) _ BACKSPACE
0 33 63 59 58 39 34 44 46 13 // ! ? ; : ' " , . ENTER
0 33 63 59 58 39 34 44 46 10 // ! ? ; : ' " , . ENTER
0 0 0 0 0 11 48 32 0 9 // PREV 0 SPC NEXT
];
shift-row = <2>;
Expand Down
7 changes: 0 additions & 7 deletions Devices/lilygo-tlora-pager/CMakeLists.txt

This file was deleted.

1 change: 1 addition & 0 deletions Devices/lilygo-tlora-pager/device.properties
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ display.dpi=227

lvgl.colorDepth=16
lvgl.dpi=150
lvgl.uiDensity=compact
8 changes: 4 additions & 4 deletions Devices/lilygo-tlora-pager/lilygo,tlora-pager.dts
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,21 @@
columns = <10>;
keymap-lc = [
113 119 101 114 116 121 117 105 111 112 // q w e r t y u i o p
97 115 100 102 103 104 106 107 108 13 // a s d f g h j k l ENTER
97 115 100 102 103 104 106 107 108 10 // a s d f g h j k l ENTER
0 122 120 99 118 98 110 109 0 8 // z x c v b n m BACKSPACE
32 0 0 0 0 0 0 0 0 0 // SPC
];
keymap-uc = [
81 87 69 82 84 89 85 73 79 80 // Q W E R T Y U I O P
65 83 68 70 71 72 74 75 76 13 // A S D F G H J K L ENTER
65 83 68 70 71 72 74 75 76 10 // A S D F G H J K L ENTER
0 90 88 67 86 66 78 77 0 8 // Z X C V B N M BACKSPACE
32 0 0 0 0 0 0 0 0 0 // SPC
];
keymap-sy = [
49 50 51 52 53 54 55 56 57 48 // 1 2 3 4 5 6 7 8 9 0
46 47 43 45 61 58 39 34 64 9 // . / + - = : ' " @ TAB
46 47 43 45 61 58 39 34 64 27 // . / + - = : ' " @ ESC
0 95 36 59 63 33 44 46 0 8 // _ $ ; ? ! , . BACKSPACE
32 0 0 0 0 0 0 0 0 0 // SPC
9 0 0 0 0 0 0 0 0 0 // TAB
];
shift-row = <2>;
shift-col = <8>;
Expand Down
1 change: 1 addition & 0 deletions Devices/lilygo-tlora-pager/module.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ dependencies:
- Drivers/drv2605-module
- Drivers/gpio-encoder-module
dts: lilygo,tlora-pager.dts
dts-only: true
35 changes: 0 additions & 35 deletions Devices/lilygo-tlora-pager/source/module.cpp

This file was deleted.

3 changes: 2 additions & 1 deletion Documentation/ideas.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
- CrashDiagnostics shouldn't show a QR when there's no callstack
- Move USB host task stacks to SPIRAM when available: esp32_usbhost*.cpp
- Add bold fonts for e-ink readability improvement
- Improve Setup: Add keyboard/keypad navigation explanation
- Improve Setup: Add keyboard/keypad/encoder navigation explanation.
e.g. encoder long press on t-lora pager to get out of textarea
- Drivers/audio-codec-module is not a module. Move it somewhere else. Or make it an actual module.
- Improve SPI kernel driver (implement read, write, transactions)
- TCA9534 keyboards should use interrupts
Expand Down
2 changes: 1 addition & 1 deletion Drivers/m5stack-module/source/cardputer_keyboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ static const CardputerKeyDef cardputer_key_map[CARDPUTER_ROWS][CARDPUTER_COLS] =
{ K('\t', '\t'), K('q', 'Q'), K('w', 'W'), K('e', 'E'), K('r', 'R'), K('t', 'T'), K('y', 'Y'),
K('u', 'U'), K('i', 'I'), K('o', 'O'), K('p', 'P'), K('[', '{'), K(']', '}'), K('\\', '|') },
{ { CARDPUTER_KEY_FN, 0, 0 }, { CARDPUTER_KEY_SHIFT, 0, 0 }, K('a', 'A'), K('s', 'S'), K('d', 'D'), K('f', 'F'), K('g', 'G'),
K('h', 'H'), K('j', 'J'), K('k', 'K'), K('l', 'L'), K(';', ':'), K('\'', '"'), K('\r', '\r') },
K('h', 'H'), K('j', 'J'), K('k', 'K'), K('l', 'L'), K(';', ':'), K('\'', '"'), K('\n', '\n') },
{ { CARDPUTER_KEY_CTRL, 0, 0 }, { CARDPUTER_KEY_OPT, 0, 0 }, { CARDPUTER_KEY_ALT, 0, 0 }, K('z', 'Z'), K('x', 'X'), K('c', 'C'), K('v', 'V'),
K('b', 'B'), K('n', 'N'), K('m', 'M'), K(',', '<'), K('.', '>'), K('/', '?'), K(' ', ' ') },
};
Expand Down
2 changes: 2 additions & 0 deletions Modules/app-esp32-module/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ tactility_add_module(app-esp32-module
SRCS ${SOURCE_FILES}
INCLUDE_DIRS include/
REQUIRES TactilityKernel app-module service-module elf_loader
# The libc wraps in source/stdio_wrap.cpp are only reached through -Wl,--wrap=, never by direct reference
WHOLE_ARCHIVE
)
4 changes: 4 additions & 0 deletions Modules/app-esp32-module/source/app_esp32_loader_service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ error_t api_load(AppLocation location, AppRuntime* out_runtime) {
return ERROR_RESOURCE;
}

// Relocation copied everything it needs (segments, symbol names) out of the file buffer
free(runtime->file_data);
runtime->file_data = nullptr;

*out_runtime = runtime;
return ERROR_NONE;
}
Expand Down
70 changes: 70 additions & 0 deletions Modules/app-esp32-module/source/elf_cache.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// SPDX-License-Identifier: Apache-2.0
#include <sdkconfig.h>

#ifdef CONFIG_ELF_LOADER_LOAD_PSRAM

#include <esp_ipc.h>
#include <freertos/FreeRTOS.h>

#include <atomic>

// elf_loader writes back the whole D-cache with the ROM's Cache_WriteBack_All(), which doesn't take
// esp_cache_msync()'s lock. A cache operation running at the same time on the other core (e.g. a display
// driver syncing a PSRAM framebuffer) then fails with "Dcache sync parameter configuration error".
// The write-back therefore runs in core 0's IPC task while core 1 is parked in its own IPC task. An IPC task
// only runs when its core is not in a critical section, which is where esp_cache_msync() does its work.
extern "C" {

void __real_esp_elf_arch_flush(void);
void Cache_WriteBack_All(void);
void spi_flash_disable_interrupts_caches_and_other_cpu(void);
void spi_flash_enable_interrupts_caches_and_other_cpu(void);

}

#if !CONFIG_FREERTOS_UNICORE && !CONFIG_IDF_TARGET_ESP32S31

namespace {

std::atomic<bool> other_core_parked { false };
std::atomic<bool> other_core_release { false };

void IRAM_ATTR park_core(void*) {
const uint32_t state = portSET_INTERRUPT_MASK_FROM_ISR();
other_core_parked.store(true, std::memory_order_release);
while (!other_core_release.load(std::memory_order_acquire)) {
}
portCLEAR_INTERRUPT_MASK_FROM_ISR(state);
}

void IRAM_ATTR write_back_with_core1_parked(void*) {
other_core_parked.store(false, std::memory_order_relaxed);
other_core_release.store(false, std::memory_order_relaxed);
esp_ipc_call(1, park_core, nullptr);
while (!other_core_parked.load(std::memory_order_acquire)) {
}
const uint32_t state = portSET_INTERRUPT_MASK_FROM_ISR();
Cache_WriteBack_All();
portCLEAR_INTERRUPT_MASK_FROM_ISR(state);
other_core_release.store(true, std::memory_order_release);
}

} // namespace

// IRAM: spi_flash_disable_interrupts_caches_and_other_cpu() returns here with the caches disabled
extern "C" void IRAM_ATTR __wrap_esp_elf_arch_flush(void) {
esp_ipc_call_blocking(0, write_back_with_core1_parked, nullptr);
// Same as elf_loader's own esp_elf_arch_flush() after its write-back
spi_flash_disable_interrupts_caches_and_other_cpu();
spi_flash_enable_interrupts_caches_and_other_cpu();
}

#else

extern "C" void IRAM_ATTR __wrap_esp_elf_arch_flush(void) {
__real_esp_elf_arch_flush();
}

#endif

#endif // CONFIG_ELF_LOADER_LOAD_PSRAM
27 changes: 27 additions & 0 deletions Modules/app-esp32-module/source/elf_relocate.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: Apache-2.0
#include <sdkconfig.h>

#include <esp_elf.h>
#include <private/elf_platform.h>

// elf_loader's Xtensa relocation ignores the addend of R_XTENSA_GLOB_DAT/R_XTENSA_JMP_SLOT, which is
// S + A per the ABI. The compiler does emit addends there: newlib's ctype macros read (_ctype_ + 1)[c],
// which becomes "R_XTENSA_GLOB_DAT _ctype_ + 1". Without the addend every ctype lookup in an app reads
// the previous character's entry (e.g. isspace('!') is true).
extern "C" {

int __real_esp_elf_arch_relocate(esp_elf_t* elf, const elf32_rela_t* rela, const elf32_sym_t* sym, uint32_t addr);

int __wrap_esp_elf_arch_relocate(esp_elf_t* elf, const elf32_rela_t* rela, const elf32_sym_t* sym, uint32_t addr) {
#if CONFIG_IDF_TARGET_ARCH_XTENSA
constexpr uint32_t R_XTENSA_GLOB_DAT = 3;
constexpr uint32_t R_XTENSA_JMP_SLOT = 4;
const uint32_t type = ELF_R_TYPE(rela->info);
if (type == R_XTENSA_GLOB_DAT || type == R_XTENSA_JMP_SLOT) {
addr += rela->addend;
}
#endif
return __real_esp_elf_arch_relocate(elf, rela, sym, addr);
}

}
Loading
Loading