local fix version of myBlueUSB (http://mbed.org/users/networker/code/myBlueUSB/). - merge deleted files which are required to compile. - enable echo back of received data via RFCOMM.

Dependencies:   AvailableMemory FatFileSystem mbed myUSBHost

rfcomm/RFCOMM.h

Committer:
nobukuma
Date:
2013-12-08
Revision:
2:9f25a7fa1a54
Parent:
0:003889bc474f

File content as of revision 2:9f25a7fa1a54:

#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