-
Notifications
You must be signed in to change notification settings - Fork 1k
Add new methods to Wire library #131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
cores/arduino/stm32/twi.c
Outdated
if(size > I2C_TXRX_BUFFER_SIZE) { | ||
size = I2C_TXRX_BUFFER_SIZE; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we rather return en error?
Otherwise application would get an incomplete frame and will not get an error ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I quickly patched a possible memory leak so I kept the function "void".
I can return 0 in case of error if you rather.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I mean is that you need to properly manage errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
libraries/Wire/src/Wire.cpp
Outdated
write(data[i]); | ||
} | ||
txBufferLength = quantity; | ||
pWriteData = (uint8_t*)pdata; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
before the patch, write() was called and transmission happens.
Now only 2 variables are updated - how does transmission actually start ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you confused master and slave mode. I only change the master mode.
The transmission only happens when endtransmission() is called (before and now).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well what I see here is that you remove the lines:
- for(size_t i = 0; i < quantity; ++i){
-
write(data[i]);
- }
and replace them by txBufferLength and pWriteData assignment ... it looks like changing the dynamic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well what I see here is that you remove the lines:
for(size_t i = 0; i < quantity; ++i){
write(data[i]);
}
and replace them by txBufferLength and pWriteData assignment ... it looks like changing the dynamic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course I changed the dynamic because I pass directly the data buffer pWriteData to the endTransmission() function (and so to the HAL) and I don't use anymore the internal buffer (low size) which is filled in the write() function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok - I got confused by write() function as I thought it would actually transmit data on I2C lines. Thanks for the clarification.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact, @LMESTM is right. the dynamic is not the same and so the txbuffer construction is broken.
I've seen the issue with test on i2C eeprom. See code below:
Wire.beginTransmission(ctrlByte);
if (_nAddrBytes == 2) Wire.write( (byte) (addr >> 8) ); //high addr byte
Wire.write( (byte) addr ); //low addr byte
Wire.write(values, nWrite);
txStatus = Wire.endTransmission();
The 2 first calls of Wire.write()
put the bytes in the internal txBuffer
but when Wire.write(values, nWrite);
is called, it initialize pWriteData
.
Finally when Wire.endTransmission();
is called:
// Select the buffer where are stored the data to send
if(pWriteData != NULL) {
data = pWriteData;
} else {
data = txBuffer;
}
the txBuffer
datas are ignored....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are 2 methods completely different now. You can't mix them as you see.
But maybe I found a solution to mix them and keep all older sketches compatibles.
I look at this.
Wire library updated to keep the write() method available as required by @fpistm . |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure about the proposal - I have posted comments and I would like to have @fpistm feedback as well.
EDIT: the good point is to have a separate API, this means that it will not break existing libraries and we may live with this proposal until we possibly find a better one ...
libraries/Wire/README.md
Outdated
called only once after _beginTransmission()_. _endTransmission()_ must be called | ||
immediately after. No other _write()_ method have to be called between | ||
_beginTransmission()_ and _endTransmission()_ when _writeBuffer()_ is used. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand the idea and this would work ok - but I am not sure that this requirement (call only once, call endTRansmission immediately after ...) is acceptable - Isn't there an alternative that is more compliant with arduino defaut API ? Coudln't we simply increase internal buffer size ? Or maybe manage malloc & free of extra buffers in case size becomes > 255 then in endTransmission you would send the default buffers + extra ones ? ... other feedbacks are welcome of course
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have discussed with @fprwi6labs about that. Changing the static buffer to a dynamic one will consume memory space. If several I2C instances are used and extra buffer size is required this will reach quickly the maximum space.
Proposal was to kept the current write function and add a new one with the usage restriction.
libraries/Wire/README.md
Outdated
* **requestFrom(uint8_t address, uint16_t quantity, uint8_t \*pdata)**: this | ||
function allows to read data and store them directly in pdata buffer. | ||
Do not call _available()_ and _read()_ after this function because data are | ||
directly stored in pdata buffer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, if new methods are not easy to understand, I am not sure whether we should offer them
libraries/Wire/src/Wire.cpp
Outdated
* @param quantity: number of bytes to write | ||
* @retval number of bytes read. If > 0 then data are present in pdata buffer. | ||
*/ | ||
size_t TwoWire::writeBuffer(uint8_t *pdata, size_t quantity) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a warning about the pdata to ensure user do not freed or changed this buffer before endTransmission()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok for me.
Wait NFC test and @LMESTM feedback
@fpistm @fprwi6labs as said above, ok with me as it will not break existing libraries and we may live with this proposal until we possibly find a better one - but I would not encourage a wide use of this API as long as it is not robust for begin/end and other APIs. |
Signed-off-by: fpr <[email protected]>
Signed-off-by: fpr <[email protected]>
Updated to use dynamic memory allocation. No new method added. Compatibility kept. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
API compatibility is preserved.
tested with i2C eeprom and its ok.
@@ -97,6 +99,10 @@ void TwoWire::begin(int address) | |||
|
|||
void TwoWire::end(void) | |||
{ | |||
free(txBuffer); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check if pointer is null before free it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
free()
accepts null pointer
If ptr is a null pointer, the function does nothing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, i've got a doubt ;)
@@ -97,6 +99,10 @@ void TwoWire::begin(int address) | |||
|
|||
void TwoWire::end(void) | |||
{ | |||
free(txBuffer); | |||
txBuffer = nullptr; | |||
free(rxBuffer); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
libraries/Wire/src/Wire.cpp
Outdated
@@ -109,6 +115,13 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres | |||
{ | |||
UNUSED(sendStop); | |||
if (master == true) { | |||
rxBuffer = allocateBuffer(rxBuffer, quantity); | |||
// error if not memory block available to allocate the buffer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'if no'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done!
libraries/Wire/src/Wire.cpp
Outdated
// don't bother if buffer is full | ||
if(txBufferLength >= BUFFER_LENGTH){ | ||
txBuffer = allocateBuffer(txBuffer, txBufferLength + 1); | ||
// error if not memory block available to allocate the buffer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'if no'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done!
…ayer Signed-off-by: fpr <[email protected]>
Hi @fprwi6labs, |
Hi @fpistm
It is OK for me. |
Ok thanks. Waiting @LMESTM feedback |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Few comments to be addressed, but overall I like the idea of not chaging the standard API.
I think the PR should be renamed now because "Add new methods to wire lib" does not make sense anymore. Same for commits titles and commit messages, they need to be updated accordingly.
} | ||
|
||
/** | ||
* @brief Reset the buffer. Reduce is size if greater than BUFFER_LENGTH. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: is size / its size
comment says that it reduce the size only if greater than BUFFER_LENGHT but code seems to do it unconditionnally
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change in the enhancement
buffer = (uint8_t *)realloc(buffer, BUFFER_LENGTH * sizeof(uint8_t)); | ||
if(buffer != nullptr) { | ||
memset(buffer, 0, BUFFER_LENGTH); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in case of nullptr, we need to raise an error (no memory ...).
I 'm not sure this is checked after every call to resetBuffer ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checked in the R/W function
@@ -66,9 +66,11 @@ void TwoWire::begin(uint8_t address) | |||
{ | |||
rxBufferIndex = 0; | |||
rxBufferLength = 0; | |||
rxBuffer = resetBuffer(rxBuffer); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if null raise en error ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Error is raised later if rx/txBuffer is NULL
|
||
txBufferIndex = 0; | ||
txBufferLength = 0; | ||
txBuffer = resetBuffer(txBuffer); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Error is raised later if rx/txBuffer is NULL
@@ -216,9 +224,15 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop) | |||
break; | |||
} | |||
|
|||
//Reduce buffer size to free memory in case of large memory use | |||
if(txBufferLength > BUFFER_LENGTH) { | |||
txBuffer = resetBuffer(txBuffer); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
raise an errror if null ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will be removed in my PR.
@@ -241,8 +255,9 @@ size_t TwoWire::write(uint8_t data) | |||
{ | |||
if(transmitting){ | |||
// in master transmitter mode | |||
// don't bother if buffer is full | |||
if(txBufferLength >= BUFFER_LENGTH){ | |||
txBuffer = allocateBuffer(txBuffer, txBufferLength + 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe not efficient to allocate +1 byte each time - maybe you could go by steps (allocateBuffer(txBuffer, txBufferLength + BUFFER_LENGTH) each time it is needed) because reallocation can be costly in performances?
In that way BUFFER_LENGHT would be used as the "unit" of buffer allocation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mainly call to set first bytes of the data (ex: address).
See fpistm@c4b9f24
In this commit the min size is BUFFER_LENGTH.
This PR has been replaced by #152 |
This solves issue #124
The library can now use an external buffer to write and read data in master mode.
The internal buffer size limitation (BUFFER_LENGTH) is no more a problem (#120) because we don't use in this case the internal buffers.
Note: when you use
requestFrom()
with an external buffer, do not useavailable()
andread()
functions to read the data.requestFrom()
will return a not null value if data are available and the data are stored in the external buffer.I took advantage of the fix to upgrade the library with the Arduino libraries rules.