Photon Listening mode

Hey,

One remaining issue I am having with the photon code is it seems that listening mode blocks all user code from running.

Has anyone else run into this?

Listening mode was not blocking on the core.

It is rather important in my code to detect that the Photon is in listening mode and if credentials have not been received by the timeout limit I’ve set, my device shuts itself off to save the battery. This photon functionality breaks an important feature of our device.

Correction: Listening mode has always been blocking on the core. I was mistaken as I had forgotten that I had worked out an ISR approach to break out of listening mode that resolved this problem for me on the core.

1 Like

@HardWater, I don’t have my photon yet, so I can’t test it yet.
Is this happening just on reboot, or hours after the processor has been running ?

Hi @Jack,

I have only tested this feature upon reboot but it would be my guess that this problem of listening mode blocking user code exists no matter how long the device has been running, but I have not checked that.

For my usage, it probably would not cause me a problem if it is just during reboot, but would if it occurs later. When I get mine I will setup a timer loop, and display the times it takes to complete a short/fast loop (max, min, and last). That should give a good idea. I expect mine by the end of June (or maybe into July now).

In my code I toggle a led on and off while waiting for the credentials unless I timeout (timeout is set to 2 minutes). What I find is once I start toggling the led when I have no credentials (should be in listening mode or will be shortly). I find the led toggles for about 2 seconds then latches. I can pass it credentials via a phone and it will continue executing from that point demonstrating listening is blocking my timeout loop.

1 Like

Can you share some code?

1 Like

Well this is a snippet (untested) where I have removed the bulk of my application, but I think it demonstrates well where the code is being blocked

SYSTEM_MODE(MANUAL);

loop()
   {
   bool ledState;
   unsigned long exit_time;

   WiFi.on();

   WiFi.connect();

   if (!WiFi.hasCredentials())
      {
      //will wait up to 2 minutes for credentials to come in

      exit_time = millis() + (120 * 1000);
      ledState = 0;
      while(!WiFi.hasCredentials() && millis() < exit_time)
         {
         if (ledState)
            {
            ledState = 0;
            pinMode(ExtLedOut, INPUT);
            }
         else
            {
            //------------> here is where it gets stuck after a couple of trips around this while loop
            ledState = 1;
            pinMode(ExtLedOut, OUTPUT);
            digitalWrite(ExtLedOut, HIGH);
            }
         delay(200);
         }
      pinMode(ExtLedOut, INPUT); //make sure led is off

      if (!WiFi.hasCredentials())
         {
         //we must have timedout to get here
      
         SetRelay(POWER_OFF);   //SHUTS OFF THE CORE/PHOTON
         //should never get here
         beep(10, 1000);
         }
      }
   do_something_useful_here();

   if (external_event() == ERASE_CREDS)
      {
      WiFi.clearCredentials();
      }
   WiFi.disconnect();
   System.sleep(SLEEP_MODE_DEEP, 1);
   }

This would be an excellent post for @mdma to chime in on.

2 Likes

Hey all — Mat is on a well-deserved vacation and won’t be responding anytime soon. :wink:

To my knowledge, listening mode has always blocked the user app, both on the Core and on the Photon. Any evidence to the contrary is of course welcome.

We are actively working on running system code and user code in separate FreeRTOS tasks so that one does not block the other on the Photon. Thus, you can look forward to a non-blocking listening mode this summer!

If you’re building the firmware with a local toolchain, you can certainly add a timeout to listening mode. It will take me some digging to find exactly where, but I’ll post a solution to that problem tonight or tomorrow.

Cheers!

This might also shed some light on how these modes currently work:

SYSTEM_MODE(MANUAL);

unsigned long exit_time;
unsigned long then;
#define toggleLED() (digitalWrite(D7,!digitalRead(D7)))
#define now() (millis())
   
void setup() 
{
    pinMode(D7,OUTPUT);
    WiFi.on();
    WiFi.clearCredentials();
}

