LoRa communication

Hello everyone,

I’m working on a project involving half-duplex LoRa communication between a Raspberry Pi and an Arduino Nano 33 IoT using RFM9x modules. My goal is to send a command from the Raspberry Pi to the Arduino, which will then switch to a mode where it sends data back to the Raspberry Pi. but im encountering an issue shown in the image.
if there is anything i can fix please let me know thank you

Project Details:

  1. Hardware Setup:
  • Arduino Nano 33 IoT with LoRa module (RFM9x).
  • Raspberry Pi with LoRa module (RFM9x).
  • Connections:
    • Arduino Nano 33 IoT: CS pin - 4, Reset pin - 2, IRQ pin - 3.
    • Raspberry Pi: CS - CE1, Reset - D25.
  1. Objective:
  • Raspberry Pi: Send a command ("SEND_DATA") to the Arduino.
  • Arduino: Receive the command and switch to send mode to transmit data back to the Raspberry Pi.
  • Half-Duplex Communication: Ensure the devices switch between sending and receiving modes correctly.
#include <SPI.h>
#include <LoRa.h>

const int csPin = 4;          // LoRa radio chip select
const int resetPin = 2;       // LoRa radio reset
const int irqPin = 3;         // change for your board; must be a hardware interrupt pin

byte msgCount = 0;            // count of outgoing messages
byte localAddress = 0xAB;     // address of this device
byte destination = 0xBA;      // destination to send to

bool sendMode = false;        // flag to indicate send mode
long sendModeStart = 0;       // timestamp for send mode start
int sendModeDuration = 5000;  // send mode duration in milliseconds

void setup() {
  Serial.begin(9600);                   // initialize serial
  while (!Serial);

  Serial.println("LoRa Duplex");

  pinMode(resetPin, OUTPUT);
  digitalWrite(resetPin, HIGH);

  // override the default CS, reset, and IRQ pins (optional)
  LoRa.setPins(csPin, resetPin, irqPin); // set CS, reset, IRQ pin

  if (!LoRa.begin(915E6)) {              // initialize radio at 915 MHz
    Serial.println("LoRa init failed. Check your connections.");
    while (true);                        // if failed, do nothing
  }

  LoRa.onReceive(onReceive);             // register the receive callback
  LoRa.receive();                        // go into receive mode

  Serial.println("LoRa init succeeded.");
}

void loop() {
  if (sendMode && (millis() - sendModeStart > sendModeDuration)) {
    sendMode = false;
    LoRa.receive();                      // go back into receive mode
    Serial.println("Switched back to receive mode after timeout.");
  }

  if (sendMode) {
    String message = "Hello from Arduino to 0xBA!"; // send a message
    sendMessage(message);
    Serial.println("Sending " + message);

    // Immediately switch back to receive mode after sending
    LoRa.receive();
    sendMode = false;
    Serial.println("Switched back to receive mode after sending message.");
  }
}

void sendMessage(String outgoing) {
  LoRa.beginPacket();                    // start packet
  LoRa.write(destination);               // add destination address
  LoRa.write(localAddress);              // add sender address
  LoRa.write(msgCount);                  // add message ID
  LoRa.write(outgoing.length());         // add payload length
  LoRa.print(outgoing);                  // add payload
  LoRa.endPacket();                      // finish packet and send it
  msgCount++;                            // increment message ID

  // Ensure the LoRa module is switched back to receive mode
  LoRa.receive();
}

