Radio communication with NRF24
Revision 0:9f5a444886a8, committed 2017-10-06
- Comitter:
- gume
- Date:
- Fri Oct 06 20:17:36 2017 +0000
- Commit message:
- Initial release
Changed in this revision
diff -r 000000000000 -r 9f5a444886a8 NodeConfig.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NodeConfig.cpp Fri Oct 06 20:17:36 2017 +0000 @@ -0,0 +1,53 @@ +#include "NodeConfig.h" + +#if defined(__AVR_ATmega328P__) +#include <EEPROM.h> +#include "Entropy.h" +#endif + +uint16_t NodeConfig::getNodeId() { + + uint16_t id; + + return id; +} + +NodeConfig::NodeConfig(PinName cePin, PinName csnPin) { + + this->cePin = cePin; + this->csnPin = csnPin; + + this->netPrefix = DEFAULT_NETWORK_PREFIX; + this->syncAddress = DEFAULT_SYNC_ADDRESS; + this->channel = DEFAULT_RADIO_CHANNEL; + this->dataRate = DEFAULT_DATA_RATE; + this->paLevel = DEFAULT_PA_LEVEL; + this->nodeId = getNodeId(); + this->gwId = DEFAULT_GW_ID; +} + +void NodeConfig::setChannel(uint8_t channel) { + this->channel = channel; +} + +void NodeConfig::setSpeed(rf24_datarate_e dataRate) { + this->dataRate = dataRate; +} + +void NodeConfig::setNetPrefix(uint32_t netPrefix) { + this->netPrefix = netPrefix; +} + +void NodeConfig::setNodeId(uint16_t nodeId) { + this->nodeId = nodeId; +} + +void NodeConfig::setGwId(uint16_t gwId) { + this->gwId = gwId; +} + +void NodeConfig::setSyncAddress(uint64_t syncAddress) { + this->syncAddress = syncAddress; +} + +
diff -r 000000000000 -r 9f5a444886a8 NodeConfig.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NodeConfig.h Fri Oct 06 20:17:36 2017 +0000 @@ -0,0 +1,47 @@ +#ifndef __NODECONFIG_H_ +#define __NODECONFIG_H_ + +//#include <Arduino.h> +#include "RF24.h" + + +#define DEFAULT_NETWORK_PREFIX 0x424D45L // All network node has a common 3 byte address prefix +#define DEFAULT_NODE_ADDRESS 0x424D455555L +#define DEFAULT_SYNC_ADDRESS 0x3333333333L +#define DEFAULT_GW_ID 0x0000 +#define DEFAULT_RADIO_CHANNEL 96 +#define DEFAULT_PA_LEVEL RF24_PA_MAX +#define DEFAULT_DATA_RATE RF24_2MBPS + +class SSRadio; + +class NodeConfig { +friend class SSRadio; + +private: + uint32_t netPrefix; + uint16_t nodeId; + uint16_t gwId; + uint64_t syncAddress; + + uint8_t channel; // Radio channel + rf24_pa_dbm_e paLevel; // PA level + rf24_datarate_e dataRate; // The transmission speed + + PinName cePin; // CE pin + PinName csnPin; // CS pin + +public: + NodeConfig(PinName _cepin, PinName _cspin); + + void setNodeId(uint16_t nodeId); + void setGwId(uint16_t gwId); + void setNetPrefix(uint32_t netPrefix); + void setSyncAddress(uint64_t syncAddress); + void setChannel(uint8_t channel); + void setSpeed(rf24_datarate_e dataRate); + + uint16_t getNodeId(); // Returns ID from EEPROM or UinqID. If no ID in EEPROM, then create one +}; + +#endif // NODECONFIG_H
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; +} +
diff -r 000000000000 -r 9f5a444886a8 ssRadio.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ssRadio.h Fri Oct 06 20:17:36 2017 +0000 @@ -0,0 +1,75 @@ +#ifndef __SSRADIO_H__ +#define __SSRADIO_H__ + +//#define SERIAL_DEBUG 1 + +#include "RF24.h" +#include "NodeConfig.h" + +#define QUEUELEN 3 + +typedef union _Packet { + struct __attribute__((packed)) { + uint16_t address; // Source address + uint8_t type; // Type. MSB signals extended type (+1 byte). Not implemented yet. + uint8_t counter; // Packet counter + uint8_t payload[28]; + } fields; + uint8_t raw[32]; +} Packet; + +class SSRadio { + +protected: + NodeConfig *config; + RF24 rf24; + + void (*onReceiveData)(uint8_t *data, uint16_t type, uint8_t len); + void (*onConnect)(); + void (*onDisconnect)(); + + uint16_t txCounter; + uint16_t rxCounter; + + uint8_t packetRx[32]; + long lastSync; // millis when the last Sync was received + int8_t sendSlot; // Transmission slot, when synced + int8_t freeSlot; // Free (for everyone) slot, when synced + uint8_t slot_ms; // Slot size in ms + + void receiveSyncFrame(uint8_t *frame, uint8_t size); + void receiveDataFrame(uint8_t *frame, uint8_t size); + + uint16_t myAddress; + uint64_t gatewayAddress; + + uint8_t txQueue[QUEUELEN * 30]; // 1 length + 1 type + 28 payload + uint8_t rxQueue[QUEUELEN * 30]; + uint8_t txQueueLength; + uint8_t rxQueueLength; + +public: + SSRadio(SPI *spi, NodeConfig *nc); + + void init(); + void loop(); + + void useIRQ(uint16_t irqPin); + + bool isRunning(); // RF24 is connected or not + bool isConnected(); // There is a GW nearby + bool isScheduled(); // Sending is scheduled by the GW + bool isAvailableData(); // Available data + + bool sendData(uint8_t *data, uint16_t type, uint8_t len); // Send data to GW + bool instantData(uint8_t *data, uint16_t type, uint8_t len); // Send data to GW immediately + bool receiveData(uint8_t *data, uint16_t &type, uint8_t &len); // Receive data from GW + void setSlotSize(uint8_t slot_ms); + + // Callbacks + void setOnReceiveData(void (*onReceiveData)(uint8_t *data, uint16_t type, uint8_t len)); + void setOnConnect(void (*onConnect)()); + void setOnDisconnect(void (*onDisconnect)()); +}; + +#endif // __SSRADIO_H__