Skip to content

Commit 9bceb28

Browse files
authored
Adds Wire::setBufferSize function (#7016)
1 parent 178aee8 commit 9bceb28

File tree

2 files changed

+148
-5
lines changed

2 files changed

+148
-5
lines changed

Diff for: libraries/Wire/src/Wire.cpp

+135-2
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,11 @@ TwoWire::TwoWire(uint8_t bus_num)
3838
:num(bus_num & 1)
3939
,sda(-1)
4040
,scl(-1)
41+
,bufferSize(I2C_BUFFER_LENGTH) // default Wire Buffer Size
42+
,rxBuffer(NULL)
4143
,rxIndex(0)
4244
,rxLength(0)
45+
,txBuffer(NULL)
4346
,txLength(0)
4447
,txAddress(0)
4548
,_timeOutMillis(50)
@@ -132,6 +135,87 @@ bool TwoWire::setPins(int sdaPin, int sclPin)
132135
return !i2cIsInit(num);
133136
}
134137

138+
bool TwoWire::allocateWireBuffer(void)
139+
{
140+
// or both buffer can be allocated or none will be
141+
if (rxBuffer == NULL) {
142+
rxBuffer = (uint8_t *)malloc(bufferSize);
143+
if (rxBuffer == NULL) {
144+
log_e("Can't allocate memory for I2C_%d rxBuffer", num);
145+
return false;
146+
}
147+
}
148+
if (txBuffer == NULL) {
149+
txBuffer = (uint8_t *)malloc(bufferSize);
150+
if (txBuffer == NULL) {
151+
log_e("Can't allocate memory for I2C_%d txBuffer", num);
152+
freeWireBuffer(); // free rxBuffer for safety!
153+
return false;
154+
}
155+
}
156+
// in case both were allocated before, they must have the same size. All good.
157+
return true;
158+
}
159+
160+
void TwoWire::freeWireBuffer(void)
161+
{
162+
if (rxBuffer != NULL) {
163+
free(rxBuffer);
164+
rxBuffer = NULL;
165+
}
166+
if (txBuffer != NULL) {
167+
free(txBuffer);
168+
txBuffer = NULL;
169+
}
170+
}
171+
172+
size_t TwoWire::setBufferSize(size_t bSize)
173+
{
174+
// Maximum size .... HEAP limited ;-)
175+
if (bSize < 32) { // 32 bytes is the I2C FIFO Len for ESP32/S2/S3/C3
176+
log_e("Minimum Wire Buffer size is 32 bytes");
177+
return 0;
178+
}
179+
180+
#if !CONFIG_DISABLE_HAL_LOCKS
181+
if(lock == NULL){
182+
lock = xSemaphoreCreateMutex();
183+
if(lock == NULL){
184+
log_e("xSemaphoreCreateMutex failed");
185+
return 0;
186+
}
187+
}
188+
//acquire lock
189+
if(xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE){
190+
log_e("could not acquire lock");
191+
return 0;
192+
}
193+
#endif
194+
// allocateWireBuffer allocates memory for both pointers or just free them
195+
if (rxBuffer != NULL || txBuffer != NULL) {
196+
// if begin() has been already executed, memory size changes... data may be lost. We don't care! :^)
197+
if (bSize != bufferSize) {
198+
// we want a new buffer size ... just reset buffer pointers and allocate new ones
199+
freeWireBuffer();
200+
bufferSize = bSize;
201+
if (!allocateWireBuffer()) {
202+
// failed! Error message already issued
203+
bSize = 0; // returns error
204+
log_e("Buffer allocation failed");
205+
}
206+
} // else nothing changes, all set!
207+
} else {
208+
// no memory allocated yet, just change the size value - allocation in begin()
209+
bufferSize = bSize;
210+
}
211+
#if !CONFIG_DISABLE_HAL_LOCKS
212+
//release lock
213+
xSemaphoreGive(lock);
214+
215+
#endif
216+
return bSize;
217+
}
218+
135219
// Slave Begin
136220
bool TwoWire::begin(uint8_t addr, int sdaPin, int sclPin, uint32_t frequency)
137221
{
@@ -159,17 +243,22 @@ bool TwoWire::begin(uint8_t addr, int sdaPin, int sclPin, uint32_t frequency)
159243
log_e("Bus already started in Master Mode.");
160244
goto end;
161245
}
246+
if (!allocateWireBuffer()) {
247+
// failed! Error Message already issued
248+
goto end;
249+
}
162250
if(!initPins(sdaPin, sclPin)){
163251
goto end;
164252
}
165253
i2cSlaveAttachCallbacks(num, onRequestService, onReceiveService, this);
166-
if(i2cSlaveInit(num, sda, scl, addr, frequency, I2C_BUFFER_LENGTH, I2C_BUFFER_LENGTH) != ESP_OK){
254+
if(i2cSlaveInit(num, sda, scl, addr, frequency, bufferSize, bufferSize) != ESP_OK){
167255
log_e("Slave Init ERROR");
168256
goto end;
169257
}
170258
is_slave = true;
171259
started = true;
172260
end:
261+
if (!started) freeWireBuffer();
173262
#if !CONFIG_DISABLE_HAL_LOCKS
174263
//release lock
175264
xSemaphoreGive(lock);
@@ -205,13 +294,18 @@ bool TwoWire::begin(int sdaPin, int sclPin, uint32_t frequency)
205294
started = true;
206295
goto end;
207296
}
297+
if (!allocateWireBuffer()) {
298+
// failed! Error Message already issued
299+
goto end;
300+
}
208301
if(!initPins(sdaPin, sclPin)){
209302
goto end;
210303
}
211304
err = i2cInit(num, sda, scl, frequency);
212305
started = (err == ESP_OK);
213306

