Vier Annahmen des Plans vor jedem Implementierungscode geprüft:
A (SMC): Lüftersteuerung bestätigt — F0md/F1md (klein!) als Auto/Manuell-
Umschalter, F0Tg als Ziel, Grenzen aus F0Mn/F0Mx. SMC-Integer sind
little-endian, nicht big-endian wie im verbreiteten Intel-Beispielcode.
Ladelimit: CHWA/CH0B/CH0C/bfE0/bfF0 existieren auf Mac17,9 nicht.
Key noch nicht identifiziert, deshalb smc-diff.sh für eine
Differenzmessung ohne jeden Schreibzugriff.
B (Media): mediaremote-adapter läuft unter 26.6.1, aus dem Quellcode gebaut.
Liefert vollständige Metadaten inkl. Cover aus Google Chrome — der
Fall, den AppleScript nicht erreicht.
C (Audio): Process Tap + privates Aggregate-Device liefern echte Samples
(469 Callbacks/5 s, 0 stille Puffer). Konflikt gefunden: SoundSource
6.1.1 mit ARK.driver ist bereits installiert.
D (Group): App-Group-Container ist aus einem nicht-sandboxed Prozess erreichbar.
Damit trägt die Sandbox-Entscheidung, die Bridge-App entfällt.
Spikes sind Wegwerfcode zur Verifikation, kein Produktionscode.
91 lines
4.0 KiB
Markdown
91 lines
4.0 KiB
Markdown
# Spike A — SMC-Keys auf Mac17,9 (M5 Pro)
|
||
|
||
Gemessen am 10.08.2026, macOS 26.6.1 (25G76), **ohne root**, ausschließlich lesend.
|
||
Werkzeug: `Spikes/smc-dump.swift`. 3486 Keys insgesamt.
|
||
|
||
## Ergebnis in einem Satz
|
||
|
||
**Lüftersteuerung: bestätigt und umsetzbar.** **Ladelimit: Key noch nicht identifiziert** —
|
||
das Standardverfahren aus AlDente/batt greift auf dieser Maschine nicht, weil die dort benutzten
|
||
Keys schlicht nicht existieren.
|
||
|
||
## Wichtige Querbefunde
|
||
|
||
**SMC-Integer sind little-endian.** Meine erste BE-Dekodierung ergab Unsinn (Akkuspannung
|
||
31023 mV). LE ergibt konsistente Werte, zweifach gegengeprüft:
|
||
|
||
| Key | Roh | LE-Wert | Gegenprobe |
|
||
|---|---|---|---|
|
||
| `B0AV` | `AA 2F` | 12202 mV | plausible Zellspannung |
|
||
| `CH0V` | `AA 2F 00 00` | 12202 mV | identisch zu `B0AV` |
|
||
| `B0AC` | `85 FD` | −635 mA | entlädt; passt zu `PMVR` = 0 W (kein Netzteil) |
|
||
| `PPBR` | — | 12,13 W | ≈ 12,2 V × 0,64 A ✓ |
|
||
|
||
`flt`-Keys sind ebenfalls little-endian IEEE-754. Für die Implementierung heißt das:
|
||
**alle Mehrbyte-SMC-Werte little-endian lesen**, entgegen dem verbreiteten Beispielcode, der
|
||
big-endian annimmt (der stammt aus der Intel-Ära).
|
||
|
||
## Lüfter — vollständig nutzbar
|
||
|
||
Zwei Lüfter vorhanden (`FNum` = 2).
|
||
|
||
| Key | Typ | Wert | Bedeutung |
|
||
|---|---|---|---|
|
||
| `F0md` / `F1md` | ui8 | 0 | **Modus: 0 = auto, 1 = manuell** |
|
||
| `F0Tg` / `F1Tg` | flt | 2317 / 2502 | Ziel-Drehzahl |
|
||
| `F0Ac` / `F1Ac` | flt | 2321 / 2499 | Ist-Drehzahl |
|
||
| `F0Mn` / `F1Mn` | flt | 2317 | Minimum |
|
||
| `F0Mx` / `F1Mx` | flt | 7826 | Maximum |
|
||
| `F0St` / `F1St` | ui8 | 5 | Status |
|
||
| `FEna` | hex | 07 | Freigabe-Bitmaske |
|
||
|
||
**Korrektur zur Planannahme:** der Modus-Key heißt `F0md` **klein geschrieben**, nicht `F0Md`.
|
||
Mit der Großschreibung aus der Intel-Dokumentation findet man ihn nicht — genau deshalb lief
|
||
dieser Spike vor dem Implementierungscode.
|
||
|
||
`FS! ` (die alte Force-Bitmaske) existiert **nicht**. Der Weg ist also:
|
||
`F0md = 1` → `F0Tg = Wunschdrehzahl`, zurück auf Automatik mit `F0md = 0`.
|
||
|
||
Der Sicherheitsrahmen aus dem Plan lässt sich damit sauber umsetzen: `F0Mn`/`F0Mx` liefern
|
||
die harten Grenzen direkt aus der Firmware, und `F0md = 0` ist ein einzelner, immer
|
||
verfügbarer Rückfallbefehl.
|
||
|
||
## Ladelimit — noch offen
|
||
|
||
**Nicht vorhanden:** `CHWA`, `CH0B`, `CH0C`, `CH0I`, `CH0J`, `CH0K`, `BCLM`, `bfE0`, `bfF0`.
|
||
|
||
Damit scheiden sowohl das AlDente-Legacy-Verfahren (`CH0B`/`CH0C`) als auch das
|
||
80-%-Flag (`CHWA`) als auch das vollständige Firmware-Backend (`bfD0`/`bfE0`/`bfF0`) aus —
|
||
von letzterem existiert nur `bfD0` (hex, 2 Byte, `00 00`).
|
||
|
||
Vorhanden ist stattdessen ein umfangreicher `CH*`-Satz. Plausible Kandidaten:
|
||
|
||
| Key | Typ | Wert (LE) | Vermutung |
|
||
|---|---|---|---|
|
||
| `CHTE` | ui32 | 0 | Ladeziel — 0 könnte „kein Limit" heißen |
|
||
| `CHTL` | ui32 | 3600 | untere Schwelle? |
|
||
| `CHTU` | ui32 | 4100 | obere Schwelle? (mV je Zelle) |
|
||
| `CHBV` | ui32 | 4125 | Ladeschlussspannung mV |
|
||
| `CHIL` / `CHIO` | flag | false | Inhibit-Flags |
|
||
| `CHSE` / `CHST` / `CHRT` | ui8 | 0 | Status/Steuerung |
|
||
|
||
**Das bleibt Vermutung, und Vermutungen werden hier nicht geschrieben.** Ein falscher Wert im
|
||
Lade-Subsystem ist die eine Operation in diesem Projekt, die Hardware dauerhaft beschädigen kann.
|
||
|
||
### Nächster Schritt: Differenzmessung statt Raten
|
||
|
||
macOS hat selbst eine Ladebegrenzung (Systemeinstellungen → Batterie → Batteriezustand →
|
||
„Optimiertes Laden" bzw. das 80-%-Limit). Wird sie umgeschaltet, muss sich der zuständige
|
||
SMC-Key ändern. `Spikes/smc-diff.sh` nimmt zwei vollständige Dumps auf und zeigt die Differenz —
|
||
damit ist der Key **ohne einen einzigen Schreibzugriff** identifizierbar.
|
||
|
||
Bis dieser Test gelaufen ist, bleibt die Akkukarte reine Anzeige.
|
||
|
||
## Auswirkungen auf den Plan
|
||
|
||
1. Phase 6 wird geteilt: **Lüftersteuerung kann gebaut werden**, das Ladelimit wartet auf die
|
||
Differenzmessung.
|
||
2. Alle SMC-Werte werden little-endian gelesen — betrifft `MetricsProvider` und `OnyxHelper`.
|
||
3. `F0Mn`/`F0Mx` werden zur Laufzeit aus der Firmware gelesen statt fest verdrahtet.
|
||
4. Lüfterdrehzahlen sind `flt`, nicht `fpe2`.
|