Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of football_project by
Radio.cpp
- Committer:
- AntonLS
- Date:
- 2016-03-02
- Revision:
- 73:ac3588017e32
- Parent:
- 70:bd4b1e19a0c6
- Child:
- 75:1b357bee1839
File content as of revision 73:ac3588017e32:
#include <RFM69.h>
#include <SPI.h>
#include "types.h"
#include "TA.h"
#include "DataStore.hh"
#include "Radio.hh"
#define RADIO_STARTUP_ID 99
#define NETWORKID 101 //the same on all nodes that talk to each other
#define FREQUENCY RF69_915MHZ
//#define IS_RFM69HW //NOTE: uncomment this ONLY for RFM69HW or RFM69HCW
#define ENCRYPT_KEY "EncryptKey123456" // use same 16byte encryption key for all devices on net
#define LED 9 // Anardino miniWireless has LEDs on D9
#define SERIAL_BAUD 115200
#define VERSION "1.0"
#define MSGBUFSIZE 64 // message buffersize, but for this demo we only use:
// 1-byte NODEID + 4-bytes for time + 1-byte for temp in C + 2-bytes for vcc(mV)
//RFM69::RFM69(PinName PinName mosi, PinName miso, PinName sclk,slaveSelectPin, PinName int)
RFM69 radio(P0_24,P0_23,P0_25,P0_28,P0_7);
static bool promiscuousMode = true; // set 'true' to sniff all packets on the same network
extern unsigned long millis();
extern bool is_master;
struct node_id_mapping
{
int mac;
int node_id;
};
struct extended_message
{
Message m;
int mac;
};
struct prev_message // maybe TODO we could have an array of NUM_CONES of these.
{
Message m;
uint8_t msgid;
};
/*
int get_node_id()
{
return my_node_id == RADIO_STARTUP_ID ? 0 : my_node_id;
}
*/
static node_id_mapping nodes[NUM_CONES] = {0};
static int node_idx = 0;
static int my_mac = 0;
void radio_init()
{
radio.initialize(FREQUENCY, datastore_node_id(), NETWORKID);
radio.encrypt(0);
radio.promiscuous(promiscuousMode);
}
/* Gets the node ID which is associated with the
* given mac. If no ID has been given then zero
* is returned.
*
* @param mac - the mac address if the cone
* @returns ID if found else zero
*/
static int get_node_id(int mac)
{
for (int i = 0; i < node_idx; ++i)
{
if (nodes[i].mac == mac)
{
return nodes[i].node_id;
}
}
return 0;
}
/* Process a radio startup message from the master.
*
* @param em - the message from the master
*/
static void slave_process(extended_message *em)
{
if (em->m.command == 'R')
{
// We have been given a node id
datastore_set_node_id(em->m.value);
if( Dbg ) writeToPhone("NID: %d\r\n", datastore_node_id());
// Now reset the radio :)
/// promiscuousMode = false;
radio_init();
}
}
/* Process a radio startup message from a slave.
*
* @param m - the message from the slave
*/
static void master_process(Message *m)
{
byte payload[10] = {0};
int node_id = 0;
if (m->command == 'S')
{
// Message from a cone requesting an ID.
// The payload should be part of the MAC address
node_id = 0;
if (node_idx == 0)
{
node_id = 2;
}
else
{
node_id = nodes[node_idx-1].node_id + 1;
}
int node_found = get_node_id(m->value);
if (node_found == 0)
{
nodes[node_idx].node_id = node_id;
nodes[node_idx++].mac = m->value;
}
else
{
node_id = node_found;
}
// Send the cone its ID
extended_message em;
em.m.cone = 99;
em.m.command = 'R';
em.m.value = node_id;
em.mac = m->value;
payload[0] = (byte)em.m.command;
payload[4] = (byte)em.m.value & 255;
payload[3] = (byte)(em.m.value >> 8);
payload[2] = (byte)(em.m.value >> 16);
payload[1] = (byte)(em.m.value >> 24);
payload[8] = (byte)em.mac & 255;
payload[7] = (byte)(em.mac >> 8);
payload[6] = (byte)(em.mac >> 16);
payload[5] = (byte)(em.mac >> 24);
radio_send_raw( em.m.cone, payload, sizeof(payload), false ); //// NO ACK req.
/// radio.send(em.m.cone, payload, sizeof(payload));
if( Dbg ) writeToPhone("SND: %d %d 0x%x\r\n", em.m.cone, node_id, em.mac);
}
}
void radio_send_raw( uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool requestACK ) ////
{
radio.send( toAddress, buffer, bufferSize, requestACK );
// radio_ensure_rx_mode();
}
void radio_send( Message *m, bool requestACK ) ////
{
static byte payload [6] = {0};
if (m == NULL)
{
return;
}
//if( Dbg ) writeToPhone("SM: %c to: %d frm: %d (%d)\r\n", m->command, m->cone, NODE_ID, m->value);
payload[0] = (byte)m->command;
payload[4] = (byte)m->value & 255;
payload[3] = (byte)(m->value >> 8);
payload[2] = (byte)(m->value >> 16);
payload[1] = (byte)(m->value >> 24);
payload[5] = (byte)++TA::msg_id; //// Msg ID, was: = (byte)'%';
radio_send_raw( m->cone, payload, sizeof(payload), requestACK );
}
void stompage_check()
{
if( --radio.INCNT != 0 )
{
writeToPhone( "LOST MSGS: %d\r\n", radio.INCNT );
radio.INCNT = 0;
}
}
bool radio_receive_complete() //// Currently not used.
{
return radio.receiveDone();
}
bool radio_receive(Message *m)
{
bool retval = false;
bool ensure_rx_mode = false;
//// For msg id feature...
static prev_message mPrev;
static long lastMsgAt = millis();
Message lm;
extended_message em;
do
{
if( m == NULL ) break;
if( radio.receiveDone() )
{
if( radio.TARGETID == datastore_node_id() ) //// Check for stompage...
{
stompage_check();
}
if( !get_crc_ok() ) // CRC error will be rechecked/sent from caller.
{
retval = true;
break;
}
if( (radio.DATALEN < 6) && !radio.ACK_RECEIVED )
{
ensure_rx_mode = true;
RA_DEBUG( "Warn: Short packet\r\n" );
RA_DEBUG( "Warn: Data len %d\r\n", radio.DATALEN );
RA_DEBUG( "Warn: Cmd %c, Frm %d\r\n", radio.DATA[0], radio.SENDERID );
break;
}
lm.cone = radio.SENDERID;
lm.command = radio.DATA[0];
lm.value = ((int)radio.DATA[1] << 24);
lm.value |= ((int)radio.DATA[2] << 16);
lm.value |= (((int)radio.DATA[3]) << 8);
lm.value |= (radio.DATA[4]);
if (is_master && lm.command == 'S')
{
// Don't pass on radio startup messages
master_process(&lm);
break;
}
else if (!is_master && (NODE_ID == 99) && radio.TARGETID == RADIO_STARTUP_ID) //// NODE_ID check allows not using auto node IDs
{
em.mac = (int)radio.DATA[8] & 0xff;
em.mac |= (int)radio.DATA[7] << 8;
em.mac |= (int)radio.DATA[6] << 16;
em.mac |= (int)radio.DATA[5] << 24;
if( Dbg ) writeToPhone("RP: 0x%x\r\n", em.mac);
if (em.mac != my_mac)
{
if( Dbg ) writeToPhone("DM 0x%x\r\n", em.mac);
break; // This message was meant for someone else
}
memcpy(&em.m, &lm, sizeof(Message));
slave_process(&em);
}
else if (radio.TARGETID == datastore_node_id())
{
memcpy(m, &lm, sizeof(Message));
if( !radio.ACK_RECEIVED )
{
//// Check if sender missed an ACK (Got duplicate of last msg, so ignore dup.)
if( (millis() -lastMsgAt < 100) && //// Only consider as dup if w/in 100ms of prev.
(mPrev.m.cone == m->cone) &&
(mPrev.msgid == radio.DATA[5]) )
{ //// ASS-U-ME [for now] last msg is from same cone.
RA_DEBUG( "Ignored dup cmd\r\n" );
radio_send_ack();
ensure_rx_mode = true;
break;
}
memcpy( &mPrev.m, m, sizeof( Message ) ); ////
mPrev.msgid = radio.DATA[5]; ////
lastMsgAt = millis(); ////
if( Dbg ) writeToPhone("GM: %d %c %d\r\n", radio.SENDERID, m->command, m->value);
}
retval = true;
}
}
} while( false );
if( ensure_rx_mode )
{
radio_ensure_rx_mode(); // Will stomp/erase payload data.
}
if( retval )
{
if( get_crc_ok() )
RA_DEBUG( "M: %c %d r:%d\r\n", m->command, m->value, get_rssi() );
if( get_fifo_ov() )
RA_DEBUG( "Radio FIFO Overflow\r\n" );
}
return retval;
}
void radio_ensure_rx_mode()
{
if( RF69_MODE_RX != radio._mode )
{
// Either do this or change the setMode in RFM69.cpp at end of sendFrame() to setMode(RF69_MODE_RX);
while( radio.receiveDone() ); //// Prevent radio from going to standby or sleep. (Shouldn't return true here.)
}
}
void radio_send_ack() ////
{
radio.sendACK( "K", 1 );
// radio_ensure_rx_mode();
}
bool radio_ack_received( int cone )
{
////bool retval = radio.ACKReceived(cone);
bool retval = radio.receiveDone();
if( !get_crc_ok() )
{
writeToPhone( "BAD-CRC on ACK wait\r\n" );
retval = false;
}
if( retval )
{
if( !((radio.SENDERID == cone || cone == RF69_BROADCAST_ADDR) && radio.ACK_RECEIVED) )////...
{
// Got something that wasn't expected ACK. (Paranoia--Haven't seen this happen yet.)
RA_DEBUG( "Got '%c', not ACK!\r\n", (char)radio.DATA[0] );
RA_DEBUG( "Wanted from %u, got from %u\r\n", cone, radio.SENDERID );
retval = false;
}
if( radio.TARGETID == datastore_node_id() )
{
stompage_check();
}
// Note if we ever want to retrieve data from ACK packet: This stomps the packet data.
// radio_ensure_rx_mode();
}
return retval;
}
/* This is only needed for the slave cones, the master
* cone will just return.
*
* If the slave cone doesn't have a valid node ID send out
* the node ID request message to the master cone.
*
* @param mac - the mac address for this cone (currently the first two bytes)
*/
void radio_loop(int mac)
{
static unsigned long last_send = 0L;
unsigned long current = millis();
Message m;
if (my_mac == 0)
{
my_mac = mac;
}
if (is_master)
{
return; // Only needed for slave cones
}
if (datastore_node_id() != RADIO_STARTUP_ID && current - last_send > 1000L)
{
if( Dbg ) writeToPhone("NID: %d\r\n", datastore_node_id());
last_send = current;
}
// Send out an i'm here message
if (datastore_node_id() != RADIO_STARTUP_ID || current - last_send < 1000L)
{
return;
}
m.command = 'S';
m.cone = 1;
m.value = my_mac;
if( Dbg ) writeToPhone("SNM\r\n");
last_send = current;
radio_send( &m, false ); ////
/// radio_send(&m);
}
int16_t get_rssi()
{
return radio.RSSI;
}
bool get_crc_ok()
{
return radio.CRCOK;
}
bool get_fifo_ov()
{
return radio.FIFOV;
}
// for debugging
void read_all_regs()
{
radio.readAllRegs();
}
