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
|
||||
|
||||
/**
|
||||
* @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
|
||||
* @brief Default RF24 PA level. Override in sketch if needed.
|
||||
|
||||
@@ -20,17 +20,47 @@
|
||||
#include "MyConfig.h"
|
||||
#include "MyTransport.h"
|
||||
#include "drivers/RF24/RF24.h"
|
||||
#include "drivers/CircularBuffer/CircularBuffer.h"
|
||||
|
||||
#if defined(MY_RF24_ENABLE_ENCRYPTION)
|
||||
#include "drivers/AES/AES.h"
|
||||
#endif
|
||||
|
||||
#if defined(MY_RF24_ENABLE_ENCRYPTION)
|
||||
AES _aes;
|
||||
uint8_t _dataenc[32] = {0};
|
||||
uint8_t _psk[16];
|
||||
#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)
|
||||
AES _aes;
|
||||
uint8_t _dataenc[32] = {0};
|
||||
uint8_t _psk[16];
|
||||
#endif
|
||||
|
||||
bool transportInit() {
|
||||
|
||||
#if defined(MY_RF24_ENABLE_ENCRYPTION)
|
||||
@@ -40,7 +70,10 @@ bool transportInit() {
|
||||
// Make sure it is purged from memory when set
|
||||
memset(_psk, 0, 16);
|
||||
#endif
|
||||
|
||||
|
||||
#if (MY_RF24_IRQ_PIN != MY_RF24_IRQ_PIN_UNUSED)
|
||||
registerReceiveCallback( rxCallback );
|
||||
#endif
|
||||
return initializeRF24();
|
||||
}
|
||||
|
||||
@@ -71,13 +104,39 @@ bool transportSend(uint8_t recipient, const void* data, uint8_t len) {
|
||||
}
|
||||
|
||||
bool transportAvailable(uint8_t *to) {
|
||||
bool avail = IsDataAvailable(to);
|
||||
return avail;
|
||||
bool avail = false;
|
||||
#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 len = readMessage(data);
|
||||
#if defined(MY_RF24_ENABLE_ENCRYPTION)
|
||||
uint8_t len;
|
||||
#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!
|
||||
_aes.set_IV(0);
|
||||
// decrypt data
|
||||
|
||||
@@ -22,8 +22,13 @@
|
||||
|
||||
#include "RF24.h"
|
||||
|
||||
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_BASE_ADDR[MY_RF24_ADDR_WIDTH] = { MY_RF24_BASE_RADIO_ID };
|
||||
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) {
|
||||
digitalWrite(MY_RF24_CS_PIN, level);
|
||||
@@ -204,14 +209,45 @@ uint8_t getNodeID(void) {
|
||||
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) {
|
||||
// Initialize pins
|
||||
pinMode(MY_RF24_CE_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
|
||||
_SPI.begin();
|
||||
ce(LOW);
|
||||
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
|
||||
writeByteRegister(NRF_CONFIG, MY_RF24_CONFIGURATION | _BV(PWR_UP) ) ;
|
||||
// settle >2ms
|
||||
|
||||
@@ -38,7 +38,11 @@
|
||||
#define MY_RF24_SPI_DATA_MODE SPI_MODE0
|
||||
|
||||
// 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_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_CE_PIN LITERAL1
|
||||
MY_RF24_CS_PIN LITERAL1
|
||||
MY_RF24_IRQ_PIN LITERAL1
|
||||
MY_RF24_PA_LEVEL LITERAL1
|
||||
MY_RF24_CHANNEL LITERAL1
|
||||
MY_RF24_DATARATE LITERAL1
|
||||
|
||||
Reference in New Issue
Block a user