Great idea. Here is my suggestion, but I have to get home to try it out. At least it compiles (assuming you include the two sparkIntervalTimer files .h and .cpp)
#include "SparkIntervalTimer.h"
SYSTEM_MODE(SEMI_AUTOMATIC);
// Create IntervalTimer object
IntervalTimer myTimer;
// Pre-define ISR callback functions
void checkWifi(void);
//const uint8_t ledPin = D7; // LED for first Interval Timer
void setup(void) {
pinMode(D7, OUTPUT);
digitalWrite(D7,HIGH); // blink D7 fast once before timer activated
delay(40);
digitalWrite(D7,LOW);
myTimer.begin(checkWifi, 60000, uSec); // check for wifi every 60 seconds or until stopped
digitalWrite(D7,HIGH); // blink D7 slow twice when timer activated (checks if blocking)
delay(500);
digitalWrite(D7,LOW);
delay(500);
digitalWrite(D7,HIGH);
delay(500);
digitalWrite(D7,LOW);
}
//volatile unsigned long blinkCount = 0; // use volatile for shared variables seems cool to know
void checkWifi(void) {
Spark.connect(); // this is normally a blocking function
}
int myLoop;
int myConnect = 0; // 0 just starting, 1 connected, 2 manual mode
void loop() {
if (myConnect == 0) { // check for connectivity
if (WiFi.ready()){ // wifi is connected
myTimer.end(); // shut down the timer
myConnect = 1; // says wifi connected
} else {
myLoop++;
delay(1000);
if (myLoop >= 20) { // tried to get Wifi for 20 seconds
Spark.disconnect(); // not sure if this is needed
myTimer.end();
myConnect = 2; // says no wifi
}
}
}
if (myConnect == 1) { // do your wifi connected loop
digitalWrite(D7,HIGH); // blink D7 fast to show that Wifi is working
delay(100);
digitalWrite(D7,LOW);
delay(100);
// other statements here
}
if (myConnect == 2) { // do your manual loop
digitalWrite(D7,HIGH); // leave D7 on to show manual mode
// other statements here
}
if (myConnect >= 1) { // do statements that are for either manual or automatic mode
// other statements here
}
}
I’d guess it won’t actually do what you intend, since you should not call a blocking function inside an ISR
In the other thread I wrote (and am still convinced, to be true)
So you’d rather call Spark.connect() in your normal code but “cancel” the connection attempt from your ISR by calling Spark.disconnect() (and possibly WiFi.off() aswell).
Ok, so here is the second attempt, using the timer to shutdown the connect process. It compiles but I have not tested it. Also finally learnt how to use the spark libraries. So the include statement is a bit easier. Can someone else load this as I have my spark core testing my Pixy Camera Rover and I don’t want to break it again.
Of course Spark.io could always send me a few Cores (like a class set=15 one per two students), so I can continue trying to make Spark products easier to use
// This #include statement was automatically added by the Spark IDE.
#include "SparkIntervalTimer/SparkIntervalTimer.h"
// Attempt number 2
// check Spark Core for Wifi on startup, if no wifi then allow it to run none-cloud dependent activities.
SYSTEM_MODE(SEMI_AUTOMATIC);
// Create IntervalTimer object
IntervalTimer myTimer;
// Pre-define ISR callback functions
void checkWifi(void);
//const uint8_t ledPin = D7; // LED for first Interval Timer
void setup(void) {
pinMode(D7, OUTPUT);
digitalWrite(D7,HIGH); // blink D7 fast once before timer activated
delay(40);
digitalWrite(D7,LOW);
myTimer.begin(checkWifi, 20000, uSec); // check for wifi and shutdown if no connection after 20 seconds
delay(50);
Spark.connect(); // try to connect
digitalWrite(D7,HIGH); // blink D7 slow twice when timer activated (checks if blocking)
delay(500);
digitalWrite(D7,LOW);
delay(500);
digitalWrite(D7,HIGH);
delay(500);
digitalWrite(D7,LOW);
}
volatile unsigned long myConnect = 0; // use volatile for shared variables: 0 just starting, 1 connected, 2 no connectivity, 99 first timer done
void checkWifi(void) {
if (myConnect != 0){ // not the first activation of the timer
if (WiFi.ready()){ // this loop should wait 20 seconds to occur
myConnect = 1; // means wifi got connected
} else {
Spark.disconnect();
WiFi.off();
myConnect =2; // means no wifi
}
myTimer.end(); // no mater what happens shut down the timer since we only want it to work once
} else {
myConnect = 99; // identifies the first run has completed.
}
}
int myLoop;
void loop() {
if (myConnect == 1) { // do your wifi connected loop
digitalWrite(D7,HIGH); // blink D7 fast to show that Wifi is working
delay(100);
digitalWrite(D7,LOW);
delay(100);
// other statements here
}
if (myConnect == 2) { // do your no wifi loop
digitalWrite(D7,HIGH); // leave D7 on to show manual mode
// other statements here
}
if (myConnect == 1 || myConnect == 2) { // do statements that are for either wifi or no wifi modes
// other statements here
}
}
.
.
.
.
Here is information about the Pixy Camera Rover, it follows a certain color. I still have to tweak some values so the rover doesn’t go racing down the street.
After the amout of effort you already put into this, I’d like to suggest these adaptions
At this point I haven’t tested them myself, but just from experience this should work - and I’ll test it soon and correct if required Edit: This is now working code, but in my tests I’ve got the impression, all that interrupt/timer effort isnotneeded anyhow, since Spark.connect() doesn’t seem to block anymore (despite still being stated to be and as I remember it to have been) @mdma, has anything been changed “recently” that hasn’t found its way into the docs? Or am I imagining things?
// This #include statement was automatically added by the Spark IDE.
#include "SparkIntervalTimer/SparkIntervalTimer.h"
SYSTEM_MODE(SEMI_AUTOMATIC);
// Create IntervalTimer object
IntervalTimer myTimer;
// Pre-define ISR callback functions
void checkWifi(void);
volatile uint8_t isrTriggered = 0;
const unsigned long CONNECT_TIMEOUT = 30000;
unsigned long lastMillis; // it's always good to have this for non-blocking delays
void setup(void) {
pinMode(D7, OUTPUT);
digitalWrite(D7,HIGH); // blink D7 fast once before timer activated
delay(40);
digitalWrite(D7,LOW);
// this would only wait 20ms since uSec is micro seconds
// myTimer.begin(checkWifi, 20000, uSec); // check for wifi and shutdown if no connection after 20 seconds
// the other time scale is half-milliseconds (hence 2*)
myTimer.begin(checkWifi, 2 * CONNECT_TIMEOUT, hmSec);
lastMillis = millis(); // store soft-delay reference time
// try to connect
isrTriggered = 0;
Spark.connect();
if (!isrTriggered)
{ // only wait if connection attempt succeeded
myTimer.end(); // don't disconnect prematurely
while ((millis() - lastMillis) < CONNECT_TIMEOUT)
{
digitalWrite(D7, HIGH);
delay(50); // flash LED about 10Hz
Spark.process();
digitalWrite(D7, LOW);
delay(50); // flash LED about 10Hz
}
Spark.disconnect(); // missed your chance for OTA flashing
}
WiFi.off(); // deactivate WiFi in any case
}
// no need to re-check inside loop() now
void loop()
{
digitalWrite(D7, HIGH);
delay(500); // flash LED about 10Hz
digitalWrite(D7, LOW);
delay(500); // flash LED about 10Hz
}
void checkWifi(void)
{
isrTriggered = 1;
Spark.disconnect(); // no more required inside ISR
}
Edit: Fixed some build error - Spark.connect() does not return any success/fail indicatior
Yep, that’s the one that introduced SYSTEM_MODE().
Only after this it became even possible to squeeze in some code before Spark.connect() that might be able to stop any running connection attempt.
Nothing has changed since the last release in October 2014. Afaict, Spark.connect() will never block, since it just calls WiFi.connect(), which is non-blocking, and sets a flag to cause the background thread to connect to the cloud.
When the user calls Spark.connect(), the user code will be blocked, and the Core will attempt to negotiate a connection. This connection will block until either the Core connects to the Cloud or an interrupt is fired that calls Spark.disconnect().
@ScruffR, @mdma perhaps some test code is in order to establish if Spark.connect() or WiFi.connect() actually block user code or not. The story until now has been that user code will block when the cloud connection is LOST in AUTOMATIC mode but SEMI_AUTOMATIC and MANUAL mode scenarios are not so clear. It would be good to understand the behavior once and for all
So what it seems like to me is this problem is solved.
If you would like to try connecting without blocking, put the Spark Core in SEMI_AUTOMATIC mode and call Spark.connect() . If you want to cancel it, just wait for millis() or the like and call Spark.disconnect() and/or Wifi.off() .
Did I get it right?
I hope the docs will be updated if there are any inconsistencies.
So should this work? Reminder that I do not have a core I can check this on just yet. If someone could try it that would be useful.
SYSTEM_MODE(SEMI_AUTOMATIC);
int myConnect=0;
void setup() {
pinMode(D7, OUTPUT);
Spark.connect();
delay(5000);
delay(5000);
delay(5000);
delay(5000);
if (WiFi.ready()){
myConnect = 1; // means wifi got connected
} else {
Spark.disconnect();
WiFi.off();
myConnect =2; // means no wifi
digitalWrite(D7,HIGH); // D7 high says no wifi but spark working fine.
}
}
void loop() {
// put generic code here
if (myConnect == 1){ // only put code here that needs wifi
digitalWrite(D7,HIGH); // fast blink says Wifi connected
delay(50);
digitalWrite(D7,LOW);
delay(50);
}
if (myConnect == 2){ // only put code here that is fine with no wifi
}
}
@rocksetta, this should work, but there are some things to improve.
Why use multiple consecutive delay() statements instead of one big one - even Arduino would allow up to 65535 and the Core 2^32 - 1
Have you had a look at the “soft delay”, I’ve used in my sample code? This is the prefered way to do long delays. This way you could keep the delays as short as needed, since you can check for state changes inside the loop.
Do you actually mean to let the cloud on, if it’s there? This didn’t seem so in the OP.
Are you intending to have more than two states for myConnect - if not I’d go for 0/1 with preset 0 and if(myConnect) ... else
I thought delays over 20 seconds messed up calls to spark.process(), but if not it isn’t a big deal.
Good idea with the soft delays. My code took about 6 minutes to write so it may have a few issues. I still haven’t got confirmation if the code works as my Core is busy with another project. That would be very helpful.
If the core connects to the Cloud, great let it continue. Trying to make the code as simple as possible so that if someone wants to change it they can.
The zero “0” state was for when you do not know yet if there is a connection or not. 1 = Good Cloud connection, 2 = No Cloud connection. Really doesn’t matter either way, I originally wanted to make the myConnect variable boolean, but sometimes when debugging code integers are just easier to work with.
Please show your new code as the interrupt and volatile variable show up in about 5 places, and all of this is supposed to be helping beginners.
Actually 0, 1, 2 is needed since 0 and 1 does not prove Wifi has been disconnected and could show a false positive. But seriously we just want working code, let the academics stress about correctness.
Anyway, got tired of waiting for someone to test my code so I thought I would include it in my Rover. Here is the slightly changed code that works:
With Wifi in range, it connects quickly breaths cyan, waits 20 seconds and then flashes D7 fast to show Wifi Cloud connectivity.
Without Wifi nearby it flashes green for 20 seconds then shows solid D7 HIGH and strangely breaths cyan??
Here is the code:
SYSTEM_MODE(SEMI_AUTOMATIC);
int myConnect = 0; // means neither connected or disconnected yet
void setup() {
pinMode(D7, OUTPUT);
Spark.connect(); // non-blocking attempt to connect to Wifi
delay(20000); // wait 20 seconds at startup
if (WiFi.ready()){
myConnect = 1; // means wifi got connected
} else {
Spark.disconnect();
WiFi.off();
myConnect =2; // means no wifi cloud connectivity
digitalWrite(D7,HIGH); // D7 high says no wifi but spark working fine.
}
}
void loop() {
// put your generic code here that works if Wifi connected or not
if (myConnect == 1){ // only put code here that needs wifi
digitalWrite(D7,HIGH); // fast blink says Wifi connected
delay(50);
digitalWrite(D7,LOW);
delay(50);
// put your code here that needs wifi Cloud connectivity
}
if (myConnect == 2){ // only put code here that is fine with no wifi
// put your code here that runs without Wifi Cloud connectivity
// LED D7 should be HIGH to prove Wifi has been disconnected
}
}