LowPowerLab Forum

Hardware support => Moteino => Topic started by: luisr320 on May 15, 2014, 07:07:11 PM

Title: Sender / Receiver pin mirror
Post by: luisr320 on May 15, 2014, 07:07:11 PM
Hi.
Complete, absolute, hopeless noob/beginner here.

I finally managed to get both moteinos to work, one as a sender and one as a receiver.
Do the pins on the sender get mirrored on the receiver?
Is this possible?
How would I go about to achieve this?

How do I program the receiver to look for the sender pins status and to react accordingly? I don't want to send data out of the receiver serial port. I just want to make the receiver have an output pin react with some logic to an input pin, as a standalone, and not having it attached to a computer. Like an intelligent remote control.

Thank you for any help.
Title: Re: Sender / Receiver pin mirror
Post by: Felix on May 15, 2014, 10:15:18 PM
Both units are hardware identical. What you are sending are mere messages. You can interpret an incoming message and do something about it - like turn a pin HIGH/LOW or whatever else. So you can make your own little protocol where you ask something like "D5:1" which would mean write a 1 or HIGH to D5.
On the sender you have to decide what to ask at the receiver (or what message to send). You can get the status of pin X and format your message accordingly then send it, and at the receiver parse for the pin number and the status then do the pin work. This is very very basic... if you look at my example sketches you will find things like that, maybe more advanced but you should at least get some idea how to do things along those lines.
At least that's what I think you're after from your description.
Title: Re: Sender / Receiver pin mirror
Post by: luisr320 on May 16, 2014, 10:08:58 AM
Ahhh!!! I see.
So it works like an Xbee in API mode. Only the Xbee is very strict on what the packet content and format is.
Here I can just setup a packet with whatever content and format I want and push it out of the serial port of the SENDER and it will show up on the serial port of the RECEIVER, as if it was sent by the USB cable.
Is that it?
If so, how does the RECEIVER forward anything into the computer where it is attached to trough the USB cable after it receives it from the SENDER via radio?

So on the sender side I would run something like this:

if pin1=high
  serial("Pin 1 is High")
endif

On the RECEIVER side I would have something like this

listen to serial
if sender transmitted something
  if packet content is (Pin 1 is High")
    set Pin1=high
  endif
endif

Is it coming warmer or still icy cold?

(Sorry for such basic lack of knowledge, but I really want to learn this stuff :))
Title: Re: Sender / Receiver pin mirror
Post by: Felix on May 16, 2014, 11:46:51 AM
Yeah you're close. Please just examine the example code. The light is in there.
If you want to transmit to the host computer you just write Serial.print("I got a message: ....!") or whatever you want.
Remember you are sending bytes over the wireless link. How you interpret those bytes is up to you. I show many examples where they are interpreted as text or as structs with numbers, etc. I guess a little programming knowledge will help.
Title: Re: Sender / Receiver pin mirror
Post by: luisr320 on May 17, 2014, 04:38:22 AM
Oh boy, I feel like I'm on my first date: very excited on not really sure of what to do :)

So I managed to get an input pin on the transmitter get some response on the receiver.
Some questions:

1 - I tried to clean the sketches to the bare minimum and if I try to get rid of the #include <SPI.h> but got some error from the compiler. So I assume that the radio is using the SPI interface to connect to the Moteino. Is this correct?

2 - When I look at the example codes I find a lot of radio functions like radio.sendWithRetry(), radio.receiveDone(), radio.SENDERID, radio.RSSI, radio.sendWithRetry(), just to mention a few. Some of them are obvious but others leave me clueless on how and when to use them. wher can I find a description on all these radio libraries functions?

Thank you
Title: Re: Sender / Receiver pin mirror
Post by: Felix on May 17, 2014, 07:46:56 PM
please take a look at the rfm69.h header file the functions are defined in there and there should be more insight.
Title: Re: Sender / Receiver pin mirror
Post by: luisr320 on May 18, 2014, 03:27:56 AM
Ok, found it. Thank you

    bool sendWithRetry(byte toAddress, const void* buffer, byte bufferSize, byte retries=2, byte retryWaitTime=30);
    bool receiveDone();
    bool ACKReceived(byte fromNodeID);
    void sendACK(const void* buffer = "", uint8_t bufferSize=0);
    void setFrequency(uint32_t FRF);
    void encrypt(const char* key);
    void setCS(byte newSPISlaveSelect);
    int readRSSI(bool forceTrigger=false);
    void promiscuous(bool onOff=true);
    void setHighPower(bool onOFF=true); //have to call it after initialize for RFM69HW
    void setPowerLevel(byte level); //reduce/increase transmit power level
    void sleep();
    byte readTemperature(byte calFactor=0); //get CMOS temperature (8bit)
    void rcCalibration(); //calibrate the internal RC oscillator for use in wide temperature variations - see datasheet section [4.3.5. RC Timer Accuracy]

Title: Re: Sender / Receiver pin mirror
Post by: luisr320 on May 19, 2014, 07:00:14 AM
Hello Felix.

I'm trying to make a simple pinging sketch, where one moteino pings the other displaying "Pinging node X" and when they receive a ping they display "Ping received from node Y".

This is the code I'm using on one of the moteinos:

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

#define NODEID 2 //unique for each node on same network
#define GATEWAYID 1
#define NETWORKID 100 //the same on all nodes that talk to each other
//Match frequency to the hardware version of the radio on your Moteino (uncomment one):
#define FREQUENCY RF69_433MHZ
//#define FREQUENCY RF69_868MHZ
//#define FREQUENCY RF69_915MHZ
#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes!
#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!
#define ACK_TIME 30 // max # of ms to wait for an ack
#define LED 9 // Moteinos have LEDs on D9
#define SERIAL_BAUD 115200

RFM69 radio;

void setup() {
  Serial.begin(SERIAL_BAUD);
  delay(10);
  radio.initialize(FREQUENCY,NODEID,NETWORKID);
  #ifdef IS_RFM69HW
    radio.setHighPower(); //uncomment only for RFM69HW!
  #endif
  radio.encrypt(ENCRYPTKEY);
  char buff[50];
  sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
  Serial.println(buff);
}

void loop() {

  if (radio.sendWithRetry(1, "PING", 4, 2, 30)){
    Serial.print("Ping sent to node 1");
    delay(500);
  }
 

  if (radio.receiveDone()) {
    byte theNodeID = radio.SENDERID;
    Serial.print("; Ping received from node ");
    Serial.println(theNodeID);
    Blink(LED,3);
  }
}

void Blink(byte PIN, int DELAY_MS)
{
  pinMode(PIN, OUTPUT);
  digitalWrite(PIN,HIGH);
  delay(DELAY_MS);
  digitalWrite(PIN,LOW);
}


and this is used on the other:

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

#define NODEID 1 //unique for each node on same network
#define NETWORKID 100 //the same on all nodes that talk to each other
//Match frequency to the hardware version of the radio on your Moteino (uncomment one):
#define FREQUENCY RF69_433MHZ
//#define FREQUENCY RF69_868MHZ
//#define FREQUENCY RF69_915MHZ
#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes!
#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!
#define ACK_TIME 30 // max # of ms to wait for an ack
#define LED 9 // Moteinos have LEDs on D9
#define SERIAL_BAUD 115200

RFM69 radio;

void setup() {
  Serial.begin(SERIAL_BAUD);
  delay(10);
  radio.initialize(FREQUENCY,NODEID,NETWORKID);
  #ifdef IS_RFM69HW
    radio.setHighPower(); //uncomment only for RFM69HW!
  #endif
  radio.encrypt(ENCRYPTKEY);
  char buff[50];
  sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
  Serial.println(buff);
}

void loop() {

  if (radio.sendWithRetry(2, "PING", 4, 2, 30)) {// 0 = only 1 attempt, no retries
    Serial.print("Ping sent to node 2");
    delay(500);
  }
 

if (radio.receiveDone()) {
    byte theNodeID = radio.SENDERID;
    Serial.print("; Ping received from node ");
    Serial.println(theNodeID);
    Blink(LED,3);
  }
}

void Blink(byte PIN, int DELAY_MS)
{
  pinMode(PIN, OUTPUT);
  digitalWrite(PIN,HIGH);
  delay(DELAY_MS);
  digitalWrite(PIN,LOW);
}


As far as I understand the line  "if (radio.sendWithRetry(1, "PING", 4, 2, 30))" it tests if the packet was received by the intended receiver and if it was, it executes the "Serial.print("Ping sent to node 1"); delay(500);". Correct?

The receiver does display "Ping requested by node Y" but somehow the sender never executes whatever is below the "if" and so it doesn't display "Ping sent to node X.

What am I doing wrong?

Thank you

Title: Re: Sender / Receiver pin mirror
Post by: Felix on May 19, 2014, 08:23:34 AM
First you have to configure the settings to match your radio hardware. Especially the isHW setting and the frequency. Then keep same network ID, but different node IDs.
Then I think what you're trying to do is illustrated in the Node and Gateway examples here: https://github.com/LowPowerLab/RFM69/tree/master/Examples
A radio cannot know if anything was received unless the other radio tells it so. So the sendwithretry sends a message and requests an ACK (acknowledgement). If it doesn't receive it it will resend the message up to 3 times (default) and wait for 30ms (default) each time.
Title: Re: Sender / Receiver pin mirror
Post by: luisr320 on May 20, 2014, 12:05:01 PM
Hello Felix.
Thank you for the feedback.

