|
| 1 | +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD |
| 2 | +// |
| 3 | +// Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | +// you may not use this file except in compliance with the License. |
| 5 | +// You may obtain a copy of the License at |
| 6 | + |
| 7 | +// http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | +// |
| 9 | +// Unless required by applicable law or agreed to in writing, software |
| 10 | +// distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | +// See the License for the specific language governing permissions and |
| 13 | +// limitations under the License. |
| 14 | + |
| 15 | +#include "NefryBLE.h" |
| 16 | +#include "esp32-hal-log.h" |
| 17 | + |
| 18 | +/* HCI Command opcode group field(OGF) */ |
| 19 | +#define HCI_GRP_HOST_CONT_BASEBAND_CMDS (0x03 << 10) /* 0x0C00 */ |
| 20 | +#define HCI_GRP_BLE_CMDS (0x08 << 10) |
| 21 | + |
| 22 | +/* HCI Command opcode command field(OCF) */ |
| 23 | +#define HCI_RESET (0x0003 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) |
| 24 | +#define HCI_BLE_WRITE_ADV_ENABLE (0x000A | HCI_GRP_BLE_CMDS) |
| 25 | +#define HCI_BLE_WRITE_ADV_PARAMS (0x0006 | HCI_GRP_BLE_CMDS) |
| 26 | +#define HCI_BLE_WRITE_ADV_DATA (0x0008 | HCI_GRP_BLE_CMDS) |
| 27 | + |
| 28 | +#define HCI_H4_CMD_PREAMBLE_SIZE (4) |
| 29 | +#define HCIC_PARAM_SIZE_WRITE_ADV_ENABLE (1) |
| 30 | +#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS (15) |
| 31 | +#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA (31) |
| 32 | + |
| 33 | +/* EIR/AD data type definitions */ |
| 34 | +#define BT_DATA_FLAGS 0x01 /* AD flags */ |
| 35 | +#define BT_DATA_UUID16_SOME 0x02 /* 16-bit UUID, more available */ |
| 36 | +#define BT_DATA_UUID16_ALL 0x03 /* 16-bit UUID, all listed */ |
| 37 | +#define BT_DATA_UUID32_SOME 0x04 /* 32-bit UUID, more available */ |
| 38 | +#define BT_DATA_UUID32_ALL 0x05 /* 32-bit UUID, all listed */ |
| 39 | +#define BT_DATA_UUID128_SOME 0x06 /* 128-bit UUID, more available */ |
| 40 | +#define BT_DATA_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ |
| 41 | +#define BT_DATA_NAME_SHORTENED 0x08 /* Shortened name */ |
| 42 | +#define BT_DATA_NAME_COMPLETE 0x09 /* Complete name */ |
| 43 | +#define BT_DATA_TX_POWER 0x0a /* Tx Power */ |
| 44 | +#define BT_DATA_SOLICIT16 0x14 /* Solicit UUIDs, 16-bit */ |
| 45 | +#define BT_DATA_SOLICIT128 0x15 /* Solicit UUIDs, 128-bit */ |
| 46 | +#define BT_DATA_SVC_DATA16 0x16 /* Service data, 16-bit UUID */ |
| 47 | +#define BT_DATA_GAP_APPEARANCE 0x19 /* GAP appearance */ |
| 48 | +#define BT_DATA_SOLICIT32 0x1f /* Solicit UUIDs, 32-bit */ |
| 49 | +#define BT_DATA_SVC_DATA32 0x20 /* Service data, 32-bit UUID */ |
| 50 | +#define BT_DATA_SVC_DATA128 0x21 /* Service data, 128-bit UUID */ |
| 51 | +#define BT_DATA_MANUFACTURER_DATA 0xff /* Manufacturer Specific Data */ |
| 52 | + |
| 53 | + |
| 54 | +/* Advertising types */ |
| 55 | +#define BLE_GAP_ADV_TYPE_ADV_IND 0x00 |
| 56 | +#define BLE_GAP_ADV_TYPE_ADV_DIRECT_IND 0x01 |
| 57 | +#define BLE_GAP_ADV_TYPE_ADV_SCAN_IND 0x02 |
| 58 | +#define BLE_GAP_ADV_TYPE_ADV_NONCONN_IND 0x03 |
| 59 | + |
| 60 | + |
| 61 | +/* Advertising Discovery Flags */ |
| 62 | +#define BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE (0x01) |
| 63 | +#define BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE (0x02) |
| 64 | +#define BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED (0x04) |
| 65 | +#define BLE_GAP_ADV_FLAG_LE_BR_EDR_CONTROLLER (0x08) |
| 66 | +#define BLE_GAP_ADV_FLAG_LE_BR_EDR_HOST (0x10) |
| 67 | +#define BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE (BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE | BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) |
| 68 | +#define BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE (BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE | BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) |
| 69 | + |
| 70 | + |
| 71 | +/* Advertising Filter Policies */ |
| 72 | +#define BLE_GAP_ADV_FP_ANY 0x00 |
| 73 | +#define BLE_GAP_ADV_FP_FILTER_SCANREQ 0x01 |
| 74 | +#define BLE_GAP_ADV_FP_FILTER_CONNREQ 0x02 |
| 75 | +#define BLE_GAP_ADV_FP_FILTER_BOTH 0x03 |
| 76 | + |
| 77 | + |
| 78 | +/* Advertising Device Address Types */ |
| 79 | +#define BLE_GAP_ADDR_TYPE_PUBLIC 0x00 |
| 80 | +#define BLE_GAP_ADDR_TYPE_RANDOM_STATIC 0x01 |
| 81 | +#define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE 0x02 |
| 82 | +#define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE 0x03 |
| 83 | + |
| 84 | + |
| 85 | +/* GAP Advertising Channel Maps */ |
| 86 | +#define GAP_ADVCHAN_37 0x01 |
| 87 | +#define GAP_ADVCHAN_38 0x02 |
| 88 | +#define GAP_ADVCHAN_39 0x04 |
| 89 | +#define GAP_ADVCHAN_ALL GAP_ADVCHAN_37 | GAP_ADVCHAN_38 | GAP_ADVCHAN_39 |
| 90 | + |
| 91 | + |
| 92 | +/* GAP Filter Policies */ |
| 93 | +#define BLE_GAP_ADV_FP_ANY 0x00 |
| 94 | +#define BLE_GAP_ADV_FP_FILTER_SCANREQ 0x01 |
| 95 | +#define BLE_GAP_ADV_FP_FILTER_CONNREQ 0x02 |
| 96 | +#define BLE_GAP_ADV_FP_FILTER_BOTH 0x03 |
| 97 | + |
| 98 | +#define BD_ADDR_LEN (6) /* Device address length */ |
| 99 | + |
| 100 | + |
| 101 | +/* |
| 102 | +* BLE System |
| 103 | +* |
| 104 | +* */ |
| 105 | + |
| 106 | +/* HCI H4 message type definitions */ |
| 107 | +enum { |
| 108 | + H4_TYPE_COMMAND = 1, |
| 109 | + H4_TYPE_ACL = 2, |
| 110 | + H4_TYPE_SCO = 3, |
| 111 | + H4_TYPE_EVENT = 4 |
| 112 | +}; |
| 113 | + |
| 114 | +volatile bool _vhci_host_send_available = false; |
| 115 | +volatile bool _vhci_host_command_running = false; |
| 116 | +static uint16_t _vhci_host_command = 0x0000; |
| 117 | +static uint8_t _vhci_host_command_result = 0x00; |
| 118 | + |
| 119 | +//controller is ready to receive command |
| 120 | +static void _on_tx_ready(void) |
| 121 | +{ |
| 122 | + _vhci_host_send_available = true; |
| 123 | +} |
| 124 | +/* |
| 125 | +static void _dump_buf(const char * txt, uint8_t *data, uint16_t len){ |
| 126 | +log_printf("%s[%u]:", txt, len); |
| 127 | +for (uint16_t i=0; i<len; i++) |
| 128 | +log_printf(" %02x", data[i]); |
| 129 | +log_printf("\n"); |
| 130 | +} |
| 131 | +*/ |
| 132 | +//controller has a packet |
| 133 | +static int _on_rx_data(uint8_t *data, uint16_t len) |
| 134 | +{ |
| 135 | + if (len == 7 && *data == 0x04) { |
| 136 | + //baseband response |
| 137 | + uint16_t cmd = (((uint16_t)data[5] << 8) | data[4]); |
| 138 | + uint8_t res = data[6]; |
| 139 | + if (_vhci_host_command_running && _vhci_host_command == cmd) { |
| 140 | + //_dump_buf("BLE: res", data, len); |
| 141 | + _vhci_host_command_result = res; |
| 142 | + _vhci_host_command_running = false; |
| 143 | + return 0; |
| 144 | + } |
| 145 | + else if (cmd == 0) { |
| 146 | + log_e("error %u", res); |
| 147 | + } |
| 148 | + } |
| 149 | + |
| 150 | + //_dump_buf("BLE: rx", data, len); |
| 151 | + return 0; |
| 152 | +} |
| 153 | + |
| 154 | + |
| 155 | + |
| 156 | + |
| 157 | +static esp_vhci_host_callback_t vhci_host_cb = { |
| 158 | + _on_tx_ready, |
| 159 | + _on_rx_data |
| 160 | +}; |
| 161 | + |
| 162 | +static bool _esp_ble_start() |
| 163 | +{ |
| 164 | + if (btStart()) { |
| 165 | + esp_vhci_host_register_callback(&vhci_host_cb); |
| 166 | + uint8_t i = 0; |
| 167 | + while (!esp_vhci_host_check_send_available() && i++ < 100) { |
| 168 | + delay(10); |
| 169 | + } |
| 170 | + if (i >= 100) { |
| 171 | + log_e("esp_vhci_host_check_send_available failed"); |
| 172 | + return false; |
| 173 | + } |
| 174 | + _vhci_host_send_available = true; |
| 175 | + } |
| 176 | + else |
| 177 | + log_e("BT Failed"); |
| 178 | + return true; |
| 179 | +} |
| 180 | + |
| 181 | +static bool _esp_ble_stop() |
| 182 | +{ |
| 183 | + if (btStarted()) { |
| 184 | + _vhci_host_send_available = false; |
| 185 | + btStop(); |
| 186 | + esp_vhci_host_register_callback(NULL); |
| 187 | + } |
| 188 | + return true; |
| 189 | +} |
| 190 | + |
| 191 | +//public |
| 192 | + |
| 193 | +static uint8_t ble_send_cmd(uint16_t cmd, uint8_t * data, uint8_t len) { |
| 194 | + static uint8_t buf[36]; |
| 195 | + if (len > 32) { |
| 196 | + //too much data |
| 197 | + return 2; |
| 198 | + } |
| 199 | + uint16_t i = 0; |
| 200 | + while (!_vhci_host_send_available && i++ < 1000) { |
| 201 | + delay(1); |
| 202 | + } |
| 203 | + if (i >= 1000) { |
| 204 | + log_e("_vhci_host_send_available failed"); |
| 205 | + return 1; |
| 206 | + } |
| 207 | + uint8_t outlen = len + HCI_H4_CMD_PREAMBLE_SIZE; |
| 208 | + buf[0] = H4_TYPE_COMMAND; |
| 209 | + buf[1] = (uint8_t)(cmd & 0xFF); |
| 210 | + buf[2] = (uint8_t)(cmd >> 8); |
| 211 | + buf[3] = len; |
| 212 | + if (len) { |
| 213 | + memcpy(buf + 4, data, len); |
| 214 | + } |
| 215 | + _vhci_host_send_available = false; |
| 216 | + _vhci_host_command_running = true; |
| 217 | + _vhci_host_command = cmd; |
| 218 | + |
| 219 | + //log_printf("BLE: cmd: 0x%04X, data[%u]:", cmd, len); |
| 220 | + //for (uint16_t i=0; i<len; i++) log_printf(" %02x", buf[i+4]); |
| 221 | + //log_printf("\n"); |
| 222 | + |
| 223 | + esp_vhci_host_send_packet(buf, outlen); |
| 224 | + while (_vhci_host_command_running); |
| 225 | + int res = _vhci_host_command_result; |
| 226 | + //log_printf("BLE: cmd: 0x%04X, res: %u\n", cmd, res); |
| 227 | + return res; |
| 228 | +} |
| 229 | + |
| 230 | + |
| 231 | +/* |
| 232 | +* BLE Arduino |
| 233 | +* |
| 234 | +* */ |
| 235 | + |
| 236 | +enum { |
| 237 | + UNIT_0_625_MS = 625, /* Number of microseconds in 0.625 milliseconds. */ |
| 238 | + UNIT_1_25_MS = 1250, /* Number of microseconds in 1.25 milliseconds. */ |
| 239 | + UNIT_10_MS = 10000 /* Number of microseconds in 10 milliseconds. */ |
| 240 | +}; |
| 241 | + |
| 242 | +/* BLE Advertising parameters struct */ |
| 243 | +typedef struct ble_gap_adv_params_s { |
| 244 | + uint8_t type; |
| 245 | + uint8_t own_addr_type; |
| 246 | + uint8_t addr_type; |
| 247 | + uint8_t addr[BD_ADDR_LEN]; |
| 248 | + uint8_t fp; // filter policy |
| 249 | + uint16_t interval_min; // minimum advertising interval between 0x0020 and 0x4000 in 0.625 ms units (20ms to 10.24s) |
| 250 | + uint16_t interval_max; |
| 251 | + uint8_t chn_map; |
| 252 | +} ble_adv_params_t; |
| 253 | + |
| 254 | +#define MSEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000) / (RESOLUTION)) |
| 255 | +#define UINT16_TO_STREAM(p, u16) {*(p)++ = (uint8_t)(u16); *(p)++ = (uint8_t)((u16) >> 8);} |
| 256 | +#define UINT8_TO_STREAM(p, u8) {*(p)++ = (uint8_t)(u8);} |
| 257 | +#define BDADDR_TO_STREAM(p, a) {int i; for (i = 0; i < BD_ADDR_LEN; i++) *(p)++ = (uint8_t) a[BD_ADDR_LEN - 1 - i];} |
| 258 | +#define ARRAY_TO_STREAM(p, a, len) {int i; for (i = 0; i < len; i++) *(p)++ = (uint8_t) a[i];} |
| 259 | + |
| 260 | +Nefry_BLE::Nefry_BLE() |
| 261 | +{ |
| 262 | + uint8_t peerAddr[BD_ADDR_LEN] = { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85 }; |
| 263 | + _ble_adv_param = (ble_adv_params_t*)malloc(sizeof(ble_adv_params_t)); |
| 264 | + memset(_ble_adv_param, 0x00, sizeof(ble_adv_params_t)); |
| 265 | + _ble_adv_param->type = BLE_GAP_ADV_TYPE_ADV_NONCONN_IND;//not connectable |
| 266 | + _ble_adv_param->chn_map = GAP_ADVCHAN_ALL; // 37, 38, 39 channels |
| 267 | + _ble_adv_param->fp = 0;//any |
| 268 | + _ble_adv_param->interval_min = 512; |
| 269 | + _ble_adv_param->interval_max = 1024; |
| 270 | + _ble_adv_param->addr_type = 0;//public |
| 271 | + memcpy(_ble_adv_param->addr, peerAddr, BD_ADDR_LEN); |
| 272 | + local_name = "esp32"; |
| 273 | +} |
| 274 | + |
| 275 | +Nefry_BLE::~Nefry_BLE(void) |
| 276 | +{ |
| 277 | + free(_ble_adv_param); |
| 278 | + _esp_ble_stop(); |
| 279 | +} |
| 280 | + |
| 281 | +bool Nefry_BLE::begin() |
| 282 | +{ |
| 283 | + if (!_esp_ble_start()) { |
| 284 | + return false; |
| 285 | + } |
| 286 | + ble_send_cmd(HCI_RESET, NULL, 0); |
| 287 | + |
| 288 | + _ble_send_adv_param(); |
| 289 | + _ble_send_adv_data(); |
| 290 | + |
| 291 | + uint8_t adv_enable = 1; |
| 292 | + ble_send_cmd(HCI_BLE_WRITE_ADV_ENABLE, &adv_enable, HCIC_PARAM_SIZE_WRITE_ADV_ENABLE); |
| 293 | + return true; |
| 294 | +} |
| 295 | + |
| 296 | + |
| 297 | +void Nefry_BLE::end() |
| 298 | +{ |
| 299 | + uint8_t adv_enable = 0; |
| 300 | + ble_send_cmd(HCI_BLE_WRITE_ADV_ENABLE, &adv_enable, HCIC_PARAM_SIZE_WRITE_ADV_ENABLE); |
| 301 | + ble_send_cmd(HCI_RESET, NULL, 0); |
| 302 | + _esp_ble_stop(); |
| 303 | +} |
| 304 | + |
| 305 | +void Nefry_BLE::_ble_send_adv_param(void) |
| 306 | +{ |
| 307 | + uint8_t dbuf[HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS]; |
| 308 | + uint8_t *buf = dbuf; |
| 309 | + UINT16_TO_STREAM(buf, _ble_adv_param->interval_min); |
| 310 | + UINT16_TO_STREAM(buf, _ble_adv_param->interval_max); |
| 311 | + UINT8_TO_STREAM(buf, _ble_adv_param->type); |
| 312 | + UINT8_TO_STREAM(buf, _ble_adv_param->own_addr_type); |
| 313 | + UINT8_TO_STREAM(buf, _ble_adv_param->addr_type); |
| 314 | + ARRAY_TO_STREAM(buf, _ble_adv_param->addr, BD_ADDR_LEN); |
| 315 | + UINT8_TO_STREAM(buf, _ble_adv_param->chn_map); |
| 316 | + UINT8_TO_STREAM(buf, _ble_adv_param->fp); |
| 317 | + ble_send_cmd(HCI_BLE_WRITE_ADV_PARAMS, dbuf, HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS); |
| 318 | +} |
| 319 | + |
| 320 | +void Nefry_BLE::_ble_send_adv_data(void) |
| 321 | +{ |
| 322 | + uint8_t adv_data[31]; |
| 323 | + uint8_t adv_data_len; |
| 324 | + |
| 325 | + adv_data[0] = 2; // Len |
| 326 | + adv_data[1] = 0x01; // Type Flags |
| 327 | + adv_data[2] = 0x06; // GENERAL_DISC_MODE 0x02 | BR_EDR_NOT_SUPPORTED 0x04 |
| 328 | + adv_data[3] = 3; // Len |
| 329 | + adv_data[4] = 0x03; // Type 16-Bit UUID |
| 330 | + adv_data[5] = 0xAA; // Eddystone UUID 2 -> 0xFEAA LSB |
| 331 | + adv_data[6] = 0xFE; // Eddystone UUID 1 MSB |
| 332 | + adv_data[7] = 19; // Length of Beacon Data |
| 333 | + adv_data[8] = 0x16; // Type Service Data |
| 334 | + adv_data[9] = 0xAA; // Eddystone UUID 2 -> 0xFEAA LSB |
| 335 | + adv_data[10] = 0xFE; // Eddystone UUID 1 MSB |
| 336 | + adv_data[11] = 0x10; // Eddystone Frame Type |
| 337 | + adv_data[12] = 0x20; // Beacons TX power at 0m |
| 338 | + adv_data[13] = 0x03; // URL Scheme 'https://' |
| 339 | + adv_data[14] = 0x67; // URL add 1 'g' |
| 340 | + adv_data[15] = 0x6F; // URL add 2 'o' |
| 341 | + adv_data[16] = 0x6F; // URL add 3 'o' |
| 342 | + adv_data[17] = 0x2E; // URL add 4 '.' |
| 343 | + adv_data[18] = 0x67; // URL add 5 'g' |
| 344 | + adv_data[19] = 0x6C; // URL add 6 'l' |
| 345 | + adv_data[20] = 0x2F; // URL add 7 '/' |
| 346 | + adv_data[21] = 0x32; // URL add 8 '2' |
| 347 | + adv_data[22] = 0x79; // URL add 9 'y' |
| 348 | + adv_data[23] = 0x43; // URL add 10 'C' |
| 349 | + adv_data[24] = 0x36; // URL add 11 '6' |
| 350 | + adv_data[25] = 0x4B; // URL add 12 'K' |
| 351 | + adv_data[26] = 0x58; // URL add 13 'X' |
| 352 | + |
| 353 | + adv_data_len = 27; |
| 354 | + ble_send_cmd(HCI_BLE_WRITE_ADV_DATA, (uint8_t *)adv_data, HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1); |
| 355 | +} |
0 commit comments