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 dec7336cb..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, OLEDDISPLAY_GEOMETRY screen_geometry) +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 adc139c8e..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, OLEDDISPLAY_GEOMETRY screen_geometry); + 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 ee456d9b2..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,10 +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_geometry), ui(&dispdev) +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 @@ -937,7 +938,7 @@ void Screen::setup() useDisplay = true; #ifdef AutoOLEDWire_h - dispdev.setDetected(screen_model); + dispdev.setDetected(model); #endif #ifdef USE_SH1107_128_64 @@ -1176,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); @@ -1188,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(); @@ -1820,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 ebffc305a..602211179 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -2,16 +2,19 @@ #include "configuration.h" +#include "detect/ScanI2C.h" +#include "mesh/generated/meshtastic/config.pb.h" +#include + #if !HAS_SCREEN #include "power.h" -#include namespace graphics { // Noop class for boards without screen. class Screen { public: - explicit Screen(char) {} + explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY); void onPress() {} void setup() {} void setOn(bool) {} @@ -116,12 +119,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. // diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp index 0fac01c3d..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, OLEDDISPLAY_GEOMETRY screen_geometry) +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 9feab3bdc..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, OLEDDISPLAY_GEOMETRY screen_geometry); + 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/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..29e8a19ed 100644 --- a/src/input/kbI2cBase.h +++ b/src/input/kbI2cBase.h @@ -2,6 +2,7 @@ #include "InputBroker.h" #include "SinglePortModule.h" // TODO: what header file to include? +#include "Wire.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 e3f7fe274..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,21 +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; -OLEDDISPLAY_GEOMETRY screen_geometry = GEOMETRY_128_64; +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 @@ -176,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; @@ -262,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(); @@ -302,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 @@ -346,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) @@ -375,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 3e6251581..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,13 +20,10 @@ extern NimbleBluetooth *nimbleBluetooth; extern NRF52Bluetooth *nrf52Bluetooth; #endif -extern uint8_t screen_found; -extern uint8_t screen_model; -extern OLEDDISPLAY_GEOMETRY screen_geometry; -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/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/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index 9ece0058a..e831db028 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -5,8 +5,11 @@ #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 @@ -43,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"; @@ -56,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/variants/tlora_t3s3_v1/variant.h b/variants/tlora_t3s3_v1/variant.h index 4f87c09d0..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,