After your comment I can now understand that the in the following sketch, Serial.print("Ping sent to node 1"); and delay(500); will only be executed if the ACK request to the receiver is received and returned, making (radio.sendWithRetry() true.
if (radio.sendWithRetry(1, "PING", 4, 2, 30)){
    Serial.print("Ping sent to node 1");
    delay(500);
  }


So now I can send data from the NODE to the GATEWAY when a digital input on the MOTE is high, but I'm having trouble using the data in a usefull way on the GATEWAY besides pushing it trough the Serial.print() for display.

Can you tell me what am I doing wrong in this code?
  if (radio.receiveDone()) {
    if (radio.TARGETID == 1) {
      Serial.print('[');Serial.print(radio.SENDERID, DEC);Serial.print("] ");
      if (promiscuousMode) {
        Serial.print("to [");Serial.print(radio.TARGETID, DEC);Serial.print("] ");
      }
      for (byte i = 0; i < radio.DATALEN+1; i++){
        Serial.print ((packet[i]) = (char)radio.DATA[i]);
      }

      Serial.print(" [RX_RSSI:");Serial.print(radio.RSSI);Serial.print("]");
      byte theNodeID = radio.SENDERID;
      Serial.print("; Data received from node ");
      Serial.print(theNodeID);
      if (radio.ACK_REQUESTED) {
        radio.sendACK();
        Serial.println(" - ACK sent");
      }

      Serial.print(packet);

      if (packet == "NODE2-D5=1") {
       
        Blink(LED,1000);
       
      }
    }
  }


The Serial.print(packet) displays the "NODE2-D5=1" message correctly on the serial monitor of the GATEWAY. But when I test its contents in the if (packet == "NODE2-D5=1") it doesn't go trough and jumps over it without blinking the led.
Any suggestion for why it doesn't work or maybe a different approach for this problem?

Thank you.

Luis
Title: Re: Sender / Receiver pin mirror
Post by: Felix on May 20, 2014, 08:53:20 PM
You can't compare strings like that. Maybe you can shorten your message and do something like "5:1". You already know the node id in the packet header (call radio.SENDERID).
Then you can check individual characters. Check first character for the pin number and the third for the mode:

if (radio.DATA[0]=='5' && radio.DATA[2]=='1')
   digitalWrite(5,1);


etc..

I would recommend you read through a C++ basic tutorial so you understand the building blocks of programming, it's a bit hard to write code in the forum on the fly and hope it will work on your end. Here's a good site: http://www.cplusplus.com/
Also www.arduino.cc has many resources.
Title: Re: Sender / Receiver pin mirror
Post by: luisr320 on May 21, 2014, 07:24:18 PM
Hello Felix. Thank you for not giving up on me  ;)

