Skip to content

USB device inspection and host transport

This reference describes USB inspection, asynchronous transfers and SIS staging. Begin with Connect a device for the paced workflow.

symbian device list enumerates candidate Symbian handsets and joins host storage or serial-port associations from macOS IOService or Linux sysfs. device info always reads the active USB function map through the SDK's statically linked libusb backend. The OS inventory supplies host associations; libusb supplies the shared descriptor, endpoint, and transfer path. The OS adapter associates a mounted disk only when that disk is a child of the same USB device; a volume label or a coincidental mount name is not enough. symbian device info [--device SELECTOR] reports the descriptors and storage that the host can actually observe. The serial number is never printed; the selector contains a short hash of it, or the port location when no serial is available. Selectors should be rediscovered after reconnecting a device. With several candidates, specify the exact selector from device list. The CLI shows a readable device and storage summary by default. Use --output-format=json on device list, device info or other commands when a script needs the unchanged structured response.

device info also reports each host USB interface's configuration, number, class, subclass and protocol, plus any macOS serial-port path descended from that USB device. The human view leads with USB-standard roles, device-declared interface names, endpoint counts, alternate settings and bound host drivers; supported terminals color the roles and probe results. JSON retains the raw codes. A label such as PC Suite Services is device-declared metadata, not proof that its application protocol was opened. Zero endpoints describes the listed alternate setting only. interface_profile describes the USB class only. The standard roles follow the USB-IF class-code registry and CDC definitions. A usb-serial identity anchor is a truncated hash of the vendor ID and USB serial, independent of USB product ID. A port-location anchor is weaker and cannot prove the same handset after a mode change. Neither prints the serial.

For the observed Nokia 808 0421:05d1 CDC ACM configuration, device info also sends four bounded, read-only AT queries by default: AT+GCAP, AT+CGMI, AT+CGMM, and AT+CGMR. Use --no-protocol to show USB descriptors without opening the port. reported_identity retains the source label; firmware revision, date and RM code are parsed from the phone's AT reply, not authenticated against preserved firmware. No IMEI, IMSI, phonebook, message, dialing or settings command is issued. The port is opened for at most five one-second exchanges by default, or seven with --at-status, including the AT handshake. Its host terminal settings are restored. The ETSI AT command specification defines the identity queries; ITU V.250 defines +GCAP. These queries provide modem-reported identity. They do not supply a Symbian debugger transport.

To check a handset-side USB mode change, save a baseline before switching:

symbian device mode begin \
  --device SELECTOR --ticket .symbian/phone-mode.json
# Select PC Suite / Nokia Suite mode on the handset.
symbian device mode verify \
  --ticket .symbian/phone-mode.json

The ticket is created once with owner-only permissions and no raw serial. verify requires the same serial-derived anchor, then compares product ID and interface descriptors. It reports unchanged, device-unavailable, or usb-transition-observed. It does not label a changed USB configuration as a verified PC Suite protocol session. The CLI cannot select the mode on the phone; the owner makes that choice on the handset.

Inspecting the 808 in PC Suite mode

With PC Suite / Nokia Suite selected on the handset, use the exact selector from device list if more than one candidate is connected. The commands below run in order; each protocol step is opt in. JSON output is available with --output-format=json.

symbian device info --no-protocol
symbian device info --at-status
symbian device info --mtp
symbian device info --mtp-list 3
symbian device info --obex-connect

The first command maps all alternate settings, endpoint directions and transfer types, CDC unions, and interface associations without claiming an interface. --at-status adds fixed AT+CBC and AT+CSQ queries to the identity probe. The returned signal code 99 means unavailable, not a measured signal strength. --mtp opens a PTP/MTP session, reads device and storage metadata, and closes it. --mtp-list 3 additionally fetches at most three root object names per storage; it does not transfer file contents. Names are private device data and should be kept out of shared logs. --obex-connect claims only the PC Suite data interface, selects alternate setting 1, sends an OBEX Connect with the PC Suite FTP target, then sends Disconnect with the returned Connection ID and restores alternate setting 0. A successful Connect alone does not prove file browsing or any debugging command works.

The native host SDK includes symbian/host/libusb-1.0.a, symbian/host/include/libusb.h, and symbian/licenses/libusb-COPYING. The extension links the same libusb version statically, so the inspection CLI has no separate runtime libusb package dependency. The library is LGPL 2.1 or later; the pinned source is libusb 1.0.30 in the wheel dependency bootstrap. The SDK installer copies the archive and header into lib/host.

For a custom Python USB flow, symbian.device.usb.open_selected() returns a context-managed native session. AsyncUsbSession drives libusb from the current asyncio loop and returns Future[UsbCompletion]. The completion is a Pydantic model with an ID, status, byte count, and IN bytes:

import asyncio
from symbian.device.usb import AsyncUsbSession, open_selected

async def main():
    async with AsyncUsbSession(open_selected()) as usb:
        result = await usb.control_in(0x80, 0, 0, 0, 2)
        assert result.status == "completed"
        print(len(result.data))

asyncio.run(main())

The native session also exposes synchronous bulk, interrupt, and control transfers. Its explicit submit_* methods return transfer IDs; handle_events() returns typed native completions for callers driving libusb themselves. claim, set_alternate, release, cancel, poll_fds, next_timeout_ms, and descriptors are available. The inspection API returns Pydantic UsbProbe models, and list_devices() returns Pydantic UsbDeviceDescriptor models. Use model_dump(mode="json") at an output boundary. Default or unobserved optional fields are omitted.

AsyncUsbSession watches libusb file descriptors and a bounded timeout. Its native transfer Futures use A11's FutureToPython bridge; cancelling a Python Future cancels the libusb transfer. The libusb callback only records bounded completion data; Python result conversion and user continuations run after the callback returns. Keep compute-heavy continuations off the event loop. Native admission stops at 32 pending plus undrained results (64 KiB per transfer). Libusb already supports asynchronous writes, so this path needs no fiber or second scheduler.

symbian device install --project PROJECT [--device SELECTOR] builds the project through its selected SDK (when it has symbian-project.json), makes a reproducible unsigned SIS, checks it with the native SIS reader, and stages it as Installs/NAME-SHA256PREFIX.sis on one selected writable volume or, in PC Suite mode, on a writable MTP store with an unambiguous Installs folder. Pass --volume diskN if several mounted volumes qualify. --package FILE.sis instead stages an already built SIS. Staging verifies the readback SHA-256 and is idempotent; it never overwrites different content, and it requires the package size plus 16 MiB of free space. MTP uploads are limited to 16 MiB. The structured result state is awaiting-on-device-install, not installed. Finish other transfers, safely eject a mounted volume, and open the SIS on the handset to approve installation. The handset may reject an unsigned package or unavailable imports. The SDK does not yet observe the phone's installer registry or launch the application, so staging does not change the result to installed. Projects with [application] in symbian.toml package registration and localized caption resources for the application menu. Change caption and short_caption there; symbian init supplies defaults. The visible SDK includes the EPL-licensed rcomp host tool. The package reader checks embedded file hashes and destinations. Older projects without [application] remain executable-only packages and may have no menu entry.

If the phone lists an Installs child but refuses its metadata, the MTP stager skips that unreadable handle. It reports the count as unreadable_children when nonzero, uses a digest-derived filename to avoid replacing another package, and still requires a complete readback match for the selected SIS. A USB disconnect can clear stale MTP listings; retry after the device reappears in symbian device list.

For a selected device:

symbian device list
symbian device info --device usb:0421:05d0:…
symbian device install \
  --project ~/dev/symbian-app-3 --device usb:0421:05d0:…

The Gammu configuration guide describes Symbian remote access through an on-phone Bluetooth applet; its install command installs that applet rather than an arbitrary SDK application. An MTP product ID or USB vendor ID alone cannot establish a writable store or installer protocol. The reusable symbian.device.mtp.stage_sis adapter and native StageMtpSis API re-check the serial anchor, interface, required operations, writable store, folder, free space and existing filename before writing. The device installer is still a separate human action.

On Linux, mounted-volume association uses sysfs USB ancestry and /proc/self/mountinfo. The SDK provides no phone screenshot, process-debug, flashing, erasure, bootloader, partition, OTP, calibration or recovery endpoint.