6.8 KiB
Contributing to Control4Free
Thanks for helping! Bug reports, compatibility reports, fixes and reviews are all welcome.
Reporting a bug
Use the bug report form. The most useful details:
- the Control4Free version, shown at the bottom of the page and of the app;
- the firmware and GoldHEN versions;
- the phone or computer and browser you used;
- what you did and what happened;
- the service's log, if you can get it:
/data/control4free/control4free.logon the PS4, over GoldHEN's FTP server (port 2121). The last segment of the previous run is kept incontrol4free.log.previous.
The log contains your console's network address. Remove it before posting if you prefer.
Security problems: please follow SECURITY.md instead of opening a public issue.
Building
Everything builds in Docker, so Docker is all you need:
git clone https://github.com/MoHadiShibli/Control4Free
cd Control4Free
docker build -t control4free-build docker/
docker build -t control4free-launcher-build -f docker/Dockerfile.launcher docker/
docker run --rm -v "$PWD:/src" -w /src control4free-launcher-build bash -lc 'make && make -C launcher'
build/control4free.elfis the service, with the page and its icon built in.build/Control4Free-<version>.pkgis the app, with its own copy of the service.
The first image pins the ps4-payload-sdk release that builds the
service; the second adds the OpenOrbis toolchain,
pinned by digest, for the app and the package. On Windows, tools/build-launcher.ps1 runs all three steps.
The version comes from the VERSION file and nowhere else: the Makefiles and the packager read it, and
the page and the app show the version the service reports.
Testing
docker run --rm --network none -v "$PWD:/src" -w /src control4free-launcher-build python3 -B tests/run.py
The six suites build the real sources for the host with only the PS4 calls stubbed, so they need no console:
test_webandtest_recoveryrun the actual service against a fake kernel log (tests/web_stub.c) that writes the same lines firmware 10.01 does, over real HTTP and a test-only WebSocket adapter; production controller connections use WebRTC;test_frontendruns the page's own functions under Node;test_launcherdrives the app's logic and input worker, compares warm tester renders with fresh renders, producesbuild/launcher-preview-*.png, and checks the package'sparam.sfo;test_loggingcovers the log, the kernel-log opener and DeviceId matching;test_rtcchecks STUN/SCTP, congestion and receive windows, UDP backpressure, and the production HTTP signalling endpoint with the WebSocket adapter disabled.
The build workflow gives the Docker commands for the browser checks, using the pinned Playwright image and package. Run these after the host suites, which build their test server:
tests/browser_test.cjs: controller-page editor, mapping and connection lifecycle;tests/fake_gamepads_test.cjs: researched gamepad emulations, without hardware compatibility claims;tests/experimental_test.cjs: optional HID, motion, output and reconnect behavior;tests/rtc_e2e.cjs: real Chromium and Firefox WebRTC connections and reliable fragmented replies;tests/rtc_input_e2e.cjs: input freshness and recovery through dropped, delayed and reordered UDP packets.
Run packaging and launcher preview tests sequentially because they share renderer scratch files.
For controller-test drawing changes, tests/test_tester_render.py runs the cache-transition checks on
their own. Its optional --benchmark reports host CPU drawing time, excluding input, framebuffer copy
and display presentation; do not describe those results as PS4 frame timings.
Changes to mapping belong in the page's mapping tests as well as its browser checks. Exercise independent analog trigger pressures and digital flags, multiple sources driving a slot, profile changes and reconnect gating. For connection RTT changes, check probe matching, expiry, ownership changes and the launcher's unavailable/measuring states. RTT is client-reported diagnostic data, separate from pad input.
Add a test with your fix: one that fails without it. Then test on a real console if you can, and say in your pull request which firmware, GoldHEN version and games you tried.
To try changes to the page without rebuilding, open client/index.html from disk and enter the console's
address, or add ?host=<ps4-ip>:4264 to the page's URL.
Code style
Match the code around your change:
- C with GNU extensions (gnu11), 4-space indent,
camelCasefunctions with ac4fprefix,C4ftypes andC4F_macros; - log with
c4fLog.c4fNotifyshows a notification on the PS4's screen: keep those rare; - comments explain why, not what;
- only button bits confirmed on hardware go in
include/c4f_sce.h; - the page is one file with no build step and no libraries: keep it that way;
- OpenOrbis's headers give
MSG_NOSIGNAL,SIGSYSandCLOCK_MONOTONICtheir Linux values, which the PS4 reads as something else. Don't use them directly inlauncher/; a test checks.
Build without new warnings; the app is built with -Werror.
Releasing
- Update
VERSIONand the changelog's release date and notes. Review mapping, compatibility and diagnostic documentation; distinguish hardware reports from emulated-input tests. - Run all six Docker host suites and all five browser checks above, including WebRTC impairment checks. Build normal and diagnostic packages without new warnings. Inspect launcher previews and browser layouts.
- Validate standard controllers on real hardware: simultaneous devices, source mixing, rumble, reconnect, logout and rest/wake. Recheck firmware 10.01 and a modern tested firmware, and record the results. Wheel/guitar model compatibility remains unverified until device reports establish it.
- Commit, tag
vX.Y.Z, and push the tag when the release gates pass. - CI checks the tag against
VERSIONand publishescontrol4free.elf, the normal package, the diagnostic package andSHA256SUMS. Release-note documentation links point to that tag.
Reviewing AI-written code
Much of Control4Free was written with the help of AI models (Claude Opus 5.5 by Anthropic and Astra GPT-6 by OpenAI). It has been tested, on the console as well, but AI-written code can look right and still be wrong. Please read it critically: if you find dead code, wrong assumptions or needless complexity, open an issue or send a pull request.
License
Contributions are accepted under the GNU General Public License v3, the project's license.