CMLabs · Psyclone AIOS

7. Whiteboards

Whiteboards are the system's shared short-term memory: catalogs specialised for storing messages, with a retrieval query language, keyed indexes, and visual browsing in PsyProbe.

What is a whiteboard?

A whiteboard is a special catalog that stores messages only. Where an ordinary module reacts to a message and forgets it, a whiteboard keeps it, indexed for later retrieval by other components. Every stored message is automatically indexed on its creation time; you can add further keyed indexes over the message contents. PsyProbe shows every whiteboard's stored messages with live filtering.

Declaring whiteboards and storing messages

The minimal whiteboard only receives messages addressed directly to it via a post's to= attribute (direct posts are also still routed to normal subscribers):

<whiteboard name="WB1" />
<!-- elsewhere: -->
<post name="Save" type="Data.Web" to="WB1" />

Usually a whiteboard subscribes by type, just like a module — wildcards included:

<whiteboard name="WB2">
  <trigger name="Ball"   type="ball.1" />
  <trigger name="Dialog" type="dialog.*" />
</whiteboard>

Retrieving messages

Retrieval is declared in the spec and executed from code. A <retrieve> names the source whiteboard and the constraints:

<retrieve name="r1" source="WB1" maxcount="10" />
std::list<DataMessage*> msgs;
uint8 status = api->retrieve(msgs, "r1");   // last 10 messages, any type
msgs = api.retrieve("r1")   # last 10 messages, any type (returns a list)

Retrieve attributes: type (PsyType filter), from/to (original sender/addressee), maxcount, maxage (stored ×1000; see the unit caveat below), tag, and the index selection key/keytype/start/end described below.

Status codes

Every retrieve/query returns one of the QUERY_* codes:

CodeValueMeaning
QUERY_FAILED1General failure
QUERY_TIMEOUT2No reply within the timeout
QUERY_NAME_UNKNOWN3No retrieve/query with that name
QUERY_COMPONENT_UNKNOWN4The source component does not exist
QUERY_QUERYFAILED5The component rejected the query
QUERY_SUCCESS6Results delivered
QUERY_NOT_AVAILABLE7Component not currently available
QUERY_NOT_REACHABLE8Component could not be reached

Keyed indexes

Besides the automatic time index, a whiteboard can index messages on a content entry. Declare the key on the whiteboard, then select it in the retrieve:

<whiteboard name="WB2" key="count" keytype="integer">
  <trigger name="Ball" type="ball.1" />
</whiteboard>

<retrieve name="r2" source="WB2" key="count" keytype="integer" />
std::list<DataMessage*> msgs;
// signature: retrieveIntegerParam(result, name, startInt, endInt, maxcount, maxage, timeout)
// messages whose "count" entry is between 2 and 8, at most 4 of them:
uint8 status = api->retrieveIntegerParam(msgs, "r2", 2, 8, 4);
// 5th arg is maxcount; 6th arg is maxage in MICROSECONDS (here 100 ms):
status = api->retrieveIntegerParam(msgs, "r2", 2, 8, 4, 100000);
# retrieveIntegerParam(name, startInt, endInt, maxcount, maxage_us, timeout)
# messages whose "count" entry is between 2 and 8, at most 4 of them:
msgs = api.retrieveIntegerParam("r2", 2, 8, 4)
# 4th arg is maxcount; 5th arg is maxage in MICROSECONDS (here 100 ms):
msgs = api.retrieveIntegerParam("r2", 2, 8, 4, 100000)

Valid keytype values are string, integer, float/double and time (the default). Range bounds go in the retrieve's start/end attributes or the ranged retrieve calls, interpreted per keytype. Additional keys can be declared with repeated key=/keytype= pairs or <key name type> children.

There are four ranged retrieve calls, one per key type, all with the same shape (result, name, start, end, maxcount, maxage, timeout) (Python drops the first arg and returns the list): retrieveIntegerParam, retrieveFloatParam, retrieveStringParam and retrieveTimeParam. maxcount caps how many messages come back (0 = all); maxage is a microsecond window against each message's creation time (0 = no age limit); timeout is milliseconds.

Unit caveat. The ranged API calls take maxage in microseconds. The XML <retrieve maxage=>/<query maxage=> attributes are parsed as a value ×1000 and the exact wall-clock unit of that attribute is being confirmed against the engine build — if you need a precise age window, prefer the API call with an explicit microsecond value.
Note. The whiteboard's root= attribute (on-disk persistence) is currently parsed but not acted on Stub — treat whiteboard contents as in-memory. Use maxcount/maxsize to bound memory, and a Replay Catalog (chapter 8) for durable recording.

The whiteboard in the dataflow

Sensorpost: ball.1 Loggerpost to="WB2" Whiteboard WB2 time index (automatic) key: count (integer) trigger: ball.1 Analyserapi->retrieve("r2") PsyProbeStored Messages tab subscription direct to= retrieve / reply live view
Messages reach the whiteboard by subscription or direct to= addressing; consumers pull them back with declared retrieves; PsyProbe browses the store live.

Free-form queries

Whiteboards (like all catalogs) also accept free-form <query> declarations for cases retrieves don't cover — a query names a source and optional constraints (maxcount, maxage, key, value, operation…) and is executed with api->queryCatalog(…). The full query mechanism, including writing your own catalog that answers queries, is covered in Catalogs.

Whiteboards in PsyProbe

Every whiteboard gets a Stored Messages tab in PsyProbe showing its contents live, with a filter line for free text, message count, size and age — ideal for verifying that the right messages are being captured. Hovering a message shows its full content; clicking opens it in a static window. The usual component tabs (Performance, Activity, Subscriptions) are there too. See PsyProbe.

Tip. A wildcard whiteboard like <whiteboard name="MessagesOfInterest"><trigger name="d" type="dialog.*" />…</whiteboard> is a cheap, non-intrusive debugging tap: it records interesting traffic without touching the modules that produce it.
Psyclone AIOS · CMLabs