214307
end:
308+
if (!started) freeWireBuffer();
215309
#if !CONFIG_DISABLE_HAL_LOCKS
216310
//release lock
217311
xSemaphoreGive(lock);
@@ -239,6 +333,7 @@ bool TwoWire::end()
239333
} else if(i2cIsInit(num)){
240334
err = i2cDeinit(num);
241335
}
336+
freeWireBuffer();
242337
#if !CONFIG_DISABLE_HAL_LOCKS
243338
//release lock
244339
xSemaphoreGive(lock);
@@ -325,12 +420,26 @@ void TwoWire::beginTransmission(uint16_t address)
325420
txLength = 0;
326421
}
327422

423+
/*
424+
https://www.arduino.cc/reference/en/language/functions/communication/wire/endtransmission/
425+
endTransmission() returns:
426+
0: success.
427+
1: data too long to fit in transmit buffer.
428+
2: received NACK on transmit of address.
429+
3: received NACK on transmit of data.
430+
4: other error.
431+
5: timeout
432+
*/
328433
uint8_t TwoWire::endTransmission(bool sendStop)
329434
{
330435
if(is_slave){
331436
log_e("Bus is in Slave Mode");
332437
return 4;
333438
}
439+
if (txBuffer == NULL){
440+
log_e("NULL TX buffer pointer");
441+
return 4;
442+
}
334443
esp_err_t err = ESP_OK;
335444
if(sendStop){
336445
err = i2cWrite(num, txAddress, txBuffer, txLength, _timeOutMillis);
@@ -360,6 +469,10 @@ size_t TwoWire::requestFrom(uint16_t address, size_t size, bool sendStop)
360469
log_e("Bus is in Slave Mode");
361470
return 0;
362471
}
472+
if (rxBuffer == NULL || txBuffer == NULL){
473+
log_e("NULL buffer pointer");
474+
return 0;
475+
}
363476
esp_err_t err = ESP_OK;
364477
if(nonStop
365478
#if !CONFIG_DISABLE_HAL_LOCKS
@@ -401,7 +514,11 @@ size_t TwoWire::requestFrom(uint16_t address, size_t size, bool sendStop)
401514

402515
size_t TwoWire::write(uint8_t data)
403516
{
404-
if(txLength >= I2C_BUFFER_LENGTH) {
517+
if (txBuffer == NULL){
518+
log_e("NULL TX buffer pointer");
519+
return 0;
520+
}
521+
if(txLength >= bufferSize) {
405522
return 0;
406523
}
407524
txBuffer[txLength++] = data;
@@ -428,6 +545,10 @@ int TwoWire::available(void)
428545
int TwoWire::read(void)
429546
{
430547
int value = -1;
548+
if (rxBuffer == NULL){
549+
log_e("NULL RX buffer pointer");
550+
return value;
551+
}
431552
if(rxIndex < rxLength) {
432553
value = rxBuffer[rxIndex++];
433554
}
@@ -437,6 +558,10 @@ int TwoWire::read(void)
437558
int TwoWire::peek(void)
438559
{
439560
int value = -1;
561+
if (rxBuffer == NULL){
562+
log_e("NULL RX buffer pointer");
563+
return value;
564+
}
440565
if(rxIndex < rxLength) {
441566
value = rxBuffer[rxIndex];
442567
}
@@ -520,6 +645,10 @@ void TwoWire::onReceiveService(uint8_t num, uint8_t* inBytes, size_t numBytes, b
520645
if(!wire->user_onReceive){
521646
return;
522647
}
648+
if (wire->rxBuffer == NULL){
649+
log_e("NULL RX buffer pointer");
650+
return;
651+
}
523652
for(uint8_t i = 0; i < numBytes; ++i){
524653
wire->rxBuffer[i] = inBytes[i];
525654
}
@@ -534,6 +663,10 @@ void TwoWire::onRequestService(uint8_t num, void * arg)
534663
if(!wire->user_onRequest){
535664
return;
536665
}
666+
if (wire->txBuffer == NULL){
667+
log_e("NULL TX buffer pointer");
668+
return;
669+
}
537670
wire->txLength = 0;
538671
wire->user_onRequest();
539672
if(wire->txLength){

Diff for: libraries/Wire/src/Wire.h

+13-3
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,13 @@
3434
#endif
3535
#include "Stream.h"
3636

37+
// WIRE_HAS_BUFFER_SIZE means Wire has setBufferSize()
38+
#define WIRE_HAS_BUFFER_SIZE 1
39+
// WIRE_HAS_END means Wire has end()
40+
#define WIRE_HAS_END 1
41+
3742
#ifndef I2C_BUFFER_LENGTH
38-
#define I2C_BUFFER_LENGTH 128
43+
#define I2C_BUFFER_LENGTH 128 // Default size, if none is set using Wire::setBuffersize(size_t)
3944
#endif
4045
typedef void(*user_onRequest)(void);
4146
typedef void(*user_onReceive)(uint8_t*, int);
@@ -47,11 +52,12 @@ class TwoWire: public Stream
4752
int8_t sda;
4853
int8_t scl;
4954

50-
uint8_t rxBuffer[I2C_BUFFER_LENGTH];
55+
size_t bufferSize;
56+
uint8_t *rxBuffer;
5157
size_t rxIndex;
5258
size_t rxLength;
5359

54-
uint8_t txBuffer[I2C_BUFFER_LENGTH];
60+
uint8_t *txBuffer;
5561
size_t txLength;
5662
uint16_t txAddress;
5763

@@ -68,6 +74,8 @@ class TwoWire: public Stream
6874
static void onRequestService(uint8_t, void *);
6975
static void onReceiveService(uint8_t, uint8_t*, size_t, bool, void *);
7076
bool initPins(int sdaPin, int sclPin);
77+
bool allocateWireBuffer(void);
78+
void freeWireBuffer(void);
7179

7280
public:
7381
TwoWire(uint8_t bus_num);
@@ -93,6 +101,8 @@ class TwoWire: public Stream
93101
}
94102
bool end();
95103

104+
size_t setBufferSize(size_t bSize);
105+
96106
void setTimeOut(uint16_t timeOutMillis); // default timeout of i2c transactions is 50ms
97107
uint16_t getTimeOut();
98108

0 commit comments

Comments
 (0)