diff --git a/.github/workflows/circuitpython.yml b/.github/workflows/circuitpython.yml index 7a459270..769d8c5c 100644 --- a/.github/workflows/circuitpython.yml +++ b/.github/workflows/circuitpython.yml @@ -181,3 +181,59 @@ jobs: - name: mdns - the API, and a service found by the process that advertised it run: timeout 300 ./builds/circuitpython/unix/coverage/micropython modules/mdns/tests/test_mdns.py + + # The ESP32-P4 host engine on CircuitPython: usbhost's C compiled against + # CircuitPython's own ESP-IDF 6 and Espressif's usb component, for the + # DEV-KIT's board cell. Nothing else in CI compiles this path, since the + # unix port builds usbhost to nothing, and a change to the shared engine + # sources (modules/usbhost/src) can break it with every other check green. + esp32p4-usbhost: + runs-on: ubuntu-latest + timeout-minutes: 90 + env: + CCACHE_DIR: /home/runner/.cache/ccache + CCACHE_MAXSIZE: 400M + CCACHE_COMPILERCHECK: content + CCACHE_BASEDIR: ${{ github.workspace }} + CMAKE_C_COMPILER_LAUNCHER: ccache + CMAKE_CXX_COMPILER_LAUNCHER: ccache + CMAKE_ASM_COMPILER_LAUNCHER: ccache + IDF_CCACHE_ENABLE: '1' + steps: + - uses: actions/checkout@v7 + + - name: Packages the build needs + run: | + sudo apt-get update + sudo apt-get install -y ccache gettext cmake ninja-build pkg-config libffi-dev + + - name: Cache the toolchains + uses: actions/cache@v6 + with: + path: | + deps/circuitpython + deps/circuitpython-venv + ~/.espressif + key: deps-cp-esp32p4-${{ hashFiles('deps.lock', 'patches/circuitpython/**') }} + + - name: Cache compiler output + uses: actions/cache@v6 + with: + path: /home/runner/.cache/ccache + key: ccache-cp-esp32p4-usbhost-${{ hashFiles('UPSTREAM', 'modules.lock') }}-${{ github.run_id }} + restore-keys: | + ccache-cp-esp32p4-usbhost-${{ hashFiles('UPSTREAM', 'modules.lock') }}- + ccache-cp-esp32p4-usbhost- + + - name: Build CircuitPython for the WIFI6 DEV-KIT with usbhost + run: | + python3 build_mp.py --interpreter circuitpython --port espressif \ + --board waveshare_esp32p4_wifi6_dev_kit --modules usbhost + + - name: The host engine is in the image + run: | + out=builds/circuitpython/espressif/waveshare_esp32p4_wifi6_dev_kit + test -s "$out/firmware.bin" + for o in mod_usbhost usbhost_host usbhost_host_xfer usbhost_host_stream; do + grep -q "/$o.o" "$out/firmware.objs" || { echo "$o.o was not linked"; exit 1; } + done diff --git a/ROADMAP.md b/ROADMAP.md index 393a3cb3..483dc026 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -13,9 +13,10 @@ More modules in CircuitPython-compatible builds - **castif casting on CircuitPython's ESP32-P4 builds.** castif and h264enc build there and h264enc encodes, but the port has no network until CircuitPython drives the boards' ESP32-C6 radio, so a cast can't start yet. -- **usbhost on a CircuitPython ESP32-P4 board.** The host builds into - CircuitPython's ESP32-P4 firmware but hasn't run on a board yet: first a - device enumerated and read. Tethering waits for the port's network. +- **More of usbhost on a CircuitPython ESP32-P4 board.** The host enumerates + and answers a wireless keyboard-and-mouse dongle on the WIFI6 DEV-KIT. Still + to try there: a drive, a webcam's stream and a phone. Tethering waits for the + port's network. - **The USB host drivers on CircuitPython's own `usb.core`**, on the RP2040 and i.MX: planned in [pydevices](https://github.com/PyDevices/pydevices/blob/main/ROADMAP.md#usb). diff --git a/docs/build-plan.md b/docs/build-plan.md index 0bbfad32..9470ba34 100644 --- a/docs/build-plan.md +++ b/docs/build-plan.md @@ -420,7 +420,7 @@ five cells of [`release-firmware.yml`](../.github/workflows/release-firmware.yml | jpegio | yes | ESP32-P4 | adds only the encoder's C API: CircuitPython has its own `jpegio` decoder | | cameraif | yes (`available()` is False) | ESP32-P4 | | | mdns | yes (was left out) | no, on purpose | CircuitPython's boards have an `mdns` of their own; its unix port had none | -| usbhost | yes, as `_usbhost`, with no host engine (was a build error) | ESP32-P4 | the host engine runs on ESP-IDF's USB host library, which from ESP-IDF 6 is Espressif's `usb` component: `build_mp.py` fetches it at the version `deps.lock` pins. The P4's boards leave its high-speed controller to us. Tethering is left out until the port has a network, and the host hasn't run on a CircuitPython board yet ([roadmap](../ROADMAP.md)). The S3's one controller is CircuitPython's drive and REPL, so it gets the module without the engine. On the RP2040 and i.MX, CircuitPython's own `usb.core` is the host, and pydevices' HID, CDC and MSC drivers are planned for it | +| usbhost | yes, as `_usbhost`, with no host engine (was a build error) | ESP32-P4 | the host engine runs on ESP-IDF's USB host library, which from ESP-IDF 6 is Espressif's `usb` component: `build_mp.py` fetches it at the version `deps.lock` pins. The P4's boards leave its high-speed controller to us. Tethering is left out until the port has a network, and on the WIFI6 DEV-KIT the host has enumerated a webcam and a keyboard-and-mouse dongle, with drives and streams still to try ([roadmap](../ROADMAP.md)). The S3's one controller is CircuitPython's drive and REPL, so it gets the module without the engine. On the RP2040 and i.MX, CircuitPython's own `usb.core` is the host, and pydevices' HID, CDC and MSC drivers are planned for it | | audioif | no | no | links against audiodsp's audio pump and `cp_compat`, which audiodsp's CircuitPython glue doesn't build. CircuitPython's audio samples are fed only from C, so audio made in Python needs a stream sample, the pump's C side shaped as one ([roadmap](../ROADMAP.md)); boards have `audiobusio` of their own | | ulab | CircuitPython's own | CircuitPython's own | | | castif | no: it is the ESP32-P4's | ESP32-P4, with no network yet | talks to lwIP directly, the lwIP under CircuitPython's own `socketpool`. CircuitPython's P4 port has no network until it drives the boards' ESP32-C6, so castif is built without one and `start()` says so ([roadmap](../ROADMAP.md)). Name tsmux, h264enc and ppa with it | diff --git a/modules/usbhost/README.md b/modules/usbhost/README.md index f4ed23a5..2218c5f0 100644 --- a/modules/usbhost/README.md +++ b/modules/usbhost/README.md @@ -10,9 +10,11 @@ ESP-IDF's USB host library. Its CMake glue skips every other part, so a firmware for those still builds, without the host. On CircuitPython the host builds for the ESP32-P4, where the boards leave the -high-speed controller free. It hasn't run on a CircuitPython board yet, so -treat it as untried there. Phone tethering is left out there, because the -port has no network yet. Every other CircuitPython build gets `_usbhost` +high-speed controller free. On the Waveshare ESP32-P4-WIFI6-DEV-KIT it +enumerates a webcam and a wireless keyboard-and-mouse dongle behind the +board's hub (started with `full_speed=True`) and answers the dongle's HID +requests; drives and streams haven't been tried there. Phone tethering is +left out there, because the port has no network yet. Every other CircuitPython build gets `_usbhost` without the host. ## The packages are in pydevices