void onReceive(int packetSize) {
  if (packetSize == 0) return;  // if there's no packet, return

  // read packet header bytes:
  int recipient = LoRa.read();  // recipient address
  byte sender = LoRa.read();    // sender address
  byte incomingMsgId = LoRa.read();  // incoming msg ID
  byte incomingLength = LoRa.read();  // incoming msg length

  // print header for debugging
  Serial.print("Recipient: ");
  Serial.println(recipient, HEX);
  Serial.print("Sender: ");
  Serial.println(sender, HEX);
  Serial.print("Message ID: ");
  Serial.println(incomingMsgId, HEX);
  Serial.print("Payload length: ");
  Serial.println(incomingLength, HEX);

  String incoming = "";
  while (LoRa.available()) {
    char receivedChar = (char)LoRa.read();
    Serial.print("Received char: ");
    Serial.println(receivedChar, HEX);  // Print each received character
    incoming += receivedChar;
  }

  // print the received message and its bytes for debugging
  Serial.print("Received message: ");
  Serial.println(incoming);
  Serial.print("Received bytes: ");
  for (int i = 0; i < incoming.length(); i++) {
    Serial.print((uint8_t)incoming[i], HEX);  // Print as hexadecimal values
    Serial.print(" ");
  }
  Serial.println();

  // Check if the received message length matches the expected length
  if (incomingLength != incoming.length()) {
    Serial.println("error: message length does not match length");
    Serial.print("Expected length: ");
    Serial.println(incomingLength);
    Serial.print("Actual length: ");
    Serial.println(incoming.length());
    return;  // skip rest of function
  }

  // if the recipient isn't this device or broadcast,
  if (recipient != localAddress && recipient != 0xFF) {
    Serial.println("This message is not for me.");
    return;  // skip rest of function
  }

  // handle the received command to switch modes
  if (incoming == "245") {
    sendMode = true;
    sendModeStart = millis();
    Serial.println("Switched to send mode.");
  } else if (incoming == "246") {
    sendMode = false;
    LoRa.receive();  // go back into receive mode
    Serial.println("Switched to receive mode.");
  } else {
    Serial.println("Unrecognized command. Staying in current mode.");
  }

  // send acknowledgment
  sendMessage("ACK");
}
import time
import board
import busio
import digitalio
import adafruit_rfm9x

# Define radio parameters
RADIO_FREQ_MHZ = 915.0  # Frequency of the radio in MHz. 868.0 MHz in Europe, 915.0 MHz in North America.
CS = digitalio.DigitalInOut(board.CE1)
RESET = digitalio.DigitalInOut(board.D25)

# Initialize SPI bus
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)

# Initialize RFM9x radio
rfm9x = adafruit_rfm9x.RFM9x(spi, CS, RESET, RADIO_FREQ_MHZ)

msg_count = 0

def send_command(command):
    global msg_count
    destination = 0xAB  # Arduino address
    sender = 0xBB  # Raspberry Pi address
    payload_length = 1  # Fixed payload length for simplicity
    command_bytes = bytes([destination, sender, msg_count, payload_length, command])

    print(f"Command bytes: {command_bytes}")

    ack_received = False
    while not ack_received:
        rfm9x.send(command_bytes)
        print(f"Sent command to 0x{destination:X}: {command}")

        # Switch to receive mode and wait for acknowledgment
        start_time = time.time()
        print("Switching to receive mode...")
        while time.time() - start_time < 2:  # Receive for 2 seconds
            packet = rfm9x.receive(with_header=True)
            if packet is not None:
                print(f"Received raw packet: {packet}")
                recipient = packet[0]
                ack_sender = packet[1]
                msg_id = packet[2]
                length = packet[3]
                message = packet[4:].decode('utf-8', errors='ignore')
                print(f"Recipient: 0x{recipient:X}, Sender: 0x{ack_sender:X}, Msg ID: {msg_id}, Length: {length}, Message: {message}")
                if recipient == sender and message == "ACK":
                    print("Acknowledgment received")
                    ack_received = True
                    break
        time.sleep(1)

    msg_count += 1

if __name__ == "__main__":
    while True:
        send_command(245)  # Command Arduino to read its address
        time.sleep(10)  # Wait for some time before sending the next command

As your topic does not relate directly to the installation or operation of the IDE it has been moved to the Programming Questions category of the forum

using different host microcontrollers and libraries can cause problems
for a start make sure the LoRa parameters of transmitter and receiver are identical

Ive been trying to find a compatible library but ive been unsuccessful. There are compatible libraries for the raspberry pi pico but non for the regular pi 4

Really?

A search for "raspberry pi lora RFM9x" turned up this as the very first hit, among others. There is nothing in the link that suggests RPi4 won't work.

I understand that but there doesn't seems to be anything about half duplex from arduino to raspberry pi 4. Most of the examples are thru pi pico and arduino. I think my major issue is to rule out that these libraries are compatible or not and then i can look into if there is any hardware issues.

Hi,
The Mysensors library support RFM95, i suppose its in LoRa mode and work both on linux & arduino/esp/...
If i understand, the receiver get the good message, if yes, it eliminates most of problem with RF.

