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