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 2:0118da9e5169, committed 2011-05-04
- Comitter:
- networker
- Date:
- Wed May 04 09:10:11 2011 +0000
- Parent:
- 1:0dde58e0cccf
- Child:
- 3:50196dce45f8
- Commit message:
- Better support for imcoming connections
Changed in this revision
--- a/FATFileSystem.lib Mon Apr 04 16:47:10 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/mbed_unsupported/code/fatfilesystem/ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/HCITransportUSB.h Wed May 04 09:10:11 2011 +0000
@@ -0,0 +1,65 @@
+#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; //printf("HCI: %d bytes avail\n", len);
+ if (t){
+ printfBytes("HCICallback:", data, len);
+ 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){
+ printfBytes("ACLCallback:", data, len);
+ t->ACLRecv(data,len);
+ }
+ printf("ACL Read pending..\n");
+ USBBulkTransfer(device,0x82,data,MAX_ACL_SIZE,AclCallback,userData);
+ }
+
+ virtual void HCISend(const u8* data, int len) {
+ printfBytes("HCISend:", data, len);
+ USBControlTransfer(_device,REQUEST_TYPE_CLASS, 0, 0, 0,(u8*)data,len);
+ }
+
+ virtual int ACLSend(const u8* data, int len) { //printf("send %d bytes to usb\n", len);
+ if (len > _acl_mtu) {
+ printf("Max outgoing packet(%d) size exceeded, segmenting necessary, pktlen = %d\n", _acl_mtu, len);
+ return 0;
+ }
+#ifdef HOST_CONTR_FLOW
+ if (data_credits == 0)
+ printf("Waiting for ACL buffers...\n");
+ while (data_credits < 1) {
+ USBLoop();
+ }
+ data_credits--;
+#endif
+ printfBytes("ACLSend:", data, len);
+ return USBBulkTransfer(_device,0x02,(u8*)data,len);
+ }
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/L2CAP.cpp Wed May 04 09:10:11 2011 +0000
@@ -0,0 +1,585 @@
+/*
+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"
+#include "sdp.h"
+#include "RFCOMM.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
+
+#define TXID (++_txid?_txid:1)
+//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;
+ _txid = 1;
+ //cntr_cred = 1;
+}
+
+// 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
+int BTDevice::Accept(SocketInternal* sock, int scid, int rxid) {
+ L2CAPSocket* s = (L2CAPSocket*)sock;
+ s->scid = 0x40 + sock->ID-1; // are these reserved?
+ s->dcid = scid;
+ u16 p[4];
+ p[0] = s->scid;
+ p[1] = scid;
+ p[2] = 0; //success
+ p[3] = 0; //no further information
+ Send(L2CAP_CONN_RSP,rxid,p,4);
+ printf("send conn_rsp with dcid=%#x and scid=%#x\n", p[0],p[1]);
+ sock->State = SocketState_L2CAP_Config_wait;
+ 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);
+#ifdef HOST_CONTR_FLOW
+ pkts_sent++;
+#endif
+ _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, 30.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::CommandReject(u16 reason, u16 data0, u16 data1) {
+ u16 p[3];
+ p[0] = reason;
+ p[1] = data0;
+ p[2] = data1;
+ int parlen = 2;
+ switch(reason){
+ case 0: //command not understood
+ break;
+ case 1: //MTU exceeded
+ parlen = 4; //return actual mtu in data
+ break;
+ case 2: //invalid CID
+ parlen = 6; //return local, remote cid
+ break;
+ }
+ return Send(L2CAP_COMMAND_REJ,TXID,p,parlen);
+}
+
+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);
+}
+
+void server(int socket, SocketState state, const u8* data, int len, void* userData) {
+ // printfBytes("Server: ", data, len);
+ if (state==SocketState_Open && len>0)
+ SDP.SDPServer(socket, state, data, len, userData);
+}
+
+void serserver(int socket, SocketState state, const u8* data, int len, void* userData) {
+ printfBytes("serserver: ", data, len);
+ SocketHandler *h = (SocketHandler*)userData;
+ printf("userData refers to %s, state = %d\n", h->Name(), state);
+ if (state==SocketState_Open) {
+ if (len == 0) { //assume that the socket has just been opened and bind it to a new rfcomm server entity
+ printf("Calling RFCOMMManager::BindSocket\n");
+ rfcomm_manager.BindSocket(socket);
+ } else {
+ printf("Calling RFCOMMManager::SerServer\n");
+ rfcomm_manager.SerServer(socket, state, data, len, userData);
+ }
+ } else if (state==SocketState_L2CAP_WaitDisconnect) {
+ printf("Calling RFCOMMManager::SerServer\n");
+ rfcomm_manager.SerServer(socket, state, data, len, userData);
+ }
+}
+
+//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");
+ {
+ int scid = LE16(data+6);
+ int psm = LE16(data+4);
+ int rxid = data[1];
+ u16 p[4];
+ p[0] = 0; //no dcid
+ p[1] = scid;
+ p[3] = 0; //no further information
+ printf(" scid=%d, psm=%d\n", scid, psm);
+ int s = 0;
+ switch (psm) {
+ case L2CAP_PSM_SDP:
+ s = Socket_Accept(SOCKET_SDP, scid, rxid, server, this);//allocate an sdp socket but use it as L2CAP
+ break;
+ case L2CAP_PSM_RFCOMM: //SOCKET_RFCOM;
+#if 0
+ s = Socket_Accept(SOCKET_RFCOM, scid, rxid, serserver, this);//allocate an rfcomm socket
+ //using L2CAP i.o. RFCOM makes little difference in processing but it also changes the handler to HCI i.o. RFCOMMManager
+#else
+//an RFCOMM requests comes in from a known (this) device
+//the channel is not yet known
+ s = rfcomm_manager.FindSocket(this);//this should return 0 otherwise the remote device was asking a second rfcomm on the same device
+ if (s==0) {
+ printf("No connection to this device yet, allocate L2CAP Socket and accept\n");
+ //accept the connection, even though there may be no listener???
+ //have no choice because w/o acceptance no rfcomm req.
+ s = Socket_Accept(SOCKET_L2CAP, scid, rxid, serserver, this);//allocate an l2cap socket
+ //get a new l2cap socket, call HCI::Accept (fill in btdevice internals), then call BTDevice::Accept (send accept message)
+ //serserver is called on state changes (SocketInternal::SetState) and on received packets from the peer device to the new l2cap handle
+ //after sending the accept message, the devices will execute the normal l2cap connection state-machine
+ //ending in a call to SetState(Open) which will invoke 'serserver' for the first time
+//or something like:
+// s = Socket_Create(SOCKET_L2CAP, serserver, this);//allocate an l2cap socket
+// Accept(GetSocketInternal(s), scid, rxid);//send accept response, this would bypass HCI::Accept()
+ } else {
+ printf("Already had an L2CAP connection on socket %d\n", s);
+ }
+#endif
+ break;
+ default:
+ printf("PSM %d not supported\n", psm);
+ }
+ switch (s) {
+ case 0:
+ printf("Not a valid socket\n");
+ break;
+ case ERR_SOCKET_TYPE_NOT_FOUND:
+ p[2] = 2; //psm not supported
+ Send(L2CAP_CONN_RSP,rxid,p,4);
+ break;
+ case ERR_SOCKET_NONE_LEFT:
+ p[2] = 4; //no resources available
+ Send(L2CAP_CONN_RSP,rxid,p,4);
+ break;
+ }
+ }
+ 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+8);
+ 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 if (result == 1) {//pending, stay in the present state
+ } 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 len = LE16(data+2);
+ int scid = LE16(data+4);//flags (data[6] LSB is continuation flag, data[10],[11] are the MTU
+ int flags = LE16(data+6);
+ if (flags)
+ printf("Warning! Continuation flag in L2CAP configuration not supported\n");
+ 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
+ printf("Connection should be rejected\n");
+ break;
+ }
+ if (len > 4)
+ switch (data[8]) {
+ case 1:
+ peer_mtu = LE16(data+10);
+ printf("Peer L2CAP 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;
+ ConfigureRequest(s->dcid);
+ s->si.State = SocketState_L2CAP_Config_wait_rsp;
+ 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
+ printf("Configure failure should be indicated\n");
+ 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(dcid);
+ if (s){
+ s->si.SetState(SocketState_Closed);
+ DisconnectResponse(data[1], scid, dcid);
+ } else {
+ printf("request to disconnect cid %d fails, no such cid\n", dcid);
+ CommandReject(0, dcid, scid);
+ }
+ }
+ 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");
+}
+
+void BTDevice::ACLFwd(const u8* data, int len) {
+ if (l2cap_sock == 1)
+ Control(data, len);
+ else {
+ SocketInternal* s = (SocketInternal*)SCIDToSocket(l2cap_sock);//in fact cid in the l2cap header
+ if (s)
+ s->Recv(data,len);//forward to the sockethandler for the type
+ 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
+int BTDevice::ACLRecv(const u8* data, int acllen) {
+ //printfBytes("L2CP",data,acllen);
+ //cntr_cred--;
+ u16 handle = LE16(data);
+ if ((handle&0x0fff) != _handle) {
+ printf("unexpected handle %#x, this _handle=%#x\n", handle, _handle);
+ return 1;
+ }
+ //below is the ACL packet recombination engine
+ char pb = (handle>>12) & 3;
+ if (pb == 2)
+ segments = 1;
+ else
+ segments++;
+ int p = 4; //start of l2cap packet
+ int len = LE16(data+2); //length of l2cap pkt
+ while (p < acllen)
+ switch (contState) {
+ case 0://allow even for fragmented length field
+ plen = data[p++];//payload length lsb
+ contState = 1;
+ break;
+ case 1:
+ plen += data[p++]<<8; //payload length msb
+ 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 segments; //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;
+ return segments;
+ }//else stay in this state to wait for the rest
+ } else {//data contains (part of) next packet, never seen this happen
+ 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 segments;//flushed
+ }
+ break;
+ }//switch (and while)
+ return 0;//the buffers are not processed yet
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Socket.cpp Wed May 04 09:10:11 2011 +0000
@@ -0,0 +1,227 @@
+/*
+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 Create(int type, 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("Creating socket %d for type %d, invoking 'Open' on %p (=%s)\n", si->ID, type, h, h->Name());
+ return h->Create(si);
+ }
+ }
+ return ERR_SOCKET_NONE_LEFT;
+ }
+
+ 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 Listen(int type, int channel, 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("Passively opening socket %d for type %d, invoking 'Listen' on %p (=%s)\n", si->ID, type, h, h->Name());
+ int sn = h->Listen(si, channel);
+ if (sn < 0)
+ si->ID = 0;//free the socket when error
+ return sn;
+ }
+ }
+ return ERR_SOCKET_NONE_LEFT;
+ }
+
+ int Accept(int type, int scid, int rxid, 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("Accepting socket %d for type %d, invoking 'Accept' on %p (=%s)\n", si->ID, type, h, h->Name());
+ return h->Accept(si, scid, rxid);
+ }
+ }
+ 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){
+ printf("Close: socket %d not found\n");
+ return ERR_SOCKET_NOT_FOUND;
+ }
+ printf("Close: socket %d (type=%d)\n", socket, si->Type);
+ 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_Listen(int type, int channel, SocketCallback callback, void* userData) // Open a socket for listening
+{
+ return gSocketManager.Listen(type,channel,callback,userData);
+}
+
+int Socket_Accept(int type, int scid, int rxid, SocketCallback callback, void* userData) // Open a socket for an incoming connection
+{
+ return gSocketManager.Accept(type,scid,rxid,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 Wed May 04 09:10:11 2011 +0000
@@ -0,0 +1,119 @@
+/*
+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_Listen,
+ SocketState_Accepting,
+ SocketState_L2CAP_WaitConnect = 8,
+ 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_Create(int type, SocketCallback callback, void* userData); // Allocate a socket
+int Socket_Open(int type, SocketAddrHdr* addr, SocketCallback callback, void* userData); // Open a socket
+int Socket_Listen(int type, int channel, SocketCallback callback, void* userData); // Open a socket passive
+int Socket_Accept(int type, int scid, int rxid, SocketCallback callback, void* userData); // Open a socket for an incoming connection
+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) {
+ printf("Socket %d has been freed\n", ID);
+ ID = 0;
+ }
+ }
+};
+
+class SocketHandler
+{
+ public:
+ virtual int Create(SocketInternal* sock) { printf("SocketHandler::Create: not implemented for %s\n", Name()); return sock->ID;}
+ 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 int Listen(SocketInternal* sock, int channel) { printf("SocketHandler::Listen: not implemented for %s\n", Name());return 0;}
+ virtual int Accept(SocketInternal* sock, int scid, int rxid) { printf("SocketHandler::Accept: not implemented for %s\n", Name());return 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
+#define ERR_SOCKET_CANT_LISTEN -203
+
+#endif // SOCKET_H_INCLUDED
--- a/TestShell.cpp Mon Apr 04 16:47:10 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,223 +0,0 @@
-
-/*
-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 "mbed.h"
-#include <vector>
-#include "Utils.h"
-#include "USBHost.h"
-#include "hci.h"
-#include "HCITransportUSB.h"
-#include "RFCOMM.h"
-#include "ftclasslibusbdevbt.h"
-#include "sdp_data.h"
-#include "sdp.h"
-
-/************************************************
-TODO:
-mtu and credits are completely unhandled - in progress
-multiple rfcomm sessions should be possible - done
-SDP would be nice - beta
-multiple rfcomm channels are untested
-decoupling of rfcomm and application - much better
-packets are not reassembled - some are (HCI and ft application level)
-disconnect and timeouts
-************************************************/
-#define DEBUG 1
-int state = 0;
-
-void printf(const BD_ADDR* addr) {
- const u8* a = addr->addr;
- printf("%02X:%02X:%02X:%02X:%02X:%02X",a[5],a[4],a[3],a[2],a[1],a[0]);
-}
-
-//int bulk = 0;
-
-char FtDevClass[3] = {0x00, 0x1F, 0x82 };
-
-// Instance
-RFCOMMManager rfcomm_manager;
-
-class application : public HCI {
- BTDevice* devs[8];
- int count, i, pending;
-public:
- // We have connected to a device
- void ConnectionComplete(connection_info* info) {
- printf("ConnectionComplete ");
- BD_ADDR* a = &info->bdaddr;
- printf(a);
- printf("\n");
- RemoteNameRequest(a);
- for (i++; i < count; i++) {//find the next device to open
- printfBytes("DEVICE CLASS",devs[i]->_info.dev_class,3);
- if (devs[i]->_handle == 0 && memcmp(devs[i]->_info.dev_class, FtDevClass, 3)==0) {//or some other way to connect to RFCOMM devices
- BD_ADDR* bd = &devs[i]->_info.bdaddr;
- printf("Connecting to ");
- printf(bd);
- printf("\n");
- pending++;
- CreateConnection(bd); //some low level connect, just let it happen for now (sets pin, mtu etc.)
- printf("connection cmd was sent\n");
- return;
- }
- }
- //state = 1; //start the real application
- }
-
- void ConnectDevices() {
- count = GetDevices(devs,8);//get pointers to all bluetooth devices
- pending = 0;
- for (i = 0; i < count; i++) {
- printfBytes("DEVICE CLASS",devs[i]->_info.dev_class,3);
- if (devs[i]->_handle == 0 && memcmp(devs[i]->_info.dev_class, FtDevClass, 3)==0) {//or some other way to connect to RFCOMM devices
- BD_ADDR* bd = &devs[i]->_info.bdaddr;
- printf("Connecting to ");
- printf(bd);
- printf("\n");
- pending++;
- CreateConnection(bd); //some low level connect, just let it happen for now (sets pin, mtu etc.)
- printf("connection cmd was sent\n");
- return;
- }
- }
- if (pending == 0) state = 1;//for the case when there are no ft devices
- }
- virtual void Callback(HCI_CALLBACK_EVENT c, const u8* data, int len);
-} App; //application instance
-
-
-void application::Callback(HCI_CALLBACK_EVENT evt, const u8* data, int len) {//these events are forwarded (in)directly from HCIRecv
- unsigned char pin[] = "1234";
- printf("\x1b[%dm", 33);
- switch (evt) {
- case CALLBACK_READY:
- printf("CALLBACK_READY\n");
- Inquiry();//start the second phase of the discovery
- break;
-
- case CALLBACK_INQUIRY_RESULT: //optionally build the list of FT devices here
- printf("CALLBACK_INQUIRY_RESULT ");
- printf((BD_ADDR*)data);
- printf("\n");//data points to inquiry_info struct
-// RemoteNameRequest((BD_ADDR*)data);
- break;
-
- case CALLBACK_INQUIRY_DONE:
- printf("CALLBACK_INQUIRY_DONE\n");
- ConnectDevices();
- break;
-
- case CALLBACK_REMOTE_NAME: {
- BD_ADDR* addr = (BD_ADDR*)data;
- const char* name = (const char*)(data + 6);
- printf(addr);
- printf(" = % s\n",name);
- pending--;
- if (pending == 0) state = 1;
- }
- break;
-
- case CALLBACK_CONNECTION_COMPLETE:
- ConnectionComplete((connection_info*)data);
- {
- printf("Going to open sdp socket\n");
- L2CAPAddr addr;
- connection_info *ci = (connection_info*)data;
- memcpy(&addr.bdaddr, &ci->bdaddr, 6);
- addr.psm = 1;//should not matter
- int s = Socket_Open(SOCKET_SDP, &addr.hdr, &SDP.OnSockCallback, &SDP);
- }
- break;
- case CALLBACK_PIN_REQ:
- printf("Enter PIN for ");
- printf((BD_ADDR*)data);
- printf(" : submitting %s\n", pin);
- PinCodeReply(data, pin);
- break;
- };
- printf("\x1b[%dm", 0);
-}
-
-// these should be placed in the DMA SRAM
-typedef struct {
- u8 _hciBuffer[MAX_HCL_SIZE];
- u8 _aclBuffer[MAX_ACL_SIZE];
-} SRAMPlacement;
-
-HCITransportUSB _HCITransportUSB; //use USB as the transport to the radio
-
-int OnBluetoothInsert(int device) {//install the HCI and start discovery, user callbacks are made to HciCalback
- printf("Bluetooth inserted of %d\n",device);
- u32 sramLen;
- u8* sram = USBGetBuffer(&sramLen);
- sram = (u8*)(((u32)sram + 1023) & ~1023);
- SRAMPlacement* s = (SRAMPlacement*)sram;
- _HCITransportUSB.Open(device,s->_hciBuffer,s->_aclBuffer);//setup buffers for USB host, incoming data goes first to HCIRecv and ACLRecv
- RegisterSocketHandler(SOCKET_L2CAP,&App); //register the application::hci as handler for L2CAP events
- RegisterSocketHandler(SOCKET_RFCOM, &rfcomm_manager);//set the RFCOMMManager as the RFCOM socket handler
- if (RegisterSocketHandler(SOCKET_SDP, &SDP))
- printf("Could not register SDP socket type\n");
- App.Open(&_HCITransportUSB);
- App.Inquiry();//start discovery of BT devices phase 0
- return 0;
-}
-
-DigitalOut led(LED1), loop(LED2);
-
-void TestShell() {
- int n=0;
- USBInit();
- for (;;) {
- switch (state) {
- case 0: //inquiry and low-level connection
- break;
- case 1: {//initialisation
- printf("Ready to open ports\n");
- InitFtBtDeviceList();
- int n = GetNrOfFtBtDevices();
- printf("%d ft BT devices have been found\n", n);
- if (n > 0) {
- ftbtdev *d = GetFtUsbDeviceHandle(0);
- if (d==0) printf("could not get device handle\n");
- int sock = OpenFtBtDevice(d);
- }
- state = 2;
- }
- break;
- case 2://main loop
- break;
- default:
- break;
- }
- loop=1;
- USBLoop();
- loop=0;
- n++;
- if (n>=500000) {
- n=0;
- led = !led;
- }
- }
- //printf("Dropped out of main loop!\n");
-}
-
-//********************************************************************************************************************************
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Utils.cpp Wed May 04 09:10:11 2011 +0000
@@ -0,0 +1,49 @@
+
+
+#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 Wed May 04 09:10:11 2011 +0000
@@ -0,0 +1,42 @@
+#ifndef UTILS_H
+#define UTILS_H
+
+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);
+//void printf(const BD_ADDR* addr);
+
+#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;
+}
+
+#endif
\ No newline at end of file
--- a/ftclasslibusbdevbt.cpp Mon Apr 04 16:47:10 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,133 +0,0 @@
-#include "mbed.h"
-#include <vector>
-#include "Utils.h"
-#include "hci.h"
-#include "ftclasslibusbdevbt.h"
-
-//extern HCI* gHCI;
-class application;
-extern application App;
-
-void printf(const BD_ADDR* addr);
-
-void ftdev::receive(int socket, SocketState state, const u8* data, int len) {
- printf("ftdev::receive was called: socket %d, state=%d, length=%d\n", socket, state, len);
- unsigned char req[] = "\xdget_ser_num\xd";
- if (len==0) {
- switch (state) {
- case SocketState_Opening:
- break;
- case SocketState_Open:
- printf("sending request \n%s\n", req);
- Socket_Send(sock, req, strlen((char*)req));
- break;
- case SocketState_Closing:
- case SocketState_Closed:
- return;
- }
- } else {
- //printHex(data, len);
- parse(data, len);
- if (state==SocketState_Open)
- ;//Socket_Close(sock);//replace with ft primitive
- }
-}
-
-unsigned short ftdev::chksum() {
- unsigned short sum = (X1_len & 0xFF) + (X1_len >> 8);
- for (int i = 0; i < X1_len; i++)
- sum += X1_pkt[i];
- return -sum;
-}
-
-void ftdev::parse (const unsigned char *buf, unsigned len) {
- unsigned i = 0;
- while (i < len) {
- char c = buf[i++];
- switch (parseState) {
- case 0: //ascii state
- if (c==2)
- parseState = 1;
- else
- putc(c, stdout);
- break;
- case 1:
- if (c==0x55)
- parseState = 2;
- else {
- parseState = 0;
- printf("expected 0x55 in X1 header, found %02X\n", c);
- }
- break;
- case 2:
- X1_len = c<<8;
- parseState= 3;
- break;
- case 3:
- X1_len += c;
- parseState= 4;
- X1_pkt = new unsigned char[X1_len];
- X1_pos = 0;
- break;
- case 4:
- if (X1_pos < X1_len) X1_pkt[X1_pos++] = c;
- else parseState = 5;
- break;
- case 5:
- X1_crc = c<<8;
- parseState= 6;
- break;
- case 6:
- X1_crc += c;
- parseState= 7;
- break;
- case 7:
- if (c == 3 && X1_crc == chksum()) {
- //handlePkt();
- printHex(X1_pkt, X1_len);
- }else
- printf("framing or checksum error, end char = %02X\n", c);
-
- parseState = 0;
- break;
- }
- }
-}
-
-vector<ftbtdev*> ft_devs;
-ftdev _ftdev; //single instance, just for test
-
-int GetNrOfFtBtDevices() {
- return ft_devs.size();
-}
-
-unsigned InitFtBtDeviceList() {//assume inquiry has been done
- static char FtDevClass[3] = {0x00, 0x1F, 0x82 };
- BTDevice* devs[8];
- int count = ((HCI*)&App)->GetDevices(devs,8);
- int n = 0;
- for (int i = 0; i < count; i++) {
- if (memcmp(devs[i]->_info.dev_class, FtDevClass, 3)==0) {
- ft_devs.push_back(new ftbtdev(&devs[i]->_info));
- printf("%d: %s\n", n++, devs[i]->_name);
- }
-// printf("device %d (handle=%d) ", i, devs[i]->_handle);
-// printfBytes("devclass: ", devs[i]->_info.dev_class, 3);
- }
- return n;
-}
-
-ftbtdev* GetFtUsbDeviceHandle(unsigned Num) {
- if (Num < ft_devs.size()) {
- return ft_devs[Num];
- }
- return 0;
-}
-
-unsigned OpenFtBtDevice(ftbtdev* d) {
- BD_ADDR* bd = d->BtAddr();
- printf("Connecting to ");
- printf(bd);
- printf("\n");
- return _ftdev.Open(bd, 1); //TODO: everything can go wrong here
-}
--- a/ftclasslibusbdevbt.h Mon Apr 04 16:47:10 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-#ifndef FTCLASSLIBUSBDEVBT_H
-#define FTCLASSLIBUSBDEVBT_H
-
-
-class ftbtdev {//small object for ft BT enumeration
- inquiry_info info;
-public:
- ftbtdev(inquiry_info* ii) {
- info = *ii;
- }
- BD_ADDR* BtAddr() {
- return &info.bdaddr;
- }
-};
-
-class ftdev {//this should in the future encapsulate the real TXC
- int sock;
- int parseState;
- unsigned short X1_crc, X1_len, X1_pos;
- unsigned char *X1_pkt;
- unsigned short chksum();
- void parse(const unsigned char *, unsigned);
-public:
- ftdev(): sock(0) { parseState = 0;}
- int Open(BD_ADDR *bt_addr, int chan=1, SocketCallback cb=&ftdev::recv) {
- L2CAPAddr s;
- s.bdaddr = *bt_addr;
- s.psm = chan;//abuse the psm for the channelID
- sock = Socket_Open(SOCKET_RFCOM, &s.hdr, cb, this);//Open the serial connection via RFCOMM
- if (sock<=0)
- printf("Opening of RFCOMM socket for ftdevice failed (%d)\n", sock);
- return sock;
- }
- static void recv(int socket, SocketState state, const u8* data, int len, void* userData) {
- if (userData) ((ftdev*)userData)->receive(socket, state, data, len);
- }
- void receive(int socket, SocketState state, const u8* data, int len);// {printf("ftdev::receive was called: socket %d, state=%d, length=%d\n", socket, state, len);}
-};
-
-extern ftdev _ftdev;
-
-unsigned InitFtBtDeviceList();
-int GetNrOfFtBtDevices();
-ftbtdev* GetFtUsbDeviceHandle(unsigned Num);
-unsigned OpenFtBtDevice(ftbtdev* d);
-
-#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hci.cpp Wed May 04 09:10:11 2011 +0000
@@ -0,0 +1,558 @@
+
+/*
+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
+#include "HCITransportUSB.h" //for ACL/HCL buffer size
+
+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
+};
+
+static const u8 local_name[] = "MBED";
+
+
+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;
+ }
+#ifdef COMMAND_FLOW
+ cmd_credits = 1;
+#endif
+ 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;
+}
+
+//reports that some commands are still in progress
+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[256];
+ b[0] = cmd;
+ b[1] = (cmd >> 8);
+ b[2] = len;
+ if (params)
+ memcpy(b+3,params,len);
+#ifdef COMMAND_FLOW
+ //printf("%d cmd_credits\n", cmd_credits);
+ while (cmd_credits == 0) {//blocks when command credits run out
+ USBLoop();
+ putc('_', stdout);
+ }
+#endif
+ _transport->HCISend(b,len+3);
+ return 0;
+}
+
+void HCI::OnCommandComplete(int cmd, const u8* data, int len) {//data is exclusive the status byte
+ //printf("%04X %s",cmd,CmdStr(cmd));
+ if (len < 0)
+ return;
+ //printfBytes(" complete",data,len/*min(16,len)*/);
+
+ switch (cmd) {
+ case 0: //NOP
+ printf("Received NOP command (for cmd_credits)\n");
+ break;
+ // 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);
+#ifdef HOST_CONTR_FLOW
+ _transport->data_credits = _acl_max_pkt;
+ _transport->_acl_mtu = _acl_mtu;
+#endif
+ 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;
+ {
+#ifdef CONTR_HOST_FLOW
+ unsigned char param[7];
+ param[0] = (u8)(MAX_ACL_SIZE-8);
+ param[1] = (u8)((MAX_ACL_SIZE-8)>>8);
+ param[2] = 0;//MAX_HCL_SIZE-8;
+ param[3] = 10;
+ param[4] = 0; //1 ACL buffer
+ param[5] = 0;
+ param[6] = 0; //0 Synchronous buffers
+ SendCmd(HCI_OP_HOST_BUFFER_SIZE, param, 7);
+ const unsigned char flow = 1;//ACL on, Synchonous off
+ SendCmd(HCI_OP_CONTR_TO_HOST_FLOW, &flow, 1);
+#endif
+ const unsigned char scan_enable = 3;
+ SendCmd(HCI_OP_WRITE_SCAN_ENABLE, &scan_enable, 1);
+ SendCmd(HCI_OP_WRITE_LOCAL_NAME, local_name, 248);
+ }
+ Callback(CALLBACK_READY,data,6);
+ break;
+
+ // 0CXX
+ case HCI_OP_READ_LOCAL_NAME:
+ case HCI_OP_LINK_KEY_NEG_REPLY:
+ case HCI_OP_WRITE_SCAN_ENABLE:
+ case HCI_OP_WRITE_LOCAL_NAME:
+ break;
+#ifdef CONTR_HOST_FLOW
+ case HCI_OP_CONTR_TO_HOST_FLOW:
+ case HCI_OP_HOST_BUFFER_SIZE:
+ break;
+ case HCI_OP_NUM_COMP_PKTS:
+ printf("Host number of Completed Packets: Invalid HCI Command Parameter\n");
+ break;
+#endif
+ 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 Completion %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) {
+ printf("BT Device not known!?! "); printf(&info->bdaddr);printf("\n");
+ return;
+ }
+ if (info->status == 0) {
+ d->_handle = info->handle;
+#ifdef HOST_CONTR_FLOW
+ d->pkts_sent = 0;
+#endif
+ printf("Connected on %04X\n",info->handle);
+ } else
+ printf("Connection failed with %d\n",info->status);
+}
+
+void HCI::Accept_Connection(const BD_ADDR* addr, bool slave) {
+ unsigned char b[7];
+ memcpy(b, addr, 6);
+ b[6] = slave;
+ BTDevice* bt = Find(addr);
+ if (!bt){
+ printf("Received connection request from undiscovered device\n");
+ for (int i = 0; i < MAX_BTDEVICES; i++) {
+ if (_devices[i]._state == 0) {
+ bt = _devices + i;
+ bt->_state = 1;
+ memcpy(&(bt->_info.bdaddr), addr, 6);//rest of inquiry info unknown!!!
+ break;
+ }
+ }
+ if (!bt) {
+ printf("HCI::InquiryResult too many devices\n");
+ return; // Too many devices!
+ }
+ }
+ SendCmd(HCI_OP_ACCEPT_CONN_REQ, b , 7);
+}
+
+void HCI::HCIRecv(const u8* data, int len) {//[0]=event, [1]=parlen, [2...]=pars
+ 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:
+ printf("Got Connection request \n");
+ Callback(CALLBACK_CONNECTION_REQUEST, data+2, data[1]);
+ Accept_Connection((BD_ADDR*)(data+2));
+ 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]);
+#ifdef COMMAND_FLOW
+ cmd_credits = data[3];
+#endif
+ }
+ Callback(CALLBACK_CMD_STATUS, data+2, 4);
+ break;
+
+ case HCI_EV_CMD_COMPLETE://[2]=cmd-pkts, [3-4]=cmd, [5...]=pars
+ if (data[5]) { //[5]=usually status
+ printf("HCIRecv error status: %s\n", HCIErrStr(data[5]));
+ }
+ OnCommandComplete(data[3] | (data[4] << 8), data+6, data[1]-4);
+#ifdef COMMAND_FLOW
+ cmd_credits = data[2];
+#endif
+ 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;
+#ifdef HOST_CONTR_FLOW
+ case HCI_EV_NUM_COMP_PKTS:
+ for (int k = 0; k < data[2]; k++) {//data[2] and 'c' are usually 1
+ u16 h = LE16(data+3+2*k);
+ u16 c = LE16(data+5+2*k);
+ BTDevice *d = Find(h);
+ if (!d)
+ continue;//skip no existing devices
+ if (d->pkts_sent >= c){
+ d->pkts_sent -= c;
+ _transport->data_credits += c;
+ }
+ else
+ d->pkts_sent = 0;
+ //printf("%d Outstanding pkts for handle %03X (total credits=%d)\n", d->pkts_sent, h, _transport->data_credits);
+ }
+ break;
+#endif
+ case HCI_EV_LINK_KEY_NOTIFY:
+ case HCI_EV_ENCRYPT_CHANGE:
+ //for(int k=0; k<1000000;k++) USBLoop();
+ 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::Accept(SocketInternal* sock, int scid, int rxid) {
+ L2CAPSocket* l2capsock = (L2CAPSocket*)sock;
+ BTDevice* bt = (BTDevice*)sock->userData;
+ if (!bt) {
+ printf("Can't accept l2cap on socket %d\n", sock->ID);
+ return ERR_HCI_DEVICE_NOT_FOUND;
+ }
+ l2capsock->btdevice = bt;
+ return bt->Accept(sock, scid, rxid);
+}
+
+int HCI::Send(SocketInternal* sock, const u8* data, int len) {//check here for appropriate buffersize on the device
+/* these checks are HCI functions but this 'Send' does not catch all ACL traffic, so it is better done in L2CAP or transport
+//assume acl packet
+//FIXME: treatment of OFFSET is dubious, OFFSET is not defined?!
+#if OFFSET==8 //sizeof ACL/L2CAP is include in data/len
+ if (len > _acl_mtu)
+#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);
+ }
+ if (data_credits == 0) {
+ printf("Out of ACL data credits\n");
+ return 0;
+ }
+ data_credits--;
+*/
+ 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::Compl_pkts(int handle, u8 p) {
+ u8 b[8] = {(u8)HCI_OP_NUM_COMP_PKTS, HCI_OP_NUM_COMP_PKTS >> 8, 5, 1, 0, 0, 1, 0};
+ b[4] = handle;
+ b[5] = (handle&0x0f00)>>8;
+ b[6] = p;//only one packet
+ _transport->HCISend(b, 8);//directly call the transport layer to prevent the command flow control from interfering
+}
+
+void HCI::ACLRecv(const u8* data, int len) {
+ int handle = LE16(data);
+ BTDevice* d = Find(handle & 0x0FFF);
+ int bufs = 1;
+ if (!d){
+ printfBytes("unk. dest. HCI:ACLRecv ", data, len);
+ }
+ else
+ bufs = d->ACLRecv(data,len);
+ //controller to host flow control
+#ifdef CONTR_HOST_FLOW
+//the ACLRecv function returned so we assume that the buffer is free, and tell this to the controller
+ if (bufs) {
+ Compl_pkts(handle, bufs);//this packet is completed
+ printf("%d ACL buffers completed\n", bufs);
+ }
+#endif
+}
+
+//===================================================================
+//===================================================================
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hci.h Wed May 04 09:10:11 2011 +0000
@@ -0,0 +1,276 @@
+/*
+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
+
+//#define CONTR_HOST_FLOW //Controller to Host flow control
+#define HOST_CONTR_FLOW //Host to Controller flow control
+#define COMMAND_FLOW //Command flow control
+
+#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;
+#ifdef HOST_CONTR_FLOW
+ u8 pkts_sent; //host to controller flow control
+#endif
+//u8 cntr_cred;
+u8 segments;
+ char _name[MAX_HCL_NAME_LENGTH];
+
+ void Init();
+
+ BD_ADDR* GetAddress() { return &_info.bdaddr; }
+
+ // Called from HCI
+ int ACLRecv(const u8* data, int len);
+ void ACLFwd(const u8* data, int len);
+
+ // SocketHandler
+ virtual int Open(SocketInternal* sock, SocketAddrHdr* addr);
+ virtual int Accept(SocketInternal* sock, int scid, int rxid);
+ 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 CommandReject(u16 reason=0, u16 data0=0, u16 data1=0);
+ 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,
+ CALLBACK_CONNECTION_REQUEST
+};
+
+// 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;
+#ifdef COMMAND_FLOW
+ char cmd_credits;//command flow control
+#endif
+//, data_credits;//host to controller flow control is per handle, hence is handled in BTDevice
+ 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 Accept(SocketInternal* sock, int scid, int rxid);
+ 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);
+ void Compl_pkts(int handle, u8 p = 1);
+protected:
+ int PinCodeReply(const u8* data, const u8* pin = "0000");
+ void Accept_Connection(const BD_ADDR* addr, bool slave=true);
+};
+
+class HCITransport
+{
+protected:
+ HCI* _target;
+public:
+#ifdef HOST_CONTR_FLOW
+ u8 data_credits;
+#endif
+ u16 _acl_mtu;
+ void Set(HCI* target) { _target = target; };
+ virtual void HCISend(const u8* data, int len) = 0;
+ virtual int ACLSend(const u8* data, int len) = 0;
+};
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hci_private.h Wed May 04 09:10:11 2011 +0000
@@ -0,0 +1,325 @@
+/*
+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_CONTR_TO_HOST_FLOW 0x0c31
+#define HCI_OP_HOST_BUFFER_SIZE 0x0c33
+#define HCI_OP_NUM_COMP_PKTS 0x0c35
+#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_REPEATED_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
--- a/main.cpp Mon Apr 04 16:47:10 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-/*
-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 "mbed.h"
-#include "USBHost.h"
-#include "Utils.h"
-#include "FATFileSystem.h"
-
-int MassStorage_ReadCapacity(int device, u32* blockCount, u32* blockSize);
-int MassStorage_Read(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize);
-int MassStorage_Write(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize);
-
-class USBFileSystem : public FATFileSystem
-{
- int _device;
- u32 _blockSize;
- u32 _blockCount;
-
-public:
- USBFileSystem() : FATFileSystem("usb"),_device(0),_blockSize(0),_blockCount(0)
- {
- }
-
- void SetDevice(int device)
- {
- _device = device;
- }
-
- virtual int disk_initialize()
- {
- return MassStorage_ReadCapacity(_device,&_blockCount,&_blockSize);
- }
-
- virtual int disk_write(const char *buffer, int block_number)
- {
- return MassStorage_Write(_device,block_number,1,(u8*)buffer,_blockSize);
- }
-
- virtual int disk_read(char *buffer, int block_number)
- {
- return MassStorage_Read(_device,block_number,1,(u8*)buffer,_blockSize);
- }
-
- virtual int disk_sectors()
- {
- return _blockCount;
- }
-};
-
-void DumpFS(int depth, int count)
-{
- DIR *d = opendir("/usb");
- if (!d)
- {
- printf("USB file system borked\n");
- return;
- }
-
- printf("\nDumping root dir\n");
- struct dirent *p;
- for(;;)
- {
- p = readdir(d);
- if (!p)
- break;
- int len = sizeof( dirent);
- printf("%s %d\n", p->d_name, len);
- }
- closedir(d);
-}
-
-int OnDiskInsert(int device)
-{
- USBFileSystem fs;
- fs.SetDevice(device);
- DumpFS(0,0);
- return 0;
-}
-
-/*
- Simple test shell to exercise mouse,keyboard,mass storage and hubs.
- Add 2 15k pulldown resistors between D+/D- and ground, attach a usb socket and have at it.
-*/
-
-Serial pc(USBTX, USBRX);
-int GetConsoleChar()
-{
- if (!pc.readable())
- return -1;
- char c = pc.getc();
- pc.putc(c); // echo
- return c;
-}
-
-void TestShell();
-
-int main()
-{
- pc.baud(460800);
- printf("BlueUSB\nNow get a bunch of usb or bluetooth things and plug them in\n");
- TestShell();
-}
--- a/mbed.bld Mon Apr 04 16:47:10 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/mbed_official/code/mbed/builds/49a220cc26e0
--- a/myUSBHost.lib Mon Apr 04 16:47:10 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/networker/code/myUSBHost/#d6bff1c2dab1
--- a/rfcomm.lib Mon Apr 04 16:47:10 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/networker/code/rfcomm/#8d7b47ceb9f5
--- a/sdp.lib Mon Apr 04 16:47:10 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/networker/code/sdp/#7493bf6bb1b9