Chapter 04

링크 계층 제어 절차: instant와 충돌 규칙

연결 간격을 바꾸고, 채널 맵을 바꾸고, PHY를 바꾸는 일은 두 기기가 같은 이벤트에서 동시에 바꿔야 한다. 한쪽만 먼저 바꾸면 서로 다른 시각, 다른 채널에서 기다리다 연결이 끊긴다. 링크 계층은 이것을 “instant”라는 미래의 이벤트 번호로 약속한다. 이 장은 그 약속의 규칙과, 두 기기가 동시에 절차를 시작했을 때 누가 양보하는지를 따라가고, 제어 PDU 하나를 공중 비트까지 직접 만들어 본다.

제어 PDU와 “한 번에 하나”

데이터 PDU 헤더의 LLID가 0b11이면 그 페이로드는 LL 제어 PDU다. 첫 바이트가 opcode이고 나머지가 CtrData다. 예: 0x00 LL_CONNECTION_UPDATE_IND, 0x01 LL_CHANNEL_MAP_IND, 0x02 LL_TERMINATE_IND, 0x03/0x04 LL_ENC_REQ/RSP(6장), 0x07 LL_UNKNOWN_RSP, 0x0F LL_CONNECTION_PARAM_REQ, 0x11 LL_REJECT_EXT_IND, 0x14/0x15 LL_LENGTH_REQ/RSP, 0x16~0x18 LL_PHY_REQ/RSP/UPDATE_IND. 모르는 opcode를 받으면 LL_UNKNOWN_RSP로 답하고, 이 답을 받은 쪽은 그 연결에서 같은 절차를 다시 시작하지 않는다.

규칙 둘. 종료 절차를 빼면 한 기기는 한 연결에서 한 번에 한 절차만 시작한다. 그리고 연결 갱신·채널 맵 갱신을 뺀 모든 절차에는 40초 응답 타임아웃(T_PRT)이 있다. 제어 PDU를 큐에 넣을 때마다 타이머를 다시 시작하고, 40초 안에 끝나지 않으면 연결을 잃은 것으로 본다(0x22 LL Response Timeout).

공연장의 “셋에 맞춰 전환”

무대 조명과 음향을 동시에 바꾸려면 “지금!”이라고 외치면 늦는다. 소리가 닿는 사이에 이미 박자가 지나 있다. 그래서 감독은 “다음 소절의 셋째 박에 전환”이라고 미리 알려 둔다. 두 기사는 같은 악보를 보고 박자를 세니까 같은 순간에 바꾼다. instant가 그 “셋째 박”이고, 악보의 박자 번호가 connEventCounter다(3장).

LL 제어 PDU 형식과 opcode(Table 2.22), LL_UNKNOWN_RSP: [Vol 6] Part B §2.4.2 · 한 번에 하나의 절차: §5.1 · 응답 타임아웃 40초: §5.2 · 오류 코드: [Vol 1] Part F §2

instant: 미래의 이벤트 번호로 약속하기

instant가 있는 PDU(연결 갱신, 채널 맵, PHY 갱신, 연결 속도 갱신 등)는 “connEventCount가 이 값이 되는 이벤트부터 새 값을 쓴다”를 뜻한다. 규칙은 이렇다.

예측해 보기

페리페럴 지연이 4(서브레이팅 없음)인 연결에서, 센트럴이 연결 갱신의 instant를 지금부터 3 이벤트 뒤로 잡았다. 무엇이 일어나기 쉬울까?

페리페럴은 몇 이벤트마다 한 번 듣나? instant 전에 PDU를 받을 기회는?

지연 4면 페리페럴은 최악의 경우 5 이벤트마다 한 번 듣는다. 3 이벤트 안에 한 번도 듣지 않을 수 있고, 그다음에 받은 연결 갱신은 instant가 이미 지났으므로 페리페럴은 연결을 잃은 것으로 처리한다. 그래서 사양은 instant를 factor × (latency + 1)을 곱해 6번의 기회 이상 뒤로 잡으라고 한다. 큰 서브레이트를 쓰는 연결이라면 먼저 서브레이트 갱신으로 factor를 1로 낮춘 뒤 절차를 하라고도 권한다.
SIMULATOR

instant를 얼마나 멀리 잡을까

페리페럴이 들을 기회—
instant 전에 한 번도 못 받을 확률—
사양 권장(기회 ≥ 6)—
모델: 센트럴은 instant 전 모든 기회에 PDU를 (재)전송하고, 페리페럴은 factor × (latency + 1) 이벤트마다 한 번 들으며, 각 기회의 실패는 서로 독립이라고 본다. 실패 확률 = 오류율^기회 수. 해볼 것: ① 오류율 30%, 기회 6이면 약 0.07%. ② 지연을 써서 곱이 6이 되면 같은 12 이벤트에 기회는 2번뿐이라 9%로 뛴다. 사양이 “6번의 기회”를 factor와 latency로 곱해 세라고 하는 이유다. ③ 그래프는 instant까지 거리에 따른 실패 확률(로그 눈금).

instant 규칙(6번, mod 65536, 과거 instant와 0x28): [Vol 6] Part B §5.5·§5.5.1 · instant를 지나면 BIG도 동기를 멈출 수 있음: §5.5.2

연결 갱신: 전송 창과 새 앵커 포인트

LL_CONNECTION_UPDATE_IND(opcode 0x00)의 CtrData는 WinSize(1바이트, × 1.25 ms), WinOffset(2바이트, × 1.25 ms), Interval(× 1.25 ms), Latency, Timeout(× 10 ms), Instant다. instant 이벤트의 앵커 포인트에서 바로 새 간격을 쓰는 것이 아니라, instant 직전 이벤트의 앵커 포인트 + 옛 간격 + WinOffset에서 시작하는 전송 창 안에서 센트럴이 처음 보낸 패킷이 새 앵커 포인트가 된다. 그래서 센트럴은 갱신을 기회로 앵커 포인트를 옮겨 다른 연결과의 충돌을 피할 수 있다(호스트에 알리지 않는 “앵커 포인트 이동”).

그 밖의 규칙: WinOffset은 0 ~ 새 간격, WinSize는 1.25 ms ~ min(10 ms, 새 간격 − 1.25 ms). instant에 감독 타이머를 다시 시작한다. 간격이 바뀌면 서브레이트 factor는 1, continuation은 0으로 돌아간다. 센트럴은 instant와 그 직전 이벤트에서 보내고, 페리페럴은 서브레이팅이나 지연과 상관없이 그 두 이벤트를 듣는다. 두 기기 모두 연결 파라미터 요청 절차(0x0F)를 지원하면 그것을 먼저 쓴다.

LL_CONNECTION_UPDATE_IND 형식: [Vol 6] Part B §2.4.2.1 · 연결 갱신 절차(전송 창, instant 전후 이벤트, 서브레이트 초기화, 앵커 포인트 이동): §5.1.1 · 연결 파라미터 요청: §5.1.7

둘이 동시에 시작했을 때

제어 PDU는 실시간으로 처리되지 않는다. 센트럴이 PHY 갱신을 보내는 사이 페리페럴도 연결 파라미터 요청을 보낼 수 있다. 둘 다 instant가 있는 절차면 서로 다른 instant로 다른 것을 바꾸려는 셈이라 함께 진행할 수 없다. 사양은 양립할 수 없는 쌍을 정해 둔다. 둘 다 instant가 있는 절차, 프레임 간격 갱신끼리 또는 프레임 간격 갱신과 CIS 생성, 서브레이트 갱신·요청과 연결 속도 갱신·요청, 그리고 몇몇 채널 사운딩 절차 쌍이다.

절차 A를 시작해 아직 끝나지 않았는데 상대가 양립할 수 없는 절차 B를 시작하면:

  1. 상대가 이미 A에 응답 PDU를 하나라도 보냈다면 → 연결 상태를 떠나는 것이 좋다(끊는다).
  2. 아니면 센트럴은 B를 LL_REJECT_EXT_IND(둘 다 지원하면, 아니면 LL_REJECT_IND)로 거절하고 A를 계속한다.
  3. 페리페럴은 센트럴의 B를 처리하고, 자기 A는 센트럴의 거절을 받는 것 말고는 손을 뗀다.

오류 코드는 같은 절차끼리 부딪혔거나 A가 연결 갱신이고 B가 연결 파라미터 요청이면 0x23(LL Procedure Collision), 그 밖에는 0x2A(Different Transaction Collision)다. 한 번 상대 절차에 응답했다면, 그 절차가 끝날 때까지 양립할 수 없는 새 절차를 시작하지 않는다.

SIMULATOR

절차 충돌 판정기

나의 역할
절차마다 시작할 수 있는 역할이 정해져 있다(연결 갱신·채널 맵·서브레이트 갱신·연결 속도 갱신은 센트럴만, 서브레이트 요청·연결 속도 요청은 페리페럴만). 목록은 그 역할에 맞는 절차만 보인다. 해볼 것: ① 센트럴, A = PHY 갱신, B = 연결 파라미터 요청 → 둘 다 instant가 있어 충돌, 센트럴이 거절(0x2A). ② 페리페럴로 바꾸면 자기 A를 버리고 센트럴의 B를 따른다. ③ A = 데이터 길이 갱신이면 어느 쪽과도 양립한다.

