@@ -1,8 +1,8 @@
# BLE Protocol Reference — VBT Device
# BLE Protocol Reference — VBT Device
VesiScan Basic Android 앱이 VBT 디바이스(VBTFW0116 + 펌웨어)와 주고받는 BLE 명령/응답 전체 정리. 코드 위치는 모두 `app/src/main/java/com/example/medilightv2android /ble/` 기준.
VesiScan Basic Android 앱이 VBT 디바이스(VBTFW0120 + 펌웨어)와 주고받는 BLE 명령/응답 전체 정리. 코드 위치는 모두 `app/src/main/java/com/medithings/vesiscan /ble/` 기준.
작성일 / 검증 FW: 2026-06-05 / **VBTFW0116 ** (reb 신구조 적용 )
작성일 / 검증 FW: 2026-07-13 / **VBTFW0120+ ** (mim FIFO + mtb queue overrun 3-layer guard 반영 )
---
---
@@ -48,7 +48,7 @@ VesiScan Basic Android 앱이 VBT 디바이스(VBTFW0116+ 펌웨어)와 주고
## 2. BLE 연결 Lifecycle
## 2. BLE 연결 Lifecycle
### 2.1 UUID (Nordic UART Service)
### 2.1 UUID (Nordic UART Service)
파일: [`BleManager.kt:45-48` ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L45 )
파일: [`BleManager.kt:45-48` ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L45 )
| 역할 | UUID |
| 역할 | UUID |
|---|---|
|---|---|
@@ -88,7 +88,7 @@ VesiScan Basic Android 앱이 VBT 디바이스(VBTFW0116+ 펌웨어)와 주고
- 두 협상 모두 디스커버리 + CCCD 활성화 이후에 진행. 너무 일찍 호출하면 reject.
- 두 협상 모두 디스커버리 + CCCD 활성화 이후에 진행. 너무 일찍 호출하면 reject.
### 2.4 자동 재연결 (silent)
### 2.4 자동 재연결 (silent)
파일: [`BleManager.kt:601` scheduleAutoReconnect ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L601 )
파일: [`BleManager.kt:601` scheduleAutoReconnect ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L601 )
- 의도하지 않은 disconnect → `scheduleAutoReconnect()` 자동 호출
- 의도하지 않은 disconnect → `scheduleAutoReconnect()` 자동 호출
- 마지막 연결 디바이스 주소를 `SharedPreferences` 에 저장 → scan + reconnect 시도
- 마지막 연결 디바이스 주소를 `SharedPreferences` 에 저장 → scan + reconnect 시도
@@ -144,7 +144,7 @@ val isMtbBusy: Boolean
## 3. 명령 빌더 — CRC16-CCITT
## 3. 명령 빌더 — CRC16-CCITT
파일: [`CRC16.kt` ](../app/src/main/java/com/example/medilightv2android /ble/CRC16.kt )
파일: [`CRC16.kt` ](../app/src/main/java/com/medithings/vesiscan /ble/CRC16.kt )
```
```
Polynomial: 0x1021
Polynomial: 0x1021
@@ -189,26 +189,26 @@ fun verify(data: ByteArray): Boolean
| 명령 | 빌더 | Send 함수 | 응답 prefix | 용도 |
| 명령 | 빌더 | Send 함수 | 응답 prefix | 용도 |
|---|---|---|---|---|
|---|---|---|---|---|
| `msr?` | ASCII " " | `disconnectAndUnbond()` 내부 ([L276 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L276 )) | — | 본딩 wipe + reboot |
| `msr?` | ASCII " " | `disconnectAndUnbond()` 내부 ([L276 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L276 )) | — | 본딩 wipe + reboot |
| `mpa?` | BE [freq, cycles] | `sendPiezoPowerOn(freq=2, cycles=5)` ([L404 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L404 )) | `rpa:` | Piezo power ON |
| `mpa?` | BE [freq, cycles] | `sendPiezoPowerOn(freq=2, cycles=5)` ([L404 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L404 )) | `rpa:` | Piezo power ON |
| `mps?` | ASCII " " | `sendPiezoStop()` ([L408 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L408 )) | — | Piezo stop |
| `mps?` | ASCII " " | `sendPiezoStop()` ([L408 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L408 )) | — | Piezo stop |
| `mec?` | BE [freq, delay, 140, cycles, 1, ch] | `sendBurst(...)` ([L412 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L412 )) | `reb:` 단일 채널 | Single-channel burst |
| `mec?` | BE [freq, delay, 140, cycles, 1, ch] | `sendBurst(...)` ([L412 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L412 )) | `reb:` 단일 채널 | Single-channel burst |
| `maa?` | ASCII " " | `sendAllChannels()` / `sendChannelsOnly()` ([L416, L513 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L416 )) | reb× 6 + raa | 6채널 sweep (도넛/placement) |
| `maa?` | ASCII " " | `sendAllChannels()` / `sendChannelsOnly()` ([L416, L513 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L416 )) | reb× 6 + raa | 6채널 sweep (도넛/placement) |
| `mtb?` | ASCII " " | `sendMtb()` ([L430 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L430 )) | reb× 6 + raa + **rim ** | 6채널 + IMU (★ Clinical) |
| `mtb?` | ASCII " " | `sendMtb()` ([L430 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L430 )) | reb× 6 + raa + **rim ** | 6채널 + IMU (★ Clinical) |
| `mbb?` | ASCII " " | `sendFullMeasurement()` ([L480 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L480 )) | rbb + reb× 6 + raa | 측정 헤더(batt+temp+IMU) + 6채널 |
| `mbb?` | ASCII " " | `sendFullMeasurement()` ([L480 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L480 )) | rbb + reb× 6 + raa | 측정 헤더(batt+temp+IMU) + 6채널 |
| `mta?` | BE [0 or 1] | `sendNirsPowerOn()/Off()` ([L441/445 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L441 )) | `rta:` | NIRS power |
| `mta?` | BE [0 or 1] | `sendNirsPowerOn()/Off()` ([L441/445 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L441 )) | `rta:` | NIRS power |
| `mqq?` | ASCII " " | `sendMqqQuery()` ([L449 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L449 )) | `rqq:` | NIRS sensor activate |
| `mqq?` | ASCII " " | `sendMqqQuery()` ([L449 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L449 )) | `rqq:` | NIRS sensor activate |
| `mag?` | ASCII " " | `sendMagQuery()` ([L453 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L453 )) | `rag:` | NIRS gain calibration |
| `mag?` | ASCII " " | `sendMagQuery()` ([L453 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L453 )) | `rag:` | NIRS gain calibration |
| `mcj?` | ASCII " " | `sendMcjQuery()` ([L457 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L457 )) | `rcj:` | NIRS MCJ raw |
| `mcj?` | ASCII " " | `sendMcjQuery()` ([L457 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L457 )) | `rcj:` | NIRS MCJ raw |
| `msn?` | BE [0] | `sendBatteryQuery()` ([L463 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L463 )) | `rsn:` | 배터리 mV 조회 |
| `msn?` | BE [0] | `sendBatteryQuery()` ([L463 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L463 )) | `rsn:` | 배터리 mV 조회 |
| `mid?` | ASCII " " | `sendDeviceInfoQuery()` ([L467 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L467 )) | `rid:` | FW/HW/Serial 조회 |
| `mid?` | ASCII " " | `sendDeviceInfoQuery()` ([L467 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L467 )) | `rid:` | FW/HW/Serial 조회 |
| `mls?` | BE [state] | `sendLedMode(state)` ([L471 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L471 )) | `rls:` | LED 모드 변경 |
| `mls?` | BE [state] | `sendLedMode(state)` ([L471 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L471 )) | `rls:` | LED 모드 변경 |
| ~~`msp?`~~ | ~~ASCII " "~~ | ~~`sendImuQuery()`~~ | `rsp:` | ⚠ **2026-07-08 완전 제거 ** — 신 firmware 는 `mim` 만 사용. `rsp:` 파서는 legacy 응답 대비 유지. |
| ~~`msp?`~~ | ~~ASCII " "~~ | ~~`sendImuQuery()`~~ | `rsp:` | ⚠ **2026-07-08 완전 제거 ** — 신 firmware 는 `mim` 만 사용. `rsp:` 파서는 legacy 응답 대비 유지. |
| `mim?` | ASCII " " | `sendImuFifoQuery()` | `rim:` (15 sample) | ★ IMU FIFO — piezo 무음, walking detector 시계열 확보용. `imuCollector.reset()` 을 먼저 호출하므로 mtb 진행 중 (isMtbBusy=true) 이면 caller 가 반드시 skip 해야 함 (mtb 의 rim 파괴 방지). |
| `mim?` | ASCII " " | `sendImuFifoQuery()` | `rim:` (15 sample) | ★ IMU FIFO — piezo 무음, walking detector 시계열 확보용. `imuCollector.reset()` 을 먼저 호출하므로 mtb 진행 중 (isMtbBusy=true) 이면 caller 가 반드시 skip 해야 함 (mtb 의 rim 파괴 방지). |
### 4.1 maa / mtb / maa 송신 throttle (canSendMaa)
### 4.1 maa / mtb / maa 송신 throttle (canSendMaa)
파일: [`BleManager.kt:494-509` ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L494 )
파일: [`BleManager.kt:494-509` ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L494 )
`maa?` , `mtb?` , `sendChannelsOnly()` 는 한 채널 그룹 응답이 280~420ms 소요되므로 다음 가드를 통과해야만 송신:
`maa?` , `mtb?` , `sendChannelsOnly()` 는 한 채널 그룹 응답이 280~420ms 소요되므로 다음 가드를 통과해야만 송신:
@@ -241,28 +241,28 @@ fun sendMtb(): Boolean {
`onCharacteristicChanged` → `processReceivedData(data)` → prefix 4글자 추출 → when 분기.
`onCharacteristicChanged` → `processReceivedData(data)` → prefix 4글자 추출 → when 분기.
파일: [`BleManager.kt:986-1097` ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L986 )
파일: [`BleManager.kt:986-1097` ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L986 )
| Prefix | 의미 | 패킷 길이 | 파싱 위치 | 콜백 |
| Prefix | 의미 | 패킷 길이 | 파싱 위치 | 콜백 |
|---|---|---|---|---|
|---|---|---|---|---|
| `rta:` `rta!` | NIRS power ON ack | — | [L991 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L991 ) | `onNirsPowerOnReceived` |
| `rta:` `rta!` | NIRS power ON ack | — | [L991 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L991 ) | `onNirsPowerOnReceived` |
| `rsh:` `rsh!` `rqq:` `rqq!` | Sensor activated | — | [L995 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L995 ) | `onNirsSensorActivated` |
| `rsh:` `rsh!` `rqq:` `rqq!` | Sensor activated | — | [L995 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L995 ) | `onNirsSensorActivated` |
| `rag:` `rag!` | NIRS gain calibration | data.size - 6 = N× 2 | [L999 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L999 ) | `onNirsMagReceived` |
| `rag:` `rag!` | NIRS gain calibration | data.size - 6 = N× 2 | [L999 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L999 ) | `onNirsMagReceived` |
| `rcj:` `rcj!` | NIRS MCJ raw | — | [L1003 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L1003 ) | `onNirsMcjReceived` |
| `rcj:` `rcj!` | NIRS MCJ raw | — | [L1003 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L1003 ) | `onNirsMcjReceived` |
| `rpa:` | Piezo ack | — | [L1007 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L1007 ) | `onPiezoDataReceived` |
| `rpa:` | Piezo ack | — | [L1007 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L1007 ) | `onPiezoDataReceived` |
| `rer:` | Preliminary header | — | [L1011 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L1011 ) | (로그만) |
| `rer:` | Preliminary header | — | [L1011 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L1011 ) | (로그만) |
| `reb:` | Piezo ADC raw (1채널) | **210B ** (신구조) | [L1014 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L1014 ) | `piezoCollector.addPacket` |
| `reb:` | Piezo ADC raw (1채널) | **210B ** (신구조) | [L1014 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L1014 ) | `piezoCollector.addPacket` |
| `red:` | Piezo continuation | — | [L1022 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L1022 ) | `piezoCollector.addPacket` |
| `red:` | Piezo continuation | — | [L1022 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L1022 ) | `piezoCollector.addPacket` |
| `ree:` | Single-ch end | 8B | [L1026 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L1026 ) | `piezoCollector.addPacket` |
| `ree:` | Single-ch end | 8B | [L1026 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L1026 ) | `piezoCollector.addPacket` |
| `raa:` | **All-ch complete ** marker | 8B | [L1026 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L1026 ) | `piezoCollector.addPacket` → set finalize |
| `raa:` | **All-ch complete ** marker | 8B | [L1026 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L1026 ) | `piezoCollector.addPacket` → set finalize |
| `rsn:` | Battery (mV) | ≥6B | [L1031 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L1031 ) | `batteryLevel.value` 갱신 |
| `rsn:` | Battery (mV) | ≥6B | [L1031 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L1031 ) | `batteryLevel.value` 갱신 |
| `rid:` | Device info (FW/HW/SN) | 가변 | [L1045 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L1045 ) | `firmwareVersion/...value` 갱신 |
| `rid:` | Device info (FW/HW/SN) | 가변 | [L1045 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L1045 ) | `firmwareVersion/...value` 갱신 |
| `rls:` | LED state | ≥5B | [L1067 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L1067 ) | (로그만) |
| `rls:` | LED state | ≥5B | [L1067 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L1067 ) | (로그만) |
| `rxs:` | Cmd not supported (echo) | 가변 | [L1071 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L1071 ) | (로그만) |
| `rxs:` | Cmd not supported (echo) | 가변 | [L1071 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L1071 ) | (로그만) |
| `rbb:` | Full measurement header | 22B | [L1075 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L1075 ) | `onMbbHeaderReceived` + collector |
| `rbb:` | Full measurement header | 22B | [L1075 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L1075 ) | `onMbbHeaderReceived` + collector |
| `rsp:` | IMU 단일 샘플 | ≥16B | [L1080 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L1080 ) | `onImuReceived` |
| `rsp:` | IMU 단일 샘플 | ≥16B | [L1080 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L1080 ) | `onImuReceived` |
| `rim:` | **IMU 15 samples ** | 188B | [L1086 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L1086 ) | `imuCollector.parseRim` |
| `rim:` | **IMU 15 samples ** | 188B | [L1086 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L1086 ) | `imuCollector.parseRim` |
| `???` | Unknown | — | [L1091 ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L1091 ) | hex 로그 + warn |
| `???` | Unknown | — | [L1091 ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L1091 ) | hex 로그 + warn |
⚠️ prefix 매칭은 * * `String(data, 0, 4, US_ASCII)` ** 로 정확히 4글자 (`"reb:"` 처럼 colon 포함).
⚠️ prefix 매칭은 * * `String(data, 0, 4, US_ASCII)` ** 로 정확히 4글자 (`"reb:"` 처럼 colon 포함).
@@ -270,7 +270,7 @@ fun sendMtb(): Boolean {
## 6. Piezo 응답 상세 (reb / red / ree / raa)
## 6. Piezo 응답 상세 (reb / red / ree / raa)
파일: [`PiezoPacketCollector.kt` ](../app/src/main/java/com/example/medilightv2android /ble/PiezoPacketCollector.kt )
파일: [`PiezoPacketCollector.kt` ](../app/src/main/java/com/medithings/vesiscan /ble/PiezoPacketCollector.kt )
### 6.1 reb 신구조 (210B, FW 2026-06-02+)
### 6.1 reb 신구조 (210B, FW 2026-06-02+)
@@ -332,7 +332,7 @@ state: 펌웨어 상태 코드. 현재 클라이언트는 사용 안 함 — 마
## 7. IMU 응답 상세 (rim)
## 7. IMU 응답 상세 (rim)
파일: [`ImuPacketCollector.kt` ](../app/src/main/java/com/example/medilightv2android /ble/ImuPacketCollector.kt )
파일: [`ImuPacketCollector.kt` ](../app/src/main/java/com/medithings/vesiscan /ble/ImuPacketCollector.kt )
### 7.1 패킷 구조 (188B)
### 7.1 패킷 구조 (188B)
```
```
@@ -380,7 +380,7 @@ if (payloadBytes < expectedBytes) {
## 8. 디바이스 정보 (rid)
## 8. 디바이스 정보 (rid)
파일: [`BleManager.kt:1045-1066` ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L1045 )
파일: [`BleManager.kt:1045-1066` ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L1045 )
### 8.1 패킷 구조
### 8.1 패킷 구조
```
```
@@ -412,7 +412,7 @@ val sn = parts.firstOrNull { it.startsWith("VBT") && !it.startsWith("VBTHW") &&
## 9. 배터리 (rsn)
## 9. 배터리 (rsn)
파일: [`BleManager.kt:1031-1043` ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L1031 )
파일: [`BleManager.kt:1031-1043` ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L1031 )
### 9.1 패킷 구조
### 9.1 패킷 구조
```
```
@@ -442,7 +442,7 @@ if (pct <= batteryLevel.value || batteryLevel.value == 0) {
- ⚠️ 충전 중 상승은 반영 안 됨 — 의도된 동작
- ⚠️ 충전 중 상승은 반영 안 됨 — 의도된 동작
### 9.4 Polling 정책 (★ 2026-06-05 변경)
### 9.4 Polling 정책 (★ 2026-06-05 변경)
파일: [`BleManager.kt:517-565` ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L517 )
파일: [`BleManager.kt:517-565` ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L517 )
```
```
1. 연결 직후 즉시 1회 msn? 송신
1. 연결 직후 즉시 1회 msn? 송신
@@ -456,7 +456,7 @@ if (pct <= batteryLevel.value || batteryLevel.value == 0) {
## 10. 측정 헤더 (rbb)
## 10. 측정 헤더 (rbb)
파일: [`BleManager.kt:1075-1078` ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L1075 )
파일: [`BleManager.kt:1075-1078` ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L1075 )
```
```
[tag 4B "rbb:"][batt 2B][IMU 2B][temp 2B][crc 2B] = 22B
[tag 4B "rbb:"][batt 2B][IMU 2B][temp 2B][crc 2B] = 22B
@@ -485,7 +485,7 @@ if (pct <= batteryLevel.value || batteryLevel.value == 0) {
`!` 변형은 펌웨어 측 에러/특수 상태. 처리 자체는 `:` 와 동일하지만 디버그 로그에 prefix 그대로 기록.
`!` 변형은 펌웨어 측 에러/특수 상태. 처리 자체는 `:` 와 동일하지만 디버그 로그에 prefix 그대로 기록.
NIRS 자세한 파싱은 [`NirsManager` ](../app/src/main/java/com/example/medilightv2android /managers/NirsManager.kt ) 참고 (Vivamyo 화면 전용).
NIRS 자세한 파싱은 [`NirsManager` ](../app/src/main/java/com/medithings/vesiscan /managers/NirsManager.kt ) 참고 (Vivamyo 화면 전용).
---
---
@@ -495,7 +495,7 @@ NIRS 자세한 파싱은 [`NirsManager`](../app/src/main/java/com/example/medili
표준 GATT 연결만으로 끝. 별도 페어링 명령 없음. CCCD enable 완료 시 service ready.
표준 GATT 연결만으로 끝. 별도 페어링 명령 없음. CCCD enable 완료 시 service ready.
### 12.2 Unpair (`disconnectAndUnbond()` )
### 12.2 Unpair (`disconnectAndUnbond()` )
파일: [`BleManager.kt:262-310` ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt#L262 )
파일: [`BleManager.kt:262-310` ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt#L262 )
```
```
1. isUserDisconnect = true ← auto-reconnect 차단 flag
1. isUserDisconnect = true ← auto-reconnect 차단 flag
@@ -540,7 +540,7 @@ NIRS 자세한 파싱은 [`NirsManager`](../app/src/main/java/com/example/medili
- `ImuCollector` — rim sample count
- `ImuCollector` — rim sample count
### 14.2 ble.log (텍스트 디버그 로그)
### 14.2 ble.log (텍스트 디버그 로그)
파일: [`BleDebugLogger.kt` ](../app/src/main/java/com/example/medilightv2android /services/BleDebugLogger.kt )
파일: [`BleDebugLogger.kt` ](../app/src/main/java/com/medithings/vesiscan /services/BleDebugLogger.kt )
각 세션 폴더에 `ble.log` 자동 작성:
각 세션 폴더에 `ble.log` 자동 작성:
```
```
@@ -610,10 +610,10 @@ T+600 App delay(600 - 290 = 310ms) 끝 → 다시 sendMtb()
---
---
**원본 소스**: `app/src/main/java/com/example/medilightv2android /ble/`
**원본 소스**: `app/src/main/java/com/medithings/vesiscan /ble/`
- [`BleManager.kt` ](../app/src/main/java/com/example/medilightv2android /ble/BleManager.kt )
- [`BleManager.kt` ](../app/src/main/java/com/medithings/vesiscan /ble/BleManager.kt )
- [`CRC16.kt` ](../app/src/main/java/com/example/medilightv2android /ble/CRC16.kt )
- [`CRC16.kt` ](../app/src/main/java/com/medithings/vesiscan /ble/CRC16.kt )
- [`PiezoPacketCollector.kt` ](../app/src/main/java/com/example/medilightv2android /ble/PiezoPacketCollector.kt )
- [`PiezoPacketCollector.kt` ](../app/src/main/java/com/medithings/vesiscan /ble/PiezoPacketCollector.kt )
- [`ImuPacketCollector.kt` ](../app/src/main/java/com/example/medilightv2android /ble/ImuPacketCollector.kt )
- [`ImuPacketCollector.kt` ](../app/src/main/java/com/medithings/vesiscan /ble/ImuPacketCollector.kt )
**관련 문서**: [iOS Porting Clinical Measurement ](iOS_PORTING_CLINICAL_MEASUREMENT.md ), [labdb.md ](../labdb.md )
**관련 문서**: [iOS Porting Clinical Measurement ](iOS_PORTING_CLINICAL_MEASUREMENT.md ), [labdb.md ](../labdb.md )