From c98cb2bf10242d0d833b010209eea82255e7f44a Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Wed, 7 Jan 2026 22:41:45 +0100 Subject: [PATCH] Add Guition JC1060P470CIWY and update other Guition device IDs (#447) This commit contains @josemalm32 's implementation for the Guition JC1060P470CIWY (see https://github.com/ByteWelder/Tactility/issues/427) I've added these changes: - Updated the branch for the new logging method - Updated the branch for the PR that I mentioned in the above linked issue - Replaced the manually pasted in esp_lcd_jd9165 driver with the one from the component registry - Updated Spanish to English - Updated all drivers' mutexes/locks - Fixed the display color format - Fixed bug in power deinit - Renamed I2C bus in config - Added device to continuous integration - Renamed several Guition devices from CYD to Guition - Fix for `EspLcdDisplayV2` init for when features are not supported - Pin esp_wifi_remote to version 1.2.3 - Fix in `WifiManage` logging - Fix for `WifiEsp.cpp`'s check for wifi presence - Fix for `WifiEsp`'s scan list logging - Fix for `gcc_soft_float_symbols` in TactiltyC --- .github/workflows/build.yml | 5 +- Data/data/settings/system.properties | 4 +- Devices/guition-jc1060p470ciwy/CMakeLists.txt | 8 + .../Source/Configuration.cpp | 38 +++ .../Source/devices/Display.cpp | 65 +++++ .../Source/devices/Display.h | 0 .../Source/devices/Jd9165Display.cpp | 203 ++++++++++++++ .../Source/devices/Jd9165Display.h | 44 +++ .../Source/devices/Power.cpp | 180 +++++++++++++ .../Source/devices/Power.h | 7 + .../Source/devices/SdCard.cpp | 127 +++++++++ .../Source/devices/SdCard.h | 6 + .../guition-jc1060p470ciwy/device.properties | 28 ++ .../CMakeLists.txt | 0 .../Source/Configuration.cpp | 0 .../Source/devices/Display.cpp | 0 .../Source/devices/Display.h | 0 .../Source/devices/SdCard.cpp | 0 .../Source/devices/SdCard.h | 0 .../device.properties | 2 +- .../CMakeLists.txt | 0 .../Source/Configuration.cpp | 0 .../Source/devices/Display.cpp | 0 .../Source/devices/Display.h | 5 + .../Source/devices/SdCard.cpp | 0 .../Source/devices/SdCard.h | 0 .../device.properties | 2 +- .../EspLcdCompat/Source/EspLcdDisplayV2.cpp | 21 +- Drivers/EspLcdCompat/Source/EspLcdDisplayV2.h | 7 + Firmware/Kconfig | 17 +- Firmware/idf_component.yml | 13 + Tactility/Source/Tactility.cpp | 8 +- Tactility/Source/app/chat/ChatApp.cpp | 2 +- .../Source/app/wifimanage/WifiManage.cpp | 7 +- Tactility/Source/service/espnow/EspNow.cpp | 2 +- .../Source/service/espnow/EspNowService.cpp | 2 +- .../Source/service/espnow/EspNowWifi.cpp | 2 +- Tactility/Source/service/wifi/WifiEsp.cpp | 30 ++- Tactility/Source/service/wifi/WifiMock.cpp | 2 +- TactilityC/Source/symbols/gcc_soft_float.cpp | 1 + .../Source/symbols/gcc_soft_float_p4.cpp | 255 ++++++++++++++++++ TactilityC/Source/symbols/pthread.cpp | 6 + TactilityC/Source/tt_init.cpp | 4 - TactilityCore/Source/CpuAffinity.cpp | 3 +- 44 files changed, 1060 insertions(+), 46 deletions(-) create mode 100644 Devices/guition-jc1060p470ciwy/CMakeLists.txt create mode 100644 Devices/guition-jc1060p470ciwy/Source/Configuration.cpp create mode 100644 Devices/guition-jc1060p470ciwy/Source/devices/Display.cpp rename Devices/{cyd-jc8048w550c => guition-jc1060p470ciwy}/Source/devices/Display.h (100%) create mode 100644 Devices/guition-jc1060p470ciwy/Source/devices/Jd9165Display.cpp create mode 100644 Devices/guition-jc1060p470ciwy/Source/devices/Jd9165Display.h create mode 100644 Devices/guition-jc1060p470ciwy/Source/devices/Power.cpp create mode 100644 Devices/guition-jc1060p470ciwy/Source/devices/Power.h create mode 100644 Devices/guition-jc1060p470ciwy/Source/devices/SdCard.cpp create mode 100644 Devices/guition-jc1060p470ciwy/Source/devices/SdCard.h create mode 100644 Devices/guition-jc1060p470ciwy/device.properties rename Devices/{cyd-jc2432w328c => guition-jc2432w328c}/CMakeLists.txt (100%) rename Devices/{cyd-jc2432w328c => guition-jc2432w328c}/Source/Configuration.cpp (100%) rename Devices/{cyd-jc2432w328c => guition-jc2432w328c}/Source/devices/Display.cpp (100%) rename Devices/{cyd-jc2432w328c => guition-jc2432w328c}/Source/devices/Display.h (100%) rename Devices/{cyd-jc2432w328c => guition-jc2432w328c}/Source/devices/SdCard.cpp (100%) rename Devices/{cyd-jc2432w328c => guition-jc2432w328c}/Source/devices/SdCard.h (100%) rename Devices/{cyd-jc2432w328c => guition-jc2432w328c}/device.properties (90%) rename Devices/{cyd-jc8048w550c => guition-jc8048w550c}/CMakeLists.txt (100%) rename Devices/{cyd-jc8048w550c => guition-jc8048w550c}/Source/Configuration.cpp (100%) rename Devices/{cyd-jc8048w550c => guition-jc8048w550c}/Source/devices/Display.cpp (100%) create mode 100644 Devices/guition-jc8048w550c/Source/devices/Display.h rename Devices/{cyd-jc8048w550c => guition-jc8048w550c}/Source/devices/SdCard.cpp (100%) rename Devices/{cyd-jc8048w550c => guition-jc8048w550c}/Source/devices/SdCard.h (100%) rename Devices/{cyd-jc8048w550c => guition-jc8048w550c}/device.properties (92%) create mode 100644 TactilityC/Source/symbols/gcc_soft_float_p4.cpp diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e360b645..6c3441d4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -39,9 +39,7 @@ jobs: { id: cyd-e32r28t, arch: esp32 }, { id: cyd-e32r32p, arch: esp32 }, { id: cyd-2432s032c, arch: esp32 }, - { id: cyd-jc2432w328c, arch: esp32 }, { id: cyd-8048s043c, arch: esp32s3 }, - { id: cyd-jc8048w550c, arch: esp32s3 }, { id: cyd-4848s040c, arch: esp32s3 }, { id: elecrow-crowpanel-advance-28, arch: esp32s3 }, { id: elecrow-crowpanel-advance-35, arch: esp32s3 }, @@ -49,6 +47,9 @@ jobs: { id: elecrow-crowpanel-basic-28, arch: esp32 }, { id: elecrow-crowpanel-basic-35, arch: esp32 }, { id: elecrow-crowpanel-basic-50, arch: esp32s3 }, + { id: guition-jc1060p470ciwy, arch: esp32p4 }, + { id: guition-jc2432w328c, arch: esp32 }, + { id: guition-jc8048w550c, arch: esp32s3 }, { id: heltec-wifi-lora-32-v3, arch: esp32s3 }, { id: lilygo-tdeck, arch: esp32s3 }, { id: lilygo-tdongle-s3, arch: esp32s3 }, diff --git a/Data/data/settings/system.properties b/Data/data/settings/system.properties index f8c4da64..8f251bec 100644 --- a/Data/data/settings/system.properties +++ b/Data/data/settings/system.properties @@ -1,5 +1,5 @@ language=en-US timeFormat24h=true -dateFormat=MM/DD/YYYY -region=US +dateFormat=DD/MM/YYYY +region=EU timezone=Europe/Amsterdam \ No newline at end of file diff --git a/Devices/guition-jc1060p470ciwy/CMakeLists.txt b/Devices/guition-jc1060p470ciwy/CMakeLists.txt new file mode 100644 index 00000000..d90d5507 --- /dev/null +++ b/Devices/guition-jc1060p470ciwy/CMakeLists.txt @@ -0,0 +1,8 @@ +file(GLOB_RECURSE SOURCE_FILES Source/*.c*) + +idf_component_register( + SRCS ${SOURCE_FILES} + INCLUDE_DIRS "Source" + REQUIRES Tactility esp_lvgl_port esp_lcd EspLcdCompat esp_lcd_jd9165 GT911 PwmBacklight driver vfs fatfs + PRIV_REQUIRES esp_adc EstimatedPower +) diff --git a/Devices/guition-jc1060p470ciwy/Source/Configuration.cpp b/Devices/guition-jc1060p470ciwy/Source/Configuration.cpp new file mode 100644 index 00000000..69f05b30 --- /dev/null +++ b/Devices/guition-jc1060p470ciwy/Source/Configuration.cpp @@ -0,0 +1,38 @@ +#include "devices/Display.h" +#include "devices/Power.h" +#include "devices/SdCard.h" + +#include + +using namespace tt::hal; + +static DeviceVector createDevices() { + return { + createDisplay(), + createSdCard(), + createPower() + }; +} + +extern const Configuration hardwareConfiguration = { + .createDevices = createDevices, + .i2c = { + i2c::Configuration { + .name = "Internal", + .port = I2C_NUM_0, + .initMode = i2c::InitMode::ByTactility, + .isMutable = false, + .config = (i2c_config_t) { + .mode = I2C_MODE_MASTER, + .sda_io_num = GPIO_NUM_7, + .scl_io_num = GPIO_NUM_8, + .sda_pullup_en = true, + .scl_pullup_en = true, + .master = { + .clk_speed = 400000 + }, + .clk_flags = 0 + } + } + } +}; diff --git a/Devices/guition-jc1060p470ciwy/Source/devices/Display.cpp b/Devices/guition-jc1060p470ciwy/Source/devices/Display.cpp new file mode 100644 index 00000000..224dc245 --- /dev/null +++ b/Devices/guition-jc1060p470ciwy/Source/devices/Display.cpp @@ -0,0 +1,65 @@ +#include "Display.h" +#include "Jd9165Display.h" + +#include +#include +#include +#include + +constexpr auto LCD_PIN_RESET = GPIO_NUM_0; // Match P4 EV board reset line +constexpr auto LCD_PIN_BACKLIGHT = GPIO_NUM_23; +constexpr auto LCD_HORIZONTAL_RESOLUTION = 1024; +constexpr auto LCD_VERTICAL_RESOLUTION = 600; + +constexpr auto TOUCH_I2C_PORT = I2C_NUM_0; +constexpr auto TOUCH_I2C_SDA = GPIO_NUM_7; +constexpr auto TOUCH_I2C_SCL = GPIO_NUM_8; +constexpr auto TOUCH_PIN_RESET = GPIO_NUM_NC; +constexpr auto TOUCH_PIN_INTERRUPT = GPIO_NUM_NC; + +static std::shared_ptr createTouch() { + auto configuration = std::make_unique( + TOUCH_I2C_PORT, + LCD_HORIZONTAL_RESOLUTION, + LCD_VERTICAL_RESOLUTION, + false, // swapXY + false, // mirrorX + false, // mirrorY + TOUCH_PIN_RESET, + TOUCH_PIN_INTERRUPT + ); + + return std::make_shared(std::move(configuration)); +} + +std::shared_ptr createDisplay() { + // Initialize PWM backlight + if (!driver::pwmbacklight::init(LCD_PIN_BACKLIGHT, 20000, LEDC_TIMER_1, LEDC_CHANNEL_0)) { + tt::Logger("jc1060p470ciwy").warn("Failed to initialize backlight"); + } + + auto touch = createTouch(); + + auto configuration = std::make_shared(EspLcdConfiguration { + .horizontalResolution = LCD_HORIZONTAL_RESOLUTION, + .verticalResolution = LCD_VERTICAL_RESOLUTION, + .gapX = 0, + .gapY = 0, + .monochrome = false, + .swapXY = false, + .mirrorX = false, + .mirrorY = false, + .invertColor = false, + .bufferSize = 0, // 0 = default (1/10 of screen) + .touch = touch, + .backlightDutyFunction = driver::pwmbacklight::setBacklightDuty, + .resetPin = LCD_PIN_RESET, + .lvglColorFormat = LV_COLOR_FORMAT_RGB565, + .lvglSwapBytes = false, + .rgbElementOrder = LCD_RGB_ELEMENT_ORDER_RGB, + .bitsPerPixel = 16 + }); + + const auto display = std::make_shared(configuration); + return std::reinterpret_pointer_cast(display); +} diff --git a/Devices/cyd-jc8048w550c/Source/devices/Display.h b/Devices/guition-jc1060p470ciwy/Source/devices/Display.h similarity index 100% rename from Devices/cyd-jc8048w550c/Source/devices/Display.h rename to Devices/guition-jc1060p470ciwy/Source/devices/Display.h diff --git a/Devices/guition-jc1060p470ciwy/Source/devices/Jd9165Display.cpp b/Devices/guition-jc1060p470ciwy/Source/devices/Jd9165Display.cpp new file mode 100644 index 00000000..4db01461 --- /dev/null +++ b/Devices/guition-jc1060p470ciwy/Source/devices/Jd9165Display.cpp @@ -0,0 +1,203 @@ +#include "Jd9165Display.h" + +#include + +#include + +static const auto LOGGER = tt::Logger("JD9165"); + +// MIPI DSI PHY power configuration +#define MIPI_DSI_PHY_PWR_LDO_CHAN 3 // LDO_VO3 connects to VDD_MIPI_DPHY +#define MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV 2500 + +// JD9165 initialization commands from ESP32-P4 Function EV Board +// Delays set to match the reference sequence exactly. +static const jd9165_lcd_init_cmd_t jd9165_init_cmds[] = { + {0x30, (uint8_t[]){0x00}, 1, 0}, + {0xF7, (uint8_t[]){0x49,0x61,0x02,0x00}, 4, 0}, + {0x30, (uint8_t[]){0x01}, 1, 0}, + {0x04, (uint8_t[]){0x0C}, 1, 0}, + {0x05, (uint8_t[]){0x00}, 1, 0}, + {0x06, (uint8_t[]){0x00}, 1, 0}, + {0x0B, (uint8_t[]){0x11}, 1, 0}, + {0x17, (uint8_t[]){0x00}, 1, 0}, + {0x20, (uint8_t[]){0x04}, 1, 0}, + {0x1F, (uint8_t[]){0x05}, 1, 0}, + {0x23, (uint8_t[]){0x00}, 1, 0}, + {0x25, (uint8_t[]){0x19}, 1, 0}, + {0x28, (uint8_t[]){0x18}, 1, 0}, + {0x29, (uint8_t[]){0x04}, 1, 0}, + {0x2A, (uint8_t[]){0x01}, 1, 0}, + {0x2B, (uint8_t[]){0x04}, 1, 0}, + {0x2C, (uint8_t[]){0x01}, 1, 0}, + {0x30, (uint8_t[]){0x02}, 1, 0}, + {0x01, (uint8_t[]){0x22}, 1, 0}, + {0x03, (uint8_t[]){0x12}, 1, 0}, + {0x04, (uint8_t[]){0x00}, 1, 0}, + {0x05, (uint8_t[]){0x64}, 1, 0}, + {0x0A, (uint8_t[]){0x08}, 1, 0}, + {0x0B, (uint8_t[]){0x0A,0x1A,0x0B,0x0D,0x0D,0x11,0x10,0x06,0x08,0x1F,0x1D}, 11, 0}, + {0x0C, (uint8_t[]){0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D}, 11, 0}, + {0x0D, (uint8_t[]){0x16,0x1B,0x0B,0x0D,0x0D,0x11,0x10,0x07,0x09,0x1E,0x1C}, 11, 0}, + {0x0E, (uint8_t[]){0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D}, 11, 0}, + {0x0F, (uint8_t[]){0x16,0x1B,0x0D,0x0B,0x0D,0x11,0x10,0x1C,0x1E,0x09,0x07}, 11, 0}, + {0x10, (uint8_t[]){0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D}, 11, 0}, + {0x11, (uint8_t[]){0x0A,0x1A,0x0D,0x0B,0x0D,0x11,0x10,0x1D,0x1F,0x08,0x06}, 11, 0}, + {0x12, (uint8_t[]){0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D}, 11, 0}, + {0x14, (uint8_t[]){0x00,0x00,0x11,0x11}, 4, 0}, + {0x18, (uint8_t[]){0x99}, 1, 0}, + {0x30, (uint8_t[]){0x06}, 1, 0}, + {0x12, (uint8_t[]){0x36,0x2C,0x2E,0x3C,0x38,0x35,0x35,0x32,0x2E,0x1D,0x2B,0x21,0x16,0x29}, 14, 0}, + {0x13, (uint8_t[]){0x36,0x2C,0x2E,0x3C,0x38,0x35,0x35,0x32,0x2E,0x1D,0x2B,0x21,0x16,0x29}, 14, 0}, + {0x30, (uint8_t[]){0x0A}, 1, 0}, + {0x02, (uint8_t[]){0x4F}, 1, 0}, + {0x0B, (uint8_t[]){0x40}, 1, 0}, + {0x12, (uint8_t[]){0x3E}, 1, 0}, + {0x13, (uint8_t[]){0x78}, 1, 0}, + {0x30, (uint8_t[]){0x0D}, 1, 0}, + {0x0D, (uint8_t[]){0x04}, 1, 0}, + {0x10, (uint8_t[]){0x0C}, 1, 0}, + {0x11, (uint8_t[]){0x0C}, 1, 0}, + {0x12, (uint8_t[]){0x0C}, 1, 0}, + {0x13, (uint8_t[]){0x0C}, 1, 0}, + {0x30, (uint8_t[]){0x00}, 1, 0}, + {0X3A, (uint8_t[]){0x55}, 1, 0}, + {0x11, (uint8_t[]){0x00}, 1, 120}, + {0x29, (uint8_t[]){0x00}, 1, 20}, +}; + +Jd9165Display::~Jd9165Display() { + // TODO: This should happen during ::stop(), but this isn't currently exposed + if (mipiDsiBus != nullptr) { + esp_lcd_del_dsi_bus(mipiDsiBus); + mipiDsiBus = nullptr; + } + if (ldoChannel != nullptr) { + esp_ldo_release_channel(ldoChannel); + ldoChannel = nullptr; + } +} + +bool Jd9165Display::createMipiDsiBus() { + // Enable MIPI DSI PHY power (transition from "no power" to "shutdown" state) + esp_ldo_channel_config_t ldo_mipi_phy_config = { + .chan_id = MIPI_DSI_PHY_PWR_LDO_CHAN, + .voltage_mv = MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV, + .flags = {} + }; + + if (esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldoChannel) != ESP_OK) { + LOGGER.error("Failed to acquire LDO channel for MIPI DSI PHY"); + return false; + } + + LOGGER.info("MIPI DSI PHY powered on"); + + // Create MIPI DSI bus + // TODO: use MIPI_DSI_PHY_CLK_SRC_DEFAULT() in future ESP-IDF 6.0.0 update with esp_lcd_jd9165 library version 2.x + const esp_lcd_dsi_bus_config_t bus_config = { + .bus_id = 0, + .num_data_lanes = 2, + .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT, + .lane_bit_rate_mbps = 750 + }; + + if (esp_lcd_new_dsi_bus(&bus_config, &mipiDsiBus) != ESP_OK) { + LOGGER.error("Failed to create MIPI DSI bus"); + return false; + } + + LOGGER.info("MIPI DSI bus created"); + return true; +} + +bool Jd9165Display::createIoHandle(esp_lcd_panel_io_handle_t& ioHandle) { + // Initialize MIPI DSI bus if not already done + if (mipiDsiBus == nullptr) { + if (!createMipiDsiBus()) { + return false; + } + } + + // Use DBI interface to send LCD commands and parameters + esp_lcd_dbi_io_config_t dbi_config = JD9165_PANEL_IO_DBI_CONFIG(); + + if (esp_lcd_new_panel_io_dbi(mipiDsiBus, &dbi_config, &ioHandle) != ESP_OK) { + LOGGER.error("Failed to create panel IO"); + return false; + } + + return true; +} + +esp_lcd_panel_dev_config_t Jd9165Display::createPanelConfig(std::shared_ptr espLcdConfiguration, gpio_num_t resetPin) { + return { + .reset_gpio_num = resetPin, + .rgb_ele_order = espLcdConfiguration->rgbElementOrder, + .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, + .bits_per_pixel = static_cast(espLcdConfiguration->bitsPerPixel), + .flags = { + .reset_active_high = 0 + }, + .vendor_config = nullptr // Will be set in createPanelHandle + }; +} + +bool Jd9165Display::createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_panel_dev_config_t& panelConfig, esp_lcd_panel_handle_t& panelHandle) { + // Create DPI panel configuration + // Override default timings + const esp_lcd_dpi_panel_config_t dpi_config = { + .virtual_channel = 0, + .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, + .dpi_clock_freq_mhz = 50, + .pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565, + .in_color_format = LCD_COLOR_FMT_RGB565, + .out_color_format = LCD_COLOR_FMT_RGB565, + .num_fbs = 1, + .video_timing = { + .h_size = 1024, + .v_size = 600, + .hsync_pulse_width = 20, + .hsync_back_porch = 160, + .hsync_front_porch = 160, + .vsync_pulse_width = 2, + .vsync_back_porch = 21, + .vsync_front_porch = 12, + }, + .flags = { + .use_dma2d = 1, + .disable_lp = 0 + } + }; + + jd9165_vendor_config_t vendor_config = { + .init_cmds = jd9165_init_cmds, + .init_cmds_size = sizeof(jd9165_init_cmds) / sizeof(jd9165_lcd_init_cmd_t), + .mipi_config = { + .dsi_bus = mipiDsiBus, + .dpi_config = &dpi_config, + }, + }; + + // Create a mutable copy of panelConfig to set vendor_config + esp_lcd_panel_dev_config_t mutable_panel_config = panelConfig; + mutable_panel_config.vendor_config = &vendor_config; + + if (esp_lcd_new_panel_jd9165(ioHandle, &mutable_panel_config, &panelHandle) != ESP_OK) { + LOGGER.error("Failed to create panel"); + return false; + } + + LOGGER.info("JD9165 panel created successfully"); + // Defer reset/init to base class applyConfiguration to avoid double initialization + return true; +} + +lvgl_port_display_dsi_cfg_t Jd9165Display::getLvglPortDisplayDsiConfig(esp_lcd_panel_io_handle_t /*ioHandle*/, esp_lcd_panel_handle_t /*panelHandle*/) { + // Disable avoid_tearing to prevent stalls/blank flashes when other tasks (e.g. flash writes) block timing + return lvgl_port_display_dsi_cfg_t{ + .flags = { + .avoid_tearing = 0, + }, + }; +} diff --git a/Devices/guition-jc1060p470ciwy/Source/devices/Jd9165Display.h b/Devices/guition-jc1060p470ciwy/Source/devices/Jd9165Display.h new file mode 100644 index 00000000..0dd66e07 --- /dev/null +++ b/Devices/guition-jc1060p470ciwy/Source/devices/Jd9165Display.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include + +#include +#include + +class Jd9165Display final : public EspLcdDisplayV2 { + + class NoLock final : public tt::Lock { + bool lock(TickType_t timeout) const override { return true; } + void unlock() const override { /* NO-OP */ } + }; + + esp_lcd_dsi_bus_handle_t mipiDsiBus = nullptr; + esp_ldo_channel_handle_t ldoChannel = nullptr; + + bool createMipiDsiBus(); + +protected: + + bool createIoHandle(esp_lcd_panel_io_handle_t& ioHandle) override; + + esp_lcd_panel_dev_config_t createPanelConfig(std::shared_ptr espLcdConfiguration, gpio_num_t resetPin) override; + + bool createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_panel_dev_config_t& panelConfig, esp_lcd_panel_handle_t& panelHandle) override; + + bool useDsiPanel() const override { return true; } + + lvgl_port_display_dsi_cfg_t getLvglPortDisplayDsiConfig(esp_lcd_panel_io_handle_t /*ioHandle*/, esp_lcd_panel_handle_t /*panelHandle*/) override; + +public: + + Jd9165Display( + const std::shared_ptr& configuration + ) : EspLcdDisplayV2(configuration, std::make_shared()) {} + + ~Jd9165Display() override; + + std::string getName() const override { return "JD9165"; } + + std::string getDescription() const override { return "JD9165 MIPI-DSI 1024x600 display"; } +}; diff --git a/Devices/guition-jc1060p470ciwy/Source/devices/Power.cpp b/Devices/guition-jc1060p470ciwy/Source/devices/Power.cpp new file mode 100644 index 00000000..5b6cf83f --- /dev/null +++ b/Devices/guition-jc1060p470ciwy/Source/devices/Power.cpp @@ -0,0 +1,180 @@ +#include "Power.h" + +#include +#include +#include +#include +#include + +using tt::hal::power::PowerDevice; + +static const auto LOGGER = tt::Logger("JcPower"); + +namespace { + +constexpr adc_unit_t ADC_UNIT = ADC_UNIT_2; +constexpr adc_channel_t ADC_CHANNEL = ADC_CHANNEL_4; // matches ADC2 CH4 used in brookesia config +constexpr adc_atten_t ADC_ATTEN = ADC_ATTEN_DB_12; +constexpr int32_t UPPER_RESISTOR_OHM = 85'000; // per brookesia settings +constexpr int32_t LOWER_RESISTOR_OHM = 100'000; // per brookesia settings + +class JcPower final : public PowerDevice { +public: + JcPower() : chargeEstimator(3.3f, 4.2f) {} + ~JcPower() override { deinit(); } + + std::string getName() const override { return "JC Power"; } + std::string getDescription() const override { return "Battery voltage via ADC"; } + + bool supportsMetric(MetricType type) const override { + switch (type) { + using enum MetricType; + case BatteryVoltage: + case ChargeLevel: + return true; + default: + return false; + } + } + + bool getMetric(MetricType type, MetricData& data) override { + if (!ensureInit()) { + return false; + } + + uint32_t batteryMv = 0; + if (!readBatteryMilliVolt(batteryMv)) { + return false; + } + + switch (type) { + case MetricType::BatteryVoltage: + data.valueAsUint32 = batteryMv; + return true; + case MetricType::ChargeLevel: + data.valueAsUint8 = chargeEstimator.estimateCharge(batteryMv); + return true; + default: + return false; + } + } + +private: + bool ensureInit() { + if (initialized) { + return true; + } + + adc_oneshot_unit_init_cfg_t init_cfg = { + .unit_id = ADC_UNIT, + .clk_src = ADC_RTC_CLK_SRC_DEFAULT, + .ulp_mode = ADC_ULP_MODE_DISABLE, + }; + if (adc_oneshot_new_unit(&init_cfg, &adcHandle) != ESP_OK) { + LOGGER.error("ADC unit init failed"); + return false; + } + + adc_oneshot_chan_cfg_t chan_cfg = { + .atten = ADC_ATTEN, + .bitwidth = ADC_BITWIDTH_DEFAULT, + }; + if (adc_oneshot_config_channel(adcHandle, ADC_CHANNEL, &chan_cfg) != ESP_OK) { + LOGGER.error("ADC channel config failed"); + adc_oneshot_del_unit(adcHandle); + adcHandle = nullptr; + return false; + } + + calibrated = tryInitCalibration(); + initialized = true; + return true; + } + + bool tryInitCalibration() { +#if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED + adc_cali_line_fitting_config_t cali_config = { + .unit_id = ADC_UNIT, + .atten = ADC_ATTEN, + .bitwidth = ADC_BITWIDTH_DEFAULT, + }; + if (adc_cali_create_scheme_line_fitting(&cali_config, &caliHandle) == ESP_OK) { + calScheme = CaliScheme::Line; + LOGGER.info("ADC calibration (line fitting) enabled"); + return true; + } +#endif + +#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED + adc_cali_curve_fitting_config_t curve_cfg = { + .unit_id = ADC_UNIT, + .chan = ADC_CHANNEL, + .atten = ADC_ATTEN, + .bitwidth = ADC_BITWIDTH_DEFAULT, + }; + if (adc_cali_create_scheme_curve_fitting(&curve_cfg, &caliHandle) == ESP_OK) { + calScheme = CaliScheme::Curve; + LOGGER.info("ADC calibration (curve fitting) enabled"); + return true; + } +#endif + + LOGGER.warn("ADC calibration not available, using raw scaling"); + return false; + } + + bool readBatteryMilliVolt(uint32_t& outMv) { + int raw = 0; + if (adc_oneshot_read(adcHandle, ADC_CHANNEL, &raw) != ESP_OK) { + LOGGER.error("ADC read failed"); + return false; + } + + int mv = 0; + if (calibrated && adc_cali_raw_to_voltage(caliHandle, raw, &mv) == ESP_OK) { + // ok + } else { + // Fallback: approximate assuming 12-bit full scale 3.3V + mv = (raw * 3300) / 4095; + } + + const int64_t numerator = static_cast(UPPER_RESISTOR_OHM + LOWER_RESISTOR_OHM) * mv; + const int64_t denominator = LOWER_RESISTOR_OHM; + outMv = static_cast(numerator / denominator); + return true; + } + + void deinit() { + if (adcHandle) { + adc_oneshot_del_unit(adcHandle); + adcHandle = nullptr; + } + if (caliHandle) { + if (calScheme == CaliScheme::Line) { +#if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED + adc_cali_delete_scheme_line_fitting(caliHandle); +#endif +#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED + } else if (calScheme == CaliScheme::Curve) { + adc_cali_delete_scheme_curve_fitting(caliHandle); +#endif + } + caliHandle = nullptr; + calibrated = false; + } + } + + enum class CaliScheme { None, Line, Curve }; + + bool initialized = false; + bool calibrated = false; + CaliScheme calScheme = CaliScheme::None; + adc_oneshot_unit_handle_t adcHandle = nullptr; + adc_cali_handle_t caliHandle = nullptr; + ChargeFromVoltage chargeEstimator; +}; +} // namespace + +std::shared_ptr createPower() { + return std::make_shared(); +} diff --git a/Devices/guition-jc1060p470ciwy/Source/devices/Power.h b/Devices/guition-jc1060p470ciwy/Source/devices/Power.h new file mode 100644 index 00000000..111f0a08 --- /dev/null +++ b/Devices/guition-jc1060p470ciwy/Source/devices/Power.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include + +// Battery measurement via ADC2 channel 4 with 85k/100k divider +std::shared_ptr createPower(); diff --git a/Devices/guition-jc1060p470ciwy/Source/devices/SdCard.cpp b/Devices/guition-jc1060p470ciwy/Source/devices/SdCard.cpp new file mode 100644 index 00000000..3a08e11f --- /dev/null +++ b/Devices/guition-jc1060p470ciwy/Source/devices/SdCard.cpp @@ -0,0 +1,127 @@ +#include "SdCard.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using tt::hal::sdcard::SdCardDevice; + +static const auto LOGGER = tt::Logger("JcSdCard"); + +// ESP32-P4 Slot 0 uses IO MUX (fixed pins, not manually configurable) +// CLK=43, CMD=44, D0=39, D1=40, D2=41, D3=42 (defined automatically by hardware) + +class SdCardDeviceImpl final : public SdCardDevice { + + class NoLock final : public tt::Lock { + bool lock(TickType_t timeout) const override { return true; } + void unlock() const override { /* NO-OP */ } + }; + + std::shared_ptr lock = std::make_shared(); + sdmmc_card_t* card = nullptr; + bool mounted = false; + std::string mountPath; + +public: + SdCardDeviceImpl() : SdCardDevice(MountBehaviour::AtBoot) {} + ~SdCardDeviceImpl() override { + if (mounted) { + unmount(); + } + } + + std::string getName() const override { return "SD Card"; } + std::string getDescription() const override { return "SD card via SDMMC host"; } + + bool mount(const std::string& newMountPath) override { + if (mounted) { + return true; + } + + esp_vfs_fat_sdmmc_mount_config_t mount_config = { + .format_if_mount_failed = false, + .max_files = 5, + .allocation_unit_size = 64 * 1024, + .disk_status_check_enable = false, + .use_one_fat = false, + }; + + sdmmc_host_t host = SDMMC_HOST_DEFAULT(); + host.slot = SDMMC_HOST_SLOT_0; + host.max_freq_khz = SDMMC_FREQ_DEFAULT; // 20MHz - more stable for initialization + host.flags = SDMMC_HOST_FLAG_4BIT; // Force 4-bit mode + // Configure LDO power supply for SD card (critical on ESP32-P4) + esp_ldo_channel_handle_t ldo_handle = nullptr; + esp_ldo_channel_config_t ldo_config = { + .chan_id = 4, // LDO channel 4 for SD power + .voltage_mv = 3300, // 3.3V + .flags { + .adjustable = 0, + .owned_by_hw = 0, + .bypass = 0 + } + }; + + esp_err_t ldo_ret = esp_ldo_acquire_channel(&ldo_config, &ldo_handle); + if (ldo_ret != ESP_OK) { + LOGGER.warn("Failed to acquire LDO for SD power: {} (continuing anyway)", esp_err_to_name(ldo_ret)); + } + + // Slot 0 uses IO MUX - pins are fixed and not specified + sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); + slot_config.width = 4; + slot_config.cd = SDMMC_SLOT_NO_CD; // No card detect + slot_config.wp = SDMMC_SLOT_NO_WP; // No write protect + slot_config.flags = 0; + + esp_err_t ret = esp_vfs_fat_sdmmc_mount(newMountPath.c_str(), &host, &slot_config, &mount_config, &card); + if (ret != ESP_OK) { + LOGGER.error("Failed to mount SD card: {}", esp_err_to_name(ret)); + card = nullptr; + return false; + } + + mountPath = newMountPath; + mounted = true; + LOGGER.info("SD card mounted at {}", mountPath); + return true; + } + + bool unmount() override { + if (!mounted) { + return true; + } + + esp_err_t ret = esp_vfs_fat_sdcard_unmount(mountPath.c_str(), card); + if (ret != ESP_OK) { + LOGGER.error("Failed to unmount SD card: {}", esp_err_to_name(ret)); + return false; + } + card = nullptr; + mounted = false; + LOGGER.info("SD card unmounted"); + return true; + } + + std::string getMountPath() const override { + return mountPath; + } + + std::shared_ptr getLock() const override { return lock; } + + State getState(TickType_t /*timeout*/) const override { + return mounted ? State::Mounted : State::Unmounted; + } +}; + +std::shared_ptr createSdCard() { + return std::make_shared(); +} diff --git a/Devices/guition-jc1060p470ciwy/Source/devices/SdCard.h b/Devices/guition-jc1060p470ciwy/Source/devices/SdCard.h new file mode 100644 index 00000000..3e170a56 --- /dev/null +++ b/Devices/guition-jc1060p470ciwy/Source/devices/SdCard.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +// Create SD card device for jc1060p470ciwy using SDMMC slot 0 (4-bit) +std::shared_ptr createSdCard(); diff --git a/Devices/guition-jc1060p470ciwy/device.properties b/Devices/guition-jc1060p470ciwy/device.properties new file mode 100644 index 00000000..ae177ffb --- /dev/null +++ b/Devices/guition-jc1060p470ciwy/device.properties @@ -0,0 +1,28 @@ +[general] +vendor=Guition +name=JC1060P470CIWY + +[hardware] +target=ESP32P4 +flashSize=16MB +spiRam=true +spiRamMode=OCT +spiRamSpeed=200M +esptoolFlashFreq=80M + +[display] +size=7" +shape=rectangle +dpi=187 + +[lvgl] +colorDepth=16 + +[sdkconfig] +CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 +CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 +CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y +CONFIG_ESP_HOSTED_ENABLED=y +CONFIG_ESP_HOSTED_P4_DEV_BOARD_FUNC_BOARD=y +CONFIG_ESP_HOSTED_SDIO_HOST_INTERFACE=y +CONFIG_SLAVE_IDF_TARGET_ESP32C6=y diff --git a/Devices/cyd-jc2432w328c/CMakeLists.txt b/Devices/guition-jc2432w328c/CMakeLists.txt similarity index 100% rename from Devices/cyd-jc2432w328c/CMakeLists.txt rename to Devices/guition-jc2432w328c/CMakeLists.txt diff --git a/Devices/cyd-jc2432w328c/Source/Configuration.cpp b/Devices/guition-jc2432w328c/Source/Configuration.cpp similarity index 100% rename from Devices/cyd-jc2432w328c/Source/Configuration.cpp rename to Devices/guition-jc2432w328c/Source/Configuration.cpp diff --git a/Devices/cyd-jc2432w328c/Source/devices/Display.cpp b/Devices/guition-jc2432w328c/Source/devices/Display.cpp similarity index 100% rename from Devices/cyd-jc2432w328c/Source/devices/Display.cpp rename to Devices/guition-jc2432w328c/Source/devices/Display.cpp diff --git a/Devices/cyd-jc2432w328c/Source/devices/Display.h b/Devices/guition-jc2432w328c/Source/devices/Display.h similarity index 100% rename from Devices/cyd-jc2432w328c/Source/devices/Display.h rename to Devices/guition-jc2432w328c/Source/devices/Display.h diff --git a/Devices/cyd-jc2432w328c/Source/devices/SdCard.cpp b/Devices/guition-jc2432w328c/Source/devices/SdCard.cpp similarity index 100% rename from Devices/cyd-jc2432w328c/Source/devices/SdCard.cpp rename to Devices/guition-jc2432w328c/Source/devices/SdCard.cpp diff --git a/Devices/cyd-jc2432w328c/Source/devices/SdCard.h b/Devices/guition-jc2432w328c/Source/devices/SdCard.h similarity index 100% rename from Devices/cyd-jc2432w328c/Source/devices/SdCard.h rename to Devices/guition-jc2432w328c/Source/devices/SdCard.h diff --git a/Devices/cyd-jc2432w328c/device.properties b/Devices/guition-jc2432w328c/device.properties similarity index 90% rename from Devices/cyd-jc2432w328c/device.properties rename to Devices/guition-jc2432w328c/device.properties index 4f911b92..c18b56df 100644 --- a/Devices/cyd-jc2432w328c/device.properties +++ b/Devices/guition-jc2432w328c/device.properties @@ -1,5 +1,5 @@ [general] -vendor=CYD +vendor=Guition name=JC2432W328C [hardware] diff --git a/Devices/cyd-jc8048w550c/CMakeLists.txt b/Devices/guition-jc8048w550c/CMakeLists.txt similarity index 100% rename from Devices/cyd-jc8048w550c/CMakeLists.txt rename to Devices/guition-jc8048w550c/CMakeLists.txt diff --git a/Devices/cyd-jc8048w550c/Source/Configuration.cpp b/Devices/guition-jc8048w550c/Source/Configuration.cpp similarity index 100% rename from Devices/cyd-jc8048w550c/Source/Configuration.cpp rename to Devices/guition-jc8048w550c/Source/Configuration.cpp diff --git a/Devices/cyd-jc8048w550c/Source/devices/Display.cpp b/Devices/guition-jc8048w550c/Source/devices/Display.cpp similarity index 100% rename from Devices/cyd-jc8048w550c/Source/devices/Display.cpp rename to Devices/guition-jc8048w550c/Source/devices/Display.cpp diff --git a/Devices/guition-jc8048w550c/Source/devices/Display.h b/Devices/guition-jc8048w550c/Source/devices/Display.h new file mode 100644 index 00000000..7a9b967d --- /dev/null +++ b/Devices/guition-jc8048w550c/Source/devices/Display.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +std::shared_ptr createDisplay(); diff --git a/Devices/cyd-jc8048w550c/Source/devices/SdCard.cpp b/Devices/guition-jc8048w550c/Source/devices/SdCard.cpp similarity index 100% rename from Devices/cyd-jc8048w550c/Source/devices/SdCard.cpp rename to Devices/guition-jc8048w550c/Source/devices/SdCard.cpp diff --git a/Devices/cyd-jc8048w550c/Source/devices/SdCard.h b/Devices/guition-jc8048w550c/Source/devices/SdCard.h similarity index 100% rename from Devices/cyd-jc8048w550c/Source/devices/SdCard.h rename to Devices/guition-jc8048w550c/Source/devices/SdCard.h diff --git a/Devices/cyd-jc8048w550c/device.properties b/Devices/guition-jc8048w550c/device.properties similarity index 92% rename from Devices/cyd-jc8048w550c/device.properties rename to Devices/guition-jc8048w550c/device.properties index 6fe99f11..e7c7b4bf 100644 --- a/Devices/cyd-jc8048w550c/device.properties +++ b/Devices/guition-jc8048w550c/device.properties @@ -1,5 +1,5 @@ [general] -vendor=CYD +vendor=Guition name=JC8048W550C [hardware] diff --git a/Drivers/EspLcdCompat/Source/EspLcdDisplayV2.cpp b/Drivers/EspLcdCompat/Source/EspLcdDisplayV2.cpp index 01e018ba..3eba9994 100644 --- a/Drivers/EspLcdCompat/Source/EspLcdDisplayV2.cpp +++ b/Drivers/EspLcdCompat/Source/EspLcdDisplayV2.cpp @@ -34,7 +34,7 @@ bool EspLcdDisplayV2::applyConfiguration() const { return false; } - if (esp_lcd_panel_invert_color(panelHandle, configuration->invertColor) != ESP_OK) { + if (configuration->invertColor && esp_lcd_panel_invert_color(panelHandle, configuration->invertColor) != ESP_OK) { LOGGER.error("Failed to set panel to invert"); return false; } @@ -42,22 +42,24 @@ bool EspLcdDisplayV2::applyConfiguration() const { // Warning: it looks like LVGL rotation is broken when "gap" is set and the screen is moved to a non-default orientation 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) { + bool should_set_gap = gap_x != 0 || gap_y != 0; + if (should_set_gap && esp_lcd_panel_set_gap(panelHandle, gap_x, gap_y) != ESP_OK) { LOGGER.error("Failed to set panel gap"); return false; } - if (esp_lcd_panel_swap_xy(panelHandle, configuration->swapXY) != ESP_OK) { + if (configuration->swapXY && esp_lcd_panel_swap_xy(panelHandle, configuration->swapXY) != ESP_OK) { LOGGER.error("Failed to swap XY "); return false; } - if (esp_lcd_panel_mirror(panelHandle, configuration->mirrorX, configuration->mirrorY) != ESP_OK) { + bool should_set_mirror = configuration->mirrorX || configuration->mirrorY; + if (should_set_mirror && esp_lcd_panel_mirror(panelHandle, configuration->mirrorX, configuration->mirrorY) != ESP_OK) { LOGGER.error("Failed to set panel to mirror"); return false; } - if (esp_lcd_panel_invert_color(panelHandle, configuration->invertColor) != ESP_OK) { + if (configuration->invertColor && esp_lcd_panel_invert_color(panelHandle, configuration->invertColor) != ESP_OK) { LOGGER.error("Failed to set panel to invert"); return false; } @@ -126,11 +128,14 @@ bool EspLcdDisplayV2::startLvgl() { auto lvgl_port_config = getLvglPortDisplayConfig(configuration, ioHandle, panelHandle); - if (isRgbPanel()) { + if (useDsiPanel()) { + auto dsi_config = getLvglPortDisplayDsiConfig(ioHandle, panelHandle); + lvglDisplay = lvgl_port_add_disp_dsi(&lvgl_port_config, &dsi_config); + } else if (isRgbPanel()) { auto rgb_config = getLvglPortDisplayRgbConfig(ioHandle, panelHandle); - lvglDisplay = lvgl_port_add_disp_rgb(&lvgl_port_config , &rgb_config); + lvglDisplay = lvgl_port_add_disp_rgb(&lvgl_port_config, &rgb_config); } else { - lvglDisplay = lvgl_port_add_disp(&lvgl_port_config ); + lvglDisplay = lvgl_port_add_disp(&lvgl_port_config); } auto touch_device = getTouchDevice(); diff --git a/Drivers/EspLcdCompat/Source/EspLcdDisplayV2.h b/Drivers/EspLcdCompat/Source/EspLcdDisplayV2.h index 93d579ae..94c66ec4 100644 --- a/Drivers/EspLcdCompat/Source/EspLcdDisplayV2.h +++ b/Drivers/EspLcdCompat/Source/EspLcdDisplayV2.h @@ -55,6 +55,13 @@ protected: virtual lvgl_port_display_rgb_cfg_t getLvglPortDisplayRgbConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) { tt_crash("Not supported"); } + // Hook for MIPI-DSI DPI panels to let LVGL port use DSI-specific path + virtual bool useDsiPanel() const { return false; } + + virtual lvgl_port_display_dsi_cfg_t getLvglPortDisplayDsiConfig(esp_lcd_panel_io_handle_t /*ioHandle*/, esp_lcd_panel_handle_t /*panelHandle*/) { + return lvgl_port_display_dsi_cfg_t{ .flags = { .avoid_tearing = 0 } }; + } + // Used for sending commands such as setting curves esp_lcd_panel_io_handle_t getIoHandle() const { return ioHandle; } diff --git a/Firmware/Kconfig b/Firmware/Kconfig index 64f5b5d4..1aded79f 100644 --- a/Firmware/Kconfig +++ b/Firmware/Kconfig @@ -27,10 +27,6 @@ menu "Tactility App" bool "CYD 2432S032C" config TT_DEVICE_CYD_8048S043C bool "CYD 8048S043C" - config TT_DEVICE_CYD_JC2432W328C - bool "CYD JC2432W328C" - config TT_DEVICE_CYD_JC8048W550C - bool "CYD JC8048W550C" config TT_DEVICE_CYD_4848S040C bool "CYD 4848S040C" config TT_DEVICE_ELECROW_CROWPANEL_ADVANCE_28 @@ -45,6 +41,12 @@ menu "Tactility App" bool "Elecrow CrowPanel Basic 3.5" config TT_DEVICE_ELECROW_CROWPANEL_BASIC_50 bool "Elecrow CrowPanel Basic 5.0" + config TT_DEVICE_GUITION_JC1060P470CIWY + bool "Guition JC1060P470CIWY" + config TT_DEVICE_GUITION_JC2432W328C + bool "Guition JC2432W328C" + config TT_DEVICE_GUITION_JC8048W550C + bool "Guition JC8048W550C" config TT_DEVICE_HELTEC_V3 bool "Heltec v3" config TT_DEVICE_LILYGO_TDECK @@ -94,4 +96,11 @@ menu "Tactility App" help The minimum time to show the splash screen in milliseconds. When set to 0, startup will continue to desktop as soon as boot operations are finished. + + config TT_WIFI_ENABLED + bool "Enable WiFi Support" + default n + help + Enable WiFi support for Tactility. + Uses native WiFi on ESP32/ESP32-S3 or ESP-Hosted on ESP32-P4. endmenu diff --git a/Firmware/idf_component.yml b/Firmware/idf_component.yml index cb204ce0..8226a1d7 100644 --- a/Firmware/idf_component.yml +++ b/Firmware/idf_component.yml @@ -1,4 +1,12 @@ dependencies: + espressif/esp_hosted: + version: "*" + rules: + - if: "target == esp32p4" + espressif/esp_wifi_remote: + version: "1.2.3" + rules: + - if: "target == esp32p4" espressif/esp_lcd_ili9341: version: "2.0.1" rules: @@ -30,6 +38,11 @@ dependencies: rules: - if: "target in [esp32, esp32s3]" espressif/esp_lcd_gc9a01: "2.0.3" + espressif/esp_lcd_jd9165: + version: "1.0.3" + rules: + # More hardware seems to be supported - enable as needed + - if: "target in [esp32p4]" espressif/esp_lcd_panel_io_additions: "1.0.1" espressif/esp_tinyusb: version: "1.7.6~1" diff --git a/Tactility/Source/Tactility.cpp b/Tactility/Source/Tactility.cpp index a82faa22..4f4cd4ed 100644 --- a/Tactility/Source/Tactility.cpp +++ b/Tactility/Source/Tactility.cpp @@ -45,7 +45,7 @@ namespace service { #ifdef ESP_PLATFORM namespace development { extern const ServiceManifest manifest; } #endif -#ifdef CONFIG_ESP_WIFI_ENABLED +#if defined(CONFIG_TT_WIFI_ENABLED) && !defined(CONFIG_ESP_WIFI_REMOTE_ENABLED) namespace espnow { extern const ServiceManifest manifest; } #endif // Secondary (UI) @@ -76,7 +76,7 @@ namespace app { namespace applist { extern const AppManifest manifest; } namespace appsettings { extern const AppManifest manifest; } namespace boot { extern const AppManifest manifest; } -#ifdef CONFIG_ESP_WIFI_ENABLED +#if defined(CONFIG_TT_WIFI_ENABLED) && !defined(CONFIG_ESP_WIFI_REMOTE_ENABLED) namespace chat { extern const AppManifest manifest; } #endif namespace development { extern const AppManifest manifest; } @@ -155,7 +155,7 @@ static void registerInternalApps() { addAppManifest(app::screenshot::manifest); #endif -#ifdef CONFIG_ESP_WIFI_ENABLED +#if defined(CONFIG_TT_WIFI_ENABLED) && !defined(CONFIG_ESP_WIFI_REMOTE_ENABLED) addAppManifest(app::chat::manifest); #endif @@ -260,7 +260,7 @@ static void registerAndStartPrimaryServices() { addService(service::development::manifest); #endif -#ifdef CONFIG_ESP_WIFI_ENABLED +#if defined(CONFIG_TT_WIFI_ENABLED) && !defined(CONFIG_ESP_WIFI_REMOTE_ENABLED) addService(service::espnow::manifest); #endif } diff --git a/Tactility/Source/app/chat/ChatApp.cpp b/Tactility/Source/app/chat/ChatApp.cpp index d79d91fa..f678cc1e 100644 --- a/Tactility/Source/app/chat/ChatApp.cpp +++ b/Tactility/Source/app/chat/ChatApp.cpp @@ -2,7 +2,7 @@ #include #endif -#ifdef CONFIG_ESP_WIFI_ENABLED +#if defined(CONFIG_TT_WIFI_ENABLED) && !defined(CONFIG_ESP_WIFI_REMOTE_ENABLED) #include #include diff --git a/Tactility/Source/app/wifimanage/WifiManage.cpp b/Tactility/Source/app/wifimanage/WifiManage.cpp index 252815c9..ab8a4241 100644 --- a/Tactility/Source/app/wifimanage/WifiManage.cpp +++ b/Tactility/Source/app/wifimanage/WifiManage.cpp @@ -120,7 +120,12 @@ void WifiManage::onShow(AppContext& app, lv_obj_t* parent) { bool can_scan = radio_state == service::wifi::RadioState::On || radio_state == service::wifi::RadioState::ConnectionPending || radio_state == service::wifi::RadioState::ConnectionActive; - LOGGER.info("{} {}", service::wifi::radioStateToString(radio_state), service::wifi::isScanning()); + std::string connection_target = service::wifi::getConnectionTarget(); + LOGGER.info("Radio: {}, Scanning: {}, Connected to: {}, Can scan: {}", + service::wifi::radioStateToString(radio_state), + service::wifi::isScanning(), + connection_target.empty() ? "(none)" : connection_target.c_str(), + can_scan); if (can_scan && !service::wifi::isScanning()) { service::wifi::scan(); } diff --git a/Tactility/Source/service/espnow/EspNow.cpp b/Tactility/Source/service/espnow/EspNow.cpp index 1834b062..015c7a56 100644 --- a/Tactility/Source/service/espnow/EspNow.cpp +++ b/Tactility/Source/service/espnow/EspNow.cpp @@ -2,7 +2,7 @@ #include #endif -#ifdef CONFIG_ESP_WIFI_ENABLED +#if defined(CONFIG_TT_WIFI_ENABLED) && !defined(CONFIG_ESP_WIFI_REMOTE_ENABLED) #include #include diff --git a/Tactility/Source/service/espnow/EspNowService.cpp b/Tactility/Source/service/espnow/EspNowService.cpp index 0fa9357a..86c6416c 100644 --- a/Tactility/Source/service/espnow/EspNowService.cpp +++ b/Tactility/Source/service/espnow/EspNowService.cpp @@ -2,7 +2,7 @@ #include #endif -#ifdef CONFIG_ESP_WIFI_ENABLED +#if defined(CONFIG_TT_WIFI_ENABLED) && !defined(CONFIG_ESP_WIFI_REMOTE_ENABLED) #include #include diff --git a/Tactility/Source/service/espnow/EspNowWifi.cpp b/Tactility/Source/service/espnow/EspNowWifi.cpp index db727ad9..81b5af7d 100644 --- a/Tactility/Source/service/espnow/EspNowWifi.cpp +++ b/Tactility/Source/service/espnow/EspNowWifi.cpp @@ -2,7 +2,7 @@ #include #endif -#ifdef CONFIG_ESP_WIFI_ENABLED +#if defined(CONFIG_TT_WIFI_ENABLED) && !defined(CONFIG_ESP_WIFI_REMOTE_ENABLED) #include #include diff --git a/Tactility/Source/service/wifi/WifiEsp.cpp b/Tactility/Source/service/wifi/WifiEsp.cpp index fe70032f..34c7d9dc 100644 --- a/Tactility/Source/service/wifi/WifiEsp.cpp +++ b/Tactility/Source/service/wifi/WifiEsp.cpp @@ -2,7 +2,7 @@ #include #endif -#ifdef CONFIG_ESP_WIFI_ENABLED +#if defined(CONFIG_SOC_WIFI_SUPPORTED) || defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED) #include @@ -413,17 +413,21 @@ static bool copy_scan_list(std::shared_ptr wifi) { LOGGER.info("Scanned {} APs. Showing {}:", record_count, safe_record_count); for (uint16_t i = 0; i < safe_record_count; i++) { wifi_ap_record_t* record = &wifi->scan_list[i]; - LOGGER.info(" - SSID {}, RSSI {}, channel {}, BSSID {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", - reinterpret_cast(record->ssid), - record->rssi, - record->primary, - record->bssid[0], - record->bssid[1], - record->bssid[2], - record->bssid[3], - record->bssid[4], - record->bssid[5] - ); + if (record->ssid[0] != 0 && record->primary != 0) { + LOGGER.info(" - SSID {}, RSSI {}, channel {}, BSSID {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", + reinterpret_cast(record->ssid), + record->rssi, + record->primary, + record->bssid[0], + record->bssid[1], + record->bssid[2], + record->bssid[3], + record->bssid[4], + record->bssid[5] + ); + } else { + LOGGER.info(" - (missing channel info)"); // Behaviour on on P4 with C6 + } } return true; } else { @@ -972,4 +976,4 @@ extern const ServiceManifest manifest = { } // namespace -#endif // ESP_PLATFORM +#endif // CONFIG_SOC_WIFI_SUPPORTED or CONFIG_SLAVE_SOC_WIFI_SUPPORTED diff --git a/Tactility/Source/service/wifi/WifiMock.cpp b/Tactility/Source/service/wifi/WifiMock.cpp index 6d86312b..ae8573b8 100644 --- a/Tactility/Source/service/wifi/WifiMock.cpp +++ b/Tactility/Source/service/wifi/WifiMock.cpp @@ -2,7 +2,7 @@ #include #endif -#ifndef CONFIG_ESP_WIFI_ENABLED +#if not defined(CONFIG_SOC_WIFI_SUPPORTED) && not defined(CONFIG_SLAVE_SOC_WIFI_SUPPORTED) #include diff --git a/TactilityC/Source/symbols/gcc_soft_float.cpp b/TactilityC/Source/symbols/gcc_soft_float.cpp index 891ba3f8..a3c259ad 100644 --- a/TactilityC/Source/symbols/gcc_soft_float.cpp +++ b/TactilityC/Source/symbols/gcc_soft_float.cpp @@ -1,3 +1,4 @@ +#include #ifndef CONFIG_IDF_TARGET_ESP32P4 #include diff --git a/TactilityC/Source/symbols/gcc_soft_float_p4.cpp b/TactilityC/Source/symbols/gcc_soft_float_p4.cpp new file mode 100644 index 00000000..134aaf93 --- /dev/null +++ b/TactilityC/Source/symbols/gcc_soft_float_p4.cpp @@ -0,0 +1,255 @@ +#include +#ifdef CONFIG_IDF_TARGET_ESP32P4 + +#include +#include + +#include + +#include + +// Reference: https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html + +extern "C" { + +extern double __adddf3(double a, double b); +// extern long double __addtf3(long double a, long double b); +// extern long double __addxf3(long double a, long double b); + +extern double __subdf3(double a, double b); +// extern long double __subtf3(long double a, long double b); +// extern long double __subxf3(long double a, long double b); + +extern double __muldf3(double a, double b); +// extern long double __multf3(long double a, long double b); +// extern long double __mulxf3(long double a, long double b); + +extern double __divdf3(double a, double b); +// extern long double __divtf3(long double a, long double b); +// extern long double __divxf3(long double a, long double b); + +extern double __negdf2(double a); +// extern long double __negtf2(long double a); +// extern long double __negxf2(long double a); + +// extern long double __extendsftf2(float a); +// extern long double __extendsfxf2(float a); +// extern long double __extenddftf2(double a); +// extern long double __extenddfxf2(double a); + +// extern double __truncxfdf2(long double a); +// extern double __trunctfdf2(long double a); +// extern float __truncxfsf2(long double a); +// extern float __trunctfsf2(long double a); +extern float __truncdfsf2(double a); + +extern int __fixdfsi(double a); +// extern int __fixtfsi(long double a); +// extern int __fixxfsi(long double a); + +extern long __fixdfdi(double a); +// extern long __fixtfdi(long double a); +// extern long __fixxfdi(long double a); + +// extern long long __fixsfti(float a); +// extern long long __fixdfti(double a); +// extern long long __fixtfti(long double a); +// extern long long __fixxfti(long double a); + +// extern unsigned int __fixunssfsi(float a); +// extern unsigned int __fixunsdfsi(double a); +// extern unsigned int __fixunstfsi(long double a); +// extern unsigned int __fixunsxfsi(long double a); + +extern unsigned long __fixunsdfdi(double a); +// extern unsigned long __fixunstfdi(long double a); +// extern unsigned long __fixunsxfdi(long double a); + +// extern unsigned long long __fixunssfti(float a); +// extern unsigned long long __fixunsdfti(double a); +// extern unsigned long long __fixunstfti(long double a); +// extern unsigned long long __fixunsxfti(long double a); + +// extern float __floatsisf(int i); +// extern double __floatsidf(int i); +// extern long double __floatsitf(int i); +// extern long double __floatsixf(int i); + +extern float __floatdisf(long i); +extern double __floatdidf(long i); +// extern long double __floatditf(long i); +// extern long double __floatdixf(long i); + +// extern float __floattisf(long long i); +// extern double __floattidf(long long i); +// extern long double __floattitf(long long i); +// extern long double __floattixf(long long i); + +extern double __floatunsidf(unsigned int i); +// extern long double __floatunsitf(unsigned int i); +// extern long double __floatunsixf(unsigned int i); + +extern float __floatundisf(unsigned long i); +extern double __floatundidf(unsigned long i); +// extern long double __floatunditf(unsigned long i); +// extern long double __floatundixf(unsigned long i); + +// extern float __floatuntisf(unsigned long long i); +// extern double __floatuntidf(unsigned long long i); +// extern long double __floatuntitf(unsigned long long i); +// extern long double __floatuntixf(unsigned long long i); + +float __powisf2(float a, int b); +double __powidf2(double a, int b); +// long double __powitf2(long double a, int b); +// long double __powixf2(long double a, int b); + +// int __cmpsf2(float a, float b); +int __cmpdf2(double a, double b); +// int __cmptf2(long double a, long double b); + +int __unorddf2(double a, double b); +// int __unordtf2(long double a, long double b); + +int __eqdf2(double a, double b); +// int __eqtf2(long double a, long double b); + +int __nedf2(double a, double b); +// int __netf2(long double a, long double b); + +int __gedf2(double a, double b); +// int __getf2(long double a, long double b); + +int __ltdf2(double a, double b); +// int __lttf2(long double a, long double b); + +int __ledf2(double a, double b); +// int __letf2(long double a, long double b); + +int __gtdf2(double a, double b); +// int __gttf2(long double a, long double b); + +} // extern "C" + +const esp_elfsym gcc_soft_float_symbols[] = { + ESP_ELFSYM_EXPORT(__adddf3), + // ESP_ELFSYM_EXPORT(__addtf3), + // ESP_ELFSYM_EXPORT(__addxf3), + + ESP_ELFSYM_EXPORT(__subdf3), + // ESP_ELFSYM_EXPORT(__subtf3), + // ESP_ELFSYM_EXPORT(__subxf3), + + ESP_ELFSYM_EXPORT(__muldf3), + // ESP_ELFSYM_EXPORT(__multf3), + // ESP_ELFSYM_EXPORT(__mulxf3), + + ESP_ELFSYM_EXPORT(__divdf3), + // ESP_ELFSYM_EXPORT(__divtf3), + // ESP_ELFSYM_EXPORT(__divxf3), + + ESP_ELFSYM_EXPORT(__negdf2), + // ESP_ELFSYM_EXPORT(__negtf2), + // ESP_ELFSYM_EXPORT(__negxf2), + + // ESP_ELFSYM_EXPORT(__extendsftf2), + // ESP_ELFSYM_EXPORT(__extendsfxf2), + // ESP_ELFSYM_EXPORT(__extenddftf2), + // ESP_ELFSYM_EXPORT(__extenddfxf2), + + // ESP_ELFSYM_EXPORT(__truncxfdf2), + // ESP_ELFSYM_EXPORT(__trunctfdf2), + // ESP_ELFSYM_EXPORT(__truncxfsf2), + // ESP_ELFSYM_EXPORT(__trunctfsf2), + ESP_ELFSYM_EXPORT(__truncdfsf2), + + ESP_ELFSYM_EXPORT(__fixdfsi), + // ESP_ELFSYM_EXPORT(__fixtfsi), + // ESP_ELFSYM_EXPORT(__fixxfsi), + + ESP_ELFSYM_EXPORT(__fixdfdi), + // ESP_ELFSYM_EXPORT(__fixtfdi), + // ESP_ELFSYM_EXPORT(__fixxfdi), + + // ESP_ELFSYM_EXPORT(__fixsfti), + // ESP_ELFSYM_EXPORT(__fixdfti), + // ESP_ELFSYM_EXPORT(__fixtfti), + // ESP_ELFSYM_EXPORT(__fixxfti), + + // ESP_ELFSYM_EXPORT(__fixunssfsi), + // ESP_ELFSYM_EXPORT(__fixunsdfsi), + // ESP_ELFSYM_EXPORT(__fixunstfsi), + // ESP_ELFSYM_EXPORT(__fixunsxfsi), + + ESP_ELFSYM_EXPORT(__fixunsdfdi), + // ESP_ELFSYM_EXPORT(__fixunstfdi), + // ESP_ELFSYM_EXPORT(__fixunsxfdi), + + // ESP_ELFSYM_EXPORT(__fixunssfti), + // ESP_ELFSYM_EXPORT(__fixunsdfti), + // ESP_ELFSYM_EXPORT(__fixunstfti), + // ESP_ELFSYM_EXPORT(__fixunsxfti), + + // ESP_ELFSYM_EXPORT(__floatsisf), + // ESP_ELFSYM_EXPORT(__floatsidf), + // ESP_ELFSYM_EXPORT(__floatsitf), + // ESP_ELFSYM_EXPORT(__floatsixf), + + ESP_ELFSYM_EXPORT(__floatdisf), + ESP_ELFSYM_EXPORT(__floatdidf), + // ESP_ELFSYM_EXPORT(__floatditf), + // ESP_ELFSYM_EXPORT(__floatdixf), + + // ESP_ELFSYM_EXPORT(__floattisf), + // ESP_ELFSYM_EXPORT(__floattidf), + // ESP_ELFSYM_EXPORT(__floattitf), + // ESP_ELFSYM_EXPORT(__floattixf), + + ESP_ELFSYM_EXPORT(__floatunsidf), + // ESP_ELFSYM_EXPORT(__floatunsitf), + // ESP_ELFSYM_EXPORT(__floatunsixf), + + ESP_ELFSYM_EXPORT(__floatundisf), + ESP_ELFSYM_EXPORT(__floatundidf), + // ESP_ELFSYM_EXPORT(__floatunditf), + // ESP_ELFSYM_EXPORT(__floatundixf), + + // ESP_ELFSYM_EXPORT(__floatuntisf), + // ESP_ELFSYM_EXPORT(__floatuntidf), + // ESP_ELFSYM_EXPORT(__floatuntitf), + // ESP_ELFSYM_EXPORT(__floatuntixf), + + ESP_ELFSYM_EXPORT(__powisf2), + ESP_ELFSYM_EXPORT(__powidf2), + // ESP_ELFSYM_EXPORT(__powitf2), + // ESP_ELFSYM_EXPORT(__powixf2), + + // ESP_ELFSYM_EXPORT(__cmpsf2), + // ESP_ELFSYM_EXPORT(__cmpdf2), + // ESP_ELFSYM_EXPORT(__cmptf2), + + ESP_ELFSYM_EXPORT(__unorddf2), + // ESP_ELFSYM_EXPORT(__unordtf2), + + ESP_ELFSYM_EXPORT(__eqdf2), + // ESP_ELFSYM_EXPORT(__eqtf2), + + ESP_ELFSYM_EXPORT(__nedf2), + // ESP_ELFSYM_EXPORT(__netf2), + + ESP_ELFSYM_EXPORT(__gedf2), + // ESP_ELFSYM_EXPORT(__getf2), + + ESP_ELFSYM_EXPORT(__ltdf2), + // ESP_ELFSYM_EXPORT(__lttf2), + + ESP_ELFSYM_EXPORT(__ledf2), + // ESP_ELFSYM_EXPORT(__letf2), + + ESP_ELFSYM_EXPORT(__gtdf2), + // ESP_ELFSYM_EXPORT(__gttf2), + + ESP_ELFSYM_END +}; + +#endif \ No newline at end of file diff --git a/TactilityC/Source/symbols/pthread.cpp b/TactilityC/Source/symbols/pthread.cpp index dbfa961c..45e842c3 100644 --- a/TactilityC/Source/symbols/pthread.cpp +++ b/TactilityC/Source/symbols/pthread.cpp @@ -12,6 +12,12 @@ const esp_elfsym pthread_symbols[] = { ESP_ELFSYM_EXPORT(pthread_detach), ESP_ELFSYM_EXPORT(pthread_join), ESP_ELFSYM_EXPORT(pthread_exit), + ESP_ELFSYM_EXPORT(pthread_mutex_init), + ESP_ELFSYM_EXPORT(pthread_mutex_destroy), + ESP_ELFSYM_EXPORT(pthread_mutex_lock), + ESP_ELFSYM_EXPORT(pthread_mutex_trylock), + ESP_ELFSYM_EXPORT(pthread_mutex_unlock), + ESP_ELFSYM_EXPORT(pthread_mutex_timedlock), // delimiter ESP_ELFSYM_END }; diff --git a/TactilityC/Source/tt_init.cpp b/TactilityC/Source/tt_init.cpp index 30c9a766..dfe71611 100644 --- a/TactilityC/Source/tt_init.cpp +++ b/TactilityC/Source/tt_init.cpp @@ -28,9 +28,7 @@ #include "symbols/string.h" #include "symbols/cplusplus.h" #include "symbols/freertos.h" -#ifndef CONFIG_IDF_TARGET_ESP32P4 #include "symbols/gcc_soft_float.h" -#endif #include #include @@ -629,9 +627,7 @@ uintptr_t resolve_symbol(const esp_elfsym* source, const char* symbolName) { uintptr_t tt_symbol_resolver(const char* symbolName) { static const std::vector all_symbols = { main_symbols, -#ifndef CONFIG_IDF_TARGET_ESP32P4 gcc_soft_float_symbols, -#endif stl_symbols, cplusplus_symbols, pthread_symbols, diff --git a/TactilityCore/Source/CpuAffinity.cpp b/TactilityCore/Source/CpuAffinity.cpp index 19ac23b6..8cdcfce9 100644 --- a/TactilityCore/Source/CpuAffinity.cpp +++ b/TactilityCore/Source/CpuAffinity.cpp @@ -35,7 +35,8 @@ static CpuAffinity getEspMainSchedulerAffinity() { #elif defined(CONFIG_ESP_WIFI_TASK_PINNED_TO_CORE_1) return 1; #else - return None; + // Default to core 0 when no explicit WiFi pinning is configured + return 0; #endif }