質問編集履歴
2
パケットキャプチャ内容とソースコード、実行結果を追加した。
title
CHANGED
File without changes
|
body
CHANGED
@@ -1,10 +1,237 @@
|
|
1
1
|
Bluetooth Low Energyを用いてプログラムを開発しています。
|
2
|
-
送信側にてキャラクタリスティックを更新し、更新通知が受信側に届いていることをパケットキャプチャで確認しました。
|
2
|
+
送信側にて64msec周期でキャラクタリスティックを更新し、更新通知が受信側に届いていることをパケットキャプチャ(nRF51 dongle + Wireshark)で確認しました。
|
3
|
+
※受信間隔にバラツキはありますが、概ね64msec周期で受信できています。
|
4
|
+
```
|
5
|
+
2501 112.789743 Slave_0x283eb820 Master_0x283eb820 ATT 53 Rcvd Handle Value Notification, Handle: 0x0019 (Unknown)
|
6
|
+
2503 112.898854 Slave_0x283eb820 Master_0x283eb820 ATT 53 Rcvd Handle Value Notification, Handle: 0x0019 (Unknown)
|
7
|
+
2505 112.907883 Slave_0x283eb820 Master_0x283eb820 ATT 53 Rcvd Handle Value Notification, Handle: 0x0019 (Unknown)
|
8
|
+
2507 113.017212 Slave_0x283eb820 Master_0x283eb820 ATT 53 Rcvd Handle Value Notification, Handle: 0x0019 (Unknown)
|
9
|
+
2511 113.030233 Slave_0x283eb820 Master_0x283eb820 ATT 53 Rcvd Handle Value Notification, Handle: 0x0019 (Unknown)
|
10
|
+
2513 113.139254 Slave_0x283eb820 Master_0x283eb820 ATT 53 Rcvd Handle Value Notification, Handle: 0x0019 (Unknown)
|
11
|
+
2515 113.147382 Slave_0x283eb820 Master_0x283eb820 ATT 53 Rcvd Handle Value Notification, Handle: 0x0019 (Unknown)
|
12
|
+
2519 113.266009 Slave_0x283eb820 Master_0x283eb820 ATT 53 Rcvd Handle Value Notification, Handle: 0x0019 (Unknown)
|
13
|
+
2521 113.273321 Slave_0x283eb820 Master_0x283eb820 ATT 53 Rcvd Handle Value Notification, Handle: 0x0019 (Unknown)
|
14
|
+
2523 113.382328 Slave_0x283eb820 Master_0x283eb820 ATT 53 Rcvd Handle Value Notification, Handle: 0x0019 (Unknown)
|
15
|
+
```
|
16
|
+
|
3
17
|
気がかりな点として、1回の更新通知でonCharacteristicChanged()が複数回呼び出されています。
|
4
18
|
これは正常な動作(仕様)なのでしょうか?
|
5
19
|
もしくは、このような事象が発生したという方はいらっしゃいますでしょうか?
|
6
20
|
|
21
|
+
事象が発生した際のソースコードは以下の通りです。
|
22
|
+
※SERVICE_UUID、CHARACTERISTIC_UUIDは伏せ字にしてあります。
|
23
|
+
```Java
|
24
|
+
// import
|
25
|
+
import android.bluetooth.BluetoothAdapter;
|
26
|
+
import android.bluetooth.BluetoothDevice;
|
27
|
+
import android.bluetooth.BluetoothGatt;
|
28
|
+
import android.bluetooth.BluetoothGattCallback;
|
29
|
+
import android.bluetooth.BluetoothGattCharacteristic;
|
30
|
+
import android.bluetooth.BluetoothGattDescriptor;
|
31
|
+
import android.bluetooth.BluetoothGattService;
|
32
|
+
import android.bluetooth.BluetoothManager;
|
33
|
+
import android.bluetooth.BluetoothProfile;
|
34
|
+
import android.bluetooth.le.BluetoothLeScanner;
|
35
|
+
import android.bluetooth.le.ScanCallback;
|
36
|
+
import android.bluetooth.le.ScanResult;
|
37
|
+
import android.bluetooth.le.ScanFilter;
|
38
|
+
import android.bluetooth.le.ScanSettings;
|
39
|
+
|
40
|
+
import android.content.Context;
|
41
|
+
import android.os.ParcelUuid;
|
42
|
+
import android.support.v7.app.AppCompatActivity;
|
43
|
+
import android.os.Bundle;
|
44
|
+
import android.util.Log;
|
45
|
+
|
46
|
+
import java.util.ArrayList;
|
47
|
+
import java.util.Arrays;
|
48
|
+
import java.util.Locale;
|
49
|
+
import java.util.UUID;
|
50
|
+
|
51
|
+
import static android.bluetooth.BluetoothGatt.CONNECTION_PRIORITY_HIGH;
|
52
|
+
|
53
|
+
|
54
|
+
public class MainActivity extends AppCompatActivity {
|
55
|
+
// グローバル変数定義
|
56
|
+
private ArrayList mScanFilterList;
|
57
|
+
private ScanSettings mScanSettings;
|
58
|
+
private BluetoothLeScanner mBtLeScanner;
|
59
|
+
private BluetoothDevice mBtDevice;
|
60
|
+
private BluetoothGatt mBtGatt;
|
61
|
+
private BluetoothGattCharacteristic mBtGattCharacteristic;
|
62
|
+
private byte[] m_byReceiveData = new byte[20];
|
63
|
+
String strMsg;
|
64
|
+
long m_CntNG = 0;
|
65
|
+
long m_CntOK = 0;
|
66
|
+
|
67
|
+
// UUID定義
|
68
|
+
// 対象のサービスUUID.
|
69
|
+
private static final String SERVICE_UUID = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX1";
|
70
|
+
// キャラクタリスティックUUID.
|
71
|
+
private static final String CHARACTERISTIC_UUID = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX2";
|
72
|
+
// キャラクタリスティック設定UUID(固定値).
|
73
|
+
private static final String CHARACTERISTIC_UUID_CONFIG = "00002902-0000-1000-8000-00805f9b34fb";
|
74
|
+
|
75
|
+
// 初期処理
|
76
|
+
@Override
|
77
|
+
protected void onCreate(Bundle savedInstanceState) {
|
78
|
+
super.onCreate(savedInstanceState);
|
79
|
+
|
80
|
+
BluetoothManager btManager;
|
81
|
+
BluetoothAdapter btAdapter;
|
82
|
+
|
83
|
+
setContentView(R.layout.activity_main);
|
84
|
+
|
85
|
+
// 前回受信データの初期化
|
86
|
+
for(int i=0; i<m_byReceiveData.length; i++) {
|
87
|
+
m_byReceiveData[i] = 0x00;
|
88
|
+
}
|
89
|
+
|
90
|
+
btManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
|
91
|
+
btAdapter = btManager.getAdapter();
|
92
|
+
|
93
|
+
// フィルタを設定する。
|
94
|
+
ScanFilter scanFilter = new ScanFilter.Builder()
|
95
|
+
.setServiceUuid(ParcelUuid.fromString(SERVICE_UUID)).build();
|
96
|
+
mScanFilterList = new ArrayList();
|
97
|
+
mScanFilterList.add(scanFilter);
|
98
|
+
|
99
|
+
mScanSettings = new ScanSettings.Builder()
|
100
|
+
.setScanMode(ScanSettings.SCAN_MODE_BALANCED).build();
|
101
|
+
|
102
|
+
// スキャンを開始する。
|
103
|
+
mBtLeScanner = btAdapter.getBluetoothLeScanner();
|
104
|
+
mBtLeScanner.startScan(mScanFilterList, mScanSettings, mScanCallback);
|
105
|
+
}
|
106
|
+
|
107
|
+
// スキャン結果コールバック関数
|
108
|
+
private final ScanCallback mScanCallback = new ScanCallback() {
|
109
|
+
// スキャン結果通知処理
|
110
|
+
@Override
|
111
|
+
public void onScanResult(int callbackType, ScanResult result) {
|
112
|
+
super.onScanResult(callbackType, result);
|
113
|
+
|
114
|
+
// デバイスを発見した
|
115
|
+
if((null != result) && (null != result.getDevice())) {
|
116
|
+
mBtDevice = result.getDevice();
|
117
|
+
|
118
|
+
// デバイスに接続する。
|
119
|
+
mBtGatt = mBtDevice.connectGatt(getApplicationContext(), false, mGattCallback);
|
120
|
+
}
|
121
|
+
}
|
122
|
+
};
|
123
|
+
|
124
|
+
// GATTコールバック関数
|
125
|
+
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback(){
|
126
|
+
// 接続状態変化検出処理
|
127
|
+
@Override
|
128
|
+
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState){
|
129
|
+
// 接続状況が変化したら実行.
|
130
|
+
if(newState == BluetoothProfile.STATE_CONNECTED) {
|
131
|
+
// 接続に成功したらサービスを検索する.
|
132
|
+
gatt.discoverServices();
|
133
|
+
} else if(newState == BluetoothProfile.STATE_DISCONNECTED) {
|
134
|
+
// 接続が切れたらGATTを空にする.
|
135
|
+
if(mBtGatt != null){
|
136
|
+
mBtGatt.close();
|
137
|
+
mBtGatt = null;
|
138
|
+
}
|
139
|
+
|
140
|
+
// スキャンを再開する。
|
141
|
+
mBtLeScanner.startScan(mScanFilterList, mScanSettings, mScanCallback);
|
142
|
+
}
|
143
|
+
}
|
144
|
+
|
145
|
+
// サービス検出処理
|
146
|
+
@Override
|
147
|
+
public void onServicesDiscovered(BluetoothGatt gatt, int status){
|
148
|
+
BluetoothGattService bleService;
|
149
|
+
boolean bRet;
|
150
|
+
BluetoothGattDescriptor bleDescriptor;
|
151
|
+
|
152
|
+
// Serviceが見つかったら実行.
|
153
|
+
if(status == BluetoothGatt.GATT_SUCCESS) {
|
154
|
+
// UUIDが同じかどうかを確認する.
|
155
|
+
bleService = gatt.getService(UUID.fromString(SERVICE_UUID));
|
156
|
+
if(bleService != null){
|
157
|
+
// 指定したUUIDを持つCharacteristicを確認する.
|
158
|
+
mBtGattCharacteristic = bleService.getCharacteristic(UUID.fromString(CHARACTERISTIC_UUID));
|
159
|
+
if(mBtGattCharacteristic != null) {
|
160
|
+
// Service, CharacteristicのUUIDが同じならBluetoothGattを更新する.
|
161
|
+
mBtGatt = gatt;
|
162
|
+
|
163
|
+
// Notifyを高速で受け取るための要求
|
164
|
+
mBtGatt.requestConnectionPriority(CONNECTION_PRIORITY_HIGH);
|
165
|
+
|
166
|
+
// キャラクタリスティックが見つかったら、Notificationをリクエスト.
|
167
|
+
bRet = mBtGatt.setCharacteristicNotification(mBtGattCharacteristic, true);
|
168
|
+
|
169
|
+
if(true == bRet) {
|
170
|
+
// Characteristic の Notificationを有効化する.
|
171
|
+
bleDescriptor = mBtGattCharacteristic.getDescriptor(UUID.fromString(CHARACTERISTIC_UUID_CONFIG));
|
172
|
+
if(null != bleDescriptor) {
|
173
|
+
bleDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
|
174
|
+
mBtGatt.writeDescriptor(bleDescriptor);
|
175
|
+
}
|
176
|
+
|
177
|
+
// scan 終了
|
178
|
+
mBtLeScanner.stopScan(mScanCallback);
|
179
|
+
}
|
180
|
+
}
|
181
|
+
}
|
182
|
+
}
|
183
|
+
}
|
184
|
+
|
185
|
+
// 更新通知受信処理
|
186
|
+
@Override
|
187
|
+
public synchronized void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic){
|
188
|
+
super.onCharacteristicChanged(gatt, characteristic);
|
189
|
+
|
190
|
+
byte byReceiveData[];
|
191
|
+
|
192
|
+
// キャラクタリスティックのUUIDをチェック(getUuidの結果が全て小文字で帰ってくるのでUpperCaseに変換)
|
193
|
+
if(CHARACTERISTIC_UUID.equals(characteristic.getUuid().toString().toUpperCase())){
|
194
|
+
// characteristicを取得する。
|
195
|
+
byReceiveData = characteristic.getValue();
|
196
|
+
|
197
|
+
// データ長が異なる場合は処理をスキップする。
|
198
|
+
if(byReceiveData.length != m_byReceiveData.length) {
|
199
|
+
strMsg = String.format(Locale.US, "***** Length (%d:%d) *****", byReceiveData.length, m_byReceiveData.length);
|
200
|
+
Log.e("TAG", strMsg);
|
201
|
+
return;
|
202
|
+
}
|
203
|
+
|
204
|
+
// 前回と同一データの場合は処理スキップする。
|
205
|
+
if(Arrays.equals(byReceiveData, m_byReceiveData)) {
|
206
|
+
m_CntNG++;
|
207
|
+
strMsg = String.format("xxx Receive NG(%d)", m_CntNG);
|
208
|
+
Log.e("TAG", strMsg);
|
209
|
+
return;
|
210
|
+
}
|
211
|
+
else {
|
212
|
+
m_CntOK++;
|
213
|
+
strMsg = String.format("ooo Receive OK(%d)", m_CntOK);
|
214
|
+
Log.e("TAG", strMsg);
|
215
|
+
System.arraycopy(byReceiveData, 0, m_byReceiveData, 0, m_byReceiveData.length);
|
216
|
+
}
|
217
|
+
}
|
218
|
+
}
|
219
|
+
};
|
220
|
+
}
|
221
|
+
```
|
222
|
+
実行結果は以下のように出力されています。
|
223
|
+
08-10 14:34:38.108 E: ooo Receive OK(1)
|
224
|
+
08-10 14:34:38.108 E: xxx Receive NG(1)
|
225
|
+
08-10 14:34:38.109 E: ooo Receive OK(2)
|
226
|
+
08-10 14:34:38.110 E: xxx Receive NG(2)
|
227
|
+
08-10 14:34:38.156 E: ooo Receive OK(3)
|
228
|
+
08-10 14:34:38.157 E: xxx Receive NG(3)
|
229
|
+
08-10 14:34:38.258 E: ooo Receive OK(4)
|
230
|
+
08-10 14:34:38.259 E: xxx Receive NG(4)
|
231
|
+
08-10 14:34:38.316 E: ooo Receive OK(5)
|
232
|
+
08-10 14:34:38.317 E: xxx Receive NG(5)
|
233
|
+
|
7
|
-
送信
|
234
|
+
送信する更新通知は20byteです。
|
8
235
|
送信側、受信側共にAndroid(7.0)、Bluetooth V4.2です。
|
9
236
|
開発環境はAndroidStudio(3.0.1)です。
|
10
237
|
|
1
コメントを追加した。
title
CHANGED
File without changes
|
body
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
送信側にてキャラクタリスティックを更新し、更新通知が受信側に届いていることをパケットキャプチャで確認しました。
|
3
3
|
気がかりな点として、1回の更新通知でonCharacteristicChanged()が複数回呼び出されています。
|
4
4
|
これは正常な動作(仕様)なのでしょうか?
|
5
|
+
もしくは、このような事象が発生したという方はいらっしゃいますでしょうか?
|
5
6
|
|
6
7
|
送信側からは64msec周期で更新通知(20bytes)を送信しています。
|
7
8
|
送信側、受信側共にAndroid(7.0)、Bluetooth V4.2です。
|