Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

While loop, sometimes takes long or never ends #378

Open
JRAlvarez2017 opened this issue Jun 21, 2020 · 12 comments
Open

While loop, sometimes takes long or never ends #378

JRAlvarez2017 opened this issue Jun 21, 2020 · 12 comments

Comments

@JRAlvarez2017
Copy link

I noticed that sometimes , the while loop in the endPacket() function takes too long. I think there should be a time-out inside the loop to break. Here I wrote an example of just an idea of how to dodge the problem.

int LoRaClass::endPacket(bool async)
{

if ((async) && (_onTxDone))
writeRegister(REG_DIO_MAPPING_1, 0x40); // DIO0 => TXDONE

// put in TX mode
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX);

if (!async) {
// wait for TX done
delay(10);
unsigned int i = 0;
while ((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0)
{
delay(5);
if (i++ > 1000)
break;
}
// clear IRQ's
writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK);
}

return 1;
}

@IoTThinks
Copy link
Collaborator

Interesting.
How long is “too long”?

What is the packet length and SF/BW?

@JRAlvarez2017
Copy link
Author

Packets are 30 to 70 bytes. Normally, It takes between 150 ms to 500 ms to ge the IRQ_TX_DONE_MASK. SF is 8, and BW is 250E3.
I am using hardware interrupt (DI0). Sometimes, I am not sure 100% why, the endPacket() loop does not see/receive the IRQ_TX_DONE_MASK, and then the code never puts back the LoRA into receive mode. Consequently, packets do not arrive anymore.
When there is a low flow of packets, it is not noticeable. However, when there are many packets flowing (easier to get two packets arriving at almost the same time), and several LoRa boards, there are higher chances that a DI0 interrupt is called in between the endPacket() lines of code, and it may create the problem.
I opted for enable and disable the DI0 before or after lines of critical code, and it eliminates the issue. Of course, some packets will be lost, but it is better, because at least the LoRa board keeps on communicating (sending and receiving packets).

@IoTThinks
Copy link
Collaborator

"then the code never puts back the LoRA into receive mode. Consequently, packets do not arrive anymore."

For me, after sending, I normally set to receive mode manually.

@PrzemyslawMotyl
Copy link

PrzemyslawMotyl commented Jan 6, 2021

I noticed similar issue as described by @JRAlvarez2017.
I'm using Lora Ra-02 with ESP8266 to send max 10 bytes every 10 seconds.
After 2-3 days of sending messages method "LoRaClass::endPacket" started execution of "while" endless loop with "yield();" method:

if (!async) {
    // wait for TX done
    while ((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) {
      yield();     // endless loop is exdecuted all the time
    }
    // clear IRQ's
    writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK);
  }

As a workaround I've started to use "endPacket" method asynchronously:

LoRa.endPacket(true);

Next I've marked "isTransmitting()" method as "public".

Now in my code I can send a message and wait defined time for end of the transmission:

LoRa.beginPacket();
LoRa.println(msg);
LoRa.endPacket(true);     // true = async / non-blocking mode
int sendingCounter = 0;
delay(50);      // Without this delay the first isTransmitting() will return "false" and "while" is ommited

// Checking for end of transimission for maximum 1 second
while (LoRa.isTransmitting() == true) {
  sendingCounter++;
  Serial.print(".");
  delay(10);
  
  if(sendingCounter == 100) {
	Serial.println("\nLora sending error");
	break;
  }
}

Please consider to add timeout for "LoRaClass::endPacket" method if it is executed synchronously.

@IoTThinks
Copy link
Collaborator

IoTThinks commented Jan 7, 2021

@PrzemyslawMotyl , @JRAlvarez2017
Any idea why the while loop does not stop after TX Done?

while ((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) {
      yield();     // endless loop is exdecuted all the time
    }

@PrzemyslawMotyl
Copy link

I don't know maybe this is hardware issue.

@hoseinaghajari
Copy link

hoseinaghajari commented May 27, 2021

Hi dears, I have same problem as you mentioned. I have good communication But after a while the receiver can't receive anything.
I changing the code as you said but it was like before. what it the problem? I have confused about it. the code is completely correct but why it stop to receive after some hours?

@PrzemyslawMotyl
Copy link

Hi,

What LoRa settings do you have?
I used 1 second timeout because I set LoRa to send small amount of data in a short time.

LoRa.setSpreadingFactor(12);           
LoRa.setSignalBandwidth(62.5E3 );           
LoRa.setCodingRate4(8);                   
LoRa.setTxPower(6);  // Try to used low TX power also
LoRa.enableCrc();

Here you can increase this timeout. Try to use 10 seconds:

if(sendingCounter == 1000) {
	Serial.println("\nLora sending error");
	break; 
}

I'm using strong 433 antennas and I had to decrease TX power also. Without this also I had problems.
After I posted this problem and use library modification I didn't have any problems with LoRa since January 2021.

Regards,
Przemek

@hoseinaghajari
Copy link

hi @PrzemyslawMotyl . I did that but it stop to receive after 15-16 hours.
how can I marked "isTransmitting()" method as "public"? Just moving it in public? Arduino say its no declare. I just put "isTransmitting()" in the LoRa.endpacket() loop. here is my library:

int LoRaClass::endPacket(bool async)
{
  
  if ((async) && (_onTxDone))
      writeRegister(REG_DIO_MAPPING_1, 0x40); // DIO0 => TXDONE

  // put in TX mode
  writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX);

  if (!async) {
    // wait for TX done
    int sendingCounter = 0;
delay(50);      // Without this delay the first isTransmitting() will return "false" and "while" is ommited

// Checking for end of transimission for maximum 1 second
while (LoRa.isTransmitting() == true) {
  sendingCounter++;
  delay(10);
  
  if(sendingCounter == 1000) {
	break;
  }
}
    // clear IRQ's
    writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK);
  }
  return 1;
}

@PrzemyslawMotyl
Copy link

PrzemyslawMotyl commented May 29, 2021

In LoRa.h just put "isTransmitting" in "public" section:

class LoRaClass : public Stream {
public:
  LoRaClass();

  int begin(long frequency);
  void end();

  int beginPacket(int implicitHeader = false);
  int endPacket(bool async = false);

  int parsePacket(int size = 0);
  int packetRssi();
  float packetSnr();
  long packetFrequencyError();

  int rssi();

  // from Print
  virtual size_t write(uint8_t byte);
  virtual size_t write(const uint8_t *buffer, size_t size);

  // from Stream
  virtual int available();
  virtual int read();
  virtual int peek();
  virtual void flush();

#ifndef ARDUINO_SAMD_MKRWAN1300
  void onReceive(void(*callback)(int));
  void onTxDone(void(*callback)());

  void receive(int size = 0);
#endif
  void idle();
  void sleep();

  void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN);
  void setFrequency(long frequency);
  void setSpreadingFactor(int sf);
  void setSignalBandwidth(long sbw);
  void setCodingRate4(int denominator);
  void setPreambleLength(long length);
  void setSyncWord(int sw);
  void enableCrc();
  void disableCrc();
  void enableInvertIQ();
  void disableInvertIQ();
  
  void setOCP(uint8_t mA); // Over Current Protection control
  
  void setGain(uint8_t gain); // Set LNA gain

  // deprecated
  void crc() { enableCrc(); }
  void noCrc() { disableCrc(); }

  byte random();

  void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN);
  void setSPI(SPIClass& spi);
  void setSPIFrequency(uint32_t frequency);

  void dumpRegisters(Stream& out);
  
  // Mark "isTransmitting" as "public"
  bool isTransmitting();

private:
  void explicitHeaderMode();
  void implicitHeaderMode();
  ...

@Gandalf1783
Copy link

Gandalf1783 commented Oct 3, 2021

This Issue still persists.
I added some Serial.println(""); statements and i got stuck at yield too.
This is my current code for the while() loop in the endPacket() function:

int LoRaClass::endPacket(bool async)
{
  if ((async) && (_onTxDone))
      writeRegister(REG_DIO_MAPPING_1, 0x40); // DIO0 => TXDONE

  // put in TX mode
  writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX);

  if (!async) {
    // wait for TX done
    while ((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) {
      yield();
	  Serial.print("REG_IRQ_FLAGS: ");
	  Serial.println(readRegister(REG_IRQ_FLAGS), HEX);
	  Serial.print("IRQ_TX_DONE_MASK: ");
	  Serial.println(readRegister(IRQ_TX_DONE_MASK), HEX);
    }
    // clear IRQ's
    writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK);
  }
  return 1;
}

This is my output for the read registers:

REG_IRQ_FLAGS: 15
IRQ_TX_DONE_MASK: 0

Value 0x15 in REG_IRQ_FLAGS seems to be the reset for the IRQs.
The Bits that are set in the register are:
CadDetected
CadDone
ValidHeader

All of them say "Writing a 1 clears the IRQ."
Doesnt seem to do it.

EDIT:
This doesnt seem to make sense.
The #define on the top of the library states that the IRQ_TX_DONE_MASK should be 0x08, while my Arduino outputs 0x0.

@Gandalf1783
Copy link

Gandalf1783 commented Oct 3, 2021

Update:
My OP-Mode actually changes after the TX-Mode to a Non-LoRa-Mode.
It unsets the upper bit in the OP-Register.

My 2nd, identical transmitter doesn't do this.

If i run the library with debug output on Arduino 1 (working one)

20:56:58.910 -> [LIB] : ENDING PACKET...
20:56:58.955 -> REG_IRQ_FLAGS & IRQ_TX_DONE_MASK: 0
20:56:59.000 -> REG_IRQ_FLAGS: 8
20:56:59.000 -> IRQ_TX_DONE_MASK: 0
20:56:59.045 -> OP-MODE:81
20:56:59.045 -> [LIB] : END PACKET DONE

On the Arduino 2 (not working) it says this:

[LIB] : ENDING PACKET...
REG_IRQ_FLAGS & IRQ_TX_DONE_MASK: 0
REG_IRQ_FLAGS: 15
IRQ_TX_DONE_MASK: 0
OP-MODE:81

REG_IRQ_FLAGS & IRQ_TX_DONE_MASK: 0
REG_IRQ_FLAGS: 15
IRQ_TX_DONE_MASK: 0
OP-MODE:9

While it not only resets OP-Mode to 0x09, it also seems to have a different REG_IRQ_FLAGS register with 0x15 instead of like Arduino 1 has (0x8). It changed from LongRangeMode = 1, Mode = 1 (Standby) to LowFrequencyModeOn = 1, Mode = 1 (Standby).

EDIT:

I just realised i used the readRegister() function for outputting the #define variable.
Still, the TxDone bit it not set. If I set it manually , it does not continue to normal operation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants