xref: /btstack/platform/daemon/binding/java/example/com/bluekitchen/GATTClientTest.java (revision 6f3fd12d2666a6213f4b3282f2093a091e66963a)
1 package com.bluekitchen;
2 
3 import com.bluekitchen.btstack.BD_ADDR;
4 import com.bluekitchen.btstack.BT_UUID;
5 import com.bluekitchen.btstack.BTstack;
6 import com.bluekitchen.btstack.GATTCharacteristic;
7 import com.bluekitchen.btstack.GATTService;
8 import com.bluekitchen.btstack.Packet;
9 import com.bluekitchen.btstack.PacketHandler;
10 import com.bluekitchen.btstack.Util;
11 import com.bluekitchen.btstack.event.BTstackEventState;
12 import com.bluekitchen.btstack.event.GAPEventAdvertisingReport;
13 import com.bluekitchen.btstack.event.GATTEventCharacteristicQueryResult;
14 import com.bluekitchen.btstack.event.GATTEventCharacteristicValueQueryResult;
15 import com.bluekitchen.btstack.event.GATTEventNotification;
16 import com.bluekitchen.btstack.event.GATTEventQueryComplete;
17 import com.bluekitchen.btstack.event.GATTEventServiceQueryResult;
18 import com.bluekitchen.btstack.event.HCIEventDisconnectionComplete;
19 import com.bluekitchen.btstack.event.HCIEventLEConnectionComplete;
20 
21 public class GATTClientTest implements PacketHandler {
22 
23 	private enum STATE {
24 		w4_btstack_working, w4_scan_result, w4_connected, w4_services_complete, w4_characteristic_complete, w4_characteristic_read
25 	, w4_characteristic_write, w4_acc_service_result, w4_acc_enable_characteristic_result, w4_write_acc_enable_result, w4_acc_client_config_characteristic_result, w4_acc_client_config_result,
26 	w4_acc_data, w4_connected_acc, battery_data
27 	};
28 
29 	private BTstack btstack;
30 	private STATE state;
31 	private int testAddrType;
32 	private BD_ADDR testAddr;
33 	private int testHandle;
34 	private GATTService testService;
35 	private GATTCharacteristic testCharacteristic;
36 	private int service_count = 0;
37 	private int characteristic_count = 0;
38 	private int connectionHandle;
39 	private int counter = 0;
40 
41 	private byte[] acc_service_uuid =           new byte[] {(byte)0xf0, 0, (byte)0xaa, (byte)0x10, 4, (byte)0x51, (byte)0x40, 0, (byte)0xb0, 0, 0, 0, 0, 0, 0, 0};
42 	private byte[] acc_chr_client_config_uuid = new byte[] {(byte)0xf0, 0, (byte)0xaa, (byte)0x11, 4, (byte)0x51, (byte)0x40, 0, (byte)0xb0, 0, 0, 0, 0, 0, 0, 0};
43 	private byte[] acc_chr_enable_uuid =        new byte[] {(byte)0xf0, 0, (byte)0xaa, (byte)0x12, 4, (byte)0x51, (byte)0x40, 0, (byte)0xb0, 0, 0, 0, 0, 0, 0, 0};
44 	private byte[] acc_enable = new byte[] {1};
45 	private byte acc_notification = 1;
46 	private GATTService accService;
47 	private GATTCharacteristic enableCharacteristic;
48 	private GATTCharacteristic configCharacteristic;
49 
50 	private GATTService batteryService;
51 	private GATTCharacteristic batteryLevelCharacteristic;
52 	private byte[] battery_level_chr_uuid = new byte[] {0, 0, (byte)0x2a, (byte)0x19, 0, 0, (byte)0x10, 0, (byte)0x80, 0, 0, (byte)0x80, (byte)0x5f, (byte)0x9b, (byte)0x34, (byte)0xfb};
53 	GATTEventCharacteristicValueQueryResult battery;
54 
55 	private BT_UUID uuid128(byte[] att_uuid) {
56 		byte [] uuid = new byte[16];
57 		Util.flipX(att_uuid, uuid);
58 		return new BT_UUID(uuid);
59 	}
60 
61 	public void handlePacket(Packet packet){
62 		if (packet instanceof HCIEventDisconnectionComplete){
63 			System.out.println(String.format("Received dissconnect, restart scannning."));
64 			state = STATE.w4_scan_result;
65 			btstack.GAPLEScanStart();
66 			return;
67 		}
68 
69 		if (packet instanceof GATTEventQueryComplete){
70 			GATTEventQueryComplete event = (GATTEventQueryComplete) packet;
71 			System.out.println(testAddr + " battery data");
72 			if (event.getATTStatus() != 0){
73 				System.out.println("Battery data could not be read.\nRestart scanning.");
74 				state = STATE.w4_scan_result;
75 				btstack.GAPLEScanStart();
76 				return;
77 			}
78 		}
79 
80 		switch (state){
81 			case w4_btstack_working:
82 				if (packet instanceof BTstackEventState){
83 					BTstackEventState event = (BTstackEventState) packet;
84 					if (event.getState() == 2)	{
85 						System.out.println("BTstack working, start scanning.");
86 						state = STATE.w4_scan_result;
87 						btstack.GAPLEScanStart();
88 					}
89 				}
90 				break;
91 			case w4_scan_result:
92 				if (packet instanceof GAPEventAdvertisingReport){
93 					// Advertisement received. Connect to the found BT address.
94 					GAPEventAdvertisingReport report = (GAPEventAdvertisingReport) packet;
95 					testAddrType = report.getAddressType();
96 					testAddr = report.getAddress();
97 					System.out.println(String.format("Adv: type %d, addr %s\ndata: %s \n Stop scan, initiate connect.", testAddrType, testAddr, Util.asHexdump(report.getData())));
98 					btstack.GAPLEScanStop();
99 					state = STATE.w4_connected;
100 					btstack.GAPLEConnect(testAddrType, testAddr);
101 				}
102 				break;
103 			case w4_connected:
104 				if (packet instanceof HCIEventLEConnectionComplete){
105 					HCIEventLEConnectionComplete event = (HCIEventLEConnectionComplete) packet;
106 					if (event.getStatus() != 0) {
107 						System.out.println(testAddr + String.format(" - connection failed, status %d.\nRestart scanning.", event.getStatus()));
108 						state = STATE.w4_scan_result;
109 						btstack.GAPLEScanStart();
110 						break;
111 					}
112 
113 					// Query battery service.
114 					state = STATE.w4_services_complete;
115 					connectionHandle = event.getConnectionHandle();
116 					System.out.println(testAddr + String.format(" - connected %x.\nQuery battery service.", connectionHandle));
117 					btstack.GATTDiscoverPrimaryServicesByUUID16(connectionHandle, 0x180f);
118 				}
119 				break;
120 			case w4_services_complete:
121 				if (packet instanceof GATTEventServiceQueryResult){
122 					// Store battery service. Wait for GATTEventQueryComplete event to send next GATT command.
123 					GATTEventServiceQueryResult event = (GATTEventServiceQueryResult) packet;
124 					System.out.println(testAddr + String.format(" - battery service %s", event.getService().getUUID()));
125 					batteryService = event.getService();
126 					break;
127 				}
128 				if (packet instanceof GATTEventQueryComplete){
129 					// Check if battery service is found.
130 					if (batteryService == null) {
131 						System.out.println(testAddr + " - no battery service. \nRestart scanning.");
132 						state = STATE.w4_scan_result;
133 						btstack.GAPLEScanStart();
134 						break;
135 					}
136 					System.out.println(testAddr + " - query battery level.");
137 					state = STATE.w4_characteristic_complete;
138 					btstack.GATTDiscoverCharacteristicsForServiceByUUID128(connectionHandle, batteryService, uuid128(this.battery_level_chr_uuid));
139 				}
140 				break;
141 			case w4_characteristic_complete:
142 				if (packet instanceof GATTEventCharacteristicQueryResult){
143 					// Store battery level characteristic. Wait for GATTEventQueryComplete event to send next GATT command.
144 					GATTEventCharacteristicQueryResult event = (GATTEventCharacteristicQueryResult) packet;
145 					batteryLevelCharacteristic = event.getCharacteristic();
146 					System.out.println(testAddr + " - battery level found.");
147 					break;
148 				}
149 
150 				if (!(packet instanceof GATTEventQueryComplete)) break;
151 				if (batteryLevelCharacteristic == null) {
152 					System.out.println("No battery level characteristic found");
153 					break;
154 				}
155 				System.out.println(testAddr + " - polling battery.");
156 				counter = 0;
157 				state = STATE.battery_data;
158 				new Thread(new Runnable(){
159 					@Override
160 					public void run() {
161 						try {
162 							while(state == STATE.battery_data){
163 								Thread.sleep(5000);
164 								btstack.GATTReadValueOfCharacteristic(connectionHandle, batteryLevelCharacteristic);
165 							}
166 						} catch (InterruptedException e) {}
167 					}
168 				}).start();
169 				break;
170 			case battery_data:
171 				if (packet instanceof GATTEventCharacteristicValueQueryResult){
172 					GATTEventCharacteristicValueQueryResult battery = (GATTEventCharacteristicValueQueryResult) packet;
173 
174 					if (battery.getValueLength() != 1) break;
175 					byte[] data = battery.getValue();
176 					counter = counter + 1;
177 					System.out.println(String.format("Counter %d, battery level: %d", counter, data[0]) + "%");
178 					break;
179 
180 				}
181 				break;
182 			default:
183 				break;
184 		}
185 	}
186 
187 	public void handlePacketAcc(Packet packet){
188 
189 //		System.out.println(packet.toString());
190 		if (packet instanceof HCIEventDisconnectionComplete){
191 			HCIEventDisconnectionComplete event = (HCIEventDisconnectionComplete) packet;
192 			testHandle = event.getConnectionHandle();
193 			System.out.println(String.format("Received disconnect, status %d, handle %x", event.getStatus(), testHandle));
194 			return;
195 		}
196 
197 		switch (state){
198 		case w4_btstack_working:
199 			if (packet instanceof BTstackEventState){
200 				BTstackEventState event = (BTstackEventState) packet;
201 				if (event.getState() == 2)	{
202 
203 					System.out.println("GAPLEScanStart()");
204 					state = STATE.w4_scan_result;
205 					btstack.GAPLEScanStart();
206 				}
207 			}
208 			break;
209 		case w4_scan_result:
210 			if (packet instanceof GAPEventAdvertisingReport){
211 				GAPEventAdvertisingReport report = (GAPEventAdvertisingReport) packet;
212 				testAddrType = report.getAddressType();
213 				testAddr = report.getAddress();
214 				System.out.println(String.format("Adv: type %d, addr %s", testAddrType, testAddr));
215 				System.out.println(String.format("Data: %s", Util.asHexdump(report.getData())));
216 				System.out.println("GAPLEScanStop()");
217 				btstack.GAPLEScanStop();
218 				System.out.println("GAPLEConnect(...)");
219 				state = STATE.w4_connected_acc;
220 				btstack.GAPLEConnect(testAddrType, testAddr);
221 			}
222 			break;
223 
224 		case w4_connected:
225 			if (packet instanceof HCIEventLEConnectionComplete){
226 				HCIEventLEConnectionComplete event = (HCIEventLEConnectionComplete) packet;
227 				testHandle = event.getConnectionHandle();
228 				System.out.println(String.format("Connection complete, status %d, handle %x", event.getStatus(), testHandle));
229 				state = STATE.w4_services_complete;
230 				System.out.println("GATTDiscoverPrimaryServices(...)");
231 				btstack.GATTDiscoverPrimaryServices(testHandle);
232 			}
233 			break;
234 		case w4_services_complete:
235 			if (packet instanceof GATTEventServiceQueryResult){
236 				GATTEventServiceQueryResult event = (GATTEventServiceQueryResult) packet;
237 				if (testService == null){
238 					System.out.println(String.format("First service UUID %s", event.getService().getUUID()));
239 					testService = event.getService();
240 				}
241 				System.out.println("Service: " + event.getService());
242 				service_count++;
243 			}
244 			if (packet instanceof GATTEventQueryComplete){
245 				System.out.println(String.format("Service query complete, total %d services", service_count));
246 				state = STATE.w4_characteristic_complete;
247 				btstack.GATTDiscoverCharacteristicsForService(testHandle, testService);
248 			}
249 			break;
250 
251 		case w4_characteristic_complete:
252 			if (packet instanceof GATTEventCharacteristicQueryResult){
253 				GATTEventCharacteristicQueryResult event = (GATTEventCharacteristicQueryResult) packet;
254 				if (testCharacteristic == null){
255 					System.out.println(String.format("First characteristic UUID %s", event.getCharacteristic().getUUID()));
256 					testCharacteristic = event.getCharacteristic();
257 				}
258 				System.out.println("Characteristic: " + event.getCharacteristic());
259 				characteristic_count++;
260 			}
261 			if (packet instanceof GATTEventQueryComplete){
262 				System.out.println(String.format("Characteristic query complete, total %d characteristics", characteristic_count));
263 				state = STATE.w4_characteristic_read;
264 				btstack.GATTReadValueOfCharacteristic(testHandle, testCharacteristic);
265 			}
266 			break;
267 
268 		case w4_characteristic_read:
269 			if (packet instanceof GATTEventCharacteristicValueQueryResult){
270 				System.out.println("Read complete");
271 				System.out.println( packet.toString());
272 				state = STATE.w4_characteristic_write;
273 				byte [] data = { 'B', 'T', 's', 't', 'a', 'c', 'k'};
274 				btstack.GATTWriteValueOfCharacteristic(testHandle, testCharacteristic, data.length, data);
275 			}
276 			break;
277 		case w4_characteristic_write:
278 			if (packet instanceof GATTEventQueryComplete){
279 				System.out.println("Write complete, search for ACC service");
280 				state = STATE.w4_acc_service_result;
281 				btstack.GATTDiscoverPrimaryServicesByUUID128(testHandle, new BT_UUID(this.acc_service_uuid)); // not working
282 			}
283 			break;
284 
285 		case w4_connected_acc:
286 			if (packet instanceof HCIEventLEConnectionComplete){
287 				HCIEventLEConnectionComplete event = (HCIEventLEConnectionComplete) packet;
288 				testHandle = event.getConnectionHandle();
289 				System.out.println(String.format("Connection complete, status %d, handle %x", event.getStatus(), testHandle));
290 				System.out.println("Search for ACC service");
291 				state = STATE.w4_acc_service_result;
292 				byte [] uuid = new byte[16];
293 				Util.flipX(this.acc_service_uuid, uuid);	// works
294 				btstack.GATTDiscoverPrimaryServicesByUUID128(testHandle, new BT_UUID(uuid));
295 			}
296 			break;
297 
298 		 case w4_acc_service_result:
299 			System.out.println(String.format("w4_acc_service_result state"));
300 			if (packet instanceof GATTEventServiceQueryResult){
301 				GATTEventServiceQueryResult event = (GATTEventServiceQueryResult) packet;
302 				System.out.println(String.format("ACC service found %s", event.getService().getUUID()));
303 				accService = event.getService();
304 				break;
305 			}
306 			if (packet instanceof GATTEventQueryComplete){
307 				if (accService == null) {
308 					System.out.println("No acc service found");
309 					break;
310 				}
311 				System.out.println("ACC Service found, searching for acc enable characteristic");
312 				state = STATE.w4_acc_enable_characteristic_result;
313 				byte [] uuid = new byte[16];
314 				Util.flipX(this.acc_chr_enable_uuid, uuid);
315 				btstack.GATTDiscoverCharacteristicsForServiceByUUID128(testHandle, accService, new BT_UUID(uuid));
316 			}
317 			break;
318 
319 		case w4_acc_enable_characteristic_result:
320 			if (packet instanceof GATTEventCharacteristicQueryResult){
321 				GATTEventCharacteristicQueryResult event = (GATTEventCharacteristicQueryResult) packet;
322 				enableCharacteristic = event.getCharacteristic();
323 				System.out.println("Enable ACC Characteristic found ");
324 			}
325 			if (packet instanceof GATTEventQueryComplete){
326 				if (enableCharacteristic == null) {
327 					System.out.println("No acc enable chr found");
328 					break;
329 				}
330 				System.out.println("Write enable acc characteristic");
331 				state = STATE.w4_write_acc_enable_result;
332 				btstack.GATTWriteValueOfCharacteristic(testHandle, enableCharacteristic, 1, this.acc_enable);
333 			}
334 			break;
335 		case w4_write_acc_enable_result:
336 			if (packet instanceof GATTEventQueryComplete){
337 				System.out.println("Acc enabled,searching for acc client config characteristic");
338 				byte [] uuid = new byte[16];
339 				Util.flipX(this.acc_chr_client_config_uuid, uuid);
340 				btstack.GATTDiscoverCharacteristicsForServiceByUUID128(testHandle, accService, new BT_UUID(uuid));
341 				state = STATE.w4_acc_client_config_characteristic_result;
342 			}
343 			break;
344 
345 		case w4_acc_client_config_characteristic_result:
346 			if (packet instanceof GATTEventCharacteristicQueryResult){
347 				GATTEventCharacteristicQueryResult event = (GATTEventCharacteristicQueryResult) packet;
348 				configCharacteristic = event.getCharacteristic();
349 				System.out.println("ACC Client Config Characteristic found");
350 			}
351 			if (packet instanceof GATTEventQueryComplete){
352 				if (configCharacteristic == null) {
353 					System.out.println("No acc config chr found");
354 					break;
355 				}
356 				System.out.println("Write ACC Client Config Characteristic");
357 				state = STATE.w4_acc_data;
358 				btstack.GATTWriteClientCharacteristicConfiguration(testHandle, configCharacteristic, this.acc_notification);
359 			}
360 			break;
361 
362 		case w4_acc_data:
363 			if (packet instanceof GATTEventQueryComplete){
364 				System.out.println("Acc configured for notification");
365 				break;
366 			}
367 
368 			if (packet instanceof GATTEventNotification){
369 				System.out.println("Acc Value");
370 				System.out.println(packet.toString());
371 				btstack.GAPDisconnect(testHandle);
372 			}
373 
374 		default:
375 			break;
376 		}
377 	}
378 
379 	void test(){
380 
381 		System.out.println("LE Test Application");
382 
383 		// connect to BTstack Daemon via default port on localhost
384 		btstack = new BTstack();
385 		btstack.setTcpPort(BTstack.DEFAULT_TCP_PORT);
386 		btstack.registerPacketHandler(this);
387 		boolean ok = btstack.connect();
388 		if (!ok) {
389 			System.out.println("Failed to connect to BTstack Server");
390 			return;
391 		}
392 
393 		System.out.println("BTstackSetPowerMode(1)");
394 
395 		state = STATE.w4_btstack_working;
396 		btstack.BTstackSetPowerMode(1);
397 	}
398 
399 	public static void main(String args[]){
400 		new GATTClientTest().test();
401 	}
402 }
403