RF24Ethernet
RF24Ethernet copied to clipboard
Communication Issue between SLIP_InteractiveServer and SLIP_Gateway
I am using the latest code downloaded from GitHub. I have very little nRF24 experience and using the libraries to learn. I successfully covered all the examples over the last few weeks up to the RF24Ethernet SLIP_InteractiveServer and SLIP_Gateway. I have made no code changes to the examples, except put a radio.printDetails() in the code to show the configuration. From the documentation it seems the problem is RX_ADDR_P0-1 in the SLIP_InteractiveServer code. I ask your assistance to help correct the addresses.
RF24Ethernet SLIP_InteractiveServer:
RF24Ethernet SLIP_Gateway:
/*
* RF24Ethernet Webserver controlling an LED example *
*
* **NOTE: This example demonstrates usage the SLIP_Gateway
* When using SLIP, there are 3 main differences:
* 1. The RF24Mesh layer must be used to provide MAC/IP translation
* 2. The specified RF24Mesh nodeID must be the same as the last octet of the IP
* ie: IP: 192.168.1.2 NodeId must be 2
*
* 3. The RF24Ethernet library must be configured for TUN
* a: Open the uip_conf.h file, make sure to #define UIP_CONF_LLH_LEN 0
*
* The following commands must be run on the Linux device to enable slip
* 1. Connect your Arduino
* 2. On RPi, cd /dev
* 3. Type 'ls' and look for a new device ttyUSB<X> where <X> is a number
* 4. Run sudo modprobe slip
* 5. Run sudo slattach -L -s 115200 -p slip /dev/ttyUSB<X> &
* 6. Run sudo ifconfig s<X> 10.10.3.1 dstaddr 10.10.3.2
* 7. Run sudo route add -net 10.10.3.0/24 gw 10.10.3.1
* RF24Ethernet uses the uIP stack by Adam Dunkels <[email protected]>
*
* This example demonstrates how to configure a sensor node to act as a webserver and
* allows a user to control a connected LED by clicking links on the webpage
* The requested URL is used as input, to determine whether to turn the LED off or on
*/
#include <RF24Network.h>
#include <RF24.h>
#include <SPI.h>
#include <printf.h>
#include <RF24Ethernet.h>
#include "HTML.h"
// Include RF24Mesh and the EEPROM libs
#include "RF24Mesh.h"
#include "EEPROM.h"
/*** Configure the radio CE & CS pins ***/
RF24 radio(7,8);
RF24Network network(radio);
RF24Mesh mesh(radio,network);
RF24EthernetClass RF24Ethernet(radio,network,mesh);
#define LED_PIN A3 //Analog pin A3
// Configure the server to listen on port 1000
EthernetServer server = EthernetServer(1000);
/**********************************************************/
void setup() {
// Set up the speed of our serial link.
Serial.begin(115200);
printf_begin();
Serial.println("start");
pinMode(LED_PIN, OUTPUT);
// This step is very important. When using TUN or SLIP, the IP of the device
// must be configured as the NodeID in the RF24Mesh layer
mesh.setNodeID(2);
mesh.begin();
//Optional
radio.printDetails();
// Set the IP address we'll be using. Make sure this doesn't conflict with
// any IP addresses or subnets on your LAN or you won't be able to connect to
// either the Arduino or your LAN...
// NOTE: The last octet/last digit of the IP must match the RF24Mesh nodeID above
IPAddress myIP(10, 10, 3, 2);
Ethernet.begin(myIP);
// If you'll be making outgoing connections from the Arduino to the rest of
// the world, you'll need a gateway set up.
IPAddress gwIP(10, 10, 3, 1);
Ethernet.set_gateway(gwIP);
// Listen for incoming connections on TCP port 1000.
server.begin();
}
/********************************************************/
uint32_t mesh_timer = 0;
void loop() {
// This is the last of the differences between this and the regular Interactive Server example
// If the master node is completely down, and unresponsive for 30 seconds, renew the address
if(millis()-mesh_timer > 30000){ //Every 30 seconds, test mesh connectivity
mesh_timer = millis();
if( ! mesh.checkConnection() ){
//refresh the network address
mesh.renewAddress();
}
}
size_t size;
if (EthernetClient client = server.available())
{
uint8_t pageReq = 0;
generate_tcp_stats();
while ((size = client.available()) > 0)
{
// If a request is received with enough characters, search for the / character
if (size >= 7) {
char slash[] = {"/"};
client.findUntil(slash, slash);
char buf[3] = {" "};
buf[0] = client.read(); // Read in the first two characters from the request
buf[1] = client.read();
if (strcmp(buf, "ON") == 0) { // If the user requested http://ip-of-node:1000/ON
led_state = 1;
pageReq = 1;
digitalWrite(LED_PIN, led_state);
}else if (strcmp(buf, "OF") == 0) { // If the user requested http://ip-of-node:1000/OF
led_state = 0;
pageReq = 1;
digitalWrite(LED_PIN, led_state);
}else if (strcmp(buf, "ST") == 0) { // If the user requested http://ip-of-node:1000/OF
pageReq = 2;
}else if (strcmp(buf, "CR") == 0) { // If the user requested http://ip-of-node:1000/OF
pageReq = 3;
}else if(buf[0] == ' '){
pageReq = 4;
}
}
// Empty the rest of the data from the client
while (client.waitAvailable()) {
client.read();
}
}
/**
* Based on the incoming URL request, send the correct page to the client
* see HTML.h
*/
switch(pageReq){
case 2: stats_page(client); break;
case 3: credits_page(client); break;
case 4: main_page(client); break;
case 1: main_page(client); break;
default: break;
}
client.stop();
Serial.println(F("********"));
}
// We can do other things in the loop, but be aware that the loop will
// briefly pause while IP data is being processed.
int save_led_state = led_state;
for(int i=0; i<10; i++){
digitalWrite(LED_PIN, 1);
delay(50);
digitalWrite(LED_PIN, 0);
delay(50);
}
digitalWrite(LED_PIN, save_led_state);
}
/**
* This section displays some basic connection stats via Serial and demonstrates
* how to interact directly with the uIP TCP/IP stack
* See the uIP documentation for more info
*/
static unsigned short generate_tcp_stats()
{
struct uip_conn *conn;
// If multiple connections are enabled, get info for each active connection
for (uint8_t i = 0; i < UIP_CONF_MAX_CONNECTIONS; i++) {
conn = &uip_conns[i];
// If there is an open connection to one of the listening ports, print the info
// This logic seems to be backwards?
if (uip_stopped(conn)) {
Serial.print(F("Connection no "));
Serial.println(i);
Serial.print(F("Local Port "));
Serial.println(htons(conn->lport));
Serial.print(F("Remote IP/Port "));
Serial.print(htons(conn->ripaddr[0]) >> 8);
Serial.print(F("."));
Serial.print(htons(conn->ripaddr[0]) & 0xff);
Serial.print(F("."));
Serial.print(htons(conn->ripaddr[1]) >> 8);
Serial.print(F("."));
Serial.print(htons(conn->ripaddr[1]) & 0xff);
Serial.print(F(":"));
Serial.println(htons(conn->rport));
Serial.print(F("Outstanding "));
Serial.println((uip_outstanding(conn)) ? '*' : ' ');
}
}
return 1;
}
The RX_ADDR_P0-1 address is fine, not sure what the problem would be. The SLIP examples never worked very well, really just a proof of concept, it’s recommended to use a raspberry Pi as the gateway with RF24gateway.
On Apr 4, 2021, at 12:30 PM, Bernard van der Nest @.***> wrote:
I am using the latest code downloaded from GitHub. I have very little nRF24 experience and using the libraries to learn. I successfully covered all the examples over the last few weeks up to the RF24Ethernet SLIP_InteractiveServer and SLIP_Gateway. I have made no code changes to the examples, except put a radio.printDetails() in the code to show the configuration. From the documentation it seems the problem is RX_ADDR_P0-1 in the SLIP_InteractiveServer code. I ask your assistance to help correct the addresses. RF24Ethernet SLIP_InteractiveServer:
RF24Ethernet SLIP_Gateway:
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or unsubscribe.
I don't know anybody who did not curse SLIP when we used it in the 90s to network systems. I have some RPis, will hook the demo gateway up on one. Your effort in expanding the nRF24 library code over years is highly appreciated.
@TMRh20 - I have the SLIP example bug fixed and working, I understand the code now much better. I will post the working code shortly.
I have modified the example code and stripped out everything that was not needed as below. It only works while you are sending GET requests via a browser, Postman or curl. If you leave the the InteractiveServer running for a few minutes then it dies. A quick disconnect and connect on the serial port and all runs well again. It seems that when there are no packets flowing or something it quits life. I am not sure I want to continue with the example code as the model is not what I require, I only did this because it was not working at all and I wanted to learn as much as possible. I might come back to this when time permits. I need a very remote Nano Node to be a SLIP client opening a SLIP connection (or simpler) to the Gateway as a server, make a MqTT connection via the PubSub Lib, publish and receive a couple of messages and then disconnect.
RF24Ethernet Serial Gateway Example using SLIP
/*
* The code was modified to work with 2 x Arduino Mega 2560 board for development purposes.
*
* RF24Ethernet Serial Gateway Example using SLIP *
* This example will allow RF24Ethernet to be used with any device capable of the SLIP protocol
*
* When using SLIP, there are 3 main differences to the SLIP_Gateway:
* 1. The RF24Mesh layer is used to provide MAC/IP translation
* 2. The Master node will always have a NodeID of 0, and the IPV4 address for the Master
* in this example is defined as 10.0.3.1
* 2. The child nodes The specified RF24Mesh nodeID must be the same as the last octet of the IP
* ie: IP: 10.0.3.2 NodeId must be 2
* * 3. The RF24Ethernet library must be configured for TUN
* a: Open the uip-conf.h file in the RF24Ethernet directory and set the #define UIP_CONF_LLH_LEN 0
*
* The following commands must be run on the Linux device to enable slip
* 1. On Linux the ports are created in the dev directory, cd /dev
* 2. Type 'ls' , note the ttyUSB<X> devices
* 3. Connect your Arduino
* 4. Type 'ls' and look for a new device ttyUSB<X> where <X> is a number
* 5. Run sudo modprobe slip
* 6. Run sudo slattach -L -s 115200 -p slip /dev/ttyUSB<X> &
* 7. Note the & at the end of the previous command. This will run slattach in the background,
* without it, slattach will appear to hang and CTRL+C will exit.
* 7. Run ifconfig , note the sl<X> device
* 8. Run sudo ifconfig sl<X> 10.10.3.1
* 9. Run sudo route add -net 10.10.3.0/24 gw 10.10.3.1
* 10. The gateway is now up and running. Active RF24Ethernet nodes should be pingable.
- Scripts used on Linux
sudo modprobe slip
sudo sysctl -w net.ipv4.ip_forward=1
sudo slattach -L -s 115200 -p slip /dev/ttyACM0 &
sudo ifconfig sl0 10.10.3.1 dstaddr 10.10.3.2
Note: If using an ip of 192.168.3.1 for the gateway, the commands are very similar:
ie: sudo route add -net 192.168.3.0/24 gw 192.168.3.1
* RF24Ethernet uses the uIP stack by Adam Dunkels <[email protected]>
*
* This example demonstrates how to configure a sensor node to act as a webserver and
* allows a user to control a connected LED by clicking links on the webpage
*
* The requested URL is used as input, to determine whether to turn the LED off or on
*
* Debug Settings:
* This example uses a second Serial Port - Serial1 to print the debug information to
* in order not to interfere with the SLIP network
* Connect a FTDI or Foca Pro to PINs 18 & 19 as well as GND
* The Serial Port on Linux will appear in the /dev directory as /dev/ttyUSB0 or higher
* number if you have more serial devices connected.
* Edit prinf.h in the RF24 directory
* */
#include <SPI.h>
#include <RF24.h>
#include <RF24Network.h>
#include <RF24Mesh.h>
#include <printf.h>
/**** Configure the nRF24L01 CE and CS pins ****/
RF24 radio(7, 8);
RF24Network network(radio);
RF24Mesh mesh(radio, network);
// Comment the following define out if no debug is needed
#define SLIP_DEBUG_LED // Will delay and flash LEDs if unable to find a node by IP address ( node needs to reconnect via RF24Mesh )
#define SLIP_DEBUG_SERIAL // Serial Output
// Define the LED pins
// #define DEBUG_LED_PIN A3
#define DEBUG_LED_PIN 40
#define SLIP_TXRX_LED_PIN 41
#define NETWORK_TXRX_LED_PIN 42
// Connect LED Cathode to the PIN and the Anode via a LED resistor to Vcc (sink mode)
#define LED_OFF 1
#define LED_ON 0
// NOTE: IMPORTANT this should be set to the same value as the UIP_BUFSIZE and
// the MAX_PAYLOAD_SIZE in RF24Network. The default is 120 bytes
#define UIP_BUFFER_SIZE MAX_PAYLOAD_SIZE
// Global variables
uint8_t slip_buf[UIP_BUFFER_SIZE]; // MSS + TCP Header Length
uint32_t mesh_timer = 0;
uint32_t mesh_time = 30000; // Every 30 seconds, test mesh connectivity
uint32_t debug_info_timer = 0;
uint32_t debug_info_time = 30000; // Every 30 seconds, we display the debug information
//Function to send incoming network data to the SLIP interface
void networkToSLIP();
void setup() {
SPI.begin();
radio.begin();
Serial.begin(115200);
while (!Serial) {
// some boards need to wait to ensure access to serial over USB
// We will use this Serial Port for SLIP <-> NETWORK messages
}
#if defined SLIP_DEBUG_SERIAL
Serial1.begin(115200);
while (!Serial1) {
// some boards need to wait to ensure access to serial over USB
// We will use this Serial Port for Debug Messages
// Foca Pro connected to GND, PIN 18 & PIN 19, /dev/ttyUSB0
}
printf_begin(); // Call once, setup for printing debug information to Serial Port 1
Serial1.println();
Serial1.print(F("RF24_SLIP_Gateway\n"));
#endif
// Set this to the master node (nodeID 0)
mesh.setNodeID(0);
mesh.begin();
// Use Serial as the SLIP device
slipdev_init(Serial);
pinMode(53, OUTPUT); // Mega 2560 SPI Library fix
// Start-up signal - make sure our LED's are working
#if defined SLIP_DEBUG_LED
// Debug LED stuff
pinMode(DEBUG_LED_PIN, OUTPUT);
pinMode(SLIP_TXRX_LED_PIN, OUTPUT); // SLIP -> Network
pinMode(NETWORK_TXRX_LED_PIN, OUTPUT); // Network -> SLIP
for (int i=0; i<5; i++){
digitalWrite(DEBUG_LED_PIN, LED_ON);
digitalWrite(SLIP_TXRX_LED_PIN, LED_ON);
digitalWrite(NETWORK_TXRX_LED_PIN, LED_ON);
delay(50);
digitalWrite(DEBUG_LED_PIN, LED_OFF);
digitalWrite(SLIP_TXRX_LED_PIN, LED_OFF);
digitalWrite(NETWORK_TXRX_LED_PIN, LED_OFF);
delay(50);
}
#endif
// Radio Settings
radio.setPALevel(RF24_PA_MIN, false);
#if defined SLIP_DEBUG_SERIAL
// //Debug information
Serial.println(F("**** RF24 Radio Information ****"));
radio.printDetails(); // (smaller) function that prints raw register values
// radio.printPrettyDetails(); // (larger) function that prints human readable data
Serial.println(F("********************************"));
#endif
}
void loop() {
// Call mesh.update to keep the network updated
mesh.update();
// In addition, keep the 'DHCP service' running on the master node so addresses will
// be assigned to the sensor nodes
mesh.DHCP();
// Provide RF24Network addresses to connecting & reconnecting nodes
if((millis()-mesh_timer)>mesh_time){
mesh_timer = millis();
mesh.DHCP();
}
if((millis()-debug_info_timer)>debug_info_time){ // Every ss seconds, display the debug values
debug_info_timer = millis();
#if defined SLIP_DEBUG_SERIAL
Serial1.println(F("**** RF24Mesh Assigned Addresses ****"));
for(int i=0; i<mesh.addrListTop; i++){
Serial1.print("NodeID: ");
Serial1.print(mesh.addrList[i].nodeID);
Serial1.print(" RF24Network Address: 0");
Serial1.println(mesh.addrList[i].address,OCT);
}
Serial1.println(F("*************************************"));
#endif
}
//Ensure any incoming user payloads are read from the buffer
while(network.available()){
RF24NetworkHeader header;
network.read(header,0,0);
}
// Handle external (TCP) data
// Note: If not utilizing RF24Network payloads directly, users can edit the RF24Network_config.h file
// and uncomment #define DISABLE_USER_PAYLOADS. This can save a few hundred bytes of RAM.
if(network.update() == EXTERNAL_DATA_TYPE) {
networkToSLIP();
}
// Poll the SLIP device for incoming data
//uint16_t len = slipdev_poll();
uint16_t len;
if( (len = slipdev_poll()) > 0 ){
if(len > MAX_PAYLOAD_SIZE){
return;
}
#if defined SLIP_DEBUG_LED
digitalWrite(SLIP_TXRX_LED_PIN, LED_ON);
#endif
RF24NetworkHeader header(01, EXTERNAL_DATA_TYPE);
uint8_t meshAddr;
// Get the last octet of the destination IP address
uint8_t lastOctet = slip_buf[19];
//Convert the IP into an RF24Network Mac address
if ( (meshAddr = mesh.getAddress(lastOctet)) > 0) {
// Set the RF24Network address in the header
header.to_node = meshAddr;
#if defined SLIP_DEBUG_LED
digitalWrite(SLIP_TXRX_LED_PIN, LED_OFF);
#endif
network.write(header, &slip_buf, len);
}
else {
// If nodeID/IP not found in address list, the node would need to renew its address
// Flash the LED 3 times slowly
#if defined SLIP_DEBUG_LED
flashLED();
#endif
}
}
}
void networkToSLIP(){
#if defined SLIP_DEBUG_LED
digitalWrite(NETWORK_TXRX_LED_PIN, LED_ON);
#endif
RF24NetworkFrame *frame = network.frag_ptr;
size_t size = frame->message_size;
uint8_t *pointer = frame->message_buffer;
slipdev_send(pointer, size);
#if defined SLIP_DEBUG_SERIAL
Serial1.print(F("ADDR not found\n"));
#endif
#if defined SLIP_DEBUG_LED
digitalWrite(NETWORK_TXRX_LED_PIN, LED_OFF);
#endif
}
void flashLED() {
for (int i=0; i<6; i++){
digitalWrite(DEBUG_LED_PIN, !digitalRead(DEBUG_LED_PIN));
delay(200);
}
}
RF24_SLIP_InteractiveServer
/*
* Configuration for Arduino Mega 2560
* SPI https://www.arduino.cc/en/Reference/SPI
* Mega 2560
* nFR24L01
*
* GND - 1 * * 2 - +Vcc
* CE - 3 * * 4 - CNS
* SCK - 5 * * 6 - MOSI
* MISO - 7 * * 8 - IRQ
*
* With adapter YL-105
*
* 1 - CE Mega 2560 PIN 7 Yellow
* 2 - CSN Mega 2560 PIN 8 Orange
* 3 - SCK Mega 2560 PIN 52 Green
* 4 - MOSI Mega 2560 PIN 51 Blue
* 5 - MISO Mega 2560 PIN 50 Purple
* 6 - IRQ NC White
*
* MOSI=ICSP-4 or 51, MISO=ICSP-1 or 50, SCK=ICSP-3 or 52, SS=53
*
* MISO - 1 * * 2 - +Vcc
* SCK - 3 * * 4 - MOSI
* Reset - 5 * * 6 - GND
*
* Insure that PIN 53 is set as Output on the Mega 2560 for the SPI Library
*
* The RF24_SLIP_InteractiveServer is a sample Webserver controlling an LED.
* Please see the RF24_SLIP_Gateway sketch for the reciprocal settings.
*
* * This example demonstrates how to configure a sensor node to act as a webserver and
* allows a user to control a connected LED by clicking links on the webpage
* The requested URL is used as input, to turn the LED OFF or ON, or show some statistics.
*
* Call with:
* http://10.10.3.2:1000/ON
* http://10.10.3.2:1000/OFF
*/
#include <SPI.h>
#include <RF24.h>
#include <RF24Network.h>
#include <RF24Ethernet.h>
#include <printf.h>
// Include RF24Mesh and the EEPROM libs
#include "RF24Mesh.h"
#include "EEPROM.h"
/*** Configure the radio CE & CS pins ***/
RF24 radio(7,8);
RF24Network network(radio);
RF24Mesh mesh(radio, network);
RF24EthernetClass RF24Ethernet(radio, network, mesh);
// If debug information is not required comment the following line out
#define SERVER_DEBUG
// #define LED_PIN A3 // Analog pin A3
#define LED_PIN 40 // For Arduino Mega 2560 LED 1 (Blue)
#define DEBUG_LED_PIN 41 // For Arduino Mega 2560 LED 2 (Red)
// State of the LED in words
String led_state;
// Connect LED Cathode to the PIN and the Anode via a LED resistor to Vcc (sink mode)
#define LED_OFF 1
#define LED_ON 0
// Configure the server to listen on port 1000
EthernetServer server = EthernetServer(1000);
// Global variables
uint32_t mesh_timer = 0;
uint32_t mesh_time = 30000; // Every 30 seconds, test mesh connectivity
uint32_t debug_timer = 0;
uint32_t debug_time = 10000; // Every 1S seconds, give us a pulse
uint16_t led_control = 0;
uint32_t led_timer = 0;
uint32_t led_time = 1000; // Every 1 second - ON/OFF
String client_Req;
char req_index = 0; // index into the Client HTTP request buffer
/**********************************************************/
void setup() {
// Set up the speed of our serial link.
Serial.begin(115200);
while (!Serial) {
// some boards need to wait to ensure access to serial over USB
// We will use this Serial Port for debug messages
}
// printf_begin(); // Required to get the printDetails() to display the values
Serial.println();
Serial.println("RF24_SLIP_InteractiveServer Start");
pinMode(LED_PIN, OUTPUT);
pinMode(DEBUG_LED_PIN, OUTPUT);
pinMode(53, OUTPUT);
// Start-up signal - make sure our LEDs are working
#if defined SERVER_DEBUG
for (int i=0; i<5; i++){
digitalWrite(DEBUG_LED_PIN, LED_ON);
digitalWrite(LED_PIN, LED_ON);
delay(50);
digitalWrite(DEBUG_LED_PIN, LED_OFF);
digitalWrite(LED_PIN, LED_OFF);
delay(50);
}
#else
for (int i=0; i<5; i++){
digitalWrite(LED_PIN, LED_ON);
delay(50);
digitalWrite(LED_PIN, LED_OFF);
delay(50);
}
#endif
// This step is very important.
// When using TUN or SLIP, the IP of the device must be
// configured as a NodeID in the RF24Mesh layer
mesh.setNodeID(2);
mesh.begin();
// Radio Settings
radio.setPALevel(RF24_PA_MIN, false);
#if defined SERVER_DEBUG
// Debug information
// Serial.println(F("**** RF24 Radio Information ****"));
// radio.printDetails(); // (smaller) function that prints raw register values
// radio.printPrettyDetails(); // (larger) function that prints human readable data
// Serial.println(F("********************************"));
#endif
// Set the IP address we'll be using. Make sure this doesn't conflict with
// any IP addresses or subnets on your LAN or you won't be able to connect to
// either the Arduino or your LAN...
// NOTE: The last octet/last digit of the IP must match the RF24Mesh nodeID above
IPAddress myIP(10, 10, 3, 2);
Ethernet.begin(myIP);
// If you'll be making outgoing connections from the Arduino to the rest of
// the world, you'll need a gateway set up.
IPAddress gwIP(10, 10, 3, 1);
Ethernet.set_gateway(gwIP);
// Listen for incoming connections on TCP port 1000.
server.begin();
// Initial state of the LED
digitalWrite(LED_PIN, LED_OFF);
led_state = "OFF";
}
/********************************************************/
void loop() {
/*
if(millis()-debug_timer > debug_time){ // Every ss seconds, test mesh connectivity
debug_timer = millis();
}
*/
if(millis()-led_timer > led_time){ // Pulse...
led_timer = millis();
if (led_control) {
digitalWrite(DEBUG_LED_PIN, LED_ON);
led_control = 0;
} else {
digitalWrite(DEBUG_LED_PIN, LED_OFF);
led_control = 1;
}
}
// For some reason the Network stops working....
mesh.update(); // Mesh update
// network.update();
// Ethernet.update(); // Keep the network stack updated
// This is the last of the differences between this and the regular Interactive Server example
// If the master node is completely down, and unresponsive for 30 seconds, renew the address
if(millis()-mesh_timer > mesh_time){ // Every ss seconds, test mesh connectivity
mesh_timer = millis();
if( ! mesh.checkConnection() ){
mesh.renewAddress(); //refresh the network address
#if defined SERVER_DEBUG
for (int i=0; i<5; i++){
digitalWrite(DEBUG_LED_PIN, LED_ON);
delay(50);
digitalWrite(DEBUG_LED_PIN, LED_OFF);
delay(50);
}
#endif
}
}
EthernetClient client = server.available();
if (client) {
Serial.println("Cient connect");
boolean endofRequest = true;
req_index=0;
while (client.connected()) {
if (client.available()) {
char c = client.read();
if (client_Req.length() < 128) { // Read char by char HTTP request
client_Req += c; // Store characters into String Object
}
if (c == '\n' && endofRequest) {
// Send the standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
// Now we send a basic web page
client.println("<!DOCTYPE html>");
client.println("<html>");
client.println("<head>");
client.println("<title>RF24_SLIP_InteractiveServer</title>");
client.println("</head>");
client.println("<body>");
client.println("<h1>Arduino Server</h1>");
client.print("<p>IP Address: ");
client.print(Ethernet.localIP());
client.println("</p>");
client.println("</body>");
client.println("</html>");
break;
}
// Check for the sequence \r\n
if (c == '\n') {
endofRequest = true; // we received a \n
}
else if (c != '\r') {
endofRequest = false;
}
} // end if (client.available())
} // end while (client.connected())
Serial.print("Client Request:");
Serial.println(client_Req);
if (client_Req.indexOf("/ON") >0){
digitalWrite(LED_PIN, LED_ON);
led_state = "ON";
Serial.println("LED ON");
}
if (client_Req.indexOf("/OFF") >0){
digitalWrite(LED_PIN, LED_OFF);
led_state = "OFF";
Serial.println("LED OFF");
}
//clearing string for next read
client_Req="";
delay(1); // Give the web browser time to receive the data
client.flush();
client.stop(); // Slose the client connection
Serial.println("Cient disconnect");
} // end if (client)
// We can do other things in the loop, but be aware that the loop will
// briefly pause while IP data is being processed.
}
I can't seem to recreate the issue, even after leaving the devices inactive for a good while, so I would have to suggest a hardware issue, loose wire etc... something else causing it not to work after a while. I noticed it was spotty after one test, but it started working again after a minute with no changes.
A couple notes:
- Should be calling
Ethernet.update();
instead ofmesh.update();
in the RF24_SLIP_InteractiveServer example code - The pubsub library seems to be a bit unreliable, suggest using the alternate mqtt library shown in 2nd mqtt example
Your advice is welcome, just when I think I am done. LOL! So I guess it is working after all, such a fantastic idea and solution. I would definitely not rule hardware out. I did a lot of reading and implemented all the fixes mentioned on the Forums. I bought the first two nRF24L01+ PA LNA boards plus interfaces from a local online shop, the quality is definitely not consumer grade. I have a 10 pack of each en route somewhere between China and home, then I can swap devices around to eliminate issues. Still learning, the fun and games will start when distance increases between the devices and the baud rate has to slow down, the packet size decrease and the noise level increases as the signal strength drops.
2021-04-26: Update, I am going to solve the problem, made lots of progress after I verified the reception and buffering of the fragments. I now have most of RF24Ethernet figured out as I added more informative debug output. Although the code is well documented there are some areas which take time to work through and understand. I am also not a C++ programmer and building usable code fragments take time as I have to stop and learn the more advanced concepts of the language.
@TMRh20, it is not the hardware. I now have some more radios and also found the RadioHead libraries to play with. However, for IP over a radio network I will spare no effort. With just the Ethernet stack running, I noticed that a lot of pings ago astray so a started there.
The methodology I followed:
- If I send a ping, I can capture the ping using wireshark.
- Then I can dump the input buffer and compare the wireshark data with the Arduino buffer.
My findings as follows. Maybe it is suppose to be like this, but I am not sure:
-
Ping data capture on sl0 the slip interface of the Linux machine: 0000 45 00 00 54 a7 e8 40 00 40 01 78 aa 0a 0a 03 02 0010 0a 0a 03 01 00 00 1d 12 00 b8 00 01 2a 84 84 60 0020 00 00 00 00 6a 7d 0a 00 00 00 00 00 10 11 12 13 0030 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 0040 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 0050 34 35 36 37
-
Data from dump. The xxxx is first 12 bytes in the data buffer which I cannot figure out (yet). Then the icmp ping data follows, but is 12 bytes short. So I took a wild guess and added 12 bytes to the length of uip_len and get the full frame.
-- Output from Serial Debugging 172599: MAC Received id 36951 from 00 to 05 type 149 172601: NET message 1514 172603: NET Enqueue @0 [Reading 20 bytes 0 blanks] write_register(07,40) 172616: MAC Received id 36951 from 00 to 05 type 150 172619: NET message 2d2c 172621: NET Enqueue @0 172623: RX 54(84) bytes xxxx 00 00 05 00 57 90 83 00 54 00 D4 05 0000 45 00 00 54 A7 E8 40 00 40 01 78 AA 0A 0A 03 01 0010 0A 0A 03 02 08 00 15 12 00 B8 00 01 2A 84 84 60 0020 00 00 00 00 6A 7D 0A 00 00 00 00 00 10 11 12 13 0030 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 0040 24 25 26 27 28 29 2A 2B After 0000 45 00 00 54 A7 E8 40 00 40 01 78 AA 0A 0A 03 01 0010 0A 0A 03 02 08 00 15 12 00 B8 00 01 2A 84 84 60 0020 00 00 00 00 6A 7D 0A 00 00 00 00 00 10 11 12 13 0030 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 0040 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 0050 34 35 36 37 write_register(00,0e) write_register(02,3f) 172683: NET Sending id 90 from 05 to 00 type 148 172686: NET message 12 1d 00 00 01 03 0a 0a 02 03 0a 0a aa 78 01 40 00 40 e8 a7 54 00 00 45 172694: MAC Sending to 00 via 00 on pipe 5 write_register(01,3f) 172700: NET Pipe 5 on node 00 has address cccccccce3 [Writing 32 bytes 0 blanks]
Code 1 - added a few lines of debug code in RF24Ethernet.cpp
void RF24EthernetClass::tick()
{
#if defined (ARDUINO_ARCH_ESP8266)
yield();
#endif
if (RF24Ethernet.network.update() == EXTERNAL_DATA_TYPE) {
if (RF24Ethernet.network.frag_ptr->message_size <= UIP_BUFSIZE) {
uip_len = RF24Ethernet.network.frag_ptr->message_size;
// Bernard - debug code to trace hang-up
// 1. Serial.println(); Serial.print(millis()); Serial.print(F(" uip_len=")); Serial.println(uip_len);
// 2. Dump the incoming data for analysis:
printf("\n\r%lu: RX %X(%d) bytes\n\r", millis(), uip_len, uip_len);
const char *msgPtr = reinterpret_cast<const char *>(RF24Ethernet.network.frag_ptr);
// 2.1 Print the unknown data
uint8_t y = 0, x = 1, r = 0;
uint8_t i = 0, j = 0, z = 0x0c;
// Not sure what this is yet.
j = z; // Print unknown data
printf("xxxx ");
for (i = 0; i < j; i++) {
printf("%02X ", msgPtr[i] & 0xff);
};
printf("\n\r");
// 2.2 Data buffer in wireshark format up to uip_len
i = z; j = uip_len;
printf("%04X ", y);
for (i; i < j; i++) {
printf("%02X ", msgPtr[i] & 0xff);
if (x > 0x0f){
printf("\n\r");
printf("%04X ", y=y+x);
x=0;
}
x++;
};
printf("\n\r*After*\n\r");
// 2.3 Now we add extra bytes(z) after ip_len
y = 0; x = 1; i = z; j = (uip_len + z);
printf("%04X ", y);
for (i; i < j; i++) {
printf("%02X ", msgPtr[i] & 0xff);
if (x > 0x0f){
printf("\n\r");
printf("%04X ", y=y+x);
x=0;
}
x++;
};
printf("\n\r");
}
}
// For TUN/SLIP - Layer 3, IP Packects
#if !defined (RF24_TAP)
if (uip_len > 0) {
// Bernard
#if defined (SERIAL_DEBUG_RXTX)
// Serial.println(); Serial.print(millis()); Serial.print(F(" uip_len=")); Serial.println(uip_len);
#endif
uip_input();
if (uip_len > 0) {
network_send();
}
}
else if (timer_expired(&Ethernet.periodic_timer)) {
timer_reset(&Ethernet.periodic_timer);
for(int i = 0; i < UIP_CONNS; i++) {
uip_periodic(i);
/* If the above function invocation resulted in data that
should be sent out on the network, the global variable
uip_len is set to a value > 0. */
if (uip_len > 0) {
network_send();
}
}
}
// For TAP - Layer 2, Ethernet Frames
#else // defined (RF24_TAP)
if (uip_len > 0) {
if (BUF->type == htons(UIP_ETHTYPE_IP)) {
uip_arp_ipin();
uip_input();
/* If the above function invocation resulted in data that
should be sent out on the network, the global variable
uip_len is set to a value > 0. */
if (uip_len > 0) {
uip_arp_out();
network_send();
}
}
else if (BUF->type == htons(UIP_ETHTYPE_ARP)) {
uip_arp_arpin();
/* If the above function invocation resulted in data that
should be sent out on the network, the global variable
uip_len is set to a value > 0. */
if (uip_len > 0) {
network_send();
}
}
}
else if (timer_expired(&Ethernet.periodic_timer)) {
timer_reset(&Ethernet.periodic_timer);
for(int i = 0; i < UIP_CONNS; i++) {
uip_periodic(i);
/* If the above function invocation resulted in data that
should be sent out on the network, the global variable
uip_len is set to a value > 0. */
if (uip_len > 0) {
uip_arp_out();
network_send();
}
}
#endif // defined (RF24_TAP)
#if UIP_UDP
for(int i = 0; i < UIP_UDP_CONNS; i++) {
uip_udp_periodic(i);
/* If the above function invocation resulted in data that
should be sent out on the network, the global variable
uip_len is set to a value > 0. */
if (uip_len > 0) {
//uip_arp_out();
//network_send();
RF24UDP::_send((uip_udp_userdata_t *)(uip_udp_conns[i].appstate));
}
}
#endif /* UIP_UDP */
#if defined (RF24_TAP)
/* Call the ARP timer function every 10 seconds. */
if (timer_expired(&Ethernet.arp_timer)) {
timer_reset(&Ethernet.arp_timer);
uip_arp_timer();
}
}
#endif //RF24_TAP
}
Code 2
#include <SPI.h>
#include <RF24.h>
#include <RF24Network.h>
#include <RF24Ethernet.h>
// Include RF24Mesh and the EEPROM libs
#include "RF24Mesh.h"
#include "EEPROM.h"
#include "printf.h"
#define RF24_CE_PIN 7
#define RF24_CS_PIN 8
/*** Configure the radio CE & CS pins ***/
RF24 radio(RF24_CE_PIN, RF24_CS_PIN);
RF24Network network(radio);
RF24Mesh mesh(radio, network);
RF24EthernetClass RF24Ethernet(radio, network, mesh);
#define LED_PIN 40 // For Arduino Mega 2560 LED 1 (Blue)
#define DEBUG_LED_PIN 41 // For Arduino Mega 2560 LED 2 (Red)
// Connect LED Cathode to the PIN and the Anode via a LED resistor to Vcc (sink mode)
#define LED_OFF 1
#define LED_ON 0
// Configure the server to listen on port 1000
EthernetServer server = EthernetServer(1000);
// Global variables
uint32_t mesh_timer = 0;
uint32_t mesh_time = 30000; // Every 30 seconds, test mesh connectivity
uint16_t led_control = 0;
uint32_t led_timer = 0;
uint32_t led_time = 1000; // Every 1 second - ON/OFF
String client_Req;
char req_index = 0; // index into the Client HTTP request buffer
// Incoming network data
uint8_t message_buffer[MAX_FRAME_SIZE];
/**********************************************************/
void setup() {
// Set up the speed of our serial link.
Serial.begin(115200);
while (!Serial) {
// some boards need to wait to ensure access to serial over USB
// We will use this Serial Port for debug messages
}
printf_begin(); // Required to get the printDetails() to display the values
Serial.println();
Serial.println("RF24_SLIP_InteractiveServer Start");
pinMode(DEBUG_LED_PIN, OUTPUT);
pinMode(53, OUTPUT);
// Start-up signal - make sure our LEDs are working
for (uint16_t i=0; i<5; i++){
digitalWrite(DEBUG_LED_PIN, LED_ON);
delay(50);
digitalWrite(DEBUG_LED_PIN, LED_OFF);
delay(50);
}
// This step is very important.
// When using TUN or SLIP, the IP of the device must be
// configured as a NodeID in the RF24Mesh layer
mesh.setNodeID(2);
mesh.begin();
// Radio Settings
radio.setPALevel(RF24_PA_MIN, false);
radio.setDataRate(RF24_250KBPS);
// Set the IP address we'll be using. Make sure this doesn't conflict with
// any IP addresses or subnets on your LAN or you won't be able to connect to
// either the Arduino or your LAN...
// NOTE: The last octet/last digit of the IP must match the RF24Mesh nodeID above
IPAddress myIP(10, 10, 3, 2);
Ethernet.begin(myIP);
// If you'll be making outgoing connections from the Arduino to the rest of
// the world, you'll need a gateway set up.
IPAddress gwIP(10, 10, 3, 1);
Ethernet.set_gateway(gwIP);
// Listen for incoming connections on TCP port 1000.
server.begin();
}
/********************************************************/
void loop() {
if(millis()-led_timer > led_time){ // Pulse...
led_timer = millis();
if (led_control) {
digitalWrite(DEBUG_LED_PIN, LED_ON);
led_control = 0;
} else {
digitalWrite(DEBUG_LED_PIN, LED_OFF);
led_control = 1;
}
}
// This is the last of the differences between this and the regular Interactive Server example
// If the master node is completely down, and unresponsive for 30 seconds, renew the address
if(millis()-mesh_timer > mesh_time){ // Every ss seconds, test mesh connectivity
mesh_timer = millis();
if( ! mesh.checkConnection() ){
mesh.renewAddress(); //refresh the network address
}
}
Ethernet.update(); // Keep the network stack updated
}
it is not the hardware
Are you sure? I'm unable to replicate the problem of it failing after a few minutes and the PA + LNA modules are notorious for having issues with power supplies. I'm not sure what to make of your results otherwise.
Power problems, you are correct. I have the modules connected to a Riden RD6006 for development and testing. I had to go from 10uF up to a 100uF decoupling capacitor to get the units stable, followed the advise on many posts and forums. Sorry about my confusing post. I will report on the issue once I can produce meaningful log results between what is transmitted and received. I have spend time to create a trace and data dumps that is less engineering and more network related. The RF24Network part runs 24x7 for days.
When time permits I have been been coding and made progress on the issue. Just using a simple ICMP ping between the gateway and the server, embedding debug printing and reading most of the code and include files - I have a better understanding and view of what goes wrong. 90% of the time I can more or less predict when the hang-up is going to occur.
- After start-up + 1 min. I ping from the Gateway to the Server a few times.
- Then I leave the two devices running for about 5 min.
- When I ping next, it either still works 100% or the First Fragment is received, then the Second Fragment and then the Radio will stop right there in an error condition - stop is perhaps the wrong word, it gets stuck and the code runs in a loop, endess loop.
- When the hang-up occurs the register RX_DR is always 1, and sometimes RX_P_NO goes to 0. Now no data is received any longer of course. Going back to power, wires, antenna placement - I have tried everything, even tracing all the radio.startListening() and radio.stopListening pairs, looking for buffer over runs, the memcpy in the enqueue.... etc.
- In the Class function RF24Network::update() I can now see the significance of radio.failureDetected = 1, as the software goes into an endless loop, running RF24Network::update() over and over from Loop().
- No matter what I have tried, I simply can't find a way to re-initialize the radio from scratch when the code is back on Loop() If it was just as simple as something like:
if(radio.failureDetected){
printf("loop() - failureDetected\n\r");
radio.powerDown();
report_failure(); // Blink leds, send a message, etc. to indicate failure
radio.powerUp();
radio.begin(); // Attempt to re-configure the radio with defaults
mesh.setNodeID(2);
mesh.begin();
radio.failureDetected = 0; // Reset the detection value
}
Some more time will tell. Here is an example of my debug output:
RX = Receiving Data
TX = Transmitting Data
FF = First Fragment
MF = More Fragment
LF = Last Fragment
SYS = System Types
-
Error: RX<-FF 00 00 05 00 B0 1D 94 04 45 00 00 54 B4 C5 40 00 40 01 6B CD 0A 0A 03 01 0A 0A 03 02 08 00 E7 FF RX<-MF 00 00 05 00 B0 1D 95 03 02 F2 00 01 33 AA A2 60 00 00 00 00 76 2F 02 00 00 00 00 00 10 11 12 13 RF24Network::update-failureDetected STATUS = 0xaa RX_DR=0 TX_DS=1 MAX_RT=0 RX_P_NO=5 TX_FULL=0 RF24Network::update-failureDetected STATUS = 0xaa RX_DR=0 TX_DS=1 MAX_RT=0 RX_P_NO=5 TX_FULL=0 RF24Network::update-failureDetected STATUS = 0xaa RX_DR=0 TX_DS=1 MAX_RT=0 RX_P_NO=5 TX_FULL=0 -- goes into endless loop
-
Working TX->POLL 24 09 40 00 6E 00 C2 21 RX<-POLL 00 00 24 09 6E 00 C2 21 TX->REQ 24 09 00 00 6E 00 C3 02 TX->POLL 24 09 40 00 6F 00 C2 02 TX->POLL 24 09 40 00 70 00 C2 02 TX->POLL 24 09 40 00 71 00 C2 02 TX->POLL 24 09 40 00 72 00 C2 02 TX->POLL 24 09 40 00 73 00 C2 02 TX->POLL 24 09 40 00 74 00 C2 02 TX->POLL 24 09 40 00 75 00 C2 02 TX->POLL 24 09 40 00 76 00 C2 02 RX<-POLL 00 00 24 09 76 00 C2 02 TX->REQ 24 09 00 00 76 00 C3 02 RX<-ADDR 00 00 24 09 76 00 80 02 05 00 TX->SYS 05 00 00 00 77 00 C6 00 05 00 RX<-SYS 00 00 05 00 77 00 C6 00 02 00 RX<-FF 00 00 05 00 3A 00 94 04 45 00 00 54 E1 60 40 00 40 01 3F 32 0A 0A 03 01 0A 0A 03 02 08 00 14 CE RX<-MF 00 00 05 00 3A 00 95 03 02 F6 00 01 9E AB A2 60 00 00 00 00 D6 5B 0A 00 00 00 00 00 10 11 12 13 RX<-MF 00 00 05 00 3A 00 95 02 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B RX<-LF 00 00 05 00 3A 00 96 83 2C 2D 2E 2F 30 31 32 33 34 35 36 37 TX->FF 05 00 00 00 78 00 94 04 45 00 00 54 E1 60 40 00 40 01 3F 32 0A 0A 03 02 0A 0A 03 01 00 00 1C CE TX->MF 05 00 00 00 78 00 95 03 02 F6 00 01 9E AB A2 60 00 00 00 00 D6 5B 0A 00 00 00 00 00 10 11 12 13 TX->MF 05 00 00 00 78 00 95 02 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B TX->LF 05 00 00 00 78 00 96 83 2C 2D 2E 2F 30 31 32 33 34 35 36 37 TX->SYS 05 00 00 00 79 00 C4 1B 02 RX<-SYS 00 00 05 00 79 00 C4 1B 05 00 You can clearly see the ping in and out in the debug dump.
Will post back if I get to solve the issue. I very much like this Library.
1hr after writing the above - I now know how to break out of the endless loop back to the main loop() - it is simple, just a bit of code to fix the library. I am going to fix this.
RX<-FF 00 00 05 00 CD 24 94 04 45 00 00 54 C0 54 40 00 40 01 60 3E 0A 0A 03 01 0A 0A 03 02 08 00 0D D2 RX<-MF 00 00 05 00 CD 24 95 03 03 1E 00 01 29 C1 A2 60 00 00 00 00 51 1A 0B 00 00 00 00 00 10 11 12 13 RF24Network::update-failureDetected STATUS = 0xc1 RX_DR=1 TX_DS=0 MAX_RT=0 RX_P_NO=0 TX_FULL=1 RF24Network::update-failureDetected STATUS = 0xc1 RX_DR=1 TX_DS=0 MAX_RT=0 RX_P_NO=0 TX_FULL=1 loop() - failureDetected TX->POLL 24 09 40 00 3B 3F C2 C6 RF24Network::update-failureDetected STATUS = 0xc1 RX_DR=1 TX_DS=0 MAX_RT=0 RX_P_NO=0 TX_FULL=1 TX->POLL 24 09 40 00 3C 3F C2 C6 RF24Network::update-failureDetected