@@ -28,12 +28,14 @@ extern "C" {
28
28
#include " Wire.h"
29
29
30
30
// Initialize Class Variables //////////////////////////////////////////////////
31
- uint8_t TwoWire::rxBuffer[BUFFER_LENGTH];
31
+ uint8_t *TwoWire::rxBuffer = nullptr ;
32
+ uint8_t TwoWire::rxBufferAllocated = 0 ;
32
33
uint8_t TwoWire::rxBufferIndex = 0 ;
33
34
uint8_t TwoWire::rxBufferLength = 0 ;
34
35
35
36
uint8_t TwoWire::txAddress = 0 ;
36
- uint8_t TwoWire::txBuffer[BUFFER_LENGTH];
37
+ uint8_t *TwoWire::txBuffer = nullptr ;
38
+ uint8_t TwoWire::txBufferAllocated = 0 ;
37
39
uint8_t TwoWire::txBufferIndex = 0 ;
38
40
uint8_t TwoWire::txBufferLength = 0 ;
39
41
@@ -66,9 +68,11 @@ void TwoWire::begin(uint8_t address)
66
68
{
67
69
rxBufferIndex = 0 ;
68
70
rxBufferLength = 0 ;
71
+ resetRxBuffer ();
69
72
70
73
txBufferIndex = 0 ;
71
74
txBufferLength = 0 ;
75
+ resetTxBuffer ();
72
76
73
77
transmitting = 0 ;
74
78
@@ -97,6 +101,12 @@ void TwoWire::begin(int address)
97
101
98
102
void TwoWire::end (void )
99
103
{
104
+ free (txBuffer);
105
+ txBuffer = nullptr ;
106
+ txBufferAllocated = 0 ;
107
+ free (rxBuffer);
108
+ rxBuffer = nullptr ;
109
+ rxBufferAllocated = 0 ;
100
110
i2c_deinit (&_i2c);
101
111
}
102
112
@@ -109,6 +119,13 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres
109
119
{
110
120
UNUSED (sendStop);
111
121
if (master == true ) {
122
+ allocateRxBuffer (quantity);
123
+ // error if no memory block available to allocate the buffer
124
+ if (rxBuffer == nullptr ){
125
+ setWriteError ();
126
+ return 0 ;
127
+ }
128
+
112
129
if (isize > 0 ) {
113
130
// send internal address; this mode allows sending a repeated start to access
114
131
// some devices' internal registers. This function is executed by the hardware
@@ -128,12 +145,7 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres
128
145
endTransmission (false );
129
146
}
130
147
131
- // clamp to buffer length
132
- if (quantity > BUFFER_LENGTH){
133
- quantity = BUFFER_LENGTH;
134
- }
135
148
// perform blocking read into buffer
136
- // uint8_t read = twi_readFrom(address, rxBuffer, quantity, sendStop);
137
149
uint8_t read = 0 ;
138
150
if (I2C_OK == i2c_master_read (&_i2c, address << 1 , rxBuffer, quantity))
139
151
read = quantity;
@@ -216,9 +228,13 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop)
216
228
break ;
217
229
}
218
230
231
+ // reset Tx buffer
232
+ resetTxBuffer ();
233
+
219
234
// reset tx buffer iterator vars
220
235
txBufferIndex = 0 ;
221
236
txBufferLength = 0 ;
237
+
222
238
// indicate that we are done transmitting
223
239
transmitting = 0 ;
224
240
}
@@ -241,8 +257,9 @@ size_t TwoWire::write(uint8_t data)
241
257
{
242
258
if (transmitting){
243
259
// in master transmitter mode
244
- // don't bother if buffer is full
245
- if (txBufferLength >= BUFFER_LENGTH){
260
+ allocateTxBuffer (txBufferLength + 1 );
261
+ // error if no memory block available to allocate the buffer
262
+ if (txBuffer == nullptr ){
246
263
setWriteError ();
247
264
return 0 ;
248
265
}
@@ -254,27 +271,44 @@ size_t TwoWire::write(uint8_t data)
254
271
}else {
255
272
// in slave send mode
256
273
// reply to master
257
- i2c_slave_write_IT (&_i2c,&data,1 );
274
+ if (i2c_slave_write_IT (&_i2c,&data,1 ) != I2C_OK) {
275
+ return 0 ;
276
+ }
258
277
}
259
278
return 1 ;
260
279
}
261
280
262
- // must be called in:
263
- // slave tx event callback
264
- // or after beginTransmission(address)
281
+ /* *
282
+ * @brief This function must be called in slave Tx event callback or after
283
+ * beginTransmission() and before endTransmission().
284
+ * @param pdata: pointer to the buffer data
285
+ * @param quantity: number of bytes to write
286
+ * @retval number of bytes ready to write.
287
+ */
265
288
size_t TwoWire::write (const uint8_t *data, size_t quantity)
266
289
{
267
290
if (transmitting){
268
291
// in master transmitter mode
269
- for (size_t i = 0 ; i < quantity; ++i){
270
- write (data[i]);
292
+ allocateTxBuffer (txBufferLength + quantity);
293
+ // error if no memory block available to allocate the buffer
294
+ if (txBuffer == nullptr ){
295
+ setWriteError ();
296
+ return 0 ;
271
297
}
298
+ // put bytes in tx buffer
299
+ memcpy (&(txBuffer[txBufferIndex]), data, quantity);
300
+ txBufferIndex= txBufferIndex + quantity;
301
+ // update amount in buffer
302
+ txBufferLength = txBufferIndex;
303
+ return quantity;
272
304
}else {
273
305
// in slave send mode
274
306
// reply to master
275
- i2c_slave_write_IT (&_i2c,(uint8_t *)data,quantity);
307
+ if (i2c_slave_write_IT (&_i2c, (uint8_t *)data, quantity) == I2C_OK) {
308
+ return quantity;
309
+ }
276
310
}
277
- return quantity ;
311
+ return 0 ;
278
312
}
279
313
280
314
// must be called in:
@@ -296,6 +330,13 @@ int TwoWire::read(void)
296
330
if (rxBufferIndex < rxBufferLength){
297
331
value = rxBuffer[rxBufferIndex];
298
332
++rxBufferIndex;
333
+
334
+ /* Commented as not I think it is not useful
335
+ * but kept to show that it is possible to
336
+ * reset rx buffer when no more data available */
337
+ /* if(rxBufferIndex == rxBufferLength) {
338
+ resetRxBuffer();
339
+ }*/
299
340
}
300
341
301
342
return value;
@@ -319,8 +360,10 @@ void TwoWire::flush(void)
319
360
{
320
361
rxBufferIndex = 0 ;
321
362
rxBufferLength = 0 ;
363
+ resetRxBuffer ();
322
364
txBufferIndex = 0 ;
323
365
txBufferLength = 0 ;
366
+ resetTxBuffer ();
324
367
}
325
368
326
369
// behind the scenes function that is called when data is received
@@ -339,9 +382,7 @@ void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes)
339
382
}
340
383
// copy twi rx buffer into local read buffer
341
384
// this enables new reads to happen in parallel
342
- for (uint8_t i = 0 ; i < numBytes; ++i){
343
- rxBuffer[i] = inBytes[i];
344
- }
385
+ memcpy (rxBuffer, inBytes, numBytes);
345
386
// set rx iterator vars
346
387
rxBufferIndex = 0 ;
347
388
rxBufferLength = numBytes;
@@ -377,6 +418,44 @@ void TwoWire::onRequest( void (*function)(void) )
377
418
user_onRequest = function;
378
419
}
379
420
421
+ /* *
422
+ * @brief Allocate the Rx/Tx buffer to the requested length if needed
423
+ * @note Minimum allocated size is BUFFER_LENGTH)
424
+ * @param length: number of bytes to allocate
425
+ */
426
+ inline void TwoWire::allocateRxBuffer (size_t length)
427
+ {
428
+ if (rxBufferAllocated < length) {
429
+ // By default we allocate BUFFER_LENGTH bytes. It is the min size of the buffer.
430
+ if (length < BUFFER_LENGTH) { length = BUFFER_LENGTH; }
431
+ rxBuffer = (uint8_t *)realloc (rxBuffer, length * sizeof (uint8_t ));
432
+ rxBufferAllocated = (rxBuffer != nullptr ) ? length: 0 ;
433
+ }
434
+ }
435
+
436
+ inline void TwoWire::allocateTxBuffer (size_t length)
437
+ {
438
+ if (txBufferAllocated < length) {
439
+ // By default we allocate BUFFER_LENGTH bytes. It is the min size of the buffer.
440
+ if (length < BUFFER_LENGTH) { length = BUFFER_LENGTH; }
441
+ txBuffer = (uint8_t *)realloc (txBuffer, length * sizeof (uint8_t ));
442
+ txBufferAllocated = (txBuffer != nullptr ) ? length: 0 ;
443
+ }
444
+ }
445
+
446
+ /* *
447
+ * @brief Reset Rx/Tx buffer content to 0
448
+ */
449
+ inline void TwoWire::resetRxBuffer (void )
450
+ {
451
+ if (rxBuffer != nullptr ) memset (rxBuffer, 0 , rxBufferAllocated);
452
+ }
453
+
454
+ inline void TwoWire::resetTxBuffer (void )
455
+ {
456
+ if (txBuffer != nullptr ) memset (txBuffer, 0 , txBufferAllocated);
457
+ }
458
+
380
459
// Preinstantiate Objects //////////////////////////////////////////////////////
381
460
382
461
TwoWire Wire = TwoWire(); // D14-D15
0 commit comments