void loop()
{
    if (!WiFi.hasCredentials())
    {
        /* put into listening mode */
        WiFi.listen();
        
        /* wait up to 1 minute for credentials to come in */
        /* THIS CODE WON'T EXECUTE FOR LONG SINCE LISTENING MODE BLOCKS */
        /* ALSO NO WAY TO EXIT LISTENING MODE WITHOUT SOME FORM OF CREDENTIALS */
        then = now();
        while (!WiFi.hasCredentials() && now()-then < 60000UL)
        {
            toggleLED();
            delay(250);
            Spark.process();
        }
        /* We never received credentials, slow blink for 10 secs */
        /* THIS CODE WON'T EXECUTE SINCE THERE IS NO WAY TO EXIT */
        /* LISTENING MODE WITHOUT SOME FORM OF CREDENTIALS */
        if (!WiFi.hasCredentials())
        {
            then = now();
            while (now()-then < 10000UL)
            {
                toggleLED();
                delay(500);
                Spark.process();
            }
        }
        /* We received credentials, slow blink for 5 secs */
        /* Connect to Wi-Fi */
        /* Connect to the Cloud */
        /* NOTICE THERE IS NO TIMEOUT IF WE ARE TRYING TO */
        /* CONNECT WITH BAD CREDENTIALS, NEED TO ADD */
        if (WiFi.hasCredentials())
        {
            then = now();
            while (now()-then < 5000UL)
            {
                toggleLED();
                delay(500);
                Spark.process();
            }
        
            WiFi.connect();
            while (WiFi.connecting())
            {
                toggleLED();
                delay(100);
                Spark.process();
            }
            
            Spark.connect();
            while (!Spark.connected())
            {
                toggleLED();
                delay(50);
                Spark.process();
            }
        }
    }
    
    if (Spark.connected()) 
    {
        toggleLED();
        delay(1000);
        Spark.process();
    }
}

Hi @zachary

Well you are right about the blocking nature of listening on the core, though ISRs still work. I went back and took a look at my core code. Something I have not touched in about a month or more.

The way I achieved the non-blocking functionality was to implement an isr that would count the time and set WLAN_SERIAL_CONFIG_DONE to break out of listening if the core did not exit normally by getting credentials.

I forgot that I had written the code this way and had taken this out long ago from the photon version as @peekay123 timer library was not working with the Photon.

So please propose ideas on how to fix as this is a feature I need to get working again.

Specifically is there a register like WLAN_SERIAL_CONFIG_DONE that can be manipulated to exit listening? Is it possible WLAN_SERIAL_CONFIG_DONE still exists for the photon?

Hi @peekay123

Is there any chance that your timer library is now working for the Photon?

The above problem makes me really think I need it.

@HardWater, I have an updated timer library for the Photon but it only work with the locally compiled develop branch. When @mdma releases v4.2 of the firmware, I will release a new timer library. :smile:

2 Likes

Hey @peekay123 thanks for the reply.

Hey is that library available so I can try it with the develop branch. I am think maybe it would help me to code a very limited subset of features that could work with the master branch of the Photon. Does that make any sense? What is it about the v4.2 on the system that is required to make the library work that does not exist now?

@HardWater, because of the HAL and the separation of the system and user firmware, access to low level resources has to be done via a HAL API. The API is necessary for accessing the ISR vector table. Only the develop branch has that right now. Can you wait till 0.4.2 is released in a couple of weeks? Develop is still beta in a lot of areas. :smile:

@peekay123 thanks for the quick answer.

We are trying so hard to get the Photon code in shape to continue the successful design we had on the Core. From the sounds oh it. There is little chance to directly set the timer registers and vector table without use of the HAL interface, which sounds like a major roadblock for us. We were planning on shipping in 2-3 weeks. How sure are you the 0.4.2 will come out in 2 weeks?

Yeah I was interested in playing with it with the develop branch but was not interested in shipping product using the develop branch as that would be way too risky.

I am thinking maybe a better approach to breaking out of listening mode might be to find out where in the low level code the photon loops while in listening mode and test against a timeout limit there. Upon tripping the timeout the code either returns or calls another function. Obviously this would have to be a local compilation of a modification to the master branch. This sounds like the most fruitful path. Any thoughts or comments would be helpful?

Anyone know where in the code this listening loop might be?

Hey @HardWater, here's the spot you want to target for a timeout. You can easily use millis() and you may have to do more than just break out of the loop and fall through the remaining function calls.
https://github.com/spark/firmware/blob/develop/system/src/system_network.cpp#L91

Also something to note: WiFi.listen(); just sets a flag, that gets checked when the loop() exits or when Spark.process() is called, or when a delay() is called.

1 Like

Thanks @BDub,

Unfortunately I spent the full day working on this and beat you to the punch by about an hour, but anyways I appreciate the help.

I have started a new thread to discuss the implications of system modification and hope that you will follow me there Implications of customized system firmware - Photon

Hi @BDub .

I can neither find this particular path in your this post in the github repository nor system_network.cpp.

I did a clone of spark/firmware and did a find on the top level for this file with no luck.

Am I missing something?

@armystic, did you clone the “develop” branch of the firmware repo? Cloning the main branch will not get you the code you need. :smile: