Author Topic: Sending first packet with RFM95 LoRa module  (Read 21635 times)

dave_sausages

  • NewMember
  • *
  • Posts: 49
Sending first packet with RFM95 LoRa module
« on: November 06, 2015, 01:37:02 AM »
Hi all,

I'm very new to Moteino and fairly new to arduino so bear with me, but I just can't seem to work out how to send a piece of unique data with my pair of Moteino LoRa modules.

I've got both modules powered up and programmed using the example programs, and they are happily sending "hello world!" and "And hello back to you" to each other and I can see this on the serial monitor.

My problem is I can't seem to work out how to swap the 'dumb' text for data that I can use in a program. My ultimate goal is to send gps coordinates, but for the moment I'm just trying to create a variable called 'data_to_send', and then send that variable across the link. But everything I try just give compile errors.

This is the code on the module with the gps:

Code: [Select]
// rf95_client.pde
// -*- mode: C++ -*-
// Example sketch showing how to create a simple messageing client
// with the RH_RF95 class. RH_RF95 class does not provide for addressing or
// reliability, so you should only use RH_RF95 if you do not need the higher
// level messaging abilities.
// It is designed to work with the other example rf95_server
// Tested with Anarduino MiniWirelessLoRa

#include <SPI.h>
#include <RH_RF95.h>

#ifdef __AVR_ATmega1284P__
  #define LED           15 // Moteino MEGAs have LEDs on D15
  #define FLASH_SS      23 // and FLASH SS on D23
#else
  #define LED           9 // Moteinos have LEDs on D9
  #define FLASH_SS      8 // and FLASH SS on D8
#endif

// Singleton instance of the radio driver
RH_RF95 rf95;

void setup()
{
  Serial.begin(115200);
  if (!rf95.init())
    Serial.println("init failed");
  else Serial.println("init OK - 915mhz");
 
  // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on
  rf95.setFrequency(915);
}

void loop()
{
  Serial.println("Sending to rf95_server");
  // Send a message to rf95_server
  uint8_t data[] = "Hello World!";
  rf95.send(data, sizeof(data));
 
  rf95.waitPacketSent();
  // Now wait for a reply
  uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
  uint8_t len = sizeof(buf);

  if (rf95.waitAvailableTimeout(3000))
  {
    // Should be a reply message for us now   
    if (rf95.recv(buf, &len))
   {
      Serial.print("got reply: ");
      Serial.println((char*)buf);
      Serial.print("RSSI: ");
      Serial.println(rf95.lastRssi(), DEC);   
    }
    else
    {
      Serial.println("recv failed");
    }
  }
  else
  {
    Serial.println("No reply, is rf95_server running?");
  }
  Blink(LED,3);
  delay(200);
}

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

I've searched for hours and can't find anything that relates to my LoRa modules. I'm sure it's a simple fix, and if someone can reply with a well annotated reply, I'll be able to continue my learning how to code.

And I would give some examples of what I've tried, but as everything has failed, I doubt it will help haha.

Thanks

Dave

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6866
  • Country: us
    • LowPowerLab
Re: Sending first packet with RFM95 LoRa module
« Reply #1 on: November 06, 2015, 08:15:35 AM »
Dave,
The trick is in these 2 lines:

Code: [Select]
  uint8_t data[] = "Hello World!";
  rf95.send(data, sizeof(data));

Notice this is a c++ byte array that gets passed to the send() function, along with the length of that array - obtained by using sizeof(). This is short and sweet for hardcoded strings like "Hello World"
To define your own custom data, you will need to format your string into a byte array/buffer. I have a ton of such examples and how to deal with various types of data, if you just look in the RFM69 library examples.
The WeatherMote example probably suitable, look for these lines:

Code: [Select]
//variables used in formatting:
double P;
byte sendLen;
char Pstr[10];
char buffer[50]; //final byte array that gets passed to radio.send
.........

    dtostrf(P, 3,2, Pstr);  // format a double variable into a small string (byte array)
    sprintf(buffer, "BAT:%sv F:%d H:%d P:%s", BATstr, weatherShield_SI7021.getFahrenheitHundredths(), weatherShield_SI7021.getHumidityPercent(), Pstr);
    sendLen = strlen(buffer);  //get the length of buffer

