Skip to content

v3.1.0: fix all open issues (#2–#7), bedtime alarm, PIN gate - #8

Merged
tailiang2008 merged 5 commits into
tailiang2008:mainfrom
puppywang:fix/issues-v3.1
Oct 14, 2026
Merged

tailiang2008 merged 5 commits into
tailiang2008:mainfrom
puppywang:fix/issues-v3.1

Conversation

@puppywang

Copy link
Copy Markdown
Contributor

Fixes #2, fixes #3, fixes #4, fixes #5, fixes #6, fixes #7.

The root causes come from reversing the fw 22.5.0 pctl sysmodule. Offsets and evidence are in docs/pctl-reverse-engineering.md. Tested on fw 22.5.0 / Atmosphère 1.12.0 (emuMMC).

Root causes and fixes

Issue Cause Fix
#3 #6 #7: limit set but nothing happens The write gate calls 1201 UnlockRestrictionTemporarily but never re-locks, so parental controls stay temporarily unlocked. This is the HOME-banner workaround described in #3. After every write, call 1007 RevertRestrictionTemporaryUnlocked and check it with 1006. The "Turn off & write" dialog is removed.
#2: no countdown 195101 stores the settings with enabled cleared. pctl re-derives enabled only if it can read the time from the NetworkSystemClock, and a console that can't reach Nintendo never sets that clock. This matches the QuickNTP finding in #2. Detect an invalid network clock at launch and offer to seed it from the user clock. The same action is in the main menu. The app opens a time:s session for this, like QuickNTP.
#5: 0x1088E This is pctl's "no PIN registered" result from the 1201 PIN check. Also, 195101 is silently ignored when no PIN is registered but still returns success. Require a PIN before any play-timer write. 1201 is never sent without one. v3.0.0 sent 32 zero bytes.
#4: bedtime alarm The 8-byte day setting is bedtimeEnabled, alarm h/m, reset h/m, limitTimeEnabled, u16 limitTime. The header bytes are enabled, restrictionMode (ALARM / FORCED_TERMINATION) and timerMode (DAILY / EACH_DAY_OF_THE_WEEK). The new editor verifies each write through getters 1954–1959.

Other changes

  • PtSettings struct replaces the u16[34] view. For the same input, writes are byte-identical to v3.0.0, except that unrestricted days keep the 06:00 reset default.
  • "When time is up: suspend software / notify only" option (restrictionMode).
  • Play-timer reads and writes are refused below fw 21.0.0, because 145601 / 195101 had a different size before.
  • "Remove limit" now goes through the same guarded write.
  • The per-day editor can set a day back to "no limit".
  • Fixed a start-up crash: borealis treats the multiline Label attribute as fatal. init_error.xml already had this latent bug. main() now catches exceptions and shuts borealis down through one more mainLoop(). Before, abort() returned to hbloader with the task thread still alive, which caused 2168-0001.
  • Logs go to sd:/switch/nx_pctl_manager.log (writes) and sd:/switch/nx_pctl_borealis.log. The diagnostic dump is always available. The PROBE build option is removed.
  • zh-Hans translation.

Behaviour change to review

The app now asks for the console's PIN at launch when one is registered. Without this check, a child can open the tool and remove the limit, because the tool reads the PIN itself. The downside is that the tool can no longer recover a forgotten PIN, so the README now points to Nintendo's master-key reset. If you'd prefer to keep the recovery path, I can make the gate optional (for example, a flag file on the SD card).


中文简述:修复了 #2–#7。

  • 写入后用 1007 恢复家长控制。
  • 网络时钟无效时提示并一键设置。
  • 写入前要求先设置 PIN。0x1088E 就是“未设置 PIN”,而且没有 PIN 时 195101 会被静默丢弃。
  • 新增就寝闹钟、到时间后的处理方式、启动时 PIN 验证和中文界面。
  • 逆向依据见 docs/pctl-reverse-engineering.md。
  • 启动时的 PIN 验证会让本工具无法再恢复忘记的 PIN。如果你希望保留这个恢复方式,我可以把 PIN 验证改成可选。

🤖 Generated with Claude Code

puppywang and others added 4 commits October 14, 2026 15:30
- Re-enable parental controls after a write via cmd 1007
  RevertRestrictionTemporaryUnlocked; v3.0.0 left them temporarily
  unlocked, so limits never applied (tailiang2008#3, tailiang2008#6, tailiang2008#7)
- Detect an unset network clock and offer to seed it from the system
  clock; the play timer doesn't count down without it (tailiang2008#2)
- Skip cmd 1201 when no PIN is registered and require a PIN before any
  play-timer write; log every write to sd:/switch/nx_pctl_manager.log (tailiang2008#5)
- Model PlayTimerSettings as 4-byte header + 8 x 8-byte day settings and
  add a bedtime alarm editor, verified against getters 1954-1959 (tailiang2008#4)
- Refuse play-timer reads/writes below fw 21.0.0 (0x44-byte struct)
- Route "remove limit" through the same guarded write
- Per-day editor can set a day back to "no limit"
- Launch-time PIN gate; diagnostic report always available
- zh-Hans translation

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
….5.0

- Name header bytes: restrictionMode (0 ALARM / 1 FORCED_TERMINATION)
  and timerMode (0 DAILY / 1 EACH_DAY_OF_THE_WEEK); read the daily slot
  when timerMode is DAILY
- Add "When time is up: suspend software / notify only" option; drop the
  PROBE header-flip experiments
- Document why writes need a PIN (pctl silently drops them otherwise)
  and a valid network clock (pctl clears `enabled` without one)
- docs/pctl-reverse-engineering.md with offsets and evidence

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Drop the unsupported `multiline` Label attribute (pin_gate.xml, and the
  same latent bug in init_error.xml); borealis treats unknown XML
  attributes as fatal
- Write borealis logs to sd:/switch/nx_pctl_borealis.log (unbuffered)
- Catch exceptions from run(): log them and shut borealis down through a
  final mainLoop() iteration, so its task thread is stopped and the GPU
  context released; previously abort() returned to hbloader with the
  thread alive and the console crashed (2168-0001), then hbmenu (2168-0002)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Also drop the README's mention of forgot-PIN recovery, which the launch
PIN check no longer allows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JigSawFr

Copy link
Copy Markdown

Hi @puppywang Great work on v3.1.0 — the pctl reverse-engineering notes are excellent, especially the PlayTimerSettings header (restrictionMode / timerMode / daily rule), the silent no-PIN drop in 195101 and the NetworkSystemClock root cause of #2.

I maintain PlayGuard, a fork of Pctl Manager that already covers most of these fixes (re-locking with 1007 after a write, setting the network clock on offline consoles, PIN checks, bedtime alarm, diagnostics…). Your findings just helped me fix DAILY-mode consoles, credited here: JigSawFr#133

I'd be really happy to get your feedback, issues or contributions, and to share what we learn on our side too. Joining our efforts would be great!


你好!v3.1.0 做得非常好——pctl 的逆向分析笔记很出色,尤其是 PlayTimerSettings 头部(restrictionMode / timerMode / 每日规则)、195101 在未设置 PIN 时静默丢弃写入,以及 #2 的根本原因(NetworkSystemClock)。

我维护着 PlayGuard,它是 Pctl Manager 的一个分支,已经包含了其中大部分修复(写入后用 1007 重新锁定、为离线主机设置网络时钟、PIN 校验、就寝闹钟、诊断报告等)。你的发现刚刚帮我修复了"每天相同"(DAILY)模式的问题,并在这里注明了出处:JigSawFr#133

非常欢迎你的反馈、issue 或贡献,我们这边的发现也很乐意分享给你。如果能一起合作就太好了!

@tailiang2008
tailiang2008 merged commit 06b14cd into tailiang2008:main Oct 14, 2026
1 check passed
@tailiang2008

Copy link
Copy Markdown
Owner

@puppywang thanks for your contribution

tailiang2008 added a commit that referenced this pull request Oct 14, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tailiang2008 added a commit that referenced this pull request Oct 19, 2026
- Play-timer setters patch the stored settings instead of rebuilding them
  from Sunday's slot, so per-day bedtimes from the companion app survive
  a limit, mode or remove write. Settings this app wrote itself produce
  the same bytes as before. The query reports bedtime_varies, shown as
  "(varies by day)".
- guarded_write also switches parental controls back on (cmd 1007) when
  they were already paused before the write; otherwise the new settings
  never applied.
- pctl_is_temporarily_unlocked returns a Result; a failed 1006 query now
  counts as still paused and shows the relock_failed dialog.
- prompt_hhmm reopens the keypad with an error header on an invalid time
  instead of returning as if cancelled.
- "Set network clock" asks before overwriting a clock that is already
  set; the seed + refresh + toast code is shared.
- borealis log level DEBUG -> INFO (no SD write on every focus change).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants