📄 hcidriver.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 21, 2003
* by Christian Lorenz
*
*/
package org.javabluetooth.stack.hci;
import java.util.*;
import org.javabluetooth.stack.l2cap.L2CAPLink;
import org.javabluetooth.util.Debug;
/**
* This interface is implemented by Drivers for specific HCI Transports.
* Right now only UART is supported, but this interface will allow future drivers for other HCI Transports such as USB.
* @see org.javabluetooth.stack.hci.UARTTransport
* @author Christian Lorenz
*/
public abstract class HCIDriver {
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_CONNECTION_COMPLETE = 0x03;
private static final byte HCI_EVENT_DISCONNECTION_COMPLETE = 0x05;
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 HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS = 0x13;
private static HCIDriver hciDriver;
private byte[] commandResponse;
private short commandResponseOpCode = 0;
private Hashtable connectionHandels = new Hashtable();
private Hashtable remoteAddresses = new Hashtable();
private Vector hciReceivers = new Vector();
private byte[] headerBuffer = new byte[5];
private short headerBufferIndex = 0;
private byte[] packetBuffer;
private int packetBufferIndex;
public static void init(HCIDriver hciTransport) { HCIDriver.hciDriver = hciTransport; }
public static HCIDriver getHCIDriver() throws HCIException {
if (hciDriver == null) throw new HCIException("HCITransport not initalized. ");
return hciDriver;
}
public void registerHCIReceiver(HCIReceiver receiver) {
if (!hciReceivers.contains(receiver)) hciReceivers.addElement(receiver);
}
public void unregisterHCIReceiver(HCIReceiver receiver) { hciReceivers.removeElement(receiver); }
public void registerL2CAPLink(L2CAPLink link) {
Short handle = new Short(link.connectionHandle);
connectionHandels.put(handle, link);
Long remoteAddress = new Long(link.remoteAddress);
remoteAddresses.put(remoteAddress, link);
}
public void unregisterL2CAPLink(L2CAPLink link) {
connectionHandels.remove(new Short(link.connectionHandle));
remoteAddresses.remove(new Long(link.remoteAddress));
}
public L2CAPLink getL2CAPLink(long remoteAddress, byte pageScanRepMode, byte pageScanMode,
short clockOffset) throws HCIException {
Long remoteAddressLong = new Long(remoteAddress);
L2CAPLink link = (L2CAPLink)remoteAddresses.get(remoteAddressLong);
if (link == null) {
byte connResult = send_HCI_LC_Create_Connection(remoteAddress, (short)0x8000, pageScanRepMode, pageScanMode,
clockOffset, (byte)0x01);
if (connResult != 0) throw new HCIException("Create Connection failed. (" + connResult + ")");
short timeout = 0;
while (link == null) {
try {
Thread.sleep(1000);
timeout++;
}
catch (InterruptedException e) { }
if (timeout == 50) throw new HCIException("Create Connection timed out.");
link = (L2CAPLink)remoteAddresses.get(remoteAddressLong);
}
}
return link;
}
public synchronized byte[] send_HCI_Command_Packet(byte[] cmdPacket) throws HCIException {
short opCode = (short)((cmdPacket[2] << 8) | (cmdPacket[1] & 0xff));
Debug.println(1, "HCI: Sending Command: " + opCode);
while (commandResponse != null) {
try { this.wait(100); }
catch (InterruptedException e) { }
}
commandResponseOpCode = opCode;
hciDriver.sendPacket(cmdPacket);
//int timer=0;
while (commandResponse == null) {
try {
this.wait(500);
/*timer++;
if(timer==50)
{ timer=0;
Debug.println("HCI: Resending Command with opCode:" + opCode + ")");
hciTransport.sendPacket(cmdPacket);
}*/
}
catch (InterruptedException e) { }
}
byte[] result = commandResponse;
commandResponseOpCode = 0;
commandResponse = null;
/* The Brainboxes Bluetooth Host Controller seems to have a bug
* which causes the module to slow down to an unacceptable speed
* when an Inquiry Complete Event is send. This is a cheap hack to
* surpress the sending of this event by simply sending a Cancel
* Inquiry Command before it naturally Completes.
* before it completes.
*/
if ((cmdPacket[1] == 0x01) && (cmdPacket[2] == 0x04)) {
try { wait(10000); }
catch (InterruptedException e) { }
byte[] cancelInquiryPacket = { 0x01, 0x02, 0x04, 0x00 };
short cancelOpCode = (short)((cancelInquiryPacket[2] << 8) | (cancelInquiryPacket[1] & 0xff));
while (commandResponse != null) {
try { wait(100); }
catch (InterruptedException e) { }
}
commandResponseOpCode = cancelOpCode;
hciDriver.sendPacket(cancelInquiryPacket);
while (commandResponse == null) {
try { wait(100); }
catch (InterruptedException e) { }
}
commandResponseOpCode = 0;
commandResponse = null;
byte[] dummyPacket = { PACKET_TYPE_EVENT, HCI_EVENT_INQUIRY_COMPLETE, (byte)0x01, (byte)0x00 };
receive_HCI_Event_Inquiry_Complete(dummyPacket);
}
/* end of Hack */
return result;
}
public synchronized void send_HCI_Data_Packet(byte[] dataPacket) throws HCIException {
Debug.println(1, "HCI: Sending Data Packet.");
sendPacket(dataPacket);
}
/**
* This command will cause the Link Manager to create a connection
* to the Bluetooth device with the BD_ADDR specified by the command
* parameters. It is triggered by <code>HCITransport.getL2CAPLink()</code>. For details see Page 568 of the Bluetooth
* Core Specification Version 1.1
* @param bd_addr
* @param packetType
* @param clockOffset
* @param allowRoleSwitching
* @return return 0x00 if the command succeeded. 0x01-0xFF if the command failed. See Table 6.1 on page 766
* for list of Error Codes.
* @throws HCIException
*/
public byte send_HCI_LC_Create_Connection(long bd_addr, short packetType, byte pageScanRepMode, byte pageScanMode,
short clockOffset, byte allowRoleSwitching) throws HCIException {
byte[] data = {
0x01, 0x05, 0x04, 0x0d, (byte)((bd_addr) & 0xff), (byte)((bd_addr >> 8) & 0xff), (byte)((bd_addr >> 16) & 0xff),
(byte)((bd_addr >> 24) & 0xff), (byte)((bd_addr >> 32) & 0xff), (byte)((bd_addr >> 40) & 0xff), (byte)((packetType) & 0xff),
(byte)((packetType >> 8) & 0xff), (byte)pageScanRepMode, // Page scan repetition mode 1 byte
(byte)pageScanMode, // Page scan mode 1 byte
(byte)((clockOffset) & 0xff), // Clock offset 2 bytes
(byte)((clockOffset >> 8) & 0xff), (byte)allowRoleSwitching
}; // Allow role switch
byte[] resultData = send_HCI_Command_Packet(data);
return resultData[3];
}
/**
* The Disconnection command is used to terminate an existing connection.
* The Connection Handle indicates which connection is to be disconnected.
* It is triggered by <code>L2CAPLink.close()</code>. When the Host Controller receives the Disconnect command, it sends
* the Command Status event to the Host. The Disconnection Complete
* event will occur at each Host when the termination of the connection has
* completed, and indicates that this command has been completed.
* For details see Page 571 of the Bluetooth Core Specification Version 1.1
* @param connectionHandle Connection Handle for the connection being disconnected.
* @return 0x00 if the command succeeded. 0x01-0xFF if the command failed. See Table 6.1 on page 766
* for list of Error Codes.
* @throws HCIException
*/
public byte send_HCI_LC_Disconnect(short connectionHandle) throws HCIException {
byte[] data =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -