diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml index b8c24ab2b..795c1b1a0 100644 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -32,6 +32,7 @@ body: options: - Not Applicable - T-Beam + - T-Beam S3 - T-Beam 0.7 - T-Lora v1 - T-Lora v1.3 @@ -42,6 +43,7 @@ body: - Heltec v1 - Heltec v2 - Heltec v2.1 + - Heltec V3 - Relay v1 - Relay v2 - DIY diff --git a/.github/workflows/build_esp32_s3.yml b/.github/workflows/build_esp32_s3.yml new file mode 100644 index 000000000..7f556a991 --- /dev/null +++ b/.github/workflows/build_esp32_s3.yml @@ -0,0 +1,59 @@ +name: Build ESP32-S3 + +on: + workflow_call: + inputs: + board: + required: true + type: string + +jobs: + build-esp32-s3: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Build base + id: base + uses: ./.github/actions/setup-base + + - name: Pull web ui + uses: dsaltares/fetch-gh-release-asset@master + with: + repo: "meshtastic/web" + file: "build.tar" + target: "build.tar" + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Unpack web ui + run: | + tar -xf build.tar -C data/static + rm build.tar + - name: Remove debug flags for release + if: ${{ github.event_name == 'workflow_dispatch' }} + run: | + sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini + sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini + sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini + - name: Build ESP32 + run: bin/build-esp32.sh ${{ inputs.board }} + + - name: Pull OTA Firmware + uses: dsaltares/fetch-gh-release-asset@master + with: + repo: "meshtastic/firmware-ota" + file: "firmware-s3.bin" + target: "release/bleota-s3.bin" + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Get release version string + shell: bash + run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT + id: version + + - name: Store binaries as an artifact + uses: actions/upload-artifact@v3 + with: + name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip + path: | + release/*.bin + release/*.elf diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index 13c32d783..ccc7c4ca8 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -62,8 +62,6 @@ jobs: - board: heltec-v1 - board: heltec-v2.0 - board: heltec-v2.1 - - board: heltec-v3 - - board: heltec-wsl-v3 - board: tbeam0.7 - board: meshtastic-diy-v1 - board: meshtastic-dr-dev @@ -71,13 +69,24 @@ jobs: - board: station-g1 - board: m5stack-core - board: m5stack-coreink - - board: tbeam-s3-core - - board: tlora-t3s3-v1 - board: nano-g1-explorer uses: ./.github/workflows/build_esp32.yml with: board: ${{ matrix.board }} + build-esp32-s3: + strategy: + fail-fast: false + matrix: + include: + - board: heltec-v3 + - board: heltec-wsl-v3 + - board: tbeam-s3-core + - board: tlora-t3s3-v1 + uses: ./.github/workflows/build_esp32_s3.yml + with: + board: ${{ matrix.board }} + build-nrf52: strategy: fail-fast: false @@ -176,7 +185,7 @@ jobs: gather-artifacts: runs-on: ubuntu-latest - needs: [build-esp32, build-nrf52, build-native] #, build-rpi2040] + needs: [build-esp32, build-esp32-s3, build-nrf52, build-native] #, build-rpi2040] steps: - name: Checkout code uses: actions/checkout@v3 @@ -193,7 +202,7 @@ jobs: id: version - name: Move files up - run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat + run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./*tbeam-s3*/bleota-s3.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat - name: Repackage in single firmware zip uses: actions/upload-artifact@v3 diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini index 99433b6ba..5cc48e191 100644 --- a/arch/esp32/esp32.ini +++ b/arch/esp32/esp32.ini @@ -1,7 +1,7 @@ ; Common settings for ESP targes, mixin with extends = esp32_base [esp32_base] extends = arduino_base -platform = platformio/espressif32@^6.0.0 +platform = platformio/espressif32@^6.1.0 build_src_filter = ${arduino_base.build_src_filter} - - - - upload_speed = 921600 diff --git a/arch/esp32/esp32s2.ini b/arch/esp32/esp32s2.ini index 1182e6d83..b266d1792 100644 --- a/arch/esp32/esp32s2.ini +++ b/arch/esp32/esp32s2.ini @@ -1,6 +1,6 @@ [esp32s2_base] extends = arduino_base -platform = platformio/espressif32@^6.0.0 +platform = platformio/espressif32@^6.1.0 build_src_filter = ${arduino_base.build_src_filter} - - - - - upload_speed = 961200 diff --git a/arch/esp32/esp32s3.ini b/arch/esp32/esp32s3.ini index ed5127bbe..9a042b22b 100644 --- a/arch/esp32/esp32s3.ini +++ b/arch/esp32/esp32s3.ini @@ -1,6 +1,6 @@ [esp32s3_base] extends = arduino_base -platform = platformio/espressif32@^6.0.0 +platform = platformio/espressif32@^6.1.0 build_src_filter = ${arduino_base.build_src_filter} - - - - upload_speed = 961200 diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini index 9ee2c37b5..c2287d7e5 100644 --- a/arch/nrf52/nrf52.ini +++ b/arch/nrf52/nrf52.ini @@ -1,6 +1,6 @@ [nrf52_base] ; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files -platform = platformio/nordicnrf52@^9.4.0 +platform = platformio/nordicnrf52@^9.5.0 extends = arduino_base build_type = debug ; I'm debugging with ICE a lot now diff --git a/bin/build-esp32.sh b/bin/build-esp32.sh index 6068eb256..f60331ed5 100755 --- a/bin/build-esp32.sh +++ b/bin/build-esp32.sh @@ -34,7 +34,7 @@ SRCBIN=.pio/build/$1/firmware.bin cp $SRCBIN $OUTDIR/$basename-update.bin echo "Building Filesystem for ESP32 targets" -pio run --environment tbeam -t buildfs -cp .pio/build/tbeam/littlefs.bin $OUTDIR/littlefs-$VERSION.bin +pio run --environment $1 -t buildfs +cp .pio/build/$1/littlefs.bin $OUTDIR/littlefs-$VERSION.bin cp bin/device-install.* $OUTDIR cp bin/device-update.* $OUTDIR diff --git a/bin/device-install.bat b/bin/device-install.bat index 15c2db352..4d14193e5 100755 --- a/bin/device-install.bat +++ b/bin/device-install.bat @@ -30,7 +30,13 @@ IF EXIST %FILENAME% IF x%FILENAME:update=%==x%FILENAME% ( echo Trying to flash update %FILENAME%, but first erasing and writing system information" %PYTHON% -m esptool --baud 115200 erase_flash %PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME% - %PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin + + @REM Account for S3 board's different OTA partition + IF x%FILENAME:s3=%==x%FILENAME% IF x%FILENAME:v3=%==x%FILENAME% ( + %PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin + ) else ( + %PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota-s3.bin + ) for %%f in (littlefs-*.bin) do ( %PYTHON% -m esptool --baud 115200 write_flash 0x300000 %%f ) diff --git a/bin/device-install.sh b/bin/device-install.sh index ca60740ab..cd5d6ad59 100755 --- a/bin/device-install.sh +++ b/bin/device-install.sh @@ -49,7 +49,12 @@ if [ -f "${FILENAME}" ] && [ ! -z "${FILENAME##*"update"*}" ]; then echo "Trying to flash ${FILENAME}, but first erasing and writing system information" "$PYTHON" -m esptool erase_flash "$PYTHON" -m esptool write_flash 0x00 ${FILENAME} - "$PYTHON" -m esptool write_flash 0x260000 bleota.bin + # Account for S3 board's different OTA partition + if [ ! -z "${FILENAME##*"s3"*}" ] && [ ! -z "${FILENAME##*"-v3"*}" ]; then + "$PYTHON" -m esptool write_flash 0x260000 bleota.bin + else + "$PYTHON" -m esptool write_flash 0x260000 bleota-s3.bin + fi "$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin else diff --git a/boards/tlora-t3s3-v1.json b/boards/tlora-t3s3-v1.json index d073fc7c1..c5a68981b 100644 --- a/boards/tlora-t3s3-v1.json +++ b/boards/tlora-t3s3-v1.json @@ -9,7 +9,8 @@ "-DARDUINO_USB_CDC_ON_BOOT=1", "-DARDUINO_USB_MODE=0", "-DARDUINO_RUNNING_CORE=1", - "-DARDUINO_EVENT_RUNNING_CORE=1" + "-DARDUINO_EVENT_RUNNING_CORE=1", + "-DBOARD_HAS_PSRAM" ], "f_cpu": "240000000L", "f_flash": "80000000L", diff --git a/platformio.ini b/platformio.ini index af18a6f8b..b54274a46 100644 --- a/platformio.ini +++ b/platformio.ini @@ -59,15 +59,14 @@ build_flags = -Wno-missing-field-initializers monitor_speed = 115200 lib_deps = - https://github.com/meshtastic/esp8266-oled-ssd1306.git#da1ede4dfcd91074283b029080759fd744120909 ; ESP8266_SSD1306 + https://github.com/meshtastic/esp8266-oled-ssd1306.git#b38094e03dfa964fbc0e799bc374e91a605c1223 ; ESP8266_SSD1306 mathertel/OneButton@^2.0.3 ; OneButton library for non-blocking button debounce https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159 https://github.com/meshtastic/TinyGPSPlus.git#127ad674ef85f0201cb68a065879653ed94792c4 https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3 - nanopb/Nanopb@^0.4.6 + nanopb/Nanopb@^0.4.7 erriez/ErriezCRC32@^1.0.1 -; jgromes/RadioLib@^5.5.1 - https://github.com/jgromes/RadioLib.git#1afa947030c5637f71f6563bc22aa75032e53a57 + jgromes/RadioLib@^5.7.0 ; Used for the code analysis in PIO Home / Inspect check_tool = cppcheck @@ -101,7 +100,7 @@ lib_deps = [environmental_base] lib_deps = adafruit/Adafruit BusIO@^1.11.4 - adafruit/Adafruit Unified Sensor@^1.1.4 + adafruit/Adafruit Unified Sensor@^1.1.9 adafruit/Adafruit BMP280 Library@^2.6.6 adafruit/Adafruit BME280 Library@^2.2.2 adafruit/Adafruit BME680 Library@^2.0.1 diff --git a/protobufs b/protobufs index b3d05ec99..e3e22cdee 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit b3d05ec995844ae888e1d43d6e5c770b7d654309 +Subproject commit e3e22cdee6024663031fa2d87afd98a88adc2685 diff --git a/src/ButtonThread.h b/src/ButtonThread.h index 5bb856027..f35c53a46 100644 --- a/src/ButtonThread.h +++ b/src/ButtonThread.h @@ -123,9 +123,6 @@ class ButtonThread : public concurrency::OSThread static void userButtonPressedLong() { // LOG_DEBUG("Long press!\n"); -#ifdef ARCH_ESP32 - screen->adjustBrightness(); -#endif // If user button is held down for 5 seconds, shutdown the device. if ((millis() - longPressTime > 5 * 1000) && (longPressTime > 0)) { #ifdef HAS_PMU @@ -133,7 +130,7 @@ class ButtonThread : public concurrency::OSThread setLed(false); power->shutdown(); } -#elif defined(ARCH_NRF52) +#elif defined(ARCH_NRF52) || defined(ARCH_ESP32) // Do actual shutdown when button released, otherwise the button release // may wake the board immediatedly. if ((!shutdown_on_long_stop) && (millis() > 30 * 1000)) { diff --git a/src/Power.cpp b/src/Power.cpp index f84c7b71d..5c5c7bca9 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -13,6 +13,10 @@ #include #endif +#ifndef DELAY_FOREVER +#define DELAY_FOREVER portMAX_DELAY +#endif + #ifdef HAS_PMU #include "XPowersAXP192.tpp" #include "XPowersAXP2101.tpp" @@ -256,16 +260,24 @@ void Power::shutdown() digitalWrite(PIN_EINK_EN, LOW); // power off backlight first #endif -#ifdef HAS_PMU LOG_INFO("Shutting down\n"); + +#ifdef HAS_PMU if (PMU) { PMU->setChargingLedMode(XPOWERS_CHG_LED_OFF); - PMU->shutdown(); } -#elif defined(ARCH_NRF52) - playBeep(); +#endif + +#if defined(ARCH_NRF52) || defined(ARCH_ESP32) +#ifdef PIN_LED1 ledOff(PIN_LED1); +#endif +#ifdef PIN_LED2 ledOff(PIN_LED2); +#endif +#ifdef PIN_LED3 + ledOff(PIN_LED2); +#endif doDeepSleep(DELAY_FOREVER); #endif } diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp new file mode 100644 index 000000000..e72478c17 --- /dev/null +++ b/src/detect/ScanI2C.cpp @@ -0,0 +1,70 @@ +#include "ScanI2C.h" + +const ScanI2C::DeviceAddress ScanI2C::ADDRESS_NONE = ScanI2C::DeviceAddress(); +const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ADDRESS_NONE); + +ScanI2C::ScanI2C() = default; + +void ScanI2C::scanPort(ScanI2C::I2CPort port) {} + +void ScanI2C::setSuppressScreen() +{ + shouldSuppressScreen = true; +} + +ScanI2C::FoundDevice ScanI2C::firstScreen() const +{ + // Allow to override the scanner results for screen + if (shouldSuppressScreen) + return DEVICE_NONE; + + ScanI2C::DeviceType types[] = {SCREEN_SSD1306, SCREEN_SH1106, SCREEN_ST7567, SCREEN_UNKNOWN}; + return firstOfOrNONE(4, types); +} + +ScanI2C::FoundDevice ScanI2C::firstRTC() const +{ + ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563}; + return firstOfOrNONE(2, types); +} + +ScanI2C::FoundDevice ScanI2C::firstKeyboard() const +{ + ScanI2C::DeviceType types[] = {CARDKB, RAK14004}; + return firstOfOrNONE(2, types); +} + +ScanI2C::FoundDevice ScanI2C::find(ScanI2C::DeviceType) const +{ + return DEVICE_NONE; +} + +bool ScanI2C::exists(ScanI2C::DeviceType) const +{ + return false; +} + +ScanI2C::FoundDevice ScanI2C::firstOfOrNONE(size_t count, ScanI2C::DeviceType *types) const +{ + return DEVICE_NONE; +} + +size_t ScanI2C::countDevices() const +{ + return 0; +} + +ScanI2C::DeviceAddress::DeviceAddress(ScanI2C::I2CPort port, uint8_t address) : port(port), address(address) {} + +ScanI2C::DeviceAddress::DeviceAddress() : DeviceAddress(I2CPort::NO_I2C, 0) {} + +bool ScanI2C::DeviceAddress::operator<(const ScanI2C::DeviceAddress &other) const +{ + return + // If this one has no port and other has a port + (port == NO_I2C && other.port != NO_I2C) + // if both have a port and this one's address is lower + || (port != NO_I2C && other.port != NO_I2C && (address < other.address)); +} + +ScanI2C::FoundDevice::FoundDevice(ScanI2C::DeviceType type, ScanI2C::DeviceAddress address) : type(type), address(address) {} diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h new file mode 100644 index 000000000..0e7e442b1 --- /dev/null +++ b/src/detect/ScanI2C.h @@ -0,0 +1,93 @@ +#pragma once + +#include +#include + +class ScanI2C +{ + public: + typedef enum DeviceType { + NONE, + SCREEN_SSD1306, + SCREEN_SH1106, + SCREEN_UNKNOWN, // has the same address as the two above but does not respond to the same commands + SCREEN_ST7567, + ATECC608B, + RTC_RV3028, + RTC_PCF8563, + CARDKB, + RAK14004, + PMU_AXP192_AXP2101, + BME_680, + BME_280, + BMP_280, + INA260, + INA219, + MCP9808, + SHT31, + SHTC3, + LPS22HB, + QMC6310, + QMI8658, + QMC5883L, + PMSA0031, + } DeviceType; + + // typedef uint8_t DeviceAddress; + typedef enum I2CPort { + NO_I2C, + WIRE, + WIRE1, + } I2CPort; + + typedef struct DeviceAddress { + I2CPort port; + uint8_t address; + + explicit DeviceAddress(I2CPort port, uint8_t address); + DeviceAddress(); + + bool operator<(const DeviceAddress &other) const; + } DeviceAddress; + + static const DeviceAddress ADDRESS_NONE; + + typedef uint8_t RegisterAddress; + + typedef struct FoundDevice { + DeviceType type; + DeviceAddress address; + + explicit FoundDevice(DeviceType = DeviceType::NONE, DeviceAddress = ADDRESS_NONE); + } FoundDevice; + + static const FoundDevice DEVICE_NONE; + + public: + ScanI2C(); + + virtual void scanPort(ScanI2C::I2CPort); + + /* + * A bit of a hack, this tells the scanner not to tell later systems there is a screen to avoid enabling it. + */ + void setSuppressScreen(); + + FoundDevice firstScreen() const; + + FoundDevice firstRTC() const; + + FoundDevice firstKeyboard() const; + + virtual FoundDevice find(DeviceType) const; + + virtual bool exists(DeviceType) const; + + virtual size_t countDevices() const; + + protected: + virtual FoundDevice firstOfOrNONE(size_t, DeviceType[]) const; + + private: + bool shouldSuppressScreen = false; +}; diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp new file mode 100644 index 000000000..53e4dca5b --- /dev/null +++ b/src/detect/ScanI2CTwoWire.cpp @@ -0,0 +1,297 @@ +#include "ScanI2CTwoWire.h" + +#include "concurrency/LockGuard.h" +#include "configuration.h" + +#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) +#include "main.h" // atecc +#endif + +// AXP192 and AXP2101 have the same device address, we just need to identify it in Power.cpp +#ifndef XPOWERS_AXP192_AXP2101_ADDRESS +#define XPOWERS_AXP192_AXP2101_ADDRESS 0x34 +#endif + +ScanI2C::FoundDevice ScanI2CTwoWire::find(ScanI2C::DeviceType type) const +{ + concurrency::LockGuard guard((concurrency::Lock *)&lock); + + return exists(type) ? ScanI2C::FoundDevice(type, deviceAddresses.at(type)) : DEVICE_NONE; +} + +bool ScanI2CTwoWire::exists(ScanI2C::DeviceType type) const +{ + return deviceAddresses.find(type) != deviceAddresses.end(); +} + +ScanI2C::FoundDevice ScanI2CTwoWire::firstOfOrNONE(size_t count, DeviceType types[]) const +{ + concurrency::LockGuard guard((concurrency::Lock *)&lock); + + for (size_t k = 0; k < count; k++) { + ScanI2C::DeviceType current = types[k]; + + if (exists(current)) { + return ScanI2C::FoundDevice(current, deviceAddresses.at(current)); + } + } + + return DEVICE_NONE; +} + +ScanI2C::DeviceType ScanI2CTwoWire::probeOLED(ScanI2C::DeviceAddress addr) const +{ + TwoWire *i2cBus = fetchI2CBus(addr); + + uint8_t r = 0; + uint8_t r_prev = 0; + uint8_t c = 0; + ScanI2C::DeviceType o_probe = ScanI2C::DeviceType::SCREEN_UNKNOWN; + do { + r_prev = r; + i2cBus->beginTransmission(addr.address); + i2cBus->write((uint8_t)0x00); + i2cBus->endTransmission(); + i2cBus->requestFrom((int)addr.address, 1); + if (i2cBus->available()) { + r = i2cBus->read(); + } + r &= 0x0f; + + if (r == 0x08 || r == 0x00) { + LOG_INFO("sh1106 display found\n"); + o_probe = SCREEN_SH1106; // SH1106 + } else if (r == 0x03 || r == 0x04 || r == 0x06 || r == 0x07) { + LOG_INFO("ssd1306 display found\n"); + o_probe = SCREEN_SSD1306; // SSD1306 + } + c++; + } while ((r != r_prev) && (c < 4)); + LOG_DEBUG("0x%x subtype probed in %i tries \n", r, c); + + return o_probe; +} +void ScanI2CTwoWire::printATECCInfo() const +{ +#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) + atecc.readConfigZone(false); + + LOG_DEBUG("ATECC608B Serial Number: "); + for (int i = 0; i < 9; i++) { + LOG_DEBUG("%02x", atecc.serialNumber[i]); + } + + LOG_DEBUG(", Rev Number: "); + for (int i = 0; i < 4; i++) { + LOG_DEBUG("%02x", atecc.revisionNumber[i]); + } + LOG_DEBUG("\n"); + + LOG_DEBUG("ATECC608B Config %s", atecc.configLockStatus ? "Locked" : "Unlocked"); + LOG_DEBUG(", Data %s", atecc.dataOTPLockStatus ? "Locked" : "Unlocked"); + LOG_DEBUG(", Slot 0 %s\n", atecc.slot0LockStatus ? "Locked" : "Unlocked"); + + if (atecc.configLockStatus && atecc.dataOTPLockStatus && atecc.slot0LockStatus) { + if (atecc.generatePublicKey() == false) { + LOG_DEBUG("ATECC608B Error generating public key\n"); + } else { + LOG_DEBUG("ATECC608B Public Key: "); + for (int i = 0; i < 64; i++) { + LOG_DEBUG("%02x", atecc.publicKey64Bytes[i]); + } + LOG_DEBUG("\n"); + } + } +#endif +} + +uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation ®isterLocation, + ScanI2CTwoWire::ResponseWidth responseWidth) const +{ + uint16_t value = 0x00; + TwoWire *i2cBus = fetchI2CBus(registerLocation.i2cAddress); + + i2cBus->beginTransmission(registerLocation.i2cAddress.address); + i2cBus->write(registerLocation.registerAddress); + i2cBus->endTransmission(); + delay(20); + i2cBus->requestFrom(registerLocation.i2cAddress.address, responseWidth); + LOG_DEBUG("Wire.available() = %d\n", i2cBus->available()); + if (i2cBus->available() == 2) { + // Read MSB, then LSB + value = (uint16_t)i2cBus->read() << 8; + value |= i2cBus->read(); + } else if (i2cBus->available()) { + value = i2cBus->read(); + } + return value; +} + +#define SCAN_SIMPLE_CASE(ADDR, T, ...) \ + case ADDR: \ + LOG_INFO(__VA_ARGS__); \ + type = T; \ + break; + +void ScanI2CTwoWire::scanPort(I2CPort port) +{ + concurrency::LockGuard guard((concurrency::Lock *)&lock); + + LOG_DEBUG("Scanning for i2c devices on port %d\n", port); + + uint8_t err; + + DeviceAddress addr(port, 0x00); + + uint16_t registerValue = 0x00; + ScanI2C::DeviceType type; + TwoWire *i2cBus; +#ifdef RV3028_RTC + Melopero_RV3028 rtc; +#endif + +#ifdef I2C_SDA1 + if (port == I2CPort::WIRE1) { + i2cBus = &Wire1; + } else { +#endif + i2cBus = &Wire; +#ifdef I2C_SDA1 + } +#endif + + for (addr.address = 1; addr.address < 127; addr.address++) { + i2cBus->beginTransmission(addr.address); + err = i2cBus->endTransmission(); + type = NONE; + if (err == 0) { + LOG_DEBUG("I2C device found at address 0x%x\n", addr.address); + + switch (addr.address) { + case SSD1306_ADDRESS: + type = probeOLED(addr); + break; + +#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) + case ATECC608B_ADDR: + type = ATECC608B; + if (atecc.begin(addr.address) == true) { + LOG_INFO("ATECC608B initialized\n"); + } else { + LOG_WARN("ATECC608B initialization failed\n"); + } + printATECCInfo(); + break; +#endif + +#ifdef RV3028_RTC + case RV3028_RTC: + // foundDevices[addr] = RTC_RV3028; + type = RTC_RV3028; + LOG_INFO("RV3028 RTC found\n"); + rtc.initI2C(*i2cBus); + rtc.writeToRegister(0x35, 0x07); // no Clkout + rtc.writeToRegister(0x37, 0xB4); + break; +#endif + +#ifdef PCF8563_RTC + SCAN_SIMPLE_CASE(PCF8563_RTC, RTC_PCF8563, "PCF8563 RTC found\n") +#endif + + case CARDKB_ADDR: + // Do we have the RAK14006 instead? + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x04), 1); + if (registerValue == 0x02) { + // KEYPAD_VERSION + LOG_INFO("RAK14004 found\n"); + type = RAK14004; + } else { + LOG_INFO("m5 cardKB found\n"); + type = CARDKB; + } + break; + + SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found\n") + +#ifdef HAS_PMU + SCAN_SIMPLE_CASE(XPOWERS_AXP192_AXP2101_ADDRESS, PMU_AXP192_AXP2101, "axp192/axp2101 PMU found\n") +#endif + case BME_ADDR: + case BME_ADDR_ALTERNATE: + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xD0), 1); // GET_ID + switch (registerValue) { + case 0x61: + LOG_INFO("BME-680 sensor found at address 0x%x\n", (uint8_t)addr.address); + type = BME_680; + break; + case 0x60: + LOG_INFO("BME-280 sensor found at address 0x%x\n", (uint8_t)addr.address); + type = BME_280; + break; + default: + LOG_INFO("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr.address); + type = BMP_280; + } + break; + + case INA_ADDR: + case INA_ADDR_ALTERNATE: + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2); + LOG_DEBUG("Register MFG_UID: 0x%x\n", registerValue); + if (registerValue == 0x5449) { + LOG_INFO("INA260 sensor found at address 0x%x\n", (uint8_t)addr.address); + type = INA260; + } else { // Assume INA219 if INA260 ID is not found + LOG_INFO("INA219 sensor found at address 0x%x\n", (uint8_t)addr.address); + type = INA219; + } + break; + + SCAN_SIMPLE_CASE(MCP9808_ADDR, MCP9808, "MCP9808 sensor found\n") + + SCAN_SIMPLE_CASE(SHT31_ADDR, SHT31, "SHT31 sensor found\n") + SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTC3, "SHTC3 sensor found\n") + + case LPS22HB_ADDR_ALT: + SCAN_SIMPLE_CASE(LPS22HB_ADDR, LPS22HB, "LPS22HB sensor found\n") + + SCAN_SIMPLE_CASE(QMC6310_ADDR, QMC6310, "QMC6310 Highrate 3-Axis magnetic sensor found\n") + SCAN_SIMPLE_CASE(QMI8658_ADDR, QMI8658, "QMI8658 Highrate 6-Axis inertial measurement sensor found\n") + SCAN_SIMPLE_CASE(QMC5883L_ADDR, QMC5883L, "QMC5883L Highrate 3-Axis magnetic sensor found\n") + + SCAN_SIMPLE_CASE(PMSA0031_ADDR, PMSA0031, "PMSA0031 air quality sensor found\n") + + default: + LOG_INFO("Device found at address 0x%x was not able to be enumerated\n", addr.address); + } + + } else if (err == 4) { + LOG_ERROR("Unknown error at address 0x%x\n", addr); + } + + // Check if a type was found for the enumerated device - save, if so + if (type != NONE) { + deviceAddresses[type] = addr; + foundDevices[addr] = type; + } + } +} + +TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const +{ + if (address.port == ScanI2C::I2CPort::WIRE1) { + return &Wire; + } else { +#ifdef I2C_SDA1 + return &Wire1; +#else + return &Wire; +#endif + } +} + +size_t ScanI2CTwoWire::countDevices() const +{ + return foundDevices.size(); +} diff --git a/src/detect/ScanI2CTwoWire.h b/src/detect/ScanI2CTwoWire.h new file mode 100644 index 000000000..52c3cb085 --- /dev/null +++ b/src/detect/ScanI2CTwoWire.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include +#include +#include + +#include + +#include "ScanI2C.h" + +#include "../concurrency/Lock.h" + +class ScanI2CTwoWire : public ScanI2C +{ + public: + void scanPort(ScanI2C::I2CPort) override; + + ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override; + + bool exists(ScanI2C::DeviceType) const override; + + size_t countDevices() const override; + + protected: + FoundDevice firstOfOrNONE(size_t, DeviceType[]) const override; + + private: + typedef struct RegisterLocation { + DeviceAddress i2cAddress; + RegisterAddress registerAddress; + + RegisterLocation(DeviceAddress deviceAddress, RegisterAddress registerAddress) + : i2cAddress(deviceAddress), registerAddress(registerAddress) + { + } + + } RegisterLocation; + + typedef uint8_t ResponseWidth; + + std::map foundDevices; + + // note: prone to overwriting if multiple devices of a type are added at different addresses (rare?) + std::map deviceAddresses; + + concurrency::Lock lock; + + void printATECCInfo() const; + + uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth) const; + + DeviceType probeOLED(ScanI2C::DeviceAddress) const; + + TwoWire *fetchI2CBus(ScanI2C::DeviceAddress) const; +}; diff --git a/src/detect/i2cScan.h b/src/detect/i2cScan.h deleted file mode 100644 index a2d7b7baf..000000000 --- a/src/detect/i2cScan.h +++ /dev/null @@ -1,237 +0,0 @@ -#include "../configuration.h" -#include "../main.h" -#include "mesh/generated/meshtastic/telemetry.pb.h" -#include - -// AXP192 and AXP2101 have the same device address, we just need to identify it in Power.cpp -#ifndef XPOWERS_AXP192_AXP2101_ADDRESS -#define XPOWERS_AXP192_AXP2101_ADDRESS 0x34 -#endif - -#if HAS_WIRE - -void printATECCInfo() -{ -#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) - atecc.readConfigZone(false); - - LOG_DEBUG("ATECC608B Serial Number: "); - for (int i = 0; i < 9; i++) { - LOG_DEBUG("%02x", atecc.serialNumber[i]); - } - - LOG_DEBUG(", Rev Number: "); - for (int i = 0; i < 4; i++) { - LOG_DEBUG("%02x", atecc.revisionNumber[i]); - } - LOG_DEBUG("\n"); - - LOG_DEBUG("ATECC608B Config %s", atecc.configLockStatus ? "Locked" : "Unlocked"); - LOG_DEBUG(", Data %s", atecc.dataOTPLockStatus ? "Locked" : "Unlocked"); - LOG_DEBUG(", Slot 0 %s\n", atecc.slot0LockStatus ? "Locked" : "Unlocked"); - - if (atecc.configLockStatus && atecc.dataOTPLockStatus && atecc.slot0LockStatus) { - if (atecc.generatePublicKey() == false) { - LOG_DEBUG("ATECC608B Error generating public key\n"); - } else { - LOG_DEBUG("ATECC608B Public Key: "); - for (int i = 0; i < 64; i++) { - LOG_DEBUG("%02x", atecc.publicKey64Bytes[i]); - } - LOG_DEBUG("\n"); - } - } -#endif -} - -uint16_t getRegisterValue(uint8_t address, uint8_t reg, uint8_t length) -{ - uint16_t value = 0x00; - Wire.beginTransmission(address); - Wire.write(reg); - Wire.endTransmission(); - delay(20); - Wire.requestFrom(address, length); - LOG_DEBUG("Wire.available() = %d\n", Wire.available()); - if (Wire.available() == 2) { - // Read MSB, then LSB - value = (uint16_t)Wire.read() << 8; - value |= Wire.read(); - } else if (Wire.available()) { - value = Wire.read(); - } - return value; -} - -uint8_t oled_probe(byte addr) -{ - uint8_t r = 0; - uint8_t r_prev = 0; - uint8_t c = 0; - uint8_t o_probe = 0; - do { - r_prev = r; - Wire.beginTransmission(addr); - Wire.write(0x00); - Wire.endTransmission(); - Wire.requestFrom((int)addr, 1); - if (Wire.available()) { - r = Wire.read(); - } - r &= 0x0f; - - if (r == 0x08 || r == 0x00) { - o_probe = 2; // SH1106 - } else if (r == 0x03 || r == 0x04 || r == 0x06 || r == 0x07) { - o_probe = 1; // SSD1306 - } - c++; - } while ((r != r_prev) && (c < 4)); - LOG_DEBUG("0x%x subtype probed in %i tries \n", r, c); - return o_probe; -} - -void scanI2Cdevice() -{ - byte err, addr; - uint16_t registerValue = 0x00; - int nDevices = 0; - for (addr = 1; addr < 127; addr++) { - Wire.beginTransmission(addr); - err = Wire.endTransmission(); - if (err == 0) { - LOG_DEBUG("I2C device found at address 0x%x\n", addr); - - nDevices++; - - if (addr == SSD1306_ADDRESS) { - screen_found = addr; - screen_model = oled_probe(addr); - if (screen_model == 1) { - LOG_INFO("ssd1306 display found\n"); - } else if (screen_model == 2) { - LOG_INFO("sh1106 display found\n"); - } else { - LOG_INFO("unknown display found\n"); - } - } -#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) - if (addr == ATECC608B_ADDR) { - keystore_found = addr; - if (atecc.begin(keystore_found) == true) { - LOG_INFO("ATECC608B initialized\n"); - } else { - LOG_WARN("ATECC608B initialization failed\n"); - } - printATECCInfo(); - } -#endif -#ifdef RV3028_RTC - if (addr == RV3028_RTC) { - rtc_found = addr; - LOG_INFO("RV3028 RTC found\n"); - Melopero_RV3028 rtc; - rtc.initI2C(); - rtc.writeToRegister(0x35, 0x07); // no Clkout - rtc.writeToRegister(0x37, 0xB4); - } -#endif -#ifdef PCF8563_RTC - if (addr == PCF8563_RTC) { - rtc_found = addr; - LOG_INFO("PCF8563 RTC found\n"); - } -#endif - if (addr == CARDKB_ADDR) { - cardkb_found = addr; - // Do we have the RAK14006 instead? - registerValue = getRegisterValue(addr, 0x04, 1); - if (registerValue == 0x02) { // KEYPAD_VERSION - LOG_INFO("RAK14004 found\n"); - kb_model = 0x02; - } else { - LOG_INFO("m5 cardKB found\n"); - kb_model = 0x00; - } - } - if (addr == ST7567_ADDRESS) { - screen_found = addr; - LOG_INFO("st7567 display found\n"); - } -#ifdef HAS_PMU - if (addr == XPOWERS_AXP192_AXP2101_ADDRESS) { - pmu_found = true; - LOG_INFO("axp192/axp2101 PMU found\n"); - } -#endif - if (addr == BME_ADDR || addr == BME_ADDR_ALTERNATE) { - registerValue = getRegisterValue(addr, 0xD0, 1); // GET_ID - if (registerValue == 0x61) { - LOG_INFO("BME-680 sensor found at address 0x%x\n", (uint8_t)addr); - nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_BME680] = addr; - } else if (registerValue == 0x60) { - LOG_INFO("BME-280 sensor found at address 0x%x\n", (uint8_t)addr); - nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_BME280] = addr; - } else { - LOG_INFO("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr); - nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_BMP280] = addr; - } - } - if (addr == INA_ADDR || addr == INA_ADDR_ALTERNATE) { - registerValue = getRegisterValue(addr, 0xFE, 2); - LOG_DEBUG("Register MFG_UID: 0x%x\n", registerValue); - if (registerValue == 0x5449) { - LOG_INFO("INA260 sensor found at address 0x%x\n", (uint8_t)addr); - nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260] = addr; - } else { // Assume INA219 if INA260 ID is not found - LOG_INFO("INA219 sensor found at address 0x%x\n", (uint8_t)addr); - nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219] = addr; - } - } - if (addr == MCP9808_ADDR) { - nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MCP9808] = addr; - LOG_INFO("MCP9808 sensor found\n"); - } - if (addr == SHT31_ADDR) { - LOG_INFO("SHT31 sensor found\n"); - nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_SHT31] = addr; - } - if (addr == SHTC3_ADDR) { - LOG_INFO("SHTC3 sensor found\n"); - nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_SHTC3] = addr; - } - if (addr == LPS22HB_ADDR || addr == LPS22HB_ADDR_ALT) { - LOG_INFO("LPS22HB sensor found\n"); - nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_LPS22] = addr; - } - - // High rate sensors, will be processed internally - if (addr == QMC6310_ADDR) { - LOG_INFO("QMC6310 Highrate 3-Axis magnetic sensor found\n"); - nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_QMC6310] = addr; - } - if (addr == QMI8658_ADDR) { - LOG_INFO("QMI8658 Highrate 6-Axis inertial measurement sensor found\n"); - nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_QMI8658] = addr; - } - if (addr == QMC5883L_ADDR) { - LOG_INFO("QMC5883L Highrate 3-Axis magnetic sensor found\n"); - nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_QMC5883L] = addr; - } - if (addr == PMSA0031_ADDR) { - LOG_INFO("PMSA0031 air quality sensor found\n"); - nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I] = addr; - } - } else if (err == 4) { - LOG_ERROR("Unknow error at address 0x%x\n", addr); - } - } - - if (nDevices == 0) - LOG_INFO("No I2C devices found\n"); - else - LOG_INFO("%i I2C devices found\n", nDevices); -} -#else -void scanI2Cdevice() {} -#endif diff --git a/src/gps/RTC.cpp b/src/gps/RTC.cpp index 2e25949af..118c2128c 100644 --- a/src/gps/RTC.cpp +++ b/src/gps/RTC.cpp @@ -1,5 +1,6 @@ #include "RTC.h" #include "configuration.h" +#include "detect/ScanI2C.h" #include "main.h" #include #include @@ -20,10 +21,14 @@ void readFromRTC() { struct timeval tv; /* btw settimeofday() is helpfull here too*/ #ifdef RV3028_RTC - if (rtc_found == RV3028_RTC) { + if (rtc_found.address == RV3028_RTC) { uint32_t now = millis(); Melopero_RV3028 rtc; +#ifdef I2C_SDA1 + rtc.initI2C(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire); +#else rtc.initI2C(); +#endif tm t; t.tm_year = rtc.getYear() - 1900; t.tm_mon = rtc.getMonth() - 1; @@ -41,14 +46,16 @@ void readFromRTC() } } #elif defined(PCF8563_RTC) - if (rtc_found == PCF8563_RTC) { + if (rtc_found.address == PCF8563_RTC) { uint32_t now = millis(); PCF8563_Class rtc; -#ifdef RTC_USE_WIRE1 - rtc.begin(Wire1); + +#ifdef I2C_SDA1 + rtc.begin(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire); #else rtc.begin(); #endif + auto tc = rtc.getDateTime(); tm t; t.tm_year = tc.year - 1900; @@ -103,19 +110,24 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv) // If this platform has a setable RTC, set it #ifdef RV3028_RTC - if (rtc_found == RV3028_RTC) { + if (rtc_found.address == RV3028_RTC) { Melopero_RV3028 rtc; +#ifdef I2C_SDA1 + rtc.initI2C(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire); +#else rtc.initI2C(); +#endif tm *t = localtime(&tv->tv_sec); rtc.setTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_wday, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); LOG_DEBUG("RV3028_RTC setTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec); } #elif defined(PCF8563_RTC) - if (rtc_found == PCF8563_RTC) { + if (rtc_found.address == PCF8563_RTC) { PCF8563_Class rtc; -#ifdef RTC_USE_WIRE1 - rtc.begin(Wire1); + +#ifdef I2C_SDA1 + rtc.begin(rtc_found.port == ScanI2C::I2CPort::WIRE1 ? Wire1 : Wire); #else rtc.begin(); #endif diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp index f9d99ab7e..a705b90b8 100644 --- a/src/graphics/EInkDisplay2.cpp +++ b/src/graphics/EInkDisplay2.cpp @@ -41,7 +41,7 @@ GxEPD2_BW *adafruitDisplay; -EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, uint8_t screen_model) +EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus) { #if defined(TTGO_T_ECHO) setGeometry(GEOMETRY_RAWMODE, TECHO_DISPLAY_MODEL::WIDTH, TECHO_DISPLAY_MODEL::HEIGHT); diff --git a/src/graphics/EInkDisplay2.h b/src/graphics/EInkDisplay2.h index 7d56c8022..c7ae6754b 100644 --- a/src/graphics/EInkDisplay2.h +++ b/src/graphics/EInkDisplay2.h @@ -22,7 +22,7 @@ class EInkDisplay : public OLEDDisplay /* constructor FIXME - the parameters are not used, just a temporary hack to keep working like the old displays */ - EInkDisplay(uint8_t address, int sda, int scl, uint8_t screen_model); + EInkDisplay(uint8_t, int, int, OLEDDISPLAY_GEOMETRY, HW_I2C); // Write the buffer to the display memory (for eink we only do this occasionally) virtual void display(void) override; diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 12d08cd17..0512b405b 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -19,6 +19,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include "Screen.h" #include "configuration.h" #if HAS_SCREEN #include @@ -26,7 +27,6 @@ along with this program. If not, see . #include "GPS.h" #include "MeshService.h" #include "NodeDB.h" -#include "Screen.h" #include "gps/GeoCoord.h" #include "gps/RTC.h" #include "graphics/images.h" @@ -886,13 +886,11 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ // } // } // #else -Screen::Screen(uint8_t address, int sda, int scl) - : OSThread("Screen"), cmdQueue(32), - dispdev(address, sda, scl, - screen_model == meshtastic_Config_DisplayConfig_OledType_OLED_SH1107 ? GEOMETRY_128_128 : GEOMETRY_128_64), +Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_OledType screenType, OLEDDISPLAY_GEOMETRY geometry) + : concurrency::OSThread("Screen"), address_found(address), model(screenType), geometry(geometry), cmdQueue(32), + dispdev(address.address, -1, -1, geometry, (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE), ui(&dispdev) { - address_found = address; cmdQueue.setReader(this); } // #endif @@ -940,9 +938,11 @@ void Screen::setup() useDisplay = true; #ifdef AutoOLEDWire_h - if (screen_model == meshtastic_Config_DisplayConfig_OledType_OLED_SH1107) - screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1106; - dispdev.setDetected(screen_model); + dispdev.setDetected(model); +#endif + +#ifdef USE_SH1107_128_64 + dispdev.setSubtype(7); #endif // Initialising the UI will init the display too. @@ -1177,7 +1177,7 @@ void Screen::drawDebugInfoWiFiTrampoline(OLEDDisplay *display, OLEDDisplayUiStat * it is expected that this will be used during the boot phase */ void Screen::setSSLFrames() { - if (address_found) { + if (address_found.address) { // LOG_DEBUG("showing SSL frames\n"); static FrameCallback sslFrames[] = {drawSSLScreen}; ui.setFrames(sslFrames, 1); @@ -1189,7 +1189,7 @@ void Screen::setSSLFrames() * it is expected that this will be used during the boot phase */ void Screen::setWelcomeFrames() { - if (address_found) { + if (address_found.address) { // LOG_DEBUG("showing Welcome frames\n"); ui.disableAllIndicators(); @@ -1821,5 +1821,6 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event) } } // namespace graphics - +#else +graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {} #endif // HAS_SCREEN diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 51f3a2fe6..992a73285 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -2,6 +2,10 @@ #include "configuration.h" +#include "detect/ScanI2C.h" +#include "mesh/generated/meshtastic/config.pb.h" +#include + #if !HAS_SCREEN #include "power.h" namespace graphics @@ -10,7 +14,7 @@ namespace graphics class Screen { public: - explicit Screen(char) {} + explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY); void onPress() {} void setup() {} void setOn(bool) {} @@ -21,10 +25,10 @@ class Screen void startBluetoothPinScreen(uint32_t pin) {} void stopBluetoothPinScreen() {} void startRebootScreen() {} + void startShutdownScreen() {} void startFirmwareUpdateScreen() {} }; } // namespace graphics - #else #include @@ -34,7 +38,7 @@ class Screen #ifdef USE_ST7567 #include -#elif defined(USE_SH1106) || defined(USE_SH1107) +#elif defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64) #include #elif defined(USE_SSD1306) #include @@ -116,12 +120,14 @@ class Screen : public concurrency::OSThread CallbackObserver(this, &Screen::handleUIFrameEvent); public: - explicit Screen(uint8_t address, int sda = -1, int scl = -1); + explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY); Screen(const Screen &) = delete; Screen &operator=(const Screen &) = delete; - uint8_t address_found; + ScanI2C::DeviceAddress address_found; + meshtastic_Config_DisplayConfig_OledType model; + OLEDDISPLAY_GEOMETRY geometry; /// Initializes the UI, turns on the display, starts showing boot screen. // @@ -370,7 +376,7 @@ class Screen : public concurrency::OSThread /// Display device -#if defined(USE_SH1106) || defined(USE_SH1107) +#if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64) SH1106Wire dispdev; #elif defined(USE_SSD1306) SSD1306Wire dispdev; diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp index 0bd1d3a99..8c07a4204 100644 --- a/src/graphics/TFTDisplay.cpp +++ b/src/graphics/TFTDisplay.cpp @@ -8,7 +8,7 @@ static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h -TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, uint8_t screen_model) +TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus) { #ifdef SCREEN_ROTATE setGeometry(GEOMETRY_RAWMODE, TFT_HEIGHT, TFT_WIDTH); diff --git a/src/graphics/TFTDisplay.h b/src/graphics/TFTDisplay.h index c18dc03c6..013f4961e 100644 --- a/src/graphics/TFTDisplay.h +++ b/src/graphics/TFTDisplay.h @@ -18,7 +18,7 @@ class TFTDisplay : public OLEDDisplay /* constructor FIXME - the parameters are not used, just a temporary hack to keep working like the old displays */ - TFTDisplay(uint8_t address, int sda, int scl, uint8_t screen_model); + TFTDisplay(uint8_t, int, int, OLEDDISPLAY_GEOMETRY, HW_I2C); // Write the buffer to the display memory virtual void display(void) override; diff --git a/src/input/RotaryEncoderInterruptBase.h b/src/input/RotaryEncoderInterruptBase.h index 06f7a2354..9bcf25a69 100644 --- a/src/input/RotaryEncoderInterruptBase.h +++ b/src/input/RotaryEncoderInterruptBase.h @@ -1,7 +1,8 @@ #pragma once #include "InputBroker.h" -#include "SinglePortModule.h" // TODO: what header file to include? +#include "concurrency/OSThread.h" +#include "mesh/NodeDB.h" enum RotaryEncoderInterruptBaseStateType { ROTARY_EVENT_OCCURRED, ROTARY_EVENT_CLEARED }; diff --git a/src/input/UpDownInterruptBase.h b/src/input/UpDownInterruptBase.h index ed7eee332..afa64d28d 100644 --- a/src/input/UpDownInterruptBase.h +++ b/src/input/UpDownInterruptBase.h @@ -1,7 +1,7 @@ #pragma once #include "InputBroker.h" -#include "SinglePortModule.h" // TODO: what header file to include? +#include "mesh/NodeDB.h" class UpDownInterruptBase : public Observable { diff --git a/src/input/cardKbI2cImpl.cpp b/src/input/cardKbI2cImpl.cpp index e1639270a..686f4b5a2 100644 --- a/src/input/cardKbI2cImpl.cpp +++ b/src/input/cardKbI2cImpl.cpp @@ -7,7 +7,7 @@ CardKbI2cImpl::CardKbI2cImpl() : KbI2cBase("cardKB") {} void CardKbI2cImpl::init() { - if (cardkb_found != CARDKB_ADDR) { + if (cardkb_found.address != CARDKB_ADDR) { disable(); return; } diff --git a/src/input/kbI2cBase.cpp b/src/input/kbI2cBase.cpp index 9212b6d4c..6850eff51 100644 --- a/src/input/kbI2cBase.cpp +++ b/src/input/kbI2cBase.cpp @@ -1,8 +1,9 @@ #include "kbI2cBase.h" -#include "configuration.h" -#include -extern uint8_t cardkb_found; +#include "configuration.h" +#include "detect/ScanI2C.h" + +extern ScanI2C::DeviceAddress cardkb_found; extern uint8_t kb_model; KbI2cBase::KbI2cBase(const char *name) : concurrency::OSThread(name) @@ -10,43 +11,64 @@ KbI2cBase::KbI2cBase(const char *name) : concurrency::OSThread(name) this->_originName = name; } -uint8_t read_from_14004(uint8_t reg, uint8_t *data, uint8_t length) +uint8_t read_from_14004(TwoWire *i2cBus, uint8_t reg, uint8_t *data, uint8_t length) { uint8_t readflag = 0; - Wire.beginTransmission(CARDKB_ADDR); - Wire.write(reg); - Wire.endTransmission(); // stop transmitting + i2cBus->beginTransmission(CARDKB_ADDR); + i2cBus->write(reg); + i2cBus->endTransmission(); // stop transmitting delay(20); - Wire.requestFrom(CARDKB_ADDR, (int)length); + i2cBus->requestFrom(CARDKB_ADDR, (int)length); int i = 0; - while (Wire.available()) // slave may send less than requested + while (i2cBus->available()) // slave may send less than requested { - data[i++] = Wire.read(); // receive a byte as a proper uint8_t + data[i++] = i2cBus->read(); // receive a byte as a proper uint8_t readflag = 1; } return readflag; } -void write_to_14004(uint8_t reg, uint8_t data) +// Unused for now - flagging it off +#if 0 +void write_to_14004(const TwoWire * i2cBus, uint8_t reg, uint8_t data) { - Wire.beginTransmission(CARDKB_ADDR); - Wire.write(reg); - Wire.write(data); - Wire.endTransmission(); // stop transmitting + i2cBus->beginTransmission(CARDKB_ADDR); + i2cBus->write(reg); + i2cBus->write(data); + i2cBus->endTransmission(); // stop transmitting } +#endif int32_t KbI2cBase::runOnce() { - if (cardkb_found != CARDKB_ADDR) { + if (cardkb_found.address != CARDKB_ADDR) { // Input device is not detected. return INT32_MAX; } + if (!i2cBus) { + switch (cardkb_found.port) { + case ScanI2C::WIRE1: +#ifdef I2C_SDA1 + LOG_DEBUG("Using I2C Bus 1 (the second one)\n"); + i2cBus = &Wire1; + break; +#endif + case ScanI2C::WIRE: + LOG_DEBUG("Using I2C Bus 0 (the first one)\n"); + i2cBus = &Wire; + break; + case ScanI2C::NO_I2C: + default: + i2cBus = 0; + } + } + if (kb_model == 0x02) { // RAK14004 uint8_t rDataBuf[8] = {0}; uint8_t PrintDataBuf = 0; - if (read_from_14004(0x01, rDataBuf, 0x04) == 1) { + if (read_from_14004(i2cBus, 0x01, rDataBuf, 0x04) == 1) { for (uint8_t aCount = 0; aCount < 0x04; aCount++) { for (uint8_t bCount = 0; bCount < 0x04; bCount++) { if (((rDataBuf[aCount] >> bCount) & 0x01) == 0x01) { @@ -65,10 +87,10 @@ int32_t KbI2cBase::runOnce() } } else { // m5 cardkb - Wire.requestFrom(CARDKB_ADDR, 1); + i2cBus->requestFrom(CARDKB_ADDR, 1); - while (Wire.available()) { - char c = Wire.read(); + while (i2cBus->available()) { + char c = i2cBus->read(); InputEvent e; e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE; e.source = this->_originName; diff --git a/src/input/kbI2cBase.h b/src/input/kbI2cBase.h index c661f95c5..a0a4dd608 100644 --- a/src/input/kbI2cBase.h +++ b/src/input/kbI2cBase.h @@ -1,7 +1,8 @@ #pragma once #include "InputBroker.h" -#include "SinglePortModule.h" // TODO: what header file to include? +#include "Wire.h" +#include "concurrency/OSThread.h" class KbI2cBase : public Observable, public concurrency::OSThread { @@ -13,4 +14,6 @@ class KbI2cBase : public Observable, public concurrency::OST private: const char *_originName; + + TwoWire *i2cBus = 0; }; diff --git a/src/main.cpp b/src/main.cpp index c1afb5c18..aca540323 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,16 +15,19 @@ #include "SPILock.h" #include "concurrency/OSThread.h" #include "concurrency/Periodic.h" +#include "detect/ScanI2C.h" +#include "detect/ScanI2CTwoWire.h" #include "detect/axpDebug.h" #include "detect/einkScan.h" -#include "detect/i2cScan.h" #include "graphics/Screen.h" #include "main.h" +#include "mesh/generated/meshtastic/config.pb.h" #include "modules/Modules.h" #include "shutdown.h" #include "sleep.h" #include "target_specific.h" #include +#include // #include #include "mesh/eth/ethClient.h" @@ -79,20 +82,19 @@ meshtastic::GPSStatus *gpsStatus = new meshtastic::GPSStatus(); // Global Node status meshtastic::NodeStatus *nodeStatus = new meshtastic::NodeStatus(); +// Scan for I2C Devices + /// The I2C address of our display (if found) -uint8_t screen_found; -uint8_t screen_model; +ScanI2C::DeviceAddress screen_found = ScanI2C::ADDRESS_NONE; // The I2C address of the cardkb or RAK14004 (if found) -uint8_t cardkb_found; +ScanI2C::DeviceAddress cardkb_found = ScanI2C::ADDRESS_NONE; // 0x02 for RAK14004 and 0x00 for cardkb uint8_t kb_model; // The I2C address of the RTC Module (if found) -uint8_t rtc_found; +ScanI2C::DeviceAddress rtc_found = ScanI2C::ADDRESS_NONE; -// Keystore Chips -uint8_t keystore_found; #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) ATECCX08A atecc; #endif @@ -175,6 +177,9 @@ __attribute__((weak, noinline)) bool loopCanSleep() void setup() { concurrency::hasBeenSetup = true; + meshtastic_Config_DisplayConfig_OledType screen_model = + meshtastic_Config_DisplayConfig_OledType::meshtastic_Config_DisplayConfig_OledType_OLED_AUTO; + OLEDDISPLAY_GEOMETRY screen_geometry = GEOMETRY_128_64; #ifdef SEGGER_STDOUT_CH auto mode = false ? SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL : SEGGER_RTT_MODE_NO_BLOCK_TRIM; @@ -261,23 +266,118 @@ void setup() #endif // Currently only the tbeam has a PMU - // PMU initialization needs to be placed before scanI2Cdevice + // PMU initialization needs to be placed before i2c scanning power = new Power(); power->setStatusHandler(powerStatus); powerStatus->observe(&power->newStatus); power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration -#ifdef LILYGO_TBEAM_S3_CORE - // In T-Beam-S3-core, the I2C device cannot be scanned before power initialization, otherwise the device will be stuck - // PCF8563 RTC in tbeam-s3 uses Wire1 to share I2C bus - Wire1.beginTransmission(PCF8563_RTC); - if (Wire1.endTransmission() == 0) { - rtc_found = PCF8563_RTC; - LOG_INFO("PCF8563 RTC found\n"); + // We need to scan here to decide if we have a screen for nodeDB.init() and because power has been applied to + // accessories + auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); + + LOG_INFO("Scanning for i2c devices...\n"); + +#ifdef I2C_SDA1 + Wire1.begin(I2C_SDA1, I2C_SCL1); + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1); +#endif + +#ifdef I2C_SDA + Wire.begin(I2C_SDA, I2C_SCL); + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE); +#elif HAS_WIRE + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE); +#endif + + auto i2cCount = i2cScanner->countDevices(); + if (i2cCount == 0) { + LOG_INFO("No I2C devices found\n"); + } else { + LOG_INFO("%i I2C devices found\n", i2cCount); + } + +#ifdef ARCH_ESP32 + // Don't init display if we don't have one or we are waking headless due to a timer event + if (wakeCause == ESP_SLEEP_WAKEUP_TIMER) { + LOG_DEBUG("suppress screen wake because this is a headless timer wakeup"); + i2cScanner->setSuppressScreen(); } #endif - // We need to scan here to decide if we have a screen for nodeDB.init() - scanI2Cdevice(); + + auto screenInfo = i2cScanner->firstScreen(); + screen_found = screenInfo.type != ScanI2C::DeviceType::NONE ? screenInfo.address : ScanI2C::ADDRESS_NONE; + + if (screen_found.port != ScanI2C::I2CPort::NO_I2C) { + switch (screenInfo.type) { + case ScanI2C::DeviceType::SCREEN_SH1106: + screen_model = meshtastic_Config_DisplayConfig_OledType::meshtastic_Config_DisplayConfig_OledType_OLED_SH1106; + break; + case ScanI2C::DeviceType::SCREEN_SSD1306: + screen_model = meshtastic_Config_DisplayConfig_OledType::meshtastic_Config_DisplayConfig_OledType_OLED_SSD1306; + break; + case ScanI2C::DeviceType::SCREEN_ST7567: + case ScanI2C::DeviceType::SCREEN_UNKNOWN: + default: + screen_model = meshtastic_Config_DisplayConfig_OledType::meshtastic_Config_DisplayConfig_OledType_OLED_AUTO; + } + } + +#define UPDATE_FROM_SCANNER(FIND_FN) + + auto rtc_info = i2cScanner->firstRTC(); + rtc_found = rtc_info.type != ScanI2C::DeviceType::NONE ? rtc_info.address : rtc_found; + + auto kb_info = i2cScanner->firstKeyboard(); + + if (kb_info.type != ScanI2C::DeviceType::NONE) { + cardkb_found = kb_info.address; + switch (kb_info.type) { + case ScanI2C::DeviceType::RAK14004: + kb_model = 0x02; + break; + case ScanI2C::DeviceType::CARDKB: + default: + // use this as default since it's also just zero + kb_model = 0x00; + } + } + + pmu_found = i2cScanner->exists(ScanI2C::DeviceType::PMU_AXP192_AXP2101); + + /* + * There are a bunch of sensors that have no further logic than to be found and stuffed into the + * nodeTelemetrySensorsMap singleton. This wraps that logic in a temporary scope to declare the temporary field + * "found". + */ + +#define STRING(S) #S + +#define SCANNER_TO_SENSORS_MAP(SCANNER_T, PB_T) \ + { \ + auto found = i2cScanner->find(SCANNER_T); \ + if (found.type != ScanI2C::DeviceType::NONE) { \ + nodeTelemetrySensorsMap[PB_T] = found.address.address; \ + LOG_DEBUG("found i2c sensor %s\n", STRING(PB_T)); \ + } \ + } + + SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BME_680, meshtastic_TelemetrySensorType_BME680) + SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BME_280, meshtastic_TelemetrySensorType_BME280) + SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BMP_280, meshtastic_TelemetrySensorType_BMP280) + SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA260, meshtastic_TelemetrySensorType_INA260) + SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA219, meshtastic_TelemetrySensorType_INA219) + SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808) + SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808) + SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHT31, meshtastic_TelemetrySensorType_SHT31) + SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHTC3, meshtastic_TelemetrySensorType_SHTC3) + SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::LPS22HB, meshtastic_TelemetrySensorType_LPS22) + SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMC6310, meshtastic_TelemetrySensorType_QMC6310) + SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMI8658, meshtastic_TelemetrySensorType_QMI8658) + SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMC5883L, meshtastic_TelemetrySensorType_QMC5883L) + SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::PMSA0031, meshtastic_TelemetrySensorType_PMSA003I) + + i2cScanner.reset(); #ifdef HAS_SDCARD setupSDCard(); @@ -301,10 +401,6 @@ void setup() LOG_INFO("Meshtastic hwvendor=%d, swver=%s\n", HW_VENDOR, optstr(APP_VERSION)); #ifdef ARCH_ESP32 - // Don't init display if we don't have one or we are waking headless due to a timer event - if (wakeCause == ESP_SLEEP_WAKEUP_TIMER) - screen_found = 0; // forget we even have the hardware - esp32Setup(); #endif @@ -326,7 +422,12 @@ void setup() screen_model = config.display.oled; #if defined(USE_SH1107) - screen_model = Config_DisplayConfig_OledType_OLED_SH1107; // set dimension of 128x128 + screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1107; // set dimension of 128x128 + display_geometry = GEOMETRY_128_128; +#endif + +#if defined(USE_SH1107_128_64) + screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1107; // keep dimension of 128x64 #endif // Init our SPI controller (must be before screen and lora) @@ -340,7 +441,7 @@ void setup() #endif // Initialize the screen first so we can show the logo while we start up everything else. - screen = new graphics::Screen(screen_found); + screen = new graphics::Screen(screen_found, screen_model, screen_geometry); readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time) @@ -369,7 +470,7 @@ void setup() #if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) screen->setup(); #else - if (screen_found) + if (screen_found.port != ScanI2C::I2CPort::NO_I2C) screen->setup(); #endif diff --git a/src/main.h b/src/main.h index 62c022b2b..29fe34f7f 100644 --- a/src/main.h +++ b/src/main.h @@ -3,7 +3,9 @@ #include "GPSStatus.h" #include "NodeStatus.h" #include "PowerStatus.h" +#include "detect/ScanI2C.h" #include "graphics/Screen.h" +#include "mesh/generated/meshtastic/config.pb.h" #include "mesh/generated/meshtastic/telemetry.pb.h" #include #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) @@ -18,12 +20,10 @@ extern NimbleBluetooth *nimbleBluetooth; extern NRF52Bluetooth *nrf52Bluetooth; #endif -extern uint8_t screen_found; -extern uint8_t screen_model; -extern uint8_t cardkb_found; +extern ScanI2C::DeviceAddress screen_found; +extern ScanI2C::DeviceAddress cardkb_found; extern uint8_t kb_model; -extern uint8_t rtc_found; -extern uint8_t keystore_found; +extern ScanI2C::DeviceAddress rtc_found; extern bool eink_found; extern bool pmu_found; diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 650f6882b..ee4ddcd77 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -82,7 +82,7 @@ int MeshService::handleFromRadio(const meshtastic_MeshPacket *mp) } printPacket("Forwarding to phone", mp); - sendToPhone((meshtastic_MeshPacket *)mp); + sendToPhone(packetPool.allocCopy(*mp)); return 0; } @@ -231,7 +231,7 @@ void MeshService::sendToMesh(meshtastic_MeshPacket *p, RxSource src, bool ccToPh } if (ccToPhone) { - sendToPhone(p); + sendToPhone(packetPool.allocCopy(*p)); } } @@ -262,9 +262,8 @@ void MeshService::sendToPhone(meshtastic_MeshPacket *p) releaseToPool(d); } - meshtastic_MeshPacket *copied = packetPool.allocCopy(*p); - perhapsDecode(copied); - assert(toPhoneQueue.enqueue(copied, 0)); + perhapsDecode(p); + assert(toPhoneQueue.enqueue(p, 0)); fromNum++; } diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 0748f50aa..6e9ac4c10 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -1,5 +1,6 @@ #include "configuration.h" +#include "../detect/ScanI2C.h" #include "Channels.h" #include "CryptoEngine.h" #include "FSCommon.h" @@ -181,7 +182,7 @@ void NodeDB::installDefaultConfig() #if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) bool hasScreen = true; #else - bool hasScreen = screen_found; + bool hasScreen = screen_found.port != ScanI2C::I2CPort::NO_I2C; #endif config.bluetooth.mode = hasScreen ? meshtastic_Config_BluetoothConfig_PairingMode_RANDOM_PIN : meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN; diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 118aab5a6..9a8c2d502 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -281,7 +281,7 @@ void printPacket(const char *prefix, const meshtastic_MeshPacket *p) if (p->priority != 0) out += DEBUG_PORT.mt_sprintf(" priority=%d", p->priority); - out + ")\n"; + out += ")\n"; LOG_DEBUG("%s", out.c_str()); } @@ -471,6 +471,9 @@ void RadioInterface::applyModemConfig() saveChannelNum(channel_num); saveFreq(freq + loraConfig.frequency_offset); + preambleTimeMsec = getPacketTime((uint32_t)0); + maxPacketTimeMsec = getPacketTime(meshtastic_Constants_DATA_PAYLOAD_LEN + sizeof(PacketHeader)); + LOG_INFO("Radio freq=%.3f, config.lora.frequency_offset=%.3f\n", freq, loraConfig.frequency_offset); LOG_INFO("Set radio: region=%s, name=%s, config=%u, ch=%d, power=%d\n", myRegion->name, channelName, loraConfig.modem_preset, channel_num, power); diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index 68dbf3522..b5fb5fcd3 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -63,7 +63,9 @@ class RadioInterface - Tx/Rx turnaround time (maximum of SX126x and SX127x); - MAC processing time (measured on T-beam) */ uint32_t slotTimeMsec = 8.5 * pow(2, sf) / bw + 0.2 + 0.4 + 7; - uint16_t preambleLength = 16; // 8 is default, but we use longer to increase the amount of sleep time when receiving + uint16_t preambleLength = 16; // 8 is default, but we use longer to increase the amount of sleep time when receiving + uint32_t preambleTimeMsec = 165; // calculated on startup, this is the default for LongFast + uint32_t maxPacketTimeMsec = 3246; // calculated on startup, this is the default for LongFast const uint32_t PROCESSING_TIME_MSEC = 4500; // time to construct, process and construct a packet again (empirically determined) const uint8_t CWmin = 2; // minimum CWsize diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index 1036042eb..c4145a30c 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -180,6 +180,7 @@ template void SX126xInterface::setStandby() assert(err == RADIOLIB_ERR_NONE); isReceiving = false; // If we were receiving, not any more + activeReceiveStart = 0; disableInterrupt(); completeSending(); // If we were sending, not anymore } @@ -212,9 +213,11 @@ template void SX126xInterface::startReceive() setStandby(); - // int err = lora.startReceive(); - int err = lora.startReceiveDutyCycleAuto(); // We use a 32 bit preamble so this should save some power by letting radio sit in - // standby mostly. + // We use a 16 bit preamble so this should save some power by letting radio sit in standby mostly. + // Furthermore, we need the PREAMBLE_DETECTED and HEADER_VALID IRQ flag to detect whether we are actively receiving + int err = lora.startReceiveDutyCycleAuto(preambleLength, 8, + RADIOLIB_SX126X_IRQ_RX_DEFAULT | RADIOLIB_SX126X_IRQ_RADIOLIB_PREAMBLE_DETECTED | + RADIOLIB_SX126X_IRQ_HEADER_VALID); assert(err == RADIOLIB_ERR_NONE); isReceiving = true; @@ -224,7 +227,7 @@ template void SX126xInterface::startReceive() #endif } -/** Could we send right now (i.e. either not actively receving or transmitting)? */ +/** Is the channel currently active? */ template bool SX126xInterface::isChannelActive() { // check if we can detect a LoRa preamble on the current channel @@ -245,17 +248,29 @@ template bool SX126xInterface::isActivelyReceiving() { // The IRQ status will be cleared when we start our read operation. Check if we've started a header, but haven't yet // received and handled the interrupt for reading the packet/handling errors. - // FIXME: it would be better to check for preamble, but we currently have our ISR not set to fire for packets that - // never even get a valid header, so we don't want preamble to get set and stay set due to noise on the network. uint16_t irq = lora.getIrqStatus(); - bool hasPreamble = (irq & RADIOLIB_SX126X_IRQ_HEADER_VALID); + bool detected = (irq & (RADIOLIB_SX126X_IRQ_HEADER_VALID | RADIOLIB_SX126X_IRQ_RADIOLIB_PREAMBLE_DETECTED)); + // Handle false detections + if (detected) { + uint32_t now = millis(); + if (!activeReceiveStart) { + activeReceiveStart = now; + } else if ((now - activeReceiveStart > 2 * preambleTimeMsec) && !(irq & RADIOLIB_SX126X_IRQ_HEADER_VALID)) { + // The HEADER_VALID flag should be set by now if it was really a packet, so ignore PREAMBLE_DETECTED flag + activeReceiveStart = 0; + LOG_DEBUG("Ignore false preamble detection.\n"); + return false; + } else if (now - activeReceiveStart > maxPacketTimeMsec) { + // We should have gotten an RX_DONE IRQ by now if it was really a packet, so ignore HEADER_VALID flag + activeReceiveStart = 0; + LOG_DEBUG("Ignore false header detection.\n"); + return false; + } + } - // this is not correct - often always true - need to add an extra conditional - // size_t bytesPending = lora.getPacketLength(); - - // if (hasPreamble) LOG_DEBUG("rx hasPreamble\n"); - return hasPreamble; + // if (detected) LOG_DEBUG("rx detected\n"); + return detected; } template bool SX126xInterface::sleep() diff --git a/src/mesh/SX126xInterface.h b/src/mesh/SX126xInterface.h index a773fd71f..f7ed270d4 100644 --- a/src/mesh/SX126xInterface.h +++ b/src/mesh/SX126xInterface.h @@ -68,4 +68,5 @@ template class SX126xInterface : public RadioLibInterface virtual void setStandby() override; private: + uint32_t activeReceiveStart = 0; }; diff --git a/src/mesh/SX128xInterface.cpp b/src/mesh/SX128xInterface.cpp index 19001a0de..aff4c1253 100644 --- a/src/mesh/SX128xInterface.cpp +++ b/src/mesh/SX128xInterface.cpp @@ -157,6 +157,7 @@ template void SX128xInterface::setStandby() #endif isReceiving = false; // If we were receiving, not any more + activeReceiveStart = 0; disableInterrupt(); completeSending(); // If we were sending, not anymore } @@ -203,7 +204,10 @@ template void SX128xInterface::startReceive() digitalWrite(SX128X_TXEN, LOW); #endif - int err = lora.startReceive(); + // We use the PREAMBLE_DETECTED and HEADER_VALID IRQ flag to detect whether we are actively receiving + int err = lora.startReceive(RADIOLIB_SX128X_RX_TIMEOUT_INF, RADIOLIB_SX128X_IRQ_RX_DEFAULT | + RADIOLIB_SX128X_IRQ_RADIOLIB_PREAMBLE_DETECTED | + RADIOLIB_SX128X_IRQ_HEADER_VALID); assert(err == RADIOLIB_ERR_NONE); @@ -214,7 +218,7 @@ template void SX128xInterface::startReceive() #endif } -/** Could we send right now (i.e. either not actively receving or transmitting)? */ +/** Is the channel currently active? */ template bool SX128xInterface::isChannelActive() { // check if we can detect a LoRa preamble on the current channel @@ -234,8 +238,27 @@ template bool SX128xInterface::isChannelActive() template bool SX128xInterface::isActivelyReceiving() { uint16_t irq = lora.getIrqStatus(); - bool hasPreamble = (irq & RADIOLIB_SX128X_IRQ_HEADER_VALID); - return hasPreamble; + bool detected = (irq & (RADIOLIB_SX128X_IRQ_HEADER_VALID | RADIOLIB_SX128X_IRQ_RADIOLIB_PREAMBLE_DETECTED)); + + // Handle false detections + if (detected) { + uint32_t now = millis(); + if (!activeReceiveStart) { + activeReceiveStart = now; + } else if ((now - activeReceiveStart > 2 * preambleTimeMsec) && !(irq & RADIOLIB_SX128X_IRQ_HEADER_VALID)) { + // The HEADER_VALID flag should be set by now if it was really a packet, so ignore PREAMBLE_DETECTED flag + activeReceiveStart = 0; + LOG_DEBUG("Ignore false preamble detection.\n"); + return false; + } else if (now - activeReceiveStart > maxPacketTimeMsec) { + // We should have gotten an RX_DONE IRQ by now if it was really a packet, so ignore HEADER_VALID flag + activeReceiveStart = 0; + LOG_DEBUG("Ignore false header detection.\n"); + return false; + } + } + + return detected; } template bool SX128xInterface::sleep() diff --git a/src/mesh/SX128xInterface.h b/src/mesh/SX128xInterface.h index 235d39ee0..434d4b1d9 100644 --- a/src/mesh/SX128xInterface.h +++ b/src/mesh/SX128xInterface.h @@ -68,4 +68,5 @@ template class SX128xInterface : public RadioLibInterface virtual void setStandby() override; private: + uint32_t activeReceiveStart = 0; }; diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index a9c415992..2518f199e 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -135,7 +135,7 @@ typedef struct _meshtastic_AdminMessage { /* Tell the node to reboot into the OTA Firmware in this many seconds (or <0 to cancel reboot) Only Implemented for ESP32 Devices. This needs to be issued to send a new main firmware via bluetooth. */ int32_t reboot_ota_seconds; - /* This message is only supported for the simulator porduino build. + /* This message is only supported for the simulator Portduino build. If received the simulator will exit successfully. */ bool exit_simulator; /* Tell the node to reboot in this many seconds (or <0 to cancel reboot) */ diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index fcb129bef..0b2aff4d8 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -152,7 +152,7 @@ typedef enum _meshtastic_Config_LoRaConfig_RegionCode { meshtastic_Config_LoRaConfig_RegionCode_US = 1, /* European Union 433mhz */ meshtastic_Config_LoRaConfig_RegionCode_EU_433 = 2, - /* European Union 433mhz */ + /* European Union 868mhz */ meshtastic_Config_LoRaConfig_RegionCode_EU_868 = 3, /* China */ meshtastic_Config_LoRaConfig_RegionCode_CN = 4, @@ -202,11 +202,11 @@ typedef enum _meshtastic_Config_LoRaConfig_ModemPreset { } meshtastic_Config_LoRaConfig_ModemPreset; typedef enum _meshtastic_Config_BluetoothConfig_PairingMode { - /* Device generates a random pin that will be shown on the screen of the device for pairing */ + /* Device generates a random PIN that will be shown on the screen of the device for pairing */ meshtastic_Config_BluetoothConfig_PairingMode_RANDOM_PIN = 0, - /* Device requires a specified fixed pin for pairing */ + /* Device requires a specified fixed PIN for pairing */ meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN = 1, - /* Device requires no pin for pairing */ + /* Device requires no PIN for pairing */ meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN = 2 } meshtastic_Config_BluetoothConfig_PairingMode; @@ -364,7 +364,7 @@ typedef struct _meshtastic_Config_DisplayConfig { /* Lora Config */ typedef struct _meshtastic_Config_LoRaConfig { - /* When enabled, the `modem_preset` fields will be adheared to, else the `bandwidth`/`spread_factor`/`coding_rate` + /* When enabled, the `modem_preset` fields will be adhered to, else the `bandwidth`/`spread_factor`/`coding_rate` will be taked from their respective manually defined fields */ bool use_preset; /* Either modem_config or bandwidth/spreading/coding will be specified - NOT BOTH. @@ -395,12 +395,12 @@ typedef struct _meshtastic_Config_LoRaConfig { /* Disable TX from the LoRa radio. Useful for hot-swapping antennas and other tests. Defaults to false */ bool tx_enabled; - /* If zero then, use default max legal continuous power (ie. something that won't + /* If zero, then use default max legal continuous power (ie. something that won't burn out the radio hardware) In most cases you should use zero here. Units are in dBm. */ int8_t tx_power; - /* This is controlling the actual hardware frequency the radio is transmitting on. + /* This controls the actual hardware frequency the radio transmits on. Most users should never need to be exposed to this field/concept. A channel number between 1 and NUM_CHANNELS (whatever the max is in the current region). If ZERO then the rule is "use the old channel name hash based @@ -422,7 +422,7 @@ typedef struct _meshtastic_Config_LoRaConfig { float override_frequency; /* For testing it is useful sometimes to force a node to never listen to particular other nodes (simulating radio out of range). All nodenums listed - in ignore_incoming will have packets they send droped on receive (by router.cpp) */ + in ignore_incoming will have packets they send dropped on receive (by router.cpp) */ pb_size_t ignore_incoming_count; uint32_t ignore_incoming[3]; } meshtastic_Config_LoRaConfig; @@ -432,7 +432,7 @@ typedef struct _meshtastic_Config_BluetoothConfig { bool enabled; /* Determines the pairing strategy for the device */ meshtastic_Config_BluetoothConfig_PairingMode mode; - /* Specified pin for PairingMode.FixedPin */ + /* Specified PIN for PairingMode.FixedPin */ uint32_t fixed_pin; } meshtastic_Config_BluetoothConfig; diff --git a/src/mesh/generated/meshtastic/connection_status.pb.h b/src/mesh/generated/meshtastic/connection_status.pb.h index c824f8b82..19ed69455 100644 --- a/src/mesh/generated/meshtastic/connection_status.pb.h +++ b/src/mesh/generated/meshtastic/connection_status.pb.h @@ -27,9 +27,9 @@ typedef struct _meshtastic_WifiConnectionStatus { /* Connection status */ bool has_status; meshtastic_NetworkConnectionStatus status; - /* WiFi access point ssid */ + /* WiFi access point SSID */ char ssid[33]; - /* Rssi of wireless connection */ + /* RSSI of wireless connection */ int32_t rssi; } meshtastic_WifiConnectionStatus; @@ -42,9 +42,9 @@ typedef struct _meshtastic_EthernetConnectionStatus { /* Bluetooth connection status */ typedef struct _meshtastic_BluetoothConnectionStatus { - /* The pairing pin for bluetooth */ + /* The pairing PIN for bluetooth */ uint32_t pin; - /* Rssi of bluetooth connection */ + /* RSSI of bluetooth connection */ int32_t rssi; /* Whether the device has an active connection or not */ bool is_connected; @@ -52,7 +52,7 @@ typedef struct _meshtastic_BluetoothConnectionStatus { /* Serial connection status */ typedef struct _meshtastic_SerialConnectionStatus { - /* The serial baud rate */ + /* Serial baud rate */ uint32_t baud; /* Whether the device has an active connection or not */ bool is_connected; diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index db19ba0ac..043c1b8a0 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -54,7 +54,7 @@ typedef struct _meshtastic_DeviceState { /* Used only during development. Indicates developer is testing and changes should never be saved to flash. */ bool no_save; - /* Some GPSes seem to have bogus settings from the factory, so we always do one factory reset. */ + /* Some GPS receivers seem to have bogus settings from the factory, so we always do one factory reset. */ bool did_gps_reset; } meshtastic_DeviceState; @@ -72,13 +72,13 @@ typedef struct _meshtastic_ChannelFile { typedef PB_BYTES_ARRAY_T(2048) meshtastic_OEMStore_oem_icon_bits_t; typedef PB_BYTES_ARRAY_T(32) meshtastic_OEMStore_oem_aes_key_t; /* This can be used for customizing the firmware distribution. If populated, - show a secondary bootup screen with cuatom logo and text for 2.5 seconds. */ + show a secondary bootup screen with custom logo and text for 2.5 seconds. */ typedef struct _meshtastic_OEMStore { /* The Logo width in Px */ uint32_t oem_icon_width; /* The Logo height in Px */ uint32_t oem_icon_height; - /* The Logo in xbm bytechar format */ + /* The Logo in XBM bytechar format */ meshtastic_OEMStore_oem_icon_bits_t oem_icon_bits; /* Use this font for the OEM text. */ meshtastic_ScreenFonts oem_font; diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h index 0e04ccf6e..31646693e 100644 --- a/src/mesh/generated/meshtastic/telemetry.pb.h +++ b/src/mesh/generated/meshtastic/telemetry.pb.h @@ -45,7 +45,7 @@ typedef enum _meshtastic_TelemetrySensorType { /* Struct definitions */ /* Key native device metrics such as battery level */ typedef struct _meshtastic_DeviceMetrics { - /* 1-100 (0 means powered) */ + /* 0-100 (>100 means powered) */ uint32_t battery_level; /* Voltage measured */ float voltage; diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 4c50d7059..106aaeafc 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -20,7 +20,7 @@ #include "mqtt/MQTT.h" #endif -#define DEFAULT_REBOOT_SECONDS 5 +#define DEFAULT_REBOOT_SECONDS 7 AdminModule *adminModule; bool hasOpenEditTransaction; diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index 9e5b63c51..e831db028 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -5,12 +5,19 @@ #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" // neede for button bypass +#include "detect/ScanI2C.h" #include "mesh/generated/meshtastic/cannedmessages.pb.h" +#include "main.h" // for cardkb_found + #ifdef OLED_RU #include "graphics/fonts/OLEDDisplayFontsRU.h" #endif +#ifdef OLED_UA +#include "graphics/fonts/OLEDDisplayFontsUA.h" +#endif + #if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) // The screen is bigger so use bigger fonts #define FONT_SMALL ArialMT_Plain_16 @@ -20,8 +27,12 @@ #ifdef OLED_RU #define FONT_SMALL ArialMT_Plain_10_RU #else +#ifdef OLED_UA +#define FONT_SMALL ArialMT_Plain_10_UA +#else #define FONT_SMALL ArialMT_Plain_10 #endif +#endif #define FONT_MEDIUM ArialMT_Plain_16 #define FONT_LARGE ArialMT_Plain_24 #endif @@ -35,7 +46,7 @@ // Remove Canned message screen if no action is taken for some milliseconds #define INACTIVATE_AFTER_MS 20000 -extern uint8_t cardkb_found; +extern ScanI2C::DeviceAddress cardkb_found; static const char *cannedMessagesConfigFile = "/prefs/cannedConf.proto"; @@ -48,7 +59,7 @@ CannedMessageModule::CannedMessageModule() { if (moduleConfig.canned_message.enabled) { this->loadProtoForModule(); - if ((this->splitConfiguredMessages() <= 0) && (cardkb_found != CARDKB_ADDR)) { + if ((this->splitConfiguredMessages() <= 0) && (cardkb_found.address != CARDKB_ADDR)) { LOG_INFO("CannedMessageModule: No messages are configured. Module is disabled\n"); this->runState = CANNED_MESSAGE_RUN_STATE_DISABLED; disable(); diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index 43c25b6a7..69de4bf1b 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -10,6 +10,8 @@ #include #include +#define MAGIC_USB_BATTERY_LEVEL 111 + int32_t DeviceTelemetryModule::runOnce() { uint32_t now = millis(); @@ -48,7 +50,12 @@ bool DeviceTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) t.which_variant = meshtastic_Telemetry_device_metrics_tag; t.variant.device_metrics.air_util_tx = myNodeInfo.air_util_tx; - t.variant.device_metrics.battery_level = powerStatus->getBatteryChargePercent(); + if (powerStatus->getIsCharging()) { + t.variant.device_metrics.battery_level = MAGIC_USB_BATTERY_LEVEL; + } else { + t.variant.device_metrics.battery_level = powerStatus->getBatteryChargePercent(); + } + t.variant.device_metrics.channel_utilization = myNodeInfo.channel_utilization; t.variant.device_metrics.voltage = powerStatus->getBatteryVoltageMv() / 1000.0; diff --git a/src/modules/esp32/AudioModule.cpp b/src/modules/esp32/AudioModule.cpp index 072ee75e4..9db7fbbc2 100644 --- a/src/modules/esp32/AudioModule.cpp +++ b/src/modules/esp32/AudioModule.cpp @@ -12,6 +12,10 @@ #include "graphics/fonts/OLEDDisplayFontsRU.h" #endif +#ifdef OLED_UA +#include "graphics/fonts/OLEDDisplayFontsUA.h" +#endif + /* AudioModule A interface to send raw codec2 audio data over the mesh network. Based on the example code from the ESP32_codec2 project. @@ -53,8 +57,12 @@ AudioModule *audioModule; #ifdef OLED_RU #define FONT_SMALL ArialMT_Plain_10_RU #else +#ifdef OLED_UA +#define FONT_SMALL ArialMT_Plain_10_UA +#else #define FONT_SMALL ArialMT_Plain_10 #endif +#endif #define FONT_MEDIUM ArialMT_Plain_16 #define FONT_LARGE ArialMT_Plain_24 #endif diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h index 8b12e2f88..2b38868be 100644 --- a/src/mqtt/MQTT.h +++ b/src/mqtt/MQTT.h @@ -30,12 +30,14 @@ class MQTT : private concurrency::OSThread #if HAS_ETHERNET EthernetClient mqttClient; #endif +#if !defined(DEBUG_HEAP_MQTT) PubSubClient pubSub; - // instead we supress sleep from our runOnce() callback - // CallbackObserver preflightSleepObserver = CallbackObserver(this, &MQTT::preflightSleepCb); - public: +#else + public: + PubSubClient pubSub; +#endif MQTT(); /** diff --git a/src/platform/esp32/architecture.h b/src/platform/esp32/architecture.h index 45ee7e6d4..da2d9d905 100644 --- a/src/platform/esp32/architecture.h +++ b/src/platform/esp32/architecture.h @@ -36,6 +36,9 @@ #ifndef HAS_RTC #define HAS_RTC 1 #endif +#ifndef HAS_CPU_SHUTDOWN +#define HAS_CPU_SHUTDOWN 1 +#endif #if defined(HAS_AXP192) || defined(HAS_AXP2101) #define HAS_PMU diff --git a/src/platform/nrf52/architecture.h b/src/platform/nrf52/architecture.h index f21635560..037e884cb 100644 --- a/src/platform/nrf52/architecture.h +++ b/src/platform/nrf52/architecture.h @@ -29,7 +29,7 @@ #ifndef HAS_RADIO #define HAS_RADIO 1 #endif -#ifdef HAS_CPU_SHUTDOWN +#ifndef HAS_CPU_SHUTDOWN #define HAS_CPU_SHUTDOWN 1 #endif diff --git a/src/shutdown.h b/src/shutdown.h index 1b0a0509a..b08478a1e 100644 --- a/src/shutdown.h +++ b/src/shutdown.h @@ -18,31 +18,16 @@ void powerCommandsCheck() #endif } -#if defined(ARCH_NRF52) || defined(HAS_PMU) +#if defined(ARCH_ESP32) || defined(ARCH_NRF52) if (shutdownAtMsec) { screen->startShutdownScreen(); - playBeep(); -#ifdef PIN_LED1 - ledOff(PIN_LED1); -#endif -#ifdef PIN_LED2 - ledOff(PIN_LED2); -#endif -#ifdef PIN_LED3 - ledOff(PIN_LED3); -#endif } #endif if (shutdownAtMsec && millis() > shutdownAtMsec) { LOG_INFO("Shutting down from admin command\n"); -#ifdef HAS_PMU - if (pmu_found == true) { - playShutdownMelody(); - power->shutdown(); - } -#elif defined(ARCH_NRF52) playShutdownMelody(); +#if defined(ARCH_NRF52) || defined(ARCH_ESP32) power->shutdown(); #else LOG_WARN("FIXME implement shutdown for this platform"); diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini index d90eec63c..3e0ace39c 100644 --- a/variants/heltec_v3/platformio.ini +++ b/variants/heltec_v3/platformio.ini @@ -1,9 +1,6 @@ [env:heltec-v3] -platform = https://github.com/Baptou88/platform-espressif32.git extends = esp32s3_base board = heltec_wifi_lora_32_V3 # Temporary until espressif creates a release with this new target -platform_packages = - framework-arduinoespressif32@https://github.com/espressif/arduino-esp32.git build_flags = ${esp32s3_base.build_flags} -D HELTEC_V3 -I variants/heltec_v3 diff --git a/variants/heltec_wsl_v3/platformio.ini b/variants/heltec_wsl_v3/platformio.ini index ea2874e0b..5f89a7466 100644 --- a/variants/heltec_wsl_v3/platformio.ini +++ b/variants/heltec_wsl_v3/platformio.ini @@ -1,9 +1,6 @@ [env:heltec-wsl-v3] -platform = https://github.com/Baptou88/platform-espressif32.git extends = esp32s3_base board = heltec_wifi_lora_32_V3 # Temporary until espressif creates a release with this new target -platform_packages = - framework-arduinoespressif32@https://github.com/espressif/arduino-esp32.git build_flags = ${esp32s3_base.build_flags} -D HELTEC_WSL_V3 -I variants/heltec_wsl_v3 diff --git a/variants/nano-g1-explorer/variant.h b/variants/nano-g1-explorer/variant.h index df8a0aad9..ad8957a51 100644 --- a/variants/nano-g1-explorer/variant.h +++ b/variants/nano-g1-explorer/variant.h @@ -33,5 +33,4 @@ #define BATTERY_SENSE_SAMPLES 15 // Set the number of samples, It has an effect of increasing sensitivity. #define ADC_MULTIPLIER 2 -//#define USE_SH1107 // Finally we will use SH1107 128x64 resolution driver, because SH1106 will shift the screen by 2 lines. -#define USE_SH1106 \ No newline at end of file +#define USE_SH1107_128_64 diff --git a/variants/rak4631/variant.h b/variants/rak4631/variant.h index 68b2b1172..69a77a029 100644 --- a/variants/rak4631/variant.h +++ b/variants/rak4631/variant.h @@ -126,7 +126,6 @@ static const uint8_t SCK = PIN_SPI_SCK; * eink display pins */ -#define PIN_EINK_EN (32 + 2) // (0 + 2) Note: this is really just backlight power #define PIN_EINK_CS (0 + 26) #define PIN_EINK_BUSY (0 + 4) #define PIN_EINK_DC (0 + 17) diff --git a/variants/rak4631_epaper/variant.h b/variants/rak4631_epaper/variant.h index 3d597d3d1..a43229088 100644 --- a/variants/rak4631_epaper/variant.h +++ b/variants/rak4631_epaper/variant.h @@ -126,7 +126,6 @@ static const uint8_t SCK = PIN_SPI_SCK; * eink display pins */ -#define PIN_EINK_EN (32 + 2) // (0 + 2) Note: this is really just backlight power #define PIN_EINK_CS (0 + 26) #define PIN_EINK_BUSY (0 + 4) #define PIN_EINK_DC (0 + 17) diff --git a/variants/tlora_t3s3_v1/variant.h b/variants/tlora_t3s3_v1/variant.h index 68eb18e31..0f88af819 100644 --- a/variants/tlora_t3s3_v1/variant.h +++ b/variants/tlora_t3s3_v1/variant.h @@ -13,6 +13,9 @@ #define I2C_SDA 18 // I2C pins for this board #define I2C_SCL 17 +#define I2C_SDA1 43 +#define I2C_SCL1 44 + #define LED_PIN 37 // If defined we will blink this LED #define BUTTON_PIN 0 // If defined, this will be used for user button presses, @@ -28,26 +31,30 @@ #define RF95_MISO 3 #define RF95_MOSI 6 #define RF95_NSS 7 - #define LORA_RESET 8 -#define LORA_DIO0 9 -#define LORA_DIO1 9 -#define LORA_DIO2 33 // SX1262 BUSY -#define LORA_DIO3 34 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled +// per SX1276_Receive_Interrupt/utilities.h +#define LORA_DIO0 9 +#define LORA_DIO1 33 // TCXO_EN ? +#define LORA_DIO2 34 +#define LORA_RXEN 21 +#define LORA_TXEN 10 + +// per SX1262_Receive_Interrupt/utilities.h #ifdef USE_SX1262 -#define SX126X_CS RF95_NSS // FIXME - we really should define LORA_CS instead +#define SX126X_CS RF95_NSS #define SX126X_DIO1 33 #define SX126X_BUSY 34 #define SX126X_RESET LORA_RESET -//#define SX126X_RXEN 21 -//#define SX126X_TXEN 10 #define SX126X_E22 #endif +// per SX128x_Receive_Interrupt/utilities.h #ifdef USE_SX1280 #define SX128X_CS RF95_NSS -#define SX128X_DIO1 LORA_DIO1 +#define SX128X_DIO1 9 +#define SX128X_DIO2 33 +#define SX128X_DIO3 34 #define SX128X_BUSY 36 #define SX128X_RESET LORA_RESET #define SX128X_RXEN 21 diff --git a/version.properties b/version.properties index dca62c699..ebd839bbb 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 -minor = 0 -build = 24 +minor = 1 +build = 3