xref: /btstack/platform/daemon/binding/java/src/com/bluekitchen/btstack/BTstackClient.java (revision 398a95ec8e0d408db97ed8e80c67c74e30698a03)
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