Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed myUSBHost AvailableMemory
Dependents: mbed_TANK_Kinect myBlueUSB_ros ftusbClass
Revision 13:327622e38551, committed 2011-07-01
- Comitter:
- networker
- Date:
- Fri Jul 01 09:16:00 2011 +0000
- Parent:
- 12:57f7679dd651
- Commit message:
- made some improvements to get massstorage functioning
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AutoEvents.cpp Fri Jul 01 09:16:00 2011 +0000
@@ -0,0 +1,202 @@
+
+/*
+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"
+
+#define AUTOEVT(_class,_subclass,_protocol) (((_class) << 16) | ((_subclass) << 8) | _protocol)
+#define AUTO_KEYBOARD AUTOEVT(CLASS_HID,1,1)
+#define AUTO_MOUSE AUTOEVT(CLASS_HID,1,2)
+
+u8 auto_mouse[4]; // buttons,dx,dy,scroll
+u8 auto_keyboard[8]; // modifiers,reserved,keycode1..keycode6
+u8 auto_joystick[4]; // x,y,buttons,throttle
+
+void AutoEventCallback(int device, int endpoint, int status, u8* data, int len, void* userData) {
+ int evt = (int)userData;
+ switch (evt) {
+ case AUTO_KEYBOARD:
+ printf("AUTO_KEYBOARD ");
+ break;
+ case AUTO_MOUSE:
+ printf("AUTO_MOUSE ");
+ break;
+ default:
+ printf("HUH ");
+ }
+ printfBytes("data",data,len);
+ USBInterruptTransfer(device,endpoint,data,len,AutoEventCallback,userData);
+}
+
+// Establish transfers for interrupt events
+void AddAutoEvent(int device, InterfaceDescriptor* id, EndpointDescriptor* ed) {
+ if ((ed->bmAttributes & 3) != ENDPOINT_INTERRUPT || !(ed->bEndpointAddress & 0x80))
+ return;
+
+ // Make automatic interrupt enpoints for known devices
+ u32 evt = AUTOEVT(id->bInterfaceClass,id->bInterfaceSubClass,id->bInterfaceProtocol);
+ u8* dst = 0;
+ int len;
+ switch (evt) {
+ case AUTO_MOUSE:
+ dst = auto_mouse;
+ len = sizeof(auto_mouse);
+ break;
+ case AUTO_KEYBOARD:
+ dst = auto_keyboard;
+ len = sizeof(auto_keyboard);
+ break;
+ default:
+ printf("Interrupt endpoint %02X %08X\n",ed->bEndpointAddress,evt);
+ break;
+ }
+ if (dst) {
+ printf("Auto Event for %02X %08X\n",ed->bEndpointAddress,evt);
+ USBInterruptTransfer(device,ed->bEndpointAddress,dst,len,AutoEventCallback,(void*)evt);
+ }
+}
+
+void PrintString(int device, int i) {
+ u8 buffer[256];
+ int le = GetDescriptor(device,DESCRIPTOR_TYPE_STRING,i,buffer,255);
+ if (le < 0)
+ return;
+ char* dst = (char*)buffer;
+ for (int j = 2; j < le; j += 2)
+ *dst++ = buffer[j];
+ *dst = 0;
+ printf("%d:%s\n",i,(const char*)buffer);
+}
+
+// Walk descriptors and create endpoints for a given device
+int StartAutoEvent(int device, int configuration, int interfaceNumber) {
+ u8 buffer[255];
+ int err = GetDescriptor(device,DESCRIPTOR_TYPE_CONFIGURATION,0,buffer,255);
+ if (err < 0)
+ return err;
+
+ int len = buffer[2] | (buffer[3] << 8);
+ u8* d = buffer;
+ u8* end = d + len;
+ while (d < end) {
+ if (d[1] == DESCRIPTOR_TYPE_INTERFACE) {
+ InterfaceDescriptor* id = (InterfaceDescriptor*)d;
+ if (id->bInterfaceNumber == interfaceNumber) {
+ d += d[0];
+ while (d < end && d[1] != DESCRIPTOR_TYPE_INTERFACE) {
+ if (d[1] == DESCRIPTOR_TYPE_ENDPOINT)
+ AddAutoEvent(device,id,(EndpointDescriptor*)d);
+ d += d[0];
+ }
+ }
+ }
+ d += d[0];
+ }
+ return 0;
+}
+
+// Implemented in main.cpp
+int OnDiskInsert(int device, unsigned char in, unsigned char out);
+
+// Implemented in TestShell.cpp
+int OnBluetoothInsert(int device);
+
+EndpointDescriptor* GetNextEndpoint(unsigned char *d) {
+ while (d) {
+ switch (d[1]) {
+ case DESCRIPTOR_TYPE_INTERFACE:
+ case DESCRIPTOR_TYPE_CONFIGURATION:
+ return 0;
+ case DESCRIPTOR_TYPE_ENDPOINT:
+ return (EndpointDescriptor*)d;
+ default:
+ printf("Skipping descriptor %02X (%d bytes)\n",d[1],d[0]);
+ }
+ d += d[0];
+ }
+ return 0;
+}
+
+EndpointDescriptor* GetEndpoint(InterfaceDescriptor* interfaceDesc, int i) {
+ unsigned char *d = (unsigned char*)interfaceDesc;
+ int n = interfaceDesc->bNumEndpoints;
+ int j = 0;
+ if (i >= n)
+ return 0;
+ d += d[0];//move to first descriptor after the interface descriptor
+ while (j < n) {
+ switch (d[1]) {
+ case DESCRIPTOR_TYPE_INTERFACE:
+ case DESCRIPTOR_TYPE_CONFIGURATION:
+ return 0;
+ case DESCRIPTOR_TYPE_ENDPOINT:
+ if (i == j)
+ return (EndpointDescriptor*)d;
+ j++;
+ break;
+ default:
+ printf("Skipping descriptor %02X (%d bytes)\n",d[1],d[0]);
+ }
+ d += d[0];
+ }
+ return 0;
+}
+
+void OnLoadDevice(int device, DeviceDescriptor* deviceDesc, InterfaceDescriptor* interfaceDesc) {
+ printf("LoadDevice %d %02X:%02X:%02X\n",device,interfaceDesc->bInterfaceClass,interfaceDesc->bInterfaceSubClass,interfaceDesc->bInterfaceProtocol);
+ char s[128];
+ for (int i = 1; i < 3; i++) {
+ if (GetString(device,i,s,sizeof(s)) < 0)
+ break;
+ printf("%d: %s\n",i,s);
+ }
+
+ switch (interfaceDesc->bInterfaceClass) {
+ case CLASS_MASS_STORAGE:
+ if (interfaceDesc->bInterfaceSubClass == 0x06 && interfaceDesc->bInterfaceProtocol == 0x50) {
+ unsigned char epin = 0x81;
+ unsigned char epout = 0x01;
+ for (int i = 0; i < interfaceDesc->bNumEndpoints; i++){
+ EndpointDescriptor* ep = GetEndpoint(interfaceDesc, i);
+ if (ep){
+ if (ep->bEndpointAddress & 0x7F)
+ if (ep->bEndpointAddress & 0x80)
+ epin = ep->bEndpointAddress;
+ else
+ epout = ep->bEndpointAddress;
+ }else break;
+ }
+ printf("In = %02X, Out = %02X\n", epin, epout);
+ OnDiskInsert(device, epin, epout); // it's SCSI!
+ }
+ break;
+ case CLASS_WIRELESS_CONTROLLER:
+ if (interfaceDesc->bInterfaceSubClass == 0x01 && interfaceDesc->bInterfaceProtocol == 0x01)
+ OnBluetoothInsert(device); // it's bluetooth!
+ break;
+ default:
+ StartAutoEvent(device,1,0);
+ break;
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AvailableMemory.lib Fri Jul 01 09:16:00 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/networker/code/AvailableMemory/#2b2aa11cebd7
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FATFileSystem.lib Fri Jul 01 09:16:00 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_unsupported/code/fatfilesystem/ \ No newline at end of file
--- a/HCITransportUSB.h Sun Jun 19 19:32:51 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-#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
--- a/L2CAP.cpp Sun Jun 19 19:32:51 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,614 +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 <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);
- peer_mtu = 672; //default mtu
- 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);
- const u8* conf = data+8;
- 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 0
- if (len > 4)
- switch (data[8]) {
- case 1:
- peer_mtu = LE16(data+10);
- printf("Peer L2CAP MTU = %d bytes\n", peer_mtu);
- break;
- case 2: //flush timeout
- case 3: //QOS
- case 4: //retrans and FC option
- default:
- printf("Unsupported configuration option %d, value = %#X\n", data[8], LE16(data+10));
- break;
- }
- else
- printf("Empty config req. peer_mtu = %d\n", peer_mtu);
-#else
- while (conf < data+len+4) {
- bool hint = conf[0] & 0x80;
- switch (conf[0] & 0x7F) {
- case 1:
- peer_mtu = LE16(conf+2);
- printf("Peer L2CAP MTU = %d bytes\n", peer_mtu);
- break;
- case 2: //flush timeout
- case 3: //QOS
- case 4: //retrans and FC option
- default:
- printf("Unsupported configuration option %d, value = %#X\n", conf[0], LE16(conf+2));
- break;
- }
- conf += conf[1]+2;
- }
-#endif
- if (1 /* options acceptable */) {
- if (flags == 0) {
- 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
- printf("L2CAP config continuation, delaying response...\n");
- } 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
-}
--- a/Socket.cpp Sun Jun 19 19:32:51 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,253 +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 <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 SetOpt(int socket, int so, int* data, int len)
- {
- SocketInternal* si = GetInternal(socket);
- if (!si || si->ID != socket)
- return ERR_SOCKET_NOT_FOUND;
- return GetHandler(si->Type)->SetOpt(si, so, data,len);
- }
-
- int GetOpt(int socket, int so, int* data, int len)
- {
- SocketInternal* si = GetInternal(socket);
- if (!si || si->ID != socket)
- return ERR_SOCKET_NOT_FOUND;
- return GetHandler(si->Type)->GetOpt(si, so, data,len);
- }
-
- int Close(int socket)
- {
- SocketInternal* si = GetInternal(socket);
- if (!si || si->ID != socket){
- printf("Close: socket %d not found\n", socket);
- 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_SetOpt(int socket, int so, int* data, int len)
-{
- return gSocketManager.SetOpt(socket, so, data,len);
-}
-
-int Socket_GetOpt(int socket, int so, int* data, int len)
-{
- return gSocketManager.GetOpt(socket, so, 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);
-}
-
--- a/Socket.h Sun Jun 19 19:32:51 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,127 +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.
-*/
-
-#ifndef SOCKET_H_INCLUDED
-#define SOCKET_H_INCLUDED
-
-#define SOCKET_HCI 1
-#define SOCKET_L2CAP 2
-#define SOCKET_RFCOM 3
-#define SOCKET_SDP 4
-
-#define SO_RECBUF 1
-#define SO_SNDBUF 2
-#define NOPROTOOPT -100
-
-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_SetOpt(int socket, int so, int* data, int len);
-int Socket_GetOpt(int socket, int so, int* data, int len);
-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 int SetOpt(SocketInternal* sock, int so, int* data, int len) { printf("SocketHandler::SetOpt: not implemented for %s\n", Name());return 0;}
- virtual int GetOpt(SocketInternal* sock, int so, int* data, int len) { printf("SocketHandler::GetOpt: 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/TestShell.cpp Fri Jul 01 09:16:00 2011 +0000
@@ -0,0 +1,314 @@
+
+/*
+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"
+#include "neighbourhood.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);
+ int csr_write_bd_addr(BD_ADDR *bdaddr, bool transient=true);
+ int csr_reset_device(bool transient=true);
+} App; //application instance
+
+extern "C" void mbed_reset();
+
+
+void application::Callback(HCI_CALLBACK_EVENT evt, const u8* data, int len) {//these events are forwarded (in)directly from HCIRecv
+ unsigned char pin[] = "1234";
+ unsigned char newaddr[] = {0x2c, 0x07, 0x54, 0x7b, 0x13, 0x00};//possible ft TX address (ROBO TX-277)
+// unsigned char newaddr[] = {0x57, 0x0a, 0x3d, 0x83, 0x15, 0x00};//original address of the cheap round BT dongle
+ printf("\x1b[%dm", 33);
+ switch (evt) {
+ case CALLBACK_READY:
+ printf("CALLBACK_READY\n");
+ printf("my address = ");
+ printf((BD_ADDR*)data);
+ if (memcmp(newaddr, data, 6) != 0) { //csr_write_bd_addr((BD_ADDR*)newaddr, false);
+ }
+ 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");
+ neighbors = new neighbourhood(&App);
+ neighbors->read();
+ 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;
+ case CALLBACK_VENDOR:
+ printfBytes("Vendor Reply:", data, len);
+ //mbed_reset();
+ if (data[0] == 0xc2)
+ csr_reset_device(false);
+ break;
+ default:
+ printf("Unhandled HCI Callback %d\n", evt);
+ };
+ printf("\x1b[%dm", 0);
+}
+
+#define CSR_WRITE 0xFC00
+
+int application::csr_write_bd_addr(BD_ADDR *bdaddr, bool transient) {
+ unsigned char cmd[] = { 0xc2,
+ 0x02, 0x00, 0x0c, 0x00, 0x11, 0x47, 0x03, 0x70,
+ 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ if (transient)
+ cmd[15] = 0x08;
+
+ cmd[17] = bdaddr->addr[2];
+ cmd[18] = 0x00;
+ cmd[19] = bdaddr->addr[0];
+ cmd[20] = bdaddr->addr[1];
+ cmd[21] = bdaddr->addr[3];
+ cmd[22] = 0x00;
+ cmd[23] = bdaddr->addr[4];
+ cmd[24] = bdaddr->addr[5];
+
+ return SendCmd(CSR_WRITE, cmd, sizeof(cmd));
+}
+
+int application::csr_reset_device(bool transient) {
+ unsigned char cmd[] = { 0xc2, 0x02, 0x00, 0x09, 0x00,
+ 0x00, 0x00, 0x01, 0x40, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ if (transient)
+ cmd[7] = 0x02;
+
+ return SendCmd(CSR_WRITE, cmd, sizeof(cmd));
+}
+
+
+// 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, *outgoing;
+
+void echo(int socket, SocketState state, const u8* data, int len, void* userData) {
+ const u8 connack[] = { 0xbe, 0xef, 8, 'C','O','N','N','_','A','C','K', 0x11};
+ printf("Echo: socket %d, state %d, len=%d\n", socket, state, len);
+ if (state==SocketState_Open) {
+ if (len == 0) {
+ printf("Sending CONN_ACK\n");
+ Socket_Send(socket, connack, sizeof(connack));
+ } else {
+ //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");
+}
+
+//********************************************************************************************************************************
--- a/Utils.cpp Sun Jun 19 19:32:51 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-
-
-#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;
- }
-}
-
--- a/Utils.h Sun Jun 19 19:32:51 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-#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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/btserial.cpp Fri Jul 01 09:16:00 2011 +0000
@@ -0,0 +1,116 @@
+#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 {
+ //Socket_GetOpt(sock, SO_RECBUF, &recbufsize, sizeof(recbufsize));
+ //Socket_GetOpt(sock, SO_SNDBUF, &sndbufsize, sizeof(sndbufsize));
+ 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);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/btserial.h Fri Jul 01 09:16:00 2011 +0000
@@ -0,0 +1,32 @@
+#ifndef BTSERIAL_H
+#define BTSERIAL_H
+#include "mbed.h"
+#include "RFCOMM.h"
+
+class btserial {
+ static const int bufsize = 350;
+ int recbufsize, sndbufsize;
+ 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ftclasslibusbdevbt.cpp Fri Jul 01 09:16:00 2011 +0000
@@ -0,0 +1,134 @@
+#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";
+ unsigned char req[] = {0xbe, 0xef, 6, 0xfc, 0,0,0,0,0, 0xaf};
+ if (len==0) {
+ switch (state) {
+ case SocketState_Opening:
+ break;
+ case SocketState_Open:
+ printf("sending request \n%s\n", req);
+ Socket_Send(sock, req, sizeof(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
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ftclasslibusbdevbt.h Fri Jul 01 09:16:00 2011 +0000
@@ -0,0 +1,47 @@
+#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
--- a/hci.cpp Sun Jun 19 19:32:51 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,605 +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 <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
-#include "neighbourhood.h"
-
-extern const char FtDevClass[];
-const char FtDevClass[3] = {0x00, 0x1F, 0x82 };
-
-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";
-static const u8 local_name[] = "ROBO TX-599";
-
-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::SetEventFilter(u8 filterType, u8 filterConditionType, u8* condition) {
- int len = 2;
- u8 buf[8];
- buf[0] = filterType;
- buf[1] = filterConditionType;
- switch (filterConditionType) {
- case 0://all devices
- if (filterType==2) { //connection setup
- buf[2] = condition[0];
- len++;
- }
- break;
- case 1: //filter by class
- case 2: //filter by BDADDR
- memcpy(buf+2, condition, 6);
- len += 6;
- break;
- default:
- printf("Unknown filter condition type %d, filter type=%d\n", filterConditionType, filterType);
- }
- SendCmd(HCI_OP_SET_EVENT_FLT, buf, len);
- 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_CLASS_OF_DEV, (const u8*)FtDevClass, 3);
- //SendCmd(HCI_OP_READ_LOCAL_VERSION, 0, 0);
- 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;
- case HCI_READ_STORED_LINK_KEY:
- neighbors->set_cap(LE16(data), LE16(data+2));
- 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: {
- u8 param[22];
- if (neighbors->get((BD_ADDR*)(data+2), param+sizeof(BD_ADDR))){
- memcpy(param, data+2, sizeof(BD_ADDR));
- SendCmd(HCI_OP_LINK_KEY_REPLY,param,sizeof(param));
- } else
- 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:
- neighbors->add((BD_ADDR*)(data+2), data+8);
- break;
- case HCI_EV_RETURN_LINK_KEYS:
- for (int i = 0; i < data[2]; i++)
- neighbors->add((BD_ADDR*)(data+3+22*i), data+9+22*i, true);
- break;
- case HCI_EV_ENCRYPT_CHANGE:
- //for(int k=0; k<1000000;k++) USBLoop();
- break;
- case HCI_EV_VENDOR:
- Callback(CALLBACK_VENDOR, data+2, data[1]);
- 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
-}
-
-//===================================================================
-//===================================================================
--- a/hci.h Sun Jun 19 19:32:51 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,280 +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.
-*/
-
-#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,
- CALLBACK_VENDOR
-};
-
-// 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);
-
- int SetEventFilter(u8 filterType, u8 filterConditionType, u8* condition);
- // 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);
- 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 SendCmd(int cmd, const u8* params = 0, int len = 0);
- int PinCodeReply(const u8* data, const u8* pin = "0000");
- void Accept_Connection(const BD_ADDR* addr, bool slave=true);
-public:
- int SendCmd(int cmd, const u8* params = 0, int len = 0);
-};
-
-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
--- a/hci_private.h Sun Jun 19 19:32:51 2011 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,327 +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.
-*/
-
-#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_RETURN_LINK_KEYS 0x15
-#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
-#define HCI_EV_VENDOR 0xff
-
-/* 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Fri Jul 01 09:16:00 2011 +0000
@@ -0,0 +1,125 @@
+/*
+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"
+#include "MassStorage.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, public USBSCSI
+{
+ //int _device;
+ u32 _blockSize;
+ u32 _blockCount;
+
+public:
+ USBFileSystem() : FATFileSystem("usb")/*,_device(0)*/,_blockSize(0),_blockCount(0)
+ {
+ }
+/*
+ void SetDevice(int device, unsigned char in, unsigned char out)
+ {
+ _device = device;
+ }
+*/
+ virtual int disk_initialize()
+ {
+ return SCSIReadCapacity(&_blockCount,&_blockSize);
+ //return MassStorage_ReadCapacity(_device,&_blockCount,&_blockSize);
+ }
+
+ virtual int disk_write(const char *buffer, int block_number)
+ {
+ return SCSITransfer(block_number, 1,(u8*)buffer,_blockSize,HOST_TO_DEVICE);
+ //return MassStorage_Write(_device,block_number,1,(u8*)buffer,_blockSize);
+ }
+
+ virtual int disk_read(char *buffer, int block_number)
+ {
+ return SCSITransfer(block_number, 1, (u8*)buffer, _blockSize, DEVICE_TO_HOST);
+ //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, unsigned char in, unsigned char out)
+{
+ USBFileSystem fs;
+ fs.SetDevice(device, in, out);
+ 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();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Fri Jul 01 09:16:00 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/63bcd7ba4912
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/myUSBHost.lib Fri Jul 01 09:16:00 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/networker/code/myUSBHost/#58c785c2b381
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/neigbourhood/neighbourhood.cpp Fri Jul 01 09:16:00 2011 +0000
@@ -0,0 +1,69 @@
+#include "Utils.h"
+#include "neighbourhood.h"
+
+neighbourhood *neighbors = 0;
+
+int neighbourhood::get(BD_ADDR *a, unsigned char *key) {
+ for (list<item>::iterator i = keys.begin(); i != keys.end(); i++)
+ if (memcmp(a, &(*i).a, sizeof(BD_ADDR)) == 0) {
+ memcpy(key, (*i).lk, lksize);
+#ifdef STRICT_MRU
+ if (i != keys.begin()) {
+ keys.push_front(*i);
+ keys.erase(i);
+ dirty = true;
+ }
+#endif
+ return 1;
+ }
+ return 0;
+}
+
+int neighbourhood::add(BD_ADDR *a, const unsigned char *key, bool init) {
+ for (list<item>::iterator i = keys.begin(); i != keys.end(); i++)
+ if (memcmp(a, &(*i).a, sizeof(BD_ADDR)) == 0) {
+ memcpy((*i).lk, key, lksize); //assume key has changed, update key
+ (*i).used = true;
+ return 1;
+ }
+ //new key
+ printf("Neighbourhood: "); printf(a); printf("\n");
+ if (keys.size() < cap) {
+ keys.push_back(item(a, key, !init));//append as long as there is space
+ } else {
+ keys.push_front(item(a, key, true));//otherwise prepend
+ dirty = true;
+ }
+ return 0;
+}
+
+void neighbourhood::write() {
+ int n = 0;
+ static const int maxkey = 11;
+ unsigned char param[maxkey*(lksize+sizeof(BD_ADDR))+1];
+ int k = keys.size()-cap;
+ list<item>::iterator i = keys.begin();
+ while (i != keys.end()) {
+ if (k>0) {
+ if (!(*i).used) {
+ delete_link_key(&(*i).a);//try to make some room
+ keys.erase(i);
+ k--;
+ } else
+ i++;
+ } else
+ break;
+ }
+ //hci->delete_link_keys();
+ unsigned char *p = ¶m[1];
+ for (list<item>::iterator i = keys.begin(); i != keys.end() && n<maxkey; i++, n++) {
+ memcpy(p, &(*i).a, sizeof(BD_ADDR));
+ p += sizeof(BD_ADDR);
+ memcpy(p, (*i).lk, lksize);
+ p += lksize;
+ }
+ param[0] = n;
+ if (n > 0)
+ write_link_keys(param);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/neigbourhood/neighbourhood.h Fri Jul 01 09:16:00 2011 +0000
@@ -0,0 +1,77 @@
+#ifndef NEIGHBOURHOOD_H
+#define NEIGHBOURHOOD_H
+
+#include <list>
+#include "hci.h"
+
+//#define STRICT_MRU
+
+/******************************************************************************************
+call 'read' as part of the startup
+on HCI_READ-STORED-LINK-KEY -COMPLETED event, call 'set_cap'
+on RETURN_LINK_KEYS_EVENT call 'add' for each key with init=true
+on LINK_KEY_NOTIFICATION_EVENT call 'add' with init=false (default)
+on LINK_KEY_REQUEST_EVENT call 'get' and send the proper reply
+call 'write' as part of shutdown
+
+a simpler approach could be to check for a link if it exists (single read) and try to add it.
+when it fails just delete all.
+********************************************************************************************/
+
+#define HCI_DELETE_STORED_LINK_KEY 0x0C12
+#define HCI_WRITE_STORED_LINK_KEY 0x0C11
+#define HCI_READ_STORED_LINK_KEY 0x0C0D
+
+void printf(const BD_ADDR* addr);
+
+class neighbourhood {
+ static const int lksize = 16;
+ struct item {
+ BD_ADDR a;
+ unsigned char lk[lksize];
+ bool used;
+ item (BD_ADDR *ad, const unsigned char *k, bool d) {
+ memcpy(&a, ad, sizeof(BD_ADDR));
+ memcpy(lk, k, lksize);
+ used=d;
+ }
+ };
+ int cap, initsize, used;
+ list<item> keys;
+ bool dirty;
+ HCI *hci;
+ void delete_link_key(BD_ADDR *a) {
+ unsigned char param[sizeof(BD_ADDR)+1];
+ memcpy(param, a, sizeof(BD_ADDR));
+ param[sizeof(BD_ADDR)] = 0;
+ hci->SendCmd(HCI_DELETE_STORED_LINK_KEY, param, sizeof(param));
+ }
+ void write_link_keys(unsigned char param[]) {
+ hci->SendCmd(HCI_WRITE_STORED_LINK_KEY, param, param[0]*(sizeof(BD_ADDR)+lksize)+1);
+ }
+public:
+ neighbourhood(HCI *h): hci(h) {
+ dirty = false;
+ used = 0;
+ cap=0;
+ initsize=0;
+ }
+ void read() {
+ unsigned char param[sizeof(BD_ADDR)+1];
+ memset(param, 0, sizeof(BD_ADDR));
+ param[sizeof(BD_ADDR)] = 1;
+ hci->SendCmd(HCI_READ_STORED_LINK_KEY, param, sizeof(param));
+ }
+ void write();
+ void set_cap(int c, int s) {
+ cap = c;
+ initsize = s;
+ printf("Neighbourhood: capacity=%d, used=%d\n", c, s);
+ }
+ int get(BD_ADDR *a, unsigned char *key);
+ int add(BD_ADDR *a, const unsigned char *key, bool init=false);
+};
+
+extern neighbourhood *neighbors;
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rfcomm/RFCOMM.cpp Fri Jul 01 09:16:00 2011 +0000
@@ -0,0 +1,682 @@
+#include "mbed.h"
+#include "Utils.h"
+#include "RFCOMM.h"
+
+// Control field values bit no. 1 2 3 4 5 6 7 8
+#define BT_RFCOMM_SABM 0x3F // 1 1 1 1 P/F 1 0 0
+#define BT_RFCOMM_UA 0x73 // 1 1 0 0 P/F 1 1 0
+#define BT_RFCOMM_DM 0x0F // 1 1 1 1 P/F 0 0 0
+#define BT_RFCOMM_DM_PF 0x1F
+#define BT_RFCOMM_DISC 0x53 // 1 1 0 0 P/F 0 1 0
+#define BT_RFCOMM_UIH 0xEF // 1 1 1 1 P/F 1 1 1
+#define BT_RFCOMM_UIH_PF 0xFF
+
+// Multiplexer message types
+#define BT_RFCOMM_PN_CMD 0x83
+#define BT_RFCOMM_PN_RSP 0x81
+#define BT_RFCOMM_TEST_CMD 0x23
+#define BT_RFCOMM_TEST_RSP 0x21
+#define BT_RFCOMM_FCON_CMD 0xA3
+#define BT_RFCOMM_FCON_RSP 0xA1
+#define BT_RFCOMM_FCOFF_CMD 0x63
+#define BT_RFCOMM_FCOFF_RSP 0x61
+#define BT_RFCOMM_MSC_CMD 0xE3
+#define BT_RFCOMM_MSC_RSP 0xE1
+#define BT_RFCOMM_RPN_CMD 0x93
+#define BT_RFCOMM_RPN_RSP 0x91
+#define BT_RFCOMM_RLS_CMD 0x53
+#define BT_RFCOMM_RLS_RSP 0x51
+#define BT_RFCOMM_NSC_RSP 0x11
+
+// FCS calc
+#define BT_RFCOMM_CODE_WORD 0xE0 // pol = x8+x2+x1+1
+#define BT_RFCOMM_CRC_CHECK_LEN 3
+#define BT_RFCOMM_UIHCRC_CHECK_LEN 2
+
+#define NR_CREDITS 1
+#define INITIAL_CREDITS 1 //0...7
+
+#define DCD (1<<7) //DV data carrier detect
+#define RI (1<<6) //IC ring indicator
+#define RTS (1<<3) //RTR request to send
+#define DSR (1<<2) //RTC data set ready
+#define FC (1<<1) //Flow Control
+#define EA (1<<0) //extended address (always 1)
+#define SIGNALS (DCD | RTS | DSR | EA)
+
+#define DEBUG 1
+#define TAKE_INITIATIVE
+
+RFCOMMManager rfcomm_manager;
+
+//uint8_t rfcomm_out_buffer[1000];//seems a bit big as default max framesize is 127
+//unsigned rfcomm::maxframesize = MAX_FRAME_SIZE; //only initial value
+
+//these functions are obtained from rfcomm.c on google code
+void _bt_rfcomm_send_sabm(unsigned short source_cid, unsigned char initiator, unsigned char channel);
+void _bt_rfcomm_send_uih_pn_command(unsigned short source_cid, unsigned char initiator, unsigned char channel, unsigned short max_frame_size);
+void _bt_rfcomm_send_uih_msc_cmd(unsigned short source_cid, unsigned char initiator, unsigned char channel, unsigned char signals);
+void _bt_rfcomm_send_uih_rpn_cmd(uint16_t source_cid, uint8_t initiator, uint8_t dlci, port_settings *val);
+int rfcomm_send_packet(unsigned short source_cid, unsigned char address, unsigned char control, unsigned char credits, const unsigned char *data, unsigned short len);
+uint8_t crc8_calc(uint8_t *data, uint16_t len);
+
+
+//find a free socket slot for channel ch
+int rfcomm::find_slot(unsigned ch) {
+ for (int i = 0; i < MAX_RFCOMM_SCKTS; i++) {
+ if (sckts[i] != 0) { //socket is in use
+ RFCOMMSocket *s = (RFCOMMSocket*)GetSocketInternal(sckts[i]);
+ if (s==0) {
+ printf("find_slot: socket %d not found\n", sckts[i]);
+ continue;
+ }
+ if (s->dlci >> 1 == ch) {
+ printf("Channel %d is already in use on socket %d\n", ch, sckts[i]);
+ return -1;
+ }
+ } else //slot is free
+ return i;
+ }
+ return -2; //no free slots
+}
+
+//find the rfcomm socket for dlci
+RFCOMMSocket* rfcomm::find_socket(unsigned dlci) {
+ for (int i = 0; i < MAX_RFCOMM_SCKTS; i++) {
+ if (sckts[i] != 0) { //socket is in use
+ RFCOMMSocket *s = (RFCOMMSocket*)GetSocketInternal(sckts[i]);
+ if (s==0) {
+ printf("find_socket: socket %d not found\n", sckts[i]);
+ continue;
+ }
+ if (s->dlci == dlci) {
+ return s;
+ }
+ }
+ }
+ printf("RFCOMMSocket for dlci %d was not found!\n", dlci);
+ return 0; //socket not found
+}
+
+//send a PN command to all sockets waiting to be opened
+void rfcomm::initChannels(int socket) {
+ for (int i = 0; i < MAX_RFCOMM_SCKTS; i++) {
+ if (sckts[i] != 0) { //socket is in use
+ RFCOMMSocket *s = (RFCOMMSocket*)GetSocketInternal(sckts[i]);
+ if (s==0) {
+ printf("initChannels: socket %d not found\n", sckts[i]);
+ continue;
+ }
+ if (s->State == SocketState_Opening) {
+ printf("Sending PN for DLCI %d on socket %d\n", s->dlci, sckts[i]);
+ _bt_rfcomm_send_uih_pn_command(socket, 1, s->dlci, maxframesize);
+ s->State = SocketState_L2CAP_Config_wait;
+ }
+ }
+ }
+}
+
+unsigned rfcomm::release_channel(unsigned dlci) {
+ int n = 0;
+ for (int i = 0; i < MAX_RFCOMM_SCKTS; i++) {
+ if (sckts[i] != 0) { //socket is in use
+ RFCOMMSocket *s = (RFCOMMSocket*)GetSocketInternal(sckts[i]);
+ if (s==0) {
+ printf("Release: socket for dlci %d not found\n", dlci);
+ continue;
+ }
+ if (s->dlci == dlci)
+ sckts[i] = 0;
+ else
+ n++;
+ }
+ }
+ return n;
+}
+
+int rfcomm::Send(SocketInternal *sock, const u8* data, int len) {//also see if credits need to be send
+ RFCOMMSocket *s = (RFCOMMSocket*)sock;
+ char credits = 0;
+ char control = BT_RFCOMM_UIH;
+ if (len + 14 > maxframesize) //hci/l2cap header =8, rfcomm header ~ 6
+ printf("Error! packetsize = %d, maxframesize = %d\n", len, maxframesize);
+ if (s->peer_credits == 0) {//peer is low on credits
+ credits = NR_CREDITS;
+ control = BT_RFCOMM_UIH_PF;
+ s->peer_credits += NR_CREDITS;//so provide some more
+ }
+ unsigned char address = (1 << 0) | (initiator << 1) | (s->dlci << 2);
+ if (s->my_credits) {
+ s->my_credits--;
+ return rfcomm_send_packet(_l2cap, address, control, credits, data, len);
+ } else
+ return rfcomm_send_packet(_l2cap, address, control, credits, data, 0);//send an empty packet when credits run out
+}
+
+int rfcomm::Close(SocketInternal* sock) {
+ RFCOMMSocket *s = (RFCOMMSocket*)sock;
+ int id = s->dlci;
+ printf("Closing rfcomm dlci %d state=%d\n", id, s->State);
+ Disconnect(s);
+ int n = release_channel(id);
+ printf("%d channels are still open\n", n);
+ if (n == 0) {//all rfcomm channels are closed
+ printf("....L2CAP must be closed as well\n");
+ rfcomm_send_packet(_l2cap, (1 << 0) | (initiator << 1), BT_RFCOMM_DISC, 0, 0, 0); //close dlci0
+ Socket_Close(_l2cap);
+ _l2cap = 0; //return rfcomm to the pool
+ }
+ return 0;
+}
+
+int rfcomm::SetOpt(SocketInternal *sock, int so, int* data, int len) {
+ switch (so) {
+ case SO_RECBUF:
+ case SO_SNDBUF:
+ maxframesize = *data; //pointless because setting takes effect only before socket is opened (before PN)
+ break;
+ default: return NOPROTOOPT;
+ }
+ return 0;
+}
+
+int rfcomm::GetOpt(SocketInternal *sock, int so, int* data, int len) {
+ switch (so) {
+ case SO_RECBUF:
+ case SO_SNDBUF:
+ if (len >= sizeof(int))
+ *data = maxframesize;
+ break;
+ default: return NOPROTOOPT;
+ }
+ return 0;
+}
+
+int rfcomm::Disconnect(RFCOMMSocket *s) {
+ unsigned char address = (1 << 0) | (initiator << 1) | (s->dlci << 2);
+ return rfcomm_send_packet(_l2cap, address, BT_RFCOMM_DISC, 0, 0, 0);
+}
+
+//expect this to be called with socket type=SOCKET_RFCOM and addr->psm = channel and addr->bdaddr is the BT addr
+//of the device to connect to.
+//eg. Socket_Open(SOCKET_RFCOM, rfcommaddr(bdaddr, chan), receiver_func, appl_obj);
+int rfcomm::Open(SocketInternal* sock, SocketAddrHdr* addr) {
+ int ch = ((L2CAPAddr*)addr)->psm;//abused psm for channel ID
+ RFCOMMSocket *s = (RFCOMMSocket*)sock;
+ int slot = find_slot(ch);
+ if (slot < 0) return 0;
+ sckts[slot] = s->ID;
+ s->serdevice = this;
+ s->State = SocketState_Opening;
+
+ if (_l2cap == 0) { //no rfcomm -> l2cap connection yet
+ printf("Need to open L2CAP channel first before opening RFCOMM channel %d\n", s->dlci);
+ ((L2CAPAddr*)addr)->psm = L2CAP_PSM_RFCOMM;//open the l2cap channel and the rfcomm_ch channel
+ initiator = 1;
+ s->dlci = (ch<<1)|!initiator;
+ _l2cap = Socket_Open(SOCKET_L2CAP, addr, OnRfCommControl, this);//this is the socket between the RFCOMM and the L2CAP layer
+ if (_l2cap)
+ printf("Successfully opened L2CAP channel on socket %d\n", _l2cap);
+ else {
+ printf("Opening L2CAP channel failed\n");
+ sckts[slot] = 0;
+ s->State = SocketState_Closed;
+ return 0;
+ }
+ } else {//bypass the l2cap channel creation
+ s->dlci = (ch<<1)|!initiator;
+ _bt_rfcomm_send_uih_pn_command(_l2cap, initiator, s->dlci, maxframesize);
+ s->State = SocketState_L2CAP_Config_wait;
+ }
+ return s->ID; //return the application unique socket nr.
+}
+
+int rfcomm::set_remote_port_parameters(unsigned char dlci, port_settings *p) {
+ _bt_rfcomm_send_uih_rpn_cmd(_l2cap, initiator, dlci, p);
+ return 0;
+}
+
+//socket is an L2CAP socket and state is the state of the L2CAP socket, not the RFCOMM socket
+void rfcomm::OnRfCommControl(int socket, SocketState state, const u8* data, int len, void* userData) {
+ int packet_processed = 0;
+ rfcomm* self = (rfcomm*)userData;
+ const u8 initiator = self->initiator;
+ printf("\x1B[%dm", 32); //debug: set a different colour
+ printf("OnRfCommControl sock = %d, state = %d, length = %d\n", socket, state, len);
+
+ if (len == 0) {//client only
+ if (state==SocketState_Open) {//callback after change to 'open', the rfcomm->l2cap channel is now open
+ _bt_rfcomm_send_sabm(socket, initiator, 0); //setup the rfcomm control channel dlci==0
+ return;
+ }
+ return; //or other states to handle, e.g. Closing or Closed
+ }
+ //we have data, so parse the header
+ const u8 &addr = data[0];
+ u8 dlci = addr>>2;
+ const u8 &control = data[1];
+ u16 length = data[2]>>1;
+ const u8 *payload = data+3;
+ const u8 *pFCS = data+len-1; //expected position of the CRC
+ if (!(data[2]&1)) { //two byte length
+ length += ((unsigned)data[3])<<7;
+ payload++;
+ }
+ u8 credits = 0;
+ if (control == BT_RFCOMM_UIH_PF)//this packet carries credits
+ credits = *(payload++);
+ //sanity check
+ if (payload+length != pFCS)
+ printf("RFCOMM size mismatch, expected %d payload bytes, got %d\n", length, pFCS-payload);
+
+ if (DEBUG) {
+ printf("RFCOMM: EA=%d, C/R=%d, D=%d, ch=%d; control=%02X (P/F=%d); length=%d\n", addr&1, (addr>>1)&1, (addr>>2)&1, (addr>>3), control, (control>>4)&1, length);
+ printfBytes("payload:", payload, length);
+ }
+ if (dlci == 0) { //dlci==0 control channel
+ L2CAPSocket *s = (L2CAPSocket*)GetSocketInternal(socket);
+ switch (control) {
+ case BT_RFCOMM_UA:// received 1. message BT_RF_COMM_UA
+ packet_processed++;
+ if (s->si.State == SocketState_Closing || s->si.State==SocketState_L2CAP_WaitDisconnect) { //Confirmation of disconnect
+ printf("Remote side confirmed disconnect for socket %d\n", s->si.ID);
+ s->si.SetState(SocketState_Closed);
+ break;
+ }
+ printf("Received RFCOMM unnumbered acknowledgement for channel 0 - multiplexer working\n");
+ printf("Sending UIH Parameter Negotiation Command from OnRfCommControl\n");
+ self->initChannels(socket);
+ break;
+ case BT_RFCOMM_UIH:// received UIH Parameter Negotiation Response
+ switch (payload[0]) {
+ case BT_RFCOMM_PN_RSP: {//client
+ packet_processed++;
+ printf("UIH Parameter Negotiation Response\n");
+ printf("Sending SABM #%u\n", payload[2]);
+ _bt_rfcomm_send_sabm(socket, initiator, payload[2]);//was rfcomm_ch
+ RFCOMMSocket *r = self->find_socket(payload[2]);
+ if (r==0) break;
+ r->my_credits = payload[9]; //initial amount of credits
+ self->maxframesize = min(self->maxframesize, payload[6] + (payload[7]<<8));
+ printf("Max Frame Size = %d, got %d initial credits\n", self->maxframesize, payload[9]);
+ }
+ break;
+ case BT_RFCOMM_PN_CMD: { //remote side sent PN command, mtu and initial credits
+ packet_processed++;
+ printf("UIH Parameter Negotiation Indication\n");
+ self->maxframesize = min(self->maxframesize, payload[6] + (payload[7]<<8));
+ unsigned char cred = payload[9] & 7;
+ unsigned char _dlci = payload[2];
+
+ int skt = rfcomm_manager.find_socket(_dlci>>1);
+ if (skt == 0) { //No-one is listening
+ printf("No-one is Listening on channel %d\n", _dlci>>1);
+ rfcomm_send_packet(socket, (_dlci<<2)|1, BT_RFCOMM_DM, 0, 0, 0);
+ break;
+ }
+ RFCOMMSocket *r = (RFCOMMSocket*)GetSocketInternal(skt);
+ r->my_credits = cred;
+ r->peer_credits = INITIAL_CREDITS;
+ unsigned char reply[10];
+ memcpy(reply, payload, sizeof(reply));
+ reply[0] = BT_RFCOMM_PN_RSP;//[1]=len, [2]=dlci, [4]=priority, [5]=timer(must be 0), [8] retransmissions (must be 0)
+ reply[3] = payload[3]==0xF0 ? 0xE0 : 0; //support credit based flow control
+ reply[6] = self->maxframesize;
+ reply[7] = self->maxframesize>>8;
+ reply[9] = payload[3]==0xF0 ? r->peer_credits : 0;
+ printf("Max Frame Size = %d, give %d initial credits\n", self->maxframesize, reply[9]);
+ rfcomm_send_packet(socket, addr^2, BT_RFCOMM_UIH, 0, reply, sizeof(reply));
+ }
+ break;
+ case BT_RFCOMM_MSC_CMD:
+ packet_processed++;
+ {
+ printf("Received BT_RFCOMM_MSC_IND\n");
+ // fine with this, return the same status and ignore the value, there is no room in the socket to store the value, rfcomm could generate an event
+ RFCOMMSocket *r = self->find_socket(payload[2]>>2);
+ if (r==0) break;
+ unsigned char reply[5];
+ memcpy(reply, payload, 5); //keep length, dlci and value(s)
+ reply[0] = BT_RFCOMM_MSC_RSP; // change command into response
+ printf("Sending MSC_RSP (%d bytes)\n", length);
+ rfcomm_send_packet(socket, addr^2, BT_RFCOMM_UIH, 0, reply, (payload[1]>>1)+2); // reply is 4 or 5 bytes
+ switch (r->State) {
+ case SocketState_L2CAP_Config_wait:
+ r->State = SocketState_L2CAP_Config_wait_send;
+ printf("Sending MSC_CMD\n");
+ _bt_rfcomm_send_uih_msc_cmd(socket, initiator, payload[2]>>2, SIGNALS); // ea=1,fc=0,rtc(DSR/DTR)=1,rtr(RTS/CTs)=1,ic(RI)=0,dv(DCD)=1
+ r->State = SocketState_L2CAP_Config_wait_rsp;
+ break;
+ case SocketState_L2CAP_Config_wait_reqrsp:
+ r->State = SocketState_L2CAP_Config_wait_rsp;
+ break;
+ case SocketState_L2CAP_Config_wait_req:
+ r->SetState(SocketState_Open);
+ break;
+ case SocketState_Open:
+ //inform port adaptation layer
+ printf("Received MSC IND in state Open for dlci 0x%02x\n", payload[2]>>2);
+ break;
+ default:
+ printf("Received MSC IND in state %d for dlci 0x%02x\n", r->State, payload[2]>>2);
+ }
+ }
+ break;
+ case BT_RFCOMM_MSC_RSP:
+ packet_processed++;
+ {
+ RFCOMMSocket *r = self->find_socket(payload[2]>>2);
+ if (r==0) break;
+ if (r->State == SocketState_L2CAP_Config_wait_reqrsp)
+ r->State = SocketState_L2CAP_Config_wait_req;
+ else if (r->State == SocketState_L2CAP_Config_wait_rsp)
+ r->SetState(SocketState_Open);
+ else
+ printf("Received MSC confirmation in state %d for dlci 0x%02x\n", r->State, payload[2]>>2);
+ }
+ break;
+ case BT_RFCOMM_RPN_CMD:
+ packet_processed++;
+ //accept and ignore all settings
+ unsigned char reply[10];
+ memcpy(reply, payload, length); //keep length, dlci and value(s)
+ reply[0] = BT_RFCOMM_RPN_RSP; // change command into response
+ printf("Responding to RPN indication (%d bytes)\n", length);
+ rfcomm_send_packet(socket, addr^2, BT_RFCOMM_UIH, 0, reply, length);
+ break;
+ case BT_RFCOMM_RPN_RSP:
+ packet_processed++;
+ //ignore a response
+ printf("Received RPN confirmation\n");
+ break;
+ default:
+ printf("Unsupported multiplexer frame, type=%02XH\n", data[3]);
+ }
+ break;
+ case BT_RFCOMM_DISC:
+ printf("Remote site actively disconnected from DLCI0\n");
+ rfcomm_send_packet(socket, addr|2, BT_RFCOMM_UA, 0, 0, 0);//confirm disconnection
+ //intentional fall through
+ case BT_RFCOMM_DM:
+ packet_processed++;
+ printf("Remote side refused connection on DLCI0\n");
+ self->_l2cap = Socket_Close(socket);
+ break;
+ case BT_RFCOMM_SABM:
+ packet_processed++;
+ printf("Remote site is seeking connection on DLCI0\n"); //respond with UA
+ rfcomm_send_packet(socket, addr|2, BT_RFCOMM_UA, 0, 0, 0);//confirm connection
+ break;
+ default:
+ printf("Unexpected RFCOMM cmd %02XH for address %02XH, length=%d\n", control, addr, length);
+ }
+ } else { //data is for one of the serial sockets
+ RFCOMMSocket *s = 0;
+ if (control == BT_RFCOMM_SABM) { //req. for conn on this dlci
+ //cannot call self->rfcomm::find_socket because it has no socket yet
+ int skt = rfcomm_manager.find_socket(dlci>>1); //find the server socket
+ s = (RFCOMMSocket*)GetSocketInternal(skt);//the listening socket
+ if (s) {//move the listening socket to the appropriate rfcomm
+ int slot = self->find_slot(dlci>>1);
+ if (slot < 0) {
+ printf("RFCOMM Channel %d is not free on rfcomm with l2cap socket %d\n", dlci>>1, self->_l2cap);
+ return;
+ }
+ s->serdevice = self; //bind the socket to this refcomm entity
+ self->sckts[slot] = skt;
+ rfcomm_manager.remove_socket(skt);
+ } else {
+ printf("Couln't find a listening socket for dlci %d\n", dlci);
+ return;
+ }
+ } else
+ s = self->find_socket(dlci);
+ if (s==0){
+ printf("DLCI %d not found\n", dlci);
+ return;
+ }
+ switch (control) {
+ case BT_RFCOMM_SABM:
+ packet_processed++;
+ rfcomm_send_packet(socket, addr|2, BT_RFCOMM_UA, 0, 0, 0);//confirm connection
+ s->State = SocketState_L2CAP_Config_wait; //wait for msc cmd
+#ifdef TAKE_INITIATIVE
+ printf("Sending MSC_CMD\n");
+ _bt_rfcomm_send_uih_msc_cmd(socket, initiator, dlci, 0x8d); // ea=1,fc=0,rtc(DSR/DTR)=1,rtr(RTS/CTs)=1,ic(RI)=0,dv(DCD)=1
+ s->State = SocketState_L2CAP_Config_wait_reqrsp;
+#endif
+ break;
+ case BT_RFCOMM_UA:// received 2. message BT_RF_COMM_UA
+ packet_processed++;
+ if (s->State == SocketState_Closing) { //Confirmation of disconnect
+ printf("Remote side confirmed disconnect for socket %d\n", s->ID);
+ s->SetState(SocketState_Closed);
+ break;
+ }
+ printf("Received RFCOMM unnumbered acknowledgement for dlci %u - channel opened\n", dlci);
+ if (s->State == SocketState_L2CAP_Config_wait) {
+ printf("Sending MSC CMD\n");
+ _bt_rfcomm_send_uih_msc_cmd(socket, initiator, dlci, 0x8d); // ea=1,fc=0,rtc(DSR/DTR)=1,rtr(RTS/CTs)=1,ic(RI)=0,dv(DCD)=1
+ s->State = SocketState_L2CAP_Config_wait_reqrsp;
+ }
+ break;
+ case BT_RFCOMM_UIH_PF: //user data with credits
+ printf("Got %u credits\n", credits);
+ s->my_credits += credits;
+ //intentional fall-through
+ case BT_RFCOMM_UIH: //user data
+ packet_processed++;
+ if (DEBUG) {
+ printf("RX: address %02x, control %02x: ", addr, control);
+ printHex( payload, length);
+ }
+ if (length) {
+ s->peer_credits--;
+ s->Recv(payload, length);
+ } else
+ printf("Received empty packet\n");
+ if (length == 0 || s->peer_credits == 0) {//send credits when peer runs out
+ //char ini = !(dlci & 1);
+ unsigned char address = (1 << 0) | (initiator << 1) | (dlci << 2);
+ printf("send %d credits to dlci %d\n", NR_CREDITS, addr>>2);
+ rfcomm_send_packet(socket, address, BT_RFCOMM_UIH_PF, NR_CREDITS, NULL, 0);
+ s->peer_credits += NR_CREDITS;
+ }
+ break;
+ case BT_RFCOMM_DISC:
+ packet_processed++;
+ printf("Received DISC IND for dlci %d\n", dlci);
+ rfcomm_send_packet(socket, addr, BT_RFCOMM_UA, 0, 0, 0);//confirm disconnection
+ s->SetState(SocketState_Closed);
+ break;
+ case BT_RFCOMM_DM:
+ case BT_RFCOMM_DM_PF:
+ packet_processed++;
+ printf("Received DM IND (%02X) for dlci %d\n", control, dlci);
+ s->SetState(SocketState_Closed);
+ break;
+ default:
+ printf("Unexpected RFCOMM cmd %02XH for address %02XH, length=%d\n", control, addr, length);
+ }
+ }
+
+ if (!packet_processed) {
+ // just dump data for now
+ printf("??: address %02x, control %02x: ", data[0], data[1]);
+ printHex( data, len );
+ }
+ printf("\x1B[%dm", 0);//reset terminal colour
+}
+
+//should make the functions below member functions
+
+/**
+ * @param credits - only used for RFCOMM flow control in UIH wiht P/F = 1
+ */
+/* Questionable optimisation. When OFFSET==8 a buffer is (dynamically) allocated that provides space for the lower
+ layer headers, this reduces copying to, and allocation of, a lower layer buffer. However, all other layers using
+ HCI/L2CAP must do the same.
+*/
+#define OFFSET 8
+
+int rfcomm_send_packet(uint16_t source_cid, uint8_t address, uint8_t control, uint8_t credits, const uint8_t *data, uint16_t len) {
+
+ uint16_t pos = OFFSET;
+ uint8_t crc_fields = 3;
+
+#if OFFSET == 8
+ uint8_t* rfcomm_out_buffer = new uint8_t[OFFSET+len+6];
+#else
+ static uint8_t rfcomm_out_buffer[MAXFRAMESIZE+6];//seems a bit big as default max framesize is 127
+#endif
+ rfcomm_out_buffer[pos++] = address;
+ rfcomm_out_buffer[pos++] = control;
+
+ // length field can be 1 or 2 octets
+ if (len < 128) {
+ rfcomm_out_buffer[pos++] = (len << 1)| 1; // bits 0-6
+ } else {
+ rfcomm_out_buffer[pos++] = (len & 0x7f) << 1; // bits 0-6
+ rfcomm_out_buffer[pos++] = len >> 7; // bits 7-14
+ crc_fields++;
+ }
+
+ // add credits for UIH frames when PF bit is set
+ if (control == BT_RFCOMM_UIH_PF) {
+ rfcomm_out_buffer[pos++] = credits;
+ }
+
+ // copy actual data
+ memcpy(&rfcomm_out_buffer[pos], data, len);
+ pos += len;
+
+ // UIH frames only calc FCS over address + control (5.1.1)
+ if ((control & 0xef) == BT_RFCOMM_UIH) {
+ crc_fields = 2;
+ }
+ rfcomm_out_buffer[pos++] = crc8_calc(rfcomm_out_buffer+OFFSET, crc_fields); // calc fcs
+ int retval = Socket_Send( source_cid, rfcomm_out_buffer, pos);
+#if OFFSET == 8
+ delete[] rfcomm_out_buffer;
+#endif
+ if (retval <= 0)
+ return retval;
+ return len;//return the size of the payload
+}
+
+void _bt_rfcomm_send_sabm(uint16_t source_cid, uint8_t initiator, uint8_t dlci) {
+ uint8_t address = (1 << 0) | (initiator << 1) | (dlci << 2);
+ rfcomm_send_packet(source_cid, address, BT_RFCOMM_SABM, 0, NULL, 0);
+}
+
+void _bt_rfcomm_send_uih_pn_command(uint16_t source_cid, uint8_t initiator, uint8_t dlci, uint16_t max_frame_size) {
+ uint8_t payload[10];
+ uint8_t address = (1 << 0) | (initiator << 1); // EA and C/R bit set - always server channel 0
+ uint8_t pos = 0;
+ payload[pos++] = BT_RFCOMM_PN_CMD;
+ payload[pos++] = 8 << 1 | 1; // len
+ payload[pos++] = dlci;
+ payload[pos++] = 0xf0; // pre defined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
+ payload[pos++] = 0; // priority
+ payload[pos++] = 0; // max 60 seconds ack
+ payload[pos++] = max_frame_size & 0xff; // max framesize low
+ payload[pos++] = max_frame_size >> 8; // max framesize high
+ payload[pos++] = 0x00; // number of retransmissions
+ payload[pos++] = INITIAL_CREDITS; // unused error recovery window
+ rfcomm_send_packet(source_cid, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
+}
+
+void _bt_rfcomm_send_uih_data(uint16_t source_cid, uint8_t initiator, uint8_t channel, uint8_t *data, uint16_t len) {
+ uint8_t address = (1 << 0) | (initiator << 1) | (!initiator << 2) | (channel << 3);
+ rfcomm_send_packet(source_cid, address, BT_RFCOMM_UIH, 0, data, len);
+}
+
+void _bt_rfcomm_send_uih_msc_cmd(uint16_t source_cid, uint8_t initiator, uint8_t dlci, uint8_t signals) {
+ uint8_t address = (1 << 0) | (initiator << 1); // EA and C/R bit set - always server channel 0
+ uint8_t payload[5];
+ uint8_t pos = 0;
+ payload[pos++] = BT_RFCOMM_MSC_CMD;
+ payload[pos++] = 2 << 1 | 1; // len, should be adapted when adding break byte
+ payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2); //C/R is always 1
+ payload[pos++] = signals;
+ // payload[pos++] = brk;
+ rfcomm_send_packet(source_cid, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
+}
+
+void _bt_rfcomm_send_uih_rpn_cmd(uint16_t source_cid, uint8_t initiator, uint8_t dlci, port_settings *val) {
+ uint8_t address = (1 << 0) | (initiator << 1); // EA and C/R bit set - always server channel 0
+ uint8_t payload[sizeof(port_settings)+3];
+ uint8_t pos = 0;
+ payload[pos++] = BT_RFCOMM_RPN_CMD;//type
+ if (val) {
+ payload[pos++] = ((1+sizeof(port_settings)) << 1) | 1; // len
+ payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2);
+ memcpy(payload+pos, (char*)val, sizeof(port_settings));
+ pos += sizeof(port_settings);
+ } else {
+ payload[pos++] = (1 << 1) | 1; // len
+ payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2);
+ }
+ rfcomm_send_packet(source_cid, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
+}
+
+int set_remote_port_parameters(int socket, port_settings *p) {
+ RFCOMMSocket* si = (RFCOMMSocket*)GetSocketInternal(socket);//gets the RFCOMM socket
+ if (!si || si->ID != socket)
+ return ERR_SOCKET_NOT_FOUND;
+ return si->serdevice->set_remote_port_parameters(si->dlci, p);
+}
+
+
+/*
+ * CRC (reversed crc) lookup table as calculated by the table generator in ETSI TS 101 369 V6.3.0.
+ */
+static const uint8_t crc8table[256] = { /* reversed, 8-bit, poly=0x07 */
+ 0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
+ 0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
+ 0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
+ 0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
+ 0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
+ 0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
+ 0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
+ 0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
+ 0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
+ 0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
+ 0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
+ 0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
+ 0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
+ 0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
+ 0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
+ 0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
+};
+
+#define CRC8_INIT 0xFF // Initial FCS value
+#define CRC8_OK 0xCF // Good final FCS value
+/*-----------------------------------------------------------------------------------*/
+uint8_t crc8(uint8_t *data, uint16_t len) {
+ uint16_t count;
+ uint8_t crc = CRC8_INIT;
+ for (count = 0; count < len; count++)
+ crc = crc8table[crc ^ data[count]];
+ return crc;
+}
+
+/*-----------------------------------------------------------------------------------*/
+uint8_t crc8_check(uint8_t *data, uint16_t len, uint8_t check_sum) {
+ uint8_t crc;
+
+ crc = crc8(data, len);
+
+ crc = crc8table[crc ^ check_sum];
+ if (crc == CRC8_OK)
+ return 0; /* Valid */
+ else
+ return 1; /* Failed */
+
+}
+
+/*-----------------------------------------------------------------------------------*/
+uint8_t crc8_calc(uint8_t *data, uint16_t len) {
+ /* Ones complement */
+ return 0xFF - crc8(data, len);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rfcomm/RFCOMM.h Fri Jul 01 09:16:00 2011 +0000
@@ -0,0 +1,326 @@
+#ifndef RFCOMM_H
+#define RFCOMM_H
+#include "USBHost.h"
+#include "hci.h"
+#include "Utils.h"
+
+#define MAX_RFCOMM_SCKTS 4
+//#define MAX_FRAME_SIZE 350 //ACL buffer - some headroom
+#define MAX_FRAME_SIZE 127 //ft size
+
+/*
+template <class T>
+T min(T a, T b) {
+ return a<b ? a : b;
+}
+*/
+
+#define MASK_BITRATE 0X0001
+#define MASK_DATABITS 0X0002
+#define MASK_STOPBITS 0X0004
+#define MASK_PARITYBITS 0X0008
+#define MASK_PARITYTYPE 0X0010
+#define MASK_XONCHAR 0X0020
+#define MASK_XOFFCHAR 0X0040
+#define MASK_XONXOFFIN 0X0100
+#define MASK_XONXOFFOUT 0X0200
+#define MASK_RTRIN 0X0400
+#define MASK_RTROUT 0X0800
+#define MASK_RTCIN 0X1000
+#define MASK_RTCOUT 0X2000
+
+struct port_settings {
+ unsigned char baud;
+unsigned char bits:
+ 2;
+unsigned char stop:
+ 1;
+unsigned char par:
+ 1;
+unsigned char par_t:
+ 2;
+unsigned char :
+ 2;
+unsigned char flow:
+ 6;
+unsigned char :
+ 2;
+ unsigned char xon;
+ unsigned char xoff;
+ unsigned short mask;
+};
+
+class rfcomm;
+class RFCOMMManager;
+#define MAX_RFCOMM_DEVICES 8 //physical devices
+
+class RFCOMMSocket: public SocketInternal {//this object must not be larger than SocketInternalPad (socketinternal + 8 bytes)
+public:
+ rfcomm* serdevice;
+ u8 dlci; //channel + D bit, D bit is inverted initiator bit
+ u8 my_credits, peer_credits;
+};
+
+class rfcomm: public SocketHandler {
+ int _l2cap; //socket to the l2cap layer
+ int _devClass;
+ BD_ADDR _addr;
+ u8 initiator;
+ u8 _pad[0]; // Struct align
+ char sckts[MAX_RFCOMM_SCKTS];
+ //static
+ unsigned maxframesize;
+ int find_slot(unsigned ch);
+ RFCOMMSocket* find_socket(unsigned dlci);
+ void initChannels(int socket);
+ unsigned release_channel(unsigned dlci);
+ static void OnRfCommControl(int socket, SocketState state, const u8* data, int len, void* userData);//I guess this is called when data comes out of the socket
+ int Disconnect(RFCOMMSocket*);
+public:
+ rfcomm() : _l2cap(0), _devClass(0) {
+ for (int i = 0; i < MAX_RFCOMM_SCKTS; i++) sckts[i] = 0;
+ maxframesize = MAX_FRAME_SIZE;
+ }
+
+ bool InUse() {
+ return _l2cap != 0;
+ }
+ virtual int Open(SocketInternal* sock, SocketAddrHdr* addr);
+ virtual int Send(SocketInternal* sock, const u8* data, int len);//wrap data in RFCOMM frame and dispatch
+ virtual int SetOpt(SocketInternal *sock, int so, int* data, int len);
+ virtual int GetOpt(SocketInternal *sock, int so, int* data, int len);
+ virtual int Close(SocketInternal* sock);
+ virtual char* Name() {
+ return "rfcomm SocketHandler";
+ }
+ void Recv(const u8* data, int len) {
+ printf("rfcomm::Recv was called\n");
+ }
+#if 0
+ int Listen(unsigned char ch=0) {//passive open, similar semantics to 'Open' but connection is only made at request of the peer
+ RFCOMMSocket *s = 0;//this entity may or may not be bound to a remote entity
+ if (ch>0) {//specific channel
+ s = find_socket(ch<<1);
+ if (s) { //socket for this channel already in use
+ printf("rfcomm::Listen: channel %d already in use\n", ch);
+ return 0;
+ } //else s==0, no socket for channel ch
+ }//else listen to any channel
+ int sn = find_slot(ch);
+ if (sn<0) {
+ printf("No socket could be found for channel %d\n", ch);
+ return 0;
+ } //else use slot 'sn' for the new rfcomm socket
+ int sock = Socket_Create(SOCKET_RFCOM, OnRfCommControl, this);//allocate an rfcomm socket
+ sckts[sn] = sock; //claim the socket
+ RFCOMMSocket *rs = (RFCOMMSocket*)GetSocketInternal(sock);
+ rs->serdevice = this;
+ rs->dlci = (ch<<1)|1;//server socket
+ //initiator = 0; what to do if already connected actively on different channel???
+ /*l2cap is already present or is created when accepting the connection
+ if (_l2cap == 0) { //no rfcomm -> l2cap connection yet
+ printf("Need to open L2CAP channel first before opening RFCOMM channel %d\n", rs->dlci);
+ ((L2CAPAddr*)addr)->psm = L2CAP_PSM_RFCOMM;//open the l2cap channel and the rfcomm_ch channel
+ initiator = 0;
+ _l2cap = Socket_Create(SOCKET_L2CAP, addr, OnRfCommControl, this);//this is the socket between the RFCOMM and the L2CAP layer
+ if (_l2cap)
+ printf("Successfully opened L2CAP channel on socket %d\n", _l2cap);
+ else {
+ printf("Opening L2CAP channel failed\n");
+ return 0;
+ }
+ }
+ */
+ return sock;
+ }
+#endif
+ //int Open(BD_ADDR* bdAddr, inquiry_info* info);
+ int set_remote_port_parameters(unsigned char dlci, port_settings *p);
+ friend RFCOMMManager;
+};
+
+class RFCOMMManager: public SocketHandler {
+ rfcomm _devs[MAX_RFCOMM_DEVICES];
+ int serverSock;
+ char sckts[MAX_RFCOMM_SCKTS];//listening sockets
+public:
+ virtual int Open(SocketInternal* sock, SocketAddrHdr* addr) {
+ L2CAPAddr* ad = (L2CAPAddr*)addr;
+ BD_ADDR* a = &ad->bdaddr;
+ rfcomm *r = FindRfCommDevice(a);
+ if (r==0)
+ r = NewRfCommDevice();
+ if (r==0)
+ return 0;
+ return r->Open(sock, addr);
+ }
+
+ int FindSocket(BTDevice* dev) {//finds the l2cap socket for a certain rfcomm-btdevice connection
+ for (int i = 0; i < MAX_RFCOMM_DEVICES; i++) {
+ rfcomm *r = _devs+i;
+ int l2cap = r->_l2cap;
+ if (l2cap) {
+ L2CAPSocket *p = (L2CAPSocket*)GetSocketInternal(l2cap);
+ if (p->btdevice == dev)
+ return l2cap;
+ }
+ }
+ return 0;
+ }
+
+ rfcomm* FindDev(BTDevice* dev) {//finds the rfcomm entity for a certain rfcomm-btdevice connection
+ for (int i = 0; i < MAX_RFCOMM_DEVICES; i++) {
+ rfcomm *r = _devs+i;
+ int l2cap = r->_l2cap;
+ if (l2cap) {
+ L2CAPSocket *p = (L2CAPSocket*)GetSocketInternal(l2cap);
+ if (p->btdevice == dev)
+ return r;
+ }
+ }
+ return 0;
+ }
+
+ int BindSocket(int s) {
+ L2CAPSocket *ls = (L2CAPSocket*)GetSocketInternal(s);
+ printf("Binding l2cap socket %d to a new rfcomm server entity\n", s);
+ rfcomm *r = NewRfCommDevice();
+ r->_l2cap = s;
+ r->initiator = 0;//we are server
+ ls->si.userData = r;//was BTDevice, make rfcomm
+ return 0;
+ }
+
+ int new_slot(unsigned ch) {
+ for (int i = 0; i < MAX_RFCOMM_SCKTS; i++) {
+ if (sckts[i] != 0) { //socket is in use
+ RFCOMMSocket *s = (RFCOMMSocket*)GetSocketInternal(sckts[i]);
+ if (s==0) {
+ printf("find_slot: socket %d not found\n", sckts[i]);
+ continue;
+ }
+ if ((s->dlci >> 1) == ch) {
+ printf("Channel %d is already in use on socket %d\n", ch, sckts[i]);
+ return -1;
+ }
+ } else //slot is free
+ return i;
+ }
+ return -2; //no free slots
+ }
+
+ int find_socket(unsigned ch) {
+ for (int i = 0; i < MAX_RFCOMM_SCKTS; i++) {
+ if (sckts[i] != 0) { //socket is in use
+ RFCOMMSocket *s = (RFCOMMSocket*)GetSocketInternal(sckts[i]);
+ if (s==0) {
+ printf("find_slot: socket %d not found\n", sckts[i]);
+ continue;
+ }
+ if ((s->dlci >> 1) == ch) {
+ printf("Found Channel %d on socket %d\n", ch, sckts[i]);
+ return sckts[i];
+ }
+ else
+ printf("slot %d has socket %d has dlci %d\n", i, sckts[i], s->dlci);
+ }
+ else
+ printf("Slot %d is free\n", i);
+ }
+ printf("channel %d not found\n", ch);
+ return 0; //channel not found
+ }
+
+ int remove_socket(int sock) {
+ for (int i = 0; i < MAX_RFCOMM_SCKTS; i++) {
+ if (sckts[i] == sock) {
+ sckts[i] = 0;
+ return 0;
+ }
+ }
+ return -1;
+ }
+
+ virtual int Listen(SocketInternal* sock, int ch) {//called by Socket_Listen(SOCKET_RFCOM, channel, callback, userData)
+ int slot = new_slot(ch);
+ switch (slot) {
+ case -1:
+ printf("There is already someone listening on ch %d\n", ch);
+ return ERR_SOCKET_CANT_LISTEN;//channel is occupied
+ case -2:
+ printf("All listener sockets are in use\n");
+ return ERR_SOCKET_NONE_LEFT;
+ }
+ RFCOMMSocket *rs = (RFCOMMSocket*)sock;
+ const char dir = 0;
+ rs->dlci = (ch<<1)|dir;
+ rs->State = SocketState_Listen;
+ rs->serdevice = 0;//don't know yet
+ sckts[slot] = rs->ID;
+ printf("RFCOMM listener socket %d for ch %d (dlci 0x%02X) is assigned to slot %d\n", rs->ID, ch, rs->dlci, slot);
+ return rs->ID;
+ }
+/*
+ virtual int Accept(SocketInternal *sock, int scid, int rxid) { //called indirectly from BTDevice::Control
+ //sock is registered as an RFCOMM sock but we use it as an L2CAP sock
+ //sock->type=RFCOM, meaning open/close/send/accept go to RFCOMMManager first
+ //sock->userData = BTDevice, necessary to make the call back to BTDevice::Accept
+ //Internal = L2CAPSocket, for scid, dcid
+ BTDevice *l2cap = (BTDevice*)sock->userData;
+ //sock->si.dcid = scid
+ //sock->si.scid = something based on sock->ID
+ serverSock = sock->ID;
+ printf("Invoking accept on %p (%s) for sock %d and scid=%d\n", l2cap, l2cap->Name(), sock->ID, scid);
+ return l2cap->Accept(sock, scid, rxid); //connect 'serverSock' to the remote RFCOMM client
+ }
+*/
+ virtual int Send(SocketInternal* sock, const u8* data, int len) {
+ RFCOMMSocket *s = (RFCOMMSocket*)sock;
+ return s->serdevice->Send(sock, data, len);
+ }
+
+ virtual int Close(SocketInternal* sock) {
+ RFCOMMSocket *s = (RFCOMMSocket*)sock;
+ return s->serdevice->Close(sock);
+ }
+
+ virtual int SetOpt(SocketInternal* sock, int so, int* data, int len) {
+ RFCOMMSocket *s = (RFCOMMSocket*)sock;
+ return s->serdevice->SetOpt(sock, so, data, len);
+ }
+
+ virtual int GetOpt(SocketInternal* sock, int so, int* data, int len) {
+ RFCOMMSocket *s = (RFCOMMSocket*)sock;
+ return s->serdevice->GetOpt(sock, so, data, len);
+ }
+
+ virtual char* Name() {
+ return "RFCOMMManager SocketHandler";
+ }
+
+ rfcomm* NewRfCommDevice() {//allocate a new RFCOMM device from the pool
+ for (int i = 0; i < MAX_RFCOMM_DEVICES; i++)
+ if (!_devs[i].InUse())
+ return _devs+i;
+ return 0;
+ }
+
+ rfcomm* FindRfCommDevice(BD_ADDR* ad) {//get a specific RFCOMM device from the pool
+ for (int i = 0; i < MAX_RFCOMM_DEVICES; i++)
+ if (_devs[i].InUse() && memcmp(ad, &_devs[i]._addr, 6)==0)
+ return _devs+i;
+ return 0;
+ }
+
+ static void SerServer(int socket, SocketState state, const u8* data, int len, void* userData) {
+ printfBytes("SerServer: ", data, len);
+ //userData is the rfcomm
+ rfcomm::OnRfCommControl(socket, state, data, len, userData);
+ }
+ //friend rfcomm;
+};
+
+int set_remote_port_parameters(int socket, port_settings *p);
+extern RFCOMMManager rfcomm_manager;
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sdp/sdp.cpp Fri Jul 01 09:16:00 2011 +0000
@@ -0,0 +1,941 @@
+#include "mbed.h"
+#include "Utils.h"
+#include "hci.h"
+#include "sdp_data.h"
+#include "sdp.h"
+
+SDPManager SDP; //instance
+const unsigned char base_uuid[16] = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0, 0x07, 0x70, 0, 0x10, 0, 0};
+map<unsigned, serv_rec*> SDPManager::server;
+int SDPManager::serverSock = 0;
+
+void attribHandler(serv_rec *r) {
+ printf("Service 0x%08X\n", (*r)[0x0000]->asUnsigned());
+ map<unsigned short, sdp_data*>::iterator it = r->begin();
+ for (;it != r->end();it++) {
+ printf(" 0x%04X: %s\n", (*it).first, (*it).second->asString());
+ }
+}
+
+#define BROWSEGROUP 0x1001
+#define BROWSEROOT 0x1002
+#define SERIALSERV 0x1101
+
+SDPHandler::SDPHandler(): txid(1), tree(0) {
+ ErrorResponse=errorhandler;
+ ServiceSearchResponse=0;
+ ServiceAttributeResponse=attribHandler;
+ ServiceSearchAttributeResponse=0;
+ buf = l2cap_buf+OFFSET;
+ contBuf = 0;
+ byteCount = 0;
+ contState[0] = 0;
+ _state = 0;
+}
+
+void SDPHandler::Clear() {
+ for (index = services.begin(); index != services.end(); index++) {//for all services
+ for (serv_rec::iterator it = index->second->begin(); it != index->second->end(); it++)//for all attributes
+ delete it->second; //delete the attribute value tree
+ delete (*index).second; //delete the attribute list
+ }
+ services.clear();//and empty the services list
+}
+
+//Called as: Socket_Open(SOCKET_SDP, addr, callback, userdata(this)) from SDPManager
+//never called
+int SDPHandler::Open(SocketInternal* sock, SocketAddrHdr* addr) {
+ printf("Successfully opened SDP socket %d\n", sock->ID);
+ sock->SetState(SocketState_Open);
+ sdp_socket = sock->ID;
+ return sdp_socket;
+}
+
+int SDPHandler::Send(SocketInternal* sock, const u8* data, int len) {
+ printf("SDPHandler::Send should not be called directly\n");
+// return Socket_Send(_l2cap, data, len);
+ BTDevice *l2cap = (BTDevice*)sock->userData;
+ return l2cap->Send(sock, data, len);
+}
+
+int SDPHandler::Close(SocketInternal* sock) {
+ printf("SDPHandler::Close(%d)\n", sock->ID);
+ Clear();
+// printf("SDP socket %d and L2CAP socket %d closed, freemem=%d\n", sock->ID, _l2cap, AvailableMemory(1));
+ int retval = 0;//Socket_Close(_l2cap);//could also keep it open for the next connection
+ return retval;
+}
+
+//this function is called when the L2CAP layer receives SDP packets (see SDPHandler::Open), userdata is the sdpmanager instance
+void SDPHandler::OnSdpRsp(int socket, SocketState state, const u8* data, int len, void* userData) {
+ printf("\x1B[%dm", 35);
+// printf("OnSdpRsp(socket=%d, state=%d, len=%d)\n", socket, state, len);
+ printf("SDPHandler::OnSdpRsp(socket=%d, state=%d, len=%d, freemem=%d\n", socket, state, len, AvailableMemory(1));
+ SDPHandler *self = (SDPHandler*)userData;
+ if (state == SocketState_Open) {
+ self->sdp_socket = socket;
+ self->OnSdpRsp(data, len);
+ } else if (state == SocketState_Closed) {
+ SDP.Destroy(socket);
+ }
+ printf("\x1B[%dm", 0);
+}
+
+//this function is called when the L2CAP layer receives SDP packets (see SDPHandler::Open), userdata is the sdpmanager instance
+//void SDPHandler::OnSdpRsp(int socket, SocketState state, const u8* data, int len, void* userData) {
+void SDPHandler::OnSdpRsp(const u8* data, int len) {
+ static sdp_data list(sdp_data::SEQUENCE);
+ static sdp_data all(0x0000ffffU,4);
+ static sdp_data serviceID(0U, 2);
+ static sdp_data name(0x100U, 2);
+ static sdp_data root(sdp_data::UUID, BROWSEROOT);
+ static sdp_data req(sdp_data::SEQUENCE);
+ static bool once = true;
+// printf("_state=%d first=%d ", _state, once);
+ if (once) {
+ list.add_element(&all);
+ //list.add_element(&serviceID);
+ //list.add_element(&name);
+ req.add_element(&root);
+ once = false;
+ }
+ if (data) {
+ parseRsp(data, len);
+ }
+ switch (_state) {
+ case 0: //closed
+ if (len==0) { //socket just opened
+ //'Open' cleared the services list
+ ServiceSearchRequest(&req, 10);
+ _state = 1; //wait for service handles
+ }
+ break;
+ case 1: //service handles arriving
+ if (contState[0]) {//continuation, repeat request
+ ServiceSearchRequest(&req, 5);
+ } else {
+ if (data[0]==3) {
+ index = services.begin();
+ if (index != services.end()) {
+ unsigned handle = (*index).first;
+ //printf("req.: handle %#X\n", handle);
+ ServiceAttributeRequest(handle, 100, &list);//0x1001D
+ } else
+ printf(" - empty list - \n");//should not happen
+ _state = 2; //wait for attribute response
+ } else
+ printf("Expected a ServiceSearchResponse 0x03, got %#x\n", data[0]);
+ }
+ break;
+ case 2:
+ if (contState[0])//repeat request
+ ServiceAttributeRequest((*index).first, 100, &list);
+ else {
+ if (data[0]==5) {
+ index++; //move to next service
+ if (index != services.end()) {
+ //printf("req.: handle %#X\n", (*index).first);
+ ServiceAttributeRequest((*index).first, 100, &list);
+ } else {
+ printf(" - end of list - \n");
+ Socket_Close(sdp_socket); //Note: socket=L2CAP, sdp_socket=SDP !!!
+ _state = 0;
+ }
+ } else
+ printf("Expected a ServiceAttributeResponse 0x05, got %#x\n", data[0]);
+ }
+ break;
+ }
+}
+
+//this function is called when the SDP sockets receives data (see HCICallback in TestShell),
+//currently does not happen because not forwarded from OnSdpRsp, can be used to handle multiple connections
+void SDPHandler::OnSockCallback(int socket, SocketState state, const u8* data, int len, void* userData) {
+ printf("SDPHandler::OnSockCallback(socket=%d, state=%d, len=%d)\n", socket, state, len);
+ printfBytes("Got SDP Response from socket: ", data, len);
+}
+
+//void SDPHandler::errorhandler(unsigned err) {//default error handler
+void errorhandler(unsigned err) {//default error handler
+ switch (err) {
+ case 1:
+ printf("Unsupported version of SDP\n");
+ break;
+ case 2:
+ printf("Invalid SDP ServiceRecordHandle\n");
+ break;
+ case 3:
+ printf("SDP syntax error\n");
+ break;
+ case 4:
+ printf("PDU size was invalid\n");
+ break;
+ case 5:
+ printf("Continuation state was invalid\n");
+ break;
+ case 6:
+ printf("SDP server has insufficient resources\n");
+ break;
+ default:
+ printf("Unknown SDP error code\n");
+ break;
+ }
+}
+
+int SDPHandler::ServiceSearchRequest(sdp_data *sp, unsigned count, unsigned cs) {
+ int parlen = sp->Size() + contState[0] + 3;
+ buf[0] = 2; //pdu
+ buf[1] = txid>>8;
+ buf[2] = txid++;
+ buf[4] = parlen;
+ buf[3] = parlen>>8;
+ int p = sp->build(buf+5, 100-10);
+ buf[p+6] = count;
+ buf[p+5] = count>>8;
+ buf[p+7] = contState[0];
+ for (int j = 1; j <= contState[0]; j++)
+ buf[p+j+7] = contState[j];
+ //printfBytes("SDP Send: ", buf, parlen+5);
+ return Socket_Send(sdp_socket, l2cap_buf, parlen + 5 + OFFSET);
+}
+
+int SDPHandler::ServiceAttributeRequest(unsigned handle, unsigned count, sdp_data* al, unsigned cs) {
+ int parlen = al->Size() + contState[0] + 7;
+ buf[0] = 4; //pdu
+ buf[1] = txid>>8;
+ buf[2] = txid++;
+ buf[4] = parlen;
+ buf[3] = parlen>>8;
+ for (int i = 0; i < 4; i++)
+ buf[i+5] = ((char*)&handle)[3-i];
+ buf[9] = count>>8;
+ buf[10] = count;
+ int p = al->build(buf+11, 100-26);
+ buf[p+11] = contState[0];
+ for (int j = 1; j <= contState[0]; j++)
+ buf[p+j+11] = contState[j];
+ //printfBytes("SDP Send: ", buf, parlen+5);
+ return Socket_Send(sdp_socket, l2cap_buf, parlen + 5 + OFFSET);
+}
+
+int SDPHandler::ServiceSearchAttributeRequest(sdp_data *sp, unsigned count, sdp_data* al, unsigned cs) {
+ int parlen = sp->Size() + al->Size() + contState[0] + 3; // count (2 bytes) + at least 1 cont
+ buf[0] = 6; //pdu
+ buf[1] = txid>>8;
+ buf[2] = txid++;
+ buf[4] = parlen;
+ buf[3] = parlen>>8;
+ int p = sp->build(buf+5, 30);
+ buf[p+6] = count;
+ buf[p+5] = count>>8;
+ p += al->build(buf+11, 100-38);
+ buf[p+7] = contState[0];
+ for (int j = 1; j <= contState[0]; j++)
+ buf[p+j+7] = contState[j];
+ //printfBytes("SDP Send: ", buf, parlen+5);
+ return Socket_Send(sdp_socket, l2cap_buf, parlen + 5 + OFFSET);
+}
+
+unsigned BE32(unsigned le) {
+ unsigned be=0;
+ for (int i = 0; i < 32; i+=8){
+ be |= ((le>>i)&0xFFU)<<(24-i);
+ }
+ return be;
+}
+
+int SDPManager::ServiceSearchReply(unsigned rxid, unsigned *handles, unsigned count, unsigned cs) {//'count' is number of matching handles and capped at the maximumservicerecordcount
+ unsigned size = count*4;
+ unsigned cont = 0;//outgoing continuation
+ unsigned char *_buf = new unsigned char[OFFSET+5+4+size+3];
+ unsigned char *buf = _buf+OFFSET;
+ unsigned current = count - cs; //remainder of data to send
+ unsigned parlen = 4 + 4*current + 1 ;// attributelistbytecount+payload+no_continuation
+ //never need a continuation unless other criterion like PDU size is used
+ if (current > count) {//still too large, need continuation
+ current = count; //limit at maximum
+ cont = cs + count; //start for next iteration
+ parlen = 4 + 4*current + 3; //adjusted for payload and continuation
+ printf("Need continuation, sending handles [%d, %d> of attributeList\n", cs, cont);
+ } else {
+ // printf("Final or only block, sending bytes [%d, %d> of attributeList\n", cs, cs+byteCount);
+ }
+ buf[0] = 3; //pdu
+ buf[1] = rxid>>8;
+ buf[2] = rxid;
+ buf[3] = parlen>>8;
+ buf[4] = parlen;
+ buf[5] = count>>8;
+ buf[6] = count;
+ buf[7] = current>>8;
+ buf[8] = current;
+ unsigned *p = (unsigned*)&buf[9];
+ for (int i = 0; i < current; i++)
+ p[i] = BE32(handles[i]);
+ //printf("'build' added %d bytes to the buffer\n", p);
+ if (cs == 0) { //this is not a continuation
+ buf[5+parlen-1] = 0;
+ } else { //this is a continuation
+ memcpy(buf+9, buf+9+cs*4, current*4);//move part of interrest to beginning of buffer
+ buf[5+parlen-3] = 2;
+ buf[5+parlen-2] = cont>>8;
+ buf[5+parlen-1] = cont;
+ }
+ //printfBytes("SDP Send: ", buf, parlen+5);
+ int retval = Socket_Send(serverSock, _buf, parlen + 5 + OFFSET);
+ delete[] _buf;
+ return retval;
+}
+
+int SDPManager::ServiceAttributeReply(unsigned rxid, sdp_data* al, unsigned count, unsigned cs) {
+ unsigned size = al->Size();
+ unsigned cont = 0;//outgoing continuation
+ unsigned char *_buf = new unsigned char[OFFSET+5+2+size+3];
+ unsigned char *buf = _buf+OFFSET;
+ unsigned byteCount = size - cs; //remainder of data to send
+ unsigned parlen = 2 + byteCount + 1 ;// attributelistbytecount+payload+no_continuation
+ if (byteCount > count) {//still too large, need continuation
+ byteCount = count; //limit at maximum
+ cont = cs + count; //start for next iteration
+ parlen = 2 + byteCount + 3; //adjusted for payload and continuation
+ printf("Need continuation, sending bytes [%d, %d> of attributeList\n", cs, cont);
+ } else {
+ // printf("Final or only block, sending bytes [%d, %d> of attributeList\n", cs, cs+byteCount);
+ }
+ buf[0] = 5; //pdu
+ buf[1] = rxid>>8;
+ buf[2] = rxid;
+ buf[3] = parlen>>8;
+ buf[4] = parlen;
+ buf[5] = byteCount>>8;
+ buf[6] = byteCount;
+ int p = al->build(buf+7, size);//limited only by buffersize
+ //printf("'build' added %d bytes to the buffer\n", p);
+ if (cs == 0) { //this is not a continuation
+ buf[byteCount+7] = 0;
+ } else { //this is a continuation
+ memcpy(buf+7, buf+7+cs, byteCount);//move part of interrest to beginning of buffer
+ buf[byteCount+7] = 2;
+ buf[byteCount+8] = cont>>8;
+ buf[byteCount+9] = cont;
+ }
+ //printfBytes("SDP Send: ", buf, parlen+5);
+ int retval = Socket_Send(serverSock, _buf, parlen + 5 + OFFSET);
+ delete[] _buf;
+ return retval;
+}
+
+int SDPManager::ServiceSearchAttributeReply(unsigned rxid, sdp_data* al, unsigned count, unsigned cs) {
+ unsigned size = al->Size();
+ unsigned cont = 0;//outgoing continuation
+ unsigned char *_buf = new unsigned char[OFFSET+5+2+size+3];
+ unsigned char *buf = _buf+OFFSET;
+ unsigned byteCount = size - cs; //remainder of data to send
+ unsigned parlen = 2 + byteCount + 1 ;// attributelistbytecount+payload+no_continuation
+ if (byteCount > count) {//still too large, need continuation
+ byteCount = count; //limit at maximum
+ cont = cs + count; //start for next iteration
+ parlen = 2 + byteCount + 3; //adjusted for payload and continuation
+ printf("Need continuation, sending bytes [%d, %d> of attributeList\n", cs, cont);
+ } else {
+ // printf("Final or only block, sending bytes [%d, %d> of attributeList\n", cs, cs+byteCount);
+ }
+ buf[0] = 7; //pdu
+ buf[1] = rxid>>8;
+ buf[2] = rxid;
+ buf[3] = parlen>>8;
+ buf[4] = parlen;
+ buf[5] = byteCount>>8;
+ buf[6] = byteCount;
+ int p = al->build(buf+7, size);//limited only by buffersize
+ //printf("'build' added %d bytes to the buffer\n", p);
+ if (cs == 0) { //this is not a continuation
+ buf[byteCount+7] = 0;
+ } else { //this is a continuation
+ memcpy(buf+7, buf+7+cs, byteCount);//move part of interrest to beginning of buffer
+ buf[byteCount+7] = 2;
+ buf[byteCount+8] = cont>>8;
+ buf[byteCount+9] = cont;
+ }
+ //printfBytes("SDP Send: ", buf, parlen+5);
+ int retval = Socket_Send(serverSock, _buf, parlen + 5 + OFFSET);
+ delete[] _buf;
+ return retval;
+}
+
+//unsigned SDPHandler::getval(const unsigned char *p, int n) {
+unsigned getval(const unsigned char *p, int n) {
+ unsigned ret = 0;
+ for (int i = 0; i < n; i++)
+ ret = (ret<<8) + (unsigned)p[i];
+ return ret;
+}
+
+//unsigned SDPHandler::length(const unsigned char *el, unsigned &p) {
+unsigned length(const unsigned char *el, unsigned &p) {
+ unsigned len = 0;
+ switch (el[p++] & 7) {//length
+ case 0:
+ len = 1;
+ break;
+ case 1:
+ len = 2;
+ break;
+ case 2:
+ len = 4;
+ break;
+ case 3:
+ len = 8;
+ break;
+ case 4:
+ len = 16;
+ break;
+ case 7://4bytes
+ len= el[p++]<<24;
+ len += el[p++]<<16;
+ case 6://2bytes
+ len += el[p++]<<8;
+ case 5://1byte
+ len += el[p++];
+ break;
+ }
+ return len;
+}
+
+extern "C" void HardFault_Handler() {
+ printf("Hard Fault! %d bytes left\n", AvailableMemory(1));
+ while (1);
+}
+
+unsigned SDPHandler::parseLight (const unsigned char *el, unsigned count, sdp_data* &result, serv_rec* &record) {
+ unsigned p = 0;
+ unsigned len = length(el, p);
+ int end = p+len;//end is the index of the item just after the sequence
+ sdp_data *item = 0;
+ switch (el[0]>>3) {//type
+ case sdp_data::NULL_:
+ printf("NULL ");
+ break;
+ case sdp_data::UNSIGNED:
+ printf("UINT%d=%u ", len, (unsigned)getval(el+p, len));
+ break;
+ case sdp_data::SIGNED:
+ printf("INT%d=%d ", len, (unsigned)getval(el+p, len));
+ break;
+ case sdp_data::UUID:
+ if (len==16) {
+ printf("UUID16= ");
+ for (int i = 0; i < 16; i++)
+ printf("%02x ", el[p+i]);
+ } else
+ printf("UUID%d=%u ", len, (unsigned)getval(el+p, len));
+ break;
+ case sdp_data::STRING:
+ printf("STR%d='%s' ", len, (char*)el+p);
+ break;
+ case sdp_data::BOOL:
+ printf("BOOL%d=%d ", len, (unsigned)getval(el+p, len));
+ break;
+ case sdp_data::SEQUENCE:
+ goto skip;
+ case sdp_data::ALTERNATIVE:
+skip: {//p points just after the length indicator, hence at the first item IN the sequence
+ printf("SEQ%d{%p ", len, item);
+ int n = 0;
+ unsigned short key;
+ serv_rec *dummy = 0;
+ while (p < end) {
+ sdp_data *elem = 0;
+ p += parseLight(el + p, len-p, elem, dummy);//parse each element in the sequence, the second arg is as yet unused
+ if (record) {
+ if (n & 1) { //value
+ record->insert(pair<unsigned short, sdp_data*>(key, elem));
+ } else //key
+ key = n;
+ n++;
+ }
+ }
+ }
+ printf("}\n");
+ break;
+ case 8:
+ printf("URL%d='%s' ", len, (char*)el+p);
+ break;
+ default:
+ printf("Parse: Unknown type %d, len=%d (code=%#02X)\n", el[0]>>3, len, el[0]);
+ }
+ result = item;
+ return end;
+}
+
+unsigned SDPHandler::parse (const unsigned char *el, unsigned count, sdp_data* &result, serv_rec* &record) {
+ unsigned p = 0;
+ unsigned len = length(el, p);
+ int end = p+len;//end is the index of the item just after the sequence
+ sdp_data *item = 0;
+ switch (el[0]>>3) {//type
+ case sdp_data::NULL_:
+ item = new sdp_data();
+ break;
+ case sdp_data::UNSIGNED:
+ item = new sdp_data((unsigned)getval(el+p, len), len);
+ break;
+ case sdp_data::SIGNED:
+ item = new sdp_data((int)getval(el+p, len), len);
+ break;
+ case sdp_data::UUID:
+ if (len==16) {
+ char rev[16];
+ for (int i = 0; i < 16; i++)
+ rev[i] = el[p+15-i];
+ item = new sdp_data(sdp_data::UUID, rev, len);
+ } else
+ item = new sdp_data(sdp_data::UUID, getval(el+p, len), len);
+ break;
+ case sdp_data::STRING:
+ item = new sdp_data((char*)el+p, len);
+ break;
+ case sdp_data::BOOL:
+ item = new sdp_data((bool)getval(el+p, len), len);
+ break;
+ case sdp_data::SEQUENCE:
+ item = new sdp_data(sdp_data::SEQUENCE);
+ goto skip;
+ case sdp_data::ALTERNATIVE:
+ item = new sdp_data(sdp_data::ALTERNATIVE);
+skip: {//p points just after the length indicator, hence at the first item IN the sequence
+ //printf("SEQ%d{%p ", len, item);
+ int n = 0;
+ unsigned short key;
+ serv_rec *dummy = 0;//means: there is no service record to fill in for deeper levels
+ while (p < end) {
+ sdp_data *elem = 0; //this becomes the tree with attribute values
+ p += parse(el + p, len-p, elem, dummy);//parse each element in the sequence, the second arg is as yet unused
+ if (record) { //if at the level of attribute list, add elem to record as key/value pair
+ if (n & 1) { //value
+ record->insert(pair<unsigned short, sdp_data*>(key, elem));
+ } else //key
+ key = elem->asUnsigned();
+ n++;
+ } else //just add the elements to the value tree
+ item->add_element(elem);
+ }
+ }
+ //printf("}\n");
+ break;
+ case 8:
+ item = new sdp_data(sdp_data::URL, (char*)el+p, len);
+ break;
+ default:
+ printf("Parse: Unknown type %d, len=%d (code=%#02X)\n", el[0]>>3, len, el[0]);
+ }
+ result = item;
+ return end;
+}
+
+void SDPHandler::append(const unsigned char *payload, int len) {
+ unsigned char *tmp = new unsigned char[byteCount + len];//append the payload to the previous continuation buffer
+ if (contBuf && byteCount) {
+ memcpy(tmp, contBuf, byteCount); //copy the existing part
+ delete[] contBuf;//delete the old buffer
+ }
+ memcpy(tmp+byteCount, payload, len); //append the new part
+ contBuf = tmp;
+ byteCount += len;
+}
+
+void SDPHandler::freeBuf() {
+ if (contBuf) {
+ delete[] contBuf;
+ contBuf = 0;
+ }
+ byteCount = 0;
+}
+
+
+//TODO: test case 7, add server support (cases 2, 4, 6)
+//3 cases: cont==0 && contBuf==0 -> use rsp; cont!=0 -> append; cont==0 && contBuf!=0 -> append and use contBuf
+int SDPHandler::parseRsp(const unsigned char*rsp, int len) {
+ //unsigned tid = rsp[2] + ((unsigned)rsp[1]<<8);
+ unsigned parlen = rsp[4] + ((unsigned)rsp[3]<<8);
+ //printf("ParseRsp: tid=%04X, parlen=%d ", tid, parlen);
+ unsigned cont = 0;
+ switch (rsp[0]) {
+ case 1: {//errorRsp
+ unsigned errorcode = rsp[6] + ((unsigned)rsp[5]<<8);
+ if (parlen > 2) {
+ printf("ErrorInfo (%d bytes) for error %d is available\n", parlen-2, errorcode);
+ }
+ if (ErrorResponse)
+ ErrorResponse(errorcode);
+ return errorcode;
+ }
+ //break;
+ case 3: { //servicesearchRsp
+ unsigned total = rsp[6] + ((unsigned)rsp[5]<<8);
+ unsigned current = rsp[8] + ((unsigned)rsp[7]<<8);
+ cont = rsp[9+4*current];
+ memcpy(contState, &rsp[9+4*current], cont+1);//copy the continuation state
+ //printf("total=%d, current=%d, cont=%d\n", total, current, cont);
+ if (cont) {
+ //no special handling here, just append the servicerecordhandles
+ }
+ //linear list of 32bit service-handles
+ for (int i = 0; i < current; i++) {
+ unsigned result = 0;
+ for (int j = 0; j< 4; j++)
+ result = (result<<8) + rsp[9 + 4*i + j];
+ printf("SDP Search handle %08X\n", result);
+ services.insert(pair<unsigned, serv_rec*>(result, 0));
+ }
+ if (ServiceSearchResponse)
+ ServiceSearchResponse();
+ }
+ break;
+ case 5: { //serviceattributeRsp
+ unsigned count = rsp[6] + ((unsigned)rsp[5]<<8);//bytes in this part of the attribute list
+// append(rsp+7, count);
+ cont = rsp[7+count];
+ memcpy(contState, &rsp[7+count], cont+1);//copy the continuation state
+ if (cont) {
+ append(rsp+7, count);
+ break;
+ }
+ //printf("count=%d parsing...\n", byteCount);
+ serv_rec *serv = new serv_rec;
+ if (contBuf) {
+ append(rsp+7, count);
+ parse(contBuf, byteCount, tree, serv);
+ } else
+ parse(rsp+7, count, tree, serv);
+ //printf("...parsing done, ");
+ //get the AttributeID, make sure attribId 0 is always included in the request
+ unsigned key = (*serv)[0]->asUnsigned();//AttributeID '0' always refers to the serviceID
+ //printf("Key=%#X\n", key); //key will be 0 when not requested
+ services[key] = serv; //Add the attribute list to the services
+ freeBuf();
+ if (ServiceAttributeResponse)
+ ServiceAttributeResponse(serv);
+ }
+ break;
+ //below is UNTESTED
+ case 7: { //servicesearchattributeRsp
+ unsigned count = rsp[6] + ((unsigned)rsp[5]<<8);
+ append(rsp+7, count);
+ cont = rsp[7+count];
+ memcpy(contState, &rsp[7+count], cont+1);
+ if (cont)
+ break;
+ unsigned pos = 0;
+ if (contBuf[pos]>>3 != sdp_data::SEQUENCE) {
+ printf("Expected a sequence of attribute lists\n");
+ break;
+ }
+ unsigned len = length(contBuf, pos);//get the length of the list of lists and advance pos to the first list
+ while (pos<len) {
+ printf("pos=%d, count=%d, parsing...\n", pos, len);
+ serv_rec *serv = new serv_rec;
+ pos = parse(contBuf+pos, len, tree, serv);
+ unsigned key = (*serv)[0]->asUnsigned();
+ services[key] = serv;
+ }
+ freeBuf();
+ printf("...parsing done, pos=%d\n", pos);
+ if (ServiceSearchAttributeResponse)
+ ServiceSearchAttributeResponse();
+ }
+ break;
+ default:
+ printf("Unknown SDP response type %02X\n", rsp[0]);
+ break;
+ }
+ return 0;
+}
+
+//************************ SERVER related *******************************************//
+
+//unsigned SDPHandler::parseUUID(const u8* data, int len, unsigned &p) {
+unsigned parseUUID(const u8* data, int len, unsigned &p) {
+ unsigned u = 0;
+ if ((data[p]>>3) != sdp_data::UUID) {
+ printf(" UUID expected, got %d ", data[p]>>3);
+ return (unsigned)-1;
+ }
+ switch (data[p++] & 7) {
+ case 1:
+ u = getval(data+p, 2);
+ p +=2;
+ break;
+ case 2:
+ u = getval(data+p, 4);
+ p += 4;
+ break;
+ case 4:
+ u = getval(data+p, 4);
+ p += 16;
+ break;
+ default:
+ printf(" UUID must be 2, 4 or 16 bytes, got type %d\n", data[p-1]);
+ }
+ return u;
+}
+
+#define SVC_HANDLE 0x0001001DU //serial service
+void SDPManager::buildServer() {
+ static sdp_data rfcomm(sdp_data::SEQUENCE);
+ static sdp_data l2cap(sdp_data::SEQUENCE);
+ static sdp_data protocol(sdp_data::SEQUENCE);
+ static sdp_data serviceclass(sdp_data::SEQUENCE);
+ static sdp_data browsegroup(sdp_data::SEQUENCE);
+ static sdp_data root(sdp_data::UUID, BROWSEROOT);
+ static sdp_data l2capuuid(sdp_data::UUID, 0x0100);
+ static sdp_data rfcommuuid(sdp_data::UUID, 0x003);
+ static sdp_data serial(sdp_data::UUID, 0x1101);
+ static sdp_data chan(1U,1);
+ static sdp_data handle(SVC_HANDLE,4);
+ static sdp_data serviceID(0U, 2);
+// static sdp_data name("MBED BlueUSB RFCOMM Serial");
+ static sdp_data name("Serial Port");
+ rfcomm.add_element(&rfcommuuid);
+ rfcomm.add_element(&chan);
+ l2cap.add_element(&l2capuuid);
+ protocol.add_element(&l2cap);
+ protocol.add_element(&rfcomm);
+ serviceclass.add_element(&serial);
+ browsegroup.add_element(&root);
+ static serv_rec attr_list;
+ attr_list[0] = &handle;
+ attr_list[1] = &serviceclass;
+ attr_list[4] = &protocol;
+ attr_list[5] = &browsegroup;
+ attr_list[0x100] = &name;
+ server[SVC_HANDLE] = &attr_list;//server is static and this statement crashes the program when invoked from the constructor which is also invoked statically
+}
+
+int SDPManager::findUUID(unsigned h, unsigned uuid) {
+ serv_rec *rec = server[h];
+ for ( serv_rec::iterator it = rec->begin(); it != rec->end(); it++) {
+ if (it->second->findUUID(uuid))
+ return it->first;
+ }
+ printf("rejected %08X because of %04Xx\n", h, uuid);
+ return -1;
+}
+
+void SDPManager::match(bool elig[], unsigned uuid) {
+ map<unsigned, serv_rec*>::iterator idx;
+ int i = 0;
+ for (idx = server.begin(); idx != server.end(); idx++, i++)
+ if (findUUID(idx->first, uuid) < 0)
+ elig[i] = false;
+}
+
+bool SDPManager::isInList(unsigned short id, const unsigned char* list, int end) {
+ int len;
+ for (unsigned pos = 0; pos < end; pos += len) {
+ len = length(list, pos);
+ switch (len) {
+ case 2: //single value
+ if (getval(list+pos, 2) == id)
+ return true;
+ break;
+ case 4: //range
+ if (getval(list+pos, 2) > id) break;
+ if (getval(list+pos+2, 2) < id) break;
+ return true;
+ default:
+ printf("Unexpected length %d\n", len);
+ }
+ }
+ return false;
+}
+
+void SDPManager::addToReply(sdp_data *svc, serv_rec *list, const unsigned char* att, int end) {
+ unsigned short len, low, high;
+ serv_rec::iterator from, to, idx;
+ if (list==0) {
+ printf("Invalid attribute list (NULL)\n");
+ return;
+ }
+ for (unsigned pos = 0; pos < end; pos += len) {
+ len = length(att, pos);
+ switch (len) {
+ case 2: //single value
+ low = getval(att+pos, 2);
+ svc->add_element(new sdp_data(low, 2));
+ svc->add_element((*list)[low]);
+ printf("Found attrib %d\n", low);
+ break;
+ case 4: //range
+ low = getval(att+pos, 2);
+ high = getval(att+pos+2, 2);
+ from = list->lower_bound(low);
+ to = list->upper_bound(high);
+ for (idx = from; idx != to; idx++) {
+ svc->add_element(new sdp_data(idx->first, 2));
+ svc->add_element(idx->second);
+ printf("Found attrib %d\n", idx->first);
+ }
+ break;
+ default:
+ printf("Unexpected length %d\n", len);
+ }
+ }
+}
+
+//for continuations, just generate the entire list, truncate to desired length and append position of the remainder as continuation
+//on the next iteration, generate the list again, use continuation to find remainder and reiterate
+void SDPManager::SDPServer(int socket, SocketState state, const u8* data, int len, void* userData) {
+ unsigned tid = data[2] + ((unsigned)data[1]<<8);
+ unsigned parlen = data[4] + ((unsigned)data[3]<<8);
+ //printf("ParseReq: PDU_ID=%d, tid=%04X, parlen=%d ", data[0], tid, parlen);
+ unsigned pos = 5;
+ switch (data[0]) {
+ case 1: {//errorRsp
+ unsigned errorcode = data[6] + ((unsigned)data[5]<<8);
+ if (parlen > 2) {
+ printf("ErrorInfo (%d bytes) for error %d is available\n", parlen-2, errorcode);
+ }
+ errorhandler(errorcode);
+ }
+ break;
+ case 2: { //servicesearchReq
+ printf("servicesearchReq almost implemented\n");
+ unsigned pat[12];//the received search pattern
+ int pn;//number of uuids in the pattern
+ if (data[pos]>>3 != sdp_data::SEQUENCE) {//the uuids are wrapped in a sequence
+ printf("Expected a sequence of UUIDs\n");
+ break;
+ }
+ unsigned end = pos + length(data, pos);//get the length of the list of lists and advance pos to the first list
+ bool *eligible = new bool[server.size()];//marks for the services identified by the search pattern
+ for (int i = 0; i < server.size(); i++) eligible[i] = true;
+ for (pn = 0; pn < 12 && pos < end; pn++) {
+ pat[pn] = parseUUID(data,end, pos);//store uuid from the sequence in the pattern
+ match(eligible, pat[pn]);//unmark a service when it does not contain the uuid
+ //printf("pos=%d, count=%d, uuid=%#X\n", pos, len, pat[pn]);
+ }
+
+ unsigned count = getval(data+pos, 2); //maximum length of attribute list to return
+ pos += 2;
+ unsigned tail = data[pos];
+ if (tail) {
+ tail = getval(data+pos+1, tail);
+ printf("requested continuation tailpos=%u\n", tail);
+ } else {
+ //printf("No continuation requested\n");
+ }
+ unsigned *handles = new unsigned[server.size()];
+ int total = 0, current = 0;
+ map<unsigned, serv_rec*>::iterator idx;
+ int i = 0;
+ for (idx = server.begin(); idx != server.end() && total < count; idx++, i++)
+ if (eligible[i])
+ handles[total++] = idx->first;
+ ServiceSearchReply(tid, handles, total, tail);
+ delete[] handles;
+ delete[] eligible;
+ }
+ break;
+ case 4: { //serviceattributeReq
+ printf("serviceattributeReq almost implemented\n");
+ sdp_data reply(sdp_data::SEQUENCE);//the attributelist of the reply
+ unsigned svcid = getval(data+pos, 4);
+ pos += 4;
+ unsigned count = getval(data+pos, 2); //maximum length of attribute list to return
+ pos += 2;
+ int len = length(data, pos); //get the length of the attributeID list
+ int cont = pos + len;
+ printf("svcid=%08X, count=%u, len=%u, pos=%u\n", svcid, count, len, pos);
+ addToReply(&reply, server[svcid], data+pos, len);
+ unsigned tail = data[cont];
+ printf("tail=%u, reply size=%d\n", tail, reply.Size());
+ if (tail) {
+ tail = getval(data+cont+1, tail);
+ printf("requested continuation tailpos=%u, size=%u\n", tail, reply.Size());
+ } else {
+ //printf("No continuation requested\n");
+ }
+
+ ServiceAttributeReply(tid, &reply, count, tail);
+ for (int k = 0; k < reply.items(); k++) {
+ if ((k & 1) == 0) //even hence ID
+ delete reply.item(k); //destroy the ID
+ reply.remove(k); //set all items to nil to prevent destruction of the DB
+ }
+ }
+ break;
+ case 6: { //servicesearchattributeReq
+ sdp_data reply(sdp_data::SEQUENCE);//the attributelist of the reply
+
+ unsigned pat[12];//the received search pattern
+ int pn;//number of uuids in the pattern
+ if (data[pos]>>3 != sdp_data::SEQUENCE) {//the uuids are wrapped in a sequence
+ printf("Expected a sequence of UUIDs\n");
+ break;
+ }
+ unsigned end = pos + length(data, pos);//get the length of the list of lists and advance pos to the first list
+ bool *eligible = new bool[server.size()];//marks for the services identified by the search pattern
+ for (int i = 0; i < server.size(); i++) eligible[i] = true;
+ for (pn = 0; pn < 12 && pos < end; pn++) {
+ pat[pn] = parseUUID(data,end, pos);//store uuid from the sequence in the pattern
+ match(eligible, pat[pn]);//unmark a service when it does not contain the uuid
+ //printf("pos=%d, count=%d, uuid=%#X\n", pos, len, pat[pn]);
+ }
+
+ unsigned count = getval(data+pos, 2); //maximum length of attribute list to return
+ pos += 2;
+
+ int len = length(data, pos); //get the length of the attributeID list
+ int cont = pos + len;
+ //printf("Count = %d pos=%d, data[pos]=%02x, len=%d, cont=%d\n", count, pos, data[pos], len, cont);
+ int i = 0;
+ for (map<unsigned, serv_rec*>::iterator idx = server.begin(); idx != server.end(); idx++, i++) {//foreach service
+ //printf("testing service handle %08X\n", idx->first);
+ if (!eligible[i]) continue; //skip services that don't match the pattern
+ sdp_data *svc = new sdp_data(sdp_data::SEQUENCE); //create a sequence for the attributes of the present service
+#if 0
+ for (serv_rec::iterator attr = idx->second->begin(); attr != idx->second->end(); attr++) {//foreach attrib in the service
+ //printf("testing attribID %u\n", attr->first);
+ if (isInList(attr->first, data+pos, len)) {//check if it is requested
+ printf("Found attribID %d\n", attr->first);
+ sdp_data *p = attr->second; //the attribute
+ svc->add_element(new sdp_data(attr->first, 2)); //add the attribute ID as an unsigned short
+ svc->add_element(p); //add the attribute
+ //printf("appending %d bytes\n", p->Size());
+ }
+ }
+#else
+//alternatively use map::lower/upper_bound and equal_range, needs only one pass over the range list for each service
+ addToReply(svc, idx->second, data+pos, len);
+#endif
+ reply.add_element(svc); //append the new attribute list to the reply list
+ }
+
+ unsigned tail = data[cont];
+ if (tail) {
+ tail = getval(data+cont+1, tail);
+ printf("requested continuation tailpos=%u, size=%u\n", tail, reply.Size());
+ } else {
+ //printf("No continuation requested\n");
+ }
+ ServiceSearchAttributeReply(tid, &reply, count, tail);
+
+ for (int j = 0; j < reply.items(); j++) {
+ sdp_data *al = reply.item(j);
+ for (int k = 0; k < al->items(); k++) {
+ if ((k & 1) == 0) //even hence ID
+ delete al->item(k); //destroy the ID
+ al->remove(k); //set all items to nil to prevent destruction of the DB
+ }
+ delete al; //destroy the list;
+ reply.remove(j);
+ }
+ delete[] eligible;
+ }
+ break;
+ default:
+ printf("Unknown SDP request type %02X\n", data[0]);
+ break;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sdp/sdp.h Fri Jul 01 09:16:00 2011 +0000
@@ -0,0 +1,186 @@
+#ifndef SDP_H
+#define SDP_H
+#include "AvailableMemory.h"
+#include "sdp_data.h"
+#include <map>
+#define OFFSET 8
+
+class SDPManager;
+extern SDPManager SDP;
+typedef map<unsigned short, sdp_data*> serv_rec;
+
+void attribHandler(serv_rec *r);
+unsigned parseUUID(const u8* data, int len, unsigned &p);
+unsigned length(const unsigned char *el, unsigned &p);
+unsigned getval(const unsigned char *p, int n) ;
+void errorhandler(unsigned err);//default error handler
+
+
+class SDPHandler: public SocketHandler {
+// int _l2cap;
+ int sdp_socket;
+ unsigned char l2cap_buf[100+OFFSET];
+ unsigned char* buf;
+ unsigned txid;
+ unsigned char contState[17];//maximum size, in practive it is 3
+ unsigned char *contBuf;
+ unsigned byteCount;
+ int _state;
+ sdp_data *tree;//root of the entire service tree
+ map<unsigned, serv_rec*> services;//the set of supported services <handle, service>
+ map<unsigned, serv_rec*>::iterator index;
+//server properties
+// static map<unsigned, serv_rec*> server;
+// static int serverSock;
+public:
+ SDPHandler();
+ void Clear();
+ virtual int Open(SocketInternal* sock, SocketAddrHdr* addr);
+// virtual int Accept(SocketInternal *sock, int scid, int rxid); //called indirectly from BTDevice::Control
+ virtual int Send(SocketInternal* sock, const u8* data, int len);
+ virtual int Close(SocketInternal* sock);
+ virtual char* Name() {
+ return "SDPHandler SocketHandler";
+ }
+ void OnSdpRsp(const u8* data, int len);
+ static void OnSdpRsp(int socket, SocketState state, const u8* data, int len, void* userData);
+
+ //this function is called when the SDP sockets receives data (see HCICallback in TestShell),
+ //currently does not happen because not forwarded from OnSdpRsp, can be used to handle multiple connections
+ static void OnSockCallback(int socket, SocketState state, const u8* data, int len, void* userData) ;
+ //The SDP server is stateless hence can be static
+// static void SDPServer(int socket, SocketState state, const u8* data, int len, void* userData) ;
+
+ void (*ErrorResponse)(unsigned) ;
+ void (*ServiceSearchResponse)() ;
+ void (*ServiceAttributeResponse)(serv_rec*) ;
+ void (*ServiceSearchAttributeResponse)() ;
+ int ServiceSearchRequest(sdp_data *sp, unsigned count, unsigned cs=0);
+ int ServiceAttributeRequest(unsigned handle, unsigned count, sdp_data* al, unsigned cs=0) ;
+ int ServiceSearchAttributeRequest(sdp_data *sp, unsigned count, sdp_data* al, unsigned cs=0);
+//server
+// static int ServiceSearchAttributeReply(unsigned rxid, sdp_data* al, unsigned count, unsigned cs=0);
+private:
+// static unsigned length(const unsigned char *el, unsigned &p);
+// static unsigned getval(const unsigned char *p, int n) ;
+// static unsigned parseUUID(const u8* data, int len, unsigned &p);
+ unsigned parse (const unsigned char *el, unsigned count, sdp_data* &result, serv_rec* &record) ;
+ unsigned parseLight (const unsigned char *el, unsigned count, sdp_data* &result, serv_rec* &record) ;
+ int parseRsp(const unsigned char*rsp, int len) ;
+ void append(const unsigned char*rsp, int len) ;
+ void freeBuf();
+};
+/*
+class SDPClient: public SDPHandler {
+};
+
+class SDPServer: public SDPHandler {
+};
+*/
+class SDPManager: public SocketHandler {
+ map<int, SDPHandler*> handlers;
+//server properties
+// SDPHandler *Server;
+ static map<unsigned, serv_rec*> server;
+ static int serverSock;
+ bool once;
+public:
+ SDPManager() {
+ once = true;
+ }
+ virtual int Open(SocketInternal* sock, SocketAddrHdr* addr) {
+ printf("SDPManager::Open(sock (ID=%d, type=%d), addr): should not be called\n", sock->ID, sock->Type);
+ return sock->ID;//((SDPHandler*)sock->userData)->Open(sock, addr);
+ }
+ int Open(SocketAddrHdr* addr) {
+ L2CAPAddr* ad = (L2CAPAddr*)addr;
+ ad->psm = L2CAP_PSM_SDP;//open the l2cap channel
+ SDPHandler *h = new SDPHandler;
+ int s = Socket_Open(SOCKET_L2CAP, addr, &SDPHandler::OnSdpRsp, h);
+ handlers[s] = h;
+ return s;
+ }
+ virtual int Accept(SocketInternal *sock, int scid, int rxid) { //called indirectly from BTDevice::Control
+ if (once) {
+ once = false;
+ buildServer();//build the DB on the first connection
+ }
+ //sock is registered as an SDP sock but we use it as an L2CAP sock
+ //type=SDP
+ //userData = BTDevice
+ //Internal = L2CAPSocket
+ BTDevice *l2cap = (BTDevice*)sock->userData;
+ //sock->dcid = scid
+ //sock->scid = something based on sock->ID
+ serverSock = sock->ID;
+ printf("Invoking accept on %p (%s) for sock %d and scid=%d\n", l2cap, l2cap->Name(), sock->ID, scid);
+ return l2cap->Accept(sock, scid, rxid);
+ }
+ virtual int Send(SocketInternal* sock, const u8* data, int len) {//called by the server
+ BTDevice *l2cap = (BTDevice*)sock->userData;
+ return l2cap->Send(sock, data, len);
+ }
+ virtual int Close(SocketInternal* sock) {
+ printf("SDPManager::Close() closing socket %d\n", sock->ID);
+ SDPHandler *h = handlers[sock->ID];
+ int retval = h->Close(sock);
+ delete h;
+ handlers[sock->ID] = 0;
+ return retval;
+ }
+ void Destroy(int s) {
+ printf("Deleting handler for socket %d\n", s);
+ delete handlers[s];
+ handlers[s] = 0;
+ }
+ virtual char* Name() {
+ return "SDPManager SocketHandler";
+ }
+ //void OnSdpRsp(const u8* data, int len);
+ static void OnSdpRsp(int socket, SocketState state, const u8* data, int len, void* userData) {
+ printf("SDPManager::OnSdpRsp(socket %d, state %d, len %d)\n", socket, state, len);
+ }
+ //The SDP server is (almost) stateless hence can be static
+ static void SDPServer(int socket, SocketState state, const u8* data, int len, void* userData) ;
+ static void match(bool elig[], unsigned uuid);
+ static bool isInList(unsigned short id, const unsigned char* list, int end);
+ static void addToReply(sdp_data *svc, serv_rec *list, const unsigned char* att, int end);
+ static int findUUID(unsigned h, unsigned uuid);
+ void buildServer();
+ static int ServiceSearchReply(unsigned rxid, unsigned *handles, unsigned count, unsigned cs=0);
+ static int ServiceAttributeReply(unsigned rxid, sdp_data* al, unsigned count, unsigned cs=0);
+ static int ServiceSearchAttributeReply(unsigned rxid, sdp_data* al, unsigned count, unsigned cs=0);
+ /*
+ //this function is called when the SDP sockets receives data (see HCICallback in TestShell),
+ //currently does not happen because not forwarded from OnSdpRsp, can be used to handle multiple connections
+ static void OnSockCallback(int socket, SocketState state, const u8* data, int len, void* userData) ;
+
+ static void errorhandler(unsigned err);
+
+ void (*ErrorResponse)(unsigned) ;
+ void (*ServiceSearchResponse)() ;
+ void (*ServiceAttributeResponse)(serv_rec*) ;
+ void (*ServiceSearchAttributeResponse)() ;
+ int ServiceSearchRequest(sdp_data *sp, unsigned count, unsigned cs=0);
+ int ServiceAttributeRequest(unsigned handle, unsigned count, sdp_data* al, unsigned cs=0) ;
+ int ServiceSearchAttributeRequest(sdp_data *sp, unsigned count, sdp_data* al, unsigned cs=0);
+ //server
+ private:
+ static unsigned length(const unsigned char *el, unsigned &p);
+ static unsigned getval(const unsigned char *p, int n) ;
+ static unsigned parseUUID(const u8* data, int len, unsigned &p);
+ static void addAttrib(unsigned h, unsigned short id, sdp_data *attrib);
+ static void addIndex(unsigned h, unsigned uuid);
+ static int findUUID(unsigned h, unsigned uuid);
+ static void match(bool elig[], unsigned uuid);
+ static bool isInList(unsigned short id, const unsigned char* list, int end);
+ void buildServer();
+ unsigned parse (const unsigned char *el, unsigned count, sdp_data* &result, serv_rec* &record) ;
+ unsigned parseLight (const unsigned char *el, unsigned count, sdp_data* &result, serv_rec* &record) ;
+ int parseRsp(const unsigned char*rsp, int len) ;
+ void append(const unsigned char*rsp, int len) ;
+ void freeBuf();
+ */
+};
+
+#endif
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sdp/sdp_data.cpp Fri Jul 01 09:16:00 2011 +0000
@@ -0,0 +1,229 @@
+#include "mbed.h"
+#include "sdp_data.h"
+#include "Utils.h"
+
+char sdp_data::ret[12];
+
+unsigned sdp_data::asUnsigned() {
+ switch (type) {
+ case NULL_:
+ return 0;
+ case UNSIGNED:
+ case SIGNED:
+ case BOOL:
+ return data;
+ case UUID:
+#ifdef LONGUUID
+ return uuid[6] + uuid[7]<<16;
+#else
+ return data;
+#endif
+ default:
+ return 0;
+ }
+}
+
+const char* sdp_data::asString(bool alt) {
+ char sep = ',';
+ switch (type) {
+ case NULL_:
+ return "NULL";
+ case UNSIGNED:
+ if (alt) sprintf(ret, "0x%0*X", size*2, data);
+ else sprintf(ret, "%u", data);
+ return ret;
+ case SIGNED:
+ sprintf(ret, "%d", data);
+ return ret;
+ case BOOL:
+ return data ? "TRUE" : "FALSE";
+ case STRING:
+ case URL:
+ return str;
+ case ALTERNATIVE:
+ sep = '|';
+ case SEQUENCE: {
+ if (longstr) delete[] longstr;
+ int n = sprintf(ret, "SEQ %d { ", size) + 1;
+ longstr = new char[n];
+ strcpy(longstr, ret);
+ for (int i = 0; i < sequence.size(); i++) {
+ const char *s = sequence[i]->asString(alt);
+ n = strlen(longstr) + strlen(s) + 2;
+ char *t = new char[n];
+ strcpy(t, longstr);
+ strcat(t, s);
+ t[n-2] = sep;
+ t[n-1]='\0';
+ //printf("[%s]+[%s]+%c=[%s]\n", longstr, s, sep, t);
+ delete[] longstr;
+ longstr = t;
+ }
+ longstr[n-2] = '}';
+ }
+ return longstr;
+ case UUID:
+#ifdef LONGUUID
+ switch (size) {
+ case 2:
+ sprintf(ret, "0x%04X", uuid[6]);
+ return ret;
+ case 4:
+ sprintf(ret, "0x%04X%04X", uuid[7],uuid[6]);
+ return ret;
+ case 16:
+ longstr = new char[35];
+ sprintf(longstr, "%04X%04X-%04X-%04X-%04X-%04X%04X%04X", uuid[7],uuid[6],uuid[5],uuid[4],uuid[3],uuid[2],uuid[1],uuid[0]);
+ return longstr;
+ }
+#else
+ switch (size) {
+ case 2:
+ sprintf(ret, "0x%04X", data & 0xffff);
+ return ret;
+ case 4:
+ sprintf(ret, "0x%08X", data);
+ return ret;
+ case 16:
+ longstr = new char[35];
+ sprintf(longstr, "%08X-%04X-%04X-%04X-%04X%04X%04X", data,base_uuid[5],base_uuid[4],base_uuid[3],base_uuid[2],base_uuid[1],base_uuid[0]);
+ return longstr;
+ }
+#endif
+ }
+ return "Unsupported";
+}
+
+unsigned sdp_data::Size() {
+ if (size==0 && type==SEQUENCE)
+ return 2;
+ if (size<3 || size==4 || size==8 || size==16)
+ return size+1;//include descriptor
+ if (size < 256) return size+2; //1 extra byte
+ if (size < 65536) return size+3; //2 extra bytes
+ return size+5; //4 extra bytes
+}
+
+unsigned sdp_data::sizedesc(unsigned char *buf) {
+ int desc, extra=0;
+ switch (size) {
+ case 0:
+ /* should be:
+ if (type != NULL_) {
+ desc = 5;
+ extra = 1;
+ buf[1] = 0;
+ }
+ */
+ case 1:
+ desc = 0;
+ break;
+ case 2:
+ desc = 1;
+ break;
+ case 4:
+ desc = 2;
+ break;
+ case 8:
+ desc = 3;
+ break;
+ case 16:
+ desc = 4;
+ break;
+ default:
+ if (size < 256) {
+ desc = 5;
+ extra = 1;
+ buf[1] = size;
+ } else if (size < 65536) {
+ desc = 6;
+ extra = 2;
+ *(unsigned short*)&buf[1] = size;
+ } else {
+ desc = 7;
+ extra = 4;
+ *(unsigned*)&buf[1] = size;
+ }
+ }
+ buf[0] |= desc;
+ return extra+1;
+}
+
+void sdp_data::revcpy(unsigned char*d, const unsigned char*s, int n) {
+ for (int i = 0; i < n; i++)
+ d[i] = s[n-i-1];
+}
+
+unsigned sdp_data::build(unsigned char *buf, unsigned max) {//max is ignored
+ int p = 0;
+ buf[p] = type<<3;
+ switch (type) {
+ case NULL_:
+ p++;
+ break;
+ case UNSIGNED:
+ case SIGNED:
+ case BOOL:
+ p += sizedesc(buf+p);
+ revcpy(buf+p, (unsigned char*)&data, size);
+ break;
+ case UUID:
+ p += sizedesc(buf+p);
+#ifdef LONGUUID
+ switch (size) {
+ case 2:
+ case 4:
+ revcpy(buf+p, (unsigned char*)&uuid[6], size);
+ break;
+ case 16:
+ revcpy(buf+p, (unsigned char*)uuid, size);
+ break;
+ }
+#else
+ switch (size) {
+ case 2:
+ case 4:
+ revcpy(buf+p, (unsigned char*)&data, size);
+ break;
+ case 16:
+ revcpy(buf+p, (unsigned char*)&data, 4);
+ revcpy(buf+p+4, base_uuid, 12);
+ break;
+ }
+#endif
+ break;
+ case STRING:
+ case URL:
+ p += sizedesc(buf+p);
+ memcpy(buf+p, str, size);
+ break;
+ case SEQUENCE:
+ case ALTERNATIVE: {
+ if (sequence.size()==0) {//hack: should be solved in sizedesc
+ buf[p++] |= 5;
+ buf[p++] = 0;
+ break;
+ }
+ int n = 0;
+ p += sizedesc(buf+p);
+ for (int i = 0; i < sequence.size(); i++)
+ n += sequence.at(i)->build(buf+p+n, max-p);
+ }
+ break;
+ }
+ p += size;
+// printfBytes("Build:", buf, p);
+ return p;
+}
+
+bool sdp_data::findUUID(unsigned uuid) {
+ if (type == UUID)
+ return asUnsigned()==uuid;
+ if (type==SEQUENCE || type==ALTERNATIVE) {
+ for (int i = 0; i < sequence.size(); i++) {
+ if (sequence[i]->findUUID(uuid))
+ return true;
+ }
+ }
+ return false;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sdp/sdp_data.h Fri Jul 01 09:16:00 2011 +0000
@@ -0,0 +1,116 @@
+#ifndef SDP_DATA_H
+#define SDP_DATA_H
+
+#include <vector>
+
+extern const unsigned char base_uuid[16];// = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0, 0x07, 0x70, 0, 0x10, 0, 0};
+
+class sdp_data {
+public:
+ enum elements { NULL_, UNSIGNED, SIGNED, UUID, STRING, BOOL, SEQUENCE, ALTERNATIVE, URL};
+private:
+ enum elements type;
+ char size;
+ union {
+ unsigned data;
+ char *str;
+#ifdef LONGUUID
+ unsigned short uuid[8];
+#endif
+ };
+ vector<sdp_data*> sequence; //not allowed to be in union
+ static char ret[12];
+ char *longstr;
+public:
+ sdp_data(): type(NULL_), size(0), longstr(0) {
+ //printf("NULL%d ", size);
+ }
+ sdp_data(unsigned d, unsigned sz=4): type(UNSIGNED), size(sz), longstr(0) {
+ data=d;
+ //printf("UINT%d=%u ", size, data);
+ }
+ sdp_data(unsigned short d, unsigned sz=2): type(UNSIGNED), size(sz), longstr(0) {
+ data=d;
+ //printf("UINT%d=%u ", size, data);
+ }
+ sdp_data(signed d, unsigned sz=4): type(SIGNED), size(sz), longstr(0) {
+ data=d;
+ //printf("INT%d=%d ", size, data);
+ }
+ sdp_data(bool d, unsigned sz=1): type(BOOL), size(sz), longstr(0) {
+ data=d;
+ //printf("BOOL%d=%u ", size, data);
+ }
+ sdp_data(char*s, unsigned sz=0): type(STRING), longstr(0) {
+ if (sz) size = sz+1;
+ else size = strlen(s)+1;
+ str = new char[size];
+ strncpy(str, s, size);
+ str[size-1] = '\0';
+ //printf("STR%d='%s' ", size, str);
+ }
+ sdp_data(enum elements t, unsigned d, unsigned sz=2): type(t), size(sz), longstr(0) {
+ if (t==UUID) {
+#ifdef LONGUUID
+ memcpy(uuid, base_uuid, 16);
+ uuid[6] = d;
+ uuid[7] = d>>16;
+ // printf("UUID%d=%04X%04X ", size, uuid[7], uuid[6]);
+#else
+ data = d;
+#endif
+ } else printf("Please use other constructor for type %d\n", t);
+ }
+ sdp_data(enum elements t, char *d=0, unsigned sz=0): type(t), size(sz), longstr(0) {
+ switch (t) {
+#ifdef LONGUUID
+ case UUID:
+ memcpy(uuid, d, size);
+ // printf("UUID%d=%08X ", size, uuid[6]);
+ break;
+#endif
+ case URL:
+ //size = strlen(d)+1;
+ str = new char[size+1];
+ strcpy(str, d);
+ // printf("URL%d='%u' ", size, str);
+ break;
+ case SEQUENCE:
+ case ALTERNATIVE:
+ break;
+ default:
+ printf("Please use other constructor for type %d\n", t);
+ }
+ }
+ ~sdp_data() {
+ switch (type) {
+ case STRING:
+ case URL:
+ delete[] str;
+ break;
+ case SEQUENCE:
+ case ALTERNATIVE:
+ for (int i = 0; i < sequence.size(); i++)
+ delete sequence.at(i);
+ break;
+ }
+ if (longstr)
+ delete[] longstr;
+ }
+ void add_element(sdp_data *el) {
+ sequence.push_back(el);
+ size += el->Size();
+ }
+ unsigned asUnsigned() ;
+ const char* asString(bool alt=false) ;
+ unsigned Size() ;
+ unsigned items() { return sequence.size();}
+ sdp_data* item(int i) { return sequence[i];}
+ void remove(int i) { sequence[i] = 0;}
+ unsigned sizedesc(unsigned char *buf) ;
+ void revcpy(unsigned char*d, const unsigned char*s, int n) ;
+ unsigned build(unsigned char *buf, unsigned max) ;
+ bool findUUID(unsigned uuid);
+};
+
+#endif
\ No newline at end of file