From dd0ee8b50a766e800395c350dea862c6a0151dd6 Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Thu, 9 Feb 2023 00:13:23 +0000 Subject: [PATCH] Additional support for Extended I2C Addresses --- I2CManager.cpp | 7 +++- I2CManager.h | 80 +++++++++++++++++++++++++++++++++++++++- I2CManager_NonBlocking.h | 2 +- 3 files changed, 85 insertions(+), 4 deletions(-) diff --git a/I2CManager.cpp b/I2CManager.cpp index 00aa71b..9608165 100644 --- a/I2CManager.cpp +++ b/I2CManager.cpp @@ -95,7 +95,7 @@ void I2CManagerClass::begin(void) { for (uint8_t addr=0x08; addr<0x78; addr++) { if (exists(addr)) { found = true; - DIAG(F("I2C Device found at x%x, %S?"), addr, guessI2CDeviceType(addr)); + DIAG(F("I2C Device found at 0x%x, %S?"), addr, guessI2CDeviceType(addr)); } } @@ -117,7 +117,7 @@ void I2CManagerClass::begin(void) { // Device responds when subbus selected but not when // subbus disabled - ergo it must be on subbus! found = true; - DIAG(F("I2C Device found at {I2CMux_%d,SubBus_%d,x%x}, %S?"), + DIAG(F("I2C Device found at {I2CMux_%d,SubBus_%d,0x%x}, %S?"), muxNo, subBus, addr, guessI2CDeviceType(addr)); } // Re-select subbus @@ -266,6 +266,9 @@ I2CManagerClass I2CManager = I2CManagerClass(); // try, and failure from timeout does not get retried. unsigned long I2CManagerClass::timeout = 100000UL; +// Buffer for conversion of I2CAddress to char*. +/* static */ char I2CAddress::addressBuffer[30]; + #if defined(I2C_EXTENDED_ADDRESS) // Count of I2C multiplexers found when initialising. If there is only one // MUX then the subbus does not de-selecting after use; however, if there diff --git a/I2CManager.h b/I2CManager.h index 2a3d80c..d50d9ce 100644 --- a/I2CManager.h +++ b/I2CManager.h @@ -192,6 +192,7 @@ private: I2CMux _muxNumber; I2CSubBus _subBus; uint8_t _deviceAddress; + static char addressBuffer[]; public: // Constructors // For I2CAddress "{Mux_0, SubBus_0, 0x23}" syntax. @@ -228,6 +229,41 @@ public: // (device assumed to be on the main I2C bus or on a currently selected subbus. operator uint8_t () const { return _deviceAddress; } + // Conversion from I2CAddress to char* (uses static storage so only + // one conversion can be done at a time). So don't call it twice in a + // single DIAG statement for example. + const char* toString() { + char *ptr = addressBuffer; + if (_muxNumber != I2CMux_None) { + strcpy_P(ptr, (const char*)F("{I2CMux_")); + ptr += 8; + *ptr++ = '0' + _muxNumber; + strcpy_P(ptr, (const char*)F(",Subbus_")); + ptr += 8; + if (_subBus == SubBus_None) { + strcpy_P(ptr, (const char*)F("None")); + ptr += 4; + } else if (_subBus == SubBus_All) { + strcpy_P(ptr, (const char*)F("All")); + ptr += 3; + } else + *ptr++ = '0' + _subBus; + *ptr++ = ','; + } + uint8_t temp = _deviceAddress; + *ptr++ = '0'; + *ptr++ = 'x'; + for (uint8_t index = 0; index<2; index++) { + uint8_t bits = (temp >> 4) & 0x0f; + *ptr++ = bits > 9 ? bits-10+'A' : bits+'0'; + temp <<= 4; + } + if (_muxNumber != I2CMux_None) + *ptr++ = '}'; + *ptr = 0; // terminate string + return addressBuffer; + } + // Comparison operator int operator == (I2CAddress &a) const { if (_deviceAddress != a._deviceAddress) @@ -249,8 +285,50 @@ public: }; #else +struct I2CAddress { +private: + uint8_t _deviceAddress; + static char addressBuffer[]; +public: + // Constructors + I2CAddress(const uint8_t deviceAddress) { + _deviceAddress = deviceAddress; + } + + // Basic constructor + I2CAddress() : I2CAddress(0) {} + + // Conversion operator from I2CAddress to uint8_t + // For "uint8_t address = i2cAddress;" syntax + operator uint8_t () const { return _deviceAddress; } + + // Conversion from I2CAddress to char* (uses static storage so only + // one conversion can be done at a time). So don't call it twice in a + // single DIAG statement for example. + const char* toString () { + char *ptr = addressBuffer; + // Just display hex value, two digits. + uint8_t temp = _deviceAddress; + *ptr++ = '0'; + *ptr++ = 'x'; + for (uint8_t index = 0; index<2; index++) { + uint8_t bits = (temp >> 4) & 0xf; + *ptr++ = bits > 9 ? bits-10+'a' : bits+'0'; + temp <<= 4; + } + *ptr = 0; // terminate string + return addressBuffer; + } + + // Comparison operator + int operator == (I2CAddress &a) const { + if (_deviceAddress != a._deviceAddress) + return false; // Different device address so no match + return true; // Same address on same mux and same subbus + } +}; // Legacy single-byte I2C address type for compact code and smooth changeover. -typedef uint8_t I2CAddress; +//typedef uint8_t I2CAddress; #endif // I2C_EXTENDED_ADDRESS diff --git a/I2CManager_NonBlocking.h b/I2CManager_NonBlocking.h index 4214ef9..4da932f 100644 --- a/I2CManager_NonBlocking.h +++ b/I2CManager_NonBlocking.h @@ -210,7 +210,7 @@ void I2CManagerClass::checkForTimeout() { unsigned long elapsed = micros() - startTime; if (elapsed > timeout) { #ifdef DIAG_IO - //DIAG(F("I2CManager Timeout on x%x, I2CRB=x%x"), (int)t->i2cAddress, currentRequest); + //DIAG(F("I2CManager Timeout on %s, I2CRB=%s"), t->i2cAddress.toString(), currentRequest); #endif // Excessive time. Dequeue request queueHead = t->nextRequest;