Glimworm Beacons / nRF51822

Fork of nRF51822 by Nordic Semiconductor

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers nRF5xGap.cpp Source File

nRF5xGap.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include "nRF5xGap.h"
00018 #include "mbed.h"
00019 
00020 #include "common/common.h"
00021 #include "ble_advdata.h "
00022 #include "ble_hci.h"
00023 
00024 nRF5xGap &nRF5xGap::getInstance() {
00025     static nRF5xGap m_instance;
00026     return m_instance;
00027 }
00028 
00029 void radioNotificationStaticCallback(bool param) {
00030     nRF5xGap::getInstance().processRadioNotificationEvent(param);
00031 }
00032 
00033 /**************************************************************************/
00034 /*!
00035     @brief  Sets the advertising parameters and payload for the device
00036 
00037     @param[in]  params
00038                 Basic advertising details, including the advertising
00039                 delay, timeout and how the device should be advertised
00040     @params[in] advData
00041                 The primary advertising data payload
00042     @params[in] scanResponse
00043                 The optional Scan Response payload if the advertising
00044                 type is set to \ref GapAdvertisingParams::ADV_SCANNABLE_UNDIRECTED
00045                 in \ref GapAdveritinngParams
00046 
00047     @returns    \ref ble_error_t
00048 
00049     @retval     BLE_ERROR_NONE
00050                 Everything executed properly
00051 
00052     @retval     BLE_ERROR_BUFFER_OVERFLOW
00053                 The proposed action would cause a buffer overflow.  All
00054                 advertising payloads must be <= 31 bytes, for example.
00055 
00056     @retval     BLE_ERROR_NOT_IMPLEMENTED
00057                 A feature was requested that is not yet supported in the
00058                 nRF51 firmware or hardware.
00059 
00060     @retval     BLE_ERROR_PARAM_OUT_OF_RANGE
00061                 One of the proposed values is outside the valid range.
00062 
00063     @section EXAMPLE
00064 
00065     @code
00066 
00067     @endcode
00068 */
00069 /**************************************************************************/
00070 ble_error_t nRF5xGap::setAdvertisingData(const GapAdvertisingData &advData, const GapAdvertisingData &scanResponse)
00071 {
00072     /* Make sure we don't exceed the advertising payload length */
00073     if (advData.getPayloadLen() > GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
00074         return BLE_ERROR_BUFFER_OVERFLOW;
00075     }
00076 
00077     /* Make sure we have a payload! */
00078     if (advData.getPayloadLen() == 0) {
00079         return BLE_ERROR_PARAM_OUT_OF_RANGE;
00080     }
00081 
00082     /* Check the scan response payload limits */
00083     //if ((params.getAdvertisingType() == GapAdvertisingParams::ADV_SCANNABLE_UNDIRECTED))
00084     //{
00085     //    /* Check if we're within the upper limit */
00086     //    if (advData.getPayloadLen() > GAP_ADVERTISING_DATA_MAX_PAYLOAD)
00087     //    {
00088     //        return BLE_ERROR_BUFFER_OVERFLOW;
00089     //    }
00090     //    /* Make sure we have a payload! */
00091     //    if (advData.getPayloadLen() == 0)
00092     //    {
00093     //        return BLE_ERROR_PARAM_OUT_OF_RANGE;
00094     //    }
00095     //}
00096 
00097     /* Send advertising data! */
00098     ASSERT(ERROR_NONE ==
00099            sd_ble_gap_adv_data_set(advData.getPayload(),
00100                                    advData.getPayloadLen(),
00101                                    scanResponse.getPayload(),
00102                                    scanResponse.getPayloadLen()),
00103            BLE_ERROR_PARAM_OUT_OF_RANGE);
00104 
00105     /* Make sure the GAP Service appearance value is aligned with the
00106      *appearance from GapAdvertisingData */
00107     ASSERT(ERROR_NONE == sd_ble_gap_appearance_set(advData.getAppearance()),
00108            BLE_ERROR_PARAM_OUT_OF_RANGE);
00109 
00110     /* ToDo: Perform some checks on the payload, for example the Scan Response can't */
00111     /* contains a flags AD type, etc. */
00112 
00113     return BLE_ERROR_NONE;
00114 }
00115 
00116 /**************************************************************************/
00117 /*!
00118     @brief  Starts the BLE HW, initialising any services that were
00119             added before this function was called.
00120 
00121     @note   All services must be added before calling this function!
00122 
00123     @returns    ble_error_t
00124 
00125     @retval     BLE_ERROR_NONE
00126                 Everything executed properly
00127 
00128     @section EXAMPLE
00129 
00130     @code
00131 
00132     @endcode
00133 */
00134 /**************************************************************************/
00135 ble_error_t nRF5xGap::startAdvertising(const GapAdvertisingParams &params)
00136 {
00137     /* Make sure we support the advertising type */
00138     if (params.getAdvertisingType() == GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) {
00139         /* ToDo: This requires a propery security implementation, etc. */
00140         return BLE_ERROR_NOT_IMPLEMENTED;
00141     }
00142 
00143     /* Check interval range */
00144     if (params.getAdvertisingType() == GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED) {
00145         /* Min delay is slightly longer for unconnectable devices */
00146         if ((params.getIntervalInADVUnits() < GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MIN_NONCON) ||
00147             (params.getIntervalInADVUnits() > GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MAX)) {
00148             return BLE_ERROR_PARAM_OUT_OF_RANGE;
00149         }
00150     } else {
00151         if ((params.getIntervalInADVUnits() < GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MIN) ||
00152             (params.getIntervalInADVUnits() > GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MAX)) {
00153             return BLE_ERROR_PARAM_OUT_OF_RANGE;
00154         }
00155     }
00156 
00157     /* Check timeout is zero for Connectable Directed */
00158     if ((params.getAdvertisingType() == GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) && (params.getTimeout() != 0)) {
00159         /* Timeout must be 0 with this type, although we'll never get here */
00160         /* since this isn't implemented yet anyway */
00161         return BLE_ERROR_PARAM_OUT_OF_RANGE;
00162     }
00163 
00164     /* Check timeout for other advertising types */
00165     if ((params.getAdvertisingType() != GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) &&
00166         (params.getTimeout() > GapAdvertisingParams::GAP_ADV_PARAMS_TIMEOUT_MAX)) {
00167         return BLE_ERROR_PARAM_OUT_OF_RANGE;
00168     }
00169 
00170     /* Start Advertising */
00171     ble_gap_adv_params_t adv_para = {0};
00172 
00173     adv_para.type        = params.getAdvertisingType();
00174     adv_para.p_peer_addr = NULL;                           // Undirected advertisement
00175     adv_para.fp          = BLE_GAP_ADV_FP_ANY;
00176     adv_para.p_whitelist = NULL;
00177     adv_para.interval    = params.getIntervalInADVUnits(); // advertising interval (in units of 0.625 ms)
00178     adv_para.timeout     = params.getTimeout();
00179 
00180     ASSERT(ERROR_NONE == sd_ble_gap_adv_start(&adv_para), BLE_ERROR_PARAM_OUT_OF_RANGE);
00181 
00182     state.advertising = 1;
00183 
00184     return BLE_ERROR_NONE;
00185 }
00186 
00187 /**************************************************************************/
00188 /*!
00189     @brief  Stops the BLE HW and disconnects from any devices
00190 
00191     @returns    ble_error_t
00192 
00193     @retval     BLE_ERROR_NONE
00194                 Everything executed properly
00195 
00196     @section EXAMPLE
00197 
00198     @code
00199 
00200     @endcode
00201 */
00202 /**************************************************************************/
00203 ble_error_t nRF5xGap::stopAdvertising(void)
00204 {
00205     /* Stop Advertising */
00206     ASSERT(ERROR_NONE == sd_ble_gap_adv_stop(), BLE_ERROR_PARAM_OUT_OF_RANGE);
00207 
00208     state.advertising = 0;
00209 
00210     return BLE_ERROR_NONE;
00211 }
00212 
00213 ble_error_t nRF5xGap::connect(const Address_t           peerAddr,
00214                               Gap::AddressType_t        peerAddrType,
00215                               const ConnectionParams_t *connectionParams,
00216                               const GapScanningParams  *scanParamsIn)
00217 {
00218     ble_gap_addr_t addr;
00219     addr.addr_type = peerAddrType;
00220     memcpy(addr.addr, peerAddr, Gap::ADDR_LEN);
00221 
00222     ble_gap_conn_params_t connParams;
00223     if (connectionParams != NULL) {
00224         connParams.min_conn_interval = connectionParams->minConnectionInterval;
00225         connParams.max_conn_interval = connectionParams->maxConnectionInterval;
00226         connParams.slave_latency     = connectionParams->slaveLatency;
00227         connParams.conn_sup_timeout  = connectionParams->connectionSupervisionTimeout;
00228     } else {
00229         connParams.min_conn_interval = 50;
00230         connParams.max_conn_interval = 100;
00231         connParams.slave_latency     = 0;
00232         connParams.conn_sup_timeout  = 600;
00233     }
00234 
00235     ble_gap_scan_params_t scanParams;
00236     scanParams.active      = 0;    /**< If 1, perform active scanning (scan requests). */
00237     scanParams.selective   = 0;    /**< If 1, ignore unknown devices (non whitelisted). */
00238     scanParams.p_whitelist = NULL; /**< Pointer to whitelist, NULL if none is given. */
00239     if (scanParamsIn != NULL) {
00240         scanParams.interval    = scanParamsIn->getInterval(); /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */
00241         scanParams.window      = scanParamsIn->getWindow();   /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */
00242         scanParams.timeout     = scanParamsIn->getTimeout();  /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */
00243     } else {
00244         scanParams.interval    = 500; /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */
00245         scanParams.window      = 200;   /**< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */
00246         scanParams.timeout     = 0;  /**< Scan timeout between 0x0001 and 0xFFFF in seconds, 0x0000 disables timeout. */
00247     }
00248 
00249     uint32_t rc = sd_ble_gap_connect(&addr, &scanParams, &connParams);
00250     if (rc == NRF_SUCCESS) {
00251         return BLE_ERROR_NONE;
00252     }
00253     switch (rc) {
00254         case NRF_ERROR_INVALID_ADDR:
00255             return BLE_ERROR_INVALID_PARAM;
00256         case NRF_ERROR_INVALID_PARAM:
00257             return BLE_ERROR_INVALID_PARAM;
00258         case NRF_ERROR_INVALID_STATE:
00259             return BLE_ERROR_INVALID_STATE;
00260         case BLE_ERROR_GAP_INVALID_BLE_ADDR:
00261             return BLE_ERROR_INVALID_PARAM;
00262         case NRF_ERROR_NO_MEM:
00263             return BLE_ERROR_NO_MEM;
00264         case NRF_ERROR_BUSY:
00265             return BLE_STACK_BUSY;
00266         default:
00267         case BLE_ERROR_GAP_WHITELIST_IN_USE:
00268             return BLE_ERROR_UNSPECIFIED;
00269     }
00270 }
00271 
00272 ble_error_t nRF5xGap::disconnect(Handle_t connectionHandle, DisconnectionReason_t reason)
00273 {
00274     state.advertising = 0;
00275     state.connected   = 0;
00276 
00277     uint8_t code = BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION;
00278     switch (reason) {
00279         case REMOTE_USER_TERMINATED_CONNECTION:
00280             code = BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION;
00281             break;
00282         case CONN_INTERVAL_UNACCEPTABLE:
00283             code = BLE_HCI_CONN_INTERVAL_UNACCEPTABLE;
00284             break;
00285         default:
00286             break;
00287     }
00288 
00289     /* Disconnect if we are connected to a central device */
00290     ASSERT_INT(ERROR_NONE, sd_ble_gap_disconnect(connectionHandle, code), BLE_ERROR_PARAM_OUT_OF_RANGE);
00291 
00292     return BLE_ERROR_NONE;
00293 }
00294 
00295 /*!
00296     @brief  Disconnects if we are connected to a central device
00297 
00298     @returns    ble_error_t
00299 
00300     @retval     BLE_ERROR_NONE
00301                 Everything executed properly
00302 */
00303 ble_error_t nRF5xGap::disconnect(DisconnectionReason_t reason)
00304 {
00305     return disconnect(m_connectionHandle, reason);
00306 }
00307 
00308 ble_error_t nRF5xGap::getPreferredConnectionParams(ConnectionParams_t *params)
00309 {
00310     ASSERT_INT(NRF_SUCCESS,
00311         sd_ble_gap_ppcp_get(reinterpret_cast<ble_gap_conn_params_t *>(params)),
00312         BLE_ERROR_PARAM_OUT_OF_RANGE);
00313 
00314     return BLE_ERROR_NONE;
00315 }
00316 
00317 ble_error_t nRF5xGap::setPreferredConnectionParams(const ConnectionParams_t *params)
00318 {
00319     ASSERT_INT(NRF_SUCCESS,
00320         sd_ble_gap_ppcp_set(reinterpret_cast<const ble_gap_conn_params_t *>(params)),
00321         BLE_ERROR_PARAM_OUT_OF_RANGE);
00322 
00323     return BLE_ERROR_NONE;
00324 }
00325 
00326 ble_error_t nRF5xGap::updateConnectionParams(Handle_t handle, const ConnectionParams_t *newParams)
00327 {
00328     uint32_t rc;
00329 
00330     rc = sd_ble_gap_conn_param_update(handle, reinterpret_cast<ble_gap_conn_params_t *>(const_cast<ConnectionParams_t*>(newParams)));
00331     if (rc == NRF_SUCCESS) {
00332         return BLE_ERROR_NONE;
00333     } else {
00334         return BLE_ERROR_PARAM_OUT_OF_RANGE;
00335     }
00336 }
00337 
00338 /**************************************************************************/
00339 /*!
00340     @brief  Sets the 16-bit connection handle
00341 */
00342 /**************************************************************************/
00343 void nRF5xGap::setConnectionHandle(uint16_t con_handle)
00344 {
00345     m_connectionHandle = con_handle;
00346 }
00347 
00348 /**************************************************************************/
00349 /*!
00350     @brief  Gets the 16-bit connection handle
00351 */
00352 /**************************************************************************/
00353 uint16_t nRF5xGap::getConnectionHandle(void)
00354 {
00355     return m_connectionHandle;
00356 }
00357 
00358 /**************************************************************************/
00359 /*!
00360     @brief      Sets the BLE device address
00361 
00362     @returns    ble_error_t
00363 
00364     @section EXAMPLE
00365 
00366     @code
00367 
00368     uint8_t device_address[6] = { 0xca, 0xfe, 0xf0, 0xf0, 0xf0, 0xf0 };
00369     nrf.getGap().setAddress(Gap::ADDR_TYPE_RANDOM_STATIC, device_address);
00370 
00371     @endcode
00372 */
00373 /**************************************************************************/
00374 ble_error_t nRF5xGap::setAddress(AddressType_t type, const Address_t address)
00375 {
00376     if (type > ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE) {
00377         return BLE_ERROR_PARAM_OUT_OF_RANGE;
00378     }
00379 
00380     ble_gap_addr_t dev_addr;
00381     dev_addr.addr_type = type;
00382     memcpy(dev_addr.addr, address, ADDR_LEN);
00383 
00384     ASSERT_INT(ERROR_NONE, sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &dev_addr), BLE_ERROR_PARAM_OUT_OF_RANGE);
00385 
00386     return BLE_ERROR_NONE;
00387 }
00388 
00389 ble_error_t nRF5xGap::getAddress(AddressType_t *typeP, Address_t address)
00390 {
00391     ble_gap_addr_t dev_addr;
00392     if (sd_ble_gap_address_get(&dev_addr) != NRF_SUCCESS) {
00393         return BLE_ERROR_PARAM_OUT_OF_RANGE;
00394     }
00395 
00396     if (typeP != NULL) {
00397         *typeP = static_cast<AddressType_t>(dev_addr.addr_type);
00398     }
00399     if (address != NULL) {
00400         memcpy(address, dev_addr.addr, ADDR_LEN);
00401     }
00402     return BLE_ERROR_NONE;
00403 }
00404 
00405 ble_error_t nRF5xGap::setDeviceName(const uint8_t *deviceName)
00406 {
00407     ble_gap_conn_sec_mode_t sec_mode;
00408     BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); // no security is needed
00409 
00410     if (sd_ble_gap_device_name_set(&sec_mode, deviceName, strlen((const char *)deviceName)) == NRF_SUCCESS) {
00411         return BLE_ERROR_NONE;
00412     } else {
00413         return BLE_ERROR_PARAM_OUT_OF_RANGE;
00414     }
00415 }
00416 
00417 ble_error_t nRF5xGap::getDeviceName(uint8_t *deviceName, unsigned *lengthP)
00418 {
00419     if (sd_ble_gap_device_name_get(deviceName, (uint16_t *)lengthP) == NRF_SUCCESS) {
00420         return BLE_ERROR_NONE;
00421     } else {
00422         return BLE_ERROR_PARAM_OUT_OF_RANGE;
00423     }
00424 }
00425 
00426 ble_error_t nRF5xGap::setAppearance(GapAdvertisingData::Appearance appearance)
00427 {
00428     if (sd_ble_gap_appearance_set(appearance) == NRF_SUCCESS) {
00429         return BLE_ERROR_NONE;
00430     } else {
00431         return BLE_ERROR_PARAM_OUT_OF_RANGE;
00432     }
00433 }
00434 
00435 ble_error_t nRF5xGap::getAppearance(GapAdvertisingData::Appearance *appearanceP)
00436 {
00437     if ((sd_ble_gap_appearance_get(reinterpret_cast<uint16_t *>(appearanceP)) == NRF_SUCCESS)) {
00438         return BLE_ERROR_NONE;
00439     } else {
00440         return BLE_ERROR_PARAM_OUT_OF_RANGE;
00441     }
00442 }
00443 
00444 /* (Valid values are -40, -20, -16, -12, -8, -4, 0, 4) */
00445 ble_error_t nRF5xGap::setTxPower(int8_t txPower)
00446 {
00447     unsigned rc;
00448     if ((rc = sd_ble_gap_tx_power_set(txPower)) != NRF_SUCCESS) {
00449         switch (rc) {
00450             case NRF_ERROR_BUSY:
00451                 return BLE_STACK_BUSY;
00452             case NRF_ERROR_INVALID_PARAM:
00453             default:
00454                 return BLE_ERROR_PARAM_OUT_OF_RANGE;
00455         }
00456     }
00457 
00458     return BLE_ERROR_NONE;
00459 }
00460 
00461 void nRF5xGap::getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP)
00462 {
00463     static const int8_t permittedTxValues[] = {
00464         -40, -30, -20, -16, -12, -8, -4, 0, 4
00465     };
00466 
00467     *valueArrayPP = permittedTxValues;
00468     *countP = sizeof(permittedTxValues) / sizeof(int8_t);
00469 }