Non-Blocking loop until Linux is completely booted (with Wlan)

Hello, My first post here. 8)

I have an Arduino Yun for several months now. I’m currently building a little remote control for my philips hue lights using an lcd (16x2 over I²C) and a rotary encoder for user input. (will share my project later over gitHub)
Got the python scripts (phue-master) working well.
I can now control my lights with the yun. A menu on my lcd shows every light and i can power them on/off or control the brightness of the bulbs.

What annoyed me the most till now was reading empty data from my python scripts after powering the Yun.
That is because the wlan connection isn’t set-up in time after the bridge connection is made.

Also, using a sd card extends the boot process for a few seconds.

So i made a little sketch to avoid this behavior. This sketch will wait until Linux is completely booted without using delay() methods. When the linux side is fully booted and the arduino is being reset the script will only wait for a few seconds checking for serial input. If no input is found within time the bridge will setup.

I’ve also made it possible to interact with the console through the serial monitor. (or just watch the boot output).
You can press the enter key while booting to go into console mode. Exit the console mode by passing a tilde (~) as command.
The sketch will continue if you’ve only watched the console without pressing the enter key while booting.

I could wrap this into a c++ class if there is a demand for it. Just have to see how i can pass a function pointer so i can call the loopWhileBooting function (written in a sketch) form the c++ class.
i think this site put me in the right direction.

Library: see this reply

My boot Sketch:

setupUnix() accepts 2 integers as arguments:

  • initTimeout: the amount of time (in ms) to wait for serial data from the Linux side.
  • bootTimeout: the amount of time (in ms) to wait for new serial data after initTimout triggered the boot timer.

For my yun (with Sd card and Wlan slave) this works fine: setupUnix(1000,20000);. This could differ on other Yun’s. Adjust it to your needs…

The method void loopWhileBooting() runs as long as Linux is booting. (or when entered into console mode)

Extra: Led D13 blinks while booting or when entered the console mode.

/*
  Arduino Yun Linux starter
  Created by VinzzB
*/
#include <Bridge.h>
#define bootLed 13

unsigned int ledBlinkTime = millis();

void setup() {
  pinMode(bootLed, OUTPUT); //set LED pin
  
  digitalWrite(bootLed, LOW);
  
  Serial.begin(115200); //or set it to an appropriate value (same value as set in device manager on windows)).
  Serial1.begin(250000); 

  //Check if Linux is booting
  setupUnix(2000,20000); // void setupUnix(initTimeout, bootTimeout)

  //Setup bridge
  digitalWrite(bootLed, LOW);
  Bridge.begin();
  digitalWrite(bootLed, HIGH);
}

void loop() {
  //Bridge & Wlan online! Start sketch.
}

//This function Loops untill all boot data is processed and bootTimeout is reached.
void loopWhileBooting()
{
   bool useConsole = false;
   do //loop as long as we are in console mode. (enter console with enterkey. Exit console by sendeing a tilde (~)
   {
         //Send data from USB to UART
         int c = -1;
         c = Serial.read();
         if (c != -1) { 
               useConsole |= (c == 13); //enter console mode (13 = enter key)
               useConsole &= !(c == '~' ); //exit console mode
              if (useConsole) Serial1.write(c);
         }
       
         //Send data from UART to USB
         c = Serial1.read();
         if (c != -1) { Serial.write(c); } 
        
        //loops until bootTime timed-out.
        if ((millis() - ledBlinkTime) > 500) //every ~500ms
        { 
          digitalWrite(bootLed, !digitalRead(bootLed)); //toggle led D13 (Blink)
          ledBlinkTime = millis();
        }        
    } while (useConsole);
}

void setupUnix(unsigned int initTimeOut, unsigned int bootTimeOut)
{
  long unsigned initTimes[] = { millis(), millis() }; //set timers
  do { //init timeout    
    if(Serial1.available() > 0) { //run the next boot timeout block only when data is available
      while (Serial1.available() > 0 || ((initTimes[1] + bootTimeOut) > millis())) { //boot Timeout         
        if (Serial1.available() > 0) { initTimes[1] = millis();} //Flag boot timer        
        loopWhileBooting(); //process serial data (or just loop until timeout is reached)
      } //end while bootTimer    
      initTimes[0] = millis(); //Flag init Timer
    } //end if
  } while (Serial1.available() > 0 || ((initTimes[0] + initTimeOut) > millis())); //serial data available within initTimeOut? (cold-boot = data / Arduino Reset = no data)
}

Regards.
Vinzz

Nice. I like how you have a similar capability to YunSerialTerminal while it's booting. 8)

I did something similar (waiting for Linux to boot) using the hardware handshaking line here (see post #2), but of course mine does no serial interaction.

While it requires a setup step on the Linux side, and ties up a data pin, maybe it gives you an idea of knowing just when Linux is done, and potentially eliminate the need for one of your timeout values?

@VinzzB,
thanks for posting your code. I’m documenting the Yun on my website. You can read some of the posts at this link. Your solution/answer will be included in the listing.

TIA
Jesse

@ShapeShifter: Your solution using the handshake method looks quite good. I'll test it out later.

@jessemonroy: that is one of the reason why i posted my sketch here. Share it as much as you want. :-)

I did a revision of my own code. While doing that i decided to create a library from it. (for C++ learning purposes)

See attachment for the library and an example.

Or copy paste the code:

C++ header

#ifndef YunBootInit_h
#define YunBootInit_h
 #include "YunBootInit.h"
  #include "Arduino.h"
  class YunBootInit
  {
 public:
 YunBootInit(const unsigned int initTimeOut , const unsigned int bootTimeOut );
 bool isBooting();
 
 private:
 
 unsigned int _initTimeOut;
 unsigned int _bootTimeOut;
 long unsigned _initTime;
 long unsigned _bootTime;
 bool _running;
 bool _isBooting;
 
 void setTimers(); 
  };
  #endif

C++ Code

#include "YunBootInit.h"
#include "Arduino.h"

 YunBootInit::YunBootInit(const unsigned int initTimeOut = 1500, const unsigned int bootTimeOut = 20000)
 {
 _initTimeOut = initTimeOut;
 _bootTimeOut = bootTimeOut;
 setTimers();
 _running = true;
 isBooting();
 }
 
 bool YunBootInit::isBooting()
 {
 if(Serial1.available() > 0)
 {
 _isBooting = true; //set boot Timer flag
 setTimers(); //update all timers
 } 

 if (_bootTime + _bootTimeOut < millis() && _isBooting)
 {
 _isBooting = false; //Go back to init Timer
 _initTime = millis(); //reset init timer.
 } 
 return (_isBooting || _initTime + _initTimeOut > millis()); //Still running?
 }
 
 void YunBootInit::setTimers()
 { _initTime = millis(); _bootTime = millis(); }

Arduino Example Sketch:

#include <YunBootInit.h>
#define ledPin 13

void setup() {

  YunBootInit YunInit(1000,20000);
  pinMode(ledPin,OUTPUT);
    digitalWrite(ledPin,LOW);
  Serial.begin(115200); //or 9600, ...
  Serial1.begin(250000);  

  while(YunInit.isBooting())
  {
        //Linux to USB Serial Monitor
       int c = Serial1.read();
       if (c != -1) Serial.write(c);
  }  
  
 // Bridge.begin(); //start bridge...
    digitalWrite(ledPin,HIGH); //done
}

void loop() {
  // put your main code here, to run repeatedly:
}

It is not easy to think in a loop whole the time. :wink:

Edited: moved YunInit declaration from global to Setup() method…

YunBootInit.zip (2.55 KB)

I'm not sure that deleting YunInit at the end of the loop will actually accomplish anything useful. It will destroy the object, but since it was statically allocated globally, it will not free up any memory space. In fact, it will probably try to free the memory and return it to the heap, but since it was never allocated with new, that will likely cause big problems.

Since you're not using it outside of setup(), if you declared YunInit within setup(), it will be allocated on the stack, and will be automatically released when setup() returns. (I'm guessing Jesse won't like this, he seems to eschew any function local variables, but I think this is an ideal application for one.)

@ShapeShifter. Thanks for your answer. now that you say it. Delete will not do anything idd.

I' don't clearly understand the way of working with memory allocations in C++ yet.

When should you delete (free-up memory) of an object? I'm writing a HueBulb C++ class.

I use a globally allocated array of those objects hueBulb* (dynamic alloc). When i renew these objects i first do delete [] HueBulbs before filling it up with objects again. This seems to work. Is that the correct way? Or i'm i still missing something?

C++ is new for me. I normally write code in C# and Java. (for my job)

You could idd declare and initialize it within the Setup() method so it goes out of scope when Setup() returns. I'm going to change that in my lib. Thanks for that! it was late yesterday. :sleeping:

VinzzB: When should you delete (free-up memory) of an object? I'm writing a HueBulb C++ class.

