Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@
ручной выбор в параметрах Windows не трогаем. По умолчанию выключено (XIC-96).

### Исправлено
- **Прошивки экрана и тачпада снова видны на вкладке «Драйверы».** Xiaomi PC Manager предлагал
прошивку панели и тачпада, а XiControl молчал: строка «прошивка» появлялась только при совпадении
hardware-id каталога с устройством в системе, а у прошивок эти id условные — такого устройства нет
ни на одном ноутбуке. Теперь, если Xiaomi публикует пакет прошивки для модели, он показан в
отдельной группе «Прошивки» — версия из каталога и ссылка, под тем же предупреждением, что и BIOS.
Текущую версию прошивки прочитать по-прежнему нечем, поэтому «у вас старее» не говорим: возможно,
она уже стоит. Для обычных драйверов ничего не изменилось (XIC-102).
- **Вебхук «заряд дошёл до порога» больше не обрывает «В дорогу».** Во время разового заряда до
100 % событие уходило всё равно, едва заряд проходил обычный порог, — и розетка из автоматизации
Home Assistant выключалась на 80 %, так что «В дорогу» до конца не доходил. Теперь на время
Expand Down
4 changes: 3 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,9 @@ WMI-событий). `Program.cs`: single-instance mutex → DI-контейне
отсекает скользящий pre-release; не чаще раза в сутки, тумблер = выключатель трафика,
самообновления нет намеренно — запущенный exe не перезаписать, XIC-20),
`OemDrivers` (XIC-95: `OemProtocol` — тело/подпись/разбор ответа сервера Xiaomi, `DriverMatch` —
сверка строго попарно по hardware-id, оба чистые и под тестами; `OemDriverCheck` — WMI + сеть, только по
сверка строго попарно по hardware-id — кроме прошивок `FWTP`/`FWSC`: их id в каталоге синтетические,
строка «в каталоге есть прошивка X» даётся по факту пакета для модели, одна на модуль (XIC-102); оба
чистые и под тестами; `OemDriverCheck` — WMI + сеть, только по
кнопке, без `sn`, ничего не скачивает и не ставит; протокол — `docs/16-oem-driver-check.md`),
`OemService` (XIC-87: службы Xiaomi — MiDeviceService на выходе из Eco откатывает яркость и сама
меняет режим питания Windows, MiService (аккаунт/телеметрия) не мешает, отключение по желанию; чтение состояния и отключение/включение через SCM напрямую, без sc.exe —
Expand Down
23 changes: 18 additions & 5 deletions docs/16-oem-driver-check.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,18 @@ XMAPT4B0P0A0A → "0A0A" → 0x0A0A = 2570 → "1.0.0.2570"
> захватом службы до символа), `DriverMatch` (сверка попарно по hardware-id), `OemDriverCheck`.
> Показываем сводку по модулям и подробно — только обновления, со ссылкой на пакет (второе нажатие
> открывает её в браузере). У BIOS — тоже ссылка, но под отдельным предупреждением «на свой страх
> и риск» (решение владельца: иначе родная утилита оставалась бы нужна ради одного BIOS). Прошивки `FWTP`/`FWSC` с версией драйвера
> не сравниваются: строка «в каталоге есть прошивка X». Ничего не скачиваем и не ставим.
> и риск» (решение владельца: иначе родная утилита оставалась бы нужна ради одного BIOS). Ничего не
> скачиваем и не ставим.
>
> **Прошивки `FWTP`/`FWSC` (XIC-102)** — отдельная группа «Прошивки», по строке на модуль, если сервер
> вернул пакет: «Прошивка: Тачпад / Экран — в каталоге версия X», ссылка на пакет под предупреждением
> как у BIOS. Сверки по hardware-id для них **нет**: их id в каталоге синтетические
> (`USB\VID_6789&PID_1234&REV_1236/1237` у экрана, `USB\VID_6989&PID_1234&REV_1836/1837` у тачпада) и в
> `Win32_PnPSignedDriver` не встречаются — до XIC-102 строка была недостижима, и XiControl молчал там,
> где PC Manager предлагал прошивку. Версия — из `hardwareIds[0].version` (на TM2424: `740B08` у экрана,
> `3.5.13.01.44.25.13.0` у тачпада), имя устройства — локализованная константа по коду модуля, не из PnP.
> С версией драйвера не сравниваем и «у вас старее» не говорим — текущую версию прошивки читать нечем
> (см. «Ограничения»). Для обычных драйверов правило прежнее: нет совпавшего устройства — нет строки.

Сверка «что установлено против того, что есть у OEM» делается без сети и без Xiaomi-софта:

