Skip to content
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

Support I2C request and add examples #115

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions examples/i2c_reply_datum/i2c_reply_datum.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "I2CTransfer.h"


I2CTransfer myTransfer;

struct __attribute__((packed)) STRUCT {
char z;
float y;
} testStruct;

void I2C_RequestHandler(void)
{
myTransfer.replyWithDatum(testStruct);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tommag I think it would be good to double check that the requested data length matches the struct the sender wants to report. There should be a check for this either at the sketch or lib level. Also, it might be nice to request a specific packet type (Packet ID field)

}

void setup()
{
Serial.begin(115200);

Wire.begin(0x10); // Begin I2C as peripheral (slave) with address 0x10
Wire.onRequest(I2C_RequestHandler); //Setup I2C_RequestHandler function as I2C request callback

myTransfer.begin(Wire);

testStruct.z = '$';
testStruct.y = 4.5;
}


void loop()
{
// Do nothing
}
47 changes: 47 additions & 0 deletions examples/i2c_request_datum/i2c_request_datum.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include "I2CTransfer.h"


I2CTransfer myTransfer;

struct __attribute__((packed)) STRUCT {
char z;
float y;
} testStruct;


/////////////////////////////////////////////////////////////////// Callbacks
void hi()
{
myTransfer.rxObj(testStruct);
Serial.print(testStruct.z);
Serial.println(testStruct.y);
}

// supplied as a reference - persistent allocation required
const functionPtr callbackArr[] = { hi };
///////////////////////////////////////////////////////////////////


void setup()
{
Serial.begin(115200);
Wire.begin(); // Begin I2C as controller (master)

///////////////////////////////////////////////////////////////// Config Parameters
configST myConfig;
myConfig.debug = true;
myConfig.callbacks = callbackArr;
myConfig.callbacksLen = sizeof(callbackArr) / sizeof(functionPtr);
/////////////////////////////////////////////////////////////////

myTransfer.begin(Wire, myConfig);
}


void loop()
{
// Request datum from connected peripheral at address 0x10
// Callback function hi() will be called on reception
myTransfer.requestDatum(sizeof(testStruct), 0x10);
delay(500);
}
11 changes: 8 additions & 3 deletions src/I2CTransfer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ void I2CTransfer::begin(TwoWire& _port, const bool& _debug, Stream& _debugPort)
to send as the payload in the next packet
* const uint8_t &packetID - The packet 8-bit identifier
* const uint8_t &targetAddress - I2C address to the device the packet
will be transmitted to
will be transmitted to. If targetAddress == 0xFF (invalid value in I2C),
data is transmitted as a reply to an I2C request.
Return:
-------
* uint8_t numBytesIncl - Number of payload bytes included in packet
Expand All @@ -66,11 +67,15 @@ uint8_t I2CTransfer::sendData(const uint16_t& messageLen, const uint8_t& packetI

numBytesIncl = packet.constructPacket(messageLen, packetID);

port->beginTransmission(targetAddress);
if (targetAddress < 0xFF)
port->beginTransmission(targetAddress);

port->write(packet.preamble, sizeof(packet.preamble));
port->write(packet.txBuff, numBytesIncl);
port->write(packet.postamble, sizeof(packet.postamble));
port->endTransmission();

if (targetAddress < 0xFF)
port->endTransmission();

return numBytesIncl;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tommag I think if the target address is invalid, the function should return 0 since nothing was transferred. Maybe we could put everything dealing with port writing, port closing, and reporting numBytesIncl in the first if statement and return 0 otherwise

}
Expand Down
49 changes: 48 additions & 1 deletion src/I2CTransfer.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,54 @@ class I2CTransfer
template <typename T>
uint8_t sendDatum(const T& val, const uint8_t& packetID = 0, const uint8_t& targetAddress = 0, const uint16_t& len = sizeof(T))
{
return sendData(packet.txObj(val, packetID, len), packetID, targetAddress);
return sendData(packet.txObj(val, 0, len), packetID, targetAddress);
}

/*
uint8_t I2CTransfer::requestDatum(const uint16_t &len, const uint8_t &packetID=0, const uint8_t &targetAddress=0)
Description:
------------
* Requests "len" number of bytes from the I2C peripheral at specified address.
* Call rxObj() or setup a rx callback to retrieve the requested data.
Inputs:
-------
* const uint16_t &len - Number of bytes to request
* const uint8_t &targetAddress - I2C address to the device the packet
will be transmitted to
Return:
-------
* uint8_t - Number of payload bytes received
*/
uint8_t requestDatum(const uint16_t& len, const uint8_t& targetAddress = 0)
{
uint8_t bytesRead = port->requestFrom(targetAddress, len + PREAMBLE_SIZE + POSTAMBLE_SIZE);
processData();
return bytesRead;
}

/*
uint8_t I2CTransfer::replyWithDatum(const T &val, const uint8_t &packetID=0, const uint16_t &len=sizeof(T))
Description:
------------
* Reply to an I2C request (requestDatum) with an arbitrary object
* Stuffs "len" number of bytes of an arbitrary object (byte, int,
float, double, struct, etc...) into the transmit buffer (txBuff)
starting at the index as specified by the argument "index" and
automatically transmits the bytes in an individual packet
Inputs:
-------
* const T &val - Pointer to the object to be copied to the
transmit buffer (txBuff)
* const uint8_t &packetID - The packet 8-bit identifier
* const uint16_t &len - Number of bytes of the object "val" to transmit
Return:
-------
* uint8_t - Number of payload bytes included in packet
*/
template <typename T>
uint8_t replyWithDatum(const T& val, const uint8_t& packetID = 0, const uint16_t& len = sizeof(T))
{
return sendDatum(val, packetID, 0xFF, len); //Send data with special I2C address 0xFF => don't initiate transmission
}


Expand Down