Library to use Arduino USB host shield on mbed
ArduinoのUSB Host Shield 2.0をmbedで使えるようにしたライブラリです。
大体のコードがArduinoからそのまま移植可能です。
Arduino UNOやMega用のホストシールド以外にもミニサイズのホストシールドでも使用可能です
シールドについて
3.3VのI/O用にシールドの改造が必要になりますがネット上に記事がたくさんあるのでそちらを参考にしてください
接続例
使い方
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"); } } }
USB_Host/BTD.cpp@1:da31140f2a1c, 2020-05-02 (annotated)
- Committer:
- robo_ichinoseki_a
- Date:
- Sat May 02 05:56:48 2020 +0000
- Revision:
- 1:da31140f2a1c
- Parent:
- 0:b1ce54272580
update
Who changed what in which revision?
User | Revision | Line number | New 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 "BTD.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 | |
kotakku | 0:b1ce54272580 | 22 | const uint8_t BTD::BTD_CONTROL_PIPE = 0; |
kotakku | 0:b1ce54272580 | 23 | const uint8_t BTD::BTD_EVENT_PIPE = 1; |
kotakku | 0:b1ce54272580 | 24 | const uint8_t BTD::BTD_DATAIN_PIPE = 2; |
kotakku | 0:b1ce54272580 | 25 | const uint8_t BTD::BTD_DATAOUT_PIPE = 3; |
kotakku | 0:b1ce54272580 | 26 | |
kotakku | 0:b1ce54272580 | 27 | BTD::BTD(USB *p) : |
kotakku | 0:b1ce54272580 | 28 | connectToWii(false), |
kotakku | 0:b1ce54272580 | 29 | pairWithWii(false), |
kotakku | 0:b1ce54272580 | 30 | connectToHIDDevice(false), |
kotakku | 0:b1ce54272580 | 31 | pairWithHIDDevice(false), |
kotakku | 0:b1ce54272580 | 32 | pUsb(p), // Pointer to USB class instance - mandatory |
kotakku | 0:b1ce54272580 | 33 | bAddress(0), // Device address - mandatory |
kotakku | 0:b1ce54272580 | 34 | bNumEP(1), // If config descriptor needs to be parsed |
kotakku | 0:b1ce54272580 | 35 | qNextPollTime(0), // Reset NextPollTime |
kotakku | 0:b1ce54272580 | 36 | pollInterval(0), |
kotakku | 0:b1ce54272580 | 37 | bPollEnable(false) // Don't start polling before dongle is connected |
kotakku | 0:b1ce54272580 | 38 | { |
kotakku | 0:b1ce54272580 | 39 | for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++) |
kotakku | 0:b1ce54272580 | 40 | btService[i] = NULL; |
kotakku | 0:b1ce54272580 | 41 | |
kotakku | 0:b1ce54272580 | 42 | Initialize(); // Set all variables, endpoint structs etc. to default values |
kotakku | 0:b1ce54272580 | 43 | |
kotakku | 0:b1ce54272580 | 44 | if(pUsb) // Register in USB subsystem |
kotakku | 0:b1ce54272580 | 45 | pUsb->RegisterDeviceClass(this); // Set devConfig[] entry |
kotakku | 0:b1ce54272580 | 46 | } |
kotakku | 0:b1ce54272580 | 47 | |
kotakku | 0:b1ce54272580 | 48 | uint8_t BTD::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) { |
kotakku | 0:b1ce54272580 | 49 | const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR); |
kotakku | 0:b1ce54272580 | 50 | uint8_t buf[constBufSize]; |
kotakku | 0:b1ce54272580 | 51 | USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf); |
kotakku | 0:b1ce54272580 | 52 | uint8_t rcode; |
kotakku | 0:b1ce54272580 | 53 | UsbDevice *p = NULL; |
kotakku | 0:b1ce54272580 | 54 | EpInfo *oldep_ptr = NULL; |
kotakku | 0:b1ce54272580 | 55 | |
kotakku | 0:b1ce54272580 | 56 | Initialize(); // Set all variables, endpoint structs etc. to default values |
kotakku | 0:b1ce54272580 | 57 | |
kotakku | 0:b1ce54272580 | 58 | AddressPool &addrPool = pUsb->GetAddressPool(); // Get memory address of USB device address pool |
kotakku | 0:b1ce54272580 | 59 | #ifdef EXTRADEBUG |
kotakku | 0:b1ce54272580 | 60 | Notify(PSTR("\r\nBTD ConfigureDevice"), 0x80); |
kotakku | 0:b1ce54272580 | 61 | #endif |
kotakku | 0:b1ce54272580 | 62 | |
kotakku | 0:b1ce54272580 | 63 | if(bAddress) { // Check if address has already been assigned to an instance |
kotakku | 0:b1ce54272580 | 64 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 65 | Notify(PSTR("\r\nAddress in use"), 0x80); |
kotakku | 0:b1ce54272580 | 66 | #endif |
kotakku | 0:b1ce54272580 | 67 | return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; |
kotakku | 0:b1ce54272580 | 68 | } |
kotakku | 0:b1ce54272580 | 69 | |
kotakku | 0:b1ce54272580 | 70 | p = addrPool.GetUsbDevicePtr(0); // Get pointer to pseudo device with address 0 assigned |
kotakku | 0:b1ce54272580 | 71 | if(!p) { |
kotakku | 0:b1ce54272580 | 72 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 73 | Notify(PSTR("\r\nAddress not found"), 0x80); |
kotakku | 0:b1ce54272580 | 74 | #endif |
kotakku | 0:b1ce54272580 | 75 | return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; |
kotakku | 0:b1ce54272580 | 76 | } |
kotakku | 0:b1ce54272580 | 77 | |
kotakku | 0:b1ce54272580 | 78 | if(!p->epinfo) { |
kotakku | 0:b1ce54272580 | 79 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 80 | Notify(PSTR("\r\nepinfo is null"), 0x80); |
kotakku | 0:b1ce54272580 | 81 | #endif |
kotakku | 0:b1ce54272580 | 82 | return USB_ERROR_EPINFO_IS_NULL; |
kotakku | 0:b1ce54272580 | 83 | } |
kotakku | 0:b1ce54272580 | 84 | |
kotakku | 0:b1ce54272580 | 85 | oldep_ptr = p->epinfo; // Save old pointer to EP_RECORD of address 0 |
kotakku | 0:b1ce54272580 | 86 | p->epinfo = epInfo; // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence |
kotakku | 0:b1ce54272580 | 87 | p->lowspeed = lowspeed; |
kotakku | 0:b1ce54272580 | 88 | rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data |
kotakku | 0:b1ce54272580 | 89 | |
kotakku | 0:b1ce54272580 | 90 | p->epinfo = oldep_ptr; // Restore p->epinfo |
kotakku | 0:b1ce54272580 | 91 | |
kotakku | 0:b1ce54272580 | 92 | if(rcode) |
kotakku | 0:b1ce54272580 | 93 | goto FailGetDevDescr; |
kotakku | 0:b1ce54272580 | 94 | |
kotakku | 0:b1ce54272580 | 95 | bAddress = addrPool.AllocAddress(parent, false, port); // Allocate new address according to device class |
kotakku | 0:b1ce54272580 | 96 | |
kotakku | 0:b1ce54272580 | 97 | if(!bAddress) { |
kotakku | 0:b1ce54272580 | 98 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 99 | Notify(PSTR("\r\nOut of address space"), 0x80); |
kotakku | 0:b1ce54272580 | 100 | #endif |
kotakku | 0:b1ce54272580 | 101 | return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; |
kotakku | 0:b1ce54272580 | 102 | } |
kotakku | 0:b1ce54272580 | 103 | |
kotakku | 0:b1ce54272580 | 104 | if (udd->bDeviceClass == 0x09) // Some dongles have an USB hub inside |
kotakku | 0:b1ce54272580 | 105 | goto FailHub; |
kotakku | 0:b1ce54272580 | 106 | |
kotakku | 0:b1ce54272580 | 107 | epInfo[0].maxPktSize = udd->bMaxPacketSize0; // Extract Max Packet Size from device descriptor |
kotakku | 0:b1ce54272580 | 108 | epInfo[1].epAddr = udd->bNumConfigurations; // Steal and abuse from epInfo structure to save memory |
kotakku | 0:b1ce54272580 | 109 | |
kotakku | 0:b1ce54272580 | 110 | VID = udd->idVendor; |
kotakku | 0:b1ce54272580 | 111 | PID = udd->idProduct; |
kotakku | 0:b1ce54272580 | 112 | |
kotakku | 0:b1ce54272580 | 113 | return USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET; |
kotakku | 0:b1ce54272580 | 114 | |
kotakku | 0:b1ce54272580 | 115 | FailHub: |
kotakku | 0:b1ce54272580 | 116 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 117 | Notify(PSTR("\r\nPlease create a hub instance in your code: \"USBHub Hub1(&Usb);\""), 0x80); |
kotakku | 0:b1ce54272580 | 118 | #endif |
kotakku | 0:b1ce54272580 | 119 | pUsb->setAddr(bAddress, 0, 0); // Reset address |
kotakku | 0:b1ce54272580 | 120 | rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; |
kotakku | 0:b1ce54272580 | 121 | Release(); |
kotakku | 0:b1ce54272580 | 122 | return rcode; |
kotakku | 0:b1ce54272580 | 123 | |
kotakku | 0:b1ce54272580 | 124 | FailGetDevDescr: |
kotakku | 0:b1ce54272580 | 125 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 126 | NotifyFailGetDevDescr(rcode); |
kotakku | 0:b1ce54272580 | 127 | #endif |
kotakku | 0:b1ce54272580 | 128 | if(rcode != hrJERR) |
kotakku | 0:b1ce54272580 | 129 | rcode = USB_ERROR_FailGetDevDescr; |
kotakku | 0:b1ce54272580 | 130 | Release(); |
kotakku | 0:b1ce54272580 | 131 | return rcode; |
kotakku | 0:b1ce54272580 | 132 | }; |
kotakku | 0:b1ce54272580 | 133 | |
kotakku | 0:b1ce54272580 | 134 | uint8_t BTD::Init(uint8_t parent __attribute__((unused)), uint8_t port __attribute__((unused)), bool lowspeed) { |
kotakku | 0:b1ce54272580 | 135 | uint8_t rcode; |
kotakku | 0:b1ce54272580 | 136 | uint8_t num_of_conf = epInfo[1].epAddr; // Number of configurations |
kotakku | 0:b1ce54272580 | 137 | epInfo[1].epAddr = 0; |
kotakku | 0:b1ce54272580 | 138 | |
kotakku | 0:b1ce54272580 | 139 | AddressPool &addrPool = pUsb->GetAddressPool(); |
kotakku | 0:b1ce54272580 | 140 | #ifdef EXTRADEBUG |
kotakku | 0:b1ce54272580 | 141 | Notify(PSTR("\r\nBTD Init"), 0x80); |
kotakku | 0:b1ce54272580 | 142 | #endif |
kotakku | 0:b1ce54272580 | 143 | UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress); // Get pointer to assigned address record |
kotakku | 0:b1ce54272580 | 144 | |
kotakku | 0:b1ce54272580 | 145 | if(!p) { |
kotakku | 0:b1ce54272580 | 146 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 147 | Notify(PSTR("\r\nAddress not found"), 0x80); |
kotakku | 0:b1ce54272580 | 148 | #endif |
kotakku | 0:b1ce54272580 | 149 | return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; |
kotakku | 0:b1ce54272580 | 150 | } |
kotakku | 0:b1ce54272580 | 151 | |
kotakku | 0:b1ce54272580 | 152 | delay(300); // Assign new address to the device |
kotakku | 0:b1ce54272580 | 153 | |
kotakku | 0:b1ce54272580 | 154 | rcode = pUsb->setAddr(0, 0, bAddress); // Assign new address to the device |
kotakku | 0:b1ce54272580 | 155 | if(rcode) { |
kotakku | 0:b1ce54272580 | 156 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 157 | Notify(PSTR("\r\nsetAddr: "), 0x80); |
kotakku | 0:b1ce54272580 | 158 | D_PrintHex<uint8_t > (rcode, 0x80); |
kotakku | 0:b1ce54272580 | 159 | #endif |
kotakku | 0:b1ce54272580 | 160 | p->lowspeed = false; |
kotakku | 0:b1ce54272580 | 161 | goto Fail; |
kotakku | 0:b1ce54272580 | 162 | } |
kotakku | 0:b1ce54272580 | 163 | #ifdef EXTRADEBUG |
kotakku | 0:b1ce54272580 | 164 | Notify(PSTR("\r\nAddr: "), 0x80); |
kotakku | 0:b1ce54272580 | 165 | D_PrintHex<uint8_t > (bAddress, 0x80); |
kotakku | 0:b1ce54272580 | 166 | #endif |
kotakku | 0:b1ce54272580 | 167 | |
kotakku | 0:b1ce54272580 | 168 | p->lowspeed = false; |
kotakku | 0:b1ce54272580 | 169 | |
kotakku | 0:b1ce54272580 | 170 | p = addrPool.GetUsbDevicePtr(bAddress); // Get pointer to assigned address record |
kotakku | 0:b1ce54272580 | 171 | if(!p) { |
kotakku | 0:b1ce54272580 | 172 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 173 | Notify(PSTR("\r\nAddress not found"), 0x80); |
kotakku | 0:b1ce54272580 | 174 | #endif |
kotakku | 0:b1ce54272580 | 175 | return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; |
kotakku | 0:b1ce54272580 | 176 | } |
kotakku | 0:b1ce54272580 | 177 | |
kotakku | 0:b1ce54272580 | 178 | p->lowspeed = lowspeed; |
kotakku | 0:b1ce54272580 | 179 | |
kotakku | 0:b1ce54272580 | 180 | rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); // Assign epInfo to epinfo pointer - only EP0 is known |
kotakku | 0:b1ce54272580 | 181 | if(rcode) |
kotakku | 0:b1ce54272580 | 182 | goto FailSetDevTblEntry; |
kotakku | 0:b1ce54272580 | 183 | |
kotakku | 0:b1ce54272580 | 184 | if(VID == PS3_VID && (PID == PS3_PID || PID == PS3NAVIGATION_PID || PID == PS3MOVE_PID)) { |
kotakku | 0:b1ce54272580 | 185 | delay(100); |
kotakku | 0:b1ce54272580 | 186 | rcode = pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, 1); // We only need the Control endpoint, so we don't have to initialize the other endpoints of device |
kotakku | 0:b1ce54272580 | 187 | if(rcode) |
kotakku | 0:b1ce54272580 | 188 | goto FailSetConfDescr; |
kotakku | 0:b1ce54272580 | 189 | |
kotakku | 0:b1ce54272580 | 190 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 191 | if(PID == PS3_PID || PID == PS3NAVIGATION_PID) { |
kotakku | 0:b1ce54272580 | 192 | if(PID == PS3_PID) |
kotakku | 0:b1ce54272580 | 193 | Notify(PSTR("\r\nDualshock 3 Controller Connected"), 0x80); |
kotakku | 0:b1ce54272580 | 194 | else // It must be a navigation controller |
kotakku | 0:b1ce54272580 | 195 | Notify(PSTR("\r\nNavigation Controller Connected"), 0x80); |
kotakku | 0:b1ce54272580 | 196 | } else // It must be a Motion controller |
kotakku | 0:b1ce54272580 | 197 | Notify(PSTR("\r\nMotion Controller Connected"), 0x80); |
kotakku | 0:b1ce54272580 | 198 | #endif |
kotakku | 0:b1ce54272580 | 199 | |
kotakku | 0:b1ce54272580 | 200 | if(my_bdaddr[0] == 0x00 && my_bdaddr[1] == 0x00 && my_bdaddr[2] == 0x00 && my_bdaddr[3] == 0x00 && my_bdaddr[4] == 0x00 && my_bdaddr[5] == 0x00) { |
kotakku | 0:b1ce54272580 | 201 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 202 | Notify(PSTR("\r\nPlease plug in the dongle before trying to pair with the PS3 Controller\r\nor set the Bluetooth address in the constructor of the PS3BT class"), 0x80); |
kotakku | 0:b1ce54272580 | 203 | #endif |
kotakku | 0:b1ce54272580 | 204 | } else { |
kotakku | 0:b1ce54272580 | 205 | if(PID == PS3_PID || PID == PS3NAVIGATION_PID) |
kotakku | 0:b1ce54272580 | 206 | setBdaddr(my_bdaddr); // Set internal Bluetooth address |
kotakku | 0:b1ce54272580 | 207 | else |
kotakku | 0:b1ce54272580 | 208 | setMoveBdaddr(my_bdaddr); // Set internal Bluetooth address |
kotakku | 0:b1ce54272580 | 209 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 210 | Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80); |
kotakku | 0:b1ce54272580 | 211 | for(int8_t i = 5; i > 0; i--) { |
kotakku | 0:b1ce54272580 | 212 | D_PrintHex<uint8_t > (my_bdaddr[i], 0x80); |
kotakku | 0:b1ce54272580 | 213 | Notify(PSTR(":"), 0x80); |
kotakku | 0:b1ce54272580 | 214 | } |
kotakku | 0:b1ce54272580 | 215 | D_PrintHex<uint8_t > (my_bdaddr[0], 0x80); |
kotakku | 0:b1ce54272580 | 216 | #endif |
kotakku | 0:b1ce54272580 | 217 | } |
kotakku | 0:b1ce54272580 | 218 | |
kotakku | 0:b1ce54272580 | 219 | pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, 0); // Reset configuration value |
kotakku | 0:b1ce54272580 | 220 | pUsb->setAddr(bAddress, 0, 0); // Reset address |
kotakku | 0:b1ce54272580 | 221 | Release(); // Release device |
kotakku | 0:b1ce54272580 | 222 | return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; // Return |
kotakku | 0:b1ce54272580 | 223 | } else { |
kotakku | 0:b1ce54272580 | 224 | // Check if attached device is a Bluetooth dongle and fill endpoint data structure |
kotakku | 0:b1ce54272580 | 225 | // First interface in the configuration must have Bluetooth assigned Class/Subclass/Protocol |
kotakku | 0:b1ce54272580 | 226 | // And 3 endpoints - interrupt-IN, bulk-IN, bulk-OUT, not necessarily in this order |
kotakku | 0:b1ce54272580 | 227 | for(uint8_t i = 0; i < num_of_conf; i++) { |
kotakku | 0:b1ce54272580 | 228 | if((VID == IOGEAR_GBU521_VID && PID == IOGEAR_GBU521_PID) || (VID == BELKIN_F8T065BF_VID && PID == BELKIN_F8T065BF_PID)) { |
kotakku | 0:b1ce54272580 | 229 | ConfigDescParser<USB_CLASS_VENDOR_SPECIFIC, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this); // Workaround issue with some dongles |
kotakku | 0:b1ce54272580 | 230 | rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); |
kotakku | 0:b1ce54272580 | 231 | } else { |
kotakku | 0:b1ce54272580 | 232 | ConfigDescParser<USB_CLASS_WIRELESS_CTRL, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this); // Set class id according to the specification |
kotakku | 0:b1ce54272580 | 233 | rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); |
kotakku | 0:b1ce54272580 | 234 | } |
kotakku | 0:b1ce54272580 | 235 | if(rcode) // Check error code |
kotakku | 0:b1ce54272580 | 236 | goto FailGetConfDescr; |
kotakku | 0:b1ce54272580 | 237 | if(bNumEP >= BTD_MAX_ENDPOINTS) // All endpoints extracted |
kotakku | 0:b1ce54272580 | 238 | break; |
kotakku | 0:b1ce54272580 | 239 | } |
kotakku | 0:b1ce54272580 | 240 | |
kotakku | 0:b1ce54272580 | 241 | if(bNumEP < BTD_MAX_ENDPOINTS) |
kotakku | 0:b1ce54272580 | 242 | goto FailUnknownDevice; |
kotakku | 0:b1ce54272580 | 243 | |
kotakku | 0:b1ce54272580 | 244 | // Assign epInfo to epinfo pointer - this time all 3 endpoins |
kotakku | 0:b1ce54272580 | 245 | rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); |
kotakku | 0:b1ce54272580 | 246 | if(rcode) |
kotakku | 0:b1ce54272580 | 247 | goto FailSetDevTblEntry; |
kotakku | 0:b1ce54272580 | 248 | |
kotakku | 0:b1ce54272580 | 249 | // Set Configuration Value |
kotakku | 0:b1ce54272580 | 250 | rcode = pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, bConfNum); |
kotakku | 0:b1ce54272580 | 251 | if(rcode) |
kotakku | 0:b1ce54272580 | 252 | goto FailSetConfDescr; |
kotakku | 0:b1ce54272580 | 253 | |
kotakku | 0:b1ce54272580 | 254 | hci_num_reset_loops = 100; // only loop 100 times before trying to send the hci reset command |
kotakku | 0:b1ce54272580 | 255 | hci_counter = 0; |
kotakku | 0:b1ce54272580 | 256 | hci_state = HCI_INIT_STATE; |
kotakku | 0:b1ce54272580 | 257 | waitingForConnection = false; |
kotakku | 0:b1ce54272580 | 258 | bPollEnable = true; |
kotakku | 0:b1ce54272580 | 259 | |
kotakku | 0:b1ce54272580 | 260 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 261 | Notify(PSTR("\r\nBluetooth Dongle Initialized"), 0x80); |
kotakku | 0:b1ce54272580 | 262 | #endif |
kotakku | 0:b1ce54272580 | 263 | } |
kotakku | 0:b1ce54272580 | 264 | return 0; // Successful configuration |
kotakku | 0:b1ce54272580 | 265 | |
kotakku | 0:b1ce54272580 | 266 | /* Diagnostic messages */ |
kotakku | 0:b1ce54272580 | 267 | FailSetDevTblEntry: |
kotakku | 0:b1ce54272580 | 268 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 269 | NotifyFailSetDevTblEntry(); |
kotakku | 0:b1ce54272580 | 270 | goto Fail; |
kotakku | 0:b1ce54272580 | 271 | #endif |
kotakku | 0:b1ce54272580 | 272 | |
kotakku | 0:b1ce54272580 | 273 | FailGetConfDescr: |
kotakku | 0:b1ce54272580 | 274 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 275 | NotifyFailGetConfDescr(); |
kotakku | 0:b1ce54272580 | 276 | goto Fail; |
kotakku | 0:b1ce54272580 | 277 | #endif |
kotakku | 0:b1ce54272580 | 278 | |
kotakku | 0:b1ce54272580 | 279 | FailSetConfDescr: |
kotakku | 0:b1ce54272580 | 280 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 281 | NotifyFailSetConfDescr(); |
kotakku | 0:b1ce54272580 | 282 | #endif |
kotakku | 0:b1ce54272580 | 283 | goto Fail; |
kotakku | 0:b1ce54272580 | 284 | |
kotakku | 0:b1ce54272580 | 285 | FailUnknownDevice: |
kotakku | 0:b1ce54272580 | 286 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 287 | NotifyFailUnknownDevice(VID, PID); |
kotakku | 0:b1ce54272580 | 288 | #endif |
kotakku | 0:b1ce54272580 | 289 | pUsb->setAddr(bAddress, 0, 0); // Reset address |
kotakku | 0:b1ce54272580 | 290 | rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; |
kotakku | 0:b1ce54272580 | 291 | Fail: |
kotakku | 0:b1ce54272580 | 292 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 293 | Notify(PSTR("\r\nBTD Init Failed, error code: "), 0x80); |
kotakku | 0:b1ce54272580 | 294 | NotifyFail(rcode); |
kotakku | 0:b1ce54272580 | 295 | #endif |
kotakku | 0:b1ce54272580 | 296 | Release(); |
kotakku | 0:b1ce54272580 | 297 | return rcode; |
kotakku | 0:b1ce54272580 | 298 | } |
kotakku | 0:b1ce54272580 | 299 | |
kotakku | 0:b1ce54272580 | 300 | void BTD::Initialize() { |
kotakku | 0:b1ce54272580 | 301 | uint8_t i; |
kotakku | 0:b1ce54272580 | 302 | for(i = 0; i < BTD_MAX_ENDPOINTS; i++) { |
kotakku | 0:b1ce54272580 | 303 | epInfo[i].epAddr = 0; |
kotakku | 0:b1ce54272580 | 304 | epInfo[i].maxPktSize = (i) ? 0 : 8; |
kotakku | 0:b1ce54272580 | 305 | epInfo[i].bmSndToggle = 0; |
kotakku | 0:b1ce54272580 | 306 | epInfo[i].bmRcvToggle = 0; |
kotakku | 0:b1ce54272580 | 307 | epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER; |
kotakku | 0:b1ce54272580 | 308 | } |
kotakku | 0:b1ce54272580 | 309 | for(i = 0; i < BTD_NUM_SERVICES; i++) { |
kotakku | 0:b1ce54272580 | 310 | if(btService[i]) |
kotakku | 0:b1ce54272580 | 311 | btService[i]->Reset(); // Reset all Bluetooth services |
kotakku | 0:b1ce54272580 | 312 | } |
kotakku | 0:b1ce54272580 | 313 | |
kotakku | 0:b1ce54272580 | 314 | connectToWii = false; |
kotakku | 0:b1ce54272580 | 315 | incomingWii = false; |
kotakku | 0:b1ce54272580 | 316 | connectToHIDDevice = false; |
kotakku | 0:b1ce54272580 | 317 | incomingHIDDevice = false; |
kotakku | 0:b1ce54272580 | 318 | incomingPS4 = false; |
kotakku | 0:b1ce54272580 | 319 | bAddress = 0; // Clear device address |
kotakku | 0:b1ce54272580 | 320 | bNumEP = 1; // Must have to be reset to 1 |
kotakku | 0:b1ce54272580 | 321 | qNextPollTime = 0; // Reset next poll time |
kotakku | 0:b1ce54272580 | 322 | pollInterval = 0; |
kotakku | 0:b1ce54272580 | 323 | bPollEnable = false; // Don't start polling before dongle is connected |
kotakku | 0:b1ce54272580 | 324 | } |
kotakku | 0:b1ce54272580 | 325 | |
kotakku | 0:b1ce54272580 | 326 | /* Extracts interrupt-IN, bulk-IN, bulk-OUT endpoint information from config descriptor */ |
kotakku | 0:b1ce54272580 | 327 | void BTD::EndpointXtract(uint8_t conf, uint8_t iface __attribute__((unused)), uint8_t alt, uint8_t proto __attribute__((unused)), const USB_ENDPOINT_DESCRIPTOR *pep) { |
kotakku | 0:b1ce54272580 | 328 | //ErrorMessage<uint8_t>(PSTR("Conf.Val"),conf); |
kotakku | 0:b1ce54272580 | 329 | //ErrorMessage<uint8_t>(PSTR("Iface Num"),iface); |
kotakku | 0:b1ce54272580 | 330 | //ErrorMessage<uint8_t>(PSTR("Alt.Set"),alt); |
kotakku | 0:b1ce54272580 | 331 | |
kotakku | 0:b1ce54272580 | 332 | if(alt) // Wrong interface - by BT spec, no alt setting |
kotakku | 0:b1ce54272580 | 333 | return; |
kotakku | 0:b1ce54272580 | 334 | |
kotakku | 0:b1ce54272580 | 335 | bConfNum = conf; |
kotakku | 0:b1ce54272580 | 336 | uint8_t index; |
kotakku | 0:b1ce54272580 | 337 | |
kotakku | 0:b1ce54272580 | 338 | if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT && (pep->bEndpointAddress & 0x80) == 0x80) { // Interrupt In endpoint found |
kotakku | 0:b1ce54272580 | 339 | index = BTD_EVENT_PIPE; |
kotakku | 0:b1ce54272580 | 340 | epInfo[index].bmNakPower = USB_NAK_NOWAIT; |
kotakku | 0:b1ce54272580 | 341 | } else if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) // Bulk endpoint found |
kotakku | 0:b1ce54272580 | 342 | index = ((pep->bEndpointAddress & 0x80) == 0x80) ? BTD_DATAIN_PIPE : BTD_DATAOUT_PIPE; |
kotakku | 0:b1ce54272580 | 343 | else |
kotakku | 0:b1ce54272580 | 344 | return; |
kotakku | 0:b1ce54272580 | 345 | |
kotakku | 0:b1ce54272580 | 346 | // Fill the rest of endpoint data structure |
kotakku | 0:b1ce54272580 | 347 | epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); |
kotakku | 0:b1ce54272580 | 348 | epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; |
kotakku | 0:b1ce54272580 | 349 | #ifdef EXTRADEBUG |
kotakku | 0:b1ce54272580 | 350 | PrintEndpointDescriptor(pep); |
kotakku | 0:b1ce54272580 | 351 | #endif |
kotakku | 0:b1ce54272580 | 352 | if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints |
kotakku | 0:b1ce54272580 | 353 | pollInterval = pep->bInterval; |
kotakku | 0:b1ce54272580 | 354 | bNumEP++; |
kotakku | 0:b1ce54272580 | 355 | } |
kotakku | 0:b1ce54272580 | 356 | |
kotakku | 0:b1ce54272580 | 357 | void BTD::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr __attribute__((unused))) { |
kotakku | 0:b1ce54272580 | 358 | #ifdef EXTRADEBUG |
kotakku | 0:b1ce54272580 | 359 | Notify(PSTR("\r\nEndpoint descriptor:"), 0x80); |
kotakku | 0:b1ce54272580 | 360 | Notify(PSTR("\r\nLength:\t\t"), 0x80); |
kotakku | 0:b1ce54272580 | 361 | D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80); |
kotakku | 0:b1ce54272580 | 362 | Notify(PSTR("\r\nType:\t\t"), 0x80); |
kotakku | 0:b1ce54272580 | 363 | D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80); |
kotakku | 0:b1ce54272580 | 364 | Notify(PSTR("\r\nAddress:\t"), 0x80); |
kotakku | 0:b1ce54272580 | 365 | D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80); |
kotakku | 0:b1ce54272580 | 366 | Notify(PSTR("\r\nAttributes:\t"), 0x80); |
kotakku | 0:b1ce54272580 | 367 | D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80); |
kotakku | 0:b1ce54272580 | 368 | Notify(PSTR("\r\nMaxPktSize:\t"), 0x80); |
kotakku | 0:b1ce54272580 | 369 | D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80); |
kotakku | 0:b1ce54272580 | 370 | Notify(PSTR("\r\nPoll Intrv:\t"), 0x80); |
kotakku | 0:b1ce54272580 | 371 | D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80); |
kotakku | 0:b1ce54272580 | 372 | #endif |
kotakku | 0:b1ce54272580 | 373 | } |
kotakku | 0:b1ce54272580 | 374 | |
kotakku | 0:b1ce54272580 | 375 | /* Performs a cleanup after failed Init() attempt */ |
kotakku | 0:b1ce54272580 | 376 | uint8_t BTD::Release() { |
kotakku | 0:b1ce54272580 | 377 | Initialize(); // Set all variables, endpoint structs etc. to default values |
kotakku | 0:b1ce54272580 | 378 | pUsb->GetAddressPool().FreeAddress(bAddress); |
kotakku | 0:b1ce54272580 | 379 | return 0; |
kotakku | 0:b1ce54272580 | 380 | } |
kotakku | 0:b1ce54272580 | 381 | |
kotakku | 0:b1ce54272580 | 382 | uint8_t BTD::Poll() { |
kotakku | 0:b1ce54272580 | 383 | if(!bPollEnable) |
kotakku | 0:b1ce54272580 | 384 | return 0; |
kotakku | 0:b1ce54272580 | 385 | if((int32_t)((uint32_t)millis() - qNextPollTime) >= 0L) { // Don't poll if shorter than polling interval |
kotakku | 0:b1ce54272580 | 386 | qNextPollTime = (uint32_t)millis() + pollInterval; // Set new poll time |
kotakku | 0:b1ce54272580 | 387 | HCI_event_task(); // Poll the HCI event pipe |
kotakku | 0:b1ce54272580 | 388 | HCI_task(); // HCI state machine |
kotakku | 0:b1ce54272580 | 389 | ACL_event_task(); // Poll the ACL input pipe too |
kotakku | 0:b1ce54272580 | 390 | } |
kotakku | 0:b1ce54272580 | 391 | return 0; |
kotakku | 0:b1ce54272580 | 392 | } |
kotakku | 0:b1ce54272580 | 393 | |
kotakku | 0:b1ce54272580 | 394 | void BTD::disconnect() { |
kotakku | 0:b1ce54272580 | 395 | for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++) |
kotakku | 0:b1ce54272580 | 396 | if(btService[i]) |
kotakku | 0:b1ce54272580 | 397 | btService[i]->disconnect(); |
kotakku | 0:b1ce54272580 | 398 | }; |
kotakku | 0:b1ce54272580 | 399 | |
kotakku | 0:b1ce54272580 | 400 | void BTD::HCI_event_task() { |
kotakku | 0:b1ce54272580 | 401 | uint16_t length = BULK_MAXPKTSIZE; // Request more than 16 bytes anyway, the inTransfer routine will take care of this |
kotakku | 0:b1ce54272580 | 402 | uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ BTD_EVENT_PIPE ].epAddr, &length, hcibuf, pollInterval); // Input on endpoint 1 |
kotakku | 0:b1ce54272580 | 403 | |
kotakku | 0:b1ce54272580 | 404 | if(!rcode || rcode == hrNAK) { // Check for errors |
kotakku | 0:b1ce54272580 | 405 | switch(hcibuf[0]) { // Switch on event type |
kotakku | 0:b1ce54272580 | 406 | case EV_COMMAND_COMPLETE: |
kotakku | 0:b1ce54272580 | 407 | if(!hcibuf[5]) { // Check if command succeeded |
kotakku | 0:b1ce54272580 | 408 | hci_set_flag(HCI_FLAG_CMD_COMPLETE); // Set command complete flag |
kotakku | 0:b1ce54272580 | 409 | if((hcibuf[3] == 0x01) && (hcibuf[4] == 0x10)) { // Parameters from read local version information |
kotakku | 0:b1ce54272580 | 410 | hci_version = hcibuf[6]; // Used to check if it supports 2.0+EDR - see http://www.bluetooth.org/Technical/AssignedNumbers/hci.htm |
kotakku | 0:b1ce54272580 | 411 | hci_set_flag(HCI_FLAG_READ_VERSION); |
kotakku | 0:b1ce54272580 | 412 | } else if((hcibuf[3] == 0x09) && (hcibuf[4] == 0x10)) { // Parameters from read local bluetooth address |
kotakku | 0:b1ce54272580 | 413 | for(uint8_t i = 0; i < 6; i++) |
kotakku | 0:b1ce54272580 | 414 | my_bdaddr[i] = hcibuf[6 + i]; |
kotakku | 0:b1ce54272580 | 415 | hci_set_flag(HCI_FLAG_READ_BDADDR); |
kotakku | 0:b1ce54272580 | 416 | } |
kotakku | 0:b1ce54272580 | 417 | } |
kotakku | 0:b1ce54272580 | 418 | break; |
kotakku | 0:b1ce54272580 | 419 | |
kotakku | 0:b1ce54272580 | 420 | case EV_COMMAND_STATUS: |
kotakku | 0:b1ce54272580 | 421 | if(hcibuf[2]) { // Show status on serial if not OK |
kotakku | 0:b1ce54272580 | 422 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 423 | Notify(PSTR("\r\nHCI Command Failed: "), 0x80); |
kotakku | 0:b1ce54272580 | 424 | D_PrintHex<uint8_t > (hcibuf[2], 0x80); |
kotakku | 0:b1ce54272580 | 425 | #endif |
kotakku | 0:b1ce54272580 | 426 | } |
kotakku | 0:b1ce54272580 | 427 | break; |
kotakku | 0:b1ce54272580 | 428 | |
kotakku | 0:b1ce54272580 | 429 | case EV_INQUIRY_COMPLETE: |
kotakku | 0:b1ce54272580 | 430 | if(inquiry_counter >= 5 && (pairWithWii || pairWithHIDDevice)) { |
kotakku | 0:b1ce54272580 | 431 | inquiry_counter = 0; |
kotakku | 0:b1ce54272580 | 432 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 433 | if(pairWithWii) |
kotakku | 0:b1ce54272580 | 434 | Notify(PSTR("\r\nCouldn't find Wiimote"), 0x80); |
kotakku | 0:b1ce54272580 | 435 | else |
kotakku | 0:b1ce54272580 | 436 | Notify(PSTR("\r\nCouldn't find HID device"), 0x80); |
kotakku | 0:b1ce54272580 | 437 | #endif |
kotakku | 0:b1ce54272580 | 438 | connectToWii = false; |
kotakku | 0:b1ce54272580 | 439 | pairWithWii = false; |
kotakku | 0:b1ce54272580 | 440 | connectToHIDDevice = false; |
kotakku | 0:b1ce54272580 | 441 | pairWithHIDDevice = false; |
kotakku | 0:b1ce54272580 | 442 | hci_state = HCI_SCANNING_STATE; |
kotakku | 0:b1ce54272580 | 443 | } |
kotakku | 0:b1ce54272580 | 444 | inquiry_counter++; |
kotakku | 0:b1ce54272580 | 445 | break; |
kotakku | 0:b1ce54272580 | 446 | |
kotakku | 0:b1ce54272580 | 447 | case EV_INQUIRY_RESULT: |
kotakku | 0:b1ce54272580 | 448 | if(hcibuf[2]) { // Check that there is more than zero responses |
kotakku | 0:b1ce54272580 | 449 | #ifdef EXTRADEBUG |
kotakku | 0:b1ce54272580 | 450 | Notify(PSTR("\r\nNumber of responses: "), 0x80); |
kotakku | 0:b1ce54272580 | 451 | Notify(hcibuf[2], 0x80); |
kotakku | 0:b1ce54272580 | 452 | #endif |
kotakku | 0:b1ce54272580 | 453 | for(uint8_t i = 0; i < hcibuf[2]; i++) { |
kotakku | 0:b1ce54272580 | 454 | uint8_t offset = 8 * hcibuf[2] + 3 * i; |
kotakku | 0:b1ce54272580 | 455 | |
kotakku | 0:b1ce54272580 | 456 | for(uint8_t j = 0; j < 3; j++) |
kotakku | 0:b1ce54272580 | 457 | classOfDevice[j] = hcibuf[j + 4 + offset]; |
kotakku | 0:b1ce54272580 | 458 | |
kotakku | 0:b1ce54272580 | 459 | #ifdef EXTRADEBUG |
kotakku | 0:b1ce54272580 | 460 | Notify(PSTR("\r\nClass of device: "), 0x80); |
kotakku | 0:b1ce54272580 | 461 | D_PrintHex<uint8_t > (classOfDevice[2], 0x80); |
kotakku | 0:b1ce54272580 | 462 | Notify(PSTR(" "), 0x80); |
kotakku | 0:b1ce54272580 | 463 | D_PrintHex<uint8_t > (classOfDevice[1], 0x80); |
kotakku | 0:b1ce54272580 | 464 | Notify(PSTR(" "), 0x80); |
kotakku | 0:b1ce54272580 | 465 | D_PrintHex<uint8_t > (classOfDevice[0], 0x80); |
kotakku | 0:b1ce54272580 | 466 | #endif |
kotakku | 0:b1ce54272580 | 467 | |
kotakku | 0:b1ce54272580 | 468 | if(pairWithWii && classOfDevice[2] == 0x00 && (classOfDevice[1] & 0x05) && (classOfDevice[0] & 0x0C)) { // See http://wiibrew.org/wiki/Wiimote#SDP_information |
kotakku | 0:b1ce54272580 | 469 | checkRemoteName = true; // Check remote name to distinguish between the different controllers |
kotakku | 0:b1ce54272580 | 470 | |
kotakku | 0:b1ce54272580 | 471 | for(uint8_t j = 0; j < 6; j++) |
kotakku | 0:b1ce54272580 | 472 | disc_bdaddr[j] = hcibuf[j + 3 + 6 * i]; |
kotakku | 0:b1ce54272580 | 473 | |
kotakku | 0:b1ce54272580 | 474 | hci_set_flag(HCI_FLAG_DEVICE_FOUND); |
kotakku | 0:b1ce54272580 | 475 | break; |
kotakku | 0:b1ce54272580 | 476 | } else if(pairWithHIDDevice && (classOfDevice[1] & 0x05) && (classOfDevice[0] & 0xC8)) { // Check if it is a mouse, keyboard or a gamepad - see: http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html |
kotakku | 0:b1ce54272580 | 477 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 478 | if(classOfDevice[0] & 0x80) |
kotakku | 0:b1ce54272580 | 479 | Notify(PSTR("\r\nMouse found"), 0x80); |
kotakku | 0:b1ce54272580 | 480 | if(classOfDevice[0] & 0x40) |
kotakku | 0:b1ce54272580 | 481 | Notify(PSTR("\r\nKeyboard found"), 0x80); |
kotakku | 0:b1ce54272580 | 482 | if(classOfDevice[0] & 0x08) |
kotakku | 0:b1ce54272580 | 483 | Notify(PSTR("\r\nGamepad found"), 0x80); |
kotakku | 0:b1ce54272580 | 484 | #endif |
kotakku | 0:b1ce54272580 | 485 | |
kotakku | 0:b1ce54272580 | 486 | for(uint8_t j = 0; j < 6; j++) |
kotakku | 0:b1ce54272580 | 487 | disc_bdaddr[j] = hcibuf[j + 3 + 6 * i]; |
kotakku | 0:b1ce54272580 | 488 | |
kotakku | 0:b1ce54272580 | 489 | hci_set_flag(HCI_FLAG_DEVICE_FOUND); |
kotakku | 0:b1ce54272580 | 490 | break; |
kotakku | 0:b1ce54272580 | 491 | } |
kotakku | 0:b1ce54272580 | 492 | } |
kotakku | 0:b1ce54272580 | 493 | } |
kotakku | 0:b1ce54272580 | 494 | break; |
kotakku | 0:b1ce54272580 | 495 | |
kotakku | 0:b1ce54272580 | 496 | case EV_CONNECT_COMPLETE: |
kotakku | 0:b1ce54272580 | 497 | hci_set_flag(HCI_FLAG_CONNECT_EVENT); |
kotakku | 0:b1ce54272580 | 498 | if(!hcibuf[2]) { // Check if connected OK |
kotakku | 0:b1ce54272580 | 499 | #ifdef EXTRADEBUG |
kotakku | 0:b1ce54272580 | 500 | Notify(PSTR("\r\nConnection established"), 0x80); |
kotakku | 0:b1ce54272580 | 501 | #endif |
kotakku | 0:b1ce54272580 | 502 | hci_handle = hcibuf[3] | ((hcibuf[4] & 0x0F) << 8); // Store the handle for the ACL connection |
kotakku | 0:b1ce54272580 | 503 | hci_set_flag(HCI_FLAG_CONNECT_COMPLETE); // Set connection complete flag |
kotakku | 0:b1ce54272580 | 504 | } else { |
kotakku | 0:b1ce54272580 | 505 | hci_state = HCI_CHECK_DEVICE_SERVICE; |
kotakku | 0:b1ce54272580 | 506 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 507 | Notify(PSTR("\r\nConnection Failed: "), 0x80); |
kotakku | 0:b1ce54272580 | 508 | D_PrintHex<uint8_t > (hcibuf[2], 0x80); |
kotakku | 0:b1ce54272580 | 509 | #endif |
kotakku | 0:b1ce54272580 | 510 | } |
kotakku | 0:b1ce54272580 | 511 | break; |
kotakku | 0:b1ce54272580 | 512 | |
kotakku | 0:b1ce54272580 | 513 | case EV_DISCONNECT_COMPLETE: |
kotakku | 0:b1ce54272580 | 514 | if(!hcibuf[2]) { // Check if disconnected OK |
kotakku | 0:b1ce54272580 | 515 | hci_set_flag(HCI_FLAG_DISCONNECT_COMPLETE); // Set disconnect command complete flag |
kotakku | 0:b1ce54272580 | 516 | hci_clear_flag(HCI_FLAG_CONNECT_COMPLETE); // Clear connection complete flag |
kotakku | 0:b1ce54272580 | 517 | } |
kotakku | 0:b1ce54272580 | 518 | break; |
kotakku | 0:b1ce54272580 | 519 | |
kotakku | 0:b1ce54272580 | 520 | case EV_REMOTE_NAME_COMPLETE: |
kotakku | 0:b1ce54272580 | 521 | if(!hcibuf[2]) { // Check if reading is OK |
kotakku | 0:b1ce54272580 | 522 | for(uint8_t i = 0; i < min(sizeof (remote_name), sizeof (hcibuf) - 9); i++) { |
kotakku | 0:b1ce54272580 | 523 | remote_name[i] = hcibuf[9 + i]; |
kotakku | 0:b1ce54272580 | 524 | if(remote_name[i] == '\0') // End of string |
kotakku | 0:b1ce54272580 | 525 | break; |
kotakku | 0:b1ce54272580 | 526 | } |
kotakku | 0:b1ce54272580 | 527 | // TODO: Altid sæt '\0' i remote name! |
kotakku | 0:b1ce54272580 | 528 | hci_set_flag(HCI_FLAG_REMOTE_NAME_COMPLETE); |
kotakku | 0:b1ce54272580 | 529 | } |
kotakku | 0:b1ce54272580 | 530 | break; |
kotakku | 0:b1ce54272580 | 531 | |
kotakku | 0:b1ce54272580 | 532 | case EV_INCOMING_CONNECT: |
kotakku | 0:b1ce54272580 | 533 | for(uint8_t i = 0; i < 6; i++) |
kotakku | 0:b1ce54272580 | 534 | disc_bdaddr[i] = hcibuf[i + 2]; |
kotakku | 0:b1ce54272580 | 535 | |
kotakku | 0:b1ce54272580 | 536 | for(uint8_t i = 0; i < 3; i++) |
kotakku | 0:b1ce54272580 | 537 | classOfDevice[i] = hcibuf[i + 8]; |
kotakku | 0:b1ce54272580 | 538 | |
kotakku | 0:b1ce54272580 | 539 | if((classOfDevice[1] & 0x05) && (classOfDevice[0] & 0xC8)) { // Check if it is a mouse, keyboard or a gamepad |
kotakku | 0:b1ce54272580 | 540 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 541 | if(classOfDevice[0] & 0x80) |
kotakku | 0:b1ce54272580 | 542 | Notify(PSTR("\r\nMouse is connecting"), 0x80); |
kotakku | 0:b1ce54272580 | 543 | if(classOfDevice[0] & 0x40) |
kotakku | 0:b1ce54272580 | 544 | Notify(PSTR("\r\nKeyboard is connecting"), 0x80); |
kotakku | 0:b1ce54272580 | 545 | if(classOfDevice[0] & 0x08) |
kotakku | 0:b1ce54272580 | 546 | Notify(PSTR("\r\nGamepad is connecting"), 0x80); |
kotakku | 0:b1ce54272580 | 547 | #endif |
kotakku | 0:b1ce54272580 | 548 | incomingHIDDevice = true; |
kotakku | 0:b1ce54272580 | 549 | } |
kotakku | 0:b1ce54272580 | 550 | |
kotakku | 0:b1ce54272580 | 551 | #ifdef EXTRADEBUG |
kotakku | 0:b1ce54272580 | 552 | Notify(PSTR("\r\nClass of device: "), 0x80); |
kotakku | 0:b1ce54272580 | 553 | D_PrintHex<uint8_t > (classOfDevice[2], 0x80); |
kotakku | 0:b1ce54272580 | 554 | Notify(PSTR(" "), 0x80); |
kotakku | 0:b1ce54272580 | 555 | D_PrintHex<uint8_t > (classOfDevice[1], 0x80); |
kotakku | 0:b1ce54272580 | 556 | Notify(PSTR(" "), 0x80); |
kotakku | 0:b1ce54272580 | 557 | D_PrintHex<uint8_t > (classOfDevice[0], 0x80); |
kotakku | 0:b1ce54272580 | 558 | #endif |
kotakku | 0:b1ce54272580 | 559 | hci_set_flag(HCI_FLAG_INCOMING_REQUEST); |
kotakku | 0:b1ce54272580 | 560 | break; |
kotakku | 0:b1ce54272580 | 561 | |
kotakku | 0:b1ce54272580 | 562 | case EV_PIN_CODE_REQUEST: |
kotakku | 0:b1ce54272580 | 563 | if(pairWithWii) { |
kotakku | 0:b1ce54272580 | 564 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 565 | Notify(PSTR("\r\nPairing with Wiimote"), 0x80); |
kotakku | 0:b1ce54272580 | 566 | #endif |
kotakku | 0:b1ce54272580 | 567 | hci_pin_code_request_reply(); |
kotakku | 0:b1ce54272580 | 568 | } else if(btdPin != NULL) { |
kotakku | 0:b1ce54272580 | 569 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 570 | Notify(PSTR("\r\nBluetooth pin is set too: "), 0x80); |
kotakku | 0:b1ce54272580 | 571 | NotifyStr(btdPin, 0x80); |
kotakku | 0:b1ce54272580 | 572 | #endif |
kotakku | 0:b1ce54272580 | 573 | hci_pin_code_request_reply(); |
kotakku | 0:b1ce54272580 | 574 | } else { |
kotakku | 0:b1ce54272580 | 575 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 576 | Notify(PSTR("\r\nNo pin was set"), 0x80); |
kotakku | 0:b1ce54272580 | 577 | #endif |
kotakku | 0:b1ce54272580 | 578 | hci_pin_code_negative_request_reply(); |
kotakku | 0:b1ce54272580 | 579 | } |
kotakku | 0:b1ce54272580 | 580 | break; |
kotakku | 0:b1ce54272580 | 581 | |
kotakku | 0:b1ce54272580 | 582 | case EV_LINK_KEY_REQUEST: |
kotakku | 0:b1ce54272580 | 583 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 584 | Notify(PSTR("\r\nReceived Key Request"), 0x80); |
kotakku | 0:b1ce54272580 | 585 | #endif |
kotakku | 0:b1ce54272580 | 586 | hci_link_key_request_negative_reply(); |
kotakku | 0:b1ce54272580 | 587 | break; |
kotakku | 0:b1ce54272580 | 588 | |
kotakku | 0:b1ce54272580 | 589 | case EV_AUTHENTICATION_COMPLETE: |
kotakku | 0:b1ce54272580 | 590 | if(!hcibuf[2]) { // Check if pairing was successful |
kotakku | 0:b1ce54272580 | 591 | if(pairWithWii && !connectToWii) { |
kotakku | 0:b1ce54272580 | 592 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 593 | Notify(PSTR("\r\nPairing successful with Wiimote"), 0x80); |
kotakku | 0:b1ce54272580 | 594 | #endif |
kotakku | 0:b1ce54272580 | 595 | connectToWii = true; // Used to indicate to the Wii service, that it should connect to this device |
kotakku | 0:b1ce54272580 | 596 | } else if(pairWithHIDDevice && !connectToHIDDevice) { |
kotakku | 0:b1ce54272580 | 597 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 598 | Notify(PSTR("\r\nPairing successful with HID device"), 0x80); |
kotakku | 0:b1ce54272580 | 599 | #endif |
kotakku | 0:b1ce54272580 | 600 | connectToHIDDevice = true; // Used to indicate to the BTHID service, that it should connect to this device |
kotakku | 0:b1ce54272580 | 601 | } |
kotakku | 0:b1ce54272580 | 602 | } else { |
kotakku | 0:b1ce54272580 | 603 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 604 | Notify(PSTR("\r\nPairing Failed: "), 0x80); |
kotakku | 0:b1ce54272580 | 605 | D_PrintHex<uint8_t > (hcibuf[2], 0x80); |
kotakku | 0:b1ce54272580 | 606 | #endif |
kotakku | 0:b1ce54272580 | 607 | hci_disconnect(hci_handle); |
kotakku | 0:b1ce54272580 | 608 | hci_state = HCI_DISCONNECT_STATE; |
kotakku | 0:b1ce54272580 | 609 | } |
kotakku | 0:b1ce54272580 | 610 | break; |
kotakku | 0:b1ce54272580 | 611 | /* We will just ignore the following events */ |
kotakku | 0:b1ce54272580 | 612 | case EV_NUM_COMPLETE_PKT: |
kotakku | 0:b1ce54272580 | 613 | case EV_ROLE_CHANGED: |
kotakku | 0:b1ce54272580 | 614 | case EV_PAGE_SCAN_REP_MODE: |
kotakku | 0:b1ce54272580 | 615 | case EV_LOOPBACK_COMMAND: |
kotakku | 0:b1ce54272580 | 616 | case EV_DATA_BUFFER_OVERFLOW: |
kotakku | 0:b1ce54272580 | 617 | case EV_CHANGE_CONNECTION_LINK: |
kotakku | 0:b1ce54272580 | 618 | case EV_MAX_SLOTS_CHANGE: |
kotakku | 0:b1ce54272580 | 619 | case EV_QOS_SETUP_COMPLETE: |
kotakku | 0:b1ce54272580 | 620 | case EV_LINK_KEY_NOTIFICATION: |
kotakku | 0:b1ce54272580 | 621 | case EV_ENCRYPTION_CHANGE: |
kotakku | 0:b1ce54272580 | 622 | case EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE: |
kotakku | 0:b1ce54272580 | 623 | break; |
kotakku | 0:b1ce54272580 | 624 | #ifdef EXTRADEBUG |
kotakku | 0:b1ce54272580 | 625 | default: |
kotakku | 0:b1ce54272580 | 626 | if(hcibuf[0] != 0x00) { |
kotakku | 0:b1ce54272580 | 627 | Notify(PSTR("\r\nUnmanaged HCI Event: "), 0x80); |
kotakku | 0:b1ce54272580 | 628 | D_PrintHex<uint8_t > (hcibuf[0], 0x80); |
kotakku | 0:b1ce54272580 | 629 | } |
kotakku | 0:b1ce54272580 | 630 | break; |
kotakku | 0:b1ce54272580 | 631 | #endif |
kotakku | 0:b1ce54272580 | 632 | } // Switch |
kotakku | 0:b1ce54272580 | 633 | } |
kotakku | 0:b1ce54272580 | 634 | #ifdef EXTRADEBUG |
kotakku | 0:b1ce54272580 | 635 | else { |
kotakku | 0:b1ce54272580 | 636 | Notify(PSTR("\r\nHCI event error: "), 0x80); |
kotakku | 0:b1ce54272580 | 637 | D_PrintHex<uint8_t > (rcode, 0x80); |
kotakku | 0:b1ce54272580 | 638 | } |
kotakku | 0:b1ce54272580 | 639 | #endif |
kotakku | 0:b1ce54272580 | 640 | } |
kotakku | 0:b1ce54272580 | 641 | |
kotakku | 0:b1ce54272580 | 642 | /* Poll Bluetooth and print result */ |
kotakku | 0:b1ce54272580 | 643 | void BTD::HCI_task() { |
kotakku | 0:b1ce54272580 | 644 | switch(hci_state) { |
kotakku | 0:b1ce54272580 | 645 | case HCI_INIT_STATE: |
kotakku | 0:b1ce54272580 | 646 | hci_counter++; |
kotakku | 0:b1ce54272580 | 647 | if(hci_counter > hci_num_reset_loops) { // wait until we have looped x times to clear any old events |
kotakku | 0:b1ce54272580 | 648 | hci_reset(); |
kotakku | 0:b1ce54272580 | 649 | hci_state = HCI_RESET_STATE; |
kotakku | 0:b1ce54272580 | 650 | hci_counter = 0; |
kotakku | 0:b1ce54272580 | 651 | } |
kotakku | 0:b1ce54272580 | 652 | break; |
kotakku | 0:b1ce54272580 | 653 | |
kotakku | 0:b1ce54272580 | 654 | case HCI_RESET_STATE: |
kotakku | 0:b1ce54272580 | 655 | hci_counter++; |
kotakku | 0:b1ce54272580 | 656 | if(hci_check_flag(HCI_FLAG_CMD_COMPLETE)) { |
kotakku | 0:b1ce54272580 | 657 | hci_counter = 0; |
kotakku | 0:b1ce54272580 | 658 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 659 | Notify(PSTR("\r\nHCI Reset complete"), 0x80); |
kotakku | 0:b1ce54272580 | 660 | #endif |
kotakku | 0:b1ce54272580 | 661 | hci_state = HCI_CLASS_STATE; |
kotakku | 0:b1ce54272580 | 662 | hci_write_class_of_device(); |
kotakku | 0:b1ce54272580 | 663 | } else if(hci_counter > hci_num_reset_loops) { |
kotakku | 0:b1ce54272580 | 664 | hci_num_reset_loops *= 10; |
kotakku | 0:b1ce54272580 | 665 | if(hci_num_reset_loops > 2000) |
kotakku | 0:b1ce54272580 | 666 | hci_num_reset_loops = 2000; |
kotakku | 0:b1ce54272580 | 667 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 668 | Notify(PSTR("\r\nNo response to HCI Reset"), 0x80); |
kotakku | 0:b1ce54272580 | 669 | #endif |
kotakku | 0:b1ce54272580 | 670 | hci_state = HCI_INIT_STATE; |
kotakku | 0:b1ce54272580 | 671 | hci_counter = 0; |
kotakku | 0:b1ce54272580 | 672 | } |
kotakku | 0:b1ce54272580 | 673 | break; |
kotakku | 0:b1ce54272580 | 674 | |
kotakku | 0:b1ce54272580 | 675 | case HCI_CLASS_STATE: |
kotakku | 0:b1ce54272580 | 676 | if(hci_check_flag(HCI_FLAG_CMD_COMPLETE)) { |
kotakku | 0:b1ce54272580 | 677 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 678 | Notify(PSTR("\r\nWrite class of device"), 0x80); |
kotakku | 0:b1ce54272580 | 679 | #endif |
kotakku | 0:b1ce54272580 | 680 | hci_state = HCI_BDADDR_STATE; |
kotakku | 0:b1ce54272580 | 681 | hci_read_bdaddr(); |
kotakku | 0:b1ce54272580 | 682 | } |
kotakku | 0:b1ce54272580 | 683 | break; |
kotakku | 0:b1ce54272580 | 684 | |
kotakku | 0:b1ce54272580 | 685 | case HCI_BDADDR_STATE: |
kotakku | 0:b1ce54272580 | 686 | if(hci_check_flag(HCI_FLAG_READ_BDADDR)) { |
kotakku | 0:b1ce54272580 | 687 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 688 | Notify(PSTR("\r\nLocal Bluetooth Address: "), 0x80); |
kotakku | 0:b1ce54272580 | 689 | for(int8_t i = 5; i > 0; i--) { |
kotakku | 0:b1ce54272580 | 690 | D_PrintHex<uint8_t > (my_bdaddr[i], 0x80); |
kotakku | 0:b1ce54272580 | 691 | Notify(PSTR(":"), 0x80); |
kotakku | 0:b1ce54272580 | 692 | } |
kotakku | 0:b1ce54272580 | 693 | D_PrintHex<uint8_t > (my_bdaddr[0], 0x80); |
kotakku | 0:b1ce54272580 | 694 | #endif |
kotakku | 0:b1ce54272580 | 695 | hci_read_local_version_information(); |
kotakku | 0:b1ce54272580 | 696 | hci_state = HCI_LOCAL_VERSION_STATE; |
kotakku | 0:b1ce54272580 | 697 | } |
kotakku | 0:b1ce54272580 | 698 | break; |
kotakku | 0:b1ce54272580 | 699 | |
kotakku | 0:b1ce54272580 | 700 | case HCI_LOCAL_VERSION_STATE: // The local version is used by the PS3BT class |
kotakku | 0:b1ce54272580 | 701 | if(hci_check_flag(HCI_FLAG_READ_VERSION)) { |
kotakku | 0:b1ce54272580 | 702 | if(btdName != NULL) { |
kotakku | 0:b1ce54272580 | 703 | hci_set_local_name(btdName); |
kotakku | 0:b1ce54272580 | 704 | hci_state = HCI_SET_NAME_STATE; |
kotakku | 0:b1ce54272580 | 705 | } else |
kotakku | 0:b1ce54272580 | 706 | hci_state = HCI_CHECK_DEVICE_SERVICE; |
kotakku | 0:b1ce54272580 | 707 | } |
kotakku | 0:b1ce54272580 | 708 | break; |
kotakku | 0:b1ce54272580 | 709 | |
kotakku | 0:b1ce54272580 | 710 | case HCI_SET_NAME_STATE: |
kotakku | 0:b1ce54272580 | 711 | if(hci_check_flag(HCI_FLAG_CMD_COMPLETE)) { |
kotakku | 0:b1ce54272580 | 712 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 713 | Notify(PSTR("\r\nThe name is set to: "), 0x80); |
kotakku | 0:b1ce54272580 | 714 | NotifyStr(btdName, 0x80); |
kotakku | 0:b1ce54272580 | 715 | #endif |
kotakku | 0:b1ce54272580 | 716 | hci_state = HCI_CHECK_DEVICE_SERVICE; |
kotakku | 0:b1ce54272580 | 717 | } |
kotakku | 0:b1ce54272580 | 718 | break; |
kotakku | 0:b1ce54272580 | 719 | |
kotakku | 0:b1ce54272580 | 720 | case HCI_CHECK_DEVICE_SERVICE: |
kotakku | 0:b1ce54272580 | 721 | if(pairWithHIDDevice || pairWithWii) { // Check if it should try to connect to a Wiimote |
kotakku | 0:b1ce54272580 | 722 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 723 | if(pairWithWii) |
kotakku | 0:b1ce54272580 | 724 | Notify(PSTR("\r\nStarting inquiry\r\nPress 1 & 2 on the Wiimote\r\nOr press the SYNC button if you are using a Wii U Pro Controller or a Wii Balance Board"), 0x80); |
kotakku | 0:b1ce54272580 | 725 | else |
kotakku | 0:b1ce54272580 | 726 | Notify(PSTR("\r\nPlease enable discovery of your device"), 0x80); |
kotakku | 0:b1ce54272580 | 727 | #endif |
kotakku | 0:b1ce54272580 | 728 | hci_inquiry(); |
kotakku | 0:b1ce54272580 | 729 | hci_state = HCI_INQUIRY_STATE; |
kotakku | 0:b1ce54272580 | 730 | } else |
kotakku | 0:b1ce54272580 | 731 | hci_state = HCI_SCANNING_STATE; // Don't try to connect to a Wiimote |
kotakku | 0:b1ce54272580 | 732 | break; |
kotakku | 0:b1ce54272580 | 733 | |
kotakku | 0:b1ce54272580 | 734 | case HCI_INQUIRY_STATE: |
kotakku | 0:b1ce54272580 | 735 | if(hci_check_flag(HCI_FLAG_DEVICE_FOUND)) { |
kotakku | 0:b1ce54272580 | 736 | hci_inquiry_cancel(); // Stop inquiry |
kotakku | 0:b1ce54272580 | 737 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 738 | if(pairWithWii) |
kotakku | 0:b1ce54272580 | 739 | Notify(PSTR("\r\nWiimote found"), 0x80); |
kotakku | 0:b1ce54272580 | 740 | else |
kotakku | 0:b1ce54272580 | 741 | Notify(PSTR("\r\nHID device found"), 0x80); |
kotakku | 0:b1ce54272580 | 742 | |
kotakku | 0:b1ce54272580 | 743 | Notify(PSTR("\r\nNow just create the instance like so:"), 0x80); |
kotakku | 0:b1ce54272580 | 744 | if(pairWithWii) |
kotakku | 0:b1ce54272580 | 745 | Notify(PSTR("\r\nWII Wii(&Btd);"), 0x80); |
kotakku | 0:b1ce54272580 | 746 | else |
kotakku | 0:b1ce54272580 | 747 | Notify(PSTR("\r\nBTHID bthid(&Btd);"), 0x80); |
kotakku | 0:b1ce54272580 | 748 | |
kotakku | 0:b1ce54272580 | 749 | Notify(PSTR("\r\nAnd then press any button on the "), 0x80); |
kotakku | 0:b1ce54272580 | 750 | if(pairWithWii) |
kotakku | 0:b1ce54272580 | 751 | Notify(PSTR("Wiimote"), 0x80); |
kotakku | 0:b1ce54272580 | 752 | else |
kotakku | 0:b1ce54272580 | 753 | Notify(PSTR("device"), 0x80); |
kotakku | 0:b1ce54272580 | 754 | #endif |
kotakku | 0:b1ce54272580 | 755 | if(checkRemoteName) { |
kotakku | 0:b1ce54272580 | 756 | hci_remote_name(); // We need to know the name to distinguish between the Wiimote, the new Wiimote with Motion Plus inside, a Wii U Pro Controller and a Wii Balance Board |
kotakku | 0:b1ce54272580 | 757 | hci_state = HCI_REMOTE_NAME_STATE; |
kotakku | 0:b1ce54272580 | 758 | } else |
kotakku | 0:b1ce54272580 | 759 | hci_state = HCI_CONNECT_DEVICE_STATE; |
kotakku | 0:b1ce54272580 | 760 | } |
kotakku | 0:b1ce54272580 | 761 | break; |
kotakku | 0:b1ce54272580 | 762 | |
kotakku | 0:b1ce54272580 | 763 | case HCI_CONNECT_DEVICE_STATE: |
kotakku | 0:b1ce54272580 | 764 | if(hci_check_flag(HCI_FLAG_CMD_COMPLETE)) { |
kotakku | 0:b1ce54272580 | 765 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 766 | if(pairWithWii) |
kotakku | 0:b1ce54272580 | 767 | Notify(PSTR("\r\nConnecting to Wiimote"), 0x80); |
kotakku | 0:b1ce54272580 | 768 | else |
kotakku | 0:b1ce54272580 | 769 | Notify(PSTR("\r\nConnecting to HID device"), 0x80); |
kotakku | 0:b1ce54272580 | 770 | #endif |
kotakku | 0:b1ce54272580 | 771 | checkRemoteName = false; |
kotakku | 0:b1ce54272580 | 772 | hci_connect(); |
kotakku | 0:b1ce54272580 | 773 | hci_state = HCI_CONNECTED_DEVICE_STATE; |
kotakku | 0:b1ce54272580 | 774 | } |
kotakku | 0:b1ce54272580 | 775 | break; |
kotakku | 0:b1ce54272580 | 776 | |
kotakku | 0:b1ce54272580 | 777 | case HCI_CONNECTED_DEVICE_STATE: |
kotakku | 0:b1ce54272580 | 778 | if(hci_check_flag(HCI_FLAG_CONNECT_EVENT)) { |
kotakku | 0:b1ce54272580 | 779 | if(hci_check_flag(HCI_FLAG_CONNECT_COMPLETE)) { |
kotakku | 0:b1ce54272580 | 780 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 781 | if(pairWithWii) |
kotakku | 0:b1ce54272580 | 782 | Notify(PSTR("\r\nConnected to Wiimote"), 0x80); |
kotakku | 0:b1ce54272580 | 783 | else |
kotakku | 0:b1ce54272580 | 784 | Notify(PSTR("\r\nConnected to HID device"), 0x80); |
kotakku | 0:b1ce54272580 | 785 | #endif |
kotakku | 0:b1ce54272580 | 786 | hci_authentication_request(); // This will start the pairing with the Wiimote |
kotakku | 0:b1ce54272580 | 787 | hci_state = HCI_SCANNING_STATE; |
kotakku | 0:b1ce54272580 | 788 | } else { |
kotakku | 0:b1ce54272580 | 789 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 790 | Notify(PSTR("\r\nTrying to connect one more time..."), 0x80); |
kotakku | 0:b1ce54272580 | 791 | #endif |
kotakku | 0:b1ce54272580 | 792 | hci_connect(); // Try to connect one more time |
kotakku | 0:b1ce54272580 | 793 | } |
kotakku | 0:b1ce54272580 | 794 | } |
kotakku | 0:b1ce54272580 | 795 | break; |
kotakku | 0:b1ce54272580 | 796 | |
kotakku | 0:b1ce54272580 | 797 | case HCI_SCANNING_STATE: |
kotakku | 0:b1ce54272580 | 798 | if(!connectToWii && !pairWithWii && !connectToHIDDevice && !pairWithHIDDevice) { |
kotakku | 0:b1ce54272580 | 799 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 800 | Notify(PSTR("\r\nWait For Incoming Connection Request"), 0x80); |
kotakku | 0:b1ce54272580 | 801 | #endif |
kotakku | 0:b1ce54272580 | 802 | hci_write_scan_enable(); |
kotakku | 0:b1ce54272580 | 803 | waitingForConnection = true; |
kotakku | 0:b1ce54272580 | 804 | hci_state = HCI_CONNECT_IN_STATE; |
kotakku | 0:b1ce54272580 | 805 | } |
kotakku | 0:b1ce54272580 | 806 | break; |
kotakku | 0:b1ce54272580 | 807 | |
kotakku | 0:b1ce54272580 | 808 | case HCI_CONNECT_IN_STATE: |
kotakku | 0:b1ce54272580 | 809 | if(hci_check_flag(HCI_FLAG_INCOMING_REQUEST)) { |
kotakku | 0:b1ce54272580 | 810 | waitingForConnection = false; |
kotakku | 0:b1ce54272580 | 811 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 812 | Notify(PSTR("\r\nIncoming Connection Request"), 0x80); |
kotakku | 0:b1ce54272580 | 813 | #endif |
kotakku | 0:b1ce54272580 | 814 | hci_remote_name(); |
kotakku | 0:b1ce54272580 | 815 | hci_state = HCI_REMOTE_NAME_STATE; |
kotakku | 0:b1ce54272580 | 816 | } else if(hci_check_flag(HCI_FLAG_DISCONNECT_COMPLETE)) |
kotakku | 0:b1ce54272580 | 817 | hci_state = HCI_DISCONNECT_STATE; |
kotakku | 0:b1ce54272580 | 818 | break; |
kotakku | 0:b1ce54272580 | 819 | |
kotakku | 0:b1ce54272580 | 820 | case HCI_REMOTE_NAME_STATE: |
kotakku | 0:b1ce54272580 | 821 | if(hci_check_flag(HCI_FLAG_REMOTE_NAME_COMPLETE)) { |
kotakku | 0:b1ce54272580 | 822 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 823 | Notify(PSTR("\r\nRemote Name: "), 0x80); |
kotakku | 0:b1ce54272580 | 824 | for(uint8_t i = 0; i < strlen(remote_name); i++) |
kotakku | 0:b1ce54272580 | 825 | Notifyc(remote_name[i], 0x80); |
kotakku | 0:b1ce54272580 | 826 | #endif |
kotakku | 0:b1ce54272580 | 827 | if(strncmp((const char*)remote_name, "Nintendo", 8) == 0) { |
kotakku | 0:b1ce54272580 | 828 | incomingWii = true; |
kotakku | 0:b1ce54272580 | 829 | motionPlusInside = false; |
kotakku | 0:b1ce54272580 | 830 | wiiUProController = false; |
kotakku | 0:b1ce54272580 | 831 | pairWiiUsingSync = false; |
kotakku | 0:b1ce54272580 | 832 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 833 | Notify(PSTR("\r\nWiimote is connecting"), 0x80); |
kotakku | 0:b1ce54272580 | 834 | #endif |
kotakku | 0:b1ce54272580 | 835 | if(strncmp((const char*)remote_name, "Nintendo RVL-CNT-01-TR", 22) == 0) { |
kotakku | 0:b1ce54272580 | 836 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 837 | Notify(PSTR(" with Motion Plus Inside"), 0x80); |
kotakku | 0:b1ce54272580 | 838 | #endif |
kotakku | 0:b1ce54272580 | 839 | motionPlusInside = true; |
kotakku | 0:b1ce54272580 | 840 | } else if(strncmp((const char*)remote_name, "Nintendo RVL-CNT-01-UC", 22) == 0) { |
kotakku | 0:b1ce54272580 | 841 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 842 | Notify(PSTR(" - Wii U Pro Controller"), 0x80); |
kotakku | 0:b1ce54272580 | 843 | #endif |
kotakku | 0:b1ce54272580 | 844 | wiiUProController = motionPlusInside = pairWiiUsingSync = true; |
kotakku | 0:b1ce54272580 | 845 | } else if(strncmp((const char*)remote_name, "Nintendo RVL-WBC-01", 19) == 0) { |
kotakku | 0:b1ce54272580 | 846 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 847 | Notify(PSTR(" - Wii Balance Board"), 0x80); |
kotakku | 0:b1ce54272580 | 848 | #endif |
kotakku | 0:b1ce54272580 | 849 | pairWiiUsingSync = true; |
kotakku | 0:b1ce54272580 | 850 | } |
kotakku | 0:b1ce54272580 | 851 | } |
kotakku | 0:b1ce54272580 | 852 | if(classOfDevice[2] == 0 && classOfDevice[1] == 0x25 && classOfDevice[0] == 0x08 && strncmp((const char*)remote_name, "Wireless Controller", 19) == 0) { |
kotakku | 0:b1ce54272580 | 853 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 854 | Notify(PSTR("\r\nPS4 controller is connecting"), 0x80); |
kotakku | 0:b1ce54272580 | 855 | #endif |
kotakku | 0:b1ce54272580 | 856 | incomingPS4 = true; |
kotakku | 0:b1ce54272580 | 857 | } |
kotakku | 0:b1ce54272580 | 858 | if(pairWithWii && checkRemoteName) |
kotakku | 0:b1ce54272580 | 859 | hci_state = HCI_CONNECT_DEVICE_STATE; |
kotakku | 0:b1ce54272580 | 860 | else { |
kotakku | 0:b1ce54272580 | 861 | hci_accept_connection(); |
kotakku | 0:b1ce54272580 | 862 | hci_state = HCI_CONNECTED_STATE; |
kotakku | 0:b1ce54272580 | 863 | } |
kotakku | 0:b1ce54272580 | 864 | } |
kotakku | 0:b1ce54272580 | 865 | break; |
kotakku | 0:b1ce54272580 | 866 | |
kotakku | 0:b1ce54272580 | 867 | case HCI_CONNECTED_STATE: |
kotakku | 0:b1ce54272580 | 868 | if(hci_check_flag(HCI_FLAG_CONNECT_COMPLETE)) { |
kotakku | 0:b1ce54272580 | 869 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 870 | Notify(PSTR("\r\nConnected to Device: "), 0x80); |
kotakku | 0:b1ce54272580 | 871 | for(int8_t i = 5; i > 0; i--) { |
kotakku | 0:b1ce54272580 | 872 | D_PrintHex<uint8_t > (disc_bdaddr[i], 0x80); |
kotakku | 0:b1ce54272580 | 873 | Notify(PSTR(":"), 0x80); |
kotakku | 0:b1ce54272580 | 874 | } |
kotakku | 0:b1ce54272580 | 875 | D_PrintHex<uint8_t > (disc_bdaddr[0], 0x80); |
kotakku | 0:b1ce54272580 | 876 | #endif |
kotakku | 0:b1ce54272580 | 877 | if(incomingPS4) |
kotakku | 0:b1ce54272580 | 878 | connectToHIDDevice = true; // We should always connect to the PS4 controller |
kotakku | 0:b1ce54272580 | 879 | |
kotakku | 0:b1ce54272580 | 880 | // Clear these flags for a new connection |
kotakku | 0:b1ce54272580 | 881 | l2capConnectionClaimed = false; |
kotakku | 0:b1ce54272580 | 882 | sdpConnectionClaimed = false; |
kotakku | 0:b1ce54272580 | 883 | rfcommConnectionClaimed = false; |
kotakku | 0:b1ce54272580 | 884 | |
kotakku | 0:b1ce54272580 | 885 | hci_event_flag = 0; |
kotakku | 0:b1ce54272580 | 886 | hci_state = HCI_DONE_STATE; |
kotakku | 0:b1ce54272580 | 887 | } |
kotakku | 0:b1ce54272580 | 888 | break; |
kotakku | 0:b1ce54272580 | 889 | |
kotakku | 0:b1ce54272580 | 890 | case HCI_DONE_STATE: |
kotakku | 0:b1ce54272580 | 891 | hci_counter++; |
kotakku | 0:b1ce54272580 | 892 | if(hci_counter > 1000) { // Wait until we have looped 1000 times to make sure that the L2CAP connection has been started |
kotakku | 0:b1ce54272580 | 893 | hci_counter = 0; |
kotakku | 0:b1ce54272580 | 894 | hci_state = HCI_SCANNING_STATE; |
kotakku | 0:b1ce54272580 | 895 | } |
kotakku | 0:b1ce54272580 | 896 | break; |
kotakku | 0:b1ce54272580 | 897 | |
kotakku | 0:b1ce54272580 | 898 | case HCI_DISCONNECT_STATE: |
kotakku | 0:b1ce54272580 | 899 | if(hci_check_flag(HCI_FLAG_DISCONNECT_COMPLETE)) { |
kotakku | 0:b1ce54272580 | 900 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 901 | Notify(PSTR("\r\nHCI Disconnected from Device"), 0x80); |
kotakku | 0:b1ce54272580 | 902 | #endif |
kotakku | 0:b1ce54272580 | 903 | hci_event_flag = 0; // Clear all flags |
kotakku | 0:b1ce54272580 | 904 | |
kotakku | 0:b1ce54272580 | 905 | // Reset all buffers |
kotakku | 0:b1ce54272580 | 906 | memset(hcibuf, 0, BULK_MAXPKTSIZE); |
kotakku | 0:b1ce54272580 | 907 | memset(l2capinbuf, 0, BULK_MAXPKTSIZE); |
kotakku | 0:b1ce54272580 | 908 | |
kotakku | 0:b1ce54272580 | 909 | connectToWii = incomingWii = pairWithWii = false; |
kotakku | 0:b1ce54272580 | 910 | connectToHIDDevice = incomingHIDDevice = pairWithHIDDevice = checkRemoteName = false; |
kotakku | 0:b1ce54272580 | 911 | incomingPS4 = false; |
kotakku | 0:b1ce54272580 | 912 | |
kotakku | 0:b1ce54272580 | 913 | hci_state = HCI_SCANNING_STATE; |
kotakku | 0:b1ce54272580 | 914 | } |
kotakku | 0:b1ce54272580 | 915 | break; |
kotakku | 0:b1ce54272580 | 916 | default: |
kotakku | 0:b1ce54272580 | 917 | break; |
kotakku | 0:b1ce54272580 | 918 | } |
kotakku | 0:b1ce54272580 | 919 | } |
kotakku | 0:b1ce54272580 | 920 | |
kotakku | 0:b1ce54272580 | 921 | void BTD::ACL_event_task() { |
kotakku | 0:b1ce54272580 | 922 | uint16_t length = BULK_MAXPKTSIZE; |
kotakku | 0:b1ce54272580 | 923 | uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ BTD_DATAIN_PIPE ].epAddr, &length, l2capinbuf, pollInterval); // Input on endpoint 2 |
kotakku | 0:b1ce54272580 | 924 | |
kotakku | 0:b1ce54272580 | 925 | if(!rcode) { // Check for errors |
kotakku | 0:b1ce54272580 | 926 | if(length > 0) { // Check if any data was read |
kotakku | 0:b1ce54272580 | 927 | for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++) { |
kotakku | 0:b1ce54272580 | 928 | if(btService[i]) |
kotakku | 0:b1ce54272580 | 929 | btService[i]->ACLData(l2capinbuf); |
kotakku | 0:b1ce54272580 | 930 | } |
kotakku | 0:b1ce54272580 | 931 | } |
kotakku | 0:b1ce54272580 | 932 | } |
kotakku | 0:b1ce54272580 | 933 | #ifdef EXTRADEBUG |
kotakku | 0:b1ce54272580 | 934 | else if(rcode != hrNAK) { |
kotakku | 0:b1ce54272580 | 935 | Notify(PSTR("\r\nACL data in error: "), 0x80); |
kotakku | 0:b1ce54272580 | 936 | D_PrintHex<uint8_t > (rcode, 0x80); |
kotakku | 0:b1ce54272580 | 937 | } |
kotakku | 0:b1ce54272580 | 938 | #endif |
kotakku | 0:b1ce54272580 | 939 | for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++) |
kotakku | 0:b1ce54272580 | 940 | if(btService[i]) |
kotakku | 0:b1ce54272580 | 941 | btService[i]->Run(); |
kotakku | 0:b1ce54272580 | 942 | } |
kotakku | 0:b1ce54272580 | 943 | |
kotakku | 0:b1ce54272580 | 944 | /************************************************************/ |
kotakku | 0:b1ce54272580 | 945 | /* HCI Commands */ |
kotakku | 0:b1ce54272580 | 946 | |
kotakku | 0:b1ce54272580 | 947 | /************************************************************/ |
kotakku | 0:b1ce54272580 | 948 | void BTD::HCI_Command(uint8_t* data, uint16_t nbytes) { |
kotakku | 0:b1ce54272580 | 949 | hci_clear_flag(HCI_FLAG_CMD_COMPLETE); |
kotakku | 0:b1ce54272580 | 950 | pUsb->ctrlReq(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, bmREQ_HCI_OUT, 0x00, 0x00, 0x00, 0x00, nbytes, nbytes, data, NULL); |
kotakku | 0:b1ce54272580 | 951 | } |
kotakku | 0:b1ce54272580 | 952 | |
kotakku | 0:b1ce54272580 | 953 | void BTD::hci_reset() { |
kotakku | 0:b1ce54272580 | 954 | hci_event_flag = 0; // Clear all the flags |
kotakku | 0:b1ce54272580 | 955 | hcibuf[0] = 0x03; // HCI OCF = 3 |
kotakku | 0:b1ce54272580 | 956 | hcibuf[1] = 0x03 << 2; // HCI OGF = 3 |
kotakku | 0:b1ce54272580 | 957 | hcibuf[2] = 0x00; |
kotakku | 0:b1ce54272580 | 958 | |
kotakku | 0:b1ce54272580 | 959 | HCI_Command(hcibuf, 3); |
kotakku | 0:b1ce54272580 | 960 | } |
kotakku | 0:b1ce54272580 | 961 | |
kotakku | 0:b1ce54272580 | 962 | void BTD::hci_write_scan_enable() { |
kotakku | 0:b1ce54272580 | 963 | hci_clear_flag(HCI_FLAG_INCOMING_REQUEST); |
kotakku | 0:b1ce54272580 | 964 | hcibuf[0] = 0x1A; // HCI OCF = 1A |
kotakku | 0:b1ce54272580 | 965 | hcibuf[1] = 0x03 << 2; // HCI OGF = 3 |
kotakku | 0:b1ce54272580 | 966 | hcibuf[2] = 0x01; // parameter length = 1 |
kotakku | 0:b1ce54272580 | 967 | if(btdName != NULL) |
kotakku | 0:b1ce54272580 | 968 | hcibuf[3] = 0x03; // Inquiry Scan enabled. Page Scan enabled. |
kotakku | 0:b1ce54272580 | 969 | else |
kotakku | 0:b1ce54272580 | 970 | hcibuf[3] = 0x02; // Inquiry Scan disabled. Page Scan enabled. |
kotakku | 0:b1ce54272580 | 971 | |
kotakku | 0:b1ce54272580 | 972 | HCI_Command(hcibuf, 4); |
kotakku | 0:b1ce54272580 | 973 | } |
kotakku | 0:b1ce54272580 | 974 | |
kotakku | 0:b1ce54272580 | 975 | void BTD::hci_write_scan_disable() { |
kotakku | 0:b1ce54272580 | 976 | hcibuf[0] = 0x1A; // HCI OCF = 1A |
kotakku | 0:b1ce54272580 | 977 | hcibuf[1] = 0x03 << 2; // HCI OGF = 3 |
kotakku | 0:b1ce54272580 | 978 | hcibuf[2] = 0x01; // parameter length = 1 |
kotakku | 0:b1ce54272580 | 979 | hcibuf[3] = 0x00; // Inquiry Scan disabled. Page Scan disabled. |
kotakku | 0:b1ce54272580 | 980 | |
kotakku | 0:b1ce54272580 | 981 | HCI_Command(hcibuf, 4); |
kotakku | 0:b1ce54272580 | 982 | } |
kotakku | 0:b1ce54272580 | 983 | |
kotakku | 0:b1ce54272580 | 984 | void BTD::hci_read_bdaddr() { |
kotakku | 0:b1ce54272580 | 985 | hci_clear_flag(HCI_FLAG_READ_BDADDR); |
kotakku | 0:b1ce54272580 | 986 | hcibuf[0] = 0x09; // HCI OCF = 9 |
kotakku | 0:b1ce54272580 | 987 | hcibuf[1] = 0x04 << 2; // HCI OGF = 4 |
kotakku | 0:b1ce54272580 | 988 | hcibuf[2] = 0x00; |
kotakku | 0:b1ce54272580 | 989 | |
kotakku | 0:b1ce54272580 | 990 | HCI_Command(hcibuf, 3); |
kotakku | 0:b1ce54272580 | 991 | } |
kotakku | 0:b1ce54272580 | 992 | |
kotakku | 0:b1ce54272580 | 993 | void BTD::hci_read_local_version_information() { |
kotakku | 0:b1ce54272580 | 994 | hci_clear_flag(HCI_FLAG_READ_VERSION); |
kotakku | 0:b1ce54272580 | 995 | hcibuf[0] = 0x01; // HCI OCF = 1 |
kotakku | 0:b1ce54272580 | 996 | hcibuf[1] = 0x04 << 2; // HCI OGF = 4 |
kotakku | 0:b1ce54272580 | 997 | hcibuf[2] = 0x00; |
kotakku | 0:b1ce54272580 | 998 | |
kotakku | 0:b1ce54272580 | 999 | HCI_Command(hcibuf, 3); |
kotakku | 0:b1ce54272580 | 1000 | } |
kotakku | 0:b1ce54272580 | 1001 | |
kotakku | 0:b1ce54272580 | 1002 | void BTD::hci_accept_connection() { |
kotakku | 0:b1ce54272580 | 1003 | hci_clear_flag(HCI_FLAG_CONNECT_COMPLETE); |
kotakku | 0:b1ce54272580 | 1004 | hcibuf[0] = 0x09; // HCI OCF = 9 |
kotakku | 0:b1ce54272580 | 1005 | hcibuf[1] = 0x01 << 2; // HCI OGF = 1 |
kotakku | 0:b1ce54272580 | 1006 | hcibuf[2] = 0x07; // parameter length 7 |
kotakku | 0:b1ce54272580 | 1007 | hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr |
kotakku | 0:b1ce54272580 | 1008 | hcibuf[4] = disc_bdaddr[1]; |
kotakku | 0:b1ce54272580 | 1009 | hcibuf[5] = disc_bdaddr[2]; |
kotakku | 0:b1ce54272580 | 1010 | hcibuf[6] = disc_bdaddr[3]; |
kotakku | 0:b1ce54272580 | 1011 | hcibuf[7] = disc_bdaddr[4]; |
kotakku | 0:b1ce54272580 | 1012 | hcibuf[8] = disc_bdaddr[5]; |
kotakku | 0:b1ce54272580 | 1013 | hcibuf[9] = 0x00; // Switch role to master |
kotakku | 0:b1ce54272580 | 1014 | |
kotakku | 0:b1ce54272580 | 1015 | HCI_Command(hcibuf, 10); |
kotakku | 0:b1ce54272580 | 1016 | } |
kotakku | 0:b1ce54272580 | 1017 | |
kotakku | 0:b1ce54272580 | 1018 | void BTD::hci_remote_name() { |
kotakku | 0:b1ce54272580 | 1019 | hci_clear_flag(HCI_FLAG_REMOTE_NAME_COMPLETE); |
kotakku | 0:b1ce54272580 | 1020 | hcibuf[0] = 0x19; // HCI OCF = 19 |
kotakku | 0:b1ce54272580 | 1021 | hcibuf[1] = 0x01 << 2; // HCI OGF = 1 |
kotakku | 0:b1ce54272580 | 1022 | hcibuf[2] = 0x0A; // parameter length = 10 |
kotakku | 0:b1ce54272580 | 1023 | hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr |
kotakku | 0:b1ce54272580 | 1024 | hcibuf[4] = disc_bdaddr[1]; |
kotakku | 0:b1ce54272580 | 1025 | hcibuf[5] = disc_bdaddr[2]; |
kotakku | 0:b1ce54272580 | 1026 | hcibuf[6] = disc_bdaddr[3]; |
kotakku | 0:b1ce54272580 | 1027 | hcibuf[7] = disc_bdaddr[4]; |
kotakku | 0:b1ce54272580 | 1028 | hcibuf[8] = disc_bdaddr[5]; |
kotakku | 0:b1ce54272580 | 1029 | hcibuf[9] = 0x01; // Page Scan Repetition Mode |
kotakku | 0:b1ce54272580 | 1030 | hcibuf[10] = 0x00; // Reserved |
kotakku | 0:b1ce54272580 | 1031 | hcibuf[11] = 0x00; // Clock offset - low byte |
kotakku | 0:b1ce54272580 | 1032 | hcibuf[12] = 0x00; // Clock offset - high byte |
kotakku | 0:b1ce54272580 | 1033 | |
kotakku | 0:b1ce54272580 | 1034 | HCI_Command(hcibuf, 13); |
kotakku | 0:b1ce54272580 | 1035 | } |
kotakku | 0:b1ce54272580 | 1036 | |
kotakku | 0:b1ce54272580 | 1037 | void BTD::hci_set_local_name(const char* name) { |
kotakku | 0:b1ce54272580 | 1038 | hcibuf[0] = 0x13; // HCI OCF = 13 |
kotakku | 0:b1ce54272580 | 1039 | hcibuf[1] = 0x03 << 2; // HCI OGF = 3 |
kotakku | 0:b1ce54272580 | 1040 | hcibuf[2] = strlen(name) + 1; // parameter length = the length of the string + end byte |
kotakku | 0:b1ce54272580 | 1041 | uint8_t i; |
kotakku | 0:b1ce54272580 | 1042 | for(i = 0; i < strlen(name); i++) |
kotakku | 0:b1ce54272580 | 1043 | hcibuf[i + 3] = name[i]; |
kotakku | 0:b1ce54272580 | 1044 | hcibuf[i + 3] = 0x00; // End of string |
kotakku | 0:b1ce54272580 | 1045 | |
kotakku | 0:b1ce54272580 | 1046 | HCI_Command(hcibuf, 4 + strlen(name)); |
kotakku | 0:b1ce54272580 | 1047 | } |
kotakku | 0:b1ce54272580 | 1048 | |
kotakku | 0:b1ce54272580 | 1049 | void BTD::hci_inquiry() { |
kotakku | 0:b1ce54272580 | 1050 | hci_clear_flag(HCI_FLAG_DEVICE_FOUND); |
kotakku | 0:b1ce54272580 | 1051 | hcibuf[0] = 0x01; |
kotakku | 0:b1ce54272580 | 1052 | hcibuf[1] = 0x01 << 2; // HCI OGF = 1 |
kotakku | 0:b1ce54272580 | 1053 | hcibuf[2] = 0x05; // Parameter Total Length = 5 |
kotakku | 0:b1ce54272580 | 1054 | hcibuf[3] = 0x33; // LAP: Genera/Unlimited Inquiry Access Code (GIAC = 0x9E8B33) - see https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm |
kotakku | 0:b1ce54272580 | 1055 | hcibuf[4] = 0x8B; |
kotakku | 0:b1ce54272580 | 1056 | hcibuf[5] = 0x9E; |
kotakku | 0:b1ce54272580 | 1057 | hcibuf[6] = 0x30; // Inquiry time = 61.44 sec (maximum) |
kotakku | 0:b1ce54272580 | 1058 | hcibuf[7] = 0x0A; // 10 number of responses |
kotakku | 0:b1ce54272580 | 1059 | |
kotakku | 0:b1ce54272580 | 1060 | HCI_Command(hcibuf, 8); |
kotakku | 0:b1ce54272580 | 1061 | } |
kotakku | 0:b1ce54272580 | 1062 | |
kotakku | 0:b1ce54272580 | 1063 | void BTD::hci_inquiry_cancel() { |
kotakku | 0:b1ce54272580 | 1064 | hcibuf[0] = 0x02; |
kotakku | 0:b1ce54272580 | 1065 | hcibuf[1] = 0x01 << 2; // HCI OGF = 1 |
kotakku | 0:b1ce54272580 | 1066 | hcibuf[2] = 0x00; // Parameter Total Length = 0 |
kotakku | 0:b1ce54272580 | 1067 | |
kotakku | 0:b1ce54272580 | 1068 | HCI_Command(hcibuf, 3); |
kotakku | 0:b1ce54272580 | 1069 | } |
kotakku | 0:b1ce54272580 | 1070 | |
kotakku | 0:b1ce54272580 | 1071 | void BTD::hci_connect() { |
kotakku | 0:b1ce54272580 | 1072 | hci_connect(disc_bdaddr); // Use last discovered device |
kotakku | 0:b1ce54272580 | 1073 | } |
kotakku | 0:b1ce54272580 | 1074 | |
kotakku | 0:b1ce54272580 | 1075 | void BTD::hci_connect(uint8_t *bdaddr) { |
kotakku | 0:b1ce54272580 | 1076 | hci_clear_flag(HCI_FLAG_CONNECT_COMPLETE | HCI_FLAG_CONNECT_EVENT); |
kotakku | 0:b1ce54272580 | 1077 | hcibuf[0] = 0x05; |
kotakku | 0:b1ce54272580 | 1078 | hcibuf[1] = 0x01 << 2; // HCI OGF = 1 |
kotakku | 0:b1ce54272580 | 1079 | hcibuf[2] = 0x0D; // parameter Total Length = 13 |
kotakku | 0:b1ce54272580 | 1080 | hcibuf[3] = bdaddr[0]; // 6 octet bdaddr (LSB) |
kotakku | 0:b1ce54272580 | 1081 | hcibuf[4] = bdaddr[1]; |
kotakku | 0:b1ce54272580 | 1082 | hcibuf[5] = bdaddr[2]; |
kotakku | 0:b1ce54272580 | 1083 | hcibuf[6] = bdaddr[3]; |
kotakku | 0:b1ce54272580 | 1084 | hcibuf[7] = bdaddr[4]; |
kotakku | 0:b1ce54272580 | 1085 | hcibuf[8] = bdaddr[5]; |
kotakku | 0:b1ce54272580 | 1086 | hcibuf[9] = 0x18; // DM1 or DH1 may be used |
kotakku | 0:b1ce54272580 | 1087 | hcibuf[10] = 0xCC; // DM3, DH3, DM5, DH5 may be used |
kotakku | 0:b1ce54272580 | 1088 | hcibuf[11] = 0x01; // Page repetition mode R1 |
kotakku | 0:b1ce54272580 | 1089 | hcibuf[12] = 0x00; // Reserved |
kotakku | 0:b1ce54272580 | 1090 | hcibuf[13] = 0x00; // Clock offset |
kotakku | 0:b1ce54272580 | 1091 | hcibuf[14] = 0x00; // Invalid clock offset |
kotakku | 0:b1ce54272580 | 1092 | hcibuf[15] = 0x00; // Do not allow role switch |
kotakku | 0:b1ce54272580 | 1093 | |
kotakku | 0:b1ce54272580 | 1094 | HCI_Command(hcibuf, 16); |
kotakku | 0:b1ce54272580 | 1095 | } |
kotakku | 0:b1ce54272580 | 1096 | |
kotakku | 0:b1ce54272580 | 1097 | void BTD::hci_pin_code_request_reply() { |
kotakku | 0:b1ce54272580 | 1098 | hcibuf[0] = 0x0D; // HCI OCF = 0D |
kotakku | 0:b1ce54272580 | 1099 | hcibuf[1] = 0x01 << 2; // HCI OGF = 1 |
kotakku | 0:b1ce54272580 | 1100 | hcibuf[2] = 0x17; // parameter length 23 |
kotakku | 0:b1ce54272580 | 1101 | hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr |
kotakku | 0:b1ce54272580 | 1102 | hcibuf[4] = disc_bdaddr[1]; |
kotakku | 0:b1ce54272580 | 1103 | hcibuf[5] = disc_bdaddr[2]; |
kotakku | 0:b1ce54272580 | 1104 | hcibuf[6] = disc_bdaddr[3]; |
kotakku | 0:b1ce54272580 | 1105 | hcibuf[7] = disc_bdaddr[4]; |
kotakku | 0:b1ce54272580 | 1106 | hcibuf[8] = disc_bdaddr[5]; |
kotakku | 0:b1ce54272580 | 1107 | if(pairWithWii) { |
kotakku | 0:b1ce54272580 | 1108 | hcibuf[9] = 6; // Pin length is the length of the Bluetooth address |
kotakku | 0:b1ce54272580 | 1109 | if(pairWiiUsingSync) { |
kotakku | 0:b1ce54272580 | 1110 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 1111 | Notify(PSTR("\r\nPairing with Wii controller via SYNC"), 0x80); |
kotakku | 0:b1ce54272580 | 1112 | #endif |
kotakku | 0:b1ce54272580 | 1113 | for(uint8_t i = 0; i < 6; i++) |
kotakku | 0:b1ce54272580 | 1114 | hcibuf[10 + i] = my_bdaddr[i]; // The pin is the Bluetooth dongles Bluetooth address backwards |
kotakku | 0:b1ce54272580 | 1115 | } else { |
kotakku | 0:b1ce54272580 | 1116 | for(uint8_t i = 0; i < 6; i++) |
kotakku | 0:b1ce54272580 | 1117 | hcibuf[10 + i] = disc_bdaddr[i]; // The pin is the Wiimote's Bluetooth address backwards |
kotakku | 0:b1ce54272580 | 1118 | } |
kotakku | 0:b1ce54272580 | 1119 | for(uint8_t i = 16; i < 26; i++) |
kotakku | 0:b1ce54272580 | 1120 | hcibuf[i] = 0x00; // The rest should be 0 |
kotakku | 0:b1ce54272580 | 1121 | } else { |
kotakku | 0:b1ce54272580 | 1122 | hcibuf[9] = strlen(btdPin); // Length of pin |
kotakku | 0:b1ce54272580 | 1123 | uint8_t i; |
kotakku | 0:b1ce54272580 | 1124 | for(i = 0; i < strlen(btdPin); i++) // The maximum size of the pin is 16 |
kotakku | 0:b1ce54272580 | 1125 | hcibuf[i + 10] = btdPin[i]; |
kotakku | 0:b1ce54272580 | 1126 | for(; i < 16; i++) |
kotakku | 0:b1ce54272580 | 1127 | hcibuf[i + 10] = 0x00; // The rest should be 0 |
kotakku | 0:b1ce54272580 | 1128 | } |
kotakku | 0:b1ce54272580 | 1129 | |
kotakku | 0:b1ce54272580 | 1130 | HCI_Command(hcibuf, 26); |
kotakku | 0:b1ce54272580 | 1131 | } |
kotakku | 0:b1ce54272580 | 1132 | |
kotakku | 0:b1ce54272580 | 1133 | void BTD::hci_pin_code_negative_request_reply() { |
kotakku | 0:b1ce54272580 | 1134 | hcibuf[0] = 0x0E; // HCI OCF = 0E |
kotakku | 0:b1ce54272580 | 1135 | hcibuf[1] = 0x01 << 2; // HCI OGF = 1 |
kotakku | 0:b1ce54272580 | 1136 | hcibuf[2] = 0x06; // parameter length 6 |
kotakku | 0:b1ce54272580 | 1137 | hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr |
kotakku | 0:b1ce54272580 | 1138 | hcibuf[4] = disc_bdaddr[1]; |
kotakku | 0:b1ce54272580 | 1139 | hcibuf[5] = disc_bdaddr[2]; |
kotakku | 0:b1ce54272580 | 1140 | hcibuf[6] = disc_bdaddr[3]; |
kotakku | 0:b1ce54272580 | 1141 | hcibuf[7] = disc_bdaddr[4]; |
kotakku | 0:b1ce54272580 | 1142 | hcibuf[8] = disc_bdaddr[5]; |
kotakku | 0:b1ce54272580 | 1143 | |
kotakku | 0:b1ce54272580 | 1144 | HCI_Command(hcibuf, 9); |
kotakku | 0:b1ce54272580 | 1145 | } |
kotakku | 0:b1ce54272580 | 1146 | |
kotakku | 0:b1ce54272580 | 1147 | void BTD::hci_link_key_request_negative_reply() { |
kotakku | 0:b1ce54272580 | 1148 | hcibuf[0] = 0x0C; // HCI OCF = 0C |
kotakku | 0:b1ce54272580 | 1149 | hcibuf[1] = 0x01 << 2; // HCI OGF = 1 |
kotakku | 0:b1ce54272580 | 1150 | hcibuf[2] = 0x06; // parameter length 6 |
kotakku | 0:b1ce54272580 | 1151 | hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr |
kotakku | 0:b1ce54272580 | 1152 | hcibuf[4] = disc_bdaddr[1]; |
kotakku | 0:b1ce54272580 | 1153 | hcibuf[5] = disc_bdaddr[2]; |
kotakku | 0:b1ce54272580 | 1154 | hcibuf[6] = disc_bdaddr[3]; |
kotakku | 0:b1ce54272580 | 1155 | hcibuf[7] = disc_bdaddr[4]; |
kotakku | 0:b1ce54272580 | 1156 | hcibuf[8] = disc_bdaddr[5]; |
kotakku | 0:b1ce54272580 | 1157 | |
kotakku | 0:b1ce54272580 | 1158 | HCI_Command(hcibuf, 9); |
kotakku | 0:b1ce54272580 | 1159 | } |
kotakku | 0:b1ce54272580 | 1160 | |
kotakku | 0:b1ce54272580 | 1161 | void BTD::hci_authentication_request() { |
kotakku | 0:b1ce54272580 | 1162 | hcibuf[0] = 0x11; // HCI OCF = 11 |
kotakku | 0:b1ce54272580 | 1163 | hcibuf[1] = 0x01 << 2; // HCI OGF = 1 |
kotakku | 0:b1ce54272580 | 1164 | hcibuf[2] = 0x02; // parameter length = 2 |
kotakku | 0:b1ce54272580 | 1165 | hcibuf[3] = (uint8_t)(hci_handle & 0xFF); //connection handle - low byte |
kotakku | 0:b1ce54272580 | 1166 | hcibuf[4] = (uint8_t)((hci_handle >> 8) & 0x0F); //connection handle - high byte |
kotakku | 0:b1ce54272580 | 1167 | |
kotakku | 0:b1ce54272580 | 1168 | HCI_Command(hcibuf, 5); |
kotakku | 0:b1ce54272580 | 1169 | } |
kotakku | 0:b1ce54272580 | 1170 | |
kotakku | 0:b1ce54272580 | 1171 | void BTD::hci_disconnect(uint16_t handle) { // This is called by the different services |
kotakku | 0:b1ce54272580 | 1172 | hci_clear_flag(HCI_FLAG_DISCONNECT_COMPLETE); |
kotakku | 0:b1ce54272580 | 1173 | hcibuf[0] = 0x06; // HCI OCF = 6 |
kotakku | 0:b1ce54272580 | 1174 | hcibuf[1] = 0x01 << 2; // HCI OGF = 1 |
kotakku | 0:b1ce54272580 | 1175 | hcibuf[2] = 0x03; // parameter length = 3 |
kotakku | 0:b1ce54272580 | 1176 | hcibuf[3] = (uint8_t)(handle & 0xFF); //connection handle - low byte |
kotakku | 0:b1ce54272580 | 1177 | hcibuf[4] = (uint8_t)((handle >> 8) & 0x0F); //connection handle - high byte |
kotakku | 0:b1ce54272580 | 1178 | hcibuf[5] = 0x13; // reason |
kotakku | 0:b1ce54272580 | 1179 | |
kotakku | 0:b1ce54272580 | 1180 | HCI_Command(hcibuf, 6); |
kotakku | 0:b1ce54272580 | 1181 | } |
kotakku | 0:b1ce54272580 | 1182 | |
kotakku | 0:b1ce54272580 | 1183 | void BTD::hci_write_class_of_device() { // See http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html |
kotakku | 0:b1ce54272580 | 1184 | hcibuf[0] = 0x24; // HCI OCF = 24 |
kotakku | 0:b1ce54272580 | 1185 | hcibuf[1] = 0x03 << 2; // HCI OGF = 3 |
kotakku | 0:b1ce54272580 | 1186 | hcibuf[2] = 0x03; // parameter length = 3 |
kotakku | 0:b1ce54272580 | 1187 | hcibuf[3] = 0x04; // Robot |
kotakku | 0:b1ce54272580 | 1188 | hcibuf[4] = 0x08; // Toy |
kotakku | 0:b1ce54272580 | 1189 | hcibuf[5] = 0x00; |
kotakku | 0:b1ce54272580 | 1190 | |
kotakku | 0:b1ce54272580 | 1191 | HCI_Command(hcibuf, 6); |
kotakku | 0:b1ce54272580 | 1192 | } |
kotakku | 0:b1ce54272580 | 1193 | /******************************************************************* |
kotakku | 0:b1ce54272580 | 1194 | * * |
kotakku | 0:b1ce54272580 | 1195 | * HCI ACL Data Packet * |
kotakku | 0:b1ce54272580 | 1196 | * * |
kotakku | 0:b1ce54272580 | 1197 | * buf[0] buf[1] buf[2] buf[3] |
kotakku | 0:b1ce54272580 | 1198 | * 0 4 8 11 12 16 24 31 MSB |
kotakku | 0:b1ce54272580 | 1199 | * .-+-+-+-+-+-+-+-|-+-+-+-|-+-|-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-. |
kotakku | 0:b1ce54272580 | 1200 | * | HCI Handle |PB |BC | Data Total Length | HCI ACL Data Packet |
kotakku | 0:b1ce54272580 | 1201 | * .-+-+-+-+-+-+-+-|-+-+-+-|-+-|-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-. |
kotakku | 0:b1ce54272580 | 1202 | * |
kotakku | 0:b1ce54272580 | 1203 | * buf[4] buf[5] buf[6] buf[7] |
kotakku | 0:b1ce54272580 | 1204 | * 0 8 16 31 MSB |
kotakku | 0:b1ce54272580 | 1205 | * .-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-. |
kotakku | 0:b1ce54272580 | 1206 | * | Length | Channel ID | Basic L2CAP header |
kotakku | 0:b1ce54272580 | 1207 | * .-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-. |
kotakku | 0:b1ce54272580 | 1208 | * |
kotakku | 0:b1ce54272580 | 1209 | * buf[8] buf[9] buf[10] buf[11] |
kotakku | 0:b1ce54272580 | 1210 | * 0 8 16 31 MSB |
kotakku | 0:b1ce54272580 | 1211 | * .-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-. |
kotakku | 0:b1ce54272580 | 1212 | * | Code | Identifier | Length | Control frame (C-frame) |
kotakku | 0:b1ce54272580 | 1213 | * .-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-. (signaling packet format) |
kotakku | 0:b1ce54272580 | 1214 | */ |
kotakku | 0:b1ce54272580 | 1215 | /************************************************************/ |
kotakku | 0:b1ce54272580 | 1216 | /* L2CAP Commands */ |
kotakku | 0:b1ce54272580 | 1217 | |
kotakku | 0:b1ce54272580 | 1218 | /************************************************************/ |
kotakku | 0:b1ce54272580 | 1219 | void BTD::L2CAP_Command(uint16_t handle, uint8_t* data, uint8_t nbytes, uint8_t channelLow, uint8_t channelHigh) { |
kotakku | 0:b1ce54272580 | 1220 | uint8_t buf[8 + nbytes]; |
kotakku | 0:b1ce54272580 | 1221 | buf[0] = (uint8_t)(handle & 0xff); // HCI handle with PB,BC flag |
kotakku | 0:b1ce54272580 | 1222 | buf[1] = (uint8_t)(((handle >> 8) & 0x0f) | 0x20); |
kotakku | 0:b1ce54272580 | 1223 | buf[2] = (uint8_t)((4 + nbytes) & 0xff); // HCI ACL total data length |
kotakku | 0:b1ce54272580 | 1224 | buf[3] = (uint8_t)((4 + nbytes) >> 8); |
kotakku | 0:b1ce54272580 | 1225 | buf[4] = (uint8_t)(nbytes & 0xff); // L2CAP header: Length |
kotakku | 0:b1ce54272580 | 1226 | buf[5] = (uint8_t)(nbytes >> 8); |
kotakku | 0:b1ce54272580 | 1227 | buf[6] = channelLow; |
kotakku | 0:b1ce54272580 | 1228 | buf[7] = channelHigh; |
kotakku | 0:b1ce54272580 | 1229 | |
kotakku | 0:b1ce54272580 | 1230 | for(uint16_t i = 0; i < nbytes; i++) // L2CAP C-frame |
kotakku | 0:b1ce54272580 | 1231 | buf[8 + i] = data[i]; |
kotakku | 0:b1ce54272580 | 1232 | |
kotakku | 0:b1ce54272580 | 1233 | uint8_t rcode = pUsb->outTransfer(bAddress, epInfo[ BTD_DATAOUT_PIPE ].epAddr, (8 + nbytes), buf); |
kotakku | 0:b1ce54272580 | 1234 | if(rcode) { |
kotakku | 0:b1ce54272580 | 1235 | delay(100); // This small delay prevents it from overflowing if it fails |
kotakku | 0:b1ce54272580 | 1236 | #ifdef DEBUG_USB_HOST |
kotakku | 0:b1ce54272580 | 1237 | Notify(PSTR("\r\nError sending L2CAP message: 0x"), 0x80); |
kotakku | 0:b1ce54272580 | 1238 | D_PrintHex<uint8_t > (rcode, 0x80); |
kotakku | 0:b1ce54272580 | 1239 | Notify(PSTR(" - Channel ID: "), 0x80); |
kotakku | 0:b1ce54272580 | 1240 | D_PrintHex<uint8_t > (channelHigh, 0x80); |
kotakku | 0:b1ce54272580 | 1241 | Notify(PSTR(" "), 0x80); |
kotakku | 0:b1ce54272580 | 1242 | D_PrintHex<uint8_t > (channelLow, 0x80); |
kotakku | 0:b1ce54272580 | 1243 | #endif |
kotakku | 0:b1ce54272580 | 1244 | } |
kotakku | 0:b1ce54272580 | 1245 | } |
kotakku | 0:b1ce54272580 | 1246 | |
kotakku | 0:b1ce54272580 | 1247 | void BTD::l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t* scid, uint16_t psm) { |
kotakku | 0:b1ce54272580 | 1248 | l2capoutbuf[0] = L2CAP_CMD_CONNECTION_REQUEST; // Code |
kotakku | 0:b1ce54272580 | 1249 | l2capoutbuf[1] = rxid; // Identifier |
kotakku | 0:b1ce54272580 | 1250 | l2capoutbuf[2] = 0x04; // Length |
kotakku | 0:b1ce54272580 | 1251 | l2capoutbuf[3] = 0x00; |
kotakku | 0:b1ce54272580 | 1252 | l2capoutbuf[4] = (uint8_t)(psm & 0xff); // PSM |
kotakku | 0:b1ce54272580 | 1253 | l2capoutbuf[5] = (uint8_t)(psm >> 8); |
kotakku | 0:b1ce54272580 | 1254 | l2capoutbuf[6] = scid[0]; // Source CID |
kotakku | 0:b1ce54272580 | 1255 | l2capoutbuf[7] = scid[1]; |
kotakku | 0:b1ce54272580 | 1256 | |
kotakku | 0:b1ce54272580 | 1257 | L2CAP_Command(handle, l2capoutbuf, 8); |
kotakku | 0:b1ce54272580 | 1258 | } |
kotakku | 0:b1ce54272580 | 1259 | |
kotakku | 0:b1ce54272580 | 1260 | void BTD::l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid, uint8_t result) { |
kotakku | 0:b1ce54272580 | 1261 | l2capoutbuf[0] = L2CAP_CMD_CONNECTION_RESPONSE; // Code |
kotakku | 0:b1ce54272580 | 1262 | l2capoutbuf[1] = rxid; // Identifier |
kotakku | 0:b1ce54272580 | 1263 | l2capoutbuf[2] = 0x08; // Length |
kotakku | 0:b1ce54272580 | 1264 | l2capoutbuf[3] = 0x00; |
kotakku | 0:b1ce54272580 | 1265 | l2capoutbuf[4] = dcid[0]; // Destination CID |
kotakku | 0:b1ce54272580 | 1266 | l2capoutbuf[5] = dcid[1]; |
kotakku | 0:b1ce54272580 | 1267 | l2capoutbuf[6] = scid[0]; // Source CID |
kotakku | 0:b1ce54272580 | 1268 | l2capoutbuf[7] = scid[1]; |
kotakku | 0:b1ce54272580 | 1269 | l2capoutbuf[8] = result; // Result: Pending or Success |
kotakku | 0:b1ce54272580 | 1270 | l2capoutbuf[9] = 0x00; |
kotakku | 0:b1ce54272580 | 1271 | l2capoutbuf[10] = 0x00; // No further information |
kotakku | 0:b1ce54272580 | 1272 | l2capoutbuf[11] = 0x00; |
kotakku | 0:b1ce54272580 | 1273 | |
kotakku | 0:b1ce54272580 | 1274 | L2CAP_Command(handle, l2capoutbuf, 12); |
kotakku | 0:b1ce54272580 | 1275 | } |
kotakku | 0:b1ce54272580 | 1276 | |
kotakku | 0:b1ce54272580 | 1277 | void BTD::l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t* dcid) { |
kotakku | 0:b1ce54272580 | 1278 | l2capoutbuf[0] = L2CAP_CMD_CONFIG_REQUEST; // Code |
kotakku | 0:b1ce54272580 | 1279 | l2capoutbuf[1] = rxid; // Identifier |
kotakku | 0:b1ce54272580 | 1280 | l2capoutbuf[2] = 0x08; // Length |
kotakku | 0:b1ce54272580 | 1281 | l2capoutbuf[3] = 0x00; |
kotakku | 0:b1ce54272580 | 1282 | l2capoutbuf[4] = dcid[0]; // Destination CID |
kotakku | 0:b1ce54272580 | 1283 | l2capoutbuf[5] = dcid[1]; |
kotakku | 0:b1ce54272580 | 1284 | l2capoutbuf[6] = 0x00; // Flags |
kotakku | 0:b1ce54272580 | 1285 | l2capoutbuf[7] = 0x00; |
kotakku | 0:b1ce54272580 | 1286 | l2capoutbuf[8] = 0x01; // Config Opt: type = MTU (Maximum Transmission Unit) - Hint |
kotakku | 0:b1ce54272580 | 1287 | l2capoutbuf[9] = 0x02; // Config Opt: length |
kotakku | 0:b1ce54272580 | 1288 | l2capoutbuf[10] = 0xFF; // MTU |
kotakku | 0:b1ce54272580 | 1289 | l2capoutbuf[11] = 0xFF; |
kotakku | 0:b1ce54272580 | 1290 | |
kotakku | 0:b1ce54272580 | 1291 | L2CAP_Command(handle, l2capoutbuf, 12); |
kotakku | 0:b1ce54272580 | 1292 | } |
kotakku | 0:b1ce54272580 | 1293 | |
kotakku | 0:b1ce54272580 | 1294 | void BTD::l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t* scid) { |
kotakku | 0:b1ce54272580 | 1295 | l2capoutbuf[0] = L2CAP_CMD_CONFIG_RESPONSE; // Code |
kotakku | 0:b1ce54272580 | 1296 | l2capoutbuf[1] = rxid; // Identifier |
kotakku | 0:b1ce54272580 | 1297 | l2capoutbuf[2] = 0x0A; // Length |
kotakku | 0:b1ce54272580 | 1298 | l2capoutbuf[3] = 0x00; |
kotakku | 0:b1ce54272580 | 1299 | l2capoutbuf[4] = scid[0]; // Source CID |
kotakku | 0:b1ce54272580 | 1300 | l2capoutbuf[5] = scid[1]; |
kotakku | 0:b1ce54272580 | 1301 | l2capoutbuf[6] = 0x00; // Flag |
kotakku | 0:b1ce54272580 | 1302 | l2capoutbuf[7] = 0x00; |
kotakku | 0:b1ce54272580 | 1303 | l2capoutbuf[8] = 0x00; // Result |
kotakku | 0:b1ce54272580 | 1304 | l2capoutbuf[9] = 0x00; |
kotakku | 0:b1ce54272580 | 1305 | l2capoutbuf[10] = 0x01; // Config |
kotakku | 0:b1ce54272580 | 1306 | l2capoutbuf[11] = 0x02; |
kotakku | 0:b1ce54272580 | 1307 | l2capoutbuf[12] = 0xA0; |
kotakku | 0:b1ce54272580 | 1308 | l2capoutbuf[13] = 0x02; |
kotakku | 0:b1ce54272580 | 1309 | |
kotakku | 0:b1ce54272580 | 1310 | L2CAP_Command(handle, l2capoutbuf, 14); |
kotakku | 0:b1ce54272580 | 1311 | } |
kotakku | 0:b1ce54272580 | 1312 | |
kotakku | 0:b1ce54272580 | 1313 | void BTD::l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid) { |
kotakku | 0:b1ce54272580 | 1314 | l2capoutbuf[0] = L2CAP_CMD_DISCONNECT_REQUEST; // Code |
kotakku | 0:b1ce54272580 | 1315 | l2capoutbuf[1] = rxid; // Identifier |
kotakku | 0:b1ce54272580 | 1316 | l2capoutbuf[2] = 0x04; // Length |
kotakku | 0:b1ce54272580 | 1317 | l2capoutbuf[3] = 0x00; |
kotakku | 0:b1ce54272580 | 1318 | l2capoutbuf[4] = dcid[0]; |
kotakku | 0:b1ce54272580 | 1319 | l2capoutbuf[5] = dcid[1]; |
kotakku | 0:b1ce54272580 | 1320 | l2capoutbuf[6] = scid[0]; |
kotakku | 0:b1ce54272580 | 1321 | l2capoutbuf[7] = scid[1]; |
kotakku | 0:b1ce54272580 | 1322 | |
kotakku | 0:b1ce54272580 | 1323 | L2CAP_Command(handle, l2capoutbuf, 8); |
kotakku | 0:b1ce54272580 | 1324 | } |
kotakku | 0:b1ce54272580 | 1325 | |
kotakku | 0:b1ce54272580 | 1326 | void BTD::l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid) { |
kotakku | 0:b1ce54272580 | 1327 | l2capoutbuf[0] = L2CAP_CMD_DISCONNECT_RESPONSE; // Code |
kotakku | 0:b1ce54272580 | 1328 | l2capoutbuf[1] = rxid; // Identifier |
kotakku | 0:b1ce54272580 | 1329 | l2capoutbuf[2] = 0x04; // Length |
kotakku | 0:b1ce54272580 | 1330 | l2capoutbuf[3] = 0x00; |
kotakku | 0:b1ce54272580 | 1331 | l2capoutbuf[4] = dcid[0]; |
kotakku | 0:b1ce54272580 | 1332 | l2capoutbuf[5] = dcid[1]; |
kotakku | 0:b1ce54272580 | 1333 | l2capoutbuf[6] = scid[0]; |
kotakku | 0:b1ce54272580 | 1334 | l2capoutbuf[7] = scid[1]; |
kotakku | 0:b1ce54272580 | 1335 | |
kotakku | 0:b1ce54272580 | 1336 | L2CAP_Command(handle, l2capoutbuf, 8); |
kotakku | 0:b1ce54272580 | 1337 | } |
kotakku | 0:b1ce54272580 | 1338 | |
kotakku | 0:b1ce54272580 | 1339 | void BTD::l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh) { |
kotakku | 0:b1ce54272580 | 1340 | l2capoutbuf[0] = L2CAP_CMD_INFORMATION_RESPONSE; // Code |
kotakku | 0:b1ce54272580 | 1341 | l2capoutbuf[1] = rxid; // Identifier |
kotakku | 0:b1ce54272580 | 1342 | l2capoutbuf[2] = 0x08; // Length |
kotakku | 0:b1ce54272580 | 1343 | l2capoutbuf[3] = 0x00; |
kotakku | 0:b1ce54272580 | 1344 | l2capoutbuf[4] = infoTypeLow; |
kotakku | 0:b1ce54272580 | 1345 | l2capoutbuf[5] = infoTypeHigh; |
kotakku | 0:b1ce54272580 | 1346 | l2capoutbuf[6] = 0x00; // Result = success |
kotakku | 0:b1ce54272580 | 1347 | l2capoutbuf[7] = 0x00; // Result = success |
kotakku | 0:b1ce54272580 | 1348 | l2capoutbuf[8] = 0x00; |
kotakku | 0:b1ce54272580 | 1349 | l2capoutbuf[9] = 0x00; |
kotakku | 0:b1ce54272580 | 1350 | l2capoutbuf[10] = 0x00; |
kotakku | 0:b1ce54272580 | 1351 | l2capoutbuf[11] = 0x00; |
kotakku | 0:b1ce54272580 | 1352 | |
kotakku | 0:b1ce54272580 | 1353 | L2CAP_Command(handle, l2capoutbuf, 12); |
kotakku | 0:b1ce54272580 | 1354 | } |
kotakku | 0:b1ce54272580 | 1355 | |
kotakku | 0:b1ce54272580 | 1356 | /* PS3 Commands - only set Bluetooth address is implemented in this library */ |
kotakku | 0:b1ce54272580 | 1357 | void BTD::setBdaddr(uint8_t* bdaddr) { |
kotakku | 0:b1ce54272580 | 1358 | /* Set the internal Bluetooth address */ |
kotakku | 0:b1ce54272580 | 1359 | uint8_t buf[8]; |
kotakku | 0:b1ce54272580 | 1360 | buf[0] = 0x01; |
kotakku | 0:b1ce54272580 | 1361 | buf[1] = 0x00; |
kotakku | 0:b1ce54272580 | 1362 | |
kotakku | 0:b1ce54272580 | 1363 | for(uint8_t i = 0; i < 6; i++) |
kotakku | 0:b1ce54272580 | 1364 | buf[i + 2] = bdaddr[5 - i]; // Copy into buffer, has to be written reversed, so it is MSB first |
kotakku | 0:b1ce54272580 | 1365 | |
kotakku | 0:b1ce54272580 | 1366 | // bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data |
kotakku | 0:b1ce54272580 | 1367 | pUsb->ctrlReq(bAddress, epInfo[BTD_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF5, 0x03, 0x00, 8, 8, buf, NULL); |
kotakku | 0:b1ce54272580 | 1368 | } |
kotakku | 0:b1ce54272580 | 1369 | |
kotakku | 0:b1ce54272580 | 1370 | void BTD::setMoveBdaddr(uint8_t* bdaddr) { |
kotakku | 0:b1ce54272580 | 1371 | /* Set the internal Bluetooth address */ |
kotakku | 0:b1ce54272580 | 1372 | uint8_t buf[11]; |
kotakku | 0:b1ce54272580 | 1373 | buf[0] = 0x05; |
kotakku | 0:b1ce54272580 | 1374 | buf[7] = 0x10; |
kotakku | 0:b1ce54272580 | 1375 | buf[8] = 0x01; |
kotakku | 0:b1ce54272580 | 1376 | buf[9] = 0x02; |
kotakku | 0:b1ce54272580 | 1377 | buf[10] = 0x12; |
kotakku | 0:b1ce54272580 | 1378 | |
kotakku | 0:b1ce54272580 | 1379 | for(uint8_t i = 0; i < 6; i++) |
kotakku | 0:b1ce54272580 | 1380 | buf[i + 1] = bdaddr[i]; |
kotakku | 0:b1ce54272580 | 1381 | |
kotakku | 0:b1ce54272580 | 1382 | // bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x05), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data |
kotakku | 0:b1ce54272580 | 1383 | pUsb->ctrlReq(bAddress, epInfo[BTD_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x05, 0x03, 0x00, 11, 11, buf, NULL); |
kotakku | 0:b1ce54272580 | 1384 | } |
kotakku | 0:b1ce54272580 | 1385 |