Implement M5Stack Cardputer + minor Tactility improvements (#331)

- Implement M5Stack Cardputer: display, SD card and keyboard
- `St7789Display` now supports a "gap" configuration
- `ElfApp` has improved errors
This commit is contained in:
Ken Van Hoeylandt 2025-09-14 02:25:10 +02:00 committed by GitHub
parent d83b98e99b
commit 62c613477a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 1385 additions and 5 deletions

View File

@ -153,6 +153,15 @@ jobs:
with:
board_id: lilygo-tlora-pager
arch: esp32s3
m5stack-cardputer:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: "Build"
uses: ./.github/actions/build-firmware
with:
board_id: m5stack-cardputer
arch: esp32s3
m5stack-core2:
runs-on: ubuntu-latest
steps:

View File

@ -43,6 +43,8 @@ menu "Tactility App"
bool "LilyGo T-Deck"
config TT_BOARD_LILYGO_TLORA_PAGER
bool "LilyGo T-Lora Pager"
config TT_BOARD_M5STACK_CARDPUTER
bool "M5Stack Cardputer"
config TT_BOARD_M5STACK_CORE2
bool "M5Stack Core2"
config TT_BOARD_M5STACK_CORES3

View File

@ -41,6 +41,9 @@
#elif (defined(CONFIG_TT_BOARD_ELECROW_CROWPANEL_BASIC_50))
#define TT_BOARD_HARDWARE &crowpanel_basic_50
#include "CrowPanelBasic50.h"
#elif defined(CONFIG_TT_BOARD_M5STACK_CARDPUTER)
#include "M5stackCardputer.h"
#define TT_BOARD_HARDWARE &m5stack_cardputer
#elif defined(CONFIG_TT_BOARD_M5STACK_CORE2)
#include "M5stackCore2.h"
#define TT_BOARD_HARDWARE &m5stack_core2

View File

@ -0,0 +1,7 @@
file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
idf_component_register(
SRCS ${SOURCE_FILES}
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port esp_lcd ST7789 PwmBacklight driver vfs fatfs
)

View File

@ -0,0 +1,10 @@
#include <PwmBacklight.h>
#include <Tactility/Log.h>
constexpr auto* TAG = "Cardputer";
bool initBoot() {
TT_LOG_I(TAG, "initBoot");
return driver::pwmbacklight::init(GPIO_NUM_38, 256);
}

View File

@ -0,0 +1,3 @@
#pragma once
bool initBoot();

View File

@ -0,0 +1,123 @@
#include "M5stackCardputer.h"
#include "InitBoot.h"
#include "devices/Display.h"
#include "devices/SdCard.h"
#include "devices/CardputerEncoder.h"
#include "devices/CardputerKeyboard.h"
#include <lvgl.h>
#include <Tactility/lvgl/LvglSync.h>
#define SPI_TRANSFER_SIZE_LIMIT (LCD_DRAW_BUFFER_SIZE * LV_COLOR_DEPTH / 8)
using namespace tt::hal;
static DeviceVector createDevices() {
return {
createSdCard(),
createDisplay(),
std::make_shared<CardputerKeyboard>(),
std::make_shared<CardputerEncoder>()
};
}
extern const Configuration m5stack_cardputer = {
.initBoot = initBoot,
.createDevices = createDevices,
.i2c = {
// Only available on Cardputer Adv (enabling it breaks the keyboard on a Cardputer v1.1)
i2c::Configuration {
.name = "Internal",
.port = I2C_NUM_0,
.initMode = i2c::InitMode::Disabled,
.isMutable = true,
.config = (i2c_config_t) {
.mode = I2C_MODE_MASTER,
.sda_io_num = GPIO_NUM_8,
.scl_io_num = GPIO_NUM_9,
.sda_pullup_en = true,
.scl_pullup_en = true,
.master = {
.clk_speed = 400000
},
.clk_flags = 0
}
}
},
.spi {
// Display
spi::Configuration {
.device = SPI2_HOST,
.dma = SPI_DMA_CH_AUTO,
.config = {
.mosi_io_num = GPIO_NUM_35,
.miso_io_num = GPIO_NUM_NC,
.sclk_io_num = GPIO_NUM_36,
.quadwp_io_num = GPIO_NUM_NC,
.quadhd_io_num = GPIO_NUM_NC,
.data4_io_num = GPIO_NUM_NC,
.data5_io_num = GPIO_NUM_NC,
.data6_io_num = GPIO_NUM_NC,
.data7_io_num = GPIO_NUM_NC,
.data_io_default_level = false,
.max_transfer_sz = SPI_TRANSFER_SIZE_LIMIT,
.flags = 0,
.isr_cpu_id = ESP_INTR_CPU_AFFINITY_AUTO,
.intr_flags = 0
},
.initMode = spi::InitMode::ByTactility,
.isMutable = false,
.lock = tt::lvgl::getSyncLock()
},
// SDCard
spi::Configuration {
.device = SPI3_HOST,
.dma = SPI_DMA_CH_AUTO,
.config = {
.mosi_io_num = GPIO_NUM_14,
.miso_io_num = GPIO_NUM_39,
.sclk_io_num = GPIO_NUM_40,
.quadwp_io_num = GPIO_NUM_NC,
.quadhd_io_num = GPIO_NUM_NC,
.data4_io_num = GPIO_NUM_NC,
.data5_io_num = GPIO_NUM_NC,
.data6_io_num = GPIO_NUM_NC,
.data7_io_num = GPIO_NUM_NC,
.data_io_default_level = false,
.max_transfer_sz = 0,
.flags = 0,
.isr_cpu_id = ESP_INTR_CPU_AFFINITY_AUTO,
.intr_flags = 0
},
.initMode = spi::InitMode::ByTactility,
.isMutable = false,
.lock = nullptr
},
},
.uart {
uart::Configuration {
.name = "Grove",
.port = UART_NUM_1,
.rxPin = GPIO_NUM_32,
.txPin = GPIO_NUM_33,
.rtsPin = GPIO_NUM_NC,
.ctsPin = GPIO_NUM_NC,
.rxBufferSize = 1024,
.txBufferSize = 1024,
.config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.rx_flow_ctrl_thresh = 0,
.source_clk = UART_SCLK_DEFAULT,
.flags = {
.allow_pd = 0,
.backup_before_sleep = 0,
}
}
},
}
};

View File

@ -0,0 +1,5 @@
#pragma once
#include <Tactility/hal/Configuration.h>
extern const tt::hal::Configuration m5stack_cardputer;

View File

