Radio communication with NRF24

Dependents:   F030

Revision:
0:9f5a444886a8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ssRadio.cpp	Fri Oct 06 20:17:36 2017 +0000
@@ -0,0 +1,180 @@
+#include "ssRadio.h"
+//#include "printf.h"
+
+SSRadio::SSRadio(SPI *spi, NodeConfig *config) : rf24(spi, config->cePin, config->csnPin) {
+    
+    this->config = config;
+    
+    this->myAddress = config->nodeId;
+    this->gatewayAddress = ((uint64_t)config->netPrefix << 16) + config->gwId;
+    
+    this->sendSlot = -1;
+    this->freeSlot = -1;
+    this->slot_ms = 4;
+    
+    this->onConnect = NULL;
+    this->onDisconnect = NULL;
+    this->onReceiveData = NULL;
+}
+
+void SSRadio::init() {
+
+    rf24.begin();
+    rf24.enableDynamicAck();
+    rf24.enableDynamicPayloads();
+    rf24.setCRCLength(RF24_CRC_16);
+    rf24.openReadingPipe(0, config->syncAddress);
+    rf24.openReadingPipe(1, ((uint64_t)config->netPrefix << 16) + config->nodeId);
+    rf24.setAutoAck(0, false);   // Disable autoACK on broadcast
+    rf24.setAutoAck(1, true);    // Ensure autoACK is enabled on data/control
+    rf24.setChannel(config->channel);
+    rf24.setPALevel(config->paLevel);
+    rf24.setDataRate(config->dataRate);
+
+    txCounter = 0;
+    rxCounter = 0;
+    
+    txQueueLength = 0;
+    rxQueueLength = 0;
+    
+    rf24.startListening();  
+  // IF_SERIAL_DEBUG(rf24.printDetails());  
+}
+    
+bool SSRadio::isRunning() {
+    return rf24.isChipConnected();
+}
+    
+void SSRadio::loop() {
+    
+    // Checking incoming frames
+    uint8_t pipenum;
+    if (rf24.available(&pipenum)) {
+        IF_SERIAL_DEBUG(Serial.println(F("Incoming packet.")));
+        uint8_t ps = rf24.getDynamicPayloadSize();
+        if (ps > 0) {
+            rf24.read(packetRx, ps);
+            if (pipenum == 0) {
+                receiveSyncFrame(packetRx, ps);
+            } else {
+                receiveDataFrame(packetRx, ps);
+            }
+        }
+    }
+    
+    long now = us_ticker_read() / 1000;
+    // Check the queues
+    bool sent = false;
+    if (txQueueLength > 0) {
+                
+        if (sendSlot > -1) {
+            // There is a timeslot now for the transmission
+            if ((now > lastSync + sendSlot * slot_ms) && (now < lastSync + (sendSlot + 1) * slot_ms)) {
+                instantData(txQueue + 2, txQueue[1], txQueue[0]);
+        //Serial.println("sendSlot");
+                sent = true;
+            }
+        }
+        else if (freeSlot > 0) {
+            // When freeSlot is not 0 (nobody is scheduled), then send in the free slot
+            if ((now >= lastSync + freeSlot * slot_ms) && (now <= lastSync + (freeSlot + 1) * slot_ms)) {
+                instantData(txQueue + 2, txQueue[1], txQueue[0]);
+        //Serial.println("freeSlot");
+                sent = true;
+            }
+        }
+        else {
+      // No sync or no others, send immediately
+            instantData(txQueue + 2, txQueue[1], txQueue[0]);
+      //Serial.println("Other");      
+            sent = true;
+        }
+        
+        if (sent) {
+            // Move in the queue;
+            txQueueLength--;
+            if (txQueueLength > 0)
+                memcpy(txQueue, txQueue + 30, txQueueLength * 30);
+        }
+    }
+    
+    // Scheduled tasks
+    if (now > lastSync + 1000) {
+        // last Sync was really long ago
+        sendSlot = -1;
+        freeSlot = -1;
+    }
+}
+
+void SSRadio::receiveSyncFrame(uint8_t *frame, uint8_t size) {
+    
+    lastSync = us_ticker_read() / 1000;
+    
+    // Find self address to get the sending slot
+    uint16_t *nodes = (uint16_t*) frame;
+    sendSlot = -1;
+    //Serial.println("Sync");
+    //Serial.println(size);
+    uint8_t i = 0;
+    while ((i < size / 2) && (nodes[i] != 0)) {
+        //Serial.println(nodes[i]);
+        if (nodes[i] == myAddress) {
+            sendSlot = i;
+        }
+        i++;
+    }
+    if (nodes[i] == 0) {
+        freeSlot = i;
+    }
+}
+
+void SSRadio::receiveDataFrame(uint8_t *frame, uint8_t size) {
+    
+  Packet *p = (Packet*) frame;
+  IF_SERIAL_DEBUG(Serial.println(F("Data frame received.")));
+  if (onReceiveData) {
+    IF_SERIAL_DEBUG(Serial.println(F("Calling onReceiveData.")));
+    (*onReceiveData)(p->fields.payload, p->fields.type, size - 4);
+  }
+}
+
+bool SSRadio::sendData(uint8_t *data, uint16_t type, uint8_t size) {
+    
+    if (txQueueLength == QUEUELEN) return false; // Queue is full
+    
+    uint8_t *frame = txQueue + txQueueLength * 30;
+    frame[0] = size;
+    frame[1] = type & 0xff; // !!! SHOULD be FIXED for extended types
+    memcpy(frame + 2, data, size);
+    
+    txQueueLength ++;
+    
+    return true;
+}
+
+bool SSRadio::instantData(uint8_t *data, uint16_t type, uint8_t size) {
+
+  Packet p;
+  p.fields.address = myAddress;
+  p.fields.type = type & 0xff;
+  p.fields.counter = txCounter ++;
+  memcpy(p.fields.payload, data, size);
+
+    IF_SERIAL_DEBUG(Serial.println(F("Sending data.")));
+    
+  rf24.stopListening();
+  rf24.setRetries(0, 5);
+  rf24.openWritingPipe(gatewayAddress);
+  bool ok = rf24.write(p.raw, size + 4);
+  rf24.startListening();
+
+  if (ok) IF_SERIAL_DEBUG(Serial.println("Success."));
+  else IF_SERIAL_DEBUG(Serial.println("Fail!"));
+  
+    return ok;
+}
+
+void SSRadio::setOnReceiveData(void (*f)(uint8_t *data, uint16_t type, uint8_t len)) {
+  onReceiveData = f;
+}
+