Skip to content

Commit 7ae74e4

Browse files
authored
Merge pull request #1562
Wire: Max TX buffer length
2 parents d51d562 + 2e73fd2 commit 7ae74e4

File tree

2 files changed

+60
-73
lines changed

2 files changed

+60
-73
lines changed

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

+48-66
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,7 @@ void TwoWire::begin(uint8_t address, bool generalCall)
6767
rxBufferAllocated = 0;
6868
resetRxBuffer();
6969

70-
txBufferIndex = 0;
71-
txBufferLength = 0;
70+
txDataSize = 0;
7271
txAddress = 0;
7372
txBuffer = nullptr;
7473
txBufferAllocated = 0;
@@ -125,48 +124,43 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres
125124

126125
if (_i2c.isMaster == 1) {
127126
allocateRxBuffer(quantity);
128-
// error if no memory block available to allocate the buffer
129-
if (rxBuffer == nullptr) {
130-
setWriteError();
131-
} else {
132127

133-
if (isize > 0) {
134-
// send internal address; this mode allows sending a repeated start to access
135-
// some devices' internal registers. This function is executed by the hardware
136-
// TWI module on other processors (for example Due's TWI_IADR and TWI_MMR registers)
128+
if (isize > 0) {
129+
// send internal address; this mode allows sending a repeated start to access
130+
// some devices' internal registers. This function is executed by the hardware
131+
// TWI module on other processors (for example Due's TWI_IADR and TWI_MMR registers)
137132

138-
beginTransmission(address);
133+
beginTransmission(address);
139134

140-
// the maximum size of internal address is 3 bytes
141-
if (isize > 3) {
142-
isize = 3;
143-
}
135+
// the maximum size of internal address is 3 bytes
136+
if (isize > 3) {
137+
isize = 3;
138+
}
144139

145-
// write internal register address - most significant byte first
146-
while (isize-- > 0) {
147-
write((uint8_t)(iaddress >> (isize * 8)));
148-
}
149-
endTransmission(false);
140+
// write internal register address - most significant byte first
141+
while (isize-- > 0) {
142+
write((uint8_t)(iaddress >> (isize * 8)));
150143
}
144+
endTransmission(false);
145+
}
151146

152-
// perform blocking read into buffer
147+
// perform blocking read into buffer
153148
#if defined(I2C_OTHER_FRAME)
154-
if (sendStop == 0) {
155-
_i2c.handle.XferOptions = I2C_OTHER_FRAME ;
156-
} else {
157-
_i2c.handle.XferOptions = I2C_OTHER_AND_LAST_FRAME;
158-
}
149+
if (sendStop == 0) {
150+
_i2c.handle.XferOptions = I2C_OTHER_FRAME ;
151+
} else {
152+
_i2c.handle.XferOptions = I2C_OTHER_AND_LAST_FRAME;
153+
}
159154
#endif
160155

161-
if (I2C_OK == i2c_master_read(&_i2c, address << 1, rxBuffer, quantity)) {
162-
read = quantity;
163-
}
156+
if (I2C_OK == i2c_master_read(&_i2c, address << 1, rxBuffer, quantity)) {
157+
read = quantity;
158+
}
164159

165-
// set rx buffer iterator vars
166-
rxBufferIndex = 0;
167-
rxBufferLength = read;
160+
// set rx buffer iterator vars
161+
rxBufferIndex = 0;
162+
rxBufferLength = read;
168163

169-
}
170164
}
171165
return read;
172166
}
@@ -202,9 +196,8 @@ void TwoWire::beginTransmission(uint8_t address)
202196
transmitting = 1;
203197
// set address of targeted slave
204198
txAddress = address << 1;
205-
// reset tx buffer iterator vars
206-
txBufferIndex = 0;
207-
txBufferLength = 0;
199+
// reset tx data size
200+
txDataSize = 0;
208201
}
209202

210203
void TwoWire::beginTransmission(int address)
@@ -242,7 +235,7 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop)
242235