@ -0,0 +1,54 @@
#include "CardputerEncoder.h"
void CardputerEncoder::readCallback(lv_indev_t* indev, lv_indev_data_t* data) {
CardputerEncoder* self = static_cast<CardputerEncoder*>(lv_indev_get_user_data(indev));
self->keyboard.updateKeyList();
data->state = LV_INDEV_STATE_RELEASED;
if (self->keyboard.keyList().size() != self->lastKeyNum) {
// If key pressed
if (self->keyboard.keyList().size() != 0) {
// Update states and values
self->keyboard.updateKeysState();
if (self->keyboard.keysState().fn) {
if (self->keyboard.keysState().enter) {
data->key = LV_KEY_ENTER;
data->state = LV_INDEV_STATE_PRESSED;
} else {
for (auto& i : self->keyboard.keysState().values) {
if (i == ';') { // Up
data->enc_diff = -1;
} else if (i == '.') { // Down
data->enc_diff = 1;
}
break; // We only care about the first value
}
}
}
self->lastKeyNum = self->keyboard.keyList().size();
} else {
self->lastKeyNum = 0;
}
}
}
bool CardputerEncoder::startLvgl(lv_display_t* display) {
keyboard.init();
lvglDevice = lv_indev_create();
lv_indev_set_type(lvglDevice, LV_INDEV_TYPE_ENCODER);
lv_indev_set_read_cb(lvglDevice, &readCallback);
lv_indev_set_display(lvglDevice, display);
lv_indev_set_user_data(lvglDevice, this);
return true;
}
bool CardputerEncoder::stopLvgl() {
lv_indev_delete(lvglDevice);
lvglDevice = nullptr;
return true;
}

View File

@ -0,0 +1,29 @@
#pragma once
#include <Tactility/hal/encoder/EncoderDevice.h>
#include "keyboard/keyboard.h"
/**
* Wrapper around the keyboard that uses the following buttons to simulate an encoder:
* - Up
* - Down
* - ok (fn + enter)
*/
class CardputerEncoder final : public tt::hal::encoder::EncoderDevice {
KEYBOARD::Keyboard keyboard;
int lastKeyNum = 0;
lv_indev_t* _Nullable lvglDevice = nullptr;
static void readCallback(lv_indev_t* indev, lv_indev_data_t* data);
public:
std::string getName() const override { return "Cardputer Encoder"; }
std::string getDescription() const override { return "Cardputer keyboard up/down acting as encoder"; }
bool startLvgl(lv_display_t* display) override;
bool stopLvgl() override;
lv_indev_t* _Nullable getLvglIndev() override { return lvglDevice; }
};

View File

@ -0,0 +1,90 @@
#include "CardputerKeyboard.h"
#include <Tactility/Log.h>
constexpr auto* TAG = "Keyboard";
bool CardputerKeyboard::startLvgl(lv_display_t* display) {
keyboard.init();
lvglDevice = lv_indev_create();
lv_indev_set_type(lvglDevice, LV_INDEV_TYPE_KEYPAD);
lv_indev_set_read_cb(lvglDevice, &readCallback);
lv_indev_set_display(lvglDevice, display);
lv_indev_set_user_data(lvglDevice, this);
return true;
}
bool CardputerKeyboard::stopLvgl() {
lv_indev_delete(lvglDevice);
lvglDevice = nullptr;
return true;
}
void CardputerKeyboard::readCallback(lv_indev_t* indev, lv_indev_data_t* data) {
CardputerKeyboard* self = static_cast<CardputerKeyboard*>(lv_indev_get_user_data(indev));
data->key = 0;
data->state = LV_INDEV_STATE_RELEASED;
self->keyboard.updateKeyList();
if (self->keyboard.keyList().size() != self->lastKeyNum) {
// If key pressed
if (self->keyboard.keyList().size() != 0) {
// Update states and values
self->keyboard.updateKeysState();
if (!self->keyboard.keysState().fn) {
if (self->keyboard.keysState().enter) {
data->key = LV_KEY_ENTER;
data->state = LV_INDEV_STATE_PRESSED;
} else if (self->keyboard.keysState().space) {
data->key = ' ';
data->state = LV_INDEV_STATE_PRESSED;
} else if (self->keyboard.keysState().del) {
data->key = LV_KEY_BACKSPACE;
data->state = LV_INDEV_STATE_PRESSED;
} else {
// Normal chars
for (auto& i : self->keyboard.keysState().values) {
data->key = i;
data->state = LV_INDEV_STATE_PRESSED;
break; // We only support 1 keypress for now
}
}
} else {
if (self->keyboard.keysState().del) {
TT_LOG_I(TAG, "del");
data->key = LV_KEY_DEL;
data->state = LV_INDEV_STATE_PRESSED;
} else {
for (auto& i : self->keyboard.keysState().values) {
if (i == ';') { // Up
data->key = LV_KEY_UP;
data->state = LV_INDEV_STATE_PRESSED;
} else if (i == '.') { // Down
data->key = LV_KEY_DOWN;
data->state = LV_INDEV_STATE_PRESSED;
} else if (i == ',') { // Left
data->key = LV_KEY_LEFT;
data->state = LV_INDEV_STATE_PRESSED;
} else if (i == '/') { // Right
data->key = LV_KEY_RIGHT;
data->state = LV_INDEV_STATE_PRESSED;
} else if (i == '`') { // Escape
data->key = LV_KEY_ESC;
data->state = LV_INDEV_STATE_PRESSED;
}
break; // We only support 1 keypress for now
}
}
}
self->lastKeyNum = self->keyboard.keyList().size();
} else {
self->lastKeyNum = 0;
}
}
}

View File

@ -0,0 +1,26 @@
#pragma once
#include <Tactility/Thread.h>
#include <Tactility/hal/keyboard/KeyboardDevice.h>
#include "keyboard/keyboard.h"
class CardputerKeyboard : public tt::hal::keyboard::KeyboardDevice {
KEYBOARD::Keyboard keyboard;
int lastKeyNum = 0;
lv_indev_t* _Nullable lvglDevice = nullptr;
static void readCallback(lv_indev_t* indev, lv_indev_data_t* data);
public:
std::string getName() const override { return "Cardputer Keyboard"; }
std::string getDescription() const override { return "Cardputer internal keyboard"; }
bool startLvgl(lv_display_t* display) override;
bool stopLvgl() override;
bool isAttached() const override { return true; }
lv_indev_t* _Nullable getLvglIndev() override { return lvglDevice; }
};

View File

