36940db938a8f4a1e919496793ed439850a221c2에 고정한다. 범위는 LE Host·HCI·Controller의 구조와 이미지 배치다. GATT 서비스 설계, 프로파일별 API, pairing 절차와 무선 성능 수치는 여기서 다루지 않는다. 그림은 원본을 복제하지 않고 설명을 위해 새로 그렸다.1. Host는 프로토콜을, Controller는 무선 시각을 맡는다
Zephyr의 Bluetooth LE Host는 애플리케이션에 API를 제공하고 GAP 역할, 연결과 상위 프로토콜의 상태를 관리한다. Controller는 Link Layer와 무선 하드웨어 쪽에서 패킷의 송수신 및 링크 절차를 수행한다. 두 층 사이의 HCI는 명령·이벤트·데이터의 형식과 교환 경계다. HCI 자체를 UART 한 가닥과 동의어로 읽으면 한 칩 안에서 Host와 Controller가 함께 동작하는 구성을 설명할 수 없다.
↔ 좁은 화면에서는 구조도를 가로로 이동해 보세요.
| 층 | 여기서 결정하는 것 | 여기서 결정하지 않는 것 | 3.7.0 확인 위치 |
|---|---|---|---|
| 애플리케이션·Host | 광고·스캔·연결 같은 요청과 Host 상태 | Radio의 슬롯별 송수신 시각 | subsys/bluetooth/host/ |
| HCI 경계 | 명령·이벤트·ACL 데이터의 교환 형식과 드라이버 전달 | 상위 애플리케이션 정책이나 실제 전파 | hci_core.c, HCI 드라이버 API |
| Controller·Radio | Link Layer 절차와 무선 패킷 처리 | 애플리케이션의 GATT 의미 | subsys/bluetooth/controller/ |
기존 Networking 글의 net_if·net_pkt·소켓 경로와 이 글의 BLE Host/Controller 경로는 분석 대상이 다르다. 같은 net_buf 타입을 볼 수 있어도 그것만으로 IP 패킷 경로와 HCI 경계를 합쳐서는 안 된다.
2. 한 칩의 경계와 두 칩의 케이블은 같은 개념이 아니다
단일칩 결합 이미지에는 애플리케이션, Host, Controller가 함께 들어간다. 공식 구조 문서는 이때 Host–Controller 사이가 RAM의 함수 호출과 큐로 연결될 수 있다고 설명한다. 듀얼칩에서는 Host 이미지와 Controller 전용 이미지가 서로 다른 칩에서 돌고, HCI가 UART·SPI·USB 같은 전송을 가로지를 수 있다. 그림의 UART는 가능한 한 예시이며 모든 보드의 필수 배선은 아니다.
↔ 좁은 화면에서는 두 배치를 가로로 비교해 보세요.
| 이미지 | 포함하는 역할 | HCI 전달 | 검증할 조건 |
|---|---|---|---|
| 단일칩 결합 | 앱 + Host + Controller | 칩 내부의 HCI 경계 | 대상 SoC의 Controller·HCI 장치가 실제 설정에 포함됐는가 |
| Host 전용 | 앱 + Host | 외부 Controller로 명령·데이터 전송 | 선택된 HCI 드라이버와 실제 전송 장치가 준비됐는가 |
| Controller 전용 | Link Layer + HCI 외부 인터페이스 | 외부 Host의 명령을 받아 이벤트·데이터를 반환 | RAW HCI 샘플의 transport·버퍼 설정이 보드에 맞는가 |
Controller 전용을 “Host 기능을 끈 결합 앱”으로만 이해하지 않는다. 3.7.0의 hci_uart 샘플은 CONFIG_BT_HCI_RAW=y와 H:4 transport를 사용해 Zephyr Controller를 외부 Host에 노출한다. 이 샘플의 설정값은 샘플과 보드에 묶인 예시다. 다른 transport나 칩에 그대로 복사하는 일반 처방이 아니다.
근거: 공식 배치와 Host/Controller 빌드 유형, HCI UART 샘플 목적·하드웨어 조건, 고정 샘플 설정.
3. 광고 요청과 연결 데이터는 HCI를 다르게 지난다
광고를 시작할 때 Host는 Controller에 설정 명령을 보내고, Controller의 명령 완료·상태 이벤트를 받는다. 스캔 중 발견한 광고는 반대로 Controller의 보고 이벤트가 Host로 올라온다. 연결된 뒤 애플리케이션 데이터가 상위 프로토콜을 통해 이동하는 경우에는 HCI ACL 데이터 경로가 쓰인다. 따라서 모든 광고 패킷을 ACL 데이터라고 부르지 않는다.
↔ 좁은 화면에서는 제어 흐름과 ACL 흐름을 오른쪽으로 이동해 확인하세요.
| HCI 단위 | 대표 방향 | 대표 상황 | 혼동하지 않을 점 |
|---|---|---|---|
| Command | Host → Controller | 광고·스캔·연결 절차 설정 | 호출 자체가 Radio 전송 완료를 뜻하지 않음 |
| Event | Controller → Host | Command Complete/Status, 광고 보고, 연결 상태 변화 | 명령 응답뿐 아니라 비동기 통지도 있음 |
| ACL Data | 양방향 | 연결된 링크의 상위 데이터 운반 | 광고 제어·광고 보고를 ACL과 합치지 않음 |
고정 소스의 bt_buf_type은 BT_BUF_CMD, BT_BUF_EVT, 송수신 ACL 버퍼를 별도 값으로 둔다. Host의 bt_hci_cmd_send_sync()는 명령 버퍼를 송신 큐에 넣고 완료·상태 처리를 기다린다. 실제 전송은 선택된 HCI 드라이버로 내려가며, 이벤트 수신은 해당 드라이버의 callback을 통해 Host로 올라온다. 이는 흐름 설명이지 모든 callback이 동일한 스레드에서 실행된다는 주장은 아니다.
근거: HCI 버퍼 유형, Host 명령 큐, HCI 드라이버 송신, HCI 드라이버 open/send/receive 계약.
4. 빌드 옵션과 선택된 장치를 분리해 확인한다
CONFIG_BT=y는 Bluetooth 기능을 켠다. 3.7.0의 BT_HCI는 HCI 기반 스택 선택이며, BT_CTLR는 SoC native Controller 구현을 포함하는 선택이다. BT_HCI_RAW는 Controller를 RAW HCI로 외부에 노출할 때 쓰인다. 그러나 개별 prj.conf의 몇 줄만으로 실제 Host–Controller 배치가 확정되지는 않는다. 보드 devicetree와 생성된 .config도 함께 확인해야 한다.
# 3.7.0 공식 hci_uart 샘플에서 발췌한 역할 표지
CONFIG_BT=y
CONFIG_BT_HCI_RAW=y
CONFIG_BT_HCI_RAW_H4=y
CONFIG_BT_HCI_RAW_H4_ENABLE=y
# 이 네 줄만 새 보드에 붙여서 동작을 보장하지 않는다.
# 보드의 Controller, UART, HCI 선택과 최종 .config를 확인한다.
BT_HCI_RAW_H4는 RAW HCI의 H:4 transport 지원을 켠다. 이 샘플의 BT_HCI_RAW_H4_ENABLE은 H:4를 빌드 시점에 활성화한다. 앞의 옵션 하나만으로 모든 실행에서 H:4가 이미 선택됐다고 가정하지 않는다.
| 확인 지점 | 성립 조건 | 실패할 때 보이는 경계 |
|---|---|---|
.config | 목적한 Host/Controller/RAW HCI 선택이 반영됨 | 소스에 함수가 있어도 이미지에는 빠질 수 있음 |
zephyr.dts·HCI 장치 | 선택한 HCI driver와 transport가 실제 보드와 맞음 | Host의 bt_enable()에서 장치 준비 실패 가능 |
bt_enable() 반환·완료 | cb=NULL이면 동기 완료를, cb!=NULL이면 호출 반환과 완료 callback의 err를 모두 확인 | -ENODEV·driver open 오류 또는 비동기 초기화 오류를 구분 |
| Controller 전용 UART 샘플 | UART H:4와 HW flow control 등 샘플 하드웨어 조건 충족 | HCI 링크 문제를 상위 GATT 문제로 오진하지 않음 |
고정 Host 소스는 zephyr,bt-hci chosen node가 있으면 해당 device를 받아 준비 여부를 검사하고 HCI driver를 연다. 그 chosen node가 없는 빌드에는 당시의 별도 legacy driver 등록 경로도 남아 있다. 그러므로 “모든 3.7 보드는 chosen node를 반드시 사용한다”라고 일반화하지 않는다. 또한 bt_enable(cb)에서 callback을 넘겼다면 호출의 반환값 0은 초기화 전체 성공의 확인값이 아니다. 완료 callback이 받은 err까지 확인해야 한다.
근거: BT·BT_HCI·RAW HCI 선택, Controller 선택, bt_enable 장치·driver·비동기 완료 분기, bt_enable callback 계약, HCI UART 샘플 요구 조건.
초기화 완료와 저장된 Bluetooth 설정 복원도 구분한다. CONFIG_BT_SETTINGS를 사용하면 bt_enable()이 성공적으로 완료된 뒤 settings_load() 또는 settings_load_subtree("bt")로 Bluetooth 설정을 읽어야 한다. 비동기 호출은 성공 callback 이후가 이 순서의 기준이다. 초기화 전에 이미 전체 설정을 읽었다고 해서 이 단계를 건너뛸 수는 없다. 고정 API의 설정 복원 전제.
5. 문제가 생기면 세 경계의 관찰 결과를 나란히 둔다
광고가 보이지 않는다는 결과 하나로 Host, HCI 링크, Controller 중 어느 층이 멈췄는지 결정할 수 없다. 먼저 빌드가 의도한 이미지 유형인지 확인하고, Host의 bt_enable() 결과(cb!=NULL이면 완료 callback의 err 포함)와 HCI driver 준비·open 상태를 기록한다. 그다음 명령에 대한 완료·상태 이벤트가 오는지 확인하고, 스캔 보고 또는 연결 데이터가 어느 방향에서 끊기는지 좁힌다. 실제 패킷 측정은 보드와 transport별 도구가 필요하다.
| 관찰 | 먼저 확인 | 그다음 분리할 것 |
|---|---|---|
bt_enable() 실패 | 선택된 HCI device와 driver open 반환 | 보드 devicetree·transport 초기화 |
| 명령을 보냈지만 다음 상태가 없음 | Command Complete/Status 이벤트 수신 | HCI transport와 Controller 처리 |
| 광고·스캔 문제 | Host 요청과 Controller 이벤트를 별도 기록 | 무선 노출·환경·상대 기기 |
| 연결 후 데이터 문제 | 양방향 ACL buffer 흐름 | 상위 프로토콜과 Controller 링크 구분 |
이 진단표는 관찰 순서다. 코드만 읽어 실제 전파 성공, 타이밍, 손실률을 인증할 수 없다. 특히 듀얼칩의 HCI transport 종류와 보드 배선은 제품 구성마다 다르다.
6. 자료의 고정점과 이어 읽기
구조와 배치의 기준은 Zephyr 3.7.0 Stack Architecture다. Host의 실제 HCI 경계는 고정 hci_core.c와 HCI driver API, Controller 쪽 소스의 출발점은 controller/hci/hci.c다. 실제 Controller 전용 transport 구성은 hci_uart 예시를 한 가지 근거로 삼았다.