Zoltan Hudak / UsbHostMAX3421E

Dependents:   UsbHostMAX3421E_Hello

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SPP.cpp Source File

SPP.cpp

00001 /* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
00002 
00003  This software may be distributed and modified under the terms of the GNU
00004  General Public License version 2 (GPL2) as published by the Free Software
00005  Foundation and appearing in the file GPL2.TXT included in the packaging of
00006  this file. Please note that GPL2 Section 2[b] requires that all works based
00007  on this software must also be made publicly available under the terms of
00008  the GPL2 ("Copyleft").
00009 
00010  Contact information
00011  -------------------
00012 
00013  Kristian Lauszus, TKJ Electronics
00014  Web      :  http://www.tkjelectronics.com
00015  e-mail   :  kristianl@tkjelectronics.com
00016  */
00017 
00018 #include "SPP.h"
00019 // To enable serial debugging see "settings.h"
00020 //#define EXTRADEBUG // Uncomment to get even more debugging data
00021 //#define PRINTREPORT // Uncomment to print the report sent to the Arduino
00022 
00023 /*
00024  * CRC (reversed crc) lookup table as calculated by the table generator in ETSI TS 101 369 V6.3.0.
00025  */
00026 const uint8_t rfcomm_crc_table[256] PROGMEM = {/* reversed, 8-bit, poly=0x07 */
00027         0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
00028         0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
00029         0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
00030         0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
00031         0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
00032         0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
00033         0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
00034         0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
00035         0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
00036         0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
00037         0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
00038         0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
00039         0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
00040         0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
00041         0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
00042         0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
00043 };
00044 
00045 SPP::SPP(BTD *p, const char* name, const char* pin) :
00046 BluetoothService(p) // Pointer to BTD class instance - mandatory
00047 {
00048         pBtd->btdName = name;
00049         pBtd->btdPin = pin;
00050 
00051         /* Set device cid for the SDP and RFCOMM channelse */
00052         sdp_dcid[0] = 0x50; // 0x0050
00053         sdp_dcid[1] = 0x00;
00054         rfcomm_dcid[0] = 0x51; // 0x0051
00055         rfcomm_dcid[1] = 0x00;
00056 
00057         Reset();
00058 }
00059 
00060 void SPP::Reset() {
00061         connected = false;
00062         RFCOMMConnected = false;
00063         SDPConnected = false;
00064         waitForLastCommand = false;
00065         l2cap_sdp_state = L2CAP_SDP_WAIT;
00066         l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT;
00067         l2cap_event_flag = 0;
00068         sppIndex = 0;
00069         creditSent = false;
00070 }
00071 
00072 void SPP::disconnect() {
00073         connected = false;
00074         // First the two L2CAP channels has to be disconnected and then the HCI connection
00075         if(RFCOMMConnected)
00076                 pBtd->l2cap_disconnection_request(hci_handle, ++identifier, rfcomm_scid, rfcomm_dcid);
00077         if(RFCOMMConnected && SDPConnected)
00078                 wait_ms(1); // Add delay between commands
00079         if(SDPConnected)
00080                 pBtd->l2cap_disconnection_request(hci_handle, ++identifier, sdp_scid, sdp_dcid);
00081         l2cap_sdp_state = L2CAP_DISCONNECT_RESPONSE;
00082 }
00083 
00084 void SPP::ACLData(uint8_t* l2capinbuf) {
00085         if(!connected) {
00086                 if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
00087                         if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM && !pBtd->sdpConnectionClaimed) {
00088                                 pBtd->sdpConnectionClaimed = true;
00089                                 hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
00090                                 l2cap_sdp_state = L2CAP_SDP_WAIT; // Reset state
00091                         } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == RFCOMM_PSM && !pBtd->rfcommConnectionClaimed) {
00092                                 pBtd->rfcommConnectionClaimed = true;
00093                                 hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
00094                                 l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT; // Reset state
00095                         }
00096                 }
00097         }
00098 
00099         if(checkHciHandle(l2capinbuf, hci_handle)) { // acl_handle_ok
00100                 if((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001U) { // l2cap_control - Channel ID for ACL-U
00101                         if(l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
00102 #ifdef DEBUG_USB_HOST
00103                                 Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
00104                                 D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
00105                                 Notify(PSTR(" "), 0x80);
00106                                 D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
00107                                 Notify(PSTR(" Data: "), 0x80);
00108                                 D_PrintHex<uint8_t > (l2capinbuf[17], 0x80);
00109                                 Notify(PSTR(" "), 0x80);
00110                                 D_PrintHex<uint8_t > (l2capinbuf[16], 0x80);
00111                                 Notify(PSTR(" "), 0x80);
00112                                 D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
00113                                 Notify(PSTR(" "), 0x80);
00114                                 D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
00115 #endif
00116                         } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
00117 #ifdef EXTRADEBUG
00118                                 Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
00119                                 D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
00120                                 Notify(PSTR(" "), 0x80);
00121                                 D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
00122                                 Notify(PSTR(" SCID: "), 0x80);
00123                                 D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
00124                                 Notify(PSTR(" "), 0x80);
00125                                 D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
00126                                 Notify(PSTR(" Identifier: "), 0x80);
00127                                 D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
00128 #endif
00129                                 if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM) { // It doesn't matter if it receives another reqeust, since it waits for the channel to disconnect in the L2CAP_SDP_DONE state, and the l2cap_event_flag will be cleared if so
00130                                         identifier = l2capinbuf[9];
00131                                         sdp_scid[0] = l2capinbuf[14];
00132                                         sdp_scid[1] = l2capinbuf[15];
00133                                         l2cap_set_flag(L2CAP_FLAG_CONNECTION_SDP_REQUEST);
00134                                 } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == RFCOMM_PSM) { // ----- || -----
00135                                         identifier = l2capinbuf[9];
00136                                         rfcomm_scid[0] = l2capinbuf[14];
00137                                         rfcomm_scid[1] = l2capinbuf[15];
00138                                         l2cap_set_flag(L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST);
00139                                 }
00140                         } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
00141                                 if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
00142                                         if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
00143                                                 //Notify(PSTR("\r\nSDP Configuration Complete"), 0x80);
00144                                                 l2cap_set_flag(L2CAP_FLAG_CONFIG_SDP_SUCCESS);
00145                                         } else if(l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) {
00146                                                 //Notify(PSTR("\r\nRFCOMM Configuration Complete"), 0x80);
00147                                                 l2cap_set_flag(L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS);
00148                                         }
00149                                 }
00150                         } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
00151                                 if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
00152                                         //Notify(PSTR("\r\nSDP Configuration Request"), 0x80);
00153                                         pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], sdp_scid);
00154                                 } else if(l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) {
00155                                         //Notify(PSTR("\r\nRFCOMM Configuration Request"), 0x80);
00156                                         pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], rfcomm_scid);
00157                                 }
00158                         } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
00159                                 if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
00160                                         //Notify(PSTR("\r\nDisconnect Request: SDP Channel"), 0x80);
00161                                         identifier = l2capinbuf[9];
00162                                         l2cap_set_flag(L2CAP_FLAG_DISCONNECT_SDP_REQUEST);
00163                                 } else if(l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) {
00164                                         //Notify(PSTR("\r\nDisconnect Request: RFCOMM Channel"), 0x80);
00165                                         identifier = l2capinbuf[9];
00166                                         l2cap_set_flag(L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST);
00167                                 }
00168                         } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) {
00169                                 if(l2capinbuf[12] == sdp_scid[0] && l2capinbuf[13] == sdp_scid[1]) {
00170                                         //Notify(PSTR("\r\nDisconnect Response: SDP Channel"), 0x80);
00171                                         identifier = l2capinbuf[9];
00172                                         l2cap_set_flag(L2CAP_FLAG_DISCONNECT_RESPONSE);
00173                                 } else if(l2capinbuf[12] == rfcomm_scid[0] && l2capinbuf[13] == rfcomm_scid[1]) {
00174                                         //Notify(PSTR("\r\nDisconnect Response: RFCOMM Channel"), 0x80);
00175                                         identifier = l2capinbuf[9];
00176                                         l2cap_set_flag(L2CAP_FLAG_DISCONNECT_RESPONSE);
00177                                 }
00178                         } else if(l2capinbuf[8] == L2CAP_CMD_INFORMATION_REQUEST) {
00179 #ifdef DEBUG_USB_HOST
00180                                 Notify(PSTR("\r\nInformation request"), 0x80);
00181 #endif
00182                                 identifier = l2capinbuf[9];
00183                                 pBtd->l2cap_information_response(hci_handle, identifier, l2capinbuf[12], l2capinbuf[13]);
00184                         }
00185 #ifdef EXTRADEBUG
00186                         else {
00187                                 Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
00188                                 D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
00189                         }
00190 #endif
00191                 } else if(l2capinbuf[6] == sdp_dcid[0] && l2capinbuf[7] == sdp_dcid[1]) { // SDP
00192                         if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU) {
00193                                 if(((l2capinbuf[16] << 8 | l2capinbuf[17]) == SERIALPORT_UUID) || ((l2capinbuf[16] << 8 | l2capinbuf[17]) == 0x0000 && (l2capinbuf[18] << 8 | l2capinbuf[19]) == SERIALPORT_UUID)) { // Check if it's sending the full UUID, see: https://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm, we will just check the first four bytes
00194                                         if(firstMessage) {
00195                                                 serialPortResponse1(l2capinbuf[9], l2capinbuf[10]);
00196                                                 firstMessage = false;
00197                                         } else {
00198                                                 serialPortResponse2(l2capinbuf[9], l2capinbuf[10]); // Serialport continuation state
00199                                                 firstMessage = true;
00200                                         }
00201                                 } else if(((l2capinbuf[16] << 8 | l2capinbuf[17]) == L2CAP_UUID) || ((l2capinbuf[16] << 8 | l2capinbuf[17]) == 0x0000 && (l2capinbuf[18] << 8 | l2capinbuf[19]) == L2CAP_UUID)) {
00202                                         if(firstMessage) {
00203                                                 l2capResponse1(l2capinbuf[9], l2capinbuf[10]);
00204                                                 firstMessage = false;
00205                                         } else {
00206                                                 l2capResponse2(l2capinbuf[9], l2capinbuf[10]); // L2CAP continuation state
00207                                                 firstMessage = true;
00208                                         }
00209                                 } else
00210                                         serviceNotSupported(l2capinbuf[9], l2capinbuf[10]); // The service is not supported
00211 #ifdef EXTRADEBUG
00212                                 Notify(PSTR("\r\nUUID: "), 0x80);
00213                                 uint16_t uuid;
00214                                 if((l2capinbuf[16] << 8 | l2capinbuf[17]) == 0x0000) // Check if it's sending the UUID as a 128-bit UUID
00215                                         uuid = (l2capinbuf[18] << 8 | l2capinbuf[19]);
00216                                 else // Short UUID
00217                                         uuid = (l2capinbuf[16] << 8 | l2capinbuf[17]);
00218                                 D_PrintHex<uint16_t > (uuid, 0x80);
00219 
00220                                 Notify(PSTR("\r\nLength: "), 0x80);
00221                                 uint16_t length = l2capinbuf[11] << 8 | l2capinbuf[12];
00222                                 D_PrintHex<uint16_t > (length, 0x80);
00223                                 Notify(PSTR("\r\nData: "), 0x80);
00224                                 for(uint8_t i = 0; i < length; i++) {
00225                                         D_PrintHex<uint8_t > (l2capinbuf[13 + i], 0x80);
00226                                         Notify(PSTR(" "), 0x80);
00227                                 }
00228 #endif
00229                         }
00230 #ifdef EXTRADEBUG
00231                         else {
00232                                 Notify(PSTR("\r\nUnknown PDU: "), 0x80);
00233                                 D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
00234                         }
00235 #endif
00236                 } else if(l2capinbuf[6] == rfcomm_dcid[0] && l2capinbuf[7] == rfcomm_dcid[1]) { // RFCOMM
00237                         rfcommChannel = l2capinbuf[8] & 0xF8;
00238                         rfcommDirection = l2capinbuf[8] & 0x04;
00239                         rfcommCommandResponse = l2capinbuf[8] & 0x02;
00240                         rfcommChannelType = l2capinbuf[9] & 0xEF;
00241                         rfcommPfBit = l2capinbuf[9] & 0x10;
00242 
00243                         if(rfcommChannel >> 3 != 0x00)
00244                                 rfcommChannelConnection = rfcommChannel;
00245 
00246 #ifdef EXTRADEBUG
00247                         Notify(PSTR("\r\nRFCOMM Channel: "), 0x80);
00248                         D_PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
00249                         Notify(PSTR(" Direction: "), 0x80);
00250                         D_PrintHex<uint8_t > (rfcommDirection >> 2, 0x80);
00251                         Notify(PSTR(" CommandResponse: "), 0x80);
00252                         D_PrintHex<uint8_t > (rfcommCommandResponse >> 1, 0x80);
00253                         Notify(PSTR(" ChannelType: "), 0x80);
00254                         D_PrintHex<uint8_t > (rfcommChannelType, 0x80);
00255                         Notify(PSTR(" PF_BIT: "), 0x80);
00256                         D_PrintHex<uint8_t > (rfcommPfBit, 0x80);
00257 #endif
00258                         if(rfcommChannelType == RFCOMM_DISC) {
00259 #ifdef DEBUG_USB_HOST
00260                                 Notify(PSTR("\r\nReceived Disconnect RFCOMM Command on channel: "), 0x80);
00261                                 D_PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
00262 #endif
00263                                 connected = false;
00264                                 sendRfcomm(rfcommChannel, rfcommDirection, rfcommCommandResponse, RFCOMM_UA, rfcommPfBit, rfcommbuf, 0x00); // UA Command
00265                         }
00266                         if(connected) {
00267                                 /* Read the incoming message */
00268                                 if(rfcommChannelType == RFCOMM_UIH && rfcommChannel == rfcommChannelConnection) {
00269                                         uint8_t length = l2capinbuf[10] >> 1; // Get length
00270                                         uint8_t offset = l2capinbuf[4] - length - 4; // Check if there is credit
00271                                         if(checkFcs(&l2capinbuf[8], l2capinbuf[11 + length + offset])) {
00272                                                 uint8_t i = 0;
00273                                                 for(; i < length; i++) {
00274                                                         if(rfcommAvailable + i >= sizeof (rfcommDataBuffer)) {
00275 #ifdef DEBUG_USB_HOST
00276                                                                 Notify(PSTR("\r\nWarning: Buffer is full!"), 0x80);
00277 #endif
00278                                                                 break;
00279                                                         }
00280                                                         rfcommDataBuffer[rfcommAvailable + i] = l2capinbuf[11 + i + offset];
00281                                                 }
00282                                                 rfcommAvailable += i;
00283 #ifdef EXTRADEBUG
00284                                                 Notify(PSTR("\r\nRFCOMM Data Available: "), 0x80);
00285                                                 Notify(rfcommAvailable, 0x80);
00286                                                 if(offset) {
00287                                                         Notify(PSTR(" - Credit: 0x"), 0x80);
00288                                                         D_PrintHex<uint8_t > (l2capinbuf[11], 0x80);
00289                                                 }
00290 #endif
00291                                         }
00292 #ifdef DEBUG_USB_HOST
00293                                         else
00294                                                 Notify(PSTR("\r\nError in FCS checksum!"), 0x80);
00295 #endif
00296 #ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send to the Arduino via Bluetooth
00297                                         for(uint8_t i = 0; i < length; i++)
00298                                                 Notifyc(l2capinbuf[i + 11 + offset], 0x80);
00299 #endif
00300                                 } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_RPN_CMD) { // UIH Remote Port Negotiation Command
00301 #ifdef DEBUG_USB_HOST
00302                                         Notify(PSTR("\r\nReceived UIH Remote Port Negotiation Command"), 0x80);
00303 #endif
00304                                         rfcommbuf[0] = BT_RFCOMM_RPN_RSP; // Command
00305                                         rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1
00306                                         rfcommbuf[2] = l2capinbuf[13]; // Channel: channel << 1 | 1
00307                                         rfcommbuf[3] = l2capinbuf[14]; // Pre difined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
00308                                         rfcommbuf[4] = l2capinbuf[15]; // Priority
00309                                         rfcommbuf[5] = l2capinbuf[16]; // Timer
00310                                         rfcommbuf[6] = l2capinbuf[17]; // Max Fram Size LSB
00311                                         rfcommbuf[7] = l2capinbuf[18]; // Max Fram Size MSB
00312                                         rfcommbuf[8] = l2capinbuf[19]; // MaxRatransm.
00313                                         rfcommbuf[9] = l2capinbuf[20]; // Number of Frames
00314                                         sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A); // UIH Remote Port Negotiation Response
00315                                 } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_CMD) { // UIH Modem Status Command
00316 #ifdef DEBUG_USB_HOST
00317                                         Notify(PSTR("\r\nSend UIH Modem Status Response"), 0x80);
00318 #endif
00319                                         rfcommbuf[0] = BT_RFCOMM_MSC_RSP; // UIH Modem Status Response
00320                                         rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1
00321                                         rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3)
00322                                         rfcommbuf[3] = l2capinbuf[14];
00323                                         sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04);
00324                                 }
00325                         } else {
00326                                 if(rfcommChannelType == RFCOMM_SABM) { // SABM Command - this is sent twice: once for channel 0 and then for the channel to establish
00327 #ifdef DEBUG_USB_HOST
00328                                         Notify(PSTR("\r\nReceived SABM Command"), 0x80);
00329 #endif
00330                                         sendRfcomm(rfcommChannel, rfcommDirection, rfcommCommandResponse, RFCOMM_UA, rfcommPfBit, rfcommbuf, 0x00); // UA Command
00331                                 } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_PN_CMD) { // UIH Parameter Negotiation Command
00332 #ifdef DEBUG_USB_HOST
00333                                         Notify(PSTR("\r\nReceived UIH Parameter Negotiation Command"), 0x80);
00334 #endif
00335                                         rfcommbuf[0] = BT_RFCOMM_PN_RSP; // UIH Parameter Negotiation Response
00336                                         rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1
00337                                         rfcommbuf[2] = l2capinbuf[13]; // Channel: channel << 1 | 1
00338                                         rfcommbuf[3] = 0xE0; // Pre difined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
00339                                         rfcommbuf[4] = 0x00; // Priority
00340                                         rfcommbuf[5] = 0x00; // Timer
00341                                         rfcommbuf[6] = BULK_MAXPKTSIZE - 14; // Max Fram Size LSB - set to the size of received data (50)
00342                                         rfcommbuf[7] = 0x00; // Max Fram Size MSB
00343                                         rfcommbuf[8] = 0x00; // MaxRatransm.
00344                                         rfcommbuf[9] = 0x00; // Number of Frames
00345                                         sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A);
00346                                 } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_CMD) { // UIH Modem Status Command
00347 #ifdef DEBUG_USB_HOST
00348                                         Notify(PSTR("\r\nSend UIH Modem Status Response"), 0x80);
00349 #endif
00350                                         rfcommbuf[0] = BT_RFCOMM_MSC_RSP; // UIH Modem Status Response
00351                                         rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1
00352                                         rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3)
00353                                         rfcommbuf[3] = l2capinbuf[14];
00354                                         sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04);
00355 
00356                                         wait_ms(1);
00357 #ifdef DEBUG_USB_HOST
00358                                         Notify(PSTR("\r\nSend UIH Modem Status Command"), 0x80);
00359 #endif
00360                                         rfcommbuf[0] = BT_RFCOMM_MSC_CMD; // UIH Modem Status Command
00361                                         rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1
00362                                         rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3)
00363                                         rfcommbuf[3] = 0x8D; // Can receive frames (YES), Ready to Communicate (YES), Ready to Receive (YES), Incomig Call (NO), Data is Value (YES)
00364 
00365                                         sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04);
00366                                 } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_RSP) { // UIH Modem Status Response
00367                                         if(!creditSent) {
00368 #ifdef DEBUG_USB_HOST
00369                                                 Notify(PSTR("\r\nSend UIH Command with credit"), 0x80);
00370 #endif
00371                                                 sendRfcommCredit(rfcommChannelConnection, rfcommDirection, 0, RFCOMM_UIH, 0x10, sizeof (rfcommDataBuffer)); // Send credit
00372                                                 creditSent = true;
00373                                                 timer = (uint32_t)millis();
00374                                                 waitForLastCommand = true;
00375                                         }
00376                                 } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[10] == 0x01) { // UIH Command with credit
00377 #ifdef DEBUG_USB_HOST
00378                                         Notify(PSTR("\r\nReceived UIH Command with credit"), 0x80);
00379 #endif
00380                                 } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_RPN_CMD) { // UIH Remote Port Negotiation Command
00381 #ifdef DEBUG_USB_HOST
00382                                         Notify(PSTR("\r\nReceived UIH Remote Port Negotiation Command"), 0x80);
00383 #endif
00384                                         rfcommbuf[0] = BT_RFCOMM_RPN_RSP; // Command
00385                                         rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1
00386                                         rfcommbuf[2] = l2capinbuf[13]; // Channel: channel << 1 | 1
00387                                         rfcommbuf[3] = l2capinbuf[14]; // Pre difined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
00388                                         rfcommbuf[4] = l2capinbuf[15]; // Priority
00389                                         rfcommbuf[5] = l2capinbuf[16]; // Timer
00390                                         rfcommbuf[6] = l2capinbuf[17]; // Max Fram Size LSB
00391                                         rfcommbuf[7] = l2capinbuf[18]; // Max Fram Size MSB
00392                                         rfcommbuf[8] = l2capinbuf[19]; // MaxRatransm.
00393                                         rfcommbuf[9] = l2capinbuf[20]; // Number of Frames
00394                                         sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A); // UIH Remote Port Negotiation Response
00395 #ifdef DEBUG_USB_HOST
00396                                         Notify(PSTR("\r\nRFCOMM Connection is now established\r\n"), 0x80);
00397 #endif
00398                                         onInit();
00399                                 }
00400 #ifdef EXTRADEBUG
00401                                 else if(rfcommChannelType != RFCOMM_DISC) {
00402                                         Notify(PSTR("\r\nUnsupported RFCOMM Data - ChannelType: "), 0x80);
00403                                         D_PrintHex<uint8_t > (rfcommChannelType, 0x80);
00404                                         Notify(PSTR(" Command: "), 0x80);
00405                                         D_PrintHex<uint8_t > (l2capinbuf[11], 0x80);
00406                                 }
00407 #endif
00408                         }
00409                 }
00410 #ifdef EXTRADEBUG
00411                 else {
00412                         Notify(PSTR("\r\nUnsupported L2CAP Data - Channel ID: "), 0x80);
00413                         D_PrintHex<uint8_t > (l2capinbuf[7], 0x80);
00414                         Notify(PSTR(" "), 0x80);
00415                         D_PrintHex<uint8_t > (l2capinbuf[6], 0x80);
00416                 }
00417 #endif
00418                 SDP_task();
00419                 RFCOMM_task();
00420         }
00421 }
00422 
00423 void SPP::Run() {
00424         if(waitForLastCommand && (int32_t)((uint32_t)millis() - timer) > 100) { // We will only wait 100ms and see if the UIH Remote Port Negotiation Command is send, as some deviced don't send it
00425 #ifdef DEBUG_USB_HOST
00426                 Notify(PSTR("\r\nRFCOMM Connection is now established - Automatic\r\n"), 0x80);
00427 #endif
00428                 onInit();
00429         }
00430         send(); // Send all bytes currently in the buffer
00431 }
00432 
00433 void SPP::onInit() {
00434         creditSent = false;
00435         waitForLastCommand = false;
00436         connected = true; // The RFCOMM channel is now established
00437         sppIndex = 0;
00438         if(pFuncOnInit)
00439                 pFuncOnInit(); // Call the user function
00440 };
00441 
00442 void SPP::SDP_task() {
00443         switch(l2cap_sdp_state) {
00444                 case L2CAP_SDP_WAIT:
00445                         if(l2cap_check_flag(L2CAP_FLAG_CONNECTION_SDP_REQUEST)) {
00446                                 l2cap_clear_flag(L2CAP_FLAG_CONNECTION_SDP_REQUEST); // Clear flag
00447 #ifdef DEBUG_USB_HOST
00448                                 Notify(PSTR("\r\nSDP Incoming Connection Request"), 0x80);
00449 #endif
00450                                 pBtd->l2cap_connection_response(hci_handle, identifier, sdp_dcid, sdp_scid, PENDING);
00451                                 wait_ms(1);
00452                                 pBtd->l2cap_connection_response(hci_handle, identifier, sdp_dcid, sdp_scid, SUCCESSFUL);
00453                                 identifier++;
00454                                 wait_ms(1);
00455                                 pBtd->l2cap_config_request(hci_handle, identifier, sdp_scid);
00456                                 l2cap_sdp_state = L2CAP_SDP_SUCCESS;
00457                         } else if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_SDP_REQUEST)) {
00458                                 l2cap_clear_flag(L2CAP_FLAG_DISCONNECT_SDP_REQUEST); // Clear flag
00459                                 SDPConnected = false;
00460 #ifdef DEBUG_USB_HOST
00461                                 Notify(PSTR("\r\nDisconnected SDP Channel"), 0x80);
00462 #endif
00463                                 pBtd->l2cap_disconnection_response(hci_handle, identifier, sdp_dcid, sdp_scid);
00464                         }
00465                         break;
00466                 case L2CAP_SDP_SUCCESS:
00467                         if(l2cap_check_flag(L2CAP_FLAG_CONFIG_SDP_SUCCESS)) {
00468                                 l2cap_clear_flag(L2CAP_FLAG_CONFIG_SDP_SUCCESS); // Clear flag
00469 #ifdef DEBUG_USB_HOST
00470                                 Notify(PSTR("\r\nSDP Successfully Configured"), 0x80);
00471 #endif
00472                                 firstMessage = true; // Reset bool
00473                                 SDPConnected = true;
00474                                 l2cap_sdp_state = L2CAP_SDP_WAIT;
00475                         }
00476                         break;
00477 
00478                 case L2CAP_DISCONNECT_RESPONSE: // This is for both disconnection response from the RFCOMM and SDP channel if they were connected
00479                         if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_RESPONSE)) {
00480 #ifdef DEBUG_USB_HOST
00481                                 Notify(PSTR("\r\nDisconnected L2CAP Connection"), 0x80);
00482 #endif
00483                                 pBtd->hci_disconnect(hci_handle);
00484                                 hci_handle = -1; // Reset handle
00485                                 Reset();
00486                         }
00487                         break;
00488         }
00489 }
00490 
00491 void SPP::RFCOMM_task() {
00492         switch(l2cap_rfcomm_state) {
00493                 case L2CAP_RFCOMM_WAIT:
00494                         if(l2cap_check_flag(L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST)) {
00495                                 l2cap_clear_flag(L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST); // Clear flag
00496 #ifdef DEBUG_USB_HOST
00497                                 Notify(PSTR("\r\nRFCOMM Incoming Connection Request"), 0x80);
00498 #endif
00499                                 pBtd->l2cap_connection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid, PENDING);
00500                                 wait_ms(1);
00501                                 pBtd->l2cap_connection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid, SUCCESSFUL);
00502                                 identifier++;
00503                                 wait_ms(1);
00504                                 pBtd->l2cap_config_request(hci_handle, identifier, rfcomm_scid);
00505                                 l2cap_rfcomm_state = L2CAP_RFCOMM_SUCCESS;
00506                         } else if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST)) {
00507                                 l2cap_clear_flag(L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST); // Clear flag
00508                                 RFCOMMConnected = false;
00509                                 connected = false;
00510 #ifdef DEBUG_USB_HOST
00511                                 Notify(PSTR("\r\nDisconnected RFCOMM Channel"), 0x80);
00512 #endif
00513                                 pBtd->l2cap_disconnection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid);
00514                         }
00515                         break;
00516                 case L2CAP_RFCOMM_SUCCESS:
00517                         if(l2cap_check_flag(L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS)) {
00518                                 l2cap_clear_flag(L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS); // Clear flag
00519 #ifdef DEBUG_USB_HOST
00520                                 Notify(PSTR("\r\nRFCOMM Successfully Configured"), 0x80);
00521 #endif
00522                                 rfcommAvailable = 0; // Reset number of bytes available
00523                                 bytesRead = 0; // Reset number of bytes received
00524                                 RFCOMMConnected = true;
00525                                 l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT;
00526                         }
00527                         break;
00528         }
00529 }
00530 /************************************************************/
00531 /*                    SDP Commands                          */
00532 
00533 /************************************************************/
00534 void SPP::SDP_Command(uint8_t* data, uint8_t nbytes) { // See page 223 in the Bluetooth specs
00535         pBtd->L2CAP_Command(hci_handle, data, nbytes, sdp_scid[0], sdp_scid[1]);
00536 }
00537 
00538 void SPP::serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow) { // See page 235 in the Bluetooth specs
00539         l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU;
00540         l2capoutbuf[1] = transactionIDHigh;
00541         l2capoutbuf[2] = transactionIDLow;
00542         l2capoutbuf[3] = 0x00; // MSB Parameter Length
00543         l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
00544         l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount
00545         l2capoutbuf[6] = 0x02; // LSB AttributeListsByteCount = 2
00546 
00547         /* Attribute ID/Value Sequence: */
00548         l2capoutbuf[7] = 0x35; // Data element sequence - length in next byte
00549         l2capoutbuf[8] = 0x00; // Length = 0
00550         l2capoutbuf[9] = 0x00; // No continuation state
00551 
00552         SDP_Command(l2capoutbuf, 10);
00553 }
00554 
00555 void SPP::serialPortResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
00556         l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU;
00557         l2capoutbuf[1] = transactionIDHigh;
00558         l2capoutbuf[2] = transactionIDLow;
00559         l2capoutbuf[3] = 0x00; // MSB Parameter Length
00560         l2capoutbuf[4] = 0x2B; // LSB Parameter Length = 43
00561         l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount
00562         l2capoutbuf[6] = 0x26; // LSB AttributeListsByteCount = 38
00563 
00564         /* Attribute ID/Value Sequence: */
00565         l2capoutbuf[7] = 0x36; // Data element sequence - length in next two bytes
00566         l2capoutbuf[8] = 0x00; // MSB Length
00567         l2capoutbuf[9] = 0x3C; // LSB Length = 60
00568 
00569         l2capoutbuf[10] = 0x36; // Data element sequence - length in next two bytes
00570         l2capoutbuf[11] = 0x00; // MSB Length
00571         l2capoutbuf[12] = 0x39; // LSB Length = 57
00572 
00573         l2capoutbuf[13] = 0x09; // Unsigned Integer - length 2 bytes
00574         l2capoutbuf[14] = 0x00; // MSB ServiceRecordHandle
00575         l2capoutbuf[15] = 0x00; // LSB ServiceRecordHandle
00576         l2capoutbuf[16] = 0x0A; // Unsigned int - length 4 bytes
00577         l2capoutbuf[17] = 0x00; // ServiceRecordHandle value - TODO: Is this related to HCI_Handle?
00578         l2capoutbuf[18] = 0x01;
00579         l2capoutbuf[19] = 0x00;
00580         l2capoutbuf[20] = 0x06;
00581 
00582         l2capoutbuf[21] = 0x09; // Unsigned Integer - length 2 bytes
00583         l2capoutbuf[22] = 0x00; // MSB ServiceClassIDList
00584         l2capoutbuf[23] = 0x01; // LSB ServiceClassIDList
00585         l2capoutbuf[24] = 0x35; // Data element sequence - length in next byte
00586         l2capoutbuf[25] = 0x03; // Length = 3
00587         l2capoutbuf[26] = 0x19; // UUID (universally unique identifier) - length = 2 bytes
00588         l2capoutbuf[27] = 0x11; // MSB SerialPort
00589         l2capoutbuf[28] = 0x01; // LSB SerialPort
00590 
00591         l2capoutbuf[29] = 0x09; // Unsigned Integer - length 2 bytes
00592         l2capoutbuf[30] = 0x00; // MSB ProtocolDescriptorList
00593         l2capoutbuf[31] = 0x04; // LSB ProtocolDescriptorList
00594         l2capoutbuf[32] = 0x35; // Data element sequence - length in next byte
00595         l2capoutbuf[33] = 0x0C; // Length = 12
00596 
00597         l2capoutbuf[34] = 0x35; // Data element sequence - length in next byte
00598         l2capoutbuf[35] = 0x03; // Length = 3
00599         l2capoutbuf[36] = 0x19; // UUID (universally unique identifier) - length = 2 bytes
00600         l2capoutbuf[37] = 0x01; // MSB L2CAP
00601         l2capoutbuf[38] = 0x00; // LSB L2CAP
00602 
00603         l2capoutbuf[39] = 0x35; // Data element sequence - length in next byte
00604         l2capoutbuf[40] = 0x05; // Length = 5
00605         l2capoutbuf[41] = 0x19; // UUID (universally unique identifier) - length = 2 bytes
00606         l2capoutbuf[42] = 0x00; // MSB RFCOMM
00607         l2capoutbuf[43] = 0x03; // LSB RFCOMM
00608         l2capoutbuf[44] = 0x08; // Unsigned Integer - length 1 byte
00609 
00610         l2capoutbuf[45] = 0x02; // ContinuationState - Two more bytes
00611         l2capoutbuf[46] = 0x00; // MSB length
00612         l2capoutbuf[47] = 0x19; // LSB length = 25 more bytes to come
00613 
00614         SDP_Command(l2capoutbuf, 48);
00615 }
00616 
00617 void SPP::serialPortResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
00618         l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU;
00619         l2capoutbuf[1] = transactionIDHigh;
00620         l2capoutbuf[2] = transactionIDLow;
00621         l2capoutbuf[3] = 0x00; // MSB Parameter Length
00622         l2capoutbuf[4] = 0x1C; // LSB Parameter Length = 28
00623         l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount
00624         l2capoutbuf[6] = 0x19; // LSB AttributeListsByteCount = 25
00625 
00626         /* Attribute ID/Value Sequence: */
00627         l2capoutbuf[7] = 0x01; // Channel 1 - TODO: Try different values, so multiple servers can be used at once
00628 
00629         l2capoutbuf[8] = 0x09; // Unsigned Integer - length 2 bytes
00630         l2capoutbuf[9] = 0x00; // MSB LanguageBaseAttributeIDList
00631         l2capoutbuf[10] = 0x06; // LSB LanguageBaseAttributeIDList
00632         l2capoutbuf[11] = 0x35; // Data element sequence - length in next byte
00633         l2capoutbuf[12] = 0x09; // Length = 9
00634 
00635         // Identifier representing the natural language = en = English - see: "ISO 639:1988"
00636         l2capoutbuf[13] = 0x09; // Unsigned Integer - length 2 bytes
00637         l2capoutbuf[14] = 0x65; // 'e'
00638         l2capoutbuf[15] = 0x6E; // 'n'
00639 
00640         // "The second element of each triplet contains an identifier that specifies a character encoding used for the language"
00641         // Encoding is set to 106 (UTF-8) - see: http://www.iana.org/assignments/character-sets/character-sets.xhtml
00642         l2capoutbuf[16] = 0x09; // Unsigned Integer - length 2 bytes
00643         l2capoutbuf[17] = 0x00; // MSB of character encoding
00644         l2capoutbuf[18] = 0x6A; // LSB of character encoding (106)
00645 
00646         // Attribute ID that serves as the base attribute ID for the natural language in the service record
00647         // "To facilitate the retrieval of human-readable universal attributes in a principal language, the base attribute ID value for the primary language supported by a service record shall be 0x0100"
00648         l2capoutbuf[19] = 0x09; // Unsigned Integer - length 2 bytes
00649         l2capoutbuf[20] = 0x01;
00650         l2capoutbuf[21] = 0x00;
00651 
00652         l2capoutbuf[22] = 0x09; // Unsigned Integer - length 2 bytes
00653         l2capoutbuf[23] = 0x01; // MSB ServiceDescription
00654         l2capoutbuf[24] = 0x00; // LSB ServiceDescription
00655 
00656         l2capoutbuf[25] = 0x25; // Text string - length in next byte
00657         l2capoutbuf[26] = 0x05; // Name length
00658         l2capoutbuf[27] = 'T';
00659         l2capoutbuf[28] = 'K';
00660         l2capoutbuf[29] = 'J';
00661         l2capoutbuf[30] = 'S';
00662         l2capoutbuf[31] = 'P';
00663         l2capoutbuf[32] = 0x00; // No continuation state
00664 
00665         SDP_Command(l2capoutbuf, 33);
00666 }
00667 
00668 void SPP::l2capResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
00669         serialPortResponse1(transactionIDHigh, transactionIDLow); // These has to send all the supported functions, since it only supports virtual serialport it just sends the message again
00670 }
00671 
00672 void SPP::l2capResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
00673         serialPortResponse2(transactionIDHigh, transactionIDLow); // Same data as serialPortResponse2
00674 }
00675 /************************************************************/
00676 /*                    RFCOMM Commands                       */
00677 
00678 /************************************************************/
00679 void SPP::RFCOMM_Command(uint8_t* data, uint8_t nbytes) {
00680         pBtd->L2CAP_Command(hci_handle, data, nbytes, rfcomm_scid[0], rfcomm_scid[1]);
00681 }
00682 
00683 void SPP::sendRfcomm(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t* data, uint8_t length) {
00684         l2capoutbuf[0] = channel | direction | CR | extendAddress; // RFCOMM Address
00685         l2capoutbuf[1] = channelType | pfBit; // RFCOMM Control
00686         l2capoutbuf[2] = length << 1 | 0x01; // Length and format (always 0x01 bytes format)
00687         uint8_t i = 0;
00688         for(; i < length; i++)
00689                 l2capoutbuf[i + 3] = data[i];
00690         l2capoutbuf[i + 3] = calcFcs(l2capoutbuf);
00691 #ifdef EXTRADEBUG
00692         Notify(PSTR(" - RFCOMM Data: "), 0x80);
00693         for(i = 0; i < length + 4; i++) {
00694                 D_PrintHex<uint8_t > (l2capoutbuf[i], 0x80);
00695                 Notify(PSTR(" "), 0x80);
00696         }
00697 #endif
00698         RFCOMM_Command(l2capoutbuf, length + 4);
00699 }
00700 
00701 void SPP::sendRfcommCredit(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t credit) {
00702         l2capoutbuf[0] = channel | direction | CR | extendAddress; // RFCOMM Address
00703         l2capoutbuf[1] = channelType | pfBit; // RFCOMM Control
00704         l2capoutbuf[2] = 0x01; // Length = 0
00705         l2capoutbuf[3] = credit; // Credit
00706         l2capoutbuf[4] = calcFcs(l2capoutbuf);
00707 #ifdef EXTRADEBUG
00708         Notify(PSTR(" - RFCOMM Credit Data: "), 0x80);
00709         for(uint8_t i = 0; i < 5; i++) {
00710                 D_PrintHex<uint8_t > (l2capoutbuf[i], 0x80);
00711                 Notify(PSTR(" "), 0x80);
00712         }
00713 #endif
00714         RFCOMM_Command(l2capoutbuf, 5);
00715 }
00716 
00717 /* CRC on 2 bytes */
00718 uint8_t SPP::crc(uint8_t *data) {
00719         return (pgm_read_byte(&rfcomm_crc_table[pgm_read_byte(&rfcomm_crc_table[0xFF ^ data[0]]) ^ data[1]]));
00720 }
00721 
00722 /* Calculate FCS */
00723 uint8_t SPP::calcFcs(uint8_t *data) {
00724         uint8_t temp = crc(data);
00725         if((data[1] & 0xEF) == RFCOMM_UIH)
00726                 return (0xFF - temp); // FCS on 2 bytes
00727         else
00728                 return (0xFF - pgm_read_byte(&rfcomm_crc_table[temp ^ data[2]])); // FCS on 3 bytes
00729 }
00730 
00731 /* Check FCS */
00732 bool SPP::checkFcs(uint8_t *data, uint8_t fcs) {
00733         uint8_t temp = crc(data);
00734         if((data[1] & 0xEF) != RFCOMM_UIH)
00735                 temp = pgm_read_byte(&rfcomm_crc_table[temp ^ data[2]]); // FCS on 3 bytes
00736         return (pgm_read_byte(&rfcomm_crc_table[temp ^ fcs]) == 0xCF);
00737 }
00738 
00739 /* Serial commands */
00740 #if defined(ARDUINO) && ARDUINO >=100
00741 
00742 size_t SPP::write(uint8_t data) {
00743         return write(&data, 1);
00744 }
00745 #else
00746 
00747 void SPP::write(uint8_t data) {
00748         write(&data, 1);
00749 }
00750 #endif
00751 
00752 #if defined(ARDUINO) && ARDUINO >=100
00753 
00754 size_t SPP::write(const uint8_t *data, size_t size) {
00755 #else
00756 
00757 void SPP::write(const uint8_t *data, size_t size) {
00758 #endif
00759         for(uint8_t i = 0; i < size; i++) {
00760                 if(sppIndex >= sizeof (sppOutputBuffer) / sizeof (sppOutputBuffer[0]))
00761                         send(); // Send the current data in the buffer
00762                 sppOutputBuffer[sppIndex++] = data[i]; // All the bytes are put into a buffer and then send using the send() function
00763         }
00764 #if defined(ARDUINO) && ARDUINO >=100
00765         return size;
00766 #endif
00767 }
00768 
00769 void SPP::send() {
00770         if(!connected || !sppIndex)
00771                 return;
00772         uint8_t length; // This is the length of the string we are sending
00773         uint8_t offset = 0; // This is used to keep track of where we are in the string
00774 
00775         l2capoutbuf[0] = rfcommChannelConnection | 0 | 0 | extendAddress; // RFCOMM Address
00776         l2capoutbuf[1] = RFCOMM_UIH; // RFCOMM Control
00777 
00778         while(sppIndex) { // We will run this while loop until this variable is 0
00779                 if(sppIndex > (sizeof (l2capoutbuf) - 4)) // Check if the string is larger than the outgoing buffer
00780                         length = sizeof (l2capoutbuf) - 4;
00781                 else
00782                         length = sppIndex;
00783 
00784                 l2capoutbuf[2] = length << 1 | 1; // Length
00785                 uint8_t i = 0;
00786                 for(; i < length; i++)
00787                         l2capoutbuf[i + 3] = sppOutputBuffer[i + offset];
00788                 l2capoutbuf[i + 3] = calcFcs(l2capoutbuf); // Calculate checksum
00789 
00790                 RFCOMM_Command(l2capoutbuf, length + 4);
00791 
00792                 sppIndex -= length;
00793                 offset += length; // Increment the offset
00794         }
00795 }
00796 
00797 int SPP::available(void) {
00798         return rfcommAvailable;
00799 };
00800 
00801 void SPP::discard(void) {
00802         rfcommAvailable = 0;
00803 }
00804 
00805 int SPP::peek(void) {
00806         if(rfcommAvailable == 0) // Don't read if there is nothing in the buffer
00807                 return -1;
00808         return rfcommDataBuffer[0];
00809 }
00810 
00811 int SPP::read(void) {
00812         if(rfcommAvailable == 0) // Don't read if there is nothing in the buffer
00813                 return -1;
00814         uint8_t output = rfcommDataBuffer[0];
00815         for(uint8_t i = 1; i < rfcommAvailable; i++)
00816                 rfcommDataBuffer[i - 1] = rfcommDataBuffer[i]; // Shift the buffer one left
00817         rfcommAvailable--;
00818         bytesRead++;
00819         if(bytesRead > (sizeof (rfcommDataBuffer) - 5)) { // We will send the command just before it runs out of credit
00820                 bytesRead = 0;
00821                 sendRfcommCredit(rfcommChannelConnection, rfcommDirection, 0, RFCOMM_UIH, 0x10, sizeof (rfcommDataBuffer)); // Send more credit
00822 #ifdef EXTRADEBUG
00823                 Notify(PSTR("\r\nSent "), 0x80);
00824                 Notify((uint8_t)sizeof (rfcommDataBuffer), 0x80);
00825                 Notify(PSTR(" more credit"), 0x80);
00826 #endif
00827         }
00828         return output;
00829 }