@ -0,0 +1,28 @@
#include "Display.h"
#include <PwmBacklight.h>
#include <St7789Display.h>
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
auto configuration = std::make_unique<St7789Display::Configuration>(
LCD_SPI_HOST,
LCD_PIN_CS,
LCD_PIN_DC,
LCD_HORIZONTAL_RESOLUTION,
LCD_VERTICAL_RESOLUTION,
nullptr,
true,
true,
false,
true,
0,
53, // Should be 52 according to https://github.com/m5stack/M5GFX/blob/master/src/M5GFX.cpp but this leaves a gap at the bottom
40
);
configuration->resetPin = LCD_PIN_RESET;
configuration->backlightDutyFunction = driver::pwmbacklight::setBacklightDuty;
auto display = std::make_shared<St7789Display>(std::move(configuration));
return std::reinterpret_pointer_cast<tt::hal::display::DisplayDevice>(display);
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "Tactility/hal/display/DisplayDevice.h"
#include <memory>
#define LCD_SPI_HOST SPI2_HOST
#define LCD_PIN_CS GPIO_NUM_37
#define LCD_PIN_DC GPIO_NUM_34 // RS
#define LCD_PIN_RESET GPIO_NUM_33
#define LCD_HORIZONTAL_RESOLUTION 240
#define LCD_VERTICAL_RESOLUTION 135
#define LCD_DRAW_BUFFER_HEIGHT (LCD_VERTICAL_RESOLUTION / 10)
#define LCD_DRAW_BUFFER_SIZE (LCD_HORIZONTAL_RESOLUTION * LCD_DRAW_BUFFER_HEIGHT)
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();

View File

@ -0,0 +1,25 @@
#include "SdCard.h"
#include <Tactility/hal/sdcard/SpiSdCardDevice.h>
constexpr auto SDCARD_PIN_CS = GPIO_NUM_12;
constexpr auto LCD_PIN_CS = GPIO_NUM_37;
using tt::hal::sdcard::SpiSdCardDevice;
std::shared_ptr<SdCardDevice> createSdCard() {
auto configuration = std::make_unique<SpiSdCardDevice::Config>(
SDCARD_PIN_CS,
GPIO_NUM_NC,
GPIO_NUM_NC,
GPIO_NUM_NC,
SdCardDevice::MountBehaviour::AtBoot,
tt::hal::spi::getLock(SPI3_HOST),
std::vector { LCD_PIN_CS },
SPI3_HOST
);
return std::make_shared<SpiSdCardDevice>(
std::move(configuration)
);
}

View File

@ -0,0 +1,7 @@
#pragma once
#include "Tactility/hal/sdcard/SdCardDevice.h"
using tt::hal::sdcard::SdCardDevice;
std::shared_ptr<SdCardDevice> createSdCard();

View File

@ -0,0 +1,31 @@
# keyboard folder
The keyboard code in this folder is from https://github.com/m5stack/M5Cardputer-UserDemo/tree/main/main/hal/keyboard
# License
The original license is an MIT license:
```
MIT License
Copyright (c) 2023 M5Stack
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```

View File

@ -0,0 +1,266 @@
/**
* @file keyboard.cpp
* @author Forairaaaaa
* @brief
* @version 0.1
* @date 2023-09-22
*
* @copyright Copyright (c) 2023
*
*/
#include "keyboard.h"
#include <driver/gpio.h>
#define digitalWrite(pin, level) gpio_set_level((gpio_num_t)pin, level)
#define digitalRead(pin) gpio_get_level((gpio_num_t)pin)
using namespace KEYBOARD;
void Keyboard::_set_output(const std::vector<int>& pinList, uint8_t output)
{
output = output & 0B00000111;
digitalWrite(pinList[0], (output & 0B00000001));
digitalWrite(pinList[1], (output & 0B00000010));
digitalWrite(pinList[2], (output & 0B00000100));
}
uint8_t Keyboard::_get_input(const std::vector<int>& pinList)
{
uint8_t buffer = 0x00;
uint8_t pin_value = 0x00;
for (int i = 0; i < 7; i++)
{
pin_value = (digitalRead(pinList[i]) == 1) ? 0x00 : 0x01;
pin_value = pin_value << i;
buffer = buffer | pin_value;
}
return buffer;
}
void Keyboard::init()
{
for (auto i : output_list)
{
gpio_reset_pin((gpio_num_t)i);
gpio_set_direction((gpio_num_t)i, GPIO_MODE_OUTPUT);
gpio_set_pull_mode((gpio_num_t)i, GPIO_PULLUP_PULLDOWN);
digitalWrite(i, 0);
}
for (auto i : input_list)
{
gpio_reset_pin((gpio_num_t)i);
gpio_set_direction((gpio_num_t)i, GPIO_MODE_INPUT);
gpio_set_pull_mode((gpio_num_t)i, GPIO_PULLUP_ONLY);
}
_set_output(output_list, 0);
}
Point2D_t Keyboard::getKey()
{
Point2D_t coor;
coor.x = -1;
coor.y = -1;
uint8_t input_value = 0;
for (int i = 0; i < 8; i++) {
_set_output(output_list, i);
// printf("% 3d,\t", get_input(inputList));
input_value = _get_input(input_list);
/* If key pressed */
if (input_value) {
/* Get X */
for (int j = 0; j < 7; j++) {
if (input_value == X_map_chart[j].value) {
coor.x = (i > 3) ? X_map_chart[j].x_1 : X_map_chart[j].x_2;
break;
}
}
/* Get Y */
coor.y = (i > 3) ? (i - 4) : i;
/* Keep the same as picture */
coor.y = -coor.y;
coor.y = coor.y + 3;
break;
}
}
// printf("%d,%d\n", x, y);
return coor;
}
uint8_t Keyboard::getKeyNum(Point2D_t keyCoor)
{
uint8_t ret = 0;
if ((keyCoor.x < 0) || (keyCoor.y < 0)) {
return 0;
}
ret = (keyCoor.y * 14) + (keyCoor.x + 1);
return ret;
}
void Keyboard::updateKeyList()
{
_key_list_buffer.clear();
Point2D_t coor;
uint8_t input_value = 0;
for (int i = 0; i < 8; i++) {
_set_output(output_list, i);
input_value = _get_input(input_list);
/* If key pressed */
if (input_value) {
/* Get X */
for (int j = 0; j < 7; j++) {
if (input_value & (0x01 << j)) {
coor.x = (i > 3) ? X_map_chart[j].x_1 : X_map_chart[j].x_2;
/* Get Y */
coor.y = (i > 3) ? (i - 4) : i;
// printf("%d,%d\t", coor.x, coor.y);
/* Keep the same as picture */
coor.y = -coor.y;
coor.y = coor.y + 3;
_key_list_buffer.push_back(coor);
}
}
}
}
}
bool Keyboard::isKeyPressing(int keyNum)
{
if (_key_list_buffer.size())
{
for (const auto& i : _key_list_buffer)
{
if (getKeyNum(i) == keyNum)
return true;
}
}
return false;
}
#include <cstring>
void Keyboard::updateKeysState()
{
_keys_state_buffer.reset();
_key_values_without_special_keys.clear();
// Get special keys
for (auto& i : _key_list_buffer)
{
if (strcmp(getKeyValue(i).value_first, "tab") == 0)
{
_keys_state_buffer.tab = true;
continue;
}
if (strcmp(getKeyValue(i).value_first, "fn") == 0)
{
_keys_state_buffer.fn = true;
continue;
}
if (strcmp(getKeyValue(i).value_first, "shift") == 0)
{
_keys_state_buffer.shift = true;
continue;
}
if (strcmp(getKeyValue(i).value_first, "ctrl") == 0)
{
_keys_state_buffer.ctrl = true;
continue;
}
if (strcmp(getKeyValue(i).value_first, "opt") == 0)
{
_keys_state_buffer.opt = true;
continue;
}
if (strcmp(getKeyValue(i).value_first, "alt") == 0)
{
_keys_state_buffer.alt = true;
continue;
}
if (strcmp(getKeyValue(i).value_first, "del") == 0)
{
_keys_state_buffer.del = true;
_keys_state_buffer.hidKey.push_back(KEY_BACKSPACE);
continue;
}
if (strcmp(getKeyValue(i).value_first, "enter") == 0)
{
_keys_state_buffer.enter = true;
_keys_state_buffer.hidKey.push_back(KEY_ENTER);
continue;
}
if (strcmp(getKeyValue(i).value_first, "space") == 0)
{
_keys_state_buffer.space = true;
_keys_state_buffer.hidKey.push_back(KEY_SPACE);
continue;
}
_key_values_without_special_keys.push_back(i);
}
// Deal what left
for (auto& i : _key_values_without_special_keys)
{
if (_keys_state_buffer.ctrl || _keys_state_buffer.shift || _is_caps_locked)
{
_keys_state_buffer.values.push_back(*getKeyValue(i).value_second);
_keys_state_buffer.hidKey.push_back(getKeyValue(i).value_num_second);
}
else
{
_keys_state_buffer.values.push_back(*getKeyValue(i).value_first);
_keys_state_buffer.hidKey.push_back(getKeyValue(i).value_num_first);
}
}
}
bool Keyboard::isChanged()
{
if (_last_key_size != _key_list_buffer.size())
{
_last_key_size = _key_list_buffer.size();
return true;
}
return false;
}

