Test version of BlueUSB stack. Includes SDP and RFCOMM. As Client it allows to connect to my fischertechnik TX Controller. As Server it echo\\\\\\\'s characters to Putty. PIN=1234
Dependencies: mbed myUSBHost AvailableMemory
Dependents: mbed_TANK_Kinect myBlueUSB_ros ftusbClass
hci.cpp@0:81ed8b6e4a8b, 2011-04-04 (annotated)
- Committer:
- networker
- Date:
- Mon Apr 04 16:41:03 2011 +0000
- Revision:
- 0:81ed8b6e4a8b
initial revision
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
networker | 0:81ed8b6e4a8b | 1 | |
networker | 0:81ed8b6e4a8b | 2 | /* |
networker | 0:81ed8b6e4a8b | 3 | Copyright (c) 2010 Peter Barrett |
networker | 0:81ed8b6e4a8b | 4 | |
networker | 0:81ed8b6e4a8b | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy |
networker | 0:81ed8b6e4a8b | 6 | of this software and associated documentation files (the "Software"), to deal |
networker | 0:81ed8b6e4a8b | 7 | in the Software without restriction, including without limitation the rights |
networker | 0:81ed8b6e4a8b | 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
networker | 0:81ed8b6e4a8b | 9 | copies of the Software, and to permit persons to whom the Software is |
networker | 0:81ed8b6e4a8b | 10 | furnished to do so, subject to the following conditions: |
networker | 0:81ed8b6e4a8b | 11 | |
networker | 0:81ed8b6e4a8b | 12 | The above copyright notice and this permission notice shall be included in |
networker | 0:81ed8b6e4a8b | 13 | all copies or substantial portions of the Software. |
networker | 0:81ed8b6e4a8b | 14 | |
networker | 0:81ed8b6e4a8b | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
networker | 0:81ed8b6e4a8b | 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
networker | 0:81ed8b6e4a8b | 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
networker | 0:81ed8b6e4a8b | 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
networker | 0:81ed8b6e4a8b | 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
networker | 0:81ed8b6e4a8b | 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
networker | 0:81ed8b6e4a8b | 21 | THE SOFTWARE. |
networker | 0:81ed8b6e4a8b | 22 | */ |
networker | 0:81ed8b6e4a8b | 23 | |
networker | 0:81ed8b6e4a8b | 24 | #include <stdio.h> |
networker | 0:81ed8b6e4a8b | 25 | #include <stdlib.h> |
networker | 0:81ed8b6e4a8b | 26 | #include <stdio.h> |
networker | 0:81ed8b6e4a8b | 27 | #include <string.h> |
networker | 0:81ed8b6e4a8b | 28 | |
networker | 0:81ed8b6e4a8b | 29 | #include "Utils.h" |
networker | 0:81ed8b6e4a8b | 30 | #include "hci.h" |
networker | 0:81ed8b6e4a8b | 31 | #include "hci_private.h" |
networker | 0:81ed8b6e4a8b | 32 | #include "USBHost.h" //for USBLoop |
networker | 0:81ed8b6e4a8b | 33 | |
networker | 0:81ed8b6e4a8b | 34 | enum hci_callback_evt { |
networker | 0:81ed8b6e4a8b | 35 | NONE, |
networker | 0:81ed8b6e4a8b | 36 | CONNECT, |
networker | 0:81ed8b6e4a8b | 37 | DISCONECT, |
networker | 0:81ed8b6e4a8b | 38 | INQUIRYRESULT |
networker | 0:81ed8b6e4a8b | 39 | }; |
networker | 0:81ed8b6e4a8b | 40 | |
networker | 0:81ed8b6e4a8b | 41 | #define MAX_BLUETOOTH_ADAPTERS 1 |
networker | 0:81ed8b6e4a8b | 42 | |
networker | 0:81ed8b6e4a8b | 43 | enum StateMask { |
networker | 0:81ed8b6e4a8b | 44 | MASK_RESET = 1, |
networker | 0:81ed8b6e4a8b | 45 | MASK_READ_BUFFER_SIZE = 2, |
networker | 0:81ed8b6e4a8b | 46 | MASK_READ_BD_ADDR = 4, |
networker | 0:81ed8b6e4a8b | 47 | MASK_INITED = 8, |
networker | 0:81ed8b6e4a8b | 48 | MASK_INQUIRY = 16, |
networker | 0:81ed8b6e4a8b | 49 | MASK_REMOTE_NAME = 32, |
networker | 0:81ed8b6e4a8b | 50 | MASK_CREATE_CONNECTION = 64 |
networker | 0:81ed8b6e4a8b | 51 | }; |
networker | 0:81ed8b6e4a8b | 52 | |
networker | 0:81ed8b6e4a8b | 53 | int HCI::Open(HCITransport* transport, HCICallback callback) { |
networker | 0:81ed8b6e4a8b | 54 | _transport = transport; |
networker | 0:81ed8b6e4a8b | 55 | _transport->Set(this); |
networker | 0:81ed8b6e4a8b | 56 | _callback = callback; |
networker | 0:81ed8b6e4a8b | 57 | _state = 0; |
networker | 0:81ed8b6e4a8b | 58 | for (int i = 0; i < MAX_BTDEVICES; i++) { |
networker | 0:81ed8b6e4a8b | 59 | _devices[i].Init(); |
networker | 0:81ed8b6e4a8b | 60 | _devices[i]._transport = transport; |
networker | 0:81ed8b6e4a8b | 61 | } |
networker | 0:81ed8b6e4a8b | 62 | cmd_credits = 1; |
networker | 0:81ed8b6e4a8b | 63 | return SendCmd(HCI_OP_RESET); |
networker | 0:81ed8b6e4a8b | 64 | } |
networker | 0:81ed8b6e4a8b | 65 | |
networker | 0:81ed8b6e4a8b | 66 | void printf(const BD_ADDR* addr); |
networker | 0:81ed8b6e4a8b | 67 | |
networker | 0:81ed8b6e4a8b | 68 | BTDevice* HCI::Find(const BD_ADDR* addr) { |
networker | 0:81ed8b6e4a8b | 69 | for (int i = 0; i < MAX_BTDEVICES; i++) |
networker | 0:81ed8b6e4a8b | 70 | if (_devices[i]._state != 0 && memcmp(addr,&_devices[i]._info.bdaddr,6) == 0) |
networker | 0:81ed8b6e4a8b | 71 | return &_devices[i]; |
networker | 0:81ed8b6e4a8b | 72 | return 0; |
networker | 0:81ed8b6e4a8b | 73 | } |
networker | 0:81ed8b6e4a8b | 74 | |
networker | 0:81ed8b6e4a8b | 75 | BTDevice* HCI::Find(int handle) { |
networker | 0:81ed8b6e4a8b | 76 | for (int i = 0; i < MAX_BTDEVICES; i++) |
networker | 0:81ed8b6e4a8b | 77 | if (_devices[i]._state != 0 && handle == _devices[i]._handle) |
networker | 0:81ed8b6e4a8b | 78 | return &_devices[i]; |
networker | 0:81ed8b6e4a8b | 79 | return 0; |
networker | 0:81ed8b6e4a8b | 80 | } |
networker | 0:81ed8b6e4a8b | 81 | // |
networker | 0:81ed8b6e4a8b | 82 | bool HCI::Busy() { |
networker | 0:81ed8b6e4a8b | 83 | return (_state & (MASK_INQUIRY | MASK_REMOTE_NAME | MASK_CREATE_CONNECTION)) != 0; |
networker | 0:81ed8b6e4a8b | 84 | } |
networker | 0:81ed8b6e4a8b | 85 | |
networker | 0:81ed8b6e4a8b | 86 | int HCI::Inquiry(int duration) { |
networker | 0:81ed8b6e4a8b | 87 | _state |= MASK_INQUIRY; |
networker | 0:81ed8b6e4a8b | 88 | u8 buf[5]; |
networker | 0:81ed8b6e4a8b | 89 | buf[0] = 0x33;//LAP=0x9e8b33 |
networker | 0:81ed8b6e4a8b | 90 | buf[1] = 0x8B; |
networker | 0:81ed8b6e4a8b | 91 | buf[2] = 0x9E; |
networker | 0:81ed8b6e4a8b | 92 | buf[3] = duration; |
networker | 0:81ed8b6e4a8b | 93 | buf[4] = 5; // 5 results |
networker | 0:81ed8b6e4a8b | 94 | SendCmd(HCI_OP_INQUIRY,buf,sizeof(buf)); |
networker | 0:81ed8b6e4a8b | 95 | return 0; |
networker | 0:81ed8b6e4a8b | 96 | } |
networker | 0:81ed8b6e4a8b | 97 | |
networker | 0:81ed8b6e4a8b | 98 | int HCI::SendCmd(int cmd, const u8* params, int len) { |
networker | 0:81ed8b6e4a8b | 99 | u8 b[32]; |
networker | 0:81ed8b6e4a8b | 100 | b[0] = cmd; |
networker | 0:81ed8b6e4a8b | 101 | b[1] = (cmd >> 8); |
networker | 0:81ed8b6e4a8b | 102 | b[2] = len; |
networker | 0:81ed8b6e4a8b | 103 | if (params) |
networker | 0:81ed8b6e4a8b | 104 | memcpy(b+3,params,len); |
networker | 0:81ed8b6e4a8b | 105 | //printf("%d cmd_credits\n", cmd_credits); |
networker | 0:81ed8b6e4a8b | 106 | while (cmd_credits == 0) { |
networker | 0:81ed8b6e4a8b | 107 | USBLoop(); |
networker | 0:81ed8b6e4a8b | 108 | putc('_', stdout); |
networker | 0:81ed8b6e4a8b | 109 | } |
networker | 0:81ed8b6e4a8b | 110 | _transport->HCISend(b,len+3); |
networker | 0:81ed8b6e4a8b | 111 | return 0; |
networker | 0:81ed8b6e4a8b | 112 | } |
networker | 0:81ed8b6e4a8b | 113 | |
networker | 0:81ed8b6e4a8b | 114 | void HCI::OnCommandComplete(int cmd, const u8* data, int len) { |
networker | 0:81ed8b6e4a8b | 115 | printf("%04X %s",cmd,CmdStr(cmd)); |
networker | 0:81ed8b6e4a8b | 116 | if (len < 0) |
networker | 0:81ed8b6e4a8b | 117 | return; |
networker | 0:81ed8b6e4a8b | 118 | printfBytes(" complete",data,min(16,len)); |
networker | 0:81ed8b6e4a8b | 119 | |
networker | 0:81ed8b6e4a8b | 120 | switch (cmd) { |
networker | 0:81ed8b6e4a8b | 121 | // Init phase 0 |
networker | 0:81ed8b6e4a8b | 122 | case HCI_OP_RESET: // Reset done, init chain to HCI_OP_READ_LOCAL_NAME |
networker | 0:81ed8b6e4a8b | 123 | SendCmd(HCI_OP_READ_BUFFER_SIZE); |
networker | 0:81ed8b6e4a8b | 124 | _state |= MASK_RESET; |
networker | 0:81ed8b6e4a8b | 125 | break; |
networker | 0:81ed8b6e4a8b | 126 | |
networker | 0:81ed8b6e4a8b | 127 | // Init phase 1 |
networker | 0:81ed8b6e4a8b | 128 | case HCI_OP_READ_BUFFER_SIZE: |
networker | 0:81ed8b6e4a8b | 129 | _acl_mtu = LE16(data); |
networker | 0:81ed8b6e4a8b | 130 | _sco_mtu = data[2]; |
networker | 0:81ed8b6e4a8b | 131 | _acl_max_pkt = LE16(data+3); |
networker | 0:81ed8b6e4a8b | 132 | _sco_max_pkt = LE16(data+5); |
networker | 0:81ed8b6e4a8b | 133 | printf("acl_mtu=%d, acl_max_pkt=%d\n", _acl_mtu, _acl_max_pkt); |
networker | 0:81ed8b6e4a8b | 134 | SendCmd(HCI_OP_READ_BD_ADDR); |
networker | 0:81ed8b6e4a8b | 135 | _state |= MASK_READ_BUFFER_SIZE; |
networker | 0:81ed8b6e4a8b | 136 | break; |
networker | 0:81ed8b6e4a8b | 137 | |
networker | 0:81ed8b6e4a8b | 138 | // Init phase 2 |
networker | 0:81ed8b6e4a8b | 139 | case HCI_OP_READ_BD_ADDR: |
networker | 0:81ed8b6e4a8b | 140 | _localAddr = *((BD_ADDR*)data); // Local Address |
networker | 0:81ed8b6e4a8b | 141 | _state |= MASK_READ_BD_ADDR; |
networker | 0:81ed8b6e4a8b | 142 | _state |= MASK_INITED; |
networker | 0:81ed8b6e4a8b | 143 | Callback(CALLBACK_READY,data,6); |
networker | 0:81ed8b6e4a8b | 144 | break; |
networker | 0:81ed8b6e4a8b | 145 | |
networker | 0:81ed8b6e4a8b | 146 | // 0CXX |
networker | 0:81ed8b6e4a8b | 147 | case HCI_OP_READ_LOCAL_NAME: |
networker | 0:81ed8b6e4a8b | 148 | case HCI_OP_LINK_KEY_NEG_REPLY: |
networker | 0:81ed8b6e4a8b | 149 | break; |
networker | 0:81ed8b6e4a8b | 150 | |
networker | 0:81ed8b6e4a8b | 151 | case HCI_OP_READ_LOCAL_VERSION: |
networker | 0:81ed8b6e4a8b | 152 | // params |
networker | 0:81ed8b6e4a8b | 153 | //SendCmd(HCI_OP_READ_LOCAL_NAME); |
networker | 0:81ed8b6e4a8b | 154 | break; |
networker | 0:81ed8b6e4a8b | 155 | |
networker | 0:81ed8b6e4a8b | 156 | case HCI_OP_READ_LOCAL_COMMANDS: |
networker | 0:81ed8b6e4a8b | 157 | break; |
networker | 0:81ed8b6e4a8b | 158 | |
networker | 0:81ed8b6e4a8b | 159 | case HCI_OP_READ_LOCAL_FEATURES: |
networker | 0:81ed8b6e4a8b | 160 | //SendCmd(HCI_OP_READ_LOCAL_VERSION); |
networker | 0:81ed8b6e4a8b | 161 | break; |
networker | 0:81ed8b6e4a8b | 162 | |
networker | 0:81ed8b6e4a8b | 163 | case HCI_OP_READ_LOCAL_EXT_FEATURES: |
networker | 0:81ed8b6e4a8b | 164 | break; |
networker | 0:81ed8b6e4a8b | 165 | |
networker | 0:81ed8b6e4a8b | 166 | case HCI_OP_PIN_CODE_REPLY: |
networker | 0:81ed8b6e4a8b | 167 | printf("Got pin reply\n"); |
networker | 0:81ed8b6e4a8b | 168 | break; |
networker | 0:81ed8b6e4a8b | 169 | |
networker | 0:81ed8b6e4a8b | 170 | default: |
networker | 0:81ed8b6e4a8b | 171 | printf("Unrecognized Command %04X\n",cmd); |
networker | 0:81ed8b6e4a8b | 172 | break; |
networker | 0:81ed8b6e4a8b | 173 | } |
networker | 0:81ed8b6e4a8b | 174 | } |
networker | 0:81ed8b6e4a8b | 175 | |
networker | 0:81ed8b6e4a8b | 176 | void HCI::Callback(HCI_CALLBACK_EVENT c, const u8* data, int len) { |
networker | 0:81ed8b6e4a8b | 177 | if (_callback) _callback(this,c,data,len); |
networker | 0:81ed8b6e4a8b | 178 | // (this->*_callback)(c, data, len); |
networker | 0:81ed8b6e4a8b | 179 | } |
networker | 0:81ed8b6e4a8b | 180 | |
networker | 0:81ed8b6e4a8b | 181 | int HCI::RemoteNameRequest(const BD_ADDR* addr) { |
networker | 0:81ed8b6e4a8b | 182 | _state |= MASK_REMOTE_NAME; |
networker | 0:81ed8b6e4a8b | 183 | u8 buf[6+4]; |
networker | 0:81ed8b6e4a8b | 184 | memset(buf,0,sizeof(buf)); |
networker | 0:81ed8b6e4a8b | 185 | memcpy(buf,addr,6); |
networker | 0:81ed8b6e4a8b | 186 | //buf[7] = 1; |
networker | 0:81ed8b6e4a8b | 187 | return SendCmd(HCI_OP_REMOTE_NAME_REQ,buf,sizeof(buf)); |
networker | 0:81ed8b6e4a8b | 188 | } |
networker | 0:81ed8b6e4a8b | 189 | int HCI::RemoteNameRequest(inquiry_info *ii) { |
networker | 0:81ed8b6e4a8b | 190 | _state |= MASK_REMOTE_NAME; |
networker | 0:81ed8b6e4a8b | 191 | u8 buf[6+4]; |
networker | 0:81ed8b6e4a8b | 192 | //memset(buf,0,sizeof(buf)); |
networker | 0:81ed8b6e4a8b | 193 | memcpy(buf,&ii->bdaddr,6); |
networker | 0:81ed8b6e4a8b | 194 | buf[6] = ii->pscan_rep_mode; |
networker | 0:81ed8b6e4a8b | 195 | buf[7] = 0; |
networker | 0:81ed8b6e4a8b | 196 | *(unsigned short*)(buf+8) = 0; |
networker | 0:81ed8b6e4a8b | 197 | return SendCmd(HCI_OP_REMOTE_NAME_REQ,buf,sizeof(buf)); |
networker | 0:81ed8b6e4a8b | 198 | } |
networker | 0:81ed8b6e4a8b | 199 | |
networker | 0:81ed8b6e4a8b | 200 | |
networker | 0:81ed8b6e4a8b | 201 | int HCI::CreateConnection(const BD_ADDR* remoteAddr) { |
networker | 0:81ed8b6e4a8b | 202 | _state |= MASK_CREATE_CONNECTION; |
networker | 0:81ed8b6e4a8b | 203 | u8 buf[6+7]; |
networker | 0:81ed8b6e4a8b | 204 | memset(buf,0,sizeof(buf)); |
networker | 0:81ed8b6e4a8b | 205 | memcpy(buf,remoteAddr,6); |
networker | 0:81ed8b6e4a8b | 206 | buf[6] = 0x18; // DM1,DH1 |
networker | 0:81ed8b6e4a8b | 207 | buf[7] = 0xCC; // DM3, DH3, DM5, DH5 |
networker | 0:81ed8b6e4a8b | 208 | buf[8] = 1; // Page Repetition R1 |
networker | 0:81ed8b6e4a8b | 209 | return SendCmd(HCI_OP_CREATE_CONN,buf,sizeof(buf)); |
networker | 0:81ed8b6e4a8b | 210 | } |
networker | 0:81ed8b6e4a8b | 211 | |
networker | 0:81ed8b6e4a8b | 212 | int HCI::Disconnect(const BD_ADDR* bdaddr) { |
networker | 0:81ed8b6e4a8b | 213 | BTDevice* d = Find(bdaddr); |
networker | 0:81ed8b6e4a8b | 214 | if (!d) |
networker | 0:81ed8b6e4a8b | 215 | return ERR_HCI_DEVICE_NOT_FOUND; |
networker | 0:81ed8b6e4a8b | 216 | int handle = d->_handle; |
networker | 0:81ed8b6e4a8b | 217 | printf("Disconnect from %d\n",handle); |
networker | 0:81ed8b6e4a8b | 218 | _state |= MASK_CREATE_CONNECTION; |
networker | 0:81ed8b6e4a8b | 219 | u8 buf[3]; |
networker | 0:81ed8b6e4a8b | 220 | buf[0] = handle; |
networker | 0:81ed8b6e4a8b | 221 | buf[1] = (handle >> 8); |
networker | 0:81ed8b6e4a8b | 222 | buf[2] = 0x13; |
networker | 0:81ed8b6e4a8b | 223 | return SendCmd(HCI_OP_DISCONNECT,buf,sizeof(buf)); |
networker | 0:81ed8b6e4a8b | 224 | } |
networker | 0:81ed8b6e4a8b | 225 | |
networker | 0:81ed8b6e4a8b | 226 | void HCI::DisconnectComplete(int handle) { |
networker | 0:81ed8b6e4a8b | 227 | BTDevice* d = Find(handle); |
networker | 0:81ed8b6e4a8b | 228 | if (!d) |
networker | 0:81ed8b6e4a8b | 229 | return; |
networker | 0:81ed8b6e4a8b | 230 | d->_handle = 0; |
networker | 0:81ed8b6e4a8b | 231 | } |
networker | 0:81ed8b6e4a8b | 232 | |
networker | 0:81ed8b6e4a8b | 233 | int HCI::DisconnectAll() { |
networker | 0:81ed8b6e4a8b | 234 | BTDevice* devs[8]; |
networker | 0:81ed8b6e4a8b | 235 | int count = GetDevices(devs,8); |
networker | 0:81ed8b6e4a8b | 236 | for (int i = 0; i < count; i++) |
networker | 0:81ed8b6e4a8b | 237 | Disconnect(&devs[i]->_info.bdaddr); |
networker | 0:81ed8b6e4a8b | 238 | return 0; |
networker | 0:81ed8b6e4a8b | 239 | } |
networker | 0:81ed8b6e4a8b | 240 | |
networker | 0:81ed8b6e4a8b | 241 | int HCI::PinCodeReply(const u8* data, const u8* pin) { |
networker | 0:81ed8b6e4a8b | 242 | u8 b[6+1+16]; |
networker | 0:81ed8b6e4a8b | 243 | memset(b,0,sizeof(b)); |
networker | 0:81ed8b6e4a8b | 244 | memcpy(b,data,6); |
networker | 0:81ed8b6e4a8b | 245 | b[6] = 4; |
networker | 0:81ed8b6e4a8b | 246 | memcpy(b+7, pin, 4); |
networker | 0:81ed8b6e4a8b | 247 | return SendCmd(HCI_OP_PIN_CODE_REPLY,b,sizeof(b)); |
networker | 0:81ed8b6e4a8b | 248 | } |
networker | 0:81ed8b6e4a8b | 249 | |
networker | 0:81ed8b6e4a8b | 250 | void HCI::InquiryResult(const inquiry_info* info) { |
networker | 0:81ed8b6e4a8b | 251 | BTDevice* bt = Find(&info->bdaddr); |
networker | 0:81ed8b6e4a8b | 252 | if (!bt) { // new device |
networker | 0:81ed8b6e4a8b | 253 | for (int i = 0; i < MAX_BTDEVICES; i++) { |
networker | 0:81ed8b6e4a8b | 254 | if (_devices[i]._state == 0) { |
networker | 0:81ed8b6e4a8b | 255 | bt = _devices + i; |
networker | 0:81ed8b6e4a8b | 256 | bt->_state = 1; |
networker | 0:81ed8b6e4a8b | 257 | break; |
networker | 0:81ed8b6e4a8b | 258 | } |
networker | 0:81ed8b6e4a8b | 259 | } |
networker | 0:81ed8b6e4a8b | 260 | if (!bt) { |
networker | 0:81ed8b6e4a8b | 261 | printf("HCI::InquiryResult too many devices\n"); |
networker | 0:81ed8b6e4a8b | 262 | return; // Too many devices! |
networker | 0:81ed8b6e4a8b | 263 | } |
networker | 0:81ed8b6e4a8b | 264 | } |
networker | 0:81ed8b6e4a8b | 265 | |
networker | 0:81ed8b6e4a8b | 266 | bt->_info = *info; |
networker | 0:81ed8b6e4a8b | 267 | } |
networker | 0:81ed8b6e4a8b | 268 | |
networker | 0:81ed8b6e4a8b | 269 | int HCI::GetDevices(BTDevice** devices, int maxDevices) { |
networker | 0:81ed8b6e4a8b | 270 | int j = 0; |
networker | 0:81ed8b6e4a8b | 271 | for (int i = 0; i < MAX_BTDEVICES; i++) { |
networker | 0:81ed8b6e4a8b | 272 | if (_devices[i]._state != 0) { |
networker | 0:81ed8b6e4a8b | 273 | devices[j++] = _devices + i; |
networker | 0:81ed8b6e4a8b | 274 | if (j == maxDevices) |
networker | 0:81ed8b6e4a8b | 275 | break; |
networker | 0:81ed8b6e4a8b | 276 | } |
networker | 0:81ed8b6e4a8b | 277 | } |
networker | 0:81ed8b6e4a8b | 278 | return j; |
networker | 0:81ed8b6e4a8b | 279 | } |
networker | 0:81ed8b6e4a8b | 280 | |
networker | 0:81ed8b6e4a8b | 281 | void HCI::RemoteName(const BD_ADDR* addr, const char* name) { |
networker | 0:81ed8b6e4a8b | 282 | BTDevice* d = Find(addr); |
networker | 0:81ed8b6e4a8b | 283 | if (d) { |
networker | 0:81ed8b6e4a8b | 284 | strncpy(d->_name,name,sizeof(d->_name)-1); |
networker | 0:81ed8b6e4a8b | 285 | d->_name[sizeof(d->_name)-1] = 0; |
networker | 0:81ed8b6e4a8b | 286 | } |
networker | 0:81ed8b6e4a8b | 287 | } |
networker | 0:81ed8b6e4a8b | 288 | |
networker | 0:81ed8b6e4a8b | 289 | void HCI::ConnectComplete(const connection_info* info) { |
networker | 0:81ed8b6e4a8b | 290 | BTDevice* d = Find(&info->bdaddr); |
networker | 0:81ed8b6e4a8b | 291 | if (!d) |
networker | 0:81ed8b6e4a8b | 292 | return; |
networker | 0:81ed8b6e4a8b | 293 | if (info->status == 0) { |
networker | 0:81ed8b6e4a8b | 294 | d->_handle = info->handle; |
networker | 0:81ed8b6e4a8b | 295 | printf("Connected on %04X\n",info->handle); |
networker | 0:81ed8b6e4a8b | 296 | } else |
networker | 0:81ed8b6e4a8b | 297 | printf("Connection failed with %d\n",info->status); |
networker | 0:81ed8b6e4a8b | 298 | } |
networker | 0:81ed8b6e4a8b | 299 | |
networker | 0:81ed8b6e4a8b | 300 | void HCI::HCIRecv(const u8* data, int len) { |
networker | 0:81ed8b6e4a8b | 301 | // printfBytes(EvtStr(data[0]),data,min(len,16)); |
networker | 0:81ed8b6e4a8b | 302 | switch (data[0]) { |
networker | 0:81ed8b6e4a8b | 303 | case HCI_EV_INQUIRY_COMPLETE: |
networker | 0:81ed8b6e4a8b | 304 | printfBytes("Inquiry Complete",data,data[1]); |
networker | 0:81ed8b6e4a8b | 305 | _state &= ~MASK_INQUIRY; |
networker | 0:81ed8b6e4a8b | 306 | Callback(CALLBACK_INQUIRY_DONE,0,0); |
networker | 0:81ed8b6e4a8b | 307 | break; |
networker | 0:81ed8b6e4a8b | 308 | |
networker | 0:81ed8b6e4a8b | 309 | case HCI_EV_INQUIRY_RESULT: { |
networker | 0:81ed8b6e4a8b | 310 | const u8* end = data[1] + data + 2; |
networker | 0:81ed8b6e4a8b | 311 | data += 3; |
networker | 0:81ed8b6e4a8b | 312 | while (data < end) { |
networker | 0:81ed8b6e4a8b | 313 | inquiry_info align; |
networker | 0:81ed8b6e4a8b | 314 | memcpy(&align,data,sizeof(inquiry_info)); |
networker | 0:81ed8b6e4a8b | 315 | InquiryResult(&align); |
networker | 0:81ed8b6e4a8b | 316 | Callback(CALLBACK_INQUIRY_RESULT,(u8*)&align,sizeof(inquiry_info)); |
networker | 0:81ed8b6e4a8b | 317 | data += 14; |
networker | 0:81ed8b6e4a8b | 318 | } |
networker | 0:81ed8b6e4a8b | 319 | } |
networker | 0:81ed8b6e4a8b | 320 | break; |
networker | 0:81ed8b6e4a8b | 321 | |
networker | 0:81ed8b6e4a8b | 322 | case HCI_EV_CONN_COMPLETE: |
networker | 0:81ed8b6e4a8b | 323 | _state &= ~MASK_CREATE_CONNECTION; |
networker | 0:81ed8b6e4a8b | 324 | { |
networker | 0:81ed8b6e4a8b | 325 | connection_info align; |
networker | 0:81ed8b6e4a8b | 326 | memcpy(&align,data+2,sizeof(connection_info)); |
networker | 0:81ed8b6e4a8b | 327 | ConnectComplete(&align); |
networker | 0:81ed8b6e4a8b | 328 | Callback(CALLBACK_CONNECTION_COMPLETE,(u8*)&align,sizeof(connection_info)); |
networker | 0:81ed8b6e4a8b | 329 | } |
networker | 0:81ed8b6e4a8b | 330 | break; |
networker | 0:81ed8b6e4a8b | 331 | |
networker | 0:81ed8b6e4a8b | 332 | case HCI_EV_CONN_REQUEST: |
networker | 0:81ed8b6e4a8b | 333 | break; |
networker | 0:81ed8b6e4a8b | 334 | |
networker | 0:81ed8b6e4a8b | 335 | case HCI_EV_DISCONN_COMPLETE: |
networker | 0:81ed8b6e4a8b | 336 | DisconnectComplete(LE16(data+3)); |
networker | 0:81ed8b6e4a8b | 337 | break; |
networker | 0:81ed8b6e4a8b | 338 | |
networker | 0:81ed8b6e4a8b | 339 | case HCI_EV_REMOTE_NAME: { |
networker | 0:81ed8b6e4a8b | 340 | BD_ADDR* addr = (BD_ADDR*)(data+3); |
networker | 0:81ed8b6e4a8b | 341 | const char* name = (const char*)(data + 9); |
networker | 0:81ed8b6e4a8b | 342 | RemoteName(addr,name); |
networker | 0:81ed8b6e4a8b | 343 | } |
networker | 0:81ed8b6e4a8b | 344 | Callback(CALLBACK_REMOTE_NAME,data+3,LE16(data+1)); // addr is in here too |
networker | 0:81ed8b6e4a8b | 345 | _state &= ~MASK_REMOTE_NAME; |
networker | 0:81ed8b6e4a8b | 346 | break; |
networker | 0:81ed8b6e4a8b | 347 | |
networker | 0:81ed8b6e4a8b | 348 | case HCI_EV_CMD_STATUS: { |
networker | 0:81ed8b6e4a8b | 349 | const char* errs = HCIErrStr(data[2]); |
networker | 0:81ed8b6e4a8b | 350 | printf("Status %s %s %d cmd pkts\n",CmdStr(LE16(data+4)),errs, data[3]); |
networker | 0:81ed8b6e4a8b | 351 | cmd_credits = data[3]; |
networker | 0:81ed8b6e4a8b | 352 | } |
networker | 0:81ed8b6e4a8b | 353 | Callback(CALLBACK_CMD_STATUS, data+2, 4); |
networker | 0:81ed8b6e4a8b | 354 | break; |
networker | 0:81ed8b6e4a8b | 355 | |
networker | 0:81ed8b6e4a8b | 356 | case HCI_EV_CMD_COMPLETE: |
networker | 0:81ed8b6e4a8b | 357 | OnCommandComplete(data[3] | (data[4] << 8),data+6,data[1]-4); |
networker | 0:81ed8b6e4a8b | 358 | cmd_credits = data[2]; |
networker | 0:81ed8b6e4a8b | 359 | break; |
networker | 0:81ed8b6e4a8b | 360 | |
networker | 0:81ed8b6e4a8b | 361 | case HCI_EV_PIN_CODE_REQ: |
networker | 0:81ed8b6e4a8b | 362 | Callback(CALLBACK_PIN_REQ, data+2, 6); |
networker | 0:81ed8b6e4a8b | 363 | //PinCodeReply(data+2); |
networker | 0:81ed8b6e4a8b | 364 | break; |
networker | 0:81ed8b6e4a8b | 365 | |
networker | 0:81ed8b6e4a8b | 366 | case HCI_EV_LINK_KEY_REQ: |
networker | 0:81ed8b6e4a8b | 367 | SendCmd(HCI_OP_LINK_KEY_NEG_REPLY,data+2,6); |
networker | 0:81ed8b6e4a8b | 368 | break; |
networker | 0:81ed8b6e4a8b | 369 | case HCI_EV_NUM_COMP_PKTS: |
networker | 0:81ed8b6e4a8b | 370 | case HCI_EV_LINK_KEY_NOTIFY: |
networker | 0:81ed8b6e4a8b | 371 | break; |
networker | 0:81ed8b6e4a8b | 372 | default: |
networker | 0:81ed8b6e4a8b | 373 | |
networker | 0:81ed8b6e4a8b | 374 | printfBytes("HCIRecv:",data,data[1]+2); |
networker | 0:81ed8b6e4a8b | 375 | break; |
networker | 0:81ed8b6e4a8b | 376 | } |
networker | 0:81ed8b6e4a8b | 377 | } |
networker | 0:81ed8b6e4a8b | 378 | |
networker | 0:81ed8b6e4a8b | 379 | int HCI::Open(SocketInternal* sock, SocketAddrHdr* addr) { |
networker | 0:81ed8b6e4a8b | 380 | L2CAPSocket* l2capsock = (L2CAPSocket*)sock; |
networker | 0:81ed8b6e4a8b | 381 | L2CAPAddr* l2capaddr = (L2CAPAddr*)addr; |
networker | 0:81ed8b6e4a8b | 382 | BTDevice* bt = Find(&l2capaddr->bdaddr); |
networker | 0:81ed8b6e4a8b | 383 | if (!bt) { |
networker | 0:81ed8b6e4a8b | 384 | printf("Can't open l2cap %d on ",l2capaddr->psm); |
networker | 0:81ed8b6e4a8b | 385 | printf(&l2capaddr->bdaddr); |
networker | 0:81ed8b6e4a8b | 386 | printf("\n"); |
networker | 0:81ed8b6e4a8b | 387 | return ERR_HCI_DEVICE_NOT_FOUND; |
networker | 0:81ed8b6e4a8b | 388 | } |
networker | 0:81ed8b6e4a8b | 389 | l2capsock->btdevice = bt; |
networker | 0:81ed8b6e4a8b | 390 | return bt->Open(sock,addr); |
networker | 0:81ed8b6e4a8b | 391 | } |
networker | 0:81ed8b6e4a8b | 392 | |
networker | 0:81ed8b6e4a8b | 393 | int HCI::Send(SocketInternal* sock, const u8* data, int len) {//check here for appropriate buffersize on the device |
networker | 0:81ed8b6e4a8b | 394 | //assume acl packet |
networker | 0:81ed8b6e4a8b | 395 | #if OFFSET==8 //sizeof ACL/L2CAP is include in data/len |
networker | 0:81ed8b6e4a8b | 396 | if (len > _acl_max_pkt) |
networker | 0:81ed8b6e4a8b | 397 | #else //OFFSET==0, data is bare application frame |
networker | 0:81ed8b6e4a8b | 398 | if (len+8 > _acl_mtu) |
networker | 0:81ed8b6e4a8b | 399 | #endif |
networker | 0:81ed8b6e4a8b | 400 | { printf("Max outgoing packet(%d) size exceeded, segmenting necessary, pktlen = %d\n", _acl_mtu, len); |
networker | 0:81ed8b6e4a8b | 401 | } |
networker | 0:81ed8b6e4a8b | 402 | L2CAPSocket* l2capsock = (L2CAPSocket*)sock; |
networker | 0:81ed8b6e4a8b | 403 | return l2capsock->btdevice->Send(sock,data,len); // Pointless double dispatch |
networker | 0:81ed8b6e4a8b | 404 | } |
networker | 0:81ed8b6e4a8b | 405 | |
networker | 0:81ed8b6e4a8b | 406 | int HCI::Close(SocketInternal* sock) { |
networker | 0:81ed8b6e4a8b | 407 | L2CAPSocket* l2capsock = (L2CAPSocket*)sock; |
networker | 0:81ed8b6e4a8b | 408 | return l2capsock->btdevice->Close(sock); // Pointless double dispatch |
networker | 0:81ed8b6e4a8b | 409 | } |
networker | 0:81ed8b6e4a8b | 410 | |
networker | 0:81ed8b6e4a8b | 411 | void HCI::ACLRecv(const u8* data, int len) { |
networker | 0:81ed8b6e4a8b | 412 | int handle = LE16(data); |
networker | 0:81ed8b6e4a8b | 413 | BTDevice* d = Find(handle & 0x0FFF); |
networker | 0:81ed8b6e4a8b | 414 | if (d) |
networker | 0:81ed8b6e4a8b | 415 | d->ACLRecv(data,len); |
networker | 0:81ed8b6e4a8b | 416 | else |
networker | 0:81ed8b6e4a8b | 417 | printfBytes("HCI:ACLRecv ", data, len); |
networker | 0:81ed8b6e4a8b | 418 | } |
networker | 0:81ed8b6e4a8b | 419 | |
networker | 0:81ed8b6e4a8b | 420 | //=================================================================== |
networker | 0:81ed8b6e4a8b | 421 | //=================================================================== |