Can you turn off WiFi.listen() once it starts? and what is the purpose of WiFi.listening()? [SOLVED]

[Original post]Please tell if I am missing something. Can the application stop WiFi.listen() after it starts? If not what is the purpose of WiFi.listening? I read the post below, but can I update via the cloud with this solution?

For my application I always want to power up in "listen" mode for a limited amount of time then connect using stored credentials (if there are any). If my connection is lost while operating I want to toggle between "listen" and try to reconnect with current credentials. My 2 cents for future improvement would be WiFi.listen(timeout in seconds as an argument). Spark.connect(timeout in seconds as argument).

Jerome

[SOLUTION] First off thanks to all, this community continues to impress me.

This makes WiFi.listen() and Spark.connect() behave pretty much how I want them to. I wanted to toggle between them... This way I don't need to WiFi.clearCredentials() when going to a new network. I can just unplug and go. a "timeout" on WiFi.listen() only got me half way there. Because if someone unplugs the router temporarily I also want to try and reconnect after a while. Anyway this code seems to work using peekay123's SparkIntervalTimer library.

#include "SparkIntervalTimer.h" //used to interrupt listen mode.

SYSTEM_MODE(SEMI_AUTOMATIC);

int led_pin = D7;

//////////////////////////////////////////////////////////////////////
//connection mode management variables
/////////////////////////////////////////////////////////////////////
#define TIMER_INTERVAL 30000 //units 1/2 millisecond
//fire_listen and fire_connect: one should be set to 0 and the other to
//    1 if fire_listen is set to one the unit will start in listen mode
//    visa versa for fire connect.
IntervalTimer conn_timer;
int fire_listen = 0;
int fire_connect = 1;
int listen_timeout = 120; // in seconds to the nearest timer interval
int connect_timeout = 15; // in seconds to the nearest timer interval
enum CONNECT_MODE {listen_mode, connect_mode};
enum CONNECT_MODE current_mode;
volatile int isr_loop_count = 0;
void si_sparkconn(void); //prototype
void si_sparkconn_isr(void);
//////////////////////////////////////////////////////////////////////
//END connection mode management variables
/////////////////////////////////////////////////////////////////////


void setup(void)
{
    pinMode(led_pin, OUTPUT);
    Serial.begin(9600);

    conn_timer.begin(si_sparkconn_isr, 30000, hmSec, TIMER4);
}

void loop(void)
{
    si_sparkconn();
    delay(200);
    digitalWrite(led_pin, !digitalRead(led_pin));
}

/////////////////////////////////////////////////////////////////////
//name: si_sparkconn
//desc: calls functions that put the sparkcore in listen for wifi
//      credentials mode, and try to connect to the spark cloud
//      respectively.  Spark.connect() specifically should not be
//      called from an isr.
//args: none
//returns: none
//notes: must be placed in the "loop" function
//author: jerome verhoeven
//date: 2/20/2014
///////////////////////////////////////////////////////////////////
void si_sparkconn (void)
{
  if(fire_listen)
  {
    current_mode = listen_mode;
    WiFi.listen();
    fire_listen = 0;
  }
  if(fire_connect)
  {
    current_mode = connect_mode;
    Spark.connect();
    fire_connect = 0;
  }
  return;

}

/////////////////////////////////////////////////////////////////////
//name: si_sparkconn_isr
//desc: this function is placed in an interrupt service routine
//      This is needed because the WiFi.listen() is blocking and
//      only an interrupt vector can check these flags
//args: none
//returns: none
//notes: if features are added check that functions are just checking
//      flags not calling other functions.  If other functions (like
//      Spark.connect() or WiFi.listen() should only be called from
//      the "loop()")
//author: jerome verhoeven
//date: 2/23/2015
/////////////////////////////////////////////////////////////////////
void si_sparkconn_isr (void)
{
  isr_loop_count++;
  if(current_mode == listen_mode)
  {
    if(WiFi.listening()
        && (isr_loop_count >= (listen_timeout / (TIMER_INTERVAL / 2000))))
    {
      WLAN_SERIAL_CONFIG_DONE = 1;
      fire_connect = 1;
      isr_loop_count = 0;
    }

  }
  else if(current_mode == connect_mode)
  {

    if(!Spark.connected()
            && (isr_loop_count >= (connect_timeout / (TIMER_INTERVAL / 2000))))
    {
      fire_listen = 1;
      isr_loop_count = 0;
    }
  }

  return;

}

