Dependents:   mbed_TANK_Kinect ftusbClass

Files at this revision

API Documentation at this revision

Comitter:
networker
Date:
Mon Apr 04 16:44:19 2011 +0000
Child:
1:9f3821db3048
Commit message:
initial revision

Changed in this revision

RFCOMM.cpp Show annotated file Show diff for this revision Revisions of this file
RFCOMM.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RFCOMM.cpp	Mon Apr 04 16:44:19 2011 +0000
@@ -0,0 +1,520 @@
+#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 1
+#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 MAX_FRAME_SIZE  350  //ACL buffer - some headroom
+
+#define DEBUG   1
+
+//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
+
+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);
+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;
+    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;
+        s->peer_credits += NR_CREDITS;//so provide some more
+    }
+    char initiator = !(s->dlci & 1);
+    unsigned char address = (1 << 0) | (initiator << 1) | (s->dlci << 2);
+    if (s->my_credits) {
+        s->my_credits--;
+        return rfcomm_send_packet(_l2cap, address, BT_RFCOMM_UIH, credits, data, len);
+    } else
+        return rfcomm_send_packet(_l2cap, address, BT_RFCOMM_UIH, 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 socket %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) |  (!initiator << 2), BT_RFCOMM_DISC, 0, 0, 0); //close dlci0
+        Socket_Close(_l2cap);
+        _l2cap = 0; //return rfcomm to the pool
+    }
+    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 = dlci 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->dlci = ch<<1; //set direction bit to 0 because we are the initator
+    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;
+        _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");
+            return 0;
+        }
+    } else {//bypass the l2cap channel creation
+        _bt_rfcomm_send_uih_pn_command(_l2cap, initiator, s->dlci, maxframesize);
+    }
+    return s->ID; //return the application unique socket nr.
+}
+/*
+int rfcomm::Open(BD_ADDR* bdAddr, inquiry_info* info) {//obsolete???
+    _addr = *bdAddr;
+    L2CAPAddr sockAddr;
+    sockAddr.bdaddr = _addr;
+    //open an L2CAP socket for RFCOMM
+    sockAddr.psm = L2CAP_PSM_RFCOMM;
+    _l2cap = Socket_Open(SOCKET_L2CAP,&sockAddr.hdr,OnRfCommControl,this);//this is the socket between the RFCOMM and the L2CAP layer
+
+    printfBytes("OPEN DEVICE CLASS",info->dev_class,3);
+    _devClass = (info->dev_class[0] << 16) | (info->dev_class[1] << 8) | info->dev_class[2];
+    return _l2cap;
+}
+*/
+
+//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) {//I guess this is called when data comes out of the socket
+    int packet_processed = 0;
+    rfcomm* self = (rfcomm*)userData;
+    const u8 initiator = 1;//self->initiator;
+    printf("\x1B[%dm", 32);
+    printf("OnRfCommControl sock = %d, state = %d, length = %d\n", socket, state, len);
+
+    if (len == 0) {
+        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
+    }
+    //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;
+    if (data[2]&1 == 0) {
+        length += data[3]<<7;
+        payload++;
+    }
+    u8 credits = 0;
+    if (control == BT_RFCOMM_UIH_PF)
+        credits = *(payload++);
+
+    if (DEBUG) {
+        printf("RFCOMM: EA=%d, C/R=%d, D=%d, DLCI=%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) { //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);
+                //_bt_rfcomm_send_uih_pn_command(socket, initiator, rfcomm_ch, MAX_FRAME_SIZE);
+                break;
+            case BT_RFCOMM_UIH://  received UIH Parameter Negotiation Response
+                switch (payload[0]) {
+                    case BT_RFCOMM_PN_RSP: {
+                        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
+                        maxframesize = min(maxframesize, payload[6] + (payload[7]<<8));
+                        printf("Max Frame Size = %d, got %d initial credits\n", maxframesize, payload[9]);
+                    }
+                    break;
+                    case BT_RFCOMM_MSC_CMD:
+                        packet_processed++;
+                        {
+                            printf("Received BT_RFCOMM_MSC_CMD\n");
+                            // fine with this
+                            RFCOMMSocket *r = self->find_socket(payload[2]>>2);
+                            if (r==0) break;
+                            if (r->State == SocketState_L2CAP_Config_wait_send ||
+                                    r->State == SocketState_L2CAP_Config_wait_rsp)
+                                break;
+                            unsigned char address = addr | 2; // set response bit
+                            unsigned char reply[4];
+                            memcpy(reply, payload, 4); //keep length, dlci and value
+                            reply[0]  = BT_RFCOMM_MSC_RSP;  // change command into response
+                            printf("Responding to 'I'm ready'\n");
+                            rfcomm_send_packet(socket, address, BT_RFCOMM_UIH, 0, reply, 4); //set credits too???
+                            switch (r->State) {
+                                case SocketState_L2CAP_Config_wait:
+                                    r->State = SocketState_L2CAP_Config_wait_send;
+                                    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;
+                            }
+                        }
+                        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);
+                        }
+                        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
+            case BT_RFCOMM_DM:
+                packet_processed++;
+                printf("Remote side refused connection on DLCI0\n");
+                self->_l2cap = Socket_Close(socket);
+                break;
+            case BT_RFCOMM_SABM:
+                printf("Remote site is seeking connection on DLCI0\n");
+                break;
+            default:
+                printf("Unexpected RFCOMM cmd %02XH for address %02XH, length=%d\n", data[1], data[0], (data[2]>>1) + ((data[2]&1) ? 0 : data[3]<<7));
+        }
+    } else { //data is for one of the serial sockets
+        RFCOMMSocket *s = self->find_socket(dlci);
+        switch (control) {
+            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  'I'm ready'\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;
+                //payload++;
+            case BT_RFCOMM_UIH: //user data
+                packet_processed++;
+                if (DEBUG) {
+                    printf("RX: address %02x, control %02x: ", addr, control);
+                    printHex( payload, pFCS-payload);
+                }
+                if (pFCS-payload) {
+                    s->Recv(payload, pFCS-payload);
+                    s->peer_credits--;
+                } else
+                    printf("Received empty packet\n");
+                if (pFCS-payload == 0 || s->peer_credits == 0) {//alternatively test for empty packet here and send credits with data
+                    char ini = !(dlci & 1);
+                    unsigned char address = (1 << 0) | (ini << 1) | (dlci << 2);
+                    printf("send %d credits to socket %d\n", NR_CREDITS, addr>>3);//was rfcomm_ch
+                    rfcomm_send_packet(socket, address, BT_RFCOMM_UIH_PF, NR_CREDITS, NULL, 0);
+                    s->peer_credits += NR_CREDITS;
+                }
+                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);
+}
+
+/**
+ * @param credits - only used for RFCOMM flow control in UIH wiht P/F = 1
+ */
+#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, 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[4];
+    uint8_t pos = 0;
+    payload[pos++] = BT_RFCOMM_MSC_CMD;
+    payload[pos++] = 2 << 1 | 1;  // len
+    payload[pos++] = (1 << 0) | (1 << 1) | (dlci << 2);
+    payload[pos++] = signals;
+    rfcomm_send_packet(source_cid, address, BT_RFCOMM_UIH, 0, (uint8_t *) payload, pos);
+}
+
+/*
+ * 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.h	Mon Apr 04 16:44:19 2011 +0000
@@ -0,0 +1,100 @@
+#ifndef RFCOMM_H
+#define RFCOMM_H
+#include "USBHost.h"
+#include "hci.h"
+
+#define MAX_RFCOMM_SCKTS    4
+/*
+template <class T> 
+T min(T a, T b) { 
+  return a<b ? a : b;
+}
+*/
+
+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; //for dlci0
+    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;
+    }
+
+    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 Close(SocketInternal* sock);
+    virtual char* Name() { return "rfcomm SocketHandler";}
+    void Recv(const u8* data, int len) {
+        printf("rfcomm::Recv was called\n");
+    }
+  //int Open(BD_ADDR* bdAddr, inquiry_info* info);  
+  friend RFCOMMManager;
+};
+
+class RFCOMMManager: public SocketHandler {
+    rfcomm _devs[MAX_RFCOMM_DEVICES];
+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();
+        return r->Open(sock, addr);
+    }
+    
+    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 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;
+    }
+};
+
+
+#endif