2017-06-16 13 views
0

アンドロイドと他のアームデバイスの間でBLE経由でデータを交換しようとしていますが、大きなデータがMTUの制限から小さなフラグメントに分割されました。ロバストネスのために、前のフレームが確認されたときに(によって)1つのフレームのみが送信される(writeCharacteristicによって)。ここで問題が発生します:アンドロイドデバイスが最後のフレームの送信を完了し、ピアデバイスからデータを受信すると(onCharacteristicChangedによって)、それはonCharacteristicChangedより後になります(少なくともログにはそれがあります)。BLE通信でonCharacteristicChanged()がonCharacteristicChanged()より遅くなる理由

@Override 
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { 
    if (status != BluetoothGatt.GATT_SUCCESS) { 
     stateProcessError();     // State = STATE_IDLE 
     return;        // Log.v("error occurs", "do something"); 
    } 
    Log.v("didsend", "State:" + State); 
    processEvent(sp_event.DATA_SEND_CFM, null); 
} 

@Override 
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { 
    Log.v("didrecv", "State:" + State); 
    Object msg = constructRxMsg(characteristic.getValue()); 
    processEvent(sp_event.DATA_RECV_CFM, msg); 
} 

private void stateSendAuthReq(sp_event event) { 
    switch (event) { 
     case DATA_IDLE: { 
      SPTxMsgAuthReq msg = new SPTxMsgAuthReq(Mode); 
      sendData(msg.getMsg()); 
     } 
      break; 
     case DATA_SEND_CFM: 
      State = sp_state.STATE_RECV_AUTH_RES; 
      Log.v("sendReq", "change State"); 
      break; 
     default: 
      Log.v("sendReq", "default"); 
      this.stateProcessError(); 
      break; 
    } 
} 

private void stateRecvAuthRes(sp_event event, SPRxMsgAuthRes msg) { 
    if (sp_event.DATA_RECV_CFM != event || null == msg) { 
     this.stateProcessError(); 
     return; 
    } 
    if (MSG_TYPE_AUTH_RES != msg.getType() || STATUS_AUTH_READY != msg.getStatus()) { 
     Log.v("recvAuthRes", "incorrect param"); 
     this.stateProcessError(); 
     return; 
    }     
    State = sp_state.STATE_RECV_NONCE; 
} 

private void processEvent(sp_event event, Object msg) { 
    switch (State) { 
     case STATE_IDLE: 
      this.stateSendAuthReq(event) 
      break; 
     case STATE_RECV_AUTH_RES: 
      this.stateRecvAuthRes(event, (SPRxMsgAuthRes) msg); 
      break; 
     ...... 
    } 
} 

ログは、このような問題を示しています

06-16 17:32:46.521 10300-10412/alps.ble.bt V/send: data:[-32, 3, 3, 1, 0] 
06-16 17:32:46.621 10300-10406/alps.ble.bt V/didrecv: State:STATE_IDEL 
06-16 17:32:46.621 10300-10406/alps.ble.bt V/constructRxMsg: data:[-31, 2, 3, 0] 
06-16 17:32:46.621 10300-10406/alps.ble.bt V/error occurs: do something 
06-16 17:32:46.621 10300-10406/alps.ble.bt V/didsend: State:STATE_IDLE 

そして、次のログが時にはエラーではありません:

06-16 16:30:05.871 22401-22502/alps.ble.bt V/send: data:[-32, 3, 3, 1, 0] 
06-16 16:30:05.911 22401-22471/alps.ble.bt D/BluetoothGatt: onClientConnParamsChanged() - Device=68:68:28:40:12:8E interval=39 status=0 
06-16 16:30:05.961 22401-22413/alps.ble.bt V/didsend: State:STATE_IDLE 
06-16 16:30:05.961 22401-22413/alps.ble.bt V/didrecv: State:STATE_RECV_AUTH_RES 
06-16 16:30:05.961 22401-22413/alps.ble.bt V/constructRxMsg: data:[-31, 2, 3, 0] 

注:すべてがOKだったので、ピアデバイス内のコードが正しいはずです私はアンドロイドの代わりにiOSでテストします。

十分な情報が提供されており、助力をいただければ幸いです。ありがとうございます!

+0

通知の前にペリフェラルが書き込み応答を送信したことは本当に確かですか?これを確認するには、BLEスニッファハードウェアを使用するか、HCIスヌープログを調べてAndroidで有効にしてからWiresharkを調べます。そしてその注文は本当にあなたのために重要ですか?いずれにしても動作するようにコードを書き直すことはできませんでしたか? – Emil

+0

はい、フロントラインBPA600を使用してこの問題をチェックしました。エアロログは注文が正しいことを示していました。私の意見では、私の使用や設定で何かが間違っていた可能性があります。私のコードにおける状態の変化は、これら2つの関数に依存しますが、この問題を避けるために書き直すことができます。とにかく私はそれを確認し、最後にあなたに感謝:) – shinyathena

答えて

0

多くの試行を経ても問題は解決していますが、バッファとフラグを使用するのを避けるために選択肢はありません。共有したいと思います。

private boolean isSending = false; 
private byte[] lastRecvData = null; 

private void sendData(byte[] data) { 
    Log.v("1", "Send data ..."); 
    mCharacteristic.setValue(data); 
    mBluetoothGatt.writeCharacteristic(mCharacteristic) 
    isSending = true; 
} 

@Override 
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { 
    isSending = false; 
    if (status != BluetoothGatt.GATT_SUCCESS) { 
     return; 
    } 
    Log.v("2", "Send data successfully"); 
    processEvent(sp_event.DATA_SEND_CFM, null); 

    if (lastRecvData != null) { 
     Object msg = constructRxMsg(lastRecvData); 
     processEvent(sp_event.DATA_RECV_CFM, msg); 
     lastRecvData = null; 
    } 
} 

@Override 
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { 
    if (isSending) { 
     lastRecvData = characteristic.getValue().clone(); 
    }else { 
     Log.v("3", "Recv data"); 
     Object msg = constructRxMsg(characteristic.getValue()); 
     processEvent(sp_event.DATA_RECV_CFM, msg); 
    } 
} 

ケースの再接続の場合は、バッファとフラグをクリアする必要があります。

public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { 
    if (newState == BluetoothProfile.STATE_CONNECTED) { 
     isSending = false; 
     lastRecvData = null; 
     ...... 

誰もがこの問題に対するより良いアイデアや解決策を持っていると大変感謝します。最後にありがとうございます。

関連する問題