Author Topic: Sending ACK before sleeping the node?  (Read 4742 times)

MrGlasspoole

  • NewMember
  • *
  • Posts: 35
  • Country: de
Sending ACK before sleeping the node?
« on: January 27, 2017, 08:42:40 AM »
Just found out that the gateway is sending full power and it seems to get ATC working it needs ACK?
So i did put that in my gateway code:
Code: [Select]
byte ackCount=0;

void loop() {

  if (radio.receiveDone()) {
    if (radio.DATALEN != sizeof(Payload)) {
      Serial.print("Invalid Payload received!");
    } else {
      theData = *(Payload*)radio.DATA; // Assume radio.DATA actually contains our struct and not something else
      if (DEBUG) {
        Serial.print("Node:");
        Serial.print(theData.nodeId);
        Serial.print(", Temp:");
        Serial.print(theData.temp);
        Serial.print(", Vcc:");
        Serial.print(theData.vcc);
        Serial.print(", TX Level:");
        Serial.print(theData.tx);
        Serial.print(", RSSI:");
        Serial.print(radio.RSSI);
        Serial.println();
        Serial.print("TX Level:");
        Serial.print(radio._transmitLevel,DEC); // Current transmit level used by this sender
      }
    }

    if (radio.ACKRequested()) { // When a node requests an ACK, respond to the ACK
      uint16_t theNodeID = radio.SENDERID;
      radio.sendACK();
      Serial.print(" - ACK sent.");
      if (ackCount++%3==0) {
        Serial.print(" Pinging node ");
        Serial.print(theNodeID);
        Serial.print(" - ACK...");
        delay(3); //need this when sending right after reception .. ?
        if (radio.sendWithRetry(theNodeID, "ACK TEST", 8, 0)) {  // 0 = only 1 attempt, no retries
          Serial.print("ok!");
          Serial.print(", RSSI:");
          Serial.print(radio.getAckRSSI(),DEC); // This sender's RSSI acked back from the receiving node (Gateway)
        } else {
          Serial.print("nothing");
        }
      }   
    }
    Serial.println();
  }

}

What i can't figure out is the battery powered node.
Do i need "radio.receiveDone" for "radio.ACKRequested" to work?
Where do i place "radio.ACKRequested" that the gateway gets the ACK before putting the node to sleep?

Code: [Select]
static void rfwrite() {
 
  if (radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData), RETRY_LIMIT, ACK_TIME)) {
    if (DEBUG) {
      Serial.print("ACK received! ");
      Serial.print("Sending ");
      Serial.print(sizeof(theData));
      Serial.print(" bytes...");
      Serial.println();
      Serial.print("Node:");
      Serial.print(theData.nodeId);
      Serial.print(", Temp:");
      Serial.print(theData.temp);
      Serial.print(", Vcc:");
      Serial.print(theData.vcc);
      Serial.print(", TX Level:");
      Serial.print(radio._transmitLevel,DEC); // Current transmit level used by this sender
      Serial.print(", RSSI:");
      Serial.println(radio.getAckRSSI(),DEC); // This sender's RSSI acked back from the receiving node (Gateway)
      Serial.flush();
    }

    if (radio.ACKRequested()) {
      radio.sendACK();
      Serial.print(" - ACK sent.");
      Serial.flush();
    }
   
    //radio.sleep(); // Put radio to sleep
  } else {
    if (DEBUG) {
      Serial.println("No ACK response!");
      Serial.flush();
    }
    Sleepy::loseSomeTime(RETRY_PERIOD * 1000); // If no ack received wait and try again
  }

}

TomWS

  • Hero Member
  • *****
  • Posts: 1930
Re: Sending ACK before sleeping the node?
« Reply #1 on: January 27, 2017, 09:04:42 AM »
@Mr Glasspoole,
To answer your question re the receive side, no, you don't need to explicitly process the ACK, this is handled in sendWithRetry() if ATC is enabled.  sendWithRetry() requires an ACK to know that the transmission was successful.  The ATC control info is automatically returned with the ACK.

Looking at your gateway code, however, I see an exposure.  You should try to ACK as soon as you can.  In your code you're printing out the received data before sending the ACK.  It is always my recommendation that you save your received data in a local buffer (before printing or processing), send the ACK, and then do whatever you want with the data received.  The reason you should save it locally is that it may get wiped out by a subsequent RX after you send the ACK.

Tom

MrGlasspoole

  • NewMember
  • *
  • Posts: 35
  • Country: de
Re: Sending ACK before sleeping the node?
« Reply #2 on: January 27, 2017, 10:41:44 AM »
Isn't the ACK not the first thing that happens?
I tried putting "radio.ACKRequested" in front of "radio.DATA" and get "Invalid Payload received!".

It is always my recommendation that you save your received data in a local buffer (before printing or processing), send the ACK, and then do whatever you want with the data received.
Why?:
1. save data > send ACK > process data
and not
2. send ACK > process data

There should be only data after sending the ACK because without ACK the sender node does not send the data?

With that code on the gateway and node as is, I guess the node goes to sleep after receiving the "radio.sendACK" from the gateway.
So when that pinging thing happens the node is sleeping?


TomWS

  • Hero Member
  • *****
  • Posts: 1930
Re: Sending ACK before sleeping the node?
« Reply #3 on: January 27, 2017, 05:38:16 PM »
Isn't the ACK not the first thing that happens?
I don't understand this question.  The first thing that happens, in the case of receive, is 'receive'.  The second thing, which I didn't notice but was in your previous code, is to save the data (and any other attributes you need, like all those used in the Serial.print statements), the next thing to do is to test and send the ACK - and do all this before your DEBUG serial print statements.
[/quote]

Tom

joelucid

  • Hero Member
  • *****
  • Posts: 868
Re: Sending ACK before sleeping the node?
« Reply #4 on: January 27, 2017, 06:09:35 PM »
I think receive should just be a method that takes a pointer into which to copy any received data. Then receive should copy the data to that destination, send the ack and return. That way it's all automatic and nobody needs to deal with this stuff. And you don't need an extra 61 bytes for temporary storage.

MrGlasspoole

  • NewMember
  • *
  • Posts: 35
  • Country: de
Re: Sending ACK before sleeping the node?
« Reply #5 on: January 28, 2017, 02:13:59 AM »
So the ACK acknowledges the receipt of the data?
I thought the ACK is there to tell the node that the gateway is there before the data is send...

Nobody does sleeping and ACK on battery nodes? No example because i can't figure it out.

I ask myself if it makes sense to do that ACK only every third time.
How much shorter would the battery life if doing it every time?

ChemE

  • Sr. Member
  • ****
  • Posts: 419
  • Country: us
Re: Sending ACK before sleeping the node?
« Reply #6 on: January 28, 2017, 02:45:31 AM »
In most schemes ACK is sent by the receiver to indicate "Hey listen, thanks.  I got your packet, had a look at it, and it all checks out so thanks again for that packet."  The transmitter listens for the ACK and if it doesn't get it back in a certain amount of time assumes that either the packet never got through or had errors and so sends another packet and waits for another ACK.

A battery node requesting ACKs comes down to how critical a single packet is.  My TH nodes don't request ACKs because if I miss a temperature/humidity reading it really doesn't matter.  As long as one gets through every five minutes, that is plenty.  Now a motion sensor for a burglar alarm, yeah that is going to request an ACK and keep sending until the packet of "someone is out there!" gets through and I know it got through.

Obviously, putting the radio into receive mode and listening/polling for the ACK just after a transmission takes extra energy and so will cut the life versus no ACKs.  There could be different ACKs too, I could imagine a NAK where the receiver signals back "got your packet but the parity bit or CRC didn't check out" and so the transmitter resends but at the same power level since the packet got through.

MrGlasspoole

  • NewMember
  • *
  • Posts: 35
  • Country: de
Re: Sending ACK before sleeping the node?
« Reply #7 on: January 28, 2017, 03:26:43 AM »
The reason for locking into it is because nodes are in different places and i want to know if RSSI from the Gateway is ok - so i can adjust it and don't need the gateway to send full power all the time.

At the moment i don't see the RSSI the node receives and the gateways tx level is always 31.

ChemE

  • Sr. Member
  • ****
  • Posts: 419
  • Country: us
Re: Sending ACK before sleeping the node?
« Reply #8 on: January 28, 2017, 04:46:18 AM »
If I am understanding you correctly, you want the gateway to broadcast at the lowest possible power level such that it can reach all your nodes.  If that is the case, the gateway will need to broadcast a packet to node 255 which will trigger every node on that network.  In this way, every node will get an RSSI which it can send back on its next packet to the gateway.  The RSSI each node gets indicates the strength of signal from the gateway to that node.  Once the gateway gets all the RSSIs back, if all are much stronger than say -90dB, it can adjust its power level downward slowly until it starts getting some -90dBs back.

ChemE

  • Sr. Member
  • ****
  • Posts: 419
  • Country: us
Re: Sending ACK before sleeping the node?
« Reply #9 on: January 28, 2017, 04:53:09 AM »
At the moment i don't see the RSSI the node receives and the gateways tx level is always 31.

I may not have answered this part of your question before.  The RSSI each node receives has to be read immediately after each receives a packet from the gateway.  Radio.RSSI on each node immediately after receiving a packet from the gateway will get the RSSI.  You will then need to put that RSSI into a payload and send it back to the gateway.  Only then will the gateway know how well each node heard it.
« Last Edit: January 28, 2017, 04:54:55 AM by ChemE »

MrGlasspoole

  • NewMember
  • *
  • Posts: 35
  • Country: de
Re: Sending ACK before sleeping the node?
« Reply #10 on: January 28, 2017, 06:05:23 AM »
It is not important that the gateway does ATC. It would be enough to set a fixed tx level.
But i need to know the RSSI to know how much tx level i need.

But from what Tom wrote here ATC need to be enabled on the gateway:
https://lowpowerlab.com/forum/moteino/some-clarification-of-automatic-power-control-(rfm69_atc)/msg10035/#msg10035

You will then need to put that RSSI into a payload and send it back to the gateway.
I can see the RSSI the gateway receives from the node on that node with:
Code: [Select]
Serial.println(radio.getAckRSSI(),DEC); // This sender's RSSI acked back from the receiving node (Gateway)
So why would i need to send it with the payload if i want the same in the other direction?


TomWS

  • Hero Member
  • *****
  • Posts: 1930
Re: Sending ACK before sleeping the node?
« Reply #11 on: January 28, 2017, 09:04:19 AM »
It is not important that the gateway does ATC. It would be enough to set a fixed tx level.
But i need to know the RSSI to know how much tx level i need.
As ChemE pointed out, you need to save the radio.RSSI immediately after return from receiveDone() and before any transmission, including sending an ACK.
Quote
But from what Tom wrote here ATC need to be enabled on the gateway:
https://lowpowerlab.com/forum/moteino/some-clarification-of-automatic-power-control-(rfm69_atc)/msg10035/#msg10035
What I said is that you need to include the ATC code in both ends of the connection, otherwise it will be unsupported in the link.  ATC does NOT have to be enabled on any end of the link that is using fixed transmit level.

So,
  • a node and a gateway both have ATC installed in the code,
  • the node enables ATC (by setting a targetRSSI via enableAutoPower mehtod) since it wants to limit transmission power to reduce battery consumption
  • the node sends, with retry, a packet to the gateway.  The retry method requests an ACK from the gateway so that the node knows the packet arrived safely,
  • the gateway receives the packet on the first try and sends an ACK immediately (before the node's retry timer times out).  The ATC code within the gateway sets a flag indicating that the received RSSI (from node to gateway) is included in the ACK packet the gateway sends back to the node.  This is handled automatically by the ATC code.
  • the node's sendWithRetry function receives the ACK from the gateway and sees the RSSI value in the ACK.  The ATC logic, prior to returning to the node's main SW, compares the RSSI value with the node's 'targetRSSI' level and adjusts the transmit level up or down depending on any difference.
  • the node's sendWithRetry returns to the caller with a flag indicating that the transmission was successful.  There are no further transmissions of this packet.

You may notice that none of this works if the gateway's ACK is not sent before the node's retry timer (typically 40mS) times out.

Tom

MrGlasspoole

  • NewMember
  • *
  • Posts: 35
  • Country: de
Re: Sending ACK before sleeping the node?
« Reply #12 on: January 28, 2017, 10:45:32 AM »
you need to include the ATC code in both ends of the connection, otherwise it will be unsupported in the link.  ATC does NOT have to be enabled on any end of the link that is using fixed transmit level.
Which code?
So i can comment out (disable ATC):
Code: [Select]
#define ENABLE_ATC      //comment out this line to disable AUTO TRANSMISSION CONTROL
This means RFM69 is used instead of RFM69_ATC:
Code: [Select]
#ifdef ENABLE_ATC
  RFM69_ATC radio;
#else
  RFM69 radio;
#endif

As ChemE pointed out, you need to save the radio.RSSI immediately after return from receiveDone() and before any transmission, including sending an ACK.
In all the examples "radio.sendACK" is at the bottom and there is allot serial.print going on before.
And i don't see something like saving radio.RSSI.

Putting "if radio.ACKRequested" above "if radio.DATALEN" gives "invalid payload".

Edit
Ok i found out the serial output does not need to be inside the "else { theData".
I thought it needs to be there because that is how it is in the examples.
So now it looks like this on the gateway:
Code: [Select]
void loop() {

  if (radio.receiveDone()) {
    if (radio.DATALEN != sizeof(Payload)) {
      #ifdef DEBUG
        Serial.print("Invalid Payload received!");
      #endif // END DEBUG
    } else {
      theData = *(Payload*)radio.DATA; // Assume radio.DATA actually contains our struct and not something else
    } // END radio.DATALEN

    if (radio.ACKRequested()) { // When a node requests an ACK, respond to the ACK
      uint16_t theNodeID = radio.SENDERID;
      radio.sendACK();
      Serial.println("ACK sent! ");
      if (ackCount++%3==0) {
        Serial.print("Pinging node ");
        Serial.print(theNodeID);
        Serial.print(" - ACK...");
        delay(3); //need this when sending right after reception .. ?
        if (radio.sendWithRetry(theNodeID, "ACK TEST", 8, 0)) {  // 0 = only 1 attempt, no retries
          Serial.println("ok!");
        } else {
          Serial.println("nothing");
        }
      }
    } // END radio.ACKRequested
   
    #ifdef DEBUG
      Serial.print("Node:");
      Serial.print(theData.nodeId);
      Serial.print(", Temp:");
      Serial.print(theData.temp);
      Serial.print(", Vcc:");
      Serial.print(theData.vcc);
      Serial.print(", TX Level:");
      Serial.print(theData.tx);
      Serial.print(", RSSI:");
      Serial.print(radio.RSSI);
      Serial.println();
      Serial.print("Gateway TX Level:");
      Serial.print(radio._transmitLevel,DEC); // Current transmit level used by this sender
      Serial.print(", Gateway RSSI:");
      Serial.print(radio.getAckRSSI(),DEC); // This sender's RSSI acked back from the receiving node (Gateway)
      Serial.println();
    #endif // END DEBUG
   
  } // END radio.receiveDone

} // END loop
And i really don't need a "radio.sendACK" or "radio.receiveDone" on the node?

Edit
I made a test.
I removed the sleep from the node and did put:
Code: [Select]
  if (radio.receiveDone()) {
    if (radio.ACKRequested()) {
      radio.sendACK();
      Serial.print(" - ACK sent.");
      Serial.flush();
    }
  }
in the main loop.
Then the ping from the gateway works and tx goes down.
« Last Edit: January 30, 2017, 03:29:16 AM by MrGlasspoole »

MrGlasspoole

  • NewMember
  • *
  • Posts: 35
  • Country: de
Re: Sending ACK before sleeping the node?
« Reply #13 on: February 02, 2017, 12:21:48 AM »
No solution?