Petr Manas / Mbed OS pdiot-f-mbed

Dependencies:   MPU9250

Committer:
fasand
Date:
Wed Oct 23 12:02:27 2019 +0000
Revision:
0:68da41d2fe5c
testik

Who changed what in which revision?

UserRevisionLine numberNew contents of line
fasand 0:68da41d2fe5c 1 #include <stdio.h>
fasand 0:68da41d2fe5c 2 #include "CordioBLE.h"
fasand 0:68da41d2fe5c 3 #include "CordioHCIDriver.h"
fasand 0:68da41d2fe5c 4 #include "CordioHCITransportDriver.h"
fasand 0:68da41d2fe5c 5 #include "mbed.h"
fasand 0:68da41d2fe5c 6 #include "hci_api.h"
fasand 0:68da41d2fe5c 7 #include "hci_cmd.h"
fasand 0:68da41d2fe5c 8 #include "hci_core.h"
fasand 0:68da41d2fe5c 9 #include "dm_api.h"
fasand 0:68da41d2fe5c 10 #include "bstream.h"
fasand 0:68da41d2fe5c 11 #include "hci_mbed_os_adaptation.h"
fasand 0:68da41d2fe5c 12 #include "bluenrg_targets.h"
fasand 0:68da41d2fe5c 13 #include "Thread.h"
fasand 0:68da41d2fe5c 14 #include "Semaphore.h"
fasand 0:68da41d2fe5c 15 #include "Mutex.h"
fasand 0:68da41d2fe5c 16
fasand 0:68da41d2fe5c 17 #define HCI_RESET_RAND_CNT 4
fasand 0:68da41d2fe5c 18
fasand 0:68da41d2fe5c 19 #define VENDOR_SPECIFIC_EVENT 0xFF
fasand 0:68da41d2fe5c 20 #define EVT_BLUE_INITIALIZED 0x0001
fasand 0:68da41d2fe5c 21 #define ACI_READ_CONFIG_DATA_OPCODE 0xFC0D
fasand 0:68da41d2fe5c 22 #define ACI_WRITE_CONFIG_DATA_OPCODE 0xFC0C
fasand 0:68da41d2fe5c 23 #define ACI_GATT_INIT_OPCODE 0xFD01
fasand 0:68da41d2fe5c 24 #define ACI_GAP_INIT_OPCODE 0xFC8A
fasand 0:68da41d2fe5c 25
fasand 0:68da41d2fe5c 26 #define PUBLIC_ADDRESS_OFFSET 0x00
fasand 0:68da41d2fe5c 27 #define RANDOM_STATIC_ADDRESS_OFFSET 0x80
fasand 0:68da41d2fe5c 28 #define LL_WITHOUT_HOST_OFFSET 0x2C
fasand 0:68da41d2fe5c 29 #define ROLE_OFFSET 0x2D
fasand 0:68da41d2fe5c 30
fasand 0:68da41d2fe5c 31 #define SPI_STACK_SIZE 1024
fasand 0:68da41d2fe5c 32
fasand 0:68da41d2fe5c 33 namespace ble {
fasand 0:68da41d2fe5c 34 namespace vendor {
fasand 0:68da41d2fe5c 35 namespace bluenrg {
fasand 0:68da41d2fe5c 36
fasand 0:68da41d2fe5c 37 /**
fasand 0:68da41d2fe5c 38 * BlueNRG HCI driver implementation.
fasand 0:68da41d2fe5c 39 * @see cordio::CordioHCIDriver
fasand 0:68da41d2fe5c 40 */
fasand 0:68da41d2fe5c 41 class HCIDriver : public cordio::CordioHCIDriver
fasand 0:68da41d2fe5c 42 {
fasand 0:68da41d2fe5c 43 public:
fasand 0:68da41d2fe5c 44 /**
fasand 0:68da41d2fe5c 45 * Construction of the BlueNRG HCIDriver.
fasand 0:68da41d2fe5c 46 * @param transport: Transport of the HCI commands.
fasand 0:68da41d2fe5c 47 * @param rst: Name of the reset pin
fasand 0:68da41d2fe5c 48 */
fasand 0:68da41d2fe5c 49 HCIDriver(cordio::CordioHCITransportDriver& transport_driver, PinName rst) :
fasand 0:68da41d2fe5c 50 cordio::CordioHCIDriver(transport_driver), rst(rst) { }
fasand 0:68da41d2fe5c 51
fasand 0:68da41d2fe5c 52 /**
fasand 0:68da41d2fe5c 53 * @see CordioHCIDriver::do_initialize
fasand 0:68da41d2fe5c 54 */
fasand 0:68da41d2fe5c 55 virtual void do_initialize() {
fasand 0:68da41d2fe5c 56 bluenrg_reset();
fasand 0:68da41d2fe5c 57 }
fasand 0:68da41d2fe5c 58
fasand 0:68da41d2fe5c 59 /**
fasand 0:68da41d2fe5c 60 * @see CordioHCIDriver::get_buffer_pool_description
fasand 0:68da41d2fe5c 61 */
fasand 0:68da41d2fe5c 62 ble::vendor::cordio::buf_pool_desc_t get_buffer_pool_description()
fasand 0:68da41d2fe5c 63 {
fasand 0:68da41d2fe5c 64 // Use default buffer pool
fasand 0:68da41d2fe5c 65 return ble::vendor::cordio::CordioHCIDriver::get_default_buffer_pool_description();
fasand 0:68da41d2fe5c 66 }
fasand 0:68da41d2fe5c 67
fasand 0:68da41d2fe5c 68 /**
fasand 0:68da41d2fe5c 69 * @see CordioHCIDriver::start_reset_sequence
fasand 0:68da41d2fe5c 70 */
fasand 0:68da41d2fe5c 71 virtual void start_reset_sequence() {
fasand 0:68da41d2fe5c 72 reset_received = false;
fasand 0:68da41d2fe5c 73 bluenrg_initialized = false;
fasand 0:68da41d2fe5c 74 enable_link_layer_mode_ongoing = false;
fasand 0:68da41d2fe5c 75 /* send an HCI Reset command to start the sequence */
fasand 0:68da41d2fe5c 76 HciResetCmd();
fasand 0:68da41d2fe5c 77 }
fasand 0:68da41d2fe5c 78
fasand 0:68da41d2fe5c 79 /**
fasand 0:68da41d2fe5c 80 * @see CordioHCIDriver::do_terminate
fasand 0:68da41d2fe5c 81 */
fasand 0:68da41d2fe5c 82 virtual void do_terminate() {
fasand 0:68da41d2fe5c 83
fasand 0:68da41d2fe5c 84 }
fasand 0:68da41d2fe5c 85
fasand 0:68da41d2fe5c 86 /**
fasand 0:68da41d2fe5c 87 * @see CordioHCIDriver::handle_reset_sequence
fasand 0:68da41d2fe5c 88 */
fasand 0:68da41d2fe5c 89 virtual void handle_reset_sequence(uint8_t *pMsg) {
fasand 0:68da41d2fe5c 90 uint16_t opcode;
fasand 0:68da41d2fe5c 91 static uint8_t randCnt;
fasand 0:68da41d2fe5c 92 //wait_ms(5);
fasand 0:68da41d2fe5c 93
fasand 0:68da41d2fe5c 94 /* if event is a command complete event */
fasand 0:68da41d2fe5c 95 if (*pMsg == HCI_CMD_CMPL_EVT)
fasand 0:68da41d2fe5c 96 {
fasand 0:68da41d2fe5c 97 /* parse parameters */
fasand 0:68da41d2fe5c 98 pMsg += HCI_EVT_HDR_LEN;
fasand 0:68da41d2fe5c 99 pMsg++; /* skip num packets */
fasand 0:68da41d2fe5c 100 BSTREAM_TO_UINT16(opcode, pMsg);
fasand 0:68da41d2fe5c 101 pMsg++; /* skip status */
fasand 0:68da41d2fe5c 102
fasand 0:68da41d2fe5c 103 /* decode opcode */
fasand 0:68da41d2fe5c 104 switch (opcode)
fasand 0:68da41d2fe5c 105 {
fasand 0:68da41d2fe5c 106 case HCI_OPCODE_RESET: {
fasand 0:68da41d2fe5c 107 /* initialize rand command count */
fasand 0:68da41d2fe5c 108 randCnt = 0;
fasand 0:68da41d2fe5c 109 reset_received = true;
fasand 0:68da41d2fe5c 110 // important, the bluenrg_initialized event come after the
fasand 0:68da41d2fe5c 111 // hci reset event (not documented)
fasand 0:68da41d2fe5c 112 bluenrg_initialized = false;
fasand 0:68da41d2fe5c 113 } break;
fasand 0:68da41d2fe5c 114
fasand 0:68da41d2fe5c 115 // ACL packet ...
fasand 0:68da41d2fe5c 116 case ACI_WRITE_CONFIG_DATA_OPCODE:
fasand 0:68da41d2fe5c 117 if (enable_link_layer_mode_ongoing) {
fasand 0:68da41d2fe5c 118 enable_link_layer_mode_ongoing = false;
fasand 0:68da41d2fe5c 119 aciSetRole();
fasand 0:68da41d2fe5c 120 } else {
fasand 0:68da41d2fe5c 121 aciGattInit();
fasand 0:68da41d2fe5c 122 }
fasand 0:68da41d2fe5c 123 break;
fasand 0:68da41d2fe5c 124
fasand 0:68da41d2fe5c 125 case ACI_GATT_INIT_OPCODE:
fasand 0:68da41d2fe5c 126 aciGapInit();
fasand 0:68da41d2fe5c 127 break;
fasand 0:68da41d2fe5c 128
fasand 0:68da41d2fe5c 129 case ACI_GAP_INIT_OPCODE:
fasand 0:68da41d2fe5c 130 aciReadConfigParameter(RANDOM_STATIC_ADDRESS_OFFSET);
fasand 0:68da41d2fe5c 131 break;
fasand 0:68da41d2fe5c 132
fasand 0:68da41d2fe5c 133 case ACI_READ_CONFIG_DATA_OPCODE:
fasand 0:68da41d2fe5c 134 // note: will send the HCI command to send the random address
fasand 0:68da41d2fe5c 135 cordio::BLE::deviceInstance().getGap().setAddress(
fasand 0:68da41d2fe5c 136 BLEProtocol::AddressType::RANDOM_STATIC,
fasand 0:68da41d2fe5c 137 pMsg
fasand 0:68da41d2fe5c 138 );
fasand 0:68da41d2fe5c 139 break;
fasand 0:68da41d2fe5c 140
fasand 0:68da41d2fe5c 141 case HCI_OPCODE_LE_SET_RAND_ADDR:
fasand 0:68da41d2fe5c 142 HciSetEventMaskCmd((uint8_t *) hciEventMask);
fasand 0:68da41d2fe5c 143 break;
fasand 0:68da41d2fe5c 144
fasand 0:68da41d2fe5c 145 case HCI_OPCODE_SET_EVENT_MASK:
fasand 0:68da41d2fe5c 146 /* send next command in sequence */
fasand 0:68da41d2fe5c 147 HciLeSetEventMaskCmd((uint8_t *) hciLeEventMask);
fasand 0:68da41d2fe5c 148 break;
fasand 0:68da41d2fe5c 149
fasand 0:68da41d2fe5c 150 case HCI_OPCODE_LE_SET_EVENT_MASK:
fasand 0:68da41d2fe5c 151 // Note: the public address is not read because there is no valid public address
fasand 0:68da41d2fe5c 152 // provisioned by default on the target
fasand 0:68da41d2fe5c 153 // Enable if the
fasand 0:68da41d2fe5c 154 #if MBED_CONF_CORDIO_BLUENRG_VALID_PUBLIC_BD_ADDRESS == 1
fasand 0:68da41d2fe5c 155 /* send next command in sequence */
fasand 0:68da41d2fe5c 156 HciReadBdAddrCmd();
fasand 0:68da41d2fe5c 157 break;
fasand 0:68da41d2fe5c 158
fasand 0:68da41d2fe5c 159 case HCI_OPCODE_READ_BD_ADDR:
fasand 0:68da41d2fe5c 160 /* parse and store event parameters */
fasand 0:68da41d2fe5c 161 BdaCpy(hciCoreCb.bdAddr, pMsg);
fasand 0:68da41d2fe5c 162
fasand 0:68da41d2fe5c 163 /* send next command in sequence */
fasand 0:68da41d2fe5c 164 #endif
fasand 0:68da41d2fe5c 165 HciLeReadBufSizeCmd();
fasand 0:68da41d2fe5c 166 break;
fasand 0:68da41d2fe5c 167
fasand 0:68da41d2fe5c 168 case HCI_OPCODE_LE_READ_BUF_SIZE:
fasand 0:68da41d2fe5c 169 /* parse and store event parameters */
fasand 0:68da41d2fe5c 170 BSTREAM_TO_UINT16(hciCoreCb.bufSize, pMsg);
fasand 0:68da41d2fe5c 171 BSTREAM_TO_UINT8(hciCoreCb.numBufs, pMsg);
fasand 0:68da41d2fe5c 172
fasand 0:68da41d2fe5c 173 /* initialize ACL buffer accounting */
fasand 0:68da41d2fe5c 174 hciCoreCb.availBufs = hciCoreCb.numBufs;
fasand 0:68da41d2fe5c 175
fasand 0:68da41d2fe5c 176 /* send next command in sequence */
fasand 0:68da41d2fe5c 177 HciLeReadSupStatesCmd();
fasand 0:68da41d2fe5c 178 break;
fasand 0:68da41d2fe5c 179
fasand 0:68da41d2fe5c 180 case HCI_OPCODE_LE_READ_SUP_STATES:
fasand 0:68da41d2fe5c 181 /* parse and store event parameters */
fasand 0:68da41d2fe5c 182 memcpy(hciCoreCb.leStates, pMsg, HCI_LE_STATES_LEN);
fasand 0:68da41d2fe5c 183
fasand 0:68da41d2fe5c 184 /* send next command in sequence */
fasand 0:68da41d2fe5c 185 HciLeReadWhiteListSizeCmd();
fasand 0:68da41d2fe5c 186 break;
fasand 0:68da41d2fe5c 187
fasand 0:68da41d2fe5c 188 case HCI_OPCODE_LE_READ_WHITE_LIST_SIZE:
fasand 0:68da41d2fe5c 189 /* parse and store event parameters */
fasand 0:68da41d2fe5c 190 BSTREAM_TO_UINT8(hciCoreCb.whiteListSize, pMsg);
fasand 0:68da41d2fe5c 191
fasand 0:68da41d2fe5c 192 /* send next command in sequence */
fasand 0:68da41d2fe5c 193 HciLeReadLocalSupFeatCmd();
fasand 0:68da41d2fe5c 194 break;
fasand 0:68da41d2fe5c 195
fasand 0:68da41d2fe5c 196 case HCI_OPCODE_LE_READ_LOCAL_SUP_FEAT:
fasand 0:68da41d2fe5c 197 /* parse and store event parameters */
fasand 0:68da41d2fe5c 198 BSTREAM_TO_UINT16(hciCoreCb.leSupFeat, pMsg);
fasand 0:68da41d2fe5c 199
fasand 0:68da41d2fe5c 200 /* send next command in sequence */
fasand 0:68da41d2fe5c 201 hciCoreReadResolvingListSize();
fasand 0:68da41d2fe5c 202 break;
fasand 0:68da41d2fe5c 203
fasand 0:68da41d2fe5c 204 case HCI_OPCODE_LE_READ_RES_LIST_SIZE:
fasand 0:68da41d2fe5c 205 /* parse and store event parameters */
fasand 0:68da41d2fe5c 206 BSTREAM_TO_UINT8(hciCoreCb.resListSize, pMsg);
fasand 0:68da41d2fe5c 207
fasand 0:68da41d2fe5c 208 /* send next command in sequence */
fasand 0:68da41d2fe5c 209 hciCoreReadMaxDataLen();
fasand 0:68da41d2fe5c 210 break;
fasand 0:68da41d2fe5c 211
fasand 0:68da41d2fe5c 212 case HCI_OPCODE_LE_READ_MAX_DATA_LEN:
fasand 0:68da41d2fe5c 213 {
fasand 0:68da41d2fe5c 214 uint16_t maxTxOctets;
fasand 0:68da41d2fe5c 215 uint16_t maxTxTime;
fasand 0:68da41d2fe5c 216
fasand 0:68da41d2fe5c 217 BSTREAM_TO_UINT16(maxTxOctets, pMsg);
fasand 0:68da41d2fe5c 218 BSTREAM_TO_UINT16(maxTxTime, pMsg);
fasand 0:68da41d2fe5c 219
fasand 0:68da41d2fe5c 220 /* use Controller's maximum supported payload octets and packet duration times
fasand 0:68da41d2fe5c 221 * for transmission as Host's suggested values for maximum transmission number
fasand 0:68da41d2fe5c 222 * of payload octets and maximum packet transmission time for new connections.
fasand 0:68da41d2fe5c 223 */
fasand 0:68da41d2fe5c 224 HciLeWriteDefDataLen(maxTxOctets, maxTxTime);
fasand 0:68da41d2fe5c 225 }
fasand 0:68da41d2fe5c 226 break;
fasand 0:68da41d2fe5c 227
fasand 0:68da41d2fe5c 228 case HCI_OPCODE_LE_WRITE_DEF_DATA_LEN:
fasand 0:68da41d2fe5c 229 if (hciCoreCb.extResetSeq)
fasand 0:68da41d2fe5c 230 {
fasand 0:68da41d2fe5c 231 /* send first extended command */
fasand 0:68da41d2fe5c 232 (*hciCoreCb.extResetSeq)(pMsg, opcode);
fasand 0:68da41d2fe5c 233 }
fasand 0:68da41d2fe5c 234 else
fasand 0:68da41d2fe5c 235 {
fasand 0:68da41d2fe5c 236 /* initialize extended parameters */
fasand 0:68da41d2fe5c 237 hciCoreCb.maxAdvDataLen = 0;
fasand 0:68da41d2fe5c 238 hciCoreCb.numSupAdvSets = 0;
fasand 0:68da41d2fe5c 239 hciCoreCb.perAdvListSize = 0;
fasand 0:68da41d2fe5c 240
fasand 0:68da41d2fe5c 241 /* send next command in sequence */
fasand 0:68da41d2fe5c 242 HciLeRandCmd();
fasand 0:68da41d2fe5c 243 }
fasand 0:68da41d2fe5c 244 break;
fasand 0:68da41d2fe5c 245
fasand 0:68da41d2fe5c 246 case HCI_OPCODE_LE_READ_MAX_ADV_DATA_LEN:
fasand 0:68da41d2fe5c 247 case HCI_OPCODE_LE_READ_NUM_SUP_ADV_SETS:
fasand 0:68da41d2fe5c 248 case HCI_OPCODE_LE_READ_PER_ADV_LIST_SIZE:
fasand 0:68da41d2fe5c 249 if (hciCoreCb.extResetSeq)
fasand 0:68da41d2fe5c 250 {
fasand 0:68da41d2fe5c 251 /* send next extended command in sequence */
fasand 0:68da41d2fe5c 252 (*hciCoreCb.extResetSeq)(pMsg, opcode);
fasand 0:68da41d2fe5c 253 }
fasand 0:68da41d2fe5c 254 break;
fasand 0:68da41d2fe5c 255
fasand 0:68da41d2fe5c 256 case HCI_OPCODE_LE_RAND:
fasand 0:68da41d2fe5c 257 /* check if need to send second rand command */
fasand 0:68da41d2fe5c 258 if (randCnt < (HCI_RESET_RAND_CNT-1))
fasand 0:68da41d2fe5c 259 {
fasand 0:68da41d2fe5c 260 randCnt++;
fasand 0:68da41d2fe5c 261 HciLeRandCmd();
fasand 0:68da41d2fe5c 262 }
fasand 0:68da41d2fe5c 263 else
fasand 0:68da41d2fe5c 264 {
fasand 0:68da41d2fe5c 265 signal_reset_sequence_done();
fasand 0:68da41d2fe5c 266 }
fasand 0:68da41d2fe5c 267 break;
fasand 0:68da41d2fe5c 268
fasand 0:68da41d2fe5c 269 default:
fasand 0:68da41d2fe5c 270 break;
fasand 0:68da41d2fe5c 271 }
fasand 0:68da41d2fe5c 272 } else {
fasand 0:68da41d2fe5c 273 /**
fasand 0:68da41d2fe5c 274 * vendor specific event
fasand 0:68da41d2fe5c 275 */
fasand 0:68da41d2fe5c 276 if (pMsg[0] == VENDOR_SPECIFIC_EVENT) {
fasand 0:68da41d2fe5c 277 /* parse parameters */
fasand 0:68da41d2fe5c 278 pMsg += HCI_EVT_HDR_LEN;
fasand 0:68da41d2fe5c 279 BSTREAM_TO_UINT16(opcode, pMsg);
fasand 0:68da41d2fe5c 280
fasand 0:68da41d2fe5c 281 if (opcode == EVT_BLUE_INITIALIZED) {
fasand 0:68da41d2fe5c 282 if (bluenrg_initialized) {
fasand 0:68da41d2fe5c 283 return;
fasand 0:68da41d2fe5c 284 }
fasand 0:68da41d2fe5c 285 bluenrg_initialized = true;
fasand 0:68da41d2fe5c 286 if (reset_received) {
fasand 0:68da41d2fe5c 287 aciEnableLinkLayerModeOnly();
fasand 0:68da41d2fe5c 288 }
fasand 0:68da41d2fe5c 289 }
fasand 0:68da41d2fe5c 290
fasand 0:68da41d2fe5c 291 }
fasand 0:68da41d2fe5c 292 }
fasand 0:68da41d2fe5c 293 }
fasand 0:68da41d2fe5c 294
fasand 0:68da41d2fe5c 295 private:
fasand 0:68da41d2fe5c 296 void aciEnableLinkLayerModeOnly() {
fasand 0:68da41d2fe5c 297 uint8_t data[1] = { 0x01 };
fasand 0:68da41d2fe5c 298 enable_link_layer_mode_ongoing = true;
fasand 0:68da41d2fe5c 299 aciWriteConfigData(LL_WITHOUT_HOST_OFFSET, data);
fasand 0:68da41d2fe5c 300 }
fasand 0:68da41d2fe5c 301
fasand 0:68da41d2fe5c 302 void aciSetRole() {
fasand 0:68da41d2fe5c 303 // master and slave, simultaneous advertising and scanning
fasand 0:68da41d2fe5c 304 // (up to 4 connections)
fasand 0:68da41d2fe5c 305 uint8_t data[1] = { 0x04 };
fasand 0:68da41d2fe5c 306 aciWriteConfigData(ROLE_OFFSET, data);
fasand 0:68da41d2fe5c 307 }
fasand 0:68da41d2fe5c 308
fasand 0:68da41d2fe5c 309 void aciGattInit() {
fasand 0:68da41d2fe5c 310 uint8_t *pBuf = hciCmdAlloc(ACI_GATT_INIT_OPCODE, 0);
fasand 0:68da41d2fe5c 311 if (!pBuf) {
fasand 0:68da41d2fe5c 312 return;
fasand 0:68da41d2fe5c 313 }
fasand 0:68da41d2fe5c 314 hciCmdSend(pBuf);
fasand 0:68da41d2fe5c 315 }
fasand 0:68da41d2fe5c 316
fasand 0:68da41d2fe5c 317 void aciGapInit() {
fasand 0:68da41d2fe5c 318 uint8_t *pBuf = hciCmdAlloc(ACI_GAP_INIT_OPCODE, 3);
fasand 0:68da41d2fe5c 319 if (!pBuf) {
fasand 0:68da41d2fe5c 320 return;
fasand 0:68da41d2fe5c 321 }
fasand 0:68da41d2fe5c 322 pBuf[3] = 0xF;
fasand 0:68da41d2fe5c 323 pBuf[4] = 0;
fasand 0:68da41d2fe5c 324 pBuf[5] = 0;
fasand 0:68da41d2fe5c 325 hciCmdSend(pBuf);
fasand 0:68da41d2fe5c 326 }
fasand 0:68da41d2fe5c 327
fasand 0:68da41d2fe5c 328 void aciReadConfigParameter(uint8_t offset) {
fasand 0:68da41d2fe5c 329 uint8_t *pBuf = hciCmdAlloc(ACI_READ_CONFIG_DATA_OPCODE, 1);
fasand 0:68da41d2fe5c 330 if (!pBuf) {
fasand 0:68da41d2fe5c 331 return;
fasand 0:68da41d2fe5c 332 }
fasand 0:68da41d2fe5c 333
fasand 0:68da41d2fe5c 334 pBuf[3] = offset;
fasand 0:68da41d2fe5c 335 hciCmdSend(pBuf);
fasand 0:68da41d2fe5c 336 }
fasand 0:68da41d2fe5c 337
fasand 0:68da41d2fe5c 338 template<size_t N>
fasand 0:68da41d2fe5c 339 void aciWriteConfigData(uint8_t offset, uint8_t (&buf)[N]) {
fasand 0:68da41d2fe5c 340 uint8_t *pBuf = hciCmdAlloc(ACI_WRITE_CONFIG_DATA_OPCODE, 2 + N);
fasand 0:68da41d2fe5c 341 if (!pBuf) {
fasand 0:68da41d2fe5c 342 return;
fasand 0:68da41d2fe5c 343 }
fasand 0:68da41d2fe5c 344
fasand 0:68da41d2fe5c 345 pBuf[3] = offset;
fasand 0:68da41d2fe5c 346 pBuf[4] = N;
fasand 0:68da41d2fe5c 347 memcpy(pBuf + 5, buf, N);
fasand 0:68da41d2fe5c 348 hciCmdSend(pBuf);
fasand 0:68da41d2fe5c 349 }
fasand 0:68da41d2fe5c 350
fasand 0:68da41d2fe5c 351 void hciCoreReadResolvingListSize(void)
fasand 0:68da41d2fe5c 352 {
fasand 0:68da41d2fe5c 353 /* if LL Privacy is supported by Controller and included */
fasand 0:68da41d2fe5c 354 if ((hciCoreCb.leSupFeat & HCI_LE_SUP_FEAT_PRIVACY) &&
fasand 0:68da41d2fe5c 355 (hciLeSupFeatCfg & HCI_LE_SUP_FEAT_PRIVACY))
fasand 0:68da41d2fe5c 356 {
fasand 0:68da41d2fe5c 357 /* send next command in sequence */
fasand 0:68da41d2fe5c 358 HciLeReadResolvingListSize();
fasand 0:68da41d2fe5c 359 }
fasand 0:68da41d2fe5c 360 else
fasand 0:68da41d2fe5c 361 {
fasand 0:68da41d2fe5c 362 hciCoreCb.resListSize = 0;
fasand 0:68da41d2fe5c 363
fasand 0:68da41d2fe5c 364 /* send next command in sequence */
fasand 0:68da41d2fe5c 365 hciCoreReadMaxDataLen();
fasand 0:68da41d2fe5c 366 }
fasand 0:68da41d2fe5c 367 }
fasand 0:68da41d2fe5c 368
fasand 0:68da41d2fe5c 369 void hciCoreReadMaxDataLen(void)
fasand 0:68da41d2fe5c 370 {
fasand 0:68da41d2fe5c 371 /* if LE Data Packet Length Extensions is supported by Controller and included */
fasand 0:68da41d2fe5c 372 if ((hciCoreCb.leSupFeat & HCI_LE_SUP_FEAT_DATA_LEN_EXT) &&
fasand 0:68da41d2fe5c 373 (hciLeSupFeatCfg & HCI_LE_SUP_FEAT_DATA_LEN_EXT))
fasand 0:68da41d2fe5c 374 {
fasand 0:68da41d2fe5c 375 /* send next command in sequence */
fasand 0:68da41d2fe5c 376 HciLeReadMaxDataLen();
fasand 0:68da41d2fe5c 377 }
fasand 0:68da41d2fe5c 378 else
fasand 0:68da41d2fe5c 379 {
fasand 0:68da41d2fe5c 380 /* send next command in sequence */
fasand 0:68da41d2fe5c 381 HciLeRandCmd();
fasand 0:68da41d2fe5c 382 }
fasand 0:68da41d2fe5c 383 }
fasand 0:68da41d2fe5c 384
fasand 0:68da41d2fe5c 385 void bluenrg_reset() {
fasand 0:68da41d2fe5c 386 /* Reset BlueNRG SPI interface. Hold reset line to 0 for 1500ms */
fasand 0:68da41d2fe5c 387 rst = 0;
fasand 0:68da41d2fe5c 388 wait_us(1500);
fasand 0:68da41d2fe5c 389 rst = 1;
fasand 0:68da41d2fe5c 390
fasand 0:68da41d2fe5c 391 /* Wait for the radio to come back up */
fasand 0:68da41d2fe5c 392 wait_us(100000);
fasand 0:68da41d2fe5c 393 }
fasand 0:68da41d2fe5c 394
fasand 0:68da41d2fe5c 395 DigitalOut rst;
fasand 0:68da41d2fe5c 396 bool reset_received;
fasand 0:68da41d2fe5c 397 bool bluenrg_initialized;
fasand 0:68da41d2fe5c 398 bool enable_link_layer_mode_ongoing;
fasand 0:68da41d2fe5c 399 };
fasand 0:68da41d2fe5c 400
fasand 0:68da41d2fe5c 401 /**
fasand 0:68da41d2fe5c 402 * Transport driver of the ST BlueNRG shield.
fasand 0:68da41d2fe5c 403 * @important: With that driver, it is assumed that the SPI bus used is not shared
fasand 0:68da41d2fe5c 404 * with other SPI peripherals. The reasons behind this choice are simplicity and
fasand 0:68da41d2fe5c 405 * performance:
fasand 0:68da41d2fe5c 406 * - Reading from the peripheral SPI can be challenging especially if other
fasand 0:68da41d2fe5c 407 * threads access the same SPI bus. Indeed it is common that the function
fasand 0:68da41d2fe5c 408 * spiRead yield nothings even if the chip has signaled data with the irq
fasand 0:68da41d2fe5c 409 * line. Sharing would make the situation worse and increase the risk of
fasand 0:68da41d2fe5c 410 * timeout of HCI commands / response.
fasand 0:68da41d2fe5c 411 * - This driver can be used even if the RTOS is disabled or not present it may
fasand 0:68da41d2fe5c 412 * may be usefull for some targets.
fasand 0:68da41d2fe5c 413 *
fasand 0:68da41d2fe5c 414 * If The SPI is shared with other peripherals then the best option would be to
fasand 0:68da41d2fe5c 415 * handle SPI read in a real time thread woken up by an event flag.
fasand 0:68da41d2fe5c 416 *
fasand 0:68da41d2fe5c 417 * Other mechanisms might also be added in the future to handle data read as an
fasand 0:68da41d2fe5c 418 * event from the stack. This might not be the best solution for all BLE chip;
fasand 0:68da41d2fe5c 419 * especially this one.
fasand 0:68da41d2fe5c 420 */
fasand 0:68da41d2fe5c 421 class TransportDriver : public cordio::CordioHCITransportDriver {
fasand 0:68da41d2fe5c 422 public:
fasand 0:68da41d2fe5c 423 /**
fasand 0:68da41d2fe5c 424 * Construct the transport driver required by a BlueNRG module.
fasand 0:68da41d2fe5c 425 * @param mosi Pin of the SPI mosi
fasand 0:68da41d2fe5c 426 * @param miso Pin of the SPI miso
fasand 0:68da41d2fe5c 427 * @param sclk Pin of the SPI clock
fasand 0:68da41d2fe5c 428 * @param irq Pin used by the module to signal data are available.
fasand 0:68da41d2fe5c 429 */
fasand 0:68da41d2fe5c 430 TransportDriver(PinName mosi, PinName miso, PinName sclk, PinName ncs, PinName irq)
fasand 0:68da41d2fe5c 431 : spi(mosi, miso, sclk), nCS(ncs), irq(irq), _spi_thread(osPriorityNormal, SPI_STACK_SIZE, _spi_thread_stack) {
fasand 0:68da41d2fe5c 432 _spi_thread.start(callback(this, &TransportDriver::spi_read_cb));
fasand 0:68da41d2fe5c 433 }
fasand 0:68da41d2fe5c 434
fasand 0:68da41d2fe5c 435 virtual ~TransportDriver() { }
fasand 0:68da41d2fe5c 436
fasand 0:68da41d2fe5c 437 /**
fasand 0:68da41d2fe5c 438 * @see CordioHCITransportDriver::initialize
fasand 0:68da41d2fe5c 439 */
fasand 0:68da41d2fe5c 440 virtual void initialize() {
fasand 0:68da41d2fe5c 441 // Setup the spi for 8 bit data, low clock polarity,
fasand 0:68da41d2fe5c 442 // 1-edge phase, with an 8MHz clock rate
fasand 0:68da41d2fe5c 443 spi.format(8, 0);
fasand 0:68da41d2fe5c 444 spi.frequency(8000000);
fasand 0:68da41d2fe5c 445
fasand 0:68da41d2fe5c 446 // Deselect the BlueNRG chip by keeping its nCS signal high
fasand 0:68da41d2fe5c 447 nCS = 1;
fasand 0:68da41d2fe5c 448
fasand 0:68da41d2fe5c 449 wait_us(500);
fasand 0:68da41d2fe5c 450
fasand 0:68da41d2fe5c 451 // Set the interrupt handler for the device
fasand 0:68da41d2fe5c 452 irq.mode(PullDown); // set irq mode
fasand 0:68da41d2fe5c 453 irq.rise(callback(this, &TransportDriver::HCI_Isr));
fasand 0:68da41d2fe5c 454 }
fasand 0:68da41d2fe5c 455
fasand 0:68da41d2fe5c 456 /**
fasand 0:68da41d2fe5c 457 * @see CordioHCITransportDriver::terminate
fasand 0:68da41d2fe5c 458 */
fasand 0:68da41d2fe5c 459 virtual void terminate() { }
fasand 0:68da41d2fe5c 460
fasand 0:68da41d2fe5c 461 /**
fasand 0:68da41d2fe5c 462 * @see CordioHCITransportDriver::write
fasand 0:68da41d2fe5c 463 */
fasand 0:68da41d2fe5c 464 virtual uint16_t write(uint8_t type, uint16_t len, uint8_t *pData) {
fasand 0:68da41d2fe5c 465 // repeat write until successfull. A number of attempt or timeout might
fasand 0:68da41d2fe5c 466 // be useful
fasand 0:68da41d2fe5c 467 while (spiWrite(type, pData, len) == 0) { }
fasand 0:68da41d2fe5c 468 return len;
fasand 0:68da41d2fe5c 469 }
fasand 0:68da41d2fe5c 470
fasand 0:68da41d2fe5c 471 private:
fasand 0:68da41d2fe5c 472 uint16_t spiWrite(uint8_t type, const uint8_t* data, uint16_t data_length) {
fasand 0:68da41d2fe5c 473 static const uint8_t header_master[] = {
fasand 0:68da41d2fe5c 474 0x0A, 0x00, 0x00, 0x00, 0x00
fasand 0:68da41d2fe5c 475 };
fasand 0:68da41d2fe5c 476 uint8_t header_slave[] = { 0xaa, 0x00, 0x00, 0x00, 0x00 };
fasand 0:68da41d2fe5c 477 uint16_t data_written = 0;
fasand 0:68da41d2fe5c 478 uint16_t write_buffer_size = 0;
fasand 0:68da41d2fe5c 479
fasand 0:68da41d2fe5c 480 _spi_mutex.lock();
fasand 0:68da41d2fe5c 481
fasand 0:68da41d2fe5c 482 /* CS reset */
fasand 0:68da41d2fe5c 483 nCS = 0;
fasand 0:68da41d2fe5c 484
fasand 0:68da41d2fe5c 485 /* Exchange header */
fasand 0:68da41d2fe5c 486 for (uint8_t i = 0; i < sizeof(header_master); ++i) {
fasand 0:68da41d2fe5c 487 header_slave[i] = spi.write(header_master[i]);
fasand 0:68da41d2fe5c 488 }
fasand 0:68da41d2fe5c 489
fasand 0:68da41d2fe5c 490 if (header_slave[0] != 0x02) {
fasand 0:68da41d2fe5c 491 goto exit;
fasand 0:68da41d2fe5c 492 }
fasand 0:68da41d2fe5c 493
fasand 0:68da41d2fe5c 494 write_buffer_size = header_slave[2] << 8 | header_slave[1];
fasand 0:68da41d2fe5c 495
fasand 0:68da41d2fe5c 496 if (write_buffer_size == 0 || write_buffer_size < (data_length + 1)) {
fasand 0:68da41d2fe5c 497 goto exit;
fasand 0:68da41d2fe5c 498 }
fasand 0:68da41d2fe5c 499
fasand 0:68da41d2fe5c 500 spi.write(type);
fasand 0:68da41d2fe5c 501
fasand 0:68da41d2fe5c 502 data_written = data_length;
fasand 0:68da41d2fe5c 503 for (uint16_t i = 0; i < data_length; ++i) {
fasand 0:68da41d2fe5c 504 spi.write(data[i]);
fasand 0:68da41d2fe5c 505 }
fasand 0:68da41d2fe5c 506
fasand 0:68da41d2fe5c 507 exit:
fasand 0:68da41d2fe5c 508 nCS = 1;
fasand 0:68da41d2fe5c 509
fasand 0:68da41d2fe5c 510 _spi_mutex.unlock();
fasand 0:68da41d2fe5c 511
fasand 0:68da41d2fe5c 512 return data_written;
fasand 0:68da41d2fe5c 513 }
fasand 0:68da41d2fe5c 514
fasand 0:68da41d2fe5c 515 uint16_t spiRead(uint8_t* data_buffer, const uint16_t buffer_size)
fasand 0:68da41d2fe5c 516 {
fasand 0:68da41d2fe5c 517 static const uint8_t header_master[] = {0x0b, 0x00, 0x00, 0x00, 0x00};
fasand 0:68da41d2fe5c 518 uint8_t header_slave[5] = { 0xaa, 0x00, 0x00, 0x00, 0x00};
fasand 0:68da41d2fe5c 519 uint16_t read_length = 0;
fasand 0:68da41d2fe5c 520 uint16_t data_available = 0;
fasand 0:68da41d2fe5c 521
fasand 0:68da41d2fe5c 522 nCS = 0;
fasand 0:68da41d2fe5c 523
fasand 0:68da41d2fe5c 524 /* Read the header */
fasand 0:68da41d2fe5c 525 for (size_t i = 0; i < sizeof(header_master); i++) {
fasand 0:68da41d2fe5c 526 header_slave[i] = spi.write(header_master[i]);
fasand 0:68da41d2fe5c 527 }
fasand 0:68da41d2fe5c 528
fasand 0:68da41d2fe5c 529 if (header_slave[0] != 0x02) {
fasand 0:68da41d2fe5c 530 goto exit;
fasand 0:68da41d2fe5c 531 }
fasand 0:68da41d2fe5c 532
fasand 0:68da41d2fe5c 533 data_available = (header_slave[4] << 8) | header_slave[3];
fasand 0:68da41d2fe5c 534 read_length = data_available > buffer_size ? buffer_size : data_available;
fasand 0:68da41d2fe5c 535
fasand 0:68da41d2fe5c 536 for (uint16_t i = 0; i < read_length; ++i) {
fasand 0:68da41d2fe5c 537 data_buffer[i] = spi.write(0xFF);
fasand 0:68da41d2fe5c 538 }
fasand 0:68da41d2fe5c 539
fasand 0:68da41d2fe5c 540 exit:
fasand 0:68da41d2fe5c 541 nCS = 1;
fasand 0:68da41d2fe5c 542
fasand 0:68da41d2fe5c 543 return read_length;
fasand 0:68da41d2fe5c 544 }
fasand 0:68da41d2fe5c 545
fasand 0:68da41d2fe5c 546 /*
fasand 0:68da41d2fe5c 547 * might be split into two parts: the IRQ signaling a real time thread and
fasand 0:68da41d2fe5c 548 * the real time thread reading data from the SPI.
fasand 0:68da41d2fe5c 549 */
fasand 0:68da41d2fe5c 550 void HCI_Isr(void)
fasand 0:68da41d2fe5c 551 {
fasand 0:68da41d2fe5c 552 _spi_read_sem.release();
fasand 0:68da41d2fe5c 553 }
fasand 0:68da41d2fe5c 554
fasand 0:68da41d2fe5c 555 void spi_read_cb() {
fasand 0:68da41d2fe5c 556 uint8_t data_buffer[256];
fasand 0:68da41d2fe5c 557 while(true) {
fasand 0:68da41d2fe5c 558 _spi_read_sem.wait();
fasand 0:68da41d2fe5c 559
fasand 0:68da41d2fe5c 560 _spi_mutex.lock();
fasand 0:68da41d2fe5c 561 while(irq == 1) {
fasand 0:68da41d2fe5c 562 uint16_t data_read = spiRead(data_buffer, sizeof(data_buffer));
fasand 0:68da41d2fe5c 563 on_data_received(data_buffer, data_read);
fasand 0:68da41d2fe5c 564 }
fasand 0:68da41d2fe5c 565 _spi_mutex.unlock();
fasand 0:68da41d2fe5c 566 }
fasand 0:68da41d2fe5c 567 }
fasand 0:68da41d2fe5c 568
fasand 0:68da41d2fe5c 569 /**
fasand 0:68da41d2fe5c 570 * Unsafe SPI, does not lock when SPI access happens.
fasand 0:68da41d2fe5c 571 */
fasand 0:68da41d2fe5c 572 ::mbed::SPI spi;
fasand 0:68da41d2fe5c 573 DigitalOut nCS;
fasand 0:68da41d2fe5c 574 InterruptIn irq;
fasand 0:68da41d2fe5c 575 rtos::Thread _spi_thread;
fasand 0:68da41d2fe5c 576 uint8_t _spi_thread_stack[SPI_STACK_SIZE];
fasand 0:68da41d2fe5c 577 rtos::Semaphore _spi_read_sem;
fasand 0:68da41d2fe5c 578 rtos::Mutex _spi_mutex;
fasand 0:68da41d2fe5c 579 };
fasand 0:68da41d2fe5c 580
fasand 0:68da41d2fe5c 581 } // namespace bluenrg
fasand 0:68da41d2fe5c 582 } // namespace vendor
fasand 0:68da41d2fe5c 583 } // namespace ble
fasand 0:68da41d2fe5c 584
fasand 0:68da41d2fe5c 585 /**
fasand 0:68da41d2fe5c 586 * Cordio HCI driver factory
fasand 0:68da41d2fe5c 587 */
fasand 0:68da41d2fe5c 588 ble::vendor::cordio::CordioHCIDriver& ble_cordio_get_hci_driver() {
fasand 0:68da41d2fe5c 589 static ble::vendor::bluenrg::TransportDriver transport_driver(
fasand 0:68da41d2fe5c 590 BLUENRG_PIN_SPI_MOSI,
fasand 0:68da41d2fe5c 591 BLUENRG_PIN_SPI_MISO,
fasand 0:68da41d2fe5c 592 BLUENRG_PIN_SPI_SCK,
fasand 0:68da41d2fe5c 593 BLUENRG_PIN_SPI_nCS,
fasand 0:68da41d2fe5c 594 BLUENRG_PIN_SPI_IRQ
fasand 0:68da41d2fe5c 595 );
fasand 0:68da41d2fe5c 596 static ble::vendor::bluenrg::HCIDriver hci_driver(
fasand 0:68da41d2fe5c 597 transport_driver,
fasand 0:68da41d2fe5c 598 BLUENRG_PIN_SPI_RESET
fasand 0:68da41d2fe5c 599 );
fasand 0:68da41d2fe5c 600 return hci_driver;
fasand 0:68da41d2fe5c 601 }