12.1. Навіщо потрібна бібліотека протоколу¶
Пара кабелів і швидкість передачі (бод) достатні для переміщення байтів із камери на хост-ПК. USB-CDC та UART надають програмі камери потік, де write вкладає байти з одного кінця, а read витягує їх з іншого. Що ж додає бібліотека протоколу поверх цього?
Три речі, які довелося б щоразу писати самостійно, якби ви намагалися побудувати серйозний канал між камерою та хостом безпосередньо на сирих байтах:
Обрамлення (Framing). Байтовий потік не має внутрішньої структури. Камера записує temp=42, а хост зчитує temp= разом із переривання, що надходить пізніше, потім 42 з наступним повідомленням, яке починається з humid=... і вже зливається з ним. Байти не мають меж. Кожне нетривіальне з’єднання хоста в підсумку вигадує якийсь маркер – \n між повідомленнями, заголовки з полем довжини, escape-послідовності для двійкових даних – щоб одержувач знав, де закінчується одне повідомлення і починається наступне. Бібліотека протоколу надає уніфікований формат пакету з синхрословом і полем довжини, і одержувачу ніколи не доводиться здогадуватися.
Надійність (Reliability). USB-CDC не губить байти непомітно в нормальному режимі роботи, але UART це робить (коли хост недостатньо швидко обслуговує порт), а від’єднання і повторне підключення серійного кабелю може залишити один бік із неповним пакетом. Правильна поведінка – виявити пошкодження, попросити іншу сторону надіслати повторно та передавати коду застосунку лише ті повідомлення, що надійшли неушкодженими. Бібліотека протоколу робить це для кожного пакету за допомогою CRC і підтверджень (ACK) для кожного пакету – увімкнено за замовчуванням; застосунок не бачить повторних спроб.
Мультиплексування (Multiplexing). Між камерою та хостом є лише один порт USB-CDC. Якщо камера транслює зображення і хост надсилає їй конфігурацію і IDE зчитує stdout для виводу print, всі три обміни повинні спільно використовувати цей єдиний байтовий потік. Бібліотека протоколу присвоює кожному незалежному потоку номер каналу, дозволяє камері зареєструвати клас Python для кожного з них і запобігає взаємному впливу читань різних каналів на хості. З погляду коду застосунку кожен канал виглядає як окреме приватне з’єднання.
12.1.1. Чому б не написати це самостійно¶
Можна. Щоб правильно реалізувати всі три аспекти на серійній лінії, знадобляться кілька тижнів роботи, і ще кілька тижнів – щоб обрамлення коректно обробляло відновлення після гарячого від’єднання, повторні передачі не витрачали зайву енергію на обходи, а мультиплексор витримував часткові читання без пошкодження байтів одного каналу в інший.
Бібліотека протоколу вже виконала цю роботу, перевірена на всіх підтримуваних камерах і має відповідні бібліотеки на стороні хоста, що розуміють той самий дротовий формат. Використання її означає, що код на стороні камери – це один невеликий клас на кожен канал, а код на стороні хоста – це об’єкт Camera з методами channel_read і channel_write. Зекономлений розумовий ресурс можна вкласти в те, що застосунок насправді робить.
Цей розділ навчає протоколу з нуля: дротовий формат, правила обрамлення, механізм надійності, модель каналів та, нарешті, класи Python на обох сторонах. Після його вивчення читач зможе створити графічний інтерфейс хоста, що спілкується з камерою, скрипт для потокової передачі даних датчиків із камери на ноутбук, а також інтерактивний інструмент калібрування, подібний до того, що постачається у openmv-projects/tools/.