mirror of
https://github.com/SirHumza/orbisRPC.git
synced 2026-10-06 10:00:36 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8f6e541d9 | ||
|
|
ba4e28c98a | ||
|
|
53b11f7a66 | ||
|
|
05401494cc | ||
|
|
0b207aa743 |
No files matched your search
@@ -5,7 +5,7 @@
|
||||
# orbisRPC — Discord Rich Presence for PS4 (GoldHEN RPC)
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/SirHumza/orbisRPC/releases/tag/v1.0.0"><img src="https://img.shields.io/badge/version-1.0.0-ffd800?style=flat-square" alt="version"></a>
|
||||
<a href="https://github.com/SirHumza/orbisRPC/releases/tag/v1.1.0"><img src="https://img.shields.io/badge/version-1.1.0-ffd800?style=flat-square" alt="version"></a>
|
||||
<img src="https://img.shields.io/badge/PS4-GoldHEN-003791?style=flat-square" alt="PS4 GoldHEN">
|
||||
<img src="https://img.shields.io/badge/Discord-Rich%20Presence-5865F2?style=flat-square" alt="Discord">
|
||||
<img src="https://img.shields.io/badge/tables-none-brightgreen?style=flat-square" alt="no tables">
|
||||
@@ -19,8 +19,8 @@ playing to Discord: name, cover art, timer. No PC at runtime.</p>
|
||||
|
||||
## Install (5 minutes)
|
||||
|
||||
1. Grab `OrbisRPC-Setup-1.0.0.pkg` from the
|
||||
[Releases page](https://github.com/SirHumza/orbisRPC/releases/tag/v1.0.0)
|
||||
1. Grab `OrbisRPC-Setup-1.1.0.pkg` from the
|
||||
[Releases page](https://github.com/SirHumza/orbisRPC/releases/tag/v1.1.0)
|
||||
and install it with Package Installer.
|
||||
2. Open **orbisRPC Setup**. It stages `orbisrpc.bin` in
|
||||
`/data/payloads`, writes `/data/orbisRPC/config.json`, retires any old
|
||||
|
||||
+34
-11
@@ -6,7 +6,19 @@ VERSION := 1.1.0
|
||||
TITLE_ID := ORPC00001
|
||||
CONTENT_ID := IV0000-ORPC00001_00-ORBISRPCSETUP000
|
||||
|
||||
LIBS := -lc -lkernel -lc++ -lSDL2 -lSDL2main -lScePigletv2VSH -lSceAudioOut -lSceVideoOut -lSceCommonDialog -lSceImeDialog -lSceSysmodule -lSceNet -lSceUserService -lSceSystemService -lScePad
|
||||
# Packaging knobs under experiment (see the note above param.sfo).
|
||||
# PKG_ATTR=32 PKG_CATEGORY=gde AUTHINFO=1 -> Apollo-parity build
|
||||
PKG_ATTR ?= 0
|
||||
PKG_CATEGORY ?= gd
|
||||
AUTHINFO ?= 0
|
||||
AUTHINFO_BLOB := 000000000000000000000000001C004000FF000000000080000000000000000000000000000000000000008000400040000000000000008000000000000000080040FFFF000000F000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
ifeq ($(AUTHINFO),1)
|
||||
AUTHINFO_FLAG := --authinfo $(AUTHINFO_BLOB)
|
||||
else
|
||||
AUTHINFO_FLAG :=
|
||||
endif
|
||||
|
||||
LIBS := -lc -lkernel -lc++ -lSceMsgDialog -lSceCommonDialog -lSceImeDialog -lSceSysmodule -lSceNet -lSceUserService -lSceSystemService -lScePad
|
||||
|
||||
ASSETS := $(wildcard installer/assets/**/*)
|
||||
LIBMODULES := $(wildcard installer/sce_module/*)
|
||||
@@ -45,12 +57,30 @@ $(CONTENT_ID).pkg: installer/pkg.gp4
|
||||
installer/pkg.gp4: installer/eboot.bin installer/assets/daemon.elf installer/assets/config.json installer/sce_sys/about/right.sprx installer/sce_sys/param.sfo installer/sce_sys/icon0.png installer/sce_sys/pic1.png $(LIBMODULES) $(ASSETS)
|
||||
cd installer && $(TOOLCHAIN)/bin/$(CDIR)/create-gp4 -out pkg.gp4 --content-id=$(CONTENT_ID) --files "eboot.bin assets/daemon.elf assets/config.json sce_sys/about/right.sprx sce_sys/param.sfo sce_sys/icon0.png sce_sys/pic1.png sce_module/libSceFios2.prx sce_module/libc.prx $(patsubst installer/%,%,$(ASSETS))"
|
||||
|
||||
# PACKAGING IS AN OPEN EXPERIMENT, NOT A SETTLED ANSWER.
|
||||
#
|
||||
# History: v1.0.0 shipped ATTRIBUTE=0 / CATEGORY=gd and launched on real
|
||||
# hardware. A "universal packaging" theory (borrowed from Apollo Save
|
||||
# Tool) changed these to 32 / gde and added --authinfo; every build
|
||||
# carrying those values died silently pre-logging on a real console (4/4).
|
||||
# Isolation ruled out --authinfo (2 builds without it, still crashed), the
|
||||
# SDL UI, and the native UI. LIBS, the object set, sce_module, and
|
||||
# installer/ui.c are identical to the working v1.0.0 build, and every
|
||||
# installer.c / icfg.c delta is provably safe before the first log call.
|
||||
# That leaves param.sfo as the only untested variable.
|
||||
#
|
||||
# COUNTER-EVIDENCE (do not delete without reading): Apollo's current main
|
||||
# (v02.32) ships ATTRIBUTE=32 / CATEGORY=gde / --authinfo and is a proven
|
||||
# universal PS4 app. So 0/gd is very likely innocent too, and the real
|
||||
# cause is still unknown. The 0/gd build is a TEST, not a conclusion.
|
||||
# Whichever value survives a console test wins; switch with:
|
||||
# make -f installer/Makefile PKG_ATTR=32 PKG_CATEGORY=gde AUTHINFO=1
|
||||
installer/sce_sys/param.sfo: installer/Makefile
|
||||
$(TOOLCHAIN)/bin/$(CDIR)/PkgTool.Core sfo_new $@
|
||||
$(TOOLCHAIN)/bin/$(CDIR)/PkgTool.Core sfo_setentry $@ APP_TYPE --type Integer --maxsize 4 --value 1
|
||||
$(TOOLCHAIN)/bin/$(CDIR)/PkgTool.Core sfo_setentry $@ APP_VER --type Utf8 --maxsize 8 --value '$(VERSION)'
|
||||
$(TOOLCHAIN)/bin/$(CDIR)/PkgTool.Core sfo_setentry $@ ATTRIBUTE --type Integer --maxsize 4 --value 32
|
||||
$(TOOLCHAIN)/bin/$(CDIR)/PkgTool.Core sfo_setentry $@ CATEGORY --type Utf8 --maxsize 4 --value 'gde'
|
||||
$(TOOLCHAIN)/bin/$(CDIR)/PkgTool.Core sfo_setentry $@ ATTRIBUTE --type Integer --maxsize 4 --value $(PKG_ATTR)
|
||||
$(TOOLCHAIN)/bin/$(CDIR)/PkgTool.Core sfo_setentry $@ CATEGORY --type Utf8 --maxsize 4 --value '$(PKG_CATEGORY)'
|
||||
$(TOOLCHAIN)/bin/$(CDIR)/PkgTool.Core sfo_setentry $@ CONTENT_ID --type Utf8 --maxsize 48 --value '$(CONTENT_ID)'
|
||||
$(TOOLCHAIN)/bin/$(CDIR)/PkgTool.Core sfo_setentry $@ DOWNLOAD_DATA_SIZE --type Integer --maxsize 4 --value 0
|
||||
$(TOOLCHAIN)/bin/$(CDIR)/PkgTool.Core sfo_setentry $@ SYSTEM_VER --type Integer --maxsize 4 --value 0
|
||||
@@ -60,18 +90,11 @@ installer/sce_sys/param.sfo: installer/Makefile
|
||||
|
||||
installer/eboot.bin: $(OBJS)
|
||||
$(LD) $(INTDIR)/*.o -o $(INTDIR)/$(PROJDIR).elf $(LDFLAGS)
|
||||
$(TOOLCHAIN)/bin/$(CDIR)/create-fself-macos -in=$(INTDIR)/$(PROJDIR).elf -out=$(INTDIR)/$(PROJDIR).oelf --eboot "installer/eboot.bin" --paid 0x3800000000000011 --authinfo 000000000000000000000000001C004000FF000000000080000000000000000000000000000000000000008000400040000000000000008000000000000000080040FFFF000000F000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
$(TOOLCHAIN)/bin/$(CDIR)/create-fself-macos -in=$(INTDIR)/$(PROJDIR).elf -out=$(INTDIR)/$(PROJDIR).oelf --eboot "installer/eboot.bin" --paid 0x3800000000000011 $(AUTHINFO_FLAG)
|
||||
|
||||
$(INTDIR)/%.o: $(PROJDIR)/%.c
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
# Embedded bitmap font (build-time rasterized; checked in but regenerable).
|
||||
installer/font.h: scripts/genfont.py
|
||||
python3 scripts/genfont.py
|
||||
|
||||
$(INTDIR)/ui.o: installer/ui.c installer/font.h
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
$(INTDIR)/jsonlite.o: orbisrpc/jsonlite.c
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
|
||||
-2366
File diff suppressed because it is too large.
Load diff
+25
-1
@@ -17,7 +17,7 @@
|
||||
#include "icfg.h"
|
||||
|
||||
#ifndef SETUP_VERSION
|
||||
#define SETUP_VERSION "1.0.0"
|
||||
#define SETUP_VERSION "1.1.0"
|
||||
#endif
|
||||
#define DAEMON_ELF "/app0/assets/daemon.elf"
|
||||
#define GEN_PATH "/data/orbisRPC/daemon.gen"
|
||||
@@ -30,6 +30,30 @@
|
||||
* back over FTP. The dialog alone can't say WHICH stage failed. */
|
||||
static const char *g_stage = "-";
|
||||
|
||||
/* --- pre-main boot marker ------------------------------------------
|
||||
* The wizard died before main() on every packaging experiment, leaving
|
||||
* install.log untouched and the crash handler (installed inside main)
|
||||
* never armed. A constructor runs before main, so it separates the two
|
||||
* failure classes for good:
|
||||
* no BOOT line at all -> the loader/SELF never got control (packaging,
|
||||
* authinfo, SIGSYS) or a pre-main fault
|
||||
* BOOT but no stage -> main started, died before the first ilog()
|
||||
* Async-signal-safe only: raw open/write, no stdio, no malloc. */
|
||||
__attribute__((constructor))
|
||||
static void boot_marker(void){
|
||||
static const char msg[] = "BOOT installer entered pre-main\n";
|
||||
const char *paths[2];
|
||||
size_t i;
|
||||
paths[0] = "/data/install.log";
|
||||
paths[1] = INST_LOG;
|
||||
for(i = 0; i < 2; i++){
|
||||
int fd = open(paths[i], O_WRONLY | O_APPEND | O_CREAT, 0666);
|
||||
if(fd < 0) continue;
|
||||
{ ssize_t w = write(fd, msg, sizeof msg - 1); (void)w; }
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static void ilog(const char *tag, int err, long expect, long got){
|
||||
FILE *f;
|
||||
g_stage = tag;
|
||||
|
||||
Binary file not shown.
+105
-296
@@ -1,15 +1,12 @@
|
||||
/* ui.c - custom SDL2 installer UI: branded fullscreen cards instead of
|
||||
* stock Sony MsgDialogs. Same ui.h API, so installer.c is untouched.
|
||||
* Token entry still uses the system IME (proven overlay); everything
|
||||
* else is rendered by us: Discord-blurple card, progress bar, X-to-continue.
|
||||
* Needs the console (SDL/Pad/IME system calls); pure logic lives in icfg.c. */
|
||||
/* ui.c - native PS4 dialogs: MsgDialog (ok / yes-no / progress) + ImeDialog.
|
||||
* Everything here needs the console (dialog system calls); pure logic
|
||||
* (validation, config merge) lives in icfg.c and is host-tested. */
|
||||
#include "ui.h"
|
||||
#include "font.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <orbis/CommonDialog.h>
|
||||
#include <orbis/MsgDialog.h>
|
||||
#include <orbis/ImeDialog.h>
|
||||
#include <orbis/UserService.h>
|
||||
#include <orbis/Sysmodule.h>
|
||||
@@ -19,325 +16,139 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define SCR_W 1920
|
||||
#define SCR_H 1080
|
||||
|
||||
/* Palette */
|
||||
#define C_BG_R 30 /* near-black warm gray */
|
||||
#define C_BG_G 31
|
||||
#define C_BG_B 34
|
||||
#define C_CARD_R 88 /* Discord blurple */
|
||||
#define C_CARD_G 101
|
||||
#define C_CARD_B 242
|
||||
#define C_INK_R 255 /* white text */
|
||||
#define C_INK_G 255
|
||||
#define C_INK_B 255
|
||||
#define C_DIM_R 200
|
||||
#define C_DIM_G 203
|
||||
#define C_DIM_B 220
|
||||
#define C_BAR_BG_R 40
|
||||
#define C_BAR_BG_G 43
|
||||
#define C_BAR_BG_B 55
|
||||
#define C_BAR_FG_R 255
|
||||
#define C_BAR_FG_G 255
|
||||
#define C_BAR_FG_B 255
|
||||
|
||||
static SDL_Window *g_win = NULL;
|
||||
static SDL_Surface *g_surf = NULL;
|
||||
static int ui_ready = 0;
|
||||
static int ime_dialog_running = 0;
|
||||
static int g_pad[4] = { -1, -1, -1, -1 };
|
||||
static uint32_t g_prevbtn[4] = { 0, 0, 0, 0 };
|
||||
|
||||
static void ime_dbg(const char *msg){
|
||||
int fd = open("/data/ime_debug.log", O_WRONLY|O_CREAT|O_APPEND, 0666);
|
||||
if(fd >= 0){ write(fd, msg, strlen(msg)); close(fd); }
|
||||
}
|
||||
|
||||
/* --- pixel helpers (format-safe via SDL_GetRGB/MapRGB) ---------------- */
|
||||
static void blend_px(int x, int y, int r, int g, int b, unsigned a){
|
||||
Uint8 dr, dg, db;
|
||||
Uint32 *p;
|
||||
if(!g_surf || x < 0 || y < 0 || x >= g_surf->w || y >= g_surf->h || a == 0) return;
|
||||
p = (Uint32 *)((Uint8 *)g_surf->pixels + (size_t)y * (size_t)g_surf->pitch + (size_t)x * 4);
|
||||
SDL_GetRGB(*p, g_surf->format, &dr, &dg, &db);
|
||||
dr = (Uint8)((dr * (255 - a) + (unsigned)r * a) / 255);
|
||||
dg = (Uint8)((dg * (255 - a) + (unsigned)g * a) / 255);
|
||||
db = (Uint8)((db * (255 - a) + (unsigned)b * a) / 255);
|
||||
*p = SDL_MapRGB(g_surf->format, dr, dg, db);
|
||||
static void base_init(OrbisMsgDialogParam *param){
|
||||
memset(param, 0, sizeof(*param));
|
||||
param->baseParam.size = (uint32_t)sizeof(param->baseParam);
|
||||
param->baseParam.magic =
|
||||
(uint32_t)(ORBIS_COMMON_DIALOG_MAGIC_NUMBER + (uint64_t)¶m->baseParam);
|
||||
param->size = sizeof(OrbisMsgDialogParam);
|
||||
param->mode = ORBIS_MSG_DIALOG_MODE_USER_MSG;
|
||||
}
|
||||
|
||||
static void fill_rect(int x, int y, int w, int h, int r, int g, int b){
|
||||
SDL_Rect rc;
|
||||
if(!g_surf) return;
|
||||
rc.x = x; rc.y = y; rc.w = w; rc.h = h;
|
||||
SDL_FillRect(g_surf, &rc, SDL_MapRGB(g_surf->format,
|
||||
(Uint8)r, (Uint8)g, (Uint8)b));
|
||||
}
|
||||
static int ui_ready = 0;
|
||||
static int ime_dialog_running = 0;
|
||||
|
||||
static unsigned text_w(const char *s){
|
||||
unsigned w = 0;
|
||||
for(; *s; s++){
|
||||
unsigned c = (unsigned char)*s;
|
||||
if(c < FONT_FIRST || c >= FONT_FIRST + FONT_COUNT) c = (unsigned)'?';
|
||||
w += font_adv[c - FONT_FIRST] + 2;
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
static void draw_text(int x, int y, const char *s, int r, int g, int b){
|
||||
if(!g_surf || !s) return;
|
||||
if(SDL_MUSTLOCK(g_surf)) SDL_LockSurface(g_surf);
|
||||
for(; *s; s++){
|
||||
unsigned c = (unsigned char)*s;
|
||||
unsigned gi, gw, gx, gy;
|
||||
if(c == '\n'){ continue; } /* caller splits lines */
|
||||
if(c < FONT_FIRST || c >= FONT_FIRST + FONT_COUNT) c = (unsigned)'?';
|
||||
gi = c - FONT_FIRST;
|
||||
gw = font_adv[gi];
|
||||
for(gy = 0; gy < FONT_H; gy++)
|
||||
for(gx = 0; gx < gw; gx++)
|
||||
blend_px(x + (int)gx, y + (int)gy, r, g, b,
|
||||
font_px[font_off[gi] + gy * gw + gx]);
|
||||
x += (int)gw + 2;
|
||||
}
|
||||
if(SDL_MUSTLOCK(g_surf)) SDL_UnlockSurface(g_surf);
|
||||
}
|
||||
|
||||
static void present(void){
|
||||
if(g_win) SDL_UpdateWindowSurface(g_win);
|
||||
}
|
||||
|
||||
/* --- card layout ------------------------------------------------------ */
|
||||
#define CARD_X 260
|
||||
#define CARD_Y 240
|
||||
#define CARD_W (SCR_W - 2 * CARD_X)
|
||||
#define CARD_H 600
|
||||
#define PAD_X 64
|
||||
#define TITLE_Y (CARD_Y + 48)
|
||||
#define BODY_Y (CARD_Y + 150)
|
||||
#define LINE_H (FONT_H + 12)
|
||||
#define MAX_LINES 12
|
||||
|
||||
/* Greedy word wrap into fixed rows. Unknown glyphs count as '?'. */
|
||||
static int wrap_lines(const char *msg, char lines[MAX_LINES][128]){
|
||||
int n = 0;
|
||||
char cur[128];
|
||||
size_t cl = 0;
|
||||
unsigned px = 0;
|
||||
int have_space = 0; /* a wrap point exists inside cur */
|
||||
size_t space_at = 0;
|
||||
unsigned px_after_space = 0;
|
||||
cur[0] = 0;
|
||||
while(*msg && n < MAX_LINES){
|
||||
unsigned c, a;
|
||||
if(*msg == '\n'){
|
||||
strncpy(lines[n], cur, 127); lines[n][127] = 0; n++;
|
||||
cur[0] = 0; cl = 0; px = 0;
|
||||
have_space = 0; space_at = 0; px_after_space = 0;
|
||||
msg++;
|
||||
continue;
|
||||
}
|
||||
c = (unsigned char)*msg;
|
||||
a = (c < FONT_FIRST || c >= FONT_FIRST + FONT_COUNT)
|
||||
? font_adv['?' - FONT_FIRST] : font_adv[c - FONT_FIRST];
|
||||
if(px + a + 2 > (unsigned)(CARD_W - 2 * PAD_X) && cl > 0){
|
||||
if(have_space){
|
||||
/* break after the last space */
|
||||
size_t tail = cl - (space_at + 1);
|
||||
memcpy(lines[n], cur, space_at);
|
||||
lines[n][space_at] = 0; n++;
|
||||
if(n >= MAX_LINES) break;
|
||||
memmove(cur, cur + space_at + 1, tail + 1);
|
||||
cl = tail; px = px - px_after_space;
|
||||
have_space = 0; space_at = 0; px_after_space = 0;
|
||||
continue; /* re-process this char */
|
||||
}
|
||||
strncpy(lines[n], cur, 127); lines[n][127] = 0; n++;
|
||||
if(n >= MAX_LINES) break;
|
||||
cur[0] = 0; cl = 0; px = 0;
|
||||
have_space = 0; space_at = 0; px_after_space = 0;
|
||||
continue; /* re-process this char */
|
||||
}
|
||||
if(cl < sizeof cur - 1){ cur[cl++] = *msg; cur[cl] = 0; px += a + 2; }
|
||||
if(c == ' '){ have_space = 1; space_at = cl - 1; px_after_space = px; }
|
||||
msg++;
|
||||
}
|
||||
if(cl > 0 && n < MAX_LINES){ strncpy(lines[n], cur, 127); lines[n][127] = 0; n++; }
|
||||
return n;
|
||||
}
|
||||
|
||||
static void render_card(const char *title, const char *msg, int pct, int show_bar,
|
||||
const char *footer){
|
||||
char lines[MAX_LINES][128];
|
||||
int n, i;
|
||||
fill_rect(0, 0, SCR_W, SCR_H, C_BG_R, C_BG_G, C_BG_B);
|
||||
fill_rect(CARD_X, CARD_Y, CARD_W, CARD_H, C_CARD_R, C_CARD_G, C_CARD_B);
|
||||
draw_text(CARD_X + PAD_X, TITLE_Y, title, C_INK_R, C_INK_G, C_INK_B);
|
||||
fill_rect(CARD_X + PAD_X, TITLE_Y + FONT_H + 16, CARD_W - 2 * PAD_X, 3,
|
||||
C_DIM_R, C_DIM_G, C_DIM_B);
|
||||
n = wrap_lines(msg ? msg : "", lines);
|
||||
for(i = 0; i < n; i++)
|
||||
draw_text(CARD_X + PAD_X, BODY_Y + i * LINE_H, lines[i],
|
||||
C_INK_R, C_INK_G, C_INK_B);
|
||||
if(show_bar){
|
||||
int bx = CARD_X + PAD_X, bw = CARD_W - 2 * PAD_X, by = CARD_Y + CARD_H - 170;
|
||||
if(pct < 0) pct = 0;
|
||||
if(pct > 100) pct = 100;
|
||||
fill_rect(bx, by, bw, 26, C_BAR_BG_R, C_BAR_BG_G, C_BAR_BG_B);
|
||||
fill_rect(bx, by, (bw * pct) / 100, 26, C_BAR_FG_R, C_BAR_FG_G, C_BAR_FG_B);
|
||||
{
|
||||
char pb[16];
|
||||
snprintf(pb, sizeof pb, "%d%%", pct);
|
||||
draw_text(bx + bw / 2 - (int)text_w(pb) / 2, by + 2, pb,
|
||||
C_CARD_R, C_CARD_G, C_CARD_B);
|
||||
}
|
||||
}
|
||||
if(footer)
|
||||
draw_text(CARD_X + PAD_X, CARD_Y + CARD_H - 64, footer,
|
||||
C_DIM_R, C_DIM_G, C_DIM_B);
|
||||
present();
|
||||
}
|
||||
|
||||
/* --- pad: Cross-to-continue ------------------------------------------- */
|
||||
static void pad_open_all(void){
|
||||
int i;
|
||||
for(i = 0; i < 4; i++){
|
||||
if(g_pad[i] < 0){
|
||||
int h = scePadOpen(i + 1, 0, 0, NULL);
|
||||
if(h >= 0){ g_pad[i] = h; g_prevbtn[i] = 0; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 1 when Cross is newly pressed on any handle. */
|
||||
static int pad_cross_pressed(void){
|
||||
int i;
|
||||
OrbisPadData d;
|
||||
for(i = 0; i < 4; i++){
|
||||
uint32_t now;
|
||||
if(g_pad[i] < 0) continue;
|
||||
memset(&d, 0, sizeof d);
|
||||
if(scePadReadState(g_pad[i], &d) < 0) continue;
|
||||
now = d.buttons;
|
||||
if((now & ORBIS_PAD_BUTTON_CROSS) && !(g_prevbtn[i] & ORBIS_PAD_BUTTON_CROSS)){
|
||||
g_prevbtn[i] = now;
|
||||
return 1;
|
||||
}
|
||||
g_prevbtn[i] = now;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wait_cross(void){
|
||||
/* consume a held Cross first so the press that opened this
|
||||
* screen does not instantly dismiss it */
|
||||
int i;
|
||||
for(i = 0; i < 40; i++){
|
||||
pad_cross_pressed();
|
||||
sceKernelUsleep(20000);
|
||||
}
|
||||
for(;;){
|
||||
if(pad_cross_pressed()) break;
|
||||
sceKernelUsleep(20000);
|
||||
}
|
||||
for(i = 0; i < 25; i++){ /* let go before the next screen arms */
|
||||
OrbisPadData d;
|
||||
int j, held = 0;
|
||||
for(j = 0; j < 4; j++){
|
||||
if(g_pad[j] < 0) continue;
|
||||
memset(&d, 0, sizeof d);
|
||||
if(scePadReadState(g_pad[j], &d) == 0 && (d.buttons & ORBIS_PAD_BUTTON_CROSS))
|
||||
held = 1;
|
||||
}
|
||||
if(!held) break;
|
||||
sceKernelUsleep(20000);
|
||||
}
|
||||
}
|
||||
|
||||
/* --- public API -------------------------------------------------------- */
|
||||
static void reap_stale(void){
|
||||
if(sceImeDialogGetStatus() == ORBIS_DIALOG_STATUS_RUNNING)
|
||||
sceImeDialogTerm();
|
||||
}
|
||||
/* Reap any stale dialog from a previous session that died
|
||||
* mid-flow. Called by ui_init() to ensure a clean start. */
|
||||
static void reap_stale(void);
|
||||
|
||||
int ui_init(void){
|
||||
if(ui_ready) return 0;
|
||||
/* Reap any stale dialog from a previous session that died
|
||||
* mid-flow. This ensures a clean start. */
|
||||
reap_stale();
|
||||
{
|
||||
/* UserService first: dialogs + pad + IME all key off the user.
|
||||
* Best-effort (already-initialized is fine); uid fallbacks
|
||||
* downstream keep every path forward-safe. */
|
||||
OrbisUserServiceInitializeParams up;
|
||||
memset(&up, 0, sizeof up);
|
||||
up.priority = ORBIS_KERNEL_PRIO_FIFO_LOWEST;
|
||||
(void)sceUserServiceInitialize(&up);
|
||||
}
|
||||
/* Same proven order as before (apollo pattern): internal modules,
|
||||
* CommonDialog init BEFORE external loads, PAD, then IME modules.
|
||||
* MESSAGE_DIALOG is gone (we render our own cards). */
|
||||
/* Mirrors apollo-ps4 initInternal()/initPad():
|
||||
* 1. internal modules (SYSTEM, USER, COMMON_DIALOG)
|
||||
* 2. sceCommonDialogInitialize() <- BEFORE external modules
|
||||
* 3. PAD module + scePadInit()
|
||||
* 4. external modules (MESSAGE_DIALOG, IME_DIALOG, IME_BACKEND)
|
||||
* Order matters: dialog init must precede external module loads,
|
||||
* and COMMON_DIALOG must precede sceCommonDialogInitialize(). */
|
||||
if(sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_SYSTEM_SERVICE) != 0) return -1;
|
||||
if(sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_USER_SERVICE) != 0) return -1;
|
||||
if(sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_COMMON_DIALOG) != 0) return -1;
|
||||
if(sceCommonDialogInitialize() < 0) return -1;
|
||||
if(sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_PAD) != 0) return -1;
|
||||
(void)scePadInit();
|
||||
if(sceSysmoduleLoadModule(ORBIS_SYSMODULE_IME_DIALOG) < 0) return -1;
|
||||
if(sceSysmoduleLoadModule(ORBIS_SYSMODULE_MESSAGE_DIALOG) < 0) return -1;
|
||||
if(sceSysmoduleLoadModule(ORBIS_SYSMODULE_IME_DIALOG) < 0){
|
||||
sceSysmoduleUnloadModule(ORBIS_SYSMODULE_MESSAGE_DIALOG);
|
||||
return -1;
|
||||
}
|
||||
if(sceSysmoduleLoadModule(ORBIS_SYSMODULE_IME_BACKEND) < 0){
|
||||
sceSysmoduleUnloadModule(ORBIS_SYSMODULE_IME_DIALOG);
|
||||
sceSysmoduleUnloadModule(ORBIS_SYSMODULE_MESSAGE_DIALOG);
|
||||
return -1;
|
||||
}
|
||||
if(SDL_Init(SDL_INIT_VIDEO) < 0) return -1;
|
||||
g_win = SDL_CreateWindow("orbisRPC Setup", SDL_WINDOWPOS_CENTERED,
|
||||
SDL_WINDOWPOS_CENTERED, SCR_W, SCR_H, SDL_WINDOW_SHOWN);
|
||||
if(!g_win){ SDL_Quit(); return -1; }
|
||||
g_surf = SDL_GetWindowSurface(g_win);
|
||||
if(!g_surf || g_surf->format->BytesPerPixel != 4){ ui_shutdown(); return -1; }
|
||||
pad_open_all();
|
||||
ui_ready = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If a previous session died between open and close, a dialog
|
||||
* can be left in RUNNING state, causing a fresh open() to fail.
|
||||
* This function is called by ui_init() to reclaim any stale
|
||||
* dialog before starting fresh. Currently unused (no stale
|
||||
* dialogs observed after ui_init), kept for safety. */
|
||||
static void reap_stale(void){
|
||||
if(sceMsgDialogGetStatus() == ORBIS_COMMON_DIALOG_STATUS_RUNNING)
|
||||
sceMsgDialogTerminate();
|
||||
if(sceImeDialogGetStatus() == ORBIS_DIALOG_STATUS_RUNNING)
|
||||
sceImeDialogTerm();
|
||||
}
|
||||
|
||||
int ui_ok(const char *msg){
|
||||
if(!ui_ready) return -1;
|
||||
render_card("orbisRPC Setup", msg, 0, 0, "Press X to continue");
|
||||
wait_cross();
|
||||
OrbisMsgDialogParam param;
|
||||
OrbisMsgDialogUserMessageParam um;
|
||||
OrbisMsgDialogResult res;
|
||||
memset(&res, 0, sizeof res);
|
||||
sceMsgDialogTerminate();
|
||||
if(sceMsgDialogInitialize() < 0) return -1;
|
||||
base_init(¶m);
|
||||
memset(&um, 0, sizeof um);
|
||||
um.msg = msg;
|
||||
um.buttonType = ORBIS_MSG_DIALOG_BUTTON_TYPE_OK;
|
||||
param.userMsgParam = &um;
|
||||
if(sceMsgDialogOpen(¶m) < 0){ sceMsgDialogTerminate(); return -1; }
|
||||
/* Yield while waiting: a hot spin starves the dialog service on the
|
||||
* console (the proven pattern on this box sleeps 20 ms per tick). */
|
||||
while(sceMsgDialogUpdateStatus() != ORBIS_COMMON_DIALOG_STATUS_FINISHED)
|
||||
sceKernelUsleep(20000);
|
||||
sceMsgDialogClose();
|
||||
sceMsgDialogGetResult(&res);
|
||||
sceMsgDialogTerminate();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int progress_open = 0;
|
||||
static char progress_msg[256] = "";
|
||||
static int progress_pct = 0;
|
||||
|
||||
static void progress_repaint(void){
|
||||
render_card("orbisRPC Setup", progress_msg, progress_pct, 1, NULL);
|
||||
}
|
||||
|
||||
int ui_progress_open(const char *msg){
|
||||
if(!ui_ready) return -1;
|
||||
if(msg){ strncpy(progress_msg, msg, sizeof progress_msg - 1); progress_msg[sizeof progress_msg - 1] = 0; }
|
||||
else progress_msg[0] = 0;
|
||||
progress_pct = 0;
|
||||
OrbisMsgDialogParam param;
|
||||
OrbisMsgDialogProgressBarParam bar;
|
||||
if(progress_open){
|
||||
/* Self-healing: a prior session that died between open and close
|
||||
* leaves the flag set with no dialog behind it. Reclaim it. */
|
||||
ui_progress_close();
|
||||
}
|
||||
sceMsgDialogTerminate();
|
||||
if(sceMsgDialogInitialize() < 0) return -1;
|
||||
base_init(¶m);
|
||||
param.mode = ORBIS_MSG_DIALOG_MODE_PROGRESS_BAR;
|
||||
memset(&bar, 0, sizeof bar);
|
||||
bar.barType = ORBIS_MSG_DIALOG_PROGRESSBAR_TYPE_PERCENTAGE;
|
||||
bar.msg = msg;
|
||||
param.progBarParam = &bar;
|
||||
if(sceMsgDialogOpen(¶m) < 0){ sceMsgDialogTerminate(); return -1; }
|
||||
progress_open = 1;
|
||||
progress_repaint();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ui_progress_msg(const char *msg){
|
||||
if(!progress_open || !msg) return;
|
||||
strncpy(progress_msg, msg, sizeof progress_msg - 1);
|
||||
progress_msg[sizeof progress_msg - 1] = 0;
|
||||
progress_repaint();
|
||||
if(progress_open && msg) sceMsgDialogProgressBarSetMsg(0, msg);
|
||||
}
|
||||
|
||||
void ui_progress_set(unsigned pct){
|
||||
if(!progress_open) return;
|
||||
progress_pct = pct > 100 ? 100 : (int)pct;
|
||||
progress_repaint();
|
||||
if(progress_open) sceMsgDialogProgressBarSetValue(0, pct > 100 ? 100 : pct);
|
||||
}
|
||||
|
||||
void ui_progress_close(void){
|
||||
if(!progress_open) return;
|
||||
progress_open = 0;
|
||||
fill_rect(0, 0, SCR_W, SCR_H, C_BG_R, C_BG_G, C_BG_B);
|
||||
present();
|
||||
sceMsgDialogClose();
|
||||
sceMsgDialogTerminate();
|
||||
}
|
||||
|
||||
int ui_input(const char *title, const char *placeholder, char *out, size_t cap){
|
||||
@@ -347,7 +158,7 @@ int ui_input(const char *title, const char *placeholder, char *out, size_t cap){
|
||||
OrbisImeDialogSetting st;
|
||||
int32_t uid = 0;
|
||||
size_t i;
|
||||
if(!ui_ready || !out || cap == 0 || cap > 200) return -1;
|
||||
if(!out || cap == 0 || cap > 200) return -1;
|
||||
/* Prefill with current value (ASCII round-trip). */
|
||||
for(i = 0; i < cap - 1 && out[i]; i++) wbuf[i] = (wchar_t)(unsigned char)out[i];
|
||||
wbuf[i] = 0;
|
||||
@@ -366,18 +177,23 @@ int ui_input(const char *title, const char *placeholder, char *out, size_t cap){
|
||||
st.option = 0;
|
||||
st.maxTextLength = (uint32_t)(cap - 1);
|
||||
st.inputTextBuffer = wbuf;
|
||||
/* Center of 1920x1080. At (0,0) the panel anchors up-left and the
|
||||
* keyboard renders half off-screen; 960,540 is the layout that is
|
||||
* known-good on this console (rutracker-ps4 uses the same values). */
|
||||
st.posx = 960;
|
||||
st.posy = 540;
|
||||
st.horizontalAlignment = ORBIS_H_CENTER;
|
||||
st.verticalAlignment = ORBIS_V_CENTER;
|
||||
st.placeholder = wplace;
|
||||
st.title = wtitle;
|
||||
/* apollo-ps4 pattern: guard against re-entry, terminate stale
|
||||
* state, then init. The dialog owns the running flag. */
|
||||
if(ime_dialog_running){ sceImeDialogTerm(); ime_dialog_running = 0; }
|
||||
ime_dbg("ime_begin\n");
|
||||
if(sceImeDialogInit(&st, NULL) < 0){ ime_dbg("ime_init_fail\n"); return -1; }
|
||||
ime_dialog_running = 1;
|
||||
{
|
||||
int spins = 0, rc = 0;
|
||||
int spins = 0;
|
||||
OrbisDialogStatus ds;
|
||||
ds = sceImeDialogGetStatus();
|
||||
if(ds == ORBIS_DIALOG_STATUS_RUNNING) ime_dbg("ime_status_running\n");
|
||||
@@ -391,45 +207,38 @@ int ui_input(const char *title, const char *placeholder, char *out, size_t cap){
|
||||
sceImeDialogGetResult(&res);
|
||||
sceImeDialogTerm();
|
||||
ime_dialog_running = 0;
|
||||
if(res.endstatus != ORBIS_DIALOG_OK){ rc = 0; break; }
|
||||
for(i = 0; i < cap - 1 && wbuf[i]; i++)
|
||||
out[i] = (wbuf[i] < 128 && wbuf[i] >= 32) ? (char)wbuf[i] : '?';
|
||||
out[i] = 0;
|
||||
rc = 1;
|
||||
if(res.endstatus != ORBIS_DIALOG_OK) return 0;
|
||||
break;
|
||||
}
|
||||
if(ds == ORBIS_DIALOG_STATUS_NONE && ++spins > 250){
|
||||
ime_dbg("ime_timeout\n");
|
||||
sceImeDialogTerm();
|
||||
ime_dialog_running = 0;
|
||||
rc = -1;
|
||||
break;
|
||||
return -1;
|
||||
}
|
||||
if(ds != ORBIS_DIALOG_STATUS_NONE) spins = 0;
|
||||
sceKernelUsleep(20000);
|
||||
}
|
||||
/* IME is a system overlay; repaint our card underneath on return. */
|
||||
if(progress_open) progress_repaint();
|
||||
else { fill_rect(0, 0, SCR_W, SCR_H, C_BG_R, C_BG_G, C_BG_B); present(); }
|
||||
return rc;
|
||||
}
|
||||
for(i = 0; i < cap - 1 && wbuf[i]; i++)
|
||||
out[i] = (wbuf[i] < 128 && wbuf[i] >= 32) ? (char)wbuf[i] : '?';
|
||||
out[i] = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Teardown for exit: terminate any live dialog, then unload the
|
||||
* modules loaded in ui_init. Called before _exit so no dialog
|
||||
* outlives the app. Must unload PAD too since it was loaded
|
||||
* internally (ORBIS_SYSMODULE_INTERNAL_PAD). */
|
||||
void ui_shutdown(void){
|
||||
int i;
|
||||
if(!ui_ready){
|
||||
/* Still unload in case init died halfway. */
|
||||
}
|
||||
if(!ui_ready) return;
|
||||
ui_ready = 0;
|
||||
progress_open = 0;
|
||||
ime_dialog_running = 0;
|
||||
for(i = 0; i < 4; i++){
|
||||
if(g_pad[i] >= 0){ scePadClose(g_pad[i]); g_pad[i] = -1; }
|
||||
}
|
||||
if(g_win){ SDL_DestroyWindow(g_win); g_win = NULL; g_surf = NULL; }
|
||||
SDL_Quit();
|
||||
sceMsgDialogTerminate();
|
||||
sceImeDialogTerm();
|
||||
sceSysmoduleUnloadModule(ORBIS_SYSMODULE_IME_BACKEND);
|
||||
sceSysmoduleUnloadModule(ORBIS_SYSMODULE_IME_DIALOG);
|
||||
sceSysmoduleUnloadModule(ORBIS_SYSMODULE_MESSAGE_DIALOG);
|
||||
sceSysmoduleUnloadModule(ORBIS_SYSMODULE_INTERNAL_PAD);
|
||||
}
|
||||
+3
-1
@@ -63,6 +63,8 @@ if [ "$MODE" = "fself" ] || [ "$MODE" = "all" ]; then
|
||||
"$SDK/bin/macos/create-fself-macos" -in="$OUT/orbisrpc.elf" \
|
||||
-out="$OUT/orbisrpc.fself" --eboot "$OUT/orbisrpc-eboot.bin" --paid 0x3800000000000011 --authinfo 000000000000000000000000001C004000FF000000000080000000000000000000000000000000000000008000400040000000000000008000000000000000080040FFFF000000F000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 || fail "fself creation"
|
||||
echo "FSELF -> $OUT/orbisrpc.fself"
|
||||
echo " (GoldHEN payload to deploy is $OUT/orbisrpc.elf -> /data/GoldHEN/payloads/orbisrpc.bin)"
|
||||
echo " (deploy $OUT/orbisrpc.elf -> /data/payloads/orbisrpc.bin for Payload Guest)"
|
||||
echo " note: GoldHEN's OWN payload slot is /data/payload.bin (a different, single-purpose slot)"; \
|
||||
echo " run orbisRPC from Payload Guest, not as a GoldHEN payload.bin"
|
||||
fi
|
||||
echo "done."
|
||||
@@ -1,87 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Rasterize an embedded bitmap font for the installer UI (no TTF on PS4).
|
||||
|
||||
Reads a system font with PIL, renders printable ASCII at a fixed pixel
|
||||
size, and emits installer/font.h: 8-bit alpha glyphs, fixed height,
|
||||
variable advance. Rerun: python3 scripts/genfont.py
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
SIZE = 30
|
||||
FIRST, LAST = 32, 126
|
||||
CANDIDATES = [
|
||||
"/System/Library/Fonts/Helvetica.ttc",
|
||||
"/System/Library/Fonts/Supplemental/Arial.ttf",
|
||||
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
|
||||
]
|
||||
|
||||
try:
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
except ImportError:
|
||||
sys.exit("PIL required: pip install pillow")
|
||||
|
||||
|
||||
def pick_font():
|
||||
for p in CANDIDATES:
|
||||
if os.path.exists(p):
|
||||
return p
|
||||
sys.exit("no usable system font found")
|
||||
|
||||
|
||||
def main():
|
||||
path = pick_font()
|
||||
out = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
|
||||
"installer", "font.h")
|
||||
glyphs = []
|
||||
max_h = 0
|
||||
for code in range(FIRST, LAST + 1):
|
||||
fnt = ImageFont.truetype(path, SIZE, index=0)
|
||||
ch = chr(code)
|
||||
tmp = Image.new("L", (SIZE * 3, SIZE * 3), 0)
|
||||
d = ImageDraw.Draw(tmp)
|
||||
d.text((SIZE, SIZE), ch, font=fnt, fill=255, anchor="lm")
|
||||
bb = tmp.getbbox()
|
||||
if bb is None: # space and friends: blank, advance from font
|
||||
adv_w = max(1, int(fnt.getlength(ch)))
|
||||
glyphs.append((adv_w, []))
|
||||
continue
|
||||
l, t, r, b = bb
|
||||
w = max(1, r - l)
|
||||
h = max(1, b - t)
|
||||
max_h = max(max_h, h)
|
||||
crop = [list(tmp.crop((l, yy, r, yy + 1)).getdata())
|
||||
for yy in range(t, b)]
|
||||
glyphs.append((w, crop))
|
||||
|
||||
H = max_h
|
||||
blob = bytearray()
|
||||
adv, off = [], []
|
||||
for w, crop in glyphs:
|
||||
off.append(len(blob))
|
||||
adv.append(w)
|
||||
# pad crop rows to (H x w), top-aligned
|
||||
for y in range(H):
|
||||
src = crop[y] if y < len(crop) else [0] * w
|
||||
src = (list(src) + [0] * w)[:w]
|
||||
blob.extend(src)
|
||||
|
||||
with open(out, "w") as f:
|
||||
f.write("/* font.h - GENERATED by scripts/genfont.py. Do not edit. */\n")
|
||||
f.write("#ifndef INSTALLER_FONT_H\n#define INSTALLER_FONT_H\n")
|
||||
f.write("#include <stdint.h>\n")
|
||||
f.write("#define FONT_H %d\n#define FONT_FIRST %d\n#define FONT_COUNT %d\n"
|
||||
% (H, FIRST, LAST - FIRST + 1))
|
||||
f.write("static const uint8_t font_adv[FONT_COUNT] = {%s};\n"
|
||||
% ",".join(str(a) for a in adv))
|
||||
f.write("static const unsigned font_off[FONT_COUNT] = {%s};\n"
|
||||
% ",".join(str(o) for o in off))
|
||||
f.write("static const uint8_t font_px[%d] = {" % len(blob))
|
||||
for i in range(0, len(blob), 16):
|
||||
f.write("\n")
|
||||
f.write(",".join(str(v) for v in blob[i:i + 16]) + ",")
|
||||
f.write("\n};\n#endif\n")
|
||||
print("wrote %s (%d glyphs, H=%d, %d bytes)" % (out, len(glyphs), H, len(blob)))
|
||||
|
||||
|
||||
main()
|
||||
Executable
+72
@@ -0,0 +1,72 @@
|
||||
#!/bin/sh
|
||||
# ps4-check.sh - one command to answer "what is the console actually running?".
|
||||
# Pulls the evidence files over FTP, lists staged PKGs, and diffs local
|
||||
# artifacts against what the console has, so support questions resolve
|
||||
# without a multi-command FTP dance.
|
||||
#
|
||||
# Usage: ./scripts/ps4-check.sh [tail_lines] (default 25)
|
||||
# Env: PS4_HOST (default 192.168.1.136) PS4_PORT (2121)
|
||||
set -eu
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
HOST="${PS4_HOST:-192.168.1.136}"
|
||||
PORT="${PS4_PORT:-2121}"
|
||||
TAIL="${1:-25}"
|
||||
BASE="ftp://$HOST:$PORT"
|
||||
FTP="curl -sS --connect-timeout 5 --max-time 20"
|
||||
|
||||
echo "=== console $HOST:$PORT ==="
|
||||
# Probe with a file we know exists; fall back to a directory listing, since
|
||||
# some FTP builds refuse listings but serve files fine.
|
||||
if $FTP "$BASE/user/data/orbisRPC/install.log" >/dev/null 2>&1 \
|
||||
|| $FTP "$BASE/user/data/orbisRPC/log.txt" >/dev/null 2>&1 \
|
||||
|| $FTP "$BASE/user/data/pkg/" >/dev/null 2>&1; then
|
||||
:
|
||||
else
|
||||
echo "UNREACHABLE (jailbreak must be active + console awake)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- evidence: newest run of the installer -------------------------
|
||||
echo
|
||||
echo "--- install.log (last $TAIL) ---"
|
||||
if $FTP "$BASE/user/data/orbisRPC/install.log" 2>/dev/null | tail -n "$TAIL"; then :; else
|
||||
echo "(missing)"
|
||||
fi
|
||||
|
||||
# --- evidence: daemon log ------------------------------------------
|
||||
echo
|
||||
echo "--- log.txt (last $TAIL) ---"
|
||||
$FTP "$BASE/user/data/orbisRPC/log.txt" 2>/dev/null | tail -n "$TAIL" || echo "(missing)"
|
||||
|
||||
# --- liveness / diagnostics (remaster v1.1.0+) ---------------------
|
||||
for f in status.json diag.json daemon.gen; do
|
||||
echo
|
||||
echo "--- $f ---"
|
||||
$FTP "$BASE/user/data/orbisRPC/$f" 2>/dev/null || echo "(missing = pre-remaster build)"
|
||||
done
|
||||
|
||||
# --- staged PKGs: which one is the current test build? -------------
|
||||
echo
|
||||
echo "--- /user/data/pkg/ ---"
|
||||
$FTP "$BASE/user/data/pkg/" 2>/dev/null | sed -n '1,40p' || echo "(missing)"
|
||||
|
||||
# --- local vs remote payload: is the console running OUR build? ---
|
||||
echo
|
||||
echo "--- payload: local vs console ---"
|
||||
LOCAL=""
|
||||
for c in build/orbisrpc.elf build-sdk/orbisrpc_sdk.elf; do
|
||||
[ -f "$c" ] && { LOCAL="$c"; break; }
|
||||
done
|
||||
if [ -z "$LOCAL" ]; then
|
||||
echo "no local build yet (run ./scripts/build.sh elf)"
|
||||
else
|
||||
lsz=$(wc -c <"$LOCAL" | tr -d ' ')
|
||||
rsz=$($FTP "$BASE/user/data/payloads/orbisrpc.bin" 2>/dev/null | wc -c | tr -d ' ')
|
||||
echo "local $LOCAL $lsz"
|
||||
echo "remote /data/payloads/orbisrpc.bin $rsz"
|
||||
[ "$lsz" = "$rsz" ] && echo "MATCH (console runs the current payload)" \
|
||||
|| echo "DIFFERS (payload staged but not launched, or console is older)"
|
||||
fi
|
||||
echo
|
||||
echo "done."
|
||||
Reference in new issue
Block a user