12.3. 패킷 형식

카메라와 호스트 사이의 와이어를 건너는 모든 바이트는 패킷의 일부입니다. 패킷은 10바이트 헤더로 시작하여 가변 길이 페이로드가 이어지고, 4바이트 후행 CRC로 끝납니다. 와이어에는 그 외의 바이트가 나타나지 않습니다 – 호스트가 2바이트 동기화 워드를 본 순간, 다음 바이트들은 정확히 이 순서로 된 헤더입니다.

10바이트 헤더(동기화 워드, 시퀀스 번호, 채널 ID, 플래그, opcode, 페이로드 길이, 헤더 CRC) 뒤에 가변 길이 페이로드와 4바이트 페이로드 CRC가 이어지는 프로토콜 패킷의 수평 레이아웃.

12.3.1. 헤더

패딩 없이 패킹된 10바이트. 각 필드:

  • sync – 리틀 엔디언 순서의 16비트 워드 0xD5AA. 와이어상의 바이트 0은 0xAA, 바이트 1은 0xD5 입니다. 바이트를 스캔하는 수신 측은 AA D5 쌍을 검색하여 패킷의 시작을 찾을 수 있으며, 그 앞의 모든 것은 쓰레기로 취급됩니다. 이 값의 선택은 의도적입니다: 0xAA0xD5 는 인쇄 가능한 텍스트에 거의 나타나지 않으며, 이 쌍이 페이로드 중간에 우연히 발생할 가능성도 낮습니다.

  • seq – 1바이트. 주어진 방향으로 전송되는 각 패킷마다 1씩 증가하는 카운터. 수신 측은 다음 패킷의 시퀀스 번호가 예상한 것인지 확인하며, 그렇지 않으면 신뢰성 계층이 재전송을 요청합니다.

  • chan – 1바이트. 이 패킷이 속한 채널 ID. 채널 0..31을 사용할 수 있으며, 내장 stdin, stdout, stream, 그리고 (선택적으로) profile 채널은 카메라가 예약한 고정 ID를 사용합니다.

  • flags – 1바이트. 수신 측에 패킷을 어떻게 해석할지 알려주는 비트 필드:

    • 비트 0 ACK – 이 패킷은 이전 패킷에 대한 확인 응답입니다.

    • 비트 1 NAK – 이 패킷은 이전 패킷을 거부합니다.

    • 비트 2 RTX – 이 패킷은 재전송입니다.

    • 비트 3 ACK_REQ – 송신 측이 이 패킷에 대한 확인 응답을 원합니다.

    • 비트 4 FRAGMENT – 더 큰 메시지에서 이 패킷 뒤에 더 많은 프래그먼트가 이어집니다.

    • 비트 5 EVENT – 이 패킷은 데이터가 아니라 채널 이벤트를 담고 있습니다.

    • 비트 6과 7은 예약되어 있습니다.

  • opcode – 1바이트. 명령 또는 응답 코드. 프로토콜 라이브러리는 목적에 따라 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 – 2바이트, 리틀 엔디언. 헤더 뒤에 따라오는 페이로드 바이트 수. 길이 0은 유효합니다 – 많은 확인 응답과 작은 명령은 페이로드를 담지 않습니다.

  • crc – 2바이트. 앞선 8개 헤더 바이트에 대한 CRC-16. 잘못된 CRC가 있는 헤더를 받은 수신 측은 페이로드를 보지도 않고 패킷 전체를 폐기합니다.

12.3.2. 페이로드

0개 이상의 바이트로, 프레이밍 계층에서는 불투명하게 취급됩니다. 페이로드의 내용은 opcode에 따라 다릅니다: CHANNEL_READ 응답의 경우 실제 채널 데이터이고, GET_CAPS 응답의 경우 작은 고정 구조체이며, 채널 쓰기의 경우 호스트가 보낸 무엇이든 됩니다.

최대 페이로드 크기는 카메라의 프로토콜 버퍼 크기에 따라 다릅니다(protocol.init() 의 보드별 표를 참조하십시오). 상한보다 긴 메시지는 마지막 프래그먼트를 제외한 모든 프래그먼트에 FRAGMENT 플래그가 설정된 채로 분할됩니다.

12.3.3. 후행 CRC

4바이트, 페이로드에 대한 CRC-32. 헤더 CRC가 볼 수 없는 손상을 잡아내며, 특히 프레임 중간의 단일 비트 오류가 그렇지 않으면 빠져나갈 수 있는 긴 페이로드에서 유용합니다.

무결성 검사를 두 개의 CRC로 나누는 것은 의도적입니다. 헤더 CRC는 프레이밍 필드 자체 – 특히 페이로드 길이 – 를 보호합니다. 별도의 헤더 CRC가 없으면 길이 바이트의 단일 비트 반전으로 인해 수신 측이 페이로드에 대해 잘못된 바이트 수를 읽어 바이트 스트림과 완전히 동기를 잃게 됩니다. 헤더 CRC가 있으면 손상된 헤더는 즉시 거부되고 수신 측은 다음 동기화 워드를 다시 스캔합니다. 그러면 페이로드 CRC는 메시지 본문을 별개의 관심사로 보호하므로, 데이터의 비트 반전은 프레이밍 오류로 오인되는 대신 손상된 페이로드로 보고됩니다.

이 형식은 바이트 단위로 살펴볼 수 있을 만큼 충분히 작으며, 모든 패킷이 동일한 레이아웃 – 동기화, 그 다음 헤더, 그 다음 페이로드, 그 다음 CRC – 을 가진다는 사실은 직접 작성한 파서가 화면 한 페이지 분량의 코드에 들어맞는다는 것을 의미합니다. 그래서 C, Python, 또는 Rust로 된 작은 호스트 구현은 주말 프로젝트입니다. 프로토콜 라이브러리는 양측에서 유지 관리되는 Python 버전입니다.