View File

@ -0,0 +1,192 @@
/**
* @file keyboard.h
* @author Forairaaaaa
* @brief
* @version 0.1
* @date 2023-09-22
*
* @copyright Copyright (c) 2023
*
*/
#pragma once
#include <iostream>
#include <vector>
#include "keymap.h"
namespace KEYBOARD
{
struct Chart_t
{
uint8_t value;
uint8_t x_1;
uint8_t x_2;
};
struct Point2D_t
{
int x;
int y;
};
const std::vector<int> output_list = {8, 9, 11};
const std::vector<int> input_list = {13, 15, 3, 4, 5, 6, 7};
// const std::vector<int> input_list = {1, 2, 3, 4, 5, 6, 7};
const Chart_t X_map_chart[7] =
{
{1, 0, 1},
{2, 2, 3},
{4, 4, 5},
{8, 6, 7},
{16, 8, 9},
{32, 10, 11},
{64, 12, 13}
};
struct KeyValue_t
{
const char* value_first;
const int value_num_first;
const char* value_second;
const int value_num_second;
};
const KeyValue_t _key_value_map[4][14] = {
{{"`", KEY_GRAVE, "~", KEY_GRAVE},
{"1", KEY_1, "!", KEY_1},
{"2", KEY_2, "@", KEY_2},
{"3", KEY_3, "#", KEY_3},
{"4", KEY_4, "$", KEY_4},
{"5", KEY_5, "%", KEY_5},
{"6", KEY_6, "^", KEY_6},
{"7", KEY_7, "&", KEY_7},
{"8", KEY_8, "*", KEY_KPASTERISK},
{"9", KEY_9, "(", KEY_KPLEFTPAREN},
{"0", KEY_0, ")", KEY_KPRIGHTPAREN},
{"-", KEY_MINUS, "_", KEY_KPMINUS},
{"=", KEY_EQUAL, "+", KEY_KPPLUS},
{"del", KEY_BACKSPACE, "del", KEY_BACKSPACE}},
{{"tab", KEY_TAB, "tab", KEY_TAB},
{"q", KEY_Q, "Q", KEY_Q},
{"w", KEY_W, "W", KEY_W},
{"e", KEY_E, "E", KEY_E},
{"r", KEY_R, "R", KEY_R},
{"t", KEY_T, "T", KEY_T},
{"y", KEY_Y, "Y", KEY_Y},
{"u", KEY_U, "U", KEY_U},
{"i", KEY_I, "I", KEY_I},
{"o", KEY_O, "O", KEY_O},
{"p", KEY_P, "P", KEY_P},
{"[", KEY_LEFTBRACE, "{", KEY_LEFTBRACE},
{"]", KEY_RIGHTBRACE, "}", KEY_RIGHTBRACE},
{"\\", KEY_BACKSLASH, "|", KEY_BACKSLASH}},
{{"fn", 0, "fn", 0},
{"shift", 0, "shift", 0},
{"a", KEY_A, "A", KEY_A},
{"s", KEY_S, "S", KEY_S},
{"d", KEY_D, "D", KEY_D},
{"f", KEY_F, "F", KEY_F},
{"g", KEY_G, "G", KEY_G},
{"h", KEY_H, "H", KEY_H},
{"j", KEY_J, "J", KEY_J},
{"k", KEY_K, "K", KEY_K},
{"l", KEY_L, "L", KEY_L},
{";", KEY_SEMICOLON, ":", KEY_SEMICOLON},
{"'", KEY_APOSTROPHE, "\"", KEY_APOSTROPHE},
{"enter", KEY_ENTER, "enter", KEY_ENTER}},
{{"ctrl", KEY_LEFTCTRL, "ctrl", KEY_LEFTCTRL},
{"opt", 0, "opt", 0},
{"alt", KEY_LEFTALT, "alt", KEY_LEFTALT},
{"z", KEY_Z, "Z", KEY_Z},
{"x", KEY_X, "X", KEY_X},
{"c", KEY_C, "C", KEY_C},
{"v", KEY_V, "V", KEY_V},
{"b", KEY_B, "B", KEY_B},
{"n", KEY_N, "N", KEY_N},
{"m", KEY_M, "M", KEY_M},
{",", KEY_COMMA, "<", KEY_COMMA},
{".", KEY_DOT, ">", KEY_DOT},
{"/", KEY_KPSLASH, "?", KEY_KPSLASH},
{"space", KEY_SPACE, "space", KEY_SPACE}}};
class Keyboard
{
public:
struct KeysState
{
bool tab = false;
bool fn = false;
bool shift = false;
bool ctrl = false;
bool opt = false;
bool alt = false;
bool del = false;
bool enter = false;
bool space = false;
std::vector<char> values;
std::vector<int> hidKey;
void reset()
{
tab = false;
fn = false;
shift = false;
ctrl = false;
opt = false;
alt = false;
del = false;
enter = false;
space = false;
values.clear();
hidKey.clear();
}
};
private:
std::vector<Point2D_t> _key_list_buffer;
std::vector<Point2D_t> _key_values_without_special_keys;
KeysState _keys_state_buffer;
bool _is_caps_locked;
uint8_t _last_key_size;
void _set_output(const std::vector<int>& pinList, uint8_t output);
uint8_t _get_input(const std::vector<int>& pinList);
public:
Keyboard() :
_is_caps_locked(false),
_last_key_size(0)
{}
void init();
Point2D_t getKey();
uint8_t getKeyNum(Point2D_t keyCoor);
void updateKeyList();
inline std::vector<KEYBOARD::Point2D_t>& keyList() { return _key_list_buffer; }
inline KeyValue_t getKeyValue(const Point2D_t& keyCoor) { return _key_value_map[keyCoor.y][keyCoor.x]; }
bool isKeyPressing(int keyNum);
void updateKeysState();
inline KeysState& keysState() { return _keys_state_buffer; }
inline bool capslocked(void) { return _is_caps_locked; }
inline void setCapsLocked(bool isLocked) { _is_caps_locked = isLocked; }
bool isChanged();
inline uint8_t isPressed() { return _key_list_buffer.size(); }
};
}

