Browse Source

wip

pull/2568/head
Christos Themelis 3 months ago
parent
commit
92ffc5c980
  1. 3
      .claude/settings.local.json
  2. 9
      examples/simple_secure_chat_ui/main.cpp
  3. 24
      examples/simple_secure_chat_ui/uiManager.cpp
  4. 30
      src/helpers/esp32/SenseCapHAL.h
  5. 82
      variants/sensecap_indicator-espnow/target.cpp
  6. 11
      variants/sensecap_indicator-espnow/target.h

3
.claude/settings.local.json

@ -14,7 +14,8 @@
"WebFetch(domain:raw.githubusercontent.com)",
"WebFetch(domain:api.github.com)",
"Bash(grep -r \"IO_EXPANDER\\\\|i2c_addr\\\\|PCA9554\\\\|expander\" D:GitMeshCore.piolibdepsSenseCapIndicator-ESPNow_comp_radio_usbLovyanGFXsrc --include=*.hpp --include=*.cpp -l)",
"Bash(dir \"D:\\\\Git\\\\MeshCore\\\\.pio\\\\libdeps\\\\SenseCapIndicator-ESPNow_comp_radio_usb\\\\LovyanGFX\\\\src\\\\lgfx\\\\v1\\\\platforms\\\\esp32s3\" /b)"
"Bash(dir \"D:\\\\Git\\\\MeshCore\\\\.pio\\\\libdeps\\\\SenseCapIndicator-ESPNow_comp_radio_usb\\\\LovyanGFX\\\\src\\\\lgfx\\\\v1\\\\platforms\\\\esp32s3\" /b)",
"Bash(findstr /S /M \"ui_Screen1_screen_init\\\\|ui_TabPageHome\\\\|lv_tabview_add_tab\" D:GitMeshCore*.cpp D:GitMeshCore*.h)"
]
}
}

9
examples/simple_secure_chat_ui/main.cpp

