Ladelimit: Key gemessen, Schreibpfad gebaut

Der Key heißt CHLT, drei Bytes. Identifiziert per Differenzmessung gegen
macOS' eigene Ladebegrenzung, ohne einen einzigen Schreibzugriff:

  80 %  →  50 01 00
  95 %  →  5F 01 00
  85 %  →  55 01 00

Erstes Byte ist die Prozentzahl, zweites offenbar „Limit aktiv", drittes
unbenutzt. Drei Messpunkte, weil einer Zufall sein kann: BACC hatte beim
ersten Vergleich ebenfalls gepasst — ein Zähler, in dem gerade 50 stand.

ChargerConfiguration aus ioreg sah zunächst wie eine zweite Quelle aus
(niedriges Byte 0x50 = 80), blieb aber unverändert, als CHLT längst auf
95 stand. Also Zufall, und gut, dass darauf nichts gebaut wurde.

Geschrieben wird nur das erste Byte, und nur zwischen 80 und 100 — dem
Bereich, den macOS selbst anbietet und in dem gemessen wurde. Darunter ist
ungemessenes Gebiet. Bei den Lüftern liefert die Firmware mit F0Mn/F0Mx
eigene Grenzen mit, an denen sich ein Sicherheitsnetz festhalten kann; hier
gibt es das nicht, hier gibt es nur die Messung. Ein falscher Wert im
Lade-Subsystem ist die eine Operation in diesem Projekt, die den Akku
dauerhaft beschädigen kann.

Nach jedem Schreiben wird zurückgelesen und gemeldet, was tatsächlich
steht — nicht, was gewünscht war. „Kein Limit" heißt 100 Prozent und nicht
das Aktiv-Byte auf null: diese Kodierung hat macOS nie geschrieben, sie
wäre also ungemessen.

Bedienung im Lüfter-Bereich der Einstellungen und in der Lüfterkachel,
also auch im Menüleisten-Popover.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-08-11 12:01:50 +02:00
parent c9366302fc
commit b2f69f34ae
11 changed files with 1577 additions and 1175 deletions

View File

@@ -104,6 +104,12 @@ final class SMCAccess {
write(key, bytes: [value])
}
/// Schreibt beliebige Bytes für `CHLT`, das drei davon hat.
@discardableResult
func writeBytes(_ key: String, _ bytes: [UInt8]) -> Bool {
write(key, bytes: bytes)
}
private func write(_ key: String, bytes: [UInt8]) -> Bool {
guard let info = keyInfo(for: key) else { return false }
// Nur schreiben, wenn die Größe zur Firmware passt. Ein zu kurzer oder
@@ -134,6 +140,12 @@ final class SMCAccess {
return output.keyInfo
}
/// Liest die Rohbytes eines Keys für `CHLT`, dessen Typ `hex_` ist und
/// das sich damit keiner der Zahlenfassungen zuordnen lässt.
func readBytes(_ key: String) -> [UInt8]? {
read(key)?.bytes
}
private func read(_ key: String) -> Value? {
guard let info = keyInfo(for: key) else { return nil }
var command = Param()