What i see :

  • The message ID stay 0, make some increment to be sure there is no bug in your sender
  • The payload part inside the message is useless. I suppose that your LoRa is in basic configuration, which mean it call onreceive only if payload + CRC are good.
  • "int Recipient = Lora.read()" but its byte.
  • PacketSize is know, its param of onReceive
  • You should call LoRa.available() before LoRa.read() ? I think it check the buffer. Need the exact library.

LoRa is half duplex, which means that only one radio at a time can be talking (transmitting) on a channel.

LoRa just one method of communication between radio modules, and if the modules are used properly, the type of MCU driving the radio is irrelevant.

However, code and libraries that you download for different processors make different default choices for configuring the radios, so unless you are extremely careful, you are very likely to have trouble establishing communications between different MCU setups, especially using different programming languages.

There is nothing special about the Raspberry Pi 4, so I recommend to try the Adafruit tutorial.

checked LoRa P2P communication between a RPi 3B+ with a Dragino_LoRa_GPS_HAT and a Adafruit Feather 32u4 LoRa - both use RFM95 LoRa radio modules - communicated OK

RPi transmitter C code

/*******************************************************************************
 *
 * Copyright (c) 2018 Dragino
 *
 * http://www.dragino.com
 *
 *******************************************************************************/

#include <string>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/time.h>
#include <signal.h>
#include <stdlib.h>

#include <sys/ioctl.h>

#include <wiringPi.h>
#include <wiringPiSPI.h>


// #############################################
// #############################################

#define REG_FIFO                    0x00
#define REG_OPMODE                  0x01
#define REG_FIFO_ADDR_PTR           0x0D
#define REG_FIFO_TX_BASE_AD         0x0E
#define REG_FIFO_RX_BASE_AD         0x0F
#define REG_RX_NB_BYTES             0x13
#define REG_FIFO_RX_CURRENT_ADDR    0x10
#define REG_IRQ_FLAGS               0x12
#define REG_DIO_MAPPING_1           0x40
#define REG_DIO_MAPPING_2           0x41
#define REG_MODEM_CONFIG            0x1D
#define REG_MODEM_CONFIG2           0x1E
#define REG_MODEM_CONFIG3           0x26
#define REG_SYMB_TIMEOUT_LSB  		0x1F
#define REG_PKT_SNR_VALUE			0x19
#define REG_PAYLOAD_LENGTH          0x22
#define REG_IRQ_FLAGS_MASK          0x11
#define REG_MAX_PAYLOAD_LENGTH 		0x23
#define REG_HOP_PERIOD              0x24
#define REG_SYNC_WORD				0x39
#define REG_VERSION	  				0x42

#define PAYLOAD_LENGTH              0x40

// LOW NOISE AMPLIFIER
#define REG_LNA                     0x0C
#define LNA_MAX_GAIN                0x23
#define LNA_OFF_GAIN                0x00
#define LNA_LOW_GAIN		    	0x20

#define RegDioMapping1                             0x40 // common
#define RegDioMapping2                             0x41 // common

#define RegPaConfig                                0x09 // common
#define RegPaRamp                                  0x0A // common
#define RegPaDac                                   0x5A // common

#define SX72_MC2_FSK                0x00
#define SX72_MC2_SF7                0x70
#define SX72_MC2_SF8                0x80
#define SX72_MC2_SF9                0x90
#define SX72_MC2_SF10               0xA0
#define SX72_MC2_SF11               0xB0
#define SX72_MC2_SF12               0xC0

#define SX72_MC1_LOW_DATA_RATE_OPTIMIZE  0x01 // mandated for SF11 and SF12

// sx1276 RegModemConfig1
#define SX1276_MC1_BW_125                0x70
#define SX1276_MC1_BW_250                0x80
#define SX1276_MC1_BW_500                0x90
#define SX1276_MC1_CR_4_5            0x02
#define SX1276_MC1_CR_4_6            0x04
#define SX1276_MC1_CR_4_7            0x06
#define SX1276_MC1_CR_4_8            0x08

#define SX1276_MC1_IMPLICIT_HEADER_MODE_ON    0x01

// sx1276 RegModemConfig2
#define SX1276_MC2_RX_PAYLOAD_CRCON        0x04

