What is a typical transmit time for a Moteino RFM69HW_HCW at 915mHz? Using radio.sendWithRetry to transmit a payload of one byte is taking about
43.8mS. That is with 0 retries. With one retry, that time about doubles. Without the radio.sendWithRetry , my basic loop is about 0.008mS.
Do those time seem right?
Here is the fragment of code I'm using:
startTime = micros();
if (radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData),0))
{
(no code here)
}
else
{
(no code here)
}
endTime = micros();
I believe that sendWithRetry() waits for an ACK even if the retry count is 0, which makes sense, you want to know the message got there or not. In this case, then, the timing will depend on the minimum of the time it takes the other end to ACK and the timeout value (which defaults to 40mS). You can change the timeout value - it is one of the parameters to the method.
Tom
Thanks, Tom I think you're on to the problem. I don't think the Send sketch retry is receiving an ACK from the Receive sketch. Here a little more of the Send code:
startTime = micros();
if (radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData),0))// Send new data
{
Serial.print("Data sent to Node ");Serial.print(GATEWAYID); Serial.println(" & ACKed");
} // data successfully send to Gateway and acknowledged by Gateway
else
{
Serial.println(" nothing...");
}
endTime = micros();
The radio.sendWithRetry above returns false "nothing...", even though the Receive sketch is actually receiving the Send payload.
Here's some of the Receive code, maybe this will help:
void loop()
{
if (radio.receiveDone())
{
Serial.print("Received from Node ");Serial.print(radio.SENDERID, DEC);
Serial.print(" [RX_RSSI:");Serial.print(radio.readRSSI());Serial.println("]");
if (promiscuousMode)
{
Serial.print("to [");Serial.print(radio.TARGETID, DEC);Serial.print("] ");
}
if (radio.DATALEN != sizeof(Payload))
Serial.print("Invalid payload received, not matching Payload struct!");
else
{
theData = *(Payload*)radio.DATA; //assume radio.DATA actually contains our struct and not something else
if ((radio.SENDERID) == 99) //Outside Node, Moteino 2
{
(I do some Serial.printing here)
}
else if ((radio.SENDERID) == 98) //Inside Node, Moteino 1
{
(I do more Serial.printing here)
}
}
if (radio.ACKRequested())
{
byte theNodeID = radio.SENDERID;
radio.sendACK();
Serial.print ("ACK sent to Node "); Serial.println(radio.SENDERID, DEC);
}
}
}
I'll wager that if you move:
if (radio.ACKRequested())
{
byte theNodeID = radio.SENDERID;
radio.sendACK();
Serial.print ("ACK sent to Node "); Serial.println(radio.SENDERID, DEC);
}
to the top of your section after receiveDone(), you'll have better success. The examples for the library are notoriously bad in wasting time between receipt of a message and ACKing it. Note, however, that once you start replying, the original message content is in jeopardy, so, IMO, it is ALWAYS best to:
1. SAVE EVERYTHING YOU WANT FROM A MESSAGE (sender, data, len, etc)
2. ACK as soon as you can.
After that, then you can leisurely print anything your want...
Tom
MightyHat and some others have ACK_TIME defined, does that do anything then?
Tom, I moved the radio.ACKRequested() as you suggested to just after receiveDone(). That improved the loop time at the Send sketch. However, I was getting a "Invalid payload received, not matching Payload struct!" error, so I moved the DATALEN function above radio.ACKRequested() and that cleared that error. The transmit times are just about 10mS for a small payload. This seems in line with what I've read elsewhere on the Forum.
Here is my current version of Receive:
void loop()
{
if (radio.receiveDone())
{
Serial.print("Received from Node ");Serial.print(radio.SENDERID, DEC);
Serial.print(" [RX_RSSI:");Serial.print(radio.readRSSI());Serial.println("]");
if (radio.DATALEN != sizeof(Payload))
Serial.print("Invalid payload received, not matching Payload struct!");
if (radio.ACKRequested()) //// check whether an ACK was requested in the last received packet (non-broadcasted packet)
{
byte theNodeID = radio.SENDERID;
radio.sendACK();
Serial.print ("ACK sent to Node "); Serial.println(radio.SENDERID, DEC);
//When a node requests an ACK, respond to the ACK
}
if (promiscuousMode)
{
Serial.print("to [");Serial.print(radio.TARGETID, DEC);Serial.print("] ");
}
theData = *(Payload*)radio.DATA; //assume radio.DATA actually contains our struct and not something else
if ((radio.SENDERID) == 99) //Outside Node, Moteino 2
{
//Several Serial.prints here...
}
else if ((radio.SENDERID) == 98) //Inside Node, Moteino 1
{
//Several more Serial.prints here...
}
}
}
Quote from: DonpK on February 25, 2018, 05:05:19 PM
Tom, I moved the radio.ACKRequested() as you suggested to just after receiveDone(). That improved the loop time at the Send sketch. However, I was getting a "Invalid payload received, not matching Payload struct!" error, so I moved the DATALEN function above radio.ACKRequested() and that cleared that error. ...
I believe my entire recommendation was:
Quote
Note, however, that once you start replying, the original message content is in jeopardy, so, IMO, it is ALWAYS best to:
1. SAVE EVERYTHING YOU WANT FROM A MESSAGE (sender, data, len, etc)
2. ACK as soon as you can.
Tom
QuoteI believe my entire recommendation was:
Quote
Note, however, that once you start replying, the original message content is in jeopardy, so, IMO, it is ALWAYS best to:
1. SAVE EVERYTHING YOU WANT FROM A MESSAGE (sender, data, len, etc)
2. ACK as soon as you can.
Indeed it was. I apologize for missing that.
I moved
theData = *(Payload*)radio.DATA; up to the top of the
radio.receiveDone() function. Should I also move the ACK up to just below
theData =, or does it make sense to identify node ID and test the packet with
radio.DATALEN != sizeof(Payload) before sending the ACK?
if (radio.receiveDone())
{
theData = *(Payload*)radio.DATA; //Save incoming payload
Serial.print("Received from Node ");Serial.print(radio.SENDERID, DEC);
Serial.print(" [RX_RSSI:");Serial.print(radio.readRSSI());Serial.println("]");
if (radio.DATALEN != sizeof(Payload))
Serial.print("Invalid payload received, not matching Payload struct!");
if (radio.ACKRequested()) //// check whether an ACK was requested in the last received packet (non-broadcasted packet)
{
byte theNodeID = radio.SENDERID;
radio.sendACK();
Serial.print ("ACK sent to Node "); Serial.println(radio.SENDERID, DEC);
//When a node requests an ACK, respond to the ACK
}
Quote from: DonpK on February 26, 2018, 03:38:58 PM
I moved theData = *(Payload*)radio.DATA; up to the top of the radio.receiveDone() function. Should I also move the ACK up to just below theData =, or does it make sense to identify node ID and test the packet with radio.DATALEN != sizeof(Payload) before sending the ACK?
...
Move the Serial prints until after you send the ACK - this is the most efficient. However, if you want to verify the contents prior to sending ACK (which is a good thing to do), then check the contents, but don't print anything until after you've sent the ACK. If the contents are incorrect, it would be very worthwhile to send an error code with the ACK. This way, your sending node knows about the error.
Note that the prototype for sendACK is:
void sendACK(const void* buffer = "", uint8_t bufferSize=0);
So... in the case of an error, you could:
int errorCode = 0;
// check for errors, set error code accordingly...
...
// now you're ready to sendACK...
if (errorCode)
radio.sendACK(&errorCode, sizeof(errorCode));
else
radio.sendACK(); // or simply send the zero errorCode for even simpler implementation
Now, the next question you're going to ask is how the original sender gets the error code from the ACK...
This is left as an exercise for the student...
Tom
Thank you, Tom, for your help on this. I've made some good progress.
Quotehow the original sender gets the error code from the ACK...
I'll take this as my homework assignment!
Don