{"id":19203327,"url":"https://github.com/rouming/usb-parser","last_synced_at":"2025-02-23T05:45:23.189Z","repository":{"id":246644685,"uuid":"821736786","full_name":"rouming/usb-parser","owner":"rouming","description":"Tool which parses USB 2.0 protocol sampled by the oscilloscope ","archived":false,"fork":false,"pushed_at":"2024-06-29T11:02:59.000Z","size":5504,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-04T14:14:35.626Z","etag":null,"topics":["ds1054z","oscilloscope","parser","protocol","rigol","scpi","usb"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rouming.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2024-06-29T09:40:39.000Z","updated_at":"2024-06-29T11:03:02.000Z","dependencies_parsed_at":"2024-06-29T10:53:57.683Z","dependency_job_id":"36061035-9350-4d69-bd2c-1d19f3633286","html_url":"https://github.com/rouming/usb-parser","commit_stats":null,"previous_names":["rouming/usb-parser"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rouming%2Fusb-parser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rouming%2Fusb-parser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rouming%2Fusb-parser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rouming%2Fusb-parser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rouming","download_url":"https://codeload.github.com/rouming/usb-parser/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240275894,"owners_count":19775614,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["ds1054z","oscilloscope","parser","protocol","rigol","scpi","usb"],"created_at":"2024-11-09T12:47:54.070Z","updated_at":"2025-02-23T05:45:23.166Z","avatar_url":"https://github.com/rouming.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# USB 2.0 parser\n\nWhen you don’t have a USB sniffer at hand, usb capture and Wireshark\ndo not work at the lowest level of the USB protocol, but you need to\nfigure out why the device completes the transaction with an error,\nthen an oscilloscope and a Python script come to the rescue.\n\nLikely any modern oscilloscope supports\n[SCPI](https://en.wikipedia.org/wiki/Standard_Commands_for_Programmable_Instruments)\ncommands, at least my budget RIGOL DS1054Z does. This brings a great\npossibility to fetch sampled data, save it to a file and parse it.\n\nMy RIGOL DS1054Z can return up to 6M samples with a sampling rate of\n500MHz per channel (two channels will be required), which gives\napproximately 12ms of capture of the USB 2.0 protocol (low speed or\nfull speed devices). This is not too much, but should be enough to\ndebug an issue.\n\nTo receive samples from my RIGOL, I use the following python\n[tool](https://github.com/pklaus/ds1054z), which exports the whole\noscilloscope buffer as a CSV file. Easy!\n\n## Wiring\n\nTo intercept USB traffic, a USB cable should be modified. What's needed\nis a short USB 2.0 extension cable that you don’t mind cutting,\nbringing out three wires: D+ (green), D- (white), GND (black):\n\n![](images/cable.jpg)\n\nThe oscilloscope channel 1 is attached to D+ (green) and channel 2 is\nattached to D- (white). Do not forget about grounding.\n\n## Capture USB\n\nSetup oscilloscope trigger mode as `single` and connect a USB device\nto a host. Here is some captured USB communication:\n\n![](images/host-gamepad_2024-06-24_18-22-32.png)\n\n## Retrieve samples\n\nIn order to retrieve samples from my RIGOL DS1054Z I use the\n[ds1054z](https://github.com/pklaus/ds1054z) tool the following way:\n\n```shell\n$ ds1054z save-data --mode RAW\n```\n\nThis receives full osciloscope buffer, and the whole operation can take\nseveral minutes. Wait time can be minimized by retrieving only screen\nsamples (exactly those samples which you see on the screen of the\nosciloscope) by calling `save-data` without `--mode RAW`, e.g.:\n\n\n```shell\n$ ds1054z save-data\n```\n\nOperation completes and tool outputs resulting CSV file which can be\nused by the `usb-parse.py` script.\n\n## Parse USB 2.0\n\nExamples of intercepted USB communication can be found in the `data` folder\nas gzipped CSV files. For example the very first `SETUP` transaction looks\nas the following:\n\n```shell\n$ ./usb-parse.py data/host-gamepad_2024-06-24_18-23-23.csv.gz\n0.000023 | SETUP | ADDR 10 | ENDP 0 | CRC5 0x1b (OK) | -\u003e [d5 2d 0a d8]\n0.000091 | DATA0 | 00 09 00 00 00 00 00 00 | CRC16 0xf426 (OK) | -\u003e [d5 c3 00 09 00 00 00 00 00 00 26 f4]\n0.000109 |   ACK | -\u003e [d5 d2]\n0.000135 |    IN | ADDR 10 | ENDP 0 | CRC5 0x1b (OK) | -\u003e [d5 69 0a d8]\n0.000152 |   NAK | -\u003e [d5 5a]\n0.000197 |    IN | ADDR 10 | ENDP 0 | CRC5 0x1b (OK) | -\u003e [d5 69 0a d8]\n0.000225 | DATA1 |  | CRC16 0x0000 (OK) | -\u003e [d5 4b 00 00]\n0.000239 |   ACK | -\u003e [d5 d2]\n```\n\nIn this example a simple USB gamepad (low speed HID device) was connected to a\nhost and host starts a device enumeration procedure.\n\n## What's analysed\n\n`usb-parse.py` script tries to follow the `Chapter 7.1 Signaling` and\n`Chapter 8 Protocol Layer` of the USB 2.0 specification, so the following\ncan be analysed:\n\n* Device speed detection by first samples: low or full speed. Can be specified\n  manually by the `--speed (low|full)` parameter\n* SE0, SE1 and EOP bus states\n* NRZI decoding\n* Bit stuffing (except dribble)\n* CRC5 and CRC16 handling\n* Major PID types\n\n## What's missing\n\n* Transaction sequence details\n* Direction of the packet: host -\u003e device, device -\u003e host\n* Standard device requests (defined as `9.4 Standard Device Requests`\n  in the USB 2.0 specification)\n\n## Summary\n\nBy no means can this simple USB protocol analyser replace a\nprofessional USB sniffer due to oscilloscope limited number of samples\nit can provide, but sometimes a low-cost (budget and implementation\n-wise) solution can help to spot and fix the problem in low-level USB\ncommunication stack.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frouming%2Fusb-parser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frouming%2Fusb-parser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frouming%2Fusb-parser/lists"}