local fix version of myBlueUSB (http://mbed.org/users/networker/code/myBlueUSB/). - merge deleted files which are required to compile. - enable echo back of received data via RFCOMM.

Dependencies:   AvailableMemory FatFileSystem mbed myUSBHost

Committer:
nobukuma
Date:
Sun Dec 08 21:52:09 2013 +0000
Revision:
2:9f25a7fa1a54
Parent:
1:4a639fa342bc
???BT??????????????????; ?????????????????

Who changed what in which revision?

UserRevisionLine numberNew contents of line
nobukuma 0:003889bc474f 1
nobukuma 0:003889bc474f 2 /*
nobukuma 0:003889bc474f 3 Copyright (c) 2010 Peter Barrett
nobukuma 0:003889bc474f 4
nobukuma 0:003889bc474f 5 Permission is hereby granted, free of charge, to any person obtaining a copy
nobukuma 0:003889bc474f 6 of this software and associated documentation files (the "Software"), to deal
nobukuma 0:003889bc474f 7 in the Software without restriction, including without limitation the rights
nobukuma 0:003889bc474f 8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
nobukuma 0:003889bc474f 9 copies of the Software, and to permit persons to whom the Software is
nobukuma 0:003889bc474f 10 furnished to do so, subject to the following conditions:
nobukuma 0:003889bc474f 11
nobukuma 0:003889bc474f 12 The above copyright notice and this permission notice shall be included in
nobukuma 0:003889bc474f 13 all copies or substantial portions of the Software.
nobukuma 0:003889bc474f 14
nobukuma 0:003889bc474f 15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
nobukuma 0:003889bc474f 16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
nobukuma 0:003889bc474f 17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
nobukuma 0:003889bc474f 18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
nobukuma 0:003889bc474f 19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
nobukuma 0:003889bc474f 20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
nobukuma 0:003889bc474f 21 THE SOFTWARE.
nobukuma 0:003889bc474f 22 */
nobukuma 0:003889bc474f 23
nobukuma 0:003889bc474f 24 #include <stdio.h>
nobukuma 0:003889bc474f 25 #include <stdlib.h>
nobukuma 0:003889bc474f 26 #include <stdio.h>
nobukuma 0:003889bc474f 27 #include <string.h>
nobukuma 0:003889bc474f 28
nobukuma 0:003889bc474f 29 #include "Utils.h"
nobukuma 0:003889bc474f 30 #include "hci.h"
nobukuma 0:003889bc474f 31 #include "hci_private.h"
nobukuma 0:003889bc474f 32 #include "USBHost.h" //for USBLoop
nobukuma 0:003889bc474f 33 #include "HCITransportUSB.h" //for ACL/HCL buffer size
nobukuma 0:003889bc474f 34 #include "neighbourhood.h"
nobukuma 0:003889bc474f 35
nobukuma 0:003889bc474f 36 extern const char FtDevClass[];
nobukuma 0:003889bc474f 37 const char FtDevClass[3] = {0x00, 0x1F, 0x82 };
nobukuma 0:003889bc474f 38
nobukuma 0:003889bc474f 39 enum hci_callback_evt {
nobukuma 0:003889bc474f 40 NONE,
nobukuma 0:003889bc474f 41 CONNECT,
nobukuma 0:003889bc474f 42 DISCONECT,
nobukuma 0:003889bc474f 43 INQUIRYRESULT
nobukuma 0:003889bc474f 44 };
nobukuma 0:003889bc474f 45
nobukuma 0:003889bc474f 46 #define MAX_BLUETOOTH_ADAPTERS 1
nobukuma 0:003889bc474f 47
nobukuma 0:003889bc474f 48 enum StateMask {
nobukuma 0:003889bc474f 49 MASK_RESET = 1,
nobukuma 0:003889bc474f 50 MASK_READ_BUFFER_SIZE = 2,
nobukuma 0:003889bc474f 51 MASK_READ_BD_ADDR = 4,
nobukuma 0:003889bc474f 52 MASK_INITED = 8,
nobukuma 0:003889bc474f 53 MASK_INQUIRY = 16,
nobukuma 0:003889bc474f 54 MASK_REMOTE_NAME = 32,
nobukuma 0:003889bc474f 55 MASK_CREATE_CONNECTION = 64
nobukuma 0:003889bc474f 56 };
nobukuma 0:003889bc474f 57
nobukuma 2:9f25a7fa1a54 58 static const u8 local_name[] = "MBED";
nobukuma 1:4a639fa342bc 59 //static const u8 local_name[] = "ROBO TX-599";
nobukuma 2:9f25a7fa1a54 60 //static const u8 local_name[] = "mbed-WP8 RFCOMM";
nobukuma 0:003889bc474f 61
nobukuma 0:003889bc474f 62 int HCI::Open(HCITransport* transport, HCICallback callback) {
nobukuma 0:003889bc474f 63 _transport = transport;
nobukuma 0:003889bc474f 64 _transport->Set(this);
nobukuma 0:003889bc474f 65 _callback = callback;
nobukuma 0:003889bc474f 66 _state = 0;
nobukuma 0:003889bc474f 67 for (int i = 0; i < MAX_BTDEVICES; i++) {
nobukuma 0:003889bc474f 68 _devices[i].Init();
nobukuma 0:003889bc474f 69 _devices[i]._transport = transport;
nobukuma 0:003889bc474f 70 }
nobukuma 0:003889bc474f 71 #ifdef COMMAND_FLOW
nobukuma 0:003889bc474f 72 cmd_credits = 1;
nobukuma 0:003889bc474f 73 #endif
nobukuma 0:003889bc474f 74 return SendCmd(HCI_OP_RESET);
nobukuma 0:003889bc474f 75 }
nobukuma 0:003889bc474f 76
nobukuma 0:003889bc474f 77 void printf(const BD_ADDR* addr);
nobukuma 0:003889bc474f 78
nobukuma 0:003889bc474f 79 BTDevice* HCI::Find(const BD_ADDR* addr) {
nobukuma 0:003889bc474f 80 for (int i = 0; i < MAX_BTDEVICES; i++)
nobukuma 0:003889bc474f 81 if (_devices[i]._state != 0 && memcmp(addr,&_devices[i]._info.bdaddr,6) == 0)
nobukuma 0:003889bc474f 82 return &_devices[i];
nobukuma 0:003889bc474f 83 return 0;
nobukuma 0:003889bc474f 84 }
nobukuma 0:003889bc474f 85
nobukuma 0:003889bc474f 86 BTDevice* HCI::Find(int handle) {
nobukuma 0:003889bc474f 87 for (int i = 0; i < MAX_BTDEVICES; i++)
nobukuma 0:003889bc474f 88 if (_devices[i]._state != 0 && handle == _devices[i]._handle)
nobukuma 0:003889bc474f 89 return &_devices[i];
nobukuma 0:003889bc474f 90 return 0;
nobukuma 0:003889bc474f 91 }
nobukuma 0:003889bc474f 92
nobukuma 0:003889bc474f 93 //reports that some commands are still in progress
nobukuma 0:003889bc474f 94 bool HCI::Busy() {
nobukuma 0:003889bc474f 95 return (_state & (MASK_INQUIRY | MASK_REMOTE_NAME | MASK_CREATE_CONNECTION)) != 0;
nobukuma 0:003889bc474f 96 }
nobukuma 0:003889bc474f 97
nobukuma 0:003889bc474f 98 int HCI::Inquiry(int duration) {
nobukuma 0:003889bc474f 99 _state |= MASK_INQUIRY;
nobukuma 0:003889bc474f 100 u8 buf[5];
nobukuma 0:003889bc474f 101 buf[0] = 0x33;//LAP=0x9e8b33
nobukuma 0:003889bc474f 102 buf[1] = 0x8B;
nobukuma 0:003889bc474f 103 buf[2] = 0x9E;
nobukuma 0:003889bc474f 104 buf[3] = duration;
nobukuma 0:003889bc474f 105 buf[4] = 5; // 5 results
nobukuma 0:003889bc474f 106 SendCmd(HCI_OP_INQUIRY,buf,sizeof(buf));
nobukuma 0:003889bc474f 107 return 0;
nobukuma 0:003889bc474f 108 }
nobukuma 0:003889bc474f 109
nobukuma 0:003889bc474f 110 int HCI::SetEventFilter(u8 filterType, u8 filterConditionType, u8* condition) {
nobukuma 0:003889bc474f 111 int len = 2;
nobukuma 0:003889bc474f 112 u8 buf[8];
nobukuma 0:003889bc474f 113 buf[0] = filterType;
nobukuma 0:003889bc474f 114 buf[1] = filterConditionType;
nobukuma 0:003889bc474f 115 switch (filterConditionType) {
nobukuma 0:003889bc474f 116 case 0://all devices
nobukuma 0:003889bc474f 117 if (filterType==2) { //connection setup
nobukuma 0:003889bc474f 118 buf[2] = condition[0];
nobukuma 0:003889bc474f 119 len++;
nobukuma 0:003889bc474f 120 }
nobukuma 0:003889bc474f 121 break;
nobukuma 0:003889bc474f 122 case 1: //filter by class
nobukuma 0:003889bc474f 123 case 2: //filter by BDADDR
nobukuma 0:003889bc474f 124 memcpy(buf+2, condition, 6);
nobukuma 0:003889bc474f 125 len += 6;
nobukuma 0:003889bc474f 126 break;
nobukuma 0:003889bc474f 127 default:
nobukuma 0:003889bc474f 128 printf("Unknown filter condition type %d, filter type=%d\n", filterConditionType, filterType);
nobukuma 0:003889bc474f 129 }
nobukuma 0:003889bc474f 130 SendCmd(HCI_OP_SET_EVENT_FLT, buf, len);
nobukuma 0:003889bc474f 131 return 0;
nobukuma 0:003889bc474f 132 }
nobukuma 0:003889bc474f 133
nobukuma 0:003889bc474f 134 int HCI::SendCmd(int cmd, const u8* params, int len) {
nobukuma 0:003889bc474f 135 u8 b[256];
nobukuma 0:003889bc474f 136 b[0] = cmd;
nobukuma 0:003889bc474f 137 b[1] = (cmd >> 8);
nobukuma 0:003889bc474f 138 b[2] = len;
nobukuma 0:003889bc474f 139 if (params)
nobukuma 0:003889bc474f 140 memcpy(b+3,params,len);
nobukuma 0:003889bc474f 141 #ifdef COMMAND_FLOW
nobukuma 0:003889bc474f 142 //printf("%d cmd_credits\n", cmd_credits);
nobukuma 0:003889bc474f 143 while (cmd_credits == 0) {//blocks when command credits run out
nobukuma 0:003889bc474f 144 USBLoop();
nobukuma 0:003889bc474f 145 putc('_', stdout);
nobukuma 0:003889bc474f 146 }
nobukuma 0:003889bc474f 147 #endif
nobukuma 0:003889bc474f 148 _transport->HCISend(b,len+3);
nobukuma 0:003889bc474f 149 return 0;
nobukuma 0:003889bc474f 150 }
nobukuma 0:003889bc474f 151
nobukuma 0:003889bc474f 152 void HCI::OnCommandComplete(int cmd, const u8* data, int len) {//data is exclusive the status byte
nobukuma 0:003889bc474f 153 //printf("%04X %s",cmd,CmdStr(cmd));
nobukuma 0:003889bc474f 154 if (len < 0)
nobukuma 0:003889bc474f 155 return;
nobukuma 0:003889bc474f 156 //printfBytes(" complete",data,len/*min(16,len)*/);
nobukuma 0:003889bc474f 157
nobukuma 0:003889bc474f 158 switch (cmd) {
nobukuma 0:003889bc474f 159 case 0: //NOP
nobukuma 0:003889bc474f 160 printf("Received NOP command (for cmd_credits)\n");
nobukuma 0:003889bc474f 161 break;
nobukuma 0:003889bc474f 162 // Init phase 0
nobukuma 0:003889bc474f 163 case HCI_OP_RESET: // Reset done, init chain to HCI_OP_READ_LOCAL_NAME
nobukuma 0:003889bc474f 164 SendCmd(HCI_OP_READ_BUFFER_SIZE);
nobukuma 0:003889bc474f 165 _state |= MASK_RESET;
nobukuma 0:003889bc474f 166 break;
nobukuma 0:003889bc474f 167
nobukuma 0:003889bc474f 168 // Init phase 1
nobukuma 0:003889bc474f 169 case HCI_OP_READ_BUFFER_SIZE:
nobukuma 0:003889bc474f 170 _acl_mtu = LE16(data);
nobukuma 0:003889bc474f 171 _sco_mtu = data[2];
nobukuma 0:003889bc474f 172 _acl_max_pkt = LE16(data+3);
nobukuma 0:003889bc474f 173 _sco_max_pkt = LE16(data+5);
nobukuma 0:003889bc474f 174 printf("acl_mtu=%d, acl_max_pkt=%d\n", _acl_mtu, _acl_max_pkt);
nobukuma 0:003889bc474f 175 #ifdef HOST_CONTR_FLOW
nobukuma 0:003889bc474f 176 _transport->data_credits = _acl_max_pkt;
nobukuma 0:003889bc474f 177 _transport->_acl_mtu = _acl_mtu;
nobukuma 0:003889bc474f 178 #endif
nobukuma 0:003889bc474f 179 SendCmd(HCI_OP_READ_BD_ADDR);
nobukuma 0:003889bc474f 180 _state |= MASK_READ_BUFFER_SIZE;
nobukuma 0:003889bc474f 181 break;
nobukuma 0:003889bc474f 182
nobukuma 0:003889bc474f 183 // Init phase 2
nobukuma 0:003889bc474f 184 case HCI_OP_READ_BD_ADDR:
nobukuma 0:003889bc474f 185 _localAddr = *((BD_ADDR*)data); // Local Address
nobukuma 0:003889bc474f 186 _state |= MASK_READ_BD_ADDR;
nobukuma 0:003889bc474f 187 _state |= MASK_INITED;
nobukuma 0:003889bc474f 188 {
nobukuma 0:003889bc474f 189 #ifdef CONTR_HOST_FLOW
nobukuma 0:003889bc474f 190 unsigned char param[7];
nobukuma 0:003889bc474f 191 param[0] = (u8)(MAX_ACL_SIZE-8);
nobukuma 0:003889bc474f 192 param[1] = (u8)((MAX_ACL_SIZE-8)>>8);
nobukuma 0:003889bc474f 193 param[2] = 0;//MAX_HCL_SIZE-8;
nobukuma 0:003889bc474f 194 param[3] = 10;
nobukuma 0:003889bc474f 195 param[4] = 0; //1 ACL buffer
nobukuma 0:003889bc474f 196 param[5] = 0;
nobukuma 0:003889bc474f 197 param[6] = 0; //0 Synchronous buffers
nobukuma 0:003889bc474f 198 SendCmd(HCI_OP_HOST_BUFFER_SIZE, param, 7);
nobukuma 0:003889bc474f 199 const unsigned char flow = 1;//ACL on, Synchonous off
nobukuma 0:003889bc474f 200 SendCmd(HCI_OP_CONTR_TO_HOST_FLOW, &flow, 1);
nobukuma 0:003889bc474f 201 #endif
nobukuma 0:003889bc474f 202 const unsigned char scan_enable = 3;
nobukuma 0:003889bc474f 203 SendCmd(HCI_OP_WRITE_SCAN_ENABLE, &scan_enable, 1);
nobukuma 0:003889bc474f 204 SendCmd(HCI_OP_WRITE_CLASS_OF_DEV, (const u8*)FtDevClass, 3);
nobukuma 0:003889bc474f 205 //SendCmd(HCI_OP_READ_LOCAL_VERSION, 0, 0);
nobukuma 0:003889bc474f 206 SendCmd(HCI_OP_WRITE_LOCAL_NAME, local_name, 248);
nobukuma 0:003889bc474f 207 }
nobukuma 0:003889bc474f 208 Callback(CALLBACK_READY,data,6);
nobukuma 0:003889bc474f 209 break;
nobukuma 0:003889bc474f 210
nobukuma 0:003889bc474f 211 // 0CXX
nobukuma 0:003889bc474f 212 case HCI_OP_READ_LOCAL_NAME:
nobukuma 0:003889bc474f 213 case HCI_OP_LINK_KEY_NEG_REPLY:
nobukuma 0:003889bc474f 214 case HCI_OP_WRITE_SCAN_ENABLE:
nobukuma 0:003889bc474f 215 case HCI_OP_WRITE_LOCAL_NAME:
nobukuma 0:003889bc474f 216 break;
nobukuma 0:003889bc474f 217 #ifdef CONTR_HOST_FLOW
nobukuma 0:003889bc474f 218 case HCI_OP_CONTR_TO_HOST_FLOW:
nobukuma 0:003889bc474f 219 case HCI_OP_HOST_BUFFER_SIZE:
nobukuma 0:003889bc474f 220 break;
nobukuma 0:003889bc474f 221 case HCI_OP_NUM_COMP_PKTS:
nobukuma 0:003889bc474f 222 printf("Host number of Completed Packets: Invalid HCI Command Parameter\n");
nobukuma 0:003889bc474f 223 break;
nobukuma 0:003889bc474f 224 #endif
nobukuma 0:003889bc474f 225 case HCI_OP_READ_LOCAL_VERSION:
nobukuma 0:003889bc474f 226 // params
nobukuma 0:003889bc474f 227 //SendCmd(HCI_OP_READ_LOCAL_NAME);
nobukuma 0:003889bc474f 228 break;
nobukuma 0:003889bc474f 229
nobukuma 0:003889bc474f 230 case HCI_OP_READ_LOCAL_COMMANDS:
nobukuma 0:003889bc474f 231 break;
nobukuma 0:003889bc474f 232
nobukuma 0:003889bc474f 233 case HCI_OP_READ_LOCAL_FEATURES:
nobukuma 0:003889bc474f 234 //SendCmd(HCI_OP_READ_LOCAL_VERSION);
nobukuma 0:003889bc474f 235 break;
nobukuma 0:003889bc474f 236
nobukuma 0:003889bc474f 237 case HCI_OP_READ_LOCAL_EXT_FEATURES:
nobukuma 0:003889bc474f 238 break;
nobukuma 0:003889bc474f 239
nobukuma 0:003889bc474f 240 case HCI_OP_PIN_CODE_REPLY:
nobukuma 0:003889bc474f 241 printf("Got pin reply\n");
nobukuma 0:003889bc474f 242 break;
nobukuma 0:003889bc474f 243 case HCI_READ_STORED_LINK_KEY:
nobukuma 0:003889bc474f 244 neighbors->set_cap(LE16(data), LE16(data+2));
nobukuma 0:003889bc474f 245 break;
nobukuma 0:003889bc474f 246
nobukuma 0:003889bc474f 247 default:
nobukuma 0:003889bc474f 248 printf("Unrecognized Command Completion %04X\n",cmd);
nobukuma 0:003889bc474f 249 break;
nobukuma 0:003889bc474f 250 }
nobukuma 0:003889bc474f 251 }
nobukuma 0:003889bc474f 252
nobukuma 0:003889bc474f 253 void HCI::Callback(HCI_CALLBACK_EVENT c, const u8* data, int len) {
nobukuma 0:003889bc474f 254 if (_callback) _callback(this,c,data,len);
nobukuma 0:003889bc474f 255 // (this->*_callback)(c, data, len);
nobukuma 0:003889bc474f 256 }
nobukuma 0:003889bc474f 257
nobukuma 0:003889bc474f 258 int HCI::RemoteNameRequest(const BD_ADDR* addr) {
nobukuma 0:003889bc474f 259 _state |= MASK_REMOTE_NAME;
nobukuma 0:003889bc474f 260 u8 buf[6+4];
nobukuma 0:003889bc474f 261 memset(buf,0,sizeof(buf));
nobukuma 0:003889bc474f 262 memcpy(buf,addr,6);
nobukuma 0:003889bc474f 263 //buf[7] = 1;
nobukuma 0:003889bc474f 264 return SendCmd(HCI_OP_REMOTE_NAME_REQ,buf,sizeof(buf));
nobukuma 0:003889bc474f 265 }
nobukuma 0:003889bc474f 266
nobukuma 0:003889bc474f 267 int HCI::RemoteNameRequest(inquiry_info *ii) {
nobukuma 0:003889bc474f 268 _state |= MASK_REMOTE_NAME;
nobukuma 0:003889bc474f 269 u8 buf[6+4];
nobukuma 0:003889bc474f 270 //memset(buf,0,sizeof(buf));
nobukuma 0:003889bc474f 271 memcpy(buf,&ii->bdaddr,6);
nobukuma 0:003889bc474f 272 buf[6] = ii->pscan_rep_mode;
nobukuma 0:003889bc474f 273 buf[7] = 0;
nobukuma 0:003889bc474f 274 *(unsigned short*)(buf+8) = 0;
nobukuma 0:003889bc474f 275 return SendCmd(HCI_OP_REMOTE_NAME_REQ,buf,sizeof(buf));
nobukuma 0:003889bc474f 276 }
nobukuma 0:003889bc474f 277
nobukuma 0:003889bc474f 278 int HCI::CreateConnection(const BD_ADDR* remoteAddr) {
nobukuma 0:003889bc474f 279 _state |= MASK_CREATE_CONNECTION;
nobukuma 0:003889bc474f 280 u8 buf[6+7];
nobukuma 0:003889bc474f 281 memset(buf,0,sizeof(buf));
nobukuma 0:003889bc474f 282 memcpy(buf,remoteAddr,6);
nobukuma 0:003889bc474f 283 buf[6] = 0x18; // DM1,DH1
nobukuma 0:003889bc474f 284 buf[7] = 0xCC; // DM3, DH3, DM5, DH5
nobukuma 0:003889bc474f 285 buf[8] = 1; // Page Repetition R1
nobukuma 0:003889bc474f 286 return SendCmd(HCI_OP_CREATE_CONN,buf,sizeof(buf));
nobukuma 0:003889bc474f 287 }
nobukuma 0:003889bc474f 288
nobukuma 0:003889bc474f 289 int HCI::Disconnect(const BD_ADDR* bdaddr) {
nobukuma 0:003889bc474f 290 BTDevice* d = Find(bdaddr);
nobukuma 0:003889bc474f 291 if (!d)
nobukuma 0:003889bc474f 292 return ERR_HCI_DEVICE_NOT_FOUND;
nobukuma 0:003889bc474f 293 int handle = d->_handle;
nobukuma 0:003889bc474f 294 printf("Disconnect from %d\n",handle);
nobukuma 0:003889bc474f 295 _state |= MASK_CREATE_CONNECTION;
nobukuma 0:003889bc474f 296 u8 buf[3];
nobukuma 0:003889bc474f 297 buf[0] = handle;
nobukuma 0:003889bc474f 298 buf[1] = (handle >> 8);
nobukuma 0:003889bc474f 299 buf[2] = 0x13;
nobukuma 0:003889bc474f 300 return SendCmd(HCI_OP_DISCONNECT,buf,sizeof(buf));
nobukuma 0:003889bc474f 301 }
nobukuma 0:003889bc474f 302
nobukuma 0:003889bc474f 303 void HCI::DisconnectComplete(int handle) {
nobukuma 0:003889bc474f 304 BTDevice* d = Find(handle);
nobukuma 0:003889bc474f 305 if (!d)
nobukuma 0:003889bc474f 306 return;
nobukuma 0:003889bc474f 307 d->_handle = 0;
nobukuma 0:003889bc474f 308 }
nobukuma 0:003889bc474f 309
nobukuma 0:003889bc474f 310 int HCI::DisconnectAll() {
nobukuma 0:003889bc474f 311 BTDevice* devs[8];
nobukuma 0:003889bc474f 312 int count = GetDevices(devs,8);
nobukuma 0:003889bc474f 313 for (int i = 0; i < count; i++)
nobukuma 0:003889bc474f 314 Disconnect(&devs[i]->_info.bdaddr);
nobukuma 0:003889bc474f 315 return 0;
nobukuma 0:003889bc474f 316 }
nobukuma 0:003889bc474f 317
nobukuma 0:003889bc474f 318 int HCI::PinCodeReply(const u8* data, const u8* pin) {
nobukuma 0:003889bc474f 319 u8 b[6+1+16];
nobukuma 0:003889bc474f 320 memset(b,0,sizeof(b));
nobukuma 0:003889bc474f 321 memcpy(b,data,6);
nobukuma 0:003889bc474f 322 b[6] = 4;
nobukuma 0:003889bc474f 323 memcpy(b+7, pin, 4);
nobukuma 0:003889bc474f 324 return SendCmd(HCI_OP_PIN_CODE_REPLY,b,sizeof(b));
nobukuma 0:003889bc474f 325 }
nobukuma 0:003889bc474f 326
nobukuma 0:003889bc474f 327 void HCI::InquiryResult(const inquiry_info* info) {
nobukuma 0:003889bc474f 328 BTDevice* bt = Find(&info->bdaddr);
nobukuma 0:003889bc474f 329 if (!bt) { // new device
nobukuma 0:003889bc474f 330 for (int i = 0; i < MAX_BTDEVICES; i++) {
nobukuma 0:003889bc474f 331 if (_devices[i]._state == 0) {
nobukuma 0:003889bc474f 332 bt = _devices + i;
nobukuma 0:003889bc474f 333 bt->_state = 1;
nobukuma 0:003889bc474f 334 break;
nobukuma 0:003889bc474f 335 }
nobukuma 0:003889bc474f 336 }
nobukuma 0:003889bc474f 337 if (!bt) {
nobukuma 0:003889bc474f 338 printf("HCI::InquiryResult too many devices\n");
nobukuma 0:003889bc474f 339 return; // Too many devices!
nobukuma 0:003889bc474f 340 }
nobukuma 0:003889bc474f 341 }
nobukuma 0:003889bc474f 342
nobukuma 0:003889bc474f 343 bt->_info = *info;
nobukuma 0:003889bc474f 344 }
nobukuma 0:003889bc474f 345
nobukuma 0:003889bc474f 346 int HCI::GetDevices(BTDevice** devices, int maxDevices) {
nobukuma 0:003889bc474f 347 int j = 0;
nobukuma 0:003889bc474f 348 for (int i = 0; i < MAX_BTDEVICES; i++) {
nobukuma 0:003889bc474f 349 if (_devices[i]._state != 0) {
nobukuma 0:003889bc474f 350 devices[j++] = _devices + i;
nobukuma 0:003889bc474f 351 if (j == maxDevices)
nobukuma 0:003889bc474f 352 break;
nobukuma 0:003889bc474f 353 }
nobukuma 0:003889bc474f 354 }
nobukuma 0:003889bc474f 355 return j;
nobukuma 0:003889bc474f 356 }
nobukuma 0:003889bc474f 357
nobukuma 0:003889bc474f 358 void HCI::RemoteName(const BD_ADDR* addr, const char* name) {
nobukuma 0:003889bc474f 359 BTDevice* d = Find(addr);
nobukuma 0:003889bc474f 360 if (d) {
nobukuma 0:003889bc474f 361 strncpy(d->_name,name,sizeof(d->_name)-1);
nobukuma 0:003889bc474f 362 d->_name[sizeof(d->_name)-1] = 0;
nobukuma 0:003889bc474f 363 }
nobukuma 0:003889bc474f 364 }
nobukuma 0:003889bc474f 365
nobukuma 0:003889bc474f 366 void HCI::ConnectComplete(const connection_info* info) {
nobukuma 0:003889bc474f 367 BTDevice* d = Find(&info->bdaddr);
nobukuma 0:003889bc474f 368 if (!d) {
nobukuma 0:003889bc474f 369 printf("BT Device not known!?! ");
nobukuma 0:003889bc474f 370 printf(&info->bdaddr);
nobukuma 0:003889bc474f 371 printf("\n");
nobukuma 0:003889bc474f 372 return;
nobukuma 0:003889bc474f 373 }
nobukuma 0:003889bc474f 374 if (info->status == 0) {
nobukuma 0:003889bc474f 375 d->_handle = info->handle;
nobukuma 0:003889bc474f 376 #ifdef HOST_CONTR_FLOW
nobukuma 0:003889bc474f 377 d->pkts_sent = 0;
nobukuma 0:003889bc474f 378 #endif
nobukuma 0:003889bc474f 379 printf("Connected on %04X\n",info->handle);
nobukuma 0:003889bc474f 380 } else
nobukuma 0:003889bc474f 381 printf("Connection failed with %d\n",info->status);
nobukuma 0:003889bc474f 382 }
nobukuma 0:003889bc474f 383
nobukuma 0:003889bc474f 384 void HCI::Accept_Connection(const BD_ADDR* addr, bool slave) {
nobukuma 0:003889bc474f 385 unsigned char b[7];
nobukuma 0:003889bc474f 386 memcpy(b, addr, 6);
nobukuma 0:003889bc474f 387 b[6] = slave;
nobukuma 0:003889bc474f 388 BTDevice* bt = Find(addr);
nobukuma 0:003889bc474f 389 if (!bt) {
nobukuma 0:003889bc474f 390 printf("Received connection request from undiscovered device\n");
nobukuma 0:003889bc474f 391 for (int i = 0; i < MAX_BTDEVICES; i++) {
nobukuma 0:003889bc474f 392 if (_devices[i]._state == 0) {
nobukuma 0:003889bc474f 393 bt = _devices + i;
nobukuma 0:003889bc474f 394 bt->_state = 1;
nobukuma 0:003889bc474f 395 memcpy(&(bt->_info.bdaddr), addr, 6);//rest of inquiry info unknown!!!
nobukuma 0:003889bc474f 396 break;
nobukuma 0:003889bc474f 397 }
nobukuma 0:003889bc474f 398 }
nobukuma 0:003889bc474f 399 if (!bt) {
nobukuma 0:003889bc474f 400 printf("HCI::InquiryResult too many devices\n");
nobukuma 0:003889bc474f 401 return; // Too many devices!
nobukuma 0:003889bc474f 402 }
nobukuma 0:003889bc474f 403 }
nobukuma 0:003889bc474f 404 SendCmd(HCI_OP_ACCEPT_CONN_REQ, b , 7);
nobukuma 0:003889bc474f 405 }
nobukuma 0:003889bc474f 406
nobukuma 0:003889bc474f 407 void HCI::HCIRecv(const u8* data, int len) {//[0]=event, [1]=parlen, [2...]=pars
nobukuma 0:003889bc474f 408 printfBytes(EvtStr(data[0]),data,min(len,16));
nobukuma 0:003889bc474f 409 switch (data[0]) {
nobukuma 0:003889bc474f 410 case HCI_EV_INQUIRY_COMPLETE:
nobukuma 0:003889bc474f 411 printfBytes("Inquiry Complete",data,data[1]);
nobukuma 0:003889bc474f 412 _state &= ~MASK_INQUIRY;
nobukuma 0:003889bc474f 413 Callback(CALLBACK_INQUIRY_DONE,0,0);
nobukuma 0:003889bc474f 414 break;
nobukuma 0:003889bc474f 415
nobukuma 0:003889bc474f 416 case HCI_EV_INQUIRY_RESULT: {
nobukuma 0:003889bc474f 417 const u8* end = data[1] + data + 2;
nobukuma 0:003889bc474f 418 data += 3;
nobukuma 0:003889bc474f 419 while (data < end) {
nobukuma 0:003889bc474f 420 inquiry_info align;
nobukuma 0:003889bc474f 421 memcpy(&align,data,sizeof(inquiry_info));
nobukuma 0:003889bc474f 422 InquiryResult(&align);
nobukuma 0:003889bc474f 423 Callback(CALLBACK_INQUIRY_RESULT,(u8*)&align,sizeof(inquiry_info));
nobukuma 0:003889bc474f 424 data += 14;
nobukuma 0:003889bc474f 425 }
nobukuma 0:003889bc474f 426 }
nobukuma 0:003889bc474f 427 break;
nobukuma 0:003889bc474f 428
nobukuma 0:003889bc474f 429 case HCI_EV_CONN_COMPLETE:
nobukuma 0:003889bc474f 430 _state &= ~MASK_CREATE_CONNECTION;
nobukuma 0:003889bc474f 431 {
nobukuma 0:003889bc474f 432 connection_info align;
nobukuma 0:003889bc474f 433 memcpy(&align,data+2,sizeof(connection_info));
nobukuma 0:003889bc474f 434 ConnectComplete(&align);
nobukuma 0:003889bc474f 435 Callback(CALLBACK_CONNECTION_COMPLETE,(u8*)&align,sizeof(connection_info));
nobukuma 0:003889bc474f 436 }
nobukuma 0:003889bc474f 437 break;
nobukuma 0:003889bc474f 438
nobukuma 0:003889bc474f 439 case HCI_EV_CONN_REQUEST:
nobukuma 0:003889bc474f 440 printf("Got Connection request \n");
nobukuma 0:003889bc474f 441 Callback(CALLBACK_CONNECTION_REQUEST, data+2, data[1]);
nobukuma 0:003889bc474f 442 Accept_Connection((BD_ADDR*)(data+2));
nobukuma 0:003889bc474f 443 break;
nobukuma 0:003889bc474f 444
nobukuma 0:003889bc474f 445 case HCI_EV_DISCONN_COMPLETE:
nobukuma 0:003889bc474f 446 DisconnectComplete(LE16(data+3));
nobukuma 0:003889bc474f 447 break;
nobukuma 0:003889bc474f 448
nobukuma 0:003889bc474f 449 case HCI_EV_REMOTE_NAME: {
nobukuma 0:003889bc474f 450 BD_ADDR* addr = (BD_ADDR*)(data+3);
nobukuma 0:003889bc474f 451 const char* name = (const char*)(data + 9);
nobukuma 0:003889bc474f 452 RemoteName(addr,name);
nobukuma 0:003889bc474f 453 }
nobukuma 0:003889bc474f 454 Callback(CALLBACK_REMOTE_NAME,data+3,LE16(data+1)); // addr is in here too
nobukuma 0:003889bc474f 455 _state &= ~MASK_REMOTE_NAME;
nobukuma 0:003889bc474f 456 break;
nobukuma 0:003889bc474f 457
nobukuma 0:003889bc474f 458 case HCI_EV_CMD_STATUS: {
nobukuma 0:003889bc474f 459 const char* errs = HCIErrStr(data[2]);
nobukuma 0:003889bc474f 460 printf("Status %s %s %d cmd pkts\n",CmdStr(LE16(data+4)),errs, data[3]);
nobukuma 0:003889bc474f 461 #ifdef COMMAND_FLOW
nobukuma 0:003889bc474f 462 cmd_credits = data[3];
nobukuma 0:003889bc474f 463 #endif
nobukuma 0:003889bc474f 464 }
nobukuma 0:003889bc474f 465 Callback(CALLBACK_CMD_STATUS, data+2, 4);
nobukuma 0:003889bc474f 466 break;
nobukuma 0:003889bc474f 467
nobukuma 0:003889bc474f 468 case HCI_EV_CMD_COMPLETE://[2]=cmd-pkts, [3-4]=cmd, [5...]=pars
nobukuma 0:003889bc474f 469 if (data[5]) { //[5]=usually status
nobukuma 0:003889bc474f 470 printf("HCIRecv error status: %s\n", HCIErrStr(data[5]));
nobukuma 0:003889bc474f 471 }
nobukuma 0:003889bc474f 472 OnCommandComplete(data[3] | (data[4] << 8), data+6, data[1]-4);
nobukuma 0:003889bc474f 473 #ifdef COMMAND_FLOW
nobukuma 0:003889bc474f 474 cmd_credits = data[2];
nobukuma 0:003889bc474f 475 #endif
nobukuma 0:003889bc474f 476 break;
nobukuma 0:003889bc474f 477
nobukuma 0:003889bc474f 478 case HCI_EV_PIN_CODE_REQ:
nobukuma 0:003889bc474f 479 Callback(CALLBACK_PIN_REQ, data+2, 6);
nobukuma 0:003889bc474f 480 //PinCodeReply(data+2);
nobukuma 0:003889bc474f 481 break;
nobukuma 0:003889bc474f 482
nobukuma 0:003889bc474f 483 case HCI_EV_LINK_KEY_REQ: {
nobukuma 0:003889bc474f 484 u8 param[22];
nobukuma 0:003889bc474f 485 if (neighbors->get((BD_ADDR*)(data+2), param+sizeof(BD_ADDR))){
nobukuma 0:003889bc474f 486 memcpy(param, data+2, sizeof(BD_ADDR));
nobukuma 0:003889bc474f 487 SendCmd(HCI_OP_LINK_KEY_REPLY,param,sizeof(param));
nobukuma 0:003889bc474f 488 } else
nobukuma 0:003889bc474f 489 SendCmd(HCI_OP_LINK_KEY_NEG_REPLY,data+2,6);
nobukuma 0:003889bc474f 490 }
nobukuma 0:003889bc474f 491 break;
nobukuma 0:003889bc474f 492 #ifdef HOST_CONTR_FLOW
nobukuma 0:003889bc474f 493 case HCI_EV_NUM_COMP_PKTS:
nobukuma 0:003889bc474f 494 for (int k = 0; k < data[2]; k++) {//data[2] and 'c' are usually 1
nobukuma 0:003889bc474f 495 u16 h = LE16(data+3+2*k);
nobukuma 0:003889bc474f 496 u16 c = LE16(data+5+2*k);
nobukuma 0:003889bc474f 497 BTDevice *d = Find(h);
nobukuma 0:003889bc474f 498 if (!d)
nobukuma 0:003889bc474f 499 continue;//skip no existing devices
nobukuma 0:003889bc474f 500 if (d->pkts_sent >= c) {
nobukuma 0:003889bc474f 501 d->pkts_sent -= c;
nobukuma 0:003889bc474f 502 _transport->data_credits += c;
nobukuma 0:003889bc474f 503 } else
nobukuma 0:003889bc474f 504 d->pkts_sent = 0;
nobukuma 0:003889bc474f 505 //printf("%d Outstanding pkts for handle %03X (total credits=%d)\n", d->pkts_sent, h, _transport->data_credits);
nobukuma 0:003889bc474f 506 }
nobukuma 0:003889bc474f 507 break;
nobukuma 0:003889bc474f 508 #endif
nobukuma 0:003889bc474f 509 case HCI_EV_LINK_KEY_NOTIFY:
nobukuma 0:003889bc474f 510 neighbors->add((BD_ADDR*)(data+2), data+8);
nobukuma 0:003889bc474f 511 break;
nobukuma 0:003889bc474f 512 case HCI_EV_RETURN_LINK_KEYS:
nobukuma 0:003889bc474f 513 for (int i = 0; i < data[2]; i++)
nobukuma 0:003889bc474f 514 neighbors->add((BD_ADDR*)(data+3+22*i), data+9+22*i, true);
nobukuma 0:003889bc474f 515 break;
nobukuma 0:003889bc474f 516 case HCI_EV_ENCRYPT_CHANGE:
nobukuma 0:003889bc474f 517 //for(int k=0; k<1000000;k++) USBLoop();
nobukuma 0:003889bc474f 518 break;
nobukuma 0:003889bc474f 519 case HCI_EV_VENDOR:
nobukuma 0:003889bc474f 520 Callback(CALLBACK_VENDOR, data+2, data[1]);
nobukuma 0:003889bc474f 521 break;
nobukuma 0:003889bc474f 522 default:
nobukuma 0:003889bc474f 523 printfBytes("HCIRecv:",data,data[1]+2);
nobukuma 0:003889bc474f 524 break;
nobukuma 0:003889bc474f 525 }
nobukuma 0:003889bc474f 526 }
nobukuma 0:003889bc474f 527
nobukuma 0:003889bc474f 528 int HCI::Open(SocketInternal* sock, SocketAddrHdr* addr) {
nobukuma 0:003889bc474f 529 L2CAPSocket* l2capsock = (L2CAPSocket*)sock;
nobukuma 0:003889bc474f 530 L2CAPAddr* l2capaddr = (L2CAPAddr*)addr;
nobukuma 0:003889bc474f 531 BTDevice* bt = Find(&l2capaddr->bdaddr);
nobukuma 0:003889bc474f 532 if (!bt) {
nobukuma 0:003889bc474f 533 printf("Can't open l2cap %d on ",l2capaddr->psm);
nobukuma 0:003889bc474f 534 printf(&l2capaddr->bdaddr);
nobukuma 0:003889bc474f 535 printf("\n");
nobukuma 0:003889bc474f 536 return ERR_HCI_DEVICE_NOT_FOUND;
nobukuma 0:003889bc474f 537 }
nobukuma 0:003889bc474f 538 l2capsock->btdevice = bt;
nobukuma 0:003889bc474f 539 return bt->Open(sock,addr);
nobukuma 0:003889bc474f 540 }
nobukuma 0:003889bc474f 541
nobukuma 0:003889bc474f 542 int HCI::Accept(SocketInternal* sock, int scid, int rxid) {
nobukuma 0:003889bc474f 543 L2CAPSocket* l2capsock = (L2CAPSocket*)sock;
nobukuma 0:003889bc474f 544 BTDevice* bt = (BTDevice*)sock->userData;
nobukuma 0:003889bc474f 545 if (!bt) {
nobukuma 0:003889bc474f 546 printf("Can't accept l2cap on socket %d\n", sock->ID);
nobukuma 0:003889bc474f 547 return ERR_HCI_DEVICE_NOT_FOUND;
nobukuma 0:003889bc474f 548 }
nobukuma 0:003889bc474f 549 l2capsock->btdevice = bt;
nobukuma 0:003889bc474f 550 return bt->Accept(sock, scid, rxid);
nobukuma 0:003889bc474f 551 }
nobukuma 0:003889bc474f 552
nobukuma 0:003889bc474f 553 int HCI::Send(SocketInternal* sock, const u8* data, int len) {//check here for appropriate buffersize on the device
nobukuma 0:003889bc474f 554 /* these checks are HCI functions but this 'Send' does not catch all ACL traffic, so it is better done in L2CAP or transport
nobukuma 0:003889bc474f 555 //assume acl packet
nobukuma 0:003889bc474f 556 //FIXME: treatment of OFFSET is dubious, OFFSET is not defined?!
nobukuma 0:003889bc474f 557 #if OFFSET==8 //sizeof ACL/L2CAP is include in data/len
nobukuma 0:003889bc474f 558 if (len > _acl_mtu)
nobukuma 0:003889bc474f 559 #else //OFFSET==0, data is bare application frame
nobukuma 0:003889bc474f 560 if (len+8 > _acl_mtu)
nobukuma 0:003889bc474f 561 #endif
nobukuma 0:003889bc474f 562 { printf("Max outgoing packet(%d) size exceeded, segmenting necessary, pktlen = %d\n", _acl_mtu, len);
nobukuma 0:003889bc474f 563 }
nobukuma 0:003889bc474f 564 if (data_credits == 0) {
nobukuma 0:003889bc474f 565 printf("Out of ACL data credits\n");
nobukuma 0:003889bc474f 566 return 0;
nobukuma 0:003889bc474f 567 }
nobukuma 0:003889bc474f 568 data_credits--;
nobukuma 0:003889bc474f 569 */
nobukuma 0:003889bc474f 570 L2CAPSocket* l2capsock = (L2CAPSocket*)sock;
nobukuma 0:003889bc474f 571 return l2capsock->btdevice->Send(sock,data,len); // Pointless double dispatch
nobukuma 0:003889bc474f 572 }
nobukuma 0:003889bc474f 573
nobukuma 0:003889bc474f 574 int HCI::Close(SocketInternal* sock) {
nobukuma 0:003889bc474f 575 L2CAPSocket* l2capsock = (L2CAPSocket*)sock;
nobukuma 0:003889bc474f 576 return l2capsock->btdevice->Close(sock); // Pointless double dispatch
nobukuma 0:003889bc474f 577 }
nobukuma 0:003889bc474f 578
nobukuma 0:003889bc474f 579 void HCI::Compl_pkts(int handle, u8 p) {
nobukuma 0:003889bc474f 580 u8 b[8] = {(u8)HCI_OP_NUM_COMP_PKTS, HCI_OP_NUM_COMP_PKTS >> 8, 5, 1, 0, 0, 1, 0};
nobukuma 0:003889bc474f 581 b[4] = handle;
nobukuma 0:003889bc474f 582 b[5] = (handle&0x0f00)>>8;
nobukuma 0:003889bc474f 583 b[6] = p;//only one packet
nobukuma 0:003889bc474f 584 _transport->HCISend(b, 8);//directly call the transport layer to prevent the command flow control from interfering
nobukuma 0:003889bc474f 585 }
nobukuma 0:003889bc474f 586
nobukuma 0:003889bc474f 587 void HCI::ACLRecv(const u8* data, int len) {
nobukuma 0:003889bc474f 588 int handle = LE16(data);
nobukuma 0:003889bc474f 589 BTDevice* d = Find(handle & 0x0FFF);
nobukuma 0:003889bc474f 590 int bufs = 1;
nobukuma 0:003889bc474f 591 if (!d) {
nobukuma 0:003889bc474f 592 printfBytes("unk. dest. HCI:ACLRecv ", data, len);
nobukuma 0:003889bc474f 593 } else
nobukuma 0:003889bc474f 594 bufs = d->ACLRecv(data,len);
nobukuma 0:003889bc474f 595 //controller to host flow control
nobukuma 0:003889bc474f 596 #ifdef CONTR_HOST_FLOW
nobukuma 0:003889bc474f 597 //the ACLRecv function returned so we assume that the buffer is free, and tell this to the controller
nobukuma 0:003889bc474f 598 if (bufs) {
nobukuma 0:003889bc474f 599 Compl_pkts(handle, bufs);//this packet is completed
nobukuma 0:003889bc474f 600 printf("%d ACL buffers completed\n", bufs);
nobukuma 0:003889bc474f 601 }
nobukuma 0:003889bc474f 602 #endif
nobukuma 0:003889bc474f 603 }
nobukuma 0:003889bc474f 604
nobukuma 0:003889bc474f 605 //===================================================================
nobukuma 0:003889bc474f 606 //===================================================================