Author Topic: RFM69 Library now works on Spark Core  (Read 5983 times)

Charly86

  • Jr. Member
  • **
  • Posts: 74
  • Country: fr
RFM69 Library now works on Spark Core
« on: December 07, 2014, 09:04:46 PM »
Hi Guys,

Just to let you know that latest RFM69 library has been forked and ported to work on Spark Core with few little improvement.

It will be used on a dedicated French specific electrical heating method hardware board
https://github.com/thibdct/programmateur-fil-pilote-wifi/tree/master/Mat%C3%A9riel/1.2

modification of library and explanation are there : https://github.com/hallard/RFM69

« Last Edit: December 07, 2014, 09:07:43 PM by Charly86 »

bmquist

  • NewMember
  • *
  • Posts: 1
Re: RFM69 Library now works on Spark Core
« Reply #1 on: September 28, 2015, 02:16:22 PM »
Can you tell os more about your project? any photos? are you using spark core /particle Photon and RFM69 together, so you skip the red PCB from lowpowerlabs? (just trying to figure out your setup) because I am working on something like that, to minimize parts,

Charly86

  • Jr. Member
  • **
  • Posts: 74
  • Country: fr
Re: RFM69 Library now works on Spark Core
« Reply #2 on: September 28, 2015, 03:13:23 PM »
@bmquist,

Yeah, for sure, you can see some picture on this blog post
https://hallard.me/particle-gateway/

I'm using Particle Photon and Spark, and since couple of days I've got also a ESP8266 Gateway with RFM69. But I must admit that I'm currently switching all of this to RadioHead library, mainly to get a kind of hardware independency on module used. I plan to test some Lora ;-)



Ric

  • NewMember
  • *
  • Posts: 9
Re: RFM69 Library now works on Spark Core
« Reply #3 on: October 12, 2015, 12:09:20 PM »
Hi folks,
I'm having the data corruption issue between my Photon with RFM69 and a moteino with the same transceiver. Using the same code with 2 moteinos I have no issues but once I move the send code to the Photon data packets are sent corrupted. I simply used the examples that came with the RFM69 library and removed the SPI.h and SPIFLASH.h libraries and code associated with them on the Photon.

Photon Code:

Code: [Select]
    // This #include statement was automatically added by the Particle IDE.
    #include "RFM69/RFM69.h"
   
    #define NODEID      1
    #define NETWORKID   100
    #define GATEWAYID   99
    #define FREQUENCY   RF69_433MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ)
    #define KEY         "thisIsEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less!
    #define LED         D7
    #define SERIAL_BAUD 115200
    #define ACK_TIME    30  // # of ms to wait for an ack
   
    int TRANSMITPERIOD = 300; //transmit a packet to gateway so often (in ms)
    byte sendSize=0;
    boolean requestACK = false;
    RFM69 radio;
   
    typedef struct {
      int           nodeId; //store this nodeId
      unsigned long uptime; //uptime in ms
      float         temp;   //temperature maybe?
    } Payload;
    Payload theData;
   
    void setup() {
      Serial.begin(SERIAL_BAUD);
      radio.initialize(FREQUENCY,NODEID,NETWORKID);
      //radio.setHighPower(); //uncomment only for RFM69HW!
      radio.encrypt(KEY);
      char buff[50];
      sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
      Serial.println(buff);
    }
   
    long lastPeriod = -1;
    void loop() {
      //process any serial input
      if (Serial.available() > 0)
      {
        char input = Serial.read();
        if (input >= 48 && input <= 57) //[0,9]
        {
          TRANSMITPERIOD = 100 * (input-48);
          if (TRANSMITPERIOD == 0) TRANSMITPERIOD = 1000;
          Serial.print("\nChanging delay to ");
          Serial.print(TRANSMITPERIOD);
          Serial.println("ms\n");
        }
       
        if (input == 'r') //d=dump register values
          radio.readAllRegs();
        //if (input == 'E') //E=enable encryption
        //  radio.encrypt(KEY);
        //if (input == 'e') //e=disable encryption
        //  radio.encrypt(null);
      }
   
      //check for any received packets
      if (radio.receiveDone())
      {
        Serial.print('[');Serial.print(radio.SENDERID, DEC);Serial.print("] ");
        for (byte i = 0; i < radio.DATALEN; i++)
          Serial.print((char)radio.DATA[i]);
        Serial.print("   [RX_RSSI:");Serial.print(radio.readRSSI());Serial.print("]");
   
        if (radio.ACKRequested())
        {
          radio.sendACK();
          Serial.print(" - ACK sent");
          delay(10);
        }
        Blink(LED,5);
        Serial.println();
      }
     
      int currPeriod = millis()/TRANSMITPERIOD;
      if (currPeriod != lastPeriod)
      {
        //fill in the struct with new values
        theData.nodeId = NODEID;
        theData.uptime = millis();
        theData.temp = 91.23; //it's hot!
       
        Serial.print("Sending struct (");
        Serial.print(sizeof(theData));
        Serial.print(" bytes) ... ");
        if (radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData)))
          Serial.print(" ok!");
        else Serial.print(" nothing...");
        Serial.println();
        Blink(LED,3);
        lastPeriod=currPeriod;
      }
    }
   
    void Blink(byte PIN, int DELAY_MS)
    {
      pinMode(PIN, OUTPUT);
      digitalWrite(PIN,HIGH);
      delay(DELAY_MS);
      digitalWrite(PIN,LOW);
    }

Moteino Code:

Code: [Select]
    #include <RFM69.h>
    #include <SPI.h>
    #include <SPIFlash.h>
   
    #define NODEID      99
    #define NETWORKID   100
    #define FREQUENCY   RF69_433MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ)
    #define KEY         "thisIsEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less!
    #define LED         9
    #define SERIAL_BAUD 115200
    #define ACK_TIME    30  // # of ms to wait for an ack
   
    RFM69 radio;
    SPIFlash flash(8, 0xEF30); //EF40 for 16mbit windbond chip
    bool promiscuousMode = false; //set to 'true' to sniff all packets on the same network
   
    typedef struct {
      int           nodeId; //store this nodeId
      unsigned long uptime; //uptime in ms
      float         temp;   //temperature maybe?
    } Payload;
    Payload theData;
   
    void setup() {
      Serial.begin(SERIAL_BAUD);
      delay(10);
      radio.initialize(FREQUENCY,NODEID,NETWORKID);
      //radio.setHighPower(); //uncomment only for RFM69HW!
      radio.encrypt(KEY);
      radio.promiscuous(promiscuousMode);
      char buff[50];
      sprintf(buff, "\nListening at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
      Serial.println(buff);
      if (flash.initialize())
        Serial.println("SPI Flash Init OK!");
      else
        Serial.println("SPI Flash Init FAIL! (is chip present?)");
    }
   
    byte ackCount=0;
    void loop() {
      //process any serial input
      if (Serial.available() > 0)
      {
        char input = Serial.read();
        if (input == 'r') //d=dump all register values
          radio.readAllRegs();
        if (input == 'E') //E=enable encryption
          radio.encrypt(KEY);
        if (input == 'e') //e=disable encryption
          radio.encrypt(null);
        if (input == 'p')
        {
          promiscuousMode = !promiscuousMode;
          radio.promiscuous(promiscuousMode);
          Serial.print("Promiscuous mode ");Serial.println(promiscuousMode ? "on" : "off");
        }
       
        if (input == 'd') //d=dump flash area
        {
          Serial.println("Flash content:");
          int counter = 0;
   
          while(counter<=256){
            Serial.print(flash.readByte(counter++), HEX);
            Serial.print('.');
          }
          while(flash.busy());
          Serial.println();
        }
        if (input == 'D')
        {
          Serial.print("Deleting Flash chip content... ");
          flash.chipErase();
          while(flash.busy());
          Serial.println("DONE");
        }
        if (input == 'i')
        {
          Serial.print("DeviceID: ");
          word jedecid = flash.readDeviceId();
          Serial.println(jedecid, HEX);
        }
      }
   
      if (radio.receiveDone())
      {
        Serial.print('[');Serial.print(radio.SENDERID, DEC);Serial.print("] ");
        Serial.print(" [RX_RSSI:");Serial.print(radio.readRSSI());Serial.print("]");
        if (promiscuousMode)
        {
          Serial.print("to [");Serial.print(radio.TARGETID, DEC);Serial.print("] ");
        }
   
        if (radio.DATALEN != sizeof(Payload))
          Serial.print("Invalid payload received, not matching Payload struct!");
        else
        {
          theData = *(Payload*)radio.DATA; //assume radio.DATA actually contains our struct and not something else
          Serial.print(" nodeId=");
          Serial.print(theData.nodeId);
          Serial.print(" uptime=");
          Serial.print(theData.uptime);
          Serial.print(" temp=");
          Serial.print(theData.temp);
        }
       
        if (radio.ACKRequested())
        {
          byte theNodeID = radio.SENDERID;
          radio.sendACK();
          Serial.print(" - ACK sent.");
   
          // When a node requests an ACK, respond to the ACK
          // and also send a packet requesting an ACK (every 3rd one only)
          // This way both TX/RX NODE functions are tested on 1 end at the GATEWAY
          if (ackCount++%3==0)
          {
            Serial.print(" Pinging node ");
            Serial.print(theNodeID);
            Serial.print(" - ACK...");
            delay(3); //need this when sending right after reception .. ?
            if (radio.sendWithRetry(theNodeID, "ACK TEST", 8, 0))  // 0 = only 1 attempt, no retries
              Serial.print("ok!");
            else Serial.print("nothing");
          }
        }
        Serial.println();
        Blink(LED,3);
      }
    }
   
    void Blink(byte PIN, int DELAY_MS)
    {
      pinMode(PIN, OUTPUT);
      digitalWrite(PIN,HIGH);
      delay(DELAY_MS);
      digitalWrite(PIN,LOW);
    }

I left the SPI.h and SPIFLASH.h libraries on the Moteino code because it does have the flash memory chip installed.

I'm getting a message saying "Invalid payload received, not matching Payload struct!" because the size of the struct received is not matching the format on hand even through they both do have the same format.

Could the RFM69 chip be having a timing issue because the Photon is so much faster than the ATmega328P on the Moteino?

Any help would be greatly appreciated.

Thanks in advance!

Charly86

  • Jr. Member
  • **
  • Posts: 74
  • Country: fr
Re: RFM69 Library now works on Spark Core
« Reply #4 on: October 12, 2015, 01:28:14 PM »
@Ric,
this is because Photon compiler does not align struct on byte but on 4 bytes, you  need to use #pragma directive as follow

Code: [Select]
#ifdef SPARK
  // This will force structure to 1 byte alignment
  #pragma pack(push)  // push current alignment to stack
  #pragma pack(1)     // set alignment to 1 byte boundary
#endif

 // Put your struct declaration here
 typedef struct {
      int           nodeId; //store this nodeId
      unsigned long uptime; //uptime in ms
      float         temp;   //temperature maybe?
    } Payload;
    Payload theData;

#ifdef SPARK
  // restore original alignment from stack
  #pragma pack(pop)
#endif

then should be working fine ;-)

You can see example in ULPNode RF Protocol definition file
https://github.com/hallard/ULPNode_RF_Protocol/blob/master/ULPNode_RF_Protocol.h

Ric

  • NewMember
  • *
  • Posts: 9
Re: RFM69 Library now works on Spark Core
« Reply #5 on: October 12, 2015, 06:16:45 PM »
Thanks for the quick response Charly! Unfortunately I'm still getting the same message. What could possibly be wrong?? Do you have different code that works for you that I could try?

Thanks again.

Charly86

  • Jr. Member
  • **
  • Posts: 74
  • Country: fr
Re: RFM69 Library now works on Spark Core
« Reply #6 on: October 12, 2015, 06:43:53 PM »
humm not sure int is same size on both side, Could you try with this struct on both side

Code: [Select]
 // Put your struct declaration here
 typedef struct {
      uint8_t           nodeId; //store this nodeId
      unsigned long uptime; //uptime in ms
      float         temp;   //temperature maybe?
    } Payload;
    Payload theData;

and add in setup the following code and check displayed size is same on both side ?

Code: [Select]
Serial.print("Struct size=");
Serial.print(sizeof(theData));
Serial.println(" bytes");

And to be sure, my first post about pragma is for Spark side

Anyway, here a project with Felix's code working but there is lot of files on it. I remember I modifed some lines in orginal RFM69 code but I don't remember which ones.
https://github.com/thibdct/programmateur-fil-pilote-wifi/tree/00e4aec1baa10f3e694f9c0b58795ea083873f0c/Logiciel/remora

It's pretty old because now I've swhitched to radiohead on my Particle Gateway.
« Last Edit: October 12, 2015, 06:52:05 PM by Charly86 »

Ric

  • NewMember
  • *
  • Posts: 9
Re: RFM69 Library now works on Spark Core
« Reply #7 on: October 12, 2015, 06:56:25 PM »
The Photon says that it's sending 9 and the Moteino says that it's receiving 10.  :o

Ric

  • NewMember
  • *
  • Posts: 9
Re: RFM69 Library now works on Spark Core
« Reply #8 on: October 12, 2015, 07:09:56 PM »
I changed the code on the Moteino to:
Code: [Select]
    if (radio.DATALEN != sizeof(Payload) - 1)
    {
      Serial.print("Invalid payload received, not matching Payload struct!");
      Serial.print("Struct size=");
      Serial.print(sizeof(theData));
      Serial.print(" bytes");
    }

So that by subtracting a byte it would match just to see what was coming out of the struct and this is what I got:

Code: [Select]
[1]  [RX_RSSI:-29] nodeId=-11263 uptime=3271559368 temp=0.00 - ACK sent.
[1]  [RX_RSSI:-29] nodeId=-11263 uptime=3271559368 temp=0.00 - ACK sent. Pinging node 1 - ACK...nothing
[1]  [RX_RSSI:-28] nodeId=1 uptime=3271559370 temp=0.00 - ACK sent.
[1]  [RX_RSSI:-29] nodeId=1 uptime=3271559370 temp=0.00 - ACK sent.
[1]  [RX_RSSI:-28] nodeId=1 uptime=3271559370 temp=0.00 - ACK sent. Pinging node 1 - ACK...nothing
[1]  [RX_RSSI:-28] nodeId=11265 uptime=3271559371 temp=0.00 - ACK sent.
[1]  [RX_RSSI:-28] nodeId=11265 uptime=3271559371 temp=0.00 - ACK sent.
[1]  [RX_RSSI:-28] nodeId=11265 uptime=3271559371 temp=0.00 - ACK sent. Pinging node 1 - ACK...nothing
[1]  [RX_RSSI:-29] nodeId=22529 uptime=3271559372 temp=0.00 - ACK sent.
[1]  [RX_RSSI:-28] nodeId=22529 uptime=3271559372 temp=0.00 - ACK sent.
[1]  [RX_RSSI:-28] nodeId=22529 uptime=3271559372 temp=0.00 - ACK sent. Pinging node 1 - ACK...nothing
[1]  [RX_RSSI:-28] nodeId=-31743 uptime=3271559373 temp=0.00 - ACK sent.
[1]  [RX_RSSI:-29] nodeId=-31743 uptime=3271559373 temp=0.00 - ACK sent.
[1]  [RX_RSSI:-28] nodeId=-31743 uptime=3271559373 temp=0.00 - ACK sent. Pinging node 1 - ACK...nothing
[1]  [RX_RSSI:-29] nodeId=-20479 uptime=3271559374 temp=0.00 - ACK sent.
[1]  [RX_RSSI:-28] nodeId=-20479 uptime=3271559374 temp=0.00 - ACK sent.
[1]  [RX_RSSI:-28] nodeId=-20479 uptime=3271559374 temp=0.00 - ACK sent. Pinging node 1 - ACK...nothing
[1]  [RX_RSSI:-28] nodeId=-9215 uptime=3271559375 temp=0.00 - ACK sent.
[1]  [RX_RSSI:-28] nodeId=-9215 uptime=3271559375 temp=0.00 - ACK sent.

Also and just to make sure that I understood your directions correctly. Here is my Photon code:
Code: [Select]
// This #include statement was automatically added by the Particle IDE.
#include "RFM69/RFM69.h"

#define NODEID      1
#define NETWORKID   100
#define GATEWAYID   99
#define FREQUENCY   RF69_433MHZ //Match this with the version of your Moteino! (others: RF69_433MHZ, RF69_868MHZ)
#define KEY         "thisIsEncryptKey" //has to be same 16 characters/bytes on all nodes, not more not less!
#define LED         D7
#define SERIAL_BAUD 115200
#define ACK_TIME    30  // # of ms to wait for an ack

int TRANSMITPERIOD = 300; //transmit a packet to gateway so often (in ms)
byte sendSize=0;
boolean requestACK = false;
RFM69 radio;

#ifdef SPARK
  // This will force structure to 1 byte alignment
  #pragma pack(push)  // push current alignment to stack
  #pragma pack(1)     // set alignment to 1 byte boundary
#endif

// Put your struct declaration here
 typedef struct {
      uint8_t           nodeId; //store this nodeId
      unsigned long uptime; //uptime in ms
      float         temp;   //temperature maybe?
    } Payload;
    Payload theData;

#ifdef SPARK
  // restore original alignment from stack
  #pragma pack(pop)
#endif

