51 Commits
Author SHA1 Message Date
MoHadiShibli b7976e8b1f Fix CI image pulls using the official Ubuntu registry 2026-10-22 20:07:14 +03:00
MoHadiShibli dba861bb7f Publish Control4Free release v1.3.0 2026-10-22 19:35:11 +03:00
MoHadiShibli 6a0e6925e5 Prepare Control4Free 1.3.0 with WebRTC and controller testing 2026-10-22 19:30:05 +03:00
MoHadiShibli aa45b9b123 Trigger rumble follows the trigger being pulled
A linked DualSense and Xbox controllers vibrate the trigger being pulled,
the last one pulled while both are, and neither while neither is. The
large motor used to drive L2 and the small one R2, so a shot fired with
R2 was felt in L2.
test-1.3.0-dualsense-2
2026-10-20 13:56:18 +03:00
MoHadiShibli 9890560867 Read a linked controller's buttons from its own reports
Over Bluetooth a linked DualShock 4 or DualSense switches to its full
reports, which the browser's gamepad doesn't read, so the PS4 got no
input from it. While linked, its buttons, sticks and triggers now come
from those reports, over USB and Bluetooth alike.

A fault in the experimental code no longer stops the page's input loop,
and "How to turn it on" only shows when the page is insecure.
test-1.3.0-dualsense
2026-10-16 23:42:52 +03:00
MoHadiShibli 7e503478c4 Add the PS4 controller test, motion input and experimental extras
PS4 app: Test controllers, opened with Options or from Actions, shows what
each signed-in user's controller sends, read the way a game reads it, on
the controller page's picture. Holding L3 + R3 opens its menu: change user,
rumble each motor, set or reset the light bar, reset orientation, go back.

Service: the control protocol takes motion ('m'), and info says so. Rumble
reached the page with the large and small motors swapped: fixed.

Page: Settings > Experimental, every switch off by default. Lights, rumble
and touchpad fingers for a DualShock 4 or DualSense over WebHID; trigger
rumble on Xbox controllers and a linked DualSense; motion from a phone or a
linked controller.
2026-10-16 16:08:13 +03:00
MoHadiShibli 5a8f9e3d0e Prepare Control4Free 1.2.1 release v1.2.1 2026-10-11 12:21:56 +03:00
MoHadiShibli 75743ef24b Render diagnostic previews with isolated page fixtures 2026-10-10 14:04:11 +03:00
MoHadiShibli 0b3b448ca5 Decode Sony remote Enter keys in the launcher 2026-10-10 13:58:09 +03:00
MoHadiShibli ed5e828701 Build with official mirrors and the verified OpenOrbis archive
Avoid Docker Hub pull limits using pinned Docker Official Images on ECR. Fetch the same OpenOrbis release directly and verify its SHA256; retain the existing toolchain and runtime dependencies.
2026-10-10 00:39:29 +03:00
MoHadiShibli 1242d7346e Add HDMI-CEC navigation to the PS4 launcher
Read system TV-remote input independently, expose launcher actions through arrows and OK, and preserve DS4 shortcuts. Add reconnect handling, explicit Stop confirmation, diagnostics, and reader/navigation regressions.

Prepare the next patch version as a test candidate; PS4 HDMI-CEC reception still needs hardware confirmation before release.
2026-10-10 00:19:43 +03:00
MoHadiShibli 252e26d2b7 Finalize Control4Free 1.2.0 fixes and release documentation v1.2.0 2026-10-09 21:13:37 +03:00
MoHadiShibli 41c476b2e2 Implement Control4Free 1.2.0 mapping and reliability 2026-10-09 17:38:23 +03:00
MoHadiShibli 017b8e2473 Docs: GoldHEN v2.4b18.10 is the minimum, and a compatibility table
GoldHEN versions before v2.4b18.10 don't run ELF payloads reliably (v2.4b18.8
improved ELF loading, v2.4b18.10 fixed a sceUserServiceInitialize failure in
them) and have no auto-start, and every firmware GoldHEN supports has a
v2.4b18.10 or later. The installation guide now lists each firmware with the
GoldHEN version it needs, marking the ones confirmed on a console (10.01,
13.02, 13.04, 13.52) apart from those that only have GoldHEN and start-up
support so far. The README points to it.
2026-10-07 02:21:39 +03:00
MoHadiShibli 96326c71b0 Docs: tested firmwares, and what to do when updating, restarting or reporting
- Requirements list the firmwares Control4Free is tested on (10.01, 13.02,
  13.04 and 13.52, with GoldHEN v2.4b18.10 and v2.4b18.12); 13.52 needs 1.1.1.
- Updating says you don't need to stop Control4Free before deleting or
  replacing the app. A new "After a restart" section says auto-start brings it
  back by itself and the app doesn't get in the way.
- Uninstalling warns that deleting the app alone leaves Control4Free starting
  with GoldHEN, and how to clean up when the app is already gone.
- Reporting a problem stops the normal version before starting the diagnostic
  one, so the report comes from the diagnostic version, and says how to switch
  back.
- The kernel-log message also names old test builds of the diagnostic app.
2026-10-07 02:03:52 +03:00
MoHadiShibli f57224ee39 Control4Free 1.1.1 v1.1.1 2026-10-07 01:39:35 +03:00
MoHadiShibli 9d0c3d6a7d Ship a diagnostic package with every release, and ask for it in bug reports
CI now builds Control4Free-<version>-diag.pkg next to the normal package and
attaches it to each release. The bug report form asks for its screenshots or
report file instead of an optional log, and the troubleshooting guide's
"Reporting a problem" section walks through it: install the diagnostic
package, make the problem happen again, screenshot the 5 pages, then put the
normal package back.
2026-10-07 01:39:35 +03:00
MoHadiShibli b583d149d8 Diagnostic app: never hold the kernel log while Control4Free runs
The app read the kernel log in short windows: when it opened, around a
start, and on Options. The log has one reader, and Control4Free needs it to
sign a controller in. A tester on 13.52 opened the app after a restart and
went back to the home screen while it was reading: the PS4 suspended the app
with the log still open, and no controller could sign in until the app was
closed. Now the app reads the log only while Control4Free is not running,
which is the only time it is useful, and stops as soon as a start succeeds.
2026-10-07 01:39:34 +03:00
MoHadiShibli eceeb7bf46 Diagnostic build: log each connection and each notification
On firmware 13.52 the service now starts and answers the launcher, but a
browser on the network gets its connection closed, and no notification
appears. The diagnostic build now logs, for every connection from another
device, what it asked for, what it was sent, and why it was closed (send or
recv errors with errno, the 10-second timeout with the first byte received),
plus the result of every notification request. The diagnostic screen shows
its build time and, while Control4Free runs, asks for the address to be
opened and page 2 screenshotted. It also reads GoldHEN's SDK version
correctly: GoldHEN returns it through the call's error value.
diag-13.52-2
2026-10-06 02:37:51 +03:00
MoHadiShibli 056a32f6c9 Let Cross retry a failed start instead of asking for a restart
When Control4Free was sent but did not answer, the app locked itself until
the PS4 restarted, so two copies could never run. The payload already takes
care of that: a second copy finds the instance lock and quits at once. So
the app now says to press Cross to try again, and a restart never helped a
payload that cannot start anyway. The lock stays only for the app itself
failing to start ("Reopen the app").
2026-10-06 02:07:00 +03:00
MoHadiShibli 745c16decf Diagnostic build: a package that shows why Control4Free does not start
For consoles it fails on, so a user can send screenshots instead of digging
out log files. `make C4F_DIAG=1` and `make -C launcher C4F_DIAG=1` (or
tools/build-launcher.ps1 -Diag) build Control4Free-<version>-diag.pkg, listed
as "Control4Free (diagnostic)".

Its app shows plain pages in place of the normal screen: a summary with a
verdict (firmware, GoldHEN, sandbox, auto-start files, the service and the
last start), the service log and the previous one, and the kernel log,
filtered and in full. The kernel log is read only in short windows, at
start-up, around a start and on Options, since Control4Free needs it to sign
controllers in. The pages are also saved to
/data/control4free/diag-report.txt, and to a USB stick when one is plugged in.

The payload says on screen that it started, and logs the kernel addresses
the SDK found and the process PayLoader runs it in.
2026-10-06 02:06:53 +03:00
MoHadiShibli 94e4a7ecd7 Build: take the payload's start-up code from a newer SDK, for firmware 13.52
The ps4-payload-sdk v0.9 release has no kernel offsets for firmware 13.52 or
14.00, so on those consoles the payload quit in its start-up code before
main(): PayLoader reported it launched, but no log or service ever appeared.
The SDK added both on master (573b4a0); crt1.o is rebuilt from that commit
with the SDK's own crt/Makefile. It exports the same symbols as v0.9's.
2026-10-06 02:06:36 +03:00
MoHadiShibli 7d3eb00e52 CHANGELOG: date 1.1.0 v1.1.0 2026-10-06 01:05:33 +03:00
MoHadiShibli 1b4ee87294 CHANGELOG: state 1.0.0's limits without promising anything 2026-10-06 01:05:33 +03:00
MoHadiShibli 200e2bfc0b Show who's signed in on each controller, and an Invite QR code
When the PS4 reports a user signed in on a controller, the service asks for
the user's name and adds it to the status as `user`. The PS4 may not have
finished signing the user in by then, so a failed look-up is retried every
half second for five seconds. The tile shows the name in place of
"Controller N" (the ring keeps the number), and the controller screen reads
"Controller 1 · Alex". Names are kept out of the log, since people post logs
in bug reports, and they go out cleaned: quotes and backslashes escaped, and
control characters or anything that isn't valid UTF-8 replaced, because a
browser drops the whole WebSocket on a text frame that isn't valid UTF-8.

An Invite panel, opened from a button next to the settings or from the menu,
shows the page's address as a QR code for friends to scan. The console makes
the code with the QR encoder the app already ships, from the address the page
reached it on, and sends the module grid; the page draws it as SVG, so it still
needs no libraries.

The gamepad picker's tooltip had the same "Controller 1 · Controller 1" doubling
the controller screen had; it now names the user too.
2026-10-06 01:05:33 +03:00
MoHadiShibli be950bf7b5 Docs: say not every controller supports vibration in the browser
Rather than a list of which pads rumble in which browser, which would go
stale; a gamepad the browser knows it can't rumble says so on its row.
2026-10-06 01:05:33 +03:00
MoHadiShibli 028cb9f2f4 Name gamepads the browser can't rumble, and time the rumble reads
A gamepad's row now says "no rumble in this browser" when the browser has
no way to rumble it: common for a DualSense, while Chrome and Edge rumble
Xbox pads. Before, it just never rumbled.

The heartbeat now reports how many rumble/light-bar reads ran in the last
minute and what they cost on average and at worst, in microseconds: the
longest an arriving input could wait behind one.
2026-10-06 01:05:33 +03:00
MoHadiShibli 6d9949f88b Build: rebuild everything when VERSION changes
The version is passed in as a compiler flag, and make doesn't notice a
changed flag. After the bump to 1.1.0, only files whose source had changed
were recompiled, so main.c and log.c still logged 1.0.0 and the app could
show it. Objects now depend on VERSION. Builds from a clean checkout, as CI
does, were never affected.
2026-10-06 01:05:33 +03:00
MoHadiShibli 627e2cec63 Log the light bar and count rumble changes
So a console test can tell a game that never rumbled from a phone that
never buzzed: each light-bar change is logged as it happens, and the
heartbeat says how many rumble changes arrived in the last minute.
2026-10-06 01:05:32 +03:00
MoHadiShibli baf36d648e 1.1.0: rumble and the light bar
A game talks to a virtual controller as it would to a real one, and the system
keeps what it asked for. scePadVirtualDeviceGetRemoteSetting reads it back in
the layout of a DualShock 4's output report: the two motors at [3] and [4], the
light bar at [5..7]. The layout was read on the console while games rumbled and
users signed in, and feedback.c is tested against those exact buffers.

The service reads it every 16 ms for each controller; games pulse rumble for
only tens of milliseconds, which a 100 ms poll missed.

- Rumble goes to the controller's owner as {"method":"v","params":[pad,large,
  small]}, once per change, and to whoever takes a controller over, so a page
  never keeps buzzing on old news. The page already drove an Android phone's
  vibration and a gamepad's actuators from it.
- The light bar goes into the status everyone sees. The PS4 sets player colours
  at a quarter strength, so the colour is brightened to full, keeping its hue;
  an unlit bar keeps the controller's own colour.
- Without the call, controllers work as before and it is logged once.

Also: the page says "Choose user on PS4", not "on TV", since not everyone plays
on a TV. The test stub takes C4F-TEST-FEEDBACK lines to set what the "game"
wants, and the test client can wait for messages the service pushes.
2026-10-06 01:05:32 +03:00
MoHadiShibli 183f9dfaee Update user selection instructions for PS4 2026-10-05 21:49:11 +03:00
MoHadiShibli 1cc59c12dc README: shorter credits, and the AI models by name
Credits are down to SplashDown, whose code the virtual-device layer is
ported from; everything else Control4Free uses, with its license, stays
listed in THIRD_PARTY.md. The AI models named are the ones actually used:
Claude Opus 5.5 and Astra GPT-6.
2026-10-05 16:30:44 +03:00
MoHadiShibli 5335bc09ce Documentation for 1.0.0: README, guides, screenshots, GitHub files
- README: what Control4Free is and why it reaches menus and sign-in, features,
  a quick start, screenshots, requirements, limitations, credits.
- docs/: installation, playing, troubleshooting (every message the page and the
  app can show), how it works, and the WebSocket protocol.
- CONTRIBUTING.md: building, testing, code style, releasing.
- Screenshots of the page on phones and a PC and of the app, made against the
  real service built for the host, at the example address 192.168.1.20.
- Issue forms, a contact list pointing at the guides and private security
  reporting, and FUNDING.yml.
- CHANGELOG.md dated. CI now publishes this version's section of it as the
  release notes rather than the whole file.
- THIRD_PARTY.md: the DualShock 4 diagram the buttons are drawn after (CC BY
  3.0), and Apollo Save Tool for the package settings.
- Page: the Vibration setting no longer promises to buzz when a game rumbles,
  which 1.0.0 cannot do yet.
v1.0.0
2026-10-05 15:53:01 +03:00
MoHadiShibli 77a1bba68d Review fixes before publishing
From a last pass over the code and a set of screenshots on phones, an iPad and
a PC:

- The menu button sat on top of R2 on a phone in landscape: R2 starts about 68px
  from the right edge, room for one corner button, not two. The menu and full
  screen buttons now stack down the edge instead.
- On a narrow phone the connection status was cut off mid-address ("Connected
  to 192.16"). The address is now a detail that narrow screens leave out.
- The controller screen said "Controller 1 · Controller 1": the page's own label
  and the console's name for it had become the same words. The console's name
  is only added now when it says something more.
- Free controllers still offered "a controller on this device", and the app
  "controllers connected to the phone or PC"; both now say gamepad, as the rest
  of the page does.
- SECURITY.md said no website could drive the console. A page opened from a
  saved file connects with Origin: null, and that has to be accepted because the
  saved file is how gamepads work in browsers that keep the Gamepad API to secure
  pages; a website can send the same Origin from a sandboxed frame. It now says
  exactly that, and what such a page still cannot do.
- THIRD_PARTY.md credited the GoldHEN call to autorun.c; it is in sandbox.c.
- Two comments pointed at a tag that only exists locally.
2026-10-05 15:43:03 +03:00
MoHadiShibli a039ce9532 Package: list the app under Applications, not Games
The package declared itself a game (CATEGORY gd), so the PS4 filed it under
Games in the library.

It now uses the values Apollo Save Tool ships with: CATEGORY gde ("Non-Game Mini
App"), ATTRIBUTE 32, APP_TYPE 1. Apollo is built with the same OpenOrbis tools and
lists under Applications. APP_TYPE 4 ("Freemium"), which is reported to move apps
there too, made the PS4 refuse to start ours (CE-39929-2), so it stays 1.

Confirmed on the console (firmware 10.01): the app installs, starts, and lists
under Library > Applications. A test reads the fields back out of the built
package.
2026-10-05 15:30:36 +03:00
MoHadiShibli ffe5615da3 Page: keep the menu and full-screen buttons together in the corner
The menu button sat at a fixed 70px from the right while the full-screen button
followed the safe area. On an iPhone in landscape the safe area is 47-59px, so
the full-screen button slid underneath the menu; on Android, with no safe area,
the two stood 24px apart; and wherever full screen is hidden, the menu was left
floating away from the corner.

Both now sit in one row that follows the safe area, 8px apart, and a hidden
button takes its gap with it.
2026-10-05 15:06:52 +03:00
MoHadiShibli 5b8433fbba Page: on iPhone, the full-screen button explains the home screen instead
Safari on iPhone lets only video go full screen, so the button did nothing
there. The check for it looked for requestFullscreen, which exists on iPhone even
though every call is refused; it now asks fullscreenEnabled instead.

On iPhone the button now says how to get the same thing: add the page to the Home
Screen and open it from there, where it runs without Safari's bars. When the page
already runs that way, or is installed anywhere else, the button goes away.
Elsewhere it goes full screen as before, prefixed or not.
2026-10-05 14:45:57 +03:00
MoHadiShibli 0c395576eb Launcher: refresh the status every 2 seconds, as it was meant to
The app's controller count, and everything else on its screen, only changed when
the app was closed and opened again.

OpenOrbis's time.h gives CLOCK_MONOTONIC the Linux value, 1. The PS4's kernel is
FreeBSD's, where clock 1 is CLOCK_VIRTUAL: the process's own CPU time. The worker
sleeps between checks and uses almost none, so its clock barely moved and the
check due 2 seconds later never came round. Only the first check, on start-up,
ever ran. The payload is unaffected: its SDK has FreeBSD's value, 4.

The launcher now uses 4 when it is built for the console. Checked the other
constants the app uses against FreeBSD's: everything matches except this one,
MSG_NOSIGNAL and SIGSYS, which were already worked around. A test now fails if
any of the three is used directly in the launcher again.
2026-10-05 14:31:24 +03:00
MoHadiShibli 34f3a3e349 Stop deleting controllers the moment they are created
On the console, every new controller was removed straight away with "That
controller was disconnected after sitting unused".

The idle reaper compared unsigned millisecond stamps directly: now - lastInput.
`now` is read at the top of a main-loop iteration, but since creation became a
state machine the claim finishes inside that iteration and stamps lastInput from
the clock afterwards. Once the two fell on different milliseconds the subtraction
wrapped to about 49 days, and every controller in the claim was deleted. On the
console the gap is InsertData and klog work, so it happened nearly every time;
on a fast host it almost never did, which is why the tests missed it.

Every elapsed-time comparison in web.c now goes through c4fSince, which cannot
wrap, and the clock is read again before the reaper runs. The reaper also logs
what it removes and why, so this would have shown up in the log at once.

The test stub can now spend time inside an iteration the way the console does
(C4F_TEST_SLOW_MS), and the new test fails on the old code in its first round.
2026-10-05 13:10:34 +03:00
MoHadiShibli de0c0a3eea Release scaffolding: changelog, CI, and a research build for rumble
CHANGELOG.md says what 1.0.0 is. The CI workflow builds both toolchain images,
the payload and the package, runs every host test, and on a vX.Y.Z tag checks the
tag against VERSION before publishing the ELF, the package and their SHA256 sums.

`make C4F_PROBE=1` adds a poll of scePadVirtualDeviceGetRemoteSetting for every
live controller, logging the return code and only the bytes that change. That is
the one call that looks like it could carry a game's rumble and light-bar state
back to a virtual pad, and nothing is known about its buffer, so this is how to
find out on hardware. It builds to control4free-probe.elf and is never in a
release.
2026-10-05 02:36:26 +03:00
MoHadiShibli 243f5efa68 Keep the page on a home screen, say the address out loud, and say what went wrong
Three bits of polish for people who did not write this.

The payload serves /manifest.webmanifest and /icon-192.png, and the page points
at both, so a phone can keep the controller on its home screen instead of typing
an IP address again. The icon is the app's own icon, rendered by the launcher's
drawing code and committed, so the payload build needs no renderer; a test
re-renders it and fails if the two drift apart. One size only: the gradient does
not compress, and a 512 copy would add 150 KB for a splash screen that a plain
HTTP shortcut never shows. write_png now picks the best filter per row, which
also shrinks the package icon.

When the service starts it works out which address the console is actually
reachable on, from the route to the outside world without sending anything, and
puts it in the start-up notification on the TV.

Every error the page can show now says what happened and what to do about it,
rather than "Invalid axis", and the README has a troubleshooting section covering
the ones people will actually hit.
2026-10-05 02:31:50 +03:00
MoHadiShibli 868840e409 Send input the moment it arrives, and leave an idle controller alone
Input was queued and handed to the virtual device on a 16 ms tick, so a press
could wait most of a frame before the console saw it, and the page only sent
state once per animation frame.

The payload now reports a sample as soon as it arrives, unless one went out
within the last 4 ms, and then keeps a 4 ms cadence while the player is doing
something, as a real DualShock 4 does. Half a second after the input stops it
falls back to the 16 ms keepalive, and the main loop's wait follows: 2 ms while
input is moving, 8 ms with a controller sitting idle, 50 ms with no controller at
all, so an unused service costs the console almost nothing.

On the page, a button, touch or key edge is flushed where it happens instead of
waiting for the next frame; stick and trigger movement still rides the frame
loop, where coalescing is what you want. A `ping` method and a round-trip
reading next to the version make a laggy network visible rather than guessed at.
2026-10-05 02:20:01 +03:00
MoHadiShibli 20b6ea2e2a Create controllers without stopping the service, and match only our own device
Connecting a controller took a second or two in the middle of the request
handler: drain the kernel log, prove it delivers, call AddDevice, then read the
log until the device turns up. Everyone else waited. A second player adding a
controller froze the first player's input for as long as it took.

The service now owns one kernel-log reader and reads it a line at a time from
its main loop, and creating a controller is a state machine that loop advances:
drain, verify with a marker, AddDevice, adopt the DeviceId. Nothing blocks, so
the other players keep playing and keep being answered while it runs. Their
slots show "Connecting" until the claim is complete. One controller is created
at a time, because two AddDevice calls at once produce two log lines with no way
to tell which device is which; a second request is refused rather than queued.

Nothing in vda.c waits any more, so the callback that kept pads reporting
through those waits is gone, and the line parsing moved to src/klog_line.c,
which the host tests build as it is.

Only the login manager's own line is accepted as our new device now:
SCE_MBUS_EVENT_DEVICE_ADDED with subType 2. The old code fell back to any
"device added" line it saw, so a real pad being plugged in while a controller
was being created could hand us a DeviceId we do not own, and every input would
go to someone else's pad.

On the page: a refused claim re-reads the console's view and gives up only the
controllers that are in use elsewhere, instead of disconnecting everything this
device was playing with; and when getGamepads() starts throwing, every gamepad
source is blanked, so a held button cannot be flushed for ever with nothing left
to release it.

The test stub is now a fake kernel log: it writes the lines firmware 10.01
writes, our own mirrored output included, so the real reading, marker check and
DeviceId matching are what the tests exercise. SECURITY.md writes down what the
open-LAN design does and does not defend.
2026-10-05 02:12:34 +03:00
MoHadiShibli 4331ec79fd Cleanup: drop the diagnostic spike, one version source, public tests
The staged spike that worked out the VDA call order is no longer part of the
build. It is kept at tag spike-final.

- src/main.c is the service only: instance lock, credentials, MBus and pad
  init, then the web service. src/server.c and include/c4f_server.h are gone
  with stage 8, and so are the stage-only helpers in src/vda.c: the MBus bind
  and holds, the assignment and button-map probes, and the GoldHEN klog stream
  path. The service reads /dev/klog, which is what works.
- VERSION holds the only version number. Both Makefiles pass it in, the
  packager reads it for param.sfo and the package name, and the build and
  deploy scripts read it for the file they look for.
- The payload's log is /data/control4free/control4free.log, not spike.log.
- The page drops the protocol 1 branches: the payload has always answered 2.
  A console slot is a "controller" and a pad plugged into the phone or PC is a
  "gamepad", so the two no longer read as the same word.
- The host tests move to tests/, with tests/run.py to run all four suites. They
  build the real sources with the PS4 calls stubbed, so they need no console.
  klog_test now covers the device path only, and asserts that nothing ever
  connects to GoldHEN's klog server.
2026-10-05 01:53:11 +03:00
MoHadiShibli f008db6e16 0.2.2: read /dev/klog directly for sign-in again
On the console, 0.2.1 often could not add a controller ("Cannot read
controller sign-in events"). Its log shows why: once Control4Free let go
of GoldHEN's klog stream, every new connection read nothing for 4-5
minutes. GoldHEN's klog server serves one client at a time and is slow to
notice that one has left.

The browser service now opens /dev/klog itself, only while a controller
waits for sign-in, and releases it afterwards, so GoldHEN's klog server
works the rest of the time. It never uses GoldHEN's stream; only the
diagnostic stages still fall back to it.

Version 0.2.2 (APP_VER 00.22).
2026-10-05 00:03:34 +03:00
MoHadiShibli 5611a55075 0.2.1: survive rest mode, share GoldHEN's klog, timestamped logs
- The service checks its listener every second and notices long pauses
  such as rest mode. It then drops stale connections, keeps controllers
  neutral, and rebuilds the listener. Confirmed on the console: Control4Free
  survives rest mode.
- A lock in /data/control4free stops a second copy before it touches the
  host process's credentials or the log.
- Browser mode reads klog through GoldHEN's klog server first, after a
  marker check, and falls back to /dev/klog. It holds a reader only while
  controllers wait for sign-in, so GoldHEN's own klog keeps working.
- Log lines carry elapsed time, the previous run is kept as
  spike.log.previous, and a heartbeat is logged every minute.
- Version 0.2.1 (APP_VER 00.21).
2026-10-04 22:59:59 +03:00
MoHadiShibli 346b18ba6c Logo: a DualShock 4 mark, and an icon with three lit controllers
The mark is a vector DualShock 4 seen from above (launcher/logo.c), filled
with stb_truetype's anti-aliased rasterizer through a small path API in
draw.c. The app's top bar and the page's top bar, toast and favicon all use
it. The package icon shows three controllers with their light bars glowing
in the page's player colours.
2026-10-04 21:42:23 +03:00
MoHadiShibli 5e38f1db2d Launcher: leave the app sandbox so it can reach Control4Free
On the console the app's connections to 127.0.0.1 and to the console's own
address both failed with EACCES: the app sandbox does not let an app reach
the console itself. So the app reached neither Control4Free nor PayLoader,
while a phone or PC on the network could.

The app now takes itself out of the sandbox at startup with GoldHEN's SDK
call, the same one the auto-start setup used, and stays out. The bundled
payload is read into memory first, since /app0 is only visible from inside,
and starts send it from there. When nothing connects at all, the screen
says the app cannot reach Control4Free instead of blaming another copy.

OpenOrbis's headers give SIGSYS Linux's value (31); the kernel's is 12.
2026-10-04 21:23:14 +03:00
MoHadiShibli 0fe839ad2e Launcher: set up GoldHEN auto-start itself; reach Control4Free from the app
- The first Cross copies the bundled payload to /data/payloads and adds it
  to GoldHEN's AutoRun list, then starts it if PayLoader is on. Triangle
  turns auto-start on or off, or updates an older copy. The app leaves its
  sandbox for this through GoldHEN's SDK call and returns right after.
- The app tries 127.0.0.1 and then the console's own address, for both
  Control4Free and PayLoader, and shows why neither answered.
- The launcher API no longer requires a loopback source address, since
  the app's sandbox may not appear as 127.0.0.1. The custom header and
  the Origin check still keep websites out.
- The screen and messages no longer assume a phone.
2026-10-04 21:12:51 +03:00
MoHadiShibli b3863fa5f1 Launcher app: home-screen PKG to start, check and stop Control4Free
An OpenOrbis app that sends the bundled payload to GoldHEN's PayLoader,
shows its address and a QR code, and stops it through the loopback API.
It draws its screen in software in the controller page's style
(stb_truetype with Roboto), and its icon with the same code.

The package (title ID CFRE00001) carries OpenOrbis's stub libc.prx and
libSceFios2.prx in sce_module/, as the toolchain asks.

The README covers GoldHEN AutoRun, the launcher, the page and the build.
2026-10-04 19:53:45 +03:00