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

Committer:
networker
Date:
Sun Jun 19 19:32:51 2011 +0000
Revision:
12:57f7679dd651
Parent:
11:e6245f64412d
fixed default mtu, small impovement in config processing

Who changed what in which revision?

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