243236
if (_i2c.isMaster == 1) {
244237
// transmit buffer (blocking)
245-
switch (i2c_master_write(&_i2c, txAddress, txBuffer, txBufferLength)) {
238+
switch (i2c_master_write(&_i2c, txAddress, txBuffer, txDataSize)) {
246239
case I2C_OK :
247240
ret = 0; // Success
248241
break;
@@ -266,9 +259,8 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop)
266259
// reset Tx buffer
267260
resetTxBuffer();
268261

269-
// reset tx buffer iterator vars
270-
txBufferIndex = 0;
271-
txBufferLength = 0;
262+
// reset tx buffer data size
263+
txDataSize = 0;
272264

273265
// indicate that we are done transmitting
274266
transmitting = 0;
@@ -292,17 +284,13 @@ size_t TwoWire::write(uint8_t data)
292284
size_t ret = 1;
293285
if (transmitting) {
294286
// in master transmitter mode
295-
allocateTxBuffer(txBufferLength + 1);
296-
// error if no memory block available to allocate the buffer
297-
if (txBuffer == nullptr) {
298-
setWriteError();
287+
if (allocateTxBuffer(txDataSize + 1) == 0) {
299288
ret = 0;
300289
} else {
301290
// put byte in tx buffer
302-
txBuffer[txBufferIndex] = data;
303-
++txBufferIndex;
291+
txBuffer[txDataSize] = data;
304292
// update amount in buffer
305-
txBufferLength = txBufferIndex;
293+
txDataSize++;
306294
}
307295
} else {
308296
// in slave send mode
@@ -327,17 +315,14 @@ size_t TwoWire::write(const uint8_t *data, size_t quantity)
327315

328316
if (transmitting) {
329317
// in master transmitter mode
330-
allocateTxBuffer(txBufferLength + quantity);
331-
// error if no memory block available to allocate the buffer
332-
if (txBuffer == nullptr) {
333-
setWriteError();
318+
if (allocateTxBuffer(txDataSize + quantity) == 0) {
334319
ret = 0;
335320
} else {
336321
// put bytes in tx buffer
337-
memcpy(&(txBuffer[txBufferIndex]), data, quantity);
338-
txBufferIndex = txBufferIndex + quantity;
322+
memcpy(&(txBuffer[txDataSize]), data, quantity);
323+
339324
// update amount in buffer
340-
txBufferLength = txBufferIndex;
325+
txDataSize += quantity;
341326
}
342327
} else {
343328
// in slave send mode
@@ -397,8 +382,7 @@ void TwoWire::flush(void)
397382
rxBufferIndex = 0;
398383
rxBufferLength = 0;
399384
resetRxBuffer();
400-
txBufferIndex = 0;
401-
txBufferLength = 0;
385+
txDataSize = 0;
402386
resetTxBuffer();
403387
}
404388

@@ -416,12 +400,7 @@ void TwoWire::onReceiveService(i2c_t *obj)
416400
// i know this drops data, but it allows for slight stupidity
417401
// meaning, they may not have read all the master requestFrom() data yet
418402
if (TW->rxBufferIndex >= TW->rxBufferLength) {
419-
420403
TW->allocateRxBuffer(numBytes);
421-
// error if no memory block available to allocate the buffer
422-
if (TW->rxBuffer == nullptr) {
423-
Error_Handler();
424-
}
425404

426405
// copy twi rx buffer into local read buffer
427406
// this enables new reads to happen in parallel
@@ -442,10 +421,9 @@ void TwoWire::onRequestService(i2c_t *obj)
442421

443422
// don't bother if user hasn't registered a callback
444423
if (TW->user_onRequest) {
445-
// reset tx buffer iterator vars
424+
// reset tx data size
446425
// !!! this will kill any pending pre-master sendTo() activity
447-
TW->txBufferIndex = 0;
448-
TW->txBufferLength = 0;
426+
TW->txDataSize = 0;
449427
// alert user program
450428
TW->user_onRequest();
451429
}
@@ -485,9 +463,12 @@ void TwoWire::allocateRxBuffer(size_t length)
485463
}
486464
}
487465

488-
inline void TwoWire::allocateTxBuffer(size_t length)
466+
inline size_t TwoWire::allocateTxBuffer(size_t length)
489467
{
490-
if (txBufferAllocated < length) {
468+
size_t ret = length;
469+
if (length > WIRE_MAX_TX_BUFF_LENGTH) {
470+
ret = 0;
471+
} else if (txBufferAllocated < length) {
491472
// By default we allocate BUFFER_LENGTH bytes. It is the min size of the buffer.
492473
if (length < BUFFER_LENGTH) {
493474
length = BUFFER_LENGTH;
@@ -500,6 +481,7 @@ inline void TwoWire::allocateTxBuffer(size_t length)
500481
_Error_Handler("No enough memory! (%i)\n", length);
501482
}
502483
}
484+
return ret;
503485
}
504486

505487
/**

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

+12-7
Original file line numberDiff line numberDiff line change
@@ -28,23 +28,28 @@ extern "C" {
2828
#include "utility/twi.h"
2929
}
3030

31+
// Minimal buffer length. Buffers length will be increased when needed,
32+
// but TX buffer is limited to a maximum to avoid too much stack consumption
33+
// Note: Buffer length and max buffer length are limited by uin16_t type
3134
#define BUFFER_LENGTH 32
35+
#if !defined(WIRE_MAX_TX_BUFF_LENGTH)
36+
#define WIRE_MAX_TX_BUFF_LENGTH 1024U
37+
#endif
3238

3339
// WIRE_HAS_END means Wire has end()
3440
#define WIRE_HAS_END 1
3541

3642
class TwoWire : public Stream {
3743
private:
3844
uint8_t *rxBuffer;
39-
uint8_t rxBufferAllocated;
40-
uint8_t rxBufferIndex;
41-
uint8_t rxBufferLength;
45+
uint16_t rxBufferAllocated;
46+
uint16_t rxBufferIndex;
47+
uint16_t rxBufferLength;
4248

4349
uint8_t txAddress;
4450
uint8_t *txBuffer;
45-
uint8_t txBufferAllocated;
46-
uint8_t txBufferIndex;
47-
uint8_t txBufferLength;
51+
uint16_t txBufferAllocated;
52+
uint16_t txDataSize;
4853

4954
uint8_t transmitting;
5055

@@ -57,7 +62,7 @@ class TwoWire : public Stream {
5762
static void onReceiveService(i2c_t *);
5863

5964
void allocateRxBuffer(size_t length);
60-
void allocateTxBuffer(size_t length);
65+
size_t allocateTxBuffer(size_t length);
6166

6267
void resetRxBuffer(void);
6368
void resetTxBuffer(void);

0 commit comments

Comments
 (0)