Pulse Oximeter (NONIN) communicates with mbed via Bluetooth dongle and sends Heart Rate and Oxygen Saturation via GPRS module

Dependencies:   C12832 GPS GSM mbed

Fork of myBlueUSB_localfix by Nobuaki Aoki

Committer:
samialshorman
Date:
Tue Apr 14 21:48:07 2015 +0000
Revision:
3:55a622e3dbb5
Parent:
2:9f25a7fa1a54
Nonin (Pulse Oximeter) connected to mbed lpc 1768 by Bluetooth dongle and sends SMS including Heart Rate and Oxygen saturation by GPRS module

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