Fix a loop that failed on a board
A loop on a board reads a name nobody bound. The board stops it where it failed and keeps it, and sends the stopped machine to your laptop. At a prompt you look at it, bind the name, and send it back. The loop carries on from the step that failed, on the board, with the count it had. Nothing is reflashed.
You need: a board set up and open in
its terminal, the command line host, and
two terminals: the board’s, and a prompt in the directory the command
line was built in. You have them when the board’s terminal prints
=== ready, and a prompt answers : 23. The addresses below are one
network’s. Yours differ, and there are two to put in: the board’s, which
its terminal printed after outer: connected, ip, and the laptop’s,
which step 1 reads.
1. Open a prompt, and say where a fault should go
In the prompt’s terminal:
./o.se -f o.se.osen/osen.ose
The first time a prompt opens a network port, macOS may ask whether
o.se may accept incoming connections. Allow it, or nothing arrives.
Two lines at the prompt. The first defines a function that keeps what
arrives on a socket under the name /arrived and says so. The second
opens port 9999 and calls it whenever something comes in:
> /keep : ({ /_e/arrived : ((/s) /o/udp/recv, 0) /o/nth, ("a machine arrived") /o/println }, ["/s"]) /o/defn
/keep -> /_e
> (("0.0.0.0", 9999) /o/udp/sock/bind, /keep) /o/watch
: []
Now the laptop’s address, which the board needs:
> (() /addr/here) /o/println
: "192.168.1.107"
Tell the board where a fault should go. This line is a program, sent to the board over TCP and run there. The first address is the laptop’s, with the port you opened; the second is the board’s:
> ({ ("192.168.1.107:9999") /fault/to }, "tcp://192.168.1.101:8889") /o/eval/at
: []
The board’s terminal says fault/to: 192.168.1.107:9999.
2. Send the board a loop that fails
The loop adds /zy to a count every second and prints the count. Nothing
binds /zy, on the board or anywhere:
> ({ /n : 0, ({ /n : (/n, /zy) /o/add, (/n) /o/println }, 1000, "/count") /continue/every }, "tcp://192.168.1.101:8889") /o/eval/at
: []
A second later, the board’s terminal:
error: /zy is not bound. Did you mean /n?
ose: slot 0 faulted -- halted and parked.
fault/to: sent to 192.168.1.107:9999
and the prompt:
: "a machine arrived"
The loop stopped at the read it could not do. The board keeps it in its slot as it was at that moment, and a copy of that machine is at your prompt.
3. Look at it
What arrived is a bundle of two things: the machine, and the verb that says what the sender meant it for. The machine is the first:
> /m : (/arrived, 0) /o/nth
/m -> /_e
> (/m) /o/db
/o/db prints the machine whole. The parts that matter:
/stack : (
/n : 0,
: "/zy",
/error : [ 65550, "/zy is not bound. Did you mean /n?" ],
...
),
/env : (
/n : 0,
...
),
/pending : (
: [ "/!/os/g", "/$/n", "/o/println", "/!/os/C1" ],
...
: "/o/add"
),
The stack holds the error and the name it was reading. The environment
is the loop’s state, /n at 0. Pending is what the period had left to
do: finish the add, then the print. (/m) /o/backtrace lists the open
frames, and the end of the /o/db listing names the other verbs.
4. Bind the name, and send it back
Every repair answers a new machine and leaves /m as it was.
/o/machine/fix/bind binds the name the machine could not find, to the
value given, in the machine’s own environment:
> /fixed : (/m, 10) /o/machine/fix/bind
/fixed -> /_e
/o/machine/resume sends it to the board, named for the loop it came
from:
> (/fixed, "/count", "tcp://192.168.1.101:8889") /o/machine/resume
: []
The board’s terminal:
land: back into loop /count, slot 0
: 10
: 20
: 30
The machine went back into the slot it was parked in. The period that
failed carried on from the read of /zy, with /zy bound, and every
period since has it: the loop’s state is its environment, and the fix is
in it.
To stop the loop:
> ({ ("/count") /continue/stop }, "tcp://192.168.1.101:8889") /o/eval/at
What happened
- The board kept the failure. A loop whose period fails is parked in
its slot, as it was at the fault, on every host.
/fault/tois a standing rule: a copy of each kept fault goes to that address. - The copy is a value.
/o/db,/o/backtraceand the/o/machine/verbs work on it as on any value, and each answers a new machine. - The fix travelled, not the program. Nothing was sent to the board but the machine it already had, with one name bound.
If something goes wrong
| what you see | do |
|---|---|
no fault/to: line on the board after the line in step 1 |
the board’s address is wrong, or it has restarted onto a new one: read it again in its terminal |
| the board faults but the prompt prints nothing | the laptop’s address in step 1 is wrong, or the firewall blocked o.se |
ose: the handler for socket N raised, so it is no longer watched |
the /keep line was mistyped: type it and the /o/watch line again |
/arrived is not bound |
nothing has arrived: see the two rows above |
| anything else | press RESET, wait for === ready, and start again from step 1 |
Examples · Talk to a board · Microcontroller · Between hosts