From 9c3e23b3f70f113e03f0e1259b6754bf65cd0f7d Mon Sep 17 00:00:00 2001 From: dac1e Date: Fri, 3 Jan 2025 13:46:56 +0100 Subject: [PATCH 1/3] Added WireBuffer.h and WireBuffer.cpp. Wire and Wire1 use WireBuffer. --- .../master_reader_custombuffer.ino | 94 +++++++++++++++ .../master_writer_custombuffer.ino | 94 +++++++++++++++ .../slave_receiver_Wire1Wire_connected.ino | 94 +++++++++++++++ .../slave_receiver_custombuffer.ino | 111 ++++++++++++++++++ .../slave_sender_Wire1Wire_connected.ino | 83 +++++++++++++ .../slave_sender_custombuffer.ino | 93 +++++++++++++++ libraries/Wire/src/Wire.cpp | 64 ++++++---- libraries/Wire/src/Wire.h | 18 ++- libraries/Wire/src/WireBuffer.cpp | 49 ++++++++ libraries/Wire/src/WireBuffer.h | 80 +++++++++++++ 10 files changed, 749 insertions(+), 31 deletions(-) create mode 100644 libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino create mode 100644 libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino create mode 100644 libraries/Wire/examples/slave_receiver_Wire1Wire_connected/slave_receiver_Wire1Wire_connected.ino create mode 100644 libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino create mode 100644 libraries/Wire/examples/slave_sender_Wire1Wire_connected/slave_sender_Wire1Wire_connected.ino create mode 100644 libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino create mode 100644 libraries/Wire/src/WireBuffer.cpp create mode 100644 libraries/Wire/src/WireBuffer.h diff --git a/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino b/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino new file mode 100644 index 00000000..8279bb28 --- /dev/null +++ b/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino @@ -0,0 +1,94 @@ +// Wire Master Reader Custom Buffer + +// Demonstrates use of the Wire library with customized buffers +// Reads data from an I2C/TWI slave device +// Refer to the "Wire Slave Sender Custom Buffer" example for use with this + +// Created 31 Dec 2024 + +// This example code is in the public domain. + + +#include +#include +#include "Arduino.h" + +#define USE_WIRE1 false // Set to true for using Wire1 + +// request 6 bytes from slave device #8 +constexpr size_t REQUESTED_BYTE_COUNT = 6; + +constexpr size_t RECEIVE_BUFFER_SIZE = REQUESTED_BYTE_COUNT; +constexpr size_t TRANSMIT_BUFFER_SIZE = 0; // There is no transmit in this sketch. + +#if not USE_WIRE1 + +SET_Wire_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, + true /* master buffers needed */, false /* no slave buffers needed */ ); + +void setup() { + Wire.begin(); // join I2C bus (address optional for master) + Serial.begin(9600); // start serial for output + + // This is just for curiosity and could be removed + printWireBufferSize(Serial); +} + +void loop() { + Wire.requestFrom(8, REQUESTED_BYTE_COUNT); + + while (Wire.available()) { // slave may send less than requested + const char c = Wire.read(); // receive a byte as character + Serial.print(c); // print the character + } + Serial.println(); + + delay(500); +} + +void printWireBufferSize(Stream& stream) { + using namespace WireBuffer; + stream.print("Wire receive buffer size is "); + stream.println(buffers.RX_BUFFER_SIZE); + stream.print("Wire transmit buffer size is "); + stream.println(buffers.TX_BUFFER_SIZE); + stream.print("Wire service buffer size is "); + stream.println(buffers.SRV_BUFFER_SIZE); +} + +#else + +SET_Wire1_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, + true /* master buffers needed */, false /* no slave buffers needed */ ); + +void setup() { + Wire1.begin(); // join I2C bus (address optional for master) + Serial.begin(9600); // start serial for output + + // This is just for curiosity and could be removed + printWire1BufferSize(Serial); +} + +void loop() { + Wire1.requestFrom(8, REQUESTED_BYTE_COUNT); + + while (Wire1.available()) { // slave may send less than requested + const char c = Wire1.read(); // receive a byte as character + Serial.print(c); // print the character + } + Serial.println(); + + delay(500); +} + +void printWire1BufferSize(Stream& stream) { + using namespace Wire1Buffer; + stream.print("Wire1 receive buffer size is "); + stream.println(buffers.RX_BUFFER_SIZE); + stream.print("Wire1 transmit buffer size is "); + stream.println(buffers.TX_BUFFER_SIZE); + stream.print("Wire1 service buffer size is "); + stream.println(buffers.SRV_BUFFER_SIZE); +} + +#endif diff --git a/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino b/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino new file mode 100644 index 00000000..d4c04d95 --- /dev/null +++ b/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino @@ -0,0 +1,94 @@ +// Wire Master Writer Custom Buffer + +// Demonstrates use of the Wire library with customized buffers +// Writes data to an I2C/TWI slave device +// Refer to the "Wire Slave Receiver Custom Buffer" example for use with this + +// Created 31 Dec 2024 + +// This example code is in the public domain. + + +#include +#include +#include "Arduino.h" + +#define USE_WIRE1 false // Set to true for using Wire1 + +// The following text will not fit into the default buffer of 32 bytes. +static const char text[] = "You really won't believe it, but x is "; + +constexpr size_t RECEIVE_BUFFER_SIZE = 0; // There is no receive in this sketch. +constexpr size_t TRANSMIT_BUFFER_SIZE = 42; // Enhance the buffer to 42 characters. + +#if not USE_WIRE1 + +SET_Wire_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, + true /* master buffers needed */, false /* no slave buffers needed */ ); + +void setup() { + Wire.begin(); // join I2C bus (address optional for master) + + // This is just for curiosity and could be removed + Serial.begin(9600); // start serial for output + printWireBufferSize(Serial); +} + +static byte x = 0; + +void loop() { + Wire.beginTransmission(8); // transmit to device #8 + Wire.write(text); // sends multiple bytes + Wire.write(x); // sends one byte + Wire.endTransmission(); // stop transmitting + + x++; + delay(500); +} + +void printWireBufferSize(Stream& stream) { + using namespace WireBuffer; + stream.print("Wire receive buffer size is "); + stream.println(buffers.RX_BUFFER_SIZE); + stream.print("Wire transmit buffer size is "); + stream.println(buffers.TX_BUFFER_SIZE); + stream.print("Wire service buffer size is "); + stream.println(buffers.SRV_BUFFER_SIZE); +} + +#else + +SET_Wire1_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, + true /* master buffers needed */, false /* no slave buffers needed */ ); + +void setup() { + Wire1.begin(); // join I2C bus (address optional for master) + + // This is just for curiosity and could be removed + Serial.begin(9600); // start serial for output + printWire1BufferSize(Serial); +} + +static byte x = 0; + +void loop() { + Wire1.beginTransmission(8); // transmit to device #8 + Wire1.write(text); // sends multiple bytes + Wire1.write(x); // sends one byte + Wire1.endTransmission(); // stop transmitting + + x++; + delay(500); +} + +void printWire1BufferSize(Stream& stream) { + using namespace Wire1Buffer; + stream.print("Wire1 receive buffer size is "); + stream.println(buffers.RX_BUFFER_SIZE); + stream.print("Wire1 transmit buffer size is "); + stream.println(buffers.TX_BUFFER_SIZE); + stream.print("Wire1 service buffer size is "); + stream.println(buffers.SRV_BUFFER_SIZE); +} + +#endif diff --git a/libraries/Wire/examples/slave_receiver_Wire1Wire_connected/slave_receiver_Wire1Wire_connected.ino b/libraries/Wire/examples/slave_receiver_Wire1Wire_connected/slave_receiver_Wire1Wire_connected.ino new file mode 100644 index 00000000..809cfaf8 --- /dev/null +++ b/libraries/Wire/examples/slave_receiver_Wire1Wire_connected/slave_receiver_Wire1Wire_connected.ino @@ -0,0 +1,94 @@ +// Wire1 connnected to Wire. (scl <-> scl1, sda <-> sda1) + +// Demonstrates use of the Wire library on a single Arduino board +// with 2 Wire interfaces (like Arduino Due). +// Uses the option of customizing the buffers. +// +// Wire data to an I2C/TWI slave device +// Wire1 receives data as an I2C/TWI slave device + +// Created 02 Jan 2025 + +// This example code is in the public domain. + + +#include +#include +#include "Arduino.h" + +static_assert(WIRE_INTERFACES_COUNT > 1, "You need two I2C interfaces on the Arduino board to run this sketch"); + +static const char text[] = "You really won't believe it, but x is "; + +// Wire is the master writer +constexpr size_t M_RECEIVE_BUFFER_SIZE = 0; // There is no receive in this sketch. +constexpr size_t M_TRANSMIT_BUFFER_SIZE = 42; // Enhance the buffer to 42 characters. +SET_Wire_BUFFERS(M_RECEIVE_BUFFER_SIZE, M_TRANSMIT_BUFFER_SIZE, + true /* master buffers needed */, false /* no slave buffers needed */ ); + +// Wire1 is the slave receiver +constexpr size_t S_RECEIVE_BUFFER_SIZE = 42; // Be able receive up to 42 characters in one message. +constexpr size_t S_TRANSMIT_BUFFER_SIZE = 0; // There is no transmit in this sketch. +SET_Wire1_BUFFERS(S_RECEIVE_BUFFER_SIZE, S_TRANSMIT_BUFFER_SIZE, + false /* no master buffers needed */, true /* slave buffers needed */ ); + +void setup() { + Serial.begin(9600); // start serial for output + Wire.begin(); // master joins I2C bus (address optional for master) + Wire1.begin(8); // slave joins I2C bus with address #8 + Wire1.onReceive(receiveEvent); // register event + + // This is just for curiosity and could be removed + printWireBufferSize(Serial); + printWire1BufferSize(Serial); +} + +static byte x = 0; + +void loop() { + Wire.beginTransmission(8); // transmit to device #8 + Wire.write(text); // sends multiple bytes + Wire.write(x); // sends one byte + Wire.endTransmission(); // stop transmitting + + x++; + delay(500); +} + +// function that executes whenever data is received from master +// this function is registered as an event, see setup() +// +// Hint: This function is called within an interrupt context. +// That means, that there must be enough space in the Serial output +// buffer for the characters to be printed. Otherwise the +// Serial.print() call will lock up. +void receiveEvent(int howMany) { + while (1 < Wire1.available()) { // loop through all but the last + const char c = Wire1.read(); // receive byte as a character + Serial.print(c); // print the character + } + const int x = Wire1.read(); // receive byte as an integer + Serial.println(x); // print the integer +} + +void printWireBufferSize(Stream& stream) { + using namespace WireBuffer; + stream.print("Wire receive buffer size is "); + stream.println(buffers.RX_BUFFER_SIZE); + stream.print("Wire transmit buffer size is "); + stream.println(buffers.TX_BUFFER_SIZE); + stream.print("Wire service buffer size is "); + stream.println(buffers.SRV_BUFFER_SIZE); + delay(250); // Give time to free up Serial output buffer. +} + +void printWire1BufferSize(Stream& stream) { + using namespace Wire1Buffer; + stream.print("Wire1 receive buffer size is "); + stream.println(buffers.RX_BUFFER_SIZE); + stream.print("Wire1 transmit buffer size is "); + stream.println(buffers.TX_BUFFER_SIZE); + stream.print("Wire1 service buffer size is "); + stream.println(buffers.SRV_BUFFER_SIZE); + delay(250); // Give time to free up Serial output buffer. +} diff --git a/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino b/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino new file mode 100644 index 00000000..525eae38 --- /dev/null +++ b/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino @@ -0,0 +1,111 @@ +// Wire Slave Receiver Custom Buffer + +// Demonstrates use of the Wire library with customized buffers +// Receives data as an I2C/TWI slave device +// Refer to the "Wire Master Writer Custom Buffer" example for use with this + +// Created 31 Dec 2024 + +// This example code is in the public domain. + + +#include +#include +#include "Arduino.h" + +#define USE_WIRE1 false // Set to true for using Wire1 + +constexpr size_t RECEIVE_BUFFER_SIZE = 42; // Be able receive up to 42 characters in one message. +constexpr size_t TRANSMIT_BUFFER_SIZE = 0; // There is no transmit in this sketch. + +#if not USE_WIRE1 + +SET_Wire_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, + false /* no master buffers needed */, true /* slave buffers needed */ ); + +void setup() { + Wire.begin(8); // join I2C bus with address #8 + Wire.onReceive(receiveEvent); // register event + Serial.begin(9600); // start serial for output + + // This is just for curiosity and could be removed + printWireBufferSize(Serial); +} + +void loop() { + delay(100); +} + +// function that executes whenever data is received from master +// this function is registered as an event, see setup() +// +// Hint: This function is called within an interrupt context. +// That means, that there must be enough space in the Serial output +// buffer for the characters to be printed. Otherwise the +// Serial.print() call will lock up. +void receiveEvent(int howMany) { + while (1 < Wire.available()) { // loop through all but the last + const char c = Wire.read(); // receive byte as a character + Serial.print(c); // print the character + } + const int x = Wire.read(); // receive byte as an integer + Serial.println(x); // print the integer +} + +void printWireBufferSize(Stream& stream) { + using namespace WireBuffer; + stream.print("Wire receive buffer size is "); + stream.println(buffers.RX_BUFFER_SIZE); + stream.print("Wire transmit buffer size is "); + stream.println(buffers.TX_BUFFER_SIZE); + stream.print("Wire service buffer size is "); + stream.println(buffers.SRV_BUFFER_SIZE); + delay(250); // Give time to free up Serial output buffer. +} + +#else + +SET_Wire1_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, + false /* no master buffers needed */, true /* slave buffers needed */ ); + +void setup() { + Wire1.begin(8); // join I2C bus with address #8 + Wire1.onReceive(receiveEvent); // register event + Serial.begin(9600); // start serial for output + + // This is just for curiosity and could be removed + printWire1BufferSize(Serial); +} + +void loop() { + delay(100); +} + +// function that executes whenever data is received from master +// this function is registered as an event, see setup() +// +// Hint: This function is called within an interrupt context. +// That means, that there must be enough space in the Serial output +// buffer for the characters to be printed. Otherwise the +// Serial.print() call will lock up. +void receiveEvent(int howMany) { + while (1 < Wire1.available()) { // loop through all but the last + const char c = Wire1.read(); // receive byte as a character + Serial.print(c); // print the character + } + const int x = Wire1.read(); // receive byte as an integer + Serial.println(x); // print the integer +} + +void printWire1BufferSize(Stream& stream) { + using namespace Wire1Buffer; + stream.print("Wire1 receive buffer size is "); + stream.println(buffers.RX_BUFFER_SIZE); + stream.print("Wire1 transmit buffer size is "); + stream.println(buffers.TX_BUFFER_SIZE); + stream.print("Wire1 service buffer size is "); + stream.println(buffers.SRV_BUFFER_SIZE); + delay(250); // Give time to free up Serial output buffer. +} + +#endif diff --git a/libraries/Wire/examples/slave_sender_Wire1Wire_connected/slave_sender_Wire1Wire_connected.ino b/libraries/Wire/examples/slave_sender_Wire1Wire_connected/slave_sender_Wire1Wire_connected.ino new file mode 100644 index 00000000..a92ec52f --- /dev/null +++ b/libraries/Wire/examples/slave_sender_Wire1Wire_connected/slave_sender_Wire1Wire_connected.ino @@ -0,0 +1,83 @@ +// Wire1 connnected to Wire. (scl <-> scl1, sda <-> sda1) + +// Demonstrates use of the Wire library on a single Arduino board +// with 2 Wire interfaces (like Arduino Due). +// Uses the option of customizing the buffers. +// +// Wire reads data from an I2C/TWI slave device +// Wire1 sends data as an I2C/TWI slave device + +// Created 02 Jan 2025 + +// This example code is in the public domain. + + +#include +#include +#include "Arduino.h" + +static_assert(WIRE_INTERFACES_COUNT > 1, "You need two I2C interfaces on the Arduino board to run this sketch"); + +static const char text[] = "hello "; // respond with message of 6 bytes + +// Wire is the master reader +constexpr size_t M_RECEIVE_BUFFER_SIZE = sizeof(text)-1; // Don't need a byte for the \0 +constexpr size_t M_TRANSMIT_BUFFER_SIZE = 0; // There is no transmit in this sketch. +SET_Wire_BUFFERS(M_RECEIVE_BUFFER_SIZE, M_TRANSMIT_BUFFER_SIZE, + true /* master buffers needed */, false /* no slave buffers needed */ ); + +// Wire1 is the slave sender +constexpr size_t S_RECEIVE_BUFFER_SIZE = 0; // There is no receive in this sketch. +constexpr size_t S_TRANSMIT_BUFFER_SIZE = sizeof(text)-1; // Don't need a byte for the \0 +SET_Wire1_BUFFERS(S_RECEIVE_BUFFER_SIZE, S_TRANSMIT_BUFFER_SIZE, + false /* no master buffers needed */, true /* slave buffers needed */ ); + +void setup() { + Serial.begin(9600); // start serial for output + Wire.begin(); // master joins I2C bus (address optional for master) + Wire1.begin(8); // slave joins I2C bus with address #8 + Wire1.onRequest(requestEvent); // register slave event + + // This is just for curiosity and could be removed + printWireBufferSize(Serial); + printWire1BufferSize(Serial); +} + +void loop() { + Wire.requestFrom(8, M_RECEIVE_BUFFER_SIZE); + + while (Wire.available()) { + const char c = Wire.read(); // receive a byte as character + Serial.print(c); // print the character + } + Serial.println(); + + delay(500); +} + +// function that executes whenever data is requested by master +// this function is registered as an event, see setup() +void requestEvent() { + Wire1.write(text); + // as expected by master +} + +void printWireBufferSize(Stream& stream) { + using namespace WireBuffer; + stream.print("Wire receive buffer size is "); + stream.println(buffers.RX_BUFFER_SIZE); + stream.print("Wire transmit buffer size is "); + stream.println(buffers.TX_BUFFER_SIZE); + stream.print("Wire service buffer size is "); + stream.println(buffers.SRV_BUFFER_SIZE); +} + +void printWire1BufferSize(Stream& stream) { + using namespace Wire1Buffer; + stream.print("Wire1 receive buffer size is "); + stream.println(buffers.RX_BUFFER_SIZE); + stream.print("Wire1 transmit buffer size is "); + stream.println(buffers.TX_BUFFER_SIZE); + stream.print("Wire1 service buffer size is "); + stream.println(buffers.SRV_BUFFER_SIZE); +} diff --git a/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino b/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino new file mode 100644 index 00000000..53a96c90 --- /dev/null +++ b/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino @@ -0,0 +1,93 @@ +// Wire Slave Sender Custom Buffer + +// Demonstrates use of the Wire library with customized buffers +// Sends data as an I2C/TWI slave device +// Refer to the "Wire Master Reader Custom Buffer" example for use with this + +// Created 31 Dec 2024 + +// This example code is in the public domain. + + +#include +#include +#include "Arduino.h" + +#define USE_WIRE1 false // Set to true for using Wire1 + +static const char text[] = "hello "; // respond with message of 6 bytes + +constexpr size_t RECEIVE_BUFFER_SIZE = 0; // There is no receive in this sketch. +constexpr size_t TRANSMIT_BUFFER_SIZE = sizeof(text)-1; // Don't need a byte for the \0 + +#if not USE_WIRE1 + +SET_Wire_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, + false /* no master buffers needed */, true /* slave buffers needed */ ); + +void setup() { + Wire.begin(8); // join I2C bus with address #8 + Wire.onRequest(requestEvent); // register event + + // This is just for curiosity and could be removed + Serial.begin(9600); + printWireBufferSize(Serial); +} + +void loop() { + delay(100); +} + +// function that executes whenever data is requested by master +// this function is registered as an event, see setup() +void requestEvent() { + Wire.write(text); + // as expected by master +} + +void printWireBufferSize(Stream& stream) { + using namespace WireBuffer; + stream.print("Wire receive buffer size is "); + stream.println(buffers.RX_BUFFER_SIZE); + stream.print("Wire transmit buffer size is "); + stream.println(buffers.TX_BUFFER_SIZE); + stream.print("Wire service buffer size is "); + stream.println(buffers.SRV_BUFFER_SIZE); +} + +#else + +SET_Wire1_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, + false /* no master buffers needed */, true /* slave buffers needed */ ); + +void setup() { + Wire1.begin(8); // join I2C bus with address #8 + Wire1.onRequest(requestEvent); // register event + + // This is just for curiosity and could be removed + Serial.begin(9600); + printWire1BufferSize(Serial); +} + +void loop() { + delay(100); +} + +// function that executes whenever data is requested by master +// this function is registered as an event, see setup() +void requestEvent() { + Wire1.write(text); + // as expected by master +} + +void printWire1BufferSize(Stream& stream) { + using namespace Wire1Buffer; + stream.print("Wire1 receive buffer size is "); + stream.println(buffers.RX_BUFFER_SIZE); + stream.print("Wire1 transmit buffer size is "); + stream.println(buffers.TX_BUFFER_SIZE); + stream.print("Wire1 service buffer size is "); + stream.println(buffers.SRV_BUFFER_SIZE); +} + +#endif diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index 2cb7dfe2..ec244c55 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -26,6 +26,7 @@ extern "C" { #include } +#include "WireBuffer.h" #include "Wire.h" static inline bool TWI_FailedAcknowledge(Twi *pTwi) { @@ -96,11 +97,24 @@ static inline bool TWI_STATUS_NACK(uint32_t status) { return (status & TWI_SR_NACK) == TWI_SR_NACK; } -TwoWire::TwoWire(Twi *_twi, void(*_beginCb)(void), void(*_endCb)(void)) : +uint8_t* TwoWire:: srvBuffer()const { + return buffers.srvBuffer; +} + +uint8_t* TwoWire:: rxBuffer()const { + return buffers.rxBuffer; +} + +uint8_t* TwoWire:: txBuffer()const { + return buffers.txBuffer; +} + +TwoWire::TwoWire(const TwoWireBuffer::Buffers& _buffers, + Twi *_twi, void(*_beginCb)(void), void(*_endCb)(void)) : buffers(_buffers), twi(_twi), rxBufferIndex(0), rxBufferLength(0), txAddress(0), - txBufferLength(0), srvBufferIndex(0), srvBufferLength(0), status( - UNINITIALIZED), onBeginCallback(_beginCb), - onEndCallback(_endCb), twiClock(TWI_CLOCK) { + txBufferLength(0), srvBufferIndex(0), srvBufferLength(0), status(UNINITIALIZED), + onBeginCallback(_beginCb), onEndCallback(_endCb), twiClock(TWI_CLOCK), + onReceiveCallback(nullptr), onRequestCallback(nullptr) { } void TwoWire::begin(void) { @@ -147,8 +161,8 @@ void TwoWire::setClock(uint32_t frequency) { } uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddress, uint8_t isize, uint8_t sendStop) { - if (quantity > BUFFER_LENGTH) - quantity = BUFFER_LENGTH; + if (quantity > buffers.RX_BUFFER_SIZE) + quantity = buffers.RX_BUFFER_SIZE; // perform blocking read into buffer int readed = 0; @@ -159,7 +173,7 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres TWI_SendSTOPCondition( twi); if (TWI_WaitByteReceived(twi, RECV_TIMEOUT)) - rxBuffer[readed++] = TWI_ReadByte(twi); + rxBuffer()[readed++] = TWI_ReadByte(twi); else break; } while (readed < quantity); @@ -216,14 +230,14 @@ void TwoWire::beginTransmission(int address) { uint8_t TwoWire::endTransmission(uint8_t sendStop) { uint8_t error = 0; // transmit buffer (blocking) - TWI_StartWrite(twi, txAddress, 0, 0, txBuffer[0]); + TWI_StartWrite(twi, txAddress, 0, 0, txBuffer()[0]); if (!TWI_WaitByteSent(twi, XMIT_TIMEOUT)) error = 2; // error, got NACK on address transmit if (error == 0) { uint16_t sent = 1; while (sent < txBufferLength) { - TWI_WriteByte(twi, txBuffer[sent++]); + TWI_WriteByte(twi, txBuffer()[sent++]); if (!TWI_WaitByteSent(twi, XMIT_TIMEOUT)) error = 3; // error, got NACK during data transmmit } @@ -250,14 +264,14 @@ uint8_t TwoWire::endTransmission(void) size_t TwoWire::write(uint8_t data) { if (status == MASTER_SEND) { - if (txBufferLength >= BUFFER_LENGTH) + if (txBufferLength >= buffers.TX_BUFFER_SIZE) return 0; - txBuffer[txBufferLength++] = data; + txBuffer()[txBufferLength++] = data; return 1; } else { - if (srvBufferLength >= BUFFER_LENGTH) + if (srvBufferLength >= buffers.SRV_BUFFER_SIZE) return 0; - srvBuffer[srvBufferLength++] = data; + srvBuffer()[srvBufferLength++] = data; return 1; } } @@ -265,15 +279,15 @@ size_t TwoWire::write(uint8_t data) { size_t TwoWire::write(const uint8_t *data, size_t quantity) { if (status == MASTER_SEND) { for (size_t i = 0; i < quantity; ++i) { - if (txBufferLength >= BUFFER_LENGTH) + if (txBufferLength >= buffers.TX_BUFFER_SIZE) return i; - txBuffer[txBufferLength++] = data[i]; + txBuffer()[txBufferLength++] = data[i]; } } else { for (size_t i = 0; i < quantity; ++i) { - if (srvBufferLength >= BUFFER_LENGTH) + if (srvBufferLength >= buffers.SRV_BUFFER_SIZE) return i; - srvBuffer[srvBufferLength++] = data[i]; + srvBuffer()[srvBufferLength++] = data[i]; } } return quantity; @@ -285,13 +299,13 @@ int TwoWire::available(void) { int TwoWire::read(void) { if (rxBufferIndex < rxBufferLength) - return rxBuffer[rxBufferIndex++]; + return rxBuffer()[rxBufferIndex++]; return -1; } int TwoWire::peek(void) { if (rxBufferIndex < rxBufferLength) - return rxBuffer[rxBufferIndex]; + return rxBuffer()[rxBufferIndex]; return -1; } @@ -342,7 +356,7 @@ void TwoWire::onService(void) { // (allows to receive another packet while the // user program reads actual data) for (uint8_t i = 0; i < srvBufferLength; ++i) - rxBuffer[i] = srvBuffer[i]; + rxBuffer()[i] = srvBuffer()[i]; rxBufferIndex = 0; rxBufferLength = srvBufferLength; @@ -359,8 +373,8 @@ void TwoWire::onService(void) { if (status == SLAVE_RECV) { if (TWI_STATUS_RXRDY(sr)) { - if (srvBufferLength < BUFFER_LENGTH) - srvBuffer[srvBufferLength++] = TWI_ReadByte(twi); + if (srvBufferLength < buffers.SRV_BUFFER_SIZE) + srvBuffer()[srvBufferLength++] = TWI_ReadByte(twi); } } @@ -368,7 +382,7 @@ void TwoWire::onService(void) { if (TWI_STATUS_TXRDY(sr) && !TWI_STATUS_NACK(sr)) { uint8_t c = 'x'; if (srvBufferIndex < srvBufferLength) - c = srvBuffer[srvBufferIndex++]; + c = srvBuffer()[srvBufferIndex++]; TWI_WriteByte(twi, c); } } @@ -405,7 +419,7 @@ static void Wire_Deinit(void) { // and pullups were not enabled } -TwoWire Wire = TwoWire(WIRE_INTERFACE, Wire_Init, Wire_Deinit); +TwoWire Wire = TwoWire(WireBuffer::buffers, WIRE_INTERFACE, Wire_Init, Wire_Deinit); void WIRE_ISR_HANDLER(void) { Wire.onService(); @@ -443,7 +457,7 @@ static void Wire1_Deinit(void) { // and pullups were not enabled } -TwoWire Wire1 = TwoWire(WIRE1_INTERFACE, Wire1_Init, Wire1_Deinit); +TwoWire Wire1 = TwoWire(Wire1Buffer::buffers, WIRE1_INTERFACE, Wire1_Init, Wire1_Deinit); void WIRE1_ISR_HANDLER(void) { Wire1.onService(); diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index 3913c983..97814d15 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -23,18 +23,21 @@ // Include Atmel CMSIS driver #include - #include "Stream.h" #include "variant.h" -#define BUFFER_LENGTH 32 +// Forward declaration of TwoWireBuffer::Buffers +namespace TwoWireBuffer { + struct Buffers; +} // WIRE_HAS_END means Wire has end() #define WIRE_HAS_END 1 class TwoWire : public Stream { public: - TwoWire(Twi *twi, void(*begin_cb)(void), void(*end_cb)(void)); + TwoWire(const TwoWireBuffer::Buffers& _buffers, + Twi *twi, void(*begin_cb)(void), void(*end_cb)(void)); void begin(); void begin(uint8_t); void begin(int); @@ -67,18 +70,21 @@ class TwoWire : public Stream { void onService(void); private: + const TwoWireBuffer::Buffers& buffers; + + // RX Buffer - uint8_t rxBuffer[BUFFER_LENGTH]; + inline uint8_t* rxBuffer() const; uint8_t rxBufferIndex; uint8_t rxBufferLength; // TX Buffer + inline uint8_t* txBuffer() const; uint8_t txAddress; - uint8_t txBuffer[BUFFER_LENGTH]; uint8_t txBufferLength; // Service buffer - uint8_t srvBuffer[BUFFER_LENGTH]; + inline uint8_t* srvBuffer() const; uint8_t srvBufferIndex; uint8_t srvBufferLength; diff --git a/libraries/Wire/src/WireBuffer.cpp b/libraries/Wire/src/WireBuffer.cpp new file mode 100644 index 00000000..d7cb7b36 --- /dev/null +++ b/libraries/Wire/src/WireBuffer.cpp @@ -0,0 +1,49 @@ +/* + WireBuffer.cpp - TWI/I2C library for Arduino & Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include "variant.h" +#include "WireBuffer.h" + +#if WIRE_INTERFACES_COUNT > 0 +// Define default buffers as weak buffers +namespace WireBuffer { + extern __attribute__((weak)) const Buffers buffers { + WIRE_BUFFER_DEFAULT_SIZE, WIRE_BUFFER_DEFAULT_SIZE, WIRE_BUFFER_DEFAULT_SIZE + , srvBuffer, rxBuffer, txBuffer + }; + __attribute__((weak)) uint8_t srvBuffer[WIRE_BUFFER_DEFAULT_SIZE]; + __attribute__((weak)) uint8_t rxBuffer[WIRE_BUFFER_DEFAULT_SIZE]; + __attribute__((weak)) uint8_t txBuffer[WIRE_BUFFER_DEFAULT_SIZE]; +} +#endif + +#if WIRE_INTERFACES_COUNT > 1 +// Define default buffers as weak buffers +namespace Wire1Buffer { + extern __attribute__((weak)) const Buffers buffers { + WIRE_BUFFER_DEFAULT_SIZE, WIRE_BUFFER_DEFAULT_SIZE, WIRE_BUFFER_DEFAULT_SIZE + , srvBuffer, rxBuffer, txBuffer + }; + __attribute__((weak)) uint8_t srvBuffer[WIRE_BUFFER_DEFAULT_SIZE]; + __attribute__((weak)) uint8_t rxBuffer[WIRE_BUFFER_DEFAULT_SIZE]; + __attribute__((weak)) uint8_t txBuffer[WIRE_BUFFER_DEFAULT_SIZE]; +} +#endif diff --git a/libraries/Wire/src/WireBuffer.h b/libraries/Wire/src/WireBuffer.h new file mode 100644 index 00000000..60568fa4 --- /dev/null +++ b/libraries/Wire/src/WireBuffer.h @@ -0,0 +1,80 @@ +/* + WireBuffer.h - TWI/I2C library for Arduino & Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once + +#ifndef Wire_WireBuffer_h_ +#define Wire_WireBuffer_h_ + +#include +#include +#include "variant.h" + + +// Use extra namespace to avoid collision with other symbols +namespace TwoWireBuffer { + // Declare twi buffers + typedef size_t bufferSize_t; + constexpr bufferSize_t WIRE_BUFFER_DEFAULT_SIZE = 32; + + struct Buffers { + bufferSize_t SRV_BUFFER_SIZE; + bufferSize_t RX_BUFFER_SIZE; + bufferSize_t TX_BUFFER_SIZE; + uint8_t* const srvBuffer; + uint8_t* const rxBuffer; + uint8_t* const txBuffer; + }; +} + +#define SET_TwoWire_BUFFERS(rxBufferSize, txBufferSize) \ + constexpr bufferSize_t srvBufferSize = (rxBufferSize) > (txBufferSize) ? (rxBufferSize) : (txBufferSize); \ + const Buffers buffers { (srvBufferSize), (rxBufferSize), (txBufferSize), srvBuffer, rxBuffer, txBuffer }; \ + uint8_t srvBuffer[srvBufferSize]; \ + uint8_t rxBuffer[(rxBufferSize)];\ + uint8_t txBuffer[(txBufferSize)]; + + +#if WIRE_INTERFACES_COUNT > 0 + namespace WireBuffer { + using namespace TwoWireBuffer; + extern const Buffers buffers; + extern uint8_t srvBuffer[]; + extern uint8_t rxBuffer[]; + extern uint8_t txBuffer[]; + } + + #define SET_Wire_BUFFERS(rxBufferSize, txBufferSize, enableMaster, enableSlave) \ + namespace WireBuffer {SET_TwoWire_BUFFERS(rxBufferSize, txBufferSize)} +#endif // WIRE_INTERFACES_COUNT > 0 + +#if WIRE_INTERFACES_COUNT > 1 + namespace Wire1Buffer { + using namespace TwoWireBuffer; + extern const Buffers buffers; + extern uint8_t srvBuffer[]; + extern uint8_t rxBuffer[]; + extern uint8_t txBuffer[]; + } + + #define SET_Wire1_BUFFERS(rxBufferSize, txBufferSize, enableMaster, enableSlave) \ + namespace Wire1Buffer {SET_TwoWire_BUFFERS(rxBufferSize, txBufferSize)} +#endif // WIRE_INTERFACES_COUNT > 1 + +#endif /* Wire_WireBuffer_h_ */ From 304441d7640dd5ae12f6ee2334dd74e2b3add8cd Mon Sep 17 00:00:00 2001 From: dac1e Date: Fri, 3 Jan 2025 19:05:53 +0100 Subject: [PATCH 2/3] Use C++ cast instead of C cast. Use size_t in for loop instead of uin8_t. Added override specifier where applicable. Changed const to constexpr where possible. Added const qualifiers where possible. --- libraries/Wire/src/Wire.cpp | 16 ++++++++-------- libraries/Wire/src/Wire.h | 34 +++++++++++++++++----------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index ec244c55..fd3a7623 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -142,7 +142,7 @@ void TwoWire::begin(uint8_t address) { } void TwoWire::begin(int address) { - begin((uint8_t) address); + begin(static_cast(address)); } void TwoWire::end(void) { @@ -187,19 +187,19 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres } uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) { - return requestFrom((uint8_t) address, (uint8_t) quantity, (uint32_t) 0, (uint8_t) 0, (uint8_t) sendStop); + return requestFrom(static_cast(address), static_cast(quantity), static_cast(0), static_cast(0), static_cast(sendStop)); } uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity) { - return requestFrom((uint8_t) address, (uint8_t) quantity, (uint8_t) true); + return requestFrom(static_cast(address), static_cast(quantity), static_cast(true)); } uint8_t TwoWire::requestFrom(int address, int quantity) { - return requestFrom((uint8_t) address, (uint8_t) quantity, (uint8_t) true); + return requestFrom(static_cast(address), static_cast(quantity), static_cast(true)); } uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop) { - return requestFrom((uint8_t) address, (uint8_t) quantity, (uint8_t) sendStop); + return requestFrom(static_cast(address), static_cast(quantity), static_cast(sendStop)); } void TwoWire::beginTransmission(uint8_t address) { @@ -211,7 +211,7 @@ void TwoWire::beginTransmission(uint8_t address) { } void TwoWire::beginTransmission(int address) { - beginTransmission((uint8_t) address); + beginTransmission(static_cast(address)); } // @@ -346,7 +346,7 @@ void TwoWire::onService(void) { onRequestCallback(); else // create a default 1-byte response - write((uint8_t) 0); + write(static_cast(0)); } } @@ -355,7 +355,7 @@ void TwoWire::onService(void) { // Copy data into rxBuffer // (allows to receive another packet while the // user program reads actual data) - for (uint8_t i = 0; i < srvBufferLength; ++i) + for (size_t i = 0; i < srvBufferLength; ++i) rxBuffer()[i] = srvBuffer()[i]; rxBufferIndex = 0; rxBufferLength = srvBufferLength; diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index 97814d15..0b83c7a0 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -52,27 +52,27 @@ class TwoWire : public Stream { uint8_t requestFrom(uint8_t, uint8_t, uint32_t, uint8_t, uint8_t); uint8_t requestFrom(int, int); uint8_t requestFrom(int, int, int); - virtual size_t write(uint8_t); - virtual size_t write(const uint8_t *, size_t); - virtual int available(void); - virtual int read(void); - virtual int peek(void); - virtual void flush(void); + size_t write(uint8_t) override; + size_t write(const uint8_t *, size_t) override; + int available(void) override; + int read(void) override; + int peek(void) override; + void flush(void) override; void onReceive(void(*)(int)); void onRequest(void(*)(void)); - inline size_t write(unsigned long n) { return write((uint8_t)n); } - inline size_t write(long n) { return write((uint8_t)n); } - inline size_t write(unsigned int n) { return write((uint8_t)n); } - inline size_t write(int n) { return write((uint8_t)n); } + inline size_t write(unsigned long n) { return write(static_cast(n)); } + inline size_t write(long n) { return write(static_cast(n)); } + inline size_t write(unsigned int n) { return write(static_cast(n)); } + inline size_t write(int n) { return write(static_cast(n)); } using Print::write; void onService(void); private: + // Container of rxBuffer, txBuffer and srvBuffer const TwoWireBuffer::Buffers& buffers; - // RX Buffer inline uint8_t* rxBuffer() const; uint8_t rxBufferIndex; @@ -93,13 +93,13 @@ class TwoWire : public Stream { void (*onReceiveCallback)(int); // Called before initialization - void (*onBeginCallback)(void); + void (*const onBeginCallback)(void); // Called after deinitialization - void (*onEndCallback)(void); + void (*const onEndCallback)(void); // TWI instance - Twi *twi; + Twi * const twi; // TWI state enum TwoWireStatus { @@ -114,12 +114,12 @@ class TwoWire : public Stream { TwoWireStatus status; // TWI clock frequency - static const uint32_t TWI_CLOCK = 100000; + static constexpr uint32_t TWI_CLOCK = 100000; uint32_t twiClock; // Timeouts ( - static const uint32_t RECV_TIMEOUT = 100000; - static const uint32_t XMIT_TIMEOUT = 100000; + static constexpr uint32_t RECV_TIMEOUT = 100000; + static constexpr uint32_t XMIT_TIMEOUT = 100000; }; #if WIRE_INTERFACES_COUNT > 0 From 0e3c6709a77bc0cdd291f53f6aed73a956d1bbc8 Mon Sep 17 00:00:00 2001 From: dac1e Date: Fri, 3 Jan 2025 19:19:27 +0100 Subject: [PATCH 3/3] Functions that just cast parameters and forward became inline for better speed and less code size. --- libraries/Wire/src/Wire.cpp | 20 -------------------- libraries/Wire/src/Wire.h | 37 ++++++++++++++++++++++++++----------- 2 files changed, 26 insertions(+), 31 deletions(-) diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index fd3a7623..7f88cc73 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -186,22 +186,6 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres return readed; } -uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) { - return requestFrom(static_cast(address), static_cast(quantity), static_cast(0), static_cast(0), static_cast(sendStop)); -} - -uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity) { - return requestFrom(static_cast(address), static_cast(quantity), static_cast(true)); -} - -uint8_t TwoWire::requestFrom(int address, int quantity) { - return requestFrom(static_cast(address), static_cast(quantity), static_cast(true)); -} - -uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop) { - return requestFrom(static_cast(address), static_cast(quantity), static_cast(sendStop)); -} - void TwoWire::beginTransmission(uint8_t address) { status = MASTER_SEND; @@ -210,10 +194,6 @@ void TwoWire::beginTransmission(uint8_t address) { txBufferLength = 0; } -void TwoWire::beginTransmission(int address) { - beginTransmission(static_cast(address)); -} - // // Originally, 'endTransmission' was an f(void) function. // It has been modified to take one parameter indicating diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index 0b83c7a0..36920120 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -44,14 +44,29 @@ class TwoWire : public Stream { void end(); void setClock(uint32_t); void beginTransmission(uint8_t); - void beginTransmission(int); + inline void beginTransmission(int address) { + beginTransmission(static_cast(address)); + } uint8_t endTransmission(void); - uint8_t endTransmission(uint8_t); - uint8_t requestFrom(uint8_t, uint8_t); - uint8_t requestFrom(uint8_t, uint8_t, uint8_t); + uint8_t endTransmission(uint8_t); uint8_t requestFrom(uint8_t, uint8_t, uint32_t, uint8_t, uint8_t); - uint8_t requestFrom(int, int); - uint8_t requestFrom(int, int, int); + inline uint8_t requestFrom(uint8_t address, uint8_t quantity) { + return requestFrom(static_cast(address), + static_cast(quantity), static_cast(true)); + } + inline uint8_t requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) { + return requestFrom(static_cast(address), + static_cast(quantity), static_cast(0), + static_cast(0), static_cast(sendStop)); + } + inline uint8_t requestFrom(int address, int quantity) { + return requestFrom(static_cast(address), + static_cast(quantity), static_cast(true)); + } + inline uint8_t requestFrom(int address, int quantity, int sendStop) { + return requestFrom(static_cast(address), + static_cast(quantity), static_cast(sendStop)); + } size_t write(uint8_t) override; size_t write(const uint8_t *, size_t) override; int available(void) override; @@ -61,11 +76,11 @@ class TwoWire : public Stream { void onReceive(void(*)(int)); void onRequest(void(*)(void)); - inline size_t write(unsigned long n) { return write(static_cast(n)); } - inline size_t write(long n) { return write(static_cast(n)); } - inline size_t write(unsigned int n) { return write(static_cast(n)); } - inline size_t write(int n) { return write(static_cast(n)); } - using Print::write; + inline size_t write(unsigned long n) { return write(static_cast(n)); } + inline size_t write(long n) { return write(static_cast(n)); } + inline size_t write(unsigned int n) { return write(static_cast(n)); } + inline size_t write(int n) { return write(static_cast(n)); } + using Print::write; void onService(void);