File content as of revision 3:37e5ebd509ea:
/*
Copyright (c) 2010 Peter Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef HCI_H_INCLUDED
#define HCI_H_INCLUDED
#include "Socket.h"
#pragma pack(1)
#define ERR_HCI_DEVICE_NOT_FOUND -300
class HCI;
class HCITransport;
class BTDevice;
typedef struct
{
u8 addr[6];
} BD_ADDR;
typedef struct
{
BD_ADDR bdaddr;
u8 pscan_rep_mode;
u8 pscan_period_mode;
u8 pscan_mode;
u8 dev_class[3];
u16 clock_offset;
} inquiry_info;
typedef struct
{
u8 status;
u16 handle;
BD_ADDR bdaddr;
u8 link_type;
u8 encr_mode;
} connection_info;
// Address struct for creating L2CAP sockets
typedef struct {
SocketAddrHdr hdr;
BD_ADDR bdaddr;
u16 psm;
} L2CAPAddr;
#pragma pack(4)
class BTDevice;
typedef struct
{
public:
SocketInternal si;
BTDevice* btdevice;
u16 scid;
u16 dcid;
} L2CAPSocket;
#define MAX_HCL_NAME_LENGTH 20 // TODO - BTDevice wants to be a multiple of 4
// BTDevice encapsulates individual device state
// It provides L2CAP layer sockets
class BTDevice : public SocketHandler
{
public:
HCITransport* _transport;
inquiry_info _info;
u16 _handle; // acl connection handle
u8 _state; // connection state
u8 _txid;
char _name[MAX_HCL_NAME_LENGTH];
void Init();
BD_ADDR* GetAddress() { return &_info.bdaddr; }
// Called from HCI
void ACLRecv(const u8* data, int len);
// SocketHandler
virtual int Open(SocketInternal* sock, SocketAddrHdr* addr);
virtual int Send(SocketInternal* sock, const u8* data, int len);
virtual int Close(SocketInternal* sock);
private:
L2CAPSocket* SCIDToSocket(int scid);
int Send(const u8* data, int len);
int Send(u8 c, u8 id, u16* params, int count);
int Connect(int scid, int psm);
int Disconnect(int scid, int dcid);
int ConfigureRequest(int dcid);
int ConfigureResponse(u8 rxid, int dcid);
int DisconnectResponse(u8 rxid, int scid, int dcid);
void Control(const u8* data, int len);
};
enum HCI_CALLBACK_EVENT
{
CALLBACK_NONE,
CALLBACK_READY,
CALLBACK_INQUIRY_RESULT,
CALLBACK_INQUIRY_DONE,
CALLBACK_REMOTE_NAME,
CALLBACK_CONNECTION_COMPLETE,
CALLBACK_CONNECTION_FAILED
};
// L2CAP Protocol/Service Multiplexor (PSM) values
#define L2CAP_PSM_ANY 0x0000 /* Any/Invalid PSM */
#define L2CAP_PSM_SDP 0x0001 /* Service Discovery Protocol */
#define L2CAP_PSM_RFCOMM 0x0003 /* RFCOMM protocol */
#define L2CAP_PSM_TCP 0x0005 /* Telephony Control Protocol */
#define L2CAP_PSM_TCS 0x0007 /* TCS cordless */
#define L2CAP_PSM_BNEP 0x000f /* Bluetooth Network Encapsulation Protocol*/
#define L2CAP_PSM_HID_CNTL 0x0011 /* HID Control */
#define L2CAP_PSM_HID_INTR 0x0013 /* HID Interrupt */
#define L2CAP_PSM_ESDP 0x0015 /* Extended Service Discovery Profile */
#define L2CAP_PSM_AVCTP 0x0017 /* Audio/Visual Control Transport Protocol */
#define L2CAP_PSM_AVDTP 0x0019 /* Audio/Visual Distribution */
// Callback from inquiry
typedef int (*HCICallback)(HCI* hci, HCI_CALLBACK_EVENT evt, const u8* data, int len);
#define MAX_BTDEVICES 8
class HCITransport;
class HCI : public SocketHandler
{
HCITransport* _transport;
HCICallback _callback;
BD_ADDR _localAddr;
BTDevice _devices[MAX_BTDEVICES];
int _deviceCount;
int _acl_mtu;
int _acl_max_pkt;
int _sco_mtu;
int _sco_max_pkt;
int _state;
public:
// Open a local adapter
int Open(HCITransport* transport, HCICallback callback);
// Return list of discovered addreses
int GetDevices(BTDevice** devices, int maxDevices);
// Lookup a device by address or handle
BTDevice* Find(const BD_ADDR* addr);
BTDevice* Find(int handle);
// Disconnect from a remote device
int Disconnect(const BD_ADDR* addr);
int DisconnectAll();
// see what devies are in the system
int Inquiry(int duration = 10);
// get a name, delivered in callback
int RemoteNameRequest(const BD_ADDR* addr);
// Connect to a remote device
int CreateConnection(const BD_ADDR* remoteAddr);
bool Busy();
// called from transport
void HCIRecv(const u8* data, int len);
// called from transport
void ACLRecv(const u8* data, int len);
// SocketHandler methods for maintaining L2CAP sockets
virtual int Open(SocketInternal* sock, SocketAddrHdr* addr);
virtual int Send(SocketInternal* sock, const u8* data, int len);
virtual int Close(SocketInternal* sock);
private:
void InquiryResult(const inquiry_info* info);
void RemoteName(const BD_ADDR* addr, const char* name);
void ConnectComplete(const connection_info* info);
void DisconnectComplete(int handle);
int SendCmd(int cmd, const u8* params = 0, int len = 0);
void OnCommandComplete(int cmd, const u8* data, int len);
void Callback(HCI_CALLBACK_EVENT c, const u8* data, int len);
int PinCodeReply(const u8* data);
};
class HCITransport
{
protected:
HCI* _target;
public:
void Set(HCI* target) { _target = target; };
virtual void HCISend(const u8* data, int len) = 0;
virtual void ACLSend(const u8* data, int len) = 0;
};
#endif