[package] name = "flowrs-device" version.workspace = true edition.workspace = true publish.workspace = true rust-version.workspace = true authors.workspace = true license = "MIT OR Apache-2.0" description = "Host-side device HAL for FlowRS: serial + WebSerial instrument/board IO, with optional probe-rs firmware flashing." [dependencies] serde = { workspace = true } # The typed link's port (postcard values, the stand-in interface digest) over this crate's # byte ports: the same code the firmware on the other end runs. flowrs-hal = { path = "../flowrs-hal", features = ["link"] } # Native (desktop) — real serial ports + async wrapper; probe-rs flashing behind a feature. [target.'cfg(not(target_arch = "wasm32"))'.dependencies] # No default features, so no libudev. On Linux it only adds port metadata that serialport # reads from sysfs without it (USB VID/PID included), and linking it made every program # that depends on this crate need the target board's libudev to cross-compile. serialport = { version = "4", default-features = false } tokio = { version = "1", features = ["sync", "rt"] } tracing = "0.1" probe-rs = { version = "0.32", optional = true } uuid = { version = "1", features = ["v4"], optional = true } tokio-modbus = { version = "0.17.0", optional = true, default-features = false, features = ["tcp"] } # The VISA-free instrument transports (`visa`): HiSLIP, VXI-11, raw socket and USBTMC # drivers over flowrs-transport's sans-IO protocol code. flowrs-transport = { path = "../flowrs-transport" } # HiSLIP 2.0 TLS, on flowrs-tls's provider (aws-lc-rs, X25519MLKEM768 first). No default # features here: the provider is always named explicitly, never left to whichever rustls # features are unified into the build. Native only, so the browser build compiles no TLS. rustls = { version = "0.23.46", default-features = false, features = ["std", "tls12"], optional = true } flowrs-tls = { path = "../flowrs-tls", optional = true } # The typed link's host nonce, from the operating system's random source. getrandom = "0.3.4" # SCRAM-SHA-256 (IVI-6.5), the tls-server-end-point channel binding and certificate pins. sha2 = { version = "0.10", optional = true } hmac = { version = "0.12", optional = true } base64 = { version = "0.22", optional = true } # USBTMC on pure-Rust USB. 0.2.7 rather than the four-day-old 0.2.8. nusb = { version = "0.2.7", optional = true } # Browser — WebSerial via web-sys navigator.serial. [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = { workspace = true } wasm-bindgen-futures = "0.4" js-sys = { workspace = true } web-sys = { workspace = true, features = [ "Window", # The typed link's nonce in the browser: crypto.getRandomValues. "Crypto", "Navigator", "Serial", "SerialPort", "SerialPortInfo", "SerialOptions", "SerialInputSignals", "SerialOutputSignals", "ReadableStream", "WritableStream", "ReadableStreamDefaultReader", "WritableStreamDefaultWriter", "ParityType", "FlowControlType", # WebUSB — the door PICOBOOT and DFU go through. Both are USB protocols a page may drive: # PICOBOOT is a vendor-class interface, DFU is class requests on the control endpoint. # Neither is mass storage, which is the one class WebUSB may not claim. "Usb", "UsbDevice", "UsbDeviceFilter", "UsbDeviceRequestOptions", "UsbControlTransferParameters", "UsbRequestType", "UsbRecipient", "UsbInTransferResult", "UsbOutTransferResult", "UsbTransferStatus", # Endpoint discovery. picotool does not hardcode PICOBOOT's interface or endpoints — it # scans for the vendor-class interface with two endpoints, which sits at index 0 or 1 # depending on whether the device also mounts mass storage. Doing the same needs the # configuration descriptor. "UsbConfiguration", "UsbInterface", "UsbAlternateInterface", "UsbEndpoint", "UsbDirection", "UsbEndpointType", # WebHID — CMSIS-DAP is a HID protocol, so a DAPLink probe arrives here. "Hid", "HidDevice", "HidDeviceFilter", "HidDeviceRequestOptions", "HidInputReportEvent", ] } # Linux host IO — GPIO lines (gpiocdev, modern character-device ABI) and # I2C/SPI as embedded-hal 1.0 traits (linux-embedded-hal). Unlocks single-board # computers (Raspberry Pi, BeagleBone, Jetson) and the Qwiic/STEMMA I2C sensor # catalog. Target-gated, so non-Linux builds never see these deps. Only linux-embedded-hal's # I2C and SPI: GPIO goes through gpiocdev, and UART through serialport above. [target.'cfg(target_os = "linux")'.dependencies] # The kernel's CAN (`can::linux`): socket, CAN FD mode, receive timestamps and vcan creation # over netlink (MIT). No default features: no candump parser and no udev. socketcan = { version = "4.0.0", default-features = false, features = ["netlink"] } # recvmsg with the timestamp control messages, and send, on that socket: the frames are read # and written in the kernel's layouts by flowrs_hal::can::socketcan (MIT). The version # socketcan 4.0 builds on, so nothing new enters the lockfile. nix = { version = "0.31", default-features = false, features = ["socket", "uio", "poll", "time", "net"] } gpiocdev = "0.8.0" linux-embedded-hal = { version = "0.5.0", default-features = false, features = ["i2c", "spi"] } embedded-hal = { workspace = true } [dev-dependencies] [features] default = ["visa", "cdc"] # A USB CDC-ACM serial function driven directly over nusb (`link::CdcAcm`): a board's USB # serial without a kernel driver or a tty, for the typed link on a Mac or Windows. cdc = ["dep:nusb"] # The VISA-free instrument transports (`visa`): TLS, SASL and USB. On by default. A program # flowRS generates for a Linux board turns it off (`default-features = false`) and keeps # `linux_io`, serial and SCPI, so it cross-compiles without a C toolchain for aws-lc. visa = ["dep:rustls", "dep:flowrs-tls", "dep:sha2", "dep:hmac", "dep:base64", "dep:nusb"] # In-process instrument simulators (HiSLIP with TLS and SASL, VXI-11 with portmapper and # abort channel, raw socket, mDNS responder, LXI identification server). Tests here use # them; other crates enable this in their dev-dependencies to test against the same ones. sim = ["visa"] # Enable probe-rs debug-probe enumeration + firmware flashing (native only). probe = ["dep:probe-rs", "dep:uuid"] # Use the richer WebSerial options (parity / flow-control setters) where the # browser + web-sys expose them; off by default (browser defaults are used). web-serial-full = [] # Modbus RTU / TCP client (industrial fieldbus) via tokio-modbus. Native-only; # off by default to keep the base build lean. modbus = ["dep:tokio-modbus"]