Radio communication with NRF24
Diff: ssRadio.cpp
- Revision:
- 0:9f5a444886a8
diff -r 000000000000 -r 9f5a444886a8 ssRadio.cpp --- /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; +} +