131ee742eSMatthias Ringwald package com.bluekitchen; 231ee742eSMatthias Ringwald 331ee742eSMatthias Ringwald import com.bluekitchen.btstack.BD_ADDR; 431ee742eSMatthias Ringwald import com.bluekitchen.btstack.BT_UUID; 531ee742eSMatthias Ringwald import com.bluekitchen.btstack.BTstack; 631ee742eSMatthias Ringwald import com.bluekitchen.btstack.GATTCharacteristic; 731ee742eSMatthias Ringwald import com.bluekitchen.btstack.GATTService; 831ee742eSMatthias Ringwald import com.bluekitchen.btstack.Packet; 931ee742eSMatthias Ringwald import com.bluekitchen.btstack.PacketHandler; 1031ee742eSMatthias Ringwald import com.bluekitchen.btstack.Util; 1131ee742eSMatthias Ringwald import com.bluekitchen.btstack.event.BTstackEventState; 1231ee742eSMatthias Ringwald import com.bluekitchen.btstack.event.GAPEventAdvertisingReport; 1331ee742eSMatthias Ringwald import com.bluekitchen.btstack.event.GATTEventCharacteristicQueryResult; 1431ee742eSMatthias Ringwald import com.bluekitchen.btstack.event.GATTEventCharacteristicValueQueryResult; 1531ee742eSMatthias Ringwald import com.bluekitchen.btstack.event.GATTEventNotification; 1631ee742eSMatthias Ringwald import com.bluekitchen.btstack.event.GATTEventQueryComplete; 1731ee742eSMatthias Ringwald import com.bluekitchen.btstack.event.GATTEventServiceQueryResult; 1831ee742eSMatthias Ringwald import com.bluekitchen.btstack.event.HCIEventDisconnectionComplete; 1931ee742eSMatthias Ringwald import com.bluekitchen.btstack.event.HCIEventLEConnectionComplete; 2031ee742eSMatthias Ringwald import com.bluekitchen.btstack.event.SMEventJustWorksRequest; 2131ee742eSMatthias Ringwald 2231ee742eSMatthias Ringwald import java.nio.charset.StandardCharsets; 2331ee742eSMatthias Ringwald 2431ee742eSMatthias Ringwald public class LEStreamerClient implements PacketHandler { 2531ee742eSMatthias Ringwald 2631ee742eSMatthias Ringwald private enum STATE { 2731ee742eSMatthias Ringwald w4_btstack_working, w4_scan_result, w4_connected, w4_services_complete, w4_characteristic_complete, 2831ee742eSMatthias Ringwald w4_write_client_config_characteristic_complete, active 2931ee742eSMatthias Ringwald }; 3031ee742eSMatthias Ringwald 3131ee742eSMatthias Ringwald private BTstack btstack; 3231ee742eSMatthias Ringwald private STATE state; 3331ee742eSMatthias Ringwald private int testAddrType; 3431ee742eSMatthias Ringwald private BD_ADDR testAddr = new BD_ADDR("00:1A:7D:DA:71:01"); 3531ee742eSMatthias Ringwald private int connectionHandle; 3631ee742eSMatthias Ringwald 3731ee742eSMatthias Ringwald private BT_UUID testServiceUUID = new BT_UUID("0000FF10-0000-1000-8000-00805F9B34FB"); 3831ee742eSMatthias Ringwald private BT_UUID testCharacteristicUUID = new BT_UUID("0000FF11-0000-1000-8000-00805F9B34FB"); 3931ee742eSMatthias Ringwald private byte testNotification = 1; 4031ee742eSMatthias Ringwald 4131ee742eSMatthias Ringwald private GATTService testService; 4231ee742eSMatthias Ringwald private GATTCharacteristic testCharacteristic; 4331ee742eSMatthias Ringwald handlePacket(Packet packet)4431ee742eSMatthias Ringwald public void handlePacket(Packet packet){ 4531ee742eSMatthias Ringwald 4631ee742eSMatthias Ringwald System.out.println("Event " + packet); 4731ee742eSMatthias Ringwald 4831ee742eSMatthias Ringwald if (packet instanceof SMEventJustWorksRequest){ 4931ee742eSMatthias Ringwald SMEventJustWorksRequest event = (SMEventJustWorksRequest) packet; 5031ee742eSMatthias Ringwald System.out.println("Received Just Works pairing request from " + event.getAddress() + " -> auto-accept"); 5131ee742eSMatthias Ringwald btstack.SMJustWorksConfirm(event.getHandle()); 5231ee742eSMatthias Ringwald return; 5331ee742eSMatthias Ringwald } 5431ee742eSMatthias Ringwald 5531ee742eSMatthias Ringwald if (packet instanceof HCIEventDisconnectionComplete){ 5631ee742eSMatthias Ringwald System.out.println("Received dissconnect, restart scannning."); 5731ee742eSMatthias Ringwald state = STATE.w4_scan_result; 5831ee742eSMatthias Ringwald btstack.GAPLEScanStart(); 5931ee742eSMatthias Ringwald return; 6031ee742eSMatthias Ringwald } 6131ee742eSMatthias Ringwald 6231ee742eSMatthias Ringwald switch (state){ 6331ee742eSMatthias Ringwald case w4_btstack_working: 6431ee742eSMatthias Ringwald if (packet instanceof BTstackEventState){ 6531ee742eSMatthias Ringwald BTstackEventState event = (BTstackEventState) packet; 6631ee742eSMatthias Ringwald if (event.getState() == 2) { 6731ee742eSMatthias Ringwald System.out.println("BTstack working, start scanning."); 6831ee742eSMatthias Ringwald state = STATE.w4_scan_result; 6931ee742eSMatthias Ringwald btstack.GAPLEScanStart(); 7031ee742eSMatthias Ringwald } 7131ee742eSMatthias Ringwald } 7231ee742eSMatthias Ringwald break; 7331ee742eSMatthias Ringwald case w4_scan_result: 7431ee742eSMatthias Ringwald if (packet instanceof GAPEventAdvertisingReport){ 7531ee742eSMatthias Ringwald // Advertisement received. Connect to the found BT address. 7631ee742eSMatthias Ringwald GAPEventAdvertisingReport report = (GAPEventAdvertisingReport) packet; 7731ee742eSMatthias Ringwald System.out.println(String.format("Adv: type %d, addr %s\ndata: %s\n", report.getAddressType(), report.getAddress(), Util.asHexdump(report.getData()))); 7831ee742eSMatthias Ringwald // hack to find 'LE Streamer' 7931ee742eSMatthias Ringwald if (new String(report.getData(), StandardCharsets.UTF_8).indexOf("LE Streamer") > 0){ 8031ee742eSMatthias Ringwald testAddrType = report.getAddressType(); 8131ee742eSMatthias Ringwald testAddr = report.getAddress(); 8231ee742eSMatthias Ringwald System.out.println(String.format("LE Streamer found, connect to %s\n", testAddr)); 8331ee742eSMatthias Ringwald btstack.GAPLEScanStop(); 8431ee742eSMatthias Ringwald state = STATE.w4_connected; 8531ee742eSMatthias Ringwald btstack.GAPLEConnect(testAddrType, testAddr); 8631ee742eSMatthias Ringwald } 8731ee742eSMatthias Ringwald } 8831ee742eSMatthias Ringwald break; 8931ee742eSMatthias Ringwald case w4_connected: 9031ee742eSMatthias Ringwald if (packet instanceof HCIEventLEConnectionComplete){ 9131ee742eSMatthias Ringwald HCIEventLEConnectionComplete event = (HCIEventLEConnectionComplete) packet; 9231ee742eSMatthias Ringwald if (event.getStatus() != 0) { 9331ee742eSMatthias Ringwald System.out.println(testAddr + String.format(" - connection failed, status %d.\nRestart scanning.", event.getStatus())); 9431ee742eSMatthias Ringwald state = STATE.w4_scan_result; 9531ee742eSMatthias Ringwald btstack.GAPLEScanStart(); 9631ee742eSMatthias Ringwald break; 9731ee742eSMatthias Ringwald } 9831ee742eSMatthias Ringwald 9931ee742eSMatthias Ringwald // Query test service. 10031ee742eSMatthias Ringwald state = STATE.w4_services_complete; 10131ee742eSMatthias Ringwald connectionHandle = event.getConnectionHandle(); 10231ee742eSMatthias Ringwald System.out.println(testAddr + String.format(" - connected %x.\nQuery streamer service.", connectionHandle)); 10331ee742eSMatthias Ringwald btstack.GATTDiscoverPrimaryServicesByUUID128(connectionHandle, testServiceUUID); 10431ee742eSMatthias Ringwald } 10531ee742eSMatthias Ringwald break; 10631ee742eSMatthias Ringwald case w4_services_complete: 10731ee742eSMatthias Ringwald if (packet instanceof GATTEventServiceQueryResult){ 10831ee742eSMatthias Ringwald // Store streamer service. Wait for GATTEventQueryComplete event to send next GATT command. 10931ee742eSMatthias Ringwald GATTEventServiceQueryResult event = (GATTEventServiceQueryResult) packet; 11031ee742eSMatthias Ringwald System.out.println(testAddr + String.format(" - streamer service %s", event.getService().getUUID())); 11131ee742eSMatthias Ringwald testService = event.getService(); 11231ee742eSMatthias Ringwald break; 11331ee742eSMatthias Ringwald } 11431ee742eSMatthias Ringwald if (packet instanceof GATTEventQueryComplete){ 11531ee742eSMatthias Ringwald // Check if streamer service is found. 11631ee742eSMatthias Ringwald if (testService == null) { 11731ee742eSMatthias Ringwald System.out.println(testAddr + " - no streamer service. \nRestart scanning."); 11831ee742eSMatthias Ringwald state = STATE.w4_scan_result; 11931ee742eSMatthias Ringwald btstack.GAPLEScanStart(); 12031ee742eSMatthias Ringwald break; 12131ee742eSMatthias Ringwald } 12231ee742eSMatthias Ringwald System.out.println(testAddr + " - query streamer characteristic."); 12331ee742eSMatthias Ringwald state = STATE.w4_characteristic_complete; 12431ee742eSMatthias Ringwald btstack.GATTDiscoverCharacteristicsForServiceByUUID128(connectionHandle, testService, testCharacteristicUUID); 12531ee742eSMatthias Ringwald } 12631ee742eSMatthias Ringwald break; 12731ee742eSMatthias Ringwald case w4_characteristic_complete: 12831ee742eSMatthias Ringwald if (packet instanceof GATTEventCharacteristicQueryResult){ 12931ee742eSMatthias Ringwald // Store streamer characteristic. Wait for GATTEventQueryComplete event to send next GATT command. 13031ee742eSMatthias Ringwald GATTEventCharacteristicQueryResult event = (GATTEventCharacteristicQueryResult) packet; 13131ee742eSMatthias Ringwald testCharacteristic = event.getCharacteristic(); 13231ee742eSMatthias Ringwald System.out.println(testAddr + " - streamer characteristic found."); 13331ee742eSMatthias Ringwald break; 13431ee742eSMatthias Ringwald } 13531ee742eSMatthias Ringwald 13631ee742eSMatthias Ringwald if (!(packet instanceof GATTEventQueryComplete)) break; 13731ee742eSMatthias Ringwald 13831ee742eSMatthias Ringwald if (testCharacteristic == null) { 13931ee742eSMatthias Ringwald System.out.println("No streamer characteristic found"); 14031ee742eSMatthias Ringwald break; 14131ee742eSMatthias Ringwald } 14231ee742eSMatthias Ringwald System.out.println(testAddr + " - enable notifications."); 14331ee742eSMatthias Ringwald state = STATE.w4_write_client_config_characteristic_complete; 14431ee742eSMatthias Ringwald btstack.GATTWriteClientCharacteristicConfiguration(connectionHandle, testCharacteristic, this.testNotification); 14531ee742eSMatthias Ringwald break; 14631ee742eSMatthias Ringwald 14731ee742eSMatthias Ringwald case w4_write_client_config_characteristic_complete: 14831ee742eSMatthias Ringwald if (packet instanceof GATTEventQueryComplete){ 14931ee742eSMatthias Ringwald System.out.println(testAddr + " - notification enabled."); 15031ee742eSMatthias Ringwald state = STATE.active; 15131ee742eSMatthias Ringwald } 15231ee742eSMatthias Ringwald break; 15331ee742eSMatthias Ringwald 15431ee742eSMatthias Ringwald case active: 15531ee742eSMatthias Ringwald if (packet instanceof GATTEventNotification){ 156*1cd21c05SMatthias Ringwald GATTEventNotification event = (GATTEventNotification) packet; 15731ee742eSMatthias Ringwald System.out.println("Data:"); 158*1cd21c05SMatthias Ringwald Util.hexdump(event.getValue()); 15931ee742eSMatthias Ringwald } 16031ee742eSMatthias Ringwald break; 16131ee742eSMatthias Ringwald 16231ee742eSMatthias Ringwald default: 16331ee742eSMatthias Ringwald break; 16431ee742eSMatthias Ringwald } 16531ee742eSMatthias Ringwald } 16631ee742eSMatthias Ringwald test()16731ee742eSMatthias Ringwald void test(){ 16831ee742eSMatthias Ringwald 16931ee742eSMatthias Ringwald System.out.println("LE Streamer Client"); 17031ee742eSMatthias Ringwald 17131ee742eSMatthias Ringwald // connect to BTstack Daemon via default port on localhost 17231ee742eSMatthias Ringwald btstack = new BTstack(); 17331ee742eSMatthias Ringwald btstack.setTcpPort(BTstack.DEFAULT_TCP_PORT); 17431ee742eSMatthias Ringwald btstack.registerPacketHandler(this); 17531ee742eSMatthias Ringwald boolean ok = btstack.connect(); 17631ee742eSMatthias Ringwald if (!ok) { 17731ee742eSMatthias Ringwald System.out.println("Failed to connect to BTstack Server"); 17831ee742eSMatthias Ringwald return; 17931ee742eSMatthias Ringwald } 18031ee742eSMatthias Ringwald 18131ee742eSMatthias Ringwald System.out.println("BTstackSetPowerMode(1)"); 18231ee742eSMatthias Ringwald 18331ee742eSMatthias Ringwald // btstack.SMSetAuthenticationRequirements(8 | 4); 18431ee742eSMatthias Ringwald // btstack.SMSetIoCapabilities(4); 18531ee742eSMatthias Ringwald 18631ee742eSMatthias Ringwald state = STATE.w4_btstack_working; 18731ee742eSMatthias Ringwald btstack.BTstackSetPowerMode(1); 18831ee742eSMatthias Ringwald } 18931ee742eSMatthias Ringwald main(String args[])19031ee742eSMatthias Ringwald public static void main(String args[]){ 19131ee742eSMatthias Ringwald new LEStreamerClient().test(); 19231ee742eSMatthias Ringwald } 19331ee742eSMatthias Ringwald } 194