I thought it was an independent function.
Sending the ACK is an independent function. However, it's use is in response to receiving a message that was sent using sendWithRetry().
On the receiving side, you'll get a positive return from receiveDone() (meaning that you received a message) and you'll have to check to see if ACKrequested() is true. If it is, then you send the ACK using sendACK() back to SENDERID.
Note that sendWithRetry() has two parameters related to ACK, 'retries' and 'retryWaitTime'. The defaults for these are 2 and 40 respectively. If you sendWithRetry() using the defaults, the sender will send the packet and then wait for an ACK. As soon as an ACK is received, the sendWithRetry() returns true - the transmission was successful. However, if no ack is returned within the wait time (40mS is default), then sendWithRetry() will try again, sending the message and waiting for ACK. It will do this 2 more times or a total of three transmissions before it returns false;
Note if retries = 0 then sendWithRetry() will send and wait only one time, it will not retry, but it will wait for an ACK to the message that was sent.
Finally, note that the wait time defaults to 40mS so don't waste a lot of time returning the ACK. Most of the examples in the RFM library, IMO, violate this rule. There are print statements between the receiveDone() and the sendACK(), which I believe is a very bad practice and certainly a bad example. A better example is to save all the received data, ACK immediately, and THEN print whatever stuff you want to print.
Tom