Added interrupt handling and reception queueing for nRF24
When nRF24 interrupt is connected to Arduino, handling of reception interrupts can be enabled. This will store all data received in a buffer which will prevent messages from getting lost when the Arduino is too busy to empty the FIFO.
This commit is contained in:
@@ -368,6 +368,24 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @def MY_RF24_IRQ_PIN
|
||||||
|
* @brief Disable RF24 interrupt pin usage by default. Override in sketch if needed.
|
||||||
|
*/
|
||||||
|
#define MY_RF24_IRQ_PIN_UNUSED 0
|
||||||
|
#ifndef MY_RF24_IRQ_PIN
|
||||||
|
#define MY_RF24_IRQ_PIN MY_RF24_IRQ_PIN_UNUSED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @def MY_RF24_MESSAGE_BUFFER_SIZE
|
||||||
|
* @brief Declare the amount of messages that can be buffered. Override in sketch if needed.
|
||||||
|
*/
|
||||||
|
#ifndef MY_RF24_MESSAGE_BUFFER_SIZE
|
||||||
|
#define MY_RF24_MESSAGE_BUFFER_SIZE (20)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @def MY_RF24_PA_LEVEL
|
* @def MY_RF24_PA_LEVEL
|
||||||
* @brief Default RF24 PA level. Override in sketch if needed.
|
* @brief Default RF24 PA level. Override in sketch if needed.
|
||||||
|
|||||||
@@ -20,15 +20,45 @@
|
|||||||
#include "MyConfig.h"
|
#include "MyConfig.h"
|
||||||
#include "MyTransport.h"
|
#include "MyTransport.h"
|
||||||
#include "drivers/RF24/RF24.h"
|
#include "drivers/RF24/RF24.h"
|
||||||
|
#include "drivers/CircularBuffer/CircularBuffer.h"
|
||||||
|
|
||||||
#if defined(MY_RF24_ENABLE_ENCRYPTION)
|
#if defined(MY_RF24_ENABLE_ENCRYPTION)
|
||||||
#include "drivers/AES/AES.h"
|
#include "drivers/AES/AES.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (MY_RF24_IRQ_PIN != MY_RF24_IRQ_PIN_UNUSED)
|
||||||
|
typedef struct _queuedMessage
|
||||||
|
{
|
||||||
|
uint8_t m_to; /** Destination address of this message. */
|
||||||
|
uint8_t m_len; /** Length of the data. */
|
||||||
|
uint8_t m_data[MAX_MESSAGE_LENGTH]; /** The raw data. */
|
||||||
|
} queuedMessage;
|
||||||
|
|
||||||
|
/** Buffer to store queued messages in. */
|
||||||
|
static queuedMessage queueStorage[MY_RF24_MESSAGE_BUFFER_SIZE];
|
||||||
|
/** Circular buffer, which uses the queueStorage and administers stored messages. */
|
||||||
|
static CircularBuffer<queuedMessage> receiveQueue(queueStorage, MY_RF24_MESSAGE_BUFFER_SIZE);
|
||||||
|
|
||||||
|
static volatile uint8_t lostMessageCount = 0;
|
||||||
|
|
||||||
|
static void rxCallback(const uint8_t to)
|
||||||
|
{
|
||||||
|
if (!receiveQueue.full())
|
||||||
|
{
|
||||||
|
queuedMessage* msg = receiveQueue.getFront();
|
||||||
|
msg->m_len = readMessage(msg->m_data);
|
||||||
|
(void)receiveQueue.pushFront(msg);
|
||||||
|
} else {
|
||||||
|
// TODO: Message is not really lost, as it is still in the nRF FIFO. But once the FIFO is also full messages will get lost.
|
||||||
|
++lostMessageCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(MY_RF24_ENABLE_ENCRYPTION)
|
#if defined(MY_RF24_ENABLE_ENCRYPTION)
|
||||||
AES _aes;
|
AES _aes;
|
||||||
uint8_t _dataenc[32] = {0};
|
uint8_t _dataenc[32] = {0};
|
||||||
uint8_t _psk[16];
|
uint8_t _psk[16];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool transportInit() {
|
bool transportInit() {
|
||||||
@@ -41,6 +71,9 @@ bool transportInit() {
|
|||||||
memset(_psk, 0, 16);
|
memset(_psk, 0, 16);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (MY_RF24_IRQ_PIN != MY_RF24_IRQ_PIN_UNUSED)
|
||||||
|
registerReceiveCallback( rxCallback );
|
||||||
|
#endif
|
||||||
return initializeRF24();
|
return initializeRF24();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,13 +104,39 @@ bool transportSend(uint8_t recipient, const void* data, uint8_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool transportAvailable(uint8_t *to) {
|
bool transportAvailable(uint8_t *to) {
|
||||||
bool avail = IsDataAvailable(to);
|
bool avail = false;
|
||||||
return avail;
|
#if (MY_RF24_IRQ_PIN != MY_RF24_IRQ_PIN_UNUSED)
|
||||||
|
queuedMessage* msg = receiveQueue.getBack();
|
||||||
|
if (msg)
|
||||||
|
{
|
||||||
|
avail = true;
|
||||||
|
*to = msg->m_to;
|
||||||
|
} else {
|
||||||
|
// TODO: The nRF FIFO could still hold a message
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
avail = IsDataAvailable(to);
|
||||||
|
#endif
|
||||||
|
return avail;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t transportReceive(void* data) {
|
uint8_t transportReceive(void* data) {
|
||||||
uint8_t len = readMessage(data);
|
uint8_t len;
|
||||||
#if defined(MY_RF24_ENABLE_ENCRYPTION)
|
#if (MY_RF24_IRQ_PIN != MY_RF24_IRQ_PIN_UNUSED)
|
||||||
|
// debug(PSTR("lost:%d\n"), lostMessageCount);
|
||||||
|
queuedMessage* msg = receiveQueue.getBack();
|
||||||
|
if (msg)
|
||||||
|
{
|
||||||
|
len = msg->m_len;
|
||||||
|
(void)memcpy(data, msg->m_data, len);
|
||||||
|
(void)receiveQueue.popBack();
|
||||||
|
} else {
|
||||||
|
// TODO: The nRF FIFO could still hold a message
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
len = readMessage(data);
|
||||||
|
#endif
|
||||||
|
#if defined(MY_RF24_ENABLE_ENCRYPTION)
|
||||||
// has to be adjusted, WIP!
|
// has to be adjusted, WIP!
|
||||||
_aes.set_IV(0);
|
_aes.set_IV(0);
|
||||||
// decrypt data
|
// decrypt data
|
||||||
|
|||||||
@@ -22,8 +22,13 @@
|
|||||||
|
|
||||||
#include "RF24.h"
|
#include "RF24.h"
|
||||||
|
|
||||||
uint8_t MY_RF24_BASE_ADDR[MY_RF24_ADDR_WIDTH] = { MY_RF24_BASE_RADIO_ID };
|
static uint8_t MY_RF24_BASE_ADDR[MY_RF24_ADDR_WIDTH] = { MY_RF24_BASE_RADIO_ID };
|
||||||
uint8_t MY_RF24_NODE_ADDRESS = AUTO;
|
static uint8_t MY_RF24_NODE_ADDRESS = AUTO;
|
||||||
|
|
||||||
|
#if (MY_RF24_IRQ_PIN != MY_RF24_IRQ_PIN_UNUSED)
|
||||||
|
typedef void (*receiveCallbackType)(const uint8_t);
|
||||||
|
static receiveCallbackType receiveCallback = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
void csn(bool level) {
|
void csn(bool level) {
|
||||||
digitalWrite(MY_RF24_CS_PIN, level);
|
digitalWrite(MY_RF24_CS_PIN, level);
|
||||||
@@ -204,14 +209,45 @@ uint8_t getNodeID(void) {
|
|||||||
return MY_RF24_NODE_ADDRESS;
|
return MY_RF24_NODE_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (MY_RF24_IRQ_PIN != MY_RF24_IRQ_PIN_UNUSED)
|
||||||
|
static void irqHandler( void )
|
||||||
|
{
|
||||||
|
if (receiveCallback)
|
||||||
|
{
|
||||||
|
uint8_t to;
|
||||||
|
(void)IsDataAvailable(&to);
|
||||||
|
receiveCallback(to);
|
||||||
|
} else {
|
||||||
|
// clear RX interrupt
|
||||||
|
writeByteRegister(RF24_STATUS, _BV(RX_DR) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerReceiveCallback( receiveCallbackType cb )
|
||||||
|
{
|
||||||
|
noInterrupts();
|
||||||
|
receiveCallback = cb;
|
||||||
|
interrupts();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool initializeRF24(void) {
|
bool initializeRF24(void) {
|
||||||
// Initialize pins
|
// Initialize pins
|
||||||
pinMode(MY_RF24_CE_PIN,OUTPUT);
|
pinMode(MY_RF24_CE_PIN,OUTPUT);
|
||||||
pinMode(MY_RF24_CS_PIN,OUTPUT);
|
pinMode(MY_RF24_CS_PIN,OUTPUT);
|
||||||
|
#if (MY_RF24_IRQ_PIN != MY_RF24_IRQ_PIN_UNUSED)
|
||||||
|
pinMode(MY_RF24_IRQ_PIN,INPUT);
|
||||||
|
#endif
|
||||||
// Initialize SPI
|
// Initialize SPI
|
||||||
_SPI.begin();
|
_SPI.begin();
|
||||||
ce(LOW);
|
ce(LOW);
|
||||||
csn(HIGH);
|
csn(HIGH);
|
||||||
|
#if (MY_RF24_IRQ_PIN != MY_RF24_IRQ_PIN_UNUSED)
|
||||||
|
// assure SPI can be used from interrupt context
|
||||||
|
_SPI.usingInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN));
|
||||||
|
// attach interrupt
|
||||||
|
attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), irqHandler, FALLING);
|
||||||
|
#endif
|
||||||
// CRC and power up
|
// CRC and power up
|
||||||
writeByteRegister(NRF_CONFIG, MY_RF24_CONFIGURATION | _BV(PWR_UP) ) ;
|
writeByteRegister(NRF_CONFIG, MY_RF24_CONFIGURATION | _BV(PWR_UP) ) ;
|
||||||
// settle >2ms
|
// settle >2ms
|
||||||
|
|||||||
@@ -38,7 +38,11 @@
|
|||||||
#define MY_RF24_SPI_DATA_MODE SPI_MODE0
|
#define MY_RF24_SPI_DATA_MODE SPI_MODE0
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
#define MY_RF24_CONFIGURATION (uint8_t) (RF24_CRC_16 << 1)
|
#if (MY_RF24_IRQ_PIN != MY_RF24_IRQ_PIN_UNUSED)
|
||||||
|
#define MY_RF24_CONFIGURATION (uint8_t)((RF24_CRC_16 << 1) | (1 << MASK_TX_DS) | (1 << MASK_MAX_RT))
|
||||||
|
#else
|
||||||
|
#define MY_RF24_CONFIGURATION (uint8_t)((RF24_CRC_16 << 1) | (1 << MASK_RX_DR) | (1 << MASK_TX_DS) | (1 << MASK_MAX_RT))
|
||||||
|
#endif
|
||||||
#define MY_RF24_FEATURE (uint8_t)( _BV(EN_DPL) | _BV(EN_ACK_PAY) )
|
#define MY_RF24_FEATURE (uint8_t)( _BV(EN_DPL) | _BV(EN_ACK_PAY) )
|
||||||
#define MY_RF24_RF_SETUP (uint8_t)( ((MY_RF24_DATARATE & 0b10 ) << 4) | ((MY_RF24_DATARATE & 0b01 ) << 3) | (MY_RF24_PA_LEVEL << 1) ) + 1 // +1 for Si24R1
|
#define MY_RF24_RF_SETUP (uint8_t)( ((MY_RF24_DATARATE & 0b10 ) << 4) | ((MY_RF24_DATARATE & 0b01 ) << 3) | (MY_RF24_PA_LEVEL << 1) ) + 1 // +1 for Si24R1
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
/**
|
||||||
|
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||||
|
* between your home built sensors/actuators and HA controller of choice.
|
||||||
|
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||||
|
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||||
|
* network topology allowing messages to be routed to nodes.
|
||||||
|
*
|
||||||
|
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||||
|
* Copyright (C) 2013-2015 Sensnology AB
|
||||||
|
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||||
|
*
|
||||||
|
* Documentation: http://www.mysensors.org
|
||||||
|
* Support Forum: http://forum.mysensors.org
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* version 2 as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
*******************************
|
||||||
|
*
|
||||||
|
* DESCRIPTION
|
||||||
|
* The ArduinoGateway prints data received from sensors on the serial link.
|
||||||
|
* The gateway accepts input on seral which will be sent out on radio network.
|
||||||
|
*
|
||||||
|
* The GW code is designed for Arduino Nano 328p / 16MHz
|
||||||
|
*
|
||||||
|
* Wire connections (OPTIONAL):
|
||||||
|
* - Inclusion button should be connected between digital pin 3 and GND
|
||||||
|
* - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series
|
||||||
|
*
|
||||||
|
* LEDs (OPTIONAL):
|
||||||
|
* - To use the feature, uncomment MY_LEDS_BLINKING_FEATURE in MyConfig.h
|
||||||
|
* - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved
|
||||||
|
* - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly
|
||||||
|
* - ERR (red) - fast blink on error during transmission error or recieve crc error
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MY_RADIO_NRF24
|
||||||
|
#define MY_RF24_CHANNEL (100)
|
||||||
|
#define MY_RF24_DATARATE (RF24_1MBPS)
|
||||||
|
#define MY_GATEWAY_SERIAL
|
||||||
|
#define MY_LEDS_BLINKING_FEATURE
|
||||||
|
#define MY_DEFAULT_LED_BLINK_PERIOD 50
|
||||||
|
#define MY_WITH_LEDS_BLINKING_INVERSE
|
||||||
|
#define MY_RF24_IRQ_PIN (2)
|
||||||
|
|
||||||
|
#define MY_DEFAULT_ERR_LED_PIN A0 // Error led pin
|
||||||
|
#define MY_DEFAULT_RX_LED_PIN A1 // Receive led pin
|
||||||
|
#define MY_DEFAULT_TX_LED_PIN A2 // the PCB, on board LED
|
||||||
|
|
||||||
|
//#define MY_DEBUG
|
||||||
|
//#define MY_DEBUG_VERBOSE_RF24
|
||||||
|
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <MySensor.h>
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void presentation() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void receive(const MyMessage &message)
|
||||||
|
{
|
||||||
|
static uint16_t prevCount = 0;
|
||||||
|
uint16_t count = message.getUInt();
|
||||||
|
if ((count-1) != prevCount)
|
||||||
|
{
|
||||||
|
Serial.print(F("Mismatch: prev="));
|
||||||
|
Serial.print(prevCount);
|
||||||
|
Serial.print(F(" new="));
|
||||||
|
Serial.println(count);
|
||||||
|
}
|
||||||
|
prevCount = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t maxCount = 100;
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
static uint8_t count = 0;
|
||||||
|
++count;
|
||||||
|
if (count++ > maxCount)
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
|
||||||
|
#define MY_RADIO_NRF24
|
||||||
|
#define MY_RF24_CHANNEL (100)
|
||||||
|
#define MY_NODE_ID (200)
|
||||||
|
#define MY_RF24_CE_PIN (9)
|
||||||
|
#define MY_RF24_CS_PIN (10)
|
||||||
|
//#define MY_RF24_IRQ_PIN (2)
|
||||||
|
#define MY_RF24_DATARATE (RF24_1MBPS)
|
||||||
|
#define MY_DEBUG
|
||||||
|
//#define MY_DEBUG_VERBOSE_RF24
|
||||||
|
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <MySensor.h>
|
||||||
|
|
||||||
|
#undef debug
|
||||||
|
#ifndef NODEBUG
|
||||||
|
#define debug(x) Serial.print(x)
|
||||||
|
#define debugln(x) Serial.println(x)
|
||||||
|
#else
|
||||||
|
#define debug(x)
|
||||||
|
#define debugln(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void presentation()
|
||||||
|
{
|
||||||
|
sendSketchInfo("Test", "1.0");
|
||||||
|
debug("ID: "); debugln(getNodeId());
|
||||||
|
|
||||||
|
present(0, S_CUSTOM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void receive(const MyMessage &message)
|
||||||
|
{
|
||||||
|
// debug("Message "); debugln(message.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
debugln(F("---- Starting sensor ----"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
static uint16_t count = 0;
|
||||||
|
send( MyMessage(0, V_VAR1).set(count) );
|
||||||
|
++count;
|
||||||
|
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -66,6 +66,7 @@ MY_RF24_ENABLE_ENCRYPTION LITERAL1
|
|||||||
MY_RF24_SPI_MAX_SPEED LITERAL1
|
MY_RF24_SPI_MAX_SPEED LITERAL1
|
||||||
MY_RF24_CE_PIN LITERAL1
|
MY_RF24_CE_PIN LITERAL1
|
||||||
MY_RF24_CS_PIN LITERAL1
|
MY_RF24_CS_PIN LITERAL1
|
||||||
|
MY_RF24_IRQ_PIN LITERAL1
|
||||||
MY_RF24_PA_LEVEL LITERAL1
|
MY_RF24_PA_LEVEL LITERAL1
|
||||||
MY_RF24_CHANNEL LITERAL1
|
MY_RF24_CHANNEL LITERAL1
|
||||||
MY_RF24_DATARATE LITERAL1
|
MY_RF24_DATARATE LITERAL1
|
||||||
|
|||||||
Reference in New Issue
Block a user