From 951aaeaa456789a9a3be568f12f713be7e6347e1 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 20 Jul 2022 12:06:11 -0300 Subject: [PATCH 01/10] initial Wire::setBufferSize commit --- libraries/Wire/src/Wire.cpp | 129 +++++++++++++++++++++++++++++++++++- libraries/Wire/src/Wire.h | 12 +++- 2 files changed, 136 insertions(+), 5 deletions(-) diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index 686a3903ee0..aa75d72e7c7 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -51,6 +51,9 @@ TwoWire::TwoWire(uint8_t bus_num) ,is_slave(false) ,user_onRequest(NULL) ,user_onReceive(NULL) + ,txBuffer(NULL) + ,rxBuffer(NULL) + ,BufferSize(I2C_BUFFER_LENGTH) // default Wire Buffer Size {} TwoWire::~TwoWire() @@ -132,6 +135,81 @@ bool TwoWire::setPins(int sdaPin, int sclPin) return !i2cIsInit(num); } +bool TwoWire::allocateWireBuffer(void) +{ + // or both buffer can be allocated or none will be + if (rxBuffer == NULL) { + rxBuffer = (uint8_t *)malloc(BufferSize); + if (rxBuffer == NULL) { + log_e("Can't allocate memory for I2C_%d rxBuffer", num); + return false; + } + } + if (txBuffer == NULL) { + txBuffer = (uint8_t *)malloc(BufferSize); + if (txBuffer == NULL) { + log_e("Can't allocate memory for I2C_%d txBuffer", num); + freeWireBuffer(); // free rxBuffer for safety! + return false; + } + } + // in case both were allocated before, they must have the same size. All good. + return true; +} + +void TwoWire::freeWireBuffer(void) +{ + if (rxBuffer != NULL) { + free(rxBuffer); + rxBuffer = NULL; + } + if (txBuffer != NULL) { + free(txBuffer); + txBuffer = NULL; + } +} + +size_t TwoWire::setBufferSize(size_t bSize) +{ + // Maximum size .... HEAP limited ;-) + if (bSize < 32) { // 32 bytes is the I2C FIFO Len for ESP32/S2/S3/C3 + log_e("Minimum Wire Buffer size is 32 bytes"); + return 0; + } + +#if !CONFIG_DISABLE_HAL_LOCKS + if(lock != NULL){ + //acquire lock + if(xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE){ + log_e("could not acquire lock"); + return 0; + } +#endif + // allocateWireBuffer allocates memory for both pointers or just free them + if (rxBuffer != NULL || txBuffer != NULL) { + // if begin() has been already executed, memory size changes... data may be lost. We don't care! :^) + if (bSize != BufferSize) { + // we want a new buffer size ... just reset buffer pointers and allocate new ones + freeWireBuffer(); + BufferSize = bSize; + if (!allocateWireBuffer()) { + // failed! Error message already issued + bSize = 0; // returns error + } + } // else nothing changes, all set! + } else { + // no memory allocated yet, just change the size value - allocation in begin() + BufferSize = bSize; + } +#if !CONFIG_DISABLE_HAL_LOCKS + //release lock + xSemaphoreGive(lock); + } +#endif + return bSize; +} + + // Slave Begin bool TwoWire::begin(uint8_t addr, int sdaPin, int sclPin, uint32_t frequency) { @@ -159,11 +237,15 @@ bool TwoWire::begin(uint8_t addr, int sdaPin, int sclPin, uint32_t frequency) log_e("Bus already started in Master Mode."); goto end; } + if (!allocateWireBuffer()) { + // failed! Error Message already issued + goto end; + } if(!initPins(sdaPin, sclPin)){ goto end; } i2cSlaveAttachCallbacks(num, onRequestService, onReceiveService, this); - if(i2cSlaveInit(num, sda, scl, addr, frequency, I2C_BUFFER_LENGTH, I2C_BUFFER_LENGTH) != ESP_OK){ + if(i2cSlaveInit(num, sda, scl, addr, frequency, BufferSize, BufferSize) != ESP_OK){ log_e("Slave Init ERROR"); goto end; } @@ -205,6 +287,10 @@ bool TwoWire::begin(int sdaPin, int sclPin, uint32_t frequency) started = true; goto end; } + if (!allocateWireBuffer()) { + // failed! Error Message already issued + goto end; + } if(!initPins(sdaPin, sclPin)){ goto end; } @@ -239,6 +325,7 @@ bool TwoWire::end() } else if(i2cIsInit(num)){ err = i2cDeinit(num); } + freeWireBuffer(); #if !CONFIG_DISABLE_HAL_LOCKS //release lock xSemaphoreGive(lock); @@ -325,12 +412,26 @@ void TwoWire::beginTransmission(uint16_t address) txLength = 0; } +/* +https://www.arduino.cc/reference/en/language/functions/communication/wire/endtransmission/ +endTransmission() returns: +0: success. +1: data too long to fit in transmit buffer. +2: received NACK on transmit of address. +3: received NACK on transmit of data. +4: other error. +5: timeout +*/ uint8_t TwoWire::endTransmission(bool sendStop) { if(is_slave){ log_e("Bus is in Slave Mode"); return 4; } + if (txBuffer == NULL){ + log_e("NULL TX buffer pointer"); + return 4; + } esp_err_t err = ESP_OK; if(sendStop){ err = i2cWrite(num, txAddress, txBuffer, txLength, _timeOutMillis); @@ -360,6 +461,10 @@ size_t TwoWire::requestFrom(uint16_t address, size_t size, bool sendStop) log_e("Bus is in Slave Mode"); return 0; } + if (rxBuffer == NULL || txBuffer == NULL){ + log_e("NULL buffer pointer"); + return 0; + } esp_err_t err = ESP_OK; if(nonStop #if !CONFIG_DISABLE_HAL_LOCKS @@ -401,7 +506,11 @@ size_t TwoWire::requestFrom(uint16_t address, size_t size, bool sendStop) size_t TwoWire::write(uint8_t data) { - if(txLength >= I2C_BUFFER_LENGTH) { + if (txBuffer == NULL){ + log_e("NULL TX buffer pointer"); + return 0; + } + if(txLength >= BufferSize) { return 0; } txBuffer[txLength++] = data; @@ -428,6 +537,10 @@ int TwoWire::available(void) int TwoWire::read(void) { int value = -1; + if (rxBuffer == NULL){ + log_e("NULL RX buffer pointer"); + return value; + } if(rxIndex < rxLength) { value = rxBuffer[rxIndex++]; } @@ -437,6 +550,10 @@ int TwoWire::read(void) int TwoWire::peek(void) { int value = -1; + if (rxBuffer == NULL){ + log_e("NULL RX buffer pointer"); + return value; + } if(rxIndex < rxLength) { value = rxBuffer[rxIndex]; } @@ -520,6 +637,10 @@ void TwoWire::onReceiveService(uint8_t num, uint8_t* inBytes, size_t numBytes, b if(!wire->user_onReceive){ return; } + if (wire->rxBuffer == NULL){ + log_e("NULL RX buffer pointer"); + return; + } for(uint8_t i = 0; i < numBytes; ++i){ wire->rxBuffer[i] = inBytes[i]; } @@ -534,6 +655,10 @@ void TwoWire::onRequestService(uint8_t num, void * arg) if(!wire->user_onRequest){ return; } + if (wire->txBuffer == NULL){ + log_e("NULL TX buffer pointer"); + return; + } wire->txLength = 0; wire->user_onRequest(); if(wire->txLength){ diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index ca048bb16c4..1444185fce3 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -34,8 +34,9 @@ #endif #include "Stream.h" +#define WIRE_HAS_BUFFER_SIZE 1 #ifndef I2C_BUFFER_LENGTH - #define I2C_BUFFER_LENGTH 128 + #define I2C_BUFFER_LENGTH 128 // Default size, if none is set using Wire::setBuffersize(size_t) #endif typedef void(*user_onRequest)(void); typedef void(*user_onReceive)(uint8_t*, int); @@ -47,11 +48,12 @@ class TwoWire: public Stream int8_t sda; int8_t scl; - uint8_t rxBuffer[I2C_BUFFER_LENGTH]; + size_t BufferSize; + uint8_t *rxBuffer; size_t rxIndex; size_t rxLength; - uint8_t txBuffer[I2C_BUFFER_LENGTH]; + uint8_t *txBuffer; size_t txLength; uint16_t txAddress; @@ -68,6 +70,8 @@ class TwoWire: public Stream static void onRequestService(uint8_t, void *); static void onReceiveService(uint8_t, uint8_t*, size_t, bool, void *); bool initPins(int sdaPin, int sclPin); + bool allocateWireBuffer(void); + void freeWireBuffer(void); public: TwoWire(uint8_t bus_num); @@ -80,6 +84,8 @@ class TwoWire: public Stream bool begin(uint8_t slaveAddr, int sda=-1, int scl=-1, uint32_t frequency=0); bool end(); + size_t setBufferSize(size_t bSize); + void setTimeOut(uint16_t timeOutMillis); // default timeout of i2c transactions is 50ms uint16_t getTimeOut(); From 5dad75326317c2d6c0c03482f1f45050962c16d6 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 20 Jul 2022 12:31:17 -0300 Subject: [PATCH 02/10] fixed reorder compiling error --- libraries/Wire/src/Wire.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index aa75d72e7c7..e0e3be925da 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -38,8 +38,11 @@ TwoWire::TwoWire(uint8_t bus_num) :num(bus_num & 1) ,sda(-1) ,scl(-1) + ,BufferSize(I2C_BUFFER_LENGTH) // default Wire Buffer Size + ,rxBuffer(NULL) ,rxIndex(0) ,rxLength(0) + ,txBuffer(NULL) ,txLength(0) ,txAddress(0) ,_timeOutMillis(50) @@ -51,9 +54,6 @@ TwoWire::TwoWire(uint8_t bus_num) ,is_slave(false) ,user_onRequest(NULL) ,user_onReceive(NULL) - ,txBuffer(NULL) - ,rxBuffer(NULL) - ,BufferSize(I2C_BUFFER_LENGTH) // default Wire Buffer Size {} TwoWire::~TwoWire() From e421a299d6aed41f29adda888f2d1e7a2744fc83 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Tue, 26 Jul 2022 22:10:59 -0300 Subject: [PATCH 03/10] free buffers in case of error in begin() fixes begin() in case of error --- libraries/Wire/src/Wire.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index e0e3be925da..367260bebd8 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -298,6 +298,7 @@ bool TwoWire::begin(int sdaPin, int sclPin, uint32_t frequency) started = (err == ESP_OK); end: + freeWireBuffer(); #if !CONFIG_DISABLE_HAL_LOCKS //release lock xSemaphoreGive(lock); From 2ae4a8af5c4337cfc6495e38c495b5927fd88e55 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Tue, 26 Jul 2022 22:16:50 -0300 Subject: [PATCH 04/10] way to let the application about functionality Adds some `defines` that let the application know what fucntionalitites are avilable in Wire and make it more portable among different platforms --- libraries/Wire/src/Wire.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index 103f9b2460c..95517586543 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -34,7 +34,11 @@ #endif #include "Stream.h" +// WIRE_HAS_BUFFER_SIZE means Wire has setBufferSize() #define WIRE_HAS_BUFFER_SIZE 1 +// WIRE_HAS_END means Wire has end() +#define WIRE_HAS_END 1 + #ifndef I2C_BUFFER_LENGTH #define I2C_BUFFER_LENGTH 128 // Default size, if none is set using Wire::setBuffersize(size_t) #endif From 771b26c884bdacaa453da828722f2aed8af66177 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Tue, 26 Jul 2022 22:20:28 -0300 Subject: [PATCH 05/10] Adds freeBuffer() to Slave --- libraries/Wire/src/Wire.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index 367260bebd8..e2a80743762 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -252,6 +252,7 @@ bool TwoWire::begin(uint8_t addr, int sdaPin, int sclPin, uint32_t frequency) is_slave = true; started = true; end: + freeWireBuffer(); #if !CONFIG_DISABLE_HAL_LOCKS //release lock xSemaphoreGive(lock); From d72322e9492b6bcd4a982d99d20296eb12b8830d Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 27 Jul 2022 06:53:42 -0300 Subject: [PATCH 06/10] Update for review --- libraries/Wire/src/Wire.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index e2a80743762..7c804aa5b76 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -38,7 +38,7 @@ TwoWire::TwoWire(uint8_t bus_num) :num(bus_num & 1) ,sda(-1) ,scl(-1) - ,BufferSize(I2C_BUFFER_LENGTH) // default Wire Buffer Size + ,bufferSize(I2C_BUFFER_LENGTH) // default Wire Buffer Size ,rxBuffer(NULL) ,rxIndex(0) ,rxLength(0) @@ -139,14 +139,14 @@ bool TwoWire::allocateWireBuffer(void) { // or both buffer can be allocated or none will be if (rxBuffer == NULL) { - rxBuffer = (uint8_t *)malloc(BufferSize); + rxBuffer = (uint8_t *)malloc(bufferSize); if (rxBuffer == NULL) { log_e("Can't allocate memory for I2C_%d rxBuffer", num); return false; } } if (txBuffer == NULL) { - txBuffer = (uint8_t *)malloc(BufferSize); + txBuffer = (uint8_t *)malloc(bufferSize); if (txBuffer == NULL) { log_e("Can't allocate memory for I2C_%d txBuffer", num); freeWireBuffer(); // free rxBuffer for safety! @@ -176,7 +176,7 @@ size_t TwoWire::setBufferSize(size_t bSize) log_e("Minimum Wire Buffer size is 32 bytes"); return 0; } - + #if !CONFIG_DISABLE_HAL_LOCKS if(lock != NULL){ //acquire lock @@ -188,10 +188,10 @@ size_t TwoWire::setBufferSize(size_t bSize) // allocateWireBuffer allocates memory for both pointers or just free them if (rxBuffer != NULL || txBuffer != NULL) { // if begin() has been already executed, memory size changes... data may be lost. We don't care! :^) - if (bSize != BufferSize) { + if (bSize != bufferSize) { // we want a new buffer size ... just reset buffer pointers and allocate new ones freeWireBuffer(); - BufferSize = bSize; + bufferSize = bSize; if (!allocateWireBuffer()) { // failed! Error message already issued bSize = 0; // returns error @@ -199,12 +199,15 @@ size_t TwoWire::setBufferSize(size_t bSize) } // else nothing changes, all set! } else { // no memory allocated yet, just change the size value - allocation in begin() - BufferSize = bSize; + bufferSize = bSize; } #if !CONFIG_DISABLE_HAL_LOCKS //release lock xSemaphoreGive(lock); - } + } else { // lock != NULL + // if lock is NULL, no begin() was executed, then just set the buffer size for future memory allocation + bufferSize = bSize; + } #endif return bSize; } @@ -245,14 +248,14 @@ bool TwoWire::begin(uint8_t addr, int sdaPin, int sclPin, uint32_t frequency) goto end; } i2cSlaveAttachCallbacks(num, onRequestService, onReceiveService, this); - if(i2cSlaveInit(num, sda, scl, addr, frequency, BufferSize, BufferSize) != ESP_OK){ + if(i2cSlaveInit(num, sda, scl, addr, frequency, bufferSize, bufferSize) != ESP_OK){ log_e("Slave Init ERROR"); goto end; } is_slave = true; started = true; end: - freeWireBuffer(); + if (!started) freeWireBuffer(); #if !CONFIG_DISABLE_HAL_LOCKS //release lock xSemaphoreGive(lock); @@ -299,7 +302,7 @@ bool TwoWire::begin(int sdaPin, int sclPin, uint32_t frequency) started = (err == ESP_OK); end: - freeWireBuffer(); + if (!started) freeWireBuffer(); #if !CONFIG_DISABLE_HAL_LOCKS //release lock xSemaphoreGive(lock); @@ -512,7 +515,7 @@ size_t TwoWire::write(uint8_t data) log_e("NULL TX buffer pointer"); return 0; } - if(txLength >= BufferSize) { + if(txLength >= bufferSize) { return 0; } txBuffer[txLength++] = data; From 1ef43ebcb6ddfdb64d1b2d0e201d2eb10a1066c5 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 27 Jul 2022 06:57:45 -0300 Subject: [PATCH 07/10] fixes BufferSize -> bufferSize --- libraries/Wire/src/Wire.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index 95517586543..339b0e2866f 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -52,7 +52,7 @@ class TwoWire: public Stream int8_t sda; int8_t scl; - size_t BufferSize; + size_t bufferSize; uint8_t *rxBuffer; size_t rxIndex; size_t rxLength; From d92a92bab0d724e1954a54ffc821b05e17da978a Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 27 Jul 2022 10:15:01 -0300 Subject: [PATCH 08/10] adds lock ceation in setBufferSize() --- libraries/Wire/src/Wire.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index 7c804aa5b76..270e6dbf80c 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -176,43 +176,46 @@ size_t TwoWire::setBufferSize(size_t bSize) log_e("Minimum Wire Buffer size is 32 bytes"); return 0; } - + #if !CONFIG_DISABLE_HAL_LOCKS - if(lock != NULL){ + if(lock == NULL){ + lock = xSemaphoreCreateMutex(); + if(lock == NULL){ + log_e("xSemaphoreCreateMutex failed"); + return false; + } //acquire lock if(xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE){ log_e("could not acquire lock"); return 0; } + } #endif // allocateWireBuffer allocates memory for both pointers or just free them if (rxBuffer != NULL || txBuffer != NULL) { // if begin() has been already executed, memory size changes... data may be lost. We don't care! :^) - if (bSize != bufferSize) { + if (bSize != BufferSize) { // we want a new buffer size ... just reset buffer pointers and allocate new ones freeWireBuffer(); - bufferSize = bSize; + BufferSize = bSize; if (!allocateWireBuffer()) { // failed! Error message already issued bSize = 0; // returns error + log_e("Buffer allocation failed"); } } // else nothing changes, all set! } else { // no memory allocated yet, just change the size value - allocation in begin() - bufferSize = bSize; + BufferSize = bSize; } #if !CONFIG_DISABLE_HAL_LOCKS - //release lock - xSemaphoreGive(lock); - } else { // lock != NULL - // if lock is NULL, no begin() was executed, then just set the buffer size for future memory allocation - bufferSize = bSize; - } + //release lock + xSemaphoreGive(lock); + #endif return bSize; } - // Slave Begin bool TwoWire::begin(uint8_t addr, int sdaPin, int sclPin, uint32_t frequency) { From c2b0657d3a2465921589cd060f9e333ae9e7b229 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 27 Jul 2022 10:24:06 -0300 Subject: [PATCH 09/10] Fixes setBufferSize() lock code --- libraries/Wire/src/Wire.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index 270e6dbf80c..da1b113ffcd 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -182,14 +182,14 @@ size_t TwoWire::setBufferSize(size_t bSize) lock = xSemaphoreCreateMutex(); if(lock == NULL){ log_e("xSemaphoreCreateMutex failed"); - return false; - } - //acquire lock - if(xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE){ - log_e("could not acquire lock"); return 0; } } + //acquire lock + if(xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE){ + log_e("could not acquire lock"); + return 0; + } #endif // allocateWireBuffer allocates memory for both pointers or just free them if (rxBuffer != NULL || txBuffer != NULL) { From 15038c10517d606a6c9ad50d951638e91fdbd080 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 27 Jul 2022 10:34:41 -0300 Subject: [PATCH 10/10] changes BufferSize vs bufferSize --- libraries/Wire/src/Wire.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index da1b113ffcd..0bab0fd58fe 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -194,10 +194,10 @@ size_t TwoWire::setBufferSize(size_t bSize) // allocateWireBuffer allocates memory for both pointers or just free them if (rxBuffer != NULL || txBuffer != NULL) { // if begin() has been already executed, memory size changes... data may be lost. We don't care! :^) - if (bSize != BufferSize) { + if (bSize != bufferSize) { // we want a new buffer size ... just reset buffer pointers and allocate new ones freeWireBuffer(); - BufferSize = bSize; + bufferSize = bSize; if (!allocateWireBuffer()) { // failed! Error message already issued bSize = 0; // returns error @@ -206,7 +206,7 @@ size_t TwoWire::setBufferSize(size_t bSize) } // else nothing changes, all set! } else { // no memory allocated yet, just change the size value - allocation in begin() - BufferSize = bSize; + bufferSize = bSize; } #if !CONFIG_DISABLE_HAL_LOCKS //release lock