Squirrel programs, both on the device and as agents, have to be written in an “event-driven” style, where basically the system runs the main loop for you, and all the code that you write hangs off it as handlers for individual events. (That’s because there are other, system, event handlers also hung off the same main loop – for handling network messages, for instance.) While this is a well-known way of writing, say, UI code or server software, it’s less common in embedded programming, where everyone’s more used to writing their own main loop. If you attempt to do that on an imp, though, you’ll find that other important things, including network messages, don’t get handled.
Fortunately for the status quo, there is a way to write (what looks very like) your own main loop – yet still leave the system event handlers running. It relies on an obscure (and, frankly, under-documented) feature of Squirrel: generators.
Let’s start by looking at the code:
`local looper;
function pause(sec)
{
return imp.wakeup(sec, function() { resume looper; });
}
function mainloop()
{
while (1) {
hardware.pin1.write(1);
yield pause(1.0); // Line 12
hardware.pin1.write(0);
yield pause(1.0); // Line 14
}
}
looper = mainloop(); // Line 18
resume looper; // Line 19
`
That function “mainloop” has a while(1) in it, which is normally a no-no – but inside that loop it repeatedly yields (lines 12 and 14). Every time Squirrel executes a “yield”, the current function stops executing – but keeps all its internal state, such as local variables – and it starts again when you “resume” it.
The syntax is a bit unusual. The “mainloop” function is what Squirrel calls a “generator” (which means, a function that includes one or more “yield” statements). Calling such a function the first time (line 18) doesn’t actually cause the function to run: it just returns an object (the generator object), which you have to “resume” (line 19) to start it running.
Once “mainloop” is running, every time it yields it also calls that “pause” function, which sets a timer wakeup for N seconds later – a wakeup which, when it fires, resumes the generator again and continues execution. But meanwhile, before the wakeup fires, the rest of the system continues to run and to process network messages and so on.
Squirrel generators are similar to facilities in other languages known by names such as “co-routines” or “co-operative threads”.
Peter