Print flow#
How the parts of the driver stack work together: what happens during a job, how the bridge picks a printer, and the protocol the printer app and the bridge speak.
A job, step by step#
CUPS, or any IPP client, sends the document to the printer app. PAPPL renders it to an
sgray_8raster.Opening the device sends
openwith the printer’s address and model.Each page starts with
wait_ready. The bridge connects if needed and pusheswaitingevents (no-sheet,lid-open,printer-off, …), which the printer app shows asprinter-state-reasonsand job messages.page_begindescribes the page;linesmessages carry its 8-bit gray rows.page_endmakes the bridge fit the page to the sheet, stream it to the printer, wait for the motor stop and eject the sheet.After the job the printer app sends
close. The bridge keeps the connection untilidle_disconnect_minutespass without a command.
Note
Cancelling a job sends abort. It is the only command the bridge accepts while another one is pending.
Interrupted pages#
Opening the lid or running out of sheet during a page does not lose the page. The bridge keeps the prepared page, reconnects, ejects a sheet it senses right after the lid closes (its position is unknown), waits for a sheet and prints the page again. The job carries on as if nothing happened.
How the printer is chosen#
The printer app always names the printer: its open carries the address and model from the device URI.
Note
A URI without ?model= (printers registered by older versions) still works. The bridge then reads the model from the printer’s advertised name.
Commands without an address, such as the command line ones, resolve the printer in this order:
the address given with
-a/--address;else the printer connected or used last since the bridge started;
else the only printer of a known model a scan finds.
With several printers in range and nothing else to go on, the command refuses and lists their addresses. An open with another address than the current printer’s drops the current connection and retargets the bridge.
A scanned printer’s model is the one whose ble_name_pattern matches its advertised name. Devices of no known model are left out of every scan.
Socket protocol#
client → {"cmd": "lines", "count": 32, "bytes": 53760}\n<53760 raw bytes>
bridge → {"ok": true, "cmd": "lines", "rows": 32}\n
Every message is one JSON object on its own line.
A message with
"bytes": Nis followed by exactly N raw bytes (raster rows).Replies and pushed events use the same framing in the other direction.
Lines are limited to 64 KiB, payloads to 16 MiB.
One client at a time.
Replies carry ok and cmd.
Events#
While a long command is pending, the bridge pushes events:
Event |
Fields |
Meaning |
|---|---|---|
|
|
Transfer progress of the page |
|
|
Why the bridge is waiting |
|
Meaning |
|---|---|
|
The connection is being brought up |
|
Printer off, out of range or in use elsewhere |
|
Bluetooth unavailable |
|
Lid open |
|
No sheet loaded |
|
The last sheet ran out; a longer one is needed |
Commands#
Command |
Arguments |
Reply |
|---|---|---|
|
|
|
|
|
Connects (or reuses the held connection) with the profile of |
|
Ends the session’s use of the connection and starts the idle timer ( |
|
|
Drops the connection now |
|
|
|
Connected: |
|
|
|
|
|
Sets the timer when |
|
|
Returns once a sheet is seated; waits as long as it takes, pushes |
|
|
|
|
|
|
|
Prints and ejects; |
|
|
Connects if needed, ejects a loaded sheet, then pulses the feed three times |
|
|
|
Connects if needed, queries the device and writes a test page PNG to |
|
|
|
|
Stops a pending |
Tip
Writing your own client? The framing lives in phomemo.bridge.protocol, the commands in phomemo.bridge.session, and phomemo.bridge.client is the Python client the command line uses. The printer app’s C client is src/printer-app/bridge.c.