-
Notifications
You must be signed in to change notification settings - Fork 29
feat(canopen): USB<->CAN bridge example + WebUSB/Web Serial CAN console #748
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
68ee5a2
feat(canopen): USB<->CAN bridge example + WebUSB/Web Serial CAN console
finger563 5626ab5
refactor(canopen): migrate CAN bridge to v2 stream_frame framing + ad…
finger563 9210757
fix(canopen): address CAN bridge review comments + register example i…
finger563 ca2877d
fix(canopen): CAN bridge handler ignores reply-flagged frames
finger563 fb8cb56
fix(canopen): make can_console.html parser correlation-aware (v2 opti…
finger563 3ddecbe
fix(usb_device): give write_cdc the same all-or-nothing backpressure …
finger563 5502782
docs(canopen): address CAN console review - a11y labels, v2 header do…
finger563 9d4aae6
fix(usb_device): make write_cdc/write_vendor truly all-or-nothing for…
finger563 ae6e9e1
fix(canopen): CAN console review round 2 - WebUSB partial write, boun…
finger563 58e12ce
fix(canopen): final review nits - shared USB write timeout, valid met…
finger563 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| # The following lines of boilerplate have to be in your project's CMakeLists | ||
| # in this exact order for cmake to work correctly | ||
| cmake_minimum_required(VERSION 3.20) | ||
|
|
||
| # NOTE: the IDF component manager is intentionally left ENABLED here (unlike most | ||
| # espp examples) so it can fetch the managed `espressif/esp_tinyusb` dependency | ||
| # declared by the usb_device component. To avoid the manager scanning every espp | ||
| # component manifest (some board components declare target-specific constraints | ||
| # that would fail on esp32s3), EXTRA_COMPONENT_DIRS is narrowed to just the | ||
| # components this example uses; the in-repo espp components there satisfy the | ||
| # `espp/*` dependencies locally. | ||
| include($ENV{IDF_PATH}/tools/cmake/project.cmake) | ||
|
|
||
| set(EXTRA_COMPONENT_DIRS | ||
| "../../../components/base_component" | ||
| "../../../components/dispatcher" | ||
| "../../../components/format" | ||
| "../../../components/logger" | ||
| "../../../components/stream_frame" | ||
| "../../../components/task" | ||
| "../../../components/twai" | ||
| "../../../components/usb_device" | ||
| ) | ||
|
|
||
| set( | ||
| COMPONENTS | ||
| "main esptool_py base_component dispatcher format logger stream_frame task twai usb_device esp_tinyusb" | ||
| CACHE STRING | ||
| "List of components to include" | ||
| ) | ||
|
|
||
| project(can_bridge_example) | ||
|
|
||
| set(CMAKE_CXX_STANDARD 20) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| # USB <-> CAN Bridge Example | ||
|
|
||
| Turns an ESP32-S3 into a **WebUSB / Web Serial CAN interface**: the hosted | ||
| [CAN console web app](https://esp-cpp.github.io/espp/apps/can_console.html) | ||
| connects over the native USB and can | ||
|
|
||
| - **send** CAN frames as a normal, ACK-ing bus participant ("master"), and | ||
| - **inspect** the bus — stream every received frame; in *listen-only* mode the | ||
| node is a passive sniffer that never ACKs or transmits. | ||
|
|
||
| It bridges the ESP32-S3 TWAI (CAN 2.0) controller to the host over USB using the | ||
| espp `stream_frame` framing and an `espp::Dispatcher` (this example owns | ||
| **module id 5**). The same framed protocol is exposed on both the USB **vendor** | ||
| interface (WebUSB) and a **CDC** interface (Web Serial), so the web app can use | ||
| either transport. The system console/logs stay on the separate built-in | ||
| USB-Serial-JTAG. | ||
|
|
||
| ## Wiring | ||
|
|
||
| Connect the TWAI TX/RX GPIOs to a CAN transceiver (e.g. SN65HVD230, TJA1050) on | ||
| a properly terminated (120 Ω) bus. Defaults (change in `can_bridge_example.cpp`): | ||
|
|
||
| | Signal | GPIO | | ||
| |--------|------| | ||
| | TWAI TX | 17 | | ||
| | TWAI RX | 16 | | ||
|
|
||
| Listen-only mode monitors an existing bus without a transceiver ACKing, but a | ||
| transceiver is still required to receive the differential signal. | ||
|
|
||
| ## Protocol (module 5) | ||
|
|
||
| Framed with `stream_frame` and routed by `espp::Dispatcher`. The full base | ||
| header order on the wire (all multi-byte fields little-endian) is: | ||
|
|
||
| ``` | ||
| [magic u16 "OT"][flags u8][module u8][type u8][len u32][payload…][crc32 u32] | ||
| ``` | ||
|
|
||
| The base header is 9 bytes. `module` is **5** for this bridge. `flags` bit0 = | ||
| reply (0 = host→device request, 1 = device→host reply/event), bits 4-7 = | ||
| version = 1 — so a request `flags` byte is `0x10` and a reply is `0x11`. (v2 | ||
| also defines an optional correlation-id field gated by `flags` bit1, inserted | ||
| between `type` and `len`; the CAN bridge never sets it, so its frames always use | ||
| the 9-byte base header.) `crc32` covers the header + payload. Host→device | ||
| requests use type high-nibble 5; device→host replies/events use high-nibble D. | ||
|
|
||
| | Type | Dir | Meaning | | ||
| |------|-----|---------| | ||
| | `0x50` CAN_TX | H→D | transmit a CAN frame | | ||
| | `0x51` SET_CONFIG | H→D | `[baudrate u32][mode u8][rsv u8]` (mode 0=normal, 1=listen-only) | | ||
| | `0x52` START | H→D | bring the bus up with the current config | | ||
| | `0x53` STOP | H→D | take the bus down | | ||
| | `0x54` GET_STATUS | H→D | request a STATUS reply | | ||
| | `0xD0` CAN_RX | D→H | a received CAN frame | | ||
| | `0xD1` OK | D→H | ack | | ||
| | `0xD2` ERROR | D→H | `[code u32][utf8 message]` | | ||
| | `0xD3` STATUS | D→H | `[baudrate u32][mode u8][running u8][rx u32][tx u32][err u32]` | | ||
|
|
||
| A CAN frame is encoded as `[id u32][flags u8][dlc u8]` optionally followed by | ||
| `dlc` data bytes, where `flags` bit0 = extended (29-bit) and bit1 = RTR. The | ||
| data bytes are present **only for non-RTR frames**: an RTR frame is just the | ||
| 6-byte header even when its `dlc` is nonzero (the DLC is the requested response | ||
| length, not a data length). A client must therefore append no data for RTR | ||
| frames — the bridge encodes and expects none — so the payload is 6 bytes for RTR | ||
| and `6 + dlc` (6..14) otherwise. | ||
|
|
||
| The bus starts **stopped**: the host sets baudrate/mode with `SET_CONFIG`, then | ||
| `START`. `SET_CONFIG` is rejected while the bus is running (stop first). | ||
|
|
||
| ## Build & flash | ||
|
|
||
| ``` | ||
| idf.py set-target esp32s3 | ||
| idf.py build flash monitor | ||
| ``` | ||
|
|
||
| Then open the CAN console web app and Connect (WebUSB or Web Serial). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| idf_component_register( | ||
| SRC_DIRS "." | ||
| INCLUDE_DIRS "." | ||
| REQUIRES usb_device twai dispatcher stream_frame task logger | ||
| ) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.