안드로이드

[Android] 블루투스(Bluetooth) Gatt 개발 순서

코딩하는후운 2022. 10. 24. 09:01
반응형

안드로이드 블루투스(Bluetooth) Gatt 개발 순서

1.oncreate에서 ACTION_BOND_STATE_CHANGED, ACTION_STATE_CHANGED
Broadcast리시버 등록
2. 권한 체크
3. bluetooth scan
4. bluetooth connect
-기존 연결 되어있으면 끊고 연결

BleManager.getInstance.apply{
	connect
}


uuid는
Service, notify, write UUID
성공: 
(1)연결된 device 저장
(2)Service
(3)characteristics
(4)Notify연결
(5)write연결

gatt?.run{
    this.service
        .filter{
        	it.uuid.toString() == serviceUuid
        }
        .map{
        	it.characteristics
        }
        .map{
            //Notify연결
            it
           		.filter{(it.properties and BluetoothGattCharacteristic.PROPERTY_NOTIFY)>0}
            	.filter{it.uuid.toString() == notifyUuid}
                .map{
                    BlaManager.getInstance().apply{
                        notify(..., callback{
                            onNotifySuccess()
                            onNotifyFailure()
                            onCharacteristicChanged(){
                            }
                        }
                    }
                }
        }
        .map{
            //Write 연결
            it
                .filter{
                	(it.properties and BluetoothGattCharacteristic.PROPERTY_WRITE_NORESPONSE)>0
                }
                .filter{
                	it.uuid.toString() == writeUuid
                }
                .map{ writeGattCharacteristic = it}
    }
}
it.onConnectSuccess




5. Bluetooth disconnect

bleDevice?.let{
    BleManager.getInstance().apply{
        if(isConnected(it)){
            disconnect(it)
            connectedBleDevice = null
            ioCallback = null
        }
    }
}



6. Bluetooth Gatt Read

notifyPublishSource
	.timeout(7, TimeUnit.SECONDS)
	.map{
		HexUtils.bytesToHexString(it)
	}
	.scan{ t1: String, t2: String ->
		t1 + t2		
	}
	.map{
		HexUtils.fromHex(it)
	}
	.subscribe(
		{it ->
			var isTail = false
			if(it.size % 20 == 0){
				for( it in 0 until it.size step 20){
					//Tail인지 확인 || ACK인지 확인 || 16frame이상인지 확인
					if(it[i] and 0x10.toByte() == x0x10.toByte() ||
					it[i] and 0x80.toByte() == 0x80.toByte() ||
					it.[i+1] and 0xF0.toByte() == it[i+1]){
						isTail = true
						break
					}
				}
			}
			
			if(isTail){
				readDisposable.clear()
				callback.onReadFromNotify(it)
			}
		},
		{
			if(it is TimeoutException){
				if(retryTimeOutCnt < 1){
					retyTimeOutCnt++
					writeDataFrame?.let{
						readDisposable.clear()
						writeToBle(true)
					}
				}else{
					callback.onReadFailure(TimeoutException())
				}
			}
		},
		{
			log.d(complete)
		}
	)
	.also{
		readDisposable.add(it)
	}


7. Bluetooth Gatt Write

Observable.fromIterable(writeDataFrame)
	.subscribeOn(Schedulers.io())
	.observeOn(Schedulers.io())
	.map{
		if(!isConnected()){
			readDisposable.clear()
			throw BleConnectionException()
		}
		it		
	}
	.map{ t->
		writeGattCharacteristic?.let{
			BleManager.getInstance().apply{
				write(
					connectedBleDevice!!,
					it.service.uuid.toString(),
					it.uuid.toString(),
					t,
					object: BleWriteCallback(){
						override fun onWriteSuccess(...){
							retryWriteCnt = 0
							ioCallback?.let{
								//write call 사이에 카드에서 다른 응답이 오면
								//readDisposable이 clear되어 ui단으로
								//response 값을 줄 수 없다.
								//하여 readDisposable에 값이 없는 경우는 다른 req에 대한 response 처리 했다고 판단하고 재 생성 한다.
								if(readDisposable.size() <= 0){
									readFromBle()
								}
								it.onWriteSuccess(...)
							}
						}
						override fun onWriteFailure(..){
						}
					}
				)					
			}
		}
	}
	.retry{ _, e ->
		//retryCnt: 재시도 욋수, e: Exception type
		//write()에서 실패 난 경우 진입. 만약 성공하면 subscribe로 바로 이동한다.
		
		//실패 후 3초 지연 시간 후 재시도 하기 위함
		Thread.sleep(3000)
		
		//재시도 횟수는 2회로 정한다. true이면 subscribe가 재 호출 된다. false이면 onErrorReturn이 호출된다.
		retyWriteCnt++
		return@rety retryWriteCnt < 2		
	}
	.onErrorReturn{ e ->
		//retry 에서 false로 리턴 되면 실행됨.
		return@onErrorReturn -1	
	}
	.subscribe(
		{ t ->
			if(t<0){
				ioCallback?.let{
					if(retryWriteCnt >= 2){	//write 2회 실패하면 read쪽에 대해 종료처리
						readDisposable.clear()
					}
					it.onWriteFailure()
				}
			}
		},
		{t->
			ioCallback?.let{
				it.onWriteFailure()
			}
		},
		{
			log.d("complete")
		}
	)
	.also{ compositeDisposable.add(it)}




반응형