View File

@ -0,0 +1,366 @@
/**
* This file is part of esp32s3-keyboard.
*
* Copyright (C) 2020-2021 Yuquan He <heyuquan20b at ict dot ac dot cn>
* (Institute of Computing Technology, Chinese Academy of Sciences)
*
* esp32s3-keyboard is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* esp32s3-keyboard is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with esp32s3-keyboard. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* USB HID format: 8 bytes
* Byte 0: Keyboard modifier bits (SHIFT, ALT, CTRL etc)
* Byte 1: reserved
* Byte 2-7: Up to six keyboard usage indexes representing the keys that are
* currently "pressed". Order is not important, a key is either
* pressed (present in the buffer) or not pressed.
*/
#ifndef MY_KEYMAP_H
#define MY_KEYMAP_H
#include <stdint.h>
/**
* Modifier masks - used for the first byte in the HID report.
* NOTE: The second byte in the report is reserved, 0x00
*/
#define KEY_MOD_LCTRL 0x01
#define KEY_MOD_LSHIFT 0x02
#define KEY_MOD_LALT 0x04
#define KEY_MOD_LMETA 0x08
#define KEY_MOD_RCTRL 0x10
#define KEY_MOD_RSHIFT 0x20
#define KEY_MOD_RALT 0x40
#define KEY_MOD_RMETA 0x80
/**
* Scan codes - last N slots in the HID report (usually 6).
* 0x00 if no key pressed.
*
* If more than N keys are pressed, the HID reports
* KEY_ERR_OVF in all slots to indicate this condition.
*/
#define KEY_NONE 0x00 // No key pressed
#define KEY_ERR_OVF \
0x01 // Keyboard Error Roll Over - used for all slots if too many keys are
// pressed ("Phantom key")
// 0x02 // Keyboard POST Fail
// 0x03 // Keyboard Error Undefined
#define KEY_A 0x04 // Keyboard a and A
#define KEY_B 0x05 // Keyboard b and B
#define KEY_C 0x06 // Keyboard c and C
#define KEY_D 0x07 // Keyboard d and D
#define KEY_E 0x08 // Keyboard e and E
#define KEY_F 0x09 // Keyboard f and F
#define KEY_G 0x0a // Keyboard g and G
#define KEY_H 0x0b // Keyboard h and H
#define KEY_I 0x0c // Keyboard i and I
#define KEY_J 0x0d // Keyboard j and J
#define KEY_K 0x0e // Keyboard k and K
#define KEY_L 0x0f // Keyboard l and L
#define KEY_M 0x10 // Keyboard m and M
#define KEY_N 0x11 // Keyboard n and N
#define KEY_O 0x12 // Keyboard o and O
#define KEY_P 0x13 // Keyboard p and P
#define KEY_Q 0x14 // Keyboard q and Q
#define KEY_R 0x15 // Keyboard r and R
#define KEY_S 0x16 // Keyboard s and S
#define KEY_T 0x17 // Keyboard t and T
#define KEY_U 0x18 // Keyboard u and U
#define KEY_V 0x19 // Keyboard v and V
#define KEY_W 0x1a // Keyboard w and W
#define KEY_X 0x1b // Keyboard x and X
#define KEY_Y 0x1c // Keyboard y and Y
#define KEY_Z 0x1d // Keyboard z and Z
#define KEY_1 0x1e // Keyboard 1 and !
#define KEY_2 0x1f // Keyboard 2 and @
#define KEY_3 0x20 // Keyboard 3 and #
#define KEY_4 0x21 // Keyboard 4 and $
#define KEY_5 0x22 // Keyboard 5 and %
#define KEY_6 0x23 // Keyboard 6 and ^
#define KEY_7 0x24 // Keyboard 7 and &
#define KEY_8 0x25 // Keyboard 8 and *
#define KEY_9 0x26 // Keyboard 9 and (
#define KEY_0 0x27 // Keyboard 0 and )
#define KEY_ENTER 0x28 // Keyboard Return (ENTER)
#define KEY_ESC 0x29 // Keyboard ESCAPE
#define KEY_BACKSPACE 0x2a // Keyboard DELETE (Backspace)
#define KEY_TAB 0x2b // Keyboard Tab
#define KEY_SPACE 0x2c // Keyboard Spacebar
#define KEY_MINUS 0x2d // Keyboard - and _
#define KEY_EQUAL 0x2e // Keyboard = and +
#define KEY_LEFTBRACE 0x2f // Keyboard [ and {
#define KEY_RIGHTBRACE 0x30 // Keyboard ] and }
#define KEY_BACKSLASH 0x31 // Keyboard \ and |
#define KEY_HASHTILDE 0x32 // Keyboard Non-US # and ~
#define KEY_SEMICOLON 0x33 // Keyboard ; and :
#define KEY_APOSTROPHE 0x34 // Keyboard ' and "
#define KEY_GRAVE 0x35 // Keyboard ` and ~
#define KEY_COMMA 0x36 // Keyboard , and <
#define KEY_DOT 0x37 // Keyboard . and >
#define KEY_SLASH 0x38 // Keyboard / and ?
#define KEY_CAPSLOCK 0x39 // Keyboard Caps Lock
#define KEY_F1 0x3a // Keyboard F1
#define KEY_F2 0x3b // Keyboard F2
#define KEY_F3 0x3c // Keyboard F3
#define KEY_F4 0x3d // Keyboard F4
#define KEY_F5 0x3e // Keyboard F5
#define KEY_F6 0x3f // Keyboard F6
#define KEY_F7 0x40 // Keyboard F7
#define KEY_F8 0x41 // Keyboard F8
#define KEY_F9 0x42 // Keyboard F9
#define KEY_F10 0x43 // Keyboard F10
#define KEY_F11 0x44 // Keyboard F11
#define KEY_F12 0x45 // Keyboard F12
#define KEY_PRTSC 0x46 // Keyboard Print Screen
#define KEY_SCROLLLOCK 0x47 // Keyboard Scroll Lock
#define KEY_PAUSE 0x48 // Keyboard Pause
#define KEY_INSERT 0x49 // Keyboard Insert
#define KEY_HOME 0x4a // Keyboard Home
#define KEY_PAGEUP 0x4b // Keyboard Page Up
// #define KEY_DELETE 0x4c // Keyboard Delete Forward
#define KEY_DELETE 0xD4 // Keyboard Delete Forward
#define KEY_END 0x4d // Keyboard End
#define KEY_PAGEDOWN 0x4e // Keyboard Page Down
#define KEY_RIGHT 0x4f // Keyboard Right Arrow
#define KEY_LEFT 0x50 // Keyboard Left Arrow
#define KEY_DOWN 0x51 // Keyboard Down Arrow
#define KEY_UP 0x52 // Keyboard Up Arrow
#define KEY_NUMLOCK 0x53 // Keyboard Num Lock and Clear
#define KEY_KPSLASH 0x54 // Keypad /
#define KEY_KPASTERISK 0x55 // Keypad *
#define KEY_KPMINUS 0x56 // Keypad -
#define KEY_KPPLUS 0x57 // Keypad +
#define KEY_KPENTER 0x58 // Keypad ENTER
#define KEY_KP1 0x59 // Keypad 1 and End
#define KEY_KP2 0x5a // Keypad 2 and Down Arrow
#define KEY_KP3 0x5b // Keypad 3 and PageDn
#define KEY_KP4 0x5c // Keypad 4 and Left Arrow
#define KEY_KP5 0x5d // Keypad 5
#define KEY_KP6 0x5e // Keypad 6 and Right Arrow
#define KEY_KP7 0x5f // Keypad 7 and Home
#define KEY_KP8 0x60 // Keypad 8 and Up Arrow
#define KEY_KP9 0x61 // Keypad 9 and Page Up
#define KEY_KP0 0x62 // Keypad 0 and Insert
#define KEY_KPDOT 0x63 // Keypad . and Delete
#define KEY_102ND 0x64 // Keyboard Non-US \ and |
#define KEY_COMPOSE 0x65 // Keyboard Application
#define KEY_POWER 0x66 // Keyboard Power
#define KEY_KPEQUAL 0x67 // Keypad =
#define KEY_F13 0x68 // Keyboard F13
#define KEY_F14 0x69 // Keyboard F14
#define KEY_F15 0x6a // Keyboard F15
#define KEY_F16 0x6b // Keyboard F16
#define KEY_F17 0x6c // Keyboard F17
#define KEY_F18 0x6d // Keyboard F18
#define KEY_F19 0x6e // Keyboard F19
#define KEY_F20 0x6f // Keyboard F20
#define KEY_F21 0x70 // Keyboard F21
#define KEY_F22 0x71 // Keyboard F22
#define KEY_F23 0x72 // Keyboard F23
#define KEY_F24 0x73 // Keyboard F24
#define KEY_OPEN 0x74 // Keyboard Execute
#define KEY_HELP 0x75 // Keyboard Help
#define KEY_PROPS 0x76 // Keyboard Menu
#define KEY_FRONT 0x77 // Keyboard Select
#define KEY_STOP 0x78 // Keyboard Stop
#define KEY_AGAIN 0x79 // Keyboard Again
#define KEY_UNDO 0x7a // Keyboard Undo
#define KEY_CUT 0x7b // Keyboard Cut
#define KEY_COPY 0x7c // Keyboard Copy
#define KEY_PASTE 0x7d // Keyboard Paste
#define KEY_FIND 0x7e // Keyboard Find
#define KEY_MUTE 0x7f // Keyboard Mute
#define KEY_VOLUMEUP 0x80 // Keyboard Volume Up
#define KEY_VOLUMEDOWN 0x81 // Keyboard Volume Down
// 0x82 Keyboard Locking Caps Lock
// 0x83 Keyboard Locking Num Lock
// 0x84 Keyboard Locking Scroll Lock
#define KEY_KPCOMMA 0x85 // Keypad Comma
// 0x86 Keypad Equal Sign
#define KEY_RO 0x87 // Keyboard International1
#define KEY_KATAKANAHIRAGANA 0x88 // Keyboard International2
#define KEY_YEN 0x89 // Keyboard International3
#define KEY_HENKAN 0x8a // Keyboard International4
#define KEY_MUHENKAN 0x8b // Keyboard International5
#define KEY_KPJPCOMMA 0x8c // Keyboard International6
// 0x8d Keyboard International7
// 0x8e Keyboard International8
// 0x8f Keyboard International9
#define KEY_HANGEUL 0x90 // Keyboard LANG1
#define KEY_HANJA 0x91 // Keyboard LANG2
#define KEY_KATAKANA 0x92 // Keyboard LANG3
#define KEY_HIRAGANA 0x93 // Keyboard LANG4
#define KEY_ZENKAKUHANKAKU 0x94 // Keyboard LANG5
// 0x95 Keyboard LANG6
// 0x96 Keyboard LANG7
// 0x97 Keyboard LANG8
// 0x98 Keyboard LANG9
// 0x99 Keyboard Alternate Erase
// 0x9a Keyboard SysReq/Attention
// 0x9b Keyboard Cancel
// 0x9c Keyboard Clear
// 0x9d Keyboard Prior
// 0x9e Keyboard Return
// 0x9f Keyboard Separator
// 0xa0 Keyboard Out
// 0xa1 Keyboard Oper
// 0xa2 Keyboard Clear/Again
// 0xa3 Keyboard CrSel/Props
// 0xa4 Keyboard ExSel
// 0xb0 Keypad 00
// 0xb1 Keypad 000
// 0xb2 Thousands Separator
// 0xb3 Decimal Separator
// 0xb4 Currency Unit
// 0xb5 Currency Sub-unit
#define KEY_KPLEFTPAREN 0xb6 // Keypad (
#define KEY_KPRIGHTPAREN 0xb7 // Keypad )
// 0xb8 Keypad {
// 0xb9 Keypad }
// 0xba Keypad Tab
#define KEY_KPBACKSPACE 0xbb // Keypad Backspace
// 0xbc Keypad A
// 0xbd Keypad B
// 0xbe Keypad C
// 0xbf Keypad D
// 0xc0 Keypad E
// 0xc1 Keypad F
// 0xc2 Keypad XOR
// 0xc3 Keypad ^
// 0xc4 Keypad %
// 0xc5 Keypad <
// 0xc6 Keypad >
// 0xc7 Keypad &
// 0xc8 Keypad &&
// 0xc9 Keypad |
// 0xca Keypad ||
// 0xcb Keypad :
// 0xcc Keypad #
// 0xcd Keypad Space
// 0xce Keypad @
// 0xcf Keypad !
// 0xd0 Keypad Memory Store
// 0xd1 Keypad Memory Recall
// 0xd2 Keypad Memory Clear
// 0xd3 Keypad Memory Add
// 0xd4 Keypad Memory Subtract
// 0xd5 Keypad Memory Multiply
// 0xd6 Keypad Memory Divide
// 0xd7 Keypad +/-
// 0xd8 Keypad Clear
// 0xd9 Keypad Clear Entry
// 0xda Keypad Binary
// 0xdb Keypad Octal
// 0xdc Keypad Decimal
// 0xdd Keypad Hexadecimal
#define KEY_LEFTCTRL 0xe0 // Keyboard Left Control
#define KEY_LEFTSHIFT 0xe1 // Keyboard Left Shift
#define KEY_LEFTALT 0xe2 // Keyboard Left Alt
#define KEY_LEFTMETA 0xe3 // Keyboard Left GUI
#define KEY_RIGHTCTRL 0xe4 // Keyboard Right Control
#define KEY_RIGHTSHIFT 0xe5 // Keyboard Right Shift
#define KEY_RIGHTALT 0xe6 // Keyboard Right Alt
#define KEY_RIGHTMETA 0xe7 // Keyboard Right GUI
#define KEY_MEDIA_PLAYPAUSE 0xe8
#define KEY_MEDIA_STOPCD 0xe9
#define KEY_MEDIA_PREVIOUSSONG 0xea
#define KEY_MEDIA_NEXTSONG 0xeb
#define KEY_MEDIA_EJECTCD 0xec
#define KEY_MEDIA_VOLUMEUP 0xed
#define KEY_MEDIA_VOLUMEDOWN 0xee
#define KEY_MEDIA_MUTE 0xef
#define KEY_MEDIA_WWW 0xf0
#define KEY_MEDIA_BACK 0xf1
#define KEY_MEDIA_FORWARD 0xf2
#define KEY_MEDIA_STOP 0xf3
#define KEY_MEDIA_FIND 0xf4
#define KEY_MEDIA_SCROLLUP 0xf5
#define KEY_MEDIA_SCROLLDOWN 0xf6
#define KEY_MEDIA_EDIT 0xf7
#define KEY_MEDIA_SLEEP 0xf8
#define KEY_MEDIA_COFFEE 0xf9
#define KEY_MEDIA_REFRESH 0xfa
#define KEY_MEDIA_CALC 0xfb
enum {
// Generic Control
KEY_CONSUMER_CONTROL = 0x0001,
// Power Control
KEY_CONSUMER_POWER = 0x0030,
KEY_CONSUMER_RESET = 0x0031,
KEY_CONSUMER_SLEEP = 0x0032,
// Screen Brightness
KEY_CONSUMER_BRIGHTNESS_INCREMENT = 0x006F,
KEY_CONSUMER_BRIGHTNESS_DECREMENT = 0x0070,
// These HID usages operate only on mobile systems (battery powered) and
// require Windows 8 (build 8302 or greater).
KEY_CONSUMER_WIRELESS_RADIO_CONTROLS = 0x000C,
KEY_CONSUMER_WIRELESS_RADIO_BUTTONS = 0x00C6,
KEY_CONSUMER_WIRELESS_RADIO_LED = 0x00C7,
KEY_CONSUMER_WIRELESS_RADIO_SLIDER_SWITCH = 0x00C8,
// Media Control
KEY_CONSUMER_PLAY_PAUSE = 0x00CD,
KEY_CONSUMER_SCAN_NEXT = 0x00B5,
KEY_CONSUMER_SCAN_PREVIOUS = 0x00B6,
KEY_CONSUMER_STOP = 0x00B7,
KEY_CONSUMER_VOLUME = 0x00E0,
KEY_CONSUMER_MUTE = 0x00E2,
KEY_CONSUMER_BASS = 0x00E3,
KEY_CONSUMER_TREBLE = 0x00E4,
KEY_CONSUMER_BASS_BOOST = 0x00E5,
KEY_CONSUMER_VOLUME_INCREMENT = 0x00E9,
KEY_CONSUMER_VOLUME_DECREMENT = 0x00EA,
KEY_CONSUMER_BASS_INCREMENT = 0x0152,
KEY_CONSUMER_BASS_DECREMENT = 0x0153,
KEY_CONSUMER_TREBLE_INCREMENT = 0x0154,
KEY_CONSUMER_TREBLE_DECREMENT = 0x0155,
// Application Launcher
KEY_CONSUMER_AL_CONSUMER_CONTROL_CONFIGURATION = 0x0183,
KEY_CONSUMER_AL_EMAIL_READER = 0x018A,
KEY_CONSUMER_AL_CALCULATOR = 0x0192,
KEY_CONSUMER_AL_LOCAL_BROWSER = 0x0194,
// Browser/Explorer Specific
KEY_CONSUMER_AC_SEARCH = 0x0221,
KEY_CONSUMER_AC_HOME = 0x0223,
KEY_CONSUMER_AC_BACK = 0x0224,
KEY_CONSUMER_AC_FORWARD = 0x0225,
KEY_CONSUMER_AC_STOP = 0x0226,
KEY_CONSUMER_AC_REFRESH = 0x0227,
KEY_CONSUMER_AC_BOOKMARKS = 0x022A,
// Mouse Horizontal scroll
KEY_CONSUMER_AC_PAN = 0x0238,
};
#endif

View File

@ -53,6 +53,8 @@ function(INIT_TACTILITY_GLOBALS SDKCONFIG_FILE)
set(TACTILITY_BOARD_PROJECT LilygoTdeck)
elseif (board_id STREQUAL "lilygo-tlora-pager")
set(TACTILITY_BOARD_PROJECT LilygoTLoraPager)
elseif (board_id STREQUAL "m5stack-cardputer")
set(TACTILITY_BOARD_PROJECT M5stackCardputer)
elseif (board_id STREQUAL "m5stack-core2")
set(TACTILITY_BOARD_PROJECT M5stackCore2)
elseif (board_id STREQUAL "m5stack-cores3")

View File

@ -69,6 +69,9 @@ release m5stack-core2
releaseSdk release/TactilitySDK-esp32
build m5stack-cardputer
release m5stack-cardputer
build m5stack-cores3
release m5stack-cores3

View File

@ -20,6 +20,8 @@
## Medium Priority
- Implement `uninstall` action in `tactility.py`
- Improve EspLcdDisplay to contain all the standard configuration options, and implement a default init function. Add a configuration class.
- Statusbar icon that shows low/critical memory warnings
- Make WiFi setup app that starts an access point and hosts a webpage to set up the device.
This will be useful for devices without a screen, a small screen or a non-touch screen.
@ -27,6 +29,8 @@
- Try out ILI9342 https://github.com/jbrilha/esp_lcd_ili9342
- All drivers (e.g. display, touch, etc.) should call stop() in their destructor, or at least assert that they should not be running.
- Bug: Turn on WiFi (when testing it wasn't connected/connecting - just active). Open chat. Observe crash.
- Toolbar: when the title doesn't fit, scroll the text instead of splitting it onto a new line (try on Waveshare 1.47")
- UI: create UI size classification (e.g. "compact" for tiny screens without touch)
## Lower Priority

View File

@ -92,6 +92,13 @@ bool St7789Display::createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lc
return false;
}
int gap_x = configuration->swapXY ? configuration->gapY : configuration->gapX;
int gap_y = configuration->swapXY ? configuration->gapX : configuration->gapY;
if (esp_lcd_panel_set_gap(panelHandle, gap_x, gap_y) != ESP_OK) {
TT_LOG_E(TAG, "Failed to set panel gap");
return false;
}
return true;
}

View File

@ -32,12 +32,16 @@ public:
bool mirrorX = false,
bool mirrorY = false,
bool invertColor = false,
uint32_t bufferSize = 0 // Size in pixel count. 0 means default, which is 1/10 of the screen size
uint32_t bufferSize = 0, // Size in pixel count. 0 means default, which is 1/10 of the screen size
int gapX = 0,
int gapY = 0
) : spiHostDevice(spiHostDevice),
csPin(csPin),
dcPin(dcPin),
horizontalResolution(horizontalResolution),
verticalResolution(verticalResolution),
gapX(gapX),
gapY(gapY),
swapXY(swapXY),
mirrorX(mirrorX),
mirrorY(mirrorY),
@ -58,6 +62,8 @@ public:
size_t transactionQueueDepth = 10;
unsigned int horizontalResolution;
unsigned int verticalResolution;
int gapX;
int gapY;
bool swapXY = false;
bool mirrorX = false;
bool mirrorY = false;

View File

@ -36,6 +36,17 @@ static size_t elfManifestSetCount = 0;
static ElfManifest elfManifest;
static std::shared_ptr<Lock> elfManifestLock = std::make_shared<Mutex>();
static std::string getErrorCodeString(int error_code) {
switch (error_code) {
case ENOMEM:
return "out of memory";
case ENOSYS:
return "missing symbol";
default:
return std::format("code {}", error_code);
}
}
class ElfApp : public App {
const std::string appPath;
@ -77,8 +88,8 @@ class ElfApp : public App {
auto relocate_result = esp_elf_relocate(&elf, elfFileData.get());
if (relocate_result != 0) {
// Note: the result code mapes to values from cstdlib's errno.h
lastError = std::format("Failed to load executable (error code {})", -relocate_result);
TT_LOG_E(TAG, "%s", lastError.c_str());
lastError = getErrorCodeString(-relocate_result);
TT_LOG_E(TAG, "Application failed to load: %s", lastError.c_str());
elfFileData = nullptr;
return false;
}

View File

@ -41,11 +41,11 @@ public:
~LvglSync() override = default;
bool lock(TickType_t timeoutTicks) const override {
return tt::lvgl::lock(timeoutTicks);
return lvgl::lock(timeoutTicks);
}
bool unlock() const override {
tt::lvgl::unlock();
lvgl::unlock();
return true;
}
};

View File

@ -0,0 +1,56 @@
# Software defaults
# Increase stack size for WiFi (fixes crash after scan)
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=3072
CONFIG_LV_FONT_MONTSERRAT_14=y
CONFIG_LV_FONT_MONTSERRAT_18=y
CONFIG_LV_USE_USER_DATA=y
CONFIG_LV_USE_FS_STDIO=y
CONFIG_LV_FS_STDIO_LETTER=65
CONFIG_LV_FS_STDIO_PATH=""
CONFIG_LV_FS_STDIO_CACHE_SIZE=4096
CONFIG_LV_USE_LODEPNG=y
CONFIG_LV_USE_BUILTIN_MALLOC=n
CONFIG_LV_USE_CLIB_MALLOC=y
CONFIG_LV_USE_MSGBOX=n
CONFIG_LV_USE_SPINNER=n
CONFIG_LV_USE_WIN=n
CONFIG_LV_USE_SNAPSHOT=y
CONFIG_FREERTOS_HZ=1000
CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=2
CONFIG_FREERTOS_SMP=n
CONFIG_FREERTOS_UNICORE=n
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=5120
CONFIG_FREERTOS_USE_TRACE_FACILITY=y
CONFIG_FATFS_LFN_HEAP=y
CONFIG_FATFS_VOLUME_COUNT=3
CONFIG_FATFS_SECTOR_512=y
CONFIG_WL_SECTOR_SIZE_512=y
CONFIG_WL_SECTOR_SIZE=512
CONFIG_WL_SECTOR_MODE_SAFE=y
CONFIG_WL_SECTOR_MODE=1
# Hardware: Main
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-4mb.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions-4mb.csv"
CONFIG_TT_BOARD_M5STACK_CARDPUTER=y
CONFIG_TT_BOARD_NAME="M5Stack Cardputer"
CONFIG_TT_BOARD_ID="m5stack-cardputer"
CONFIG_IDF_EXPERIMENTAL_FEATURES=y
CONFIG_IDF_TARGET="esp32s3"
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
CONFIG_FLASHMODE_QIO=y
# SPI Flash (can set back to 80MHz after ESP-IDF bug is resolved)
CONFIG_ESPTOOLPY_FLASHFREQ_120M=y
# LVGL
CONFIG_LV_DPI_DEF=139
CONFIG_LV_DISP_DEF_REFR_PERIOD=10
CONFIG_LV_THEME_DEFAULT_DARK=y
# USB
CONFIG_TINYUSB_MSC_ENABLED=y
CONFIG_TINYUSB_MSC_MOUNT_PATH="/sdcard"
# Memory protection
CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=n
CONFIG_ESP_SYSTEM_MEMPROT_FEATURE_LOCK=n