LowPowerLab Forum

Hardware support => Moteino => Topic started by: jrdoner on January 24, 2016, 10:46:59 PM

Title: Trouble with two-way communication
Post by: jrdoner on January 24, 2016, 10:46:59 PM
I have set up a simple example using nodes 1 and 2, with 2 transmitting data to 1.  That works fine, but I cannot seem to get a transmit path working in the other direction.  Does this require promiscuous mode, or some  secret handshake?

The radios initialize just fine.  My loop()s for these two programs are shown below.

void loop()
{
  int txRSSI;

 
  if (radio.receiveDone())
  {
      Serial.print("Tx node: "); Serial.println(radio.SENDERID);
      Serial.print("message "); Serial.println((char*)radio.DATA);
      txRSSI = radio.RSSI;
      Serial.print("RSSI "); Serial.println(txRSSI);
      Serial.println(); 

 
    wait(500);
    radio.send(1,"Got it", 6);
  } 
}



void loop()
{
  String stuff;
  int extra;
 
  timePassed = timePassed + 2;
  extra = timePassed + 3;
 
  sprintf(buff, "Init %d, %d, %d", timePassed, extra, extra + 1);
  radio.send(2, buff, strlen(buff));   //receiver node ID, message, length of message
 
  wait(550);
  if (!radio.receiveDone()) {};       //hang until data arrives
  if (radio.receiveDone()) Serial.println((char*) radio.DATA);
  wait(500);
}


Data flows from the bottom code to the top code, but nothing seems to occur when I send the "Got it".
Title: Re: Trouble with two-way communication
Post by: syrinxtech on January 25, 2016, 07:13:02 AM
Quote from: jrdoner on January 24, 2016, 10:46:59 PM
I have set up a simple example using nodes 1 and 2, with 2 transmitting data to 1.  That works fine, but I cannot seem to get a transmit path working in the other direction.  Does this require promiscuous mode, or some  secret handshake?

The radios initialize just fine.  My loop()s for these two programs are shown below.

void loop()
{
  int txRSSI;

 
  if (radio.receiveDone())
  {
      Serial.print("Tx node: "); Serial.println(radio.SENDERID);
      Serial.print("message "); Serial.println((char*)radio.DATA);
      txRSSI = radio.RSSI;
      Serial.print("RSSI "); Serial.println(txRSSI);
      Serial.println(); 

 
    wait(500);
    radio.send(1,"Got it", 6);
  } 
}



void loop()
{
  String stuff;
  int extra;
 
  timePassed = timePassed + 2;
  extra = timePassed + 3;
 
  sprintf(buff, "Init %d, %d, %d", timePassed, extra, extra + 1);
  radio.send(2, buff, strlen(buff));   //receiver node ID, message, length of message
 
  wait(550);
  if (!radio.receiveDone()) {};       //hang until data arrives
  if (radio.receiveDone()) Serial.println((char*) radio.DATA);
  wait(500);
}


Data flows from the bottom code to the top code, but nothing seems to occur when I send the "Got it".


I think your problem might be the double radio.receiveDone() calls in the second set of code.  The first call to radio.receiveDone() would get the "Got it" and clear the buffer.  When you call it again the message has already been received and processed so there is nothing let to receive.  Why the double call?
Title: Re: Trouble with two-way communication
Post by: jrdoner on January 25, 2016, 11:37:26 AM
I only put the first one in thinking that the

if (!radio.receiveDone)){};

line would cause the code to wait for actual data to arrive.

I was getting no response before I put that line in, also.
Title: Re: Trouble with two-way communication
Post by: syrinxtech on January 25, 2016, 04:51:23 PM
Seems to me it might be safer and more reliable to re-code this project using ACKs.  You could include the "Got it" message as part of the ACK.

The line:

if (!radio.receiveDone()) {};

isn't going to wait for anything.  The radio.receiveDone() call simply checks the incoming radio queue to see if anything has come in over the radio destined for this Moteino.  If yes, you process the data and if not, you move on to the next line of code.  The return is simply "true" or "false".  Since you threw in a NOT operator, the line of code translates to "If there is no data incoming on the radio, do nothing (empty braces)".  If you wanted this code to hold there until data came in you should probably change the "if" to a "while".  Of course, that is going to block the whole program until something does come in so from an efficiency standpoint that's probably not good programming.

I would look at the many examples from Felix and others on the Forum and re-write using ACK's.  Just my $0.02.
Title: Re: Trouble with two-way communication
Post by: jrdoner on January 25, 2016, 07:31:41 PM
You are correct about the need for a "while" statement.   But its not just an ACK that I want.  My point is that if I establish data flow in one direction, I can't seem to get data flow (not just ACK;s) going in the other direction.  Every example I've checked involves one way data flow.
Title: Re: Trouble with two-way communication
Post by: Felix on January 25, 2016, 09:14:17 PM
jrdorner,
A lot of my examples involve 2 way. Just look at the examples (https://github.com/LowPowerLab/RFM69/tree/master/Examples), for instance DoorBell, GarageMote, SwitchMote all receive
and transmit at various times.
The mating sketch that talks to them is the PiGateway (https://github.com/LowPowerLab/RFM69/blob/master/Examples/PiGateway/PiGateway.ino) sketch or MightyHat (https://github.com/LowPowerLab/RFM69/blob/master/Examples/MightyHat/MightyHat.ino). They both listen to serial for a request and then forward the message to the listening node.
In fact I would start simply with the Gateway and Node sketches which also do that. Every 3rd received packet, the Gateway example will send a packet to the node and also request an ACK from the node.
Title: Re: Trouble with two-way communication
Post by: jrdoner on January 25, 2016, 10:07:02 PM
Felix,.

I have looked at the doorbell example, and others.  Indeed, they involve two-way comm.   But I am trying to achieve two-way comm, basically doing the same thing, and I seem to get one way comm only.  I am using a Moteino and a  MoteMega.  None of the radio pins on either one are attached to anything external.  Both units can send and receive, because I can reverse their roles and get comm in the other direction, but never in both directions.  I will put my simplified loops here, just a few lines total, and please just tell me what is wrong with this code.  There must be something I don't get.


void loop()                //node 2 -- receive first, then transmit           
{

  if (radio.receiveDone())
  {
      Serial.print("Tx node: "); Serial.println(radio.SENDERID);
      Serial.print("message "); Serial.println((char*)radio.DATA);
      Serial.println(); 
     
      wait(100);                  //0.1 sec. delay
      data = data + 2;
      sprintf(buff, "Data %d", data);
      radio.send(1, buff, strlen(buff));
  } 
}



void loop()                      //node 1 -- transmit first, wait for reply
{
 
   data = data + 2;
 
   sprintf(buff, "Data =  %d", data);
   radio.send(2, buff, strlen(buff));             //receiver node ID, message, length of message
   wait(100);   
   if (radio.receiveDone())
   {
     Serial.print("Tx node: "); Serial.println(radio.SENDERID);
     Serial.print("message "); Serial.println((char*) radio.DATA);
   } 
   wait(800);     
}
Title: Re: Trouble with two-way communication
Post by: Felix on January 25, 2016, 10:21:30 PM
BIG RED FLAGS: using delay()
Remove those completely, you want to hit receiveDone as often as possible. Look at how I implement delays, I never use delay(), I always just look at the "time" using millis and remember when I last did something with an unsigned long (uint32_t) variable. Look in the Node and Gateway examples for that.
Title: Re: Trouble with two-way communication
Post by: jrdoner on January 25, 2016, 11:48:56 PM
Felix,

OK, I removed the wait() functions (differs from delay() in that I use timer 2 to operate wait()).
I did use millis() to stop it from running so fast that many transmissions were skipped.  Still the same results as before. 
Here's the two versions now.  Node 1 gets data to node 2, but not the other way.


void loop()                      //node 1 -- transmit first, wait for reply
{
 
   data = data + 2;
 
   sprintf(buff, "Data =  %d", data);
   radio.send(2, buff, strlen(buff));             //receiver node ID, message, length of message
   
   if (radio.receiveDone())
   {
     Serial.print("Tx node: "); Serial.println(radio.SENDERID);
     Serial.print("message "); Serial.println((char*) radio.DATA);
   } 
   while (millis() < clockTick) {};
   clockTick = millis() + 250;
       
}



void loop()                //node 2 -- receive first, then transmit           
{

  if (radio.receiveDone())
  {
      Serial.print("Tx node: "); Serial.println(radio.SENDERID);
      Serial.print("message "); Serial.println((char*)radio.DATA);
      Serial.println(); 
                   
      data = data + 2;
      sprintf(buff, "Data %d", data);
      radio.send(1, buff, strlen(buff));
  } 
}




Title: Re: Trouble with two-way communication
Post by: Felix on January 26, 2016, 08:31:32 AM
This is the same thing as delay():

while (millis() < clockTick) {};

You have to keep looping, and not stop and do nothing for 250ms. When you do while (bla) {}, that means your program spends 250 ms in {} (ie doing nothing). Does that make sense?

So what you're doing is:

receiveDone()
sleep 250ms
receiveDone()
sleep 250ms
receiveDone()
sleep 250ms
... forever

Again, look at my sketches, i never use any delays or empty while loops.
Title: Re: Trouble with two-way communication
Post by: jrdoner on January 26, 2016, 08:26:27 PM
Felix, I finally got both units talking to each other, but I would like, if possible, to understand some of the details, re buffers and timing.

1. If an incoming buffer is not read before the next arriving transmission, what happens?  Is there an overflow flag somewhere?

2. The transceiver uses pin 2 as an interrupt.  Is it possible for me to somehow piggyback into that interrupt to get to incoming data as quickly as possible?

3. As you say, you never use and delays.  But if I know I have to wait for a single receipt that should be arriving, why can't I use a delay?
Title: Re: Trouble with two-way communication
Post by: Felix on January 26, 2016, 08:48:52 PM
You get the data by calling receiveDone() and then the examples show how to read it.
You could write your own interrupt by why would you do that since the lib does it for you...
There is no overflow flag. You just have to be on the lookout for your packets. Since they can generally arrive any time you should be listening all the time and not sleeping the micro, or else your other node will send the packet while this one is sleeping and will time out waiting for an ACK, then you wonder why it doesn't work. That is why delay() is a no no.
Title: Re: Trouble with two-way communication
Post by: jrdoner on January 30, 2016, 04:45:37 PM
I'm creating a network with 6 nodes, with a master node and 5 remotes.  The master talks to the remotes, and vice versa.  The remotes have different sensor arrays to read and report on, and the master may also send them data at any time.  Maybe I could write main loops that listen all the time for the received traffic, but it seems like a much more complicated way of doing it then looking for data on a regular schedule.

I have written a program which ping pongs data between two Motes,  It uses timer2 to look for traffic at 0.1 sec. intervals.  I'm not using ACKS.  Each radio gets a packet, and sends a reply 0.5 sec. later.  So I'm listening at five times the rate I'm sending.

This code will run just fine, for an arbitrary length of time.  Maybe for 5 cycles, maybe for 200, but eventually it always hangs.  Code is below.  The only difference between the programs is that one of them sends a first packet, during Setup().


#include <RFM69.h>
#include <SPI.h>

#define NETWORKID    100                 //all nodes in network must use same network ID
#define NODEID       1                   //this node is 1
#define FREQUENCY    RF69_433MHZ
#define ENCRYPTKEY  "adjjsk#6))L3ooa*"  //16 characters, and the same for all communicating nodes

RFM69 radio;

boolean msgArrived;
boolean checkReceive;
volatile unsigned long clockTick;
volatile unsigned long secTick;
int LEDPin = 9;


typedef struct
{
  int nodeID;
  int cmdType;
  int param1;
  int param2;
  int param3;
  int param4;
}payload;

payload inData;

void setup( )
{
  radio.initialize(FREQUENCY,NODEID,NETWORKID);
  radio.encrypt(ENCRYPTKEY);

  //Serial.begin(115200);
  pinMode(LEDPin, OUTPUT);
  digitalWrite(LEDPin, LOW);
 
  //setup 2 kHz. timer for various timing operations
   
  cli();                                 //disable all interrupts
                                          //setting up timer2 for 0.5 ms. cycle
   TCCR2A = 0;                            //clear both timer2 configuration registers: gonna use as a 0.5 msec. timer
   TCCR2B = 0; 
   TCNT2  = 0;                            //set the counter register to 0, and set 
   OCR2A = 255;                           //128x64/16000000 = 0.512 ms. 
   TCCR2A = TCCR2A | B00000010;           //turn on CTC mode
   TCCR2B = B00001011;                    //CS1:2:0 to 101 to operate at clock speed/64
                                          //this also establishes that WGM13:0 = 0100, i.e., CTC mode
   TIMSK2 = TIMSK2 | B00000010;           //enable the CTC interrupt                                                 
   sei(); 

  msgArrived = false;
  checkReceive = false;
  clockTick = 0;
  secTick = 0;

  inData.nodeID = 1;
  inData.param1 = 0;
  radio.send(2, (const void*)(&inData), sizeof(inData));           
  Serial.println("Initial data sent");
 
}  //setup


ISR(TIMER2_COMPA_vect)           
{
  clockTick++;                    //counts half milliseconds
  if ((clockTick % 2000) == 0) secTick++;
  if ((clockTick % 200) == 0) checkReceive = true;
}//ISR(Timer0..

void wait(int millisec)
{
  unsigned long later;
 
  later = 2*millisec + clockTick;
  while (clockTick < later) {};



void loop()                      //node 1 -- transmit first, wait for reply
{
  if (checkReceive) checkTraffic();
 
  if (msgArrived)
  { 
     inData.param1 = inData.param1 + 1;
     wait(500);
     radio.send(2, (const void*)(&inData), sizeof(inData)); 
     msgArrived = false;
     radio.receiveDone();
  }   
}//loop


void checkTraffic()

   cli();
   if (radio.receiveDone())
   {
    // Serial.println();
   // Serial.print("Received from node "); Serial.println(radio.SENDERID);
     inData = *(payload*)radio.DATA;   
    // Serial.print("  received data: "); Serial.println(inData.param1);
     
     digitalWrite(LEDPin, HIGH);
     wait(100);
     digitalWrite(LEDPin, LOW);
     msgArrived = true;
   
   }
   checkReceive = false;
   sei(); 
}



I really don't understand why this has to be so difficult;  I've used simple OOK 3 pin radios before, and  never had such difficulties.

1. Do I need some pullups somewhere?

2. Do I need to clear a buffer somewhere?
Title: Re: Trouble with two-way communication
Post by: TomWS on January 30, 2016, 07:10:38 PM
@jrdoner, I would suggest drawing a state diagram to show the different states each node can be in and the events that are necessary to trigger each state change (including the conditions that KEEP a state from changing - like missing a packet to take a random example).

I'm not sure why you call receiveDone() at the bottom of loop() - if a message comes in and this call fields it, you've lost it because you don't check the result.

I'd also look at why you time when you call checkTraffic().  ISTM that you would use the timer to control when your node sends, but let the other node control the timing on when you receive (ie, when it sends).

Tom
Title: Re: Trouble with two-way communication
Post by: jrdoner on January 30, 2016, 08:59:17 PM
TomWS,

You're right about the call to receiveDone() at the end of the loop.  It was an experiment on my part to see if it would somehow clear a buffer ,or something.  But the code behaves exactly the same with that instruction removed: it ping pongs successfully for some length of time and then hangs.

As to one node controlling another, why should I need to do that?  Consider the air traffic control system; the pilots don't tell the controllers when to talk, nor vice versa.  If these radios require that, they're of very limited utility. 

But the point is, why should this run for some period of time, then stop?  If its due to hardware, it usually is something like a missing pullup/down resistor.  If its software, then maybe its some sort of memory/variable overflow.  I have fiddled with this for a week of evenings, and I have used other radios that worked fine in similar contexts.   This seems like a perfectly reasonable way to check for traffic. 
Title: Re: Trouble with two-way communication
Post by: TomWS on January 30, 2016, 09:40:06 PM
Quote from: jrdoner on January 30, 2016, 08:59:17 PM
As to one node controlling another, why should I need to do that?  Consider the air traffic control system; the pilots don't tell the controllers when to talk, nor vice versa.  If these radios require that, they're of very limited utility. 
I do believe that Air Traffic controllers/Pilots operate at different frequencies in a totally full duplex link.  A model very different than one you've created.
Quote
But the point is, why should this run for some period of time, then stop?  If its due to hardware, it usually is something like a missing pullup/down resistor.  If its software, then maybe its some sort of memory/variable overflow.  I have fiddled with this for a week of evenings, and I have used other radios that worked fine in similar contexts.   This seems like a perfectly reasonable way to check for traffic.
I will 'suggest' that EVERY ping pong protocol will fail at 'some' time if there is no contingency for lost packets or realization that 500us at one node does NOT equal 500uS at the other.

Tom
Title: Re: Trouble with two-way communication
Post by: luisr320 on January 31, 2016, 08:16:46 PM
Pilot/controller comms are on a single comm frequency. Normally a controller calls a pilot by his flight number and all other pilots wait until the controller finishes his message. Then they wait for the pilot to acknowledge the message by repeating it back to the controller. Then the controller fires another instruction to another pilot. Generally there is a small gap between each communication so that some other pilot may send some urgent message. Sometimes the controller speaks at the same time as a pilot, which will be noticed by all the other pilots on that frequency. When the controllers stops speaking, someone just say "Blocked" and the controller repeats his message. A duplex system would be nice to have, but not really required.
Title: Re: Trouble with two-way communication
Post by: jrdoner on February 01, 2016, 02:13:03 PM
In response to Felix's recommendation, I went back and rewrote my ping-pong code to poll the radio every time I pass through the loop.  The code is as shown below.  The two programs involved differ only in that the one shown starts the messaging in the setup() procedure, and of course, the node ID's.    I still use a timer to send messages, but hey, surely they put timers in microcontrollers because virtually every real-world application uses them.   


/* Simple demo program providing radio transmission from a Moteino with minimum configutation*/

#include <RFM69.h>
#include <SPI.h>

#define NETWORKID    100                 //all nodes in network must use same network ID
#define NODEID       1                   //this node is 1
#define FREQUENCY    RF69_433MHZ
//#define ENCRYPTKEY  "adjjsk#6))L3ooa*"   
//16 characters, and the same for all communicating nodes

RFM69 radio;

boolean newData;
boolean sendMsg;
volatile unsigned long clockTick;
volatile unsigned long secTick;
int LEDPin = 9;


typedef struct
{
  int nodeID;
  int cmdType;
  int param1;
  int param2;
  int param3;
  int param4;
}payload;

payload inData;

void setup( )
{
  radio.initialize(FREQUENCY,NODEID,NETWORKID);
  //radio.encrypt(ENCRYPTKEY);

  Serial.begin(115200);
  pinMode(LEDPin, OUTPUT);
  digitalWrite(LEDPin, LOW);
 
  //setup 2 kHz. timer for various timing operations
   
  cli();                                 //disable all interrupts
                                          //setting up timer2 for 0.5 ms. cycle
   TCCR2A = 0;                            //clear both timer2 configuration registers: gonna use as a 0.5 msec. timer
   TCCR2B = 0; 
   TCNT2  = 0;                            //set the counter register to 0, and set 
   OCR2A = 255;                           //128x64/16000000 = 0.512 ms. 
   TCCR2A = TCCR2A | B00000010;           //turn on CTC mode
   TCCR2B = B00001011;                    //CS1:2:0 to 101 to operate at clock speed/64
                                          //this also establishes that WGM13:0 = 0100, i.e., CTC mode
   TIMSK2 = TIMSK2 | B00000010;           //enable the CTC interrupt                                                 
   sei(); 

   newData = false;
   sendMsg = false;
   clockTick = 0;
   secTick = 0;

   inData.nodeID = 1;
   inData.param1 = 0;
   radio.sendWithRetry(2, (const void*)(&inData), sizeof(inData));           
   Serial.println("Initial data sent");
}  //setup


ISR(TIMER2_COMPA_vect)           
{
  clockTick++;                                                //counts half milliseconds
  if ((clockTick % 2000) == 0) secTick++;
  if ((clockTick % 1000) == 0) sendMsg = true;
}//ISR(Timer0..

void wait(int millisec)
{
  unsigned long later;
 
  later = 2*millisec + clockTick;
  while (clockTick < later) {};



void loop()                      //node 1 -- transmit first, wait for reply
{
   if (radio.receiveDone() && !newData)
   {
     inData = *(payload*)radio.DATA;   
     Serial.print("RSSI  "); Serial.print(radio.RSSI);
     Serial.print("  data: "); Serial.println(inData.param1);
     inData.param1 = inData.param1 + 1;
     newData = true;
   } 
 
 
   if (sendMsg && newData)    //this is triggered every 0.5 sec. if there is data to send
   {
     radio.sendWithRetry(2, (const void*)(&inData), sizeof(inData));
     sendMsg = false;
     newData = false;
   } 
}//loop


The results with this recoding is the same.  This ping-pong process might run for 10 cycles, or it might run for 200 cycles, but after a while, it hangs.

Things I've tried;

checking the RF environment;
changing out the SPI library for a different one;
not talking to either serial port while running.

No luck with anything.  And one other strangeness to report.  I didn't originally have the newData variable in there to prevent reading the radio even when no message was expected.  However, without the newData restriction anded with radioReceiveDone, the loop would drop into the radioReceiveDone code two or three times in succession, even though the data had already been pulled out on the first pass.

So at the moment, I am at my wit's end as to how to get these to work in any asynchronous system.   Suggestions please.

Title: Re: Trouble with two-way communication
Post by: jrdoner on February 01, 2016, 05:00:38 PM
In desperation, I have taken Felix's advice and recoded my ping-pong program to read the radio every time I loop.  The code is as below, and the other program is identical, except for node ID and the fact that the program shown here sends the first message in setup().


#include <RFM69.h>
#include <SPI.h>

#define NETWORKID    100                 //all nodes in network must use same network ID
#define NODEID       1                   //this node is 1
#define FREQUENCY    RF69_433MHZ
#define ENCRYPTKEY  "adjjsk#6))L3ooa*"   
//16 characters, and the same for all communicating nodes

RFM69 radio;

boolean newData;
boolean sendMsg;
volatile unsigned long clockTick;
volatile unsigned long secTick;
int LEDPin = 9;


typedef struct
{
  int nodeID;
  int cmdType;
  int param1;
  int param2;
  int param3;
  int param4;
}payload;

payload inData;

void setup( )
{
  radio.initialize(FREQUENCY,NODEID,NETWORKID);
  //radio.encrypt(ENCRYPTKEY);

  Serial.begin(115200);
  pinMode(LEDPin, OUTPUT);
  digitalWrite(LEDPin, LOW);
 
  //setup 2 kHz. timer for various timing operations
   
  cli();                                 //disable all interrupts
                                          //setting up timer2 for 0.5 ms. cycle
   TCCR2A = 0;                            //clear both timer2 configuration registers: gonna use as a 0.5 msec. timer
   TCCR2B = 0; 
   TCNT2  = 0;                            //set the counter register to 0, and set 
   OCR2A = 255;                           //128x64/16000000 = 0.512 ms. 
   TCCR2A = TCCR2A | B00000010;           //turn on CTC mode
   TCCR2B = B00001011;                    //CS1:2:0 to 101 to operate at clock speed/64
                                          //this also establishes that WGM13:0 = 0100, i.e., CTC mode
   TIMSK2 = TIMSK2 | B00000010;           //enable the CTC interrupt                                                 
   sei(); 

   newData = false;
   sendMsg = false;
   clockTick = 0;
   secTick = 0;

   inData.nodeID = 1;
   inData.param1 = 0;
   radio.sendWithRetry(2, (const void*)(&inData), sizeof(inData));           
   Serial.println("Initial data sent");
}  //setup


ISR(TIMER2_COMPA_vect)           
{
  clockTick++;                    //counts half milliseconds
  if ((clockTick % 2000) == 0) secTick++;
  if ((clockTick % 1000) == 0) sendMsg = true;
}//ISR(Timer0..

void wait(int millisec)
{
  unsigned long later;
 
  later = 2*millisec + clockTick;
  while (clockTick < later) {};



void loop()                      //node 1 -- transmit first, wait for reply
{
   if (radio.receiveDone() && !newData)
   {
     inData = *(payload*)radio.DATA;   
     Serial.print("RSSI  "); Serial.print(radio.RSSI);
     Serial.print("  data: "); Serial.println(inData.param1);
     inData.param1 = inData.param1 + 1;
     newData = true;
   } 
 
 
   if (sendMsg && newData)    //this is triggered every 0.5 sec. if there is data to send
   {
     radio.sendWithRetry(2, (const void*)(&inData), sizeof(inData));
     sendMsg = false;
     newData = false;
   } 
}//loop


The recoding has not helped.  The ping-pong game may last for five cycles, or it may last for 200, but it always eventually hangs.

Things I have tried, besides recoding.

1. checked the RF environment;
2. tried a different SPI library;
3. ran the program without talking to the serial ports.

Besides the fact that this process always hangs, I noticed one other strange thing.  If I remove the newData variable from the control statement reading the radio, sometimes the radio will be read several times in succession, even though the data was read the first time, and another message has certainly not arrived.

At this point, I have no idea why this doesn't work, and I certainly welcome any new suggestions.  Otherwise, I've got more than $100 worth of Moteinos, that I'll have to demote to Nanos.
Title: Re: Trouble with two-way communication
Post by: luisr320 on February 02, 2016, 10:05:23 AM
I've spent the whole morning around this and I think I figured out what is wrong.

You probably have your two Moteinos right next to each other while making these tests.
The problem, I think, is that they just get overloaded with each other transmitting power, causing some kind of distortion and nothing gets trough after a while.

I have loaded two ping-pong sketches on two different Moteinos, making sure that, as I described on a couple of posts back regarding the way pilots and controllers talk, one of the Moteinos is the "Master" (the Controller) and the other is a "Slave" (the Pilot). This way, if the communication is lost, one of them, the "Master" takes the initiative to resend the data and the other goes back to be a listener. And once the data is received, an acknowledge (ACK) is sent back to the sender to make sure all data went trough.

The idea that works is as follows:

The Master has a sendMsg flag defined initially as true and the Slave as false.

Both radios have no restriction to enter the "if radio.Receivedone()" loop. So if something is received, they just check if the contents was destined to that node and act upon it.

So, when the Master first enters the loop and has his sendMsg as true, it sends the first data, a "0", to the Slave and waits for an ACK to be received back.

And when the Slave first enters the loop and has its SendMsg as false, it keeps running over the "if radio.Receivedone() loop" until something gets trough to it.
If something does came trough and it is was sent to that node, it shown the data content on the serial monitor, sends an ACK back to the Master and sets its sendMsg flag to true.
As the sendMsg flag now is true, it enters the radio.Sendwithretry() loop, sends a "1" and waits for an ACK to be received from the Master.

After the Master receives the ACK to the "0" that it sent to the Slave, it sets its sendMsg to false and waits for the Slave to send a new data, a "1".
When the "1" comes trough, it sends a ACK back to the Slave and sets if SendMsg flag to true and all starts over.

Here is a printscreen of both radios after sending more then a 150.000 successful ping pongs between them:
(http://www.linhadafrente.net/Moteino/pingpong.jpg)

And here are the sketches:

MASTER:
#include <RFM69.h>
#include <SPI.h>

#define NETWORKID    300                 //all nodes in network must use same network ID
#define NODEID       1                   //this node is node 1, the "MASTER"
#define DESTINATION_NODE 2               //this is the "SLAVE" node
#define ACK_TIME 50                      //Time in ms to wait for an ACK to be received before it tries again
#define FREQUENCY    RF69_433MHZ
#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!

RFM69 radio;

boolean sendMsg = true; //I'm the "MASTER", so I will start first

//Data Struct
typedef struct
{
  unsigned long param1;
}payload;

payload inData;

void setup( )
{
  radio.initialize(FREQUENCY,NODEID,NETWORKID);
  #ifdef IS_RFM69HW
    radio.setHighPower();
  #endif

  Serial.begin(115200);
  Serial.println ("I'm the Master. I'll start first. Sending first packet now.");

  inData.param1 = 0;

}

void loop()
{
   if (radio.receiveDone()) //as often as possible
   {
     if (radio.TARGETID == 1)//Check if the packet destination is this radio (NODE 1)
      {
       inData = *(payload*)radio.DATA; 
       Serial.print("RSSI  "); Serial.print(radio.RSSI);
       Serial.print("  data: "); Serial.print(inData.param1); Serial.println("  A Moteino is not a Nano!");
       inData.param1 = inData.param1 + 1;
       radio.sendACK(); //Tell the "SLAVE" that all was received well
       sendMsg = true;
      }
   }

   if (sendMsg) //If the sendMsg flag is set, send a new message to the "SLAVE"
   {
     if (radio.sendWithRetry(DESTINATION_NODE, (const void*)(&inData), sizeof(inData), 3, ACK_TIME))//Send the data to node 2 for processing, try that 3 times and wait 50ms each time for an ACK
     {
        sendMsg = false;  // ACK received
     }
     else
     {
        sendMsg = true; // ACK was not received yet and the waiting timed out. Go back to be a "sender"
     }
   }
}


And SLAVE:
#include <RFM69.h>
#include <SPI.h>

#define NETWORKID    300                 //all nodes in network must use same network ID
#define NODEID       2                   //this is the "SLAVE" node
#define DESTINATION_NODE 1               //this node is node 1, the "MASTER"
#define ACK_TIME 50                      //Time in ms to wait for an ACK to be received before it tries again
#define FREQUENCY    RF69_433MHZ
#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!

RFM69 radio;

boolean sendMsg = false; //I'm the "SLAVE" I will wait for the first packet

//Data Struct
typedef struct
{
  unsigned long param1;
}payload;

payload inData;

void setup( )
{
  radio.initialize(FREQUENCY,NODEID,NETWORKID);
  //radio.encrypt(ENCRYPTKEY);
  #ifdef IS_RFM69HW
    radio.setHighPower();
  #endif

  Serial.begin(115200);
  Serial.println ("I'm the Slave. I'm waiting for the first packet...");

  inData.param1 = 0;

}

void loop()
{
   if (radio.receiveDone()) //as often as possible
   {
   if (radio.TARGETID == 2) //Check if the packet destination is this radio (NODE 2)
    {
      inData = *(payload*)radio.DATA;   
      Serial.print("RSSI  "); Serial.print(radio.RSSI);
      Serial.print("  data: "); Serial.print(inData.param1); Serial.println("  Yes, I know...");
      inData.param1 = inData.param1 + 1;
      radio.sendACK(); //Tell the "MASTER" that all was received well
      sendMsg = true;
    }
   }

   if (sendMsg) //If the sendMsg flag is set, send a new message to the "MASTER"
   {
     if (radio.sendWithRetry(DESTINATION_NODE, (const void*)(&inData), sizeof(inData), 3, ACK_TIME))//Send the data to node 1 for processing, try that 3 times and wait 50ms each time for an ACK
     {
       sendMsg = false; // ACK received
     }
     else
     {
       sendMsg = false; //  ACK was not received yet and the waiting timed out. Go back to be a "listener"
     }
   }
}



Now say it: "A Moteino is not a Nano". Nothing is like a Moteino.  :)


Title: Re: Trouble with two-way communication
Post by: jrdoner on February 02, 2016, 12:28:38 PM
LuisR320,

Thanks for the very excellent examples.  My problem was not overload, my RSSI readings are at -20.   I had tried using sendWithRetry in a previous version, with no improvement.  So the distinction in your code is indeed that you will keep trying to send from the master, even if the first sendWithRetry() wasn't enough. 

In my case, I have a master node, and 5 remotes.  The remotes are watching the world around them, and may communicate at any time.  Likewise for the master.  So I am going to try to adapt this so that everybody gets through to everybody, and if somebody dies, it is duly recorded by the master.

At any rate, your work is tutorially first rate.  You should write a guide to Moteinos. 

Title: Re: Trouble with two-way communication
Post by: jrdoner on February 02, 2016, 12:55:47 PM
One other thought:  if more than one node were trying to get to the master and both continually transmitted, they would probably just create a continuing wall of intererence.  So if the first sendWithRetry() fails, the software should insert a short random delay before the next attempt.
Title: Re: Trouble with two-way communication
Post by: luisr320 on February 02, 2016, 05:06:49 PM
As Felix said, delay() is a bad practice. You shouldn't block the access to the radio.ReceiveDone().
I have a lot of Moteinos firing all kind of traffic to my Gateway, just another Moteino that I considered as such, and they all mange to pass their information correctly without dropping any data.
The trick is to not have the Remote nodes firing data at every milisecond but only when necessary, like when some event happened, or every 10 seconds or whatever. Just not all the time.
Don't make them wait. Just make them check on each loop if something is in the mailbox (radio) for them. If there is, send an ACK to that node and do something with the new data.
I have my nodes sending a ping every 10 seconds to the Gateway so that the Gateway may access if any node is down and set some flag to advise me if no Pings are received from any node for more then 10 seconds.
Title: Re: Trouble with two-way communication
Post by: Felix on February 04, 2016, 12:55:49 PM
It's all about how receiveDone() works. You have to understand it, and the effect it has on the state of the radio - which can be in several modes of operation, only 1 at 1 time - RX, STANDBY, TX etc.

After you've put the radio in RX, and it receives a packet, it stops receiving, generates an interrupt to the RFM69 library handler, which reads the packet into a memory buffer. Then it's ready for you to pick up later. It is assumed that after a receiveDone = true you will immediately read the packet from the library buffers before calling receiveDone() again, - which will effectively clear everything and put the radio in RX again. That's just how it was done. You can make your own fork and change that state machine to fit your needs.