This is pretty awesome solution too, but it didn't get me the whole way there. +I am trying to stay in the "application.ino" part of the project if possible.
Continuing the discussion from Control Smart Config mode [SOLVED]:

@jerome I'm not sure what you are trying to do. What is the point of powering up in just 'listen' mode. You are not really getting any information w/o an established connection to a router.

Oops - WiFi.listen() is not what I thought it was. OK, so I understand you want to use this to reconfigure the WiFi credentials. WiFi.listening() lets you check if you have WiFi credentials while in the WiFi.listen mode. Once you have credentials you could call WiFi.connect() to attempt to connect to the router.

No, if you don't have any valid connection to a router you will not have a cloud connection.

Are you trying to give the user the opportunity to always set new access point credentials every time you want to connect to the network?

mtnscott thanks for reading.

First I will try to explain the problem (like the real world problem). My device will be moved from house to house (network to network). Once at a new house I want to be in listen modeā€¦ However how can I tell whether I moved to a new house (new network) or the router just got unplugged. So the idea is if I cannot connect try listening for a little while. If I donā€™t get credentials, try connecting again, and so on and so forth until I connect.

If this doesnā€™t make sense just let me know I can try to explain this better.

If I try to add a timeout on my listen feature like this but it doesnā€™t work? It sure seems like if you call WiFi.listen() you are stuck listening until you hear something.

My non-working timeout. I used from of BDub codes to test this and added the timeout. Basically you type in ā€˜Lā€™ from the terminal and it goes into listening modeā€¦ and wonā€™t come out of it unless you send credentials.

     case 'L': start_time = millis();
                WiFi.listen();
                break;
    }
  }

  if(WiFi.listening())
  {
    if(millis() - start_time > LISTEN_TIMEOUT)
    {
      Spark.connect();
    }
  }

@jerome OK, I think I understand. I have not ever used WiFi.listen(). Does your loop still get executed after a call to WiFi.listen()? If so then I suggest that you try calling WiFi.off() after your timeout, then let your loop execute a few times (to let the Spark firmware process the change) and then call Spark.connect(). The call to WiFi.off() should clear out any previous state such that the future call to Spark.connect() can act normally using the stored credentials.

The loop doesnā€™t get executed near as I can tell. So if WiFi.listen() never returns to the main loop, then what is the point of WiFi.listening()?

I tried reset, deep sleep, and WiFi.off() instead of Spark.connect() none work.

Youā€™re totally right - WiFi.listen() will block the main user loop.

You could setup a interrupt routine that is called from a timer, which checks WiFi.listening() to know if the system is listening or not.

To exit listening, as a quick hack, you could set WLAN_SERIAL_CONFIG_DONE to 1 to cause WiFi.listening() to exit. But please keep in mind that access to internal variables will be replaced by an API in future versions.

Hope that helps! :slight_smile:

1 Like

It helps a tonā€¦ Thanks

Any resources on setting up a timer interrupt? I donā€™t remember reading as an interrupt source on your docs pageā€¦

Thanks again

@jerome While @mdma was replying - thanks @mdma (you rock as always!) I wrote a test app that let me see that WiFi.listen() does not return unless you provide WiFi credentials. The listen mode has two commands (AFAIK) 'i' for getting the core ID and 'w' for setting WiFi credentials. So you will need to have an timer interrupt that function and you can shut down that mode and continue in your application. (NOTE: going into listen mode currently closes any serial connection and so any debugging on that port - you will have to re-establish the serial connection to continue)

