12.2. 네 개의 계층¶
프로토콜 라이브러리는 각각 하나의 문제만 해결하고 그 아래 계층 위에 쌓이는 네 개 계층의 스택으로 구성됩니다. 이 장의 나머지 부분은 스택을 아래에서 위로 따라갑니다.
12.2.1. 전송¶
맨 아래에는 카메라와 호스트 사이의 바이트 파이프가 있습니다. 프로토콜 라이브러리는 어느 것이 바이트를 운반하는지 신경 쓰지 않습니다:
카메라가 꽂혀 있는 USB 포트를 통한 USB-CDC. 모든 카메라에서 기본이자 가장 높은 대역폭을 제공하는 선택지입니다.
카메라의 GPIO 핀 한 쌍을 호스트의 시리얼 어댑터에 연결한 UART. USB 포트가 사용 중이거나 물리적으로 접근할 수 없는 헤드리스 배포에 유용합니다.
전송의 유일한 임무는 “바이트가 들어가면 바이트가 순서대로 나온다”입니다. 이 계층 위의 모든 것은 전송이 바이트를 쓰여진 순서대로 전달한다고 가정하지만, 바이트 자체가 손상되거나 링크가 완전히 끊길 수 있음을 허용합니다. 손실성 버스트(몇 바이트 누락)와 깔끔한 단절(링크 전체가 한동안 사라졌다가 다시 돌아옴)은 둘 다 상위에서 처리됩니다.
12.2.2. 프레이밍¶
그 다음 계층은 바이트 스트림에 구조를 부여합니다. 모든 메시지는 패킷이 됩니다 – 10바이트 헤더 다음에 페이로드가 오고 그 뒤에 4바이트 트레일러가 옵니다. 헤더가 담는 것은:
수신자가 동기화가 깨진 후 패킷의 시작을 다시 찾을 수 있게 하는 2바이트 동기화 워드(
0xD5AA).신뢰성 계층이 사용하는 1바이트 시퀀스 번호.
패킷이 어느 논리적 스트림에 속하는지 알려 주는 1바이트 채널 ID.
ACK / NAK / 조각 / 이벤트 비트를 위한 1바이트 플래그 필드.
프로토콜 명령, 시스템 명령, 채널 명령을 구분하는 1바이트 오피코드.
2바이트 페이로드 길이.
앞선 여덟 개의 헤더 바이트에 대한 2바이트 CRC.
그 다음 페이로드가 오고, 이어서 페이로드 자체에 대한 4바이트 CRC가 옵니다. 두 CRC는 손상을 독립적으로 잡아냅니다: 헤더에서 비트 하나가 뒤집히면 헤더 CRC가 무효화되고, 수신자는 페이로드를 읽을 필요 없이 패킷을 버릴 수 있습니다.
12.2.3. 신뢰성¶
신뢰성 계층은 “도착할 수도 있는 패킷”을 “도착한 패킷”으로 바꿉니다. 헤더의 시퀀스 번호를 추적하고, 확인 응답이 필요한 모든 패킷에 대해 상대측에 확인 응답을 보내도록 요청하며, 확인 응답이 타임아웃 내에 도착하지 않으면 재전송합니다. 기본적으로 재전송 타임아웃은 500ms에서 시작하여 재시도마다 두 배가 되며, 포기하기 전에 세 번 재시도합니다.
이러한 동작 각각은 protocol.init() 호출에서 구성할 수 있습니다: 단방향 스트림에서는 ACK를 끌 수 있고, 완벽하게 깨끗한 전송에서는 CRC 검증을 건너뛸 수 있으며, 느리거나 지연 시간이 긴 링크에 맞춰 재전송 매개변수를 조정할 수 있습니다.
12.2.4. 채널¶
맨 위 계층은 애플리케이션 코드가 보는 것입니다. 채널 은 0에서 31까지의 채널 ID로 식별되는 명명된 논리적 스트림입니다. 하나의 전송 수단에 최대 32개의 채널이 공존할 수 있으며, 각각은 다른 채널과 독립적이고 모든 패킷의 헤더에서 자신의 ID로 주소가 지정됩니다. 카메라는 네 개의 내장 채널 – stdin, stdout, stream, profile – 로 부팅하며, 애플리케이션 코드는 Python 클래스를 인수로 protocol.register() 를 호출하여 그 위에 더 많은 채널을 등록합니다.
네 계층은 관심사를 섞지 않습니다. 프레이밍은 채널에 대해 알지 못하고, 신뢰성은 패킷 내용에 대해 알지 못하며, 채널 계층은 바이트가 어떻게 도착하는지 알지 못합니다. 이러한 분리 덕분에 전송 수단을 교체해도(예를 들어 USB에서 UART로) 그 변화가 채널 코드로 파급되지 않으며, 바로 이것이 이 장의 나머지를 한 번에 한 계층씩 따라갈 수 있게 해 주는 요소입니다.