00001 // RF22ReliableDatagram.h 00002 // 00003 // Author: Mike McCauley (mikem@open.com.au) 00004 // Copyright (C) 2011 Mike McCauley 00005 // $Id: RF22ReliableDatagram.h,v 1.6 2011/02/15 01:18:03 mikem Exp $ 00006 00007 #ifndef RF22ReliableDatagram_h 00008 #define RF22ReliableDatagram_h 00009 00010 #include <RF22Datagram.h> 00011 00012 // The acknowledgement bit in the FLAGS 00013 #define RF22_FLAGS_ACK 0x80 00014 00015 ///////////////////////////////////////////////////////////////////// 00016 /// \class RF22ReliableDatagram RF22ReliableDatagram.h <RF22ReliableDatagram.h> 00017 /// \brief RF22 subclass for sending addressed, acknowledged, retransmitted datagrams. 00018 /// 00019 /// Extends RF22Datagram to define addressed, reliable datagrams with acknowledgement and retransmission. 00020 /// Based on RF22Datagram, adds flags and sequence numbers. RF22ReliableDatagram is reliable in the sense 00021 /// that messages are acknowledged, and unacknowledged messages are retransmitted until acknowledged or the 00022 /// retries are exhausted. 00023 /// When addressed messages are sent (by sendtoWait()), it will wait for an ack, and retransmit 00024 /// after timeout until an ack is received or retries are exhausted. 00025 /// When addressed messages are collected by the application (by recvfromAck()), 00026 /// an acknowledgement is automatically sent. 00027 /// 00028 /// The retransmit timeout is randomly varied between timeout and timeout*2 to prevent collisions on all 00029 /// retries when 2 nodes happen to start sending at the same time . 00030 /// 00031 /// Each new message sent by sendtoWait() has its ID incremented. 00032 /// 00033 /// An ack consists of a message with: 00034 /// - TO set to the from address of the original message 00035 /// - FROM set to this node address 00036 /// - ID set to the ID of the original message 00037 /// - FLAGS with the RF22_FLAGS_ACK bit set 00038 /// 00039 /// Part of the Arduino RF22 library for operating with HopeRF RF22 compatible transceivers 00040 /// (see http://www.hoperf.com) 00041 class RF22ReliableDatagram : public RF22Datagram 00042 { 00043 public: 00044 /// Constructor. 00045 /// \param[in] thisAddress The address to assign to this node. Defaults to 0 00046 /// \param[in] slaveSelectPin the Arduino pin number of the output to use to select the RF22 before 00047 /// accessing it 00048 /// \param[in] interrupt The interrupt number to use. Default is interrupt 0 (Arduino input pin 2) 00049 RF22ReliableDatagram(uint8_t thisAddress = 0, uint8_t slaveSelectPin = 10, uint8_t interrupt = 0); 00050 00051 /// Sets the minimum retransmit timeout. If sendtoWait is waiting for an ack 00052 /// longer than this time (in milliseconds), 00053 /// it will retransmit the message. Defaults to 200ms. The timeout is measured from the end of 00054 /// transmission of the message. It must be at least longer than the the transmit 00055 /// time of the acknowledgement (6 octets) plus the latency/poll time of the receiver. 00056 /// The actual timeout is randomly varied between timeout and timeout*2. 00057 /// \param[in] timeout The new timeout period in milliseconds 00058 void setTimeout(uint16_t timeout); 00059 00060 /// Sets the max number of retries. Defaults to 3. If set to 0, the message will only be sent once. 00061 /// sendtoWait will give up and return false if there is no ack received after all transmissions time out. 00062 /// param[in] retries The maximum number a retries. 00063 void setRetries(uint8_t retries); 00064 00065 /// Send the message and waits for an ack. Returns true if an acknowledgement is received. 00066 /// Synchronous: any message other than the desired ACK received while waiting is discarded. 00067 /// Blocks until an ACK is received or all retries are exhausted (ie up to retries*timeout milliseconds). 00068 /// \param[in] address The address to send the message to. 00069 /// \param[in] buf Pointer to the binary message to send 00070 /// \param[in] len Number of octets to send 00071 /// \return true if the message was transmitted and an acknowledgement was received. 00072 boolean sendtoWait(uint8_t* buf, uint8_t len, uint8_t address); 00073 00074 /// If there is a valid message available for this node, send an acknowledgement to the SRC 00075 /// address (blocking until this is complete), then copy the message to buf and return true 00076 /// else return false. 00077 /// If a message is copied, *len is set to the length.. 00078 /// If from is not NULL, the SRC address is placed in *from. 00079 /// If to is not NULL, the DEST address is placed in *to. 00080 /// This is the preferred function for getting messages addressed to this node. 00081 /// If the message is not a broadcast, acknowledge to the sender before returning. 00082 /// You should be sure to call this function frequently enough to not miss any messages 00083 /// It is recommended that you call it in your main loop. 00084 /// \param[in] buf Location to copy the received message 00085 /// \param[in,out] len Available space in buf. Set to the actual number of octets copied. 00086 /// \param[in] from If present and not NULL, the referenced uint8_t will be set to the SRC address 00087 /// \param[in] to If present and not NULL, the referenced uint8_t will be set to the DEST address 00088 /// \param[in] id If present and not NULL, the referenced uint8_t will be set to the ID 00089 /// \param[in] flags If present and not NULL, the referenced uint8_t will be set to the FLAGS 00090 /// (not just those addressed to this node). 00091 /// \return true if a valid message was copied to buf 00092 boolean recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* from = NULL, uint8_t* to = NULL, uint8_t* id = NULL, uint8_t* flags = NULL); 00093 00094 /// Similar to recvfromAck(), this will block until either a valid message available for this node 00095 /// or the timeout expires. Starts the receiver automatically. 00096 /// You should be sure to call this function frequently enough to not miss any messages 00097 /// It is recommended that you call it in your main loop. 00098 /// \param[in] buf Location to copy the received message 00099 /// \param[in,out] len Available space in buf. Set to the actual number of octets copied. 00100 /// \param[in] timeout Maximum time to wait in milliseconds 00101 /// \param[in] from If present and not NULL, the referenced uint8_t will be set to the SRC address 00102 /// \param[in] to If present and not NULL, the referenced uint8_t will be set to the DEST address 00103 /// \param[in] id If present and not NULL, the referenced uint8_t will be set to the ID 00104 /// \param[in] flags If present and not NULL, the referenced uint8_t will be set to the FLAGS 00105 /// (not just those addressed to this node). 00106 /// \return true if a valid message was copied to buf 00107 boolean recvfromAckTimeout(uint8_t* buf, uint8_t* len, uint16_t timeout, uint8_t* from = NULL, uint8_t* to = NULL, uint8_t* id = NULL, uint8_t* flags = NULL); 00108 00109 /// Returns the number of retransmissions 00110 /// we have had to send 00111 /// \return The number of retransmissions since initialisation. 00112 uint16_t retransmissions(); 00113 00114 protected: 00115 /// Send an ACK for the message id to the given from address 00116 /// Blocks until the ACK has been sent 00117 void acknowledge(uint8_t id, uint8_t from); 00118 00119 /// Checks whether the message currently in the Rx buffer is a new message, not previously received 00120 /// based on the from address and the sequence. If it is new, it is acknowledged and returns true 00121 /// \return true if there is a message received and it is a new message 00122 boolean haveNewMessage(); 00123 00124 private: 00125 /// Count of retransmissions we have had to send 00126 uint16_t _retransmissions; 00127 00128 /// The last sequence number to be used 00129 /// Defaults to 0 00130 uint8_t _lastSequenceNumber; 00131 00132 // Retransmit timeout (milliseconds) 00133 /// Defaults to 200 00134 uint16_t _timeout; 00135 00136 // Retries (0 means one try only) 00137 /// Defaults to 3 00138 uint8_t _retries; 00139 00140 /// Array of the last seen sequence number indexed by node address that sent it 00141 /// It is used for duplicate detection. Duplicated messages are re-acknowledged when received 00142 /// (this is generally due to lost ACKs, causing the sender to retransmit, even though we have already 00143 /// received that message) 00144 uint8_t _seenIds[256]; 00145 00146 00147 }; 00148 00149 #endif 00150