// sx1276 RegModemConfig3
#define SX1276_MC3_LOW_DATA_RATE_OPTIMIZE  0x08
#define SX1276_MC3_AGCAUTO                 0x04

// preamble for lora networks (nibbles swapped)
#define LORA_MAC_PREAMBLE                  0x34

#define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG1 0x0A
#ifdef LMIC_SX1276
#define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2 0x70
#elif LMIC_SX1272
#define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2 0x74
#endif

// FRF
#define        REG_FRF_MSB              0x06
#define        REG_FRF_MID              0x07
#define        REG_FRF_LSB              0x08

#define        FRF_MSB                  0xD9 // 868.1 Mhz
#define        FRF_MID                  0x06
#define        FRF_LSB                  0x66

// ----------------------------------------
// Constants for radio registers
#define OPMODE_LORA      0x80
#define OPMODE_MASK      0x07
#define OPMODE_SLEEP     0x00
#define OPMODE_STANDBY   0x01
#define OPMODE_FSTX      0x02
#define OPMODE_TX        0x03
#define OPMODE_FSRX      0x04
#define OPMODE_RX        0x05
#define OPMODE_RX_SINGLE 0x06
#define OPMODE_CAD       0x07

// ----------------------------------------
// Bits masking the corresponding IRQs from the radio
#define IRQ_LORA_RXTOUT_MASK 0x80
#define IRQ_LORA_RXDONE_MASK 0x40
#define IRQ_LORA_CRCERR_MASK 0x20
#define IRQ_LORA_HEADER_MASK 0x10
#define IRQ_LORA_TXDONE_MASK 0x08
#define IRQ_LORA_CDDONE_MASK 0x04
#define IRQ_LORA_FHSSCH_MASK 0x02
#define IRQ_LORA_CDDETD_MASK 0x01

// DIO function mappings                D0D1D2D3
#define MAP_DIO0_LORA_RXDONE   0x00  // 00------
#define MAP_DIO0_LORA_TXDONE   0x40  // 01------
#define MAP_DIO1_LORA_RXTOUT   0x00  // --00----
#define MAP_DIO1_LORA_NOP      0x30  // --11----
#define MAP_DIO2_LORA_NOP      0xC0  // ----11--

// #############################################
// #############################################
//
typedef bool boolean;
typedef unsigned char byte;

static const int CHANNEL = 0;

char message[256];

bool sx1272 = true;

byte receivedbytes;

enum sf_t { SF7=7, SF8, SF9, SF10, SF11, SF12 };

/*******************************************************************************
 *
 * Configure these values!
 *
 *******************************************************************************/

// SX1272 - Raspberry connections
int ssPin = 6;
int dio0  = 7;
int RST   = 0;

// Set spreading factor (SF7 - SF12)
sf_t sf = SF7;

// Set center frequency
uint32_t  freq = 868100000; // in Mhz! (868.1)

byte hello[32] = "HELLO";

void die(const char *s)
{
    perror(s);
    exit(1);
}

void selectreceiver()
{
    digitalWrite(ssPin, LOW);
}

void unselectreceiver()
{
    digitalWrite(ssPin, HIGH);
}

byte readReg(byte addr)
{
    unsigned char spibuf[2];

    selectreceiver();
    spibuf[0] = addr & 0x7F;
    spibuf[1] = 0x00;
    wiringPiSPIDataRW(CHANNEL, spibuf, 2);
    unselectreceiver();

    return spibuf[1];
}

void writeReg(byte addr, byte value)
{
    unsigned char spibuf[2];

    spibuf[0] = addr | 0x80;
    spibuf[1] = value;
    selectreceiver();
    wiringPiSPIDataRW(CHANNEL, spibuf, 2);

    unselectreceiver();
}

static void opmode (uint8_t mode) {
    writeReg(REG_OPMODE, (readReg(REG_OPMODE) & ~OPMODE_MASK) | mode);
}

static void opmodeLora() {
    uint8_t u = OPMODE_LORA;
    if (sx1272 == false)
        u |= 0x8;   // TBD: sx1276 high freq
    writeReg(REG_OPMODE, u);
}


