{"id":28452538,"url":"https://github.com/surban/upc","last_synced_at":"2026-03-14T13:23:44.977Z","repository":{"id":199982319,"uuid":"704128329","full_name":"surban/upc","owner":"surban","description":"USB packet channel (UPC): provides a reliable, packet-based transport over USB.","archived":false,"fork":false,"pushed_at":"2025-07-28T12:44:28.000Z","size":114,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-28T14:37:20.720Z","etag":null,"topics":["channel","packet","rust","usb","webassembly","webusb"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/upc","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/surban.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-10-12T15:38:39.000Z","updated_at":"2025-07-28T12:44:32.000Z","dependencies_parsed_at":"2025-02-07T21:18:52.155Z","dependency_job_id":"6f488de4-9291-4636-96b8-b5406ff79ad1","html_url":"https://github.com/surban/upc","commit_stats":null,"previous_names":["surban/upc"],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/surban/upc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surban%2Fupc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surban%2Fupc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surban%2Fupc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surban%2Fupc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/surban","download_url":"https://codeload.github.com/surban/upc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surban%2Fupc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29880743,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-26T23:51:21.483Z","status":"ssl_error","status_checked_at":"2026-02-26T23:50:46.793Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["channel","packet","rust","usb","webassembly","webusb"],"created_at":"2025-06-06T18:11:42.782Z","updated_at":"2026-03-14T13:23:44.972Z","avatar_url":"https://github.com/surban.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"USB packet channel (UPC)\n========================\n\n[![crates.io page](https://img.shields.io/crates/v/upc)](https://crates.io/crates/upc)\n[![docs.rs page](https://docs.rs/upc/badge.svg)](https://docs.rs/upc)\n[![Apache 2.0 license](https://img.shields.io/crates/l/upc)](https://github.com/surban/upc/blob/master/LICENSE)\n\nUPC provides a reliable, packet-based transport over a physical USB connection.\nIt uses a vendor-specific USB interface with bulk endpoints and works with any\nUSB device controller (UDC) on the device side and any operating system on the\nhost side, including web browsers via [WebUSB].\n\nOn the wire, UPC uses a single vendor-specific USB interface with two bulk\nendpoints for data and control transfers for connection management.\nUnlike standard USB classes (CDC-ACM, HID, etc.) that require\nOS drivers or are limited to specific use cases, UPC operates as a\nvendor-specific interface — your application gets exclusive, direct access\nfrom userspace. Compared to using raw bulk transfers directly, UPC adds:\n\n* no OS driver interference — the vendor-specific interface is never claimed by the kernel,\n* driverless on Windows — automatically requests the WinUSB driver via Microsoft OS descriptors,\n* packet framing with preserved message boundaries,\n* connection lifecycle management (open, close, capability handshake),\n* independent half-close of send and receive directions,\n* liveness detection via periodic ping/status polling,\n* max packet size negotiation between host and device,\n* cross-platform support: native, Linux gadget, and WebUSB from one codebase.\n\nThe library offers an async [Tokio]-based Rust API (with futures `Sink`/`Stream` support) for\nboth the host and device side, making it easy to build custom USB communication\ninto your application. It contains no `unsafe` code.\n\nA [command-line tool](#cli-tool) is also included for testing, debugging and\nstandalone data transfer.\n\n[Tokio]: https://tokio.rs\n[WebUSB]: https://developer.mozilla.org/en-US/docs/Web/API/WebUSB_API\n\nUsage\n-----\n\nAdd `upc` to your `Cargo.toml` with the features you need:\n\n```toml\n[dependencies]\nupc = { version = \"0.9\", features = [\"host\"] }    # host side\n# or\nupc = { version = \"0.9\", features = [\"device\"] }  # device side\n```\n\n### Host side\n\n```rust,no_run\nuse upc::{host::{connect, find_interface}, Class};\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() -\u003e std::io::Result\u003c()\u003e {\n    let class = Class::vendor_specific(0x01, 0);\n\n    // Find and open the USB device.\n    let dev_info = nusb::list_devices().await?\n        .find(|d| d.vendor_id() == 0x1209 \u0026\u0026 d.product_id() == 0x0001)\n        .expect(\"device not found\");\n    let iface = find_interface(\u0026dev_info, class)?;\n    let dev = dev_info.open().await?;\n\n    // Connect and exchange packets.\n    let (tx, mut rx) = connect(dev, iface, b\"hello\").await?;\n    tx.send(b\"ping\"[..].into()).await?;\n    let reply = rx.recv().await?;\n    println!(\"received: {:?}\", reply);\n    Ok(())\n}\n```\n\n### Device side\n\n```rust,no_run\nuse std::time::Duration;\nuse upc::{device::{InterfaceId, UpcFunction}, Class};\nuse usb_gadget::{default_udc, Config, Gadget, Id, OsDescriptor, Strings};\nuse uuid::uuid;\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() -\u003e std::io::Result\u003c()\u003e {\n    let class = Class::vendor_specific(0x01, 0);\n\n    // Create a USB gadget with a UPC function.\n    let (mut upc, hnd) = UpcFunction::new(\n        InterfaceId::new(class)\n            .with_guid(uuid!(\"3bf77270-42d2-42c6-a475-490227a9cc89\")),\n    );\n    upc.set_info(b\"my device\".to_vec()).await;\n\n    let udc = default_udc().expect(\"no UDC available\");\n    let gadget = Gadget::new(class.into(), Id::new(0x1209, 0x0001), Strings::new(\"mfr\", \"product\", \"serial\"))\n        .with_config(Config::new(\"config\").with_function(hnd))\n        .with_os_descriptor(OsDescriptor::microsoft());\n    let _reg = gadget.bind(\u0026udc).expect(\"cannot bind to UDC\");\n\n    // Accept a connection and exchange packets.\n    let (tx, mut rx) = upc.accept().await?;\n    if let Some(data) = rx.recv().await? {\n        println!(\"received: {:?}\", data);\n        tx.send(b\"pong\"[..].into()).await?;\n    }\n\n    // Allow USB transport to flush before teardown.\n    tokio::time::sleep(Duration::from_secs(1)).await;\n    Ok(())\n}\n```\n\nSee the [examples](examples/) directory, [API documentation](https://docs.rs/upc),\nand [protocol specification](PROTOCOL.md) for more details.\n\nFeatures\n--------\n\nThis crate provides the following main features:\n\n* `host` enables the native host-side part,\n* `web` enables the web host-side part using [WebUSB] for device access and targeting WebAssembly,\n* `device` enables the device-side part.\n\nTo be useful, at least one of these features must be enabled.\n\nAdditionally, the feature `trace-packets` can be enabled to log USB packets at log level trace.\n\nRequirements\n------------\n\nThe minimum supported Rust version (MSRV) is 1.85.\n\nThe native host-side part supports Linux, macOS and Windows via [nusb].\nThe WebUSB host-side part works in browsers with WebUSB support (Chrome, Edge).\n\nThe device-side part requires Linux and a USB device controller (UDC).\n\n[nusb]: https://crates.io/crates/nusb\n\nCLI tool\n--------\n\nThe `upc` command-line tool can act as either the host or device side of a\nUPC connection, forwarding data between stdin/stdout and the USB channel.\nUse it to test and debug devices that use the UPC library, or as a standalone\ntool for transferring data over USB.\n\nInstall it with:\n\n```console\ncargo install upc --features cli,host         # host side only\ncargo install upc --features cli,device       # device side only\ncargo install upc --features cli,host,device  # both\n```\n\n### Device side\n\nStart a USB gadget and wait for a connection (requires root and a UDC):\n\n```console\nupc device\n```\n\nThis creates a USB gadget with default VID/PID and waits for a host to connect.\nData received from the host is written to stdout; data read from stdin is sent\nto the host. \n\n### Host side\n\nScan for all UPC devices on the system:\n\n```console\nupc scan\n```\n\nThis probes every vendor-specific USB interface and outputs one tab-separated\nline per discovered UPC channel:\n\n```text\n1209:0001       003:020         0       00\n```\n\nThe columns are: VID:PID, bus:address, serial, interface, subclass, info.\n\nUse `-v` for a human-readable listing of all USB devices and their interfaces.\n\nConnect to a UPC device and forward stdin/stdout:\n\n```console\nupc connect\n```\n\nWithout filter options, `connect` probes all vendor-specific interfaces to\nfind a UPC channel automatically. Use `--protocol`, `--subclass`, or `--interface` to\nconnect by class filter instead.\n\nLicense\n-------\n\nupc is licensed under the [Apache 2.0 license].\n\n[Apache 2.0 license]: https://github.com/surban/upc/blob/master/LICENSE\n\n### Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in upc by you, shall be licensed as Apache 2.0, without any\nadditional terms or conditions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsurban%2Fupc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsurban%2Fupc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsurban%2Fupc/lists"}