{"id":51634926,"url":"https://github.com/cc90202/DCC-esp32","last_synced_at":"2026-08-01T16:00:44.220Z","repository":{"id":347282575,"uuid":"1193357319","full_name":"cc90202/DCC-esp32","owner":"cc90202","description":"DCC command station for ESP32-C6 — NMRA-compliant model railroad controller in Rust","archived":false,"fork":false,"pushed_at":"2026-07-27T16:02:15.000Z","size":2089,"stargazers_count":7,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-07-27T16:09:53.975Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","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/cc90202.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-27T06:13:16.000Z","updated_at":"2026-07-27T14:51:12.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/cc90202/DCC-esp32","commit_stats":null,"previous_names":["cc90202/dcc-esp32"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cc90202/DCC-esp32","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cc90202%2FDCC-esp32","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cc90202%2FDCC-esp32/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cc90202%2FDCC-esp32/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cc90202%2FDCC-esp32/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cc90202","download_url":"https://codeload.github.com/cc90202/DCC-esp32/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cc90202%2FDCC-esp32/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":36161704,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-08-01T02:00:05.789Z","response_time":100,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2026-07-13T13:00:40.281Z","updated_at":"2026-08-01T16:00:44.213Z","avatar_url":"https://github.com/cc90202.png","language":"Rust","funding_links":[],"categories":["Projects"],"sub_categories":["`no_std`"],"readme":"```\n                               .=########%%####%@@@*:\n                               +############%%@@@@@@%\n              %@%               %@@%%@%@%=-*@@+@@@@@:                  .\n           :#%@@@%##%%%%%%%##%%%@@@@@#%+*-:+@@@@@@@@%%%%@@@@@@@%%%%@@@@@@########%%#=.:.\n          .@@@@@@@@@@@@@@@@@@@@@%@@@@%%#%%%%@@@@@@@@@@@@@@@@@@@@@@@@%@@@@%%%%%%%%%%%-=+*+\n          .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-=@@%.\n       ---:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@--@@@.  -\n       :  .%@@@@@@@@@@@@@@@@@@@@@@@@@@@%%#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@--@@@:  :\n      ::  :%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-::=@-  :-\n      -==*:%@@@@@@@@@@@@@@@@@@@@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%@@@=::-@+  -=\n      -#+*#-:..........-:.........................................:-:::::---====*%%***:-@@#*#=\n    @+-@@@@#@@@@@@@@@%@@@@@@@@@@@@@%%@@@@%%###%@@@@@@@@@@@@@@@*#@@@@@@@@@@@@@@@*@%@@@%:=@@@@@@@@.\n    + -#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-=@@@@@#=.\n     -*%@@@#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#*@@@@@@@@*.\n   .=#@@@@@:.@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.            @@@@@@@@@@@@@@@%@@@@@@@@@@@@@@@      .*+\n              ...%%@@@@@@-   ..*%#@@@@@%...              ..*##@@@@@*.:.. .##*@@@@@=....\n#%#%##%%##%%#####%#%##%%%#%%###%#%#%##%%##%%#####%#%##%%##%%%####%#%##%%##%%#####%#%##%%##%%###%#%#%\n###%#%%#%%%%%%#####%#%##%%%%%%#####%#%%#%%%%%#%####%#%##%%%%%%#####%#%##%%%%%%#####%#%%#%%%%%%#####%\n+++++*++++++*++++++++*++++++*++++++++*++++++*++++++++*=+++++*++++++++*++++++*++++++++*++++++*+++++=+\n```\n\n# DCC-esp32\n\n`no_std` Rust firmware for a DCC command station built on the ESP32-C6, using\n`esp-hal`, Embassy async tasks and `esp-wifi`. Together with its companion\nhardware it drives up to 12 locomotives at once, controlled from the Roco Z21\napp over a Z21-compatible UDP layer.\n\n## What this software does\n\nThe track waveform comes out of the RMT peripheral, with packet swaps handled\ninside the interrupt while the preamble is still playing. That keeps the signal\nfree of inter-packet gaps and costs under 0.4% of the CPU, which is what makes\n12 simultaneous decoders possible without the signal degrading.\n\nAbove that sit the NMRA packet encoder for both locomotive control and service\nmode, a scheduler that keeps every active decoder refreshed with its speed,\ndirection and function state, emergency stop and fault handling, and the\nZ21-compatible network layer the app talks to.\n\nWiFi credentials are configured at runtime from a setup page the board serves\nitself, so nothing is baked in at build time. Protocol, encoder and scheduler\nlogic is pure and covered by host-side tests; the rest runs on the target.\n\n## Hardware documentation\n\nRead this before wiring or powering anything:\n\n- [Components inventory](docs/hardware/components-inventory.md)\n\nTwo track drivers have been used on the bench. The BTS7960 is the\nhigher-current H-bridge, and the older breadboard and RailCom notes still refer\nto it. The Pololu DRV8874 carrier (#4035) is the compact option used for the\ncurrent bring-up and short-recovery testing.\n\nThe firmware drives the DCC signal path and the control logic, but safe operation depends on the\nexternal hardware around it: the power stage, the protection circuitry, and how the signals are\nrouted. Detailed wiring notes for the two drivers are kept outside this repository for now, so do\nnot wire a track from this README alone.\n\n## Getting started\n\n1. Build and flash the firmware:\n\n   ```bash\n   cargo run --release\n   ```\n\n2. Configure WiFi from the ESP32 setup page.\n\n   On first boot, or whenever no valid WiFi credentials are stored, the ESP32\n   starts safe WiFi setup mode instead of the normal command-station runtime.\n   Track output, DCC, RailCom, and Z21 services remain disabled during setup.\n\n   Connect a phone or computer to:\n\n   - AP SSID: `DCC-Setup-XXXX`, where `XXXX` is derived from the ESP32 MAC\n     suffix\n   - AP password: `dcc-setup`\n   - Setup URL: `http://192.168.4.1`\n\n   The setup page asks for the station WiFi SSID and password. After a valid\n   save, the ESP32 sends the success page, reboots, and starts station mode\n   using the stored credentials.\n\n3. To re-enter setup mode later, hold the blue Resume button on GPIO21 for at\n   least 10 seconds, then release it. The board reboots and starts the setup\n   access point. This also works when the saved home WiFi network is absent.\n\n   Short GPIO21 presses still perform Resume. A press below the 10 second setup\n   threshold does not enter WiFi setup. The red Stop button on GPIO22 remains\n   Stop/E-stop and is unchanged by WiFi provisioning.\n\n4. Once station mode is connected, the OLED display shows the station's IP\n   address.\n\n5. In the Roco Z21 app, go to settings and enter that IP address as the command station.\n\n6. Select the locomotive address and drive.\n\nBuild-time `.env` credentials have been removed entirely: WiFi credentials are\nconfigured from the setup page and stored in flash.\n\nCV programming is still being worked on. The RailCom and programming-on-main\nread and write paths are being integrated, but the programming-track hardware\nsupport is not finished.\n\n## Cargo aliases\n\nCustom aliases are defined in `.cargo/config.toml` for common workflows:\n\n| Alias | Description |\n|-------|-------------|\n| `cargo test-host` | Run host-side unit tests (protocol logic, fast feedback) |\n| `cargo check-esp` | Type-check for ESP32-C6 target (no flash) |\n| `cargo build-esp` | Build firmware for ESP32-C6 |\n| `cargo build-esp-release` | Release build (LTO enabled) |\n| `bash scripts/check-isr-ram.sh` | Verify RMT/cutout ISR symbols are linked in internal RAM |\n| `cargo clippy-host` | Lint for host target |\n| `cargo clippy-esp` | Lint for ESP32-C6 target |\n| `cargo run` | Flash to device via espflash and monitor |\n\n## Build\n\n```bash\ncargo build-esp            # debug build\ncargo build-esp-release    # release build (LTO, size-optimized)\n```\n\n## Flash\n\n```bash\ncargo run                  # flash and monitor via espflash\ncargo run --release        # flash release build\n```\n\n## Test and validation\n\n```bash\ncargo test-host            # host-side unit tests\ncargo check-esp            # fast embedded compile check\ncargo clippy-host          # lint (host)\ncargo clippy-esp           # lint (ESP32-C6)\n```\n\n## Commit conventions\n\nCommit messages follow Conventional Commits and are validated with `cocogitto`.\n\n- Format: `type(scope)!: short imperative summary`\n- Reference: [CONTRIBUTING.md](CONTRIBUTING.md)\n- Local check: `cog check origin/main..HEAD`\n- Local hook install: `cog install-hook`\n\n## Project layout\n\n- `src/bin/main.rs`: firmware entrypoint\n- `src/dcc/`: DCC packet, encoder, timing, scheduler, validator, CV logic, ISR-driven RMT backend\n- `src/net/`: Z21-compatible network protocol, UDP control, WiFi, and provisioning\n- `src/railcom/`: RailCom capture, parsing, runtime dispatch, and POM integration\n- `docs/specs/`: protocol and standards references\n- `docs/hardware/`: component inventory and hardware notes\n\n## Safety notes\n\n- Current output/control behavior must match the external amplifier and protection hardware.\n- For protocol, power-stage, or GPIO wiring changes, re-check the hardware documentation before flashing.\n- DCC track power can damage decoders or hardware if the power stage is wired incorrectly.\n\n## TODO\n\n- [ ] CV programming hardware integration (prog track relay, ACK detection circuit)\n- [ ] Z21 multi-client support (multiple apps controlling the same station)\n- [ ] RailCom bi-directional communication (hardware + firmware)\n- [ ] PCB design for a standalone command station board\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcc90202%2FDCC-esp32","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcc90202%2FDCC-esp32","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcc90202%2FDCC-esp32/lists"}