Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: UsbHostMAX3421E_Hello
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 }
Generated on Tue Jul 12 2022 18:12:05 by
1.7.2