📄 bluetoothtcpclient.java
字号:
/*
* (c) Copyright 2003 Christian Lorenz ALL RIGHTS RESERVED.
*
* This file is part of the JavaBluetooth Stack.
*
* The JavaBluetooth Stack is free software; you can redistribute it
* and/or modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* The JavaBluetooth Stack is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Created on May 23, 2003
* by Christian Lorenz
*
*/
package org.javabluetooth.distributed;
import java.io.*;
import java.net.*;
import javax.bluetooth.RemoteDevice;
import org.javabluetooth.stack.BluetoothStack;
import org.javabluetooth.stack.hci.HCIException;
import org.javabluetooth.stack.l2cap.L2CAPChannel;
import org.javabluetooth.stack.l2cap.L2CAPSender;
import org.javabluetooth.util.Debug;
/**
* This implementation of <code>BluetoothStack</code> connects via TCP
* to a <code>BluetoothTCPServer</code>. This server provides the interface
* to a remote <code>HCITransport</code> and allows multiple <code>BluetoothTCPClient</code> instances to
* share one Bluetooth Device.
* @see org.javabluetooth.stack.BluetoothStack
* @see org.javabluetooth.stack.server.BluetoothTCPServer
* @author Christian Lorenz
*/
public class BluetoothTCPClient extends BluetoothStack implements L2CAPSender, Runnable {
//private static final byte PACKET_TYPE_ACL = 0x02;
private static final byte PACKET_TYPE_EVENT = 0x04;
private static final byte HCI_EVENT_INQUIRY_COMPLETE = 0x01;
private static final byte HCI_EVENT_INQUIRY_RESULT = 0x02;
private static final byte HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE = 0x07;
private static final byte HCI_EVENT_COMMAND_COMPLETE = 0x0E;
private static final byte HCI_EVENT_COMMAND_STATUS = 0x0F;
private static final byte L2CAP_CREATE_CONNECTION_REQUEST = (byte)0xf0;
private static final byte L2CAP_CREATE_CONNECTION_RESPONSE = (byte)0xf1;
private static final byte L2CAP_DISCONNECT_CHANNEL_REQUEST = (byte)0xf2;
private static final byte SDP_REGISTER_SERVICE_REQUEST = (byte)0xf3;
private static final byte L2CAP_PACKET = (byte)0xff;
private Socket socket;
private InputStream socketIn;
private OutputStream socketOut;
private boolean isConnected;
private byte[] commandResponse;
private short commandResponseOpCode;
private L2CAPChannel[] channels;
/**
* Connects to the <code>BluetoothTCPServer</code> at <code>remoteAddress</code>
* and starts a new <code>Thread</code> receiving and parsing Event Packets.
* @param remoteAddress
* @param remotePort
* @throws HCIException
*/
public BluetoothTCPClient(String remoteAddress, int remotePort) throws HCIException {
try {
channels = new L2CAPChannel[16];
socket = new Socket(remoteAddress, remotePort);
socketIn = socket.getInputStream();
socketOut = socket.getOutputStream();
isConnected = true;
Thread thisThread = new Thread(this);
thisThread.start();
}
catch (UnknownHostException e) {
throw new HCIException("HCIManagerRemoteClient: Unknown Host " + remoteAddress + ":" + remotePort + ". " + e);
}
catch (IOException e) { throw new HCIException("HCIManagerRemoteClient: IOException: " + e); }
}
/** @see org.javabluetooth.stack.BluetoothStack#send_HCI_Command_Packet(byte[]) */
public byte[] send_HCI_Command_Packet(byte[] cmdPacket) throws HCIException {
short opCode = (short)((cmdPacket[2] << 8) | (cmdPacket[1] & 0xff));
while (commandResponse != null) {
try { this.wait(100); }
catch (InterruptedException e) { }
}
commandResponseOpCode = opCode;
try {
Debug.println(6, "BluetoothTCPClient: Sending HCI Command:", cmdPacket);
socketOut.write(cmdPacket);
socketOut.flush();
}
catch (IOException e) {
cleanExit();
throw new HCIException("IOException: " + e);
}
int timer = 0;
while (commandResponse == null) {
try {
Thread.sleep(500);
timer++;
if (timer == 100) { throw new HCIException("Command Packet Response Timed Out. "); }
}
catch (InterruptedException e) { }
}
byte[] result = commandResponse;
commandResponseOpCode = 0;
commandResponse = null;
return result;
}
/**
* Run Loop of the Client Thread. This loop reads data from the socket
* and parses it into Event Packets which are then dispatched to their proper receive methods.
* @see java.lang.Runnable#run()
*/
public void run() {
try {
byte[] headerBuffer = new byte[3];
short headerBufferIndex = 0;
byte[] packetBuffer = { };
int packetBufferIndex = 0;
while (isConnected) {
byte[] incomingBytes = new byte[32];
int incomingLength = socketIn.read(incomingBytes);
//Debug.println("read"+Debug.printByteArray(incomingBytes));
if (incomingLength == -1) break;
int incomingBytesIndex = 0;
while (incomingBytesIndex < incomingLength) //process all received bytes
{
if (headerBufferIndex < headerBuffer.length) //header is still incomplete
{
int length = headerBuffer.length - headerBufferIndex;
if (length > incomingLength - incomingBytesIndex) length = incomingLength - incomingBytesIndex;
System.arraycopy(incomingBytes, incomingBytesIndex, headerBuffer, headerBufferIndex, length);
incomingBytesIndex += length;
headerBufferIndex += length;
if (headerBufferIndex == headerBuffer.length)
//header is complete
{ //creates Packet and copy header into packet.
switch (headerBuffer[0]) {
case L2CAP_CREATE_CONNECTION_RESPONSE:
case L2CAP_DISCONNECT_CHANNEL_REQUEST:
case L2CAP_PACKET:
packetBuffer = new byte[3 + (short)
(((short)headerBuffer[2] & 0xff) << 8 | ((short)headerBuffer[1] & 0xff))];
System.arraycopy(headerBuffer, 0, packetBuffer, 0, headerBuffer.length);
packetBufferIndex = headerBuffer.length;
break;
case PACKET_TYPE_EVENT:
packetBuffer = new byte[3 + (short)(((short)headerBuffer[2]) & 0xff)];
System.arraycopy(headerBuffer, 0, packetBuffer, 0, headerBuffer.length);
packetBufferIndex = headerBuffer.length;
break;
default:
headerBufferIndex = 0; //reset packet parser
incomingBytesIndex -= (headerBuffer.length - 1);
System.err.println("BluetoothTCPClient: Received Invalid Packet Header" + headerBuffer);
}
}
}
if (headerBufferIndex == headerBuffer.length) //header is complete. copy data to packet.
{
int length = packetBuffer.length - packetBufferIndex;
if (length > incomingLength - incomingBytesIndex) length = incomingLength - incomingBytesIndex;
System.arraycopy(incomingBytes, incomingBytesIndex, packetBuffer, packetBufferIndex, length);
incomingBytesIndex += length;
packetBufferIndex += length;
if (packetBufferIndex == packetBuffer.length) { //packet is complete
dispatchPacket(packetBuffer);
headerBufferIndex = 0;
}
}
}
}
}
catch (IOException e) { System.err.println("BluetoothTCPClient: IOException: " + e); }
cleanExit();
}
/** Closes Sockets cleanly and causes the run() method to exit properly. Also changes all L2CAPChannels to CLOSED. */
private void cleanExit() {
Debug.println(6, "BluetoothTCPClient: Disconnecting.");
isConnected = false;
for (int i = 0; i < channels.length; i++) {
if (channels[i] != null) {
channels[i].channelState = L2CAPChannel.CLOSED;
channels[i].wasDisconnected();
}
}
try { socketIn.close(); }
catch (IOException e) { }
try { socketOut.close(); }
catch (IOException e) { }
try { socket.close(); }
catch (IOException e) { }
}
/** Dispatches Event Packets to their proppe receive methods. */
private void dispatchPacket(byte[] packet) {
//Debug.println(7,"BluetoothTCPClient: Received: ",packet);
switch (packet[0]) //Packet Type
{
case PACKET_TYPE_EVENT:
switch (packet[1]) //Event Type
{
case HCI_EVENT_INQUIRY_COMPLETE:
Debug.println(6, "BluetoothTCPClient: Received HCI Inquiry Complete Event:", packet);
receive_HCI_Event_Inquiry_Complete(packet);
break;
case HCI_EVENT_INQUIRY_RESULT:
Debug.println(6, "BluetoothTCPClient: Received HCI Inquiry Result Event:", packet);
receive_HCI_Event_Inquiry_Result(packet);
break;
case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
Debug.println(6, "BluetoothTCPClient: Received HCI Remote Name Request Complete Event:", packet);
receive_HCI_Event_Remote_Name_Request_Complete(packet);
break;
case HCI_EVENT_COMMAND_COMPLETE:
Debug.println(6, "BluetoothTCPClient: Received HCI Command Complete Event:", packet);
receive_HCI_Event_Command_Complete(packet);
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -