WendyOS Docs
AdvancedWendy Lite

Wendy Lite StdIO

On Wendy Lite, a WASM app can print data to the standard output. When developed in Swift, the app typically uses print() to do so.

Wendy Lite StdIO

On Wendy Lite, a WASM app can print data to the standard output. When developed in Swift, the app typically uses print() to do so.

A native app can use printf() or any C API related to stdout. It can also use write() on STDOUT_FILENO. And finally, it can also use the ESP-IDF log routines, named ESP_LOGx().

In all these cases, the output goes to these destinations:

  • UART: Even if slow and archaic, this is the primary destination. Bootloader messages, and any message related to a runtime fatal error (assertions, crashes, ...), are output only on the UART interface.
  • USB-Serial-JTAG (USJ): In the modern era, we always use USB to connect the computer to the device. This allows flashing the firmware, running the debugger and displaying logs.
  • WendyCom connection: when the device is controlled remotely via the WendyCom protocol, the client can attach to the device and collect all outputs.

Implementation

  • ESP_LOGx() calls are redirected to stdout.
  • stdout is a stdlib FILE opened on /dev/console.
  • /dev/console is managed by the wendy_stdio component. It implements the VFS which redirects the output to the UART, to the USJ and to any additional subscriber.
  • wendy_com_stdio subscribes to wendy_stdio and stores the output in a ring buffer, making the collected data available to the WendyCom client.

There is one caveat: when the output data is collected by the WendyCom client, wendy_com is in charge of draining the ring buffer. wendy_com runs in the com thread. Therefore, the com thread must never block and, in particular, it must never block by writing logs when the ring buffer is full. This would result in a deadlock.

To mitigate this problem, we adopted two rules:

  1. The com thread must never write to stdout or stderr. Note that these FILEs have their own locks, which makes it impossible to prevent com thread deadlocks other than by avoiding the com thread writing to them in the first place.
  2. Logs generated by the com thread by calling ESP_LOGx() go through a special path that never blocks.

When invoked in the com thread, ESP_LOGx() works in this way:

  1. wendy_com_stdio subscribes to the ESP_LOG mechanism and intercepts the logs coming from the com thread.
  2. wendy_com_stdio puts the data into the ring buffer, in non-blocking mode.
  3. wendy_com_stdio delivers the same data to any subscriber.
  4. Wendy_USJ subscribes to wendy_com_stdio, gets the com thread logs from it and prints them on the USJ output.

On this page