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