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 4:b94984a20500, committed 2011-05-08
- Comitter:
- networker
- Date:
- Sun May 08 18:30:10 2011 +0000
- Parent:
- 3:50196dce45f8
- Child:
- 5:378c208637e3
- Commit message:
Changed in this revision
--- a/AvailableMemory.lib Wed May 04 09:31:15 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/networker/code/AvailableMemory/#2b2aa11cebd7
--- a/FATFileSystem.lib Wed May 04 09:31:15 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 Sun May 08 18:30:10 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 Sun May 08 18:30:10 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 Sun May 08 18:30:10 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 Sun May 08 18:30:10 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 Wed May 04 09:31:15 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,254 +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" -#include "btserial.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; - -//int bulk = 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]); -} - -const char FtDevClass[3] = {0x00, 0x1F, 0x82 }; -const char SerDevClass[3] = {4, 1, 0x00}; -// 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"); - printf("my address = "); - printf((BD_ADDR*)data); - 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: { - connection_info *ci = (connection_info*)data; - if (ci->status>0) { - printf("Connection failed, status=0x%02X\n", ci->status); - break; - } - ConnectionComplete(ci); - printf("Going to open sdp socket\n"); - L2CAPAddr addr; - memcpy(&addr.bdaddr, &ci->bdaddr, 6); - //int s = SDP.Open(&addr.hdr); - } - break; - case CALLBACK_PIN_REQ: - printf("Enter PIN for "); - printf((BD_ADDR*)data); - printf(" : submitting %s\n", pin); - //USBLoop(); wait(1.0); USBLoop(); - //for(int k=0; k<2000000;k++) USBLoop(); - PinCodeReply(data, pin); - break; - default: - printf("Unhandled HCI Callback %d\n", evt); - }; - 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);//the callback is virtual - App.Inquiry();//start discovery of BT devices phase 0 - return 0; -} - -DigitalOut led(LED1), loop(LED2); - -int comm = 0; -btserial *incoming; - -void echo(int socket, SocketState state, const u8* data, int len, void* userData) { -printf("Echo: socket %d, state %d, len=%d\n", socket, state, len); - if (state==SocketState_Open && len>0) { - Socket_Send(socket, data, len); - printfBytes("echo:", data, len); - } -} - -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; - //comm = Socket_Listen(SOCKET_RFCOM, 1, echo, 0); - incoming = new btserial(1); - } - break; - case 2://main loop - if (incoming->readable()>0){ - int c= incoming->getc(); - putc(c, stderr); - incoming->putc(c); - } - else if (incoming->readable()<0){ - state = 3; - printf("end of session"); - delete incoming; - } - 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 Sun May 08 18:30:10 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 Sun May 08 18:30:10 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/btserial.cpp Wed May 04 09:31:15 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -#include "btserial.h" btserial::btserial(char ba[6], char ch) { L2CAPAddr a; memcpy(&a.bdaddr, ba, 6); a.psm = ch; sendptr = 0; recptrin = 0; recptrout = bufsize - 1; free = bufsize; sock = Socket_Open(SOCKET_RFCOM, &a.hdr, cb, this); } btserial::btserial(char ch) { sendptr = 0; recptrin = 0; recptrout = bufsize - 1; free = bufsize; sock = Socket_Listen(SOCKET_RFCOM, ch, cb, this); } void btserial::cb(int socket, SocketState state, const unsigned char *data, int len, void* userData) { btserial *self = (btserial*)userData; if (state == SocketState_Open) if (len > 0) self->stash(data, len); else { port_settings ps;//defaults are ok ps.baud = 3; //9600 baud ps.bits = 3;//8 bits ps.stop = 0;//1 bit ps.par = 0; //no parity ps.mask = MASK_BITRATE|MASK_DATABITS|MASK_STOPBITS|MASK_PARITYBITS; //set_remote_port_parameters(sock, &ps); self->open = true; } else if (state == SocketState_Closed) self->open = false; } void btserial::stash(const unsigned char *data, int len) { int i = 0; while (i < len && free>0) { recbuf[recptrin++] = data[i++]; if (recptrin == bufsize) recptrin = 0; free--; } } int btserial::getc() { if (free == bufsize || !open) return -1; free++; recptrout++; if (recptrout == bufsize) recptrout = 0; return recbuf[recptrout]; } int btserial::putc(int c) { if (sendptr==bufsize || !open) return -1; sendbuf[sendptr++] = c; if (sendptr==bufsize || c=='\n' || c=='\r') { Socket_Send(sock, sendbuf, sendptr); sendptr = 0; } return c; } void btserial::baud(int br) { int rates[] = {2400,4800,7200,9600,19200,38400,57600,115200,230400}; if (!open) return; for (int i = 0; i < sizeof(rates)/sizeof(int);i++) if (rates[i] == br) { port_settings ps; ps.baud = i; ps.mask = MASK_BITRATE; set_remote_port_parameters(sock, &ps); return; } printf("Illegal baudrate requested %d\n", br); } void btserial::format(int bits, Serial::Parity par, int stop) { if (!open) return; port_settings ps; ps.bits = bits-5; ps.stop = stop-1; switch (par) { case Serial::None: ps.par = 0; ps.par_t = 0; break; case Serial::Odd: ps.par = 1; ps.par_t = 0; break; case Serial::Even: ps.par = 1; ps.par_t = 1; break; case Serial::Forced0: ps.par = 1; ps.par_t = 3; break; case Serial::Forced1: ps.par = 1; ps.par_t = 2; break; } ps.mask = MASK_DATABITS|MASK_STOPBITS|MASK_PARITYBITS|MASK_PARITYTYPE; set_remote_port_parameters(sock, &ps); } \ No newline at end of file
--- a/btserial.h Wed May 04 09:31:15 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -#ifndef BTSERIAL_H -#define BTSERIAL_H -#include "mbed.h" -#include "RFCOMM.h" - -class btserial { - static const int bufsize = 127; - int sock; - unsigned char sendbuf[bufsize], recbuf[bufsize]; - int sendptr, recptrin, recptrout, free; - static void cb(int socket, SocketState state, const unsigned char *data, int len, void* userData); - void stash(const unsigned char *data, int len); - bool open; -public: - btserial(char ba[6], char ch);//outgoing - btserial(char ch);//incoming - void baud(int); - void format(int, Serial::Parity, int); - int putc(int); - int getc(); - int readable() { - if (!open) return -1; - return bufsize-free; - } - int writeable() { - if (!open) return -1; - return bufsize - sendptr; - } -}; - -#endif \ No newline at end of file
--- a/ftclasslibusbdevbt.cpp Wed May 04 09:31:15 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 Wed May 04 09:31:15 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 Sun May 08 18:30:10 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 Sun May 08 18:30:10 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 Sun May 08 18:30:10 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 Wed May 04 09:31:15 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 Wed May 04 09:31:15 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/63bcd7ba4912
--- a/myUSBHost.lib Wed May 04 09:31:15 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/networker/code/myUSBHost/#05d0fe737d3b
--- a/rfcomm.lib Wed May 04 09:31:15 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/networker/code/rfcomm/#9f3821db3048
--- a/sdp.lib Wed May 04 09:31:15 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/networker/code/sdp/#e8d2ebb7392e