Initial commit: Base Project for Kode Dot (ESP32-S3)
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
.pio
|
||||||
|
.vscode/.browse.c_cpp.db*
|
||||||
|
.vscode/c_cpp_properties.json
|
||||||
|
.vscode/launch.json
|
||||||
|
.vscode/ipch
|
||||||
Vendored
+8
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"pioarduino.pioarduino-ide"
|
||||||
|
],
|
||||||
|
"unwantedRecommendations": [
|
||||||
|
"ms-vscode.cpptools-extension-pack"
|
||||||
|
]
|
||||||
|
}
|
||||||
Vendored
+11
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "PlatformIO Build",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "pio run",
|
||||||
|
"group": "build"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# KodeDot FTP Explorer — Agent Memory
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
FTP server for Kode Dot (ESP32-S3) that serves the microSD card over Wi-Fi.
|
||||||
|
Reads Wi-Fi credentials from `SD:/Wi-Fi.json`, syncs time via NTP (Vienna), displays status on AMOLED via LVGL.
|
||||||
|
|
||||||
|
## Hardware
|
||||||
|
| Feature | Detail |
|
||||||
|
|---------|--------|
|
||||||
|
| MCU | ESP32-S3, 240 MHz dual-core, 32 MB flash, 8 MB PSRAM |
|
||||||
|
| Display | AMOLED 2.13" 410x502 (CO5300 QSPI + CST820 I2C touch) |
|
||||||
|
| SD Card | SDMMC 1-bit: CMD=GPIO5, CLK=GPIO6, D0=GPIO7, CD=EXP14 |
|
||||||
|
| IO Exp | TCA9555 @ 0x20 (buttons, SD detect, interrupts) |
|
||||||
|
| LED | NeoPixel GPIO4 (1 LED, GRB 800 kHz) |
|
||||||
|
| Partition | App at 0x400000 (8 MB). KodeOS bootloader below — DO NOT TOUCH |
|
||||||
|
| Port | COM10 |
|
||||||
|
|
||||||
|
## Key APIs
|
||||||
|
- `DisplayManager` — `init()`, `update()`, `setBrightness()`, `getTouchCoordinates()`
|
||||||
|
- `SD_MMC` — `setPins(clk=6, cmd=5, d0=7)`, `begin("/sdcard", 1)` (1-bit mode)
|
||||||
|
- `SimpleFTPServer` — `FtpServer ftpSrv; ftpSrv.begin("user","pass"); ftpSrv.handleFTP();`
|
||||||
|
- `ArduinoJson` — parse `[{"ssid":"...","pass":"..."}]` from SD
|
||||||
|
- NTP — `configTzTime("CET-1CEST,M3.5.0,M10.5.0/3", "pool.ntp.org")`
|
||||||
|
|
||||||
|
## Build Notes
|
||||||
|
- Build flag `-DDEFAULT_STORAGE_TYPE_ESP32=STORAGE_SD_MMC` overrides FtpServerKey.h
|
||||||
|
- Flash: `esptool --chip esp32s3 ... write-flash 0x400000 <bin>` (preserves bootloader)
|
||||||
|
- Upload speed: 460800 baud
|
||||||
|
|
||||||
|
## Git Remote
|
||||||
|
- Host: git.lago.dev
|
||||||
|
- Repo: KodeDot-FTP-Explorer
|
||||||
|
- Auth: service key token
|
||||||
|
|
||||||
|
## Findings & Notes
|
||||||
|
- SimpleFTPServer v3.0.2 supports SD_MMC on ESP32, passive mode, single session
|
||||||
|
- SFTP not feasible on ESP32 (crypto overhead too high)
|
||||||
|
- Vienna timezone string: `CET-1CEST,M3.5.0,M10.5.0/3`
|
||||||
|
- FTP credentials: `kode`/`kode`
|
||||||
|
- SD card uses `SD_MMC.begin("/sdcard", 1)` — the `1` means 1-bit bus width
|
||||||
|
- LVGL v8.3.x API (not v9) — uses `lv_disp_drv_t`, `lv_label_create`, etc.
|
||||||
|
|
||||||
|
## Status
|
||||||
|
- [ ] Phase 1: Project setup & git
|
||||||
|
- [ ] Phase 2: Backend (Wi-Fi + SD + FTP + NTP)
|
||||||
|
- [ ] Phase 3: Frontend (LVGL UI)
|
||||||
|
- [ ] Phase 4: Integration & polish
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"ssid": "Lago Sommer IoT",
|
||||||
|
"pass": "Jose1999"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino":{
|
||||||
|
"ldscript": "esp32s3_out.ld",
|
||||||
|
"partitions": "partitions_app.csv"
|
||||||
|
},
|
||||||
|
"core": "esp32",
|
||||||
|
"memory_type": "opi_opi",
|
||||||
|
"extra_flags": [
|
||||||
|
"-DARDUINO_ESP32S3_DEV",
|
||||||
|
"-DARDUINO_USB_MODE=1",
|
||||||
|
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||||
|
"-DBOARD_HAS_PSRAM"
|
||||||
|
],
|
||||||
|
"hwids": [
|
||||||
|
["0x303A", "0x1001"]
|
||||||
|
],
|
||||||
|
"f_cpu": "240000000L",
|
||||||
|
"f_flash": "80000000L",
|
||||||
|
"flash_mode": "dio",
|
||||||
|
"mcu": "esp32s3",
|
||||||
|
"variant": "esp32s3"
|
||||||
|
},
|
||||||
|
"connectivity": [
|
||||||
|
"wifi",
|
||||||
|
"bluetooth"
|
||||||
|
],
|
||||||
|
"debug": {
|
||||||
|
"openocd_target": "esp32s3.cfg"
|
||||||
|
},
|
||||||
|
"frameworks": [
|
||||||
|
"arduino"
|
||||||
|
],
|
||||||
|
"name": "Kode Dot",
|
||||||
|
"upload": {
|
||||||
|
"flash_size": "32MB",
|
||||||
|
"maximum_ram_size": 524288,
|
||||||
|
"maximum_size": 33554432,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"speed": 921600
|
||||||
|
},
|
||||||
|
"url": "https://kode.diy",
|
||||||
|
"vendor": "kode."
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
Import("env")
|
||||||
|
|
||||||
|
# Auto-detect serial port for upload and monitor if not explicitly set
|
||||||
|
try:
|
||||||
|
# Only override when user didn't set a concrete value (e.g. not "auto")
|
||||||
|
opt = env.GetProjectOption("upload_port", None)
|
||||||
|
if not opt or opt == "auto":
|
||||||
|
port = env.AutodetectUploadPort()
|
||||||
|
if port:
|
||||||
|
env.Replace(UPLOAD_PORT=port)
|
||||||
|
# Keep monitor in sync with upload port unless overridden
|
||||||
|
if not env.GetProjectOption("monitor_port", None):
|
||||||
|
env.Replace(MONITOR_PORT=port)
|
||||||
|
else:
|
||||||
|
print("[auto_port] No serial device detected; leaving UPLOAD_PORT = auto")
|
||||||
|
except Exception as e:
|
||||||
|
print("[auto_port] Warning: could not autodetect upload/monitor port:", e)
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
Import("env")
|
||||||
|
# Rename firmware binary according to custom_prog_name in platformio.ini
|
||||||
|
project_name = env.GetProjectOption("custom_prog_name", "BaseApp")
|
||||||
|
env.Replace(PROGNAME=project_name)
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
This directory is intended for project header files.
|
||||||
|
|
||||||
|
A header file is a file containing C declarations and macro definitions
|
||||||
|
to be shared between several project source files. You request the use of a
|
||||||
|
header file in your project source file (C, C++, etc) located in `src` folder
|
||||||
|
by including it, with the C preprocessing directive `#include'.
|
||||||
|
|
||||||
|
```src/main.c
|
||||||
|
|
||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Including a header file produces the same results as copying the header file
|
||||||
|
into each source file that needs it. Such copying would be time-consuming
|
||||||
|
and error-prone. With a header file, the related declarations appear
|
||||||
|
in only one place. If they need to be changed, they can be changed in one
|
||||||
|
place, and programs that include the header file will automatically use the
|
||||||
|
new version when next recompiled. The header file eliminates the labor of
|
||||||
|
finding and changing all the copies as well as the risk that a failure to
|
||||||
|
find one copy will result in inconsistencies within a program.
|
||||||
|
|
||||||
|
In C, the convention is to give header files names that end with `.h'.
|
||||||
|
|
||||||
|
Read more about using header files in official GCC documentation:
|
||||||
|
|
||||||
|
* Include Syntax
|
||||||
|
* Include Operation
|
||||||
|
* Once-Only Headers
|
||||||
|
* Computed Includes
|
||||||
|
|
||||||
|
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
This directory is intended for project specific (private) libraries.
|
||||||
|
PlatformIO will compile them to static libraries and link into the executable file.
|
||||||
|
|
||||||
|
The source code of each library should be placed in a separate directory
|
||||||
|
("lib/your_library_name/[Code]").
|
||||||
|
|
||||||
|
For example, see the structure of the following example libraries `Foo` and `Bar`:
|
||||||
|
|
||||||
|
|--lib
|
||||||
|
| |
|
||||||
|
| |--Bar
|
||||||
|
| | |--docs
|
||||||
|
| | |--examples
|
||||||
|
| | |--src
|
||||||
|
| | |- Bar.c
|
||||||
|
| | |- Bar.h
|
||||||
|
| | |- library.json (optional. for custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||||
|
| |
|
||||||
|
| |--Foo
|
||||||
|
| | |- Foo.c
|
||||||
|
| | |- Foo.h
|
||||||
|
| |
|
||||||
|
| |- README --> THIS FILE
|
||||||
|
|
|
||||||
|
|- platformio.ini
|
||||||
|
|--src
|
||||||
|
|- main.c
|
||||||
|
|
||||||
|
Example contents of `src/main.c` using Foo and Bar:
|
||||||
|
```
|
||||||
|
#include <Foo.h>
|
||||||
|
#include <Bar.h>
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
The PlatformIO Library Dependency Finder will find automatically dependent
|
||||||
|
libraries by scanning project source files.
|
||||||
|
|
||||||
|
More information about PlatformIO Library Dependency Finder
|
||||||
|
- https://docs.platformio.org/page/librarymanager/ldf.html
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# KodeDotBSP
|
||||||
|
|
||||||
|
Board Support Package for Kode Dot: display bring-up (Arduino_GFX), LVGL integration and capacitive touch.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Include the public headers with the `kodedot/` prefix:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <kodedot/display_manager.h>
|
||||||
|
#include <kodedot/pin_config.h>
|
||||||
|
```
|
||||||
|
|
||||||
|
Initialize once in `setup()` and update in `loop()`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
DisplayManager display;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
if (!display.init()) {
|
||||||
|
while (1) delay(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
display.update();
|
||||||
|
delay(5);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`pin_config.h` exposes board pins and constants for the Kode Dot.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
- Prefers PSRAM for LVGL draw buffers; falls back to internal SRAM.
|
||||||
|
- Registers LVGL display and input drivers.
|
||||||
|
- Provides simple brightness and touch helpers.
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <Arduino_GFX_Library.h>
|
||||||
|
#include <lvgl.h>
|
||||||
|
#include <kodedot/pin_config.h>
|
||||||
|
#include <bb_captouch.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief High-level manager that initializes and wires up the display, LVGL, and touch input.
|
||||||
|
*
|
||||||
|
* Responsibilities:
|
||||||
|
* - Bring up the panel using Arduino_GFX
|
||||||
|
* - Allocate LVGL draw buffers (prefer PSRAM, fallback to SRAM)
|
||||||
|
* - Register LVGL display and input drivers
|
||||||
|
* - Provide simple helpers for brightness and touch reading
|
||||||
|
*/
|
||||||
|
class DisplayManager {
|
||||||
|
private:
|
||||||
|
// Hardware interfaces
|
||||||
|
Arduino_DataBus *bus;
|
||||||
|
Arduino_CO5300 *gfx;
|
||||||
|
BBCapTouch bbct;
|
||||||
|
|
||||||
|
// LVGL draw buffer and driver handles
|
||||||
|
lv_disp_draw_buf_t draw_buf;
|
||||||
|
lv_color_t *buf;
|
||||||
|
lv_color_t *buf2;
|
||||||
|
lv_disp_drv_t disp_drv;
|
||||||
|
|
||||||
|
// Static callbacks required by LVGL
|
||||||
|
static void disp_flush_callback(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p);
|
||||||
|
static void touchpad_read_callback(lv_indev_drv_t *indev_drv, lv_indev_data_t *data);
|
||||||
|
|
||||||
|
// Singleton-like back-reference used by static callbacks
|
||||||
|
static DisplayManager* instance;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DisplayManager();
|
||||||
|
~DisplayManager();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fully initialize display, LVGL, and touch.
|
||||||
|
* @return true on success, false otherwise
|
||||||
|
*/
|
||||||
|
bool init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the underlying Arduino_GFX panel instance.
|
||||||
|
*/
|
||||||
|
Arduino_CO5300* getGfx() { return gfx; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the touch controller instance.
|
||||||
|
*/
|
||||||
|
BBCapTouch* getTouch() { return &bbct; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pump LVGL timers and tick. Call frequently in loop().
|
||||||
|
*/
|
||||||
|
void update();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set backlight brightness.
|
||||||
|
* @param brightness Range 0-255
|
||||||
|
*/
|
||||||
|
void setBrightness(uint8_t brightness);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read current touch coordinates.
|
||||||
|
* @param x Output X coordinate
|
||||||
|
* @param y Output Y coordinate
|
||||||
|
* @return true if there is an active touch
|
||||||
|
*/
|
||||||
|
bool getTouchCoordinates(int16_t &x, int16_t &y);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
#pragma once
|
||||||
|
/* ---------- Buttons ---------- */
|
||||||
|
#define BUTTON_TOP 0 // GPIO_NUM_0
|
||||||
|
// Bottom button is provided by the IO expander
|
||||||
|
#define BUTTON_BOTTOM EXPANDER_BUTTON_BOTTOM
|
||||||
|
|
||||||
|
/* ---------- NeoPixel LED ---------- */
|
||||||
|
#define LED_STRIP_PIN 4
|
||||||
|
#define LED_STRIP_NUM_LEDS 1
|
||||||
|
#define LED_STRIP_RMT_RES_HZ 10000000 // 10 MHz
|
||||||
|
|
||||||
|
/* ---------- LCD Panel ---------- */
|
||||||
|
#define LCD_WIDTH 410
|
||||||
|
#define LCD_HEIGHT 502
|
||||||
|
#define LCD_SPI_HOST SPI3_HOST
|
||||||
|
#define LCD_PIXEL_CLK_HZ 40000000 // 40 MHz
|
||||||
|
#define LCD_CMD_BITS 8
|
||||||
|
#define LCD_PARAM_BITS 8
|
||||||
|
#define LCD_COLOR_SPACE ESP_LCD_COLOR_SPACE_RGB
|
||||||
|
#define LCD_BITS_PER_PIXEL 16
|
||||||
|
#define LCD_DRAW_BUFF_DOUBLE 1
|
||||||
|
// Use full-height buffer (PSRAM available)
|
||||||
|
#define LCD_DRAW_BUFF_HEIGHT LCD_HEIGHT
|
||||||
|
|
||||||
|
// LCD pins (QSPI)
|
||||||
|
#define LCD_SCLK 17
|
||||||
|
#define LCD_SDIO0 15
|
||||||
|
#define LCD_SDIO1 14
|
||||||
|
#define LCD_SDIO2 16
|
||||||
|
#define LCD_SDIO3 10
|
||||||
|
#define LCD_RST 8
|
||||||
|
#define LCD_CS 9
|
||||||
|
#define LCD_EN -1 // no dedicated enable pin
|
||||||
|
|
||||||
|
/* ---------- Touch / IO Expander ---------- */
|
||||||
|
#define TOUCH_I2C_NUM 0
|
||||||
|
#define TOUCH_I2C_SCL 47
|
||||||
|
#define TOUCH_I2C_SDA 48
|
||||||
|
#define TOUCH_INT -1
|
||||||
|
#define TOUCH_RST -1
|
||||||
|
|
||||||
|
#define IOEXP_I2C_NUM TOUCH_I2C_NUM
|
||||||
|
#define IOEXP_I2C_SCL TOUCH_I2C_SCL
|
||||||
|
#define IOEXP_I2C_SDA TOUCH_I2C_SDA
|
||||||
|
#define IOEXP_I2C_ADDR 0x20 // TCA9555 address 000
|
||||||
|
#define IOEXP_INT_PIN 18
|
||||||
|
|
||||||
|
/* ---------- SD-Card (SDMMC) ---------- */
|
||||||
|
// Host and frequency
|
||||||
|
#define SD_SDMMC_HOST SDMMC_HOST_SLOT_1
|
||||||
|
#define SD_MAX_FREQ_KHZ 50000
|
||||||
|
// SDMMC pins (1-bit width)
|
||||||
|
#define SD_PIN_CMD 5
|
||||||
|
#define SD_PIN_CLK 6
|
||||||
|
#define SD_PIN_D0 7
|
||||||
|
// Card detect via IO expander
|
||||||
|
#define SD_DETECT_PIN EXPANDER_SD_CD
|
||||||
|
// Mount parameters
|
||||||
|
#define SD_MOUNT_POINT "/sdcard"
|
||||||
|
#define SD_MAX_FILES 5
|
||||||
|
#define SD_FORMAT_IF_FAIL 0
|
||||||
|
|
||||||
|
/* ---------- Sensors ---------- */
|
||||||
|
#define MAX17048_I2C_ADDRESS 0x36
|
||||||
|
#define BQ25896_I2C_ADDRESS 0x6A
|
||||||
|
|
||||||
|
/* ---------- IO Expander pin map ---------- */
|
||||||
|
// These defines require including <TCA9555.h> in the source file that uses them
|
||||||
|
#define EXPANDER_MAG_INT 0x00 // P00 - Magnetometer interrupt
|
||||||
|
#define EXPANDER_RTC_INTB 0x01 // P01 - RTC INTB
|
||||||
|
#define EXPANDER_RTC_INTA 0x02 // P02 - RTC INTA
|
||||||
|
#define EXPANDER_SPK_SHUTDOWN 0x03 // P03 - Speaker shutdown
|
||||||
|
#define EXPANDER_PWR_PHRL 0x04 // P04 - Power PHRL
|
||||||
|
#define EXPANDER_FG_ALRT 0x05 // P05 - Fuel gauge alert
|
||||||
|
#define EXPANDER_PAD_TOP 0x06 // P06 - D-pad TOP (external pull-up)
|
||||||
|
#define EXPANDER_PAD_LEFT 0x07 // P07 - D-pad LEFT (external pull-up)
|
||||||
|
#define EXPANDER_PAD_BOTTOM 8 // P10 - D-pad BOTTOM (external pull-up)
|
||||||
|
#define EXPANDER_BUTTON_BOTTOM 9 // P11 - Bottom button (external pull-up)
|
||||||
|
#define EXPANDER_PWR_INT 10 // P12 - Power INT
|
||||||
|
#define EXPANDER_PAD_RIGHT 11 // P13 - D-pad RIGHT (external pull-up)
|
||||||
|
#define EXPANDER_SD_CD 14 // P16 - SD card detect
|
||||||
|
|
||||||
|
/* ---------- NeoPixel convenience ---------- */
|
||||||
|
#define NEO_PIXEL_PIN LED_STRIP_PIN
|
||||||
|
#define NEO_PIXEL_COUNT LED_STRIP_NUM_LEDS
|
||||||
|
// Type: NEO_GRB + NEO_KHZ800 (define in the source using Adafruit_NeoPixel)
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"name": "KodeDotBSP",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"description": "Board Support Package for Kode Dot: display, LVGL and touch bring-up.",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Kode Project",
|
||||||
|
"maintainer": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"build": {
|
||||||
|
"includeDir": "include",
|
||||||
|
"srcDir": "src"
|
||||||
|
},
|
||||||
|
"frameworks": ["arduino"],
|
||||||
|
"platforms": ["espressif32"],
|
||||||
|
"headers": [
|
||||||
|
"kodedot/display_manager.h",
|
||||||
|
"kodedot/pin_config.h"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// src/custom_ota_override.cpp
|
||||||
|
// Strong override of the weak boot/OTA hook in the core.
|
||||||
|
// Returning true means: "do NOT auto-validate the running OTA image".
|
||||||
|
// After any reset, the bootloader will roll back to the last valid app (your factory).
|
||||||
|
|
||||||
|
extern "C" bool verifyRollbackLater(); // must use C linkage to match the weak symbol
|
||||||
|
|
||||||
|
extern "C" bool verifyRollbackLater() {
|
||||||
|
return true; // never auto-validate OTAs
|
||||||
|
}
|
||||||
@@ -0,0 +1,204 @@
|
|||||||
|
#include <kodedot/display_manager.h>
|
||||||
|
#include <Preferences.h>
|
||||||
|
|
||||||
|
// Forward declarations for internal helpers
|
||||||
|
extern "C" void __wrap_esp_ota_mark_app_valid_cancel_rollback(void);
|
||||||
|
void init_nvs();
|
||||||
|
void lvgl_port_rounder_callback(lv_disp_drv_t *disp_drv, lv_area_t *area);
|
||||||
|
|
||||||
|
// Static instance used by LVGL callbacks
|
||||||
|
DisplayManager* DisplayManager::instance = nullptr;
|
||||||
|
|
||||||
|
// --- Internal system utilities ---
|
||||||
|
extern "C" void __wrap_esp_ota_mark_app_valid_cancel_rollback(void) {
|
||||||
|
// no-op: always disables OTA validation
|
||||||
|
}
|
||||||
|
|
||||||
|
static Preferences prefs;
|
||||||
|
|
||||||
|
void init_nvs() {
|
||||||
|
// Initialize NVS namespace for application storage
|
||||||
|
prefs.begin("kode_storage", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- LVGL helper ---
|
||||||
|
void lvgl_port_rounder_callback(lv_disp_drv_t *disp_drv, lv_area_t *area) {
|
||||||
|
// Efficiently align area to even/odd boundaries as required by the panel
|
||||||
|
area->x1 &= ~1; // round down to even
|
||||||
|
area->y1 &= ~1;
|
||||||
|
area->x2 = (area->x2 & ~1) + 1; // round up to odd
|
||||||
|
area->y2 = (area->y2 & ~1) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayManager::DisplayManager() : bus(nullptr), gfx(nullptr), buf(nullptr), buf2(nullptr) {
|
||||||
|
instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayManager::~DisplayManager() {
|
||||||
|
if (buf) free(buf);
|
||||||
|
if (buf2) free(buf2);
|
||||||
|
if (gfx) {
|
||||||
|
delete gfx;
|
||||||
|
}
|
||||||
|
if (bus) {
|
||||||
|
delete bus;
|
||||||
|
}
|
||||||
|
instance = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DisplayManager::init() {
|
||||||
|
Serial.println("Bringing up display subsystem...");
|
||||||
|
|
||||||
|
// Initialize NVS (preferences)
|
||||||
|
init_nvs();
|
||||||
|
|
||||||
|
// Power on the panel if an enable pin is provided
|
||||||
|
if (LCD_EN >= 0) {
|
||||||
|
pinMode(LCD_EN, OUTPUT);
|
||||||
|
digitalWrite(LCD_EN, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
bus = new Arduino_ESP32QSPI(
|
||||||
|
LCD_CS, LCD_SCLK, LCD_SDIO0, LCD_SDIO1, LCD_SDIO2, LCD_SDIO3
|
||||||
|
);
|
||||||
|
|
||||||
|
gfx = new Arduino_CO5300(
|
||||||
|
bus, LCD_RST, 0, LCD_WIDTH, LCD_HEIGHT,
|
||||||
|
22, 0, 0, 0
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!gfx->begin()) {
|
||||||
|
Serial.println("Error: failed to initialize panel");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx->setRotation(0);
|
||||||
|
// Load brightness percentage (0-100) from NVS and apply to panel (0-255)
|
||||||
|
{
|
||||||
|
uint8_t saved_pct = prefs.getUChar("brightness_pct", 100);
|
||||||
|
if (saved_pct > 100) saved_pct = 100;
|
||||||
|
uint8_t saved_brightness = (uint8_t)(((uint16_t)saved_pct * 255 + 50) / 100); // round
|
||||||
|
gfx->setBrightness(saved_brightness);
|
||||||
|
Serial.printf("Brightness (pct=%u) applied from NVS\n", (unsigned)saved_pct);
|
||||||
|
}
|
||||||
|
gfx->fillScreen(BLACK);
|
||||||
|
Serial.println("Panel initialized");
|
||||||
|
|
||||||
|
// Initialize LVGL core
|
||||||
|
lv_init();
|
||||||
|
|
||||||
|
// Allocate draw buffers (prefer PSRAM; fallback to internal SRAM)
|
||||||
|
size_t draw_buf_pixels = (size_t)LCD_WIDTH * (size_t)LCD_DRAW_BUFF_HEIGHT;
|
||||||
|
size_t draw_buf_bytes = draw_buf_pixels * sizeof(lv_color_t);
|
||||||
|
Serial.printf("Requesting LVGL draw buffer: %u bytes\n", (unsigned)draw_buf_bytes);
|
||||||
|
|
||||||
|
buf = (lv_color_t*)heap_caps_malloc(draw_buf_bytes, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||||
|
if (!buf) {
|
||||||
|
// Fallback to internal SRAM with reduced height window
|
||||||
|
size_t fallback_height = 100; // small window to avoid exhausting SRAM
|
||||||
|
draw_buf_pixels = (size_t)LCD_WIDTH * fallback_height;
|
||||||
|
draw_buf_bytes = draw_buf_pixels * sizeof(lv_color_t);
|
||||||
|
Serial.printf("PSRAM not available, using SRAM fallback: %u bytes\n", (unsigned)draw_buf_bytes);
|
||||||
|
buf = (lv_color_t*)heap_caps_malloc(draw_buf_bytes, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||||
|
if (!buf) {
|
||||||
|
Serial.println("Error: unable to allocate draw buffer in SRAM");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try double buffering in PSRAM if there is room
|
||||||
|
buf2 = (lv_color_t*)heap_caps_malloc(draw_buf_bytes, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||||
|
if (!buf2) {
|
||||||
|
// If not enough memory, keep single buffer
|
||||||
|
buf2 = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure LVGL display driver
|
||||||
|
lv_disp_draw_buf_init(&draw_buf, buf, buf2, (uint32_t)draw_buf_pixels);
|
||||||
|
|
||||||
|
// Initialize the display driver
|
||||||
|
lv_disp_drv_init(&disp_drv);
|
||||||
|
disp_drv.hor_res = LCD_WIDTH;
|
||||||
|
disp_drv.ver_res = LCD_HEIGHT;
|
||||||
|
disp_drv.flush_cb = disp_flush_callback;
|
||||||
|
disp_drv.rounder_cb = lvgl_port_rounder_callback; // avoid visual artifacts on odd/even alignment
|
||||||
|
disp_drv.draw_buf = &draw_buf;
|
||||||
|
lv_disp_drv_register(&disp_drv);
|
||||||
|
Serial.println("LVGL initialized");
|
||||||
|
|
||||||
|
// Initialize capacitive touch
|
||||||
|
if(bbct.init(TOUCH_I2C_SDA, TOUCH_I2C_SCL, TOUCH_RST, TOUCH_INT) != CT_SUCCESS) {
|
||||||
|
Serial.println("Error: failed to initialize touch");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
Serial.println("Touch initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register LVGL input driver (touch)
|
||||||
|
static lv_indev_drv_t indev_drv;
|
||||||
|
lv_indev_drv_init(&indev_drv);
|
||||||
|
indev_drv.type = LV_INDEV_TYPE_POINTER;
|
||||||
|
indev_drv.read_cb = touchpad_read_callback;
|
||||||
|
lv_indev_drv_register(&indev_drv);
|
||||||
|
|
||||||
|
Serial.println("Display subsystem ready");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisplayManager::update() {
|
||||||
|
// Advance LVGL tick by 5 ms per iteration
|
||||||
|
lv_tick_inc(5);
|
||||||
|
// Let LVGL process timers
|
||||||
|
lv_timer_handler();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisplayManager::setBrightness(uint8_t brightness) {
|
||||||
|
if (gfx) {
|
||||||
|
gfx->setBrightness(brightness);
|
||||||
|
}
|
||||||
|
// Persist brightness as percentage (0-100) in NVS
|
||||||
|
uint8_t pct = (uint8_t)(((uint16_t)brightness * 100 + 127) / 255); // round
|
||||||
|
if (pct > 100) pct = 100;
|
||||||
|
prefs.putUChar("brightness_pct", pct);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DisplayManager::getTouchCoordinates(int16_t &x, int16_t &y) {
|
||||||
|
TOUCHINFO ti;
|
||||||
|
if(bbct.getSamples(&ti) && ti.count > 0) {
|
||||||
|
x = ti.x[0];
|
||||||
|
y = ti.y[0];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LVGL display flush callback
|
||||||
|
void DisplayManager::disp_flush_callback(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) {
|
||||||
|
if (!instance || !instance->gfx) return;
|
||||||
|
|
||||||
|
uint32_t w = (area->x2 - area->x1 + 1);
|
||||||
|
uint32_t h = (area->y2 - area->y1 + 1);
|
||||||
|
|
||||||
|
instance->gfx->startWrite();
|
||||||
|
instance->gfx->writeAddrWindow(area->x1, area->y1, w, h);
|
||||||
|
instance->gfx->writePixels((uint16_t *)&color_p->full, w * h);
|
||||||
|
instance->gfx->endWrite();
|
||||||
|
|
||||||
|
lv_disp_flush_ready(disp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// LVGL touch read callback
|
||||||
|
void DisplayManager::touchpad_read_callback(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) {
|
||||||
|
if (!instance) return;
|
||||||
|
|
||||||
|
TOUCHINFO ti;
|
||||||
|
if(instance->bbct.getSamples(&ti) && ti.count > 0) {
|
||||||
|
data->state = LV_INDEV_STATE_PRESSED;
|
||||||
|
data->point.x = ti.x[0];
|
||||||
|
data->point.y = ti.y[0];
|
||||||
|
} else {
|
||||||
|
data->state = LV_INDEV_STATE_RELEASED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# Name, Type, SubType, Offset, Size, Flags
|
||||||
|
nvs, data, nvs, 0x9000, 0x6000,
|
||||||
|
phy_init, data, phy, 0xf000, 0x1000,
|
||||||
|
otadata, data, ota, 0x10000, 0x2000,
|
||||||
|
app, app, factory, 0x400000, 0x800000,
|
||||||
|
storage, data, spiffs, 0xC00000, 0x400000,
|
||||||
|
@@ -0,0 +1,65 @@
|
|||||||
|
; PlatformIO Project Configuration File
|
||||||
|
;
|
||||||
|
; Build options: build flags, source filter
|
||||||
|
; Upload options: custom upload port, speed and extra flags
|
||||||
|
; Library options: dependencies, extra library storages
|
||||||
|
; Advanced options: extra scripting
|
||||||
|
;
|
||||||
|
; Please visit documentation for the other options and examples
|
||||||
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
; ==============================================================
|
||||||
|
; BaseApp for Kode Dot (ESP32‑S3)
|
||||||
|
; Builds Arduino firmware and flashes app only (keeps bootloader/partitions).
|
||||||
|
; ==============================================================
|
||||||
|
[platformio]
|
||||||
|
; Default environment
|
||||||
|
default_envs = kode_dot
|
||||||
|
|
||||||
|
[env:kode_dot]
|
||||||
|
; Kode Dot target (ESP32‑S3)
|
||||||
|
; ESP32 platform (pinned stable)
|
||||||
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/stable/platform-espressif32.zip
|
||||||
|
; Board id (see boards/kode_dot.json)
|
||||||
|
board = kode_dot
|
||||||
|
framework = arduino
|
||||||
|
lib_compat_mode = off
|
||||||
|
monitor_speed = 115200
|
||||||
|
lib_ldf_mode = chain+
|
||||||
|
; Serial monitor filters
|
||||||
|
monitor_filters = time, esp32_exception_decoder
|
||||||
|
; Build flags
|
||||||
|
build_flags =
|
||||||
|
; Add include path for src
|
||||||
|
-I src
|
||||||
|
; Wrap OTA validation/rollback
|
||||||
|
-Wl,--wrap=esp_ota_mark_app_valid_cancel_rollback
|
||||||
|
; Enable LVGL simple include
|
||||||
|
-DLV_CONF_INCLUDE_SIMPLE
|
||||||
|
; Suppress deprecation warnings
|
||||||
|
-Wno-deprecated-declarations
|
||||||
|
; Allow #warning without failing build
|
||||||
|
-Wno-cpp
|
||||||
|
; Suppress narrowing conversion warnings
|
||||||
|
-Wno-narrowing
|
||||||
|
; Pre-build scripts
|
||||||
|
extra_scripts = pre:extra_scripts/auto_port.py, pre:extra_scripts/rename_bin.py
|
||||||
|
upload_protocol = custom
|
||||||
|
upload_port = auto
|
||||||
|
monitor_port = auto
|
||||||
|
upload_speed = 460800
|
||||||
|
; Flash app at 0x400000 (preserve bootloader/partitions)
|
||||||
|
upload_command = esptool --chip esp32s3 --port ${UPLOAD_PORT} --baud ${UPLOAD_SPEED} write-flash --flash-freq 80m --flash-mode dio --flash-size 32MB 0x400000 "${BUILD_DIR}/${PROGNAME}.bin"
|
||||||
|
|
||||||
|
; Libraries
|
||||||
|
lib_deps =
|
||||||
|
adafruit/Adafruit BusIO @ ^1.15.0
|
||||||
|
adafruit/Adafruit Unified Sensor @ ^1.1.4
|
||||||
|
moononournation/GFX Library for Arduino @ ^1.6.0
|
||||||
|
lvgl/lvgl @ ^8.3.9
|
||||||
|
adafruit/Adafruit NeoPixel
|
||||||
|
https://github.com/RobTillaart/TCA9555.git#0.4.3
|
||||||
|
adafruit/Adafruit LSM6DS @ ^4.7.4
|
||||||
|
adafruit/Adafruit LIS2MDL @ ^2.1.8
|
||||||
|
adafruit/Adafruit MAX1704X @ ^1.0.3
|
||||||
|
https://github.com/bitbank2/bb_captouch.git
|
||||||
|
https://github.com/andhieSetyabudi/BQ25896.git
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+11975
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+19705
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,85 @@
|
|||||||
|
#ifndef LV_CONF_H
|
||||||
|
#define LV_CONF_H
|
||||||
|
|
||||||
|
#define LV_USE_DEV_VERSION 1
|
||||||
|
|
||||||
|
/* Color settings */
|
||||||
|
#define LV_COLOR_DEPTH 16
|
||||||
|
#define LV_COLOR_16_SWAP 0
|
||||||
|
|
||||||
|
/* Memory settings */
|
||||||
|
#define LV_MEM_CUSTOM 0
|
||||||
|
#define LV_MEM_SIZE (64U * 1024U)
|
||||||
|
|
||||||
|
/* HAL settings */
|
||||||
|
#define LV_DISP_DEF_REFR_PERIOD 30
|
||||||
|
#define LV_INDEV_DEF_READ_PERIOD 30
|
||||||
|
|
||||||
|
/* Feature usage */
|
||||||
|
#define LV_USE_ANIMATION 1
|
||||||
|
#define LV_USE_SHADOW 1
|
||||||
|
#define LV_USE_BLEND_MODES 1
|
||||||
|
#define LV_USE_OPA_SCALE 1
|
||||||
|
#define LV_USE_IMG_TRANSFORM 1
|
||||||
|
|
||||||
|
/* Widget usage */
|
||||||
|
#define LV_USE_ARC 1
|
||||||
|
#define LV_USE_ANIMIMG 1
|
||||||
|
#define LV_USE_BAR 1
|
||||||
|
#define LV_USE_BTN 1
|
||||||
|
#define LV_USE_BTNMATRIX 1
|
||||||
|
#define LV_USE_CANVAS 1
|
||||||
|
#define LV_USE_CHECKBOX 1
|
||||||
|
#define LV_USE_DROPDOWN 1
|
||||||
|
#define LV_USE_IMG 1
|
||||||
|
#define LV_USE_LABEL 1
|
||||||
|
#define LV_USE_LINE 1
|
||||||
|
#define LV_USE_LIST 1
|
||||||
|
#define LV_USE_METER 1
|
||||||
|
#define LV_USE_MSGBOX 1
|
||||||
|
#define LV_USE_ROLLER 1
|
||||||
|
#define LV_USE_SLIDER 1
|
||||||
|
#define LV_USE_SPAN 1
|
||||||
|
#define LV_USE_SPINBOX 1
|
||||||
|
#define LV_USE_SPINNER 1
|
||||||
|
#define LV_USE_SWITCH 1
|
||||||
|
#define LV_USE_TEXTAREA 1
|
||||||
|
#define LV_USE_TABLE 1
|
||||||
|
#define LV_USE_TABVIEW 1
|
||||||
|
#define LV_USE_TILEVIEW 1
|
||||||
|
#define LV_USE_WIN 1
|
||||||
|
|
||||||
|
/* Themes */
|
||||||
|
#define LV_USE_THEME_DEFAULT 1
|
||||||
|
#define LV_USE_THEME_BASIC 1
|
||||||
|
|
||||||
|
/* Font usage */
|
||||||
|
#define LV_FONT_MONTSERRAT_14 1
|
||||||
|
#define LV_FONT_MONTSERRAT_18 1
|
||||||
|
#define LV_FONT_MONTSERRAT_22 1
|
||||||
|
#define LV_FONT_MONTSERRAT_26 1
|
||||||
|
#define LV_FONT_MONTSERRAT_30 1
|
||||||
|
#define LV_FONT_MONTSERRAT_34 1
|
||||||
|
#define LV_FONT_MONTSERRAT_38 1
|
||||||
|
#define LV_FONT_MONTSERRAT_42 1
|
||||||
|
#define LV_FONT_MONTSERRAT_46 1
|
||||||
|
#define LV_FONT_MONTSERRAT_48 1
|
||||||
|
|
||||||
|
/* Others */
|
||||||
|
#define LV_USE_PERF_MONITOR 0
|
||||||
|
#define LV_USE_MEM_MONITOR 0
|
||||||
|
#define LV_USE_REFR_DEBUG 0
|
||||||
|
|
||||||
|
/* Compiler settings */
|
||||||
|
#define LV_ATTRIBUTE_TICK_INC
|
||||||
|
#define LV_ATTRIBUTE_TIMER_HANDLER
|
||||||
|
#define LV_ATTRIBUTE_FLUSH_READY
|
||||||
|
#define LV_ATTRIBUTE_MEM_ALIGN
|
||||||
|
#define LV_ATTRIBUTE_LARGE_CONST
|
||||||
|
#define LV_ATTRIBUTE_LARGE_RAM_ARRAY
|
||||||
|
|
||||||
|
/* HAL settings */
|
||||||
|
#define LV_TICK_CUSTOM 0
|
||||||
|
#define LV_DPI_DEF 130
|
||||||
|
|
||||||
|
#endif /*LV_CONF_H*/
|
||||||
+188
@@ -0,0 +1,188 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <lvgl.h>
|
||||||
|
#include <kodedot/display_manager.h>
|
||||||
|
#include <TCA9555.h>
|
||||||
|
#include <kodedot/pin_config.h>
|
||||||
|
#include <Adafruit_NeoPixel.h>
|
||||||
|
|
||||||
|
// Display manager instance
|
||||||
|
DisplayManager display;
|
||||||
|
|
||||||
|
// UI labels
|
||||||
|
static lv_obj_t *touch_label;
|
||||||
|
static lv_obj_t *button_label;
|
||||||
|
|
||||||
|
// IO Expander
|
||||||
|
static TCA9555 ioexp(IOEXP_I2C_ADDR);
|
||||||
|
|
||||||
|
// NeoPixel
|
||||||
|
static Adafruit_NeoPixel pixel(NEO_PIXEL_COUNT, NEO_PIXEL_PIN, NEO_GRB + NEO_KHZ800);
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
void createUserInterface();
|
||||||
|
void createFontExamples(lv_obj_t *parent);
|
||||||
|
void updateTouchDisplay();
|
||||||
|
void updateButtonDisplay();
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("Starting Base Project with LVGL...");
|
||||||
|
|
||||||
|
// Initialize display subsystem
|
||||||
|
if (!display.init()) {
|
||||||
|
Serial.println("Error: Failed to initialize display");
|
||||||
|
while(1) {
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the UI
|
||||||
|
createUserInterface();
|
||||||
|
|
||||||
|
// Initialize IO Expander (inputs)
|
||||||
|
if (!ioexp.begin(INPUT)) {
|
||||||
|
Serial.println("Warning: IO Expander not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure TOP button (GPIO with external pull-up)
|
||||||
|
pinMode(BUTTON_TOP, INPUT);
|
||||||
|
|
||||||
|
// Initialize NeoPixel
|
||||||
|
pixel.begin();
|
||||||
|
pixel.setBrightness(64);
|
||||||
|
pixel.clear();
|
||||||
|
pixel.show();
|
||||||
|
|
||||||
|
Serial.println("System ready!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// Pump display subsystem
|
||||||
|
display.update();
|
||||||
|
|
||||||
|
// Update touch coordinates on the UI
|
||||||
|
updateTouchDisplay();
|
||||||
|
updateButtonDisplay();
|
||||||
|
|
||||||
|
delay(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create the main user interface
|
||||||
|
*/
|
||||||
|
void createUserInterface() {
|
||||||
|
lv_obj_t * scr = lv_scr_act();
|
||||||
|
lv_obj_set_style_bg_color(scr, lv_color_hex(0x111111), 0);
|
||||||
|
|
||||||
|
// Title
|
||||||
|
lv_obj_t * title = lv_label_create(scr);
|
||||||
|
lv_obj_set_style_text_font(title, &lv_font_montserrat_30, 0);
|
||||||
|
lv_label_set_text(title, "Base Project");
|
||||||
|
lv_obj_set_style_text_color(title, lv_color_hex(0xFFFFFF), 0);
|
||||||
|
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 30);
|
||||||
|
|
||||||
|
// Label for touch coordinates
|
||||||
|
touch_label = lv_label_create(scr);
|
||||||
|
lv_obj_set_style_text_font(touch_label, &lv_font_montserrat_22, 0);
|
||||||
|
lv_label_set_text(touch_label, "Touch: (-, -)");
|
||||||
|
lv_obj_set_style_text_color(touch_label, lv_color_hex(0x00FF00), 0);
|
||||||
|
lv_obj_align(touch_label, LV_ALIGN_CENTER, 0, 0);
|
||||||
|
|
||||||
|
// Label for buttons state (expander)
|
||||||
|
button_label = lv_label_create(scr);
|
||||||
|
lv_obj_set_style_text_font(button_label, &lv_font_montserrat_18, 0);
|
||||||
|
lv_label_set_text(button_label, "Button: none");
|
||||||
|
lv_obj_set_style_text_color(button_label, lv_color_hex(0x66CCFF), 0);
|
||||||
|
lv_obj_align(button_label, LV_ALIGN_BOTTOM_MID, 0, -10);
|
||||||
|
|
||||||
|
// Ejemplos de diferentes fuentes
|
||||||
|
createFontExamples(scr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create sample labels using different font sizes
|
||||||
|
*/
|
||||||
|
void createFontExamples(lv_obj_t *parent) {
|
||||||
|
// Small font
|
||||||
|
lv_obj_t * font_small = lv_label_create(parent);
|
||||||
|
lv_obj_set_style_text_font(font_small, &lv_font_montserrat_14, 0);
|
||||||
|
lv_label_set_text(font_small, "Montserrat 14px");
|
||||||
|
lv_obj_set_style_text_color(font_small, lv_color_hex(0xCCCCCC), 0);
|
||||||
|
lv_obj_align(font_small, LV_ALIGN_BOTTOM_LEFT, 20, -80);
|
||||||
|
|
||||||
|
// Medium font
|
||||||
|
lv_obj_t * font_medium = lv_label_create(parent);
|
||||||
|
lv_obj_set_style_text_font(font_medium, &lv_font_montserrat_18, 0);
|
||||||
|
lv_label_set_text(font_medium, "Montserrat 18px");
|
||||||
|
lv_obj_set_style_text_color(font_medium, lv_color_hex(0xCCCCCC), 0);
|
||||||
|
lv_obj_align(font_medium, LV_ALIGN_BOTTOM_LEFT, 20, -50);
|
||||||
|
|
||||||
|
// Large font
|
||||||
|
lv_obj_t * font_large = lv_label_create(parent);
|
||||||
|
lv_obj_set_style_text_font(font_large, &lv_font_montserrat_42, 0);
|
||||||
|
lv_label_set_text(font_large, "42");
|
||||||
|
lv_obj_set_style_text_color(font_large, lv_color_hex(0x999999), 0);
|
||||||
|
lv_obj_align(font_large, LV_ALIGN_BOTTOM_RIGHT, -30, -30);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update the touch coordinates label
|
||||||
|
*/
|
||||||
|
void updateTouchDisplay() {
|
||||||
|
if (!touch_label) return;
|
||||||
|
|
||||||
|
int16_t x, y;
|
||||||
|
if (display.getTouchCoordinates(x, y)) {
|
||||||
|
lv_label_set_text_fmt(touch_label, "Touch: (%d, %d)", x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isPressed(uint8_t pinIndex) {
|
||||||
|
// Entradas con pull-up externa: activo en LOW
|
||||||
|
int v = ioexp.read1(pinIndex);
|
||||||
|
return (v != TCA9555_INVALID_READ) && (v == LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isGpioPressed(int gpio) {
|
||||||
|
return digitalRead(gpio) == LOW; // activo en LOW por pull-up externa
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateButtonDisplay() {
|
||||||
|
if (!button_label) return;
|
||||||
|
|
||||||
|
const char* status = "none";
|
||||||
|
|
||||||
|
if (isGpioPressed(BUTTON_TOP)) {
|
||||||
|
status = "BUTTON_TOP";
|
||||||
|
} else if (isPressed(EXPANDER_BUTTON_BOTTOM)) {
|
||||||
|
status = "BUTTON_BOTTOM";
|
||||||
|
} else if (isPressed(EXPANDER_PAD_TOP)) {
|
||||||
|
status = "PAD_TOP";
|
||||||
|
} else if (isPressed(EXPANDER_PAD_BOTTOM)) {
|
||||||
|
status = "PAD_BOTTOM";
|
||||||
|
} else if (isPressed(EXPANDER_PAD_LEFT)) {
|
||||||
|
status = "PAD_LEFT";
|
||||||
|
} else if (isPressed(EXPANDER_PAD_RIGHT)) {
|
||||||
|
status = "PAD_RIGHT";
|
||||||
|
}
|
||||||
|
|
||||||
|
lv_label_set_text_fmt(button_label, "Button: %s", status);
|
||||||
|
|
||||||
|
// Actualizar NeoPixel según botón
|
||||||
|
uint32_t color = pixel.Color(0, 0, 0);
|
||||||
|
if (status == (const char*)"BUTTON_TOP") {
|
||||||
|
color = pixel.Color(255, 0, 0); // rojo
|
||||||
|
} else if (status == (const char*)"BOTON_INFERIOR") {
|
||||||
|
color = pixel.Color(0, 0, 255); // azul
|
||||||
|
} else if (status == (const char*)"PAD_TOP") {
|
||||||
|
color = pixel.Color(255, 255, 0); // amarillo
|
||||||
|
} else if (status == (const char*)"PAD_BOTTOM") {
|
||||||
|
color = pixel.Color(255, 0, 255); // magenta
|
||||||
|
} else if (status == (const char*)"PAD_LEFT") {
|
||||||
|
color = pixel.Color(0, 255, 0); // verde
|
||||||
|
} else if (status == (const char*)"PAD_RIGHT") {
|
||||||
|
color = pixel.Color(0, 255, 255); // cian
|
||||||
|
}
|
||||||
|
pixel.setPixelColor(0, color);
|
||||||
|
pixel.show();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user