Files
Vivian 742a1fe3ac PS5: check param.json against console-tested profiles; listening diagnostics
0.3.0's param.json (Jelly5's Media profile) starts and gets 120 Hz, but the
console refuses to let the app listen: Settings > From your phone fails with
"listen: permission denied".

- ps5/app/param-profiles.json: what each profile did on the console (area,
  start, listening, 120 Hz); scripts/check-param.py warns in build-ps5.sh and
  refuses in release-ps5.sh a profile never seen to start and to listen.
- The start-up probe logs bind and listen apart (port 8085 and a port the
  system picks) and the installed param.json's profile; the phone page's
  error says which call failed.
- 120 Hz endurance test: a file named stress in the title's folder forces
  120 Hz and runs the tour in a loop, the heap logged every 10 s, GET
  requests only.
- RELEASING.md: the phone page, the tile's area and the refresh rate are
  checked at every release.
2026-10-14 13:26:00 +02:00

60 lines
2.6 KiB
Python
Executable File

#!/usr/bin/env python3
# Regie5 — checks a title's param.json against the profiles tried on a console.
# SPDX-License-Identifier: GPL-3.0-or-later
"""
scripts/check-param.py <param.json> [--release]
The fields that decide where the tile goes, whether the title starts, 120 Hz
and whether the app may listen (Settings > From your phone) are compared with
ps5/app/param-profiles.json. 0.3.0 shipped a profile that starts but cannot
listen; this check is there so that it does not happen again.
Without --release (test builds): a warning, the build goes on.
With --release: refused (exit 1) unless the profile is known to start and to
listen. A new profile is added to param-profiles.json after a console test.
"""
import json
import os
import sys
FIELDS = ("applicationCategoryType", "contentBadgeType", "attribute", "attribute2", "attribute3",
"amm", "kernel", "gameIntent")
def profile_of(param):
return {k: param.get(k) for k in FIELDS}
def main(argv):
if len(argv) not in (2, 3) or (len(argv) == 3 and argv[2] != "--release"):
sys.exit(__doc__.strip())
release = len(argv) == 3
root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
with open(argv[1], encoding="utf-8") as f:
mine = profile_of(json.load(f))
with open(os.path.join(root, "ps5", "app", "param-profiles.json"), encoding="utf-8") as f:
known = json.load(f)["profiles"]
match = next((p for p in known if p["fields"] == mine), None)
what = "release refused" if release else "warning"
if match is None:
print(f"param.json: {what}: this profile was never tried on a console "
f"(category {mine['applicationCategoryType']}, attribute {mine['attribute']:#x}, "
f"attribute3 {mine['attribute3']:#x}); check the tile, the start and the phone page, "
"then add it to ps5/app/param-profiles.json", file=sys.stderr)
return 1 if release else 0
c = match["console"]
hz = "120 Hz" if c.get("hz120") else "60 Hz only"
if not c.get("starts"):
print(f"param.json: {what}: profile '{match['name']}' does not start ({c.get('note', '')})", file=sys.stderr)
return 1 if release else 0
if not c.get("listens"):
print(f"param.json: {what}: profile '{match['name']}' starts but CANNOT LISTEN: "
f"Settings > From your phone fails ({c.get('note', '')})", file=sys.stderr)
return 1 if release else 0
print(f"param.json: profile '{match['name']}' ({c['area']}, starts, listens, {hz}; {c['seen']})")
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))