xref: /btstack/platform/daemon/binding/java/example/com/bluekitchen/SPPStreamerClient.java (revision 6418890ec2728b03ec282297211783245bec3298)
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  *
34  * Adapt the remote MAC address in:
35  *
36  * example/com/bluekitchen/SPPStreamerClient.java
37  *
38  *  ant run
39  *
40  */
41 public class SPPStreamerClient implements PacketHandler {
42 
43     private final static int NUM_ROWS = 25;
44     private final static int NUM_COLS = 40;
45 
46     private enum STATE {
47         BTSTACK_WORKING, SDP_QUERY_RESULT, CONNECTED, SENDING
48     }
49 
50     private BTstack btstack;
51     private STATE state;
52 
53     private final BD_ADDR remote = new BD_ADDR("00:15:83:D1:17:9F");
54 
55     private int outgoing_channel_nr = -1;
56     private int rfcommChannelID = 0;
57 
58     private final static int REPORT_INTERVAL_MS = 3000;
59     private long test_data_transferred;
60     private long test_data_start;
61     private byte[] sppTestData;
62 
63 
64     private void createSppTestData(final int mtu) {
65         byte[] temp = new byte[NUM_ROWS * NUM_COLS];
66         int x, y;
67         for (y = 0; y < NUM_ROWS; y++) {
68             for (x = 0; x < NUM_COLS - 2; x++) {
69                 temp[y * NUM_COLS + x] = (byte) ('0' + (x % 10));
70             }
71             temp[y * NUM_COLS + NUM_COLS - 2] = '\n';
72             temp[y * NUM_COLS + NUM_COLS - 1] = '\r';
73         }
74 
75         // cut to MTU
76         sppTestData = new byte[Math.min(mtu, temp.length)];
77         System.arraycopy(temp, 0, sppTestData, 0, sppTestData.length);
78     }
79 
80     void testReset() {
81         test_data_start = System.currentTimeMillis();
82         test_data_transferred = 0;
83     }
84 
85     private void calculateSpeedAndLog(int bytesSent){
86         test_data_transferred += bytesSent;
87         // evaluate
88         long now = System.currentTimeMillis();
89         long timePassed = now - test_data_start;
90         if (timePassed < REPORT_INTERVAL_MS) return;
91 
92         // print speed
93         long bytesPerSecond = test_data_transferred * 1000 / timePassed;
94         System.out.printf("%d bytes -> %d.%03d kB/s\n", (int) test_data_transferred, (int) bytesPerSecond / 1000, bytesPerSecond % 1000);
95 
96         // restart
97         test_data_start = now;
98         test_data_transferred  = 0;
99     }
100 
101     private void startSDPQuery() {
102         state = STATE.SDP_QUERY_RESULT;
103         int sppUUID = 0x1101;
104         byte[] serviceSearchPattern = Util.serviceSearchPatternForUUID16(sppUUID);
105         btstack.SDPClientQueryRFCOMMServices(remote, serviceSearchPattern);
106     }
107 
108     public void handlePacket(Packet packet) {
109         if (packet instanceof HCIEventDisconnectionComplete) {
110             final HCIEventDisconnectionComplete event = (HCIEventDisconnectionComplete) packet;
111             System.out.printf("Received disconnect, status %d, handle %x%n", event.getStatus(), event.getConnectionHandle());
112             btstack.disconnect();
113             return;
114         }
115 
116         switch (state) {
117             case BTSTACK_WORKING:
118                 if (packet instanceof BTstackEventState) {
119                     final BTstackEventState event = (BTstackEventState) packet;
120                     if (event.getState() == 2) {
121                         System.out.println("BTstack working. Start SDP inquiry.");
122                         startSDPQuery();
123                     }
124                 }
125                 break;
126 
127             case SDP_QUERY_RESULT:
128                 if (packet instanceof SDPEventQueryRFCOMMService) {
129                     final SDPEventQueryRFCOMMService service = (SDPEventQueryRFCOMMService) packet;
130                     System.out.println("Found RFCOMM channel " + service.getName() + ", channel nr: " + service.getRFCOMMChannel());
131                     outgoing_channel_nr = service.getRFCOMMChannel();
132                 }
133                 if (packet instanceof SDPEventQueryComplete) {
134                     SDPEventQueryComplete complete = (SDPEventQueryComplete) packet;
135                     if (complete.getStatus() != 0) {
136                         System.out.printf("SDP Query failed with status 0x%02x, retry SDP query.%n", complete.getStatus());
137                         startSDPQuery();
138                         break;
139                     }
140                     if (outgoing_channel_nr >= 0) {
141                         state = STATE.CONNECTED;
142                         System.out.println("Connect to channel nr " + outgoing_channel_nr);
143                         btstack.RFCOMMCreateChannel(remote, outgoing_channel_nr);
144                     }
145                 }
146                 break;
147 
148             case CONNECTED:
149                 if (packet instanceof RFCOMMEventChannelOpened) {
150                     RFCOMMEventChannelOpened e = (RFCOMMEventChannelOpened) packet;
151                     System.out.println("RFCOMMEventChannelOpened with status " + e.getStatus());
152                     if (e.getStatus() != 0) {
153                         System.out.println("RFCOMM channel open failed, status " + e.getStatus());
154                     } else {
155                         state = STATE.SENDING;
156                         rfcommChannelID = e.getRFCOMMCid();
157                         System.out.printf("RFCOMM channel open succeeded. New RFCOMM Channel ID %d, max frame size %d%n", rfcommChannelID, e.getMaxFrameSize());
158 
159                         createSppTestData(e.getMaxFrameSize());
160                         testReset();
161 
162                         btstack.RFCOMMRequestCanSendNow(e.getRFCOMMCid());
163                     }
164                 }
165                 break;
166 
167             case SENDING:
168                 if (packet instanceof RFCOMMEventCanSendNow) {
169                     btstack.RFCOMMSendData(rfcommChannelID, sppTestData);
170                     calculateSpeedAndLog(sppTestData.length);
171                     btstack.RFCOMMRequestCanSendNow(rfcommChannelID);
172                 }
173 
174                 if (packet instanceof RFCOMMDataPacket) {
175                     // duplex
176                     calculateSpeedAndLog(sppTestData.length);
177                 }
178             default:
179                 break;
180         }
181     }
182 
183     void stream() {
184         System.out.println("SPP Streamer Client");
185 
186         // connect to BTstack Daemon via default port on localhost
187         // start: src/BTdaemon --tcp
188 
189         btstack = new BTstack();
190         btstack.setTcpPort(BTstack.DEFAULT_TCP_PORT);
191         btstack.registerPacketHandler(this);
192         boolean ok = btstack.connect();
193         if (!ok) {
194             System.out.println("Failed to connect to BTstack Server");
195             return;
196         }
197 
198         System.out.println("BTstackSetPowerMode(1)");
199 
200         state = STATE.BTSTACK_WORKING;
201         btstack.BTstackSetPowerMode(1);
202     }
203 
204     public static void main(String[] args) {
205         new SPPStreamerClient().stream();
206     }
207 }
208 
209