Author Topic: Can RFM69 communicate with RFM12B? [YES!]  (Read 88409 times)

panosnl

  • NewMember
  • *
  • Posts: 6
Re: Can RFM69 communicate with RFM12B? [YES!]
« Reply #15 on: February 07, 2014, 04:59:51 AM »
I am currently migrating from RFM12 to RFM69 and with the above libraries got the RFM12 to talk to the RFM69.
Thanks for all the efforts from `Felix and Timw for making this possible!

However the modified RFM12 Library seems to have broken the receive examples that uses pointers:

*radio.DataLen gives:
Code: [Select]
..\libraries\RFM12B_mod/RFM12B.h: In function 'void loop()':
..\libraries\RFM12B_mod/RFM12B.h:202: error: 'volatile uint8_t* RFM12B::DataLen' is private Test_2way_gateway:41: error: within this context
..\libraries\RFM12B_mod/RFM12B.h:201: error: 'volatile uint8_t* RFM12B::Data' is private Test_2way_gateway:42: error: within this context

and
theData = *(Payload*)radio.Data;  gives:
Code: [Select]
d:\Program Files (x86)\Arduino\libraries\RFM12B_mod/RFM12B.h: In function 'void loop()':
d:\Program Files (x86)\Arduino\libraries\RFM12B_mod/RFM12B.h:201: error: 'volatile uint8_t* RFM12B::Data' is private
RFM12B_Struct_gateway:82: error: within this context

When I replaced the modded RFM12 libraries with the original libraries the code compiles OK.

For the DataLen I could use GetDataLen() but for getting data into the struct I don't know how to avoid pointers.
Any suggestions? I like the RFM12 also to be able to listen to at least the RFM12

panosnl

  • NewMember
  • *
  • Posts: 6
Re: Can RFM69 communicate with RFM12B? [YES!]
« Reply #16 on: February 07, 2014, 06:45:30 AM »

I got the original code and my pointers working now.

I changed the RFM12B.h library from line200:

Code: [Select]
..
#if defined(RF69_COMPAT)
  volatile uint8_t* Data;
  volatile uint8_t* DataLen;
#endif
 
public:
    //constructor
..

so the the Data and DataLen are now defined as public:

Code: [Select]
..
public:

#if defined(RF69_COMPAT)
  volatile uint8_t* Data;
  volatile uint8_t* DataLen;
#endif
 
    //constructor
..

uChip

  • NewMember
  • *
  • Posts: 13
Re: Can RFM69 communicate with RFM12B? [YES!]
« Reply #17 on: February 08, 2014, 11:17:33 AM »
So now we have two forks of both RFM12B and RFM69 libs.  Is there any interest in bringing Timw's compatibility mods back into the LowPowerLab repo?

I'm now Watching all four forks, but as my local github app does not allow two identically named repos (in the same directory) and as the Arduino IDE does not allow two identically named libraries, maintenance is somewhat awkward.  And as panosnl's post would indicate, ongoing maintenance is going to be needed.

Thoughts?
« Last Edit: February 08, 2014, 11:20:03 AM by uChip »

uChip

  • NewMember
  • *
  • Posts: 13
Re: Can RFM69 communicate with RFM12B? [YES!]
« Reply #18 on: February 09, 2014, 03:59:10 PM »
I was able to duplicate Felix's test using Struct_receive and RF12_Struct_node, however the node side reports no ACKs received.

Looking at Tim's mods to the RFM12B library I think that maybe the definitions for ACK and Ask for ACK are reversed. 

In SendStart():
Code: [Select]
  rf12_hdr3 = (sendACK ? 0x40 : 0) | (requestACK ? 0x80 : 0);


I am comparing them to the LPL packet definition document which I read as saying that bit 7 (0x80) defines a packet as an ACK and bit6 (0x40) is the ASK for ACK flag. 

I double checked his by looking at the RFM69 library source.  In the interrupt handler I see the following. (code is the same in both Tim's and LPL's libraries).

Code: [Select]

    ACK_RECEIVED = CTLbyte & 0x80; //extract ACK-requested flag
    ACK_REQUESTED = CTLbyte & 0x40; //extract ACK-received flag


The code appears to follow the documentation however the comments are reversed.

Later, in Tim's RFM12B ACKReceived() I see the following.

Code: [Select]

#if !defined(RF69_COMPAT)
          (rf12_hdr3 & 0x40) &&
          !(rf12_hdr3 & 0x80);
#else
          (rf12_hdr1 & RF12_HDR_ACKCTLMASK) &&
          !(rf12_hdr2 & RF12_HDR_ACKCTLMASK);
#endif


It looks to me like the if-clause and the else-clause are reversed.

I tried editing these to wire the bits up correctly, but I just caused more errors and still no ACKs.  I will keep looking but if folks could confirm or refute my interpretation above that would be helpful.

Thanks,
  - Chip

uChip

  • NewMember
  • *
  • Posts: 13
Re: Can RFM69 communicate with RFM12B? [YES!]
« Reply #19 on: February 09, 2014, 11:58:37 PM »
I have fiddled with this some more this afternoon and have learned a lot.  Hopefully I'm also making changes that are helpful.  :)

First off, I had made the changes suggested by panosnl above.  Sorry but those changes cause problems.  Timw has it correct.  The reason why he made those variables private is that they change meaning in compatibility mode.  Instead, change the sketch not the library.  Specifically, in RFM12B_Struct_node.ino use the accessor functions.  Do not access the variables directly.

  In Loop()
  Change this:
Code: [Select]
      Serial.print('[');Serial.print(radio.GetSender(), DEC);Serial.print("] ");
      for (byte i = 0; i < *radio.DataLen; i++)
        Serial.print((char)radio.Data[i]);
  to this:
Code: [Select]
      Serial.print('[');Serial.print(radio.GetSender(), DEC);Serial.print("] ");
      for (byte i = 0; i < *radio.GetDataLen(); i++)
        Serial.print((char)radio.GetData()[i]);

Now we can make changes to the library.  Here are the changes to address the issues I noticed before, plus I found one more.

in RFM12B.h
Change this:
Code: [Select]
// shorthands to simplify sending out the proper ACK when requested
#define RF12_WANTS_ACK ((rf12_hdr2 & RF12_HDR_ACKCTLMASK) && !(rf12_hdr1 & RF12_HDR_ACKCTLMASK))
to this:
Code: [Select]
// shorthands to simplify sending out the proper ACK when requested
#if !defined(RF69_COMPAT)
#define RF12_WANTS_ACK ((rf12_hdr2 & RF12_HDR_ACKCTLMASK) && !(rf12_hdr1 & RF12_HDR_ACKCTLMASK))
#else
#define RF12_WANTS_ACK ((rf12_hdr3 & 0x40) && !(rf12_hdr3 & 0x80))
#endif

In RFM12B.cpp
  In ACKReceived()
  Change this:
Code: [Select]
#if !defined(RF69_COMPAT)
          (rf12_hdr3 & 0x40) &&
          !(rf12_hdr3 & 0x80);
#else
          (rf12_hdr1 & RF12_HDR_ACKCTLMASK) &&
          !(rf12_hdr2 & RF12_HDR_ACKCTLMASK);
#endif
  to this:
Code: [Select]
#if !defined(RF69_COMPAT)
          (rf12_hdr1 & RF12_HDR_ACKCTLMASK) &&
          !(rf12_hdr2 & RF12_HDR_ACKCTLMASK);
#else
          (rf12_hdr3 & 0x80) &&
          !(rf12_hdr3 & 0x40);
#endif

In RFM12B.cpp
  In SendStart()
  Change this:
Code: [Select]
  rf12_hdr3 = (sendACK ? 0x40 : 0) | (requestACK ? 0x80 : 0);
  to this:
Code: [Select]
  rf12_hdr3 = (sendACK ? 0x80 : 0) | (requestACK ? 0x40 : 0);

With these changes the logic seems correct, however most ACK messages are still lost.  This is because the other side (Struct_receive.ino) does several Serial.print()s before sending the ACK.  This delays when the ACK is sent and the RFM12B_Struct_node side times out.  I don't know if everyone sees this problem or if it's something unique to my environment.  If I change the define for the timeout from 30mS to 150mS about 95% of the ACKs make it in time.

  Change this:
Code: [Select]
#define ACK_TIME    30  // # of ms to wait for an ack
  To this:
Code: [Select]
#define ACK_TIME    150  // # of ms to wait for an ack

I would still like to see Tim's fork merged back into the LPL mainstream as the two have already diverged a little.

Oh, and for what it's worth, I really like the restructuring done in the RFM69 library.  It's much easier to read and understand.
Thanks,
  - Chip
« Last Edit: February 10, 2014, 12:32:51 AM by uChip »

uChip

  • NewMember
  • *
  • Posts: 13
Re: Can RFM69 communicate with RFM12B? [YES!]
« Reply #20 on: February 10, 2014, 01:30:08 AM »
Found one more on the RFM69 side.

In RFM69.cpp
  In sendWithRetry()
  Change this:
Code: [Select]
    while (millis()-sentTime<retryWaitTime)
    {
      if (ACKReceived(toAddress))
      {
        //Serial.print(" ~ms:");Serial.print(millis()-sentTime);
        return true;
      }
    }
  to this:
Code: [Select]
    do
    {
      if (ACKReceived(toAddress))
      {
        //Serial.print(" ~ms:");Serial.print(millis()-sentTime);
        return true;
      }
    } while (millis()-sentTime<retryWaitTime);

Always want to check the ACKReceived() at least once.

Then in Struct_receive.ino
  In Loop()
  Change this:
Code: [Select]
        if (radio.sendWithRetry(theNodeID, "ACK TEST", 8, 0))  // 0 = only 1 attempt, no retries

  to this:
Code: [Select]
        if (radio.sendWithRetry(theNodeID, "ACK TEST", 8, 0, 50))  // 0 = only 1 attempt, no retries; wait up to 50mS for the ACK


Looks like this ACK is consistently taking 40mS on my machine.  Making me wonder if my machine is slow for some reason.

uChip

  • NewMember
  • *
  • Posts: 13
Re: Can RFM69 communicate with RFM12B? [YES!]
« Reply #21 on: February 10, 2014, 12:07:21 PM »
As I said, maintenance is awkward.  Also error prone.

In my suggested changes above:
This:
Code: [Select]
for (byte i = 0; i < *radio.GetDataLen(); i++)
should be this:
Code: [Select]
for (byte i = 0; i < radio.GetDataLen(); i++)

Sorry folks,
  - Chip

fgomes

  • Jr. Member
  • **
  • Posts: 65
Re: Can RFM69 communicate with RFM12B? [YES!]
« Reply #22 on: February 17, 2014, 01:38:29 PM »
What a coincidence, I was just starting addressing these issues (access to protected variables, ack processing mismatch) when I found this thread and the libraries corrected (https://github.com/aanon4), haven't tested them yet, maybe tonight :-)
One curiosity is that the ack also is not working between two RFM12B nodes when I don't define the compatibility mode, I saw the ack being requested, the gateway sending it, but the node always missing it. The nodes work well with code based on the JeeLib.
Since I have some RFM69 and some RFM12B this compatibility mode is interesting to me, do you have tested the communication between two RFM12B nodes using the compatibility mode? If this also works I will start using only this mode.

Fernando

fgomes

  • Jr. Member
  • **
  • Posts: 65
Re: Can RFM69 communicate with RFM12B? [YES!]
« Reply #23 on: February 18, 2014, 10:01:34 AM »
Just an update of the problems I found with the current lib version (always using RF69_COMPAT mode):
In the RFM12B_Struct_node example, there is still the bug *radio.GetDataLen(), it should be replaced by radio.GetDataLen()
In the RFM12B_Struct_Gateway the *radio.DataLen should be replaced by radio.GetDataLen(), and the *(Payload*)radio.Data should be replaced by *(Payload*)radio.GetData()
Do you want me to propose the changes in the GitHub project directly?
I have a setup with two nodes with the RFM12B (JeeNodes) and I have also noticed a frequent failure in the acknowledges, somehow reduced if I wait a bit more than the standard 30ms for the acknowledge, but even waiting more it fails a lot. Also the normal messages also fail from time to time, not so bad as the acks, but I think that they are failing at a rate of 5% or more. I've tried to put some debug to identify the failures in the acknowledges and noticed that part of them fail because of wrong CRC and other part by not receiving the message (ReceiveComplete doesn't return true during the wait for ACK), about 50% for each case. These situations shouldn't occur when the two nodes are 10cm away from each other, so to introduce an additional test scenario I put the RFM12B_Struct_node in another room, about 10m away from the gateway with a brick wall between them, and the result is more or less the same, so it seems it isn't a noise / RF power limitation but some implementation issue. I'll have to use a sniffer to try to dig more into this.
Using the same two nodes with the original code for the JeeNodes the communication results are much better. Any ideas of what could be the problem?

Fernando

uChip

  • NewMember
  • *
  • Posts: 13
Re: Can RFM69 communicate with RFM12B? [YES!]
« Reply #24 on: February 18, 2014, 11:06:50 AM »
The first problem you mention is my mistake in the post above.  That one and the other changes to the examples sketches to use the accessor functions have already been sent to Timw as a pull request.  No response from Tim yet.

I have tested most of the example sketches with two RFM12Bs.  Once the above changes are made they all seem to work, but they all have the problem that you mention.  I found the same issue with ACKs but thought it was something unique to my system.  I can get most ACKs to go through if I increase the ACK timeout to about 150 to 200 mS.  Even there some small percentage of ACKs are lost.

  - Chip

fgomes

  • Jr. Member
  • **
  • Posts: 65
Re: Can RFM69 communicate with RFM12B? [YES!]
« Reply #25 on: February 20, 2014, 09:32:54 AM »
Thanks for your reply, I'm continuing to make some tests with the RFM12B library in the RF69_COMPAT mode, and found two things that I need to clarify:

In the function RFM12B::SendStart there is a increment of 3 in the rf12_len, and in the GetDataLen function the rf12_len is decremented by 3 (to keep the original size of the payload). So the message that goes to the air has a payload length that is 3 byte bigger than the real payload, is this a need for the RFM69 module?

I'm sending messages periodically and printing the received bytes inside ReceiveComplete to try to figure out why I'm loosing some messages between two nodes that are side by side. What I found is that the messages that are lost have always the same byte changed, the last CRC byte.

Good message:
64 17 1 6F 40 2 0 0 30 42 1 0 0 A0 41 1 0 0 A9 41 0 0 0 0 0 59 98
Corrupted message:
64 17 1 6F 40 2 0 0 30 42 1 0 0 A0 41 1 0 0 A9 41 0 0 0 0 0 59 99

Good message:
64 17 1 6F 40 2 0 0 28 42 1 0 0 A8 41 1 0 0 AE 41 0 0 0 0 0 C2 64
Corrupted message:
64 17 1 6F 40 2 0 0 28 42 1 0 0 A8 41 1 0 0 AE 41 0 0 0 0 0 C2 65

Good message:
64 17 1 6F 40 2 0 0 28 42 1 0 0 A8 41 1 0 80 AC 41 0 0 0 0 0 5F 7
Corrupted message:
64 17 1 6F 40 2 0 0 28 42 1 0 0 A8 41 1 0 80 AC 41 0 0 0 0 0 5F 6

It is always the last byte (second CRC byte) that gets corrupted, and always the same bit changed in the byte, B0 changes from 0 to 1, or from 1 to 0, always the same bit in the same byte. The CRC in these cases is always 2E 0D instead of 1D 0F, and the wrong CRC value is the same even for different messages. In average I get a failure rate of about 4% (18 corrupted messages in 500) for two nodes that sit side by side (10 cm away from each other).

Any idea of why could this happen?

Fernando

« Last Edit: February 20, 2014, 10:15:48 AM by fgomes »

uChip

  • NewMember
  • *
  • Posts: 13
Re: Can RFM69 communicate with RFM12B? [YES!]
« Reply #26 on: February 20, 2014, 10:33:36 PM »
I can tackle the first question.  The length field of the original RFM12B does not include the header bytes for DestID and SourceID.  In the RFM69 compat mode both these (now called DestID and SenderID) are after the PayloadLen byte plus there is the new CTL byte for defining ACK and ASKforACK.  Altogether that makes the length field three bytes longer than it was before.  The GetDataLen function retrieves the PayloadLen byte and then reduces it by three because that returns the length of the data, not the length of the entire payload.  Felix has a nice drawing of the packet structure in his documentation for each of RFM12B and RFM69.  You might want to give those a look and compare them side-by-side. 

  - Chip