webapp_example

Example of the component espp/mcp266 v1.3.6
# MCP266 Web Console Example

Turns an ESP32-S3 into a **WebUSB / Web Serial front-end** for a Basicmicro
MCP266 motor controller: the hosted
[MCP266 console web app](https://esp-cpp.github.io/espp/apps/mcp266_console.html)
connects over native USB and can

- **configure** each axis' position loop (clamp + fallback P gain) and CiA 402
  software limits, and clear faults / e-stop,
- **command** profile-position moves (target, velocity, accel, decel), and
- **view** live per-axis status — position, velocity, DS402 state, target-reached
  — plus device telemetry (battery voltage, temperature).

Unlike the [CAN bridge](../../canopen/can_bridge_example) (which forwards raw CAN
and runs CANopen in the browser), this example runs the `espp::Mcp266` driver
**on the device** and exposes a small high-level protocol (see
`main/mcp266_protocol.hpp`, dispatcher **module id 6**), so the web app needs no
CANopen/DS402 knowledge. Both the vendor (WebUSB) and CDC (Web Serial) interfaces
carry the same protocol; the system console/logs go to **UART0** (set in
`sdkconfig.defaults`): on the S3 / P4, USB-Serial-JTAG shares the native USB
port's PHY with USB-OTG, which TinyUSB takes over.

## Wiring & configuration

The ESP32-S3 is the CANopen **master** of the MCP266 node. Connect the TWAI
TX/RX GPIOs to a 3.3 V CAN transceiver (e.g. SN65HVD230) on a 120 Ω-terminated
bus, at the baudrate configured on the MCP266 in Basicmicro Motion Studio.

Defaults (change in `main/mcp266_webapp_example.cpp`):

| Setting | Value |
|---------|-------|
| TWAI TX | GPIO 17 |
| TWAI RX | GPIO 16 |
| CAN baudrate | 1000000 |
| MCP266 node id | 10 |

## Protocol (module 6)

Framed with `stream_frame` and routed by `espp::Dispatcher`. Requests use type
high-nibble 6; replies/events use high-nibble E (reply flag set).

| Type | Dir | Meaning |
|------|-----|---------|
| `0x60` START | H→D | NMT-start the node + clear faults |
| `0x61` RESET_FAULTS | H→D | clear latched CiA 402 faults (both axes) |
| `0x62` RESET_ESTOP | H→D | attempt an e-stop reset |
| `0x63` CONFIGURE_POSITION_LOOP | H→D | `[axis u8][min i32][max i32][fallback_p i32]` |
| `0x64` SET_POSITION_LIMITS | H→D | CiA 402 software limits: `[axis u8][min i32][max i32]` |
| `0x65` MOVE_TO_POSITION | H→D | `[axis u8][target i32][vel u32][accel u32][decel u32]` |
| `0x66` DRIVE_SPEED | H→D | `[axis u8][qpps i32]` (inert on tested firmware) |
| `0x67` DRIVE_DUTY | H→D | `[axis u8][duty i16]` (inert on tested firmware) |
| `0x68` GET_STATUS | H→D | request one STATUS snapshot |
| `0x69` SET_STATUS_STREAM | H→D | `[enable u8][period_ms u16]` |
| `0x6A` GET_DEVICE_INFO | H→D | request DEVICE_INFO |
| `0xE0` STATUS | D→H | per-axis `[pos i32][vel i32][statusword u16]` ×2, then `[battery_dV u16][temp_dC u16][flags u8]` |
| `0xE1` OK | D→H | `[request_type u8]` |
| `0xE2` ERROR | D→H | `[request_type u8][code u32][utf8 message]` |
| `0xE3` DEVICE_INFO | D→H | `[device_type u32][utf8 name]` |

`axis` is `0` = M1, `1` = M2.

## Build & flash

```
idf.py set-target esp32s3
idf.py build flash monitor   # console is on UART0 (USB-UART adapter)
```

Then open the MCP266 console web app and Connect (WebUSB or Web Serial). Click
**Start node**, tick **Live status**, then configure a loop and command a move.

## Standard USB services

Like every espp USB example, this one serves the standard service set on its
framed USB link(s) next to its own protocol, so the hosted consoles and the
[Device Hub](https://esp-cpp.github.io/espp/apps/dispatcher_hub.html) (which
finds each service through discovery, by protocol id) work against it:

| Service | Module (default) | Protocol id | Console |
|---|---|---|---|
| `espp::SystemService` -- device info, reboot, reboot into the bootloader | 7 | `espp.system` | [system console](https://esp-cpp.github.io/espp/apps/system_console.html) |
| `espp::MonitorService` -- heap regions + task table, on request or streamed | 8 | `espp.monitor` | system console |
| `espp::OtaService` -- firmware update (host-driven rollback confirmation) | 0 | `espp.ota` | [OTA console](https://esp-cpp.github.io/espp/apps/ota_console.html) |
| `espp::CoreDumpService` -- last-crash report, core dump download / erase | 4 | `espp.coredump` | [coredump console](https://esp-cpp.github.io/espp/apps/coredump_console.html) |

`partitions.csv` therefore carries the OTA layout (`otadata`, `ota_0`, `ota_1`)
plus a `coredump` partition, and `sdkconfig.defaults` enables core dumps to
flash, OTA rollback and the FreeRTOS run-time statistics the task monitor
reads. Every device->host write on a transport goes through one mutex, so the
services (and any streaming) never interleave frames.

To create a project from this example, run:

idf.py create-project-from-example "espp/mcp266=1.3.6:webapp_example"

or download archive (~9.12 KB)