Test version of BlueUSB stack. Includes SDP and RFCOMM. As Client it allows to connect to my fischertechnik TX Controller. As Server it echo\\\\\\\'s characters to Putty. PIN=1234

Dependencies:   mbed myUSBHost AvailableMemory

Dependents:   mbed_TANK_Kinect myBlueUSB_ros ftusbClass

Revision:
13:327622e38551
--- /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