충돌하는 쌍과 처리 순서, 0x23·0x2A: [Vol 6] Part B §5.3 · 절차별 시작 역할: §5.1.1·§5.1.2·§5.1.19·§5.1.20·§5.1.32·§5.1.33

제어 PDU 하나를 공중 비트까지

사양 [Vol 6] Part C §4.3.2에는 LL_CHANNEL_MAP_IND 하나가 공중에 나가는 비트 그대로 실려 있다. 채널 2, 5, 33~36을 빼는 채널 맵, instant 0x4321, 그리고 40 µs짜리 AoD 상수 톤 확장(CTE, 17장)까지. 헤더 첫 바이트의 비트는 LLID(2) · NESN · SN · MD · CP(CTE 정보 있음) · RFU(2)이고, CP가 1이면 길이 바이트 뒤에 CTEInfo 바이트가 붙는다. CRC는 헤더(CTEInfo 포함)와 페이로드에 대해 계산하고, 화이트닝은 그 둘과 CRC에 걸고, CTE는 화이트닝하지 않은 1로 끝에 붙는다.

WORKBENCH

LL 제어 PDU → 공중 비트 (사양 4.3.2 샘플)

PDU 길이—
공중 비트 수—
사양 샘플과 비교—
비트는 공중에 나가는 순서(각 바이트의 작은 비트부터, CRC는 큰 비트부터)로 적었다. 연결 갱신은 WinSize 1, WinOffset 0, Interval 24(30 ms), Latency 0, Timeout 200(2 s)을, 종료는 이유 0x13을 쓴다. 해볼 것: ① 처음 값이 사양의 “Complete packet”과 비트 하나까지 같은지 보자(✓). ② CTE를 0으로 하면 CP가 0이 되고 CTEInfo 바이트와 끝의 1들이 사라진다. ③ 채널 하나를 더 빼면 채널 맵 바이트, CRC, 화이트닝된 비트가 모두 바뀐다.

헤더(Table 2.21)·CP·CTEInfo: [Vol 6] Part B §2.4·§2.5.2 · LL_CHANNEL_MAP_IND: §2.4.2.2 · CRC: §3.1.1 · 화이트닝: §3.2 · 샘플: [Vol 6] Part C §4.3.2(데이터 PDU는 §4.3.1)

핵심 정리

  1. LLID 0b11 = LL 제어 PDU, 첫 바이트 opcode. 한 기기는 한 연결에서 한 번에 한 절차(종료 제외), 응답 타임아웃 40초(연결 갱신·채널 맵 제외).
  2. instant = 새 값을 쓰기 시작할 connEventCount. 센트럴이 고르고, 페리페럴이 들을 기회가 6번 이상이게, mod 65536으로 비교. 지난 instant의 연결 갱신은 0x28로 끊긴다.
  3. 연결 갱신의 새 앵커 포인트는 instant 직전 앵커 + 옛 간격 + WinOffset에서 여는 전송 창 안의 첫 패킷.
  4. 양립할 수 없는 절차가 겹치면: 상대가 이미 응답했으면 끊고, 아니면 센트럴이 거절, 페리페럴이 양보. 같은 절차끼리면 0x23, 아니면 0x2A.
  5. 공중 비트 = 프리앰블 · 접근 주소 · 화이트닝된(헤더 · CTEInfo · 페이로드 · CRC) · 화이트닝 안 한 CTE.

확인 퀴즈

connEventCount가 0xFFF0일 때 Instant 0x0005인 PDU를 받았다. instant는?

(0x0005 − 0xFFF0) mod 65536 = 21 < 32767 이므로 미래.

연결 갱신 PDU의 instant가 이미 지났다. 페리페럴은?

[Vol 6] Part B §5.5.1: LL_CONNECTION_UPDATE_IND면 반드시, 그 밖의 PDU면 그래도 된다.

페리페럴이 PHY 갱신을 시작했는데, 응답을 받기 전에 센트럴이 채널 맵 갱신을 보냈다. 페리페럴은?

둘 다 instant가 있어 양립할 수 없다. 센트럴이 아직 PHY 갱신에 응답하지 않았으므로 페리페럴이 양보한다(오류 0x2A).

LL 제어 PDU 응답 타임아웃이 적용되지 않는 절차는?

[Vol 6] Part B §5.2. 이 둘은 센트럴이 일방적으로 알리는 절차다.