12.3. Формат пакету#
Кожен байт, що перетинає дріт між камерою та хостом, є частиною пакету. Пакет починається з 10-байтного заголовка, містить корисне навантаження змінної довжини та завершується 4-байтним кінцевим CRC. На дроті не з’являються жодні інші байти – після того як хост побачив 2-байтне синхрослово, наступні байти є заголовком у такій точній послідовності.
12.3.1. Заголовок#
Десять байтів, упакованих без відступів. Кожне поле:
sync– 16-бітне слово0xD5AAу форматі little-endian. Байт 0 на дроті –0xAA, байт 1 –0xD5. Одержувач, що сканує байти, може знайти початок пакету, шукаючи паруAA D5; все, що перед нею, вважається сміттям. Вибір значення є навмисним:0xAAта0xD5рідко зустрічаються в друкованому тексті, і пара навряд чи виникне випадково всередині корисного навантаження.seq– один байт. Лічильник, що збільшується на одиницю для кожного надісланого пакету у заданому напрямку. Одержувач перевіряє, що порядковий номер наступного пакету є очікуваним; якщо ні, рівень надійності запитує повторну передачу.chan– один байт. ID каналу, якому належить цей пакет. Канали 0..31 є придатними для використання; вбудовані каналиstdin,stdout,streamта (опційно)profileотримують фіксовані ID, зарезервовані камерою.flags– один байт. Бітове поле, що повідомляє одержувачу, як інтерпретувати пакет:біт 0
ACK– цей пакет є підтвердженням попереднього.біт 1
NAK– цей пакет відхиляє попередній.біт 2
RTX– цей пакет є повторною передачею.біт 3
ACK_REQ– відправник бажає, щоб цей пакет було підтверджено.біт 4
FRAGMENT– за цим фрагментом ідуть ще в межах більшого повідомлення.біт 5
EVENT– цей пакет містить подію каналу, а не дані.біти 6 та 7 зарезервовані.
opcode– один байт. Код команди або відповіді. Бібліотека протоколу резервує діапазони опкодів за призначенням:0x00..0x0F– команди протоколу (SYNC, GET_CAPS, SET_CAPS, STATS, VERSION).0x10..0x1F– системні команди (RESET, BOOT, INFO, EVENT, MEMORY).0x20..0x2F– команди каналів (LIST, POLL, LOCK, UNLOCK, SHAPE, SIZE, READ, WRITE, IOCTL, EVENT).
len– два байти, little-endian. Кількість байтів корисного навантаження, що йдуть після заголовка. Довжина нуль є допустимою – багато підтверджень і невеликих команд не містять корисного навантаження.crc– два байти. CRC-16 від попередніх восьми байтів заголовка. Одержувач, що отримав заголовок із неправильним CRC, відкидає весь пакет, навіть не дивлячись на корисне навантаження.
12.3.2. Корисне навантаження#
Нуль або більше байтів, що вважаються непрозорими для рівня обрамлення. Вміст корисного навантаження залежить від опкоду: для відповіді CHANNEL_READ – це фактичні дані каналу; для відповіді GET_CAPS – невелика фіксована структура; для запису в канал – це те, що надіслав хост.
Максимальний розмір корисного навантаження залежить від розміру буфера протоколу камери (зверніться до таблиці для відповідної плати у protocol.init()). Повідомлення, що перевищують ліміт, розбиваються на фрагменти з прапорцем FRAGMENT, встановленим для всіх, крім останнього.
12.3.3. Кінцевий CRC#
Чотири байти, CRC-32 від корисного навантаження. Виявляє пошкодження, яке не може побачити CRC заголовка, зокрема у довгих корисних навантаженнях, де інакше одноразова помилка посередині кадру непомітно проскочила б.
Розбиття перевірки цілісності на два CRC є навмисним. CRC заголовка захищає самі поля обрамлення – зокрема довжину корисного навантаження. Без окремого CRC заголовка єдине перевернуте бітове значення в байті довжини змусило б одержувача прочитати неправильну кількість байтів корисного навантаження і повністю вийти із синхронізації з байтовим потоком; з ним пошкоджений заголовок одразу відхиляється, а одержувач знову шукає наступне синхрослово. CRC корисного навантаження потім захищає тіло повідомлення як окрему проблему, тому перевернутий біт у даних повідомляється як пошкоджене корисне навантаження, а не помилка обрамлення.
Формат достатньо малий, щоб розібрати його байт за байтом, а той факт, що кожен пакет має однакове розташування – синхрослово, потім заголовок, потім корисне навантаження, потім CRC – означає, що власноруч написаний аналізатор вміщується на екрані коду. Саме тому мала реалізація хоста на C, Python або Rust – це проект вихідних днів; бібліотека протоколу є підтримуваною версією на Python для кожної зі сторін.