As previously mentioned, we have already created a radio object class for the RFM69HCW radios. You can use it in this project and not worry about creating your own. However if you would like to implement some other means of transmitting data between your devices you would start with the baseRadio
class and make an extension of it with the specifics for your particular radio.
Our implementation of the RF69Radio
class is based upon the RadioHead
Library, therefore our baseRadio
class closely resembles some of the methods used in RadioHead
. If you create another transport system that is not based on RadioHead
you will have to conform to our API which might be a little more difficult.
class baseRadio { public: uint8_t myPlayerNum; //my radios address uint8_t otherPlayerNum; //opponent's radio address virtual bool setup(uint8_t myPlayerNum, uint8_t otherPlayerNum)=0; virtual bool send(uint8_t* packet_ptr,uint8_t len)=0; virtual bool recvTimeout(uint8_t* packet_ptr,uint8_t* len_ptr,uint16_t timeout)=0; virtual bool recv(uint8_t* packet_ptr,uint8_t* len_ptr)=0; virtual bool available(void)=0; };
Note that this is an abstract class that cannot be instantiated itself. All of the methods are pure virtual so you will have to implement all of them.
Each device has its own unique address. Player 1 will be device #1 and Player 2 will be device #2. This device number is the ONLY difference between the software on one device versus the other.
-
bool setup(uint8_t myPlayerNum, uint8_t otherPlayerNum);
-- Gets called ONCE during yourGame.setup()
call inside your main programsetup()
. Returnstrue
if the setup was successful. -
bool send(uint8_t* packet_ptr,uint8_t len);
-- Sends a packet of data starting at memory addresspacket_ptr
with the number of bytes specified bylen
. Returnstrue
if sent data was acknowledged as received. -
bool recvTimeout(uint8_t* packet_ptr,uint8_t* len_ptr,uint16_t timeout);
-- Attempts to receive a packet and waits until the specified timeout. Thepacket_ptr
is the start address of the data. Thelen_ptr
points to auint8_t
specifying the size of our buffer. Upon return it passes back the actual number of bytes received. Returns true if data was received before the timeout. -
bool recv(uint8_t* packet_ptr,uint8_t* len_ptr);
-- If data is available it receives it. Parameters are the same as the first two ofrecvTimeout
explained above. Returnstrue
if successful. -
bool available(void);
-- Returnstrue
if data is available to be received.
See the discussion on basePacket
about how we determine the start address in the length of the data to send.
Our RF69Radio object class
The RadioHead
library offers an advanced packet transmission system called RHReliableDatagram
that includes encrypting the data, an automatic acknowledgment of a packet received, and multiple retries if an initial transmission doesn't get through. All of this is completely transparent to us. We just send or receive using the methods we defined in our baseRadio
class which in turn call similar methods in the RHReliableDatagram
library.
Every packet which is sent is acknowledged by the receiving device using a system that is invisible to us. So for example if send a Move
packet, when it is received by the other device it sends a hidden acknowledgment back to us to let us know the move was received. This is not the Results
packet that we ourselves send back. This is a behind-the-scenes acknowledgment. When the other device sends a Results
packet in response to our move, it also is acknowledged. Only after multiple failures to receive an acknowledgment do we get a packet error. This makes for extremely reliable data transmission. If you are implementing a different type of radio and it is supported by RadioHead
and RHReliableDatagram
then you should definitely take advantage of that system.
The only errors we are likely to see is if one device is too busy perhaps playing a sound file or doing something else that would prevent it from sending an acknowledgment signal. This would cause a fatal error in our code. At some point we might try to implement a way to recover such mistakes but keep in mind that we only get this failure after the RHReliableDatagram
system has already tried multiple times so it is unlikely we can do anything to recover from such errors. In implementing the sound effects in the Battleship game we created a special myDelay(amount)
function to use instead of the traditional Arduino delay(amount)
. It includes a yield()
statement and it seemed to solve many of our conflicts between packet transmission and sound effects.
Page last edited March 08, 2024
Text editor powered by tinymce.