Fawwaz Nadzmy / mbed-STM

Fork of mbed-dev by mbed official

Committer:
<>
Date:
Fri Oct 28 11:17:30 2016 +0100
Revision:
149:156823d33999
Parent:
targets/hal/TARGET_NORDIC/TARGET_NRF5/sdk/ble/peer_manager/gatt_cache_manager.c@144:ef7eb2e8f9f7
This updates the lib to the mbed lib v128

NOTE: This release includes a restructuring of the file and directory locations and thus some
include paths in your code may need updating accordingly.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
<> 144:ef7eb2e8f9f7 1 /*
<> 144:ef7eb2e8f9f7 2 * Copyright (c) 2015 Nordic Semiconductor ASA
<> 144:ef7eb2e8f9f7 3 * All rights reserved.
<> 144:ef7eb2e8f9f7 4 *
<> 144:ef7eb2e8f9f7 5 * Redistribution and use in source and binary forms, with or without modification,
<> 144:ef7eb2e8f9f7 6 * are permitted provided that the following conditions are met:
<> 144:ef7eb2e8f9f7 7 *
<> 144:ef7eb2e8f9f7 8 * 1. Redistributions of source code must retain the above copyright notice, this list
<> 144:ef7eb2e8f9f7 9 * of conditions and the following disclaimer.
<> 144:ef7eb2e8f9f7 10 *
<> 144:ef7eb2e8f9f7 11 * 2. Redistributions in binary form, except as embedded into a Nordic Semiconductor ASA
<> 144:ef7eb2e8f9f7 12 * integrated circuit in a product or a software update for such product, must reproduce
<> 144:ef7eb2e8f9f7 13 * the above copyright notice, this list of conditions and the following disclaimer in
<> 144:ef7eb2e8f9f7 14 * the documentation and/or other materials provided with the distribution.
<> 144:ef7eb2e8f9f7 15 *
<> 144:ef7eb2e8f9f7 16 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its contributors may be
<> 144:ef7eb2e8f9f7 17 * used to endorse or promote products derived from this software without specific prior
<> 144:ef7eb2e8f9f7 18 * written permission.
<> 144:ef7eb2e8f9f7 19 *
<> 144:ef7eb2e8f9f7 20 * 4. This software, with or without modification, must only be used with a
<> 144:ef7eb2e8f9f7 21 * Nordic Semiconductor ASA integrated circuit.
<> 144:ef7eb2e8f9f7 22 *
<> 144:ef7eb2e8f9f7 23 * 5. Any software provided in binary or object form under this license must not be reverse
<> 144:ef7eb2e8f9f7 24 * engineered, decompiled, modified and/or disassembled.
<> 144:ef7eb2e8f9f7 25 *
<> 144:ef7eb2e8f9f7 26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
<> 144:ef7eb2e8f9f7 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
<> 144:ef7eb2e8f9f7 28 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
<> 144:ef7eb2e8f9f7 29 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
<> 144:ef7eb2e8f9f7 30 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
<> 144:ef7eb2e8f9f7 31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
<> 144:ef7eb2e8f9f7 32 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
<> 144:ef7eb2e8f9f7 33 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
<> 144:ef7eb2e8f9f7 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
<> 144:ef7eb2e8f9f7 35 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<> 144:ef7eb2e8f9f7 36 *
<> 144:ef7eb2e8f9f7 37 */
<> 144:ef7eb2e8f9f7 38
<> 144:ef7eb2e8f9f7 39
<> 144:ef7eb2e8f9f7 40
<> 144:ef7eb2e8f9f7 41 #include "gatt_cache_manager.h"
<> 144:ef7eb2e8f9f7 42
<> 144:ef7eb2e8f9f7 43 #include "nrf_ble_gap.h"
<> 144:ef7eb2e8f9f7 44 #include "ble_conn_state.h"
<> 144:ef7eb2e8f9f7 45 #include "peer_manager_types.h"
<> 144:ef7eb2e8f9f7 46 #include "peer_manager_internal.h"
<> 144:ef7eb2e8f9f7 47 #include "peer_database.h"
<> 144:ef7eb2e8f9f7 48 #include "id_manager.h"
<> 144:ef7eb2e8f9f7 49 #include "security_dispatcher.h"
<> 144:ef7eb2e8f9f7 50 #include "gatts_cache_manager.h"
<> 144:ef7eb2e8f9f7 51 #include "gattc_cache_manager.h"
<> 144:ef7eb2e8f9f7 52 #include "sdk_common.h"
<> 144:ef7eb2e8f9f7 53
<> 144:ef7eb2e8f9f7 54 /**@brief Structure containing the module variable(s) of the GCM module.
<> 144:ef7eb2e8f9f7 55 */
<> 144:ef7eb2e8f9f7 56 typedef struct
<> 144:ef7eb2e8f9f7 57 {
<> 144:ef7eb2e8f9f7 58 gcm_evt_handler_t evt_handler; /**< The event handler to use for outbound GSCM events. */
<> 144:ef7eb2e8f9f7 59 ble_conn_state_user_flag_id_t flag_id_local_db_update_pending; /**< Flag ID for flag collection to keep track of which connections need a local DB update procedure. */
<> 144:ef7eb2e8f9f7 60 ble_conn_state_user_flag_id_t flag_id_local_db_apply_pending; /**< Flag ID for flag collection to keep track of which connections need a local DB apply procedure. */
<> 144:ef7eb2e8f9f7 61 ble_conn_state_user_flag_id_t flag_id_service_changed_pending; /**< Flag ID for flag collection to keep track of which connections need to be sent a service changed indication. */
<> 144:ef7eb2e8f9f7 62 ble_conn_state_user_flag_id_t flag_id_service_changed_sent; /**< Flag ID for flag collection to keep track of which connections have been sent a service changed indication and are waiting for a handle value confirmation. */
<> 144:ef7eb2e8f9f7 63 } gcm_t;
<> 144:ef7eb2e8f9f7 64
<> 144:ef7eb2e8f9f7 65 static gcm_t m_gcm; /**< Instantiation of module variable(s). */
<> 144:ef7eb2e8f9f7 66
<> 144:ef7eb2e8f9f7 67 #define MODULE_INITIALIZED (m_gcm.evt_handler != NULL)
<> 144:ef7eb2e8f9f7 68 #include "sdk_macros.h"
<> 144:ef7eb2e8f9f7 69
<> 144:ef7eb2e8f9f7 70
<> 144:ef7eb2e8f9f7 71 static void service_changed_pending_flags_check(void);
<> 144:ef7eb2e8f9f7 72
<> 144:ef7eb2e8f9f7 73 /**@brief Function for resetting the module variable(s) of the GSCM module.
<> 144:ef7eb2e8f9f7 74 *
<> 144:ef7eb2e8f9f7 75 * @param[out] The instance to reset.
<> 144:ef7eb2e8f9f7 76 */
<> 144:ef7eb2e8f9f7 77 static void internal_state_reset(gcm_t * p_gcm)
<> 144:ef7eb2e8f9f7 78 {
<> 144:ef7eb2e8f9f7 79 memset(p_gcm, 0, sizeof(gcm_t));
<> 144:ef7eb2e8f9f7 80 }
<> 144:ef7eb2e8f9f7 81
<> 144:ef7eb2e8f9f7 82
<> 144:ef7eb2e8f9f7 83 /**@brief Function for checking a write event for whether a CCCD was written during the write
<> 144:ef7eb2e8f9f7 84 * operation.
<> 144:ef7eb2e8f9f7 85 *
<> 144:ef7eb2e8f9f7 86 * @param[in] p_write_evt The parameters of the write event.
<> 144:ef7eb2e8f9f7 87 *
<> 144:ef7eb2e8f9f7 88 * @return Whether the write was on a CCCD.
<> 144:ef7eb2e8f9f7 89 */
<> 144:ef7eb2e8f9f7 90 static bool cccd_written(ble_gatts_evt_write_t * p_write_evt)
<> 144:ef7eb2e8f9f7 91 {
<> 144:ef7eb2e8f9f7 92 return ( (p_write_evt->op == BLE_GATTS_OP_WRITE_REQ)
<> 144:ef7eb2e8f9f7 93 && (p_write_evt->uuid.type == BLE_UUID_TYPE_BLE)
<> 144:ef7eb2e8f9f7 94 && (p_write_evt->uuid.uuid == BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG)
<> 144:ef7eb2e8f9f7 95 );
<> 144:ef7eb2e8f9f7 96 }
<> 144:ef7eb2e8f9f7 97
<> 144:ef7eb2e8f9f7 98
<> 144:ef7eb2e8f9f7 99 /**@brief Function for performing the local DB update procedure in an event context, where no return
<> 144:ef7eb2e8f9f7 100 * code can be given.
<> 144:ef7eb2e8f9f7 101 *
<> 144:ef7eb2e8f9f7 102 * @details This function will do the procedure, and check the result, set a flag if needed, and
<> 144:ef7eb2e8f9f7 103 * send an event if needed.
<> 144:ef7eb2e8f9f7 104 *
<> 144:ef7eb2e8f9f7 105 * @param[in] conn_handle The connection to perform the procedure on.
<> 144:ef7eb2e8f9f7 106 */
<> 144:ef7eb2e8f9f7 107 static void local_db_apply_in_evt(uint16_t conn_handle)
<> 144:ef7eb2e8f9f7 108 {
<> 144:ef7eb2e8f9f7 109 bool set_procedure_as_pending = false;
<> 144:ef7eb2e8f9f7 110 ret_code_t err_code;
<> 144:ef7eb2e8f9f7 111 gcm_evt_t event;
<> 144:ef7eb2e8f9f7 112
<> 144:ef7eb2e8f9f7 113 if (conn_handle == BLE_CONN_HANDLE_INVALID)
<> 144:ef7eb2e8f9f7 114 {
<> 144:ef7eb2e8f9f7 115 return;
<> 144:ef7eb2e8f9f7 116 }
<> 144:ef7eb2e8f9f7 117
<> 144:ef7eb2e8f9f7 118 err_code = gscm_local_db_cache_apply(conn_handle);
<> 144:ef7eb2e8f9f7 119
<> 144:ef7eb2e8f9f7 120 switch(err_code)
<> 144:ef7eb2e8f9f7 121 {
<> 144:ef7eb2e8f9f7 122 case NRF_SUCCESS:
<> 144:ef7eb2e8f9f7 123 event.evt_id = GCM_EVT_LOCAL_DB_CACHE_APPLIED;
<> 144:ef7eb2e8f9f7 124 event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
<> 144:ef7eb2e8f9f7 125 event.params.local_db_cache_applied.conn_handle = conn_handle;
<> 144:ef7eb2e8f9f7 126
<> 144:ef7eb2e8f9f7 127 m_gcm.evt_handler(&event);
<> 144:ef7eb2e8f9f7 128 break;
<> 144:ef7eb2e8f9f7 129
<> 144:ef7eb2e8f9f7 130 case NRF_ERROR_BUSY:
<> 144:ef7eb2e8f9f7 131 set_procedure_as_pending = true;
<> 144:ef7eb2e8f9f7 132 break;
<> 144:ef7eb2e8f9f7 133
<> 144:ef7eb2e8f9f7 134 case NRF_ERROR_INVALID_DATA:
<> 144:ef7eb2e8f9f7 135 event.evt_id = GCM_EVT_ERROR_LOCAL_DB_CACHE_APPLY;
<> 144:ef7eb2e8f9f7 136 event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
<> 144:ef7eb2e8f9f7 137 event.params.error_local_db_cache_apply.conn_handle = conn_handle;
<> 144:ef7eb2e8f9f7 138
<> 144:ef7eb2e8f9f7 139 m_gcm.evt_handler(&event);
<> 144:ef7eb2e8f9f7 140 break;
<> 144:ef7eb2e8f9f7 141
<> 144:ef7eb2e8f9f7 142 case BLE_ERROR_INVALID_CONN_HANDLE:
<> 144:ef7eb2e8f9f7 143 /* Do nothing */
<> 144:ef7eb2e8f9f7 144 break;
<> 144:ef7eb2e8f9f7 145
<> 144:ef7eb2e8f9f7 146 default:
<> 144:ef7eb2e8f9f7 147 event.evt_id = GCM_EVT_ERROR_UNEXPECTED;
<> 144:ef7eb2e8f9f7 148 event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
<> 144:ef7eb2e8f9f7 149 event.params.error_unexpected.conn_handle = conn_handle;
<> 144:ef7eb2e8f9f7 150 event.params.error_unexpected.error = err_code;
<> 144:ef7eb2e8f9f7 151
<> 144:ef7eb2e8f9f7 152 m_gcm.evt_handler(&event);
<> 144:ef7eb2e8f9f7 153 break;
<> 144:ef7eb2e8f9f7 154 }
<> 144:ef7eb2e8f9f7 155
<> 144:ef7eb2e8f9f7 156 ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_local_db_apply_pending, set_procedure_as_pending);
<> 144:ef7eb2e8f9f7 157 }
<> 144:ef7eb2e8f9f7 158
<> 144:ef7eb2e8f9f7 159
<> 144:ef7eb2e8f9f7 160 /**@brief Function for performing the local DB apply procedure in an event context, where no return
<> 144:ef7eb2e8f9f7 161 * code can be given.
<> 144:ef7eb2e8f9f7 162 *
<> 144:ef7eb2e8f9f7 163 * @details This function will do the procedure, and check the result, set a flag if needed, and
<> 144:ef7eb2e8f9f7 164 * send an event if needed.
<> 144:ef7eb2e8f9f7 165 *
<> 144:ef7eb2e8f9f7 166 * @param[in] conn_handle The connection to perform the procedure on.
<> 144:ef7eb2e8f9f7 167 */
<> 144:ef7eb2e8f9f7 168 static void local_db_update_in_evt(uint16_t conn_handle)
<> 144:ef7eb2e8f9f7 169 {
<> 144:ef7eb2e8f9f7 170 gcm_evt_t event;
<> 144:ef7eb2e8f9f7 171 bool set_procedure_as_pending = false;
<> 144:ef7eb2e8f9f7 172 ret_code_t err_code = gscm_local_db_cache_update(conn_handle);
<> 144:ef7eb2e8f9f7 173
<> 144:ef7eb2e8f9f7 174 switch(err_code)
<> 144:ef7eb2e8f9f7 175 {
<> 144:ef7eb2e8f9f7 176 case NRF_SUCCESS:
<> 144:ef7eb2e8f9f7 177 event.evt_id = GCM_EVT_LOCAL_DB_CACHE_UPDATED;
<> 144:ef7eb2e8f9f7 178 event.params.local_db_cache_applied.conn_handle = conn_handle;
<> 144:ef7eb2e8f9f7 179 event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
<> 144:ef7eb2e8f9f7 180
<> 144:ef7eb2e8f9f7 181 m_gcm.evt_handler(&event);
<> 144:ef7eb2e8f9f7 182 break;
<> 144:ef7eb2e8f9f7 183
<> 144:ef7eb2e8f9f7 184 case BLE_ERROR_INVALID_CONN_HANDLE:
<> 144:ef7eb2e8f9f7 185 /* Do nothing */
<> 144:ef7eb2e8f9f7 186 break;
<> 144:ef7eb2e8f9f7 187
<> 144:ef7eb2e8f9f7 188 case NRF_ERROR_BUSY:
<> 144:ef7eb2e8f9f7 189 set_procedure_as_pending = true;
<> 144:ef7eb2e8f9f7 190 break;
<> 144:ef7eb2e8f9f7 191
<> 144:ef7eb2e8f9f7 192 case NRF_ERROR_DATA_SIZE:
<> 144:ef7eb2e8f9f7 193 event.evt_id = GCM_EVT_ERROR_DATA_SIZE;
<> 144:ef7eb2e8f9f7 194 event.params.error_data_size.conn_handle = conn_handle;
<> 144:ef7eb2e8f9f7 195 event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
<> 144:ef7eb2e8f9f7 196
<> 144:ef7eb2e8f9f7 197 m_gcm.evt_handler(&event);
<> 144:ef7eb2e8f9f7 198 break;
<> 144:ef7eb2e8f9f7 199
<> 144:ef7eb2e8f9f7 200 case NRF_ERROR_NO_MEM:
<> 144:ef7eb2e8f9f7 201 event.evt_id = GCM_EVT_ERROR_STORAGE_FULL;
<> 144:ef7eb2e8f9f7 202 event.params.error_no_mem.conn_handle = conn_handle;
<> 144:ef7eb2e8f9f7 203 event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
<> 144:ef7eb2e8f9f7 204
<> 144:ef7eb2e8f9f7 205 m_gcm.evt_handler(&event);
<> 144:ef7eb2e8f9f7 206 break;
<> 144:ef7eb2e8f9f7 207
<> 144:ef7eb2e8f9f7 208 default:
<> 144:ef7eb2e8f9f7 209 event.evt_id = GCM_EVT_ERROR_UNEXPECTED;
<> 144:ef7eb2e8f9f7 210 event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
<> 144:ef7eb2e8f9f7 211 event.params.error_unexpected.conn_handle = conn_handle;
<> 144:ef7eb2e8f9f7 212 event.params.error_unexpected.error = err_code;
<> 144:ef7eb2e8f9f7 213
<> 144:ef7eb2e8f9f7 214 m_gcm.evt_handler(&event);
<> 144:ef7eb2e8f9f7 215 break;
<> 144:ef7eb2e8f9f7 216 }
<> 144:ef7eb2e8f9f7 217
<> 144:ef7eb2e8f9f7 218 ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_local_db_update_pending, set_procedure_as_pending);
<> 144:ef7eb2e8f9f7 219 }
<> 144:ef7eb2e8f9f7 220
<> 144:ef7eb2e8f9f7 221
<> 144:ef7eb2e8f9f7 222 /**@brief Function for sending a service changed indication in an event context, where no return
<> 144:ef7eb2e8f9f7 223 * code can be given.
<> 144:ef7eb2e8f9f7 224 *
<> 144:ef7eb2e8f9f7 225 * @details This function will do the procedure, and check the result, set a flag if needed, and
<> 144:ef7eb2e8f9f7 226 * send an event if needed.
<> 144:ef7eb2e8f9f7 227 *
<> 144:ef7eb2e8f9f7 228 * @param[in] conn_handle The connection to perform the procedure on.
<> 144:ef7eb2e8f9f7 229 */
<> 144:ef7eb2e8f9f7 230 static void service_changed_send_in_evt(uint16_t conn_handle)
<> 144:ef7eb2e8f9f7 231 {
<> 144:ef7eb2e8f9f7 232 gcm_evt_t event;
<> 144:ef7eb2e8f9f7 233 bool sc_pending_state = true;
<> 144:ef7eb2e8f9f7 234 bool sc_sent_state = false;
<> 144:ef7eb2e8f9f7 235 ret_code_t err_code = gscm_service_changed_ind_send(conn_handle);
<> 144:ef7eb2e8f9f7 236
<> 144:ef7eb2e8f9f7 237 switch(err_code)
<> 144:ef7eb2e8f9f7 238 {
<> 144:ef7eb2e8f9f7 239 case NRF_SUCCESS:
<> 144:ef7eb2e8f9f7 240 sc_sent_state = true;
<> 144:ef7eb2e8f9f7 241
<> 144:ef7eb2e8f9f7 242 event.evt_id = GCM_EVT_SERVICE_CHANGED_IND_SENT;
<> 144:ef7eb2e8f9f7 243 event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
<> 144:ef7eb2e8f9f7 244 event.params.service_changed_ind_sent.conn_handle = conn_handle;
<> 144:ef7eb2e8f9f7 245
<> 144:ef7eb2e8f9f7 246 m_gcm.evt_handler(&event);
<> 144:ef7eb2e8f9f7 247 break;
<> 144:ef7eb2e8f9f7 248
<> 144:ef7eb2e8f9f7 249 case NRF_ERROR_BUSY:
<> 144:ef7eb2e8f9f7 250 // Do nothing.
<> 144:ef7eb2e8f9f7 251 break;
<> 144:ef7eb2e8f9f7 252
<> 144:ef7eb2e8f9f7 253 case NRF_ERROR_INVALID_STATE:
<> 144:ef7eb2e8f9f7 254 // CCCDs not enabled. Drop indication.
<> 144:ef7eb2e8f9f7 255 // Fallthrough.
<> 144:ef7eb2e8f9f7 256
<> 144:ef7eb2e8f9f7 257 case NRF_ERROR_NOT_SUPPORTED:
<> 144:ef7eb2e8f9f7 258 // Service changed not supported. Drop indication.
<> 144:ef7eb2e8f9f7 259 sc_pending_state = false;
<> 144:ef7eb2e8f9f7 260 gscm_db_change_notification_done(im_peer_id_get_by_conn_handle(conn_handle));
<> 144:ef7eb2e8f9f7 261 break;
<> 144:ef7eb2e8f9f7 262
<> 144:ef7eb2e8f9f7 263 case BLE_ERROR_GATTS_SYS_ATTR_MISSING:
<> 144:ef7eb2e8f9f7 264 local_db_apply_in_evt(conn_handle);
<> 144:ef7eb2e8f9f7 265 break;
<> 144:ef7eb2e8f9f7 266
<> 144:ef7eb2e8f9f7 267 case BLE_ERROR_INVALID_CONN_HANDLE:
<> 144:ef7eb2e8f9f7 268 // Do nothing.
<> 144:ef7eb2e8f9f7 269 break;
<> 144:ef7eb2e8f9f7 270
<> 144:ef7eb2e8f9f7 271 default:
<> 144:ef7eb2e8f9f7 272 event.evt_id = GCM_EVT_ERROR_UNEXPECTED;
<> 144:ef7eb2e8f9f7 273 event.params.error_unexpected.conn_handle = conn_handle;
<> 144:ef7eb2e8f9f7 274 event.params.error_unexpected.error = err_code;
<> 144:ef7eb2e8f9f7 275 event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
<> 144:ef7eb2e8f9f7 276
<> 144:ef7eb2e8f9f7 277 m_gcm.evt_handler(&event);
<> 144:ef7eb2e8f9f7 278 break;
<> 144:ef7eb2e8f9f7 279 }
<> 144:ef7eb2e8f9f7 280
<> 144:ef7eb2e8f9f7 281 ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_service_changed_pending, sc_pending_state);
<> 144:ef7eb2e8f9f7 282 ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_service_changed_sent, sc_sent_state);
<> 144:ef7eb2e8f9f7 283 }
<> 144:ef7eb2e8f9f7 284
<> 144:ef7eb2e8f9f7 285
<> 144:ef7eb2e8f9f7 286 /**@brief Callback function for events from the GATT Cache Server Manager module.
<> 144:ef7eb2e8f9f7 287 *
<> 144:ef7eb2e8f9f7 288 * @param[in] p_event The event from the GATT Cache Server Manager module.
<> 144:ef7eb2e8f9f7 289 */
<> 144:ef7eb2e8f9f7 290 static void gscm_evt_handler(gscm_evt_t const * p_event)
<> 144:ef7eb2e8f9f7 291 {
<> 144:ef7eb2e8f9f7 292 gcm_evt_t event;
<> 144:ef7eb2e8f9f7 293 event.peer_id = p_event->peer_id;
<> 144:ef7eb2e8f9f7 294
<> 144:ef7eb2e8f9f7 295 switch (p_event->evt_id)
<> 144:ef7eb2e8f9f7 296 {
<> 144:ef7eb2e8f9f7 297 case GSCM_EVT_LOCAL_DB_CACHE_STORED:
<> 144:ef7eb2e8f9f7 298 event.evt_id = GCM_EVT_LOCAL_DB_CACHE_STORED;
<> 144:ef7eb2e8f9f7 299
<> 144:ef7eb2e8f9f7 300 m_gcm.evt_handler(&event);
<> 144:ef7eb2e8f9f7 301 local_db_apply_in_evt(im_conn_handle_get(p_event->peer_id));
<> 144:ef7eb2e8f9f7 302 break;
<> 144:ef7eb2e8f9f7 303
<> 144:ef7eb2e8f9f7 304 case GSCM_EVT_LOCAL_DB_CACHE_UPDATED:
<> 144:ef7eb2e8f9f7 305 event.evt_id = GCM_EVT_LOCAL_DB_CACHE_UPDATED;
<> 144:ef7eb2e8f9f7 306 event.params.local_db_cache_updated.conn_handle = p_event->params.local_db_cache_updated.conn_handle;
<> 144:ef7eb2e8f9f7 307
<> 144:ef7eb2e8f9f7 308 m_gcm.evt_handler(&event);
<> 144:ef7eb2e8f9f7 309 break;
<> 144:ef7eb2e8f9f7 310
<> 144:ef7eb2e8f9f7 311 case GSCM_EVT_SC_STATE_STORED:
<> 144:ef7eb2e8f9f7 312 if (p_event->params.sc_state_stored.state)
<> 144:ef7eb2e8f9f7 313 {
<> 144:ef7eb2e8f9f7 314 uint16_t conn_handle = im_conn_handle_get(p_event->peer_id);
<> 144:ef7eb2e8f9f7 315 if (conn_handle != BLE_CONN_HANDLE_INVALID)
<> 144:ef7eb2e8f9f7 316 {
<> 144:ef7eb2e8f9f7 317 ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_service_changed_pending, true);
<> 144:ef7eb2e8f9f7 318 service_changed_pending_flags_check();
<> 144:ef7eb2e8f9f7 319 }
<> 144:ef7eb2e8f9f7 320 }
<> 144:ef7eb2e8f9f7 321 break;
<> 144:ef7eb2e8f9f7 322 }
<> 144:ef7eb2e8f9f7 323 }
<> 144:ef7eb2e8f9f7 324
<> 144:ef7eb2e8f9f7 325
<> 144:ef7eb2e8f9f7 326 /**@brief Callback function for events from the GATT Cache Client Manager module.
<> 144:ef7eb2e8f9f7 327 *
<> 144:ef7eb2e8f9f7 328 * @param[in] p_event The event from the GATT Cache Client Manager module.
<> 144:ef7eb2e8f9f7 329 */
<> 144:ef7eb2e8f9f7 330 static void gccm_evt_handler(gccm_evt_t const * p_event)
<> 144:ef7eb2e8f9f7 331 {
<> 144:ef7eb2e8f9f7 332
<> 144:ef7eb2e8f9f7 333 }
<> 144:ef7eb2e8f9f7 334
<> 144:ef7eb2e8f9f7 335
<> 144:ef7eb2e8f9f7 336 /**@brief Callback function for events from the Identity Manager module.
<> 144:ef7eb2e8f9f7 337 *
<> 144:ef7eb2e8f9f7 338 * @param[in] p_event The event from the Identity Manager module.
<> 144:ef7eb2e8f9f7 339 */
<> 144:ef7eb2e8f9f7 340 static void im_evt_handler(im_evt_t const * p_event)
<> 144:ef7eb2e8f9f7 341 {
<> 144:ef7eb2e8f9f7 342 switch (p_event->evt_id)
<> 144:ef7eb2e8f9f7 343 {
<> 144:ef7eb2e8f9f7 344 case IM_EVT_BONDED_PEER_CONNECTED:
<> 144:ef7eb2e8f9f7 345 local_db_apply_in_evt(p_event->conn_handle);
<> 144:ef7eb2e8f9f7 346 if (gscm_service_changed_ind_needed(p_event->conn_handle))
<> 144:ef7eb2e8f9f7 347 {
<> 144:ef7eb2e8f9f7 348 ble_conn_state_user_flag_set(p_event->conn_handle, m_gcm.flag_id_service_changed_pending, true);
<> 144:ef7eb2e8f9f7 349 }
<> 144:ef7eb2e8f9f7 350 break;
<> 144:ef7eb2e8f9f7 351 default:
<> 144:ef7eb2e8f9f7 352 break;
<> 144:ef7eb2e8f9f7 353 }
<> 144:ef7eb2e8f9f7 354 }
<> 144:ef7eb2e8f9f7 355
<> 144:ef7eb2e8f9f7 356
<> 144:ef7eb2e8f9f7 357 /**@brief Callback function for events from the Security Dispatcher module.
<> 144:ef7eb2e8f9f7 358 *
<> 144:ef7eb2e8f9f7 359 * @param[in] p_event The event from the Security Dispatcher module.
<> 144:ef7eb2e8f9f7 360 */
<> 144:ef7eb2e8f9f7 361 static void smd_evt_handler(smd_evt_t const * p_event)
<> 144:ef7eb2e8f9f7 362 {
<> 144:ef7eb2e8f9f7 363 switch (p_event->evt_id)
<> 144:ef7eb2e8f9f7 364 {
<> 144:ef7eb2e8f9f7 365 case SMD_EVT_BONDING_INFO_STORED:
<> 144:ef7eb2e8f9f7 366 local_db_update_in_evt(p_event->conn_handle);
<> 144:ef7eb2e8f9f7 367 break;
<> 144:ef7eb2e8f9f7 368 default:
<> 144:ef7eb2e8f9f7 369 break;
<> 144:ef7eb2e8f9f7 370 }
<> 144:ef7eb2e8f9f7 371 }
<> 144:ef7eb2e8f9f7 372
<> 144:ef7eb2e8f9f7 373
<> 144:ef7eb2e8f9f7 374 ret_code_t gcm_init(gcm_evt_handler_t evt_handler)
<> 144:ef7eb2e8f9f7 375 {
<> 144:ef7eb2e8f9f7 376 VERIFY_PARAM_NOT_NULL(evt_handler);
<> 144:ef7eb2e8f9f7 377
<> 144:ef7eb2e8f9f7 378 ret_code_t err_code;
<> 144:ef7eb2e8f9f7 379
<> 144:ef7eb2e8f9f7 380 err_code = gscm_init(gscm_evt_handler);
<> 144:ef7eb2e8f9f7 381 VERIFY_SUCCESS(err_code);
<> 144:ef7eb2e8f9f7 382
<> 144:ef7eb2e8f9f7 383 err_code = gccm_init(gccm_evt_handler);
<> 144:ef7eb2e8f9f7 384 VERIFY_SUCCESS(err_code);
<> 144:ef7eb2e8f9f7 385
<> 144:ef7eb2e8f9f7 386 internal_state_reset(&m_gcm);
<> 144:ef7eb2e8f9f7 387 m_gcm.evt_handler = evt_handler;
<> 144:ef7eb2e8f9f7 388
<> 144:ef7eb2e8f9f7 389 err_code = im_register(im_evt_handler);
<> 144:ef7eb2e8f9f7 390 VERIFY_SUCCESS(err_code);
<> 144:ef7eb2e8f9f7 391
<> 144:ef7eb2e8f9f7 392 err_code = smd_register(smd_evt_handler);
<> 144:ef7eb2e8f9f7 393 VERIFY_SUCCESS(err_code);
<> 144:ef7eb2e8f9f7 394
<> 144:ef7eb2e8f9f7 395
<> 144:ef7eb2e8f9f7 396 m_gcm.flag_id_local_db_update_pending = ble_conn_state_user_flag_acquire();
<> 144:ef7eb2e8f9f7 397 m_gcm.flag_id_local_db_apply_pending = ble_conn_state_user_flag_acquire();
<> 144:ef7eb2e8f9f7 398 m_gcm.flag_id_service_changed_pending = ble_conn_state_user_flag_acquire();
<> 144:ef7eb2e8f9f7 399 m_gcm.flag_id_service_changed_sent = ble_conn_state_user_flag_acquire();
<> 144:ef7eb2e8f9f7 400
<> 144:ef7eb2e8f9f7 401 if ((m_gcm.flag_id_local_db_update_pending == BLE_CONN_STATE_USER_FLAG_INVALID)
<> 144:ef7eb2e8f9f7 402 || (m_gcm.flag_id_local_db_apply_pending == BLE_CONN_STATE_USER_FLAG_INVALID)
<> 144:ef7eb2e8f9f7 403 || (m_gcm.flag_id_service_changed_pending == BLE_CONN_STATE_USER_FLAG_INVALID)
<> 144:ef7eb2e8f9f7 404 || (m_gcm.flag_id_service_changed_sent == BLE_CONN_STATE_USER_FLAG_INVALID))
<> 144:ef7eb2e8f9f7 405 {
<> 144:ef7eb2e8f9f7 406 err_code = NRF_ERROR_INTERNAL;
<> 144:ef7eb2e8f9f7 407 }
<> 144:ef7eb2e8f9f7 408
<> 144:ef7eb2e8f9f7 409 return err_code;
<> 144:ef7eb2e8f9f7 410 }
<> 144:ef7eb2e8f9f7 411
<> 144:ef7eb2e8f9f7 412
<> 144:ef7eb2e8f9f7 413 /**@brief Function for performing the Local DB apply procedure if it is pending on any connections.
<> 144:ef7eb2e8f9f7 414 */
<> 144:ef7eb2e8f9f7 415 static void apply_pending_flags_check(void)
<> 144:ef7eb2e8f9f7 416 {
<> 144:ef7eb2e8f9f7 417 sdk_mapped_flags_t apply_pending_flags;
<> 144:ef7eb2e8f9f7 418
<> 144:ef7eb2e8f9f7 419 apply_pending_flags = ble_conn_state_user_flag_collection(m_gcm.flag_id_local_db_apply_pending);
<> 144:ef7eb2e8f9f7 420 if (sdk_mapped_flags_any_set(apply_pending_flags))
<> 144:ef7eb2e8f9f7 421 {
<> 144:ef7eb2e8f9f7 422 sdk_mapped_flags_key_list_t conn_handle_list;
<> 144:ef7eb2e8f9f7 423 conn_handle_list = ble_conn_state_conn_handles();
<> 144:ef7eb2e8f9f7 424
<> 144:ef7eb2e8f9f7 425 for (uint32_t i = 0; i < conn_handle_list.len; i++)
<> 144:ef7eb2e8f9f7 426 {
<> 144:ef7eb2e8f9f7 427 if (ble_conn_state_user_flag_get(conn_handle_list.flag_keys[i], m_gcm.flag_id_local_db_apply_pending))
<> 144:ef7eb2e8f9f7 428 {
<> 144:ef7eb2e8f9f7 429 local_db_apply_in_evt(conn_handle_list.flag_keys[i]);
<> 144:ef7eb2e8f9f7 430 }
<> 144:ef7eb2e8f9f7 431 }
<> 144:ef7eb2e8f9f7 432 }
<> 144:ef7eb2e8f9f7 433 }
<> 144:ef7eb2e8f9f7 434
<> 144:ef7eb2e8f9f7 435
<> 144:ef7eb2e8f9f7 436 /**@brief Function for performing the Local DB update procedure if it is pending on any connections.
<> 144:ef7eb2e8f9f7 437 */
<> 144:ef7eb2e8f9f7 438 static void update_pending_flags_check(void)
<> 144:ef7eb2e8f9f7 439 {
<> 144:ef7eb2e8f9f7 440 sdk_mapped_flags_t update_pending_flags;
<> 144:ef7eb2e8f9f7 441
<> 144:ef7eb2e8f9f7 442 update_pending_flags = ble_conn_state_user_flag_collection(m_gcm.flag_id_local_db_update_pending);
<> 144:ef7eb2e8f9f7 443 if (sdk_mapped_flags_any_set(update_pending_flags))
<> 144:ef7eb2e8f9f7 444 {
<> 144:ef7eb2e8f9f7 445 sdk_mapped_flags_key_list_t conn_handle_list;
<> 144:ef7eb2e8f9f7 446 conn_handle_list = ble_conn_state_conn_handles();
<> 144:ef7eb2e8f9f7 447
<> 144:ef7eb2e8f9f7 448 for (uint32_t i = 0; i < conn_handle_list.len; i++)
<> 144:ef7eb2e8f9f7 449 {
<> 144:ef7eb2e8f9f7 450 if (ble_conn_state_user_flag_get(conn_handle_list.flag_keys[i], m_gcm.flag_id_local_db_update_pending))
<> 144:ef7eb2e8f9f7 451 {
<> 144:ef7eb2e8f9f7 452 local_db_update_in_evt(conn_handle_list.flag_keys[i]);
<> 144:ef7eb2e8f9f7 453 }
<> 144:ef7eb2e8f9f7 454 }
<> 144:ef7eb2e8f9f7 455 }
<> 144:ef7eb2e8f9f7 456 }
<> 144:ef7eb2e8f9f7 457
<> 144:ef7eb2e8f9f7 458
<> 144:ef7eb2e8f9f7 459 /**@brief Function for sending service changed indications if it is pending on any connections.
<> 144:ef7eb2e8f9f7 460 */
<> 144:ef7eb2e8f9f7 461 static void service_changed_pending_flags_check(void)
<> 144:ef7eb2e8f9f7 462 {
<> 144:ef7eb2e8f9f7 463 sdk_mapped_flags_t service_changed_pending_flags;
<> 144:ef7eb2e8f9f7 464
<> 144:ef7eb2e8f9f7 465 service_changed_pending_flags = ble_conn_state_user_flag_collection(m_gcm.flag_id_service_changed_pending);
<> 144:ef7eb2e8f9f7 466 if (sdk_mapped_flags_any_set(service_changed_pending_flags))
<> 144:ef7eb2e8f9f7 467 {
<> 144:ef7eb2e8f9f7 468 sdk_mapped_flags_key_list_t conn_handle_list;
<> 144:ef7eb2e8f9f7 469 conn_handle_list = ble_conn_state_conn_handles();
<> 144:ef7eb2e8f9f7 470
<> 144:ef7eb2e8f9f7 471 for (uint32_t i = 0; i < conn_handle_list.len; i++)
<> 144:ef7eb2e8f9f7 472 {
<> 144:ef7eb2e8f9f7 473 if ( ble_conn_state_user_flag_get(conn_handle_list.flag_keys[i],
<> 144:ef7eb2e8f9f7 474 m_gcm.flag_id_service_changed_pending)
<> 144:ef7eb2e8f9f7 475 && !ble_conn_state_user_flag_get(conn_handle_list.flag_keys[i],
<> 144:ef7eb2e8f9f7 476 m_gcm.flag_id_service_changed_sent))
<> 144:ef7eb2e8f9f7 477 {
<> 144:ef7eb2e8f9f7 478 service_changed_send_in_evt(conn_handle_list.flag_keys[i]);
<> 144:ef7eb2e8f9f7 479 }
<> 144:ef7eb2e8f9f7 480 }
<> 144:ef7eb2e8f9f7 481 }
<> 144:ef7eb2e8f9f7 482 }
<> 144:ef7eb2e8f9f7 483
<> 144:ef7eb2e8f9f7 484
<> 144:ef7eb2e8f9f7 485 /**@brief Callback function for BLE events from the SoftDevice.
<> 144:ef7eb2e8f9f7 486 *
<> 144:ef7eb2e8f9f7 487 * @param[in] p_ble_evt The BLE event from the SoftDevice.
<> 144:ef7eb2e8f9f7 488 */
<> 144:ef7eb2e8f9f7 489 void gcm_ble_evt_handler(ble_evt_t * p_ble_evt)
<> 144:ef7eb2e8f9f7 490 {
<> 144:ef7eb2e8f9f7 491 gcm_evt_t event;
<> 144:ef7eb2e8f9f7 492
<> 144:ef7eb2e8f9f7 493 switch(p_ble_evt->header.evt_id)
<> 144:ef7eb2e8f9f7 494 {
<> 144:ef7eb2e8f9f7 495 case BLE_GATTS_EVT_SYS_ATTR_MISSING:
<> 144:ef7eb2e8f9f7 496 local_db_apply_in_evt(p_ble_evt->evt.gatts_evt.conn_handle);
<> 144:ef7eb2e8f9f7 497 break;
<> 144:ef7eb2e8f9f7 498
<> 144:ef7eb2e8f9f7 499 case BLE_GATTS_EVT_SC_CONFIRM:
<> 144:ef7eb2e8f9f7 500 event.evt_id = GCM_EVT_SERVICE_CHANGED_IND_CONFIRMED;
<> 144:ef7eb2e8f9f7 501 event.peer_id = im_peer_id_get_by_conn_handle(p_ble_evt->evt.gatts_evt.conn_handle);
<> 144:ef7eb2e8f9f7 502 event.params.service_changed_ind_sent.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
<> 144:ef7eb2e8f9f7 503
<> 144:ef7eb2e8f9f7 504 gscm_db_change_notification_done(event.peer_id);
<> 144:ef7eb2e8f9f7 505 ble_conn_state_user_flag_set(p_ble_evt->evt.gatts_evt.conn_handle, m_gcm.flag_id_service_changed_pending, false);
<> 144:ef7eb2e8f9f7 506
<> 144:ef7eb2e8f9f7 507 m_gcm.evt_handler(&event);
<> 144:ef7eb2e8f9f7 508 break;
<> 144:ef7eb2e8f9f7 509
<> 144:ef7eb2e8f9f7 510 case BLE_GATTS_EVT_WRITE:
<> 144:ef7eb2e8f9f7 511 if (cccd_written(&p_ble_evt->evt.gatts_evt.params.write))
<> 144:ef7eb2e8f9f7 512 {
<> 144:ef7eb2e8f9f7 513 local_db_update_in_evt(p_ble_evt->evt.gatts_evt.conn_handle);
<> 144:ef7eb2e8f9f7 514 }
<> 144:ef7eb2e8f9f7 515 break;
<> 144:ef7eb2e8f9f7 516 }
<> 144:ef7eb2e8f9f7 517
<> 144:ef7eb2e8f9f7 518 apply_pending_flags_check();
<> 144:ef7eb2e8f9f7 519 update_pending_flags_check();
<> 144:ef7eb2e8f9f7 520 service_changed_pending_flags_check();
<> 144:ef7eb2e8f9f7 521 }
<> 144:ef7eb2e8f9f7 522
<> 144:ef7eb2e8f9f7 523
<> 144:ef7eb2e8f9f7 524 ret_code_t gcm_remote_db_store(pm_peer_id_t peer_id,
<> 144:ef7eb2e8f9f7 525 ble_gatt_db_srv_t * p_remote_db,
<> 144:ef7eb2e8f9f7 526 uint32_t n_services)
<> 144:ef7eb2e8f9f7 527 {
<> 144:ef7eb2e8f9f7 528 VERIFY_MODULE_INITIALIZED();
<> 144:ef7eb2e8f9f7 529
<> 144:ef7eb2e8f9f7 530 return gccm_remote_db_store(peer_id, p_remote_db, n_services);
<> 144:ef7eb2e8f9f7 531 }
<> 144:ef7eb2e8f9f7 532
<> 144:ef7eb2e8f9f7 533
<> 144:ef7eb2e8f9f7 534 ret_code_t gcm_remote_db_retrieve(pm_peer_id_t peer_id,
<> 144:ef7eb2e8f9f7 535 ble_gatt_db_srv_t * p_remote_db,
<> 144:ef7eb2e8f9f7 536 uint32_t * p_n_services)
<> 144:ef7eb2e8f9f7 537 {
<> 144:ef7eb2e8f9f7 538 VERIFY_MODULE_INITIALIZED();
<> 144:ef7eb2e8f9f7 539 VERIFY_PARAM_NOT_NULL(p_remote_db);
<> 144:ef7eb2e8f9f7 540
<> 144:ef7eb2e8f9f7 541 return gccm_remote_db_retrieve(peer_id, p_remote_db, p_n_services);
<> 144:ef7eb2e8f9f7 542 }
<> 144:ef7eb2e8f9f7 543
<> 144:ef7eb2e8f9f7 544
<> 144:ef7eb2e8f9f7 545 ret_code_t gcm_local_db_cache_update(uint16_t conn_handle)
<> 144:ef7eb2e8f9f7 546 {
<> 144:ef7eb2e8f9f7 547 VERIFY_MODULE_INITIALIZED();
<> 144:ef7eb2e8f9f7 548
<> 144:ef7eb2e8f9f7 549 ret_code_t err_code = gscm_local_db_cache_update(conn_handle);
<> 144:ef7eb2e8f9f7 550 bool set_procedure_as_pending = false;
<> 144:ef7eb2e8f9f7 551
<> 144:ef7eb2e8f9f7 552 if (err_code == NRF_ERROR_BUSY)
<> 144:ef7eb2e8f9f7 553 {
<> 144:ef7eb2e8f9f7 554 set_procedure_as_pending = true;
<> 144:ef7eb2e8f9f7 555 err_code = NRF_SUCCESS;
<> 144:ef7eb2e8f9f7 556 }
<> 144:ef7eb2e8f9f7 557
<> 144:ef7eb2e8f9f7 558 ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_local_db_update_pending, set_procedure_as_pending);
<> 144:ef7eb2e8f9f7 559
<> 144:ef7eb2e8f9f7 560 return err_code;
<> 144:ef7eb2e8f9f7 561 }
<> 144:ef7eb2e8f9f7 562
<> 144:ef7eb2e8f9f7 563
<> 144:ef7eb2e8f9f7 564 ret_code_t gcm_local_db_cache_set(pm_peer_id_t peer_id, pm_peer_data_local_gatt_db_t * p_local_db)
<> 144:ef7eb2e8f9f7 565 {
<> 144:ef7eb2e8f9f7 566 VERIFY_MODULE_INITIALIZED();
<> 144:ef7eb2e8f9f7 567
<> 144:ef7eb2e8f9f7 568 return gscm_local_db_cache_set(peer_id, p_local_db);
<> 144:ef7eb2e8f9f7 569 }
<> 144:ef7eb2e8f9f7 570
<> 144:ef7eb2e8f9f7 571
<> 144:ef7eb2e8f9f7 572 ret_code_t gcm_local_db_cache_get(pm_peer_id_t peer_id, pm_peer_data_local_gatt_db_t * p_local_db)
<> 144:ef7eb2e8f9f7 573 {
<> 144:ef7eb2e8f9f7 574 VERIFY_MODULE_INITIALIZED();
<> 144:ef7eb2e8f9f7 575
<> 144:ef7eb2e8f9f7 576 return gscm_local_db_cache_get(peer_id, p_local_db);
<> 144:ef7eb2e8f9f7 577 }
<> 144:ef7eb2e8f9f7 578
<> 144:ef7eb2e8f9f7 579
<> 144:ef7eb2e8f9f7 580 void gcm_local_database_has_changed(void)
<> 144:ef7eb2e8f9f7 581 {
<> 144:ef7eb2e8f9f7 582 gscm_local_database_has_changed();
<> 144:ef7eb2e8f9f7 583
<> 144:ef7eb2e8f9f7 584 sdk_mapped_flags_key_list_t conn_handles = ble_conn_state_conn_handles();
<> 144:ef7eb2e8f9f7 585
<> 144:ef7eb2e8f9f7 586 for (uint16_t i = 0; i < conn_handles.len; i++)
<> 144:ef7eb2e8f9f7 587 {
<> 144:ef7eb2e8f9f7 588 if (im_peer_id_get_by_conn_handle(conn_handles.flag_keys[i]) == PM_PEER_ID_INVALID)
<> 144:ef7eb2e8f9f7 589 {
<> 144:ef7eb2e8f9f7 590 ble_conn_state_user_flag_set(conn_handles.flag_keys[i], m_gcm.flag_id_service_changed_pending, true);
<> 144:ef7eb2e8f9f7 591 }
<> 144:ef7eb2e8f9f7 592 }
<> 144:ef7eb2e8f9f7 593
<> 144:ef7eb2e8f9f7 594 service_changed_pending_flags_check();
<> 144:ef7eb2e8f9f7 595 }