Library to use Arduino USB host shield on mbed

Dependents:   USBHOST_PS5

ArduinoのUSB Host Shield 2.0をmbedで使えるようにしたライブラリです。
大体のコードがArduinoからそのまま移植可能です。

Arduino UNOやMega用のホストシールド以外にもミニサイズのホストシールドでも使用可能です https://os.mbed.com/media/uploads/kotakku/dffgfddswa.png

シールドについて

3.3VのI/O用にシールドの改造が必要になりますがネット上に記事がたくさんあるのでそちらを参考にしてください

接続例

https://os.mbed.com/media/uploads/kotakku/esgsvfvhjrekldkcjxvb.png

使い方

Arduinoのコードと違うのはUSBのインスタンスの宣言部分のみです。
ピンを自分で指定できるようにしたので使いやすくなりました。

仕様

  • Arduinoのmillis関数、micros関数の移植のために内部でTimerクラスを使用しています。

main.cpp

#include "mbed.h"
#include <PS3BT.h>
#include <usbhub.h>

Serial pc(USBTX, USBRX, 115200);

//Nucleo f303k8用
USB Usb(A6, A5, A4, A3, A2); // mosi, miso, sclk, ssel, intr
BTD Btd(&Usb);
PS3BT PS3(&Btd);

int main()
{
    bool printAngle = false;

    if (Usb.Init() == -1)
    {
        pc.printf("\r\nOSC did not start");
        while (1); // Halt
    }
    pc.printf("\r\nPS3 USB Library Started");

    while (1)
    {
        Usb.Task();
        
        if (PS3.PS3Connected || PS3.PS3NavigationConnected) {
            if (PS3.getAnalogHat(LeftHatX) > 137 || PS3.getAnalogHat(LeftHatX) < 117 || PS3.getAnalogHat(LeftHatY) > 137 || PS3.getAnalogHat(LeftHatY) < 117 || PS3.getAnalogHat(RightHatX) > 137 || PS3.getAnalogHat(RightHatX) < 117 || PS3.getAnalogHat(RightHatY) > 137 || PS3.getAnalogHat(RightHatY) < 117)
            {
                pc.printf("\r\nLeftHatX: %d", PS3.getAnalogHat(LeftHatX));
                pc.printf("\tLeftHatY: %d", PS3.getAnalogHat(LeftHatY));
                if (PS3.PS3Connected)
                { // The Navigation controller only have one joystick
                    pc.printf("\tRightHatX: %d", PS3.getAnalogHat(RightHatX));
                    pc.printf("\tRightHatY: %d", PS3.getAnalogHat(RightHatY));
                }
            }
            // Analog button values can be read from almost all buttons
            if (PS3.getAnalogButton(L2) || PS3.getAnalogButton(R2))
            {
                pc.printf("\r\nL2: %d", PS3.getAnalogButton(L2));
                if (!PS3.PS3NavigationConnected)
                {
                    pc.printf("\tR2: %d", PS3.getAnalogButton(R2));
                }
            }
            if (PS3.getButtonClick(PS))
            {
                PS3.disconnect();
                pc.printf("\r\nPS");
            }
    
            if (PS3.getButtonClick(TRIANGLE))
                pc.printf("\r\nTriangle");
            if (PS3.getButtonClick(CIRCLE))
                pc.printf("\r\nCircle");
            if (PS3.getButtonClick(CROSS))
                pc.printf("\r\nCross");
            if (PS3.getButtonClick(SQUARE))
                pc.printf("\r\nSquare");
    
            if (PS3.getButtonClick(UP))
            {
                pc.printf("\r\nUp");
                PS3.setLedOff();
                PS3.setLedOn(CONTROLLER_LED4);
            }
            if (PS3.getButtonClick(RIGHT))
            {
                pc.printf("\r\nRight");
                PS3.setLedOff();
                PS3.setLedOn(CONTROLLER_LED1);
            }
            if (PS3.getButtonClick(DOWN))
            {
                pc.printf("\r\nDown");
                PS3.setLedOff();
                PS3.setLedOn(CONTROLLER_LED2);
            }
            if (PS3.getButtonClick(LEFT))
            {
                pc.printf("\r\nLeft");
                PS3.setLedOff();
                PS3.setLedOn(CONTROLLER_LED3);
            }
    
            if (PS3.getButtonClick(L1))
                pc.printf("\r\nL1");
            if (PS3.getButtonClick(L3))
                pc.printf("\r\nL3");
            if (PS3.getButtonClick(R1))
                pc.printf("\r\nR1");
            if (PS3.getButtonClick(R3))
                pc.printf("\r\nR3");
    
            if (PS3.getButtonClick(SELECT))
            {
                pc.printf("\r\nSelect - ");
                PS3.printStatusString();
            }
            if (PS3.getButtonClick(START))
            {
                pc.printf("\r\nStart");
                printAngle = !printAngle;
            }
            if (printAngle)
            {
                pc.printf("\r\nPitch: %.3lf", PS3.getAngle(Pitch));
                pc.printf("\tRoll: %.3lf", PS3.getAngle(Roll));
            }
        }
        else
        {
            pc.printf("not connect\n");
        }
    }
}
Committer:
kotakku
Date:
Sat Jan 18 15:06:35 2020 +0000
Revision:
0:b1ce54272580
1.0.0 first commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kotakku 0:b1ce54272580 1 /* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
kotakku 0:b1ce54272580 2
kotakku 0:b1ce54272580 3 This software may be distributed and modified under the terms of the GNU
kotakku 0:b1ce54272580 4 General Public License version 2 (GPL2) as published by the Free Software
kotakku 0:b1ce54272580 5 Foundation and appearing in the file GPL2.TXT included in the packaging of
kotakku 0:b1ce54272580 6 this file. Please note that GPL2 Section 2[b] requires that all works based
kotakku 0:b1ce54272580 7 on this software must also be made publicly available under the terms of
kotakku 0:b1ce54272580 8 the GPL2 ("Copyleft").
kotakku 0:b1ce54272580 9
kotakku 0:b1ce54272580 10 Contact information
kotakku 0:b1ce54272580 11 -------------------
kotakku 0:b1ce54272580 12
kotakku 0:b1ce54272580 13 Kristian Lauszus, TKJ Electronics
kotakku 0:b1ce54272580 14 Web : http://www.tkjelectronics.com
kotakku 0:b1ce54272580 15 e-mail : kristianl@tkjelectronics.com
kotakku 0:b1ce54272580 16 */
kotakku 0:b1ce54272580 17
kotakku 0:b1ce54272580 18 #include "SPP.h"
kotakku 0:b1ce54272580 19 // To enable serial debugging see "settings.h"
kotakku 0:b1ce54272580 20 //#define EXTRADEBUG // Uncomment to get even more debugging data
kotakku 0:b1ce54272580 21 //#define PRINTREPORT // Uncomment to print the report sent to the Arduino
kotakku 0:b1ce54272580 22
kotakku 0:b1ce54272580 23 /*
kotakku 0:b1ce54272580 24 * CRC (reversed crc) lookup table as calculated by the table generator in ETSI TS 101 369 V6.3.0.
kotakku 0:b1ce54272580 25 */
kotakku 0:b1ce54272580 26 const uint8_t rfcomm_crc_table[256] PROGMEM = {/* reversed, 8-bit, poly=0x07 */
kotakku 0:b1ce54272580 27 0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
kotakku 0:b1ce54272580 28 0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
kotakku 0:b1ce54272580 29 0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
kotakku 0:b1ce54272580 30 0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
kotakku 0:b1ce54272580 31 0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
kotakku 0:b1ce54272580 32 0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19, 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
kotakku 0:b1ce54272580 33 0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
kotakku 0:b1ce54272580 34 0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
kotakku 0:b1ce54272580 35 0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
kotakku 0:b1ce54272580 36 0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
kotakku 0:b1ce54272580 37 0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
kotakku 0:b1ce54272580 38 0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
kotakku 0:b1ce54272580 39 0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
kotakku 0:b1ce54272580 40 0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
kotakku 0:b1ce54272580 41 0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
kotakku 0:b1ce54272580 42 0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
kotakku 0:b1ce54272580 43 };
kotakku 0:b1ce54272580 44
kotakku 0:b1ce54272580 45 SPP::SPP(BTD *p, const char* name, const char* pin) :
kotakku 0:b1ce54272580 46 BluetoothService(p) // Pointer to BTD class instance - mandatory
kotakku 0:b1ce54272580 47 {
kotakku 0:b1ce54272580 48 pBtd->btdName = name;
kotakku 0:b1ce54272580 49 pBtd->btdPin = pin;
kotakku 0:b1ce54272580 50
kotakku 0:b1ce54272580 51 /* Set device cid for the SDP and RFCOMM channelse */
kotakku 0:b1ce54272580 52 sdp_dcid[0] = 0x50; // 0x0050
kotakku 0:b1ce54272580 53 sdp_dcid[1] = 0x00;
kotakku 0:b1ce54272580 54 rfcomm_dcid[0] = 0x51; // 0x0051
kotakku 0:b1ce54272580 55 rfcomm_dcid[1] = 0x00;
kotakku 0:b1ce54272580 56
kotakku 0:b1ce54272580 57 Reset();
kotakku 0:b1ce54272580 58 }
kotakku 0:b1ce54272580 59
kotakku 0:b1ce54272580 60 void SPP::Reset() {
kotakku 0:b1ce54272580 61 connected = false;
kotakku 0:b1ce54272580 62 RFCOMMConnected = false;
kotakku 0:b1ce54272580 63 SDPConnected = false;
kotakku 0:b1ce54272580 64 waitForLastCommand = false;
kotakku 0:b1ce54272580 65 l2cap_sdp_state = L2CAP_SDP_WAIT;
kotakku 0:b1ce54272580 66 l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT;
kotakku 0:b1ce54272580 67 l2cap_event_flag = 0;
kotakku 0:b1ce54272580 68 sppIndex = 0;
kotakku 0:b1ce54272580 69 creditSent = false;
kotakku 0:b1ce54272580 70 }
kotakku 0:b1ce54272580 71
kotakku 0:b1ce54272580 72 void SPP::disconnect() {
kotakku 0:b1ce54272580 73 connected = false;
kotakku 0:b1ce54272580 74 // First the two L2CAP channels has to be disconnected and then the HCI connection
kotakku 0:b1ce54272580 75 if(RFCOMMConnected)
kotakku 0:b1ce54272580 76 pBtd->l2cap_disconnection_request(hci_handle, ++identifier, rfcomm_scid, rfcomm_dcid);
kotakku 0:b1ce54272580 77 if(RFCOMMConnected && SDPConnected)
kotakku 0:b1ce54272580 78 delay(1); // Add delay between commands
kotakku 0:b1ce54272580 79 if(SDPConnected)
kotakku 0:b1ce54272580 80 pBtd->l2cap_disconnection_request(hci_handle, ++identifier, sdp_scid, sdp_dcid);
kotakku 0:b1ce54272580 81 l2cap_sdp_state = L2CAP_DISCONNECT_RESPONSE;
kotakku 0:b1ce54272580 82 }
kotakku 0:b1ce54272580 83
kotakku 0:b1ce54272580 84 void SPP::ACLData(uint8_t* l2capinbuf) {
kotakku 0:b1ce54272580 85 if(!connected) {
kotakku 0:b1ce54272580 86 if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
kotakku 0:b1ce54272580 87 if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM && !pBtd->sdpConnectionClaimed) {
kotakku 0:b1ce54272580 88 pBtd->sdpConnectionClaimed = true;
kotakku 0:b1ce54272580 89 hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
kotakku 0:b1ce54272580 90 l2cap_sdp_state = L2CAP_SDP_WAIT; // Reset state
kotakku 0:b1ce54272580 91 } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == RFCOMM_PSM && !pBtd->rfcommConnectionClaimed) {
kotakku 0:b1ce54272580 92 pBtd->rfcommConnectionClaimed = true;
kotakku 0:b1ce54272580 93 hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
kotakku 0:b1ce54272580 94 l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT; // Reset state
kotakku 0:b1ce54272580 95 }
kotakku 0:b1ce54272580 96 }
kotakku 0:b1ce54272580 97 }
kotakku 0:b1ce54272580 98
kotakku 0:b1ce54272580 99 if(checkHciHandle(l2capinbuf, hci_handle)) { // acl_handle_ok
kotakku 0:b1ce54272580 100 if((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001U) { // l2cap_control - Channel ID for ACL-U
kotakku 0:b1ce54272580 101 if(l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
kotakku 0:b1ce54272580 102 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 103 Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
kotakku 0:b1ce54272580 104 D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
kotakku 0:b1ce54272580 105 Notify(PSTR(" "), 0x80);
kotakku 0:b1ce54272580 106 D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
kotakku 0:b1ce54272580 107 Notify(PSTR(" Data: "), 0x80);
kotakku 0:b1ce54272580 108 D_PrintHex<uint8_t > (l2capinbuf[17], 0x80);
kotakku 0:b1ce54272580 109 Notify(PSTR(" "), 0x80);
kotakku 0:b1ce54272580 110 D_PrintHex<uint8_t > (l2capinbuf[16], 0x80);
kotakku 0:b1ce54272580 111 Notify(PSTR(" "), 0x80);
kotakku 0:b1ce54272580 112 D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
kotakku 0:b1ce54272580 113 Notify(PSTR(" "), 0x80);
kotakku 0:b1ce54272580 114 D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
kotakku 0:b1ce54272580 115 #endif
kotakku 0:b1ce54272580 116 } else if(l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
kotakku 0:b1ce54272580 117 #ifdef EXTRADEBUG
kotakku 0:b1ce54272580 118 Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
kotakku 0:b1ce54272580 119 D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
kotakku 0:b1ce54272580 120 Notify(PSTR(" "), 0x80);
kotakku 0:b1ce54272580 121 D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
kotakku 0:b1ce54272580 122 Notify(PSTR(" SCID: "), 0x80);
kotakku 0:b1ce54272580 123 D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
kotakku 0:b1ce54272580 124 Notify(PSTR(" "), 0x80);
kotakku 0:b1ce54272580 125 D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
kotakku 0:b1ce54272580 126 Notify(PSTR(" Identifier: "), 0x80);
kotakku 0:b1ce54272580 127 D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
kotakku 0:b1ce54272580 128 #endif
kotakku 0:b1ce54272580 129 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
kotakku 0:b1ce54272580 130 identifier = l2capinbuf[9];
kotakku 0:b1ce54272580 131 sdp_scid[0] = l2capinbuf[14];
kotakku 0:b1ce54272580 132 sdp_scid[1] = l2capinbuf[15];
kotakku 0:b1ce54272580 133 l2cap_set_flag(L2CAP_FLAG_CONNECTION_SDP_REQUEST);
kotakku 0:b1ce54272580 134 } else if((l2capinbuf[12] | (l2capinbuf[13] << 8)) == RFCOMM_PSM) { // ----- || -----
kotakku 0:b1ce54272580 135 identifier = l2capinbuf[9];
kotakku 0:b1ce54272580 136 rfcomm_scid[0] = l2capinbuf[14];
kotakku 0:b1ce54272580 137 rfcomm_scid[1] = l2capinbuf[15];
kotakku 0:b1ce54272580 138 l2cap_set_flag(L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST);
kotakku 0:b1ce54272580 139 }
kotakku 0:b1ce54272580 140 } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
kotakku 0:b1ce54272580 141 if((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
kotakku 0:b1ce54272580 142 if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
kotakku 0:b1ce54272580 143 //Notify(PSTR("\r\nSDP Configuration Complete"), 0x80);
kotakku 0:b1ce54272580 144 l2cap_set_flag(L2CAP_FLAG_CONFIG_SDP_SUCCESS);
kotakku 0:b1ce54272580 145 } else if(l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) {
kotakku 0:b1ce54272580 146 //Notify(PSTR("\r\nRFCOMM Configuration Complete"), 0x80);
kotakku 0:b1ce54272580 147 l2cap_set_flag(L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS);
kotakku 0:b1ce54272580 148 }
kotakku 0:b1ce54272580 149 }
kotakku 0:b1ce54272580 150 } else if(l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
kotakku 0:b1ce54272580 151 if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
kotakku 0:b1ce54272580 152 //Notify(PSTR("\r\nSDP Configuration Request"), 0x80);
kotakku 0:b1ce54272580 153 pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], sdp_scid);
kotakku 0:b1ce54272580 154 } else if(l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) {
kotakku 0:b1ce54272580 155 //Notify(PSTR("\r\nRFCOMM Configuration Request"), 0x80);
kotakku 0:b1ce54272580 156 pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], rfcomm_scid);
kotakku 0:b1ce54272580 157 }
kotakku 0:b1ce54272580 158 } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
kotakku 0:b1ce54272580 159 if(l2capinbuf[12] == sdp_dcid[0] && l2capinbuf[13] == sdp_dcid[1]) {
kotakku 0:b1ce54272580 160 //Notify(PSTR("\r\nDisconnect Request: SDP Channel"), 0x80);
kotakku 0:b1ce54272580 161 identifier = l2capinbuf[9];
kotakku 0:b1ce54272580 162 l2cap_set_flag(L2CAP_FLAG_DISCONNECT_SDP_REQUEST);
kotakku 0:b1ce54272580 163 } else if(l2capinbuf[12] == rfcomm_dcid[0] && l2capinbuf[13] == rfcomm_dcid[1]) {
kotakku 0:b1ce54272580 164 //Notify(PSTR("\r\nDisconnect Request: RFCOMM Channel"), 0x80);
kotakku 0:b1ce54272580 165 identifier = l2capinbuf[9];
kotakku 0:b1ce54272580 166 l2cap_set_flag(L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST);
kotakku 0:b1ce54272580 167 }
kotakku 0:b1ce54272580 168 } else if(l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) {
kotakku 0:b1ce54272580 169 if(l2capinbuf[12] == sdp_scid[0] && l2capinbuf[13] == sdp_scid[1]) {
kotakku 0:b1ce54272580 170 //Notify(PSTR("\r\nDisconnect Response: SDP Channel"), 0x80);
kotakku 0:b1ce54272580 171 identifier = l2capinbuf[9];
kotakku 0:b1ce54272580 172 l2cap_set_flag(L2CAP_FLAG_DISCONNECT_RESPONSE);
kotakku 0:b1ce54272580 173 } else if(l2capinbuf[12] == rfcomm_scid[0] && l2capinbuf[13] == rfcomm_scid[1]) {
kotakku 0:b1ce54272580 174 //Notify(PSTR("\r\nDisconnect Response: RFCOMM Channel"), 0x80);
kotakku 0:b1ce54272580 175 identifier = l2capinbuf[9];
kotakku 0:b1ce54272580 176 l2cap_set_flag(L2CAP_FLAG_DISCONNECT_RESPONSE);
kotakku 0:b1ce54272580 177 }
kotakku 0:b1ce54272580 178 } else if(l2capinbuf[8] == L2CAP_CMD_INFORMATION_REQUEST) {
kotakku 0:b1ce54272580 179 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 180 Notify(PSTR("\r\nInformation request"), 0x80);
kotakku 0:b1ce54272580 181 #endif
kotakku 0:b1ce54272580 182 identifier = l2capinbuf[9];
kotakku 0:b1ce54272580 183 pBtd->l2cap_information_response(hci_handle, identifier, l2capinbuf[12], l2capinbuf[13]);
kotakku 0:b1ce54272580 184 }
kotakku 0:b1ce54272580 185 #ifdef EXTRADEBUG
kotakku 0:b1ce54272580 186 else {
kotakku 0:b1ce54272580 187 Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
kotakku 0:b1ce54272580 188 D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
kotakku 0:b1ce54272580 189 }
kotakku 0:b1ce54272580 190 #endif
kotakku 0:b1ce54272580 191 } else if(l2capinbuf[6] == sdp_dcid[0] && l2capinbuf[7] == sdp_dcid[1]) { // SDP
kotakku 0:b1ce54272580 192 if(l2capinbuf[8] == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU) {
kotakku 0:b1ce54272580 193 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
kotakku 0:b1ce54272580 194 if(firstMessage) {
kotakku 0:b1ce54272580 195 serialPortResponse1(l2capinbuf[9], l2capinbuf[10]);
kotakku 0:b1ce54272580 196 firstMessage = false;
kotakku 0:b1ce54272580 197 } else {
kotakku 0:b1ce54272580 198 serialPortResponse2(l2capinbuf[9], l2capinbuf[10]); // Serialport continuation state
kotakku 0:b1ce54272580 199 firstMessage = true;
kotakku 0:b1ce54272580 200 }
kotakku 0:b1ce54272580 201 } else if(((l2capinbuf[16] << 8 | l2capinbuf[17]) == L2CAP_UUID) || ((l2capinbuf[16] << 8 | l2capinbuf[17]) == 0x0000 && (l2capinbuf[18] << 8 | l2capinbuf[19]) == L2CAP_UUID)) {
kotakku 0:b1ce54272580 202 if(firstMessage) {
kotakku 0:b1ce54272580 203 l2capResponse1(l2capinbuf[9], l2capinbuf[10]);
kotakku 0:b1ce54272580 204 firstMessage = false;
kotakku 0:b1ce54272580 205 } else {
kotakku 0:b1ce54272580 206 l2capResponse2(l2capinbuf[9], l2capinbuf[10]); // L2CAP continuation state
kotakku 0:b1ce54272580 207 firstMessage = true;
kotakku 0:b1ce54272580 208 }
kotakku 0:b1ce54272580 209 } else
kotakku 0:b1ce54272580 210 serviceNotSupported(l2capinbuf[9], l2capinbuf[10]); // The service is not supported
kotakku 0:b1ce54272580 211 #ifdef EXTRADEBUG
kotakku 0:b1ce54272580 212 Notify(PSTR("\r\nUUID: "), 0x80);
kotakku 0:b1ce54272580 213 uint16_t uuid;
kotakku 0:b1ce54272580 214 if((l2capinbuf[16] << 8 | l2capinbuf[17]) == 0x0000) // Check if it's sending the UUID as a 128-bit UUID
kotakku 0:b1ce54272580 215 uuid = (l2capinbuf[18] << 8 | l2capinbuf[19]);
kotakku 0:b1ce54272580 216 else // Short UUID
kotakku 0:b1ce54272580 217 uuid = (l2capinbuf[16] << 8 | l2capinbuf[17]);
kotakku 0:b1ce54272580 218 D_PrintHex<uint16_t > (uuid, 0x80);
kotakku 0:b1ce54272580 219
kotakku 0:b1ce54272580 220 Notify(PSTR("\r\nLength: "), 0x80);
kotakku 0:b1ce54272580 221 uint16_t length = l2capinbuf[11] << 8 | l2capinbuf[12];
kotakku 0:b1ce54272580 222 D_PrintHex<uint16_t > (length, 0x80);
kotakku 0:b1ce54272580 223 Notify(PSTR("\r\nData: "), 0x80);
kotakku 0:b1ce54272580 224 for(uint8_t i = 0; i < length; i++) {
kotakku 0:b1ce54272580 225 D_PrintHex<uint8_t > (l2capinbuf[13 + i], 0x80);
kotakku 0:b1ce54272580 226 Notify(PSTR(" "), 0x80);
kotakku 0:b1ce54272580 227 }
kotakku 0:b1ce54272580 228 #endif
kotakku 0:b1ce54272580 229 }
kotakku 0:b1ce54272580 230 #ifdef EXTRADEBUG
kotakku 0:b1ce54272580 231 else {
kotakku 0:b1ce54272580 232 Notify(PSTR("\r\nUnknown PDU: "), 0x80);
kotakku 0:b1ce54272580 233 D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
kotakku 0:b1ce54272580 234 }
kotakku 0:b1ce54272580 235 #endif
kotakku 0:b1ce54272580 236 } else if(l2capinbuf[6] == rfcomm_dcid[0] && l2capinbuf[7] == rfcomm_dcid[1]) { // RFCOMM
kotakku 0:b1ce54272580 237 rfcommChannel = l2capinbuf[8] & 0xF8;
kotakku 0:b1ce54272580 238 rfcommDirection = l2capinbuf[8] & 0x04;
kotakku 0:b1ce54272580 239 rfcommCommandResponse = l2capinbuf[8] & 0x02;
kotakku 0:b1ce54272580 240 rfcommChannelType = l2capinbuf[9] & 0xEF;
kotakku 0:b1ce54272580 241 rfcommPfBit = l2capinbuf[9] & 0x10;
kotakku 0:b1ce54272580 242
kotakku 0:b1ce54272580 243 if(rfcommChannel >> 3 != 0x00)
kotakku 0:b1ce54272580 244 rfcommChannelConnection = rfcommChannel;
kotakku 0:b1ce54272580 245
kotakku 0:b1ce54272580 246 #ifdef EXTRADEBUG
kotakku 0:b1ce54272580 247 Notify(PSTR("\r\nRFCOMM Channel: "), 0x80);
kotakku 0:b1ce54272580 248 D_PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
kotakku 0:b1ce54272580 249 Notify(PSTR(" Direction: "), 0x80);
kotakku 0:b1ce54272580 250 D_PrintHex<uint8_t > (rfcommDirection >> 2, 0x80);
kotakku 0:b1ce54272580 251 Notify(PSTR(" CommandResponse: "), 0x80);
kotakku 0:b1ce54272580 252 D_PrintHex<uint8_t > (rfcommCommandResponse >> 1, 0x80);
kotakku 0:b1ce54272580 253 Notify(PSTR(" ChannelType: "), 0x80);
kotakku 0:b1ce54272580 254 D_PrintHex<uint8_t > (rfcommChannelType, 0x80);
kotakku 0:b1ce54272580 255 Notify(PSTR(" PF_BIT: "), 0x80);
kotakku 0:b1ce54272580 256 D_PrintHex<uint8_t > (rfcommPfBit, 0x80);
kotakku 0:b1ce54272580 257 #endif
kotakku 0:b1ce54272580 258 if(rfcommChannelType == RFCOMM_DISC) {
kotakku 0:b1ce54272580 259 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 260 Notify(PSTR("\r\nReceived Disconnect RFCOMM Command on channel: "), 0x80);
kotakku 0:b1ce54272580 261 D_PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
kotakku 0:b1ce54272580 262 #endif
kotakku 0:b1ce54272580 263 connected = false;
kotakku 0:b1ce54272580 264 sendRfcomm(rfcommChannel, rfcommDirection, rfcommCommandResponse, RFCOMM_UA, rfcommPfBit, rfcommbuf, 0x00); // UA Command
kotakku 0:b1ce54272580 265 }
kotakku 0:b1ce54272580 266 if(connected) {
kotakku 0:b1ce54272580 267 /* Read the incoming message */
kotakku 0:b1ce54272580 268 if(rfcommChannelType == RFCOMM_UIH && rfcommChannel == rfcommChannelConnection) {
kotakku 0:b1ce54272580 269 uint8_t length = l2capinbuf[10] >> 1; // Get length
kotakku 0:b1ce54272580 270 uint8_t offset = l2capinbuf[4] - length - 4; // Check if there is credit
kotakku 0:b1ce54272580 271 if(checkFcs(&l2capinbuf[8], l2capinbuf[11 + length + offset])) {
kotakku 0:b1ce54272580 272 uint8_t i = 0;
kotakku 0:b1ce54272580 273 for(; i < length; i++) {
kotakku 0:b1ce54272580 274 if(rfcommAvailable + i >= sizeof (rfcommDataBuffer)) {
kotakku 0:b1ce54272580 275 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 276 Notify(PSTR("\r\nWarning: Buffer is full!"), 0x80);
kotakku 0:b1ce54272580 277 #endif
kotakku 0:b1ce54272580 278 break;
kotakku 0:b1ce54272580 279 }
kotakku 0:b1ce54272580 280 rfcommDataBuffer[rfcommAvailable + i] = l2capinbuf[11 + i + offset];
kotakku 0:b1ce54272580 281 }
kotakku 0:b1ce54272580 282 rfcommAvailable += i;
kotakku 0:b1ce54272580 283 #ifdef EXTRADEBUG
kotakku 0:b1ce54272580 284 Notify(PSTR("\r\nRFCOMM Data Available: "), 0x80);
kotakku 0:b1ce54272580 285 Notify(rfcommAvailable, 0x80);
kotakku 0:b1ce54272580 286 if(offset) {
kotakku 0:b1ce54272580 287 Notify(PSTR(" - Credit: 0x"), 0x80);
kotakku 0:b1ce54272580 288 D_PrintHex<uint8_t > (l2capinbuf[11], 0x80);
kotakku 0:b1ce54272580 289 }
kotakku 0:b1ce54272580 290 #endif
kotakku 0:b1ce54272580 291 }
kotakku 0:b1ce54272580 292 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 293 else
kotakku 0:b1ce54272580 294 Notify(PSTR("\r\nError in FCS checksum!"), 0x80);
kotakku 0:b1ce54272580 295 #endif
kotakku 0:b1ce54272580 296 #ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send to the Arduino via Bluetooth
kotakku 0:b1ce54272580 297 for(uint8_t i = 0; i < length; i++)
kotakku 0:b1ce54272580 298 Notifyc(l2capinbuf[i + 11 + offset], 0x80);
kotakku 0:b1ce54272580 299 #endif
kotakku 0:b1ce54272580 300 } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_RPN_CMD) { // UIH Remote Port Negotiation Command
kotakku 0:b1ce54272580 301 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 302 Notify(PSTR("\r\nReceived UIH Remote Port Negotiation Command"), 0x80);
kotakku 0:b1ce54272580 303 #endif
kotakku 0:b1ce54272580 304 rfcommbuf[0] = BT_RFCOMM_RPN_RSP; // Command
kotakku 0:b1ce54272580 305 rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1
kotakku 0:b1ce54272580 306 rfcommbuf[2] = l2capinbuf[13]; // Channel: channel << 1 | 1
kotakku 0:b1ce54272580 307 rfcommbuf[3] = l2capinbuf[14]; // Pre difined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
kotakku 0:b1ce54272580 308 rfcommbuf[4] = l2capinbuf[15]; // Priority
kotakku 0:b1ce54272580 309 rfcommbuf[5] = l2capinbuf[16]; // Timer
kotakku 0:b1ce54272580 310 rfcommbuf[6] = l2capinbuf[17]; // Max Fram Size LSB
kotakku 0:b1ce54272580 311 rfcommbuf[7] = l2capinbuf[18]; // Max Fram Size MSB
kotakku 0:b1ce54272580 312 rfcommbuf[8] = l2capinbuf[19]; // MaxRatransm.
kotakku 0:b1ce54272580 313 rfcommbuf[9] = l2capinbuf[20]; // Number of Frames
kotakku 0:b1ce54272580 314 sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A); // UIH Remote Port Negotiation Response
kotakku 0:b1ce54272580 315 } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_CMD) { // UIH Modem Status Command
kotakku 0:b1ce54272580 316 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 317 Notify(PSTR("\r\nSend UIH Modem Status Response"), 0x80);
kotakku 0:b1ce54272580 318 #endif
kotakku 0:b1ce54272580 319 rfcommbuf[0] = BT_RFCOMM_MSC_RSP; // UIH Modem Status Response
kotakku 0:b1ce54272580 320 rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1
kotakku 0:b1ce54272580 321 rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3)
kotakku 0:b1ce54272580 322 rfcommbuf[3] = l2capinbuf[14];
kotakku 0:b1ce54272580 323 sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04);
kotakku 0:b1ce54272580 324 }
kotakku 0:b1ce54272580 325 } else {
kotakku 0:b1ce54272580 326 if(rfcommChannelType == RFCOMM_SABM) { // SABM Command - this is sent twice: once for channel 0 and then for the channel to establish
kotakku 0:b1ce54272580 327 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 328 Notify(PSTR("\r\nReceived SABM Command"), 0x80);
kotakku 0:b1ce54272580 329 #endif
kotakku 0:b1ce54272580 330 sendRfcomm(rfcommChannel, rfcommDirection, rfcommCommandResponse, RFCOMM_UA, rfcommPfBit, rfcommbuf, 0x00); // UA Command
kotakku 0:b1ce54272580 331 } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_PN_CMD) { // UIH Parameter Negotiation Command
kotakku 0:b1ce54272580 332 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 333 Notify(PSTR("\r\nReceived UIH Parameter Negotiation Command"), 0x80);
kotakku 0:b1ce54272580 334 #endif
kotakku 0:b1ce54272580 335 rfcommbuf[0] = BT_RFCOMM_PN_RSP; // UIH Parameter Negotiation Response
kotakku 0:b1ce54272580 336 rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1
kotakku 0:b1ce54272580 337 rfcommbuf[2] = l2capinbuf[13]; // Channel: channel << 1 | 1
kotakku 0:b1ce54272580 338 rfcommbuf[3] = 0xE0; // Pre difined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
kotakku 0:b1ce54272580 339 rfcommbuf[4] = 0x00; // Priority
kotakku 0:b1ce54272580 340 rfcommbuf[5] = 0x00; // Timer
kotakku 0:b1ce54272580 341 rfcommbuf[6] = BULK_MAXPKTSIZE - 14; // Max Fram Size LSB - set to the size of received data (50)
kotakku 0:b1ce54272580 342 rfcommbuf[7] = 0x00; // Max Fram Size MSB
kotakku 0:b1ce54272580 343 rfcommbuf[8] = 0x00; // MaxRatransm.
kotakku 0:b1ce54272580 344 rfcommbuf[9] = 0x00; // Number of Frames
kotakku 0:b1ce54272580 345 sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A);
kotakku 0:b1ce54272580 346 } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_CMD) { // UIH Modem Status Command
kotakku 0:b1ce54272580 347 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 348 Notify(PSTR("\r\nSend UIH Modem Status Response"), 0x80);
kotakku 0:b1ce54272580 349 #endif
kotakku 0:b1ce54272580 350 rfcommbuf[0] = BT_RFCOMM_MSC_RSP; // UIH Modem Status Response
kotakku 0:b1ce54272580 351 rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1
kotakku 0:b1ce54272580 352 rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3)
kotakku 0:b1ce54272580 353 rfcommbuf[3] = l2capinbuf[14];
kotakku 0:b1ce54272580 354 sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04);
kotakku 0:b1ce54272580 355
kotakku 0:b1ce54272580 356 delay(1);
kotakku 0:b1ce54272580 357 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 358 Notify(PSTR("\r\nSend UIH Modem Status Command"), 0x80);
kotakku 0:b1ce54272580 359 #endif
kotakku 0:b1ce54272580 360 rfcommbuf[0] = BT_RFCOMM_MSC_CMD; // UIH Modem Status Command
kotakku 0:b1ce54272580 361 rfcommbuf[1] = 2 << 1 | 1; // Length and shiftet like so: length << 1 | 1
kotakku 0:b1ce54272580 362 rfcommbuf[2] = l2capinbuf[13]; // Channel: (1 << 0) | (1 << 1) | (0 << 2) | (channel << 3)
kotakku 0:b1ce54272580 363 rfcommbuf[3] = 0x8D; // Can receive frames (YES), Ready to Communicate (YES), Ready to Receive (YES), Incomig Call (NO), Data is Value (YES)
kotakku 0:b1ce54272580 364
kotakku 0:b1ce54272580 365 sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04);
kotakku 0:b1ce54272580 366 } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_RSP) { // UIH Modem Status Response
kotakku 0:b1ce54272580 367 if(!creditSent) {
kotakku 0:b1ce54272580 368 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 369 Notify(PSTR("\r\nSend UIH Command with credit"), 0x80);
kotakku 0:b1ce54272580 370 #endif
kotakku 0:b1ce54272580 371 sendRfcommCredit(rfcommChannelConnection, rfcommDirection, 0, RFCOMM_UIH, 0x10, sizeof (rfcommDataBuffer)); // Send credit
kotakku 0:b1ce54272580 372 creditSent = true;
kotakku 0:b1ce54272580 373 timer = (uint32_t)millis();
kotakku 0:b1ce54272580 374 waitForLastCommand = true;
kotakku 0:b1ce54272580 375 }
kotakku 0:b1ce54272580 376 } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[10] == 0x01) { // UIH Command with credit
kotakku 0:b1ce54272580 377 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 378 Notify(PSTR("\r\nReceived UIH Command with credit"), 0x80);
kotakku 0:b1ce54272580 379 #endif
kotakku 0:b1ce54272580 380 } else if(rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_RPN_CMD) { // UIH Remote Port Negotiation Command
kotakku 0:b1ce54272580 381 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 382 Notify(PSTR("\r\nReceived UIH Remote Port Negotiation Command"), 0x80);
kotakku 0:b1ce54272580 383 #endif
kotakku 0:b1ce54272580 384 rfcommbuf[0] = BT_RFCOMM_RPN_RSP; // Command
kotakku 0:b1ce54272580 385 rfcommbuf[1] = l2capinbuf[12]; // Length and shiftet like so: length << 1 | 1
kotakku 0:b1ce54272580 386 rfcommbuf[2] = l2capinbuf[13]; // Channel: channel << 1 | 1
kotakku 0:b1ce54272580 387 rfcommbuf[3] = l2capinbuf[14]; // Pre difined for Bluetooth, see 5.5.3 of TS 07.10 Adaption for RFCOMM
kotakku 0:b1ce54272580 388 rfcommbuf[4] = l2capinbuf[15]; // Priority
kotakku 0:b1ce54272580 389 rfcommbuf[5] = l2capinbuf[16]; // Timer
kotakku 0:b1ce54272580 390 rfcommbuf[6] = l2capinbuf[17]; // Max Fram Size LSB
kotakku 0:b1ce54272580 391 rfcommbuf[7] = l2capinbuf[18]; // Max Fram Size MSB
kotakku 0:b1ce54272580 392 rfcommbuf[8] = l2capinbuf[19]; // MaxRatransm.
kotakku 0:b1ce54272580 393 rfcommbuf[9] = l2capinbuf[20]; // Number of Frames
kotakku 0:b1ce54272580 394 sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A); // UIH Remote Port Negotiation Response
kotakku 0:b1ce54272580 395 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 396 Notify(PSTR("\r\nRFCOMM Connection is now established\r\n"), 0x80);
kotakku 0:b1ce54272580 397 #endif
kotakku 0:b1ce54272580 398 onInit();
kotakku 0:b1ce54272580 399 }
kotakku 0:b1ce54272580 400 #ifdef EXTRADEBUG
kotakku 0:b1ce54272580 401 else if(rfcommChannelType != RFCOMM_DISC) {
kotakku 0:b1ce54272580 402 Notify(PSTR("\r\nUnsupported RFCOMM Data - ChannelType: "), 0x80);
kotakku 0:b1ce54272580 403 D_PrintHex<uint8_t > (rfcommChannelType, 0x80);
kotakku 0:b1ce54272580 404 Notify(PSTR(" Command: "), 0x80);
kotakku 0:b1ce54272580 405 D_PrintHex<uint8_t > (l2capinbuf[11], 0x80);
kotakku 0:b1ce54272580 406 }
kotakku 0:b1ce54272580 407 #endif
kotakku 0:b1ce54272580 408 }
kotakku 0:b1ce54272580 409 }
kotakku 0:b1ce54272580 410 #ifdef EXTRADEBUG
kotakku 0:b1ce54272580 411 else {
kotakku 0:b1ce54272580 412 Notify(PSTR("\r\nUnsupported L2CAP Data - Channel ID: "), 0x80);
kotakku 0:b1ce54272580 413 D_PrintHex<uint8_t > (l2capinbuf[7], 0x80);
kotakku 0:b1ce54272580 414 Notify(PSTR(" "), 0x80);
kotakku 0:b1ce54272580 415 D_PrintHex<uint8_t > (l2capinbuf[6], 0x80);
kotakku 0:b1ce54272580 416 }
kotakku 0:b1ce54272580 417 #endif
kotakku 0:b1ce54272580 418 SDP_task();
kotakku 0:b1ce54272580 419 RFCOMM_task();
kotakku 0:b1ce54272580 420 }
kotakku 0:b1ce54272580 421 }
kotakku 0:b1ce54272580 422
kotakku 0:b1ce54272580 423 void SPP::Run() {
kotakku 0:b1ce54272580 424 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
kotakku 0:b1ce54272580 425 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 426 Notify(PSTR("\r\nRFCOMM Connection is now established - Automatic\r\n"), 0x80);
kotakku 0:b1ce54272580 427 #endif
kotakku 0:b1ce54272580 428 onInit();
kotakku 0:b1ce54272580 429 }
kotakku 0:b1ce54272580 430 send(); // Send all bytes currently in the buffer
kotakku 0:b1ce54272580 431 }
kotakku 0:b1ce54272580 432
kotakku 0:b1ce54272580 433 void SPP::onInit() {
kotakku 0:b1ce54272580 434 creditSent = false;
kotakku 0:b1ce54272580 435 waitForLastCommand = false;
kotakku 0:b1ce54272580 436 connected = true; // The RFCOMM channel is now established
kotakku 0:b1ce54272580 437 sppIndex = 0;
kotakku 0:b1ce54272580 438 if(pFuncOnInit)
kotakku 0:b1ce54272580 439 pFuncOnInit(); // Call the user function
kotakku 0:b1ce54272580 440 };
kotakku 0:b1ce54272580 441
kotakku 0:b1ce54272580 442 void SPP::SDP_task() {
kotakku 0:b1ce54272580 443 switch(l2cap_sdp_state) {
kotakku 0:b1ce54272580 444 case L2CAP_SDP_WAIT:
kotakku 0:b1ce54272580 445 if(l2cap_check_flag(L2CAP_FLAG_CONNECTION_SDP_REQUEST)) {
kotakku 0:b1ce54272580 446 l2cap_clear_flag(L2CAP_FLAG_CONNECTION_SDP_REQUEST); // Clear flag
kotakku 0:b1ce54272580 447 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 448 Notify(PSTR("\r\nSDP Incoming Connection Request"), 0x80);
kotakku 0:b1ce54272580 449 #endif
kotakku 0:b1ce54272580 450 pBtd->l2cap_connection_response(hci_handle, identifier, sdp_dcid, sdp_scid, PENDING);
kotakku 0:b1ce54272580 451 delay(1);
kotakku 0:b1ce54272580 452 pBtd->l2cap_connection_response(hci_handle, identifier, sdp_dcid, sdp_scid, SUCCESSFUL);
kotakku 0:b1ce54272580 453 identifier++;
kotakku 0:b1ce54272580 454 delay(1);
kotakku 0:b1ce54272580 455 pBtd->l2cap_config_request(hci_handle, identifier, sdp_scid);
kotakku 0:b1ce54272580 456 l2cap_sdp_state = L2CAP_SDP_SUCCESS;
kotakku 0:b1ce54272580 457 } else if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_SDP_REQUEST)) {
kotakku 0:b1ce54272580 458 l2cap_clear_flag(L2CAP_FLAG_DISCONNECT_SDP_REQUEST); // Clear flag
kotakku 0:b1ce54272580 459 SDPConnected = false;
kotakku 0:b1ce54272580 460 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 461 Notify(PSTR("\r\nDisconnected SDP Channel"), 0x80);
kotakku 0:b1ce54272580 462 #endif
kotakku 0:b1ce54272580 463 pBtd->l2cap_disconnection_response(hci_handle, identifier, sdp_dcid, sdp_scid);
kotakku 0:b1ce54272580 464 }
kotakku 0:b1ce54272580 465 break;
kotakku 0:b1ce54272580 466 case L2CAP_SDP_SUCCESS:
kotakku 0:b1ce54272580 467 if(l2cap_check_flag(L2CAP_FLAG_CONFIG_SDP_SUCCESS)) {
kotakku 0:b1ce54272580 468 l2cap_clear_flag(L2CAP_FLAG_CONFIG_SDP_SUCCESS); // Clear flag
kotakku 0:b1ce54272580 469 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 470 Notify(PSTR("\r\nSDP Successfully Configured"), 0x80);
kotakku 0:b1ce54272580 471 #endif
kotakku 0:b1ce54272580 472 firstMessage = true; // Reset bool
kotakku 0:b1ce54272580 473 SDPConnected = true;
kotakku 0:b1ce54272580 474 l2cap_sdp_state = L2CAP_SDP_WAIT;
kotakku 0:b1ce54272580 475 }
kotakku 0:b1ce54272580 476 break;
kotakku 0:b1ce54272580 477
kotakku 0:b1ce54272580 478 case L2CAP_DISCONNECT_RESPONSE: // This is for both disconnection response from the RFCOMM and SDP channel if they were connected
kotakku 0:b1ce54272580 479 if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_RESPONSE)) {
kotakku 0:b1ce54272580 480 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 481 Notify(PSTR("\r\nDisconnected L2CAP Connection"), 0x80);
kotakku 0:b1ce54272580 482 #endif
kotakku 0:b1ce54272580 483 pBtd->hci_disconnect(hci_handle);
kotakku 0:b1ce54272580 484 hci_handle = -1; // Reset handle
kotakku 0:b1ce54272580 485 Reset();
kotakku 0:b1ce54272580 486 }
kotakku 0:b1ce54272580 487 break;
kotakku 0:b1ce54272580 488 }
kotakku 0:b1ce54272580 489 }
kotakku 0:b1ce54272580 490
kotakku 0:b1ce54272580 491 void SPP::RFCOMM_task() {
kotakku 0:b1ce54272580 492 switch(l2cap_rfcomm_state) {
kotakku 0:b1ce54272580 493 case L2CAP_RFCOMM_WAIT:
kotakku 0:b1ce54272580 494 if(l2cap_check_flag(L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST)) {
kotakku 0:b1ce54272580 495 l2cap_clear_flag(L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST); // Clear flag
kotakku 0:b1ce54272580 496 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 497 Notify(PSTR("\r\nRFCOMM Incoming Connection Request"), 0x80);
kotakku 0:b1ce54272580 498 #endif
kotakku 0:b1ce54272580 499 pBtd->l2cap_connection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid, PENDING);
kotakku 0:b1ce54272580 500 delay(1);
kotakku 0:b1ce54272580 501 pBtd->l2cap_connection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid, SUCCESSFUL);
kotakku 0:b1ce54272580 502 identifier++;
kotakku 0:b1ce54272580 503 delay(1);
kotakku 0:b1ce54272580 504 pBtd->l2cap_config_request(hci_handle, identifier, rfcomm_scid);
kotakku 0:b1ce54272580 505 l2cap_rfcomm_state = L2CAP_RFCOMM_SUCCESS;
kotakku 0:b1ce54272580 506 } else if(l2cap_check_flag(L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST)) {
kotakku 0:b1ce54272580 507 l2cap_clear_flag(L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST); // Clear flag
kotakku 0:b1ce54272580 508 RFCOMMConnected = false;
kotakku 0:b1ce54272580 509 connected = false;
kotakku 0:b1ce54272580 510 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 511 Notify(PSTR("\r\nDisconnected RFCOMM Channel"), 0x80);
kotakku 0:b1ce54272580 512 #endif
kotakku 0:b1ce54272580 513 pBtd->l2cap_disconnection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid);
kotakku 0:b1ce54272580 514 }
kotakku 0:b1ce54272580 515 break;
kotakku 0:b1ce54272580 516 case L2CAP_RFCOMM_SUCCESS:
kotakku 0:b1ce54272580 517 if(l2cap_check_flag(L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS)) {
kotakku 0:b1ce54272580 518 l2cap_clear_flag(L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS); // Clear flag
kotakku 0:b1ce54272580 519 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 520 Notify(PSTR("\r\nRFCOMM Successfully Configured"), 0x80);
kotakku 0:b1ce54272580 521 #endif
kotakku 0:b1ce54272580 522 rfcommAvailable = 0; // Reset number of bytes available
kotakku 0:b1ce54272580 523 bytesRead = 0; // Reset number of bytes received
kotakku 0:b1ce54272580 524 RFCOMMConnected = true;
kotakku 0:b1ce54272580 525 l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT;
kotakku 0:b1ce54272580 526 }
kotakku 0:b1ce54272580 527 break;
kotakku 0:b1ce54272580 528 }
kotakku 0:b1ce54272580 529 }
kotakku 0:b1ce54272580 530 /************************************************************/
kotakku 0:b1ce54272580 531 /* SDP Commands */
kotakku 0:b1ce54272580 532
kotakku 0:b1ce54272580 533 /************************************************************/
kotakku 0:b1ce54272580 534 void SPP::SDP_Command(uint8_t* data, uint8_t nbytes) { // See page 223 in the Bluetooth specs
kotakku 0:b1ce54272580 535 pBtd->L2CAP_Command(hci_handle, data, nbytes, sdp_scid[0], sdp_scid[1]);
kotakku 0:b1ce54272580 536 }
kotakku 0:b1ce54272580 537
kotakku 0:b1ce54272580 538 void SPP::serviceNotSupported(uint8_t transactionIDHigh, uint8_t transactionIDLow) { // See page 235 in the Bluetooth specs
kotakku 0:b1ce54272580 539 l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU;
kotakku 0:b1ce54272580 540 l2capoutbuf[1] = transactionIDHigh;
kotakku 0:b1ce54272580 541 l2capoutbuf[2] = transactionIDLow;
kotakku 0:b1ce54272580 542 l2capoutbuf[3] = 0x00; // MSB Parameter Length
kotakku 0:b1ce54272580 543 l2capoutbuf[4] = 0x05; // LSB Parameter Length = 5
kotakku 0:b1ce54272580 544 l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount
kotakku 0:b1ce54272580 545 l2capoutbuf[6] = 0x02; // LSB AttributeListsByteCount = 2
kotakku 0:b1ce54272580 546
kotakku 0:b1ce54272580 547 /* Attribute ID/Value Sequence: */
kotakku 0:b1ce54272580 548 l2capoutbuf[7] = 0x35; // Data element sequence - length in next byte
kotakku 0:b1ce54272580 549 l2capoutbuf[8] = 0x00; // Length = 0
kotakku 0:b1ce54272580 550 l2capoutbuf[9] = 0x00; // No continuation state
kotakku 0:b1ce54272580 551
kotakku 0:b1ce54272580 552 SDP_Command(l2capoutbuf, 10);
kotakku 0:b1ce54272580 553 }
kotakku 0:b1ce54272580 554
kotakku 0:b1ce54272580 555 void SPP::serialPortResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
kotakku 0:b1ce54272580 556 l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU;
kotakku 0:b1ce54272580 557 l2capoutbuf[1] = transactionIDHigh;
kotakku 0:b1ce54272580 558 l2capoutbuf[2] = transactionIDLow;
kotakku 0:b1ce54272580 559 l2capoutbuf[3] = 0x00; // MSB Parameter Length
kotakku 0:b1ce54272580 560 l2capoutbuf[4] = 0x2B; // LSB Parameter Length = 43
kotakku 0:b1ce54272580 561 l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount
kotakku 0:b1ce54272580 562 l2capoutbuf[6] = 0x26; // LSB AttributeListsByteCount = 38
kotakku 0:b1ce54272580 563
kotakku 0:b1ce54272580 564 /* Attribute ID/Value Sequence: */
kotakku 0:b1ce54272580 565 l2capoutbuf[7] = 0x36; // Data element sequence - length in next two bytes
kotakku 0:b1ce54272580 566 l2capoutbuf[8] = 0x00; // MSB Length
kotakku 0:b1ce54272580 567 l2capoutbuf[9] = 0x3C; // LSB Length = 60
kotakku 0:b1ce54272580 568
kotakku 0:b1ce54272580 569 l2capoutbuf[10] = 0x36; // Data element sequence - length in next two bytes
kotakku 0:b1ce54272580 570 l2capoutbuf[11] = 0x00; // MSB Length
kotakku 0:b1ce54272580 571 l2capoutbuf[12] = 0x39; // LSB Length = 57
kotakku 0:b1ce54272580 572
kotakku 0:b1ce54272580 573 l2capoutbuf[13] = 0x09; // Unsigned Integer - length 2 bytes
kotakku 0:b1ce54272580 574 l2capoutbuf[14] = 0x00; // MSB ServiceRecordHandle
kotakku 0:b1ce54272580 575 l2capoutbuf[15] = 0x00; // LSB ServiceRecordHandle
kotakku 0:b1ce54272580 576 l2capoutbuf[16] = 0x0A; // Unsigned int - length 4 bytes
kotakku 0:b1ce54272580 577 l2capoutbuf[17] = 0x00; // ServiceRecordHandle value - TODO: Is this related to HCI_Handle?
kotakku 0:b1ce54272580 578 l2capoutbuf[18] = 0x01;
kotakku 0:b1ce54272580 579 l2capoutbuf[19] = 0x00;
kotakku 0:b1ce54272580 580 l2capoutbuf[20] = 0x06;
kotakku 0:b1ce54272580 581
kotakku 0:b1ce54272580 582 l2capoutbuf[21] = 0x09; // Unsigned Integer - length 2 bytes
kotakku 0:b1ce54272580 583 l2capoutbuf[22] = 0x00; // MSB ServiceClassIDList
kotakku 0:b1ce54272580 584 l2capoutbuf[23] = 0x01; // LSB ServiceClassIDList
kotakku 0:b1ce54272580 585 l2capoutbuf[24] = 0x35; // Data element sequence - length in next byte
kotakku 0:b1ce54272580 586 l2capoutbuf[25] = 0x03; // Length = 3
kotakku 0:b1ce54272580 587 l2capoutbuf[26] = 0x19; // UUID (universally unique identifier) - length = 2 bytes
kotakku 0:b1ce54272580 588 l2capoutbuf[27] = 0x11; // MSB SerialPort
kotakku 0:b1ce54272580 589 l2capoutbuf[28] = 0x01; // LSB SerialPort
kotakku 0:b1ce54272580 590
kotakku 0:b1ce54272580 591 l2capoutbuf[29] = 0x09; // Unsigned Integer - length 2 bytes
kotakku 0:b1ce54272580 592 l2capoutbuf[30] = 0x00; // MSB ProtocolDescriptorList
kotakku 0:b1ce54272580 593 l2capoutbuf[31] = 0x04; // LSB ProtocolDescriptorList
kotakku 0:b1ce54272580 594 l2capoutbuf[32] = 0x35; // Data element sequence - length in next byte
kotakku 0:b1ce54272580 595 l2capoutbuf[33] = 0x0C; // Length = 12
kotakku 0:b1ce54272580 596
kotakku 0:b1ce54272580 597 l2capoutbuf[34] = 0x35; // Data element sequence - length in next byte
kotakku 0:b1ce54272580 598 l2capoutbuf[35] = 0x03; // Length = 3
kotakku 0:b1ce54272580 599 l2capoutbuf[36] = 0x19; // UUID (universally unique identifier) - length = 2 bytes
kotakku 0:b1ce54272580 600 l2capoutbuf[37] = 0x01; // MSB L2CAP
kotakku 0:b1ce54272580 601 l2capoutbuf[38] = 0x00; // LSB L2CAP
kotakku 0:b1ce54272580 602
kotakku 0:b1ce54272580 603 l2capoutbuf[39] = 0x35; // Data element sequence - length in next byte
kotakku 0:b1ce54272580 604 l2capoutbuf[40] = 0x05; // Length = 5
kotakku 0:b1ce54272580 605 l2capoutbuf[41] = 0x19; // UUID (universally unique identifier) - length = 2 bytes
kotakku 0:b1ce54272580 606 l2capoutbuf[42] = 0x00; // MSB RFCOMM
kotakku 0:b1ce54272580 607 l2capoutbuf[43] = 0x03; // LSB RFCOMM
kotakku 0:b1ce54272580 608 l2capoutbuf[44] = 0x08; // Unsigned Integer - length 1 byte
kotakku 0:b1ce54272580 609
kotakku 0:b1ce54272580 610 l2capoutbuf[45] = 0x02; // ContinuationState - Two more bytes
kotakku 0:b1ce54272580 611 l2capoutbuf[46] = 0x00; // MSB length
kotakku 0:b1ce54272580 612 l2capoutbuf[47] = 0x19; // LSB length = 25 more bytes to come
kotakku 0:b1ce54272580 613
kotakku 0:b1ce54272580 614 SDP_Command(l2capoutbuf, 48);
kotakku 0:b1ce54272580 615 }
kotakku 0:b1ce54272580 616
kotakku 0:b1ce54272580 617 void SPP::serialPortResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
kotakku 0:b1ce54272580 618 l2capoutbuf[0] = SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU;
kotakku 0:b1ce54272580 619 l2capoutbuf[1] = transactionIDHigh;
kotakku 0:b1ce54272580 620 l2capoutbuf[2] = transactionIDLow;
kotakku 0:b1ce54272580 621 l2capoutbuf[3] = 0x00; // MSB Parameter Length
kotakku 0:b1ce54272580 622 l2capoutbuf[4] = 0x1C; // LSB Parameter Length = 28
kotakku 0:b1ce54272580 623 l2capoutbuf[5] = 0x00; // MSB AttributeListsByteCount
kotakku 0:b1ce54272580 624 l2capoutbuf[6] = 0x19; // LSB AttributeListsByteCount = 25
kotakku 0:b1ce54272580 625
kotakku 0:b1ce54272580 626 /* Attribute ID/Value Sequence: */
kotakku 0:b1ce54272580 627 l2capoutbuf[7] = 0x01; // Channel 1 - TODO: Try different values, so multiple servers can be used at once
kotakku 0:b1ce54272580 628
kotakku 0:b1ce54272580 629 l2capoutbuf[8] = 0x09; // Unsigned Integer - length 2 bytes
kotakku 0:b1ce54272580 630 l2capoutbuf[9] = 0x00; // MSB LanguageBaseAttributeIDList
kotakku 0:b1ce54272580 631 l2capoutbuf[10] = 0x06; // LSB LanguageBaseAttributeIDList
kotakku 0:b1ce54272580 632 l2capoutbuf[11] = 0x35; // Data element sequence - length in next byte
kotakku 0:b1ce54272580 633 l2capoutbuf[12] = 0x09; // Length = 9
kotakku 0:b1ce54272580 634
kotakku 0:b1ce54272580 635 // Identifier representing the natural language = en = English - see: "ISO 639:1988"
kotakku 0:b1ce54272580 636 l2capoutbuf[13] = 0x09; // Unsigned Integer - length 2 bytes
kotakku 0:b1ce54272580 637 l2capoutbuf[14] = 0x65; // 'e'
kotakku 0:b1ce54272580 638 l2capoutbuf[15] = 0x6E; // 'n'
kotakku 0:b1ce54272580 639
kotakku 0:b1ce54272580 640 // "The second element of each triplet contains an identifier that specifies a character encoding used for the language"
kotakku 0:b1ce54272580 641 // Encoding is set to 106 (UTF-8) - see: http://www.iana.org/assignments/character-sets/character-sets.xhtml
kotakku 0:b1ce54272580 642 l2capoutbuf[16] = 0x09; // Unsigned Integer - length 2 bytes
kotakku 0:b1ce54272580 643 l2capoutbuf[17] = 0x00; // MSB of character encoding
kotakku 0:b1ce54272580 644 l2capoutbuf[18] = 0x6A; // LSB of character encoding (106)
kotakku 0:b1ce54272580 645
kotakku 0:b1ce54272580 646 // Attribute ID that serves as the base attribute ID for the natural language in the service record
kotakku 0:b1ce54272580 647 // "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"
kotakku 0:b1ce54272580 648 l2capoutbuf[19] = 0x09; // Unsigned Integer - length 2 bytes
kotakku 0:b1ce54272580 649 l2capoutbuf[20] = 0x01;
kotakku 0:b1ce54272580 650 l2capoutbuf[21] = 0x00;
kotakku 0:b1ce54272580 651
kotakku 0:b1ce54272580 652 l2capoutbuf[22] = 0x09; // Unsigned Integer - length 2 bytes
kotakku 0:b1ce54272580 653 l2capoutbuf[23] = 0x01; // MSB ServiceDescription
kotakku 0:b1ce54272580 654 l2capoutbuf[24] = 0x00; // LSB ServiceDescription
kotakku 0:b1ce54272580 655
kotakku 0:b1ce54272580 656 l2capoutbuf[25] = 0x25; // Text string - length in next byte
kotakku 0:b1ce54272580 657 l2capoutbuf[26] = 0x05; // Name length
kotakku 0:b1ce54272580 658 l2capoutbuf[27] = 'T';
kotakku 0:b1ce54272580 659 l2capoutbuf[28] = 'K';
kotakku 0:b1ce54272580 660 l2capoutbuf[29] = 'J';
kotakku 0:b1ce54272580 661 l2capoutbuf[30] = 'S';
kotakku 0:b1ce54272580 662 l2capoutbuf[31] = 'P';
kotakku 0:b1ce54272580 663 l2capoutbuf[32] = 0x00; // No continuation state
kotakku 0:b1ce54272580 664
kotakku 0:b1ce54272580 665 SDP_Command(l2capoutbuf, 33);
kotakku 0:b1ce54272580 666 }
kotakku 0:b1ce54272580 667
kotakku 0:b1ce54272580 668 void SPP::l2capResponse1(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
kotakku 0:b1ce54272580 669 serialPortResponse1(transactionIDHigh, transactionIDLow); // These has to send all the supported functions, since it only supports virtual serialport it just sends the message again
kotakku 0:b1ce54272580 670 }
kotakku 0:b1ce54272580 671
kotakku 0:b1ce54272580 672 void SPP::l2capResponse2(uint8_t transactionIDHigh, uint8_t transactionIDLow) {
kotakku 0:b1ce54272580 673 serialPortResponse2(transactionIDHigh, transactionIDLow); // Same data as serialPortResponse2
kotakku 0:b1ce54272580 674 }
kotakku 0:b1ce54272580 675 /************************************************************/
kotakku 0:b1ce54272580 676 /* RFCOMM Commands */
kotakku 0:b1ce54272580 677
kotakku 0:b1ce54272580 678 /************************************************************/
kotakku 0:b1ce54272580 679 void SPP::RFCOMM_Command(uint8_t* data, uint8_t nbytes) {
kotakku 0:b1ce54272580 680 pBtd->L2CAP_Command(hci_handle, data, nbytes, rfcomm_scid[0], rfcomm_scid[1]);
kotakku 0:b1ce54272580 681 }
kotakku 0:b1ce54272580 682
kotakku 0:b1ce54272580 683 void SPP::sendRfcomm(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t* data, uint8_t length) {
kotakku 0:b1ce54272580 684 l2capoutbuf[0] = channel | direction | CR | extendAddress; // RFCOMM Address
kotakku 0:b1ce54272580 685 l2capoutbuf[1] = channelType | pfBit; // RFCOMM Control
kotakku 0:b1ce54272580 686 l2capoutbuf[2] = length << 1 | 0x01; // Length and format (always 0x01 bytes format)
kotakku 0:b1ce54272580 687 uint8_t i = 0;
kotakku 0:b1ce54272580 688 for(; i < length; i++)
kotakku 0:b1ce54272580 689 l2capoutbuf[i + 3] = data[i];
kotakku 0:b1ce54272580 690 l2capoutbuf[i + 3] = calcFcs(l2capoutbuf);
kotakku 0:b1ce54272580 691 #ifdef EXTRADEBUG
kotakku 0:b1ce54272580 692 Notify(PSTR(" - RFCOMM Data: "), 0x80);
kotakku 0:b1ce54272580 693 for(i = 0; i < length + 4; i++) {
kotakku 0:b1ce54272580 694 D_PrintHex<uint8_t > (l2capoutbuf[i], 0x80);
kotakku 0:b1ce54272580 695 Notify(PSTR(" "), 0x80);
kotakku 0:b1ce54272580 696 }
kotakku 0:b1ce54272580 697 #endif
kotakku 0:b1ce54272580 698 RFCOMM_Command(l2capoutbuf, length + 4);
kotakku 0:b1ce54272580 699 }
kotakku 0:b1ce54272580 700
kotakku 0:b1ce54272580 701 void SPP::sendRfcommCredit(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t channelType, uint8_t pfBit, uint8_t credit) {
kotakku 0:b1ce54272580 702 l2capoutbuf[0] = channel | direction | CR | extendAddress; // RFCOMM Address
kotakku 0:b1ce54272580 703 l2capoutbuf[1] = channelType | pfBit; // RFCOMM Control
kotakku 0:b1ce54272580 704 l2capoutbuf[2] = 0x01; // Length = 0
kotakku 0:b1ce54272580 705 l2capoutbuf[3] = credit; // Credit
kotakku 0:b1ce54272580 706 l2capoutbuf[4] = calcFcs(l2capoutbuf);
kotakku 0:b1ce54272580 707 #ifdef EXTRADEBUG
kotakku 0:b1ce54272580 708 Notify(PSTR(" - RFCOMM Credit Data: "), 0x80);
kotakku 0:b1ce54272580 709 for(uint8_t i = 0; i < 5; i++) {
kotakku 0:b1ce54272580 710 D_PrintHex<uint8_t > (l2capoutbuf[i], 0x80);
kotakku 0:b1ce54272580 711 Notify(PSTR(" "), 0x80);
kotakku 0:b1ce54272580 712 }
kotakku 0:b1ce54272580 713 #endif
kotakku 0:b1ce54272580 714 RFCOMM_Command(l2capoutbuf, 5);
kotakku 0:b1ce54272580 715 }
kotakku 0:b1ce54272580 716
kotakku 0:b1ce54272580 717 /* CRC on 2 bytes */
kotakku 0:b1ce54272580 718 uint8_t SPP::crc(uint8_t *data) {
kotakku 0:b1ce54272580 719 return (pgm_read_byte(&rfcomm_crc_table[pgm_read_byte(&rfcomm_crc_table[0xFF ^ data[0]]) ^ data[1]]));
kotakku 0:b1ce54272580 720 }
kotakku 0:b1ce54272580 721
kotakku 0:b1ce54272580 722 /* Calculate FCS */
kotakku 0:b1ce54272580 723 uint8_t SPP::calcFcs(uint8_t *data) {
kotakku 0:b1ce54272580 724 uint8_t temp = crc(data);
kotakku 0:b1ce54272580 725 if((data[1] & 0xEF) == RFCOMM_UIH)
kotakku 0:b1ce54272580 726 return (0xFF - temp); // FCS on 2 bytes
kotakku 0:b1ce54272580 727 else
kotakku 0:b1ce54272580 728 return (0xFF - pgm_read_byte(&rfcomm_crc_table[temp ^ data[2]])); // FCS on 3 bytes
kotakku 0:b1ce54272580 729 }
kotakku 0:b1ce54272580 730
kotakku 0:b1ce54272580 731 /* Check FCS */
kotakku 0:b1ce54272580 732 bool SPP::checkFcs(uint8_t *data, uint8_t fcs) {
kotakku 0:b1ce54272580 733 uint8_t temp = crc(data);
kotakku 0:b1ce54272580 734 if((data[1] & 0xEF) != RFCOMM_UIH)
kotakku 0:b1ce54272580 735 temp = pgm_read_byte(&rfcomm_crc_table[temp ^ data[2]]); // FCS on 3 bytes
kotakku 0:b1ce54272580 736 return (pgm_read_byte(&rfcomm_crc_table[temp ^ fcs]) == 0xCF);
kotakku 0:b1ce54272580 737 }
kotakku 0:b1ce54272580 738
kotakku 0:b1ce54272580 739 /* Serial commands */
kotakku 0:b1ce54272580 740 #if defined(ARDUINO) && ARDUINO >=100
kotakku 0:b1ce54272580 741
kotakku 0:b1ce54272580 742 size_t SPP::write(uint8_t data) {
kotakku 0:b1ce54272580 743 return write(&data, 1);
kotakku 0:b1ce54272580 744 }
kotakku 0:b1ce54272580 745 #else
kotakku 0:b1ce54272580 746
kotakku 0:b1ce54272580 747 void SPP::write(uint8_t data) {
kotakku 0:b1ce54272580 748 write(&data, 1);
kotakku 0:b1ce54272580 749 }
kotakku 0:b1ce54272580 750 #endif
kotakku 0:b1ce54272580 751
kotakku 0:b1ce54272580 752 #if defined(ARDUINO) && ARDUINO >=100
kotakku 0:b1ce54272580 753
kotakku 0:b1ce54272580 754 size_t SPP::write(const uint8_t *data, size_t size) {
kotakku 0:b1ce54272580 755 #else
kotakku 0:b1ce54272580 756
kotakku 0:b1ce54272580 757 void SPP::write(const uint8_t *data, size_t size) {
kotakku 0:b1ce54272580 758 #endif
kotakku 0:b1ce54272580 759 for(uint8_t i = 0; i < size; i++) {
kotakku 0:b1ce54272580 760 if(sppIndex >= sizeof (sppOutputBuffer) / sizeof (sppOutputBuffer[0]))
kotakku 0:b1ce54272580 761 send(); // Send the current data in the buffer
kotakku 0:b1ce54272580 762 sppOutputBuffer[sppIndex++] = data[i]; // All the bytes are put into a buffer and then send using the send() function
kotakku 0:b1ce54272580 763 }
kotakku 0:b1ce54272580 764 #if defined(ARDUINO) && ARDUINO >=100
kotakku 0:b1ce54272580 765 return size;
kotakku 0:b1ce54272580 766 #endif
kotakku 0:b1ce54272580 767 }
kotakku 0:b1ce54272580 768
kotakku 0:b1ce54272580 769 void SPP::send() {
kotakku 0:b1ce54272580 770 if(!connected || !sppIndex)
kotakku 0:b1ce54272580 771 return;
kotakku 0:b1ce54272580 772 uint8_t length; // This is the length of the string we are sending
kotakku 0:b1ce54272580 773 uint8_t offset = 0; // This is used to keep track of where we are in the string
kotakku 0:b1ce54272580 774
kotakku 0:b1ce54272580 775 l2capoutbuf[0] = rfcommChannelConnection | 0 | 0 | extendAddress; // RFCOMM Address
kotakku 0:b1ce54272580 776 l2capoutbuf[1] = RFCOMM_UIH; // RFCOMM Control
kotakku 0:b1ce54272580 777
kotakku 0:b1ce54272580 778 while(sppIndex) { // We will run this while loop until this variable is 0
kotakku 0:b1ce54272580 779 if(sppIndex > (sizeof (l2capoutbuf) - 4)) // Check if the string is larger than the outgoing buffer
kotakku 0:b1ce54272580 780 length = sizeof (l2capoutbuf) - 4;
kotakku 0:b1ce54272580 781 else
kotakku 0:b1ce54272580 782 length = sppIndex;
kotakku 0:b1ce54272580 783
kotakku 0:b1ce54272580 784 l2capoutbuf[2] = length << 1 | 1; // Length
kotakku 0:b1ce54272580 785 uint8_t i = 0;
kotakku 0:b1ce54272580 786 for(; i < length; i++)
kotakku 0:b1ce54272580 787 l2capoutbuf[i + 3] = sppOutputBuffer[i + offset];
kotakku 0:b1ce54272580 788 l2capoutbuf[i + 3] = calcFcs(l2capoutbuf); // Calculate checksum
kotakku 0:b1ce54272580 789
kotakku 0:b1ce54272580 790 RFCOMM_Command(l2capoutbuf, length + 4);
kotakku 0:b1ce54272580 791
kotakku 0:b1ce54272580 792 sppIndex -= length;
kotakku 0:b1ce54272580 793 offset += length; // Increment the offset
kotakku 0:b1ce54272580 794 }
kotakku 0:b1ce54272580 795 }
kotakku 0:b1ce54272580 796
kotakku 0:b1ce54272580 797 int SPP::available(void) {
kotakku 0:b1ce54272580 798 return rfcommAvailable;
kotakku 0:b1ce54272580 799 };
kotakku 0:b1ce54272580 800
kotakku 0:b1ce54272580 801 void SPP::discard(void) {
kotakku 0:b1ce54272580 802 rfcommAvailable = 0;
kotakku 0:b1ce54272580 803 }
kotakku 0:b1ce54272580 804
kotakku 0:b1ce54272580 805 int SPP::peek(void) {
kotakku 0:b1ce54272580 806 if(rfcommAvailable == 0) // Don't read if there is nothing in the buffer
kotakku 0:b1ce54272580 807 return -1;
kotakku 0:b1ce54272580 808 return rfcommDataBuffer[0];
kotakku 0:b1ce54272580 809 }
kotakku 0:b1ce54272580 810
kotakku 0:b1ce54272580 811 int SPP::read(void) {
kotakku 0:b1ce54272580 812 if(rfcommAvailable == 0) // Don't read if there is nothing in the buffer
kotakku 0:b1ce54272580 813 return -1;
kotakku 0:b1ce54272580 814 uint8_t output = rfcommDataBuffer[0];
kotakku 0:b1ce54272580 815 for(uint8_t i = 1; i < rfcommAvailable; i++)
kotakku 0:b1ce54272580 816 rfcommDataBuffer[i - 1] = rfcommDataBuffer[i]; // Shift the buffer one left
kotakku 0:b1ce54272580 817 rfcommAvailable--;
kotakku 0:b1ce54272580 818 bytesRead++;
kotakku 0:b1ce54272580 819 if(bytesRead > (sizeof (rfcommDataBuffer) - 5)) { // We will send the command just before it runs out of credit
kotakku 0:b1ce54272580 820 bytesRead = 0;
kotakku 0:b1ce54272580 821 sendRfcommCredit(rfcommChannelConnection, rfcommDirection, 0, RFCOMM_UIH, 0x10, sizeof (rfcommDataBuffer)); // Send more credit
kotakku 0:b1ce54272580 822 #ifdef EXTRADEBUG
kotakku 0:b1ce54272580 823 Notify(PSTR("\r\nSent "), 0x80);
kotakku 0:b1ce54272580 824 Notify((uint8_t)sizeof (rfcommDataBuffer), 0x80);
kotakku 0:b1ce54272580 825 Notify(PSTR(" more credit"), 0x80);
kotakku 0:b1ce54272580 826 #endif
kotakku 0:b1ce54272580 827 }
kotakku 0:b1ce54272580 828 return output;
kotakku 0:b1ce54272580 829 }
kotakku 0:b1ce54272580 830