Toit, infinite resilient application loops (try “catch”)

October 15, 2024 0 By addshore

Toit is a modern high-level language designed specifically for microcontrollers. I’m spending some time at work making use of it these days, and as it’s a younger language, there are not as many resources out there in comparison to others.

In Toit, you could write a very simple hello world application with the following code…

main:
    print "Hello world"Code language: PHP (php)

Say you wanted to get a new name from an external package to say hello to, you might do the following, which would call the method names.next, which can return a string, and print it to the user.

import somePackage show names

main:
    print "Hello world " + names.nextCode language: JavaScript (javascript)

To do this in a loop every second, your code might look something like this…

import somePackage show names

main:
    while true:
        print "Hello world " + names.next
        sleep --ms=500Code language: JavaScript (javascript)

If you wanted two separate tasks running with their own control flows, you might make use of tasks, and a second loop.

Here we have one that prints a name every 500ms, and one that prints the time every 1s.

import somePackage show names

main:
    task:: loopOne
    task:: loopTwo

loopOne:
    while true:
        print "Hello world " + names.next
        sleep --ms=500

loopTwo:
    while true:
        print "Current time " + Time.now.stringify[11..22]
        sleep --s=1Code language: PHP (php)

If names.next is the sort of thing that might throw an exception, or crash for some other unknown reason, the state of the app might end up a little wonkey, with loopTwo continuing to print the time, but loopOne having crashed.

The whole app started in main will continue running in this situation.

In order to avoid this and keep the loops restarting in case of any unhandled exception, we can wrap them in a try block.

We can abstract this try block away so that it can be used for as many loops as our application has.

import log

main:
    log.info "Application starting"
    task:: catchAndRestart "loopOne" (:: loopOne)
    task:: catchAndRestart "loopTwo" (:: loopTwo)
    log.info "Application started"

catchAndRestart name/string l/Lambda:
    while true:
        e := catch --trace:
            log.info "Running " + name
            l.call
    if e:
        log.error "Caught exception: " + e.stringify
        log.info "Restarting " + name

//... Including the same loops as aboveCode language: JavaScript (javascript)

I only wrote this little method today, and there might be better ways to achieve it, but right now I quite like it.