xref: /btstack/platform/daemon/binding/java/example/com/bluekitchen/SPPStreamerClient.java (revision 2281ada7921e55288a45180ce35a34d9af2af65c)
1 package com.bluekitchen;
2 
3 import com.bluekitchen.btstack.BD_ADDR;
4 import com.bluekitchen.btstack.BTstack;
5 import com.bluekitchen.btstack.Packet;
6 import com.bluekitchen.btstack.PacketHandler;
7 import com.bluekitchen.btstack.RFCOMMDataPacket;
8 import com.bluekitchen.btstack.Util;
9 import com.bluekitchen.btstack.event.*;
10 
11 /**
12  * Simple demonstration of the Java binding by streaming data over SPP.
13  *
14  * This is the same example as the: example/spp_streamer_client.c example.
15  *
16  * It can be run against the 'spp_streamer' example.
17  *
18  * To run, two dongles are needed, then:
19  *
20  * 1. In a first terminal run:
21  *
22  * cd port/libusb
23  * ./spp_streamer
24  *
25  * 2. In a second terminal, run the daemon:
26  *
27  * cd port/daemon
28  * ./src/BTdaemon --tcp
29  *
30  * 3. In a third terminal, run the java application:
31  *
32  * cd platform/daemon/binding/java
33  * ant run
34  */
35 public class SPPStreamerClient implements PacketHandler {
36 
37     private final static int NUM_ROWS = 25;
38     private final static int NUM_COLS = 40;
39     public static final int TEST_COD = 0x1234;
40 
41     private enum STATE {
42         BTSTACK_WORKING, INQUIRY_RESULT, SDP_QUERY_RESULT, CONNECTED, SENDING
43     }
44 
45     private BTstack btstack;
46     private STATE state;
47 
48     private BD_ADDR remote;
49 
50     private int outgoing_channel_nr = -1;
51     private int rfcommChannelID = 0;
52 
53     private final static int REPORT_INTERVAL_MS = 3000;
54     private long test_data_transferred;
55     private long test_data_start;
56     private byte[] sppTestData;
57 
58 
59     private void createSppTestData(final int mtu) {
60         byte[] temp = new byte[NUM_ROWS * NUM_COLS];
61         int x, y;
62         for (y = 0; y < NUM_ROWS; y++) {
63             for (x = 0; x < NUM_COLS - 2; x++) {
64                 temp[y * NUM_COLS + x] = (byte) ('0' + (x % 10));
65             }
66             temp[y * NUM_COLS + NUM_COLS - 2] = '\n';
67             temp[y * NUM_COLS + NUM_COLS - 1] = '\r';
68         }
69 
70         // cut to MTU
71         sppTestData = new byte[Math.min(mtu, temp.length)];
72         System.arraycopy(temp, 0, sppTestData, 0, sppTestData.length);
73     }
74 
75     void testReset() {
76         test_data_start = System.currentTimeMillis();
77         test_data_transferred = 0;
78     }
79 
80     private void calculateSpeedAndLog(int bytesSent){
81         test_data_transferred += bytesSent;
82         // evaluate
83         long now = System.currentTimeMillis();
84         long timePassed = now - test_data_start;
85         if (timePassed < REPORT_INTERVAL_MS) return;
86 
87         // print speed
88         long bytesPerSecond = test_data_transferred * 1000 / timePassed;
89         System.out.printf("%d bytes -> %d.%03d kB/s\n", (int) test_data_transferred, (int) bytesPerSecond / 1000, bytesPerSecond % 1000);
90 
91         // restart
92         test_data_start = now;
93         test_data_transferred  = 0;
94     }
95 
96     private void startSDPQuery() {
97         state = STATE.SDP_QUERY_RESULT;
98         int sppUUID = 0x1101;
99         byte[] serviceSearchPattern = Util.serviceSearchPatternForUUID16(sppUUID);
100         btstack.SDPClientQueryRFCOMMServices(remote, serviceSearchPattern);
101     }
102 
103     public void handlePacket(Packet packet) {
104         if (packet instanceof HCIEventDisconnectionComplete) {
105             final HCIEventDisconnectionComplete event = (HCIEventDisconnectionComplete) packet;
106             System.out.printf("Received disconnect, status %d, handle %x%n", event.getStatus(), event.getConnectionHandle());
107             btstack.disconnect();
108             return;
109         }
110 
111         switch (state) {
112             case BTSTACK_WORKING:
113                 if (packet instanceof BTstackEventState) {
114                     final BTstackEventState event = (BTstackEventState) packet;
115                     if (event.getState() == 2) {
116                         System.out.println("BTstack working. Start inquiry..");
117                         state = STATE.INQUIRY_RESULT;
118                         btstack.GAPInquiryStart(5);
119                     }
120                 }
121                 break;
122 
123             case INQUIRY_RESULT:
124                 if (packet instanceof GAPEventInquiryResult) {
125                     final GAPEventInquiryResult event = ((GAPEventInquiryResult) packet);
126                     System.out.printf("Found device with COD: %d with address: %s\n", event.getClassOfDevice(), event.getBdAddr());
127                     if (event.getClassOfDevice() == TEST_COD) {
128                         remote = event.getBdAddr();
129                         btstack.GAPInquiryStop();
130                         System.out.println("Start SDP query on: " + remote);
131                         startSDPQuery();
132                     }
133                 }
134                 if (packet instanceof GAPEventInquiryComplete) {
135                     if (remote == null) {
136                         System.out.println("No device with COD: %d found -> scan again.");
137                         btstack.GAPInquiryStart(5);
138                     }
139                 }
140                 break;
141 
142             case SDP_QUERY_RESULT:
143                 if (packet instanceof SDPEventQueryRFCOMMService) {
144                     final SDPEventQueryRFCOMMService service = (SDPEventQueryRFCOMMService) packet;
145                     System.out.println("Found RFCOMM channel " + service.getName() + ", channel nr: " + service.getRFCOMMChannel());
146                     outgoing_channel_nr = service.getRFCOMMChannel();
147                 }
148                 if (packet instanceof SDPEventQueryComplete) {
149                     SDPEventQueryComplete complete = (SDPEventQueryComplete) packet;
150                     if (complete.getStatus() != 0) {
151                         System.out.printf("SDP Query failed with status 0x%02x, retry SDP query.%n", complete.getStatus());
152                         startSDPQuery();
153                         break;
154                     }
155                     if (outgoing_channel_nr >= 0) {
156                         state = STATE.CONNECTED;
157                         System.out.println("Connect to channel nr " + outgoing_channel_nr);
158                         btstack.RFCOMMCreateChannel(remote, outgoing_channel_nr);
159                     }
160                 }
161                 break;
162 
163             case CONNECTED:
164                 if (packet instanceof RFCOMMEventChannelOpened) {
165                     RFCOMMEventChannelOpened e = (RFCOMMEventChannelOpened) packet;
166                     System.out.println("RFCOMMEventChannelOpened with status " + e.getStatus());
167                     if (e.getStatus() != 0) {
168                         System.out.println("RFCOMM channel open failed, status " + e.getStatus());
169                     } else {
170                         state = STATE.SENDING;
171                         rfcommChannelID = e.getRFCOMMCid();
172                         System.out.printf("RFCOMM channel open succeeded. New RFCOMM Channel ID %d, max frame size %d%n", rfcommChannelID, e.getMaxFrameSize());
173 
174                         createSppTestData(e.getMaxFrameSize());
175                         testReset();
176 
177                         btstack.RFCOMMRequestCanSendNow(e.getRFCOMMCid());
178                     }
179                 }
180                 break;
181 
182             case SENDING:
183                 if (packet instanceof RFCOMMEventCanSendNow) {
184                     btstack.RFCOMMSendData(rfcommChannelID, sppTestData);
185                     calculateSpeedAndLog(sppTestData.length);
186                     btstack.RFCOMMRequestCanSendNow(rfcommChannelID);
187                 }
188 
189                 if (packet instanceof RFCOMMDataPacket) {
190                     // duplex
191                     calculateSpeedAndLog(sppTestData.length);
192                 }
193             default:
194                 break;
195         }
196     }
197 
198     void stream() {
199         System.out.println("SPP Streamer Client");
200 
201         // connect to BTstack Daemon via default port on localhost
202         // start: src/BTdaemon --tcp
203 
204         btstack = new BTstack();
205         btstack.setTcpPort(BTstack.DEFAULT_TCP_PORT);
206         btstack.registerPacketHandler(this);
207         boolean ok = btstack.connect();
208         if (!ok) {
209             System.out.println("Failed to connect to BTstack Server");
210             return;
211         }
212 
213         System.out.println("BTstackSetPowerMode(1)");
214 
215         state = STATE.BTSTACK_WORKING;
216         btstack.BTstackSetPowerMode(1);
217     }
218 
219     public static void main(String[] args) {
220         new SPPStreamerClient().stream();
221     }
222 }
223 
224