radio.send(buffer, sendLen); //finally pass the string (byte array) to the radio to send

sprintf is where the magic happens. You can use this function to format your string using all kinds of variables. For simple types like integers you can use %d, for strings (byte arrays) you can use %s, the rest is just plain text.

dave_sausages

  • NewMember
  • *
  • Posts: 49
Re: Sending first packet with RFM95 LoRa module
« Reply #2 on: November 06, 2015, 10:06:14 PM »
Thanks Felix,

I've transposed your code  into my LoRa sketch and it makes sense to me now, but I'm still getting a compile error of:

Code: [Select]
Arduino: 1.6.5 (Windows 7), Board: "Moteino"

v1_client_unadress.ino: In function 'void loop()':
v1_client_unadress:55: error: invalid conversion from 'char*' to 'const uint8_t* {aka const unsigned char*}' [-fpermissive]
In file included from v1_client_unadress.ino:11:0:
C:\Users\User\Documents\Arduino\libraries\RadioHead/RH_RF95.h:507:21: error:   initializing argument 1 of 'virtual bool RH_RF95::send(const uint8_t*, uint8_t)' [-fpermissive]
     virtual bool    send(const uint8_t* data, uint8_t len);
                     ^
invalid conversion from 'char*' to 'const uint8_t* {aka const unsigned char*}' [-fpermissive]

This is my code:

Code: [Select]
// rf95_client.pde
// -*- mode: C++ -*-
// Example sketch showing how to create a simple messageing client
// with the RH_RF95 class. RH_RF95 class does not provide for addressing or
// reliability, so you should only use RH_RF95 if you do not need the higher
// level messaging abilities.
// It is designed to work with the other example rf95_server
// Tested with Anarduino MiniWirelessLoRa

#include <SPI.h>
#include <RH_RF95.h>

#ifdef __AVR_ATmega1284P__
  #define LED           15 // Moteino MEGAs have LEDs on D15
  #define FLASH_SS      23 // and FLASH SS on D23
#else
  #define LED           9 // Moteinos have LEDs on D9
  #define FLASH_SS      8 // and FLASH SS on D8
#endif

// Singleton instance of the radio driver
RH_RF95 rf95;

//variables used in formatting:
byte sendLen;
char Pstr[10];
char buffer[50]; //final byte array that gets passed to radio.send

int data_to_send = 43;

void setup()
{
  Serial.begin(115200);
  if (!rf95.init())
    Serial.println("init failed");
  else Serial.println("init OK - 915mhz");
 
  // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on
  rf95.setFrequency(915);
}

void loop()
{
  Serial.println("Sending to rf95_server");
  // Send a message to rf95_server

 
  // byte data[] = "hello";
  // rf95.send(data, sizeof(data));

  // dtostrf(P, 3,2, Pstr);  // convert a double variable into a small string (byte array) (float variable to be read, length of string being created inc decimal point, number of digits after DP to print, array to store results)
    sprintf(buffer, "%d", data_to_send);
    sendLen = strlen(buffer);  //get the length of buffer

    rf95.send(buffer, sendLen); //finally pass the string (byte array) to the radio to send


  rf95.waitPacketSent();
  // Now wait for a reply
  uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
  uint8_t len = sizeof(buf);

  if (rf95.waitAvailableTimeout(3000))
  {
    // Should be a reply message for us now   
    if (rf95.recv(buf, &len))
   {
      Serial.print("got reply: ");
      Serial.println((char*)buf);
      Serial.print("RSSI: ");
      Serial.println(rf95.lastRssi(), DEC);   
    }
    else
    {
      Serial.println("recv failed");
    }
  }
  else
  {
    Serial.println("No reply, is rf95_server running?");
  }
  Blink(LED,3);
  delay(200);
}

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

I changed radio.send to rf95.send (for the LoRa module), and created my own integer of 'data_to_send' for testing purposes. My ultimate goal is to send gps coordinates, but for the moment I'll settle with the number 43 haha.

My guess is that rf95.send doesn't like receiving either the buffer or sendlen, but as I've copied your code exactly complete with variable types, I don't understand why.
« Last Edit: November 06, 2015, 10:48:32 PM by dave_sausages »

