1 package com.bluekitchen.btstack; 2 3 import com.bluekitchen.btstack.event.BTstackEventDaemonDisconnect; 4 5 public class BTstackClient { 6 7 /** 8 * BTstack Server Client 9 * uses background receive thread 10 */ 11 12 public static final int DEFAULT_TCP_PORT = 13333; 13 public static final String DEFAULT_UNIX_SOCKET = "/tmp/BTstack"; 14 15 private volatile SocketConnection socketConnection; 16 private PacketHandler packetHandler; 17 private boolean connected; 18 private int logicTime = 1; 19 private Thread rxThread; 20 private String unixDomainSocketPath; 21 private int tcpPort; 22 BTstackClient()23 public BTstackClient(){ 24 connected = false; 25 socketConnection = null; 26 rxThread = null; 27 } 28 setUnixDomainSocketPath(String path)29 public void setUnixDomainSocketPath(String path){ 30 this.unixDomainSocketPath = path; 31 } 32 setTcpPort(int port)33 public void setTcpPort(int port){ 34 this.tcpPort = port; 35 } 36 registerPacketHandler(PacketHandler packetHandler)37 public void registerPacketHandler(PacketHandler packetHandler){ 38 this.packetHandler = packetHandler; 39 } 40 connect()41 public boolean connect(){ 42 43 rxThread = null; 44 45 if (tcpPort == 0){ 46 try { 47 Class<?> clazz = Class.forName("com.bluekitchen.btstack.SocketConnectionUnix"); 48 socketConnection = (SocketConnection) clazz.newInstance(); 49 if (unixDomainSocketPath != null){ 50 socketConnection.setUnixDomainSocketPath(unixDomainSocketPath); 51 } 52 } catch (ClassNotFoundException e) { 53 e.printStackTrace(); 54 return false; 55 } catch (InstantiationException e) { 56 e.printStackTrace(); 57 return false; 58 } catch (IllegalAccessException e) { 59 e.printStackTrace(); 60 return false; 61 } 62 63 } else { 64 // TODO implement SocketConnectionTcp 65 socketConnection = new SocketConnectionTCP(); 66 socketConnection.setTcpPort(tcpPort); 67 } 68 69 connected = socketConnection.connect(); 70 if (!connected) return false; 71 72 logicTime++; 73 final int rxThreadId = logicTime; 74 final SocketConnection threadSocketConnection = socketConnection; 75 rxThread = new Thread(new Runnable(){ 76 @Override 77 public void run() { 78 while (logicTime == rxThreadId){ 79 Packet packet = threadSocketConnection.receivePacket(); 80 if (Thread.currentThread().isInterrupted()){ 81 System.out.println("Rx Thread: exit via interrupt, thread id " + rxThreadId); 82 return; 83 } 84 if (packet == null) { 85 // server disconnected 86 System.out.println("Rx Thread: Daemon Disconnected"); 87 packetHandler.handlePacket(new BTstackEventDaemonDisconnect()); 88 return; 89 } 90 switch (packet.getPacketType()){ 91 case Packet.HCI_EVENT_PACKET: 92 packetHandler.handlePacket(EventFactory.eventForPacket(packet)); 93 break; 94 case Packet.L2CAP_DATA_PACKET: 95 packetHandler.handlePacket(new L2CAPDataPacket(packet)); 96 break; 97 case Packet.RFCOMM_DATA_PACKET: 98 packetHandler.handlePacket(new RFCOMMDataPacket(packet)); 99 break; 100 default: 101 packetHandler.handlePacket(packet); 102 break; 103 } 104 } 105 System.out.println("Rx Thread: exit via logic time change, thread id " + rxThreadId); 106 } 107 }); 108 rxThread.start(); 109 110 return true; 111 } 112 sendPacket(Packet packet)113 public boolean sendPacket(Packet packet){ 114 if (socketConnection == null) return false; 115 return socketConnection.sendPacket(packet); 116 } 117 L2CAPSendData(int l2capChannelID, byte[] data)118 public boolean L2CAPSendData(int l2capChannelID, byte[] data){ 119 return sendPacket(new L2CAPDataPacket(l2capChannelID, data)); 120 } 121 RFCOMMSendData(int rfcommChannelID, byte[] data)122 public boolean RFCOMMSendData(int rfcommChannelID, byte[] data){ 123 return sendPacket(new RFCOMMDataPacket(rfcommChannelID, data)); 124 } 125 disconnect()126 public void disconnect(){ 127 if (socketConnection == null) return; 128 129 logicTime++; 130 131 // check if we're called on rx thread 132 if (Thread.currentThread() != rxThread){ 133 134 // signal rx thread to stop 135 rxThread.interrupt(); 136 137 // unblock read by sending an arbitrary command 138 if (this instanceof BTstack){ 139 BTstack btstack = (BTstack) this; 140 btstack.BTstackGetState(); 141 } 142 143 // wait for thread to stop 144 try { 145 rxThread.join(); 146 } catch (InterruptedException e){ 147 System.out.println("Unexpected interrupted execption waiting for receive thread to terminate"); 148 e.printStackTrace(); 149 } 150 } 151 152 // disconnect socket -> triggers IOException on read 153 socketConnection.disconnect(); 154 155 // done 156 socketConnection = null; 157 } 158 } 159