Test version of BlueUSB stack. Includes SDP and RFCOMM. As Client it allows to connect to my fischertechnik TX Controller. As Server it echo\\\\\\\'s characters to Putty. PIN=1234
Dependencies: mbed myUSBHost AvailableMemory
Dependents: mbed_TANK_Kinect myBlueUSB_ros ftusbClass
Revision 0:81ed8b6e4a8b, committed 2011-04-04
- Comitter:
- networker
- Date:
- Mon Apr 04 16:41:03 2011 +0000
- Child:
- 1:0dde58e0cccf
- Commit message:
- initial revision
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/HCITransportUSB.h Mon Apr 04 16:41:03 2011 +0000
@@ -0,0 +1,46 @@
+#ifndef HCITRANSPORTUSB_H
+#define HCITRANSPORTUSB_H
+#define MAX_HCL_SIZE 260
+#define MAX_ACL_SIZE 400
+#include "USBHost.h"
+
+extern int bulk;
+
+class HCITransportUSB : public HCITransport {
+ int _device;
+ u8* _hciBuffer;
+ u8* _aclBuffer;
+
+public:
+ void Open(int device, u8* hciBuffer, u8* aclBuffer) {
+ _device = device;
+ _hciBuffer = hciBuffer;
+ _aclBuffer = aclBuffer;
+ USBInterruptTransfer(_device,0x81,_hciBuffer,MAX_HCL_SIZE,HciCallback,this);
+ USBBulkTransfer(_device,0x82,_aclBuffer,MAX_ACL_SIZE,AclCallback,this);
+ }
+
+ static void HciCallback(int device, int endpoint, int status, u8* data, int len, void* userData) {
+ HCI* t = ((HCITransportUSB*)userData)->_target;
+ if (t)
+ t->HCIRecv(data,len);
+ USBInterruptTransfer(device,0x81,data,MAX_HCL_SIZE,HciCallback,userData);
+ }
+
+ static void AclCallback(int device, int endpoint, int status, u8* data, int len, void* userData) {
+ HCI* t = ((HCITransportUSB*)userData)->_target; //printf("ACL: %d bytes avail\n", len);
+ if (t)
+ t->ACLRecv(data,len);
+ USBBulkTransfer(device,0x82,data,MAX_ACL_SIZE,AclCallback,userData);
+ }
+
+ virtual void HCISend(const u8* data, int len) {
+ USBControlTransfer(_device,REQUEST_TYPE_CLASS, 0, 0, 0,(u8*)data,len);
+ }
+
+ virtual void ACLSend(const u8* data, int len) {
+ USBBulkTransfer(_device,0x02,(u8*)data,len);
+ }
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/L2CAP.cpp Mon Apr 04 16:41:03 2011 +0000
@@ -0,0 +1,569 @@
+/*
+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.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "Utils.h"
+#include "hci.h"
+#include "HCITransportUSB.h"
+
+#define L2CAP_COMMAND_REJ 0x01
+#define L2CAP_CONN_REQ 0x02
+#define L2CAP_CONN_RSP 0x03
+#define L2CAP_CONF_REQ 0x04
+#define L2CAP_CONF_RSP 0x05
+#define L2CAP_DISCONN_REQ 0x06
+#define L2CAP_DISCONN_RSP 0x07
+#define L2CAP_ECHO_REQ 0x08
+#define L2CAP_ECHO_RSP 0x09
+#define L2CAP_INFO_REQ 0x0a
+#define L2CAP_INFO_RSP 0x0b
+
+//template <class T> T min(T a, T b) { return a<b ? a : b;}
+
+/* L2CAP command codes */
+const char* L2CAP_ComandCodeStr(int c) {
+ switch (c) {
+ case L2CAP_COMMAND_REJ:
+ return "L2CAP_COMMAND_REJ";
+ case L2CAP_CONN_REQ:
+ return "L2CAP_CONN_REQ";
+ case L2CAP_CONN_RSP:
+ return "L2CAP_CONN_RSP";
+ case L2CAP_CONF_REQ:
+ return "L2CAP_CONF_REQ";
+ case L2CAP_CONF_RSP:
+ return "L2CAP_CONF_RSP";
+ case L2CAP_DISCONN_REQ:
+ return "L2CAP_DISCONN_REQ";
+ case L2CAP_DISCONN_RSP:
+ return "L2CAP_DISCONN_RSP";
+ case L2CAP_ECHO_REQ:
+ return "L2CAP_ECHO_REQ";
+ case L2CAP_ECHO_RSP:
+ return "L2CAP_ECHO_RSP";
+ case L2CAP_INFO_REQ:
+ return "L2CAP_INFO_REQ";
+ case L2CAP_INFO_RSP:
+ return "L2CAP_INFO_RSP";
+ }
+ return "unknown";
+}
+
+#define OFFSET 8 //means the buffer also has space for the l2cap/hci headers and need not be allocated and copied
+//#define OFFSET 0 //means the buffer only has space for the payload which need to be copied
+#if OFFSET == 0
+#define L2CAPBUFSIZE 128
+#else
+#define L2CAPBUFSIZE 0
+#endif
+
+typedef struct {
+ u16 handle;
+ u16 length; // total
+ u16 l2capLength; // length -4
+ u16 cid; // Signaling packet CID = 1
+ u8 data[L2CAPBUFSIZE]; // Largest thing to send!!! todo
+} L2CAPData;
+
+//
+void BTDevice::Init() {
+ memset(&_info,0,sizeof(inquiry_info));
+ _handle = 0;
+ _name[0] = 0;
+ _state = 0;
+}
+
+// virtual SocketHandler
+int BTDevice::Open(SocketInternal* sock, SocketAddrHdr* addr) {
+ L2CAPSocket* s = (L2CAPSocket*)sock;
+ L2CAPAddr* a = (L2CAPAddr*)addr;
+ s->scid = 0x40 + sock->ID-1; // are these reserved?
+ s->dcid = 0;
+ Connect(s->scid,a->psm);
+ sock->State = SocketState_L2CAP_WaitConnectRsp;
+ contState = 0;
+ return sock->ID;
+}
+
+// virtual SocketHandler, called from HCI which is ABOVE L2CAP
+int BTDevice::Send(SocketInternal* sock, const u8* data, int len) {
+ L2CAPSocket* s = (L2CAPSocket*)sock;
+#if OFFSET == 8 //sizeof L2CAPData header
+ L2CAPData &d = *const_cast<L2CAPData*>((L2CAPData*)data);
+#else
+ L2CAPData d;
+#endif
+ if (len > peer_mtu) {//mtu concerns the l2cap mtu, because we use basic mode we cannot segment
+ printf("MTU (%d) for outgoing packet (%d) exceeded\n", peer_mtu, len);
+ return 0;
+ }
+ d.handle = _handle | 0x2000;
+ d.length = 4 + len - OFFSET;
+ d.l2capLength = len - OFFSET;
+ d.cid = s->dcid;
+ printf("cid=%d: ", d.cid);
+ printfBytes("sending: ", data, len);
+
+#if OFFSET == 0
+ if (len > L2CAPBUFSIZE)
+ return -1;
+ memcpy(d.data,data,len);
+ return Send((u8*)&d,len+8);
+#else
+ return Send(data, len);
+#endif
+}
+
+// virtual SocketHandler
+int BTDevice::Close(SocketInternal* sock) {
+ printf("L2CAP close %d\n",sock->ID);
+ sock->State = SocketState_L2CAP_WaitDisconnect;
+ L2CAPSocket* s = (L2CAPSocket*)sock;
+ return Disconnect(s->scid,s->dcid);
+}
+
+L2CAPSocket* BTDevice::SCIDToSocket(int scid) {
+ return (L2CAPSocket*)GetSocketInternal(scid-0x40+1);
+}
+
+int BTDevice::Send(const u8* data, int len) {//printfBytes("Transport : ", data, len);
+ _transport->ACLSend(data,len);
+ return 0;
+}
+
+void BTDevice::repeat_cmd() {
+printf("Cmd on handle %#x timed out, resending txid=%d\n", _handle, last_req.id);
+ Send ((u8*)&last_req, last_req.length+4);//danger! interrupt context, Send is not reentrant
+ //optionally set new larger timeout
+}
+
+int BTDevice::Send(u8 c, u8 id, u16* params, int count) {
+ L2CAPCmd cmd;
+ cmd.handle = _handle | 0x2000;
+ cmd.length = 8 + count*2;
+
+ cmd.l2capLength = cmd.length-4;
+ cmd.cid = 1; // Signaling packet
+
+ cmd.cmd = c;
+ cmd.id = id;
+ cmd.cmdLength = count*2;
+ for (int i = 0; i < count; i++)
+ cmd.params[i] = params[i];
+ if ((c & 1) == 0) { //this is a request
+ last_req = cmd;
+ rtx.attach(this, &BTDevice::repeat_cmd, 5.0);
+ printf("Starting timeout for %#x, txid=%d\n", _handle, id);
+ }
+ return Send((u8*)&cmd,cmd.length+4);
+}
+
+int BTDevice::Connect(int scid, int psm) {
+ u16 p[2];
+ p[0] = psm;
+ p[1] = scid;
+ return Send(L2CAP_CONN_REQ,_txid++,p,2);
+}
+
+int BTDevice::Disconnect(int scid, int dcid) {
+ u16 p[2];
+ p[0] = dcid;
+ p[1] = scid;
+ return Send(L2CAP_DISCONN_REQ,_txid++,p,2);
+}
+
+int BTDevice::ConfigureRequest(int dcid) {
+ u16 p[4];
+ p[0] = dcid;
+ p[1] = 0;
+ p[2] = 0x0201; // Options
+ p[3] = min(0x02A0, MAX_ACL_SIZE); // my receiving MTU 672
+ return Send(L2CAP_CONF_REQ,_txid++,p,4);
+}
+
+int BTDevice::ConfigureResponse(u8 rxid, int dcid) {
+ u16 p[3];
+ p[0] = dcid; //source cid
+ p[1] = 0; //flags (no continuation)
+ p[2] = 0; //result (success)
+ return Send(L2CAP_CONF_RSP,rxid,p,3);
+}
+
+int BTDevice::DisconnectResponse(u8 rxid, int scid, int dcid) {
+ u16 p[2];
+ p[0] = dcid;
+ p[1] = scid;
+ return Send(L2CAP_DISCONN_RSP,rxid,p,2);
+}
+#if 0
+//handle16, length16, lengthL2CAP16, cid16, code8, tid8, lengthData16
+// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+void BTDevice::Control(const u8* data, int len) { //control channel receive
+ printf("\x1B[%dm", 31);
+ int cc = data[8];//command code
+ printf(L2CAP_ComandCodeStr(cc));
+ //int result = LE16(data+16);//conn_rsp, and conf_resp only
+ //printf(" Result %d\n",result);
+ switch (cc) {
+ case L2CAP_COMMAND_REJ://bad command, eg. MTU, check (reason)
+ printf(" rejection reason=%d\n", LE16(data+12));
+ break;
+ case L2CAP_CONN_REQ://incoming connection request, not expected but should reply with proper rejection (or accept)
+ //when a connection is accepted a new socket must be opened
+ break;
+ // Response to our initial connect from Remote
+ case L2CAP_CONN_RSP: {
+ int dcid = LE16(data+12);
+ int scid = LE16(data+14);
+ L2CAPSocket* s = SCIDToSocket(scid);
+ int result = LE16(data+16);
+ printf("Result=%d, Status = %d\n", result, LE16(data+18));
+ if (s->si.State != SocketState_L2CAP_WaitConnectRsp) {
+ printf("Unexpected event ignored\n");
+ break;
+ }
+ if (result == 0) {
+ if (s) {
+ s->si.State = SocketState_L2CAP_Config_wait;
+ s->dcid = dcid;
+ ConfigureRequest(dcid);
+ s->si.State = SocketState_L2CAP_Config_wait_reqrsp;
+ printf("Sent ConfigureRequest, state=WAIT_CONFIG_REQ-RSP\n");
+ }
+ } else {
+ s->si.SetState(SocketState_Closed);
+ printf("Connect failed?\n");
+ }
+ }
+ break;
+
+ case L2CAP_CONF_RSP: {
+ int result = LE16(data+16);
+ printf("Result=%d, datalen=%d, %smore conf to follow\n", result, LE16(data+10), LE16(data+14)?"":"No ");
+ //should parse the config
+ printfBytes("CONF RSP:", data+8, LE16(data+10)+4);
+ int scid = LE16(data+12);
+ SocketInternal* s = (SocketInternal*)SCIDToSocket(scid);
+ if (s == 0) break;
+ if (s->State != SocketState_L2CAP_Config_wait_reqrsp && s->State != SocketState_L2CAP_Config_wait_rsp) {
+ printf("Unexpected event ignored\n");
+ break;
+ }
+ if (result == 0) { //configuration acceptable
+ if (s->State == SocketState_L2CAP_Config_wait_reqrsp) {
+ s->State = SocketState_L2CAP_Config_wait_req;
+ printf("State=WAIT_CONFIG_REQ\n");
+ } else {
+ ConfigureResponse(data[9],((L2CAPSocket*)s)->dcid);//data[9]==txid
+ printf("Sent ConfigureResponse, state=Open\n");
+ s->SetState(SocketState_Open);
+ }
+ } else {
+ printf("Renegotiate configuration\n");
+ }
+ }
+ break;
+
+ case L2CAP_CONF_REQ: {
+ int scid = LE16(data+12);//flags (data[14] LSB is continuation flag, data[18],[19] are the MTU
+ L2CAPSocket* s = SCIDToSocket(scid);
+ printfBytes("CONF REQ: ", data+8, LE16(data+10)+4);//data+16 contains option type 1-4 1=MTU, 2=flush timeout, 3=QoS, 4=FCM
+ if (s == 0) break;
+ if (s->si.State == SocketState_Closed ||
+ s->si.State == SocketState_L2CAP_WaitConnectRsp ||
+ s->si.State == SocketState_L2CAP_WaitDisconnect) {
+ //Send Reject command
+ break;
+ }
+ switch (data[16]) {
+ case 1:
+ peer_mtu = LE16(data+18);
+ printf("MTU = %d bytes\n", peer_mtu);
+ break;
+ default:
+ printf("Unsupported configuration option %d, value = %#X\n", data[16], LE16(data+18));
+ break;
+ }
+ if (1 /* options acceptable */) {
+ printf("Sending ConfigureResponse, old state=%d ", s->si.State);
+ ConfigureResponse(data[9],s->dcid);//data[9]==txid, success
+ switch (s->si.State) {
+ case SocketState_L2CAP_Config_wait:
+ s->si.State = SocketState_L2CAP_Config_wait_send;
+ break;
+ case SocketState_L2CAP_Config_wait_req:
+ ((SocketInternal*)s)->SetState(SocketState_Open);
+ break;
+ case SocketState_L2CAP_Config_wait_rsp:
+ break;
+ case SocketState_L2CAP_Config_wait_reqrsp:
+ s->si.State = SocketState_L2CAP_Config_wait_rsp;
+ break;
+ }
+ printf("new state=%d\n", s->si.State);
+ } else { //options not acceptable
+ ConfigureResponse(data[9],s->dcid);//indicates success but should indicate fail
+ }
+ }
+ break;
+ case L2CAP_DISCONN_REQ: {
+ int dcid = LE16(data+12);
+ int scid = LE16(data+14);
+ L2CAPSocket* s = SCIDToSocket(scid);
+ s->si.SetState(SocketState_Closed);
+ DisconnectResponse(data[9], scid, dcid);
+ }
+ break;
+ case L2CAP_DISCONN_RSP: {
+ int scid = LE16(data+14);
+ L2CAPSocket* s = SCIDToSocket(scid);
+ if (s->si.State == SocketState_L2CAP_WaitDisconnect)
+ s->si.SetState(SocketState_Closed);
+ }
+ break;
+ }
+ printf("\x1b[0m");
+}
+#else
+//code8, tid8, lengthData16
+// 0, 1, 2, 3
+void BTDevice::Control(const u8* data, int len) { //control channel receive
+ printf("\x1B[%dm", 31);
+ int cc = data[0];//command code
+ if (cc & 1) { //it is a response or a reject
+ rtx.detach(); //kill the timeout
+ printf("timeout cancelled for handle %#x, txid=%d\n", _handle, data[1]);
+ }
+ printf(L2CAP_ComandCodeStr(cc));
+ switch (cc) {
+ case L2CAP_COMMAND_REJ://bad command, eg. MTU, check (reason)
+ printf(" rejection reason=%d\n", LE16(data+4));
+ break;
+ case L2CAP_CONN_REQ://incoming connection request, not expected but should reply with proper rejection (or accept)
+ //when a connection is accepted a new socket must be opened
+ printf("Remote side requested a connection\n");
+ break;
+ // Response to our initial connect from Remote
+ case L2CAP_CONN_RSP: {
+ int dcid = LE16(data+4);
+ int scid = LE16(data+6);
+ L2CAPSocket* s = SCIDToSocket(scid);
+ int result = LE16(data+10);
+ printf(" Result=%d, Status = %d\n", result, LE16(data+10));
+ if (s->si.State != SocketState_L2CAP_WaitConnectRsp) {
+ printf("Unexpected event ignored\n");
+ break;
+ }
+ if (result == 0) {
+ if (s) {
+ s->si.State = SocketState_L2CAP_Config_wait;
+ s->dcid = dcid;
+ ConfigureRequest(dcid);
+ s->si.State = SocketState_L2CAP_Config_wait_reqrsp;
+ printf("Sent ConfigureRequest, state=WAIT_CONFIG_REQ_RSP\n");
+ }
+ } else {
+ s->si.SetState(SocketState_Closed);
+ printf("Connect failed?\n");
+ }
+ }
+ break;
+
+ case L2CAP_CONF_RSP: {
+ int result = LE16(data+8);
+ printf("Result=%d, datalen=%d, %smore conf to follow\n", result, LE16(data+2), LE16(data+6)?"":"No ");
+ //should parse the config
+ printfBytes("CONF RSP:", data, LE16(data+2)+4);
+ int scid = LE16(data+4);
+ SocketInternal* s = (SocketInternal*)SCIDToSocket(scid);
+ if (s == 0) break;
+ if (s->State != SocketState_L2CAP_Config_wait_reqrsp && s->State != SocketState_L2CAP_Config_wait_rsp) {
+ printf("Unexpected event ignored\n");
+ break;
+ }
+ if (result == 0) { //configuration acceptable
+ if (s->State == SocketState_L2CAP_Config_wait_reqrsp) {
+ s->State = SocketState_L2CAP_Config_wait_req;
+ printf("State=WAIT_CONFIG_REQ\n");
+ } else {
+ ConfigureResponse(data[1],((L2CAPSocket*)s)->dcid);//data[1]==txid
+ printf("Sent ConfigureResponse, state=Open\n");
+ s->SetState(SocketState_Open);
+ }
+ } else {
+ printf("Renegotiate configuration\n");
+ }
+ }
+ break;
+
+ case L2CAP_CONF_REQ: {
+ int scid = LE16(data+4);//flags (data[6] LSB is continuation flag, data[10],[11] are the MTU
+ L2CAPSocket* s = SCIDToSocket(scid);
+ printfBytes("CONF REQ: ", data, LE16(data+2)+4);//data+8 contains option type 1-4 1=MTU, 2=flush timeout, 3=QoS, 4=FCM
+ if (s == 0) break;
+ if (s->si.State == SocketState_Closed ||
+ s->si.State == SocketState_L2CAP_WaitConnectRsp ||
+ s->si.State == SocketState_L2CAP_WaitDisconnect) {
+ //Send Reject command
+ break;
+ }
+ switch (data[8]) {
+ case 1:
+ peer_mtu = LE16(data+10);
+ printf("MTU = %d bytes\n", peer_mtu);
+ break;
+ default:
+ printf("Unsupported configuration option %d, value = %#X\n", data[8], LE16(data+10));
+ break;
+ }
+ if (1 /* options acceptable */) {
+ printf("Sending ConfigureResponse, old state=%d ", s->si.State);
+ ConfigureResponse(data[1],s->dcid);//data[1]==txid, success
+ switch (s->si.State) {
+ case SocketState_L2CAP_Config_wait:
+ s->si.State = SocketState_L2CAP_Config_wait_send;
+ break;
+ case SocketState_L2CAP_Config_wait_req:
+ ((SocketInternal*)s)->SetState(SocketState_Open);
+ break;
+ case SocketState_L2CAP_Config_wait_rsp:
+ break;
+ case SocketState_L2CAP_Config_wait_reqrsp:
+ s->si.State = SocketState_L2CAP_Config_wait_rsp;
+ break;
+ }
+ printf("new state=%d\n", s->si.State);
+ } else { //options not acceptable
+ ConfigureResponse(data[1],s->dcid);//indicates success but should indicate fail
+ }
+ }
+ break;
+ case L2CAP_DISCONN_REQ: {
+ int dcid = LE16(data+4);
+ int scid = LE16(data+6);
+ L2CAPSocket* s = SCIDToSocket(scid);
+ s->si.SetState(SocketState_Closed);
+ DisconnectResponse(data[1], scid, dcid);
+ }
+ break;
+ case L2CAP_DISCONN_RSP: {
+ int scid = LE16(data+6);
+ L2CAPSocket* s = SCIDToSocket(scid);
+ if (s->si.State == SocketState_L2CAP_WaitDisconnect)
+ s->si.SetState(SocketState_Closed);
+ }
+ break;
+ default: printf("Unsupported L2CAP message %d\n", cc);
+ }
+ printf("\x1b[0m");
+}
+#endif
+
+void BTDevice::ACLFwd(const u8* data, int len) {
+ if (l2cap_sock == 1) {
+ //printf("cannot handle segmented ACL control packets\n");
+ Control(data, len);
+ return;
+ }
+ SocketInternal* s = (SocketInternal*)SCIDToSocket(l2cap_sock);
+ if (s)
+ s->Recv(data,len);
+ else
+ printf("Bad event cid %d\n",l2cap_sock);
+}
+//sometimes acl packets are segmented, in that case the l2cap payload length does not correspond to the acl pkt length
+//and the l2cap packet length. L2CAP works in basic mode and cannot be segmented hence the l2cap pkt size corresponds to
+//the acl pkt size
+void BTDevice::ACLRecv(const u8* data, int acllen) {
+ printfBytes("L2CP",data,acllen);
+ u16 handle = LE16(data);
+ if ((handle&0x0fff) != _handle) {
+ printf("unexpected handle %#x, this _handle=%#x\n", handle, _handle);
+ return;
+ }
+ char pb = (handle>>12) & 3;
+ int p = 4; //start of l2cap packet
+ int len = LE16(data+2); //length of l2cap pkt
+ while (p < len)
+ switch (contState) {
+ case 0:
+ plen = data[p++];
+ contState = 1;
+ break;
+ case 1:
+ plen += data[p++]<<8;
+ if (pb == 2 && plen == acllen-8) {//normal case, l2cap pkt is contained completely in this hci pkt
+ l2cap_sock = data[p] + (data[p+1]<<8);
+ contState = 0;
+ ACLFwd(data+8, plen); //forward the packet in its original buffer
+ return; //all data was dealt with
+ } else { //packet is segmented
+ printf("ACL packet is segmented\n");
+ contState = 2;
+ contBuf = new unsigned char[plen];//allocate recombination buffer
+ contPos = 0;
+ }
+ break;
+ case 2:
+ l2cap_sock = data[p++];
+ contState = 3;
+ break;
+ case 3:
+ l2cap_sock += data[p++]<<8;
+ contState = 4;
+ break;
+ case 4: //data, recombine segmented ACL (not l2cap!) frames
+ if (contPos < plen) {//buffer not yet full
+ int datalen = acllen - p; //data in this incoming pkt
+ int remcap = plen - contPos; //remaining capacity in the recombination buffer
+ if (datalen <= remcap) {
+ memcpy(contBuf+contPos, data+p, datalen);
+ contPos += datalen;
+ p = acllen;//end of data, stop the while loop
+ if (contPos == plen) {//buffer is full now
+ printfBytes("Recombined packet is:", contBuf, plen);
+ ACLFwd(contBuf, plen); //forward the recombination buffer
+ delete[] contBuf;//and free the buffer
+ contState = 0;
+ }//else stay in this state to wait for the rest
+ } else {//data contains (part of) next packet
+ memcpy(contBuf+contPos, data+p, plen-contPos);//this packet is complete
+ p += plen-contPos;
+ printfBytes("Recombined packet is:", contBuf, plen);
+ printfBytes("Next packet starts with:", data+p, acllen-p);
+ ACLFwd(contBuf, plen); //forward the recombination buffer
+ delete[] contBuf;//and free the buffer
+ contState = 0; //continue with the next packet
+ }
+ } else {
+ printf("Cannot append to buffer (size=%d, pos=%d, datalen = %d)\n", plen, contPos, len-p);
+ contState = 0;
+ return;
+ }
+ break;
+ }//switch (and while)
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Socket.cpp Mon Apr 04 16:41:03 2011 +0000
@@ -0,0 +1,145 @@
+/*
+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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "Utils.h"
+#include "Socket.h"
+
+#define MAX_SOCKET_HANDLERS 4
+#define MAX_SOCKETS 16
+
+class SocketInternalPad
+{
+ public:
+ SocketInternal si;
+ u8 pad[8];
+};
+
+class SocketManager
+{
+ SocketHandler* _handlers[MAX_SOCKET_HANDLERS];
+ SocketInternalPad _sockets[MAX_SOCKETS];
+
+ public:
+ SocketManager()
+ {
+ memset(_handlers,0,sizeof(_handlers));
+ memset(_sockets,0,sizeof(_sockets));
+ }
+
+ SocketHandler* GetHandler(int type)
+ {
+ if (type < 1 || type > MAX_SOCKET_HANDLERS)
+ return 0;
+ return _handlers[type - 1];
+ }
+
+ SocketInternal* GetInternal(int s)
+ {
+ if (s < 1 || s > MAX_SOCKETS)
+ return 0;
+ return &_sockets[s - 1].si;
+ }
+
+ int RegisterSocketHandler(int type, SocketHandler* handler)
+ {
+ if (type < 1 || type > MAX_SOCKET_HANDLERS)
+ return ERR_SOCKET_TYPE_NOT_FOUND;
+ _handlers[type - 1] = handler;
+ return 0;
+ }
+
+ int Open(int type, SocketAddrHdr* addr, SocketCallback callback, void* userData)
+ {
+ SocketHandler* h = GetHandler(type);
+ if (!h)
+ return ERR_SOCKET_TYPE_NOT_FOUND;
+
+ for (int i = 0; i < MAX_SOCKETS; i++)
+ {
+ SocketInternal* si = (SocketInternal*)(_sockets+i);
+ if (si->ID == 0)
+ {
+ si->ID = i+1;
+ si->Type = type;
+ si->Callback = callback;
+ si->userData = userData;
+ printf("Opening socket %d for type %d, invoking 'Open' on %p (=%s)\n", si->ID, type, h, h->Name());
+ return h->Open(si,addr);
+ }
+ }
+ return ERR_SOCKET_NONE_LEFT;
+ }
+
+ int Send(int socket, const u8* data, int len)
+ {
+ SocketInternal* si = GetInternal(socket);
+ if (!si || si->ID != socket)
+ return ERR_SOCKET_NOT_FOUND;
+ // printf("sending %d bytes to socket %d (ID=%d)\n", len, socket, si->ID);
+ return GetHandler(si->Type)->Send(si,data,len);
+ }
+
+ int Close(int socket)
+ {
+ SocketInternal* si = GetInternal(socket);
+ if (!si || si->ID != socket)
+ return ERR_SOCKET_NOT_FOUND;
+ si->SetState(SocketState_Closing);
+ int retval = GetHandler(si->Type)->Close(si);
+ //si->SetState(Socket_Closed);
+ //si->ID = 0;
+ return retval;
+ }
+};
+
+SocketManager gSocketManager;
+
+int Socket_Open(int type, SocketAddrHdr* addr, SocketCallback callback, void* userData)
+{
+ return gSocketManager.Open(type,addr,callback,userData);
+}
+
+int Socket_Send(int socket, const u8* data, int len)
+{
+ return gSocketManager.Send(socket,data,len);
+}
+
+int Socket_Close(int socket)
+{
+ return gSocketManager.Close(socket);
+}
+
+int RegisterSocketHandler(int type, SocketHandler* handler)
+{
+ return gSocketManager.RegisterSocketHandler(type,handler);
+}
+
+SocketInternal* GetSocketInternal(int socket)
+{
+ return gSocketManager.GetInternal(socket);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Socket.h Mon Apr 04 16:41:03 2011 +0000
@@ -0,0 +1,108 @@
+/*
+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 SOCKET_H_INCLUDED
+#define SOCKET_H_INCLUDED
+
+#define SOCKET_HCI 1
+#define SOCKET_L2CAP 2
+#define SOCKET_RFCOM 3
+#define SOCKET_SDP 4
+
+typedef struct
+{
+ u8 AddressSpecific[0]; // BDADDR,psm etc
+} SocketAddrHdr;
+
+enum SocketState
+{
+ SocketState_Unknown,
+ SocketState_Opening,
+ SocketState_Open,
+ SocketState_Closing,
+ SocketState_Closed,
+ SocketState_L2CAP_WaitConnect,
+ SocketState_L2CAP_WaitConnectRsp,
+ SocketState_L2CAP_WaitDisconnect,
+ SocketState_L2CAP_Config_wait = 16,
+ SocketState_L2CAP_Config_wait_send,
+ SocketState_L2CAP_Config_wait_req,
+ SocketState_L2CAP_Config_wait_rsp,
+ SocketState_L2CAP_Config_wait_reqrsp
+};
+
+typedef void (*SocketCallback)(int socket, SocketState state, const u8* data, int len, void* userData);
+
+int Socket_Open(int type, SocketAddrHdr* addr, SocketCallback callback, void* userData); // Open a socket
+int Socket_Send(int socket, const u8* data, int len);
+int Socket_State(int socket);
+int Socket_Close(int socket);
+
+//===========================================================================
+//===========================================================================
+// Don't need to look at or use anything below this line:
+// Internal representation of socket
+
+class SocketHandler;
+class SocketInternal
+{
+ public:
+
+ u8 ID;
+ u8 State;
+ u8 Type;
+ u8 B0;
+ SocketCallback Callback;
+ void* userData;
+ u8 Data[0]; // Extra socket data starts here
+
+ void Recv(const u8* data, int len)
+ {
+ Callback(ID,(SocketState)State,data,len,userData);
+ }
+
+ void SetState(SocketState state)
+ {
+ State = state;
+ Callback(ID,(SocketState)State,0,0,userData);
+ if (state == SocketState_Closed)
+ ID = 0;
+ }
+};
+
+class SocketHandler
+{
+ public:
+ virtual int Open(SocketInternal* sock, SocketAddrHdr* addr) = 0;
+ virtual int Send(SocketInternal* sock, const u8* data, int len) = 0;
+ virtual int Close(SocketInternal* sock) = 0;
+ virtual char* Name() { return "Base SocketHandler";}
+};
+
+int RegisterSocketHandler(int type, SocketHandler* handler);
+SocketInternal* GetSocketInternal(int socket);
+
+#define ERR_SOCKET_TYPE_NOT_FOUND -200
+#define ERR_SOCKET_NOT_FOUND -201
+#define ERR_SOCKET_NONE_LEFT -202
+
+#endif // SOCKET_H_INCLUDED
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Utils.cpp Mon Apr 04 16:41:03 2011 +0000
@@ -0,0 +1,48 @@
+
+
+#include "mbed.h"
+#include "Utils.h"
+
+void printfBytes(const char* s, const u8* data, int len)
+{
+ printf("%s %d:",s,len);
+ if (len > 256)
+ len = 256;
+ while (len-- > 0)
+ printf(" %02X",*data++);
+ printf("\n");
+}
+
+void printHexLine(const u8* d, int addr, int len)
+{
+ printf("%04X ",addr);
+ int i;
+ for (i = 0; i < len; i++)
+ printf("%02X ",d[i]);
+ for (;i < 16; i++)
+ printf(" ");
+ char s[16+1];
+ memset(s,0,sizeof(s));
+ for (i = 0; i < len; i++)
+ {
+ int c = d[i];
+ if (c < 0x20 || c > 0x7E)
+ c = '.';
+ s[i] = c;
+ }
+ printf("%s\n",s);
+}
+
+void printHex(const u8* d, int len)
+{
+ int addr = 0;
+ while (len)
+ {
+ int count = len;
+ if (count > 16)
+ count = 16;
+ printHexLine(d+addr,addr,count);
+ addr += 16;
+ len -= count;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Utils.h Mon Apr 04 16:41:03 2011 +0000
@@ -0,0 +1,37 @@
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+
+void DelayMS(int ms);
+
+void printfBytes(const char* label,const u8* data, int len);
+void printHex(const u8* d, int len);
+
+#ifndef min
+#define min(_a,_b) ((_a) < (_b) ? (_a) : (_b))
+#endif
+
+inline int LE16(const u8* d)
+{
+ return d[0] | (d[1] << 8);
+}
+
+inline u32 BE32(const u8* d)
+{
+ return (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3];
+}
+
+inline void BE32(u32 n, u8* d)
+{
+ d[0] = (u8)(n >> 24);
+ d[1] = (u8)(n >> 16);
+ d[2] = (u8)(n >> 8);
+ d[3] = (u8)n;
+}
+
+inline void BE16(u32 n, u8* d)
+{
+ d[0] = (u8)(n >> 8);
+ d[1] = (u8)n;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hci.cpp Mon Apr 04 16:41:03 2011 +0000
@@ -0,0 +1,421 @@
+
+/*
+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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "Utils.h"
+#include "hci.h"
+#include "hci_private.h"
+#include "USBHost.h" //for USBLoop
+
+enum hci_callback_evt {
+ NONE,
+ CONNECT,
+ DISCONECT,
+ INQUIRYRESULT
+};
+
+#define MAX_BLUETOOTH_ADAPTERS 1
+
+enum StateMask {
+ MASK_RESET = 1,
+ MASK_READ_BUFFER_SIZE = 2,
+ MASK_READ_BD_ADDR = 4,
+ MASK_INITED = 8,
+ MASK_INQUIRY = 16,
+ MASK_REMOTE_NAME = 32,
+ MASK_CREATE_CONNECTION = 64
+};
+
+int HCI::Open(HCITransport* transport, HCICallback callback) {
+ _transport = transport;
+ _transport->Set(this);
+ _callback = callback;
+ _state = 0;
+ for (int i = 0; i < MAX_BTDEVICES; i++) {
+ _devices[i].Init();
+ _devices[i]._transport = transport;
+ }
+ cmd_credits = 1;
+ return SendCmd(HCI_OP_RESET);
+}
+
+void printf(const BD_ADDR* addr);
+
+BTDevice* HCI::Find(const BD_ADDR* addr) {
+ for (int i = 0; i < MAX_BTDEVICES; i++)
+ if (_devices[i]._state != 0 && memcmp(addr,&_devices[i]._info.bdaddr,6) == 0)
+ return &_devices[i];
+ return 0;
+}
+
+BTDevice* HCI::Find(int handle) {
+ for (int i = 0; i < MAX_BTDEVICES; i++)
+ if (_devices[i]._state != 0 && handle == _devices[i]._handle)
+ return &_devices[i];
+ return 0;
+}
+//
+bool HCI::Busy() {
+ return (_state & (MASK_INQUIRY | MASK_REMOTE_NAME | MASK_CREATE_CONNECTION)) != 0;
+}
+
+int HCI::Inquiry(int duration) {
+ _state |= MASK_INQUIRY;
+ u8 buf[5];
+ buf[0] = 0x33;//LAP=0x9e8b33
+ buf[1] = 0x8B;
+ buf[2] = 0x9E;
+ buf[3] = duration;
+ buf[4] = 5; // 5 results
+ SendCmd(HCI_OP_INQUIRY,buf,sizeof(buf));
+ return 0;
+}
+
+int HCI::SendCmd(int cmd, const u8* params, int len) {
+ u8 b[32];
+ b[0] = cmd;
+ b[1] = (cmd >> 8);
+ b[2] = len;
+ if (params)
+ memcpy(b+3,params,len);
+ //printf("%d cmd_credits\n", cmd_credits);
+ while (cmd_credits == 0) {
+ USBLoop();
+ putc('_', stdout);
+ }
+ _transport->HCISend(b,len+3);
+ return 0;
+}
+
+void HCI::OnCommandComplete(int cmd, const u8* data, int len) {
+ printf("%04X %s",cmd,CmdStr(cmd));
+ if (len < 0)
+ return;
+ printfBytes(" complete",data,min(16,len));
+
+ switch (cmd) {
+ // Init phase 0
+ case HCI_OP_RESET: // Reset done, init chain to HCI_OP_READ_LOCAL_NAME
+ SendCmd(HCI_OP_READ_BUFFER_SIZE);
+ _state |= MASK_RESET;
+ break;
+
+ // Init phase 1
+ case HCI_OP_READ_BUFFER_SIZE:
+ _acl_mtu = LE16(data);
+ _sco_mtu = data[2];
+ _acl_max_pkt = LE16(data+3);
+ _sco_max_pkt = LE16(data+5);
+ printf("acl_mtu=%d, acl_max_pkt=%d\n", _acl_mtu, _acl_max_pkt);
+ SendCmd(HCI_OP_READ_BD_ADDR);
+ _state |= MASK_READ_BUFFER_SIZE;
+ break;
+
+ // Init phase 2
+ case HCI_OP_READ_BD_ADDR:
+ _localAddr = *((BD_ADDR*)data); // Local Address
+ _state |= MASK_READ_BD_ADDR;
+ _state |= MASK_INITED;
+ Callback(CALLBACK_READY,data,6);
+ break;
+
+ // 0CXX
+ case HCI_OP_READ_LOCAL_NAME:
+ case HCI_OP_LINK_KEY_NEG_REPLY:
+ break;
+
+ case HCI_OP_READ_LOCAL_VERSION:
+ // params
+ //SendCmd(HCI_OP_READ_LOCAL_NAME);
+ break;
+
+ case HCI_OP_READ_LOCAL_COMMANDS:
+ break;
+
+ case HCI_OP_READ_LOCAL_FEATURES:
+ //SendCmd(HCI_OP_READ_LOCAL_VERSION);
+ break;
+
+ case HCI_OP_READ_LOCAL_EXT_FEATURES:
+ break;
+
+ case HCI_OP_PIN_CODE_REPLY:
+ printf("Got pin reply\n");
+ break;
+
+ default:
+ printf("Unrecognized Command %04X\n",cmd);
+ break;
+ }
+}
+
+void HCI::Callback(HCI_CALLBACK_EVENT c, const u8* data, int len) {
+ if (_callback) _callback(this,c,data,len);
+// (this->*_callback)(c, data, len);
+}
+
+int HCI::RemoteNameRequest(const BD_ADDR* addr) {
+ _state |= MASK_REMOTE_NAME;
+ u8 buf[6+4];
+ memset(buf,0,sizeof(buf));
+ memcpy(buf,addr,6);
+ //buf[7] = 1;
+ return SendCmd(HCI_OP_REMOTE_NAME_REQ,buf,sizeof(buf));
+}
+int HCI::RemoteNameRequest(inquiry_info *ii) {
+ _state |= MASK_REMOTE_NAME;
+ u8 buf[6+4];
+ //memset(buf,0,sizeof(buf));
+ memcpy(buf,&ii->bdaddr,6);
+ buf[6] = ii->pscan_rep_mode;
+ buf[7] = 0;
+ *(unsigned short*)(buf+8) = 0;
+ return SendCmd(HCI_OP_REMOTE_NAME_REQ,buf,sizeof(buf));
+}
+
+
+int HCI::CreateConnection(const BD_ADDR* remoteAddr) {
+ _state |= MASK_CREATE_CONNECTION;
+ u8 buf[6+7];
+ memset(buf,0,sizeof(buf));
+ memcpy(buf,remoteAddr,6);
+ buf[6] = 0x18; // DM1,DH1
+ buf[7] = 0xCC; // DM3, DH3, DM5, DH5
+ buf[8] = 1; // Page Repetition R1
+ return SendCmd(HCI_OP_CREATE_CONN,buf,sizeof(buf));
+}
+
+int HCI::Disconnect(const BD_ADDR* bdaddr) {
+ BTDevice* d = Find(bdaddr);
+ if (!d)
+ return ERR_HCI_DEVICE_NOT_FOUND;
+ int handle = d->_handle;
+ printf("Disconnect from %d\n",handle);
+ _state |= MASK_CREATE_CONNECTION;
+ u8 buf[3];
+ buf[0] = handle;
+ buf[1] = (handle >> 8);
+ buf[2] = 0x13;
+ return SendCmd(HCI_OP_DISCONNECT,buf,sizeof(buf));
+}
+
+void HCI::DisconnectComplete(int handle) {
+ BTDevice* d = Find(handle);
+ if (!d)
+ return;
+ d->_handle = 0;
+}
+
+int HCI::DisconnectAll() {
+ BTDevice* devs[8];
+ int count = GetDevices(devs,8);
+ for (int i = 0; i < count; i++)
+ Disconnect(&devs[i]->_info.bdaddr);
+ return 0;
+}
+
+int HCI::PinCodeReply(const u8* data, const u8* pin) {
+ u8 b[6+1+16];
+ memset(b,0,sizeof(b));
+ memcpy(b,data,6);
+ b[6] = 4;
+ memcpy(b+7, pin, 4);
+ return SendCmd(HCI_OP_PIN_CODE_REPLY,b,sizeof(b));
+}
+
+void HCI::InquiryResult(const inquiry_info* info) {
+ BTDevice* bt = Find(&info->bdaddr);
+ if (!bt) { // new device
+ for (int i = 0; i < MAX_BTDEVICES; i++) {
+ if (_devices[i]._state == 0) {
+ bt = _devices + i;
+ bt->_state = 1;
+ break;
+ }
+ }
+ if (!bt) {
+ printf("HCI::InquiryResult too many devices\n");
+ return; // Too many devices!
+ }
+ }
+
+ bt->_info = *info;
+}
+
+int HCI::GetDevices(BTDevice** devices, int maxDevices) {
+ int j = 0;
+ for (int i = 0; i < MAX_BTDEVICES; i++) {
+ if (_devices[i]._state != 0) {
+ devices[j++] = _devices + i;
+ if (j == maxDevices)
+ break;
+ }
+ }
+ return j;
+}
+
+void HCI::RemoteName(const BD_ADDR* addr, const char* name) {
+ BTDevice* d = Find(addr);
+ if (d) {
+ strncpy(d->_name,name,sizeof(d->_name)-1);
+ d->_name[sizeof(d->_name)-1] = 0;
+ }
+}
+
+void HCI::ConnectComplete(const connection_info* info) {
+ BTDevice* d = Find(&info->bdaddr);
+ if (!d)
+ return;
+ if (info->status == 0) {
+ d->_handle = info->handle;
+ printf("Connected on %04X\n",info->handle);
+ } else
+ printf("Connection failed with %d\n",info->status);
+}
+
+void HCI::HCIRecv(const u8* data, int len) {
+ // printfBytes(EvtStr(data[0]),data,min(len,16));
+ switch (data[0]) {
+ case HCI_EV_INQUIRY_COMPLETE:
+ printfBytes("Inquiry Complete",data,data[1]);
+ _state &= ~MASK_INQUIRY;
+ Callback(CALLBACK_INQUIRY_DONE,0,0);
+ break;
+
+ case HCI_EV_INQUIRY_RESULT: {
+ const u8* end = data[1] + data + 2;
+ data += 3;
+ while (data < end) {
+ inquiry_info align;
+ memcpy(&align,data,sizeof(inquiry_info));
+ InquiryResult(&align);
+ Callback(CALLBACK_INQUIRY_RESULT,(u8*)&align,sizeof(inquiry_info));
+ data += 14;
+ }
+ }
+ break;
+
+ case HCI_EV_CONN_COMPLETE:
+ _state &= ~MASK_CREATE_CONNECTION;
+ {
+ connection_info align;
+ memcpy(&align,data+2,sizeof(connection_info));
+ ConnectComplete(&align);
+ Callback(CALLBACK_CONNECTION_COMPLETE,(u8*)&align,sizeof(connection_info));
+ }
+ break;
+
+ case HCI_EV_CONN_REQUEST:
+ break;
+
+ case HCI_EV_DISCONN_COMPLETE:
+ DisconnectComplete(LE16(data+3));
+ break;
+
+ case HCI_EV_REMOTE_NAME: {
+ BD_ADDR* addr = (BD_ADDR*)(data+3);
+ const char* name = (const char*)(data + 9);
+ RemoteName(addr,name);
+ }
+ Callback(CALLBACK_REMOTE_NAME,data+3,LE16(data+1)); // addr is in here too
+ _state &= ~MASK_REMOTE_NAME;
+ break;
+
+ case HCI_EV_CMD_STATUS: {
+ const char* errs = HCIErrStr(data[2]);
+ printf("Status %s %s %d cmd pkts\n",CmdStr(LE16(data+4)),errs, data[3]);
+ cmd_credits = data[3];
+ }
+ Callback(CALLBACK_CMD_STATUS, data+2, 4);
+ break;
+
+ case HCI_EV_CMD_COMPLETE:
+ OnCommandComplete(data[3] | (data[4] << 8),data+6,data[1]-4);
+ cmd_credits = data[2];
+ break;
+
+ case HCI_EV_PIN_CODE_REQ:
+ Callback(CALLBACK_PIN_REQ, data+2, 6);
+ //PinCodeReply(data+2);
+ break;
+
+ case HCI_EV_LINK_KEY_REQ:
+ SendCmd(HCI_OP_LINK_KEY_NEG_REPLY,data+2,6);
+ break;
+ case HCI_EV_NUM_COMP_PKTS:
+ case HCI_EV_LINK_KEY_NOTIFY:
+ break;
+ default:
+
+ printfBytes("HCIRecv:",data,data[1]+2);
+ break;
+ }
+}
+
+int HCI::Open(SocketInternal* sock, SocketAddrHdr* addr) {
+ L2CAPSocket* l2capsock = (L2CAPSocket*)sock;
+ L2CAPAddr* l2capaddr = (L2CAPAddr*)addr;
+ BTDevice* bt = Find(&l2capaddr->bdaddr);
+ if (!bt) {
+ printf("Can't open l2cap %d on ",l2capaddr->psm);
+ printf(&l2capaddr->bdaddr);
+ printf("\n");
+ return ERR_HCI_DEVICE_NOT_FOUND;
+ }
+ l2capsock->btdevice = bt;
+ return bt->Open(sock,addr);
+}
+
+int HCI::Send(SocketInternal* sock, const u8* data, int len) {//check here for appropriate buffersize on the device
+//assume acl packet
+#if OFFSET==8 //sizeof ACL/L2CAP is include in data/len
+ if (len > _acl_max_pkt)
+#else //OFFSET==0, data is bare application frame
+ if (len+8 > _acl_mtu)
+#endif
+ { printf("Max outgoing packet(%d) size exceeded, segmenting necessary, pktlen = %d\n", _acl_mtu, len);
+ }
+ L2CAPSocket* l2capsock = (L2CAPSocket*)sock;
+ return l2capsock->btdevice->Send(sock,data,len); // Pointless double dispatch
+}
+
+int HCI::Close(SocketInternal* sock) {
+ L2CAPSocket* l2capsock = (L2CAPSocket*)sock;
+ return l2capsock->btdevice->Close(sock); // Pointless double dispatch
+}
+
+void HCI::ACLRecv(const u8* data, int len) {
+ int handle = LE16(data);
+ BTDevice* d = Find(handle & 0x0FFF);
+ if (d)
+ d->ACLRecv(data,len);
+ else
+ printfBytes("HCI:ACLRecv ", data, len);
+}
+
+//===================================================================
+//===================================================================
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hci.h Mon Apr 04 16:41:03 2011 +0000
@@ -0,0 +1,253 @@
+/*
+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 "mbed.h"
+#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;
+
+typedef struct {
+ u16 handle;
+ u16 length; // total
+ u16 l2capLength; // length -4
+ u16 cid; // Signaling packet CID = 1
+
+ // Payload
+ u8 cmd; //
+ u8 id;
+ u16 cmdLength; // total-8
+ u16 params[4]; // Params
+} L2CAPCmd;
+
+#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;
+ u16 peer_mtu;
+ char _name[MAX_HCL_NAME_LENGTH];
+
+ void Init();
+
+ BD_ADDR* GetAddress() { return &_info.bdaddr; }
+
+ // Called from HCI
+ void ACLRecv(const u8* data, int len);
+ void ACLFwd(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);
+ virtual char* Name() { return "BTDevice SocketHandler";}
+
+private:
+ int l2cap_sock, plen, contPos, contState;
+ unsigned char *contBuf;
+ Timeout rtx;
+ L2CAPCmd last_req;
+ void repeat_cmd();
+
+ 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,
+ CALLBACK_PIN_REQ,
+ CALLBACK_CMD_STATUS
+};
+
+// 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);
+//typedef int (HCI::*HCICallback)(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;
+char cmd_credits, data_credits;
+ public:
+
+ // Open a local adapter
+ int Open(HCITransport* transport, HCICallback callback=0);
+
+ // 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);
+ int RemoteNameRequest(inquiry_info* ii);
+
+ // 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);
+ virtual char* Name() { return "HCI SocketHandler";}
+
+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);
+ virtual void Callback(HCI_CALLBACK_EVENT c, const u8* data, int len);
+protected:
+ int PinCodeReply(const u8* data, const u8* pin = "0000");
+};
+
+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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hci_private.h Mon Apr 04 16:41:03 2011 +0000
@@ -0,0 +1,323 @@
+/*
+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_PRIVATE_H_INCLUDED
+#define HCI_PRIVATE_H_INCLUDED
+
+#define HCI_OP_INQUIRY 0x0401
+#define HCI_OP_INQUIRY_CANCEL 0x0402
+#define HCI_OP_EXIT_PERIODIC_INQ 0x0404
+#define HCI_OP_CREATE_CONN 0x0405
+#define HCI_OP_DISCONNECT 0x0406
+#define HCI_OP_ADD_SCO 0x0407
+#define HCI_OP_CREATE_CONN_CANCEL 0x0408
+#define HCI_OP_ACCEPT_CONN_REQ 0x0409
+#define HCI_OP_REJECT_CONN_REQ 0x040a
+#define HCI_OP_LINK_KEY_REPLY 0x040b
+#define HCI_OP_LINK_KEY_NEG_REPLY 0x040c
+#define HCI_OP_PIN_CODE_REPLY 0x040d
+#define HCI_OP_PIN_CODE_NEG_REPLY 0x040e
+#define HCI_OP_CHANGE_CONN_PTYPE 0x040f
+#define HCI_OP_AUTH_REQUESTED 0x0411
+#define HCI_OP_SET_CONN_ENCRYPT 0x0413
+#define HCI_OP_CHANGE_CONN_LINK_KEY 0x0415
+#define HCI_OP_REMOTE_NAME_REQ 0x0419
+#define HCI_OP_REMOTE_NAME_REQ_CANCEL 0x041a
+#define HCI_OP_READ_REMOTE_FEATURES 0x041b
+#define HCI_OP_READ_REMOTE_EXT_FEATURES 0x041c
+#define HCI_OP_READ_REMOTE_VERSION 0x041d
+#define HCI_OP_SETUP_SYNC_CONN 0x0428
+#define HCI_OP_ACCEPT_SYNC_CONN_REQ 0x0429
+#define HCI_OP_REJECT_SYNC_CONN_REQ 0x042a
+
+#define HCI_OP_SNIFF_MODE 0x0803
+#define HCI_OP_EXIT_SNIFF_MODE 0x0804
+#define HCI_OP_ROLE_DISCOVERY 0x0809
+#define HCI_OP_SWITCH_ROLE 0x080b
+#define HCI_OP_READ_LINK_POLICY 0x080c
+#define HCI_OP_WRITE_LINK_POLICY 0x080d
+#define HCI_OP_READ_DEF_LINK_POLICY 0x080e
+#define HCI_OP_WRITE_DEF_LINK_POLICY 0x080f
+#define HCI_OP_SNIFF_SUBRATE 0x0811
+
+
+#define HCI_OP_SET_EVENT_MASK 0x0c01
+#define HCI_OP_RESET 0x0c03
+#define HCI_OP_SET_EVENT_FLT 0x0c05
+#define HCI_OP_WRITE_LOCAL_NAME 0x0c13
+#define HCI_OP_READ_LOCAL_NAME 0x0c14
+#define HCI_OP_WRITE_CA_TIMEOUT 0x0c16
+#define HCI_OP_WRITE_PG_TIMEOUT 0x0c18
+#define HCI_OP_WRITE_SCAN_ENABLE 0x0c1a
+#define HCI_OP_READ_AUTH_ENABLE 0x0c1f
+#define HCI_OP_WRITE_AUTH_ENABLE 0x0c20
+#define HCI_OP_READ_ENCRYPT_MODE 0x0c21
+#define HCI_OP_WRITE_ENCRYPT_MODE 0x0c22
+ #define ENCRYPT_DISABLED 0x00
+ #define ENCRYPT_P2P 0x01
+ #define ENCRYPT_BOTH 0x02
+#define HCI_OP_READ_CLASS_OF_DEV 0x0c23
+#define HCI_OP_WRITE_CLASS_OF_DEV 0x0c24
+#define HCI_OP_READ_VOICE_SETTING 0x0c25
+#define HCI_OP_WRITE_VOICE_SETTING 0x0c26
+#define HCI_OP_HOST_BUFFER_SIZE 0x0c33
+#define HCI_OP_READ_SSP_MODE 0x0c55
+#define HCI_OP_WRITE_SSP_MODE 0x0c56
+
+#define HCI_OP_READ_LOCAL_VERSION 0x1001
+#define HCI_OP_READ_LOCAL_COMMANDS 0x1002
+#define HCI_OP_READ_LOCAL_FEATURES 0x1003
+#define HCI_OP_READ_LOCAL_EXT_FEATURES 0x1004
+#define HCI_OP_READ_BUFFER_SIZE 0x1005
+#define HCI_OP_READ_BD_ADDR 0x1009
+
+// events
+#define HCI_EV_INQUIRY_COMPLETE 0x01
+#define HCI_EV_INQUIRY_RESULT 0x02
+#define HCI_EV_CONN_COMPLETE 0x03
+#define HCI_EV_CONN_REQUEST 0x04
+#define HCI_EV_DISCONN_COMPLETE 0x05
+#define HCI_EV_AUTH_COMPLETE 0x06
+#define HCI_EV_REMOTE_NAME 0x07
+#define HCI_EV_ENCRYPT_CHANGE 0x08
+#define HCI_EV_CHANGE_LINK_KEY_COMPLETE 0x09
+#define HCI_EV_REMOTE_FEATURES 0x0b
+#define HCI_EV_REMOTE_VERSION 0x0c
+#define HCI_EV_QOS_SETUP_COMPLETE 0x0d
+#define HCI_EV_CMD_COMPLETE 0x0e
+#define HCI_EV_CMD_STATUS 0x0f
+#define HCI_EV_ROLE_CHANGE 0x12
+#define HCI_EV_NUM_COMP_PKTS 0x13
+#define HCI_EV_MODE_CHANGE 0x14
+#define HCI_EV_PIN_CODE_REQ 0x16
+#define HCI_EV_LINK_KEY_REQ 0x17
+#define HCI_EV_LINK_KEY_NOTIFY 0x18
+#define HCI_EV_CLOCK_OFFSET 0x1c
+#define HCI_EV_PKT_TYPE_CHANGE 0x1d
+#define HCI_EV_PSCAN_REP_MODE 0x20
+#define HCI_EV_INQUIRY_RESULT_WITH_RSSI 0x22
+#define HCI_EV_REMOTE_EXT_FEATURES 0x23
+#define HCI_EV_SYNC_CONN_COMPLETE 0x2c
+#define HCI_EV_SYNC_CONN_CHANGED 0x2d
+#define HCI_EV_SNIFF_SUBRATE 0x2e
+#define HCI_EV_EXTENDED_INQUIRY_RESULT 0x2f
+#define HCI_EV_IO_CAPA_REQUEST 0x31
+#define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36
+#define HCI_EV_REMOTE_HOST_FEATURES 0x3d
+
+/* Possible error codes */
+#define HCI_UNKNOWN_HCI_COMMAND 0x01
+#define HCI_NO_CONNECTION 0x02
+#define HCI_HW_FAILURE 0x03
+#define HCI_PAGE_TIMEOUT 0x04
+#define HCI_AUTHENTICATION_FAILURE 0x05
+#define HCI_KEY_MISSING 0x06
+#define HCI_MEMORY_FULL 0x07
+#define HCI_CONN_TIMEOUT 0x08
+#define HCI_MAX_NUMBER_OF_CONNECTIONS 0x09
+#define HCI_MAX_NUMBER_OF_SCO_CONNECTIONS_TO_DEVICE 0x0A
+#define HCI_ACL_CONNECTION_EXISTS 0x0B
+#define HCI_COMMAND_DISSALLOWED 0x0C
+#define HCI_HOST_REJECTED_DUE_TO_LIMITED_RESOURCES 0x0D
+#define HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS 0x0E
+#define HCI_HOST_REJECTED_DUE_TO_REMOTE_DEVICE_ONLY_PERSONAL_SERVICE 0x0F
+#define HCI_HOST_TIMEOUT 0x10
+#define HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE 0x11
+#define HCI_INVALID_HCI_COMMAND_PARAMETERS 0x12
+#define HCI_OTHER_END_TERMINATED_CONN_USER_ENDED 0x13
+#define HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES 0x14
+#define HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF 0x15
+#define HCI_CONN_TERMINATED_BY_LOCAL_HOST 0x16
+#define HCI_REPETED_ATTEMPTS 0x17
+#define HCI_PAIRING_NOT_ALLOWED 0x18
+#define HCI_UNKNOWN_LMP_PDU 0x19
+#define HCI_UNSUPPORTED_REMOTE_FEATURE 0x1A
+#define HCI_SCO_OFFSET_REJECTED 0x1B
+#define HCI_SCO_INTERVAL_REJECTED 0x1C
+#define HCI_SCO_AIR_MODE_REJECTED 0x1D
+#define HCI_INVALID_LMP_PARAMETERS 0x1E
+#define HCI_UNSPECIFIED_ERROR 0x1F
+#define HCI_UNSUPPORTED_LMP_PARAMETER_VALUE 0x20
+#define HCI_ROLE_CHANGE_NOT_ALLOWED 0x21
+#define HCI_LMP_RESPONSE_TIMEOUT 0x22
+#define HCI_LMP_ERROR_TRANSACTION_COLLISION 0x23
+#define HCI_LMP_PDU_NOT_ALLOWED 0x24
+#define HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE 0x25
+#define HCI_UNIT_KEY_USED 0x26
+#define HCI_QOS_NOT_SUPPORTED 0x27
+#define HCI_INSTANT_PASSED 0x28
+#define HCI_PAIRING_UNIT_KEY_NOT_SUPPORTED 0x29
+
+const char* EvtStr(int evt)
+{
+ switch (evt)
+ {
+ case HCI_EV_INQUIRY_COMPLETE: return "HCI_EV_INQUIRY_COMPLETE";
+ case HCI_EV_INQUIRY_RESULT: return "HCI_EV_INQUIRY_RESULT";
+ case HCI_EV_CONN_COMPLETE: return "HCI_EV_CONN_COMPLETE";
+ case HCI_EV_CONN_REQUEST: return "HCI_EV_CONN_REQUEST";
+ case HCI_EV_DISCONN_COMPLETE: return "HCI_EV_DISCONN_COMPLETE";
+ case HCI_EV_AUTH_COMPLETE: return "HCI_EV_AUTH_COMPLETE";
+ case HCI_EV_REMOTE_NAME: return "HCI_EV_REMOTE_NAME";
+ case HCI_EV_ENCRYPT_CHANGE: return "HCI_EV_ENCRYPT_CHANGE";
+ case HCI_EV_CHANGE_LINK_KEY_COMPLETE : return "HCI_EV_CHANGE_LINK_KEY_COMPLETE";
+ case HCI_EV_REMOTE_FEATURES: return "HCI_EV_REMOTE_FEATURES";
+ case HCI_EV_REMOTE_VERSION: return "HCI_EV_REMOTE_VERSION";
+ case HCI_EV_QOS_SETUP_COMPLETE : return "HCI_EV_QOS_SETUP_COMPLETE";
+ case HCI_EV_CMD_COMPLETE: return "HCI_EV_CMD_COMPLETE";
+ case HCI_EV_CMD_STATUS: return "HCI_EV_CMD_STATUS";
+ case HCI_EV_ROLE_CHANGE: return "HCI_EV_ROLE_CHANGE";
+ case HCI_EV_NUM_COMP_PKTS: return "HCI_EV_NUM_COMP_PKTS";
+ case HCI_EV_MODE_CHANGE: return "HCI_EV_MODE_CHANGE";
+ case HCI_EV_PIN_CODE_REQ: return "HCI_EV_PIN_CODE_REQ";
+ case HCI_EV_LINK_KEY_REQ: return "HCI_EV_LINK_KEY_REQ";
+ case HCI_EV_LINK_KEY_NOTIFY: return "HCI_EV_LINK_KEY_NOTIFY";
+ case HCI_EV_CLOCK_OFFSET: return "HCI_EV_CLOCK_OFFSET";
+ case HCI_EV_PKT_TYPE_CHANGE: return "HCI_EV_PKT_TYPE_CHANGE";
+ case HCI_EV_PSCAN_REP_MODE: return "HCI_EV_PSCAN_REP_MODE";
+ case HCI_EV_INQUIRY_RESULT_WITH_RSSI : return "HCI_EV_INQUIRY_RESULT_WITH_RSSI";
+ case HCI_EV_REMOTE_EXT_FEATURES: return "HCI_EV_REMOTE_EXT_FEATURES";
+ case HCI_EV_SYNC_CONN_COMPLETE: return "HCI_EV_SYNC_CONN_COMPLETE";
+ case HCI_EV_SYNC_CONN_CHANGED: return "HCI_EV_SYNC_CONN_CHANGED";
+ case HCI_EV_SNIFF_SUBRATE: return "HCI_EV_SNIFF_SUBRATE";
+ case HCI_EV_EXTENDED_INQUIRY_RESULT: return "HCI_EV_EXTENDED_INQUIRY_RESULT";
+ case HCI_EV_IO_CAPA_REQUEST: return "HCI_EV_IO_CAPA_REQUEST";
+ case HCI_EV_SIMPLE_PAIR_COMPLETE: return "HCI_EV_SIMPLE_PAIR_COMPLETE";
+ case HCI_EV_REMOTE_HOST_FEATURES: return "HCI_EV_REMOTE_HOST_FEATURES";
+ }
+ return "Unknown Event";
+}
+
+const char* CmdStr(int cmd)
+{
+ switch (cmd)
+ {
+ // 0x04XX
+ case HCI_OP_INQUIRY: return "HCI_OP_INQUIRY";
+ case HCI_OP_INQUIRY_CANCEL: return "HCI_OP_INQUIRY_CANCEL";
+ case HCI_OP_EXIT_PERIODIC_INQ: return "HCI_OP_EXIT_PERIODIC_INQ";
+ case HCI_OP_CREATE_CONN: return "HCI_OP_CREATE_CONN";
+ case HCI_OP_DISCONNECT: return "HCI_OP_DISCONNECT";
+ case HCI_OP_ADD_SCO: return "HCI_OP_ADD_SCO";
+ case HCI_OP_CREATE_CONN_CANCEL: return "HCI_OP_CREATE_CONN_CANCEL";
+ case HCI_OP_ACCEPT_CONN_REQ: return "HCI_OP_ACCEPT_CONN_REQ";
+ case HCI_OP_REJECT_CONN_REQ: return "HCI_OP_REJECT_CONN_REQ";
+ case HCI_OP_LINK_KEY_REPLY: return "HCI_OP_LINK_KEY_REPLY";
+ case HCI_OP_LINK_KEY_NEG_REPLY: return "HCI_OP_LINK_KEY_NEG_REPLY";
+ case HCI_OP_PIN_CODE_REPLY: return "HCI_OP_PIN_CODE_REPLY";
+ case HCI_OP_PIN_CODE_NEG_REPLY: return "HCI_OP_PIN_CODE_NEG_REPLY";
+ case HCI_OP_CHANGE_CONN_PTYPE: return "HCI_OP_CHANGE_CONN_PTYPE";
+ case HCI_OP_AUTH_REQUESTED: return "HCI_OP_AUTH_REQUESTED";
+ case HCI_OP_SET_CONN_ENCRYPT: return "HCI_OP_SET_CONN_ENCRYPT";
+ case HCI_OP_CHANGE_CONN_LINK_KEY: return "HCI_OP_CHANGE_CONN_LINK_KEY";
+ case HCI_OP_REMOTE_NAME_REQ: return "HCI_OP_REMOTE_NAME_REQ";
+ case HCI_OP_REMOTE_NAME_REQ_CANCEL: return "HCI_OP_REMOTE_NAME_REQ_CANCEL";
+ case HCI_OP_READ_REMOTE_FEATURES: return "HCI_OP_READ_REMOTE_FEATURES";
+ case HCI_OP_READ_REMOTE_EXT_FEATURES: return "HCI_OP_READ_REMOTE_EXT_FEATURES";
+ case HCI_OP_READ_REMOTE_VERSION: return "HCI_OP_READ_REMOTE_VERSION";
+ case HCI_OP_SETUP_SYNC_CONN: return "HCI_OP_SETUP_SYNC_CONN";
+ case HCI_OP_ACCEPT_SYNC_CONN_REQ: return "HCI_OP_ACCEPT_SYNC_CONN_REQ";
+ case HCI_OP_REJECT_SYNC_CONN_REQ: return "HCI_OP_REJECT_SYNC_CONN_REQ";
+ // 0x0CXX
+ case HCI_OP_SET_EVENT_MASK: return "HCI_OP_SET_EVENT_MASK";
+ case HCI_OP_RESET: return "HCI_OP_RESET";
+ case HCI_OP_SET_EVENT_FLT: return "HCI_OP_SET_EVENT_FLT";
+ case HCI_OP_WRITE_LOCAL_NAME: return "HCI_OP_WRITE_LOCAL_NAME";
+ case HCI_OP_READ_LOCAL_NAME: return "HCI_OP_READ_LOCAL_NAME";
+ case HCI_OP_WRITE_CA_TIMEOUT: return "HCI_OP_WRITE_CA_TIMEOUT";
+ case HCI_OP_WRITE_PG_TIMEOUT: return "HCI_OP_WRITE_PG_TIMEOUT";
+ case HCI_OP_WRITE_SCAN_ENABLE: return "HCI_OP_WRITE_SCAN_ENABLE";
+ case HCI_OP_READ_AUTH_ENABLE: return "HCI_OP_READ_AUTH_ENABLE";
+ case HCI_OP_WRITE_AUTH_ENABLE: return "HCI_OP_WRITE_AUTH_ENABLE";
+ case HCI_OP_READ_ENCRYPT_MODE: return "HCI_OP_READ_ENCRYPT_MODE";
+ case HCI_OP_WRITE_ENCRYPT_MODE: return "HCI_OP_WRITE_ENCRYPT_MODE";
+ case HCI_OP_READ_CLASS_OF_DEV: return "HCI_OP_READ_CLASS_OF_DEV";
+ case HCI_OP_WRITE_CLASS_OF_DEV: return "HCI_OP_WRITE_CLASS_OF_DEV";
+ case HCI_OP_READ_VOICE_SETTING: return "HCI_OP_READ_VOICE_SETTING";
+ case HCI_OP_WRITE_VOICE_SETTING: return "HCI_OP_WRITE_VOICE_SETTING";
+ case HCI_OP_HOST_BUFFER_SIZE: return "HCI_OP_HOST_BUFFER_SIZE";
+ case HCI_OP_READ_SSP_MODE: return "HCI_OP_READ_SSP_MODE";
+ case HCI_OP_WRITE_SSP_MODE: return "HCI_OP_WRITE_SSP_MODE";
+
+ // 10xx
+ case HCI_OP_READ_LOCAL_VERSION: return "HCI_OP_READ_LOCAL_VERSION";
+ case HCI_OP_READ_LOCAL_COMMANDS: return "HCI_OP_READ_LOCAL_COMMANDS";
+ case HCI_OP_READ_LOCAL_FEATURES: return "HCI_OP_READ_LOCAL_FEATURES";
+ case HCI_OP_READ_LOCAL_EXT_FEATURES: return "HCI_OP_READ_LOCAL_EXT_FEATURES";
+ case HCI_OP_READ_BUFFER_SIZE: return "HCI_OP_READ_BUFFER_SIZE";
+ case HCI_OP_READ_BD_ADDR: return "HCI_OP_READ_BD_ADDR";
+ }
+ return "Unknown Cmd";
+}
+
+const char* HCIErrStr(int err)
+{
+ switch (err)
+ {
+ case 0: return "OK";
+ case HCI_UNKNOWN_HCI_COMMAND: return "HCI_UNKNOWN_HCI_COMMAND";
+ case HCI_NO_CONNECTION: return "HCI_NO_CONNECTION";
+ case HCI_HW_FAILURE: return "HCI_HW_FAILURE";
+ case HCI_PAGE_TIMEOUT: return "HCI_PAGE_TIMEOUT";
+ case HCI_AUTHENTICATION_FAILURE: return "HCI_AUTHENTICATION_FAILURE";
+ case HCI_KEY_MISSING: return "HCI_KEY_MISSING";
+ case HCI_MEMORY_FULL: return "HCI_MEMORY_FULL";
+ case HCI_CONN_TIMEOUT: return "HCI_CONN_TIMEOUT";
+ case HCI_MAX_NUMBER_OF_CONNECTIONS: return "HCI_CONN_TIMEOUT";
+ case HCI_MAX_NUMBER_OF_SCO_CONNECTIONS_TO_DEVICE: return "HCI_MAX_NUMBER_OF_SCO_CONNECTIONS_TO_DEVICE";
+ case HCI_ACL_CONNECTION_EXISTS: return "HCI_ACL_CONNECTION_EXISTS";
+ case HCI_COMMAND_DISSALLOWED: return "HCI_COMMAND_DISSALLOWED";
+ case HCI_HOST_REJECTED_DUE_TO_LIMITED_RESOURCES: return "HCI_HOST_REJECTED_DUE_TO_LIMITED_RESOURCES";
+ case HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS: return "HCI_HOST_REJECTED_DUE_TO_SECURITY_REASONS";
+ case HCI_HOST_REJECTED_DUE_TO_REMOTE_DEVICE_ONLY_PERSONAL_SERVICE: return "HCI_HOST_REJECTED_DUE_TO_REMOTE_DEVICE_ONLY_PERSONAL_SERVICE";
+ case HCI_HOST_TIMEOUT: return "HCI_HOST_TIMEOUT";
+ case HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE: return "HCI_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE";
+ case HCI_INVALID_HCI_COMMAND_PARAMETERS: return "HCI_INVALID_HCI_COMMAND_PARAMETERS";
+ case HCI_OTHER_END_TERMINATED_CONN_USER_ENDED: return "HCI_OTHER_END_TERMINATED_CONN_USER_ENDED";
+ case HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES: return "HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES";
+ case HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF: return "HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF";
+ case HCI_CONN_TERMINATED_BY_LOCAL_HOST: return "HCI_CONN_TERMINATED_BY_LOCAL_HOST";
+ case HCI_REPETED_ATTEMPTS: return "HCI_REPETED_ATTEMPTS";
+ case HCI_PAIRING_NOT_ALLOWED: return "HCI_PAIRING_NOT_ALLOWED";
+ case HCI_UNKNOWN_LMP_PDU: return "HCI_UNKNOWN_LMP_PDU";
+ case HCI_UNSUPPORTED_REMOTE_FEATURE: return "HCI_UNSUPPORTED_REMOTE_FEATURE";
+ case HCI_SCO_OFFSET_REJECTED: return "HCI_SCO_OFFSET_REJECTED";
+ case HCI_SCO_INTERVAL_REJECTED: return "HCI_SCO_INTERVAL_REJECTED";
+ case HCI_SCO_AIR_MODE_REJECTED: return "HCI_SCO_AIR_MODE_REJECTED";
+ case HCI_INVALID_LMP_PARAMETERS: return "HCI_INVALID_LMP_PARAMETERS";
+ case HCI_UNSPECIFIED_ERROR: return "HCI_UNSPECIFIED_ERROR";
+ case HCI_UNSUPPORTED_LMP_PARAMETER_VALUE: return "HCI_UNSUPPORTED_LMP_PARAMETER_VALUE";
+ case HCI_ROLE_CHANGE_NOT_ALLOWED: return "HCI_ROLE_CHANGE_NOT_ALLOWED";
+ case HCI_LMP_RESPONSE_TIMEOUT: return "HCI_LMP_RESPONSE_TIMEOUT";
+ case HCI_LMP_ERROR_TRANSACTION_COLLISION: return "HCI_LMP_ERROR_TRANSACTION_COLLISION";
+ case HCI_LMP_PDU_NOT_ALLOWED: return "HCI_LMP_PDU_NOT_ALLOWED";
+ case HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE: return "HCI_ENCRYPTION_MODE_NOT_ACCEPTABLE";
+ case HCI_UNIT_KEY_USED: return "HCI_UNIT_KEY_USED";
+ case HCI_QOS_NOT_SUPPORTED: return "HCI_QOS_NOT_SUPPORTED";
+ case HCI_INSTANT_PASSED: return "HCI_INSTANT_PASSED";
+ case HCI_PAIRING_UNIT_KEY_NOT_SUPPORTED: return "HCI_PAIRING_UNIT_KEY_NOT_SUPPORTED";
+ };
+ return "Unknow HCI err";
+};
+
+
+#endif // HCI_PRIVATE_H_INCLUDED