void setup() {
  Serial.begin(SERIAL_BAUD);
  delay(10);
  radio.initialize(FREQUENCY,NODEID,NETWORKID);
  //radio.setHighPower(); //uncomment only for RFM69HW!
  radio.encrypt(KEY);
  radio.setIRQ(D2);
  radio.setBaudRate(60000);
  char buff[50];
  sprintf(buff, "\nTransmitting at %d Mhz...", FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
  Serial.println(buff);
  Serial.println();
Serial.print("Struct size=");
Serial.print(sizeof(theData));
Serial.print(" bytes");
}

long lastPeriod = -1;
void loop() {
  //process any serial input
  if (Serial.available() > 0)
  {
    char input = Serial.read();
    if (input >= 48 && input <= 57) //[0,9]
    {
      TRANSMITPERIOD = 100 * (input-48);
      if (TRANSMITPERIOD == 0) TRANSMITPERIOD = 1000;
      Serial.print("\nChanging delay to ");
      Serial.print(TRANSMITPERIOD);
      Serial.println("ms\n");
    }
   
    if (input == 'r') //d=dump register values
      radio.readAllRegs();
    //if (input == 'E') //E=enable encryption
    //  radio.encrypt(KEY);
    //if (input == 'e') //e=disable encryption
    //  radio.encrypt(null);
  }

  //check for any received packets
  if (radio.receiveDone())
  {
    Serial.print('[');Serial.print(radio.SENDERID, DEC);Serial.print("] ");
    for (byte i = 0; i < radio.DATALEN; i++)
      Serial.print((char)radio.DATA[i]);
    Serial.print("   [RX_RSSI:");Serial.print(radio.readRSSI());Serial.print("]");

    if (radio.ACKRequested())
    {
      radio.sendACK();
      Serial.print(" - ACK sent");
      delay(10);
    }
    Blink(LED,5);
    Serial.println();
  }
 
  int currPeriod = millis()/TRANSMITPERIOD;
  if (currPeriod != lastPeriod)
  {
    //fill in the struct with new values
    theData.nodeId = NODEID;
    theData.uptime = millis();
    theData.temp = 91.23; //it's hot!
   
    Serial.print("Sending struct (");
    Serial.print(sizeof(theData));
    Serial.print(" bytes) ... ");
    if (radio.sendWithRetry(GATEWAYID, (const void*)(&theData), sizeof(theData)))
      Serial.print(" ok!");
    else Serial.print(" nothing...");
    Serial.println();
    Blink(LED,3);
    lastPeriod=currPeriod;
  }
}

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

And here is my Moteino code the only part I changed was:
Code: [Select]
    if (radio.DATALEN != sizeof(Payload) - 1)
    {
      Serial.print("Invalid payload received, not matching Payload struct!");
      Serial.print("Struct size=");
      Serial.print(sizeof(theData));
      Serial.print(" bytes");
    }

Charly86

  • Jr. Member
  • **
  • Posts: 74
  • Country: fr
Re: RFM69 Library now works on Spark Core
« Reply #9 on: October 12, 2015, 07:14:01 PM »
Humm, sounds strange that moteino is 2 bytes aligned is it moteino or moteino mega ?

Woud you try with pack 2 bytes instead on 1,

Code: [Select]
#pragma pack(2)     // set alignment to 2 bytes boundary

Ric

  • NewMember
  • *
  • Posts: 9
Re: RFM69 Library now works on Spark Core
« Reply #10 on: October 12, 2015, 07:19:15 PM »
That's it! Packing 2 bytes worked!!!!

By the way, I'm using just a regular Moteino, not the mega.

Thank you so so so much for your help!

Charly86

  • Jr. Member
  • **
  • Posts: 74
  • Country: fr
Re: RFM69 Library now works on Spark Core
« Reply #11 on: October 12, 2015, 07:19:33 PM »
may be another idea would be to set the same #pragma directive on both sketches without any #ifdef to be sure they're all the same

just put on each sketch the following line, moteino should now says size of 9 bytes

#
Code: [Select]
pragma pack(1)     // set alignment to 1 byte boundary

Charly86

  • Jr. Member
  • **
  • Posts: 74
  • Country: fr
Re: RFM69 Library now works on Spark Core
« Reply #12 on: October 12, 2015, 07:23:47 PM »
great it worked,
I was not aware moteino is 2 bytes aligned, I was sure it was 1 and never set this option on Arduino side and always worked.
So I've got 2 options :
- new compiler version is now aligning to 2 bytes
- I was always lucky to get all my structures 2 bytes aligned between arduino and Spark/ESP8266 ;-)

I will correct my code just in case ;-)

thanks pointing out on this

Ric

  • NewMember
  • *
  • Posts: 9
Re: RFM69 Library now works on Spark Core
« Reply #13 on: October 15, 2015, 12:32:00 PM »
***UPDATE***

Hi Charly,
On the Photon sketch that I actually use my struct was

Code: [Select]
typedef struct {
  char        Type;
  int           ID;
  char        Action;
  int           Var1;
  int           Var2;
  int           Var3;
} Payload;
Payload theData;

After changing the struct to
Code: [Select]
typedef struct {
  byte            Type;
  int16_t           ID;
  byte            Action;
  int16_t           Var1;
  int16_t           Var2;
  int16_t           Var3;
} Payload;
Payload theData;

I only needed to align 1 byte, not 2. With this I didn't have to make any modification on the Moteino.