mirror of https://github.com/meshcore-dev/MeshCore
7 changed files with 298 additions and 86 deletions
@ -0,0 +1,20 @@ |
|||
{ |
|||
"permissions": { |
|||
"allow": [ |
|||
"Bash(dir \"D:\\\\Git\\\\MeshCore\\\\variants\")", |
|||
"Bash(find /d/Git/MeshCore -name *.h -path */include/* -type f)", |
|||
"WebFetch(domain:github.com)", |
|||
"WebSearch", |
|||
"WebFetch(domain:wiki.seeedstudio.com)", |
|||
"WebFetch(domain:meshtastic.org)", |
|||
"WebFetch(domain:adrelien.com)", |
|||
"WebFetch(domain:manuals.plus)", |
|||
"WebFetch(domain:devices.esphome.io)", |
|||
"WebFetch(domain:files.seeedstudio.com)", |
|||
"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)" |
|||
] |
|||
} |
|||
} |
|||
@ -0,0 +1,143 @@ |
|||
#pragma once |
|||
|
|||
// SenseCapHAL - Custom RadioLib 7.x HAL for the Seeed SenseCAP Indicator
|
|||
//
|
|||
// The SenseCAP Indicator routes SX1262 control pins through a TCA9535
|
|||
// 16-bit I2C IO expander (address 0x20) because GPIOs 0-15 are used by
|
|||
// the 16-bit RGB display bus.
|
|||
//
|
|||
// Pin encoding matches LovyanGFX convention: (pin_index | IO_EXPANDER)
|
|||
// IO_EXPANDER = 0x40 (defined as build flag in platformio.ini)
|
|||
//
|
|||
// SX1262 expander pin assignments (TCA9535 Port 0):
|
|||
// pin 0 = NSS (EXPANDER_IO_RADIO_NSS)
|
|||
// pin 1 = RESET (EXPANDER_IO_RADIO_RST)
|
|||
// pin 2 = BUSY (EXPANDER_IO_RADIO_BUSY)
|
|||
// pin 3 = DIO1 (EXPANDER_IO_RADIO_DIO_1)
|
|||
//
|
|||
// DIO1 interrupt: TCA9535 /INT output → GPIO 42 (IO_EXPANDER_IRQ)
|
|||
// The /INT pin fires FALLING when any input changes.
|
|||
//
|
|||
// TCA9535 register map (Port 0 only):
|
|||
// 0x00 Input Port 0 (read)
|
|||
// 0x02 Output Port 0 (write; 1=HIGH, 0=LOW)
|
|||
// 0x06 Config Port 0 (0=output, 1=input)
|
|||
|
|||
#include <RadioLib.h> |
|||
#include <Wire.h> |
|||
#include <SPI.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
|
|||
|
|||
// A pin is on the expander when its upper nibble equals IO_EXPANDER
|
|||
static bool isExp(uint32_t pin) { |
|||
return (pin & ~0x0Fu) == (uint32_t)IO_EXPANDER; |
|||
} |
|||
// Bit mask within TCA9535 port register
|
|||
static uint8_t expBit(uint32_t pin) { |
|||
return (uint8_t)(1u << (pin & 0x07u)); |
|||
} |
|||
// Pins 0-7 are Port 0; pins 8-15 are Port 1
|
|||
static bool isPort0(uint32_t pin) { |
|||
return (pin & 0x08u) == 0; |
|||
} |
|||
|
|||
void writeReg(uint8_t reg, uint8_t val) { |
|||
_wire->beginTransmission(_addr); |
|||
_wire->write(reg); |
|||
_wire->write(val); |
|||
_wire->endTransmission(); |
|||
} |
|||
uint8_t readReg(uint8_t reg) { |
|||
_wire->beginTransmission(_addr); |
|||
_wire->write(reg); |
|||
_wire->endTransmission(false); |
|||
_wire->requestFrom(_addr, (uint8_t)1); |
|||
return _wire->available() ? _wire->read() : 0xFF; |
|||
} |
|||
|
|||
public: |
|||
SenseCapHAL(SPIClass& spi, int sclk, int miso, int mosi, |
|||
uint8_t i2c_addr = 0x20, TwoWire* wire = &Wire) |
|||
: ArduinoHal(spi, SPISettings(2000000, MSBFIRST, SPI_MODE0)) |
|||
, _wire(wire), _addr(i2c_addr) |
|||
, _out0(0xFF) // all HIGH (NSS, RESET de-asserted)
|
|||
, _cfg0(0xFF) // all inputs initially
|
|||
, _sclk(sclk), _miso(miso), _mosi(mosi) |
|||
{} |
|||
|
|||
// Call once Wire is running — sets TCA9535 Port 0: all outputs HIGH
|
|||
void initExpander() { |
|||
writeReg(0x02, _out0); // Output Port 0: all HIGH
|
|||
writeReg(0x06, _cfg0); // Config Port 0: all inputs (RadioLib will reconfigure)
|
|||
Serial.printf("[SenseCapHAL] TCA9535@0x%02X init: out=0x%02X cfg=0x%02X\n", |
|||
_addr, _out0, _cfg0); |
|||
} |
|||
|
|||
// ── Overrides ──────────────────────────────────────────────────────────
|
|||
|
|||
// Initialize SPI with the correct pin numbers for SenseCAP Indicator
|
|||
void spiBegin() override { |
|||
this->spi->begin(_sclk, _miso, _mosi); |
|||
Serial.printf("[SenseCapHAL] SPI begin: SCLK=%d MISO=%d MOSI=%d\n", |
|||
_sclk, _miso, _mosi); |
|||
} |
|||
|
|||
void pinMode(uint32_t pin, uint32_t mode) override { |
|||
if (isExp(pin) && isPort0(pin)) { |
|||
if (mode == OUTPUT) _cfg0 &= ~expBit(pin); |
|||
else _cfg0 |= expBit(pin); |
|||
writeReg(0x06, _cfg0); |
|||
} else { |
|||
ArduinoHal::pinMode(pin, mode); |
|||
} |
|||
} |
|||
|
|||
void digitalWrite(uint32_t pin, uint32_t value) override { |
|||
if (isExp(pin) && isPort0(pin)) { |
|||
if (value) _out0 |= expBit(pin); |
|||
else _out0 &= ~expBit(pin); |
|||
writeReg(0x02, _out0); |
|||
} else { |
|||
ArduinoHal::digitalWrite(pin, value); |
|||
} |
|||
} |
|||
|
|||
uint32_t digitalRead(uint32_t pin) override { |
|||
if (isExp(pin) && isPort0(pin)) { |
|||
return (readReg(0x00) & expBit(pin)) ? 1 : 0; |
|||
} |
|||
return ArduinoHal::digitalRead(pin); |
|||
} |
|||
|
|||
// DIO1 is expander pin 3; redirect the interrupt to IO_EXPANDER_IRQ (GPIO 42).
|
|||
// TCA9535 /INT fires FALLING when any input changes (DIO1 going HIGH = packet ready).
|
|||
void attachInterrupt(uint32_t pin, void (*cb)(void), uint32_t mode) override { |
|||
if (isExp(pin)) { |
|||
::pinMode(IO_EXPANDER_IRQ, INPUT_PULLUP); |
|||
::attachInterrupt(digitalPinToInterrupt(IO_EXPANDER_IRQ), cb, FALLING); |
|||
Serial.printf("[SenseCapHAL] DIO1 interrupt → GPIO %d (FALLING)\n", IO_EXPANDER_IRQ); |
|||
} else { |
|||
ArduinoHal::attachInterrupt(pin, cb, mode); |
|||
} |
|||
} |
|||
|
|||
void detachInterrupt(uint32_t pin) override { |
|||
if (isExp(pin)) { |
|||
::detachInterrupt(digitalPinToInterrupt(IO_EXPANDER_IRQ)); |
|||
} else { |
|||
ArduinoHal::detachInterrupt(pin); |
|||
} |
|||
} |
|||
|
|||
// Scan for the TCA9535 on I2C and log the result
|
|||
bool scanExpander() { |
|||
_wire->beginTransmission(_addr); |
|||
return (_wire->endTransmission() == 0); |
|||
} |
|||
}; |
|||
@ -42,11 +42,17 @@ build_flags = |
|||
-D CORE_DEBUG_LEVEL=4 ; 0: None, 1: Error, 2: Warn, 3: Info, 4: Debug, 5: Verbose |
|||
-D LV_CONF_PATH=lv_conf.h |
|||
-D SEEED_SENSECAP_INDICATOR |
|||
-D RADIO_CLASS=SX1262 |
|||
-D RADIO_CLASS=CustomSX1262 |
|||
-D WRAPPER_CLASS=CustomSX1262Wrapper |
|||
-D PIN_USER_BTN=38 |
|||
-D LANG_GR |
|||
-D LORA_FREQ=869.618 |
|||
-D LORA_BW=62.5 |
|||
-D LORA_SF=8 |
|||
-D LORA_CR=8 |
|||
-D LORA_TX_POWER=20 |
|||
-D SX126X_DIO3_TCXO_VOLTAGE=2.4 |
|||
-D SX126X_DIO2_AS_RF_SWITCH=true |
|||
-D ADVERT_NAME='"SenseCap Client"' |
|||
-D MAX_CONTACTS=350 |
|||
-D MAX_GROUP_CHANNELS=8 |
|||
@ -55,16 +61,13 @@ build_flags = |
|||
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 |
|||
; NOTE: DO NOT ENABLE --> -D ESPNOW_DEBUG_LOGGING=1 |
|||
build_src_filter = ${SenseCapIndicator-ESPNow.build_src_filter} |
|||
+<../examples/companion_radio/*.cpp> |
|||
;+<../examples/simple_secure_chat_ui/*.cpp> |
|||
+<../examples/simple_secure_chat_ui/*.cpp> |
|||
+<fonts/*.c> |
|||
+<UI/*.c> |
|||
lib_deps = |
|||
${SenseCapIndicator-ESPNow.lib_deps} |
|||
adafruit/Adafruit SSD1306 @ ^2.5.15 |
|||
fbiego/ESP32Time@^2.0.6 |
|||
lvgl/[email protected] |
|||
lovyan03/LovyanGFX@^1.1.16 |
|||
bitbank2/PNGdec@^1.1.6 |
|||
;tamctec/TAMC_GT911@^1.0.2 |
|||
densaugeo/base64 @ ~1.4.0 |
|||
|
|||
Loading…
Reference in new issue