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:
// 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:
#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!
@Ric,
this is because Photon compiler does not align struct on byte but on 4 bytes, you need to use #pragma directive as follow
#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 (https://github.com/hallard/ULPNode_RF_Protocol/blob/master/ULPNode_RF_Protocol.h)
humm not sure int is same size on both side, Could you try with this struct on both side
// 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 ?
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.
I changed the code on the Moteino to:
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:
[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:
// 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:
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");
}
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,
#pragma pack(2) // set alignment to 2 bytes boundary
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
#pragma pack(1) // set alignment to 1 byte boundary
***UPDATE***
Hi Charly,
On the Photon sketch that I actually use my struct was
typedef struct {
char Type;
int ID;
char Action;
int Var1;
int Var2;
int Var3;
} Payload;
Payload theData;
After changing the struct to
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.