mirror of
https://github.com/felis/USB_Host_Shield_2.0.git
synced 2024-03-22 11:31:26 +01:00
687 lines
30 KiB
C++
Executable file
687 lines
30 KiB
C++
Executable file
/* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
|
|
|
|
This software may be distributed and modified under the terms of the GNU
|
|
General Public License version 2 (GPL2) as published by the Free Software
|
|
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
|
this file. Please note that GPL2 Section 2[b] requires that all works based
|
|
on this software must also be made publicly available under the terms of
|
|
the GPL2 ("Copyleft").
|
|
|
|
Contact information
|
|
-------------------
|
|
|
|
Kristian Lauszus, TKJ Electronics
|
|
Web : http://www.tkjelectronics.com
|
|
e-mail : kristianl@tkjelectronics.com
|
|
|
|
Enhanced by Dmitry Pakhomenko to initiate connection with remote SPP-aware device
|
|
04.04.2014, Magictale Electronics
|
|
*/
|
|
|
|
|
|
#include "SPPClient.h"
|
|
// To enable serial debugging see "settings.h"
|
|
//#define EXTRADEBUG // Uncomment to get even more debugging data
|
|
//#define PRINTREPORT // Uncomment to print the report sent to the Arduino
|
|
|
|
/*
|
|
* "RFCOMM UUID" signature, a channel number comes immediately after it
|
|
*/
|
|
const uint8_t rfcomm_uuid_sign[6] PROGMEM = { 0x35, 0x05, 0x19, 0x00, 0x03, 0x08 };
|
|
|
|
SPPClient::SPPClient(BTD *p, const char* name, const char* pin, bool pair, uint8_t *addr) :
|
|
SPPBase(p)
|
|
{
|
|
if (pBtd)
|
|
pBtd->registerServiceClass(this); // Register it as a Bluetooth service
|
|
|
|
pBtd->btdName = name;
|
|
pBtd->btdPin = pin;
|
|
|
|
if (addr) // Make sure address is set
|
|
pBtd->pairWithOtherDevice = pair;
|
|
|
|
for (uint8_t i = 0; i < 6; i++)
|
|
pBtd->remote_bdaddr[i] = addr[i];
|
|
|
|
/* Set device cid for the SDP and RFCOMM channels */
|
|
sdp_scid[0] = 0x50; // 0x0050
|
|
sdp_scid[1] = 0x00;
|
|
|
|
rfcomm_scid[0] = 0x51; // 0x0051
|
|
rfcomm_scid[1] = 0x00;
|
|
|
|
Reset();
|
|
}
|
|
|
|
void SPPClient::Reset() {
|
|
connected = false;
|
|
RFCOMMConnected = false;
|
|
SDPConnected = false;
|
|
l2cap_sdp_state = L2CAP_SDP_WAIT;
|
|
l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT;
|
|
sppIndex = 0;
|
|
|
|
rfcomm_uuid_sign_idx = 0;
|
|
rfcomm_found = false;
|
|
}
|
|
|
|
void SPPClient::ACLData(uint8_t *l2capinbuf) {
|
|
|
|
#ifdef EXTRADEBUG
|
|
Notify(PSTR("\r\nIncoming Packet: "), 0x80);
|
|
|
|
for (uint8_t i = 0; i < (l2capinbuf[2] + 4); i++) {
|
|
D_PrintHex<uint8_t > (l2capinbuf[i], 0x80);
|
|
Notify(PSTR(" "), 0x80);
|
|
}
|
|
Notify(PSTR("\r\n"), 0x80);
|
|
#endif
|
|
|
|
//if((l2capinbuf[0] | (uint16_t)l2capinbuf[1] << 8) == (hci_handle | 0x2000U)) { // acl_handle_ok
|
|
if(UHS_ACL_HANDLE_OK(l2capinbuf, hci_handle)) { // acl_handle_ok
|
|
if((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001U) { // l2cap_control - Channel ID for ACL-U
|
|
if (l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
|
|
D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
|
|
Notify(PSTR(" "), 0x80);
|
|
D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
|
|
Notify(PSTR(" Data: "), 0x80);
|
|
D_PrintHex<uint8_t > (l2capinbuf[17], 0x80);
|
|
Notify(PSTR(" "), 0x80);
|
|
D_PrintHex<uint8_t > (l2capinbuf[16], 0x80);
|
|
Notify(PSTR(" "), 0x80);
|
|
D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
|
|
Notify(PSTR(" "), 0x80);
|
|
D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
|
|
#endif
|
|
}else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_RESPONSE) {
|
|
if (((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) && ((l2capinbuf[18] | (l2capinbuf[19] << 8)) == SUCCESSFUL)) { // Success
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nL2CAP Connection Response"), 0x80);
|
|
#endif
|
|
if (l2capinbuf[14] == sdp_scid[0] && l2capinbuf[15] == sdp_scid[1]) {
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nSDP Connection Response"), 0x80);
|
|
#endif
|
|
sdp_dcid[0] = l2capinbuf[12];
|
|
sdp_dcid[1] = l2capinbuf[13];
|
|
|
|
identifier++;
|
|
l2cap_sdp_state = L2CAP_SDP_CONN_RESPONSE;
|
|
} else if (l2capinbuf[14] == rfcomm_scid[0] && l2capinbuf[15] == rfcomm_scid[1]) {
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nRFComm Connection Response"), 0x80);
|
|
#endif
|
|
rfcomm_dcid[0] = l2capinbuf[12];
|
|
rfcomm_dcid[1] = l2capinbuf[13];
|
|
|
|
identifier++;
|
|
l2cap_rfcomm_state = L2CAP_RFCOMM_CONN_RESPONSE;
|
|
}
|
|
}
|
|
} else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
|
|
if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
|
|
if(l2capinbuf[12] == sdp_scid[0] && l2capinbuf[13] == sdp_scid[1]) {
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nSDP Configuration Response Received"), 0x80);
|
|
Notify(PSTR("\r\nSDP Successfully Configured"), 0x80);
|
|
#endif
|
|
l2cap_sdp_state = L2CAP_SDP_SERVICE_SEARCH_ATTR1;
|
|
identifier++;
|
|
SDP_Service_Search_Attr(0, identifier);
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nSDP Service Search Attribute Request 1 Sent"), 0x80);
|
|
#endif
|
|
} else if(l2capinbuf[12] == rfcomm_scid[0] && l2capinbuf[13] == rfcomm_scid[1]) {
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nRFComm Configuration Response Received"), 0x80);
|
|
Notify(PSTR("\r\nRFComm Successfully Configured"), 0x80);
|
|
#endif
|
|
l2cap_sdp_state = L2CAP_RFCOMM_DONE;
|
|
identifier++;
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nRFComm SABM Sent"), 0x80);
|
|
#endif
|
|
rfcommAvailable = 0; // Reset number of bytes available
|
|
bytesRead = 0; // Reset number of bytes received
|
|
RFCOMMConnected = true;
|
|
|
|
// channel direction, CR,channelType, pfBit, data, length
|
|
sendRfcomm(0, 0, (1 << 1), RFCOMM_SABM, (1 << 4), rfcommbuf, 0);
|
|
}
|
|
}
|
|
} else if (l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
|
|
if (l2capinbuf[12] == sdp_scid[0] && l2capinbuf[13] == sdp_scid[1]) {
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nSDP Configuration Request Received"), 0x80);
|
|
#endif
|
|
identifier = l2capinbuf[9];
|
|
pBtd->l2cap_config_response(hci_handle, identifier, sdp_dcid);
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nSDP Configuration Response Sent"), 0x80);
|
|
#endif
|
|
l2cap_sdp_state = L2CAP_SDP_CONFIG_REQUEST;
|
|
identifier++;
|
|
delay(1);
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nSDP Configuration Request Sent"), 0x80);
|
|
#endif
|
|
pBtd->l2cap_config_request(hci_handle, identifier, sdp_dcid);
|
|
|
|
}else if (l2capinbuf[12] == rfcomm_scid[0] && l2capinbuf[13] == rfcomm_scid[1]) {
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nRFComm Configuration Request Received"), 0x80);
|
|
#endif
|
|
identifier = l2capinbuf[9];
|
|
|
|
pBtd->l2cap_config_response(hci_handle, identifier, rfcomm_dcid);
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nRFComm Configuration Response Sent"), 0x80);
|
|
#endif
|
|
l2cap_rfcomm_state = L2CAP_RFCOMM_CONFIG_REQUEST;
|
|
identifier++;
|
|
delay(1);
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nRFComm Configuration Request Sent"), 0x80);
|
|
#endif
|
|
pBtd->l2cap_config_request(hci_handle, identifier, rfcomm_dcid);
|
|
}
|
|
|
|
} else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
|
|
if (l2capinbuf[12] == sdp_scid[0] && l2capinbuf[13] == sdp_scid[1]) {
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nDisconnect Request: SDP Channel"), 0x80);
|
|
#endif
|
|
identifier = l2capinbuf[9];
|
|
|
|
SDPConnected = false;
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nDisconnected SDP Channel"), 0x80);
|
|
#endif
|
|
pBtd->l2cap_disconnection_response(hci_handle, identifier, sdp_scid, sdp_dcid);
|
|
l2cap_sdp_state = L2CAP_SDP_WAIT;
|
|
|
|
}else if (l2capinbuf[12] == rfcomm_scid[0] && l2capinbuf[13] == rfcomm_scid[1]) {
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nDisconnect Request: RFComm Channel"), 0x80);
|
|
#endif
|
|
identifier = l2capinbuf[9];
|
|
|
|
RFCOMMConnected = false;
|
|
connected = false;
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nDisconnected RFComm Channel"), 0x80);
|
|
#endif
|
|
pBtd->l2cap_disconnection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid);
|
|
l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT;
|
|
|
|
}
|
|
} else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) {
|
|
if (l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nDisconnect Response: SDP Channel"), 0x80);
|
|
#endif
|
|
SDPConnected = false;
|
|
l2cap_sdp_state = L2CAP_SDP_WAIT;
|
|
|
|
}else if (l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) {
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nDisconnect Response: RFComm Channel"), 0x80);
|
|
Notify(PSTR("\r\nDisconnected L2CAP Connection"), 0x80);
|
|
#endif
|
|
RFCOMMConnected = false;
|
|
|
|
pBtd->hci_disconnect(hci_handle);
|
|
hci_handle = -1; // Reset handle
|
|
|
|
l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT;
|
|
}
|
|
|
|
} else if (l2capinbuf[8] == L2CAP_CMD_INFORMATION_REQUEST) {
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nInformation request"), 0x80);
|
|
#endif
|
|
identifier = l2capinbuf[9];
|
|
pBtd->l2cap_information_response(hci_handle, identifier, l2capinbuf[12], l2capinbuf[13]);
|
|
}
|
|
else {
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
|
|
D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
|
|
#endif
|
|
}
|
|
} else if (l2capinbuf[6] == sdp_scid[0] && l2capinbuf[7] == sdp_scid[1]) { // SDP
|
|
#ifdef EXTRADEBUG
|
|
Notify(PSTR("\r\nSDP data:"), 0x80);
|
|
#endif
|
|
if (l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU) {
|
|
|
|
if (l2cap_sdp_state == L2CAP_SDP_SERVICE_SEARCH_ATTR1){
|
|
#ifdef EXTRADEBUG
|
|
Notify(PSTR(" - SDP Service Search Attribute Response 1: "), 0x80);
|
|
#endif
|
|
remainingBytes = l2capinbuf[l2capinbuf[2] + 3];
|
|
|
|
parseAttrReply(l2capinbuf);
|
|
|
|
l2cap_sdp_state = L2CAP_SDP_SERVICE_SEARCH_ATTR2;
|
|
identifier++;
|
|
if (remainingBytes) {
|
|
SDP_Service_Search_Attr(0, identifier, remainingBytes);
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nSDP Service Search Attribute Request 2 Sent"), 0x80);
|
|
#endif
|
|
} else {
|
|
l2cap_sdp_state = L2CAP_SDP_DONE;
|
|
|
|
if (rfcomm_found) {
|
|
pBtd->l2cap_connection_request(hci_handle, identifier, rfcomm_scid, RFCOMM_PSM);
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nRFComm Connection Request Sent"), 0x80);
|
|
#endif
|
|
l2cap_rfcomm_state = L2CAP_RFCOMM_REQUEST;
|
|
} else{
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nRFComm Channel Number not found"), 0x80);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
} else if (l2cap_sdp_state == L2CAP_SDP_SERVICE_SEARCH_ATTR2){
|
|
#ifdef EXTRADEBUG
|
|
Notify(PSTR(" - SDP Service Search Attribute Response 2: "), 0x80);
|
|
#endif
|
|
|
|
parseAttrReply(l2capinbuf);
|
|
|
|
l2cap_sdp_state = L2CAP_SDP_DONE;
|
|
identifier++;
|
|
|
|
if (rfcomm_found) {
|
|
pBtd->l2cap_connection_request(hci_handle, identifier, rfcomm_scid, RFCOMM_PSM);
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nRFComm Connection Request Sent"), 0x80);
|
|
#endif
|
|
l2cap_rfcomm_state = L2CAP_RFCOMM_REQUEST;
|
|
}else{
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nRFComm Channel Number not found"), 0x80);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
#ifdef EXTRADEBUG
|
|
Notify(PSTR("\r\nUnknown PDU: "), 0x80);
|
|
D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
|
|
#endif
|
|
}
|
|
|
|
} else if (l2capinbuf[6] == rfcomm_scid[0] && l2capinbuf[7] == rfcomm_scid[1]) { // RFCOMM
|
|
|
|
rfcommChannel = l2capinbuf[8] & 0xF8;
|
|
rfcommDirection = l2capinbuf[8] & 0x04;
|
|
rfcommCommandResponse = l2capinbuf[8] & 0x02;
|
|
rfcommChannelType = l2capinbuf[9] & 0xEF;
|
|
rfcommPfBit = l2capinbuf[9] & 0x10;
|
|
|
|
#ifdef EXTRADEBUG
|
|
Notify(PSTR("\r\nRFComm Channel: "), 0x80);
|
|
D_PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
|
|
Notify(PSTR(" Direction: "), 0x80);
|
|
D_PrintHex<uint8_t > (rfcommDirection >> 2, 0x80);
|
|
Notify(PSTR(" CommandResponse: "), 0x80);
|
|
D_PrintHex<uint8_t > (rfcommCommandResponse >> 1, 0x80);
|
|
Notify(PSTR(" ChannelType: "), 0x80);
|
|
D_PrintHex<uint8_t > (rfcommChannelType, 0x80);
|
|
Notify(PSTR(" PF_BIT: "), 0x80);
|
|
D_PrintHex<uint8_t > (rfcommPfBit >> 4, 0x80);
|
|
#endif
|
|
if (rfcommChannelType == RFCOMM_DISC) {
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nReceived Disconnect RFComm Command on channel: "), 0x80);
|
|
D_PrintHex<uint8_t > (rfcommChannel, 0x80);
|
|
#endif
|
|
connected = false;
|
|
// sendRfcomm(rfcommChannel, rfcommDirection, rfcommCommandResponse, RFCOMM_UA, rfcommPfBit, rfcommbuf, 0x00); // UA Command
|
|
}
|
|
|
|
if (connected)
|
|
{
|
|
/* Read the incoming message */
|
|
if (rfcommChannelType == RFCOMM_UIH && rfcommChannel == (rfcommChannelConnection << 3)) {
|
|
uint8_t length = l2capinbuf[10] >> 1; // Get length
|
|
uint8_t offset = l2capinbuf[4] - length - 4; // Check if there is credit
|
|
if (checkFcs(&l2capinbuf[8], l2capinbuf[11 + length + offset])) {
|
|
uint8_t i = 0;
|
|
for (; i < length; i++) {
|
|
if (rfcommAvailable + i >= sizeof (rfcommDataBuffer)) {
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nWarning: Buffer is full!"), 0x80);
|
|
#endif
|
|
break;
|
|
}
|
|
rfcommDataBuffer[rfcommAvailable + i] = l2capinbuf[11 + i + offset];
|
|
}
|
|
rfcommAvailable += i;
|
|
#ifdef EXTRADEBUG
|
|
Notify(PSTR("\r\nRFCOMM Data Available: "), 0x80);
|
|
Notify(rfcommAvailable, 0x80);
|
|
if (offset) {
|
|
Notify(PSTR(" - Credit: 0x"), 0x80);
|
|
D_PrintHex<uint8_t > (l2capinbuf[11], 0x80);
|
|
}
|
|
#endif
|
|
}
|
|
#ifdef DEBUG_USB_HOST
|
|
else
|
|
Notify(PSTR("\r\nError in FCS checksum!"), 0x80);
|
|
#endif
|
|
#ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send to the Arduino via Bluetooth
|
|
for (uint8_t i = 0; i < length; i++)
|
|
Notifyc(l2capinbuf[i + 11 + offset], 0x80);
|
|
#endif
|
|
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_RPN_CMD) { // UIH Remote Port Negotiation Command
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nReceived UIH Remote Port Negotiation Command"), 0x80);
|
|
#endif
|
|
/* rfcommbuf[0] = BT_RFCOMM_RPN_RSP; // Command
|
|
rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1
|
|
rfcommbuf[2] = l2capinbuf[13]; // Channel: channel << 1 | 1
|
|
rfcommbuf[3] = l2capinbuf[14]; // Pre difined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
|
|
rfcommbuf[4] = l2capinbuf[15]; // Priority
|
|
rfcommbuf[5] = l2capinbuf[16]; // Timer
|
|
rfcommbuf[6] = l2capinbuf[17]; // Max Fram Size LSB
|
|
rfcommbuf[7] = l2capinbuf[18]; // Max Fram Size MSB
|
|
rfcommbuf[8] = l2capinbuf[19]; // MaxRatransm.
|
|
rfcommbuf[9] = l2capinbuf[20]; // Number of Frames
|
|
sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A); // UIH Remote Port Negotiation Response*/
|
|
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_CMD) { // UIH Modem Status Command
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nSend UIH Modem Status Response"), 0x80);
|
|
#endif
|
|
/*rfcommbuf[0] = BT_RFCOMM_MSC_RSP; // UIH Modem Status Response
|
|
rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1
|
|
rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3)
|
|
rfcommbuf[3] = l2capinbuf[14];
|
|
sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04);*/
|
|
}
|
|
}else{
|
|
|
|
if (rfcommChannelType == RFCOMM_SABM) {
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nReceived SAMB RFComm Packet on channel: "), 0x80);
|
|
D_PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
|
|
#endif
|
|
} else if (rfcommChannelType == RFCOMM_UA) {
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nReceived UA RFComm Packet on channel: "), 0x80);
|
|
D_PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
|
|
#endif
|
|
if ((rfcommChannel >> 3) == 0)
|
|
{
|
|
//Reply on 1-st SAMB command on channel 0
|
|
rfcommbuf[0] = BT_RFCOMM_PN_CMD; // UIH Parameter Negotiation Request
|
|
rfcommbuf[1] = ((8 << 1) | 1); // Length and shiftet like so: length << 1 | 1
|
|
rfcommbuf[2] = ((0x10<< 1)); // Channel: channel << 1 | 1 TODO: replace channel with variable
|
|
rfcommbuf[3] = 0xE0; // Pre defined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
|
|
rfcommbuf[4] = 0x00; // Priority
|
|
rfcommbuf[5] = 0x00; // Timer
|
|
rfcommbuf[6] = BULK_MAXPKTSIZE - 14; // Max Fram Size LSB - set to the size of received data (50)
|
|
rfcommbuf[7] = 0x00; // Max Fram Size MSB
|
|
rfcommbuf[8] = 0x00; // MaxRetransm.
|
|
rfcommbuf[9] = 0x00; // Number of Frames
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nSent UAH RFComm Cmd BT_RFCOMM_PN_CMD (Parameter Negotiation Request) on channel: "), 0x80);
|
|
D_PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
|
|
#endif
|
|
// channel direction, CR,channelType,pfBit, data, length
|
|
sendRfcomm(0, 0, (1 << 1), RFCOMM_UIH, 0, rfcommbuf, 0x0A);
|
|
}else{
|
|
//Reply on 2-nd SAMB command on channel 0
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nSend UIH RFComm Cmd BT_RFCOMM_MSC_CMD (Modem Status Command)"), 0x80);
|
|
#endif
|
|
rfcommbuf[0] = BT_RFCOMM_MSC_CMD; // UIH Modem Status Command
|
|
rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1
|
|
rfcommbuf[2] = (1 << 0) | (1 << 1) | (0 << 2) | (rfcommChannelConnection << 3); //0x83 // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3)
|
|
rfcommbuf[3] = 0x8D; // Can receive frames (YES), Ready to Communicate (YES), Ready to Receive (YES), Incomig Call (NO), Data is Value (YES)
|
|
|
|
// channel direction, CR,channelType,pfBit, data, length
|
|
sendRfcomm(0, 0, (1 << 1), RFCOMM_UIH, 0, rfcommbuf, 0x04);
|
|
}
|
|
} else if (rfcommChannelType == RFCOMM_UIH) {
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nReceived UIH RFComm Packet on channel: "), 0x80);
|
|
D_PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
|
|
#endif
|
|
if (l2capinbuf[11] == BT_RFCOMM_PN_RSP)
|
|
{
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR(" - BT_RFCOMM_PN_RSP (Parameter Negotiation Response)"), 0x80);
|
|
Notify(PSTR("\r\nRFComm 2-nd SABM Sent"), 0x80);
|
|
#endif
|
|
// channel direction, CR,channelType, pfBit, data, length
|
|
sendRfcomm((rfcommChannelConnection << 3), 0, (1 << 1), RFCOMM_SABM, (1 << 4), rfcommbuf, 0);
|
|
}else if (l2capinbuf[11] == BT_RFCOMM_MSC_CMD)
|
|
{
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR(" - BT_RFCOMM_MSC_CMD (Modem Status Cmd)"), 0x80);
|
|
#endif
|
|
rfcommbuf[0] = BT_RFCOMM_MSC_RSP; // UIH Modem Status Command
|
|
rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1
|
|
rfcommbuf[2] = (1 << 0) | (1 << 1) | (0 << 2) | (rfcommChannelConnection << 3); //0x83 // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3)
|
|
rfcommbuf[3] = 0x8D; // Can receive frames (YES), Ready to Communicate (YES), Ready to Receive (YES), Incomig Call (NO), Data is Value (YES)
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nSend UIH RFComm Cmd BT_RFCOMM_MSC_RSP (Modem Status Response)"), 0x80);
|
|
#endif
|
|
// channel direction, CR,channelType,pfBit, data, length
|
|
sendRfcomm(0, 0, (1 << 1), RFCOMM_UIH, 0, rfcommbuf, 0x04);
|
|
}else if (l2capinbuf[11] == BT_RFCOMM_MSC_RSP)
|
|
{
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR(" - BT_RFCOMM_MSC_RSP (Modem Status Response)"), 0x80);
|
|
Notify(PSTR("\r\nRFComm Cmd with Credit Sent"), 0x80);
|
|
#endif
|
|
sendRfcommCredit((0x10 << 3), 0, (1 << 1), RFCOMM_UIH, 0x10,
|
|
sizeof (rfcommDataBuffer)); // Send credit
|
|
|
|
connected = true; // The RFCOMM channel is now established
|
|
sppIndex = 0;
|
|
}else if (l2capinbuf[11] == BT_RFCOMM_RPN_CMD)
|
|
{
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR(" - BT_RFCOMM_RPN_CMD (Remote Port Negotiation Cmd)"), 0x80);
|
|
#endif
|
|
//Just a stub. This command is optional according to the spec
|
|
}else if (l2capinbuf[11] == BT_RFCOMM_RPN_RSP)
|
|
{
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR(" - BT_RFCOMM_RPN_RSP (Remote Port Negotiation Response)"), 0x80);
|
|
#endif
|
|
//Just a stub. This command is optional according to the spec
|
|
}else
|
|
{
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR(" - Unknown Response: "), 0x80);
|
|
D_PrintHex<uint8_t > (l2capinbuf[11], 0x80);
|
|
#endif
|
|
}
|
|
} else if (rfcommChannelType == RFCOMM_DM) {
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nReceived DM RFComm Command on channel: "), 0x80);
|
|
D_PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
|
|
#endif
|
|
} else {
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nUnknown Response, rfCommChannelType: "), 0x80);
|
|
D_PrintHex<uint8_t > (rfcommChannelType, 0x80);
|
|
#endif
|
|
}
|
|
}
|
|
} else {
|
|
#ifdef EXTRADEBUG
|
|
Notify(PSTR("\r\nUnsupported L2CAP Data - Channel ID: "), 0x80);
|
|
D_PrintHex<uint8_t > (l2capinbuf[7], 0x80);
|
|
Notify(PSTR(" "), 0x80);
|
|
D_PrintHex<uint8_t > (l2capinbuf[6], 0x80);
|
|
Notify(PSTR("\r\n"), 0x80);
|
|
|
|
for (uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) {
|
|
D_PrintHex<uint8_t > (l2capinbuf[i], 0x80);
|
|
Notify(PSTR(" "), 0x80);
|
|
}
|
|
#endif
|
|
}
|
|
}else{
|
|
#ifdef EXTRADEBUG
|
|
Notify(PSTR("\r\nBad ACL handle: "), 0x80);
|
|
D_PrintHex<uint8_t > (l2capinbuf[0], 0x80);
|
|
Notify(PSTR(" "), 0x80);
|
|
D_PrintHex<uint8_t > (l2capinbuf[1], 0x80);
|
|
Notify(PSTR(" "), 0x80);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void SPPClient::Run() {
|
|
if (pBtd->pairWithOtherDevice){
|
|
if (l2cap_sdp_state == L2CAP_SDP_WAIT) {
|
|
if (pBtd->connectToOtherDevice && !pBtd->l2capConnectionClaimed && !connected) {
|
|
pBtd->l2capConnectionClaimed = true;
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nSDP Connection Request Sent"), 0x80);
|
|
#endif
|
|
hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
|
|
identifier = 0;
|
|
|
|
pBtd->l2cap_connection_request(hci_handle, identifier, sdp_scid, SDP_PSM);
|
|
l2cap_sdp_state = L2CAP_SDP_REQUEST;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/************************************************************/
|
|
/* SDP Commands */
|
|
/************************************************************/
|
|
void SPPClient::SDP_Command(uint8_t *data, uint8_t nbytes) { // See page 223 in the Bluetooth specs
|
|
pBtd->L2CAP_Command(hci_handle, data, nbytes, sdp_dcid[0], sdp_dcid[1]);
|
|
}
|
|
|
|
void SPPClient::SDP_Service_Search_Attr(uint8_t transactionIDHigh, uint8_t transactionIDLow, uint8_t remainingLen) {
|
|
l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU;
|
|
l2capoutbuf[1] = transactionIDHigh;
|
|
l2capoutbuf[2] = transactionIDLow;
|
|
|
|
l2capoutbuf[3] = 0x00; // Parameter Length
|
|
if (remainingLen == 0)
|
|
l2capoutbuf[4] = 0x0F; // Parameter Length
|
|
else
|
|
l2capoutbuf[4] = 0x11; // Parameter Length
|
|
|
|
l2capoutbuf[5] = 0x35; // Data Element Sequence, data size in next 8 bits
|
|
l2capoutbuf[6] = 0x03; // Data size
|
|
|
|
l2capoutbuf[7] = 0x19; // 00011 001 UUID, 2 bytes
|
|
l2capoutbuf[8] = 0x01;
|
|
l2capoutbuf[9] = 0x00; // 0x0100 - L2CAP_UUID
|
|
|
|
l2capoutbuf[10] = 0x00;
|
|
l2capoutbuf[11] = 0x26;// 0x0026 Maximum attribute byte count
|
|
|
|
l2capoutbuf[12] = 0x35;// Data Element Sequence, data size in next 8 bits
|
|
l2capoutbuf[13] = 0x05;// Data size
|
|
|
|
l2capoutbuf[14] = 0x0A;// 00001 010 unsigned int, 4 bytes - Attribute ID range
|
|
|
|
l2capoutbuf[15] = 0x00;
|
|
l2capoutbuf[16] = 0x00;// range from 0x0000...
|
|
|
|
l2capoutbuf[17] = 0xFF;
|
|
l2capoutbuf[18] = 0xFF;// ... to 0xFFFF
|
|
|
|
if (remainingLen == 0) {
|
|
l2capoutbuf[19] = 0x00;// No more data
|
|
SDP_Command(l2capoutbuf, 20);
|
|
} else{
|
|
l2capoutbuf[19] = 0x02;
|
|
l2capoutbuf[20] = 0x0; //will be 0 anyway
|
|
l2capoutbuf[21] = remainingLen;
|
|
SDP_Command(l2capoutbuf, 22);
|
|
}
|
|
}
|
|
|
|
/************************************************************/
|
|
/* RFCOMM Commands */
|
|
/************************************************************/
|
|
void SPPClient::RFCOMM_Command(uint8_t* data, uint8_t nbytes) {
|
|
pBtd->L2CAP_Command(hci_handle, data, nbytes, rfcomm_dcid[0], rfcomm_dcid[1]);
|
|
}
|
|
|
|
void SPPClient::parseAttrReply(uint8_t *l2capinbuf) {
|
|
if ((l2capinbuf[2] + 4) < 15) return; // Sanity check
|
|
|
|
if (rfcomm_found) {
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nChannel is already found"), 0x80);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
if (rfcomm_uuid_sign_idx == sizeof(rfcomm_uuid_sign)) {
|
|
// Signature has been already found but channel is in next packet
|
|
rfcommChannelConnection = l2capinbuf[15];
|
|
rfcomm_found = true;
|
|
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nChannel found in second packet: "), 0x80);
|
|
Notify((uint8_t)rfcommChannelConnection, 0x80);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
uint8_t nextSignBt;
|
|
for (uint8_t i = 15; i < (l2capinbuf[2] + 4); i++) { // Searching through packet payload only
|
|
// Keep searching for signature
|
|
if (l2capinbuf[i] == pgm_read_byte(&rfcomm_uuid_sign[rfcomm_uuid_sign_idx])) {
|
|
#ifdef EXTRADEBUG
|
|
Notify(PSTR("\r\nFound match @"), 0x80);
|
|
Notify((uint8_t)i, 0x80);
|
|
#endif
|
|
rfcomm_uuid_sign_idx++;
|
|
if (rfcomm_uuid_sign_idx == sizeof(rfcomm_uuid_sign)) {
|
|
// Signature found, trying to get channel number
|
|
if (l2capinbuf[i + 1] == 0x2) {
|
|
// Is the byte we are looking at the second last in the packet?
|
|
if ((l2capinbuf[2] + 1) == (i + 1)) {
|
|
// Oh well, channel number didn't fit in this packet, waiting for next
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nChannel will be in the next packet"), 0x80);
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
rfcommChannelConnection = l2capinbuf[i + 1];
|
|
rfcomm_found = true;
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nChannel found in first packet: "), 0x80);
|
|
D_PrintHex<uint8_t > (rfcommChannelConnection, 0x80);
|
|
#endif
|
|
return;
|
|
}
|
|
} else if ((l2capinbuf[i] == 0x2) && (i == l2capinbuf[2] + 1)) {
|
|
// This is an indication of packet end with more data to come in next packet - do not reset rfcomm_uuid_sign_idx, we will continue when next packet arrives
|
|
#ifdef DEBUG_USB_HOST
|
|
Notify(PSTR("\r\nEnd of packet reached, no full signature yet"), 0x80);
|
|
#endif
|
|
return;
|
|
} else {
|
|
// Otherwise the signature is not found - start over again
|
|
rfcomm_uuid_sign_idx = 0;
|
|
}
|
|
}
|
|
return;
|
|
}
|