mirror of
https://github.com/meshtastic/firmware.git
synced 2026-09-21 05:45:27 -04:00
fix(detect): check LPS22HB before SFA30 at 0x5D and CRC-validate SFA30 probe
The SFA30 probe only compared the requestFrom() length, which equals the requested length for any device that ACKs, so an LPS33HW/LPS35HW at 0x5D was reported as SFA30. Probe WHO_AM_I first so ST sensors never receive the SFA30 command, and require valid Sensirion CRC-8 on every word of the device marking response. Fixes #11880
This commit is contained in:
1 parent
67e8aafef7
commit
dc4e835f5c
2 files changed
+24
-12
No files matched your search
@@ -139,7 +139,9 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation
|
||||
return value;
|
||||
}
|
||||
|
||||
bool ScanI2CTwoWire::i2cCommandResponseLength(ScanI2C::DeviceAddress addr, uint16_t command, uint8_t expectedLength) const
|
||||
// requestFrom() reports the full length for any device that ACKs, so only the per-word Sensirion
|
||||
// CRC-8 (poly 0x31, init 0xFF) proves a Sensirion device answered.
|
||||
bool ScanI2CTwoWire::sensirionResponseValid(ScanI2C::DeviceAddress addr, uint16_t command, uint8_t expectedLength) const
|
||||
{
|
||||
TwoWire *i2cBus = fetchI2CBus(addr);
|
||||
i2cBus->beginTransmission(addr.address);
|
||||
@@ -151,11 +153,20 @@ bool ScanI2CTwoWire::i2cCommandResponseLength(ScanI2C::DeviceAddress addr, uint1
|
||||
return false;
|
||||
}
|
||||
delay(20);
|
||||
uint8_t received = i2cBus->requestFrom(addr.address, expectedLength);
|
||||
bool match = (received == expectedLength);
|
||||
bool valid = (i2cBus->requestFrom(addr.address, expectedLength) == expectedLength);
|
||||
for (uint8_t i = 0; valid && i + 2 < expectedLength; i += 3) {
|
||||
uint8_t crc = 0xFF;
|
||||
for (uint8_t j = 0; j < 2; j++) {
|
||||
crc ^= (uint8_t)i2cBus->read();
|
||||
for (uint8_t bit = 0; bit < 8; bit++) {
|
||||
crc = (crc & 0x80) ? (crc << 1) ^ 0x31 : crc << 1;
|
||||
}
|
||||
}
|
||||
valid = (crc == i2cBus->read());
|
||||
}
|
||||
while (i2cBus->available())
|
||||
i2cBus->read();
|
||||
return match;
|
||||
return valid;
|
||||
}
|
||||
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR
|
||||
@@ -706,17 +717,18 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
}
|
||||
}
|
||||
}
|
||||
// SFA30 detection: send 2-byte command 0xD060 (Get Device Marking) and check for 48-byte response
|
||||
if (i2cCommandResponseLength(addr, 0xD060, 48)) {
|
||||
type = SFA30;
|
||||
logFoundDevice("SFA30", (uint8_t)addr.address);
|
||||
break;
|
||||
}
|
||||
// Fallback: LPS22HB detection at alternate address using WHO_AM_I register (0x0F == 0xB1)
|
||||
// LPS22HB family (also LPS33HW/LPS35HW): WHO_AM_I (0x0F) == 0xB1. Checked before SFA30, whose
|
||||
// command an ST sensor would take as a write to a reserved register.
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0F), 1);
|
||||
if (registerValue == 0xB1) {
|
||||
type = LPS22HB;
|
||||
logFoundDevice("LPS22HB", (uint8_t)addr.address);
|
||||
break;
|
||||
}
|
||||
// SFA30 detection: 2-byte command 0xD060 (Get Device Marking) returns 48 bytes of CRC-checked words
|
||||
if (sensirionResponseValid(addr, 0xD060, 48)) {
|
||||
type = SFA30;
|
||||
logFoundDevice("SFA30", (uint8_t)addr.address);
|
||||
}
|
||||
break;
|
||||
SCAN_SIMPLE_CASE(LPS22HB_ADDR, LPS22HB, "LPS22HB", (uint8_t)addr.address)
|
||||
|
||||
@@ -55,7 +55,7 @@ class ScanI2CTwoWire : public ScanI2C
|
||||
|
||||
uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth, bool) const;
|
||||
|
||||
bool i2cCommandResponseLength(DeviceAddress addr, uint16_t command, uint8_t expectedLength) const;
|
||||
bool sensirionResponseValid(DeviceAddress addr, uint16_t command, uint8_t expectedLength) const;
|
||||
|
||||
DeviceType probeOLED(ScanI2C::DeviceAddress) const;
|
||||
|
||||
|
||||
Reference in new issue
Block a user