Andriy Makukha / Mbed 2 deprecated football_project_wo_output

Dependencies:   mbed

Fork of football_project by MZJ

Radio.cpp

Committer:
AntonLS
Date:
2016-02-12
Revision:
69:a3295b74209e
Parent:
68:0c96bb3d73a7
Child:
70:bd4b1e19a0c6

File content as of revision 69:a3295b74209e:

#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()
{
    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);
        radio.receiveDone();  //// Prevent radio from going to standby or sleep. (Should never 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);

    if( retval )
    {
        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();
}