16418890eSBoris Zweimuelller package com.bluekitchen; 26418890eSBoris Zweimuelller 36418890eSBoris Zweimuelller import com.bluekitchen.btstack.BD_ADDR; 46418890eSBoris Zweimuelller import com.bluekitchen.btstack.BTstack; 56418890eSBoris Zweimuelller import com.bluekitchen.btstack.Packet; 66418890eSBoris Zweimuelller import com.bluekitchen.btstack.PacketHandler; 76418890eSBoris Zweimuelller import com.bluekitchen.btstack.RFCOMMDataPacket; 86418890eSBoris Zweimuelller import com.bluekitchen.btstack.Util; 96418890eSBoris Zweimuelller import com.bluekitchen.btstack.event.*; 106418890eSBoris Zweimuelller 116418890eSBoris Zweimuelller /** 126418890eSBoris Zweimuelller * Simple demonstration of the Java binding by streaming data over SPP. 136418890eSBoris Zweimuelller * 146418890eSBoris Zweimuelller * This is the same example as the: example/spp_streamer_client.c example. 156418890eSBoris Zweimuelller * 166418890eSBoris Zweimuelller * It can be run against the 'spp_streamer' example. 176418890eSBoris Zweimuelller * 186418890eSBoris Zweimuelller * To run, two dongles are needed, then: 196418890eSBoris Zweimuelller * 206418890eSBoris Zweimuelller * 1. In a first terminal run: 216418890eSBoris Zweimuelller * 226418890eSBoris Zweimuelller * cd port/libusb 236418890eSBoris Zweimuelller * ./spp_streamer 246418890eSBoris Zweimuelller * 256418890eSBoris Zweimuelller * 2. In a second terminal, run the daemon: 266418890eSBoris Zweimuelller * 276418890eSBoris Zweimuelller * cd port/daemon 286418890eSBoris Zweimuelller * ./src/BTdaemon --tcp 296418890eSBoris Zweimuelller * 306418890eSBoris Zweimuelller * 3. In a third terminal, run the java application: 316418890eSBoris Zweimuelller * 326418890eSBoris Zweimuelller * cd platform/daemon/binding/java 336418890eSBoris Zweimuelller * ant run 346418890eSBoris Zweimuelller */ 356418890eSBoris Zweimuelller public class SPPStreamerClient implements PacketHandler { 366418890eSBoris Zweimuelller 376418890eSBoris Zweimuelller private final static int NUM_ROWS = 25; 386418890eSBoris Zweimuelller private final static int NUM_COLS = 40; 39*8ceba64eSBoris Zweimuelller public static final int TEST_COD = 0x1234; 406418890eSBoris Zweimuelller 416418890eSBoris Zweimuelller private enum STATE { 42*8ceba64eSBoris Zweimuelller BTSTACK_WORKING, INQUIRY_RESULT, SDP_QUERY_RESULT, CONNECTED, SENDING 436418890eSBoris Zweimuelller } 446418890eSBoris Zweimuelller 456418890eSBoris Zweimuelller private BTstack btstack; 466418890eSBoris Zweimuelller private STATE state; 476418890eSBoris Zweimuelller 48*8ceba64eSBoris Zweimuelller private BD_ADDR remote; 496418890eSBoris Zweimuelller 506418890eSBoris Zweimuelller private int outgoing_channel_nr = -1; 516418890eSBoris Zweimuelller private int rfcommChannelID = 0; 526418890eSBoris Zweimuelller 536418890eSBoris Zweimuelller private final static int REPORT_INTERVAL_MS = 3000; 546418890eSBoris Zweimuelller private long test_data_transferred; 556418890eSBoris Zweimuelller private long test_data_start; 566418890eSBoris Zweimuelller private byte[] sppTestData; 576418890eSBoris Zweimuelller 586418890eSBoris Zweimuelller createSppTestData(final int mtu)596418890eSBoris Zweimuelller private void createSppTestData(final int mtu) { 606418890eSBoris Zweimuelller byte[] temp = new byte[NUM_ROWS * NUM_COLS]; 616418890eSBoris Zweimuelller int x, y; 626418890eSBoris Zweimuelller for (y = 0; y < NUM_ROWS; y++) { 636418890eSBoris Zweimuelller for (x = 0; x < NUM_COLS - 2; x++) { 646418890eSBoris Zweimuelller temp[y * NUM_COLS + x] = (byte) ('0' + (x % 10)); 656418890eSBoris Zweimuelller } 666418890eSBoris Zweimuelller temp[y * NUM_COLS + NUM_COLS - 2] = '\n'; 676418890eSBoris Zweimuelller temp[y * NUM_COLS + NUM_COLS - 1] = '\r'; 686418890eSBoris Zweimuelller } 696418890eSBoris Zweimuelller 706418890eSBoris Zweimuelller // cut to MTU 716418890eSBoris Zweimuelller sppTestData = new byte[Math.min(mtu, temp.length)]; 726418890eSBoris Zweimuelller System.arraycopy(temp, 0, sppTestData, 0, sppTestData.length); 736418890eSBoris Zweimuelller } 746418890eSBoris Zweimuelller testReset()756418890eSBoris Zweimuelller void testReset() { 766418890eSBoris Zweimuelller test_data_start = System.currentTimeMillis(); 776418890eSBoris Zweimuelller test_data_transferred = 0; 786418890eSBoris Zweimuelller } 796418890eSBoris Zweimuelller calculateSpeedAndLog(int bytesSent)806418890eSBoris Zweimuelller private void calculateSpeedAndLog(int bytesSent){ 816418890eSBoris Zweimuelller test_data_transferred += bytesSent; 826418890eSBoris Zweimuelller // evaluate 836418890eSBoris Zweimuelller long now = System.currentTimeMillis(); 846418890eSBoris Zweimuelller long timePassed = now - test_data_start; 856418890eSBoris Zweimuelller if (timePassed < REPORT_INTERVAL_MS) return; 866418890eSBoris Zweimuelller 876418890eSBoris Zweimuelller // print speed 886418890eSBoris Zweimuelller long bytesPerSecond = test_data_transferred * 1000 / timePassed; 896418890eSBoris Zweimuelller System.out.printf("%d bytes -> %d.%03d kB/s\n", (int) test_data_transferred, (int) bytesPerSecond / 1000, bytesPerSecond % 1000); 906418890eSBoris Zweimuelller 916418890eSBoris Zweimuelller // restart 926418890eSBoris Zweimuelller test_data_start = now; 936418890eSBoris Zweimuelller test_data_transferred = 0; 946418890eSBoris Zweimuelller } 956418890eSBoris Zweimuelller startSDPQuery()966418890eSBoris Zweimuelller private void startSDPQuery() { 976418890eSBoris Zweimuelller state = STATE.SDP_QUERY_RESULT; 986418890eSBoris Zweimuelller int sppUUID = 0x1101; 996418890eSBoris Zweimuelller byte[] serviceSearchPattern = Util.serviceSearchPatternForUUID16(sppUUID); 1006418890eSBoris Zweimuelller btstack.SDPClientQueryRFCOMMServices(remote, serviceSearchPattern); 1016418890eSBoris Zweimuelller } 1026418890eSBoris Zweimuelller handlePacket(Packet packet)1036418890eSBoris Zweimuelller public void handlePacket(Packet packet) { 1046418890eSBoris Zweimuelller if (packet instanceof HCIEventDisconnectionComplete) { 1056418890eSBoris Zweimuelller final HCIEventDisconnectionComplete event = (HCIEventDisconnectionComplete) packet; 1066418890eSBoris Zweimuelller System.out.printf("Received disconnect, status %d, handle %x%n", event.getStatus(), event.getConnectionHandle()); 1076418890eSBoris Zweimuelller btstack.disconnect(); 1086418890eSBoris Zweimuelller return; 1096418890eSBoris Zweimuelller } 1106418890eSBoris Zweimuelller 1116418890eSBoris Zweimuelller switch (state) { 1126418890eSBoris Zweimuelller case BTSTACK_WORKING: 1136418890eSBoris Zweimuelller if (packet instanceof BTstackEventState) { 1146418890eSBoris Zweimuelller final BTstackEventState event = (BTstackEventState) packet; 1156418890eSBoris Zweimuelller if (event.getState() == 2) { 116*8ceba64eSBoris Zweimuelller System.out.println("BTstack working. Start inquiry.."); 117*8ceba64eSBoris Zweimuelller state = STATE.INQUIRY_RESULT; 118*8ceba64eSBoris Zweimuelller btstack.GAPInquiryStart(5); 119*8ceba64eSBoris Zweimuelller } 120*8ceba64eSBoris Zweimuelller } 121*8ceba64eSBoris Zweimuelller break; 122*8ceba64eSBoris Zweimuelller 123*8ceba64eSBoris Zweimuelller case INQUIRY_RESULT: 124*8ceba64eSBoris Zweimuelller if (packet instanceof GAPEventInquiryResult) { 125*8ceba64eSBoris Zweimuelller final GAPEventInquiryResult event = ((GAPEventInquiryResult) packet); 126*8ceba64eSBoris Zweimuelller System.out.printf("Found device with COD: %d with address: %s\n", event.getClassOfDevice(), event.getBdAddr()); 127*8ceba64eSBoris Zweimuelller if (event.getClassOfDevice() == TEST_COD) { 128*8ceba64eSBoris Zweimuelller remote = event.getBdAddr(); 129*8ceba64eSBoris Zweimuelller btstack.GAPInquiryStop(); 130*8ceba64eSBoris Zweimuelller System.out.println("Start SDP query on: " + remote); 1316418890eSBoris Zweimuelller startSDPQuery(); 1326418890eSBoris Zweimuelller } 1336418890eSBoris Zweimuelller } 134*8ceba64eSBoris Zweimuelller if (packet instanceof GAPEventInquiryComplete) { 135*8ceba64eSBoris Zweimuelller if (remote == null) { 136*8ceba64eSBoris Zweimuelller System.out.println("No device with COD: %d found -> scan again."); 137*8ceba64eSBoris Zweimuelller btstack.GAPInquiryStart(5); 138*8ceba64eSBoris Zweimuelller } 139*8ceba64eSBoris Zweimuelller } 1406418890eSBoris Zweimuelller break; 1416418890eSBoris Zweimuelller 1426418890eSBoris Zweimuelller case SDP_QUERY_RESULT: 1436418890eSBoris Zweimuelller if (packet instanceof SDPEventQueryRFCOMMService) { 1446418890eSBoris Zweimuelller final SDPEventQueryRFCOMMService service = (SDPEventQueryRFCOMMService) packet; 1456418890eSBoris Zweimuelller System.out.println("Found RFCOMM channel " + service.getName() + ", channel nr: " + service.getRFCOMMChannel()); 1466418890eSBoris Zweimuelller outgoing_channel_nr = service.getRFCOMMChannel(); 1476418890eSBoris Zweimuelller } 1486418890eSBoris Zweimuelller if (packet instanceof SDPEventQueryComplete) { 1496418890eSBoris Zweimuelller SDPEventQueryComplete complete = (SDPEventQueryComplete) packet; 1506418890eSBoris Zweimuelller if (complete.getStatus() != 0) { 1516418890eSBoris Zweimuelller System.out.printf("SDP Query failed with status 0x%02x, retry SDP query.%n", complete.getStatus()); 1526418890eSBoris Zweimuelller startSDPQuery(); 1536418890eSBoris Zweimuelller break; 1546418890eSBoris Zweimuelller } 1556418890eSBoris Zweimuelller if (outgoing_channel_nr >= 0) { 1566418890eSBoris Zweimuelller state = STATE.CONNECTED; 1576418890eSBoris Zweimuelller System.out.println("Connect to channel nr " + outgoing_channel_nr); 1586418890eSBoris Zweimuelller btstack.RFCOMMCreateChannel(remote, outgoing_channel_nr); 1596418890eSBoris Zweimuelller } 1606418890eSBoris Zweimuelller } 1616418890eSBoris Zweimuelller break; 1626418890eSBoris Zweimuelller 1636418890eSBoris Zweimuelller case CONNECTED: 1646418890eSBoris Zweimuelller if (packet instanceof RFCOMMEventChannelOpened) { 1656418890eSBoris Zweimuelller RFCOMMEventChannelOpened e = (RFCOMMEventChannelOpened) packet; 1666418890eSBoris Zweimuelller System.out.println("RFCOMMEventChannelOpened with status " + e.getStatus()); 1676418890eSBoris Zweimuelller if (e.getStatus() != 0) { 1686418890eSBoris Zweimuelller System.out.println("RFCOMM channel open failed, status " + e.getStatus()); 1696418890eSBoris Zweimuelller } else { 1706418890eSBoris Zweimuelller state = STATE.SENDING; 1716418890eSBoris Zweimuelller rfcommChannelID = e.getRFCOMMCid(); 1726418890eSBoris Zweimuelller System.out.printf("RFCOMM channel open succeeded. New RFCOMM Channel ID %d, max frame size %d%n", rfcommChannelID, e.getMaxFrameSize()); 1736418890eSBoris Zweimuelller 1746418890eSBoris Zweimuelller createSppTestData(e.getMaxFrameSize()); 1756418890eSBoris Zweimuelller testReset(); 1766418890eSBoris Zweimuelller 1776418890eSBoris Zweimuelller btstack.RFCOMMRequestCanSendNow(e.getRFCOMMCid()); 1786418890eSBoris Zweimuelller } 1796418890eSBoris Zweimuelller } 1806418890eSBoris Zweimuelller break; 1816418890eSBoris Zweimuelller 1826418890eSBoris Zweimuelller case SENDING: 1836418890eSBoris Zweimuelller if (packet instanceof RFCOMMEventCanSendNow) { 1846418890eSBoris Zweimuelller btstack.RFCOMMSendData(rfcommChannelID, sppTestData); 1856418890eSBoris Zweimuelller calculateSpeedAndLog(sppTestData.length); 1866418890eSBoris Zweimuelller btstack.RFCOMMRequestCanSendNow(rfcommChannelID); 1876418890eSBoris Zweimuelller } 1886418890eSBoris Zweimuelller 1896418890eSBoris Zweimuelller if (packet instanceof RFCOMMDataPacket) { 1906418890eSBoris Zweimuelller // duplex 1916418890eSBoris Zweimuelller calculateSpeedAndLog(sppTestData.length); 1926418890eSBoris Zweimuelller } 1936418890eSBoris Zweimuelller default: 1946418890eSBoris Zweimuelller break; 1956418890eSBoris Zweimuelller } 1966418890eSBoris Zweimuelller } 1976418890eSBoris Zweimuelller stream()1986418890eSBoris Zweimuelller void stream() { 1996418890eSBoris Zweimuelller System.out.println("SPP Streamer Client"); 2006418890eSBoris Zweimuelller 2016418890eSBoris Zweimuelller // connect to BTstack Daemon via default port on localhost 2026418890eSBoris Zweimuelller // start: src/BTdaemon --tcp 2036418890eSBoris Zweimuelller 2046418890eSBoris Zweimuelller btstack = new BTstack(); 2056418890eSBoris Zweimuelller btstack.setTcpPort(BTstack.DEFAULT_TCP_PORT); 2066418890eSBoris Zweimuelller btstack.registerPacketHandler(this); 2076418890eSBoris Zweimuelller boolean ok = btstack.connect(); 2086418890eSBoris Zweimuelller if (!ok) { 2096418890eSBoris Zweimuelller System.out.println("Failed to connect to BTstack Server"); 2106418890eSBoris Zweimuelller return; 2116418890eSBoris Zweimuelller } 2126418890eSBoris Zweimuelller 2136418890eSBoris Zweimuelller System.out.println("BTstackSetPowerMode(1)"); 2146418890eSBoris Zweimuelller 2156418890eSBoris Zweimuelller state = STATE.BTSTACK_WORKING; 2166418890eSBoris Zweimuelller btstack.BTstackSetPowerMode(1); 2176418890eSBoris Zweimuelller } 2186418890eSBoris Zweimuelller main(String[] args)2196418890eSBoris Zweimuelller public static void main(String[] args) { 2206418890eSBoris Zweimuelller new SPPStreamerClient().stream(); 2216418890eSBoris Zweimuelller } 2226418890eSBoris Zweimuelller } 2236418890eSBoris Zweimuelller 224