2023-03-08 19:13:46 -08:00
|
|
|
#include "ScanI2CTwoWire.h"
|
|
|
|
|
|
2024-07-26 03:16:21 +02:00
|
|
|
#if !MESHTASTIC_EXCLUDE_I2C
|
|
|
|
|
|
2023-03-08 19:13:46 -08:00
|
|
|
#include "concurrency/LockGuard.h"
|
2024-01-12 02:00:31 -06:00
|
|
|
#if defined(ARCH_PORTDUINO)
|
2023-11-29 00:48:30 -06:00
|
|
|
#include "linux/LinuxHardwareI2C.h"
|
|
|
|
|
#endif
|
2023-03-08 19:13:46 -08:00
|
|
|
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
2024-10-24 21:58:24 +02:00
|
|
|
#include "meshUtils.h" // vformat
|
2023-03-08 19:13:46 -08:00
|
|
|
#endif
|
|
|
|
|
|
2024-05-25 12:37:55 +02:00
|
|
|
bool in_array(uint8_t *array, int size, uint8_t lookfor)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < size; i++)
|
|
|
|
|
if (lookfor == array[i])
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-08 19:13:46 -08:00
|
|
|
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) {
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("SH1106", (uint8_t)addr.address);
|
2023-03-08 19:13:46 -08:00
|
|
|
o_probe = SCREEN_SH1106; // SH1106
|
|
|
|
|
} else if (r == 0x03 || r == 0x04 || r == 0x06 || r == 0x07) {
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("SSD1306", (uint8_t)addr.address);
|
2023-03-08 19:13:46 -08:00
|
|
|
o_probe = SCREEN_SSD1306; // SSD1306
|
|
|
|
|
}
|
|
|
|
|
c++;
|
|
|
|
|
} while ((r != r_prev) && (c < 4));
|
2024-10-14 06:11:43 +02:00
|
|
|
LOG_DEBUG("0x%x subtype probed in %i tries ", r, c);
|
2023-03-08 19:13:46 -08:00
|
|
|
|
|
|
|
|
return o_probe;
|
|
|
|
|
}
|
|
|
|
|
uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation ®isterLocation,
|
2025-01-18 14:10:13 +01:00
|
|
|
ScanI2CTwoWire::ResponseWidth responseWidth, bool zeropad = false) const
|
2023-03-08 19:13:46 -08:00
|
|
|
{
|
|
|
|
|
uint16_t value = 0x00;
|
|
|
|
|
TwoWire *i2cBus = fetchI2CBus(registerLocation.i2cAddress);
|
|
|
|
|
|
|
|
|
|
i2cBus->beginTransmission(registerLocation.i2cAddress.address);
|
|
|
|
|
i2cBus->write(registerLocation.registerAddress);
|
2025-01-18 14:10:13 +01:00
|
|
|
if (zeropad) {
|
|
|
|
|
// Lark Commands need the argument list length in 2 bytes.
|
|
|
|
|
i2cBus->write((int)0);
|
|
|
|
|
i2cBus->write((int)0);
|
|
|
|
|
}
|
2023-03-08 19:13:46 -08:00
|
|
|
i2cBus->endTransmission();
|
|
|
|
|
delay(20);
|
|
|
|
|
i2cBus->requestFrom(registerLocation.i2cAddress.address, responseWidth);
|
2025-01-18 14:10:13 +01:00
|
|
|
if (i2cBus->available() > 1) {
|
2023-03-08 19:13:46 -08:00
|
|
|
// Read MSB, then LSB
|
|
|
|
|
value = (uint16_t)i2cBus->read() << 8;
|
|
|
|
|
value |= i2cBus->read();
|
|
|
|
|
} else if (i2cBus->available()) {
|
|
|
|
|
value = i2cBus->read();
|
|
|
|
|
}
|
2025-01-18 14:10:13 +01:00
|
|
|
// Drain excess bytes
|
|
|
|
|
for (uint8_t i = 0; i < responseWidth - 1; i++) {
|
|
|
|
|
if (i2cBus->available())
|
|
|
|
|
i2cBus->read();
|
|
|
|
|
}
|
2023-03-08 19:13:46 -08:00
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define SCAN_SIMPLE_CASE(ADDR, T, ...) \
|
|
|
|
|
case ADDR: \
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice(__VA_ARGS__); \
|
2023-03-08 19:13:46 -08:00
|
|
|
type = T; \
|
|
|
|
|
break;
|
|
|
|
|
|
2024-05-25 12:37:55 +02:00
|
|
|
void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
2023-03-08 19:13:46 -08:00
|
|
|
{
|
|
|
|
|
concurrency::LockGuard guard((concurrency::Lock *)&lock);
|
|
|
|
|
|
2024-11-04 12:16:25 -06:00
|
|
|
LOG_DEBUG("Scan for I2C devices on port %d", port);
|
2023-03-08 19:13:46 -08:00
|
|
|
|
|
|
|
|
uint8_t err;
|
|
|
|
|
|
|
|
|
|
DeviceAddress addr(port, 0x00);
|
|
|
|
|
|
|
|
|
|
uint16_t registerValue = 0x00;
|
|
|
|
|
ScanI2C::DeviceType type;
|
|
|
|
|
TwoWire *i2cBus;
|
|
|
|
|
#ifdef RV3028_RTC
|
|
|
|
|
Melopero_RV3028 rtc;
|
|
|
|
|
#endif
|
|
|
|
|
|
2024-09-18 03:28:23 +12:00
|
|
|
#if WIRE_INTERFACES_COUNT == 2
|
2023-03-08 19:13:46 -08:00
|
|
|
if (port == I2CPort::WIRE1) {
|
|
|
|
|
i2cBus = &Wire1;
|
|
|
|
|
} else {
|
|
|
|
|
#endif
|
|
|
|
|
i2cBus = &Wire;
|
2024-09-18 03:28:23 +12:00
|
|
|
#if WIRE_INTERFACES_COUNT == 2
|
2023-03-08 19:13:46 -08:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2024-10-26 12:03:28 +02:00
|
|
|
// We only need to scan 112 addresses, the rest is reserved for special purposes
|
|
|
|
|
// 0x00 General Call
|
|
|
|
|
// 0x01 CBUS addresses
|
|
|
|
|
// 0x02 Reserved for different bus formats
|
|
|
|
|
// 0x03 Reserved for future purposes
|
|
|
|
|
// 0x04-0x07 High Speed Master Code
|
|
|
|
|
// 0x78-0x7B 10-bit slave addressing
|
|
|
|
|
// 0x7C-0x7F Reserved for future purposes
|
|
|
|
|
|
|
|
|
|
for (addr.address = 8; addr.address < 120; addr.address++) {
|
2024-06-17 15:09:38 +02:00
|
|
|
if (asize != 0) {
|
2024-11-26 13:59:50 -06:00
|
|
|
if (!in_array(address, asize, (uint8_t)addr.address))
|
2024-05-25 12:37:55 +02:00
|
|
|
continue;
|
2024-11-26 13:59:50 -06:00
|
|
|
LOG_DEBUG("Scan address 0x%x", (uint8_t)addr.address);
|
2024-06-17 15:09:38 +02:00
|
|
|
}
|
2023-03-08 19:13:46 -08:00
|
|
|
i2cBus->beginTransmission(addr.address);
|
2023-11-29 00:48:30 -06:00
|
|
|
#ifdef ARCH_PORTDUINO
|
2024-12-22 22:53:54 -06:00
|
|
|
err = 2;
|
|
|
|
|
if ((addr.address >= 0x30 && addr.address <= 0x37) || (addr.address >= 0x50 && addr.address <= 0x5F)) {
|
|
|
|
|
if (i2cBus->read() != -1)
|
|
|
|
|
err = 0;
|
|
|
|
|
} else {
|
|
|
|
|
err = i2cBus->writeQuick((uint8_t)0);
|
|
|
|
|
}
|
|
|
|
|
if (err != 0)
|
2023-11-29 00:48:30 -06:00
|
|
|
err = 2;
|
|
|
|
|
#else
|
2023-03-08 19:13:46 -08:00
|
|
|
err = i2cBus->endTransmission();
|
2023-11-29 00:48:30 -06:00
|
|
|
#endif
|
2023-03-08 19:13:46 -08:00
|
|
|
type = NONE;
|
|
|
|
|
if (err == 0) {
|
|
|
|
|
switch (addr.address) {
|
|
|
|
|
case SSD1306_ADDRESS:
|
|
|
|
|
type = probeOLED(addr);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
#ifdef RV3028_RTC
|
|
|
|
|
case RV3028_RTC:
|
|
|
|
|
// foundDevices[addr] = RTC_RV3028;
|
|
|
|
|
type = RTC_RV3028;
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("RV3028", (uint8_t)addr.address);
|
2023-03-08 19:13:46 -08:00
|
|
|
rtc.initI2C(*i2cBus);
|
|
|
|
|
rtc.writeToRegister(0x35, 0x07); // no Clkout
|
|
|
|
|
rtc.writeToRegister(0x37, 0xB4);
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef PCF8563_RTC
|
2024-11-26 13:59:50 -06:00
|
|
|
SCAN_SIMPLE_CASE(PCF8563_RTC, RTC_PCF8563, "PCF8563", (uint8_t)addr.address)
|
2023-03-08 19:13:46 -08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
case CARDKB_ADDR:
|
|
|
|
|
// Do we have the RAK14006 instead?
|
|
|
|
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x04), 1);
|
|
|
|
|
if (registerValue == 0x02) {
|
|
|
|
|
// KEYPAD_VERSION
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("RAK14004", (uint8_t)addr.address);
|
2023-03-08 19:13:46 -08:00
|
|
|
type = RAK14004;
|
|
|
|
|
} else {
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("M5 cardKB", (uint8_t)addr.address);
|
2023-03-08 19:13:46 -08:00
|
|
|
type = CARDKB;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2024-11-26 13:59:50 -06:00
|
|
|
SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard", (uint8_t)addr.address);
|
|
|
|
|
SCAN_SIMPLE_CASE(BBQ10_KB_ADDR, BBQ10KB, "BB Q10", (uint8_t)addr.address);
|
2024-10-21 16:53:36 +10:00
|
|
|
|
2024-11-26 13:59:50 -06:00
|
|
|
SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "ST7567", (uint8_t)addr.address);
|
2023-07-03 16:34:32 +02:00
|
|
|
#ifdef HAS_NCP5623
|
2024-11-26 13:59:50 -06:00
|
|
|
SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623", (uint8_t)addr.address);
|
2023-07-03 16:34:32 +02:00
|
|
|
#endif
|
2025-04-01 22:39:40 +02:00
|
|
|
#ifdef HAS_LP5562
|
|
|
|
|
SCAN_SIMPLE_CASE(LP5562_ADDR, LP5562, "LP5562", (uint8_t)addr.address);
|
|
|
|
|
#endif
|
2025-04-03 19:18:18 +00:00
|
|
|
case XPOWERS_AXP192_AXP2101_ADDRESS:
|
|
|
|
|
// Do we have the axp2101/192 or the TCA8418
|
|
|
|
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x90), 1);
|
|
|
|
|
if (registerValue == 0x0) {
|
|
|
|
|
logFoundDevice("TCA8418", (uint8_t)addr.address);
|
|
|
|
|
type = TCA8418KB;
|
|
|
|
|
} else {
|
|
|
|
|
logFoundDevice("AXP192/AXP2101", (uint8_t)addr.address);
|
|
|
|
|
type = PMU_AXP192_AXP2101;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2023-03-08 19:13:46 -08:00
|
|
|
case BME_ADDR:
|
|
|
|
|
case BME_ADDR_ALTERNATE:
|
|
|
|
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xD0), 1); // GET_ID
|
|
|
|
|
switch (registerValue) {
|
|
|
|
|
case 0x61:
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("BME680", (uint8_t)addr.address);
|
2023-03-08 19:13:46 -08:00
|
|
|
type = BME_680;
|
|
|
|
|
break;
|
|
|
|
|
case 0x60:
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("BME280", (uint8_t)addr.address);
|
2023-03-08 19:13:46 -08:00
|
|
|
type = BME_280;
|
|
|
|
|
break;
|
2024-03-02 22:14:34 +01:00
|
|
|
case 0x55:
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("BMP085/BMP180", (uint8_t)addr.address);
|
2024-03-02 22:14:34 +01:00
|
|
|
type = BMP_085;
|
|
|
|
|
break;
|
2025-03-05 22:58:18 -05:00
|
|
|
case 0x00:
|
|
|
|
|
// do we have a DPS310 instead?
|
|
|
|
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0D), 1);
|
|
|
|
|
switch (registerValue) {
|
|
|
|
|
case 0x10:
|
|
|
|
|
logFoundDevice("DPS310", (uint8_t)addr.address);
|
|
|
|
|
type = DPS310;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2023-03-08 19:13:46 -08:00
|
|
|
default:
|
2024-08-17 16:19:39 +10:00
|
|
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1); // GET_ID
|
2024-09-02 10:23:31 +02:00
|
|
|
switch (registerValue) {
|
2024-08-17 16:19:39 +10:00
|
|
|
case 0x50: // BMP-388 should be 0x50
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("BMP-388", (uint8_t)addr.address);
|
2024-08-17 16:19:39 +10:00
|
|
|
type = BMP_3XX;
|
|
|
|
|
break;
|
2025-02-20 14:36:49 +01:00
|
|
|
case 0x60: // BMP-390 should be 0x60
|
|
|
|
|
logFoundDevice("BMP-390", (uint8_t)addr.address);
|
|
|
|
|
type = BMP_3XX;
|
|
|
|
|
break;
|
2024-08-17 16:19:39 +10:00
|
|
|
case 0x58: // BMP-280 should be 0x58
|
|
|
|
|
default:
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("BMP-280", (uint8_t)addr.address);
|
2024-08-17 16:19:39 +10:00
|
|
|
type = BMP_280;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-09-02 10:23:31 +02:00
|
|
|
break;
|
2023-03-08 19:13:46 -08:00
|
|
|
}
|
|
|
|
|
break;
|
2024-05-31 18:17:53 +02:00
|
|
|
#ifndef HAS_NCP5623
|
|
|
|
|
case AHT10_ADDR:
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("AHT10", (uint8_t)addr.address);
|
2024-05-31 18:17:53 +02:00
|
|
|
type = AHT10;
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
2023-03-08 19:13:46 -08:00
|
|
|
case INA_ADDR:
|
|
|
|
|
case INA_ADDR_ALTERNATE:
|
2024-03-16 16:01:43 +01:00
|
|
|
case INA_ADDR_WAVESHARE_UPS:
|
2023-03-08 19:13:46 -08:00
|
|
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2);
|
2024-10-14 06:11:43 +02:00
|
|
|
LOG_DEBUG("Register MFG_UID: 0x%x", registerValue);
|
2023-03-08 19:13:46 -08:00
|
|
|
if (registerValue == 0x5449) {
|
2024-12-21 12:24:29 +11:00
|
|
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFF), 2);
|
|
|
|
|
LOG_DEBUG("Register DIE_UID: 0x%x", registerValue);
|
|
|
|
|
|
|
|
|
|
if (registerValue == 0x2260) {
|
|
|
|
|
logFoundDevice("INA226", (uint8_t)addr.address);
|
|
|
|
|
type = INA226;
|
|
|
|
|
} else {
|
|
|
|
|
logFoundDevice("INA260", (uint8_t)addr.address);
|
|
|
|
|
type = INA260;
|
|
|
|
|
}
|
2023-03-08 19:13:46 -08:00
|
|
|
} else { // Assume INA219 if INA260 ID is not found
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("INA219", (uint8_t)addr.address);
|
2023-03-08 19:13:46 -08:00
|
|
|
type = INA219;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2023-11-04 19:07:00 -06:00
|
|
|
case INA3221_ADDR:
|
2024-04-20 14:58:21 -06:00
|
|
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2);
|
2024-11-23 16:56:40 +01:00
|
|
|
LOG_DEBUG("Register MFG_UID FE: 0x%x", registerValue);
|
2024-04-20 14:58:21 -06:00
|
|
|
if (registerValue == 0x5449) {
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("INA3221", (uint8_t)addr.address);
|
2024-04-20 14:58:21 -06:00
|
|
|
type = INA3221;
|
2024-06-03 21:50:28 -05:00
|
|
|
} else {
|
2024-11-23 16:56:40 +01:00
|
|
|
/* check the first 2 bytes of the 6 byte response register
|
|
|
|
|
LARK FW 1.0 should return:
|
|
|
|
|
RESPONSE_STATUS STATUS_SUCCESS (0x53)
|
|
|
|
|
RESPONSE_CMD CMD_GET_VERSION (0x05)
|
|
|
|
|
RESPONSE_LEN_L 0x02
|
|
|
|
|
RESPONSE_LEN_H 0x00
|
|
|
|
|
RESPONSE_PAYLOAD 0x01
|
|
|
|
|
RESPONSE_PAYLOAD+1 0x00
|
|
|
|
|
*/
|
2025-01-18 14:10:13 +01:00
|
|
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x05), 6, true);
|
2024-11-23 16:56:40 +01:00
|
|
|
LOG_DEBUG("Register MFG_UID 05: 0x%x", registerValue);
|
|
|
|
|
if (registerValue == 0x5305) {
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("DFRobot Lark", (uint8_t)addr.address);
|
2024-11-23 16:56:40 +01:00
|
|
|
type = DFROBOT_LARK;
|
|
|
|
|
}
|
|
|
|
|
// else: probably a RAK12500/UBLOX GPS on I2C
|
2024-04-20 14:58:21 -06:00
|
|
|
}
|
2024-04-21 11:35:42 -06:00
|
|
|
break;
|
2023-03-23 11:32:04 -05:00
|
|
|
case MCP9808_ADDR:
|
2024-09-12 01:53:17 +02:00
|
|
|
// We need to check for STK8BAXX first, since register 0x07 is new data flag for the z-axis and can produce some
|
|
|
|
|
// weird result. and register 0x00 doesn't seems to be colliding with MCP9808 and LIS3DH chips.
|
|
|
|
|
{
|
2024-11-23 17:18:22 -06:00
|
|
|
#ifdef HAS_STK8XXX
|
2024-09-12 01:53:17 +02:00
|
|
|
// Check register 0x00 for 0x8700 response to ID STK8BA53 chip.
|
|
|
|
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 2);
|
|
|
|
|
if (registerValue == 0x8700) {
|
|
|
|
|
type = STK8BAXX;
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("STK8BAXX", (uint8_t)addr.address);
|
2024-09-12 01:53:17 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2024-11-23 17:18:22 -06:00
|
|
|
#endif
|
2023-03-23 11:32:04 -05:00
|
|
|
|
2024-09-12 01:53:17 +02:00
|
|
|
// Check register 0x07 for 0x0400 response to ID MCP9808 chip.
|
|
|
|
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x07), 2);
|
|
|
|
|
if (registerValue == 0x0400) {
|
|
|
|
|
type = MCP9808;
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("MCP9808", (uint8_t)addr.address);
|
2024-09-12 01:53:17 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check register 0x0F for 0x3300 response to ID LIS3DH chip.
|
|
|
|
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0F), 2);
|
2024-09-23 18:40:54 -05:00
|
|
|
if (registerValue == 0x3300 || registerValue == 0x3333) { // RAK4631 WisBlock has LIS3DH register at 0x3333
|
2024-09-12 01:53:17 +02:00
|
|
|
type = LIS3DH;
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("LIS3DH", (uint8_t)addr.address);
|
2024-09-12 01:53:17 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2025-03-06 20:49:55 -05:00
|
|
|
case SHT31_4x_ADDR: // same as OPT3001_ADDR_ALT
|
|
|
|
|
case SHT31_4x_ADDR_ALT: // same as OPT3001_ADDR
|
2024-05-10 07:13:12 -05:00
|
|
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x89), 2);
|
2025-06-18 13:19:52 +02:00
|
|
|
if (registerValue == 0x11a2 || registerValue == 0x11da || registerValue == 0xe9c || registerValue == 0xc8d) {
|
2024-05-10 07:13:12 -05:00
|
|
|
type = SHT4X;
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("SHT4X", (uint8_t)addr.address);
|
2024-06-02 07:39:08 -05:00
|
|
|
} else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2) == 0x5449) {
|
|
|
|
|
type = OPT3001;
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("OPT3001", (uint8_t)addr.address);
|
2024-05-10 07:13:12 -05:00
|
|
|
} else {
|
|
|
|
|
type = SHT31;
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("SHT31", (uint8_t)addr.address);
|
2024-05-10 07:13:12 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
2024-11-26 13:59:50 -06:00
|
|
|
SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTC3, "SHTC3", (uint8_t)addr.address)
|
2024-10-07 19:50:44 -05:00
|
|
|
case RCWL9620_ADDR:
|
|
|
|
|
// get MAX30102 PARTID
|
|
|
|
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFF), 1);
|
|
|
|
|
if (registerValue == 0x15) {
|
|
|
|
|
type = MAX30102;
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("MAX30102", (uint8_t)addr.address);
|
2024-10-07 19:50:44 -05:00
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
type = RCWL9620;
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("RCWL9620", (uint8_t)addr.address);
|
2024-10-07 19:50:44 -05:00
|
|
|
}
|
|
|
|
|
break;
|
2023-03-08 19:13:46 -08:00
|
|
|
|
|
|
|
|
case LPS22HB_ADDR_ALT:
|
2024-11-26 13:59:50 -06:00
|
|
|
SCAN_SIMPLE_CASE(LPS22HB_ADDR, LPS22HB, "LPS22HB", (uint8_t)addr.address)
|
|
|
|
|
SCAN_SIMPLE_CASE(QMC6310_ADDR, QMC6310, "QMC6310", (uint8_t)addr.address)
|
2024-04-05 13:20:22 +01:00
|
|
|
|
|
|
|
|
case QMI8658_ADDR:
|
|
|
|
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0A), 1); // get ID
|
|
|
|
|
if (registerValue == 0xC0) {
|
|
|
|
|
type = BQ24295;
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("BQ24295", (uint8_t)addr.address);
|
2024-04-15 13:30:45 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0F), 1); // get ID
|
|
|
|
|
if (registerValue == 0x6A) {
|
|
|
|
|
type = LSM6DS3;
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("LSM6DS3", (uint8_t)addr.address);
|
2024-04-05 13:20:22 +01:00
|
|
|
} else {
|
|
|
|
|
type = QMI8658;
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("QMI8658", (uint8_t)addr.address);
|
2024-04-05 13:20:22 +01:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2024-11-26 13:59:50 -06:00
|
|
|
SCAN_SIMPLE_CASE(QMC5883L_ADDR, QMC5883L, "QMC5883L", (uint8_t)addr.address)
|
|
|
|
|
SCAN_SIMPLE_CASE(HMC5883L_ADDR, HMC5883L, "HMC5883L", (uint8_t)addr.address)
|
2024-10-26 12:03:28 +02:00
|
|
|
#ifdef HAS_QMA6100P
|
2024-11-26 13:59:50 -06:00
|
|
|
SCAN_SIMPLE_CASE(QMA6100P_ADDR, QMA6100P, "QMA6100P", (uint8_t)addr.address)
|
2024-10-26 12:03:28 +02:00
|
|
|
#else
|
2024-11-26 13:59:50 -06:00
|
|
|
SCAN_SIMPLE_CASE(PMSA0031_ADDR, PMSA0031, "PMSA0031", (uint8_t)addr.address)
|
2024-10-26 12:03:28 +02:00
|
|
|
#endif
|
2024-11-07 18:01:58 +01:00
|
|
|
case BMA423_ADDR: // this can also be LIS3DH_ADDR_ALT
|
|
|
|
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0F), 2);
|
|
|
|
|
if (registerValue == 0x3300 || registerValue == 0x3333) { // RAK4631 WisBlock has LIS3DH register at 0x3333
|
|
|
|
|
type = LIS3DH;
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("LIS3DH", (uint8_t)addr.address);
|
2024-11-07 18:01:58 +01:00
|
|
|
} else {
|
|
|
|
|
type = BMA423;
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("BMA423", (uint8_t)addr.address);
|
2024-11-07 18:01:58 +01:00
|
|
|
}
|
|
|
|
|
break;
|
Add rak12035 VB Soil Monitor Tested & Working (#6741)
* [WIP] Add RAK12035VB Soil Moisture Sensor support
Introduce the RAK12035 sensor as an environmental telemetry sensor,
including necessary calibration checks and default values. Update
relevant files to integrate the sensor into the existing telemetry system.
This hardware is not just one module, but a couple.. RAK12023 and
RAK12035 is the component stack, the RAK12023 does not seem to matter
much and allows for multiple RAK12035 devices to be used.
Co-Authored-By: @Justin-Mann
* [WIP] Add RAK12035VB Soil Moisture Sensor support
Introduce the RAK12035 sensor as an environmental telemetry sensor,
including necessary calibration checks and default values. Update
relevant files to integrate the sensor into the existing telemetry system.
This hardware is not just one module, but a couple.. RAK12023 and
RAK12035 is the component stack, the RAK12023 does not seem to matter
much and allows for multiple RAK12035 devices to be used.
Co-Authored-By: @Justin-Mann
* [WIP] Add RAK12035VB Soil Moisture Sensor support
Introduce the RAK12035 sensor as an environmental telemetry sensor,
including necessary calibration checks and default values. Update
relevant files to integrate the sensor into the existing telemetry system.
This hardware is not just one module, but a couple.. RAK12023 and
RAK12035 is the component stack, the RAK12023 does not seem to matter
much and allows for multiple RAK12035 devices to be used.
Co-Authored-By: @Justin-Mann
* [WIP] Add RAK12035VB Soil Moisture Sensor support
Introduce the RAK12035 sensor as an environmental telemetry sensor,
including necessary calibration checks and default values. Update
relevant files to integrate the sensor into the existing telemetry system.
This hardware is not just one module, but a couple.. RAK12023 and
RAK12035 is the component stack, the RAK12023 does not seem to matter
much and allows for multiple RAK12035 devices to be used.
Co-Authored-By: @Justin-Mann
* Update to 1.0.4 release of RAK12035_SoilMoisture
* cleanup
* cool
* .
* ..
* little bit of cleanup and recompile/upload/test on RAK WISBLAOCK STACK: RAK19007/RAK4631/RAK12035VB/RAK12500
looks like soil monitor is working correctly, new environmental metrics are comming thru [new protos soil_moisture, soil_temperature] and GPS is working again with the RAK 12500.
improvements could be made around the configuration of the monitor.
next steps include updating the client(s) to react to, log and display the new proto metrics for soil temp and humidity.
* . comments about current limitations and TODOs
* trunk update
* trying to autoformat..
* fix formatting attempt 2
* ..
* ...
* ...
* .
* some corrections and local build success
* correction in temp code
* grr formatting
* cleanup after a few experiments
* remove temp code to overwrite values for temp and humidity protos.. next step just update the clients to know about soil_temperature and soil_humidity protos.
* update some values in varient for rak wistap
* working out trunk formatting..
* wip
. corrections to other build variants
* .
* protobuffs?
* protobufs?
* Update protobufs ref
* Protobufs ref
* Trunk
* Update RAK12035Sensor.cpp
* Fmt
* comment changes
* dumb mistakes... resolved, actually built and tested.. all good..
* Update src/modules/Telemetry/Sensor/RAK12035Sensor.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update src/modules/Telemetry/Sensor/RAK12035Sensor.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* . proto submod
* proto
* proto
* merge master
* mabe a fix for GPS pin conflict, waiting on a new gps module to try
* merge master, attempt to fix gps (RAK12500) pin conflict with RAK12023/12035
* .
* .
---------
Co-authored-by: Tom Fifield <tom@tomfifield.net>
Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-19 17:51:03 -06:00
|
|
|
case TCA9535_ADDR:
|
|
|
|
|
case RAK120352_ADDR:
|
|
|
|
|
case RAK120353_ADDR:
|
|
|
|
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x02), 1);
|
|
|
|
|
if (registerValue == addr.address) { // RAK12035 returns its I2C address at 0x02 (eg 0x20)
|
|
|
|
|
type = RAK12035;
|
|
|
|
|
logFoundDevice("RAK12035", (uint8_t)addr.address);
|
|
|
|
|
} else {
|
|
|
|
|
type = TCA9535;
|
|
|
|
|
logFoundDevice("TCA9535", (uint8_t)addr.address);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
2024-11-07 18:01:58 +01:00
|
|
|
|
2024-11-26 13:59:50 -06:00
|
|
|
SCAN_SIMPLE_CASE(LSM6DS3_ADDR, LSM6DS3, "LSM6DS3", (uint8_t)addr.address);
|
|
|
|
|
SCAN_SIMPLE_CASE(TCA9555_ADDR, TCA9555, "TCA9555", (uint8_t)addr.address);
|
|
|
|
|
SCAN_SIMPLE_CASE(VEML7700_ADDR, VEML7700, "VEML7700", (uint8_t)addr.address);
|
|
|
|
|
SCAN_SIMPLE_CASE(TSL25911_ADDR, TSL2591, "TSL2591", (uint8_t)addr.address);
|
|
|
|
|
SCAN_SIMPLE_CASE(MLX90632_ADDR, MLX90632, "MLX90632", (uint8_t)addr.address);
|
|
|
|
|
SCAN_SIMPLE_CASE(NAU7802_ADDR, NAU7802, "NAU7802", (uint8_t)addr.address);
|
|
|
|
|
SCAN_SIMPLE_CASE(MAX1704X_ADDR, MAX17048, "MAX17048", (uint8_t)addr.address);
|
2025-01-18 14:10:13 +01:00
|
|
|
SCAN_SIMPLE_CASE(DFROBOT_RAIN_ADDR, DFROBOT_RAIN, "DFRobot Rain Gauge", (uint8_t)addr.address);
|
2025-03-07 18:51:38 +08:00
|
|
|
SCAN_SIMPLE_CASE(LTR390UV_ADDR, LTR390UV, "LTR390UV", (uint8_t)addr.address);
|
2025-05-25 14:29:02 +02:00
|
|
|
SCAN_SIMPLE_CASE(PCT2075_ADDR, PCT2075, "PCT2075", (uint8_t)addr.address);
|
2024-10-08 14:05:13 +02:00
|
|
|
#ifdef HAS_TPS65233
|
2024-11-26 13:59:50 -06:00
|
|
|
SCAN_SIMPLE_CASE(TPS65233_ADDR, TPS65233, "TPS65233", (uint8_t)addr.address);
|
2024-10-08 14:05:13 +02:00
|
|
|
#endif
|
2024-10-21 16:53:36 +10:00
|
|
|
|
|
|
|
|
case MLX90614_ADDR_DEF:
|
|
|
|
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0e), 1);
|
|
|
|
|
if (registerValue == 0x5a) {
|
|
|
|
|
type = MLX90614;
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("MLX90614", (uint8_t)addr.address);
|
2024-10-21 16:53:36 +10:00
|
|
|
} else {
|
|
|
|
|
type = MPR121KB;
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("MPR121KB", (uint8_t)addr.address);
|
2024-10-21 16:53:36 +10:00
|
|
|
}
|
|
|
|
|
break;
|
2023-03-08 19:13:46 -08:00
|
|
|
|
2024-09-25 21:25:31 +10:00
|
|
|
case ICM20948_ADDR: // same as BMX160_ADDR
|
|
|
|
|
case ICM20948_ADDR_ALT: // same as MPU6050_ADDR
|
|
|
|
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1);
|
|
|
|
|
if (registerValue == 0xEA) {
|
|
|
|
|
type = ICM20948;
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("ICM20948", (uint8_t)addr.address);
|
2024-09-25 21:25:31 +10:00
|
|
|
break;
|
|
|
|
|
} else if (addr.address == BMX160_ADDR) {
|
|
|
|
|
type = BMX160;
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("BMX160", (uint8_t)addr.address);
|
2024-09-25 21:25:31 +10:00
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
type = MPU6050;
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("MPU6050", (uint8_t)addr.address);
|
2024-09-25 21:25:31 +10:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2024-11-24 07:53:52 -05:00
|
|
|
case CGRADSENS_ADDR:
|
|
|
|
|
// Register 0x00 of the RadSens sensor contains is product identifier 0x7D
|
2024-12-09 20:46:13 -05:00
|
|
|
// Undocumented, but some devices return a product identifier of 0x7A
|
2024-11-24 07:53:52 -05:00
|
|
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1);
|
2024-12-09 20:46:13 -05:00
|
|
|
if (registerValue == 0x7D || registerValue == 0x7A) {
|
2024-11-24 07:53:52 -05:00
|
|
|
type = CGRADSENS;
|
2024-11-26 13:59:50 -06:00
|
|
|
logFoundDevice("ClimateGuard RadSens", (uint8_t)addr.address);
|
2024-11-24 07:53:52 -05:00
|
|
|
break;
|
2024-12-09 20:46:13 -05:00
|
|
|
} else {
|
|
|
|
|
LOG_DEBUG("Unexpected Device ID for RadSense: addr=0x%x id=0x%x", CGRADSENS_ADDR, registerValue);
|
2024-11-24 07:53:52 -05:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2024-12-22 22:53:54 -06:00
|
|
|
case 0x48: {
|
|
|
|
|
i2cBus->beginTransmission(addr.address);
|
|
|
|
|
uint8_t getInfo[] = {0x5A, 0xC0, 0x00, 0xFF, 0xFC};
|
|
|
|
|
uint8_t expectedInfo[] = {0xa5, 0xE0, 0x00, 0x3F, 0x19};
|
|
|
|
|
uint8_t info[5];
|
|
|
|
|
size_t len = 0;
|
|
|
|
|
i2cBus->write(getInfo, 5);
|
|
|
|
|
i2cBus->endTransmission();
|
|
|
|
|
len = i2cBus->readBytes(info, 5);
|
|
|
|
|
if (len == 5 && memcmp(expectedInfo, info, len) == 0) {
|
2024-12-27 18:01:02 +11:00
|
|
|
LOG_INFO("NXP SE050 crypto chip found");
|
2024-12-22 22:53:54 -06:00
|
|
|
type = NXP_SE050;
|
|
|
|
|
|
|
|
|
|
} else {
|
2024-12-27 18:01:02 +11:00
|
|
|
LOG_INFO("FT6336U touchscreen found");
|
2024-12-22 22:53:54 -06:00
|
|
|
type = FT6336U;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-08 19:13:46 -08:00
|
|
|
default:
|
2024-11-26 13:59:50 -06:00
|
|
|
LOG_INFO("Device found at address 0x%x was not able to be enumerated", (uint8_t)addr.address);
|
2023-03-08 19:13:46 -08:00
|
|
|
}
|
|
|
|
|
} else if (err == 4) {
|
2024-11-26 13:59:50 -06:00
|
|
|
LOG_ERROR("Unknown error at address 0x%x", (uint8_t)addr.address);
|
2023-03-08 19:13:46 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if a type was found for the enumerated device - save, if so
|
|
|
|
|
if (type != NONE) {
|
|
|
|
|
deviceAddresses[type] = addr;
|
|
|
|
|
foundDevices[addr] = type;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-19 19:32:08 +02:00
|
|
|
void ScanI2CTwoWire::scanPort(I2CPort port)
|
|
|
|
|
{
|
2024-05-25 12:37:55 +02:00
|
|
|
scanPort(port, nullptr, 0);
|
2024-05-19 19:32:08 +02:00
|
|
|
}
|
|
|
|
|
|
2023-03-08 19:13:46 -08:00
|
|
|
TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const
|
|
|
|
|
{
|
2023-05-30 11:22:29 +08:00
|
|
|
if (address.port == ScanI2C::I2CPort::WIRE) {
|
2023-03-08 19:13:46 -08:00
|
|
|
return &Wire;
|
|
|
|
|
} else {
|
2024-09-18 03:28:23 +12:00
|
|
|
#if WIRE_INTERFACES_COUNT == 2
|
2023-03-08 19:13:46 -08:00
|
|
|
return &Wire1;
|
|
|
|
|
#else
|
|
|
|
|
return &Wire;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t ScanI2CTwoWire::countDevices() const
|
|
|
|
|
{
|
|
|
|
|
return foundDevices.size();
|
2024-07-02 20:03:51 +08:00
|
|
|
}
|
2024-11-26 13:59:50 -06:00
|
|
|
|
|
|
|
|
void ScanI2CTwoWire::logFoundDevice(const char *device, uint8_t address)
|
|
|
|
|
{
|
|
|
|
|
LOG_INFO("%s found at address 0x%x", device, address);
|
|
|
|
|
}
|
2025-03-27 08:31:57 -05:00
|
|
|
#endif
|