From 29859c1bd9488e8a8348006789d90f47c9a17855 Mon Sep 17 00:00:00 2001 From: vistalba Date: Tue, 26 May 2026 20:21:33 +0200 Subject: [PATCH] feat: add M5Stack Unit C6L variant support Add variant configuration for M5Stack Unit C6L (ESP32-C6, SX1262 LoRa, SSD1306 64x48 SPI display). Includes: - Board class with PI4IO I/O expander for LoRa RF control - DIO flash mode fix for ESP32-C6 bootloader compatibility - SSD1306 SPI display with custom minimal UITask for 64x48 - CustomSerialBLEInterface fix for correct BLE Connected status - All 4 firmware environments: companion (USB/BLE), repeater, room server --- src/helpers/esp32/SerialBLEInterface.cpp | 2 +- src/helpers/ui/DisplayDriver.h | 32 ++++ src/helpers/ui/SSD1306SPIDisplay.cpp | 120 +++++++++++++++ src/helpers/ui/SSD1306SPIDisplay.h | 38 +++++ variants/m5stack_unit_c6l/UnitC6LBoard.cpp | 11 +- variants/m5stack_unit_c6l/UnitC6LBoard.h | 117 ++++++++++++++- .../m5stack_unit_c6l/companion/UITask.cpp | 111 ++++++++++++++ variants/m5stack_unit_c6l/companion/UITask.h | 29 ++++ variants/m5stack_unit_c6l/platformio.ini | 138 +++++++++--------- variants/m5stack_unit_c6l/target.h | 15 +- 10 files changed, 542 insertions(+), 71 deletions(-) create mode 100644 src/helpers/ui/SSD1306SPIDisplay.cpp create mode 100644 src/helpers/ui/SSD1306SPIDisplay.h create mode 100644 variants/m5stack_unit_c6l/companion/UITask.cpp create mode 100644 variants/m5stack_unit_c6l/companion/UITask.h diff --git a/src/helpers/esp32/SerialBLEInterface.cpp b/src/helpers/esp32/SerialBLEInterface.cpp index dcfa0e1e34..d14a386418 100644 --- a/src/helpers/esp32/SerialBLEInterface.cpp +++ b/src/helpers/esp32/SerialBLEInterface.cpp @@ -1,5 +1,5 @@ #include "SerialBLEInterface.h" -#include "esp_mac.h" +#include // See the following for generating UUIDs: // https://www.uuidgenerator.net/ diff --git a/src/helpers/ui/DisplayDriver.h b/src/helpers/ui/DisplayDriver.h index ec63c19123..dd65f39ec7 100644 --- a/src/helpers/ui/DisplayDriver.h +++ b/src/helpers/ui/DisplayDriver.h @@ -3,6 +3,38 @@ #include #include +struct MarqueeScroller { + int offset = 0; + unsigned long next_time = 0; + bool paused = true; + + void reset() { + offset = 0; + next_time = 0; + paused = true; + } + + // Call once per loop iteration to advance the scroll. + // textW/displayW in pixels, now = millis(). + void update(int textW, int displayW, unsigned long now, + unsigned long speed_ms = 150, unsigned long pause_ms = 2000) { + int maxScroll = textW - displayW; + if (maxScroll <= 0) { offset = 0; return; } + if (now < next_time) return; + if (paused) { + paused = false; + next_time = now + pause_ms; + } else { + offset++; + if (offset >= maxScroll) { + offset = 0; + paused = true; + } + next_time = now + speed_ms; + } + } +}; + class DisplayDriver { int _w, _h; protected: diff --git a/src/helpers/ui/SSD1306SPIDisplay.cpp b/src/helpers/ui/SSD1306SPIDisplay.cpp new file mode 100644 index 0000000000..78a4ce5391 --- /dev/null +++ b/src/helpers/ui/SSD1306SPIDisplay.cpp @@ -0,0 +1,120 @@ +#include "SSD1306SPIDisplay.h" + +// Check if SPI is ready (set by radio_init in target.cpp) +#if defined(P_LORA_SCLK) + extern bool spi_initialized; +#else + static bool spi_initialized = true; // Assume ready if no custom SPI +#endif + +bool SSD1306SPIDisplay::begin() { + // Defer actual initialization - SPI may not be ready yet + // Real init happens in lazyInit() on first use (after radio_init) + return true; +} + +bool SSD1306SPIDisplay::lazyInit() { + if (_initialized) return true; + if (!spi_initialized) { + Serial.println("SSD1306: SPI not initialized yet"); + return false; + } + + Serial.println("SSD1306: Attempting display init..."); + #ifdef DISPLAY_ROTATION + display.setRotation(DISPLAY_ROTATION); + #endif + // SPI is now initialized by radio_init() + // Pass periphBegin=false to skip spi.begin() since radio already did it + if (!display.begin(SSD1306_SWITCHCAPVCC, 0, true, false)) { + Serial.println("SSD1306: display.begin() FAILED"); + return false; + } + Serial.println("SSD1306: display.begin() OK"); + + // Fix for 64x48 displays: Adafruit library lacks this case and defaults + // to comPins=0x02 (sequential). Displays taller than 32px need 0x12 + // (alternative COM pin config) or the output is garbled. + #if defined(DISPLAY_WIDTH) && defined(DISPLAY_HEIGHT) + #if (DISPLAY_WIDTH == 64) && (DISPLAY_HEIGHT == 48) + display.ssd1306_command(SSD1306_SETCOMPINS); + display.ssd1306_command(0x12); + #endif + #endif + + // Clear any garbage in the display buffer + display.clearDisplay(); + display.display(); + _initialized = true; + return true; +} + +void SSD1306SPIDisplay::turnOn() { + if (!lazyInit()) return; + display.ssd1306_command(SSD1306_DISPLAYON); + _isOn = true; +} + +void SSD1306SPIDisplay::turnOff() { + if (!lazyInit()) return; + display.ssd1306_command(SSD1306_DISPLAYOFF); + _isOn = false; +} + +void SSD1306SPIDisplay::clear() { + if (!lazyInit()) return; + display.clearDisplay(); + display.display(); +} + +void SSD1306SPIDisplay::startFrame(Color bkg) { + if (!lazyInit()) return; + display.clearDisplay(); // TODO: apply 'bkg' + _color = SSD1306_WHITE; + display.setTextColor(_color); + display.setFont(NULL); // Default 6x8 font + display.setTextSize(1); + display.setTextWrap(false); + display.cp437(true); +} + +void SSD1306SPIDisplay::setTextSize(int sz) { + display.setTextSize(sz); +} + +void SSD1306SPIDisplay::setColor(Color c) { + _color = (c != 0) ? SSD1306_WHITE : SSD1306_BLACK; + display.setTextColor(_color); +} + +void SSD1306SPIDisplay::setCursor(int x, int y) { + display.setCursor(x, y); +} + +void SSD1306SPIDisplay::print(const char* str) { + display.print(str); +} + +void SSD1306SPIDisplay::fillRect(int x, int y, int w, int h) { + display.fillRect(x, y, w, h, _color); +} + +void SSD1306SPIDisplay::drawRect(int x, int y, int w, int h) { + display.drawRect(x, y, w, h, _color); +} + +void SSD1306SPIDisplay::drawXbm(int x, int y, const uint8_t* bits, int w, int h) { + display.drawBitmap(x, y, bits, w, h, SSD1306_WHITE); +} + +uint16_t SSD1306SPIDisplay::getTextWidth(const char* str) { + int16_t x1, y1; + uint16_t w, h; + display.getTextBounds(str, 0, 0, &x1, &y1, &w, &h); + return w; +} + +void SSD1306SPIDisplay::endFrame() { + if (!_initialized) return; + display.display(); +} diff --git a/src/helpers/ui/SSD1306SPIDisplay.h b/src/helpers/ui/SSD1306SPIDisplay.h new file mode 100644 index 0000000000..68539a5614 --- /dev/null +++ b/src/helpers/ui/SSD1306SPIDisplay.h @@ -0,0 +1,38 @@ +#pragma once + +#include "DisplayDriver.h" +#include +#include +#define SSD1306_NO_SPLASH +#include + +class SSD1306SPIDisplay : public DisplayDriver { + Adafruit_SSD1306 display; + bool _isOn; + bool _initialized; + uint8_t _color; + + bool lazyInit(); // Deferred init for SPI bus sharing + +public: + // Accept pre-initialized SPI - do NOT call spi.begin() + SSD1306SPIDisplay(SPIClass* spi, int16_t w, int16_t h, int8_t dc, int8_t rst, int8_t cs) + : DisplayDriver(w, h), display(w, h, spi, dc, rst, cs) { _isOn = false; _initialized = false; } + + bool begin(); + + bool isOn() override { return _isOn; } + void turnOn() override; + void turnOff() override; + void clear() override; + void startFrame(Color bkg = DARK) override; + void setTextSize(int sz) override; + void setColor(Color c) override; + void setCursor(int x, int y) override; + void print(const char* str) override; + void fillRect(int x, int y, int w, int h) override; + void drawRect(int x, int y, int w, int h) override; + void drawXbm(int x, int y, const uint8_t* bits, int w, int h) override; + uint16_t getTextWidth(const char* str) override; + void endFrame() override; +}; diff --git a/variants/m5stack_unit_c6l/UnitC6LBoard.cpp b/variants/m5stack_unit_c6l/UnitC6LBoard.cpp index ab192ebeff..8350f2128e 100644 --- a/variants/m5stack_unit_c6l/UnitC6LBoard.cpp +++ b/variants/m5stack_unit_c6l/UnitC6LBoard.cpp @@ -4,7 +4,8 @@ UnitC6LBoard board; #if defined(P_LORA_SCLK) - static SPIClass spi(0); + SPIClass spi(0); + bool spi_initialized = false; RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); #else RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY); @@ -16,12 +17,17 @@ ESP32RTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); SensorManager sensors; +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display(&spi, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_DC, DISPLAY_RST, DISPLAY_CS); +#endif + bool radio_init() { fallback_clock.begin(); rtc_clock.begin(Wire); #if defined(P_LORA_SCLK) spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); + spi_initialized = true; return radio.std_init(&spi); #else return radio.std_init(); @@ -30,6 +36,5 @@ bool radio_init() { mesh::LocalIdentity radio_new_identity() { RadioNoiseListener rng(radio); - return mesh::LocalIdentity(&rng); // create new random identity + return mesh::LocalIdentity(&rng); } - diff --git a/variants/m5stack_unit_c6l/UnitC6LBoard.h b/variants/m5stack_unit_c6l/UnitC6LBoard.h index a4ea3ee6e5..88ba4649f2 100644 --- a/variants/m5stack_unit_c6l/UnitC6LBoard.h +++ b/variants/m5stack_unit_c6l/UnitC6LBoard.h @@ -1,15 +1,130 @@ #pragma once #include +#include #include +// PI4IO I/O Expander (I2C address 0x43) +// Pin mapping: +// P0 = Button (active low) +// P1 = (unused input) +// P5 = LNA_EN (LNA Enable) +// P6 = ANT_SW (RF Switch) +// P7 = NRST (LoRa Reset) +#define PI4IO_ADDR 0x43 + +// PI4IO registers +#define PI4IO_REG_CHIP_RESET 0x01 +#define PI4IO_REG_IO_DIR 0x03 +#define PI4IO_REG_OUT_SET 0x05 +#define PI4IO_REG_OUT_H_IM 0x07 +#define PI4IO_REG_IN_DEF_STA 0x09 +#define PI4IO_REG_PULL_EN 0x0B +#define PI4IO_REG_PULL_SEL 0x0D +#define PI4IO_REG_IN_STA 0x0F +#define PI4IO_REG_INT_MASK 0x11 +#define PI4IO_REG_IRQ_STA 0x13 + class UnitC6LBoard : public ESP32Board { +private: + bool i2c_write_byte(uint8_t addr, uint8_t reg, uint8_t value) { + Wire.beginTransmission(addr); + Wire.write(reg); + Wire.write(value); + return Wire.endTransmission() == 0; + } + + bool i2c_read_byte(uint8_t addr, uint8_t reg, uint8_t *value) { + Wire.beginTransmission(addr); + Wire.write(reg); + if (Wire.endTransmission() != 0) return false; + if (Wire.requestFrom(addr, (uint8_t)1) != 1) return false; + if (!Wire.available()) return false; + *value = Wire.read(); + return true; + } + + void initIOExpander() { + uint8_t in_data; + + // Reset the I/O expander + i2c_write_byte(PI4IO_ADDR, PI4IO_REG_CHIP_RESET, 0xFF); + delay(10); + + i2c_read_byte(PI4IO_ADDR, PI4IO_REG_CHIP_RESET, &in_data); + delay(10); + + // Set P5, P6, P7 as outputs (0: input, 1: output) + i2c_write_byte(PI4IO_ADDR, PI4IO_REG_IO_DIR, 0b11100000); + delay(10); + + // Disable High-Impedance for used pins + i2c_write_byte(PI4IO_ADDR, PI4IO_REG_OUT_H_IM, 0b00011100); + delay(10); + + // Pull up/down select (0: down, 1: up) + i2c_write_byte(PI4IO_ADDR, PI4IO_REG_PULL_SEL, 0b11100011); + delay(10); + + // Pull up/down enable (0: disable, 1: enable) + i2c_write_byte(PI4IO_ADDR, PI4IO_REG_PULL_EN, 0b11100011); + delay(10); + + // Default input state for P0, P1 (buttons) + i2c_write_byte(PI4IO_ADDR, PI4IO_REG_IN_DEF_STA, 0b00000011); + delay(10); + + // Enable interrupts for P0, P1 (0: enable, 1: disable) + i2c_write_byte(PI4IO_ADDR, PI4IO_REG_INT_MASK, 0b11111100); + delay(10); + + // Set P7 (Reset) high, P5 and P6 will be set after + i2c_write_byte(PI4IO_ADDR, PI4IO_REG_OUT_SET, 0b10000000); + delay(10); + + // Clear IRQ status + i2c_read_byte(PI4IO_ADDR, PI4IO_REG_IRQ_STA, &in_data); + + // Enable RF switch (P6 high) and LNA (P5 high) + i2c_read_byte(PI4IO_ADDR, PI4IO_REG_OUT_SET, &in_data); + in_data |= (1 << 6); // P6 = RF Switch = HIGH + in_data |= (1 << 5); // P5 = LNA Enable = HIGH + i2c_write_byte(PI4IO_ADDR, PI4IO_REG_OUT_SET, in_data); + } + public: void begin() { ESP32Board::begin(); + + // Initialize I/O expander for LoRa RF control + initIOExpander(); + +#ifdef PIN_BUZZER + pinMode(PIN_BUZZER, OUTPUT); + digitalWrite(PIN_BUZZER, LOW); +#endif } const char* getManufacturerName() const override { - return "Unit C6L"; + return "M5Stack Unit C6L"; + } + + // Read button state from I/O expander P0 (active low) + bool isButtonPressed() { + uint8_t in_data = 0xFF; + if (!i2c_read_byte(PI4IO_ADDR, PI4IO_REG_IN_STA, &in_data)) { + return false; + } + return !(in_data & 0x01); + } + +#ifdef PIN_BUZZER + void playTone(uint16_t frequency, uint16_t duration_ms) { + tone(PIN_BUZZER, frequency, duration_ms); + } + + void stopTone() { + noTone(PIN_BUZZER); } +#endif }; diff --git a/variants/m5stack_unit_c6l/companion/UITask.cpp b/variants/m5stack_unit_c6l/companion/UITask.cpp new file mode 100644 index 0000000000..c177b6ac4a --- /dev/null +++ b/variants/m5stack_unit_c6l/companion/UITask.cpp @@ -0,0 +1,111 @@ +#include "UITask.h" +#include +#include "../../examples/companion_radio/MyMesh.h" + +#define AUTO_OFF_MILLIS 30000 +#define BOOT_SCREEN_MILLIS 4000 +#define SCROLL_SPEED_MS 150 +#define SCROLL_PAUSE_MS 2000 + +void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* node_prefs) { + _display = display; + _node_prefs = node_prefs; + _need_refresh = true; + _msgcount = 0; + _next_refresh = 0; + _auto_off = millis() + AUTO_OFF_MILLIS; + _scroller.reset(); + + if (_display != NULL) { + _display->turnOn(); + } +} + +void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) { + _msgcount = msgcount; + _need_refresh = true; + if (_display != NULL && !_display->isOn()) { + _display->turnOn(); + _auto_off = millis() + AUTO_OFF_MILLIS; + } +} + +void UITask::renderScreen() { + if (_display == NULL) return; + + int w = _display->width(); + char tmp[32]; + + if (millis() < BOOT_SCREEN_MILLIS) { + _display->setTextSize(1); + _display->drawTextCentered(w / 2, 3, "MeshCore"); + _display->drawTextCentered(w / 2, 20, FIRMWARE_VERSION); + _display->drawTextCentered(w / 2, 34, "Companion"); + return; + } + + _display->setTextSize(1); + +#ifdef BLE_PIN_CODE + uint32_t pin = the_mesh.getBLEPin(); + if (_connected) { + _display->drawTextCentered(w / 2, 0, "Connected"); + } else if (pin != 0) { + sprintf(tmp, "PIN:%06d", pin); + _display->drawTextCentered(w / 2, 0, tmp); + } else { + _display->drawTextCentered(w / 2, 0, "Ready"); + } +#else + _display->drawTextCentered(w / 2, 0, "USB Ready"); +#endif + + int nameW = _display->getTextWidth(_node_prefs->node_name); + if (nameW <= w) { + _display->setCursor(0, 10); + _display->print(_node_prefs->node_name); + } else { + _display->setCursor(-_scroller.offset, 10); + _display->print(_node_prefs->node_name); + } + + sprintf(tmp, "%.3f", _node_prefs->freq); + _display->setCursor(0, 20); + _display->print(tmp); + + if (_msgcount > 0) { + sprintf(tmp, "%d unread", _msgcount); + _display->setCursor(0, 30); + _display->print(tmp); + } +} + +void UITask::loop() { + if (_display == NULL) return; + + if (board.isButtonPressed()) { + if (!_display->isOn()) { + _display->turnOn(); + _need_refresh = true; + } + _auto_off = millis() + AUTO_OFF_MILLIS; + } + + if (_display->isOn()) { + if (_node_prefs != NULL) { + _scroller.update(_display->getTextWidth(_node_prefs->node_name), + _display->width(), millis(), SCROLL_SPEED_MS, SCROLL_PAUSE_MS); + } + + if (millis() >= _next_refresh) { + _display->startFrame(); + renderScreen(); + _display->endFrame(); + _next_refresh = millis() + 200; + } + + if (millis() > _auto_off) { + _display->turnOff(); + } + } +} diff --git a/variants/m5stack_unit_c6l/companion/UITask.h b/variants/m5stack_unit_c6l/companion/UITask.h new file mode 100644 index 0000000000..2a681ed1da --- /dev/null +++ b/variants/m5stack_unit_c6l/companion/UITask.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include +#include "../../examples/companion_radio/NodePrefs.h" +#include "../../examples/companion_radio/AbstractUITask.h" + +class UITask : public AbstractUITask { +public: + UITask(mesh::MainBoard* board, BaseSerialInterface* serial) + : AbstractUITask(board, serial), _display(NULL) {} + + void begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* node_prefs); + void loop() override; + void notify(UIEventType t) override {} + void msgRead(int msgcount) override { _msgcount = msgcount; _need_refresh = true; } + void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) override; + +private: + void renderScreen(); + DisplayDriver* _display; + NodePrefs* _node_prefs; + int _msgcount; + bool _need_refresh; + uint32_t _next_refresh; + uint32_t _auto_off; + MarqueeScroller _scroller; +}; diff --git a/variants/m5stack_unit_c6l/platformio.ini b/variants/m5stack_unit_c6l/platformio.ini index 94083eb486..c64f9945ab 100644 --- a/variants/m5stack_unit_c6l/platformio.ini +++ b/variants/m5stack_unit_c6l/platformio.ini @@ -1,12 +1,17 @@ -[M5Stack_Unit_C6L] +; M5Stack Unit C6L - ESP32-C6 with SX1262 LoRa +; https://docs.m5stack.com/en/unit/Unit_C6L +[m5stack_unit_c6l] extends = esp32c6_base board = esp32-c6-devkitm-1 +board_build.flash_mode = dio board_build.partitions = min_spiffs.csv ; get around 4mb flash limit build_flags = ${esp32c6_base.build_flags} ${sensor_base.build_flags} -I variants/m5stack_unit_c6l - -D P_LORA_TX_LED=15 + -D ARDUINO_USB_CDC_ON_BOOT=1 + -D ARDUINO_USB_MODE=1 + ; LoRa SX1262 SPI pins -D P_LORA_SCLK=20 -D P_LORA_MISO=22 -D P_LORA_MOSI=21 @@ -14,99 +19,102 @@ build_flags = -D P_LORA_DIO_1=7 -D P_LORA_BUSY=19 -D P_LORA_RESET=-1 - -D PIN_BUZZER=11 - -D PIN_BOARD_SDA=16 - -D PIN_BOARD_SCL=17 - -D SX126X_RXEN=5 + ; I2C pins (PI4IO expander + sensors) + -D PIN_BOARD_SDA=10 + -D PIN_BOARD_SCL=8 + ; SX1262 configuration -D SX126X_DIO2_AS_RF_SWITCH=true - -D SX126X_DIO3_TCXO_VOLTAGE=1.8 + -D SX126X_DIO3_TCXO_VOLTAGE=3.0 -D SX126X_CURRENT_LIMIT=140 -D SX126X_RX_BOOSTED_GAIN=1 - -D USE_SX1262 + ; Radio configuration -D RADIO_CLASS=CustomSX1262 -D WRAPPER_CLASS=CustomSX1262Wrapper -D LORA_TX_POWER=22 -D DISABLE_WIFI_OTA=1 + ; NeoPixel LED for TX indication + -D P_LORA_TX_NEOPIXEL_LED=2 + ; Buzzer + -D PIN_BUZZER=11 + ; GPS on Grove port -D GPS_RX=4 -D GPS_TX=5 -build_src_filter = ${esp32c6_base.build_src_filter} - +<../variants/m5stack_unit_c6l> - + + ; Display configuration (64x48 SSD1306 OLED via SPI, shared with LoRa) + -D DISPLAY_CLASS=SSD1306SPIDisplay + -D DISPLAY_CS=6 + -D DISPLAY_DC=18 + -D DISPLAY_RST=15 + -D DISPLAY_WIDTH=64 + -D DISPLAY_HEIGHT=48 + -D DISPLAY_ROTATION=2 lib_deps = ${esp32c6_base.lib_deps} - ${sensor_base.lib_deps} - -[env:M5Stack_Unit_C6L_repeater] -extends = M5Stack_Unit_C6L -build_src_filter = ${M5Stack_Unit_C6L.build_src_filter} - +<../examples/simple_repeater/*.cpp> -build_flags = - ${M5Stack_Unit_C6L.build_flags} - -D ADVERT_NAME='"Unit C6L Repeater"' - -D ADVERT_LAT=0.0 - -D ADVERT_LON=0.0 - -D ADMIN_PASSWORD='"password"' - -D MAX_NEIGHBOURS=50 -; -D MESH_PACKET_LOGGING=1 -; -D MESH_DEBUG=1 -lib_deps = - ${M5Stack_Unit_C6L.lib_deps} -; ${esp32_ota.lib_deps} + adafruit/Adafruit SSD1306 @ ^2.5.13 +build_src_filter = ${esp32c6_base.build_src_filter} + +<../variants/m5stack_unit_c6l> + -<../variants/m5stack_unit_c6l/companion/*.cpp> + + -[env:M5Stack_Unit_C6L_room_server] -extends = M5Stack_Unit_C6L -build_src_filter = ${M5Stack_Unit_C6L.build_src_filter} - +<../examples/simple_room_server> +[env:m5stack_unit_c6l_companion_radio_usb] +extends = m5stack_unit_c6l build_flags = - ${M5Stack_Unit_C6L.build_flags} - -D ADVERT_NAME='"Unit C6L Room"' - -D ADVERT_LAT=0.0 - -D ADVERT_LON=0.0 - -D ADMIN_PASSWORD='"password"' - -D ROOM_PASSWORD='"hello"' -; -D MESH_PACKET_LOGGING=1 -; -D MESH_DEBUG=1 -lib_deps = - ${M5Stack_Unit_C6L.lib_deps} -; ${esp32_ota.lib_deps} - -[env:M5Stack_Unit_C6L_companion_radio_ble] -extends = M5Stack_Unit_C6L -build_flags = ${M5Stack_Unit_C6L.build_flags} + ${m5stack_unit_c6l.build_flags} -D MAX_CONTACTS=350 -D MAX_GROUP_CHANNELS=40 - -D BLE_PIN_CODE=123456 - -D BLE_DEBUG_LOGGING=1 -D OFFLINE_QUEUE_SIZE=256 -; -D MESH_PACKET_LOGGING=1 -; -D MESH_DEBUG=1 -build_src_filter = ${M5Stack_Unit_C6L.build_src_filter} + -I variants/m5stack_unit_c6l/companion +build_src_filter = ${m5stack_unit_c6l.build_src_filter} + - +<../examples/companion_radio/*.cpp> + +<../variants/m5stack_unit_c6l/companion/*.cpp> lib_deps = - ${M5Stack_Unit_C6L.lib_deps} + ${m5stack_unit_c6l.lib_deps} densaugeo/base64 @ ~1.4.0 end2endzone/NonBlockingRTTTL@^1.3.0 -[env:M5Stack_Unit_C6L_companion_radio_usb] -extends = M5Stack_Unit_C6L -build_flags = ${M5Stack_Unit_C6L.build_flags} +[env:m5stack_unit_c6l_companion_radio_ble] +extends = m5stack_unit_c6l +build_flags = + ${m5stack_unit_c6l.build_flags} -D MAX_CONTACTS=350 -D MAX_GROUP_CHANNELS=40 + -D BLE_PIN_CODE=123456 -D OFFLINE_QUEUE_SIZE=256 - -D ARDUINO_USB_CDC_ON_BOOT=1 - -D ARDUINO_USB_MODE=1 -build_src_filter = ${M5Stack_Unit_C6L.build_src_filter} + -I variants/m5stack_unit_c6l/companion +build_src_filter = ${m5stack_unit_c6l.build_src_filter} + - +<../examples/companion_radio/*.cpp> + +<../variants/m5stack_unit_c6l/companion/*.cpp> lib_deps = - ${M5Stack_Unit_C6L.lib_deps} + ${m5stack_unit_c6l.lib_deps} densaugeo/base64 @ ~1.4.0 end2endzone/NonBlockingRTTTL@^1.3.0 -[env:M5Stack_Unit_C6L_kiss_modem] -extends = M5Stack_Unit_C6L -build_src_filter = ${M5Stack_Unit_C6L.build_src_filter} - +<../examples/kiss_modem/> +[env:m5stack_unit_c6l_repeater] +extends = m5stack_unit_c6l +build_flags = + ${m5stack_unit_c6l.build_flags} + -D ADVERT_NAME='"M5Stack C6L Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=50 +build_src_filter = ${m5stack_unit_c6l.build_src_filter} + +<../examples/simple_repeater> +lib_deps = + ${m5stack_unit_c6l.lib_deps} + +[env:m5stack_unit_c6l_room_server] +extends = m5stack_unit_c6l +build_flags = ${m5stack_unit_c6l.build_flags} + -D ADVERT_NAME='"M5Stack C6L Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +build_src_filter = ${m5stack_unit_c6l.build_src_filter} + +<../examples/simple_room_server> +lib_deps = + ${m5stack_unit_c6l.lib_deps} diff --git a/variants/m5stack_unit_c6l/target.h b/variants/m5stack_unit_c6l/target.h index 0a959b97dc..6809524fa8 100644 --- a/variants/m5stack_unit_c6l/target.h +++ b/variants/m5stack_unit_c6l/target.h @@ -9,10 +9,23 @@ #include #include +#ifdef DISPLAY_CLASS + #include + extern DISPLAY_CLASS display; +#endif + +#if defined(P_LORA_SCLK) + extern SPIClass spi; + extern bool spi_initialized; +#endif + extern UnitC6LBoard board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; extern SensorManager sensors; bool radio_init(); -mesh::LocalIdentity radio_new_identity(); \ No newline at end of file +uint32_t radio_get_rng_seed(); +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); +void radio_set_tx_power(uint8_t dbm); +mesh::LocalIdentity radio_new_identity();