Radio communication with NRF24

Dependents:   F030

Committer:
gume
Date:
Fri Oct 06 20:17:36 2017 +0000
Revision:
0:9f5a444886a8
Initial release

Who changed what in which revision?

UserRevisionLine numberNew contents of line
gume 0:9f5a444886a8 1 #include "ssRadio.h"
gume 0:9f5a444886a8 2 //#include "printf.h"
gume 0:9f5a444886a8 3
gume 0:9f5a444886a8 4 SSRadio::SSRadio(SPI *spi, NodeConfig *config) : rf24(spi, config->cePin, config->csnPin) {
gume 0:9f5a444886a8 5
gume 0:9f5a444886a8 6 this->config = config;
gume 0:9f5a444886a8 7
gume 0:9f5a444886a8 8 this->myAddress = config->nodeId;
gume 0:9f5a444886a8 9 this->gatewayAddress = ((uint64_t)config->netPrefix << 16) + config->gwId;
gume 0:9f5a444886a8 10
gume 0:9f5a444886a8 11 this->sendSlot = -1;
gume 0:9f5a444886a8 12 this->freeSlot = -1;
gume 0:9f5a444886a8 13 this->slot_ms = 4;
gume 0:9f5a444886a8 14
gume 0:9f5a444886a8 15 this->onConnect = NULL;
gume 0:9f5a444886a8 16 this->onDisconnect = NULL;
gume 0:9f5a444886a8 17 this->onReceiveData = NULL;
gume 0:9f5a444886a8 18 }
gume 0:9f5a444886a8 19
gume 0:9f5a444886a8 20 void SSRadio::init() {
gume 0:9f5a444886a8 21
gume 0:9f5a444886a8 22 rf24.begin();
gume 0:9f5a444886a8 23 rf24.enableDynamicAck();
gume 0:9f5a444886a8 24 rf24.enableDynamicPayloads();
gume 0:9f5a444886a8 25 rf24.setCRCLength(RF24_CRC_16);
gume 0:9f5a444886a8 26 rf24.openReadingPipe(0, config->syncAddress);
gume 0:9f5a444886a8 27 rf24.openReadingPipe(1, ((uint64_t)config->netPrefix << 16) + config->nodeId);
gume 0:9f5a444886a8 28 rf24.setAutoAck(0, false); // Disable autoACK on broadcast
gume 0:9f5a444886a8 29 rf24.setAutoAck(1, true); // Ensure autoACK is enabled on data/control
gume 0:9f5a444886a8 30 rf24.setChannel(config->channel);
gume 0:9f5a444886a8 31 rf24.setPALevel(config->paLevel);
gume 0:9f5a444886a8 32 rf24.setDataRate(config->dataRate);
gume 0:9f5a444886a8 33
gume 0:9f5a444886a8 34 txCounter = 0;
gume 0:9f5a444886a8 35 rxCounter = 0;
gume 0:9f5a444886a8 36
gume 0:9f5a444886a8 37 txQueueLength = 0;
gume 0:9f5a444886a8 38 rxQueueLength = 0;
gume 0:9f5a444886a8 39
gume 0:9f5a444886a8 40 rf24.startListening();
gume 0:9f5a444886a8 41 // IF_SERIAL_DEBUG(rf24.printDetails());
gume 0:9f5a444886a8 42 }
gume 0:9f5a444886a8 43
gume 0:9f5a444886a8 44 bool SSRadio::isRunning() {
gume 0:9f5a444886a8 45 return rf24.isChipConnected();
gume 0:9f5a444886a8 46 }
gume 0:9f5a444886a8 47
gume 0:9f5a444886a8 48 void SSRadio::loop() {
gume 0:9f5a444886a8 49
gume 0:9f5a444886a8 50 // Checking incoming frames
gume 0:9f5a444886a8 51 uint8_t pipenum;
gume 0:9f5a444886a8 52 if (rf24.available(&pipenum)) {
gume 0:9f5a444886a8 53 IF_SERIAL_DEBUG(Serial.println(F("Incoming packet.")));
gume 0:9f5a444886a8 54 uint8_t ps = rf24.getDynamicPayloadSize();
gume 0:9f5a444886a8 55 if (ps > 0) {
gume 0:9f5a444886a8 56 rf24.read(packetRx, ps);
gume 0:9f5a444886a8 57 if (pipenum == 0) {
gume 0:9f5a444886a8 58 receiveSyncFrame(packetRx, ps);
gume 0:9f5a444886a8 59 } else {
gume 0:9f5a444886a8 60 receiveDataFrame(packetRx, ps);
gume 0:9f5a444886a8 61 }
gume 0:9f5a444886a8 62 }
gume 0:9f5a444886a8 63 }
gume 0:9f5a444886a8 64
gume 0:9f5a444886a8 65 long now = us_ticker_read() / 1000;
gume 0:9f5a444886a8 66 // Check the queues
gume 0:9f5a444886a8 67 bool sent = false;
gume 0:9f5a444886a8 68 if (txQueueLength > 0) {
gume 0:9f5a444886a8 69
gume 0:9f5a444886a8 70 if (sendSlot > -1) {
gume 0:9f5a444886a8 71 // There is a timeslot now for the transmission
gume 0:9f5a444886a8 72 if ((now > lastSync + sendSlot * slot_ms) && (now < lastSync + (sendSlot + 1) * slot_ms)) {
gume 0:9f5a444886a8 73 instantData(txQueue + 2, txQueue[1], txQueue[0]);
gume 0:9f5a444886a8 74 //Serial.println("sendSlot");
gume 0:9f5a444886a8 75 sent = true;
gume 0:9f5a444886a8 76 }
gume 0:9f5a444886a8 77 }
gume 0:9f5a444886a8 78 else if (freeSlot > 0) {
gume 0:9f5a444886a8 79 // When freeSlot is not 0 (nobody is scheduled), then send in the free slot
gume 0:9f5a444886a8 80 if ((now >= lastSync + freeSlot * slot_ms) && (now <= lastSync + (freeSlot + 1) * slot_ms)) {
gume 0:9f5a444886a8 81 instantData(txQueue + 2, txQueue[1], txQueue[0]);
gume 0:9f5a444886a8 82 //Serial.println("freeSlot");
gume 0:9f5a444886a8 83 sent = true;
gume 0:9f5a444886a8 84 }
gume 0:9f5a444886a8 85 }
gume 0:9f5a444886a8 86 else {
gume 0:9f5a444886a8 87 // No sync or no others, send immediately
gume 0:9f5a444886a8 88 instantData(txQueue + 2, txQueue[1], txQueue[0]);
gume 0:9f5a444886a8 89 //Serial.println("Other");
gume 0:9f5a444886a8 90 sent = true;
gume 0:9f5a444886a8 91 }
gume 0:9f5a444886a8 92
gume 0:9f5a444886a8 93 if (sent) {
gume 0:9f5a444886a8 94 // Move in the queue;
gume 0:9f5a444886a8 95 txQueueLength--;
gume 0:9f5a444886a8 96 if (txQueueLength > 0)
gume 0:9f5a444886a8 97 memcpy(txQueue, txQueue + 30, txQueueLength * 30);
gume 0:9f5a444886a8 98 }
gume 0:9f5a444886a8 99 }
gume 0:9f5a444886a8 100
gume 0:9f5a444886a8 101 // Scheduled tasks
gume 0:9f5a444886a8 102 if (now > lastSync + 1000) {
gume 0:9f5a444886a8 103 // last Sync was really long ago
gume 0:9f5a444886a8 104 sendSlot = -1;
gume 0:9f5a444886a8 105 freeSlot = -1;
gume 0:9f5a444886a8 106 }
gume 0:9f5a444886a8 107 }
gume 0:9f5a444886a8 108
gume 0:9f5a444886a8 109 void SSRadio::receiveSyncFrame(uint8_t *frame, uint8_t size) {
gume 0:9f5a444886a8 110
gume 0:9f5a444886a8 111 lastSync = us_ticker_read() / 1000;
gume 0:9f5a444886a8 112
gume 0:9f5a444886a8 113 // Find self address to get the sending slot
gume 0:9f5a444886a8 114 uint16_t *nodes = (uint16_t*) frame;
gume 0:9f5a444886a8 115 sendSlot = -1;
gume 0:9f5a444886a8 116 //Serial.println("Sync");
gume 0:9f5a444886a8 117 //Serial.println(size);
gume 0:9f5a444886a8 118 uint8_t i = 0;
gume 0:9f5a444886a8 119 while ((i < size / 2) && (nodes[i] != 0)) {
gume 0:9f5a444886a8 120 //Serial.println(nodes[i]);
gume 0:9f5a444886a8 121 if (nodes[i] == myAddress) {
gume 0:9f5a444886a8 122 sendSlot = i;
gume 0:9f5a444886a8 123 }
gume 0:9f5a444886a8 124 i++;
gume 0:9f5a444886a8 125 }
gume 0:9f5a444886a8 126 if (nodes[i] == 0) {
gume 0:9f5a444886a8 127 freeSlot = i;
gume 0:9f5a444886a8 128 }
gume 0:9f5a444886a8 129 }
gume 0:9f5a444886a8 130
gume 0:9f5a444886a8 131 void SSRadio::receiveDataFrame(uint8_t *frame, uint8_t size) {
gume 0:9f5a444886a8 132
gume 0:9f5a444886a8 133 Packet *p = (Packet*) frame;
gume 0:9f5a444886a8 134 IF_SERIAL_DEBUG(Serial.println(F("Data frame received.")));
gume 0:9f5a444886a8 135 if (onReceiveData) {
gume 0:9f5a444886a8 136 IF_SERIAL_DEBUG(Serial.println(F("Calling onReceiveData.")));
gume 0:9f5a444886a8 137 (*onReceiveData)(p->fields.payload, p->fields.type, size - 4);
gume 0:9f5a444886a8 138 }
gume 0:9f5a444886a8 139 }
gume 0:9f5a444886a8 140
gume 0:9f5a444886a8 141 bool SSRadio::sendData(uint8_t *data, uint16_t type, uint8_t size) {
gume 0:9f5a444886a8 142
gume 0:9f5a444886a8 143 if (txQueueLength == QUEUELEN) return false; // Queue is full
gume 0:9f5a444886a8 144
gume 0:9f5a444886a8 145 uint8_t *frame = txQueue + txQueueLength * 30;
gume 0:9f5a444886a8 146 frame[0] = size;
gume 0:9f5a444886a8 147 frame[1] = type & 0xff; // !!! SHOULD be FIXED for extended types
gume 0:9f5a444886a8 148 memcpy(frame + 2, data, size);
gume 0:9f5a444886a8 149
gume 0:9f5a444886a8 150 txQueueLength ++;
gume 0:9f5a444886a8 151
gume 0:9f5a444886a8 152 return true;
gume 0:9f5a444886a8 153 }
gume 0:9f5a444886a8 154
gume 0:9f5a444886a8 155 bool SSRadio::instantData(uint8_t *data, uint16_t type, uint8_t size) {
gume 0:9f5a444886a8 156
gume 0:9f5a444886a8 157 Packet p;
gume 0:9f5a444886a8 158 p.fields.address = myAddress;
gume 0:9f5a444886a8 159 p.fields.type = type & 0xff;
gume 0:9f5a444886a8 160 p.fields.counter = txCounter ++;
gume 0:9f5a444886a8 161 memcpy(p.fields.payload, data, size);
gume 0:9f5a444886a8 162
gume 0:9f5a444886a8 163 IF_SERIAL_DEBUG(Serial.println(F("Sending data.")));
gume 0:9f5a444886a8 164
gume 0:9f5a444886a8 165 rf24.stopListening();
gume 0:9f5a444886a8 166 rf24.setRetries(0, 5);
gume 0:9f5a444886a8 167 rf24.openWritingPipe(gatewayAddress);
gume 0:9f5a444886a8 168 bool ok = rf24.write(p.raw, size + 4);
gume 0:9f5a444886a8 169 rf24.startListening();
gume 0:9f5a444886a8 170
gume 0:9f5a444886a8 171 if (ok) IF_SERIAL_DEBUG(Serial.println("Success."));
gume 0:9f5a444886a8 172 else IF_SERIAL_DEBUG(Serial.println("Fail!"));
gume 0:9f5a444886a8 173
gume 0:9f5a444886a8 174 return ok;
gume 0:9f5a444886a8 175 }
gume 0:9f5a444886a8 176
gume 0:9f5a444886a8 177 void SSRadio::setOnReceiveData(void (*f)(uint8_t *data, uint16_t type, uint8_t len)) {
gume 0:9f5a444886a8 178 onReceiveData = f;
gume 0:9f5a444886a8 179 }
gume 0:9f5a444886a8 180