StuartsProjects / SX12XX-LoRa

Library for SX12XX LoRa devices
315 stars 68 forks source link

Pkt Loss while doing Asynq TX and RX #66

Closed iottrends closed 8 months ago

iottrends commented 1 year ago

I am building a simple transceiver using ESP8266 and sx1280.

  1. Read 128 byte serial data from Uart and do a LT.transmitIRQ(rxData, TXPacketL, LORA_TX_TIMEOUT, TXpower, WAIT_TX))

  2. wait for Lora RX pkt using RXPacketL = LT.receiveIRQ(RXBUFFER, RXBUFFER_SIZE, LORA_RX_TIMEOUT, WAIT_RX);

  3. /*LORA RX & TX TIME OUT**/

    define LORA_RX_TIMEOUT 50 //50ms

    define LORA_TX_TIMEOUT 20 //20ms

  4. Write the Lora-Received pkt on uart, repeat the loop.

  5. Same code is running on 2 modules.

  6. The code works!!! , both Lora module are able to send and receive data.

  7. How ever I see a lot of pkt loss is happening.(50% loss)

  8. Looks like when LT.receiveIRQ is called in that window only the Lora RX pkts are received. is there a way to trigger a ISR when RX happens and I can do a simple rx_pkt copy to a queue and process it later.

StuartsProjects commented 1 year ago

Depending on the LoRa modem settings, its possible the 'packet loss' is being caused by the very short RX timeouts. If there is an RX timeout reported, then its can take some mS for RX to be ready again, and thus miss a packet. Try extending the timeouts.

The receiveIRQ and transmitIRQ functions are intended for use in applications where you dont have access to the DIO1 pin due to a shortage of available IO pins.

If you want to trigger an ISR you would need to write the code to call the ISR when DIO1 signals TX complete or RX complete.

iottrends commented 1 year ago

Thanks for responding.. DIO1 pin is available and connected to GPIO-4 on ESP8266. For Transmit operation we are good as for 128byte pkt , Lora transmit time is close to 5ms. However for RX path we want to use ISR? Is there any ISR specific function "LT.receive" function that can be used? or you can point us to the example code. Another query :Do we need to call setDioIrqParams in our setup function.

Regarding the pkt timeouts : they aren't happening as pkt rate is kind of high(60 pkts/sec; avg pkt=32 bytes) Also is it possible to do LT.readIrqStatus() to check for any received RX pkts and then retrive the rx_pkt

StuartsProjects commented 1 year ago

If you have DIO1 pin connected, then use the plain transmit() and receive() functions.

The IRQ functions are only intended to be used in the circumstance that DIO1 is not readable.

There no known problem with the IRQ routines causing packet loss, on the micros that examples have been published for. The IRQ routines were used for the ESP32 camera examples and operted at very high speed with very little packet loss. Its possible there is an issue specific to the ESP8266, but that microcontroller is not explicitly supported by the library or examples and I have never tested the library against it.

setDioIrqParams is carried out automatically as part of setupLoRa(), see example 103_LoRa_Transmitter_Detailed_Setup for full details of what setupLoRa() does.

There are no examples using interupts. and no libray code that supports them. The code in an ISR needs to be kept to an absolute minimum to prevent interfering with other running code. All you should really do in an ISR is to set a flag indicating packet received and then read this flag as part of loop(). Since DIO1 acts as a flag you can just read DIO1 in loop() to see if a packet has been received, no need for interrupts.

Also is it possible to do LT.readIrqStatus() to check for any received RX pkts and then retrive the rx_pkt

Of course, and that is what receiveIRQ() does already.

iottrends commented 1 year ago

After debugging further, I found this problem is more about half duplex synchronization. Since both the modules are transceivers. the pkt loss happens when both the transceivers, transmit the pkt at the same time. Any approach, you can suggest for half-duplex transmission.

StuartsProjects commented 1 year ago

There is no way that I am aware of keeping two devices synchronised in order to prevent on-air packet collisions.

You can avoid collisions by polling the othere devices for data.

iottrends commented 1 year ago

I am trying to use your function *uint8_t SX128XLT::receiveReliable(uint8_t rxbuffer, uint8_t size, uint16_t networkID, uint32_t rxtimeout, uint8_t wait )**

