Files
shturman/docs/domains/b-power-lifecycle.md
T
kk0t9 b9500356b0 docs(v0.3): синхронизация швов power-safe + статус
Двунаправленные швы (спека v0.3 §10) после реализации Плана 7:
- domain B: banner «Реализация (v0.3)» (B01–B07, VM-модель abort/PONR=stop+umount+remount);
  §12 — MCU/supercap (B08/B09) → v0.4.
- ipc.md §3: Power оживлён из FSM (не mock); Sleep/Wake/RequestSleep зарезервированы.
- foundation §5.2: «Power-стаб» → реальный PowerFsm (проекции state/ignition/source из FSM);
  dev-mock кормит входы FSM.
- CLAUDE.md: статус v0.3 ГОТОВО; «Следующее» → v0.5 shell / v0.4 MCU-thermal.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Alexander <akotenev2003@gmail.com>
2026-06-25 00:21:10 +03:00

21 KiB
Raw Blame History

Домен B — Power / Lifecycle

Привилегированный core-сервис: владеет power-path, детектом зажигания, graceful shutdown, протоколом MCU-копилота, watchdog, sleep/wake и сохранением времени. Вторая половина «power-safe с дня 1» (с доменом A).

Статус: v2 (на ревью). v2 — после adversarial-ревью (22 находки). Связано с: architecture.md (§6) · hardware.md (§3 питание/MCU) · a-base-system.md (§5–§11) · ipc.md (Power) · principles.md (#5) · домены D (гейт wake-word), E (engine-state)

Реализация (v0.3): срезы B01B07 реализованы — чистый PowerFsm (§2: off↔accessory↔running→shutting-down {abortable→committed}→off, abort до PONR) + сервис ru.shturman.Power оживлён из FSM (grace-таймер + durable-barrier sync на commit), watchdog/save-time-конфиг. VM-модель: abort/PONR в Lima = stop+umount+remount, power-cut = SIGKILL+fsck. Аппаратное (MCU/hold-up/heartbeat/safe-to-cut/fail-safe-таймер) и выбор B08/B09v0.4; sleep/wake/battery-cutoff — каркас (no-op), тело → v1/v2 (§7). Спека: docs/specs/v0.3-power-safe.md.


1. Назначение и границы

  • Что делает: детект зажигания, секвенсинг питания, graceful shutdown, watchdog-арбитраж, sleep/wake, сохранение времени; публикует ru.shturman.Power.
  • Границы: не трогает CAN и не управляет узлами авто; координирует только питание устройства.
  • Power-safe (#5) = A + B вместе: A — read-only rootfs / ФС / atomic-write; B — graceful shutdown + hold-up-секвенсинг + watchdog.
  • Владение состоянием: Power.IgnitionState (off/accessory/running) — единственный канонический источник lifecycle-состояния (voltage/GPIO/MCU). E владеет лишь engine_running (узко, из RPM — отличить «заглушен» от «нет данных»), не дублирует IgnitionState (см. §9, e-vehicle-data §2).

2. Машина состояний питания

   ┌─────┐  ACC-on   ┌───────────┐  напряжение>порог  ┌──────────┐
   │ off │──────────▶│ accessory │──(генератор)──────▶│ running  │
   └─────┘           └───────────┘◀──напряжение<порог─└──────────┘
     ▲ ▲                  │                                │
     │ │ ACC-off(debounced)/under-voltage-held/thermal-trip│
     │ │                  ▼                                │
     │ │        ┌──────────────────────┐◀─────────────────┘
     │ │        │ shutting-down(ABORTABLE)│ pre-PONR: re-power → назад в accessory/running
     │ │        └──────────┬────────────┘
     │ │   unmount (PONR)  ▼
     │ └──── cut ◀─ ┌──────────────────────┐ committed: только → off
     │              │ shutting-down(COMMITTED)│
     │              └──────────────────────┘
   off ◀─ battery-cutoff ◀─ sleep ⇄ accessory/running   (sleep: wake по ACC/таймеру/реверсу)
  • running детектится по напряжению бортсети (генератор ~13.8–14.4 В vs покой ~12.2–12.6 В), доступному Power/MCU напрямую через ADC того же рейла, где hardware §3 ставит brown-out-пороги. RPM/CAN — опциональное уточнение в v2 (когда поднимется E), не обязательное.
  • shutting-down разбит на ABORTABLE (до point-of-no-return) и COMMITTED (с unmount).
  • battery-cutoff: при долгой стоянке — forced off для сохранения энергии на запуск (§7).
  • Триггеры shutting-down: ACC-off (debounced) · under-voltage held · thermal-trip (§4).

3. Детект зажигания (ACC) — кондиционированный

Не голый уровень GPIO (hardware §3): debounce/glitch + минимальная стабильная длительность ACC-off больше worst-case cold-crank-просадки; гистерезис + приоритет crank. Владелец: MCU-копилот (рек.) либо софт на SoC (supercap-only).

4. Graceful shutdown (секвенсинг)

Триггеры (три, все ведут полный путь — есть время на флаш, кроме самого резкого обрыва):

  • ACC-off (debounced, окно > crank) — авторитетное решение «выключаемся».
  • Under-voltage ниже brown-out-порога с гистерезисом (hardware §3), удержанное дольше worst-case crank — backstop при реальном обвале рейла (НЕ rate-of-change: «резкое падение» срабатывало бы на каждом запуске, cold-crank до ~6 В — НОРМА, ride-through).
  • Thermal-trip (критическая температура, a-base §10) — причина ≠ ACC, UX «перегрев» в Shell.

Порядок (sizing энергии — hardware §3; секвенсинг — здесь):

  1. Power эмитит ShutdownImminent(seconds, reason).
  2. Load-shedding (политика по триггеру):
    • резкий обрыв/hold-up: агрессивно сбросить всё, кроме SoC+хранилище;
    • управляемый ACC-off: мягко, с коротким grace-окном на дисплей/камеру-рейл (парковка с реверсом — §7, B-COMPL-04).
    • amp-mute перед снятием рейла усилителя (anti-pop): mute-GPIO усилителя (hardware §4) дёргается ДО cut — шов с медиа-выходом H §8.
  3. Ordered teardown: App-Host останавливает апы/плагины (StopApp) с per-app ack/save-таймаутом (сумма ≤ hold-up-бюджет); E на ShutdownImminent гасит активный OBD-TX и закрывает ISO-TP-сессии (B даёт сигнал, E владеет закрытием — B не трогает CAN).
  4. Settings флашится в /data + критичные логи fsync (a-base §9) — критичный fsync завершается ДО PONR.
  5. Сохранение last-known-time (§8).
  6. Размонтирование RW → point-of-no-return.
  7. Sn-питания по safe-to-cut (§5).

Abort (re-power до PONR): стабильное восстановление ACC/напряжения (через debounce/гистерезис) → обратный переход; откат: переподнять сброшенные нагрузки, снять у апов save-режим; Power эмитит ShutdownAborted (= канонизированный сигнал отмены). После PONR abort недоступен.

Деградированный путь (исчерпание hold-up): часть шагов — critical-and-atomic (должны завершиться), часть — best-effort (могут быть потеряны); инвариант «после усечённого shutdown /data консистентен» держится atomic-write-контрактом A §3.

5. MCU-копилот (прошивка + протокол)

  • Делает: мониторит зажигание (дебаунснутый ACC) и напряжение, управляет hold-up/секвенсингом, сигналит SoC, держит watchdog, sleep/wake.

Shutdown-протокол (специфицируем СЕЙЧАС — shutdown это MVP, не §12-задел):

  1. ACC-off → MCU стартует hold-up-таймер (= hold-time hardware §3); это и есть тот же бюджет, что fail-safe-таймер §5 (один когерентный, не два).
  2. SoC ведёт секвенсинг (§4 шаги 2–6); heartbeat SoC→MCU во время shutdown — MCU отличает «SoC работает» (держать питание до бюджета) от «SoC завис» (cut по таймеру).
  3. SoC шлёт safe-to-cut после PONR → MCU снимает питание немедленно.
  4. Таймер истёк без safe-to-cut → MCU снимает всё равно (детерминированно; durability — до последнего fsync).
  5. Потеря линка (обрыв шлейфа): fail-safe в ОБЕ стороны определён явно — MCU при тишине в running трактует по политике (cut/reboot vs hold — §12); SoC при тишине MCU — деградирует.
  6. Supercap-only: аналог на SoC-таймере + разряд cap (нет умного MCU для cut).

Безопасность линка: MCU — fail-safe-авторитет, НЕ подчиняется слепо командам SoC с power-эффектом; ни одно SoC-сообщение не должно (а) снять питание на ходу, (б) держать вечно и разрядить АКБ. Защита от replay/мусора/десинка на UART/I2C (аналог защиты CAN-линка hardware §4).

Критичность MCU: прошивка обновляема (бутлоадер — баг не кирпичит); независимый аппаратный fail-safe-таймер снятия питания при отказе самого MCU; позиция в цепочке доверия (подмена прошивки не обходит red-line). ⚠️ Если v0-таргет = MCU-вариант — аппаратный fail-safe- таймер ОБЯЗАН быть в v0 (иначе v0 power-safe не закрыт); прошивка-update — v1.

MCU-вариант vs supercap-only

Функция MCU-вариант supercap-only Потеря/замена
Детект ACC MCU (дебаунс) софт на SoC
Hold-up секвенсинг MCU-таймер + safe-to-cut SoC-таймер + разряд cap при зависшем SoC некому shed/cut → нужен внешний таймер или принятый риск
Fail-safe при зависшем SoC независимый MCU-таймер отсутствует внешний WDT-чип ЛИБО письменный риск единой точки
Watchdog-бэкстоп независимый от SoC-WDT только SoC-WDT см. §6
Sleep / scheduled-wake always-on MCU ограничено (нет always-on) глубокий sleep/таймер-wake может быть недоступен

6. Watchdog (по фазам жизненного цикла)

  • Runtime: on-SoC RK3588 WDT — единственный userspace-владелец (systemd RuntimeWatchdogSec), второй пэтящий клиент запрещён.
  • Shutdown-фаза: RuntimeWatchdogSec её НЕ покрывает → отдельный таймаут: systemd RebootWatchdogSec (путь reboot) либо детерминированный дедлайн MCU/supercap на финальный unmount/sync (шаги 46). Зависание в sync/unmount (PONR) не оставляет устройство под питанием вечно. MCU на shutdown-imminent переключается в wait-for-completion (расширенный таймаут ≥ shutdown-бюджет), не продолжает короткий keepalive — чтобы не снять питание посреди unmount.
  • MCU-watchdog — независимый бэкстоп.
  • Boot-окно: WDT вооружён до userspace (U-Boot / always-on MCU).
  • System-of-record форс-ресета (v0) = SoC-WDT + MCU-backstop + reboot, стыкуемый с базовым recovery A §6 (v0). Интеграция force-reset → bootcount/slot-switch/откат A/B (A §5) — v4 (с OTA); v0-watchdog от bootcount-handshake НЕ зависит.

7. Sleep / wake и защита АКБ

  • Низкопотребление при заглушённом двигателе (быстрый/scheduled wake).
  • Источники пробуждения: ACC-on, таймер, реверс-передача (Stage 0 камера, §4/J), опц. CAN-wakeup.
  • battery-cutoff (отдельно от ACC-off): при долгой стоянке порог напряжения (раньше/выше operating-brown-out hardware §3 — зарезервировать энергию на запуск) → sleep → forced off; гистерезис на wake-on-ACC. Бюджет разряда — §12 (с hardware).
  • Гейт wake-word: D §8 слушает только в running/accessory, не в sleep/off (читает сигналы Power).

8. Сохранение и монотонность времени

  • Save last-known-time (fake-hwclock) в /data не только на graceful shutdown, но и: (а) периодически systemd-таймером (~1–5 мин, только вперёд, по порогу прироста, atomic-write A §3); (б) на каждом успешном NTP/GPS-синке (a-base §7). Save-on-shutdown — финальный, не единственный (после резкого обрыва часы откатываются максимум на один интервал, не на всю сессию).
  • Lifecycle-таймеры на МОНОТОННЫХ часах (CLOCK_MONOTONIC): ShutdownImminent-отсчёт, hold-up-бюджет, watchdog keepalive, Uptime, sleep/wake — НЕ wall-clock (плата без RTC, wall-clock легитимно прыгает при синке).
  • Первый boot/factory-reset (нет файла fake-hwclock): wall-clock с epoch до первого fix → TLS-egress gated (a-base §7), метки критичных/audit-логов помечаются «до синка»; lifecycle-таймеры работают (монотонные).
  • Монотонность «только вперёд»: при boot wall-clock = max(fake-hwclock, build-epoch, last-log-ts) — не идти назад относительно последней записи (порядок audit-log не ломается).

9. IPC (ru.shturman.Power)

Реестр — ipc.md §3. Уточнения этого домена:

  • GetPowerState() → state — enum по §2 (off/accessory/running/shutting_down/sleep/battery_cutoff).
  • IgnitionState (ось зажигания: off/accessory/running) — канонический; E зеркалит/потребляет, не дублирует.
  • PowerSource — enum { vehicle_12v, holdup_cap, sleep_rail, low_battery }; переход в holdup_cap сообщает потребителям «питание от cap, времени мало».
  • ShutdownImminent(seconds, reason)reason ∈ {acc_off, under_voltage, thermal, battery_cutoff}.
  • ShutdownAborted() — отмена (re-power до PONR).

10. Функции

функция MVP/later зависит от фаза
Детект ACC (debounce + crank) + running по напряжению MVP (день 1) hardware/MCU v0
Graceful shutdown sequencing (+ ordered teardown) MVP (день 1) a-base, hold-up (hardware §3) v0
Машина состояний (+ abort/committed) MVP v0
ru.shturman.Power сервис MVP ipc v0
Watchdog (runtime + shutdown-фаза + boot-окно) MVP hardware, a-base v0
Load-shedding при power-loss MVP селективные рейлы (hardware §6) v0
Save last-known-time + периодика MVP a-base §7 v0
MCU-копилот shutdown-протокол (если MCU) MVP hardware §3 v0
MCU аппаратный fail-safe-таймер MVP hardware §3 v0
Thermal shutdown (триггер + hysteresis + UX) MVP a-base §10, hardware §1a v0/v1
MCU прошивка: update path later hardware v1
Sleep/wake + battery-cutoff later v1/v2
Гейт wake-word по состояниям (с D) MVP D v1
Реверс-wake (Stage 0 камера) · scheduled/CAN-wake later hardware §4, J v2/later

11. Зависимости

  • Вниз: hardware (power-path, селективные рейлы, ACC-GPIO, ADC напряжения, MCU + fail-safe-таймер, hold-up sizing, secure-boot trust).
  • Вбок: A (RO-rootfs/ФС/atomic-write/время-синк/recovery — вместе делают power-safe); E (engine_running, закрытие ISO-TP на shutdown).
  • Вверх/потребители: все апы (ShutdownImminent→«сохранись», ShutdownAborted→откат); Settings; D (гейт wake-word); Shell (UX «перегрев»).

12. Открытые вопросы

  • 🟡 MCU-копилот vs supercap-only (hardware §3, B08/B09) — определяет владельца ACC/watchdog, наличие независимого бэкстопа и fail-safe-снятия при зависшем SoC, и доступность scheduled-wake. → v0.4 (вероятно нужна аппаратная проверка).
  • ◻️ Протокол SoC↔MCU (UART/I2C/GPIO, формат, keepalive, политика тишины-линка, replay-защита) — shutdown-подмножество уже специфицировано в §4/§5, остальное здесь.
  • ◻️ Бюджет разряда АКБ (sleep, ACC-off listening, battery-cutoff порог) — числа с hardware.
  • ◻️ Тепловые пороги (critical-trip + recovery-hysteresis) — согласовать с a-base §10 + hardware §1a.
  • Удержание дисплей/камера-рейла после ACC-off (grace-hold): J — запросчик (J §7), B — владелец/арбитр (§4 шаг 2 grace-окно, §7) — ограничивает hold-up-бюджетом, не переопределяет PONR. С реверс-камерой Stage 0.

Журнал решений (домен B)

Решение Выбор Дата
Детект ACC (debounce+crank) + running по напряжению (RPM — v2-уточнение); IgnitionState — канон B 2026-06-16
Триггеры shutdown ACC-off / under-voltage-held (не rate-of-change) / thermal-trip; cold-crank — ride-through 2026-06-16
Shutdown sequencing + ordered teardown (E закрывает ISO-TP); abort до PONR (ShutdownAborted); degraded path 2026-06-16
MCU-протокол hold-up-таймер + heartbeat + safe-to-cut; fail-safe при потере линка; MCU — fail-safe-авторитет 2026-06-16
MCU фазы HW fail-safe-таймер = v0 (с MCU-вариантом); прошивка-update = v1 2026-06-16
Watchdog runtime (RuntimeWatchdogSec) + shutdown-фаза (Reboot/MCU дедлайн) + boot-окно; v0=SoC+MCU+reboot, bootcount=v4 2026-06-16
Время save периодически + on-sync + on-shutdown; lifecycle-таймеры монотонны; «только вперёд» 2026-06-16
Состояние Power.IgnitionState канон; E владеет узким engine_running 2026-06-16