@ -141,9 +141,16 @@ void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color
void my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data)
{
// Serialize Wire access with SenseCapHAL (TCA9535 radio expander).
// g_i2c_mutex is nullptr until radio_init() creates it — safe to skip then.
if (g_i2c_mutex) xSemaphoreTake(g_i2c_mutex, pdMS_TO_TICKS(20));
uint16_t x, y;
bool touched = lcd.getTouch(&x, &y);
if (g_i2c_mutex) xSemaphoreGive(g_i2c_mutex);
if (lcd.getTouch(&x, &y))
if (touched)
{
data->state = LV_INDEV_STATE_PR;
data->point.x = x;

24
examples/simple_secure_chat_ui/uiManager.cpp

@ -482,6 +482,11 @@ void UIManager::onHideKeyboard()
LvObj(ui_SendBtn, true).positionY(channelInputBaseY);
}
static void s_onRestartClick(lv_event_t *e)
{
ESP.restart();
}
static void s_onChannelInputFocus(lv_event_t *e)
{
UIManager *self = (UIManager*) lv_event_get_user_data(e);
@ -639,6 +644,25 @@ void UIManager::ui_Screen1_screen_init(void)
.align(LV_ALIGN_CENTER)
.position(0, -100);
lv_obj_t* ui_RestartBtn = LvButton(ui_TabPageHome)
.size(200, 56)
.align(LV_ALIGN_CENTER)
.position(0, 60)
.bgColor(0xC62828)
.onClick(s_onRestartClick, nullptr)
.raw();
lv_obj_t* ui_RestartLabel = LvLabel(ui_RestartBtn)
#if defined(LANG_EN)
.text(LV_SYMBOL_REFRESH " Restart")
#elif defined(LANG_GR)
.text(LV_SYMBOL_REFRESH " Επανεκκίνηση")
#endif
.font(&lv_font_arial_22)
.textColor(0xFFFFFF)
.raw();
lv_obj_center(ui_RestartLabel);
ui_Contacts = LvList(ui_TabPageContacts)
.width(140)
.height(400)

30
src/helpers/esp32/SenseCapHAL.h

@ -26,13 +26,16 @@
#include <RadioLib.h>
#include <Wire.h>
#include <SPI.h>
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
class SenseCapHAL : public ArduinoHal {
TwoWire* _wire;
uint8_t _addr; // 7-bit I2C address of TCA9535 (0x20)
uint8_t _out0; // cached Output Port 0 latch (all HIGH = de-asserted)
uint8_t _cfg0; // cached Config Port 0 (all 1 = input initially)
int _sclk, _miso, _mosi; // SPI data pins
TwoWire* _wire;
uint8_t _addr; // 7-bit I2C address of TCA9535 (0x20)
uint8_t _out0; // cached Output Port 0 latch (all HIGH = de-asserted)
uint8_t _cfg0; // cached Config Port 0 (all 1 = input initially)
int _sclk, _miso, _mosi; // SPI data pins
SemaphoreHandle_t _mutex; // shared Wire mutex (set via setMutex() after creation)
// A pin is on the expander when its upper nibble equals IO_EXPANDER
static bool isExp(uint32_t pin) {
@ -48,17 +51,22 @@ class SenseCapHAL : public ArduinoHal {
}
void writeReg(uint8_t reg, uint8_t val) {
if (_mutex) xSemaphoreTake(_mutex, portMAX_DELAY);
_wire->beginTransmission(_addr);
_wire->write(reg);
_wire->write(val);
_wire->endTransmission();
if (_mutex) xSemaphoreGive(_mutex);
}
uint8_t readReg(uint8_t reg) {
if (_mutex) xSemaphoreTake(_mutex, portMAX_DELAY);
_wire->beginTransmission(_addr);
_wire->write(reg);
_wire->endTransmission(false);
_wire->requestFrom(_addr, (uint8_t)1);
return _wire->available() ? _wire->read() : 0xFF;
uint8_t val = _wire->available() ? _wire->read() : 0xFF;
if (_mutex) xSemaphoreGive(_mutex);
return val;
}
public:
@ -69,8 +77,13 @@ public:
, _out0(0xFF) // all HIGH (NSS, RESET de-asserted)
, _cfg0(0xFF) // all inputs initially
, _sclk(sclk), _miso(miso), _mosi(mosi)
, _mutex(nullptr)
{}
// Set the shared I2C mutex. Must be called before any Wire operations.
// Both this HAL and the touch-read callback must use the same handle.
void setMutex(SemaphoreHandle_t m) { _mutex = m; }
// Call once Wire is running — sets TCA9535 Port 0: all outputs HIGH
void initExpander() {
writeReg(0x02, _out0); // Output Port 0: all HIGH
@ -137,7 +150,10 @@ public:
// Scan for the TCA9535 on I2C and log the result
bool scanExpander() {
if (_mutex) xSemaphoreTake(_mutex, portMAX_DELAY);
_wire->beginTransmission(_addr);
return (_wire->endTransmission() == 0);
bool found = (_wire->endTransmission() == 0);
if (_mutex) xSemaphoreGive(_mutex);
return found;
}
};

82
variants/sensecap_indicator-espnow/target.cpp

@ -1,5 +1,47 @@
#include <Arduino.h>
#include "target.h"
#include <driver/gpio.h>
// Recover a stuck I2C bus by manually clocking SCL up to 9 times until
// SDA is released, then issuing a STOP condition.
static void i2c_bus_recovery() {
Serial.println("[i2c_recover] Attempting I2C bus recovery...");
pinMode(PIN_BOARD_SCL, OUTPUT_OPEN_DRAIN);
pinMode(PIN_BOARD_SDA, INPUT_PULLUP);
digitalWrite(PIN_BOARD_SCL, HIGH);
delayMicroseconds(10);
bool released = false;
for (int i = 0; i < 9; i++) {
digitalWrite(PIN_BOARD_SCL, LOW);
delayMicroseconds(10);
digitalWrite(PIN_BOARD_SCL, HIGH);
delayMicroseconds(10);
if (digitalRead(PIN_BOARD_SDA) == HIGH) {
released = true;
Serial.printf("[i2c_recover] SDA released after %d clocks\n", i + 1);
break;
}
}
if (!released) {
Serial.println("[i2c_recover] SDA still LOW after 9 clocks!");
}
// Generate STOP condition: SDA LOW→HIGH while SCL HIGH
pinMode(PIN_BOARD_SDA, OUTPUT_OPEN_DRAIN);
digitalWrite(PIN_BOARD_SDA, LOW);
delayMicroseconds(10);
digitalWrite(PIN_BOARD_SCL, HIGH);
delayMicroseconds(10);
digitalWrite(PIN_BOARD_SDA, HIGH);
delayMicroseconds(10);
// Restore pins to input so Wire can take over
pinMode(PIN_BOARD_SCL, INPUT_PULLUP);
pinMode(PIN_BOARD_SDA, INPUT_PULLUP);
delay(5);
Serial.println("[i2c_recover] Done.");
}
ESP32Board board;
@ -35,9 +77,17 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock);
EnvironmentSensorManager sensors;
// Shared Wire mutex — created in radio_init(), exported via target.h
SemaphoreHandle_t g_i2c_mutex = nullptr;
// ── radio_init ─────────────────────────────────────────────────────────
bool radio_init() {
// Create the shared Wire mutex FIRST so both the radio HAL and the
// LVGL touch callback (my_touchpad_read) serialise their Wire access.
g_i2c_mutex = xSemaphoreCreateMutex();
radio_hal.setMutex(g_i2c_mutex);
Serial.println("[radio_init] Starting...");
Serial.printf("[radio_init] SPI : SCLK=%d MISO=%d MOSI=%d\n",
LORA_SCLK, LORA_MISO, LORA_MOSI);
@ -45,9 +95,37 @@ bool radio_init() {
LORA_NSS & 0x0F, LORA_RESET & 0x0F, LORA_BUSY & 0x0F, LORA_DIO1 & 0x0F);
Serial.printf("[radio_init] DIO1 interrupt → GPIO %d\n", IO_EXPANDER_IRQ);
// Wire must be up before TCA9535 access.
// (lcd.begin() may have already called Wire.begin, but re-init is safe.)
// Take mutex for bus recovery + Wire re-init + scan
// (prevents LVGL touch task from accessing Wire concurrently)
xSemaphoreTake(g_i2c_mutex, portMAX_DELAY);
// Recover stuck I2C bus (may be left in bad state after display init)
i2c_bus_recovery();
// Wire must be up before TCA9535 access — force full re-init after recovery
Wire.end();
delay(5);
Wire.begin(PIN_BOARD_SDA, PIN_BOARD_SCL);
Wire.setTimeOut(15); // 15 ms per address for fast scan
delay(10);
// ── Full I2C bus scan ───────────────────────────────────────────────────
Serial.println("[radio_init] I2C scan:");
uint8_t found_addr = 0;
for (uint8_t addr = 0x08; addr <= 0x77; addr++) {
Wire.beginTransmission(addr);
uint8_t err = Wire.endTransmission();
if (err == 0) {
Serial.printf("[radio_init] Device found at 0x%02X\n", addr);
found_addr = addr;
}
}
if (found_addr == 0) {
Serial.println("[radio_init] No I2C devices found!");
}
Serial.println("[radio_init] I2C scan done.");
xSemaphoreGive(g_i2c_mutex);
// Verify TCA9535 is present on the bus
if (radio_hal.scanExpander()) {

11
variants/sensecap_indicator-espnow/target.h

@ -3,6 +3,8 @@
#include <Arduino.h>
#include <RadioLib.h>
#include <Wire.h>
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
#include <helpers/ESP32Board.h>
#include <helpers/radiolib/RadioLibWrappers.h>
@ -56,6 +58,15 @@ extern EnvironmentSensorManager sensors;
#endif
// -------------------------------------------------
// Shared I2C mutex
// Protects Wire access shared between SenseCapHAL (TCA9535 @ 0x20)
// and the LVGL touch callback (FT5x06 @ 0x48).
// Created in radio_init() before std_init(); use via g_i2c_mutex.
// -------------------------------------------------
extern SemaphoreHandle_t g_i2c_mutex;
// -------------------------------------------------
// Functions
// -------------------------------------------------

Loading…
Cancel
Save