jgromes / RadioLib

Universal wireless communication library for embedded devices
https://jgromes.github.io/RadioLib/
MIT License
1.6k stars 400 forks source link

Radiolib <--> Radiohead is communication possible? #148

Closed EmilM256 closed 4 years ago

EmilM256 commented 4 years ago

Is there a known way for proper transmission between Radiolib and Radiohead? I use RFM95 modules. It seems to me that setting the same values for carrier frequency, bandwidth, spreading factor, coding rate, sync word, preamble length is not sufficient. I could not send or receive the package.

If there is a simple, proven method, I would like to know it. If no one has tried it, sorry about this post. Please close the topic.

I will change the library in my old projects to Radiolib :)

jgromes commented 4 years ago

I haven't tried it, but to answer the question in the title - I don't see any reason why it shouldn't be possible.

I'd suggest checking I/Q inversion, RadioLib leaves it at the default (non-inverted IQ). Next, check CRC configuration and header mode (implicit/explicit) are the same.

EmilM256 commented 4 years ago

I did two tests. The first is to start the receiver in the mode: int state = lora.scanChannel (); Result obtained:

[SX1278] Scanning channel for LoRa preamble ... channel is free!
[SX1278] Scanning channel for LoRa preamble ... detected preamble!
[SX1278] Scanning channel for LoRa preamble ... channel is free!

The second is to receive data without the CRC function: lora.setCRC (false);

SX1278[SX1278] Initializing ... success!
[SX1278] Starting to listen ... success!
[SX1278] Received packet!
[SX1278] Data:      ⸮⸮
[SX1278] RSSI:      -85.00 dBm
[SX1278] SNR:       9.75 dB
[SX1278] Frequency error:   -7591.69 Hz
[SX1278] Received packet!
[SX1278] Data:      ⸮⸮
[SX1278] RSSI:      -85.00 dBm
[SX1278] SNR:       9.75 dB
[SX1278] Frequency error:   -7658.80 Hz
[SX1278] Received packet!
[SX1278] Data:      ⸮⸮
[SX1278] RSSI:      -85.00 dBm
[SX1278] SNR:       9.75 dB
[SX1278] Frequency error:   -7658.80 Hz

The broadcasting system with the Radiohead library transmitted 8 characters. Different values of transmitted characters. The result has always been the same: [SX1278] Data: ⸮⸮ I don't know how to change I/Q inversion and header mode (implicit / explicit) ...

Stuck for now ...

jgromes commented 4 years ago

