テスト用

Fork of nRF51822 by Nordic Semiconductor

Committer:
Rohit Grover
Date:
Mon Jul 07 13:43:31 2014 +0100
Revision:
37:c29c330d942c
Parent:
0:eff01767de02
Child:
51:63ba3bcf5cd6
changes required to upgrade to V7 of the soft-device

Who changed what in which revision?

UserRevisionLine numberNew contents of line
bogdanm 0:eff01767de02 1 /* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved.
bogdanm 0:eff01767de02 2 *
bogdanm 0:eff01767de02 3 * The information contained herein is property of Nordic Semiconductor ASA.
bogdanm 0:eff01767de02 4 * Terms and conditions of usage are described in detail in NORDIC
bogdanm 0:eff01767de02 5 * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
bogdanm 0:eff01767de02 6 *
bogdanm 0:eff01767de02 7 * Licensees are granted free, non-transferable use of the information. NO
bogdanm 0:eff01767de02 8 * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
bogdanm 0:eff01767de02 9 * the file.
bogdanm 0:eff01767de02 10 *
bogdanm 0:eff01767de02 11 */
bogdanm 0:eff01767de02 12
bogdanm 0:eff01767de02 13 #include "softdevice_handler.h"
bogdanm 0:eff01767de02 14 #include <stdlib.h>
bogdanm 0:eff01767de02 15 #include "nordic_common.h"
bogdanm 0:eff01767de02 16 #include "app_error.h"
bogdanm 0:eff01767de02 17 #include "app_util.h"
bogdanm 0:eff01767de02 18 #include "nrf_assert.h"
bogdanm 0:eff01767de02 19 #include "nrf_soc.h"
bogdanm 0:eff01767de02 20 #include "mbed.h"
bogdanm 0:eff01767de02 21
bogdanm 0:eff01767de02 22 #if defined(ANT_STACK_SUPPORT_REQD) && defined(BLE_STACK_SUPPORT_REQD)
bogdanm 0:eff01767de02 23 #include "ant_interface.h"
Rohit Grover 37:c29c330d942c 24 #elif defined(ANT_STACK_SUPPORT_REQD)
bogdanm 0:eff01767de02 25 #include "ant_interface.h"
bogdanm 0:eff01767de02 26 #elif defined(BLE_STACK_SUPPORT_REQD)
bogdanm 0:eff01767de02 27 #include "ble.h"
bogdanm 0:eff01767de02 28 #endif
bogdanm 0:eff01767de02 29
bogdanm 0:eff01767de02 30
bogdanm 0:eff01767de02 31 static softdevice_evt_schedule_func_t m_evt_schedule_func; /**< Pointer to function for propagating SoftDevice events to the scheduler. */
bogdanm 0:eff01767de02 32
bogdanm 0:eff01767de02 33 #if defined (BLE_STACK_SUPPORT_REQD) || defined (ANT_STACK_SUPPORT_REQD)
bogdanm 0:eff01767de02 34 // The following two definition is needed only if ANT or BLE events are needed to be pulled from the stack.
bogdanm 0:eff01767de02 35 static uint8_t * m_evt_buffer; /**< Buffer for receiving events from the SoftDevice. */
bogdanm 0:eff01767de02 36 #endif
bogdanm 0:eff01767de02 37
bogdanm 0:eff01767de02 38 #ifdef BLE_STACK_SUPPORT_REQD
bogdanm 0:eff01767de02 39 static uint16_t m_ble_evt_buffer_size; /**< Size of BLE event buffer. */
bogdanm 0:eff01767de02 40 #endif
bogdanm 0:eff01767de02 41
bogdanm 0:eff01767de02 42 static volatile bool m_softdevice_enabled = false; /**< Variable to indicate whether the SoftDevice is enabled. */
bogdanm 0:eff01767de02 43
bogdanm 0:eff01767de02 44 #ifdef BLE_STACK_SUPPORT_REQD
bogdanm 0:eff01767de02 45 static ble_evt_handler_t m_ble_evt_handler; /**< Application event handler for handling BLE events. */
bogdanm 0:eff01767de02 46 #endif
bogdanm 0:eff01767de02 47
bogdanm 0:eff01767de02 48 #ifdef ANT_STACK_SUPPORT_REQD
bogdanm 0:eff01767de02 49 static ant_evt_handler_t m_ant_evt_handler; /**< Application event handler for handling ANT events. */
bogdanm 0:eff01767de02 50 #endif
bogdanm 0:eff01767de02 51
bogdanm 0:eff01767de02 52 static sys_evt_handler_t m_sys_evt_handler; /**< Application event handler for handling System (SOC) events. */
bogdanm 0:eff01767de02 53
bogdanm 0:eff01767de02 54
bogdanm 0:eff01767de02 55 /**@brief Callback function for asserts in the SoftDevice.
bogdanm 0:eff01767de02 56 *
bogdanm 0:eff01767de02 57 * @details A pointer to this function will be passed to the SoftDevice. This function will be
bogdanm 0:eff01767de02 58 * called if an ASSERT statement in the SoftDevice fails.
bogdanm 0:eff01767de02 59 *
bogdanm 0:eff01767de02 60 * @param[in] pc The value of the program counter when the ASSERT call failed.
bogdanm 0:eff01767de02 61 * @param[in] line_num Line number of the failing ASSERT call.
bogdanm 0:eff01767de02 62 * @param[in] file_name File name of the failing ASSERT call.
bogdanm 0:eff01767de02 63 */
bogdanm 0:eff01767de02 64 void softdevice_assertion_handler(uint32_t pc, uint16_t line_num, const uint8_t * file_name)
bogdanm 0:eff01767de02 65 {
bogdanm 0:eff01767de02 66 UNUSED_PARAMETER(pc);
bogdanm 0:eff01767de02 67 assert_nrf_callback(line_num, file_name);
bogdanm 0:eff01767de02 68 }
bogdanm 0:eff01767de02 69
bogdanm 0:eff01767de02 70
bogdanm 0:eff01767de02 71 void intern_softdevice_events_execute(void)
bogdanm 0:eff01767de02 72 {
bogdanm 0:eff01767de02 73 if (!m_softdevice_enabled)
bogdanm 0:eff01767de02 74 {
bogdanm 0:eff01767de02 75 // SoftDevice not enabled. This can be possible if the SoftDevice was enabled by the
bogdanm 0:eff01767de02 76 // application without using this module's API (i.e softdevice_handler_init)
bogdanm 0:eff01767de02 77
bogdanm 0:eff01767de02 78 return;
bogdanm 0:eff01767de02 79 }
bogdanm 0:eff01767de02 80
bogdanm 0:eff01767de02 81 bool no_more_soc_evts = (m_sys_evt_handler == NULL);
bogdanm 0:eff01767de02 82 #ifdef BLE_STACK_SUPPORT_REQD
bogdanm 0:eff01767de02 83 bool no_more_ble_evts = (m_ble_evt_handler == NULL);
bogdanm 0:eff01767de02 84 #endif
bogdanm 0:eff01767de02 85 #ifdef ANT_STACK_SUPPORT_REQD
bogdanm 0:eff01767de02 86 bool no_more_ant_evts = (m_ant_evt_handler == NULL);
bogdanm 0:eff01767de02 87 #endif
bogdanm 0:eff01767de02 88
bogdanm 0:eff01767de02 89 for (;;)
bogdanm 0:eff01767de02 90 {
bogdanm 0:eff01767de02 91 uint32_t err_code;
bogdanm 0:eff01767de02 92
bogdanm 0:eff01767de02 93 if (!no_more_soc_evts)
bogdanm 0:eff01767de02 94 {
bogdanm 0:eff01767de02 95 uint32_t evt_id;
bogdanm 0:eff01767de02 96
bogdanm 0:eff01767de02 97 // Pull event from SOC.
bogdanm 0:eff01767de02 98 err_code = sd_evt_get(&evt_id);
Rohit Grover 37:c29c330d942c 99
bogdanm 0:eff01767de02 100 if (err_code == NRF_ERROR_NOT_FOUND)
bogdanm 0:eff01767de02 101 {
bogdanm 0:eff01767de02 102 no_more_soc_evts = true;
bogdanm 0:eff01767de02 103 }
bogdanm 0:eff01767de02 104 else if (err_code != NRF_SUCCESS)
bogdanm 0:eff01767de02 105 {
bogdanm 0:eff01767de02 106 APP_ERROR_HANDLER(err_code);
bogdanm 0:eff01767de02 107 }
bogdanm 0:eff01767de02 108 else
bogdanm 0:eff01767de02 109 {
bogdanm 0:eff01767de02 110 // Call application's SOC event handler.
bogdanm 0:eff01767de02 111 m_sys_evt_handler(evt_id);
bogdanm 0:eff01767de02 112 }
bogdanm 0:eff01767de02 113 }
bogdanm 0:eff01767de02 114
bogdanm 0:eff01767de02 115 #ifdef BLE_STACK_SUPPORT_REQD
bogdanm 0:eff01767de02 116 // Fetch BLE Events.
bogdanm 0:eff01767de02 117 if (!no_more_ble_evts)
bogdanm 0:eff01767de02 118 {
bogdanm 0:eff01767de02 119 // Pull event from stack
bogdanm 0:eff01767de02 120 uint16_t evt_len = m_ble_evt_buffer_size;
bogdanm 0:eff01767de02 121
bogdanm 0:eff01767de02 122 err_code = sd_ble_evt_get(m_evt_buffer, &evt_len);
bogdanm 0:eff01767de02 123 if (err_code == NRF_ERROR_NOT_FOUND)
bogdanm 0:eff01767de02 124 {
bogdanm 0:eff01767de02 125 no_more_ble_evts = true;
bogdanm 0:eff01767de02 126 }
bogdanm 0:eff01767de02 127 else if (err_code != NRF_SUCCESS)
bogdanm 0:eff01767de02 128 {
bogdanm 0:eff01767de02 129 APP_ERROR_HANDLER(err_code);
bogdanm 0:eff01767de02 130 }
bogdanm 0:eff01767de02 131 else
bogdanm 0:eff01767de02 132 {
bogdanm 0:eff01767de02 133 // Call application's BLE stack event handler.
bogdanm 0:eff01767de02 134 m_ble_evt_handler((ble_evt_t *)m_evt_buffer);
bogdanm 0:eff01767de02 135 }
bogdanm 0:eff01767de02 136 }
bogdanm 0:eff01767de02 137 #endif
bogdanm 0:eff01767de02 138
bogdanm 0:eff01767de02 139 #ifdef ANT_STACK_SUPPORT_REQD
bogdanm 0:eff01767de02 140 // Fetch ANT Events.
bogdanm 0:eff01767de02 141 if (!no_more_ant_evts)
bogdanm 0:eff01767de02 142 {
bogdanm 0:eff01767de02 143 // Pull event from stack
bogdanm 0:eff01767de02 144 err_code = sd_ant_event_get(&((ant_evt_t *)m_evt_buffer)->channel,
bogdanm 0:eff01767de02 145 &((ant_evt_t *)m_evt_buffer)->event,
bogdanm 0:eff01767de02 146 ((ant_evt_t *)m_evt_buffer)->evt_buffer);
bogdanm 0:eff01767de02 147 if (err_code == NRF_ERROR_NOT_FOUND)
bogdanm 0:eff01767de02 148 {
bogdanm 0:eff01767de02 149 no_more_ant_evts = true;
bogdanm 0:eff01767de02 150 }
bogdanm 0:eff01767de02 151 else if (err_code != NRF_SUCCESS)
bogdanm 0:eff01767de02 152 {
bogdanm 0:eff01767de02 153 APP_ERROR_HANDLER(err_code);
bogdanm 0:eff01767de02 154 }
bogdanm 0:eff01767de02 155 else
bogdanm 0:eff01767de02 156 {
bogdanm 0:eff01767de02 157 // Call application's ANT stack event handler.
bogdanm 0:eff01767de02 158 m_ant_evt_handler((ant_evt_t *)m_evt_buffer);
bogdanm 0:eff01767de02 159 }
bogdanm 0:eff01767de02 160 }
bogdanm 0:eff01767de02 161 #endif
bogdanm 0:eff01767de02 162
bogdanm 0:eff01767de02 163 if (no_more_soc_evts)
bogdanm 0:eff01767de02 164 {
bogdanm 0:eff01767de02 165 // There are no remaining System (SOC) events to be fetched from the SoftDevice.
bogdanm 0:eff01767de02 166 #if defined(ANT_STACK_SUPPORT_REQD) && defined(BLE_STACK_SUPPORT_REQD)
bogdanm 0:eff01767de02 167 // Check if there are any remaining BLE and ANT events.
bogdanm 0:eff01767de02 168 if (no_more_ble_evts && no_more_ant_evts)
bogdanm 0:eff01767de02 169 {
bogdanm 0:eff01767de02 170 break;
bogdanm 0:eff01767de02 171 }
bogdanm 0:eff01767de02 172 #elif defined(BLE_STACK_SUPPORT_REQD)
bogdanm 0:eff01767de02 173 // Check if there are any remaining BLE events.
bogdanm 0:eff01767de02 174 if (no_more_ble_evts)
bogdanm 0:eff01767de02 175 {
bogdanm 0:eff01767de02 176 break;
bogdanm 0:eff01767de02 177 }
bogdanm 0:eff01767de02 178 #elif defined(ANT_STACK_SUPPORT_REQD)
bogdanm 0:eff01767de02 179 // Check if there are any remaining ANT events.
bogdanm 0:eff01767de02 180 if (no_more_ant_evts)
bogdanm 0:eff01767de02 181 {
bogdanm 0:eff01767de02 182 break;
bogdanm 0:eff01767de02 183 }
bogdanm 0:eff01767de02 184 #else
bogdanm 0:eff01767de02 185 // No need to check for BLE or ANT events since there is no support for BLE and ANT
bogdanm 0:eff01767de02 186 // required.
bogdanm 0:eff01767de02 187 break;
bogdanm 0:eff01767de02 188 #endif
bogdanm 0:eff01767de02 189 }
bogdanm 0:eff01767de02 190 }
bogdanm 0:eff01767de02 191 }
bogdanm 0:eff01767de02 192
bogdanm 0:eff01767de02 193
bogdanm 0:eff01767de02 194 uint32_t softdevice_handler_init(nrf_clock_lfclksrc_t clock_source,
bogdanm 0:eff01767de02 195 void * p_evt_buffer,
bogdanm 0:eff01767de02 196 uint16_t evt_buffer_size,
bogdanm 0:eff01767de02 197 softdevice_evt_schedule_func_t evt_schedule_func)
bogdanm 0:eff01767de02 198 {
bogdanm 0:eff01767de02 199 uint32_t err_code;
bogdanm 0:eff01767de02 200
bogdanm 0:eff01767de02 201 // Save configuration.
bogdanm 0:eff01767de02 202 #if defined (BLE_STACK_SUPPORT_REQD) || defined (ANT_STACK_SUPPORT_REQD)
bogdanm 0:eff01767de02 203 // Check that buffer is not NULL.
bogdanm 0:eff01767de02 204 if (p_evt_buffer == NULL)
bogdanm 0:eff01767de02 205 {
bogdanm 0:eff01767de02 206 return NRF_ERROR_INVALID_PARAM;
bogdanm 0:eff01767de02 207 }
Rohit Grover 37:c29c330d942c 208
bogdanm 0:eff01767de02 209 // Check that buffer is correctly aligned.
bogdanm 0:eff01767de02 210 if (!is_word_aligned(p_evt_buffer))
bogdanm 0:eff01767de02 211 {
bogdanm 0:eff01767de02 212 return NRF_ERROR_INVALID_PARAM;
bogdanm 0:eff01767de02 213 }
bogdanm 0:eff01767de02 214
bogdanm 0:eff01767de02 215 m_evt_buffer = (uint8_t *)p_evt_buffer;
bogdanm 0:eff01767de02 216 #else
Rohit Grover 37:c29c330d942c 217 // The variable p_evt_buffer is not needed if neither BLE Stack nor ANT stack support is
bogdanm 0:eff01767de02 218 // required.
bogdanm 0:eff01767de02 219 UNUSED_PARAMETER(p_evt_buffer);
bogdanm 0:eff01767de02 220 #endif
bogdanm 0:eff01767de02 221
Rohit Grover 37:c29c330d942c 222 #if defined (BLE_STACK_SUPPORT_REQD)
bogdanm 0:eff01767de02 223 m_ble_evt_buffer_size = evt_buffer_size;
bogdanm 0:eff01767de02 224 #else
bogdanm 0:eff01767de02 225 // The variable evt_buffer_size is not needed if BLE Stack support is NOT required.
bogdanm 0:eff01767de02 226 UNUSED_PARAMETER(evt_buffer_size);
bogdanm 0:eff01767de02 227 #endif
Rohit Grover 37:c29c330d942c 228
bogdanm 0:eff01767de02 229 m_evt_schedule_func = evt_schedule_func;
bogdanm 0:eff01767de02 230
bogdanm 0:eff01767de02 231 // Initialize SoftDevice.
Rohit Grover 37:c29c330d942c 232
bogdanm 0:eff01767de02 233 err_code = sd_softdevice_enable(clock_source, softdevice_assertion_handler);
bogdanm 0:eff01767de02 234 if (err_code != NRF_SUCCESS)
bogdanm 0:eff01767de02 235 {
bogdanm 0:eff01767de02 236 return err_code;
bogdanm 0:eff01767de02 237 }
bogdanm 0:eff01767de02 238
Rohit Grover 37:c29c330d942c 239 /**
Rohit Grover 37:c29c330d942c 240 * Using this call, the application can select whether to include the
Rohit Grover 37:c29c330d942c 241 * Service Changed characteristic in the GATT Server. The default in all
Rohit Grover 37:c29c330d942c 242 * previous releases has been to include the Service Changed characteristic,
Rohit Grover 37:c29c330d942c 243 * but this affects how GATT clients behave. Specifically, it requires
Rohit Grover 37:c29c330d942c 244 * clients to subscribe to this attribute and not to cache attribute handles
Rohit Grover 37:c29c330d942c 245 * between connections unless the devices are bonded. If the application
Rohit Grover 37:c29c330d942c 246 * does not need to change the structure of the GATT server attributes at
Rohit Grover 37:c29c330d942c 247 * runtime this adds unnecessary complexity to the interaction with peer
Rohit Grover 37:c29c330d942c 248 * clients. If the SoftDevice is enabled with the Service Changed
Rohit Grover 37:c29c330d942c 249 * Characteristics turned off, then clients are allowed to cache attribute
Rohit Grover 37:c29c330d942c 250 * handles making applications simpler on both sides.
Rohit Grover 37:c29c330d942c 251 */
Rohit Grover 37:c29c330d942c 252 ble_enable_params_t enableParams = {
Rohit Grover 37:c29c330d942c 253 .gatts_enable_params = {
Rohit Grover 37:c29c330d942c 254 .service_changed = 0
Rohit Grover 37:c29c330d942c 255 }
Rohit Grover 37:c29c330d942c 256 };
Rohit Grover 37:c29c330d942c 257 if ((err_code = sd_ble_enable(&enableParams)) != NRF_SUCCESS) {
Rohit Grover 37:c29c330d942c 258 return err_code;
Rohit Grover 37:c29c330d942c 259 }
Rohit Grover 37:c29c330d942c 260
Rohit Grover 37:c29c330d942c 261 ble_gap_addr_t addr;
Rohit Grover 37:c29c330d942c 262 if ((err_code = sd_ble_gap_address_get(&addr)) != NRF_SUCCESS) {
Rohit Grover 37:c29c330d942c 263 return err_code;
Rohit Grover 37:c29c330d942c 264 }
Rohit Grover 37:c29c330d942c 265 if ((err_code = sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &addr)) != NRF_SUCCESS) {
Rohit Grover 37:c29c330d942c 266 return err_code;
Rohit Grover 37:c29c330d942c 267 }
Rohit Grover 37:c29c330d942c 268
bogdanm 0:eff01767de02 269 m_softdevice_enabled = true;
bogdanm 0:eff01767de02 270 // Enable BLE event interrupt (interrupt priority has already been set by the stack).
bogdanm 0:eff01767de02 271 return sd_nvic_EnableIRQ(SWI2_IRQn);
bogdanm 0:eff01767de02 272 }
bogdanm 0:eff01767de02 273
bogdanm 0:eff01767de02 274
bogdanm 0:eff01767de02 275 uint32_t softdevice_handler_sd_disable(void)
bogdanm 0:eff01767de02 276 {
bogdanm 0:eff01767de02 277 uint32_t err_code = sd_softdevice_disable();
Rohit Grover 37:c29c330d942c 278
bogdanm 0:eff01767de02 279 m_softdevice_enabled = !(err_code == NRF_SUCCESS);
bogdanm 0:eff01767de02 280
bogdanm 0:eff01767de02 281 return err_code;
bogdanm 0:eff01767de02 282 }
bogdanm 0:eff01767de02 283
bogdanm 0:eff01767de02 284
bogdanm 0:eff01767de02 285 #ifdef BLE_STACK_SUPPORT_REQD
bogdanm 0:eff01767de02 286 uint32_t softdevice_ble_evt_handler_set(ble_evt_handler_t ble_evt_handler)
bogdanm 0:eff01767de02 287 {
bogdanm 0:eff01767de02 288 if (ble_evt_handler == NULL)
bogdanm 0:eff01767de02 289 {
bogdanm 0:eff01767de02 290 return NRF_ERROR_NULL;
bogdanm 0:eff01767de02 291 }
bogdanm 0:eff01767de02 292
bogdanm 0:eff01767de02 293 m_ble_evt_handler = ble_evt_handler;
bogdanm 0:eff01767de02 294
bogdanm 0:eff01767de02 295 return NRF_SUCCESS;
bogdanm 0:eff01767de02 296 }
bogdanm 0:eff01767de02 297 #endif
bogdanm 0:eff01767de02 298
bogdanm 0:eff01767de02 299
bogdanm 0:eff01767de02 300 #ifdef ANT_STACK_SUPPORT_REQD
bogdanm 0:eff01767de02 301 uint32_t softdevice_ant_evt_handler_set(ant_evt_handler_t ant_evt_handler)
bogdanm 0:eff01767de02 302 {
bogdanm 0:eff01767de02 303 if (ant_evt_handler == NULL)
bogdanm 0:eff01767de02 304 {
bogdanm 0:eff01767de02 305 return NRF_ERROR_NULL;
bogdanm 0:eff01767de02 306 }
bogdanm 0:eff01767de02 307
bogdanm 0:eff01767de02 308 m_ant_evt_handler = ant_evt_handler;
bogdanm 0:eff01767de02 309
bogdanm 0:eff01767de02 310 return NRF_SUCCESS;
bogdanm 0:eff01767de02 311 }
bogdanm 0:eff01767de02 312 #endif
bogdanm 0:eff01767de02 313
bogdanm 0:eff01767de02 314
bogdanm 0:eff01767de02 315 uint32_t softdevice_sys_evt_handler_set(sys_evt_handler_t sys_evt_handler)
bogdanm 0:eff01767de02 316 {
bogdanm 0:eff01767de02 317 if (sys_evt_handler == NULL)
bogdanm 0:eff01767de02 318 {
bogdanm 0:eff01767de02 319 return NRF_ERROR_NULL;
bogdanm 0:eff01767de02 320 }
bogdanm 0:eff01767de02 321
bogdanm 0:eff01767de02 322 m_sys_evt_handler = sys_evt_handler;
bogdanm 0:eff01767de02 323
bogdanm 0:eff01767de02 324 return NRF_SUCCESS;
bogdanm 0:eff01767de02 325 }
bogdanm 0:eff01767de02 326
bogdanm 0:eff01767de02 327
bogdanm 0:eff01767de02 328 /**@brief Function for handling the Application's BLE Stack events interrupt.
bogdanm 0:eff01767de02 329 *
bogdanm 0:eff01767de02 330 * @details This function is called whenever an event is ready to be pulled.
bogdanm 0:eff01767de02 331 */
bogdanm 0:eff01767de02 332 extern "C" void SWI2_IRQHandler(void)
bogdanm 0:eff01767de02 333 {
bogdanm 0:eff01767de02 334 if (m_evt_schedule_func != NULL)
bogdanm 0:eff01767de02 335 {
bogdanm 0:eff01767de02 336 uint32_t err_code = m_evt_schedule_func();
bogdanm 0:eff01767de02 337 APP_ERROR_CHECK(err_code);
bogdanm 0:eff01767de02 338 }
bogdanm 0:eff01767de02 339 else
bogdanm 0:eff01767de02 340 {
bogdanm 0:eff01767de02 341 intern_softdevice_events_execute();
bogdanm 0:eff01767de02 342 }
bogdanm 0:eff01767de02 343 }