Here is my receive code... void rfReceive() { uint8_t p_rx_buf; /Start of Lora RX + UART TX*/ //WAIT_RX =1 RXPacketL = LT.receiveReliable(RXBUFFER, RXBUFFER_SIZE, NetworkID,LORA_RX_TIMEOUT, WAIT_RX); if (RXPacketL == 0) //if the LT.receive() function detects an error, RXpacketL == 0 { // led_Flash(15,50);// free wheeling } else { RXPacketL = LT.readRXPacketL(); RXPacketL = RXPacketL -4; if(RXBUFFER[0] == network_id) { p_rx_buf = RXBUFFER; p_rx_buf++; if(dbg == true) { Serial.println("recvd pkt, pkt len="); Serial.print(RXPacketL); printHex(RXBUFFER,RXPacketL); } Serial.write(p_rx_buf, (RXPacketL - 1)); memset(RXBUFFER,0x0, RXBUFFER_SIZE); RXPacketL =0; } } //}

But unable to receive the pkt However I have transmitReliable works... I tested it by calling LT.receive(). Below is my code for rftransmit() { lora_tx_timeout = get_lora_tx_time(len); // 4 bytes of networkID & CRC will be added. if(dbg == true) { Serial.println("Pkt time =" + String(lora_tx_timeout)); } //if (LT.transmitIRQ(rxData, TXPacketL, lora_tx_timeout, TXpower, WAIT_TX)) //return packet length sent if OK, otherwise 0 if transmit, timeout 10 seconds //if (LT.transmit(rxData, TXPacketL, lora_tx_timeout, TXpower, WAIT_TX)) if(LT.transmitReliable(rxData, TXPacketL, NetworkID, lora_tx_timeout, TXpower, WAIT_TX)) {
//led_Flash(2,150);// successful transmit if(dbg == true) { Serial.println("rfTransmit: Sucessful tx,pkt len:"); Serial.println(TXPacketL); } } else { //transmit packet returned 0, there was an error if(dbg == true) { Serial.println("rfTransmit: fail tx,pkt len:"); Serial.println(TXPacketL); } //led_Flash(2,50);//quick 2 flashes

ifdef SX128XDEBUG

    printHex(rxData, len);

endif

}
//TXPacketL = 0;

}

  1. How do I know the Reliable option is set ON... I assume I don't have to set any flags...

  2. Another query; In you receive function. if (!wait) { return 0; //not wait requested so no packet length to pass }

    while (!digitalRead(_RXDonePin)); //Wait for DIO1 to go high setMode(MODE_STDBY_RC); //ensure to stop further packet reception

    if ( readIrqStatus() & (IRQ_HEADER_ERROR + IRQ_CRC_ERROR + IRQ_RX_TX_TIMEOUT + IRQ_SYNCWORD_ERROR)) { return 0; //packet is errored somewhere so return 0 }

if wait is set to 0 it always comes out without waiting for DIO1 to High or the IRQ registerstatus then when How it is supposed to read packets, even in next loop? I mean even in the next call this function it again going to exit at wait. (wait is set to 0) Shouldn't there be a code like: if (wait == 0 ) { if (1 == digitalRead(_RXDonePin)) { //Rest of your code after While(!digitalRead(_RXDonePin)) }

StuartsProjects commented 1 year ago

On the circumstance of receiveReliable() do the standard library examples for transmit and receive work on your hardware ?

The code checking for No_Wait is as intended. If you use WAIT, then the receive function is blocking. If you want the receive to be non-blocking, say to setup for wake up on a packet receipt you use NO_WAIT and then setup your sketch\code appropriatly. You will need to add code to read the packet on receipt. This is mentioned in the readme. See example 62 in the SX127X part of the library for the process.

iottrends commented 1 year ago

Hi Stuart, For me the reliable didn't work. I am doing the testing with simple Transmit() and LT. receive(). Based on testing... Node-A is sending 250 byte pkts around 30 pkts/sec. and Node-B is receiving them. But I get a lot of CRC errors, around 50% pkts. Also one thing I observed Some time 2 packets are merged like Once I saw 2 64 bytes coming as single 128 byte pkts.
I can see if pkts are 100ms apart between works well.. however when It reaches around 50ms i see the problem of pkt error

StuartsProjects commented 1 year ago

For me the reliable didn't work.

Not sure what you mean by that, I was asking if the libray examples were working or your setup.

If you load example '201_Reliable_Transmitter' and '202_Reliable_Receiver' do they work ?

iottrends commented 1 year ago

let me try and get back ...

iottrends commented 1 year ago

Transmitter is working but reciever is crashing. attached the serial logs.. for both tx and rx 201_reliable_tx.txt 202_reliable_rx_log.txt lora-test.zip

StuartsProjects commented 1 year ago

Which Arduino are you using ?

Which version of the Arduino IDE are you using ?

Which LoRa SX1280 module are you using ?

iottrends commented 1 year ago

I am using sx1280 semtech, PlatformIO, esp8285

iottrends commented 1 year ago

reducing the timeout to 100ms fixes the crash issue... anything below 1000ms works

StuartsProjects commented 1 year ago

Those example sketches have been extensivly tested, there are no known issues with the sketches or the library on the supported microcontrollers.

The library has never been tested on ESP8285 or ESP8266 and I will not be investigating why the sketches crash or adding support for those microcontrollers.

The only supported programming platform is the Arduino IDE versions 1.8.xx.

As far as I am aware Semtech only manufacture the LoRa RF IC itself, other manufacturers produce the Modules such as HopeRF, Ebyte etc and there can be different wiring implementations.

I note you changed the LoRa modem settings for the example sketches.

iottrends commented 1 year ago

image

iottrends commented 1 year ago

this is what I am trying to fix... you see Pkt loss field... and Quality... if I use ESPnow it is 100%

StuartsProjects commented 8 months ago

The library has never been tested on ESP8285 or ESP8266 and I will not be investigating why the sketches crash or adding support for those microcontrollers.