Expand Down Expand Up @@ -159,9 +169,12 @@ XMAPT4B0P0A0A → "0A0A" → 0x0A0A = 2570 → "1.0.0.2570"
- метаданные местами мусорные (у чипсета `releaseTime` = `1968-07-18`) — даты показывать с оглядкой;
- **текущие версии прошивок тачпада (`FWTP`) и экрана (`FWSC`) читать пока нечем.** Служба берёт
их через `firmware::GetFirmwareVersionById` — реестр плюс `FirmwareScreenTool.exe`, то есть части
MiService. Без неё скажем «есть пакет версии X», но не «у вас старее». Возможный путь для
тачпада — наш канал `COL05` (в `SvrCModule.dll` есть `sc::TouchSettingManager::ReadFirmware`),
не проверено.
MiService. Без неё говорим «в каталоге есть прошивка X» (так и сделано, XIC-102), но не «у вас
старее» — пакет может оказаться уже установленным, об этом предупреждаем прямо в UI. Возможный
путь для тачпада — наш канал `COL05` (в `SvrCModule.dll` есть `sc::TouchSettingManager::ReadFirmware`),
не проверено;
- hardware-id прошивок в каталоге **синтетические** и ни с чем в системе не совпадают — сверять их
по PnP бессмысленно, строка даётся по факту пакета для модели.

## 5. Где лежат данные

Expand Down
4 changes: 4 additions & 0 deletions src/Localization/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@
"settings.drivers.updates.warn": "Packages come from Xiaomi's server: XiControl has not checked them and does not install them. The link opens in your browser. Create a restore point before installing.",
"settings.drivers.update.desc": "{0} → {1} · {2}",
"settings.drivers.package": "{0}, {1} MB",
"settings.drivers.firmware.group": "Firmware",
"settings.drivers.firmware.warn": "Flashing the display or touchpad firmware is at your own risk. XiControl has not checked the package and does not install it: the link opens in your browser. The current firmware version cannot be read — you may already have this one. Install only with the tool inside this archive, on AC power, and do not interrupt it.",
"settings.drivers.firmware.title": "Firmware: {0}",
"settings.drivers.firmware.desc": "Catalog version {0} · {1}. The current firmware version cannot be read, so it cannot be compared.",
"settings.drivers.download": "Open link",
Expand Down Expand Up @@ -309,6 +311,8 @@
"settings.drivers.mod.PMT": "Platform monitoring",
"settings.drivers.mod.HDR": "Display HDR",
"settings.drivers.mod.OTS": "IoT module",
"settings.drivers.mod.FWSC": "Display",
"settings.drivers.mod.FWTP": "Touchpad",
"settings.drivers.oem.group": "Xiaomi services",
"settings.drivers.oem.desc": "Preinstalled by Xiaomi and stays after PC Manager is uninstalled. When you leave Eco mode it restores the previous brightness, and on every mode change it switches the Windows power mode by itself. XiControl does not need it.",
"settings.drivers.oem.status": "Now: {0}, startup — {1}.",
Expand Down
4 changes: 4 additions & 0 deletions src/Localization/lang/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@
"settings.drivers.updates.warn": "Пакеты лежат на сервере Xiaomi: XiControl их не проверял и не устанавливает. Ссылка откроется в браузере. Перед установкой создайте точку восстановления.",
"settings.drivers.update.desc": "{0} → {1} · {2}",
"settings.drivers.package": "{0}, {1} МБ",
"settings.drivers.firmware.group": "Прошивки",
"settings.drivers.firmware.warn": "Прошивка экрана или тачпада — на ваш страх и риск. XiControl пакет не проверял и не устанавливает: ссылка откроется в браузере. Текущую версию прошивки прочитать нечем — возможно, у вас уже она. Ставьте только штатной утилитой из этого архива, на питании от сети и не прерывая процесс.",
"settings.drivers.firmware.title": "Прошивка: {0}",
"settings.drivers.firmware.desc": "В каталоге версия {0} · {1}. Текущую версию прошивки прочитать нечем — сравнить не можем.",
"settings.drivers.download": "Открыть ссылку",
Expand Down Expand Up @@ -309,6 +311,8 @@
"settings.drivers.mod.PMT": "Мониторинг платформы",
"settings.drivers.mod.HDR": "HDR экрана",
"settings.drivers.mod.OTS": "IoT-модуль",
"settings.drivers.mod.FWSC": "Экран",
"settings.drivers.mod.FWTP": "Тачпад",
"settings.drivers.oem.group": "Службы Xiaomi",
"settings.drivers.oem.desc": "Предустановлена Xiaomi и остаётся после удаления PC Manager. При выходе из режима Eco возвращает прежнюю яркость, а при смене режима сама переключает режим питания Windows. XiControl она не нужна.",
"settings.drivers.oem.status": "Сейчас: {0}, запуск — {1}.",
Expand Down
4 changes: 4 additions & 0 deletions src/Localization/lang/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@
"settings.drivers.updates.warn": "驱动包来自小米服务器:XiControl 未对其进行检查,也不会安装。链接将在浏览器中打开。安装前请创建还原点。",
"settings.drivers.update.desc": "{0} → {1} · {2}",
"settings.drivers.package": "{0},{1} MB",
"settings.drivers.firmware.group": "固件",
"settings.drivers.firmware.warn": "刷写屏幕或触控板固件风险自负。XiControl 未检查该固件包,也不会安装:链接将在浏览器中打开。无法读取当前固件版本——你可能已经是这个版本。请仅使用此压缩包内的官方工具、在接通电源的情况下刷写,且不要中断。",
"settings.drivers.firmware.title": "固件:{0}",
"settings.drivers.firmware.desc": "目录版本 {0} · {1}。无法读取当前固件版本,因此无法比较。",
"settings.drivers.download": "打开链接",
Expand Down Expand Up @@ -309,6 +311,8 @@
"settings.drivers.mod.PMT": "平台监控",
"settings.drivers.mod.HDR": "屏幕 HDR",
"settings.drivers.mod.OTS": "IoT 模块",
"settings.drivers.mod.FWSC": "屏幕",
"settings.drivers.mod.FWTP": "触控板",
"settings.drivers.oem.group": "小米服务",
"settings.drivers.oem.desc": "由小米预装,卸载 PC Manager 后仍会保留。退出 Eco 模式时它会恢复之前的亮度,每次切换模式时还会自行切换 Windows 电源模式。XiControl 不需要它。",
"settings.drivers.oem.status": "当前:{0},启动类型:{1}。",
Expand Down
23 changes: 14 additions & 9 deletions src/SystemIntegration/OemDrivers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public sealed record OemHardwareId(string Id, string Version);
public sealed record InstalledDriver(string HardwareId, string Version, string Device);

/// <summary>Сверка одного устройства с каталогом. <see cref="Firmware"/> — прошивка: её текущую
/// версию читать нечем, поэтому только «в каталоге есть такая».</summary>
/// версию читать нечем и устройства под её id в системе нет, поэтому только «в каталоге есть такая».</summary>
public enum DriverState { Same, Update, Newer, Firmware }

public sealed record DriverRow(string Module, string Device, string? Installed, string Catalog, DriverState State, OemPackage? Package);
Expand Down Expand Up @@ -156,7 +156,8 @@ private static OemPackage ParsePackage(JsonElement p)
private static string Str(string s) => JsonSerializer.Serialize(s);
}

/// <summary>Сверка каталога с установленным — строго попарно по hardware-id (чистая логика).</summary>
/// <summary>Сверка каталога с установленным — строго попарно по hardware-id (чистая логика);
/// прошивки — исключение, см. <see cref="Compare"/>.</summary>
public static class DriverMatch
{
/// <summary>
Expand Down Expand Up @@ -187,23 +188,27 @@ internal static int CompareVersions(string a, string b) =>
/// Строки сверки. Версия — из записи ЭТОГО hardware-id, не «пакета»: один zip везёт драйверы
/// разных вендоров (у аудио 10 разных версий на 125 id). Несколько id каталога могут указывать
/// на одно устройство — строку даём одну.
/// Прошивки (XIC-102) — без сверки по hardware-id: их id в каталоге синтетические
/// (<c>USB\VID_6789&amp;PID_1234&amp;REV_1236</c> у экрана), такого устройства в системе нет,
/// а текущую версию прошивки читать нечем. Поэтому строка — одна на модуль с пакетом,
/// «в каталоге есть прошивка X»; в <c>Device</c> — код модуля, имя ему даёт UI по локализации.
/// </summary>
internal static List<DriverRow> Compare(IEnumerable<OemModule> modules, IReadOnlyList<InstalledDriver> installed)
{
var rows = new List<DriverRow>();
var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var m in modules)
{
bool firmware = OemProtocol.IsFirmware(m.Name);
if (OemProtocol.IsFirmware(m.Name))
{
if (m.Package is not null && seen.Add(m.Name))
rows.Add(new DriverRow(m.Name, m.Name, null, m.HardwareIds.Count > 0 ? m.HardwareIds[0].Version : "", DriverState.Firmware, m.Package));
continue;
}
foreach (var h in m.HardwareIds)
{
if (Find(installed, h.Id) is not { } inst) continue;
if (!seen.Add($"{m.Name}|{inst.Device}|{h.Version}")) continue;
if (firmware)
{
rows.Add(new DriverRow(m.Name, inst.Device, null, h.Version, DriverState.Firmware, m.Package));
continue;
}
int c = CompareVersions(h.Version, inst.Version);
var state = c > 0 ? DriverState.Update : c < 0 ? DriverState.Newer : DriverState.Same;
rows.Add(new DriverRow(m.Name, inst.Device, inst.Version, h.Version, state, m.Package));
Expand Down Expand Up @@ -274,7 +279,7 @@ public static async Task<DriverCheckResult> RunAsync(CancellationToken ct = defa
: rows.Count == 0 ? DriverCheckStatus.NoMatch
: DriverCheckStatus.Ok;
Log.Write($"OemDriverCheck: {product}, модулей с пакетом {modules.Count}, устройств сверено {rows.Count}, " +
$"обновлений {rows.Count(r => r.State == DriverState.Update)}, без ответа {failed}");
$"обновлений {rows.Count(r => r.State == DriverState.Update)}, прошивок {rows.Count(r => r.State == DriverState.Firmware)}, без ответа {failed}");
return new DriverCheckResult(status, product, rows, sys.Bios, bios?.FirstOrDefault()?.Package,
bios is not null, failed, DateTime.Now);
}
Expand Down
Loading
Loading