Briefly looking over the RadioHead source (in this repo: https://github.com/adafruit/RadioHead/blob/master/RH_RF95.cpp), it looks like the only implemented header mode is explicit, and there doesn't seem to be any changes to IQ setup, so that should be the same as RadioLib default.

I'd try receiving the data as binary array, not as String. I'm not sure what exactly is RadioHead transmitting (you haven't provided the source code for that), but if there's a null byte in the packet, it will terminate the string.

EmilM256 commented 4 years ago

Thanks for the hint. My next test was to read the byte array. It turned out that the RadioHead library sends 4 additional bytes at the beginning of the transmission: 255, 255, 0, 0. Zero, of course, ends the string, which is why I did not see my message. If I send a byte array from Radiolib that looks like this:

byte byteArr [] = {255, 255, 0, 0, 51, 50, 49, 32, 49, 32, 49, 0};
int state = lora.startTransmit (byteArr, 12);

RadioHead will read the message as: 51, 50, 49, 32, 49, 32, 49, 0 (i.e. 321 1 1, bytes 255, 255, 0, 0 are not taken into account). Transmission is possible and successful.

Which makes me happy, it also works with CRC checksum checking enabled (lora.setCRC (true);).

I modified the library example to show it. Here is the code result, the first transmission from RadioHead, the second from Radiolib:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 
[SX1278] Received packet!
[SX1278] Data:      ⸮ ⸮    3 2 1   1   1 
255 255 0 0 51 50 49 32 49 32 49 32 0 0 0
[SX1278] RSSI:      -82.00 dBm
[SX1278] SNR:       9.75 dB
[SX1278] Frequency error:   -7222.59 Hz
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 
[SX1278] Received packet!
[SX1278] Data:      H e l l o   W o r l d ! 
72 101 108 108 111 32 87 111 114 108 100 33 0 0 0
[SX1278] RSSI:      -40.00 dBm
[SX1278] SNR:       9.25 dB
[SX1278] Frequency error:   -6383.73 Hz

The modified example is below:

/*
   RadioLib SX127x Receive Example

   This example listens for LoRa transmissions using SX127x Lora modules.
   To successfully receive data, the following settings have to be the same
   on both transmitter and receiver:
    - carrier frequency
    - bandwidth
    - spreading factor
    - coding rate
    - sync word
    - preamble length

   Other modules from SX127x/RFM9x family can also be used.

   For full API reference, see the GitHub Pages
   https://jgromes.github.io/RadioLib/
*/

// include the library
#include <RadioLib.h>

// SX1278 has the following connections:
// NSS pin:   10
// DIO0 pin:  2
// RESET pin: 9
// DIO1 pin:  3
RFM95 lora = new Module(10, 2, 9, 3);

// or using RadioShield
// https://github.com/jgromes/RadioShield
//SX1278 lora = RadioShield.ModuleA;

void setup() {
  Serial.begin(9600);

  // initialize SX1278 with default settings
  Serial.print(F("[SX1278] Initializing ... "));
  // carrier frequency:           434.0 MHz
  // bandwidth:                   125.0 kHz
  // spreading factor:            9
  // coding rate:                 7
  // sync word:                   0x12
  // output power:                17 dBm
  // current limit:               100 mA
  // preamble length:             8 symbols
  // amplifier gain:              0 (automatic gain control)
  int state = lora.begin(868.0, 125.0, 7, 5, 0x12);
  lora.setCRC(true);
  if (state == ERR_NONE) {
    Serial.println(F("success!"));
  } else {
    Serial.print(F("failed, code "));
    Serial.println(state);
    while (true);
  }

  // set the function that will be called
  // when new packet is received
  lora.setDio0Action(setFlag);

  // start listening for LoRa packets
  Serial.print(F("[SX1278] Starting to listen ... "));
  state = lora.startReceive();
  if (state == ERR_NONE) {
    Serial.println(F("success!"));
  } else {
    Serial.print(F("failed, code "));
    Serial.println(state);
    while (true);
  }

  // if needed, 'listen' mode can be disabled by calling
  // any of the following methods:
  //
  // lora.standby()
  // lora.sleep()
  // lora.transmit();
  // lora.receive();
  // lora.readData();
  // lora.scanChannel();
}

// flag to indicate that a packet was received
volatile bool receivedFlag = false;

// disable interrupt when it's not needed
volatile bool enableInterrupt = true;

// this function is called when a complete packet
// is received by the module
// IMPORTANT: this function MUST be 'void' type
//            and MUST NOT have any arguments!
void setFlag(void) {
  // check if the interrupt is enabled
  if(!enableInterrupt) {
    return;
  }

  // we got a packet, set the flag
  receivedFlag = true;
}

void loop() {
  // check if the flag is set
  if(receivedFlag) {
    // disable the interrupt service routine while
    // processing the data
    enableInterrupt = false;

    // reset flag
    receivedFlag = false;

    // you can read received data as an Arduino String
    //String str;
    //int state = lora.readData(str);

    // you can also read received data as byte array
    ///*
      byte byteArr[15];
      int x;
      for (x=0; x < 15; x++){
        byteArr[x] = 1;
        Serial.print(x); Serial.print(" ");
      }
      Serial.println("");
      int state = lora.readData(byteArr, 15);
    //*/

    if (state == ERR_NONE) {
      // packet was successfully received
      Serial.println(F("[SX1278] Received packet!"));

      // print data of the packet
      Serial.print(F("[SX1278] Data:\t\t"));
      //Serial.println(str);
      Serial.write(byteArr[0]); Serial.print(" ");
      Serial.write(byteArr[1]); Serial.print(" ");
      Serial.write(byteArr[2]); Serial.print(" ");
      Serial.write(byteArr[3]); Serial.print(" ");
      Serial.write(byteArr[4]); Serial.print(" ");
      Serial.write(byteArr[5]); Serial.print(" ");
      Serial.write(byteArr[6]); Serial.print(" ");
      Serial.write(byteArr[7]); Serial.print(" ");
      Serial.write(byteArr[8]); Serial.print(" ");
      Serial.write(byteArr[9]); Serial.print(" ");
      Serial.write(byteArr[10]); Serial.print(" ");
      Serial.write(byteArr[11]); Serial.print(" ");
      Serial.write(byteArr[12]); Serial.print(" ");
      Serial.write(byteArr[13]); Serial.print(" ");
      Serial.write(byteArr[14]); Serial.println(" ");

      Serial.print(byteArr[0], DEC); Serial.print(" ");
      Serial.print(byteArr[1], DEC); Serial.print(" ");
      Serial.print(byteArr[2], DEC); Serial.print(" ");
      Serial.print(byteArr[3], DEC); Serial.print(" ");
      Serial.print(byteArr[4], DEC); Serial.print(" ");
      Serial.print(byteArr[5], DEC); Serial.print(" ");
      Serial.print(byteArr[6], DEC); Serial.print(" ");
      Serial.print(byteArr[7], DEC); Serial.print(" ");
      Serial.print(byteArr[8], DEC); Serial.print(" ");
      Serial.print(byteArr[9], DEC); Serial.print(" ");
      Serial.print(byteArr[10], DEC); Serial.print(" ");
      Serial.print(byteArr[11], DEC); Serial.print(" ");
      Serial.print(byteArr[12], DEC); Serial.print(" ");
      Serial.print(byteArr[13], DEC); Serial.print(" ");
      Serial.println(byteArr[14], DEC);

      // print RSSI (Received Signal Strength Indicator)
      Serial.print(F("[SX1278] RSSI:\t\t"));
      Serial.print(lora.getRSSI());
      Serial.println(F(" dBm"));

      // print SNR (Signal-to-Noise Ratio)
      Serial.print(F("[SX1278] SNR:\t\t"));
      Serial.print(lora.getSNR());
      Serial.println(F(" dB"));

      // print frequency error
      Serial.print(F("[SX1278] Frequency error:\t"));
      Serial.print(lora.getFrequencyError(true));
      Serial.println(F(" Hz"));
      //lora.getFrequencyError(bool autoCorrect = true);

    } else if (state == ERR_CRC_MISMATCH) {
      // packet was received, but is malformed
      Serial.println(F("[SX1278] CRC error!"));

    } else {
      // some other error occurred
      Serial.print(F("[SX1278] Failed, code "));
      Serial.println(state);

    }

    // put module back to listen mode
    lora.startReceive();

    // we're ready to receive more packets,
    // enable interrupt service routine
    enableInterrupt = true;
  }

}

I signed up, but it may be useful to someone. I don't know if RadioHead adds these 4 bytes for other radio modules ... I think the topic is finished. You could add to Radiolib, "RadioHead compatibility mode", but probably very few people would need it and it is not necessary.

Thank you for your help.

jgromes commented 4 years ago

Glad you have it working ;) This issue is probably enough to document that it is indeed possible.