Characterizing examples

Picking this 16739 comment into generalization, let’s think about what purposes examples serve:

  • Demos. Users flash this, and can right away explore what RIOT can do, play with it, learn the high-level concepts and verify their understanding of what their hardware can do.

    Examples: filesystem, gcoap, saul, nimble_heart_rate_sensor

  • Utilities: Similar to demos, but with the additional expectation that you’d just flash them and start using them in almost a productive setup.

    Examples: gnrc_border_router, maybe ccn-lite-relay

  • Scaffolding to start own applications: You can flash this, but usually you’d start editing there until you’re fed up with the “helloworld” name and copy what by now has become an own project of yours into a separate folder.

    Examples: gcoap (esp. server side), hello-world, usbus_minimal

  • Illustrations of concrete APIs and how to use them.

    Examples: the TCP Echo server of the abovementioned issue, dtls-echo, timer_periodic_wakeup

  • Build and hardware testing:

    Examples: everything in test

The reason I’m pulling test in here is that time and again when trying to understand an API I grep to the examples, find nothing, but the tests work perfectly fine to serve the “Illustration of a concrete API” case.

So far, I don’t have a point to make, but more of an open question:

Is the line currently drawn between tests and examples the right one? Do API examples water down the more read-to-start examples? Did we see feedback from newcomers who try to navigate the examples?

1 Like

I think I agree mostly with your assessment. However, I think tests also used to be, at least in the past, also be a place where to look up API usage.

Maybe, by your characterization, we should finally go ahead and add a sub-hierarchy within the examples directory. This at least seems a far more sensible and entry-level friendly hierarchy than hierarchies proposed in the past (e.g. by sub-modules).

[Seperate post in case this spins out into its own discussion]

Another aspect of examples, aside from characterization, I am a bit worried about tbh, is that many examples do not contain much of an example. gnrc_networking e.g. mostly contains the UDP usage code (with efforts being made to remove that too), but mostly shows which modules to include to get a certain set of functionality (and even that sometimes not really well, judging from the emails I sometimes get, asking why a node does not forward packets very well with gnrc_ipv6_default pulled in).

While I agree, that code duplication needs to be also addressed, I remember that I was quite confused in the beginning where all those nice shell commands came from. Maybe moving shell commands to their respective modules, using XFAs can help, but then again, as a beginner you do not always know where which module is located.

The UDP pointer is spot-on:

Code that can serve to illustrate a particular API can live anywhere, for example in a shell command.

(Granted, if tailored towards “compact but still shell command” or towards “teaching the API”, there’d be different outcomes. But that’s only for APIs that don’t have perfect usability ;-), and for as long as we’re not spot on there, there’s nothing wrong with any rough edges showing in the example code).

Maybe we can find ways to make them more visible in the documentation? (Rust will do this automatically for shipped examples in the future, but we wouldn’t limit ourselves to examples.)

Taking up the recent question of “Which boards can RIOTBOOT be used with”, part of a classification of examples could be a criterion (ideally expanded to a list in some documentation automatically, if one may dream) for which board this can meaningfully be used with.

(This is pulling the “bootloaders” into the discussion, but on a high level where tests and examples are lumped together, they should go in there too.)

On the “utilities” side, I’d like to add a few things just so they’re out. Note that some may do the same things but differ in their advertised metadata (eg. an output GPIO and a LED which has a color):

  • GNRC border router
  • “Just exposing the hardware there is through the PC connection there is”:
    • Keyboard (needs buttons with known semantics, exposed via BLE, USB or UART)
    • BLE dongle (exposed by USB)
    • 802.15.4 dongle (exposed by USB, I think there’s a protocol for something softmac-like)
    • IrDA (needs IR LED and photodiode with highpass, exposed by USB or serial)
    • Sound card (needs dac_play, possibly ADC, exposed by USB or Bluetooth)
    • Pixel or character display (char via UART or USB, pixel … is there an established USB proto for them?)
    • non-display LED control (needs SAUL LEDs backed by PWM, neopixels or DMX, not sure what a good backend is)
    • UART (exposed by USB) – I think there’s one of those in the tests
    • SD Card reader (exposed as block device or MTP)
    • any other low-level peripheral there is generic USB support for (I2C, SPI, GPIO, PWM, CAN?)
  • any of the above exposed via CoAP, once specified for CoAP
    • pixel display (in Rust modules, currently only for microbit pixel matrix)
    • keyboard and character display (sharing UART-over-CoAP interface)
  • piano / sound clip player
  • MP3 player (serving a dac_play from SD card; overlaps with sound card, might be one)
  • Door bell (might be trivial combination of “keyboard”, “serial over CoAP” and “piano”
  • Visual thermometer (might actually be a reactive SAUL serial demo combined with serial display and serial-over-CoAP)

There is an old PR that’d already resolve some of this: [RFC] tests: group applications in subdirectories by aabadie · Pull Request #15358 · RIOT-OS/RIOT · GitHub

With in mind, there might also be the category: “Build your own dev tools”. Things like a custom programmer might also fit into that category.