12.3. Định dạng gói tin

Mỗi byte truyền qua dây giữa cam và máy chủ đều là một phần của gói tin. Một gói tin bắt đầu với tiêu đề 10 byte, chạy qua một tải trọng có độ dài thay đổi, và kết thúc với CRC đầu cuối 4 byte. Không có byte nào khác xuất hiện trên dây -- khi máy chủ đã thấy từ đồng bộ 2 byte, các byte tiếp theo là tiêu đề theo trình tự chính xác này.

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. Tiêu đề

Mười byte, đóng gói không có phần đệm. Mỗi trường:

  • sync -- từ 16 bit 0xD5AA theo thứ tự little-endian. Byte 0 trên dây là 0xAA, byte 1 là 0xD5. Một bộ nhận quét byte có thể tìm thấy đầu của gói tin bằng cách tìm kiếm cặp AA D5; bất cứ điều gì trước nó được coi là rác. Việc chọn giá trị này là cố ý: 0xAA0xD5 hiếm khi xuất hiện trong văn bản có thể in, và cặp này khó xảy ra ngẫu nhiên ở giữa tải trọng.

  • seq -- một byte. Một bộ đếm tăng thêm một cho mỗi gói tin được gửi theo một hướng nhất định. Bộ nhận kiểm tra xem số thứ tự của gói tin tiếp theo có phải là số dự kiến hay không; nếu không, lớp độ tin cậy yêu cầu truyền lại.

  • chan -- một byte. ID kênh mà gói tin này thuộc về. Các kênh 0..31 có thể sử dụng; các kênh stdin, stdout, stream và (tùy chọn) profile tích hợp sẵn chiếm các ID cố định mà cam dành riêng.

  • flags -- một byte. Một trường bit cho bộ nhận biết cách diễn giải gói tin:

    • bit 0 ACK -- gói tin này là xác nhận của một gói tin trước đó.

    • bit 1 NAK -- gói tin này từ chối một gói tin trước đó.

    • bit 2 RTX -- gói tin này là một lần truyền lại.

    • bit 3 ACK_REQ -- người gửi muốn gói tin này được xác nhận.

    • bit 4 FRAGMENT -- có thêm các mảnh theo sau gói tin này trong một thông điệp lớn hơn.

    • bit 5 EVENT -- gói tin này mang sự kiện kênh thay vì dữ liệu.

    • bit 6 và 7 được dành riêng.

  • opcode -- một byte. Mã lệnh hoặc phản hồi. Thư viện giao thức dành riêng các dải mã lệnh theo mục đích:

    • 0x00..0x0F -- lệnh giao thức (SYNC, GET_CAPS, SET_CAPS, STATS, VERSION).

    • 0x10..0x1F -- lệnh hệ thống (RESET, BOOT, INFO, EVENT, MEMORY).

    • 0x20..0x2F -- lệnh kênh (LIST, POLL, LOCK, UNLOCK, SHAPE, SIZE, READ, WRITE, IOCTL, EVENT).

  • len -- hai byte, little-endian. Số byte tải trọng theo sau tiêu đề. Độ dài bằng không là hợp lệ -- nhiều xác nhận và lệnh nhỏ không mang tải trọng.

  • crc -- hai byte. CRC-16 trên tám byte tiêu đề trước đó. Một bộ nhận nhận được tiêu đề với CRC xấu sẽ bỏ toàn bộ gói tin mà không cần xem xét tải trọng.

12.3.2. Tải trọng

Không có hoặc nhiều byte, được lớp đóng khung xử lý như dữ liệu không trong suốt. Nội dung của tải trọng phụ thuộc vào mã lệnh: đối với phản hồi CHANNEL_READ là dữ liệu kênh thực tế; đối với phản hồi GET_CAPS là một cấu trúc cố định nhỏ; đối với lệnh ghi kênh là bất cứ thứ gì máy chủ gửi.

Kích thước tải trọng tối đa phụ thuộc vào kích thước bộ đệm giao thức của cam (tham khảo bảng theo bo mạch trong protocol.init()). Các thông điệp dài hơn giới hạn được chia thành các mảnh với cờ FRAGMENT được đặt trên tất cả trừ mảnh cuối cùng.

12.3.3. CRC đầu cuối

Bốn byte, CRC-32 trên tải trọng. Phát hiện sự hỏng hóc mà CRC tiêu đề không thể thấy, đặc biệt là trên các tải trọng dài khi một lỗi bit đơn giữa khung hình sẽ bị bỏ qua.

Việc chia kiểm tra tính toàn vẹn thành hai CRC là cố ý. CRC tiêu đề bảo vệ các trường đóng khung -- đặc biệt là độ dài tải trọng. Không có CRC tiêu đề riêng biệt, một bit lật trong byte độ dài sẽ khiến bộ nhận đọc sai số byte cho tải trọng và mất đồng bộ với luồng byte hoàn toàn; với CRC đó, một tiêu đề bị hỏng bị từ chối ngay lập tức và bộ nhận quét lại để tìm từ đồng bộ tiếp theo. CRC tải trọng sau đó bảo vệ nội dung thông điệp như một mối quan tâm riêng biệt, vì vậy một bit lật trong dữ liệu được báo cáo là tải trọng bị hỏng thay vì bị nhầm lẫn với lỗi đóng khung.

Định dạng đủ nhỏ để đi qua từng byte, và thực tế là mỗi gói tin có cùng bố cục -- đồng bộ, rồi tiêu đề, rồi tải trọng, rồi CRC -- có nghĩa là một trình phân tích cú pháp tự viết tay phù hợp trong một màn hình mã. Đó là lý do tại sao một triển khai máy chủ nhỏ bằng C, Python hoặc Rust là một dự án cuối tuần; thư viện giao thức là phiên bản Python được duy trì ở mỗi phía.