From f601964083e38ff01a82bca9b360b3ec21fcb16a Mon Sep 17 00:00:00 2001 From: dj99k Date: Tue, 4 Aug 2026 22:13:35 +0900 Subject: [PATCH] =?UTF-8?q?first=20Commit=201.=20BLE=EC=9E=85=EB=A0=A5?= =?UTF-8?q?=EB=90=98=EB=8A=94=20=EB=A9=94=EC=84=B8=EC=A7=80=EB=8A=94=20\r\?= =?UTF-8?q?n=20=20=EC=97=86=EC=9D=8C.=20-=20=EA=B4=80=EB=A0=A8=20=ED=95=AD?= =?UTF-8?q?=EB=AA=A9=20=EC=82=AD=EC=A0=9C=20=20=20=20=20-.=20=EA=B5=AD?= =?UTF-8?q?=EB=8F=84=EB=AA=A8=EB=8B=88=ED=84=B0=20BLE=EB=A1=9C=20=EB=B6=80?= =?UTF-8?q?=ED=84=B0=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=88=98=EC=8B=A0=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=20=EC=99=84=EB=A3=8C.=202.=20UI=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=203.=20=EA=B0=80=EB=B3=80=EC=B6=95=20=ED=95=98?= =?UTF-8?q?=EC=A4=91=20=EB=B6=84=EB=B0=B0=EC=9C=A8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bluetooth/BluetoothManager.kt | 62 +++++++------------ 1 file changed, 24 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/com/example/variableaxlemonitor/bluetooth/BluetoothManager.kt b/app/src/main/java/com/example/variableaxlemonitor/bluetooth/BluetoothManager.kt index fa66cd4..34661f7 100644 --- a/app/src/main/java/com/example/variableaxlemonitor/bluetooth/BluetoothManager.kt +++ b/app/src/main/java/com/example/variableaxlemonitor/bluetooth/BluetoothManager.kt @@ -52,7 +52,6 @@ class BluetoothManager(private val context: Context) { val foundDevices: StateFlow> = _foundDevices private var gatt: BluetoothGatt? = null - private val dataBuffer = StringBuilder() private val scanCallback = object : ScanCallback() { @SuppressLint("MissingPermission") @@ -154,12 +153,30 @@ class BluetoothManager(private val context: Context) { processReceivedData(characteristic.value) } + + //1. 역할: "구독 승인 확인" + //BLE 기기(ESP32-C3)로부터 데이터를 자동으로 받으려면(Notification), 단순히 앱에서 "받겠다"고 설정하는 것뿐만 아니라, + // **기기 내부의 스위치(Descriptor)**를 켜줘야 합니다. + // onDescriptorWrite는 바로 그 스위치를 켜는 작업이 성공했는지 결과를 알려주는 시점입니다. + //2. 동작 흐름 (Flow) + // 1.서비스 발견: 기기의 기능을 찾습니다. (onServicesDiscovered) + //2.특성 알림 설정: 앱 내부적으로 알림을 받을 준비를 합니다. (setCharacteristicNotification) + //3.디스크립터 쓰기: 기기에게 "이제 데이터를 보내줘"라고 명령을 보냅니다. (writeDescriptor) + //4.결과 수신 (onDescriptorWrite): 기기가 명령을 잘 받았는지 확인합니다. (현재 코드 부분) + //5.데이터 수신: 이때부터 실제 데이터가 들어옵니다. (onCharacteristicChanged) + override fun onDescriptorWrite(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int) { + // 1. 로그 기록: 어떤 결과(status)로 어떤 항목(descriptor)에 쓰기가 완료되었는지 남깁니다. Log.d(TAG, "onDescriptorWrite: status=$status, descriptor=${descriptor.uuid}") + // 2. 성공 여부 판단: status가 0(GATT_SUCCESS)이면 성공입니다. if (status == BluetoothGatt.GATT_SUCCESS) { + // 성공 시: 사용자가 볼 수 있게 상태 메시지를 업데이트합니다. + // 이제부터 기기가 데이터를 보내기 시작할 준비가 완벽히 끝났음을 의미합니다. _lastMessage.value = "통신 준비 완료. 데이터 수신 대기 중..." } else { - _lastMessage.value = "구독 설정 실패 (status=$status)" + // 실패 시: 에러 코드와 함께 실패 메시지를 띄웁니다. + // 이 경우 기기가 데이터를 보내지 않으므로 원인을 파악해야 합니다. + _lastMessage.value = "데이터 수신 실패 (status=$status)" } } } @@ -167,42 +184,11 @@ class BluetoothManager(private val context: Context) { private fun processReceivedData(value: ByteArray?) { if (value == null) return - val received = String(value) - // Log.d(TAG, "Raw Data (String): $received") - - synchronized(dataBuffer) { - dataBuffer.append(received) - - // Check for various delimiters including literal strings like "\r\n" or "\r\" - val delimiters = listOf("\r\n", "\\r\\n", "\\r\\", "\n", "\r") - - var foundDelimiter = true - while (foundDelimiter) { - foundDelimiter = false - var earliestIndex = Int.MAX_VALUE - var selectedDelimiter = "" - - for (delim in delimiters) { - val index = dataBuffer.indexOf(delim) - if (index != -1 && index < earliestIndex) { - earliestIndex = index - selectedDelimiter = delim - foundDelimiter = true - } - } - - if (foundDelimiter) { - val line = dataBuffer.substring(0, earliestIndex).trim() - dataBuffer.delete(0, earliestIndex + selectedDelimiter.length) - - if (line.isNotEmpty()) { - Log.d(TAG, "Extracted line: '$line'") - // _lastMessage.value = "데이터 수집 중: $line" - scope.launch { - parseData(line) - } - } - } + val received = String(value).trim() + if (received.isNotEmpty()) { + Log.d(TAG, "Extracted line: '$received'") + scope.launch { + parseData(received) } } }