dconstructing / rfm69

Node module for interfacing with HopeRF RFM69 modules on a Raspberry Pi
14 stars 6 forks source link

Send timed out <Buffer ...> <Buffer ...> #8

Open ghost opened 8 years ago

ghost commented 8 years ago

Hi, I'm trying to get a RFM69HCW radio from HopeRF working as a trasmitter in the following environment:

Raspberry Pi 2 Model B (raspbian jessie, release from 2016-03-18) node --version = v4.4.2 npm --version = 2.15.0 uname -a = Linux raspberry 4.1.19-v7+ #858 SMP Tue Mar 15 15:56:00 GMT 2016 armv7l GNU/Linux

Along with an Arduino which works as a receiver and has been tested with another arduino that worked as a trasmitter.

I'm using the following node.js test code:

var RFM69 = require('/home/pi/Desktop/DEV/project/node_modules/rfm69');

// configure a module
var config = {
    encryptionKey: "sampleEncryptKey",
    highPower: true,
    nodeAddress: 1,
    broadcastAddress: 100,
    //spiBus: 0,
    //spiDevice: 0,
    frequency: 433,
    interruptPin: 22,
    resetPin: 27,
    verbose: true,
    config: 'lowPowerLab'
};

var rfm69 = new RFM69(config);

rfm69.onReady = function() {
    // module initialized
    //rfm69.listen();  // can receive
    console.log("----------------------------------------------RFM69 Ready----------------------------------------------");
    rfm69.send("Hello World", function(err, data){
        if (err) {
            console.error('[debug] Error sending', err);
        } else {
            console.log('[debug] sent to mote', data);
        }
    });
};

rfm69.onMessage = function(buffer) {
    console.log('received message', buffer);
};

// start up the module
rfm69.initialize();

// clean up on shutdown
process.on('SIGINT', function() {
    rfm69.close();
    process.exit();
});

And the following Arduino Receiver code:

/* RFM69 library and code by Felix Rusu - felix@lowpowerlab.com
// (...)
// Please maintain this license information along with authorship
// and copyright notices in any redistribution of this code
// **********************************************************************************/

#include <RFM69.h>    //get it here: https://www.github.com/lowpowerlab/rfm69
#include <SPI.h>

//*********************************************************************************************
// *********** IMPORTANT SETTINGS - YOU MUST CHANGE/ONFIGURE TO FIT YOUR HARDWARE *************
//*********************************************************************************************
#define NETWORKID     100  //the same on all nodes that talk to each other
#define NODEID        3  

//Match frequency to the hardware version of the radio on your Feather
#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_RFM69HCW    true // set to 'true' if you are using an RFM69HCW module

//*********************************************************************************************
#define SERIAL_BAUD   115200

#define RFM69_CS      10
#define RFM69_IRQ     2
#define RFM69_IRQN    0  // Pin 2 is IRQ 0!
#define RFM69_RST     9

#define LED           13  // onboard blinky

int16_t packetnum = 0;  // packet counter, we increment per xmission

RFM69 radio = RFM69(RFM69_CS, RFM69_IRQ, IS_RFM69HCW, RFM69_IRQN);

void setup() {
  //while (!Serial); // wait until serial console is open, remove if not tethered to computer
  Serial.begin(SERIAL_BAUD);

  Serial.println("Feather RFM69HCW Receiver");

  // Hard Reset the RFM module
  pinMode(RFM69_RST, OUTPUT);
  digitalWrite(RFM69_RST, HIGH);
  delay(100);
  digitalWrite(RFM69_RST, LOW);
  delay(100);

  // Initialize radio
  bool initState = radio.initialize(FREQUENCY,NODEID,NETWORKID);
  if(initState){
    Serial.println("Receiver Initialized");
  } else {
    Serial.println("Receiver Failed To Initialize");
  }

  if (IS_RFM69HCW) {
    radio.setHighPower();    // Only for RFM69HCW & HW!
  }
  radio.setPowerLevel(31); // power output ranges from 0 (5dBm) to 31 (20dBm)

  radio.encrypt(ENCRYPTKEY);

  pinMode(LED, OUTPUT);

  Serial.print("\nListening at ");
  Serial.print(FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
  Serial.println(" MHz");
}

void loop() {
  //check if something was received (could be an interrupt from the radio)
  if (radio.receiveDone())
  {
    //print message received to serial
    Serial.print('[');Serial.print(radio.SENDERID);Serial.print("] ");
    Serial.print((char*)radio.DATA);
    Serial.print("   [RX_RSSI:");Serial.print(radio.RSSI);Serial.print("]");

    //check if received message contains Hello World
    //if (strstr((char *)radio.DATA, "Hello World"))
    //{
      //check if sender wanted an ACK
      if (radio.ACKRequested())
      {
        radio.sendACK();
        Serial.println(" - ACK sent");
      }
      Blink(LED, 40, 3); //blink LED 3 times, 40ms between blinks
    //}  
  }

  radio.receiveDone(); //put radio in RX mode
  Serial.flush(); //make sure all serial data is clocked out before sleeping the MCU
}

void Blink(byte PIN, byte DELAY_MS, byte loops)
{
  for (byte i=0; i<loops; i++)
  {
    digitalWrite(PIN,HIGH);
    delay(DELAY_MS);
    digitalWrite(PIN,LOW);
    delay(DELAY_MS);
  }
}

And the node.js output is as follows:

>sudo node rfm69hcw.js 
register read 1 => 100
register read 2 => 0
register read 3 => 11010
register read 4 => 1011
register read 5 => 0
register read 6 => 1010010
register read 7 => 11100100
register read 8 => 11000000
register read 9 => 0
register read 19 => 10000110
register read 25 => 0
register read 26 => 101
register read 28 => 0
register read 29 => 11111111
register read 2e => 10011000
register read 2f => 0
register read 30 => 0
register read 37 => 10000
register read 38 => 1000000
register read 3c => 1111
register read 3d => 10
register read 5a => 1010101
register read 5c => 1110000
register read 6f => 0
register write 1 => 100 (was 100 )
register write 2 => 0 (was 0 )
register write 3 => 10 (was 11010 )
register write 4 => 1000000 (was 1011 )
register write 5 => 11 (was 0 )
register write 6 => 110011 (was 1010010 )
register write 7 => 1101100 (was 11100100 )
register write 8 => 1000000 (was 11000000 )
register write 9 => 0 (was 0 )
register write 11 => 1100000 (was 10011111 )
register write 13 => 1111 (was 11010 )
register write 19 => 1000010 (was 10000110 )
register write 25 => 1000000 (was 0 )
register write 26 => 111 (was 101 )
register write 28 => 10000 (was 0 )
register write 29 => 11011100 (was 11111111 )
register write 2e => 10001000 (was 10011000 )
register write 2f => 101101 (was 0 )
register write 30 => 1100100 (was 0 )
register write 37 => 10010000 (was 10000 )
register write 38 => 1000010 (was 1000000 )
register write 39 => 1 (was 0 )
register write 3a => 1100100 (was 0 )
register write 3c => 10001111 (was 1111 )
register write 3d => 1 (was 10 )
register write 3e => 1110011 (was 0 )
register write 3f => 1100001 (was 0 )
register write 40 => 1101101 (was 0 )
register write 41 => 1110000 (was 0 )
register write 42 => 1101100 (was 0 )
register write 43 => 1100101 (was 0 )
register write 44 => 1000101 (was 0 )
register write 45 => 1101110 (was 0 )
register write 46 => 1100011 (was 0 )
register write 47 => 1110010 (was 0 )
register write 48 => 1111001 (was 0 )
register write 49 => 1110000 (was 0 )
register write 4a => 1110100 (was 0 )
register write 4b => 1001011 (was 0 )
register write 4c => 1100101 (was 0 )
register write 4d => 1111001 (was 0 )
register write 5a => 1010101 (was 1010101 )
register write 5c => 1110000 (was 1110000 )
register write 6f => 110000 (was 0 )
all configured 44
register read 27 => 10000000
----------------------------------------------RFM69 Ready----------------------------------------------
register read 1 => 100
Original Mode detected 4
register read 1 => 100
mode detected 4
register write 1 => 100 (was 100 )
switched to standby mode
register read 27 => 10000000
register write 25 => 0 (was 1000000 )
Going to transfer <Buffer 80 0e 11 64 40 48 65 6c 6c 6f 20 57 6f 72 6c 64>
transferred <Buffer 80 0e 11 64 40 48 65 6c 6c 6f 20 57 6f 72 6c 64> and got <Buffer 00 00 0e 0e 0e 0e 0e 0e 0e 0e 0e 0e 0e 0e 0e 0e>
register read 1 => 100
mode detected 4
register write 1 => 1100 (was 100 )
switched to transmit mode
register write 5a => 1011101 (was 1010101 )
register write 5c => 1111100 (was 1110000 )
transmit initiated
send timed out <Buffer 80 0e 11 64 40 48 65 6c 6c 6f 20 57 6f 72 6c 64> <Buffer 00 00 0e 0e 0e 0e 0e 0e 0e 0e 0e 0e 0e 0e 0e 0e>
Error sending to mote [Error: Send timed out]
register read 1 => 1100
mode detected 12
register write 1 => 100 (was 1100 )
Reset to Original Mode 4
sent to mote <Buffer 00 0c>
[debug] sent to mote <Buffer 00 0c>

Can you @losttime or anyone else help me understand what I'm doing wrong? Thanks.

oschade commented 8 years ago

Same issue on Banana Pi with Node 4.4.7. I'm able to receive but not to send data.

Same Error: sent to mote <Buffer 00 0c>

JojoS62 commented 7 years ago

Hello, is there still some activity here? I've got the same issue on RaspberryPi 3 with Node 7.2. Receiving works, but sending reports a timeout error. Has sending ever worked? I've tried only the LowPowerLab profile, not the default yet.

losttime commented 7 years ago

I'll try to submit an update in the next day or two. I've had sending working for a few months. It's mostly stable, but can get locked up from time to time. I'd welcome a pull-request to make it more reliable.

JojoS62 commented 7 years ago

thanks! I have nearly no experience in JS, so the code is hard to read for me... So what I checked today:

So if your version is working better now I would like to test it also.

losttime commented 7 years ago

I've updated the repo. I'll have to look into code implementation later when I have more time to remind myself how implementation details may have changed.

I use the low power lab profile exclusively, so that should be the most reliable.

JojoS62 commented 7 years ago

Ok, I have tried the updated version, but I still get the timeout error message. The send function waits for a packet sent interrupt, but the int is not enabled for the send. So I enabled the setInterrupt(true) in the init.js for the send function. Now I get the packet sent message, but I run into packet re-transmissions five times until the re-transmit error. So there must be something more in the program flow for the send acknowledge.

JojoS62 commented 7 years ago

So the sending works, but the javascript interrupt service is slow. From start send to clear int it takes about 4 ms, my µC is sending the ack faster and so it gets lost many times. I've tried another project now with a driver written in C, there the same response takes 200 µs (on my microcontroller LPC812 @30 MHz it takes 100 µs).

losttime commented 7 years ago

@JojoS62 That's good information. I'll do a little bit of work to see if I can speed up the library's ability to quickly get back to listening mode.

What is on the remote end that is sending back the ACK so quickly? Is that the LPC812? And am I right to understand that the ACK should ideally be received by ~ 100µs?

losttime commented 7 years ago

@PIPOKID After looking into this more (sorry for the long delay), it looks like you need to enable listening in order for the library to register the ACK coming from the remote end, otherwise the send is considered timed out.

The sample code you provided has the listen function commented out ~ line 22.

I'll make a note to remove the need to enable listening in a future update, but for the time being it's required.

JojoS62 commented 7 years ago

about the ACK response time: I have not seen something like a spec for the protocol with the original RFM lib, so I would say it depends on your nodes. I think the faster the response the better, but if some clients need some more time switching form transmit to receive you will run into re-transmits when the ACK comes to fast. For a simple sensor/actor node it will be no issue to wait a few milliseconds before sending the ACK. I digged also deeper into the original lib because I use a fork for the Cortex-M MCU instead of the ATMega. There I've seen also that handling the ACK is not clean, the canSend() always causes a state change in the first call and is then called again. There was some discussion in 2014 in the LPL forum, but Felix did not accept the PR. This makes the reply also slower as it could be and more worse, it clears the received data so that you have to handle or copy the received data before calling the sendACK. About your JS code: as far as I understood, there is a list of listeners for the interrupt. Is there a use case where multiple listeneres make sense? Otherwise simplifying this IRQ handler could make it faster? And when I played with the module, calling setInterrupt(true) more than one time results also in registering and calling the handler multiple times. Now I'm using this piGateway from https://github.com/abouillot/HomeAutomation on my Raspberry. This gateway is written in C what is easier to understand for me. The messages are sent to MQTT and so also available in the JS world.

NetHans commented 5 years ago

Hi, is there a working library available now?