Додавання типу пристрою
Каталог периферійних пристроїв Sentinel містить апаратні факти. Новий тип пристрою (наприклад, дисплей або послідовний ад аптер) потребує типізованого запису, провайдера, який його виявляє, тестів і сторінки в цій теці. Чи підтримує застосунок пристрій, вирішує сам застосунок, а не Sentinel.
1. Визначте запис
Додайте модуль у src/peripherals/ зі структурою serde для пристрою і
додайте її як варіант Peripheral у src/peripherals/mod.rs. Ім’я
варіанта стає тегом type у JSON, тож Display(display::Display) серіалізується
як {"type": "display", ...}. Розширте Peripheral::id, kind і describe
для нового варіанта.
idмає бути стабільним між повторними підключеннями та перезавантаженнями: виводьте його зі шляху шини, серійного номера або іншого атрибута, що їх переживає, і ніколи — з індексу переліку, як-от номера карти чи/dev/videoN.idтакож має бути унікальним у межах усього каталогу; робочий потік (worker) цього не перевіряє. Додавайте до нього префікс із типу та провайдера, як це роблять наявні id (camera:v4l2:…,microphone:alsa:…), а решту будуйте з того, що не може бути спільним для двох однакових пристроїв, як-от порт, до якого їх підключено. Самого серійного номера недостатньо: дешеві пристрої часто мають однакові номери.- Необов’язкові факти — це поля
Option, позначені#[serde(default, skip_serializing_if = "Option::is_none")], як у наявних записах, тож невідомий факт не потрапляє до JSON. Звичайне полеOptionсеріалізувалося б якnull. - Повідомляйте факти, які надає ядро або пристрій. Не додавайте полів, що кодують політику, як-от те, чи підтримується режим.
2. Напишіть провайдер
Реалізуйте трейт Provider:
pub trait Provider: Send {
fn name(&self) -> &'static str; // e.g. "display.drm"
fn subsystems(&self) -> &'static [&'static str]; // uevent subsystems, e.g. ["drm"]
fn discover(&mut self) -> Result<Vec<Peripheral>, ProviderError>;
}
discover виконує одне повне сканування в потоці peripherals. Робочий потік викликає
його під час запуску, після uevent від однієї з підсистем subsystems і за запитом на оновлення.
- Лише читання. Відкривайте вузли пристроїв лише для читання й використовуйте тільки інтерфейси запитів. Ніколи не захоплюйте пристрій у володіння, не налаштовуйте його й не запускайте з нього потік.
- Обмеженість. Обмежуйте кожен список, який читаєте, і кожен цикл запитів, щоб несправний
пристрій не міг загальмувати сканування. Допоміжні функції V4L2 у
videodev2.rsдемо нструють цей підхід. - Помилки. Повертайте
ProviderErrorз кодом на кшталтio.permission_deniedабоio.open(див.sysutil.rs), коли сканування не може завершитися. Тоді каталог зберігає останні справні пристрої цього провайдера й показує помилку вerrors. Пристрій, що зникає під час сканування, пропускається, і це не помилка; uevent, який надсилається під час його від’єднання, запускає повторне сканування. - Плавна деградація замість збою. Якщо необов’язкового атрибута немає, його поле пропускається.
Атрибут, який існує, але не читається, обробляйте відповідно до його призначення:
- атрибут, потрібний скануванню для пошуку чи ідентифікації пристрою (його id, його ідентичність USB), є помилкою, тож останні справні пристрої провайдера зберігаються;
- атрибут, який лише додає факт, не заважає опублікувати пристрій без цього факту,
із зазначенням причини в записі (так робить поле
issuesзапису мікрофона для нечитабельних метаданих захоплення).
Зареєструйте провайдер у builtin_providers() у src/peripherals/mod.rs.
3. Протестуйте його
Тести читають дерево фікстур замість живої системи: передайте провайдеру його
кореневі каталоги sysfs, procfs і /dev як параметри та підробіть шар ioctl, як це роблять
alsa/tests.rs і v4l2/tests.rs. Охопіть кожну відмінність між пристроями класу,
а не лише пристрій, який у вас є: кількості, формати, діапазони проти дискретних
значень, відсутні необов’язкові поля, кілька однакових пристроїв одночасно та
пристрій, що зникає посеред сканування. Перевірте, що два однакові пристрої отримують
різні id. Позначайте фікстури, скопійовані з реального обладнання, як
реальні знімки.
cargo test --locked має проходити, а cargo fmt --check і cargo clippy --locked --all-targets не повинні повідомляти нічого нового.
4. Задокументуйте його
Додайте в цю теку ст орінку, яка містить ім’я провайдера, підсистеми
uevent, спосіб виведення id, кожне поле з умовою його наявності,
коди помилок і приклад JSON. Додайте посилання на неї з довідника API
та покажчика документації, а потім перегенеруйте переклади
(див. розділ Локалізація).