Long Range IoT Networks - Chapter 2 | Particle + LoRa Better together

@chipmc Yeah, I think what I am attempting to accomplish is necessary functionality but as you said, maybe there is an easier or at least more robust way to accomplish it without having the complexity/concerns of threads.

From the threading explainer:

Used incorrectly they can introduce new and novel issues into your code that are often more difficult to debug than single-threaded code. Exercise caution and consider alternate designs such as finite state machines when your requirements allow.

There are even harsher wording here.

My vague concern is I'm new to threads so honestly I don't know how much of what I'm doing is incorrect vs correct. I just know it works (at least initially. :slight_smile: ).

What I am considering trying now is keeping the LoRa Finite state machine (FSM) separate as shown but instead of executing it from a thread function, simply locate the FSM within a LoRa.Process() method in the LoRa singleton class. Then within the main thread I can just execute LoRa.Process() each call to loop(). Likewise I could add it to softDelay() just like we do for Particle.Process(). I.e. kind of like this:

/*************************************************************************************/
//                            LOOP
/*************************************************************************************/
void loop()
{
  ab1805.loop();
  Particle.process();
  LoRa.process(); 
  PublishQueuePosix::instance().loop();

  //Run the main state machine
  stateMachine();
}

As well as anywhere I need to use a delay() I use softDelay() and I can include LoRa.Process() there as welll.

/*******************************************************************************
 * Function Name  : softDelay()
 *******************************************************************************/
inline void softDelay(uint32_t t) {
  uint32_t ms = millis();
  while(millis() - ms < t){
    Particle.process(); 
    LoRa.process();
    PublishQueuePosix::instance().loop();
    ab1805.loop();
  }   
}

If I did this, the LoRa FSM should be executed all the time in order to service messages all the time. I think this would accomplish the desired functionality without introducing a dedicated thread. However, my understanding LoRa.Process() can block the main thread now as several functions within RadioHead are blocking. I.e. manager.SendToWait() as an example. I believe this blocks until it receives an ACK back or a timeout. Most times will only block for 150 ms or so but at times can block the main thread for 3-4 seconds based on needing to perform a route discovery, the number of re-tries and timeouts due to retries. I assume this would still be more robust then multi-threading though right?

I'd be curious to hear what other people think of this method vs using a separate thread. Which way is better/more robust?