void SetupLoRa()
{
    
    digitalWrite(RST, HIGH);
    delay(100);
    digitalWrite(RST, LOW);
    delay(100);

    byte version = readReg(REG_VERSION);

    if (version == 0x22) {
        // sx1272
        printf("SX1272 detected, starting.\n");
        sx1272 = true;
    } else {
        // sx1276?
        digitalWrite(RST, LOW);
        delay(100);
        digitalWrite(RST, HIGH);
        delay(100);
        version = readReg(REG_VERSION);
        if (version == 0x12) {
            // sx1276
            printf("SX1276 detected, starting.\n");
            sx1272 = false;
        } else {
            printf("Unrecognized transceiver.\n");
            //printf("Version: 0x%x\n",version);
            exit(1);
        }
    }

    opmode(OPMODE_SLEEP);

    // set frequency
    uint64_t frf = ((uint64_t)freq << 19) / 32000000;
    writeReg(REG_FRF_MSB, (uint8_t)(frf>>16) );
    writeReg(REG_FRF_MID, (uint8_t)(frf>> 8) );
    writeReg(REG_FRF_LSB, (uint8_t)(frf>> 0) );

    writeReg(REG_SYNC_WORD, 0x34); // LoRaWAN public sync word

    if (sx1272) {
        if (sf == SF11 || sf == SF12) {
            writeReg(REG_MODEM_CONFIG,0x0B);
        } else {
            writeReg(REG_MODEM_CONFIG,0x0A);
        }
        writeReg(REG_MODEM_CONFIG2,(sf<<4) | 0x04);
    } else {
        if (sf == SF11 || sf == SF12) {
            writeReg(REG_MODEM_CONFIG3,0x0C);
        } else {
            writeReg(REG_MODEM_CONFIG3,0x04);
        }
        writeReg(REG_MODEM_CONFIG,0x72);
        writeReg(REG_MODEM_CONFIG2,(sf<<4) | 0x04);
    }

    if (sf == SF10 || sf == SF11 || sf == SF12) {
        writeReg(REG_SYMB_TIMEOUT_LSB,0x05);
    } else {
        writeReg(REG_SYMB_TIMEOUT_LSB,0x08);
    }
    writeReg(REG_MAX_PAYLOAD_LENGTH,0x80);
    writeReg(REG_PAYLOAD_LENGTH,PAYLOAD_LENGTH);
    writeReg(REG_HOP_PERIOD,0xFF);
    writeReg(REG_FIFO_ADDR_PTR, readReg(REG_FIFO_RX_BASE_AD));

    writeReg(REG_LNA, LNA_MAX_GAIN);

}

boolean receive(char *payload) {
    // clear rxDone
    writeReg(REG_IRQ_FLAGS, 0x40);

    int irqflags = readReg(REG_IRQ_FLAGS);

    //  payload crc: 0x20
    if((irqflags & 0x20) == 0x20)
    {
        printf("CRC error\n");
        writeReg(REG_IRQ_FLAGS, 0x20);
        return false;
    } else {

        byte currentAddr = readReg(REG_FIFO_RX_CURRENT_ADDR);
        byte receivedCount = readReg(REG_RX_NB_BYTES);
        receivedbytes = receivedCount;

        writeReg(REG_FIFO_ADDR_PTR, currentAddr);

        for(int i = 0; i < receivedCount; i++)
        {
            payload[i] = (char)readReg(REG_FIFO);
        }
    }
    return true;
}

void receivepacket() {

    long int SNR;
    int rssicorr;

    if(digitalRead(dio0) == 1)
    {
        if(receive(message)) {
            byte value = readReg(REG_PKT_SNR_VALUE);
            if( value & 0x80 ) // The SNR sign bit is 1
            {
                // Invert and divide by 4
                value = ( ( ~value + 1 ) & 0xFF ) >> 2;
                SNR = -value;
            }
            else
            {
                // Divide by 4
                SNR = ( value & 0xFF ) >> 2;
            }
            
            if (sx1272) {
                rssicorr = 139;
            } else {
                rssicorr = 157;
            }

            printf("Packet RSSI: %d, ", readReg(0x1A)-rssicorr);
            printf("RSSI: %d, ", readReg(0x1B)-rssicorr);
            printf("SNR: %li, ", SNR);
            printf("Length: %i", (int)receivedbytes);
            printf("\n");
            printf("Payload: %s\n", message);

        } // received a message

    } // dio0=1
}