Here is some work previously done by @peekay123 with timers.

1 Like

Thanks @mtnscott! Yep, I was thinking @peekay123ā€™s excellent timer library. (Although Iā€™ve been also toying with the idea of allowing user code to easily hook the millisecond interrupt for simple use cases - https://github.com/spark/firmware/issues/399)

btw, the issue where serial connection closes on entering listen mode has been fixed in the development branch, will be released as 0.4.0 in time for the photon.

An alternative, rather than using WiFi.listen() you could code your own code to read the serial port, retrieve wifi details and call WiFi.setCredentials() to add the credentials to the existing list. This would also give you the freedom to do this only when a wifi connection isnā€™t made with the current credentials.

1 Like

Thanks guys, this community is awesome.

I like peekay123ā€™s interval timer (@peekay123 awesome job). peekay warns not to call other functions, if possible from the ISR. Well, I will need to. normally when I have written ISRā€™s in the past I disable interrupts when I enter the ISR and re-enable before I leave the ISR. Is this possible to do using the SparkIntervalTimer? Is is already being done? (I didnā€™t see it being done in SparkIntervalTimer.cpp, but I am not really a .cpp ninja).

@jerome, it all comes down to how much time your ISR uses when calling other functions. Using noInterrupts() in the timer ISR will not disable it but there is a timer function to disable the timerā€™s interrupt. What exactly are you doing in your ISR and how fast are your timer interrupts?

check connection state and change if necessary.

something like

//after trying to connect unsuccessful or a period of time
if(WiFi.connecting() && timeout)
{
   //try listening for new credentials
   WiFi.listen();
}
//if we have been listening for awhile try connecting again
else if(WiFi.listening() && timeout)
{
   Spark.connect();
}

Edit: forgot to add interval timingā€¦ As long as possible, the only reason I need the interrupt timer is because WiFi.listen() is blockingā€¦ and I think the Spark.connect() is blocking too. I donā€™t know the exact interval but like 10 - 60 seconds.

Iā€™m afraid you canā€™t call WiFi.listen() or Spark.connect() from an interrupt - that will run a huge amount of code as an interrupt, potentially blocking other lower priority, but essential interrupts.

You should only set flags on interrupts, such as setting the WLAN_SERIAL_CONFIG_DONE flag to cause WiFi to stop listening.

@mdma, great info! Are there key flags that a user could set to:

  1. Stop a cloud connection attempt?
  2. Stop a wifi connection attempt?

For WiFi.listen, does setting the flag ā€œimmediatelyā€ stop the listening code? Would it be good practice for a user to set a ā€œtimeoutā€ flag in the ISR so it can be tested after calling WiFi.listen()?

Having a definitive way to abort these three blocking events using a hardware timer would be great to document. :slight_smile:

I thought WiFi.listen() did just set a flag? I thought I read that in a thread in this forum. Hmmmā€¦ Maybe I will have to look that out again. I think it was posted BDub.

Currently I am calling WiFi.listen() and Spark.connet() from my interrupt routine (not that it is a good idea) and it works! I will try switching over to using flags instead. And report backā€¦

@jerome, you are partially correct. WiFi.listen() sets a flag only but Spark.connect() will call WiFi.connect() and that will take longer and slow down the ISR. However, I am intrigued that is is working without problems. Keep us posted! :smile:

I guess WiFi.listen() does set the flag, but it also does a lot of other things

And from this post of @mdma

I'd gather that WiFi.listen() (and not WiFi.listening()) does its job as long as the flag is 0 (aka FALSE).

The sources are there for everyone to see - no guessing needed! https://github.com/spark/firmware/blob/master/src/spark_wiring_wifi.cpp#L235-L248

1 Like

Sorry, my bad again :blush: - I should have looked, before guessing wrong :stuck_out_tongue_winking_eye:

1 Like

Haha, no worries my friend! :slight_smile: Thereā€™s a lot to keep track of - I only know because Iā€™ve been closely involved with firmware development the past few months.

2 Likes