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.
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.
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);
}
Hey all — Mat is on a well-deserved vacation and won’t be responding anytime soon.
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.
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();
}
}
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?
@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.
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.
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?
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.