Great success!!!
(http://s2.quickmeme.com/img/14/14c0f057abec6dabfc5be48cbbd0d904fef889a8781eee667984089207daf998.jpg)


I was, indeed, trying to match two completely different types of data, which is not possible. As "packet[]" is an array, I must check the contents of the required index to see if it hold whatever I want and then it's a simple task of programming the Moteino to do whatever I want with it to.

So now I have it all set up to be used as a tutorial for others like me who are a bit lost with all the new radio stuff.
In this case, I have set up a simple pushbutton, connected to digital input number 4 of the transmitting Moteino, which is NODE 2.
The other Moteino is the receiver and is NODE 1. Of course they can change roles as both are transmitters and receivers.

So this is the setup:
(http://www.linhadafrente.net/arduino/photo1.jpg)

The Moteino on the top is the receiver and the one on the bottom is the transmitter. They are both connected to my computer USB ports, each assigned a different com number.

The transmitter scketch is very simple (well, now it is, after a week looking at your examples :)). It monitors if the button is pushed. If it finds that the button is pushed it send a packet of data trough the radio with the origin node number, the destination node number, the digital pin number of the transmitter that was set HIGH by the button and waits 30 ms for an acknowledge (ACK) to be sent by the receiver that it get there. If no ACK is received, it sends it again, a total of 3 times. These numbers are programmable on the transmitter sketch, of course.

The receiver that is the destination of the data packet stores its contents in an data array and sends an acknowledge back. Then it looks in the array for specific indexes and according to what it finds there, it executes some action.

In this case when the button is pushed, the transmitter sends a data packet with "D4:1", a content chosen by me which means that the pin D4 is high and when the receiver finds "D" on index  0 and 4 on the index 2 of the receiving data array it pulses pin 9 for 100 ms, which in this case is the onbord led of the receiver Moteino.

So I guess now all possibilities are open where I can mirror a pin from the transmitter to the receiver and do whatever is required wit that pin.

Here is the transmitter sketch:
// **********************************************************************************************************
// A simple button status transmitting sketch that works with Moteinos equipped with HopeRF RFM69W/RFM69HW
// Can be adapted to use Moteinos using RFM12B
// Ver 1.0
// 2014-05-22 (C) [email protected]
// Adapted from [email protected], http://www.LowPowerLab.com mote.ino
// **********************************************************************************************************
// It uses a button to send a data packet to the receiver stating that button position, making a digital output of the receiver pulse
// **********************************************************************************************************
// Creative Commons Attrib Share-Alike License
// You are free to use/extend this code/library but please abide with the CCSA license:
// http://creativecommons.org/licenses/by-sa/3.0/
// **********************************************************************************************************

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

#define NODEID 2 //unique for each node on same network
#define GATAWAYID 1
#define NETWORKID 100 //the same on all nodes that talk to each other
//Match frequency to the hardware version of the radio on your Moteino (uncomment one):
#define FREQUENCY RF69_433MHZ
//#define FREQUENCY RF69_868MHZ
//#define FREQUENCY RF69_915MHZ
#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes!
#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!
#define ACK_TIME 30 // max # of ms to wait for an ack
#define LED 9 // Moteinos have LEDs on D9
#define SERIAL_BAUD 115200
#define D4 4
#define DESTINATION_NODE 2

RFM69 radio;
bool promiscuousMode = true; //set to 'true' to sniff all packets on the same network
int D4Status = 0;

void setup()
{

//Setup the pins
pinMode(LED, OUTPUT);
pinMode(D4, INPUT);
   
//Start the Serial
Serial.begin(SERIAL_BAUD);
delay(10);

//Initialize the radio
radio.initialize(FREQUENCY,NODEID,NETWORKID);
#ifdef IS_RFM69HW
    radio.setHighPower(); //uncomment only for RFM69HW!
#endif
radio.encrypt(ENCRYPTKEY);//Turn encryption ON
radio.promiscuous(promiscuousMode);
char buff[50];
sprintf(buff, "\nTransmiting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
Serial.println(buff);
}


void loop()
{
if (digitalRead(D4) == HIGH)//If the button connected to Digital Input pin 4 was pushed,
{
delay(10);//wait 10ms for debounce
Serial.print("Sending a D4 Status to node "); Serial.print(DESTINATION_NODE); Serial.println(" and waiting for ACK...");
if (radio.sendWithRetry(DESTINATION_NODE, "4:1", 3, 2, ACK_TIME))//Send the 3 byte packet to node 1 for processing, try that 2 times and wait 30ms each time for an ACK
{
Serial.println("ACK Received");//If the sent packet was delivered and an ACK received, send this message to the serial monitor
delay(3);// Allow the the radio to switch to receive mode
Blink(LED,100);//Blink the transmitter led to show the data was successfully sent
while (digitalRead(D4) == HIGH)//Just a loop to wait for the button to be released
{
}
}
}
}

void Blink(byte PIN, int DELAY_MS)//Local led blinking function
{
  pinMode(PIN, OUTPUT);
  digitalWrite(PIN,HIGH);
  delay(DELAY_MS);
  digitalWrite(PIN,LOW);
}


And here is the receiver sketch:
// **********************************************************************************************************
// A simple button status receiving sketch that works with Moteinos equipped with HopeRF RFM69W/RFM69HW
// Can be adapted to use Moteinos using RFM12B
// Ver 1.0
// 2014-05-22 (C) [email protected]
// Adapted from [email protected], http://www.LowPowerLab.com mote.ino
// **********************************************************************************************************
// It receives the status of a button on a transmitter which makes a digital output pulse
// **********************************************************************************************************
// Creative Commons Attrib Share-Alike License
// You are free to use/extend this code/library but please abide with the CCSA license:
// http://creativecommons.org/licenses/by-sa/3.0/
// **********************************************************************************************************


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

#define NODEID 1 //unique for each node on same network
#define NETWORKID 100 //the same on all nodes that talk to each other
//Match frequency to the hardware version of the radio on your Moteino (uncomment one):
#define FREQUENCY RF69_433MHZ
//#define FREQUENCY RF69_868MHZ
//#define FREQUENCY RF69_915MHZ
#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes!
#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!
#define ACK_TIME 30 // max # of ms to wait for an ack
#define LED 9 // Moteinos have LEDs on D9
#define SERIAL_BAUD 115200

RFM69 radio;
bool promiscuousMode = true; //set to 'true' to sniff all packets on the same network
char packet[3]; // Allocate some space for the packet array

void setup()
{
Serial.begin(SERIAL_BAUD);//Initialize the Serial port at the specified baud rate
delay(10);//Wait for the Serial port to settle down

//Initialize the radio
radio.initialize(FREQUENCY,NODEID,NETWORKID);
#ifdef IS_RFM69HW
radio.setHighPower();
#endif
radio.encrypt(ENCRYPTKEY);//Turn the radio Encryption ON
radio.promiscuous(promiscuousMode);//Turn the radio Promiscuous mode ON

//Create and display a startup message on the serial monitor
char buff[23];//buff[] is an array that will hold the "Listening at XXX Mhz..." message
sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);//buff will be filled with th FREQUENCY variable content
Serial.println(buff);//Send the message to the serial monitor
}

void loop()
{
if (radio.receiveDone())//If some packet was received by the radio, wait for all its contents to come trough
{
if (radio.TARGETID == 1)//Check if the packet destination is this radio (NODE 1)
{

//Display a message on the serial monitor showing the packet origin radio NODE number
Serial.print('[');Serial.print(radio.SENDERID, DEC);Serial.print("] ");

//If the radio Promiscuous mode is ON, show the packet destination radio NODE number on the serial monitor
if (promiscuousMode)
{
Serial.print("to [");Serial.print(radio.TARGETID, DEC);Serial.print("] ");
}

//Check the data packet length and fill the packet[] array with its contents
for (byte i = 0; i < radio.DATALEN; i++)
{
packet[i] = (char) radio.DATA[i];

//Display the data packet content on the serial monitor
Serial.print (packet[i]);
}
//Add the transmission signal level to the message to be displayed on the serial monitor
Serial.print(" [RX_RSSI:");Serial.print(radio.RSSI);Serial.print("]");

//Add a plain message stating the radio NODE number which sent the data
byte theNodeID = radio.SENDERID;
Serial.print("; Data received from node ");
Serial.print(theNodeID);

//If an ACK (acknowledge) was requested by the data packet transmitter radio, send the ACK back to it and display "ACK sent" on the serial monitor
if (radio.ACK_REQUESTED)
{
radio.sendACK();
Serial.println(" - ACK sent");
}
     
//Now the receiving Moteino can do something with the data sent in from the transmitter.
//In the packet received, the index 0 of the array holds the digital pin number and index 2 its HIGH/LOW status
//If it matches the next condition, set the pin accordingly, and blink the local led for 100ms
if (packet[0]=='4' && packet[2]=='1')
{
Blink(LED,100);
packet == "";
}
}
//If the destination radio was not this one, show the 3 requests for ACK from the transmitter radio
else
{
Serial.print('[');Serial.print(radio.SENDERID, DEC);Serial.print("] ");
if (promiscuousMode)
{
Serial.print("to [");Serial.print(radio.TARGETID, DEC);Serial.print("] ");
}

for (byte i = 0; i < radio.DATALEN; i++)
{
packet[i] = (char) radio.DATA[i];
Serial.print (packet[i]);
}

Serial.print(" [RX_RSSI:");Serial.print(radio.RSSI);Serial.print("]");
byte theNodeID = radio.SENDERID;
Serial.println("; Not for me");
}
}
}



void Blink(byte PIN, int DELAY_MS)//The led blinking function
{
  pinMode(PIN, OUTPUT);
  digitalWrite(PIN,HIGH);
  delay(DELAY_MS);
  digitalWrite(PIN,LOW);
}


The sketches are heavily commented to avoid the frustration I felt by not being very used to some advanced programming of the examples.
It is, of course, the work of someone more result oriented than efficiency coding and as such some of its contents may be better coded. But those who know how to do that surely are not waisting their time reading this :)

The serial monitors of both Moteinos show the following messages when the button is pushed and released a couple of times:
(http://www.linhadafrente.net/arduino/serial%20monitor%201.jpg)

And when I change the destination NODE number on the transmitter to one that will not reply, this is what is shown:
(http://www.linhadafrente.net/arduino/serial%20monitor%202.jpg)
Title: Re: Sender / Receiver pin mirror
Post by: Felix on May 21, 2014, 11:11:27 PM
Awesome, thanks for following up in such a detailed way, this could come in handy for others that are looking to do similar things.