mirror of
https://github.com/MoHadiShibli/Control4Free.git
synced 2026-10-06 10:00:28 +02:00
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).
This commit is contained in:
1 parent
5611a55075
commit
f008db6e16
7 files changed
+60
-43
No files matched your search
@@ -5,10 +5,10 @@ keyboard, or an Xbox/other controller exposed by the browser's Gamepad API.
|
||||
Virtual controllers use the PS4's native user-selection screen, so they work on
|
||||
the home screen, at sign-in and in games.
|
||||
|
||||
**Status: browser control, native user sign-in, gameplay, the launcher and
|
||||
GoldHEN AutoRun have been confirmed on the development console.** Version 0.2.1
|
||||
adds network recovery and changes klog ownership; these changes pass local tests
|
||||
and still need a console rest/wake test. Four virtual slots are exposed; the
|
||||
**Status: browser control, native user sign-in, gameplay, the launcher,
|
||||
GoldHEN AutoRun and recovery after rest mode have been confirmed on the
|
||||
development console.** Version 0.2.2 reads the kernel log directly again for
|
||||
sign-in; it still needs its console check. Four virtual slots are exposed; the
|
||||
console's device limits apply.
|
||||
|
||||
## Requirements
|
||||
@@ -25,7 +25,7 @@ console's device limits apply.
|
||||
|
||||
## Install
|
||||
|
||||
1. Copy `build/Control4Free-0.2.1.pkg` to a USB drive (or to `/data/pkg/` over
|
||||
1. Copy `build/Control4Free-0.2.2.pkg` to a USB drive (or to `/data/pkg/` over
|
||||
GoldHEN's FTP server) and install it with GoldHEN's Package Installer.
|
||||
2. Open **Control4Free** from the home screen and press **Cross** once. The app
|
||||
adds Control4Free to GoldHEN's AutoRun (GoldHEN 2.4b18.10 or later), so GoldHEN
|
||||
@@ -63,7 +63,7 @@ When you update Control4Free this way, replace `/data/payloads/control4free.elf`
|
||||
controller page's menu, or restart the PS4. That old version has no launcher API,
|
||||
so the app will not start a second copy over it.
|
||||
|
||||
**Rest mode (0.2.1):** the service now closes stale connections and rebuilds its
|
||||
**Rest mode (since 0.2.1):** the service closes stale connections and rebuilds its
|
||||
listener after socket failures or a long pause. Queued input is discarded, and
|
||||
disconnected controllers report neutral input. Reopen the controller page and
|
||||
select your controller after waking; an unused controller is removed after the
|
||||
@@ -71,12 +71,13 @@ reconnect grace period. This can recover a surviving payload's network service;
|
||||
it cannot revive a host process that the console terminated or stopped running.
|
||||
When upgrading a stuck older instance, restart the PS4 and load GoldHEN again.
|
||||
|
||||
**Kernel logs:** Control4Free requests a verified stream from GoldHEN first,
|
||||
falling back to `/dev/klog`. It only keeps the reader while controllers are
|
||||
awaiting native sign-in, and releases it once sign-in finishes or those
|
||||
controllers are removed. Close other klog viewers when adding a controller:
|
||||
GoldHEN versions that serve one reader cannot share that capture window. A busy
|
||||
reader now produces a retryable error before a virtual device is created.
|
||||
**Kernel logs:** controller sign-in is detected in the PS4's kernel log, which
|
||||
has a single reader. Control4Free opens `/dev/klog` only while a controller is
|
||||
waiting for sign-in and releases it afterwards, so GoldHEN's klog server works
|
||||
the rest of the time. It does not use GoldHEN's klog stream: GoldHEN serves one
|
||||
client at a time and, after one leaves, can go minutes without serving the next.
|
||||
If a klog viewer is connected to GoldHEN when you add a controller, the page
|
||||
says so; close the viewer and try again.
|
||||
|
||||
Diagnostics are saved at `/data/control4free/spike.log`, with elapsed timestamps
|
||||
such as `[c4f] [+00:01:23.456]`; the PS4's calendar setting is not used. Starting
|
||||
@@ -150,7 +151,7 @@ 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'
|
||||
```
|
||||
|
||||
Output: `build/Control4Free-0.2.1.pkg` (title ID `CFRE00001`). On Windows,
|
||||
Output: `build/Control4Free-0.2.2.pkg` (title ID `CFRE00001`). On Windows,
|
||||
`tools/build-launcher.ps1` runs both image builds and the package build. It does
|
||||
not send anything to a console. Packaging uses OpenOrbis and LibOrbisPkg. The
|
||||
launcher draws its screen and its icon in software, in the controller page's style.
|
||||
|
||||
+4
-2
@@ -99,8 +99,10 @@ void c4fProbeButtonMap(const C4fVirtualPad *pad, int32_t readHandle);
|
||||
* already held by that server. */
|
||||
#define C4F_KLOG_PORT 3232
|
||||
|
||||
/* Verified GoldHEN socket first, /dev/klog fallback; -1 if neither delivers
|
||||
* a fresh marker. The caller must release it when sign-in capture finishes. */
|
||||
/* /dev/klog only, verified by a fresh marker; -1 if busy or silent. For the
|
||||
* browser service, which holds it only while a controller signs in. */
|
||||
int c4fKlogOpenDevice(void);
|
||||
/* /dev/klog, else GoldHEN's stream on 3232 (diagnostic stages); verified. */
|
||||
int c4fKlogOpen(void);
|
||||
void c4fKlogDrain(int fd);
|
||||
/* Writes a marker to klog and reads it back. 0 = the capture path works. */
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
#ifndef C4F_LAUNCHER_SCREEN_H
|
||||
#define C4F_LAUNCHER_SCREEN_H
|
||||
#include <stdint.h>
|
||||
#define C4F_LAUNCHER_VERSION "0.2.1"
|
||||
#define C4F_LAUNCHER_VERSION "0.2.2"
|
||||
#define C4F_SCREEN_WIDTH 1920
|
||||
#define C4F_SCREEN_HEIGHT 1080
|
||||
typedef struct {
|
||||
|
||||
@@ -238,28 +238,42 @@ fail:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Drained and proven by a marker that comes back, or closed. */
|
||||
static int c4fKlogVerified(int fd, const char *what)
|
||||
{
|
||||
c4fKlogDrain(fd);
|
||||
if (c4fKlogSelfTest(fd) == 0) {
|
||||
c4fLog("reading klog through %s\n", what);
|
||||
return fd;
|
||||
}
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* GoldHEN's klog server opens /dev/klog only while it has a client and serves
|
||||
* one client at a time. After a client leaves it can go minutes without
|
||||
* serving the next one: on the console (2026-10-04) every reconnect after a
|
||||
* release read 0 bytes for 4-5 minutes. So the browser service never uses the
|
||||
* stream; it reads the device itself, only while a controller signs in. */
|
||||
int c4fKlogOpenDevice(void)
|
||||
{
|
||||
int fd = open("/dev/klog", O_RDONLY | O_NONBLOCK);
|
||||
if (fd < 0) {
|
||||
c4fLog("open(/dev/klog) failed errno=%d (16: GoldHEN's klog server has a client)\n", errno);
|
||||
return -1;
|
||||
}
|
||||
return c4fKlogVerified(fd, "/dev/klog");
|
||||
}
|
||||
|
||||
int c4fKlogOpen(void)
|
||||
{
|
||||
int fd = c4fKlogConnectLocal();
|
||||
if (fd >= 0) {
|
||||
c4fKlogDrain(fd);
|
||||
if (c4fKlogSelfTest(fd) == 0) {
|
||||
c4fLog("reading klog through 127.0.0.1:%d\n", C4F_KLOG_PORT);
|
||||
return fd;
|
||||
}
|
||||
close(fd);
|
||||
c4fLog("klog socket has no live stream; another log client may own it\n");
|
||||
}
|
||||
fd = open("/dev/klog", O_RDONLY | O_NONBLOCK);
|
||||
if (fd >= 0) {
|
||||
c4fKlogDrain(fd);
|
||||
if (c4fKlogSelfTest(fd) == 0) {
|
||||
c4fLog("temporarily reading /dev/klog for controller sign-in\n");
|
||||
return fd;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
c4fLog("no verified klog source; close other log viewers before adding a controller\n");
|
||||
int fd = c4fKlogOpenDevice();
|
||||
if (fd >= 0) return fd;
|
||||
/* The diagnostic stages run once, usually with the PC's klog viewer
|
||||
* attached, which holds the device: then the stream is the only way. */
|
||||
fd = c4fKlogConnectLocal();
|
||||
if (fd >= 0 && (fd = c4fKlogVerified(fd, "127.0.0.1:3232")) >= 0) return fd;
|
||||
c4fLog("no verified klog source\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "c4f_vda.h"
|
||||
#include "c4f_web.h"
|
||||
|
||||
#define C4F_VERSION "0.2.1"
|
||||
#define C4F_VERSION "0.2.2"
|
||||
#define C4F_INPUT_MASK 0x0011ffffu
|
||||
#define C4F_REPORT_MS 16
|
||||
#ifndef C4F_STALE_MS
|
||||
@@ -257,8 +257,8 @@ static void c4fClaim(C4fWeb *app, C4fNetClient *c, C4fRequest *r)
|
||||
c4fReadKlog(app);
|
||||
if (app->klogFd >= 0 && c4fKlogSelfTest(app->klogFd)) c4fReleaseKlog(app);
|
||||
}
|
||||
if (app->klogFd < 0) app->klogFd = c4fKlogOpen();
|
||||
if (app->klogFd < 0 && needsDevice) { c4fError(c, r, 503, "Cannot read controller sign-in events. Close other klog viewers and try again."); return; }
|
||||
if (app->klogFd < 0) app->klogFd = c4fKlogOpenDevice();
|
||||
if (app->klogFd < 0 && needsDevice) { c4fError(c, r, 503, "Cannot read the PS4's kernel log, which sign-in needs. If a klog viewer is connected to GoldHEN, close it and try again."); return; }
|
||||
}
|
||||
for (int i = 0; i < C4F_MAX_PADS; i++) if ((wanted & (1u << i)) && !app->pads[i].active) {
|
||||
C4fWebPad *p = &app->pads[i];
|
||||
|
||||
@@ -9,7 +9,7 @@ try {
|
||||
if ($LASTEXITCODE -ne 0) { throw 'Launcher toolchain build failed.' }
|
||||
docker run --rm --network none -v "${projectRoot}:/src" -w /src control4free-launcher-build bash -lc 'make && make -C launcher'
|
||||
if ($LASTEXITCODE -ne 0) { throw 'Launcher package build failed.' }
|
||||
Get-Item -LiteralPath (Join-Path $projectRoot 'build/Control4Free-0.2.1.pkg') | Select-Object FullName,Length
|
||||
Get-Item -LiteralPath (Join-Path $projectRoot 'build/Control4Free-0.2.2.pkg') | Select-Object FullName,Length
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
@@ -93,11 +93,11 @@ def main():
|
||||
sfo = 'sce_sys/param.sfo'
|
||||
run(pkgtool, 'sfo_new', sfo)
|
||||
entries = {
|
||||
'APP_TYPE': ('Integer', 4, '1'), 'APP_VER': ('Utf8', 8, '00.21'),
|
||||
'APP_TYPE': ('Integer', 4, '1'), 'APP_VER': ('Utf8', 8, '00.22'),
|
||||
'ATTRIBUTE': ('Integer', 4, '0'), 'CATEGORY': ('Utf8', 4, 'gd'),
|
||||
'CONTENT_ID': ('Utf8', 48, CONTENT_ID), 'DOWNLOAD_DATA_SIZE': ('Integer', 4, '0'),
|
||||
'SYSTEM_VER': ('Integer', 4, '0'), 'TITLE': ('Utf8', 128, 'Control4Free'),
|
||||
'TITLE_ID': ('Utf8', 12, TITLE_ID), 'VERSION': ('Utf8', 8, '00.21'),
|
||||
'TITLE_ID': ('Utf8', 12, TITLE_ID), 'VERSION': ('Utf8', 8, '00.22'),
|
||||
}
|
||||
for key, (kind, size, value) in entries.items():
|
||||
run(pkgtool, 'sfo_setentry', sfo, key, '--type', kind, '--maxsize', size, '--value', value)
|
||||
@@ -123,7 +123,7 @@ def main():
|
||||
shutil.copyfile(project, OUT / 'launcher.gp4')
|
||||
run(pkgtool, 'pkg_build', project, OUT)
|
||||
generated = OUT / (CONTENT_ID + '.pkg')
|
||||
target = ROOT / 'build/Control4Free-0.2.1.pkg'
|
||||
target = ROOT / 'build/Control4Free-0.2.2.pkg'
|
||||
shutil.copyfile(generated, target)
|
||||
print(f'Built {target} ({target.stat().st_size:,} bytes)', flush=True)
|
||||
|
||||
|
||||
Reference in new issue
Block a user