static void configPower (int8_t pw) {
    if (sx1272 == false) {
        // no boost used for now
        if(pw >= 17) {
            pw = 15;
        } else if(pw < 2) {
            pw = 2;
        }
        // check board type for BOOST pin
        writeReg(RegPaConfig, (uint8_t)(0x80|(pw&0xf)));
        writeReg(RegPaDac, readReg(RegPaDac)|0x4);

    } else {
        // set PA config (2-17 dBm using PA_BOOST)
        if(pw > 17) {
            pw = 17;
        } else if(pw < 2) {
            pw = 2;
        }
        writeReg(RegPaConfig, (uint8_t)(0x80|(pw-2)));
    }
}


static void writeBuf(byte addr, byte *value, byte len) {                                                       
    unsigned char spibuf[256];                                                                          
    spibuf[0] = addr | 0x80;                                                                            
    for (int i = 0; i < len; i++) {                                                                         
        spibuf[i + 1] = value[i];                                                                       
    }                                                                                                   
    selectreceiver();                                                                                   
    wiringPiSPIDataRW(CHANNEL, spibuf, len + 1);                                                        
    unselectreceiver();                                                                                 
}

void txlora(byte *frame, byte datalen) {

    // set the IRQ mapping DIO0=TxDone DIO1=NOP DIO2=NOP
    writeReg(RegDioMapping1, MAP_DIO0_LORA_TXDONE|MAP_DIO1_LORA_NOP|MAP_DIO2_LORA_NOP);
    // clear all radio IRQ flags
    writeReg(REG_IRQ_FLAGS, 0xFF);
    // mask all IRQs but TxDone
    writeReg(REG_IRQ_FLAGS_MASK, ~IRQ_LORA_TXDONE_MASK);

    // initialize the payload size and address pointers
    writeReg(REG_FIFO_TX_BASE_AD, 0x00);
    writeReg(REG_FIFO_ADDR_PTR, 0x00);
    writeReg(REG_PAYLOAD_LENGTH, datalen);

    // download buffer to the radio FIFO
    writeBuf(REG_FIFO, frame, datalen);
    // now we actually start the transmission
    opmode(OPMODE_TX);

    printf("send: %s\n", frame);
}

int main (int argc, char *argv[]) {

    if (argc < 2) {
        printf ("Usage: argv[0] sender|rec [message]\n");
        exit(1);
    }

    wiringPiSetup () ;
    pinMode(ssPin, OUTPUT);
    pinMode(dio0, INPUT);
    pinMode(RST, OUTPUT);

    wiringPiSPISetup(CHANNEL, 500000);

    SetupLoRa();

    if (!strcmp("sender", argv[1])) {
        opmodeLora();
        // enter standby mode (required for FIFO loading))
        opmode(OPMODE_STANDBY);

        writeReg(RegPaRamp, (readReg(RegPaRamp) & 0xF0) | 0x08); // set PA ramp-up time 50 uSec

        configPower(23);

        printf("Send packets at SF%i on %.6lf Mhz.\n", sf,(double)freq/1000000);
        printf("------------------\n");

        if (argc > 2)
            strncpy((char *)hello, argv[2], sizeof(hello));

        while(1) {
            static int test=0;
            sprintf((char *)hello,"hello %d", test++);
            txlora(hello, strlen((char *)hello));
            delay(5000);
        }
    } else {

        // radio init
        opmodeLora();
        opmode(OPMODE_STANDBY);
        opmode(OPMODE_RX);
        printf("Listening at SF%i on %.6lf Mhz.\n", sf,(double)freq/1000000);
        printf("------------------\n");
        while(1) {
            receivepacket(); 
            delay(1);
        }

    }

    return (0);
}

Feather 32u4 LoRa receiver code

#include <SPI.h>
#include <LoRa.h>
void setup() {
  Serial.begin(115200);
  while (!Serial)
    ;
  Serial.println("LoRa Receiver");
  // void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN);
  LoRa.setPins(8, 4, 7);  // for Lora 32u4
  if (!LoRa.begin(868100000)) {
    Serial.println("Starting LoRa failed!");
    while (1)
      ;
  }
  LoRa.setSpreadingFactor(7);
}
void loop() {
  // try to parse packet
  int packetSize = LoRa.parsePacket();
  if (packetSize) {
    // received a packet
    Serial.print("Received packet '");
    // read packet
    while (LoRa.available()) {
      Serial.print((char)LoRa.read());
    }
    // print RSSI of packet
    Serial.print("' with RSSI ");
    Serial.println(LoRa.packetRssi());
  }
}

RPi LoRa transmitter console output

pi@raspberrypi:~/rpi-lora-tranceiver-master/dragino_lora_app $ make
g++ -c -Wall main.c
g++ main.o  -lwiringPi -o dragino_lora_app

pi@raspberrypi:~/rpi-lora-tranceiver-master/dragino_lora_app $ ./dragino_lora_app sender
SX1276 detected, starting.
Send packets at SF7 on 868.100000 Mhz.
------------------
send: hello 0
send: hello 1
send: hello 2
send: hello 3
send: hello 4
send: hello 5
send: hello 6
send: hello 7
send: hello 8
send: hello 9
send: hello 10
send: hello 11
send: hello 12
send: hello 13
send: hello 14

Feather 32u4 LoRa receiver serial monitor output

LoRa Receiver
Received packet 'hello 0' with RSSI -66
Received packet 'hello 1' with RSSI -68
Received packet 'hello 2' with RSSI -66
Received packet 'hello 3' with RSSI -68
Received packet 'hello 4' with RSSI -65
Received packet 'hello 5' with RSSI -68
Received packet 'hello 6' with RSSI -66
Received packet 'hello 7' with RSSI -68
Received packet 'hello 8' with RSSI -67
Received packet 'hello 9' with RSSI -68
Received packet 'hello 10' with RSSI -64
Received packet 'hello 11' with RSSI -64
Received packet 'hello 12' with RSSI -64
Received packet 'hello 13' with RSSI -64
Received packet 'hello 14' with RSSI -64

I was unable to get your Python code to compile - it displays

pi@raspberrypi:~/python $ python3 LoRa_1.py
Traceback (most recent call last):
  File "LoRa_1.py", line 5, in <module>
    import adafruit_rfm9x
  File "/home/pi/.local/lib/python3.7/site-packages/adafruit_rfm9x.py", line 34, in <module>
    from circuitpython_typing import WriteableBuffer, ReadableBuffer
  File "/home/pi/.local/lib/python3.7/site-packages/circuitpython_typing/__init__.py", line 79
    def read(self, count: Optional[int] = None, /) -> Optional[bytes]:
                                                ^
SyntaxError: invalid syntax

I only use Python when I absolutely have to so have no idea what the problem is

problem identified by Adafruit Forum post as requiring Python 3

pip3 install adafruit-circuitpython-typing==1.10.1

simple Python program for RPi sending LoRa packet and receiving reply

import time
import board
import busio
import digitalio
import adafruit_rfm9x

# Define radio parameters
RADIO_FREQ_MHZ = 868.0  # Frequency of the radio in MHz. 868.0 MHz in Europe, 915.0 MHz in North America.
CS = digitalio.DigitalInOut(board.D25) 
RESET = digitalio.DigitalInOut(board.D17)

# Initialize SPI bus
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
#spi = busio.SPI(board.D11, MOSI=board.D10, MISO=board.D9)
# Initialize RFM9x radio
rfm9x = adafruit_rfm9x.RFM9x(spi, CS, RESET, RADIO_FREQ_MHZ)
count=0
while True:
        text='Hello world '+ str(count)
        rfm9x.send(str.encode(text))
        count=count+1
        packet = rfm9x.receive()  # Wait for a packet to be received (up to 0.5 seconds)
        if packet is not None:
            packet_text = str(packet, 'ascii')
            print('Received: {0}'.format(packet_text))
        time.sleep(5)  # Wait for some time before sending the next command

Adafruit Feather 23u4 LoRa board using RH_RF95 library

// Feather9x_RX
// -*- mode: C++ -*-
// Example sketch showing how to create a simple messaging client (receiver)
// with the RH_RF95 class. RH_RF95 class does not provide for addressing or
// reliability, so you should only use RH_RF95 if you do not need the higher
// level messaging abilities.
// It is designed to work with the other example Feather9x_TX

#include <SPI.h>
#include <RH_RF95.h>

/* for feather32u4 */
#define RFM95_CS 8
#define RFM95_RST 4
#define RFM95_INT 7

/* for feather m0  
#define RFM95_CS 8
#define RFM95_RST 4
#define RFM95_INT 3
*/

/* for shield 
#define RFM95_CS 10
#define RFM95_RST 9
#define RFM95_INT 2
*/


/* for ESP w/featherwing 
#define RFM95_CS  2    // "E"
#define RFM95_RST 16   // "D"
#define RFM95_INT 15   // "B"
*/

/* Feather 32u4 w/wing
#define RFM95_RST     11   // "A"
#define RFM95_CS      10   // "B"
#define RFM95_INT     2    // "SDA" (only SDA/SCL/RX/TX have IRQ!)
*/

/* Feather m0 w/wing 
#define RFM95_RST     11   // "A"
#define RFM95_CS      10   // "B"
#define RFM95_INT     6    // "D"
*/

/* Teensy 3.x w/wing 
#define RFM95_RST     9   // "A"
#define RFM95_CS      10   // "B"
#define RFM95_INT     4    // "C"
*/

// Change to 434.0 or other frequency, must match RX's freq!
#define RF95_FREQ 868.0

// Singleton instance of the radio driver
RH_RF95 rf95(RFM95_CS, RFM95_INT);

// Blinky on receipt
#define LED 13

void setup() 
{
  pinMode(LED, OUTPUT);     
  pinMode(RFM95_RST, OUTPUT);
  digitalWrite(RFM95_RST, HIGH);

  while (!Serial);
  Serial.begin(115200);
  delay(100);

  Serial.println("Feather LoRa RX Test!");
  
  // manual reset
  digitalWrite(RFM95_RST, LOW);
  delay(10);
  digitalWrite(RFM95_RST, HIGH);
  delay(10);

  while (!rf95.init()) {
    Serial.println("LoRa radio init failed");
    while (1);
  }
  Serial.println("LoRa radio init OK!");

  // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM
  if (!rf95.setFrequency(RF95_FREQ)) {
    Serial.println("setFrequency failed");
    while (1);
  }
  Serial.print("Set Freq to: "); Serial.println(RF95_FREQ);

  // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on

  // The default transmitter power is 13dBm, using PA_BOOST.
  // If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then 
  // you can set transmitter powers from 5 to 23 dBm:
  rf95.setTxPower(23, false);
}

void loop()
{
  if (rf95.available())
  {
    // Should be a message for us now   
    uint8_t buf[RH_RF95_MAX_MESSAGE_LEN]={0};
    uint8_t len = sizeof(buf);
    
    if (rf95.recv(buf, &len))
    {
      digitalWrite(LED, HIGH);
      RH_RF95::printBuffer("Received: ", buf, len);
      Serial.print("Got: ");
      Serial.print((char*)buf);
       Serial.print(" RSSI: ");
      Serial.println(rf95.lastRssi(), DEC);
      delay(10);
      // Send a reply
      delay(200); // may or may not be needed
      static int count=0;
      uint8_t data[50]={0};
      sprintf(data, "And hello back to you %d", count++);
      Serial.print("sending reply: ");
      Serial.println((char *)data);
      rf95.send(data, sizeof(data));
      rf95.waitPacketSent();
      digitalWrite(LED, LOW);
    }
    else
    {
      Serial.println("Receive failed");
    }
  }
}

RPi console displays

pi@raspberrypi:~/python $ python3 LoRa_3.py
Received: And hello back to you 0
Received: And hello back to you 1
Received: And hello back to you 2
Received: And hello back to you 3
Received: And hello back to you 4

Feather serial monitor displays

Feather LoRa RX Test!
LoRa radio init OK!
Set Freq to: 868.00
Received: 
48 65 6C 6C 6F 20 77 6F 72 6C 64 20 30 
Got: Hello world 0 RSSI: -68
sending reply: And hello back to you 0
Received: 
48 65 6C 6C 6F 20 77 6F 72 6C 64 20 31 
Got: Hello world 1 RSSI: -68
sending reply: And hello back to you 1
Received: 
48 65 6C 6C 6F 20 77 6F 72 6C 64 20 32 
Got: Hello world 2 RSSI: -68
sending reply: And hello back to you 2
Received: 
48 65 6C 6C 6F 20 77 6F 72 6C 64 20 33 
Got: Hello world 3 RSSI: -68
sending reply: And hello back to you 3