xref: /btstack/platform/daemon/binding/java/example/com/bluekitchen/SPPStreamerClient.java (revision 8ceba64edf9a6083c393c3791854d88b48704ce5)
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