12.3. Формат пакету#

Кожен байт, що перетинає дріт між камерою та хостом, є частиною пакету. Пакет починається з 10-байтного заголовка, містить корисне навантаження змінної довжини та завершується 4-байтним кінцевим CRC. На дроті не з’являються жодні інші байти – після того як хост побачив 2-байтне синхрослово, наступні байти є заголовком у такій точній послідовності.

A horizontal layout of a protocol packet showing the 10-byte header (sync word, sequence number, channel ID, flags, opcode, payload length, header CRC) followed by the variable-length payload and a 4-byte payload CRC.

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 для кожної зі сторін.