test

Fork of nRF51822 by Nordic Semiconductor

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ble_conn_params.cpp Source File

ble_conn_params.cpp

00001 /*
00002  * Copyright (c) Nordic Semiconductor ASA
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without modification,
00006  * are permitted provided that the following conditions are met:
00007  *
00008  *   1. Redistributions of source code must retain the above copyright notice, this
00009  *   list of conditions and the following disclaimer.
00010  *
00011  *   2. Redistributions in binary form must reproduce the above copyright notice, this
00012  *   list of conditions and the following disclaimer in the documentation and/or
00013  *   other materials provided with the distribution.
00014  *
00015  *   3. Neither the name of Nordic Semiconductor ASA nor the names of other
00016  *   contributors to this software may be used to endorse or promote products
00017  *   derived from this software without specific prior written permission.
00018  *
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00021  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00022  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00023  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
00024  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00025  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00026  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00027  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00028  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00029  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030  *
00031  */
00032 
00033 #include "ble_conn_params.h "
00034 #include <stdlib.h>
00035 #include "nordic_common.h"
00036 #include "ble_hci.h"
00037 #include "ble_srv_common.h "
00038 #include "app_util.h"
00039 
00040 #ifdef USE_APP_TIMER
00041 #include "app_timer.h"
00042 #else
00043 #include "mbed.h"
00044 #endif
00045 
00046 static ble_conn_params_init_t m_conn_params_config;     /**< Configuration as specified by the application. */
00047 static ble_gap_conn_params_t  m_preferred_conn_params;  /**< Connection parameters preferred by the application. */
00048 static uint8_t                m_update_count;           /**< Number of Connection Parameter Update messages that has currently been sent. */
00049 static uint16_t               m_conn_handle;            /**< Current connection handle. */
00050 static ble_gap_conn_params_t  m_current_conn_params;    /**< Connection parameters received in the most recent Connect event. */
00051 #ifdef USE_APP_TIMER
00052 static app_timer_id_t         m_conn_params_timer_id;   /**< Connection parameters timer. */
00053 #else
00054 static Ticker                 m_conn_params_timer;
00055 #endif
00056 
00057 static bool m_change_param = false;
00058 
00059 static bool is_conn_params_ok(ble_gap_conn_params_t * p_conn_params)
00060 {
00061     // Check if interval is within the acceptable range.
00062     // NOTE: Using max_conn_interval in the received event data because this contains
00063     //       the client's connection interval.
00064     if (
00065         (p_conn_params->max_conn_interval >= m_preferred_conn_params.min_conn_interval)
00066         && 
00067         (p_conn_params->max_conn_interval <= m_preferred_conn_params.max_conn_interval)
00068        )
00069     {
00070         return true;
00071     }
00072     else
00073     {
00074         return false;
00075     }
00076 }
00077 
00078 
00079 #ifdef USE_APP_TIMER
00080 static void update_timeout_handler(void * p_context)
00081 {
00082     UNUSED_PARAMETER(p_context);
00083 
00084 #else /* #if !USE_APP_TIMER */
00085 static void update_timeout_handler(void)
00086 {
00087     m_conn_params_timer.detach(); /* this is supposed to be a single-shot timer callback */
00088 #endif /* #if !USE_APP_TIMER */
00089     if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
00090     {
00091         // Check if we have reached the maximum number of attempts
00092         m_update_count++;
00093         if (m_update_count <= m_conn_params_config.max_conn_params_update_count)
00094         {
00095             uint32_t err_code;
00096 
00097             // Parameters are not ok, send connection parameters update request.
00098             err_code = sd_ble_gap_conn_param_update(m_conn_handle, &m_preferred_conn_params);
00099             if ((err_code != NRF_SUCCESS) && (m_conn_params_config.error_handler != NULL))
00100             {
00101                 m_conn_params_config.error_handler(err_code);
00102             }
00103         }
00104         else
00105         {
00106             m_update_count = 0;
00107 
00108             // Negotiation failed, disconnect automatically if this has been configured
00109             if (m_conn_params_config.disconnect_on_fail)
00110             {
00111                 uint32_t err_code;
00112 
00113                 err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
00114                 if ((err_code != NRF_SUCCESS) && (m_conn_params_config.error_handler != NULL))
00115                 {
00116                     m_conn_params_config.error_handler(err_code);
00117                 }
00118             }
00119 
00120             // Notify the application that the procedure has failed
00121             if (m_conn_params_config.evt_handler != NULL)
00122             {
00123                 ble_conn_params_evt_t evt;
00124 
00125                 evt.evt_type = BLE_CONN_PARAMS_EVT_FAILED;
00126                 m_conn_params_config.evt_handler(&evt);
00127             }
00128         }
00129     }
00130 }
00131 
00132 
00133 uint32_t ble_conn_params_init(const ble_conn_params_init_t * p_init)
00134 {
00135     uint32_t err_code;
00136 
00137     m_conn_params_config = *p_init;
00138     m_change_param = false;
00139     if (p_init->p_conn_params != NULL)
00140     {
00141         m_preferred_conn_params = *p_init->p_conn_params;
00142 
00143         // Set the connection params in stack
00144         err_code = sd_ble_gap_ppcp_set(&m_preferred_conn_params);
00145         if (err_code != NRF_SUCCESS)
00146         {
00147             return err_code;
00148         }
00149     }
00150     else
00151     {
00152         // Fetch the connection params from stack
00153         err_code = sd_ble_gap_ppcp_get(&m_preferred_conn_params);
00154         if (err_code != NRF_SUCCESS)
00155         {
00156             return err_code;
00157         }
00158     }
00159 
00160     m_conn_handle  = BLE_CONN_HANDLE_INVALID;
00161     m_update_count = 0;
00162 
00163 #ifdef USE_APP_TIMER
00164     return app_timer_create(&m_conn_params_timer_id,
00165                             APP_TIMER_MODE_SINGLE_SHOT,
00166                             update_timeout_handler);
00167 #else
00168     return NRF_SUCCESS;
00169 #endif
00170 }
00171 
00172 
00173 uint32_t ble_conn_params_stop(void)
00174 {
00175 #ifdef USE_APP_TIMER
00176     return app_timer_stop(m_conn_params_timer_id);
00177 #else /* #if !USE_APP_TIMER */
00178     m_conn_params_timer.detach();
00179     return NRF_SUCCESS;
00180 #endif /* #if !USE_APP_TIMER */
00181 }
00182 
00183 
00184 static void conn_params_negotiation(void)
00185 {
00186     // Start negotiation if the received connection parameters are not acceptable
00187     if (!is_conn_params_ok(&m_current_conn_params))
00188     {
00189 #ifdef USE_APP_TIMER
00190         uint32_t err_code;
00191 #endif
00192         uint32_t timeout_ticks;
00193 
00194         if (m_change_param)
00195         {
00196             // Notify the application that the procedure has failed
00197             if (m_conn_params_config.evt_handler != NULL)
00198             {
00199                 ble_conn_params_evt_t evt;
00200 
00201                 evt.evt_type = BLE_CONN_PARAMS_EVT_FAILED;
00202                 m_conn_params_config.evt_handler(&evt);
00203             }
00204         }
00205         else
00206         {
00207             if (m_update_count == 0)
00208             {
00209                 // First connection parameter update
00210                 timeout_ticks = m_conn_params_config.first_conn_params_update_delay;
00211             }
00212             else
00213             {
00214                 timeout_ticks = m_conn_params_config.next_conn_params_update_delay;
00215             }
00216 
00217 #ifdef USE_APP_TIMER
00218             err_code = app_timer_start(m_conn_params_timer_id, timeout_ticks, NULL);
00219             if ((err_code != NRF_SUCCESS) && (m_conn_params_config.error_handler != NULL))
00220             {
00221                 m_conn_params_config.error_handler(err_code);
00222             }
00223 #else
00224             m_conn_params_timer.attach(update_timeout_handler, timeout_ticks / 32768);
00225 #endif
00226         }
00227     }
00228     else
00229     {
00230         // Notify the application that the procedure has succeded
00231         if (m_conn_params_config.evt_handler != NULL)
00232         {
00233             ble_conn_params_evt_t evt;
00234 
00235             evt.evt_type = BLE_CONN_PARAMS_EVT_SUCCEEDED;
00236             m_conn_params_config.evt_handler(&evt);
00237         }
00238     }
00239     m_change_param = false;
00240 }
00241 
00242 
00243 static void on_connect(ble_evt_t * p_ble_evt)
00244 {
00245     // Save connection parameters
00246     m_conn_handle         = p_ble_evt->evt.gap_evt.conn_handle;
00247     m_current_conn_params = p_ble_evt->evt.gap_evt.params.connected.conn_params;
00248     m_update_count        = 0;  // Connection parameter negotiation should re-start every connection
00249 
00250     // Check if we shall handle negotiation on connect
00251     if (m_conn_params_config.start_on_notify_cccd_handle == BLE_GATT_HANDLE_INVALID)
00252     {
00253         conn_params_negotiation();
00254     }
00255 }
00256 
00257 
00258 static void on_disconnect(ble_evt_t * p_ble_evt)
00259 {
00260 #ifdef USE_APP_TIMER
00261     uint32_t err_code;
00262 #endif
00263 
00264     m_conn_handle = BLE_CONN_HANDLE_INVALID;
00265 
00266     // Stop timer if running
00267     m_update_count = 0; // Connection parameters updates should happen during every connection
00268 
00269 #ifdef USE_APP_TIMER
00270     err_code = app_timer_stop(m_conn_params_timer_id);
00271     if ((err_code != NRF_SUCCESS) && (m_conn_params_config.error_handler != NULL))
00272     {
00273         m_conn_params_config.error_handler(err_code);
00274     }
00275 #else
00276     m_conn_params_timer.detach();
00277 #endif
00278 }
00279 
00280 
00281 static void on_write(ble_evt_t * p_ble_evt)
00282 {
00283     ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
00284 
00285     // Check if this the correct CCCD
00286     if (
00287         (p_evt_write->handle == m_conn_params_config.start_on_notify_cccd_handle)
00288         &&
00289         (p_evt_write->len == 2)
00290        )
00291     {
00292         // Check if this is a 'start notification'
00293         if (ble_srv_is_notification_enabled(p_evt_write->data))
00294         {
00295             // Do connection parameter negotiation if necessary
00296             conn_params_negotiation();
00297         }
00298         else
00299         {
00300 #ifdef USE_APP_TIMER
00301             uint32_t err_code;
00302 
00303             // Stop timer if running
00304             err_code = app_timer_stop(m_conn_params_timer_id);
00305             if ((err_code != NRF_SUCCESS) && (m_conn_params_config.error_handler != NULL))
00306             {
00307                 m_conn_params_config.error_handler(err_code);
00308             }
00309 #else /* #if !USE_APP_TIMER */
00310             m_conn_params_timer.detach();
00311 #endif /* #if !USE_APP_TIMER */
00312         }
00313     }
00314 }
00315 
00316 
00317 static void on_conn_params_update(ble_evt_t * p_ble_evt)
00318 {
00319     // Copy the parameters
00320     m_current_conn_params = p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params;
00321 
00322     conn_params_negotiation();
00323 }
00324 
00325 
00326 void ble_conn_params_on_ble_evt(ble_evt_t * p_ble_evt)
00327 {
00328     switch (p_ble_evt->header.evt_id)
00329     {
00330         case BLE_GAP_EVT_CONNECTED:
00331             on_connect(p_ble_evt);
00332             break;
00333 
00334         case BLE_GAP_EVT_DISCONNECTED:
00335             on_disconnect(p_ble_evt);
00336             break;
00337 
00338         case BLE_GATTS_EVT_WRITE:
00339             on_write(p_ble_evt);
00340             break;
00341 
00342         case BLE_GAP_EVT_CONN_PARAM_UPDATE:
00343             on_conn_params_update(p_ble_evt);
00344             break;
00345 
00346         default:
00347             // No implementation needed.
00348             break;
00349     }
00350 }
00351 
00352 uint32_t ble_conn_params_change_conn_params(ble_gap_conn_params_t *new_params)
00353 {
00354     uint32_t err_code;
00355 
00356     m_preferred_conn_params = *new_params;
00357     // Set the connection params in stack
00358     err_code = sd_ble_gap_ppcp_set(&m_preferred_conn_params);
00359     if (err_code == NRF_SUCCESS)
00360     {
00361         if (!is_conn_params_ok(&m_current_conn_params))
00362         {
00363             m_change_param = true;
00364             err_code = sd_ble_gap_conn_param_update(m_conn_handle, &m_preferred_conn_params);
00365             m_update_count = 1;
00366         }
00367         else
00368         {
00369             // Notify the application that the procedure has succeded
00370             if (m_conn_params_config.evt_handler != NULL)
00371             {
00372                 ble_conn_params_evt_t evt;
00373 
00374                 evt.evt_type = BLE_CONN_PARAMS_EVT_SUCCEEDED;
00375                 m_conn_params_config.evt_handler(&evt);
00376             }
00377             err_code = NRF_SUCCESS;
00378         }
00379     }
00380     return err_code;
00381 }