링크 계층 상태 기계와 컨트롤러 스케줄링
스마트워치 하나가 휴대폰과 연결을 유지하면서, 다른 휴대폰에게 광고하고, 체중계를 스캔하고, 이어폰 방송을 받는다. 그런데 무선은 하나다. 사양은 “무엇을 언제 해야 하는가”를 정하고, “겹치면 무엇을 먼저 하는가”는 컨트롤러 구현에 맡긴다. 이 장은 그 경계를 따라간다. 연결 이벤트를 어떻게 세고 건너뛰는지는 사양대로 정확히 계산하고, 스케줄러는 사양의 제약을 지키는 예시 모델로 만들어 본다.
- 링크 계층의 일곱 상태, 상태 기계 여러 개, 반드시 함께 지원해야 하는 조합(Table 1.1)을 안다.
- 앵커 포인트, connEventCounter, T_IFS·T_MCES로 연결 이벤트 하나의 시간을 설명할 수 있다.
- 서브레이팅·연속 이벤트·페리페럴 지연 규칙으로 어느 이벤트에서 누가 듣는지 계산할 수 있다.
- 스케줄링 충돌로 이벤트를 건너뛰어도 되는 한계(감독 타임아웃)와, 그 한계를 어기는 설정을 알아본다.
일곱 상태, 여러 개의 상태 기계
링크 계층 상태 기계 하나는 한 번에 한 상태에만 있다. 대기(Standby), 광고, 스캔, 연결 시작(Initiating), 연결(센트럴 또는 페리페럴 역할), 동기화(주기적 광고·BIG 받기), 등시성 방송. 모든 상태는 대기에서 들어가고, 연결 상태만 예외로 연결 시작(→ 센트럴)이나 광고(→ 페리페럴)에서 들어간다. 그리고 링크 계층은 상태 기계를 여러 개 가질 수 있다. 위의 스마트워치는 상태 기계 넷이 동시에 돌고 있는 것이다.
모든 조합을 지원할 의무는 없지만 짝을 이룬 의무가 있다. 연결 시작 상태(+ 다른 상태 C)를 지원하면 같은 C와 함께 센트럴 연결도 지원해야 하고, 센트럴 연결 + 연결 시작을 지원하면 페리페럴 여럿과의 센트럴 연결도 지원해야 한다. 광고 쪽도 대칭이다. 연결을 “만들 수 있는” 조합이면 만든 뒤의 조합도 감당해야 한다는 뜻이다.
일곱 상태와 전이(그림 1.1): [Vol 6] Part B §1.1 · 상태 기계 여러 개와 조합 의무(Table 1.1): §1.1.1
연결 이벤트 하나의 시간
연결 이벤트의 시작이 앵커 포인트다. 센트럴은 보낼 것이 있으면 앵커 포인트에 정확히 첫 PDU를 보내고, 페리페럴은 그 시각에 듣는다. 이벤트 안에서는 센트럴 → 페리페럴 사이에 T_IFS_ACL_CP, 페리페럴 → 센트럴 사이에 T_IFS_ACL_PC(기본 150 µs)를 두고 번갈아 보내며, 한 이벤트는 한 채널만 쓴다. 이벤트가 끝나는 조건(MD 비트, CRC 오류 연속)은 1권 6장에서 봤다. 센트럴은 마지막 패킷과 다음 앵커 포인트 사이에 최소 T_MCES(기본 150 µs)를 남겨야 한다. 앵커 포인트는 connInterval마다 오고 서로 겹치지 않는다.
두 기기는 connEventCounter(16비트)를 함께 센다. 첫 이벤트가 0이고, 이벤트마다 1씩 늘며 0xFFFF 다음 0으로 돌아간다. 중요한 것은 건너뛴 이벤트도 센다는 점이다. 센트럴이 아무것도 보내지 않았어도, 페리페럴이 듣지 않았어도 카운터는 오른다. 다음 장의 “instant”가 이 카운터로 약속하기 때문에, 둘이 서로 다른 이벤트 수를 셌다면 절차가 어긋난다.
“매일 정각마다 통화하고, 오늘부터 23번째 통화에서 새 번호로 바꾸자”고 약속했다면, 내가 바빠서 받지 못한 정각도 세어야 둘의 23번째가 같은 시각이 된다. 그래서 링크 계층은 건너뛴 이벤트도 빠짐없이 센다.
앵커 포인트·connEventCounter·T_MCES 규칙: [Vol 6] Part B §4.5.1 · T_IFS: §4.1.1 · T_MCES 기본 150 µs: §4.1.5 · 이벤트 닫기: §4.5.6
누가 어느 이벤트에 나오나: 서브레이팅·연속 이벤트·지연
connInterval이 짧으면 반응은 빠르지만 전력이 든다. 연결을 끊지 않고 이벤트를 줄이는 장치가 셋 있다.
- 서브레이팅(5.3): (connEventCount − connSubrateBaseEvent)가 connSubrateFactor의 배수인 이벤트만 서브레이트 이벤트(S)다. 센트럴은 S 이벤트에만 보낸다(그리고 아래 C 이벤트, 절차가 정한 이벤트). factor는 1~500.
- 연속 이벤트(C): 데이터가 오가기 시작하면 다음 S까지 기다리지 않도록, 바로 앞 connContinuationNumber개의 이벤트(마지막 S 이후) 가운데 하나라도 길이가 0이 아닌 PDU가 오갔다면 그 이벤트도 쓴다. continuation은 0 ~ factor − 1.
- 페리페럴 지연(L): 페리페럴은 connPeripheralLatency개의 연속된 S 이벤트를 듣지 않아도 된다. 단 S 이벤트에서 센트럴의 패킷을 받았다면 그다음 C 이벤트는 반드시 듣고, 센트럴에게 받지 못한 동안은 지연을 쓰지 않고 매 S를 듣는 것이 좋다.
제약은 factor × (latency + 1) ≤ 500, connInterval × factor × (latency + 1) < 감독 타임아웃의 절반이다. 사양의 예: factor 3, continuation 0, latency 6이면 페리페럴은 21번째 이벤트마다(7번째 S마다) 들으면 된다.
이벤트 지도: S·C·L
서브레이트·연속 이벤트·페리페럴 지연의 정의와 예(21번째 이벤트), 제약: [Vol 6] Part B §4.5.1(그림 4.43~4.47) · 카운터가 넘칠 때 base 조정: 같은 절 · 서브레이팅 절차: §5.1.19·§5.1.20
무선 하나, 일 여럿: 스케줄러
센트럴의 연결 이벤트, 광고 이벤트, 스캔 창, 다른 연결의 이벤트가 같은 시각에 겹치면 컨트롤러는 하나만 할 수 있다. 사양은 어떤 것을 고르라고 정하지 않는다. 대신 경계를 정한다. 센트럴은 “일정 충돌로” 한 이벤트에서 아무것도 보내지 않을 수 있지만, 감독 타임아웃 안에 적어도 한 번은 보내야 한다. 페리페럴도 지연이나 충돌과 상관없이 감독 타임아웃 안에 적어도 한 번은 들어야 한다. 이 경계를 넘으면 상대 쪽 타이머가 끝나 연결이 끊기고 오류 코드 0x08(Connection Timeout)이 남는다.
그래서 실제 스케줄러는 대개 우선순위에 “굶은 정도”를 더한다. 오래 건너뛴 일일수록 다음 충돌에서 이기게 한다. 센트럴은 자기 연결들의 앵커 포인트를 처음부터 서로 엇갈리게 놓아 충돌 자체를 줄인다(연결 간격을 서로 배수로 맞추는 이유).
스케줄러 예시 모델: 1초 동안의 무선
센트럴이 연결 여섯 개를 7.5 ms 간격으로 유지하고, 각 연결이 매 이벤트에 2.5 ms씩 쓴다. 무엇이 일어날까?
이벤트 하나에 2.5 ms × 6 = ?
일정 충돌로 이벤트에서 보내지 않음·감독 타임아웃 안에 한 번: [Vol 6] Part B §4.5.1 · 감독 타임아웃: §4.5.2 · 오류 코드 0x08: [Vol 1] Part F §2
핵심 정리
- 상태는 일곱, 상태 기계는 여럿. 연결을 만들 수 있는 조합을 지원하면 만든 뒤의 조합도 지원해야 한다(Table 1.1).
- 앵커 포인트에 센트럴이 먼저 보내고, 이벤트 사이에 T_MCES(기본 150 µs)를 남긴다. connEventCounter는 건너뛴 이벤트도 센다.
- S = (count − base)가 factor의 배수인 이벤트, C = 직전 continuation개 이벤트에 데이터가 있었던 이벤트, L = 페리페럴이 지연으로 건너뛰는 S. factor × (latency + 1) ≤ 500.
- 스케줄러는 구현의 몫이지만, 감독 타임아웃 안에 센트럴은 한 번 보내고 페리페럴은 한 번 들어야 한다. 어기면 0x08로 끊긴다.
확인 퀴즈
센트럴이 충돌로 한 연결 이벤트에서 아무것도 보내지 않았다. connEventCounter는?
factor 4, base 1이면 서브레이트 이벤트는?
factor 3, continuation 0, latency 6에서 페리페럴이 반드시 들어야 하는 간격은?
센트럴이 감독 타임아웃 동안 한 번도 보내지 못하면?