syrinxtech

  • Sr. Member
  • ****
  • Posts: 347
  • Country: us
    • Syrinx Technologies
Re: Sending first packet with RFM95 LoRa module
« Reply #3 on: November 07, 2015, 11:57:56 AM »
I think if you change:

radio.send(buffer, sendLen); //finally pass the string (byte array) to the radio to send

to:

radio.send((uint8_t *) buffer, sendLen); //finally pass the string (byte array) to the radio to send

you will be fine.  You just needed the cast to the proper data type.


dave_sausages

  • NewMember
  • *
  • Posts: 49
Re: Sending first packet with RFM95 LoRa module
« Reply #4 on: November 07, 2015, 01:53:52 PM »
I'll have at that later on today.

Oh and from my previous attempts I've got compile errors when I use 'radio.send' instead of 'rf95.send'. Should I be using radio.send with my LoRa moteino? The error was 'radio is not declared in this scope from memory'.

And just so I'm learning from this, what does the inserted (uint8_t *) do? I'm guessing it is telling the send function to convert 'buffer' and 'sendlen' into an unsigned integer before processing it? Sorry for the questions but I'm really keen to properly learn how to code so I'll be better off in the future rather than just copying code I don't understand  :) If you recommend any tutorial series then I'll also do them so I don't keep bother you as much.

Regards

Dave

syrinxtech

  • Sr. Member
  • ****
  • Posts: 347
  • Country: us
    • Syrinx Technologies
Re: Sending first packet with RFM95 LoRa module
« Reply #5 on: November 07, 2015, 10:26:21 PM »
Well, if you're using the RadioHead libraries I'm assuming you would use rf95.send() instead of the radio.send() which is used for the RFM69 radios.  The "radio" variable is just an instantiation of the "RFM69" object.  The "send" is just the function in the class which actually transmits the data.  If you're using the RH libraries you could use "rf95" instead of "radio".  But, remember that both "radio" and "radio95" is just the common convention name for the variable.  You could have called it "hotdog" instead.  You just have to match up the name you use when you instantiate the class object with the name you use to call the methods.

For example, in your code you write:

RH_RF95 rf95;

This declares an object of class "RH_RF95" that has a name of "rf95".  When you want this object to send data you would call "rf95.send()".  If you want to learn more, there are lots of tutorials on the web regarding Object-Oriented Programming in C++.


The extra code is called a "cast" and it tells the compiler to treat one data type as another.  Since you're declaring the buffer as a char pointer (since it is an array of chars) and the data type of the argument to the function is uint8_t pointer (really an unsigned 8-bit integer), the compiler is going to complain without the cast.

ghowe

  • NewMember
  • *
  • Posts: 9
  • Country: us
Re: Sending first packet with RFM95 LoRa module
« Reply #6 on: March 06, 2016, 10:56:43 AM »
Piggy backing on this thread, I am having problems with the received data packet on the "server".  If I send "123" the received message is "123*******" where the '*' are unrecognized characters in the serial monitor.

Client Code:
Code: [Select]
#include <SPI.h>
#include <RH_RF95.h>

#define FREQUENCY  434
#define FREQUENCY  915

#ifdef __AVR_ATmega1284P__
  #define LED           15 // Moteino MEGAs have LEDs on D15
  #define FLASH_SS      23 // and FLASH SS on D23
#else
  #define LED           9 // Moteinos have LEDs on D9
  #define FLASH_SS      8 // and FLASH SS on D8
#endif

// Singleton instance of the radio driver
RH_RF95 rf95;

byte sendLen;
char buffer[50]; //final byte array that gets passed to radio.send

void setup()
{
  Serial.begin(115200);
  if (!rf95.init())
    Serial.println("init failed");
  else { Serial.print("init OK - "); Serial.print(FREQUENCY); Serial.print("mhz"); }
 
  // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on
  rf95.setFrequency(FREQUENCY);
  //rf95.setFrequency(915);
}

void loop()
{
  Serial.println("Sending to rf95_server");
  // Send a message to rf95_server
  //uint8_t data[] = "Hello World!";
  //rf95.send(data, sizeof(data));

  int data_to_send = 123;

  sprintf(buffer, "%d", data_to_send);
  sendLen = strlen(buffer);  //get the length of buffer

  rf95.send((uint8_t *) buffer, sendLen); //finally pass the string (byte array) to the radio to send
 
  rf95.waitPacketSent();
  // Now wait for a reply
  uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
  uint8_t len = sizeof(buf);

  if (rf95.waitAvailableTimeout(3000))
  {
    // Should be a reply message for us now   
    if (rf95.recv(buf, &len))
   {
      Serial.print("got reply: ");
      Serial.println((char*)buf);
      Serial.print("RSSI: ");
      Serial.println(rf95.lastRssi(), DEC);   
    }
    else
    {
      Serial.println("recv failed");
    }
  }
  else
  {
    Serial.println("No reply, is rf95_server running?");
  }
  Blink(LED,3);
  delay(200);
}

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

Server Code

Code: [Select]
#include <SPI.h>
#include <RH_RF95.h>

#define FREQUENCY  434
#define FREQUENCY  915

// Singleton instance of the radio driver
#ifdef __AVR_ATmega1284P__
  #define LED           15 // Moteino MEGAs have LEDs on D15
  #define FLASH_SS      23 // and FLASH SS on D23
#else
  #define LED           9 // Moteinos have LEDs on D9
  #define FLASH_SS      8 // and FLASH SS on D8
#endif

RH_RF95 rf95;

void setup()
{
  pinMode(LED, OUTPUT);
  Serial.begin(115200);
  if (!rf95.init())
    Serial.println("init failed");
  else { Serial.print("init OK - "); Serial.print(FREQUENCY); Serial.print("mhz"); }
  // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on
  rf95.setFrequency(FREQUENCY);
}

void loop()
{
  if (rf95.available())
  {
    // Should be a message for us now   
    uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(buf);
    if (rf95.recv(buf, &len))
    {
      digitalWrite(LED, HIGH);
//      RH_RF95::printBuffer("request: ", buf, len);
      Serial.print("got request: ");
      Serial.println((char*)buf);
      Serial.print("RSSI: ");
      Serial.println(rf95.lastRssi(), DEC);
     
      // Send a reply
      uint8_t data[] = "And hello back to you";
      rf95.send(data, sizeof(data));
      rf95.waitPacketSent();
      Serial.println("Sent a reply");
      digitalWrite(LED, LOW);
    }
    else
    {
      Serial.println("recv failed");
    }
  }
}

How do I get the message to print correctly on the serial monitor without the extra characters?

syrinxtech

  • Sr. Member
  • ****
  • Posts: 347
  • Country: us
    • Syrinx Technologies
Re: Sending first packet with RFM95 LoRa module
« Reply #7 on: March 06, 2016, 01:41:21 PM »
@ghowe,

First, it's generally a good idea to use send/receive buffers of the same length and type.  In your client code the buffer is char[50].  In the server code the buffer is uint8_t buf[RH_RF95_MAX_MESSAGE_LEN].  I know you added some typecasts to fix the problem but in general it's good form to match them up, or to match them to the type specified by the function call you're using.

I think your problem is that the string you're sending doesn't have a terminating null character (\0).

There are several ways to fix this problem, but here is what I normally do:

In the client code, add this line to the top of your loop() code:

memset(buffer, '\0', sizeof(buffer));



ghowe

  • NewMember
  • *
  • Posts: 9
  • Country: us
Re: Sending first packet with RFM95 LoRa module
« Reply #8 on: March 06, 2016, 03:08:12 PM »
@syrinxtech-

Added
memset(buf, '\0', sizeof(buf));

to the server code and that worked.

Thanks for the pointers.

syrinxtech

  • Sr. Member
  • ****
  • Posts: 347
  • Country: us
    • Syrinx Technologies
Re: Sending first packet with RFM95 LoRa module
« Reply #9 on: March 06, 2016, 04:37:19 PM »
Good, I wasn't sure if it would take one or the other or both to fix the problem.

I usually memset my buffers whenever I'm dealing with strings to make sure they are properly terminated.

You can also do something similar to the following:

Assume len = strlen(buffer)

You can do the following:

buffer(len) = '\0';