The short answer: you call delete once and only once for every object you created with new. You never call delete more than once for an object, you never call delete for an object that is statically allocated (as in the YunInit object in post #4) and you never call delete for an object allocated at a specific address by the new(place) operator.

Basically, if the system created the object for you, like the global YunInit above, or a local YunInit in a function, you don't call delete. For example, this one does not need a delete:

void setup()
{
   YunBootInit YunInit(1000, 20000);

   // More code here
}

A delete is not needed here because the object itself is automatically allocated on the stack when the function begins, so it is automatically deleted (and its destructor called) when the function exits.

This example DOES need a delete:

void setup()
{
  YunBootInit *YunInit = new YunInit(1000, 20000);

  // More code here

  delete YunInit;
}

In this case, it is a pointer to the object that is allocated on the stack when the function begins, and only the pointer goes away when the function exits. The object itself was explicitly allocated dynamically on the heap using the new operator, so it must be explicitly deleted when it is no longer needed.

The difference between these two examples is the use of a pointer. When the object itself is on the stack, the compiler knows that it is going away when the function exits, so the destructor (delete) is automatically called. But when it's a pointer that's on the stack, all the compiler knows is that the lifetime of the pointer is going away, and it leaves it up to you to delete it when appropriate since it doesn't know anything about your intentions toward the object it points to:

  • Were you done with the object and want to delete it?
  • Did you pass that pointer to another function, and it saved it somewhere so it can be accessed later?
  • Do you want the object to stick around and keep doing something (perhaps you saved a delegate (Microsoft's terminology) or a closure (Borland's terminology) to a member function for later access)?

that’s a well described answer. Thank you! I think i get it now. so only when initializing an object using a new keyword needs to be freed up manually.

This code seems to be correct then:

HueBulb* hueBulbs; //Global dynamic array

void setup()
{ receiveData(); }

void receiveData()
{
   delete [] hueBulbs; //is this wrong when huebulb isn't initialized yet (on first iteration)? 
   hueBulbs = new HueBulb[6]; //(is actually dynamic in size by getting count from server).
    //Get & Do something with data...
}

Even the delete call on it’s first iteration seems to be harmless.

I did learn a lot of c++ over the past few days, it’s fun to write. :slight_smile:

btw: I’m going a bit off-topic. Sorry for that.

Edit: did some research on the web and found a site that explains it very well (with arrays) C++ Tutorials - Lesson 24: Arrays and Pointers of Classes .

Converted my code above into:

int hueArrayLength = -1;
HueBulb* *hueBulbs; //Global dynamic array to pointers (HueBulb *hueBulbs[20]; = would buffer 20 pointers max)

void setup()
{ receiveData(); }

void receiveData()
{
    if (hueArrayLength != -1)
      for (int x=0; x <= hueArrayLength;x++)
        delete hueBulbs[x];
delete hueBulbs;

int bulbsFound = 5; //starts counting at 1

hueBulbs = new HueBulb*[bulbsFound ];

for(x=0;x<hueBulbs;x++){
   hueBulbs[x] = new HueBulb();
   hueBulbs[x]->ParseData("some data");
}
hueArrayLength = bulbsFound -1; //5 bulbs found. (start at 0)
}

I’m just playing with the code to get it right. In my final project i will update the existing objects instead of removing and re-inserting the objects on each update. But this could be faster with less code. Still figuring that out. At the end, if the hardware is wired correctly, it all depends on the code. :slight_smile:

Still got one minor question: is there a way to make hueArrayLength obsolete? can i use sizeof() on an array with pointers?

It’s been a few years since I was heavy into C++, most of my recent time has been spent in straight C with some occasional C# (which has a lot of the same object orientation as C++, but a completely different memory management model.) You’re getting into some more advanced topics, and using some constructs I normally didn’t use.

VinzzB:
HueBulb* hueBulbs; //Global dynamic array

I’m not a fan of this construct. Without your comment, it looks like a pointer to a single object, rather than an array of actual objects.To create this array of objects, all of the objects are created at once, using a default constructor. All objects are also deleted at once. This means that you can’t delete and recreate a single object, only the whole batch. This limits your flexibility.

delete hueBulbs; //is this wrong when huebulb isn’t initialized yet (on first iteration)?

Deleting a pointer with a NULL value has no effect. Deleting a pointer with an uninitiated non-NULL value has a disastrous effect. Your best bet is to explicitly initialize the pointer to NULL before this first delete to make sure it doesn’t cause problems. Do it in the declaration or in setup().

btw: I’m going a bit off-topic. Sorry for that.

Hey, it’s your topic! :wink:

HueBulb* *hueBulbs; //Global dynamic array to pointers (HueBulb *hueBulbs[20]; = would buffer 20 pointers max)

I like this construct better. The double pointer shows that this is more than just a pointer to an object, which takes away some of the ambiguity of the prior construct. While it takes more work to create the array of pointers, and then create each individual object, it lets you use constructors other than the default (no parameters) constructor, and it lets you delete and re-create them individually (even though you aren’t doing this in your later example.)

if (hueArrayLength != -1)

I’m curious why are you using -1 as a magic number to indicate an empty array? Using zero would be more intuitive (after all, an empty array has zero elements, not -1 of them.) It also lets you simplify this guarding IF statement since zero is considered false, and non-zero is true. After all, the name is implying that it holds the length of the array, in which case you wouldn’t subtract one. If you really want to subtract one, then a better name would be hueArrayLastIndex.

Assuming you want to keep the hueArrayLength name and the semantics that go with that name (which is what I would do) your logic would change around a little bit. It would eliminate the need for the subtraction when converting bulbsFound into hueArrayLength, and would change the FOR statement slightly (taking out the equals in the termination comparison.) Another concern is that you may be creating and deleting the base array of pointers even when there are no bulbs found. I don’t really like that idea.

Taking all that into account, this is how I would handle the array creation/deletion:

void receiveData(int bulbsFound)
{
   // Delete the existing array of objects
   if (hueArrayLength)
   {
      // There is an array, so step through each element and delete it.
      for (int x=0; x<hueArrayLength; x++)
         delete hueBulbs[x];

      // Delete the underlying array of pointers
      delete hueBulbs;
   }

   if (bulbsFound)
   {
      // Found at least one bulb, so create the underlying array of pointers
      hueBulbs = new HueBulb*[bulbsFound];

      // Create an object for each bulb found
      for(x=0; x<hueBulbs; x++)
      {
         hueBulbs[x] = new HueBulb();
         hueBulbs[x]->ParseData("some data");
      }
   }
   else
      // No bulbs found, zero out the array pointer to prevent confusion
      hueBulbs = NULL;

   // Save the new array length
   hueArrayLength = bulbsFound;
}

NOTE: I have not compiled this!

I added some braces to the initial guarding IF statement, so that the array is only deleted if there is at least one element, and the code doesn’t create the array if there are no new objects to be created. Instead, it zeros out the array pointer, both to signal that there is nothing there, and to prevent an error if it should ever be deleted. Now, hueArrayLength is really the length of the arrray, and not the index of the last element. Therefore, any loop using this value needs to end while less than the value, not less than or equal.

Still got one minor question: is there a way to make hueArrayLength obsolete? can i use sizeof() on an array with pointers?

Not really. Given these declarations, and assuming sizeof(short) is 2. and sizeof(pointer) is 4:

short  array1[10];
short *array2 = array1;
short  array3[] = {1, 2, 3, 4};

sizeof(array1) would return 20, since it was passed the actual array, and the size of the array is known.

sizeof(array2) would return return 4, since it was passed a pointer to the array, even though it points to an array.

sizeof(array3) would return 8, since again it was passed the actual array, and the size of the array is known.

To compute the number of elements in an array, one could use this code:

(sizeof(array) / sizeof(array[0]))

In the case of array1, sizeof(array1) is 20, sizeof(array1[0]) is 2, so the result of the division is 10. Correct.

In the case of array2, sizeof(array2) is 4, sizeof(array2[0]) is 2, so the result of the division is 2. WRONG!

In the case of array3, sizeof(array3) is 8, sizeof(array3[0]) is 2, so the result of the division is 4. Correct.

When dealing with just the pointer, sizeof() will rarely give you the size you want, and is not the way to do it. You really will need to have the separate variable to track the size. You could wrap the array into a class that manages it, but all that would do is move that size tracking variable into the class, it would not eliminate the need for it.

ok, That's clear to me. Thanks for the contribution shapeshifter!

Hello,

Thank you for the post, I have used the YunBootInit Class, my arduino mega & Dragino Yun detect good the boot event, but the sketch is reseted after the linux booting, so I have like two starting event, I don’t found the function which reset the arduino sketch ?!.

Thank you for your help.

kiman26: my arduino mega & Dragino Yun detect good the boot event, but the sketch is reseted after the linux booting, so I have like two starting event, I don't found the function which reset the arduino sketch ?!.

I don't have any specific experience with the Dragino Yun shield, and there may be differences from an actual Arduino Yun board. But the first place I would look on the Linux side is in /etc/rc.local which is the file that is run when Linux is finishing the boot process. In my case, I sometimes do want the sketch to be restarted once Linux has finished booting, so have a line in my rc.local which reads reset-mcu

Maybe you have something similar in your /etc/rc.local?

Here are the contents of /etc/rc.local

# Put your custom commands here that should be executed once
# the system init finished. By default this file does nothing.

exit 0

it always restarts twice !

Hmmm… not much there. It’s very different from the rc/local of an official Yun board. The start-up sequence is apparently yet another significant difference between the Dragino shield and the official Yun board. Your best bet might be to bring this topic up with the folks at Dragino?