aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble')
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_advertising/ble_advertising.c790
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_advertising/ble_advertising.h337
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_db_discovery/ble_db_discovery.c986
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_db_discovery/ble_db_discovery.h235
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_dtm/ble_dtm.c957
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_dtm/ble_dtm.h237
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_dtm/ble_dtm_hw.h103
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_dtm/ble_dtm_hw_nrf51.c120
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_dtm/ble_dtm_hw_nrf52.c128
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_lesc/ble_lesc.c443
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_lesc/ble_lesc.h128
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_link_ctx_manager/ble_link_ctx_manager.c79
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_link_ctx_manager/ble_link_ctx_manager.h127
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_racp/ble_racp.c87
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_racp/ble_racp.h136
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_radio_notification/ble_radio_notification.c87
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_radio_notification/ble_radio_notification.h82
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_app_attr_get.c367
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_app_attr_get.h66
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_attr_parser.c392
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_attr_parser.h77
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_tx_buffer.c113
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_tx_buffer.h103
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/nrf_ble_ancs_c.c652
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/nrf_ble_ancs_c.h604
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ans_c/ble_ans_c.c575
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ans_c/ble_ans_c.h409
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bas/ble_bas.c384
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bas/ble_bas.h194
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bas_c/ble_bas_c.c405
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bas_c/ble_bas_c.h274
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bps/ble_bps.c475
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bps/ble_bps.h221
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cscs/ble_cscs.c489
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cscs/ble_cscs.h218
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cscs/ble_sc_ctrlpt.c686
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cscs/ble_sc_ctrlpt.h247
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cts_c/ble_cts_c.c357
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cts_c/ble_cts_c.h284
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dfu/ble_dfu.c337
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dfu/ble_dfu.h251
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dfu/ble_dfu_bonded.c407
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dfu/ble_dfu_unbonded.c325
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dis/ble_dis.c304
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dis/ble_dis.h134
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dis_c/ble_dis_c.c557
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dis_c/ble_dis_c.h308
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_escs/escs_defs.h133
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_escs/nrf_ble_escs.c675
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_escs/nrf_ble_escs.h259
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_gls/ble_gls.c1314
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_gls/ble_gls.h323
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_gls/ble_gls_db.c143
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_gls/ble_gls_db.h121
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hids/ble_hids.c1794
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hids/ble_hids.h430
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hrs/ble_hrs.c479
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hrs/ble_hrs.h266
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hrs_c/ble_hrs_c.c384
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hrs_c/ble_hrs_c.h295
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hts/ble_hts.c462
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hts/ble_hts.h219
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ias/ble_ias.c242
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ias/ble_ias.h194
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ias_c/ble_ias_c.c214
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ias_c/ble_ias_c.h237
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ipsp/ble_ipsp.c981
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ipsp/ble_ipsp.h253
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lbs/ble_lbs.c235
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lbs/ble_lbs.h161
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lbs_c/ble_lbs_c.c394
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lbs_c/ble_lbs_c.h254
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lls/ble_lls.c260
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lls/ble_lls.h175
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_nus/ble_nus.c440
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_nus/ble_nus.h244
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_nus_c/ble_nus_c.c265
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_nus_c/ble_nus_c.h272
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_rscs/ble_rscs.c417
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_rscs/ble_rscs.h201
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_rscs_c/ble_rscs_c.c390
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_rscs_c/ble_rscs_c.h231
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_tps/ble_tps.c170
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_tps/ble_tps.h138
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es.h198
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv.c342
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv.h129
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_frame.c120
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_frame.h73
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_timing.c220
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_timing.h97
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_timing_resolver.c145
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_timing_resolver.h96
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_battery_voltage.h66
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_battery_voltage_saadc.c104
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_flash.c340
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_flash.h177
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts.c188
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts.h109
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts_read.c246
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts_read.h73
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts_write.c254
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts_write.h71
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_security.c596
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_security.h238
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_slot.c440
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_slot.h202
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_slot_reg.c181
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_slot_reg.h90
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_stopwatch.c106
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_stopwatch.h71
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_tlm.c140
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_tlm.h76
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_util.h137
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/nrf_ble_es.c438
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/nrf_ble_es.h99
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_common.h94
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_cp.c821
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_cp.h255
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_db.c151
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_db.h122
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_lns.c1014
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_lns.h381
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_hvx_buffering.c102
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_hvx_buffering.h104
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots.c249
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots.h472
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_l2cap.c437
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_l2cap.h117
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_oacp.c606
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_oacp.h90
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_object.c577
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_object.h86
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_gatts_c/nrf_ble_gatts_c.c276
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_gatts_c/nrf_ble_gatts_c.h229
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_db.c143
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_db.h118
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_meas.c248
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_meas.h103
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_racp.c866
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_racp.h99
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_socp.c431
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_socp.h107
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_sst.c235
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_sst.h115
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/nrf_ble_cgms.c504
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/nrf_ble_cgms.h453
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c.c374
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c.h320
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c_l2cap.c244
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c_l2cap.h101
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c_oacp.c253
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c_oacp.h126
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/ots_tx_buffer.c113
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/ots_tx_buffer.h103
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/nrf_ble_bms/nrf_ble_bms.c622
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/nrf_ble_bms/nrf_ble_bms.h316
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_advdata.c827
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_advdata.h326
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_conn_params.c572
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_conn_params.h156
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_conn_state.c481
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_conn_state.h345
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_date_time.h113
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_gatt_db.h92
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_sensor_location.h76
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_srv_common.c237
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_srv_common.h409
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/nrf_ble_gatt/nrf_ble_gatt.c550
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/nrf_ble_gatt/nrf_ble_gatt.h242
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/nrf_ble_qwr/nrf_ble_qwr.c488
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/nrf_ble_qwr/nrf_ble_qwr.h246
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatt_cache_manager.c578
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatt_cache_manager.h113
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatts_cache_manager.c347
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatts_cache_manager.h163
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/id_manager.c890
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/id_manager.h327
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_data_storage.c678
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_data_storage.h270
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_database.c814
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_database.h309
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_id.c202
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_id.h167
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager.c983
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager.h781
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager_internal.h207
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager_types.h354
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_buffer.c151
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_buffer.h159
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_mutex.c144
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_mutex.h125
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_dispatcher.c1110
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_dispatcher.h166
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_manager.c675
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_manager.h181
196 files changed, 62035 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_advertising/ble_advertising.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_advertising/ble_advertising.c
new file mode 100644
index 0000000..e09c2dd
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_advertising/ble_advertising.c
@@ -0,0 +1,790 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_ADVERTISING)
+#include "ble_advdata.h"
+#include "ble_advertising.h"
+#include "nrf_soc.h"
+#include "nrf_log.h"
+#include "nrf_fstorage.h"
+#include "sdk_errors.h"
+#include "nrf_sdh_ble.h"
+#include "nrf_sdh_soc.h"
+
+#define BLE_ADV_MODES (5) /**< Total number of possible advertising modes. */
+
+
+/**@brief Function for checking if the whitelist is in use.
+ *
+ * @param[in] p_advertising Advertising module instance.
+ */
+static bool whitelist_has_entries(ble_advertising_t * const p_advertising)
+{
+ return p_advertising->whitelist_in_use;
+}
+
+
+/**@brief Function for checking if an address is valid.
+ *
+ * @param[in] p_addr Pointer to a bluetooth address.
+ */
+static bool addr_is_valid(uint8_t const * const p_addr)
+{
+ for (uint32_t i = 0; i < BLE_GAP_ADDR_LEN; i++)
+ {
+ if (p_addr[i] != 0)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/**@brief Function for checking the next advertising mode.
+ *
+ * @param[in] adv_mode Current advertising mode.
+ */
+static ble_adv_mode_t adv_mode_next_get(ble_adv_mode_t adv_mode)
+{
+ return (ble_adv_mode_t)((adv_mode + 1) % BLE_ADV_MODES);
+}
+
+
+/**@brief Function for handling the Connected event.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_connected(ble_advertising_t * const p_advertising, ble_evt_t const * p_ble_evt)
+{
+ if (p_ble_evt->evt.gap_evt.params.connected.role == BLE_GAP_ROLE_PERIPH)
+ {
+ p_advertising->current_slave_link_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+ }
+}
+
+
+/**@brief Function for handling the Disconnected event.
+ *
+ * @param[in] p_advertising Advertising module instance.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_disconnected(ble_advertising_t * const p_advertising, ble_evt_t const * p_ble_evt)
+{
+ uint32_t ret;
+
+ p_advertising->whitelist_temporarily_disabled = false;
+
+ if (p_ble_evt->evt.gap_evt.conn_handle == p_advertising->current_slave_link_conn_handle &&
+ p_advertising->adv_modes_config.ble_adv_on_disconnect_disabled == false)
+ {
+ ret = ble_advertising_start(p_advertising, BLE_ADV_MODE_DIRECTED_HIGH_DUTY);
+ if ((ret != NRF_SUCCESS) && (p_advertising->error_handler != NULL))
+ {
+ p_advertising->error_handler(ret);
+ }
+ }
+}
+
+
+/**@brief Function for handling the Timeout event.
+ *
+ * @param[in] p_advertising Advertising module instance.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_terminated(ble_advertising_t * const p_advertising, ble_evt_t const * p_ble_evt)
+{
+ ret_code_t ret;
+
+ if (p_ble_evt->header.evt_id != BLE_GAP_EVT_ADV_SET_TERMINATED)
+ {
+ // Nothing to do.
+ return;
+ }
+
+ if ( p_ble_evt->evt.gap_evt.params.adv_set_terminated.reason == BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_TIMEOUT
+ ||p_ble_evt->evt.gap_evt.params.adv_set_terminated.reason == BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_LIMIT_REACHED)
+ {
+ // Start advertising in the next mode.
+ ret = ble_advertising_start(p_advertising, adv_mode_next_get(p_advertising->adv_mode_current));
+
+ if ((ret != NRF_SUCCESS) && (p_advertising->error_handler != NULL))
+ {
+ p_advertising->error_handler(ret);
+ }
+ }
+}
+
+
+/** @brief Function to determine if a flash write operation in in progress.
+ *
+ * @return true if a flash operation is in progress, false if not.
+ */
+static bool flash_access_in_progress()
+{
+ return nrf_fstorage_is_busy(NULL);
+}
+
+
+/**@brief Get the next available advertising mode.
+ *
+ * @param[in] p_advertising Advertising module instance.
+ * @param[in] adv_mode Requested advertising mode.
+ *
+ * @returns adv_mode if possible, or the best available mode if not.
+ */
+static ble_adv_mode_t adv_mode_next_avail_get(ble_advertising_t * const p_advertising,
+ ble_adv_mode_t adv_mode)
+{
+ bool peer_addr_is_valid = addr_is_valid(p_advertising->peer_address.addr);
+
+ // If a mode is disabled, continue to the next mode.
+
+ switch (adv_mode)
+ {
+ case BLE_ADV_MODE_DIRECTED_HIGH_DUTY:
+ if ( (p_advertising->adv_modes_config.ble_adv_directed_high_duty_enabled)
+ && (!p_advertising->adv_modes_config.ble_adv_extended_enabled)
+ && (peer_addr_is_valid))
+ {
+ return BLE_ADV_MODE_DIRECTED_HIGH_DUTY;
+ }
+ // Fallthrough.
+
+ case BLE_ADV_MODE_DIRECTED:
+ if ((p_advertising->adv_modes_config.ble_adv_directed_enabled) && peer_addr_is_valid)
+ {
+ return BLE_ADV_MODE_DIRECTED;
+ }
+ // Fallthrough.
+
+ case BLE_ADV_MODE_FAST:
+ if (p_advertising->adv_modes_config.ble_adv_fast_enabled)
+ {
+ return BLE_ADV_MODE_FAST;
+ }
+ // Fallthrough.
+
+ case BLE_ADV_MODE_SLOW:
+ if (p_advertising->adv_modes_config.ble_adv_slow_enabled)
+ {
+ return BLE_ADV_MODE_SLOW;
+ }
+ // Fallthrough.
+
+ default:
+ return BLE_ADV_MODE_IDLE;
+ }
+}
+
+
+/**@brief Function for starting high duty directed advertising.
+ *
+ * @param[in] p_advertising Advertising instance.
+ * @param[out] p_adv_params Advertising parameters.
+ *
+ * @return NRF_SUCCESS
+ */
+static ret_code_t set_adv_mode_directed_high_duty(ble_advertising_t * const p_advertising,
+ ble_gap_adv_params_t * p_adv_params)
+{
+ p_advertising->adv_evt = BLE_ADV_EVT_DIRECTED_HIGH_DUTY;
+ p_advertising->p_adv_data = NULL;
+
+ p_adv_params->p_peer_addr = &(p_advertising->peer_address);
+ p_adv_params->interval = 0;
+ p_adv_params->properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE;
+ p_adv_params->duration = BLE_GAP_ADV_TIMEOUT_HIGH_DUTY_MAX;
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for starting directed slow advertising.
+ *
+ * @param[in] p_advertising Advertising module instance.
+ * @param[out] p_adv_params Advertising parameters.
+ *
+ * @return NRF_SUCCESS
+ */
+static ret_code_t set_adv_mode_directed(ble_advertising_t * const p_advertising,
+ ble_gap_adv_params_t * p_adv_params)
+{
+ p_advertising->adv_evt = BLE_ADV_EVT_DIRECTED;
+#if !defined (S112)
+ if (p_advertising->adv_modes_config.ble_adv_extended_enabled)
+ {
+ p_adv_params->properties.type = BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_DIRECTED;
+ }
+ else
+ {
+#endif // !defined (S112)
+ p_adv_params->properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED;
+#if !defined (S112)
+ }
+#endif // !defined (S112)
+ p_adv_params->duration = p_advertising->adv_modes_config.ble_adv_directed_timeout;
+
+ p_advertising->p_adv_data = NULL;
+
+ p_adv_params->p_peer_addr = &p_advertising->peer_address;
+ p_adv_params->interval = p_advertising->adv_modes_config.ble_adv_directed_interval;
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for indicating whether to use whitelist for advertising.
+ *
+ * @param[in] p_advertising Advertising module instance.
+ *
+ * @return Whether to use whitelist.
+ */
+static bool use_whitelist(ble_advertising_t * const p_advertising)
+{
+ return((p_advertising->adv_modes_config.ble_adv_whitelist_enabled) &&
+ (!p_advertising->whitelist_temporarily_disabled) &&
+ (whitelist_has_entries(p_advertising)));
+}
+
+
+/**@brief Function for setting new advertising flags in the advertising parameters.
+ *
+ * @param[in] p_advertising Advertising module instance.
+ * @param[in] flags New flags.
+ *
+ * @return Any error from @ref sd_ble_gap_adv_set_configure.
+ */
+static ret_code_t flags_set(ble_advertising_t * const p_advertising, uint8_t flags)
+{
+ uint8_t * p_flags = ble_advdata_parse(p_advertising->adv_data.adv_data.p_data,
+ p_advertising->adv_data.adv_data.len,
+ BLE_GAP_AD_TYPE_FLAGS);
+
+ if (p_flags != NULL)
+ {
+ *p_flags = flags;
+ }
+
+ return sd_ble_gap_adv_set_configure(&p_advertising->adv_handle, &p_advertising->adv_data, &p_advertising->adv_params);
+}
+
+
+/**@brief Function for starting fast advertising.
+ *
+ * @param[in] p_advertising Advertising module instance.
+ * @param[out] p_adv_params Advertising parameters.
+ *
+ * @return NRF_SUCCESS or an error from @ref flags_set().
+ */
+static ret_code_t set_adv_mode_fast(ble_advertising_t * const p_advertising,
+ ble_gap_adv_params_t * p_adv_params)
+{
+ ret_code_t ret;
+
+ p_adv_params->interval = p_advertising->adv_modes_config.ble_adv_fast_interval;
+ p_adv_params->duration = p_advertising->adv_modes_config.ble_adv_fast_timeout;
+
+#if !defined (S112)
+ if (p_advertising->adv_modes_config.ble_adv_extended_enabled)
+ {
+ p_advertising->adv_params.properties.type = BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED;
+ }
+ else
+ {
+#endif // !defined (S112)
+ p_advertising->adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
+#if !defined (S112)
+ }
+#endif // !defined (S112)
+
+ if (use_whitelist(p_advertising))
+ {
+ p_adv_params->filter_policy = BLE_GAP_ADV_FP_FILTER_CONNREQ;
+
+ // Set correct flags.
+ ret = flags_set(p_advertising, BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED);
+ VERIFY_SUCCESS(ret);
+
+ p_advertising->adv_evt = BLE_ADV_EVT_FAST_WHITELIST;
+ }
+ else
+ {
+ p_advertising->adv_evt = BLE_ADV_EVT_FAST;
+ }
+ p_advertising->p_adv_data = &(p_advertising->adv_data);
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for starting slow advertising.
+ *
+ * @param[in] p_advertising Advertising module instance.
+ * @param[out] p_adv_params Advertising parameters.
+ *
+ * @return NRF_SUCCESS or an error from @ref flags_set().
+ */
+static ret_code_t set_adv_mode_slow(ble_advertising_t * const p_advertising,
+ ble_gap_adv_params_t * p_adv_params)
+{
+ ret_code_t ret;
+
+ p_adv_params->interval = p_advertising->adv_modes_config.ble_adv_slow_interval;
+ p_adv_params->duration = p_advertising->adv_modes_config.ble_adv_slow_timeout;
+
+#if !defined (S112)
+ if (p_advertising->adv_modes_config.ble_adv_extended_enabled)
+ {
+ p_advertising->adv_params.properties.type = BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED;
+ }
+ else
+ {
+#endif // !defined (S112)
+ p_advertising->adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
+#if !defined (S112)
+ }
+#endif // !defined (S112)
+
+ if (use_whitelist(p_advertising))
+ {
+ p_adv_params->filter_policy = BLE_GAP_ADV_FP_FILTER_CONNREQ;
+
+ // Set correct flags.
+ ret = flags_set(p_advertising, BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED);
+ VERIFY_SUCCESS(ret);
+
+ p_advertising->adv_evt = BLE_ADV_EVT_SLOW_WHITELIST;
+ }
+ else
+ {
+ p_advertising->adv_evt = BLE_ADV_EVT_SLOW;
+ }
+ p_advertising->p_adv_data = &(p_advertising->adv_data);
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for checking if an advertising module configuration is legal.
+ *
+ * @details Advertising module can not be initialized if high duty directed advertising is used
+ * together with extended advertising.
+ *
+ * @param[in] p_config Pointer to the configuration.
+ *
+ * @return True If the configuration is valid.
+ * @return False If the configuration is invalid.
+ */
+static bool config_is_valid(ble_adv_modes_config_t const * const p_config)
+{
+ if ((p_config->ble_adv_directed_high_duty_enabled == true) &&
+ (p_config->ble_adv_extended_enabled == true))
+ {
+ return false;
+ }
+#if !defined (S140)
+ else if ( p_config->ble_adv_primary_phy == BLE_GAP_PHY_CODED ||
+ p_config->ble_adv_secondary_phy == BLE_GAP_PHY_CODED)
+ {
+ return false;
+ }
+#endif // !defined (S140)
+ else
+ {
+ return true;
+ }
+}
+
+
+void ble_advertising_conn_cfg_tag_set(ble_advertising_t * const p_advertising,
+ uint8_t ble_cfg_tag)
+{
+ p_advertising->conn_cfg_tag = ble_cfg_tag;
+}
+
+
+uint32_t ble_advertising_init(ble_advertising_t * const p_advertising,
+ ble_advertising_init_t const * const p_init)
+{
+ uint32_t ret;
+ if ((p_init == NULL) || (p_advertising == NULL))
+ {
+ return NRF_ERROR_NULL;
+ }
+ if (!config_is_valid(&p_init->config))
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ p_advertising->adv_mode_current = BLE_ADV_MODE_IDLE;
+ p_advertising->adv_modes_config = p_init->config;
+ p_advertising->conn_cfg_tag = BLE_CONN_CFG_TAG_DEFAULT;
+ p_advertising->evt_handler = p_init->evt_handler;
+ p_advertising->error_handler = p_init->error_handler;
+ p_advertising->current_slave_link_conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_advertising->p_adv_data = &p_advertising->adv_data;
+
+ memset(&p_advertising->peer_address, 0, sizeof(p_advertising->peer_address));
+
+ // Copy advertising data.
+ if (!p_advertising->initialized)
+ {
+ p_advertising->adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET;
+ }
+ p_advertising->adv_data.adv_data.p_data = p_advertising->enc_advdata;
+ p_advertising->adv_data.adv_data.len = BLE_GAP_ADV_SET_DATA_SIZE_MAX;
+
+ ret = ble_advdata_encode(&p_init->advdata, p_advertising->enc_advdata, &p_advertising->adv_data.adv_data.len);
+ VERIFY_SUCCESS(ret);
+
+ if (&p_init->srdata != NULL)
+ {
+ p_advertising->adv_data.scan_rsp_data.p_data = p_advertising->enc_scan_rsp_data;
+ p_advertising->adv_data.scan_rsp_data.len = BLE_GAP_ADV_SET_DATA_SIZE_MAX;
+
+ ret = ble_advdata_encode(&p_init->srdata,
+ p_advertising->adv_data.scan_rsp_data.p_data,
+ &p_advertising->adv_data.scan_rsp_data.len);
+ VERIFY_SUCCESS(ret);
+ }
+ else
+ {
+ p_advertising->adv_data.scan_rsp_data.p_data = NULL;
+ p_advertising->adv_data.scan_rsp_data.len = 0;
+ }
+
+ // Configure a initial advertising configuration. The advertising data and and advertising
+ // parameters will be changed later when we call @ref ble_advertising_start, but must be set
+ // to legal values here to define an advertising handle.
+ p_advertising->adv_params.primary_phy = BLE_GAP_PHY_1MBPS;
+ p_advertising->adv_params.duration = p_advertising->adv_modes_config.ble_adv_fast_timeout;
+ p_advertising->adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
+ p_advertising->adv_params.p_peer_addr = NULL;
+ p_advertising->adv_params.filter_policy = BLE_GAP_ADV_FP_ANY;
+ p_advertising->adv_params.interval = p_advertising->adv_modes_config.ble_adv_fast_interval;
+
+ ret = sd_ble_gap_adv_set_configure(&p_advertising->adv_handle, NULL, &p_advertising->adv_params);
+ VERIFY_SUCCESS(ret);
+
+ p_advertising->initialized = true;
+ return ret;
+}
+
+
+/**@brief Function for checking that a phy define value matches one of the valid phys from the SD.
+ *
+ * @param[in] PHY to be validated.
+ *
+ * @retval true If the PHY value is valid (1mbit, 2mbit, coded).
+ * @retval false If the PHY value is invalid.
+ */
+static bool phy_is_valid(uint32_t const * const p_phy)
+{
+ if ((*p_phy) == BLE_GAP_PHY_1MBPS ||
+ (*p_phy) == BLE_GAP_PHY_2MBPS
+#if defined (S140)
+ || (*p_phy) == BLE_GAP_PHY_CODED
+#endif // !defined (S140)
+ )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+uint32_t ble_advertising_start(ble_advertising_t * const p_advertising,
+ ble_adv_mode_t advertising_mode)
+{
+ uint32_t ret;
+
+ if (p_advertising->initialized == false)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ p_advertising->adv_mode_current = advertising_mode;
+
+ // Delay starting advertising until the flash operations are complete.
+ if (flash_access_in_progress())
+ {
+ p_advertising->advertising_start_pending = true;
+ return NRF_SUCCESS;
+ }
+
+ memset(&p_advertising->peer_address, 0, sizeof(p_advertising->peer_address));
+
+ if ( ((p_advertising->adv_modes_config.ble_adv_directed_high_duty_enabled) && (p_advertising->adv_mode_current == BLE_ADV_MODE_DIRECTED_HIGH_DUTY))
+ ||((p_advertising->adv_modes_config.ble_adv_directed_enabled) && (p_advertising->adv_mode_current == BLE_ADV_MODE_DIRECTED_HIGH_DUTY))
+ ||((p_advertising->adv_modes_config.ble_adv_directed_enabled) && (p_advertising->adv_mode_current == BLE_ADV_MODE_DIRECTED))
+ )
+ {
+ if (p_advertising->evt_handler != NULL)
+ {
+ p_advertising->peer_addr_reply_expected = true;
+ p_advertising->evt_handler(BLE_ADV_EVT_PEER_ADDR_REQUEST);
+ }
+ else
+ {
+ p_advertising->peer_addr_reply_expected = false;
+ }
+ }
+
+ p_advertising->adv_mode_current = adv_mode_next_avail_get(p_advertising, advertising_mode);
+
+ // Fetch the whitelist.
+ if ((p_advertising->evt_handler != NULL) &&
+ (p_advertising->adv_mode_current == BLE_ADV_MODE_FAST || p_advertising->adv_mode_current == BLE_ADV_MODE_SLOW) &&
+ (p_advertising->adv_modes_config.ble_adv_whitelist_enabled) &&
+ (!p_advertising->whitelist_temporarily_disabled))
+ {
+ p_advertising->whitelist_in_use = false;
+ p_advertising->whitelist_reply_expected = true;
+ p_advertising->evt_handler(BLE_ADV_EVT_WHITELIST_REQUEST);
+ }
+ else
+ {
+ p_advertising->whitelist_reply_expected = false;
+ }
+
+ // Initialize advertising parameters with default values.
+ memset(&p_advertising->adv_params, 0, sizeof(p_advertising->adv_params));
+
+ p_advertising->adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
+
+ // Use 1MBIT as primary phy if no phy was selected.
+ if (phy_is_valid(&p_advertising->adv_modes_config.ble_adv_primary_phy))
+ {
+ p_advertising->adv_params.primary_phy = p_advertising->adv_modes_config.ble_adv_primary_phy;
+ }
+ else
+ {
+ p_advertising->adv_params.primary_phy = BLE_GAP_PHY_1MBPS;
+ }
+
+ if (p_advertising->adv_modes_config.ble_adv_extended_enabled)
+ {
+ // Use 1MBIT as secondary phy if no phy was selected.
+ if (phy_is_valid(&p_advertising->adv_modes_config.ble_adv_primary_phy))
+ {
+ p_advertising->adv_params.secondary_phy = p_advertising->adv_modes_config.ble_adv_secondary_phy;
+ }
+ else
+ {
+ p_advertising->adv_params.secondary_phy = BLE_GAP_PHY_1MBPS;
+ }
+ }
+ p_advertising->adv_params.filter_policy = BLE_GAP_ADV_FP_ANY;
+
+ // Set advertising parameters and events according to selected advertising mode.
+ switch (p_advertising->adv_mode_current)
+ {
+ case BLE_ADV_MODE_DIRECTED_HIGH_DUTY:
+ ret = set_adv_mode_directed_high_duty(p_advertising, &p_advertising->adv_params);
+ break;
+
+ case BLE_ADV_MODE_DIRECTED:
+ ret = set_adv_mode_directed(p_advertising, &p_advertising->adv_params);
+ break;
+
+ case BLE_ADV_MODE_FAST:
+ ret = set_adv_mode_fast(p_advertising, &p_advertising->adv_params);
+ break;
+
+ case BLE_ADV_MODE_SLOW:
+ ret = set_adv_mode_slow(p_advertising, &p_advertising->adv_params);
+ break;
+
+ case BLE_ADV_MODE_IDLE:
+ p_advertising->adv_evt = BLE_ADV_EVT_IDLE;
+ break;
+
+ default:
+ break;
+ }
+
+ if (p_advertising->adv_mode_current != BLE_ADV_MODE_IDLE)
+ {
+
+ ret = sd_ble_gap_adv_set_configure(&p_advertising->adv_handle, p_advertising->p_adv_data, &p_advertising->adv_params);
+ if (ret != NRF_SUCCESS)
+ {
+ return ret;
+ }
+ ret = sd_ble_gap_adv_start(p_advertising->adv_handle, p_advertising->conn_cfg_tag);
+
+ if (ret != NRF_SUCCESS)
+ {
+ return ret;
+ }
+ }
+
+ if (p_advertising->evt_handler != NULL)
+ {
+ p_advertising->evt_handler(p_advertising->adv_evt);
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+void ble_advertising_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ ble_advertising_t * p_advertising = (ble_advertising_t *)p_context;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ on_connected(p_advertising, p_ble_evt);
+ break;
+
+ // Upon disconnection, whitelist will be activated and direct advertising is started.
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnected(p_advertising, p_ble_evt);
+ break;
+
+ // Upon terminated advertising (time-out), the next advertising mode is started.
+ case BLE_GAP_EVT_ADV_SET_TERMINATED:
+ on_terminated(p_advertising, p_ble_evt);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+void ble_advertising_on_sys_evt(uint32_t evt_id, void * p_context)
+{
+ ble_advertising_t * p_advertising = (ble_advertising_t *)p_context;
+
+ switch (evt_id)
+ {
+ //When a flash operation finishes, re-attempt to start advertising operations.
+ case NRF_EVT_FLASH_OPERATION_SUCCESS:
+ case NRF_EVT_FLASH_OPERATION_ERROR:
+ {
+ if (p_advertising->advertising_start_pending)
+ {
+ p_advertising->advertising_start_pending = false;
+ ret_code_t ret = ble_advertising_start(p_advertising,
+ p_advertising->adv_mode_current);
+
+ if ((ret != NRF_SUCCESS) && (p_advertising->error_handler != NULL))
+ {
+ p_advertising->error_handler(ret);
+ }
+ }
+ } break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+
+uint32_t ble_advertising_peer_addr_reply(ble_advertising_t * const p_advertising,
+ ble_gap_addr_t * p_peer_address)
+{
+ if (!p_advertising->peer_addr_reply_expected)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ p_advertising->peer_addr_reply_expected = false;
+
+ memcpy(&p_advertising->peer_address, p_peer_address, sizeof(p_advertising->peer_address));
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_advertising_whitelist_reply(ble_advertising_t * const p_advertising,
+ ble_gap_addr_t const * p_gap_addrs,
+ uint32_t addr_cnt,
+ ble_gap_irk_t const * p_gap_irks,
+ uint32_t irk_cnt)
+{
+ if (!p_advertising->whitelist_reply_expected)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ p_advertising->whitelist_reply_expected = false;
+ p_advertising->whitelist_in_use = ((addr_cnt > 0) || (irk_cnt > 0));
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_advertising_restart_without_whitelist(ble_advertising_t * const p_advertising)
+{
+ ret_code_t ret;
+
+ (void) sd_ble_gap_adv_stop(p_advertising->adv_handle);
+
+ p_advertising->whitelist_temporarily_disabled = true;
+ p_advertising->whitelist_in_use = false;
+ p_advertising->adv_params.filter_policy = BLE_GAP_ADV_FP_ANY;
+ // Set correct flags.
+ ret = flags_set(p_advertising, BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ VERIFY_SUCCESS(ret);
+
+ ret = ble_advertising_start(p_advertising, p_advertising->adv_mode_current);
+ if ((ret != NRF_SUCCESS) && (p_advertising->error_handler != NULL))
+ {
+ p_advertising->error_handler(ret);
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+void ble_advertising_modes_config_set(ble_advertising_t * const p_advertising,
+ ble_adv_modes_config_t const * const p_adv_modes_config)
+{
+ p_advertising->adv_modes_config = *p_adv_modes_config;
+}
+
+
+#endif // NRF_MODULE_ENABLED(BLE_ADVERTISING)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_advertising/ble_advertising.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_advertising/ble_advertising.h
new file mode 100644
index 0000000..8840821
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_advertising/ble_advertising.h
@@ -0,0 +1,337 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/**@file
+ *
+ * @defgroup ble_advertising Advertising Module
+ * @{
+ * @ingroup ble_sdk_lib
+ * @brief Module for handling connectable BLE advertising.
+ *
+ * @details The Advertising Module handles connectable advertising for your application. It can
+ * be configured with advertising modes to suit most typical use cases.
+ * Your main application can react to changes in advertising modes
+ * if an event handler is provided.
+ *
+ * @note The Advertising Module supports only applications with a single peripheral link.
+ *
+ */
+
+#ifndef BLE_ADVERTISING_H__
+#define BLE_ADVERTISING_H__
+
+#include <stdint.h>
+#include "nrf_error.h"
+#include "ble.h"
+#include "ble_gattc.h"
+#include "ble_advdata.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_advertising instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_ADVERTISING_DEF(_name) \
+static ble_advertising_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _ble_obs, \
+ BLE_ADV_BLE_OBSERVER_PRIO, \
+ ble_advertising_on_ble_evt, &_name); \
+NRF_SDH_SOC_OBSERVER(_name ## _soc_obs, \
+ BLE_ADV_SOC_OBSERVER_PRIO, \
+ ble_advertising_on_sys_evt, &_name)
+
+
+/**@brief Advertising modes. */
+typedef enum
+{
+ BLE_ADV_MODE_IDLE, /**< Idle; no connectable advertising is ongoing. */
+ BLE_ADV_MODE_DIRECTED_HIGH_DUTY, /**< Directed advertising (high duty cycle) attempts to connect to the most recently disconnected peer. */
+ BLE_ADV_MODE_DIRECTED, /**< Directed advertising (low duty cycle) attempts to connect to the most recently disconnected peer. */
+ BLE_ADV_MODE_FAST, /**< Fast advertising will connect to any peer device, or filter with a whitelist if one exists. */
+ BLE_ADV_MODE_SLOW, /**< Slow advertising is similar to fast advertising. By default, it uses a longer advertising interval and time-out than fast advertising. However, these options are defined by the user. */
+} ble_adv_mode_t;
+
+/**@brief Advertising events.
+ *
+ * @details These events are propagated to the main application if a handler was provided during
+ * initialization of the Advertising Module. Events for modes that are not used can be
+ * ignored. Similarly, BLE_ADV_EVT_WHITELIST_REQUEST and BLE_ADV_EVT_PEER_ADDR_REQUEST
+ * can be ignored if whitelist and direct advertising is not used.
+ */
+typedef enum
+{
+ BLE_ADV_EVT_IDLE, /**< Idle; no connectable advertising is ongoing.*/
+ BLE_ADV_EVT_DIRECTED_HIGH_DUTY, /**< Direct advertising mode has started. */
+ BLE_ADV_EVT_DIRECTED, /**< Directed advertising (low duty cycle) has started. */
+ BLE_ADV_EVT_FAST, /**< Fast advertising mode has started. */
+ BLE_ADV_EVT_SLOW, /**< Slow advertising mode has started. */
+ BLE_ADV_EVT_FAST_WHITELIST, /**< Fast advertising mode using the whitelist has started. */
+ BLE_ADV_EVT_SLOW_WHITELIST, /**< Slow advertising mode using the whitelist has started. */
+ BLE_ADV_EVT_WHITELIST_REQUEST, /**< Request a whitelist from the main application. For whitelist advertising to work, the whitelist must be set when this event occurs. */
+ BLE_ADV_EVT_PEER_ADDR_REQUEST /**< Request a peer address from the main application. For directed advertising to work, the peer address must be set when this event occurs. */
+} ble_adv_evt_t;
+
+/**@brief Options for the different advertisement modes.
+ *
+ * @details This structure is used to enable or disable advertising modes and to configure time-out
+ * periods and advertising intervals.
+ */
+typedef struct
+{
+ bool ble_adv_on_disconnect_disabled; /**< Enable or disable automatic return to advertising upon disconnecting.*/
+ bool ble_adv_whitelist_enabled; /**< Enable or disable use of the whitelist. */
+ bool ble_adv_directed_high_duty_enabled; /**< Enable or disable direct advertising mode. can only be used if ble_adv_legacy_enabled is true. */
+ bool ble_adv_directed_enabled; /**< Enable or disable direct advertising mode. */
+ bool ble_adv_fast_enabled; /**< Enable or disable fast advertising mode. */
+ bool ble_adv_slow_enabled; /**< Enable or disable slow advertising mode. */
+ uint32_t ble_adv_directed_interval; /**< Advertising interval for directed advertising. */
+ uint32_t ble_adv_directed_timeout; /**< Time-out (number of tries) for direct advertising. */
+ uint32_t ble_adv_fast_interval; /**< Advertising interval for fast advertising. */
+ uint32_t ble_adv_fast_timeout; /**< Time-out (in seconds) for fast advertising. */
+ uint32_t ble_adv_slow_interval; /**< Advertising interval for slow advertising. */
+ uint32_t ble_adv_slow_timeout; /**< Time-out (in seconds) for slow advertising. */
+ bool ble_adv_extended_enabled; /**< Enable or disable extended advertising. */
+ uint32_t ble_adv_secondary_phy; /**< PHY for the secondary (extended) advertising @ref BLE_GAP_PHYS (BLE_GAP_PHY_1MBPS, BLE_GAP_PHY_2MBPS or BLE_GAP_PHY_CODED). */
+ uint32_t ble_adv_primary_phy; /**< PHY for the primary advertising. @ref BLE_GAP_PHYS (BLE_GAP_PHY_1MBPS, BLE_GAP_PHY_2MBPS or BLE_GAP_PHY_CODED). */
+} ble_adv_modes_config_t;
+
+/**@brief BLE advertising event handler type. */
+typedef void (*ble_adv_evt_handler_t) (ble_adv_evt_t const adv_evt);
+
+/**@brief BLE advertising error handler type. */
+typedef void (*ble_adv_error_handler_t) (uint32_t nrf_error);
+
+typedef struct
+{
+ bool initialized;
+ bool advertising_start_pending; /**< Flag to keep track of ongoing operations in flash. */
+ ble_adv_mode_t adv_mode_current; /**< Variable to keep track of the current advertising mode. */
+ ble_adv_modes_config_t adv_modes_config; /**< Struct to keep track of disabled and enabled advertising modes, as well as time-outs and intervals.*/
+ uint8_t conn_cfg_tag; /**< Variable to keep track of what connection settings will be used if the advertising results in a connection. */
+
+ ble_adv_evt_t adv_evt; /**< Advertising event propogated to the main application. The event is either a transaction to a new advertising mode, or a request for whitelist or peer address. */
+ ble_adv_evt_handler_t evt_handler; /**< Handler for the advertising events. Can be initialized as NULL if no handling is implemented on in the main application. */
+ ble_adv_error_handler_t error_handler; /**< Handler for the advertising error events. */
+
+ ble_gap_adv_params_t adv_params; /**< GAP advertising parameters. */
+ uint8_t adv_handle; /**< Handle for the advertising set. */
+ uint8_t enc_advdata[BLE_GAP_ADV_SET_DATA_SIZE_MAX]; /**< Current advertising data in encoded form. */
+ uint8_t enc_scan_rsp_data[BLE_GAP_ADV_SET_DATA_SIZE_MAX]; /**< Current scan response data in encoded form. */
+ ble_gap_adv_data_t adv_data; /**< Advertising data. */
+ ble_gap_adv_data_t *p_adv_data; /**< Will be set to point to @ref ble_advertising_t::adv_data for undirected advertising, and will be set to NULL for directed advertising. */
+
+ uint16_t current_slave_link_conn_handle; /**< Connection handle for the active link. */
+ ble_gap_addr_t peer_address; /**< Address of the most recently connected peer, used for direct advertising. */
+ bool peer_addr_reply_expected; /**< Flag to verify that peer address is only set when requested. */
+ bool whitelist_temporarily_disabled; /**< Flag to keep track of temporary disabling of the whitelist. */
+ bool whitelist_reply_expected; /**< Flag to verify that the whitelist is only set when requested. */
+ bool whitelist_in_use; /**< This module needs to be aware of whether or not a whitelist has been set (e.g. using the Peer Manager) in order to start advertising with the proper advertising params (filter policy). */
+} ble_advertising_t;
+
+typedef struct
+{
+ uint32_t interval;
+ uint32_t timeout;
+ bool enabled;
+} ble_adv_mode_config_t;
+
+/**@brief Initialization parameters for the Advertising Module.
+ * @details This structure is used to pass advertising options, advertising data,
+ * and an event handler to the Advertising Module during initialization.
+ */
+typedef struct
+{
+ ble_advdata_t advdata; /**< Advertising data: name, appearance, discovery flags, and more. */
+ ble_advdata_t srdata; /**< Scan response data: Supplement to advertising data. */
+ ble_adv_modes_config_t config; /**< Select which advertising modes and intervals will be utilized.*/
+ ble_adv_evt_handler_t evt_handler; /**< Event handler that will be called upon advertising events. */
+ ble_adv_error_handler_t error_handler; /**< Error handler that will propogate internal errors to the main applications. */
+} ble_advertising_init_t;
+
+
+/**@brief Function for handling BLE events.
+ *
+ * @details This function must be called from the BLE stack event dispatcher for
+ * the module to handle BLE events that are relevant for the Advertising Module.
+ *
+ * @param[in] p_ble_evt BLE stack event.
+ * @param[in] p_adv Advertising module instance.
+ */
+void ble_advertising_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_adv);
+
+
+/**@brief Function for handling system events.
+ *
+ * @details This function must be called to handle system events that are relevant
+ * for the Advertising Module. Specifically, the advertising module can not use the
+ * softdevice as long as there are pending writes to the flash memory. This
+ * event handler is designed to delay advertising until there is no flash operation.
+ *
+ * @param[in] sys_evt System event.
+ * @param[in] p_adv Advertising module instance.
+ */
+void ble_advertising_on_sys_evt(uint32_t sys_evt, void * p_adv);
+
+
+/**@brief Function for initializing the Advertising Module.
+ *
+ * @details Encodes the required advertising data and passes it to the stack.
+ * Also builds a structure to be passed to the stack when starting advertising.
+ * The supplied advertising data is copied to a local structure and is manipulated
+ * depending on what advertising modes are started in @ref ble_advertising_start.
+ *
+ * @param[out] p_advertising Advertising module instance. This structure must be supplied by
+ * the application. It is initialized by this function and will later
+ * be used to identify this particular module instance.
+ * @param[in] p_init Information needed to initialize the module.
+ *
+ * @retval NRF_SUCCESS If initialization was successful.
+ * @retval NRF_ERROR_INVALID_PARAM If the advertising configuration in \p p_init is invalid.
+ * @return If functions from other modules return errors to this function, the @ref nrf_error are propagated.
+ */
+uint32_t ble_advertising_init(ble_advertising_t * const p_advertising,
+ ble_advertising_init_t const * const p_init);
+
+
+ /**@brief Function for changing the connection settings tag that will be used for upcoming connections.
+ *
+ * @details See @ref sd_ble_cfg_set for more details about changing connection settings. If this
+ * function is never called, @ref BLE_CONN_CFG_TAG_DEFAULT will be used.
+ *
+ * @param[in] p_advertising Advertising module instance.
+ * @param[in] ble_cfg_tag Configuration for the connection settings (see @ref sd_ble_cfg_set).
+ */
+void ble_advertising_conn_cfg_tag_set(ble_advertising_t * const p_advertising, uint8_t ble_cfg_tag);
+
+/**@brief Function for starting advertising.
+ *
+ * @details You can start advertising in any of the advertising modes that you enabled
+ * during initialization.
+ *
+ * @param[in] p_advertising Advertising module instance.
+ * @param[in] advertising_mode Advertising mode.
+ *
+ * @retval @ref NRF_SUCCESS On success, else an error code indicating reason for failure.
+ * @retval @ref NRF_ERROR_INVALID_STATE If the module is not initialized.
+ */
+uint32_t ble_advertising_start(ble_advertising_t * const p_advertising,
+ ble_adv_mode_t advertising_mode);
+
+
+/**@brief Function for setting the peer address.
+ *
+ * @details The peer address must be set by the application upon receiving a
+ * @ref BLE_ADV_EVT_PEER_ADDR_REQUEST event. Without the peer address, the directed
+ * advertising mode will not be run.
+ *
+ * @param[in] p_advertising Advertising module instance.
+ * @param[in] p_peer_addr Pointer to a peer address.
+ *
+ * @retval @ref NRF_SUCCESS Successfully stored the peer address pointer in the advertising module.
+ * @retval @ref NRF_ERROR_INVALID_STATE If a reply was not expected.
+ */
+uint32_t ble_advertising_peer_addr_reply(ble_advertising_t * const p_advertising,
+ ble_gap_addr_t * p_peer_addr);
+
+
+/**@brief Function for setting a whitelist.
+ *
+ * @details The whitelist must be set by the application upon receiving a
+ * @ref BLE_ADV_EVT_WHITELIST_REQUEST event. Without the whitelist, the whitelist
+ * advertising for fast and slow modes will not be run.
+ *
+ * @param[in] p_advertising Advertising module instance.
+ * @param[in] p_gap_addrs The list of GAP addresses to whitelist.
+ * @param[in] addr_cnt The number of GAP addresses to whitelist.
+ * @param[in] p_gap_irks The list of peer IRK to whitelist.
+ * @param[in] irk_cnt The number of peer IRK to whitelist.
+ *
+ * @retval @ref NRF_SUCCESS If the operation was successful.
+ * @retval @ref NRF_ERROR_INVALID_STATE If a call to this function was made without a
+ * BLE_ADV_EVT_WHITELIST_REQUEST event being received.
+ */
+uint32_t ble_advertising_whitelist_reply(ble_advertising_t * const p_advertising,
+ ble_gap_addr_t const * p_gap_addrs,
+ uint32_t addr_cnt,
+ ble_gap_irk_t const * p_gap_irks,
+ uint32_t irk_cnt);
+
+
+/**@brief Function for disabling whitelist advertising.
+ *
+ * @details This function temporarily disables whitelist advertising.
+ * Calling this function resets the current time-out countdown.
+ *
+ * @param[in] p_advertising Advertising module instance.
+ *
+ * @retval @ref NRF_SUCCESS On success, else an error message propogated from the Softdevice.
+ */
+uint32_t ble_advertising_restart_without_whitelist(ble_advertising_t * const p_advertising);
+
+
+/**@brief Function for changing advertising modes configuration.
+ *
+ * @details This function can be called if you wish to reconfigure the advertising modes that the
+ * advertising module will cycle through. Enable or disable modes as listed in
+ * @ref ble_adv_mode_t; or change the duration of the advertising and use of whitelist.
+ *
+ * Keep in mind that @ref ble_adv_modes_config_t is also supplied when calling
+ * @ref ble_advertising_init. Calling @ref ble_advertising_modes_config_set
+ * is only necessary if your application requires this behaviour to change.
+ *
+ * @param[in] p_advertising Advertising module instance.
+ * @param[in] p_adv_modes_config Struct to keep track of disabled and enabled advertising modes,
+ * as well as time-outs and intervals.
+ */
+void ble_advertising_modes_config_set(ble_advertising_t * const p_advertising,
+ ble_adv_modes_config_t const * const p_adv_modes_config);
+/** @} */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_ADVERTISING_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_db_discovery/ble_db_discovery.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_db_discovery/ble_db_discovery.c
new file mode 100644
index 0000000..5ae6e20
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_db_discovery/ble_db_discovery.c
@@ -0,0 +1,986 @@
+/**
+ * Copyright (c) 2013 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "sdk_common.h"
+
+#if NRF_MODULE_ENABLED(BLE_DB_DISCOVERY)
+#include "ble_db_discovery.h"
+#include <stdlib.h>
+#include "ble_srv_common.h"
+#define NRF_LOG_MODULE_NAME ble_db_disc
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define SRV_DISC_START_HANDLE 0x0001 /**< The start handle value used during service discovery. */
+#define DB_DISCOVERY_MAX_USERS BLE_DB_DISCOVERY_MAX_SRV /**< The maximum number of users/registrations allowed by this module. */
+#define MODULE_INITIALIZED (m_initialized == true) /**< Macro designating whether the module has been initialized properly. */
+
+
+/**@brief Array of structures containing information about the registered application modules. */
+static ble_uuid_t m_registered_handlers[DB_DISCOVERY_MAX_USERS];
+
+
+/**@brief Array of structures containing pending events to be sent to the application modules.
+ *
+ * @details Whenever a discovery related event is to be raised to a user module, it will be stored
+ * in this array first. When all services needed to be discovered have been
+ * discovered, all pending events will be sent to the corresponding user modules.
+ **/
+static struct
+{
+ ble_db_discovery_evt_t evt; /**< The pending event. */
+ ble_db_discovery_evt_handler_t evt_handler; /**< The event handler which should be called to raise this event. */
+} m_pending_user_evts[DB_DISCOVERY_MAX_USERS];
+
+static ble_db_discovery_evt_handler_t m_evt_handler;
+static uint32_t m_pending_usr_evt_index; /**< The index to the pending user event array, pointing to the last added pending user event. */
+static uint32_t m_num_of_handlers_reg; /**< The number of handlers registered with the DB Discovery module. */
+static bool m_initialized = false; /**< This variable Indicates if the module is initialized or not. */
+
+/**@brief Function for fetching the event handler provided by a registered application module.
+ *
+ * @param[in] srv_uuid UUID of the service.
+ *
+ * @retval evt_handler Event handler of the module, registered for the given service UUID.
+ * @retval NULL If no event handler is found.
+ */
+static ble_db_discovery_evt_handler_t registered_handler_get(ble_uuid_t const * p_srv_uuid)
+{
+ for (uint32_t i = 0; i < m_num_of_handlers_reg; i++)
+ {
+ if (BLE_UUID_EQ(&(m_registered_handlers[i]), p_srv_uuid))
+ {
+ return (m_evt_handler);
+ }
+ }
+
+ return NULL;
+}
+
+
+/**@brief Function for storing the event handler provided by a registered application module.
+ *
+ * @param[in] p_srv_uuid The UUID of the service.
+ * @param[in] p_evt_handler The event handler provided by the application.
+ *
+ * @retval NRF_SUCCESS If the handler was stored or already present in the list.
+ * @retval NRF_ERROR_NO_MEM If there is no space left to store the handler.
+ */
+static uint32_t registered_handler_set(ble_uuid_t const * p_srv_uuid,
+ ble_db_discovery_evt_handler_t p_evt_handler)
+{
+ if (registered_handler_get(p_srv_uuid) != NULL)
+ {
+ return NRF_SUCCESS;
+ }
+
+ if (m_num_of_handlers_reg < DB_DISCOVERY_MAX_USERS)
+ {
+ m_registered_handlers[m_num_of_handlers_reg] = *p_srv_uuid;
+ m_num_of_handlers_reg++;
+
+ return NRF_SUCCESS;
+ }
+ else
+ {
+ return NRF_ERROR_NO_MEM;
+ }
+}
+
+
+/**@brief Function for sending all pending discovery events to the corresponding user modules.
+ */
+static void pending_user_evts_send(void)
+{
+ for (uint32_t i = 0; i < m_num_of_handlers_reg; i++)
+ {
+ // Pass the event to the corresponding event handler.
+ m_pending_user_evts[i].evt_handler(&(m_pending_user_evts[i].evt));
+ }
+
+ m_pending_usr_evt_index = 0;
+}
+
+
+/**@brief Function for indicating error to the application.
+ *
+ * @details This function will fetch the event handler based on the UUID of the service being
+ * discovered. (The event handler is registered by the application beforehand).
+ * The error code is added to the pending events together with the event handler.
+ * If no event handler was found, then this function will do nothing.
+ *
+ * @param[in] p_db_discovery Pointer to the DB discovery structure.
+ * @param[in] err_code Error code that should be provided to the application.
+ * @param[in] conn_handle Connection Handle.
+ *
+ */
+static void discovery_error_evt_trigger(ble_db_discovery_t * p_db_discovery,
+ uint32_t err_code,
+ uint16_t conn_handle)
+{
+ ble_db_discovery_evt_handler_t p_evt_handler;
+ ble_gatt_db_srv_t * p_srv_being_discovered;
+
+ p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
+
+ p_evt_handler = registered_handler_get(&(p_srv_being_discovered->srv_uuid));
+
+ if (p_evt_handler != NULL)
+ {
+ ble_db_discovery_evt_t evt =
+ {
+ .conn_handle = conn_handle,
+ .evt_type = BLE_DB_DISCOVERY_ERROR,
+ .params.err_code = err_code,
+ };
+
+ p_evt_handler(&evt);
+ }
+}
+
+
+/**@brief Function for triggering a Discovery Complete or Service Not Found event to the
+ * application.
+ *
+ * @details This function will fetch the event handler based on the UUID of the service being
+ * discovered. (The event handler is registered by the application beforehand).
+ * It then triggers an event indicating the completion of the service discovery.
+ * If no event handler was found, then this function will do nothing.
+ *
+ * @param[in] p_db_discovery Pointer to the DB discovery structure.
+ * @param[in] is_srv_found Variable to indicate if the service was found at the peer.
+ * @param[in] conn_handle Connection Handle.
+ */
+static void discovery_complete_evt_trigger(ble_db_discovery_t * p_db_discovery,
+ bool is_srv_found,
+ uint16_t conn_handle)
+{
+ ble_db_discovery_evt_handler_t p_evt_handler;
+ ble_gatt_db_srv_t * p_srv_being_discovered;
+
+ p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
+
+ p_evt_handler = registered_handler_get(&(p_srv_being_discovered->srv_uuid));
+
+ if (p_evt_handler != NULL)
+ {
+ if (m_pending_usr_evt_index < DB_DISCOVERY_MAX_USERS)
+ {
+ // Insert an event into the pending event list.
+ m_pending_user_evts[m_pending_usr_evt_index].evt.conn_handle = conn_handle;
+ m_pending_user_evts[m_pending_usr_evt_index].evt.params.discovered_db =
+ *p_srv_being_discovered;
+
+ if (is_srv_found)
+ {
+ m_pending_user_evts[m_pending_usr_evt_index].evt.evt_type =
+ BLE_DB_DISCOVERY_COMPLETE;
+ }
+ else
+ {
+ m_pending_user_evts[m_pending_usr_evt_index].evt.evt_type =
+ BLE_DB_DISCOVERY_SRV_NOT_FOUND;
+ }
+
+ m_pending_user_evts[m_pending_usr_evt_index].evt_handler = p_evt_handler;
+ m_pending_usr_evt_index++;
+
+ if (m_pending_usr_evt_index == m_num_of_handlers_reg)
+ {
+ // All registered modules have pending events. Send all pending events to the user
+ // modules.
+ pending_user_evts_send();
+ }
+ else
+ {
+ // Too many events pending. Do nothing. (Ideally this should not happen.)
+ }
+ }
+ }
+}
+
+
+/**@brief Function for handling service discovery completion.
+ *
+ * @details This function will be used to determine if there are more services to be discovered,
+ * and if so, initiate the discovery of the next service.
+ *
+ * @param[in] p_db_discovery Pointer to the DB Discovery Structure.
+ * @param[in] conn_handle Connection Handle.
+ */
+static void on_srv_disc_completion(ble_db_discovery_t * p_db_discovery,
+ uint16_t conn_handle)
+{
+ p_db_discovery->discoveries_count++;
+
+ // Check if more services need to be discovered.
+ if (p_db_discovery->discoveries_count < m_num_of_handlers_reg)
+ {
+ // Reset the current characteristic index since a new service discovery is about to start.
+ p_db_discovery->curr_char_ind = 0;
+
+ // Initiate discovery of the next service.
+ p_db_discovery->curr_srv_ind++;
+
+ ble_gatt_db_srv_t * p_srv_being_discovered;
+
+ p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
+
+ p_srv_being_discovered->srv_uuid = m_registered_handlers[p_db_discovery->curr_srv_ind];
+
+ // Reset the characteristic count in the current service to zero since a new service
+ // discovery is about to start.
+ p_srv_being_discovered->char_count = 0;
+
+ NRF_LOG_DEBUG("Starting discovery of service with UUID 0x%x on connection handle 0x%x.",
+ p_srv_being_discovered->srv_uuid.uuid, conn_handle);
+
+ uint32_t err_code;
+
+ err_code = sd_ble_gattc_primary_services_discover(conn_handle,
+ SRV_DISC_START_HANDLE,
+ &(p_srv_being_discovered->srv_uuid));
+
+ if (err_code != NRF_SUCCESS)
+ {
+ p_db_discovery->discovery_in_progress = false;
+
+ // Error with discovering the service.
+ // Indicate the error to the registered user application.
+ discovery_error_evt_trigger(p_db_discovery, err_code, conn_handle);
+
+ m_pending_user_evts[0].evt.evt_type = BLE_DB_DISCOVERY_AVAILABLE;
+ m_pending_user_evts[0].evt.conn_handle = conn_handle;
+
+ return;
+ }
+ }
+ else
+ {
+ // No more service discovery is needed.
+ p_db_discovery->discovery_in_progress = false;
+ m_pending_user_evts[0].evt.evt_type = BLE_DB_DISCOVERY_AVAILABLE;
+ m_pending_user_evts[0].evt.conn_handle = conn_handle;
+ }
+}
+
+
+/**@brief Function for finding out if a characteristic discovery should be performed after the
+ * last discovered characteristic.
+ *
+ * @details This function is used during the time of database discovery to find out if there is
+ * a need to do more characteristic discoveries. The value handles of the
+ * last discovered characteristic is compared with the end handle of the service.
+ * If the service handle is greater than one of the former characteristic handles,
+ * it means that a characteristic discovery is required.
+ *
+ * @param[in] p_db_discovery The pointer to the DB Discovery structure.
+ * @param[in] p_after_char The pointer to the last discovered characteristic.
+ *
+ * @retval True if a characteristic discovery is required.
+ * @retval False if a characteristic discovery is NOT required.
+ */
+static bool is_char_discovery_reqd(ble_db_discovery_t * p_db_discovery,
+ ble_gattc_char_t * p_after_char)
+{
+ if (p_after_char->handle_value <
+ p_db_discovery->services[p_db_discovery->curr_srv_ind].handle_range.end_handle)
+ {
+ // Handle value of the characteristic being discovered is less than the end handle of
+ // the service being discovered. There is a possibility of more characteristics being
+ // present. Hence a characteristic discovery is required.
+ return true;
+ }
+
+ return false;
+}
+
+
+/**@brief Function to find out if a descriptor discovery is required.
+ *
+ * @details This function finds out if there is a possibility of existence of descriptors between
+ * current characteristic and the next characteristic. If so, this function will compute
+ * the handle range on which the descriptors may be present and will return it.
+ * If the current characteristic is the last known characteristic, then this function
+ * will use the service end handle to find out if the current characteristic can have
+ * descriptors.
+ *
+ * @param[in] p_db_discovery Pointer to the DB Discovery structure.
+ * @param[in] p_curr_char Pointer to the current characteristic.
+ * @param[in] p_next_char Pointer to the next characteristic. This should be NULL if the
+ * caller knows that there is no characteristic after the current
+ * characteristic at the peer.
+ * @param[out] p_handle_range Pointer to the handle range in which descriptors may exist at the
+ * the peer.
+ *
+ * @retval True If a descriptor discovery is required.
+ * @retval False If a descriptor discovery is NOT required.
+ */
+static bool is_desc_discovery_reqd(ble_db_discovery_t * p_db_discovery,
+ ble_gatt_db_char_t * p_curr_char,
+ ble_gatt_db_char_t * p_next_char,
+ ble_gattc_handle_range_t * p_handle_range)
+{
+ if (p_next_char == NULL)
+ {
+ // Current characteristic is the last characteristic in the service. Check if the value
+ // handle of the current characteristic is equal to the service end handle.
+ if (
+ p_curr_char->characteristic.handle_value ==
+ p_db_discovery->services[p_db_discovery->curr_srv_ind].handle_range.end_handle
+ )
+ {
+ // No descriptors can be present for the current characteristic. p_curr_char is the last
+ // characteristic with no descriptors.
+ return false;
+ }
+
+ p_handle_range->start_handle = p_curr_char->characteristic.handle_value + 1;
+
+ // Since the current characteristic is the last characteristic in the service, the end
+ // handle should be the end handle of the service.
+ p_handle_range->end_handle =
+ p_db_discovery->services[p_db_discovery->curr_srv_ind].handle_range.end_handle;
+
+ return true;
+ }
+
+ // p_next_char != NULL. Check for existence of descriptors between the current and the next
+ // characteristic.
+ if ((p_curr_char->characteristic.handle_value + 1) == p_next_char->characteristic.handle_decl)
+ {
+ // No descriptors can exist between the two characteristic.
+ return false;
+ }
+
+ p_handle_range->start_handle = p_curr_char->characteristic.handle_value + 1;
+ p_handle_range->end_handle = p_next_char->characteristic.handle_decl - 1;
+
+ return true;
+}
+
+
+/**@brief Function for performing characteristic discovery.
+ *
+ * @param[in] p_db_discovery Pointer to the DB Discovery structure.
+ * @param[in] conn_handle Connection Handle.
+ *
+ * @return NRF_SUCCESS if the SoftDevice was successfully requested to perform the characteristic
+ * discovery. Otherwise an error code. This function returns the error code returned
+ * by the SoftDevice API @ref sd_ble_gattc_characteristics_discover.
+ */
+static uint32_t characteristics_discover(ble_db_discovery_t * p_db_discovery,
+ uint16_t conn_handle)
+{
+ ble_gatt_db_srv_t * p_srv_being_discovered;
+ ble_gattc_handle_range_t handle_range;
+
+ p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
+
+ if (p_db_discovery->curr_char_ind != 0)
+ {
+ // This is not the first characteristic being discovered. Hence the 'start handle' to be
+ // used must be computed using the handle_value of the previous characteristic.
+ ble_gattc_char_t * p_prev_char;
+ uint8_t prev_char_ind = p_db_discovery->curr_char_ind - 1;
+
+ p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
+
+ p_prev_char = &(p_srv_being_discovered->charateristics[prev_char_ind].characteristic);
+
+ handle_range.start_handle = p_prev_char->handle_value + 1;
+ }
+ else
+ {
+ // This is the first characteristic of this service being discovered.
+ handle_range.start_handle = p_srv_being_discovered->handle_range.start_handle;
+ }
+
+ handle_range.end_handle = p_srv_being_discovered->handle_range.end_handle;
+
+ return sd_ble_gattc_characteristics_discover(conn_handle, &handle_range);
+}
+
+
+/**@brief Function for performing descriptor discovery, if required.
+ *
+ * @details This function will check if descriptor discovery is required and then perform it if
+ * needed. If no more descriptor discovery is required for the service, then the output
+ * parameter p_raise_discov_complete is set to true, indicating to the caller that a
+ * discovery complete event can be triggered to the application.
+ *
+ * @param[in] p_db_discovery Pointer to the DB Discovery structure.
+ * @param[out] p_raise_discov_complete The value pointed to by this pointer will be set to true if
+ * the Discovery Complete event can be triggered to the
+ * application.
+ * @param[in] conn_handle Connection Handle.
+ *
+ * @return NRF_SUCCESS if the SoftDevice was successfully requested to perform the descriptor
+ * discovery, or if no more descriptor discovery is required. Otherwise an error code.
+ * This function returns the error code returned by the SoftDevice API @ref
+ * sd_ble_gattc_descriptors_discover.
+ */
+static uint32_t descriptors_discover(ble_db_discovery_t * p_db_discovery,
+ bool * p_raise_discov_complete,
+ uint16_t conn_handle)
+{
+ ble_gattc_handle_range_t handle_range;
+ ble_gatt_db_char_t * p_curr_char_being_discovered;
+ ble_gatt_db_srv_t * p_srv_being_discovered;
+ bool is_discovery_reqd = false;
+
+ p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
+
+ p_curr_char_being_discovered =
+ &(p_srv_being_discovered->charateristics[p_db_discovery->curr_char_ind]);
+
+ if ((p_db_discovery->curr_char_ind + 1) == p_srv_being_discovered->char_count)
+ {
+ // This is the last characteristic of this service.
+ is_discovery_reqd = is_desc_discovery_reqd(p_db_discovery,
+ p_curr_char_being_discovered,
+ NULL,
+ &handle_range);
+ }
+ else
+ {
+ uint8_t i;
+ ble_gatt_db_char_t * p_next_char;
+
+ for (i = p_db_discovery->curr_char_ind; i < p_srv_being_discovered->char_count; i++)
+ {
+ if (i == (p_srv_being_discovered->char_count - 1))
+ {
+ // The current characteristic is the last characteristic in the service.
+ p_next_char = NULL;
+ }
+ else
+ {
+ p_next_char = &(p_srv_being_discovered->charateristics[i + 1]);
+ }
+
+ // Check if it is possible for the current characteristic to have a descriptor.
+ if (is_desc_discovery_reqd(p_db_discovery,
+ p_curr_char_being_discovered,
+ p_next_char,
+ &handle_range))
+ {
+ is_discovery_reqd = true;
+ break;
+ }
+ else
+ {
+ // No descriptors can exist.
+ p_curr_char_being_discovered = p_next_char;
+ p_db_discovery->curr_char_ind++;
+ }
+ }
+ }
+
+ if (!is_discovery_reqd)
+ {
+ // No more descriptor discovery required. Discovery is complete.
+ // This informs the caller that a discovery complete event can be triggered.
+ *p_raise_discov_complete = true;
+
+ return NRF_SUCCESS;
+ }
+
+ *p_raise_discov_complete = false;
+
+ return sd_ble_gattc_descriptors_discover(conn_handle, &handle_range);
+}
+
+
+/**@brief Function for handling primary service discovery response.
+ *
+ * @details This function will handle the primary service discovery response and start the
+ * discovery of characteristics within that service.
+ *
+ * @param[in] p_db_discovery Pointer to the DB Discovery structure.
+ * @param[in] p_ble_gattc_evt Pointer to the GATT Client event.
+ */
+static void on_primary_srv_discovery_rsp(ble_db_discovery_t * p_db_discovery,
+ ble_gattc_evt_t const * p_ble_gattc_evt)
+{
+ ble_gatt_db_srv_t * p_srv_being_discovered;
+
+ p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
+
+ if (p_ble_gattc_evt->conn_handle != p_db_discovery->conn_handle)
+ {
+ return;
+ }
+
+ if (p_ble_gattc_evt->gatt_status == BLE_GATT_STATUS_SUCCESS)
+ {
+ uint32_t err_code;
+ ble_gattc_evt_prim_srvc_disc_rsp_t const * p_prim_srvc_disc_rsp_evt;
+
+ NRF_LOG_DEBUG("Found service UUID 0x%x.", p_srv_being_discovered->srv_uuid.uuid);
+
+ p_prim_srvc_disc_rsp_evt = &(p_ble_gattc_evt->params.prim_srvc_disc_rsp);
+
+ p_srv_being_discovered->srv_uuid = p_prim_srvc_disc_rsp_evt->services[0].uuid;
+ p_srv_being_discovered->handle_range = p_prim_srvc_disc_rsp_evt->services[0].handle_range;
+
+ err_code = characteristics_discover(p_db_discovery, p_ble_gattc_evt->conn_handle);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ p_db_discovery->discovery_in_progress = false;
+
+ // Error with discovering the service.
+ // Indicate the error to the registered user application.
+ discovery_error_evt_trigger(p_db_discovery, err_code, p_ble_gattc_evt->conn_handle);
+
+ m_pending_user_evts[0].evt.evt_type = BLE_DB_DISCOVERY_AVAILABLE;
+ m_pending_user_evts[0].evt.conn_handle = p_ble_gattc_evt->conn_handle;
+ }
+ }
+ else
+ {
+ NRF_LOG_DEBUG("Service UUID 0x%x not found.", p_srv_being_discovered->srv_uuid.uuid);
+ // Trigger Service Not Found event to the application.
+ discovery_complete_evt_trigger(p_db_discovery, false, p_ble_gattc_evt->conn_handle);
+ on_srv_disc_completion(p_db_discovery, p_ble_gattc_evt->conn_handle);
+ }
+}
+
+
+/**@brief Function for handling characteristic discovery response.
+ *
+ * @param[in] p_db_discovery Pointer to the DB Discovery structure.
+ * @param[in] p_ble_gattc_evt Pointer to the GATT Client event.
+ */
+static void on_characteristic_discovery_rsp(ble_db_discovery_t * p_db_discovery,
+ ble_gattc_evt_t const * p_ble_gattc_evt)
+{
+ uint32_t err_code;
+ ble_gatt_db_srv_t * p_srv_being_discovered;
+ bool perform_desc_discov = false;
+
+ if (p_ble_gattc_evt->conn_handle != p_db_discovery->conn_handle)
+ {
+ return;
+ }
+
+ p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
+
+ if (p_ble_gattc_evt->gatt_status == BLE_GATT_STATUS_SUCCESS)
+ {
+ ble_gattc_evt_char_disc_rsp_t const * p_char_disc_rsp_evt;
+
+ p_char_disc_rsp_evt = &(p_ble_gattc_evt->params.char_disc_rsp);
+
+ // Find out the number of characteristics that were previously discovered (in earlier
+ // characteristic discovery responses, if any).
+ uint8_t num_chars_prev_disc = p_srv_being_discovered->char_count;
+
+ // Find out the number of characteristics that are currently discovered (in the
+ // characteristic discovery response being handled).
+ uint8_t num_chars_curr_disc = p_char_disc_rsp_evt->count;
+
+ // Check if the total number of discovered characteristics are supported by this module.
+ if ((num_chars_prev_disc + num_chars_curr_disc) <= BLE_GATT_DB_MAX_CHARS)
+ {
+ // Update the characteristics count.
+ p_srv_being_discovered->char_count += num_chars_curr_disc;
+ }
+ else
+ {
+ // The number of characteristics discovered at the peer is more than the supported
+ // maximum. This module will store only the characteristics found up to this point.
+ p_srv_being_discovered->char_count = BLE_GATT_DB_MAX_CHARS;
+ }
+
+ uint32_t i;
+ uint32_t j;
+
+ for (i = num_chars_prev_disc, j = 0; i < p_srv_being_discovered->char_count; i++, j++)
+ {
+ p_srv_being_discovered->charateristics[i].characteristic =
+ p_char_disc_rsp_evt->chars[j];
+
+ p_srv_being_discovered->charateristics[i].cccd_handle = BLE_GATT_HANDLE_INVALID;
+ p_srv_being_discovered->charateristics[i].ext_prop_handle = BLE_GATT_HANDLE_INVALID;
+ p_srv_being_discovered->charateristics[i].user_desc_handle = BLE_GATT_HANDLE_INVALID;
+ p_srv_being_discovered->charateristics[i].report_ref_handle = BLE_GATT_HANDLE_INVALID;
+ }
+
+ ble_gattc_char_t * p_last_known_char;
+
+ p_last_known_char = &(p_srv_being_discovered->charateristics[i - 1].characteristic);
+
+ // If no more characteristic discovery is required, or if the maximum number of supported
+ // characteristic per service has been reached, descriptor discovery will be performed.
+ if ( !is_char_discovery_reqd(p_db_discovery, p_last_known_char)
+ || (p_srv_being_discovered->char_count == BLE_GATT_DB_MAX_CHARS))
+ {
+ perform_desc_discov = true;
+ }
+ else
+ {
+ // Update the current characteristic index.
+ p_db_discovery->curr_char_ind = p_srv_being_discovered->char_count;
+
+ // Perform another round of characteristic discovery.
+ err_code = characteristics_discover(p_db_discovery, p_ble_gattc_evt->conn_handle);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ p_db_discovery->discovery_in_progress = false;
+
+ discovery_error_evt_trigger(p_db_discovery, err_code, p_ble_gattc_evt->conn_handle);
+
+ m_pending_user_evts[0].evt.evt_type = BLE_DB_DISCOVERY_AVAILABLE;
+ m_pending_user_evts[0].evt.conn_handle = p_ble_gattc_evt->conn_handle;
+
+ return;
+ }
+ }
+ }
+ else
+ {
+ // The previous characteristic discovery resulted in no characteristics.
+ // descriptor discovery should be performed.
+ perform_desc_discov = true;
+ }
+
+ if (perform_desc_discov)
+ {
+ bool raise_discov_complete;
+
+ p_db_discovery->curr_char_ind = 0;
+
+ err_code = descriptors_discover(p_db_discovery,
+ &raise_discov_complete,
+ p_ble_gattc_evt->conn_handle);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ p_db_discovery->discovery_in_progress = false;
+
+ discovery_error_evt_trigger(p_db_discovery, err_code, p_ble_gattc_evt->conn_handle);
+
+ m_pending_user_evts[0].evt.evt_type = BLE_DB_DISCOVERY_AVAILABLE;
+ m_pending_user_evts[0].evt.conn_handle = p_ble_gattc_evt->conn_handle;
+
+ return;
+ }
+ if (raise_discov_complete)
+ {
+ // No more characteristics and descriptors need to be discovered. Discovery is complete.
+ // Send a discovery complete event to the user application.
+ NRF_LOG_DEBUG("Discovery of service with UUID 0x%x completed with success"
+ " on connection handle 0x%x.",
+ p_srv_being_discovered->srv_uuid.uuid,
+ p_ble_gattc_evt->conn_handle);
+
+ discovery_complete_evt_trigger(p_db_discovery, true, p_ble_gattc_evt->conn_handle);
+ on_srv_disc_completion(p_db_discovery, p_ble_gattc_evt->conn_handle);
+ }
+ }
+}
+
+
+/**@brief Function for handling descriptor discovery response.
+ *
+ * @param[in] p_db_discovery Pointer to the DB Discovery structure.
+ * @param[in] p_ble_gattc_evt Pointer to the GATT Client event.
+ */
+static void on_descriptor_discovery_rsp(ble_db_discovery_t * const p_db_discovery,
+ const ble_gattc_evt_t * const p_ble_gattc_evt)
+{
+ const ble_gattc_evt_desc_disc_rsp_t * p_desc_disc_rsp_evt;
+ ble_gatt_db_srv_t * p_srv_being_discovered;
+
+ if (p_ble_gattc_evt->conn_handle != p_db_discovery->conn_handle)
+ {
+ return;
+ }
+
+ p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
+
+ p_desc_disc_rsp_evt = &(p_ble_gattc_evt->params.desc_disc_rsp);
+
+ ble_gatt_db_char_t * p_char_being_discovered =
+ &(p_srv_being_discovered->charateristics[p_db_discovery->curr_char_ind]);
+
+ if (p_ble_gattc_evt->gatt_status == BLE_GATT_STATUS_SUCCESS)
+ {
+ // The descriptor was found at the peer.
+ // Iterate through and collect CCCD, Extended Properties,
+ // User Description & Report Reference descriptor handles.
+ for (uint32_t i = 0; i < p_desc_disc_rsp_evt->count; i++)
+ {
+ switch (p_desc_disc_rsp_evt->descs[i].uuid.uuid)
+ {
+ case BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG:
+ p_char_being_discovered->cccd_handle =
+ p_desc_disc_rsp_evt->descs[i].handle;
+ break;
+
+ case BLE_UUID_DESCRIPTOR_CHAR_EXT_PROP:
+ p_char_being_discovered->ext_prop_handle =
+ p_desc_disc_rsp_evt->descs[i].handle;
+ break;
+
+ case BLE_UUID_DESCRIPTOR_CHAR_USER_DESC:
+ p_char_being_discovered->user_desc_handle =
+ p_desc_disc_rsp_evt->descs[i].handle;
+ break;
+
+ case BLE_UUID_REPORT_REF_DESCR:
+ p_char_being_discovered->report_ref_handle =
+ p_desc_disc_rsp_evt->descs[i].handle;
+ break;
+ }
+
+ /* Break if we've found all the descriptors we are looking for. */
+ if (p_char_being_discovered->cccd_handle != BLE_GATT_HANDLE_INVALID &&
+ p_char_being_discovered->ext_prop_handle != BLE_GATT_HANDLE_INVALID &&
+ p_char_being_discovered->user_desc_handle != BLE_GATT_HANDLE_INVALID &&
+ p_char_being_discovered->report_ref_handle != BLE_GATT_HANDLE_INVALID)
+ {
+ break;
+ }
+ }
+ }
+
+ bool raise_discov_complete = false;
+
+ if ((p_db_discovery->curr_char_ind + 1) == p_srv_being_discovered->char_count)
+ {
+ // No more characteristics and descriptors need to be discovered. Discovery is complete.
+ // Send a discovery complete event to the user application.
+
+ raise_discov_complete = true;
+ }
+ else
+ {
+ // Begin discovery of descriptors for the next characteristic.
+ uint32_t err_code;
+
+ p_db_discovery->curr_char_ind++;
+
+ err_code = descriptors_discover(p_db_discovery,
+ &raise_discov_complete,
+ p_ble_gattc_evt->conn_handle);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ p_db_discovery->discovery_in_progress = false;
+
+ // Error with discovering the service.
+ // Indicate the error to the registered user application.
+ discovery_error_evt_trigger(p_db_discovery, err_code, p_ble_gattc_evt->conn_handle);
+
+ m_pending_user_evts[0].evt.evt_type = BLE_DB_DISCOVERY_AVAILABLE;
+ m_pending_user_evts[0].evt.conn_handle = p_ble_gattc_evt->conn_handle;
+
+ return;
+ }
+ }
+
+ if (raise_discov_complete)
+ {
+ NRF_LOG_DEBUG("Discovery of service with UUID 0x%x completed with success"
+ " on connection handle 0x%x.",
+ p_srv_being_discovered->srv_uuid.uuid,
+ p_ble_gattc_evt->conn_handle);
+
+ discovery_complete_evt_trigger(p_db_discovery, true, p_ble_gattc_evt->conn_handle);
+ on_srv_disc_completion(p_db_discovery, p_ble_gattc_evt->conn_handle);
+ }
+}
+
+
+uint32_t ble_db_discovery_init(const ble_db_discovery_evt_handler_t evt_handler)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ VERIFY_PARAM_NOT_NULL(evt_handler);
+
+ m_num_of_handlers_reg = 0;
+ m_initialized = true;
+ m_pending_usr_evt_index = 0;
+ m_evt_handler = evt_handler;
+
+ return err_code;
+
+}
+
+
+uint32_t ble_db_discovery_close()
+{
+ m_num_of_handlers_reg = 0;
+ m_initialized = false;
+ m_pending_usr_evt_index = 0;
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_db_discovery_evt_register(ble_uuid_t const * p_uuid)
+{
+ VERIFY_PARAM_NOT_NULL(p_uuid);
+ VERIFY_MODULE_INITIALIZED();
+
+ return registered_handler_set(p_uuid, m_evt_handler);
+}
+
+
+static uint32_t discovery_start(ble_db_discovery_t * const p_db_discovery, uint16_t conn_handle)
+{
+ uint32_t err_code;
+ ble_gatt_db_srv_t * p_srv_being_discovered;
+
+ memset(p_db_discovery, 0x00, sizeof(ble_db_discovery_t));
+
+ p_db_discovery->conn_handle = conn_handle;
+
+ m_pending_usr_evt_index = 0;
+
+ p_db_discovery->discoveries_count = 0;
+ p_db_discovery->curr_srv_ind = 0;
+ p_db_discovery->curr_char_ind = 0;
+
+ p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
+ p_srv_being_discovered->srv_uuid = m_registered_handlers[p_db_discovery->curr_srv_ind];
+
+ NRF_LOG_DEBUG("Starting discovery of service with UUID 0x%x on connection handle 0x%x.",
+ p_srv_being_discovered->srv_uuid.uuid, conn_handle);
+
+ err_code = sd_ble_gattc_primary_services_discover(conn_handle,
+ SRV_DISC_START_HANDLE,
+ &(p_srv_being_discovered->srv_uuid));
+ if (err_code != NRF_ERROR_BUSY)
+ {
+ VERIFY_SUCCESS(err_code);
+ p_db_discovery->discovery_in_progress = true;
+ p_db_discovery->discovery_pending = false;
+ }
+ else
+ {
+ p_db_discovery->discovery_in_progress = true;
+ p_db_discovery->discovery_pending = true;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_db_discovery_start(ble_db_discovery_t * const p_db_discovery, uint16_t conn_handle)
+{
+ VERIFY_PARAM_NOT_NULL(p_db_discovery);
+ VERIFY_MODULE_INITIALIZED();
+
+ if (m_num_of_handlers_reg == 0)
+ {
+ // No user modules were registered. There are no services to discover.
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ if (p_db_discovery->discovery_in_progress)
+ {
+ return NRF_ERROR_BUSY;
+ }
+
+ return discovery_start(p_db_discovery, conn_handle);
+}
+
+
+/**@brief Function for handling disconnected event.
+ *
+ * @param[in] p_db_discovery Pointer to the DB Discovery structure.
+ * @param[in] p_ble_gattc_evt Pointer to the GAP event.
+ */
+static void on_disconnected(ble_db_discovery_t * p_db_discovery,
+ ble_gap_evt_t const * p_evt)
+{
+ if (p_evt->conn_handle == p_db_discovery->conn_handle)
+ {
+ p_db_discovery->discovery_in_progress = false;
+ p_db_discovery->discovery_pending = false;
+ p_db_discovery->conn_handle = BLE_CONN_HANDLE_INVALID;
+ }
+}
+
+
+void ble_db_discovery_on_ble_evt(ble_evt_t const * p_ble_evt,
+ void * p_context)
+{
+ VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
+ VERIFY_PARAM_NOT_NULL_VOID(p_context);
+ VERIFY_MODULE_INITIALIZED_VOID();
+
+ ble_db_discovery_t * p_db_discovery = (ble_db_discovery_t *)p_context;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP:
+ on_primary_srv_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt));
+ break;
+
+ case BLE_GATTC_EVT_CHAR_DISC_RSP:
+ on_characteristic_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt));
+ break;
+
+ case BLE_GATTC_EVT_DESC_DISC_RSP:
+ on_descriptor_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt));
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnected(p_db_discovery, &(p_ble_evt->evt.gap_evt));
+ break;
+
+ default:
+ break;
+ }
+
+ if ( (p_db_discovery->discovery_pending)
+ && (p_ble_evt->header.evt_id >= BLE_GATTC_EVT_BASE)
+ && (p_ble_evt->header.evt_id <= BLE_GATTC_EVT_LAST)
+ && (p_ble_evt->evt.gattc_evt.conn_handle == p_db_discovery->conn_handle))
+ {
+ (void)discovery_start(p_db_discovery, p_db_discovery->conn_handle);
+ }
+}
+#endif // NRF_MODULE_ENABLED(BLE_DB_DISCOVERY)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_db_discovery/ble_db_discovery.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_db_discovery/ble_db_discovery.h
new file mode 100644
index 0000000..a2094c9
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_db_discovery/ble_db_discovery.h
@@ -0,0 +1,235 @@
+/**
+ * Copyright (c) 2013 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/**@file
+ *
+ * @defgroup ble_db_discovery Database Discovery
+ * @{
+ * @ingroup ble_sdk_lib
+ * @brief Database discovery module.
+ *
+ * @details This module contains the APIs and types exposed by the DB Discovery module. These APIs
+ * and types can be used by the application to perform discovery of a service and its
+ * characteristics at the peer server. This module can also be used to discover the
+ * desired services in multiple remote devices.
+ *
+ * @warning The maximum number of characteristics per service that can be discovered by this module
+ * is determined by the number of characteristics in the service structure defined in
+ * db_disc_config.h. If the peer has more than the supported number of characteristics, then
+ * the first found will be discovered and any further characteristics will be ignored. Only the
+ * following descriptors will be searched for at the peer: Client Characteristic Configuration,
+ * Characteristic Extended Properties, Characteristic User Description, and Report Reference.
+ *
+ * @note Presently only one instance of a Primary Service can be discovered by this module. If
+ * there are multiple instances of the service at the peer, only the first instance
+ * of it at the peer is fetched and returned to the application.
+ *
+ * @note The application must propagate BLE stack events to this module by calling
+ * ble_db_discovery_on_ble_evt().
+ *
+ */
+
+#ifndef BLE_DB_DISCOVERY_H__
+#define BLE_DB_DISCOVERY_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "nrf_error.h"
+#include "ble.h"
+#include "ble_gattc.h"
+#include "ble_gatt_db.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_db_discovery instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_DB_DISCOVERY_DEF(_name) \
+static ble_db_discovery_t _name = {.discovery_in_progress = 0, \
+ .discovery_pending = 0, \
+ .conn_handle = BLE_CONN_HANDLE_INVALID}; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_DB_DISC_BLE_OBSERVER_PRIO, \
+ ble_db_discovery_on_ble_evt, &_name)
+
+/** @brief Macro for defining multiple ble_db_discovery instances.
+ *
+ * @param _name Name of the array of instances.
+ * @param _cnt Number of instances to define.
+ */
+#define BLE_DB_DISCOVERY_ARRAY_DEF(_name, _cnt) \
+static ble_db_discovery_t _name[_cnt] = {{.discovery_in_progress = 0, \
+ .discovery_pending = 0, \
+ .conn_handle = BLE_CONN_HANDLE_INVALID}}; \
+NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
+ BLE_DB_DISC_BLE_OBSERVER_PRIO, \
+ ble_db_discovery_on_ble_evt, &_name, _cnt)
+
+#define BLE_DB_DISCOVERY_MAX_SRV 6 /**< Maximum number of services supported by this module. This also indicates the maximum number of users allowed to be registered to this module (one user per service). */
+
+
+/**@brief DB Discovery event type. */
+typedef enum
+{
+ BLE_DB_DISCOVERY_COMPLETE, /**< Event indicating that the discovery of one service is complete. */
+ BLE_DB_DISCOVERY_ERROR, /**< Event indicating that an internal error has occurred in the DB Discovery module. This could typically be because of the SoftDevice API returning an error code during the DB discover.*/
+ BLE_DB_DISCOVERY_SRV_NOT_FOUND, /**< Event indicating that the service was not found at the peer.*/
+ BLE_DB_DISCOVERY_AVAILABLE /**< Event indicating that the DB discovery instance is available.*/
+} ble_db_discovery_evt_type_t;
+
+/**@brief Structure for holding the information related to the GATT database at the server.
+ *
+ * @details This module identifies a remote database. Use one instance of this structure per
+ * connection.
+ *
+ * @warning This structure must be zero-initialized.
+ */
+typedef struct
+{
+ ble_gatt_db_srv_t services[BLE_DB_DISCOVERY_MAX_SRV]; /**< Information related to the current service being discovered. This is intended for internal use during service discovery.*/
+ uint8_t srv_count; /**< Number of services at the peers GATT database.*/
+ uint8_t curr_char_ind; /**< Index of the current characteristic being discovered. This is intended for internal use during service discovery.*/
+ uint8_t curr_srv_ind; /**< Index of the current service being discovered. This is intended for internal use during service discovery.*/
+ bool discovery_in_progress; /**< Variable to indicate if there is a service discovery in progress. */
+ bool discovery_pending; /**< Discovery was requested, but could not start because the SoftDevice was busy. */
+ uint8_t discoveries_count; /**< Number of service discoveries made, both successful and unsuccessful. */
+ uint16_t conn_handle; /**< Connection handle on which the discovery is started*/
+} ble_db_discovery_t;
+
+/**@brief Structure containing the event from the DB discovery module to the application. */
+typedef struct
+{
+ ble_db_discovery_evt_type_t evt_type; /**< Type of event. */
+ uint16_t conn_handle; /**< Handle of the connection for which this event has occurred. */
+ union
+ {
+ ble_gatt_db_srv_t discovered_db; /**< Structure containing the information about the GATT Database at the server. This will be filled when the event type is @ref BLE_DB_DISCOVERY_COMPLETE. The UUID field of this will be filled when the event type is @ref BLE_DB_DISCOVERY_SRV_NOT_FOUND. */
+ uint32_t err_code; /**< nRF Error code indicating the type of error which occurred in the DB Discovery module. This will be filled when the event type is @ref BLE_DB_DISCOVERY_ERROR. */
+ } params;
+} ble_db_discovery_evt_t;
+
+/**@brief DB Discovery event handler type. */
+typedef void (* ble_db_discovery_evt_handler_t)(ble_db_discovery_evt_t * p_evt);
+
+
+/**@brief Function for initializing the DB Discovery module.
+ *
+ * @param[in] evt_handler Event handler to be called by the DB discovery module when any event
+ * related to discovery of the registered service occurs.
+ *
+ * @retval NRF_SUCCESS On successful initialization.
+ * @retval NRF_ERROR_NULL If the handler was NULL.
+ */
+uint32_t ble_db_discovery_init(ble_db_discovery_evt_handler_t evt_handler);
+
+
+/**@brief Function for closing the DB Discovery module.
+ *
+ * @details This function will clear up any internal variables and states maintained by the
+ * module. To re-use the module after calling this function, the function @ref
+ * ble_db_discovery_init must be called again.
+ *
+ * @retval NRF_SUCCESS Operation success.
+ */
+uint32_t ble_db_discovery_close(void);
+
+
+/**@brief Function for registering with the DB Discovery module.
+ *
+ * @details The application can use this function to inform which service it is interested in
+ * discovering at the server.
+ *
+ * @param[in] p_uuid Pointer to the UUID of the service to be discovered at the server.
+ *
+ * @note The total number of services that can be discovered by this module is @ref
+ * BLE_DB_DISCOVERY_MAX_SRV. This effectively means that the maximum number of
+ * registrations possible is equal to the @ref BLE_DB_DISCOVERY_MAX_SRV.
+ *
+ * @retval NRF_SUCCESS Operation success.
+ * @retval NRF_ERROR_NULL When a NULL pointer is passed as input.
+ * @retval NRF_ERROR_INVALID_STATE If this function is called without calling the
+ * @ref ble_db_discovery_init.
+ * @retval NRF_ERROR_NO_MEM The maximum number of registrations allowed by this module
+ * has been reached.
+ */
+uint32_t ble_db_discovery_evt_register(const ble_uuid_t * const p_uuid);
+
+
+/**@brief Function for starting the discovery of the GATT database at the server.
+ *
+ * @param[out] p_db_discovery Pointer to the DB Discovery structure.
+ * @param[in] conn_handle The handle of the connection for which the discovery should be
+ * started.
+ *
+ * @retval NRF_SUCCESS Operation success.
+ * @retval NRF_ERROR_NULL When a NULL pointer is passed as input.
+ * @retval NRF_ERROR_INVALID_STATE If this function is called without calling the
+ * @ref ble_db_discovery_init, or without calling
+ * @ref ble_db_discovery_evt_register.
+ * @retval NRF_ERROR_BUSY If a discovery is already in progress using
+ * @p p_db_discovery. Use a different @ref ble_db_discovery_t
+ * structure, or wait for a DB Discovery event before retrying.
+ *
+ * @return This API propagates the error code returned by the
+ * SoftDevice API @ref sd_ble_gattc_primary_services_discover.
+ */
+uint32_t ble_db_discovery_start(ble_db_discovery_t * p_db_discovery,
+ uint16_t conn_handle);
+
+
+/**@brief Function for handling the Application's BLE Stack events.
+ *
+ * @param[in] p_ble_evt Pointer to the BLE event received.
+ * @param[in,out] p_context Pointer to the DB Discovery structure.
+ */
+void ble_db_discovery_on_ble_evt(ble_evt_t const * p_ble_evt,
+ void * p_context);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_DB_DISCOVERY_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_dtm/ble_dtm.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_dtm/ble_dtm.c
new file mode 100644
index 0000000..f73c030
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_dtm/ble_dtm.c
@@ -0,0 +1,957 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_DTM)
+#include "ble_dtm.h"
+#include "ble_dtm_hw.h"
+#include <stdbool.h>
+#include <string.h>
+#include "nrf.h"
+
+#define DTM_HEADER_OFFSET 0 /**< Index where the header of the pdu is located. */
+#define DTM_HEADER_SIZE 2 /**< Size of PDU header. */
+#define DTM_PAYLOAD_MAX_SIZE 255 /**< Maximum payload size allowed during dtm execution. */
+#define DTM_LENGTH_OFFSET (DTM_HEADER_OFFSET + 1) /**< Index where the length of the payload is encoded. */
+#define DTM_PDU_MAX_MEMORY_SIZE (DTM_HEADER_SIZE + DTM_PAYLOAD_MAX_SIZE) /**< Maximum PDU size allowed during dtm execution. */
+#define DTM_ON_AIR_OVERHEAD_SIZE 10 /**< Size of the packet on air without the payload (preamble + sync word + type + RFU + length + CRC). */
+
+#define RX_MODE true /**< Constant defining RX mode for radio during dtm test. */
+#define TX_MODE false /**< Constant defining TX mode for radio during dtm test. */
+
+#define PHYS_CH_MAX 39 /**< Maximum number of valid channels in BLE. */
+
+// Values that for now are "constants" - they could be configured by a function setting them,
+// but most of these are set by the BLE DTM standard, so changing them is not relevant.
+#define RFPHY_TEST_0X0F_REF_PATTERN 0x0f /**< RF-PHY test packet patterns, for the repeated octet packets. */
+#define RFPHY_TEST_0X55_REF_PATTERN 0x55 /**< RF-PHY test packet patterns, for the repeated octet packets. */
+#define RFPHY_TEST_0XFF_REF_PATTERN 0xFF /**< RF-PHY test packet patterns, for the repeated octet packets. */
+
+#define PRBS9_CONTENT {0xFF, 0xC1, 0xFB, 0xE8, 0x4C, 0x90, 0x72, 0x8B, \
+ 0xE7, 0xB3, 0x51, 0x89, 0x63, 0xAB, 0x23, 0x23, \
+ 0x02, 0x84, 0x18, 0x72, 0xAA, 0x61, 0x2F, 0x3B, \
+ 0x51, 0xA8, 0xE5, 0x37, 0x49, 0xFB, 0xC9, 0xCA, \
+ 0x0C, 0x18, 0x53, 0x2C, 0xFD, 0x45, 0xE3, 0x9A, \
+ 0xE6, 0xF1, 0x5D, 0xB0, 0xB6, 0x1B, 0xB4, 0xBE, \
+ 0x2A, 0x50, 0xEA, 0xE9, 0x0E, 0x9C, 0x4B, 0x5E, \
+ 0x57, 0x24, 0xCC, 0xA1, 0xB7, 0x59, 0xB8, 0x87, \
+ 0xFF, 0xE0, 0x7D, 0x74, 0x26, 0x48, 0xB9, 0xC5, \
+ 0xF3, 0xD9, 0xA8, 0xC4, 0xB1, 0xD5, 0x91, 0x11, \
+ 0x01, 0x42, 0x0C, 0x39, 0xD5, 0xB0, 0x97, 0x9D, \
+ 0x28, 0xD4, 0xF2, 0x9B, 0xA4, 0xFD, 0x64, 0x65, \
+ 0x06, 0x8C, 0x29, 0x96, 0xFE, 0xA2, 0x71, 0x4D, \
+ 0xF3, 0xF8, 0x2E, 0x58, 0xDB, 0x0D, 0x5A, 0x5F, \
+ 0x15, 0x28, 0xF5, 0x74, 0x07, 0xCE, 0x25, 0xAF, \
+ 0x2B, 0x12, 0xE6, 0xD0, 0xDB, 0x2C, 0xDC, 0xC3, \
+ 0x7F, 0xF0, 0x3E, 0x3A, 0x13, 0xA4, 0xDC, 0xE2, \
+ 0xF9, 0x6C, 0x54, 0xE2, 0xD8, 0xEA, 0xC8, 0x88, \
+ 0x00, 0x21, 0x86, 0x9C, 0x6A, 0xD8, 0xCB, 0x4E, \
+ 0x14, 0x6A, 0xF9, 0x4D, 0xD2, 0x7E, 0xB2, 0x32, \
+ 0x03, 0xC6, 0x14, 0x4B, 0x7F, 0xD1, 0xB8, 0xA6, \
+ 0x79, 0x7C, 0x17, 0xAC, 0xED, 0x06, 0xAD, 0xAF, \
+ 0x0A, 0x94, 0x7A, 0xBA, 0x03, 0xE7, 0x92, 0xD7, \
+ 0x15, 0x09, 0x73, 0xE8, 0x6D, 0x16, 0xEE, 0xE1, \
+ 0x3F, 0x78, 0x1F, 0x9D, 0x09, 0x52, 0x6E, 0xF1, \
+ 0x7C, 0x36, 0x2A, 0x71, 0x6C, 0x75, 0x64, 0x44, \
+ 0x80, 0x10, 0x43, 0x4E, 0x35, 0xEC, 0x65, 0x27, \
+ 0x0A, 0xB5, 0xFC, 0x26, 0x69, 0x3F, 0x59, 0x99, \
+ 0x01, 0x63, 0x8A, 0xA5, 0xBF, 0x68, 0x5C, 0xD3, \
+ 0x3C, 0xBE, 0x0B, 0xD6, 0x76, 0x83, 0xD6, 0x57, \
+ 0x05, 0x4A, 0x3D, 0xDD, 0x81, 0x73, 0xC9, 0xEB, \
+ 0x8A, 0x84, 0x39, 0xF4, 0x36, 0x0B, 0xF7} /**< The PRBS9 sequence used as packet payload.
+ The bytes in the sequence is in the right order, but the bits of each byte in the array is reverse.
+ of that found by running the PRBS9 algorithm. This is because of the endianess of the nRF5 radio. */
+
+/**@brief Structure holding the PDU used for transmitting/receiving a PDU.
+ */
+typedef struct
+{
+ uint8_t content[DTM_HEADER_SIZE + DTM_PAYLOAD_MAX_SIZE]; /**< PDU packet content. */
+} pdu_type_t;
+
+/**@brief States used for the DTM test implementation.
+ */
+typedef enum
+{
+ STATE_UNINITIALIZED, /**< The DTM is uninitialized. */
+ STATE_IDLE, /**< State when system has just initialized, or current test has completed. */
+ STATE_TRANSMITTER_TEST, /**< State used when a DTM Transmission test is running. */
+ STATE_CARRIER_TEST, /**< State used when a DTM Carrier test is running (Vendor specific test). */
+ STATE_RECEIVER_TEST /**< State used when a DTM Receive test is running. */
+} state_t;
+
+
+// Internal variables set as side effects of commands or events.
+static state_t m_state = STATE_UNINITIALIZED; /**< Current machine state. */
+static uint16_t m_rx_pkt_count; /**< Number of valid packets received. */
+static pdu_type_t m_pdu; /**< PDU to be sent. */
+static uint16_t m_event; /**< current command status - initially "ok", may be set if error detected, or to packet count. */
+static bool m_new_event; /**< Command has been processed - number of not yet reported event bytes. */
+static uint32_t m_packet_length; /**< Payload length of transmitted PDU, bits 2:7 of 16-bit dtm command. */
+static dtm_pkt_type_t m_packet_type; /**< Bits 0..1 of 16-bit transmit command, or 0xFFFFFFFF. */
+static dtm_freq_t m_phys_ch; /**< 0..39 physical channel number (base 2402 MHz, Interval 2 MHz), bits 8:13 of 16-bit dtm command. */
+static uint32_t m_current_time = 0; /**< Counter for interrupts from timer to ensure that the 2 bytes forming a DTM command are received within the time window. */
+
+// Nordic specific configuration values (not defined by BLE standard).
+// Definition of initial values found in ble_dtm.h
+static int32_t m_tx_power = DEFAULT_TX_POWER; /**< TX power for transmission test, default to maximum value (+4 dBm). */
+static NRF_TIMER_Type * mp_timer = DEFAULT_TIMER; /**< Timer to be used. */
+static IRQn_Type m_timer_irq = DEFAULT_TIMER_IRQn; /**< which interrupt line to clear on every timeout */
+
+static uint8_t const m_prbs_content[] = PRBS9_CONTENT; /**< Pseudo-random bit sequence defined by the BLE standard. */
+static uint8_t m_packetHeaderLFlen = 8; /**< Length of length field in packet Header (in bits). */
+static uint8_t m_packetHeaderS0len = 1; /**< Length of S0 field in packet Header (in bytes). */
+static uint8_t m_packetHeaderS1len = 0; /**< Length of S1 field in packet Header (in bits). */
+static uint8_t m_packetHeaderPlen = RADIO_PCNF0_PLEN_8bit; /**< Length of the preamble. */
+
+static uint8_t m_crcConfSkipAddr = 1; /**< Leave packet address field out of CRC calculation. */
+static uint8_t m_static_length = 0; /**< Number of bytes sent in addition to the var.length payload. */
+static uint32_t m_balen = 3; /**< Base address length in bytes. */
+static uint32_t m_endian = RADIO_PCNF1_ENDIAN_Little; /**< On air endianess of packet, this applies to the S0, LENGTH, S1 and the PAYLOAD fields. */
+static uint32_t m_whitening = RADIO_PCNF1_WHITEEN_Disabled; /**< Whitening disabled. */
+static uint8_t m_crcLength = RADIO_CRCCNF_LEN_Three; /**< CRC Length (in bytes). */
+static uint32_t m_address = 0x71764129; /**< Address. */
+static uint32_t m_crc_poly = 0x0000065B; /**< CRC polynomial. */
+static uint32_t m_crc_init = 0x00555555; /**< Initial value for CRC calculation. */
+static uint8_t m_radio_mode = RADIO_MODE_MODE_Ble_1Mbit; /**< nRF51 specific radio mode value. */
+static uint32_t m_txIntervaluS = 2500; /**< Time between start of Tx packets (in uS). */
+
+
+/**@brief Function for verifying that a received PDU has the expected structure and content.
+ */
+static bool check_pdu(void)
+{
+ uint8_t k; // Byte pointer for running through PDU payload
+ uint8_t pattern; // Repeating octet value in payload
+ dtm_pkt_type_t pdu_packet_type; // Note: PDU packet type is a 4-bit field in HCI, but 2 bits in BLE DTM
+ uint32_t length = 0;
+
+ pdu_packet_type = (dtm_pkt_type_t)(m_pdu.content[DTM_HEADER_OFFSET] & 0x0F);
+ length = m_pdu.content[DTM_LENGTH_OFFSET];
+
+ // Check that the length is valid.
+ if (length > DTM_PAYLOAD_MAX_SIZE)
+ {
+ return false;
+ }
+
+ // If the 1Mbit or 2Mbit radio mode is active, check that one of the three valid uncoded DTM packet types are selected.
+ if ((m_radio_mode == RADIO_MODE_MODE_Ble_1Mbit || m_radio_mode == RADIO_MODE_MODE_Ble_2Mbit) && (pdu_packet_type > (dtm_pkt_type_t)DTM_PKT_0X55))
+ {
+ return false;
+ }
+
+#ifdef NRF52840_XXAA
+ // If a long range radio mode is active, check that one of the four valid coded DTM packet types are selected.
+ if ((m_radio_mode == RADIO_MODE_MODE_Ble_LR500Kbit || m_radio_mode == RADIO_MODE_MODE_Ble_LR125Kbit) && (pdu_packet_type > (dtm_pkt_type_t)DTM_PKT_0XFF))
+ {
+ return false;
+ }
+#endif
+
+ if (pdu_packet_type == DTM_PKT_PRBS9)
+ {
+ // Payload does not consist of one repeated octet; must compare ir with entire block into
+ return (memcmp(m_pdu.content + DTM_HEADER_SIZE, m_prbs_content, length) == 0);
+ }
+
+ if (pdu_packet_type == DTM_PKT_0X0F)
+ {
+ pattern = RFPHY_TEST_0X0F_REF_PATTERN;
+ }
+ else if (pdu_packet_type == DTM_PKT_0X55)
+ {
+ pattern = RFPHY_TEST_0X55_REF_PATTERN;
+ }
+ else if (pdu_packet_type == DTM_PKT_0XFF)
+ {
+ pattern = RFPHY_TEST_0XFF_REF_PATTERN;
+ }
+ else
+ {
+ // No valid packet type set.
+ return false;
+ }
+
+ for (k = 0; k < length; k++)
+ {
+ // Check repeated pattern filling the PDU payload
+ if (m_pdu.content[k + 2] != pattern)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+/**@brief Function for turning off the radio after a test.
+ * Also called after test done, to be ready for next test.
+ */
+static void radio_reset(void)
+{
+ NRF_PPI->CHENCLR = PPI_CHENCLR_CH0_Msk | PPI_CHENCLR_CH1_Msk;
+
+ NRF_RADIO->SHORTS = 0;
+ NRF_RADIO->EVENTS_DISABLED = 0;
+ NRF_RADIO->TASKS_DISABLE = 1;
+
+ while (NRF_RADIO->EVENTS_DISABLED == 0)
+ {
+ // Do nothing
+ }
+
+ NRF_RADIO->EVENTS_DISABLED = 0;
+ NRF_RADIO->TASKS_RXEN = 0;
+ NRF_RADIO->TASKS_TXEN = 0;
+
+ m_rx_pkt_count = 0;
+}
+
+
+/**@brief Function for initializing the radio for DTM.
+ */
+static uint32_t radio_init(void)
+{
+ if (dtm_radio_validate(m_tx_power, m_radio_mode) != DTM_SUCCESS)
+ {
+ m_event = LE_TEST_STATUS_EVENT_ERROR;
+ return DTM_ERROR_ILLEGAL_CONFIGURATION;
+ }
+
+ // Turn off radio before configuring it
+ radio_reset();
+
+ NRF_RADIO->TXPOWER = m_tx_power;
+ NRF_RADIO->MODE = m_radio_mode << RADIO_MODE_MODE_Pos;
+
+ // Set the access address, address0/prefix0 used for both Rx and Tx address
+ NRF_RADIO->PREFIX0 &= ~RADIO_PREFIX0_AP0_Msk;
+ NRF_RADIO->PREFIX0 |= (m_address >> 24) & RADIO_PREFIX0_AP0_Msk;
+ NRF_RADIO->BASE0 = m_address << 8;
+ NRF_RADIO->RXADDRESSES = RADIO_RXADDRESSES_ADDR0_Enabled << RADIO_RXADDRESSES_ADDR0_Pos;
+ NRF_RADIO->TXADDRESS = (0x00 << RADIO_TXADDRESS_TXADDRESS_Pos) & RADIO_TXADDRESS_TXADDRESS_Msk;
+
+ // Configure CRC calculation
+ NRF_RADIO->CRCCNF = (m_crcConfSkipAddr << RADIO_CRCCNF_SKIP_ADDR_Pos) |
+ (m_crcLength << RADIO_CRCCNF_LEN_Pos);
+
+ if (m_radio_mode == RADIO_MODE_MODE_Ble_1Mbit || m_radio_mode == RADIO_MODE_MODE_Ble_2Mbit)
+ {
+ // Non-coded PHY
+ NRF_RADIO->PCNF0 = (m_packetHeaderS1len << RADIO_PCNF0_S1LEN_Pos) |
+ (m_packetHeaderS0len << RADIO_PCNF0_S0LEN_Pos) |
+ (m_packetHeaderLFlen << RADIO_PCNF0_LFLEN_Pos) |
+ (m_packetHeaderPlen << RADIO_PCNF0_PLEN_Pos);
+ }
+#ifdef NRF52840_XXAA
+ else
+ {
+ // Coded PHY (Long range)
+ NRF_RADIO->PCNF0 = (m_packetHeaderS1len << RADIO_PCNF0_S1LEN_Pos) |
+ (m_packetHeaderS0len << RADIO_PCNF0_S0LEN_Pos) |
+ (m_packetHeaderLFlen << RADIO_PCNF0_LFLEN_Pos) |
+ (3 << RADIO_PCNF0_TERMLEN_Pos) |
+ (2 << RADIO_PCNF0_CILEN_Pos) |
+ (m_packetHeaderPlen << RADIO_PCNF0_PLEN_Pos);
+ }
+#endif
+
+ NRF_RADIO->PCNF1 = (m_whitening << RADIO_PCNF1_WHITEEN_Pos) |
+ (m_endian << RADIO_PCNF1_ENDIAN_Pos) |
+ (m_balen << RADIO_PCNF1_BALEN_Pos) |
+ (m_static_length << RADIO_PCNF1_STATLEN_Pos) |
+ (DTM_PAYLOAD_MAX_SIZE << RADIO_PCNF1_MAXLEN_Pos);
+
+ return DTM_SUCCESS;
+}
+
+
+/**@brief Function for preparing the radio. At start of each test: Turn off RF, clear interrupt flags of RF, initialize the radio
+ * at given RF channel.
+ *
+ *@param[in] rx boolean indicating if radio should be prepared in rx mode (true) or tx mode.
+ */
+static void radio_prepare(bool rx)
+{
+ dtm_turn_off_test();
+ NRF_RADIO->CRCPOLY = m_crc_poly;
+ NRF_RADIO->CRCINIT = m_crc_init;
+ NRF_RADIO->FREQUENCY = (m_phys_ch << 1) + 2; // Actual frequency (MHz): 2400 + register value
+ NRF_RADIO->PACKETPTR = (uint32_t)&m_pdu; // Setting packet pointer will start the radio
+ NRF_RADIO->EVENTS_READY = 0;
+ NRF_RADIO->SHORTS = (1 << RADIO_SHORTS_READY_START_Pos) | // Shortcut between READY event and START task
+ (1 << RADIO_SHORTS_END_DISABLE_Pos); // Shortcut between END event and DISABLE task
+
+ if (rx)
+ {
+ NRF_RADIO->EVENTS_END = 0;
+ NRF_RADIO->TASKS_RXEN = 1; // shorts will start radio in RX mode when it is ready
+ }
+ else // tx
+ {
+ NRF_RADIO->TXPOWER = m_tx_power;
+ }
+}
+
+
+/**@brief Function for terminating the ongoing test (if any) and closing down the radio.
+ */
+static void dtm_test_done(void)
+{
+ dtm_turn_off_test();
+ NRF_PPI->CHENCLR = 0x01;
+ NRF_PPI->CH[0].EEP = 0; // Break connection from timer to radio to stop transmit loop
+ NRF_PPI->CH[0].TEP = 0;
+
+ radio_reset();
+ m_state = STATE_IDLE;
+}
+
+
+/**@brief Function for configuring the timer for 625us cycle time.
+ */
+static uint32_t timer_init(void)
+{
+ // Use 16MHz from external crystal
+ // This could be customized for RC/Xtal, or even to use a 32 kHz crystal
+ NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
+ NRF_CLOCK->TASKS_HFCLKSTART = 1;
+
+ while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)
+ {
+ // Do nothing while waiting for the clock to start
+ }
+
+ mp_timer->TASKS_STOP = 1; // Stop timer, if it was running
+ mp_timer->TASKS_CLEAR = 1;
+ mp_timer->MODE = TIMER_MODE_MODE_Timer; // Timer mode (not counter)
+ mp_timer->EVENTS_COMPARE[0] = 0; // clean up possible old events
+ mp_timer->EVENTS_COMPARE[1] = 0;
+ mp_timer->EVENTS_COMPARE[2] = 0;
+ mp_timer->EVENTS_COMPARE[3] = 0;
+
+ // Timer is polled, but enable the compare0 interrupt in order to wakeup from CPU sleep
+ mp_timer->INTENSET = TIMER_INTENSET_COMPARE0_Msk;
+ mp_timer->SHORTS = 1 << TIMER_SHORTS_COMPARE0_CLEAR_Pos; // Clear the count every time timer reaches the CCREG0 count
+ mp_timer->PRESCALER = 4; // Input clock is 16MHz, timer clock = 2 ^ prescale -> interval 1us
+ mp_timer->CC[0] = m_txIntervaluS; // 625uS with 1MHz clock to the timer
+ mp_timer->CC[1] = UART_POLL_CYCLE; // Depends on the baud rate of the UART. Default baud rate of 19200 will result in a 260uS time with 1MHz clock to the timer
+ mp_timer->TASKS_START = 1; // Start the timer - it will be running continuously
+ m_current_time = 0;
+ return DTM_SUCCESS;
+}
+
+
+/**@brief Function for handling vendor specific commands.
+ * Used when packet type is set to Vendor specific.
+ * The length field is used for encoding vendor specific command.
+ * The frequency field is used for encoding vendor specific options to the command.
+ *
+ * @param[in] vendor_cmd Vendor specific command to be executed.
+ * @param[in] vendor_option Vendor specific option to the vendor command.
+ *
+ * @return DTM_SUCCESS or one of the DTM_ERROR_ values
+ */
+static uint32_t dtm_vendor_specific_pkt(uint32_t vendor_cmd, dtm_freq_t vendor_option)
+{
+ switch (vendor_cmd)
+ {
+ // nRFgo Studio uses CARRIER_TEST_STUDIO to indicate a continuous carrier without
+ // a modulated signal.
+ case CARRIER_TEST:
+ case CARRIER_TEST_STUDIO:
+ // Not a packet type, but used to indicate that a continuous carrier signal
+ // should be transmitted by the radio.
+ radio_prepare(TX_MODE);
+
+ dtm_constant_carrier();
+
+ // Shortcut between READY event and START task
+ NRF_RADIO->SHORTS = 1 << RADIO_SHORTS_READY_START_Pos;
+
+ // Shortcut will start radio in Tx mode when it is ready
+ NRF_RADIO->TASKS_TXEN = 1;
+ m_state = STATE_CARRIER_TEST;
+ break;
+
+ case SET_TX_POWER:
+ if (!dtm_set_txpower(vendor_option))
+ {
+ m_event = LE_TEST_STATUS_EVENT_ERROR;
+ return DTM_ERROR_ILLEGAL_CONFIGURATION;
+ }
+ break;
+
+ case SELECT_TIMER:
+ if (!dtm_set_timer(vendor_option))
+ {
+ m_event = LE_TEST_STATUS_EVENT_ERROR;
+ return DTM_ERROR_ILLEGAL_CONFIGURATION;
+ }
+ break;
+ }
+ // Event code is unchanged, successful
+ return DTM_SUCCESS;
+}
+
+
+static uint32_t dtm_packet_interval_calculate(uint32_t test_payload_length, uint32_t mode)
+{
+ uint32_t test_packet_length = 0; // [us] NOTE: bits are us at 1Mbit
+ uint32_t packet_interval = 0; // us
+ uint32_t overhead_bits = 0; // bits
+
+ /* packet overhead
+ * see BLE [Vol 6, Part F] page 213
+ * 4.1 LE TEST PACKET FORMAT */
+ if (mode == RADIO_MODE_MODE_Ble_2Mbit)
+ {
+ // 16 preamble
+ // 32 sync word
+ // 8 PDU header, actually packetHeaderS0len * 8
+ // 8 PDU length, actually packetHeaderLFlen
+ // 24 CRC
+ overhead_bits = 88; // 11 bytes
+ }
+ else if (mode == RADIO_MODE_MODE_Ble_1Mbit)
+ {
+ // 8 preamble
+ // 32 sync word
+ // 8 PDU header, actually packetHeaderS0len * 8
+ // 8 PDU length, actually packetHeaderLFlen
+ // 24 CRC
+ overhead_bits = 80; // 10 bytes
+ }
+#ifdef NRF52840_XXAA
+ else if (mode == RADIO_MODE_MODE_Ble_LR125Kbit)
+ {
+ // 80 preamble
+ // 32 * 8 sync word coding=8
+ // 2 * 8 Coding indicator, coding=8
+ // 3 * 8 TERM1 coding=8
+ // 8 * 8 PDU header, actually packetHeaderS0len * 8 coding=8
+ // 8 * 8 PDU length, actually packetHeaderLFlen coding=8
+ // 24 * 8 CRC coding=8
+ // 3 * 8 TERM2 coding=8
+ overhead_bits = 720; // 90 bytes
+ }
+ else if (mode == RADIO_MODE_MODE_Ble_LR500Kbit)
+ {
+ // 80 preamble
+ // 32 * 8 sync word coding=8
+ // 2 * 8 Coding indicator, coding=8
+ // 3 * 8 TERM 1 coding=8
+ // 8 * 2 PDU header, actually packetHeaderS0len * 8 coding=2
+ // 8 * 2 PDU length, actually packetHeaderLFlen coding=2
+ // 24 * 2 CRC coding=2
+ // 3 * 2 TERM2 coding=2
+ // NOTE: this makes us clock out 46 bits for CI + TERM1 + TERM2
+ // assumption the radio will handle this
+ overhead_bits = 462; // 57.75 bytes
+ }
+#endif
+ /* add PDU payload test_payload length */
+ test_packet_length = (test_payload_length * 8); // in bits
+#ifdef NRF52840_XXAA
+ // account for the encoding of PDU
+ if (mode == RADIO_MODE_MODE_Ble_LR125Kbit)
+ {
+ test_packet_length *= 8; // 1 to 8 encoding
+ }
+ if (mode == RADIO_MODE_MODE_Ble_LR500Kbit)
+ {
+ test_packet_length *= 2; // 1 to 2 encoding
+ }
+#endif
+ // add overhead calculated above
+ test_packet_length += overhead_bits;
+ // we remember this bits are us in 1Mbit
+ if (mode == RADIO_MODE_MODE_Ble_2Mbit)
+ {
+ test_packet_length /= 2; // double speed
+ }
+
+ /*
+ * packet_interval = ceil((test_packet_length+249)/625)*625
+ * NOTE: To avoid floating point an equivalent calculation is used.
+ */
+ uint32_t i = 0;
+ uint32_t timeout = 0;
+ do
+ {
+ i++;
+ timeout = i * 625;
+ } while (test_packet_length + 249 > timeout);
+ packet_interval = i * 625;
+
+ return packet_interval;
+}
+
+
+uint32_t dtm_init(void)
+{
+ if ((timer_init() != DTM_SUCCESS) || (radio_init() != DTM_SUCCESS))
+ {
+ return DTM_ERROR_ILLEGAL_CONFIGURATION;
+ }
+ m_new_event = false;
+ m_state = STATE_IDLE;
+ m_packet_length = 0;
+
+ // Enable wake-up on event
+ SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
+
+ return DTM_SUCCESS;
+}
+
+
+uint32_t dtm_wait(void)
+{
+ // Enable wake-up on event
+ SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
+
+ for (;;)
+ {
+ // Event may be the reception of a packet -
+ // handle radio first, to give it highest priority:
+ if (NRF_RADIO->EVENTS_END != 0)
+ {
+ NRF_RADIO->EVENTS_END = 0;
+ NVIC_ClearPendingIRQ(RADIO_IRQn);
+
+ if (m_state == STATE_RECEIVER_TEST)
+ {
+ NRF_RADIO->TASKS_RXEN = 1;
+ if ((NRF_RADIO->CRCSTATUS == 1) && check_pdu())
+ {
+ // Count the number of successfully received packets
+ m_rx_pkt_count++;
+ }
+ // Note that failing packets are simply ignored (CRC or contents error).
+
+ // Zero fill all pdu fields to avoid stray data
+ memset(&m_pdu, 0, DTM_PDU_MAX_MEMORY_SIZE);
+ }
+ // If no RECEIVER_TEST is running, ignore incoming packets (but do clear IRQ!)
+ }
+
+ // Check for timeouts:
+ if (mp_timer->EVENTS_COMPARE[0] != 0)
+ {
+ mp_timer->EVENTS_COMPARE[0] = 0;
+ }
+ else if (mp_timer->EVENTS_COMPARE[1] != 0)
+ {
+ // Reset timeout event flag for next iteration.
+ mp_timer->EVENTS_COMPARE[1] = 0;
+ NVIC_ClearPendingIRQ(m_timer_irq);
+ return ++m_current_time;
+ }
+
+ // Other events: No processing
+ }
+}
+
+uint32_t dtm_cmd(dtm_cmd_t cmd, dtm_freq_t freq, uint32_t length, dtm_pkt_type_t payload)
+{
+ // Save specified packet in static variable for tx/rx functions to use.
+ // Note that BLE conformance testers always use full length packets.
+ m_packet_length = (m_packet_length & 0xC0) | ((uint8_t)length & 0x3F);
+ m_packet_type = payload;
+ m_phys_ch = freq;
+
+ // If 1 Mbit or 2 Mbit radio mode is in use check for Vendor Specific payload.
+ if ((m_radio_mode == RADIO_MODE_MODE_Ble_1Mbit || m_radio_mode == RADIO_MODE_MODE_Ble_2Mbit) && payload == DTM_PKT_VENDORSPECIFIC)
+ {
+ /* Note that in a HCI adaption layer, as well as in the DTM PDU format,
+ the value 0x03 is a distinct bit pattern (PRBS15). Even though BLE does not
+ support PRBS15, this implementation re-maps 0x03 to DTM_PKT_VENDORSPECIFIC,
+ to avoid the risk of confusion, should the code be extended to greater coverage.
+ */
+ m_packet_type = DTM_PKT_TYPE_VENDORSPECIFIC;
+ }
+
+ // Clean out any non-retrieved event that might linger from an earlier test
+ m_new_event = true;
+
+ // Set default event; any error will set it to LE_TEST_STATUS_EVENT_ERROR
+ m_event = LE_TEST_STATUS_EVENT_SUCCESS;
+
+ if (m_state == STATE_UNINITIALIZED)
+ {
+ // Application has not explicitly initialized DTM,
+ return DTM_ERROR_UNINITIALIZED;
+ }
+
+ if (cmd == LE_TEST_SETUP)
+ {
+ // Note that timer will continue running after a reset
+ dtm_test_done();
+ if (freq == LE_TEST_SETUP_RESET)
+ {
+ if (length != 0x00)
+ {
+ m_event = LE_TEST_STATUS_EVENT_ERROR;
+ return DTM_ERROR_ILLEGAL_CONFIGURATION;
+ }
+ // Reset the packet length upper bits.
+ m_packet_length = 0;
+
+ // Reset the selected PHY to 1Mbit
+ m_radio_mode = RADIO_MODE_MODE_Ble_1Mbit;
+ m_packetHeaderPlen = RADIO_PCNF0_PLEN_8bit;
+
+#ifdef NRF52840_XXAA
+ // Workaround for Errata ID 164
+ *(volatile uint32_t *)0x4000173C &= ~0x80000000;
+
+ // Workaround for Errata ID 191
+ *(volatile uint32_t *) 0x40001740 = ((*((volatile uint32_t *) 0x40001740)) & 0x7FFFFFFF);
+#endif
+ }
+ else if (freq == LE_TEST_SETUP_SET_UPPER)
+ {
+ if (length > 0x03)
+ {
+ m_event = LE_TEST_STATUS_EVENT_ERROR;
+ return DTM_ERROR_ILLEGAL_CONFIGURATION;
+ }
+ m_packet_length = length << 6;
+ }
+ else if (freq == LE_TEST_SETUP_SET_PHY)
+ {
+ switch (length)
+ {
+ case LE_PHY_1M:
+ m_radio_mode = RADIO_MODE_MODE_Ble_1Mbit;
+ m_packetHeaderPlen = RADIO_PCNF0_PLEN_8bit;
+
+#ifdef NRF52840_XXAA
+ // Workaround for Errata ID 164
+ *(volatile uint32_t *)0x4000173C &= ~0x80000000;
+
+ // Workaround for Errata ID 191
+ *(volatile uint32_t *) 0x40001740 = ((*((volatile uint32_t *) 0x40001740)) & 0x7FFFFFFF);
+#endif
+
+ return radio_init();
+
+ case LE_PHY_2M:
+ m_radio_mode = RADIO_MODE_MODE_Ble_2Mbit;
+ m_packetHeaderPlen = RADIO_PCNF0_PLEN_16bit;
+
+#ifdef NRF52840_XXAA
+ // Workaround for Errata ID 164
+ *(volatile uint32_t *)0x4000173C &= ~0x80000000;
+
+ // Workaround for Errata ID 191
+ *(volatile uint32_t *) 0x40001740 = ((*((volatile uint32_t *) 0x40001740)) & 0x7FFFFFFF);
+#endif
+
+ return radio_init();
+
+ case LE_PHY_LE_CODED_S8:
+#ifdef NRF52840_XXAA
+ m_radio_mode = RADIO_MODE_MODE_Ble_LR125Kbit;
+ m_packetHeaderPlen = RADIO_PCNF0_PLEN_LongRange;
+
+ // Workaround for Errata ID 164
+ *(volatile uint32_t *)0x4000173C |= 0x80000000;
+ *(volatile uint32_t *)0x4000173C = ((*(volatile uint32_t *)0x4000173C & 0xFFFFFF00) | 0x5C);
+
+ // Workaround for Errata ID 191
+ *(volatile uint32_t *) 0x40001740 = ((*((volatile uint32_t *) 0x40001740)) & 0x7FFF00FF) | 0x80000000 | (((uint32_t)(196)) << 8);
+
+ return radio_init();
+#else
+ m_event = LE_TEST_STATUS_EVENT_ERROR;
+ return DTM_ERROR_ILLEGAL_CONFIGURATION;
+#endif // NRF52840_XXAA
+ case LE_PHY_LE_CODED_S2:
+#ifdef NRF52840_XXAA
+ m_radio_mode = RADIO_MODE_MODE_Ble_LR500Kbit;
+ m_packetHeaderPlen = RADIO_PCNF0_PLEN_LongRange;
+
+ // Workaround for Errata ID 164
+ *(volatile uint32_t *)0x4000173C |= 0x80000000;
+ *(volatile uint32_t *)0x4000173C = ((*(volatile uint32_t *)0x4000173C & 0xFFFFFF00) | 0x5C);
+
+ // Workaround for Errata ID 191
+ *(volatile uint32_t *) 0x40001740 = ((*((volatile uint32_t *) 0x40001740)) & 0x7FFF00FF) | 0x80000000 | (((uint32_t)(196)) << 8);
+
+ return radio_init();
+#else
+ m_event = LE_TEST_STATUS_EVENT_ERROR;
+ return DTM_ERROR_ILLEGAL_CONFIGURATION;
+#endif
+ default:
+ m_event = LE_TEST_STATUS_EVENT_ERROR;
+ return DTM_ERROR_ILLEGAL_CONFIGURATION;
+ }
+ }
+ else if(freq == LE_TEST_SETUP_SELECT_MODULATION)
+ {
+ if (length > 0x01)
+ {
+ m_event = LE_TEST_STATUS_EVENT_ERROR;
+ return DTM_ERROR_ILLEGAL_CONFIGURATION;
+ }
+ // Only standard modulation is supported.
+ }
+ else if (freq == LE_TEST_SETUP_READ_SUPPORTED)
+ {
+ if (length != 0x00)
+ {
+ m_event = LE_TEST_STATUS_EVENT_ERROR;
+ return DTM_ERROR_ILLEGAL_CONFIGURATION;
+ }
+ // 0XXXXXXXXXXX0110 indicate that 2Mbit and DLE is supported and stable modulation is not supported (No nRF5 device supports this).
+ m_event = 0x0006;
+ }
+ else if (freq == LE_TEST_SETUP_READ_MAX)
+ {
+ // Read max supported value.
+ switch (length)
+ {
+ case 0x00:
+ // Read supportedMaxTxOctets
+ m_event = 0x01FE;
+ break;
+
+ case 0x01:
+ // Read supportedMaxTxTime
+ m_event = 0x4290;
+ break;
+
+ case 0x02:
+ // Read supportedMaxRxOctets
+ m_event = 0x01FE;
+ break;
+
+ case 0x03:
+ // Read supportedMaxRxTime
+ m_event = 0x4290;
+ break;
+
+ default:
+ m_event = LE_TEST_STATUS_EVENT_ERROR;
+ return DTM_ERROR_ILLEGAL_CONFIGURATION;
+ }
+ }
+ else
+ {
+ m_event = LE_TEST_STATUS_EVENT_ERROR;
+ return DTM_ERROR_ILLEGAL_CONFIGURATION;
+ }
+ return DTM_SUCCESS;
+ }
+
+ if (cmd == LE_TEST_END)
+ {
+ if (m_state == STATE_IDLE)
+ {
+ // Sequencing error - only rx or tx test may be ended!
+ m_event = LE_TEST_STATUS_EVENT_ERROR;
+ return DTM_ERROR_INVALID_STATE;
+ }
+ m_event = LE_PACKET_REPORTING_EVENT | m_rx_pkt_count;
+ dtm_test_done();
+ return DTM_SUCCESS;
+ }
+
+ if (m_state != STATE_IDLE)
+ {
+ // Sequencing error - only TEST_END/RESET are legal while test is running
+ // Note: State is unchanged; ongoing test not affected
+ m_event = LE_TEST_STATUS_EVENT_ERROR;
+ return DTM_ERROR_INVALID_STATE;
+ }
+
+ // Check for illegal values of m_phys_ch. Skip the check if the packet is vendor spesific.
+ if (payload != DTM_PKT_VENDORSPECIFIC && m_phys_ch > PHYS_CH_MAX)
+ {
+ // Parameter error
+ // Note: State is unchanged; ongoing test not affected
+ m_event = LE_TEST_STATUS_EVENT_ERROR;
+
+ return DTM_ERROR_ILLEGAL_CHANNEL;
+ }
+
+ m_rx_pkt_count = 0;
+
+ if (cmd == LE_RECEIVER_TEST)
+ {
+ // Zero fill all pdu fields to avoid stray data from earlier test run
+ memset(&m_pdu, 0, DTM_PDU_MAX_MEMORY_SIZE);
+ radio_prepare(RX_MODE); // Reinitialize "everything"; RF interrupts OFF
+ m_state = STATE_RECEIVER_TEST;
+ return DTM_SUCCESS;
+ }
+
+ if (cmd == LE_TRANSMITTER_TEST)
+ {
+ // Check for illegal values of m_packet_length. Skip the check if the packet is vendor spesific.
+ if (m_packet_type != DTM_PKT_TYPE_VENDORSPECIFIC && m_packet_length > DTM_PAYLOAD_MAX_SIZE)
+ {
+ // Parameter error
+ m_event = LE_TEST_STATUS_EVENT_ERROR;
+ return DTM_ERROR_ILLEGAL_LENGTH;
+ }
+
+
+ m_pdu.content[DTM_LENGTH_OFFSET] = m_packet_length;
+ // Note that PDU uses 4 bits even though BLE DTM uses only 2 (the HCI SDU uses all 4)
+ switch (m_packet_type)
+ {
+ case DTM_PKT_PRBS9:
+ m_pdu.content[DTM_HEADER_OFFSET] = DTM_PDU_TYPE_PRBS9;
+ // Non-repeated, must copy entire pattern to PDU
+ memcpy(m_pdu.content + DTM_HEADER_SIZE, m_prbs_content, m_packet_length);
+ break;
+
+ case DTM_PKT_0X0F:
+ m_pdu.content[DTM_HEADER_OFFSET] = DTM_PDU_TYPE_0X0F;
+ // Bit pattern 00001111 repeated
+ memset(m_pdu.content + DTM_HEADER_SIZE, RFPHY_TEST_0X0F_REF_PATTERN, m_packet_length);
+ break;
+
+ case DTM_PKT_0X55:
+ m_pdu.content[DTM_HEADER_OFFSET] = DTM_PDU_TYPE_0X55;
+ // Bit pattern 01010101 repeated
+ memset(m_pdu.content + DTM_HEADER_SIZE, RFPHY_TEST_0X55_REF_PATTERN, m_packet_length);
+ break;
+
+ case DTM_PKT_0XFF:
+ m_pdu.content[DTM_HEADER_OFFSET] = DTM_PDU_TYPE_0XFF;
+ // Bit pattern 11111111 repeated. Only available in coded PHY (Long range).
+ memset(m_pdu.content + DTM_HEADER_SIZE, RFPHY_TEST_0XFF_REF_PATTERN, m_packet_length);
+ break;
+
+ case DTM_PKT_TYPE_VENDORSPECIFIC:
+ // The length field is for indicating the vendor specific command to execute.
+ // The frequency field is used for vendor specific options to the command.
+ return dtm_vendor_specific_pkt(length, freq);
+
+ default:
+ // Parameter error
+ m_event = LE_TEST_STATUS_EVENT_ERROR;
+ return DTM_ERROR_ILLEGAL_CONFIGURATION;
+ }
+
+ // Initialize CRC value, set channel:
+ radio_prepare(TX_MODE);
+
+ // Set the timer to the correct period. The delay between each packet is described in the
+ // Bluetooth Core Spsification version 4.2 Vol. 6 Part F Section 4.1.6.
+ mp_timer->CC[0] = dtm_packet_interval_calculate(m_packet_length, m_radio_mode);
+
+ // Configure PPI so that timer will activate radio every 625 us
+ NRF_PPI->CH[0].EEP = (uint32_t)&mp_timer->EVENTS_COMPARE[0];
+ NRF_PPI->CH[0].TEP = (uint32_t)&NRF_RADIO->TASKS_TXEN;
+ NRF_PPI->CHENSET = 0x01;
+ m_state = STATE_TRANSMITTER_TEST;
+ }
+ return DTM_SUCCESS;
+}
+
+
+bool dtm_event_get(dtm_event_t *p_dtm_event)
+{
+ bool was_new = m_new_event;
+ // mark the current event as retrieved
+ m_new_event = false;
+ *p_dtm_event = m_event;
+ // return value indicates whether this value was already retrieved.
+ return was_new;
+}
+
+
+// =================================================================================================
+// Configuration functions (only for parameters not definitely determined by the BLE DTM standard).
+// These functions return true if successful, false if value could not be set
+
+
+/**@brief Function for configuring the output power for transmitter test.
+ This function may be called directly, or through dtm_cmd() specifying
+ DTM_PKT_VENDORSPECIFIC as payload, SET_TX_POWER as length, and the dBm value as frequency.
+ */
+bool dtm_set_txpower(uint32_t new_tx_power)
+{
+ // radio->TXPOWER register is 32 bits, low octet a signed value, upper 24 bits zeroed
+ int8_t new_power8 = (int8_t)(new_tx_power & 0xFF);
+
+ // The two most significant bits are not sent in the 6 bit field of the DTM command.
+ // These two bits are 1's if and only if the tx_power is a negative number.
+ // All valid negative values have the fourth most significant bit as 1.
+ // All valid positive values have the fourth most significant bit as 0.
+ // By checking this bit, the two most significant bits can be determined.
+ new_power8 = (new_power8 & 0x30) != 0 ? (new_power8 | 0xC0) : new_power8;
+
+ if (m_state > STATE_IDLE)
+ {
+ // radio must be idle to change the tx power
+ return false;
+ }
+
+ m_tx_power = new_power8;
+
+ return true;
+}
+
+
+/**@brief Function for selecting a timer resource.
+ * This function may be called directly, or through dtm_cmd() specifying
+ * DTM_PKT_VENDORSPECIFIC as payload, SELECT_TIMER as length, and the timer as freq
+ *
+ * @param[in] new_timer Timer id for the timer to use: 0, 1, or 2.
+ *
+ * @return true if the timer was successfully changed, false otherwise.
+ */
+bool dtm_set_timer(uint32_t new_timer)
+{
+ if (m_state > STATE_IDLE)
+ {
+ return false;
+ }
+ return dtm_hw_set_timer(&mp_timer, &m_timer_irq, new_timer);
+}
+
+/// @}
+#endif // NRF_MODULE_ENABLED(BLE_DTM)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_dtm/ble_dtm.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_dtm/ble_dtm.h
new file mode 100644
index 0000000..61f92c5
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_dtm/ble_dtm.h
@@ -0,0 +1,237 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_dtm DTM - Direct Test Mode
+ * @{
+ * @ingroup ble_sdk_lib
+ * @brief Module for testing RF/PHY using DTM commands.
+ */
+
+#ifndef BLE_DTM_H__
+#define BLE_DTM_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "nrf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**@brief Configuration parameters. */
+#define DTM_BITRATE UARTE_BAUDRATE_BAUDRATE_Baud19200 /**< Serial bitrate on the UART */
+#define DEFAULT_TX_POWER RADIO_TXPOWER_TXPOWER_0dBm /**< Default Transmission power using in the DTM module. */
+#define DEFAULT_TIMER NRF_TIMER0 /**< Default timer used for timing. */
+#define DEFAULT_TIMER_IRQn TIMER0_IRQn /**< IRQ used for timer. NOTE: MUST correspond to DEFAULT_TIMER. */
+
+/**@brief BLE DTM command codes. */
+typedef uint32_t dtm_cmd_t; /**< DTM command type. */
+
+#define LE_TEST_SETUP 0 /**< DTM command: Set PHY or modulation, configure upper two bits of length,
+ request matrix of supported features or request max values of parameters. */
+#define LE_RECEIVER_TEST 1 /**< DTM command: Start receive test. */
+#define LE_TRANSMITTER_TEST 2 /**< DTM command: Start transmission test. */
+#define LE_TEST_END 3 /**< DTM command: End test and send packet report. */
+
+#define LE_TEST_SETUP_RESET 0 /**< DTM command parameter: Stop TX/RX, reset the packet length upper bits and set the PHY to 1Mbit. */
+#define LE_TEST_SETUP_SET_UPPER 1 /**< DTM command parameter: Set the upper two bits of the length field. */
+#define LE_TEST_SETUP_SET_PHY 2 /**< DTM command parameter: Select the PHY to be used for packets. */
+#define LE_TEST_SETUP_SELECT_MODULATION 3 /**< DTM command parameter: Select standard or stable modulation index. Stable modulation index is not supported. */
+#define LE_TEST_SETUP_READ_SUPPORTED 4 /**< DTM command parameter: Read the supported test case features. */
+#define LE_TEST_SETUP_READ_MAX 5 /**< DTM command parameter: Read the max supported time and length for packets. */
+
+#define LE_PHY_1M 1 /**< DTM command parameter: Set PHY for future packets to use 1MBit PHY. */
+#define LE_PHY_2M 2 /**< DTM command parameter: Set PHY for future packets to use 2MBit PHY. */
+#define LE_PHY_LE_CODED_S8 3 /**< DTM command parameter: Set PHY for future packets to use coded PHY with S=8. */
+#define LE_PHY_LE_CODED_S2 4 /**< DTM command parameter: Set PHY for future packets to use coded PHY with S=2 */
+
+// Configuration options used as parameter 2
+// when cmd == LE_TRANSMITTER_TEST and payload == DTM_PKT_VENDORSPECIFIC
+// Configuration value, if any, is supplied in parameter 3
+
+#define CARRIER_TEST 0 /**< Length=0 indicates a constant, unmodulated carrier until LE_TEST_END or LE_RESET */
+#define CARRIER_TEST_STUDIO 1 /**< nRFgo Studio uses value 1 in length field, to indicate a constant, unmodulated carrier until LE_TEST_END or LE_RESET */
+#define SET_TX_POWER 2 /**< Set transmission power, value -40..+4 dBm in steps of 4 */
+#define SELECT_TIMER 3 /**< Select on of the 16 MHz timers 0, 1 or 2 */
+
+#define LE_PACKET_REPORTING_EVENT 0x8000 /**< DTM Packet reporting event, returned by the device to the tester. */
+#define LE_TEST_STATUS_EVENT_SUCCESS 0x0000 /**< DTM Status event, indicating success. */
+#define LE_TEST_STATUS_EVENT_ERROR 0x0001 /**< DTM Status event, indicating an error. */
+
+#define DTM_PKT_PRBS9 0x00 /**< Bit pattern PRBS9. */
+#define DTM_PKT_0X0F 0x01 /**< Bit pattern 11110000 (LSB is the leftmost bit). */
+#define DTM_PKT_0X55 0x02 /**< Bit pattern 10101010 (LSB is the leftmost bit). */
+#define DTM_PKT_0XFF 0x03 /**< Bit pattern 11111111 (Used only for coded PHY). */
+#define DTM_PKT_VENDORSPECIFIC 0x03 /**< Vendor specific PKT field value. Nordic: Continuous carrier test, or configuration. */
+#define DTM_PKT_TYPE_VENDORSPECIFIC 0xFF /**< Vendor specific packet type for internal use. */
+
+// The pdu payload type for each bit pattern. Identical to the PKT value except pattern 0xFF which is 0x04.
+#define DTM_PDU_TYPE_PRBS9 0x00 /**< PDU payload type for bit pattern PRBS9. */
+#define DTM_PDU_TYPE_0X0F 0x01 /**< PDU payload type for bit pattern 11110000 (LSB is the leftmost bit). */
+#define DTM_PDU_TYPE_0X55 0x02 /**< PDU payload type for bit pattern 10101010 (LSB is the leftmost bit). */
+#define DTM_PDU_TYPE_0XFF 0x04 /**< PDU payload type for bit pattern 11111111 (Used only for coded PHY). */
+
+/**@brief Return codes from dtm_cmd(). */
+#define DTM_SUCCESS 0x00 /**< Indicate that the DTM function completed with success. */
+#define DTM_ERROR_ILLEGAL_CHANNEL 0x01 /**< Physical channel number must be in the range 0..39. */
+#define DTM_ERROR_INVALID_STATE 0x02 /**< Sequencing error: Command is not valid now. */
+#define DTM_ERROR_ILLEGAL_LENGTH 0x03 /**< Payload size must be in the range 0..37. */
+#define DTM_ERROR_ILLEGAL_CONFIGURATION 0x04 /**< Parameter out of range (legal range is function dependent). */
+#define DTM_ERROR_UNINITIALIZED 0x05 /**< DTM module has not been initialized by the application. */
+
+/**@details The UART poll cycle in micro seconds.
+ * A baud rate of e.g. 19200 bits / second, and 8 data bits, 1 start/stop bit, no flow control,
+ * give the time to transmit a byte: 10 bits * 1/19200 = approx: 520 us.
+ * To ensure no loss of bytes, the UART should be polled every 260 us.
+ */
+#if DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud9600
+#define UART_POLL_CYCLE ((uint32_t)(10*1e6/9600/2))
+#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud14400
+#define UART_POLL_CYCLE ((uint32_t)(10*1e6/14400/2))
+#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud19200
+#define UART_POLL_CYCLE ((uint32_t)(10*1e6/19200/2))
+#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud28800
+#define UART_POLL_CYCLE ((uint32_t)(10*1e6/28800/2))
+#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud38400
+#define UART_POLL_CYCLE ((uint32_t)(10*1e6/38400/2))
+#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud57600
+#define UART_POLL_CYCLE ((uint32_t)(10*1e6/57600/2))
+#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud76800
+#define UART_POLL_CYCLE ((uint32_t)(10*1e6/768000/2))
+#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud115200
+#define UART_POLL_CYCLE ((uint32_t)(10*1e6/115200/2))
+#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud230400
+#define UART_POLL_CYCLE ((uint32_t)(10*1e6/230400/2))
+#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud250000
+#define UART_POLL_CYCLE ((uint32_t)(10*1e6/250000/2))
+#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud460800
+#define UART_POLL_CYCLE ((uint32_t)(10*1e6/460800/2))
+#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud921600
+#define UART_POLL_CYCLE ((uint32_t)(10*1e6/921600/2))
+#elif DTM_BITRATE == UARTE_BAUDRATE_BAUDRATE_Baud1M
+#define UART_POLL_CYCLE ((uint32_t)(10*1e6/1e6/2))
+#else
+// It is possible to find values that work for other baud rates, but the formula above is not
+// guaranteed to work for all values. Suitable values may have to be found by trial and error.
+#error "Unsupported baud rate set."
+#endif
+
+// Note: DTM_PKT_VENDORSPECIFIC, is not a packet type
+#define PACKET_TYPE_MAX DTM_PKT_0XFF /**< Highest value allowed as DTM Packet type. */
+
+/** @brief BLE DTM event type. */
+typedef uint32_t dtm_event_t; /**< Type for handling DTM event. */
+
+/** @brief BLE DTM frequency type. */
+typedef uint32_t dtm_freq_t; /**< Physical channel, valid range: 0..39. */
+
+/**@brief BLE DTM packet types. */
+typedef uint32_t dtm_pkt_type_t; /**< Type for holding the requested DTM payload type.*/
+
+
+/**@brief Function for initializing or re-initializing DTM module
+ *
+ * @return DTM_SUCCESS on successful initialization of the DTM module.
+*/
+uint32_t dtm_init(void);
+
+
+/**@brief Function for giving control to dtmlib for handling timer and radio events.
+ * Will return to caller at 625us intervals or whenever another event than radio occurs
+ * (such as UART input). Function will put MCU to sleep between events.
+ *
+ * @return Time counter, incremented every 625 us.
+ */
+uint32_t dtm_wait(void);
+
+
+/**@brief Function for calling when a complete command has been prepared by the Tester.
+ *
+ * @param[in] cmd One of the DTM_CMD values (bits 14:15 in the 16-bit UART format).
+ * @param[in] freq Phys. channel no - actual frequency = (2402 + freq * 2) MHz (bits 8:13 in
+ * the 16-bit UART format).
+ * @param[in] length Payload length, 0..37 (bits 2:7 in the 16-bit UART format).
+ * @param[in] payload One of the DTM_PKT values (bits 0:1 in the 16-bit UART format).
+ *
+ * @return DTM_SUCCESS or one of the DTM_ERROR_ values
+ */
+uint32_t dtm_cmd(dtm_cmd_t cmd, dtm_freq_t freq, uint32_t length, dtm_pkt_type_t payload);
+
+
+/**@brief Function for reading the result of a DTM command
+ *
+ * @param[out] p_dtm_event Pointer to buffer for 16 bit event code according to DTM standard.
+ *
+ * @return true: new event, false: no event since last call, this event has been read earlier
+ */
+bool dtm_event_get(dtm_event_t * p_dtm_event);
+
+
+/**@brief Function for configuring the timer to use.
+ *
+ * @note Must be called when no DTM test is running.
+ *
+ * @param[in] new_timer Index (0..2) of timer to be used by the DTM library
+ *
+ * @return true: success, new timer was selected, false: parameter error
+ */
+bool dtm_set_timer(uint32_t new_timer);
+
+
+/**@brief Function for configuring the transmit power.
+ *
+ * @note Must be called when no DTM test is running.
+ *
+ * @param[in] new_tx_power New output level, +4..-40, in steps of 4.
+ *
+ * @return true: tx power setting changed, false: parameter error
+ */
+bool dtm_set_txpower(uint32_t new_tx_power);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_DTM_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_dtm/ble_dtm_hw.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_dtm/ble_dtm_hw.h
new file mode 100644
index 0000000..944cf33
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_dtm/ble_dtm_hw.h
@@ -0,0 +1,103 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_dtm_hw Direct Test Mode HW
+ * @{
+ * @ingroup ble_sdk_lib
+ * @brief Module contains hardware related function for testing RF/PHY using DTM commands.
+ */
+
+#ifndef BLE_DTM_HW_H__
+#define BLE_DTM_HW_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "nrf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**@brief Function for selecting a timer resource.
+ * This function may be called directly, or through dtm_cmd() specifying
+ * DTM_PKT_VENDORSPECIFIC as payload, SELECT_TIMER as length, and the timer as freq
+ *
+ * @param[out] mp_timer Pointer to timer instance used in dtm source file.
+ * @param[out] m_timer_irq Pointer to timer interrupt related to mp_timer.
+ * @param[in] new_timer Timer id for the timer to use.
+ *
+ * @retval true if the timer was successfully changed.
+ * @retval false if the error occurs.
+ */
+
+bool dtm_hw_set_timer(NRF_TIMER_Type ** mp_timer, IRQn_Type * m_timer_irq, uint32_t new_timer);
+
+
+/**@brief Function for turning off radio test.
+ * This function is platform depending. For now only nRF51 requieres this special function.
+ */
+void dtm_turn_off_test(void);
+
+
+/**@brief Function for setting constant carrier in radio settings.
+ * This function is used to handle vendor specific command testing continous carrier without
+ * a modulated signal.
+ */
+void dtm_constant_carrier(void);
+
+
+/**@brief Function for validating tx power and radio move settings.
+ * @param[in] m_tx_power TX power for transmission test.
+ * @param[in] m_radio_mode Radio mode value.
+ *
+ * @retval DTM_SUCCESS if input parameters values are correct.
+ * @retval DTM_ERROR_ILLEGAL_CONFIGURATION if input parameters values are not correct.
+ */
+uint32_t dtm_radio_validate(int32_t m_tx_power, uint8_t m_radio_mode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_DTM_HW_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_dtm/ble_dtm_hw_nrf51.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_dtm/ble_dtm_hw_nrf51.c
new file mode 100644
index 0000000..1e6acca
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_dtm/ble_dtm_hw_nrf51.c
@@ -0,0 +1,120 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "ble_dtm_hw.h"
+#include "ble_dtm.h"
+#include <stdbool.h>
+#include <string.h>
+#include "nrf.h"
+
+
+void dtm_turn_off_test()
+{
+ NRF_RADIO->TEST = 0;
+}
+
+
+void dtm_constant_carrier()
+{
+ NRF_RADIO->TEST = (RADIO_TEST_PLL_LOCK_Enabled << RADIO_TEST_PLL_LOCK_Pos) |
+ (RADIO_TEST_CONST_CARRIER_Enabled << RADIO_TEST_CONST_CARRIER_Pos);
+}
+
+
+uint32_t dtm_radio_validate(int32_t m_tx_power, uint8_t m_radio_mode)
+{
+ // Handle BLE Radio tuning parameters from production for DTM if required.
+ // Only needed for DTM without SoftDevice, as the SoftDevice normally handles this.
+ // PCN-083.
+ if ( ((NRF_FICR->OVERRIDEEN) & FICR_OVERRIDEEN_BLE_1MBIT_Msk) == FICR_OVERRIDEEN_BLE_1MBIT_Override)
+ {
+ NRF_RADIO->OVERRIDE0 = NRF_FICR->BLE_1MBIT[0];
+ NRF_RADIO->OVERRIDE1 = NRF_FICR->BLE_1MBIT[1];
+ NRF_RADIO->OVERRIDE2 = NRF_FICR->BLE_1MBIT[2];
+ NRF_RADIO->OVERRIDE3 = NRF_FICR->BLE_1MBIT[3];
+ NRF_RADIO->OVERRIDE4 = NRF_FICR->BLE_1MBIT[4];
+ }
+
+ // Initializing code below is quite generic - for BLE, the values are fixed, and expressions
+ // are constant. Non-constant values are essentially set in radio_prepare().
+ if (!(m_tx_power == RADIO_TXPOWER_TXPOWER_0dBm ||
+ m_tx_power == RADIO_TXPOWER_TXPOWER_Pos4dBm ||
+ m_tx_power == RADIO_TXPOWER_TXPOWER_Neg30dBm ||
+ m_tx_power == RADIO_TXPOWER_TXPOWER_Neg20dBm ||
+ m_tx_power == RADIO_TXPOWER_TXPOWER_Neg16dBm ||
+ m_tx_power == RADIO_TXPOWER_TXPOWER_Neg12dBm ||
+ m_tx_power == RADIO_TXPOWER_TXPOWER_Neg8dBm ||
+ m_tx_power == RADIO_TXPOWER_TXPOWER_Neg4dBm
+ ) ||
+ (m_radio_mode > RADIO_MODE_MODE_Ble_1Mbit) // Values 0 - 2: Proprietary mode, 3 (last valid): BLE
+ )
+ {
+ return DTM_ERROR_ILLEGAL_CONFIGURATION;
+ }
+
+ return DTM_SUCCESS;
+}
+
+
+bool dtm_hw_set_timer(NRF_TIMER_Type ** mp_timer, IRQn_Type * m_timer_irq, uint32_t new_timer)
+{
+ if (new_timer == 0)
+ {
+ *mp_timer = NRF_TIMER0;
+ *m_timer_irq = TIMER0_IRQn;
+ }
+ else if (new_timer == 1)
+ {
+ *mp_timer = NRF_TIMER1;
+ *m_timer_irq = TIMER1_IRQn;
+ }
+ else if (new_timer == 2)
+ {
+ *mp_timer = NRF_TIMER2;
+ *m_timer_irq = TIMER2_IRQn;
+ }
+ else
+ {
+ // Parameter error: Only TIMER 0, 1, 2 provided by nRF51
+ return false;
+ }
+ // New timer has been selected:
+ return true;
+}
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_dtm/ble_dtm_hw_nrf52.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_dtm/ble_dtm_hw_nrf52.c
new file mode 100644
index 0000000..4dcfa96
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_dtm/ble_dtm_hw_nrf52.c
@@ -0,0 +1,128 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "ble_dtm_hw.h"
+#include "ble_dtm.h"
+#include <stdbool.h>
+#include <string.h>
+#include "nrf.h"
+
+
+void dtm_turn_off_test()
+{
+}
+
+
+void dtm_constant_carrier()
+{
+NRF_RADIO->MODECNF0 = (RADIO_MODECNF0_RU_Default << RADIO_MODECNF0_RU_Pos) |
+ (RADIO_MODECNF0_DTX_Center << RADIO_MODECNF0_DTX_Pos);
+}
+
+
+uint32_t dtm_radio_validate(int32_t m_tx_power, uint8_t m_radio_mode)
+{
+ // Initializing code below is quite generic - for BLE, the values are fixed, and expressions
+ // are constant. Non-constant values are essentially set in radio_prepare().
+ if (!(m_tx_power == RADIO_TXPOWER_TXPOWER_0dBm ||
+ m_tx_power == RADIO_TXPOWER_TXPOWER_Pos4dBm ||
+ m_tx_power == RADIO_TXPOWER_TXPOWER_Neg30dBm ||
+ m_tx_power == RADIO_TXPOWER_TXPOWER_Neg20dBm ||
+ m_tx_power == RADIO_TXPOWER_TXPOWER_Neg16dBm ||
+ m_tx_power == RADIO_TXPOWER_TXPOWER_Neg12dBm ||
+ m_tx_power == RADIO_TXPOWER_TXPOWER_Neg8dBm ||
+ m_tx_power == RADIO_TXPOWER_TXPOWER_Neg4dBm ||
+ m_tx_power == RADIO_TXPOWER_TXPOWER_Pos3dBm ||
+ m_tx_power == RADIO_TXPOWER_TXPOWER_Neg40dBm
+ ) ||
+
+ !(
+#ifdef NRF52840_XXAA
+ m_radio_mode == RADIO_MODE_MODE_Ble_LR125Kbit ||
+ m_radio_mode == RADIO_MODE_MODE_Ble_LR500Kbit ||
+#endif //NRF52840_XXAA
+ m_radio_mode == RADIO_MODE_MODE_Ble_1Mbit ||
+ m_radio_mode == RADIO_MODE_MODE_Ble_2Mbit
+ )
+ )
+ {
+ return DTM_ERROR_ILLEGAL_CONFIGURATION;
+ }
+
+ return DTM_SUCCESS;
+}
+
+
+bool dtm_hw_set_timer(NRF_TIMER_Type ** mp_timer, IRQn_Type * m_timer_irq, uint32_t new_timer)
+{
+ if (new_timer == 0)
+ {
+ *mp_timer = NRF_TIMER0;
+ *m_timer_irq = TIMER0_IRQn;
+ }
+ else if (new_timer == 1)
+ {
+ *mp_timer = NRF_TIMER1;
+ *m_timer_irq = TIMER1_IRQn;
+ }
+ else if (new_timer == 2)
+ {
+ *mp_timer = NRF_TIMER2;
+ *m_timer_irq = TIMER2_IRQn;
+ }
+#ifndef NRF52810_XXAA
+ else if (new_timer == 3)
+ {
+ *mp_timer = NRF_TIMER3;
+ *m_timer_irq = TIMER3_IRQn;
+ }
+ else if (new_timer == 4)
+ {
+ *mp_timer = NRF_TIMER4;
+ *m_timer_irq = TIMER4_IRQn;
+ }
+#endif //NRF52810_XXAA
+ else
+ {
+ // Parameter error: Only TIMER 0, 1, 2, 3 and 4 provided by nRF52
+ return false;
+ }
+ // New timer has been selected:
+ return true;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_lesc/ble_lesc.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_lesc/ble_lesc.c
new file mode 100644
index 0000000..a3d808d
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_lesc/ble_lesc.c
@@ -0,0 +1,443 @@
+/**
+ * Copyright (c) 2018 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_LESC)
+
+#include "sdk_common.h"
+#include "ble_gap.h"
+#include "ble_lesc.h"
+#include "nrf_crypto.h"
+#include "nrf_crypto_mem.h"
+#include "peer_manager.h"
+#include "nrf_sdh_ble.h"
+#include "ble_conn_state.h"
+#define NRF_LOG_MODULE_NAME ble_lesc
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+/**@brief Structure holding a ECDH public key, connection handle and valid state */
+typedef struct
+{
+ nrf_crypto_ecc_public_key_t public_key; /**< Public key used in either central or peripheral link. */
+ volatile uint16_t conn_handle; /**< Connection handle for connection that received the public key. */
+ volatile bool is_valid; /**< Flag indicating that the public key was valid. */
+} ble_lesc_public_key_t;
+
+/**@brief Context to generate an ECC private/public key pair
+ */
+static nrf_crypto_ecc_key_pair_generate_context_t m_ecc_keygen_context;
+
+
+/**@brief Context to do the LESC ECDH calculation.
+ */
+static nrf_crypto_ecdh_context_t m_ecdh_context;
+
+
+/**@brief Private key to use for LESC ECDH calculations
+ */
+static nrf_crypto_ecc_private_key_t m_local_private_key;
+
+
+/**@brief Public key to use for LESC ECDH calculation
+ */
+static ble_lesc_public_key_t m_local_public_key;
+
+
+/**@brief Structure holding peer central LESC ECC public key and valid state
+ */
+static ble_lesc_public_key_t m_peer_public_key_central =
+{
+ .conn_handle = BLE_CONN_HANDLE_INVALID,
+ .is_valid = false
+};
+
+
+/**@brief Structure holding peer peripheral LESC ECC public key and valid state
+ */
+static ble_lesc_public_key_t m_peer_public_key_peripheral =
+{
+ .conn_handle = BLE_CONN_HANDLE_INVALID,
+ .is_valid = false
+};
+
+/**@brief LESC ECC public key in a format usable by SoftDevice APIs.
+ *
+ * @note The BLE specification requires this key to be in little-endian format.
+ */
+static ble_gap_lesc_p256_pk_t m_lesc_public_key;
+
+
+/**@brief LESC ECDH key in a format usable by SoftDevice APIs.
+ *
+ * @note The BLE specification requires this key to be in little-endian format.
+ */
+static ble_gap_lesc_dhkey_t m_lesc_ecdh_key;
+
+
+static bool m_ble_lesc_invalid_state = false;
+static bool m_keypair_generated = false; /**< Flag indicating that the local ECDH key pair was generated. */
+
+
+static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context);
+NRF_SDH_BLE_OBSERVER(m_ble_evt_observer, BLE_LESC_OBSERVER_PRIO, ble_evt_handler, NULL);
+
+
+/**@brief Function to calculate LESC ECDH and set it using SoftDevice API
+ *
+ * @details This function calculates a LESC ECDH key (also know as a shared secret)
+ * sets it using a call to @ref sd_ble_gap_lesc_dhkey_reply.
+ *
+ * @note This function will only work if there is a generated local ECC key pair (private and
+ * public key pair) and a valid ECC public key received from the peer on either a peripheral
+ * or central link. If the ECC public key from the peer is invalid, a random shared secret
+ * is generated and set using the @ref sd_ble_gap_lesc_dhkey_reply call.
+ *
+ * @warning This function must be run in a low interrupt priority, like the main
+ * application context. Running this in a high priority interrupt level
+ * may disrupt time critical operations like radio communications.
+ *
+ * @retval
+ */
+static ret_code_t ble_lesc_dhkey_calculate_and_set(ble_lesc_public_key_t * const p_peer_public_key)
+{
+ ret_code_t err_code = NRF_ERROR_INVALID_STATE;
+ size_t shared_secret_size = BLE_GAP_LESC_DHKEY_LEN;
+
+ uint8_t * p_shared_secret = m_lesc_ecdh_key.key;
+
+ // Check if there is a valid generated and set local ECDH public key
+ if (!m_keypair_generated)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ // Check if the public_key is valid
+ if (p_peer_public_key->is_valid)
+ {
+ err_code = nrf_crypto_ecdh_compute(&m_ecdh_context,
+ &m_local_private_key,
+ &p_peer_public_key->public_key,
+ p_shared_secret,
+ &shared_secret_size);
+ }
+
+ if(err_code == NRF_SUCCESS)
+ {
+ err_code = nrf_crypto_ecc_byte_order_invert(&g_nrf_crypto_ecc_secp256r1_curve_info,
+ p_shared_secret,
+ p_shared_secret,
+ BLE_GAP_LESC_DHKEY_LEN);
+ VERIFY_SUCCESS(err_code);
+ }
+ else
+ {
+ NRF_LOG_WARNING("Creating invalid shared secret to make LESC fail.");
+ err_code = nrf_crypto_rng_vector_generate(p_shared_secret, BLE_GAP_LESC_DHKEY_LEN);
+ VERIFY_SUCCESS(err_code);
+ }
+
+ NRF_LOG_DEBUG("Calling sd_ble_gap_lesc_dhkey_reply on conn_handle: %d", p_peer_public_key->conn_handle);
+ err_code = sd_ble_gap_lesc_dhkey_reply(p_peer_public_key->conn_handle, &m_lesc_ecdh_key);
+
+ return err_code;
+}
+
+
+/**@brief Function to set the peer ECC public key for a peripheral link
+ *
+ * @details This call should be made to
+ *
+ * @param[in] conn_handle The connection handle to the peripheral connection.
+ * @param[in] p_public_key Pointer to structure holding the public key received from the peer.
+ *
+ * @retval
+ */
+static ret_code_t ble_lesc_peer_peripheral_public_key_set(
+ uint16_t conn_handle,
+ ble_gap_lesc_p256_pk_t const * const p_public_key)
+{
+ ret_code_t err_code;
+
+ uint8_t public_raw[BLE_GAP_LESC_P256_PK_LEN];
+ size_t public_raw_len = BLE_GAP_LESC_P256_PK_LEN;
+
+ VERIFY_TRUE(conn_handle != BLE_CONN_HANDLE_INVALID, NRF_ERROR_INVALID_PARAM);
+ VERIFY_PARAM_NOT_NULL(p_public_key);
+
+ memcpy(public_raw, p_public_key->pk, BLE_GAP_LESC_P256_PK_LEN);
+
+ err_code = nrf_crypto_ecc_byte_order_invert(&g_nrf_crypto_ecc_secp256r1_curve_info,
+ public_raw,
+ public_raw,
+ NRF_CRYPTO_ECC_SECP256R1_RAW_PUBLIC_KEY_SIZE);
+ VERIFY_SUCCESS(err_code);
+
+
+ err_code = nrf_crypto_ecc_public_key_from_raw(&g_nrf_crypto_ecc_secp256r1_curve_info,
+ &m_peer_public_key_peripheral.public_key,
+ public_raw,
+ public_raw_len);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ m_peer_public_key_peripheral.is_valid = true;
+ }
+ else
+ {
+ m_peer_public_key_peripheral.is_valid = false;
+ }
+
+ m_peer_public_key_peripheral.conn_handle = conn_handle;
+
+ return NRF_SUCCESS;
+}
+
+/**@brief Function to set peer ECC public key for a central link
+ *
+ * @details Setting the peer ECC public key will start a
+ *
+ * @param[in] conn_handle The connection handle to the peripheral connection.
+ * @param[in] p_public_key Pointer to structure holding the public key received from the peer.
+ *
+ * @retval
+ */
+static ret_code_t ble_lesc_peer_central_public_key_set(
+ uint16_t conn_handle,
+ ble_gap_lesc_p256_pk_t const * const p_public_key)
+{
+ ret_code_t err_code;
+
+ uint8_t public_raw[BLE_GAP_LESC_P256_PK_LEN];
+ size_t public_raw_len = BLE_GAP_LESC_P256_PK_LEN;
+
+ VERIFY_TRUE(conn_handle != BLE_CONN_HANDLE_INVALID, NRF_ERROR_INVALID_PARAM);
+ VERIFY_PARAM_NOT_NULL(p_public_key);
+
+ memcpy(public_raw, p_public_key->pk, BLE_GAP_LESC_P256_PK_LEN);
+
+ err_code = nrf_crypto_ecc_byte_order_invert(&g_nrf_crypto_ecc_secp256r1_curve_info,
+ public_raw,
+ public_raw,
+ NRF_CRYPTO_ECC_SECP256R1_RAW_PUBLIC_KEY_SIZE);
+ VERIFY_SUCCESS(err_code);
+
+ err_code = nrf_crypto_ecc_public_key_from_raw(&g_nrf_crypto_ecc_secp256r1_curve_info,
+ &m_peer_public_key_central.public_key,
+ public_raw,
+ public_raw_len);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ m_peer_public_key_central.is_valid = true;
+ }
+ else
+ {
+ m_peer_public_key_central.is_valid = false;
+ }
+
+ m_peer_public_key_central.conn_handle = conn_handle;
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief BLE event handler for LESC DHKEY requests
+ */
+static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ ret_code_t err_code = NRF_SUCCESS;
+ uint16_t conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+ uint16_t role = ble_conn_state_role(conn_handle);
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_LESC_DHKEY_REQUEST:
+ {
+ NRF_LOG_DEBUG("Handling BLE_GAP_EVT_LESC_DHKEY_REQUEST");
+
+ ble_gap_lesc_p256_pk_t const * p_pk_peer =
+ p_ble_evt->evt.gap_evt.params.lesc_dhkey_request.p_pk_peer;
+
+ if (role == BLE_GAP_ROLE_CENTRAL)
+ {
+ err_code = ble_lesc_peer_central_public_key_set(conn_handle,
+ p_pk_peer);
+ }
+ else if (role == BLE_GAP_ROLE_PERIPH)
+ {
+ err_code = ble_lesc_peer_peripheral_public_key_set(conn_handle,
+ p_pk_peer);
+ }
+
+ if (err_code != NRF_SUCCESS)
+ {
+ // Set the state to invalid
+ m_ble_lesc_invalid_state = true;
+ }
+
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+
+ret_code_t ble_lesc_init(void)
+{
+ ret_code_t err_code;
+
+#if NRF_CRYPTO_ALLOCATOR == NRF_CRYPTO_ALLOCATOR_NRF_MALLOC
+
+ // Initialize mem_manager if used by nrf_crypto
+ err_code = nrf_mem_init();
+ VERIFY_SUCCESS(err_code);
+
+#endif
+
+ // Ensure that nrf_crypto has been initialized
+ err_code = nrf_crypto_init();
+ VERIFY_SUCCESS(err_code);
+
+#if defined(NRF_CRYPTO_RNG_AUTO_INIT_ENABLED) && (NRF_CRYPTO_RNG_AUTO_INIT_ENABLED == 1)
+
+ // Do nothing. RNG is initialized with nrf_crypto_init call.
+
+#elif defined((NRF_CRYPTO_RNG_AUTO_INIT_ENABLED) && (NRF_CRYPTO_RNG_AUTO_INIT_ENABLED == 0)
+
+ // Initialize the RNG
+ err_code = nrf_crypto_rng_init(NULL, NULL);
+ VERIFY_SUCCESS(err_code);
+
+#else
+
+ #error Invalid sdk_config.h (does not contain NRF_CRYPTO_RNG_AUTO_INIT_ENABLED)
+
+#endif // defined(NRF_CRYPTO_RNG_AUTO_INIT_ENABLED) && (NRF_CRYPTO_RNG_AUTO_INIT_ENABLED == 1)
+
+ return err_code;
+}
+
+
+ret_code_t ble_lesc_ecc_keypair_generate_and_set(void)
+{
+ ret_code_t err_code;
+
+ size_t public_len = BLE_GAP_LESC_P256_PK_LEN;
+
+ // Update flag to indicate that there is no valid private key
+ m_keypair_generated = false;
+
+ err_code = nrf_crypto_ecc_key_pair_generate(&m_ecc_keygen_context,
+ &g_nrf_crypto_ecc_secp256r1_curve_info,
+ &m_local_private_key,
+ &m_local_public_key.public_key);
+ VERIFY_SUCCESS(err_code);
+
+ // Converting public key to raw format.
+ err_code = nrf_crypto_ecc_public_key_to_raw(&m_local_public_key.public_key,
+ (uint8_t *)m_lesc_public_key.pk,
+ &public_len);
+ VERIFY_SUCCESS(err_code);
+
+ // Convert the raw public key to little-endian (required for BLE)
+ err_code = nrf_crypto_ecc_byte_order_invert(&g_nrf_crypto_ecc_secp256r1_curve_info,
+ m_lesc_public_key.pk,
+ m_lesc_public_key.pk,
+ NRF_CRYPTO_ECC_SECP256R1_RAW_PUBLIC_KEY_SIZE);
+ VERIFY_SUCCESS(err_code);
+
+ // Set the local public key used for all LESC pairing procedures.
+ err_code = pm_lesc_public_key_set(&m_lesc_public_key);
+
+ if(err_code == NRF_SUCCESS)
+ {
+ // Set the flag to indicate that there is a valid ECDH key pair generated
+ m_keypair_generated = true;
+ }
+
+ return err_code;
+}
+
+
+ret_code_t ble_lesc_ecc_local_public_key_get(ble_gap_lesc_p256_pk_t const ** pp_lesc_public_key)
+{
+ VERIFY_PARAM_NOT_NULL(pp_lesc_public_key);
+ VERIFY_TRUE(m_keypair_generated, NRF_ERROR_INVALID_STATE);
+
+ (*pp_lesc_public_key) = &m_lesc_public_key;
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t ble_lesc_service_request_handler(void)
+{
+ ret_code_t err_code = NRF_SUCCESS;
+
+ // If the LESC module is in an invalid state restart is required
+ if (m_ble_lesc_invalid_state)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ if (m_peer_public_key_central.conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ // The central link has received a DHKEY_REQUEST.
+ err_code = ble_lesc_dhkey_calculate_and_set(&m_peer_public_key_central);
+
+ m_peer_public_key_central.conn_handle = BLE_CONN_HANDLE_INVALID;
+ }
+ else if (m_peer_public_key_peripheral.conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ // The peripheral link has received a DHKEY_REQUEST.
+ err_code = ble_lesc_dhkey_calculate_and_set(&m_peer_public_key_peripheral);
+
+ m_peer_public_key_peripheral.conn_handle = BLE_CONN_HANDLE_INVALID;
+ }
+ else
+ {
+ // Do nothing
+ }
+
+ return err_code;
+}
+
+#endif // NRF_MODULE_ENABLED(BLE_LESC)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_lesc/ble_lesc.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_lesc/ble_lesc.h
new file mode 100644
index 0000000..b3ef35d
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_lesc/ble_lesc.h
@@ -0,0 +1,128 @@
+/**
+ * Copyright (c) 2018 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_lesc BLE LESC module
+ * @{
+ * @ingroup ble_sdk_lib
+ *
+ * @brief Module for handling LESC DHKey requests.
+ */
+#ifndef BLE_LESC_H__
+#define BLE_LESC_H__
+
+#include "sdk_common.h"
+#include "ble_gap.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Function to initialize the ble_lesc module.
+ *
+ * @details This function initializes the nrf_crypto for key
+ * generation and ECDH calculations.
+ *
+ * @retval NRF_SUCCESS Initalization was successful.
+ * @return Any error code reported by @ref nrf_crypto_init.
+ * @return Any error code reported by @ref nrf_crypto_rng_init.
+ */
+ret_code_t ble_lesc_init(void);
+
+
+/**@brief Function to generate a ECC key pair to use in LESC
+ *
+ * @details This function initializes the crypto system by calling nrf_crypto_init
+ * and nrf_crypto_rng_init before calling the required functions to generate
+ * the ECC key pair. If the key generation was successful this function sets
+ * the LESC local public key in peer manager by calling
+ * @ref pm_lesc_public_key_set.
+ *
+ * @note Run @ref ble_lesc_init before calling this API.
+ *
+ * @retval NRF_SUCCESS Generating ECC key pair was successful.
+ * @return Any error code form @ref nrf_crypto_ecc_key_pair_generate.
+ * @return Any error code from @ref nrf_crypto_ecc_public_key_to_raw.
+ * @return Any error code from @ref nrf_crypto_ecc_byte_order_invert.
+ * @return Any error code reported by @ref pm_lesc_public_key_set.
+ */
+ret_code_t ble_lesc_ecc_keypair_generate_and_set(void);
+
+
+/**@brief Function to get the current LESC ECC local public key
+ *
+ * @details This function gets the current ECC local public key used LESC pairing procedure
+ * the format of this key is in a type usable by peer manager, NFC (OOB) and SoftDevice.
+ *
+ * @note Run @ref ble_lesc_ecc_keypair_generate_and_set before calling this function.
+ *
+ * @retval NRF_SUCCESS Getting the local public key was successful.
+ * @retval NRF_ERROR_NULL pp_lesc_public_key was NULL.
+ * @retval NRF_ERROR_INVALID_STATE No ECC keypair was generated prior to this call
+ */
+ret_code_t ble_lesc_ecc_local_public_key_get(ble_gap_lesc_p256_pk_t const ** pp_lesc_public_key);
+
+
+/**@brief Function to service LESC ECDH calculations
+ *
+ * @details This function will calculate a LESC ECDH key (also known as shared secret) as long as
+ * @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST event has been received from SoftDevice.
+ *
+ * @note This function should be run in a low interrupt priority like an idle-loop in the main
+ * application context.
+ *
+ * @warning Any error code reported by this function that is not @ref NRF_SUCCESS is critical and should be
+ * handled by aborting all ongoing BLE operations and resetting the device.
+ * Failure to do is a security risk.
+ *
+ * @retval NRF_SUCCESS Service operation was successful.
+ * @return Any other error code than NRF_SUCCESS which indicates that the device is in a critical state
+ * and must be restarted.
+ */
+ret_code_t ble_lesc_service_request_handler(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_LESC_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_link_ctx_manager/ble_link_ctx_manager.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_link_ctx_manager/ble_link_ctx_manager.c
new file mode 100644
index 0000000..ea60e6d
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_link_ctx_manager/ble_link_ctx_manager.c
@@ -0,0 +1,79 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "ble_link_ctx_manager.h"
+#include "sdk_common.h"
+
+
+ret_code_t blcm_link_ctx_get(blcm_link_ctx_storage_t const * const p_link_ctx_storage,
+ uint16_t const conn_handle,
+ void ** const pp_ctx_data)
+{
+ uint8_t conn_id;
+
+ if (pp_ctx_data == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+ else
+ {
+ *pp_ctx_data = NULL;
+ }
+
+ VERIFY_PARAM_NOT_NULL(p_link_ctx_storage);
+ VERIFY_PARAM_NOT_NULL(p_link_ctx_storage->p_ctx_data_pool);
+ VERIFY_TRUE((p_link_ctx_storage->link_ctx_size % BYTES_PER_WORD) == 0, NRF_ERROR_INVALID_PARAM);
+
+ conn_id = ble_conn_state_conn_idx(conn_handle);
+
+ if (conn_id == BLE_CONN_STATE_MAX_CONNECTIONS)
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ if (conn_id >= p_link_ctx_storage->max_links_cnt)
+ {
+ return NRF_ERROR_NO_MEM;
+ }
+
+ *pp_ctx_data = (void *) ((uint8_t *) p_link_ctx_storage->p_ctx_data_pool +
+ conn_id * p_link_ctx_storage->link_ctx_size);
+ return NRF_SUCCESS;
+}
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_link_ctx_manager/ble_link_ctx_manager.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_link_ctx_manager/ble_link_ctx_manager.h
new file mode 100644
index 0000000..2ac3693
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_link_ctx_manager/ble_link_ctx_manager.h
@@ -0,0 +1,127 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_link_ctx_manager BLE Link Context Manager
+ * @{
+ * @ingroup ble_sdk_lib
+ * @brief Storage for link-related data.
+ *
+ * @details BLE Link Context Manager can be used as a simple storage for link-related data.
+ * Each link context data is uniquely identified within the storage by its connection
+ * handle and can be retrieved from it by using this handle.
+ *
+ */
+#ifndef BLE_LINK_CTX_MANAGER_H__
+#define BLE_LINK_CTX_MANAGER_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include "ble_conn_state.h"
+#include "sdk_errors.h"
+
+
+/**@brief Macro for defining a blcm_link_ctx_storage instance.
+ *
+ * @param[in] _name Name of the instance.
+ * @param[in] _max_clients Maximum number of clients connected at a time.
+ * @param[in] _link_ctx_size Context size in bytes for a single link.
+ */
+#define BLE_LINK_CTX_MANAGER_DEF(_name, _max_clients, _link_ctx_size) \
+ STATIC_ASSERT((_max_clients) < BLE_CONN_STATE_MAX_CONNECTIONS); \
+ static uint32_t CONCAT_2(_name, _ctx_data_pool)[(_max_clients)*BYTES_TO_WORDS(_link_ctx_size)]; \
+ static blcm_link_ctx_storage_t _name = \
+ { \
+ .p_ctx_data_pool = CONCAT_2(_name, _ctx_data_pool), \
+ .max_links_cnt = (_max_clients), \
+ .link_ctx_size = sizeof(CONCAT_2(_name, _ctx_data_pool))/(_max_clients) \
+ }
+
+
+/**
+ * @brief Type of description that is used for registry of all current connections.
+ */
+typedef struct
+{
+ void * const p_ctx_data_pool; /**< Pointer to links context memory pool. */
+ uint8_t const max_links_cnt; /**< Maximum number of concurrent links. */
+ uint16_t const link_ctx_size; /**< Context size in bytes for a single link (word-aligned). */
+} blcm_link_ctx_storage_t;
+
+
+/**
+ * @brief Function for getting the link context from the link registry.
+ *
+ * This function finds the link context in the registry. The link to find is identified by the
+ * connection handle within the registry.
+ *
+ * The context is preserved for the lifetime of the connection. When a new connection occurs, the
+ * value of its context is undefined, and should be initialized.
+ *
+ * @param[in] p_link_ctx_storage Pointer to the link storage descriptor.
+ * @param[in] conn_handle Connection whose context to find.
+ * @param[out] pp_ctx_data Pointer to data with context for the connection.
+ *
+ * @retval NRF_ERROR_NULL If \p p_link_ctx_storage is NULL or contains a NULL pointer, or if
+ * \p pp_ctx_data is NULL.
+ * @retval NRF_ERROR_INVALID_PARAM If \p p_link_ctx_storage::link_ctx_size is not multiple of word
+ * size.
+ * @retval NRF_ERROR_NOT_FOUND If \p conn_handle does not refer to an active or recently
+ * disconnected link.
+ * @retval NRF_ERROR_NO_MEM If there is not enough memory to store context for the given
+ * connection handle. This can happen if the number of links is
+ * greater than \p p_link_ctx_storage::max_links_cnt.
+ * @retval NRF_SUCCESS If the operation was successful.
+ */
+ret_code_t blcm_link_ctx_get(blcm_link_ctx_storage_t const * const p_link_ctx_storage,
+ uint16_t const conn_handle,
+ void ** const pp_ctx_data);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_LINK_CTX_MANAGER_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_racp/ble_racp.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_racp/ble_racp.c
new file mode 100644
index 0000000..88b50b0
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_racp/ble_racp.c
@@ -0,0 +1,87 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_RACP)
+#include "ble_racp.h"
+#include <stdlib.h>
+
+
+void ble_racp_decode(uint8_t data_len, uint8_t const * p_data, ble_racp_value_t * p_racp_val)
+{
+ p_racp_val->opcode = 0xFF;
+ p_racp_val->operator = 0xFF;
+ p_racp_val->operand_len = 0;
+ p_racp_val->p_operand = NULL;
+
+ if (data_len > 0)
+ {
+ p_racp_val->opcode = p_data[0];
+ }
+ if (data_len > 1)
+ {
+ p_racp_val->operator = p_data[1]; //lint !e415
+ }
+ if (data_len > 2)
+ {
+ p_racp_val->operand_len = data_len - 2;
+ p_racp_val->p_operand = (uint8_t*)&p_data[2]; //lint !e416
+ }
+}
+
+
+uint8_t ble_racp_encode(const ble_racp_value_t * p_racp_val, uint8_t * p_data)
+{
+ uint8_t len = 0;
+ int i;
+
+ if (p_data != NULL)
+ {
+ p_data[len++] = p_racp_val->opcode;
+ p_data[len++] = p_racp_val->operator;
+
+ for (i = 0; i < p_racp_val->operand_len; i++)
+ {
+ p_data[len++] = p_racp_val->p_operand[i];
+ }
+ }
+
+ return len;
+}
+#endif // NRF_MODULE_ENABLED(BLE_RACP)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_racp/ble_racp.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_racp/ble_racp.h
new file mode 100644
index 0000000..1280ad1
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_racp/ble_racp.h
@@ -0,0 +1,136 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_racp Record Access Control Point
+ * @{
+ * @ingroup ble_sdk_lib
+ * @brief Record Access Control Point library.
+ */
+
+#ifndef BLE_RACP_H__
+#define BLE_RACP_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ble.h"
+#include "ble_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Record Access Control Point opcodes. */
+#define RACP_OPCODE_RESERVED 0 /**< Record Access Control Point opcode - Reserved for future use. */
+#define RACP_OPCODE_REPORT_RECS 1 /**< Record Access Control Point opcode - Report stored records. */
+#define RACP_OPCODE_DELETE_RECS 2 /**< Record Access Control Point opcode - Delete stored records. */
+#define RACP_OPCODE_ABORT_OPERATION 3 /**< Record Access Control Point opcode - Abort operation. */
+#define RACP_OPCODE_REPORT_NUM_RECS 4 /**< Record Access Control Point opcode - Report number of stored records. */
+#define RACP_OPCODE_NUM_RECS_RESPONSE 5 /**< Record Access Control Point opcode - Number of stored records response. */
+#define RACP_OPCODE_RESPONSE_CODE 6 /**< Record Access Control Point opcode - Response code. */
+
+/**@brief Record Access Control Point operators. */
+#define RACP_OPERATOR_NULL 0 /**< Record Access Control Point operator - Null. */
+#define RACP_OPERATOR_ALL 1 /**< Record Access Control Point operator - All records. */
+#define RACP_OPERATOR_LESS_OR_EQUAL 2 /**< Record Access Control Point operator - Less than or equal to. */
+#define RACP_OPERATOR_GREATER_OR_EQUAL 3 /**< Record Access Control Point operator - Greater than or equal to. */
+#define RACP_OPERATOR_RANGE 4 /**< Record Access Control Point operator - Within range of (inclusive). */
+#define RACP_OPERATOR_FIRST 5 /**< Record Access Control Point operator - First record (i.e. oldest record). */
+#define RACP_OPERATOR_LAST 6 /**< Record Access Control Point operator - Last record (i.e. most recent record). */
+#define RACP_OPERATOR_RFU_START 7 /**< Record Access Control Point operator - Start of Reserved for Future Use area. */
+
+/**@brief Record Access Control Point Operand Filter Type Value. */
+#define RACP_OPERAND_FILTER_TYPE_TIME_OFFSET 1 /**< Record Access Control Point Operand Filter Type Value - Time Offset. */
+#define RACP_OPERAND_FILTER_TYPE_FACING_TIME 2 /**< Record Access Control Point Operand Filter Type Value - User Facing Time. */
+
+/**@brief Record Access Control Point response codes. */
+#define RACP_RESPONSE_RESERVED 0 /**< Record Access Control Point response code - Reserved for future use. */
+#define RACP_RESPONSE_SUCCESS 1 /**< Record Access Control Point response code - Successful operation. */
+#define RACP_RESPONSE_OPCODE_UNSUPPORTED 2 /**< Record Access Control Point response code - Unsupported op code received. */
+#define RACP_RESPONSE_INVALID_OPERATOR 3 /**< Record Access Control Point response code - Operator not valid for service. */
+#define RACP_RESPONSE_OPERATOR_UNSUPPORTED 4 /**< Record Access Control Point response code - Unsupported operator. */
+#define RACP_RESPONSE_INVALID_OPERAND 5 /**< Record Access Control Point response code - Operand not valid for service. */
+#define RACP_RESPONSE_NO_RECORDS_FOUND 6 /**< Record Access Control Point response code - No matching records found. */
+#define RACP_RESPONSE_ABORT_FAILED 7 /**< Record Access Control Point response code - Abort could not be completed. */
+#define RACP_RESPONSE_PROCEDURE_NOT_DONE 8 /**< Record Access Control Point response code - Procedure could not be completed. */
+#define RACP_RESPONSE_OPERAND_UNSUPPORTED 9 /**< Record Access Control Point response code - Unsupported operand. */
+
+/**@brief Record Access Control Point value structure. */
+typedef struct
+{
+ uint8_t opcode; /**< Op Code. */
+ uint8_t operator; /**< Operator. */
+ uint8_t operand_len; /**< Length of the operand. */
+ uint8_t * p_operand; /**< Pointer to the operand. */
+} ble_racp_value_t;
+
+/**@brief Function for decoding a Record Access Control Point write.
+ *
+ * @details This call decodes a write to the Record Access Control Point.
+ *
+ * @param[in] data_len Length of data in received write.
+ * @param[in] p_data Pointer to received data.
+ * @param[out] p_racp_val Pointer to decoded Record Access Control Point write.
+ * @note This does not do a data copy. It assumes the data pointed to by
+ * p_data is persistant until no longer needed.
+ */
+void ble_racp_decode(uint8_t data_len, uint8_t const * p_data, ble_racp_value_t * p_racp_val);
+
+/**@brief Function for encoding a Record Access Control Point response.
+ *
+ * @details This call encodes a response from the Record Access Control Point response.
+ *
+ * @param[in] p_racp_val Pointer to Record Access Control Point to encode.
+ * @param[out] p_data Pointer to where encoded data is written.
+ * NOTE! It is calling routines respsonsibility to make sure.
+ *
+ * @return Length of encoded data.
+ */
+uint8_t ble_racp_encode(const ble_racp_value_t * p_racp_val, uint8_t * p_data);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_RACP_H__
+
+/** @} */
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_radio_notification/ble_radio_notification.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_radio_notification/ble_radio_notification.c
new file mode 100644
index 0000000..44b2bf9
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_radio_notification/ble_radio_notification.c
@@ -0,0 +1,87 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "ble_radio_notification.h"
+#include <stdlib.h>
+
+
+static bool m_radio_active = false; /**< Current radio state. */
+static ble_radio_notification_evt_handler_t m_evt_handler = NULL; /**< Application event handler for handling Radio Notification events. */
+
+
+void SWI1_IRQHandler(void)
+{
+ m_radio_active = !m_radio_active;
+ if (m_evt_handler != NULL)
+ {
+ m_evt_handler(m_radio_active);
+ }
+}
+
+
+uint32_t ble_radio_notification_init(uint32_t irq_priority,
+ uint8_t distance,
+ ble_radio_notification_evt_handler_t evt_handler)
+{
+ uint32_t err_code;
+
+ m_evt_handler = evt_handler;
+
+ // Initialize Radio Notification software interrupt
+ err_code = sd_nvic_ClearPendingIRQ(SWI1_IRQn);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ err_code = sd_nvic_SetPriority(SWI1_IRQn, irq_priority);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ err_code = sd_nvic_EnableIRQ(SWI1_IRQn);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Configure the event
+ return sd_radio_notification_cfg_set(NRF_RADIO_NOTIFICATION_TYPE_INT_ON_BOTH, distance);
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_radio_notification/ble_radio_notification.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_radio_notification/ble_radio_notification.h
new file mode 100644
index 0000000..0f89b2f
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_radio_notification/ble_radio_notification.h
@@ -0,0 +1,82 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_radio_notification Radio Notification Event Handler
+ * @{
+ * @ingroup ble_sdk_lib
+ * @brief Module for propagating Radio Notification events to the application.
+ */
+
+#ifndef BLE_RADIO_NOTIFICATION_H__
+#define BLE_RADIO_NOTIFICATION_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "nrf_soc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Application radio notification event handler type. */
+typedef void (*ble_radio_notification_evt_handler_t) (bool radio_active);
+
+/**@brief Function for initializing the Radio Notification module.
+ *
+ * @param[in] irq_priority Interrupt priority for the Radio Notification interrupt handler.
+ * @param[in] distance The time from an Active event until the radio is activated.
+ * @param[in] evt_handler Handler to be executed when a radio notification event has been
+ * received.
+ *
+ * @return NRF_SUCCESS on successful initialization, otherwise an error code.
+ */
+uint32_t ble_radio_notification_init(uint32_t irq_priority,
+ uint8_t distance,
+ ble_radio_notification_evt_handler_t evt_handler);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_RADIO_NOTIFICATION_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_app_attr_get.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_app_attr_get.c
new file mode 100644
index 0000000..38ed510
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_app_attr_get.c
@@ -0,0 +1,367 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Disclaimer: This client implementation of the Apple Notification Center Service can and will be changed at any time by Nordic Semiconductor ASA.
+ * Server implementations such as the ones found in iOS can be changed at any time by Apple and may cause this client implementation to stop working.
+ */
+
+#include "ancs_app_attr_get.h"
+#include "nrf_ble_ancs_c.h"
+#include "ancs_tx_buffer.h"
+#include "sdk_macros.h"
+#include "nrf_log.h"
+#include "string.h"
+
+#define GATTC_OPCODE_SIZE 1 /**< Size of the GATTC OPCODE. */
+#define GATTC_ATTR_HANDLE_SIZE 4 /**< Size of the Attribute handle Size. */
+
+
+#define ANCS_GATTC_WRITE_PAYLOAD_LEN_MAX (BLE_GATT_ATT_MTU_DEFAULT - GATTC_OPCODE_SIZE - GATTC_ATTR_HANDLE_SIZE) /**< Maximum Length of the data we can send in one write. */
+
+
+/**@brief Enum to keep track of the state based encoding while requesting App attributes. */
+typedef enum
+{
+ APP_ATTR_COMMAND_ID, /**< Currently encoding the Command ID. */
+ APP_ATTR_APP_ID, /**< Currently encoding the App ID. */
+ APP_ATTR_ATTR_ID, /**< Currently encoding the Attribute ID. */
+ APP_ATTR_DONE /**< Encoding done. */
+}encode_app_attr_t;
+
+
+/**@brief Function for determening if an attribute is desired to get.
+ *
+ * @param[in] p_ancs iOS notification structure. This structure must be supplied by
+ * the application. It identifies the particular client instance to use.
+ *
+ * @return True If it is requested
+ * @return False If it is not be requested.
+*/
+static bool app_attr_is_requested(ble_ancs_c_t * p_ancs, uint32_t attr_id)
+{
+ if (p_ancs->ancs_app_attr_list[attr_id].get == true)
+ {
+ return true;
+ }
+ return false;
+}
+
+/**@brief Function for counting the number of attributes that will be requested upon a Get App Attribute.
+ *
+ * @param[in] p_ancs iOS notification structure. This structure must be supplied by
+ * the application. It identifies the particular client instance to use.
+ *
+ * @return Number of attributes that will be requested upon a Get App Attribute.
+*/
+static uint32_t app_attr_nb_to_get(ble_ancs_c_t * p_ancs)
+{
+ uint32_t attr_nb_to_get = 0;
+ for (uint32_t i = 0; i < (sizeof(p_ancs->ancs_app_attr_list)/sizeof(ble_ancs_c_attr_list_t)); i++)
+ {
+ if (app_attr_is_requested(p_ancs,i))
+ {
+ attr_nb_to_get++;
+ }
+ }
+ return attr_nb_to_get;
+}
+
+
+/**@brief Function for encoding the Command ID as part of assembling a "Get App Attributes" command.
+ *
+ * @param[in] conn_handle Connection handle for where the prepared write will be executed.
+ * @param[in] handle_value The handle that will receive the execute command.
+ * @param[in] p_offset Pointer to the offset for the write.
+ * @param[in] p_index Pointer to the length encoded so far for the current write.
+ * @param[in,out] p_msg Pointer to the tx message that has been filled out and will be added to
+ * tx queue in this function.
+ */
+static void queued_write_tx_message(uint16_t conn_handle,
+ uint16_t handle_value,
+ uint16_t * p_offset,
+ uint32_t * p_index,
+ tx_message_t * p_msg)
+{
+ NRF_LOG_DEBUG("Starting new TX message.");
+
+ p_msg->conn_handle = conn_handle;
+ p_msg->type = WRITE_REQ;
+ p_msg->req.write_req.gattc_params.len = *p_index;
+ p_msg->req.write_req.gattc_params.handle = handle_value;
+ p_msg->req.write_req.gattc_params.p_value = p_msg->req.write_req.gattc_value;
+
+ p_msg->req.write_req.gattc_params.offset = *p_offset;
+
+ p_msg->req.write_req.gattc_params.write_op = BLE_GATT_OP_PREP_WRITE_REQ;
+
+ tx_buffer_insert(p_msg);
+}
+
+
+/**@brief Function for encoding the Command ID as part of assembling a "Get App Attributes" command.
+ *
+ * @param[in] p_ancs iOS notification structure. This structure must be supplied by
+ * the application. It identifies the particular client instance to use.
+ * @param[in] p_index Pointer to the length encoded so far for the current write.
+ * @param[in] p_offset Pointer to the accumulated offset for the next write.
+ * @param[in,out] p_msg Pointer to the tx message that will be filled out in this function.
+ */
+static encode_app_attr_t app_attr_encode_cmd_id(ble_ancs_c_t * p_ancs,
+ uint32_t * index,
+ tx_message_t * p_msg)
+{
+ NRF_LOG_DEBUG("Encoding Command ID");
+
+ // Encode Command ID.
+ p_msg->req.write_req.gattc_value[(*index)++] = BLE_ANCS_COMMAND_ID_GET_APP_ATTRIBUTES;
+ return APP_ATTR_APP_ID;
+}
+
+/**@brief Function for encoding the App Identifier as part of assembling a "Get App Attributes" command.
+ *
+ * @param[in] p_ancs iOS notification structure. This structure must be supplied by
+ * the application. It identifies the particular client instance to use.
+ * @param[in] p_app_id The App ID for the App which we will request App Attributes for.
+ * @param[in] app_id_len Length of the App ID.
+ * @param[in] p_index Pointer to the length encoded so far for the current write.
+ * @param[in] p_offset Pointer to the accumulated offset for the next write.
+ * @param[in] p_app_id_bytes_encoded_count Variable to keep count of the encoded APP ID bytes.
+ * As long as it is lower than the length of the App ID,
+ * parsing will continue.
+ */
+static encode_app_attr_t app_attr_encode_app_id(ble_ancs_c_t * p_ancs,
+ uint32_t * p_index,
+ uint16_t * p_offset,
+ tx_message_t * p_msg,
+ const uint8_t * p_app_id,
+ const uint32_t app_id_len,
+ uint32_t * p_app_id_bytes_encoded_count)
+{
+ NRF_LOG_DEBUG("Encoding APP ID");
+ if (*p_index >= ANCS_GATTC_WRITE_PAYLOAD_LEN_MAX)
+ {
+ queued_write_tx_message(p_ancs->conn_handle, p_ancs->service.control_point_char.handle_value, p_offset, p_index, p_msg);
+ *(p_offset) += *p_index;
+ *p_index = 0;
+ }
+
+ //Encode App Identifier.
+ if (*p_app_id_bytes_encoded_count == app_id_len)
+ {
+ p_msg->req.write_req.gattc_value[(*p_index)++] = '\0';
+ (*p_app_id_bytes_encoded_count)++;
+ }
+ NRF_LOG_DEBUG("%c", p_app_id[(*p_app_id_bytes_encoded_count)]);
+ if (*p_app_id_bytes_encoded_count < app_id_len)
+ {
+ p_msg->req.write_req.gattc_value[(*p_index)++] = p_app_id[(*p_app_id_bytes_encoded_count)++];
+ }
+ if (*p_app_id_bytes_encoded_count > app_id_len)
+ {
+ return APP_ATTR_ATTR_ID;
+ }
+ return APP_ATTR_APP_ID;
+}
+
+/**@brief Function for encoding the Attribute ID as part of assembling a "Get App Attributes" command.
+ *
+ * @param[in] p_ancs iOS notification structure. This structure must be supplied by
+ *
+ * @param[in] p_index Pointer to the length encoded so far for the current write.
+ * @param[in] p_offset Pointer to the accumulated offset for the next write.
+ * @param[in,out] p_msg Pointer to the tx message that will be filled out in this function.
+ * @param[in] p_attr_count Pointer to a variable that iterates the possible App Attributes.
+ */
+static encode_app_attr_t app_attr_encode_attr_id(ble_ancs_c_t * p_ancs,
+ uint32_t * p_index,
+ uint16_t * p_offset,
+ tx_message_t * p_msg,
+ uint32_t * p_attr_count,
+ uint32_t * attr_get_total_nb)
+{
+ NRF_LOG_DEBUG("Encoding Attribute ID");
+ if ((*p_index) >= ANCS_GATTC_WRITE_PAYLOAD_LEN_MAX)
+ {
+ queued_write_tx_message(p_ancs->conn_handle,
+ p_ancs->service.control_point_char.handle_value,
+ p_offset, p_index, p_msg);
+ *(p_offset) += *p_index;
+ *p_index = 0;
+ }
+ //Encode Attribute ID.
+ if (*p_attr_count < BLE_ANCS_NB_OF_APP_ATTR)
+ {
+ if (app_attr_is_requested(p_ancs, *p_attr_count))
+ {
+ p_msg->req.write_req.gattc_value[(*p_index)] = *p_attr_count;
+ p_ancs->number_of_requested_attr++;
+ (*p_index)++;
+ NRF_LOG_DEBUG("offset %i", *p_offset);
+ }
+ (*p_attr_count)++;
+ }
+ if (*p_attr_count == BLE_ANCS_NB_OF_APP_ATTR)
+ {
+ return APP_ATTR_DONE;
+ }
+ return APP_ATTR_APP_ID;
+}
+
+/**@brief Function for writing the execute write command to a handle for a given connection.
+ *
+ * @param[in] conn_handle Connection handle for where the prepared write will be executed.
+ * @param[in] handle_value The handle that will receive the execute command.
+ * @param[in] p_msg Pointer to the message that will be filled out in this function and then
+ * added to the tx queue.
+ */
+static void app_attr_execute_write(uint16_t conn_handle, uint16_t handle_value, tx_message_t * p_msg)
+{
+ NRF_LOG_DEBUG("Sending Execute Write.");
+ memset(p_msg,0,sizeof(tx_message_t));
+
+ p_msg->req.write_req.gattc_params.handle = handle_value;
+ p_msg->req.write_req.gattc_params.p_value = p_msg->req.write_req.gattc_value;
+ p_msg->req.write_req.gattc_params.offset = 0;
+ p_msg->req.write_req.gattc_params.write_op = BLE_GATT_OP_EXEC_WRITE_REQ;
+ p_msg->req.write_req.gattc_params.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE;
+
+ p_msg->req.write_req.gattc_params.len = 0;
+ p_msg->conn_handle = conn_handle;
+ p_msg->type = WRITE_REQ;
+
+ tx_buffer_insert(p_msg);
+}
+
+
+/**@brief Function for sending a get App Attributes request.
+ *
+ * @details Since the APP id may not fit in a single write, we use long write
+ * with a state machine to encode the Get App Attribute request.
+ *
+ * @param[in] p_ancs iOS notification structure. This structure must be supplied by
+ * the application. It identifies the particular client instance to use.
+ * @param[in] p_app_id The App ID for the App which we will request App Attributes for.
+ * @param[in] app_id_len Length of the App ID.
+ *
+*/
+static uint32_t app_attr_get(ble_ancs_c_t * p_ancs,
+ const uint8_t * p_app_id,
+ uint32_t app_id_len)
+{
+ uint32_t index = 0;
+ uint32_t attr_bytes_encoded_count = 0;
+ uint16_t offset = 0;
+ uint32_t app_id_bytes_encoded_count = 0;
+ encode_app_attr_t state = APP_ATTR_COMMAND_ID;
+ p_ancs->number_of_requested_attr = 0;
+
+ uint32_t attr_get_total_nb = app_attr_nb_to_get(p_ancs);
+ tx_message_t p_msg;
+
+ memset(&p_msg, 0, sizeof(tx_message_t));
+
+ while (state != APP_ATTR_DONE)
+ {
+ switch (state)
+ {
+ case APP_ATTR_COMMAND_ID:
+ state = app_attr_encode_cmd_id(p_ancs,
+ &index,
+ &p_msg);
+ break;
+ case APP_ATTR_APP_ID:
+ state = app_attr_encode_app_id(p_ancs,
+ &index,
+ &offset,
+ &p_msg,
+ p_app_id,
+ app_id_len,
+ &app_id_bytes_encoded_count);
+ break;
+ case APP_ATTR_ATTR_ID:
+ state = app_attr_encode_attr_id(p_ancs,
+ &index,
+ &offset,
+ &p_msg,
+ &attr_bytes_encoded_count,
+ &attr_get_total_nb);
+ break;
+ case APP_ATTR_DONE:
+ break;
+ default:
+ break;
+ }
+ }
+ queued_write_tx_message(p_ancs->conn_handle,
+ p_ancs->service.control_point_char.handle_value,
+ &offset,
+ &index,
+ &p_msg);
+
+ app_attr_execute_write(p_ancs->conn_handle,
+ p_ancs->service.control_point_char.handle_value,
+ &p_msg);
+
+ p_ancs->parse_info.expected_number_of_attrs = p_ancs->number_of_requested_attr;
+
+ tx_buffer_process();
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ancs_c_app_attr_request(ble_ancs_c_t * p_ancs,
+ const uint8_t * p_app_id,
+ uint32_t len)
+{
+ uint32_t err_code;
+
+ if (len == 0)
+ {
+ return NRF_ERROR_DATA_SIZE;
+ }
+ if (p_app_id[len] != '\0') // App id to be requestes must be NULL terminated
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ p_ancs->parse_info.parse_state = COMMAND_ID;
+ err_code = app_attr_get(p_ancs, p_app_id, len);
+ VERIFY_SUCCESS(err_code);
+ return NRF_SUCCESS;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_app_attr_get.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_app_attr_get.h
new file mode 100644
index 0000000..c942f73
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_app_attr_get.h
@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef ANCS_APP_ATTR_GET_H__
+#define ANCS_APP_ATTR_GET_H__
+
+#include "nrf_ble_ancs_c.h"
+/** @file
+ *
+ * @addtogroup ble_ancs_c
+ * @{
+ */
+
+/**@brief Function for requesting attributes for an app.
+ *
+ * @param[in] p_ancs iOS notification structure. This structure must be supplied by
+ * the application. It identifies the particular client instance to use.
+ * @param[in] app_id App identifier of the app for which to request app attributes.
+ * @param[in] len Length of the app identifier.
+ *
+ * @retval NRF_SUCCESS If all operations were successful. Otherwise, an error code is returned.
+ */
+uint32_t ancs_c_app_attr_request(ble_ancs_c_t * p_ancs,
+ const uint8_t * app_id,
+ uint32_t len);
+
+/** @} */
+
+#endif // ANCS_APP_ATTR_GET_H__
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_attr_parser.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_attr_parser.c
new file mode 100644
index 0000000..60f18e0
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_attr_parser.c
@@ -0,0 +1,392 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Disclaimer: This client implementation of the Apple Notification Center Service can and will be changed at any time by Nordic Semiconductor ASA.
+ * Server implementations such as the ones found in iOS can be changed at any time by Apple and may cause this client implementation to stop working.
+ */
+
+ #include "nrf_ble_ancs_c.h"
+ #include "ancs_attr_parser.h"
+ #include "nrf_log.h"
+
+
+static bool all_req_attrs_parsed(ble_ancs_c_t * p_ancs)
+{
+ if (p_ancs->parse_info.expected_number_of_attrs == 0)
+ {
+ return true;
+ }
+ return false;
+}
+
+static bool attr_is_requested(ble_ancs_c_t * p_ancs, ble_ancs_c_attr_t attr)
+{
+ if (p_ancs->parse_info.p_attr_list[attr.attr_id].get == true)
+ {
+ return true;
+ }
+ return false;
+}
+
+
+/**@brief Function for parsing command id and notification id.
+ * Used in the @ref parse_get_notif_attrs_response state machine.
+ *
+ * @details UID and command ID will be received only once at the beginning of the first
+ * GATTC notification of a new attribute request for a given iOS notification.
+ *
+ * @param[in] p_ancs Pointer to an ANCS instance to which the event belongs.
+ * @param[in] p_data_src Pointer to data that was received from the Notification Provider.
+ * @param[in] index Pointer to an index that helps us keep track of the current data to be parsed.
+ *
+ * @return The next parse state.
+ */
+static ble_ancs_c_parse_state_t command_id_parse(ble_ancs_c_t * p_ancs,
+ const uint8_t * p_data_src,
+ uint32_t * index)
+{
+ ble_ancs_c_parse_state_t parse_state;
+
+ p_ancs->parse_info.command_id = (ble_ancs_c_cmd_id_val_t) p_data_src[(*index)++];
+
+ switch (p_ancs->parse_info.command_id)
+ {
+ case BLE_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES:
+ p_ancs->evt.evt_type = BLE_ANCS_C_EVT_NOTIF_ATTRIBUTE;
+ p_ancs->parse_info.p_attr_list = p_ancs->ancs_notif_attr_list;
+ p_ancs->parse_info.nb_of_attr = BLE_ANCS_NB_OF_NOTIF_ATTR;
+ parse_state = NOTIF_UID;
+ break;
+
+ case BLE_ANCS_COMMAND_ID_GET_APP_ATTRIBUTES:
+ p_ancs->evt.evt_type = BLE_ANCS_C_EVT_APP_ATTRIBUTE;
+ p_ancs->parse_info.p_attr_list = p_ancs->ancs_app_attr_list;
+ p_ancs->parse_info.nb_of_attr = BLE_ANCS_NB_OF_APP_ATTR;
+ parse_state = APP_ID;
+ break;
+
+ default:
+ //no valid command_id, abort the rest of the parsing procedure.
+ NRF_LOG_DEBUG("Invalid Command ID");
+ parse_state = DONE;
+ break;
+ }
+ return parse_state;
+}
+
+
+static ble_ancs_c_parse_state_t notif_uid_parse(ble_ancs_c_t * p_ancs,
+ const uint8_t * p_data_src,
+ uint32_t * index)
+{
+ p_ancs->evt.notif_uid = uint32_decode(&p_data_src[*index]);
+ *index += sizeof(uint32_t);
+ return ATTR_ID;
+}
+
+static ble_ancs_c_parse_state_t app_id_parse(ble_ancs_c_t * p_ancs,
+ const uint8_t * p_data_src,
+ uint32_t * index)
+{
+ p_ancs->evt.app_id[p_ancs->parse_info.current_app_id_index] = p_data_src[(*index)++];
+
+ if (p_ancs->evt.app_id[p_ancs->parse_info.current_app_id_index] != '\0')
+ {
+ p_ancs->parse_info.current_app_id_index++;
+ return APP_ID;
+ }
+ else
+ {
+ return ATTR_ID;
+ }
+}
+
+/**@brief Function for parsing the id of an iOS attribute.
+ * Used in the @ref parse_get_notif_attrs_response state machine.
+ *
+ * @details We only request attributes that are registered with @ref ble_ancs_c_attr_add
+ * once they have been reveiced we stop parsing.
+ *
+ * @param[in] p_ancs Pointer to an ANCS instance to which the event belongs.
+ * @param[in] p_data_src Pointer to data that was received from the Notification Provider.
+ * @param[in] index Pointer to an index that helps us keep track of the current data to be parsed.
+ *
+ * @return The next parse state.
+ */
+static ble_ancs_c_parse_state_t attr_id_parse(ble_ancs_c_t * p_ancs,
+ const uint8_t * p_data_src,
+ uint32_t * index)
+{
+ p_ancs->evt.attr.attr_id = p_data_src[(*index)++];
+
+ if (p_ancs->evt.attr.attr_id >= p_ancs->parse_info.nb_of_attr)
+ {
+ NRF_LOG_DEBUG("Attribute ID Invalid.");
+ return DONE;
+ }
+ p_ancs->evt.attr.p_attr_data = p_ancs->parse_info.p_attr_list[p_ancs->evt.attr.attr_id].p_attr_data;
+
+ if (all_req_attrs_parsed(p_ancs))
+ {
+ NRF_LOG_DEBUG("All requested attributes received. ");
+ return DONE;
+ }
+ else
+ {
+ if (attr_is_requested(p_ancs, p_ancs->evt.attr))
+ {
+ p_ancs->parse_info.expected_number_of_attrs--;
+ }
+ NRF_LOG_DEBUG("Attribute ID %i ", p_ancs->evt.attr.attr_id);
+ return ATTR_LEN1;
+ }
+}
+
+
+/**@brief Function for parsing the length of an iOS attribute.
+ * Used in the @ref parse_get_notif_attrs_response state machine.
+ *
+ * @details The Length is 2 bytes. Since there is a chance we reveice the bytes in two different
+ * GATTC notifications, we parse only the first byte here and then set the state machine
+ * ready to parse the next byte.
+ *
+ * @param[in] p_ancs Pointer to an ANCS instance to which the event belongs.
+ * @param[in] p_data_src Pointer to data that was received from the Notification Provider.
+ * @param[in] index Pointer to an index that helps us keep track of the current data to be parsed.
+ *
+ * @return The next parse state.
+ */
+static ble_ancs_c_parse_state_t attr_len1_parse(ble_ancs_c_t * p_ancs, const uint8_t * p_data_src, uint32_t * index)
+{
+ p_ancs->evt.attr.attr_len = p_data_src[(*index)++];
+ return ATTR_LEN2;
+}
+
+/**@brief Function for parsing the length of an iOS attribute.
+ * Used in the @ref parse_get_notif_attrs_response state machine.
+ *
+ * @details Second byte of the length field. If the length is zero, it means that the attribute is not
+ * present and the state machine is set to parse the next attribute.
+ *
+ * @param[in] p_ancs Pointer to an ANCS instance to which the event belongs.
+ * @param[in] p_data_src Pointer to data that was received from the Notification Provider.
+ * @param[in] index Pointer to an index that helps us keep track of the current data to be parsed.
+ *
+ * @return The next parse state.
+ */
+static ble_ancs_c_parse_state_t attr_len2_parse(ble_ancs_c_t * p_ancs, const uint8_t * p_data_src, uint32_t * index)
+{
+ p_ancs->evt.attr.attr_len |= (p_data_src[(*index)++] << 8);
+ p_ancs->parse_info.current_attr_index = 0;
+
+ if (p_ancs->evt.attr.attr_len != 0)
+ {
+ //If the attribute has a length but there is no allocated space for this attribute
+ if ((p_ancs->parse_info.p_attr_list[p_ancs->evt.attr.attr_id].attr_len == 0) ||
+ (p_ancs->parse_info.p_attr_list[p_ancs->evt.attr.attr_id].p_attr_data == NULL))
+ {
+ return ATTR_SKIP;
+ }
+ else
+ {
+ return ATTR_DATA;
+ }
+ }
+ else
+ {
+
+ NRF_LOG_DEBUG("Attribute LEN %i ", p_ancs->evt.attr.attr_len);
+ if (attr_is_requested(p_ancs, p_ancs->evt.attr))
+ {
+ p_ancs->evt_handler(&p_ancs->evt);
+ }
+ if (all_req_attrs_parsed(p_ancs))
+ {
+ return DONE;
+ }
+ else
+ {
+ return ATTR_ID;
+ }
+ }
+}
+
+
+/**@brief Function for parsing the data of an iOS attribute.
+ * Used in the @ref parse_get_notif_attrs_response state machine.
+ *
+ * @details Read the data of the attribute into our local buffer.
+ *
+ * @param[in] p_ancs Pointer to an ANCS instance to which the event belongs.
+ * @param[in] p_data_src Pointer to data that was received from the Notification Provider.
+ * @param[in] index Pointer to an index that helps us keep track of the current data to be parsed.
+ *
+ * @return The next parse state.
+ */
+static ble_ancs_c_parse_state_t attr_data_parse(ble_ancs_c_t * p_ancs,
+ const uint8_t * p_data_src,
+ uint32_t * index)
+{
+ // We have not reached the end of the attribute, nor our max allocated internal size.
+ // Proceed with copying data over to our buffer.
+ if ( (p_ancs->parse_info.current_attr_index < p_ancs->parse_info.p_attr_list[p_ancs->evt.attr.attr_id].attr_len)
+ && (p_ancs->parse_info.current_attr_index < p_ancs->evt.attr.attr_len))
+ {
+ //NRF_LOG_DEBUG("Byte copied to buffer: %c", p_data_src[(*index)]); // Un-comment this line to see every byte of an attribute as it is parsed. Commented out by default since it can overflow the uart buffer.
+ p_ancs->evt.attr.p_attr_data[p_ancs->parse_info.current_attr_index++] = p_data_src[(*index)++];
+ }
+
+ // We have reached the end of the attribute, or our max allocated internal size.
+ // Stop copying data over to our buffer. NUL-terminate at the current index.
+ if ( (p_ancs->parse_info.current_attr_index == p_ancs->evt.attr.attr_len) ||
+ (p_ancs->parse_info.current_attr_index == p_ancs->parse_info.p_attr_list[p_ancs->evt.attr.attr_id].attr_len - 1))
+ {
+ if (attr_is_requested(p_ancs, p_ancs->evt.attr))
+ {
+ p_ancs->evt.attr.p_attr_data[p_ancs->parse_info.current_attr_index] = '\0';
+ }
+
+ // If our max buffer size is smaller than the remaining attribute data, we must
+ // increase index to skip the data until the start of the next attribute.
+ if (p_ancs->parse_info.current_attr_index < p_ancs->evt.attr.attr_len)
+ {
+ return ATTR_SKIP;
+ }
+ NRF_LOG_DEBUG("Attribute finished!");
+ if (attr_is_requested(p_ancs, p_ancs->evt.attr))
+ {
+ p_ancs->evt_handler(&p_ancs->evt);
+ }
+ if (all_req_attrs_parsed(p_ancs))
+ {
+ return DONE;
+ }
+ else
+ {
+ return ATTR_ID;
+ }
+ }
+ return ATTR_DATA;
+}
+
+
+static ble_ancs_c_parse_state_t attr_skip(ble_ancs_c_t * p_ancs, const uint8_t * p_data_src, uint32_t * index)
+{
+ // We have not reached the end of the attribute, nor our max allocated internal size.
+ // Proceed with copying data over to our buffer.
+ if (p_ancs->parse_info.current_attr_index < p_ancs->evt.attr.attr_len)
+ {
+ p_ancs->parse_info.current_attr_index++;
+ (*index)++;
+ }
+ // At the end of the attribute, determine if it should be passed to event handler and
+ // continue parsing the next attribute ID if we are not done with all the attributes.
+ if (p_ancs->parse_info.current_attr_index == p_ancs->evt.attr.attr_len)
+ {
+ if (attr_is_requested(p_ancs, p_ancs->evt.attr))
+ {
+ p_ancs->evt_handler(&p_ancs->evt);
+ }
+ if (all_req_attrs_parsed(p_ancs))
+ {
+ return DONE;
+ }
+ else
+ {
+ return ATTR_ID;
+ }
+ }
+ return ATTR_SKIP;
+}
+
+
+void ancs_parse_get_attrs_response(ble_ancs_c_t * p_ancs,
+ const uint8_t * p_data_src,
+ const uint16_t hvx_data_len)
+{
+ uint32_t index;
+
+ for (index = 0; index < hvx_data_len;)
+ {
+ switch (p_ancs->parse_info.parse_state)
+ {
+ case COMMAND_ID:
+ p_ancs->parse_info.parse_state = command_id_parse(p_ancs, p_data_src, &index);
+ break;
+
+ case NOTIF_UID:
+ p_ancs->parse_info.parse_state = notif_uid_parse(p_ancs, p_data_src, &index);
+ break;
+
+ case APP_ID:
+ p_ancs->parse_info.parse_state = app_id_parse(p_ancs, p_data_src, &index);
+ break;
+
+ case ATTR_ID:
+ p_ancs->parse_info.parse_state = attr_id_parse(p_ancs, p_data_src, &index);
+ break;
+
+ case ATTR_LEN1:
+ p_ancs->parse_info.parse_state = attr_len1_parse(p_ancs, p_data_src, &index);
+ break;
+
+ case ATTR_LEN2:
+ p_ancs->parse_info.parse_state = attr_len2_parse(p_ancs, p_data_src, &index);
+ break;
+
+ case ATTR_DATA:
+ p_ancs->parse_info.parse_state = attr_data_parse(p_ancs, p_data_src, &index);
+ break;
+
+ case ATTR_SKIP:
+ p_ancs->parse_info.parse_state = attr_skip(p_ancs, p_data_src, &index);
+ break;
+
+ case DONE:
+ NRF_LOG_DEBUG("Parse state: Done ");
+ index = hvx_data_len;
+ break;
+
+ default:
+ // Default case will never trigger intentionally. Go to the DONE state to minimize the consequences.
+ p_ancs->parse_info.parse_state = DONE;
+ break;
+ }
+ }
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_attr_parser.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_attr_parser.h
new file mode 100644
index 0000000..92cea55
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_attr_parser.h
@@ -0,0 +1,77 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef BLE_ANCS_ATTR_PARSER_H__
+#define BLE_ANCS_ATTR_PARSER_H__
+
+#include "nrf_ble_ancs_c.h"
+
+/** @file
+ *
+ * @addtogroup ble_ancs_c
+ * @{
+ */
+
+/**@brief Function for parsing notification or app attribute response data.
+ *
+ * @details The data that comes from the Notification Provider can be much longer than what
+ * would fit in a single GATTC notification. Therefore, this function relies on a
+ * state-oriented switch case.
+ * UID and command ID will be received only once at the beginning of the first
+ * GATTC notification of a new attribute request for a given iOS notification.
+ * After this, we can loop several ATTR_ID > LENGTH > DATA > ATTR_ID > LENGTH > DATA until
+ * we have received all attributes we wanted as a Notification Consumer.
+ * The Notification Provider can also simply stop sending attributes.
+ *
+ * 1 byte | 4 bytes |1 byte |2 bytes |... X bytes ... |1 bytes| 2 bytes| ... X bytes ...
+ * --------|-------------|-------|--------|----------------|-------|--------|----------------
+ * CMD_ID | NOTIF_UID |ATTR_ID| LENGTH | DATA |ATTR_ID| LENGTH | DATA
+ *
+ * @param[in] p_ancs Pointer to an ANCS instance to which the event belongs.
+ * @param[in] p_data_src Pointer to data that was received from the Notification Provider.
+ * @param[in] hvx_data_len Length of the data that was received from the Notification Provider.
+ */
+void ancs_parse_get_attrs_response(ble_ancs_c_t * p_ancs,
+ const uint8_t * p_data_src,
+ const uint16_t hvx_data_len);
+
+/** @} */
+
+#endif // BLE_ANCS_ATTR_PARSER_H__
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_tx_buffer.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_tx_buffer.c
new file mode 100644
index 0000000..91e6886
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_tx_buffer.c
@@ -0,0 +1,113 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Disclaimer: This client implementation of the Apple Notification Center Service can and will be changed at any time by Nordic Semiconductor ASA.
+ * Server implementations such as the ones found in iOS can be changed at any time by Apple and may cause this client implementation to stop working.
+ */
+
+ #include "nrf_ble_ancs_c.h"
+ #include "ancs_tx_buffer.h"
+ #include "sdk_macros.h"
+ #include "nrf_log.h"
+ #include "string.h"
+
+
+static tx_message_t m_tx_buffer[TX_BUFFER_SIZE]; /**< Transmit buffer for messages to be transmitted to the Notification Provider. */
+static uint32_t m_tx_insert_index = 0; /**< Current index in the transmit buffer where the next message should be inserted. */
+static uint32_t m_tx_index = 0; /**< Current index in the transmit buffer from where the next message to be transmitted resides. */
+
+
+void tx_buffer_init(void)
+{
+ memset(m_tx_buffer, 0, sizeof(m_tx_buffer));
+}
+
+
+void tx_buffer_insert(tx_message_t * p_msg)
+{
+
+ memset(&(m_tx_buffer[m_tx_insert_index]), 0, sizeof(m_tx_buffer)/sizeof(tx_message_t));
+
+ m_tx_buffer[m_tx_insert_index].conn_handle = p_msg->conn_handle;
+ m_tx_buffer[m_tx_insert_index].type = p_msg->type;
+
+ m_tx_buffer[m_tx_insert_index].req.write_req.gattc_params.handle = p_msg->req.write_req.gattc_params.handle;
+ m_tx_buffer[m_tx_insert_index].req.write_req.gattc_params.len = p_msg->req.write_req.gattc_params.len;
+ m_tx_buffer[m_tx_insert_index].req.write_req.gattc_params.write_op = p_msg->req.write_req.gattc_params.write_op;
+ m_tx_buffer[m_tx_insert_index].req.write_req.gattc_params.flags = p_msg->req.write_req.gattc_params.flags;
+ m_tx_buffer[m_tx_insert_index].req.write_req.gattc_params.p_value = m_tx_buffer[m_tx_insert_index].req.write_req.gattc_value;
+ m_tx_buffer[m_tx_insert_index].req.write_req.gattc_params.offset = p_msg->req.write_req.gattc_params.offset;
+
+ if (p_msg->type == WRITE_REQ)
+ {
+ memcpy(m_tx_buffer[m_tx_insert_index].req.write_req.gattc_value,
+ p_msg->req.write_req.gattc_value,
+ WRITE_MESSAGE_LENGTH);
+ }
+
+ m_tx_insert_index++;
+ m_tx_insert_index &= TX_BUFFER_MASK;
+}
+
+
+
+void tx_buffer_process(void)
+{
+ if (m_tx_index != m_tx_insert_index)
+ {
+ uint32_t err_code;
+
+ if (m_tx_buffer[m_tx_index].type == READ_REQ)
+ {
+ err_code = sd_ble_gattc_read(m_tx_buffer[m_tx_index].conn_handle,
+ m_tx_buffer[m_tx_index].req.read_handle,
+ 0);
+ }
+ else
+ {
+ err_code = sd_ble_gattc_write(m_tx_buffer[m_tx_index].conn_handle,
+ &m_tx_buffer[m_tx_index].req.write_req.gattc_params);
+ }
+ if (err_code == NRF_SUCCESS)
+ {
+ ++m_tx_index;
+ m_tx_index &= TX_BUFFER_MASK;
+ }
+ }
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_tx_buffer.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_tx_buffer.h
new file mode 100644
index 0000000..6953438
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/ancs_tx_buffer.h
@@ -0,0 +1,103 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef ANCS_TX_BUFFER_H__
+#define ANCS_TX_BUFFER_H__
+
+#include "nrf_ble_ancs_c.h"
+
+/** @file
+ *
+ * @addtogroup ble_ancs_c
+ * @{
+ */
+
+#define TX_BUFFER_MASK 0x07 //!< TX buffer mask. Must be a mask of contiguous zeroes followed by a contiguous sequence of ones: 000...111.
+#define TX_BUFFER_SIZE (TX_BUFFER_MASK + 1) //!< Size of the send buffer, which is 1 bigger than the mask.
+#define WRITE_MESSAGE_LENGTH 20 //!< Length of the write message for the CCCD/control point.
+
+/**@brief ANCS request types.
+ */
+typedef enum
+{
+ READ_REQ = 1, /**< Type identifying that this TX message is a read request. */
+ WRITE_REQ /**< Type identifying that this TX message is a write request. */
+} tx_request_t;
+
+
+/**@brief Structure for writing a message to the central, thus the Control Point or CCCD.
+ */
+typedef struct
+{
+ uint8_t gattc_value[WRITE_MESSAGE_LENGTH]; //!< The message to write.
+ ble_gattc_write_params_t gattc_params; //!< GATTC parameters for this message.
+} write_params_t;
+
+
+/**@brief Data to be transmitted to the connected master.
+ */
+typedef struct
+{
+ uint16_t conn_handle; //!< Connection handle to be used when transmitting this message.
+ tx_request_t type; //!< Type of this message (read or write message).
+ union
+ {
+ uint16_t read_handle; //!< Read request message.
+ write_params_t write_req; //!< Write request message.
+ } req;
+} tx_message_t;
+
+/**@brief Function for clearing the TX buffer.
+ *
+ * @details Always call this function before using the TX buffer.
+*/
+void tx_buffer_init(void);
+
+/**@brief Function for moving the pointer of the ring buffer to the next element.
+*/
+void tx_buffer_insert(tx_message_t * p_msg);
+
+/**@brief Function for passing any pending request from the buffer to the stack.
+*/
+void tx_buffer_process(void);
+
+/** @} */
+
+#endif // ANCS_TX_BUFFER_H__
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/nrf_ble_ancs_c.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/nrf_ble_ancs_c.c
new file mode 100644
index 0000000..0ba177f
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/nrf_ble_ancs_c.c
@@ -0,0 +1,652 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Disclaimer: This client implementation of the Apple Notification Center Service can and will be changed at any time by Nordic Semiconductor ASA.
+ * Server implementations such as the ones found in iOS can be changed at any time by Apple and may cause this client implementation to stop working.
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_ANCS_C)
+#include "nrf_ble_ancs_c.h"
+#include "ancs_tx_buffer.h"
+#include "ancs_attr_parser.h"
+#include "ancs_app_attr_get.h"
+#include "ble_err.h"
+#include "ble_srv_common.h"
+#include "ble_db_discovery.h"
+#include "app_error.h"
+#define NRF_LOG_MODULE_NAME ble_ancs_c
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define BLE_ANCS_NOTIF_EVT_ID_INDEX 0 /**< Index of the Event ID field when parsing notifications. */
+#define BLE_ANCS_NOTIF_FLAGS_INDEX 1 /**< Index of the Flags field when parsing notifications. */
+#define BLE_ANCS_NOTIF_CATEGORY_ID_INDEX 2 /**< Index of the Category ID field when parsing notifications. */
+#define BLE_ANCS_NOTIF_CATEGORY_CNT_INDEX 3 /**< Index of the Category Count field when parsing notifications. */
+#define BLE_ANCS_NOTIF_NOTIF_UID 4 /**< Index of the Notification UID field when patsin notifications. */
+
+#define BLE_CCCD_NOTIFY_BIT_MASK 0x0001 /**< Enable notification bit. */
+
+#define TIME_STRING_LEN 15 /**< Unicode Technical Standard (UTS) #35 date format pattern "yyyyMMdd'T'HHmmSS" + "'\0'". */
+
+
+/**@brief 128-bit service UUID for the Apple Notification Center Service. */
+ble_uuid128_t const ble_ancs_base_uuid128 =
+{
+ {
+ // 7905F431-B5CE-4E99-A40F-4B1E122D00D0
+ 0xd0, 0x00, 0x2d, 0x12, 0x1e, 0x4b, 0x0f, 0xa4,
+ 0x99, 0x4e, 0xce, 0xb5, 0x31, 0xf4, 0x05, 0x79
+ }
+};
+
+
+/**@brief 128-bit control point UUID. */
+ble_uuid128_t const ble_ancs_cp_base_uuid128 =
+{
+ {
+ // 69d1d8f3-45e1-49a8-9821-9BBDFDAAD9D9
+ 0xd9, 0xd9, 0xaa, 0xfd, 0xbd, 0x9b, 0x21, 0x98,
+ 0xa8, 0x49, 0xe1, 0x45, 0xf3, 0xd8, 0xd1, 0x69
+ }
+};
+
+/**@brief 128-bit notification source UUID. */
+ble_uuid128_t const ble_ancs_ns_base_uuid128 =
+{
+ {
+ // 9FBF120D-6301-42D9-8C58-25E699A21DBD
+ 0xbd, 0x1d, 0xa2, 0x99, 0xe6, 0x25, 0x58, 0x8c,
+ 0xd9, 0x42, 0x01, 0x63, 0x0d, 0x12, 0xbf, 0x9f
+
+ }
+};
+
+/**@brief 128-bit data source UUID. */
+ble_uuid128_t const ble_ancs_ds_base_uuid128 =
+{
+ {
+ // 22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB
+ 0xfb, 0x7b, 0x7c, 0xce, 0x6a, 0xb3, 0x44, 0xbe,
+ 0xb5, 0x4b, 0xd6, 0x24, 0xe9, 0xc6, 0xea, 0x22
+ }
+};
+
+
+/**@brief Function for handling Disconnected event received from the SoftDevice.
+ *
+ * @details This function check if the disconnect event is happening on the link
+ * associated with the current instance of the module, if so it will set its
+ * conn_handle to invalid.
+ *
+ * @param[in] p_ancs Pointer to the ANCS client structure.
+ * @param[in] p_ble_evt Pointer to the BLE event received.
+ */
+static void on_disconnected(ble_ancs_c_t * p_ancs, ble_evt_t const * p_ble_evt)
+{
+ if (p_ancs->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
+ {
+ p_ancs->conn_handle = BLE_CONN_HANDLE_INVALID;
+ }
+}
+
+
+void ble_ancs_c_on_db_disc_evt(ble_ancs_c_t * p_ancs, ble_db_discovery_evt_t * p_evt)
+{
+ NRF_LOG_DEBUG("Database Discovery handler called with event 0x%x", p_evt->evt_type);
+
+ ble_ancs_c_evt_t evt;
+ ble_gatt_db_char_t * p_chars;
+
+ p_chars = p_evt->params.discovered_db.charateristics;
+
+ // Check if the ANCS Service was discovered.
+ if ( (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE)
+ && (p_evt->params.discovered_db.srv_uuid.uuid == ANCS_UUID_SERVICE)
+ && (p_evt->params.discovered_db.srv_uuid.type == p_ancs->service.service.uuid.type))
+ {
+ // Find the handles of the ANCS characteristic.
+ for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
+ {
+ switch (p_chars[i].characteristic.uuid.uuid)
+ {
+ case ANCS_UUID_CHAR_CONTROL_POINT:
+ NRF_LOG_INFO("Control Point Characteristic found.");
+ memcpy(&evt.service.control_point_char,
+ &p_chars[i].characteristic,
+ sizeof(ble_gattc_char_t));
+ break;
+
+ case ANCS_UUID_CHAR_DATA_SOURCE:
+ NRF_LOG_INFO("Data Source Characteristic found.");
+ memcpy(&evt.service.data_source_char,
+ &p_chars[i].characteristic,
+ sizeof(ble_gattc_char_t));
+ evt.service.data_source_cccd.handle = p_chars[i].cccd_handle;
+ break;
+
+ case ANCS_UUID_CHAR_NOTIFICATION_SOURCE:
+ NRF_LOG_INFO("Notification point Characteristic found.");
+ memcpy(&evt.service.notif_source_char,
+ &p_chars[i].characteristic,
+ sizeof(ble_gattc_char_t));
+ evt.service.notif_source_cccd.handle = p_chars[i].cccd_handle;
+ break;
+
+ default:
+ break;
+ }
+ }
+ evt.evt_type = BLE_ANCS_C_EVT_DISCOVERY_COMPLETE;
+ evt.conn_handle = p_evt->conn_handle;
+ p_ancs->evt_handler(&evt);
+ }
+ else
+ {
+ evt.evt_type = BLE_ANCS_C_EVT_DISCOVERY_FAILED;
+ p_ancs->evt_handler(&evt);
+ }
+}
+
+
+/**@brief Function for checking if data in an iOS notification is out of bounds.
+ *
+ * @param[in] notif An iOS notification.
+ *
+ * @retval NRF_SUCCESS If the notification is within bounds.
+ * @retval NRF_ERROR_INVALID_PARAM If the notification is out of bounds.
+ */
+static uint32_t ble_ancs_verify_notification_format(ble_ancs_c_evt_notif_t const * notif)
+{
+ if ( (notif->evt_id >= BLE_ANCS_NB_OF_EVT_ID)
+ || (notif->category_id >= BLE_ANCS_NB_OF_CATEGORY_ID))
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ return NRF_SUCCESS;
+}
+
+/**@brief Function for receiving and validating notifications received from the Notification Provider.
+ *
+ * @param[in] p_ancs Pointer to an ANCS instance to which the event belongs.
+ * @param[in] p_data_src Pointer to data that was received from the Notification Provider.
+ * @param[in] hvx_len Length of the data that was received by the Notification Provider.
+ */
+static void parse_notif(ble_ancs_c_t const * p_ancs,
+ uint8_t const * p_data_src,
+ uint16_t const hvx_data_len)
+{
+ ble_ancs_c_evt_t ancs_evt;
+ uint32_t err_code;
+ if (hvx_data_len != BLE_ANCS_NOTIFICATION_DATA_LENGTH)
+ {
+ ancs_evt.evt_type = BLE_ANCS_C_EVT_INVALID_NOTIF;
+ p_ancs->evt_handler(&ancs_evt);
+ }
+
+ /*lint --e{415} --e{416} -save suppress Warning 415: possible access out of bond */
+ ancs_evt.notif.evt_id =
+ (ble_ancs_c_evt_id_values_t) p_data_src[BLE_ANCS_NOTIF_EVT_ID_INDEX];
+
+ ancs_evt.notif.evt_flags.silent =
+ (p_data_src[BLE_ANCS_NOTIF_FLAGS_INDEX] >> BLE_ANCS_EVENT_FLAG_SILENT) & 0x01;
+
+ ancs_evt.notif.evt_flags.important =
+ (p_data_src[BLE_ANCS_NOTIF_FLAGS_INDEX] >> BLE_ANCS_EVENT_FLAG_IMPORTANT) & 0x01;
+
+ ancs_evt.notif.evt_flags.pre_existing =
+ (p_data_src[BLE_ANCS_NOTIF_FLAGS_INDEX] >> BLE_ANCS_EVENT_FLAG_PREEXISTING) & 0x01;
+
+ ancs_evt.notif.evt_flags.positive_action =
+ (p_data_src[BLE_ANCS_NOTIF_FLAGS_INDEX] >> BLE_ANCS_EVENT_FLAG_POSITIVE_ACTION) & 0x01;
+
+ ancs_evt.notif.evt_flags.negative_action =
+ (p_data_src[BLE_ANCS_NOTIF_FLAGS_INDEX] >> BLE_ANCS_EVENT_FLAG_NEGATIVE_ACTION) & 0x01;
+
+ ancs_evt.notif.category_id =
+ (ble_ancs_c_category_id_val_t) p_data_src[BLE_ANCS_NOTIF_CATEGORY_ID_INDEX];
+
+ ancs_evt.notif.category_count = p_data_src[BLE_ANCS_NOTIF_CATEGORY_CNT_INDEX];
+ ancs_evt.notif.notif_uid = uint32_decode(&p_data_src[BLE_ANCS_NOTIF_NOTIF_UID]);
+ /*lint -restore*/
+
+ err_code = ble_ancs_verify_notification_format(&ancs_evt.notif);
+ if (err_code == NRF_SUCCESS)
+ {
+ ancs_evt.evt_type = BLE_ANCS_C_EVT_NOTIF;
+ }
+ else
+ {
+ ancs_evt.evt_type = BLE_ANCS_C_EVT_INVALID_NOTIF;
+ }
+
+ p_ancs->evt_handler(&ancs_evt);
+}
+
+
+ret_code_t nrf_ble_ancs_c_app_attr_request(ble_ancs_c_t * p_ancs,
+ uint8_t const * p_app_id,
+ uint32_t len)
+{
+ return ancs_c_app_attr_request(p_ancs, p_app_id, len);
+}
+
+
+/**@brief Function for receiving and validating notifications received from the Notification Provider.
+ *
+ * @param[in] p_ancs Pointer to an ANCS instance to which the event belongs.
+ * @param[in] p_ble_evt Bluetooth stack event.
+ */
+static void on_evt_gattc_notif(ble_ancs_c_t * p_ancs, ble_evt_t const * p_ble_evt)
+{
+ ble_gattc_evt_hvx_t const * p_notif = &p_ble_evt->evt.gattc_evt.params.hvx;
+
+ if (p_ble_evt->evt.gattc_evt.conn_handle != p_ancs->conn_handle)
+ {
+ return;
+ }
+
+ if (p_notif->handle == p_ancs->service.notif_source_char.handle_value)
+ {
+ parse_notif(p_ancs, p_notif->data, p_notif->len);
+ }
+ else if (p_notif->handle == p_ancs->service.data_source_char.handle_value)
+ {
+ ancs_parse_get_attrs_response(p_ancs, p_notif->data, p_notif->len);
+ }
+ else
+ {
+ // No applicable action.
+ }
+}
+
+/**@brief Function for handling error response events.
+ *
+ * @param[in] p_ancs_c Pointer to the Battery Service Client Structure.
+ * @param[in] p_ble_evt Pointer to the SoftDevice event.
+ */
+static void on_ctrlpt_error_rsp(ble_ancs_c_t * p_ancs, ble_evt_t const * p_ble_evt)
+{
+ ble_ancs_c_evt_t ancs_evt;
+
+ ancs_evt.evt_type = BLE_ANCS_C_EVT_NP_ERROR;
+ ancs_evt.err_code_np = p_ble_evt->evt.gattc_evt.gatt_status;
+
+ p_ancs->evt_handler(&ancs_evt);
+}
+
+/**@brief Function for handling write response events.
+ *
+ * @param[in] p_ancs_c Pointer to the Battery Service Client Structure.
+ * @param[in] p_ble_evt Pointer to the SoftDevice event.
+ */
+static void on_write_rsp(ble_ancs_c_t * p_ancs, ble_evt_t const* p_ble_evt)
+{
+ // Check if the event if on the link for this instance
+ if (p_ancs->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
+ {
+ return;
+ }
+ if ((p_ble_evt->evt.gattc_evt.error_handle != BLE_GATT_HANDLE_INVALID)
+ && (p_ble_evt->evt.gattc_evt.error_handle == p_ancs->service.control_point_char.handle_value))
+ {
+ on_ctrlpt_error_rsp(p_ancs,p_ble_evt);
+ }
+ // Check if there is any message to be sent across to the peer and send it.
+ tx_buffer_process();
+}
+
+
+void ble_ancs_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ ble_ancs_c_t * p_ancs = (ble_ancs_c_t *)p_context;
+ uint16_t evt = p_ble_evt->header.evt_id;
+
+ switch (evt)
+ {
+ case BLE_GATTC_EVT_WRITE_RSP:
+ on_write_rsp(p_ancs, p_ble_evt);
+ break;
+
+ case BLE_GATTC_EVT_HVX:
+ on_evt_gattc_notif(p_ancs, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnected(p_ancs, p_ble_evt);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+ret_code_t ble_ancs_c_init(ble_ancs_c_t * p_ancs, ble_ancs_c_init_t const * p_ancs_init)
+{
+ uint32_t err_code;
+
+ //Verify that the parameters needed for to initialize this instance of ANCS are not NULL.
+ VERIFY_PARAM_NOT_NULL(p_ancs);
+ VERIFY_PARAM_NOT_NULL(p_ancs_init);
+ VERIFY_PARAM_NOT_NULL(p_ancs_init->evt_handler);
+
+ //Initialize state for the attribute parsing state machine.
+ p_ancs->parse_info.parse_state = COMMAND_ID;
+ p_ancs->parse_info.p_data_dest = NULL;
+ p_ancs->parse_info.current_attr_index = 0;
+ p_ancs->parse_info.current_app_id_index = 0;
+
+ p_ancs->evt_handler = p_ancs_init->evt_handler;
+ p_ancs->error_handler = p_ancs_init->error_handler;
+ p_ancs->conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ p_ancs->service.data_source_cccd.uuid.uuid = BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG;
+ p_ancs->service.notif_source_cccd.uuid.uuid = BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG;
+
+ // Make sure instance of service is clear. GATT handles inside the service and characteristics are set to @ref BLE_GATT_HANDLE_INVALID.
+ memset(&p_ancs->service, 0, sizeof(ble_ancs_c_service_t));
+ tx_buffer_init();
+
+ // Assign UUID types.
+ err_code = sd_ble_uuid_vs_add(&ble_ancs_base_uuid128, &p_ancs->service.service.uuid.type);
+ VERIFY_SUCCESS(err_code);
+
+ err_code = sd_ble_uuid_vs_add(&ble_ancs_cp_base_uuid128, &p_ancs->service.control_point_char.uuid.type);
+ VERIFY_SUCCESS(err_code);
+
+ err_code = sd_ble_uuid_vs_add(&ble_ancs_ns_base_uuid128, &p_ancs->service.notif_source_char.uuid.type);
+ VERIFY_SUCCESS(err_code);
+
+ err_code = sd_ble_uuid_vs_add(&ble_ancs_ds_base_uuid128, &p_ancs->service.data_source_char.uuid.type);
+ VERIFY_SUCCESS(err_code);
+
+ // Assign UUID to the service.
+ p_ancs->service.service.uuid.uuid = ANCS_UUID_SERVICE;
+ p_ancs->service.service.uuid.type = p_ancs->service.service.uuid.type;
+
+ return ble_db_discovery_evt_register(&p_ancs->service.service.uuid);
+}
+
+
+/**@brief Function for creating a TX message for writing a CCCD.
+ *
+ * @param[in] conn_handle Connection handle on which to perform the configuration.
+ * @param[in] handle_cccd Handle of the CCCD.
+ * @param[in] enable Enable or disable GATTC notifications.
+ *
+ * @retval NRF_SUCCESS If the message was created successfully.
+ * @retval NRF_ERROR_INVALID_PARAM If one of the input parameters was invalid.
+ */
+static uint32_t cccd_configure(const uint16_t conn_handle, const uint16_t handle_cccd, bool enable)
+{
+ tx_message_t p_msg;
+ memset(&p_msg, 0, sizeof(tx_message_t));
+ uint16_t cccd_val = enable ? BLE_CCCD_NOTIFY_BIT_MASK : 0;
+
+ p_msg.req.write_req.gattc_params.handle = handle_cccd;
+ p_msg.req.write_req.gattc_params.len = 2;
+ p_msg.req.write_req.gattc_params.p_value = p_msg.req.write_req.gattc_value;
+ p_msg.req.write_req.gattc_params.offset = 0;
+ p_msg.req.write_req.gattc_params.write_op = BLE_GATT_OP_WRITE_REQ;
+ p_msg.req.write_req.gattc_value[0] = LSB_16(cccd_val);
+ p_msg.req.write_req.gattc_value[1] = MSB_16(cccd_val);
+ p_msg.conn_handle = conn_handle;
+ p_msg.type = WRITE_REQ;
+
+ tx_buffer_insert(&p_msg);
+
+ tx_buffer_process();
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t ble_ancs_c_notif_source_notif_enable(ble_ancs_c_t const * p_ancs)
+{
+ NRF_LOG_INFO("Enable Notification Source notifications. writing to handle: %i ",
+ p_ancs->service.notif_source_cccd.handle);
+ return cccd_configure(p_ancs->conn_handle, p_ancs->service.notif_source_cccd.handle, true);
+}
+
+
+ret_code_t ble_ancs_c_notif_source_notif_disable(ble_ancs_c_t const * p_ancs)
+{
+ return cccd_configure(p_ancs->conn_handle, p_ancs->service.notif_source_cccd.handle, false);
+}
+
+
+ret_code_t ble_ancs_c_data_source_notif_enable(ble_ancs_c_t const * p_ancs)
+{
+ NRF_LOG_INFO("Enable Data Source notifications. Writing to handle: %i ",
+ p_ancs->service.data_source_cccd.handle);
+ return cccd_configure(p_ancs->conn_handle, p_ancs->service.data_source_cccd.handle, true);
+}
+
+
+ret_code_t ble_ancs_c_data_source_notif_disable(ble_ancs_c_t const * p_ancs)
+{
+ return cccd_configure(p_ancs->conn_handle, p_ancs->service.data_source_cccd.handle, false);
+}
+
+
+uint32_t ble_ancs_get_notif_attrs(ble_ancs_c_t * p_ancs,
+ uint32_t const p_uid)
+{
+ tx_message_t p_msg;
+ memset(&p_msg, 0, sizeof(tx_message_t));
+
+ uint32_t index = 0;
+ p_ancs->number_of_requested_attr = 0;
+
+
+ p_msg.req.write_req.gattc_params.handle = p_ancs->service.control_point_char.handle_value;
+ p_msg.req.write_req.gattc_params.p_value = p_msg.req.write_req.gattc_value;
+ p_msg.req.write_req.gattc_params.offset = 0;
+ p_msg.req.write_req.gattc_params.write_op = BLE_GATT_OP_WRITE_REQ;
+
+ //Encode Command ID.
+ p_msg.req.write_req.gattc_value[index++] = BLE_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES;
+
+ //Encode Notification UID.
+ index += uint32_encode(p_uid, &(p_msg.req.write_req.gattc_value[index]));
+
+ //Encode Attribute ID.
+ for (uint32_t attr = 0; attr < BLE_ANCS_NB_OF_NOTIF_ATTR; attr++)
+ {
+ if (p_ancs->ancs_notif_attr_list[attr].get == true)
+ {
+ p_msg.req.write_req.gattc_value[index++] = attr;
+ if ((attr == BLE_ANCS_NOTIF_ATTR_ID_TITLE) ||
+ (attr == BLE_ANCS_NOTIF_ATTR_ID_SUBTITLE) ||
+ (attr == BLE_ANCS_NOTIF_ATTR_ID_MESSAGE))
+ {
+ //Encode Length field, only applicable for Title, Subtitle and Message
+ index += uint16_encode(p_ancs->ancs_notif_attr_list[attr].attr_len,
+ &(p_msg.req.write_req.gattc_value[index]));
+ }
+ p_ancs->number_of_requested_attr++;
+ }
+ }
+ p_msg.req.write_req.gattc_params.len = index;
+ p_msg.conn_handle = p_ancs->conn_handle;
+ p_msg.type = WRITE_REQ;
+ p_ancs->parse_info.expected_number_of_attrs = p_ancs->number_of_requested_attr;
+
+ tx_buffer_insert(&p_msg);
+ tx_buffer_process();
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t nrf_ble_ancs_c_attr_add(ble_ancs_c_t * p_ancs,
+ ble_ancs_c_notif_attr_id_val_t const id,
+ uint8_t * p_data,
+ uint16_t const len)
+{
+ VERIFY_PARAM_NOT_NULL(p_data);
+
+ if ((len == 0) || (len > BLE_ANCS_ATTR_DATA_MAX))
+ {
+ return NRF_ERROR_INVALID_LENGTH;
+ }
+
+ p_ancs->ancs_notif_attr_list[id].get = true;
+ p_ancs->ancs_notif_attr_list[id].attr_len = len;
+ p_ancs->ancs_notif_attr_list[id].p_attr_data = p_data;
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t nrf_ble_ancs_c_app_attr_add(ble_ancs_c_t * p_ancs,
+ ble_ancs_c_app_attr_id_val_t const id,
+ uint8_t * p_data,
+ uint16_t const len)
+{
+ VERIFY_PARAM_NOT_NULL(p_ancs);
+ VERIFY_PARAM_NOT_NULL(p_data);
+
+ if ((len == 0) || (len > BLE_ANCS_ATTR_DATA_MAX))
+ {
+ return NRF_ERROR_INVALID_LENGTH;
+ }
+
+ p_ancs->ancs_app_attr_list[id].get = true;
+ p_ancs->ancs_app_attr_list[id].attr_len = len;
+ p_ancs->ancs_app_attr_list[id].p_attr_data = p_data;
+
+ return NRF_SUCCESS;
+}
+
+ret_code_t ble_ancs_c_app_attr_remove(ble_ancs_c_t * p_ancs,
+ ble_ancs_c_app_attr_id_val_t const id)
+{
+ p_ancs->ancs_app_attr_list[id].get = false;
+ p_ancs->ancs_app_attr_list[id].attr_len = 0;
+ p_ancs->ancs_app_attr_list[id].p_attr_data = NULL;
+ return NRF_SUCCESS;
+}
+
+ret_code_t ble_ancs_c_notif_attr_remove(ble_ancs_c_t * p_ancs,
+ ble_ancs_c_notif_attr_id_val_t const id)
+{
+ p_ancs->ancs_notif_attr_list[id].get = false;
+ p_ancs->ancs_notif_attr_list[id].attr_len = 0;
+ p_ancs->ancs_notif_attr_list[id].p_attr_data = NULL;
+ return NRF_SUCCESS;
+}
+
+ret_code_t nrf_ble_ancs_c_attr_req_clear_all(ble_ancs_c_t * p_ancs)
+{
+ memset(p_ancs->ancs_notif_attr_list, 0 , sizeof(p_ancs->ancs_notif_attr_list));
+ memset(p_ancs->ancs_app_attr_list, 0 , sizeof(p_ancs->ancs_app_attr_list));
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t nrf_ble_ancs_c_request_attrs(ble_ancs_c_t * p_ancs,
+ ble_ancs_c_evt_notif_t const * p_notif)
+{
+ uint32_t err_code;
+ err_code = ble_ancs_verify_notification_format(p_notif);
+ VERIFY_SUCCESS(err_code);
+
+ err_code = ble_ancs_get_notif_attrs(p_ancs, p_notif->notif_uid);
+ p_ancs->parse_info.parse_state = COMMAND_ID;
+ VERIFY_SUCCESS(err_code);
+
+ return NRF_SUCCESS;
+}
+
+static uint16_t encode_notif_action(uint8_t * p_encoded_data, uint32_t uid, ble_ancs_c_action_id_values_t action_id)
+{
+ uint8_t index = 0;
+
+ p_encoded_data[index++] = BLE_ANCS_COMMAND_ID_GET_PERFORM_NOTIF_ACTION;
+ index += uint32_encode(uid, &p_encoded_data[index]);
+ p_encoded_data[index++] = (uint8_t)action_id;
+
+ return index;
+}
+
+ret_code_t nrf_ancs_perform_notif_action(ble_ancs_c_t * p_ancs, uint32_t uid, ble_ancs_c_action_id_values_t action_id)
+{
+ VERIFY_PARAM_NOT_NULL(p_ancs);
+
+ tx_message_t msg;
+ memset(&msg, 0, sizeof(tx_message_t));
+
+ uint16_t len = encode_notif_action(msg.req.write_req.gattc_value, uid, action_id);
+
+ msg.req.write_req.gattc_params.handle = p_ancs->service.control_point_char.handle_value;
+ msg.req.write_req.gattc_params.p_value = msg.req.write_req.gattc_value;
+ msg.req.write_req.gattc_params.offset = 0;
+ msg.req.write_req.gattc_params.write_op = BLE_GATT_OP_WRITE_REQ;
+
+ msg.req.write_req.gattc_params.len = len;
+ msg.conn_handle = p_ancs->conn_handle;
+ msg.type = WRITE_REQ;
+
+ tx_buffer_insert(&msg);
+ tx_buffer_process();
+
+ return NRF_SUCCESS;
+}
+
+ret_code_t nrf_ble_ancs_c_handles_assign(ble_ancs_c_t * p_ancs,
+ uint16_t const conn_handle,
+ ble_ancs_c_service_t const * p_peer_handles)
+{
+ VERIFY_PARAM_NOT_NULL(p_ancs);
+
+ p_ancs->conn_handle = conn_handle;
+
+ if (p_peer_handles != NULL)
+ {
+ p_ancs->service.control_point_char.handle_value = p_peer_handles->control_point_char.handle_value;
+ p_ancs->service.data_source_cccd.handle = p_peer_handles->data_source_cccd.handle;
+ p_ancs->service.data_source_char.handle_value = p_peer_handles->data_source_char.handle_value;
+ p_ancs->service.notif_source_cccd.handle = p_peer_handles->notif_source_cccd.handle;
+ p_ancs->service.notif_source_char.handle_value = p_peer_handles->notif_source_char.handle_value;
+ }
+
+ return NRF_SUCCESS;
+}
+
+#endif// NRF_MODULE_ENABLED(BLE_ANCS_C)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/nrf_ble_ancs_c.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/nrf_ble_ancs_c.h
new file mode 100644
index 0000000..550583e
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ancs_c/nrf_ble_ancs_c.h
@@ -0,0 +1,604 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_ancs_c Apple Notification Service client
+ * @{
+ * @ingroup ble_sdk_srv
+ *
+ * @brief Apple Notification Center Service Client Module.
+ *
+ * @details Disclaimer: This client implementation of the Apple Notification Center Service can
+ * be changed at any time by Nordic Semiconductor ASA. Server implementations such as the
+ * ones found in iOS can be changed at any time by Apple and may cause this client
+ * implementation to stop working.
+ *
+ * This module implements the Apple Notification Center Service (ANCS) client.
+ * This client can be used as a Notification Consumer (NC) that receives data
+ * notifications from a Notification Provider (NP). The NP is typically an iOS
+ * device acting as a server. For terminology and up-to-date specs, see
+ * http://developer.apple.com.
+ *
+ * The term "notification" is used in two different meanings:
+ * - An <i>iOS notification</i> is the data received from the Notification Provider.
+ * - A <i>GATTC notification</i> is a way to transfer data with <i>Bluetooth</i> Smart.
+ * In this module, we receive iOS notifications using GATTC notifications.
+ * We use the full term (iOS notification or GATTC notification) where required to avoid confusion.
+ *
+ * Upon initializing the module, you must add the different iOS notification attributes you
+ * would like to receive for iOS notifications (see @ref nrf_ble_ancs_c_attr_add).
+ *
+ * Once a connection is established with a central device, the module does a service discovery to
+ * discover the ANCS server handles. If this succeeds (@ref BLE_ANCS_C_EVT_DISCOVERY_COMPLETE),
+ * the handles for the ANCS server are part of the @ref ble_ancs_c_evt_t structure and must be
+ * assigned to an ANCS_C instance using the @ref nrf_ble_ancs_c_handles_assign function. For more
+ * information about service discovery, see the @ref lib_ble_db_discovery documentation.
+ *
+ * The application can now subscribe to iOS notifications using
+ * @ref ble_ancs_c_notif_source_notif_enable. They arrive in the @ref BLE_ANCS_C_EVT_NOTIF event.
+ * @ref nrf_ble_ancs_c_request_attrs can be used to request attributes for the notifications. They
+ * arrive in the @ref BLE_ANCS_C_EVT_NOTIF_ATTRIBUTE event.
+ * @ref nrf_ble_ancs_c_app_attr_request can be used to request attributes of the app that issued
+ * the notifications. They arrive in the @ref BLE_ANCS_C_EVT_APP_ATTRIBUTE event.
+ * @ref nrf_ancs_perform_notif_action can be used to make the Notification Provider perform an
+ * action based on the provided notification.
+ *
+ * @msc
+ * hscale = "1.5";
+ * Application, ANCS_C;
+ * |||;
+ * Application=>ANCS_C [label = "ble_ancs_c_attr_add(attribute)"];
+ * Application=>ANCS_C [label = "ble_ancs_c_init(ancs_instance, event_handler)"];
+ * ...;
+ * Application<<=ANCS_C [label = "BLE_ANCS_C_EVT_DISCOVERY_COMPLETE"];
+ * Application=>ANCS_C [label = "ble_ancs_c_handles_assign(ancs_instance, conn_handle, service_handles)"];
+ * Application=>ANCS_C [label = "ble_ancs_c_notif_source_notif_enable(ancs_instance)"];
+ * Application=>ANCS_C [label = "ble_ancs_c_data_source_notif_enable(ancs_instance)"];
+ * |||;
+ * ...;
+ * |||;
+ * Application<<=ANCS_C [label = "BLE_ANCS_C_EVT_NOTIF"];
+ * |||;
+ * ...;
+ * |||;
+ * Application=>ANCS_C [label = "ble_ancs_c_request_attrs(attr_id, buffer)"];
+ * Application<<=ANCS_C [label = "BLE_ANCS_C_EVT_NOTIF_ATTRIBUTE"];
+ * |||;
+ * @endmsc
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_ancs_c_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_ANCS_C_BLE_OBSERVER_PRIO,
+ * ble_ancs_c_on_ble_evt, &instance);
+ * @endcode
+ */
+#ifndef BLE_ANCS_C_H__
+#define BLE_ANCS_C_H__
+
+#include "ble_types.h"
+#include "ble_srv_common.h"
+#include "sdk_errors.h"
+#include "ble_db_discovery.h"
+#include "nrf_sdh_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_ancs_c instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_ANCS_C_DEF(_name) \
+static ble_ancs_c_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_ANCS_C_BLE_OBSERVER_PRIO, \
+ ble_ancs_c_on_ble_evt, &_name)
+
+/** @brief Macro for defining multiple ble_ancs_c instances.
+ *
+ * @param _name Name of the array of instances.
+ * @param _cnt Number of instances to define.
+ * @hideinitializer
+ */
+#define BLE_ANCS_C_ARRAY_DEF(_name, _cnt) \
+sstatic ble_ancs_c_t _name[_cnt]; \
+NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
+ BLE_ANCS_C_BLE_OBSERVER_PRIO, \
+ ble_ancs_c_on_ble_evt, &_name, _cnt)
+
+#define BLE_ANCS_ATTR_DATA_MAX 32 //!< Maximum data length of an iOS notification attribute.
+#define BLE_ANCS_NB_OF_CATEGORY_ID 12 //!< Number of iOS notification categories: Other, Incoming Call, Missed Call, Voice Mail, Social, Schedule, Email, News, Health And Fitness, Business And Finance, Location, Entertainment.
+#define BLE_ANCS_NB_OF_NOTIF_ATTR 8 //!< Number of iOS notification attributes: AppIdentifier, Title, Subtitle, Message, MessageSize, Date, PositiveActionLabel, NegativeActionLabel.
+#define BLE_ANCS_NB_OF_APP_ATTR 1 //!< Number of iOS application attributes: DisplayName.
+#define BLE_ANCS_NB_OF_EVT_ID 3 //!< Number of iOS notification events: Added, Modified, Removed.
+
+/** @brief Length of the iOS notification data.
+ *
+ * @details 8 bytes:
+ * Event ID |Event flags |Category ID |Category count|Notification UID
+ * ---------|------------|------------|--------------|----------------
+ * 1 byte | 1 byte | 1 byte | 1 byte | 4 bytes
+ */
+#define BLE_ANCS_NOTIFICATION_DATA_LENGTH 8
+
+#define ANCS_UUID_SERVICE 0xF431 //!< 16-bit service UUID for the Apple Notification Center Service.
+#define ANCS_UUID_CHAR_CONTROL_POINT 0xD8F3 //!< 16-bit control point UUID.
+#define ANCS_UUID_CHAR_DATA_SOURCE 0xC6E9 //!< 16-bit data source UUID.
+#define ANCS_UUID_CHAR_NOTIFICATION_SOURCE 0x120D //!< 16-bit notification source UUID.
+
+#define BLE_ANCS_EVENT_FLAG_SILENT 0 //!< 0b.......1 Silent: First (LSB) bit is set. All flags can be active at the same time.
+#define BLE_ANCS_EVENT_FLAG_IMPORTANT 1 //!< 0b......1. Important: Second (LSB) bit is set. All flags can be active at the same time.
+#define BLE_ANCS_EVENT_FLAG_PREEXISTING 2 //!< 0b.....1.. Pre-existing: Third (LSB) bit is set. All flags can be active at the same time.
+#define BLE_ANCS_EVENT_FLAG_POSITIVE_ACTION 3 //!< 0b....1... Positive action: Fourth (LSB) bit is set. All flags can be active at the same time.
+#define BLE_ANCS_EVENT_FLAG_NEGATIVE_ACTION 4 //!< 0b...1.... Negative action: Fifth (LSB) bit is set. All flags can be active at the same time.
+
+/** @defgroup BLE_ANCS_NP_ERROR_CODES Notification Provider (iOS) Error Codes
+ * @{ */
+#define BLE_ANCS_NP_UNKNOWN_COMMAND 0x01A0 //!< The command ID is unknown to the NP.
+#define BLE_ANCS_NP_INVALID_COMMAND 0x01A1 //!< The command format is invalid.
+#define BLE_ANCS_NP_INVALID_PARAMETER 0x01A2 //!< One or more parameters does not exist in the NP.
+#define BLE_ANCS_NP_ACTION_FAILED 0x01A3 //!< The action failed to be performed by the NP.
+/** @} */
+
+
+/**@brief Event types that are passed from client to application on an event. */
+typedef enum
+{
+ BLE_ANCS_C_EVT_DISCOVERY_COMPLETE, /**< A successful connection has been established and the service was found on the connected peer. */
+ BLE_ANCS_C_EVT_DISCOVERY_FAILED, /**< It was not possible to discover the service or characteristics of the connected peer. */
+ BLE_ANCS_C_EVT_NOTIF, /**< An iOS notification was received on the notification source control point. */
+ BLE_ANCS_C_EVT_INVALID_NOTIF, /**< An iOS notification was received on the notification source control point, but the format is invalid. */
+ BLE_ANCS_C_EVT_NOTIF_ATTRIBUTE, /**< A received iOS notification attribute has been parsed. */
+ BLE_ANCS_C_EVT_APP_ATTRIBUTE, /**< An iOS app attribute has been parsed. */
+ BLE_ANCS_C_EVT_NP_ERROR, /**< An error has been sent on the ANCS Control Point from the iOS Notification Provider. */
+} ble_ancs_c_evt_type_t;
+
+/**@brief Category IDs for iOS notifications. */
+typedef enum
+{
+ BLE_ANCS_CATEGORY_ID_OTHER, /**< The iOS notification belongs to the "other" category. */
+ BLE_ANCS_CATEGORY_ID_INCOMING_CALL, /**< The iOS notification belongs to the "Incoming Call" category. */
+ BLE_ANCS_CATEGORY_ID_MISSED_CALL, /**< The iOS notification belongs to the "Missed Call" category. */
+ BLE_ANCS_CATEGORY_ID_VOICE_MAIL, /**< The iOS notification belongs to the "Voice Mail" category. */
+ BLE_ANCS_CATEGORY_ID_SOCIAL, /**< The iOS notification belongs to the "Social" category. */
+ BLE_ANCS_CATEGORY_ID_SCHEDULE, /**< The iOS notification belongs to the "Schedule" category. */
+ BLE_ANCS_CATEGORY_ID_EMAIL, /**< The iOS notification belongs to the "E-mail" category. */
+ BLE_ANCS_CATEGORY_ID_NEWS, /**< The iOS notification belongs to the "News" category. */
+ BLE_ANCS_CATEGORY_ID_HEALTH_AND_FITNESS, /**< The iOS notification belongs to the "Health and Fitness" category. */
+ BLE_ANCS_CATEGORY_ID_BUSINESS_AND_FINANCE, /**< The iOS notification belongs to the "Buisness and Finance" category. */
+ BLE_ANCS_CATEGORY_ID_LOCATION, /**< The iOS notification belongs to the "Location" category. */
+ BLE_ANCS_CATEGORY_ID_ENTERTAINMENT /**< The iOS notification belongs to the "Entertainment" category. */
+} ble_ancs_c_category_id_val_t;
+
+/**@brief Event IDs for iOS notifications. */
+typedef enum
+{
+ BLE_ANCS_EVENT_ID_NOTIFICATION_ADDED, /**< The iOS notification was added. */
+ BLE_ANCS_EVENT_ID_NOTIFICATION_MODIFIED, /**< The iOS notification was modified. */
+ BLE_ANCS_EVENT_ID_NOTIFICATION_REMOVED /**< The iOS notification was removed. */
+} ble_ancs_c_evt_id_values_t;
+
+/**@brief Control point command IDs that the Notification Consumer can send to the Notification Provider. */
+typedef enum
+{
+ BLE_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES, /**< Requests attributes to be sent from the NP to the NC for a given notification. */
+ BLE_ANCS_COMMAND_ID_GET_APP_ATTRIBUTES, /**< Requests attributes to be sent from the NP to the NC for a given iOS app. */
+ BLE_ANCS_COMMAND_ID_GET_PERFORM_NOTIF_ACTION, /**< Requests an action to be performed on a given notification, for example, dismiss an alarm. */
+} ble_ancs_c_cmd_id_val_t;
+
+/**@brief IDs for actions that can be performed for iOS notifications. */
+typedef enum
+{
+ ACTION_ID_POSITIVE = 0, /**< Positive action. */
+ ACTION_ID_NEGATIVE /**< Negative action. */
+} ble_ancs_c_action_id_values_t;
+
+/**@brief App attribute ID values.
+ * @details Currently, only one value is defined. However, the number of app
+ * attributes might increase. Therefore, they are stored in an enumeration.
+ */
+typedef enum
+{
+ BLE_ANCS_APP_ATTR_ID_DISPLAY_NAME = 0 /**< Command used to get the display name for an app identifier. */
+} ble_ancs_c_app_attr_id_val_t;
+
+/**@brief IDs for iOS notification attributes. */
+typedef enum
+{
+ BLE_ANCS_NOTIF_ATTR_ID_APP_IDENTIFIER = 0, /**< Identifies that the attribute data is of an "App Identifier" type. */
+ BLE_ANCS_NOTIF_ATTR_ID_TITLE, /**< Identifies that the attribute data is a "Title". */
+ BLE_ANCS_NOTIF_ATTR_ID_SUBTITLE, /**< Identifies that the attribute data is a "Subtitle". */
+ BLE_ANCS_NOTIF_ATTR_ID_MESSAGE, /**< Identifies that the attribute data is a "Message". */
+ BLE_ANCS_NOTIF_ATTR_ID_MESSAGE_SIZE, /**< Identifies that the attribute data is a "Message Size". */
+ BLE_ANCS_NOTIF_ATTR_ID_DATE, /**< Identifies that the attribute data is a "Date". */
+ BLE_ANCS_NOTIF_ATTR_ID_POSITIVE_ACTION_LABEL, /**< The notification has a "Positive action" that can be executed associated with it. */
+ BLE_ANCS_NOTIF_ATTR_ID_NEGATIVE_ACTION_LABEL, /**< The notification has a "Negative action" that can be executed associated with it. */
+} ble_ancs_c_notif_attr_id_val_t;
+
+/**@brief Flags for iOS notifications. */
+typedef struct
+{
+ uint8_t silent : 1; //!< If this flag is set, the notification has a low priority.
+ uint8_t important : 1; //!< If this flag is set, the notification has a high priority.
+ uint8_t pre_existing : 1; //!< If this flag is set, the notification is pre-existing.
+ uint8_t positive_action : 1; //!< If this flag is set, the notification has a positive action that can be taken.
+ uint8_t negative_action : 1; //!< If this flag is set, the notification has a negative action that can be taken.
+} ble_ancs_c_notif_flags_t;
+
+/**@brief Parsing states for received iOS notification and app attributes. */
+typedef enum
+{
+ COMMAND_ID, /**< Parsing the command ID. */
+ NOTIF_UID, /**< Parsing the notification UID. */
+ APP_ID, /**< Parsing app ID. */
+ ATTR_ID, /**< Parsing attribute ID. */
+ ATTR_LEN1, /**< Parsing the LSB of the attribute length. */
+ ATTR_LEN2, /**< Parsing the MSB of the attribute length. */
+ ATTR_DATA, /**< Parsing the attribute data. */
+ ATTR_SKIP, /**< Parsing is skipped for the rest (or entire) of an attribute. */
+ DONE, /**< Parsing for one attribute is done. */
+} ble_ancs_c_parse_state_t;
+
+/**@brief iOS notification structure. */
+typedef struct
+{
+ uint32_t notif_uid; //!< Notification UID.
+ ble_ancs_c_evt_id_values_t evt_id; //!< Whether the notification was added, removed, or modified.
+ ble_ancs_c_notif_flags_t evt_flags; //!< Bitmask to signal if a special condition applies to the notification, for example, "Silent" or "Important".
+ ble_ancs_c_category_id_val_t category_id; //!< Classification of the notification type, for example, email or location.
+ uint8_t category_count; //!< Current number of active notifications for this category ID.
+} ble_ancs_c_evt_notif_t;
+
+/**@brief iOS attribute structure. This type is used for both notification attributes and app attributes. */
+typedef struct
+{
+ uint16_t attr_len; //!< Length of the received attribute data.
+ uint32_t attr_id; //!< Classification of the attribute type, for example, title or date.
+ uint8_t * p_attr_data; //!< Pointer to where the memory is allocated for storing incoming attributes.
+} ble_ancs_c_attr_t;
+
+/**@brief iOS notification attribute structure for incoming attributes. */
+typedef struct
+{
+ uint32_t notif_uid; //!< UID of the notification that the attribute belongs to.
+ ble_ancs_c_attr_t attrs; //!< A received attribute.
+} ble_ancs_c_evt_attr_t;
+
+typedef struct
+{
+ uint16_t attr_len; //!< Length of the received attribute data.
+ uint32_t attr_id; //!< Classification of the attribute type, for example, title or date.
+ uint8_t * p_attr_data; //!< Pointer to where the memory is allocated for storing incoming attributes.
+} ble_ancs_c_evt_app_attr_t;
+
+/**@brief iOS notification attribute content wanted by our application. */
+typedef struct
+{
+ bool get; //!< Boolean to determine if this attribute will be requested from the Notification Provider.
+ uint32_t attr_id; //!< Attribute ID: AppIdentifier(0), Title(1), Subtitle(2), Message(3), MessageSize(4), Date(5), PositiveActionLabel(6), NegativeActionLabel(7).
+ uint16_t attr_len; //!< Length of the attribute. If more data is received from the Notification Provider, all data beyond this length is discarded.
+ uint8_t * p_attr_data; //!< Pointer to where the memory is allocated for storing incoming attributes.
+} ble_ancs_c_attr_list_t;
+
+/**@brief Structure used for holding the Apple Notification Center Service found during the
+ discovery process.
+ */
+typedef struct
+{
+ ble_gattc_service_t service; //!< The GATT Service holding the discovered Apple Notification Center Service. (0xF431).
+ ble_gattc_char_t control_point_char; //!< ANCS Control Point Characteristic. Allows interaction with the peer (0xD8F3).
+ ble_gattc_char_t notif_source_char; //!< ANCS Notification Source Characteristic. Keeps track of arrival, modification, and removal of notifications (0x120D).
+ ble_gattc_desc_t notif_source_cccd; //!< ANCS Notification Source Characteristic Descriptor. Enables or disables GATT notifications.
+ ble_gattc_char_t data_source_char; //!< ANCS Data Source Characteristic, where attribute data for the notifications is received from peer (0xC6E9).
+ ble_gattc_desc_t data_source_cccd; //!< ANCS Data Source Characteristic Descriptor. Enables or disables GATT notifications.
+} ble_ancs_c_service_t;
+
+/**@brief ANCS client module event structure.
+ *
+ * @details The structure contains the event that should be handled by the main application.
+ */
+typedef struct
+{
+ ble_ancs_c_evt_type_t evt_type; //!< Type of event.
+ uint16_t conn_handle; //!< Connection handle on which the ANCS service was discovered on the peer device. This field will be filled if the @p evt_type is @ref BLE_ANCS_C_EVT_DISCOVERY_COMPLETE.
+ ble_ancs_c_evt_notif_t notif; //!< iOS notification. This field will be filled if @p evt_type is @ref BLE_ANCS_C_EVT_NOTIF.
+ uint16_t err_code_np; //!< An error coming from the Notification Provider. This field will be filled with @ref BLE_ANCS_NP_ERROR_CODES if @p evt_type is @ref BLE_ANCS_C_EVT_NP_ERROR.
+ ble_ancs_c_attr_t attr; //!< iOS notification attribute or app attribute, depending on the event type.
+ uint32_t notif_uid; //!< Notification UID.
+ uint8_t app_id[BLE_ANCS_ATTR_DATA_MAX]; //!< App identifier.
+ ble_ancs_c_service_t service; //!< Information on the discovered Alert Notification Service. This field will be filled if the @p evt_type is @ref BLE_ANCS_C_EVT_DISCOVERY_COMPLETE.
+} ble_ancs_c_evt_t;
+
+/**@brief iOS notification event handler type. */
+typedef void (*ble_ancs_c_evt_handler_t) (ble_ancs_c_evt_t * p_evt);
+
+typedef struct
+{
+ ble_ancs_c_attr_list_t * p_attr_list; //!< The current list of attributes being parsed. This field will point to either @ref ble_ancs_c_t::ancs_notif_attr_list or @ref ble_ancs_c_t::ancs_app_attr_list.
+ uint32_t nb_of_attr; //!< Number of possible attributes. When parsing begins, it is set to either @ref BLE_ANCS_NB_OF_NOTIF_ATTR or @ref BLE_ANCS_NB_OF_APP_ATTR.
+ uint32_t expected_number_of_attrs; //!< The number of attributes expected upon receiving attributes. Keeps track of when to stop reading incoming attributes.
+ ble_ancs_c_parse_state_t parse_state; //!< ANCS notification attribute parsing state.
+ ble_ancs_c_cmd_id_val_t command_id; //!< Variable to keep track of what command type we are currently parsing ( @ref BLE_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES or @ref BLE_ANCS_COMMAND_ID_GET_APP_ATTRIBUTES.
+ uint8_t * p_data_dest; //!< Attribute that the parsed data will be copied into.
+ uint16_t current_attr_index; //!< Variable to keep track of how much (for a given attribute) we are done parsing.
+ uint32_t current_app_id_index; //!< Variable to keep track of how much (for a given app identifier) we are done parsing.
+} ble_ancs_parse_sm_t;
+
+/**@brief iOS notification structure, which contains various status information for the client. */
+typedef struct
+{
+ ble_ancs_c_evt_handler_t evt_handler; //!< Event handler to be called for handling events in the Apple Notification client application.
+ ble_srv_error_handler_t error_handler; //!< Function to be called in case of an error.
+ uint16_t conn_handle; //!< Handle of the current connection. Set with @ref nrf_ble_ancs_c_handles_assign when connected.
+ ble_ancs_c_service_t service; //!< Structure to store the different handles and UUIDs related to the service.
+ ble_ancs_c_attr_list_t ancs_notif_attr_list[BLE_ANCS_NB_OF_NOTIF_ATTR]; //!< For all attributes; contains whether they should be requested upon attribute request and the length and buffer of where to store attribute data.
+ ble_ancs_c_attr_list_t ancs_app_attr_list[BLE_ANCS_NB_OF_APP_ATTR]; //!< For all app attributes; contains whether they should be requested upon attribute request and the length and buffer of where to store attribute data.
+ uint32_t number_of_requested_attr; //!< The number of attributes that will be requested when an iOS notification attribute request is made.
+ ble_ancs_parse_sm_t parse_info; //!< Structure containing different information used to parse incoming attributes (from data_source characteristic) correctly.
+ ble_ancs_c_evt_t evt; //!< The event is filled with several iterations of the @ref ancs_parse_get_attrs_response function when requesting iOS notification attributes. So we must allocate memory for it here.
+} ble_ancs_c_t;
+
+/**@brief Apple Notification client init structure, which contains all options and data needed for
+ * initialization of the client. */
+typedef struct
+{
+ ble_ancs_c_evt_handler_t evt_handler; //!< Event handler to be called for handling events in the Battery Service.
+ ble_srv_error_handler_t error_handler; //!< Function to be called in case of an error.
+} ble_ancs_c_init_t;
+
+
+/**@brief Apple Notification Center Service UUIDs. */
+extern const ble_uuid128_t ble_ancs_base_uuid128; //!< Service UUID.
+extern const ble_uuid128_t ble_ancs_cp_base_uuid128; //!< Control point UUID.
+extern const ble_uuid128_t ble_ancs_ns_base_uuid128; //!< Notification source UUID.
+extern const ble_uuid128_t ble_ancs_ds_base_uuid128; //!< Data source UUID.
+
+
+/**@brief Function for handling the application's BLE stack events.
+ *
+ * @details Handles all events from the BLE stack that are of interest to the ANCS client.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context ANCS client structure.
+ */
+void ble_ancs_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for handling events from the database discovery module.
+ *
+ * @details This function will handle an event from the database discovery module and determine
+ * if it relates to the discovery of ANCS at the peer. If so, it will
+ * call the application's event handler indicating that ANCS has been
+ * discovered at the peer. It also populates the event with the service related
+ * information before providing it to the application.
+ *
+ * @param[in] p_ancs Pointer to the ANCS client structure.
+ * @param[in] p_evt Pointer to the event received from the database discovery module.
+ */
+ void ble_ancs_c_on_db_disc_evt(ble_ancs_c_t * p_ancs, ble_db_discovery_evt_t * p_evt);
+
+
+/**@brief Function for initializing the ANCS client.
+ *
+ * @param[out] p_ancs ANCS client structure. This structure must be
+ * supplied by the application. It is initialized by this function
+ * and will later be used to identify this particular client instance.
+ * @param[in] p_ancs_init Information needed to initialize the client.
+ *
+ * @retval NRF_SUCCESS If the client was initialized successfully. Otherwise, an error code is returned.
+ */
+ret_code_t ble_ancs_c_init(ble_ancs_c_t * p_ancs, ble_ancs_c_init_t const * p_ancs_init);
+
+
+/**@brief Function for writing to the CCCD to enable notifications from the Apple Notification Service.
+ *
+ * @param[in] p_ancs iOS notification structure. This structure must be supplied by
+ * the application. It identifies the particular client instance to use.
+ *
+ * @retval NRF_SUCCESS If writing to the CCCD was successful. Otherwise, an error code is returned.
+ */
+ret_code_t ble_ancs_c_notif_source_notif_enable(ble_ancs_c_t const * p_ancs);
+
+
+/**@brief Function for writing to the CCCD to enable data source notifications from the ANCS.
+ *
+ * @param[in] p_ancs iOS notification structure. This structure must be supplied by
+ * the application. It identifies the particular client instance to use.
+ *
+ * @retval NRF_SUCCESS If writing to the CCCD was successful. Otherwise, an error code is returned.
+ */
+ret_code_t ble_ancs_c_data_source_notif_enable(ble_ancs_c_t const * p_ancs);
+
+
+/**@brief Function for writing to the CCCD to disable notifications from the ANCS.
+ *
+ * @param[in] p_ancs iOS notification structure. This structure must be supplied by
+ * the application. It identifies the particular client instance to use.
+ *
+ * @retval NRF_SUCCESS If writing to the CCCD was successful. Otherwise, an error code is returned.
+ */
+ret_code_t ble_ancs_c_notif_source_notif_disable(ble_ancs_c_t const * p_ancs);
+
+
+/**@brief Function for writing to the CCCD to disable data source notifications from the ANCS.
+ *
+ * @param[in] p_ancs iOS notification structure. This structure must be supplied by
+ * the application. It identifies the particular client instance to use.
+ *
+ * @retval NRF_SUCCESS If writing to the CCCD was successful. Otherwise, an error code is returned.
+ */
+ret_code_t ble_ancs_c_data_source_notif_disable(ble_ancs_c_t const * p_ancs);
+
+
+/**@brief Function for registering attributes that will be requested when @ref nrf_ble_ancs_c_request_attrs
+ * is called.
+ *
+ * @param[in] p_ancs ANCS client instance on which the attribute will be registered.
+ * @param[in] id ID of the attribute that will be added.
+ * @param[in] p_data Pointer to a buffer where the data of the attribute can be stored.
+ * @param[in] len Length of the buffer where the data of the attribute can be stored.
+
+ * @retval NRF_SUCCESS If all operations were successful. Otherwise, an error code is returned.
+ */
+ret_code_t nrf_ble_ancs_c_attr_add(ble_ancs_c_t * p_ancs,
+ ble_ancs_c_notif_attr_id_val_t const id,
+ uint8_t * p_data,
+ uint16_t const len);
+
+
+/**@brief Function for removing attributes so that they will no longer be requested when
+ * @ref nrf_ble_ancs_c_request_attrs is called.
+ *
+ * @param[in] p_ancs ANCS client instance on which the attribute will be removed.
+ * @param[in] id ID of the attribute that will be removed.
+ *
+ * @retval NRF_SUCCESS If all operations were successful. Otherwise, an error code is returned.
+ */
+ret_code_t nrf_ble_ancs_c_attr_remove(ble_ancs_c_t * p_ancs,
+ ble_ancs_c_notif_attr_id_val_t const id);
+
+/**@brief Function for removing attributes so that they will no longer be requested when
+ * @ref nrf_ble_ancs_c_app_attr_request is called.
+ *
+ * @param[in] p_ancs ANCS client instance on which the attribute will be removed.
+ * @param[in] id ID of the attribute that will be removed.
+ *
+ * @retval NRF_SUCCESS If all operations were successful. Otherwise, an error code is returned.
+ */
+ret_code_t nrf_ble_ancs_c_app_attr_remove(ble_ancs_c_t * p_ancs,
+ ble_ancs_c_app_attr_id_val_t const id);
+
+
+/**@brief Function for registering attributes that will be requested when @ref nrf_ble_ancs_c_app_attr_request
+ * is called.
+ *
+ * @param[in] p_ancs ANCS client instance on which the attribute will be registered.
+ * @param[in] id ID of the attribute that will be added.
+ * @param[in] p_data Pointer to a buffer where the data of the attribute can be stored.
+ * @param[in] len Length of the buffer where the data of the attribute can be stored.
+ *
+ * @retval NRF_SUCCESS If all operations were successful. Otherwise, an error code is returned.
+ */
+ret_code_t nrf_ble_ancs_c_app_attr_add(ble_ancs_c_t * p_ancs,
+ ble_ancs_c_app_attr_id_val_t const id,
+ uint8_t * p_data,
+ uint16_t const len);
+
+/**@brief Function for clearing the list of notification attributes and app attributes that
+ * would be requested from NP.
+ *
+ * @param[in] p_ancs iOS notification structure. This structure must be supplied by
+ * the application. It identifies the particular client instance to use.
+**/
+ret_code_t nrf_ble_ancs_c_attr_req_clear_all(ble_ancs_c_t * p_ancs);
+
+/**@brief Function for requesting attributes for a notification.
+ *
+ * @param[in] p_ancs iOS notification structure. This structure must be supplied by
+ * the application. It identifies the particular client instance to use.
+ * @param[in] p_notif Pointer to the notification whose attributes will be requested from
+ * the Notification Provider.
+ *
+ * @retval NRF_SUCCESS If all operations were successful. Otherwise, an error code is returned.
+ */
+ret_code_t nrf_ble_ancs_c_request_attrs(ble_ancs_c_t * p_ancs,
+ ble_ancs_c_evt_notif_t const * p_notif);
+
+/**@brief Function for requesting attributes for a given app.
+ *
+ * @param[in] p_ancs iOS notification structure. This structure must be supplied by
+ * the application. It identifies the particular client instance to use.
+ * @param[in] p_app_id App identifier of the app for which the app attributes are requested.
+ * @param[in] len Length of the app identifier.
+ *
+ * @retval NRF_SUCCESS If all operations were successful. Otherwise, an error code is returned.
+ */
+ret_code_t nrf_ble_ancs_c_app_attr_request(ble_ancs_c_t * p_ancs,
+ uint8_t const * p_app_id,
+ uint32_t len);
+
+
+/**@brief Function for performing a notification action.
+ *
+ * @param[in] p_ancs iOS notification structure. This structure must be supplied by
+ * the application. It identifies the particular client instance to use.
+ * @param[in] uuid The UUID of the notification for which to perform the action.
+ * @param[in] action_id Perform a positive or negative action.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_NULL If @p p_ancs was a NULL pointer.
+ */
+ret_code_t nrf_ancs_perform_notif_action(ble_ancs_c_t * p_ancs,
+ uint32_t uuid,
+ ble_ancs_c_action_id_values_t action_id);
+
+/**@brief Function for assigning a handle to this instance of ancs_c.
+ *
+ * @details Call this function when a link has been established with a peer to
+ * associate this link to this instance of the module. This makes it
+ * possible to handle several link and associate each link to a particular
+ * instance of this module. The connection handle and attribute handles will be
+ * provided from the discovery event @ref BLE_ANCS_C_EVT_DISCOVERY_COMPLETE.
+ *
+ * @param[in] p_ancs Pointer to the ANCS client structure instance to associate with these
+ * handles.
+ * @param[in] conn_handle Connection handle to associate with the given ANCS instance.
+ * @param[in] p_service Attribute handles on the ANCS server that you want this ANCS client to
+ * interact with.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_NULL If @p p_ancs was a NULL pointer.
+ */
+ret_code_t nrf_ble_ancs_c_handles_assign(ble_ancs_c_t * p_ancs,
+ uint16_t const conn_handle,
+ ble_ancs_c_service_t const * p_service);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_ANCS_C_H__
+
+/** @} */
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ans_c/ble_ans_c.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ans_c/ble_ans_c.c
new file mode 100644
index 0000000..9fc8ad6
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ans_c/ble_ans_c.c
@@ -0,0 +1,575 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Attention!
+ * To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_ANS_C)
+#include "ble_ans_c.h"
+#include <string.h>
+#include <stdbool.h>
+#include "ble_err.h"
+#include "nrf_assert.h"
+#include "ble_db_discovery.h"
+#define NRF_LOG_MODULE_NAME ble_ans_c
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define NOTIFICATION_DATA_LENGTH 2 /**< The mandatory length of notification data. After the mandatory data, the optional message is located. */
+#define READ_DATA_LENGTH_MIN 1 /**< Minimum data length in a valid Alert Notification Read Response message. */
+
+#define TX_BUFFER_MASK 0x07 /**< TX Buffer mask, must be a mask of contiguous zeroes, followed by contiguous sequence of ones: 000...111. */
+#define TX_BUFFER_SIZE (TX_BUFFER_MASK + 1) /**< Size of send buffer, which is 1 higher than the mask. */
+#define WRITE_MESSAGE_LENGTH 2 /**< Length of the write message for CCCD/control point. */
+
+
+typedef enum
+{
+ READ_REQ = 1, /**< Type identifying that this tx_message is a read request. */
+ WRITE_REQ /**< Type identifying that this tx_message is a write request. */
+} ans_tx_request_t;
+
+
+/**@brief Structure for writing a message to the central, i.e. Control Point or CCCD.
+ */
+typedef struct
+{
+ uint8_t gattc_value[WRITE_MESSAGE_LENGTH]; /**< The message to write. */
+ ble_gattc_write_params_t gattc_params; /**< GATTC parameters for this message. */
+} ans_write_params_t;
+
+/**@brief Structure for holding data to be transmitted to the connected central.
+ */
+typedef struct
+{
+ uint16_t conn_handle; /**< Connection handle to be used when transmitting this message. */
+ ans_tx_request_t type; /**< Type of this message, i.e. read or write message. */
+ union
+ {
+ uint16_t read_handle; /**< Read request message. */
+ ans_write_params_t write_req; /**< Write request message. */
+ } req;
+} ans_tx_message_t;
+
+static ans_tx_message_t m_tx_buffer[TX_BUFFER_SIZE]; /**< Transmit buffer for messages to be transmitted to the central. */
+static uint32_t m_tx_insert_index = 0; /**< Current index in the transmit buffer where next message should be inserted. */
+static uint32_t m_tx_index = 0; /**< Current index in the transmit buffer from where the next message to be transmitted resides. */
+
+
+/**@brief Function for passing any pending request from the buffer to the stack.
+ */
+static void tx_buffer_process(void)
+{
+ if (m_tx_index != m_tx_insert_index)
+ {
+ uint32_t err_code;
+
+ if (m_tx_buffer[m_tx_index].type == READ_REQ)
+ {
+ err_code = sd_ble_gattc_read(m_tx_buffer[m_tx_index].conn_handle,
+ m_tx_buffer[m_tx_index].req.read_handle,
+ 0);
+ }
+ else
+ {
+ err_code = sd_ble_gattc_write(m_tx_buffer[m_tx_index].conn_handle,
+ &m_tx_buffer[m_tx_index].req.write_req.gattc_params);
+ }
+ if (err_code == NRF_SUCCESS)
+ {
+ ++m_tx_index;
+ m_tx_index &= TX_BUFFER_MASK;
+ }
+ }
+}
+
+
+/** @brief Function for copying a characteristic.
+ */
+static void char_set(ble_gattc_char_t * p_dest_char, ble_gattc_char_t const * p_source_char)
+{
+ memcpy(p_dest_char, p_source_char, sizeof(ble_gattc_char_t));
+}
+
+static void char_cccd_set(ble_gattc_desc_t * p_cccd, uint16_t cccd_handle)
+{
+ p_cccd->handle = cccd_handle;
+}
+
+/** @brief Function to check that all handles required by the client to use the server are present.
+ */
+static bool is_valid_ans_srv_discovered(ble_ans_c_service_t const * p_srv)
+{
+ if ((p_srv->alert_notif_ctrl_point.handle_value == BLE_GATT_HANDLE_INVALID) ||
+ (p_srv->suported_new_alert_cat.handle_value == BLE_GATT_HANDLE_INVALID) ||
+ (p_srv->suported_unread_alert_cat.handle_value == BLE_GATT_HANDLE_INVALID) ||
+ (p_srv->new_alert.handle_value == BLE_GATT_HANDLE_INVALID) ||
+ (p_srv->unread_alert_status.handle_value == BLE_GATT_HANDLE_INVALID) ||
+ (p_srv->new_alert_cccd.handle == BLE_GATT_HANDLE_INVALID) ||
+ (p_srv->unread_alert_cccd.handle == BLE_GATT_HANDLE_INVALID)
+ )
+ {
+ // At least one required characteristic is missing on the server side.
+ return false;
+ }
+ return true;
+}
+
+
+void ble_ans_c_on_db_disc_evt(ble_ans_c_t * p_ans, ble_db_discovery_evt_t const * p_evt)
+{
+ ble_ans_c_evt_t evt;
+
+ memset(&evt, 0, sizeof(ble_ans_c_evt_t));
+ evt.conn_handle = p_evt->conn_handle;
+ evt.evt_type = BLE_ANS_C_EVT_DISCOVERY_FAILED;
+
+ // Check if the Alert Notification Service was discovered.
+ if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE
+ &&
+ p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_ALERT_NOTIFICATION_SERVICE
+ &&
+ p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE)
+ {
+ // Find the characteristics inside the service.
+ for (uint8_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
+ {
+ ble_gatt_db_char_t const * p_char = &(p_evt->params.discovered_db.charateristics[i]);
+
+ switch (p_char->characteristic.uuid.uuid)
+ {
+ case BLE_UUID_ALERT_NOTIFICATION_CONTROL_POINT_CHAR:
+ NRF_LOG_DEBUG("Found Ctrlpt \r\n\r");
+ char_set(&evt.data.service.alert_notif_ctrl_point, &p_char->characteristic);
+ break;
+
+ case BLE_UUID_UNREAD_ALERT_CHAR:
+ NRF_LOG_DEBUG("Found Unread Alert \r\n\r");
+ char_set(&evt.data.service.unread_alert_status, &p_char->characteristic);
+ char_cccd_set(&evt.data.service.unread_alert_cccd,
+ p_char->cccd_handle);
+ break;
+
+ case BLE_UUID_NEW_ALERT_CHAR:
+ NRF_LOG_DEBUG("Found New Alert \r\n\r");
+ char_set(&evt.data.service.new_alert, &p_char->characteristic);
+ char_cccd_set(&evt.data.service.new_alert_cccd,
+ p_char->cccd_handle);
+ break;
+
+ case BLE_UUID_SUPPORTED_UNREAD_ALERT_CATEGORY_CHAR:
+ NRF_LOG_DEBUG("Found supported unread alert category \r\n\r");
+ char_set(&evt.data.service.suported_unread_alert_cat, &p_char->characteristic);
+ break;
+
+ case BLE_UUID_SUPPORTED_NEW_ALERT_CATEGORY_CHAR:
+ NRF_LOG_DEBUG("Found supported new alert category \r\n\r");
+ char_set(&evt.data.service.suported_new_alert_cat, &p_char->characteristic);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+ }
+ if (is_valid_ans_srv_discovered(&evt.data.service))
+ {
+ evt.evt_type = BLE_ANS_C_EVT_DISCOVERY_COMPLETE;
+ }
+ }
+ p_ans->evt_handler(&evt);
+}
+
+
+/**@brief Function for receiving and validating notifications received from the central.
+ */
+static void event_notify(ble_ans_c_t * p_ans, ble_evt_t const * p_ble_evt)
+{
+ uint32_t message_length;
+ ble_ans_c_evt_t event;
+ ble_ans_alert_notification_t * p_alert = &event.data.alert;
+ ble_gattc_evt_hvx_t const * p_notification = &p_ble_evt->evt.gattc_evt.params.hvx;
+
+ // Message is not valid -> ignore.
+ event.evt_type = BLE_ANS_C_EVT_NOTIFICATION;
+ if (p_notification->len < NOTIFICATION_DATA_LENGTH)
+ {
+ return;
+ }
+ message_length = p_notification->len - NOTIFICATION_DATA_LENGTH;
+
+ if (p_notification->handle == p_ans->service.new_alert.handle_value)
+ {
+ BLE_UUID_COPY_INST(event.uuid, p_ans->service.new_alert.uuid);
+ }
+ else if (p_notification->handle == p_ans->service.unread_alert_status.handle_value)
+ {
+ BLE_UUID_COPY_INST(event.uuid, p_ans->service.unread_alert_status.uuid);
+ }
+ else
+ {
+ // Nothing to process.
+ return;
+ }
+
+ p_alert->alert_category = p_notification->data[0];
+ p_alert->alert_category_count = p_notification->data[1]; //lint !e415
+ p_alert->alert_msg_length = (message_length > p_ans->message_buffer_size)
+ ? p_ans->message_buffer_size
+ : message_length;
+ p_alert->p_alert_msg_buf = p_ans->p_message_buffer;
+
+ memcpy(p_alert->p_alert_msg_buf,
+ &p_notification->data[NOTIFICATION_DATA_LENGTH],
+ p_alert->alert_msg_length); //lint !e416
+
+ p_ans->evt_handler(&event);
+}
+
+
+/**@brief Function for handling write response events.
+ */
+static void event_write_rsp(ble_ans_c_t * p_ans, ble_evt_t const * p_ble_evt)
+{
+ tx_buffer_process();
+}
+
+
+/**@brief Function for validating and passing the response to the application,
+ * when a read response is received.
+ */
+static void event_read_rsp(ble_ans_c_t * p_ans, ble_evt_t const * p_ble_evt)
+{
+ ble_ans_c_evt_t event;
+ ble_gattc_evt_read_rsp_t const * p_response;
+
+ p_response = &p_ble_evt->evt.gattc_evt.params.read_rsp;
+ event.evt_type = BLE_ANS_C_EVT_READ_RESP;
+
+ if (p_response->len < READ_DATA_LENGTH_MIN)
+ {
+ tx_buffer_process();
+ return;
+ }
+
+ if (p_response->handle == p_ans->service.suported_new_alert_cat.handle_value)
+ {
+ BLE_UUID_COPY_INST(event.uuid, p_ans->service.suported_new_alert_cat.uuid);
+ }
+ else if (p_response->handle == p_ans->service.suported_unread_alert_cat.handle_value)
+ {
+ BLE_UUID_COPY_INST(event.uuid, p_ans->service.suported_unread_alert_cat.uuid);
+ }
+ else
+ {
+ // Bad response, ignore.
+ tx_buffer_process();
+ return;
+ }
+
+ event.data.settings = *(ble_ans_alert_settings_t *)(p_response->data);
+
+ if (p_response->len == READ_DATA_LENGTH_MIN)
+ {
+ // Those must default to 0, if they are not returned by central.
+ event.data.settings.ans_high_prioritized_alert_support = 0;
+ event.data.settings.ans_instant_message_support = 0;
+ }
+
+ p_ans->evt_handler(&event);
+
+ tx_buffer_process();
+}
+
+
+/**@brief Function for disconnecting and cleaning the current service.
+ */
+static void event_disconnect(ble_ans_c_t * p_ans, ble_evt_t const * p_ble_evt)
+{
+ if (p_ans->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
+ {
+ p_ans->conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ // Clearing all data for the service will also set all handle values to @ref BLE_GATT_HANDLE_INVALID
+ memset(&p_ans->service, 0, sizeof(ble_ans_c_service_t));
+
+ // There was a valid instance of IAS on the peer. Send an event to the
+ // application, so that it can do any clean up related to this module.
+ ble_ans_c_evt_t evt;
+
+ evt.evt_type = BLE_ANS_C_EVT_DISCONN_COMPLETE;
+ p_ans->evt_handler(&evt);
+ }
+}
+
+
+/**@brief Function for handling of BLE stack events. */
+void ble_ans_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ ble_ans_c_t * p_ans = (ble_ans_c_t *)p_context;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GATTC_EVT_HVX:
+ event_notify(p_ans, p_ble_evt);
+ break;
+
+ case BLE_GATTC_EVT_WRITE_RSP:
+ event_write_rsp(p_ans, p_ble_evt);
+ break;
+
+ case BLE_GATTC_EVT_READ_RSP:
+ event_read_rsp(p_ans, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ event_disconnect(p_ans, p_ble_evt);
+ break;
+ }
+}
+
+
+uint32_t ble_ans_c_init(ble_ans_c_t * p_ans, ble_ans_c_init_t const * p_ans_init)
+{
+ VERIFY_PARAM_NOT_NULL(p_ans);
+ VERIFY_PARAM_NOT_NULL(p_ans_init);
+ VERIFY_PARAM_NOT_NULL(p_ans_init->evt_handler);
+
+ // clear all handles
+ memset(p_ans, 0, sizeof(ble_ans_c_t));
+ memset(m_tx_buffer, 0, TX_BUFFER_SIZE);
+ p_ans->conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ p_ans->evt_handler = p_ans_init->evt_handler;
+ p_ans->error_handler = p_ans_init->error_handler;
+ p_ans->message_buffer_size = p_ans_init->message_buffer_size;
+ p_ans->p_message_buffer = p_ans_init->p_message_buffer;
+
+ BLE_UUID_BLE_ASSIGN(p_ans->service.service.uuid, BLE_UUID_ALERT_NOTIFICATION_SERVICE);
+ BLE_UUID_BLE_ASSIGN(p_ans->service.new_alert.uuid, BLE_UUID_NEW_ALERT_CHAR);
+ BLE_UUID_BLE_ASSIGN(p_ans->service.alert_notif_ctrl_point.uuid,
+ BLE_UUID_ALERT_NOTIFICATION_CONTROL_POINT_CHAR);
+ BLE_UUID_BLE_ASSIGN(p_ans->service.unread_alert_status.uuid, BLE_UUID_UNREAD_ALERT_CHAR);
+ BLE_UUID_BLE_ASSIGN(p_ans->service.suported_new_alert_cat.uuid,
+ BLE_UUID_SUPPORTED_NEW_ALERT_CATEGORY_CHAR);
+ BLE_UUID_BLE_ASSIGN(p_ans->service.suported_unread_alert_cat.uuid,
+ BLE_UUID_SUPPORTED_UNREAD_ALERT_CATEGORY_CHAR);
+
+ BLE_UUID_BLE_ASSIGN(p_ans->service.new_alert_cccd.uuid, BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG);
+ BLE_UUID_BLE_ASSIGN(p_ans->service.unread_alert_cccd.uuid,
+ BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG);
+
+ return ble_db_discovery_evt_register(&p_ans->service.service.uuid);
+}
+
+
+/**@brief Function for creating a TX message for writing a CCCD.
+ */
+static uint32_t cccd_configure(uint16_t conn_handle, uint16_t handle_cccd, bool enable)
+{
+ ans_tx_message_t * p_msg;
+ uint16_t cccd_val = enable ? BLE_GATT_HVX_NOTIFICATION : 0;
+
+ p_msg = &m_tx_buffer[m_tx_insert_index++];
+ m_tx_insert_index &= TX_BUFFER_MASK;
+
+ p_msg->req.write_req.gattc_params.handle = handle_cccd;
+ p_msg->req.write_req.gattc_params.len = WRITE_MESSAGE_LENGTH;
+ p_msg->req.write_req.gattc_params.p_value = p_msg->req.write_req.gattc_value;
+ p_msg->req.write_req.gattc_params.offset = 0;
+ p_msg->req.write_req.gattc_params.write_op = BLE_GATT_OP_WRITE_REQ;
+ p_msg->req.write_req.gattc_value[0] = LSB_16(cccd_val);
+ p_msg->req.write_req.gattc_value[1] = MSB_16(cccd_val);
+ p_msg->conn_handle = conn_handle;
+ p_msg->type = WRITE_REQ;
+
+ tx_buffer_process();
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_ans_c_enable_notif_new_alert(ble_ans_c_t const * p_ans)
+{
+ if (p_ans->conn_handle == BLE_CONN_HANDLE_INVALID)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+ else
+ {
+ return cccd_configure(p_ans->conn_handle,
+ p_ans->service.new_alert_cccd.handle,
+ true);
+ }
+}
+
+
+uint32_t ble_ans_c_disable_notif_new_alert(ble_ans_c_t const * p_ans)
+{
+ return cccd_configure(p_ans->conn_handle,
+ p_ans->service.new_alert_cccd.handle,
+ false);
+}
+
+
+uint32_t ble_ans_c_enable_notif_unread_alert(ble_ans_c_t const * p_ans)
+{
+ if ( p_ans->conn_handle == BLE_CONN_HANDLE_INVALID)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+ return cccd_configure(p_ans->conn_handle,
+ p_ans->service.unread_alert_cccd.handle,
+ true);
+}
+
+
+uint32_t ble_ans_c_disable_notif_unread_alert(ble_ans_c_t const * p_ans)
+{
+ return cccd_configure(p_ans->conn_handle,
+ p_ans->service.unread_alert_cccd.handle,
+ false);
+}
+
+
+uint32_t ble_ans_c_control_point_write(ble_ans_c_t const * p_ans,
+ ble_ans_control_point_t const * p_control_point)
+{
+ ans_tx_message_t * p_msg;
+
+ p_msg = &m_tx_buffer[m_tx_insert_index++];
+ m_tx_insert_index &= TX_BUFFER_MASK;
+
+ p_msg->req.write_req.gattc_params.handle = p_ans->service.alert_notif_ctrl_point.handle_value;
+ p_msg->req.write_req.gattc_params.len = WRITE_MESSAGE_LENGTH;
+ p_msg->req.write_req.gattc_params.p_value = p_msg->req.write_req.gattc_value;
+ p_msg->req.write_req.gattc_params.offset = 0;
+ p_msg->req.write_req.gattc_params.write_op = BLE_GATT_OP_WRITE_REQ;
+ p_msg->req.write_req.gattc_value[0] = p_control_point->command;
+ p_msg->req.write_req.gattc_value[1] = p_control_point->category;
+ p_msg->conn_handle = p_ans->conn_handle;
+ p_msg->type = WRITE_REQ;
+
+ tx_buffer_process();
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_ans_c_new_alert_read(ble_ans_c_t const * p_ans)
+{
+ ans_tx_message_t * msg;
+
+ msg = &m_tx_buffer[m_tx_insert_index++];
+ m_tx_insert_index &= TX_BUFFER_MASK;
+
+ msg->req.read_handle = p_ans->service.suported_new_alert_cat.handle_value;
+ msg->conn_handle = p_ans->conn_handle;
+ msg->type = READ_REQ;
+
+ tx_buffer_process();
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_ans_c_unread_alert_read(ble_ans_c_t const * p_ans)
+{
+ ans_tx_message_t * msg;
+
+ msg = &m_tx_buffer[m_tx_insert_index++];
+ m_tx_insert_index &= TX_BUFFER_MASK;
+
+ msg->req.read_handle = p_ans->service.suported_unread_alert_cat.handle_value;
+ msg->conn_handle = p_ans->conn_handle;
+ msg->type = READ_REQ;
+
+ tx_buffer_process();
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_ans_c_new_alert_notify(ble_ans_c_t const * p_ans, ble_ans_category_id_t category_id)
+{
+ ble_ans_control_point_t control_point;
+
+ control_point.command = ANS_NOTIFY_NEW_INCOMING_ALERT_IMMEDIATELY;
+ control_point.category = category_id;
+
+ return ble_ans_c_control_point_write(p_ans, &control_point);
+}
+
+
+uint32_t ble_ans_c_unread_alert_notify(ble_ans_c_t const * p_ans, ble_ans_category_id_t category_id)
+{
+ ble_ans_control_point_t control_point;
+
+ control_point.command = ANS_NOTIFY_UNREAD_CATEGORY_STATUS_IMMEDIATELY;
+ control_point.category = category_id;
+
+ return ble_ans_c_control_point_write(p_ans, &control_point);
+}
+
+
+uint32_t ble_ans_c_handles_assign(ble_ans_c_t * p_ans,
+ uint16_t conn_handle,
+ ble_ans_c_service_t const * p_peer_handles)
+{
+ VERIFY_PARAM_NOT_NULL(p_ans);
+
+ if (!is_valid_ans_srv_discovered(p_peer_handles))
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ p_ans->conn_handle = conn_handle;
+
+ if (p_peer_handles != NULL)
+ {
+ // Copy the handles from the discovered characteristics over to the provided client instance.
+ char_set(&p_ans->service.alert_notif_ctrl_point, &p_peer_handles->alert_notif_ctrl_point);
+ char_set(&p_ans->service.suported_new_alert_cat, &p_peer_handles->suported_new_alert_cat);
+ char_set(&p_ans->service.suported_unread_alert_cat, &p_peer_handles->suported_unread_alert_cat);
+ char_set(&p_ans->service.new_alert, &p_peer_handles->new_alert);
+ char_cccd_set(&p_ans->service.new_alert_cccd, p_peer_handles->new_alert_cccd.handle);
+ char_set(&p_ans->service.unread_alert_status, &p_peer_handles->unread_alert_status);
+ char_cccd_set(&p_ans->service.unread_alert_cccd, p_peer_handles->unread_alert_cccd.handle);
+ }
+
+ return NRF_SUCCESS;
+}
+#endif // NRF_MODULE_ENABLED(BLE_ANS_C)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ans_c/ble_ans_c.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ans_c/ble_ans_c.h
new file mode 100644
index 0000000..642cffd
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ans_c/ble_ans_c.h
@@ -0,0 +1,409 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_ans_c Alert Notification Service Client
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Alert Notification module.
+ *
+ * @details This module implements the Alert Notification Client according to the
+ * Alert Notification Profile.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_ans_c_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_ANS_C_BLE_OBSERVER_PRIO,
+ * ble_ans_c_on_ble_evt, &instance);
+ * @endcode
+ *
+ * @note Attention!
+ * To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+#ifndef BLE_ANS_C_H__
+#define BLE_ANS_C_H__
+
+#include "ble.h"
+#include "ble_gatts.h"
+#include "ble_types.h"
+#include "sdk_common.h"
+#include "ble_srv_common.h"
+#include "ble_db_discovery.h"
+#include "nrf_sdh_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_ans_c instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_ANS_C_DEF(_name) \
+static ble_ans_c_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_ANS_C_BLE_OBSERVER_PRIO, \
+ ble_ans_c_on_ble_evt, &_name)
+
+/** @brief Macro for defining multiple ble_ans_c instances.
+ *
+ * @param _name Name of the array of instances.
+ * @param _cnt Number of instances to define.
+ * @hideinitializer
+ */
+#define BLE_ANS_C_ARRAY_DEF(_name, _cnt) \
+static ble_ans_c_t _name[_cnt]; \
+NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
+ BLE_ANS_C_BLE_OBSERVER_PRIO, \
+ ble_ans_c_on_ble_evt, &_name, _cnt)
+
+// Forward declaration of the ble_ans_c_t type.
+typedef struct ble_ans_c_s ble_ans_c_t;
+
+/** Alerts types as defined in the alert category id; UUID: 0x2A43. */
+typedef enum
+{
+ ANS_TYPE_SIMPLE_ALERT = 0, /**< General text alert or non-text alert.*/
+ ANS_TYPE_EMAIL = 1, /**< Alert when email messages arrives.*/
+ ANS_TYPE_NEWS = 2, /**< News feeds such as RSS, Atom.*/
+ ANS_TYPE_NOTIFICATION_CALL = 3, /**< Incoming call.*/
+ ANS_TYPE_MISSED_CALL = 4, /**< Missed call.*/
+ ANS_TYPE_SMS_MMS = 5, /**< SMS/MMS message arrives.*/
+ ANS_TYPE_VOICE_MAIL = 6, /**< Voice mail.*/
+ ANS_TYPE_SCHEDULE = 7, /**< Alert occurred on calendar, planner.*/
+ ANS_TYPE_HIGH_PRIORITIZED_ALERT = 8, /**< Alert that should be handled as high priority.*/
+ ANS_TYPE_INSTANT_MESSAGE = 9, /**< Alert for incoming instant messages.*/
+ ANS_TYPE_ALL_ALERTS = 0xFF /**< Identifies All Alerts. */
+} ble_ans_category_id_t;
+
+/** Alerts notification control point commands as defined in the Alert Notification Specification;
+ * UUID: 0x2A44.
+ */
+typedef enum
+{
+ ANS_ENABLE_NEW_INCOMING_ALERT_NOTIFICATION = 0, /**< Enable New Incoming Alert Notification.*/
+ ANS_ENABLE_UNREAD_CATEGORY_STATUS_NOTIFICATION = 1, /**< Enable Unread Category Status Notification.*/
+ ANS_DISABLE_NEW_INCOMING_ALERT_NOTIFICATION = 2, /**< Disable New Incoming Alert Notification.*/
+ ANS_DISABLE_UNREAD_CATEGORY_STATUS_NOTIFICATION = 3, /**< Disable Unread Category Status Notification.*/
+ ANS_NOTIFY_NEW_INCOMING_ALERT_IMMEDIATELY = 4, /**< Notify New Incoming Alert immediately.*/
+ ANS_NOTIFY_UNREAD_CATEGORY_STATUS_IMMEDIATELY = 5, /**< Notify Unread Category Status immediately.*/
+} ble_ans_command_id_t;
+
+/**@brief Alert Notification Event types that are passed from client to application on an event. */
+typedef enum
+{
+ BLE_ANS_C_EVT_DISCOVERY_COMPLETE, /**< A successful connection has been established and the characteristics of the server has been fetched. */
+ BLE_ANS_C_EVT_DISCOVERY_FAILED, /**< It was not possible to discover service or characteristics of the connected peer. */
+ BLE_ANS_C_EVT_DISCONN_COMPLETE, /**< The connection has been taken down. */
+ BLE_ANS_C_EVT_NOTIFICATION, /**< A valid Alert Notification has been received from the server.*/
+ BLE_ANS_C_EVT_READ_RESP, /**< A read response has been received from the server.*/
+ BLE_ANS_C_EVT_WRITE_RESP /**< A write response has been received from the server.*/
+} ble_ans_c_evt_type_t;
+
+/**@brief Alert Notification Control Point structure. */
+typedef struct
+{
+ ble_ans_command_id_t command; /**< The command to be written to the control point, see @ref ble_ans_command_id_t. */
+ ble_ans_category_id_t category; /**< The category for the control point for which the command applies, see @ref ble_ans_category_id_t. */
+} ble_ans_control_point_t;
+
+/**@brief Alert Notification Setting structure containing the supported alerts in the service.
+ *
+ *@details
+ * The structure contains bit fields describing which alerts that are supported:
+ * 0 = Unsupported
+ * 1 = Supported
+ */
+typedef struct
+{
+ uint8_t ans_simple_alert_support : 1; /**< Support for General text alert or non-text alert.*/
+ uint8_t ans_email_support : 1; /**< Support for Alert when email messages arrives.*/
+ uint8_t ans_news_support : 1; /**< Support for News feeds such as RSS, Atom.*/
+ uint8_t ans_notification_call_support : 1; /**< Support for Incoming call.*/
+ uint8_t ans_missed_call_support : 1; /**< Support for Missed call.*/
+ uint8_t ans_sms_mms_support : 1; /**< Support for SMS/MMS message arrives.*/
+ uint8_t ans_voice_mail_support : 1; /**< Support for Voice mail.*/
+ uint8_t ans_schedule_support : 1; /**< Support for Alert occurred on calendar, planner.*/
+ uint8_t ans_high_prioritized_alert_support : 1; /**< Support for Alert that should be handled as high priority.*/
+ uint8_t ans_instant_message_support : 1; /**< Support for Alert for incoming instant messages.*/
+ uint8_t reserved : 6; /**< Reserved for future use. */
+} ble_ans_alert_settings_t;
+
+/**@brief Alert Notification structure
+ */
+typedef struct
+{
+ uint8_t alert_category; /**< Alert category to which this alert belongs.*/
+ uint8_t alert_category_count; /**< Number of alerts in the category. */
+ uint32_t alert_msg_length; /**< Length of optional text message send by the server. */
+ uint8_t * p_alert_msg_buf; /**< Pointer to buffer containing the optional text message. */
+} ble_ans_alert_notification_t;
+
+/**@brief Struct to hold information on the Alert Notification Service if found on the server. */
+typedef struct
+{
+ ble_gattc_service_t service; /**< The GATT service holding the discovered Alert Notification Service. */
+ ble_gattc_char_t alert_notif_ctrl_point; /**< Characteristic for the Alert Notification Control Point. @ref BLE_UUID_ALERT_NOTIFICATION_CONTROL_POINT_CHAR */
+ ble_gattc_char_t suported_new_alert_cat; /**< Characteristic for the Supported New Alert category. @ref BLE_UUID_SUPPORTED_NEW_ALERT_CATEGORY_CHAR */
+ ble_gattc_char_t suported_unread_alert_cat; /**< Characteristic for the Unread Alert category. @ref BLE_UUID_SUPPORTED_UNREAD_ALERT_CATEGORY_CHAR */
+ ble_gattc_char_t new_alert; /**< Characteristic for the New Alert Notification. @ref BLE_UUID_NEW_ALERT_CHAR */
+ ble_gattc_desc_t new_alert_cccd; /**< Characteristic Descriptor for New Alert Category. Enables or Disables GATT notifications */
+ ble_gattc_char_t unread_alert_status; /**< Characteristic for the Unread Alert Notification. @ref BLE_UUID_UNREAD_ALERT_CHAR */
+ ble_gattc_desc_t unread_alert_cccd; /**< Characteristic Descriptor for Unread Alert Category. Enables or Disables GATT notifications */
+} ble_ans_c_service_t;
+
+/**@brief Alert Notification Event structure
+ *
+ * @details The structure contains the event that should be handled, as well as
+ * additional information.
+ */
+typedef struct
+{
+ ble_ans_c_evt_type_t evt_type; /**< Type of event. */
+ uint16_t conn_handle; /**< Connection handle on which the ANS service was discovered on the peer device. This will be filled if the evt_type is @ref BLE_ANS_C_EVT_DISCOVERY_COMPLETE.*/
+ ble_uuid_t uuid; /**< UUID of the event in case of an alert or notification. */
+ union
+ {
+ ble_ans_alert_settings_t settings; /**< Setting returned from server on read request. */
+ ble_ans_alert_notification_t alert; /**< Alert Notification data sent by the server. */
+ uint32_t error_code; /**< Additional status/error code if the event was caused by a stack error or gatt status, e.g. during service discovery. */
+ ble_ans_c_service_t service; /**< Info on the discovered Alert Notification Service discovered. This will be filled if the evt_type is @ref BLE_ANS_C_EVT_DISCOVERY_COMPLETE.*/
+ } data;
+} ble_ans_c_evt_t;
+
+/**@brief Alert Notification event handler type. */
+typedef void (*ble_ans_c_evt_handler_t) (ble_ans_c_evt_t * p_evt);
+
+/**@brief Alert Notification structure. This contains various status information for the client. */
+struct ble_ans_c_s
+{
+ ble_ans_c_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Alert Notification Client Application. */
+ ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
+ uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
+ uint8_t central_handle; /**< Handle for the currently connected central if peer is bonded. */
+ uint8_t service_handle; /**< Handle to the service in the database to use for this instance. */
+ uint32_t message_buffer_size; /**< Size of message buffer to hold the additional text messages received on notifications. */
+ uint8_t * p_message_buffer; /**< Pointer to the buffer to be used for additional text message handling. */
+ ble_ans_c_service_t service; /**< Struct to store the different handles and UUIDs related to the service. */
+};
+
+/**@brief Alert Notification init structure. This contains all options and data needed for
+ * initialization of the client.*/
+typedef struct
+{
+ ble_ans_c_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Battery Service. */
+ ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
+ uint32_t message_buffer_size; /**< Size of buffer to handle messages. */
+ uint8_t * p_message_buffer; /**< Pointer to buffer for passing messages. */
+} ble_ans_c_init_t;
+
+
+/**@brief Function for handling events from the database discovery module.
+ *
+ * @details Call this function when getting a callback event from the DB discovery modue.
+ * This function will handle an event from the database discovery module, and determine
+ * if it relates to the discovery of heart rate service at the peer. If so, it will
+ * call the application's event handler indicating that the heart rate service has been
+ * discovered at the peer. It also populates the event with the service related
+ * information before providing it to the application.
+ *
+ * @param[in] p_ans Pointer to the Alert Notification client structure instance that will handle
+ * the discovery.
+ * @param[in] p_evt Pointer to the event received from the database discovery module.
+ */
+void ble_ans_c_on_db_disc_evt(ble_ans_c_t * p_ans, ble_db_discovery_evt_t const * p_evt);
+
+
+/**@brief Function for handling the Application's BLE Stack events.
+ *
+ * @details Handles all events from the BLE stack of interest to the Alert Notification Client.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Alert Notification Client structure.
+ */
+void ble_ans_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for initializing the Alert Notification Client.
+ *
+ * @param[out] p_ans Alert Notification Client structure. This structure will have to be
+ * supplied by the application. It will be initialized by this function,
+ * and will later be used to identify this particular client instance.
+ * @param[in] p_ans_init Information needed to initialize the client.
+ *
+ * @return NRF_SUCCESS on successful initialization of client, otherwise an error code.
+ */
+uint32_t ble_ans_c_init(ble_ans_c_t * p_ans, ble_ans_c_init_t const * p_ans_init);
+
+
+/**@brief Function for writing the to CCCD to enable new alert notifications from the Alert Notification Service.
+ *
+ * @param[in] p_ans Alert Notification structure. This structure will have to be supplied by
+ * the application. It identifies the particular client instance to use.
+ *
+ * @return NRF_SUCCESS on successful writing of the CCCD, otherwise an error code.
+ */
+uint32_t ble_ans_c_enable_notif_new_alert(ble_ans_c_t const * p_ans);
+
+
+/**@brief Function for writing to the CCCD to enable unread alert notifications from the Alert Notification Service.
+ *
+ * @param[in] p_ans Alert Notification structure. This structure will have to be supplied by
+ * the application. It identifies the particular client instance to use.
+ *
+ * @return NRF_SUCCESS on successful writing of the CCCD, otherwise an error code.
+ */
+uint32_t ble_ans_c_enable_notif_unread_alert(ble_ans_c_t const * p_ans);
+
+
+/**@brief Function for writing to the CCCD to disable new alert notifications from the Alert Notification Service.
+ *
+ * @param[in] p_ans Alert Notification structure. This structure will have to be supplied by
+ * the application. It identifies the particular client instance to use.
+ *
+ * @return NRF_SUCCESS on successful writing of the CCCD, otherwise an error code.
+ */
+uint32_t ble_ans_c_disable_notif_new_alert(ble_ans_c_t const * p_ans);
+
+
+/**@brief Function for writing to the CCCD to disable unread alert notifications from the Alert Notification Service.
+ *
+ * @param[in] p_ans Alert Notification structure. This structure will have to be supplied by
+ * the application. It identifies the particular client instance to use.
+ *
+ * @return NRF_SUCCESS on successful writing of the CCCD, otherwise an error code.
+ */
+uint32_t ble_ans_c_disable_notif_unread_alert(ble_ans_c_t const * p_ans);
+
+
+/**@brief Function for writing to the Alert Notification Control Point to specify alert notification behavior in the
+ * Alert Notification Service on the Central.
+ *
+ * @param[in] p_ans Alert Notification structure. This structure will have to be
+ * supplied by the application. It identifies the particular client
+ * instance to use.
+ * @param[in] p_control_point Alert Notification Control Point structure. This structure
+ * specifies the values to write to the Alert Notification Control
+ * Point, UUID 0x2A44.
+ *
+ * @return NRF_SUCCESS on successful writing of the Control Point, otherwise an error code.
+ */
+uint32_t ble_ans_c_control_point_write(ble_ans_c_t const * p_ans,
+ ble_ans_control_point_t const * p_control_point);
+
+
+/**@brief Function for reading the Supported New Alert characteristic value of the service.
+ * The value describes the alerts supported in the central.
+ *
+ * @param[in] p_ans Alert Notification structure. This structure will have to be supplied by
+ * the application. It identifies the particular client instance to use.
+ *
+ * @return NRF_SUCCESS on successful transmission of the read request, otherwise an error code.
+ */
+uint32_t ble_ans_c_new_alert_read(ble_ans_c_t const * p_ans);
+
+
+/**@brief Function for reading the Supported Unread Alert characteristic value of the service.
+ * The value describes the alerts supported in the central.
+ *
+ * @param[in] p_ans Alert Notification structure. This structure will have to be supplied by
+ * the application. It identifies the particular client instance to use.
+ *
+ * @return NRF_SUCCESS on successful transmission of the read request, otherwise an error code.
+ */
+uint32_t ble_ans_c_unread_alert_read(ble_ans_c_t const * p_ans);
+
+
+/**@brief Function for requesting the peer to notify the New Alert characteristics immediately.
+ *
+ * @param[in] p_ans Alert Notification structure. This structure will have to be supplied by
+ * the application. It identifies the particular client instance to use.
+ * @param[in] category The category ID for which the peer should notify the client.
+ *
+ * @return NRF_SUCCESS on successful transmission of the read request, otherwise an error code.
+ */
+uint32_t ble_ans_c_new_alert_notify(ble_ans_c_t const * p_ans, ble_ans_category_id_t category);
+
+
+/**@brief Function for requesting the peer to notify the Unread Alert characteristics immediately.
+ *
+ * @param[in] p_ans Alert Notification structure. This structure will have to be supplied by
+ * the application. It identifies the particular client instance to use.
+ * @param[in] category The category ID for which the peer should notify the client.
+ *
+ * @return NRF_SUCCESS on successful transmission of the read request, otherwise an error code.
+ */
+uint32_t ble_ans_c_unread_alert_notify(ble_ans_c_t const * p_ans, ble_ans_category_id_t category);
+
+
+/**@brief Function for assigning a handles to a an instance of ans_c.
+ *
+ * @details Call this function when a link has been established with a peer to
+ * associate this link to an instance of the module. This makes it
+ * possible to handle several link and associate each link to a particular
+ * instance of the ans_c module. The connection handle and attribute handles will be
+ * provided from the discovery event @ref BLE_ANS_C_EVT_DISCOVERY_COMPLETE.
+ *
+ * @param[in] p_ans Pointer to the Alert Notification client structure instance to
+ * associate with the handles.
+ * @param[in] conn_handle Connection handle to associated with the given Alert Notification Client
+ * Instance.
+ * @param[in] p_peer_handles Attribute handles on the ANS server that you want this ANS client to
+ * interact with.
+ *
+ */
+uint32_t ble_ans_c_handles_assign(ble_ans_c_t * p_ans,
+ uint16_t const conn_handle,
+ ble_ans_c_service_t const * p_peer_handles);
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_ANS_C_H__
+
+/** @} */
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bas/ble_bas.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bas/ble_bas.c
new file mode 100644
index 0000000..4c7d174
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bas/ble_bas.c
@@ -0,0 +1,384 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Attention!
+ * To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_BAS)
+#include "ble_bas.h"
+#include <string.h>
+#include "ble_srv_common.h"
+#include "ble_conn_state.h"
+
+#define NRF_LOG_MODULE_NAME ble_bas
+#if BLE_BAS_CONFIG_LOG_ENABLED
+#define NRF_LOG_LEVEL BLE_BAS_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR BLE_BAS_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR BLE_BAS_CONFIG_DEBUG_COLOR
+#else // BLE_BAS_CONFIG_LOG_ENABLED
+#define NRF_LOG_LEVEL 0
+#endif // BLE_BAS_CONFIG_LOG_ENABLED
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+
+#define INVALID_BATTERY_LEVEL 255
+
+
+/**@brief Function for handling the Write event.
+ *
+ * @param[in] p_bas Battery Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_write(ble_bas_t * p_bas, ble_evt_t const * p_ble_evt)
+{
+ if (!p_bas->is_notification_supported)
+ {
+ return;
+ }
+
+ ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+ if ( (p_evt_write->handle == p_bas->battery_level_handles.cccd_handle)
+ && (p_evt_write->len == 2))
+ {
+ if (p_bas->evt_handler == NULL)
+ {
+ return;
+ }
+
+ ble_bas_evt_t evt;
+
+ if (ble_srv_is_notification_enabled(p_evt_write->data))
+ {
+ evt.evt_type = BLE_BAS_EVT_NOTIFICATION_ENABLED;
+ }
+ else
+ {
+ evt.evt_type = BLE_BAS_EVT_NOTIFICATION_DISABLED;
+ }
+ evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
+
+ // CCCD written, call application event handler.
+ p_bas->evt_handler(p_bas, &evt);
+ }
+}
+
+
+void ble_bas_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ if ((p_context == NULL) || (p_ble_evt == NULL))
+ {
+ return;
+ }
+
+ ble_bas_t * p_bas = (ble_bas_t *)p_context;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GATTS_EVT_WRITE:
+ on_write(p_bas, p_ble_evt);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+
+/**@brief Function for adding the Battery Level characteristic.
+ *
+ * @param[in] p_bas Battery Service structure.
+ * @param[in] p_bas_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static ret_code_t battery_level_char_add(ble_bas_t * p_bas, const ble_bas_init_t * p_bas_init)
+{
+ ret_code_t err_code;
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_md_t cccd_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+ uint8_t initial_battery_level;
+ uint8_t encoded_report_ref[BLE_SRV_ENCODED_REPORT_REF_LEN];
+ uint8_t init_len;
+
+ // Add Battery Level characteristic
+ if (p_bas->is_notification_supported)
+ {
+ memset(&cccd_md, 0, sizeof(cccd_md));
+
+ // According to BAS_SPEC_V10, the read operation on cccd should be possible without
+ // authentication.
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
+ cccd_md.write_perm = p_bas_init->battery_level_char_attr_md.cccd_write_perm;
+ cccd_md.vloc = BLE_GATTS_VLOC_STACK;
+ }
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.char_props.notify = (p_bas->is_notification_supported) ? 1 : 0;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = (p_bas->is_notification_supported) ? &cccd_md : NULL;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_BATTERY_LEVEL_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.read_perm = p_bas_init->battery_level_char_attr_md.read_perm;
+ attr_md.write_perm = p_bas_init->battery_level_char_attr_md.write_perm;
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ initial_battery_level = p_bas_init->initial_batt_level;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = sizeof(uint8_t);
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = sizeof(uint8_t);
+ attr_char_value.p_value = &initial_battery_level;
+
+ err_code = sd_ble_gatts_characteristic_add(p_bas->service_handle, &char_md,
+ &attr_char_value,
+ &p_bas->battery_level_handles);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ if (p_bas_init->p_report_ref != NULL)
+ {
+ // Add Report Reference descriptor
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_REPORT_REF_DESCR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.read_perm = p_bas_init->battery_level_report_read_perm;
+ BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
+
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ init_len = ble_srv_report_ref_encode(encoded_report_ref, p_bas_init->p_report_ref);
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = init_len;
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = attr_char_value.init_len;
+ attr_char_value.p_value = encoded_report_ref;
+
+ err_code = sd_ble_gatts_descriptor_add(p_bas->battery_level_handles.value_handle,
+ &attr_char_value,
+ &p_bas->report_ref_handle);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+ else
+ {
+ p_bas->report_ref_handle = BLE_GATT_HANDLE_INVALID;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t ble_bas_init(ble_bas_t * p_bas, const ble_bas_init_t * p_bas_init)
+{
+ if (p_bas == NULL || p_bas_init == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ ret_code_t err_code;
+ ble_uuid_t ble_uuid;
+
+ // Initialize service structure
+ p_bas->evt_handler = p_bas_init->evt_handler;
+ p_bas->is_notification_supported = p_bas_init->support_notification;
+ p_bas->battery_level_last = INVALID_BATTERY_LEVEL;
+
+ // Add service
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_BATTERY_SERVICE);
+
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_bas->service_handle);
+ VERIFY_SUCCESS(err_code);
+
+ // Add battery level characteristic
+ err_code = battery_level_char_add(p_bas, p_bas_init);
+ return err_code;
+}
+
+
+/**@brief Function for sending notifications with the Battery Level characteristic.
+ *
+ * @param[in] p_hvx_params Pointer to structure with notification data.
+ * @param[in] conn_handle Connection handle.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static ret_code_t battery_notification_send(ble_gatts_hvx_params_t * const p_hvx_params,
+ uint16_t conn_handle)
+{
+ ret_code_t err_code = sd_ble_gatts_hvx(conn_handle, p_hvx_params);
+ if (err_code == NRF_SUCCESS)
+ {
+ NRF_LOG_INFO("Battery notification has been sent using conn_handle: 0x%04X", conn_handle);
+ }
+ else
+ {
+ NRF_LOG_DEBUG("Error: 0x%08X while sending notification with conn_handle: 0x%04X",
+ err_code,
+ conn_handle);
+ }
+ return err_code;
+}
+
+
+ret_code_t ble_bas_battery_level_update(ble_bas_t * p_bas,
+ uint8_t battery_level,
+ uint16_t conn_handle)
+{
+ if (p_bas == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ ret_code_t err_code = NRF_SUCCESS;
+ ble_gatts_value_t gatts_value;
+
+ if (battery_level != p_bas->battery_level_last)
+ {
+ // Initialize value struct.
+ memset(&gatts_value, 0, sizeof(gatts_value));
+
+ gatts_value.len = sizeof(uint8_t);
+ gatts_value.offset = 0;
+ gatts_value.p_value = &battery_level;
+
+ // Update database.
+ err_code = sd_ble_gatts_value_set(BLE_CONN_HANDLE_INVALID,
+ p_bas->battery_level_handles.value_handle,
+ &gatts_value);
+ if (err_code == NRF_SUCCESS)
+ {
+ NRF_LOG_INFO("Battery level has been updated: %d%%", battery_level)
+
+ // Save new battery value.
+ p_bas->battery_level_last = battery_level;
+ }
+ else
+ {
+ NRF_LOG_DEBUG("Error during battery level update: 0x%08X", err_code)
+
+ return err_code;
+ }
+
+ // Send value if connected and notifying.
+ if (p_bas->is_notification_supported)
+ {
+ ble_gatts_hvx_params_t hvx_params;
+
+ memset(&hvx_params, 0, sizeof(hvx_params));
+
+ hvx_params.handle = p_bas->battery_level_handles.value_handle;
+ hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
+ hvx_params.offset = gatts_value.offset;
+ hvx_params.p_len = &gatts_value.len;
+ hvx_params.p_data = gatts_value.p_value;
+
+ if (conn_handle == BLE_CONN_HANDLE_ALL)
+ {
+ ble_conn_state_conn_handle_list_t conn_handles = ble_conn_state_conn_handles();
+
+ // Try sending notifications to all valid connection handles.
+ for (uint32_t i = 0; i < conn_handles.len; i++)
+ {
+ if (ble_conn_state_status(conn_handles.conn_handles[i]) == BLE_CONN_STATUS_CONNECTED)
+ {
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = battery_notification_send(&hvx_params,
+ conn_handles.conn_handles[i]);
+ }
+ else
+ {
+ // Preserve the first non-zero error code
+ UNUSED_RETURN_VALUE(battery_notification_send(&hvx_params,
+ conn_handles.conn_handles[i]));
+ }
+ }
+ }
+ }
+ else
+ {
+ err_code = battery_notification_send(&hvx_params, conn_handle);
+ }
+ }
+ else
+ {
+ err_code = NRF_ERROR_INVALID_STATE;
+ }
+ }
+
+ return err_code;
+}
+
+
+#endif // NRF_MODULE_ENABLED(BLE_BAS)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bas/ble_bas.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bas/ble_bas.h
new file mode 100644
index 0000000..bf11ca6
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bas/ble_bas.h
@@ -0,0 +1,194 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_bas Battery Service
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Battery Service module.
+ *
+ * @details This module implements the Battery Service with the Battery Level characteristic.
+ * During initialization it adds the Battery Service and Battery Level characteristic
+ * to the BLE stack database. Optionally it can also add a Report Reference descriptor
+ * to the Battery Level characteristic (used when including the Battery Service in
+ * the HID service).
+ *
+ * If specified, the module will support notification of the Battery Level characteristic
+ * through the ble_bas_battery_level_update() function.
+ * If an event handler is supplied by the application, the Battery Service will
+ * generate Battery Service events to the application.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_bas_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_BAS_BLE_OBSERVER_PRIO,
+ * ble_bas_on_ble_evt, &instance);
+ * @endcode
+ *
+ * @note Attention!
+ * To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+#ifndef BLE_BAS_H__
+#define BLE_BAS_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "nrf_sdh_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_bas instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_BAS_DEF(_name) \
+ static ble_bas_t _name; \
+ NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_BAS_BLE_OBSERVER_PRIO, \
+ ble_bas_on_ble_evt, \
+ &_name)
+
+/**@brief Battery Service event type. */
+typedef enum
+{
+ BLE_BAS_EVT_NOTIFICATION_ENABLED, /**< Battery value notification enabled event. */
+ BLE_BAS_EVT_NOTIFICATION_DISABLED /**< Battery value notification disabled event. */
+} ble_bas_evt_type_t;
+
+/**@brief Battery Service event. */
+typedef struct
+{
+ ble_bas_evt_type_t evt_type; /**< Type of event. */
+ uint16_t conn_handle; /**< Connection handle. */
+} ble_bas_evt_t;
+
+// Forward declaration of the ble_bas_t type.
+typedef struct ble_bas_s ble_bas_t;
+
+/**@brief Battery Service event handler type. */
+typedef void (* ble_bas_evt_handler_t) (ble_bas_t * p_bas, ble_bas_evt_t * p_evt);
+
+/**@brief Battery Service init structure. This contains all options and data needed for
+ * initialization of the service.*/
+typedef struct
+{
+ ble_bas_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Battery Service. */
+ bool support_notification; /**< TRUE if notification of Battery Level measurement is supported. */
+ ble_srv_report_ref_t * p_report_ref; /**< If not NULL, a Report Reference descriptor with the specified value will be added to the Battery Level characteristic */
+ uint8_t initial_batt_level; /**< Initial battery level */
+ ble_srv_cccd_security_mode_t battery_level_char_attr_md; /**< Initial security level for battery characteristics attribute */
+ ble_gap_conn_sec_mode_t battery_level_report_read_perm; /**< Initial security level for battery report read attribute */
+} ble_bas_init_t;
+
+/**@brief Battery Service structure. This contains various status information for the service. */
+struct ble_bas_s
+{
+ ble_bas_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Battery Service. */
+ uint16_t service_handle; /**< Handle of Battery Service (as provided by the BLE stack). */
+ ble_gatts_char_handles_t battery_level_handles; /**< Handles related to the Battery Level characteristic. */
+ uint16_t report_ref_handle; /**< Handle of the Report Reference descriptor. */
+ uint8_t battery_level_last; /**< Last Battery Level measurement passed to the Battery Service. */
+ bool is_notification_supported; /**< TRUE if notification of Battery Level is supported. */
+};
+
+
+/**@brief Function for initializing the Battery Service.
+ *
+ * @param[out] p_bas Battery Service structure. This structure will have to be supplied by
+ * the application. It will be initialized by this function, and will later
+ * be used to identify this particular service instance.
+ * @param[in] p_bas_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
+ */
+ret_code_t ble_bas_init(ble_bas_t * p_bas, const ble_bas_init_t * p_bas_init);
+
+
+/**@brief Function for handling the Application's BLE Stack events.
+ *
+ * @details Handles all events from the BLE stack of interest to the Battery Service.
+ *
+ * @note For the requirements in the BAS specification to be fulfilled,
+ * ble_bas_battery_level_update() must be called upon reconnection if the
+ * battery level has changed while the service has been disconnected from a bonded
+ * client.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Battery Service structure.
+ */
+void ble_bas_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for updating the battery level.
+ *
+ * @details The application calls this function after having performed a battery measurement.
+ * The battery level characteristic will only be sent to the clients which have
+ * enabled notifications. \ref BLE_CONN_HANDLE_ALL can be used as a connection handle
+ * to send notifications to all connected devices.
+ *
+ * @note For the requirements in the BAS specification to be fulfilled,
+ * this function must be called upon reconnection if the battery level has changed
+ * while the service has been disconnected from a bonded client.
+ *
+ * @param[in] p_bas Battery Service structure.
+ * @param[in] battery_level New battery measurement value (in percent of full capacity).
+ * @param[in] conn_handle Connection handle.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+ret_code_t ble_bas_battery_level_update(ble_bas_t * p_bas,
+ uint8_t battery_level,
+ uint16_t conn_handle);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_BAS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bas_c/ble_bas_c.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bas_c/ble_bas_c.c
new file mode 100644
index 0000000..f9a494e
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bas_c/ble_bas_c.c
@@ -0,0 +1,405 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_BAS_C)
+#include "ble_bas_c.h"
+#include "ble_types.h"
+#include "ble_db_discovery.h"
+#include "ble_srv_common.h"
+#include "ble_gattc.h"
+#define NRF_LOG_MODULE_NAME ble_bas_c
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define TX_BUFFER_MASK 0x07 /**< TX Buffer mask, must be a mask of contiguous zeroes, followed by contiguous sequence of ones: 000...111. */
+#define TX_BUFFER_SIZE (TX_BUFFER_MASK + 1) /**< Size of the send buffer, which is 1 higher than the mask. */
+#define WRITE_MESSAGE_LENGTH BLE_CCCD_VALUE_LEN /**< Length of the write message for CCCD. */
+
+typedef enum
+{
+ READ_REQ, /**< Type identifying that this tx_message is a read request. */
+ WRITE_REQ /**< Type identifying that this tx_message is a write request. */
+} tx_request_t;
+
+/**@brief Structure for writing a message to the peer, i.e. CCCD.
+ */
+typedef struct
+{
+ uint8_t gattc_value[WRITE_MESSAGE_LENGTH]; /**< The message to write. */
+ ble_gattc_write_params_t gattc_params; /**< The GATTC parameters for this message. */
+} write_params_t;
+
+/**@brief Structure for holding the data that will be transmitted to the connected central.
+ */
+typedef struct
+{
+ uint16_t conn_handle; /**< Connection handle to be used when transmitting this message. */
+ tx_request_t type; /**< Type of message. (read or write). */
+ union
+ {
+ uint16_t read_handle; /**< Read request handle. */
+ write_params_t write_req; /**< Write request message. */
+ } req;
+} tx_message_t;
+
+
+static tx_message_t m_tx_buffer[TX_BUFFER_SIZE]; /**< Transmit buffer for the messages that will be transmitted to the central. */
+static uint32_t m_tx_insert_index = 0; /**< Current index in the transmit buffer where the next message should be inserted. */
+static uint32_t m_tx_index = 0; /**< Current index in the transmit buffer containing the next message to be transmitted. */
+
+/**@brief Function for passing any pending request from the buffer to the stack.
+ */
+static void tx_buffer_process(void)
+{
+ if (m_tx_index != m_tx_insert_index)
+ {
+ uint32_t err_code;
+
+ if (m_tx_buffer[m_tx_index].type == READ_REQ)
+ {
+ err_code = sd_ble_gattc_read(m_tx_buffer[m_tx_index].conn_handle,
+ m_tx_buffer[m_tx_index].req.read_handle,
+ 0);
+ }
+ else
+ {
+ err_code = sd_ble_gattc_write(m_tx_buffer[m_tx_index].conn_handle,
+ &m_tx_buffer[m_tx_index].req.write_req.gattc_params);
+ }
+ if (err_code == NRF_SUCCESS)
+ {
+ NRF_LOG_DEBUG("SD Read/Write API returns Success..");
+ m_tx_index++;
+ m_tx_index &= TX_BUFFER_MASK;
+ }
+ else
+ {
+ NRF_LOG_DEBUG("SD Read/Write API returns error. This message sending will be "
+ "attempted again..");
+ }
+ }
+}
+
+
+/**@brief Function for handling write response events.
+ *
+ * @param[in] p_bas_c Pointer to the Battery Service Client Structure.
+ * @param[in] p_ble_evt Pointer to the SoftDevice event.
+ */
+static void on_write_rsp(ble_bas_c_t * p_bas_c, ble_evt_t const * p_ble_evt)
+{
+ // Check if the event if on the link for this instance
+ if (p_bas_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
+ {
+ return;
+ }
+ // Check if there is any message to be sent across to the peer and send it.
+ tx_buffer_process();
+}
+
+
+/**@brief Function for handling read response events.
+ *
+ * @details This function will validate the read response and raise the appropriate
+ * event to the application.
+ *
+ * @param[in] p_bas_c Pointer to the Battery Service Client Structure.
+ * @param[in] p_ble_evt Pointer to the SoftDevice event.
+ */
+static void on_read_rsp(ble_bas_c_t * p_bas_c, ble_evt_t const * p_ble_evt)
+{
+ const ble_gattc_evt_read_rsp_t * p_response;
+
+ // Check if the event if on the link for this instance
+ if (p_bas_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
+ {
+ return;
+ }
+
+ p_response = &p_ble_evt->evt.gattc_evt.params.read_rsp;
+
+ if (p_response->handle == p_bas_c->peer_bas_db.bl_handle)
+ {
+ ble_bas_c_evt_t evt;
+
+ evt.conn_handle = p_ble_evt->evt.gattc_evt.conn_handle;
+ evt.evt_type = BLE_BAS_C_EVT_BATT_READ_RESP;
+
+ evt.params.battery_level = p_response->data[0];
+
+ p_bas_c->evt_handler(p_bas_c, &evt);
+ }
+ // Check if there is any buffered transmissions and send them.
+ tx_buffer_process();
+}
+
+
+/**@brief Function for handling Handle Value Notification received from the SoftDevice.
+ *
+ * @details This function will handle the Handle Value Notification received from the SoftDevice
+ * and checks if it is a notification of the Battery Level measurement from the peer. If
+ * so, this function will decode the battery level measurement and send it to the
+ * application.
+ *
+ * @param[in] p_ble_bas_c Pointer to the Battery Service Client structure.
+ * @param[in] p_ble_evt Pointer to the BLE event received.
+ */
+static void on_hvx(ble_bas_c_t * p_ble_bas_c, ble_evt_t const * p_ble_evt)
+{
+ // Check if the event if on the link for this instance
+ if (p_ble_bas_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
+ {
+ return;
+ }
+ // Check if this notification is a battery level notification.
+ if (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_bas_c->peer_bas_db.bl_handle)
+ {
+ if (p_ble_evt->evt.gattc_evt.params.hvx.len == 1)
+ {
+ ble_bas_c_evt_t ble_bas_c_evt;
+ ble_bas_c_evt.conn_handle = p_ble_evt->evt.gattc_evt.conn_handle;
+ ble_bas_c_evt.evt_type = BLE_BAS_C_EVT_BATT_NOTIFICATION;
+
+ ble_bas_c_evt.params.battery_level = p_ble_evt->evt.gattc_evt.params.hvx.data[0];
+
+ p_ble_bas_c->evt_handler(p_ble_bas_c, &ble_bas_c_evt);
+ }
+ }
+}
+
+
+void ble_bas_on_db_disc_evt(ble_bas_c_t * p_ble_bas_c, const ble_db_discovery_evt_t * p_evt)
+{
+ // Check if the Battery Service was discovered.
+ if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE
+ &&
+ p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_BATTERY_SERVICE
+ &&
+ p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE)
+ {
+ // Find the CCCD Handle of the Battery Level characteristic.
+ uint8_t i;
+
+ ble_bas_c_evt_t evt;
+ evt.evt_type = BLE_BAS_C_EVT_DISCOVERY_COMPLETE;
+ evt.conn_handle = p_evt->conn_handle;
+ for (i = 0; i < p_evt->params.discovered_db.char_count; i++)
+ {
+ if (p_evt->params.discovered_db.charateristics[i].characteristic.uuid.uuid ==
+ BLE_UUID_BATTERY_LEVEL_CHAR)
+ {
+ // Found Battery Level characteristic. Store CCCD handle and break.
+ evt.params.bas_db.bl_cccd_handle =
+ p_evt->params.discovered_db.charateristics[i].cccd_handle;
+ evt.params.bas_db.bl_handle =
+ p_evt->params.discovered_db.charateristics[i].characteristic.handle_value;
+ break;
+ }
+ }
+
+ NRF_LOG_DEBUG("Battery Service discovered at peer.");
+
+ //If the instance has been assigned prior to db_discovery, assign the db_handles
+ if (p_ble_bas_c->conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ if ((p_ble_bas_c->peer_bas_db.bl_cccd_handle == BLE_GATT_HANDLE_INVALID)&&
+ (p_ble_bas_c->peer_bas_db.bl_handle == BLE_GATT_HANDLE_INVALID))
+ {
+ p_ble_bas_c->peer_bas_db = evt.params.bas_db;
+ }
+ }
+ p_ble_bas_c->evt_handler(p_ble_bas_c, &evt);
+ }
+ else
+ {
+ NRF_LOG_DEBUG("Battery Service discovery failure at peer. ");
+ }
+}
+
+
+/**@brief Function for creating a message for writing to the CCCD.
+ */
+static uint32_t cccd_configure(uint16_t conn_handle, uint16_t handle_cccd, bool notification_enable)
+{
+ NRF_LOG_DEBUG("Configuring CCCD. CCCD Handle = %d, Connection Handle = %d",
+ handle_cccd,conn_handle);
+
+ tx_message_t * p_msg;
+ uint16_t cccd_val = notification_enable ? BLE_GATT_HVX_NOTIFICATION : 0;
+
+ p_msg = &m_tx_buffer[m_tx_insert_index++];
+ m_tx_insert_index &= TX_BUFFER_MASK;
+
+ p_msg->req.write_req.gattc_params.handle = handle_cccd;
+ p_msg->req.write_req.gattc_params.len = WRITE_MESSAGE_LENGTH;
+ p_msg->req.write_req.gattc_params.p_value = p_msg->req.write_req.gattc_value;
+ p_msg->req.write_req.gattc_params.offset = 0;
+ p_msg->req.write_req.gattc_params.write_op = BLE_GATT_OP_WRITE_REQ;
+ p_msg->req.write_req.gattc_value[0] = LSB_16(cccd_val);
+ p_msg->req.write_req.gattc_value[1] = MSB_16(cccd_val);
+ p_msg->conn_handle = conn_handle;
+ p_msg->type = WRITE_REQ;
+
+ tx_buffer_process();
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_bas_c_init(ble_bas_c_t * p_ble_bas_c, ble_bas_c_init_t * p_ble_bas_c_init)
+{
+ VERIFY_PARAM_NOT_NULL(p_ble_bas_c);
+ VERIFY_PARAM_NOT_NULL(p_ble_bas_c_init);
+
+ ble_uuid_t bas_uuid;
+
+ bas_uuid.type = BLE_UUID_TYPE_BLE;
+ bas_uuid.uuid = BLE_UUID_BATTERY_SERVICE;
+
+ p_ble_bas_c->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_ble_bas_c->peer_bas_db.bl_cccd_handle = BLE_GATT_HANDLE_INVALID;
+ p_ble_bas_c->peer_bas_db.bl_handle = BLE_GATT_HANDLE_INVALID;
+ p_ble_bas_c->evt_handler = p_ble_bas_c_init->evt_handler;
+
+ return ble_db_discovery_evt_register(&bas_uuid);
+}
+
+
+/**@brief Function for handling Disconnected event received from the SoftDevice.
+ *
+ * @details This function check if the disconnect event is happening on the link
+ * associated with the current instance of the module, if so it will set its
+ * conn_handle to invalid.
+ *
+ * @param[in] p_ble_bas_c Pointer to the Battery Service Client structure.
+ * @param[in] p_ble_evt Pointer to the BLE event received.
+ */
+static void on_disconnected(ble_bas_c_t * p_ble_bas_c, const ble_evt_t * p_ble_evt)
+{
+ if (p_ble_bas_c->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
+ {
+ p_ble_bas_c->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_ble_bas_c->peer_bas_db.bl_cccd_handle = BLE_GATT_HANDLE_INVALID;
+ p_ble_bas_c->peer_bas_db.bl_handle = BLE_GATT_HANDLE_INVALID;
+ }
+}
+
+
+void ble_bas_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ if ((p_ble_evt == NULL) || (p_context == NULL))
+ {
+ return;
+ }
+
+ ble_bas_c_t * p_ble_bas_c = (ble_bas_c_t *)p_context;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GATTC_EVT_HVX:
+ on_hvx(p_ble_bas_c, p_ble_evt);
+ break;
+
+ case BLE_GATTC_EVT_WRITE_RSP:
+ on_write_rsp(p_ble_bas_c, p_ble_evt);
+ break;
+
+ case BLE_GATTC_EVT_READ_RSP:
+ on_read_rsp(p_ble_bas_c, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnected(p_ble_bas_c, p_ble_evt);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+uint32_t ble_bas_c_bl_notif_enable(ble_bas_c_t * p_ble_bas_c)
+{
+ VERIFY_PARAM_NOT_NULL(p_ble_bas_c);
+
+ if (p_ble_bas_c->conn_handle == BLE_CONN_HANDLE_INVALID)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ return cccd_configure(p_ble_bas_c->conn_handle, p_ble_bas_c->peer_bas_db.bl_cccd_handle, true);
+}
+
+
+uint32_t ble_bas_c_bl_read(ble_bas_c_t * p_ble_bas_c)
+{
+ VERIFY_PARAM_NOT_NULL(p_ble_bas_c);
+ if (p_ble_bas_c->conn_handle == BLE_CONN_HANDLE_INVALID)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ tx_message_t * msg;
+
+ msg = &m_tx_buffer[m_tx_insert_index++];
+ m_tx_insert_index &= TX_BUFFER_MASK;
+
+ msg->req.read_handle = p_ble_bas_c->peer_bas_db.bl_handle;
+ msg->conn_handle = p_ble_bas_c->conn_handle;
+ msg->type = READ_REQ;
+
+ tx_buffer_process();
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_bas_c_handles_assign(ble_bas_c_t * p_ble_bas_c,
+ uint16_t conn_handle,
+ ble_bas_c_db_t * p_peer_handles)
+{
+ VERIFY_PARAM_NOT_NULL(p_ble_bas_c);
+
+ p_ble_bas_c->conn_handle = conn_handle;
+ if (p_peer_handles != NULL)
+ {
+ p_ble_bas_c->peer_bas_db = *p_peer_handles;
+ }
+ return NRF_SUCCESS;
+}
+#endif // NRF_MODULE_ENABLED(BLE_BAS_C)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bas_c/ble_bas_c.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bas_c/ble_bas_c.h
new file mode 100644
index 0000000..10eb126
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bas_c/ble_bas_c.h
@@ -0,0 +1,274 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/**@file
+ *
+ * @defgroup ble_bas_c Battery Service Client
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Battery Service Client module.
+ *
+ * @details This module contains APIs to read and interact with the Battery Service of a remote
+ * device.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_bas_c_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_BAS_C_BLE_OBSERVER_PRIO,
+ * ble_bas_c_on_ble_evt, &instance);
+ * @endcode
+ */
+
+#ifndef BLE_BAS_C_H__
+#define BLE_BAS_C_H__
+
+#include <stdint.h>
+#include "ble.h"
+#include "ble_db_discovery.h"
+#include "nrf_sdh_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_bas_c instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_BAS_C_DEF(_name) \
+static ble_bas_c_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_BAS_C_BLE_OBSERVER_PRIO, \
+ ble_bas_c_on_ble_evt, &_name)
+
+/** @brief Macro for defining multiple ble_bas_c instances.
+ *
+ * @param _name Name of the array of instances.
+ * @param _cnt Number of instances to define.
+ * @hideinitializer
+ */
+#define BLE_BAS_C_ARRAY_DEF(_name, _cnt) \
+static ble_bas_c_t _name[_cnt]; \
+NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
+ BLE_BAS_C_BLE_OBSERVER_PRIO, \
+ ble_bas_c_on_ble_evt, &_name, _cnt)
+
+/**
+ * @defgroup bas_c_enums Enumerations
+ * @{
+ */
+
+/**@brief Battery Service Client event type. */
+typedef enum
+{
+ BLE_BAS_C_EVT_DISCOVERY_COMPLETE, /**< Event indicating that the Battery Service has been discovered at the peer. */
+ BLE_BAS_C_EVT_BATT_NOTIFICATION, /**< Event indicating that a notification of the Battery Level characteristic has been received from the peer. */
+ BLE_BAS_C_EVT_BATT_READ_RESP /**< Event indicating that a read response on Battery Level characteristic has been received from peer. */
+} ble_bas_c_evt_type_t;
+
+/** @} */
+
+/**
+ * @defgroup bas_c_structs Structures
+ * @{
+ */
+
+/**@brief Structure containing the handles related to the Battery Service found on the peer. */
+typedef struct
+{
+ uint16_t bl_cccd_handle; /**< Handle of the CCCD of the Battery Level characteristic. */
+ uint16_t bl_handle; /**< Handle of the Battery Level characteristic as provided by the SoftDevice. */
+} ble_bas_c_db_t;
+
+/**@brief Battery Service Client Event structure. */
+typedef struct
+{
+ ble_bas_c_evt_type_t evt_type; /**< Event Type. */
+ uint16_t conn_handle; /**< Connection handle relevent to this event.*/
+ union
+ {
+ ble_bas_c_db_t bas_db; /**< Battery Service related handles found on the peer device. This will be filled if the evt_type is @ref BLE_BAS_C_EVT_DISCOVERY_COMPLETE.*/
+ uint8_t battery_level; /**< Battery level received from peer. This field will be used for the events @ref BLE_BAS_C_EVT_BATT_NOTIFICATION and @ref BLE_BAS_C_EVT_BATT_READ_RESP.*/
+ } params;
+} ble_bas_c_evt_t;
+
+/** @} */
+
+/**
+ * @defgroup bas_c_types Types
+ * @{
+ */
+
+// Forward declaration of the ble_bas_t type.
+typedef struct ble_bas_c_s ble_bas_c_t;
+
+/**@brief Event handler type.
+ *
+ * @details This is the type of the event handler that should be provided by the application
+ * of this module in order to receive events.
+ */
+typedef void (* ble_bas_c_evt_handler_t) (ble_bas_c_t * p_bas_bas_c, ble_bas_c_evt_t * p_evt);
+
+/** @} */
+
+/**
+ * @addtogroup bas_c_structs
+ * @{
+ */
+
+/**@brief Battery Service Client structure. */
+struct ble_bas_c_s
+{
+ uint16_t conn_handle; /**< Connection handle as provided by the SoftDevice. */
+ ble_bas_c_db_t peer_bas_db; /**< Handles related to BAS on the peer*/
+ ble_bas_c_evt_handler_t evt_handler; /**< Application event handler to be called when there is an event related to the Battery service. */
+};
+
+/**@brief Battery Service Client initialization structure. */
+typedef struct
+{
+ ble_bas_c_evt_handler_t evt_handler; /**< Event handler to be called by the Battery Service Client module whenever there is an event related to the Battery Service. */
+} ble_bas_c_init_t;
+
+/** @} */
+
+/**
+ * @defgroup bas_c_functions Functions
+ * @{
+ */
+
+/**@brief Function for initializing the Battery Service Client module.
+ *
+ * @details This function will initialize the module and set up Database Discovery to discover
+ * the Battery Service. After calling this function, call @ref ble_db_discovery_start
+ * to start discovery once a link with a peer has been established.
+ *
+ * @param[out] p_ble_bas_c Pointer to the Battery Service client structure.
+ * @param[in] p_ble_bas_c_init Pointer to the Battery Service initialization structure containing
+ * the initialization information.
+ *
+ * @retval NRF_SUCCESS Operation success.
+ * @retval NRF_ERROR_NULL A parameter is NULL.
+ * Otherwise, an error code returned by @ref ble_db_discovery_evt_register.
+ */
+uint32_t ble_bas_c_init(ble_bas_c_t * p_ble_bas_c, ble_bas_c_init_t * p_ble_bas_c_init);
+
+
+/**@brief Function for handling BLE events from the SoftDevice.
+ *
+ * @details This function will handle the BLE events received from the SoftDevice. If the BLE
+ * event is relevant for the Battery Service Client module, then it is used to update
+ * interval variables and, if necessary, send events to the application.
+ *
+ * @note This function must be called by the application.
+ *
+ * @param[in] p_ble_evt Pointer to the BLE event.
+ * @param[in] p_context Pointer to the Battery Service client structure.
+ */
+void ble_bas_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for enabling notifications on the Battery Level characteristic.
+ *
+ * @details This function will enable to notification of the Battery Level characteristic at the
+ * peer by writing to the CCCD of the Battery Level Characteristic.
+ *
+ * @param p_ble_bas_c Pointer to the Battery Service client structure.
+ *
+ * @retval NRF_SUCCESS If the SoftDevice has been requested to write to the CCCD of the peer.
+ * NRF_ERROR_NULL Parameter is NULL.
+ * Otherwise, an error code returned by the SoftDevice API @ref
+ * sd_ble_gattc_write.
+ */
+uint32_t ble_bas_c_bl_notif_enable(ble_bas_c_t * p_ble_bas_c);
+
+
+/**@brief Function for reading the Battery Level characteristic.
+ *
+ * @param p_ble_bas_c Pointer to the Battery Service client structure.
+ *
+ * @retval NRF_SUCCESS If the read request was successfully queued to be sent to peer.
+ */
+uint32_t ble_bas_c_bl_read(ble_bas_c_t * p_ble_bas_c);
+
+
+/**@brief Function for handling events from the database discovery module.
+ *
+ * @details Call this function when getting a callback event from the DB discovery modue.
+ * This function will handle an event from the database discovery module, and determine
+ * if it relates to the discovery of Battery service at the peer. If so, it will
+ * call the application's event handler indicating that the Battery service has been
+ * discovered at the peer. It also populates the event with the service related
+ * information before providing it to the application.
+ *
+ * @param p_ble_bas_c Pointer to the Battery Service client structure.
+ * @param[in] p_evt Pointer to the event received from the database discovery module.
+ *
+ */
+void ble_bas_on_db_disc_evt(ble_bas_c_t * p_ble_bas_c, ble_db_discovery_evt_t const * p_evt);
+
+
+/**@brief Function for assigning handles to a this instance of bas_c.
+ *
+ * @details Call this function when a link has been established with a peer to
+ * associate this link to this instance of the module. This makes it
+ * possible to handle several link and associate each link to a particular
+ * instance of this module. The connection handle and attribute handles will be
+ * provided from the discovery event @ref BLE_BAS_C_EVT_DISCOVERY_COMPLETE.
+ *
+ * @param[in] p_ble_bas_c Pointer to the Battery client structure instance to associate.
+ * @param[in] conn_handle Connection handle to associated with the given Battery Client Instance.
+ * @param[in] p_peer_handles Attribute handles on the BAS server you want this BAS client to
+ * interact with.
+ */
+uint32_t ble_bas_c_handles_assign(ble_bas_c_t * p_ble_bas_c,
+ uint16_t conn_handle,
+ ble_bas_c_db_t * p_peer_handles);
+
+/** @} */ // End tag for Function group.
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_BAS_C_H__
+
+/** @} */ // End tag for the file.
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bps/ble_bps.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bps/ble_bps.c
new file mode 100644
index 0000000..c96bad1
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bps/ble_bps.c
@@ -0,0 +1,475 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Attention!
+ * To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_BPS)
+#include "ble_bps.h"
+#include "ble_err.h"
+#include <string.h>
+#include "nordic_common.h"
+#include "ble_srv_common.h"
+
+
+#define OPCODE_LENGTH 1 /**< Length of opcode inside Blood Pressure Measurement packet. */
+#define HANDLE_LENGTH 2 /**< Length of handle inside Blood Pressure Measurement packet. */
+#define MAX_BPM_LEN (BLE_GATT_ATT_MTU_DEFAULT - OPCODE_LENGTH - HANDLE_LENGTH) /**< Maximum size of a transmitted Blood Pressure Measurement. */
+
+// Blood Pressure Measurement Flags bits
+#define BPS_MEAS_BLOOD_PRESSURE_UNITS_FLAG_BIT (0x01 << 0) /**< Blood Pressure Units Flag bit. */
+#define BPS_MEAS_TIME_STAMP_FLAG_BIT (0x01 << 1) /**< Time Stamp Flag bit. */
+#define BPS_MEAS_PULSE_RATE_FLAG_BIT (0x01 << 2) /**< Pulse Rate Flag bit. */
+#define BPS_MEAS_USER_ID_FLAG_BIT (0x01 << 3) /**< User ID Flag bit. */
+#define BPS_MEAS_MEASUREMENT_STATUS_FLAG_BIT (0x01 << 4) /**< Measurement Status Flag bit. */
+
+
+/**@brief Function for handling the Connect event.
+ *
+ * @param[in] p_bps Blood Pressure Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_connect(ble_bps_t * p_bps, ble_evt_t const * p_ble_evt)
+{
+ p_bps->conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
+}
+
+
+/**@brief Function for handling the Disconnect event.
+ *
+ * @param[in] p_bps Blood Pressure Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_disconnect(ble_bps_t * p_bps, ble_evt_t const * p_ble_evt)
+{
+ UNUSED_PARAMETER(p_ble_evt);
+ p_bps->conn_handle = BLE_CONN_HANDLE_INVALID;
+}
+
+
+/**@brief Function for handling the write events to the Blood Pressure Measurement characteristic.
+ *
+ * @param[in] p_bps Blood Pressure Service structure.
+ * @param[in] p_evt_write Write event received from the BLE stack.
+ */
+static void on_cccd_write(ble_bps_t * p_bps, ble_gatts_evt_write_t const * p_evt_write)
+{
+ if (p_evt_write->len == 2)
+ {
+ // CCCD written, update indication state
+ if (p_bps->evt_handler != NULL)
+ {
+ ble_bps_evt_t evt;
+
+ if (ble_srv_is_indication_enabled(p_evt_write->data))
+ {
+ evt.evt_type = BLE_BPS_EVT_INDICATION_ENABLED;
+ }
+ else
+ {
+ evt.evt_type = BLE_BPS_EVT_INDICATION_DISABLED;
+ }
+
+ p_bps->evt_handler(p_bps, &evt);
+ }
+ }
+}
+
+
+/**@brief Function for handling the Write event.
+ *
+ * @param[in] p_bps Blood Pressure Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_write(ble_bps_t * p_bps, ble_evt_t const * p_ble_evt)
+{
+ ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+ if (p_evt_write->handle == p_bps->meas_handles.cccd_handle)
+ {
+ on_cccd_write(p_bps, p_evt_write);
+ }
+}
+
+
+/**@brief Function for handling the HVC event.
+ *
+ * @details Handles HVC events from the BLE stack.
+ *
+ * @param[in] p_bps Blood Pressure Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_hvc(ble_bps_t * p_bps, ble_evt_t const * p_ble_evt)
+{
+ ble_gatts_evt_hvc_t const * p_hvc = &p_ble_evt->evt.gatts_evt.params.hvc;
+
+ if (p_hvc->handle == p_bps->meas_handles.value_handle)
+ {
+ ble_bps_evt_t evt;
+
+ evt.evt_type = BLE_BPS_EVT_INDICATION_CONFIRMED;
+ p_bps->evt_handler(p_bps, &evt);
+ }
+}
+
+
+void ble_bps_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ ble_bps_t * p_bps = (ble_bps_t *)p_context;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ on_connect(p_bps, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnect(p_bps, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_WRITE:
+ on_write(p_bps, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_HVC:
+ on_hvc(p_bps, p_ble_evt);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+
+/**@brief Function for encoding a Blood Pressure Measurement.
+ *
+ * @param[in] p_bps Blood Pressure Service structure.
+ * @param[in] p_bps_meas Measurement to be encoded.
+ * @param[out] p_encoded_buffer Buffer where the encoded data will be written.
+ *
+ * @return Size of encoded data.
+ */
+static uint8_t bps_measurement_encode(ble_bps_t * p_bps,
+ ble_bps_meas_t * p_bps_meas,
+ uint8_t * p_encoded_buffer)
+{
+ uint8_t flags = 0;
+ uint8_t len = 1;
+ uint16_t encoded_sfloat;
+
+ // Set measurement units flag
+ if (p_bps_meas->blood_pressure_units_in_kpa)
+ {
+ flags |= BPS_MEAS_BLOOD_PRESSURE_UNITS_FLAG_BIT;
+ }
+
+ // Blood Pressure Measurement - Systolic
+ encoded_sfloat = ((p_bps_meas->blood_pressure_systolic.exponent << 12) & 0xF000) |
+ ((p_bps_meas->blood_pressure_systolic.mantissa << 0) & 0x0FFF);
+ len += uint16_encode(encoded_sfloat, &p_encoded_buffer[len]);
+
+ // Blood Pressure Measurement - Diastolic
+ encoded_sfloat = ((p_bps_meas->blood_pressure_diastolic.exponent << 12) & 0xF000) |
+ ((p_bps_meas->blood_pressure_diastolic.mantissa << 0) & 0x0FFF);
+ len += uint16_encode(encoded_sfloat, &p_encoded_buffer[len]);
+
+ // Blood Pressure Measurement - Mean Arterial Pressure
+ encoded_sfloat = ((p_bps_meas->mean_arterial_pressure.exponent << 12) & 0xF000) |
+ ((p_bps_meas->mean_arterial_pressure.mantissa << 0) & 0x0FFF);
+ len += uint16_encode(encoded_sfloat, &p_encoded_buffer[len]);
+
+ // Time Stamp field
+ if (p_bps_meas->time_stamp_present)
+ {
+ flags |= BPS_MEAS_TIME_STAMP_FLAG_BIT;
+ len += ble_date_time_encode(&p_bps_meas->time_stamp, &p_encoded_buffer[len]);
+ }
+
+ // Pulse Rate
+ if (p_bps_meas->pulse_rate_present)
+ {
+ flags |= BPS_MEAS_PULSE_RATE_FLAG_BIT;
+
+ encoded_sfloat = ((p_bps_meas->pulse_rate.exponent << 12) & 0xF000) |
+ ((p_bps_meas->pulse_rate.mantissa << 0) & 0x0FFF);
+ len += uint16_encode(encoded_sfloat, &p_encoded_buffer[len]);
+ }
+
+ // User ID
+ if (p_bps_meas->user_id_present)
+ {
+ flags |= BPS_MEAS_USER_ID_FLAG_BIT;
+ p_encoded_buffer[len++] = p_bps_meas->user_id;
+ }
+
+ // Measurement Status
+ if (p_bps_meas->measurement_status_present)
+ {
+ flags |= BPS_MEAS_MEASUREMENT_STATUS_FLAG_BIT;
+ len += uint16_encode(p_bps_meas->measurement_status, &p_encoded_buffer[len]);
+ }
+
+ // Flags field
+ p_encoded_buffer[0] = flags;
+
+ return len;
+}
+
+
+/**@brief Function for adding Blood Pressure Measurement characteristics.
+ *
+ * @param[in] p_bps Blood Pressure Service structure.
+ * @param[in] p_bps_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t bps_measurement_char_add(ble_bps_t * p_bps, ble_bps_init_t const * p_bps_init)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_md_t cccd_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+ ble_bps_meas_t initial_bpm;
+ uint8_t encoded_bpm[MAX_BPM_LEN];
+
+ memset(&cccd_md, 0, sizeof(cccd_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
+ cccd_md.vloc = BLE_GATTS_VLOC_STACK;
+ cccd_md.write_perm = p_bps_init->bps_meas_attr_md.cccd_write_perm;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.indicate = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = &cccd_md;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_BLOOD_PRESSURE_MEASUREMENT_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.read_perm = p_bps_init->bps_meas_attr_md.read_perm;
+ attr_md.write_perm = p_bps_init->bps_meas_attr_md.write_perm;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 1;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+ memset(&initial_bpm, 0, sizeof(initial_bpm));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = bps_measurement_encode(p_bps, &initial_bpm, encoded_bpm);
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = MAX_BPM_LEN;
+ attr_char_value.p_value = encoded_bpm;
+
+ return sd_ble_gatts_characteristic_add(p_bps->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_bps->meas_handles);
+}
+
+
+/**@brief Function for adding Blood Pressure Feature characteristics.
+ *
+ * @param[in] p_bps Blood Pressure Service structure.
+ * @param[in] p_bps_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t bps_feature_char_add(ble_bps_t * p_bps, ble_bps_init_t const * p_bps_init)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+ uint8_t init_value_encoded[2];
+ uint8_t init_value_len;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = NULL;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_BLOOD_PRESSURE_FEATURE_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.read_perm = p_bps_init->bps_feature_attr_md.read_perm;
+ attr_md.write_perm = p_bps_init->bps_feature_attr_md.write_perm;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ init_value_len = uint16_encode(p_bps_init->feature, init_value_encoded);
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = init_value_len;
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = init_value_len;
+ attr_char_value.p_value = init_value_encoded;
+
+ return sd_ble_gatts_characteristic_add(p_bps->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_bps->feature_handles);
+}
+
+
+uint32_t ble_bps_init(ble_bps_t * p_bps, ble_bps_init_t const * p_bps_init)
+{
+ uint32_t err_code;
+ ble_uuid_t ble_uuid;
+
+ // Initialize service structure
+ p_bps->evt_handler = p_bps_init->evt_handler;
+ p_bps->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_bps->feature = p_bps_init->feature;
+
+ // Add service
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_BLOOD_PRESSURE_SERVICE);
+
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_bps->service_handle);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add measurement characteristic
+ err_code = bps_measurement_char_add(p_bps, p_bps_init);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add feature characteristic
+ err_code = bps_feature_char_add(p_bps, p_bps_init);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_bps_measurement_send(ble_bps_t * p_bps, ble_bps_meas_t * p_bps_meas)
+{
+ uint32_t err_code;
+
+ // Send value if connected
+ if (p_bps->conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ uint8_t encoded_bps_meas[MAX_BPM_LEN];
+ uint16_t len;
+ uint16_t hvx_len;
+ ble_gatts_hvx_params_t hvx_params;
+
+ len = bps_measurement_encode(p_bps, p_bps_meas, encoded_bps_meas);
+ hvx_len = len;
+
+ memset(&hvx_params, 0, sizeof(hvx_params));
+
+ hvx_params.handle = p_bps->meas_handles.value_handle;
+ hvx_params.type = BLE_GATT_HVX_INDICATION;
+ hvx_params.offset = 0;
+ hvx_params.p_len = &hvx_len;
+ hvx_params.p_data = encoded_bps_meas;
+
+ err_code = sd_ble_gatts_hvx(p_bps->conn_handle, &hvx_params);
+ if ((err_code == NRF_SUCCESS) && (hvx_len != len))
+ {
+ err_code = NRF_ERROR_DATA_SIZE;
+ }
+ }
+ else
+ {
+ err_code = NRF_ERROR_INVALID_STATE;
+ }
+
+ return err_code;
+}
+
+
+uint32_t ble_bps_is_indication_enabled(ble_bps_t * p_bps, bool * p_indication_enabled)
+{
+ uint32_t err_code;
+ uint8_t cccd_value_buf[BLE_CCCD_VALUE_LEN];
+ ble_gatts_value_t gatts_value;
+
+ // Initialize value struct.
+ memset(&gatts_value, 0, sizeof(gatts_value));
+
+ gatts_value.len = BLE_CCCD_VALUE_LEN;
+ gatts_value.offset = 0;
+ gatts_value.p_value = cccd_value_buf;
+
+ err_code = sd_ble_gatts_value_get(p_bps->conn_handle,
+ p_bps->meas_handles.cccd_handle,
+ &gatts_value);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ *p_indication_enabled = ble_srv_is_indication_enabled(cccd_value_buf);
+ }
+ if (err_code == BLE_ERROR_GATTS_SYS_ATTR_MISSING)
+ {
+ *p_indication_enabled = false;
+ return NRF_SUCCESS;
+ }
+ return err_code;
+}
+#endif // NRF_MODULE_ENABLED(BLE_BPS)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bps/ble_bps.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bps/ble_bps.h
new file mode 100644
index 0000000..b0cb4ad
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_bps/ble_bps.h
@@ -0,0 +1,221 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_bps Blood Pressure Service
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Blood Pressure Service module.
+ *
+ * @details This module implements the Blood Pressure Service.
+ *
+ * If an event handler is supplied by the application, the Blood Pressure
+ * Service will generate Blood Pressure Service events to the application.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_bps_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_BPS_BLE_OBSERVER_PRIO,
+ * ble_bps_on_ble_evt, &instance);
+ * @endcode
+ *
+ * @note Attention!
+ * To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+
+#ifndef BLE_BPS_H__
+#define BLE_BPS_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "ble_date_time.h"
+#include "nrf_sdh_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_bps instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_BPS_DEF(_name) \
+static ble_bps_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_BPS_BLE_OBSERVER_PRIO, \
+ ble_bps_on_ble_evt, &_name)
+
+
+// Blood Pressure Feature bits
+#define BLE_BPS_FEATURE_BODY_MOVEMENT_BIT (0x01 << 0) /**< Body Movement Detection Support bit. */
+#define BLE_BPS_FEATURE_CUFF_FIT_BIT (0x01 << 1) /**< Cuff Fit Detection Support bit. */
+#define BLE_BPS_FEATURE_IRREGULAR_PULSE_BIT (0x01 << 2) /**< Irregular Pulse Detection Support bit. */
+#define BLE_BPS_FEATURE_PULSE_RATE_RANGE_BIT (0x01 << 3) /**< Pulse Rate Range Detection Support bit. */
+#define BLE_BPS_FEATURE_MEASUREMENT_POSITION_BIT (0x01 << 4) /**< Measurement Position Detection Support bit. */
+#define BLE_BPS_FEATURE_MULTIPLE_BOND_BIT (0x01 << 5) /**< Multiple Bond Support bit. */
+
+
+/**@brief Blood Pressure Service event type. */
+typedef enum
+{
+ BLE_BPS_EVT_INDICATION_ENABLED, /**< Blood Pressure value indication enabled event. */
+ BLE_BPS_EVT_INDICATION_DISABLED, /**< Blood Pressure value indication disabled event. */
+ BLE_BPS_EVT_INDICATION_CONFIRMED /**< Confirmation of a blood pressure measurement indication has been received. */
+} ble_bps_evt_type_t;
+
+/**@brief Blood Pressure Service event. */
+typedef struct
+{
+ ble_bps_evt_type_t evt_type; /**< Type of event. */
+} ble_bps_evt_t;
+
+// Forward declaration of the ble_bps_t type.
+typedef struct ble_bps_s ble_bps_t;
+
+/**@brief Blood Pressure Service event handler type. */
+typedef void (*ble_bps_evt_handler_t) (ble_bps_t * p_bps, ble_bps_evt_t * p_evt);
+
+/**@brief SFLOAT format (IEEE-11073 16-bit FLOAT, defined as a 16-bit vlue with 12-bit mantissa and
+ * 4-bit exponent. */
+typedef struct
+{
+ int8_t exponent; /**< Base 10 exponent, only 4 bits */
+ int16_t mantissa; /**< Mantissa, only 12 bits */
+} ieee_float16_t;
+
+/**@brief Blood Pressure Service init structure. This contains all options and data
+ * needed for initialization of the service. */
+typedef struct
+{
+ ble_bps_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Blood Pressure Service. */
+ ble_srv_cccd_security_mode_t bps_meas_attr_md; /**< Initial security level for blood pressure measurement attribute */
+ ble_srv_security_mode_t bps_feature_attr_md; /**< Initial security level for blood pressure feature attribute */
+ uint16_t feature; /**< Initial value for blood pressure feature */
+} ble_bps_init_t;
+
+/**@brief Blood Pressure Service structure. This contains various status information for
+ * the service. */
+struct ble_bps_s
+{
+ ble_bps_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Blood Pressure Service. */
+ uint16_t service_handle; /**< Handle of Blood Pressure Service (as provided by the BLE stack). */
+ ble_gatts_char_handles_t meas_handles; /**< Handles related to the Blood Pressure Measurement characteristic. */
+ ble_gatts_char_handles_t feature_handles; /**< Handles related to the Blood Pressure Feature characteristic. */
+ uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
+ uint16_t feature; /**< Value of Blood Pressure feature. */
+};
+
+/**@brief Blood Pressure Service measurement structure. This contains a Blood Pressure
+ * measurement. */
+typedef struct ble_bps_meas_s
+{
+ bool blood_pressure_units_in_kpa; /**< Blood Pressure Units Flag, 0=mmHg, 1=kPa */
+ bool time_stamp_present; /**< Time Stamp Flag, 0=not present, 1=present. */
+ bool pulse_rate_present; /**< Pulse Rate Flag, 0=not present, 1=present. */
+ bool user_id_present; /**< User ID Flag, 0=not present, 1=present. */
+ bool measurement_status_present; /**< Measurement Status Flag, 0=not present, 1=present. */
+ ieee_float16_t blood_pressure_systolic; /**< Blood Pressure Measurement Compound Value - Systolic. */
+ ieee_float16_t blood_pressure_diastolic; /**< Blood Pressure Measurement Compound Value - Diastolic . */
+ ieee_float16_t mean_arterial_pressure; /**< Blood Pressure Measurement Compound Value - Mean Arterial Pressure. */
+ ble_date_time_t time_stamp; /**< Time Stamp. */
+ ieee_float16_t pulse_rate; /**< Pulse Rate. */
+ uint8_t user_id; /**< User ID. */
+ uint16_t measurement_status; /**< Measurement Status. */
+} ble_bps_meas_t;
+
+
+/**@brief Function for initializing the Blood Pressure Service.
+ *
+ * @param[out] p_bps Blood Pressure Service structure. This structure will have to
+ * be supplied by the application. It will be initialized by this function,
+ * and will later be used to identify this particular service instance.
+ * @param[in] p_bps_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
+ */
+uint32_t ble_bps_init(ble_bps_t * p_bps, ble_bps_init_t const * p_bps_init);
+
+
+/**@brief Function for handling the Application's BLE Stack events.
+ *
+ * @details Handles all events from the BLE stack of interest to the Blood Pressure Service.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Blood Pressure Service structure.
+ */
+void ble_bps_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for sending blood pressure measurement if indication has been enabled.
+ *
+ * @details The application calls this function after having performed a Blood Pressure
+ * measurement. If indication has been enabled, the measurement data is encoded and
+ * sent to the client.
+ *
+ * @param[in] p_bps Blood Pressure Service structure.
+ * @param[in] p_bps_meas Pointer to new blood pressure measurement.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+uint32_t ble_bps_measurement_send(ble_bps_t * p_bps, ble_bps_meas_t * p_bps_meas);
+
+
+/**@brief Function for checking if indication of Blood Pressure Measurement is currently enabled.
+ *
+ * @param[in] p_bps Blood Pressure Service structure.
+ * @param[out] p_indication_enabled TRUE if indication is enabled, FALSE otherwise.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+uint32_t ble_bps_is_indication_enabled(ble_bps_t * p_bps, bool * p_indication_enabled);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_BPS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cscs/ble_cscs.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cscs/ble_cscs.c
new file mode 100644
index 0000000..6e45d0f
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cscs/ble_cscs.c
@@ -0,0 +1,489 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Attention!
+ * To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+
+#include "ble_cscs.h"
+#include <string.h>
+#include "nordic_common.h"
+#include "ble.h"
+#include "ble_err.h"
+#include "ble_srv_common.h"
+#include "app_util.h"
+
+#define OPCODE_LENGTH 1 /**< Length of opcode inside Cycling Speed and Cadence Measurement packet. */
+#define HANDLE_LENGTH 2 /**< Length of handle inside Cycling Speed and Cadence Measurement packet. */
+#define MAX_CSCM_LEN (BLE_GATT_ATT_MTU_DEFAULT - OPCODE_LENGTH - HANDLE_LENGTH) /**< Maximum size of a transmitted Cycling Speed and Cadence Measurement. */
+
+// Cycling Speed and Cadence Measurement flag bits
+#define CSC_MEAS_FLAG_MASK_WHEEL_REV_DATA_PRESENT (0x01 << 0) /**< Wheel revolution data present flag bit. */
+#define CSC_MEAS_FLAG_MASK_CRANK_REV_DATA_PRESENT (0x01 << 1) /**< Crank revolution data present flag bit. */
+
+
+/**@brief Function for handling the Connect event.
+ *
+ * @param[in] p_cscs Cycling Speed and Cadence Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_connect(ble_cscs_t * p_cscs, ble_evt_t const * p_ble_evt)
+{
+ p_cscs->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+}
+
+
+/**@brief Function for handling the Disconnect event.
+ *
+ * @param[in] p_cscs Cycling Speed and Cadence Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_disconnect(ble_cscs_t * p_cscs, ble_evt_t const * p_ble_evt)
+{
+ UNUSED_PARAMETER(p_ble_evt);
+ p_cscs->conn_handle = BLE_CONN_HANDLE_INVALID;
+}
+
+
+/**@brief Function for handling write events to the CSCS Measurement characteristic.
+ *
+ * @param[in] p_cscs Cycling Speed and Cadence Service structure.
+ * @param[in] p_evt_write Write event received from the BLE stack.
+ */
+static void on_meas_cccd_write(ble_cscs_t * p_cscs, ble_gatts_evt_write_t const * p_evt_write)
+{
+ if (p_evt_write->len == 2)
+ {
+ // CCCD written, update notification state
+ if (p_cscs->evt_handler != NULL)
+ {
+ ble_cscs_evt_t evt;
+
+ if (ble_srv_is_notification_enabled(p_evt_write->data))
+ {
+ evt.evt_type = BLE_CSCS_EVT_NOTIFICATION_ENABLED;
+ }
+ else
+ {
+ evt.evt_type = BLE_CSCS_EVT_NOTIFICATION_DISABLED;
+ }
+
+ p_cscs->evt_handler(p_cscs, &evt);
+ }
+ }
+}
+
+
+/**@brief Function for handling the Write event.
+ *
+ * @param[in] p_cscs Cycling Speed and Cadence Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_write(ble_cscs_t * p_cscs, ble_evt_t const * p_ble_evt)
+{
+ ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+ if (p_evt_write->handle == p_cscs->meas_handles.cccd_handle)
+ {
+ on_meas_cccd_write(p_cscs, p_evt_write);
+ }
+}
+
+
+void ble_cscs_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ ble_cscs_t * p_cscs = (ble_cscs_t *)p_context;
+
+ if (p_cscs == NULL || p_ble_evt == NULL)
+ {
+ return;
+ }
+
+
+ ble_sc_ctrlpt_on_ble_evt(&(p_cscs->ctrl_pt), p_ble_evt);
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ on_connect(p_cscs, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnect(p_cscs, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_WRITE:
+ on_write(p_cscs, p_ble_evt);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+
+/**@brief Function for encoding a CSCS Measurement.
+ *
+ * @param[in] p_cscs Cycling Speed and Cadence Service structure.
+ * @param[in] p_csc_measurement Measurement to be encoded.
+ * @param[out] p_encoded_buffer Buffer where the encoded data will be written.
+ *
+ * @return Size of encoded data.
+ */
+static uint8_t csc_measurement_encode(ble_cscs_t * p_cscs,
+ ble_cscs_meas_t * p_csc_measurement,
+ uint8_t * p_encoded_buffer)
+{
+ uint8_t flags = 0;
+ uint8_t len = 1;
+
+ // Cumulative Wheel Revolutions and Last Wheel Event Time Fields
+ if (p_cscs->feature & BLE_CSCS_FEATURE_WHEEL_REV_BIT)
+ {
+ if (p_csc_measurement->is_wheel_rev_data_present)
+ {
+ flags |= CSC_MEAS_FLAG_MASK_WHEEL_REV_DATA_PRESENT;
+ len += uint32_encode(p_csc_measurement->cumulative_wheel_revs, &p_encoded_buffer[len]);
+ len += uint16_encode(p_csc_measurement->last_wheel_event_time, &p_encoded_buffer[len]);
+ }
+ }
+
+ // Cumulative Crank Revolutions and Last Crank Event Time Fields
+ if (p_cscs->feature & BLE_CSCS_FEATURE_CRANK_REV_BIT)
+ {
+ if (p_csc_measurement->is_crank_rev_data_present)
+ {
+ flags |= CSC_MEAS_FLAG_MASK_CRANK_REV_DATA_PRESENT;
+ len += uint16_encode(p_csc_measurement->cumulative_crank_revs, &p_encoded_buffer[len]);
+ len += uint16_encode(p_csc_measurement->last_crank_event_time, &p_encoded_buffer[len]);
+ }
+ }
+
+ // Flags Field
+ p_encoded_buffer[0] = flags;
+
+ return len;
+}
+
+
+/**@brief Function for adding CSC Measurement characteristics.
+ *
+ * @param[in] p_cscs Cycling Speed and Cadence Service structure.
+ * @param[in] p_cscs_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t csc_measurement_char_add(ble_cscs_t * p_cscs, ble_cscs_init_t const * p_cscs_init)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_md_t cccd_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+ ble_cscs_meas_t initial_scm = {0};
+ uint8_t encoded_scm[MAX_CSCM_LEN];
+ memset(&cccd_md, 0, sizeof(cccd_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
+ cccd_md.write_perm = p_cscs_init->csc_meas_attr_md.cccd_write_perm;
+ cccd_md.vloc = BLE_GATTS_VLOC_STACK;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.notify = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = &cccd_md;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_CSC_MEASUREMENT_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm );
+
+ BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 1;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = csc_measurement_encode(p_cscs, &initial_scm, encoded_scm);
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = MAX_CSCM_LEN;
+ attr_char_value.p_value = encoded_scm;
+
+ return sd_ble_gatts_characteristic_add(p_cscs->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_cscs->meas_handles);
+}
+
+
+/**@brief Function for adding CSC Feature characteristics.
+ *
+ * @param[in] p_cscs Cycling Speed and Cadence Service structure.
+ * @param[in] p_cscs_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t csc_feature_char_add(ble_cscs_t * p_cscs, ble_cscs_init_t const * p_cscs_init)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+ uint8_t init_value_encoded[2];
+ uint8_t init_value_len;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = NULL;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_CSC_FEATURE_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.read_perm = p_cscs_init->csc_feature_attr_md.read_perm;
+
+ BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ init_value_len = uint16_encode(p_cscs_init->feature, &init_value_encoded[0]);
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = init_value_len;
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = init_value_len;
+ attr_char_value.p_value = init_value_encoded;
+
+ return sd_ble_gatts_characteristic_add(p_cscs->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_cscs->feature_handles);
+}
+
+
+/**@brief Function for adding CSC Sensor Location characteristic.
+ *
+ * @param[in] p_cscs Cycling Speed and Cadence Service structure.
+ * @param[in] p_cscs_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t csc_sensor_loc_char_add(ble_cscs_t * p_cscs, ble_cscs_init_t const * p_cscs_init)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+ uint8_t init_value_len;
+ uint8_t encoded_init_value[1];
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = NULL;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_SENSOR_LOCATION_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.read_perm = p_cscs_init->csc_sensor_loc_attr_md.read_perm;
+ BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ init_value_len = sizeof(uint8_t);
+ if (p_cscs_init->sensor_location != NULL)
+ {
+ encoded_init_value[0] = *p_cscs_init->sensor_location;
+ }
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = init_value_len;
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = init_value_len;
+ attr_char_value.p_value = encoded_init_value;
+
+ return sd_ble_gatts_characteristic_add(p_cscs->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_cscs->sensor_loc_handles);
+}
+
+
+uint32_t ble_cscs_init(ble_cscs_t * p_cscs, ble_cscs_init_t const * p_cscs_init)
+{
+ if (p_cscs == NULL || p_cscs_init == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ uint32_t err_code;
+ ble_uuid_t ble_uuid;
+ ble_cs_ctrlpt_init_t sc_ctrlpt_init;
+
+ // Initialize service structure
+ p_cscs->evt_handler = p_cscs_init->evt_handler;
+ p_cscs->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_cscs->feature = p_cscs_init->feature;
+
+ // Add service
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_CYCLING_SPEED_AND_CADENCE);
+
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
+ &ble_uuid,
+ &p_cscs->service_handle);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add cycling speed and cadence measurement characteristic
+ err_code = csc_measurement_char_add(p_cscs, p_cscs_init);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add cycling speed and cadence feature characteristic
+ err_code = csc_feature_char_add(p_cscs, p_cscs_init);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add Sensor Location characteristic (optional)
+ if (p_cscs_init->sensor_location != NULL)
+ {
+ err_code = csc_sensor_loc_char_add(p_cscs, p_cscs_init);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+
+ // Add speed and cadence control point characteristic
+ sc_ctrlpt_init.error_handler = p_cscs_init->error_handler;
+ sc_ctrlpt_init.size_list_supported_locations = p_cscs_init->size_list_supported_locations;
+ sc_ctrlpt_init.supported_functions = p_cscs_init->ctrplt_supported_functions;
+ sc_ctrlpt_init.evt_handler = p_cscs_init->ctrlpt_evt_handler;
+ sc_ctrlpt_init.list_supported_locations = p_cscs_init->list_supported_locations;
+ sc_ctrlpt_init.sc_ctrlpt_attr_md = p_cscs_init->csc_ctrlpt_attr_md;
+ sc_ctrlpt_init.sensor_location_handle = p_cscs->sensor_loc_handles.value_handle;
+ sc_ctrlpt_init.service_handle = p_cscs->service_handle;
+
+ return ble_sc_ctrlpt_init(&p_cscs->ctrl_pt, &sc_ctrlpt_init);
+}
+
+
+uint32_t ble_cscs_measurement_send(ble_cscs_t * p_cscs, ble_cscs_meas_t * p_measurement)
+{
+ if (p_cscs == NULL || p_measurement == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ uint32_t err_code;
+
+ // Send value if connected and notifying
+ if (p_cscs->conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ uint8_t encoded_csc_meas[MAX_CSCM_LEN];
+ uint16_t len;
+ uint16_t hvx_len;
+ ble_gatts_hvx_params_t hvx_params;
+
+ len = csc_measurement_encode(p_cscs, p_measurement, encoded_csc_meas);
+ hvx_len = len;
+
+ memset(&hvx_params, 0, sizeof(hvx_params));
+
+ hvx_params.handle = p_cscs->meas_handles.value_handle;
+ hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
+ hvx_params.offset = 0;
+ hvx_params.p_len = &hvx_len;
+ hvx_params.p_data = encoded_csc_meas;
+
+ err_code = sd_ble_gatts_hvx(p_cscs->conn_handle, &hvx_params);
+ if ((err_code == NRF_SUCCESS) && (hvx_len != len))
+ {
+ err_code = NRF_ERROR_DATA_SIZE;
+ }
+ }
+ else
+ {
+ err_code = NRF_ERROR_INVALID_STATE;
+ }
+
+ return err_code;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cscs/ble_cscs.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cscs/ble_cscs.h
new file mode 100644
index 0000000..c62d09c
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cscs/ble_cscs.h
@@ -0,0 +1,218 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_cscs Cycling Speed and Cadence Service
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Cycling Speed and Cadence Service module.
+ *
+ * @details This module implements the Cycling Speed and Cadence Service. If enabled, notification
+ * of the Cycling Speead and Candence Measurement is performed when the application
+ * calls ble_cscs_measurement_send().
+ *
+ * To use this service, you need to provide the the supported features (@ref BLE_CSCS_FEATURES).
+ * If you choose to support Wheel revolution data (feature bit @ref BLE_CSCS_FEATURE_WHEEL_REV_BIT),
+ * you then need to support the 'setting of cumulative value' operation by the supporting the
+ * Speed and Cadence Control Point (@ref ble_sdk_srv_sc_ctrlpt) by setting the @ref BLE_SRV_SC_CTRLPT_CUM_VAL_OP_SUPPORTED
+ * bit of the ctrplt_supported_functions in the @ref ble_cscs_init_t structure.
+ * If you want to support the 'start autocalibration' control point feature, you need, after the @ref BLE_SC_CTRLPT_EVT_START_CALIBRATION
+ * has been received and the auto calibration is finished, to call the @ref ble_sc_ctrlpt_rsp_send to indicate that the operation is finished
+ * and thus be able to receive new control point operations.
+ * If you want to support the 'sensor location' related operation, you need to provide a list of supported location in the
+ * @ref ble_cscs_init_t structure.
+ *
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_cscs_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_CSCS_BLE_OBSERVER_PRIO,
+ * ble_cscs_on_ble_evt, &instance);
+ * @endcode
+ *
+ * @note Attention!
+ * To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+
+#ifndef BLE_CSCS_H__
+#define BLE_CSCS_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "ble_sc_ctrlpt.h"
+#include "ble_sensor_location.h"
+#include "nrf_sdh_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_cscs instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_CSCS_DEF(_name) \
+static ble_cscs_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_CSCS_BLE_OBSERVER_PRIO, \
+ ble_cscs_on_ble_evt, &_name)
+
+
+/** @defgroup BLE_CSCS_FEATURES Cycling Speed and Cadence Service feature bits
+ * @{ */
+#define BLE_CSCS_FEATURE_WHEEL_REV_BIT (0x01 << 0) /**< Wheel Revolution Data Supported bit. */
+#define BLE_CSCS_FEATURE_CRANK_REV_BIT (0x01 << 1) /**< Crank Revolution Data Supported bit. */
+#define BLE_CSCS_FEATURE_MULTIPLE_SENSORS_BIT (0x01 << 2) /**< Multiple Sensor Locations Supported bit. */
+/** @} */
+
+
+/**@brief Cycling Speed and Cadence Service event type. */
+typedef enum
+{
+ BLE_CSCS_EVT_NOTIFICATION_ENABLED, /**< Cycling Speed and Cadence value notification enabled event. */
+ BLE_CSCS_EVT_NOTIFICATION_DISABLED /**< Cycling Speed and Cadence value notification disabled event. */
+} ble_cscs_evt_type_t;
+
+/**@brief Cycling Speed and Cadence Service event. */
+typedef struct
+{
+ ble_cscs_evt_type_t evt_type; /**< Type of event. */
+} ble_cscs_evt_t;
+
+// Forward declaration of the ble_csc_t type.
+typedef struct ble_cscs_s ble_cscs_t;
+
+/**@brief Cycling Speed and Cadence Service event handler type. */
+typedef void (*ble_cscs_evt_handler_t) (ble_cscs_t * p_cscs, ble_cscs_evt_t * p_evt);
+
+/**@brief Cycling Speed and Cadence Service init structure. This contains all options and data
+* needed for initialization of the service. */
+typedef struct
+{
+ ble_cscs_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Cycling Speed and Cadence Service. */
+ ble_srv_cccd_security_mode_t csc_meas_attr_md; /**< Initial security level for cycling speed and cadence measurement attribute */
+ ble_srv_cccd_security_mode_t csc_ctrlpt_attr_md; /**< Initial security level for cycling speed and cadence control point attribute */
+ ble_srv_security_mode_t csc_feature_attr_md; /**< Initial security level for feature attribute */
+ uint16_t feature; /**< Initial value for features of sensor @ref BLE_CSCS_FEATURES. */
+ uint8_t ctrplt_supported_functions; /**< Supported control point functionalities see @ref BLE_SRV_SC_CTRLPT_SUPP_FUNC. */
+ ble_sc_ctrlpt_evt_handler_t ctrlpt_evt_handler; /**< Event handler */
+ ble_sensor_location_t *list_supported_locations; /**< List of supported sensor locations.*/
+ uint8_t size_list_supported_locations; /**< Number of supported sensor locations in the list.*/
+ ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
+ ble_sensor_location_t *sensor_location; /**< Initial Sensor Location, if NULL, sensor_location characteristic is not added*/
+ ble_srv_cccd_security_mode_t csc_sensor_loc_attr_md; /**< Initial security level for sensor location attribute */
+} ble_cscs_init_t;
+
+/**@brief Cycling Speed and Cadence Service structure. This contains various status information for
+ * the service. */
+struct ble_cscs_s
+{
+ ble_cscs_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Cycling Speed and Cadence Service. */
+ uint16_t service_handle; /**< Handle of Cycling Speed and Cadence Service (as provided by the BLE stack). */
+ ble_gatts_char_handles_t meas_handles; /**< Handles related to the Cycling Speed and Cadence Measurement characteristic. */
+ ble_gatts_char_handles_t feature_handles; /**< Handles related to the Cycling Speed and Cadence feature characteristic. */
+ ble_gatts_char_handles_t sensor_loc_handles; /**< Handles related to the Cycling Speed and Cadence Sensor Location characteristic. */
+ uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
+ uint16_t feature; /**< Bit mask of features available on sensor. */
+ ble_sc_ctrlpt_t ctrl_pt; /**< data for speed and cadence control point */
+};
+
+/**@brief Cycling Speed and Cadence Service measurement structure. This contains a Cycling Speed and
+ * Cadence Service measurement. */
+typedef struct ble_cscs_meas_s
+{
+ bool is_wheel_rev_data_present; /**< True if Wheel Revolution Data is present in the measurement. */
+ bool is_crank_rev_data_present; /**< True if Crank Revolution Data is present in the measurement. */
+ uint32_t cumulative_wheel_revs; /**< Cumulative Wheel Revolutions. */
+ uint16_t last_wheel_event_time; /**< Last Wheel Event Time. */
+ uint16_t cumulative_crank_revs; /**< Cumulative Crank Revolutions. */
+ uint16_t last_crank_event_time; /**< Last Crank Event Time. */
+} ble_cscs_meas_t;
+
+
+/**@brief Function for initializing the Cycling Speed and Cadence Service.
+ *
+ * @param[out] p_cscs Cycling Speed and Cadence Service structure. This structure will have to
+ * be supplied by the application. It will be initialized by this function,
+ * and will later be used to identify this particular service instance.
+ * @param[in] p_cscs_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
+ */
+uint32_t ble_cscs_init(ble_cscs_t * p_cscs, ble_cscs_init_t const * p_cscs_init);
+
+
+/**@brief Function for handling the Application's BLE Stack events.
+ *
+ * @details Handles all events from the BLE stack of interest to the Cycling Speed and Cadence
+ * Service.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Cycling Speed and Cadence Service structure.
+ */
+void ble_cscs_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for sending cycling speed and cadence measurement if notification has been enabled.
+ *
+ * @details The application calls this function after having performed a Cycling Speed and Cadence
+ * Service measurement. If notification has been enabled, the measurement data is encoded
+ * and sent to the client.
+ *
+ * @param[in] p_cscs Cycling Speed and Cadence Service structure.
+ * @param[in] p_measurement Pointer to new cycling speed and cadence measurement.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+uint32_t ble_cscs_measurement_send(ble_cscs_t * p_cscs, ble_cscs_meas_t * p_measurement);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_CSCS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cscs/ble_sc_ctrlpt.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cscs/ble_sc_ctrlpt.c
new file mode 100644
index 0000000..faef930
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cscs/ble_sc_ctrlpt.c
@@ -0,0 +1,686 @@
+/**
+ * Copyright (c) 2013 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Attention!
+ * To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+
+#include "ble_sc_ctrlpt.h"
+#include <string.h>
+#include "nordic_common.h"
+#include "ble.h"
+#include "ble_err.h"
+#include "ble_srv_common.h"
+#include "app_util.h"
+
+#define SC_CTRLPT_NACK_PROC_ALREADY_IN_PROGRESS (BLE_GATT_STATUS_ATTERR_APP_BEGIN + 0)
+#define SC_CTRLPT_NACK_CCCD_IMPROPERLY_CONFIGURED (BLE_GATT_STATUS_ATTERR_APP_BEGIN + 1)
+
+uint32_t ble_sc_ctrlpt_init(ble_sc_ctrlpt_t * p_sc_ctrlpt,
+ const ble_cs_ctrlpt_init_t * p_sc_ctrlpt_init)
+{
+ if (p_sc_ctrlpt == NULL || p_sc_ctrlpt_init == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_md_t cccd_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+
+ p_sc_ctrlpt->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_sc_ctrlpt->procedure_status = BLE_SCPT_NO_PROC_IN_PROGRESS;
+
+ p_sc_ctrlpt->size_list_supported_locations = p_sc_ctrlpt_init->size_list_supported_locations;
+
+ if ((p_sc_ctrlpt_init->size_list_supported_locations != 0) &&
+ (p_sc_ctrlpt_init->list_supported_locations != NULL))
+ {
+ memcpy(p_sc_ctrlpt->list_supported_locations,
+ p_sc_ctrlpt_init->list_supported_locations,
+ p_sc_ctrlpt->size_list_supported_locations * sizeof(ble_sensor_location_t));
+ }
+
+ p_sc_ctrlpt->service_handle = p_sc_ctrlpt_init->service_handle;
+ p_sc_ctrlpt->evt_handler = p_sc_ctrlpt_init->evt_handler;
+ p_sc_ctrlpt->supported_functions = p_sc_ctrlpt_init->supported_functions;
+ p_sc_ctrlpt->sensor_location_handle = p_sc_ctrlpt_init->sensor_location_handle;
+ p_sc_ctrlpt->error_handler = p_sc_ctrlpt_init->error_handler;
+
+ memset(&cccd_md, 0, sizeof(cccd_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
+ cccd_md.write_perm = p_sc_ctrlpt_init->sc_ctrlpt_attr_md.cccd_write_perm;
+ cccd_md.vloc = BLE_GATTS_VLOC_STACK;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.indicate = 1;
+ char_md.char_props.write = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = &cccd_md;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_SC_CTRLPT_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm);
+ attr_md.write_perm = p_sc_ctrlpt_init->sc_ctrlpt_attr_md.write_perm;
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 1;
+ attr_md.vlen = 1;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = 0;
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = BLE_SC_CTRLPT_MAX_LEN;
+ attr_char_value.p_value = 0;
+
+ return sd_ble_gatts_characteristic_add(p_sc_ctrlpt->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_sc_ctrlpt->sc_ctrlpt_handles);
+}
+
+
+/**@brief Decode an incoming control point write.
+ *
+ * @param[in] rcvd_val received write value
+ * @param[in] len value length
+ * @param[out] decoded_ctrlpt decoded control point structure
+ */
+static uint32_t sc_ctrlpt_decode(uint8_t const * p_rcvd_val,
+ uint8_t len,
+ ble_sc_ctrlpt_val_t * p_write_val)
+{
+ int pos = 0;
+
+ if (len < BLE_SC_CTRLPT_MIN_LEN)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ p_write_val->opcode = (ble_scpt_operator_t) p_rcvd_val[pos++];
+
+ switch (p_write_val->opcode)
+ {
+ case BLE_SCPT_REQUEST_SUPPORTED_SENSOR_LOCATIONS:
+ break;
+
+ case BLE_SCPT_START_AUTOMATIC_CALIBRATION:
+ break;
+
+ case BLE_SCPT_UPDATE_SENSOR_LOCATION:
+ p_write_val->location = (ble_sensor_location_t)p_rcvd_val[pos];
+ break;
+
+ case BLE_SCPT_SET_CUMULATIVE_VALUE:
+ p_write_val->cumulative_value = uint32_decode(&(p_rcvd_val[pos]));
+ break;
+
+ default:
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ return NRF_SUCCESS;
+}
+
+
+/**@brief encode a control point response indication.
+ *
+ * @param[in] p_sc_ctrlpt SC Ctrlpt structure.
+ * @param[in] p_ctrlpt_rsp structure containing response data to be encoded
+ * @param[out] p_data pointer where data needs to be written
+ * @return size of encoded data
+ */
+static int ctrlpt_rsp_encode(ble_sc_ctrlpt_t * p_sc_ctrlpt,
+ ble_sc_ctrlpt_rsp_t * p_ctrlpt_rsp,
+ uint8_t * p_data)
+{
+ int len = 0;
+
+ p_data[len++] = BLE_SCPT_RESPONSE_CODE;
+ p_data[len++] = p_ctrlpt_rsp->opcode;
+ p_data[len++] = p_ctrlpt_rsp->status;
+
+ if (p_ctrlpt_rsp->status == BLE_SCPT_SUCCESS)
+ {
+ switch (p_ctrlpt_rsp->opcode)
+ {
+ case BLE_SCPT_REQUEST_SUPPORTED_SENSOR_LOCATIONS:
+ {
+ int i;
+ for (i = 0; i < p_sc_ctrlpt->size_list_supported_locations; i++)
+ {
+ p_data[len++] = p_sc_ctrlpt->list_supported_locations[i];
+ }
+ break;
+ }
+
+ default:
+ // No implementation needed.
+ break;
+ }
+ }
+ return len;
+}
+
+
+/**@brief check if a given sensor location is supported or not.
+ *
+ * @param[in] p_sc_ctrlpt SC Ctrlpt structure.
+ * @param[in] location sensor location to check.
+ * @return true if the given location is found in the list of supported locations, false otherwise.
+ */
+static bool is_location_supported(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_sensor_location_t location)
+{
+ int i;
+
+ for (i = 0; i < p_sc_ctrlpt->size_list_supported_locations; i++)
+ {
+ if (p_sc_ctrlpt->list_supported_locations[i] == location)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/**@brief check if the cccd is configured
+ *
+ * @param[in] p_sc_ctrlpt SC Ctrlpt structure.
+ * @return true if the sc_control point's cccd is correctly configured, false otherwise.
+ */
+static bool is_cccd_configured(ble_sc_ctrlpt_t * p_sc_ctrlpt)
+{
+ uint32_t err_code;
+ uint8_t cccd_value_buf[BLE_CCCD_VALUE_LEN];
+ bool is_sccp_indic_enabled = false;
+ ble_gatts_value_t gatts_value;
+
+ // Initialize value struct.
+ memset(&gatts_value, 0, sizeof(gatts_value));
+
+ gatts_value.len = BLE_CCCD_VALUE_LEN;
+ gatts_value.offset = 0;
+ gatts_value.p_value = cccd_value_buf;
+
+ err_code = sd_ble_gatts_value_get(p_sc_ctrlpt->conn_handle,
+ p_sc_ctrlpt->sc_ctrlpt_handles.cccd_handle,
+ &gatts_value);
+ if (err_code != NRF_SUCCESS)
+ {
+ // Report error to application
+ if (p_sc_ctrlpt->error_handler != NULL)
+ {
+ p_sc_ctrlpt->error_handler(err_code);
+ }
+ }
+
+ is_sccp_indic_enabled = ble_srv_is_indication_enabled(cccd_value_buf);
+
+ return is_sccp_indic_enabled;
+}
+
+
+/**@brief sends a control point indication.
+ *
+ * @param[in] p_sc_ctrlpt SC Ctrlpt structure.
+ */
+static void sc_ctrlpt_resp_send(ble_sc_ctrlpt_t * p_sc_ctrlpt)
+{
+ uint16_t hvx_len;
+ ble_gatts_hvx_params_t hvx_params;
+ uint32_t err_code;
+
+ if (p_sc_ctrlpt->procedure_status == BLE_SCPT_INDICATION_PENDING)
+ {
+ hvx_len = p_sc_ctrlpt->response.len;
+ memset(&hvx_params, 0, sizeof(hvx_params));
+
+ hvx_params.handle = p_sc_ctrlpt->sc_ctrlpt_handles.value_handle;
+ hvx_params.type = BLE_GATT_HVX_INDICATION;
+ hvx_params.offset = 0;
+ hvx_params.p_len = &hvx_len;
+ hvx_params.p_data = p_sc_ctrlpt->response.encoded_ctrl_rsp;
+
+ err_code = sd_ble_gatts_hvx(p_sc_ctrlpt->conn_handle, &hvx_params);
+
+ // Error handling
+ if ((err_code == NRF_SUCCESS) && (hvx_len != p_sc_ctrlpt->response.len))
+ {
+ err_code = NRF_ERROR_DATA_SIZE;
+ }
+
+ switch (err_code)
+ {
+ case NRF_SUCCESS:
+ p_sc_ctrlpt->procedure_status = BLE_SCPT_IND_CONFIRM_PENDING;
+ // Wait for HVC event
+ break;
+
+ case NRF_ERROR_RESOURCES:
+ // Wait for TX_COMPLETE event to retry transmission.
+ p_sc_ctrlpt->procedure_status = BLE_SCPT_INDICATION_PENDING;
+ break;
+
+ default:
+ // Report error to application.
+ p_sc_ctrlpt->procedure_status = BLE_SCPT_NO_PROC_IN_PROGRESS;
+ if (p_sc_ctrlpt->error_handler != NULL)
+ {
+ p_sc_ctrlpt->error_handler(err_code);
+ }
+ break;
+ }
+ }
+}
+
+
+/**@brief Handle a write event to the Speed and Cadence Control Point.
+ *
+ * @param[in] p_sc_ctrlpt SC Ctrlpt structure.
+ * @param[in] p_evt_write WRITE event to be handled.
+ */
+static void on_ctrlpt_write(ble_sc_ctrlpt_t * p_sc_ctrlpt,
+ ble_gatts_evt_write_t const * p_evt_write)
+{
+ ble_sc_ctrlpt_val_t rcvd_ctrlpt =
+ { BLE_SCPT_RESPONSE_CODE , 0, BLE_SENSOR_LOCATION_OTHER };
+
+ ble_sc_ctrlpt_rsp_t rsp;
+ uint32_t err_code;
+ ble_gatts_rw_authorize_reply_params_t auth_reply;
+ ble_sc_ctrlpt_evt_t evt;
+
+ auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
+ auth_reply.params.write.offset = 0;
+ auth_reply.params.write.len = 0;
+ auth_reply.params.write.p_data = NULL;
+ auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ auth_reply.params.write.update = 1;
+
+ if (is_cccd_configured(p_sc_ctrlpt))
+ {
+ if (p_sc_ctrlpt->procedure_status == BLE_SCPT_NO_PROC_IN_PROGRESS)
+ {
+ auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ }
+ else
+ {
+ auth_reply.params.write.gatt_status = SC_CTRLPT_NACK_PROC_ALREADY_IN_PROGRESS;
+ }
+ }
+ else
+ {
+ auth_reply.params.write.gatt_status = SC_CTRLPT_NACK_CCCD_IMPROPERLY_CONFIGURED;
+ }
+
+ err_code = sd_ble_gatts_rw_authorize_reply(p_sc_ctrlpt->conn_handle, &auth_reply);
+ if (err_code != NRF_SUCCESS)
+ {
+ // Report error to application.
+ if (p_sc_ctrlpt->error_handler != NULL)
+ {
+ p_sc_ctrlpt->error_handler(err_code);
+ }
+ }
+
+ if (auth_reply.params.write.gatt_status != BLE_GATT_STATUS_SUCCESS)
+ {
+ return;
+ }
+
+ p_sc_ctrlpt->procedure_status = BLE_SCPT_INDICATION_PENDING;
+ rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
+
+ err_code = sc_ctrlpt_decode(p_evt_write->data, p_evt_write->len, &rcvd_ctrlpt);
+ if (err_code != NRF_SUCCESS)
+ {
+ rsp.opcode = rcvd_ctrlpt.opcode;
+ rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
+ }
+ else
+ {
+ rsp.opcode = rcvd_ctrlpt.opcode;
+
+ switch (rcvd_ctrlpt.opcode)
+ {
+ case BLE_SCPT_REQUEST_SUPPORTED_SENSOR_LOCATIONS:
+ if ((p_sc_ctrlpt->supported_functions &
+ BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED) ==
+ BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED)
+ {
+ rsp.status = BLE_SCPT_SUCCESS;
+ }
+ else
+ {
+ rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
+ }
+ break;
+
+ case BLE_SCPT_UPDATE_SENSOR_LOCATION:
+ if ((p_sc_ctrlpt->supported_functions &
+ BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED) ==
+ BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED)
+ {
+ if (is_location_supported(p_sc_ctrlpt, rcvd_ctrlpt.location))
+ {
+ ble_gatts_value_t gatts_value;
+ uint8_t rcvd_location = (uint8_t)rcvd_ctrlpt.location;
+ rsp.status = BLE_SCPT_SUCCESS;
+
+ // Initialize value struct.
+ memset(&gatts_value, 0, sizeof(gatts_value));
+
+ gatts_value.len = sizeof(uint8_t);
+ gatts_value.offset = 0;
+ gatts_value.p_value = &rcvd_location;
+
+ evt.evt_type = BLE_SC_CTRLPT_EVT_UPDATE_LOCATION;
+ evt.params.update_location = rcvd_ctrlpt.location;
+ if (p_sc_ctrlpt->evt_handler != NULL)
+ {
+ rsp.status = p_sc_ctrlpt->evt_handler(p_sc_ctrlpt, &evt);
+ }
+ if (rsp.status == BLE_SCPT_SUCCESS)
+ {
+ err_code = sd_ble_gatts_value_set(p_sc_ctrlpt->conn_handle,
+ p_sc_ctrlpt->sensor_location_handle,
+ &gatts_value);
+ if (err_code != NRF_SUCCESS)
+ {
+ // Report error to application
+ if (p_sc_ctrlpt->error_handler != NULL)
+ {
+ p_sc_ctrlpt->error_handler(err_code);
+ }
+ rsp.status = BLE_SCPT_OPERATION_FAILED;
+ }
+ }
+ }
+ else
+ {
+ rsp.status = BLE_SCPT_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
+ }
+ break;
+
+ case BLE_SCPT_SET_CUMULATIVE_VALUE:
+ if ((p_sc_ctrlpt->supported_functions &
+ BLE_SRV_SC_CTRLPT_CUM_VAL_OP_SUPPORTED) ==
+ BLE_SRV_SC_CTRLPT_CUM_VAL_OP_SUPPORTED)
+ {
+ rsp.status = BLE_SCPT_SUCCESS;
+
+ evt.evt_type = BLE_SC_CTRLPT_EVT_SET_CUMUL_VALUE;
+ evt.params.cumulative_value = rcvd_ctrlpt.cumulative_value;
+ if (p_sc_ctrlpt->evt_handler != NULL)
+ {
+ rsp.status = p_sc_ctrlpt->evt_handler(p_sc_ctrlpt, &evt);
+ }
+ }
+ else
+ {
+ rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
+ }
+ break;
+
+ case BLE_SCPT_START_AUTOMATIC_CALIBRATION:
+ if ((p_sc_ctrlpt->supported_functions &
+ BLE_SRV_SC_CTRLPT_START_CALIB_OP_SUPPORTED) ==
+ BLE_SRV_SC_CTRLPT_START_CALIB_OP_SUPPORTED)
+ {
+ p_sc_ctrlpt->procedure_status = BLE_SCPT_AUTOMATIC_CALIB_IN_PROGRESS;
+ evt.evt_type = BLE_SC_CTRLPT_EVT_START_CALIBRATION;
+ if (p_sc_ctrlpt->evt_handler != NULL)
+ {
+ rsp.status = p_sc_ctrlpt->evt_handler(p_sc_ctrlpt, &evt);
+ if (rsp.status != BLE_SCPT_SUCCESS)
+ {
+ // If the application returns an error, the response is to be sent
+ // right away and the calibration is considered as not started.
+ p_sc_ctrlpt->procedure_status = BLE_SCPT_INDICATION_PENDING;
+ }
+ }
+ }
+ else
+ {
+ rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
+ }
+ break;
+
+ default:
+ rsp.status = BLE_SCPT_OP_CODE_NOT_SUPPORTED;
+ break;
+ }
+
+ }
+
+ p_sc_ctrlpt->response.len = ctrlpt_rsp_encode(p_sc_ctrlpt, &rsp,
+ p_sc_ctrlpt->response.encoded_ctrl_rsp);
+
+
+ if (p_sc_ctrlpt->procedure_status == BLE_SCPT_INDICATION_PENDING)
+ {
+ sc_ctrlpt_resp_send(p_sc_ctrlpt);
+ }
+}
+
+
+/**@brief Authorize WRITE request event handler.
+ *
+ * @details Handles WRITE events from the BLE stack.
+ *
+ * @param[in] p_sc_ctrlpt SC Ctrlpt structure.
+ * @param[in] p_gatts_evt GATTS Event received from the BLE stack.
+ *
+ */
+static void on_rw_authorize_request(ble_sc_ctrlpt_t * p_sc_ctrlpt,
+ ble_gatts_evt_t const * p_gatts_evt)
+{
+ ble_gatts_evt_rw_authorize_request_t const * p_auth_req =
+ &p_gatts_evt->params.authorize_request;
+
+ if (p_auth_req->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
+ {
+ if ( (p_gatts_evt->params.authorize_request.request.write.op
+ != BLE_GATTS_OP_PREP_WRITE_REQ)
+ && (p_gatts_evt->params.authorize_request.request.write.op
+ != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW)
+ && (p_gatts_evt->params.authorize_request.request.write.op
+ != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)
+ )
+ {
+ if (p_auth_req->request.write.handle == p_sc_ctrlpt->sc_ctrlpt_handles.value_handle)
+ {
+ on_ctrlpt_write(p_sc_ctrlpt, &p_auth_req->request.write);
+ }
+ }
+ }
+}
+
+
+/**@brief Tx Complete event handler.
+ *
+ * @details Tx Complete event handler.
+ * Handles WRITE events from the BLE stack and if an indication was pending try sending it
+ * again.
+ *
+ * @param[in] p_sc_ctrlpt SC Ctrlpt structure.
+ *
+ */
+static void on_tx_complete(ble_sc_ctrlpt_t * p_sc_ctrlpt)
+{
+ if (p_sc_ctrlpt->procedure_status == BLE_SCPT_INDICATION_PENDING)
+ {
+ sc_ctrlpt_resp_send(p_sc_ctrlpt);
+ }
+}
+
+
+/**@brief Function for handling the Connect event.
+ *
+ * @param[in] p_sc_ctrlpt SC Ctrlpt structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_connect(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_evt_t const * p_ble_evt)
+{
+ p_sc_ctrlpt->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+ p_sc_ctrlpt->procedure_status = BLE_SCPT_NO_PROC_IN_PROGRESS;
+}
+
+
+/**@brief Function for handling the Disconnect event.
+ *
+ * @param[in] p_sc_ctrlpt SC Ctrlpt structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_disconnect(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_evt_t const * p_ble_evt)
+{
+ UNUSED_PARAMETER(p_ble_evt);
+ p_sc_ctrlpt->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_sc_ctrlpt->procedure_status = BLE_SCPT_NO_PROC_IN_PROGRESS;
+}
+
+
+/**@brief Function for handling the BLE_GATTS_EVT_HVC event.
+ *
+ * @param[in] p_sc_ctrlpt SC Ctrlpt structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_sc_hvc_confirm(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_evt_t const * p_ble_evt)
+{
+ if (p_ble_evt->evt.gatts_evt.params.hvc.handle == p_sc_ctrlpt->sc_ctrlpt_handles.value_handle)
+ {
+ if (p_sc_ctrlpt->procedure_status == BLE_SCPT_IND_CONFIRM_PENDING)
+ {
+ p_sc_ctrlpt->procedure_status = BLE_SCPT_NO_PROC_IN_PROGRESS;
+ }
+ }
+}
+
+
+void ble_sc_ctrlpt_on_ble_evt(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_evt_t const * p_ble_evt)
+{
+ if (p_sc_ctrlpt == NULL || p_ble_evt == NULL)
+ {
+ return;
+ }
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ on_connect(p_sc_ctrlpt, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnect(p_sc_ctrlpt, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
+ on_rw_authorize_request(p_sc_ctrlpt, &p_ble_evt->evt.gatts_evt);
+ break;
+
+ case BLE_GATTS_EVT_HVC:
+ on_sc_hvc_confirm(p_sc_ctrlpt, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_HVN_TX_COMPLETE:
+ on_tx_complete(p_sc_ctrlpt);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+uint32_t ble_sc_ctrlpt_rsp_send(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_scpt_response_t response_status)
+{
+ if (p_sc_ctrlpt == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ uint32_t err_code = NRF_SUCCESS;
+ ble_sc_ctrlpt_rsp_t rsp;
+ uint8_t encoded_ctrl_rsp[BLE_SC_CTRLPT_MAX_LEN];
+ uint16_t hvx_len;
+ ble_gatts_hvx_params_t hvx_params;
+
+ if (p_sc_ctrlpt->procedure_status != BLE_SCPT_AUTOMATIC_CALIB_IN_PROGRESS)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+ rsp.status = response_status;
+ rsp.opcode = BLE_SCPT_START_AUTOMATIC_CALIBRATION;
+ hvx_len = ctrlpt_rsp_encode(p_sc_ctrlpt, &rsp, encoded_ctrl_rsp);
+
+ // Send indication
+ memset(&hvx_params, 0, sizeof(hvx_params));
+
+ hvx_params.handle = p_sc_ctrlpt->sc_ctrlpt_handles.value_handle;
+ hvx_params.type = BLE_GATT_HVX_INDICATION;
+ hvx_params.offset = 0;
+ hvx_params.p_len = &hvx_len;
+ hvx_params.p_data = encoded_ctrl_rsp;
+
+ err_code = sd_ble_gatts_hvx(p_sc_ctrlpt->conn_handle, &hvx_params);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ p_sc_ctrlpt->procedure_status = BLE_SCPT_NO_PROC_IN_PROGRESS;
+ }
+ return err_code;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cscs/ble_sc_ctrlpt.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cscs/ble_sc_ctrlpt.h
new file mode 100644
index 0000000..05a701d
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cscs/ble_sc_ctrlpt.h
@@ -0,0 +1,247 @@
+/**
+ * Copyright (c) 2013 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_sdk_srv_sc_ctrlpt Speed and Cadence Control Point
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Speed and Cadence Control Point module.
+ *
+ * @details This module implements the Speed and Cadence control point behavior. It is used
+ * by the @ref ble_cscs module and the ble_sdk_srv_rsc module for control point
+ * mechanisms like setting a cumulative value, Start an automatic calibration,
+ * Update the sensor location or request the supported locations.
+ *
+ * @note Attention!
+ * To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+
+#ifndef BLE_SC_CTRLPT_H__
+#define BLE_SC_CTRLPT_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "ble_sensor_location.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BLE_SC_CTRLPT_MAX_LEN 19 /**< maximum lenght for Speed and cadence control point characteristic value. */
+#define BLE_SC_CTRLPT_MIN_LEN 1 /**< minimum length for Speed and cadence control point characteristic value. */
+
+// Forward declaration of the ble_sc_ctrlpt_t type.
+typedef struct ble_sc_ctrlpt_s ble_sc_ctrlpt_t;
+
+
+/**@brief Speed and Cadence Control Point event type. */
+typedef enum
+{
+ BLE_SC_CTRLPT_EVT_UPDATE_LOCATION, /**< rcvd update location opcode (the control point handles the change of location automatically, the event just informs the application in case it needs to adjust its algorithm). */
+ BLE_SC_CTRLPT_EVT_SET_CUMUL_VALUE, /**< rcvd set cumulative value opcode, it is then up to the application to use the new cumulative value. */
+ BLE_SC_CTRLPT_EVT_START_CALIBRATION, /**< rcvd start calibration opcode, the application needs, at the end ot the calibration to call ble_sc_ctrlpt_send_rsp. */
+} ble_sc_ctrlpt_evt_type_t;
+
+
+/**@brief Speed and Cadence Control point event. */
+typedef struct
+{
+ ble_sc_ctrlpt_evt_type_t evt_type; /**< Type of event. */
+ union
+ {
+ ble_sensor_location_t update_location;
+ uint32_t cumulative_value;
+ }params;
+} ble_sc_ctrlpt_evt_t;
+
+
+/** Speed and Cadence Control Point operator code (see RSC service specification)*/
+typedef enum {
+ BLE_SCPT_SET_CUMULATIVE_VALUE = 0x01, /**< Operator to set a given cumulative value. */
+ BLE_SCPT_START_AUTOMATIC_CALIBRATION = 0x02, /**< Operator to start automatic calibration. */
+ BLE_SCPT_UPDATE_SENSOR_LOCATION = 0x03, /**< Operator to update the sensor location. */
+ BLE_SCPT_REQUEST_SUPPORTED_SENSOR_LOCATIONS = 0x04, /**< Operator to request the supported sensor locations. */
+ BLE_SCPT_RESPONSE_CODE = 0x10, /**< Response Code. */
+} ble_scpt_operator_t;
+
+
+/** Speed and Cadence Control Point response parameter (see RSC service specification)*/
+typedef enum {
+ BLE_SCPT_SUCCESS = 0x01, /**< Sucess Response. */
+ BLE_SCPT_OP_CODE_NOT_SUPPORTED = 0x02, /**< Error Response received opcode not supported. */
+ BLE_SCPT_INVALID_PARAMETER = 0x03, /**< Error Response received parameter invalid. */
+ BLE_SCPT_OPERATION_FAILED = 0x04, /**< Error Response operation failed. */
+} ble_scpt_response_t;
+
+
+/** Speed and Cadence Control Point procedure status (indicates is a procedure is in progress or not and which procedure is in progress*/
+typedef enum {
+ BLE_SCPT_NO_PROC_IN_PROGRESS = 0x00, /**< No procedure in progress. */
+ BLE_SCPT_AUTOMATIC_CALIB_IN_PROGRESS = 0x01, /**< Automatic Calibration is in progress. */
+ BLE_SCPT_INDICATION_PENDING = 0x02, /**< Control Point Indication is pending. */
+ BLE_SCPT_IND_CONFIRM_PENDING = 0x03, /**< Waiting for the indication confirmation. */
+}ble_scpt_procedure_status_t;
+
+/**@brief Speed and Cadence Control point event handler type. */
+typedef ble_scpt_response_t (*ble_sc_ctrlpt_evt_handler_t) (ble_sc_ctrlpt_t * p_sc_ctrlpt,
+ ble_sc_ctrlpt_evt_t * p_evt);
+
+
+typedef struct{
+ ble_scpt_operator_t opcode;
+ uint32_t cumulative_value;
+ ble_sensor_location_t location;
+}ble_sc_ctrlpt_val_t;
+
+
+typedef struct{
+ ble_scpt_operator_t opcode;
+ ble_scpt_response_t status;
+ ble_sensor_location_t location_list[BLE_NB_MAX_SENSOR_LOCATIONS];
+}ble_sc_ctrlpt_rsp_t;
+
+
+/**
+ * \defgroup BLE_SRV_SC_CTRLPT_SUPP_FUNC Control point functionalities.
+ *@{
+ */
+#define BLE_SRV_SC_CTRLPT_SENSOR_LOCATIONS_OP_SUPPORTED 0x01 /**< Support for sensor location related operations */
+#define BLE_SRV_SC_CTRLPT_CUM_VAL_OP_SUPPORTED 0x02 /**< Support for setting cumulative value related operations */
+#define BLE_SRV_SC_CTRLPT_START_CALIB_OP_SUPPORTED 0x04 /**< Support for starting calibration related operations */
+/**
+ *@}
+ */
+
+/**@brief Speed and Cadence Control Point init structure. This contains all options and data
+* needed for initialization of the Speed and Cadence Control Point module. */
+typedef struct
+{
+ ble_srv_cccd_security_mode_t sc_ctrlpt_attr_md; /**< Initial security level for cycling speed and cadence control point attribute */
+ uint8_t supported_functions; /**< supported control point functionalities see @ref BLE_SRV_SC_CTRLPT_SUPP_FUNC. */
+ uint16_t service_handle; /**< Handle of the parent service (as provided by the BLE stack). */
+ ble_sc_ctrlpt_evt_handler_t evt_handler; /**< event handler */
+ ble_sensor_location_t *list_supported_locations; /**< list of supported sensor locations.*/
+ uint8_t size_list_supported_locations; /**< number of supported sensor locations in the list.*/
+ uint16_t sensor_location_handle; /**< handle for the sensor location characteristic (if sensor_location related operation are supported).*/
+ ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
+} ble_cs_ctrlpt_init_t;
+
+
+/**@brief Speed and Cadence Control Point response indication structure. */
+typedef struct
+{
+ ble_scpt_response_t status; /**< control point response status .*/
+ uint8_t len; /**< control point response length .*/
+ uint8_t encoded_ctrl_rsp[BLE_SC_CTRLPT_MAX_LEN]; /**< control point encoded response.*/
+}ble_sc_ctrlpt_resp_t;
+
+
+/**@brief Speed and Cadence Control Point structure. This contains various status information for
+ * the Speed and Cadence Control Point behavior. */
+struct ble_sc_ctrlpt_s
+{
+ uint8_t supported_functions; /**< supported control point functionalities see @ref BLE_SRV_SC_CTRLPT_SUPP_FUNC. */
+ uint16_t service_handle; /**< Handle of the parent service (as provided by the BLE stack). */
+ ble_gatts_char_handles_t sc_ctrlpt_handles; /**< Handles related to the Speed and Cadence Control Point characteristic. */
+ uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
+ ble_sensor_location_t list_supported_locations[BLE_NB_MAX_SENSOR_LOCATIONS]; /**< list of supported sensor locations.*/
+ uint8_t size_list_supported_locations; /**< number of supported sensor locations in the list.*/
+ ble_sc_ctrlpt_evt_handler_t evt_handler; /**< Handle of the parent service (as provided by the BLE stack). */
+ uint16_t sensor_location_handle; /**< handle for the sensor location characteristic (if sensor_location related operation are supported).*/
+ ble_scpt_procedure_status_t procedure_status; /**< status of possible procedure*/
+ ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
+ ble_sc_ctrlpt_resp_t response; /**< pending response data.*/
+};
+
+#define SCPT_OPCODE_POS 0 /**< Request opcode position. */
+#define SCPT_PARAMETER_POS 1 /**< Request parameter position. */
+
+#define SCPT_RESPONSE_REQUEST_OPCODE_POS 1 /**< Response position of requested opcode. */
+#define SCPT_RESPONSE_CODE_POS 2 /**< Response position of response code. */
+#define SCPT_RESPONSE_PARAMETER 3 /**< Response position of response parameter. */
+
+#define SCPT_MIN_RESPONSE_SIZE 3 /**< Minimum size for control point response. */
+#define SCPT_MAX_RESPONSE_SIZE (SCPT_MIN_RESPONSE_SIZE + NB_MAX_SENSOR_LOCATIONS) /**< Maximum size for control point response. */
+
+
+/**@brief Function for Initializing the Speed and Cadence Control Point.
+ *
+ * @details Function for Initializing the Speed and Cadence Control Point.
+ * @param[in] p_sc_ctrlpt Speed and Cadence Control Point structure.
+ * @param[in] p_sc_ctrlpt_init Information needed to initialize the control point behavior.
+ *
+ * @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
+ */
+uint32_t ble_sc_ctrlpt_init(ble_sc_ctrlpt_t * p_sc_ctrlpt,
+ ble_cs_ctrlpt_init_t const * p_sc_ctrlpt_init);
+
+
+/**@brief Function for sending a control point response.
+ *
+ * @details Function for sending a control point response when the control point received was
+ * BLE_SCPT_START_AUTOMATIC_CALIBRATION. To be called after the calibration procedure is finished.
+ *
+ * @param[in] p_sc_ctrlpt Speed and Cadence Control Point structure.
+ * @param[in] response_status status to include in the control point response.
+ */
+uint32_t ble_sc_ctrlpt_rsp_send(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_scpt_response_t response_status);
+
+
+/**@brief Speed and Cadence Control Point BLE stack event handler.
+ *
+ * @details Handles all events from the BLE stack of interest to the Speed and Cadence Control Point.
+ *
+ * @param[in] p_sc_ctrlpt Speed and Cadence Control Point structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+void ble_sc_ctrlpt_on_ble_evt(ble_sc_ctrlpt_t * p_sc_ctrlpt, ble_evt_t const * p_ble_evt);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_SC_CTRLPT_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cts_c/ble_cts_c.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cts_c/ble_cts_c.c
new file mode 100644
index 0000000..09d4d7d
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cts_c/ble_cts_c.c
@@ -0,0 +1,357 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_CTS_C)
+#include <string.h>
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "ble_gattc.h"
+#include "ble_cts_c.h"
+#include "ble_date_time.h"
+#include "ble_db_discovery.h"
+#define NRF_LOG_MODULE_NAME ble_cts_c
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define CTS_YEAR_MIN 1582 /**< The lowest valid Current Time year is the year when the western calendar was introduced. */
+#define CTS_YEAR_MAX 9999 /**< The highest possible Current Time. */
+
+#define CTS_C_CURRENT_TIME_EXPECTED_LENGTH 10 /**< | Year |Month |Day |Hours |Minutes |Seconds |Weekday |Fraction|Reason |
+ | 2 bytes |1 byte |1 byte |1 byte |1 byte |1 byte |1 byte |1 byte |1 byte | = 10 bytes. */
+
+
+/**@brief Function for handling events from the database discovery module.
+ *
+ * @details This function will handle an event from the database discovery module, and determine
+ * if it relates to the discovery of Current Time Service at the peer. If so, it will
+ * call the application's event handler indicating that the Current Time Service has been
+ * discovered at the peer. It also populates the event with the service related
+ * information before providing it to the application.
+ *
+ * @param[in] p_evt Pointer to the event received from the database discovery module.
+ *
+ */
+void ble_cts_c_on_db_disc_evt(ble_cts_c_t * p_cts, ble_db_discovery_evt_t * p_evt)
+{
+ NRF_LOG_DEBUG("Database Discovery handler called with event 0x%x", p_evt->evt_type);
+
+ ble_cts_c_evt_t evt;
+ const ble_gatt_db_char_t * p_chars = p_evt->params.discovered_db.charateristics;
+
+ evt.evt_type = BLE_CTS_C_EVT_DISCOVERY_FAILED;
+ evt.conn_handle = p_evt->conn_handle;
+
+ // Check if the Current Time Service was discovered.
+ if ( (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE)
+ && (p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_CURRENT_TIME_SERVICE)
+ && (p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE))
+ {
+ // Find the handles of the Current Time characteristic.
+ for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
+ {
+ if (p_evt->params.discovered_db.charateristics[i].characteristic.uuid.uuid ==
+ BLE_UUID_CURRENT_TIME_CHAR)
+ {
+ // Found Current Time characteristic. Store CCCD and value handle and break.
+ evt.params.char_handles.cts_handle = p_chars->characteristic.handle_value;
+ evt.params.char_handles.cts_cccd_handle = p_chars->cccd_handle;
+ break;
+ }
+ }
+
+ NRF_LOG_INFO("Current Time Service discovered at peer.");
+
+ evt.evt_type = BLE_CTS_C_EVT_DISCOVERY_COMPLETE;
+ }
+ p_cts->evt_handler(p_cts, &evt);
+}
+
+
+uint32_t ble_cts_c_init(ble_cts_c_t * p_cts, ble_cts_c_init_t const * p_cts_init)
+{
+ //Verify that the parameters needed for to initialize this instance of CTS are not NULL.
+ VERIFY_PARAM_NOT_NULL(p_cts);
+ VERIFY_PARAM_NOT_NULL(p_cts_init);
+ VERIFY_PARAM_NOT_NULL(p_cts_init->error_handler);
+ VERIFY_PARAM_NOT_NULL(p_cts_init->evt_handler);
+
+ static ble_uuid_t cts_uuid;
+
+ BLE_UUID_BLE_ASSIGN(cts_uuid, BLE_UUID_CURRENT_TIME_SERVICE);
+
+ p_cts->evt_handler = p_cts_init->evt_handler;
+ p_cts->error_handler = p_cts_init->error_handler;
+ p_cts->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_cts->char_handles.cts_handle = BLE_GATT_HANDLE_INVALID;
+ p_cts->char_handles.cts_cccd_handle = BLE_GATT_HANDLE_INVALID;
+
+ return ble_db_discovery_evt_register(&cts_uuid);
+}
+
+
+/**@brief Function for decoding a read from the current time characteristic.
+ *
+ * @param[in] p_time Current Time structure.
+ * @param[in] p_data Pointer to the buffer containing the current time.
+ * @param[in] length length of the buffer containing the current time.
+ *
+ * @return NRF_SUCCESS if the time struct is valid.
+ * @return NRF_ERROR_DATA_SIZE if length does not match the expected size of the data.
+ */
+static uint32_t current_time_decode(current_time_char_t * p_time,
+ uint8_t const * p_data,
+ uint32_t const length)
+{
+ //lint -save -e415 -e416 "Access of out of bounds pointer" "Creation of out of bounds pointer"
+
+ if (length != CTS_C_CURRENT_TIME_EXPECTED_LENGTH)
+ {
+ // Return to prevent accessing out of bounds data.
+ return NRF_ERROR_DATA_SIZE;
+ }
+
+ NRF_LOG_DEBUG("Current Time read response data:");
+ NRF_LOG_HEXDUMP_DEBUG(p_data, 10);
+
+ uint32_t index = 0;
+
+ // Date.
+ index += ble_date_time_decode(&p_time->exact_time_256.day_date_time.date_time, p_data);
+
+ // Day of week.
+ p_time->exact_time_256.day_date_time.day_of_week = p_data[index++];
+
+ // Fractions of a second.
+ p_time->exact_time_256.fractions256 = p_data[index++];
+
+ // Reason for updating the time.
+ p_time->adjust_reason.manual_time_update = (p_data[index] >> 0) & 0x01;
+ p_time->adjust_reason.external_reference_time_update = (p_data[index] >> 1) & 0x01;
+ p_time->adjust_reason.change_of_time_zone = (p_data[index] >> 2) & 0x01;
+ p_time->adjust_reason.change_of_daylight_savings_time = (p_data[index] >> 3) & 0x01;
+
+ //lint -restore
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for decoding a read from the current time characteristic.
+ *
+ * @param[in] p_time Current Time struct.
+ *
+ * @return NRF_SUCCESS if the time struct is valid.
+ * @return NRF_ERROR_INVALID_DATA if the time is out of bounds.
+ */
+static uint32_t current_time_validate(current_time_char_t * p_time)
+{
+ // Year.
+ if ( (p_time->exact_time_256.day_date_time.date_time.year > CTS_YEAR_MAX)
+ || ((p_time->exact_time_256.day_date_time.date_time.year < CTS_YEAR_MIN)
+ && (p_time->exact_time_256.day_date_time.date_time.year != 0)))
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ // Month.
+ if (p_time->exact_time_256.day_date_time.date_time.month > 12)
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ // Day.
+ if (p_time->exact_time_256.day_date_time.date_time.day > 31)
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ // Hours.
+ if (p_time->exact_time_256.day_date_time.date_time.hours > 23)
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ // Minutes.
+ if (p_time->exact_time_256.day_date_time.date_time.minutes > 59)
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ // Seconds.
+ if (p_time->exact_time_256.day_date_time.date_time.seconds > 59)
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ // Day of week.
+ if (p_time->exact_time_256.day_date_time.day_of_week > 7)
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for reading the current time. The time is decoded, then it is validated.
+ * Depending on the outcome the cts event handler will be called with
+ * the current time event or an invalid time event.
+ *
+ * @param[in] p_cts Current Time Service client structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void current_time_read(ble_cts_c_t * p_cts, ble_evt_t const * p_ble_evt)
+{
+ ble_cts_c_evt_t evt;
+ uint32_t err_code = NRF_SUCCESS;
+
+ // Check if the event is on the same connection as this cts instance
+ if (p_cts->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
+ {
+ return;
+ }
+
+ if (p_ble_evt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_SUCCESS)
+ {
+ err_code = current_time_decode(&evt.params.current_time,
+ p_ble_evt->evt.gattc_evt.params.read_rsp.data,
+ p_ble_evt->evt.gattc_evt.params.read_rsp.len);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ // The data length was invalid, decoding was not completed.
+ evt.evt_type = BLE_CTS_C_EVT_INVALID_TIME;
+ }
+ else
+ {
+ // Verify That the time is valid.
+ err_code = current_time_validate(&evt.params.current_time);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ // Invalid time received.
+ evt.evt_type = BLE_CTS_C_EVT_INVALID_TIME;
+ }
+ else
+ {
+ // Valid time reveiced.
+ evt.evt_type = BLE_CTS_C_EVT_CURRENT_TIME;
+ }
+ }
+ p_cts->evt_handler(p_cts, &evt);
+ }
+}
+
+
+/**@brief Function for handling the Disconnect event.
+ *
+ * @param[in] p_cts Current Time Service client structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_disconnect(ble_cts_c_t * p_cts, ble_evt_t const * p_ble_evt)
+{
+ if (p_cts->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
+ {
+ p_cts->conn_handle = BLE_CONN_HANDLE_INVALID;
+ }
+
+ if (ble_cts_c_is_cts_discovered(p_cts))
+ {
+ // There was a valid instance of cts on the peer. Send an event to the
+ // application, so that it can do any clean up related to this module.
+ ble_cts_c_evt_t evt;
+
+ evt.evt_type = BLE_CTS_C_EVT_DISCONN_COMPLETE;
+
+ p_cts->evt_handler(p_cts, &evt);
+ p_cts->char_handles.cts_handle = BLE_GATT_HANDLE_INVALID;
+ p_cts->char_handles.cts_cccd_handle = BLE_GATT_HANDLE_INVALID;
+ }
+}
+
+
+void ble_cts_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ ble_cts_c_t * p_cts = (ble_cts_c_t *)p_context;
+ NRF_LOG_DEBUG("BLE event handler called with event 0x%x", p_ble_evt->header.evt_id);
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GATTC_EVT_READ_RSP:
+ current_time_read(p_cts, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnect(p_cts, p_ble_evt);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+
+uint32_t ble_cts_c_current_time_read(ble_cts_c_t const * p_cts)
+{
+ if (!ble_cts_c_is_cts_discovered(p_cts))
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ return sd_ble_gattc_read(p_cts->conn_handle, p_cts->char_handles.cts_handle, 0);
+}
+
+
+uint32_t ble_cts_c_handles_assign(ble_cts_c_t * p_cts,
+ const uint16_t conn_handle,
+ const ble_cts_c_handles_t * p_peer_handles)
+{
+ VERIFY_PARAM_NOT_NULL(p_cts);
+
+ p_cts->conn_handle = conn_handle;
+ if (p_peer_handles != NULL)
+ {
+ p_cts->char_handles.cts_cccd_handle = p_peer_handles->cts_cccd_handle;
+ p_cts->char_handles.cts_handle = p_peer_handles->cts_handle;
+ }
+
+ return NRF_SUCCESS;
+}
+#endif // NRF_MODULE_ENABLED(BLE_CTS_C)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cts_c/ble_cts_c.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cts_c/ble_cts_c.h
new file mode 100644
index 0000000..1abdf9c
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_cts_c/ble_cts_c.h
@@ -0,0 +1,284 @@
+/**
+ * Copyright (c) 2014 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_cts_c Current Time Service client
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Current Time Service client module.
+ *
+ * @details This module implements the Current Time Service (CTS) client-peripheral role of
+ * the Time Profile. After security is established, the module tries to discover the
+ * Current Time Service and Characteristic on the central side. If this succeeds,
+ * the application can trigger a read of the current time from the connected server.
+ *
+ * The module informs the application about a successful discovery using the
+ * @ref BLE_CTS_C_EVT_DISCOVERY_COMPLETE event. The handles for the CTS server is now
+ * available in the @ref ble_cts_c_evt_t structure. These handles must be assigned to an
+ * instance of CTS_C, using @ref ble_cts_c_handles_assign. For more information about
+ * service discovery, see the ble_discovery module documentation @ref lib_ble_db_discovery.
+ *
+ * The application can then use the function @ref ble_cts_c_current_time_read to read the
+ * current time. If the read succeeds, it will trigger either a
+ * @ref BLE_CTS_C_EVT_CURRENT_TIME event or a @ref BLE_CTS_C_EVT_INVALID_TIME event
+ * (depending on if the data that was read was actually a valid time), which is then sent
+ * to the application. The current time is then available in the params field of the
+ * passed @ref ble_cts_c_evt_t structure.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_cts_c_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_CTS_C_BLE_OBSERVER_PRIO,
+ * ble_cts_c_on_ble_evt, &instance);
+ * @endcode
+ */
+
+#ifndef BLE_CTS_C_H__
+#define BLE_CTS_C_H__
+
+#include "ble_srv_common.h"
+#include "ble_gattc.h"
+#include "ble.h"
+#include "ble_date_time.h"
+#include "ble_db_discovery.h"
+#include "nrf_sdh_ble.h"
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_bps instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_CTS_C_DEF(_name) \
+static ble_cts_c_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_CTS_C_BLE_OBSERVER_PRIO, \
+ ble_cts_c_on_ble_evt, &_name)
+
+/** @brief Macro for defining multiple ble_cts_c instances.
+ *
+ * @param _name Name of the array of instances.
+ * @param _cnt Number of instances to define.
+ * @hideinitializer
+ */
+#define BLE_CTS_C_ARRAY_DEF(_name, _cnt) \
+static ble_cts_c_t _name[_cnt]; \
+NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
+ BLE_CTS_C_BLE_OBSERVER_PRIO, \
+ ble_cts_c_on_ble_evt, &_name, _cnt)
+
+
+/**@brief "Day Date Time" field of the "Exact Time 256" field of the Current Time Characteristic. */
+typedef struct
+{
+ ble_date_time_t date_time;
+ uint8_t day_of_week;
+} day_date_time_t;
+
+/**@brief "Exact Time 256" field of the Current Time Characteristic. */
+typedef struct
+{
+ day_date_time_t day_date_time;
+ uint8_t fractions256;
+} exact_time_256_t;
+
+/**@brief "Adjust Reason" field of the Current Time Characteristic. */
+typedef struct
+{
+ uint8_t manual_time_update : 1;
+ uint8_t external_reference_time_update : 1;
+ uint8_t change_of_time_zone : 1;
+ uint8_t change_of_daylight_savings_time : 1;
+} adjust_reason_t;
+
+/**@brief Data structure for the Current Time Characteristic. */
+typedef struct
+{
+ exact_time_256_t exact_time_256;
+ adjust_reason_t adjust_reason;
+} current_time_char_t;
+
+// Forward declaration of the ble_cts_c_t type.
+typedef struct ble_cts_c_s ble_cts_c_t;
+
+/**@brief Current Time Service client event type. */
+typedef enum
+{
+ BLE_CTS_C_EVT_DISCOVERY_COMPLETE, /**< The Current Time Service was found at the peer. */
+ BLE_CTS_C_EVT_DISCOVERY_FAILED, /**< The Current Time Service was not found at the peer. */
+ BLE_CTS_C_EVT_DISCONN_COMPLETE, /**< Event indicating that the Current Time Service client module has finished processing the BLE_GAP_EVT_DISCONNECTED event. This event is raised only if a valid instance of the Current Time Service was found at the server. The event can be used by the application to do clean up related to the Current Time Service client.*/
+ BLE_CTS_C_EVT_CURRENT_TIME, /**< A new current time reading has been received. */
+ BLE_CTS_C_EVT_INVALID_TIME /**< The current time value received from the peer is invalid.*/
+} ble_cts_c_evt_type_t;
+
+/**@brief Structure containing the handles related to the Heart Rate Service found on the peer. */
+typedef struct
+{
+ uint16_t cts_handle; /**< Handle of the Current Time characteristic as provided by the SoftDevice. */
+ uint16_t cts_cccd_handle; /**< Handle of the CCCD of the Current Time characteristic. */
+} ble_cts_c_handles_t;
+
+/**@brief Current Time Service client event. */
+typedef struct
+{
+ ble_cts_c_evt_type_t evt_type; /**< Type of event. */
+ uint16_t conn_handle; /**< Connection handle on which the CTS service was discovered on the peer device. This will be filled if the evt_type is @ref BLE_CTS_C_EVT_DISCOVERY_COMPLETE.*/
+ union
+ {
+ current_time_char_t current_time; /**< Current Time Characteristic data. This will be filled when the evt_type is @ref BLE_CTS_C_EVT_CURRENT_TIME. */
+ ble_cts_c_handles_t char_handles; /**< Current Time related handles found on the peer device. This will be filled when the evt_type is @ref BLE_HRS_C_EVT_DISCOVERY_COMPLETE.*/
+ } params;
+} ble_cts_c_evt_t;
+
+/**@brief Current Time Service client event handler type. */
+typedef void (* ble_cts_c_evt_handler_t) (ble_cts_c_t * p_cts, ble_cts_c_evt_t * p_evt);
+
+
+/**@brief Current Time Service client structure. This structure contains status information for the client. */
+struct ble_cts_c_s
+{
+ ble_cts_c_evt_handler_t evt_handler; /**< Event handler to be called for handling events from the Current Time Service client. */
+ ble_srv_error_handler_t error_handler; /**< Function to be called if an error occurs. */
+ ble_cts_c_handles_t char_handles; /**< Handles of Current Time Characteristic at the peer (handles are provided by the BLE stack through the DB Discovery module). */
+ uint16_t conn_handle; /**< Handle of the current connection. BLE_CONN_HANDLE_INVALID if not in a connection. */
+};
+
+/**@brief Current Time Service client init structure. This structure contains all options and data needed for initialization of the client.*/
+typedef struct
+{
+ ble_cts_c_evt_handler_t evt_handler; /**< Event handler to be called for handling events from the Current Time Service client. */
+ ble_srv_error_handler_t error_handler; /**< Function to be called if an error occurs. */
+} ble_cts_c_init_t;
+
+
+/**@brief Function for initializing the Current Time Service client.
+ *
+ * @details This function must be used by the application to initialize the Current Time Service client.
+ *
+ * @param[out] p_cts Current Time Service client structure. This structure must
+ * be supplied by the application. It is initialized by this
+ * function and can later be used to identify this particular client
+ * instance.
+ * @param[in] p_cts_init Information needed to initialize the Current Time Service client.
+ *
+ * @retval NRF_SUCCESS If the service was initialized successfully.
+ */
+uint32_t ble_cts_c_init(ble_cts_c_t * p_cts, const ble_cts_c_init_t * p_cts_init);
+
+
+/**@brief Function for handling events from the database discovery module.
+ *
+ * @details This function will handle an event from the database discovery module, and determine
+ * if it relates to the discovery of CTS at the peer. If so, it will
+ * call the application's event handler indicating that CTS has been
+ * discovered. It also populates the event with the service related
+ * information before providing it to the application.
+ *
+ * @param[in] p_cts Pointer to the CTS client structure.
+ * @param[in] p_evt Pointer to the event received from the database discovery module.
+ */
+ void ble_cts_c_on_db_disc_evt(ble_cts_c_t * p_cts, ble_db_discovery_evt_t * p_evt);
+
+
+/**@brief Function for handling the application's BLE stack events.
+ *
+ * @details This function handles all events from the BLE stack that are of interest to the
+ * Current Time Service client. This is a callback function that must be dispatched
+ * from main application context.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Current Time Service client structure.
+ */
+void ble_cts_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for checking whether the peer's Current Time Service instance and the Current Time
+ * Characteristic have been discovered.
+ *
+ * @param[in] p_cts Current Time Service client structure.
+ */
+static __INLINE bool ble_cts_c_is_cts_discovered(const ble_cts_c_t * p_cts)
+{
+ return (p_cts->char_handles.cts_handle != BLE_GATT_HANDLE_INVALID);
+}
+
+
+/**@brief Function for reading the peer's Current Time Service Current Time Characteristic.
+ *
+ * @param[in] p_cts Current Time Service client structure.
+ *
+ * @retval NRF_SUCCESS If the operation is successful. Otherwise, an error code is returned.
+ */
+uint32_t ble_cts_c_current_time_read(ble_cts_c_t const * p_cts);
+
+
+/**@brief Function for assigning handles to a this instance of cts_c.
+ *
+ * @details Call this function when a link has been established with a peer to
+ * associate the link to this instance of the module. This makes it
+ * possible to handle several links and associate each link to a particular
+ * instance of this module. The connection handle and attribute handles will be
+ * provided from the discovery event @ref BLE_CTS_C_EVT_DISCOVERY_COMPLETE.
+ *
+ * @param[in] p_cts Pointer to the CTS client structure instance to associate.
+ * @param[in] conn_handle Connection handle to associated with the given CTS instance.
+ * @param[in] p_peer_handles Attribute handles for the CTS server you want this CTS client to
+ * interact with.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_NULL If a p_cts was a NULL pointer.
+ */
+uint32_t ble_cts_c_handles_assign(ble_cts_c_t * p_cts,
+ const uint16_t conn_handle,
+ const ble_cts_c_handles_t * p_peer_handles);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_CTS_C_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dfu/ble_dfu.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dfu/ble_dfu.c
new file mode 100644
index 0000000..18961ef
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dfu/ble_dfu.c
@@ -0,0 +1,337 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Attention!
+ * To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+
+#include "ble_dfu.h"
+#include <string.h>
+#include "ble_hci.h"
+#include "sdk_macros.h"
+#include "ble_srv_common.h"
+#include "nrf_nvic.h"
+#include "nrf_sdm.h"
+#include "nrf_soc.h"
+#include "nrf_log.h"
+#include "nrf_dfu_ble_svci_bond_sharing.h"
+#include "nrf_bootloader_info.h"
+#include "nrf_svci_async_function.h"
+#include "nrf_pwr_mgmt.h"
+#include "peer_manager.h"
+#include "gatts_cache_manager.h"
+#include "peer_id.h"
+
+#define MAX_CTRL_POINT_RESP_PARAM_LEN 3 /**< Max length of the responses. */
+
+#define BLE_DFU_SERVICE_UUID 0xFE59 /**< The 16-bit UUID of the Secure DFU Service. */
+
+static ble_dfu_buttonless_t m_dfu; /**< Structure holding information about the Buttonless Secure DFU Service. */
+
+NRF_SDH_BLE_OBSERVER(m_dfus_obs, BLE_DFU_BLE_OBSERVER_PRIO, ble_dfu_buttonless_on_ble_evt, &m_dfu);
+
+/**@brief Function for handling write events to the Buttonless Secure DFU Service Service Control Point characteristic.
+ *
+ * @param[in] p_evt_write Write event received from the BLE stack.
+ */
+static void on_ctrlpt_write(ble_gatts_evt_write_t const * p_evt_write)
+{
+ uint32_t err_code;
+
+
+ ble_gatts_rw_authorize_reply_params_t write_authorize_reply;
+ memset(&write_authorize_reply, 0, sizeof(write_authorize_reply));
+
+ write_authorize_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
+
+ if (m_dfu.is_ctrlpt_indication_enabled)
+ {
+ write_authorize_reply.params.write.update = 1;
+ write_authorize_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ }
+ else
+ {
+ write_authorize_reply.params.write.gatt_status = DFU_RSP_CCCD_CONFIG_IMPROPER;
+ }
+
+ // Authorize the write request
+ do {
+ err_code = sd_ble_gatts_rw_authorize_reply(m_dfu.conn_handle, &write_authorize_reply);
+ } while (err_code == NRF_ERROR_BUSY);
+
+
+ if (write_authorize_reply.params.write.gatt_status != BLE_GATT_STATUS_SUCCESS)
+ {
+ return;
+ }
+
+ // Forward the write event to the Buttonless DFU module.
+ ble_dfu_buttonless_on_ctrl_pt_write(p_evt_write);
+}
+
+
+/**@brief Write authorization request event handler.
+ *
+ * @details The write authorization request event handler is called when writing to the control point.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_rw_authorize_req(ble_evt_t const * p_ble_evt)
+{
+ if (p_ble_evt->evt.gatts_evt.conn_handle != m_dfu.conn_handle)
+ {
+ return;
+ }
+
+ const ble_gatts_evt_rw_authorize_request_t * p_auth_req =
+ &p_ble_evt->evt.gatts_evt.params.authorize_request;
+
+ if (
+ (p_auth_req->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE) &&
+ (p_auth_req->request.write.handle == m_dfu.control_point_char.value_handle) &&
+ (p_auth_req->request.write.op != BLE_GATTS_OP_PREP_WRITE_REQ) &&
+ (p_auth_req->request.write.op != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW) &&
+ (p_auth_req->request.write.op != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)
+ )
+ {
+ on_ctrlpt_write(&p_auth_req->request.write);
+ }
+}
+
+
+/**@brief Connect event handler.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_connect(ble_evt_t const * p_ble_evt)
+{
+ m_dfu.conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+}
+
+
+/**@brief Disconnect event handler.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_disconnect(ble_evt_t const * p_ble_evt)
+{
+ if (m_dfu.conn_handle != p_ble_evt->evt.gatts_evt.conn_handle)
+ {
+ return;
+ }
+
+ m_dfu.conn_handle = BLE_CONN_HANDLE_INVALID;
+}
+
+
+/**@brief Write event handler.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_write(ble_evt_t const * p_ble_evt)
+{
+ const ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+ if (p_evt_write->handle != m_dfu.control_point_char.cccd_handle)
+ {
+ return;
+ }
+
+ if (p_evt_write->len == BLE_CCCD_VALUE_LEN)
+ {
+ // CCCD written, update indications state
+ m_dfu.is_ctrlpt_indication_enabled = ble_srv_is_indication_enabled(p_evt_write->data);
+
+ NRF_LOG_INFO("Received indication state %d",
+ m_dfu.is_ctrlpt_indication_enabled);
+ }
+}
+
+
+/**@brief Function for handling the HVC events.
+ *
+ * @details Handles HVC events from the BLE stack.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_hvc(ble_evt_t const * p_ble_evt)
+{
+ uint32_t err_code;
+ ble_gatts_evt_hvc_t const * p_hvc = &p_ble_evt->evt.gatts_evt.params.hvc;
+
+ if (p_hvc->handle == m_dfu.control_point_char.value_handle)
+ {
+ // Enter bootloader if we were waiting for reset after hvc indication confimation.
+ if (m_dfu.is_waiting_for_reset)
+ {
+ err_code = ble_dfu_buttonless_bootloader_start_prepare();
+ if (err_code != NRF_SUCCESS)
+ {
+ m_dfu.evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED);
+ }
+ }
+ }
+}
+
+
+void ble_dfu_buttonless_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ on_connect(p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnect(p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
+ on_rw_authorize_req(p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_WRITE:
+ on_write(p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_HVC:
+ on_hvc(p_ble_evt);
+ break;
+
+ default:
+ // no implementation
+ break;
+ }
+}
+
+
+uint32_t ble_dfu_buttonless_resp_send(ble_dfu_buttonless_op_code_t op_code, ble_dfu_buttonless_rsp_code_t rsp_code)
+{
+ // Send notification
+ uint32_t err_code;
+ const uint16_t len = 3;
+ uint16_t hvx_len;
+ uint8_t hvx_data[MAX_CTRL_POINT_RESP_PARAM_LEN];
+ ble_gatts_hvx_params_t hvx_params;
+
+ memset(&hvx_params, 0, sizeof(hvx_params));
+
+ hvx_len = len;
+ hvx_data[0] = DFU_OP_RESPONSE_CODE;
+ hvx_data[1] = (uint8_t)op_code;
+ hvx_data[2] = (uint8_t)rsp_code;
+
+ hvx_params.handle = m_dfu.control_point_char.value_handle;
+ hvx_params.type = BLE_GATT_HVX_INDICATION;
+ hvx_params.offset = 0;
+ hvx_params.p_len = &hvx_len;
+ hvx_params.p_data = hvx_data;
+
+
+ err_code = sd_ble_gatts_hvx(m_dfu.conn_handle, &hvx_params);
+ if ((err_code == NRF_SUCCESS) && (hvx_len != len))
+ {
+ err_code = NRF_ERROR_DATA_SIZE;
+ }
+
+ return err_code;
+}
+
+
+uint32_t ble_dfu_buttonless_bootloader_start_finalize(void)
+{
+ uint32_t err_code;
+
+ NRF_LOG_DEBUG("In ble_dfu_buttonless_bootloader_start_finalize\r\n");
+
+ err_code = sd_power_gpregret_clr(0, 0xffffffff);
+ VERIFY_SUCCESS(err_code);
+
+ err_code = sd_power_gpregret_set(0, BOOTLOADER_DFU_START);
+ VERIFY_SUCCESS(err_code);
+
+ // Indicate that the Secure DFU bootloader will be entered
+ m_dfu.evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER);
+
+ // Signal that DFU mode is to be enter to the power management module
+ nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_DFU);
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_dfu_buttonless_init(const ble_dfu_buttonless_init_t * p_dfu_init)
+{
+ uint32_t err_code;
+ ble_uuid_t service_uuid;
+ ble_uuid128_t nordic_base_uuid = BLE_NORDIC_VENDOR_BASE_UUID;
+
+ VERIFY_PARAM_NOT_NULL(p_dfu_init);
+
+ // Initialize the service structure.
+ m_dfu.conn_handle = BLE_CONN_HANDLE_INVALID;
+ m_dfu.evt_handler = p_dfu_init->evt_handler;
+ m_dfu.is_waiting_for_reset = false;
+ m_dfu.is_ctrlpt_indication_enabled = false;
+
+ err_code = ble_dfu_buttonless_backend_init(&m_dfu);
+ VERIFY_SUCCESS(err_code);
+
+ BLE_UUID_BLE_ASSIGN(service_uuid, BLE_DFU_SERVICE_UUID);
+
+ // Add the DFU service declaration.
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
+ &service_uuid,
+ &(m_dfu.service_handle));
+
+ VERIFY_SUCCESS(err_code);
+
+ // Add vendor specific base UUID to use with the Buttonless DFU characteristic.
+ err_code = sd_ble_uuid_vs_add(&nordic_base_uuid, &m_dfu.uuid_type);
+ VERIFY_SUCCESS(err_code);
+
+ // Add the Buttonless DFU Characteristic (with bonds/without bonds).
+ err_code = ble_dfu_buttonless_char_add(&m_dfu);
+ VERIFY_SUCCESS(err_code);
+
+ return NRF_SUCCESS;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dfu/ble_dfu.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dfu/ble_dfu.h
new file mode 100644
index 0000000..c348362
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dfu/ble_dfu.h
@@ -0,0 +1,251 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_dfu Buttonless DFU Service
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Buttonless DFU Service module.
+ *
+ * @details This module implements a proprietary Buttonless Secure DFU Service. The service can
+ * be configured to support bonds or not. The bond support configuration must correspond to the
+ * requirement of Secure DFU bootloader.
+ *
+ * @note Attention!
+ * To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+
+#ifndef BLE_DFU_H__
+#define BLE_DFU_H__
+
+#include <stdint.h>
+#include "ble_srv_common.h"
+#include "nrf_sdh_ble.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**@brief SoC observer priority.
+ * @details Priority of this module's SoC event handler.
+ */
+#define BLE_DFU_SOC_OBSERVER_PRIO 1
+
+#define BLE_DFU_BUTTONLESS_CHAR_UUID (0x0003) /**< Value combined with vendor-specific base to create Unbonded Buttonless characteristic UUID. */
+#define BLE_DFU_BUTTONLESS_BONDED_CHAR_UUID (0x0004) /**< Value combined with vendor-specific base to create Bonded Buttonless characteristic UUID. */
+
+
+/**@brief Nordic vendor-specific base UUID.
+ */
+#define BLE_NORDIC_VENDOR_BASE_UUID \
+{{ \
+ 0x50, 0xEA, 0xDA, 0x30, 0x88, 0x83, 0xB8, 0x9F, \
+ 0x60, 0x4F, 0x15, 0xF3, 0x00, 0x00, 0xC9, 0x8E \
+}}
+
+
+/**@brief Nordic Buttonless DFU Service event type .
+ */
+typedef enum
+{
+ BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE, /**< Event indicating that the device is preparing to enter bootloader.*/
+ BLE_DFU_EVT_BOOTLOADER_ENTER, /**< Event indicating that the bootloader will be entered after return of this event.*/
+ BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED, /**< Failure to enter bootloader mode.*/
+ BLE_DFU_EVT_RESPONSE_SEND_ERROR, /**< Failure to send response.*/
+} ble_dfu_buttonless_evt_type_t;
+
+
+/**@brief Nordic Buttonless DFU Service event handler type.
+ */
+typedef void (*ble_dfu_buttonless_evt_handler_t) (ble_dfu_buttonless_evt_type_t p_evt);
+/**@brief Enumeration of Bootloader DFU response codes.
+ */
+typedef enum
+{
+ DFU_RSP_INVALID = 0x00, /**< Invalid op code. */
+ DFU_RSP_SUCCESS = 0x01, /**< Success. */
+ DFU_RSP_OP_CODE_NOT_SUPPORTED = 0x02, /**< Op code not supported. */
+ DFU_RSP_OPERATION_FAILED = 0x04, /**< Operation failed. */
+ DFU_RSP_ADV_NAME_INVALID = 0x05, /**< Requested advertisement name is too short or too long. */
+ DFU_RSP_BUSY = 0x06, /**< Ongoing async operation. */
+ DFU_RSP_NOT_BONDED = 0x07, /**< Buttonless unavailable due to device not bonded. */
+ DFU_RSP_CCCD_CONFIG_IMPROPER = BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR /**< CCCD is improperly configured. */
+} ble_dfu_buttonless_rsp_code_t;
+
+
+/**@brief Enumeration of Bootloader DFU Operation codes.
+ */
+typedef enum
+{
+ DFU_OP_RESERVED = 0x00, /**< Reserved for future use. */
+ DFU_OP_ENTER_BOOTLOADER = 0x01, /**< Enter bootloader. */
+ DFU_OP_SET_ADV_NAME = 0x02, /**< Set advertisement name to use in DFU mode. */
+ DFU_OP_RESPONSE_CODE = 0x20 /**< Response code. */
+} ble_dfu_buttonless_op_code_t;
+
+
+/**@brief Type holding memory used by Secure DFU Buttonless Service.
+ */
+typedef struct
+{
+ uint8_t uuid_type; /**< UUID type for DFU UUID. */
+ uint16_t service_handle; /**< Service Handle of DFU (as provided by the SoftDevice). */
+ uint16_t conn_handle; /**< Connection handle for the current peer. */
+ ble_gatts_char_handles_t control_point_char; /**< Handles related to the DFU Control Point characteristic. */
+ uint32_t peers_count; /**< Counter to see how many persistently stored peers must be updated for Service Changed indication. This value will be counted down when comparing write requests. */
+ ble_dfu_buttonless_evt_handler_t evt_handler; /**< Event handler that is called upon Buttonless DFU events. See @ref ble_dfu_buttonless_evt_type_t. */
+ bool is_ctrlpt_indication_enabled; /**< Flag indicating that indication is enabled for the control point. */
+ bool is_waiting_for_reset; /**< Flag indicating that the device will enter bootloader. */
+ bool is_waiting_for_svci; /**< Flag indicating that the device is waiting for async SVCI operation */
+} ble_dfu_buttonless_t;
+
+
+/**@brief Type used to initialize the Secure DFU Buttonless Service.
+ */
+typedef struct
+{
+ ble_dfu_buttonless_evt_handler_t evt_handler; /**< Bootloader event handler. */
+} ble_dfu_buttonless_init_t;
+
+
+/**@brief Function for initializing the Device Firmware Update module.
+ *
+ * @param[in] p_dfu_init Structure containing the values of characteristics needed by the
+ * service.
+ * @retval NRF_SUCCESS on successful initialization of the service.
+ */
+uint32_t ble_dfu_buttonless_init(const ble_dfu_buttonless_init_t * p_dfu_init);
+
+
+/**@brief Function for initializing the async SVCI interface.
+ *
+ * @warning Ensure that no interrupts are triggered when calling this functions as
+ * interrupts and exceptions are forwarded to the bootloader for the period
+ * of the call and may be lost.
+ *
+ * @details This configures the async interface for calling to the
+ * bootloader through SVCI interface.
+ *
+ * @retval NRF_SUCCESS on success, otherwise an error code.
+ */
+uint32_t ble_dfu_buttonless_async_svci_init(void);
+
+
+/**@brief Function to initialize the backend Secure DFU Buttonless service which is either
+ * supports bonds or not.
+ *
+ * @note Do not call this function directly. It is called internally by @ref ble_dfu_buttonless_init.
+ *
+ * @param[in] p_dfu Nordic DFU Service structure.
+ *
+ * @return NRF_SUCCESS On sucessfully initializing, otherwise an error code.
+ */
+uint32_t ble_dfu_buttonless_backend_init(ble_dfu_buttonless_t * p_dfu);
+
+
+
+/**@brief Function for adding the buttonless characteristic.
+ *
+ * @note This will be implemented differently on bonded/unbonded Buttonless DFU service.
+ *
+ * @param[in] p_dfu Nordic DFU Service structure.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+uint32_t ble_dfu_buttonless_char_add(ble_dfu_buttonless_t * p_dfu);
+
+
+/**@brief Function for sending a response back to the client.
+ *
+ * @param[in] op_code Operation code to send the response for.
+ * @param[in] rsp_code Response code for the operation.
+ *
+ * @retval NRF_SUCCESS on success, otherwise an error code.
+ */
+uint32_t ble_dfu_buttonless_resp_send(ble_dfu_buttonless_op_code_t op_code, ble_dfu_buttonless_rsp_code_t rsp_code);
+
+
+/**@brief Function for handling the application's BLE stack events.
+ *
+ * @details Handles all events from the BLE stack of interest to the DFU buttonless service.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context BLE context structure.
+ */
+void ble_dfu_buttonless_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for handling control point write requests.
+ *
+ * @details Handles write requests to the control point in
+ * DFU with bonds or without bonds.
+ *
+ * @param[in] p_evt_write GATTS write event.
+ */
+void ble_dfu_buttonless_on_ctrl_pt_write(ble_gatts_evt_write_t const * p_evt_write);
+
+
+/**@brief Function for preparing to enter the bootloader.
+ *
+ * @warning This function is called directly. (It is called internally).
+ *
+ * @retval Any error code from calling @ref sd_ble_gap_disconnect.
+ */
+uint32_t ble_dfu_buttonless_bootloader_start_prepare(void);
+
+
+/**@brief Function for finalizing entering the bootloader.
+ *
+ * @warning This function is not to be called. (It is called internally).
+ *
+ * @retval NRF_SUCCESS Finalize was started correctly.
+ */
+uint32_t ble_dfu_buttonless_bootloader_start_finalize(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_DIS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dfu/ble_dfu_bonded.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dfu/ble_dfu_bonded.c
new file mode 100644
index 0000000..3189896
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dfu/ble_dfu_bonded.c
@@ -0,0 +1,407 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include "nrf_dfu_ble_svci_bond_sharing.h"
+#include "nordic_common.h"
+#include "nrf_error.h"
+#include "ble_dfu.h"
+#include "nrf_log.h"
+#include "peer_manager.h"
+#include "gatts_cache_manager.h"
+#include "peer_id.h"
+#include "nrf_sdh_soc.h"
+#include "nrf_strerror.h"
+
+#if (NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS)
+
+
+void ble_dfu_buttonless_on_sys_evt(uint32_t, void * );
+uint32_t nrf_dfu_svci_vector_table_set(void);
+uint32_t nrf_dfu_svci_vector_table_unset(void);
+
+/**@brief Define function for async interface to set peer data. */
+NRF_SVCI_ASYNC_FUNC_DEFINE(NRF_DFU_SVCI_SET_PEER_DATA, nrf_dfu_set_peer_data, nrf_dfu_peer_data_t);
+
+// Register SoC observer for the Buttonless Secure DFU service
+NRF_SDH_SOC_OBSERVER(m_dfu_buttonless_soc_obs, BLE_DFU_SOC_OBSERVER_PRIO, ble_dfu_buttonless_on_sys_evt, NULL);
+
+ble_dfu_buttonless_t * mp_dfu;
+static nrf_dfu_peer_data_t m_peer_data;
+
+
+/**@brief Function for handling Peer Manager events.
+ *
+ * @param[in] p_evt Peer Manager event.
+ */
+static void pm_evt_handler(pm_evt_t const * p_evt)
+{
+ uint32_t ret;
+
+ if (mp_dfu == NULL)
+ {
+ return;
+ }
+
+ // Only handle this when we are waiting to reset into DFU mode
+ if (!mp_dfu->is_waiting_for_reset)
+ {
+ return;
+ }
+
+ switch(p_evt->evt_id)
+ {
+ case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
+ if (p_evt->params.peer_data_update_succeeded.data_id == PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING)
+ {
+ mp_dfu->peers_count--;
+ NRF_LOG_DEBUG("Updating Service Changed indication for peers, %d left", mp_dfu->peers_count);
+ if (mp_dfu->peers_count == 0)
+ {
+ NRF_LOG_DEBUG("Finished updating Service Changed indication for peers");
+ // We have updated Service Changed Indication for all devices.
+ ret = ble_dfu_buttonless_bootloader_start_finalize();
+ if (ret != NRF_SUCCESS)
+ {
+ mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED);
+ }
+ }
+ }
+ break;
+
+ case PM_EVT_PEER_DATA_UPDATE_FAILED:
+ // Failure to update data. Service Changed cannot be sent but DFU mode is still possible
+ ret = ble_dfu_buttonless_bootloader_start_finalize();
+ if (ret != NRF_SUCCESS)
+ {
+ mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+static uint32_t retrieve_peer_data(void)
+{
+ ret_code_t ret;
+ pm_peer_data_bonding_t bonding_data = {0};
+ pm_peer_id_t peer_id;
+
+ ret = pm_peer_id_get(mp_dfu->conn_handle, &peer_id);
+ VERIFY_SUCCESS(ret);
+
+ if (peer_id == PM_PEER_ID_INVALID)
+ {
+ return NRF_ERROR_FORBIDDEN;
+ }
+
+ ret = pm_peer_data_bonding_load(peer_id, &bonding_data);
+ VERIFY_SUCCESS(ret);
+
+ memcpy(&m_peer_data.ble_id, &bonding_data.peer_ble_id, sizeof(ble_gap_id_key_t));
+ memcpy(&m_peer_data.enc_key, &bonding_data.own_ltk, sizeof(ble_gap_enc_key_t));
+
+ uint16_t len = SYSTEM_SERVICE_ATT_SIZE;
+ ret = sd_ble_gatts_sys_attr_get(mp_dfu->conn_handle,
+ m_peer_data.sys_serv_attr,
+ &len,
+ BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
+
+ NRF_LOG_DEBUG("system attribute table len: %d", len);
+
+ return ret;
+}
+
+
+/**@brief Function for entering the bootloader.
+ *
+ * @details This starts forwarding peer data to the Secure DFU bootloader.
+ */
+static uint32_t enter_bootloader(void)
+{
+ uint32_t ret;
+
+ NRF_LOG_INFO("Writing peer data to the bootloader...");
+
+ if (mp_dfu->is_waiting_for_svci)
+ {
+ return ble_dfu_buttonless_resp_send(DFU_OP_ENTER_BOOTLOADER, DFU_RSP_BUSY);
+ }
+
+ // If retrieve_peer_data returns NRF_ERROR_FORBIDDEN, then the device was not bonded.
+ ret = retrieve_peer_data();
+ VERIFY_SUCCESS(ret);
+
+ ret = nrf_dfu_set_peer_data(&m_peer_data);
+ if (ret == NRF_SUCCESS)
+ {
+ // The request was accepted. Waiting for sys events to progress.
+ mp_dfu->is_waiting_for_svci = true;
+ }
+ else if (ret == NRF_ERROR_FORBIDDEN)
+ {
+ NRF_LOG_ERROR("The bootloader has write protected its settings page. This prohibits setting the peer data. "\
+ "The bootloader must be compiled with NRF_BL_SETTINGS_PAGE_PROTECT=0 to allow setting the peer data.");
+ }
+
+ return ret;
+}
+
+
+uint32_t ble_dfu_buttonless_backend_init(ble_dfu_buttonless_t * p_dfu)
+{
+ VERIFY_PARAM_NOT_NULL(p_dfu);
+
+ // Set the memory used by the backend.
+ mp_dfu = p_dfu;
+
+ // Initialize the Peer manager handler.
+ return pm_register(&pm_evt_handler);
+}
+
+
+uint32_t ble_dfu_buttonless_async_svci_init(void)
+{
+ uint32_t ret;
+
+ // Set the vector table base address to the bootloader.
+ ret = nrf_dfu_svci_vector_table_set();
+ NRF_LOG_DEBUG("nrf_dfu_svci_vector_table_set() -> %s",
+ (ret == NRF_SUCCESS) ? "success" : nrf_strerror_get(ret));
+ VERIFY_SUCCESS(ret);
+
+ // Initialize the asynchronous SuperVisor interface to set peer data in Secure DFU bootloader.
+ ret = nrf_dfu_set_peer_data_init();
+ NRF_LOG_DEBUG("nrf_dfu_set_peer_data_init() -> %s",
+ (ret == NRF_SUCCESS) ? "success" : nrf_strerror_get(ret));
+ VERIFY_SUCCESS(ret);
+
+ // Set the vector table base address back to main application.
+ ret = nrf_dfu_svci_vector_table_unset();
+ NRF_LOG_DEBUG("nrf_dfu_svci_vector_table_unset() -> %s",
+ (ret == NRF_SUCCESS) ? "success" : nrf_strerror_get(ret));
+
+ return ret;
+}
+
+
+void ble_dfu_buttonless_on_sys_evt(uint32_t sys_evt, void * p_context)
+{
+ uint32_t ret;
+
+ if (!nrf_dfu_set_peer_data_is_initialized())
+ {
+ return;
+ }
+
+ ret = nrf_dfu_set_peer_data_on_sys_evt(sys_evt);
+ if (ret == NRF_ERROR_INVALID_STATE)
+ {
+ // The system event is not from an operation started by buttonless DFU.
+ // No action is taken, and nothing is reported.
+ }
+ else if (ret == NRF_SUCCESS)
+ {
+ // Peer data was successfully forwarded to the Secure DFU bootloader.
+ // Set the flag indicating that we are waiting for indication response
+ // to activate the reset.
+ mp_dfu->is_waiting_for_reset = true;
+ mp_dfu->is_waiting_for_svci = false;
+
+ // Report back the positive response
+ ret = ble_dfu_buttonless_resp_send(DFU_OP_ENTER_BOOTLOADER, DFU_RSP_SUCCESS);
+ if (ret != NRF_SUCCESS)
+ {
+ mp_dfu->evt_handler(BLE_DFU_EVT_RESPONSE_SEND_ERROR);
+ mp_dfu->is_waiting_for_reset = false;
+ }
+ }
+ else
+ {
+ // Failed to set peer data. Report this.
+ mp_dfu->is_waiting_for_reset = false;
+ mp_dfu->is_waiting_for_svci = false;
+ ret = ble_dfu_buttonless_resp_send(DFU_OP_ENTER_BOOTLOADER, DFU_RSP_BUSY);
+
+ // Report the failure to send the response to the client
+ if (ret != NRF_SUCCESS)
+ {
+ mp_dfu->evt_handler(BLE_DFU_EVT_RESPONSE_SEND_ERROR);
+ }
+
+ // Report the failure to enter DFU mode
+ mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED);
+ }
+}
+
+
+uint32_t ble_dfu_buttonless_char_add(ble_dfu_buttonless_t * p_dfu)
+{
+ ble_gatts_char_md_t char_md = {{0}};
+ ble_gatts_attr_md_t cccd_md = {{0}};
+ ble_gatts_attr_t attr_char_value = {0};
+ ble_gatts_attr_md_t attr_md = {{0}};
+ ble_uuid_t char_uuid;
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&cccd_md.write_perm);
+
+ cccd_md.vloc = BLE_GATTS_VLOC_STACK;
+
+ char_md.char_props.indicate = 1;
+ char_md.char_props.write = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = &cccd_md;
+ char_md.p_sccd_md = NULL;
+
+ char_uuid.type = p_dfu->uuid_type;
+ char_uuid.uuid = BLE_DFU_BUTTONLESS_BONDED_CHAR_UUID;
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.write_perm);
+
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 1;
+ attr_md.vlen = 1;
+
+ attr_char_value.p_uuid = &char_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = 0;
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = BLE_GATT_ATT_MTU_DEFAULT;
+ attr_char_value.p_value = 0;
+
+ return sd_ble_gatts_characteristic_add(p_dfu->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_dfu->control_point_char);
+}
+
+
+void ble_dfu_buttonless_on_ctrl_pt_write(ble_gatts_evt_write_t const * p_evt_write)
+{
+ uint32_t ret;
+ ble_dfu_buttonless_rsp_code_t rsp_code = DFU_RSP_OPERATION_FAILED;
+
+ // Start executing the control point write action
+ switch (p_evt_write->data[0])
+ {
+ case DFU_OP_ENTER_BOOTLOADER:
+ ret = enter_bootloader();
+ if (ret == NRF_SUCCESS)
+ {
+ rsp_code = DFU_RSP_SUCCESS;
+ }
+ else if (ret == NRF_ERROR_BUSY)
+ {
+ rsp_code = DFU_RSP_BUSY;
+ }
+ else if (ret == NRF_ERROR_FORBIDDEN)
+ {
+ rsp_code = DFU_RSP_NOT_BONDED;
+ }
+ break;
+
+ default:
+ rsp_code = DFU_RSP_OP_CODE_NOT_SUPPORTED;
+ break;
+ }
+
+ // Report back in case of error
+ if (rsp_code != DFU_RSP_SUCCESS)
+ {
+ ret = ble_dfu_buttonless_resp_send((ble_dfu_buttonless_op_code_t)p_evt_write->data[0],
+ rsp_code);
+
+ if (ret != NRF_SUCCESS)
+ {
+ mp_dfu->evt_handler(BLE_DFU_EVT_RESPONSE_SEND_ERROR);
+ }
+
+ // Report the error to the main application
+ mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED);
+ }
+}
+
+
+uint32_t ble_dfu_buttonless_bootloader_start_prepare(void)
+{
+ uint32_t ret;
+
+ NRF_LOG_DEBUG("In ble_dfu_buttonless_bootloader_start_prepare");
+
+ // Indicate to main app that DFU mode is starting.
+ // This event can be used to let the device take down any connection to
+ // bonded devices.
+ mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE);
+
+ // Disconnect from the device to enable Service Changed on next connection.
+ // (Stored in Peer Manager persistent storage for next bootup).
+ ret = sd_ble_gap_disconnect(mp_dfu->conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
+ if (ret != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Failed to disconnect GAP connection");
+ return ret;
+ }
+ else
+ {
+ NRF_LOG_DEBUG("Disconnected peer");
+ }
+
+ // Store the number of peers for which Peer Manager is expected to successfully write events.
+ mp_dfu->peers_count = peer_id_n_ids();
+
+ // Set local database changed to get Service Changed indication for all bonded peers
+ // on next bootup (either because of a successful or aborted DFU).
+ gscm_local_database_has_changed();
+
+ return ret;
+}
+
+#endif // NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dfu/ble_dfu_unbonded.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dfu/ble_dfu_unbonded.c
new file mode 100644
index 0000000..e6301bc
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dfu/ble_dfu_unbonded.c
@@ -0,0 +1,325 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include "nrf_dfu_ble_svci_bond_sharing.h"
+#include "nordic_common.h"
+#include "nrf_error.h"
+#include "ble_dfu.h"
+#include "nrf_log.h"
+#include "nrf_sdh_soc.h"
+
+#if (!NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS)
+
+#define NRF_DFU_ADV_NAME_MAX_LENGTH (20)
+
+
+void ble_dfu_buttonless_on_sys_evt(uint32_t, void * );
+uint32_t nrf_dfu_svci_vector_table_set(void);
+uint32_t nrf_dfu_svci_vector_table_unset(void);
+
+/**@brief Define functions for async interface to set new advertisement name for DFU mode. */
+NRF_SVCI_ASYNC_FUNC_DEFINE(NRF_DFU_SVCI_SET_ADV_NAME, nrf_dfu_set_adv_name, nrf_dfu_adv_name_t);
+
+// Register SoC observer for the Buttonless Secure DFU service
+NRF_SDH_SOC_OBSERVER(m_dfu_buttonless_soc_obs, BLE_DFU_SOC_OBSERVER_PRIO, ble_dfu_buttonless_on_sys_evt, NULL);
+
+ble_dfu_buttonless_t * mp_dfu = NULL;
+static nrf_dfu_adv_name_t m_adv_name;
+
+
+/**@brief Function for setting an advertisement name.
+ *
+ * @param[in] adv_name The new advertisement name.
+ *
+ * @retval NRF_SUCCESS Advertisement name was successfully set.
+ * @retval DFU_RSP_BUSY Advertisement name was not set because of an ongoing operation.
+ * @retval Any other errors from the SVCI interface call.
+ */
+static uint32_t set_adv_name(nrf_dfu_adv_name_t * p_adv_name)
+{
+ uint32_t err_code;
+
+ if (mp_dfu->is_waiting_for_svci)
+ {
+ return DFU_RSP_BUSY;
+ }
+
+ err_code = nrf_dfu_set_adv_name(p_adv_name);
+ if (err_code == NRF_SUCCESS)
+ {
+ // The request was accepted.
+ mp_dfu->is_waiting_for_svci = true;
+ }
+ else if (err_code == NRF_ERROR_FORBIDDEN)
+ {
+ NRF_LOG_ERROR("The bootloader has write protected its settings page. This prohibits setting the advertising name. "\
+ "The bootloader must be compiled with NRF_BL_SETTINGS_PAGE_PROTECT=0 to allow setting the advertising name.");
+ }
+
+ return err_code;
+}
+
+
+/**@brief Function for entering the bootloader.
+ */
+static uint32_t enter_bootloader()
+{
+ uint32_t err_code;
+
+ if (mp_dfu->is_waiting_for_svci)
+ {
+ // We have an ongoing async operation. Entering bootloader mode is not possible at this time.
+ err_code = ble_dfu_buttonless_resp_send(DFU_OP_ENTER_BOOTLOADER, DFU_RSP_BUSY);
+ if (err_code != NRF_SUCCESS)
+ {
+ mp_dfu->evt_handler(BLE_DFU_EVT_RESPONSE_SEND_ERROR);
+ }
+ return NRF_SUCCESS;
+ }
+
+ // Set the flag indicating that we expect DFU mode.
+ // This will be handled on acknowledgement of the characteristic indication.
+ mp_dfu->is_waiting_for_reset = true;
+
+ err_code = ble_dfu_buttonless_resp_send(DFU_OP_ENTER_BOOTLOADER, DFU_RSP_SUCCESS);
+ if (err_code != NRF_SUCCESS)
+ {
+ mp_dfu->is_waiting_for_reset = false;
+ }
+
+ return err_code;
+}
+
+
+uint32_t ble_dfu_buttonless_backend_init(ble_dfu_buttonless_t * p_dfu)
+{
+ VERIFY_PARAM_NOT_NULL(p_dfu);
+
+ mp_dfu = p_dfu;
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_dfu_buttonless_async_svci_init(void)
+{
+ uint32_t ret_val;
+
+ ret_val = nrf_dfu_svci_vector_table_set();
+ VERIFY_SUCCESS(ret_val);
+
+ ret_val = nrf_dfu_set_adv_name_init();
+ VERIFY_SUCCESS(ret_val);
+
+ ret_val = nrf_dfu_svci_vector_table_unset();
+
+ return ret_val;
+}
+
+
+void ble_dfu_buttonless_on_sys_evt(uint32_t sys_evt, void * p_context)
+{
+ uint32_t err_code;
+
+ if (!nrf_dfu_set_adv_name_is_initialized())
+ {
+ return;
+ }
+
+ err_code = nrf_dfu_set_adv_name_on_sys_evt(sys_evt);
+ if (err_code == NRF_ERROR_INVALID_STATE)
+ {
+ // The system event is not from an operation started by buttonless DFU.
+ // No action is taken, and nothing is reported.
+ }
+ else if (err_code == NRF_SUCCESS)
+ {
+ // The async operation is finished.
+ // Set the flag indicating that we are waiting for indication response
+ // to activate the reset.
+ mp_dfu->is_waiting_for_svci = false;
+
+ // Report back the positive response
+ err_code = ble_dfu_buttonless_resp_send(DFU_OP_SET_ADV_NAME, DFU_RSP_SUCCESS);
+ if (err_code != NRF_SUCCESS)
+ {
+ mp_dfu->evt_handler(BLE_DFU_EVT_RESPONSE_SEND_ERROR);
+ }
+ }
+ else
+ {
+ // Invalid error code reported back.
+ mp_dfu->is_waiting_for_svci = false;
+
+ err_code = ble_dfu_buttonless_resp_send(DFU_OP_SET_ADV_NAME, DFU_RSP_BUSY);
+ if (err_code != NRF_SUCCESS)
+ {
+ mp_dfu->evt_handler(BLE_DFU_EVT_RESPONSE_SEND_ERROR);
+ }
+
+ // Report the failure to enter DFU mode
+ mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED);
+ }
+}
+
+
+uint32_t ble_dfu_buttonless_char_add(ble_dfu_buttonless_t * p_dfu)
+{
+ ble_gatts_char_md_t char_md = {{0}};
+ ble_gatts_attr_md_t cccd_md = {{0}};
+ ble_gatts_attr_t attr_char_value = {0};
+ ble_gatts_attr_md_t attr_md = {{0}};
+ ble_uuid_t char_uuid;
+
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
+
+ cccd_md.vloc = BLE_GATTS_VLOC_STACK;
+
+ char_md.char_props.indicate = 1;
+ char_md.char_props.write = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = &cccd_md;
+ char_md.p_sccd_md = NULL;
+
+ char_uuid.type = p_dfu->uuid_type;
+ char_uuid.uuid = BLE_DFU_BUTTONLESS_CHAR_UUID;
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
+
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 1;
+ attr_md.vlen = 1;
+
+ attr_char_value.p_uuid = &char_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = 0;
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = BLE_GATT_ATT_MTU_DEFAULT;
+ attr_char_value.p_value = 0;
+
+ return sd_ble_gatts_characteristic_add(p_dfu->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_dfu->control_point_char);
+}
+
+
+void ble_dfu_buttonless_on_ctrl_pt_write(ble_gatts_evt_write_t const * p_evt_write)
+{
+ uint32_t err_code;
+ ble_dfu_buttonless_rsp_code_t rsp_code = DFU_RSP_OPERATION_FAILED;
+
+ // Start executing the control point write operation
+ /*lint -e415 -e416 -save "Out of bounds access"*/
+ switch (p_evt_write->data[0])
+ {
+ case DFU_OP_ENTER_BOOTLOADER:
+ err_code = enter_bootloader();
+ if (err_code == NRF_SUCCESS)
+ {
+ rsp_code = DFU_RSP_SUCCESS;
+ }
+ else if (err_code == NRF_ERROR_BUSY)
+ {
+ rsp_code = DFU_RSP_BUSY;
+ }
+ break;
+
+ case DFU_OP_SET_ADV_NAME:
+ if( (p_evt_write->data[1] > NRF_DFU_ADV_NAME_MAX_LENGTH)
+ || (p_evt_write->data[1] == 0))
+ {
+ // New advertisement name too short or too long.
+ rsp_code = DFU_RSP_ADV_NAME_INVALID;
+ }
+ else
+ {
+ memcpy(m_adv_name.name, &p_evt_write->data[2], p_evt_write->data[1]);
+ m_adv_name.len = p_evt_write->data[1];
+ err_code = set_adv_name(&m_adv_name);
+ if (err_code == NRF_SUCCESS)
+ {
+ rsp_code = DFU_RSP_SUCCESS;
+ }
+ }
+ break;
+
+ default:
+ rsp_code = DFU_RSP_OP_CODE_NOT_SUPPORTED;
+ break;
+ }
+ /*lint -restore*/
+
+
+ // Report back in case of error
+ if (rsp_code != DFU_RSP_SUCCESS)
+ {
+ err_code = ble_dfu_buttonless_resp_send((ble_dfu_buttonless_op_code_t)p_evt_write->data[0], rsp_code);
+ if (err_code != NRF_SUCCESS)
+ {
+ mp_dfu->evt_handler(BLE_DFU_EVT_RESPONSE_SEND_ERROR);
+
+ }
+ // Report the error to the main application
+ mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_FAILED);
+ }
+}
+
+uint32_t ble_dfu_buttonless_bootloader_start_prepare(void)
+{
+ uint32_t err_code;
+
+ // Indicate to main app that DFU mode is starting.
+ mp_dfu->evt_handler(BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE);
+
+ err_code = ble_dfu_buttonless_bootloader_start_finalize();
+ return err_code;
+}
+
+#endif // NRF_DFU_BOTTONLESS_SUPPORT_BOND
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dis/ble_dis.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dis/ble_dis.c
new file mode 100644
index 0000000..0b8da92
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dis/ble_dis.c
@@ -0,0 +1,304 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Attention!
+ * To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_DIS)
+#include "ble_dis.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include "app_error.h"
+#include "ble_gatts.h"
+#include "ble_srv_common.h"
+
+
+#define BLE_DIS_SYS_ID_LEN 8 /**< Length of System ID Characteristic Value. */
+#define BLE_DIS_PNP_ID_LEN 7 /**< Length of Pnp ID Characteristic Value. */
+
+static uint16_t service_handle;
+static ble_gatts_char_handles_t manufact_name_handles;
+static ble_gatts_char_handles_t model_num_handles;
+static ble_gatts_char_handles_t serial_num_handles;
+static ble_gatts_char_handles_t hw_rev_handles;
+static ble_gatts_char_handles_t fw_rev_handles;
+static ble_gatts_char_handles_t sw_rev_handles;
+static ble_gatts_char_handles_t sys_id_handles;
+static ble_gatts_char_handles_t reg_cert_data_list_handles;
+static ble_gatts_char_handles_t pnp_id_handles;
+
+
+/**@brief Function for encoding a System ID.
+ *
+ * @param[out] p_encoded_buffer Buffer where the encoded data will be written.
+ * @param[in] p_sys_id System ID to be encoded.
+ */
+static void sys_id_encode(uint8_t * p_encoded_buffer, ble_dis_sys_id_t const * p_sys_id)
+{
+ APP_ERROR_CHECK_BOOL(p_sys_id != NULL);
+ APP_ERROR_CHECK_BOOL(p_encoded_buffer != NULL);
+
+ p_encoded_buffer[0] = (p_sys_id->manufacturer_id & 0x00000000FF);
+ p_encoded_buffer[1] = (p_sys_id->manufacturer_id & 0x000000FF00) >> 8;
+ p_encoded_buffer[2] = (p_sys_id->manufacturer_id & 0x0000FF0000) >> 16;
+ p_encoded_buffer[3] = (p_sys_id->manufacturer_id & 0x00FF000000) >> 24;
+ p_encoded_buffer[4] = (p_sys_id->manufacturer_id & 0xFF00000000) >> 32;
+
+ p_encoded_buffer[5] = (p_sys_id->organizationally_unique_id & 0x0000FF);
+ p_encoded_buffer[6] = (p_sys_id->organizationally_unique_id & 0x00FF00) >> 8;
+ p_encoded_buffer[7] = (p_sys_id->organizationally_unique_id & 0xFF0000) >> 16;
+}
+
+
+/**@brief Function for encoding a PnP ID.
+ *
+ * @param[out] p_encoded_buffer Buffer where the encoded data will be written.
+ * @param[in] p_pnp_id PnP ID to be encoded.
+ */
+static void pnp_id_encode(uint8_t * p_encoded_buffer, ble_dis_pnp_id_t const * p_pnp_id)
+{
+ uint8_t len = 0;
+
+ APP_ERROR_CHECK_BOOL(p_pnp_id != NULL);
+ APP_ERROR_CHECK_BOOL(p_encoded_buffer != NULL);
+
+ p_encoded_buffer[len++] = p_pnp_id->vendor_id_source;
+
+ len += uint16_encode(p_pnp_id->vendor_id, &p_encoded_buffer[len]);
+ len += uint16_encode(p_pnp_id->product_id, &p_encoded_buffer[len]);
+ len += uint16_encode(p_pnp_id->product_version, &p_encoded_buffer[len]);
+
+ APP_ERROR_CHECK_BOOL(len == BLE_DIS_PNP_ID_LEN);
+}
+
+
+/**@brief Function for adding the Characteristic.
+ *
+ * @param[in] uuid UUID of characteristic to be added.
+ * @param[in] p_char_value Initial value of characteristic to be added.
+ * @param[in] char_len Length of initial value. This will also be the maximum value.
+ * @param[in] dis_attr_md Security settings of characteristic to be added.
+ * @param[out] p_handles Handles of new characteristic.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t char_add(uint16_t uuid,
+ uint8_t * p_char_value,
+ uint16_t char_len,
+ ble_srv_security_mode_t const * dis_attr_md,
+ ble_gatts_char_handles_t * p_handles)
+{
+ ble_uuid_t ble_uuid;
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_gatts_attr_md_t attr_md;
+
+ APP_ERROR_CHECK_BOOL(p_char_value != NULL);
+ APP_ERROR_CHECK_BOOL(char_len > 0);
+
+ // The ble_gatts_char_md_t structure uses bit fields. So we reset the memory to zero.
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = NULL;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, uuid);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.read_perm = dis_attr_md->read_perm;
+ attr_md.write_perm = dis_attr_md->write_perm;
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = char_len;
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = char_len;
+ attr_char_value.p_value = p_char_value;
+
+ return sd_ble_gatts_characteristic_add(service_handle, &char_md, &attr_char_value, p_handles);
+}
+
+
+uint32_t ble_dis_init(ble_dis_init_t const * p_dis_init)
+{
+ uint32_t err_code;
+ ble_uuid_t ble_uuid;
+
+ // Add service
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_DEVICE_INFORMATION_SERVICE);
+
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &service_handle);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add characteristics
+ if (p_dis_init->manufact_name_str.length > 0)
+ {
+ err_code = char_add(BLE_UUID_MANUFACTURER_NAME_STRING_CHAR,
+ p_dis_init->manufact_name_str.p_str,
+ p_dis_init->manufact_name_str.length,
+ &p_dis_init->dis_attr_md,
+ &manufact_name_handles);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+ if (p_dis_init->model_num_str.length > 0)
+ {
+ err_code = char_add(BLE_UUID_MODEL_NUMBER_STRING_CHAR,
+ p_dis_init->model_num_str.p_str,
+ p_dis_init->model_num_str.length,
+ &p_dis_init->dis_attr_md,
+ &model_num_handles);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+ if (p_dis_init->serial_num_str.length > 0)
+ {
+ err_code = char_add(BLE_UUID_SERIAL_NUMBER_STRING_CHAR,
+ p_dis_init->serial_num_str.p_str,
+ p_dis_init->serial_num_str.length,
+ &p_dis_init->dis_attr_md,
+ &serial_num_handles);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+ if (p_dis_init->hw_rev_str.length > 0)
+ {
+ err_code = char_add(BLE_UUID_HARDWARE_REVISION_STRING_CHAR,
+ p_dis_init->hw_rev_str.p_str,
+ p_dis_init->hw_rev_str.length,
+ &p_dis_init->dis_attr_md,
+ &hw_rev_handles);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+ if (p_dis_init->fw_rev_str.length > 0)
+ {
+ err_code = char_add(BLE_UUID_FIRMWARE_REVISION_STRING_CHAR,
+ p_dis_init->fw_rev_str.p_str,
+ p_dis_init->fw_rev_str.length,
+ &p_dis_init->dis_attr_md,
+ &fw_rev_handles);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+ if (p_dis_init->sw_rev_str.length > 0)
+ {
+ err_code = char_add(BLE_UUID_SOFTWARE_REVISION_STRING_CHAR,
+ p_dis_init->sw_rev_str.p_str,
+ p_dis_init->sw_rev_str.length,
+ &p_dis_init->dis_attr_md,
+ &sw_rev_handles);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+ if (p_dis_init->p_sys_id != NULL)
+ {
+ uint8_t encoded_sys_id[BLE_DIS_SYS_ID_LEN];
+
+ sys_id_encode(encoded_sys_id, p_dis_init->p_sys_id);
+ err_code = char_add(BLE_UUID_SYSTEM_ID_CHAR,
+ encoded_sys_id,
+ BLE_DIS_SYS_ID_LEN,
+ &p_dis_init->dis_attr_md,
+ &sys_id_handles);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+ if (p_dis_init->p_reg_cert_data_list != NULL)
+ {
+ err_code = char_add(BLE_UUID_IEEE_REGULATORY_CERTIFICATION_DATA_LIST_CHAR,
+ p_dis_init->p_reg_cert_data_list->p_list,
+ p_dis_init->p_reg_cert_data_list->list_len,
+ &p_dis_init->dis_attr_md,
+ &reg_cert_data_list_handles);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+ if (p_dis_init->p_pnp_id != NULL)
+ {
+ uint8_t encoded_pnp_id[BLE_DIS_PNP_ID_LEN];
+
+ pnp_id_encode(encoded_pnp_id, p_dis_init->p_pnp_id);
+ err_code = char_add(BLE_UUID_PNP_ID_CHAR,
+ encoded_pnp_id,
+ BLE_DIS_PNP_ID_LEN,
+ &p_dis_init->dis_attr_md,
+ &pnp_id_handles);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+#endif // NRF_MODULE_ENABLED(BLE_DIS)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dis/ble_dis.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dis/ble_dis.h
new file mode 100644
index 0000000..7c8cb9f
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dis/ble_dis.h
@@ -0,0 +1,134 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_dis Device Information Service
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Device Information Service module.
+ *
+ * @details This module implements the Device Information Service.
+ * During initialization it adds the Device Information Service to the BLE stack database.
+ * It then encodes the supplied information, and adds the corresponding characteristics.
+ *
+ * @note Attention!
+ * To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+
+#ifndef BLE_DIS_H__
+#define BLE_DIS_H__
+
+#include <stdint.h>
+#include "ble_srv_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @defgroup DIS_VENDOR_ID_SRC_VALUES Vendor ID Source values
+ * @{
+ */
+#define BLE_DIS_VENDOR_ID_SRC_BLUETOOTH_SIG 1 /**< Vendor ID assigned by Bluetooth SIG. */
+#define BLE_DIS_VENDOR_ID_SRC_USB_IMPL_FORUM 2 /**< Vendor ID assigned by USB Implementer's Forum. */
+/** @} */
+
+/**@brief System ID parameters */
+typedef struct
+{
+ uint64_t manufacturer_id; /**< Manufacturer ID. Only 5 LSOs shall be used. */
+ uint32_t organizationally_unique_id; /**< Organizationally unique ID. Only 3 LSOs shall be used. */
+} ble_dis_sys_id_t;
+
+/**@brief IEEE 11073-20601 Regulatory Certification Data List Structure */
+typedef struct
+{
+ uint8_t * p_list; /**< Pointer the byte array containing the encoded opaque structure based on IEEE 11073-20601 specification. */
+ uint8_t list_len; /**< Length of the byte array. */
+} ble_dis_reg_cert_data_list_t;
+
+/**@brief PnP ID parameters */
+typedef struct
+{
+ uint8_t vendor_id_source; /**< Vendor ID Source. see @ref DIS_VENDOR_ID_SRC_VALUES. */
+ uint16_t vendor_id; /**< Vendor ID. */
+ uint16_t product_id; /**< Product ID. */
+ uint16_t product_version; /**< Product Version. */
+} ble_dis_pnp_id_t;
+
+/**@brief Device Information Service init structure. This contains all possible characteristics
+ * needed for initialization of the service.
+ */
+typedef struct
+{
+ ble_srv_utf8_str_t manufact_name_str; /**< Manufacturer Name String. */
+ ble_srv_utf8_str_t model_num_str; /**< Model Number String. */
+ ble_srv_utf8_str_t serial_num_str; /**< Serial Number String. */
+ ble_srv_utf8_str_t hw_rev_str; /**< Hardware Revision String. */
+ ble_srv_utf8_str_t fw_rev_str; /**< Firmware Revision String. */
+ ble_srv_utf8_str_t sw_rev_str; /**< Software Revision String. */
+ ble_dis_sys_id_t * p_sys_id; /**< System ID. */
+ ble_dis_reg_cert_data_list_t * p_reg_cert_data_list; /**< IEEE 11073-20601 Regulatory Certification Data List. */
+ ble_dis_pnp_id_t * p_pnp_id; /**< PnP ID. */
+ ble_srv_security_mode_t dis_attr_md; /**< Initial Security Setting for Device Information Characteristics. */
+} ble_dis_init_t;
+
+/**@brief Function for initializing the Device Information Service.
+ *
+ * @details This call allows the application to initialize the device information service.
+ * It adds the DIS service and DIS characteristics to the database, using the initial
+ * values supplied through the p_dis_init parameter. Characteristics which are not to be
+ * added, shall be set to NULL in p_dis_init.
+ *
+ * @param[in] p_dis_init The structure containing the values of characteristics needed by the
+ * service.
+ *
+ * @return NRF_SUCCESS on successful initialization of service.
+ */
+uint32_t ble_dis_init(ble_dis_init_t const * p_dis_init);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_DIS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dis_c/ble_dis_c.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dis_c/ble_dis_c.c
new file mode 100644
index 0000000..deebdf8
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dis_c/ble_dis_c.c
@@ -0,0 +1,557 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_DIS_C)
+#include <stdlib.h>
+
+#include "ble.h"
+#include "ble_dis_c.h"
+#include "ble_gattc.h"
+#include "nrf_bitmask.h"
+#include "nrf_queue.h"
+#include "app_error.h"
+
+#define NRF_LOG_MODULE_NAME ble_dis
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+
+// Value Field lengths for System ID characteristic.
+#define BLE_DIS_C_MANUF_ID_LEN 5 /**< Length of Manufacturer ID field inside System ID characteristic. */
+#define BLE_DIS_C_OU_ID_LEN 3 /**< Length of Organizationally Unique ID field inside System ID characteristic. */
+
+// Value Field lengths for PnP ID characteristic.
+#define BLE_DIS_C_VENDOR_ID_SRC_LEN 1 /**< Length of Vendor ID Source field inside PnP ID characteristic. */
+#define BLE_DIS_C_VENDOR_ID_LEN 2 /**< Length of Vendor ID field inside PnP ID characteristic. */
+#define BLE_DIS_C_PRODUCT_ID_LEN 2 /**< Length of Product ID field inside PnP ID characteristic. */
+#define BLE_DIS_C_PRODUCT_VER_LEN 2 /**< Length of Product Version field inside PnP ID characteristic. */
+
+#define BLE_DIS_C_ALL_CHARS_DISABLED_MASK 0x0000 /**< All DIS characteristics should be disabled. */
+#define BLE_DIS_C_ALL_CHARS_ENABLED_MASK 0xFFFF /**< All DIS characteristics should be enabled. */
+
+
+/**@brief Structure for describing Client read request.
+ */
+typedef struct
+{
+ uint16_t conn_handle; /**< Connection handle for the read request. */
+ uint16_t att_handle; /**< Attribute handle for the read request. */
+} ble_dis_c_req_t;
+
+/**@brief Queue for holding Client read requests.
+ */
+NRF_QUEUE_DEF(ble_dis_c_req_t, m_ble_dis_c_queue, BLE_DIS_C_QUEUE_SIZE, NRF_QUEUE_MODE_NO_OVERFLOW);
+NRF_QUEUE_INTERFACE_DEC(ble_dis_c_req_t, ble_dis_c_queue);
+NRF_QUEUE_INTERFACE_DEF(ble_dis_c_req_t, ble_dis_c_queue, &m_ble_dis_c_queue);
+
+
+/**@brief Function for decoding System ID characteristic value.
+ *
+ * @param[in] p_data Pointer to System ID characteristic data.
+ * @param[in] len Length of the System ID characteristic data.
+ * @param[out] p_sys_id Decoded System ID characteristic.
+ *
+ * @retval NRF_SUCCESS If the characteristic was initialized successfully.
+ * @retval NRF_ERROR_INVALID_LENGTH Any parameter is NULL.
+ */
+static ret_code_t system_id_decode(uint8_t const * p_data,
+ uint16_t len,
+ ble_dis_sys_id_t * const p_sys_id)
+{
+ uint16_t const expected_len = (BLE_DIS_C_MANUF_ID_LEN + BLE_DIS_C_OU_ID_LEN);
+
+ // Validate response length.
+ if (expected_len != len)
+ {
+ NRF_LOG_ERROR("System ID characteristic data cannot be decoded.");
+ NRF_LOG_ERROR("Expected data length != Received data length: %d != %d", expected_len, len);
+ return NRF_ERROR_INVALID_LENGTH;
+ }
+
+ // Decode Manufacturer ID.
+ p_sys_id->manufacturer_id = uint40_decode(p_data);
+ p_data += BLE_DIS_C_MANUF_ID_LEN;
+
+ // Decode Organizationally unique ID.
+ p_sys_id->organizationally_unique_id = uint24_decode(p_data);
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for decoding PnP ID characteristic value.
+ *
+ * @param[in] p_data Pointer to PnP ID characteristic data.
+ * @param[in] len Length of the PnP ID characteristic data.
+ * @param[out] p_pnp_id Decoded PnP ID characteristic.
+ *
+ * @retval NRF_SUCCESS If the characteristic was initialized successfully.
+ * @retval NRF_ERROR_INVALID_LENGTH Any parameter is NULL.
+ */
+static ret_code_t pnp_id_decode(uint8_t const * p_data,
+ uint16_t len,
+ ble_dis_pnp_id_t * const p_pnp_id)
+{
+ uint16_t const expected_len = (BLE_DIS_C_VENDOR_ID_SRC_LEN + BLE_DIS_C_VENDOR_ID_LEN +
+ BLE_DIS_C_PRODUCT_ID_LEN + BLE_DIS_C_PRODUCT_VER_LEN);
+
+ // Validate response length.
+ if (expected_len != len)
+ {
+ NRF_LOG_ERROR("PnP ID characteristic data cannot be decoded.");
+ NRF_LOG_ERROR("Expected data length != Received data length: %d != %d", expected_len, len);
+ return NRF_ERROR_INVALID_LENGTH;
+ }
+
+ // Decode Vendor ID Source.
+ p_pnp_id->vendor_id_source = p_data[0];
+ p_data += BLE_DIS_C_VENDOR_ID_SRC_LEN;
+
+ // Decode Vendor ID.
+ p_pnp_id->vendor_id = uint16_decode(p_data);
+ p_data += BLE_DIS_C_VENDOR_ID_LEN;
+
+ // Decode Product ID.
+ p_pnp_id->product_id = uint16_decode(p_data);
+ p_data += BLE_DIS_C_PRODUCT_ID_LEN;
+
+ // Decode Product Version.
+ p_pnp_id->product_version = uint16_decode(p_data);
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for matching DIS Client characteristic type with the provided response handle.
+ *
+ * @param[in] p_ble_dis_c Pointer to the Device Information Client Structure.
+ * @param[in] response_handle Attribute handle from the response event.
+ */
+static ble_dis_c_char_type_t char_type_get(ble_dis_c_t * p_ble_dis_c, uint16_t response_handle)
+{
+ for (ble_dis_c_char_type_t char_type = (ble_dis_c_char_type_t) 0;
+ char_type < BLE_DIS_C_CHAR_TYPES_NUM;
+ char_type++)
+ {
+ if (response_handle == p_ble_dis_c->handles[char_type])
+ {
+ return char_type;
+ }
+ }
+ return BLE_DIS_C_CHAR_TYPES_NUM;
+}
+
+
+/**@brief Function for passing any pending request from the queue to the stack.
+ *
+ * @param[in] p_ble_dis_c Pointer to the Device Information Client Structure.
+ */
+static void queue_process(ble_dis_c_t * p_ble_dis_c)
+{
+ ret_code_t err_code;
+ ble_dis_c_req_t dis_c_req;
+
+ err_code = ble_dis_c_queue_peek(&dis_c_req);
+ if (err_code == NRF_SUCCESS) // Queue is not empty
+ {
+ err_code = sd_ble_gattc_read(dis_c_req.conn_handle,
+ dis_c_req.att_handle,
+ 0);
+ if (err_code == NRF_ERROR_BUSY) // SoftDevice is processing another Client procedure
+ {
+ NRF_LOG_DEBUG("SD is currently busy. This request for Client Read procedure will be \
+ attempted again.",
+ err_code);
+ }
+ else
+ {
+ UNUSED_RETURN_VALUE(ble_dis_c_queue_pop(&dis_c_req));
+ if (err_code == NRF_SUCCESS)
+ {
+ NRF_LOG_DEBUG("SD Read/Write API returns Success.");
+ }
+ else
+ {
+ NRF_LOG_ERROR("SD Read API returns error: 0x%08X.", err_code);
+ if (p_ble_dis_c->error_handler != NULL)
+ {
+ p_ble_dis_c->error_handler(err_code);
+ }
+ }
+ }
+ }
+}
+
+
+/**@brief Function for handling read response events.
+ *
+ * @details This function will validate the read response and raise the appropriate
+ * event to the application.
+ *
+ * @param[in] p_ble_dis_c Pointer to the Device Information Client Structure.
+ * @param[in] p_ble_evt Pointer to the SoftDevice event.
+ */
+static void on_read_rsp(ble_dis_c_t * p_ble_dis_c, ble_evt_t const * p_ble_evt)
+{
+ ret_code_t err_code;
+ ble_gattc_evt_read_rsp_t const * p_response = &p_ble_evt->evt.gattc_evt.params.read_rsp;
+ ble_dis_c_evt_t ble_dis_c_evt;
+ ble_dis_c_char_type_t char_type;
+
+ // Check if the event is on the link for this instance and the event handler is present.
+ if ((p_ble_dis_c->evt_handler == NULL) ||
+ (p_ble_dis_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle))
+ {
+ return;
+ }
+
+ char_type = char_type_get(p_ble_dis_c, p_response->handle);
+ if (char_type < BLE_DIS_C_CHAR_TYPES_NUM) // Characteristic type is valid.
+ {
+ memset(&ble_dis_c_evt, 0, sizeof(ble_dis_c_evt_t));
+
+ ble_dis_c_evt.conn_handle = p_ble_evt->evt.gattc_evt.conn_handle;
+
+ if (p_ble_evt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_SUCCESS)
+ {
+ ble_dis_c_evt_read_rsp_t * const p_dis_rsp = &ble_dis_c_evt.params.read_rsp;
+
+ ble_dis_c_evt.evt_type = BLE_DIS_C_EVT_DIS_C_READ_RSP;
+
+ p_dis_rsp->char_type = char_type;
+ p_dis_rsp->handle = p_response->handle;
+
+ // Decode characteristic value.
+ switch (char_type)
+ {
+ case BLE_DIS_C_MANUF_NAME:
+ case BLE_DIS_C_MODEL_NUM:
+ case BLE_DIS_C_SERIAL_NUM:
+ case BLE_DIS_C_HW_REV:
+ case BLE_DIS_C_FW_REV:
+ case BLE_DIS_C_SW_REV:
+ p_dis_rsp->content.string.p_data = (uint8_t *) p_response->data;
+ p_dis_rsp->content.string.len = p_response->len;
+ break;
+
+ case BLE_DIS_C_SYS_ID:
+ err_code = system_id_decode(p_response->data,
+ p_response->len,
+ &p_dis_rsp->content.sys_id);
+ if ((p_ble_dis_c->error_handler != NULL) && (err_code != NRF_SUCCESS))
+ {
+ p_ble_dis_c->error_handler(err_code);
+ }
+ break;
+
+ case BLE_DIS_C_CERT_LIST:
+ p_dis_rsp->content.cert_list.p_list = (uint8_t *) p_response->data;
+ p_dis_rsp->content.cert_list.list_len = p_response->len;
+ break;
+
+ case BLE_DIS_C_PNP_ID:
+ err_code = pnp_id_decode(p_response->data,
+ p_response->len,
+ &p_dis_rsp->content.pnp_id);
+ if ((p_ble_dis_c->error_handler != NULL) && (err_code != NRF_SUCCESS))
+ {
+ p_ble_dis_c->error_handler(err_code);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ p_ble_dis_c->evt_handler(p_ble_dis_c, &ble_dis_c_evt);
+ NRF_LOG_DEBUG("Received correct read response.");
+ }
+ else // Generate error event.
+ {
+ ble_dis_c_evt.evt_type = BLE_DIS_C_EVT_DIS_C_READ_RSP_ERROR;
+
+ ble_dis_c_evt.params.read_rsp_err.char_type = char_type;
+ ble_dis_c_evt.params.read_rsp_err.err_handle = p_ble_evt->evt.gattc_evt.error_handle;
+ ble_dis_c_evt.params.read_rsp_err.gatt_status = p_ble_evt->evt.gattc_evt.gatt_status;
+
+ p_ble_dis_c->evt_handler(p_ble_dis_c, &ble_dis_c_evt);
+ NRF_LOG_ERROR("Read request failed: 0x%04X.", p_ble_evt->evt.gattc_evt.gatt_status);
+ }
+ }
+}
+
+
+/**@brief Function for handling Disconnected event received from the SoftDevice.
+ *
+ * @details This function checks if the disconnect event is happening on the link
+ * associated with the current instance of the module. If so, it will set its
+ * conn_handle to invalid.
+ *
+ * @param[in] p_ble_dis_c Pointer to the Device Information Client Structure.
+ * @param[in] p_ble_evt Pointer to the BLE event received.
+ */
+static void on_disconnected(ble_dis_c_t * p_ble_dis_c, const ble_evt_t * p_ble_evt)
+{
+ if (p_ble_dis_c->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
+ {
+ p_ble_dis_c->conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ if (p_ble_dis_c->evt_handler != NULL)
+ {
+ ble_dis_c_evt_t dis_c_evt =
+ {
+ .evt_type = BLE_DIS_C_EVT_DISCONNECTED,
+ .conn_handle = p_ble_evt->evt.gap_evt.conn_handle
+ };
+
+ p_ble_dis_c->evt_handler(p_ble_dis_c, &dis_c_evt);
+ }
+ }
+}
+
+
+ret_code_t ble_dis_c_init(ble_dis_c_t * p_ble_dis_c, ble_dis_c_init_t * p_ble_dis_c_init)
+{
+ ble_uuid_t dis_uuid;
+
+ VERIFY_PARAM_NOT_NULL(p_ble_dis_c);
+ VERIFY_PARAM_NOT_NULL(p_ble_dis_c_init);
+
+ dis_uuid.type = BLE_UUID_TYPE_BLE;
+ dis_uuid.uuid = BLE_UUID_DEVICE_INFORMATION_SERVICE;
+
+ p_ble_dis_c->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_ble_dis_c->evt_handler = p_ble_dis_c_init->evt_handler;
+ p_ble_dis_c->error_handler = p_ble_dis_c_init->error_handler;
+ memset(p_ble_dis_c->handles, BLE_GATT_HANDLE_INVALID, sizeof(p_ble_dis_c->handles));
+
+ // Enable only selected characteristics if characteristic group is defined.
+ if (p_ble_dis_c_init->char_group.p_char_type != NULL)
+ {
+ p_ble_dis_c->char_mask = BLE_DIS_C_ALL_CHARS_DISABLED_MASK;
+
+ for (uint8_t i = 0; i < p_ble_dis_c_init->char_group.size; i++)
+ {
+ nrf_bitmask_bit_set(p_ble_dis_c_init->char_group.p_char_type[i],
+ &p_ble_dis_c->char_mask);
+ }
+ }
+ else
+ {
+ p_ble_dis_c->char_mask = BLE_DIS_C_ALL_CHARS_ENABLED_MASK;
+ }
+
+ return ble_db_discovery_evt_register(&dis_uuid);
+}
+
+
+void ble_dis_c_on_db_disc_evt(ble_dis_c_t * p_ble_dis_c, ble_db_discovery_evt_t * p_evt)
+{
+ ble_gatt_db_char_t * p_chars = p_evt->params.discovered_db.charateristics;
+ ble_dis_c_evt_t ble_dis_c_evt;
+
+ // Check if the service discovery is necessary for the link and if the event handler is present.
+ if ((p_ble_dis_c->evt_handler == NULL) ||
+ (p_ble_dis_c->conn_handle == p_evt->conn_handle))
+ {
+ return;
+ }
+
+ // Check if the DIS was discovered.
+ if ((p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE) &&
+ (p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_DEVICE_INFORMATION_SERVICE) &&
+ (p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE))
+ {
+ memset(&ble_dis_c_evt, 0, sizeof(ble_dis_c_evt_t));
+ ble_dis_c_evt.evt_type = BLE_DIS_C_EVT_DISCOVERY_COMPLETE;
+ ble_dis_c_evt.conn_handle = p_evt->conn_handle;
+
+ for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
+ {
+ switch (p_chars[i].characteristic.uuid.uuid)
+ {
+ case BLE_UUID_MANUFACTURER_NAME_STRING_CHAR:
+ ble_dis_c_evt.params.disc_complete.handles[BLE_DIS_C_MANUF_NAME] =
+ p_chars[i].characteristic.handle_value;
+ break;
+
+ case BLE_UUID_MODEL_NUMBER_STRING_CHAR:
+ ble_dis_c_evt.params.disc_complete.handles[BLE_DIS_C_MODEL_NUM] =
+ p_chars[i].characteristic.handle_value;
+ break;
+
+ case BLE_UUID_SERIAL_NUMBER_STRING_CHAR:
+ ble_dis_c_evt.params.disc_complete.handles[BLE_DIS_C_SERIAL_NUM] =
+ p_chars[i].characteristic.handle_value;
+ break;
+
+ case BLE_UUID_HARDWARE_REVISION_STRING_CHAR:
+ ble_dis_c_evt.params.disc_complete.handles[BLE_DIS_C_HW_REV] =
+ p_chars[i].characteristic.handle_value;
+ break;
+
+ case BLE_UUID_FIRMWARE_REVISION_STRING_CHAR:
+ ble_dis_c_evt.params.disc_complete.handles[BLE_DIS_C_FW_REV] =
+ p_chars[i].characteristic.handle_value;
+ break;
+
+ case BLE_UUID_SOFTWARE_REVISION_STRING_CHAR:
+ ble_dis_c_evt.params.disc_complete.handles[BLE_DIS_C_SW_REV] =
+ p_chars[i].characteristic.handle_value;
+ break;
+
+ case BLE_UUID_SYSTEM_ID_CHAR:
+ ble_dis_c_evt.params.disc_complete.handles[BLE_DIS_C_SYS_ID] =
+ p_chars[i].characteristic.handle_value;
+ break;
+
+ case BLE_UUID_IEEE_REGULATORY_CERTIFICATION_DATA_LIST_CHAR:
+ ble_dis_c_evt.params.disc_complete.handles[BLE_DIS_C_CERT_LIST] =
+ p_chars[i].characteristic.handle_value;
+ break;
+
+ case BLE_UUID_PNP_ID_CHAR:
+ ble_dis_c_evt.params.disc_complete.handles[BLE_DIS_C_PNP_ID] =
+ p_chars[i].characteristic.handle_value;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // Forget handle values for disabled characteristics
+ for (ble_dis_c_char_type_t char_type = (ble_dis_c_char_type_t) 0;
+ char_type < BLE_DIS_C_CHAR_TYPES_NUM;
+ char_type++)
+ {
+ if (!nrf_bitmask_bit_is_set(char_type, &p_ble_dis_c->char_mask))
+ {
+ ble_dis_c_evt.params.disc_complete.handles[char_type] = BLE_GATT_HANDLE_INVALID;
+ }
+ }
+
+ p_ble_dis_c->evt_handler(p_ble_dis_c, &ble_dis_c_evt);
+ }
+}
+
+
+void ble_dis_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ ble_dis_c_t * p_ble_dis_c = (ble_dis_c_t *) p_context;
+
+ if ((p_ble_dis_c == NULL) || (p_ble_evt == NULL))
+ {
+ return;
+ }
+
+ if (p_ble_dis_c->conn_handle == BLE_CONN_HANDLE_INVALID)
+ {
+ return;
+ }
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GATTC_EVT_READ_RSP:
+ on_read_rsp(p_ble_dis_c, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnected(p_ble_dis_c, p_ble_evt);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+
+ // Process any DIS Client read requests that are pending.
+ queue_process(p_ble_dis_c);
+}
+
+
+ret_code_t ble_dis_c_read(ble_dis_c_t * p_ble_dis_c, ble_dis_c_char_type_t char_type)
+{
+ ret_code_t err_code;
+ ble_dis_c_req_t dis_c_req;
+
+ VERIFY_PARAM_NOT_NULL(p_ble_dis_c);
+ VERIFY_TRUE(char_type < BLE_DIS_C_CHAR_TYPES_NUM, NRF_ERROR_INVALID_PARAM);
+
+ if ((p_ble_dis_c->conn_handle == BLE_CONN_HANDLE_INVALID) ||
+ (p_ble_dis_c->handles[char_type] == BLE_GATT_HANDLE_INVALID))
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ dis_c_req.conn_handle = p_ble_dis_c->conn_handle;
+ dis_c_req.att_handle = p_ble_dis_c->handles[char_type];
+
+ err_code = ble_dis_c_queue_push(&dis_c_req);
+ VERIFY_SUCCESS(err_code);
+
+ queue_process(p_ble_dis_c);
+ return err_code;
+}
+
+
+ret_code_t ble_dis_c_handles_assign(ble_dis_c_t * p_ble_dis_c,
+ uint16_t conn_handle,
+ ble_dis_c_handle_t const * p_peer_handles)
+{
+ VERIFY_PARAM_NOT_NULL(p_ble_dis_c);
+
+ p_ble_dis_c->conn_handle = conn_handle;
+ ble_dis_c_queue_reset();
+ if (p_peer_handles != NULL)
+ {
+ memcpy(p_ble_dis_c->handles, p_peer_handles, sizeof(p_ble_dis_c->handles));
+ }
+ else
+ {
+ memset(p_ble_dis_c->handles, BLE_GATT_HANDLE_INVALID, sizeof(p_ble_dis_c->handles));
+ }
+ return NRF_SUCCESS;
+}
+
+
+#endif // NRF_MODULE_ENABLED(BLE_DIS_C)
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dis_c/ble_dis_c.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dis_c/ble_dis_c.h
new file mode 100644
index 0000000..ce243d8
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_dis_c/ble_dis_c.h
@@ -0,0 +1,308 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/**@file
+ *
+ * @defgroup ble_dis_c Device Information Service Client
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Device information Service Client module.
+ *
+ * @details This module contains the APIs and types exposed by the Device information Service Client
+ * module. These APIs and types can be used by the application to perform discovery of
+ * the Device information Service at the peer and interact with it.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_dis_c_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_DIS_C_BLE_OBSERVER_PRIO,
+ * ble_dis_c_on_ble_evt, &instance);
+ * @endcode
+ *
+ */
+
+
+#ifndef BLE_DIS_C_H__
+#define BLE_DIS_C_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ble.h"
+#include "ble_gatt.h"
+#include "ble_db_discovery.h"
+#include "ble_srv_common.h"
+#include "ble_dis.h"
+#include "nrf_sdh_ble.h"
+
+#include "sdk_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_dis_c instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_DIS_C_DEF(_name) \
+ static ble_dis_c_t _name; \
+ NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_DIS_C_BLE_OBSERVER_PRIO, \
+ ble_dis_c_on_ble_evt, &_name)
+
+/** @brief Macro for defining multiple ble_dis_c instances.
+ *
+ * @param _name Name of the array of instances.
+ * @param _cnt Number of instances to define.
+ * @hideinitializer
+ */
+#define BLE_DIS_C_ARRAY_DEF(_name, _cnt) \
+ static ble_dis_c_t _name[_cnt]; \
+ NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
+ BLE_DIS_C_BLE_OBSERVER_PRIO, \
+ ble_dis_c_on_ble_evt, &_name, _cnt)
+
+
+/**@brief DIS Client event type. */
+typedef enum
+{
+ BLE_DIS_C_EVT_DISCOVERY_COMPLETE, /**< Event indicating that the DIS and its characteristics were discovered. See @ref ble_dis_c_evt_disc_complete_t. */
+ BLE_DIS_C_EVT_DIS_C_READ_RSP, /**< Event indicating that the client has received a read response from a peer. See @ref ble_dis_c_evt_read_rsp_t. */
+ BLE_DIS_C_EVT_DIS_C_READ_RSP_ERROR, /**< Event indicating that the client's read request has failed. See @ref ble_dis_c_evt_read_rsp_err_t. */
+ BLE_DIS_C_EVT_DISCONNECTED /**< Event indicating that the DIS server has disconnected. */
+} ble_dis_c_evt_type_t;
+
+/**@brief DIS Client characteristic type. */
+typedef enum
+{
+ BLE_DIS_C_MANUF_NAME, /**< Manufacturer Name String characteristic. */
+ BLE_DIS_C_MODEL_NUM, /**< Model Number String characteristic. */
+ BLE_DIS_C_SERIAL_NUM, /**< Serial Number String characteristic. */
+ BLE_DIS_C_HW_REV, /**< Hardware Revision String characteristic. */
+ BLE_DIS_C_FW_REV, /**< Firmware Revision String characteristic. */
+ BLE_DIS_C_SW_REV, /**< Software Revision String characteristic. */
+ BLE_DIS_C_SYS_ID, /**< System ID characteristic. */
+ BLE_DIS_C_CERT_LIST, /**< IEEE 11073-20601 Regulatory Certification Data List characteristic. */
+ BLE_DIS_C_PNP_ID, /**< PnP ID characteristic. */
+ BLE_DIS_C_CHAR_TYPES_NUM /**< Number of all possible characteristic types. */
+} ble_dis_c_char_type_t;
+
+/**@brief Attribute handle pointing to DIS characteristics on the connected peer device. */
+typedef uint16_t ble_dis_c_handle_t;
+
+/**@brief Event structure for @ref BLE_DIS_C_EVT_DISCOVERY_COMPLETE. */
+typedef struct
+{
+ ble_dis_c_handle_t handles[BLE_DIS_C_CHAR_TYPES_NUM]; /**< Handles on the connected peer device needed to interact with it. */
+} ble_dis_c_evt_disc_complete_t;
+
+/**@brief Response data for string-based DIS characteristics. */
+typedef struct
+{
+ uint8_t * p_data; /**< Pointer to response data. */
+ uint8_t len; /**< Response data length. */
+} ble_dis_c_string_t;
+
+/**@brief Event structure for @ref BLE_DIS_C_EVT_DIS_C_READ_RSP. */
+typedef struct
+{
+ ble_dis_c_char_type_t char_type; /**< Characteristic type. */
+ ble_dis_c_handle_t handle; /**< Attribute handle from the response event. */
+ union
+ {
+ ble_dis_c_string_t string; /**< String-based characteristics response data. Filled when char_type is in the following range: @ref BLE_DIS_C_MANUF_NAME - @ref BLE_DIS_C_SW_REV (inclusive). */
+ ble_dis_sys_id_t sys_id; /**< System ID characteristic response data. Filled when char_type is @ref BLE_DIS_C_SYS_ID. */
+ ble_dis_reg_cert_data_list_t cert_list; /**< IEEE 11073-20601 Regulatory Certification Data List characteristic response data. Filled when char_type is @ref BLE_DIS_C_CERT_LIST. */
+ ble_dis_pnp_id_t pnp_id; /**< PnP ID characteristic response data. Filled when char_type is @ref BLE_DIS_C_PNP_ID. */
+ } content;
+} ble_dis_c_evt_read_rsp_t;
+
+/**@brief Event structure for @ref BLE_DIS_C_EVT_DIS_C_READ_RSP_ERROR. */
+typedef struct
+{
+ ble_dis_c_char_type_t char_type; /**< Characteristic type. */
+ ble_dis_c_handle_t err_handle; /**< Attribute handle from the response event. */
+ uint16_t gatt_status; /**< GATT status code for the read operation, see @ref BLE_GATT_STATUS_CODES. */
+} ble_dis_c_evt_read_rsp_err_t;
+
+/**@brief Structure containing the DIS event data received from the peer. */
+typedef struct
+{
+ ble_dis_c_evt_type_t evt_type; /**< Type of the event. */
+ uint16_t conn_handle; /**< Connection handle on which the @ref ble_dis_c_evt_t event occurred.*/
+ union
+ {
+ ble_dis_c_evt_disc_complete_t disc_complete; /**< Discovery Complete Event Parameters. Filled when evt_type is @ref BLE_DIS_C_EVT_DISCOVERY_COMPLETE. */
+ ble_dis_c_evt_read_rsp_t read_rsp; /**< Read Response Event Parameters. Filled when evt_type is @ref BLE_DIS_C_EVT_DIS_C_READ_RSP. */
+ ble_dis_c_evt_read_rsp_err_t read_rsp_err; /**< Read Response Error Event Parameters. Filled when evt_type is @ref BLE_DIS_C_EVT_DIS_C_READ_RSP_ERROR. */
+ } params;
+} ble_dis_c_evt_t;
+
+// Forward declaration of the ble_dis_t type.
+typedef struct ble_dis_c_s ble_dis_c_t;
+
+/**@brief Event handler type.
+ *
+ * @details This is the type of the event handler that should be provided by the application
+ * of this module to receive events.
+ */
+typedef void (* ble_dis_c_evt_handler_t)(ble_dis_c_t * p_ble_dis_c, ble_dis_c_evt_t const * p_evt);
+
+/**@brief DIS Client structure. */
+struct ble_dis_c_s
+{
+ uint16_t conn_handle; /**< Handle of the current connection. Set with @ref ble_dis_c_handles_assign when connected. */
+ uint16_t char_mask; /**< Mask with enabled DIS characteristics.*/
+ ble_dis_c_handle_t handles[BLE_DIS_C_CHAR_TYPES_NUM]; /**< Handles on the connected peer device needed to interact with it. */
+ ble_srv_error_handler_t error_handler; /**< Application error handler to be called in case of an error. */
+ ble_dis_c_evt_handler_t evt_handler; /**< Application event handler to be called when there is an event related to the DIS. */
+};
+
+/**@brief Structure describing the group of DIS characteristics with which this module can interact. */
+typedef struct
+{
+ ble_dis_c_char_type_t * p_char_type; /**< Pointer to array with selected characteristics. */
+ uint8_t size; /**< Group size. */
+} ble_dis_c_char_group_t;
+
+/**@brief DIS Client initialization structure. */
+typedef struct
+{
+ ble_dis_c_char_group_t char_group; /**< Group of DIS characteristics that should be enabled for this module instance. */
+ ble_srv_error_handler_t error_handler; /**< Application error handler to be called in case of an error. */
+ ble_dis_c_evt_handler_t evt_handler; /**< Application event handler to be called when there is an event related to the Device Information service. */
+} ble_dis_c_init_t;
+
+
+/**@brief Function for initializing the Device Information service client module.
+ *
+ * @details This function registers with the Database Discovery module
+ * for the DIS. Doing so will make the Database Discovery
+ * module look for the presence of a DIS instance at the peer when a
+ * discovery is started.
+ *
+ * @param[in] p_ble_dis_c Pointer to the DIS client structure.
+ * @param[in] p_ble_dis_c_init Pointer to the DIS initialization structure containing the
+ * initialization information.
+ *
+ * @retval NRF_SUCCESS If the module was initialized successfully.
+ * @retval NRF_ERROR_NULL Any parameter is NULL.
+ * @return If functions from other modules return errors to this function
+ * (@ref ble_db_discovery_evt_register), the @ref nrf_error are propagated.
+ */
+ret_code_t ble_dis_c_init(ble_dis_c_t * p_ble_dis_c, ble_dis_c_init_t * p_ble_dis_c_init);
+
+
+/**@brief Function for handling events from the database discovery module.
+ *
+ * @details This function will handle an event from the database discovery module, and determine
+ * if it relates to the discovery of DIS at the peer. If so, it will
+ * call the application's event handler indicating that DIS has been
+ * discovered at the peer. It also populates the event with the service related
+ * information before providing it to the application.
+ *
+ * @param[in] p_ble_dis_c Pointer to the DIS client structure.
+ * @param[in] p_evt Pointer to the event received from the database discovery module.
+ */
+void ble_dis_c_on_db_disc_evt(ble_dis_c_t * p_ble_dis_c, ble_db_discovery_evt_t * p_evt);
+
+
+/**@brief Function for handling BLE events from the SoftDevice.
+ *
+ * @details This function handles the BLE events received from the SoftDevice. If a BLE
+ * event is relevant to the DIS module, it is used to update internal variables
+ * and, if necessary, send events to the application.
+ *
+ * @param[in] p_ble_evt Pointer to the BLE event.
+ * @param[in] p_context Pointer to the DIS client structure.
+ */
+void ble_dis_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for reading different characteristics from DIS.
+ *
+ * @details This function can be used to read different characteristics that are available
+ * inside DIS. The response data will be provided from the response event
+ * @ref BLE_DIS_C_EVT_DIS_C_READ_RSP. The @ref BLE_DIS_C_EVT_DIS_C_READ_RSP_ERROR
+ * event can be generated if the read operation is unsuccessful.
+ *
+ * @param[in] p_ble_dis_c Pointer to the DIS client structure.
+ * @param[in] char_type Type of characteristic to read.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_NULL If a \p p_ble_dis_c was a NULL pointer.
+ * @retval NRF_ERROR_INVALID_PARAM If a \p char_type is not valid.
+ * @retval NRF_ERROR_INVALID_STATE If connection handle or attribute handle is invalid.
+ * @retval NRF_ERROR_NO_MEM If the client request queue is full.
+ */
+ret_code_t ble_dis_c_read(ble_dis_c_t * p_ble_dis_c, ble_dis_c_char_type_t char_type);
+
+
+/**@brief Function for assigning handles to this instance of dis_c.
+ *
+ * @details Call this function when a link has been established with a peer to
+ * associate this link to this instance of the module. This makes it
+ * possible to handle several links and associate each link to a particular
+ * instance of this module. The connection handle and attribute handles will be
+ * provided from the discovery event @ref BLE_DIS_C_EVT_DISCOVERY_COMPLETE.
+ *
+ * @param[in] p_ble_dis_c Pointer to the DIS client structure instance to associate with these
+ * handles.
+ * @param[in] conn_handle Connection handle associated with the given DIS Instance.
+ * @param[in] p_peer_handles Attribute handles on the DIS server that you want this DIS client to
+ * interact with.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_NULL If a \p p_ble_dis_c was a NULL pointer.
+ */
+ret_code_t ble_dis_c_handles_assign(ble_dis_c_t * p_ble_dis_c,
+ uint16_t conn_handle,
+ ble_dis_c_handle_t const * p_peer_handles);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_DIS_C_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_escs/escs_defs.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_escs/escs_defs.h
new file mode 100644
index 0000000..0498939
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_escs/escs_defs.h
@@ -0,0 +1,133 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef ESCS_DEFS_H__
+#define ESCS_DEFS_H__
+
+#include "es.h"
+
+/*@file Contains definitions specific to the Eddystone Configuration Service */
+
+#define ESCS_LOCK_STATE_NEW_LOCK_CODE_WRITE_LENGTH 17
+
+#define ESCS_UID_READ_LENGTH (ES_UID_LENGTH)
+#define ESCS_UID_WRITE_LENGTH (ES_UID_NAMESPACE_LENGTH + \
+ ES_UID_INSTANCE_LENGTH + ES_FRAME_TYPE_LENGTH)
+
+#define ESCS_TLM_READ_LENGTH (ESCS_TLM_READ_LENGTH)
+#define ESCS_TLM_WRITE_LENGTH (ES_FRAME_TYPE_LENGTH)
+
+#define ESCS_EID_READ_LENGTH (14)
+#define ESCS_EID_WRITE_ECDH_LENGTH (34)
+#define ESCS_EID_WRITE_PUB_KEY_INDEX (1)
+#define ESCS_EID_WRITE_ENC_ID_KEY_INDEX (1)
+#define ESCS_EID_WRITE_IDK_LENGTH (18)
+
+#define ESCS_URL_MIN_WRITE_LENGTH (4)
+#define ESCS_URL_WRITE_LENGTH (19)
+
+#ifdef NRF52_SERIES
+#define ESCS_NUM_OF_SUPPORTED_TX_POWER (9)
+/**@brief TX power levels, based on nRF52 specifications. */
+#define ESCS_SUPPORTED_TX_POWER {-40, -20, -16, -12, -8, -4, 0, 3, 4}
+#elif NRF51
+/**@brief TX power levels, based on nRF51 specifications. */
+#define ESCS_NUM_OF_SUPPORTED_TX_POWER (8)
+#define ESCS_SUPPORTED_TX_POWER {-30, -20, -16, -12, -8, -4, 0, 4}
+#else
+#error MISSING TX POWER
+#endif
+
+// Defined in Eddystone Specifications
+#define ESCS_AES_KEY_SIZE (16)
+#define ESCS_ECDH_KEY_SIZE (32)
+
+#define ESCS_ADV_SLOT_CHAR_LENGTH_MAX (34) // Corresponds to when the slots is configured as an EID slot
+
+// Characteristic: Broadcast Capabilities
+
+// Field: nrf_ble_escs_init_params_t.broadcast_cap.cap_bitfield
+#define ESCS_BROADCAST_VAR_ADV_SUPPORTED_Yes (1) // Set if the beacon supports individual per-slot adv intervals
+#define ESCS_BROADCAST_VAR_ADV_SUPPORTED_No (0)
+#define ESCS_BROADCAST_VAR_ADV_SUPPORTED_Pos (0)
+#define ESCS_BROADCAST_VAR_ADV_SUPPORTED_Msk (1 << ESCS_BROADCAST_VAR_ADV_SUPPORTED_Pos)
+#define ESCS_BROADCAST_VAR_TX_POWER_SUPPORTED_Yes (1) // Set if the beacon supports individual per-slot TX intervals
+#define ESCS_BROADCAST_VAR_TX_POWER_SUPPORTED_No (0)
+#define ESCS_BROADCAST_VAR_TX_POWER_SUPPORTED_Pos (1)
+#define ESCS_BROADCAST_VAR_TX_POWER_SUPPORTED_Msk (1 << ESCS_BROADCAST_VAR_TX_POWER_SUPPORTED_Pos)
+#define ESCS_BROADCAST_VAR_RFU_MASK (0x03) // AND Mask to guarantee that bits 0x04 to 0x80 (RFU) are cleared
+
+// Field: nrf_ble_escs_init_params_t.broadcast_cap.supp_frame_types
+#define ESCS_FRAME_TYPE_UID_SUPPORTED_Yes (1)
+#define ESCS_FRAME_TYPE_UID_SUPPORTED_No (0)
+#define ESCS_FRAME_TYPE_UID_SUPPORTED_Pos (0)
+#define ESCS_FRAME_TYPE_UID_SUPPORTED_Msk (1 << ESCS_FRAME_TYPE_UID_SUPPORTED_Pos)
+
+#define ESCS_FRAME_TYPE_URL_SUPPORTED_Yes (1)
+#define ESCS_FRAME_TYPE_URL_SUPPORTED_No (0)
+#define ESCS_FRAME_TYPE_URL_SUPPORTED_Pos (1)
+#define ESCS_FRAME_TYPE_URL_SUPPORTED_Msk (1 << ESCS_FRAME_TYPE_URL_SUPPORTED_Pos)
+
+#define ESCS_FRAME_TYPE_TLM_SUPPORTED_Yes (1)
+#define ESCS_FRAME_TYPE_TLM_SUPPORTED_No (0)
+#define ESCS_FRAME_TYPE_TLM_SUPPORTED_Pos (2)
+#define ESCS_FRAME_TYPE_TLM_SUPPORTED_Msk (1 << ESCS_FRAME_TYPE_TLM_SUPPORTED_Pos)
+
+#define ESCS_FRAME_TYPE_EID_SUPPORTED_Yes (1)
+#define ESCS_FRAME_TYPE_EID_SUPPORTED_No (0)
+#define ESCS_FRAME_TYPE_EID_SUPPORTED_Pos (3)
+#define ESCS_FRAME_TYPE_EID_SUPPORTED_Msk (1 << ESCS_FRAME_TYPE_EID_SUPPORTED_Pos)
+
+#define ESCS_FRAME_TYPE_RFU_MASK (0x000F) // AND Mask to guarantee that bits 0x0010 to 0x8000 (RFU) are cleared
+
+// Characteristic: Lock State: Lock State (READ)
+#define ESCS_LOCK_STATE_LOCKED (0x00)
+#define ESCS_LOCK_STATE_UNLOCKED (0x01)
+#define ESCS_LOCK_STATE_UNLOCKED_AUTO_RELOCK_DISABLED (0x02)
+
+// Characteristic: Lock State: Lock Byte (WRITE)
+#define ESCS_LOCK_BYTE_LOCK (0x00)
+#define ESCS_LOCK_BYTE_DISABLE_AUTO_RELOCK (0x02)
+
+
+// Charcteristic: Remain Connectable
+#define ESCS_FUNCT_REMAIN_CONNECTABLE_SUPPORTED_Yes (0x01)
+#define ESCS_FUNCT_REMAIN_CONNECTABLE_SUPPORTED_No (0x00)
+
+#endif // ESCS_DEFS_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_escs/nrf_ble_escs.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_escs/nrf_ble_escs.c
new file mode 100644
index 0000000..d841c4a
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_escs/nrf_ble_escs.c
@@ -0,0 +1,675 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "nrf_ble_escs.h"
+#include <string.h>
+#include "es_app_config.h"
+
+#ifdef BLE_HANDLER_DEBUG
+ #include "SEGGER_RTT.h"
+ #define DEBUG_PRINTF SEGGER_RTT_printf
+#else
+ #define DEBUG_PRINTF(...)
+#endif
+
+#define EID_BUFF_SIZE 64
+
+typedef struct
+{
+ uint16_t uuid;
+ uint8_t read:1;
+ uint8_t write:1;
+ uint8_t rd_auth:1;
+ uint8_t wr_auth:1;
+ uint8_t vlen:1;
+ uint8_t vloc:2;
+ uint8_t init_len;
+ uint8_t max_len;
+} char_init_t;
+
+typedef struct
+{
+ uint16_t val_handle;
+ uint16_t uuid;
+} val_handle_to_uuid_t;
+
+static const char_init_t BROADCAST_CAP_CHAR_INIT =
+{
+ .uuid = BLE_UUID_ESCS_BROADCAST_CAP_CHAR,
+ .read = 1,
+ .write = 0,
+ .rd_auth = 1,
+ .wr_auth = 0,
+ .vlen = 1,
+ .vloc = BLE_GATTS_VLOC_STACK,
+ .init_len = NRF_BLE_ESCS_BROADCAST_CAP_LEN,
+ .max_len = NRF_BLE_ESCS_BROADCAST_CAP_LEN
+};
+
+static const char_init_t ACTIVE_SLOT_CHAR_INIT =
+{
+ .uuid = BLE_UUID_ESCS_ACTIVE_SLOT_CHAR,
+ .read = 1,
+ .write = 1,
+ .rd_auth = 1,
+ .wr_auth = 1,
+ .vlen = 0,
+ .vloc = BLE_GATTS_VLOC_USER,
+ .init_len = sizeof(nrf_ble_escs_active_slot_t),
+ .max_len = sizeof(nrf_ble_escs_active_slot_t)
+};
+
+static const char_init_t ADV_INTERVAL_CHAR_INIT =
+{
+ .uuid = BLE_UUID_ESCS_ADV_INTERVAL_CHAR,
+ .read = 1,
+ .write = 1,
+ .rd_auth = 1,
+ .wr_auth = 1,
+ .vlen = 0,
+ .vloc = BLE_GATTS_VLOC_STACK,
+ .init_len = sizeof(nrf_ble_escs_adv_interval_t),
+ .max_len = sizeof(nrf_ble_escs_adv_interval_t)
+};
+
+static const char_init_t RADIO_TX_PWR_CHAR_INIT =
+{
+ .uuid = BLE_UUID_ESCS_RADIO_TX_PWR_CHAR,
+ .read = 1,
+ .write = 1,
+ .rd_auth = 1,
+ .wr_auth = 1,
+ .vlen = 0,
+ .vloc = BLE_GATTS_VLOC_STACK,
+ .init_len = sizeof(nrf_ble_escs_radio_tx_pwr_t),
+ .max_len = sizeof(nrf_ble_escs_radio_tx_pwr_t)
+};
+
+static const char_init_t ADV_TX_PWR_CHAR_INIT =
+{
+ .uuid = BLE_UUID_ESCS_ADV_TX_PWR_CHAR,
+ .read = 1,
+ .write = 1,
+ .rd_auth = 1,
+ .wr_auth = 1,
+ .vlen = 0,
+ .vloc = BLE_GATTS_VLOC_STACK,
+ .init_len = sizeof(nrf_ble_escs_adv_tx_pwr_t),
+ .max_len = sizeof(nrf_ble_escs_adv_tx_pwr_t)
+};
+
+static const char_init_t LOCK_STATE_CHAR_INIT =
+{
+ .uuid = BLE_UUID_ESCS_LOCK_STATE_CHAR,
+ .read = 1,
+ .write = 1,
+ .rd_auth = 1,
+ .wr_auth = 1,
+ .vlen = 1,
+ .vloc = BLE_GATTS_VLOC_USER,
+ .init_len = 1,
+ .max_len = 17
+};
+
+static const char_init_t UNLOCK_CHAR_INIT =
+{
+ .uuid = BLE_UUID_ESCS_UNLOCK_CHAR,
+ .read = 1,
+ .write = 1,
+ .rd_auth = 1,
+ .wr_auth = 1,
+ .vlen = 0,
+ .vloc = BLE_GATTS_VLOC_STACK,
+ .init_len = 1,
+ .max_len = ESCS_AES_KEY_SIZE
+};
+
+static const char_init_t PUBLIC_ECDH_KEY_CHAR_INIT =
+{
+ .uuid = BLE_UUID_ESCS_PUBLIC_ECDH_KEY_CHAR,
+ .read = 1,
+ .write = 0,
+ .rd_auth = 1,
+ .wr_auth = 0,
+ .vlen = 1,
+ .init_len = 1,
+ .vloc = BLE_GATTS_VLOC_STACK,
+ .max_len = ESCS_ECDH_KEY_SIZE
+};
+
+static const char_init_t EID_ID_KEY_CHAR_INIT =
+{
+ .uuid = BLE_UUID_ESCS_EID_ID_KEY_CHAR,
+ .read = 1,
+ .write = 0,
+ .rd_auth = 1,
+ .wr_auth = 0,
+ .vlen = 1,
+ .vloc = BLE_GATTS_VLOC_STACK,
+ .init_len = 1,
+ .max_len = ESCS_AES_KEY_SIZE
+};
+
+static const char_init_t RW_ADV_SLOT_CHAR_INIT =
+{
+ .uuid = BLE_UUID_ESCS_RW_ADV_SLOT_CHAR,
+ .read = 1,
+ .write = 1,
+ .rd_auth = 1,
+ .wr_auth = 1,
+ .vlen = 1,
+ .vloc = BLE_GATTS_VLOC_STACK,
+ .init_len = 0,
+ .max_len = ESCS_ADV_SLOT_CHAR_LENGTH_MAX
+};
+
+static const char_init_t FACTORY_RESET_CHAR_INIT =
+{
+ .uuid = BLE_UUID_ESCS_FACTORY_RESET_CHAR,
+ .read = 0,
+ .write = 1,
+ .rd_auth = 0,
+ .wr_auth = 1,
+ .vlen = 0,
+ .vloc = BLE_GATTS_VLOC_STACK,
+ .init_len = sizeof(nrf_ble_escs_factory_reset_t),
+ .max_len = sizeof(nrf_ble_escs_factory_reset_t)
+};
+
+static const char_init_t REMAIN_CONNECTABLE_CHAR_INIT =
+{
+ .uuid = BLE_UUID_ESCS_REMAIN_CONNECTABLE_CHAR,
+ .read = 1,
+ .write = 1,
+ .rd_auth = 1,
+ .wr_auth = 1,
+ .vlen = 0,
+ .vloc = BLE_GATTS_VLOC_STACK,
+ .init_len = 1,
+ .max_len = 1
+};
+
+static val_handle_to_uuid_t m_handle_to_uuid_map[BLE_ESCS_NUMBER_OF_CHARACTERISTICS]; //!< Map from handle to UUID.
+static uint8_t m_handle_to_uuid_map_idx = 0; //!< Index of map from handle to UUID.
+static uint8_t m_eid_mem[EID_BUFF_SIZE] = {0}; //!< Memory buffer used for EID writes.
+static ble_user_mem_block_t m_eid_mem_block =
+{
+ .p_mem = m_eid_mem,
+ .len = EID_BUFF_SIZE
+}; //!< Memory block used for EID writes.
+
+
+
+/**@brief Function for adding characteristic to Eddystone service.
+ *
+ * @param[in] p_escs Eddystone Configuration Service structure.
+ * @param[in] p_escs_init Information needed to initialize the service.
+ * @param[in] p_char_init Information needed to initialize the characteristic.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t char_add(const char_init_t * p_char_init,
+ nrf_ble_escs_t * p_escs,
+ void * p_value,
+ ble_gatts_char_handles_t * p_handles)
+{
+ uint32_t err_code;
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+
+ VERIFY_PARAM_NOT_NULL(p_char_init);
+ VERIFY_PARAM_NOT_NULL(p_escs);
+ VERIFY_PARAM_NOT_NULL(p_value);
+ VERIFY_PARAM_NOT_NULL(p_handles);
+
+ memset(&char_md, 0, sizeof(char_md));
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+ memset(&ble_uuid, 0, sizeof(ble_uuid));
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ if (p_char_init->read)
+ {
+ char_md.char_props.read = 1;
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
+ }
+
+ else
+ {
+ BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm);
+ }
+
+ if (p_char_init->write)
+ {
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
+ char_md.char_props.write = 1;
+ }
+
+ else
+ {
+ BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
+ }
+
+ ble_uuid.type = p_escs->uuid_type;
+ ble_uuid.uuid = p_char_init->uuid;
+
+ attr_md.vloc = p_char_init->vloc;
+ attr_md.rd_auth = p_char_init->rd_auth;
+ attr_md.wr_auth = p_char_init->wr_auth;
+ attr_md.vlen = p_char_init->vlen;
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = p_char_init->init_len;
+ attr_char_value.p_value = p_value;
+ attr_char_value.max_len = p_char_init->max_len;
+
+ err_code = sd_ble_gatts_characteristic_add(p_escs->service_handle,
+ &char_md,
+ &attr_char_value,
+ p_handles);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ ASSERT(m_handle_to_uuid_map_idx < BLE_ESCS_NUMBER_OF_CHARACTERISTICS);
+ m_handle_to_uuid_map[m_handle_to_uuid_map_idx].val_handle = p_handles->value_handle;
+ m_handle_to_uuid_map[m_handle_to_uuid_map_idx].uuid = p_char_init->uuid;
+ m_handle_to_uuid_map_idx++;
+ }
+
+ return err_code;
+}
+
+
+/**@brief Function for handling the @ref BLE_GAP_EVT_CONNECTED event from the SoftDevice.
+ *
+ * @param[in] p_escs Eddystone Configuration Service structure.
+ * @param[in] p_ble_evt Pointer to the event received from BLE stack.
+ */
+static void on_connect(nrf_ble_escs_t * p_escs, ble_evt_t const * p_ble_evt)
+{
+ VERIFY_PARAM_NOT_NULL_VOID(p_escs);
+ p_escs->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+}
+
+
+/**@brief Function for handling the @ref BLE_GAP_EVT_DISCONNECTED event from the SoftDevice.
+ *
+ * @param[in] p_escs Eddystone Configuration Service structure.
+ * @param[in] p_ble_evt Pointer to the event received from BLE stack.
+ */
+static void on_disconnect(nrf_ble_escs_t * p_escs, ble_evt_t const * p_ble_evt)
+{
+ VERIFY_PARAM_NOT_NULL_VOID(p_escs);
+ UNUSED_PARAMETER(p_ble_evt);
+ p_escs->conn_handle = BLE_CONN_HANDLE_INVALID;
+}
+
+
+static uint32_t get_evt_type_for_handle(uint16_t handle, uint16_t * p_uuid)
+{
+ VERIFY_PARAM_NOT_NULL(p_uuid);
+
+ for (uint8_t i = 0; i < BLE_ESCS_NUMBER_OF_CHARACTERISTICS; ++i)
+ {
+ if (m_handle_to_uuid_map[i].val_handle == handle)
+ {
+ *p_uuid = m_handle_to_uuid_map[i].uuid;
+ return NRF_SUCCESS;
+ }
+ }
+
+ return NRF_ERROR_NOT_FOUND;
+}
+
+/**@brief Function for handling the @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: BLE_GATTS_AUTHORIZE_TYPE_WRITE event from the SoftDevice.
+ *
+ * @param[in] p_escs Eddystone Configuration Service structure.
+ * @param[in] p_ble_evt Pointer to the event received from BLE stack.
+ */
+static ret_code_t on_write(nrf_ble_escs_t * p_escs, ble_evt_t const * p_ble_evt)
+{
+ uint32_t err_code;
+ uint16_t write_evt_uuid = 0;
+
+ VERIFY_PARAM_NOT_NULL(p_escs);
+ VERIFY_PARAM_NOT_NULL(p_ble_evt);
+
+ ble_gatts_evt_write_t const * p_evt_write =
+ &p_ble_evt->evt.gatts_evt.params.authorize_request.request.write;
+
+ err_code = get_evt_type_for_handle(p_evt_write->handle, &write_evt_uuid);
+ RETURN_IF_ERROR(err_code);
+
+ p_escs->write_evt_handler(p_escs,
+ write_evt_uuid,
+ p_evt_write->handle,
+ p_evt_write->data,
+ p_evt_write->len);
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for handling the @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: BLE_GATTS_AUTHORIZE_TYPE_WRITE: event from the SoftDevice.
+ *
+ * @param[in] p_escs Eddystone Configuration Service structure.
+ * @param[in] p_ble_evt Pointer to the event received from BLE stack.
+ */
+static void on_long_write(nrf_ble_escs_t * p_escs, ble_evt_t const * p_ble_evt)
+{
+ static uint16_t write_evt_uuid;
+ static bool write_evt_uuid_set = false;
+ uint32_t err_code;
+
+ VERIFY_PARAM_NOT_NULL_VOID(p_escs);
+ VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
+
+ ble_gatts_evt_write_t const * p_evt_write =
+ &p_ble_evt->evt.gatts_evt.params.authorize_request.request.write;
+
+ ble_gatts_rw_authorize_reply_params_t reply = {0};
+
+ if (p_evt_write->op == BLE_GATTS_OP_PREP_WRITE_REQ)
+ {
+ err_code = get_evt_type_for_handle(p_evt_write->handle, &write_evt_uuid);
+ APP_ERROR_CHECK(err_code);
+
+ write_evt_uuid_set = true;
+
+ reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
+ reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ reply.params.write.update = 0;
+ reply.params.write.offset = 0;
+ reply.params.write.len = p_evt_write->len;
+ reply.params.write.p_data = NULL;
+
+ err_code = sd_ble_gatts_rw_authorize_reply(p_escs->conn_handle, &reply);
+ APP_ERROR_CHECK(err_code);
+ }
+
+ else if (p_evt_write->op == BLE_GATTS_OP_EXEC_WRITE_REQ_NOW)
+ {
+ uint8_t value_buffer[ESCS_ADV_SLOT_CHAR_LENGTH_MAX] = {0};
+ ble_gatts_value_t value =
+ {
+ .len = sizeof(value_buffer),
+ .offset = 0,
+ .p_value = &(value_buffer[0])
+ };
+
+ ASSERT(write_evt_uuid_set);
+ write_evt_uuid_set = false;
+
+ reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
+ reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ reply.params.write.update = 0;
+ reply.params.write.offset = 0;
+ reply.params.write.len = p_evt_write->len;
+ reply.params.write.p_data = NULL;
+
+ err_code = sd_ble_gatts_rw_authorize_reply(p_escs->conn_handle, &reply);
+ APP_ERROR_CHECK(err_code);
+
+ // Now that the value has been accepted using 'sd_ble_gatts_rw_authorize_reply', it can be found in the database.
+ err_code = sd_ble_gatts_value_get( p_escs->conn_handle,
+ p_escs->rw_adv_slot_handles.value_handle,
+ &value);
+ APP_ERROR_CHECK(err_code);
+
+ p_escs->write_evt_handler(p_escs,
+ write_evt_uuid,
+ p_evt_write->handle,
+ value.p_value,
+ value.len);
+ }
+ else
+ {
+ }
+}
+
+
+/**@brief Function for handling events from the SoftDevice related to long writes.
+ *
+ * @param[in] p_escs Eddystone Configuration Service structure.
+ * @param[in] p_ble_evt Pointer to the event received from BLE stack.
+ */
+static ret_code_t on_read(nrf_ble_escs_t * p_escs, ble_evt_t const * p_ble_evt)
+{
+ VERIFY_PARAM_NOT_NULL(p_escs);
+ VERIFY_PARAM_NOT_NULL(p_ble_evt);
+ ret_code_t err_code;
+ uint16_t read_evt_uuid = 0;
+ uint16_t val_handle = p_ble_evt->evt.gatts_evt.params.authorize_request.request.read.handle;
+ err_code = get_evt_type_for_handle(val_handle, &read_evt_uuid);
+ RETURN_IF_ERROR(err_code);
+
+ p_escs->read_evt_handler(p_escs, read_evt_uuid, val_handle);
+
+ return NRF_SUCCESS;
+}
+
+
+static ret_code_t on_rw_authorize_req(nrf_ble_escs_t * p_escs, ble_evt_t const * p_ble_evt)
+{
+ ret_code_t err_code;
+ VERIFY_PARAM_NOT_NULL(p_escs);
+ VERIFY_PARAM_NOT_NULL(p_ble_evt);
+
+ ble_gatts_evt_rw_authorize_request_t const * ar =
+ &p_ble_evt->evt.gatts_evt.params.authorize_request;
+
+ if (ar->type == BLE_GATTS_AUTHORIZE_TYPE_READ)
+ {
+ err_code = on_read(p_escs, p_ble_evt);
+ RETURN_IF_ERROR(err_code);
+ }
+ else if (ar->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
+ {
+ if (ar->request.write.op == BLE_GATTS_OP_WRITE_REQ
+ || ar->request.write.op == BLE_GATTS_OP_WRITE_CMD)
+ {
+ err_code = on_write(p_escs, p_ble_evt);
+ RETURN_IF_ERROR(err_code);
+ }
+
+ else if (ar->request.write.op == BLE_GATTS_OP_PREP_WRITE_REQ
+ || ar->request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_NOW)
+ {
+ on_long_write(p_escs, p_ble_evt);
+ }
+ else if (ar->request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)
+ {
+ ble_gatts_rw_authorize_reply_params_t auth_reply;
+ memset(&auth_reply, 0, sizeof(auth_reply));
+
+ auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
+ auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+
+ err_code = sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gatts_evt.conn_handle, &auth_reply);
+ VERIFY_SUCCESS(err_code);
+ }
+ else
+ {
+ }
+ }
+ else
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+
+ret_code_t nrf_ble_escs_on_ble_evt(nrf_ble_escs_t * p_escs, ble_evt_t const * p_ble_evt)
+{
+ ret_code_t err_code;
+
+ VERIFY_PARAM_NOT_NULL(p_escs);
+ VERIFY_PARAM_NOT_NULL(p_ble_evt);
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ on_connect(p_escs, p_ble_evt);
+
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnect(p_escs, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
+ err_code = on_rw_authorize_req(p_escs, p_ble_evt);
+ VERIFY_SUCCESS(err_code);
+ break;
+
+ // BLE_EVT_USER_MEM_REQUEST & BLE_EVT_USER_MEM_RELEASE are for long writes to the RW ADV slot characteristic
+ case BLE_EVT_USER_MEM_REQUEST:
+ err_code = sd_ble_user_mem_reply(p_escs->conn_handle, &m_eid_mem_block);
+ VERIFY_SUCCESS(err_code);
+ break;
+
+ case BLE_EVT_USER_MEM_RELEASE:
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t nrf_ble_escs_init(nrf_ble_escs_t * p_escs, const nrf_ble_escs_init_t * p_escs_init)
+{
+ uint32_t err_code;
+ ble_uuid_t ble_uuid;
+ ble_uuid128_t ecs_base_uuid = ESCS_BASE_UUID;
+ uint8_t zero_val = 0;
+
+ VERIFY_PARAM_NOT_NULL(p_escs);
+ VERIFY_PARAM_NOT_NULL(p_escs_init);
+
+ // Initialize the service structure.
+ p_escs->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_escs->write_evt_handler = p_escs_init->write_evt_handler;
+ p_escs->read_evt_handler = p_escs_init->read_evt_handler;
+
+ // Add a custom base UUID.
+ err_code = sd_ble_uuid_vs_add(&ecs_base_uuid, &p_escs->uuid_type);
+ VERIFY_SUCCESS(err_code);
+
+ ble_uuid.type = p_escs->uuid_type;
+ ble_uuid.uuid = BLE_UUID_ESCS_SERVICE;
+
+ // Add the service.
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
+ &ble_uuid,
+ &p_escs->service_handle);
+ VERIFY_SUCCESS(err_code);
+
+ m_handle_to_uuid_map_idx = 0;
+
+ // Set up initial values for characteristics
+
+ // Eddystone spec requires big endian
+ nrf_ble_escs_broadcast_cap_t temp = p_escs_init->p_init_vals->broadcast_cap;
+ temp.supp_frame_types = BYTES_SWAP_16BIT(temp.supp_frame_types);
+
+ nrf_ble_escs_adv_interval_t temp_interval = p_escs_init->p_init_vals->adv_interval;
+ temp_interval = BYTES_SWAP_16BIT(temp_interval);
+
+ // Adding chracteristics
+
+ err_code = char_add(&BROADCAST_CAP_CHAR_INIT, p_escs,
+ &temp, &p_escs->broadcast_cap_handles);
+ VERIFY_SUCCESS(err_code);
+
+ err_code = char_add(&ACTIVE_SLOT_CHAR_INIT, p_escs,
+ p_escs->p_active_slot, &p_escs->active_slot_handles);
+ VERIFY_SUCCESS(err_code);
+
+ err_code = char_add(&ADV_INTERVAL_CHAR_INIT, p_escs,
+ &temp_interval, &p_escs->adv_interval_handles);
+ VERIFY_SUCCESS(err_code);
+
+ err_code = char_add(&RADIO_TX_PWR_CHAR_INIT, p_escs,
+ &(p_escs_init->p_init_vals->radio_tx_pwr), &p_escs->radio_tx_pwr_handles);
+ VERIFY_SUCCESS(err_code);
+
+ err_code = char_add(&ADV_TX_PWR_CHAR_INIT, p_escs,
+ &(p_escs_init->p_init_vals->adv_tx_pwr), &p_escs->adv_tx_pwr_handles);
+ VERIFY_SUCCESS(err_code);
+
+ err_code = char_add(&LOCK_STATE_CHAR_INIT, p_escs,
+ p_escs->p_lock_state, &p_escs->lock_state_handles);
+ VERIFY_SUCCESS(err_code);
+
+ err_code = char_add(&UNLOCK_CHAR_INIT, p_escs,
+ &zero_val, &p_escs->unlock_handles);
+ VERIFY_SUCCESS(err_code);
+
+ err_code = char_add(&PUBLIC_ECDH_KEY_CHAR_INIT, p_escs,
+ &zero_val, &p_escs->pub_ecdh_key_handles);
+ VERIFY_SUCCESS(err_code);
+
+ err_code = char_add(&EID_ID_KEY_CHAR_INIT, p_escs,
+ &zero_val, &p_escs->eid_id_key_handles);
+ VERIFY_SUCCESS(err_code);
+
+ err_code = char_add(&RW_ADV_SLOT_CHAR_INIT, p_escs,
+ &zero_val, &p_escs->rw_adv_slot_handles);
+ VERIFY_SUCCESS(err_code);
+
+ err_code = char_add(&FACTORY_RESET_CHAR_INIT, p_escs,
+ &(p_escs_init->p_init_vals->factory_reset), &p_escs->factory_reset_handles);
+ VERIFY_SUCCESS(err_code);
+
+ err_code = char_add(&REMAIN_CONNECTABLE_CHAR_INIT, p_escs,
+ &(p_escs_init->p_init_vals->remain_connectable.r_is_non_connectable_supported),
+ &p_escs->remain_connectable_handles);
+ VERIFY_SUCCESS(err_code);
+
+ return NRF_SUCCESS;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_escs/nrf_ble_escs.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_escs/nrf_ble_escs.h
new file mode 100644
index 0000000..77bb5ae
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_escs/nrf_ble_escs.h
@@ -0,0 +1,259 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef NRF_BLE_ESCS_H__
+#define NRF_BLE_ESCS_H__
+
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "app_util_platform.h"
+#include "sdk_common.h"
+#include "escs_defs.h"
+#include <stdint.h>
+#include <stdbool.h>
+
+
+/**
+ * @file
+ * @defgroup nrf_ble_escs Eddystone Configuration Service
+ * @brief Eddystone Configuration Service module.
+ * @ingroup ble_sdk_srv
+ * @{
+ */
+
+#define BLE_ESCS_NUMBER_OF_CHARACTERISTICS 13 //!< Number of characteristics contained in the Eddystone Configuration Service.
+
+#define BLE_UUID_ESCS_SERVICE 0x7500 //!< UUID of the Eddystone Configuration Service.
+
+// ECS UUIDs
+#define BLE_UUID_ESCS_BROADCAST_CAP_CHAR 0x7501
+#define BLE_UUID_ESCS_ACTIVE_SLOT_CHAR 0x7502
+#define BLE_UUID_ESCS_ADV_INTERVAL_CHAR 0x7503
+#define BLE_UUID_ESCS_RADIO_TX_PWR_CHAR 0x7504
+#define BLE_UUID_ESCS_ADV_TX_PWR_CHAR 0x7505
+#define BLE_UUID_ESCS_LOCK_STATE_CHAR 0x7506
+#define BLE_UUID_ESCS_UNLOCK_CHAR 0x7507
+#define BLE_UUID_ESCS_PUBLIC_ECDH_KEY_CHAR 0x7508
+#define BLE_UUID_ESCS_EID_ID_KEY_CHAR 0x7509
+#define BLE_UUID_ESCS_RW_ADV_SLOT_CHAR 0x750A
+#define BLE_UUID_ESCS_FACTORY_RESET_CHAR 0x750B
+#define BLE_UUID_ESCS_REMAIN_CONNECTABLE_CHAR 0x750C
+
+#define ESCS_BASE_UUID \
+ {{0x95, 0xE2, 0xED, 0xEB, 0x1B, 0xA0, 0x39, 0x8A, 0xDF, 0x4B, 0xD3, 0x8E, 0x00, 0x00, 0xC8, \
+ 0xA3}}
+// A3C8XXXX-8ED3-4BDF-8A39-A01BEBEDE295
+
+#define NRF_BLE_ESCS_BROADCAST_CAP_LEN (ESCS_NUM_OF_SUPPORTED_TX_POWER + 6) // According to the eddystone spec, there are 6 bytes of data in addition to the supported_radio_tx_power array
+
+
+/**@brief Data fields in the Broadcast Capabilities characteristic.
+ * @note This is a packed structure. Therefore, you should not change it.
+ */
+typedef PACKED_STRUCT
+{
+ int8_t vers_byte;
+ int8_t max_supp_total_slots;
+ int8_t max_supp_eid_slots;
+ int8_t cap_bitfield;
+ int16_t supp_frame_types;
+ int8_t supp_radio_tx_power[ESCS_NUM_OF_SUPPORTED_TX_POWER];
+} nrf_ble_escs_broadcast_cap_t;
+
+typedef uint8_t nrf_ble_escs_active_slot_t;
+typedef uint16_t nrf_ble_escs_adv_interval_t;
+typedef int8_t nrf_ble_escs_radio_tx_pwr_t;
+typedef int8_t nrf_ble_escs_adv_tx_pwr_t;
+
+/**@brief Read states of the Lock State characteristic. */
+typedef enum
+{
+ NRF_BLE_ESCS_LOCK_STATE_LOCKED = ESCS_LOCK_STATE_LOCKED,
+ NRF_BLE_ESCS_LOCK_STATE_UNLOCKED = ESCS_LOCK_STATE_UNLOCKED,
+ NRF_BLE_ESCS_LOCK_STATE_UNLOCKED_AUTO_RELOCK_DISABLED =
+ ESCS_LOCK_STATE_UNLOCKED_AUTO_RELOCK_DISABLED
+} nrf_ble_escs_lock_state_read_t;
+
+/**@brief Write bytes of the Lock State characteristic. */
+typedef enum
+{
+ NRF_BLE_ESCS_LOCK_BYTE_LOCK = ESCS_LOCK_BYTE_LOCK,
+ NRF_BLE_ESCS_LOCK_BYTE_DISABLE_AUTO_RELOCK = ESCS_LOCK_BYTE_DISABLE_AUTO_RELOCK
+} nrf_ble_escs_lock_byte_t;
+
+/**@brief Write data fields of the Lock State characteristic.
+ * @note This is a packed structure. Therefore, you should not change it.
+*/
+typedef PACKED_STRUCT
+{
+ nrf_ble_escs_lock_byte_t lock_byte;
+ int8_t encrypted_key[ESCS_AES_KEY_SIZE];
+} nrf_ble_escs_lock_state_write_t;
+
+/**@brief Lock State characteristic. */
+typedef union
+{
+ nrf_ble_escs_lock_state_read_t read;
+ nrf_ble_escs_lock_state_write_t write;
+} nrf_ble_escs_lock_state_t;
+
+/**@brief Unlock characteristic (read/write). */
+typedef union
+{
+ int8_t r_challenge[ESCS_AES_KEY_SIZE];
+ int8_t w_unlock_token[ESCS_AES_KEY_SIZE];
+} nrf_ble_escs_unlock_t;
+
+/**@brief Public ECDH Key characteristic.
+ * @note This is a packed structure. Therefore, you should not change it.
+*/
+typedef PACKED_STRUCT
+{
+ int8_t key[ESCS_ECDH_KEY_SIZE];
+} nrf_ble_escs_public_ecdh_key_t;
+
+/**@brief EID Identity Key characteristic.
+ * @note This is a packed structure. Therefore, you should not change it.
+*/
+typedef PACKED_STRUCT
+{
+ int8_t key[ESCS_AES_KEY_SIZE];
+} nrf_ble_escs_eid_id_key_t;
+
+
+typedef uint8_t nrf_ble_escs_factory_reset_t;
+
+/**@brief Unlock characteristic (read/write). */
+typedef union
+{
+ uint8_t r_is_non_connectable_supported;
+ uint8_t w_remain_connectable_boolean;
+} nrf_ble_escs_remain_conntbl_t;
+
+/**@brief Eddystone Configuration Service initialization parameters (corresponding to required characteristics). */
+typedef struct
+{
+ nrf_ble_escs_broadcast_cap_t broadcast_cap;
+ nrf_ble_escs_adv_interval_t adv_interval;
+ nrf_ble_escs_radio_tx_pwr_t radio_tx_pwr;
+ nrf_ble_escs_adv_tx_pwr_t adv_tx_pwr;
+ nrf_ble_escs_factory_reset_t factory_reset;
+ nrf_ble_escs_remain_conntbl_t remain_connectable;
+} nrf_ble_escs_init_params_t;
+
+// Forward Declaration of nrf_ble_escs_t type.
+typedef struct nrf_ble_escs_s nrf_ble_escs_t;
+
+typedef void (*nrf_ble_escs_write_evt_handler_t)(nrf_ble_escs_t * p_escs,
+ uint16_t uuid,
+ uint16_t value_handle,
+ uint8_t const * p_data,
+ uint16_t length);
+
+typedef void (*nrf_ble_escs_read_evt_handler_t)(nrf_ble_escs_t * p_escs,
+ uint16_t uuid,
+ uint16_t value_handle);
+
+/**@brief Eddystone Configuration Service initialization structure.
+ *
+ * @details This structure contains the initialization information for the service. The application
+ * must fill this structure and pass it to the service using the @ref nrf_ble_escs_init
+ * function.
+ */
+typedef struct
+{
+ nrf_ble_escs_init_params_t * p_init_vals; //!< Initialization parameters for the service.
+ nrf_ble_escs_write_evt_handler_t write_evt_handler; //!< Event handler to be called for authorizing write requests.
+ nrf_ble_escs_read_evt_handler_t read_evt_handler; //!< Event handler to be called for authorizing read requests.
+} nrf_ble_escs_init_t;
+
+struct nrf_ble_escs_s
+{
+ uint8_t uuid_type; //!< UUID type for the Eddystone Configuration Service Base UUID.
+ uint16_t service_handle; //!< Handle of the Eddystone Configuration Service (as provided by the SoftDevice).
+ ble_gatts_char_handles_t broadcast_cap_handles; //!< Handles related to the Capabilities characteristic (as provided by the SoftDevice).
+ ble_gatts_char_handles_t active_slot_handles; //!< Handles related to the Active Slot characteristic (as provided by the SoftDevice).
+ ble_gatts_char_handles_t adv_interval_handles; //!< Handles related to the Advertising Interval characteristic (as provided by the SoftDevice).
+ ble_gatts_char_handles_t radio_tx_pwr_handles; //!< Handles related to the Radio Tx Power characteristic (as provided by the SoftDevice).
+ ble_gatts_char_handles_t adv_tx_pwr_handles; //!< Handles related to the (Advanced) Advertised Tx Power characteristic (as provided by the SoftDevice).
+ ble_gatts_char_handles_t lock_state_handles; //!< Handles related to the Lock State characteristic (as provided by the SoftDevice).
+ ble_gatts_char_handles_t unlock_handles; //!< Handles related to the Unlock characteristic (as provided by the SoftDevice).
+ ble_gatts_char_handles_t pub_ecdh_key_handles; //!< Handles related to the Public ECDH Key characteristic (as provided by the SoftDevice).
+ ble_gatts_char_handles_t eid_id_key_handles; //!< Handles related to the EID Identity Key characteristic (as provided by the SoftDevice).
+ ble_gatts_char_handles_t rw_adv_slot_handles; //!< Handles related to the ADV Slot Data characteristic (as provided by the SoftDevice).
+ ble_gatts_char_handles_t factory_reset_handles; //!< Handles related to the (Advanced) Factory reset characteristic (as provided by the SoftDevice).
+ ble_gatts_char_handles_t remain_connectable_handles; //!< Handles related to the (Advanced) Remain Connectable characteristic (as provided by the SoftDevice).
+ uint16_t conn_handle; //!< Handle of the current connection (as provided by the SoftDevice). @ref BLE_CONN_HANDLE_INVALID if not in a connection.
+ nrf_ble_escs_write_evt_handler_t write_evt_handler; //!< Event handler to be called for handling write attempts.
+ nrf_ble_escs_read_evt_handler_t read_evt_handler; //!< Event handler to be called for handling read attempts.
+ uint8_t * p_active_slot;
+ nrf_ble_escs_lock_state_read_t * p_lock_state;
+};
+
+
+/**@brief Function for initializing the Eddystone Configuration Service.
+ *
+ * @param[out] p_escs Eddystone Configuration Service structure. This structure must be supplied
+ * by the application. It is initialized by this function and will
+ * later be used to identify this particular service instance.
+ * @param[in] p_ecs_init Information needed to initialize the service.
+ *
+ * @retval NRF_SUCCESS If the service was successfully initialized. Otherwise, an error code is returned.
+ * @retval NRF_ERROR_NULL If either of the pointers @p p_escs or @p p_ecs_init is NULL.
+ */
+ret_code_t nrf_ble_escs_init(nrf_ble_escs_t * p_escs, const nrf_ble_escs_init_t * p_ecs_init);
+
+/**@brief Function for handling the Eddystone Configuration Service's BLE events.
+ *
+ * @details The Eddystone Configuration Service expects the application to call this function each time an
+ * event is received from the SoftDevice. This function processes the event if it
+ * is relevant and calls the Eddystone Configuration Service event handler of the
+ * application if necessary.
+ *
+ * @param[in] p_escs Eddystone Configuration Service structure.
+ * @param[in] p_ble_evt Event received from the SoftDevice.
+ *
+ * @retval NRF_ERROR_NULL If any of the arguments given are NULL.
+ * @retval NRF_SUCCESS otherwise.
+ */
+ret_code_t nrf_ble_escs_on_ble_evt(nrf_ble_escs_t * p_escs, ble_evt_t const * p_ble_evt);
+
+/** @} */
+
+#endif // NRF_BLE_ESCS_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_gls/ble_gls.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_gls/ble_gls.c
new file mode 100644
index 0000000..2fe5f70
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_gls/ble_gls.c
@@ -0,0 +1,1314 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Attention!
+ * To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+
+#include "sdk_common.h"
+
+#if NRF_MODULE_ENABLED(BLE_GLS)
+
+#include "ble_gls.h"
+#include <string.h>
+#include "ble_gls_db.h"
+#include "ble_racp.h"
+#include "ble_srv_common.h"
+
+
+#define OPERAND_FILTER_TYPE_SEQ_NUM 0x01 /**< Filter data using Sequence Number criteria. */
+#define OPERAND_FILTER_TYPE_FACING_TIME 0x02 /**< Filter data using User Facing Time criteria. */
+#define OPERAND_FILTER_TYPE_RFU_START 0x07 /**< Start of filter types reserved For Future Use range */
+#define OPERAND_FILTER_TYPE_RFU_END 0xFF /**< End of filter types reserved For Future Use range */
+
+#define OPCODE_LENGTH 1 /**< Length of opcode inside Glucose Measurement packet. */
+#define HANDLE_LENGTH 2 /**< Length of handle inside Glucose Measurement packet. */
+#define MAX_GLM_LEN (BLE_GATT_ATT_MTU_DEFAULT - OPCODE_LENGTH - HANDLE_LENGTH) /**< Maximum size of a transmitted Glucose Measurement. */
+
+#define GLS_NACK_PROC_ALREADY_IN_PROGRESS BLE_GATT_STATUS_ATTERR_APP_BEGIN + 0 /**< Reply when a requested procedure is already in progress. */
+#define GLS_NACK_CCCD_IMPROPERLY_CONFIGURED BLE_GATT_STATUS_ATTERR_APP_BEGIN + 1 /**< Reply when the a s CCCD is improperly configured. */
+
+/**@brief Glucose Service communication state. */
+typedef enum
+{
+ STATE_NO_COMM, /**< The service is not in a communicating state. */
+ STATE_RACP_PROC_ACTIVE, /**< Processing requested data. */
+ STATE_RACP_RESPONSE_PENDING, /**< There is a RACP indication waiting to be sent. */
+ STATE_RACP_RESPONSE_IND_VERIF /**< Waiting for a verification of a RACP indication. */
+} gls_state_t;
+
+static gls_state_t m_gls_state; /**< Current communication state. */
+static uint16_t m_next_seq_num; /**< Sequence number of the next database record. */
+static uint8_t m_racp_proc_operator; /**< Operator of current request. */
+static uint16_t m_racp_proc_seq_num; /**< Sequence number of current request. */
+static uint8_t m_racp_proc_record_ndx; /**< Current record index. */
+static uint8_t m_racp_proc_records_reported; /**< Number of reported records. */
+static uint8_t m_racp_proc_records_reported_since_txcomplete; /**< Number of reported records since last TX_COMPLETE event. */
+static ble_racp_value_t m_pending_racp_response; /**< RACP response to be sent. */
+static uint8_t m_pending_racp_response_operand[2]; /**< Operand of RACP response to be sent. */
+
+
+/**@brief Function for setting the GLS communication state.
+ *
+ * @param[in] new_state New communication state.
+ */
+static void state_set(gls_state_t new_state)
+{
+ m_gls_state = new_state;
+}
+
+
+/**@brief Function for setting the next sequence number by reading the last record in the data base.
+ *
+ * @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
+ */
+static uint32_t next_sequence_number_set(void)
+{
+ uint16_t num_records;
+ ble_gls_rec_t rec;
+
+ num_records = ble_gls_db_num_records_get();
+ if (num_records > 0)
+ {
+ // Get last record
+ uint32_t err_code = ble_gls_db_record_get(num_records - 1, &rec);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ m_next_seq_num = rec.meas.sequence_number + 1;
+ }
+ else
+ {
+ m_next_seq_num = 0;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for encoding a Glucose measurement.
+ *
+ * @param[in] p_meas Measurement to be encoded.
+ * @param[out] p_encoded_buffer Pointer to buffer where the encoded measurement is to be stored.
+ *
+ * @return Size of encoded measurement.
+ */
+static uint8_t gls_meas_encode(const ble_gls_meas_t * p_meas, uint8_t * p_encoded_buffer)
+{
+ uint8_t len = 0;
+
+ p_encoded_buffer[len++] = p_meas->flags;
+
+ len += uint16_encode(p_meas->sequence_number, &p_encoded_buffer[len]);
+ len += ble_date_time_encode(&p_meas->base_time, &p_encoded_buffer[len]);
+
+ if (p_meas->flags & BLE_GLS_MEAS_FLAG_TIME_OFFSET)
+ {
+ len += uint16_encode(p_meas->time_offset, &p_encoded_buffer[len]);
+ }
+
+ if (p_meas->flags & BLE_GLS_MEAS_FLAG_CONC_TYPE_LOC)
+ {
+ uint16_t encoded_concentration;
+
+ encoded_concentration = ((p_meas->glucose_concentration.exponent << 12) & 0xF000) |
+ ((p_meas->glucose_concentration.mantissa << 0) & 0x0FFF);
+
+ p_encoded_buffer[len++] = (uint8_t)(encoded_concentration);
+ p_encoded_buffer[len++] = (uint8_t)(encoded_concentration >> 8);
+ p_encoded_buffer[len++] = (p_meas->sample_location << 4) | (p_meas->type & 0x0F);
+ }
+
+ if (p_meas->flags & BLE_GLS_MEAS_FLAG_SENSOR_STATUS)
+ {
+ len += uint16_encode(p_meas->sensor_status_annunciation, &p_encoded_buffer[len]);
+ }
+
+ return len;
+}
+
+
+/**@brief Function for adding the characteristic for a glucose measurement.
+ *
+ * @param[in] p_gls Service instance.
+ *
+ * @return NRF_SUCCESS if characteristic was successfully added, otherwise an error code.
+ */
+static uint32_t glucose_measurement_char_add(ble_gls_t * p_gls)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_md_t cccd_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+ ble_gls_rec_t initial_gls_rec_value;
+ uint8_t encoded_gls_meas[MAX_GLM_LEN];
+ uint8_t num_recs;
+ memset(&cccd_md, 0, sizeof(cccd_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&cccd_md.write_perm);
+ cccd_md.vloc = BLE_GATTS_VLOC_STACK;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.notify = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = &cccd_md;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_GLUCOSE_MEASUREMENT_CHAR);
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
+
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 1;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+ memset(&initial_gls_rec_value, 0, sizeof(initial_gls_rec_value));
+
+ num_recs = ble_gls_db_num_records_get();
+ if (num_recs > 0)
+ {
+ uint32_t err_code = ble_gls_db_record_get(num_recs - 1, &initial_gls_rec_value);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = gls_meas_encode(&initial_gls_rec_value.meas, encoded_gls_meas);
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = MAX_GLM_LEN;
+ attr_char_value.p_value = encoded_gls_meas;
+
+ return sd_ble_gatts_characteristic_add(p_gls->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_gls->glm_handles);
+}
+
+
+/**@brief Function for adding the characteristic for a glucose feature.
+ *
+ * @param[in] p_gls Service instance.
+ *
+ * @return NRF_SUCCESS if characteristic was successfully added, otherwise an error code.
+ */
+static uint32_t glucose_feature_char_add(ble_gls_t * p_gls)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+ uint8_t encoded_initial_feature[2];
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = NULL;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_GLUCOSE_FEATURE_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.read_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
+
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ encoded_initial_feature[0] = (uint8_t)(p_gls->feature);
+ encoded_initial_feature[1] = (uint8_t)((p_gls->feature) >> 8);
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = sizeof (uint16_t);
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = sizeof (uint16_t);
+ attr_char_value.p_value = encoded_initial_feature;
+
+ return sd_ble_gatts_characteristic_add(p_gls->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_gls->glf_handles);
+}
+
+
+/**@brief Function for adding the characteristic for a record access control point.
+ *
+ * @param[in] p_gls Service instance.
+ *
+ * @return NRF_SUCCESS if characteristic was successfully added, otherwise an error code.
+ */
+static uint32_t record_access_control_point_char_add(ble_gls_t * p_gls)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_md_t cccd_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+
+ memset(&cccd_md, 0, sizeof(cccd_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&cccd_md.write_perm);
+ cccd_md.vloc = BLE_GATTS_VLOC_STACK;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.indicate = 1;
+ char_md.char_props.write = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = &cccd_md;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_RECORD_ACCESS_CONTROL_POINT_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.write_perm);
+
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 1;
+ attr_md.vlen = 1;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = 0;
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = BLE_GATT_ATT_MTU_DEFAULT;
+ attr_char_value.p_value = 0;
+
+ return sd_ble_gatts_characteristic_add(p_gls->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_gls->racp_handles);
+}
+
+
+uint32_t ble_gls_init(ble_gls_t * p_gls, const ble_gls_init_t * p_gls_init)
+{
+ uint32_t err_code;
+ ble_uuid_t ble_uuid;
+
+ // Initialize data base
+ err_code = ble_gls_db_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ err_code = next_sequence_number_set();
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Initialize service structure
+ p_gls->evt_handler = p_gls_init->evt_handler;
+ p_gls->error_handler = p_gls_init->error_handler;
+ p_gls->feature = p_gls_init->feature;
+ p_gls->is_context_supported = p_gls_init->is_context_supported;
+ p_gls->conn_handle = BLE_CONN_HANDLE_INVALID;
+
+
+ // Initialize global variables
+ state_set(STATE_NO_COMM);
+ m_racp_proc_records_reported_since_txcomplete = 0;
+
+ // Add service
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_GLUCOSE_SERVICE);
+
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_gls->service_handle);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add glucose measurement characteristic
+ err_code = glucose_measurement_char_add(p_gls);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add glucose measurement feature characteristic
+ err_code = glucose_feature_char_add(p_gls);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add record control access point characteristic
+ err_code = record_access_control_point_char_add(p_gls);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for sending a response from the Record Access Control Point.
+ *
+ * @param[in] p_gls Service instance.
+ * @param[in] p_racp_val RACP value to be sent.
+ */
+static void racp_send(ble_gls_t * p_gls, ble_racp_value_t * p_racp_val)
+{
+ uint32_t err_code;
+ uint8_t encoded_resp[25];
+ uint8_t len;
+ uint16_t hvx_len;
+ ble_gatts_hvx_params_t hvx_params;
+
+ if (
+ (m_gls_state != STATE_RACP_RESPONSE_PENDING)
+ &&
+ (m_racp_proc_records_reported_since_txcomplete > 0)
+ )
+ {
+ state_set(STATE_RACP_RESPONSE_PENDING);
+ return;
+ }
+
+ // Send indication
+ len = ble_racp_encode(p_racp_val, encoded_resp);
+ hvx_len = len;
+
+ memset(&hvx_params, 0, sizeof(hvx_params));
+
+ hvx_params.handle = p_gls->racp_handles.value_handle;
+ hvx_params.type = BLE_GATT_HVX_INDICATION;
+ hvx_params.offset = 0;
+ hvx_params.p_len = &hvx_len;
+ hvx_params.p_data = encoded_resp;
+
+ err_code = sd_ble_gatts_hvx(p_gls->conn_handle, &hvx_params);
+
+ // Error handling
+ if ((err_code == NRF_SUCCESS) && (hvx_len != len))
+ {
+ err_code = NRF_ERROR_DATA_SIZE;
+ }
+ switch (err_code)
+ {
+ case NRF_SUCCESS:
+ // Wait for HVC event
+ state_set(STATE_RACP_RESPONSE_IND_VERIF);
+ break;
+
+ case NRF_ERROR_BUSY:
+ // Wait for BLE_GATTS_EVT_HVC event to retry transmission
+ state_set(STATE_RACP_RESPONSE_PENDING);
+ break;
+
+ case NRF_ERROR_INVALID_STATE:
+ // Make sure state machine returns to the default state
+ state_set(STATE_NO_COMM);
+ break;
+
+ default:
+ // Report error to application
+ if (p_gls->error_handler != NULL)
+ {
+ p_gls->error_handler(err_code);
+ }
+
+ // Make sure state machine returns to the default state
+ state_set(STATE_NO_COMM);
+ break;
+ }
+}
+
+
+/**@brief Function for sending a RACP response containing a Response Code Op Code and a Response Code Value.
+ *
+ * @param[in] p_gls Service instance.
+ * @param[in] opcode RACP Op Code.
+ * @param[in] value RACP Response Code Value.
+ */
+static void racp_response_code_send(ble_gls_t * p_gls, uint8_t opcode, uint8_t value)
+{
+ m_pending_racp_response.opcode = RACP_OPCODE_RESPONSE_CODE;
+ m_pending_racp_response.operator = RACP_OPERATOR_NULL;
+ m_pending_racp_response.operand_len = 2;
+ m_pending_racp_response.p_operand = m_pending_racp_response_operand;
+
+ m_pending_racp_response_operand[0] = opcode;
+ m_pending_racp_response_operand[1] = value;
+
+ racp_send(p_gls, &m_pending_racp_response);
+}
+
+
+/**@brief Function for sending a glucose measurement/context.
+ *
+ * @param[in] p_gls Service instance.
+ * @param[in] p_rec Measurement to be sent.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t glucose_meas_send(ble_gls_t * p_gls, ble_gls_rec_t * p_rec)
+{
+ uint32_t err_code;
+ uint8_t encoded_glm[MAX_GLM_LEN];
+ uint16_t len;
+ uint16_t hvx_len;
+ ble_gatts_hvx_params_t hvx_params;
+
+ len = gls_meas_encode(&p_rec->meas, encoded_glm);
+ hvx_len = len;
+
+ memset(&hvx_params, 0, sizeof (hvx_params));
+
+ hvx_params.handle = p_gls->glm_handles.value_handle;
+ hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
+ hvx_params.offset = 0;
+ hvx_params.p_len = &hvx_len;
+ hvx_params.p_data = encoded_glm;
+
+ err_code = sd_ble_gatts_hvx(p_gls->conn_handle, &hvx_params);
+ if (err_code == NRF_SUCCESS)
+ {
+ if (hvx_len != len)
+ {
+ err_code = NRF_ERROR_DATA_SIZE;
+ }
+ else
+ {
+ // Measurement successfully sent
+ m_racp_proc_records_reported++;
+ m_racp_proc_records_reported_since_txcomplete++;
+ }
+ }
+
+ return err_code;
+}
+
+
+/**@brief Function for responding to the ALL operation.
+ *
+ * @param[in] p_gls Service instance.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t racp_report_records_all(ble_gls_t * p_gls)
+{
+ uint16_t total_records = ble_gls_db_num_records_get();
+
+ if (m_racp_proc_record_ndx >= total_records)
+ {
+ state_set(STATE_NO_COMM);
+ }
+ else
+ {
+ uint32_t err_code;
+ ble_gls_rec_t rec;
+
+ err_code = ble_gls_db_record_get(m_racp_proc_record_ndx, &rec);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ err_code = glucose_meas_send(p_gls, &rec);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for responding to the FIRST or the LAST operation.
+ *
+ * @param[in] p_gls Service instance.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t racp_report_records_first_last(ble_gls_t * p_gls)
+{
+ uint32_t err_code;
+ ble_gls_rec_t rec;
+ uint16_t total_records;
+
+ total_records = ble_gls_db_num_records_get();
+
+ if ((m_racp_proc_records_reported != 0) || (total_records == 0))
+ {
+ state_set(STATE_NO_COMM);
+ }
+ else
+ {
+ if (m_racp_proc_operator == RACP_OPERATOR_FIRST)
+ {
+ err_code = ble_gls_db_record_get(0, &rec);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+ else if (m_racp_proc_operator == RACP_OPERATOR_LAST)
+ {
+ err_code = ble_gls_db_record_get(total_records - 1, &rec);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ err_code = glucose_meas_send(p_gls, &rec);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for responding to the GREATER_OR_EQUAL operation.
+ *
+ * @param[in] p_gls Service instance.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t racp_report_records_greater_or_equal(ble_gls_t * p_gls)
+{
+ uint16_t total_records = ble_gls_db_num_records_get();
+
+ while (m_racp_proc_record_ndx < total_records)
+ {
+ uint32_t err_code;
+ ble_gls_rec_t rec;
+
+ err_code = ble_gls_db_record_get(m_racp_proc_record_ndx, &rec);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ if (rec.meas.sequence_number >= m_racp_proc_seq_num)
+ {
+ err_code = glucose_meas_send(p_gls, &rec);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ break;
+ }
+ m_racp_proc_record_ndx++;
+ }
+ if (m_racp_proc_record_ndx == total_records)
+ {
+ state_set(STATE_NO_COMM);
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for informing that the REPORT RECORDS procedure is completed.
+ *
+ * @param[in] p_gls Service instance.
+ */
+static void racp_report_records_completed(ble_gls_t * p_gls)
+{
+ uint8_t resp_code_value;
+
+ if (m_racp_proc_records_reported > 0)
+ {
+ resp_code_value = RACP_RESPONSE_SUCCESS;
+ }
+ else
+ {
+ resp_code_value = RACP_RESPONSE_NO_RECORDS_FOUND;
+ }
+
+ racp_response_code_send(p_gls, RACP_OPCODE_REPORT_RECS, resp_code_value);
+}
+
+
+/**@brief Function for the RACP report records procedure.
+ *
+ * @param[in] p_gls Service instance.
+ */
+static void racp_report_records_procedure(ble_gls_t * p_gls)
+{
+ uint32_t err_code;
+
+ while (m_gls_state == STATE_RACP_PROC_ACTIVE)
+ {
+ // Execute requested procedure
+ switch (m_racp_proc_operator)
+ {
+ case RACP_OPERATOR_ALL:
+ err_code = racp_report_records_all(p_gls);
+ break;
+
+ case RACP_OPERATOR_FIRST:
+ case RACP_OPERATOR_LAST:
+ err_code = racp_report_records_first_last(p_gls);
+ break;
+
+ case RACP_OPERATOR_GREATER_OR_EQUAL:
+ err_code = racp_report_records_greater_or_equal(p_gls);
+ break;
+
+ default:
+ // Report error to application
+ if (p_gls->error_handler != NULL)
+ {
+ p_gls->error_handler(NRF_ERROR_INTERNAL);
+ }
+
+ // Make sure state machine returns to the default state
+ state_set(STATE_NO_COMM);
+ return;
+ }
+
+ // Error handling
+ switch (err_code)
+ {
+ case NRF_SUCCESS:
+ if (m_gls_state == STATE_RACP_PROC_ACTIVE)
+ {
+ m_racp_proc_record_ndx++;
+ }
+ else
+ {
+ racp_report_records_completed(p_gls);
+ }
+ break;
+
+ case NRF_ERROR_RESOURCES:
+ // Wait for TX_COMPLETE event to resume transmission
+ return;
+
+ case NRF_ERROR_INVALID_STATE:
+ // Notification is probably not enabled. Ignore request.
+ state_set(STATE_NO_COMM);
+ return;
+
+ default:
+ // Report error to application
+ if (p_gls->error_handler != NULL)
+ {
+ p_gls->error_handler(err_code);
+ }
+
+ // Make sure state machine returns to the default state
+ state_set(STATE_NO_COMM);
+ return;
+ }
+ }
+}
+
+
+/**@brief Function for testing if the received request is to be executed.
+ *
+ * @param[in] p_racp_request Request to be checked.
+ * @param[out] p_response_code Response code to be sent in case the request is rejected.
+ * RACP_RESPONSE_RESERVED is returned if the received message is
+ * to be rejected without sending a response.
+ *
+ * @return TRUE if the request is to be executed, FALSE if it is to be rejected.
+ * If it is to be rejected, p_response_code will contain the response code to be
+ * returned to the central.
+ */
+static bool is_request_to_be_executed(ble_racp_value_t const * p_racp_request,
+ uint8_t * p_response_code)
+{
+ *p_response_code = RACP_RESPONSE_RESERVED;
+
+ if (p_racp_request->opcode == RACP_OPCODE_ABORT_OPERATION)
+ {
+ if (m_gls_state == STATE_RACP_PROC_ACTIVE)
+ {
+ if (p_racp_request->operator != RACP_OPERATOR_NULL)
+ {
+ *p_response_code = RACP_RESPONSE_INVALID_OPERATOR;
+ }
+ else if (p_racp_request->operand_len != 0)
+ {
+ *p_response_code = RACP_RESPONSE_INVALID_OPERAND;
+ }
+ else
+ {
+ *p_response_code = RACP_RESPONSE_SUCCESS;
+ }
+ }
+ else
+ {
+ *p_response_code = RACP_RESPONSE_ABORT_FAILED;
+ }
+ }
+ else if (m_gls_state != STATE_NO_COMM)
+ {
+ return false;
+ }
+ // Supported opcodes.
+ else if ((p_racp_request->opcode == RACP_OPCODE_REPORT_RECS) ||
+ (p_racp_request->opcode == RACP_OPCODE_REPORT_NUM_RECS))
+ {
+ switch (p_racp_request->operator)
+ {
+ // Operators WITHOUT a filter.
+ case RACP_OPERATOR_ALL:
+ case RACP_OPERATOR_FIRST:
+ case RACP_OPERATOR_LAST:
+ if (p_racp_request->operand_len != 0)
+ {
+ *p_response_code = RACP_RESPONSE_INVALID_OPERAND;
+ }
+ break;
+
+ // Operators WITH a filter.
+ case RACP_OPERATOR_GREATER_OR_EQUAL:
+ if (p_racp_request->p_operand[0] == OPERAND_FILTER_TYPE_SEQ_NUM)
+ {
+ if (p_racp_request->operand_len != 3)
+ {
+ *p_response_code = RACP_RESPONSE_INVALID_OPERAND;
+ }
+ }
+ else if (p_racp_request->p_operand[0] == OPERAND_FILTER_TYPE_FACING_TIME)
+ {
+ *p_response_code = RACP_RESPONSE_OPERAND_UNSUPPORTED;
+ }
+ else if (p_racp_request->p_operand[0] >= OPERAND_FILTER_TYPE_RFU_START)
+ {
+ *p_response_code = RACP_RESPONSE_OPERAND_UNSUPPORTED;
+ }
+ else
+ {
+ *p_response_code = RACP_RESPONSE_INVALID_OPERAND;
+ }
+ break;
+
+ // Unsupported operators.
+ case RACP_OPERATOR_LESS_OR_EQUAL:
+ case RACP_OPERATOR_RANGE:
+ *p_response_code = RACP_RESPONSE_OPERATOR_UNSUPPORTED;
+ break;
+
+ // Invalid operators.
+ case RACP_OPERATOR_NULL:
+ default:
+ if (p_racp_request->operator >= RACP_OPERATOR_RFU_START)
+ {
+ *p_response_code = RACP_RESPONSE_OPERATOR_UNSUPPORTED;
+ }
+ else
+ {
+ *p_response_code = RACP_RESPONSE_INVALID_OPERATOR;
+ }
+ break;
+ }
+ }
+ // Unsupported opcodes,
+ else if (p_racp_request->opcode == RACP_OPCODE_DELETE_RECS)
+ {
+ *p_response_code = RACP_RESPONSE_OPCODE_UNSUPPORTED;
+ }
+ // Unknown opcodes.
+ else
+ {
+ *p_response_code = RACP_RESPONSE_OPCODE_UNSUPPORTED;
+ }
+
+ // NOTE: The computation of the return value will change slightly when deferred write has been
+ // implemented in the stack.
+ return (*p_response_code == RACP_RESPONSE_RESERVED);
+}
+
+
+/**@brief Function for processing a REPORT RECORDS request.
+ *
+ * @param[in] p_gls Service instance.
+ * @param[in] p_racp_request Request to be executed.
+ */
+static void report_records_request_execute(ble_gls_t * p_gls, ble_racp_value_t * p_racp_request)
+{
+ uint16_t seq_num = (p_racp_request->p_operand[2] << 8) | p_racp_request->p_operand[1];
+
+ state_set(STATE_RACP_PROC_ACTIVE);
+
+ m_racp_proc_record_ndx = 0;
+ m_racp_proc_operator = p_racp_request->operator;
+ m_racp_proc_records_reported = 0;
+ m_racp_proc_seq_num = seq_num;
+
+ racp_report_records_procedure(p_gls);
+}
+
+
+/**@brief Function for processing a REPORT NUM RECORDS request.
+ *
+ * @param[in] p_gls Service instance.
+ * @param[in] p_racp_request Request to be executed.
+ */
+static void report_num_records_request_execute(ble_gls_t * p_gls, ble_racp_value_t * p_racp_request)
+{
+ uint16_t total_records;
+ uint16_t num_records;
+
+ total_records = ble_gls_db_num_records_get();
+ num_records = 0;
+
+ if (p_racp_request->operator == RACP_OPERATOR_ALL)
+ {
+ num_records = total_records;
+ }
+ else if (p_racp_request->operator == RACP_OPERATOR_GREATER_OR_EQUAL)
+ {
+ uint16_t seq_num;
+ uint16_t i;
+
+ seq_num = (p_racp_request->p_operand[2] << 8) | p_racp_request->p_operand[1];
+
+ for (i = 0; i < total_records; i++)
+ {
+ uint32_t err_code;
+ ble_gls_rec_t rec;
+
+ err_code = ble_gls_db_record_get(i, &rec);
+ if (err_code != NRF_SUCCESS)
+ {
+ if (p_gls->error_handler != NULL)
+ {
+ p_gls->error_handler(err_code);
+ }
+ return;
+ }
+
+ if (rec.meas.sequence_number >= seq_num)
+ {
+ num_records++;
+ }
+ }
+ }
+ else if ((p_racp_request->operator == RACP_OPERATOR_FIRST) ||
+ (p_racp_request->operator == RACP_OPERATOR_LAST))
+ {
+ if (total_records > 0)
+ {
+ num_records = 1;
+ }
+ }
+
+ m_pending_racp_response.opcode = RACP_OPCODE_NUM_RECS_RESPONSE;
+ m_pending_racp_response.operator = RACP_OPERATOR_NULL;
+ m_pending_racp_response.operand_len = sizeof(uint16_t);
+ m_pending_racp_response.p_operand = m_pending_racp_response_operand;
+
+ m_pending_racp_response_operand[0] = num_records & 0xFF;
+ m_pending_racp_response_operand[1] = num_records >> 8;
+
+ racp_send(p_gls, &m_pending_racp_response);
+}
+
+
+/**@brief Function for checking if the CCCDs are configured.
+ *
+ * @param[in] p_gls Service instance.
+ * @param[in] p_are_cccd_configured boolean indicating if both cccds are configured
+ */
+uint32_t ble_gls_are_cccd_configured(ble_gls_t * p_gls, bool * p_are_cccd_configured)
+{
+ uint32_t err_code;
+ uint8_t cccd_value_buf[BLE_CCCD_VALUE_LEN];
+ bool is_glm_notif_enabled = false;
+ bool is_racp_indic_enabled = false;
+ ble_gatts_value_t gatts_value;
+
+ // Initialize value struct.
+ memset(&gatts_value, 0, sizeof(gatts_value));
+
+ gatts_value.len = BLE_CCCD_VALUE_LEN;
+ gatts_value.offset = 0;
+ gatts_value.p_value = cccd_value_buf;
+
+ err_code = sd_ble_gatts_value_get(p_gls->conn_handle,
+ p_gls->glm_handles.cccd_handle,
+ &gatts_value);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ is_glm_notif_enabled = ble_srv_is_notification_enabled(cccd_value_buf);
+
+ err_code = sd_ble_gatts_value_get(p_gls->conn_handle,
+ p_gls->racp_handles.cccd_handle,
+ &gatts_value);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ is_racp_indic_enabled = ble_srv_is_indication_enabled(cccd_value_buf);
+ if (is_racp_indic_enabled & is_glm_notif_enabled)
+ {
+ *p_are_cccd_configured = true;
+ }
+ else
+ {
+ *p_are_cccd_configured = false;
+ }
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for handling a write event to the Record Access Control Point.
+ *
+ * @param[in] p_gls Service instance.
+ * @param[in] p_evt_write WRITE event to be handled.
+ */
+static void on_racp_value_write(ble_gls_t * p_gls, ble_gatts_evt_write_t const * p_evt_write)
+{
+ ble_racp_value_t racp_request;
+ uint8_t response_code;
+ ble_gatts_rw_authorize_reply_params_t auth_reply;
+ bool are_cccd_configured;
+ uint32_t err_code;
+
+ auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
+ auth_reply.params.write.offset = 0;
+ auth_reply.params.write.len = 0;
+ auth_reply.params.write.p_data = NULL;
+
+ err_code = ble_gls_are_cccd_configured(p_gls, &are_cccd_configured);
+ if (err_code != NRF_SUCCESS)
+ {
+ if (p_gls->error_handler != NULL)
+ {
+ p_gls->error_handler(err_code);
+ }
+ return;
+ }
+
+ if (!are_cccd_configured)
+ {
+ auth_reply.params.write.gatt_status = GLS_NACK_CCCD_IMPROPERLY_CONFIGURED;
+ err_code = sd_ble_gatts_rw_authorize_reply(p_gls->conn_handle,
+ &auth_reply);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ if (p_gls->error_handler != NULL)
+ {
+ p_gls->error_handler(err_code);
+ }
+ }
+ return;
+ }
+
+ // Decode request.
+ ble_racp_decode(p_evt_write->len, (uint8_t*)p_evt_write->data, &racp_request);
+
+ // Check if request is to be executed.
+ if (is_request_to_be_executed(&racp_request, &response_code))
+ {
+ auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ auth_reply.params.write.update = 1;
+
+ err_code = sd_ble_gatts_rw_authorize_reply(p_gls->conn_handle,
+ &auth_reply);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ if (p_gls->error_handler != NULL)
+ {
+ p_gls->error_handler(err_code);
+ }
+ return;
+ }
+ // Execute request.
+ if (racp_request.opcode == RACP_OPCODE_REPORT_RECS)
+ {
+ report_records_request_execute(p_gls, &racp_request);
+ }
+ else if (racp_request.opcode == RACP_OPCODE_REPORT_NUM_RECS)
+ {
+ report_num_records_request_execute(p_gls, &racp_request);
+ }
+ }
+ else if (response_code != RACP_RESPONSE_RESERVED)
+ {
+ auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ auth_reply.params.write.update = 1;
+ err_code = sd_ble_gatts_rw_authorize_reply(p_gls->conn_handle,
+ &auth_reply);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ if (p_gls->error_handler != NULL)
+ {
+ p_gls->error_handler(err_code);
+ }
+ return;
+ }
+
+ // Abort any running procedure.
+ state_set(STATE_NO_COMM);
+
+ // Respond with error code.
+ racp_response_code_send(p_gls, racp_request.opcode, response_code);
+ }
+ else
+ {
+ auth_reply.params.write.gatt_status = GLS_NACK_PROC_ALREADY_IN_PROGRESS;
+ err_code = sd_ble_gatts_rw_authorize_reply(p_gls->conn_handle,
+ &auth_reply);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ if (p_gls->error_handler != NULL)
+ {
+ p_gls->error_handler(err_code);
+ }
+ return;
+ }
+ }
+}
+
+
+/**@brief Function for handling the Glucose measurement CCCD write event.
+ *
+ * @param[in] p_gls Service instance.
+ * @param[in] p_evt_write WRITE event to be handled.
+ */
+static void on_glm_cccd_write(ble_gls_t * p_gls, ble_gatts_evt_write_t const * p_evt_write)
+{
+ if (p_evt_write->len == 2)
+ {
+ // CCCD written, update notification state
+ ble_gls_evt_t evt;
+
+ if (ble_srv_is_notification_enabled(p_evt_write->data))
+ {
+ evt.evt_type = BLE_GLS_EVT_NOTIFICATION_ENABLED;
+ }
+ else
+ {
+ evt.evt_type = BLE_GLS_EVT_NOTIFICATION_DISABLED;
+ }
+
+ if (p_gls->evt_handler != NULL)
+ {
+ p_gls->evt_handler(p_gls, &evt);
+ }
+ }
+}
+
+
+/**@brief Function for handling the WRITE event.
+ *
+ * @details Handles WRITE events from the BLE stack.
+ *
+ * @param[in] p_gls Glucose Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_write(ble_gls_t * p_gls, ble_evt_t const * p_ble_evt)
+{
+ ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+ if (p_evt_write->handle == p_gls->glm_handles.cccd_handle)
+ {
+ on_glm_cccd_write(p_gls, p_evt_write);
+ }
+ else if (p_evt_write->handle == p_gls->racp_handles.value_handle)
+ {
+ on_racp_value_write(p_gls, p_evt_write);
+ }
+}
+
+
+/**@brief Function for handling the TX_COMPLETE event.
+ *
+ * @details Handles TX_COMPLETE events from the BLE stack.
+ *
+ * @param[in] p_gls Glucose Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_tx_complete(ble_gls_t * p_gls, ble_evt_t const * p_ble_evt)
+{
+ m_racp_proc_records_reported_since_txcomplete = 0;
+
+ if (m_gls_state == STATE_RACP_RESPONSE_PENDING)
+ {
+ racp_send(p_gls, &m_pending_racp_response);
+ }
+ else if (m_gls_state == STATE_RACP_PROC_ACTIVE)
+ {
+ racp_report_records_procedure(p_gls);
+ }
+}
+
+
+/**@brief Function for handling the HVC event.
+ *
+ * @details Handles HVC events from the BLE stack.
+ *
+ * @param[in] p_gls Glucose Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_hvc(ble_gls_t * p_gls, ble_evt_t const * p_ble_evt)
+{
+ ble_gatts_evt_hvc_t const * p_hvc = &p_ble_evt->evt.gatts_evt.params.hvc;
+
+ if (p_hvc->handle == p_gls->racp_handles.value_handle)
+ {
+ if (m_gls_state == STATE_RACP_RESPONSE_IND_VERIF)
+ {
+ // Indication has been acknowledged. Return to default state.
+ state_set(STATE_NO_COMM);
+ }
+ else if (m_gls_state == STATE_RACP_RESPONSE_PENDING)
+ {
+ racp_send(p_gls, &m_pending_racp_response);
+ }
+ else
+ {
+ // We did not expect this event in this state. Report error to application.
+ if (p_gls->error_handler != NULL)
+ {
+ p_gls->error_handler(NRF_ERROR_INVALID_STATE);
+ }
+ }
+ }
+}
+
+
+static void on_rw_authorize_request(ble_gls_t * p_gls, ble_gatts_evt_t const * p_gatts_evt)
+{
+ ble_gatts_evt_rw_authorize_request_t const * p_auth_req =
+ &p_gatts_evt->params.authorize_request;
+
+ if (p_auth_req->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
+ {
+ if ( (p_gatts_evt->params.authorize_request.request.write.op
+ != BLE_GATTS_OP_PREP_WRITE_REQ)
+ && (p_gatts_evt->params.authorize_request.request.write.op
+ != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW)
+ && (p_gatts_evt->params.authorize_request.request.write.op
+ != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)
+ )
+ {
+ if (p_auth_req->request.write.handle == p_gls->racp_handles.value_handle)
+ {
+ on_racp_value_write(p_gls, &p_auth_req->request.write);
+ }
+ }
+ }
+}
+
+void ble_gls_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ ble_gls_t * p_gls = (ble_gls_t *)p_context;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ p_gls->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+ state_set(STATE_NO_COMM);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ p_gls->conn_handle = BLE_CONN_HANDLE_INVALID;
+ break;
+
+ case BLE_GATTS_EVT_WRITE:
+ on_write(p_gls, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_HVN_TX_COMPLETE:
+ on_tx_complete(p_gls, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
+ on_rw_authorize_request(p_gls, &p_ble_evt->evt.gatts_evt);
+ break;
+
+ case BLE_GATTS_EVT_HVC:
+ on_hvc(p_gls, p_ble_evt);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+
+uint32_t ble_gls_glucose_new_meas(ble_gls_t * p_gls, ble_gls_rec_t * p_rec)
+{
+ p_rec->meas.sequence_number = m_next_seq_num++;
+ return ble_gls_db_record_add(p_rec);
+}
+#endif // NRF_MODULE_ENABLED(BLE_GLS)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_gls/ble_gls.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_gls/ble_gls.h
new file mode 100644
index 0000000..374d3a3
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_gls/ble_gls.h
@@ -0,0 +1,323 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_gls Glucose Service
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Glucose Service module.
+ *
+ * @details This module implements the Glucose Service.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_gls_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_GLS_BLE_OBSERVER_PRIO,
+ * ble_gls_on_ble_evt, &instance);
+ * @endcode
+ *
+ * @note Attention!
+ * To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+
+#ifndef BLE_GLS_H__
+#define BLE_GLS_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "ble_date_time.h"
+#include "nrf_sdh_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_gls instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_GLS_DEF(_name) \
+static ble_gls_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_GLS_BLE_OBSERVER_PRIO, \
+ ble_gls_on_ble_evt, &_name)
+
+
+/**@brief Glucose feature */
+#define BLE_GLS_FEATURE_LOW_BATT 0x0001 /**< Low Battery Detection During Measurement Supported */
+#define BLE_GLS_FEATURE_MALFUNC 0x0002 /**< Sensor Malfunction Detection Supported */
+#define BLE_GLS_FEATURE_SAMPLE_SIZE 0x0004 /**< Sensor Sample Size Supported */
+#define BLE_GLS_FEATURE_INSERT_ERR 0x0008 /**< Sensor Strip Insertion Error Detection Supported */
+#define BLE_GLS_FEATURE_TYPE_ERR 0x0010 /**< Sensor Strip Type Error Detection Supported */
+#define BLE_GLS_FEATURE_RES_HIGH_LOW 0x0020 /**< Sensor Result High-Low Detection Supported */
+#define BLE_GLS_FEATURE_TEMP_HIGH_LOW 0x0040 /**< Sensor Temperature High-Low Detection Supported */
+#define BLE_GLS_FEATURE_READ_INT 0x0080 /**< Sensor Read Interrupt Detection Supported */
+#define BLE_GLS_FEATURE_GENERAL_FAULT 0x0100 /**< General Device Fault Supported */
+#define BLE_GLS_FEATURE_TIME_FAULT 0x0200 /**< Time Fault Supported */
+#define BLE_GLS_FEATURE_MULTI_BOND 0x0400 /**< Multiple Bond Supported */
+
+/**@brief Glucose measurement flags */
+#define BLE_GLS_MEAS_FLAG_TIME_OFFSET 0x01 /**< Time Offset Present */
+#define BLE_GLS_MEAS_FLAG_CONC_TYPE_LOC 0x02 /**< Glucose Concentration, Type, and Sample Location Present */
+#define BLE_GLS_MEAS_FLAG_UNITS_KG_L 0x00 /**< Glucose Concentration Units kg/L */
+#define BLE_GLS_MEAS_FLAG_UNITS_MOL_L 0x04 /**< Glucose Concentration Units mol/L */
+#define BLE_GLS_MEAS_FLAG_SENSOR_STATUS 0x08 /**< Sensor Status Annunciation Present */
+#define BLE_GLS_MEAS_FLAG_CONTEXT_INFO 0x10 /**< Context Information Follows */
+
+/**@brief Glucose measurement type */
+#define BLE_GLS_MEAS_TYPE_CAP_BLOOD 1 /**< Capillary whole blood */
+#define BLE_GLS_MEAS_TYPE_CAP_PLASMA 2 /**< Capillary plasma */
+#define BLE_GLS_MEAS_TYPE_VEN_BLOOD 3 /**< Venous whole blood */
+#define BLE_GLS_MEAS_TYPE_VEN_PLASMA 4 /**< Venous plasma */
+#define BLE_GLS_MEAS_TYPE_ART_BLOOD 5 /**< Arterial whole blood */
+#define BLE_GLS_MEAS_TYPE_ART_PLASMA 6 /**< Arterial plasma */
+#define BLE_GLS_MEAS_TYPE_UNDET_BLOOD 7 /**< Undetermined whole blood */
+#define BLE_GLS_MEAS_TYPE_UNDET_PLASMA 8 /**< Undetermined plasma */
+#define BLE_GLS_MEAS_TYPE_FLUID 9 /**< Interstitial fluid (ISF) */
+#define BLE_GLS_MEAS_TYPE_CONTROL 10 /**< Control solution */
+
+/**@brief Glucose measurement location */
+#define BLE_GLS_MEAS_LOC_FINGER 1 /**< Finger */
+#define BLE_GLS_MEAS_LOC_AST 2 /**< Alternate Site Test (AST) */
+#define BLE_GLS_MEAS_LOC_EAR 3 /**< Earlobe */
+#define BLE_GLS_MEAS_LOC_CONTROL 4 /**< Control solution */
+#define BLE_GLS_MEAS_LOC_NOT_AVAIL 15 /**< Sample Location value not available */
+
+/**@brief Glucose sensor status annunciation */
+#define BLE_GLS_MEAS_STATUS_BATT_LOW 0x0001 /**< Device battery low at time of measurement */
+#define BLE_GLS_MEAS_STATUS_SENSOR_FAULT 0x0002 /**< Sensor malfunction or faulting at time of measurement */
+#define BLE_GLS_MEAS_STATUS_SAMPLE_SIZE 0x0004 /**< Sample size for blood or control solution insufficient at time of measurement */
+#define BLE_GLS_MEAS_STATUS_STRIP_INSERT 0x0008 /**< Strip insertion error */
+#define BLE_GLS_MEAS_STATUS_STRIP_TYPE 0x0010 /**< Strip type incorrect for device */
+#define BLE_GLS_MEAS_STATUS_RESULT_HIGH 0x0020 /**< Sensor result higher than the device can process */
+#define BLE_GLS_MEAS_STATUS_RESULT_LOW 0x0040 /**< Sensor result lower than the device can process */
+#define BLE_GLS_MEAS_STATUS_TEMP_HIGH 0x0080 /**< Sensor temperature too high for valid test/result at time of measurement */
+#define BLE_GLS_MEAS_STATUS_TEMP_LOW 0x0100 /**< Sensor temperature too low for valid test/result at time of measurement */
+#define BLE_GLS_MEAS_STATUS_STRIP_PULL 0x0200 /**< Sensor read interrupted because strip was pulled too soon at time of measurement */
+#define BLE_GLS_MEAS_STATUS_GENERAL_FAULT 0x0400 /**< General device fault has occurred in the sensor */
+#define BLE_GLS_MEAS_STATUS_TIME_FAULT 0x0800 /**< Time fault has occurred in the sensor and time may be inaccurate */
+
+/**@brief Glucose measurement context flags */
+#define BLE_GLS_CONTEXT_FLAG_CARB 0x01 /**< Carbohydrate id and carbohydrate present */
+#define BLE_GLS_CONTEXT_FLAG_MEAL 0x02 /**< Meal present */
+#define BLE_GLS_CONTEXT_FLAG_TESTER 0x04 /**< Tester-health present */
+#define BLE_GLS_CONTEXT_FLAG_EXERCISE 0x08 /**< Exercise duration and exercise intensity present */
+#define BLE_GLS_CONTEXT_FLAG_MED 0x10 /**< Medication ID and medication present */
+#define BLE_GLS_CONTEXT_FLAG_MED_KG 0x00 /**< Medication value units, kilograms */
+#define BLE_GLS_CONTEXT_FLAG_MED_L 0x20 /**< Medication value units, liters */
+#define BLE_GLS_CONTEXT_FLAG_HBA1C 0x40 /**< Hba1c present */
+#define BLE_GLS_CONTEXT_FLAG_EXT 0x80 /**< Extended flags present */
+
+/**@brief Glucose measurement context carbohydrate ID */
+#define BLE_GLS_CONTEXT_CARB_BREAKFAST 1 /**< Breakfast */
+#define BLE_GLS_CONTEXT_CARB_LUNCH 2 /**< Lunch */
+#define BLE_GLS_CONTEXT_CARB_DINNER 3 /**< Dinner */
+#define BLE_GLS_CONTEXT_CARB_SNACK 4 /**< Snack */
+#define BLE_GLS_CONTEXT_CARB_DRINK 5 /**< Drink */
+#define BLE_GLS_CONTEXT_CARB_SUPPER 6 /**< Supper */
+#define BLE_GLS_CONTEXT_CARB_BRUNCH 7 /**< Brunch */
+
+/**@brief Glucose measurement context meal */
+#define BLE_GLS_CONTEXT_MEAL_PREPRANDIAL 1 /**< Preprandial (before meal) */
+#define BLE_GLS_CONTEXT_MEAL_POSTPRANDIAL 2 /**< Postprandial (after meal) */
+#define BLE_GLS_CONTEXT_MEAL_FASTING 3 /**< Fasting */
+#define BLE_GLS_CONTEXT_MEAL_CASUAL 4 /**< Casual (snacks, drinks, etc.) */
+#define BLE_GLS_CONTEXT_MEAL_BEDTIME 5 /**< Bedtime */
+
+/**@brief Glucose measurement context tester */
+#define BLE_GLS_CONTEXT_TESTER_SELF 1 /**< Self */
+#define BLE_GLS_CONTEXT_TESTER_PRO 2 /**< Health care professional */
+#define BLE_GLS_CONTEXT_TESTER_LAB 3 /**< Lab test */
+#define BLE_GLS_CONTEXT_TESTER_NOT_AVAIL 15 /**< Tester value not available */
+
+/**@brief Glucose measurement context health */
+#define BLE_GLS_CONTEXT_HEALTH_MINOR 1 /**< Minor health issues */
+#define BLE_GLS_CONTEXT_HEALTH_MAJOR 2 /**< Major health issues */
+#define BLE_GLS_CONTEXT_HEALTH_MENSES 3 /**< During menses */
+#define BLE_GLS_CONTEXT_HEALTH_STRESS 4 /**< Under stress */
+#define BLE_GLS_CONTEXT_HEALTH_NONE 5 /**< No health issues */
+#define BLE_GLS_CONTEXT_HEALTH_NOT_AVAIL 15 /**< Health value not available */
+
+/**@brief Glucose measurement context medication ID */
+#define BLE_GLS_CONTEXT_MED_RAPID 1 /**< Rapid acting insulin */
+#define BLE_GLS_CONTEXT_MED_SHORT 2 /**< Short acting insulin */
+#define BLE_GLS_CONTEXT_MED_INTERMED 3 /**< Intermediate acting insulin */
+#define BLE_GLS_CONTEXT_MED_LONG 4 /**< Long acting insulin */
+#define BLE_GLS_CONTEXT_MED_PREMIX 5 /**< Pre-mixed insulin */
+
+
+/**@brief SFLOAT format (IEEE-11073 16-bit FLOAT, meaning 4 bits for exponent (base 10) and 12 bits mantissa) */
+typedef struct
+{
+ int8_t exponent; /**< Base 10 exponent, should be using only 4 bits */
+ int16_t mantissa; /**< Mantissa, should be using only 12 bits */
+} sfloat_t;
+
+/**@brief Glucose Service event type. */
+typedef enum
+{
+ BLE_GLS_EVT_NOTIFICATION_ENABLED, /**< Glucose value notification enabled event. */
+ BLE_GLS_EVT_NOTIFICATION_DISABLED /**< Glucose value notification disabled event. */
+} ble_gls_evt_type_t;
+
+/**@brief Glucose Service event. */
+typedef struct
+{
+ ble_gls_evt_type_t evt_type; /**< Type of event. */
+} ble_gls_evt_t;
+
+// Forward declaration of the ble_gls_t type.
+typedef struct ble_gls_s ble_gls_t;
+
+/**@brief Glucose Service event handler type. */
+typedef void (*ble_gls_evt_handler_t) (ble_gls_t * p_gls, ble_gls_evt_t * p_evt);
+
+/**@brief Glucose Measurement structure. This contains glucose measurement value. */
+typedef struct
+{
+ uint8_t flags; /**< Flags */
+ uint16_t sequence_number; /**< Sequence number */
+ ble_date_time_t base_time; /**< Time stamp */
+ int16_t time_offset; /**< Time offset */
+ sfloat_t glucose_concentration; /**< Glucose concentration */
+ uint8_t type; /**< Type */
+ uint8_t sample_location; /**< Sample location */
+ uint16_t sensor_status_annunciation; /**< Sensor status annunciation */
+} ble_gls_meas_t;
+
+/**@brief Glucose measurement context structure */
+typedef struct
+{
+ uint8_t flags; /**< Flags */
+ uint8_t extended_flags; /**< Extended Flags */
+ uint8_t carbohydrate_id; /**< Carbohydrate ID */
+ sfloat_t carbohydrate; /**< Carbohydrate */
+ uint8_t meal; /**< Meal */
+ uint8_t tester_and_health; /**< Tester and health */
+ uint16_t exercise_duration; /**< Exercise Duration */
+ uint8_t exercise_intensity; /**< Exercise Intensity */
+ uint8_t medication_id; /**< Medication ID */
+ sfloat_t medication; /**< Medication */
+ uint16_t hba1c; /**< HbA1c */
+} ble_gls_meas_context_t;
+
+/**@brief Glucose measurement record */
+typedef struct
+{
+ ble_gls_meas_t meas; /**< Glucose measurement */
+ ble_gls_meas_context_t context; /**< Glucose measurement context */
+} ble_gls_rec_t;
+
+/**@brief Glucose Service init structure. This contains all options and data needed for
+ * initialization of the service. */
+typedef struct
+{
+ ble_gls_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Glucose Service. */
+ ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
+ uint16_t feature; /**< Glucose Feature value indicating supported features. */
+ bool is_context_supported; /**< Determines if optional Glucose Measurement Context is to be supported. */
+} ble_gls_init_t;
+
+/**@brief Glucose Service structure. This contains various status information for the service. */
+struct ble_gls_s
+{
+ ble_gls_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Glucose Service. */
+ ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
+ uint16_t service_handle; /**< Handle of Glucose Service (as provided by the BLE stack). */
+ ble_gatts_char_handles_t glm_handles; /**< Handles related to the Glucose Measurement characteristic. */
+ ble_gatts_char_handles_t glm_context_handles; /**< Handles related to the Glucose Measurement Context characteristic. */
+ ble_gatts_char_handles_t glf_handles; /**< Handles related to the Glucose Feature characteristic. */
+ ble_gatts_char_handles_t racp_handles; /**< Handles related to the Record Access Control Point characteristic. */
+ uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
+ uint16_t feature;
+ bool is_context_supported;
+};
+
+
+/**@brief Function for initializing the Glucose Service.
+ *
+ * @details This call allows the application to initialize the Glucose Service.
+ *
+ * @param[out] p_gls Glucose Service structure. This structure will have to be supplied by
+ * the application. It will be initialized by this function, and will later
+ * be used to identify this particular service instance.
+ * @param[in] p_gls_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
+ */
+uint32_t ble_gls_init(ble_gls_t * p_gls, ble_gls_init_t const * p_gls_init);
+
+
+/**@brief Function for handling the Application's BLE Stack events.
+ *
+ * @details Handles all events from the BLE stack of interest to the Glucose Service.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Glucose Service structure.
+ */
+void ble_gls_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for reporting a new glucose measurement to the glucose service module.
+ *
+ * @details The application calls this function after having performed a new glucose measurement.
+ * The new measurement is recorded in the RACP database.
+ *
+ * @param[in] p_gls Glucose Service structure.
+ * @param[in] p_rec Pointer to glucose record (measurement plus context).
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+uint32_t ble_gls_glucose_new_meas(ble_gls_t * p_gls, ble_gls_rec_t * p_rec);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_GLS_H__
+
+/** @} */
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_gls/ble_gls_db.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_gls/ble_gls_db.c
new file mode 100644
index 0000000..679a359
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_gls/ble_gls_db.c
@@ -0,0 +1,143 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_GLS)
+#include "ble_gls_db.h"
+
+
+typedef struct
+{
+ bool in_use_flag;
+ ble_gls_rec_t record;
+} database_entry_t;
+
+static database_entry_t m_database[BLE_GLS_DB_MAX_RECORDS];
+static uint8_t m_database_crossref[BLE_GLS_DB_MAX_RECORDS];
+static uint16_t m_num_records;
+
+
+uint32_t ble_gls_db_init(void)
+{
+ int i;
+
+ for (i = 0; i < BLE_GLS_DB_MAX_RECORDS; i++)
+ {
+ m_database[i].in_use_flag = false;
+ m_database_crossref[i] = 0xFF;
+ }
+
+ m_num_records = 0;
+
+ return NRF_SUCCESS;
+}
+
+
+uint16_t ble_gls_db_num_records_get(void)
+{
+ return m_num_records;
+}
+
+
+uint32_t ble_gls_db_record_get(uint8_t rec_ndx, ble_gls_rec_t * p_rec)
+{
+ if (rec_ndx >= m_num_records)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ // copy record to the specified memory
+ *p_rec = m_database[m_database_crossref[rec_ndx]].record;
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_gls_db_record_add(ble_gls_rec_t * p_rec)
+{
+ int i;
+
+ if (m_num_records == BLE_GLS_DB_MAX_RECORDS)
+ {
+ return NRF_ERROR_NO_MEM;
+ }
+
+ // find next available database entry
+ for (i = 0; i < BLE_GLS_DB_MAX_RECORDS; i++)
+ {
+ if (!m_database[i].in_use_flag)
+ {
+ m_database[i].in_use_flag = true;
+ m_database[i].record = *p_rec;
+
+ m_database_crossref[m_num_records] = i;
+ m_num_records++;
+
+ return NRF_SUCCESS;
+ }
+ }
+
+ return NRF_ERROR_NO_MEM;
+}
+
+
+uint32_t ble_gls_db_record_delete(uint8_t rec_ndx)
+{
+ int i;
+
+ if (rec_ndx >= m_num_records)
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ // free entry
+ m_database[m_database_crossref[rec_ndx]].in_use_flag = false;
+
+ // decrease number of records
+ m_num_records--;
+
+ // remove cross reference index
+ for (i = rec_ndx; i < m_num_records; i++)
+ {
+ m_database_crossref[i] = m_database_crossref[i + 1];
+ }
+
+ return NRF_SUCCESS;
+}
+#endif // NRF_MODULE_ENABLED(BLE_GLS)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_gls/ble_gls_db.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_gls/ble_gls_db.h
new file mode 100644
index 0000000..98465f0
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_gls/ble_gls_db.h
@@ -0,0 +1,121 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_sdk_srv_gls_db Glucose Database Service
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Glucose Service module.
+ *
+ * @details This module implements at database of stored glucose measurement values.
+ *
+ * @note Attention!
+ * To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
+ * qualification listings, These APIs must not be modified. However, the corresponding
+ * functions' implementations can be modified.
+ */
+
+#ifndef BLE_GLS_DB_H__
+#define BLE_GLS_DB_H__
+
+#include <stdint.h>
+#include "ble_gls.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BLE_GLS_DB_MAX_RECORDS 20
+
+/**@brief Function for initializing the glucose record database.
+ *
+ * @details This call initializes the database holding glucose records.
+ *
+ * @return NRF_SUCCESS on success.
+ */
+uint32_t ble_gls_db_init(void);
+
+/**@brief Function for getting the number of records in the database.
+ *
+ * @details This call returns the number of records in the database.
+ *
+ * @return Number of records in the database.
+ */
+uint16_t ble_gls_db_num_records_get(void);
+
+/**@brief Function for getting a record from the database.
+ *
+ * @details This call returns a specified record from the database.
+ *
+ * @param[in] record_num Index of the record to retrieve.
+ * @param[out] p_rec Pointer to record structure where retrieved record is copied to.
+ *
+ * @return NRF_SUCCESS on success.
+ */
+uint32_t ble_gls_db_record_get(uint8_t record_num, ble_gls_rec_t * p_rec);
+
+/**@brief Function for adding a record at the end of the database.
+ *
+ * @details This call adds a record as the last record in the database.
+ *
+ * @param[in] p_rec Pointer to record to add to database.
+ *
+ * @return NRF_SUCCESS on success.
+ */
+uint32_t ble_gls_db_record_add(ble_gls_rec_t * p_rec);
+
+/**@brief Function for deleting a database entry.
+ *
+ * @details This call deletes an record from the database.
+ *
+ * @param[in] record_num Index of record to delete.
+ *
+ * @return NRF_SUCCESS on success.
+ */
+uint32_t ble_gls_db_record_delete(uint8_t record_num);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_GLS_DB_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hids/ble_hids.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hids/ble_hids.c
new file mode 100644
index 0000000..1bf0b38
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hids/ble_hids.c
@@ -0,0 +1,1794 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Attention!
+ * To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_HIDS)
+#include "ble_hids.h"
+#include <string.h>
+#include "app_error.h"
+#include "ble_srv_common.h"
+
+
+// Protocol Mode values
+#define PROTOCOL_MODE_BOOT 0x00 /**< Boot Protocol Mode. */
+#define PROTOCOL_MODE_REPORT 0x01 /**< Report Protocol Mode. */
+
+// HID Control Point values
+#define HIDS_CONTROL_POINT_SUSPEND 0 /**< Suspend command. */
+#define HIDS_CONTROL_POINT_EXIT_SUSPEND 1 /**< Exit Suspend command. */
+
+#define DEFAULT_PROTOCOL_MODE PROTOCOL_MODE_REPORT /**< Default value for the Protocol Mode characteristic. */
+#define INITIAL_VALUE_HID_CONTROL_POINT HIDS_CONTROL_POINT_SUSPEND /**< Initial value for the HID Control Point characteristic. */
+
+#define ENCODED_HID_INFORMATION_LEN 4 /**< Maximum size of an encoded HID Information characteristic. */
+
+/**@brief Handles errors for HID service module.
+ *
+ * @param[in] _p_hids HID Service structure.
+ * @param[in] _err_code Maximum number of HID hosts connected at a time.
+ *
+ */
+#define BLE_HIDS_ERROR_HANDLE(_p_hids, _err_code) \
+ do \
+ { \
+ if (((_err_code) != NRF_SUCCESS) && ((_p_hids)->error_handler != NULL)) \
+ { \
+ (_p_hids)->error_handler((_err_code)); \
+ } \
+ } while (0)
+
+
+/**@brief Function for calculating the link context size for the HID service.
+ *
+ * @param[in] p_hids HID Service structure.
+ *
+ * @return Link context size.
+ */
+static size_t ble_hids_client_context_size_calc(ble_hids_t * p_hids)
+{
+ size_t client_size = sizeof(ble_hids_client_context_t) + (BOOT_KB_INPUT_REPORT_MAX_SIZE) +
+ (BOOT_KB_OUTPUT_REPORT_MAX_SIZE) + (BOOT_MOUSE_INPUT_REPORT_MAX_SIZE);
+
+ if (p_hids->p_inp_rep_init_array != NULL)
+ {
+ for (uint32_t i = 0; i < p_hids->inp_rep_count; i++)
+ {
+ client_size += p_hids->p_inp_rep_init_array[i].max_len;
+ }
+ }
+ if (p_hids->p_outp_rep_init_array != NULL)
+ {
+ for (uint32_t i = 0; i < p_hids->outp_rep_count; i++)
+ {
+ client_size += p_hids->p_outp_rep_init_array[i].max_len;
+ }
+ }
+ if (p_hids->p_feature_rep_init_array != NULL)
+ {
+ for (uint32_t i = 0; i < p_hids->feature_rep_count; i++)
+ {
+ client_size += p_hids->p_feature_rep_init_array[i].max_len;
+ }
+ }
+
+ return client_size;
+}
+
+
+/**@brief Function for making a HID Service characteristic id.
+ *
+ * @param[in] uuid UUID of characteristic.
+ * @param[in] rep_type Type of report.
+ * @param[in] rep_index Index of the characteristic.
+ *
+ * @return HID Service characteristic id structure.
+ */
+static ble_hids_char_id_t make_char_id(uint16_t uuid, uint8_t rep_type, uint8_t rep_index)
+{
+ ble_hids_char_id_t char_id = {0};
+
+ char_id.uuid = uuid;
+ char_id.rep_type = rep_type;
+ char_id.rep_index = rep_index;
+
+ return char_id;
+}
+
+
+/**@brief Function for handling the Connect event.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_connect(ble_hids_t * p_hids, ble_evt_t const * p_ble_evt)
+{
+ uint32_t err_code;
+ ble_gatts_value_t gatts_value;
+ ble_hids_client_context_t * p_client = NULL;
+
+ err_code = blcm_link_ctx_get(p_hids->p_link_ctx_storage,
+ p_ble_evt->evt.gap_evt.conn_handle,
+ (void *) &p_client);
+ BLE_HIDS_ERROR_HANDLE(p_hids, err_code);
+
+ if (p_client == NULL)
+ {
+ return;
+ }
+
+ memset(p_client, 0, ble_hids_client_context_size_calc(p_hids));
+
+ if (p_hids->protocol_mode_handles.value_handle)
+ {
+ // Set Protocol Mode characteristic value to default value
+ p_client->protocol_mode = DEFAULT_PROTOCOL_MODE;
+
+ // Initialize value struct.
+ memset(&gatts_value, 0, sizeof(gatts_value));
+
+ gatts_value.len = sizeof(uint8_t);
+ gatts_value.offset = 0;
+ gatts_value.p_value = &p_client->protocol_mode;
+
+ err_code = sd_ble_gatts_value_set(p_ble_evt->evt.gap_evt.conn_handle,
+ p_hids->protocol_mode_handles.value_handle,
+ &gatts_value);
+ BLE_HIDS_ERROR_HANDLE(p_hids, err_code);
+ }
+}
+
+
+/**@brief Function for handling write events to the HID Control Point value.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] p_evt_write Write event received from the BLE stack.
+ */
+static void on_control_point_write(ble_hids_t * p_hids, ble_evt_t const * p_ble_evt)
+{
+ ret_code_t err_code;
+ ble_hids_client_context_t * p_host;
+ ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+ err_code = blcm_link_ctx_get(p_hids->p_link_ctx_storage,
+ p_ble_evt->evt.gatts_evt.conn_handle,
+ (void *) &p_host);
+ BLE_HIDS_ERROR_HANDLE(p_hids, err_code);
+
+ if (p_host == NULL)
+ {
+ return;
+ }
+
+ if (p_evt_write->len == 1)
+ {
+ ble_hids_evt_t evt;
+
+ switch (p_evt_write->data[0])
+ {
+ case HIDS_CONTROL_POINT_SUSPEND:
+ evt.evt_type = BLE_HIDS_EVT_HOST_SUSP;
+ break;
+
+ case HIDS_CONTROL_POINT_EXIT_SUSPEND:
+ evt.evt_type = BLE_HIDS_EVT_HOST_EXIT_SUSP;
+ break;
+
+ default:
+ // Illegal Control Point value, ignore
+ return;
+ }
+
+ // Store the new Control Point value for the host
+ p_host->ctrl_pt = p_evt_write->data[0];
+
+ // HID Control Point written, propagate event to application
+ if (p_hids->evt_handler != NULL)
+ {
+ evt.p_ble_evt = p_ble_evt;
+ p_hids->evt_handler(p_hids, &evt);
+ }
+ }
+}
+
+
+/**@brief Function for handling write events to the Protocol Mode value.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] p_ble_evt BLE event received from the BLE stack.
+ */
+static void on_protocol_mode_write(ble_hids_t * p_hids, ble_evt_t const * p_ble_evt)
+{
+ ret_code_t err_code;
+ ble_hids_client_context_t * p_host;
+ ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+ err_code = blcm_link_ctx_get(p_hids->p_link_ctx_storage,
+ p_ble_evt->evt.gatts_evt.conn_handle,
+ (void *) &p_host);
+ BLE_HIDS_ERROR_HANDLE(p_hids, err_code);
+
+
+ if (p_host == NULL)
+ {
+ return;
+ }
+
+ if (p_evt_write->len == 1)
+ {
+ ble_hids_evt_t evt;
+
+ switch (p_evt_write->data[0])
+ {
+ case PROTOCOL_MODE_BOOT:
+ evt.evt_type = BLE_HIDS_EVT_BOOT_MODE_ENTERED;
+ break;
+
+ case PROTOCOL_MODE_REPORT:
+ evt.evt_type = BLE_HIDS_EVT_REPORT_MODE_ENTERED;
+ break;
+
+ default:
+ // Illegal Protocol Mode value, ignore
+ return;
+ }
+
+ // Store Protocol Mode of the host
+ p_host->protocol_mode = p_evt_write->data[0];
+
+ // HID Protocol Mode written, propagate event to application
+ if (p_hids->evt_handler != NULL)
+ {
+ evt.p_ble_evt = p_ble_evt;
+ p_hids->evt_handler(p_hids, &evt);
+ }
+ }
+}
+
+
+/**@brief Function for handling authorize read events to the Protocol Mode value.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] p_ble_evt BLE event received from the BLE stack.
+ */
+void on_protocol_mode_read_auth(ble_hids_t * p_hids, ble_evt_t const * p_ble_evt)
+{
+ ret_code_t err_code;
+ ble_gatts_rw_authorize_reply_params_t auth_read_params;
+ ble_hids_client_context_t * p_host;
+ ble_gatts_evt_rw_authorize_request_t const * p_read_auth =
+ &p_ble_evt->evt.gatts_evt.params.authorize_request;
+
+ err_code = blcm_link_ctx_get(p_hids->p_link_ctx_storage,
+ p_ble_evt->evt.gatts_evt.conn_handle,
+ (void *) &p_host);
+ BLE_HIDS_ERROR_HANDLE(p_hids, err_code);
+
+ // Update GATTS table with this host's Protocol Mode value and authorize Read
+ if (p_host != NULL)
+ {
+ memset(&auth_read_params, 0, sizeof(auth_read_params));
+
+ auth_read_params.type = BLE_GATTS_AUTHORIZE_TYPE_READ;
+ auth_read_params.params.read.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ auth_read_params.params.read.offset = p_read_auth->request.read.offset;
+ auth_read_params.params.read.len = sizeof(uint8_t);
+ auth_read_params.params.read.p_data = &p_host->protocol_mode;
+ auth_read_params.params.read.update = 1;
+
+ err_code = sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gap_evt.conn_handle,
+ &auth_read_params);
+ BLE_HIDS_ERROR_HANDLE(p_hids, err_code);
+ }
+}
+
+
+/**@brief Function for handling write events to a report CCCD.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] p_char_id Id of report characteristic.
+ * @param[in] p_ble_evt BLE event received from the BLE stack.
+ */
+static void on_report_cccd_write(ble_hids_t * p_hids,
+ ble_hids_char_id_t * p_char_id,
+ ble_evt_t const * p_ble_evt)
+{
+ ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+ if (p_evt_write->len == 2)
+ {
+ // CCCD written, update notification state
+ if (p_hids->evt_handler != NULL)
+ {
+ ble_hids_evt_t evt;
+
+ if (ble_srv_is_notification_enabled(p_evt_write->data))
+ {
+ evt.evt_type = BLE_HIDS_EVT_NOTIF_ENABLED;
+ }
+ else
+ {
+ evt.evt_type = BLE_HIDS_EVT_NOTIF_DISABLED;
+ }
+ evt.params.notification.char_id = *p_char_id;
+ evt.p_ble_evt = p_ble_evt;
+
+ p_hids->evt_handler(p_hids, &evt);
+ }
+ }
+}
+
+
+/**@brief Function for handling write events to a report value.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] p_ble_evt Pointer to BLE event structure.
+ * @param[in] p_char_id Id of report characteristic.
+ * @param[in] rep_offset Offset to the affected HID report data.
+ * @param[in] rep_max_len Maximum HID report length.
+ */
+static void on_report_value_write(ble_hids_t * p_hids,
+ ble_evt_t const * p_ble_evt,
+ ble_hids_char_id_t * p_char_id,
+ uint16_t rep_offset,
+ uint16_t rep_max_len)
+{
+ // Update host's Output Report data
+ ret_code_t err_code;
+ uint8_t * p_report;
+ ble_hids_client_context_t * p_host;
+ ble_gatts_evt_write_t const * p_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+ err_code = blcm_link_ctx_get(p_hids->p_link_ctx_storage,
+ p_ble_evt->evt.gatts_evt.conn_handle,
+ (void *) &p_host);
+ BLE_HIDS_ERROR_HANDLE(p_hids, err_code);
+
+ // Store the written values in host's report data
+ if ((p_host != NULL) && (p_write->len + p_write->offset <= rep_max_len))
+ {
+ p_report = (uint8_t *) p_host + rep_offset;
+ memcpy(p_report, p_write->data, p_write->len);
+ }
+ else
+ {
+ return;
+ }
+
+ // Notify the applicartion
+ if (p_hids->evt_handler != NULL)
+ {
+ ble_hids_evt_t evt;
+
+ evt.evt_type = BLE_HIDS_EVT_REP_CHAR_WRITE;
+ evt.params.char_write.char_id = *p_char_id;
+ evt.params.char_write.offset = p_ble_evt->evt.gatts_evt.params.write.offset;
+ evt.params.char_write.len = p_ble_evt->evt.gatts_evt.params.write.len;
+ evt.params.char_write.data = p_ble_evt->evt.gatts_evt.params.write.data;
+ evt.p_ble_evt = p_ble_evt;
+
+ p_hids->evt_handler(p_hids, &evt);
+ }
+}
+
+
+/**@brief Handle authorize read events to a report value.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] p_char_id Id of report characteristic.
+ * @param[in] p_ble_evt Pointer to BLE event structure.
+ * @param[in] rep_offset Report data offset.
+ * @param[in] rep_max_len Report maximum length.
+ */
+static void on_report_value_read_auth(ble_hids_t * p_hids,
+ ble_hids_char_id_t * p_char_id,
+ ble_evt_t const * p_ble_evt,
+ uint16_t rep_offset,
+ uint16_t rep_max_len)
+{
+ ble_gatts_rw_authorize_reply_params_t auth_read_params;
+ ble_hids_client_context_t * p_host;
+ uint8_t * p_report;
+ uint16_t read_offset;
+ uint32_t err_code = NRF_SUCCESS;
+
+ err_code = blcm_link_ctx_get(p_hids->p_link_ctx_storage,
+ p_ble_evt->evt.gatts_evt.conn_handle,
+ (void *) &p_host);
+ BLE_HIDS_ERROR_HANDLE(p_hids, err_code);
+
+ // Update Report GATTS table with host's current report data
+ if (p_host != NULL)
+ {
+ read_offset = p_ble_evt->evt.gatts_evt.params.authorize_request.request.read.offset;
+ p_report = (uint8_t *) p_host + rep_offset;
+ memset(&auth_read_params, 0, sizeof(auth_read_params));
+
+ auth_read_params.type = BLE_GATTS_AUTHORIZE_TYPE_READ;
+ auth_read_params.params.read.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ auth_read_params.params.read.offset = read_offset;
+ auth_read_params.params.read.len = rep_max_len - read_offset;
+ auth_read_params.params.read.p_data = p_report + read_offset;
+ auth_read_params.params.read.update = 1;
+
+ err_code = sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gap_evt.conn_handle,
+ &auth_read_params);
+
+ BLE_HIDS_ERROR_HANDLE(p_hids, err_code);
+ }
+ else
+ {
+ return;
+ }
+
+ if (p_hids->evt_handler != NULL)
+ {
+ ble_hids_evt_t evt;
+
+ evt.evt_type = BLE_HIDS_EVT_REPORT_READ;
+ evt.params.char_auth_read.char_id = *p_char_id;
+ evt.p_ble_evt = p_ble_evt;
+
+ p_hids->evt_handler(p_hids, &evt);
+ }
+}
+
+
+/**@brief Function for finding the Characteristic Id of a characteristic corresponding to a CCCD handle.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] handle Handle to search for.
+ * @param[out] p_char_id Id of report characteristic.
+ *
+ * @return TRUE if CCCD handle was found, FALSE otherwise.
+ */
+static bool inp_rep_cccd_identify(ble_hids_t * p_hids,
+ uint16_t handle,
+ ble_hids_char_id_t * p_char_id)
+{
+ uint8_t i;
+
+ for (i = 0; i < p_hids->inp_rep_count; i++)
+ {
+ if (handle == p_hids->inp_rep_array[i].char_handles.cccd_handle)
+ {
+ *p_char_id = make_char_id(BLE_UUID_REPORT_CHAR, BLE_HIDS_REP_TYPE_INPUT, i);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+/**@brief Function for finding the Characteristic Id of a characteristic corresponding to a value handle.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] handle Handle to search for.
+ * @param[out] p_char_id Id of report characteristic.
+ * @param[out] p_context_offset Pointer to offset to the report data within the host data.
+ * @param[out] p_rep_max_len Pointer to maximum report length.
+ *
+ * @return TRUE if value handle was found, FALSE otherwise.
+ */
+static bool rep_value_identify(ble_hids_t * p_hids,
+ uint16_t handle,
+ ble_hids_char_id_t * p_char_id,
+ uint16_t * p_context_offset,
+ uint16_t * p_rep_max_len)
+{
+ uint8_t i;
+
+ /* Initialize the offset with size of non-report-related data */
+ *p_context_offset = sizeof(ble_hids_client_context_t) + BOOT_KB_INPUT_REPORT_MAX_SIZE +
+ BOOT_KB_OUTPUT_REPORT_MAX_SIZE + BOOT_MOUSE_INPUT_REPORT_MAX_SIZE;
+
+ if (p_hids->p_inp_rep_init_array != NULL)
+ {
+ for (i = 0; i < p_hids->inp_rep_count; i++)
+ {
+ if (handle == p_hids->inp_rep_array[i].char_handles.value_handle)
+ {
+ *p_char_id = make_char_id(BLE_UUID_REPORT_CHAR, BLE_HIDS_REP_TYPE_INPUT, i);
+ *p_rep_max_len = p_hids->p_inp_rep_init_array[i].max_len;
+ return true;
+ }
+ *p_context_offset += p_hids->p_inp_rep_init_array[i].max_len;
+ }
+ }
+ if (p_hids->p_outp_rep_init_array != NULL)
+ {
+ for (i = 0; i < p_hids->outp_rep_count; i++)
+ {
+ if (handle == p_hids->outp_rep_array[i].char_handles.value_handle)
+ {
+ *p_char_id = make_char_id(BLE_UUID_REPORT_CHAR, BLE_HIDS_REP_TYPE_OUTPUT, i);
+ *p_rep_max_len = p_hids->p_outp_rep_init_array[i].max_len;
+ return true;
+ }
+ *p_context_offset += p_hids->p_outp_rep_init_array[i].max_len;
+ }
+ }
+ if (p_hids->p_feature_rep_init_array != NULL)
+ {
+ for (i = 0; i < p_hids->feature_rep_count; i++)
+ {
+ if (handle == p_hids->feature_rep_array[i].char_handles.value_handle)
+ {
+ *p_char_id = make_char_id(BLE_UUID_REPORT_CHAR, BLE_HIDS_REP_TYPE_FEATURE, i);
+ *p_rep_max_len = p_hids->p_feature_rep_init_array[i].max_len;
+ return true;
+ }
+ *p_context_offset += p_hids->p_feature_rep_init_array[i].max_len;
+ }
+ }
+
+ return false;
+}
+
+
+/**@brief Function for handling the Write event.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_write(ble_hids_t * p_hids, ble_evt_t const * p_ble_evt)
+{
+ ble_hids_char_id_t char_id;
+ ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+ uint16_t rep_data_offset = sizeof(ble_hids_client_context_t);
+ uint16_t max_rep_len = 0;
+
+ if (p_evt_write->handle == p_hids->hid_control_point_handles.value_handle)
+ {
+ on_control_point_write(p_hids, p_ble_evt);
+ }
+ else if (p_evt_write->handle == p_hids->protocol_mode_handles.value_handle)
+ {
+ on_protocol_mode_write(p_hids, p_ble_evt);
+ }
+ else if (p_evt_write->handle == p_hids->boot_kb_inp_rep_handles.cccd_handle)
+ {
+ char_id = make_char_id(BLE_UUID_BOOT_KEYBOARD_INPUT_REPORT_CHAR, 0, 0);
+ on_report_cccd_write(p_hids, &char_id, p_ble_evt);
+ }
+ else if (p_evt_write->handle == p_hids->boot_kb_inp_rep_handles.value_handle)
+ {
+ char_id = make_char_id(BLE_UUID_BOOT_KEYBOARD_INPUT_REPORT_CHAR, 0, 0);
+ max_rep_len = BOOT_KB_INPUT_REPORT_MAX_SIZE;
+ on_report_value_write(p_hids, p_ble_evt, &char_id, rep_data_offset, max_rep_len);
+ }
+ else if (p_evt_write->handle == p_hids->boot_kb_outp_rep_handles.value_handle)
+ {
+ char_id = make_char_id(BLE_UUID_BOOT_KEYBOARD_OUTPUT_REPORT_CHAR, 0, 0);
+ rep_data_offset += BOOT_KB_INPUT_REPORT_MAX_SIZE;
+ max_rep_len = BOOT_KB_OUTPUT_REPORT_MAX_SIZE;
+ on_report_value_write(p_hids, p_ble_evt, &char_id, rep_data_offset, max_rep_len);
+ }
+ else if (p_evt_write->handle == p_hids->boot_mouse_inp_rep_handles.cccd_handle)
+ {
+ char_id = make_char_id(BLE_UUID_BOOT_MOUSE_INPUT_REPORT_CHAR, 0, 0);
+ on_report_cccd_write(p_hids, &char_id, p_ble_evt);
+ }
+ else if (p_evt_write->handle == p_hids->boot_mouse_inp_rep_handles.value_handle)
+ {
+ char_id = make_char_id(BLE_UUID_BOOT_MOUSE_INPUT_REPORT_CHAR, 0, 0);
+ rep_data_offset += BOOT_KB_INPUT_REPORT_MAX_SIZE + BOOT_KB_OUTPUT_REPORT_MAX_SIZE;
+ max_rep_len = BOOT_MOUSE_INPUT_REPORT_MAX_SIZE;
+ on_report_value_write(p_hids, p_ble_evt, &char_id, rep_data_offset, max_rep_len);
+ }
+ else if (inp_rep_cccd_identify(p_hids, p_evt_write->handle, &char_id))
+ {
+ on_report_cccd_write(p_hids, &char_id, p_ble_evt);
+ }
+ else if (rep_value_identify(p_hids,
+ p_evt_write->handle,
+ &char_id,
+ &rep_data_offset,
+ &max_rep_len))
+ {
+ on_report_value_write(p_hids, p_ble_evt, &char_id, rep_data_offset, max_rep_len);
+ }
+ else
+ {
+ // No implementation needed.
+ }
+}
+
+
+/**@brief Read/write authorize request event handler.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_rw_authorize_request(ble_hids_t * p_hids, ble_evt_t const * p_ble_evt)
+{
+ ble_gatts_evt_rw_authorize_request_t const * evt_rw_auth =
+ &p_ble_evt->evt.gatts_evt.params.authorize_request;
+
+ ble_hids_char_id_t char_id;
+ uint16_t rep_data_offset = sizeof(ble_hids_client_context_t);
+ uint16_t max_rep_len = 0;
+
+ if (evt_rw_auth->type != BLE_GATTS_AUTHORIZE_TYPE_READ)
+ {
+ // Unexpected operation
+ return;
+ }
+
+ /* Update SD GATTS values of appropriate host before SD sends the Read Response */
+ if (evt_rw_auth->request.read.handle == p_hids->protocol_mode_handles.value_handle)
+ {
+ on_protocol_mode_read_auth(p_hids, p_ble_evt);
+ }
+ else if (evt_rw_auth->request.read.handle == p_hids->boot_kb_inp_rep_handles.value_handle)
+ {
+ char_id = make_char_id(BLE_UUID_BOOT_KEYBOARD_INPUT_REPORT_CHAR, 0, 0);
+ max_rep_len = BOOT_KB_INPUT_REPORT_MAX_SIZE;
+ on_report_value_read_auth(p_hids, &char_id, p_ble_evt, rep_data_offset, max_rep_len);
+ }
+ else if (evt_rw_auth->request.read.handle == p_hids->boot_kb_outp_rep_handles.value_handle)
+ {
+ char_id = make_char_id(BLE_UUID_BOOT_KEYBOARD_OUTPUT_REPORT_CHAR, 0, 0);
+ rep_data_offset += BOOT_KB_INPUT_REPORT_MAX_SIZE;
+ max_rep_len = BOOT_KB_OUTPUT_REPORT_MAX_SIZE;
+ on_report_value_read_auth(p_hids, &char_id, p_ble_evt, rep_data_offset, max_rep_len);
+ }
+ else if (evt_rw_auth->request.read.handle == p_hids->boot_mouse_inp_rep_handles.value_handle)
+ {
+ char_id = make_char_id(BLE_UUID_BOOT_MOUSE_INPUT_REPORT_CHAR, 0, 0);
+ rep_data_offset += BOOT_KB_INPUT_REPORT_MAX_SIZE + BOOT_KB_OUTPUT_REPORT_MAX_SIZE;
+ max_rep_len = BOOT_MOUSE_INPUT_REPORT_MAX_SIZE;
+ on_report_value_read_auth(p_hids, &char_id, p_ble_evt, rep_data_offset, max_rep_len);
+ }
+ else if (rep_value_identify(p_hids,
+ evt_rw_auth->request.read.handle,
+ &char_id,
+ &rep_data_offset,
+ &max_rep_len))
+ {
+ on_report_value_read_auth(p_hids, &char_id, p_ble_evt, rep_data_offset, max_rep_len);
+ }
+}
+
+
+void ble_hids_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ ble_hids_t * p_hids = (ble_hids_t *) p_context;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ on_connect(p_hids, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_WRITE:
+ on_write(p_hids, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
+ on_rw_authorize_request(p_hids, p_ble_evt);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+
+/**@brief Function for adding Protocol Mode characteristics.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] p_sec_mode Characteristic security settings.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t protocol_mode_char_add(ble_hids_t * p_hids,
+ const ble_srv_security_mode_t * p_sec_mode)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+ uint8_t initial_protocol_mode;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.char_props.write_wo_resp = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = NULL;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_PROTOCOL_MODE_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.read_perm = p_sec_mode->read_perm;
+ attr_md.write_perm = p_sec_mode->write_perm;
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 1;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ initial_protocol_mode = DEFAULT_PROTOCOL_MODE;
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = sizeof(uint8_t);
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = sizeof(uint8_t);
+ attr_char_value.p_value = &initial_protocol_mode;
+
+ return sd_ble_gatts_characteristic_add(p_hids->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_hids->protocol_mode_handles);
+}
+
+
+/**@brief Function for adding report characteristics.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] p_properties Report characteristic properties.
+ * @param[in] max_len Maximum length of report value.
+ * @param[in] p_rep_ref Report Reference descriptor.
+ * @param[in] p_rep_ref_attr_md Characteristic security settings.
+ * @param[in] is_read_resp Characteristic read authorization.
+ * @param[out] p_rep_char Handles of new characteristic.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t rep_char_add(ble_hids_t * p_hids,
+ ble_gatt_char_props_t * p_properties,
+ uint16_t max_len,
+ ble_srv_report_ref_t const * p_rep_ref,
+ ble_srv_cccd_security_mode_t const * p_rep_ref_attr_md,
+ bool is_read_resp,
+ ble_hids_rep_char_t * p_rep_char)
+{
+ uint32_t err_code;
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_md_t cccd_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+ uint8_t encoded_rep_ref[BLE_SRV_ENCODED_REPORT_REF_LEN];
+
+ // Add Report characteristic
+ if (p_properties->notify)
+ {
+ memset(&cccd_md, 0, sizeof(cccd_md));
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
+ cccd_md.write_perm = p_rep_ref_attr_md->cccd_write_perm;
+ cccd_md.vloc = BLE_GATTS_VLOC_STACK;
+ }
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props = *p_properties;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = (p_properties->notify) ? &cccd_md : NULL;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_REPORT_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.read_perm = p_rep_ref_attr_md->read_perm;
+ attr_md.write_perm = p_rep_ref_attr_md->write_perm;
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = is_read_resp ? 1 : 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 1;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = 0;
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = max_len;
+ attr_char_value.p_value = NULL;
+
+ err_code = sd_ble_gatts_characteristic_add(p_hids->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_rep_char->char_handles);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add Report Reference descriptor
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_REPORT_REF_DESCR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.read_perm = p_rep_ref_attr_md->read_perm;
+ attr_md.write_perm = p_rep_ref_attr_md->write_perm;
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = ble_srv_report_ref_encode(encoded_rep_ref, p_rep_ref);
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = attr_char_value.init_len;
+ attr_char_value.p_value = encoded_rep_ref;
+
+ return sd_ble_gatts_descriptor_add(p_rep_char->char_handles.value_handle,
+ &attr_char_value,
+ &p_rep_char->ref_handle);
+}
+
+
+/**@brief Function for adding Report Map characteristics.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] p_hids_init Service initialization structure.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t rep_map_char_add(ble_hids_t * p_hids, const ble_hids_init_t * p_hids_init)
+{
+ uint32_t err_code;
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+
+ // Add Report Map characteristic
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = NULL;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_REPORT_MAP_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.read_perm = p_hids_init->rep_map.security_mode.read_perm;
+ attr_md.write_perm = p_hids_init->rep_map.security_mode.write_perm;
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 1;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = p_hids_init->rep_map.data_len;
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = p_hids_init->rep_map.data_len;
+ attr_char_value.p_value = p_hids_init->rep_map.p_data;
+
+ err_code = sd_ble_gatts_characteristic_add(p_hids->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_hids->rep_map_handles);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ if (p_hids_init->rep_map.ext_rep_ref_num != 0 && p_hids_init->rep_map.p_ext_rep_ref == NULL)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ for (int i = 0; i < p_hids_init->rep_map.ext_rep_ref_num; ++i)
+ {
+ uint8_t encoded_rep_ref[sizeof(ble_uuid128_t)];
+ uint8_t encoded_rep_ref_len;
+
+ // Add External Report Reference descriptor
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_EXTERNAL_REPORT_REF_DESCR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.read_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
+
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ err_code = sd_ble_uuid_encode(&p_hids_init->rep_map.p_ext_rep_ref[i],
+ &encoded_rep_ref_len,
+ encoded_rep_ref);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = encoded_rep_ref_len;
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = attr_char_value.init_len;
+ attr_char_value.p_value = encoded_rep_ref;
+
+ err_code = sd_ble_gatts_descriptor_add(p_hids->rep_map_handles.value_handle,
+ &attr_char_value,
+ &p_hids->rep_map_ext_rep_ref_handle);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for adding Input Report characteristics.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] uuid UUID of report characteristic to be added.
+ * @param[in] max_data_len Maximum length of report value.
+ * @param[in] p_sec_mode Characteristic security settings.
+ * @param[out] p_char_handles Handles of new characteristic.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t boot_inp_rep_char_add(ble_hids_t * p_hids,
+ uint16_t uuid,
+ uint16_t max_data_len,
+ const ble_srv_cccd_security_mode_t * p_sec_mode,
+ ble_gatts_char_handles_t * p_char_handles)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_md_t cccd_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+
+ memset(&cccd_md, 0, sizeof(cccd_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
+ cccd_md.write_perm = p_sec_mode->cccd_write_perm;
+ cccd_md.vloc = BLE_GATTS_VLOC_STACK;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.char_props.write = (p_sec_mode->write_perm.sm) ? 1 : 0;
+ char_md.char_props.notify = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = &cccd_md;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, uuid);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.read_perm = p_sec_mode->read_perm;
+ attr_md.write_perm = p_sec_mode->write_perm;
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 1;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = 0;
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = max_data_len;
+ attr_char_value.p_value = NULL;
+
+ return sd_ble_gatts_characteristic_add(p_hids->service_handle,
+ &char_md,
+ &attr_char_value,
+ p_char_handles);
+}
+
+
+/**@brief Function for adding Boot Keyboard Output Report characteristics.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] p_hids_init Service initialization structure.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t boot_kb_outp_rep_char_add(ble_hids_t * p_hids, const ble_hids_init_t * p_hids_init)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.char_props.write = 1;
+ char_md.char_props.write_wo_resp = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = NULL;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_BOOT_KEYBOARD_OUTPUT_REPORT_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.read_perm = p_hids_init->security_mode_boot_kb_outp_rep.read_perm;
+ attr_md.write_perm = p_hids_init->security_mode_boot_kb_outp_rep.write_perm;
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 1;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = 0;
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = BOOT_KB_OUTPUT_REPORT_MAX_SIZE;
+ attr_char_value.p_value = NULL;
+
+ return sd_ble_gatts_characteristic_add(p_hids->service_handle, &char_md, &attr_char_value,
+ &p_hids->boot_kb_outp_rep_handles);
+}
+
+
+/**@brief Function for encoding a HID Information characteristic value.
+ *
+ * @param[out] p_encoded_buffer Buffer where the encoded data will be written.
+ * @param[in] p_hid_information Measurement to be encoded.
+ *
+ * @return Size of encoded data.
+ */
+static uint8_t encode_hid_information(uint8_t * p_encoded_buffer,
+ const ble_hids_hid_information_t * p_hid_information)
+{
+ uint8_t len = uint16_encode(p_hid_information->bcd_hid, p_encoded_buffer);
+
+ p_encoded_buffer[len++] = p_hid_information->b_country_code;
+ p_encoded_buffer[len++] = p_hid_information->flags;
+
+ APP_ERROR_CHECK_BOOL(len == ENCODED_HID_INFORMATION_LEN);
+
+ return len;
+}
+
+
+/**@brief Function for adding HID Information characteristics.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] p_hids_init Service initialization structure.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t hid_information_char_add(ble_hids_t * p_hids, const ble_hids_init_t * p_hids_init)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+ uint8_t encoded_hid_information[ENCODED_HID_INFORMATION_LEN];
+ uint8_t hid_info_len;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = NULL;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_HID_INFORMATION_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.read_perm = p_hids_init->hid_information.security_mode.read_perm;
+ attr_md.write_perm = p_hids_init->hid_information.security_mode.write_perm;
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ hid_info_len = encode_hid_information(encoded_hid_information, &p_hids_init->hid_information);
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = hid_info_len;
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = attr_char_value.init_len;
+ attr_char_value.p_value = encoded_hid_information;
+
+ return sd_ble_gatts_characteristic_add(p_hids->service_handle, &char_md,
+ &attr_char_value,
+ &p_hids->hid_information_handles);
+}
+
+
+/**@brief Function for adding HID Control Point characteristics.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] p_sec_mode Characteristic security settings.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t hid_control_point_char_add(ble_hids_t * p_hids,
+ const ble_srv_security_mode_t * p_sec_mode)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+ uint8_t initial_hid_control_point;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.write_wo_resp = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = NULL;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_HID_CONTROL_POINT_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.read_perm = p_sec_mode->read_perm;
+ attr_md.write_perm = p_sec_mode->write_perm;
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ initial_hid_control_point = INITIAL_VALUE_HID_CONTROL_POINT;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = sizeof(uint8_t);
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = sizeof(uint8_t);
+ attr_char_value.p_value = &initial_hid_control_point;
+
+ return sd_ble_gatts_characteristic_add(p_hids->service_handle, &char_md,
+ &attr_char_value,
+ &p_hids->hid_control_point_handles);
+}
+
+
+/**@brief Function for adding input report characteristics.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] p_hids_init Service initialization structure.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t inp_rep_characteristics_add(ble_hids_t * p_hids,
+ const ble_hids_init_t * p_hids_init)
+{
+ if ((p_hids_init->inp_rep_count != 0) && (p_hids_init->p_inp_rep_array != NULL))
+ {
+ uint8_t i;
+
+ for (i = 0; i < p_hids_init->inp_rep_count; i++)
+ {
+ uint32_t err_code;
+ ble_hids_inp_rep_init_t const * p_rep_init = &p_hids_init->p_inp_rep_array[i];
+ ble_gatt_char_props_t properties;
+
+ memset(&properties, 0, sizeof(properties));
+
+ properties.read = true;
+ properties.write = p_rep_init->security_mode.write_perm.sm ? 1 : 0;
+ properties.notify = true;
+
+ err_code = rep_char_add(p_hids,
+ &properties,
+ p_rep_init->max_len,
+ &p_rep_init->rep_ref,
+ &p_rep_init->security_mode,
+ 1,
+ &p_hids->inp_rep_array[i]);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for adding output report characteristics.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] p_hids_init Service initialization structure.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t outp_rep_characteristics_add(ble_hids_t * p_hids,
+ const ble_hids_init_t * p_hids_init)
+{
+ if ((p_hids_init->outp_rep_count != 0) && (p_hids_init->p_outp_rep_array != NULL))
+ {
+ uint8_t i;
+
+ for (i = 0; i < p_hids_init->outp_rep_count; i++)
+ {
+ uint32_t err_code;
+ ble_hids_outp_rep_init_t const * p_rep_init = &p_hids_init->p_outp_rep_array[i];
+ ble_gatt_char_props_t properties;
+
+ memset(&properties, 0, sizeof(properties));
+
+ properties.read = true;
+ properties.write = true;
+ properties.write_wo_resp = true;
+
+ err_code = rep_char_add(p_hids,
+ &properties,
+ p_rep_init->max_len,
+ &p_rep_init->rep_ref,
+ &p_rep_init->security_mode,
+ 1,
+ &p_hids->outp_rep_array[i]);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for adding feature report characteristics.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] p_hids_init Service initialization structure.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t feature_rep_characteristics_add(ble_hids_t * p_hids,
+ const ble_hids_init_t * p_hids_init)
+{
+ if ((p_hids_init->feature_rep_count != 0) && (p_hids_init->p_feature_rep_array != NULL))
+ {
+ uint8_t i;
+
+ for (i = 0; i < p_hids_init->feature_rep_count; i++)
+ {
+ uint32_t err_code;
+ ble_hids_feature_rep_init_t const * p_rep_init = &p_hids_init->p_feature_rep_array[i];
+ ble_gatt_char_props_t properties;
+
+ memset(&properties, 0, sizeof(properties));
+
+ properties.read = true;
+ properties.write = true;
+
+ err_code = rep_char_add(p_hids,
+ &properties,
+ p_rep_init->max_len,
+ &p_rep_init->rep_ref,
+ &p_rep_init->security_mode,
+ 1,
+ &p_hids->feature_rep_array[i]);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for adding included services.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] p_hids_init Service initialization structure.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t includes_add(ble_hids_t * p_hids, const ble_hids_init_t * p_hids_init)
+{
+ uint32_t err_code;
+ uint8_t i;
+ uint16_t unused_include_handle;
+
+ for (i = 0; i < p_hids_init->included_services_count; i++)
+ {
+ err_code = sd_ble_gatts_include_add(p_hids->service_handle,
+ p_hids_init->p_included_services_array[i],
+ &unused_include_handle);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_hids_init(ble_hids_t * p_hids, const ble_hids_init_t * p_hids_init)
+{
+ uint32_t err_code;
+ ble_uuid_t ble_uuid;
+
+ if ((p_hids_init->inp_rep_count > BLE_HIDS_MAX_INPUT_REP) ||
+ (p_hids_init->outp_rep_count > BLE_HIDS_MAX_OUTPUT_REP) ||
+ (p_hids_init->feature_rep_count > BLE_HIDS_MAX_FEATURE_REP)
+ )
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ // Initialize service structure.
+ p_hids->evt_handler = p_hids_init->evt_handler;
+ p_hids->error_handler = p_hids_init->error_handler;
+ p_hids->inp_rep_count = p_hids_init->inp_rep_count;
+ p_hids->outp_rep_count = p_hids_init->outp_rep_count;
+ p_hids->feature_rep_count = p_hids_init->feature_rep_count;
+
+ // Add service.
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_HUMAN_INTERFACE_DEVICE_SERVICE);
+
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
+ &ble_uuid,
+ &p_hids->service_handle);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add includes.
+ err_code = includes_add(p_hids, p_hids_init);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ if (p_hids_init->is_kb || p_hids_init->is_mouse)
+ {
+ // Add Protocol Mode characteristic.
+ err_code = protocol_mode_char_add(p_hids, &p_hids_init->security_mode_protocol);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ // Add Input Report characteristics (if any).
+ err_code = inp_rep_characteristics_add(p_hids, p_hids_init);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add Output Report characteristics (if any).
+ err_code = outp_rep_characteristics_add(p_hids, p_hids_init);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add Feature Report characteristic (if any).
+ err_code = feature_rep_characteristics_add(p_hids, p_hids_init);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add Report Map characteristic.
+ err_code = rep_map_char_add(p_hids, p_hids_init);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ if (p_hids_init->is_kb)
+ {
+ // Add Boot Keyboard Input Report characteristic.
+ err_code = boot_inp_rep_char_add(p_hids,
+ BLE_UUID_BOOT_KEYBOARD_INPUT_REPORT_CHAR,
+ BOOT_KB_INPUT_REPORT_MAX_SIZE,
+ &p_hids_init->security_mode_boot_kb_inp_rep,
+ &p_hids->boot_kb_inp_rep_handles);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add Boot Keyboard Output Report characteristic.
+ err_code = boot_kb_outp_rep_char_add(p_hids, p_hids_init);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ if (p_hids_init->is_mouse)
+ {
+ // Add Boot Mouse Input Report characteristic.
+ err_code = boot_inp_rep_char_add(p_hids,
+ BLE_UUID_BOOT_MOUSE_INPUT_REPORT_CHAR,
+ BOOT_MOUSE_INPUT_REPORT_MAX_SIZE,
+ &p_hids_init->security_mode_boot_mouse_inp_rep,
+ &p_hids->boot_mouse_inp_rep_handles);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ // Add HID Information characteristic.
+ err_code = hid_information_char_add(p_hids, p_hids_init);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add HID Control Point characteristic.
+ err_code = hid_control_point_char_add(p_hids, &p_hids_init->security_mode_ctrl_point);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Set pointers to user-defined report arrays
+ p_hids->p_inp_rep_init_array = p_hids_init->p_inp_rep_array;
+ p_hids->p_outp_rep_init_array = p_hids_init->p_outp_rep_array;
+ p_hids->p_feature_rep_init_array = p_hids_init->p_feature_rep_array;
+
+ return err_code;
+}
+
+
+uint32_t ble_hids_inp_rep_send(ble_hids_t * p_hids,
+ uint8_t rep_index,
+ uint16_t len,
+ uint8_t * p_data,
+ uint16_t conn_handle)
+{
+ uint32_t err_code;
+
+ if (rep_index < p_hids->inp_rep_count)
+ {
+ ble_hids_rep_char_t * p_rep_char = &p_hids->inp_rep_array[rep_index];
+
+ if (conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ ble_gatts_hvx_params_t hvx_params;
+ uint8_t index = 0;
+ uint16_t hvx_len = len;
+ uint8_t * p_host_rep_data;
+
+ err_code = blcm_link_ctx_get(p_hids->p_link_ctx_storage,
+ conn_handle,
+ (void *) &p_host_rep_data);
+ VERIFY_SUCCESS(err_code);
+
+ if (p_host_rep_data != NULL)
+ {
+ p_host_rep_data += sizeof(ble_hids_client_context_t) + BOOT_KB_INPUT_REPORT_MAX_SIZE +
+ BOOT_KB_OUTPUT_REPORT_MAX_SIZE + BOOT_MOUSE_INPUT_REPORT_MAX_SIZE;
+ }
+ else
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ // Store the new report data in host's context
+ while (index < rep_index)
+ {
+ p_host_rep_data += p_hids->p_inp_rep_init_array[index].max_len;
+ ++index;
+ }
+
+ if (len <= p_hids->p_inp_rep_init_array[rep_index].max_len)
+ {
+ memcpy(p_host_rep_data, p_data, len);
+ }
+ else
+ {
+ return NRF_ERROR_DATA_SIZE;
+ }
+
+ // Notify host
+ memset(&hvx_params, 0, sizeof(hvx_params));
+
+ hvx_params.handle = p_rep_char->char_handles.value_handle;
+ hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
+ hvx_params.offset = 0;
+ hvx_params.p_len = &hvx_len;
+ hvx_params.p_data = p_data;
+
+ err_code = sd_ble_gatts_hvx(conn_handle, &hvx_params);
+ if ((err_code == NRF_SUCCESS) && (hvx_len != len))
+ {
+ err_code = NRF_ERROR_DATA_SIZE;
+ }
+ }
+ else
+ {
+ err_code = NRF_ERROR_INVALID_STATE;
+ }
+ }
+ else
+ {
+ err_code = NRF_ERROR_INVALID_PARAM;
+ }
+
+ return err_code;
+}
+
+
+uint32_t ble_hids_boot_kb_inp_rep_send(ble_hids_t * p_hids,
+ uint16_t len,
+ uint8_t * p_data,
+ uint16_t conn_handle)
+{
+ uint32_t err_code;
+
+ if (conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ ble_gatts_hvx_params_t hvx_params;
+ uint16_t hvx_len = len;
+ uint8_t * p_host_rep_data;
+
+ err_code = blcm_link_ctx_get(p_hids->p_link_ctx_storage,
+ conn_handle,
+ (void *) &p_host_rep_data);
+ VERIFY_SUCCESS(err_code);
+
+ if (p_host_rep_data != NULL)
+ {
+ p_host_rep_data += sizeof(ble_hids_client_context_t);
+ }
+ else
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ // Store the new value in the host's context
+ if (len <= BOOT_KB_INPUT_REPORT_MAX_SIZE)
+ {
+ memcpy(p_host_rep_data, p_data, len);
+ }
+
+ // Notify host
+ memset(&hvx_params, 0, sizeof(hvx_params));
+
+ hvx_params.handle = p_hids->boot_kb_inp_rep_handles.value_handle;
+ hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
+ hvx_params.offset = 0;
+ hvx_params.p_len = &hvx_len;
+ hvx_params.p_data = p_data;
+
+ err_code = sd_ble_gatts_hvx(conn_handle, &hvx_params);
+ if ((err_code == NRF_SUCCESS) && (hvx_len != len))
+ {
+ err_code = NRF_ERROR_DATA_SIZE;
+ }
+ }
+ else
+ {
+ err_code = NRF_ERROR_INVALID_STATE;
+ }
+
+ return err_code;
+}
+
+
+uint32_t ble_hids_boot_mouse_inp_rep_send(ble_hids_t * p_hids,
+ uint8_t buttons,
+ int8_t x_delta,
+ int8_t y_delta,
+ uint16_t optional_data_len,
+ uint8_t * p_optional_data,
+ uint16_t conn_handle)
+{
+ uint32_t err_code;
+
+ if (conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ uint16_t hvx_len = BOOT_MOUSE_INPUT_REPORT_MIN_SIZE + optional_data_len;
+
+ if (hvx_len <= BOOT_MOUSE_INPUT_REPORT_MAX_SIZE)
+ {
+ uint8_t buffer[BOOT_MOUSE_INPUT_REPORT_MAX_SIZE];
+ ble_gatts_hvx_params_t hvx_params;
+ uint8_t * p_host_rep_data;
+
+ err_code = blcm_link_ctx_get(p_hids->p_link_ctx_storage,
+ conn_handle,
+ (void *) &p_host_rep_data);
+ VERIFY_SUCCESS(err_code);
+
+ if (p_host_rep_data != NULL)
+ {
+ p_host_rep_data += sizeof(ble_hids_client_context_t) + BOOT_KB_INPUT_REPORT_MAX_SIZE +
+ BOOT_KB_OUTPUT_REPORT_MAX_SIZE;
+ }
+ else
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ APP_ERROR_CHECK_BOOL(BOOT_MOUSE_INPUT_REPORT_MIN_SIZE == 3);
+
+ // Build buffer
+ buffer[0] = buttons;
+ buffer[1] = (uint8_t)x_delta;
+ buffer[2] = (uint8_t)y_delta;
+
+ if (optional_data_len > 0)
+ {
+ memcpy(&buffer[3], p_optional_data, optional_data_len);
+ }
+
+ // Store the new value in the host's context
+ memcpy(p_host_rep_data, buffer, hvx_len);
+
+ // Pass buffer to stack
+ memset(&hvx_params, 0, sizeof(hvx_params));
+
+ hvx_params.handle = p_hids->boot_mouse_inp_rep_handles.value_handle;
+ hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
+ hvx_params.offset = 0;
+ hvx_params.p_len = &hvx_len;
+ hvx_params.p_data = buffer;
+
+ err_code = sd_ble_gatts_hvx(conn_handle, &hvx_params);
+ if ((err_code == NRF_SUCCESS) &&
+ (hvx_len != BOOT_MOUSE_INPUT_REPORT_MIN_SIZE + optional_data_len)
+ )
+ {
+ err_code = NRF_ERROR_DATA_SIZE;
+ }
+ }
+ else
+ {
+ err_code = NRF_ERROR_DATA_SIZE;
+ }
+ }
+ else
+ {
+ err_code = NRF_ERROR_INVALID_STATE;
+ }
+
+ return err_code;
+}
+
+
+uint32_t ble_hids_outp_rep_get(ble_hids_t * p_hids,
+ uint8_t rep_index,
+ uint16_t len,
+ uint8_t offset,
+ uint16_t conn_handle,
+ uint8_t * p_outp_rep)
+{
+ ret_code_t err_code;
+ uint8_t * p_rep_data;
+
+ if (rep_index > p_hids->outp_rep_count)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ err_code = blcm_link_ctx_get(p_hids->p_link_ctx_storage,
+ conn_handle,
+ (void *) &p_rep_data);
+ VERIFY_SUCCESS(err_code);
+
+ if (p_rep_data != NULL)
+ {
+ uint8_t index;
+ p_rep_data += sizeof(ble_hids_client_context_t) + BOOT_KB_INPUT_REPORT_MAX_SIZE +
+ BOOT_KB_OUTPUT_REPORT_MAX_SIZE + BOOT_MOUSE_INPUT_REPORT_MAX_SIZE;
+
+ for (index = 0; index < p_hids->inp_rep_count; index++)
+ {
+ p_rep_data += p_hids->p_inp_rep_init_array[index].max_len;
+ }
+
+ for (index = 0; index < rep_index; index++)
+ {
+ p_rep_data += p_hids->p_outp_rep_init_array[index].max_len;
+ }
+ }
+ else
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ // Copy the requested output report data
+ if (len + offset <= p_hids->p_outp_rep_init_array[rep_index].max_len)
+ {
+ memcpy(p_outp_rep, p_rep_data + offset, len);
+ }
+ else
+ {
+ return NRF_ERROR_INVALID_LENGTH;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**
+ @}
+ */
+#endif // NRF_MODULE_ENABLED(BLE_HIDS)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hids/ble_hids.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hids/ble_hids.h
new file mode 100644
index 0000000..d53de82
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hids/ble_hids.h
@@ -0,0 +1,430 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_hids Human Interface Device Service
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Human Interface Device Service module.
+ *
+ * @details This module implements the Human Interface Device Service with the corresponding set of
+ * characteristics. During initialization it adds the Human Interface Device Service and
+ * a set of characteristics as per the Human Interface Device Service specification and
+ * the user requirements to the BLE stack database.
+ *
+ * If enabled, notification of Input Report characteristics is performed when the
+ * application calls the corresponding ble_hids_xx_input_report_send() function.
+ *
+ * If an event handler is supplied by the application, the Human Interface Device Service
+ * will generate Human Interface Device Service events to the application.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_hids_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_HIDS_BLE_OBSERVER_PRIO,
+ * ble_hids_on_ble_evt, &instance);
+ * @endcode
+ *
+ * @note Attention!
+ * To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+
+#ifndef BLE_HIDS_H__
+#define BLE_HIDS_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "ble_link_ctx_manager.h"
+#include "nrf_sdh_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Allocate static data for keeping host connection contexts.
+ *
+ * @param _name Name of BLE HIDS instance.
+ * @param[in] _hids_max_clients Maximum number of HIDS clients connected at a time.
+ * @param[in] ... Lengths of HIDS reports.
+ *
+ * @details
+ * Mapping of HIDS reports in the HIDS report context:
+ * - Structure of type @ref ble_hids_client_context_t
+ * - Boot keyboard input report
+ * - Boot keyboard output report
+ * - Boot mouse input report
+ * - Input reports
+ * - Output reports
+ * - Feature reports
+ * @hideinitializer
+ */
+#define BLE_HIDS_DEF(_name, \
+ _hids_max_clients, \
+ ...) \
+ BLE_LINK_CTX_MANAGER_DEF(CONCAT_2(_name, _link_ctx_storage), \
+ (_hids_max_clients), \
+ BLE_HIDS_LINK_CTX_SIZE_CALC(__VA_ARGS__)); \
+ static ble_hids_t _name = \
+ { \
+ .p_link_ctx_storage = &CONCAT_2(_name, _link_ctx_storage) \
+ }; \
+ NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_HIDS_BLE_OBSERVER_PRIO, \
+ ble_hids_on_ble_evt, \
+ &_name)
+
+/**@brief Helping macro for @ref BLE_HIDS_DEF, that calculates the link context size for BLE HIDS
+ * instance.
+ *
+ * @param[in] ... Lengths of HIDS reports
+ * @hideinitializer
+ */
+#define BLE_HIDS_LINK_CTX_SIZE_CALC(...) \
+ (sizeof(ble_hids_client_context_t) + \
+ MACRO_MAP_REC(BLE_HIDS_REPORT_ADD, __VA_ARGS__) \
+ (BOOT_KB_INPUT_REPORT_MAX_SIZE) + \
+ (BOOT_KB_OUTPUT_REPORT_MAX_SIZE) + \
+ (BOOT_MOUSE_INPUT_REPORT_MAX_SIZE)) \
+
+/**@brief Helping macro for @ref BLE_HIDS_LINK_CTX_SIZE_CALC, that adds Input/Output/Feature report
+ * lengths.
+ *
+ * @param[in] _report_size Length of the specific report.
+ * @hideinitializer
+ */
+#define BLE_HIDS_REPORT_ADD(_report_size) (_report_size) +
+
+/** @name Report Type values
+ * @anchor BLE_HIDS_REPORT_TYPE @{
+ */
+// Report Type values
+#define BLE_HIDS_REP_TYPE_INPUT 1
+#define BLE_HIDS_REP_TYPE_OUTPUT 2
+#define BLE_HIDS_REP_TYPE_FEATURE 3
+/** @} */
+
+// Maximum number of the various Report Types
+#define BLE_HIDS_MAX_INPUT_REP 10
+#define BLE_HIDS_MAX_OUTPUT_REP 10
+#define BLE_HIDS_MAX_FEATURE_REP 10
+
+// Information Flags
+#define HID_INFO_FLAG_REMOTE_WAKE_MSK 0x01
+#define HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK 0x02
+
+#define BOOT_KB_INPUT_REPORT_MAX_SIZE 8 /**< Maximum size of a Boot Keyboard Input Report (as per Appendix B in Device Class Definition for Human Interface Devices (HID), Version 1.11). */
+#define BOOT_KB_OUTPUT_REPORT_MAX_SIZE 1 /**< Maximum size of a Boot Keyboard Output Report (as per Appendix B in Device Class Definition for Human Interface Devices (HID), Version 1.11). */
+#define BOOT_MOUSE_INPUT_REPORT_MIN_SIZE 3 /**< Minimum size of a Boot Mouse Input Report (as per Appendix B in Device Class Definition for Human Interface Devices (HID), Version 1.11). */
+#define BOOT_MOUSE_INPUT_REPORT_MAX_SIZE 8 /**< Maximum size of a Boot Mouse Input Report (as per Appendix B in Device Class Definition for Human Interface Devices (HID), Version 1.11). */
+
+/**@brief HID Service characteristic id. */
+typedef struct
+{
+ uint16_t uuid; /**< UUID of characteristic. */
+ uint8_t rep_type; /**< Type of report (only used for BLE_UUID_REPORT_CHAR, see @ref BLE_HIDS_REPORT_TYPE). */
+ uint8_t rep_index; /**< Index of the characteristic (only used for BLE_UUID_REPORT_CHAR). */
+} ble_hids_char_id_t;
+
+/**@brief HID Service event type. */
+typedef enum
+{
+ BLE_HIDS_EVT_HOST_SUSP, /**< Suspend command received. */
+ BLE_HIDS_EVT_HOST_EXIT_SUSP, /**< Exit suspend command received. */
+ BLE_HIDS_EVT_NOTIF_ENABLED, /**< Notification enabled event. */
+ BLE_HIDS_EVT_NOTIF_DISABLED, /**< Notification disabled event. */
+ BLE_HIDS_EVT_REP_CHAR_WRITE, /**< A new value has been written to an Report characteristic. */
+ BLE_HIDS_EVT_BOOT_MODE_ENTERED, /**< Boot mode entered. */
+ BLE_HIDS_EVT_REPORT_MODE_ENTERED, /**< Report mode entered. */
+ BLE_HIDS_EVT_REPORT_READ /**< Read with response */
+} ble_hids_evt_type_t;
+
+/**@brief HID Service event. */
+typedef struct
+{
+ ble_hids_evt_type_t evt_type; /**< Type of event. */
+ union
+ {
+ struct
+ {
+ ble_hids_char_id_t char_id; /**< Id of characteristic for which notification has been started. */
+ } notification;
+ struct
+ {
+ ble_hids_char_id_t char_id; /**< Id of characteristic having been written. */
+ uint16_t offset; /**< Offset for the write operation. */
+ uint16_t len; /**< Length of the incoming data. */
+ uint8_t const * data; /**< Incoming data, variable length */
+ } char_write;
+ struct
+ {
+ ble_hids_char_id_t char_id; /**< Id of characteristic being read. */
+ } char_auth_read;
+ } params;
+ ble_evt_t const * p_ble_evt; /**< corresponding received ble event, NULL if not relevant */
+} ble_hids_evt_t;
+
+// Forward declaration of the ble_hids_t type.
+typedef struct ble_hids_s ble_hids_t;
+
+/**@brief HID Service event handler type. */
+typedef void (*ble_hids_evt_handler_t) (ble_hids_t * p_hids, ble_hids_evt_t * p_evt);
+
+/**@brief HID Information characteristic value. */
+typedef struct
+{
+ uint16_t bcd_hid; /**< 16-bit unsigned integer representing version number of base USB HID Specification implemented by HID Device */
+ uint8_t b_country_code; /**< Identifies which country the hardware is localized for. Most hardware is not localized and thus this value would be zero (0). */
+ uint8_t flags; /**< See http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.hid_information.xml */
+ ble_srv_security_mode_t security_mode; /**< Security mode for the HID Information characteristic. */
+} ble_hids_hid_information_t;
+
+/**@brief HID Service Input Report characteristic init structure. This contains all options and
+ * data needed for initialization of one Input Report characteristic. */
+typedef struct
+{
+ uint16_t max_len; /**< Maximum length of characteristic value. */
+ ble_srv_report_ref_t rep_ref; /**< Value of the Report Reference descriptor. */
+ ble_srv_cccd_security_mode_t security_mode; /**< Security mode for the HID Input Report characteristic, including cccd. */
+} ble_hids_inp_rep_init_t;
+
+/**@brief HID Service Output Report characteristic init structure. This contains all options and
+ * data needed for initialization of one Output Report characteristic. */
+typedef struct
+{
+ uint16_t max_len; /**< Maximum length of characteristic value. */
+ ble_srv_report_ref_t rep_ref; /**< Value of the Report Reference descriptor. */
+ ble_srv_cccd_security_mode_t security_mode; /**< Security mode for the HID Output Report characteristic, including cccd. */
+} ble_hids_outp_rep_init_t;
+
+/**@brief HID Service Feature Report characteristic init structure. This contains all options and
+ * data needed for initialization of one Feature Report characteristic. */
+typedef struct
+{
+ uint16_t max_len; /**< Maximum length of characteristic value. */
+ ble_srv_report_ref_t rep_ref; /**< Value of the Report Reference descriptor. */
+ ble_srv_cccd_security_mode_t security_mode; /**< Security mode for the HID Service Feature Report characteristic, including cccd. */
+} ble_hids_feature_rep_init_t;
+
+/**@brief HID Service Report Map characteristic init structure. This contains all options and data
+ * needed for initialization of the Report Map characteristic. */
+typedef struct
+{
+ uint8_t * p_data; /**< Report map data. */
+ uint16_t data_len; /**< Length of report map data. */
+ uint8_t ext_rep_ref_num; /**< Number of Optional External Report Reference descriptors. */
+ ble_uuid_t const * p_ext_rep_ref; /**< Optional External Report Reference descriptor (will be added if != NULL). */
+ ble_srv_security_mode_t security_mode; /**< Security mode for the HID Service Report Map characteristic. */
+} ble_hids_rep_map_init_t;
+
+/**@brief HID Report characteristic structure. */
+typedef struct
+{
+ ble_gatts_char_handles_t char_handles; /**< Handles related to the Report characteristic. */
+ uint16_t ref_handle; /**< Handle of the Report Reference descriptor. */
+} ble_hids_rep_char_t;
+
+/**@brief HID Host context structure. It keeps information relevant to a single host. */
+typedef struct
+{
+ uint8_t protocol_mode; /**< Protocol mode. */
+ uint8_t ctrl_pt; /**< HID Control Point. */
+} ble_hids_client_context_t;
+
+/**@brief HID Service init structure. This contains all options and data needed for initialization
+ * of the service. */
+typedef struct
+{
+ ble_hids_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the HID Service. */
+ ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
+ bool is_kb; /**< TRUE if device is operating as a keyboard, FALSE if it is not. */
+ bool is_mouse; /**< TRUE if device is operating as a mouse, FALSE if it is not. */
+ uint8_t inp_rep_count; /**< Number of Input Report characteristics. */
+ ble_hids_inp_rep_init_t const * p_inp_rep_array; /**< Information about the Input Report characteristics. */
+ uint8_t outp_rep_count; /**< Number of Output Report characteristics. */
+ ble_hids_outp_rep_init_t const * p_outp_rep_array; /**< Information about the Output Report characteristics. */
+ uint8_t feature_rep_count; /**< Number of Feature Report characteristics. */
+ ble_hids_feature_rep_init_t const * p_feature_rep_array; /**< Information about the Feature Report characteristics. */
+ ble_hids_rep_map_init_t rep_map; /**< Information nedeed for initialization of the Report Map characteristic. */
+ ble_hids_hid_information_t hid_information; /**< Value of the HID Information characteristic. */
+ uint8_t included_services_count; /**< Number of services to include in HID service. */
+ uint16_t * p_included_services_array; /**< Array of services to include in HID service. */
+ ble_srv_security_mode_t security_mode_protocol; /**< Security settings for HID service protocol attribute */
+ ble_srv_security_mode_t security_mode_ctrl_point; /**< Security settings for HID service Control Point attribute */
+ ble_srv_cccd_security_mode_t security_mode_boot_mouse_inp_rep; /**< Security settings for HID service Mouse input report attribute */
+ ble_srv_cccd_security_mode_t security_mode_boot_kb_inp_rep; /**< Security settings for HID service Keyboard input report attribute */
+ ble_srv_security_mode_t security_mode_boot_kb_outp_rep; /**< Security settings for HID service Keyboard output report attribute */
+} ble_hids_init_t;
+
+/**@brief HID Service structure. This contains various status information for the service. */
+struct ble_hids_s
+{
+ ble_hids_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the HID Service. */
+ ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
+ uint16_t service_handle; /**< Handle of HID Service (as provided by the BLE stack). */
+ ble_gatts_char_handles_t protocol_mode_handles; /**< Handles related to the Protocol Mode characteristic (will only be created if ble_hids_init_t.is_kb or ble_hids_init_t.is_mouse is set). */
+ uint8_t inp_rep_count; /**< Number of Input Report characteristics. */
+ ble_hids_rep_char_t inp_rep_array[BLE_HIDS_MAX_INPUT_REP]; /**< Information about the Input Report characteristics. */
+ uint8_t outp_rep_count; /**< Number of Output Report characteristics. */
+ ble_hids_rep_char_t outp_rep_array[BLE_HIDS_MAX_OUTPUT_REP]; /**< Information about the Output Report characteristics. */
+ uint8_t feature_rep_count; /**< Number of Feature Report characteristics. */
+ ble_hids_rep_char_t feature_rep_array[BLE_HIDS_MAX_FEATURE_REP]; /**< Information about the Feature Report characteristics. */
+ ble_gatts_char_handles_t rep_map_handles; /**< Handles related to the Report Map characteristic. */
+ uint16_t rep_map_ext_rep_ref_handle; /**< Handle of the Report Map External Report Reference descriptor. */
+ ble_gatts_char_handles_t boot_kb_inp_rep_handles; /**< Handles related to the Boot Keyboard Input Report characteristic (will only be created if ble_hids_init_t.is_kb is set). */
+ ble_gatts_char_handles_t boot_kb_outp_rep_handles; /**< Handles related to the Boot Keyboard Output Report characteristic (will only be created if ble_hids_init_t.is_kb is set). */
+ ble_gatts_char_handles_t boot_mouse_inp_rep_handles; /**< Handles related to the Boot Mouse Input Report characteristic (will only be created if ble_hids_init_t.is_mouse is set). */
+ ble_gatts_char_handles_t hid_information_handles; /**< Handles related to the Report Map characteristic. */
+ ble_gatts_char_handles_t hid_control_point_handles; /**< Handles related to the Report Map characteristic. */
+ blcm_link_ctx_storage_t * const p_link_ctx_storage; /**< Link context storage with handles of all current connections and its data context. */
+ ble_hids_inp_rep_init_t const * p_inp_rep_init_array; /**< Pointer to information about the Input Report characteristics. */
+ ble_hids_outp_rep_init_t const * p_outp_rep_init_array; /**< Pointer to information about the Output Report characteristics. */
+ ble_hids_feature_rep_init_t const * p_feature_rep_init_array; /**< Pointer to information about the Feature Report characteristics. */
+};
+
+/**@brief Function for initializing the HID Service.
+ *
+ * @param[out] p_hids HID Service structure. This structure will have to be supplied by the
+ * application. It will be initialized by this function, and will later be
+ * used to identify this particular service instance.
+ * @param[in] p_hids_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
+ */
+uint32_t ble_hids_init(ble_hids_t * p_hids, const ble_hids_init_t * p_hids_init);
+
+/**@brief Function for handling the Application's BLE Stack events.
+ *
+ * @details Handles all events from the BLE stack of interest to the HID Service.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context HID Service structure.
+ */
+void ble_hids_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+/**@brief Function for sending Input Report.
+ *
+ * @details Sends data on an Input Report characteristic.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] rep_index Index of the characteristic (corresponding to the index in
+ * ble_hids_t.inp_rep_array as passed to ble_hids_init()).
+ * @param[in] len Length of data to be sent.
+ * @param[in] p_data Pointer to data to be sent.
+ * @param[in] conn_handle Connection handle, where the notification will be sent.
+ *
+ * @return NRF_SUCCESS on successful sending of input report, otherwise an error code.
+ */
+uint32_t ble_hids_inp_rep_send(ble_hids_t * p_hids,
+ uint8_t rep_index,
+ uint16_t len,
+ uint8_t * p_data,
+ uint16_t conn_handle);
+
+/**@brief Function for sending Boot Keyboard Input Report.
+ *
+ * @details Sends data on an Boot Keyboard Input Report characteristic.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] len Length of data to be sent.
+ * @param[in] p_data Pointer to data to be sent.
+ * @param[in] conn_handle Connection handle, where the notification will be sent.
+ *
+ * @return NRF_SUCCESS on successful sending of the report, otherwise an error code.
+ */
+uint32_t ble_hids_boot_kb_inp_rep_send(ble_hids_t * p_hids,
+ uint16_t len,
+ uint8_t * p_data,
+ uint16_t conn_handle);
+
+/**@brief Function for sending Boot Mouse Input Report.
+ *
+ * @details Sends data on an Boot Mouse Input Report characteristic.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] buttons State of mouse buttons.
+ * @param[in] x_delta Horizontal movement.
+ * @param[in] y_delta Vertical movement.
+ * @param[in] optional_data_len Length of optional part of Boot Mouse Input Report.
+ * @param[in] p_optional_data Optional part of Boot Mouse Input Report.
+ * @param[in] conn_handle Connection handle.
+ *
+ * @return NRF_SUCCESS on successful sending of the report, otherwise an error code.
+ */
+uint32_t ble_hids_boot_mouse_inp_rep_send(ble_hids_t * p_hids,
+ uint8_t buttons,
+ int8_t x_delta,
+ int8_t y_delta,
+ uint16_t optional_data_len,
+ uint8_t * p_optional_data,
+ uint16_t conn_handle);
+
+/**@brief Function for getting the current value of Output Report from the stack.
+ *
+ * @details Fetches the current value of the output report characteristic from the stack.
+ *
+ * @param[in] p_hids HID Service structure.
+ * @param[in] rep_index Index of the characteristic (corresponding to the index in
+ * ble_hids_t.outp_rep_array as passed to ble_hids_init()).
+ * @param[in] len Length of output report needed.
+ * @param[in] offset Offset in bytes to read from.
+ * @param[in] conn_handle Connection handle.
+ * @param[out] p_outp_rep Pointer to the output report.
+ *
+ * @return NRF_SUCCESS on successful read of the report, otherwise an error code.
+ */
+uint32_t ble_hids_outp_rep_get(ble_hids_t * p_hids,
+ uint8_t rep_index,
+ uint16_t len,
+ uint8_t offset,
+ uint16_t conn_handle,
+ uint8_t * p_outp_rep);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_HIDS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hrs/ble_hrs.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hrs/ble_hrs.c
new file mode 100644
index 0000000..58aa657
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hrs/ble_hrs.c
@@ -0,0 +1,479 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Attention!
+ * To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_HRS)
+#include "ble_hrs.h"
+#include <string.h>
+#include "ble_srv_common.h"
+
+
+#define OPCODE_LENGTH 1 /**< Length of opcode inside Heart Rate Measurement packet. */
+#define HANDLE_LENGTH 2 /**< Length of handle inside Heart Rate Measurement packet. */
+#define MAX_HRM_LEN (NRF_SDH_BLE_GATT_MAX_MTU_SIZE - OPCODE_LENGTH - HANDLE_LENGTH) /**< Maximum size of a transmitted Heart Rate Measurement. */
+
+#define INITIAL_VALUE_HRM 0 /**< Initial Heart Rate Measurement value. */
+
+// Heart Rate Measurement flag bits
+#define HRM_FLAG_MASK_HR_VALUE_16BIT (0x01 << 0) /**< Heart Rate Value Format bit. */
+#define HRM_FLAG_MASK_SENSOR_CONTACT_DETECTED (0x01 << 1) /**< Sensor Contact Detected bit. */
+#define HRM_FLAG_MASK_SENSOR_CONTACT_SUPPORTED (0x01 << 2) /**< Sensor Contact Supported bit. */
+#define HRM_FLAG_MASK_EXPENDED_ENERGY_INCLUDED (0x01 << 3) /**< Energy Expended Status bit. Feature Not Supported */
+#define HRM_FLAG_MASK_RR_INTERVAL_INCLUDED (0x01 << 4) /**< RR-Interval bit. */
+
+
+/**@brief Function for handling the Connect event.
+ *
+ * @param[in] p_hrs Heart Rate Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_connect(ble_hrs_t * p_hrs, ble_evt_t const * p_ble_evt)
+{
+ p_hrs->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+}
+
+
+/**@brief Function for handling the Disconnect event.
+ *
+ * @param[in] p_hrs Heart Rate Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_disconnect(ble_hrs_t * p_hrs, ble_evt_t const * p_ble_evt)
+{
+ UNUSED_PARAMETER(p_ble_evt);
+ p_hrs->conn_handle = BLE_CONN_HANDLE_INVALID;
+}
+
+
+/**@brief Function for handling write events to the Heart Rate Measurement characteristic.
+ *
+ * @param[in] p_hrs Heart Rate Service structure.
+ * @param[in] p_evt_write Write event received from the BLE stack.
+ */
+static void on_hrm_cccd_write(ble_hrs_t * p_hrs, ble_gatts_evt_write_t const * p_evt_write)
+{
+ if (p_evt_write->len == 2)
+ {
+ // CCCD written, update notification state
+ if (p_hrs->evt_handler != NULL)
+ {
+ ble_hrs_evt_t evt;
+
+ if (ble_srv_is_notification_enabled(p_evt_write->data))
+ {
+ evt.evt_type = BLE_HRS_EVT_NOTIFICATION_ENABLED;
+ }
+ else
+ {
+ evt.evt_type = BLE_HRS_EVT_NOTIFICATION_DISABLED;
+ }
+
+ p_hrs->evt_handler(p_hrs, &evt);
+ }
+ }
+}
+
+
+/**@brief Function for handling the Write event.
+ *
+ * @param[in] p_hrs Heart Rate Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_write(ble_hrs_t * p_hrs, ble_evt_t const * p_ble_evt)
+{
+ ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+ if (p_evt_write->handle == p_hrs->hrm_handles.cccd_handle)
+ {
+ on_hrm_cccd_write(p_hrs, p_evt_write);
+ }
+}
+
+
+void ble_hrs_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ ble_hrs_t * p_hrs = (ble_hrs_t *) p_context;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ on_connect(p_hrs, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnect(p_hrs, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_WRITE:
+ on_write(p_hrs, p_ble_evt);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+
+/**@brief Function for encoding a Heart Rate Measurement.
+ *
+ * @param[in] p_hrs Heart Rate Service structure.
+ * @param[in] heart_rate Measurement to be encoded.
+ * @param[out] p_encoded_buffer Buffer where the encoded data will be written.
+ *
+ * @return Size of encoded data.
+ */
+static uint8_t hrm_encode(ble_hrs_t * p_hrs, uint16_t heart_rate, uint8_t * p_encoded_buffer)
+{
+ uint8_t flags = 0;
+ uint8_t len = 1;
+ int i;
+
+ // Set sensor contact related flags
+ if (p_hrs->is_sensor_contact_supported)
+ {
+ flags |= HRM_FLAG_MASK_SENSOR_CONTACT_SUPPORTED;
+ }
+ if (p_hrs->is_sensor_contact_detected)
+ {
+ flags |= HRM_FLAG_MASK_SENSOR_CONTACT_DETECTED;
+ }
+
+ // Encode heart rate measurement
+ if (heart_rate > 0xff)
+ {
+ flags |= HRM_FLAG_MASK_HR_VALUE_16BIT;
+ len += uint16_encode(heart_rate, &p_encoded_buffer[len]);
+ }
+ else
+ {
+ p_encoded_buffer[len++] = (uint8_t)heart_rate;
+ }
+
+ // Encode rr_interval values
+ if (p_hrs->rr_interval_count > 0)
+ {
+ flags |= HRM_FLAG_MASK_RR_INTERVAL_INCLUDED;
+ }
+ for (i = 0; i < p_hrs->rr_interval_count; i++)
+ {
+ if (len + sizeof(uint16_t) > p_hrs->max_hrm_len)
+ {
+ // Not all stored rr_interval values can fit into the encoded hrm,
+ // move the remaining values to the start of the buffer.
+ memmove(&p_hrs->rr_interval[0],
+ &p_hrs->rr_interval[i],
+ (p_hrs->rr_interval_count - i) * sizeof(uint16_t));
+ break;
+ }
+ len += uint16_encode(p_hrs->rr_interval[i], &p_encoded_buffer[len]);
+ }
+ p_hrs->rr_interval_count -= i;
+
+ // Add flags
+ p_encoded_buffer[0] = flags;
+
+ return len;
+}
+
+
+/**@brief Function for adding the Heart Rate Measurement characteristic.
+ *
+ * @param[in] p_hrs Heart Rate Service structure.
+ * @param[in] p_hrs_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t heart_rate_measurement_char_add(ble_hrs_t * p_hrs,
+ const ble_hrs_init_t * p_hrs_init)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_md_t cccd_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+ uint8_t encoded_initial_hrm[MAX_HRM_LEN];
+
+ memset(&cccd_md, 0, sizeof(cccd_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
+ cccd_md.write_perm = p_hrs_init->hrs_hrm_attr_md.cccd_write_perm;
+ cccd_md.vloc = BLE_GATTS_VLOC_STACK;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.notify = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = &cccd_md;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_HEART_RATE_MEASUREMENT_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.read_perm = p_hrs_init->hrs_hrm_attr_md.read_perm;
+ attr_md.write_perm = p_hrs_init->hrs_hrm_attr_md.write_perm;
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 1;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = hrm_encode(p_hrs, INITIAL_VALUE_HRM, encoded_initial_hrm);
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = MAX_HRM_LEN;
+ attr_char_value.p_value = encoded_initial_hrm;
+
+ return sd_ble_gatts_characteristic_add(p_hrs->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_hrs->hrm_handles);
+}
+
+
+/**@brief Function for adding the Body Sensor Location characteristic.
+ *
+ * @param[in] p_hrs Heart Rate Service structure.
+ * @param[in] p_hrs_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t body_sensor_location_char_add(ble_hrs_t * p_hrs, const ble_hrs_init_t * p_hrs_init)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = NULL;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_BODY_SENSOR_LOCATION_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.read_perm = p_hrs_init->hrs_bsl_attr_md.read_perm;
+ attr_md.write_perm = p_hrs_init->hrs_bsl_attr_md.write_perm;
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = sizeof (uint8_t);
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = sizeof (uint8_t);
+ attr_char_value.p_value = p_hrs_init->p_body_sensor_location;
+
+ return sd_ble_gatts_characteristic_add(p_hrs->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_hrs->bsl_handles);
+}
+
+
+uint32_t ble_hrs_init(ble_hrs_t * p_hrs, const ble_hrs_init_t * p_hrs_init)
+{
+ uint32_t err_code;
+ ble_uuid_t ble_uuid;
+
+ // Initialize service structure
+ p_hrs->evt_handler = p_hrs_init->evt_handler;
+ p_hrs->is_sensor_contact_supported = p_hrs_init->is_sensor_contact_supported;
+ p_hrs->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_hrs->is_sensor_contact_detected = false;
+ p_hrs->rr_interval_count = 0;
+ p_hrs->max_hrm_len = MAX_HRM_LEN;
+
+ // Add service
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_HEART_RATE_SERVICE);
+
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
+ &ble_uuid,
+ &p_hrs->service_handle);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add heart rate measurement characteristic
+ err_code = heart_rate_measurement_char_add(p_hrs, p_hrs_init);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ if (p_hrs_init->p_body_sensor_location != NULL)
+ {
+ // Add body sensor location characteristic
+ err_code = body_sensor_location_char_add(p_hrs, p_hrs_init);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_hrs_heart_rate_measurement_send(ble_hrs_t * p_hrs, uint16_t heart_rate)
+{
+ uint32_t err_code;
+
+ // Send value if connected and notifying
+ if (p_hrs->conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ uint8_t encoded_hrm[MAX_HRM_LEN];
+ uint16_t len;
+ uint16_t hvx_len;
+ ble_gatts_hvx_params_t hvx_params;
+
+ len = hrm_encode(p_hrs, heart_rate, encoded_hrm);
+ hvx_len = len;
+
+ memset(&hvx_params, 0, sizeof(hvx_params));
+
+ hvx_params.handle = p_hrs->hrm_handles.value_handle;
+ hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
+ hvx_params.offset = 0;
+ hvx_params.p_len = &hvx_len;
+ hvx_params.p_data = encoded_hrm;
+
+ err_code = sd_ble_gatts_hvx(p_hrs->conn_handle, &hvx_params);
+ if ((err_code == NRF_SUCCESS) && (hvx_len != len))
+ {
+ err_code = NRF_ERROR_DATA_SIZE;
+ }
+ }
+ else
+ {
+ err_code = NRF_ERROR_INVALID_STATE;
+ }
+
+ return err_code;
+}
+
+
+void ble_hrs_rr_interval_add(ble_hrs_t * p_hrs, uint16_t rr_interval)
+{
+ if (p_hrs->rr_interval_count == BLE_HRS_MAX_BUFFERED_RR_INTERVALS)
+ {
+ // The rr_interval buffer is full, delete the oldest value
+ memmove(&p_hrs->rr_interval[0],
+ &p_hrs->rr_interval[1],
+ (BLE_HRS_MAX_BUFFERED_RR_INTERVALS - 1) * sizeof(uint16_t));
+ p_hrs->rr_interval_count--;
+ }
+
+ // Add new value
+ p_hrs->rr_interval[p_hrs->rr_interval_count++] = rr_interval;
+}
+
+
+bool ble_hrs_rr_interval_buffer_is_full(ble_hrs_t * p_hrs)
+{
+ return (p_hrs->rr_interval_count == BLE_HRS_MAX_BUFFERED_RR_INTERVALS);
+}
+
+
+uint32_t ble_hrs_sensor_contact_supported_set(ble_hrs_t * p_hrs, bool is_sensor_contact_supported)
+{
+ // Check if we are connected to peer
+ if (p_hrs->conn_handle == BLE_CONN_HANDLE_INVALID)
+ {
+ p_hrs->is_sensor_contact_supported = is_sensor_contact_supported;
+ return NRF_SUCCESS;
+ }
+ else
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+}
+
+
+void ble_hrs_sensor_contact_detected_update(ble_hrs_t * p_hrs, bool is_sensor_contact_detected)
+{
+ p_hrs->is_sensor_contact_detected = is_sensor_contact_detected;
+}
+
+
+uint32_t ble_hrs_body_sensor_location_set(ble_hrs_t * p_hrs, uint8_t body_sensor_location)
+{
+ ble_gatts_value_t gatts_value;
+
+ // Initialize value struct.
+ memset(&gatts_value, 0, sizeof(gatts_value));
+
+ gatts_value.len = sizeof(uint8_t);
+ gatts_value.offset = 0;
+ gatts_value.p_value = &body_sensor_location;
+
+ return sd_ble_gatts_value_set(p_hrs->conn_handle, p_hrs->bsl_handles.value_handle, &gatts_value);
+}
+
+
+void ble_hrs_on_gatt_evt(ble_hrs_t * p_hrs, nrf_ble_gatt_evt_t const * p_gatt_evt)
+{
+ if ( (p_hrs->conn_handle == p_gatt_evt->conn_handle)
+ && (p_gatt_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED))
+ {
+ p_hrs->max_hrm_len = p_gatt_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;
+ }
+}
+#endif // NRF_MODULE_ENABLED(BLE_HRS)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hrs/ble_hrs.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hrs/ble_hrs.h
new file mode 100644
index 0000000..afc6c0a
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hrs/ble_hrs.h
@@ -0,0 +1,266 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_hrs Heart Rate Service
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Heart Rate Service module.
+ *
+ * @details This module implements the Heart Rate Service with the Heart Rate Measurement,
+ * Body Sensor Location and Heart Rate Control Point characteristics.
+ * During initialization it adds the Heart Rate Service and Heart Rate Measurement
+ * characteristic to the BLE stack database. Optionally it also adds the
+ * Body Sensor Location and Heart Rate Control Point characteristics.
+ *
+ * If enabled, notification of the Heart Rate Measurement characteristic is performed
+ * when the application calls ble_hrs_heart_rate_measurement_send().
+ *
+ * The Heart Rate Service also provides a set of functions for manipulating the
+ * various fields in the Heart Rate Measurement characteristic, as well as setting
+ * the Body Sensor Location characteristic value.
+ *
+ * If an event handler is supplied by the application, the Heart Rate Service will
+ * generate Heart Rate Service events to the application.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_hrs_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_HRS_BLE_OBSERVER_PRIO,
+ * ble_hrs_on_ble_evt, &instance);
+ * @endcode
+ *
+ * @note Attention!
+ * To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+
+#ifndef BLE_HRS_H__
+#define BLE_HRS_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "nrf_sdh_ble.h"
+#include "nrf_ble_gatt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_hrs instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_HRS_DEF(_name) \
+static ble_hrs_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_HRS_BLE_OBSERVER_PRIO, \
+ ble_hrs_on_ble_evt, &_name)
+
+// Body Sensor Location values
+#define BLE_HRS_BODY_SENSOR_LOCATION_OTHER 0
+#define BLE_HRS_BODY_SENSOR_LOCATION_CHEST 1
+#define BLE_HRS_BODY_SENSOR_LOCATION_WRIST 2
+#define BLE_HRS_BODY_SENSOR_LOCATION_FINGER 3
+#define BLE_HRS_BODY_SENSOR_LOCATION_HAND 4
+#define BLE_HRS_BODY_SENSOR_LOCATION_EAR_LOBE 5
+#define BLE_HRS_BODY_SENSOR_LOCATION_FOOT 6
+
+#define BLE_HRS_MAX_BUFFERED_RR_INTERVALS 20 /**< Size of RR Interval buffer inside service. */
+
+
+/**@brief Heart Rate Service event type. */
+typedef enum
+{
+ BLE_HRS_EVT_NOTIFICATION_ENABLED, /**< Heart Rate value notification enabled event. */
+ BLE_HRS_EVT_NOTIFICATION_DISABLED /**< Heart Rate value notification disabled event. */
+} ble_hrs_evt_type_t;
+
+/**@brief Heart Rate Service event. */
+typedef struct
+{
+ ble_hrs_evt_type_t evt_type; /**< Type of event. */
+} ble_hrs_evt_t;
+
+// Forward declaration of the ble_hrs_t type.
+typedef struct ble_hrs_s ble_hrs_t;
+
+/**@brief Heart Rate Service event handler type. */
+typedef void (*ble_hrs_evt_handler_t) (ble_hrs_t * p_hrs, ble_hrs_evt_t * p_evt);
+
+/**@brief Heart Rate Service init structure. This contains all options and data needed for
+ * initialization of the service. */
+typedef struct
+{
+ ble_hrs_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Heart Rate Service. */
+ bool is_sensor_contact_supported; /**< Determines if sensor contact detection is to be supported. */
+ uint8_t * p_body_sensor_location; /**< If not NULL, initial value of the Body Sensor Location characteristic. */
+ ble_srv_cccd_security_mode_t hrs_hrm_attr_md; /**< Initial security level for heart rate service measurement attribute */
+ ble_srv_security_mode_t hrs_bsl_attr_md; /**< Initial security level for body sensor location attribute */
+} ble_hrs_init_t;
+
+/**@brief Heart Rate Service structure. This contains various status information for the service. */
+struct ble_hrs_s
+{
+ ble_hrs_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Heart Rate Service. */
+ bool is_expended_energy_supported; /**< TRUE if Expended Energy measurement is supported. */
+ bool is_sensor_contact_supported; /**< TRUE if sensor contact detection is supported. */
+ uint16_t service_handle; /**< Handle of Heart Rate Service (as provided by the BLE stack). */
+ ble_gatts_char_handles_t hrm_handles; /**< Handles related to the Heart Rate Measurement characteristic. */
+ ble_gatts_char_handles_t bsl_handles; /**< Handles related to the Body Sensor Location characteristic. */
+ ble_gatts_char_handles_t hrcp_handles; /**< Handles related to the Heart Rate Control Point characteristic. */
+ uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
+ bool is_sensor_contact_detected; /**< TRUE if sensor contact has been detected. */
+ uint16_t rr_interval[BLE_HRS_MAX_BUFFERED_RR_INTERVALS]; /**< Set of RR Interval measurements since the last Heart Rate Measurement transmission. */
+ uint16_t rr_interval_count; /**< Number of RR Interval measurements since the last Heart Rate Measurement transmission. */
+ uint8_t max_hrm_len; /**< Current maximum HR measurement length, adjusted according to the current ATT MTU. */
+};
+
+
+/**@brief Function for initializing the Heart Rate Service.
+ *
+ * @param[out] p_hrs Heart Rate Service structure. This structure will have to be supplied by
+ * the application. It will be initialized by this function, and will later
+ * be used to identify this particular service instance.
+ * @param[in] p_hrs_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
+ */
+uint32_t ble_hrs_init(ble_hrs_t * p_hrs, ble_hrs_init_t const * p_hrs_init);
+
+
+/**@brief Function for handling the GATT module's events.
+ *
+ * @details Handles all events from the GATT module of interest to the Heart Rate Service.
+ *
+ * @param[in] p_hrs Heart Rate Service structure.
+ * @param[in] p_gatt_evt Event received from the GATT module.
+ */
+void ble_hrs_on_gatt_evt(ble_hrs_t * p_hrs, nrf_ble_gatt_evt_t const * p_gatt_evt);
+
+
+/**@brief Function for handling the Application's BLE Stack events.
+ *
+ * @details Handles all events from the BLE stack of interest to the Heart Rate Service.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Heart Rate Service structure.
+ */
+void ble_hrs_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for sending heart rate measurement if notification has been enabled.
+ *
+ * @details The application calls this function after having performed a heart rate measurement.
+ * If notification has been enabled, the heart rate measurement data is encoded and sent to
+ * the client.
+ *
+ * @param[in] p_hrs Heart Rate Service structure.
+ * @param[in] heart_rate New heart rate measurement.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+uint32_t ble_hrs_heart_rate_measurement_send(ble_hrs_t * p_hrs, uint16_t heart_rate);
+
+
+/**@brief Function for adding a RR Interval measurement to the RR Interval buffer.
+ *
+ * @details All buffered RR Interval measurements will be included in the next heart rate
+ * measurement message, up to the maximum number of measurements that will fit into the
+ * message. If the buffer is full, the oldest measurement in the buffer will be deleted.
+ *
+ * @param[in] p_hrs Heart Rate Service structure.
+ * @param[in] rr_interval New RR Interval measurement (will be buffered until the next
+ * transmission of Heart Rate Measurement).
+ */
+void ble_hrs_rr_interval_add(ble_hrs_t * p_hrs, uint16_t rr_interval);
+
+
+/**@brief Function for checking if RR Interval buffer is full.
+ *
+ * @param[in] p_hrs Heart Rate Service structure.
+ *
+ * @return true if RR Interval buffer is full, false otherwise.
+ */
+bool ble_hrs_rr_interval_buffer_is_full(ble_hrs_t * p_hrs);
+
+
+/**@brief Function for setting the state of the Sensor Contact Supported bit.
+ *
+ * @param[in] p_hrs Heart Rate Service structure.
+ * @param[in] is_sensor_contact_supported New state of the Sensor Contact Supported bit.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+uint32_t ble_hrs_sensor_contact_supported_set(ble_hrs_t * p_hrs, bool is_sensor_contact_supported);
+
+
+/**@brief Function for setting the state of the Sensor Contact Detected bit.
+ *
+ * @param[in] p_hrs Heart Rate Service structure.
+ * @param[in] is_sensor_contact_detected TRUE if sensor contact is detected, FALSE otherwise.
+ */
+void ble_hrs_sensor_contact_detected_update(ble_hrs_t * p_hrs, bool is_sensor_contact_detected);
+
+
+/**@brief Function for setting the Body Sensor Location.
+ *
+ * @details Sets a new value of the Body Sensor Location characteristic. The new value will be sent
+ * to the client the next time the client reads the Body Sensor Location characteristic.
+ *
+ * @param[in] p_hrs Heart Rate Service structure.
+ * @param[in] body_sensor_location New Body Sensor Location.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+uint32_t ble_hrs_body_sensor_location_set(ble_hrs_t * p_hrs, uint8_t body_sensor_location);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_HRS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hrs_c/ble_hrs_c.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hrs_c/ble_hrs_c.c
new file mode 100644
index 0000000..6517d71
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hrs_c/ble_hrs_c.c
@@ -0,0 +1,384 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/**@cond To Make Doxygen skip documentation generation for this file.
+ * @{
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_HRS_C)
+#include "ble_hrs_c.h"
+#include "ble_db_discovery.h"
+#include "ble_types.h"
+#include "ble_srv_common.h"
+#include "ble_gattc.h"
+
+#define NRF_LOG_MODULE_NAME ble_hrs_c
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define HRM_FLAG_MASK_HR_16BIT (0x01 << 0) /**< Bit mask used to extract the type of heart rate value. This is used to find if the received heart rate is a 16 bit value or an 8 bit value. */
+#define HRM_FLAG_MASK_HR_RR_INT (0x01 << 4) /**< Bit mask used to extract the presence of RR_INTERVALS. This is used to find if the received measurement includes RR_INTERVALS. */
+
+#define TX_BUFFER_MASK 0x07 /**< TX Buffer mask, must be a mask of continuous zeroes, followed by continuous sequence of ones: 000...111. */
+#define TX_BUFFER_SIZE (TX_BUFFER_MASK + 1) /**< Size of send buffer, which is 1 higher than the mask. */
+
+#define WRITE_MESSAGE_LENGTH BLE_CCCD_VALUE_LEN /**< Length of the write message for CCCD. */
+#define WRITE_MESSAGE_LENGTH BLE_CCCD_VALUE_LEN /**< Length of the write message for CCCD. */
+
+typedef enum
+{
+ READ_REQ, /**< Type identifying that this tx_message is a read request. */
+ WRITE_REQ /**< Type identifying that this tx_message is a write request. */
+} tx_request_t;
+
+/**@brief Structure for writing a message to the peer, i.e. CCCD.
+ */
+typedef struct
+{
+ uint8_t gattc_value[WRITE_MESSAGE_LENGTH]; /**< The message to write. */
+ ble_gattc_write_params_t gattc_params; /**< GATTC parameters for this message. */
+} write_params_t;
+
+/**@brief Structure for holding data to be transmitted to the connected central.
+ */
+typedef struct
+{
+ uint16_t conn_handle; /**< Connection handle to be used when transmitting this message. */
+ tx_request_t type; /**< Type of this message, i.e. read or write message. */
+ union
+ {
+ uint16_t read_handle; /**< Read request message. */
+ write_params_t write_req; /**< Write request message. */
+ } req;
+} tx_message_t;
+
+
+static tx_message_t m_tx_buffer[TX_BUFFER_SIZE]; /**< Transmit buffer for messages to be transmitted to the central. */
+static uint32_t m_tx_insert_index = 0; /**< Current index in the transmit buffer where the next message should be inserted. */
+static uint32_t m_tx_index = 0; /**< Current index in the transmit buffer from where the next message to be transmitted resides. */
+
+
+/**@brief Function for passing any pending request from the buffer to the stack.
+ */
+static void tx_buffer_process(void)
+{
+ if (m_tx_index != m_tx_insert_index)
+ {
+ uint32_t err_code;
+
+ if (m_tx_buffer[m_tx_index].type == READ_REQ)
+ {
+ err_code = sd_ble_gattc_read(m_tx_buffer[m_tx_index].conn_handle,
+ m_tx_buffer[m_tx_index].req.read_handle,
+ 0);
+ }
+ else
+ {
+ err_code = sd_ble_gattc_write(m_tx_buffer[m_tx_index].conn_handle,
+ &m_tx_buffer[m_tx_index].req.write_req.gattc_params);
+ }
+ if (err_code == NRF_SUCCESS)
+ {
+ m_tx_index++;
+ m_tx_index &= TX_BUFFER_MASK;
+ }
+ else
+ {
+ NRF_LOG_DEBUG("SD Read/Write API returns error. This message sending will be "
+ "attempted again..");
+ }
+ }
+}
+
+
+/**@brief Function for handling write response events.
+ *
+ * @param[in] p_ble_hrs_c Pointer to the Heart Rate Client structure.
+ * @param[in] p_ble_evt Pointer to the BLE event received.
+ */
+static void on_write_rsp(ble_hrs_c_t * p_ble_hrs_c, const ble_evt_t * p_ble_evt)
+{
+ // Check if the event if on the link for this instance
+ if (p_ble_hrs_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
+ {
+ return;
+ }
+ // Check if there is any message to be sent across to the peer and send it.
+ tx_buffer_process();
+}
+
+
+/**@brief Function for handling Handle Value Notification received from the SoftDevice.
+ *
+ * @details This function will uses the Handle Value Notification received from the SoftDevice
+ * and checks if it is a notification of the heart rate measurement from the peer. If
+ * it is, this function will decode the heart rate measurement and send it to the
+ * application.
+ *
+ * @param[in] p_ble_hrs_c Pointer to the Heart Rate Client structure.
+ * @param[in] p_ble_evt Pointer to the BLE event received.
+ */
+static void on_hvx(ble_hrs_c_t * p_ble_hrs_c, const ble_evt_t * p_ble_evt)
+{
+ // Check if the event is on the link for this instance
+ if (p_ble_hrs_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
+ {
+ NRF_LOG_DEBUG("Received HVX on link 0x%x, not associated to this instance, ignore",
+ p_ble_evt->evt.gattc_evt.conn_handle);
+ return;
+ }
+
+ NRF_LOG_DEBUG("Received HVX on link 0x%x, hrm_handle 0x%x",
+ p_ble_evt->evt.gattc_evt.params.hvx.handle,
+ p_ble_hrs_c->peer_hrs_db.hrm_handle);
+
+ // Check if this is a heart rate notification.
+ if (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_hrs_c->peer_hrs_db.hrm_handle)
+ {
+ ble_hrs_c_evt_t ble_hrs_c_evt;
+ uint32_t index = 0;
+
+ ble_hrs_c_evt.evt_type = BLE_HRS_C_EVT_HRM_NOTIFICATION;
+ ble_hrs_c_evt.conn_handle = p_ble_hrs_c->conn_handle;
+ ble_hrs_c_evt.params.hrm.rr_intervals_cnt = 0;
+
+ if (!(p_ble_evt->evt.gattc_evt.params.hvx.data[index++] & HRM_FLAG_MASK_HR_16BIT))
+ {
+ // 8 Bit heart rate value received.
+ ble_hrs_c_evt.params.hrm.hr_value = p_ble_evt->evt.gattc_evt.params.hvx.data[index++]; //lint !e415 suppress Lint Warning 415: Likely access out of bond
+ }
+ else
+ {
+ // 16 bit heart rate value received.
+ ble_hrs_c_evt.params.hrm.hr_value =
+ uint16_decode(&(p_ble_evt->evt.gattc_evt.params.hvx.data[index]));
+ index += sizeof(uint16_t);
+ }
+
+ if ((p_ble_evt->evt.gattc_evt.params.hvx.data[0] & HRM_FLAG_MASK_HR_RR_INT))
+ {
+ uint32_t i;
+ /*lint --e{415} --e{416} --e{662} --e{661} -save suppress Warning 415: possible access out of bond */
+ for (i = 0; i < BLE_HRS_C_RR_INTERVALS_MAX_CNT; i ++)
+ {
+ if (index >= p_ble_evt->evt.gattc_evt.params.hvx.len)
+ {
+ break;
+ }
+ ble_hrs_c_evt.params.hrm.rr_intervals[i] =
+ uint16_decode(&(p_ble_evt->evt.gattc_evt.params.hvx.data[index]));
+ index += sizeof(uint16_t);
+ }
+ /*lint -restore*/
+ ble_hrs_c_evt.params.hrm.rr_intervals_cnt = (uint8_t)i;
+ }
+ p_ble_hrs_c->evt_handler(p_ble_hrs_c, &ble_hrs_c_evt);
+ }
+}
+
+
+/**@brief Function for handling Disconnected event received from the SoftDevice.
+ *
+ * @details This function check if the disconnect event is happening on the link
+ * associated with the current instance of the module, if so it will set its
+ * conn_handle to invalid.
+ *
+ * @param[in] p_ble_hrs_c Pointer to the Heart Rate Client structure.
+ * @param[in] p_ble_evt Pointer to the BLE event received.
+ */
+static void on_disconnected(ble_hrs_c_t * p_ble_hrs_c, const ble_evt_t * p_ble_evt)
+{
+ if (p_ble_hrs_c->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
+ {
+ p_ble_hrs_c->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle = BLE_GATT_HANDLE_INVALID;
+ p_ble_hrs_c->peer_hrs_db.hrm_handle = BLE_GATT_HANDLE_INVALID;
+ }
+}
+
+
+void ble_hrs_on_db_disc_evt(ble_hrs_c_t * p_ble_hrs_c, const ble_db_discovery_evt_t * p_evt)
+{
+ // Check if the Heart Rate Service was discovered.
+ if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE &&
+ p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_HEART_RATE_SERVICE &&
+ p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE)
+ {
+ // Find the CCCD Handle of the Heart Rate Measurement characteristic.
+ uint32_t i;
+
+ ble_hrs_c_evt_t evt;
+
+ evt.evt_type = BLE_HRS_C_EVT_DISCOVERY_COMPLETE;
+ evt.conn_handle = p_evt->conn_handle;
+
+ for (i = 0; i < p_evt->params.discovered_db.char_count; i++)
+ {
+ if (p_evt->params.discovered_db.charateristics[i].characteristic.uuid.uuid ==
+ BLE_UUID_HEART_RATE_MEASUREMENT_CHAR)
+ {
+ // Found Heart Rate characteristic. Store CCCD handle and break.
+ evt.params.peer_db.hrm_cccd_handle =
+ p_evt->params.discovered_db.charateristics[i].cccd_handle;
+ evt.params.peer_db.hrm_handle =
+ p_evt->params.discovered_db.charateristics[i].characteristic.handle_value;
+ break;
+ }
+ }
+
+ NRF_LOG_DEBUG("Heart Rate Service discovered at peer.");
+ //If the instance has been assigned prior to db_discovery, assign the db_handles
+ if (p_ble_hrs_c->conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ if ((p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle == BLE_GATT_HANDLE_INVALID)&&
+ (p_ble_hrs_c->peer_hrs_db.hrm_handle == BLE_GATT_HANDLE_INVALID))
+ {
+ p_ble_hrs_c->peer_hrs_db = evt.params.peer_db;
+ }
+ }
+
+
+ p_ble_hrs_c->evt_handler(p_ble_hrs_c, &evt);
+ }
+}
+
+
+uint32_t ble_hrs_c_init(ble_hrs_c_t * p_ble_hrs_c, ble_hrs_c_init_t * p_ble_hrs_c_init)
+{
+ VERIFY_PARAM_NOT_NULL(p_ble_hrs_c);
+ VERIFY_PARAM_NOT_NULL(p_ble_hrs_c_init);
+
+ ble_uuid_t hrs_uuid;
+
+ hrs_uuid.type = BLE_UUID_TYPE_BLE;
+ hrs_uuid.uuid = BLE_UUID_HEART_RATE_SERVICE;
+
+
+ p_ble_hrs_c->evt_handler = p_ble_hrs_c_init->evt_handler;
+ p_ble_hrs_c->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle = BLE_GATT_HANDLE_INVALID;
+ p_ble_hrs_c->peer_hrs_db.hrm_handle = BLE_GATT_HANDLE_INVALID;
+
+ return ble_db_discovery_evt_register(&hrs_uuid);
+}
+
+void ble_hrs_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ ble_hrs_c_t * p_ble_hrs_c = (ble_hrs_c_t *)p_context;
+
+ if ((p_ble_hrs_c == NULL) || (p_ble_evt == NULL))
+ {
+ return;
+ }
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GATTC_EVT_HVX:
+ on_hvx(p_ble_hrs_c, p_ble_evt);
+ break;
+
+ case BLE_GATTC_EVT_WRITE_RSP:
+ on_write_rsp(p_ble_hrs_c, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnected(p_ble_hrs_c, p_ble_evt);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/**@brief Function for creating a message for writing to the CCCD.
+ */
+static uint32_t cccd_configure(uint16_t conn_handle, uint16_t handle_cccd, bool enable)
+{
+ NRF_LOG_DEBUG("Configuring CCCD. CCCD Handle = %d, Connection Handle = %d",
+ handle_cccd,conn_handle);
+
+ tx_message_t * p_msg;
+ uint16_t cccd_val = enable ? BLE_GATT_HVX_NOTIFICATION : 0;
+
+ p_msg = &m_tx_buffer[m_tx_insert_index++];
+ m_tx_insert_index &= TX_BUFFER_MASK;
+
+ p_msg->req.write_req.gattc_params.handle = handle_cccd;
+ p_msg->req.write_req.gattc_params.len = WRITE_MESSAGE_LENGTH;
+ p_msg->req.write_req.gattc_params.p_value = p_msg->req.write_req.gattc_value;
+ p_msg->req.write_req.gattc_params.offset = 0;
+ p_msg->req.write_req.gattc_params.write_op = BLE_GATT_OP_WRITE_REQ;
+ p_msg->req.write_req.gattc_value[0] = LSB_16(cccd_val);
+ p_msg->req.write_req.gattc_value[1] = MSB_16(cccd_val);
+ p_msg->conn_handle = conn_handle;
+ p_msg->type = WRITE_REQ;
+
+ tx_buffer_process();
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_hrs_c_hrm_notif_enable(ble_hrs_c_t * p_ble_hrs_c)
+{
+ VERIFY_PARAM_NOT_NULL(p_ble_hrs_c);
+
+ return cccd_configure(p_ble_hrs_c->conn_handle,
+ p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle,
+ true);
+}
+
+
+uint32_t ble_hrs_c_handles_assign(ble_hrs_c_t * p_ble_hrs_c,
+ uint16_t conn_handle,
+ const hrs_db_t * p_peer_hrs_handles)
+{
+ VERIFY_PARAM_NOT_NULL(p_ble_hrs_c);
+
+ p_ble_hrs_c->conn_handle = conn_handle;
+ if (p_peer_hrs_handles != NULL)
+ {
+ p_ble_hrs_c->peer_hrs_db = *p_peer_hrs_handles;
+ }
+ return NRF_SUCCESS;
+}
+/** @}
+ * @endcond
+ */
+#endif // NRF_MODULE_ENABLED(BLE_HRS_C)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hrs_c/ble_hrs_c.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hrs_c/ble_hrs_c.h
new file mode 100644
index 0000000..0dea00f
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hrs_c/ble_hrs_c.h
@@ -0,0 +1,295 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/**@file
+ *
+ * @defgroup ble_hrs_c Heart Rate Service Client
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Heart Rate Service Client module.
+ *
+ * @details This module contains the APIs and types exposed by the Heart Rate Service Client
+ * module. These APIs and types can be used by the application to perform discovery of
+ * Heart Rate Service at the peer and interact with it.
+ *
+ * @warning Currently this module only has support for Heart Rate Measurement characteristic. This
+ * means that it will be able to enable notification of the characteristic at the peer and
+ * be able to receive Heart Rate Measurement notifications from the peer. It does not
+ * support the Body Sensor Location and the Heart Rate Control Point characteristics.
+ * When a Heart Rate Measurement is received, this module will decode only the
+ * Heart Rate Measurement Value (both 8 bit and 16 bit) field from it and provide it to
+ * the application.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_hrs_c_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_HRS_C_BLE_OBSERVER_PRIO,
+ * ble_hrs_c_on_ble_evt, &instance);
+ * @endcode
+ */
+
+#ifndef BLE_HRS_C_H__
+#define BLE_HRS_C_H__
+
+#include <stdint.h>
+#include "ble.h"
+#include "ble_db_discovery.h"
+#include "sdk_config.h"
+#include "nrf_sdh_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_hrs_c instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_HRS_C_DEF(_name) \
+static ble_hrs_c_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_HRS_C_BLE_OBSERVER_PRIO, \
+ ble_hrs_c_on_ble_evt, &_name)
+
+/** @brief Macro for defining multiple ble_hrs_c instances.
+ *
+ * @param _name Name of the array of instances.
+ * @param _cnt Number of instances to define.
+ * @hideinitializer
+ */
+#define BLE_HRS_C_ARRAY_DEF(_name, _cnt) \
+static ble_hrs_c_t _name[_cnt]; \
+NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
+ BLE_HRS_C_BLE_OBSERVER_PRIO, \
+ ble_hrs_c_on_ble_evt, &_name, _cnt)
+
+
+/** @brief Maximum number of RR intervals to be decoded for each HRM notifications (any extra RR intervals will be ignored).
+ *
+ * This define should be defined in the sdk_config.h file to override the default.
+ */
+#ifndef BLE_HRS_C_RR_INTERVALS_MAX_CNT
+#define BLE_HRS_C_RR_INTERVALS_MAX_CNT 20
+#endif
+
+
+/**
+ * @defgroup hrs_c_enums Enumerations
+ * @{
+ */
+
+/**@brief HRS Client event type. */
+typedef enum
+{
+ BLE_HRS_C_EVT_DISCOVERY_COMPLETE = 1, /**< Event indicating that the Heart Rate Service has been discovered at the peer. */
+ BLE_HRS_C_EVT_HRM_NOTIFICATION /**< Event indicating that a notification of the Heart Rate Measurement characteristic has been received from the peer. */
+} ble_hrs_c_evt_type_t;
+
+/** @} */
+
+/**
+ * @defgroup hrs_c_structs Structures
+ * @{
+ */
+
+/**@brief Structure containing the heart rate measurement received from the peer. */
+typedef struct
+{
+ uint16_t hr_value; /**< Heart Rate Value. */
+ uint8_t rr_intervals_cnt; /**< Number of RR intervals. */
+ uint16_t rr_intervals[BLE_HRS_C_RR_INTERVALS_MAX_CNT]; /**< RR intervals. */
+} ble_hrm_t;
+
+/**@brief Structure containing the handles related to the Heart Rate Service found on the peer. */
+typedef struct
+{
+ uint16_t hrm_cccd_handle; /**< Handle of the CCCD of the Heart Rate Measurement characteristic. */
+ uint16_t hrm_handle; /**< Handle of the Heart Rate Measurement characteristic as provided by the SoftDevice. */
+} hrs_db_t;
+
+/**@brief Heart Rate Event structure. */
+typedef struct
+{
+ ble_hrs_c_evt_type_t evt_type; /**< Type of the event. */
+ uint16_t conn_handle; /**< Connection handle on which the Heart Rate service was discovered on the peer device..*/
+ union
+ {
+ hrs_db_t peer_db; /**< Heart Rate related handles found on the peer device.. This will be filled if the evt_type is @ref BLE_HRS_C_EVT_DISCOVERY_COMPLETE.*/
+ ble_hrm_t hrm; /**< Heart rate measurement received. This will be filled if the evt_type is @ref BLE_HRS_C_EVT_HRM_NOTIFICATION. */
+ } params;
+} ble_hrs_c_evt_t;
+
+/** @} */
+
+/**
+ * @defgroup hrs_c_types Types
+ * @{
+ */
+
+// Forward declaration of the ble_bas_t type.
+typedef struct ble_hrs_c_s ble_hrs_c_t;
+
+/**@brief Event handler type.
+ *
+ * @details This is the type of the event handler that should be provided by the application
+ * of this module in order to receive events.
+ */
+typedef void (* ble_hrs_c_evt_handler_t) (ble_hrs_c_t * p_ble_hrs_c, ble_hrs_c_evt_t * p_evt);
+
+/** @} */
+
+/**
+ * @addtogroup hrs_c_structs
+ * @{
+ */
+
+/**@brief Heart Rate Client structure.
+ */
+struct ble_hrs_c_s
+{
+ uint16_t conn_handle; /**< Connection handle as provided by the SoftDevice. */
+ hrs_db_t peer_hrs_db; /**< Handles related to HRS on the peer*/
+ ble_hrs_c_evt_handler_t evt_handler; /**< Application event handler to be called when there is an event related to the heart rate service. */
+};
+
+/**@brief Heart Rate Client initialization structure.
+ */
+typedef struct
+{
+ ble_hrs_c_evt_handler_t evt_handler; /**< Event handler to be called by the Heart Rate Client module whenever there is an event related to the Heart Rate Service. */
+} ble_hrs_c_init_t;
+
+/** @} */
+
+
+/**
+ * @defgroup hrs_c_functions Functions
+ * @{
+ */
+
+/**@brief Function for initializing the heart rate client module.
+ *
+ * @details This function will register with the DB Discovery module. There it
+ * registers for the Heart Rate Service. Doing so will make the DB Discovery
+ * module look for the presence of a Heart Rate Service instance at the peer when a
+ * discovery is started.
+ *
+ * @param[in] p_ble_hrs_c Pointer to the heart rate client structure.
+ * @param[in] p_ble_hrs_c_init Pointer to the heart rate initialization structure containing the
+ * initialization information.
+ *
+ * @retval NRF_SUCCESS On successful initialization. Otherwise an error code. This function
+ * propagates the error code returned by the Database Discovery module API
+ * @ref ble_db_discovery_evt_register.
+ */
+uint32_t ble_hrs_c_init(ble_hrs_c_t * p_ble_hrs_c, ble_hrs_c_init_t * p_ble_hrs_c_init);
+
+
+/**@brief Function for handling BLE events from the SoftDevice.
+ *
+ * @details This function will handle the BLE events received from the SoftDevice. If a BLE
+ * event is relevant to the Heart Rate Client module, then it uses it to update
+ * interval variables and, if necessary, send events to the application.
+ *
+ * @param[in] p_ble_evt Pointer to the BLE event.
+ * @param[in] p_context Pointer to the heart rate client structure.
+ */
+void ble_hrs_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for requesting the peer to start sending notification of Heart Rate
+ * Measurement.
+ *
+ * @details This function will enable to notification of the Heart Rate Measurement at the peer
+ * by writing to the CCCD of the Heart Rate Measurement Characteristic.
+ *
+ * @param p_ble_hrs_c Pointer to the heart rate client structure.
+ *
+ * @retval NRF_SUCCESS If the SoftDevice has been requested to write to the CCCD of the peer.
+ * Otherwise, an error code. This function propagates the error code returned
+ * by the SoftDevice API @ref sd_ble_gattc_write.
+ */
+uint32_t ble_hrs_c_hrm_notif_enable(ble_hrs_c_t * p_ble_hrs_c);
+
+
+/**@brief Function for handling events from the database discovery module.
+ *
+ * @details Call this function when getting a callback event from the DB discovery modue.
+ * This function will handle an event from the database discovery module, and determine
+ * if it relates to the discovery of heart rate service at the peer. If so, it will
+ * call the application's event handler indicating that the heart rate service has been
+ * discovered at the peer. It also populates the event with the service related
+ * information before providing it to the application.
+ *
+ * @param[in] p_ble_hrs_c Pointer to the heart rate client structure instance to associate.
+ * @param[in] p_evt Pointer to the event received from the database discovery module.
+ *
+ */
+void ble_hrs_on_db_disc_evt(ble_hrs_c_t * p_ble_hrs_c, const ble_db_discovery_evt_t * p_evt);
+
+
+/**@brief Function for assigning a handles to a this instance of hrs_c.
+ *
+ * @details Call this function when a link has been established with a peer to
+ * associate this link to this instance of the module. This makes it
+ * possible to handle several link and associate each link to a particular
+ * instance of this module.The connection handle and attribute handles will be
+ * provided from the discovery event @ref BLE_HRS_C_EVT_DISCOVERY_COMPLETE.
+ *
+ * @param[in] p_ble_hrs_c Pointer to the heart rate client structure instance to associate.
+ * @param[in] conn_handle Connection handle to associated with the given Heart Rate Client Instance.
+ * @param[in] p_peer_hrs_handles Attribute handles for the HRS server you want this HRS_C client to
+ * interact with.
+ */
+uint32_t ble_hrs_c_handles_assign(ble_hrs_c_t * p_ble_hrs_c,
+ uint16_t conn_handle,
+ const hrs_db_t * p_peer_hrs_handles);
+
+/** @} */ // End tag for Function group.
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_HRS_C_H__
+
+/** @} */ // End tag for the file.
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hts/ble_hts.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hts/ble_hts.c
new file mode 100644
index 0000000..25afa01
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hts/ble_hts.c
@@ -0,0 +1,462 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Attention!
+ * To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_HTS)
+#include "ble_err.h"
+#include "ble_hts.h"
+#include <string.h>
+#include "ble_srv_common.h"
+
+
+#define OPCODE_LENGTH 1 /**< Length of opcode inside Health Thermometer Measurement packet. */
+#define HANDLE_LENGTH 2 /**< Length of handle inside Health Thermometer Measurement packet. */
+#define MAX_HTM_LEN (BLE_GATT_ATT_MTU_DEFAULT - OPCODE_LENGTH - HANDLE_LENGTH) /**< Maximum size of a transmitted Health Thermometer Measurement. */
+
+// Health Thermometer Measurement flag bits
+#define HTS_MEAS_FLAG_TEMP_UNITS_BIT (0x01 << 0) /**< Temperature Units flag. */
+#define HTS_MEAS_FLAG_TIME_STAMP_BIT (0x01 << 1) /**< Time Stamp flag. */
+#define HTS_MEAS_FLAG_TEMP_TYPE_BIT (0x01 << 2) /**< Temperature Type flag. */
+
+
+/**@brief Function for handling the Connect event.
+ *
+ * @param[in] p_hts Health Thermometer Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_connect(ble_hts_t * p_hts, ble_evt_t const * p_ble_evt)
+{
+ p_hts->conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
+}
+
+
+/**@brief Function for handling the Disconnect event.
+ *
+ * @param[in] p_hts Health Thermometer Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_disconnect(ble_hts_t * p_hts, ble_evt_t const * p_ble_evt)
+{
+ UNUSED_PARAMETER(p_ble_evt);
+ p_hts->conn_handle = BLE_CONN_HANDLE_INVALID;
+}
+
+
+/**@brief Function for handling write events to the Blood Pressure Measurement characteristic.
+ *
+ * @param[in] p_hts Health Thermometer Service structure.
+ * @param[in] p_evt_write Write event received from the BLE stack.
+ */
+static void on_cccd_write(ble_hts_t * p_hts, ble_gatts_evt_write_t const * p_evt_write)
+{
+ if (p_evt_write->len == 2)
+ {
+ // CCCD written, update indication state
+ if (p_hts->evt_handler != NULL)
+ {
+ ble_hts_evt_t evt;
+
+ if (ble_srv_is_indication_enabled(p_evt_write->data))
+ {
+ evt.evt_type = BLE_HTS_EVT_INDICATION_ENABLED;
+ }
+ else
+ {
+ evt.evt_type = BLE_HTS_EVT_INDICATION_DISABLED;
+ }
+
+ p_hts->evt_handler(p_hts, &evt);
+ }
+ }
+}
+
+
+/**@brief Function for handling the Write event.
+ *
+ * @param[in] p_hts Health Thermometer Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_write(ble_hts_t * p_hts, ble_evt_t const * p_ble_evt)
+{
+ ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+ if (p_evt_write->handle == p_hts->meas_handles.cccd_handle)
+ {
+ on_cccd_write(p_hts, p_evt_write);
+ }
+}
+
+
+/**@brief Function for handling the HVC event.
+ *
+ * @details Handles HVC events from the BLE stack.
+ *
+ * @param[in] p_hts Health Thermometer Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_hvc(ble_hts_t * p_hts, ble_evt_t const * p_ble_evt)
+{
+ ble_gatts_evt_hvc_t const * p_hvc = &p_ble_evt->evt.gatts_evt.params.hvc;
+
+ if (p_hvc->handle == p_hts->meas_handles.value_handle)
+ {
+ ble_hts_evt_t evt;
+
+ evt.evt_type = BLE_HTS_EVT_INDICATION_CONFIRMED;
+ p_hts->evt_handler(p_hts, &evt);
+ }
+}
+
+
+void ble_hts_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ ble_hts_t * p_hts = (ble_hts_t *)p_context;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ on_connect(p_hts, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnect(p_hts, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_WRITE:
+ on_write(p_hts, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_HVC:
+ on_hvc(p_hts, p_ble_evt);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+
+/**@brief Function for encoding a Health Thermometer Measurement.
+ *
+ * @param[in] p_hts Health Thermometer Service structure.
+ * @param[in] p_hts_meas Measurement to be encoded.
+ * @param[out] p_encoded_buffer Buffer where the encoded data will be written.
+ *
+ * @return Size of encoded data.
+ */
+static uint8_t hts_measurement_encode(ble_hts_t * p_hts,
+ ble_hts_meas_t * p_hts_meas,
+ uint8_t * p_encoded_buffer)
+{
+ uint8_t flags = 0;
+ uint8_t len = 1;
+ uint32_t encoded_temp;
+
+ // Flags field
+ if (p_hts_meas->temp_in_fahr_units)
+ {
+ flags |= HTS_MEAS_FLAG_TEMP_UNITS_BIT;
+ }
+ if (p_hts_meas->time_stamp_present)
+ {
+ flags |= HTS_MEAS_FLAG_TIME_STAMP_BIT;
+ }
+
+ // Temperature Measurement Value field
+ if (p_hts_meas->temp_in_fahr_units)
+ {
+ flags |= HTS_MEAS_FLAG_TEMP_UNITS_BIT;
+
+ encoded_temp = ((p_hts_meas->temp_in_fahr.exponent << 24) & 0xFF000000) |
+ ((p_hts_meas->temp_in_fahr.mantissa << 0) & 0x00FFFFFF);
+ }
+ else
+ {
+ encoded_temp = ((p_hts_meas->temp_in_celcius.exponent << 24) & 0xFF000000) |
+ ((p_hts_meas->temp_in_celcius.mantissa << 0) & 0x00FFFFFF);
+ }
+ len += uint32_encode(encoded_temp, &p_encoded_buffer[len]);
+
+ // Time Stamp field
+ if (p_hts_meas->time_stamp_present)
+ {
+ flags |= HTS_MEAS_FLAG_TIME_STAMP_BIT;
+ len += ble_date_time_encode(&p_hts_meas->time_stamp, &p_encoded_buffer[len]);
+ }
+
+ // Temperature Type field
+ if (p_hts_meas->temp_type_present)
+ {
+ flags |= HTS_MEAS_FLAG_TEMP_TYPE_BIT;
+ p_encoded_buffer[len++] = p_hts_meas->temp_type;
+ }
+
+ // Flags field
+ p_encoded_buffer[0] = flags;
+
+ return len;
+}
+
+
+/**@brief Function for adding Health Thermometer Measurement characteristics.
+ *
+ * @param[in] p_hts Health Thermometer Service structure.
+ * @param[in] p_hts_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t hts_measurement_char_add(ble_hts_t * p_hts, ble_hts_init_t const * p_hts_init)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_md_t cccd_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+ ble_hts_meas_t initial_htm;
+ uint8_t encoded_htm[MAX_HTM_LEN];
+
+ memset(&cccd_md, 0, sizeof(cccd_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
+ cccd_md.vloc = BLE_GATTS_VLOC_STACK;
+ cccd_md.write_perm = p_hts_init->hts_meas_attr_md.cccd_write_perm;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.indicate = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = &cccd_md;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_TEMPERATURE_MEASUREMENT_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.read_perm = p_hts_init->hts_meas_attr_md.read_perm;
+ attr_md.write_perm = p_hts_init->hts_meas_attr_md.write_perm;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 1;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+ memset(&initial_htm, 0, sizeof(initial_htm));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = hts_measurement_encode(p_hts, &initial_htm, encoded_htm);
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = MAX_HTM_LEN;
+ attr_char_value.p_value = encoded_htm;
+
+ return sd_ble_gatts_characteristic_add(p_hts->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_hts->meas_handles);
+}
+
+
+/**@brief Function for adding Temperature Type characteristics.
+ *
+ * @param[in] p_hts Health Thermometer Service structure.
+ * @param[in] p_hts_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t hts_temp_type_char_add(ble_hts_t * p_hts, ble_hts_init_t const * p_hts_init)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+ uint8_t init_value_temp_type;
+ uint8_t init_value_encoded[1];
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = NULL;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_TEMPERATURE_TYPE_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.read_perm = p_hts_init->hts_temp_type_attr_md.read_perm;
+ attr_md.write_perm = p_hts_init->hts_temp_type_attr_md.write_perm;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ init_value_temp_type = p_hts_init->temp_type;
+ init_value_encoded[0] = init_value_temp_type;
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = sizeof (uint8_t);
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = sizeof (uint8_t);
+ attr_char_value.p_value = init_value_encoded;
+
+ return sd_ble_gatts_characteristic_add(p_hts->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_hts->temp_type_handles);
+}
+
+
+uint32_t ble_hts_init(ble_hts_t * p_hts, ble_hts_init_t const * p_hts_init)
+{
+ uint32_t err_code;
+ ble_uuid_t ble_uuid;
+
+ // Initialize service structure
+ p_hts->evt_handler = p_hts_init->evt_handler;
+ p_hts->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_hts->temp_type = p_hts_init->temp_type;
+
+ // Add service
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_HEALTH_THERMOMETER_SERVICE);
+
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_hts->service_handle);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add measurement characteristic
+ err_code = hts_measurement_char_add(p_hts, p_hts_init);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add temperature type characteristic
+ if (p_hts_init->temp_type_as_characteristic)
+ {
+ err_code = hts_temp_type_char_add(p_hts, p_hts_init);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_hts_measurement_send(ble_hts_t * p_hts, ble_hts_meas_t * p_hts_meas)
+{
+ uint32_t err_code;
+
+ // Send value if connected
+ if (p_hts->conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ uint8_t encoded_hts_meas[MAX_HTM_LEN];
+ uint16_t len;
+ uint16_t hvx_len;
+ ble_gatts_hvx_params_t hvx_params;
+
+ len = hts_measurement_encode(p_hts, p_hts_meas, encoded_hts_meas);
+ hvx_len = len;
+
+ memset(&hvx_params, 0, sizeof(hvx_params));
+
+ hvx_params.handle = p_hts->meas_handles.value_handle;
+ hvx_params.type = BLE_GATT_HVX_INDICATION;
+ hvx_params.offset = 0;
+ hvx_params.p_len = &hvx_len;
+ hvx_params.p_data = encoded_hts_meas;
+
+ err_code = sd_ble_gatts_hvx(p_hts->conn_handle, &hvx_params);
+ if ((err_code == NRF_SUCCESS) && (hvx_len != len))
+ {
+ err_code = NRF_ERROR_DATA_SIZE;
+ }
+ }
+ else
+ {
+ err_code = NRF_ERROR_INVALID_STATE;
+ }
+
+ return err_code;
+}
+
+
+uint32_t ble_hts_is_indication_enabled(ble_hts_t * p_hts, bool * p_indication_enabled)
+{
+ uint32_t err_code;
+ uint8_t cccd_value_buf[BLE_CCCD_VALUE_LEN];
+ ble_gatts_value_t gatts_value;
+
+ // Initialize value struct.
+ memset(&gatts_value, 0, sizeof(gatts_value));
+
+ gatts_value.len = BLE_CCCD_VALUE_LEN;
+ gatts_value.offset = 0;
+ gatts_value.p_value = cccd_value_buf;
+
+ err_code = sd_ble_gatts_value_get(p_hts->conn_handle,
+ p_hts->meas_handles.cccd_handle,
+ &gatts_value);
+ if (err_code == NRF_SUCCESS)
+ {
+ *p_indication_enabled = ble_srv_is_indication_enabled(cccd_value_buf);
+ }
+ if (err_code == BLE_ERROR_GATTS_SYS_ATTR_MISSING)
+ {
+ *p_indication_enabled = false;
+ return NRF_SUCCESS;
+ }
+ return err_code;
+}
+#endif // NRF_MODULE_ENABLED(BLE_HTS)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hts/ble_hts.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hts/ble_hts.h
new file mode 100644
index 0000000..a9f76cd
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_hts/ble_hts.h
@@ -0,0 +1,219 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_hts Health Thermometer Service
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Health Thermometer Service module.
+ *
+ * @details This module implements the Health Thermometer Service.
+ *
+ * If an event handler is supplied by the application, the Health Thermometer
+ * Service will generate Health Thermometer Service events to the application.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_hts_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_HTS_BLE_OBSERVER_PRIO,
+ * ble_hts_on_ble_evt, &instance);
+ * @endcode
+ *
+ * @note Attention!
+ * To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+
+#ifndef BLE_HTS_H__
+#define BLE_HTS_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "ble_date_time.h"
+#include "nrf_sdh_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_hts instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_HTS_DEF(_name) \
+static ble_hts_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_HTS_BLE_OBSERVER_PRIO, \
+ ble_hts_on_ble_evt, &_name)
+
+// Temperature Type measurement locations
+#define BLE_HTS_TEMP_TYPE_ARMPIT 1
+#define BLE_HTS_TEMP_TYPE_BODY 2
+#define BLE_HTS_TEMP_TYPE_EAR 3
+#define BLE_HTS_TEMP_TYPE_FINGER 4
+#define BLE_HTS_TEMP_TYPE_GI_TRACT 5
+#define BLE_HTS_TEMP_TYPE_MOUTH 6
+#define BLE_HTS_TEMP_TYPE_RECTUM 7
+#define BLE_HTS_TEMP_TYPE_TOE 8
+#define BLE_HTS_TEMP_TYPE_EAR_DRUM 9
+
+
+/**@brief Health Thermometer Service event type. */
+typedef enum
+{
+ BLE_HTS_EVT_INDICATION_ENABLED, /**< Health Thermometer value indication enabled event. */
+ BLE_HTS_EVT_INDICATION_DISABLED, /**< Health Thermometer value indication disabled event. */
+ BLE_HTS_EVT_INDICATION_CONFIRMED /**< Confirmation of a temperature measurement indication has been received. */
+} ble_hts_evt_type_t;
+
+/**@brief Health Thermometer Service event. */
+typedef struct
+{
+ ble_hts_evt_type_t evt_type; /**< Type of event. */
+} ble_hts_evt_t;
+
+// Forward declaration of the ble_hts_t type.
+typedef struct ble_hts_s ble_hts_t;
+
+/**@brief Health Thermometer Service event handler type. */
+typedef void (*ble_hts_evt_handler_t) (ble_hts_t * p_hts, ble_hts_evt_t * p_evt);
+
+/**@brief FLOAT format (IEEE-11073 32-bit FLOAT, defined as a 32-bit value with a 24-bit mantissa
+ * and an 8-bit exponent. */
+typedef struct
+{
+ int8_t exponent; /**< Base 10 exponent */
+ int32_t mantissa; /**< Mantissa, should be using only 24 bits */
+} ieee_float32_t;
+
+/**@brief Health Thermometer Service init structure. This contains all options and data
+ * needed for initialization of the service. */
+typedef struct
+{
+ ble_hts_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Health Thermometer Service. */
+ ble_srv_cccd_security_mode_t hts_meas_attr_md; /**< Initial security level for health thermometer measurement attribute */
+ ble_srv_security_mode_t hts_temp_type_attr_md; /**< Initial security level for health thermometer tempearture type attribute */
+ uint8_t temp_type_as_characteristic; /**< Set non-zero if temp type given as characteristic */
+ uint8_t temp_type; /**< Temperature type if temperature characteristic is used */
+} ble_hts_init_t;
+
+/**@brief Health Thermometer Service structure. This contains various status information for
+ * the service. */
+struct ble_hts_s
+{
+ ble_hts_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Health Thermometer Service. */
+ uint16_t service_handle; /**< Handle of Health Thermometer Service (as provided by the BLE stack). */
+ ble_gatts_char_handles_t meas_handles; /**< Handles related to the Health Thermometer Measurement characteristic. */
+ ble_gatts_char_handles_t temp_type_handles; /**< Handles related to the Health Thermometer Temperature Type characteristic. */
+ uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
+ uint8_t temp_type; /**< Temperature type indicates where the measurement was taken. */
+};
+
+/**@brief Health Thermometer Service measurement structure. This contains a Health Thermometer
+ * measurement. */
+typedef struct ble_hts_meas_s
+{
+ bool temp_in_fahr_units; /**< True if Temperature is in Fahrenheit units, Celcius otherwise. */
+ bool time_stamp_present; /**< True if Time Stamp is present. */
+ bool temp_type_present; /**< True if Temperature Type is present. */
+ ieee_float32_t temp_in_celcius; /**< Temperature Measurement Value (Celcius). */
+ ieee_float32_t temp_in_fahr; /**< Temperature Measurement Value (Fahrenheit). */
+ ble_date_time_t time_stamp; /**< Time Stamp. */
+ uint8_t temp_type; /**< Temperature Type. */
+} ble_hts_meas_t;
+
+
+/**@brief Function for initializing the Health Thermometer Service.
+ *
+ * @param[out] p_hts Health Thermometer Service structure. This structure will have to
+ * be supplied by the application. It will be initialized by this function,
+ * and will later be used to identify this particular service instance.
+ * @param[in] p_hts_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
+ */
+uint32_t ble_hts_init(ble_hts_t * p_hts, const ble_hts_init_t * p_hts_init);
+
+
+/**@brief Function for handling the Application's BLE Stack events.
+ *
+ * @details Handles all events from the BLE stack of interest to the Health Thermometer Service.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Health Thermometer Service structure.
+ */
+void ble_hts_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for sending health thermometer measurement if indication has been enabled.
+ *
+ * @details The application calls this function after having performed a Health Thermometer
+ * measurement. If indication has been enabled, the measurement data is encoded and
+ * sent to the client.
+ *
+ * @param[in] p_hts Health Thermometer Service structure.
+ * @param[in] p_hts_meas Pointer to new health thermometer measurement.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+uint32_t ble_hts_measurement_send(ble_hts_t * p_hts, ble_hts_meas_t * p_hts_meas);
+
+
+/**@brief Function for checking if indication of Temperature Measurement is currently enabled.
+ *
+ * @param[in] p_hts Health Thermometer Service structure.
+ * @param[out] p_indication_enabled TRUE if indication is enabled, FALSE otherwise.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+uint32_t ble_hts_is_indication_enabled(ble_hts_t * p_hts, bool * p_indication_enabled);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_HTS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ias/ble_ias.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ias/ble_ias.c
new file mode 100644
index 0000000..55a0b20
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ias/ble_ias.c
@@ -0,0 +1,242 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Attention!
+ * To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_IAS)
+#include "ble_ias.h"
+#include <string.h>
+#include "ble_srv_common.h"
+
+#define NRF_LOG_MODULE_NAME ble_ias
+#if BLE_IAS_CONFIG_LOG_ENABLED
+#define NRF_LOG_LEVEL BLE_IAS_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR BLE_IAS_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR BLE_IAS_CONFIG_DEBUG_COLOR
+#else // BLE_IAS_CONFIG_LOG_ENABLED
+#define NRF_LOG_LEVEL 0
+#endif // BLE_IAS_CONFIG_LOG_ENABLED
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+
+#define INITIAL_ALERT_LEVEL BLE_CHAR_ALERT_LEVEL_NO_ALERT
+
+
+/**@brief Function for handling the Connect event.
+ *
+ * @param[in] p_ias Immediate Alert Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_connect(ble_ias_t * p_ias, ble_evt_t const * p_ble_evt)
+{
+ ret_code_t err_code;
+ ble_ias_client_context_t * p_client = NULL;
+
+ err_code = blcm_link_ctx_get(p_ias->p_link_ctx_storage,
+ p_ble_evt->evt.gap_evt.conn_handle,
+ (void *) &p_client);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.",
+ p_ble_evt->evt.gap_evt.conn_handle);
+ }
+ else
+ {
+ p_client->alert_level = INITIAL_ALERT_LEVEL;
+ }
+}
+
+
+/**@brief Function for handling the Write event.
+ *
+ * @param[in] p_ias Immediate Alert Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_write(ble_ias_t * p_ias, ble_evt_t const * p_ble_evt)
+{
+ ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+ if ((p_evt_write->handle == p_ias->alert_level_handles.value_handle) && (p_evt_write->len == 1))
+ {
+ // Alert level written, call application event handler
+ ret_code_t err_code;
+ ble_ias_evt_t evt;
+ ble_ias_client_context_t * p_client;
+
+ err_code = blcm_link_ctx_get(p_ias->p_link_ctx_storage,
+ p_ble_evt->evt.gatts_evt.conn_handle,
+ (void *) &p_client);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.",
+ p_ble_evt->evt.gatts_evt.conn_handle);
+ }
+ else
+ {
+ p_client->alert_level = p_evt_write->data[0];
+ }
+
+ evt.evt_type = BLE_IAS_EVT_ALERT_LEVEL_UPDATED;
+ evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
+ evt.p_link_ctx = p_client;
+
+ p_ias->evt_handler(p_ias, &evt);
+ }
+}
+
+
+void ble_ias_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ ble_ias_t * p_ias = (ble_ias_t *)p_context;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ on_connect(p_ias, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_WRITE:
+ on_write(p_ias, p_ble_evt);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+
+/**@brief Function for adding Alert Level characteristics.
+ *
+ * @param[in] p_ias Immediate Alert Service structure.
+ * @param[in] p_ias_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t alert_level_char_add(ble_ias_t * p_ias)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+ uint8_t initial_alert_level;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.write_wo_resp = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = NULL;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_ALERT_LEVEL_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.write_perm);
+
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+ initial_alert_level = INITIAL_ALERT_LEVEL;
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = sizeof (uint8_t);
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = sizeof (uint8_t);
+ attr_char_value.p_value = &initial_alert_level;
+
+ return sd_ble_gatts_characteristic_add(p_ias->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_ias->alert_level_handles);
+}
+
+
+uint32_t ble_ias_init(ble_ias_t * p_ias, const ble_ias_init_t * p_ias_init)
+{
+ uint32_t err_code;
+ ble_uuid_t ble_uuid;
+
+ // Initialize service structure
+ if (p_ias_init->evt_handler == NULL)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ p_ias->evt_handler = p_ias_init->evt_handler;
+
+ // Add service
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_IMMEDIATE_ALERT_SERVICE);
+
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
+ &ble_uuid,
+ &p_ias->service_handle);
+ VERIFY_SUCCESS(err_code);
+
+ // Add alert level characteristic
+ err_code = alert_level_char_add(p_ias);
+ VERIFY_SUCCESS(err_code);
+
+ return err_code;
+}
+
+
+uint32_t ble_ias_alert_level_get(ble_ias_t * p_ias, uint16_t conn_handle, uint8_t * p_alert_level)
+{
+ ret_code_t err_code;
+ ble_ias_client_context_t * p_client;
+
+ err_code = blcm_link_ctx_get(p_ias->p_link_ctx_storage, conn_handle, (void *) &p_client);
+ VERIFY_SUCCESS(err_code);
+
+ *p_alert_level = p_client->alert_level;
+ return NRF_SUCCESS;
+}
+
+#endif // NRF_MODULE_ENABLED(BLE_IAS)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ias/ble_ias.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ias/ble_ias.h
new file mode 100644
index 0000000..985ecdb
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ias/ble_ias.h
@@ -0,0 +1,194 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_ias Immediate Alert Service
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Immediate Alert Service module.
+ *
+ * @details This module implements the Immediate Alert Service with the Alert Level characteristic.
+ * During initialization it adds the Immediate Alert Service and Alert Level characteristic
+ * to the BLE stack database.
+ *
+ * The application must supply an event handler for receiving Immediate Alert Service
+ * events. Using this handler, the service will notify the application when the
+ * Alert Level characteristic value changes.
+ *
+ * The service also provides a function for letting the application poll the current
+ * value of the Alert Level characteristic.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_ias_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_IAS_BLE_OBSERVER_PRIO,
+ * ble_ias_on_ble_evt, &instance);
+ * @endcode
+ *
+ * @note Attention!
+ * To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+*/
+
+#ifndef BLE_IAS_H__
+#define BLE_IAS_H__
+
+#include <stdint.h>
+#include "ble.h"
+#include "nrf_sdh_ble.h"
+#include "ble_link_ctx_manager.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**@brief Macro for defining a ble_ias instance.
+ *
+ * @param _name Name of the instance.
+ * @param[in] _ias_max_clients Maximum number of IAS clients connected at a time.
+ * @hideinitializer
+ */
+#define BLE_IAS_DEF(_name, _ias_max_clients) \
+ BLE_LINK_CTX_MANAGER_DEF(CONCAT_2(_name, _link_ctx_storage), \
+ (_ias_max_clients), \
+ sizeof(ble_ias_client_context_t)); \
+ static ble_ias_t _name = \
+ { \
+ .p_link_ctx_storage = &CONCAT_2(_name, _link_ctx_storage) \
+ }; \
+ NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_IAS_BLE_OBSERVER_PRIO, \
+ ble_ias_on_ble_evt, \
+ &_name)
+
+
+/**@brief Immediate Alert Service event type. */
+typedef enum
+{
+ BLE_IAS_EVT_ALERT_LEVEL_UPDATED /**< Alert Level Updated event. */
+} ble_ias_evt_type_t;
+
+
+/**@brief Immediate Alert Service client context structure.
+ *
+ * @details This structure contains state context related to hosts.
+ */
+typedef struct
+{
+ uint8_t alert_level; /**< New Alert Level value. */
+} ble_ias_client_context_t;
+
+
+/**@brief Immediate Alert Service event. */
+typedef struct
+{
+ ble_ias_evt_type_t evt_type; /**< Type of event. */
+ uint16_t conn_handle; /**< Connection handle. */
+ ble_ias_client_context_t * p_link_ctx; /**< A pointer to the link context. */
+} ble_ias_evt_t;
+
+
+// Forward declaration of the ble_ias_t type.
+typedef struct ble_ias_s ble_ias_t;
+
+
+/**@brief Immediate Alert Service event handler type. */
+typedef void (*ble_ias_evt_handler_t) (ble_ias_t * p_ias, ble_ias_evt_t * p_evt);
+
+
+/**@brief Immediate Alert Service init structure. This contains all options and data needed for
+ * initialization of the service. */
+typedef struct
+{
+ ble_ias_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Immediate Alert Service. */
+} ble_ias_init_t;
+
+
+/**@brief Immediate Alert Service structure. This contains various status information for the
+ * service. */
+struct ble_ias_s
+{
+ ble_ias_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Immediate Alert Service. */
+ uint16_t service_handle; /**< Handle of Immediate Alert Service (as provided by the BLE stack). */
+ ble_gatts_char_handles_t alert_level_handles; /**< Handles related to the Alert Level characteristic. */
+ blcm_link_ctx_storage_t * const p_link_ctx_storage; /**< Pointer to link context storage with handles of all current connections and its context. */
+};
+
+
+/**@brief Function for initializing the Immediate Alert Service.
+ *
+ * @param[out] p_ias Immediate Alert Service structure. This structure will have to be
+ * supplied by the application. It will be initialized by this function,
+ * and will later be used to identify this particular service instance.
+ * @param[in] p_ias_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
+ */
+uint32_t ble_ias_init(ble_ias_t * p_ias, const ble_ias_init_t * p_ias_init);
+
+
+/**@brief Function for handling the Application's BLE Stack events.
+ *
+ * @details Handles all events from the BLE stack of interest to the Immediate Alert Service.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Immediate Alert Service structure.
+ */
+void ble_ias_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for getting value of the Alert Level characteristic.
+ *
+ * @param[in] p_ias Immediate Alert Service structure.
+ * @param[in] conn_handle Connection handle of the destination client.
+ * @param[out] p_alert_level Alert Level value which has been set by the specific client.
+ */
+uint32_t ble_ias_alert_level_get(ble_ias_t * p_ias, uint16_t conn_handle, uint8_t * p_alert_level);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_IAS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ias_c/ble_ias_c.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ias_c/ble_ias_c.c
new file mode 100644
index 0000000..c303cd6
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ias_c/ble_ias_c.c
@@ -0,0 +1,214 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_IAS_C)
+#include "ble_ias_c.h"
+
+#include <string.h>
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "ble_gattc.h"
+#include "ble_db_discovery.h"
+
+
+void ble_ias_c_on_db_disc_evt(ble_ias_c_t * p_ias_c, ble_db_discovery_evt_t const * p_evt)
+{
+ ble_ias_c_evt_t evt;
+
+ memset(&evt, 0, sizeof(ble_ias_c_evt_t));
+ evt.evt_type = BLE_IAS_C_EVT_DISCOVERY_FAILED;
+ evt.conn_handle = p_evt->conn_handle;
+
+ ble_gatt_db_char_t const * p_chars = p_evt->params.discovered_db.charateristics;
+
+ // Check if the Immediate Alert Service was discovered.
+ if ( (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE)
+ && (p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_IMMEDIATE_ALERT_SERVICE)
+ && (p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE))
+ {
+ for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
+ {
+ // The Alert Level characteristic in the Immediate Alert Service instance is found
+ // on peer. Check if it has the correct property 'Write without response'.
+ switch (p_chars[i].characteristic.uuid.uuid)
+ {
+ case BLE_UUID_ALERT_LEVEL_CHAR:
+ if (p_chars[i].characteristic.char_props.write_wo_resp)
+ {
+ // Found Alert Level characteristic inside the Immediate Alert Service.
+ memcpy(&evt.alert_level,
+ &p_chars[i].characteristic,
+ sizeof(ble_gattc_char_t));
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ if (evt.alert_level.handle_value != BLE_GATT_HANDLE_INVALID)
+ {
+ evt.evt_type = BLE_IAS_C_EVT_DISCOVERY_COMPLETE;
+ }
+
+ p_ias_c->evt_handler(p_ias_c, &evt);
+}
+
+
+uint32_t ble_ias_c_init(ble_ias_c_t * p_ias_c, ble_ias_c_init_t const * p_ias_c_init)
+{
+ VERIFY_PARAM_NOT_NULL(p_ias_c);
+ VERIFY_PARAM_NOT_NULL(p_ias_c_init->evt_handler);
+ VERIFY_PARAM_NOT_NULL(p_ias_c_init);
+
+ p_ias_c->evt_handler = p_ias_c_init->evt_handler;
+ p_ias_c->error_handler = p_ias_c_init->error_handler;
+ p_ias_c->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_ias_c->alert_level_char.handle_value = BLE_GATT_HANDLE_INVALID;
+
+ BLE_UUID_BLE_ASSIGN(p_ias_c->alert_level_char.uuid, BLE_UUID_ALERT_LEVEL_CHAR);
+ BLE_UUID_BLE_ASSIGN(p_ias_c->service_uuid, BLE_UUID_IMMEDIATE_ALERT_SERVICE);
+
+ return ble_db_discovery_evt_register(&p_ias_c->service_uuid);
+}
+
+
+
+/**@brief Function for handling the Disconnect event.
+ *
+ * @param[in] p_ias_c Immediate Alert Service client structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_disconnect(ble_ias_c_t * p_ias_c, ble_evt_t const * p_ble_evt)
+{
+ // The following values will be re-initialized when a new connection is made.
+ p_ias_c->conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ if (ble_ias_c_is_discovered(p_ias_c))
+ {
+ // There was a valid instance of IAS on the peer. Send an event to the
+ // application, so that it can do any clean up related to this module.
+ ble_ias_c_evt_t evt;
+
+ evt.evt_type = BLE_IAS_C_EVT_DISCONN_COMPLETE;
+
+ p_ias_c->evt_handler(p_ias_c, &evt);
+ p_ias_c->alert_level_char.handle_value = BLE_GATT_HANDLE_INVALID;
+ }
+}
+
+
+void ble_ias_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ ble_ias_c_t * p_ias_c = (ble_ias_c_t *)p_context;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnect(p_ias_c, p_ble_evt);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+
+ if ((err_code != NRF_SUCCESS) && (p_ias_c->error_handler != NULL))
+ {
+ p_ias_c->error_handler(err_code);
+ }
+}
+
+
+/**@brief Function for performing a Write procedure.
+ *
+ * @param[in] conn_handle Handle of the connection on which to perform the write operation.
+ * @param[in] write_handle Handle of the attribute to be written.
+ * @param[in] length Length of data to be written.
+ * @param[in] p_value Data to be written.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t write_characteristic_value(uint16_t conn_handle,
+ uint16_t write_handle,
+ uint16_t length,
+ uint8_t * p_value)
+{
+ ble_gattc_write_params_t write_params;
+
+ memset(&write_params, 0, sizeof(write_params));
+
+ write_params.handle = write_handle;
+ write_params.write_op = BLE_GATT_OP_WRITE_CMD;
+ write_params.offset = 0;
+ write_params.len = length;
+ write_params.p_value = p_value;
+
+ return sd_ble_gattc_write(conn_handle, &write_params);
+}
+
+
+uint32_t ble_ias_c_send_alert_level(ble_ias_c_t const * p_ias_c, uint8_t alert_level)
+{
+ if (!ble_ias_c_is_discovered(p_ias_c))
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ return write_characteristic_value(p_ias_c->conn_handle,
+ p_ias_c->alert_level_char.handle_value,
+ sizeof(uint8_t),
+ &alert_level);
+}
+
+
+uint32_t ble_ias_c_handles_assign(ble_ias_c_t * p_ias_c,
+ const uint16_t conn_handle,
+ const uint16_t alert_level_handle)
+{
+ VERIFY_PARAM_NOT_NULL(p_ias_c);
+
+ p_ias_c->conn_handle = conn_handle;
+ p_ias_c->alert_level_char.handle_value = alert_level_handle;
+ return NRF_SUCCESS;
+}
+#endif //NRF_MODULE_ENABLED(BLE_IAS_C)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ias_c/ble_ias_c.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ias_c/ble_ias_c.h
new file mode 100644
index 0000000..5d46d93
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ias_c/ble_ias_c.h
@@ -0,0 +1,237 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_ias_c Immediate Alert Service Client
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Immediate Alert Service Client module
+ *
+ * @details This module implements the Immediate Alert Service client - locator role of the Find Me
+ * profile. On @ref BLE_GAP_EVT_CONNECTED event, this module starts discovery of the
+ * Immediate Alert Service with Alert Level characteristic at the peer. This module will
+ * indicate the application about a successful service & characteristic discovery using
+ * @ref BLE_IAS_C_EVT_DISCOVERY_COMPLETE event. The application can use @ref
+ * ble_ias_c_send_alert_level function to signal alerts to the peer.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_ias_c_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_IAS_C_BLE_OBSERVER_PRIO,
+ * ble_ias_c_on_ble_evt, &instance);
+ * @endcode
+ */
+
+#ifndef BLE_IAS_C_H__
+#define BLE_IAS_C_H__
+
+#include <stdint.h>
+#include "ble_srv_common.h"
+#include "ble_gattc.h"
+#include "ble.h"
+#include "ble_db_discovery.h"
+#include "nrf_sdh_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_ias_c instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_IAS_C_DEF(_name) \
+static ble_ias_c_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_IAS_C_BLE_OBSERVER_PRIO, \
+ ble_ias_c_on_ble_evt, &_name)
+
+/** @brief Macro for defining multiple ble_ias_c instances.
+ *
+ * @param _name Name of the array of instances.
+ * @param _cnt Number of instances to define.
+ * @hideinitializer
+ */
+#define BLE_IAS_C_ARRAY_DEF(_name, _cnt) \
+static ble_ias_c_t _name[_cnt]; \
+NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
+ BLE_IAS_C_BLE_OBSERVER_PRIO, \
+ ble_ias_c_on_ble_evt, &_name, _cnt)
+
+
+// Forward declaration of the ble_ias_c_t type.
+typedef struct ble_ias_c_s ble_ias_c_t;
+
+/**@brief Immediate Alert Service client event type. */
+typedef enum
+{
+ BLE_IAS_C_EVT_DISCOVERY_COMPLETE, /**< Event indicating that the Immediate Alert Service is found at the peer. */
+ BLE_IAS_C_EVT_DISCOVERY_FAILED, /**< Event indicating that the Immediate Alert Service is not found at the peer. */
+ BLE_IAS_C_EVT_DISCONN_COMPLETE /**< Event indicating that the Immediate Alert Service client module has completed the processing of BLE_GAP_EVT_DISCONNECTED event. This event is raised only if a valid instance of IAS was found at the peer during the discovery phase. This event can be used the application to do clean up related to the IAS Client.*/
+} ble_ias_c_evt_type_t;
+
+/**@brief Immediate Alert Service client event. */
+typedef struct
+{
+ ble_ias_c_evt_type_t evt_type; /**< Type of event. */
+ uint16_t conn_handle; /**< Connection handle on which the IAS service was discovered on the peer device. This will be filled if the evt_type is @ref BLE_IAS_C_EVT_DISCOVERY_COMPLETE.*/
+ ble_gattc_char_t alert_level; /**< Info on the discovered Alert Level characteristic discovered. This will be filled if the evt_type is @ref BLE_IAS_C_EVT_DISCOVERY_COMPLETE.*/
+} ble_ias_c_evt_t;
+
+/**@brief Immediate Alert Service client event handler type. */
+typedef void (*ble_ias_c_evt_handler_t) (ble_ias_c_t * p_ias_c, ble_ias_c_evt_t * p_evt);
+
+/**@brief IAS Client structure. This contains various status information for the client. */
+struct ble_ias_c_s
+{
+ ble_ias_c_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Immediate Alert Service client. */
+ ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
+ uint16_t conn_handle; /**< Handle of the current connection. Set with @ref ble_ias_c_handles_assign when connected. */
+ ble_uuid_t service_uuid; /**< The GATT Service holding the discovered Immediate Service. */
+ ble_gattc_char_t alert_level_char; /**< IAS Alert Level Characteristic. Stores data about the alert characteristic found on the peer. */
+};
+
+/**@brief IAS Client init structure. This contains all options and data needed for initialization of
+ * the client.*/
+typedef struct
+{
+ ble_ias_c_evt_handler_t evt_handler; /**< Event handler to be called for handling events from the Immediate Alert Service client. */
+ ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
+} ble_ias_c_init_t;
+
+
+/**@brief Function for initializing the Immediate Alert Service client.
+ *
+ * @details This call allows the application to initialize the Immediate Alert Service client.
+ *
+ * @param[out] p_ias_c Immediate Alert Service client structure. This structure will have to
+ * be supplied by the application. It will be initialized by this
+ * function, and will later be used to identify this particular client
+ * instance.
+ * @param[in] p_ias_c_init Information needed to initialize the Immediate Alert Service client.
+ *
+ * @return NRF_SUCCESS on successful initialization of service.
+ */
+uint32_t ble_ias_c_init(ble_ias_c_t * p_ias_c, ble_ias_c_init_t const * p_ias_c_init);
+
+
+/**@brief Function for sending alert level to the peer.
+ *
+ * @details This function allows the application to send an alert to the peer.
+ *
+ * @param[in] p_ias_c Immediate Alert Service client structure.
+ * @param[in] alert_level Required alert level to be sent to the peer.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+uint32_t ble_ias_c_send_alert_level(ble_ias_c_t const * p_ias_c, uint8_t alert_level);
+
+
+/**@brief Function for handling the Application's BLE Stack events for Immediate Alert Service client.
+ *
+ * @details Handles all events from the BLE stack of interest to the Immediate Alert Service client.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Immediate Alert Service client structure.
+ */
+void ble_ias_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for checking whether the peer's Immediate Alert Service instance and the alert level
+ * characteristic have been discovered.
+ *
+ * @param[in] p_ias_c Immediate Alert Service client structure.
+ *
+ * @return TRUE if a handle has been assigned to alert_level_handle, meaning it must have been
+ * discovered. FALSE if the handle is invalid.
+ */
+static __INLINE bool ble_ias_c_is_discovered(ble_ias_c_t const * p_ias_c)
+{
+ return (p_ias_c->alert_level_char.handle_value != BLE_GATT_HANDLE_INVALID);
+}
+
+
+/**@brief Function for handling events from the database discovery module.
+ *
+ * @details Call this function when getting a callback event from the DB discovery modue.
+ * This function will handle an event from the database discovery module, and determine
+ * if it relates to the discovery of heart rate service at the peer. If so, it will
+ * call the application's event handler indicating that the heart rate service has been
+ * discovered at the peer. It also populates the event with the service related
+ * information before providing it to the application.
+ *
+ * @param[in] p_ias_c Pointer to the immediate alert client structure instance that will handle
+ * the discovery.
+ * @param[in] p_evt Pointer to the event received from the database discovery module.
+ *
+ */
+void ble_ias_c_on_db_disc_evt(ble_ias_c_t * p_ias_c, ble_db_discovery_evt_t const * p_evt);
+
+
+/**@brief Function for assigning handles to an instance of ias_c.
+ *
+ * @details Call this function when a link has been established with a peer to
+ * associate this link to this instance of the module. This makes it
+ * possible to handle several links and associate each link to a particular
+ * instance of this module. The connection handle and attribute handles will be
+ * provided from the discovery event @ref BLE_IAS_C_EVT_DISCOVERY_COMPLETE.
+ *
+ * @param[in] p_ias_c Pointer to the IAS client structure instance to associate.
+ * @param[in] conn_handle Connection handle to associated with the given IAS Instance.
+ * @param[in] alert_level_handle Attribute handle on the IAS server that you want this IAS_C client to
+ * interact with.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_NULL If a p_ias_c was a NULL pointer.
+ */
+uint32_t ble_ias_c_handles_assign(ble_ias_c_t * p_ias_c,
+ uint16_t conn_handle,
+ uint16_t alert_level_handle);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_IAS_C_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ipsp/ble_ipsp.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ipsp/ble_ipsp.c
new file mode 100644
index 0000000..291b536
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ipsp/ble_ipsp.c
@@ -0,0 +1,981 @@
+/**
+ * Copyright (c) 2014 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Attention!
+ * To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+#include <stdbool.h>
+#include <string.h>
+#include "nordic_common.h"
+#include "sdk_errors.h"
+#include "nrf.h"
+#include "sdk_config.h"
+#include "ble_ipsp.h"
+#include "ble_srv_common.h"
+#include "sdk_os.h"
+
+
+/**
+ * @defgroup ble_ipsp_log Module's Log Macros
+ * @details Macros used for creating module logs which can be useful in understanding handling
+ * of events or actions on API requests. These are intended for debugging purposes and
+ * can be enabled by defining the IOT_BLE_IPSP_CONFIG_LOG_ENABLED to 1.
+ * @note If NRF_LOG_ENABLED is disabled, having IOT_BLE_IPSP_CONFIG_LOG_ENABLED
+ * has no effect.
+ * @{
+ */
+
+#if IOT_BLE_IPSP_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME ipsp
+
+#define NRF_LOG_LEVEL IOT_BLE_IPSP_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR IOT_BLE_IPSP_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR IOT_BLE_IPSP_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define BLE_IPSP_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
+#define BLE_IPSP_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define BLE_IPSP_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define BLE_IPSP_ENTRY() BLE_IPSP_TRC(">> %s", __func__)
+#define BLE_IPSP_EXIT() BLE_IPSP_TRC("<< %s", __func__)
+#define BLE_IPSP_EXIT_WITH_RESULT(result) BLE_IPSP_TRC("<< %s, result 0x%08lX", __func__, result)
+
+#else // IOT_BLE_IPSP_CONFIG_LOG_ENABLED
+
+#define BLE_IPSP_TRC(...) /**< Disables traces. */
+#define BLE_IPSP_DUMP(...) /**< Disables dumping of octet streams. */
+#define BLE_IPSP_ERR(...) /**< Disables error logs. */
+
+#define BLE_IPSP_ENTRY(...)
+#define BLE_IPSP_EXIT(...)
+#define BLE_IPSP_EXIT_WITH_RESULT(...)
+
+#endif // IOT_BLE_IPSP_CONFIG_LOG_ENABLED
+
+#define IPSP_ANY_CID 0xFFFE /**< Identifier for any channel. Usage: Search for existing channel on a connection handle. */
+
+/**
+ * @defgroup api_param_check API Parameters check macros.
+ *
+ * @details Macros that verify parameters passed to the module in the APIs. These macros
+ * could be mapped to nothing in final versions of code to save execution and size.
+ * BLE_HPS_DISABLE_API_PARAM_CHECK should be defined to disable these checks.
+ *
+ * @{
+ */
+#if (BLE_IPSP_DISABLE_API_PARAM_CHECK == 0)
+
+/**@brief Macro to check is module is initialized before requesting one of the module procedures. */
+#define VERIFY_MODULE_IS_INITIALIZED() \
+ if (m_evt_handler == NULL) \
+ { \
+ return (NRF_ERROR_MODULE_NOT_INITIALIZED + NRF_ERROR_BLE_IPSP_ERR_BASE); \
+ }
+
+/**@brief Macro to check is module is initialized before requesting one of the module
+ procedures but does not use any return code. */
+#define VERIFY_MODULE_IS_INITIALIZED_VOID() \
+ if (m_evt_handler == NULL) \
+ { \
+ return; \
+ }
+
+/**@brief Verify NULL parameters are not passed to API by application. */
+#define NULL_PARAM_CHECK(PARAM) \
+ if ((PARAM) == NULL) \
+ { \
+ return (NRF_ERROR_NULL + NRF_ERROR_BLE_IPSP_ERR_BASE); \
+ }
+
+/**@brief Verify the connection handle passed to the API. */
+#define VERIFY_CON_HANDLE(CON_HANDLE) \
+ if ((CON_HANDLE) == BLE_CONN_HANDLE_INVALID) \
+ { \
+ return (NRF_ERROR_INVALID_PARAM + NRF_ERROR_BLE_IPSP_ERR_BASE); \
+ }
+
+#else // BLE_IPSP_DISABLE_API_PARAM_CHECK
+
+#define VERIFY_MODULE_IS_INITIALIZED()
+#define VERIFY_MODULE_IS_INITIALIZED_VOID()
+#define NULL_PARAM_CHECK(PARAM)
+#define VERIFY_CON_HANDLE(CON_HANDLE)
+
+#endif //BLE_IPSP_DISABLE_API_PARAM_CHECK
+
+/**
+ * @defgroup ble_ipsp_mutex_lock_unlock Module's Mutex Lock/Unlock Macros.
+ *
+ * @details Macros used to lock and unlock modules. Currently, SDK does not use mutexes but
+ * framework is provided in case the need to use an alternative architecture arises.
+ * @{
+ */
+#define BLE_IPSP_MUTEX_LOCK() SDK_MUTEX_LOCK(m_ipsp_mutex) /**< Lock module using mutex */
+#define BLE_IPSP_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_ipsp_mutex) /**< Unlock module using mutex */
+/** @} */
+
+#define IPSP_MAX_CONNECTED_DEVICES BLE_IPSP_MAX_CHANNELS /**< Table for maximum number of connected devices the module will keep track of. */
+#define RX_BUFFER_TOTAL_SIZE (BLE_IPSP_RX_BUFFER_SIZE * BLE_IPSP_RX_BUFFER_COUNT) /**< Total receive buffer size reserved for each IPSP channel. */
+#define MAX_L2CAP_RX_BUFFER (RX_BUFFER_TOTAL_SIZE * BLE_IPSP_MAX_CHANNELS) /**< Total receive buffer received for all channels. */
+#define INVALID_CHANNEL_INSTANCE 0xFF /**< Indicates channel instance is invalid. */
+
+
+/**@brief IPSP Channel States. */
+typedef enum
+{
+ CHANNEL_IDLE, /**< Indicates the channel is free and not in use. */
+ CHANNEL_CONNECTING, /**< Indicates the channel creation is requested and is awaiting a response. */
+ CHANNEL_CONNECTED, /**< Indicates the channel is connected and ready for data exchange. */
+ CHANNEL_DISCONNECTING /**< Indicates the channel is in the process of being disconnected. */
+} channel_state_t;
+
+
+/**@brief Possible response actions for an incoming channel. Default is to accept. */
+typedef enum
+{
+ INCOMING_CHANNEL_ACCEPT, /**< Indicates that the incoming channel should be accepted if all other criteria are met. */
+ INCOMING_CHANNEL_REJECT /**< Indicates that the incoming channel for IPSP PSM should be rejected regardless of the other criteria. */
+} incoming_channel_action_t;
+
+/**@brief Data type for book keeping connected devices.
+ *
+ * @note Not all connected devices establish an L2CAP connection.
+ */
+typedef struct
+{
+ volatile incoming_channel_action_t response; /**< Indicator if the incoming channel should be accepted or rejected. */
+ ble_gap_addr_t ble_addr; /**< Bluetooth device address of the peer. */
+ uint16_t conn_handle; /**< Connection handle identifying the link with the peer. */
+} peer_connection_t;
+
+
+/**@brief IPSP Channel Information. */
+typedef struct
+{
+ uint16_t conn_handle; /**< Identifies the BLE link on which channel is established. BLE_CONN_HANDLE_INVALID if channel is unassigned. */
+ uint16_t cid; /**< L2CAP channel identifier needed to manage the channel once established. BLE_L2CAP_CID_INVALID if channel is unassigned. */
+ uint16_t rx_buffer_status; /**< Usage status of RX buffers. */
+ uint8_t state; /**< State information for the channel. See @ref channel_state_t for details. */
+ uint8_t * p_rx_buffer; /**< Receive buffer for the channel. */
+} channel_t;
+
+
+static ble_ipsp_evt_handler_t m_evt_handler = NULL; /**< Asynchronous event notification callback registered with the module. */
+static channel_t m_channel[BLE_IPSP_MAX_CHANNELS]; /**< Table of channels managed by the module. */
+static uint8_t m_rx_buffer[MAX_L2CAP_RX_BUFFER]; /**< Receive buffer reserved for all channels to receive data on the L2CAP IPSP channel. */
+static peer_connection_t m_connected_device[IPSP_MAX_CONNECTED_DEVICES]; /**< Table maintaining list of peer devices and the connection handle.
+ \n This information is needed for the 6lowpan compression and decompression.
+ \n And no interface exists to query the softdevice. */
+SDK_MUTEX_DEFINE(m_ipsp_mutex) /**< Mutex variable. Currently unused, this declaration does not occupy any space in RAM. */
+
+
+/**@brief Initialize the peer connected device in the list.
+ *
+ * @param[in] index Identifies the list element to be initialized.
+ */
+static __INLINE void connected_device_init(uint32_t index)
+{
+ memset (&m_connected_device[index].ble_addr, 0, sizeof(ble_gap_addr_t));
+ m_connected_device[index].conn_handle = BLE_CONN_HANDLE_INVALID;
+ m_connected_device[index].response = INCOMING_CHANNEL_ACCEPT;
+}
+
+
+/**@brief Allocate an entry for the peer connected device in the list.
+ *
+ * @param[in] p_peer_addr Pointer to peer's device address.
+ * @param[in] conn_handle Connection handle identifying the link with the peer.
+ */
+static __INLINE void connected_device_allocate(ble_gap_addr_t const * p_peer_addr,
+ uint16_t conn_handle)
+{
+ for (uint32_t index = 0; index < IPSP_MAX_CONNECTED_DEVICES; index++)
+ {
+ if (m_connected_device[index].conn_handle == BLE_CONN_HANDLE_INVALID)
+ {
+ m_connected_device[index].conn_handle = conn_handle;
+ memcpy(m_connected_device[index].ble_addr.addr, p_peer_addr->addr, BLE_GAP_ADDR_LEN);
+ break;
+ }
+ }
+}
+
+
+/**@brief Search for an entry for the peer connected device in the list.
+ *
+ * @param[in] conn_handle Connection handle identifying the link with the peer.
+ *
+ * @retval A valid device index in the list if found, else,
+ * IPSP_MAX_CONNECTED_DEVICES indicating the search failed.
+ */
+static __INLINE uint32_t connected_device_search(uint16_t conn_handle)
+{
+ for (uint32_t index = 0; index < IPSP_MAX_CONNECTED_DEVICES; index++)
+ {
+ if (m_connected_device[index].conn_handle == conn_handle)
+ {
+ return index;
+ }
+ }
+ return IPSP_MAX_CONNECTED_DEVICES;
+}
+
+
+/**@brief Initialize channel.
+ *
+ * @param[in] ch_id Identifies the IPSP channel on which the procedure is requested.
+ */
+static __INLINE void channel_init(uint8_t ch_id)
+{
+ m_channel[ch_id].conn_handle = BLE_CONN_HANDLE_INVALID;
+ m_channel[ch_id].cid = BLE_L2CAP_CID_INVALID;
+ m_channel[ch_id].rx_buffer_status = 0;
+ m_channel[ch_id].state = CHANNEL_IDLE;
+ m_channel[ch_id].p_rx_buffer = &m_rx_buffer[ch_id*RX_BUFFER_TOTAL_SIZE];
+}
+
+
+/**@brief Free channel.
+ *
+ * @param[in] ch_id Identifies the IPSP channel on which the procedure is requested.
+ */
+static __INLINE void channel_free(uint8_t ch_id)
+{
+ BLE_IPSP_TRC("[Index 0x%02X]:[Conn Handle 0x%04X]:[CID 0x%04X]: Freeing channel",
+ ch_id, m_channel[ch_id].conn_handle, m_channel[ch_id].cid);
+
+ channel_init(ch_id);
+}
+
+
+/**@brief Searches the IPSP channel based on connection handle and local L2CAP channel identifier.
+ *
+ * @param[in] conn_handle The connection handle, identifying the peer device.
+ * @param[in] l2cap_cid The local L2CAP channel identifier, identifying the L2CAP channel.
+ * @param[out] p_ch_id The IPSP channel identifier, if the search succeeded, else,
+ * BLE_IPSP_MAX_CHANNELS indicating no IPSP channel was found.
+ */
+static __INLINE uint32_t channel_search(uint16_t conn_handle, uint16_t l2cap_cid, uint8_t * p_ch_id)
+{
+ BLE_IPSP_TRC("[Conn Handle 0x%04X]:[CID 0x%04X]: channel_search",
+ conn_handle, l2cap_cid);
+
+ for (int i = 0; i < BLE_IPSP_MAX_CHANNELS; i++)
+ {
+ BLE_IPSP_TRC("[@ Index 0x%02X] ==> Conn Handle: 0x%04X"
+ " CID : 0x%04X",
+ i, m_channel[i].conn_handle, m_channel[i].cid);
+
+ if (m_channel[i].conn_handle == conn_handle)
+ {
+ if ((l2cap_cid == IPSP_ANY_CID) || (m_channel[i].cid == l2cap_cid))
+ {
+ BLE_IPSP_TRC("channel_search succeeded, index 0x%04X", i);
+
+ *p_ch_id = (uint8_t)i;
+ return NRF_SUCCESS;
+ }
+ }
+ }
+
+ BLE_IPSP_TRC("No matching channel found!");
+ return (NRF_ERROR_BLE_IPSP_ERR_BASE + NRF_ERROR_NOT_FOUND);
+}
+
+
+/**@brief Notify application of an event.
+ *
+ * @param[in] Identifies the IPSP instance for which the event is notified.
+ * @param[in] Describes the notified event and its parameters, if any.
+ */
+static __INLINE void app_notify(ble_ipsp_handle_t * p_handle, ble_ipsp_evt_t * p_event)
+{
+ BLE_IPSP_MUTEX_UNLOCK();
+
+ BLE_IPSP_TRC("[Conn Handle 0x%04X]:[CID 0x%04X]: Notifying application of event 0x%04X",
+ p_handle->conn_handle, p_handle->cid, p_event->evt_id);
+
+ UNUSED_VARIABLE(m_evt_handler(p_handle, p_event));
+
+ BLE_IPSP_MUTEX_LOCK();
+}
+
+
+/**@brief Verifies if the buffer is TX buffer on the channel or not.
+ *
+ * @param[in] ch_id Identifies the IPSP channel for which the procedure is requested.
+ * @param[in] p_buffer Address of the buffer being verified to be TX or not.
+ */
+static __INLINE bool is_tx_buffer(uint32_t ch_id, const uint8_t * p_buffer)
+{
+ // If the buffer is in the RX buffer list, then it is not TX!
+ if ((p_buffer >= (uint8_t *)&m_channel[ch_id].p_rx_buffer) &&
+ (p_buffer < (uint8_t *)&m_channel[ch_id].p_rx_buffer[RX_BUFFER_TOTAL_SIZE]))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+
+/**@brief Submit receive buffers to the softdevice for a channel.
+ *
+ * @param[in] ch_id Identifies the IPSP channel for which the procedure is requested.
+ */
+static __INLINE void rx_buffers_submit(uint32_t ch_id)
+{
+ uint32_t retval;
+
+ for (uint32_t buffer_index = 0; buffer_index < BLE_IPSP_RX_BUFFER_COUNT; buffer_index++)
+ {
+ const ble_data_t sdu_buf =
+ {
+ .p_data = (uint8_t *)&m_channel[ch_id].p_rx_buffer[buffer_index * BLE_IPSP_MTU],
+ .len = BLE_IPSP_MTU
+ };
+
+ if (IS_SET(m_channel[ch_id].rx_buffer_status, buffer_index) == 0)
+ {
+ retval = sd_ble_l2cap_ch_rx(m_channel[ch_id].conn_handle,
+ m_channel[ch_id].cid,
+ &sdu_buf);
+ if (retval == NRF_SUCCESS)
+ {
+ SET_BIT(m_channel[ch_id].rx_buffer_status, buffer_index);
+ }
+ }
+ }
+}
+
+
+/**@brief Mark a receive buffer as not in use for a particular channel.
+ *
+ * @param[in] ch_id Identifies the IPSP channel for which the procedure is requested.
+ * @param[in] p_buffer The buffer to be marked as unused.
+ *
+ * @note This is a temporary state for the receive buffer before it is resubmitted to the SoftDevice.
+ */
+static __INLINE void rx_buffer_mark_unused(uint32_t ch_id, uint8_t * p_buffer)
+{
+ for (uint32_t buffer_index = 0; buffer_index < BLE_IPSP_RX_BUFFER_COUNT; buffer_index++)
+ {
+ if (&m_channel[ch_id].p_rx_buffer[buffer_index * BLE_IPSP_MTU] == p_buffer)
+ {
+ CLR_BIT(m_channel[ch_id].rx_buffer_status, buffer_index);
+ }
+ }
+}
+
+
+void ble_ipsp_evt_handler(ble_evt_t const * p_evt)
+{
+ VERIFY_MODULE_IS_INITIALIZED_VOID();
+
+ ble_ipsp_handle_t handle;
+ ble_ipsp_evt_t ipsp_event;
+ uint32_t retval;
+ uint8_t ch_id;
+ bool notify_event;
+ bool submit_rx_buffer;
+
+ ch_id = INVALID_CHANNEL_INSTANCE;
+ notify_event = false;
+ submit_rx_buffer = false;
+ retval = NRF_SUCCESS;
+ ipsp_event.evt_result = NRF_SUCCESS;
+ handle.conn_handle = BLE_CONN_HANDLE_INVALID;
+ handle.cid = BLE_L2CAP_CID_INVALID;
+
+ BLE_IPSP_TRC("Received BLE Event 0x%04X",p_evt->header.evt_id);
+
+ BLE_IPSP_MUTEX_LOCK();
+
+ switch (p_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ {
+ // Create an entry in the connected devices table.
+ // This is needed to be able to fetch the peer address on IPSP channel establishment.
+ connected_device_allocate(&p_evt->evt.gap_evt.params.connected.peer_addr,
+ p_evt->evt.gap_evt.conn_handle);
+ break;
+ }
+ case BLE_L2CAP_EVT_CH_SETUP_REQUEST:
+ {
+ // This event is generated for the acceptor role and indicates an channel establishment
+ // request from the peer.
+ ble_l2cap_ch_setup_params_t reply_param;
+ uint16_t local_cid;
+
+ memset(&reply_param, 0, sizeof(ble_l2cap_ch_setup_params_t));
+
+ reply_param.le_psm = p_evt->evt.l2cap_evt.params.ch_setup_request.le_psm;
+ reply_param.rx_params.rx_mtu = BLE_IPSP_MTU;
+ reply_param.rx_params.rx_mps = BLE_IPSP_RX_MPS;
+
+ // Check if a channel already exists with the peer.
+ retval = channel_search(p_evt->evt.l2cap_evt.conn_handle,
+ IPSP_ANY_CID,
+ &ch_id);
+
+ BLE_IPSP_TRC("Exiting channel_search result 0x%08X", ch_id);
+
+ if (retval == NRF_SUCCESS)
+ {
+ BLE_IPSP_TRC("Rejecting channel, as IPSP channel already exists "
+ "0x%08X in state 0x%08X", ch_id, m_channel[ch_id].state);
+
+ reply_param.status = BLE_L2CAP_CH_STATUS_CODE_NO_RESOURCES;
+
+ // Reinitialize ch_id to invalid so that existing channel is not impacted.
+ ch_id = INVALID_CHANNEL_INSTANCE;
+ }
+ else
+ {
+ uint32_t peer_device_index = connected_device_search(p_evt->evt.l2cap_evt.conn_handle);
+ local_cid = p_evt->evt.l2cap_evt.local_cid;
+
+ if (p_evt->evt.l2cap_evt.params.ch_setup_request.le_psm != BLE_IPSP_PSM)
+ {
+ reply_param.status = BLE_L2CAP_CH_STATUS_CODE_LE_PSM_NOT_SUPPORTED;
+ BLE_IPSP_TRC("Rejecting L2CAP Channel, unknown PSM %04X!",
+ p_evt->evt.l2cap_evt.params.ch_setup_request.le_psm);
+ }
+ else if ((peer_device_index != IPSP_MAX_CONNECTED_DEVICES) &&
+ (m_connected_device[peer_device_index].response == INCOMING_CHANNEL_REJECT))
+ {
+ reply_param.status = BLE_L2CAP_CH_STATUS_CODE_NO_RESOURCES;
+ BLE_IPSP_ERR("Barred incoming requests by the application. "
+ "Rejecting L2CAP Channel %04X!",
+ p_evt->evt.l2cap_evt.params.ch_setup_request.le_psm);
+ }
+ else if (p_evt->evt.l2cap_evt.params.ch_setup_request.tx_params.tx_mtu < BLE_IPSP_MTU)
+ {
+ reply_param.status = BLE_L2CAP_CH_STATUS_CODE_UNACCEPTABLE_PARAMS;
+ BLE_IPSP_TRC("Rejecting L2CAP Channel, unacceptable TX parameters!");
+ }
+ else
+ {
+ // Peer request acceptable, look for a free channel.
+ retval = channel_search(BLE_CONN_HANDLE_INVALID, BLE_L2CAP_CID_INVALID, &ch_id);
+ BLE_IPSP_TRC("Free channel search result 0x%08X", ch_id);
+
+ if (retval != NRF_SUCCESS)
+ {
+ BLE_IPSP_TRC("Rejecting L2CAP Channel, no resources!");
+ reply_param.status = BLE_L2CAP_CH_STATUS_CODE_NO_RESOURCES;
+ }
+ else
+ {
+ BLE_IPSP_TRC("Accepting L2CAP Channel");
+ reply_param.rx_params.sdu_buf.p_data = NULL;
+ reply_param.rx_params.sdu_buf.len = 0;
+ reply_param.status = BLE_L2CAP_CH_STATUS_CODE_SUCCESS;
+ }
+ }
+ }
+
+ retval = sd_ble_l2cap_ch_setup(p_evt->evt.l2cap_evt.conn_handle,
+ &local_cid,
+ &reply_param);
+
+ BLE_IPSP_TRC("sd_ble_l2cap_ch_setup result = 0x%08lX", retval);
+
+ if ((retval == NRF_SUCCESS) &&
+ (reply_param.status == BLE_L2CAP_CH_STATUS_CODE_SUCCESS) &&
+ (ch_id != INVALID_CHANNEL_INSTANCE))
+ {
+ BLE_IPSP_TRC("[0x%04X][0x%04X]: Channel Connected. Rx MPS = 0x%04X",
+ p_evt->evt.l2cap_evt.conn_handle,
+ p_evt->evt.l2cap_evt.local_cid,
+ reply_param.rx_params.rx_mps);
+
+ ipsp_event.evt_id = BLE_IPSP_EVT_CHANNEL_CONNECTED;
+ ipsp_event.evt_result = NRF_SUCCESS;
+
+ // Channel is assigned to this link.
+ m_channel[ch_id].state = CHANNEL_CONNECTING;
+ m_channel[ch_id].conn_handle = p_evt->evt.l2cap_evt.conn_handle;
+ m_channel[ch_id].cid = local_cid;
+ }
+ else if (ch_id != INVALID_CHANNEL_INSTANCE)
+ {
+ // Free the allocated channel.
+ channel_init(ch_id);
+ }
+ break;
+ }
+ case BLE_L2CAP_EVT_CH_SETUP:
+ {
+ // This event is generated for both initiator and acceptor roles.
+ // This event indicates that the IPSP channel is successfully established.
+ retval = channel_search(p_evt->evt.l2cap_evt.conn_handle,
+ p_evt->evt.l2cap_evt.local_cid,
+ &ch_id);
+
+ if (retval != NRF_SUCCESS)
+ {
+ BLE_IPSP_TRC("Reply on unknown channel, dropping the event.");
+ }
+ else
+ {
+ if (m_channel[ch_id].state == CHANNEL_CONNECTING)
+ {
+ // Channel created successfully.
+
+ // Initialize IPSP handle.
+ handle.conn_handle = p_evt->evt.l2cap_evt.conn_handle;
+ handle.cid = p_evt->evt.l2cap_evt.local_cid;
+
+ // Initialize the event.
+ ipsp_event.evt_id = BLE_IPSP_EVT_CHANNEL_CONNECTED;
+ ipsp_event.evt_result = NRF_SUCCESS;
+
+ // Set the channel state appropriately.
+ m_channel[ch_id].state = CHANNEL_CONNECTED;
+
+ // Set the flag to trigger submission of the receive buffers to the softdevice.
+ submit_rx_buffer = true;
+
+ // Notify the event to the application.
+ notify_event = true;
+ }
+ }
+ break;
+ }
+ case BLE_L2CAP_EVT_CH_SETUP_REFUSED:
+ {
+ // This event is generated for both initiator and acceptor roles.
+ // This event indicates that the IPSP channel establishment failed.
+ retval = channel_search(p_evt->evt.l2cap_evt.conn_handle,
+ p_evt->evt.l2cap_evt.local_cid,
+ &ch_id);
+
+ if (retval != NRF_SUCCESS)
+ {
+ BLE_IPSP_TRC("Reply on unknown channel, dropping the event.");
+ }
+ else
+ {
+ if (m_channel[ch_id].state == CHANNEL_CONNECTING)
+ {
+ // Channel creation failed as peer rejected the connection.
+
+ // Initialize the event.
+ ipsp_event.evt_id = BLE_IPSP_EVT_CHANNEL_CONNECTED;
+ ipsp_event.evt_result = NRF_ERROR_BLE_IPSP_PEER_REJECTED;
+
+ BLE_IPSP_ERR("Peer rejected channel creation request, reason %d",
+ p_evt->evt.l2cap_evt.params.ch_setup_refused.status);
+
+ // Free the channel.
+ channel_free(ch_id);
+
+ // Notify the event to the application.
+ notify_event = true;
+ }
+ }
+ break;
+ }
+ case BLE_L2CAP_EVT_CH_RELEASED:
+ {
+ BLE_IPSP_TRC("L2CAP Channel disconnected.");
+
+ ipsp_event.evt_id = BLE_IPSP_EVT_CHANNEL_DISCONNECTED;
+
+ retval = channel_search(p_evt->evt.l2cap_evt.conn_handle,
+ p_evt->evt.l2cap_evt.local_cid,
+ &ch_id);
+
+ // Notify application of disconnection.
+ if (retval == NRF_SUCCESS)
+ {
+ handle.conn_handle = p_evt->evt.l2cap_evt.conn_handle;
+ handle.cid = p_evt->evt.l2cap_evt.local_cid;
+
+ channel_free(ch_id);
+
+ // Notify the event to the application.
+ notify_event = true;
+ }
+ break;
+ }
+ case BLE_L2CAP_EVT_CH_RX:
+ {
+ ipsp_event.evt_id = BLE_IPSP_EVT_CHANNEL_DATA_RX;
+
+ retval = channel_search(p_evt->evt.l2cap_evt.conn_handle,
+ p_evt->evt.l2cap_evt.local_cid,
+ &ch_id);
+
+ if (retval == NRF_SUCCESS)
+ {
+ handle.conn_handle = p_evt->evt.l2cap_evt.conn_handle;
+ handle.cid = p_evt->evt.l2cap_evt.local_cid;
+
+ rx_buffer_mark_unused(ch_id, p_evt->evt.l2cap_evt.params.rx.sdu_buf.p_data);
+
+ // Set the flag to trigger submission of the receive buffers to the softdevice.
+ submit_rx_buffer = true;
+
+ // Notify the event to the application.
+ notify_event = true;
+ }
+ break;
+ }
+ case BLE_L2CAP_EVT_CH_TX:
+ {
+ BLE_IPSP_TRC("BLE_L2CAP_EVT_CH_TX --> p_sdu_buf = %p, p_sdu_buf.p_data = %p",
+ &p_evt->evt.l2cap_evt.params.tx.sdu_buf, p_evt->evt.l2cap_evt.params.tx.sdu_buf.p_data);
+
+ retval = channel_search(p_evt->evt.l2cap_evt.conn_handle,
+ p_evt->evt.l2cap_evt.local_cid,
+ &ch_id);
+
+ if ((ch_id != INVALID_CHANNEL_INSTANCE) &&
+ p_evt->evt.l2cap_evt.local_cid == m_channel[ch_id].cid)
+ {
+ // Initialize the event.
+ ipsp_event.evt_id = BLE_IPSP_EVT_CHANNEL_DATA_TX_COMPLETE;
+
+ // Initialize the handle.
+ handle.conn_handle = m_channel[ch_id].conn_handle;
+ handle.cid = m_channel[ch_id].cid;
+
+ // Notify the event to the application.
+ notify_event = true;
+ }
+ break;
+ }
+ case BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED:
+ {
+ BLE_IPSP_TRC("BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED --> p_sdu_buf = %p, p_sdu_buf.p_data = %p",
+ &p_evt->evt.l2cap_evt.params.ch_sdu_buf_released.sdu_buf,
+ p_evt->evt.l2cap_evt.params.ch_sdu_buf_released.sdu_buf.p_data);
+
+ retval = channel_search(p_evt->evt.l2cap_evt.conn_handle,
+ p_evt->evt.l2cap_evt.local_cid,
+ &ch_id);
+
+ if ((ch_id != INVALID_CHANNEL_INSTANCE) &&
+ (p_evt->evt.l2cap_evt.local_cid == m_channel[ch_id].cid) &&
+ (is_tx_buffer(ch_id, p_evt->evt.l2cap_evt.params.ch_sdu_buf_released.sdu_buf.p_data)))
+ {
+ // Initialize the event.
+ ipsp_event.evt_id = BLE_IPSP_EVT_CHANNEL_DATA_TX_COMPLETE;
+ ipsp_event.evt_result = NRF_ERROR_BLE_IPSP_LINK_DISCONNECTED;
+
+ // Initialize the handle.
+ handle.conn_handle = m_channel[ch_id].conn_handle;
+ handle.cid = m_channel[ch_id].cid;
+
+ // Notify the event to the application.
+ notify_event = true;
+ }
+ break;
+ }
+ case BLE_GAP_EVT_DISCONNECTED:
+ {
+ uint32_t peer_device_index = connected_device_search(handle.conn_handle);
+ if (peer_device_index < IPSP_MAX_CONNECTED_DEVICES)
+ {
+ connected_device_init(peer_device_index);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (notify_event)
+ {
+ ble_ipsp_event_param_t event_param;
+ uint32_t peer_device_index;
+
+ peer_device_index = connected_device_search(handle.conn_handle);
+
+ if (peer_device_index < IPSP_MAX_CONNECTED_DEVICES)
+ {
+ event_param.p_peer = &m_connected_device[peer_device_index].ble_addr;
+ BLE_IPSP_TRC("Found peer device. Address type = 0x%02x",
+ event_param.p_peer->addr_type);
+ BLE_IPSP_DUMP((uint8_t *)event_param.p_peer->addr, 6);
+ }
+ else
+ {
+ event_param.p_peer = NULL;
+ }
+
+ event_param.p_l2cap_evt = &p_evt->evt.l2cap_evt;
+ ipsp_event.p_evt_param = &event_param;
+
+ app_notify(&handle, &ipsp_event);
+ }
+
+ // Trigger submission of the receive buffers to the softdevice.
+ if (submit_rx_buffer)
+ {
+ rx_buffers_submit(ch_id);
+ }
+
+ BLE_IPSP_MUTEX_UNLOCK();
+ UNUSED_VARIABLE(retval);
+}
+
+
+uint32_t ble_ipsp_init(const ble_ipsp_init_t * p_init)
+{
+ BLE_IPSP_ENTRY();
+
+ ble_uuid_t ble_uuid;
+ uint32_t err_code;
+ uint16_t handle;
+
+ NULL_PARAM_CHECK(p_init);
+ NULL_PARAM_CHECK(p_init->evt_handler);
+
+ SDK_MUTEX_INIT(m_ipsp_mutex);
+
+ BLE_IPSP_MUTEX_LOCK();
+
+ // Add service to indicate IPSP support.
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_IPSP_SERVICE);
+
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &handle);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ m_evt_handler = p_init->evt_handler;
+
+ // Initialize the channel.
+ for (int i = 0; i < BLE_IPSP_MAX_CHANNELS; i++)
+ {
+ channel_init(i);
+ }
+
+ // Initialize the connected peer device table.
+ for (int i = 0; i < IPSP_MAX_CONNECTED_DEVICES; i++)
+ {
+ connected_device_init(i);
+ }
+ BLE_IPSP_MUTEX_UNLOCK();
+
+ BLE_IPSP_EXIT();
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_ipsp_connect(const ble_ipsp_handle_t * p_handle)
+{
+ VERIFY_MODULE_IS_INITIALIZED();
+ NULL_PARAM_CHECK(p_handle);
+ VERIFY_CON_HANDLE(p_handle->conn_handle);
+
+ uint32_t err_code;
+ uint8_t ch_id = INVALID_CHANNEL_INSTANCE;
+
+ BLE_IPSP_TRC("[Conn Handle 0x%04X]: >> ble_ipsp_connect",
+ p_handle->conn_handle);
+
+ BLE_IPSP_MUTEX_LOCK();
+
+ // Check if channel already exists with the peer.
+ err_code = channel_search(p_handle->conn_handle, IPSP_ANY_CID, &ch_id);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // IPSP channel already exists.
+ err_code = NRF_ERROR_BLE_IPSP_CHANNEL_ALREADY_EXISTS;
+ }
+ else
+ {
+ // Search for a free channel.
+ err_code = channel_search(BLE_CONN_HANDLE_INVALID, BLE_L2CAP_CID_INVALID, &ch_id);
+ BLE_IPSP_TRC("2 channel_search result %08X", err_code);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ m_channel[ch_id].state = CHANNEL_CONNECTING;
+
+ ble_l2cap_ch_setup_params_t param =
+ {
+ .le_psm = BLE_IPSP_PSM,
+ .rx_params = {
+ .rx_mtu = BLE_IPSP_MTU,
+ .rx_mps = BLE_IPSP_RX_MPS,
+ .sdu_buf =
+ {
+ .p_data = NULL,
+ .len = 0
+ }
+ }
+ };
+ BLE_IPSP_TRC("Requesting sd_ble_l2cap_ch_setup");
+
+ err_code = sd_ble_l2cap_ch_setup(p_handle->conn_handle,
+ &m_channel[ch_id].cid,
+ &param);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ BLE_IPSP_ERR("sd_ble_l2cap_ch_conn_request failed, reason %08lX", err_code);
+ channel_free(ch_id);
+ }
+ else
+ {
+ BLE_IPSP_TRC("Local channel id from SD %04X.", m_channel[ch_id].cid);
+ m_channel[ch_id].conn_handle = p_handle->conn_handle;
+ }
+ }
+ else
+ {
+ err_code = (NRF_ERROR_BLE_IPSP_ERR_BASE + NRF_ERROR_NO_MEM);
+ }
+ }
+
+ BLE_IPSP_MUTEX_UNLOCK();
+
+ BLE_IPSP_EXIT_WITH_RESULT(err_code);
+
+ return err_code;
+}
+
+
+uint32_t ble_ipsp_send(ble_ipsp_handle_t const * p_handle,
+ uint8_t const * p_data,
+ uint16_t data_len)
+{
+ BLE_IPSP_ENTRY();
+
+ VERIFY_MODULE_IS_INITIALIZED();
+ NULL_PARAM_CHECK(p_handle);
+ NULL_PARAM_CHECK(p_data);
+ VERIFY_CON_HANDLE(p_handle->conn_handle);
+
+ uint32_t err_code;
+ uint8_t ch_id;
+
+ BLE_IPSP_MUTEX_LOCK();
+
+ err_code = channel_search(p_handle->conn_handle, p_handle->cid, &ch_id);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ const ble_data_t p_sdu_buf =
+ {
+ .p_data = (uint8_t *)p_data,
+ .len = data_len
+ };
+
+ BLE_IPSP_TRC("p_sdu_buf = %p, p_sdu_buf.p_data = %p",
+ &p_sdu_buf, p_data);
+
+ err_code = sd_ble_l2cap_ch_tx(p_handle->conn_handle,
+ p_handle->cid,
+ &p_sdu_buf);
+ }
+
+ BLE_IPSP_MUTEX_UNLOCK();
+
+ BLE_IPSP_EXIT_WITH_RESULT(err_code);
+
+ return err_code;
+}
+
+
+uint32_t ble_ipsp_disconnect(ble_ipsp_handle_t const * p_handle)
+{
+ BLE_IPSP_ENTRY();
+
+ VERIFY_MODULE_IS_INITIALIZED();
+ NULL_PARAM_CHECK(p_handle);
+ VERIFY_CON_HANDLE(p_handle->conn_handle);
+
+ uint32_t err_code;
+ uint8_t ch_id;
+
+ BLE_IPSP_MUTEX_LOCK();
+
+ err_code = channel_search(p_handle->conn_handle, p_handle->cid, &ch_id);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ m_channel[ch_id].state = CHANNEL_DISCONNECTING;
+
+ err_code = sd_ble_l2cap_ch_release(p_handle->conn_handle,
+ p_handle->cid);
+ }
+
+ BLE_IPSP_MUTEX_UNLOCK();
+
+ BLE_IPSP_EXIT_WITH_RESULT(err_code);
+
+ return err_code;
+}
+
+
+void ble_ipsp_incoming_channel_reject(uint16_t conn_handle)
+{
+ uint32_t peer_device_index = connected_device_search(conn_handle);
+
+ if (peer_device_index != IPSP_MAX_CONNECTED_DEVICES)
+ {
+ m_connected_device[peer_device_index].response = INCOMING_CHANNEL_REJECT;
+ }
+}
+
+
+void ble_ipsp_incoming_channel_accept(uint16_t conn_handle)
+{
+ uint32_t peer_device_index = connected_device_search(conn_handle);
+
+ if (peer_device_index != IPSP_MAX_CONNECTED_DEVICES)
+ {
+ m_connected_device[peer_device_index].response = INCOMING_CHANNEL_ACCEPT;
+ }
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ipsp/ble_ipsp.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ipsp/ble_ipsp.h
new file mode 100644
index 0000000..d8edcbd
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_ipsp/ble_ipsp.h
@@ -0,0 +1,253 @@
+/**
+ * Copyright (c) 2014 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_ipsp Internet Protocol Support Profile
+ * @{
+ * @ingroup iot_sdk_6lowpan
+ * @brief Internet Protocol Support Profile.
+ *
+ * @details This module implements the Internet Protocol Support Profile creating and managing
+ * transport for 6lowpan.
+ * GATT is used to discover if IPSP is supported or not, but no IP data is exchanged
+ * over GATT. To exchange data, LE L2CAP Credit Mode is used. The PSM used for the channel
+ * is BLE_IPSP_PSM and is defined by the specification. The MTU mandated by the
+ * specification is 1280 bytes.
+ *
+ * @note Attention!
+ * To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+
+#ifndef BLE_IPSP_H__
+#define BLE_IPSP_H__
+
+#include <stdint.h>
+#include "ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Maximum IPSP channels required to be supported. */
+#define BLE_IPSP_MAX_CHANNELS 1
+
+/**@brief Maximum Transmit Unit on IPSP channel. */
+#define BLE_IPSP_MTU 1280
+
+/**@brief Receive MPS used by IPSP. */
+#define BLE_IPSP_RX_MPS 50
+
+/**@brief Transmission MPS used by IPSP.
+ *
+ * @note The actual MPS used is minimum of this value and the one requested by
+ * the peer during the channel setup. Here, the value used is
+ * (23 + 27 * 7).
+ */
+#define BLE_IPSP_TX_MPS 212
+
+/**@brief Maximum data size that can be received.
+ *
+ * @details Maximum data size that can be received on the IPSP channel.
+ * Modify this values to intentionally set a receive size less
+ * than the MTU set on the channel.
+ */
+#define BLE_IPSP_RX_BUFFER_SIZE 1280
+
+/**@brief Maximum number of receive buffers.
+ *
+ * @details Maximum number of receive buffers to be used per IPSP channel.
+ * Each receive buffer is of size @ref BLE_IPSP_RX_BUFFER_SIZE.
+ * This configuration has implications on the number of SDUs that can
+ * be received while an SDU is being consumed by the application
+ * (6LoWPAN/IP Stack).
+ */
+#define BLE_IPSP_RX_BUFFER_COUNT 4
+
+/**@brief L2CAP Protocol Service Multiplexers number. */
+#define BLE_IPSP_PSM 0x0023
+
+
+/**@brief IPSP event identifier type. */
+typedef enum
+{
+ BLE_IPSP_EVT_CHANNEL_CONNECTED, /**< Channel connection event. */
+ BLE_IPSP_EVT_CHANNEL_DISCONNECTED, /**< Channel disconnection event. */
+ BLE_IPSP_EVT_CHANNEL_DATA_RX, /**< Data received on channel event. */
+ BLE_IPSP_EVT_CHANNEL_DATA_TX_COMPLETE /**< Requested data transmission complete on channel event. */
+} ble_ipsp_evt_type_t;
+
+
+/**@brief IPSP event parameter. */
+typedef struct
+{
+ ble_l2cap_evt_t const * p_l2cap_evt; /**< L2CAP event parameters. */
+ ble_gap_addr_t const * p_peer; /**< Peer device address. */
+} ble_ipsp_event_param_t;
+
+
+/**@brief IPSP event and associated parameter type. */
+typedef struct
+{
+ ble_ipsp_evt_type_t evt_id; /**< Identifier event type. */
+ ble_ipsp_event_param_t * p_evt_param; /**< Parameters associated with the event. */
+ uint32_t evt_result; /**< Result of the event.
+ \n The event result is SDK_ERR_RX_PKT_TRUNCATED for @ref BLE_IPSP_EVT_CHANNEL_DATA_RX,
+ \n implies that an incomplete SDU was received due to insufficient RX buffer size.
+ \n The size determined by @ref BLE_IPSP_RX_BUFFER_SIZE. */
+} ble_ipsp_evt_t;
+
+
+/**@brief IPSP handle. */
+typedef struct
+{
+ uint16_t conn_handle; /**< Identifies the link on which the IPSP channel is established. */
+ uint16_t cid; /**< Identifies the IPSP logical channel. */
+} ble_ipsp_handle_t;
+
+
+/**@brief Profile event handler type.
+ *
+ * @param[in] p_handle Identifies the connection and channel on which the event occurred.
+ * @param[in] p_evt Event and related parameters (if any).
+ *
+ * @returns Provision for the application to indicate if the event was successfully processed or
+ * not. Currently not used.
+ */
+typedef uint32_t (*ble_ipsp_evt_handler_t) (ble_ipsp_handle_t const * p_handle,
+ ble_ipsp_evt_t const * p_evt);
+
+
+/**@brief IPSP initialization structure.
+ *
+ * @details IPSP initialization structure containing all options and data needed to
+ * initialize the profile.
+ */
+typedef struct
+{
+ ble_ipsp_evt_handler_t evt_handler; /**< Event notification callback registered with the module to receive asynchronous events. */
+} ble_ipsp_init_t;
+
+
+/**@brief Function for initializing the Internet Protocol Support Profile.
+ *
+ * @param[in] p_init Information needed to initialize the service.
+ *
+ * @retval NRF_SUCCESS If initialization of the service was successful, else,
+ * an error code indicating reason for failure.
+ */
+uint32_t ble_ipsp_init(ble_ipsp_init_t const * p_init);
+
+
+/**@brief Function for requesting a channel creation for the Internet Protocol Support Profile.
+ *
+ * @details Channel creation for Internet Protocol Support Profile (IPSP) is requested using this
+ * API. Connection handle provided in p_handle parameter identifies the peer with which
+ * the IPSP channel is being requested.
+ * NRF_SUCCESS return value by the API is only indicative of request procedure having
+ * succeeded. Result of channel establishment is known when the
+ * @ref BLE_IPSP_EVT_CHANNEL_CONNECTED event is notified.
+ * Therefore, the application must wait for @ref BLE_IPSP_EVT_CHANNEL_CONNECTED event on
+ * successful return of this API.
+ *
+ * @param[in] p_handle Indicates the connection handle on which IPSP channel is to be created.
+ *
+ * @retval NRF_SUCCESS If initialization of the service was successful, else,
+ * an error code indicating reason for failure.
+ */
+uint32_t ble_ipsp_connect(ble_ipsp_handle_t const * p_handle);
+
+
+/**@brief Function for sending IP data to peer.
+ *
+ * @param[in] p_handle Instance of the logical channel and peer for which the data is intended.
+ * @param[in] p_data Pointer to memory containing the data to be transmitted.
+ * @note This memory must be resident and should not be freed unless
+ * @ref BLE_IPSP_EVT_CHANNEL_DATA_TX_COMPLETE event is notified.
+ * @param[in] data_len Length/size of data to be transferred.
+ *
+ * @retval NRF_SUCCESS If initialization of the service was successful, else,
+ * an error code indicating reason for failure.
+ */
+uint32_t ble_ipsp_send(ble_ipsp_handle_t const * p_handle,
+ uint8_t const * p_data,
+ uint16_t data_len);
+
+
+/**@brief Function for disconnecting IP transport.
+ *
+ * @param[in] p_handle Identifies IPSP transport.
+ *
+ * @retval NRF_SUCCESS If initialization of the service was successful, else,
+ * an error code indicating reason for failure.
+ */
+uint32_t ble_ipsp_disconnect(ble_ipsp_handle_t const * p_handle);
+
+
+/**@brief Function to accept incoming connections from a peer.
+ *
+ * @param[in] conn_handle Identifies the link with the peer.
+ */
+void ble_ipsp_incoming_channel_accept(uint16_t conn_handle);
+
+
+/**@brief Function to reject incoming connections from a peer.
+ *
+ * @param[in] conn_handle Identifies the link with the peer.
+ */
+void ble_ipsp_incoming_channel_reject(uint16_t conn_handle);
+
+
+/**@brief BLE event handler of the module.
+ *
+ * @param[in] p_evt BLE event to be handled.
+ *
+ * @retval NRF_SUCCESS If initialization of the service was successful, else,
+ * an error code indicating reason for failure.
+ */
+void ble_ipsp_evt_handler(ble_evt_t const * p_evt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_IPSP_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lbs/ble_lbs.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lbs/ble_lbs.c
new file mode 100644
index 0000000..09adc92
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lbs/ble_lbs.c
@@ -0,0 +1,235 @@
+/**
+ * Copyright (c) 2013 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_LBS)
+#include "ble_lbs.h"
+#include "ble_srv_common.h"
+
+
+/**@brief Function for handling the Write event.
+ *
+ * @param[in] p_lbs LED Button Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_write(ble_lbs_t * p_lbs, ble_evt_t const * p_ble_evt)
+{
+ ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+ if ( (p_evt_write->handle == p_lbs->led_char_handles.value_handle)
+ && (p_evt_write->len == 1)
+ && (p_lbs->led_write_handler != NULL))
+ {
+ p_lbs->led_write_handler(p_ble_evt->evt.gap_evt.conn_handle, p_lbs, p_evt_write->data[0]);
+ }
+}
+
+
+void ble_lbs_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ ble_lbs_t * p_lbs = (ble_lbs_t *)p_context;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GATTS_EVT_WRITE:
+ on_write(p_lbs, p_ble_evt);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+
+/**@brief Function for adding the LED Characteristic.
+ *
+ * @param[in] p_lbs LED Button Service structure.
+ * @param[in] p_lbs_init LED Button Service initialization structure.
+ *
+ * @retval NRF_SUCCESS on success, else an error value from the SoftDevice
+ */
+static uint32_t led_char_add(ble_lbs_t * p_lbs, const ble_lbs_init_t * p_lbs_init)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.char_props.write = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = NULL;
+ char_md.p_sccd_md = NULL;
+
+ ble_uuid.type = p_lbs->uuid_type;
+ ble_uuid.uuid = LBS_UUID_LED_CHAR;
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = sizeof(uint8_t);
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = sizeof(uint8_t);
+ attr_char_value.p_value = NULL;
+
+ return sd_ble_gatts_characteristic_add(p_lbs->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_lbs->led_char_handles);
+}
+
+
+/**@brief Function for adding the Button Characteristic.
+ *
+ * @param[in] p_lbs LED Button Service structure.
+ * @param[in] p_lbs_init LED Button Service initialization structure.
+ *
+ * @retval NRF_SUCCESS on success, else an error value from the SoftDevice
+ */
+static uint32_t button_char_add(ble_lbs_t * p_lbs, const ble_lbs_init_t * p_lbs_init)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_md_t cccd_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+
+ memset(&cccd_md, 0, sizeof(cccd_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
+ cccd_md.vloc = BLE_GATTS_VLOC_STACK;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.char_props.notify = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = &cccd_md;
+ char_md.p_sccd_md = NULL;
+
+ ble_uuid.type = p_lbs->uuid_type;
+ ble_uuid.uuid = LBS_UUID_BUTTON_CHAR;
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = sizeof(uint8_t);
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = sizeof(uint8_t);
+ attr_char_value.p_value = NULL;
+
+ return sd_ble_gatts_characteristic_add(p_lbs->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_lbs->button_char_handles);
+}
+
+
+uint32_t ble_lbs_init(ble_lbs_t * p_lbs, const ble_lbs_init_t * p_lbs_init)
+{
+ uint32_t err_code;
+ ble_uuid_t ble_uuid;
+
+ // Initialize service structure.
+ p_lbs->led_write_handler = p_lbs_init->led_write_handler;
+
+ // Add service.
+ ble_uuid128_t base_uuid = {LBS_UUID_BASE};
+ err_code = sd_ble_uuid_vs_add(&base_uuid, &p_lbs->uuid_type);
+ VERIFY_SUCCESS(err_code);
+
+ ble_uuid.type = p_lbs->uuid_type;
+ ble_uuid.uuid = LBS_UUID_SERVICE;
+
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_lbs->service_handle);
+ VERIFY_SUCCESS(err_code);
+
+ // Add characteristics.
+ err_code = button_char_add(p_lbs, p_lbs_init);
+ VERIFY_SUCCESS(err_code);
+
+ err_code = led_char_add(p_lbs, p_lbs_init);
+ VERIFY_SUCCESS(err_code);
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_lbs_on_button_change(uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t button_state)
+{
+ ble_gatts_hvx_params_t params;
+ uint16_t len = sizeof(button_state);
+
+ memset(&params, 0, sizeof(params));
+ params.type = BLE_GATT_HVX_NOTIFICATION;
+ params.handle = p_lbs->button_char_handles.value_handle;
+ params.p_data = &button_state;
+ params.p_len = &len;
+
+ return sd_ble_gatts_hvx(conn_handle, &params);
+}
+#endif // NRF_MODULE_ENABLED(BLE_LBS)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lbs/ble_lbs.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lbs/ble_lbs.h
new file mode 100644
index 0000000..5791698
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lbs/ble_lbs.h
@@ -0,0 +1,161 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_lbs LED Button Service Server
+ * @{
+ * @ingroup ble_sdk_srv
+ *
+ * @brief LED Button Service Server module.
+ *
+ * @details This module implements a custom LED Button Service with an LED and Button Characteristics.
+ * During initialization, the module adds the LED Button Service and Characteristics
+ * to the BLE stack database.
+ *
+ * The application must supply an event handler for receiving LED Button Service
+ * events. Using this handler, the service notifies the application when the
+ * LED value changes.
+ *
+ * The service also provides a function for letting the application notify
+ * the state of the Button Characteristic to connected peers.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_hids_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_HIDS_BLE_OBSERVER_PRIO,
+ * ble_hids_on_ble_evt, &instance);
+ * @endcode
+ */
+
+#ifndef BLE_LBS_H__
+#define BLE_LBS_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "nrf_sdh_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_lbs instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_LBS_DEF(_name) \
+static ble_lbs_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_LBS_BLE_OBSERVER_PRIO, \
+ ble_lbs_on_ble_evt, &_name)
+
+#define LBS_UUID_BASE {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, \
+ 0xDE, 0xEF, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00}
+#define LBS_UUID_SERVICE 0x1523
+#define LBS_UUID_BUTTON_CHAR 0x1524
+#define LBS_UUID_LED_CHAR 0x1525
+
+
+// Forward declaration of the ble_lbs_t type.
+typedef struct ble_lbs_s ble_lbs_t;
+
+typedef void (*ble_lbs_led_write_handler_t) (uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t new_state);
+
+/** @brief LED Button Service init structure. This structure contains all options and data needed for
+ * initialization of the service.*/
+typedef struct
+{
+ ble_lbs_led_write_handler_t led_write_handler; /**< Event handler to be called when the LED Characteristic is written. */
+} ble_lbs_init_t;
+
+/**@brief LED Button Service structure. This structure contains various status information for the service. */
+struct ble_lbs_s
+{
+ uint16_t service_handle; /**< Handle of LED Button Service (as provided by the BLE stack). */
+ ble_gatts_char_handles_t led_char_handles; /**< Handles related to the LED Characteristic. */
+ ble_gatts_char_handles_t button_char_handles; /**< Handles related to the Button Characteristic. */
+ uint8_t uuid_type; /**< UUID type for the LED Button Service. */
+ ble_lbs_led_write_handler_t led_write_handler; /**< Event handler to be called when the LED Characteristic is written. */
+};
+
+
+/**@brief Function for initializing the LED Button Service.
+ *
+ * @param[out] p_lbs LED Button Service structure. This structure must be supplied by
+ * the application. It is initialized by this function and will later
+ * be used to identify this particular service instance.
+ * @param[in] p_lbs_init Information needed to initialize the service.
+ *
+ * @retval NRF_SUCCESS If the service was initialized successfully. Otherwise, an error code is returned.
+ */
+uint32_t ble_lbs_init(ble_lbs_t * p_lbs, const ble_lbs_init_t * p_lbs_init);
+
+
+/**@brief Function for handling the application's BLE stack events.
+ *
+ * @details This function handles all events from the BLE stack that are of interest to the LED Button Service.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context LED Button Service structure.
+ */
+void ble_lbs_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for sending a button state notification.
+ *
+ ' @param[in] conn_handle Handle of the peripheral connection to which the button state notification will be sent.
+ * @param[in] p_lbs LED Button Service structure.
+ * @param[in] button_state New button state.
+ *
+ * @retval NRF_SUCCESS If the notification was sent successfully. Otherwise, an error code is returned.
+ */
+uint32_t ble_lbs_on_button_change(uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t button_state);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_LBS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lbs_c/ble_lbs_c.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lbs_c/ble_lbs_c.c
new file mode 100644
index 0000000..10d8dc6
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lbs_c/ble_lbs_c.c
@@ -0,0 +1,394 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_LBS_C)
+
+#include "ble_lbs_c.h"
+#include "ble_db_discovery.h"
+#include "ble_types.h"
+#include "ble_srv_common.h"
+#include "ble_gattc.h"
+#define NRF_LOG_MODULE_NAME ble_lbs_c
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define TX_BUFFER_MASK 0x07 /**< TX Buffer mask, must be a mask of continuous zeroes, followed by continuous sequence of ones: 000...111. */
+#define TX_BUFFER_SIZE (TX_BUFFER_MASK + 1) /**< Size of send buffer, which is 1 higher than the mask. */
+
+#define WRITE_MESSAGE_LENGTH BLE_CCCD_VALUE_LEN /**< Length of the write message for CCCD. */
+#define WRITE_MESSAGE_LENGTH BLE_CCCD_VALUE_LEN /**< Length of the write message for CCCD. */
+
+typedef enum
+{
+ READ_REQ, /**< Type identifying that this tx_message is a read request. */
+ WRITE_REQ /**< Type identifying that this tx_message is a write request. */
+} tx_request_t;
+
+/**@brief Structure for writing a message to the peer, i.e. CCCD.
+ */
+typedef struct
+{
+ uint8_t gattc_value[WRITE_MESSAGE_LENGTH]; /**< The message to write. */
+ ble_gattc_write_params_t gattc_params; /**< GATTC parameters for this message. */
+} write_params_t;
+
+/**@brief Structure for holding data to be transmitted to the connected central.
+ */
+typedef struct
+{
+ uint16_t conn_handle; /**< Connection handle to be used when transmitting this message. */
+ tx_request_t type; /**< Type of this message, i.e. read or write message. */
+ union
+ {
+ uint16_t read_handle; /**< Read request message. */
+ write_params_t write_req; /**< Write request message. */
+ } req;
+} tx_message_t;
+
+
+static tx_message_t m_tx_buffer[TX_BUFFER_SIZE]; /**< Transmit buffer for messages to be transmitted to the central. */
+static uint32_t m_tx_insert_index = 0; /**< Current index in the transmit buffer where the next message should be inserted. */
+static uint32_t m_tx_index = 0; /**< Current index in the transmit buffer from where the next message to be transmitted resides. */
+
+
+/**@brief Function for passing any pending request from the buffer to the stack.
+ */
+static void tx_buffer_process(void)
+{
+ if (m_tx_index != m_tx_insert_index)
+ {
+ uint32_t err_code;
+
+ if (m_tx_buffer[m_tx_index].type == READ_REQ)
+ {
+ err_code = sd_ble_gattc_read(m_tx_buffer[m_tx_index].conn_handle,
+ m_tx_buffer[m_tx_index].req.read_handle,
+ 0);
+ }
+ else
+ {
+ err_code = sd_ble_gattc_write(m_tx_buffer[m_tx_index].conn_handle,
+ &m_tx_buffer[m_tx_index].req.write_req.gattc_params);
+ }
+ if (err_code == NRF_SUCCESS)
+ {
+ NRF_LOG_DEBUG("SD Read/Write API returns Success..");
+ m_tx_index++;
+ m_tx_index &= TX_BUFFER_MASK;
+ }
+ else
+ {
+ NRF_LOG_DEBUG("SD Read/Write API returns error. This message sending will be "
+ "attempted again..");
+ }
+ }
+}
+
+
+/**@brief Function for handling write response events.
+ *
+ * @param[in] p_ble_lbs_c Pointer to the Led Button Client structure.
+ * @param[in] p_ble_evt Pointer to the BLE event received.
+ */
+static void on_write_rsp(ble_lbs_c_t * p_ble_lbs_c, ble_evt_t const * p_ble_evt)
+{
+ // Check if the event if on the link for this instance
+ if (p_ble_lbs_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
+ {
+ return;
+ }
+ // Check if there is any message to be sent across to the peer and send it.
+ tx_buffer_process();
+}
+
+
+/**@brief Function for handling Handle Value Notification received from the SoftDevice.
+ *
+ * @details This function will uses the Handle Value Notification received from the SoftDevice
+ * and checks if it is a notification of Button state from the peer. If
+ * it is, this function will decode the state of the button and send it to the
+ * application.
+ *
+ * @param[in] p_ble_lbs_c Pointer to the Led Button Client structure.
+ * @param[in] p_ble_evt Pointer to the BLE event received.
+ */
+static void on_hvx(ble_lbs_c_t * p_ble_lbs_c, ble_evt_t const * p_ble_evt)
+{
+ // Check if the event is on the link for this instance
+ if (p_ble_lbs_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
+ {
+ return;
+ }
+ // Check if this is a Button notification.
+ if (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_lbs_c->peer_lbs_db.button_handle)
+ {
+ if (p_ble_evt->evt.gattc_evt.params.hvx.len == 1)
+ {
+ ble_lbs_c_evt_t ble_lbs_c_evt;
+
+ ble_lbs_c_evt.evt_type = BLE_LBS_C_EVT_BUTTON_NOTIFICATION;
+ ble_lbs_c_evt.conn_handle = p_ble_lbs_c->conn_handle;
+ ble_lbs_c_evt.params.button.button_state = p_ble_evt->evt.gattc_evt.params.hvx.data[0];
+ p_ble_lbs_c->evt_handler(p_ble_lbs_c, &ble_lbs_c_evt);
+ }
+ }
+}
+
+
+/**@brief Function for handling Disconnected event received from the SoftDevice.
+ *
+ * @details This function check if the disconnect event is happening on the link
+ * associated with the current instance of the module, if so it will set its
+ * conn_handle to invalid.
+ *
+ * @param[in] p_ble_lbs_c Pointer to the Led Button Client structure.
+ * @param[in] p_ble_evt Pointer to the BLE event received.
+ */
+static void on_disconnected(ble_lbs_c_t * p_ble_lbs_c, ble_evt_t const * p_ble_evt)
+{
+ if (p_ble_lbs_c->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
+ {
+ p_ble_lbs_c->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_ble_lbs_c->peer_lbs_db.button_cccd_handle = BLE_GATT_HANDLE_INVALID;
+ p_ble_lbs_c->peer_lbs_db.button_handle = BLE_GATT_HANDLE_INVALID;
+ p_ble_lbs_c->peer_lbs_db.led_handle = BLE_GATT_HANDLE_INVALID;
+ }
+}
+
+
+void ble_lbs_on_db_disc_evt(ble_lbs_c_t * p_ble_lbs_c, ble_db_discovery_evt_t const * p_evt)
+{
+ // Check if the Led Button Service was discovered.
+ if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE &&
+ p_evt->params.discovered_db.srv_uuid.uuid == LBS_UUID_SERVICE &&
+ p_evt->params.discovered_db.srv_uuid.type == p_ble_lbs_c->uuid_type)
+ {
+ ble_lbs_c_evt_t evt;
+
+ evt.evt_type = BLE_LBS_C_EVT_DISCOVERY_COMPLETE;
+ evt.conn_handle = p_evt->conn_handle;
+
+ for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
+ {
+ const ble_gatt_db_char_t * p_char = &(p_evt->params.discovered_db.charateristics[i]);
+ switch (p_char->characteristic.uuid.uuid)
+ {
+ case LBS_UUID_LED_CHAR:
+ evt.params.peer_db.led_handle = p_char->characteristic.handle_value;
+ break;
+ case LBS_UUID_BUTTON_CHAR:
+ evt.params.peer_db.button_handle = p_char->characteristic.handle_value;
+ evt.params.peer_db.button_cccd_handle = p_char->cccd_handle;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ NRF_LOG_DEBUG("Led Button Service discovered at peer.");
+ //If the instance has been assigned prior to db_discovery, assign the db_handles
+ if (p_ble_lbs_c->conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ if ((p_ble_lbs_c->peer_lbs_db.led_handle == BLE_GATT_HANDLE_INVALID)&&
+ (p_ble_lbs_c->peer_lbs_db.button_handle == BLE_GATT_HANDLE_INVALID)&&
+ (p_ble_lbs_c->peer_lbs_db.button_cccd_handle == BLE_GATT_HANDLE_INVALID))
+ {
+ p_ble_lbs_c->peer_lbs_db = evt.params.peer_db;
+ }
+ }
+
+ p_ble_lbs_c->evt_handler(p_ble_lbs_c, &evt);
+
+ }
+}
+
+
+uint32_t ble_lbs_c_init(ble_lbs_c_t * p_ble_lbs_c, ble_lbs_c_init_t * p_ble_lbs_c_init)
+{
+ uint32_t err_code;
+ ble_uuid_t lbs_uuid;
+ ble_uuid128_t lbs_base_uuid = {LBS_UUID_BASE};
+
+ VERIFY_PARAM_NOT_NULL(p_ble_lbs_c);
+ VERIFY_PARAM_NOT_NULL(p_ble_lbs_c_init);
+ VERIFY_PARAM_NOT_NULL(p_ble_lbs_c_init->evt_handler);
+
+ p_ble_lbs_c->peer_lbs_db.button_cccd_handle = BLE_GATT_HANDLE_INVALID;
+ p_ble_lbs_c->peer_lbs_db.button_handle = BLE_GATT_HANDLE_INVALID;
+ p_ble_lbs_c->peer_lbs_db.led_handle = BLE_GATT_HANDLE_INVALID;
+ p_ble_lbs_c->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_ble_lbs_c->evt_handler = p_ble_lbs_c_init->evt_handler;
+
+ err_code = sd_ble_uuid_vs_add(&lbs_base_uuid, &p_ble_lbs_c->uuid_type);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ VERIFY_SUCCESS(err_code);
+
+ lbs_uuid.type = p_ble_lbs_c->uuid_type;
+ lbs_uuid.uuid = LBS_UUID_SERVICE;
+
+ return ble_db_discovery_evt_register(&lbs_uuid);
+}
+
+void ble_lbs_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ if ((p_context == NULL) || (p_ble_evt == NULL))
+ {
+ return;
+ }
+
+ ble_lbs_c_t * p_ble_lbs_c = (ble_lbs_c_t *)p_context;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GATTC_EVT_HVX:
+ on_hvx(p_ble_lbs_c, p_ble_evt);
+ break;
+
+ case BLE_GATTC_EVT_WRITE_RSP:
+ on_write_rsp(p_ble_lbs_c, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnected(p_ble_lbs_c, p_ble_evt);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/**@brief Function for configuring the CCCD.
+ *
+ * @param[in] conn_handle The connection handle on which to configure the CCCD.
+ * @param[in] handle_cccd The handle of the CCCD to be configured.
+ * @param[in] enable Whether to enable or disable the CCCD.
+ *
+ * @return NRF_SUCCESS if the CCCD configure was successfully sent to the peer.
+ */
+static uint32_t cccd_configure(uint16_t conn_handle, uint16_t handle_cccd, bool enable)
+{
+ NRF_LOG_DEBUG("Configuring CCCD. CCCD Handle = %d, Connection Handle = %d",
+ handle_cccd,conn_handle);
+
+ tx_message_t * p_msg;
+ uint16_t cccd_val = enable ? BLE_GATT_HVX_NOTIFICATION : 0;
+
+ p_msg = &m_tx_buffer[m_tx_insert_index++];
+ m_tx_insert_index &= TX_BUFFER_MASK;
+
+ p_msg->req.write_req.gattc_params.handle = handle_cccd;
+ p_msg->req.write_req.gattc_params.len = WRITE_MESSAGE_LENGTH;
+ p_msg->req.write_req.gattc_params.p_value = p_msg->req.write_req.gattc_value;
+ p_msg->req.write_req.gattc_params.offset = 0;
+ p_msg->req.write_req.gattc_params.write_op = BLE_GATT_OP_WRITE_REQ;
+ p_msg->req.write_req.gattc_value[0] = LSB_16(cccd_val);
+ p_msg->req.write_req.gattc_value[1] = MSB_16(cccd_val);
+ p_msg->conn_handle = conn_handle;
+ p_msg->type = WRITE_REQ;
+
+ tx_buffer_process();
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_lbs_c_button_notif_enable(ble_lbs_c_t * p_ble_lbs_c)
+{
+ VERIFY_PARAM_NOT_NULL(p_ble_lbs_c);
+
+ if (p_ble_lbs_c->conn_handle == BLE_CONN_HANDLE_INVALID)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ return cccd_configure(p_ble_lbs_c->conn_handle,
+ p_ble_lbs_c->peer_lbs_db.button_cccd_handle,
+ true);
+}
+
+
+uint32_t ble_lbs_led_status_send(ble_lbs_c_t * p_ble_lbs_c, uint8_t status)
+{
+ VERIFY_PARAM_NOT_NULL(p_ble_lbs_c);
+
+ if (p_ble_lbs_c->conn_handle == BLE_CONN_HANDLE_INVALID)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ NRF_LOG_DEBUG("writing LED status 0x%x", status);
+
+ tx_message_t * p_msg;
+
+ p_msg = &m_tx_buffer[m_tx_insert_index++];
+ m_tx_insert_index &= TX_BUFFER_MASK;
+
+ p_msg->req.write_req.gattc_params.handle = p_ble_lbs_c->peer_lbs_db.led_handle;
+ p_msg->req.write_req.gattc_params.len = sizeof(status);
+ p_msg->req.write_req.gattc_params.p_value = p_msg->req.write_req.gattc_value;
+ p_msg->req.write_req.gattc_params.offset = 0;
+ p_msg->req.write_req.gattc_params.write_op = BLE_GATT_OP_WRITE_CMD;
+ p_msg->req.write_req.gattc_value[0] = status;
+ p_msg->conn_handle = p_ble_lbs_c->conn_handle;
+ p_msg->type = WRITE_REQ;
+
+ tx_buffer_process();
+ return NRF_SUCCESS;
+}
+
+uint32_t ble_lbs_c_handles_assign(ble_lbs_c_t * p_ble_lbs_c,
+ uint16_t conn_handle,
+ const lbs_db_t * p_peer_handles)
+{
+ VERIFY_PARAM_NOT_NULL(p_ble_lbs_c);
+
+ p_ble_lbs_c->conn_handle = conn_handle;
+ if (p_peer_handles != NULL)
+ {
+ p_ble_lbs_c->peer_lbs_db = *p_peer_handles;
+ }
+ return NRF_SUCCESS;
+}
+
+#endif // NRF_MODULE_ENABLED(BLE_LBS_C)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lbs_c/ble_lbs_c.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lbs_c/ble_lbs_c.h
new file mode 100644
index 0000000..a3b19d6
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lbs_c/ble_lbs_c.h
@@ -0,0 +1,254 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/**@file
+ *
+ * @defgroup ble_lbs_c LED Button Service Client
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief The LED Button Service client can be used to set a LED, and read a button state on a
+ * LED button service server.
+ *
+ * @details This module contains the APIs and types exposed by the LED Button Service Client
+ * module. These APIs and types can be used by the application to perform discovery of
+ * LED Button Service at the peer and interact with it.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_lbs_c_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_LBS_C_BLE_OBSERVER_PRIO,
+ * ble_lbs_c_on_ble_evt, &instance);
+ * @endcode
+ */
+
+#ifndef BLE_LBS_C_H__
+#define BLE_LBS_C_H__
+
+#include <stdint.h>
+#include "ble.h"
+#include "ble_db_discovery.h"
+#include "nrf_sdh_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_lbs_c instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_LBS_C_DEF(_name) \
+static ble_lbs_c_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_LBS_C_BLE_OBSERVER_PRIO, \
+ ble_lbs_c_on_ble_evt, &_name)
+
+/**@brief Macro for defining multiple ble_lbs_c instances.
+ *
+ * @param _name Name of the array of instances.
+ * @param _cnt Number of instances to define.
+ */
+#define BLE_LBS_C_ARRAY_DEF(_name, _cnt) \
+static ble_lbs_c_t _name[_cnt]; \
+NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
+ BLE_LBS_C_BLE_OBSERVER_PRIO, \
+ ble_lbs_c_on_ble_evt, &_name, _cnt)
+
+
+#define LBS_UUID_BASE {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, \
+ 0xDE, 0xEF, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00}
+#define LBS_UUID_SERVICE 0x1523
+#define LBS_UUID_BUTTON_CHAR 0x1524
+#define LBS_UUID_LED_CHAR 0x1525
+
+/**@brief LBS Client event type. */
+typedef enum
+{
+ BLE_LBS_C_EVT_DISCOVERY_COMPLETE = 1, /**< Event indicating that the LED Button Service has been discovered at the peer. */
+ BLE_LBS_C_EVT_BUTTON_NOTIFICATION /**< Event indicating that a notification of the LED Button Button characteristic has been received from the peer. */
+} ble_lbs_c_evt_type_t;
+
+/**@brief Structure containing the Button value received from the peer. */
+typedef struct
+{
+ uint8_t button_state; /**< Button Value. */
+} ble_button_t;
+
+/**@brief Structure containing the handles related to the LED Button Service found on the peer. */
+typedef struct
+{
+ uint16_t button_cccd_handle; /**< Handle of the CCCD of the Button characteristic. */
+ uint16_t button_handle; /**< Handle of the Button characteristic as provided by the SoftDevice. */
+ uint16_t led_handle; /**< Handle of the LED characteristic as provided by the SoftDevice. */
+} lbs_db_t;
+
+/**@brief LED Button Event structure. */
+typedef struct
+{
+ ble_lbs_c_evt_type_t evt_type; /**< Type of the event. */
+ uint16_t conn_handle; /**< Connection handle on which the event occured.*/
+ union
+ {
+ ble_button_t button; /**< Button Value received. This will be filled if the evt_type is @ref BLE_LBS_C_EVT_BUTTON_NOTIFICATION. */
+ lbs_db_t peer_db; /**< LED Button Service related handles found on the peer device. This will be filled if the evt_type is @ref BLE_LBS_C_EVT_DISCOVERY_COMPLETE.*/
+ } params;
+} ble_lbs_c_evt_t;
+
+// Forward declaration of the ble_lbs_c_t type.
+typedef struct ble_lbs_c_s ble_lbs_c_t;
+
+/**@brief Event handler type.
+ *
+ * @details This is the type of the event handler that should be provided by the application
+ * of this module in order to receive events.
+ */
+typedef void (* ble_lbs_c_evt_handler_t) (ble_lbs_c_t * p_ble_lbs_c, ble_lbs_c_evt_t * p_evt);
+
+/**@brief LED Button Client structure. */
+struct ble_lbs_c_s
+{
+ uint16_t conn_handle; /**< Connection handle as provided by the SoftDevice. */
+ lbs_db_t peer_lbs_db; /**< Handles related to LBS on the peer*/
+ ble_lbs_c_evt_handler_t evt_handler; /**< Application event handler to be called when there is an event related to the LED Button service. */
+ uint8_t uuid_type; /**< UUID type. */
+};
+
+/**@brief LED Button Client initialization structure. */
+typedef struct
+{
+ ble_lbs_c_evt_handler_t evt_handler; /**< Event handler to be called by the LED Button Client module whenever there is an event related to the LED Button Service. */
+} ble_lbs_c_init_t;
+
+
+/**@brief Function for initializing the LED Button client module.
+ *
+ * @details This function will register with the DB Discovery module. There it registers for the
+ * LED Button Service. Doing so will make the DB Discovery module look for the presence
+ * of a LED Button Service instance at the peer when a discovery is started.
+ *
+ * @param[in] p_ble_lbs_c Pointer to the LED Button client structure.
+ * @param[in] p_ble_lbs_c_init Pointer to the LED Button initialization structure containing the
+ * initialization information.
+ *
+ * @retval NRF_SUCCESS On successful initialization. Otherwise an error code. This function
+ * propagates the error code returned by the Database Discovery module API
+ * @ref ble_db_discovery_evt_register.
+ */
+uint32_t ble_lbs_c_init(ble_lbs_c_t * p_ble_lbs_c, ble_lbs_c_init_t * p_ble_lbs_c_init);
+
+
+/**@brief Function for handling BLE events from the SoftDevice.
+ *
+ * @details This function will handle the BLE events received from the SoftDevice. If a BLE event
+ * is relevant to the LED Button Client module, then it uses it to update interval
+ * variables and, if necessary, send events to the application.
+ *
+ * @param[in] p_ble_evt Pointer to the BLE event.
+ * @param[in] p_context Pointer to the LED button client structure.
+ */
+void ble_lbs_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for requesting the peer to start sending notification of the Button
+ * Characteristic.
+ *
+ * @details This function will enable to notification of the Button at the peer
+ * by writing to the CCCD of the Button Characteristic.
+ *
+ * @param[in] p_ble_lbs_c Pointer to the LED Button Client structure.
+ *
+ * @retval NRF_SUCCESS If the SoftDevice has been requested to write to the CCCD of the peer.
+ * Otherwise, an error code. This function propagates the error code returned
+ * by the SoftDevice API @ref sd_ble_gattc_write.
+ * NRF_ERROR_INVALID_STATE if no connection handle has been assigned (@ref ble_lbs_c_handles_assign)
+ * NRF_ERROR_NULL if the given parameter is NULL
+ */
+uint32_t ble_lbs_c_button_notif_enable(ble_lbs_c_t * p_ble_lbs_c);
+
+
+/**@brief Function for handling events from the database discovery module.
+ *
+ * @details Call this function when getting a callback event from the DB discovery module. This
+ * function will handle an event from the database discovery module, and determine if it
+ * relates to the discovery of LED Button service at the peer. If so, it will call the
+ * application's event handler indicating that the LED Button service has been discovered
+ * at the peer. It also populates the event with the service related information before
+ * providing it to the application.
+ *
+ * @param[in] p_ble_lbs_c Pointer to the LED Button client structure.
+ * @param[in] p_evt Pointer to the event received from the database discovery module.
+ */
+void ble_lbs_on_db_disc_evt(ble_lbs_c_t * p_ble_lbs_c, const ble_db_discovery_evt_t * p_evt);
+
+
+/**@brief Function for assigning a Handles to this instance of lbs_c.
+ *
+ * @details Call this function when a link has been established with a peer to associate this link
+ * to this instance of the module. This makes it possible to handle several links and
+ * associate each link to a particular instance of this module.
+ *
+ * @param[in] p_ble_lbs_c Pointer to the LED Button client structure instance to associate.
+ * @param[in] conn_handle Connection handle to associate with the given LED Button Client Instance.
+ * @param[in] p_peer_handles LED Button Service handles found on the peer (from @ref BLE_LBS_C_EVT_DISCOVERY_COMPLETE event).
+ *
+ */
+uint32_t ble_lbs_c_handles_assign(ble_lbs_c_t * p_ble_lbs_c,
+ uint16_t conn_handle,
+ const lbs_db_t * p_peer_handles);
+
+
+/**@brief Function for writing the LED status to the connected server.
+ *
+ * @param[in] p_ble_lbs_c Pointer to the LED Button client structure.
+ * @param[in] status LED status to send.
+ *
+ * @retval NRF_SUCCESS If the staus was sent successfully. Otherwise, an error code is returned.
+ */
+uint32_t ble_lbs_led_status_send(ble_lbs_c_t * p_ble_lbs_c, uint8_t status);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_LBS_C_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lls/ble_lls.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lls/ble_lls.c
new file mode 100644
index 0000000..ceb3102
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lls/ble_lls.c
@@ -0,0 +1,260 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Attention!
+ * To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_LLS)
+#include "ble_lls.h"
+#include <string.h>
+#include "ble_hci.h"
+#include "ble_srv_common.h"
+
+
+/**@brief Function for handling the Connect event.
+ *
+ * @param[in] p_lls Link Loss Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_connect(ble_lls_t * p_lls, ble_evt_t const * p_ble_evt)
+{
+ // Link reconnected, notify application with a no_alert event
+ ble_lls_evt_t evt;
+
+ p_lls->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+
+ evt.evt_type = BLE_LLS_EVT_LINK_LOSS_ALERT;
+ evt.params.alert_level = BLE_CHAR_ALERT_LEVEL_NO_ALERT;
+ p_lls->evt_handler(p_lls, &evt);
+}
+
+
+/**@brief Function for handling the Disconnect event.
+ *
+ * @param[in] p_lls Link Loss Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_disconnect(ble_lls_t * p_lls, ble_evt_t const * p_ble_evt)
+{
+ uint8_t reason = p_ble_evt->evt.gap_evt.params.disconnected.reason;
+
+ if (reason == BLE_HCI_CONNECTION_TIMEOUT)
+ {
+ // Link loss detected, notify application
+ uint32_t err_code;
+ ble_lls_evt_t evt;
+
+ evt.evt_type = BLE_LLS_EVT_LINK_LOSS_ALERT;
+
+ err_code = ble_lls_alert_level_get(p_lls, &evt.params.alert_level);
+ if (err_code == NRF_SUCCESS)
+ {
+ p_lls->evt_handler(p_lls, &evt);
+ }
+ else
+ {
+ if (p_lls->error_handler != NULL)
+ {
+ p_lls->error_handler(err_code);
+ }
+ }
+ }
+}
+
+
+/**@brief Function for handling the Authentication Status event.
+ *
+ * @param[in] p_lls Link Loss Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_auth_status(ble_lls_t * p_lls, ble_evt_t const * p_ble_evt)
+{
+ if (p_ble_evt->evt.gap_evt.params.auth_status.auth_status == BLE_GAP_SEC_STATUS_SUCCESS)
+ {
+ ble_lls_evt_t evt;
+
+ evt.evt_type = BLE_LLS_EVT_LINK_LOSS_ALERT;
+ evt.params.alert_level = BLE_CHAR_ALERT_LEVEL_NO_ALERT;
+
+ p_lls->evt_handler(p_lls, &evt);
+ }
+}
+
+
+void ble_lls_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ ble_lls_t * p_lls = (ble_lls_t *)p_context;
+
+ if (p_lls == NULL || p_ble_evt == NULL)
+ {
+ return;
+ }
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ on_connect(p_lls, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnect(p_lls, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_AUTH_STATUS:
+ on_auth_status(p_lls, p_ble_evt);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+
+/**@brief Function for adding Alert Level characteristics.
+ *
+ * @param[in] p_lls Link Loss Service structure.
+ * @param[in] p_lls_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t alert_level_char_add(ble_lls_t * p_lls, const ble_lls_init_t * p_lls_init)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+ uint8_t initial_alert_level;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.char_props.write = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = NULL;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_ALERT_LEVEL_CHAR);
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.read_perm = p_lls_init->lls_attr_md.read_perm;
+ attr_md.write_perm = p_lls_init->lls_attr_md.write_perm;
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+ initial_alert_level = p_lls_init->initial_alert_level;
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = sizeof (uint8_t);
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = sizeof (uint8_t);
+ attr_char_value.p_value = &initial_alert_level;
+
+ return sd_ble_gatts_characteristic_add(p_lls->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_lls->alert_level_handles);
+}
+
+
+uint32_t ble_lls_init(ble_lls_t * p_lls, const ble_lls_init_t * p_lls_init)
+{
+ uint32_t err_code;
+ ble_uuid_t ble_uuid;
+
+ if (p_lls == NULL || p_lls_init == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ if (p_lls_init->evt_handler == NULL)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ // Initialize service structure
+ p_lls->evt_handler = p_lls_init->evt_handler;
+ p_lls->error_handler = p_lls_init->error_handler;
+
+ // Add service
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_LINK_LOSS_SERVICE);
+
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
+ &ble_uuid,
+ &p_lls->service_handle);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add alert level characteristic
+ return alert_level_char_add(p_lls, p_lls_init);
+}
+
+
+uint32_t ble_lls_alert_level_get(ble_lls_t * p_lls, uint8_t * p_alert_level)
+{
+ ble_gatts_value_t gatts_value;
+
+ if (p_lls == NULL || p_alert_level == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ // Initialize value struct.
+ memset(&gatts_value, 0, sizeof(gatts_value));
+
+ gatts_value.len = sizeof(uint8_t);
+ gatts_value.offset = 0;
+ gatts_value.p_value = p_alert_level;
+
+ return sd_ble_gatts_value_get(p_lls->conn_handle,
+ p_lls->alert_level_handles.value_handle,
+ &gatts_value);
+}
+#endif // NRF_MODULE_ENABLED(BLE_LLS)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lls/ble_lls.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lls/ble_lls.h
new file mode 100644
index 0000000..22ea716
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_lls/ble_lls.h
@@ -0,0 +1,175 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_lls Link Loss Service
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Link Loss Service module.
+ *
+ * @details This module implements the Link Loss Service with the Alert Level characteristic.
+ * During initialization it adds the Link Loss Service and Alert Level characteristic
+ * to the BLE stack database.
+ *
+ * The application must supply an event handler for receiving Link Loss Service
+ * events. Using this handler, the service will notify the application when the
+ * link has been lost, and which Alert Level has been set.
+ *
+ * The service also provides a function for letting the application poll the current
+ * value of the Alert Level characteristic.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_lls_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_LLS_BLE_OBSERVER_PRIO,
+ * ble_lls_on_ble_evt, &instance);
+ * @endcode
+ *
+ * @note Attention!
+ * To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+*/
+
+#ifndef BLE_LLS_H__
+#define BLE_LLS_H__
+
+#include <stdint.h>
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "nrf_sdh_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_lls instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_LLS_DEF(_name) \
+static ble_lls_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_LLS_BLE_OBSERVER_PRIO, \
+ ble_lls_on_ble_evt, &_name)
+
+
+/**@brief Link Loss Service event type. */
+typedef enum
+{
+ BLE_LLS_EVT_LINK_LOSS_ALERT /**< Alert Level Updated event. */
+} ble_lls_evt_type_t;
+
+/**@brief Link Loss Service event. */
+typedef struct
+{
+ ble_lls_evt_type_t evt_type; /**< Type of event. */
+ union
+ {
+ uint8_t alert_level; /**< New Alert Level value. */
+ } params;
+} ble_lls_evt_t;
+
+// Forward declaration of the ble_lls_t type.
+typedef struct ble_lls_s ble_lls_t;
+
+/**@brief Link Loss Service event handler type. */
+typedef void (*ble_lls_evt_handler_t) (ble_lls_t * p_lls, ble_lls_evt_t * p_evt);
+
+/**@brief Link Loss Service init structure. This contains all options and data needed for initialization of the service. */
+typedef struct
+{
+ ble_lls_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Link Loss Service. */
+ ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
+ uint8_t initial_alert_level; /**< Initial value of the Alert Level characteristic. */
+ ble_srv_security_mode_t lls_attr_md; /**< Initial Security Setting for Link Loss Service Characteristics. */
+} ble_lls_init_t;
+
+/**@brief Link Loss Service structure. This contains various status information for the service. */
+struct ble_lls_s
+{
+ ble_lls_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Link Loss Service. */
+ ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
+ uint16_t service_handle; /**< Handle of Link Loss Service (as provided by the BLE stack). */
+ ble_gatts_char_handles_t alert_level_handles; /**< Handles related to the Alert Level characteristic. */
+ uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
+};
+
+
+/**@brief Function for initializing the Link Loss Service.
+ *
+ * @param[out] p_lls Link Loss Service structure. This structure will have to be supplied by
+ * the application. It will be initialized by this function, and will later
+ * be used to identify this particular service instance.
+ * @param[in] p_lls_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
+ */
+uint32_t ble_lls_init(ble_lls_t * p_lls, const ble_lls_init_t * p_lls_init);
+
+
+/**@brief Function for handling the Application's BLE Stack events.
+ *
+ * @details Handles all events from the BLE stack of interest to the Link Loss Service.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Link Loss Service structure.
+ */
+void ble_lls_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for getting current value of the Alert Level characteristic.
+ *
+ * @param[in] p_lls Link Loss Service structure.
+ * @param[out] p_alert_level Current Alert Level value.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+uint32_t ble_lls_alert_level_get(ble_lls_t * p_lls, uint8_t * p_alert_level);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_LLS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_nus/ble_nus.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_nus/ble_nus.c
new file mode 100644
index 0000000..738b6d6
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_nus/ble_nus.c
@@ -0,0 +1,440 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_NUS)
+#include "ble.h"
+#include "ble_nus.h"
+#include "ble_srv_common.h"
+
+#define NRF_LOG_MODULE_NAME ble_nus
+#if BLE_NUS_CONFIG_LOG_ENABLED
+#define NRF_LOG_LEVEL BLE_NUS_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR BLE_NUS_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR BLE_NUS_CONFIG_DEBUG_COLOR
+#else // BLE_NUS_CONFIG_LOG_ENABLED
+#define NRF_LOG_LEVEL 0
+#endif // BLE_NUS_CONFIG_LOG_ENABLED
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+
+#define BLE_UUID_NUS_TX_CHARACTERISTIC 0x0003 /**< The UUID of the TX Characteristic. */
+#define BLE_UUID_NUS_RX_CHARACTERISTIC 0x0002 /**< The UUID of the RX Characteristic. */
+
+#define BLE_NUS_MAX_RX_CHAR_LEN BLE_NUS_MAX_DATA_LEN /**< Maximum length of the RX Characteristic (in bytes). */
+#define BLE_NUS_MAX_TX_CHAR_LEN BLE_NUS_MAX_DATA_LEN /**< Maximum length of the TX Characteristic (in bytes). */
+
+#define NUS_BASE_UUID {{0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E}} /**< Used vendor specific UUID. */
+
+
+/**@brief Function for handling the @ref BLE_GAP_EVT_CONNECTED event from the SoftDevice.
+ *
+ * @param[in] p_nus Nordic UART Service structure.
+ * @param[in] p_ble_evt Pointer to the event received from BLE stack.
+ */
+static void on_connect(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
+{
+ ret_code_t err_code;
+ ble_nus_evt_t evt;
+ ble_gatts_value_t gatts_val;
+ uint8_t cccd_value[2];
+ ble_nus_client_context_t * p_client = NULL;
+
+ err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage,
+ p_ble_evt->evt.gap_evt.conn_handle,
+ (void *) &p_client);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.",
+ p_ble_evt->evt.gap_evt.conn_handle);
+ }
+
+ /* Check the hosts CCCD value to inform of readiness to send data using the RX characteristic */
+ memset(&gatts_val, 0, sizeof(ble_gatts_value_t));
+ gatts_val.p_value = cccd_value;
+ gatts_val.len = sizeof(cccd_value);
+ gatts_val.offset = 0;
+
+ err_code = sd_ble_gatts_value_get(p_ble_evt->evt.gap_evt.conn_handle,
+ p_nus->rx_handles.cccd_handle,
+ &gatts_val);
+
+ if ((err_code == NRF_SUCCESS) &&
+ (p_nus->data_handler != NULL) &&
+ ble_srv_is_notification_enabled(gatts_val.p_value))
+ {
+ if (p_client != NULL)
+ {
+ p_client->is_notification_enabled = true;
+ }
+
+ memset(&evt, 0, sizeof(ble_nus_evt_t));
+ evt.type = BLE_NUS_EVT_COMM_STARTED;
+ evt.p_nus = p_nus;
+ evt.conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+ evt.p_link_ctx = p_client;
+
+ p_nus->data_handler(&evt);
+ }
+}
+
+
+/**@brief Function for handling the @ref BLE_GATTS_EVT_WRITE event from the SoftDevice.
+ *
+ * @param[in] p_nus Nordic UART Service structure.
+ * @param[in] p_ble_evt Pointer to the event received from BLE stack.
+ */
+static void on_write(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
+{
+ ret_code_t err_code;
+ ble_nus_evt_t evt;
+ ble_nus_client_context_t * p_client;
+ ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+ err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage,
+ p_ble_evt->evt.gatts_evt.conn_handle,
+ (void *) &p_client);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.",
+ p_ble_evt->evt.gatts_evt.conn_handle);
+ }
+
+ memset(&evt, 0, sizeof(ble_nus_evt_t));
+ evt.p_nus = p_nus;
+ evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
+ evt.p_link_ctx = p_client;
+
+ if ((p_evt_write->handle == p_nus->tx_handles.cccd_handle) &&
+ (p_evt_write->len == 2))
+ {
+ if (p_client != NULL)
+ {
+ if (ble_srv_is_notification_enabled(p_evt_write->data))
+ {
+ p_client->is_notification_enabled = true;
+ evt.type = BLE_NUS_EVT_COMM_STARTED;
+ }
+ else
+ {
+ p_client->is_notification_enabled = false;
+ evt.type = BLE_NUS_EVT_COMM_STOPPED;
+ }
+
+ if (p_nus->data_handler != NULL)
+ {
+ p_nus->data_handler(&evt);
+ }
+
+ }
+ }
+ else if ((p_evt_write->handle == p_nus->rx_handles.value_handle) &&
+ (p_nus->data_handler != NULL))
+ {
+ evt.type = BLE_NUS_EVT_RX_DATA;
+ evt.params.rx_data.p_data = p_evt_write->data;
+ evt.params.rx_data.length = p_evt_write->len;
+
+ p_nus->data_handler(&evt);
+ }
+ else
+ {
+ // Do Nothing. This event is not relevant for this service.
+ }
+}
+
+
+/**@brief Function for handling the @ref BLE_GATTS_EVT_HVN_TX_COMPLETE event from the SoftDevice.
+ *
+ * @param[in] p_nus Nordic UART Service structure.
+ * @param[in] p_ble_evt Pointer to the event received from BLE stack.
+ */
+static void on_hvx_tx_complete(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
+{
+ ret_code_t err_code;
+ ble_nus_evt_t evt;
+ ble_nus_client_context_t * p_client;
+
+ err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage,
+ p_ble_evt->evt.gatts_evt.conn_handle,
+ (void *) &p_client);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.",
+ p_ble_evt->evt.gatts_evt.conn_handle);
+ return;
+ }
+
+ if (p_client->is_notification_enabled)
+ {
+ memset(&evt, 0, sizeof(ble_nus_evt_t));
+ evt.type = BLE_NUS_EVT_TX_RDY;
+ evt.p_nus = p_nus;
+ evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
+ evt.p_link_ctx = p_client;
+
+ p_nus->data_handler(&evt);
+ }
+}
+
+
+/**@brief Function for adding TX characteristic.
+ *
+ * @param[in] p_nus Nordic UART Service structure.
+ * @param[in] p_nus_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t tx_char_add(ble_nus_t * p_nus, ble_nus_init_t const * p_nus_init)
+{
+ /**@snippet [Adding proprietary characteristic to the SoftDevice] */
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_md_t cccd_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+
+ memset(&cccd_md, 0, sizeof(cccd_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
+
+ cccd_md.vloc = BLE_GATTS_VLOC_STACK;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.notify = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = &cccd_md;
+ char_md.p_sccd_md = NULL;
+
+ ble_uuid.type = p_nus->uuid_type;
+ ble_uuid.uuid = BLE_UUID_NUS_TX_CHARACTERISTIC;
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
+
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 1;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = sizeof(uint8_t);
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = BLE_NUS_MAX_TX_CHAR_LEN;
+
+ return sd_ble_gatts_characteristic_add(p_nus->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_nus->tx_handles);
+ /**@snippet [Adding proprietary characteristic to the SoftDevice] */
+}
+
+
+/**@brief Function for adding RX characteristic.
+ *
+ * @param[in] p_nus Nordic UART Service structure.
+ * @param[in] p_nus_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t rx_char_add(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.write = 1;
+ char_md.char_props.write_wo_resp = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = NULL;
+ char_md.p_sccd_md = NULL;
+
+ ble_uuid.type = p_nus->uuid_type;
+ ble_uuid.uuid = BLE_UUID_NUS_RX_CHARACTERISTIC;
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
+
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 1;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = 1;
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = BLE_NUS_MAX_RX_CHAR_LEN;
+
+ return sd_ble_gatts_characteristic_add(p_nus->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_nus->rx_handles);
+}
+
+
+void ble_nus_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ if ((p_context == NULL) || (p_ble_evt == NULL))
+ {
+ return;
+ }
+
+ ble_nus_t * p_nus = (ble_nus_t *)p_context;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ on_connect(p_nus, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_WRITE:
+ on_write(p_nus, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_HVN_TX_COMPLETE:
+ on_hvx_tx_complete(p_nus, p_ble_evt);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+
+uint32_t ble_nus_init(ble_nus_t * p_nus, ble_nus_init_t const * p_nus_init)
+{
+ ret_code_t err_code;
+ ble_uuid_t ble_uuid;
+ ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;
+
+ VERIFY_PARAM_NOT_NULL(p_nus);
+ VERIFY_PARAM_NOT_NULL(p_nus_init);
+
+ // Initialize the service structure.
+ p_nus->data_handler = p_nus_init->data_handler;
+
+ /**@snippet [Adding proprietary Service to the SoftDevice] */
+ // Add a custom base UUID.
+ err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_nus->uuid_type);
+ VERIFY_SUCCESS(err_code);
+
+ ble_uuid.type = p_nus->uuid_type;
+ ble_uuid.uuid = BLE_UUID_NUS_SERVICE;
+
+ // Add the service.
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
+ &ble_uuid,
+ &p_nus->service_handle);
+ /**@snippet [Adding proprietary Service to the SoftDevice] */
+ VERIFY_SUCCESS(err_code);
+
+ // Add the RX Characteristic.
+ err_code = rx_char_add(p_nus, p_nus_init);
+ VERIFY_SUCCESS(err_code);
+
+ // Add the TX Characteristic.
+ err_code = tx_char_add(p_nus, p_nus_init);
+ VERIFY_SUCCESS(err_code);
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_nus_data_send(ble_nus_t * p_nus,
+ uint8_t * p_data,
+ uint16_t * p_length,
+ uint16_t conn_handle)
+{
+ ret_code_t err_code;
+ ble_gatts_hvx_params_t hvx_params;
+ ble_nus_client_context_t * p_client;
+
+ VERIFY_PARAM_NOT_NULL(p_nus);
+
+ err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage, conn_handle, (void *) &p_client);
+ VERIFY_SUCCESS(err_code);
+
+ if ((conn_handle == BLE_CONN_HANDLE_INVALID) || (p_client == NULL))
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ if (!p_client->is_notification_enabled)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ if (*p_length > BLE_NUS_MAX_DATA_LEN)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ memset(&hvx_params, 0, sizeof(hvx_params));
+
+ hvx_params.handle = p_nus->tx_handles.value_handle;
+ hvx_params.p_data = p_data;
+ hvx_params.p_len = p_length;
+ hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
+
+ return sd_ble_gatts_hvx(conn_handle, &hvx_params);
+}
+
+
+#endif // NRF_MODULE_ENABLED(BLE_NUS)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_nus/ble_nus.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_nus/ble_nus.h
new file mode 100644
index 0000000..5f17ac8
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_nus/ble_nus.h
@@ -0,0 +1,244 @@
+ /**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/**@file
+ *
+ * @defgroup ble_nus Nordic UART Service
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Nordic UART Service implementation.
+ *
+ * @details The Nordic UART Service is a simple GATT-based service with TX and RX characteristics.
+ * Data received from the peer is passed to the application, and the data received
+ * from the application of this service is sent to the peer as Handle Value
+ * Notifications. This module demonstrates how to implement a custom GATT-based
+ * service and characteristics using the SoftDevice. The service
+ * is used by the application to send and receive ASCII text strings to and from the
+ * peer.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_nus_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_NUS_BLE_OBSERVER_PRIO,
+ * ble_nus_on_ble_evt, &instance);
+ * @endcode
+ */
+#ifndef BLE_NUS_H__
+#define BLE_NUS_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "sdk_config.h"
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "nrf_sdh_ble.h"
+#include "ble_link_ctx_manager.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_nus instance.
+ *
+ * @param _name Name of the instance.
+ * @param[in] _nus_max_clients Maximum number of NUS clients connected at a time.
+ * @hideinitializer
+ */
+#define BLE_NUS_DEF(_name, _nus_max_clients) \
+ BLE_LINK_CTX_MANAGER_DEF(CONCAT_2(_name, _link_ctx_storage), \
+ (_nus_max_clients), \
+ sizeof(ble_nus_client_context_t)); \
+ static ble_nus_t _name = \
+ { \
+ .p_link_ctx_storage = &CONCAT_2(_name, _link_ctx_storage) \
+ }; \
+ NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_NUS_BLE_OBSERVER_PRIO, \
+ ble_nus_on_ble_evt, \
+ &_name)
+
+#define BLE_UUID_NUS_SERVICE 0x0001 /**< The UUID of the Nordic UART Service. */
+
+#define OPCODE_LENGTH 1
+#define HANDLE_LENGTH 2
+
+/**@brief Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */
+#if defined(NRF_SDH_BLE_GATT_MAX_MTU_SIZE) && (NRF_SDH_BLE_GATT_MAX_MTU_SIZE != 0)
+ #define BLE_NUS_MAX_DATA_LEN (NRF_SDH_BLE_GATT_MAX_MTU_SIZE - OPCODE_LENGTH - HANDLE_LENGTH)
+#else
+ #define BLE_NUS_MAX_DATA_LEN (BLE_GATT_MTU_SIZE_DEFAULT - OPCODE_LENGTH - HANDLE_LENGTH)
+ #warning NRF_SDH_BLE_GATT_MAX_MTU_SIZE is not defined.
+#endif
+
+
+/**@brief Nordic UART Service event types. */
+typedef enum
+{
+ BLE_NUS_EVT_RX_DATA, /**< Data received. */
+ BLE_NUS_EVT_TX_RDY, /**< Service is ready to accept new data to be transmitted. */
+ BLE_NUS_EVT_COMM_STARTED, /**< Notification has been enabled. */
+ BLE_NUS_EVT_COMM_STOPPED, /**< Notification has been disabled. */
+} ble_nus_evt_type_t;
+
+
+/* Forward declaration of the ble_nus_t type. */
+typedef struct ble_nus_s ble_nus_t;
+
+
+/**@brief Nordic UART Service @ref BLE_NUS_EVT_RX_DATA event data.
+ *
+ * @details This structure is passed to an event when @ref BLE_NUS_EVT_RX_DATA occurs.
+ */
+typedef struct
+{
+ uint8_t const * p_data; /**< A pointer to the buffer with received data. */
+ uint16_t length; /**< Length of received data. */
+} ble_nus_evt_rx_data_t;
+
+
+/**@brief Nordic UART Service client context structure.
+ *
+ * @details This structure contains state context related to hosts.
+ */
+typedef struct
+{
+ bool is_notification_enabled; /**< Variable to indicate if the peer has enabled notification of the RX characteristic.*/
+} ble_nus_client_context_t;
+
+
+/**@brief Nordic UART Service event structure.
+ *
+ * @details This structure is passed to an event coming from service.
+ */
+typedef struct
+{
+ ble_nus_evt_type_t type; /**< Event type. */
+ ble_nus_t * p_nus; /**< A pointer to the instance. */
+ uint16_t conn_handle; /**< Connection handle. */
+ ble_nus_client_context_t * p_link_ctx; /**< A pointer to the link context. */
+ union
+ {
+ ble_nus_evt_rx_data_t rx_data; /**< @ref BLE_NUS_EVT_RX_DATA event data. */
+ } params;
+} ble_nus_evt_t;
+
+
+/**@brief Nordic UART Service event handler type. */
+typedef void (* ble_nus_data_handler_t) (ble_nus_evt_t * p_evt);
+
+
+/**@brief Nordic UART Service initialization structure.
+ *
+ * @details This structure contains the initialization information for the service. The application
+ * must fill this structure and pass it to the service using the @ref ble_nus_init
+ * function.
+ */
+typedef struct
+{
+ ble_nus_data_handler_t data_handler; /**< Event handler to be called for handling received data. */
+} ble_nus_init_t;
+
+
+/**@brief Nordic UART Service structure.
+ *
+ * @details This structure contains status information related to the service.
+ */
+struct ble_nus_s
+{
+ uint8_t uuid_type; /**< UUID type for Nordic UART Service Base UUID. */
+ uint16_t service_handle; /**< Handle of Nordic UART Service (as provided by the SoftDevice). */
+ ble_gatts_char_handles_t tx_handles; /**< Handles related to the TX characteristic (as provided by the SoftDevice). */
+ ble_gatts_char_handles_t rx_handles; /**< Handles related to the RX characteristic (as provided by the SoftDevice). */
+ blcm_link_ctx_storage_t * const p_link_ctx_storage; /**< Pointer to link context storage with handles of all current connections and its context. */
+ ble_nus_data_handler_t data_handler; /**< Event handler to be called for handling received data. */
+};
+
+
+/**@brief Function for initializing the Nordic UART Service.
+ *
+ * @param[out] p_nus Nordic UART Service structure. This structure must be supplied
+ * by the application. It is initialized by this function and will
+ * later be used to identify this particular service instance.
+ * @param[in] p_nus_init Information needed to initialize the service.
+ *
+ * @retval NRF_SUCCESS If the service was successfully initialized. Otherwise, an error code is returned.
+ * @retval NRF_ERROR_NULL If either of the pointers p_nus or p_nus_init is NULL.
+ */
+uint32_t ble_nus_init(ble_nus_t * p_nus, ble_nus_init_t const * p_nus_init);
+
+
+/**@brief Function for handling the Nordic UART Service's BLE events.
+ *
+ * @details The Nordic UART Service expects the application to call this function each time an
+ * event is received from the SoftDevice. This function processes the event if it
+ * is relevant and calls the Nordic UART Service event handler of the
+ * application if necessary.
+ *
+ * @param[in] p_ble_evt Event received from the SoftDevice.
+ * @param[in] p_context Nordic UART Service structure.
+ */
+void ble_nus_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for sending a data to the peer.
+ *
+ * @details This function sends the input string as an RX characteristic notification to the
+ * peer.
+ *
+ * @param[in] p_nus Pointer to the Nordic UART Service structure.
+ * @param[in] p_data String to be sent.
+ * @param[in,out] p_length Pointer Length of the string. Amount of sent bytes.
+ * @param[in] conn_handle Connection Handle of the destination client.
+ *
+ * @retval NRF_SUCCESS If the string was sent successfully. Otherwise, an error code is returned.
+ */
+uint32_t ble_nus_data_send(ble_nus_t * p_nus,
+ uint8_t * p_data,
+ uint16_t * p_length,
+ uint16_t conn_handle);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_NUS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_nus_c/ble_nus_c.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_nus_c/ble_nus_c.c
new file mode 100644
index 0000000..ac27af7
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_nus_c/ble_nus_c.c
@@ -0,0 +1,265 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_NUS_C)
+#include <stdlib.h>
+
+#include "ble.h"
+#include "ble_nus_c.h"
+#include "ble_gattc.h"
+#include "ble_srv_common.h"
+#include "app_error.h"
+
+#define NRF_LOG_MODULE_NAME ble_nus
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+void ble_nus_c_on_db_disc_evt(ble_nus_c_t * p_ble_nus_c, ble_db_discovery_evt_t * p_evt)
+{
+ ble_nus_c_evt_t nus_c_evt;
+ memset(&nus_c_evt,0,sizeof(ble_nus_c_evt_t));
+
+ ble_gatt_db_char_t * p_chars = p_evt->params.discovered_db.charateristics;
+
+ // Check if the NUS was discovered.
+ if ( (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE)
+ && (p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_NUS_SERVICE)
+ && (p_evt->params.discovered_db.srv_uuid.type == p_ble_nus_c->uuid_type))
+ {
+ for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
+ {
+ switch (p_chars[i].characteristic.uuid.uuid)
+ {
+ case BLE_UUID_NUS_RX_CHARACTERISTIC:
+ nus_c_evt.handles.nus_rx_handle = p_chars[i].characteristic.handle_value;
+ break;
+
+ case BLE_UUID_NUS_TX_CHARACTERISTIC:
+ nus_c_evt.handles.nus_tx_handle = p_chars[i].characteristic.handle_value;
+ nus_c_evt.handles.nus_tx_cccd_handle = p_chars[i].cccd_handle;
+ break;
+
+ default:
+ break;
+ }
+ }
+ if (p_ble_nus_c->evt_handler != NULL)
+ {
+ nus_c_evt.conn_handle = p_evt->conn_handle;
+ nus_c_evt.evt_type = BLE_NUS_C_EVT_DISCOVERY_COMPLETE;
+ p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt);
+ }
+ }
+}
+
+/**@brief Function for handling Handle Value Notification received from the SoftDevice.
+ *
+ * @details This function will uses the Handle Value Notification received from the SoftDevice
+ * and checks if it is a notification of the NUS TX characteristic from the peer. If
+ * it is, this function will decode the data and send it to the
+ * application.
+ *
+ * @param[in] p_ble_nus_c Pointer to the NUS Client structure.
+ * @param[in] p_ble_evt Pointer to the BLE event received.
+ */
+static void on_hvx(ble_nus_c_t * p_ble_nus_c, ble_evt_t const * p_ble_evt)
+{
+ // HVX can only occur from client sending.
+ if ( (p_ble_nus_c->handles.nus_tx_handle != BLE_GATT_HANDLE_INVALID)
+ && (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_nus_c->handles.nus_tx_handle)
+ && (p_ble_nus_c->evt_handler != NULL))
+ {
+ ble_nus_c_evt_t ble_nus_c_evt;
+
+ ble_nus_c_evt.evt_type = BLE_NUS_C_EVT_NUS_TX_EVT;
+ ble_nus_c_evt.p_data = (uint8_t *)p_ble_evt->evt.gattc_evt.params.hvx.data;
+ ble_nus_c_evt.data_len = p_ble_evt->evt.gattc_evt.params.hvx.len;
+
+ p_ble_nus_c->evt_handler(p_ble_nus_c, &ble_nus_c_evt);
+ NRF_LOG_DEBUG("Client sending data.");
+ }
+}
+
+uint32_t ble_nus_c_init(ble_nus_c_t * p_ble_nus_c, ble_nus_c_init_t * p_ble_nus_c_init)
+{
+ uint32_t err_code;
+ ble_uuid_t uart_uuid;
+ ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;
+
+ VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
+ VERIFY_PARAM_NOT_NULL(p_ble_nus_c_init);
+
+ err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_ble_nus_c->uuid_type);
+ VERIFY_SUCCESS(err_code);
+
+ uart_uuid.type = p_ble_nus_c->uuid_type;
+ uart_uuid.uuid = BLE_UUID_NUS_SERVICE;
+
+ p_ble_nus_c->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_ble_nus_c->evt_handler = p_ble_nus_c_init->evt_handler;
+ p_ble_nus_c->handles.nus_tx_handle = BLE_GATT_HANDLE_INVALID;
+ p_ble_nus_c->handles.nus_rx_handle = BLE_GATT_HANDLE_INVALID;
+
+ return ble_db_discovery_evt_register(&uart_uuid);
+}
+
+void ble_nus_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ ble_nus_c_t * p_ble_nus_c = (ble_nus_c_t *)p_context;
+
+ if ((p_ble_nus_c == NULL) || (p_ble_evt == NULL))
+ {
+ return;
+ }
+
+ if ( (p_ble_nus_c->conn_handle != BLE_CONN_HANDLE_INVALID)
+ &&(p_ble_nus_c->conn_handle != p_ble_evt->evt.gap_evt.conn_handle)
+ )
+ {
+ return;
+ }
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GATTC_EVT_HVX:
+ on_hvx(p_ble_nus_c, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ if (p_ble_evt->evt.gap_evt.conn_handle == p_ble_nus_c->conn_handle
+ && p_ble_nus_c->evt_handler != NULL)
+ {
+ ble_nus_c_evt_t nus_c_evt;
+
+ nus_c_evt.evt_type = BLE_NUS_C_EVT_DISCONNECTED;
+
+ p_ble_nus_c->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt);
+ }
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+/**@brief Function for creating a message for writing to the CCCD. */
+static uint32_t cccd_configure(uint16_t conn_handle, uint16_t cccd_handle, bool enable)
+{
+ uint8_t buf[BLE_CCCD_VALUE_LEN];
+
+ buf[0] = enable ? BLE_GATT_HVX_NOTIFICATION : 0;
+ buf[1] = 0;
+
+ ble_gattc_write_params_t const write_params =
+ {
+ .write_op = BLE_GATT_OP_WRITE_REQ,
+ .flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE,
+ .handle = cccd_handle,
+ .offset = 0,
+ .len = sizeof(buf),
+ .p_value = buf
+ };
+
+ return sd_ble_gattc_write(conn_handle, &write_params);
+}
+
+
+uint32_t ble_nus_c_tx_notif_enable(ble_nus_c_t * p_ble_nus_c)
+{
+ VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
+
+ if ( (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
+ ||(p_ble_nus_c->handles.nus_tx_cccd_handle == BLE_GATT_HANDLE_INVALID)
+ )
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+ return cccd_configure(p_ble_nus_c->conn_handle,p_ble_nus_c->handles.nus_tx_cccd_handle, true);
+}
+
+
+uint32_t ble_nus_c_string_send(ble_nus_c_t * p_ble_nus_c, uint8_t * p_string, uint16_t length)
+{
+ VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
+
+ if (length > BLE_NUS_MAX_DATA_LEN)
+ {
+ NRF_LOG_WARNING("Content too long.");
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ if (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
+ {
+ NRF_LOG_WARNING("Connection handle invalid.");
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ ble_gattc_write_params_t const write_params =
+ {
+ .write_op = BLE_GATT_OP_WRITE_CMD,
+ .flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE,
+ .handle = p_ble_nus_c->handles.nus_rx_handle,
+ .offset = 0,
+ .len = length,
+ .p_value = p_string
+ };
+
+ return sd_ble_gattc_write(p_ble_nus_c->conn_handle, &write_params);
+}
+
+
+uint32_t ble_nus_c_handles_assign(ble_nus_c_t * p_ble_nus,
+ uint16_t conn_handle,
+ ble_nus_c_handles_t const * p_peer_handles)
+{
+ VERIFY_PARAM_NOT_NULL(p_ble_nus);
+
+ p_ble_nus->conn_handle = conn_handle;
+ if (p_peer_handles != NULL)
+ {
+ p_ble_nus->handles.nus_tx_cccd_handle = p_peer_handles->nus_tx_cccd_handle;
+ p_ble_nus->handles.nus_tx_handle = p_peer_handles->nus_tx_handle;
+ p_ble_nus->handles.nus_rx_handle = p_peer_handles->nus_rx_handle;
+ }
+ return NRF_SUCCESS;
+}
+#endif // NRF_MODULE_ENABLED(BLE_NUS_C)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_nus_c/ble_nus_c.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_nus_c/ble_nus_c.h
new file mode 100644
index 0000000..1bdc182
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_nus_c/ble_nus_c.h
@@ -0,0 +1,272 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/**@file
+ *
+ * @defgroup ble_nus_c Nordic UART Service Client
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Nordic UART Service Client module.
+ *
+ * @details This module contains the APIs and types exposed by the Nordic UART Service Client
+ * module. These APIs and types can be used by the application to perform discovery of
+ * the Nordic UART Service at the peer and interact with it.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_nus_c_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_NUS_C_BLE_OBSERVER_PRIO,
+ * ble_nus_c_on_ble_evt, &instance);
+ * @endcode
+ *
+ */
+
+
+#ifndef BLE_NUS_C_H__
+#define BLE_NUS_C_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ble.h"
+#include "ble_gatt.h"
+#include "ble_db_discovery.h"
+#include "nrf_sdh_ble.h"
+
+#include "sdk_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_nus_c instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_NUS_C_DEF(_name) \
+static ble_nus_c_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_NUS_C_BLE_OBSERVER_PRIO, \
+ ble_nus_c_on_ble_evt, &_name)
+
+/** @brief Macro for defining multiple ble_nus_c instances.
+ *
+ * @param _name Name of the array of instances.
+ * @param _cnt Number of instances to define.
+ * @hideinitializer
+ */
+#define BLE_NUS_C_ARRAY_DEF(_name, _cnt) \
+static ble_nus_c_t _name[_cnt]; \
+NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
+ BLE_NUS_C_BLE_OBSERVER_PRIO, \
+ ble_nus_c_on_ble_evt, &_name, _cnt)
+
+#define NUS_BASE_UUID {{0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E}} /**< Used vendor specific UUID. */
+
+#define BLE_UUID_NUS_SERVICE 0x0001 /**< The UUID of the Nordic UART Service. */
+#define BLE_UUID_NUS_RX_CHARACTERISTIC 0x0002 /**< The UUID of the RX Characteristic. */
+#define BLE_UUID_NUS_TX_CHARACTERISTIC 0x0003 /**< The UUID of the TX Characteristic. */
+
+#define OPCODE_LENGTH 1
+#define HANDLE_LENGTH 2
+
+/**@brief Maximum length of data (in bytes) that can be transmitted to the peer by the Nordic UART service module. */
+#if defined(NRF_SDH_BLE_GATT_MAX_MTU_SIZE) && (NRF_SDH_BLE_GATT_MAX_MTU_SIZE != 0)
+ #define BLE_NUS_MAX_DATA_LEN (NRF_SDH_BLE_GATT_MAX_MTU_SIZE - OPCODE_LENGTH - HANDLE_LENGTH)
+#else
+ #define BLE_NUS_MAX_DATA_LEN (BLE_GATT_MTU_SIZE_DEFAULT - OPCODE_LENGTH - HANDLE_LENGTH)
+ #warning NRF_SDH_BLE_GATT_MAX_MTU_SIZE is not defined.
+#endif
+
+
+/**@brief NUS Client event type. */
+typedef enum
+{
+ BLE_NUS_C_EVT_DISCOVERY_COMPLETE, /**< Event indicating that the NUS service and its characteristics was found. */
+ BLE_NUS_C_EVT_NUS_TX_EVT, /**< Event indicating that the central has received something from a peer. */
+ BLE_NUS_C_EVT_DISCONNECTED /**< Event indicating that the NUS server has disconnected. */
+} ble_nus_c_evt_type_t;
+
+/**@brief Handles on the connected peer device needed to interact with it. */
+typedef struct
+{
+ uint16_t nus_tx_handle; /**< Handle of the NUS TX characteristic as provided by a discovery. */
+ uint16_t nus_tx_cccd_handle; /**< Handle of the CCCD of the NUS TX characteristic as provided by a discovery. */
+ uint16_t nus_rx_handle; /**< Handle of the NUS RX characteristic as provided by a discovery. */
+} ble_nus_c_handles_t;
+
+/**@brief Structure containing the NUS event data received from the peer. */
+typedef struct
+{
+ ble_nus_c_evt_type_t evt_type;
+ uint16_t conn_handle;
+ uint16_t max_data_len;
+ uint8_t * p_data;
+ uint8_t data_len;
+ ble_nus_c_handles_t handles; /**< Handles on which the Nordic Uart service characteristics was discovered on the peer device. This will be filled if the evt_type is @ref BLE_NUS_C_EVT_DISCOVERY_COMPLETE.*/
+} ble_nus_c_evt_t;
+
+// Forward declaration of the ble_nus_t type.
+typedef struct ble_nus_c_s ble_nus_c_t;
+
+/**@brief Event handler type.
+ *
+ * @details This is the type of the event handler that should be provided by the application
+ * of this module to receive events.
+ */
+typedef void (* ble_nus_c_evt_handler_t)(ble_nus_c_t * p_ble_nus_c, ble_nus_c_evt_t const * p_evt);
+
+/**@brief NUS Client structure. */
+struct ble_nus_c_s
+{
+ uint8_t uuid_type; /**< UUID type. */
+ uint16_t conn_handle; /**< Handle of the current connection. Set with @ref ble_nus_c_handles_assign when connected. */
+ ble_nus_c_handles_t handles; /**< Handles on the connected peer device needed to interact with it. */
+ ble_nus_c_evt_handler_t evt_handler; /**< Application event handler to be called when there is an event related to the NUS. */
+};
+
+/**@brief NUS Client initialization structure. */
+typedef struct
+{
+ ble_nus_c_evt_handler_t evt_handler;
+} ble_nus_c_init_t;
+
+
+/**@brief Function for initializing the Nordic UART client module.
+ *
+ * @details This function registers with the Database Discovery module
+ * for the NUS. Doing so will make the Database Discovery
+ * module look for the presence of a NUS instance at the peer when a
+ * discovery is started.
+ *
+ * @param[in] p_ble_nus_c Pointer to the NUS client structure.
+ * @param[in] p_ble_nus_c_init Pointer to the NUS initialization structure containing the
+ * initialization information.
+ *
+ * @retval NRF_SUCCESS If the module was initialized successfully. Otherwise, an error
+ * code is returned. This function
+ * propagates the error code returned by the Database Discovery module API
+ * @ref ble_db_discovery_evt_register.
+ */
+uint32_t ble_nus_c_init(ble_nus_c_t * p_ble_nus_c, ble_nus_c_init_t * p_ble_nus_c_init);
+
+
+/**@brief Function for handling events from the database discovery module.
+ *
+ * @details This function will handle an event from the database discovery module, and determine
+ * if it relates to the discovery of NUS at the peer. If so, it will
+ * call the application's event handler indicating that NUS has been
+ * discovered at the peer. It also populates the event with the service related
+ * information before providing it to the application.
+ *
+ * @param[in] p_ble_nus_c Pointer to the NUS client structure.
+ * @param[in] p_evt Pointer to the event received from the database discovery module.
+ */
+ void ble_nus_c_on_db_disc_evt(ble_nus_c_t * p_ble_nus_c, ble_db_discovery_evt_t * p_evt);
+
+
+/**@brief Function for handling BLE events from the SoftDevice.
+ *
+ * @details This function handles the BLE events received from the SoftDevice. If a BLE
+ * event is relevant to the NUS module, it is used to update
+ * internal variables and, if necessary, send events to the application.
+ *
+ * @param[in] p_ble_evt Pointer to the BLE event.
+ * @param[in] p_context Pointer to the NUS client structure.
+ */
+void ble_nus_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for requesting the peer to start sending notification of TX characteristic.
+ *
+ * @details This function enables notifications of the NUS TX characteristic at the peer
+ * by writing to the CCCD of the NUS TX characteristic.
+ *
+ * @param p_ble_nus_c Pointer to the NUS client structure.
+ *
+ * @retval NRF_SUCCESS If the SoftDevice has been requested to write to the CCCD of the peer.
+ * Otherwise, an error code is returned. This function propagates the error
+ * code returned by the SoftDevice API @ref sd_ble_gattc_write.
+ */
+uint32_t ble_nus_c_tx_notif_enable(ble_nus_c_t * p_ble_nus_c);
+
+
+/**@brief Function for sending a string to the server.
+ *
+ * @details This function writes the RX characteristic of the server.
+ *
+ * @param[in] p_ble_nus_c Pointer to the NUS client structure.
+ * @param[in] p_string String to be sent.
+ * @param[in] length Length of the string.
+ *
+ * @retval NRF_SUCCESS If the string was sent successfully. Otherwise, an error code is returned.
+ */
+uint32_t ble_nus_c_string_send(ble_nus_c_t * p_ble_nus_c, uint8_t * p_string, uint16_t length);
+
+
+/**@brief Function for assigning handles to a this instance of nus_c.
+ *
+ * @details Call this function when a link has been established with a peer to
+ * associate this link to this instance of the module. This makes it
+ * possible to handle several link and associate each link to a particular
+ * instance of this module. The connection handle and attribute handles will be
+ * provided from the discovery event @ref BLE_NUS_C_EVT_DISCOVERY_COMPLETE.
+ *
+ * @param[in] p_ble_nus_c Pointer to the NUS client structure instance to associate with these
+ * handles.
+ * @param[in] conn_handle Connection handle to associated with the given NUS Instance.
+ * @param[in] p_peer_handles Attribute handles on the NUS server that you want this NUS client to
+ * interact with.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_NULL If a p_nus was a NULL pointer.
+ */
+uint32_t ble_nus_c_handles_assign(ble_nus_c_t * p_ble_nus_c,
+ uint16_t conn_handle,
+ ble_nus_c_handles_t const * p_peer_handles);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_NUS_C_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_rscs/ble_rscs.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_rscs/ble_rscs.c
new file mode 100644
index 0000000..59fed13
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_rscs/ble_rscs.c
@@ -0,0 +1,417 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Attention!
+ * To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+
+#include "sdk_common.h"
+
+#if NRF_MODULE_ENABLED(BLE_RSCS)
+
+#include "ble_rscs.h"
+#include <string.h>
+#include "ble.h"
+#include "ble_srv_common.h"
+
+#define OPCODE_LENGTH 1 /**< Length of opcode inside Running Speed and Cadence Measurement packet. */
+#define HANDLE_LENGTH 2 /**< Length of handle inside Running Speed and Cadence Measurement packet. */
+#define MAX_RSCM_LEN (BLE_GATT_ATT_MTU_DEFAULT - OPCODE_LENGTH - HANDLE_LENGTH) /**< Maximum size of a transmitted Running Speed and Cadence Measurement. */
+
+// Running Speed and Cadence Measurement flag bits
+#define RSC_MEAS_FLAG_INSTANT_STRIDE_LEN_PRESENT (0x01 << 0) /**< Instantaneous Stride Length Present flag bit. */
+#define RSC_MEAS_FLAG_TOTAL_DISTANCE_PRESENT (0x01 << 1) /**< Total Distance Present flag bit. */
+#define RSC_MEAS_FLAG_WALKING_OR_RUNNING_BIT (0x01 << 2) /**< Walking or Running Status flag bit. */
+
+
+/**@brief Function for handling the Connect event.
+ *
+ * @param[in] p_rscs Running Speed and Cadence Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_connect(ble_rscs_t * p_rscs, ble_evt_t const * p_ble_evt)
+{
+ p_rscs->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+}
+
+
+/**@brief Function for handling the Disconnect event.
+ *
+ * @param[in] p_rscs Running Speed and Cadence Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_disconnect(ble_rscs_t * p_rscs, ble_evt_t const * p_ble_evt)
+{
+ UNUSED_PARAMETER(p_ble_evt);
+ p_rscs->conn_handle = BLE_CONN_HANDLE_INVALID;
+}
+
+
+/**@brief Function for handling the write events to the RSCS Measurement characteristic.
+ *
+ * @param[in] p_rscs Running Speed and Cadence Service structure.
+ * @param[in] p_evt_write Write event received from the BLE stack.
+ */
+static void on_meas_cccd_write(ble_rscs_t * p_rscs, ble_gatts_evt_write_t const * p_evt_write)
+{
+ if (p_evt_write->len == 2)
+ {
+ // CCCD written, update notification state
+ if (p_rscs->evt_handler != NULL)
+ {
+ ble_rscs_evt_t evt;
+
+ if (ble_srv_is_notification_enabled(p_evt_write->data))
+ {
+ evt.evt_type = BLE_RSCS_EVT_NOTIFICATION_ENABLED;
+ }
+ else
+ {
+ evt.evt_type = BLE_RSCS_EVT_NOTIFICATION_DISABLED;
+ }
+
+ p_rscs->evt_handler(p_rscs, &evt);
+ }
+ }
+}
+
+
+/**@brief Function for handling the Write event.
+ *
+ * @param[in] p_rscs Running Speed and Cadence Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_write(ble_rscs_t * p_rscs, ble_evt_t const * p_ble_evt)
+{
+ ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+ if (p_evt_write->handle == p_rscs->meas_handles.cccd_handle)
+ {
+ on_meas_cccd_write(p_rscs, p_evt_write);
+ }
+}
+
+
+void ble_rscs_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ if ((p_context == NULL) || (p_ble_evt == NULL))
+ {
+ return;
+ }
+
+ ble_rscs_t * p_rscs = (ble_rscs_t *)p_context;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ on_connect(p_rscs, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnect(p_rscs, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_WRITE:
+ on_write(p_rscs, p_ble_evt);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+
+/**@brief Function for encoding a RSCS Measurement.
+ *
+ * @param[in] p_rscs Running Speed and Cadence Service structure.
+ * @param[in] p_rsc_measurement Measurement to be encoded.
+ * @param[out] p_encoded_buffer Buffer where the encoded data will be written.
+ *
+ * @return Size of encoded data.
+ */
+static uint8_t rsc_measurement_encode(const ble_rscs_t * p_rscs,
+ const ble_rscs_meas_t * p_rsc_measurement,
+ uint8_t * p_encoded_buffer)
+{
+ uint8_t flags = 0;
+ uint8_t len = 1;
+
+ // Instantaneous speed field
+ len += uint16_encode(p_rsc_measurement->inst_speed, &p_encoded_buffer[len]);
+
+ // Instantaneous cadence field
+ p_encoded_buffer[len++] = p_rsc_measurement->inst_cadence;
+
+ // Instantaneous stride length field
+ if (p_rscs->feature & BLE_RSCS_FEATURE_INSTANT_STRIDE_LEN_BIT)
+ {
+ if (p_rsc_measurement->is_inst_stride_len_present)
+ {
+ flags |= RSC_MEAS_FLAG_INSTANT_STRIDE_LEN_PRESENT;
+ len += uint16_encode(p_rsc_measurement->inst_stride_length,
+ &p_encoded_buffer[len]);
+ }
+ }
+
+ // Total distance field
+ if (p_rscs->feature & BLE_RSCS_FEATURE_TOTAL_DISTANCE_BIT)
+ {
+ if (p_rsc_measurement->is_total_distance_present)
+ {
+ flags |= RSC_MEAS_FLAG_TOTAL_DISTANCE_PRESENT;
+ len += uint32_encode(p_rsc_measurement->total_distance, &p_encoded_buffer[len]);
+ }
+ }
+
+ // Flags field
+ if (p_rscs->feature & BLE_RSCS_FEATURE_WALKING_OR_RUNNING_STATUS_BIT)
+ {
+ if (p_rsc_measurement->is_running)
+ {
+ flags |= RSC_MEAS_FLAG_WALKING_OR_RUNNING_BIT;
+ }
+ }
+ p_encoded_buffer[0] = flags;
+
+ return len;
+}
+
+
+/**@brief Function for adding RSC Measurement characteristics.
+ *
+ * @param[in] p_rscs Running Speed and Cadence Service structure.
+ * @param[in] p_rscs_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t rsc_measurement_char_add(ble_rscs_t * p_rscs, const ble_rscs_init_t * p_rscs_init)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_md_t cccd_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+ uint8_t encoded_rcm[MAX_RSCM_LEN];
+
+ memset(&cccd_md, 0, sizeof(cccd_md));
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
+ cccd_md.write_perm = p_rscs_init->rsc_meas_attr_md.cccd_write_perm;
+ cccd_md.vloc = BLE_GATTS_VLOC_STACK;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.notify = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = &cccd_md;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_RSC_MEASUREMENT_CHAR);
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.read_perm = p_rscs_init->rsc_meas_attr_md.read_perm;
+ attr_md.write_perm = p_rscs_init->rsc_meas_attr_md.write_perm;
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 1;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = rsc_measurement_encode(p_rscs, &p_rscs_init->initial_rcm, encoded_rcm);
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = MAX_RSCM_LEN;
+ attr_char_value.p_value = encoded_rcm;
+
+ return sd_ble_gatts_characteristic_add(p_rscs->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_rscs->meas_handles);
+}
+
+
+/**@brief Function for adding RSC Feature characteristics.
+ *
+ * @param[in] p_rscs Running Speed and Cadence Service structure.
+ * @param[in] p_rscs_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t rsc_feature_char_add(ble_rscs_t * p_rscs, const ble_rscs_init_t * p_rscs_init)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+ uint16_t init_value_feature;
+ uint8_t init_value_encoded[2];
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = NULL;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_RSC_FEATURE_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.read_perm = p_rscs_init->rsc_feature_attr_md.read_perm;
+ attr_md.write_perm = p_rscs_init->rsc_feature_attr_md.write_perm;
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ init_value_feature = p_rscs_init->feature;
+ init_value_encoded[0] = init_value_feature & 0xFF;
+ init_value_encoded[1] = (init_value_feature >> 8) & 0xFF;
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = sizeof (uint16_t);
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = sizeof (uint16_t);
+ attr_char_value.p_value = init_value_encoded;
+
+ return sd_ble_gatts_characteristic_add(p_rscs->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_rscs->feature_handles);
+}
+
+
+uint32_t ble_rscs_init(ble_rscs_t * p_rscs, const ble_rscs_init_t * p_rscs_init)
+{
+ if (p_rscs == NULL || p_rscs_init == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ uint32_t err_code;
+ ble_uuid_t ble_uuid;
+
+ // Initialize service structure
+ p_rscs->evt_handler = p_rscs_init->evt_handler;
+ p_rscs->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_rscs->feature = p_rscs_init->feature;
+
+ // Add service
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_RUNNING_SPEED_AND_CADENCE);
+
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
+ &ble_uuid,
+ &p_rscs->service_handle);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add measurement characteristic
+ err_code = rsc_measurement_char_add(p_rscs, p_rscs_init);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add feature characteristic
+ err_code = rsc_feature_char_add(p_rscs, p_rscs_init);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_rscs_measurement_send(ble_rscs_t * p_rscs, ble_rscs_meas_t * p_measurement)
+{
+ if (p_rscs == NULL || p_measurement == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ uint32_t err_code;
+
+ // Send value if connected and notifying
+ if (p_rscs->conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ uint8_t encoded_rsc_meas[MAX_RSCM_LEN];
+ uint16_t len;
+ uint16_t hvx_len;
+ ble_gatts_hvx_params_t hvx_params;
+
+ len = rsc_measurement_encode(p_rscs, p_measurement, encoded_rsc_meas);
+ hvx_len = len;
+
+ memset(&hvx_params, 0, sizeof(hvx_params));
+
+ hvx_params.handle = p_rscs->meas_handles.value_handle;
+ hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
+ hvx_params.offset = 0;
+ hvx_params.p_len = &hvx_len;
+ hvx_params.p_data = encoded_rsc_meas;
+
+ err_code = sd_ble_gatts_hvx(p_rscs->conn_handle, &hvx_params);
+ if ((err_code == NRF_SUCCESS) && (hvx_len != len))
+ {
+ err_code = NRF_ERROR_DATA_SIZE;
+ }
+ }
+ else
+ {
+ err_code = NRF_ERROR_INVALID_STATE;
+ }
+
+ return err_code;
+}
+#endif // NRF_MODULE_ENABLED(BLE_RSCS)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_rscs/ble_rscs.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_rscs/ble_rscs.h
new file mode 100644
index 0000000..18ca265
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_rscs/ble_rscs.h
@@ -0,0 +1,201 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_rscs Running Speed and Cadence Service
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Running Speed and Cadence Service module.
+ *
+ * @details This module implements the Running Speed and Cadence Service. If enabled, notification
+ * of the Running Speead and Candence Measurement is performed when the application
+ * calls ble_rscs_measurement_send().
+ *
+ * If an event handler is supplied by the application, the Running Speed and Cadence
+ * Service will generate Running Speed and Cadence Service events to the application.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_rscs_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_RSCS_BLE_OBSERVER_PRIO,
+ * ble_rscs_on_ble_evt, &instance);
+ * @endcode
+ *
+ * @note Attention!
+ * To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+
+#ifndef BLE_RSCS_H__
+#define BLE_RSCS_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ble_srv_common.h"
+#include "nrf_sdh_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_rscs instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_RSCS_DEF(_name) \
+static ble_rscs_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_RSCS_BLE_OBSERVER_PRIO, \
+ ble_rscs_on_ble_evt, &_name)
+
+/**@brief Running Speed and Cadence Service feature bits. */
+#define BLE_RSCS_FEATURE_INSTANT_STRIDE_LEN_BIT (0x01 << 0) /**< Instantaneous Stride Length Measurement Supported bit. */
+#define BLE_RSCS_FEATURE_TOTAL_DISTANCE_BIT (0x01 << 1) /**< Total Distance Measurement Supported bit. */
+#define BLE_RSCS_FEATURE_WALKING_OR_RUNNING_STATUS_BIT (0x01 << 2) /**< Walking or Running Status Supported bit. */
+#define BLE_RSCS_FEATURE_CALIBRATION_PROCEDURE_BIT (0x01 << 3) /**< Calibration Procedure Supported bit. */
+#define BLE_RSCS_FEATURE_MULTIPLE_SENSORS_BIT (0x01 << 4) /**< Multiple Sensor Locations Supported bit. */
+
+
+/**@brief Running Speed and Cadence Service event type. */
+typedef enum
+{
+ BLE_RSCS_EVT_NOTIFICATION_ENABLED, /**< Running Speed and Cadence value notification enabled event. */
+ BLE_RSCS_EVT_NOTIFICATION_DISABLED /**< Running Speed and Cadence value notification disabled event. */
+} ble_rscs_evt_type_t;
+
+/**@brief Running Speed and Cadence Service event. */
+typedef struct
+{
+ ble_rscs_evt_type_t evt_type; /**< Type of event. */
+} ble_rscs_evt_t;
+
+// Forward declaration of the ble_rsc types.
+typedef struct ble_rscs_s ble_rscs_t;
+typedef struct ble_rscs_meas_s ble_rscs_meas_t;
+
+/**@brief Running Speed and Cadence Service event handler type. */
+typedef void (*ble_rscs_evt_handler_t) (ble_rscs_t * p_rscs, ble_rscs_evt_t * p_evt);
+
+/**@brief Running Speed and Cadence Service measurement structure. This contains a Running Speed and
+ * Cadence measurement.
+ */
+struct ble_rscs_meas_s
+{
+ bool is_inst_stride_len_present; /**< True if Instantaneous Stride Length is present in the measurement. */
+ bool is_total_distance_present; /**< True if Total Distance is present in the measurement. */
+ bool is_running; /**< True if running, False if walking. */
+ uint16_t inst_speed; /**< Instantaneous Speed. */
+ uint8_t inst_cadence; /**< Instantaneous Cadence. */
+ uint16_t inst_stride_length; /**< Instantaneous Stride Length. */
+ uint32_t total_distance; /**< Total Distance. */
+};
+
+/**@brief Running Speed and Cadence Service init structure. This contains all options and data
+ * needed for initialization of the service.
+ */
+typedef struct
+{
+ ble_rscs_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Running Speed and Cadence Service. */
+ ble_srv_cccd_security_mode_t rsc_meas_attr_md; /**< Initial security level for running speed and cadence measurement attribute */
+ ble_srv_security_mode_t rsc_feature_attr_md; /**< Initial security level for feature attribute */
+ uint16_t feature; /**< Initial value for features of sensor. */
+ ble_rscs_meas_t initial_rcm; /**< Initial Running Speed Cadence Measurement.*/
+} ble_rscs_init_t;
+
+/**@brief Running Speed and Cadence Service structure. This contains various status information for
+ * the service.
+ */
+struct ble_rscs_s
+{
+ ble_rscs_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Running Speed and Cadence Service. */
+ uint16_t service_handle; /**< Handle of Running Speed and Cadence Service (as provided by the BLE stack). */
+ ble_gatts_char_handles_t meas_handles; /**< Handles related to the Running Speed and Cadence Measurement characteristic. */
+ ble_gatts_char_handles_t feature_handles; /**< Handles related to the Running Speed and Cadence feature characteristic. */
+ uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
+ uint16_t feature; /**< Bit mask of features available on sensor. */
+};
+
+
+/**@brief Function for initializing the Running Speed and Cadence Service.
+ *
+ * @param[out] p_rscs Running Speed and Cadence Service structure. This structure will have to
+ * be supplied by the application. It will be initialized by this function,
+ * and will later be used to identify this particular service instance.
+ * @param[in] p_rscs_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
+ */
+uint32_t ble_rscs_init(ble_rscs_t * p_rscs, const ble_rscs_init_t * p_rscs_init);
+
+
+/**@brief Function for handling the Application's BLE Stack events.
+ *
+ * @details Handles all events from the BLE stack of interest to the Running Speed and Cadence
+ * Service.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Running Speed and Cadence Service structure.
+ */
+void ble_rscs_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for sending running speed and cadence measurement if notification has been enabled.
+ *
+ * @details The application calls this function after having performed a Running Speed and Cadence
+ * measurement. If notification has been enabled, the measurement data is encoded and sent
+ * to the client.
+ *
+ * @param[in] p_rscs Running Speed and Cadence Service structure.
+ * @param[in] p_measurement Pointer to new running speed and cadence measurement.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+uint32_t ble_rscs_measurement_send(ble_rscs_t * p_rscs, ble_rscs_meas_t * p_measurement);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_RSCS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_rscs_c/ble_rscs_c.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_rscs_c/ble_rscs_c.c
new file mode 100644
index 0000000..f9c16ad
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_rscs_c/ble_rscs_c.c
@@ -0,0 +1,390 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/**@cond To Make Doxygen skip documentation generation for this file.
+ * @{
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_RSCS_C)
+#include "ble_rscs_c.h"
+#include "ble_db_discovery.h"
+#include "ble_types.h"
+#include "ble_srv_common.h"
+#include "ble_gattc.h"
+
+#define NRF_LOG_MODULE_NAME ble_rscs_c
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define TX_BUFFER_MASK 0x07 /**< TX Buffer mask, must be a mask of continuous zeroes, followed by continuous sequence of ones: 000...111. */
+#define TX_BUFFER_SIZE (TX_BUFFER_MASK + 1) /**< Size of send buffer, which is 1 higher than the mask. */
+
+#define WRITE_MESSAGE_LENGTH BLE_CCCD_VALUE_LEN /**< Length of the write message for CCCD. */
+
+typedef enum
+{
+ READ_REQ, /**< Type identifying that this tx_message is a read request. */
+ WRITE_REQ /**< Type identifying that this tx_message is a write request. */
+} tx_request_t;
+
+/**@brief Structure for writing a message to the peer, i.e. CCCD.
+ */
+typedef struct
+{
+ uint8_t gattc_value[WRITE_MESSAGE_LENGTH]; /**< The message to write. */
+ ble_gattc_write_params_t gattc_params; /**< GATTC parameters for this message. */
+} write_params_t;
+
+/**@brief Structure for holding data to be transmitted to the connected central.
+ */
+typedef struct
+{
+ uint16_t conn_handle; /**< Connection handle to be used when transmitting this message. */
+ tx_request_t type; /**< Type of this message, i.e. read or write message. */
+ union
+ {
+ uint16_t read_handle; /**< Read request message. */
+ write_params_t write_req; /**< Write request message. */
+ } req;
+} tx_message_t;
+
+
+static tx_message_t m_tx_buffer[TX_BUFFER_SIZE]; /**< Transmit buffer for messages to be transmitted to the central. */
+static uint32_t m_tx_insert_index = 0; /**< Current index in the transmit buffer where the next message should be inserted. */
+static uint32_t m_tx_index = 0; /**< Current index in the transmit buffer from where the next message to be transmitted resides. */
+
+
+/**@brief Function for passing any pending request from the buffer to the stack.
+ */
+static void tx_buffer_process(void)
+{
+ if (m_tx_index != m_tx_insert_index)
+ {
+ uint32_t err_code;
+
+ if (m_tx_buffer[m_tx_index].type == READ_REQ)
+ {
+ err_code = sd_ble_gattc_read(m_tx_buffer[m_tx_index].conn_handle,
+ m_tx_buffer[m_tx_index].req.read_handle,
+ 0);
+ }
+ else
+ {
+ err_code = sd_ble_gattc_write(m_tx_buffer[m_tx_index].conn_handle,
+ &m_tx_buffer[m_tx_index].req.write_req.gattc_params);
+ }
+ if (err_code == NRF_SUCCESS)
+ {
+ NRF_LOG_DEBUG("SD Read/Write API returns Success.");
+ m_tx_index++;
+ m_tx_index &= TX_BUFFER_MASK;
+ }
+ else
+ {
+ NRF_LOG_DEBUG("SD Read/Write API returns error. This message sending will be "
+ "attempted again..");
+ }
+ }
+}
+
+
+/**@brief Function for handling write response events.
+ *
+ * @param[in] p_ble_rscs_c Pointer to the Running Speed and Cadence Client structure.
+ * @param[in] p_ble_evt Pointer to the BLE event received.
+ */
+static void on_write_rsp(ble_rscs_c_t * p_ble_rscs_c, const ble_evt_t * p_ble_evt)
+{
+ // Check if the event if on the link for this instance
+ if (p_ble_rscs_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
+ {
+ return;
+ }
+ // Check if there is any message to be sent across to the peer and send it.
+ tx_buffer_process();
+}
+
+
+/**@brief Function for handling Handle Value Notification received from the SoftDevice.
+ *
+ * @details This function will uses the Handle Value Notification received from the SoftDevice
+ * and checks if it is a notification of the Running Speed and Cadence measurement from
+ * the peer. If it is, this function will decode the Running Speed measurement and send it
+ * to the application.
+ *
+ * @param[in] p_ble_rscs_c Pointer to the Running Speed and Cadence Client structure.
+ * @param[in] p_ble_evt Pointer to the BLE event received.
+ */
+static void on_hvx(ble_rscs_c_t * p_ble_rscs_c, const ble_evt_t * p_ble_evt)
+{
+ const ble_gattc_evt_hvx_t * p_notif = &p_ble_evt->evt.gattc_evt.params.hvx;
+
+ // Check if the event if on the link for this instance
+ if (p_ble_rscs_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
+ {
+ return;
+ }
+
+ // Check if this is a Running Speed and Cadence notification.
+ if (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_rscs_c->peer_db.rsc_handle)
+ {
+ uint32_t index = 0;
+ ble_rscs_c_evt_t ble_rscs_c_evt;
+ ble_rscs_c_evt.evt_type = BLE_RSCS_C_EVT_RSC_NOTIFICATION;
+ ble_rscs_c_evt.conn_handle = p_ble_evt->evt.gattc_evt.conn_handle;
+
+ //lint -save -e415 -e416 -e662 "Access of out of bounds pointer" "Creation of out of bounds pointer"
+
+ // Flags field
+ ble_rscs_c_evt.params.rsc.is_inst_stride_len_present = p_notif->data[index] >> BLE_RSCS_INSTANT_STRIDE_LEN_PRESENT & 0x01;
+ ble_rscs_c_evt.params.rsc.is_total_distance_present = p_notif->data[index] >> BLE_RSCS_TOTAL_DISTANCE_PRESENT & 0x01;
+ ble_rscs_c_evt.params.rsc.is_running = p_notif->data[index] >> BLE_RSCS_WALKING_OR_RUNNING_STATUS_BIT & 0x01;
+ index++;
+
+ // Instantaneous Speed
+ ble_rscs_c_evt.params.rsc.inst_speed = uint16_decode(&p_notif->data[index]);
+ index += sizeof(uint16_t);
+
+ // Instantaneous Cadence
+ ble_rscs_c_evt.params.rsc.inst_cadence = p_notif->data[index];
+ index++;
+
+ // Instantaneous Stride Length
+ if (ble_rscs_c_evt.params.rsc.is_inst_stride_len_present == true)
+ {
+ ble_rscs_c_evt.params.rsc.inst_stride_length = uint16_decode(&p_notif->data[index]);
+ index += sizeof(uint16_t);
+ }
+
+ // Total distance field
+ if (ble_rscs_c_evt.params.rsc.is_total_distance_present == true)
+ {
+ ble_rscs_c_evt.params.rsc.total_distance = uint32_decode(&p_notif->data[index]);
+ //index += sizeof(uint32_t);
+ }
+
+ p_ble_rscs_c->evt_handler(p_ble_rscs_c, &ble_rscs_c_evt);
+
+ //lint -restore
+ }
+}
+
+
+/**@brief Function for handling events from the database discovery module.
+ *
+ * @details This function will handle an event from the database discovery module, and determine
+ * if it relates to the discovery of heart rate service at the peer. If so, it will
+ * call the application's event handler indicating that the Running Speed and Cadence
+ * service has been discovered at the peer. It also populates the event with the service
+ * related information before providing it to the application.
+ *
+ * @param[in] p_evt Pointer to the event received from the database discovery module.
+ *
+ */
+void ble_rscs_on_db_disc_evt(ble_rscs_c_t * p_ble_rscs_c, const ble_db_discovery_evt_t * p_evt)
+{
+ // Check if the Heart Rate Service was discovered.
+ if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE &&
+ p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_RUNNING_SPEED_AND_CADENCE &&
+ p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE)
+ {
+ ble_rscs_c_evt_t evt;
+ evt.conn_handle = p_evt->conn_handle;
+
+ // Find the CCCD Handle of the Running Speed and Cadence characteristic.
+ for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
+ {
+ if (p_evt->params.discovered_db.charateristics[i].characteristic.uuid.uuid ==
+ BLE_UUID_RSC_MEASUREMENT_CHAR)
+ {
+ // Found Running Speed and Cadence characteristic. Store CCCD handle and break.
+ evt.params.rscs_db.rsc_cccd_handle =
+ p_evt->params.discovered_db.charateristics[i].cccd_handle;
+ evt.params.rscs_db.rsc_handle =
+ p_evt->params.discovered_db.charateristics[i].characteristic.handle_value;
+ break;
+ }
+ }
+
+ NRF_LOG_DEBUG("Running Speed and Cadence Service discovered at peer.");
+
+ //If the instance has been assigned prior to db_discovery, assign the db_handles
+ if (p_ble_rscs_c->conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ if ((p_ble_rscs_c->peer_db.rsc_cccd_handle == BLE_GATT_HANDLE_INVALID)&&
+ (p_ble_rscs_c->peer_db.rsc_handle == BLE_GATT_HANDLE_INVALID))
+ {
+ p_ble_rscs_c->peer_db = evt.params.rscs_db;
+ }
+ }
+
+ evt.evt_type = BLE_RSCS_C_EVT_DISCOVERY_COMPLETE;
+
+ p_ble_rscs_c->evt_handler(p_ble_rscs_c, &evt);
+ }
+}
+
+
+uint32_t ble_rscs_c_init(ble_rscs_c_t * p_ble_rscs_c, ble_rscs_c_init_t * p_ble_rscs_c_init)
+{
+ VERIFY_PARAM_NOT_NULL(p_ble_rscs_c);
+ VERIFY_PARAM_NOT_NULL(p_ble_rscs_c_init);
+
+ ble_uuid_t rscs_uuid;
+
+ rscs_uuid.type = BLE_UUID_TYPE_BLE;
+ rscs_uuid.uuid = BLE_UUID_RUNNING_SPEED_AND_CADENCE;
+
+ p_ble_rscs_c->evt_handler = p_ble_rscs_c_init->evt_handler;
+ p_ble_rscs_c->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_ble_rscs_c->peer_db.rsc_cccd_handle = BLE_GATT_HANDLE_INVALID;
+ p_ble_rscs_c->peer_db.rsc_handle = BLE_GATT_HANDLE_INVALID;
+
+ return ble_db_discovery_evt_register(&rscs_uuid);
+}
+
+
+uint32_t ble_rscs_c_handles_assign(ble_rscs_c_t * p_ble_rscs_c,
+ uint16_t conn_handle,
+ ble_rscs_c_db_t * p_peer_handles)
+{
+ VERIFY_PARAM_NOT_NULL(p_ble_rscs_c);
+ p_ble_rscs_c->conn_handle = conn_handle;
+ if (p_peer_handles != NULL)
+ {
+ p_ble_rscs_c->peer_db = *p_peer_handles;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for handling Disconnected event received from the SoftDevice.
+ *
+ * @details This function check if the disconnect event is happening on the link
+ * associated with the current instance of the module, if so it will set its
+ * conn_handle to invalid.
+ *
+ * @param[in] p_ble_rscs_c Pointer to the RSC Client structure.
+ * @param[in] p_ble_evt Pointer to the BLE event received.
+ */
+static void on_disconnected(ble_rscs_c_t * p_ble_rscs_c, const ble_evt_t * p_ble_evt)
+{
+ if (p_ble_rscs_c->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
+ {
+ p_ble_rscs_c->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_ble_rscs_c->peer_db.rsc_cccd_handle = BLE_GATT_HANDLE_INVALID;
+ p_ble_rscs_c->peer_db.rsc_handle = BLE_GATT_HANDLE_INVALID;
+ }
+}
+
+
+void ble_rscs_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ if ((p_context == NULL) || (p_ble_evt == NULL))
+ {
+ return;
+ }
+
+ ble_rscs_c_t * p_ble_rscs_c = (ble_rscs_c_t *)p_context;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GATTC_EVT_HVX:
+ on_hvx(p_ble_rscs_c, p_ble_evt);
+ break;
+
+ case BLE_GATTC_EVT_WRITE_RSP:
+ on_write_rsp(p_ble_rscs_c, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnected(p_ble_rscs_c, p_ble_evt);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/**@brief Function for creating a message for writing to the CCCD.
+ */
+static uint32_t cccd_configure(uint16_t conn_handle, uint16_t handle_cccd, bool enable)
+{
+ NRF_LOG_DEBUG("Configuring CCCD. CCCD Handle = %d, Connection Handle = %d",
+ handle_cccd, conn_handle);
+
+ tx_message_t * p_msg;
+ uint16_t cccd_val = enable ? BLE_GATT_HVX_NOTIFICATION : 0;
+
+ p_msg = &m_tx_buffer[m_tx_insert_index++];
+ m_tx_insert_index &= TX_BUFFER_MASK;
+
+ p_msg->req.write_req.gattc_params.handle = handle_cccd;
+ p_msg->req.write_req.gattc_params.len = WRITE_MESSAGE_LENGTH;
+ p_msg->req.write_req.gattc_params.p_value = p_msg->req.write_req.gattc_value;
+ p_msg->req.write_req.gattc_params.offset = 0;
+ p_msg->req.write_req.gattc_params.write_op = BLE_GATT_OP_WRITE_REQ;
+ p_msg->req.write_req.gattc_value[0] = LSB_16(cccd_val);
+ p_msg->req.write_req.gattc_value[1] = MSB_16(cccd_val);
+ p_msg->conn_handle = conn_handle;
+ p_msg->type = WRITE_REQ;
+
+ tx_buffer_process();
+ return NRF_SUCCESS;
+}
+
+
+uint32_t ble_rscs_c_rsc_notif_enable(ble_rscs_c_t * p_ble_rscs_c)
+{
+ VERIFY_PARAM_NOT_NULL(p_ble_rscs_c);
+
+ if (p_ble_rscs_c->conn_handle == BLE_CONN_HANDLE_INVALID)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ return cccd_configure(p_ble_rscs_c->conn_handle, p_ble_rscs_c->peer_db.rsc_cccd_handle, true);
+}
+
+/** @}
+ * @endcond
+ */
+#endif // NRF_MODULE_ENABLED(BLE_RSCS_C)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_rscs_c/ble_rscs_c.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_rscs_c/ble_rscs_c.h
new file mode 100644
index 0000000..664d03b
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_rscs_c/ble_rscs_c.h
@@ -0,0 +1,231 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/**
+ * @defgroup ble_rscs_c Running Speed and Cadence Service Client
+ * @{
+ * @ingroup ble_sdk_srv
+ *
+ * @details This module contains the APIs and types exposed by the Running Speed and Cadence
+ * Service Client module. These APIs and types can be used by the application to perform
+ * discovery of Running Speed and Cadence Service at the peer and interact with it.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_rscs_c_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_RSCS_C_BLE_OBSERVER_PRIO,
+ * ble_rscs_c_on_ble_evt, &instance);
+ * @endcode
+ */
+#ifndef BLE_RSCS_C_H__
+#define BLE_RSCS_C_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ble.h"
+#include "ble_db_discovery.h"
+#include "nrf_sdh_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_rscs_c instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_RSCS_C_DEF(_name) \
+static ble_rscs_c_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_RSCS_C_BLE_OBSERVER_PRIO, \
+ ble_rscs_c_on_ble_evt, &_name)
+
+/** @brief Macro for defining multiple ble_rscs_c instances.
+ *
+ * @param _name Name of the array of instances.
+ * @param _cnt Number of instances to define.
+ * @hideinitializer
+ */
+#define BLE_RSCS_C_ARRAY_DEF(_name, _cnt) \
+static ble_rscs_c_t _name[_cnt]; \
+NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
+ BLE_RSCS_C_BLE_OBSERVER_PRIO, \
+ ble_rscs_c_on_ble_evt, &_name, _cnt)
+
+#define BLE_RSCS_INSTANT_STRIDE_LEN_PRESENT 0x00 /**< Instantaneous Stride Length Measurement Supported bit. */
+#define BLE_RSCS_TOTAL_DISTANCE_PRESENT 0x01 /**< Total Distance Measurement Supported bit. */
+#define BLE_RSCS_WALKING_OR_RUNNING_STATUS_BIT 0x02 /**< Walking or Running Status Supported bit. */
+
+
+/**@brief Structure containing the handles related to the Running Speed and Cadence Service found on the peer. */
+typedef struct
+{
+ uint16_t rsc_cccd_handle; /**< Handle of the CCCD of the Running Speed and Cadence characteristic. */
+ uint16_t rsc_handle; /**< Handle of the Running Speed and Cadence characteristic as provided by the SoftDevice. */
+} ble_rscs_c_db_t;
+
+/**@brief RSCS Client event type. */
+typedef enum
+{
+ BLE_RSCS_C_EVT_DISCOVERY_COMPLETE = 1, /**< Event indicating that the Running Speed and Cadence Service has been discovered at the peer. */
+ BLE_RSCS_C_EVT_RSC_NOTIFICATION /**< Event indicating that a notification of the Running Speed and Cadence measurement characteristic has been received from the peer. */
+} ble_rscs_c_evt_type_t;
+
+/**@brief Structure containing the Running Speed and Cadence measurement received from the peer. */
+typedef struct
+{
+ bool is_inst_stride_len_present; /**< True if Instantaneous Stride Length is present in the measurement. */
+ bool is_total_distance_present; /**< True if Total Distance is present in the measurement. */
+ bool is_running; /**< True if running, False if walking. */
+ uint16_t inst_speed; /**< Instantaneous Speed. */
+ uint8_t inst_cadence; /**< Instantaneous Cadence. */
+ uint16_t inst_stride_length; /**< Instantaneous Stride Length. */
+ uint32_t total_distance; /**< Total Distance. */
+} ble_rsc_t;
+
+/**@brief Running Speed and Cadence Event structure. */
+typedef struct
+{
+ ble_rscs_c_evt_type_t evt_type; /**< Type of the event. */
+ uint16_t conn_handle; /**< Connection handle on which the rscs_c event occured.*/
+ union
+ {
+ ble_rscs_c_db_t rscs_db; /**< Running Speed and Cadence Service related handles found on the peer device. This will be filled if the evt_type is @ref BLE_RSCS_C_EVT_DISCOVERY_COMPLETE.*/
+ ble_rsc_t rsc; /**< Running Speed and Cadence measurement received. This will be filled if the evt_type is @ref BLE_RSCS_C_EVT_RSC_NOTIFICATION. */
+ } params;
+} ble_rscs_c_evt_t;
+
+// Forward declaration of the ble_rscs_c_t type.
+typedef struct ble_rscs_c_s ble_rscs_c_t;
+
+/**@brief Event handler type.
+ *
+ * @details This is the type of the event handler that should be provided by the application
+ * of this module in order to receive events.
+ */
+typedef void (* ble_rscs_c_evt_handler_t) (ble_rscs_c_t * p_ble_rscs_c, ble_rscs_c_evt_t * p_evt);
+
+/**@brief Running Speed and Cadence client structure. */
+struct ble_rscs_c_s
+{
+ uint16_t conn_handle; /**< Connection handle as provided by the SoftDevice. */
+ ble_rscs_c_db_t peer_db; /**< Handles related to RSCS on the peer*/
+ ble_rscs_c_evt_handler_t evt_handler; /**< Application event handler to be called when there is an event related to the Running Speed and Cadence service. */
+};
+
+/**@brief Running Speed and Cadence client initialization structure. */
+typedef struct
+{
+ ble_rscs_c_evt_handler_t evt_handler; /**< Event handler to be called by the Running Speed and Cadence Client module whenever there is an event related to the Running Speed and Cadence Service. */
+} ble_rscs_c_init_t;
+
+
+/**@brief Function for initializing the Running Speed and Cadence Service Client module.
+ *
+ * @details This function will initialize the module and set up Database Discovery to discover
+ * the Running Speed and Cadence Service. After calling this function, call @ref ble_db_discovery_start
+ * to start discovery once a link with a peer has been established.
+ *
+ * @param[out] p_ble_rscs_c Pointer to the RSC Service client structure.
+ * @param[in] p_ble_rscs_c_init Pointer to the RSC Service initialization structure containing
+ * the initialization information.
+ *
+ * @retval NRF_SUCCESS Operation success.
+ * @retval NRF_ERROR_NULL A parameter is NULL.
+ * Otherwise, an error code returned by @ref ble_db_discovery_evt_register.
+ */
+uint32_t ble_rscs_c_init(ble_rscs_c_t * p_ble_rscs_c, ble_rscs_c_init_t * p_ble_rscs_c_init);
+
+
+/**@brief Function for handling the Application's BLE Stack events.
+ *
+ * @details Handles all events from the BLE stack of interest to the Running Speed and Cadence
+ * Service client.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Running Speed and Cadence Service client structure.
+ */
+void ble_rscs_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+uint32_t ble_rscs_c_rsc_notif_enable(ble_rscs_c_t * p_ble_rscs_c);
+
+
+/**@brief Function for handling events from the database discovery module.
+ *
+ * @details Call this function when getting a callback event from the DB discovery modue.
+ * This function will handle an event from the database discovery module, and determine
+ * if it relates to the discovery of Running Speed and Cadence service at the peer.
+ * If so, it will call the application's event handler indicating that the RSC service has
+ * been discovered at the peer. It also populates the event with the service related
+ * information before providing it to the application.
+ *
+ * @param p_ble_rscs_c Pointer to the Runnind Speed and Cadence Service client structure.
+ * @param[in] p_evt Pointer to the event received from the database discovery module.
+ */
+void ble_rscs_on_db_disc_evt(ble_rscs_c_t * p_ble_rscs_c, ble_db_discovery_evt_t const * p_evt);
+
+
+/**@brief Function for assigning handles to a this instance of rscs_c.
+ *
+ * @details Call this function when a link has been established with a peer to
+ * associate this link to this instance of the module. This makes it
+ * possible to handle several link and associate each link to a particular
+ * instance of this module. The connection handle and attribute handles will be
+ * provided from the discovery event @ref BLE_RSCS_C_EVT_DISCOVERY_COMPLETE.
+ *
+ * @param[in] p_ble_rscs_c Pointer to the RSC client structure instance to associate.
+ * @param[in] conn_handle Connection handle to associated with the given RSCS Client Instance.
+ * @param[in] p_peer_handles Attribute handles on the RSCS server that you want this RSCS client
+ * to interact with.
+ */
+uint32_t ble_rscs_c_handles_assign(ble_rscs_c_t * p_ble_rscs_c,
+ uint16_t conn_handle,
+ ble_rscs_c_db_t * p_peer_handles);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_RSCS_C_H__
+
+/** @} */ // End tag for the file.
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_tps/ble_tps.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_tps/ble_tps.c
new file mode 100644
index 0000000..9f49541
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_tps/ble_tps.c
@@ -0,0 +1,170 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Attention!
+ * To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_TPS)
+#include "ble_tps.h"
+#include <string.h>
+#include "ble_srv_common.h"
+
+
+/**@brief Function for handling the Connect event.
+ *
+ * @param[in] p_tps TX Power Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_connect(ble_tps_t * p_tps, ble_evt_t const * p_ble_evt)
+{
+ p_tps->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+}
+
+
+void ble_tps_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ ble_tps_t * p_tps = (ble_tps_t *)p_context;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ on_connect(p_tps, p_ble_evt);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+
+/**@brief Function for adding TX Power Level characteristics.
+ *
+ * @param[in] p_tps TX Power Service structure.
+ * @param[in] p_tps_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t tx_power_level_char_add(ble_tps_t * p_tps,
+ const ble_tps_init_t * p_tps_init)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t ble_uuid;
+ ble_gatts_attr_md_t attr_md;
+
+ memset(&char_md, 0, sizeof(char_md));
+
+ char_md.char_props.read = 1;
+ char_md.p_char_user_desc = NULL;
+ char_md.p_char_pf = NULL;
+ char_md.p_user_desc_md = NULL;
+ char_md.p_cccd_md = NULL;
+ char_md.p_sccd_md = NULL;
+
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_TX_POWER_LEVEL_CHAR);
+
+ memset(&attr_md, 0, sizeof(attr_md));
+
+ attr_md.read_perm = p_tps_init->tps_attr_md.read_perm;
+ attr_md.write_perm = p_tps_init->tps_attr_md.write_perm;
+ attr_md.vloc = BLE_GATTS_VLOC_STACK;
+ attr_md.rd_auth = 0;
+ attr_md.wr_auth = 0;
+ attr_md.vlen = 0;
+
+ memset(&attr_char_value, 0, sizeof(attr_char_value));
+
+ memset(&attr_char_value, 0, sizeof (attr_char_value));
+
+ attr_char_value.p_uuid = &ble_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.init_len = sizeof (int8_t);
+ attr_char_value.init_offs = 0;
+ attr_char_value.max_len = sizeof (uint8_t);
+ attr_char_value.p_value = (uint8_t*)&p_tps_init->initial_tx_power_level;
+
+ return sd_ble_gatts_characteristic_add(p_tps->service_handle,
+ &char_md,
+ &attr_char_value,
+ &p_tps->tx_power_level_handles);
+}
+
+
+uint32_t ble_tps_init(ble_tps_t * p_tps, const ble_tps_init_t * p_tps_init)
+{
+ uint32_t err_code;
+ ble_uuid_t ble_uuid;
+
+ // Add service
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_TX_POWER_SERVICE);
+
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
+ &ble_uuid,
+ &p_tps->service_handle);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add TX Power Level characteristic
+ return tx_power_level_char_add(p_tps, p_tps_init);
+}
+
+
+uint32_t ble_tps_tx_power_level_set(ble_tps_t * p_tps, int8_t tx_power_level)
+{
+ ble_gatts_value_t gatts_value;
+
+ // Initialize value struct.
+ memset(&gatts_value, 0, sizeof(gatts_value));
+
+ gatts_value.len = sizeof(uint8_t);
+ gatts_value.offset = 0;
+ gatts_value.p_value = (uint8_t*)&tx_power_level;
+
+ // Update database
+ return sd_ble_gatts_value_set(p_tps->conn_handle,
+ p_tps->tx_power_level_handles.value_handle,
+ &gatts_value);
+}
+#endif // NRF_MODULE_ENABLED(BLE_TPS)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_tps/ble_tps.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_tps/ble_tps.h
new file mode 100644
index 0000000..1912179
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/ble_tps/ble_tps.h
@@ -0,0 +1,138 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_tps TX Power Service
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief TX Power Service module.
+ *
+ * @details This module implements the TX Power Service with the TX Power Level characteristic.
+ * During initialization it adds the TX Power Service and TX Power Level characteristic
+ * with the specified initial value to the BLE stack database.
+ *
+ * It provides a function for letting the application update the TX Power Level
+ * characteristic.
+ *
+ * @note Attention!
+ * To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+
+#ifndef BLE_TPS_H__
+#define BLE_TPS_H__
+
+#include <stdint.h>
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "nrf_sdh_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_tps instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_TPS_DEF(_name) \
+static ble_tps_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_TPS_BLE_OBSERVER_PRIO, \
+ ble_tps_on_ble_evt, &_name)
+
+
+/**@brief TX Power Service init structure. This contains all options and data needed for
+ * initialization of the service. */
+typedef struct
+{
+ int8_t initial_tx_power_level; /**< Initial value of the TX Power Level characteristic (in dBm). */
+ ble_srv_security_mode_t tps_attr_md; /**< Initial Security Setting for TX Power Service Characteristics. */
+} ble_tps_init_t;
+
+/**@brief TX Power Service structure. This contains various status information for the service. */
+typedef struct
+{
+ uint16_t service_handle; /**< Handle of TX Power Service (as provided by the BLE stack). */
+ ble_gatts_char_handles_t tx_power_level_handles; /**< Handles related to the TX Power Level characteristic. */
+ uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
+} ble_tps_t;
+
+
+/**@brief Function for initializing the TX Power Service.
+ *
+ * @param[out] p_hrs TX Power Service structure. This structure will have to be supplied by
+ * the application. It will be initialized by this function, and will later
+ * be used to identify this particular service instance.
+ * @param[in] p_tps_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
+ */
+uint32_t ble_tps_init(ble_tps_t * p_hrs, const ble_tps_init_t * p_tps_init);
+
+
+/**@brief Function for handling the Application's BLE Stack events.
+ *
+ * @details Handles all events from the BLE stack of interest to the TX Power Service.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context TX Power Service structure.
+ */
+void ble_tps_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for setting the value of the TX Power Level characteristic.
+ *
+ * @param[in] p_tps TX Power Service structure.
+ * @param[in] tx_power_level New TX Power Level (unit dBm, range -100 to 20).
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+uint32_t ble_tps_tx_power_level_set(ble_tps_t * p_tps, int8_t tx_power_level);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_TPS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es.h
new file mode 100644
index 0000000..ce4221d
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es.h
@@ -0,0 +1,198 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef ES_H__
+#define ES_H__
+
+#include <stdint.h>
+#include "app_util_platform.h"
+
+/**
+ * @file
+ *
+ * @defgroup eddystone_types Frame types and data formats
+ * @brief Definitions specific to Eddystone frame types and data formats.
+ * @ingroup eddystone
+ * @{
+ */
+
+/** @brief Swap 2 bytes.
+ */
+#define BYTES_SWAP_16BIT(x) (x << 8 | x >> 8)
+
+/** @brief Reverse 4 bytes.
+ */
+#define BYTES_REVERSE_32BIT(x) \
+ ((x << 24 | ((x << 8) & 0x00FF0000)) | (((x >> 8) & 0x0000FF00) | x >> 24))
+
+/** @brief Check if the error code is equal to NRF_SUCCESS. If it is not, return the error code.
+ */
+#define RETURN_IF_ERROR(PARAM) \
+ if ((PARAM) != NRF_SUCCESS) \
+ { \
+ return (PARAM); \
+ }
+
+#define ES_UUID 0xFEAA //!< UUID for Eddystone beacons according to specification.
+
+#define ES_UID_FRAME_TYPE 0x00 //!< UID frame type (fixed at 0x00).
+#define ES_UID_RFU 0x00, 0x00 //!< Reserved for future use according to specification.
+
+#define ES_URL_FRAME_TYPE 0x10 //!< URL frame type (fixed at 0x10).
+#define ES_URL_SCHEME 0x00 //!< URL prefix scheme according to specification (0x00 = "http://www").
+
+#define ES_TLM_FRAME_TYPE 0x20 //!< TLM frame type (fixed at 0x20).
+#define ES_EID_FRAME_TYPE 0x30 //!< EID frame type (fixed at 0x30).
+
+#define ES_FRAME_TYPE_LENGTH (1) //!< Length of a frame type field.
+
+#define ES_UID_LENGTH (20) //!< Length of a UID frame.
+#define ES_UID_NAMESPACE_LENGTH (10) //!< Length of a UID frame namespace field.
+#define ES_UID_INSTANCE_LENGTH (6) //!< Length of a UID frame instance field.
+#define ES_UID_RFU_LENGTH (2) //!< Length of a UID frame RFU field.
+
+#define ES_URL_LENGTH (20) //!< Length of a URL frame.
+#define ES_URL_URL_SCHEME_LENGTH (1) //!< Length of a URL frame URL scheme field.
+#define ES_URL_ENCODED_URL_LENGTH (17) //!< Maximum length of a URL frame encoded URL field.
+
+#define ES_TLM_LENGTH (14) //!< Length of a TLM frame.
+#define ES_TLM_VBATT_LENGTH (2) //!< Length of a TLM frame VBATT field.
+#define ES_TLM_TEMP_LENGTH (2) //!< Length of a TLM frame TEMP field.
+#define ES_TLM_ADV_CNT_LENGTH (4) //!< Length of a TLM frame ADV count field.
+#define ES_TLM_SEC_CNT_LENGTH (4) //!< Length of a TLM frame seconds field.
+
+#define ES_EID_LENGTH (10) //!< Length of an EID frame.
+#define ES_EID_ID_LENGTH (8) //!< Length of an EID frame ephemeral ID field.
+#define ES_EID_GATTS_READ_LENGTH (14)
+#define ES_EID_GATTS_READ_FRAME_TYPE_IDX (0)
+#define ES_EID_GATTS_READ_EXPONENT_IDX (1)
+#define ES_EID_GATTS_READ_CLCK_VALUE_IDX (2)
+#define ES_EID_GATTS_READ_EID_IDX (6)
+
+#define ES_ETLM_LENGTH (18) //!< Length of an eTLM frame.
+#define ES_ETLM_ECRYPTED_LENGTH (ES_TLM_VBATT_LENGTH + \
+ ES_TLM_TEMP_LENGTH + \
+ ES_TLM_ADV_CNT_LENGTH + \
+ ES_TLM_SEC_CNT_LENGTH) //!< Length of an eTLM frame encrypted TLM field.
+
+#define ES_ETLM_RFU (0x00) //!< eTLM frame RFU field value.
+#define ES_SPEC_VERSION_BYTE (0x00) //!< eTLM frame specification version field value.
+
+/** @brief Eddystone frame type values. These values are advertised as frame types. */
+typedef enum
+{
+ ES_FRAME_TYPE_UID = ES_UID_FRAME_TYPE, /**< UID frame type. */
+ ES_FRAME_TYPE_URL = ES_URL_FRAME_TYPE, /**< URL frame type. */
+ ES_FRAME_TYPE_TLM = ES_TLM_FRAME_TYPE, /**< TLM frame type. */
+ ES_FRAME_TYPE_EID = ES_EID_FRAME_TYPE /**< EID frame type. */
+} es_frame_type_t;
+
+/** @brief TLM version values. */
+typedef enum
+{
+ ES_TLM_VERSION_TLM = 0x00, /**< TLM. */
+ ES_TLM_VERSION_ETLM = 0x01 /**< Encrypted TLM (eTLM). */
+} es_tlm_version_t;
+
+/** @brief UID frame data representation.
+ * @note This is a packed structure. Therefore, you should not change it.
+ */
+typedef PACKED_STRUCT
+{
+ es_frame_type_t frame_type; //!< Frame type (see @ref es_frame_type_t).
+ int8_t ranging_data; //!< Calibrated TX power at 0 m.
+ int8_t namespace[ES_UID_NAMESPACE_LENGTH]; //!< UID namespace.
+ int8_t instance[ES_UID_INSTANCE_LENGTH]; //!< UID instance.
+ int8_t rfu[ES_UID_RFU_LENGTH]; //!< RFU.
+} es_uid_frame_t;
+
+
+/** @brief URL frame data representation.
+ * @note This is a packed structure. Therefore, you should not change it.
+*/
+typedef PACKED_STRUCT
+{
+ es_frame_type_t frame_type; //!< Frame type (see @ref es_frame_type_t).
+ int8_t ranging_data; //!< Calibrated TX power at 0 m.
+ uint8_t url_scheme; //!< URL scheme.
+ uint8_t encoded_url[ES_URL_ENCODED_URL_LENGTH]; //!< Encoded URL (variable length).
+} es_url_frame_t;
+
+
+/** @brief TLM frame data representation.
+ * @note This is a packed structure. Therefore, you should not change it.
+*/
+typedef PACKED_STRUCT
+{
+ es_frame_type_t frame_type; //!< Frame type (see @ref es_frame_type_t).
+ es_tlm_version_t version; //!< TLM version (see @ref es_tlm_version_t).
+ int8_t vbatt[ES_TLM_VBATT_LENGTH]; //!< Battery voltage (in 1 mV units).
+ int8_t temp[ES_TLM_TEMP_LENGTH]; //!< Beacon temperature.
+ int8_t adv_cnt[ES_TLM_ADV_CNT_LENGTH]; //!< Advertising PDU count.
+ int8_t sec_cnt[ES_TLM_SEC_CNT_LENGTH]; //!< Time since power-on or reboot.
+} es_tlm_frame_t;
+
+/** @brief EID frame data representation.
+ * @note This is a packed structure. Therefore, you should not change it.
+*/
+typedef PACKED_STRUCT
+{
+ es_frame_type_t frame_type; //!< Frame type (see @ref es_frame_type_t).
+ int8_t ranging_data; //!< Calibrated TX power at 0 m.
+ int8_t eid[ES_EID_ID_LENGTH]; //!< 8-byte ephemeral identifier.
+} es_eid_frame_t;
+
+
+/** @brief eTLM frame data representation.
+ * @note This is a packed structure. Therefore, you should not change it.
+*/
+typedef PACKED_STRUCT
+{
+ es_frame_type_t frame_type; //!< Frame type (see @ref es_frame_type_t).
+ es_tlm_version_t version; //!< TLM version (see @ref es_tlm_version_t).
+ int8_t encrypted_tlm[ES_ETLM_ECRYPTED_LENGTH]; //!< Encrypted TLM data.
+ int16_t random_salt; //!< Salt
+ int16_t msg_integrity_check; //!< Message integrity check.
+} es_etlm_frame_t;
+
+/**
+ * @}
+ */
+
+#endif // ES_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv.c
new file mode 100644
index 0000000..bf6913f
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv.c
@@ -0,0 +1,342 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "es_adv.h"
+#include "app_error.h"
+#include "es_adv_frame.h"
+#include "es_adv_timing.h"
+#include "es_tlm.h"
+#include "es_slot.h"
+
+static es_adv_evt_handler_t m_adv_evt_handler; //!< Eddystone advertisement event handler.
+static bool m_is_connected = false; //!< Is the Eddystone beacon in a connected state.
+static bool m_remain_connectable = false; //!< Should the Eddystone beacon remain connectable.
+static uint8_t m_ecs_uuid_type = 0; //!< UUID type of the Eddystone Configuration Service.
+static uint16_t m_adv_interval = APP_CFG_NON_CONN_ADV_INTERVAL_MS; //!< Current advertisement interval.
+
+static uint8_t m_enc_advdata[BLE_GAP_ADV_SET_DATA_SIZE_MAX]; //!< Buffer for storing an encoded advertising set.
+static uint8_t m_enc_scan_response_data[BLE_GAP_ADV_SET_DATA_SIZE_MAX]; //!< Buffer for storing an encoded scan data.
+static uint8_t *mp_adv_handle; //!< Pointer to the advertising handle.
+
+/**@brief Struct that contains pointers to the encoded advertising data. */
+static ble_gap_adv_data_t m_adv_data =
+{
+ .adv_data =
+ {
+ .p_data = m_enc_advdata,
+ .len = BLE_GAP_ADV_SET_DATA_SIZE_MAX
+ },
+ .scan_rsp_data =
+ {
+ .p_data = m_enc_scan_response_data,
+ .len = BLE_GAP_ADV_SET_DATA_SIZE_MAX
+
+ }
+};
+
+/**@brief Function for invoking registered callback.
+ *
+ * @param[in] evt Event to issue to callback.
+ */
+static void invoke_callback(es_adv_evt_t evt)
+{
+ if (m_adv_evt_handler != NULL)
+ {
+ m_adv_evt_handler(evt);
+ }
+}
+
+/**@brief Starting advertising.
+ * @param[in] p_adv_params Advertisement parameters to use.
+ */
+static void adv_start(ble_gap_adv_params_t * p_adv_params)
+{
+ ret_code_t err_code = NRF_SUCCESS;
+
+ es_tlm_adv_cnt_inc();
+
+ err_code = sd_ble_gap_adv_set_configure(mp_adv_handle, &m_adv_data, p_adv_params);
+ APP_ERROR_CHECK(err_code);
+
+ err_code = sd_ble_gap_adv_start(*mp_adv_handle, BLE_CONN_CFG_TAG_DEFAULT);
+
+ if (err_code != NRF_ERROR_BUSY && err_code != NRF_SUCCESS)
+ {
+ APP_ERROR_CHECK(err_code);
+ }
+}
+
+
+/**@brief Given state of Eddystone beacon, get advertisement parameters. */
+static void get_adv_params(ble_gap_adv_params_t * p_adv_params,
+ bool non_connectable,
+ bool remain_connectable)
+{
+ // Initialize advertising parameters (used when starting advertising).
+ memset(p_adv_params, 0, sizeof(ble_gap_adv_params_t));
+
+ // Non-connectable
+ p_adv_params->properties.type = non_connectable
+ ? BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED
+ : BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
+ p_adv_params->p_peer_addr = NULL; // Undirected advertisement.
+ p_adv_params->filter_policy = BLE_GAP_ADV_FP_ANY;
+ p_adv_params->interval = non_connectable ? BLE_GAP_ADV_INTERVAL_MAX : 1000;
+ p_adv_params->duration = non_connectable
+ ? APP_CFG_NON_CONN_ADV_TIMEOUT
+ : (remain_connectable ? 0 : APP_CFG_CONNECTABLE_ADV_TIMEOUT);
+ p_adv_params->primary_phy = BLE_GAP_PHY_1MBPS;
+}
+
+
+/**@brief Update advertisement data and start connectable advertisements. */
+static void connectable_adv_start(void)
+{
+ ble_gap_adv_params_t connectable_adv_params;
+ ble_advdata_t scrsp_data;
+ ble_uuid_t scrp_uuids[] = {{BLE_UUID_ESCS_SERVICE, m_ecs_uuid_type}};
+
+ memset(&scrsp_data, 0, sizeof(scrsp_data));
+ scrsp_data.name_type = BLE_ADVDATA_FULL_NAME;
+ scrsp_data.include_appearance = false;
+ scrsp_data.uuids_complete.uuid_cnt = sizeof(scrp_uuids) / sizeof(scrp_uuids[0]);
+ scrsp_data.uuids_complete.p_uuids = scrp_uuids;
+
+ m_adv_data.scan_rsp_data.p_data = m_enc_scan_response_data;
+ m_adv_data.scan_rsp_data.len = BLE_GAP_ADV_SET_DATA_SIZE_MAX;
+
+ // As the data to be written does not depend on the slot_no, we can safely send
+ es_adv_frame_fill_connectable_adv_data(&scrsp_data, &m_adv_data);
+
+ get_adv_params(&connectable_adv_params, false, m_remain_connectable);
+ adv_start(&connectable_adv_params);
+
+ invoke_callback(ES_ADV_EVT_CONNECTABLE_ADV_STARTED);
+}
+
+
+static void adv_stop(void)
+{
+ ret_code_t err_code;
+
+ err_code = sd_ble_gap_adv_stop(*mp_adv_handle);
+ if (err_code != NRF_ERROR_INVALID_STATE)
+ {
+ APP_ERROR_CHECK(err_code);
+ }
+
+ es_adv_timing_stop();
+}
+
+
+static void adv_restart(void)
+{
+ if (!m_remain_connectable)
+ {
+ es_adv_start_non_connctable_adv();
+ }
+
+ else
+ {
+ connectable_adv_start();
+ }
+}
+
+
+/**@brief Function handling events from @ref es_adv_timing.c.
+ *
+ * @param[in] p_evt Advertisement timing event.
+ */
+static void adv_timing_callback(const es_adv_timing_evt_t * p_evt)
+{
+ ret_code_t err_code;
+ ble_gap_adv_params_t non_connectable_adv_params;
+ const es_slot_reg_t * p_reg = es_slot_get_registry();
+
+ // As new advertisement data will be loaded, stop advertising.
+ err_code = sd_ble_gap_adv_stop(*mp_adv_handle);
+ if (err_code != NRF_ERROR_INVALID_STATE && err_code != BLE_ERROR_INVALID_ADV_HANDLE)
+ {
+ APP_ERROR_CHECK(err_code);
+ }
+
+ // If a non-eTLM frame is to be advertised.
+ if (p_evt->evt_id == ES_ADV_TIMING_EVT_ADV_SLOT)
+ {
+ err_code = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, 0, p_reg->slots[p_evt->slot_no].radio_tx_pwr);
+ if (err_code != BLE_ERROR_INVALID_ADV_HANDLE)
+ {
+ APP_ERROR_CHECK(err_code);
+ }
+ es_adv_frame_fill_non_connectable_adv_data(p_evt->slot_no, false, &m_adv_data);
+ }
+
+ // If an eTLM frame is to be advertised
+ else if (p_evt->evt_id == ES_ADV_TIMING_EVT_ADV_ETLM)
+ {
+ err_code = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, 0, p_reg->slots[p_reg->tlm_slot].radio_tx_pwr);
+ APP_ERROR_CHECK(err_code);
+
+ es_adv_frame_fill_non_connectable_adv_data(p_evt->slot_no, true, &m_adv_data);
+ }
+
+ invoke_callback(ES_ADV_EVT_NON_CONN_ADV);
+
+ get_adv_params(&non_connectable_adv_params, true, m_remain_connectable);
+ adv_start(&non_connectable_adv_params);
+}
+
+
+void es_adv_start_connectable_adv(void)
+{
+ if (!m_is_connected)
+ {
+ adv_stop();
+
+ connectable_adv_start();
+ }
+}
+
+
+void es_adv_start_non_connctable_adv(void)
+{
+ es_adv_timing_start(m_adv_interval);
+}
+
+
+void es_adv_remain_connectable_set(bool remain_connectable)
+{
+ m_remain_connectable = remain_connectable;
+}
+
+
+bool es_adv_remain_connectable_get(void)
+{
+ return m_remain_connectable;
+}
+
+
+void es_adv_on_ble_evt(ble_evt_t const * p_ble_evt)
+{
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ m_is_connected = true;
+
+ // The beacon must provide these advertisements for the client to see updated values
+ // during the connection.
+ es_adv_start_non_connctable_adv();
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ m_is_connected = false;
+
+ // Stop all advertising to give some time for writing to flash.
+ adv_stop();
+ adv_restart();
+ break;
+
+ case BLE_GAP_EVT_ADV_SET_TERMINATED:
+ if (p_ble_evt->evt.gap_evt.params.adv_set_terminated.reason == BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_TIMEOUT &&
+ !m_is_connected)
+ {
+ invoke_callback(ES_ADV_EVT_CONNECTABLE_ADV_STOPPED);
+
+ adv_restart();
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+void es_adv_interval_set(nrf_ble_escs_adv_interval_t interval)
+{
+ const es_slot_reg_t * p_reg = es_slot_get_registry();
+ uint16_t min_valid_adv_interval;
+
+ bool eTLM_required = (p_reg->num_configured_eid_slots > 0) && (p_reg->tlm_configured);
+
+ min_valid_adv_interval = eTLM_required ? \
+ p_reg->num_configured_slots * (APP_CONFIG_ADV_FRAME_SPACING_MS_MIN + \
+ APP_CONFIG_ADV_FRAME_ETLM_SPACING_MS) \
+ : \
+ p_reg->num_configured_slots * APP_CONFIG_ADV_FRAME_SPACING_MS_MIN;
+
+ m_adv_interval = (interval > min_valid_adv_interval) ? interval : min_valid_adv_interval;
+
+#ifdef APP_CONFIG_ADV_INTERVAL_MS_MAX
+ if (m_adv_interval > APP_CONFIG_ADV_INTERVAL_MS_MAX)
+ {
+ m_adv_interval = APP_CONFIG_ADV_INTERVAL_MS_MAX;
+ }
+#endif // APP_CONFIG_ADV_INTERVAL_MS_MAX
+}
+
+
+nrf_ble_escs_adv_interval_t es_adv_interval_get(void)
+{
+ return m_adv_interval;
+}
+
+
+void es_adv_init(uint8_t ecs_uuid_type,
+ es_adv_evt_handler_t adv_event_handler,
+ nrf_ble_escs_adv_interval_t adv_interval,
+ bool remain_connectable,
+ uint8_t * const p_adv_handle)
+{
+ m_ecs_uuid_type = ecs_uuid_type;
+ m_adv_evt_handler = adv_event_handler;
+ m_is_connected = false;
+ m_remain_connectable = remain_connectable;
+ m_adv_interval = adv_interval;
+ mp_adv_handle = p_adv_handle;
+
+ es_tlm_init();
+
+ es_adv_timing_init(adv_timing_callback);
+}
+
+void es_adv_timers_init(void)
+{
+ es_adv_timing_timers_init();
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv.h
new file mode 100644
index 0000000..bb0177c
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv.h
@@ -0,0 +1,129 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef ES_ADV_H__
+#define ES_ADV_H__
+
+#include "nrf_ble_escs.h"
+
+/**
+ * @file
+ * @defgroup eddystone_adv Eddystone advertising module
+ * @brief Types and functions for handling advertising in Eddystone beacons.
+ * @ingroup eddystone
+ * @{
+ */
+
+/** @brief Eddystone Advertiser events. */
+typedef enum
+{
+ ES_ADV_EVT_NON_CONN_ADV,
+ ES_ADV_EVT_CONNECTABLE_ADV_STARTED,
+ ES_ADV_EVT_CONNECTABLE_ADV_STOPPED,
+} es_adv_evt_t;
+
+/** @brief Eddystone Advertiser event handler. */
+typedef void (*es_adv_evt_handler_t)(es_adv_evt_t evt);
+
+/** @brief Function for initializing the module.
+ *
+ * @param[in] ecs_uuid_type ECS UUID type used for advertising the Eddystone Configuration Service UUID.
+ * @param[in] adv_event_handler Eddystone advertiser event handler.
+ * @param[in] adv_interval Advertisement interval to use.
+ * @param[in] remain_connectable Flag that specifies if advertisements should remain connectable.
+ * @param[in] p_adv_handle Pointer to the advertising handle used to start and stop advertising.
+ */
+void es_adv_init(uint8_t ecs_uuid_type,
+ es_adv_evt_handler_t adv_event_handler,
+ nrf_ble_escs_adv_interval_t adv_interval,
+ bool remain_connectable,
+ uint8_t * const p_adv_handle);
+
+/** @brief Function for passing BLE events to this module.
+ *
+ * @param[in] p_ble_evt Pointer to the BLE evt.
+ */
+void es_adv_on_ble_evt(ble_evt_t const * p_ble_evt);
+
+/** @brief Function for starting the advertisements.
+ */
+void es_adv_start_non_connctable_adv(void);
+
+/** @brief Function for specifying if the beacon should remain connectable.
+ *
+ * @param[in] remain_connectable Value to be set.
+ */
+void es_adv_remain_connectable_set(bool remain_connectable);
+
+/** @brief Function for starting connectable advertisements.
+ */
+void es_adv_start_connectable_adv(void);
+
+/** @brief Function for setting the base advertisement interval for non-connectable advertisements.
+ *
+ * The minimum allowed advertisement interval is calculated based on the configured minimum advertisement
+ * frame spacings and the number of configured slots. If eTLM slots are configured a separate minimum
+ * advertisement frame spacing is used for those. If @p interval is outside of range, the closest valid value
+ * is set.
+ *
+ * @param interval The new advertisement interval.
+ */
+void es_adv_interval_set(nrf_ble_escs_adv_interval_t interval);
+
+/** @brief Function for getting a pointer to the current advertisement interval.
+ *
+ * @retval Pointer to the current advertisement interval.
+ */
+nrf_ble_escs_adv_interval_t es_adv_interval_get(void);
+
+/** @brief Function for getting the value of the 'remain_connectable' field.
+ *
+ * @retval Value of 'remain_connectable'.
+ */
+bool es_adv_remain_connectable_get(void);
+
+/** @brief Function for initializing the Eddystone advertisement timers.
+ */
+void es_adv_timers_init(void);
+
+/**
+ * @}
+ */
+
+#endif // ES_ADV_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_frame.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_frame.c
new file mode 100644
index 0000000..0333c43
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_frame.c
@@ -0,0 +1,120 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "es_adv_frame.h"
+#include "es_slot.h"
+
+
+/**@brief Function for setting advertisement data, using 'ble_advdata_encode'.
+ *
+ * @param[in] p_scrsp_data Scan response data.
+ * @param[in] p_es_data_array Eddystone service data array.
+ */
+static void fill_adv_data(ble_advdata_t * p_scrsp_data, uint8_array_t * p_es_data_array, ble_gap_adv_data_t * const p_adv_data)
+{
+ ble_advdata_t adv_data;
+ ret_code_t err_code;
+ ble_uuid_t adv_uuids[] = {{ES_UUID, BLE_UUID_TYPE_BLE}};
+ uint8_array_t es_data_array = {0};
+
+ ble_advdata_service_data_t service_data; // Structure to hold Service Data.
+
+ service_data.service_uuid = APP_ES_UUID; // Eddystone UUID to allow discoverability on iOS devices.
+
+ service_data.data = (p_es_data_array != NULL) ? *p_es_data_array : es_data_array;
+
+ // Build and set advertising data.
+ memset(&adv_data, 0, sizeof(ble_advdata_t));
+
+ adv_data.name_type = BLE_ADVDATA_NO_NAME;
+ adv_data.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
+ adv_data.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]);
+ adv_data.uuids_complete.p_uuids = adv_uuids;
+ adv_data.p_service_data_array = &service_data;
+ adv_data.service_data_count = (p_es_data_array != NULL) ? 1 : 0;
+
+ err_code = ble_advdata_encode(&adv_data,
+ p_adv_data->adv_data.p_data,
+ &p_adv_data->adv_data.len);
+ APP_ERROR_CHECK(err_code);
+ if (p_scrsp_data != NULL)
+ {
+ err_code = ble_advdata_encode(p_scrsp_data,
+ p_adv_data->scan_rsp_data.p_data,
+ &p_adv_data->scan_rsp_data.len);
+ APP_ERROR_CHECK(err_code);
+ }
+ else
+ {
+ p_adv_data->scan_rsp_data.p_data = NULL;
+ p_adv_data->scan_rsp_data.len = 0;
+ }
+}
+
+
+void es_adv_frame_fill_connectable_adv_data(ble_advdata_t * p_scrsp_data, ble_gap_adv_data_t * const p_adv_data)
+{
+ fill_adv_data(p_scrsp_data, NULL, p_adv_data);
+}
+
+
+void es_adv_frame_fill_non_connectable_adv_data(uint8_t slot_no, bool etlm, ble_gap_adv_data_t * const p_adv_data)
+{
+ uint8_array_t es_data_array = {0};
+ const es_slot_reg_t * p_reg = es_slot_get_registry();
+
+ if (etlm)
+ {
+ es_slot_etlm_update(slot_no);
+
+ // If eTLM, the incoming slot_no points to the corresponding EID slot, update to point to TLM slot.
+ slot_no = p_reg->tlm_slot;
+ }
+
+ // If TLM, update the TLM data.
+ else if (p_reg->slots[slot_no].adv_frame.type == ES_FRAME_TYPE_TLM)
+ {
+ es_slot_tlm_update();
+ }
+
+ es_data_array.p_data = (uint8_t *)&p_reg->slots[slot_no].adv_frame.frame;
+ es_data_array.size = p_reg->slots[slot_no].adv_frame.length;
+
+ fill_adv_data(NULL, &es_data_array, p_adv_data);
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_frame.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_frame.h
new file mode 100644
index 0000000..0facf5d
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_frame.h
@@ -0,0 +1,73 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef ES_ADV_FRAME_H__
+#define ES_ADV_FRAME_H__
+
+#include <stdint.h>
+#include "ble_advdata.h"
+
+/**
+ * @file
+ * @addtogroup eddystone_adv
+ * @{
+ */
+
+/**@brief Function for setting up connectable advertisement data using @ref
+ * ble_advdata_encode.
+ *
+ * @param[in] p_scrsp_data Pointer to the scan response data that will be encoded.
+ * @param[in,out] p_adv_data Pointer to the encoded advertising data (including scan response).
+ */
+void es_adv_frame_fill_connectable_adv_data(ble_advdata_t * p_scrsp_data, ble_gap_adv_data_t * const p_adv_data);
+
+/**@brief Function for setting up non-connectable advertisement data using @ref
+ * ble_advdata_encode.
+ *
+ * @param[in] slot_no Slot to fill in data for.
+ * @param[in] etlm Flag that specifies if Eddystone-TLM is required.
+ * @param[in,out] p_adv_data Pointer to the encoded advertising data (including scan response).
+ */
+void es_adv_frame_fill_non_connectable_adv_data(uint8_t slot_no, bool etlm, ble_gap_adv_data_t * const p_adv_data);
+
+/**
+ * @}
+ */
+
+#endif // ES_ADV_FRAME_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_timing.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_timing.c
new file mode 100644
index 0000000..d575ba8
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_timing.c
@@ -0,0 +1,220 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "app_timer.h"
+#include "es_adv_timing.h"
+#include "es_adv_timing_resolver.h"
+#include "es_slot.h"
+
+
+APP_TIMER_DEF(m_es_adv_interval_timer); //!< Timer for advertising the set of slots.
+APP_TIMER_DEF(m_es_slot_timer); //!< Timer for advertising individual slots.
+
+static nrf_ble_escs_adv_interval_t m_current_adv_interval; //!< Current advertisement interval.
+static es_adv_timing_callback_t m_timing_mgr_callback; //!< Registered callback.
+static es_adv_timing_resolver_result_t m_adv_timing_result; //!< Current advertising timing result.
+static bool m_non_conn_adv_active; //!< Is the beacon advertising non-conn advertisements?
+
+/**@brief Function for invoking registered callback.
+ *
+ * @param[in] p_evt Event to issue to callback.
+ */
+static void invoke_callback(const es_adv_timing_evt_t * p_evt)
+{
+ if (m_timing_mgr_callback != NULL && m_non_conn_adv_active)
+ {
+ m_timing_mgr_callback(p_evt);
+ }
+}
+
+
+#if APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO > 1
+static bool frame_to_adv_is_tlm(const es_adv_timing_evt_t * p_evt)
+{
+ const es_slot_reg_t * p_reg = es_slot_get_registry();
+
+ return (p_reg->tlm_configured &&
+ (p_evt->slot_no == p_reg->tlm_slot || p_evt->evt_id == ES_ADV_TIMING_EVT_ADV_ETLM));
+}
+
+
+static bool tlm_should_be_advertised(uint32_t adv_event_cnt)
+{
+ return (adv_event_cnt % APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO) == 0;
+}
+#endif // APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO > 1
+
+
+/**@brief Timeout handler for the advertisement slot timer. */
+static void adv_slot_timeout(void * p_context)
+{
+
+ ret_code_t err_code;
+ uint32_t active_slot_index = (uint32_t)p_context;
+
+ es_adv_timing_evt_t evt;
+
+ evt.slot_no = m_adv_timing_result.timing_results[active_slot_index].slot_no;
+
+ evt.evt_id = m_adv_timing_result.timing_results[active_slot_index].is_etlm
+ ? ES_ADV_TIMING_EVT_ADV_ETLM
+ : ES_ADV_TIMING_EVT_ADV_SLOT;
+
+ // Trigger an event for the next slot if this slot is not the last to be advertised in this event.
+ // Note: since we check 'm_adv_timing_result.len_timing_results > 1' we can safely cast the result of
+ // the subtraction to a uint32.
+ if (m_non_conn_adv_active && \
+ m_adv_timing_result.len_timing_results > 1 && \
+ active_slot_index < (uint32_t)(m_adv_timing_result.len_timing_results - 1))
+ {
+ err_code = app_timer_start( m_es_slot_timer,
+ APP_TIMER_TICKS(m_adv_timing_result.timing_results[active_slot_index].delay_ms),
+ (void*)(active_slot_index + 1));
+ APP_ERROR_CHECK(err_code);
+ }
+
+#if APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO > 1
+ static uint32_t adv_event_cnt = 0;
+
+ if (active_slot_index == 0)
+ {
+ adv_event_cnt++;
+ }
+
+ if (frame_to_adv_is_tlm(&evt) && !tlm_should_be_advertised(adv_event_cnt))
+ {
+ return;
+ }
+#endif // APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO > 1
+
+ invoke_callback(&evt);
+}
+
+
+/**@brief Timeout handler for the advertisement interval timer. */
+static void adv_interval_timeout(void * p_context)
+{
+ if (es_slot_get_registry()->num_configured_slots > 0)
+ {
+ // Trigger slot timeout for advertising the first slot.
+ // Note: The slot number is not the index in the slot registry, it is the index of the active slots.
+ adv_slot_timeout(NULL);
+ }
+
+ if (m_non_conn_adv_active)
+ {
+ uint32_t err_code = app_timer_start(m_es_adv_interval_timer,
+ APP_TIMER_TICKS(m_current_adv_interval),
+ NULL);
+ APP_ERROR_CHECK(err_code);
+ }
+}
+
+
+void es_adv_timing_timers_init(void)
+{
+ ret_code_t err_code;
+
+ err_code = app_timer_create(&m_es_adv_interval_timer,
+ APP_TIMER_MODE_SINGLE_SHOT,
+ adv_interval_timeout);
+ APP_ERROR_CHECK(err_code);
+
+ err_code = app_timer_create(&m_es_slot_timer,
+ APP_TIMER_MODE_SINGLE_SHOT,
+ adv_slot_timeout);
+ APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for finding and setting advertisement timing configuration. */
+static void adv_timing_set(void)
+{
+ ret_code_t err_code;
+ const es_slot_reg_t * p_reg = es_slot_get_registry();
+
+ es_adv_timing_resolver_input_t resolver_input = {
+ .adv_interval = m_current_adv_interval,
+ .p_result = &m_adv_timing_result,
+ .num_slots_configured = p_reg->num_configured_slots,
+ .p_slots_configured = p_reg->slots_configured,
+ .num_eid_slots_configured = p_reg->num_configured_eid_slots,
+ .p_eid_slots_configured = p_reg->eid_slots_configured,
+ .tlm_configured = p_reg->tlm_configured,
+ .tlm_slot = p_reg->tlm_slot};
+
+ err_code = es_adv_timing_resolve(&resolver_input);
+ APP_ERROR_CHECK(err_code);
+}
+
+
+void es_adv_timing_start(uint16_t adv_interval)
+{
+ ret_code_t err_code;
+
+ const es_slot_reg_t * p_reg = es_slot_get_registry();
+
+ m_non_conn_adv_active = true;
+
+ if (p_reg->num_configured_slots > 0)
+ {
+ m_current_adv_interval = adv_interval;
+
+ err_code = app_timer_start(m_es_adv_interval_timer,
+ APP_TIMER_TICKS(m_current_adv_interval),
+ NULL);
+ APP_ERROR_CHECK(err_code);
+
+ adv_timing_set();
+ }
+}
+
+
+void es_adv_timing_stop(void)
+{
+ m_non_conn_adv_active = false; // Stops timers from being re-fired.
+}
+
+
+void es_adv_timing_init(es_adv_timing_callback_t p_handler)
+{
+ m_non_conn_adv_active = false;
+ m_timing_mgr_callback = p_handler;
+ memset(&m_adv_timing_result, 0, sizeof(m_adv_timing_result));
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_timing.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_timing.h
new file mode 100644
index 0000000..6728de5
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_timing.h
@@ -0,0 +1,97 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef ES_ADV_TIMING_H__
+#define ES_ADV_TIMING_H__
+
+#include <stdint.h>
+
+/**
+ * @file
+ * @defgroup eddystone_adv_timing Timing
+ * @brief Events and functions for advertisement timing.
+ * @ingroup eddystone_adv
+ * @{
+ */
+
+/**@brief Eddystone advertisement timing event types. */
+typedef enum
+{
+ ES_ADV_TIMING_EVT_ADV_SLOT, //!< Advertising non-eTLM slot.
+ ES_ADV_TIMING_EVT_ADV_ETLM //!< Advertising eTLM slot.
+} es_adv_timing_evt_id_t;
+
+/**@brief Eddystone advertisement timing event. */
+typedef struct
+{
+ es_adv_timing_evt_id_t evt_id; //!< Event type ID.
+ uint8_t slot_no; /**< @brief Slot number.
+ * @details For non-eTLM events: The slot number to advertise.
+ *
+ * For eTLM events: The slot number of the corresponding EID slot. */
+} es_adv_timing_evt_t;
+
+/**@brief Eddystone advertisement timing event callback.
+ *
+ * @param[in] p_evt Pointer to the Eddystone advertisement timing event.
+ */
+typedef void (*es_adv_timing_callback_t)(const es_adv_timing_evt_t * p_evt);
+
+/**@brief Function for starting Eddystone advertisement timing event generation. */
+void es_adv_timing_start(uint16_t adv_interval);
+
+
+/**@brief Function for stopping Eddystone advertisement timing event generation. */
+void es_adv_timing_stop(void);
+
+/**@brief Function for initializing the Eddystone advertisement timers.
+ */
+void es_adv_timing_timers_init(void);
+
+/**@brief Function for initializing the Eddystone advertisement timing module.
+ *
+ * @param[in] handler Eddystone advertisement timing event handler to register.
+ */
+void es_adv_timing_init(es_adv_timing_callback_t handler);
+
+/**
+ * @}
+ */
+
+#endif // ES_ADV_TIMING_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_timing_resolver.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_timing_resolver.c
new file mode 100644
index 0000000..35c29c9
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_timing_resolver.c
@@ -0,0 +1,145 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "es_adv_timing_resolver.h"
+#include "sdk_macros.h"
+
+/**@brief Function for finding delay to use after each non-eTLM advertisement.
+ *
+ * @param[in] adv_interval Configured advertisement interval.
+ * @param[in] num_slots_configured Number of configured slots.
+ * @param[in] eTLM_required Is there an eTLM slot.
+ */
+static uint16_t get_adv_delay(uint16_t adv_interval,
+ uint8_t num_slots_configured,
+ bool eTLM_required)
+{
+ // If eTLM is required, don't count this when calculating delay.
+ return adv_interval / (num_slots_configured - (eTLM_required ? 1 : 0));
+}
+
+
+/**@brief Function for checking if given slot_no is an EID slot.
+ *
+ * @param[in] slot_no Slot number to check.
+ * @param[in] p_eid_slots_configured Pointer to list of configured EID slots.
+ * @param[in] num_eid_slots_configured Number of EID slots configured.
+ */
+static bool is_eid(uint8_t slot_no, const uint8_t * p_eid_slots_configured, uint8_t num_eid_slots_configured)
+{
+ for (uint32_t i = 0; i < num_eid_slots_configured; ++i)
+ {
+ if (slot_no == p_eid_slots_configured[i])
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+ret_code_t es_adv_timing_resolve(es_adv_timing_resolver_input_t * p_input)
+{
+ VERIFY_PARAM_NOT_NULL(p_input);
+
+ uint8_t result_index = 0;
+ bool eTLM_required = p_input->tlm_configured && p_input->num_eid_slots_configured > 0;
+ uint16_t base_delay;
+
+ if (p_input->num_slots_configured == 0)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ base_delay = get_adv_delay(p_input->adv_interval, p_input->num_slots_configured, eTLM_required);
+
+ for (uint32_t i = 0; i < p_input->num_slots_configured; ++i)
+ {
+ uint8_t slot_no = p_input->p_slots_configured[i];
+
+ if (!(eTLM_required && slot_no == p_input->tlm_slot))
+ {
+ es_adv_timing_resolver_adv_timing_t * p_current_result = &p_input->p_result->timing_results[result_index];
+ p_current_result->slot_no = slot_no;
+ p_current_result->is_etlm = false;
+
+ // If an eTLM is to be advertised for this frame, this value will be changed.
+ p_current_result->delay_ms = base_delay;
+
+ result_index++;
+
+ if (eTLM_required &&
+ is_eid(slot_no, p_input->p_eid_slots_configured, p_input->num_eid_slots_configured))
+ {
+ es_adv_timing_resolver_adv_timing_t * p_eTLM_timing_result =
+ &p_input->p_result->timing_results[result_index];
+
+ p_current_result->delay_ms = APP_CONFIG_ADV_FRAME_ETLM_SPACING_MS; // Update delay from EID to eTLM frame.
+
+ p_eTLM_timing_result->slot_no = slot_no; // Point to EID slot-no, as this will be
+ // used for finding the correct EIK.
+ p_eTLM_timing_result->is_etlm = true; // Configure as eTLM frame.
+
+ if (base_delay > APP_CONFIG_ADV_FRAME_ETLM_SPACING_MS)
+ {
+ p_eTLM_timing_result->delay_ms =
+ base_delay -
+ APP_CONFIG_ADV_FRAME_ETLM_SPACING_MS; // Set delay of eTLM frame.
+ }
+
+ else
+ {
+ p_eTLM_timing_result->delay_ms = APP_CONFIG_ADV_FRAME_SPACING_MS_MIN;
+ }
+
+ result_index++;
+ }
+ }
+ }
+
+ p_input->p_result->len_timing_results = result_index; // Note: index has been increased to equal length of result.
+
+ if (p_input->p_result->len_timing_results > 0)
+ {
+ p_input->p_result->timing_results[p_input->p_result->len_timing_results - 1].delay_ms = 0; // Last Slot does not need delay.
+ }
+
+ return NRF_SUCCESS;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_timing_resolver.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_timing_resolver.h
new file mode 100644
index 0000000..303ec53
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_adv_timing_resolver.h
@@ -0,0 +1,96 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef ES_ADV_TIMING_RESOLVER_H__
+#define ES_ADV_TIMING_RESOLVER_H__
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "es_app_config.h"
+
+/**
+ * @file
+ * @addtogroup eddystone_adv_timing
+ * @{
+ */
+
+/** @brief Timing parameters for a single slot. */
+typedef struct
+{
+ bool is_etlm; //!< Flag that specifies if the slot is an eTLM.
+ uint8_t slot_no; /**< @brief Slot number. @details
+ * For non-eTLM slots: The slot number of the given frame.
+ *
+ * For eTLM slots: The slot number of the corresponding EID frame. */
+ uint16_t delay_ms; //!< Delay from this frame to the next.
+} es_adv_timing_resolver_adv_timing_t;
+
+/**@brief Results of calculating advertisement delays. */
+typedef struct
+{
+ es_adv_timing_resolver_adv_timing_t timing_results[APP_MAX_ADV_SLOTS - APP_MAX_EID_SLOTS +
+ (APP_MAX_EID_SLOTS * 2)]; //!< List of timing results.
+ uint8_t len_timing_results; //!< Length of results.
+} es_adv_timing_resolver_result_t;
+
+/**@brief Input to the timing resolver. */
+typedef struct
+{
+ uint16_t adv_interval; //!< Global advertisement interval.
+ uint8_t num_slots_configured; //!< Number of configured slots.
+ const uint8_t * p_slots_configured; //!< Pointer to the list of configured slots.
+ uint8_t num_eid_slots_configured; //!< Number of configured EID slots.
+ const uint8_t * p_eid_slots_configured; //!< Pointer to the list of configured EID slots.
+ bool tlm_configured; //!< Flag that specifies if TLM slot is configured.
+ uint8_t tlm_slot; //!< Slot number of the TLM slot (if @p tlm_configured is true).
+ es_adv_timing_resolver_result_t * p_result; //!< Output result.
+} es_adv_timing_resolver_input_t;
+
+/**@brief Function for getting the input for advertisement interval calculation.
+ *
+ * @param[in,out] p_input Input to advertisement interval calculation (see @ref es_adv_timing_resolver_input_t).
+ * @retval NRF_SUCCESS If the operation was successful. Otherwise, an error code is returned.
+ */
+ret_code_t es_adv_timing_resolve(es_adv_timing_resolver_input_t * p_input);
+
+/**
+ * @}
+ */
+
+#endif // ES_ADV_TIMING_RESOLVER_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_battery_voltage.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_battery_voltage.h
new file mode 100644
index 0000000..2125f00
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_battery_voltage.h
@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef ES_BATTERY_VOLTAGE_H__
+#define ES_BATTERY_VOLTAGE_H__
+
+#include <stdint.h>
+
+/**
+ * @file
+ *
+ * @addtogroup eddystone_tlm
+ * @{
+ */
+
+/**@brief Function for initializing the battery voltage module.
+ */
+void es_battery_voltage_init(void);
+
+/**@brief Function for reading the battery voltage.
+ *
+ * @param[out] p_vbatt Pointer to the battery voltage value.
+ */
+void es_battery_voltage_get(uint16_t * p_vbatt);
+
+/**
+ * @}
+ */
+
+#endif // ES_BATTERY_VOLTAGE_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_battery_voltage_saadc.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_battery_voltage_saadc.c
new file mode 100644
index 0000000..71502da
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_battery_voltage_saadc.c
@@ -0,0 +1,104 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "es_battery_voltage.h"
+#include "nrf_drv_saadc.h"
+#include "sdk_macros.h"
+
+#define ADC_REF_VOLTAGE_IN_MILLIVOLTS 600 //!< Reference voltage (in milli volts) used by ADC while doing conversion.
+#define DIODE_FWD_VOLT_DROP_MILLIVOLTS 270 //!< Typical forward voltage drop of the diode (Part no: SD103ATW-7-F) that is connected in series with the voltage supply. This is the voltage drop when the forward current is 1mA. Source: Data sheet of 'SURFACE MOUNT SCHOTTKY BARRIER DIODE ARRAY' available at www.diodes.com.
+#define ADC_RES_10BIT 1024 //!< Maximum digital value for 10-bit ADC conversion.
+#define ADC_PRE_SCALING_COMPENSATION 6 //!< The ADC is configured to use VDD with 1/3 prescaling as input. And hence the result of conversion is to be multiplied by 3 to get the actual value of the battery voltage.
+#define ADC_RESULT_IN_MILLI_VOLTS(ADC_VALUE) \
+ ((((ADC_VALUE) *ADC_REF_VOLTAGE_IN_MILLIVOLTS) / ADC_RES_10BIT) * ADC_PRE_SCALING_COMPENSATION)
+
+static nrf_saadc_value_t adc_buf; //!< Buffer used for storing ADC value.
+static uint16_t m_batt_lvl_in_milli_volts; //!< Current battery level.
+
+/**@brief Function handling events from 'nrf_drv_saadc.c'.
+ *
+ * @param[in] p_evt SAADC event.
+ */
+static void saadc_event_handler(nrf_drv_saadc_evt_t const * p_evt)
+{
+ if (p_evt->type == NRF_DRV_SAADC_EVT_DONE)
+ {
+ nrf_saadc_value_t adc_result;
+
+ adc_result = p_evt->data.done.p_buffer[0];
+
+ m_batt_lvl_in_milli_volts =
+ ADC_RESULT_IN_MILLI_VOLTS(adc_result) + DIODE_FWD_VOLT_DROP_MILLIVOLTS;
+ }
+}
+
+
+void es_battery_voltage_init(void)
+{
+ ret_code_t err_code = nrf_drv_saadc_init(NULL, saadc_event_handler);
+
+ APP_ERROR_CHECK(err_code);
+
+ nrf_saadc_channel_config_t config =
+ NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_VDD);
+ err_code = nrf_drv_saadc_channel_init(0, &config);
+ APP_ERROR_CHECK(err_code);
+
+ err_code = nrf_drv_saadc_buffer_convert(&adc_buf, 1);
+ APP_ERROR_CHECK(err_code);
+
+ err_code = nrf_drv_saadc_sample();
+ APP_ERROR_CHECK(err_code);
+}
+
+
+void es_battery_voltage_get(uint16_t * p_vbatt)
+{
+ VERIFY_PARAM_NOT_NULL_VOID(p_vbatt);
+
+ *p_vbatt = m_batt_lvl_in_milli_volts;
+ if (!nrf_drv_saadc_is_busy())
+ {
+ ret_code_t err_code = nrf_drv_saadc_buffer_convert(&adc_buf, 1);
+ APP_ERROR_CHECK(err_code);
+
+ err_code = nrf_drv_saadc_sample();
+ APP_ERROR_CHECK(err_code);
+ }
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_flash.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_flash.c
new file mode 100644
index 0000000..2e408bb
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_flash.c
@@ -0,0 +1,340 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <string.h>
+#include "es_flash.h"
+#include "es_util.h"
+#include "app_scheduler.h"
+#include "ble_hci.h"
+#include "fds.h"
+#include "nrf_nvic.h"
+
+#define SIZE_OF_PRIV_KEY ESCS_ECDH_KEY_SIZE //!< Size of ECDH private key.
+#define SIZE_OF_PUB_KEY ESCS_ECDH_KEY_SIZE //!< Size of ECDH public key.
+#define SIZE_OF_LOCK_KEY ESCS_AES_KEY_SIZE //!< Size of lock key.
+#define FILE_ID_ES_FLASH 0x1337 //!< File ID used for all flash access EXCEPT lock code.
+#define FILE_ID_ES_FLASH_LOCK_KEY 0x1338 //!< File ID used for lock code flash access.
+#define RECORD_KEY_FLAGS 0x1 //!< File record for flash flags.
+#define RECORD_KEY_PRIV_KEY 0x2 //!< File record for private key.
+#define RECORD_KEY_PUB_KEY 0x3 //!< File record for public key.
+#define RECORD_KEY_LOCK_KEY 0x4 //!< File record for lock key.
+#define RECORD_KEY_BEACON_CONFIG 0x5 //!< File record for lock key.
+
+static uint16_t RECORD_KEY_SLOTS[5] = {0x6, 0x7, 0x8, 0x9, 0xa}; //!< File record for slots.
+
+/**@brief Structure used for invoking flash access function. */
+typedef struct
+{
+ uint16_t record_key;
+ uint16_t file_id;
+ uint8_t * p_data_buf;
+ uint8_t * p_data;
+ uint16_t size_bytes;
+ es_flash_access_t access_type;
+} flash_access_params_t;
+
+static volatile uint32_t m_num_pending_ops; //!< Current number of outstanding FDS operations.
+static volatile bool m_factory_reset; //!< Should factory reset be performed.
+static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID; //!< Current connection handle.
+
+
+#if APP_MAX_ADV_SLOTS > 32
+#error "APP_MAX_ADV_SLOTS must be <= 32"
+#endif
+
+#define SLOT_DECL(i, _) __ALIGN(4) static uint8_t slot## i ##_buf[sizeof(es_slot_t)];
+EVAL(REPEAT(APP_MAX_ADV_SLOTS, SLOT_DECL, ~))
+
+__ALIGN(4) static uint8_t lock_key_buf[SIZE_OF_LOCK_KEY]; //!< Buffer for lock key flash access.
+
+#define SLOT(i, _) slot## i ##_buf,
+static uint8_t * slots_buf_p[APP_MAX_ADV_SLOTS] = {
+ EVAL(REPEAT(APP_MAX_ADV_SLOTS, SLOT, ~))
+};
+
+__ALIGN(4) static uint8_t flash_flags_buf[sizeof(es_flash_flags_t)]; //!< Buffer for flash flags flash access.
+__ALIGN(4) static uint8_t beacon_config_buf[sizeof(es_flash_beacon_config_t)]; //!< Buffer for beacon config flash access.
+
+/**@brief Function handling scheduled FDS garbage collection. */
+static void fds_gc_event(void * p_event_data, uint16_t event_size)
+{
+ ret_code_t fds_err_code;
+
+ fds_err_code = fds_gc();
+ if (fds_err_code != FDS_SUCCESS)
+ APP_ERROR_CHECK_BOOL(NRF_ERROR_INTERNAL);
+ m_num_pending_ops++;
+}
+
+
+/**@brief Function handling FDS events.
+ *
+ * @param[in] p_evt FDS event.
+ */
+static void fds_cb(fds_evt_t const * const p_evt)
+{
+ ret_code_t err_code;
+
+ switch (p_evt->id)
+ {
+ case FDS_EVT_INIT:
+ m_num_pending_ops = 0;
+ break;
+
+ case FDS_EVT_DEL_FILE:
+ case FDS_EVT_DEL_RECORD:
+ // Schedule garbage collection
+ err_code = app_sched_event_put(NULL, 0, fds_gc_event);
+ APP_ERROR_CHECK(err_code);
+ break;
+
+ case FDS_EVT_GC:
+ if (m_factory_reset && m_conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ err_code =
+ sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
+ APP_ERROR_CHECK(err_code);
+ }
+
+ // Fall through:
+ case FDS_EVT_UPDATE:
+ case FDS_EVT_WRITE:
+ if (m_num_pending_ops > 0)
+ {
+ m_num_pending_ops--;
+ }
+ break;
+ }
+}
+
+
+/**@brief Function performing flash access (read/write/clear).
+ *
+ * @param[in] p_params Flash access parameters.
+ */
+static ret_code_t access_flash_data(const flash_access_params_t * p_params)
+{
+ ret_code_t err_code;
+ fds_flash_record_t record = {0};
+ fds_record_desc_t desc = {0};
+ fds_find_token_t ft = {0};
+ fds_record_t record_to_write =
+ {
+ .data.p_data = p_params->p_data_buf,
+ .file_id = p_params->file_id
+ };
+
+ err_code = fds_record_find_by_key(p_params->record_key, &desc, &ft);
+
+ // If its a read or clear, we can not accept errors on lookup
+ if (p_params->access_type == ES_FLASH_ACCESS_READ)
+ {
+ RETURN_IF_ERROR(err_code);
+ }
+
+ if (p_params->access_type == ES_FLASH_ACCESS_CLEAR && err_code == FDS_ERR_NOT_FOUND)
+ {
+ return NRF_SUCCESS;
+ }
+
+ switch (p_params->access_type)
+ {
+ case ES_FLASH_ACCESS_READ:
+ err_code = fds_record_open(&desc, &record);
+ RETURN_IF_ERROR(err_code);
+
+ memcpy(p_params->p_data, record.p_data, p_params->size_bytes);
+
+ err_code = fds_record_close(&desc);
+ RETURN_IF_ERROR(err_code);
+
+ break;
+
+ case ES_FLASH_ACCESS_WRITE:
+ memcpy(p_params->p_data_buf, p_params->p_data, p_params->size_bytes);
+
+ record_to_write.data.length_words = (p_params->size_bytes +3) / 4;
+ record_to_write.key = p_params->record_key;
+
+ if (err_code == FDS_ERR_NOT_FOUND)
+ {
+ err_code = fds_record_write(&desc, &record_to_write);
+ }
+
+ else
+ {
+ err_code = fds_record_update(&desc, &record_to_write);
+ }
+
+ RETURN_IF_ERROR(err_code);
+ m_num_pending_ops++;
+ break;
+
+ case ES_FLASH_ACCESS_CLEAR:
+ err_code = fds_record_delete(&desc);
+ RETURN_IF_ERROR(err_code);
+ m_num_pending_ops++;
+ break;
+
+ default:
+ break;
+ }
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t es_flash_access_lock_key(uint8_t * p_lock_key, es_flash_access_t access_type)
+{
+ flash_access_params_t params = {.record_key = RECORD_KEY_LOCK_KEY,
+ .file_id = FILE_ID_ES_FLASH_LOCK_KEY,
+ .p_data_buf = lock_key_buf,
+ .p_data = (uint8_t *)p_lock_key,
+ .size_bytes = SIZE_OF_LOCK_KEY,
+ .access_type = access_type};
+
+ return access_flash_data(&params);
+}
+
+
+ret_code_t es_flash_access_beacon_config(es_flash_beacon_config_t * p_config,
+ es_flash_access_t access_type)
+{
+ ret_code_t err_code;
+
+ flash_access_params_t params = {.record_key = RECORD_KEY_BEACON_CONFIG,
+ .file_id = FILE_ID_ES_FLASH,
+ .p_data_buf = beacon_config_buf,
+ .p_data = (uint8_t *)p_config,
+ .size_bytes = sizeof(es_flash_beacon_config_t),
+ .access_type = access_type};
+
+ err_code = access_flash_data(&params);
+
+ return err_code;
+}
+
+
+ret_code_t es_flash_access_slot_configs(uint8_t slot_no,
+ es_slot_t * p_slot,
+ es_flash_access_t access_type)
+{
+ if (slot_no >= APP_MAX_ADV_SLOTS)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ flash_access_params_t params = {.record_key = RECORD_KEY_SLOTS[slot_no],
+ .file_id = FILE_ID_ES_FLASH,
+ .p_data_buf = slots_buf_p[slot_no],
+ .p_data = (uint8_t *)p_slot,
+ .size_bytes = sizeof(es_slot_t),
+ .access_type = access_type};
+
+ return access_flash_data(&params);
+}
+
+
+ret_code_t es_flash_access_flags(es_flash_flags_t * p_flags, es_flash_access_t access_type)
+{
+ flash_access_params_t params = {.record_key = RECORD_KEY_FLAGS,
+ .file_id = FILE_ID_ES_FLASH,
+ .p_data_buf = flash_flags_buf,
+ .p_data = (uint8_t *)p_flags,
+ .size_bytes = sizeof(es_flash_flags_t),
+ .access_type = access_type};
+
+ return access_flash_data(&params);
+}
+
+
+ret_code_t es_flash_factory_reset(void)
+{
+ // Delete everything except the lock key:
+ ret_code_t ret_code = fds_file_delete(FILE_ID_ES_FLASH);
+
+ if (ret_code == FDS_SUCCESS)
+ m_factory_reset = true;
+ return ret_code;
+}
+
+
+uint32_t es_flash_num_pending_ops(void)
+{
+ return m_num_pending_ops;
+}
+
+
+void es_flash_on_ble_evt(ble_evt_t const * p_evt)
+{
+ switch (p_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ m_conn_handle = p_evt->evt.common_evt.conn_handle;
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ m_conn_handle = BLE_CONN_HANDLE_INVALID;
+ if (m_factory_reset)
+ {
+ (void)sd_nvic_SystemReset();
+ }
+ break;
+ }
+}
+
+
+ret_code_t es_flash_init(void)
+{
+ ret_code_t err_code;
+
+ m_num_pending_ops = 1; // Will be set to 0 when getting FDS_EVT_INIT event
+
+ m_conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ m_factory_reset = false;
+
+ err_code = fds_register(fds_cb);
+ RETURN_IF_ERROR(err_code);
+
+ err_code = fds_init();
+ RETURN_IF_ERROR(err_code);
+
+ return NRF_SUCCESS;
+}
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_flash.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_flash.h
new file mode 100644
index 0000000..d896669
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_flash.h
@@ -0,0 +1,177 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef ES_FLASH_H__
+#define ES_FLASH_H__
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "es_slot.h"
+
+
+/**
+ * @file
+ * @defgroup eddystone_flash Flash access
+ * @brief Types and functions to access the flash of the Eddystone beacon.
+ * @ingroup eddystone
+ * @{
+ */
+
+#define WORD_SIZE 4
+
+#define FLASH_ACCES_ERROR_CHECK_ALLOW_NOT_FOUND(err_code) \
+ if (err_code != (FDS_ERR_NOT_FOUND)) \
+ APP_ERROR_CHECK(err_code);
+
+#define FLASH_OP_WAIT() \
+ uint32_t pending_ops = es_flash_num_pending_ops(); \
+ while (pending_ops != 0) \
+ { \
+ pending_ops = es_flash_num_pending_ops(); \
+ }
+
+/**@brief Beacon configuration. */
+typedef struct
+{
+ nrf_ble_escs_adv_interval_t adv_interval; //!< Advertising interval.
+ bool remain_connectable; //!< Flag that specifies if the beacon should remain connectable.
+} es_flash_beacon_config_t;
+
+/**@brief Structure for keeping track of which slot has a configuration that must be restored upon reboot.
+ * @details The size of this structure must be word aligned and match the flash block size of 32 bytes.
+ */
+typedef struct
+{
+ bool slot_is_empty[APP_MAX_ADV_SLOTS]; //!< Flag that indicates whether the slot is empty.
+ uint8_t padding[WORD_SIZE - ((APP_MAX_ADV_SLOTS + 1) % WORD_SIZE)]; //!< Padding used to ensure word alignment.
+} es_flash_flags_t;
+
+/**@brief Flash access types.
+ */
+typedef enum
+{
+ ES_FLASH_ACCESS_READ, //!< Read data.
+ ES_FLASH_ACCESS_WRITE, //!< Write data.
+ ES_FLASH_ACCESS_CLEAR //!< Clear data.
+} es_flash_access_t;
+
+/**@brief Function for accessing beacon configurations.
+ *
+ * @param[out,in] p_config Pointer to the beacon configuration buffer.
+ * @param[in] access_type Access type (see @ref es_flash_access_t).
+ * @return For possible return values, see:
+ * - @ref fds_record_find_by_key
+ * - @ref fds_record_open
+ * - @ref fds_record_close
+ * - @ref fds_record_write
+ * - @ref fds_record_update
+ * - @ref fds_record_delete
+ */
+ret_code_t es_flash_access_beacon_config(es_flash_beacon_config_t * p_config,
+ es_flash_access_t access_type);
+
+/**@brief Function for accessing slot configuration from flash.
+ *
+ * @param[in] slot_no Slot index.
+ * @param[out,in] p_slot Pointer to the slot configuration buffer.
+ * @param[in] access_type Access type (see @ref es_flash_access_t).
+ * @return For possible return values, see:
+ * - @ref fds_record_find_by_key
+ * - @ref fds_record_open
+ * - @ref fds_record_close
+ * - @ref fds_record_write
+ * - @ref fds_record_update
+ * - @ref fds_record_delete
+ */
+ret_code_t es_flash_access_slot_configs(uint8_t slot_no,
+ es_slot_t * p_slot,
+ es_flash_access_t access_type);
+
+
+/**@brief Function for accessing the beacon lock key from flash.
+ *
+ * @param[out,in] p_lock_key Pointer to the lock key buffer.
+ * @param[in] access_type Access type (see @ref es_flash_access_t).
+ * @return For possible return values, see:
+ * - @ref fds_record_find_by_key
+ * - @ref fds_record_open
+ * - @ref fds_record_close
+ * - @ref fds_record_write
+ * - @ref fds_record_update
+ * - @ref fds_record_delete
+ */
+ret_code_t es_flash_access_lock_key(uint8_t * p_lock_key, es_flash_access_t access_type);
+
+/**@brief Function for accessing the flash configuration flag from flash.
+ *
+ * @param[out,in] p_flags Pointer to the flag buffer.
+ * @param[in] access_type Access type (see @ref es_flash_access_t).
+ * @return For possible return values, see:
+ * - @ref fds_record_find_by_key
+ * - @ref fds_record_open
+ * - @ref fds_record_close
+ * - @ref fds_record_write
+ * - @ref fds_record_update
+ * - @ref fds_record_delete
+ */
+ret_code_t es_flash_access_flags(es_flash_flags_t * p_flags, es_flash_access_t access_type);
+
+/**@brief Function for retrieving the number of queued operations.
+ * @return The number of operations that are queued.
+ */
+uint32_t es_flash_num_pending_ops(void);
+
+/**@brief Function for performing a factory reset.
+ * @return FDS return code.
+ */
+ret_code_t es_flash_factory_reset(void);
+
+void es_flash_on_ble_evt(ble_evt_t const * p_evt);
+
+/**@brief Function for initializing the flash module.
+ *
+ * @return See @ref fds_init for possible return values.
+ */
+ret_code_t es_flash_init(void);
+
+/**
+ * @}
+ */
+
+#endif // ES_FLASH_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts.c
new file mode 100644
index 0000000..c6280e2
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts.c
@@ -0,0 +1,188 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "es_gatts.h"
+#include "es_gatts_read.h"
+#include "es_gatts_write.h"
+#include "es_slot.h"
+
+static nrf_ble_escs_lock_state_read_t m_lock_state;
+static uint8_t m_active_slot;
+
+/**@brief Function checking if beacon is unlocked.
+ *
+ * @param[in] p_escs Pointer to Eddystone Configuration Service.
+ *
+ * @retval true If beacon is unlocked.
+ * @retval false If beacon is locked.
+ */
+static bool is_beacon_unlocked(const nrf_ble_escs_t * p_escs)
+{
+ return m_lock_state != NRF_BLE_ESCS_LOCK_STATE_LOCKED;
+}
+
+
+ret_code_t es_gatts_send_reply(nrf_ble_escs_t * p_escs,
+ ble_gatts_rw_authorize_reply_params_t * p_reply)
+{
+ VERIFY_PARAM_NOT_NULL(p_escs);
+ VERIFY_PARAM_NOT_NULL(p_reply);
+
+ if (p_escs->conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ return sd_ble_gatts_rw_authorize_reply(p_escs->conn_handle, p_reply);
+ }
+
+ return NRF_ERROR_INVALID_STATE;
+}
+
+
+ret_code_t es_gatts_send_op_not_permitted(nrf_ble_escs_t * p_escs, bool read)
+{
+ ble_gatts_rw_authorize_reply_params_t reply = {0};
+
+ VERIFY_PARAM_NOT_NULL(p_escs);
+
+ if (read)
+ {
+ reply.type = BLE_GATTS_AUTHORIZE_TYPE_READ;
+ reply.params.read.gatt_status = BLE_GATT_STATUS_ATTERR_READ_NOT_PERMITTED;
+ }
+
+ else
+ {
+ reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
+ reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_WRITE_NOT_PERMITTED;
+ }
+
+ return es_gatts_send_reply(p_escs, &reply);
+}
+
+
+
+void es_gatts_handle_write(nrf_ble_escs_t * p_escs,
+ uint16_t uuid,
+ uint16_t val_handle,
+ uint8_t const * p_data,
+ uint16_t length)
+{
+ ret_code_t err_code;
+
+ if (is_beacon_unlocked(p_escs))
+ {
+ if (uuid == BLE_UUID_ESCS_UNLOCK_CHAR)
+ {
+ err_code = es_gatts_send_op_not_permitted(p_escs, false);
+ APP_ERROR_CHECK(err_code);
+ }
+
+ else
+ {
+ err_code = es_gatts_write_handle_unlocked_write(
+ p_escs, uuid, val_handle, p_data, length, m_active_slot);
+ APP_ERROR_CHECK(err_code);
+ }
+ }
+
+ else
+ {
+ if (uuid == BLE_UUID_ESCS_UNLOCK_CHAR)
+ {
+ err_code = es_gatts_write_handle_unlock(p_escs, p_data, length, val_handle);
+ APP_ERROR_CHECK(err_code);
+ }
+
+ else
+ {
+ err_code = es_gatts_send_op_not_permitted(p_escs, false);
+ APP_ERROR_CHECK(err_code);
+ }
+ }
+}
+
+
+void es_gatts_handle_read(nrf_ble_escs_t * p_escs, uint16_t uuid, uint16_t val_handle)
+{
+ ret_code_t err_code;
+
+ if (is_beacon_unlocked(p_escs))
+ {
+ if (uuid == BLE_UUID_ESCS_UNLOCK_CHAR)
+ {
+ err_code = es_gatts_send_op_not_permitted(p_escs, true);
+ APP_ERROR_CHECK(err_code);
+ }
+
+ else
+ {
+ err_code = es_gatts_read_handle_unlocked_read(p_escs, uuid, val_handle, m_active_slot, m_lock_state);
+ APP_ERROR_CHECK(err_code);
+ }
+ }
+
+ else // Beacon is locked.
+ {
+ if (uuid == BLE_UUID_ESCS_UNLOCK_CHAR)
+ {
+ err_code = es_gatts_read_handle_unlock(p_escs);
+ APP_ERROR_CHECK(err_code);
+ }
+
+ else
+ {
+ err_code = es_gatts_read_handle_locked_read(p_escs, uuid, m_lock_state);
+ APP_ERROR_CHECK(err_code);
+ }
+ }
+}
+
+
+ret_code_t es_gatts_init(nrf_ble_escs_t * p_ble_escs)
+{
+ VERIFY_PARAM_NOT_NULL(p_ble_escs);
+
+ m_active_slot = 0;
+ m_lock_state = NRF_BLE_ESCS_LOCK_STATE_LOCKED;
+
+ p_ble_escs->p_active_slot = &m_active_slot;
+ p_ble_escs->p_lock_state = &m_lock_state;
+
+ return NRF_SUCCESS;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts.h
new file mode 100644
index 0000000..b5da232
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts.h
@@ -0,0 +1,109 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef ES_GATTS_H__
+#define ES_GATTS_H__
+
+#include <stdint.h>
+#include "nrf_ble_escs.h"
+
+/**
+ * @file
+ * @defgroup eddystone_gatts GATTS
+ * @brief Functions for handling GATTS write and read requests.
+ * @ingroup eddystone
+ * @{
+ */
+
+ret_code_t es_gatts_init(nrf_ble_escs_t * p_ble_escs);
+
+/**@brief Function for handling all write requests from the Central.
+ *
+ * @param[in] p_escs Pointer to the Eddystone Configuration Service.
+ * @param[in] uuid The UUID of the characteristic that is being written to.
+ * @param[in] val_handle Value handle field of the characteristic handle of the characteristic that is being written to.
+ * @param[in] p_data Pointer to the data to be written.
+ * @param[in] length Length of the data to be written.
+ *
+ */
+void es_gatts_handle_write(nrf_ble_escs_t * p_escs,
+ uint16_t uuid,
+ uint16_t val_handle,
+ uint8_t const * p_data,
+ uint16_t length);
+
+
+/**@brief Function for handling all read requests from the Central.
+ *
+ * @param[in] p_escs Pointer to the Eddystone Configuration Service.
+ * @param[in] uuid The UUID of the characteristic that is being read from.
+ * @param[in] val_handle Value handle field of the characteristic handle of the characteristic that is being read from.
+ *
+ */
+void es_gatts_handle_read(nrf_ble_escs_t * p_escs, uint16_t uuid, uint16_t val_handle);
+
+/**@brief Function for sending an RW-authorization reply.
+ *
+ * @param[in] p_escs Pointer to the Eddystone Configuration Service.
+ * @param[in] p_reply Pointer to the reply to send.
+ *
+ * @retval NRF_SUCCESS If the reply was successfully issued to the SoftDevice.
+ * @retval NRF_ERROR_NULL If either of the pointers @p p_escs or @p p_reply is NULL.
+ * @retval NRF_ERROR_INVALID_STATE If the connection handle of @p p_escs is invalid.
+ * @return Otherwise, an error code from sd_ble_gatts_rw_authorize_reply() is returned.
+ */
+ret_code_t es_gatts_send_reply(nrf_ble_escs_t * p_escs, ble_gatts_rw_authorize_reply_params_t * p_reply);
+
+/**@brief Function for sending an RW-authorization reply with status 'Operation not permitted'.
+ *
+ * @param[in] p_escs Pointer to the Eddystone Configuration Service.
+ * @param[in] op_is_read Flag that specifies if the operation being responded to is a 'read' operation.
+ If false, a 'write' operation is assumed.
+ *
+ * @retval NRF_ERROR_NULL If @p p_escs is NULL.
+ * @return Otherwise, the error code from es_gatts_send_reply() is returned.
+ */
+ret_code_t es_gatts_send_op_not_permitted(nrf_ble_escs_t * p_escs, bool op_is_read);
+
+/**
+ * @}
+ */
+
+#endif // ES_GATTS_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts_read.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts_read.c
new file mode 100644
index 0000000..6ab51de
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts_read.c
@@ -0,0 +1,246 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "es_gatts_read.h"
+#include "es_adv.h"
+#include "es_gatts.h"
+#include "es_security.h"
+#include "es_slot.h"
+
+static ret_code_t send_read_reply(nrf_ble_escs_t * p_escs, ble_gatts_rw_authorize_reply_params_t * p_reply)
+{
+ VERIFY_PARAM_NOT_NULL(p_escs);
+ VERIFY_PARAM_NOT_NULL(p_reply);
+
+ p_reply->type = BLE_GATTS_AUTHORIZE_TYPE_READ;
+ p_reply->params.read.update = 1;
+ p_reply->params.read.offset = 0;
+
+ return es_gatts_send_reply(p_escs, p_reply);
+}
+
+
+static ret_code_t read_value(nrf_ble_escs_t * p_escs, uint8_t length, const void * p_value)
+{
+ VERIFY_PARAM_NOT_NULL(p_escs);
+ VERIFY_PARAM_NOT_NULL(p_value);
+
+ ble_gatts_rw_authorize_reply_params_t reply = {0};
+ reply.params.read.len = length;
+ reply.params.read.p_data = p_value;
+ reply.params.read.gatt_status = BLE_GATT_STATUS_SUCCESS;
+
+ return send_read_reply(p_escs, &reply);
+}
+
+
+static ret_code_t read_from_gattdb(nrf_ble_escs_t * p_escs, uint16_t val_handle)
+{
+ VERIFY_PARAM_NOT_NULL(p_escs);
+
+ ret_code_t err_code;
+
+ // Go straight to the characteristic
+ uint8_t value_buffer[ESCS_ADV_SLOT_CHAR_LENGTH_MAX] = {0};
+ ble_gatts_value_t value = {.len = sizeof(value_buffer),
+ .offset = 0,
+ .p_value = &(value_buffer[0])};
+
+ err_code = sd_ble_gatts_value_get(p_escs->conn_handle, val_handle, &value);
+ RETURN_IF_ERROR(err_code);
+
+ return read_value(p_escs, value.len, value.p_value);
+}
+
+
+static ret_code_t read_adv_slot(nrf_ble_escs_t * p_escs, uint8_t active_slot, const es_slot_reg_t * p_reg)
+{
+ VERIFY_PARAM_NOT_NULL(p_escs);
+
+ ble_gatts_rw_authorize_reply_params_t reply = {0};
+ uint8_t eid_buf[14];
+
+ // If an EID slot is read, load scaler, clock value and ephemeral ID.
+ if (p_reg->slots[active_slot].adv_frame.type == ES_FRAME_TYPE_EID)
+ {
+ /*lint -save -e666 */
+ uint32_t clock_value = es_security_clock_get(active_slot);
+ clock_value = BYTES_REVERSE_32BIT(clock_value);
+ /*lint -restore */
+
+ reply.params.read.len = ES_EID_GATTS_READ_LENGTH;
+
+ // Fill EID buffer with data
+ eid_buf[ES_EID_GATTS_READ_FRAME_TYPE_IDX] = ES_FRAME_TYPE_EID;
+ eid_buf[ES_EID_GATTS_READ_EXPONENT_IDX] = es_security_scaler_get(active_slot);
+
+ memcpy(&eid_buf[ES_EID_GATTS_READ_CLCK_VALUE_IDX], &clock_value, sizeof(clock_value));
+ /*lint -save -e545 */
+ memcpy(&eid_buf[ES_EID_GATTS_READ_EID_IDX],
+ &p_reg->slots[active_slot].adv_frame.frame.eid.eid,
+ ES_EID_ID_LENGTH);
+ /*lint -restore */
+ reply.params.read.p_data = eid_buf;
+ }
+
+ // Otherwise, simply load the contents of the frame.
+ else
+ {
+ // Check if slot being read is an eTLM slot.
+ if ((p_reg->num_configured_eid_slots > 0) && p_reg->tlm_configured && (p_reg->tlm_slot == active_slot))
+ {
+ // Fill eTLM slot using EID key from first EID slot.
+ es_slot_etlm_update(p_reg->eid_slots_configured[0]);
+ }
+ reply.params.read.len = p_reg->slots[active_slot].adv_frame.length;
+ reply.params.read.p_data = (uint8_t *)&p_reg->slots[active_slot].adv_frame.frame;
+ }
+
+ reply.params.read.gatt_status = BLE_GATT_STATUS_SUCCESS;
+
+ return send_read_reply(p_escs, &reply);
+}
+
+
+ret_code_t es_gatts_read_handle_locked_read(nrf_ble_escs_t * p_escs, uint16_t uuid, uint8_t lock_state)
+{
+ VERIFY_PARAM_NOT_NULL(p_escs);
+
+ if (uuid == BLE_UUID_ESCS_REMAIN_CONNECTABLE_CHAR)
+ {
+ uint8_t retval = APP_IS_REMAIN_CONNECTABLE_SUPPORTED;
+ return read_value(p_escs, sizeof(retval), &retval);
+ }
+
+ else if (uuid == BLE_UUID_ESCS_LOCK_STATE_CHAR)
+ {
+ return read_value(p_escs, sizeof(lock_state), &lock_state);
+ }
+
+ else
+ {
+ return es_gatts_send_op_not_permitted(p_escs, true);
+ }
+}
+
+
+ret_code_t es_gatts_read_handle_unlock(nrf_ble_escs_t * p_escs)
+{
+ VERIFY_PARAM_NOT_NULL(p_escs);
+
+ ret_code_t err_code;
+ uint8_t key_buff[ESCS_AES_KEY_SIZE];
+
+ err_code = es_security_random_challenge_generate(key_buff);
+ RETURN_IF_ERROR(err_code);
+
+ es_security_unlock_prepare(key_buff);
+
+ return read_value(p_escs, ESCS_AES_KEY_SIZE, key_buff);
+}
+
+
+ret_code_t es_gatts_read_handle_unlocked_read(nrf_ble_escs_t * p_escs,
+ uint16_t uuid,
+ uint16_t val_handle,
+ uint8_t active_slot,
+ uint8_t lock_state)
+{
+ VERIFY_PARAM_NOT_NULL(p_escs);
+
+ const es_slot_reg_t * p_reg = es_slot_get_registry();
+
+ switch (uuid)
+ {
+ case BLE_UUID_ESCS_BROADCAST_CAP_CHAR:
+ case BLE_UUID_ESCS_UNLOCK_CHAR:
+ case BLE_UUID_ESCS_PUBLIC_ECDH_KEY_CHAR:
+ case BLE_UUID_ESCS_ACTIVE_SLOT_CHAR:
+ return read_from_gattdb(p_escs, val_handle);
+
+ case BLE_UUID_ESCS_LOCK_STATE_CHAR:
+ return read_value(p_escs, sizeof(lock_state), &lock_state);
+
+ case BLE_UUID_ESCS_ADV_INTERVAL_CHAR:
+ {
+ nrf_ble_escs_adv_interval_t adv_interval = es_adv_interval_get();
+ adv_interval = BYTES_SWAP_16BIT(adv_interval);
+ return read_value(p_escs, sizeof(adv_interval), &adv_interval);
+ }
+
+ case BLE_UUID_ESCS_RADIO_TX_PWR_CHAR:
+ return read_value(p_escs,
+ sizeof(nrf_ble_escs_radio_tx_pwr_t),
+ &p_reg->slots[active_slot].radio_tx_pwr);
+
+ case BLE_UUID_ESCS_ADV_TX_PWR_CHAR:
+ return read_value(p_escs,
+ sizeof(nrf_ble_escs_radio_tx_pwr_t),
+ p_reg->slots[active_slot].adv_custom_tx_power
+ ? (uint8_t *)(&p_reg->slots[active_slot].custom_tx_power)
+ : (uint8_t *)(&p_reg->slots[active_slot].radio_tx_pwr));
+
+ case BLE_UUID_ESCS_REMAIN_CONNECTABLE_CHAR:
+ {
+ uint8_t retval = APP_IS_REMAIN_CONNECTABLE_SUPPORTED;
+ return read_value(p_escs, sizeof(retval), &retval);
+ }
+
+ case BLE_UUID_ESCS_EID_ID_KEY_CHAR:
+ if (p_reg->slots[active_slot].configured &&
+ (p_reg->slots[active_slot].adv_frame.type == ES_FRAME_TYPE_EID))
+ {
+ return read_value(p_escs,
+ sizeof(nrf_ble_escs_eid_id_key_t),
+ &p_reg->slots[active_slot].encrypted_eid_id_key);
+ }
+
+ else
+ {
+ return es_gatts_send_op_not_permitted(p_escs, true);
+ }
+
+ case BLE_UUID_ESCS_RW_ADV_SLOT_CHAR:
+ return read_adv_slot(p_escs, active_slot, p_reg);
+
+ default:
+ return NRF_ERROR_INVALID_PARAM;
+ }
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts_read.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts_read.h
new file mode 100644
index 0000000..32cc818
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts_read.h
@@ -0,0 +1,73 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef ES_GATTS_READ_H__
+#define ES_GATTS_READ_H__
+
+#include <stdint.h>
+#include "nrf_ble_escs.h"
+
+/**
+ * @file
+ * @defgroup eddystone_gatts_read GATTS read
+ * @brief Functions for handling GATTS read requests.
+ * @ingroup eddystone_gatts
+ * @{
+ */
+
+ret_code_t es_gatts_read_send_not_permitted(nrf_ble_escs_t * p_escs);
+
+ret_code_t es_gatts_read_handle_unlocked_read(nrf_ble_escs_t * p_escs,
+ uint16_t uuid,
+ uint16_t val_handle,
+ uint8_t active_slot,
+ uint8_t lock_state);
+
+ret_code_t es_gatts_read_handle_unlock(nrf_ble_escs_t * p_escs);
+
+ret_code_t es_gatts_read_handle_locked_read(nrf_ble_escs_t * p_escs,
+ uint16_t uuid,
+ uint8_t lock_state);
+
+/**
+ * @}
+ */
+
+#endif // ES_GATTS_READ_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts_write.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts_write.c
new file mode 100644
index 0000000..8a66493
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts_write.c
@@ -0,0 +1,254 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "es_gatts_write.h"
+#include "es_adv.h"
+#include "es_flash.h"
+#include "es_gatts.h"
+#include "es_security.h"
+
+
+static ret_code_t send_write_reply(nrf_ble_escs_t * p_escs, ble_gatts_rw_authorize_reply_params_t * p_reply)
+{
+ VERIFY_PARAM_NOT_NULL(p_escs);
+ VERIFY_PARAM_NOT_NULL(p_reply);
+
+ p_reply->type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
+ p_reply->params.write.update = 1;
+ p_reply->params.write.offset = 0;
+
+ return es_gatts_send_reply(p_escs, p_reply);
+}
+
+
+/**@brief Function checking if length of event is correct, given the frame data.
+ *
+ * @param[in] p_data Written ADV Slot data.
+ * @param[in] length Written length.
+ *
+ * @retval true If length is valid.
+ * @retval false If length is not valid.
+ */
+static bool length_is_valid(uint8_t const * p_data, uint8_t length)
+{
+ if (length == 0 || (length == 1 && p_data[0] == 0))
+ {
+ return true;
+ }
+
+ else
+ {
+ switch ((es_frame_type_t)p_data[0])
+ {
+ case ES_FRAME_TYPE_UID:
+ return length == ESCS_UID_WRITE_LENGTH;
+
+ case ES_FRAME_TYPE_URL:
+ return ((length >= ESCS_URL_MIN_WRITE_LENGTH) && (length <= ESCS_URL_WRITE_LENGTH));
+
+ case ES_FRAME_TYPE_TLM:
+ return (length == ESCS_TLM_WRITE_LENGTH);
+
+ case ES_FRAME_TYPE_EID:
+ return ((length == ESCS_EID_WRITE_ECDH_LENGTH) ||
+ (length == ESCS_EID_WRITE_IDK_LENGTH));
+
+ default:
+ return false;
+ }
+ }
+}
+
+
+ret_code_t es_gatts_write_handle_unlocked_write(nrf_ble_escs_t * p_escs,
+ uint16_t uuid,
+ uint16_t val_handle,
+ uint8_t const * p_data,
+ uint16_t length,
+ uint8_t active_slot)
+{
+ VERIFY_PARAM_NOT_NULL(p_escs);
+ VERIFY_PARAM_NOT_NULL(p_data);
+
+ ret_code_t err_code;
+ ble_gatts_rw_authorize_reply_params_t reply = {0};
+ bool long_write = false;
+
+ reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+
+ switch (uuid)
+ {
+ case BLE_UUID_ESCS_ACTIVE_SLOT_CHAR:
+ if (*p_data > APP_MAX_ADV_SLOTS - 1)
+ {
+ // Invalid Attribute Length: for an attempt to write illegal values.
+ // The beacon will list the total number of available slots in the
+ // max_supported_total_slots field in the Capabilities characteristic.
+ reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH;
+ length = 0;
+ }
+ break;
+
+ case BLE_UUID_ESCS_ADV_INTERVAL_CHAR:
+ es_adv_interval_set(BYTES_SWAP_16BIT(*(nrf_ble_escs_adv_interval_t *)p_data));
+ break;
+
+ case BLE_UUID_ESCS_RADIO_TX_PWR_CHAR:
+ es_slot_radio_tx_pwr_set(active_slot, *(nrf_ble_escs_radio_tx_pwr_t *)(p_data));
+ break;
+
+ case BLE_UUID_ESCS_ADV_TX_PWR_CHAR:
+ // Update slot info so that ADV data will only be read from what is written by client.
+ es_slot_set_adv_custom_tx_power(active_slot, *(nrf_ble_escs_radio_tx_pwr_t *)(p_data));
+ break;
+
+ case BLE_UUID_ESCS_LOCK_STATE_CHAR:
+ if (length == 1 && (*p_data == NRF_BLE_ESCS_LOCK_BYTE_LOCK ||
+ *p_data == NRF_BLE_ESCS_LOCK_BYTE_DISABLE_AUTO_RELOCK))
+ {
+ // Do nothing special, allow the write.
+ }
+ else if (length == ESCS_LOCK_STATE_NEW_LOCK_CODE_WRITE_LENGTH &&
+ *p_data == NRF_BLE_ESCS_LOCK_BYTE_LOCK)
+ {
+ // 0x00 + key[16] : transition to lock state and update the lock code.
+ err_code = es_security_lock_code_update((uint8_t*)(p_data) + 1);
+ RETURN_IF_ERROR(err_code);
+
+ // Only write the lock byte (0x00) to the characteristic, so set length to 1.
+ length = 1;
+ }
+ else
+ {
+ // Any invalid values locks the characteristic by default.
+ (*(uint8_t*)p_data) = NRF_BLE_ESCS_LOCK_BYTE_LOCK;
+ length = 1;
+ }
+ break;
+
+ case BLE_UUID_ESCS_RW_ADV_SLOT_CHAR:
+ if (length > 20)
+ {
+ long_write = true;
+ }
+ reply.params.write.gatt_status = length_is_valid(p_data, length)
+ ? BLE_GATT_STATUS_SUCCESS
+ : BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH;
+
+ if (reply.params.write.gatt_status == BLE_GATT_STATUS_SUCCESS)
+ {
+ es_slot_on_write(active_slot, length, p_data);
+ es_adv_interval_set(es_adv_interval_get()); // Ensure that valid advertisement interval is used.
+ }
+ break;
+
+ case BLE_UUID_ESCS_FACTORY_RESET_CHAR:
+ if (*p_data == 0x0B)
+ {
+ err_code = es_flash_factory_reset();
+ RETURN_IF_ERROR(err_code);
+ }
+ break;
+
+ case BLE_UUID_ESCS_REMAIN_CONNECTABLE_CHAR:
+#if APP_IS_REMAIN_CONNECTABLE_SUPPORTED == ESCS_FUNCT_REMAIN_CONNECTABLE_SUPPORTED_Yes
+ if (*p_data != 0)
+ {
+ es_adv_remain_connectable_set(true);
+ }
+
+ else
+ {
+ es_adv_remain_connectable_set(false);
+ }
+#endif
+ break;
+
+ default:
+ break;
+ }
+ reply.params.write.len = length;
+ reply.params.write.p_data = p_data;
+
+ if (!long_write)
+ {
+ return send_write_reply(p_escs, &reply);
+ }
+
+ else
+ {
+ return NRF_SUCCESS;
+ }
+}
+
+
+ret_code_t es_gatts_write_handle_unlock(nrf_ble_escs_t * p_escs,
+ uint8_t const * p_data,
+ uint16_t length,
+ uint16_t val_handle)
+{
+ VERIFY_PARAM_NOT_NULL(p_escs);
+ VERIFY_PARAM_NOT_NULL(p_data);
+
+ ret_code_t err_code;
+ ble_gatts_rw_authorize_reply_params_t reply = {0};
+ ble_gatts_value_t value = {.len = length, .offset = 0, .p_value = (uint8_t*)p_data};
+
+ if (length == ESCS_AES_KEY_SIZE)
+ {
+ err_code = sd_ble_gatts_value_set(p_escs->conn_handle, val_handle, &value);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ es_security_unlock_verify((value.p_value));
+ }
+
+ else
+ {
+ reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_WRITE_NOT_PERMITTED;
+ }
+ }
+
+ reply.params.write.len = length;
+ reply.params.write.p_data = (const uint8_t *)value.p_value;
+
+ return send_write_reply(p_escs, &reply);
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts_write.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts_write.h
new file mode 100644
index 0000000..2bcbce1
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_gatts_write.h
@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef ES_GATTS_WRITE_H__
+#define ES_GATTS_WRITE_H__
+
+#include <stdint.h>
+#include "nrf_ble_escs.h"
+
+/**
+ * @file
+ * @defgroup eddystone_gatts_write GATTS write
+ * @brief Functions for handling GATTS write requests.
+ * @ingroup eddystone_gatts
+ * @{
+ */
+
+ret_code_t es_gatts_write_handle_unlocked_write(nrf_ble_escs_t * p_escs,
+ uint16_t uuid,
+ uint16_t val_handle,
+ uint8_t const * p_data,
+ uint16_t length,
+ uint8_t active_slot);
+
+ret_code_t es_gatts_write_handle_unlock(nrf_ble_escs_t * p_escs,
+ uint8_t const * p_data,
+ uint16_t length,
+ uint16_t val_handle);
+
+/**
+ * @}
+ */
+
+#endif // ES_GATTS_WRITE_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_security.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_security.c
new file mode 100644
index 0000000..303556a
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_security.c
@@ -0,0 +1,596 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <stdbool.h>
+#include <stdint.h>
+#include "es_security.h"
+#include "app_timer.h"
+#include "es_flash.h"
+#include "es_stopwatch.h"
+#include "fds.h"
+#include "modes.h"
+#include "nrf_crypto.h"
+
+#define TK_ROLLOVER 0x10000
+
+#define NONCE_SIZE (6)
+#define TAG_SIZE (2)
+#define SALT_SIZE (2)
+#define TLM_DATA_SIZE (ES_TLM_LENGTH - 2)
+#define EIK_SIZE (ESCS_AES_KEY_SIZE)
+#define AES_ECB_CIPHERTEXT_LENGTH (16)
+#define AES_ECB_CLEARTEXT_LENGTH (16)
+
+/**@brief Timing structure. */
+typedef struct
+{
+ uint32_t time_counter;
+ uint8_t k_scaler;
+} es_security_timing_t;
+
+/**@brief Security slot structure. */
+typedef struct
+{
+ nrf_ecb_hal_data_t aes_ecb_ik;
+ nrf_ecb_hal_data_t aes_ecb_tk;
+ uint8_t eid[ES_EID_ID_LENGTH];
+ es_security_timing_t timing;
+ bool is_occupied;
+} es_security_slot_t;
+
+/**@brief Key pair structure. */
+typedef struct
+{
+ nrf_crypto_ecc_private_key_t private;
+ nrf_crypto_ecc_public_key_t public;
+} ecdh_key_pair_t;
+
+/**@brief ECDH structure. */
+typedef struct
+{
+ ecdh_key_pair_t ecdh_key_pair;
+} es_security_ecdh_t;
+
+static nrf_ecb_hal_data_t m_aes_ecb_lk;
+static es_security_slot_t m_security_slot[APP_MAX_EID_SLOTS];
+static es_security_ecdh_t m_ecdh;
+static es_security_msg_cb_t m_security_callback;
+static es_stopwatch_id_t m_seconds_passed_sw_id;
+
+// Use static context variables to avoid stack allocation.
+static nrf_crypto_aes_context_t m_aes_context;
+static nrf_crypto_hmac_context_t m_hmac_context;
+static nrf_crypto_aead_context_t m_aead_context;
+static nrf_crypto_ecc_key_pair_generate_context_t ecc_key_pair_generate_context;
+static nrf_crypto_ecdh_context_t ecdh_context;
+
+/**@brief Generates a EID with the Temporary Key*/
+static void eid_generate(uint8_t slot_no)
+{
+ ret_code_t err_code;
+ size_t ciphertext_size = AES_ECB_CIPHERTEXT_LENGTH;
+
+ memset(m_security_slot[slot_no].aes_ecb_tk.cleartext, 0, ESCS_AES_KEY_SIZE);
+ m_security_slot[slot_no].aes_ecb_tk.cleartext[11] = m_security_slot[slot_no].timing.k_scaler;
+
+ uint32_t k_bits_cleared_time =
+ (m_security_slot[slot_no].timing.time_counter >> m_security_slot[slot_no].timing.k_scaler)
+ << m_security_slot[slot_no].timing.k_scaler;
+
+ m_security_slot[slot_no].aes_ecb_tk.cleartext[12] =
+ (uint8_t)((k_bits_cleared_time >> 24) & 0xff);
+ m_security_slot[slot_no].aes_ecb_tk.cleartext[13] =
+ (uint8_t)((k_bits_cleared_time >> 16) & 0xff);
+ m_security_slot[slot_no].aes_ecb_tk.cleartext[14] = (uint8_t)((k_bits_cleared_time >> 8) & 0xff);
+ m_security_slot[slot_no].aes_ecb_tk.cleartext[15] = (uint8_t)((k_bits_cleared_time) & 0xff);
+
+ err_code = nrf_crypto_aes_crypt(&m_aes_context,
+ &g_nrf_crypto_aes_ecb_128_info,
+ NRF_CRYPTO_ENCRYPT, // Operation
+ m_security_slot[slot_no].aes_ecb_tk.key, // Key
+ NULL, // IV
+ m_security_slot[slot_no].aes_ecb_tk.cleartext, // Data in
+ AES_ECB_CLEARTEXT_LENGTH, // Data in size
+ m_security_slot[slot_no].aes_ecb_tk.ciphertext, // Data out
+ &ciphertext_size); // Data out size
+
+ APP_ERROR_CHECK(err_code);
+
+ memcpy(m_security_slot[slot_no].eid,
+ m_security_slot[slot_no].aes_ecb_tk.ciphertext,
+ ES_EID_ID_LENGTH);
+
+ m_security_callback(slot_no, ES_SECURITY_MSG_EID);
+}
+
+
+/**@brief Generates a temporary key with the Identity key. */
+static void temp_key_generate(uint8_t slot_no)
+{
+ ret_code_t err_code;
+ size_t ciphertext_size = AES_ECB_CIPHERTEXT_LENGTH;
+
+ memset(m_security_slot[slot_no].aes_ecb_ik.cleartext, 0, ESCS_AES_KEY_SIZE);
+ m_security_slot[slot_no].aes_ecb_ik.cleartext[11] = 0xFF;
+ m_security_slot[slot_no].aes_ecb_ik.cleartext[14] =
+ (uint8_t)((m_security_slot[slot_no].timing.time_counter >> 24) & 0xff);
+ m_security_slot[slot_no].aes_ecb_ik.cleartext[15] =
+ (uint8_t)((m_security_slot[slot_no].timing.time_counter >> 16) & 0xff);
+
+ err_code = nrf_crypto_aes_crypt(&m_aes_context,
+ &g_nrf_crypto_aes_ecb_128_info,
+ NRF_CRYPTO_ENCRYPT, // Operation
+ m_security_slot[slot_no].aes_ecb_ik.key, // Key
+ NULL, // IV
+ m_security_slot[slot_no].aes_ecb_ik.cleartext, // Data in
+ AES_ECB_CLEARTEXT_LENGTH, // Data in size
+ m_security_slot[slot_no].aes_ecb_ik.ciphertext, // Data out
+ &ciphertext_size); // Data out size
+
+ APP_ERROR_CHECK(err_code);
+
+ memcpy(m_security_slot[slot_no].aes_ecb_tk.key,
+ m_security_slot[slot_no].aes_ecb_ik.ciphertext,
+ ESCS_AES_KEY_SIZE);
+}
+
+
+static void check_rollovers_and_update_eid(uint8_t slot_no)
+{
+ if (m_security_slot[slot_no].timing.time_counter % TK_ROLLOVER == 0)
+ {
+ temp_key_generate(slot_no);
+ }
+ /*lint -save -e573 */
+ if ((m_security_slot[slot_no].timing.time_counter %
+ (2 << (m_security_slot[slot_no].timing.k_scaler - 1))) == 0)
+ {
+ eid_generate(slot_no);
+ }
+ /*lint -restore */
+}
+
+
+/**@brief Initialize lock code from flash. If it does not exist, copy from APP_CONFIG_LOCK_CODE.
+ */
+static void lock_code_init(uint8_t * p_lock_buff)
+{
+ ret_code_t err_code;
+
+ err_code = es_flash_access_lock_key(p_lock_buff, ES_FLASH_ACCESS_READ);
+ FLASH_ACCES_ERROR_CHECK_ALLOW_NOT_FOUND(err_code);
+
+ // If no lock keys exist, then generate one and copy it to buffer.
+ if (err_code == FDS_ERR_NOT_FOUND)
+ {
+ uint8_t lock_code[16] = APP_CONFIG_LOCK_CODE;
+
+ memcpy(p_lock_buff, lock_code, sizeof(lock_code));
+
+ err_code = es_flash_access_lock_key(p_lock_buff, ES_FLASH_ACCESS_WRITE);
+ APP_ERROR_CHECK(err_code);
+ }
+}
+
+
+void es_security_update_time(void)
+{
+ static uint32_t timer_persist;
+ uint32_t second_since_last_invocation = es_stopwatch_check(m_seconds_passed_sw_id);
+
+ if (second_since_last_invocation > 0)
+ {
+ for (uint32_t i = 0; i < APP_MAX_EID_SLOTS; ++i)
+ {
+ if (m_security_slot[i].is_occupied)
+ {
+ m_security_slot[i].timing.time_counter += second_since_last_invocation;
+ check_rollovers_and_update_eid(i);
+ }
+ }
+
+ // Every 24 hr, write the new EID timer to flash.
+ timer_persist += second_since_last_invocation;
+ const uint32_t TWENTY_FOUR_HOURS = 60 * 60 * 24;
+ if (timer_persist >= TWENTY_FOUR_HOURS)
+ {
+ for (uint32_t i = 0; i < APP_MAX_EID_SLOTS; ++i)
+ {
+ if (m_security_slot[i].is_occupied)
+ {
+ m_security_callback(i, ES_SECURITY_MSG_STORE_TIME);
+ }
+ }
+ timer_persist = 0;
+ }
+ }
+}
+
+
+void es_security_eid_slots_restore(uint8_t slot_no,
+ uint8_t k_scaler,
+ uint32_t time_counter,
+ const uint8_t * p_ik)
+{
+ m_security_slot[slot_no].timing.k_scaler = k_scaler;
+ m_security_slot[slot_no].timing.time_counter = time_counter;
+ memcpy(m_security_slot[slot_no].aes_ecb_ik.key, p_ik, ESCS_AES_KEY_SIZE);
+ m_security_slot[slot_no].is_occupied = true;
+ m_security_callback(slot_no, ES_SECURITY_MSG_IK);
+ temp_key_generate(slot_no);
+ eid_generate(slot_no);
+}
+
+
+ret_code_t es_security_lock_code_update(uint8_t * p_ecrypted_key)
+{
+ ret_code_t err_code;
+ uint8_t temp_buff[ESCS_AES_KEY_SIZE] = {0};
+ size_t temp_buff_size = sizeof(temp_buff);
+
+ err_code = nrf_crypto_aes_crypt(&m_aes_context,
+ &g_nrf_crypto_aes_ecb_128_info,
+ NRF_CRYPTO_DECRYPT, // Operation
+ m_aes_ecb_lk.key, // Key
+ NULL, // IV
+ p_ecrypted_key, // Data in
+ 16, // Data in size
+ temp_buff, // Data out
+ &temp_buff_size); // Data out size
+
+ VERIFY_SUCCESS(err_code);
+
+ memcpy(m_aes_ecb_lk.key, temp_buff, ESCS_AES_KEY_SIZE);
+ return es_flash_access_lock_key(m_aes_ecb_lk.key, ES_FLASH_ACCESS_WRITE);
+}
+
+
+void es_security_unlock_prepare(uint8_t * p_challenge)
+{
+ ret_code_t err_code;
+ size_t ciphertext_size = AES_ECB_CIPHERTEXT_LENGTH;
+
+ memcpy(m_aes_ecb_lk.cleartext, p_challenge, ESCS_AES_KEY_SIZE);
+
+ err_code = nrf_crypto_aes_crypt(&m_aes_context,
+ &g_nrf_crypto_aes_ecb_128_info,
+ NRF_CRYPTO_ENCRYPT, // Operation
+ m_aes_ecb_lk.key, // Key
+ NULL, // IV
+ m_aes_ecb_lk.cleartext, // Data in
+ AES_ECB_CLEARTEXT_LENGTH, // Data in size
+ m_aes_ecb_lk.ciphertext, // Data out
+ &ciphertext_size); // Data out size
+
+ APP_ERROR_CHECK(err_code);
+}
+
+
+void es_security_unlock_verify(uint8_t * p_unlock_token)
+{
+ if (memcmp(p_unlock_token, m_aes_ecb_lk.ciphertext, ESCS_AES_KEY_SIZE) == 0)
+ {
+ m_security_callback(0, ES_SECURITY_MSG_UNLOCKED);
+ }
+}
+
+
+ret_code_t es_security_random_challenge_generate(uint8_t * p_rand_chlg_buff)
+{
+ return nrf_crypto_rng_vector_generate(p_rand_chlg_buff, ESCS_AES_KEY_SIZE);
+}
+
+
+void es_security_shared_ik_receive(uint8_t slot_no, uint8_t * p_encrypted_ik, uint8_t scaler_k)
+{
+ ret_code_t err_code;
+ size_t cleartext_size = AES_ECB_CLEARTEXT_LENGTH;
+
+ m_security_slot[slot_no].is_occupied = true;
+ m_security_slot[slot_no].timing.k_scaler = scaler_k;
+ m_security_slot[slot_no].timing.time_counter = APP_CONFIG_TIMING_INIT_VALUE;
+
+ err_code = nrf_crypto_aes_crypt(&m_aes_context,
+ &g_nrf_crypto_aes_ecb_128_info,
+ NRF_CRYPTO_DECRYPT, // Operation
+ m_aes_ecb_lk.key, // Key
+ NULL, // IV
+ p_encrypted_ik, // Data in
+ 16, // Data in size
+ m_security_slot[slot_no].aes_ecb_ik.key, // Data out
+ &cleartext_size); // Data out size
+
+ APP_ERROR_CHECK(err_code);
+
+ temp_key_generate(slot_no);
+ eid_generate(slot_no);
+
+ m_security_callback(slot_no, ES_SECURITY_MSG_IK);
+}
+
+
+void es_security_client_pub_ecdh_receive(uint8_t slot_no, uint8_t * p_pub_ecdh, uint8_t scaler_k)
+{
+ ret_code_t err_code;
+ nrf_crypto_ecc_public_key_t phone_public; // Phone public ECDH key
+ uint8_t beacon_public[ESCS_ECDH_KEY_SIZE]; // Beacon public ECDH key
+ uint8_t shared[ESCS_ECDH_KEY_SIZE]; // Shared secret ECDH key
+ uint8_t public_keys[64]; // Buffer for concatenated public keys
+ uint8_t key_material[64]; // Buffer for holding key material
+ uint8_t empty_check[ESCS_ECDH_KEY_SIZE] = {0};
+ size_t beacon_public_size = sizeof(beacon_public);
+ size_t shared_size = sizeof(shared);
+ size_t key_material_size = sizeof(key_material);
+
+ m_security_slot[slot_no].is_occupied = true;
+ m_security_slot[slot_no].timing.k_scaler = scaler_k;
+ m_security_slot[slot_no].timing.time_counter = APP_CONFIG_TIMING_INIT_VALUE;
+
+ // Get public 32-byte service ECDH key from phone.
+ err_code = nrf_crypto_ecc_public_key_from_raw(&g_nrf_crypto_ecc_curve25519_curve_info,
+ &phone_public,
+ p_pub_ecdh,
+ ESCS_ECDH_KEY_SIZE);
+
+ APP_ERROR_CHECK(err_code);
+
+ // Generate key pair.
+ err_code = nrf_crypto_ecc_key_pair_generate(&ecc_key_pair_generate_context,
+ &g_nrf_crypto_ecc_curve25519_curve_info,
+ &m_ecdh.ecdh_key_pair.private,
+ &m_ecdh.ecdh_key_pair.public);
+
+ APP_ERROR_CHECK(err_code);
+
+ // Generate shared 32-byte ECDH secret from beacon private service ECDH key and phone public ECDH key.
+ err_code = nrf_crypto_ecdh_compute(&ecdh_context,
+ &m_ecdh.ecdh_key_pair.private,
+ &phone_public,
+ shared,
+ &shared_size);
+
+ APP_ERROR_CHECK(err_code);
+
+ // Verify that the shared secret is not zero at this point, and report an error/reset if it is.
+ if (memcmp(empty_check, shared, ESCS_ECDH_KEY_SIZE) == 0)
+ {
+ APP_ERROR_CHECK(NRF_ERROR_INTERNAL);
+ }
+
+ // Concatenate the resolver's public key and beacon's public key
+ err_code = nrf_crypto_ecc_public_key_to_raw(&m_ecdh.ecdh_key_pair.public,
+ beacon_public,
+ &beacon_public_size);
+
+ APP_ERROR_CHECK(err_code);
+
+ memcpy(public_keys, p_pub_ecdh, 32);
+ memcpy(public_keys + 32, beacon_public, 32);
+
+ // Convert the shared secret to key material using HKDF-SHA256. HKDF is used with the salt set
+ // to a concatenation of the resolver's public key and beacon's public key
+ err_code = nrf_crypto_hkdf_calculate(&m_hmac_context,
+ &g_nrf_crypto_hmac_sha256_info,
+ key_material, // Output key
+ &key_material_size, // Output key size
+ shared, // Input key
+ sizeof(shared), // Input key size
+ public_keys, // Salt
+ sizeof(public_keys), // Salt size
+ NULL, // Additional info
+ 0, // Additional info size
+ NRF_CRYPTO_HKDF_EXTRACT_AND_EXPAND); // Mode
+
+ APP_ERROR_CHECK(err_code);
+
+ // Truncate the key material to 128 bits to convert it to an AES-128 secret key (Identity key).
+ memcpy(m_security_slot[slot_no].aes_ecb_ik.key, key_material, ESCS_AES_KEY_SIZE);
+
+ temp_key_generate(slot_no);
+ eid_generate(slot_no);
+
+ m_security_callback(slot_no, ES_SECURITY_MSG_ECDH);
+ m_security_callback(slot_no, ES_SECURITY_MSG_IK);
+}
+
+
+void es_security_pub_ecdh_get(uint8_t slot_no, uint8_t * p_edch_buffer)
+{
+ ret_code_t err_code;
+ size_t buffer_size = ESCS_ECDH_KEY_SIZE;
+
+ err_code = nrf_crypto_ecc_public_key_to_raw(&m_ecdh.ecdh_key_pair.public,
+ p_edch_buffer,
+ &buffer_size);
+
+ APP_ERROR_CHECK(err_code);
+}
+
+
+uint32_t es_security_clock_get(uint8_t slot_no)
+{
+ return m_security_slot[slot_no].timing.time_counter;
+}
+
+
+void es_security_eid_slot_destroy(uint8_t slot_no)
+{
+ memset(&m_security_slot[slot_no], 0, sizeof(es_security_slot_t));
+}
+
+
+uint8_t es_security_scaler_get(uint8_t slot_no)
+{
+ return m_security_slot[slot_no].timing.k_scaler;
+}
+
+
+void es_security_eid_get(uint8_t slot_no, uint8_t * p_eid_buffer)
+{
+ memcpy(p_eid_buffer, m_security_slot[slot_no].eid, ES_EID_ID_LENGTH);
+}
+
+
+void es_security_encrypted_eid_id_key_get(uint8_t slot_no, uint8_t * p_key_buffer)
+{
+ ret_code_t err_code;
+ size_t ciphertext_size = AES_ECB_CIPHERTEXT_LENGTH;
+
+ memcpy(m_aes_ecb_lk.cleartext, m_security_slot[slot_no].aes_ecb_ik.key, ESCS_AES_KEY_SIZE);
+
+ err_code = nrf_crypto_aes_crypt(&m_aes_context,
+ &g_nrf_crypto_aes_ecb_128_info,
+ NRF_CRYPTO_ENCRYPT, // Operation
+ m_aes_ecb_lk.key, // Key
+ NULL, // IV
+ m_aes_ecb_lk.cleartext, // Data in
+ AES_ECB_CLEARTEXT_LENGTH, // Data in size
+ m_aes_ecb_lk.ciphertext, // Data out
+ &ciphertext_size); // Data out size
+
+ APP_ERROR_CHECK(err_code);
+
+ memcpy(p_key_buffer, m_aes_ecb_lk.ciphertext, ESCS_AES_KEY_SIZE);
+}
+
+
+void es_security_plain_eid_id_key_get(uint8_t slot_no, uint8_t * p_key_buffer)
+{
+ memcpy(p_key_buffer, m_security_slot[slot_no].aes_ecb_ik.key, ESCS_AES_KEY_SIZE);
+}
+
+
+void es_security_tlm_to_etlm(uint8_t ik_slot_no, es_tlm_frame_t * p_tlm, es_etlm_frame_t * p_etlm)
+{
+ ret_code_t err_code;
+ uint8_t plain[TLM_DATA_SIZE] = {0}; // Plaintext tlm, without the frame byte and version.
+ size_t nplain = TLM_DATA_SIZE; // Length of message plaintext.
+
+ /*lint -save -e420 */
+ memcpy(plain, &p_tlm->vbatt[0], sizeof(plain));
+
+ uint8_t key[EIK_SIZE] = {0}; // Encryption/decryption key: EIK.
+
+ memcpy(key, &m_security_slot[ik_slot_no].aes_ecb_ik.key[0], EIK_SIZE);
+ /*lint -restore */
+
+ uint8_t nonce[NONCE_SIZE] = {0}; // Nonce. This must not repeat for a given key.
+ size_t nnonce = NONCE_SIZE; // Length of nonce.First 4 bytes are beacon time base with k-bits cleared.
+ // Last two bits are randomly generated
+
+ // Take the current timestamp and clear the lowest K bits, use it as nonce.
+ uint32_t k_bits_cleared_time = (m_security_slot[ik_slot_no].timing.time_counter
+ >> m_security_slot[ik_slot_no].timing.k_scaler)
+ << m_security_slot[ik_slot_no].timing.k_scaler;
+
+ nonce[0] = (uint8_t)((k_bits_cleared_time >> 24) & 0xff);
+ nonce[1] = (uint8_t)((k_bits_cleared_time >> 16) & 0xff);
+ nonce[2] = (uint8_t)((k_bits_cleared_time >> 8) & 0xff);
+ nonce[3] = (uint8_t)((k_bits_cleared_time) & 0xff);
+
+ // Generate random salt.
+ uint8_t salt[SALT_SIZE] = {0};
+ err_code = nrf_crypto_rng_vector_generate(salt, SALT_SIZE);
+ APP_ERROR_CHECK(err_code);
+ memcpy(&nonce[4], salt, SALT_SIZE);
+
+ uint8_t cipher[ES_ETLM_ECRYPTED_LENGTH]; // Ciphertext output. nplain bytes are written.
+ uint8_t tag[TAG_SIZE] = {0}; // Authentication tag. ntag bytes are written.
+ size_t ntag = TAG_SIZE; // Length of authentication tag.
+
+ // Encryption
+ // --------------------------------------------------------------------------
+ err_code = nrf_crypto_aead_init(&m_aead_context, &g_nrf_crypto_aes_eax_128_info, key);
+ APP_ERROR_CHECK(err_code);
+
+ err_code = nrf_crypto_aead_crypt(&m_aead_context,
+ NRF_CRYPTO_ENCRYPT, // Operation
+ nonce, // Nonce
+ nnonce, // Nonce size
+ NULL, // Additional authenticated data (adata)
+ 0, // Additional authenticated data size
+ plain, // Input data
+ nplain, // Input data size
+ cipher, // Output data
+ tag, // MAC result output
+ ntag); // MAC size
+
+ APP_ERROR_CHECK(err_code);
+
+ err_code = nrf_crypto_aead_uninit(&m_aead_context);
+ APP_ERROR_CHECK(err_code);
+
+ // Construct the eTLM.
+ // --------------------------------------------------------------------------
+ p_etlm->frame_type = p_tlm->frame_type;
+ p_etlm->version = ES_TLM_VERSION_ETLM;
+ memcpy(p_etlm->encrypted_tlm, cipher, ES_ETLM_ECRYPTED_LENGTH);
+ memcpy((uint8_t *)&p_etlm->random_salt, salt, SALT_SIZE);
+ memcpy((uint8_t *)&p_etlm->msg_integrity_check, tag, TAG_SIZE);
+}
+
+
+ret_code_t es_security_init(es_security_msg_cb_t security_callback)
+{
+ ret_code_t err_code;
+
+ if (security_callback == NULL)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ // Get lock code from 'es_app_config.h', or fetch it from flash if exists.
+ lock_code_init(m_aes_ecb_lk.key);
+
+ m_security_callback = security_callback;
+
+ memset(&m_ecdh, 0, sizeof(es_security_ecdh_t));
+
+ for (uint32_t i = 0; i < APP_MAX_EID_SLOTS; ++i)
+ {
+ m_security_slot[i].timing.time_counter = APP_CONFIG_TIMING_INIT_VALUE;
+ }
+ err_code = es_stopwatch_create(&m_seconds_passed_sw_id, APP_TIMER_TICKS(1000));
+ APP_ERROR_CHECK(err_code);
+
+ err_code = nrf_crypto_init();
+ APP_ERROR_CHECK(err_code);
+
+ return NRF_SUCCESS;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_security.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_security.h
new file mode 100644
index 0000000..e518ebe
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_security.h
@@ -0,0 +1,238 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef ES_SECURITY_H__
+#define ES_SECURITY_H__
+
+#include "app_error.h"
+#include "nrf_ble_escs.h"
+
+/**
+ * @file
+ * @defgroup eddystone_security Security
+ * @brief Types and functions for dealing with security of Eddystone beacons.
+ * @ingroup eddystone
+ * @{
+ */
+
+/**@brief Security events.
+ */
+typedef enum
+{
+ ES_SECURITY_MSG_UNLOCKED, //!< Beacon is unlocked.
+ ES_SECURITY_MSG_EID, //!< EID has been generated.
+ ES_SECURITY_MSG_IK, //!< IK has been generated.
+ ES_SECURITY_MSG_ECDH, //!< Public ECDH has been generated.
+ ES_SECURITY_MSG_STORE_TIME //!< EID slot time must be stored.
+} es_security_msg_t;
+
+/* @brief Callback for security events. */
+typedef void (*es_security_msg_cb_t)(uint8_t slot_no, es_security_msg_t msg_type);
+
+/**@brief EID configuration.
+ *
+ * @details This structure is used to preserve or restore an EID slot.
+ *
+ * @note This is a packed structure. Therefore, you should not change it.
+*/
+typedef PACKED_STRUCT
+{
+ es_frame_type_t frame_type;
+ uint8_t k_scaler;
+ uint32_t time_counter;
+ uint8_t ik[ESCS_AES_KEY_SIZE];
+} es_eid_config_t;
+
+/**@brief Eddystone beacon lock state.
+ */
+typedef nrf_ble_escs_lock_state_read_t es_security_lock_state_t;
+
+/**@brief Function for initializing the security module.
+ *
+ * @param[in] msg_cb Callback function.
+ *
+ * @return See @ref app_timer_start for possible return values.
+ */
+ret_code_t es_security_init(es_security_msg_cb_t msg_cb);
+
+/**@brief Function for updating the lock code and storing it to flash.
+ *
+ * @param[in] p_encrypted_key Pointer to the new lock code.
+ *
+ * @return See @ref es_flash_access_lock_key for possible return values.
+ */
+ret_code_t es_security_lock_code_update(uint8_t * p_encrypted_key);
+
+/**@brief Function for reading the challenge and encrypting it with AES_ECB.
+ *
+ * @details The result of the encryption is compared with the provided unlock token
+ * in @ref es_security_unlock_verify.
+ *
+ * @param[in] p_challenge Pointer to the challenge buffer.
+ *
+ * @return See @ref sd_ecb_block_encrypt for possible return values.
+ */
+void es_security_unlock_prepare(uint8_t * p_challenge);
+
+/**@brief Function for unlocking the beacon.
+ *
+ * @details This function compares the result from @ref es_security_unlock_prepare to the input
+ * unlock token and unlocks the beacon if matching.
+ *
+ * @param[in] p_unlock_token The unlock token written by the client.
+ */
+void es_security_unlock_verify(uint8_t * p_unlock_token);
+
+/**@brief Function for generating a random challenge for the unlock characteristic.
+ *
+ * @param[out] p_rand_chlg_buff Pointer to a buffer to which the random challenge is copied.
+ *
+ * @return See @ref sd_rand_application_vector_get for possible return values.
+ */
+ret_code_t es_security_random_challenge_generate(uint8_t * p_rand_chlg_buff);
+
+/**@brief Function for storing the public ECDH key from the client in the beacon registration process.
+ *
+ * @details This function starts a series of cryptographic activities, including the generation of temporary keys and EIDs.
+ *
+ * @param[in] slot_no The index of the slot whose public ECDH key is retrieved.
+ * @param[in] p_pub_ecdh Pointer to the public ECDH.
+ * @param[in] scaler_k K rotation scaler.
+ */
+void es_security_client_pub_ecdh_receive(uint8_t slot_no, uint8_t * p_pub_ecdh, uint8_t scaler_k);
+
+
+/**@brief Function for storing the shared IK from the client in the beacon registration process.
+ *
+ * @details This function starts a series of cryptographic activities, including the generation of temporary keys and EIDs.
+ *
+ * @param[in] slot_no The index of the slot whose public ECDH key is retrieved.
+ * @param[in] p_encrypted_ik Pointer to the received IK.
+ * @param[in] scaler_k K rotation scaler.
+ */
+void es_security_shared_ik_receive(uint8_t slot_no, uint8_t * p_encrypted_ik, uint8_t scaler_k);
+
+/**@brief Function for copying the 32-byte ECDH key into the provided buffer.
+ *
+ * @param[in] slot_no The index of the slot whose public ECDH key is retrieved.
+ * @param[out] p_edch_buffer Pointer to the buffer.
+ */
+void es_security_pub_ecdh_get(uint8_t slot_no, uint8_t * p_edch_buffer);
+
+/**@brief Function for returning the beacon clock value (in little endian).
+ *
+ * @param[in] slot_no The index of the slot.
+ *
+ * @return 32-bit clock value.
+ */
+uint32_t es_security_clock_get(uint8_t slot_no);
+
+/**@brief Function for updating the beacon time counter.
+ *
+ * @details This function checks how much time has passed since the last
+ * invocation and, if required, updates the EID, the temporary key, or both.
+ * The function generates an @ref ES_SECURITY_MSG_STORE_TIME event
+ * for each active security slot every 24 hours.
+ */
+void es_security_update_time(void);
+
+/**@brief Function for returning the rotation exponent scaler value.
+ *
+ * @param[in] slot_no The index of the slot.
+ *
+ * @return K rotation scaler.
+ */
+uint8_t es_security_scaler_get(uint8_t slot_no);
+
+/**@brief Function for copying the 8-byte EID into the provided buffer.
+ *
+ * @param[in] slot_no The index of the slot whose EID is retrieved.
+ * @param[out] p_eid_buffer Pointer to the buffer.
+ */
+void es_security_eid_get(uint8_t slot_no, uint8_t * p_eid_buffer);
+
+/**@brief Function for restoring an EID slot.
+ *
+ * @param[in] slot_no The index of the slot to restore.
+ * @param[in] k_scaler K rotation scaler.
+ * @param[in] time_counter EID slot time counter value (in seconds).
+ * @param[in] p_ik Pointer to the identity key of the specified slot.
+ */
+void es_security_eid_slots_restore(uint8_t slot_no,
+ uint8_t k_scaler,
+ uint32_t time_counter,
+ const uint8_t * p_ik);
+
+/**@brief Function for destroying stored EID states.
+ *
+ * @details This function should be called when the slot is either overwritten as another slot or
+ * cleared by writing an empty byte or a single 0.
+ *
+ * @param[in] slot_no The index of the slot to destroy.
+ */
+void es_security_eid_slot_destroy(uint8_t slot_no);
+
+/**@brief Function for copying the 16-byte EID ID key into the provided buffer.
+ *
+ * @param[in] slot_no The index of the EID slot whose IK is retrieved.
+ * @param[out] p_key_buffer Buffer for the key.
+ */
+void es_security_plain_eid_id_key_get(uint8_t slot_no, uint8_t * p_key_buffer);
+
+/**@brief Function for copying the 16-byte LK encrypted EID ID key into the provided buffer.
+ *
+ * @param[in] slot_no The index of the EID slot whose encrypted IK is retrieved.
+ * @param[out] p_key_buffer Buffer for the key.
+ */
+void es_security_encrypted_eid_id_key_get(uint8_t slot_no, uint8_t * p_key_buffer);
+
+
+/**@brief Function for converting a TLM frame into an eTLM frame using the EIK of the specified slot.
+ *
+ * @param[in] ik_slot_no The index of the EID slot whose IK is paired with the eTLM.
+ * @param[in] p_tlm Pointer to the TLM frame buffer.
+ * @param[out] p_etlm Pointer to the eTLM frame buffer.
+ */
+void es_security_tlm_to_etlm(uint8_t ik_slot_no, es_tlm_frame_t * p_tlm, es_etlm_frame_t * p_etlm);
+
+/**
+ * @}
+ */
+
+#endif // ES_SECURITY_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_slot.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_slot.c
new file mode 100644
index 0000000..55590a7
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_slot.c
@@ -0,0 +1,440 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <stdint.h>
+#include <string.h>
+#include "es_slot.h"
+#include "es_flash.h"
+#include "es_security.h"
+#include "es_slot_reg.h"
+#include "es_tlm.h"
+#include "fds.h"
+
+static es_slot_reg_t m_reg; //!< Slot registry.
+static bool m_eid_loaded_from_flash; //!< Set to true if EID slot has been loaded from flash.
+
+#define RANGING_DATA_INDEX (1) //!< Index of ranging data within frames that contain ranging data.
+#define RANGING_DATA_LENGTH (1) //!< Length of ranging data.
+
+/**@brief Enforce legal slot number.
+ *
+ * @param[in] p_slot Pointer to the slot number variable to check.
+ */
+static void slot_boundary_check(uint8_t * p_slot)
+{
+ if (*p_slot > (APP_MAX_ADV_SLOTS - 1))
+ {
+ *p_slot = (APP_MAX_ADV_SLOTS - 1);
+ }
+}
+
+
+/**@brief Function loading slot data from flash.
+ *
+ * @param[in] slot_no Slot number to be used.
+ */
+static void load_slot_from_flash(uint8_t slot_no)
+{
+ ret_code_t err_code;
+
+ err_code = es_flash_access_slot_configs(slot_no, &m_reg.slots[slot_no], ES_FLASH_ACCESS_READ);
+ if (err_code != FDS_ERR_NOT_FOUND)
+ {
+ APP_ERROR_CHECK(err_code);
+
+ if (m_reg.slots[slot_no].adv_frame.type == ES_FRAME_TYPE_EID)
+ {
+ m_eid_loaded_from_flash = true;
+
+ es_security_eid_slots_restore(slot_no,
+ m_reg.slots[slot_no].k_scaler,
+ m_reg.slots[slot_no].seconds,
+ (const uint8_t *)m_reg.slots[slot_no].ik);
+ }
+
+ else
+ {
+ // If a non-EID slot has been loaded, update the state of m_reg immediately.
+ es_slot_reg_update_slot_list_info_on_add(&m_reg, slot_no, m_reg.slots[slot_no].adv_frame.type, true);
+ }
+ }
+}
+
+
+/**@brief Function for setting the ranging data field to be broadcast in the frame.
+ *
+ * @param[in] slot_no The slot index.
+ * @param[in] tx_power The radio tx power to be calibrated to ranging data.
+ */
+static void set_ranging_data_for_slot(uint8_t slot_no, nrf_ble_escs_radio_tx_pwr_t tx_power)
+{
+ int8_t ranging_data_array[ESCS_NUM_OF_SUPPORTED_TX_POWER] = APP_CONFIG_CALIBRATED_RANGING_DATA;
+ nrf_ble_escs_radio_tx_pwr_t supported_tx[ESCS_NUM_OF_SUPPORTED_TX_POWER] =
+ ESCS_SUPPORTED_TX_POWER;
+
+ int8_t ranging_data = 0;
+
+ if (m_reg.slots[slot_no].adv_custom_tx_power)
+ {
+ ranging_data = m_reg.slots[slot_no].custom_tx_power;
+ }
+
+ else
+ {
+ for (uint32_t i = 0; i < ESCS_NUM_OF_SUPPORTED_TX_POWER; ++i)
+ {
+ if (supported_tx[i] >= tx_power)
+ {
+ ranging_data = ranging_data_array[i];
+ break;
+ }
+ }
+ }
+ es_adv_frame_t * frame = &m_reg.slots[slot_no].adv_frame;
+ switch (frame->type)
+ {
+ case ES_FRAME_TYPE_UID:
+ {
+ es_uid_frame_t * uid = &frame->frame.uid;
+ uid->ranging_data = ranging_data;
+ break;
+ }
+
+ case ES_FRAME_TYPE_URL:
+ {
+ es_url_frame_t * url = &frame->frame.url;
+ url->ranging_data = ranging_data;
+ break;
+ }
+
+ case ES_FRAME_TYPE_EID:
+ {
+ es_eid_frame_t * eid = &frame->frame.eid;
+ eid->ranging_data = ranging_data;
+ break;
+ }
+
+ case ES_FRAME_TYPE_TLM:
+ APP_ERROR_CHECK(NRF_ERROR_INVALID_PARAM);
+ break;
+ }
+}
+
+
+/**@brief Function configuring a non-EID slot.
+ *
+ * @param[in] slot_no Slot number to be used.
+ * @param[in] length Length of write operation.
+ * @param[in] p_frame_data Pointer to written data.
+ */
+static void configure_slot(uint8_t slot_no, uint8_t length, uint8_t const * p_frame_data)
+{
+ // If a TLM slot is being configured and there already exists a TLM.
+ if ((es_frame_type_t)p_frame_data[0] == ES_FRAME_TYPE_TLM && m_reg.tlm_configured)
+ {
+ return; // Silently ignore any attempts to create more than one TLM slot as there is no point.
+ }
+
+ es_slot_reg_update_slot_list_info_on_add(&m_reg, slot_no, (es_frame_type_t)p_frame_data[0], false);
+
+ // For convenience, frame_type is stored in two places, set both.
+ m_reg.slots[slot_no].adv_frame.type = (es_frame_type_t)p_frame_data[0];
+ memcpy(&m_reg.slots[slot_no].adv_frame.frame, &m_reg.slots[slot_no].adv_frame.type, 1);
+
+ uint8_t * p_data_after_ranging_data = ((uint8_t *)(&m_reg.slots[slot_no].adv_frame.frame) +
+ RANGING_DATA_INDEX + RANGING_DATA_LENGTH);
+
+ switch (m_reg.slots[slot_no].adv_frame.type)
+ {
+ case ES_FRAME_TYPE_UID:
+ // Fall through.
+ case ES_FRAME_TYPE_URL:
+ memcpy(p_data_after_ranging_data, &p_frame_data[1], length - 1);
+ set_ranging_data_for_slot(slot_no, APP_CFG_DEFAULT_RADIO_TX_POWER);
+ m_reg.slots[slot_no].adv_frame.length = length + 1; // + 1 for ranging data
+ break;
+
+ case ES_FRAME_TYPE_TLM:
+ es_tlm_tlm_get(&m_reg.slots[slot_no].adv_frame.frame.tlm);
+ m_reg.slots[slot_no].adv_frame.length = ES_TLM_LENGTH;
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/**@brief Function configuring an EID slot.
+ *
+ * @param[in] slot_no Slot number to be used.
+ * @param[in] length Length of write operation.
+ * @param[in] p_frame_data Pointer to written data.
+ */
+static void configure_eid_slot(uint8_t slot_no, uint8_t length, uint8_t const * p_frame_data)
+{
+ bool clear_eid_slot = false;
+
+ // Do not update slot count, as this will be done when in the callback invoked when the EID data
+ // is ready.
+ // As it takes a while to do the calculation, temporarily remove the slot being overwritten.
+ // The slot will be re-added in the callback invoked when the EID data is ready.
+ clear_eid_slot = es_slot_reg_clear_slot(&m_reg, slot_no);
+
+ if (clear_eid_slot)
+ {
+ es_security_eid_slot_destroy(slot_no);
+ }
+
+ if (p_frame_data[0] != ES_FRAME_TYPE_EID)
+ {
+ APP_ERROR_CHECK(NRF_ERROR_INVALID_STATE);
+ }
+
+ if (length == ESCS_EID_WRITE_ECDH_LENGTH)
+ {
+ es_security_client_pub_ecdh_receive(slot_no,
+ (uint8_t*)&p_frame_data[ESCS_EID_WRITE_PUB_KEY_INDEX],
+ p_frame_data[ESCS_EID_WRITE_ECDH_LENGTH -1]);
+ }
+
+ else if (length == ESCS_EID_WRITE_IDK_LENGTH)
+ {
+ es_security_shared_ik_receive(slot_no,
+ (uint8_t*)&p_frame_data[ESCS_EID_WRITE_ENC_ID_KEY_INDEX],
+ p_frame_data[ESCS_EID_WRITE_IDK_LENGTH - 1]);
+ }
+
+ else
+ {
+ // Invalid length being written.
+ APP_ERROR_CHECK(NRF_ERROR_INVALID_PARAM);
+ }
+}
+
+
+ret_code_t es_slot_write_to_flash(uint8_t slot_no)
+{
+ if (m_reg.slots[slot_no].configured)
+ {
+ // If its an EID, we need to store some metadata in order to re-initialize the EID.
+ if (m_reg.slots[slot_no].adv_frame.type == ES_FRAME_TYPE_EID)
+ {
+ m_reg.slots[slot_no].seconds = es_security_clock_get(slot_no);
+ m_reg.slots[slot_no].k_scaler = es_security_scaler_get(slot_no);
+ es_security_plain_eid_id_key_get(slot_no, m_reg.slots[slot_no].ik);
+ }
+ return es_flash_access_slot_configs(slot_no, &m_reg.slots[slot_no], ES_FLASH_ACCESS_WRITE);
+ }
+
+ else
+ {
+ return es_flash_access_slot_configs(slot_no, NULL, ES_FLASH_ACCESS_CLEAR);
+ }
+}
+
+
+void es_slot_radio_tx_pwr_set(uint8_t slot_no, nrf_ble_escs_radio_tx_pwr_t radio_tx_pwr)
+{
+ slot_boundary_check(&slot_no);
+
+ m_reg.slots[slot_no].radio_tx_pwr = radio_tx_pwr;
+
+ if (!m_reg.slots[slot_no].adv_custom_tx_power) // Only update TX power in ADV if custom TX power is not set
+ {
+ set_ranging_data_for_slot(slot_no, radio_tx_pwr);
+ }
+}
+
+
+void es_slot_set_adv_custom_tx_power(uint8_t slot_no, nrf_ble_escs_adv_tx_pwr_t tx_pwr)
+{
+ slot_boundary_check(&slot_no);
+
+ m_reg.slots[slot_no].adv_custom_tx_power = true;
+ m_reg.slots[slot_no].custom_tx_power = tx_pwr;
+ set_ranging_data_for_slot(slot_no, tx_pwr);
+}
+
+
+void es_slot_on_write(uint8_t slot_no, uint8_t length, uint8_t const * p_frame_data)
+{
+ slot_boundary_check(&slot_no);
+
+ if (p_frame_data == NULL)
+ {
+ APP_ERROR_CHECK(NRF_ERROR_NULL);
+ }
+
+ // Cleared
+ if (length == 0 || (length == 1 && p_frame_data[0] == 0))
+ {
+ (void)es_slot_reg_clear_slot(&m_reg, slot_no);
+ }
+ // EID slot being configured
+ else if (p_frame_data[0] == ES_FRAME_TYPE_EID &&
+ (length == ESCS_EID_WRITE_ECDH_LENGTH || length == ESCS_EID_WRITE_IDK_LENGTH))
+ {
+ if (m_reg.slots[slot_no].configured)
+ (void)es_slot_reg_clear_slot(&m_reg, slot_no);
+ configure_eid_slot(slot_no, length, p_frame_data);
+ }
+ // Non-EID slot configured.
+ else
+ {
+ if (m_reg.slots[slot_no].configured)
+ (void)es_slot_reg_clear_slot(&m_reg, slot_no);
+ configure_slot(slot_no, length, p_frame_data);
+ }
+}
+
+
+void es_slot_encrypted_eid_id_key_set(uint8_t slot_no, nrf_ble_escs_eid_id_key_t * p_eid_id_key)
+{
+ slot_boundary_check(&slot_no);
+ if (p_eid_id_key != NULL)
+ {
+ memcpy(&(m_reg.slots[slot_no].encrypted_eid_id_key), p_eid_id_key,
+ sizeof(nrf_ble_escs_eid_id_key_t));
+ }
+}
+
+
+void es_slot_eid_ready(uint8_t slot_no)
+{
+ m_reg.slots[slot_no].adv_frame.type = ES_FRAME_TYPE_EID;
+ m_reg.slots[slot_no].adv_frame.length = ES_EID_LENGTH;
+ es_security_eid_get(slot_no, (uint8_t *)m_reg.slots[slot_no].adv_frame.frame.eid.eid);
+ m_reg.slots[slot_no].adv_frame.frame.eid.frame_type = ES_FRAME_TYPE_EID;
+ set_ranging_data_for_slot(slot_no, m_reg.slots[slot_no].radio_tx_pwr);
+
+ if (m_eid_loaded_from_flash)
+ {
+ es_slot_reg_update_slot_list_info_on_add(&m_reg, slot_no, ES_FRAME_TYPE_EID, true);
+ m_eid_loaded_from_flash = false;
+ }
+
+ else
+ {
+ es_slot_reg_update_slot_list_info_on_add(&m_reg, slot_no, ES_FRAME_TYPE_EID, false);
+ }
+}
+
+
+static bool slot_is_eid(uint8_t eid_slot_no)
+{
+ for (uint32_t i = 0; i < m_reg.num_configured_eid_slots; ++i)
+ {
+ if (m_reg.eid_slots_configured[i] == eid_slot_no)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+void es_slot_tlm_update(void)
+{
+ if (m_reg.tlm_configured)
+ {
+ es_tlm_tlm_get(&m_reg.slots[m_reg.tlm_slot].adv_frame.frame.tlm);
+ }
+}
+
+
+void es_slot_etlm_update(uint8_t eid_slot_no)
+{
+ es_tlm_frame_t tlm;
+ es_etlm_frame_t etlm;
+
+ // Ignore the request if eTLM is not required or slot no does not correspond to an EID slot.
+ if (!es_slot_reg_etlm_required(&m_reg) || !slot_is_eid(eid_slot_no))
+ {
+ return;
+ }
+
+ es_tlm_tlm_get(&tlm);
+
+ es_security_tlm_to_etlm(eid_slot_no, &tlm, &etlm);
+
+ memcpy(&m_reg.slots[m_reg.tlm_slot].adv_frame.frame.etlm, &etlm, sizeof(es_etlm_frame_t));
+ m_reg.slots[m_reg.tlm_slot].adv_frame.length = sizeof(es_etlm_frame_t);
+}
+
+
+const es_slot_reg_t * es_slot_get_registry(void)
+{
+ return (const es_slot_reg_t *)&m_reg;
+}
+
+
+void es_slots_init(const es_slot_t * p_default_slot)
+{
+ ret_code_t err_code;
+ es_flash_flags_t flash_flags = {{0}};
+
+ es_slot_reg_init(&m_reg);
+
+ m_eid_loaded_from_flash = false;
+
+ // Read the flash flags to see if there are any previously stored slot configs
+ err_code = es_flash_access_flags(&flash_flags, ES_FLASH_ACCESS_READ);
+
+ if (err_code == FDS_ERR_NOT_FOUND)
+ {
+ // Factory reset or initial boot, load default data
+ memcpy(&m_reg.slots[0], p_default_slot, sizeof(*p_default_slot));
+ es_slot_reg_update_slot_list_info_on_add(&m_reg, 0, p_default_slot->adv_frame.type, true);
+ }
+
+ else
+ {
+ APP_ERROR_CHECK(err_code);
+
+ for (uint32_t i = 0; i < APP_MAX_ADV_SLOTS; ++i)
+ {
+ if (!flash_flags.slot_is_empty[i])
+ {
+ load_slot_from_flash(i);
+ }
+ }
+ }
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_slot.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_slot.h
new file mode 100644
index 0000000..5b7482e
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_slot.h
@@ -0,0 +1,202 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef ES_SLOT_H__
+#define ES_SLOT_H__
+
+#include <stdint.h>
+#include "es_app_config.h"
+#include "nrf_ble_escs.h"
+
+/**
+ * @file
+ * @defgroup eddystone_slot Slots
+ * @brief Types and functions for handling Eddystone slots.
+ * @ingroup eddystone
+ * @{
+ */
+
+/**@brief Advertisable frame types that can be passed in to the advertising
+ * data during non-connectable slot advertising. */
+
+typedef struct
+{
+ union
+ {
+ es_uid_frame_t uid; //!< UID frame.
+ es_url_frame_t url; //!< URL frame.
+ es_tlm_frame_t tlm; //!< TLM frame.
+ es_eid_frame_t eid; //!< EID frame.
+ es_etlm_frame_t etlm; //!< eTLM frame.
+ } frame;
+ es_frame_type_t type; //!< Type defined twice for convenience (because the other one is inside a union).
+ uint8_t length;
+}es_adv_frame_t;
+
+/**@brief Slot. */
+typedef struct
+{
+ uint8_t slot_no; //!< Identifier for the slot, indexed at 0.
+ nrf_ble_escs_radio_tx_pwr_t radio_tx_pwr; //!< Radio TX power (in dB).
+ nrf_ble_escs_eid_id_key_t encrypted_eid_id_key; //!< EID key for the slot.
+ es_adv_frame_t adv_frame; //!< Frame structure to be passed in for advertising data.
+ bool adv_custom_tx_power; //!< Flag that specifies if the client has written to the 'Advertised TX Power' field of this slot.
+ nrf_ble_escs_radio_tx_pwr_t custom_tx_power; //!< Custom TX power to advertise (only if @ref adv_custom_tx_power is true).
+ bool configured; //!< Is this slot configured and active.
+ uint8_t k_scaler;
+ uint32_t seconds;
+ uint8_t ik[ESCS_AES_KEY_SIZE];
+} es_slot_t;
+
+/**@brief Slot registry. */
+typedef struct
+{
+ es_slot_t slots[APP_MAX_ADV_SLOTS];
+ uint8_t num_configured_slots;
+ uint8_t num_configured_eid_slots;
+ uint8_t slots_configured[APP_MAX_ADV_SLOTS];
+ uint8_t eid_slots_configured[APP_MAX_EID_SLOTS];
+ uint8_t tlm_slot;
+ bool tlm_configured;
+ uint8_t scaler_k;
+ uint8_t enc_key[ESCS_AES_KEY_SIZE];
+} es_slot_reg_t;
+
+/**@brief Function for initializing the Eddystone slots with default values.
+ *
+ * @details This function synchronizes all slots with the initial values.
+ *
+ * @param[in] p_default_slot Pointer to the default parameters for a slot.
+ */
+void es_slots_init(const es_slot_t * p_default_slot);
+
+/**@brief Function for setting the advertising interval of the specified slot.
+ *
+ * For compatibility with the Eddystone specifications, @p p_adv_interval must point to
+ * a 16-bit big endian value (coming from the characteristic write request),
+ * which is then converted to a little endian value inside the function before
+ * it is written into the variable in the slot.
+ *
+ * @parameternoteslot
+ * @parameternoteadv
+ *
+ * @param[in] slot_no The index of the slot.
+ * @param[in,out] p_adv_interval Pointer to the advertisement interval (in ms) to set.
+ * @param[in] global Flag that should be set if the beacon does not support variable advertising intervals.
+ */
+void es_slot_adv_interval_set(uint8_t slot_no,
+ nrf_ble_escs_adv_interval_t * p_adv_interval,
+ bool global);
+
+/**@brief Function for setting the TX power of the specified slot.
+ *
+ * @parameternoteslot
+ * @parameternotetxpower
+ *
+ * @param[in] slot_no The index of the slot.
+ * @param[in,out] radio_tx_pwr TX power value to set.
+ */
+void es_slot_radio_tx_pwr_set(uint8_t slot_no, nrf_ble_escs_radio_tx_pwr_t radio_tx_pwr);
+
+/**@brief Function for setting the R/W ADV of the specified slot.
+ *
+ * @parameternoteslot
+ *
+ * @param[in] slot_no The index of the slot.
+ * @param[in,out] length The length of the data written or read.
+ * @param[in,out] p_frame_data Pointer to the data.
+ *
+ */
+void es_slot_on_write(uint8_t slot_no, uint8_t length, uint8_t const * p_frame_data);
+
+/**@brief Function for writing the slot's configuration to flash.
+ *
+ * @param[in] slot_no The index of the slot.
+ */
+ret_code_t es_slot_write_to_flash(uint8_t slot_no);
+
+/**@brief Function for setting the slot's encrypted EID Identity Key to be displayed in the EID Identity Key characteristic.
+ *
+ * @parameternoteslot
+ *
+ * @param[in] slot_no The index of the slot.
+ * @param[in,out] p_eid_id_key Pointer to a @ref nrf_ble_escs_eid_id_key_t structure from where the key will be written.
+ */
+void es_slot_encrypted_eid_id_key_set(uint8_t slot_no, nrf_ble_escs_eid_id_key_t * p_eid_id_key);
+
+/**@brief Function for marking an EID slot as ready for populating.
+ *
+ * @details Call this function when an EID has been generated and the advertisement frame can be populated with the EID.
+ *
+ * @param[in] slot_no The index of the slot.
+ */
+void es_slot_eid_ready(uint8_t slot_no);
+
+/**@brief Function for updating the TLM slot with updated data. */
+void es_slot_tlm_update(void);
+
+/**@brief Function for updating the TLM slot with eTLM data.
+ *
+ * @details This function uses the EID identity key from the given EID slot number to update the TLM slot.
+ *
+ * @param[in] eid_slot_no EID slot to get EID identity key from.
+ */
+void es_slot_etlm_update(uint8_t eid_slot_no);
+
+/**@brief Function for getting a pointer to the slot registry.
+ *
+ * @return A pointer to the slot registry.
+ */
+const es_slot_reg_t * es_slot_get_registry(void);
+
+/**@brief Function for setting a custom advertisement TX power for a given slot.
+ *
+ * @parameternoteslot
+ * @parameternotetxpower
+ *
+ * @param[in] slot_no The index of the slot.
+ * @param[in] tx_pwr Advertised TX power to be set.
+ */
+void es_slot_set_adv_custom_tx_power(uint8_t slot_no, nrf_ble_escs_adv_tx_pwr_t tx_pwr);
+
+/**
+ * @}
+ */
+
+#endif // ES_SLOT_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_slot_reg.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_slot_reg.c
new file mode 100644
index 0000000..f789e6b
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_slot_reg.c
@@ -0,0 +1,181 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "es_slot_reg.h"
+
+#define ES_SLOT_NOT_CONFIGURED 0xab /** Value set in configured lists to indicate not configured slot. */
+
+/**@brief Function updating 'tlm_configured' property of slot registry when slot is being cleared.
+ *
+ * @param[in] p_reg Pointer to slot registry.
+ * @param[in] slot_no Slot number to be used.
+ */
+static void update_tlm_configured_on_clearing(es_slot_reg_t * p_reg, uint8_t slot_no)
+{
+ if (p_reg->tlm_configured && slot_no == p_reg->tlm_slot)
+ {
+ p_reg->tlm_configured = false;
+ }
+}
+
+
+/**@brief Function updating 'num_configured_slots' and 'slots_configured' properties of slot registry when slot is being cleared.
+ *
+ * @param[in] p_configured Pointer to list of configured slots.
+ * @param[in] p_num_configured_slots Pointer to number of configured slots.
+ * @param[in] slot_no Slot number to clear.
+ */
+static void configured_slots_on_clear_update(uint8_t * p_configured, uint8_t * p_num_configured_slots, uint8_t slot_no)
+{
+ uint8_t index_of_last_configured_slot = *p_num_configured_slots - 1;
+
+ for (uint32_t i = 0; i < APP_MAX_ADV_SLOTS; ++i)
+ {
+ if (p_configured[i] == slot_no)
+ {
+ // Copy all values 'to the right' of the cleared slot one step to the left.
+ if (i < index_of_last_configured_slot)
+ {
+ for (uint32_t j = i; j < index_of_last_configured_slot; ++j)
+ {
+ p_configured[j] = p_configured[j + 1];
+ }
+ // Write ES_SLOT_NOT_CONFIGURED to all rightmost not configured indexes.
+ memset(&p_configured[index_of_last_configured_slot],
+ ES_SLOT_NOT_CONFIGURED,
+ APP_MAX_ADV_SLOTS - index_of_last_configured_slot);
+ }
+
+ else
+ {
+ // There are no values 'to the right', simply overwrite with ES_SLOT_NOT_CONFIGURED
+ p_configured[i] = ES_SLOT_NOT_CONFIGURED;
+ }
+
+ *p_num_configured_slots -= 1;
+
+ return;
+ }
+ }
+}
+
+
+bool es_slot_reg_etlm_required(const es_slot_reg_t * p_reg)
+{
+ return (p_reg->num_configured_eid_slots > 0 && p_reg->tlm_configured);
+}
+
+
+bool es_slot_reg_clear_slot(es_slot_reg_t * p_reg, uint8_t slot_no)
+{
+ bool eid_has_been_cleared = false;
+
+ if (p_reg->slots[slot_no].configured)
+ {
+ update_tlm_configured_on_clearing(p_reg, slot_no);
+
+ configured_slots_on_clear_update(p_reg->slots_configured,
+ &p_reg->num_configured_slots,
+ slot_no);
+
+ if (p_reg->slots[slot_no].adv_frame.type == ES_FRAME_TYPE_EID)
+ {
+ configured_slots_on_clear_update(p_reg->eid_slots_configured,
+ &p_reg->num_configured_eid_slots,
+ slot_no);
+
+ eid_has_been_cleared = true;
+ }
+
+ p_reg->slots[slot_no].configured = false;
+ }
+
+ memset(&p_reg->slots[slot_no], 0, sizeof(p_reg->slots[slot_no]));
+
+ return eid_has_been_cleared;
+}
+
+
+void es_slot_reg_update_slot_list_info_on_add(es_slot_reg_t * p_reg,
+ uint8_t slot_no,
+ es_frame_type_t frame_type,
+ bool init)
+{
+ if (frame_type == ES_FRAME_TYPE_TLM)
+ {
+ p_reg->tlm_configured = true;
+ p_reg->tlm_slot = slot_no;
+ }
+
+ if (!p_reg->slots[slot_no].configured || init)
+ {
+ p_reg->slots[slot_no].configured = true;
+
+ // Note, we use 'num_configured_slots' before incrementing it, so it is pointing to the correct index.
+ p_reg->slots_configured[p_reg->num_configured_slots] = slot_no;
+
+ p_reg->num_configured_slots++;
+
+ if (frame_type == ES_FRAME_TYPE_EID)
+ {
+ p_reg->eid_slots_configured[p_reg->num_configured_eid_slots] = slot_no;
+
+ p_reg->num_configured_eid_slots++;
+ }
+ }
+
+ // If an already configured slot has changed from anything TO an EID slot.
+ else if (frame_type == ES_FRAME_TYPE_EID &&
+ p_reg->slots[slot_no].adv_frame.type != ES_FRAME_TYPE_EID)
+ {
+ p_reg->eid_slots_configured[p_reg->num_configured_eid_slots] = slot_no;
+
+ p_reg->num_configured_eid_slots++;
+ }
+}
+
+
+void es_slot_reg_init(es_slot_reg_t * p_reg)
+{
+ p_reg->tlm_configured = false;
+ memset(p_reg->slots_configured, ES_SLOT_NOT_CONFIGURED, APP_MAX_ADV_SLOTS);
+ memset(p_reg->eid_slots_configured, ES_SLOT_NOT_CONFIGURED, APP_MAX_EID_SLOTS);
+ p_reg->num_configured_eid_slots = 0;
+ p_reg->num_configured_slots = 0;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_slot_reg.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_slot_reg.h
new file mode 100644
index 0000000..5f34d55
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_slot_reg.h
@@ -0,0 +1,90 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef ES_SLOT_REG_H__
+#define ES_SLOT_REG_H__
+
+#include <stdint.h>
+#include "es_slot.h"
+
+/**
+ * @file
+ * @addtogroup eddystone_slot
+ * @{
+ */
+
+/** @brief Function for checking if an eTLM frame is required.
+ *
+ * @param[in] p_reg Pointer to the slot registry.
+ *
+ * @retval true If an eTLM frame is required.
+ * @retval false Otherwise.
+ */
+bool es_slot_reg_etlm_required(const es_slot_reg_t * p_reg);
+
+/** @brief Function for clearing a slot.
+ *
+ * @param[in] p_reg Pointer to the slot registry.
+ * @param[in] slot_no The slot number to clear.
+ *
+ * @retval true If an EID slot was cleared.
+ */
+bool es_slot_reg_clear_slot(es_slot_reg_t * p_reg, uint8_t slot_no);
+
+/** @brief Function for updating the state of the slot registry after adding a slot.
+ *
+ * @param[in] p_reg Pointer to the slot registry.
+ * @param[in] slot_no The slot number that was added.
+ * @param[in] frame_type The frame type that was added.
+ * @param[in] init Information if the data is loaded during initialization. Set this
+ * parameter to false if the call is a result of a write to the Eddystone Configuration Service.
+ */
+void es_slot_reg_update_slot_list_info_on_add(es_slot_reg_t * p_reg, uint8_t slot_no, es_frame_type_t frame_type, bool init);
+
+/** @brief Function for initializing the slot registry.
+ *
+ * @param[in] p_reg Pointer to the slot registry to initialize.
+ */
+void es_slot_reg_init(es_slot_reg_t * p_reg);
+
+/**
+ * @}
+ */
+
+#endif // ES_SLOT_REG_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_stopwatch.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_stopwatch.c
new file mode 100644
index 0000000..0f022bf
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_stopwatch.c
@@ -0,0 +1,106 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include "es_stopwatch.h"
+#include "sdk_macros.h"
+#include "app_timer.h"
+#include "es_app_config.h"
+
+static uint32_t m_ticks_last_returned[ES_STOPWATCH_MAX_USERS];
+static uint32_t m_ids_ticks_wrap[ES_STOPWATCH_MAX_USERS];
+static uint8_t m_nof_ids = 0;
+static bool m_initialized = false;
+
+uint32_t es_stopwatch_check(es_stopwatch_id_t id)
+{
+ uint32_t ticks_current = app_timer_cnt_get();
+ uint32_t ticks_diff;
+
+ if (m_ids_ticks_wrap[id] == 0)
+ {
+ APP_ERROR_CHECK(NRF_ERROR_INVALID_STATE);
+ }
+
+ ticks_diff = app_timer_cnt_diff_compute(ticks_current, m_ticks_last_returned[id]);
+
+ if (ticks_diff >= m_ids_ticks_wrap[id])
+ {
+ m_ticks_last_returned[id] = (ticks_current / m_ids_ticks_wrap[id]) * m_ids_ticks_wrap[id];
+
+ return ticks_diff / m_ids_ticks_wrap[id];
+ }
+
+ return 0;
+}
+
+ret_code_t es_stopwatch_create(es_stopwatch_id_t * p_sw_id, uint32_t ticks_wrap)
+{
+ VERIFY_PARAM_NOT_NULL(p_sw_id);
+
+ if (m_nof_ids == ES_STOPWATCH_MAX_USERS)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ if (!m_initialized)
+ {
+ return NRF_ERROR_MODULE_NOT_INITIALIZED;
+ }
+
+ *p_sw_id = m_nof_ids;
+
+ m_ids_ticks_wrap[m_nof_ids] = ticks_wrap;
+
+ m_nof_ids++;
+
+ return NRF_SUCCESS;
+}
+
+
+void es_stopwatch_init(void)
+{
+ m_nof_ids = 0;
+ memset(m_ticks_last_returned, 0, sizeof(m_ticks_last_returned));
+ memset(m_ids_ticks_wrap, 0, sizeof(m_ids_ticks_wrap));
+ m_initialized = true;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_stopwatch.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_stopwatch.h
new file mode 100644
index 0000000..1318861
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_stopwatch.h
@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef ES_SECURITY_TIMING_H__
+#define ES_SECURITY_TIMING_H__
+
+#include <stdint.h>
+#include "app_error.h"
+
+/**
+ * @file
+ * @addtogroup eddystone_security
+ * @{
+ */
+
+typedef uint8_t es_stopwatch_id_t;
+
+/**@brief Function for getting the number of seconds passed since the last invocation.
+ * @details If the function returns zero, the 'last time called' state is not updated. If a non-zero value
+ * is returned, the 'last time called' state will point to the last whole second.
+ * @return Number of seconds passed since the last invocation.
+ */
+uint32_t es_stopwatch_check(es_stopwatch_id_t id);
+
+ret_code_t es_stopwatch_create(es_stopwatch_id_t * p_sw_id, uint32_t ticks_wrap);
+
+/**@brief Function for initializing the security timing module.
+ */
+void es_stopwatch_init(void);
+
+/**
+ * @}
+ */
+
+#endif // ES_SECURITY_TIMING_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_tlm.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_tlm.c
new file mode 100644
index 0000000..dec4b6e
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_tlm.c
@@ -0,0 +1,140 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <string.h>
+#include "app_timer.h"
+#include "es_tlm.h"
+#include "es_app_config.h"
+#include "es_battery_voltage.h"
+#include "es_stopwatch.h"
+#include "nrf_soc.h"
+
+#define TICKS_100_MS APP_TIMER_TICKS(100) //!< Tick count for 100ms.
+
+static es_tlm_frame_t m_tlm;
+static uint32_t m_le_adv_cnt;
+static es_stopwatch_id_t m_time_sec_sw_id;
+static es_stopwatch_id_t m_tlm_refresh_sw_id;
+
+/**@brief Function for updating the ADV_SEC field of TLM*/
+static void update_time(void)
+{
+ static uint32_t time_total_100_ms = 0;
+ uint32_t be_time_100_ms; // Big endian version of 0.1 second counter.
+
+ time_total_100_ms += es_stopwatch_check(m_time_sec_sw_id);
+
+ be_time_100_ms = BYTES_REVERSE_32BIT(time_total_100_ms);
+
+ memcpy(m_tlm.sec_cnt, &be_time_100_ms, ES_TLM_SEC_CNT_LENGTH);
+}
+
+
+/**@brief Function for updating the TEMP field of TLM*/
+static void update_temp(void)
+{
+ int32_t temp; // variable to hold temp reading
+ (void)sd_temp_get(&temp); // get new temperature
+ int16_t temp_new = (int16_t) temp; // convert from int32_t to int16_t
+ m_tlm.temp[0] = (uint8_t)((temp_new >> 2) & 0xFFUL); // Right-shift by two to remove decimal part
+ m_tlm.temp[1] = (uint8_t)((temp_new << 6) & 0xFFUL); // Left-shift 6 to get fractional part with 0.25 degrees C resolution
+}
+
+
+/**@brief Function for updating the VBATT field of TLM*/
+static void update_vbatt(void)
+{
+ uint16_t vbatt; // Variable to hold voltage reading
+ es_battery_voltage_get(&vbatt); // Get new battery voltage
+ m_tlm.vbatt[0] = (uint8_t)(vbatt >> 8);
+ m_tlm.vbatt[1] = (uint8_t)vbatt;
+}
+
+
+static void update_adv_cnt(void)
+{
+ uint32_t be_adv_cnt = BYTES_REVERSE_32BIT(m_le_adv_cnt);
+ memcpy(m_tlm.adv_cnt, (uint8_t *)(&be_adv_cnt), ES_TLM_ADV_CNT_LENGTH);
+}
+
+
+void es_tlm_tlm_get(es_tlm_frame_t * p_tlm_frame)
+{
+ // Note that frame type and TLM version fields are set in initialization.
+ update_time();
+ update_adv_cnt();
+
+ if (es_stopwatch_check(m_tlm_refresh_sw_id) > 0)
+ {
+ update_temp();
+ update_vbatt();
+ }
+
+ memcpy(p_tlm_frame, &m_tlm, sizeof(es_tlm_frame_t));
+}
+
+
+void es_tlm_adv_cnt_inc(void)
+{
+ m_le_adv_cnt++;
+}
+
+
+void es_tlm_init(void)
+{
+ ret_code_t err_code;
+
+ memset(&m_tlm, 0, sizeof(m_tlm));
+ m_tlm.frame_type = ES_FRAME_TYPE_TLM;
+ m_tlm.version = ES_TLM_VERSION_TLM;
+ m_le_adv_cnt = 0;
+
+ update_time();
+ update_vbatt();
+ update_temp();
+
+ err_code = es_stopwatch_create(&m_time_sec_sw_id, APP_TIMER_TICKS(100));
+ APP_ERROR_CHECK(err_code);
+
+ err_code = es_stopwatch_create(
+ &m_tlm_refresh_sw_id,
+ APP_TIMER_TICKS(APP_CONFIG_TLM_TEMP_VBATT_UPDATE_INTERVAL_SECONDS * 1000));
+ APP_ERROR_CHECK(err_code);
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_tlm.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_tlm.h
new file mode 100644
index 0000000..055d22b
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_tlm.h
@@ -0,0 +1,76 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef ES_TLM_H__
+#define ES_TLM_H__
+
+#include "es.h"
+
+/**
+ * @file
+ * @defgroup eddystone_tlm TLM
+ * @brief Functions for the Eddystone telemetry (TLM) manager.
+ * @ingroup eddystone_adv
+ * @{
+ */
+
+/**@brief Function for initializing the TLM manager.
+ *
+ * @return See @ref app_timer_start for possible return values.
+ */
+void es_tlm_init(void);
+
+/**@brief Function for getting the current TLM.
+ *
+ * @param[in] p_tlm_frame Pointer to the TLM frame to which the frame is retrieved.
+ */
+void es_tlm_tlm_get(es_tlm_frame_t * p_tlm_frame);
+
+/**@brief Function for incrementing the ADV_CNT field of the TLM frame.
+ *
+ * @details This function should be called every time a frame is advertised.
+ *
+ */
+void es_tlm_adv_cnt_inc(void);
+
+/**
+ * @}
+ */
+
+#endif // ES_TLM_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_util.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_util.h
new file mode 100644
index 0000000..36e33d9
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/es_util.h
@@ -0,0 +1,137 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+// See https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms
+
+#ifndef ES_UTIL_H__
+#define ES_UTIL_H__
+
+#define BOOL(x) COMPL(NOT(x))
+#define IF(c) IIF(BOOL(c))
+
+#define CHECK_N(x, n, ...) n
+#define CHECK(...) CHECK_N(__VA_ARGS__, 0,)
+#define PROBE(x) x, 1,
+
+#define EAT(...)
+#define EXPAND(...) __VA_ARGS__
+#define WHEN(c) IF(c)(EXPAND, EAT)
+
+#define NOT(x) CHECK(PRIMITIVE_CAT(NOT_, x))
+#define NOT_0 PROBE(~)
+
+#define COMPL(b) PRIMITIVE_CAT(COMPL_, b)
+#define COMPL_0 1
+#define COMPL_1 0
+
+#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
+#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
+
+#define IIF(c) PRIMITIVE_CAT(IIF_, c)
+#define IIF_0(t, ...) __VA_ARGS__
+#define IIF_1(t, ...) t
+
+#define DEC(x) PRIMITIVE_CAT(DEC_, x)
+#define DEC_0 0
+#define DEC_1 0
+#define DEC_2 1
+#define DEC_3 2
+#define DEC_4 3
+#define DEC_5 4
+#define DEC_6 5
+#define DEC_7 6
+#define DEC_8 7
+#define DEC_9 8
+#define DEC_10 9
+#define DEC_11 10
+#define DEC_12 11
+#define DEC_13 12
+#define DEC_14 13
+#define DEC_15 14
+#define DEC_16 15
+#define DEC_17 16
+#define DEC_18 17
+#define DEC_19 18
+#define DEC_20 19
+#define DEC_21 20
+#define DEC_22 21
+#define DEC_23 22
+#define DEC_24 23
+#define DEC_25 24
+#define DEC_26 25
+#define DEC_27 26
+#define DEC_28 27
+#define DEC_29 28
+#define DEC_30 29
+#define DEC_31 30
+#define DEC_32 31
+
+#define EMPTY()
+#define DEFER(id) id EMPTY()
+#define OBSTRUCT(...) __VA_ARGS__ DEFER(EMPTY)()
+#define EXPAND(...) __VA_ARGS__
+
+#define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
+#define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
+#define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
+#define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
+#define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__)))
+#define EVAL5(...) __VA_ARGS__
+
+#define REPEAT(count, macro, ...) \
+ WHEN(count) \
+ ( \
+ OBSTRUCT(REPEAT_INDIRECT) () \
+ ( \
+ DEC(count), macro, __VA_ARGS__ \
+ ) \
+ OBSTRUCT(macro) \
+ ( \
+ DEC(count), __VA_ARGS__ \
+ ) \
+ )
+#define REPEAT_INDIRECT() REPEAT
+
+
+/**
+ * @}
+ */
+
+#endif // ES_UTIL_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/nrf_ble_es.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/nrf_ble_es.c
new file mode 100644
index 0000000..67fdb3f
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/nrf_ble_es.c
@@ -0,0 +1,438 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <string.h>
+#include "nrf_ble_es.h"
+#include "app_error.h"
+#include "fds.h"
+#include "es_adv.h"
+#include "es_battery_voltage.h"
+#include "es_flash.h"
+#include "es_gatts.h"
+#include "es_security.h"
+#include "es_slot.h"
+#include "es_stopwatch.h"
+#include "escs_defs.h"
+#include "nrf_sdh_ble.h"
+
+static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID; //!< Connection handle.
+static nrf_ble_escs_t m_ble_ecs; //!< Struct identifying the Eddystone Config Service.
+static nrf_ble_es_evt_handler_t m_evt_handler; //!< Event handler.
+
+uint8_t m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; //!< Advertising handle used to identify an advertising set.
+
+/**@brief Function for invoking registered callback.
+ *
+ * @param[in] evt Event to issue to callback.
+ */
+static void handle_evt(nrf_ble_es_evt_t evt)
+{
+ if (m_evt_handler != NULL)
+ {
+ m_evt_handler(evt);
+ }
+}
+
+
+/**@brief Function resetting MAC address. Will resume advertisement. */
+static void new_address_set(void)
+{
+
+ ret_code_t err_code;
+ uint8_t bytes_available;
+ ble_gap_addr_t new_address;
+
+ new_address.addr_type = BLE_GAP_ADDR_TYPE_PUBLIC;
+
+ // Randomize the MAC address on every EID generation
+ (void)sd_rand_application_bytes_available_get(&bytes_available);
+
+ while (bytes_available < BLE_GAP_ADDR_LEN)
+ {
+ // wait for SD to acquire enough RNs
+ (void)sd_rand_application_bytes_available_get(&bytes_available);
+ }
+
+ (void)sd_rand_application_vector_get(new_address.addr, BLE_GAP_ADDR_LEN);
+
+ // Stop advertising to ensure that it is possible to change the address.
+ (void)sd_ble_gap_adv_stop(m_adv_handle);
+
+ do
+ {
+ err_code = sd_ble_gap_addr_set(&new_address);
+ } while (err_code == NRF_ERROR_INVALID_STATE);
+
+ APP_ERROR_CHECK(err_code);
+
+ if (es_adv_remain_connectable_get())
+ {
+ es_adv_start_connectable_adv();
+ }
+ else
+ {
+ es_adv_start_non_connctable_adv();
+ }
+}
+
+
+/**@brief Function updating MAC address if required.
+ *
+ * @param[in] demand_new_mac If 'true', mac address will be updated on next invocation when not connected.
+ * If 'false', simply check if we have an outstanding demand for new MAC and update if not connected.
+ */
+static void check_and_update_mac_address(bool demand_new_mac)
+{
+ static bool reset_mac_address = false;
+
+ if (demand_new_mac)
+ {
+ reset_mac_address = true;
+ }
+
+ // Not possible to update MAC address while in a connection
+ if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ return;
+ }
+
+ else if (reset_mac_address)
+ {
+ reset_mac_address = false;
+
+ new_address_set();
+ }
+}
+
+
+/**@brief Function to lock the beacon (change lock state characteristic to LOCKED)
+ */
+static void lock_beacon(void)
+{
+ *(m_ble_ecs.p_lock_state) = NRF_BLE_ESCS_LOCK_STATE_LOCKED;
+}
+
+
+/**@brief Function for handling BLE event from the SoftDevice.
+ *
+ * @param[in] p_ble_evt Pointer to BLE event.
+ */
+static void on_ble_evt(ble_evt_t const * p_ble_evt)
+{
+ ret_code_t err_code;
+ es_flash_flags_t flash_flag = {{0}};
+ const es_slot_reg_t * p_reg = es_slot_get_registry();
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ m_conn_handle = p_ble_evt->evt.common_evt.conn_handle;
+ *(m_ble_ecs.p_active_slot) = 0;
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ m_conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ for (uint32_t i = 0; i < APP_MAX_ADV_SLOTS; ++i)
+ {
+ err_code = es_slot_write_to_flash(i);
+ APP_ERROR_CHECK(err_code);
+
+ flash_flag.slot_is_empty[i] = !p_reg->slots[i].configured;
+ }
+
+ err_code = es_flash_access_flags(&flash_flag, ES_FLASH_ACCESS_WRITE);
+ APP_ERROR_CHECK(err_code);
+
+ es_flash_beacon_config_t beacon_config;
+ beacon_config.adv_interval = es_adv_interval_get();
+ beacon_config.remain_connectable = es_adv_remain_connectable_get();
+
+ err_code = es_flash_access_beacon_config(&beacon_config, ES_FLASH_ACCESS_WRITE);
+ APP_ERROR_CHECK(err_code);
+
+ if (*m_ble_ecs.p_lock_state == NRF_BLE_ESCS_LOCK_STATE_UNLOCKED)
+ {
+ lock_beacon();
+ }
+
+ check_and_update_mac_address(false);
+
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+
+/**@brief Callback function to receive messages from the security module
+ *
+ * @details Need to be passed in during es_security_init(). The security
+ * module will callback anytime a particular security process is completed
+ *
+ * @params[in] slot_no Index of the slot
+ * @params[in] msg_type Message type corersponding to different security components
+ */
+static void nrf_ble_escs_security_cb(uint8_t slot_no, es_security_msg_t msg_type)
+{
+ nrf_ble_escs_eid_id_key_t encrypted_id_key;
+ nrf_ble_escs_public_ecdh_key_t pub_ecdh_key;
+
+ ret_code_t err_code;
+ static ble_gatts_value_t value;
+
+ switch (msg_type)
+ {
+ case ES_SECURITY_MSG_UNLOCKED:
+ *(m_ble_ecs.p_lock_state) = NRF_BLE_ESCS_LOCK_STATE_UNLOCKED;
+ break;
+
+ case ES_SECURITY_MSG_EID:
+ es_slot_eid_ready(slot_no);
+#ifdef MAC_RANDOMIZED
+ check_and_update_mac_address(true);
+#endif // MAC_RANDOMIZED
+ break;
+
+ case ES_SECURITY_MSG_IK:
+ es_security_encrypted_eid_id_key_get(slot_no, (uint8_t *)encrypted_id_key.key);
+ // Set the EID ID key in the slot so it can be exposed in the characteristic
+ es_slot_encrypted_eid_id_key_set(slot_no, &encrypted_id_key);
+ break;
+
+ case ES_SECURITY_MSG_ECDH:
+ es_security_pub_ecdh_get(slot_no, (uint8_t *)pub_ecdh_key.key);
+
+ // Set the characteristic to the ECDH key value
+ value.len = sizeof(nrf_ble_escs_public_ecdh_key_t);
+ value.offset = 0;
+ value.p_value = (uint8_t *)pub_ecdh_key.key;
+
+ if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ err_code = sd_ble_gatts_value_set(m_ble_ecs.conn_handle,
+ m_ble_ecs.pub_ecdh_key_handles.value_handle,
+ &value);
+ if (err_code != NRF_SUCCESS)
+ {
+ APP_ERROR_CHECK(err_code);
+ }
+ }
+ break;
+
+ case ES_SECURITY_MSG_STORE_TIME:
+ // Every 24 hours any EID slots time is stored to flash to allow for power lock_state_handles
+ // recovery. Only time needs to be stored, but just store the entire slot anyway for API simplicity.
+ err_code = es_slot_write_to_flash(slot_no);
+ APP_ERROR_CHECK(err_code);
+
+ break;
+
+ default:
+ APP_ERROR_CHECK(NRF_ERROR_INVALID_PARAM); // Should never happen
+ break;
+ }
+}
+
+
+/**@brief Function for handling advertisement events from 'es_adv'.
+ *
+ * @param[in] evt Advertisement event to handle.
+ */
+static void adv_evt_handler(es_adv_evt_t evt)
+{
+ switch (evt)
+ {
+ case ES_ADV_EVT_NON_CONN_ADV:
+ handle_evt(NRF_BLE_ES_EVT_ADVERTISEMENT_SENT);
+ es_security_update_time();
+ break;
+
+ case ES_ADV_EVT_CONNECTABLE_ADV_STARTED:
+ handle_evt(NRF_BLE_ES_EVT_CONNECTABLE_ADV_STARTED);
+ break;
+
+ case ES_ADV_EVT_CONNECTABLE_ADV_STOPPED:
+ handle_evt(NRF_BLE_ES_EVT_CONNECTABLE_ADV_STOPPED);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/**@brief Initialize the ECS with initial values for the characteristics and other necessary modules */
+static void ble_escs_init(void)
+{
+ ret_code_t err_code;
+ nrf_ble_escs_init_t ecs_init;
+ nrf_ble_escs_init_params_t init_params;
+ int8_t tx_powers[ESCS_NUM_OF_SUPPORTED_TX_POWER] = ESCS_SUPPORTED_TX_POWER;
+
+ /*Init the broadcast capabilities characteristic*/
+ memset(&init_params.broadcast_cap, 0, sizeof(init_params.broadcast_cap));
+ init_params.broadcast_cap.vers_byte = ES_SPEC_VERSION_BYTE;
+ init_params.broadcast_cap.max_supp_total_slots = APP_MAX_ADV_SLOTS;
+ init_params.broadcast_cap.max_supp_eid_slots = APP_MAX_EID_SLOTS;
+ init_params.broadcast_cap.cap_bitfield = ( (APP_IS_VARIABLE_ADV_SUPPORTED << ESCS_BROADCAST_VAR_ADV_SUPPORTED_Pos)
+ | (APP_IS_VARIABLE_TX_POWER_SUPPORTED << ESCS_BROADCAST_VAR_TX_POWER_SUPPORTED_Pos))
+ & (ESCS_BROADCAST_VAR_RFU_MASK);
+ init_params.broadcast_cap.supp_frame_types = ( (APP_IS_URL_SUPPORTED << ESCS_FRAME_TYPE_URL_SUPPORTED_Pos)
+ | (APP_IS_UID_SUPPORTED << ESCS_FRAME_TYPE_UID_SUPPORTED_Pos)
+ | (APP_IS_TLM_SUPPORTED << ESCS_FRAME_TYPE_TLM_SUPPORTED_Pos)
+ | (APP_IS_EID_SUPPORTED << ESCS_FRAME_TYPE_EID_SUPPORTED_Pos))
+ & (ESCS_FRAME_TYPE_RFU_MASK);
+ memcpy(init_params.broadcast_cap.supp_radio_tx_power, tx_powers, ESCS_NUM_OF_SUPPORTED_TX_POWER);
+
+ init_params.adv_interval = APP_CFG_NON_CONN_ADV_INTERVAL_MS;
+ init_params.adv_tx_pwr = APP_CFG_DEFAULT_RADIO_TX_POWER;
+ init_params.radio_tx_pwr = 0x00;
+ init_params.factory_reset = 0;
+ init_params.remain_connectable.r_is_non_connectable_supported = APP_IS_REMAIN_CONNECTABLE_SUPPORTED;
+
+ // Initialize evt handlers and the service
+ memset(&ecs_init, 0, sizeof(ecs_init));
+ ecs_init.write_evt_handler = es_gatts_handle_write;
+ ecs_init.read_evt_handler = es_gatts_handle_read;
+ ecs_init.p_init_vals = &(init_params);
+
+ err_code = nrf_ble_escs_init(&m_ble_ecs, &ecs_init);
+ APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for initializing 'es_adv' module. */
+static void adv_init(void)
+{
+ ret_code_t err_code;
+ es_flash_beacon_config_t beacon_config;
+
+ err_code = es_flash_access_beacon_config(&beacon_config, ES_FLASH_ACCESS_READ);
+
+ if (err_code == FDS_ERR_NOT_FOUND)
+ {
+ beacon_config.adv_interval = APP_CFG_NON_CONN_ADV_INTERVAL_MS;
+ beacon_config.remain_connectable = false;
+ }
+
+ else
+ {
+ APP_ERROR_CHECK(err_code);
+ }
+
+ es_adv_init(m_ble_ecs.uuid_type,
+ adv_evt_handler,
+ beacon_config.adv_interval,
+ beacon_config.remain_connectable,
+ &m_adv_handle);
+}
+
+
+/**@brief Function for initializing es_slots module. */
+static void adv_slots_init(void)
+{
+ uint8_t default_frame_data[DEFAULT_FRAME_LENGTH] = DEFAULT_FRAME_DATA;
+
+ es_slot_t default_adv_slot = {.slot_no = 0,
+ .radio_tx_pwr = 0,
+ .adv_frame.type = DEFAULT_FRAME_TYPE,
+ .adv_frame.length = DEFAULT_FRAME_LENGTH,
+ .adv_custom_tx_power = false,
+ .configured = true};
+
+ memcpy(&default_adv_slot.adv_frame.frame, default_frame_data, DEFAULT_FRAME_LENGTH);
+
+ es_slots_init(&default_adv_slot);
+}
+
+
+void nrf_ble_es_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ ret_code_t err_code;
+
+ es_adv_on_ble_evt(p_ble_evt);
+ err_code = nrf_ble_escs_on_ble_evt(&m_ble_ecs, p_ble_evt);
+ APP_ERROR_CHECK(err_code);
+ on_ble_evt(p_ble_evt);
+ es_flash_on_ble_evt(p_ble_evt);
+}
+
+NRF_SDH_BLE_OBSERVER(m_es_observer, NRF_BLE_ES_BLE_OBSERVER_PRIO, nrf_ble_es_on_ble_evt, NULL);
+
+
+void nrf_ble_es_on_start_connectable_advertising(void)
+{
+ es_adv_start_connectable_adv();
+}
+
+
+void nrf_ble_es_init(nrf_ble_es_evt_handler_t evt_handler)
+{
+ ret_code_t err_code;
+
+ m_evt_handler = evt_handler;
+ m_conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ es_stopwatch_init();
+
+ err_code = es_gatts_init(&m_ble_ecs);
+ APP_ERROR_CHECK(err_code);
+
+ err_code = es_flash_init();
+ APP_ERROR_CHECK(err_code);
+
+ while (es_flash_num_pending_ops() > 0)
+ {
+ ; // Busy wait while initialization of FDS module completes
+ }
+
+ err_code = es_security_init(nrf_ble_escs_security_cb);
+ APP_ERROR_CHECK(err_code);
+
+ es_adv_timers_init();
+ ble_escs_init();
+ adv_slots_init();
+ es_battery_voltage_init();
+ adv_init();
+ es_adv_start_non_connctable_adv();
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/nrf_ble_es.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/nrf_ble_es.h
new file mode 100644
index 0000000..3262136
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/eddystone/nrf_ble_es.h
@@ -0,0 +1,99 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef NRF_ES_H__
+#define NRF_ES_H__
+
+#include <stdint.h>
+#include "ble.h"
+
+/**
+ * @file
+ * @defgroup eddystone Eddystone library
+ * @ingroup app_common
+ * @{
+ *
+ * @brief Library for Eddystone beacons. This library is used in the @ref ble_sdk_app_es.
+ *
+ * @note The API documentation is provided for reference only. You should
+ * not modify this library, and you should not use any functions
+ * except for the main level functions defined in @c nrf_ble_es.h
+ * in different contexts.
+ */
+
+/** @brief Eddystone event types. */
+typedef enum
+{
+ NRF_BLE_ES_EVT_ADVERTISEMENT_SENT, //!< A non-connectable Eddystone frame advertisement was sent.
+ NRF_BLE_ES_EVT_CONNECTABLE_ADV_STARTED, //!< Advertising in connectable mode was started.
+ NRF_BLE_ES_EVT_CONNECTABLE_ADV_STOPPED, //!< Advertising in connectable mode was stopped.
+} nrf_ble_es_evt_t;
+
+/**@brief Eddystone event handler type. */
+typedef void (*nrf_ble_es_evt_handler_t)(nrf_ble_es_evt_t evt);
+
+/**@brief Function for handling the application's BLE stack events.
+ *
+ * @details This function handles all events from the BLE stack that are of
+ * interest to the Eddystone library.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context User parameter.
+ */
+void nrf_ble_es_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+/**@brief Function for putting the beacon in connectable mode.
+ *
+ * @details This function makes the beacon advertise connectable advertisements.
+ * If the beacon is in a connected state, the request is ignored.
+ */
+void nrf_ble_es_on_start_connectable_advertising(void);
+
+/** @brief Function for initializing the Eddystone library.
+ *
+ * @param[in] evt_handler Event handler to be called for handling BLE events.
+ */
+void nrf_ble_es_init(nrf_ble_es_evt_handler_t evt_handler);
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_common.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_common.h
new file mode 100644
index 0000000..54cb080
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_common.h
@@ -0,0 +1,94 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_sdk_srv_ln_common Location and Navigation common defines
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Location and Navigation common defines
+ *
+ * @details This module contains define values common to LNS and LNCP
+ */
+
+#ifndef BLE_LNS_COMMON_H__
+#define BLE_LNS_COMMON_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BLE_LNS_INVALID_ROUTE 0xFFFF
+#define BLE_LNS_NO_FIX 0xFF
+
+#define BLE_LNS_MAX_NUM_ROUTES 10 /**< The maximum number of routes. This affects memory usage only. */
+#define BLE_LNS_MAX_ROUTE_NAME_LEN BLE_GATT_ATT_MTU_DEFAULT - 5 /**< The maximum length of length of a route name. */
+#define MAX_CTRL_POINT_RESP_PARAM_LEN BLE_LNS_MAX_ROUTE_NAME_LEN + 3 /**< Maximum length of a control point response. */
+
+// Location and Navigation Service feature bits
+#define BLE_LNS_FEATURE_INSTANT_SPEED_SUPPORTED (0x01 << 0) /**< Instaneous Speed Supported bit. */
+#define BLE_LNS_FEATURE_TOTAL_DISTANCE_SUPPORTED (0x01 << 1) /**< Total Distance Supported bit. */
+#define BLE_LNS_FEATURE_LOCATION_SUPPORTED (0x01 << 2) /**< Location Supported bit. */
+#define BLE_LNS_FEATURE_ELEVATION_SUPPORTED (0x01 << 3) /**< Elevation Supported bit. */
+#define BLE_LNS_FEATURE_HEADING_SUPPORTED (0x01 << 4) /**< Heading Supported bit. */
+#define BLE_LNS_FEATURE_ROLLING_TIME_SUPPORTED (0x01 << 5) /**< Rolling Time Supported bit. */
+#define BLE_LNS_FEATURE_UTC_TIME_SUPPORTED (0x01 << 6) /**< UTC Time Supported bit. */
+#define BLE_LNS_FEATURE_REMAINING_DISTANCE_SUPPORTED (0x01 << 7) /**< Remaining Distance Supported bit. */
+#define BLE_LNS_FEATURE_REMAINING_VERT_DISTANCE_SUPPORTED (0x01 << 8) /**< Remaining Vertical Distance Supported bit. */
+#define BLE_LNS_FEATURE_EST_TIME_OF_ARRIVAL_SUPPORTED (0x01 << 9) /**< Estimated Time of Arrival Supported bit. */
+#define BLE_LNS_FEATURE_NUM_SATS_IN_SOLUTION_SUPPORTED (0x01 << 10) /**< Number of Satellites in Solution Supported bit. */
+#define BLE_LNS_FEATURE_NUM_SATS_IN_VIEW_SUPPORTED (0x01 << 11) /**< Number of Satellites in View Supported bit. */
+#define BLE_LNS_FEATURE_TIME_TO_FIRST_FIX_SUPPORTED (0x01 << 12) /**< Time to First Fix Supported bit. */
+#define BLE_LNS_FEATURE_EST_HORZ_POS_ERROR_SUPPORTED (0x01 << 13) /**< Estimated Horizontal Position Error Supported bit. */
+#define BLE_LNS_FEATURE_EST_VERT_POS_ERROR_SUPPORTED (0x01 << 14) /**< Estimated Vertical Position Error Supported bit. */
+#define BLE_LNS_FEATURE_HORZ_DILUTION_OF_PRECISION_SUPPORTED (0x01 << 15) /**< Horizontal Dilution of Precision Supported bit. */
+#define BLE_LNS_FEATURE_VERT_DILUTION_OF_PRECISION_SUPPORTED (0x01 << 16) /**< Vertical Dilution of Precision Supported bit. */
+#define BLE_LNS_FEATURE_LOC_AND_SPEED_CONTENT_MASKING_SUPPORTED (0x01 << 17) /**< Location and Speed Characteristic Content Masking Supported bit. */
+#define BLE_LNS_FEATURE_FIX_RATE_SETTING_SUPPORTED (0x01 << 18) /**< Fix Rate Setting Supported bit. */
+#define BLE_LNS_FEATURE_ELEVATION_SETTING_SUPPORTED (0x01 << 19) /**< Elevation Setting Supported bit. */
+#define BLE_LNS_FEATURE_POSITION_STATUS_SUPPORTED (0x01 << 20) /**< Position Status Supported bit. */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BLE_LNS_COMMON_H__ */
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_cp.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_cp.c
new file mode 100644
index 0000000..97eb3d9
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_cp.c
@@ -0,0 +1,821 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "ble_ln_cp.h"
+#include "ble_ln_db.h"
+#include "ble_ln_common.h"
+#include "sdk_common.h"
+
+#define NRF_LOG_MODULE_NAME ble_ln_cp
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+// Feature Mask bits
+#define FEATURE_MASK_INSTANTANEOUS_SPEED (0x01 << 0) /**< Instantaneous Speed mask bit. */
+#define FEATURE_MASK_TOTAL_DISTANCE (0x01 << 1) /**< Total Distance mask bit. */
+#define FEATURE_MASK_LOCATION (0x01 << 2) /**< Location mask bit. */
+#define FEATURE_MASK_ELEVATION (0x01 << 3) /**< Elevation mask bit. */
+#define FEATURE_MASK_HEADING (0x01 << 4) /**< Heading mask bit. */
+#define FEATURE_MASK_ROLLING_TIME (0x01 << 5) /**< Rolling Time mask bit. */
+#define FEATURE_MASK_UTC_TIME (0x01 << 6) /**< UTC Time mask bit. */
+
+// Data Control point parameter type lengths.
+#define INT8_LEN 1
+#define INT16_LEN 2
+#define INT24_LEN 3
+#define INT32_LEN 4
+
+#define OPCODE_LENGTH 1 /**< Length of opcode inside Location and Navigation Measurement packet. */
+#define HANDLE_LENGTH 2 /**< Length of handle inside Location and Navigation Measurement packet. */
+
+static ble_lncp_rsp_code_t notify_app(ble_lncp_t const * p_lncp, ble_lncp_evt_t const * p_evt)
+{
+ ble_lncp_rsp_code_t rsp = LNCP_RSP_SUCCESS;
+
+ if (p_lncp->evt_handler != NULL)
+ {
+ rsp = p_lncp->evt_handler(p_lncp, p_evt);
+ }
+
+ return rsp;
+}
+
+
+static void resp_send(ble_lncp_t * p_lncp)
+{
+ // Send indication
+ uint16_t hvx_len;
+ uint8_t hvx_data[MAX_CTRL_POINT_RESP_PARAM_LEN];
+ ble_gatts_hvx_params_t hvx_params;
+ uint32_t err_code;
+
+ memset(&hvx_params, 0, sizeof(hvx_params));
+
+ hvx_len = 3 + p_lncp->pending_rsp.rsp_param_len;
+ hvx_data[0] = LNCP_OP_RESPONSE_CODE;
+ hvx_data[1] = p_lncp->pending_rsp.op_code;
+ hvx_data[2] = p_lncp->pending_rsp.rsp_code;
+
+ memcpy(&hvx_data[3], &p_lncp->pending_rsp.rsp_param[0], p_lncp->pending_rsp.rsp_param_len);
+
+ hvx_params.handle = p_lncp->ctrlpt_handles.value_handle;
+ hvx_params.type = BLE_GATT_HVX_INDICATION;
+ hvx_params.offset = 0;
+ hvx_params.p_len = &hvx_len;
+ hvx_params.p_data = hvx_data;
+
+ err_code = sd_ble_gatts_hvx(p_lncp->conn_handle, &hvx_params);
+
+ // Error handling
+ if ((err_code == NRF_SUCCESS) && (hvx_len != p_lncp->pending_rsp.rsp_param_len + 3))
+ {
+ err_code = NRF_ERROR_DATA_SIZE;
+ }
+
+ switch (err_code)
+ {
+ case NRF_SUCCESS:
+ p_lncp->procedure_status = LNCP_STATE_CONFIRMATION_PENDING;
+ // Wait for HVC event
+ break;
+
+ case NRF_ERROR_RESOURCES:
+ // Wait for TX_COMPLETE event to retry transmission
+ p_lncp->procedure_status = LNCP_STATE_INDICATION_PENDING;
+ break;
+
+ default:
+ p_lncp->procedure_status = LNCP_STATE_INDICATION_PENDING;
+ // error
+ if (p_lncp->error_handler != NULL)
+ {
+ p_lncp->error_handler(err_code);
+ }
+ break;
+ }
+}
+
+
+static void on_connect(ble_lncp_t * p_lncp, ble_evt_t const * p_ble_evt)
+{
+ memset(&p_lncp->mask, 0, sizeof(ble_lncp_mask_t));
+ p_lncp->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+ p_lncp->procedure_status = LNCP_STATE_NO_PROC_IN_PROGRESS;
+}
+
+
+static void on_disconnect(ble_lncp_t * p_lncp, ble_evt_t const * p_ble_evt)
+{
+ UNUSED_PARAMETER(p_ble_evt);
+ p_lncp->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_lncp->procedure_status = LNCP_STATE_NO_PROC_IN_PROGRESS;
+}
+
+
+static void on_hvc_confirm(ble_lncp_t * p_lncp, ble_evt_t const * p_ble_evt)
+{
+ if (p_ble_evt->evt.gatts_evt.params.hvc.handle == p_lncp->ctrlpt_handles.value_handle)
+ {
+ if (p_lncp->procedure_status == LNCP_STATE_CONFIRMATION_PENDING)
+ {
+ p_lncp->procedure_status = LNCP_STATE_NO_PROC_IN_PROGRESS;
+ }
+ else
+ {
+ if (p_lncp->error_handler != NULL)
+ {
+ p_lncp->error_handler(NRF_ERROR_INVALID_STATE);
+ }
+ }
+ }
+}
+
+
+static void on_tx_complete(ble_lncp_t * p_lncp)
+{
+ if (p_lncp->procedure_status == LNCP_STATE_INDICATION_PENDING)
+ {
+ resp_send(p_lncp);
+ }
+}
+
+
+/**@brief Handle write events to the control point cccd.
+ *
+ * @param[in] p_lncp Location and Navigation Service structure.
+ * @param[in] p_evt_write Write event received from the BLE stack.
+ */
+static void on_lncp_cccd_write(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
+{
+ if (p_evt_write->len == BLE_CCCD_VALUE_LEN)
+ {
+ // CCCD written, update indications state
+ p_lncp->is_ctrlpt_indication_enabled = ble_srv_is_indication_enabled(p_evt_write->data);
+ }
+}
+
+
+/**@brief Handle write events to the navigation cccd.
+ *
+ * @param[in] p_lncp Location and Navigation Service structure.
+ * @param[in] p_evt_write Write event received from the BLE stack.
+ */
+static void on_nav_cccd_write(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
+{
+ if (p_evt_write->len == BLE_CCCD_VALUE_LEN)
+ {
+ // CCCD written, update notification state
+ p_lncp->is_nav_notification_enabled = ble_srv_is_notification_enabled(p_evt_write->data);
+ }
+}
+
+
+/**@brief Event handler for control point write.
+ *
+ * @param[in] p_lncp Location and Navigation Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_set_cumulative_value(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
+{
+ if ( !(p_lncp->available_features & BLE_LNS_FEATURE_TOTAL_DISTANCE_SUPPORTED) )
+ {
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED;
+ return;
+ }
+
+ if (p_evt_write->len != OPCODE_LENGTH + INT24_LEN)
+ {
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
+ return;
+ }
+
+ const uint32_t total_distance = uint24_decode(&p_evt_write->data[1]);
+
+ const ble_lncp_evt_t evt = {
+ .evt_type = LNCP_EVT_TOTAL_DISTANCE_SET,
+ .params.total_distance = total_distance
+ };
+ p_lncp->pending_rsp.rsp_code = notify_app(p_lncp, &evt);
+
+ if (p_lncp->pending_rsp.rsp_code == LNCP_RSP_SUCCESS)
+ {
+ p_lncp->total_distance = total_distance;
+ }
+
+}
+
+
+/**@brief Event handler for control point write.
+ *
+ * @param[in] p_lncp Location and Navigation Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_mask_loc_speed_content(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
+{
+ if ( !(p_lncp->available_features & BLE_LNS_FEATURE_LOC_AND_SPEED_CONTENT_MASKING_SUPPORTED) )
+ {
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED;
+ return;
+ }
+
+ if (p_evt_write->len != OPCODE_LENGTH + INT16_LEN)
+ {
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
+ return;
+ }
+
+ uint16_t rcvd_mask = uint16_decode(&p_evt_write->data[1]);
+
+ if (rcvd_mask > 0x7F)
+ {
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
+ return;
+ }
+
+ const ble_lncp_evt_t evt = {
+ .evt_type = LNCP_EVT_MASK_SET,
+ .params.mask.flags = rcvd_mask
+ };
+ p_lncp->pending_rsp.rsp_code = notify_app(p_lncp, &evt);
+
+ if (p_lncp->pending_rsp.rsp_code == LNCP_RSP_SUCCESS)
+ {
+ p_lncp->mask.flags = rcvd_mask;
+ }
+}
+
+
+/**@brief Event handler for control point write.
+ *
+ * @param[in] p_lncp Location and Navigation Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_nav_control(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
+{
+ if ( !(p_lncp->is_navigation_present) )
+ {
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED;
+ return;
+ }
+
+ if (p_evt_write->len != LNCP_NAV_CMD_LEN)
+ {
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
+ return;
+ }
+
+ /*lint --e{415} --e{416} -save suppress Warning 415: possible access out of bond */
+ const uint8_t data_buf = p_evt_write->data[1];
+ /*lint -restore*/
+
+ if (data_buf > LNCP_NAV_CMD_MAX)
+ {
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
+ return;
+ }
+
+ const ble_lncp_nav_cmd_t cmd = (ble_lncp_nav_cmd_t) data_buf;
+
+ if (cmd == LNCP_CMD_NAV_START || cmd == LNCP_CMD_NAV_CONTINUE || cmd == LNCP_CMD_NAV_NEAREST)
+ {
+ p_lncp->is_navigation_running = true;
+ }
+ else if (cmd == LNCP_CMD_NAV_STOP || cmd == LNCP_CMD_NAV_PAUSE)
+ {
+ p_lncp->is_navigation_running = false;
+ }
+
+ const ble_lncp_evt_t evt = {
+ .evt_type = LNCP_EVT_NAV_COMMAND,
+ .params.nav_cmd = cmd
+ };
+ p_lncp->pending_rsp.rsp_code = notify_app(p_lncp, &evt);
+}
+
+
+/**@brief Event handler for control point write.
+ *
+ * @param[in] p_lncp Location and Navigation Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_req_num_routes(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
+{
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_SUCCESS;
+
+ if ( !(p_lncp->is_navigation_present) )
+ {
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED;
+ return;
+ }
+
+ if (p_evt_write->len != OPCODE_LENGTH)
+ {
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
+ return;
+ }
+
+ const uint8_t num_records = ble_ln_db_num_records_get();
+ p_lncp->pending_rsp.rsp_param_len = uint16_encode(num_records, &p_lncp->pending_rsp.rsp_param[0]);
+}
+
+
+/**@brief Event handler for control point write.
+ *
+ * @param[in] p_lncp Location and Navigation Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_req_name_of_route(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
+{
+ uint8_t * p_name;
+ uint32_t err_code;
+
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_SUCCESS;
+
+ if ( !(p_lncp->is_navigation_present) )
+ {
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED;
+ return;
+ }
+
+ if (p_evt_write->len != OPCODE_LENGTH + INT16_LEN)
+ {
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
+ return;
+ }
+
+ /*lint --e{415} --e{416} -save suppress Warning 415: possible access out of bond */
+ const uint16_t route_num = uint16_decode(&p_evt_write->data[1]);
+ /*lint -restore*/
+
+ err_code = ble_ln_db_record_name_get(route_num, &p_name);
+ if (err_code != NRF_SUCCESS)
+ {
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_OPERATION_FAILED;
+ return;
+ }
+ memcpy(&p_lncp->pending_rsp.rsp_param[0], p_name, BLE_LNS_MAX_ROUTE_NAME_LEN);
+
+ p_lncp->pending_rsp.rsp_param_len = BLE_LNS_MAX_ROUTE_NAME_LEN;
+}
+
+
+/**@brief Event handler for control point write.
+ *
+ * @param[in] p_lncp Location and Navigation Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_select_route(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
+{
+ if ( !(p_lncp->is_navigation_present))
+ {
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED;
+ return;
+ }
+
+ if (p_evt_write->len != OPCODE_LENGTH + INT16_LEN)
+ {
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
+ return;
+ }
+
+ const uint16_t route_num = uint16_decode(&p_evt_write->data[1]);
+ const uint16_t stored_num = ble_ln_db_num_records_get();
+
+ if (route_num >= stored_num)
+ {
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
+ return;
+ }
+
+ const ble_lncp_evt_t evt = {
+ .evt_type = LNCP_EVT_ROUTE_SELECTED,
+ .params.selected_route = route_num
+ };
+ p_lncp->pending_rsp.rsp_code = notify_app(p_lncp, &evt);
+
+ if (p_lncp->pending_rsp.rsp_code == LNCP_RSP_SUCCESS)
+ {
+ p_lncp->selected_route = route_num;
+ }
+}
+
+
+/**@brief Event handler for control point write.
+ *
+ * @param[in] p_lncp Location and Navigation Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_set_fix_rate(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
+{
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_SUCCESS;
+
+ if ( !(p_lncp->available_features & BLE_LNS_FEATURE_FIX_RATE_SETTING_SUPPORTED) )
+ {
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED;
+ return;
+ }
+
+ if (p_evt_write->len != OPCODE_LENGTH + INT8_LEN)
+ {
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
+ return;
+ }
+
+ /*lint --e{415} --e{416} -save suppress Warning 415: possible access out of bond */
+ const uint8_t fix_rate = p_evt_write->data[1];
+ /*lint -restore*/
+
+ const ble_lncp_evt_t evt = {
+ .evt_type = LNCP_EVT_FIX_RATE_SET,
+ .params.fix_rate = fix_rate
+ };
+ p_lncp->pending_rsp.rsp_code = notify_app(p_lncp, &evt);
+
+ if (p_lncp->pending_rsp.rsp_code == LNCP_RSP_SUCCESS)
+ {
+ p_lncp->fix_rate = fix_rate;
+ }
+}
+
+
+/**@brief Event handler for control point write.
+ *
+ * @param[in] p_lncp Location and Navigation Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_set_elevation(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
+{
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_SUCCESS;
+
+ if ( !(p_lncp->available_features & BLE_LNS_FEATURE_ELEVATION_SETTING_SUPPORTED) )
+ {
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED;
+ return;
+ }
+
+ if (p_evt_write->len != OPCODE_LENGTH + INT24_LEN)
+ {
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_INVALID_PARAMETER;
+ return;
+ }
+
+ const uint32_t elevation = uint24_decode(&p_evt_write->data[1]);
+ ble_lncp_evt_t evt = {
+ .evt_type = LNCP_EVT_ELEVATION_SET,
+ .params.elevation = elevation
+ };
+ p_lncp->pending_rsp.rsp_code = notify_app(p_lncp, &evt);
+
+ if (p_lncp->pending_rsp.rsp_code == LNCP_RSP_SUCCESS)
+ {
+ p_lncp->elevation = elevation;
+ }
+}
+
+
+/**@brief Handle write events to the Location and Navigation Service Control Point characteristic.
+ *
+ * @param[in] p_lncp Location and Navigation Service structure.
+ * @param[in] p_evt_write Write event received from the BLE stack.
+ */
+static void on_ctrlpt_write(ble_lncp_t * p_lncp, ble_gatts_evt_write_t const * p_evt_write)
+{
+ uint32_t err_code;
+
+ p_lncp->pending_rsp.rsp_param_len = 0;
+
+ ble_gatts_rw_authorize_reply_params_t write_authorize_reply;
+ memset(&write_authorize_reply, 0, sizeof(write_authorize_reply));
+
+ write_authorize_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
+
+ if (p_lncp->is_ctrlpt_indication_enabled)
+ {
+ if (p_lncp->procedure_status == LNCP_STATE_NO_PROC_IN_PROGRESS)
+ {
+ write_authorize_reply.params.write.update = 1;
+ write_authorize_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+
+ // if the op code is navigation control, its cccd must be checked
+ if (p_evt_write->len > 0 && p_lncp->is_navigation_present)
+ {
+ if ( p_evt_write->data[0] == LNCP_OP_NAV_CONTROL
+ || p_evt_write->data[0] == LNCP_OP_REQ_NAME_OF_ROUTE
+ || p_evt_write->data[0] == LNCP_OP_REQ_NUM_ROUTES)
+ {
+ if (!p_lncp->is_nav_notification_enabled)
+ {
+ write_authorize_reply.params.write.gatt_status = LNCP_RSP_CCCD_CONFIG_IMPROPER;
+ }
+ }
+ }
+ }
+ else
+ {
+ write_authorize_reply.params.write.gatt_status = LNCP_RSP_PROC_ALR_IN_PROG;
+ }
+ }
+ else
+ {
+ write_authorize_reply.params.write.gatt_status = LNCP_RSP_CCCD_CONFIG_IMPROPER;
+ }
+
+ // reply to the write authorization
+ do {
+ err_code = sd_ble_gatts_rw_authorize_reply(p_lncp->conn_handle, &write_authorize_reply);
+ if (err_code != NRF_SUCCESS && err_code != NRF_ERROR_BUSY)
+ {
+ if (p_lncp->error_handler != NULL)
+ {
+ p_lncp->error_handler(err_code);
+ }
+ }
+ } while (err_code == NRF_ERROR_BUSY);
+
+
+ if (write_authorize_reply.params.write.gatt_status != BLE_GATT_STATUS_SUCCESS)
+ {
+ return;
+ }
+
+ // Start executing the control point write action
+ p_lncp->procedure_status = LNCP_STATE_INDICATION_PENDING;
+ if (p_evt_write->len > 0)
+ {
+ p_lncp->pending_rsp.op_code = (ble_lncp_op_code_t) p_evt_write->data[0];
+ switch (p_lncp->pending_rsp.op_code)
+ {
+ case LNCP_OP_SET_CUMULATIVE_VALUE:
+ on_set_cumulative_value(p_lncp, p_evt_write);
+ break;
+
+ case LNCP_OP_MASK_LOC_SPEED_CONTENT:
+ on_mask_loc_speed_content(p_lncp, p_evt_write);
+ break;
+
+ case LNCP_OP_NAV_CONTROL:
+ on_nav_control(p_lncp, p_evt_write);
+ break;
+
+ case LNCP_OP_REQ_NUM_ROUTES:
+ on_req_num_routes(p_lncp, p_evt_write);
+ break;
+
+ case LNCP_OP_REQ_NAME_OF_ROUTE:
+ on_req_name_of_route(p_lncp, p_evt_write);
+ break;
+
+ case LNCP_OP_SELECT_ROUTE:
+ on_select_route(p_lncp, p_evt_write);
+ break;
+
+ case LNCP_OP_SET_FIX_RATE:
+ on_set_fix_rate(p_lncp, p_evt_write);
+ break;
+
+ case LNCP_OP_SET_ELEVATION:
+ on_set_elevation(p_lncp, p_evt_write);
+ break;
+
+ // Unrecognized Op Code
+ default:
+ p_lncp->pending_rsp.rsp_code = LNCP_RSP_OP_CODE_NOT_SUPPORTED;
+ break;
+ }
+
+ resp_send(p_lncp);
+ }
+ else
+ {
+ p_lncp->procedure_status = LNCP_STATE_NO_PROC_IN_PROGRESS;
+ }
+}
+
+
+/**@brief Write authorization request event handler.
+ *
+ * @details The write authorization request event handler is only called when writing to the control point.
+ *
+ * @param[in] p_lncp Location and Navigation Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_rw_authorize_req(ble_lncp_t * p_lncp, ble_evt_t const * p_ble_evt)
+{
+ const ble_gatts_evt_rw_authorize_request_t * p_auth_req =
+ &p_ble_evt->evt.gatts_evt.params.authorize_request;
+
+ if (
+ (p_auth_req->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
+ &&
+ (p_auth_req->request.write.handle == p_lncp->ctrlpt_handles.value_handle)
+ &&
+ (p_auth_req->request.write.op != BLE_GATTS_OP_PREP_WRITE_REQ)
+ &&
+ (p_auth_req->request.write.op != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW)
+ &&
+ (p_auth_req->request.write.op != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)
+ )
+ {
+ on_ctrlpt_write(p_lncp, &p_auth_req->request.write);
+ }
+
+}
+
+
+/**@brief Write event handler.
+ *
+ * @param[in] p_lncp Location and Navigation Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_write(ble_lncp_t * p_lncp, ble_evt_t const * p_ble_evt)
+{
+ const ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+ if (p_evt_write->handle == p_lncp->ctrlpt_handles.cccd_handle)
+ {
+ on_lncp_cccd_write(p_lncp, p_evt_write);
+ }
+ else if (p_evt_write->handle == p_lncp->navigation_handles.cccd_handle)
+ {
+ on_nav_cccd_write(p_lncp, p_evt_write);
+ }
+}
+
+
+void ble_lncp_on_ble_evt(ble_lncp_t * p_lncp, ble_evt_t const * p_ble_evt)
+{
+ VERIFY_PARAM_NOT_NULL_VOID(p_lncp);
+ VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ on_connect(p_lncp, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ if (p_ble_evt->evt.gap_evt.conn_handle == p_lncp->conn_handle)
+ {
+ on_disconnect(p_lncp, p_ble_evt);
+ }
+ break;
+
+ case BLE_GATTS_EVT_WRITE:
+ if (p_ble_evt->evt.gatts_evt.conn_handle == p_lncp->conn_handle)
+ {
+ on_write(p_lncp, p_ble_evt);
+ }
+ break;
+
+ case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
+ if (p_ble_evt->evt.gatts_evt.conn_handle == p_lncp->conn_handle)
+ {
+ on_rw_authorize_req(p_lncp, p_ble_evt);
+ }
+ break;
+
+ case BLE_GATTS_EVT_HVC:
+ if (p_ble_evt->evt.gatts_evt.conn_handle == p_lncp->conn_handle)
+ {
+ on_hvc_confirm(p_lncp, p_ble_evt);
+ }
+ break;
+
+ case BLE_GATTS_EVT_HVN_TX_COMPLETE:
+ on_tx_complete(p_lncp);
+ break;
+
+ default:
+ // no implementation
+ break;
+ }
+}
+
+
+uint32_t ble_lncp_total_distance_get(ble_lncp_t const * p_lncp)
+{
+ if (p_lncp == NULL)
+ {
+ return 0;
+ }
+
+ return p_lncp->total_distance;
+}
+
+
+uint32_t ble_lncp_elevation_get(ble_lncp_t const * p_lncp)
+{
+ if (p_lncp == NULL)
+ {
+ return 0;
+ }
+
+ return p_lncp->elevation;
+}
+
+
+ble_lncp_mask_t ble_lncp_mask_get(ble_lncp_t const * p_lncp)
+{
+ if (p_lncp == NULL)
+ {
+ const ble_lncp_mask_t empty_mask = {0};
+ return empty_mask;
+ }
+
+ return p_lncp->mask;
+}
+
+
+bool ble_lncp_is_navigation_running(ble_lncp_t const * p_lncp)
+{
+ if (p_lncp == NULL)
+ {
+ return false;
+ }
+
+ return p_lncp->is_navigation_running;
+}
+
+
+ret_code_t ble_lncp_init(ble_lncp_t * p_lncp, ble_lncp_init_t const * p_lncp_init)
+{
+ VERIFY_PARAM_NOT_NULL(p_lncp);
+ VERIFY_PARAM_NOT_NULL(p_lncp_init);
+
+ ble_add_char_params_t add_char_params;
+
+ memset(&add_char_params, 0, sizeof(add_char_params));
+
+ p_lncp->service_handle = p_lncp_init->service_handle;
+ p_lncp->evt_handler = p_lncp_init->evt_handler;
+ p_lncp->error_handler = p_lncp_init->error_handler;
+ p_lncp->available_features = p_lncp_init->available_features;
+ p_lncp->is_position_quality_present = p_lncp_init->is_position_quality_present;
+ p_lncp->is_navigation_present = p_lncp_init->is_navigation_present;
+ p_lncp->total_distance = p_lncp_init->total_distance;
+ p_lncp->elevation = p_lncp_init->elevation;
+ p_lncp->navigation_handles = p_lncp_init->navigation_handles;
+
+ p_lncp->fix_rate = BLE_LNS_NO_FIX;
+ p_lncp->selected_route = BLE_LNS_INVALID_ROUTE;
+
+ p_lncp->procedure_status = LNCP_STATE_NO_PROC_IN_PROGRESS;
+ p_lncp->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_lncp->is_navigation_running = false;
+ p_lncp->is_nav_notification_enabled = false;
+ p_lncp->is_ctrlpt_indication_enabled = false;
+
+ memset(&p_lncp->mask, 0, sizeof(ble_lncp_mask_t));
+
+ add_char_params.uuid = BLE_UUID_LN_CONTROL_POINT_CHAR;
+ add_char_params.max_len = 0;
+ add_char_params.char_props.indicate = true;
+ add_char_params.char_props.write = true;
+ add_char_params.is_defered_write = true;
+ add_char_params.is_var_len = true;
+ add_char_params.max_len = BLE_GATT_ATT_MTU_DEFAULT;
+ add_char_params.write_access = p_lncp_init->write_perm;
+ add_char_params.cccd_write_access = p_lncp_init->cccd_write_perm;
+
+ NRF_LOG_DEBUG("Initialized");
+
+ return characteristic_add(p_lncp->service_handle,
+ &add_char_params,
+ &p_lncp->ctrlpt_handles);
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_cp.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_cp.h
new file mode 100644
index 0000000..768ba23
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_cp.h
@@ -0,0 +1,255 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_sdk_srv_lncp Location and Navigation Service Control Point
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Location and Navigation Service Control Point module
+ *
+ * @details This module implements the Location and Navigation Service Control Point behavior.
+ */
+
+#ifndef BLE_LN_CTRLPT_H__
+#define BLE_LN_CTRLPT_H__
+
+#include "ble_srv_common.h"
+#include "sdk_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BLE_LNS_MAX_ROUTE_NAME_LEN BLE_GATT_ATT_MTU_DEFAULT - 5 /**< The maximum length of length of a route name. */
+#define MAX_CTRL_POINT_RESP_PARAM_LEN BLE_LNS_MAX_ROUTE_NAME_LEN + 3 /**< Maximum length of a control point response. */
+
+typedef struct ble_lncp_s ble_lncp_t;
+
+/** @brief Location and Navigation event type. This list defines the possible events types from the Location and Navigation Service. */
+typedef enum
+{
+ LNCP_EVT_ELEVATION_SET, /**< Location and Navigation elevation was set. */
+ LNCP_EVT_FIX_RATE_SET, /**< Fix rate was set. */
+ LNCP_EVT_ROUTE_SELECTED, /**< A route was selected. */
+ LNCP_EVT_NAV_COMMAND, /**< A navigation command was issued. */
+ LNCP_EVT_MASK_SET, /**< Location and Speed feature mask was set. */
+ LNCP_EVT_TOTAL_DISTANCE_SET /**< Location and Navigation total distance was set. */
+} ble_lncp_evt_type_t;
+
+
+/** @brief Navigation commands. These commands can be sent to the control point and returned by an event callback. */
+typedef enum
+{
+ LNCP_CMD_NAV_STOP = 0x00, /**< When received, is_navigation_running in @ref ble_lns_s will be set to false. */
+ LNCP_CMD_NAV_START = 0x01, /**< When received, is_navigation_running in @ref ble_lns_s will be set to true. */
+ LNCP_CMD_NAV_PAUSE = 0x02, /**< When received, is_navigation_running in @ref ble_lns_s will be set to false. */
+ LNCP_CMD_NAV_CONTINUE = 0x03, /**< When received, is_navigation_running in @ref ble_lns_s will be set to true. */
+ LNCP_CMD_NAV_SKIP_WAYPOINT = 0x04, /**< When received, is_navigation_running in @ref ble_lns_s will not be affected. */
+ LNCP_CMD_NAV_NEAREST = 0x05, /**< When received, is_navigation_running in @ref ble_lns_s will be set to true. */
+} ble_lncp_nav_cmd_t;
+#define LNCP_NAV_CMD_MAX 0x05
+#define LNCP_NAV_CMD_LEN (OPCODE_LENGTH + 1)
+
+
+#if defined(__CC_ARM)
+ #pragma push
+ #pragma anon_unions
+#elif defined(__ICCARM__)
+ #pragma language=extended
+#elif defined(__GNUC__)
+ /* anonymous unions are enabled by default */
+#endif
+
+/** @brief A mask can be used to temporarily enable and disable features of the Location and Speed characteristic.*/
+typedef union
+{
+ uint8_t flags;
+ struct
+ {
+ uint8_t instantaneous_speed :1;
+ uint8_t total_distance :1;
+ uint8_t location :1;
+ uint8_t elevation :1;
+ uint8_t heading :1;
+ uint8_t rolling_time :1;
+ uint8_t utc_time :1;
+ };
+} ble_lncp_mask_t;
+
+#if defined(__CC_ARM)
+ #pragma pop
+#elif defined(__ICCARM__)
+ /* leave anonymous unions enabled */
+#elif defined(__GNUC__)
+ /* anonymous unions are enabled by default */
+#endif
+
+typedef struct
+{
+ ble_lncp_evt_type_t evt_type;
+ union
+ {
+ ble_lncp_mask_t mask;
+ ble_lncp_nav_cmd_t nav_cmd;
+ uint32_t total_distance;
+ uint8_t fix_rate;
+ uint16_t selected_route;
+ uint32_t elevation;
+ } params;
+} ble_lncp_evt_t;
+
+
+// Location and Navigation Control Point response values
+typedef enum
+{
+ LNCP_RSP_RESERVED = 0x00, /**< Reserved for future use. */
+ LNCP_RSP_SUCCESS = 0x01, /**< Success. */
+ LNCP_RSP_OP_CODE_NOT_SUPPORTED = 0x02, /**< Op Code not supported. */
+ LNCP_RSP_INVALID_PARAMETER = 0x03, /**< Invalid Parameter. */
+ LNCP_RSP_OPERATION_FAILED = 0x04, /**< Operation Failed. */
+ LNCP_RSP_PROC_ALR_IN_PROG = BLE_GATT_STATUS_ATTERR_CPS_PROC_ALR_IN_PROG, /**< Control point procedure is already in progress. */
+ LNCP_RSP_CCCD_CONFIG_IMPROPER = BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR /**< CCCD is improperly configured. */
+} ble_lncp_rsp_code_t;
+
+
+typedef ble_lncp_rsp_code_t (*ble_lncp_evt_handler_t) (ble_lncp_t const * p_lncp, ble_lncp_evt_t const * p_evt);
+
+// Location and Navigation Control Point Op Code values
+typedef enum
+{
+ LNCP_OP_RESERVED = 0x00, /**< Reserved for future use. */
+ LNCP_OP_SET_CUMULATIVE_VALUE = 0x01, /**< Set Cumulative Value. */
+ LNCP_OP_MASK_LOC_SPEED_CONTENT = 0x02, /**< Mask Location and Speed Characteristic Content. */
+ LNCP_OP_NAV_CONTROL = 0x03, /**< Navigation Control. */
+ LNCP_OP_REQ_NUM_ROUTES = 0x04, /**< Request Number of Routes. */
+ LNCP_OP_REQ_NAME_OF_ROUTE = 0x05, /**< Request Name of Route. */
+ LNCP_OP_SELECT_ROUTE = 0x06, /**< Select Route. */
+ LNCP_OP_SET_FIX_RATE = 0x07, /**< Set Fix Rate. */
+ LNCP_OP_SET_ELEVATION = 0x08, /**< Set Elevation. */
+ LNCP_OP_RESPONSE_CODE = 0x20 /**< Response code. */
+} ble_lncp_op_code_t;
+
+
+/** @brief Location and Navigation Control Point procedure status */
+typedef enum
+{
+ LNCP_STATE_NO_PROC_IN_PROGRESS, /**< No procedure in progress. */
+ LNCP_STATE_INDICATION_PENDING, /**< Control Point indication is pending. */
+ LNCP_STATE_CONFIRMATION_PENDING, /**< Waiting for the indication confirmation. */
+} ble_lncp_procedure_status_t;
+
+
+/** @brief Information included in a control point write response indication. */
+typedef struct
+{
+ ble_lncp_op_code_t op_code; /**< Opcode of the control point write action. */
+ ble_lncp_rsp_code_t rsp_code; /**< Response code of the control point write action. */
+ uint8_t rsp_param_len;
+ uint8_t rsp_param[MAX_CTRL_POINT_RESP_PARAM_LEN];
+} ble_lncp_rsp_t;
+
+
+typedef struct
+{
+ uint16_t service_handle;
+ ble_lncp_evt_handler_t evt_handler;
+ ble_srv_error_handler_t error_handler;
+
+ uint32_t available_features; /**< Value of the LN feature. */
+ bool is_position_quality_present; /**< If set to true, the position quality characteristic will be added. Else not. */
+ bool is_control_point_present; /**< If set to true, the control point characteristic will be added. Else not. */
+ bool is_navigation_present; /**< If set to true, the navigation characteristic will be added. Else not. */
+ ble_gatts_char_handles_t navigation_handles;
+
+ uint32_t total_distance;
+ uint32_t elevation;
+
+ security_req_t write_perm;
+ security_req_t cccd_write_perm;
+} ble_lncp_init_t;
+
+
+struct ble_lncp_s
+{
+ uint16_t conn_handle;
+ uint16_t service_handle;
+ ble_gatts_char_handles_t ctrlpt_handles;
+ ble_gatts_char_handles_t navigation_handles;
+ ble_lncp_evt_handler_t evt_handler;
+ ble_srv_error_handler_t error_handler;
+ ble_lncp_procedure_status_t procedure_status;
+ ble_lncp_rsp_t pending_rsp;
+
+ ble_lncp_mask_t mask;
+ uint32_t total_distance;
+ uint32_t elevation;
+ uint8_t fix_rate;
+ uint16_t selected_route;
+ uint32_t available_features; /**< Value of the LN feature. */
+ bool is_position_quality_present; /**< If set to true, the position quality characteristic will be added. Else not. */
+ bool is_control_point_present; /**< If set to true, the control point characteristic will be added. Else not. */
+ bool is_navigation_present; /**< If set to true, the navigation characteristic will be added. Else not. */
+ bool is_navigation_running; /**< This variable can be set using the control point. Must be true to be able to send navigation updates. */
+
+ bool is_ctrlpt_indication_enabled; /**< True if indication is enabled on the Control Point characteristic. */
+ bool is_nav_notification_enabled; /**< True if notification is enabled on the Navigation characteristic. */
+};
+
+
+void ble_lncp_on_ble_evt(ble_lncp_t * p_lncp, ble_evt_t const * p_ble_evt);
+
+uint32_t ble_lncp_total_distance_get(ble_lncp_t const * p_lncp);
+
+uint32_t ble_lncp_elevation_get(ble_lncp_t const * p_lncp);
+
+ble_lncp_mask_t ble_lncp_mask_get(ble_lncp_t const * p_lncp);
+
+bool ble_lncp_is_navigation_running(ble_lncp_t const * p_lncp);
+
+ret_code_t ble_lncp_init(ble_lncp_t * p_lncp, ble_lncp_init_t const * p_lncp_init);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //BLE_LN_CTRLPT_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_db.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_db.c
new file mode 100644
index 0000000..d1ef5f6
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_db.c
@@ -0,0 +1,151 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "ble_ln_db.h"
+#include "ble_ln_common.h"
+
+typedef struct
+{
+ bool in_use_flag;
+ ble_lns_route_t record;
+} database_entry_t;
+
+static database_entry_t m_database[BLE_LNS_MAX_NUM_ROUTES];
+static uint8_t m_database_crossref[BLE_LNS_MAX_NUM_ROUTES];
+static uint16_t m_num_records;
+
+void ble_ln_db_init(void)
+{
+ int i;
+
+ for (i = 0; i < BLE_LNS_MAX_NUM_ROUTES; i++)
+ {
+ m_database[i].in_use_flag = false;
+ m_database_crossref[i] = 0xFF;
+ }
+
+ m_num_records = 0;
+}
+
+
+uint16_t ble_ln_db_num_records_get(void)
+{
+ return m_num_records;
+}
+
+
+ret_code_t ble_ln_db_record_get(uint8_t rec_ndx, ble_lns_route_t * p_rec)
+{
+ if (rec_ndx >= m_num_records)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ // copy record to the specified memory
+ *p_rec = m_database[m_database_crossref[rec_ndx]].record;
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t ble_ln_db_record_name_get(uint8_t rec_ndx, uint8_t ** p_buf)
+{
+ if (rec_ndx >= m_num_records)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ // copy record to the specified memory
+ *p_buf = m_database[m_database_crossref[rec_ndx]].record.route_name;
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t ble_ln_db_record_add(ble_lns_route_t * p_rec)
+{
+ int i;
+
+ if (m_num_records == BLE_LNS_MAX_NUM_ROUTES)
+ {
+ return NRF_ERROR_NO_MEM;
+ }
+
+ // find next available database entry
+ for (i = 0; i < BLE_LNS_MAX_NUM_ROUTES; i++)
+ {
+ if (!m_database[i].in_use_flag)
+ {
+ m_database[i].in_use_flag = true;
+ m_database[i].record = *p_rec;
+ m_database[i].record.route_id = i;
+ m_database_crossref[m_num_records] = i;
+ p_rec->route_id = i;
+ m_num_records++;
+ return NRF_SUCCESS;
+ }
+ }
+
+ return NRF_ERROR_NO_MEM;
+}
+
+
+ret_code_t ble_ln_db_record_delete(uint8_t rec_ndx)
+{
+ int i;
+
+ if (rec_ndx >= m_num_records)
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ // free entry
+ m_database[m_database_crossref[rec_ndx]].in_use_flag = false;
+
+ // decrease number of records
+ m_num_records--;
+
+ // remove cross reference index
+ for (i = rec_ndx; i < m_num_records; i++)
+ {
+ m_database_crossref[i] = m_database_crossref[i + 1];
+ }
+
+ return NRF_SUCCESS;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_db.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_db.h
new file mode 100644
index 0000000..649c19f
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_ln_db.h
@@ -0,0 +1,122 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_sdk_srv_ln_db Location and Navigation database
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Location and Navigation route database
+ */
+
+#ifndef BLE_LN_DB__
+#define BLE_LN_DB__
+
+#include "ble_lns.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Function for initializing the route database.
+ *
+ * @details This call initializes the database holding route records.
+ *
+ * @return NRF_SUCCESS on success.
+ */
+void ble_ln_db_init(void);
+
+/**@brief Function for getting the number of records in the database.
+ *
+ * @details This call returns the number of records in the database.
+ *
+ * @return Number of records in the database.
+ */
+uint16_t ble_ln_db_num_records_get(void);
+
+/**@brief Function for getting a record from the database.
+ *
+ * @details This call returns a specified record from the database.
+ *
+ * @param[in] record_num Index of the record to retrieve.
+ * @param[out] p_rec Pointer to record structure where retrieved record is copied to.
+ *
+ * @return NRF_SUCCESS on success.
+ */
+ret_code_t ble_ln_db_record_get(uint8_t record_num, ble_lns_route_t * p_rec);
+
+/**@brief Function for getting a record name from the database.
+ *
+ * @details This call returns a specified record name from the database.
+ *
+ * @param[in] rec_ndx Index of the record to retrieve.
+ * @param[out] p_buf Pointer to array where retrieved record name is copied to.
+ *
+ * @return NRF_SUCCESS on success.
+ */
+ret_code_t ble_ln_db_record_name_get(uint8_t rec_ndx, uint8_t ** p_buf);
+
+/**@brief Function for adding a record at the end of the database.
+ *
+ * @details This call adds a record as the last record in the database.
+ *
+ * @param[in] p_rec Pointer to record to add to database.
+ *
+ * @return NRF_SUCCESS on success.
+ */
+ret_code_t ble_ln_db_record_add(ble_lns_route_t * p_rec);
+
+/**@brief Function for deleting a database entry.
+ *
+ * @details This call deletes an record from the database.
+ *
+ * @param[in] record_num Index of record to delete.
+ *
+ * @return NRF_SUCCESS on success.
+ */
+ret_code_t ble_ln_db_record_delete(uint8_t record_num);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_LN_DB_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_lns.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_lns.c
new file mode 100644
index 0000000..4129d1d
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_lns.c
@@ -0,0 +1,1014 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "ble_lns.h"
+#include "ble_ln_db.h"
+#include "ble_ln_common.h"
+#include "sdk_common.h"
+
+#define NRF_LOG_MODULE_NAME ble_lns
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+// Location and Speed flag bits
+#define LOC_SPEED_FLAG_INSTANT_SPEED_PRESENT (0x01 << 0) /**< Instantaneous Speed Present bit. */
+#define LOC_SPEED_FLAG_TOTAL_DISTANCE_PRESENT (0x01 << 1) /**< Total Distance Present bit. */
+#define LOC_SPEED_FLAG_LOCATION_PRESENT (0x01 << 2) /**< Location Present bit. */
+#define LOC_SPEED_FLAG_ELEVATION_PRESENT (0x01 << 3) /**< Elevation Present bit. */
+#define LOC_SPEED_FLAG_HEADING_PRESENT (0x01 << 4) /**< Heading Present bit. */
+#define LOC_SPEED_FLAG_ROLLING_TIME_PRESENT (0x01 << 5) /**< Rolling Time Present bit. */
+#define LOC_SPEED_FLAG_UTC_TIME_PRESENT (0x01 << 6) /**< UTC Time Present bit. */
+#define LOC_SPEED_FLAG_POSITION_STATUS (0x03 << 7) /**< Position Status bits(2). */
+#define LOC_SPEED_FLAG_SPEED_AND_DIST_FORMAT (0x01 << 9) /**< Speed and Distance Format. */
+#define LOC_SPEED_FLAG_ELEVATION_SOURCE (0x03 << 10) /**< Elevation Source bits(2). */
+#define LOC_SPEED_FLAG_HEADING_SOURCE (0x01 << 12) /**< Heading Source. */
+
+// Position Quality flag bits
+#define POS_QUAL_FLAG_NUM_SATS_IN_SOLUTION_PRESENT (0x01 << 0) /**< Number of Satellites in Solution Present bit. */
+#define POS_QUAL_FLAG_NUM_SATS_IN_VIEW_PRESENT (0x01 << 1) /**< Number of Satellites in View Present bit. */
+#define POS_QUAL_FLAG_TIME_TO_FIRST_FIX_PRESESNT (0x01 << 2) /**< Time to First Fix Present bit. */
+#define POS_QUAL_FLAG_EHPE_PRESENT (0x01 << 3) /**< EHPE Present bit. */
+#define POS_QUAL_FLAG_EVPE_PRESENT (0x01 << 4) /**< EVPE Present bit. */
+#define POS_QUAL_FLAG_HDOP_PRESENT (0x01 << 5) /**< HDOP Present bit. */
+#define POS_QUAL_FLAG_VDOP_PRESENT (0x01 << 6) /**< VDOP Present bit. */
+#define POS_QUAL_FLAG_POSITION_STATUS (0x03 << 7) /**< Position Status bits(2). */
+
+// Navigation flag bits
+#define NAV_FLAG_REMAINING_DIST_PRESENT (0x01 << 0) /**< Remaining Distance Present bit. */
+#define NAV_FLAG_REAMINGING_VERT_DIST_PRESESNT (0x01 << 1) /**< Remaining Vertical Distance Present bit . */
+#define NAV_FLAG_ETA_PRESENT (0x01 << 2) /**< Estimated Time of Arrival Present bit. */
+#define NAV_FLAG_POSITION_STATUS (0x03 << 3) /**< Position Status bits(2). */
+#define NAV_FLAG_HEADING_SOURCE (0x01 << 5) /**< Heading Source bit. */
+#define NAV_FLAG_NAVIGATION_INDICATOR_TYPE (0x01 << 6) /**< Navigation Indicator Type bit. */
+#define NAV_FLAG_WAYPOINT_REACHED (0x01 << 7) /**< Waypoint Reached bit. */
+#define NAV_FLAG_DESTINATION_REACHED (0x01 << 8) /**< Destination Reached bit. */
+
+#define BLE_LNS_NAV_MAX_LEN 19 /**< The length of a navigation notification when all features are enabled. See @ref ble_lns_navigation_t to see what this represents, or check https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.navigation.xml. */
+
+
+static void notification_buffer_process(ble_lns_t * p_lns)
+{
+ notification_t * p_notification;
+
+ // See if a notification is pending
+ if (p_lns->pending_loc_speed_notifications[0].is_pending == true)
+ {
+ p_notification = &p_lns->pending_loc_speed_notifications[0];
+ }
+ else if (p_lns->pending_loc_speed_notifications[1].is_pending == true)
+ {
+ p_notification = &p_lns->pending_loc_speed_notifications[1];
+ }
+ else if (p_lns->pending_navigation_notification.is_pending == true)
+ {
+ p_notification = &p_lns->pending_navigation_notification;
+ }
+ else
+ {
+ p_notification = NULL;
+ }
+
+ // send the notification if necessary
+ if (p_notification != NULL)
+ {
+ uint32_t err_code;
+ ble_gatts_hvx_params_t hvx_params;
+
+ memset(&hvx_params, 0, sizeof(hvx_params));
+
+ uint16_t hvx_len = p_notification->len;
+
+ hvx_params.handle = p_notification->handle;
+ hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
+ hvx_params.offset = 0;
+ hvx_params.p_len = &hvx_len;
+ hvx_params.p_data = &p_notification->data[0];
+
+ err_code = sd_ble_gatts_hvx(p_lns->conn_handle, &hvx_params);
+
+ if ((err_code == NRF_SUCCESS) && (hvx_len == p_notification->len))
+ {
+ p_notification->is_pending = false;
+ }
+ }
+}
+
+
+/**@brief Connect event handler.
+ *
+ * @param[in] p_lns Location and Navigation Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_connect(ble_lns_t * p_lns, ble_evt_t const * p_ble_evt)
+{
+ p_lns->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+
+ // clear pending notifications
+ p_lns->pending_loc_speed_notifications[0].is_pending = false;
+ p_lns->pending_loc_speed_notifications[1].is_pending = false;
+ p_lns->pending_navigation_notification.is_pending = false;
+}
+
+
+/**@brief Disconnect event handler.
+ *
+ * @param[in] p_lns Location and Navigation Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_disconnect(ble_lns_t * p_lns, ble_evt_t const * p_ble_evt)
+{
+ if (p_lns->conn_handle != p_ble_evt->evt.gatts_evt.conn_handle)
+ {
+ return;
+ }
+
+ p_lns->conn_handle = BLE_CONN_HANDLE_INVALID;
+}
+
+
+/**@brief Handle write events to the control point cccd.
+ *
+ * @param[in] p_lncp Location and Navigation Service structure.
+ * @param[in] p_evt_write Write event received from the BLE stack.
+ */
+static void on_ctrl_pt_cccd_write(ble_lns_t * p_lns, ble_gatts_evt_write_t const * p_evt_write)
+{
+ if (p_evt_write->len == BLE_CCCD_VALUE_LEN)
+ {
+ if (p_lns->evt_handler != NULL)
+ {
+ ble_lns_evt_t evt;
+
+ if (ble_srv_is_indication_enabled(p_evt_write->data))
+ {
+ evt.evt_type = BLE_LNS_CTRLPT_EVT_INDICATION_ENABLED;
+ }
+ else
+ {
+ evt.evt_type = BLE_LNS_CTRLPT_EVT_INDICATION_DISABLED;
+ }
+
+ p_lns->evt_handler(p_lns, &evt);
+ }
+ }
+}
+
+
+/**@brief Handle write events to the Location and Speed cccd.
+ *
+ * @param[in] p_lns Location and Navigation Service structure.
+ * @param[in] p_evt_write Write event received from the BLE stack.
+ */
+static void on_loc_speed_cccd_write(ble_lns_t * p_lns,
+ ble_gatts_evt_write_t const * p_evt_write)
+{
+ if (p_evt_write->len == BLE_CCCD_VALUE_LEN)
+ {
+ // CCCD written, update notification state
+ p_lns->is_loc_speed_notification_enabled = ble_srv_is_notification_enabled(p_evt_write->data);
+ if (p_lns->evt_handler != NULL)
+ {
+ ble_lns_evt_t evt;
+
+ if (p_lns->is_loc_speed_notification_enabled)
+ {
+ evt.evt_type = BLE_LNS_LOC_SPEED_EVT_NOTIFICATION_ENABLED;
+ }
+ else
+ {
+ evt.evt_type = BLE_LNS_LOC_SPEED_EVT_NOTIFICATION_DISABLED;
+ }
+
+ p_lns->evt_handler(p_lns, &evt);
+ }
+ }
+}
+
+
+/**@brief Handle write events to the navigation cccd.
+ *
+ * @param[in] p_lns Location and Navigation Service structure.
+ * @param[in] p_evt_write Write event received from the BLE stack.
+ */
+static void on_nav_cccd_write(ble_lns_t * p_lns,
+ ble_gatts_evt_write_t const * p_evt_write)
+{
+ if (p_evt_write->len == BLE_CCCD_VALUE_LEN)
+ {
+ p_lns->is_nav_notification_enabled = ble_srv_is_notification_enabled(p_evt_write->data);
+ if (p_lns->evt_handler != NULL)
+ {
+ ble_lns_evt_t evt;
+
+ if (p_lns->is_nav_notification_enabled)
+ {
+ evt.evt_type = BLE_LNS_NAVIGATION_EVT_NOTIFICATION_ENABLED;
+ }
+ else
+ {
+ evt.evt_type = BLE_LNS_NAVIGATION_EVT_NOTIFICATION_DISABLED;
+ }
+
+ p_lns->evt_handler(p_lns, &evt);
+ }
+ }
+}
+
+
+/**@brief Write event handler.
+ *
+ * @param[in] p_lns Location and Navigation Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_write(ble_lns_t * p_lns, ble_evt_t const * p_ble_evt)
+{
+ if (p_lns->conn_handle != p_ble_evt->evt.gatts_evt.conn_handle)
+ {
+ return;
+ }
+
+ ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+ if (p_evt_write->handle == p_lns->ctrlpt_handles.cccd_handle)
+ {
+ on_ctrl_pt_cccd_write(p_lns, p_evt_write);
+ }
+ else if (p_evt_write->handle == p_lns->loc_speed_handles.cccd_handle)
+ {
+ on_loc_speed_cccd_write(p_lns, p_evt_write);
+ }
+ else if (p_evt_write->handle == p_lns->navigation_handles.cccd_handle)
+ {
+ on_nav_cccd_write(p_lns, p_evt_write);
+ }
+}
+
+
+/**@brief Tx Complete event handler. This is used to retry sending a packet.
+ *
+ * @details Tx Complete event handler.
+ * Handles WRITE events from the BLE stack and if an indication was pending try sending it
+ * again.
+ *
+ * @param[in] p_lns Location navigation structure.
+ */
+static void on_tx_complete(ble_lns_t * p_lns)
+{
+ notification_buffer_process(p_lns);
+}
+
+
+/**@brief Encode position quality.
+ *
+ * @param[in] p_lns Location and Navigation Service structure.
+ * @param[in] p_pos_qual Position quality data to be encoded.
+ * @param[out] p_encoded_buffer Buffer where the encoded data will be written.
+ *
+ * @return Size of encoded data.
+ */
+static uint8_t pos_qual_encode(ble_lns_t const * p_lns,
+ ble_lns_pos_quality_t const * p_pos_qual,
+ uint8_t * p_encoded_buffer)
+{
+ uint16_t flags = 0;
+ uint8_t len = 2; // flags are added at last
+
+ flags |= ((uint16_t)p_pos_qual->position_status << 7) & POS_QUAL_FLAG_POSITION_STATUS;
+
+ if (p_pos_qual->number_of_satellites_in_solution_present)
+ {
+ flags |= POS_QUAL_FLAG_NUM_SATS_IN_SOLUTION_PRESENT;
+ p_encoded_buffer[len++] = p_pos_qual->number_of_satellites_in_solution;
+ }
+
+ if (p_pos_qual->number_of_satellites_in_view_present)
+ {
+ flags |= POS_QUAL_FLAG_NUM_SATS_IN_VIEW_PRESENT;
+ p_encoded_buffer[len++] = p_pos_qual->number_of_satellites_in_view;
+ }
+
+ if (p_pos_qual->time_to_first_fix_present)
+ {
+ flags |= POS_QUAL_FLAG_TIME_TO_FIRST_FIX_PRESESNT;
+ len += uint16_encode(p_pos_qual->time_to_first_fix, &p_encoded_buffer[len]);
+ }
+
+ if (p_pos_qual->ehpe_present)
+ {
+ flags |= POS_QUAL_FLAG_EHPE_PRESENT;
+ len += uint32_encode(p_pos_qual->ehpe, &p_encoded_buffer[len]);
+ }
+
+ if (p_pos_qual->evpe_present)
+ {
+ flags |= POS_QUAL_FLAG_EVPE_PRESENT;
+ len += uint32_encode(p_pos_qual->evpe, &p_encoded_buffer[len]);
+ }
+
+ if (p_pos_qual->hdop_present)
+ {
+ flags |= POS_QUAL_FLAG_HDOP_PRESENT;
+ p_encoded_buffer[len++] = p_pos_qual->hdop;
+ }
+
+ if (p_pos_qual->vdop_present)
+ {
+ flags |= POS_QUAL_FLAG_VDOP_PRESENT;
+ p_encoded_buffer[len++] = p_pos_qual->vdop;
+ }
+
+ // Flags field
+ uint16_encode(flags, &p_encoded_buffer[0]); //lint !e534 "Ignoring return value of function"
+
+ return len;
+}
+
+
+/**@brief Encode Location and Speed data packet 1
+ *
+ * @param[in] p_lns Location and Navigation Service structure.
+ * @param[in] p_loc_speed Location and Speed data to be encoded.
+ * @param[out] p_encoded_buffer Pointer to buffer buffer where encoded data will be written.
+ *
+ * @return Size of encoded data.
+ *
+ */
+static uint8_t loc_speed_encode_packet1(ble_lns_t const * p_lns,
+ ble_lns_loc_speed_t const * p_loc_speed,
+ uint8_t * p_encoded_buffer)
+{
+ uint16_t flags = 0;
+ uint8_t len = 2;
+
+ ble_lncp_mask_t const mask = ble_lncp_mask_get(&p_lns->ctrl_pt);
+
+ // Instantaneous Speed
+ if (p_lns->available_features & BLE_LNS_FEATURE_INSTANT_SPEED_SUPPORTED)
+ {
+ if (p_loc_speed->instant_speed_present && !mask.instantaneous_speed)
+ {
+ flags |= LOC_SPEED_FLAG_INSTANT_SPEED_PRESENT;
+ flags |= ((uint16_t)p_loc_speed->data_format<<9) & LOC_SPEED_FLAG_SPEED_AND_DIST_FORMAT;
+ len += uint16_encode(p_loc_speed->instant_speed, &p_encoded_buffer[len]);
+ }
+ }
+
+ // Total Distance
+ if (p_lns->available_features & BLE_LNS_FEATURE_TOTAL_DISTANCE_SUPPORTED)
+ {
+ if (p_loc_speed->total_distance_present && !mask.total_distance)
+ {
+ uint32_t const total_distance = ble_lncp_total_distance_get(&p_lns->ctrl_pt);
+ flags |= LOC_SPEED_FLAG_TOTAL_DISTANCE_PRESENT;
+ len += uint24_encode(total_distance, &p_encoded_buffer[len]);
+ }
+ }
+
+ // Location
+ if (p_lns->available_features & BLE_LNS_FEATURE_LOCATION_SUPPORTED)
+ {
+ if (p_loc_speed->location_present && !mask.location)
+ {
+ flags |= LOC_SPEED_FLAG_LOCATION_PRESENT;
+ flags |= ((uint16_t)p_loc_speed->position_status <<7) & LOC_SPEED_FLAG_POSITION_STATUS;
+ len += uint32_encode(p_loc_speed->latitude, &p_encoded_buffer[len]);
+ len += uint32_encode(p_loc_speed->longitude, &p_encoded_buffer[len]);
+ }
+ }
+
+ // Flags field
+ uint16_encode(flags, &p_encoded_buffer[0]); //lint !e534 "Ignoring return value of function"
+
+ return len;
+}
+
+
+/**@brief Encode Location and Speed data packet 2
+ *
+ * @param[in] p_lns Location and Navigation Service structure.
+ * @param[in] p_loc_speed Location and Speed data to be encoded.
+ * @param[out] p_encoded_buffer Pointer to buffer buffer where encoded data will be written.
+ *
+ * @return Size of encoded data.
+ *
+ */
+static uint8_t loc_speed_encode_packet2(ble_lns_t const * p_lns,
+ ble_lns_loc_speed_t const * p_loc_speed,
+ uint8_t * p_encoded_buffer)
+{
+ uint16_t flags = 0;
+ uint8_t len = 2;
+
+ ble_lncp_mask_t const mask = ble_lncp_mask_get(&p_lns->ctrl_pt);
+
+ // Elevation
+ if (p_lns->available_features & BLE_LNS_FEATURE_ELEVATION_SUPPORTED)
+ {
+ if (p_loc_speed->elevation_present && !mask.elevation)
+ {
+ uint32_t const elevation = ble_lncp_elevation_get(&p_lns->ctrl_pt);
+
+ flags |= LOC_SPEED_FLAG_ELEVATION_PRESENT;
+ flags |= ((uint16_t) p_loc_speed->elevation_source << 10) & LOC_SPEED_FLAG_ELEVATION_SOURCE;
+ len += uint24_encode(elevation, &p_encoded_buffer[len]);
+ }
+ }
+
+ // Heading
+ if (p_lns->available_features & BLE_LNS_FEATURE_HEADING_SUPPORTED)
+ {
+ if (p_loc_speed->heading_present && !mask.heading)
+ {
+ flags |= LOC_SPEED_FLAG_HEADING_PRESENT;
+ flags |= ((uint16_t) p_loc_speed->heading_source << 12) & LOC_SPEED_FLAG_HEADING_SOURCE;
+ len += uint16_encode(p_loc_speed->heading, &p_encoded_buffer[len]);
+ }
+ }
+
+ // Rolling Time
+ if (p_lns->available_features & BLE_LNS_FEATURE_ROLLING_TIME_SUPPORTED)
+ {
+ if ((p_loc_speed->rolling_time_present && !mask.rolling_time))
+ {
+ flags |= LOC_SPEED_FLAG_ROLLING_TIME_PRESENT;
+ p_encoded_buffer[len++] = p_loc_speed->rolling_time;
+ }
+ }
+
+ // UTC Time
+ if (p_lns->available_features & BLE_LNS_FEATURE_UTC_TIME_SUPPORTED)
+ {
+ if ((p_loc_speed->utc_time_time_present && !mask.utc_time))
+ {
+ flags |= LOC_SPEED_FLAG_UTC_TIME_PRESENT;
+ len += ble_date_time_encode(&p_loc_speed->utc_time, &p_encoded_buffer[len]);
+ }
+ }
+ // Flags field
+ uint16_encode(flags, &p_encoded_buffer[0]); //lint !e534 "Ignoring return value of function"
+
+ return len;
+}
+
+
+/**@brief Encode Navigation data.
+ *
+ * @param[in] p_lns Location and Navigation Service structure.
+ * @param[in] p_navigation Navigation data to be encoded.
+ * @param[out] p_encoded_buffer Buffer where the encoded data will be written.
+ *
+ * @return Size of encoded data.
+ */
+static uint8_t navigation_encode(ble_lns_t const * p_lns,
+ ble_lns_navigation_t const * p_navigation,
+ uint8_t * p_encoded_buffer)
+{
+ uint16_t flags = 0;
+ uint8_t len = 2;
+
+ // Bearing
+ len += uint16_encode(p_navigation->bearing, &p_encoded_buffer[len]);
+
+ // Heading
+ len += uint16_encode(p_navigation->heading, &p_encoded_buffer[len]);
+
+ // Remaining Distance
+ if (p_lns->available_features & BLE_LNS_FEATURE_REMAINING_DISTANCE_SUPPORTED)
+ {
+ if (p_navigation->remaining_dist_present)
+ {
+ flags |= NAV_FLAG_REMAINING_DIST_PRESENT;
+ p_encoded_buffer[len++] = ((p_navigation->remaining_distance >> 0) & 0xFF);
+ p_encoded_buffer[len++] = ((p_navigation->remaining_distance >> 8) & 0xFF);
+ p_encoded_buffer[len++] = ((p_navigation->remaining_distance >> 16) & 0xFF);
+ }
+ }
+
+ // Remaining Vertical Distance
+ if (p_lns->available_features & BLE_LNS_FEATURE_REMAINING_VERT_DISTANCE_SUPPORTED)
+ {
+ if (p_navigation->remaining_vert_dist_present)
+ {
+ flags |= NAV_FLAG_REAMINGING_VERT_DIST_PRESESNT;
+ p_encoded_buffer[len++] = ((p_navigation->remaining_vert_distance >> 0) & 0xFF);
+ p_encoded_buffer[len++] = ((p_navigation->remaining_vert_distance >> 8) & 0xFF);
+ p_encoded_buffer[len++] = ((p_navigation->remaining_vert_distance >> 16) & 0xFF);
+ }
+ }
+
+ // Estimated Time of Arrival
+ if (p_lns->available_features & BLE_LNS_FEATURE_EST_TIME_OF_ARRIVAL_SUPPORTED)
+ {
+ if (p_navigation->eta_present)
+ {
+ flags |= NAV_FLAG_ETA_PRESENT;
+ len += ble_date_time_encode(&p_navigation->eta, &p_encoded_buffer[len]);
+ }
+ }
+
+ flags |= ((uint16_t)p_navigation->position_status <<3) & NAV_FLAG_POSITION_STATUS;
+ flags |= ((uint16_t)p_navigation->heading_source <<5) & NAV_FLAG_HEADING_SOURCE;
+ flags |= ((uint16_t)p_navigation->navigation_indicator_type<<6)& NAV_FLAG_NAVIGATION_INDICATOR_TYPE;
+ flags |= ((uint16_t)p_navigation->waypoint_reached <<7)& NAV_FLAG_WAYPOINT_REACHED;
+ flags |= ((uint16_t)p_navigation->destination_reached <<8)& NAV_FLAG_DESTINATION_REACHED;
+
+ // Flags field
+ uint16_encode(flags, &p_encoded_buffer[0]); //lint !e534 "Ignoring return value of function"
+
+ return len;
+}
+
+
+/**@brief Add Location and Navigation Feature characteristic.
+ *
+ * @param[in] p_lns Location and Navigation Service structure.
+ * @param[in] p_lns_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static ret_code_t loc_and_nav_feature_char_add(ble_lns_t * p_lns, ble_lns_init_t const * p_lns_init)
+{
+ uint8_t init_value_encoded[sizeof(uint32_t)];
+ uint8_t len;
+ ble_add_char_params_t add_char_params;
+
+ len = uint32_encode(p_lns_init->available_features, init_value_encoded);
+
+ memset(&add_char_params, 0, sizeof(add_char_params));
+
+ add_char_params.uuid = BLE_UUID_LN_FEATURE_CHAR;
+ add_char_params.max_len = len;
+ add_char_params.init_len = len;
+ add_char_params.p_init_value = &init_value_encoded[0];
+ add_char_params.char_props.read = true;
+ add_char_params.read_access = p_lns_init->loc_nav_feature_security_req_read_perm;
+
+ return characteristic_add(p_lns->service_handle,
+ &add_char_params,
+ &p_lns->feature_handles);
+}
+
+
+/**@brief Add Location and Speed characteristic.
+ *
+ * @param[in] p_lns Location and Navigation Service structure.
+ * @param[in] p_lns_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static ret_code_t loc_speed_char_add(ble_lns_t * p_lns, ble_lns_init_t const * p_lns_init)
+{
+ uint8_t encoded_initial_loc_speed1[BLE_GATT_ATT_MTU_DEFAULT];
+ uint8_t len;
+ ble_add_char_params_t add_char_params;
+
+ len = loc_speed_encode_packet1(p_lns, p_lns_init->p_location_speed, &encoded_initial_loc_speed1[0]);
+
+ memset(&add_char_params, 0, sizeof(add_char_params));
+
+ add_char_params.uuid = BLE_UUID_LN_LOCATION_AND_SPEED_CHAR;
+ add_char_params.max_len = BLE_GATT_ATT_MTU_DEFAULT ;
+ add_char_params.init_len = len;
+ add_char_params.p_init_value = &encoded_initial_loc_speed1[0];
+ add_char_params.is_var_len = true;
+ add_char_params.char_props.notify = true;
+ add_char_params.cccd_write_access = p_lns_init->loc_speed_security_req_cccd_write_perm;
+
+ return characteristic_add(p_lns->service_handle,
+ &add_char_params,
+ &p_lns->loc_speed_handles);
+}
+
+
+/**@brief Add Location and Navigation position quality characteristic.
+ *
+ * @param[in] p_lns Location and Navigation Service structure.
+ * @param[in] p_lns_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static ret_code_t pos_quality_char_add(ble_lns_t * p_lns, ble_lns_init_t const * p_lns_init)
+{
+ uint8_t len;
+ uint8_t init_value_encoded[BLE_GATT_ATT_MTU_DEFAULT];
+ ble_add_char_params_t add_char_params;
+
+ len = pos_qual_encode(p_lns, p_lns_init->p_position_quality, init_value_encoded);
+
+ memset(&add_char_params, 0, sizeof(add_char_params));
+
+ add_char_params.uuid = BLE_UUID_LN_POSITION_QUALITY_CHAR;
+ add_char_params.max_len = BLE_GATT_ATT_MTU_DEFAULT ;
+ add_char_params.init_len = len;
+ add_char_params.p_init_value = init_value_encoded;
+ add_char_params.char_props.read = true;
+ add_char_params.read_access = p_lns_init->position_quality_security_req_read_perm;
+
+ return characteristic_add(p_lns->service_handle,
+ &add_char_params,
+ &p_lns->pos_qual_handles);
+}
+
+
+/**@brief Add Navigation characteristic.
+ *
+ * @param[in] p_lns Location and Navigation Service structure.
+ * @param[in] p_lns_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static ret_code_t navigation_char_add(ble_lns_t * p_lns, ble_lns_init_t const * p_lns_init)
+{
+ ble_add_char_params_t add_char_params;
+
+ memset(&add_char_params, 0, sizeof(add_char_params));
+
+ add_char_params.uuid = BLE_UUID_LN_NAVIGATION_CHAR;
+ add_char_params.max_len = BLE_LNS_NAV_MAX_LEN;
+ add_char_params.init_len = 0;
+ add_char_params.p_init_value = NULL;
+ add_char_params.char_props.notify = true;
+ add_char_params.cccd_write_access = p_lns_init->navigation_security_req_cccd_write_perm;
+
+ return characteristic_add(p_lns->service_handle,
+ &add_char_params,
+ &p_lns->navigation_handles);
+}
+
+
+/** @brief Check if there is a mismatch in initialization parameters.
+ *
+ * @details It is possible to give an input which has an internal mismatch. Such a mismatch can arise in two different ways.
+ * One possibility is a mismatch between the characteristic present indicators and the available features specified.
+ * The other mismatch arises when no pointer to the characteristic data structure is specified.
+ *
+ * @param[in] p_lns_init The init structure which will be checked
+ *
+ * @return false if there is no mismatch. true if there is a mismatch
+ */
+static bool init_param_mismatch_present(ble_lns_init_t const * p_lns_init)
+{
+ if (p_lns_init->is_position_quality_present == false)
+ {
+ if (p_lns_init->available_features &
+ (BLE_LNS_FEATURE_NUM_SATS_IN_SOLUTION_SUPPORTED |
+ BLE_LNS_FEATURE_NUM_SATS_IN_VIEW_SUPPORTED |
+ BLE_LNS_FEATURE_TIME_TO_FIRST_FIX_SUPPORTED |
+ BLE_LNS_FEATURE_EST_HORZ_POS_ERROR_SUPPORTED |
+ BLE_LNS_FEATURE_EST_VERT_POS_ERROR_SUPPORTED |
+ BLE_LNS_FEATURE_HORZ_DILUTION_OF_PRECISION_SUPPORTED |
+ BLE_LNS_FEATURE_VERT_DILUTION_OF_PRECISION_SUPPORTED)
+ )
+ {
+ return true;
+ }
+ if (p_lns_init->p_position_quality != NULL)
+ {
+ return true;
+ }
+ }
+ else if (p_lns_init->is_position_quality_present == true)
+ {
+ if (p_lns_init->p_position_quality == NULL)
+ {
+ return true;
+ }
+ }
+
+ if (p_lns_init->is_control_point_present == false)
+ {
+ if (p_lns_init->available_features &
+ (BLE_LNS_FEATURE_LOC_AND_SPEED_CONTENT_MASKING_SUPPORTED |
+ BLE_LNS_FEATURE_FIX_RATE_SETTING_SUPPORTED |
+ BLE_LNS_FEATURE_ELEVATION_SETTING_SUPPORTED)
+ )
+ {
+ return true;
+ }
+ }
+
+ if (p_lns_init->is_navigation_present == false)
+ {
+ if (p_lns_init->available_features &
+ (BLE_LNS_FEATURE_REMAINING_DISTANCE_SUPPORTED |
+ BLE_LNS_FEATURE_REMAINING_VERT_DISTANCE_SUPPORTED |
+ BLE_LNS_FEATURE_EST_TIME_OF_ARRIVAL_SUPPORTED)
+ )
+ {
+ return true;
+ }
+ if (p_lns_init->p_navigation != NULL)
+ {
+ return true;
+ }
+ }
+ else if (p_lns_init->is_navigation_present == true)
+ {
+ if (p_lns_init->p_navigation == NULL)
+ {
+ return true;
+ }
+ }
+
+ // location and speed must always be specified
+ if (p_lns_init->p_location_speed == NULL)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+
+void ble_lns_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ VERIFY_PARAM_NOT_NULL_VOID(p_context);
+ VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
+
+ ble_lns_t * p_lns = (ble_lns_t *)p_context;
+ ble_lncp_on_ble_evt(&p_lns->ctrl_pt, p_ble_evt);
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ on_connect(p_lns, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnect(p_lns, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_WRITE:
+ on_write(p_lns, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_HVN_TX_COMPLETE:
+ on_tx_complete(p_lns);
+ break;
+
+ default:
+ // no implementation
+ break;
+ }
+}
+
+
+ret_code_t ble_lns_init(ble_lns_t * p_lns, ble_lns_init_t const * p_lns_init)
+{
+ VERIFY_PARAM_NOT_NULL(p_lns);
+ VERIFY_PARAM_NOT_NULL(p_lns_init);
+
+ if (init_param_mismatch_present(p_lns_init) == true)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ uint32_t err_code;
+ ble_uuid_t service_uuid;
+ ble_lncp_init_t lncp_init;
+
+ // Initialize service structure
+ p_lns->evt_handler = p_lns_init->evt_handler;
+ p_lns->error_handler = p_lns_init->error_handler;
+ p_lns->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_lns->available_features = p_lns_init->available_features;
+ p_lns->is_navigation_present = p_lns_init->is_navigation_present;
+
+ // clear pending notifications
+ p_lns->pending_loc_speed_notifications[0].is_pending = false;
+ p_lns->pending_loc_speed_notifications[1].is_pending = false;
+ p_lns->pending_navigation_notification.is_pending = false;
+
+ p_lns->p_location_speed = p_lns_init->p_location_speed;
+ p_lns->p_position_quality = p_lns_init->p_position_quality;
+ p_lns->p_navigation = p_lns_init->p_navigation;
+
+ p_lns->is_loc_speed_notification_enabled = false;
+ p_lns->is_nav_notification_enabled = false;
+
+ ble_ln_db_init();
+
+ // Add service
+ BLE_UUID_BLE_ASSIGN(service_uuid, BLE_UUID_LOCATION_AND_NAVIGATION_SERVICE);
+
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &service_uuid, &p_lns->service_handle);
+ VERIFY_SUCCESS(err_code);
+
+ // Add location and navigation feature characteristic
+ err_code = loc_and_nav_feature_char_add(p_lns, p_lns_init);
+ VERIFY_SUCCESS(err_code);
+
+ // Add location and speed characteristic
+ err_code = loc_speed_char_add(p_lns, p_lns_init);
+ VERIFY_SUCCESS(err_code);
+
+ if (p_lns_init->is_position_quality_present)
+ {
+ // Add Position quality characteristic
+ err_code = pos_quality_char_add(p_lns, p_lns_init);
+ VERIFY_SUCCESS(err_code);
+ }
+ else
+ {
+ p_lns->pos_qual_handles.cccd_handle = BLE_GATT_HANDLE_INVALID;
+ p_lns->pos_qual_handles.sccd_handle = BLE_GATT_HANDLE_INVALID;
+ p_lns->pos_qual_handles.user_desc_handle = BLE_GATT_HANDLE_INVALID;
+ p_lns->pos_qual_handles.value_handle = BLE_GATT_HANDLE_INVALID;
+ }
+
+ if (p_lns_init->is_navigation_present)
+ {
+ // Add navigation characteristic
+ err_code = navigation_char_add(p_lns, p_lns_init);
+ VERIFY_SUCCESS(err_code);
+ }
+ else
+ {
+ p_lns->navigation_handles.cccd_handle = BLE_GATT_HANDLE_INVALID;
+ p_lns->navigation_handles.sccd_handle = BLE_GATT_HANDLE_INVALID;
+ p_lns->navigation_handles.user_desc_handle = BLE_GATT_HANDLE_INVALID;
+ p_lns->navigation_handles.value_handle = BLE_GATT_HANDLE_INVALID;
+ }
+
+ if (p_lns_init->is_control_point_present)
+ {
+ lncp_init.error_handler = p_lns_init->error_handler;
+ lncp_init.evt_handler = p_lns_init->lncp_evt_handler;
+ lncp_init.write_perm = p_lns_init->ctrl_point_security_req_write_perm;
+ lncp_init.cccd_write_perm = p_lns_init->ctrl_point_security_req_cccd_write_perm;
+ lncp_init.available_features = p_lns_init->available_features;
+ lncp_init.is_position_quality_present = p_lns_init->is_position_quality_present;
+ lncp_init.is_navigation_present = p_lns_init->is_navigation_present;
+
+ lncp_init.total_distance = p_lns_init->p_location_speed->total_distance;
+ lncp_init.elevation = p_lns_init->p_location_speed->elevation;
+
+ lncp_init.service_handle = p_lns->service_handle;
+ lncp_init.navigation_handles = p_lns->navigation_handles;
+
+ // Add control pointer characteristic
+ err_code = ble_lncp_init(&p_lns->ctrl_pt, &lncp_init);
+ VERIFY_SUCCESS(err_code);
+
+ memcpy(&p_lns->ctrlpt_handles, &p_lns->ctrl_pt.ctrlpt_handles, sizeof(ble_gatts_char_handles_t));
+ }
+
+ NRF_LOG_DEBUG("Initialized");
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t ble_lns_loc_speed_send(ble_lns_t * p_lns)
+{
+ VERIFY_PARAM_NOT_NULL(p_lns);
+
+ if (p_lns->conn_handle == BLE_CONN_HANDLE_INVALID)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ if (!p_lns->is_loc_speed_notification_enabled)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ notification_t * notif1 = &p_lns->pending_loc_speed_notifications[0];
+ notification_t * notif2 = &p_lns->pending_loc_speed_notifications[1];
+
+ // clear previous unsent data. Previous data is invalid.
+ notif1->is_pending = false;
+ notif2->is_pending = false;
+
+ // check if it is necessary to send packet 1
+ if (p_lns->available_features & (BLE_LNS_FEATURE_INSTANT_SPEED_SUPPORTED
+ | BLE_LNS_FEATURE_TOTAL_DISTANCE_SUPPORTED
+ | BLE_LNS_FEATURE_LOCATION_SUPPORTED))
+ {
+ // encode
+ notif1->len = loc_speed_encode_packet1(p_lns, p_lns->p_location_speed, &notif1->data[0]);
+ notif1->handle = p_lns->loc_speed_handles.value_handle;
+ notif1->is_pending = true;
+
+ // send
+ notification_buffer_process(p_lns);
+ }
+
+ // check if it is necessary to send packet 2
+ if (p_lns->available_features & (BLE_LNS_FEATURE_ELEVATION_SUPPORTED
+ | BLE_LNS_FEATURE_HEADING_SUPPORTED
+ | BLE_LNS_FEATURE_ROLLING_TIME_SUPPORTED
+ | BLE_LNS_FEATURE_UTC_TIME_SUPPORTED))
+ {
+ notif2->len = loc_speed_encode_packet2(p_lns, p_lns->p_location_speed, &notif2->data[0]);
+ notif2->handle = p_lns->loc_speed_handles.value_handle;
+ notif2->is_pending = true;
+
+ // send
+ notification_buffer_process(p_lns);
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t ble_lns_navigation_send(ble_lns_t * p_lns)
+{
+ VERIFY_PARAM_NOT_NULL(p_lns);
+
+ if (p_lns->conn_handle == BLE_CONN_HANDLE_INVALID)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ notification_t * notif = &p_lns->pending_navigation_notification;
+
+ // clear previous unsent data. Previous data is invalid.
+ notif->is_pending = false;
+
+ if (!p_lns->is_navigation_present)
+ {
+ return NRF_ERROR_NOT_SUPPORTED;
+ }
+
+ if (!p_lns->is_nav_notification_enabled)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ if (!ble_lncp_is_navigation_running(&p_lns->ctrl_pt))
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ notif->len = navigation_encode(p_lns, p_lns->p_navigation, &notif->data[0]);
+ notif->handle = p_lns->navigation_handles.value_handle;
+ notif->is_pending = true;
+
+ notification_buffer_process(p_lns);
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t ble_lns_add_route(ble_lns_t * p_lns, ble_lns_route_t * p_route)
+{
+ VERIFY_PARAM_NOT_NULL(p_lns);
+ VERIFY_PARAM_NOT_NULL(p_route);
+
+ if (p_lns->is_navigation_present == false)
+ {
+ return NRF_ERROR_NOT_SUPPORTED;
+ }
+
+ return ble_ln_db_record_add(p_route);
+}
+
+
+ret_code_t ble_lns_remove_route(ble_lns_t * p_lns, uint16_t route_id)
+{
+ VERIFY_PARAM_NOT_NULL(p_lns);
+
+ if (p_lns->is_navigation_present == false)
+ {
+ return NRF_ERROR_NOT_SUPPORTED;
+ }
+
+ return ble_ln_db_record_delete(route_id);
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_lns.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_lns.h
new file mode 100644
index 0000000..28a9223
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_lns/ble_lns.h
@@ -0,0 +1,381 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_lns Location and Navigation Service
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Location and Navigation Service module.
+ *
+ * @details This module implements the Location and Navigation Service with the Location and Speed, Position
+ * Quality, Feature, Control Point, and Navigation characteristics.
+ *
+ * If an event handler is supplied by the application, the Location and Navigation Service will
+ * generate Location and Navigation Service events to the application.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_lns_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_LNS_BLE_OBSERVER_PRIO,
+ * ble_lns_on_ble_evt, &instance);
+ * @endcode
+ */
+
+#ifndef BLE_LNS_H__
+#define BLE_LNS_H__
+
+#include "ble_srv_common.h"
+#include "ble_date_time.h"
+#include "ble_ln_common.h"
+#include "ble_ln_cp.h"
+#include "sdk_common.h"
+#include "nrf_sdh_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@ Macro for defining a ble_lns instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_LNS_DEF(_name) \
+static ble_lns_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ BLE_LNS_BLE_OBSERVER_PRIO, \
+ ble_lns_on_ble_evt, &_name)
+
+
+/**@brief Location and Navigation event type. This list defines the possible events types from the Location and Navigation Service. */
+typedef enum
+{
+ BLE_LNS_CTRLPT_EVT_INDICATION_ENABLED, /**< Control Point value indication was enabled. */
+ BLE_LNS_CTRLPT_EVT_INDICATION_DISABLED, /**< Control Point value indication was disabled. */
+ BLE_LNS_LOC_SPEED_EVT_NOTIFICATION_ENABLED, /**< Location and Speed value notification was enabled. */
+ BLE_LNS_LOC_SPEED_EVT_NOTIFICATION_DISABLED, /**< Location and Speed value notification was disabled. */
+ BLE_LNS_NAVIGATION_EVT_NOTIFICATION_ENABLED, /**< Navigation value notification was enabled. */
+ BLE_LNS_NAVIGATION_EVT_NOTIFICATION_DISABLED, /**< Navigation value notification was disabled. */
+} ble_lns_evt_type_t;
+
+/**@brief Location and Navigation event structure. When an event occurs, the data structures of the module are automatically updated. */
+typedef struct
+{
+ ble_lns_evt_type_t evt_type;
+} ble_lns_evt_t;
+
+// Forward declarations of the ble_lns types.
+typedef struct ble_lns_init_s ble_lns_init_t;
+typedef struct ble_lns_s ble_lns_t;
+typedef struct ble_lns_loc_speed_s ble_lns_loc_speed_t;
+typedef struct ble_lns_pos_quality_s ble_lns_pos_quality_t;
+typedef struct ble_lns_navigation_s ble_lns_navigation_t;
+
+
+typedef struct
+{
+ bool is_pending;
+ uint16_t handle;
+ uint16_t len;
+ uint8_t data[BLE_GATT_ATT_MTU_DEFAULT];
+} notification_t;
+
+
+/**@brief Location and Navigation Service event handler type. */
+typedef void (*ble_lns_evt_handler_t) (ble_lns_t const * p_lns, ble_lns_evt_t const * p_evt);
+
+
+/**@brief Location and Navigation Service init structure. This structure contains all options
+ * and data needed to initialize the service.
+ */
+struct ble_lns_init_s
+{
+ ble_lns_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Location and Navigation Service. */
+ ble_lncp_evt_handler_t lncp_evt_handler;
+ ble_srv_error_handler_t error_handler; /**< Errors will be sent back to this function. */
+
+ bool is_position_quality_present; /**< If set to true, the position quality characteristic will be added. Else not. */
+ bool is_control_point_present; /**< If set to true, the control point characteristic will be added. Else not. */
+ bool is_navigation_present; /**< If set to true, the navigation characteristic will be added. Else not. */
+
+ security_req_t loc_nav_feature_security_req_read_perm; /**< Read security level of the LN Feature characteristic. */
+ security_req_t loc_speed_security_req_cccd_write_perm; /**< CCCD write security level of the Write Location and Speed characteristic. */
+ security_req_t position_quality_security_req_read_perm; /**< Read security level of the Position Quality characteristic. */
+ security_req_t navigation_security_req_cccd_write_perm; /**< CCCD write security level of the Navigation characteristic. */
+ security_req_t ctrl_point_security_req_write_perm; /**< Read security level of the LN Control Point characteristic. */
+ security_req_t ctrl_point_security_req_cccd_write_perm; /**< CCCD write security level of the LN Control Point characteristic. */
+
+ uint32_t available_features; /**< Value of the LN feature. */
+ ble_lns_loc_speed_t * p_location_speed; /**< Initial Location and Speed. */
+ ble_lns_pos_quality_t * p_position_quality; /**< Initial Position Quality. */
+ ble_lns_navigation_t * p_navigation; /**< Initial Navigation data structure. */
+};
+
+/**@brief Definition of a navigation route.*/
+typedef struct
+{
+ uint16_t route_id;
+ uint8_t route_name[BLE_LNS_MAX_ROUTE_NAME_LEN];
+} ble_lns_route_t;
+
+/**@brief Location and Navigation Service structure. This structure contains various status information for the service. */
+struct ble_lns_s
+{
+ ble_lns_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Location and Navigation Service. */
+ ble_srv_error_handler_t error_handler; /**< Error handler. */
+
+ bool is_navigation_present; /**< If set to true, the navigation characteristic is present. Else not. */
+
+ uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack; BLE_CONN_HANDLE_INVALID if not in a connection). */
+ uint16_t service_handle; /**< Handle of Location and Navigation Service (as provided by the BLE stack). */
+ ble_gatts_char_handles_t loc_speed_handles; /**< Handles related to the Location and Speed characteristic. */
+ ble_gatts_char_handles_t feature_handles; /**< Handles related to the Location and Navigation Feature characteristic. */
+ ble_gatts_char_handles_t navigation_handles; /**< Handles related to the Navigation characteristic. */
+ ble_gatts_char_handles_t pos_qual_handles; /**< Handles related to the Position Quality characteristic. */
+ ble_gatts_char_handles_t ctrlpt_handles;
+ uint32_t available_features; /**< Value of Location and Navigation feature. */
+
+ bool is_loc_speed_notification_enabled; /**< True if notification is enabled on the Location and Speed characteristic. */
+ bool is_nav_notification_enabled; /**< True if notification is enabled on the Navigation characteristic. */
+
+ notification_t pending_loc_speed_notifications[2]; /**< This buffer holds location and speed notifications. */
+ notification_t pending_navigation_notification; /**< This buffer holds navigation notifications. */
+ ble_lns_loc_speed_t * p_location_speed; /**< Location and Speed. */
+ ble_lns_pos_quality_t * p_position_quality; /**< Position measurement quality. */
+ ble_lns_navigation_t * p_navigation; /**< Navigation data structure. */
+ ble_lncp_t ctrl_pt;
+};
+
+/**@brief Position status. This enumeration defines how to interpret the position data. */
+typedef enum
+{
+ BLE_LNS_NO_POSITION = 0,
+ BLE_LNS_POSITION_OK = 1,
+ BLE_LNS_ESTIMATED = 2,
+ BLE_LNS_LAST_KNOWN_POSITION = 3
+} ble_lns_pos_status_type_t;
+
+/**@brief The format of the position and speed measurements. */
+typedef enum
+{
+ BLE_LNS_SPEED_DISTANCE_FORMAT_2D = 0,
+ BLE_LNS_SPEED_DISTANCE_FORMAT_3D = 1
+} ble_lns_speed_distance_format_t;
+
+/**@brief Elevation source. */
+typedef enum
+{
+ BLE_LNS_ELEV_SOURCE_POSITIONING_SYSTEM = 0,
+ BLE_LNS_ELEV_SOURCE_BAROMETRIC = 1,
+ BLE_LNS_ELEV_SOURCE_DATABASE_SERVICE = 2,
+ BLE_LNS_ELEV_SOURCE_OTHER = 3
+} ble_lns_elevation_source_t;
+
+/**@brief Heading source. */
+typedef enum
+{
+ BLE_LNS_HEADING_SOURCE_MOVEMENT = 0,
+ BLE_LNS_HEADING_SOURCE_COMPASS = 1
+} ble_lns_heading_source_t;
+
+/**@brief Location and Speed data structure. */
+struct ble_lns_loc_speed_s
+{
+ bool instant_speed_present; /**< Instantaneous Speed present (0=not present, 1=present). */
+ bool total_distance_present; /**< Total Distance present (0=not present, 1=present). */
+ bool location_present; /**< Location present (0=not present, 1=present). */
+ bool elevation_present; /**< Elevation present (0=not present, 1=present). */
+ bool heading_present; /**< Heading present (0=not present, 1=present). */
+ bool rolling_time_present; /**< Rolling Time present (0=not present, 1=present). */
+ bool utc_time_time_present; /**< UTC Time present (0=not present, 1=present). */
+ ble_lns_pos_status_type_t position_status; /**< Status of current position */
+ ble_lns_speed_distance_format_t data_format; /**< Format of data (either 2D or 3D). */
+ ble_lns_elevation_source_t elevation_source; /**< Source of the elevation measurement. */
+ ble_lns_heading_source_t heading_source; /**< Source of the heading measurement. */
+ uint16_t instant_speed; /**< Instantaneous Speed (1/10 meter per sec). */
+ uint32_t total_distance; /**< Total Distance (meters), size=24 bits. */
+ int32_t latitude; /**< Latitude (10e-7 degrees). */
+ int32_t longitude; /**< Longitude (10e-7 degrees). */
+ int32_t elevation; /**< Elevation (1/100 meters), size=24 bits. */
+ uint16_t heading; /**< Heading (1/100 degrees). */
+ uint8_t rolling_time; /**< Rolling Time (seconds). */
+ ble_date_time_t utc_time; /**< UTC Time. */
+};
+
+/**@brief Position quality structure. */
+struct ble_lns_pos_quality_s
+{
+ bool number_of_satellites_in_solution_present; /**< The number of satellites present in solution (0=not present, 1=present). */
+ bool number_of_satellites_in_view_present; /**< The number of satellites present in solution (0=not present, 1=present). */
+ bool time_to_first_fix_present; /**< Time to the first position fix present (0=not present, 1=present). */
+ bool ehpe_present; /**< Error in horizontal position estimate present (0=not present, 1=present). */
+ bool evpe_present; /**< Error in vertical position estimate present (0=not present, 1=present). */
+ bool hdop_present; /**< Horizontal dilution of precision present (0=not present, 1=present). */
+ bool vdop_present; /**< Vertical dilution of precision present (0=not present, 1=present). */
+ ble_lns_pos_status_type_t position_status; /**< Status of last measured position. */
+ uint8_t number_of_satellites_in_solution; /**< The number of satellites in solution (unitless, with a resolution of 1). */
+ uint8_t number_of_satellites_in_view; /**< The number of satellites in view (unitless, with a resolution of 1). */
+ uint16_t time_to_first_fix; /**< Time to the first position fix (seconds, with a resolution of 1/10). */
+ uint32_t ehpe; /**< Error in horizontal position estimate (meters, with a resolution of 1/100). */
+ uint32_t evpe; /**< Error in vertical position estimate (meters, with a resolution of 1/100). */
+ uint8_t hdop; /**< Horizontal dilution of precision (unitless, with a resolution of 2/10). */
+ uint8_t vdop; /**< Vertical dilution of precision (unitless, with a resolution of 2/10). */
+};
+
+/**@brief Navigation indicator type. */
+typedef enum
+{
+ BLE_LNS_NAV_TO_WAYPOINT = 0,
+ BLE_LNS_NAV_TO_DESTINATION = 1
+} ble_lns_nav_indicator_type_t;
+
+/**@brief Navigation data structure. */
+struct ble_lns_navigation_s
+{
+ bool remaining_dist_present; /**< Remaining Distance present (0=not present, 1=present). */
+ bool remaining_vert_dist_present; /**< Remaining Vertical Distance present (0=not present, 1=present). */
+ bool eta_present; /**< Estimated Time of Arrival present (0=not present, 1=present). */
+ ble_lns_pos_status_type_t position_status; /**< Status of last measured position. */
+ ble_lns_heading_source_t heading_source; /**< Source of the heading measurement. */
+ ble_lns_nav_indicator_type_t navigation_indicator_type; /**< Navigation indicator type. */
+ bool waypoint_reached; /**< Waypoint Reached (0=not reached, 1=reached). */
+ bool destination_reached; /**< Destination Reached (0=not reached, 1=reached). */
+ uint16_t bearing; /**< Bearing (1/100 degrees).*/
+ uint16_t heading; /**< Heading (1/100 degrees), size=24 bit. */
+ uint32_t remaining_distance; /**< Remaining Distance (1/10 meters), size=24 bit. */
+ int32_t remaining_vert_distance; /**< Remaining Vertical Distance (1/100 meters), size=24 bit. */
+ ble_date_time_t eta; /**< Estimated Time of Arrival. */
+};
+
+
+/**@brief Function for initializing the Location and Navigation Service.
+ *
+ * @param[out] p_lns Location and Navigation Service structure. This structure must be supplied by
+ * the application. It is initialized by this function, and will later
+ * be used to identify this particular service instance.
+ * @param[in] p_lns_init Information needed to initialize the service.
+ *
+ * @retval NRF_SUCCESS If the service was initialized successfully.
+ * @retval NRF_ERROR_NULL If a NULL parameter was provided.
+ * @retval NRF_INVALID_PARAMS If there is an inconsistency in the initialization structure.
+ * @return Otherwise, an error code from either sd_ble_gatts_service_add() or sd_ble_gatts_characteristic_add() is returned.
+ */
+ret_code_t ble_lns_init(ble_lns_t * p_lns, ble_lns_init_t const * p_lns_init);
+
+
+/**@brief Function for handling Location and Navigation Service BLE stack events.
+ *
+ * @details This function handles all events from the BLE stack that are of interest to the
+ * Location and Navigation Service.
+ *
+ * @note The function returns when a NULL parameter is provided.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Location and Navigation Service structure.
+ */
+void ble_lns_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for sending location and speed data if notification has been enabled.
+ *
+ * @details The application calls this function after having performed a location and speed determination.
+ * If notification has been enabled, the location and speed data is encoded and sent to
+ * the client.
+ *
+ * @param[in] p_lns Location and Navigation Service structure holding the location and speed data.
+ *
+ * @retval NRF_SUCCESS If the data was sent successfully.
+ * @retval NRF_ERROR_NULL If a NULL parameter was provided.
+ * @retval NRF_ERROR_INVALID_STATE If notification is disabled.
+ */
+ret_code_t ble_lns_loc_speed_send(ble_lns_t * p_lns);
+
+
+/**@brief Function for sending navigation data if notification has been enabled.
+ *
+ * @details The application calls this function after having performed a navigation determination.
+ * If notification has been enabled, the navigation data is encoded and sent to
+ * the client.
+ *
+ * @param[in] p_lns Location and Navigation Service structure holding the navigation data.
+ *
+ * @retval NRF_SUCCESS If the data was sent successfully.
+ * @retval NRF_ERROR_NULL If a NULL parameter was provided.
+ * @retval NRF_ERROR_NOT_SUPPORTED If the navigation characteristic is absent.
+ * @retval NRF_ERROR_INVALID_STATE If navigation is not running or notification is disabled.
+ */
+ret_code_t ble_lns_navigation_send(ble_lns_t * p_lns);
+
+
+/**@brief Function for adding a route to the Location and Navigation Service.
+ *
+ * @param[in] p_lns Location and Navigation Service structure.
+ * @param[in,out] p_route The new route to be added. The route ID is updated.
+ *
+ * @retval NRF_SUCCESS If the route was added successfully.
+ * @retval NRF_ERROR_NULL If a NULL parameter was provided.
+ * @retval NRF_ERROR_NOT_SUPPORTED If the navigation characteristic is absent.
+ * @retval NRF_ERROR_NO_MEM If there is no memory left.
+ * @retval NRF_ERROR_INTERNAL If there is an inconsistency in the routes table.
+ */
+ret_code_t ble_lns_add_route(ble_lns_t * p_lns, ble_lns_route_t * p_route);
+
+
+/**@brief Function for removing a route from the Location and Navigation Service.
+ *
+ * @param[in] p_lns Location and Navigation Service structure.
+ * @param[in] route_id The ID of the route to be removed.
+ *
+ * @retval NRF_SUCCESS If the route was removed successfully.
+ * @retval NRF_ERROR_NULL If a NULL parameter was provided.
+ * @retval NRF_ERROR_NOT_SUPPORTED If the navigation characteristic is absent.
+ * @retval NRF_INVALID_PARAM If the route ID does not exist.
+ */
+ret_code_t ble_lns_remove_route(ble_lns_t * p_lns, uint16_t route_id);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_LNS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_hvx_buffering.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_hvx_buffering.c
new file mode 100644
index 0000000..80b3afc
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_hvx_buffering.c
@@ -0,0 +1,102 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "ble_hvx_buffering.h"
+#include <string.h>
+
+uint32_t ble_hvx_init(ble_hvx_buf_t * p_ble_hvx_buf)
+{
+ if (p_ble_hvx_buf == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ p_ble_hvx_buf->insert_index = 0;
+ p_ble_hvx_buf->read_index = 0;
+
+ return NRF_SUCCESS;
+}
+
+ble_hvx_t * ble_hvx_get_p_to_next_hvx(ble_hvx_buf_t * p_ble_hvx_buf)
+{
+ ble_hvx_t * p_hvx;
+ p_hvx = &p_ble_hvx_buf->buf[p_ble_hvx_buf->insert_index++];
+
+ p_hvx->params.p_data = p_hvx->data;
+ p_hvx->params.p_len = &p_hvx->data_len;
+
+ p_ble_hvx_buf->insert_index &= BLE_HVX_BUF_MASK;
+ return p_hvx;
+}
+
+
+uint32_t ble_hvx_buffer_process(ble_hvx_buf_t * p_ble_hvx_buf)
+{
+ uint32_t err_code;
+ while (p_ble_hvx_buf->read_index != p_ble_hvx_buf->insert_index)
+ {
+
+ ble_gatts_hvx_params_t * p_hvx_params;
+
+ p_hvx_params = &p_ble_hvx_buf->buf[p_ble_hvx_buf->read_index].params;
+ err_code = sd_ble_gatts_hvx(p_ble_hvx_buf->buf[p_ble_hvx_buf->read_index].conn_handle, p_hvx_params);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ p_ble_hvx_buf->read_index++;
+ p_ble_hvx_buf->read_index &= BLE_HVX_BUF_MASK;
+ }
+ else
+ {
+ if (err_code == NRF_ERROR_BUSY || err_code == NRF_ERROR_RESOURCES)
+ {
+ return NRF_SUCCESS; // not a critical error.
+ }
+ else
+ {
+ // remove element from buffer
+ p_ble_hvx_buf->insert_index--;
+ p_ble_hvx_buf->insert_index &= BLE_HVX_BUF_MASK;
+ return err_code;
+ }
+ }
+ }
+ return NRF_SUCCESS;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_hvx_buffering.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_hvx_buffering.h
new file mode 100644
index 0000000..005e123
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_hvx_buffering.h
@@ -0,0 +1,104 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/**@file
+ *
+ * @defgroup ble_sdk_srv_ots_buf Object Transfer Service, HVX buffering
+ * @{
+ * @ingroup ble_ots
+ * @brief Object Transfer Service module
+ *
+ * @details This module is responsible for buffering indications and notifications.
+ */
+
+#ifndef BLE_HVX_BUFFERING_H__
+#define BLE_HVX_BUFFERING_H__
+
+
+#include <stdint.h>
+#include "ble_types.h"
+#include "ble_gatts.h"
+
+#define BLE_HVX_BUF_LEN (1 << 3) // 8
+#define BLE_HVX_BUF_MASK (BLE_HVX_BUF_LEN-1)
+
+/**@brief ble_hvx_t represents one notification/indication. */
+typedef struct {
+ uint16_t conn_handle; /**< The associated connection handle. */
+ uint8_t data[BLE_GATT_ATT_MTU_DEFAULT]; /**< The hvx data. */
+ uint16_t data_len;
+ ble_gatts_hvx_params_t params; /**< Parameters of the hvx. */
+} ble_hvx_t;
+
+/**@brief ble_hvx_buf_t is the structure holding the state of the hvx buffering module. */
+typedef struct {
+ ble_hvx_t buf[BLE_HVX_BUF_LEN]; /**< A buffer of nofications/indications. */
+
+ uint8_t insert_index;
+ uint8_t read_index;
+} ble_hvx_buf_t;
+
+/**@brief Function for initializing the HVX buffer module.
+ *
+ * @param[out] p_ble_hvx_buf HVX buffering structure.
+ * @return NRF_SUCCESS If the given paramer is valid.
+ */
+uint32_t ble_hvx_init(ble_hvx_buf_t * p_ble_hvx_buf);
+
+/**@brief Function for obtaining the pointer to the next hvx. The user can then fill out the hvx structure.
+ *
+ * @param[in] p_ble_hvx_buf HVX buffering structure.
+ * @return ble_hvx_t * If there is a free ble_hvx_t.
+ * @return NULL If there is no free ble_hvx_t, or an invalid parameter is supplied.
+ */
+ble_hvx_t * ble_hvx_get_p_to_next_hvx(ble_hvx_buf_t * p_ble_hvx_buf);
+
+/**@brief Function for sending something from the HVX buffer.
+ *
+ * @param[in] p_ble_hvx_buf HVX buffering structure.
+ * @return NRF_SUCCESS If a indication/notification was successfully sent.
+ */
+uint32_t ble_hvx_buffer_process(ble_hvx_buf_t * p_ble_hvx_buf);
+
+
+#endif // BLE_HVX_BUFFERING_H__
+
+/** @} */
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots.c
new file mode 100644
index 0000000..b4076c4
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots.c
@@ -0,0 +1,249 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include "ble_ots.h"
+#include "ble_ots_object.h"
+#include "ble_ots_oacp.h"
+#include "fds.h"
+
+#define BLE_OTS_MAX_OBJ_TYPE_SIZE 16
+#define BLE_OTS_OBJ_CHANGED_SIZE 7
+#define OTS_INVALID_ID 0xFF
+
+#define SIZE_DATE_TIME 7
+
+#define BLE_OTS_INVALID_OCTET_OFFSET BLE_GATT_STATUS_ATTERR_APP_BEGIN + 1
+#define BLE_OTS_INVALID_METADATA BLE_GATT_STATUS_ATTERR_APP_BEGIN + 2
+#define BLE_OTS_CONCURRENCY_LIMIT_EXCEEDED BLE_GATT_STATUS_ATTERR_APP_BEGIN + 3
+
+
+#define BLE_OTS_OACP_SUPPORT_FEATURE_CREATE_bp 0
+#define BLE_OTS_OACP_SUPPORT_FEATURE_DELETE_bp 1
+#define BLE_OTS_OACP_SUPPORT_FEATURE_CALC_CHECKSUM_bp 2
+#define BLE_OTS_OACP_SUPPORT_FEATURE_EXECUTE_bp 3
+#define BLE_OTS_OACP_SUPPORT_FEATURE_READ_bp 4
+#define BLE_OTS_OACP_SUPPORT_FEATURE_WRITE_bp 5
+#define BLE_OTS_OACP_SUPPORT_FEATURE_APPEND_bp 6
+#define BLE_OTS_OACP_SUPPORT_FEATURE_TRUNCATE_bp 7
+#define BLE_OTS_OACP_SUPPORT_FEATURE_PATCH_bp 8
+#define BLE_OTS_OACP_SUPPORT_FEATURE_ABORT_bp 9
+
+#define BLE_OTS_OLCP_SUPPORT_FEATURE_GOTO_bp 0
+#define BLE_OTS_OLCP_SUPPORT_FEATURE_ORDER_bp 1
+#define BLE_OTS_OLCP_SUPPORT_FEATURE_REQ_NUM_OBJECTS_bp 2
+#define BLE_OTS_OLCP_SUPPORT_FEATURE_CLEAR_MARKING_bp 3
+
+/**@brief Function for adding the features characteristic.
+ *
+ * @param[in] p_ots Object Transfer Service structure.
+ * @param[in] read_access Read security level for the feature characteristic.
+ * @param[in] p_feature_char_handles Pointer to the handles for the feature characteristic.
+ */
+static uint32_t feature_char_add(ble_ots_t * const p_ots,
+ security_req_t read_access,
+ ble_gatts_char_handles_t * p_feature_char_handles)
+{
+ ble_add_char_params_t add_char_params;
+
+ uint8_t feature[BLE_OTS_FEATURE_LEN];
+
+ uint32_t oacp_features;
+ uint32_t olcp_features;
+
+ oacp_features = 0;
+ oacp_features |= (1 << BLE_OTS_OACP_SUPPORT_FEATURE_READ_bp);
+ oacp_features |= (1 << BLE_OTS_OACP_SUPPORT_FEATURE_APPEND_bp);
+ oacp_features |= (1 << BLE_OTS_OACP_SUPPORT_FEATURE_TRUNCATE_bp);
+ oacp_features |= (1 << BLE_OTS_OACP_SUPPORT_FEATURE_PATCH_bp);
+ oacp_features |= (1 << BLE_OTS_OACP_SUPPORT_FEATURE_ABORT_bp);
+
+ olcp_features = 0;
+
+ uint32_t i = 0;
+ i += uint32_encode(oacp_features, &feature[i]);
+ i += uint32_encode(olcp_features, &feature[i]);
+
+ memset(&add_char_params, 0, sizeof(add_char_params));
+
+ add_char_params.uuid = BLE_UUID_OTS_FEATURES;
+ add_char_params.uuid_type = BLE_UUID_TYPE_BLE;
+ add_char_params.max_len = BLE_OTS_FEATURE_LEN;
+ add_char_params.init_len = BLE_OTS_FEATURE_LEN;
+ add_char_params.p_init_value = &feature[0];
+ add_char_params.char_props.read = 1;
+ add_char_params.read_access = read_access;
+
+ return characteristic_add(p_ots->service_handle,
+ &add_char_params,
+ p_feature_char_handles);
+}
+
+/**@brief Function for handling the Connect event.
+ *
+ * @param[in] p_ots Object Transfer Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_connect(ble_ots_t * p_ots, ble_evt_t const * p_ble_evt)
+{
+ p_ots->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+}
+
+/**@brief Function for handling the BLE_GAP_EVT_DISCONNECTED event.
+ *
+ * @param[in] p_ots OTS Service Structure.
+ * @param[in] p_ble_evt Pointer to the event received from BLE stack.
+ */
+static void on_disconnect(ble_ots_t * p_ots, ble_evt_t const * p_ble_evt)
+{
+ p_ots->conn_handle = BLE_CONN_HANDLE_INVALID;
+}
+
+uint32_t ble_ots_init(ble_ots_t * p_ots, ble_ots_init_t * p_ots_init)
+{
+ if ((p_ots == NULL) || (p_ots_init == NULL))
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ if (p_ots_init->p_object == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ p_ots->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_ots->error_handler = p_ots_init->error_handler;
+ p_ots->evt_handler = p_ots_init->evt_handler;
+ p_ots->p_current_object = p_ots_init->p_object;
+ p_ots->error_handler = p_ots_init->error_handler;
+ p_ots->evt_handler = p_ots_init->evt_handler;
+ p_ots->p_current_object = p_ots_init->p_object;
+
+
+ ble_uuid_t service_uuid =
+ {
+ .uuid = BLE_UUID_OTS_SERVICE,
+ .type = BLE_UUID_TYPE_BLE
+ };
+ uint32_t err_code;
+
+ err_code = fds_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
+ &service_uuid,
+ &(p_ots->service_handle));
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ err_code = feature_char_add(p_ots, p_ots_init->feature_char_read_access, &p_ots->feature_handles);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ err_code = ble_ots_object_representation_init(&p_ots->object_chars, &p_ots_init->object_chars_init);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ err_code = ble_ots_oacp_init(&p_ots->oacp_chars, &p_ots_init->oacp_init);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ p_ots->oacp_chars.ots_l2cap.conn_mps = p_ots_init->rx_mps;
+ p_ots->oacp_chars.ots_l2cap.conn_mtu = p_ots_init->rx_mtu;
+
+ return NRF_SUCCESS;
+}
+
+/**@brief Function for handling the BLE_EVT_TX_COMPLETE event. Calls the hvx buffering module.
+ * @param[in] p_ots Object Transfer Service structure. */
+static inline void on_tx_complete(ble_ots_t * p_ots)
+{
+ uint32_t err_code;
+ err_code = ble_hvx_buffer_process(&p_ots->hvx_buf);
+ if (err_code != NRF_SUCCESS)
+ {
+ p_ots->error_handler(err_code);
+ }
+
+}
+
+void ble_ots_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ ble_ots_t * p_ots;
+ p_ots = (ble_ots_t*) p_context;
+
+ if ((p_ots == NULL) || (p_ble_evt == NULL))
+ {
+ return;
+ }
+ ble_ots_oacp_on_ble_evt(&p_ots->oacp_chars, p_ble_evt);
+ ble_ots_object_on_ble_evt(&p_ots->object_chars, p_ble_evt);
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ on_connect(p_ots, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnect(p_ots, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_HVN_TX_COMPLETE:
+ on_tx_complete(p_ots);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots.h
new file mode 100644
index 0000000..634bfd4
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots.h
@@ -0,0 +1,472 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+ /**@file
+ *
+ * @defgroup ble_ots Object Transfer Service
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Object Transfer Service module
+ *
+ * @details This is the main module of the OTS service.
+ */
+
+#ifndef BLE_OTS_H__
+#define BLE_OTS_H__
+
+#include <stdint.h>
+#include "ble_srv_common.h"
+#include "ble_date_time.h"
+#include "ble_hvx_buffering.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_ots instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define BLE_OTS_DEF(_name) \
+static ble_ots_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _ble_obs, \
+ BLE_OTS_BLE_OBSERVER_PRIO, \
+ ble_ots_on_ble_evt, &_name) \
+
+
+#define NRF_BLE_OTS_SIZE_CHAR_LEN (2*sizeof(uint32_t))
+#define BLE_OTS_FEATURE_LEN (2*sizeof(uint32_t))
+#define BLE_OTS_NAME_MAX_SIZE 128
+#define BLE_OTS_MAX_OBJ_SIZE 1028
+#define BLE_OTS_INVALID_CID 0x0000 /**< Invalid connection ID. */
+#define BLE_OTS_PSM 0x0025
+#define BLE_OTS_MAX_OACP_SIZE 21
+#define BLE_OTS_WRITE_MODE_TRUNCATE (1 << 1)
+#define BLE_OTS_WRITE_MODE_NO_TRUNCATE 0
+
+// Forward declarations.
+typedef struct ble_ots_s ble_ots_t;
+typedef struct ble_ots_oacp_s ble_ots_oacp_t;
+typedef struct ble_ots_l2cap_s ble_ots_l2cap_t;
+
+
+/*------------------------------------------ BLE OTS OBJECT --------------------------------------*/
+
+/**@brief Properties of an Object Transfer Service object. */
+typedef union
+{
+ struct
+ {
+ bool is_delete_permitted :1;
+ bool is_execute_permitted :1;
+ bool is_read_permitted :1;
+ bool is_write_permitted :1;
+ bool is_append_permitted :1;
+ bool is_truncate_permitted:1; /**< When writing using truncate mode, and the written length is shorter than the object, the object size is decreased. */
+ bool is_patch_permitted :1; /**< When patching, a part of the object is replaced. */
+ bool is_marked :1;
+ } decoded;
+ uint32_t raw;
+} ble_ots_obj_properties_t;
+
+/**@brief A structure representing the object type. */
+typedef struct
+{
+ uint8_t len; /**< The length of the object type in bytes. 2 and 16 are the only valid type lengths. */
+ union
+ {
+ uint16_t type16;
+ uint8_t type128[16];
+ } param;
+} ble_ots_obj_type_t;
+
+/**@brief The structure representing one Object Transfer Service object. */
+typedef struct
+{
+ uint8_t name[BLE_OTS_NAME_MAX_SIZE]; /**< The name of the object. If the name is "", the object will be invalidated on disconnect. */
+ uint8_t data[BLE_OTS_MAX_OBJ_SIZE];
+ ble_ots_obj_type_t type;
+ ble_ots_obj_properties_t properties;
+ uint32_t current_size;
+ uint32_t alloc_len;
+ bool is_valid; /**< States if the object will be shown in a list. */
+ bool is_locked; /**< When an object is written or read, the object will be locked. */
+} ble_ots_object_t;
+
+/**@brief The definition of an event from the object characteristics. */
+typedef struct
+{
+ enum
+ {
+ BLE_OTS_OBJECT_EVT_NAME_CHANGED,
+ BLE_OTS_OBJECT_EVT_PROPERTIES_CHANGED,
+ } type;
+ union
+ {
+ ble_ots_object_t * p_object;
+ } evt;
+} ble_ots_object_evt_t;
+
+/**@brief Initialization properties of the Object Transfer Service Object characteristics. */
+typedef struct
+{
+ ble_ots_t * p_ots;
+ security_req_t name_read_access;
+ security_req_t name_write_access;
+ security_req_t type_read_access;
+ security_req_t size_read_access;
+ security_req_t properties_read_access;
+ security_req_t properties_write_access;
+} ble_ots_object_chars_init_t;
+
+/**@brief The structure holding the state of the OTS object characteristics. */
+typedef struct
+{
+ ble_ots_t * p_ots;
+ ble_gatts_char_handles_t obj_name_handles;
+ ble_gatts_char_handles_t obj_type_handles;
+ ble_gatts_char_handles_t obj_size_handles;
+ ble_gatts_char_handles_t obj_properties_handles;
+} ble_ots_object_chars_t;
+
+
+/*------------------------------------------ BLE OTS L2CAP ---------------------------------------*/
+
+/**@brief L2cap event types. */
+typedef enum
+{
+ BLE_OTS_L2CAP_EVT_CH_CONNECTED,
+ BLE_OTS_L2CAP_EVT_CH_DISCONNECTED,
+ BLE_OTS_L2CAP_EVT_SEND_COMPLETE,
+ BLE_OTS_L2CAP_EVT_RECV_COMPLETE,
+} ble_ots_l2cap_evt_type_t;
+
+/**@brief l2cap event. */
+typedef struct
+{
+ ble_ots_l2cap_evt_type_t type;
+ struct
+ {
+ uint8_t * p_data;
+ uint16_t len;
+ } param;
+} ble_ots_l2cap_evt_t;
+
+/**@brief L2CAP event handler. */
+typedef void (*ble_ots_l2cap_evt_handler_t)(ble_ots_l2cap_t * p_ots_l2cap,
+ ble_ots_l2cap_evt_t * p_evt);
+
+/**@brief The structure holding the l2cap connection oriented channels state. */
+struct ble_ots_l2cap_s
+{
+ ble_ots_l2cap_evt_handler_t evt_handler;
+ ble_ots_oacp_t * p_ots_oacp;
+ enum
+ {
+ NOT_CONNECTED,
+ CONNECTED,
+ SENDING,
+ RECEIVING
+ } state;
+ ble_data_t tx_transfer_buffer;
+ ble_l2cap_ch_rx_params_t rx_params;
+ ble_l2cap_ch_tx_params_t tx_params;
+ uint16_t remaining_bytes; /**< The number of remaining bytes in the current transfer. */
+ uint16_t transfered_bytes;
+ uint16_t transfer_len; /**< The total number of bytes in the current transfer. */
+ uint16_t local_cid; /**< Connection id of the current connection. */
+ uint16_t conn_mtu; /**< The maximum transmission unit, that is the number of packets that can be sent or received. */
+ uint16_t conn_mps; /**< MPS defines the maximum payload size in bytes. */
+};
+
+/**@brief The initialization structure of the l2cap module. */
+typedef struct
+{
+ ble_ots_oacp_t * p_ots_oacp;
+ ble_ots_l2cap_evt_handler_t evt_handler;
+ uint8_t * p_transfer_buffer; /**< The user must provide buffer for transfers. */
+ uint16_t buffer_len; /**< Length of the transfer buffer. */
+} ble_ots_l2cap_init_t;
+
+
+/*------------------------------------------ BLE OTS OCAP ----------------------------------------*/
+
+/**< Types of Object Action Control Point Procedures. */
+typedef enum
+{
+ BLE_OTS_OACP_PROC_CREATE = 0x01, //!< Create object.
+ BLE_OTS_OACP_PROC_DELETE = 0x02, //!< Delete object.
+ BLE_OTS_OACP_PROC_CALC_CHKSUM = 0x03, //!< Calculate Checksum.
+ BLE_OTS_OACP_PROC_EXECUTE = 0x04, //!< Execute Object.
+ BLE_OTS_OACP_PROC_READ = 0x05, //!< Read object.
+ BLE_OTS_OACP_PROC_WRITE = 0x06, //!< Write object.
+ BLE_OTS_OACP_PROC_ABORT = 0x07, //!< Abort object.
+ BLE_OTS_OACP_PROC_RESP = 0x60 //!< Procedure response.
+} ble_ots_oacp_proc_type_t;
+
+/**< Object Action Control Point return codes. */
+typedef enum
+{
+ BLE_OTS_OACP_RES_SUCCESS = 0x01, //!< Success.
+ BLE_OTS_OACP_RES_OPCODE_NOT_SUP = 0x02, //!< Not supported
+ BLE_OTS_OACP_RES_INV_PARAM = 0x03, //!< Invalid parameter
+ BLE_OTS_OACP_RES_INSUFF_RES = 0x04, //!< Insufficient resources.
+ BLE_OTS_OACP_RES_INV_OBJ = 0x05, //!< Invalid object.
+ BLE_OTS_OACP_RES_CHAN_UNAVAIL = 0x06, //!< Channel unavailable.
+ BLE_OTS_OACP_RES_UNSUP_TYPE = 0x07, //!< Unsupported procedure.
+ BLE_OTS_OACP_RES_NOT_PERMITTED = 0x08, //!< Procedure not permitted.
+ BLE_OTS_OACP_RES_OBJ_LOCKED = 0x09, //!< Object locked.
+ BLE_OTS_OACP_RES_OPER_FAILED = 0x0A //!< Operation Failed.
+} ble_ots_oacp_res_code_t;
+
+/**< Object Action Control Point procedure definition. */
+typedef struct
+{
+ ble_ots_oacp_proc_type_t type;
+ union
+ {
+ struct
+ {
+ uint32_t size;
+ ble_ots_obj_type_t * p_obj_type;
+ } create_params;
+ struct
+ {
+ uint32_t offset;
+ uint32_t length;
+ } checksum_params;
+ struct
+ {
+ uint8_t cmd_data_len;
+ uint8_t * p_cmd_data;
+ } execute_params;
+ struct
+ {
+ uint32_t offset;
+ uint32_t length;
+ } read_params;
+ struct
+ {
+ uint32_t offset;
+ uint32_t length;
+ uint8_t write_mode;
+ } write_params;
+ } params;
+} ble_ots_oacp_proc_t;
+
+/**@brief Definition of an OACP event. */
+typedef struct
+{
+ enum
+ {
+ BLE_OTS_OACP_EVT_EXECUTE,
+ BLE_OTS_OACP_EVT_REQ_READ,
+ BLE_OTS_OACP_EVT_INCREASE_ALLOC_LEN,
+ BLE_OTS_OACP_EVT_REQ_WRITE,
+ BLE_OTS_OACP_EVT_ABORT,
+ } type;
+ union
+ {
+ ble_ots_object_t * p_object;
+ struct
+ {
+ uint8_t cmd_data_len;
+ uint8_t * p_cmd_data;
+ } execute_params;
+ } evt;
+} ble_ots_oacp_evt_t;
+
+/**@brief OACP initialization properties. */
+typedef struct
+{
+ ble_ots_t * p_ots;
+ uint32_t on_create_obj_properties_raw; /**< The encoded properties of a newly created object.*/
+ security_req_t write_access; /**< The write security level for the OACP. */
+ security_req_t cccd_write_access; /**< The write security level for the OACP CCCD. */
+ uint8_t * p_l2cap_buffer;
+ uint16_t l2cap_buffer_len;
+} ble_ots_oacp_init_t;
+
+struct ble_ots_oacp_s
+{
+ ble_ots_t * p_ots;
+ uint32_t on_create_obj_properties_raw; /**< The encoded properties of a newly created object.*/
+ ble_ots_l2cap_t ots_l2cap; /**< L2CAP connection oriented channel module. */
+ ble_gatts_char_handles_t oacp_handles; /**< The characteristic handles of the OACP. */
+};
+
+
+/*------------------------------------------ BLE OTS ---------------------------------------------*/
+
+/**@brief The event type indicates which module the event is connected to.*/
+typedef enum
+{
+ BLE_OTS_EVT_OACP,
+ BLE_OTS_EVT_OBJECT,
+ BLE_OTS_EVT_INDICATION_ENABLED,
+ BLE_OTS_EVT_INDICATION_DISABLED,
+ BLE_OTS_EVT_OBJECT_RECEIVED /**< If this event is received, data is now available in the current object.*/
+} ble_ots_evt_type_t;
+
+/**@brief This structure represents the state of the Object Transfer Service. */
+typedef struct
+{
+ ble_ots_evt_type_t type;
+ union
+ {
+ ble_ots_oacp_evt_t oacp_evt;
+ ble_ots_object_evt_t object_evt;
+
+ } evt; /**< Event data. */
+} ble_ots_evt_t;
+
+/**@brief OTS event handler. */
+typedef void (*ble_ots_evt_handler_t) (ble_ots_t * p_ots, ble_ots_evt_t * p_evt);
+
+/**@brief Structure for initializing the OTS. */
+typedef struct
+{
+ ble_ots_evt_handler_t evt_handler;
+ ble_srv_error_handler_t error_handler;
+ ble_ots_object_t * p_object; /**< Pointer to the object. */
+ security_req_t feature_char_read_access; /**< Read security level for the feature characteristic value. */
+ ble_ots_object_chars_init_t object_chars_init; /**< The initialization structure of the object characteristics. */
+ ble_ots_oacp_init_t oacp_init; /**< The initialization structure of the object action control point. */
+ uint16_t rx_mps; /**< Size of L2CAP Rx MPS (must be at least BLE_L2CAP_MPS_MIN).*/
+ uint16_t rx_mtu; /**< Size of L2CAP Rx MTU (must be at least BLE_L2CAP_MTU_MIN).*/
+} ble_ots_init_t;
+
+struct ble_ots_s
+{
+ uint16_t conn_handle; /**< Connection handle of service. */
+ uint16_t service_handle; /**< THe service handle of OTS. */
+ ble_ots_evt_handler_t evt_handler;
+ ble_srv_error_handler_t error_handler;
+ ble_gatts_char_handles_t feature_handles;
+ ble_ots_object_chars_t object_chars; /**< The structure holding the object characteristics representation. */
+ ble_ots_oacp_t oacp_chars; /**< The structure holding the object action control point characteristics representation. */
+ ble_ots_object_t * p_current_object; /**< Pointer to the currently selected object. */
+ ble_hvx_buf_t hvx_buf; /**< A buffer holding unsent handle value indications/notifications. */
+};
+
+
+/**@brief Function for initializing the Object Transfer Service.
+ *
+ * @param[out] p_ots Object Transfer Service structure. This structure will have to be supplied by
+ * the application. It will be initialized by this function, and will later
+ * be used to identify this particular service instance.
+ * @param[in] p_ots_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
+ */
+uint32_t ble_ots_init(ble_ots_t * p_ots, ble_ots_init_t * p_ots_init);
+
+/**@brief Function for handling the Application's BLE Stack events.
+ *
+ * @details Handles all events from the BLE stack of interest to the Object Transfer Service.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Object Transfer Service structure.
+ */
+void ble_ots_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+/**@brief Function for setting the name of an object.
+ *
+ * @details If p_object is the current selected object, and the notifications is enabled, the client will be notified that the object has changed.
+ * @note If the name of the object is "" on disconnection, the object will be invalidated.
+ *
+ * @param[in] p_ots_object_chars Object Transfer Service Object Characteristics structure.
+ * @param[in] p_object Pointer to the object where the name will be changed.
+ * @param[in] new_name The new name of the object.
+ *
+ * @return NRF_SUCCESS On success, otherwise an error code.
+ */
+uint32_t ble_ots_object_set_name(ble_ots_object_chars_t * p_ots_object_chars,
+ ble_ots_object_t * p_object,
+ char const * new_name);
+
+/**@brief Function for setting the type of an object.
+ *
+ * @details If p_object is the current selected object, and the notifications is enabled, the client will be notified that the object has changed.
+ * @param[in] p_ots_object_chars Object Transfer Service Object Characteristics structure.
+ * @param[in] p_object Pointer to the object where the type will be changed.
+ * @param[in] p_new_type Pointer to the new type of the object.
+ *
+ * @return NRF_SUCCESS On success, otherwise an error code.
+ */
+uint32_t ble_ots_object_set_type(ble_ots_object_chars_t * p_ots_object_chars,
+ ble_ots_object_t * p_object,
+ ble_ots_obj_type_t * p_new_type);
+
+/**@brief Function for setting the current size of an object.
+ *
+ * @details If p_object is the current selected object, and the notifications is enabled, the client will be notified that the object has changed.
+ * @note If the new current size is smaller than the current size, the object will be truncated.
+ *
+ * @param[in] p_ots_object_chars Object Transfer Service Object Characteristics structure.
+ * @param[in] p_object Pointer to the object where the current size will be changed.
+ * @param[in] new_current_size The new current size of the object.
+ *
+ * @return NRF_SUCCESS On success, otherwise an error code.
+ */
+uint32_t ble_ots_object_set_current_size(ble_ots_object_chars_t * p_ots_object_chars,
+ ble_ots_object_t * p_object,
+ uint32_t new_current_size);
+
+/**@brief Function for setting the properties of an object.
+ *
+ * @details If p_object is the current selected object, and the notifications is enabled, the client will be notified that the object has changed.
+ *
+ * @param[in] p_ots_object_chars Object Transfer Service Object Characteristics structure.
+ * @param[in] p_object Pointer to the object where the properties will be changed.
+ * @param[in] p_new_properties The properties of the object.
+ *
+ * @return NRF_SUCCESS On success, otherwise an error code.
+ */
+uint32_t ble_ots_object_set_properties(ble_ots_object_chars_t * p_ots_object_chars,
+ ble_ots_object_t * p_object,
+ ble_ots_obj_properties_t * p_new_properties);
+
+
+
+#endif // BLE_OTS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_l2cap.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_l2cap.c
new file mode 100644
index 0000000..b51e086
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_l2cap.c
@@ -0,0 +1,437 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "ble_ots_l2cap.h"
+
+#include <string.h>
+#include "ble_l2cap.h"
+
+#include "ble_ots.h"
+#include "ble_ots_oacp.h"
+
+#define NRF_LOG_MODULE_NAME ble_ots_l2cap
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define SDU_SIZE 256
+
+
+static uint8_t data[SDU_SIZE];
+static ble_data_t m_sdu_buf =
+{
+ .p_data = data,
+ .len = SDU_SIZE
+};
+
+bool ble_ots_l2cap_is_channel_available(ble_ots_l2cap_t * p_ots_l2cap)
+{
+ return p_ots_l2cap->state == CONNECTED;
+}
+
+uint32_t ble_ots_l2cap_abort_transmission(ble_ots_l2cap_t * p_ots_l2cap)
+{
+ if (p_ots_l2cap == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+ return NRF_ERROR_INVALID_PARAM;
+}
+
+uint32_t ble_ots_l2cap_init(ble_ots_l2cap_t * p_ots_l2cap, ble_ots_l2cap_init_t * p_ots_l2cap_init)
+{
+ if (p_ots_l2cap == NULL || p_ots_l2cap_init == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+ if (p_ots_l2cap_init->p_transfer_buffer == NULL || p_ots_l2cap_init->buffer_len == 0)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ if (p_ots_l2cap_init->p_ots_oacp == NULL)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ if (p_ots_l2cap_init->evt_handler == NULL)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ memset(p_ots_l2cap, 0, sizeof(ble_ots_l2cap_t));
+
+ p_ots_l2cap->local_cid = BLE_OTS_INVALID_CID;
+
+ p_ots_l2cap->p_ots_oacp = p_ots_l2cap_init->p_ots_oacp;
+ p_ots_l2cap->evt_handler = p_ots_l2cap_init->evt_handler;
+ p_ots_l2cap->rx_params.sdu_buf.len = m_sdu_buf.len;
+ p_ots_l2cap->rx_params.sdu_buf.p_data = m_sdu_buf.p_data;
+
+ p_ots_l2cap->state = NOT_CONNECTED;
+
+ return NRF_SUCCESS;
+}
+
+
+
+/**@brief This function resumes sending data after an interrupt in the transfer.
+ *
+ * @param[in] p_ots_l2cap Object Transfer Service structure.
+ */
+static void ble_ots_l2cap_resume_send(ble_ots_l2cap_t * p_ots_l2cap)
+{
+ uint16_t transmit_size;
+ ble_data_t data_buf;
+
+ transmit_size = MIN(p_ots_l2cap->tx_params.tx_mtu, p_ots_l2cap->remaining_bytes);
+
+ data_buf.p_data = &p_ots_l2cap->tx_transfer_buffer.p_data[p_ots_l2cap->transfer_len - p_ots_l2cap->remaining_bytes];
+ data_buf.len = transmit_size;
+
+
+ uint32_t err_code = sd_ble_l2cap_ch_tx(p_ots_l2cap->p_ots_oacp->p_ots->conn_handle,
+ p_ots_l2cap->local_cid,
+ &data_buf);
+
+ if (err_code != NRF_SUCCESS && err_code != NRF_ERROR_BUSY)
+ {
+ if (p_ots_l2cap->p_ots_oacp->p_ots->error_handler != NULL)
+ {
+ p_ots_l2cap->p_ots_oacp->p_ots->error_handler(err_code);
+ return;
+ }
+ }
+}
+
+
+uint32_t ble_ots_l2cap_start_send(ble_ots_l2cap_t * p_ots_l2cap, uint8_t * p_data, uint16_t data_len)
+{
+ if (p_ots_l2cap == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+ if (p_data == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+ if (data_len == 0)
+ {
+ return NRF_ERROR_INVALID_LENGTH;
+ }
+ if (p_ots_l2cap->local_cid == BLE_L2CAP_CID_INVALID)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+ if (p_ots_l2cap->state != CONNECTED)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ p_ots_l2cap->tx_transfer_buffer.p_data = p_data;
+ p_ots_l2cap->tx_transfer_buffer.len = data_len;
+
+ p_ots_l2cap->remaining_bytes = data_len;
+ p_ots_l2cap->transfer_len = data_len;
+
+ p_ots_l2cap->state = SENDING;
+
+ ble_ots_l2cap_resume_send(p_ots_l2cap);
+
+ return NRF_SUCCESS;
+}
+
+uint32_t ble_ots_l2cap_start_recv(ble_ots_l2cap_t * p_ots_l2cap, uint16_t len)
+{
+ uint32_t err_code;
+
+ if (p_ots_l2cap == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+ if (p_ots_l2cap->state != CONNECTED)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+ if (p_ots_l2cap->local_cid == BLE_L2CAP_CID_INVALID)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+ p_ots_l2cap->transfered_bytes = 0;
+ p_ots_l2cap->remaining_bytes = len;
+ p_ots_l2cap->transfer_len = len;
+
+ err_code = sd_ble_l2cap_ch_rx(p_ots_l2cap->p_ots_oacp->p_ots->conn_handle,
+ p_ots_l2cap->local_cid,
+ &p_ots_l2cap->rx_params.sdu_buf);
+ if (err_code == NRF_SUCCESS)
+ {
+ p_ots_l2cap->state = RECEIVING;
+ }
+
+ return err_code;
+}
+
+/**@brief This function is called on a channel setup request. It responds with the connection parameters.
+ * @param[in] p_ots_l2cap Object transfer service l2cap module structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static inline void on_l2cap_ch_setup_request(ble_ots_l2cap_t * p_ots_l2cap, ble_evt_t const * p_ble_evt)
+{
+ uint32_t err_code;
+ ble_l2cap_ch_setup_params_t ch_setup_params = {{0}};
+
+ if (p_ble_evt->evt.l2cap_evt.params.ch_setup_request.le_psm != BLE_OTS_PSM)
+ {
+ ch_setup_params.status = BLE_L2CAP_CH_STATUS_CODE_LE_PSM_NOT_SUPPORTED;
+ NRF_LOG_WARNING("l2cap setup request for PSM 0x%x, rejecting since OTS PSM is 0x%x",
+ p_ble_evt->evt.l2cap_evt.params.ch_setup_request.le_psm,
+ BLE_L2CAP_CH_STATUS_CODE_LE_PSM_NOT_SUPPORTED);
+ }
+
+ else
+ {
+ ch_setup_params.status = BLE_L2CAP_CH_STATUS_CODE_SUCCESS;
+
+ ch_setup_params.rx_params.rx_mps = p_ots_l2cap->conn_mps;
+ if (ch_setup_params.rx_params.rx_mps < BLE_L2CAP_MPS_MIN)
+ {
+ ch_setup_params.rx_params.rx_mps = BLE_L2CAP_MPS_MIN;
+ }
+ ch_setup_params.rx_params.rx_mtu = p_ots_l2cap->conn_mtu;
+ if (ch_setup_params.rx_params.rx_mtu < BLE_L2CAP_MTU_MIN)
+ {
+ ch_setup_params.rx_params.rx_mtu = BLE_L2CAP_MTU_MIN;
+ }
+ ch_setup_params.rx_params.sdu_buf.p_data = NULL;
+ }
+
+ p_ots_l2cap->local_cid = p_ble_evt->evt.l2cap_evt.local_cid;
+
+ err_code = sd_ble_l2cap_ch_setup(p_ots_l2cap->p_ots_oacp->p_ots->conn_handle,
+ &p_ots_l2cap->local_cid,
+ &ch_setup_params);
+ if (err_code != NRF_SUCCESS)
+ {
+ if (p_ots_l2cap->p_ots_oacp->p_ots->error_handler != NULL)
+ {
+ p_ots_l2cap->p_ots_oacp->p_ots->error_handler(err_code);
+ }
+
+ }
+ NRF_LOG_INFO("Accepted L2CAP Channel");
+}
+
+
+/**@brief This function is called on a channel setup request. The parameters are stored. Events are forwarded.
+ *
+ * @param[in] p_ots_l2cap Object transfer service l2cap module structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static inline void on_l2cap_ch_setup(ble_ots_l2cap_t * p_ots_l2cap, ble_evt_t const * p_ble_evt)
+{
+ p_ots_l2cap->local_cid = p_ble_evt->evt.l2cap_evt.local_cid;
+ p_ots_l2cap->tx_params.credits = p_ble_evt->evt.l2cap_evt.params.ch_setup.tx_params.credits;
+ p_ots_l2cap->tx_params.tx_mps = p_ble_evt->evt.l2cap_evt.params.ch_setup.tx_params.tx_mps;
+ p_ots_l2cap->tx_params.tx_mtu = p_ble_evt->evt.l2cap_evt.params.ch_setup.tx_params.tx_mtu;
+ ble_ots_l2cap_evt_t evt;
+
+ evt.type = BLE_OTS_L2CAP_EVT_CH_CONNECTED;
+
+ p_ots_l2cap->state = CONNECTED;
+ p_ots_l2cap->evt_handler(p_ots_l2cap, &evt);
+}
+
+
+/**@brief Function for handling the BLE_L2CAP_EVT_CH_RELEASED event.
+ *
+ * @param[in] p_ots_l2cap Object transfer service l2cap module structure.
+ * @param[in] p_ble_evt Pointer to the event received from BLE stack.
+ */
+static inline void on_l2cap_ch_released(ble_ots_l2cap_t * p_ots_l2cap, ble_evt_t const * p_ble_evt)
+{
+ if(p_ots_l2cap->local_cid != p_ble_evt->evt.l2cap_evt.local_cid)
+ {
+ return;
+ }
+ ble_ots_l2cap_evt_t evt;
+
+ evt.type = BLE_OTS_L2CAP_EVT_CH_DISCONNECTED;
+
+ p_ots_l2cap->evt_handler(p_ots_l2cap, &evt);
+
+ p_ots_l2cap->state = NOT_CONNECTED;
+
+ p_ots_l2cap->local_cid = BLE_OTS_INVALID_CID;
+
+}
+
+
+/**@brief This function ois called tx is completet. It continues to send if necessary.
+ *
+ * @param[in] p_ots_l2cap Object transfer service l2cap module structure.
+ * @param[in] p_ble_evt Pointer to the event received from BLE stack.
+ */
+static void on_tx_complete(ble_ots_l2cap_t * p_ots_l2cap, ble_evt_t const * p_ble_evt)
+{
+ if(p_ots_l2cap->local_cid != p_ble_evt->evt.l2cap_evt.local_cid)
+ {
+ return;
+ }
+
+ p_ots_l2cap->remaining_bytes -= p_ble_evt->evt.l2cap_evt.params.tx.sdu_buf.len;
+
+ if (p_ots_l2cap->remaining_bytes == 0)
+ {
+ ble_ots_l2cap_evt_t evt;
+
+ evt.type = BLE_OTS_L2CAP_EVT_SEND_COMPLETE;
+ evt.param.len = p_ots_l2cap->transfer_len;
+ evt.param.p_data = p_ots_l2cap->tx_transfer_buffer.p_data;
+ evt.param.len = p_ots_l2cap->tx_transfer_buffer.len;
+
+ p_ots_l2cap->evt_handler(p_ots_l2cap, &evt);
+
+ p_ots_l2cap->state = CONNECTED;
+
+ p_ots_l2cap->transfer_len = 0;
+ }
+ else
+ {
+ ble_ots_l2cap_resume_send(p_ots_l2cap);
+ }
+}
+
+
+static void on_l2cap_ch_rx(ble_ots_l2cap_t * p_ots_l2cap, ble_evt_t const * p_ble_evt)
+{
+ if(p_ots_l2cap->local_cid != p_ble_evt->evt.l2cap_evt.local_cid)
+ {
+ return;
+ }
+
+ ble_ots_l2cap_evt_t evt;
+
+ memcpy(&p_ots_l2cap->p_ots_oacp->p_ots->p_current_object->data[p_ots_l2cap->transfered_bytes],
+ p_ble_evt->evt.l2cap_evt.params.rx.sdu_buf.p_data,
+ p_ble_evt->evt.l2cap_evt.params.rx.sdu_len);
+ NRF_LOG_DEBUG("Object buffer dump");
+ NRF_LOG_HEXDUMP_DEBUG(p_ots_l2cap->rx_params.sdu_buf.p_data , p_ots_l2cap->rx_params.sdu_buf.len);
+ p_ots_l2cap->transfered_bytes += p_ble_evt->evt.l2cap_evt.params.rx.sdu_len;
+ p_ots_l2cap->remaining_bytes -= p_ble_evt->evt.l2cap_evt.params.rx.sdu_len;
+ NRF_LOG_INFO("Bytes remaining to receive: %i", p_ots_l2cap->remaining_bytes);
+ p_ots_l2cap->state = CONNECTED;
+
+ p_ots_l2cap->transfer_len = 0;
+
+ if(p_ots_l2cap->remaining_bytes <= 0)
+ {
+ evt.type = BLE_OTS_L2CAP_EVT_RECV_COMPLETE;
+ evt.param.len = p_ots_l2cap->rx_params.sdu_buf.len;
+ evt.param.p_data = p_ots_l2cap->rx_params.sdu_buf.p_data;
+ p_ots_l2cap->evt_handler(p_ots_l2cap, &evt);
+ }
+ else
+ {
+ ret_code_t err_code;
+
+ ble_data_t sdu_buf;
+ sdu_buf.p_data = &p_ots_l2cap->rx_params.sdu_buf.p_data[p_ots_l2cap->transfered_bytes];
+ sdu_buf.len = p_ots_l2cap->rx_params.sdu_buf.len;
+
+ err_code = sd_ble_l2cap_ch_rx(p_ots_l2cap->p_ots_oacp->p_ots->conn_handle,
+ p_ots_l2cap->local_cid,
+ &sdu_buf);
+ if (err_code == NRF_SUCCESS)
+ {
+ p_ots_l2cap->state = RECEIVING;
+ }
+ else
+ {
+ p_ots_l2cap->state = CONNECTED;
+ }
+ }
+}
+
+
+
+void ble_ots_l2cap_on_ble_evt(ble_ots_l2cap_t * p_ots_l2cap, ble_evt_t const * p_ble_evt)
+{
+ if ((p_ots_l2cap == NULL) || (p_ble_evt == NULL))
+ {
+ return;
+ }
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_L2CAP_EVT_CH_SETUP_REQUEST:
+ on_l2cap_ch_setup_request(p_ots_l2cap, p_ble_evt);
+ break;
+
+ case BLE_L2CAP_EVT_CH_SETUP_REFUSED:
+ // This should not happen because the client should be the initiator.
+ if (p_ots_l2cap->p_ots_oacp->p_ots->error_handler != NULL)
+ {
+ p_ots_l2cap->p_ots_oacp->p_ots->error_handler(NRF_ERROR_INVALID_STATE);
+ }
+ break;
+
+ case BLE_L2CAP_EVT_CH_SETUP:
+ on_l2cap_ch_setup(p_ots_l2cap, p_ble_evt);
+ break;
+
+ case BLE_L2CAP_EVT_CH_RELEASED:
+ on_l2cap_ch_released(p_ots_l2cap, p_ble_evt);
+ break;
+ case BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED:
+ break;
+ case BLE_L2CAP_EVT_CH_CREDIT:
+ break;
+ case BLE_L2CAP_EVT_CH_RX:
+ on_l2cap_ch_rx(p_ots_l2cap, p_ble_evt);
+ break;
+
+ case BLE_L2CAP_EVT_CH_TX:
+ on_tx_complete(p_ots_l2cap, p_ble_evt);
+ break;
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_l2cap.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_l2cap.h
new file mode 100644
index 0000000..be0312a
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_l2cap.h
@@ -0,0 +1,117 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/**@file
+ *
+ * @defgroup ble_sdk_srv_ots_l2cap Object Transfer Service, l2cap channel handling
+ * @{
+ * @ingroup ble_ots
+ * @brief Object Transfer Service module
+ *
+ * @details This module is responsible for handling the l2cap connection oriented channels.
+ */
+
+#ifndef BLE_OTS_L2CAP_H__
+#define BLE_OTS_L2CAP_H__
+
+#include <stdint.h>
+#include "ble_ots.h"
+
+/**@brief Function for initializing the Object Transfer Service l2cap module.
+ *
+ * @param[out] p_ots_l2cap Object Transfer Service l2cap structure. This structure will have to be
+ * supplied by the application. It will be initialized by this function, * and will later be used to identify this particular instance.
+ * @param[in] p_ots_l2cap_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on successful initialization, otherwise an error code.
+ */
+uint32_t ble_ots_l2cap_init(ble_ots_l2cap_t * p_ots_l2cap, ble_ots_l2cap_init_t * p_ots_l2cap_init);
+
+/**@brief Function for handling the Application's BLE Stack events.
+ *
+ * @details Handles all events from the BLE stack of interest to the l2cap module.
+ *
+ * @param[in] p_ots_l2cap Object transfer service l2cap module structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+void ble_ots_l2cap_on_ble_evt(ble_ots_l2cap_t * p_ots_l2cap, ble_evt_t const * p_ble_evt);
+
+/**@brief Function starting to send the data in the transfer buffer.
+ *
+ * @param[in] p_ots_l2cap Object transfer service l2cap module structure.
+ * @param[in] p_data Pointer to the data to be sent.
+ * @param[in] data_len The length of the data to be sent.
+ *
+ * @return NRF_SUCCESS If the transmission was started.
+ * @return NRF_ERROR_INVALID_STATE When in an invalid state. Otherwise an other error code.
+ */
+uint32_t ble_ots_l2cap_start_send(ble_ots_l2cap_t * p_ots_l2cap, uint8_t * p_data, uint16_t data_len);
+
+/**@brief Function starting to receive data to the transfer buffer.
+ *
+ * @param[in] p_ots_l2cap Object transfer service l2cap module structure.
+ * @param[in] len The length of the data to be received.
+ *
+ * @return NRF_SUCCESS If the transmission was started.
+ * @return NRF_ERROR_INVALID_STATE When in an invalid state. Otherwise an other error code.
+ */
+uint32_t ble_ots_l2cap_start_recv(ble_ots_l2cap_t * p_ots_l2cap, uint16_t len);
+
+/**@brief Function that checks if the channel is available for transmission.
+ *
+ * @param[in] p_ots_l2cap Object transfer service l2cap module structure.
+ *
+ * @return true if the channel is available.
+ */
+bool ble_ots_l2cap_is_channel_available(ble_ots_l2cap_t * p_ots_l2cap);
+
+/**@brief Function starting to abort the current transmission.
+ *
+ * @param[in] p_ots_l2cap Object transfer service l2cap module structure.
+ *
+ * @return NRF_SUCCESS If the transmission was aborted.
+ * @return NRF_ERROR_INVALID_STATE When in an invalid state. Otherwise an other error code.
+ */
+uint32_t ble_ots_l2cap_abort_transmission(ble_ots_l2cap_t * p_ots_l2cap);
+
+#endif // BLE_OTS_L2CAP_H__
+
+/** @} */ // End tag for the file.
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_oacp.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_oacp.c
new file mode 100644
index 0000000..1357b29
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_oacp.c
@@ -0,0 +1,606 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "ble_ots_oacp.h"
+
+#include <string.h>
+#include "fds.h"
+#include "crc32.h"
+
+#include "ble_ots.h"
+#include "ble_ots_l2cap.h"
+#include "ble_ots_object.h"
+
+#define NRF_LOG_MODULE_NAME ble_ots_oacp
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define OTS_FILE_ID 1234
+#define OTS_FDS_KEY 4321
+
+
+/**@brief Checks if the cccd handle is configured for indication
+ *
+ * @param[in] cccd_handle The CCCD handle.
+ */
+bool is_cccd_configured(ble_ots_oacp_t * const p_ots_oacp)
+{
+ uint32_t err_code;
+ uint8_t cccd_value_buf[BLE_CCCD_VALUE_LEN];
+ bool is_oacp_indic_enabled = false;
+ ble_gatts_value_t gatts_value;
+
+ uint16_t cccd_handle = p_ots_oacp->oacp_handles.cccd_handle;
+ uint16_t conn_handle = p_ots_oacp->p_ots->conn_handle;
+ // Initialize value struct.
+ memset(&gatts_value, 0, sizeof(gatts_value));
+
+ gatts_value.len = BLE_CCCD_VALUE_LEN;
+ gatts_value.offset = 0;
+ gatts_value.p_value = cccd_value_buf;
+
+ err_code = sd_ble_gatts_value_get(conn_handle,
+ cccd_handle,
+ &gatts_value);
+ if (err_code != NRF_SUCCESS)
+ {
+ // Report error to application
+ if (p_ots_oacp->p_ots->error_handler != NULL)
+ {
+ p_ots_oacp->p_ots->error_handler(err_code);
+ }
+ }
+
+ is_oacp_indic_enabled = ble_srv_is_indication_enabled(cccd_value_buf);
+
+ return is_oacp_indic_enabled;
+}
+
+
+
+/** @brief This is the l2cap connection oriented channel event handler.
+ *
+ * @param[in] p_ots_l2cap Pointer to the l2cap module
+ * @param[in] p_evt The pointer to the event.
+ */
+static void ots_l2cap_evt_handler(ble_ots_l2cap_t * p_ots_l2cap, ble_ots_l2cap_evt_t * p_evt)
+{
+ uint32_t err_code;
+
+ switch (p_evt->type)
+ {
+ case BLE_OTS_L2CAP_EVT_CH_CONNECTED:
+ NRF_LOG_INFO("BLE_OTS_L2CAP_EVT_CH_CONNECTED.");
+ break;
+ case BLE_OTS_L2CAP_EVT_CH_DISCONNECTED:
+ NRF_LOG_INFO("BLE_OTS_L2CAP_EVT_CH_DISCONNECTED.");
+ break;
+ case BLE_OTS_L2CAP_EVT_SEND_COMPLETE:
+ p_ots_l2cap->p_ots_oacp->p_ots->p_current_object->is_locked = false;
+ break;
+ case BLE_OTS_L2CAP_EVT_RECV_COMPLETE:
+ NRF_LOG_INFO("BLE_OTS_L2CAP_EVT_RECV_COMPLETE.");
+ memcpy(p_ots_l2cap->p_ots_oacp->p_ots->p_current_object->data,
+ p_ots_l2cap->rx_params.sdu_buf.p_data,
+ p_ots_l2cap->rx_params.sdu_buf.len);
+ err_code = ble_ots_object_set_current_size(&p_ots_l2cap->p_ots_oacp->p_ots->object_chars,
+ p_ots_l2cap->p_ots_oacp->p_ots->p_current_object,
+ p_ots_l2cap->p_ots_oacp->p_ots->p_current_object->current_size);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("ble_ots_object_set_current_size returned error 0x%x", err_code);
+ }
+ ble_ots_evt_t evt;
+ evt.type = BLE_OTS_EVT_OBJECT_RECEIVED;
+ p_ots_l2cap->p_ots_oacp->p_ots->evt_handler(p_ots_l2cap->p_ots_oacp->p_ots, &evt);
+ break;
+ }
+}
+
+
+/**@brief Adds the OACP characteristic
+ *
+ * @param[in] p_ots_oacp Pointer to the OACP structure.
+ * @param[in] service_handle The service handle to attach the characteristic to.
+ * @param[in] write_access The write security level for the OACP value handle.
+ * @param[in] cccd_write_access The write security level for the OACP cccd handle.
+ *
+ * @return NRF_SUCCESS When added successfully, else an error code from characteristic_add().
+ */
+static uint32_t oacp_char_add(ble_ots_oacp_t * const p_ots_oacp,
+ uint16_t service_handle,
+ security_req_t write_access,
+ security_req_t cccd_write_access)
+{
+ ble_add_char_params_t add_char_params;
+ memset(&add_char_params, 0, sizeof(add_char_params));
+
+ add_char_params.uuid = BLE_UUID_OTS_OACP;
+ add_char_params.uuid_type = BLE_UUID_TYPE_BLE;
+ add_char_params.max_len = BLE_OTS_MAX_OACP_SIZE;
+ add_char_params.init_len = 0;
+ add_char_params.is_var_len = 1;
+ add_char_params.char_props.indicate = true;
+ add_char_params.char_props.write = true;
+ add_char_params.cccd_write_access = cccd_write_access;
+ //add_char_params.is_defered_write = true;
+ add_char_params.write_access = write_access;
+
+ return characteristic_add(service_handle,
+ &add_char_params,
+ &p_ots_oacp->oacp_handles);
+}
+
+
+/**@brief Handling the OACP write procedure.
+ *
+ * @details The object is opened, and a l2cap transfer is started.
+ *
+ * @param[in] p_ots_oacp Pointer to the OACP structure.
+ * @param[in] offset The offset for where the read should start.
+ * @param[in] length The length of the read.
+ */
+static inline ble_ots_oacp_res_code_t oacp_write_proc(ble_ots_oacp_t * p_ots_oacp,
+ uint32_t offset,
+ uint32_t length,
+ uint8_t mode)
+{
+ uint32_t err_code;
+
+ if (p_ots_oacp->p_ots->p_current_object == NULL)
+ {
+ return BLE_OTS_OACP_RES_INV_OBJ;
+ }
+ if (p_ots_oacp->p_ots->p_current_object->is_valid == false)
+ {
+ return BLE_OTS_OACP_RES_INV_OBJ;
+ }
+
+
+ if (p_ots_oacp->p_ots->p_current_object->properties.decoded.is_write_permitted == false)
+ {
+ return BLE_OTS_OACP_RES_NOT_PERMITTED;
+ }
+
+ if (ble_ots_l2cap_is_channel_available(&p_ots_oacp->ots_l2cap) == false)
+ {
+ return BLE_OTS_OACP_RES_CHAN_UNAVAIL;
+ }
+
+ if (length + offset > p_ots_oacp->p_ots->p_current_object->alloc_len)
+ {
+ return BLE_OTS_OACP_RES_INV_PARAM;
+ }
+
+ if (p_ots_oacp->p_ots->p_current_object->is_locked)
+ {
+ return BLE_OTS_OACP_RES_OBJ_LOCKED;
+ }
+
+ err_code = ble_ots_l2cap_start_recv(&p_ots_oacp->ots_l2cap, length);
+ if (err_code != NRF_SUCCESS)
+ {
+ return BLE_OTS_OACP_RES_OPER_FAILED;
+ }
+
+ ble_ots_evt_t ble_ots_evt;
+
+ ble_ots_evt.type = BLE_OTS_EVT_OACP;
+
+ ble_ots_evt.evt.oacp_evt.type = BLE_OTS_OACP_EVT_REQ_WRITE;
+ ble_ots_evt.evt.oacp_evt.evt.p_object = p_ots_oacp->p_ots->p_current_object;
+
+ p_ots_oacp->p_ots->p_current_object->current_size = length;
+
+ p_ots_oacp->p_ots->evt_handler(p_ots_oacp->p_ots, &ble_ots_evt);
+
+ return BLE_OTS_OACP_RES_SUCCESS;
+}
+
+
+
+/**@brief Handling the OACP read procedure.
+ *
+ * @details The object is opened, and a l2cap transfer is started.
+ *
+ * @param[in] p_ots_oacp Pointer to the OACP structure.
+ * @param[in] offset The offset for where the read should start.
+ * @param[in] length The length of the read.
+ */
+static inline ble_ots_oacp_res_code_t oacp_read_proc(ble_ots_oacp_t * p_ots_oacp,
+ uint32_t offset,
+ uint32_t length)
+{
+
+ if (p_ots_oacp->p_ots->p_current_object == NULL)
+ {
+ return BLE_OTS_OACP_RES_INV_OBJ;
+ }
+ if (p_ots_oacp->p_ots->p_current_object->is_valid == false)
+ {
+ return BLE_OTS_OACP_RES_INV_OBJ;
+ }
+
+
+ if (p_ots_oacp->p_ots->p_current_object->properties.decoded.is_read_permitted == false)
+ {
+ return BLE_OTS_OACP_RES_NOT_PERMITTED;
+ }
+
+ if (ble_ots_l2cap_is_channel_available(&p_ots_oacp->ots_l2cap) == false)
+ {
+ return BLE_OTS_OACP_RES_CHAN_UNAVAIL;
+ }
+
+ if (length + offset > p_ots_oacp->p_ots->p_current_object->current_size)
+ {
+ return BLE_OTS_OACP_RES_INV_PARAM;
+ }
+
+ if (p_ots_oacp->p_ots->p_current_object->is_locked)
+ {
+ return BLE_OTS_OACP_RES_OBJ_LOCKED;
+ }
+
+ ble_ots_evt_t ble_ots_evt;
+
+ ble_ots_evt.type = BLE_OTS_EVT_OACP;
+
+ ble_ots_evt.evt.oacp_evt.type = BLE_OTS_OACP_EVT_REQ_READ;
+ ble_ots_evt.evt.oacp_evt.evt.p_object = p_ots_oacp->p_ots->p_current_object;
+
+ p_ots_oacp->p_ots->evt_handler(p_ots_oacp->p_ots, &ble_ots_evt);
+
+ ret_code_t err_code = ble_ots_l2cap_start_send(&p_ots_oacp->ots_l2cap,
+ p_ots_oacp->p_ots->p_current_object->data,
+ p_ots_oacp->p_ots->p_current_object->current_size);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("ble_ots_l2cap_start_send returned error 0x%x", err_code);
+ }
+ return BLE_OTS_OACP_RES_SUCCESS;
+}
+
+
+/**@brief Handling the OACP abort procedure.
+ *
+ * @details The transmission is aborted.
+ *
+ * @param[in] p_ots_oacp Pointer to the OACP structure.
+ */
+static inline ble_ots_oacp_res_code_t oacp_abort_proc(ble_ots_oacp_t * p_ots_oacp)
+{
+ uint32_t err_code;
+
+ err_code = ble_ots_l2cap_abort_transmission(&p_ots_oacp->ots_l2cap);
+ if (err_code != NRF_SUCCESS)
+ {
+ return BLE_OTS_OACP_RES_OPER_FAILED;
+ }
+
+ p_ots_oacp->p_ots->p_current_object->is_locked = false;
+
+ ble_ots_evt_t ble_ots_evt;
+
+ ble_ots_evt.type = BLE_OTS_EVT_OACP;
+
+ ble_ots_evt.evt.oacp_evt.type = BLE_OTS_OACP_EVT_ABORT;
+ ble_ots_evt.evt.oacp_evt.evt.p_object = p_ots_oacp->p_ots->p_current_object;
+ p_ots_oacp->p_ots->evt_handler(p_ots_oacp->p_ots, &ble_ots_evt);
+
+ return BLE_OTS_OACP_RES_SUCCESS;
+}
+
+/**@brief Sending the oacp procedure response back to the client.
+ *
+ * @details Encodes and sends the response.
+ *
+ * @param[in] p_ots_oacp Pointer to the OACP structure.
+ * @param[in] req_op_code The operation code of the procedure.
+ * @param[in] result_code The result of the procedure.
+ * @param[in] conn_handle The connection handle to send the result to.
+ */
+static uint32_t ble_ots_oacp_response_send(ble_ots_oacp_t * p_ots_oacp,
+ ble_ots_oacp_proc_type_t req_op_code,
+ ble_ots_oacp_res_code_t result_code,
+ uint16_t conn_handle)
+{
+ uint16_t index = 0;
+ uint8_t * p_data;
+ ble_gatts_hvx_params_t *p_hvx_params;
+
+ ble_hvx_t * p_hvx = ble_hvx_get_p_to_next_hvx(&p_ots_oacp->p_ots->hvx_buf);
+ p_data = p_hvx->data;
+ p_hvx_params = &p_hvx->params;
+
+ p_data[index++] = BLE_OTS_OACP_PROC_RESP;
+
+ // Encode the Request Op code
+ p_data[index++] = (uint8_t)req_op_code;
+
+ // Encode the Result code.
+ p_data[index++] = (uint8_t)result_code;
+
+
+ memset(p_hvx_params, 0, sizeof(ble_gatts_hvx_params_t));
+
+ p_hvx_params->handle = p_ots_oacp->oacp_handles.value_handle;
+ p_hvx_params->type = BLE_GATT_HVX_INDICATION;
+ p_hvx_params->offset = 0;
+ p_hvx_params->p_len = &index;
+ p_hvx_params->p_data = p_data;
+
+ return ble_hvx_buffer_process(&p_ots_oacp->p_ots->hvx_buf);
+}
+
+/**@brief Decode an OACP command, and extract its data.
+ *
+ * @param[in] p_ble_write_evt The write event from BLE stack.
+ * @param[out] p_proc The decoded OACP procedure is sent out.
+ *
+ * @return BLE_OTS_WRITE_SUCCESS If the filter was decoded correctly, else an error code.
+ */
+static inline ble_ots_oacp_res_code_t decode_oacp_command(ble_gatts_evt_write_t const * p_ble_write_evt,
+ ble_ots_oacp_proc_t * p_proc)
+{
+ uint32_t index = 0;
+
+ p_proc->type = (ble_ots_oacp_proc_type_t)p_ble_write_evt->data[index++];
+
+ switch (p_proc->type)
+ {
+ case BLE_OTS_OACP_PROC_READ:
+ if (p_ble_write_evt->len !=
+ sizeof(p_proc->params.read_params.offset)
+ + sizeof(p_proc->params.read_params.length)
+ + index)
+ {
+ return BLE_OTS_OACP_RES_INV_PARAM;
+ }
+/*lint --e{415} --e{416} -save suppress Warning 415: Likely access of out-of-bounds pointer */
+ p_proc->params.read_params.offset = uint32_decode(&(p_ble_write_evt->data[index]));
+ index += 4;
+ p_proc->params.read_params.length = uint32_decode(&(p_ble_write_evt->data[index]));
+/*lint -restore*/
+ break;
+ //return BLE_OTS_OACP_RES_SUCCESS;
+ case BLE_OTS_OACP_PROC_WRITE:
+ p_proc->params.write_params.offset = uint32_decode(&(p_ble_write_evt->data[index]));
+ index += sizeof(uint32_t);
+ p_proc->params.write_params.length = uint32_decode(&(p_ble_write_evt->data[index]));
+ index += sizeof(uint32_t);
+ p_proc->params.write_params.write_mode = p_ble_write_evt->data[index];
+ break;
+ default:
+ // No implementation needed
+ break;
+ }
+ return BLE_OTS_OACP_RES_SUCCESS;
+}
+
+
+/**@brief Function for handling the BLE_GAP_EVT_DISCONNECTED event.
+ *
+ * @param[in] p_ots_oacp OTS OACP Structure.
+ * @param[in] p_ble_evt Pointer to the event received from BLE stack.
+ */
+static inline void on_disconnect(ble_ots_oacp_t * p_ots_oacp, ble_evt_t const * p_ble_evt)
+{
+ uint32_t err_code;
+ err_code = fds_gc();
+ if (err_code != NRF_SUCCESS)
+ {
+ p_ots_oacp->p_ots->error_handler(err_code);
+ }
+
+}
+
+
+/**@brief Function for handling the write events to the Blood Pressure Measurement characteristic.
+ *
+ * @param[in] p_bps Blood Pressure Service structure.
+ * @param[in] p_evt_write Write event received from the BLE stack.
+ */
+static void on_cccd_write(ble_ots_oacp_t * p_ots_oacp, ble_gatts_evt_write_t const * p_evt_write)
+{
+ if (p_evt_write->len == 2)
+ {
+ // CCCD written, update indication state
+ if (p_ots_oacp->p_ots->evt_handler != NULL)
+ {
+ ble_ots_evt_t evt;
+
+ if (ble_srv_is_indication_enabled(p_evt_write->data))
+ {
+ evt.type = BLE_OTS_EVT_INDICATION_ENABLED;
+ }
+ else
+ {
+ evt.type = BLE_OTS_EVT_INDICATION_DISABLED;
+ }
+
+ p_ots_oacp->p_ots->evt_handler(p_ots_oacp->p_ots, &evt);
+ }
+ }
+}
+
+
+static void on_oacp_write(ble_ots_oacp_t * p_ots_oacp, ble_gatts_evt_write_t const * p_ble_evt_write)
+{
+ ret_code_t err_code;
+ ble_ots_oacp_res_code_t oacp_status;
+ ble_ots_oacp_proc_t oacp_proc;
+
+ memset(&oacp_proc, 0, sizeof(oacp_proc));
+
+ oacp_status = decode_oacp_command(p_ble_evt_write, &oacp_proc);
+
+ if (oacp_status == BLE_OTS_OACP_RES_SUCCESS)
+ {
+ oacp_status = ble_ots_oacp_do_proc(p_ots_oacp, &oacp_proc);
+ }
+
+ err_code = ble_ots_oacp_response_send(p_ots_oacp,
+ oacp_proc.type,
+ oacp_status,
+ p_ots_oacp->p_ots->conn_handle);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ p_ots_oacp->p_ots->error_handler(err_code);
+ }
+}
+
+
+
+/**@brief Function for handling the Write event.
+ *
+ * @param[in] p_bps Blood Pressure Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_write(ble_ots_oacp_t * p_ots_oacp, ble_evt_t const * p_ble_evt)
+{
+ ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+ if (p_evt_write->handle == p_ots_oacp->p_ots->oacp_chars.oacp_handles.cccd_handle)
+ {
+ on_cccd_write(p_ots_oacp, p_evt_write);
+ }
+ if (p_evt_write->handle == p_ots_oacp->p_ots->oacp_chars.oacp_handles.value_handle)
+ {
+ on_oacp_write(p_ots_oacp, p_evt_write);
+ }
+}
+
+
+void ble_ots_oacp_on_ble_evt(ble_ots_oacp_t * p_ots_oacp, ble_evt_t const * p_ble_evt)
+{
+ if ((p_ots_oacp == NULL) || (p_ble_evt == NULL))
+ {
+ return;
+ }
+
+ ble_ots_l2cap_on_ble_evt(&p_ots_oacp->ots_l2cap, p_ble_evt);
+
+ switch (p_ble_evt->header.evt_id)
+ {
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnect(p_ots_oacp, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_WRITE:
+ on_write(p_ots_oacp, p_ble_evt);
+ break;
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+uint32_t ble_ots_oacp_init(ble_ots_oacp_t * p_ots_oacp, ble_ots_oacp_init_t * p_ots_oacp_init)
+{
+ uint32_t err_code;
+
+ if (p_ots_oacp == NULL || p_ots_oacp_init == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+ p_ots_oacp->p_ots = p_ots_oacp_init->p_ots;
+ p_ots_oacp->on_create_obj_properties_raw = p_ots_oacp_init->on_create_obj_properties_raw;
+
+ ble_ots_l2cap_init_t l2cap_init;
+
+ l2cap_init.p_ots_oacp = p_ots_oacp;
+ l2cap_init.evt_handler = ots_l2cap_evt_handler;
+ l2cap_init.p_transfer_buffer = p_ots_oacp_init->p_l2cap_buffer;
+ l2cap_init.buffer_len = p_ots_oacp_init->l2cap_buffer_len;
+
+ err_code = ble_ots_l2cap_init(&p_ots_oacp->ots_l2cap, &l2cap_init);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+
+ return oacp_char_add(p_ots_oacp,
+ p_ots_oacp->p_ots->service_handle,
+ p_ots_oacp_init->write_access,
+ p_ots_oacp_init->cccd_write_access);
+}
+
+
+ble_ots_oacp_res_code_t ble_ots_oacp_do_proc(ble_ots_oacp_t * p_ots_oacp,
+ ble_ots_oacp_proc_t * p_oacp_proc)
+{
+ if (p_ots_oacp == NULL || p_oacp_proc == NULL)
+ {
+ return BLE_OTS_OACP_RES_INV_PARAM;
+ }
+
+ ble_ots_oacp_res_code_t oacp_status;
+
+ switch (p_oacp_proc->type)
+ {
+ case BLE_OTS_OACP_PROC_WRITE:
+ oacp_status = oacp_write_proc(p_ots_oacp,
+ p_oacp_proc->params.write_params.offset,
+ p_oacp_proc->params.write_params.length,
+ p_oacp_proc->params.write_params.write_mode);
+ break;
+ case BLE_OTS_OACP_PROC_READ:
+ oacp_status = oacp_read_proc(p_ots_oacp,
+ p_oacp_proc->params.read_params.offset,
+ p_oacp_proc->params.read_params.length);
+ break;
+
+ case BLE_OTS_OACP_PROC_ABORT:
+ oacp_status = oacp_abort_proc(p_ots_oacp);
+ break;
+
+ default:
+ // Unsupported op code.
+ oacp_status = BLE_OTS_OACP_RES_OPCODE_NOT_SUP;
+
+ }
+ return oacp_status;
+}
+
+
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_oacp.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_oacp.h
new file mode 100644
index 0000000..9f41204
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_oacp.h
@@ -0,0 +1,90 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/**@file
+ *
+ * @defgroup ble_sdk_srv_ots_oacp Object Transfer Service, OACP handling
+ * @{
+ * @ingroup ble_ots
+ * @brief Object Transfer Service module
+ *
+ * @details This module is responsible for handling the Object Transfer Service
+ * Object Action Control Point.
+ */
+#ifndef BLE_OTS_OACP_H__
+#define BLE_OTS_OACP_H__
+
+#include <stdint.h>
+#include "ble_ots.h"
+
+/**@brief Function for initializing the Object Transfer OACP characteristic.
+ *
+ * @param[out] p_ots_oacp Object Transfer Service OACP structure. This structure will have
+ * to be supplied by the application. It will be initialized by this function,
+ * and will later be used to identify this particular instance.
+ * @param[in] p_ots_oacp_init Information needed to initialize the module.
+ *
+ * @return NRF_SUCCESS on successful initialization, otherwise an error code.
+ */
+uint32_t ble_ots_oacp_init(ble_ots_oacp_t * p_ots_oacp, ble_ots_oacp_init_t * p_ots_oacp_init);
+
+/**@brief Function for handling the Application's BLE Stack events.
+ *
+ * @details Handles all events from the BLE stack of interest to the OACP module.
+ *
+ * @param[in] p_ots_oacp Object Transfer Service OACP structure
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+void ble_ots_oacp_on_ble_evt(ble_ots_oacp_t * p_ots_oacp, ble_evt_t const * p_ble_evt);
+
+/**@brief Execute an Object Action Control Point procedure
+ *
+ * @param[in] p_ots_oacp Object Transfer Service OACP structure.
+ * @param[in] p_oacp_proc Pointer to the procedure to be applied.
+ *
+ * @return BLE_OTS_WRITE_SUCCESS on success, otherwise an error.
+ */
+ble_ots_oacp_res_code_t ble_ots_oacp_do_proc(ble_ots_oacp_t * p_ots_oacp,
+ ble_ots_oacp_proc_t * p_oacp_proc);
+
+
+#endif // BLE_OTS_OACP_H__
+
+/** @} */ // End tag for the file.
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_object.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_object.c
new file mode 100644
index 0000000..0abc39d
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_object.c
@@ -0,0 +1,577 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "ble_ots_object.h"
+
+#include <string.h>
+#include "ble_srv_common.h"
+
+#include "ble_ots.h"
+
+#define BLE_OTS_WRITE_REQUEST_REJECTED 0x80
+
+#define BLE_OTS_OBJECT_NOT_SELECTED 0x81
+#define BLE_OTS_CONCURRENCY_LIMIT_EXCEEDED 0x82
+#define BLE_OTS_OBJ_NAME_ALREADY_EXISTS 0x83
+#define BLE_SIZE_DATE_TIME 7
+
+
+uint32_t ble_ots_object_refresh_current(ble_ots_object_chars_t * p_ots_object_chars)
+{
+ uint32_t err_code;
+ ble_ots_object_t * p_obj;
+
+ p_obj = p_ots_object_chars->p_ots->p_current_object;
+
+ if (p_obj == NULL)
+ {
+ // Clear all characteristics
+ return NRF_SUCCESS;
+ }
+
+
+ // obtain the largest necessary buffer
+ typedef union {
+ uint8_t type_buf[sizeof(ble_ots_obj_type_t)+sizeof(uint8_t)];
+ uint8_t size_buf[2*sizeof(uint32_t)];
+ uint8_t prop_buf[sizeof(uint32_t)];
+ } buffer_t;
+
+ buffer_t buffer;
+
+ ble_gatts_value_t gatts_value;
+
+ memset(&gatts_value, 0, sizeof(gatts_value));
+
+ // name
+ gatts_value.len = strlen((const char *)p_obj->name) + 1;
+ gatts_value.p_value = p_obj->name;
+ err_code = sd_ble_gatts_value_set(p_ots_object_chars->p_ots->conn_handle,
+ p_ots_object_chars->obj_name_handles.value_handle,
+ &gatts_value);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // type
+ if (p_obj->type.len == sizeof(uint16_t))
+ {
+ gatts_value.len = uint16_encode(p_obj->type.param.type16, buffer.type_buf);
+ gatts_value.p_value = buffer.type_buf;
+ err_code = sd_ble_gatts_value_set(p_ots_object_chars->p_ots->conn_handle,
+ p_ots_object_chars->obj_type_handles.value_handle,
+ &gatts_value);
+ }
+ else
+ {
+ gatts_value.len = uint16_encode(p_obj->type.param.type16, buffer.type_buf);
+ gatts_value.p_value = p_obj->type.param.type128;
+ err_code = sd_ble_gatts_value_set(p_ots_object_chars->p_ots->conn_handle,
+ p_ots_object_chars->obj_type_handles.value_handle,
+ &gatts_value);
+ }
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ gatts_value.len = uint32_encode(p_obj->current_size, &buffer.size_buf[0]);
+ gatts_value.len += uint32_encode(p_obj->alloc_len, &buffer.size_buf[gatts_value.len]);
+ gatts_value.p_value = &buffer.size_buf[0];
+ err_code = sd_ble_gatts_value_set(p_ots_object_chars->p_ots->conn_handle,
+ p_ots_object_chars->obj_size_handles.value_handle,
+ &gatts_value);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ gatts_value.len = uint32_encode(p_obj->properties.raw, buffer.prop_buf);
+ gatts_value.p_value = buffer.prop_buf;
+ err_code = sd_ble_gatts_value_set(p_ots_object_chars->p_ots->conn_handle,
+ p_ots_object_chars->obj_properties_handles.value_handle,
+ &gatts_value);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ return NRF_SUCCESS;
+}
+
+/**@brief Function for adding the object name characteristic.
+ *
+ * @param[in] p_ots_object_chars Pointer the the object characteristics.
+ * @param[in] service_handle The service handle where the characteristic should be added.
+ * @param[in] read_access The read security level for the characteristic.
+ * @param[in] write_access The write security level for the characteristic.
+ *
+ * @return NRF_SUCCESS if the characteristic was successfully added, else a return code from
+ * characteristic_add().
+ */
+static uint32_t obj_name_char_add(ble_ots_object_chars_t * const p_ots_object_chars,
+ uint16_t service_handle,
+ security_req_t read_access,
+ security_req_t write_access)
+{
+ ble_add_char_params_t add_char_params;
+
+ memset(&add_char_params, 0, sizeof(add_char_params));
+
+ add_char_params.uuid = BLE_UUID_OTS_OBJECT_NAME;
+ add_char_params.uuid_type = BLE_UUID_TYPE_BLE;
+ add_char_params.max_len = BLE_OTS_NAME_MAX_SIZE;
+ add_char_params.is_var_len = 1;
+ add_char_params.char_props.read = 1;
+ add_char_params.read_access = read_access;
+ add_char_params.char_props.write = 0;
+
+ return characteristic_add(service_handle,
+ &add_char_params,
+ &p_ots_object_chars->obj_name_handles);
+}
+
+/**@brief Function for adding the object type characteristic.
+ *
+ * @param[in] p_ots_object_chars Pointer the the object characteristics.
+ * @param[in] service_handle The service handle where the characteristic should be added.
+ * @param[in] read_access The read security level for the characteristic.
+ *
+ * @return NRF_SUCCESS if the characteristic was successfully added, else a return code from
+ * characteristic_add().
+ */
+static uint32_t obj_type_char_add(ble_ots_object_chars_t * const p_ots_object_chars,
+ uint16_t service_handle,
+ security_req_t read_access)
+{
+ ble_add_char_params_t add_char_params;
+
+ memset(&add_char_params, 0, sizeof(add_char_params));
+
+ add_char_params.uuid = BLE_UUID_OTS_OBJECT_TYPE;
+ add_char_params.uuid_type = BLE_UUID_TYPE_BLE;
+ add_char_params.max_len = sizeof(ble_ots_obj_type_t);
+ add_char_params.is_var_len = 1;
+ add_char_params.char_props.read = 1;
+ add_char_params.read_access = read_access;
+
+ return characteristic_add(service_handle,
+ &add_char_params,
+ &p_ots_object_chars->obj_type_handles);
+}
+
+/**@brief Function for adding the object size characteristic.
+ *
+ * @param[in] p_ots_object_chars Pointer the the object characteristics.
+ * @param[in] service_handle The service handle where the characteristic should be added.
+ * @param[in] read_access The read security level for the characteristic.
+ *
+ * @return NRF_SUCCESS if the characteristic was successfully added, else a return code from
+ * characteristic_add().
+ */
+static uint32_t obj_size_char_add(ble_ots_object_chars_t * const p_ots_object_chars,
+ uint16_t service_handle,
+ security_req_t read_access)
+{
+ ble_add_char_params_t add_char_params;
+
+ memset(&add_char_params, 0, sizeof(add_char_params));
+
+ add_char_params.uuid = BLE_UUID_OTS_OBJECT_SIZE;
+ add_char_params.uuid_type = BLE_UUID_TYPE_BLE;
+ add_char_params.max_len = NRF_BLE_OTS_SIZE_CHAR_LEN;
+ add_char_params.is_var_len = 0;
+ add_char_params.char_props.read = 1;
+ add_char_params.read_access = read_access;
+
+ return characteristic_add(service_handle,
+ &add_char_params,
+ &p_ots_object_chars->obj_size_handles);
+}
+
+/**@brief Function for adding the object properties characteristic.
+ *
+ * @param[in] p_ots_object_chars Pointer the the object characteristics.
+ * @param[in] service_handle The service handle where the characteristic should be added.
+ * @param[in] read_access The read security level for the characteristic.
+ * @param[in] write_access The write security level for the characteristic.
+ *
+ * @return NRF_SUCCESS if the characteristic was successfully added, else a return code from
+ * characteristic_add().
+ */
+static uint32_t obj_prop_char_add(ble_ots_object_chars_t * const p_ots_object_chars,
+ uint16_t service_handle,
+ security_req_t read_access,
+ security_req_t write_access)
+{
+ ble_add_char_params_t add_char_params;
+
+ memset(&add_char_params, 0, sizeof(add_char_params));
+
+ add_char_params.uuid = BLE_UUID_OTS_OBJECT_PROPERTIES;
+ add_char_params.uuid_type = BLE_UUID_TYPE_BLE;
+ add_char_params.max_len = sizeof(uint32_t);
+ add_char_params.is_var_len = 0;
+ add_char_params.char_props.read = 1;
+ add_char_params.read_access = read_access;
+
+ add_char_params.is_defered_write = 1;
+ add_char_params.write_access = write_access;
+
+ return characteristic_add(service_handle,
+ &add_char_params,
+ &p_ots_object_chars->obj_properties_handles);
+}
+
+
+
+
+
+uint32_t ble_ots_object_representation_init(ble_ots_object_chars_t * p_ots_object_chars,
+ ble_ots_object_chars_init_t * p_ots_object_chars_init)
+{
+ if (p_ots_object_chars == NULL || p_ots_object_chars_init == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ uint32_t err_code;
+
+ p_ots_object_chars->p_ots = p_ots_object_chars_init->p_ots;
+
+ err_code = obj_name_char_add(p_ots_object_chars,
+ p_ots_object_chars_init->p_ots->service_handle,
+ p_ots_object_chars_init->name_read_access,
+ p_ots_object_chars_init->name_write_access);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ err_code = obj_type_char_add(p_ots_object_chars,
+ p_ots_object_chars_init->p_ots->service_handle,
+ p_ots_object_chars_init->type_read_access);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ err_code = obj_size_char_add(p_ots_object_chars,
+ p_ots_object_chars_init->p_ots->service_handle,
+ p_ots_object_chars_init->size_read_access);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ err_code = obj_prop_char_add(p_ots_object_chars,
+ p_ots_object_chars_init->p_ots->service_handle,
+ p_ots_object_chars_init->properties_read_access,
+ p_ots_object_chars_init->properties_write_access);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ return ble_ots_object_refresh_current(p_ots_object_chars);
+}
+
+
+uint32_t ble_ots_object_set_name(ble_ots_object_chars_t * p_ots_object_chars,
+ ble_ots_object_t * p_object,
+ const char * new_name)
+{
+ if (p_ots_object_chars == NULL || p_object == NULL || new_name == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+
+
+ strncpy((char *)p_object->name, new_name, BLE_OTS_NAME_MAX_SIZE);
+
+ if (p_object == p_ots_object_chars->p_ots->p_current_object)
+ {
+ // update characteristic
+ uint32_t err_code;
+ ble_gatts_value_t gatts_value;
+
+ memset(&gatts_value, 0, sizeof(gatts_value));
+
+ gatts_value.len = strlen((const char *)p_object->name) + 1;
+ gatts_value.p_value = p_object->name;
+ err_code = sd_ble_gatts_value_set(p_ots_object_chars->p_ots->conn_handle,
+ p_ots_object_chars->obj_name_handles.value_handle,
+ &gatts_value);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+
+ return NRF_SUCCESS;
+}
+
+uint32_t ble_ots_object_set_type(ble_ots_object_chars_t * p_ots_object_chars,
+ ble_ots_object_t * p_object,
+ ble_ots_obj_type_t * p_new_type)
+{
+ if (p_ots_object_chars == NULL || p_object == NULL || p_new_type == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ if (p_new_type->len != sizeof(p_new_type->param.type16) && p_new_type->len != sizeof(p_new_type->param.type128))
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ memcpy(&p_object->type, p_new_type, sizeof(ble_ots_obj_type_t));
+
+ if (p_object == p_ots_object_chars->p_ots->p_current_object)
+ {
+ // update characteristic
+ uint32_t err_code;
+ uint8_t buffer[sizeof(p_new_type->param.type16)];
+ ble_gatts_value_t gatts_value;
+
+ memset(&gatts_value, 0, sizeof(gatts_value));
+
+ if (p_object->type.len == sizeof(uint16_t))
+ {
+ gatts_value.len = uint16_encode(p_object->type.param.type16, buffer);
+ gatts_value.p_value = buffer;
+ err_code = sd_ble_gatts_value_set(p_ots_object_chars->p_ots->conn_handle,
+ p_ots_object_chars->obj_type_handles.value_handle,
+ &gatts_value);
+ }
+ else
+ {
+ gatts_value.len = uint16_encode(p_object->type.param.type16, buffer);
+ gatts_value.p_value = p_object->type.param.type128;
+ err_code = sd_ble_gatts_value_set(p_ots_object_chars->p_ots->conn_handle,
+ p_ots_object_chars->obj_type_handles.value_handle,
+ &gatts_value);
+ }
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+
+ return NRF_SUCCESS;
+
+}
+
+uint32_t ble_ots_object_set_current_size(ble_ots_object_chars_t * p_ots_object_chars,
+ ble_ots_object_t * p_object,
+ uint32_t new_current_size)
+{
+ if (p_ots_object_chars == NULL || p_object == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ p_object->current_size = new_current_size;
+
+ if (p_object == p_ots_object_chars->p_ots->p_current_object)
+ {
+ // update characteristic
+ uint32_t err_code;
+ uint8_t buffer[NRF_BLE_OTS_SIZE_CHAR_LEN];
+ ble_gatts_value_t gatts_value;
+
+ memset(&gatts_value, 0, sizeof(gatts_value));
+
+ gatts_value.len = 0;
+ gatts_value.len += uint32_encode(p_object->current_size, &buffer[gatts_value.len]);
+ gatts_value.len += uint32_encode(p_object->alloc_len, &buffer[gatts_value.len]);
+ gatts_value.p_value = &buffer[0];
+ err_code = sd_ble_gatts_value_set(p_ots_object_chars->p_ots->conn_handle,
+ p_ots_object_chars->obj_size_handles.value_handle,
+ &gatts_value);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+
+ return NRF_SUCCESS;
+
+}
+
+
+/**@brief Function for handling write on object properties meta data.
+ *
+ * @param[in] p_ots_object_chars Pointer the the object characteristics.
+ * @param[in] p_ble_evt Pointer to the event received from BLE stack.
+ */
+static uint32_t on_obj_properties_write(ble_ots_object_chars_t * p_ots_object_chars,
+ ble_evt_t const * p_ble_evt)
+{
+// uint32_t err_code;
+ ble_gatts_rw_authorize_reply_params_t write_authorize_reply;
+ ble_gatts_evt_write_t const * p_write_evt;
+
+ p_write_evt = &p_ble_evt->evt.gatts_evt.params.authorize_request.request.write;
+
+ write_authorize_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
+
+ uint32_t raw_prop = uint32_decode(p_write_evt->data);
+ if ((raw_prop & 0xFFFFFF80) != 0)
+ {
+ write_authorize_reply.params.write.gatt_status = BLE_OTS_WRITE_REQUEST_REJECTED;
+ }
+ else
+ {
+ p_ots_object_chars->p_ots->p_current_object->properties.raw = raw_prop;
+ write_authorize_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+
+ ble_ots_evt_t ble_ots_evt;
+
+ ble_ots_evt.type = BLE_OTS_EVT_OBJECT;
+
+ ble_ots_evt.evt.object_evt.type = BLE_OTS_OBJECT_EVT_PROPERTIES_CHANGED;
+ ble_ots_evt.evt.object_evt.evt.p_object = p_ots_object_chars->p_ots->p_current_object;
+ p_ots_object_chars->p_ots->evt_handler(p_ots_object_chars->p_ots, &ble_ots_evt);
+
+ }
+ return sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gatts_evt.conn_handle, &write_authorize_reply);
+}
+
+uint32_t ble_ots_object_set_properties(ble_ots_object_chars_t * p_ots_object_chars,
+ ble_ots_object_t * p_object,
+ ble_ots_obj_properties_t * p_new_properties)
+{
+ if (p_ots_object_chars == NULL || p_object == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ memcpy(&p_object->properties, p_new_properties, sizeof(ble_ots_obj_properties_t));
+
+
+ if (p_object == p_ots_object_chars->p_ots->p_current_object)
+ {
+ // update characteristic
+ uint32_t err_code;
+ uint8_t buffer[sizeof(ble_ots_obj_properties_t)];
+ ble_gatts_value_t gatts_value;
+
+ memset(&gatts_value, 0, sizeof(gatts_value));
+
+ gatts_value.len = uint32_encode(p_object->properties.raw, buffer);
+ gatts_value.p_value = buffer;
+ err_code = sd_ble_gatts_value_set(p_ots_object_chars->p_ots->conn_handle,
+ p_ots_object_chars->obj_properties_handles.value_handle,
+ &gatts_value);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for handling the @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST event.
+ *
+ * @param[in] p_ots_object_chars Pointer the the object characteristics.
+ * @param[in] p_ble_evt Pointer to the event received from BLE stack.
+ */
+static void on_rw_auth_req(ble_ots_object_chars_t * p_ots_object_chars, ble_evt_t const * p_ble_evt)
+{
+ uint32_t err_code;
+ ble_gatts_evt_rw_authorize_request_t const * p_authorize_request;
+
+ p_authorize_request = &(p_ble_evt->evt.gatts_evt.params.authorize_request);
+
+ if (p_authorize_request->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
+ {
+ if (p_authorize_request->request.write.handle == p_ots_object_chars->obj_name_handles.value_handle)
+ {
+ //err_code = on_name_prepare_write(p_ots_object_chars, p_ble_evt);
+
+ // if (err_code != NRF_SUCCESS)
+ // {
+ // p_ots_object_chars->p_ots->error_handler(err_code);
+ // }
+ }
+ else
+ if (p_authorize_request->request.write.handle == p_ots_object_chars->obj_properties_handles.value_handle)
+ {
+ err_code = on_obj_properties_write(p_ots_object_chars, p_ble_evt);
+ if (err_code != NRF_SUCCESS)
+ {
+ p_ots_object_chars->p_ots->error_handler(err_code);
+ }
+ }
+ }
+}
+
+
+void ble_ots_object_on_ble_evt(ble_ots_object_chars_t * p_ots_chars, ble_evt_t const * p_ble_evt)
+{
+ if ((p_ots_chars == NULL) || (p_ble_evt == NULL))
+ {
+ return;
+ }
+// uint32_t err_code;
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+// err_code = ble_ots_object_refresh_current(p_ots_chars);
+// if (err_code != NRF_SUCCESS)
+// {
+// p_ots_chars->p_ots->error_handler(err_code);
+// }
+ break;
+
+ case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
+ on_rw_auth_req(p_ots_chars, p_ble_evt);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_object.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_object.h
new file mode 100644
index 0000000..b42a24d
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_ble_ots/ble_ots_object.h
@@ -0,0 +1,86 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+ /**@file
+ *
+ * @defgroup ble_sdk_srv_ots_obj Object Transfer Service, Object characteristics
+ * @{
+ * @ingroup ble_ots
+ * @brief Object Transfer Service module
+ *
+ * @details This module is responsible for the object properties characteristics.
+ */
+
+#ifndef BLE_OTS_OBJECT_H__
+#define BLE_OTS_OBJECT_H__
+
+#include <stdint.h>
+#include "ble_ots.h"
+
+/**@brief Function for initializing the Object Transfer Object representation characteristics.
+ *
+ * @param[out] p_ots_object_chars Object Transfer Service object characteristics representation structure. * This structure will have to be supplied by the application. It * will be initialized by this function, and will later be used to * identify this particular instance.
+ * @param[in] p_ots_object_chars_init Information needed to initialize the module.
+ *
+ * @return NRF_SUCCESS on successful initialization, otherwise an error code.
+ */
+uint32_t ble_ots_object_representation_init(ble_ots_object_chars_t * p_ots_object_chars,
+ ble_ots_object_chars_init_t * p_ots_object_chars_init);
+
+/**@brief Refresh the characteristics of the current object.
+ * @param[in] p_ots_object_chars Pointer the the object characteristics.
+ * @return NRF_SUCCESS if everything was refreshed.
+ */
+uint32_t ble_ots_object_refresh_current(ble_ots_object_chars_t * p_ots_object_chars);
+
+
+/**@brief Function for handling the Application's BLE Stack events.
+ *
+ * @details Handles all events from the BLE stack of interest to the list filter module.
+ *
+ * @param[in] p_ots_object_chars Pointer the the object characteristics.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+void ble_ots_object_on_ble_evt(ble_ots_object_chars_t * p_ots_object_chars,
+ ble_evt_t const * p_ble_evt);
+
+#endif // BLE_OTS_OBJECT_H__
+
+/** @} */ // End tag for the file.
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_gatts_c/nrf_ble_gatts_c.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_gatts_c/nrf_ble_gatts_c.c
new file mode 100644
index 0000000..8450ad6
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_gatts_c/nrf_ble_gatts_c.c
@@ -0,0 +1,276 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(NRF_BLE_GATTS_C)
+
+#include "nrf_ble_gatts_c.h"
+#include <string.h>
+#include "ble.h"
+
+#define NRF_LOG_MODULE_NAME nrf_ble_gatts_c
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+
+#define GATTS_LOG NRF_LOG_DEBUG /**< A debug logger macro that can be used in this file to perform logging over UART. */
+#define MODULE_INITIALIZED (p_gatts_c->initialized) /**< Macro indicating whether the module has been initialized properly. */
+
+static const ble_uuid_t m_gatts_uuid = {BLE_UUID_GATT, BLE_UUID_TYPE_BLE}; /**< Service Changed indication UUID. */
+
+
+/**@brief Function for handling the indication and notifications from the GATT Service Server.
+
+ @param[in] p_gatts_c Pointer to Service Changed client structure.
+ @param[in] p_ble_gattc_evt Pointer to a gattc event.
+*/
+static void on_hvx(nrf_ble_gatts_c_t const * const p_gatts_c,
+ ble_gattc_evt_t const * const p_ble_gattc_evt)
+{
+ uint16_t srv_changed_handle = p_gatts_c->srv_changed_char.characteristic.handle_value;
+
+ if ((p_ble_gattc_evt->params.hvx.handle == srv_changed_handle)
+ && (p_gatts_c->evt_handler != NULL))
+ {
+ ret_code_t err_code = sd_ble_gattc_hv_confirm(p_ble_gattc_evt->conn_handle,
+ srv_changed_handle);
+
+ if ((err_code != NRF_SUCCESS) && (p_gatts_c->err_handler != NULL))
+ {
+ p_gatts_c->err_handler(err_code);
+ }
+
+ nrf_ble_gatts_c_evt_t evt;
+ nrf_ble_gatts_c_evt_handler_t evt_handler = p_gatts_c->evt_handler;
+
+ /*lint --e{415} --e{416} -save suppress Warning 415: Likely access of out-of-bounds pointer */
+ evt.params.handle_range.start_handle = uint16_decode(p_ble_gattc_evt->params.hvx.data);
+ evt.params.handle_range.end_handle = uint16_decode(p_ble_gattc_evt->params.hvx.data + sizeof(uint16_t));
+ /*lint -restore*/
+
+ evt.evt_type = NRF_BLE_GATTS_C_EVT_SRV_CHANGED;
+ evt.conn_handle = p_ble_gattc_evt->conn_handle;
+
+ GATTS_LOG ("Service Changed Indication.\n\r");
+ evt_handler(&evt);
+
+ }
+}
+
+
+ret_code_t nrf_ble_gatts_c_init(nrf_ble_gatts_c_t * p_gatts_c,
+ nrf_ble_gatts_c_init_t * p_gatts_c_init)
+{
+ ret_code_t err_code = NRF_SUCCESS;
+ VERIFY_PARAM_NOT_NULL(p_gatts_c);
+ VERIFY_PARAM_NOT_NULL(p_gatts_c_init);
+ VERIFY_PARAM_NOT_NULL(p_gatts_c_init->evt_handler);
+ memset (p_gatts_c, 0, sizeof(nrf_ble_gatts_c_t));
+
+ p_gatts_c->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_gatts_c->evt_handler = p_gatts_c_init->evt_handler;
+
+ err_code = ble_db_discovery_evt_register(&m_gatts_uuid);
+ VERIFY_SUCCESS(err_code);
+
+ p_gatts_c->initialized = true;
+ return err_code;
+}
+
+
+/**@brief Function for checking whether the peer's GATT Service instance and the Service Changed
+ Characteristic have been discovered.
+
+ @param[in] p_gatts_c Pointer to the GATT Service client structure instance.
+
+ @return True if the Service Changed Characteristic handle is valid.
+ @return False if the Service Changed Characteristic handle is invalid.
+ */
+static bool gatts_gatt_handles_are_valid(nrf_ble_gatts_c_t const * const p_gatts_c)
+{
+ return (p_gatts_c->srv_changed_char.characteristic.handle_value != BLE_GATT_HANDLE_INVALID);
+}
+
+
+ret_code_t nrf_ble_gatts_c_enable_indication(nrf_ble_gatts_c_t * const p_gatts_c,
+ bool const enable)
+{
+ VERIFY_MODULE_INITIALIZED();
+
+ if ( (p_gatts_c->conn_handle == BLE_CONN_HANDLE_INVALID)
+ || !(gatts_gatt_handles_are_valid(p_gatts_c)))
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ ret_code_t err_code = NRF_SUCCESS;
+ uint16_t cccd_val = (enable) ? BLE_GATT_HVX_INDICATION : 0;
+
+ ble_gattc_write_params_t gattc_params =
+ {
+ .handle = p_gatts_c->srv_changed_char.cccd_handle,
+ .len = BLE_CCCD_VALUE_LEN,
+ .p_value = (uint8_t *)&cccd_val,
+ .offset = 0,
+ .write_op = BLE_GATT_OP_WRITE_REQ,
+ };
+
+ err_code = sd_ble_gattc_write(p_gatts_c->conn_handle, &gattc_params);
+ return err_code;
+}
+
+
+void nrf_ble_gatts_c_on_db_disc_evt(nrf_ble_gatts_c_t const * const p_gatts_c,
+ ble_db_discovery_evt_t * const p_evt)
+{
+ VERIFY_MODULE_INITIALIZED_VOID();
+
+ nrf_ble_gatts_c_evt_t evt;
+ ble_gatt_db_char_t * p_chars;
+
+ p_chars = p_evt->params.discovered_db.charateristics;
+ evt.evt_type = NRF_BLE_GATTS_C_EVT_DISCOVERY_FAILED;
+
+ if ( (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE)
+ && (p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_GATT)
+ && (p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE))
+ {
+ // Find the handles of the Service Changed Characteristics.
+ for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
+ {
+ if ( (p_chars[i].characteristic.uuid.uuid == BLE_UUID_GATT_CHARACTERISTIC_SERVICE_CHANGED)
+ && (p_chars[i].characteristic.char_props.indicate != 0))
+ {
+ memcpy(&evt.params.srv_changed_char,
+ &p_chars[i],
+ sizeof(ble_gatt_db_char_t));
+
+ evt.evt_type = NRF_BLE_GATTS_C_EVT_DISCOVERY_COMPLETE;
+ GATTS_LOG("Service Changed Characteristic found.\n\r");
+ break;
+ }
+ }
+ }
+
+ if (p_gatts_c->evt_handler != NULL)
+ {
+ nrf_ble_gatts_c_evt_handler_t evt_handler = p_gatts_c->evt_handler;
+ evt.conn_handle = p_evt->conn_handle;
+ evt_handler(&evt);
+ }
+}
+
+
+/**@brief Function for handling the Disconnect event.
+
+ @param[in] p_cts Pointer to the GATT Service client structure instance.
+ @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_disconnect(nrf_ble_gatts_c_t * p_gatts_c, ble_evt_t const * p_ble_evt)
+{
+ if (p_gatts_c->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
+ {
+ p_gatts_c->conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ if (gatts_gatt_handles_are_valid(p_gatts_c))
+ {
+ // There was a valid instance of GATTS on the peer. Send an event to the
+ // application, so that it can do any clean up related to this module.
+ nrf_ble_gatts_c_evt_t evt;
+
+ evt.evt_type = NRF_BLE_GATTS_C_EVT_DISCONN_COMPLETE;
+
+ p_gatts_c->evt_handler(&evt);
+ p_gatts_c->srv_changed_char.characteristic.handle_value = BLE_GATT_HANDLE_INVALID;
+ p_gatts_c->srv_changed_char.cccd_handle = BLE_GATT_HANDLE_INVALID;
+ p_gatts_c->srv_changed_char.ext_prop_handle = BLE_GATT_HANDLE_INVALID;
+ p_gatts_c->srv_changed_char.report_ref_handle = BLE_GATT_HANDLE_INVALID;
+ p_gatts_c->srv_changed_char.user_desc_handle = BLE_GATT_HANDLE_INVALID;
+ }
+ }
+}
+
+
+void nrf_ble_gatts_c_on_ble_evt(ble_evt_t const * p_ble_evt,
+ void * p_context)
+{
+ nrf_ble_gatts_c_t * p_gatts_c;
+ p_gatts_c = p_context;
+
+ VERIFY_MODULE_INITIALIZED_VOID();
+ VERIFY_PARAM_NOT_NULL_VOID(p_gatts_c);
+ VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnect(p_gatts_c, p_ble_evt);
+ break;
+
+ case BLE_GATTC_EVT_HVX:
+ on_hvx(p_gatts_c, &(p_ble_evt->evt.gattc_evt));
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+ret_code_t nrf_ble_gatts_c_handles_assign(nrf_ble_gatts_c_t * const p_gatts_c,
+ uint16_t const conn_handle,
+ ble_gatt_db_char_t const * const p_peer_handles)
+{
+ VERIFY_PARAM_NOT_NULL(p_gatts_c);
+ VERIFY_MODULE_INITIALIZED();
+
+ p_gatts_c->conn_handle = conn_handle;
+ if (p_peer_handles != NULL)
+ {
+ p_gatts_c->srv_changed_char.cccd_handle = p_peer_handles->cccd_handle;
+ p_gatts_c->srv_changed_char.ext_prop_handle = p_peer_handles->ext_prop_handle;
+ p_gatts_c->srv_changed_char.report_ref_handle = p_peer_handles->report_ref_handle;
+ p_gatts_c->srv_changed_char.user_desc_handle = p_peer_handles->user_desc_handle;
+ p_gatts_c->srv_changed_char.characteristic.handle_value = p_peer_handles->characteristic.handle_value;
+
+ }
+ return NRF_SUCCESS;
+}
+#endif // NRF_MODULE_ENABLED(BLE_GATTS_C)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_gatts_c/nrf_ble_gatts_c.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_gatts_c/nrf_ble_gatts_c.h
new file mode 100644
index 0000000..fb488f0
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_gatts_c/nrf_ble_gatts_c.h
@@ -0,0 +1,229 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/** @file
+ *
+ * @defgroup nrf_ble_gatts_c GATT Service Client
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief GATT Service Client module.
+ *
+ * @details This module implements a client for the Generic Attribute Profile (GATT) Service.
+ * It subscribes to indications from the Service Changed Characteristic (0x2A05).
+ *
+ * @note The application must register this module as a BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * ble_gatts_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, BLE_GATTS_BLE_OBSERVER_PRIO,
+ * nrf_ble_gatts_c_on_ble_evt, &instance);
+ * @endcode
+*/
+
+
+#ifndef NRF_BLE_GATTS_C_H__
+#define NRF_BLE_GATTS_C_H__
+
+#include <stdint.h>
+#include "ble_gattc.h"
+#include "ble.h"
+#include "nrf_error.h"
+#include "ble_srv_common.h"
+#include "ble_db_discovery.h"
+#include "sdk_errors.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a nrf_ble_gatts_c instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define NRF_BLE_GATTS_C_DEF(_name) \
+static nrf_ble_gatts_c_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ NRF_BLE_GATTS_C_BLE_OBSERVER_PRIO, \
+ nrf_ble_gatts_c_on_ble_evt, &_name)
+
+/** @brief Macro for defining multiple nrf_ble_gatts_c instances.
+ *
+ * @param _name Name of the array of instances.
+ * @param _cnt Number of instances to define.
+ * @hideinitializer
+ */
+#define NRF_BLE_GATTS_C_ARRAY_DEF(_name, _cnt) \
+static nrf_ble_gatts_c_t _name[_cnt]; \
+NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
+ NRF_BLE_GATTS_C_BLE_OBSERVER_PRIO, \
+ nrf_ble_gatts_c_on_ble_evt, &_name, _cnt)
+
+/**@brief Type of the GATT Service client event. */
+typedef enum
+{
+ NRF_BLE_GATTS_C_EVT_DISCOVERY_COMPLETE, /**< Event indicating that the GATT Service and Service Changed Characteristic have been found on the peer. */
+ NRF_BLE_GATTS_C_EVT_DISCOVERY_FAILED, /**< Event indicating that the Service Changed characteristic has not been found on the peer. */
+ NRF_BLE_GATTS_C_EVT_DISCONN_COMPLETE, /**< Event indicating that the GATT Service client module has finished processing the BLE_GAP_EVT_DISCONNECTED event. The event can be used by the application to do cleanup related to the GATT Service client.*/
+ NRF_BLE_GATTS_C_EVT_SRV_CHANGED, /**< Event indicating that a Service Changed indication has been received. */
+} nrf_ble_gatts_c_evt_type_t;
+
+/**@brief Structure containing the event from the Service Changed client module to the application.
+ */
+typedef struct
+{
+ nrf_ble_gatts_c_evt_type_t evt_type; /**< Type of event. See @ref nrf_ble_gatts_c_evt_type_t. */
+ uint16_t conn_handle; /**< Handle of the connection for which this event has occurred. */
+ union
+ {
+ ble_gatt_db_char_t srv_changed_char; /**< Handles for the Service Changed characteristic. Will be filled if the event type is @ref NRF_BLE_GATTS_C_EVT_DISCOVERY_COMPLETE. */
+ ble_gattc_handle_range_t handle_range; /**< The affected attribute handle range where the service has changed. Will be provided if the event type is @ref NRF_BLE_GATTS_C_EVT_SRV_CHANGED.*/
+ } params;
+} nrf_ble_gatts_c_evt_t;
+
+/**@brief Service Changed handler type. */
+typedef void (* nrf_ble_gatts_c_evt_handler_t)(nrf_ble_gatts_c_evt_t * p_evt);
+
+/**@brief Structure for holding the information related to the Service Changed indication at the server.
+ *
+ * @details A GATT Server will never have more than one instance of the Service Changed Characteristic.
+ * Therefore, you never need more than one instance of the GATT Service client structure.
+ *
+ * @warning This structure must be zero-initialized.
+ */
+typedef struct
+{
+ bool initialized; /**< Boolean indicating whether the context has been initialized or not. */
+ bool char_found; /**< Boolean indicating whether the Service Changed indication has been found.*/
+ ble_gatt_db_char_t srv_changed_char; /**< Information of the Service Changed characteristics. */
+ uint16_t conn_handle; /**< Active connection handle. */
+ nrf_ble_gatts_c_evt_handler_t evt_handler; /**< Pointer to event handler function. */
+ ble_srv_error_handler_t err_handler; /**< Pointer to error handler function. */
+} nrf_ble_gatts_c_t;
+
+/**@brief Initialization parameters. These must be supplied when calling @ref nrf_ble_gatts_c_init. */
+typedef struct
+{
+ nrf_ble_gatts_c_evt_handler_t evt_handler; /**< Event handler that is called by the Service Changed client module when any related event occurs. */
+ ble_srv_error_handler_t err_handler; /**< Error handler that is called by the Service Changed client module if any error occurs. */
+} nrf_ble_gatts_c_init_t;
+
+
+/**@brief Function for initializing the Service Changed client module.
+ *
+ * @param[in,out] p_gatts_c Pointer to the GATT Service client structure instance.
+ * @param[in] p_gatts_c_init Init parameters containing the event handler that is called by
+ * the Service Changed client module when any related event occurs.
+ *
+ * @retval NRF_SUCCESS If the service was initialized successfully.
+ * @retval NRF_ERROR_NULL If any of the input parameters are NULL.
+ * @return If functions from other modules return errors to this function,
+ * the @ref nrf_error are propagated.
+ */
+ret_code_t nrf_ble_gatts_c_init(nrf_ble_gatts_c_t * p_gatts_c,
+ nrf_ble_gatts_c_init_t * p_gatts_c_init);
+
+
+/**@brief Function for enabling remote indication.
+ *
+ * @param[in,out] p_gatts_c Pointer to the Service Changed client structure.
+ * @param[in] enable True to enable Service Changed remote indication, false to disable.
+ *
+ * @retval NRF_SUCCESS Operation success.
+ * @return If functions from other modules return errors to this function,
+ * the @ref nrf_error are propagated.
+ */
+ret_code_t nrf_ble_gatts_c_enable_indication(nrf_ble_gatts_c_t * p_gatts_c,
+ bool enable);
+
+
+/**@brief Function for handling events from the database discovery module.
+ *
+ * @details This function handles an event from the database discovery module, and determine
+ * if it relates to the discovery of Service Changed characteristics at the peer. If so,
+ * it will call the application's event handler indicating that Service Changed
+ * characteristic has been discovered at the peer.
+ *
+ * @param[in,out] p_gatts_c Pointer to the GATT Service client structure instance.
+ * @param[in] p_evt Pointer to the event received from the database discovery module.
+ */
+void nrf_ble_gatts_c_on_db_disc_evt(nrf_ble_gatts_c_t const * p_gatts_c,
+ ble_db_discovery_evt_t * p_evt);
+
+
+/**@brief Function for handling BLE events.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Context.
+ */
+void nrf_ble_gatts_c_on_ble_evt(ble_evt_t const * p_ble_evt,
+ void * p_context);
+
+
+/**@brief Function for assigning handles to a GATT Service client instance.
+ *
+ * @details Call this function when a link has been established with a peer to
+ * associate this link to an instance of the module. This makes it
+ * possible to handle several links and associate each link with a particular
+ * instance of the GATT Service client module. The connection handle and attribute
+ * handles will be provided from the discovery event
+ * @ref NRF_BLE_GATTS_C_EVT_DISCOVERY_COMPLETE.
+ *
+ * @param[in,out] p_gatts_c Pointer to the GATT Service client structure instance to
+ * associate with the handles.
+ * @param[in] conn_handle Connection handle to be associated with the given
+ * GATT Service client Instance.
+ * @param[in] p_peer_handles Attribute handles on the GATT Service server that you want this
+ * GATT Service client to interact with.
+ *
+ * @retval NRF_SUCCESS If the connection handle was successfully stored in the GATT Service instance.
+ * @retval NRF_ERROR_NULL If any of the input parameters are NULL.
+ */
+ret_code_t nrf_ble_gatts_c_handles_assign(nrf_ble_gatts_c_t * p_gatts_c,
+ uint16_t conn_handle,
+ ble_gatt_db_char_t const * p_peer_handles);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // NRF_BLE_GATTS_C_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_db.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_db.c
new file mode 100644
index 0000000..e5f6240
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_db.c
@@ -0,0 +1,143 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <stdbool.h>
+#include <stdint.h>
+#include "cgms_db.h"
+
+typedef struct
+{
+ bool in_use_flag;
+ ble_cgms_rec_t record;
+} database_entry_t;
+
+static database_entry_t m_database[CGMS_DB_MAX_RECORDS];
+static uint8_t m_database_crossref[CGMS_DB_MAX_RECORDS];
+static uint16_t m_num_records;
+
+
+ret_code_t cgms_db_init(void)
+{
+ int i;
+
+ for (i = 0; i < CGMS_DB_MAX_RECORDS; i++)
+ {
+ m_database[i].in_use_flag = false;
+ m_database_crossref[i] = 0xFF;
+ }
+
+ m_num_records = 0;
+
+ return NRF_SUCCESS;
+}
+
+
+uint16_t cgms_db_num_records_get(void)
+{
+ return m_num_records;
+}
+
+
+ret_code_t cgms_db_record_get(uint8_t record_num, ble_cgms_rec_t * p_rec)
+{
+ if ((record_num >= m_num_records) || (m_num_records == 0))
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+ // copy record to the specified memory
+ *p_rec = m_database[m_database_crossref[record_num]].record;
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t cgms_db_record_add(ble_cgms_rec_t * p_rec)
+{
+ int i;
+
+ if (m_num_records == CGMS_DB_MAX_RECORDS)
+ {
+ return NRF_ERROR_NO_MEM;
+ }
+
+ // find next available database entry
+ for (i = 0; i < CGMS_DB_MAX_RECORDS; i++)
+ {
+ if (!m_database[i].in_use_flag)
+ {
+ m_database[i].in_use_flag = true;
+ m_database[i].record = *p_rec;
+
+ m_database_crossref[m_num_records] = i;
+ m_num_records++;
+
+ return NRF_SUCCESS;
+ }
+ }
+
+ return NRF_ERROR_NO_MEM;
+}
+
+
+ret_code_t cgms_db_record_delete(uint8_t record_num)
+{
+ int i;
+
+ if (record_num >= m_num_records)
+ {
+ // Deleting a non-existent record is not an error
+ return NRF_SUCCESS;
+ }
+
+ // free entry
+ m_database[m_database_crossref[record_num]].in_use_flag = false;
+
+ // decrease number of records
+ m_num_records--;
+
+ // remove cross reference index
+ for (i = record_num; i < m_num_records; i++)
+ {
+ m_database_crossref[i] = m_database_crossref[i + 1];
+ }
+
+ return NRF_SUCCESS;
+}
+
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_db.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_db.h
new file mode 100644
index 0000000..6928057
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_db.h
@@ -0,0 +1,118 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_sdk_srv_cgms_db Continuous Glucose Monitoring Service database
+ * @{
+ * @ingroup ble_cgms
+ *
+ * @brief Continuous Glucose Monitoring Service database module.
+ *
+ * @details This module implements a database of stored glucose measurement values.
+ * This database is meant as an example of a database that the @ref ble_cgms can use.
+ * Replace this module if this implementation does not suit
+ * your application. Any replacement implementation should follow the API below to ensure
+ * that the qualification of the @ref ble_cgms is not compromised.
+ */
+
+#ifndef BLE_CGMS_DB_H__
+#define BLE_CGMS_DB_H__
+
+#include "sdk_errors.h"
+#include "nrf_ble_cgms.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CGMS_DB_MAX_RECORDS 100 // !< Number of records that can be stored in the database.
+
+
+/**@brief Function for initializing the glucose record database.
+ *
+ * @retval NRF_SUCCESS If the database was successfully initialized.
+ */
+ret_code_t cgms_db_init(void);
+
+
+/**@brief Function for getting the number of records in the database.
+ *
+ * @return The number of records in the database.
+ */
+uint16_t cgms_db_num_records_get(void);
+
+
+/**@brief Function for getting a specific record from the database.
+ *
+ * @param[in] record_num Index of the record to retrieve.
+ * @param[out] p_rec Pointer to the record structure to which the retrieved record is copied.
+ *
+ * @retval NRF_SUCCESS If the record was successfully retrieved.
+ */
+ret_code_t cgms_db_record_get(uint8_t record_num, ble_cgms_rec_t * p_rec);
+
+
+/**@brief Function for adding a record at the end of the database.
+ *
+ * @param[in] p_rec Pointer to the record to add to the database.
+ *
+ * @retval NRF_SUCCESS If the record was successfully added to the database.
+ */
+ret_code_t cgms_db_record_add(ble_cgms_rec_t * p_rec);
+
+
+/**@brief Function for deleting a database entry.
+ *
+ * @details This call deletes an record from the database.
+ *
+ * @param[in] record_num Index of the record to delete.
+ *
+ * @retval NRF_SUCCESS If the record was successfully deleted from the database.
+ */
+ret_code_t cgms_db_record_delete(uint8_t record_num);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_CGMS_DB_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_meas.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_meas.c
new file mode 100644
index 0000000..50d6416
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_meas.c
@@ -0,0 +1,248 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <stdint.h>
+#include <string.h>
+#include "ble.h"
+#include "sdk_macros.h"
+#include "ble_srv_common.h"
+#include "nrf_ble_cgms.h"
+#include "cgms_meas.h"
+#include "cgms_db.h"
+
+/**@brief Function for encoding a Glucose measurement.
+ *
+ * @param[in] p_meas Measurement to be encoded.
+ * @param[out] p_encoded_buffer Pointer to buffer where the encoded measurement is to be stored.
+ *
+ * @return Size of encoded measurement.
+ */
+static uint8_t cgms_meas_encode(nrf_ble_cgms_t * p_cgms,
+ const nrf_ble_cgms_meas_t * p_meas,
+ uint8_t * p_encoded_buffer)
+{
+ uint8_t len = 2;
+
+ uint8_t flags = p_meas->flags;
+
+ len += uint16_encode(p_meas->glucose_concentration,
+ &p_encoded_buffer[len]);
+ len += uint16_encode(p_meas->time_offset,
+ &p_encoded_buffer[len]);
+
+ if (p_meas->sensor_status_annunciation.warning != 0)
+ {
+ p_encoded_buffer[len++] = p_meas->sensor_status_annunciation.warning;
+ flags |= NRF_BLE_CGMS_STATUS_FLAGS_WARNING_OCT_PRESENT;
+ }
+
+ if (p_meas->sensor_status_annunciation.calib_temp != 0)
+ {
+ p_encoded_buffer[len++] = p_meas->sensor_status_annunciation.calib_temp;
+ flags |= NRF_BLE_CGMS_STATUS_FLAGS_CALTEMP_OCT_PRESENT;
+ }
+
+ if (p_meas->sensor_status_annunciation.status != 0)
+ {
+ p_encoded_buffer[len++] = p_meas->sensor_status_annunciation.status;
+ flags |= NRF_BLE_CGMS_STATUS_FLAGS_STATUS_OCT_PRESENT;
+ }
+
+ // Trend field
+ if (p_cgms->feature.feature & NRF_BLE_CGMS_FEAT_CGM_TREND_INFORMATION_SUPPORTED)
+ {
+ if (flags & NRF_BLE_CGMS_FLAG_TREND_INFO_PRESENT)
+ {
+ len += uint16_encode(p_meas->trend, &p_encoded_buffer[len]);
+ }
+ }
+
+ // Quality field
+ if (p_cgms->feature.feature & NRF_BLE_CGMS_FEAT_CGM_QUALITY_SUPPORTED)
+ {
+ if (flags & NRF_BLE_CGMS_FLAGS_QUALITY_PRESENT)
+ {
+ len += uint16_encode(p_meas->quality, &p_encoded_buffer[len]);
+ }
+ }
+
+ p_encoded_buffer[1] = flags;
+ p_encoded_buffer[0] = len;
+ return len;
+}
+
+
+/**@brief Function for adding a characteristic for the Continuous Glucose Meter Measurement.
+ *
+ * @param[in] p_cgms Service instance.
+ *
+ * @return NRF_SUCCESS if characteristic was successfully added, otherwise an error code.
+ */
+ret_code_t cgms_meas_char_add(nrf_ble_cgms_t * p_cgms)
+{
+ uint8_t num_recs;
+ uint8_t encoded_cgms_meas[NRF_BLE_CGMS_MEAS_LEN_MAX];
+ ble_add_char_params_t add_char_params;
+ ble_cgms_rec_t initial_cgms_rec_value;
+
+ memset(&add_char_params, 0, sizeof(add_char_params));
+ memset(&initial_cgms_rec_value, 0, sizeof(ble_cgms_rec_t));
+
+ num_recs = cgms_db_num_records_get();
+ if (num_recs > 0)
+ {
+ uint32_t err_code = cgms_db_record_get(num_recs - 1, &initial_cgms_rec_value);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ add_char_params.uuid = BLE_UUID_CGM_MEASUREMENT;
+ add_char_params.max_len = NRF_BLE_CGMS_MEAS_LEN_MAX;
+ add_char_params.init_len = cgms_meas_encode(p_cgms,
+ &initial_cgms_rec_value.meas,
+ encoded_cgms_meas);
+ add_char_params.p_init_value = encoded_cgms_meas;
+ add_char_params.is_var_len = true;
+ add_char_params.char_props.notify = true;
+ add_char_params.cccd_write_access = SEC_JUST_WORKS;
+
+
+ return characteristic_add(p_cgms->service_handle,
+ &add_char_params,
+ &p_cgms->char_handles.measurment);
+}
+
+
+ret_code_t cgms_meas_send(nrf_ble_cgms_t * p_cgms, ble_cgms_rec_t * p_rec, uint8_t * p_count)
+{
+
+ uint32_t err_code;
+ uint8_t encoded_meas[NRF_BLE_CGMS_MEAS_LEN_MAX + NRF_BLE_CGMS_MEAS_REC_LEN_MAX];
+ uint16_t len = 0;
+ uint16_t hvx_len = NRF_BLE_CGMS_MEAS_LEN_MAX;
+ int i;
+ ble_gatts_hvx_params_t hvx_params;
+
+ for (i = 0; i < *p_count; i++)
+ {
+ uint8_t meas_len = cgms_meas_encode(p_cgms, &(p_rec[i].meas), (encoded_meas + len));
+ if (len + meas_len >= NRF_BLE_CGMS_MEAS_LEN_MAX)
+ {
+ break;
+ }
+ len += meas_len;
+ }
+ *p_count = i;
+ hvx_len = len;
+
+ memset(&hvx_params, 0, sizeof(hvx_params));
+
+ hvx_params.handle = p_cgms->char_handles.measurment.value_handle;
+ hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
+ hvx_params.offset = 0;
+ hvx_params.p_len = &hvx_len;
+ hvx_params.p_data = encoded_meas;
+
+ err_code = sd_ble_gatts_hvx(p_cgms->conn_handle, &hvx_params);
+ if (err_code == NRF_SUCCESS)
+ {
+ if (hvx_len != len)
+ {
+ err_code = NRF_ERROR_DATA_SIZE;
+ }
+ else
+ {
+ // Measurement successfully sent
+ p_cgms->racp_data.racp_proc_records_reported += *p_count;
+ p_cgms->racp_data.racp_proc_records_reported_since_txcomplete++;
+ }
+ }
+
+ return err_code;
+}
+
+
+/**@brief Function for handling the Glucose measurement CCCD write event.
+ *
+ * @param[in] p_cgms Service instance.
+ * @param[in] p_evt_write WRITE event to be handled.
+ */
+static void on_meas_cccd_write(nrf_ble_cgms_t * p_cgms, ble_gatts_evt_write_t const * p_evt_write)
+{
+ if (p_evt_write->len == 2)
+ {
+ // CCCD written, update notification state
+ if (p_cgms->evt_handler != NULL)
+ {
+ nrf_ble_cgms_evt_t evt;
+
+ if (ble_srv_is_notification_enabled(p_evt_write->data))
+ {
+ evt.evt_type = NRF_BLE_CGMS_EVT_NOTIFICATION_ENABLED;
+ }
+ else
+ {
+ evt.evt_type = NRF_BLE_CGMS_EVT_NOTIFICATION_DISABLED;
+ }
+
+ p_cgms->evt_handler(p_cgms, &evt);
+ }
+ }
+}
+
+
+/**@brief Function for handling the WRITE event.
+ *
+ * @details Handles WRITE events from the BLE stack.
+ *
+ * @param[in] p_cgms Glucose Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+void cgms_meas_on_write(nrf_ble_cgms_t * p_cgms, ble_gatts_evt_write_t const * p_evt_write)
+{
+
+ if (p_evt_write->handle == p_cgms->char_handles.measurment.cccd_handle)
+ {
+ on_meas_cccd_write(p_cgms, p_evt_write);
+ }
+}
+
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_meas.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_meas.h
new file mode 100644
index 0000000..d56c704
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_meas.h
@@ -0,0 +1,103 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_sdk_srv_cgms_meas Continuous Glucose Monitoring Service Measurement
+ * @{
+ * @ingroup ble_cgms
+ * @brief Continuous Glucose Monitoring Service Measurement module.
+ *
+ * @details This module implements parts of the Continuous Glucose Monitoring that relate to the
+ * Measurement characteristic. Events are propagated to this module from @ref ble_cgms
+ * using @ref cgms_meas_on_write.
+ *
+ */
+
+
+#ifndef NRF_BLE_CGMS_MEAS_H__
+#define NRF_BLE_CGMS_MEAS_H__
+
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "sdk_errors.h"
+#include "nrf_ble_cgms.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**@brief Function for adding a characteristic for the Continuous Glucose Monitoring Measurement.
+ *
+ * @param[in] p_cgms Instance of the CGM Service.
+ *
+ * @retval NRF_SUCCESS If the characteristic was successfully added.
+ * @return If functions from other modules return errors to this function,
+ * the @ref nrf_error are propagated.
+ */
+ret_code_t cgms_meas_char_add(nrf_ble_cgms_t * p_cgms);
+
+/**@brief Function for sending a CGM Measurement.
+ *
+ * @param[in] p_cgms Instance of the CGM Service.
+ * @param[in] p_rec Measurement to be sent.
+ * @param[in] count Number of measurements to encode.
+ *
+ * @retval NRF_SUCCESS If the measurement was successfully sent.
+ * @return If functions from other modules return errors to this function,
+ * the @ref nrf_error are propagated.
+ */
+ret_code_t cgms_meas_send(nrf_ble_cgms_t * p_cgms, ble_cgms_rec_t * p_rec, uint8_t * count);
+
+
+/**@brief Function for handling the @ref BLE_GATTS_EVT_WRITE event from the BLE stack.
+ *
+ * @param[in] p_cgms Instance of the CGM Service.
+ * @param[in] p_evt_write Event received from the BLE stack.
+ */
+void cgms_meas_on_write(nrf_ble_cgms_t * p_cgms, ble_gatts_evt_write_t const * p_evt_write);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // NRF_BLE_CGMS_MEAS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_racp.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_racp.c
new file mode 100644
index 0000000..0327383
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_racp.c
@@ -0,0 +1,866 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <stdint.h>
+#include <string.h>
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "cgms_racp.h"
+#include "cgms_db.h"
+#include "cgms_meas.h"
+
+#define OPERAND_LESS_GREATER_FILTER_TYPE_SIZE 1 // !< 1 byte.
+#define OPERAND_LESS_GREATER_FILTER_PARAM_SIZE 2 // !< 2 bytes.
+#define OPERAND_LESS_GREATER_SIZE OPERAND_LESS_GREATER_FILTER_TYPE_SIZE \
+ + OPERAND_LESS_GREATER_FILTER_PARAM_SIZE // !< Total size of the operand.
+
+/**@brief Function for adding a characteristic for the Record Access Control Point.
+ *
+ * @param[in] p_cgms Service instance.
+ *
+ * @return NRF_SUCCESS if characteristic was successfully added, otherwise an error code.
+ */
+ret_code_t cgms_racp_char_add(nrf_ble_cgms_t * p_cgms)
+{
+ ble_add_char_params_t add_char_params;
+
+ memset(&add_char_params, 0, sizeof(add_char_params));
+
+ add_char_params.uuid = BLE_UUID_RECORD_ACCESS_CONTROL_POINT_CHAR;
+ add_char_params.max_len = BLE_GATT_ATT_MTU_DEFAULT;
+ add_char_params.init_len = 0;
+ add_char_params.p_init_value = 0;
+ add_char_params.is_var_len = true;
+ add_char_params.write_access = SEC_JUST_WORKS;
+ add_char_params.char_props.write = true;
+ add_char_params.char_props.indicate = true;
+ add_char_params.cccd_write_access = SEC_JUST_WORKS;
+ add_char_params.is_defered_write = 1;
+
+ return characteristic_add(p_cgms->service_handle,
+ &add_char_params,
+ &p_cgms->char_handles.racp);
+}
+
+
+/**@brief Function for sending response from Specific Operation Control Point.
+ *
+ * @param[in] p_cgms Service instance.
+ * @param[in] p_racp_val RACP value to be sent.
+ */
+static void racp_send(nrf_ble_cgms_t * p_cgms, ble_racp_value_t * p_racp_val)
+{
+ uint32_t err_code;
+ uint8_t encoded_resp[25];
+ uint8_t len;
+ uint16_t hvx_len;
+ ble_gatts_hvx_params_t hvx_params;
+
+ if (
+ (p_cgms->cgms_com_state != STATE_RACP_RESPONSE_PENDING)
+ &&
+ (p_cgms->racp_data.racp_proc_records_reported_since_txcomplete > 0)
+ )
+ {
+ p_cgms->cgms_com_state = STATE_RACP_RESPONSE_PENDING;
+ return;
+ }
+
+ // Send indication
+ len = ble_racp_encode(p_racp_val, encoded_resp);
+ hvx_len = len;
+
+ memset(&hvx_params, 0, sizeof(hvx_params));
+
+ hvx_params.handle = p_cgms->char_handles.racp.value_handle;
+ hvx_params.type = BLE_GATT_HVX_INDICATION;
+ hvx_params.offset = 0;
+ hvx_params.p_len = &hvx_len;
+ hvx_params.p_data = encoded_resp;
+
+ err_code = sd_ble_gatts_hvx(p_cgms->conn_handle, &hvx_params);
+
+ // Error handling
+ if ((err_code == NRF_SUCCESS) && (hvx_len != len))
+ {
+ err_code = NRF_ERROR_DATA_SIZE;
+ }
+
+ switch (err_code)
+ {
+ case NRF_SUCCESS:
+ // Wait for HVC event.
+ p_cgms->cgms_com_state = STATE_RACP_RESPONSE_IND_VERIF;
+ break;
+
+ case NRF_ERROR_RESOURCES:
+ // Wait for TX_COMPLETE event to retry transmission.
+ p_cgms->cgms_com_state = STATE_RACP_RESPONSE_PENDING;
+ break;
+
+ case NRF_ERROR_INVALID_STATE:
+ // Make sure state machine returns to the default state.
+ p_cgms->cgms_com_state = STATE_NO_COMM;
+ break;
+
+ default:
+ // Report error to application.
+ if (p_cgms->error_handler != NULL)
+ {
+ p_cgms->error_handler(err_code);
+ }
+
+ // Make sure state machine returns to the default state.
+ p_cgms->cgms_com_state = STATE_NO_COMM;
+ break;
+ }
+}
+
+
+/**@brief Function for sending a RACP response containing a Response Code Op Code and Response Code Value.
+ *
+ * @param[in] p_cgms Service instance.
+ * @param[in] opcode RACP Op Code.
+ * @param[in] value RACP Response Code Value.
+ */
+static void racp_response_code_send(nrf_ble_cgms_t * p_cgms, uint8_t opcode, uint8_t value)
+{
+ p_cgms->racp_data.pending_racp_response.opcode = RACP_OPCODE_RESPONSE_CODE;
+ p_cgms->racp_data.pending_racp_response.operator = RACP_OPERATOR_NULL;
+ p_cgms->racp_data.pending_racp_response.operand_len = 2;
+ p_cgms->racp_data.pending_racp_response.p_operand =
+ p_cgms->racp_data.pending_racp_response_operand;
+
+ p_cgms->racp_data.pending_racp_response_operand[0] = opcode;
+ p_cgms->racp_data.pending_racp_response_operand[1] = value;
+
+ racp_send(p_cgms, &p_cgms->racp_data.pending_racp_response);
+}
+
+
+/**@brief Function for responding to the ALL operation.
+ *
+ * @param[in] p_cgms Service instance.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t racp_report_records_all(nrf_ble_cgms_t * p_cgms)
+{
+ uint16_t total_records = cgms_db_num_records_get();
+ uint16_t cur_nb_rec;
+ uint8_t i;
+ uint8_t nb_rec_to_send;
+
+ if (p_cgms->racp_data.racp_proc_record_ndx >= total_records)
+ {
+ p_cgms->cgms_com_state = STATE_NO_COMM;
+ }
+ else
+ {
+ uint32_t err_code;
+ ble_cgms_rec_t rec[NRF_BLE_CGMS_MEAS_REC_PER_NOTIF_MAX];
+
+ cur_nb_rec = total_records - p_cgms->racp_data.racp_proc_record_ndx;
+ if (cur_nb_rec > NRF_BLE_CGMS_MEAS_REC_PER_NOTIF_MAX)
+ {
+ cur_nb_rec = NRF_BLE_CGMS_MEAS_REC_PER_NOTIF_MAX;
+ }
+ nb_rec_to_send = (uint8_t)cur_nb_rec;
+
+ for (i = 0; i < cur_nb_rec; i++)
+ {
+ err_code = cgms_db_record_get(p_cgms->racp_data.racp_proc_record_ndx + i, &(rec[i]));
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+ err_code = cgms_meas_send(p_cgms, rec, &nb_rec_to_send);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ p_cgms->racp_data.racp_proc_record_ndx += nb_rec_to_send;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for responding to the FIRST or the LAST operation.
+ *
+ * @param[in] p_cgms Service instance.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t racp_report_records_first_last(nrf_ble_cgms_t * p_cgms)
+{
+ uint32_t err_code;
+ ble_cgms_rec_t rec;
+ uint16_t total_records;
+ uint8_t nb_rec_to_send = 1;
+
+ total_records = cgms_db_num_records_get();
+
+ if ((p_cgms->racp_data.racp_proc_records_reported != 0) || (total_records == 0))
+ {
+ p_cgms->cgms_com_state = STATE_NO_COMM;
+ }
+ else
+ {
+ if (p_cgms->racp_data.racp_proc_operator == RACP_OPERATOR_FIRST)
+ {
+ err_code = cgms_db_record_get(0, &rec);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+ else if (p_cgms->racp_data.racp_proc_operator == RACP_OPERATOR_LAST)
+ {
+ err_code = cgms_db_record_get(total_records - 1, &rec);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ err_code = cgms_meas_send(p_cgms, &rec, &nb_rec_to_send);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ p_cgms->racp_data.racp_proc_record_ndx++;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for responding to the LESS OR EQUAL operation.
+ *
+ * @param[in] p_cgms Service instance.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static ret_code_t racp_report_records_less_equal(nrf_ble_cgms_t * p_cgms)
+{
+ uint16_t total_rec_nb_to_send;
+ uint16_t rec_nb_left_to_send;
+ uint8_t nb_rec_to_send;
+ uint16_t i;
+
+ total_rec_nb_to_send = p_cgms->racp_data.racp_proc_records_ndx_last_to_send +1;
+
+ if (p_cgms->racp_data.racp_proc_record_ndx >= total_rec_nb_to_send)
+ {
+ p_cgms->cgms_com_state = STATE_NO_COMM;
+ }
+ else
+ {
+ ret_code_t err_code;
+ ble_cgms_rec_t rec[NRF_BLE_CGMS_MEAS_REC_PER_NOTIF_MAX];
+
+ rec_nb_left_to_send = total_rec_nb_to_send - p_cgms->racp_data.racp_proc_records_reported;
+
+ if (rec_nb_left_to_send > NRF_BLE_CGMS_MEAS_REC_PER_NOTIF_MAX)
+ {
+ nb_rec_to_send = NRF_BLE_CGMS_MEAS_REC_PER_NOTIF_MAX;
+ }
+ else
+ {
+ nb_rec_to_send = (uint8_t)rec_nb_left_to_send;
+ }
+
+ for (i = 0; i < nb_rec_to_send; i++)
+ {
+ err_code = cgms_db_record_get(p_cgms->racp_data.racp_proc_record_ndx + i, &(rec[i]));
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+ err_code = cgms_meas_send(p_cgms, rec, &nb_rec_to_send);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ p_cgms->racp_data.racp_proc_record_ndx += nb_rec_to_send;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for responding to the GREATER OR EQUAL operation.
+ *
+ * @param[in] p_cgms Service instance.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code.
+ */
+static ret_code_t racp_report_records_greater_equal(nrf_ble_cgms_t * p_cgms)
+{
+ ret_code_t err_code;
+ uint16_t total_rec_nb = cgms_db_num_records_get();
+ uint16_t rec_nb_left_to_send;
+ uint8_t nb_rec_to_send;
+ uint16_t i;
+
+
+ total_rec_nb = cgms_db_num_records_get();
+ if (p_cgms->racp_data.racp_proc_record_ndx >= total_rec_nb)
+ {
+ p_cgms->cgms_com_state = STATE_NO_COMM;
+ return NRF_SUCCESS;
+ }
+
+ ble_cgms_rec_t rec[NRF_BLE_CGMS_MEAS_REC_PER_NOTIF_MAX];
+
+ rec_nb_left_to_send = total_rec_nb - p_cgms->racp_data.racp_proc_record_ndx;
+ if (rec_nb_left_to_send > NRF_BLE_CGMS_MEAS_REC_PER_NOTIF_MAX)
+ {
+ nb_rec_to_send = NRF_BLE_CGMS_MEAS_REC_PER_NOTIF_MAX;
+ }
+ else
+ {
+ nb_rec_to_send = (uint8_t)rec_nb_left_to_send;
+ }
+
+ for (i = 0; i < nb_rec_to_send; i++)
+ {
+ err_code = cgms_db_record_get(p_cgms->racp_data.racp_proc_record_ndx + i, &(rec[i]));
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+ err_code = cgms_meas_send(p_cgms, rec, &nb_rec_to_send);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ p_cgms->racp_data.racp_proc_record_ndx += nb_rec_to_send;
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for informing that the REPORT RECORDS procedure is completed.
+ *
+ * @param[in] p_cgms Service instance.
+ */
+static void racp_report_records_completed(nrf_ble_cgms_t * p_cgms)
+{
+ uint8_t resp_code_value;
+
+ if (p_cgms->racp_data.racp_proc_records_reported > 0)
+ {
+ resp_code_value = RACP_RESPONSE_SUCCESS;
+ }
+ else
+ {
+ resp_code_value = RACP_RESPONSE_NO_RECORDS_FOUND;
+ }
+
+ racp_response_code_send(p_cgms, RACP_OPCODE_REPORT_RECS, resp_code_value);
+}
+
+
+/**@brief Function for the RACP report records procedure.
+ *
+ * @param[in] p_cgms Service instance.
+ */
+static void racp_report_records_procedure(nrf_ble_cgms_t * p_cgms)
+{
+ ret_code_t err_code = NRF_SUCCESS;
+
+ while (p_cgms->cgms_com_state == STATE_RACP_PROC_ACTIVE)
+ {
+ // Execute requested procedure
+ switch (p_cgms->racp_data.racp_proc_operator)
+ {
+ case RACP_OPERATOR_ALL:
+ err_code = racp_report_records_all(p_cgms);
+ break;
+
+ case RACP_OPERATOR_FIRST:
+ // Fall through.
+ case RACP_OPERATOR_LAST:
+ err_code = racp_report_records_first_last(p_cgms);
+ break;
+ case RACP_OPERATOR_GREATER_OR_EQUAL:
+ err_code = racp_report_records_greater_equal(p_cgms);
+ break;
+ case RACP_OPERATOR_LESS_OR_EQUAL:
+ err_code = racp_report_records_less_equal(p_cgms);
+ break;
+ default:
+ // Report error to application
+ if (p_cgms->error_handler != NULL)
+ {
+ p_cgms->error_handler(NRF_ERROR_INTERNAL);
+ }
+
+ // Make sure state machine returns to the default state
+ // state_set(STATE_NO_COMM);
+ p_cgms->cgms_com_state = STATE_NO_COMM;
+ return;
+ }
+
+ // Error handling
+ switch (err_code)
+ {
+ case NRF_SUCCESS:
+ if (p_cgms->cgms_com_state != STATE_RACP_PROC_ACTIVE)
+ {
+ racp_report_records_completed(p_cgms);
+ }
+ break;
+
+ case NRF_ERROR_RESOURCES:
+ // Wait for TX_COMPLETE event to resume transmission.
+ return;
+
+ case NRF_ERROR_INVALID_STATE:
+ // Notification is probably not enabled. Ignore request.
+ p_cgms->cgms_com_state = STATE_NO_COMM;
+ return;
+
+ default:
+ // Report error to application.
+ if (p_cgms->error_handler != NULL)
+ {
+ p_cgms->error_handler(err_code);
+ }
+
+ // Make sure state machine returns to the default state.
+ p_cgms->cgms_com_state = STATE_NO_COMM;
+ return;
+ }
+ }
+}
+
+
+/**@brief Function for testing if the received request is to be executed.
+ *
+ * @param[in] p_racp_request Request to be checked.
+ * @param[out] p_response_code Response code to be sent in case the request is rejected.
+ * RACP_RESPONSE_RESERVED is returned if the received message is
+ * to be rejected without sending a respone.
+ *
+ * @return TRUE if the request is to be executed, FALSE if it is to be rejected.
+ * If it is to be rejected, p_response_code will contain the response code to be
+ * returned to the central.
+ */
+static bool is_request_to_be_executed(nrf_ble_cgms_t * p_cgms,
+ const ble_racp_value_t * p_racp_request,
+ uint8_t * p_response_code)
+{
+ *p_response_code = RACP_RESPONSE_RESERVED;
+
+ if (p_racp_request->opcode == RACP_OPCODE_ABORT_OPERATION)
+ {
+ if (p_cgms->cgms_com_state == STATE_RACP_PROC_ACTIVE)
+ {
+ if (p_racp_request->operator != RACP_OPERATOR_NULL)
+ {
+ *p_response_code = RACP_RESPONSE_INVALID_OPERATOR;
+ }
+ else if (p_racp_request->operand_len != 0)
+ {
+ *p_response_code = RACP_RESPONSE_INVALID_OPERAND;
+ }
+ else
+ {
+ *p_response_code = RACP_RESPONSE_SUCCESS;
+ }
+ }
+ else
+ {
+ *p_response_code = RACP_RESPONSE_ABORT_FAILED;
+ }
+ }
+ else if (p_cgms->cgms_com_state != STATE_NO_COMM)
+ {
+ return false;
+ }
+ // Supported opcodes
+ else if ((p_racp_request->opcode == RACP_OPCODE_REPORT_RECS) ||
+ (p_racp_request->opcode == RACP_OPCODE_REPORT_NUM_RECS))
+ {
+ switch (p_racp_request->operator)
+ {
+ // Operators without a filter.
+ case RACP_OPERATOR_ALL:
+ // Fall through.
+ case RACP_OPERATOR_FIRST:
+ // Fall through.
+ case RACP_OPERATOR_LAST:
+ if (p_racp_request->operand_len != 0)
+ {
+ *p_response_code = RACP_RESPONSE_INVALID_OPERAND;
+ }
+ break;
+
+ // Operators with a filter as part of the operand.
+ case RACP_OPERATOR_LESS_OR_EQUAL:
+ // Fall Through.
+ case RACP_OPERATOR_GREATER_OR_EQUAL:
+ if (*(p_racp_request->p_operand) == RACP_OPERAND_FILTER_TYPE_FACING_TIME)
+ {
+ *p_response_code = RACP_RESPONSE_PROCEDURE_NOT_DONE;
+ }
+ if (p_racp_request->operand_len != OPERAND_LESS_GREATER_SIZE)
+ {
+ *p_response_code = RACP_RESPONSE_INVALID_OPERAND;
+ }
+ break;
+
+ case RACP_OPERATOR_RANGE:
+ *p_response_code = RACP_RESPONSE_OPERATOR_UNSUPPORTED;
+ break;
+
+ // Invalid operators.
+ case RACP_OPERATOR_NULL:
+ // Fall through.
+ default:
+ *p_response_code = RACP_RESPONSE_INVALID_OPERATOR;
+ break;
+ }
+ }
+ // Unsupported opcodes.
+ else if (p_racp_request->opcode == RACP_OPCODE_DELETE_RECS)
+ {
+ *p_response_code = RACP_RESPONSE_OPCODE_UNSUPPORTED;
+ }
+ // Unknown opcodes.
+ else
+ {
+ *p_response_code = RACP_RESPONSE_OPCODE_UNSUPPORTED;
+ }
+
+ return (*p_response_code == RACP_RESPONSE_RESERVED);
+}
+
+
+
+
+/**@brief Function for getting a record with time offset less or equal to the input param.
+ *
+ * @param[in] offset The record that this function returns must have an time offset less or greater to this.
+ * @param[out] record_num Pointer to the record index of the record that has the desired time offset.
+ *
+ * @retval NRF_SUCCESS If the record was successfully retrieved.
+ * @retval NRF_ERROR_NOT_FOUND A record with the desired offset does not exist in the database.
+ * @return If functions from other modules return errors to this function,
+ * the @ref nrf_error are propagated.
+ */
+static ret_code_t record_index_offset_less_or_equal_get(uint16_t offset, uint16_t * record_num)
+{
+ ret_code_t err_code;
+ ble_cgms_rec_t rec;
+ uint16_t upper_bound = cgms_db_num_records_get();
+
+ for((*record_num) = upper_bound; (*record_num)-- >0;)
+ {
+ err_code = cgms_db_record_get(*record_num, &rec);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ if (rec.meas.time_offset <= offset)
+ {
+ return NRF_SUCCESS;
+ }
+ }
+ return NRF_ERROR_NOT_FOUND;
+}
+
+
+
+/**@brief Function for getting a record with time offset greater or equal to the input param.
+ *
+ * @param[in] offset The record that this function returns must have an time offset equal or
+ * greater to this.
+ * @param[out] record_num Pointer to the record index of the record that has the desired time offset.
+ *
+ * @retval NRF_SUCCESS If the record was successfully retrieved.
+ * @retval NRF_ERROR_NOT_FOUND A record with the desired offset does not exist in the database.
+ * @return If functions from other modules return errors to this function,
+ * the @ref nrf_error are propagated.
+ */
+static ret_code_t record_index_offset_greater_or_equal_get(uint16_t offset, uint16_t * record_num)
+{
+ ret_code_t err_code;
+ ble_cgms_rec_t rec;
+ uint16_t upper_bound = cgms_db_num_records_get();
+
+ for(*record_num = 0; *record_num < upper_bound; (*record_num)++)
+ {
+ err_code = cgms_db_record_get(*record_num, &rec);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ if (rec.meas.time_offset >= offset)
+ {
+ return NRF_SUCCESS;
+ }
+ }
+ return NRF_ERROR_NOT_FOUND;
+}
+
+
+/**@brief Function for processing a REPORT RECORDS request.
+ *
+ * @details Set initial values before entering the state machine of racp_report_records_procedure().
+ *
+ * @param[in] p_cgms Service instance.
+ * @param[in] p_racp_request Request to be executed.
+ */
+static void report_records_request_execute(nrf_ble_cgms_t * p_cgms,
+ ble_racp_value_t * p_racp_request)
+{
+ p_cgms->cgms_com_state = STATE_RACP_PROC_ACTIVE;
+
+ p_cgms->racp_data.racp_proc_record_ndx = 0;
+ p_cgms->racp_data.racp_proc_operator = p_racp_request->operator;
+ p_cgms->racp_data.racp_proc_records_reported = 0;
+ p_cgms->racp_data.racp_proc_records_ndx_last_to_send = 0;
+
+ if (p_cgms->racp_data.racp_proc_operator == RACP_OPERATOR_GREATER_OR_EQUAL)
+ {
+ uint16_t offset_requested = uint16_decode(&p_cgms->racp_data.racp_request.p_operand[OPERAND_LESS_GREATER_FILTER_TYPE_SIZE]);
+ ret_code_t err_code = record_index_offset_greater_or_equal_get(offset_requested, &p_cgms->racp_data.racp_proc_record_ndx);
+ if (err_code != NRF_SUCCESS)
+ {
+ racp_report_records_completed(p_cgms);
+ }
+
+ }
+ if (p_cgms->racp_data.racp_proc_operator == RACP_OPERATOR_LESS_OR_EQUAL)
+ {
+ uint16_t offset_requested = uint16_decode(&p_cgms->racp_data.racp_request.p_operand[OPERAND_LESS_GREATER_FILTER_TYPE_SIZE]);
+ ret_code_t err_code = record_index_offset_less_or_equal_get(offset_requested,
+ &p_cgms->racp_data.racp_proc_records_ndx_last_to_send);
+ if (err_code != NRF_SUCCESS)
+ {
+ racp_report_records_completed(p_cgms);
+ }
+ }
+ racp_report_records_procedure(p_cgms);
+}
+
+
+/**@brief Function for processing a REPORT NUM RECORDS request.
+ *
+ * @param[in] p_cgms Service instance.
+ * @param[in] p_racp_request Request to be executed.
+ */
+static void report_num_records_request_execute(nrf_ble_cgms_t * p_cgms,
+ ble_racp_value_t * p_racp_request)
+{
+ uint16_t total_records;
+ uint16_t num_records;
+
+ total_records = cgms_db_num_records_get();
+ num_records = 0;
+
+ if (p_racp_request->operator == RACP_OPERATOR_ALL)
+ {
+ num_records = total_records;
+ }
+ else if ((p_racp_request->operator == RACP_OPERATOR_FIRST) ||
+ (p_racp_request->operator == RACP_OPERATOR_LAST))
+ {
+ if (total_records > 0)
+ {
+ num_records = 1;
+ }
+ }
+ else if (p_racp_request->operator == RACP_OPERATOR_GREATER_OR_EQUAL)
+ {
+ uint16_t index_of_offset;
+ uint16_t offset_requested = uint16_decode(&p_cgms->racp_data.racp_request.p_operand[OPERAND_LESS_GREATER_FILTER_TYPE_SIZE]);
+ ret_code_t err_code = record_index_offset_greater_or_equal_get(offset_requested, &index_of_offset);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ num_records = 0;
+ }
+ else
+ {
+ num_records = total_records - index_of_offset;
+ }
+ }
+
+ p_cgms->racp_data.pending_racp_response.opcode = RACP_OPCODE_NUM_RECS_RESPONSE;
+ p_cgms->racp_data.pending_racp_response.operator = RACP_OPERATOR_NULL;
+ p_cgms->racp_data.pending_racp_response.operand_len = sizeof(uint16_t);
+ p_cgms->racp_data.pending_racp_response.p_operand =
+ p_cgms->racp_data.pending_racp_response_operand;
+
+ p_cgms->racp_data.pending_racp_response_operand[0] = num_records & 0xFF;
+ p_cgms->racp_data.pending_racp_response_operand[1] = num_records >> 8;
+
+ racp_send(p_cgms, &p_cgms->racp_data.pending_racp_response);
+}
+
+
+/**@brief Function for handling a write event to the Record Access Control Point.
+ *
+ * @param[in] p_cgms Service instance.
+ * @param[in] p_evt_write WRITE event to be handled.
+ */
+static void on_racp_value_write(nrf_ble_cgms_t * p_cgms, ble_gatts_evt_write_t const * p_evt_write)
+{
+ uint8_t response_code;
+
+ // set up reply to authorized write.
+ ble_gatts_rw_authorize_reply_params_t auth_reply;
+ uint32_t err_code;
+
+ auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
+ auth_reply.params.write.offset = 0;
+ auth_reply.params.write.len = 0;
+ auth_reply.params.write.p_data = NULL;
+
+ // Decode request.
+ ble_racp_decode(p_evt_write->len, p_evt_write->data, &p_cgms->racp_data.racp_request);
+
+ // Check if request is to be executed
+ if (is_request_to_be_executed(p_cgms, &p_cgms->racp_data.racp_request, &response_code))
+ {
+ auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ auth_reply.params.write.update = 1;
+
+ err_code = sd_ble_gatts_rw_authorize_reply(p_cgms->conn_handle,
+ &auth_reply);
+ if (err_code != NRF_SUCCESS)
+ {
+ if (p_cgms->error_handler != NULL)
+ {
+ p_cgms->error_handler(err_code);
+ }
+ return;
+ }
+
+ // Execute request
+ if (p_cgms->racp_data.racp_request.opcode == RACP_OPCODE_REPORT_RECS)
+ {
+ report_records_request_execute(p_cgms, &p_cgms->racp_data.racp_request);
+ }
+ else if (p_cgms->racp_data.racp_request.opcode == RACP_OPCODE_REPORT_NUM_RECS)
+ {
+ report_num_records_request_execute(p_cgms, &p_cgms->racp_data.racp_request);
+ }
+ }
+ else if (response_code != RACP_RESPONSE_RESERVED)
+ {
+ auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ auth_reply.params.write.update = 1;
+ err_code = sd_ble_gatts_rw_authorize_reply(p_cgms->conn_handle,
+ &auth_reply);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ if (p_cgms->error_handler != NULL)
+ {
+ p_cgms->error_handler(err_code);
+ }
+ return;
+ }
+ // Abort any running procedure
+ p_cgms->cgms_com_state = STATE_NO_COMM;
+
+ // Respond with error code
+ racp_response_code_send(p_cgms, p_cgms->racp_data.racp_request.opcode, response_code);
+ }
+ else
+ {
+ // ignore request
+ auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ auth_reply.params.write.update = 1;
+ err_code = sd_ble_gatts_rw_authorize_reply(p_cgms->conn_handle,
+ &auth_reply);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ if (p_cgms->error_handler != NULL)
+ {
+ p_cgms->error_handler(err_code);
+ }
+ return;
+ }
+ }
+}
+
+
+void cgms_racp_on_rw_auth_req(nrf_ble_cgms_t * p_cgms,
+ ble_gatts_evt_rw_authorize_request_t const * p_auth_req)
+{
+ if (p_auth_req->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
+ {
+ if (p_auth_req->request.write.handle == p_cgms->char_handles.racp.value_handle)
+ {
+ on_racp_value_write(p_cgms, &p_auth_req->request.write);
+ }
+ }
+}
+
+
+/**@brief Function for handling BLE_GATTS_EVT_HVN_TX_COMPLETE events.
+ *
+ * @param[in] p_cgms Glucose Service structure.
+ */
+void cgms_racp_on_tx_complete(nrf_ble_cgms_t * p_cgms)
+{
+ p_cgms->racp_data.racp_proc_records_reported_since_txcomplete = 0;
+
+ if (p_cgms->cgms_com_state == STATE_RACP_RESPONSE_PENDING)
+ {
+ racp_send(p_cgms, &p_cgms->racp_data.pending_racp_response);
+ }
+ else if (p_cgms->cgms_com_state == STATE_RACP_PROC_ACTIVE)
+ {
+ racp_report_records_procedure(p_cgms);
+ }
+}
+
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_racp.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_racp.h
new file mode 100644
index 0000000..e1d92af
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_racp.h
@@ -0,0 +1,99 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_sdk_srv_cgms_racp Record Access Control Point
+ * @{
+ * @ingroup ble_cgms
+ * @brief Continuous Glucose Monitoring Service RACP module.
+ *
+ * @details This module implements parts of the Continuous Glucose Monitoring that relate to the
+ * Record Access Control Point. Events are propagated to this module from @ref ble_cgms
+ * using @ref cgms_racp_on_rw_auth_req and @ref cgms_racp_on_tx_complete.
+ *
+ */
+
+#ifndef NRF_BLE_CGMS_RACP_H__
+#define NRF_BLE_CGMS_RACP_H__
+
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "sdk_errors.h"
+#include "nrf_ble_cgms.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**@brief Function for adding a characteristic for the Record Access Control Point.
+ *
+ * @param[in] p_cgms Instance of the CGM Service.
+ *
+ * @retval NRF_SUCCESS If the characteristic was successfully added.
+ * @retval NRF_ERROR_NULL If any of the input parameters are NULL.
+ * @return If functions from other modules return errors to this function,
+ * the @ref nrf_error are propagated.
+ */
+ret_code_t cgms_racp_char_add(nrf_ble_cgms_t * p_cgms);
+
+
+/**@brief Function for handling @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST events.
+ *
+ * @param[in] p_cgms Instance of the CGM Service.
+ * @param[in] p_auth_req Authorize request event to be handled.
+ */
+void cgms_racp_on_rw_auth_req(nrf_ble_cgms_t * p_cgms,
+ ble_gatts_evt_rw_authorize_request_t const * p_auth_req);
+
+
+/**@brief Function for handling @ref BLE_GATTS_EVT_HVN_TX_COMPLETE events.
+ *
+ * @param[in] p_cgms Instance of the CGM Service.
+ */
+void cgms_racp_on_tx_complete(nrf_ble_cgms_t * p_cgms);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // NRF_BLE_CGMS_RACP_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_socp.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_socp.c
new file mode 100644
index 0000000..2ade378
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_socp.c
@@ -0,0 +1,431 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <stdint.h>
+#include <string.h>
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "cgms_sst.h"
+#include "cgms_socp.h"
+
+
+#define NRF_BLE_CGMS_PLUS_INFINTE 0x07FE
+#define NRF_BLE_CGMS_MINUS_INFINTE 0x0802
+
+/**@brief Specific Operation Control Point opcodes. */
+#define SOCP_OPCODE_RESERVED 0x00 /**< Specific Operation Control Point opcode - Reserved for future use. */
+#define SOCP_WRITE_CGM_COMMUNICATION_INTERVAL 0x01
+#define SOCP_READ_CGM_COMMUNICATION_INTERVAL 0x02
+#define SOCP_READ_CGM_COMMUNICATION_INTERVAL_RESPONSE 0x03
+#define SOCP_WRITE_GLUCOSE_CALIBRATION_VALUE 0x04
+#define SOCP_READ_GLUCOSE_CALIBRATION_VALUE 0x05
+#define SOCP_READ_GLUCOSE_CALIBRATION_VALUE_RESPONSE 0x06
+#define SOCP_WRITE_PATIENT_HIGH_ALERT_LEVEL 0x07
+#define SOCP_READ_PATIENT_HIGH_ALERT_LEVEL 0x08
+#define SOCP_READ_PATIENT_HIGH_ALERT_LEVEL_RESPONSE 0x09
+#define SOCP_WRITE_PATIENT_LOW_ALERT_LEVEL 0x0A
+#define SOCP_READ_PATIENT_LOW_ALERT_LEVEL 0x0B
+#define SOCP_READ_PATIENT_LOW_ALERT_LEVEL_RESPONSE 0x0C
+#define SOCP_SET_HYPO_ALERT_LEVEL 0x0D /**Set Hypo Alert Level Hypo Alert Level value in mg/dL The response to this control point is Response Code. */
+#define SOCP_GET_HYPO_ALERT_LEVEL 0x0E /**Get Hypo Alert Level N/A The normal response to this control point is Op Code 0x0F. For error conditions, the response is Response Code */
+#define SOCP_HYPO_ALERT_LEVEL_RESPONSE 0x0F /**Hypo Alert Level Response Hypo Alert Level value in mg/dL This is the normal response to Op Code 0x0E */
+#define SOCP_SET_HYPER_ALERT_LEVEL 0x10 /**Set Hyper Alert Level Hyper Alert Level value in mg/dL The response to this control point is Response Code. */
+#define SOCP_GET_HYPER_ALERT_LEVEL 0x11 /**Get Hyper Alert Level N/A The normal response to this control point is Op Code 0x12. For error conditions, the response is Response Code */
+#define SOCP_HYPER_ALERT_LEVEL_RESPONSE 0x12 /**Hyper Alert Level Response Hyper Alert Level value in mg/dL This is the normal response to Op Code 0x11 */
+#define SOCP_SET_RATE_OF_DECREASE_ALERT_LEVEL 0x13 /**Set Rate of Decrease Alert Level Rate of Decrease Alert Level value in mg/dL/min The response to this control point is Response Code. */
+#define SOCP_GET_RATE_OF_DECREASE_ALERT_LEVEL 0x14 /**Get Rate of Decrease Alert Level N/A The normal response to this control point is Op Code 0x15. For error conditions, the response is Response Code */
+#define SOCP_RATE_OF_DECREASE_ALERT_LEVEL_RESPONSE 0x15 /**Rate of Decrease Alert Level Response Rate of Decrease Alert Level value in mg/dL/min This is the normal response to Op Code 0x14 */
+#define SOCP_SET_RATE_OF_INCREASE_ALERT_LEVEL 0x16 /**Set Rate of Increase Alert Level Rate of Increase Alert Level value in mg/dL/min The response to this control point is Response Code. */
+#define SOCP_GET_RATE_OF_INCREASE_ALERT_LEVEL 0x17 /**Get Rate of Increase Alert Level N/A The normal response to this control point is Op Code 0x18. For error conditions, the response is Response Code */
+#define SOCP_RATE_OF_INCREASE_ALERT_LEVEL_RESPONSE 0x18 /**Rate of Increase Alert Level Response Rate of Increase Alert Level value in mg/dL/min This is the normal response to Op Code 0x17 */
+#define SOCP_RESET_DEVICE_SPECIFIC_ALERT 0x19 /**Reset Device Specific Alert N/A The response to this control point is Response Code. */
+
+#define SOCP_START_THE_SESSION 0x1A
+#define SOCP_STOP_THE_SESSION 0x1B
+#define SOCP_RESPONSE_CODE 0x1C
+
+#define SOCP_RSP_RESERVED_FOR_FUTURE_USE 0x00
+#define SOCP_RSP_SUCCESS 0x01
+#define SOCP_RSP_OP_CODE_NOT_SUPPORTED 0x02
+#define SOCP_RSP_INVALID_OPERAND 0x03
+#define SOCP_RSP_PROCEDURE_NOT_COMPLETED 0x04
+#define SOCP_RSP_OUT_OF_RANGE 0x05
+
+static void ble_socp_decode(uint8_t data_len, uint8_t const * p_data, ble_cgms_socp_value_t * p_socp_val)
+{
+ p_socp_val->opcode = 0xFF;
+ p_socp_val->operand_len = 0;
+ p_socp_val->p_operand = NULL;
+
+ if (data_len > 0)
+ {
+ p_socp_val->opcode = p_data[0];
+ }
+ if (data_len > 1)
+ {
+ p_socp_val->operand_len = data_len - 1;
+ p_socp_val->p_operand = (uint8_t*)&p_data[1]; // lint !e416
+ }
+}
+
+
+uint8_t ble_socp_encode(const ble_socp_rsp_t * p_socp_rsp, uint8_t * p_data)
+{
+ uint8_t len = 0;
+ int i;
+
+
+ if (p_data != NULL)
+ {
+ p_data[len++] = p_socp_rsp->opcode;
+
+ if (
+ (p_socp_rsp->opcode != SOCP_READ_CGM_COMMUNICATION_INTERVAL_RESPONSE)
+ && (p_socp_rsp->opcode != SOCP_READ_PATIENT_HIGH_ALERT_LEVEL_RESPONSE)
+ && (p_socp_rsp->opcode != SOCP_READ_PATIENT_LOW_ALERT_LEVEL_RESPONSE)
+ && (p_socp_rsp->opcode != SOCP_HYPO_ALERT_LEVEL_RESPONSE)
+ && (p_socp_rsp->opcode != SOCP_HYPER_ALERT_LEVEL_RESPONSE)
+ && (p_socp_rsp->opcode != SOCP_RATE_OF_DECREASE_ALERT_LEVEL_RESPONSE)
+ && (p_socp_rsp->opcode != SOCP_RATE_OF_INCREASE_ALERT_LEVEL_RESPONSE)
+ && (p_socp_rsp->opcode != SOCP_READ_GLUCOSE_CALIBRATION_VALUE_RESPONSE)
+ )
+ {
+ p_data[len++] = p_socp_rsp->req_opcode;
+ p_data[len++] = p_socp_rsp->rsp_code;
+ }
+
+ for (i = 0; i < p_socp_rsp->size_val; i++)
+ {
+ p_data[len++] = p_socp_rsp->resp_val[i];
+ }
+ }
+
+ return len;
+}
+
+
+/**@brief Function for adding a characteristic for the Specific Operations Control Point.
+ *
+ * @param[in] p_cgms Service instance.
+ *
+ * @return NRF_SUCCESS if characteristic was successfully added, otherwise an error code.
+ */
+ret_code_t cgms_socp_char_add(nrf_ble_cgms_t * p_cgms)
+{
+ ble_add_char_params_t add_char_params;
+
+ memset(&add_char_params, 0, sizeof(add_char_params));
+
+ add_char_params.uuid = BLE_UUID_CGM_SPECIFIC_OPS_CTRLPT;
+ add_char_params.max_len = BLE_GATT_ATT_MTU_DEFAULT;
+ add_char_params.init_len = 0;
+ add_char_params.p_init_value = 0;
+ add_char_params.is_var_len = true;
+ add_char_params.char_props.indicate = true;
+ add_char_params.char_props.write = true;
+ add_char_params.write_access = SEC_JUST_WORKS;
+ add_char_params.cccd_write_access = SEC_JUST_WORKS;
+ add_char_params.is_defered_write = 1;
+
+ return characteristic_add(p_cgms->service_handle,
+ &add_char_params,
+ &p_cgms->char_handles.socp);
+}
+
+
+/**@brief Function for sending a response from the Specific Operation Control Point.
+ *
+ * @param[in] p_cgms Service instance.
+ */
+static void socp_send(nrf_ble_cgms_t * p_cgms)
+{
+ uint32_t err_code;
+ uint8_t encoded_resp[25];
+ uint8_t len;
+ uint16_t hvx_len;
+ ble_gatts_hvx_params_t hvx_params;
+
+ // Send indication
+ len = ble_socp_encode(&(p_cgms->socp_response), encoded_resp);
+ hvx_len = len;
+
+ memset(&hvx_params, 0, sizeof(hvx_params));
+
+ hvx_params.handle = p_cgms->char_handles.socp.value_handle;
+ hvx_params.type = BLE_GATT_HVX_INDICATION;
+ hvx_params.offset = 0;
+ hvx_params.p_len = &hvx_len;
+ hvx_params.p_data = encoded_resp;
+
+ err_code = sd_ble_gatts_hvx(p_cgms->conn_handle, &hvx_params);
+
+ // Error handling
+ if ((err_code == NRF_SUCCESS) && (hvx_len != len))
+ {
+ err_code = NRF_ERROR_DATA_SIZE;
+ }
+
+ switch (err_code)
+ {
+ case NRF_SUCCESS:
+ // Wait for HVC event.
+ p_cgms->cgms_com_state = STATE_SOCP_RESPONSE_IND_VERIF;
+ break;
+
+ case NRF_ERROR_RESOURCES:
+ // Wait for TX_COMPLETE event to retry transmission.
+ p_cgms->cgms_com_state = STATE_SOCP_RESPONSE_PENDING;
+ break;
+
+ case NRF_ERROR_INVALID_STATE:
+ // Make sure state machine returns to the default state.
+ p_cgms->cgms_com_state = STATE_NO_COMM;
+ break;
+
+ default:
+ // Report error to application.
+ if (p_cgms->error_handler != NULL)
+ {
+ p_cgms->error_handler(err_code);
+ }
+
+ // Make sure state machine returns to the default state.
+ p_cgms->cgms_com_state = STATE_NO_COMM;
+ break;
+ }
+}
+
+
+void encode_get_response(uint8_t rsp_code, ble_socp_rsp_t * p_rsp, uint16_t in_val)
+{
+ p_rsp->opcode = rsp_code;
+ p_rsp->rsp_code = SOCP_RSP_SUCCESS;
+ p_rsp->size_val += uint16_encode(in_val, &(p_rsp->resp_val[p_rsp->size_val]));
+}
+
+
+void decode_set_opcode(nrf_ble_cgms_t * p_cgms,
+ ble_cgms_socp_value_t * rcv_val,
+ uint16_t min,
+ uint16_t max,
+ uint16_t * p_val)
+{
+ uint16_t rcvd_val = uint16_decode(rcv_val->p_operand);
+
+ if ((rcvd_val == NRF_BLE_CGMS_PLUS_INFINTE)
+ || (rcvd_val == NRF_BLE_CGMS_MINUS_INFINTE)
+ || (rcvd_val > max)
+ || (rcvd_val < min))
+ {
+ p_cgms->socp_response.rsp_code = SOCP_RSP_OUT_OF_RANGE;
+ }
+ else
+ {
+ p_cgms->socp_response.rsp_code = SOCP_RSP_SUCCESS;
+ *p_val = rcvd_val;
+ }
+}
+
+
+static bool is_feature_present(nrf_ble_cgms_t * p_cgms, uint32_t feature)
+{
+ return (p_cgms->feature.feature & feature);
+}
+
+
+/**@brief Function for handling a write event to the Specific Operation Control Point.
+ *
+ * @param[in] p_cgms Service instance.
+ * @param[in] p_evt_write WRITE event to be handled.
+ */
+static void on_socp_value_write(nrf_ble_cgms_t * p_cgms, ble_gatts_evt_write_t const * p_evt_write)
+{
+ ble_cgms_socp_value_t socp_request;
+ nrf_ble_cgms_evt_t evt;
+ ble_gatts_rw_authorize_reply_params_t auth_reply;
+ uint32_t err_code;
+
+ memset(&auth_reply, 0, sizeof(auth_reply));
+
+ auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
+
+ auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ auth_reply.params.write.update = 1;
+
+ err_code = sd_ble_gatts_rw_authorize_reply(p_cgms->conn_handle, &auth_reply);
+ if (err_code != NRF_SUCCESS)
+ {
+ if (p_cgms->error_handler != NULL)
+ {
+ p_cgms->error_handler(err_code);
+ }
+ return;
+ }
+
+ // Decode request
+ ble_socp_decode(p_evt_write->len, p_evt_write->data, &socp_request);
+
+ p_cgms->socp_response.opcode = SOCP_RESPONSE_CODE;
+ p_cgms->socp_response.req_opcode = socp_request.opcode;
+ p_cgms->socp_response.rsp_code = SOCP_RSP_OP_CODE_NOT_SUPPORTED;
+ p_cgms->socp_response.size_val = 0;
+
+
+ switch (socp_request.opcode)
+ {
+ case SOCP_WRITE_CGM_COMMUNICATION_INTERVAL:
+ p_cgms->socp_response.rsp_code = SOCP_RSP_SUCCESS;
+ p_cgms->comm_interval = socp_request.p_operand[0];
+ evt.evt_type = NRF_BLE_CGMS_EVT_WRITE_COMM_INTERVAL;
+ p_cgms->evt_handler(p_cgms, &evt);
+ break;
+
+ case SOCP_READ_CGM_COMMUNICATION_INTERVAL:
+ p_cgms->socp_response.opcode = SOCP_READ_CGM_COMMUNICATION_INTERVAL_RESPONSE;
+ p_cgms->socp_response.resp_val[0] = p_cgms->comm_interval;
+ p_cgms->socp_response.size_val++;
+ break;
+
+ case SOCP_START_THE_SESSION:
+ if (p_cgms->is_session_started)
+ {
+ p_cgms->socp_response.rsp_code = SOCP_RSP_PROCEDURE_NOT_COMPLETED;
+ }
+ else if ((p_cgms->nb_run_session != 0) &&
+ !(is_feature_present(p_cgms, NRF_BLE_CGMS_FEAT_MULTIPLE_SESSIONS_SUPPORTED)))
+ {
+ p_cgms->socp_response.rsp_code = SOCP_RSP_PROCEDURE_NOT_COMPLETED;
+ }
+ else
+ {
+ p_cgms->socp_response.rsp_code = SOCP_RSP_SUCCESS;
+ p_cgms->is_session_started = true;
+ p_cgms->nb_run_session++;
+
+ if (p_cgms->evt_handler != NULL)
+ {
+ evt.evt_type = NRF_BLE_CGMS_EVT_START_SESSION;
+ p_cgms->evt_handler(p_cgms, &evt);
+ }
+
+ ble_cgms_sst_t sst;
+ memset(&sst, 0, sizeof(ble_cgms_sst_t));
+
+ err_code = cgms_sst_set(p_cgms, &sst);
+ if (err_code != NRF_SUCCESS)
+ {
+ if (p_cgms->error_handler != NULL)
+ {
+ p_cgms->error_handler(err_code);
+ }
+ }
+ p_cgms->sensor_status.time_offset = 0;
+ p_cgms->sensor_status.status.status &= (~NRF_BLE_CGMS_STATUS_SESSION_STOPPED);
+
+ err_code = nrf_ble_cgms_update_status(p_cgms, &p_cgms->sensor_status);
+ if (err_code != NRF_SUCCESS)
+ {
+ if (p_cgms->error_handler != NULL)
+ {
+ p_cgms->error_handler(err_code);
+ }
+ }
+ }
+ break;
+
+ case SOCP_STOP_THE_SESSION:
+ {
+ nrf_ble_cgm_status_t status;
+ memset(&status, 0, sizeof(nrf_ble_cgm_status_t));
+
+ p_cgms->evt_handler(p_cgms, &evt);
+ p_cgms->socp_response.rsp_code = SOCP_RSP_SUCCESS;
+ p_cgms->is_session_started = false;
+
+ status.time_offset = p_cgms->sensor_status.time_offset;
+ status.status.status = p_cgms->sensor_status.status.status |
+ NRF_BLE_CGMS_STATUS_SESSION_STOPPED;
+
+ if (p_cgms->evt_handler != NULL)
+ {
+ evt.evt_type = NRF_BLE_CGMS_EVT_STOP_SESSION;
+ p_cgms->evt_handler(p_cgms, &evt);
+ }
+ err_code = nrf_ble_cgms_update_status(p_cgms, &status);
+ if (err_code != NRF_SUCCESS)
+ {
+ if (p_cgms->error_handler != NULL)
+ {
+ p_cgms->error_handler(err_code);
+ }
+ }
+ break;
+ }
+
+ default:
+ p_cgms->socp_response.rsp_code = SOCP_RSP_OP_CODE_NOT_SUPPORTED;
+ break;
+ }
+
+ socp_send(p_cgms);
+}
+
+
+void cgms_socp_on_rw_auth_req(nrf_ble_cgms_t * p_cgms,
+ ble_gatts_evt_rw_authorize_request_t const * p_auth_req)
+{
+ if (p_auth_req->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
+ {
+ if (p_auth_req->request.write.handle == p_cgms->char_handles.socp.value_handle)
+ {
+ on_socp_value_write(p_cgms, &p_auth_req->request.write);
+ }
+ }
+}
+
+
+void cgms_socp_on_tx_complete(nrf_ble_cgms_t * p_cgms)
+{
+ if (p_cgms->cgms_com_state == STATE_SOCP_RESPONSE_PENDING)
+ {
+ socp_send(p_cgms);
+ }
+}
+
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_socp.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_socp.h
new file mode 100644
index 0000000..80cb35b
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_socp.h
@@ -0,0 +1,107 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_sdk_srv_cgms_socp Specific Operations Control Point
+ * @{
+ * @ingroup ble_cgms
+ * @brief Continuous Glucose Monitoring Service SOCP module.
+ *
+ * @details This module implements parts of the Continuous Glucose Monitoring that relate to the
+ * Specific Operations Control Point. Events are propagated to this module from @ref ble_cgms
+ * using @ref cgms_socp_on_rw_auth_req and @ref cgms_socp_on_tx_complete.
+ *
+ */
+
+#ifndef NRF_BLE_CGMS_SOCP_H__
+#define NRF_BLE_CGMS_SOCP_H__
+
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "sdk_errors.h"
+#include "nrf_ble_cgms.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**@brief Specific Operation Control Point value. */
+typedef struct
+{
+ uint8_t opcode; /**< Opcode. */
+ uint8_t operand_len; /**< Length of the operand. */
+ uint8_t * p_operand; /**< Pointer to the operand. */
+} ble_cgms_socp_value_t;
+
+
+/**@brief Function for adding a characteristic for the Specific Operations Control Point.
+ *
+ * @param[in] p_cgms Instance of the CGM Service.
+ *
+ * @retval NRF_SUCCESS If the characteristic was successfully added.
+ * @return If functions from other modules return errors to this function,
+ * the @ref nrf_error are propagated.
+ */
+ret_code_t cgms_socp_char_add(nrf_ble_cgms_t * p_cgms);
+
+
+/**@brief Function for handling @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST events.
+ *
+ * @param[in] p_cgms Instance of the CGM Service.
+ * @param[in] p_auth_req Authorize request event to be handled.
+ */
+void cgms_socp_on_rw_auth_req(nrf_ble_cgms_t * p_cgms,
+ ble_gatts_evt_rw_authorize_request_t const * p_auth_req);
+
+
+/**@brief Function for handling @ref BLE_GATTS_EVT_HVN_TX_COMPLETE events.
+ *
+ * @param[in] p_cgms Instance of the CGM Service.
+ */
+void cgms_socp_on_tx_complete(nrf_ble_cgms_t * p_cgms);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // NRF_BLE_CGMS_SOCP_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_sst.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_sst.c
new file mode 100644
index 0000000..b6b2fcd
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_sst.c
@@ -0,0 +1,235 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <stdint.h>
+#include <string.h>
+#include <time.h>
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "nrf_ble_cgms.h"
+#include "cgms_sst.h"
+
+
+void sst_decode(ble_cgms_sst_t * p_sst, const uint8_t * p_data, const uint16_t len)
+{
+ uint32_t index;
+
+ if (len != NRF_BLE_CGMS_SST_LEN)
+ {
+ return;
+ }
+
+ index = ble_date_time_decode(&p_sst->date_time, p_data);
+
+ p_sst->time_zone = p_data[index++];
+ p_sst->dst = p_data[index++];
+}
+
+
+void convert_ble_time_c_time(ble_cgms_sst_t * p_sst, struct tm * p_c_time_date)
+{
+ p_c_time_date->tm_sec = p_sst->date_time.seconds;
+ p_c_time_date->tm_min = p_sst->date_time.minutes;
+ p_c_time_date->tm_hour = p_sst->date_time.hours;
+ p_c_time_date->tm_mday = p_sst->date_time.day;
+ p_c_time_date->tm_mon = p_sst->date_time.month;
+ p_c_time_date->tm_year = p_sst->date_time.year - 1900;
+
+ // Ignore daylight saving for this conversion.
+ p_c_time_date->tm_isdst = 0;
+}
+
+
+void calc_sst(uint16_t offset, struct tm * p_c_time_date)
+{
+ time_t c_time_in_sec;
+
+ c_time_in_sec = mktime(p_c_time_date);
+ c_time_in_sec = c_time_in_sec - (offset * 60);
+ *p_c_time_date = *(localtime(&c_time_in_sec));
+
+ if (p_c_time_date->tm_isdst == 1)
+ {
+ // Daylight saving time is not used and must be removed.
+ p_c_time_date->tm_hour = p_c_time_date->tm_hour - 1;
+ p_c_time_date->tm_isdst = 0;
+ }
+}
+
+
+static void convert_c_time_ble_time(ble_cgms_sst_t * p_sst, struct tm * p_c_time_date)
+{
+ p_sst->date_time.seconds = p_c_time_date->tm_sec;
+ p_sst->date_time.minutes = p_c_time_date->tm_min;
+ p_sst->date_time.hours = p_c_time_date->tm_hour;
+ p_sst->date_time.day = p_c_time_date->tm_mday;
+ p_sst->date_time.month = p_c_time_date->tm_mon;
+ p_sst->date_time.year = p_c_time_date->tm_year + 1900;
+}
+
+
+static uint8_t sst_encode(ble_cgms_sst_t * p_sst, uint8_t * p_encoded_sst)
+{
+ uint8_t len;
+
+ len = ble_date_time_encode(&p_sst->date_time, p_encoded_sst);
+
+ p_encoded_sst[len++] = p_sst->time_zone;
+ p_encoded_sst[len++] = p_sst->dst;
+
+ return len;
+}
+
+
+static ret_code_t cgm_update_sst(nrf_ble_cgms_t * p_cgms, ble_gatts_evt_write_t const * p_evt_write)
+{
+ ble_cgms_sst_t sst;
+ struct tm c_time_and_date;
+
+ memset(&sst, 0, sizeof(ble_cgms_sst_t));
+
+ sst_decode(&sst, p_evt_write->data, p_evt_write->len);
+ convert_ble_time_c_time(&sst, &c_time_and_date);
+ calc_sst(p_cgms->sensor_status.time_offset, &c_time_and_date);
+ convert_c_time_ble_time(&sst, &c_time_and_date);
+
+ return cgms_sst_set(p_cgms, &sst);
+}
+
+
+/**@brief Function for handling the Glucose session start time write event.
+ *
+ * @param[in] p_cgms Service instance.
+ * @param[in] p_evt_write WRITE event to be handled.
+ */
+static void on_sst_value_write(nrf_ble_cgms_t * p_cgms, ble_gatts_evt_write_t const * p_evt_write)
+{
+ ble_gatts_rw_authorize_reply_params_t auth_reply;
+ uint32_t err_code;
+
+ memset(&auth_reply, 0, sizeof(auth_reply));
+
+ auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
+ auth_reply.params.write.update = 1;
+ auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+
+ err_code = sd_ble_gatts_rw_authorize_reply(p_cgms->conn_handle, &auth_reply);
+ if (err_code != NRF_SUCCESS)
+ {
+ if (p_cgms->error_handler != NULL)
+ {
+ p_cgms->error_handler(err_code);
+ }
+ }
+
+ err_code = cgm_update_sst(p_cgms, p_evt_write);
+ if (err_code != NRF_SUCCESS)
+ {
+ if (p_cgms->error_handler != NULL)
+ {
+ p_cgms->error_handler(err_code);
+ }
+ }
+}
+
+
+/**@brief Function for adding a characteristic for the Session Start Time.
+ *
+ * @param[in] p_cgms Service instance.
+ *
+ * @return NRF_SUCCESS if characteristic was successfully added, otherwise an error code.
+ */
+ret_code_t cgms_sst_char_add(nrf_ble_cgms_t * p_cgms)
+{
+ ble_add_char_params_t add_char_params;
+ uint8_t init_value[NRF_BLE_CGMS_SST_LEN] = {0};
+
+ memset(&add_char_params, 0, sizeof(add_char_params));
+
+ add_char_params.uuid = BLE_UUID_CGM_SESSION_START_TIME;
+ add_char_params.max_len = NRF_BLE_CGMS_SST_LEN;
+
+ add_char_params.init_len = NRF_BLE_CGMS_SST_LEN;
+ add_char_params.p_init_value = init_value;
+
+ add_char_params.read_access = SEC_JUST_WORKS;
+ add_char_params.write_access = SEC_JUST_WORKS;
+ add_char_params.is_defered_write = 1;
+ add_char_params.char_props.write = true;
+ add_char_params.char_props.read = true;
+
+ return characteristic_add(p_cgms->service_handle,
+ &add_char_params,
+ &p_cgms->char_handles.sst);
+}
+
+
+ret_code_t cgms_sst_set(nrf_ble_cgms_t * p_cgms, ble_cgms_sst_t * p_sst)
+{
+ uint16_t conn_handle;
+ uint16_t value_handle;
+ ble_gatts_value_t sst_val;
+ uint8_t encoded_start_session_time[NRF_BLE_CGMS_SST_LEN];
+ uint8_t gatts_value_set_len = 0;
+
+ gatts_value_set_len = sst_encode(p_sst, encoded_start_session_time);
+ conn_handle = p_cgms->conn_handle;
+ value_handle = p_cgms->char_handles.sst.value_handle;
+ memset(&sst_val, 0, sizeof(ble_gatts_value_t));
+ sst_val.len = gatts_value_set_len;
+ sst_val.p_value = encoded_start_session_time;
+ sst_val.offset = 0;
+
+ return (sd_ble_gatts_value_set(conn_handle, value_handle, &sst_val));
+}
+
+
+void cgms_sst_on_rw_auth_req(nrf_ble_cgms_t * p_cgms,
+ ble_gatts_evt_rw_authorize_request_t const * p_auth_req)
+{
+ if (p_auth_req->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
+ {
+ if (p_auth_req->request.write.handle == p_cgms->char_handles.sst.value_handle)
+ {
+ on_sst_value_write(p_cgms, &p_auth_req->request.write);
+ }
+ }
+}
+
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_sst.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_sst.h
new file mode 100644
index 0000000..800c81c
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/cgms_sst.h
@@ -0,0 +1,115 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_sdk_srv_cgms_sst Session Start Time
+ * @{
+ * @ingroup ble_cgms
+ *
+ * @brief Continuous Glucose Monitoring Service SST module.
+ *
+ * @details This module implements parts of the Continuous Glucose Monitoring that relate to the
+ * Session Start Time characteristic. Events are propagated to this module from @ref ble_cgms
+ * using @ref cgms_sst_on_rw_auth_req.
+ *
+ */
+
+#ifndef NRF_BLE_CGMS_SST_H__
+#define NRF_BLE_CGMS_SST_H__
+
+
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "ble_date_time.h"
+#include "sdk_errors.h"
+#include "nrf_ble_cgms.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**@brief Required data for setting the SST characteristic value. */
+typedef struct
+{
+ ble_date_time_t date_time; /**< Date and time. */
+ uint8_t time_zone; /**< Time zone. */
+ uint8_t dst; /**< Daylight saving time. */
+}ble_cgms_sst_t;
+
+/**@brief Function for adding a characteristic for the Session Start Time.
+ *
+ * @param[in] p_cgms Instance of the CGM Service.
+ *
+ * @retval NRF_SUCCESS If the characteristic was successfully added.
+ * @return If functions from other modules return errors to this function,
+ * the @ref nrf_error are propagated.
+ */
+ret_code_t cgms_sst_char_add(nrf_ble_cgms_t * p_cgms);
+
+
+/**@brief Function for setting the Session Run Time attribute.
+ *
+ * @param[in] p_cgms Instance of the CGM Service.
+ * @param[in] p_sst Time and date that will be displayed in the session start time attribute.
+ *
+ * @retval NRF_SUCCESS If the Session Run Time Attribute was successfully set.
+ * @return If functions from other modules return errors to this function,
+ * the @ref nrf_error are propagated.
+ */
+ret_code_t cgms_sst_set(nrf_ble_cgms_t * p_cgms, ble_cgms_sst_t * p_sst);
+
+
+/**@brief Function for handling @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST events.
+ *
+ * @param[in] p_cgms Instance of the CGM Service.
+ * @param[in] p_auth_req Authorize request event to be handled.
+ */
+void cgms_sst_on_rw_auth_req(nrf_ble_cgms_t * p_cgms,
+ ble_gatts_evt_rw_authorize_request_t const * p_auth_req);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // NRF_BLE_CGMS_SST_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/nrf_ble_cgms.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/nrf_ble_cgms.c
new file mode 100644
index 0000000..f895edb
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/nrf_ble_cgms.c
@@ -0,0 +1,504 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "ble_racp.h"
+#include "ble_srv_common.h"
+
+#include "ble_date_time.h"
+#include "sdk_common.h"
+
+#include "nrf_ble_cgms.h"
+#include "cgms_db.h"
+#include "cgms_meas.h"
+#include "cgms_racp.h"
+#include "cgms_socp.h"
+#include "cgms_sst.h"
+
+#define OPERAND_FILTER_TYPE_RESV 0x00 /**< Filter type value reserved for future use. */
+#define OPERAND_FILTER_TYPE_SEQ_NUM 0x01 /**< Filter data using Sequence Number criteria. */
+#define OPERAND_FILTER_TYPE_FACING_TIME 0x02 /**< Filter data using User Facing Time criteria. */
+
+
+/**@brief Function for setting next sequence number by reading the last record in the data base.
+ *
+ * @return NRF_SUCCESS on successful initialization of service, otherwise an error code.
+ */
+static uint32_t next_sequence_number_set(void)
+{
+ uint16_t num_records;
+ ble_cgms_rec_t rec;
+
+ num_records = cgms_db_num_records_get();
+ if (num_records > 0)
+ {
+ // Get last record
+ uint32_t err_code = cgms_db_record_get(num_records - 1, &rec);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+uint8_t encode_feature_location_type(uint8_t * p_out_buffer, nrf_ble_cgms_feature_t * p_in_feature)
+{
+ uint8_t len = 0;
+
+ len += uint24_encode(p_in_feature->feature, &p_out_buffer[len]);
+ p_out_buffer[len++] = (p_in_feature->sample_location << 4) | (p_in_feature->type & 0x0F);
+ len += uint16_encode(0xFFFF, &p_out_buffer[len]);
+
+ return len;
+}
+
+
+/**@brief Function for adding a characteristic for the glucose feature.
+ *
+ * @param[in] p_cgms Service instance.
+ *
+ * @return NRF_SUCCESS if characteristic was successfully added, otherwise an error code.
+ */
+static uint32_t glucose_feature_char_add(nrf_ble_cgms_t * p_cgms)
+{
+ uint8_t init_value_len;
+ uint8_t encoded_initial_feature[NRF_BLE_CGMS_FEATURE_LEN];
+ ble_add_char_params_t add_char_params;
+
+ memset(&add_char_params, 0, sizeof(add_char_params));
+
+ init_value_len = encode_feature_location_type(encoded_initial_feature, &(p_cgms->feature));
+
+ add_char_params.uuid = BLE_UUID_CGM_FEATURE;
+ add_char_params.max_len = init_value_len;
+ add_char_params.init_len = init_value_len;
+ add_char_params.p_init_value = encoded_initial_feature;
+ add_char_params.read_access = SEC_JUST_WORKS;
+ add_char_params.write_access = SEC_NO_ACCESS;
+
+
+ return characteristic_add(p_cgms->service_handle,
+ &add_char_params,
+ &p_cgms->char_handles.feature);
+}
+
+
+uint8_t encode_status(uint8_t * p_out_buffer, nrf_ble_cgms_t * p_cgms)
+{
+ uint8_t len = 0;
+
+ len += uint16_encode(p_cgms->sensor_status.time_offset, &p_out_buffer[len]);
+
+ p_out_buffer[len++] = p_cgms->sensor_status.status.status;
+ p_out_buffer[len++] = p_cgms->sensor_status.status.calib_temp;
+ p_out_buffer[len++] = p_cgms->sensor_status.status.warning;
+
+ return len;
+}
+
+
+/**@brief Function for adding a status characteristic for the CGMS.
+ *
+ * @param[in] p_cgms Service instance.
+ *
+ * @return NRF_SUCCESS if characteristic was successfully added, otherwise an error code.
+ */
+static uint32_t status_char_add(nrf_ble_cgms_t * p_cgms)
+{
+ uint8_t init_value_len;
+ uint8_t encoded_initial_status[NRF_BLE_CGMS_STATUS_LEN];
+ ble_add_char_params_t add_char_params;
+
+ memset(&add_char_params, 0, sizeof(add_char_params));
+
+ init_value_len = encode_status(encoded_initial_status, p_cgms);
+
+ add_char_params.uuid = BLE_UUID_CGM_STATUS;
+ add_char_params.max_len = init_value_len;
+ add_char_params.init_len = init_value_len;
+ add_char_params.p_init_value = encoded_initial_status;
+ add_char_params.read_access = SEC_JUST_WORKS;
+ add_char_params.write_access = SEC_NO_ACCESS;
+
+ return characteristic_add(p_cgms->service_handle,
+ &add_char_params,
+ &p_cgms->char_handles.status);
+}
+
+
+/**@brief Function for adding a characteristic for the Session Run Time.
+ *
+ * @param[in] p_cgms Service instance.
+ *
+ * @return NRF_SUCCESS if characteristic was successfully added, otherwise an error code.
+ */
+static uint32_t srt_char_add(nrf_ble_cgms_t * p_cgms)
+{
+ uint8_t len = 0;
+ uint8_t encoded_initial_srt[NRF_BLE_CGMS_SRT_LEN];
+ ble_add_char_params_t add_char_params;
+
+ memset(&add_char_params, 0, sizeof(add_char_params));
+
+
+ len += uint16_encode(p_cgms->session_run_time, &(encoded_initial_srt[len]));
+
+ add_char_params.uuid = BLE_UUID_CGM_SESSION_RUN_TIME;
+ add_char_params.max_len = NRF_BLE_CGMS_SRT_LEN;
+ add_char_params.init_len = len;
+ add_char_params.p_init_value = encoded_initial_srt;
+ add_char_params.read_access = SEC_JUST_WORKS;
+ add_char_params.write_access = SEC_NO_ACCESS;
+ add_char_params.char_props.read = true;
+
+ return characteristic_add(p_cgms->service_handle,
+ &add_char_params,
+ &p_cgms->char_handles.srt);
+}
+
+
+uint8_t init_calib_val[] = {
+ 0x3E,
+ 0x00,
+ 0x07,
+ 0x00,
+ 0x06,
+ 0x07,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+};
+ret_code_t nrf_ble_cgms_init(nrf_ble_cgms_t * p_cgms, const nrf_ble_cgms_init_t * p_cgms_init)
+{
+ VERIFY_PARAM_NOT_NULL(p_cgms);
+ VERIFY_PARAM_NOT_NULL(p_cgms_init);
+ VERIFY_PARAM_NOT_NULL(p_cgms_init->evt_handler);
+
+ uint32_t err_code;
+ ble_uuid_t ble_uuid;
+
+ // Initialize data base
+ err_code = cgms_db_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ err_code = next_sequence_number_set();
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Initialize service structure
+ p_cgms->evt_handler = p_cgms_init->evt_handler;
+ p_cgms->error_handler = p_cgms_init->error_handler;
+ p_cgms->feature = p_cgms_init->feature;
+ p_cgms->sensor_status = p_cgms_init->initial_sensor_status;
+ p_cgms->session_run_time = p_cgms_init->initial_run_time;
+ p_cgms->is_session_started = false;
+ p_cgms->nb_run_session = 0;
+ p_cgms->conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ p_cgms->feature.feature = 0;
+ p_cgms->feature.feature |= NRF_BLE_CGMS_FEAT_MULTIPLE_BOND_SUPPORTED;
+ p_cgms->feature.feature |= NRF_BLE_CGMS_FEAT_MULTIPLE_SESSIONS_SUPPORTED;
+ p_cgms->feature.type = NRF_BLE_CGMS_MEAS_TYPE_VEN_BLOOD;
+ p_cgms->feature.sample_location = NRF_BLE_CGMS_MEAS_LOC_AST;
+ p_cgms->feature.feature |= NRF_BLE_CGMS_FEAT_MULTIPLE_BOND_SUPPORTED;
+
+ memcpy(p_cgms->calibration_val[0].value, init_calib_val, NRF_BLE_CGMS_MAX_CALIB_LEN);
+
+ // Initialize global variables
+ p_cgms->cgms_com_state = STATE_NO_COMM;
+ p_cgms->racp_data.racp_proc_records_reported_since_txcomplete = 0;
+
+ // Add service
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_CGM_SERVICE);
+
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
+ &ble_uuid,
+ &p_cgms->service_handle);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add glucose measurement characteristic
+ err_code = cgms_meas_char_add(p_cgms);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add glucose measurement feature characteristic
+ err_code = glucose_feature_char_add(p_cgms);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add glucose measurement status characteristic
+ err_code = status_char_add(p_cgms);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add record control access point characteristic
+ err_code = cgms_racp_char_add(p_cgms);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add Start Session Time characteristic
+ err_code = cgms_sst_char_add(p_cgms);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add Session Run Time characteristic
+ err_code = srt_char_add(p_cgms);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ // Add Specific Operations Control Point characteristic
+ err_code = cgms_socp_char_add(p_cgms);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for handling the WRITE event.
+ *
+ * @details Handles WRITE events from the BLE stack.
+ *
+ * @param[in] p_cgms Glucose Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_write(nrf_ble_cgms_t * p_cgms, ble_evt_t const * p_ble_evt)
+{
+ ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+ cgms_meas_on_write(p_cgms, p_evt_write);
+}
+
+
+/**@brief Function for handling the TX_COMPLETE event.
+ *
+ * @details Handles TX_COMPLETE events from the BLE stack.
+ *
+ * @param[in] p_cgms Glucose Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_tx_complete(nrf_ble_cgms_t * p_cgms, ble_evt_t const * p_ble_evt)
+{
+ p_cgms->racp_data.racp_proc_records_reported_since_txcomplete = 0;
+
+ cgms_racp_on_tx_complete(p_cgms);
+ cgms_socp_on_tx_complete(p_cgms);
+}
+
+
+/**@brief Function for handling the HVC event.
+ *
+ * @details Handles HVC events from the BLE stack.
+ *
+ * @param[in] p_cgms Glucose Service structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_hvc(nrf_ble_cgms_t * p_cgms, ble_evt_t const * p_ble_evt)
+{
+ ble_gatts_evt_hvc_t const * p_hvc = &p_ble_evt->evt.gatts_evt.params.hvc;
+
+ if (p_hvc->handle == p_cgms->char_handles.racp.value_handle)
+ {
+ if (p_cgms->cgms_com_state == STATE_RACP_RESPONSE_IND_VERIF)
+ {
+ // Indication has been acknowledged. Return to default state.
+ p_cgms->cgms_com_state = STATE_NO_COMM;
+ }
+ else
+ {
+ // We did not expect this event in this state. Report error to application.
+ if (p_cgms->error_handler != NULL)
+ {
+ p_cgms->error_handler(NRF_ERROR_INVALID_STATE);
+ }
+ }
+ }
+ if (p_hvc->handle == p_cgms->char_handles.socp.value_handle)
+ {
+ if (p_cgms->cgms_com_state == STATE_SOCP_RESPONSE_IND_VERIF)
+ {
+ // Indication has been acknowledged. Return to default state.
+ p_cgms->cgms_com_state = STATE_NO_COMM;
+ }
+ else
+ {
+ // We did not expect this event in this state. Report error to application.
+ if (p_cgms->error_handler != NULL)
+ {
+ p_cgms->error_handler(NRF_ERROR_INVALID_STATE);
+ }
+ }
+ }
+}
+
+
+static void on_rw_authorize_request(nrf_ble_cgms_t * p_cgms, ble_gatts_evt_t const * p_gatts_evt)
+{
+ ble_gatts_evt_rw_authorize_request_t const * p_auth_req =
+ &p_gatts_evt->params.authorize_request;
+
+ cgms_racp_on_rw_auth_req(p_cgms, p_auth_req);
+ cgms_socp_on_rw_auth_req(p_cgms, p_auth_req);
+ cgms_sst_on_rw_auth_req(p_cgms, p_auth_req);
+}
+
+
+void nrf_ble_cgms_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ nrf_ble_cgms_t * p_cgms = (nrf_ble_cgms_t *)p_context;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ p_cgms->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+ p_cgms->cgms_com_state = STATE_NO_COMM;
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ p_cgms->conn_handle = BLE_CONN_HANDLE_INVALID;
+ break;
+
+ case BLE_GATTS_EVT_WRITE:
+ on_write(p_cgms, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_HVN_TX_COMPLETE:
+ on_tx_complete(p_cgms, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
+ on_rw_authorize_request(p_cgms, &p_ble_evt->evt.gatts_evt);
+ break;
+
+ case BLE_GATTS_EVT_HVC:
+ on_hvc(p_cgms, p_ble_evt);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+
+ret_code_t nrf_ble_cgms_meas_create(nrf_ble_cgms_t * p_cgms, ble_cgms_rec_t * p_rec)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ uint8_t nb_rec_to_send = 1;
+
+ err_code = cgms_db_record_add(p_rec);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ if ((p_cgms->conn_handle != BLE_CONN_HANDLE_INVALID) && (p_cgms->comm_interval != 0))
+ {
+ err_code = cgms_meas_send(p_cgms, p_rec, &nb_rec_to_send);
+ }
+ return err_code;
+}
+
+
+ret_code_t nrf_ble_cgms_update_status(nrf_ble_cgms_t * p_cgms, nrf_ble_cgm_status_t * p_status)
+{
+ uint8_t encoded_status[NRF_BLE_CGMS_STATUS_LEN];
+ ble_gatts_value_t status_val;
+
+ memset(&status_val, 0, sizeof(status_val));
+ p_cgms->sensor_status = *p_status;
+ status_val.len = encode_status(encoded_status, p_cgms);
+ status_val.p_value = encoded_status;
+ status_val.offset = 0;
+
+ return (sd_ble_gatts_value_set(p_cgms->conn_handle, p_cgms->char_handles.status.value_handle,
+ &status_val));
+}
+
+
+ret_code_t nrf_ble_cgms_conn_handle_assign(nrf_ble_cgms_t * p_cgms, uint16_t conn_handle)
+{
+ VERIFY_PARAM_NOT_NULL(p_cgms);
+ p_cgms->conn_handle = conn_handle;
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t nrf_ble_cgms_srt_set(nrf_ble_cgms_t * p_cgms, uint16_t run_time)
+{
+ ble_gatts_value_t srt_val;
+ uint8_t encoded_session_run_time[NRF_BLE_CGMS_SRT_LEN];
+ uint8_t gatts_value_set_len = 0;
+
+ gatts_value_set_len = uint16_encode(run_time, encoded_session_run_time); // (p_sst, encoded_start_session_time);
+
+ memset(&srt_val, 0, sizeof(ble_gatts_value_t));
+ srt_val.len = gatts_value_set_len;
+ srt_val.p_value = encoded_session_run_time;
+ srt_val.offset = 0;
+
+ return (sd_ble_gatts_value_set(p_cgms->conn_handle, p_cgms->char_handles.srt.value_handle,
+ &srt_val));
+}
+
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/nrf_ble_cgms.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/nrf_ble_cgms.h
new file mode 100644
index 0000000..dbac766
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_cgms/nrf_ble_cgms.h
@@ -0,0 +1,453 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_cgms Continuous Glucose Monitoring Service
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Continuous Glucose Monitoring Service (CGMS) module.
+ *
+ * @details This module implements a sensor for the Continuous Glucose Monitoring Service.
+ * The sensor is a GATT Server that sends CGM measurements to a connected CGMS
+ * Collector. The CGMS Sensor stores records that can be accessed with the
+ * Record Access Control Point (RACP). The collector can access the features and status
+ * of the sensor. Session Run Time and Session Start Time can be used to convey timing
+ * information between the sensor and the collector. The Specific Operations Control Point
+ * is used to stop and start monitoring sessions, among other things.
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * nrf_ble_cgms_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, NRF_BLE_CGMS_BLE_OBSERVER_PRIO,
+ * nrf_ble_cgms_on_ble_evt, &instance);
+ * @endcode
+ */
+
+#ifndef NRF_BLE_CGMS_H__
+#define NRF_BLE_CGMS_H__
+
+#include "ble_srv_common.h"
+#include "sdk_errors.h"
+#include "ble_racp.h"
+#include "nrf_sdh_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a nrf_ble_cgms instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define NRF_BLE_CGMS_DEF(_name) \
+static nrf_ble_cgms_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ NRF_BLE_CGMS_BLE_OBSERVER_PRIO, \
+ nrf_ble_cgms_on_ble_evt, &_name)
+
+/**@name CGM Feature characteristic defines
+ * @{ */
+#define NRF_BLE_CGMS_FEAT_CALIBRATION_SUPPORTED (0x01 << 0) //!< Calibration supported.
+#define NRF_BLE_CGMS_FEAT_PATIENT_HIGH_LOW_ALERTS_SUPPORTED (0x01 << 1) //!< Patient High/Low Alerts supported.
+#define NRF_BLE_CGMS_FEAT_HYPO_ALERTS_SUPPORTED (0x01 << 2) //!< Hypo Alerts supported.
+#define NRF_BLE_CGMS_FEAT_HYPER_ALERTS_SUPPORTED (0x01 << 3) //!< Hyper Alerts supported.
+#define NRF_BLE_CGMS_FEAT_RATE_OF_INCREASE_DECREASE_ALERTS_SUPPORTED (0x01 << 4) //!< Rate of Increase/Decrease Alerts supported.
+#define NRF_BLE_CGMS_FEAT_DEVICE_SPECIFIC_ALERT_SUPPORTED (0x01 << 5) //!< Device Specific Alert supported.
+#define NRF_BLE_CGMS_FEAT_SENSOR_MALFUNCTION_DETECTION_SUPPORTED (0x01 << 6) //!< Sensor Malfunction Detection supported.
+#define NRF_BLE_CGMS_FEAT_SENSOR_TEMPERATURE_HIGH_LOW_DETECTION_SUPPORTED (0x01 << 7) //!< Sensor Temperature High-Low Detection supported.
+#define NRF_BLE_CGMS_FEAT_SENSOR_RESULT_HIGH_LOW_DETECTION_SUPPORTED (0x01 << 8) //!< Sensor Result High-Low Detection supported.
+#define NRF_BLE_CGMS_FEAT_LOW_BATTERY_DETECTION_SUPPORTED (0x01 << 9) //!< Low Battery Detection supported.
+#define NRF_BLE_CGMS_FEAT_SENSOR_TYPE_ERROR_DETECTION_SUPPORTED (0x01 << 10) //!< Sensor Type Error Detection supported.
+#define NRF_BLE_CGMS_FEAT_GENERAL_DEVICE_FAULT_SUPPORTED (0x01 << 11) //!< General Device Fault supported.
+#define NRF_BLE_CGMS_FEAT_E2E_CRC_SUPPORTED (0x01 << 12) //!< E2E-CRC supported.
+#define NRF_BLE_CGMS_FEAT_MULTIPLE_BOND_SUPPORTED (0x01 << 13) //!< Multiple Bond supported.
+#define NRF_BLE_CGMS_FEAT_MULTIPLE_SESSIONS_SUPPORTED (0x01 << 14) //!< Multiple Sessions supported.
+#define NRF_BLE_CGMS_FEAT_CGM_TREND_INFORMATION_SUPPORTED (0x01 << 15) //!< CGM Trend Information supported.
+#define NRF_BLE_CGMS_FEAT_CGM_QUALITY_SUPPORTED (0x01 << 16) //!< CGM Quality supported.
+/** @} */
+
+/**@name Continuous Glucose Monitoring type
+ * @{ */
+#define NRF_BLE_CGMS_MEAS_TYPE_CAP_BLOOD 0x01 //!< Capillary Whole blood.
+#define NRF_BLE_CGMS_MEAS_TYPE_CAP_PLASMA 0x02 //!< Capillary Plasma.
+#define NRF_BLE_CGMS_MEAS_TYPE_VEN_BLOOD 0x03 //!< Venous Whole blood.
+#define NRF_BLE_CGMS_MEAS_TYPE_VEN_PLASMA 0x04 //!< Venous Plasma.
+#define NRF_BLE_CGMS_MEAS_TYPE_ART_BLOOD 0x05 //!< Arterial Whole blood.
+#define NRF_BLE_CGMS_MEAS_TYPE_ART_PLASMA 0x06 //!< Arterial Plasma.
+#define NRF_BLE_CGMS_MEAS_TYPE_UNDET_BLOOD 0x07 //!< Undetermined Whole blood.
+#define NRF_BLE_CGMS_MEAS_TYPE_UNDET_PLASMA 0x08 //!< Undetermined Plasma.
+#define NRF_BLE_CGMS_MEAS_TYPE_FLUID 0x09 //!< Interstitial Fluid (ISF).
+#define NRF_BLE_CGMS_MEAS_TYPE_CONTROL 0x0A //!< Control Solution.
+/** @} */
+
+/**@name CGM sample location
+ * @{ */
+#define NRF_BLE_CGMS_MEAS_LOC_FINGER 0x01 //!< Finger.
+#define NRF_BLE_CGMS_MEAS_LOC_AST 0x02 //!< Alternate Site Test (AST).
+#define NRF_BLE_CGMS_MEAS_LOC_EAR 0x03 //!< Earlobe.
+#define NRF_BLE_CGMS_MEAS_LOC_CONTROL 0x04 //!< Control solution.
+#define NRF_BLE_CGMS_MEAS_LOC_SUB_TISSUE 0x05 //!< Subcutaneous tissue.
+#define NRF_BLE_CGMS_MEAS_LOC_NOT_AVAIL 0x0F //!< Sample Location value not available.
+/** @} */
+
+/**@name CGM Measurement Sensor Status Annunciation
+ * @{ */
+#define NRF_BLE_CGMS_STATUS_SESSION_STOPPED (0x01 << 0) //!< Status: Session Stopped.
+#define NRF_BLE_CGMS_STATUS_DEVICE_BATTERY_LOW (0x01 << 1) //!< Status: Device Battery Low.
+#define NRF_BLE_CGMS_STATUS_SENSOR_TYPE_INCORRECT_FOR_DEVICE (0x01 << 2) //!< Status: Sensor type incorrect for device.
+#define NRF_BLE_CGMS_STATUS_SENSOR_MALFUNCTION (0x01 << 3) //!< Status: Sensor malfunction.
+#define NRF_BLE_CGMS_STATUS_DEVICE_SPECIFIC_ALERT (0x01 << 4) //!< Status: Device Specific Alert.
+#define NRF_BLE_CGMS_STATUS_GENERAL_DEVICE_FAULT (0x01 << 5) //!< Status: General device fault has occurred in the sensor.
+/** @} */
+
+/**@name CGM Measurement flags
+ * @{ */
+#define NRF_BLE_CGMS_FLAG_TREND_INFO_PRESENT 0x01 //!< CGM Trend Information Present.
+#define NRF_BLE_CGMS_FLAGS_QUALITY_PRESENT 0x02 //!< CGM Quality Present.
+#define NRF_BLE_CGMS_STATUS_FLAGS_WARNING_OCT_PRESENT 0x20 //!< Sensor Status Annunciation Field, Warning-Octet present.
+#define NRF_BLE_CGMS_STATUS_FLAGS_CALTEMP_OCT_PRESENT 0x40 //!< Sensor Status Annunciation Field, Cal/Temp-Octet present.
+#define NRF_BLE_CGMS_STATUS_FLAGS_STATUS_OCT_PRESENT 0x80 //!< Sensor Status Annunciation Field, Status-Octet present.
+/** @} */
+
+/**@name Byte length of various commands (used for validating, encoding, and decoding data).
+ * @{ */
+#define NRF_BLE_CGMS_MEAS_OP_LEN 1 //!< Length of the opcode inside the Glucose Measurement packet.
+#define NRF_BLE_CGMS_MEAS_HANDLE_LEN 2 //!< Length of the handle inside the Glucose Measurement packet.
+#define NRF_BLE_CGMS_MEAS_LEN_MAX (BLE_GATT_ATT_MTU_DEFAULT - \
+ NRF_BLE_CGMS_MEAS_OP_LEN - \
+ NRF_BLE_CGMS_MEAS_HANDLE_LEN) //!< Maximum size of a transmitted Glucose Measurement.
+
+#define NRF_BLE_CGMS_MEAS_REC_LEN_MAX 15 //!< Maximum length of one measurement record. Size 1 byte, flags 1 byte, glucose concentration 2 bytes, offset 2 bytes, status 3 bytes, trend 2 bytes, quality 2 bytes, CRC 2 bytes.
+#define NRF_BLE_CGMS_MEAS_REC_LEN_MIN 6 //!< Minimum length of one measurement record. Size 1 byte, flags 1 byte, glucose concentration 2 bytes, offset 2 bytes.
+#define NRF_BLE_CGMS_MEAS_REC_PER_NOTIF_MAX (NRF_BLE_CGMS_MEAS_LEN_MAX / \
+ NRF_BLE_CGMS_MEAS_REC_LEN_MIN) //!< Maximum number of records per notification. We can send more than one measurement record per notification, but we do not want a a single record split over two notifications.
+
+#define NRF_BLE_CGMS_SOCP_RESP_CODE_LEN 2 //!< Length of a response. Response code 1 byte, response value 1 byte.
+#define NRF_BLE_CGMS_FEATURE_LEN 6 //!< Length of a feature. Feature 3 bytes, type 4 bits, sample location 4 bits, CRC 2 bytes.
+#define NRF_BLE_CGMS_STATUS_LEN 7 //!< Length of a status. Offset 2 bytes, status 3 bytes, CRC 2 bytes.
+#define NRF_BLE_CGMS_MAX_CALIB_LEN 10 //!< Length of a calibration record. Concentration 2 bytes, time 2 bytes, calibration 4 bits, calibration sample location 4 bits, next calibration time 2 bytes, record number 2 bytes, calibration status 1 byte.
+#define NRF_BLE_CGMS_CALIBS_NB_MAX 5 //!< Maximum number of calibration values that can be stored.
+#define NRF_BLE_CGMS_SST_LEN 9 //!< Length of the start time. Date time 7 bytes, time zone 1 byte, DST 1 byte.
+#define NRF_BLE_CGMS_CRC_LEN 2 //!< Length of the CRC bytes (if used).
+#define NRF_BLE_CGMS_SRT_LEN 2 //!< Length of the Session Run Time attribute.
+
+#define NRF_BLE_CGMS_SOCP_RESP_LEN (NRF_BLE_CGMS_MEAS_LEN_MAX - \
+ NRF_BLE_CGMS_SOCP_RESP_CODE_LEN) //!< Max lenth of a SOCP response.
+
+#define NRF_BLE_CGMS_RACP_PENDING_OPERANDS_MAX 2 // !< Maximum number of pending Record Access Control Point operations.
+/** @} */
+
+/**
+ * @defgroup nrf_ble_cgms_enums Enumerations
+ * @{
+ */
+
+/**@brief CGM Service events. */
+typedef enum
+{
+ NRF_BLE_CGMS_EVT_NOTIFICATION_ENABLED, /**< Glucose value notification enabled. */
+ NRF_BLE_CGMS_EVT_NOTIFICATION_DISABLED, /**< Glucose value notification disabled. */
+ NRF_BLE_CGMS_EVT_START_SESSION, /**< Glucose value notification start session. */
+ NRF_BLE_CGMS_EVT_STOP_SESSION, /**< Glucose value notification stop session. */
+ NRF_BLE_CGMS_EVT_WRITE_COMM_INTERVAL, /**< Glucose value write communication interval. */
+} nrf_ble_cgms_evt_type_t;
+
+
+/**@brief CGM Service communication states. */
+typedef enum
+{
+ STATE_NO_COMM, /**< The service is not in a communicating state. */
+ STATE_RACP_PROC_ACTIVE, /**< Processing requested data. */
+ STATE_RACP_RESPONSE_PENDING, /**< There is an RACP indication waiting to be sent. */
+ STATE_RACP_RESPONSE_IND_VERIF, /**< Waiting for a verification of an RACP indication. */
+ STATE_SOCP_RESPONSE_PENDING, /**< There is an SOCP indication waiting to be sent. */
+ STATE_SOCP_RESPONSE_IND_VERIF /**< Waiting for a verification of an SOCP indication. */
+} nrf_ble_cgms_com_state_t;
+
+/** @} */ // End tag for Enumeration group.
+
+/**
+ * @defgroup nrf_ble_cgms_structs Structures
+ * @{
+ */
+
+/**@brief CGM Service event. */
+typedef struct
+{
+ nrf_ble_cgms_evt_type_t evt_type; /**< Type of event. */
+} nrf_ble_cgms_evt_t;
+
+/** @} */ // End tag for Structure group.
+
+/**
+ * @defgroup nrf_ble_cgms_types Types
+ * @{
+ */
+
+/**@brief Forward declaration of the nrf_ble_cgms_t type. */
+typedef struct ble_cgms_s nrf_ble_cgms_t;
+
+
+/**@brief CGM Service event handler type. */
+typedef void (* ble_cgms_evt_handler_t) (nrf_ble_cgms_t * p_cgms, nrf_ble_cgms_evt_t * p_evt);
+
+/** @} */ // End tag for Types group.
+
+/**
+ * @addtogroup nrf_ble_cgms_structs
+ * @{
+ */
+
+/**@brief CGM Measurement Sensor Status Annunciation. */
+typedef struct
+{
+ uint8_t warning; /**< Warning annunciation. */
+ uint8_t calib_temp; /**< Calibration and Temperature annunciation. */
+ uint8_t status; /**< Status annunciation. */
+} nrf_ble_cgms_sensor_annunc_t;
+
+
+/**@brief CGM measurement. */
+typedef struct
+{
+ uint8_t flags; /**< Indicates the presence of optional fields and the Sensor Status Annunciation field. */
+ uint16_t glucose_concentration; /**< Glucose concentration. 16-bit word comprising 4-bit exponent and signed 12-bit mantissa. */
+ uint16_t time_offset; /**< Time offset. Represents the time difference between measurements. */
+ nrf_ble_cgms_sensor_annunc_t sensor_status_annunciation; /**< Sensor Status Annunciation. Variable length, can include Status, Cal/Temp, and Warning. */
+ uint16_t trend; /**< Optional field that can include Trend Information. */
+ uint16_t quality; /**< Optional field that includes the Quality of the measurement. */
+} nrf_ble_cgms_meas_t;
+
+
+/**@brief CGM Measurement record. */
+typedef struct
+{
+ nrf_ble_cgms_meas_t meas; /**< CGM measurement. */
+} ble_cgms_rec_t;
+
+
+/**@brief Features supported by the CGM Service. */
+typedef struct
+{
+ uint32_t feature; /**< Information on supported features in the CGM Service. */
+ uint8_t type; /**< Type. */
+ uint8_t sample_location; /**< Sample location. */
+}nrf_ble_cgms_feature_t;
+
+
+/**@brief Status of the CGM measurement. */
+typedef struct
+{
+ uint16_t time_offset; /**< Time offset. */
+ nrf_ble_cgms_sensor_annunc_t status; /**< Status. */
+} nrf_ble_cgm_status_t;
+
+
+/**@brief CGM Service initialization structure that contains all options and data needed for
+ * initializing the service. */
+typedef struct
+{
+ ble_cgms_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the CGM Service. */
+ ble_srv_error_handler_t error_handler; /**< Function to be called when an error occurs. */
+ nrf_ble_cgms_feature_t feature; /**< Features supported by the service. */
+ nrf_ble_cgm_status_t initial_sensor_status; /**< Sensor status. */
+ uint16_t initial_run_time; /**< Run time. */
+} nrf_ble_cgms_init_t;
+
+
+/**@brief Specific Operation Control Point response structure. */
+typedef struct
+{
+ uint8_t opcode; /**< Opcode describing the response. */
+ uint8_t req_opcode; /**< The original opcode for the request to which this response belongs. */
+ uint8_t rsp_code; /**< Response code. */
+ uint8_t resp_val[NRF_BLE_CGMS_SOCP_RESP_LEN]; /**< Array containing the response value. */
+ uint8_t size_val; /**< Length of the response value. */
+} ble_socp_rsp_t;
+
+
+/**@brief Calibration value. */
+typedef struct
+{
+ uint8_t value[NRF_BLE_CGMS_MAX_CALIB_LEN]; /**< Array containing the calibration value. */
+} nrf_ble_cgms_calib_t;
+
+
+/**@brief Record Access Control Point transaction data. */
+typedef struct
+{
+ uint8_t racp_proc_operator; /**< Operator of the current request. */
+ uint16_t racp_proc_record_ndx; /**< Current record index. */
+ uint16_t racp_proc_records_ndx_last_to_send; /**< The last record to send, can be used together with racp_proc_record_ndx to determine a range of records to send. (used by greater/less filters). */
+ uint16_t racp_proc_records_reported; /**< Number of reported records. */
+ uint16_t racp_proc_records_reported_since_txcomplete; /**< Number of reported records since the last TX_COMPLETE event. */
+ ble_racp_value_t racp_request; /**< RACP procedure that has been requested from the peer. */
+ ble_racp_value_t pending_racp_response; /**< RACP response to be sent. */
+ uint8_t pending_racp_response_operand[NRF_BLE_CGMS_RACP_PENDING_OPERANDS_MAX]; /**< Operand of the RACP response to be sent. */
+} nrf_ble_cgms_racp_t;
+
+
+/** @brief Handles related to CGM characteristics. */
+typedef struct
+{
+ ble_gatts_char_handles_t measurment; /**< Handles related to the CGM Measurement characteristic. */
+ ble_gatts_char_handles_t feature; /**< Handles related to the CGM Feature characteristic. */
+ ble_gatts_char_handles_t sst; /**< Handles related to the CGM Session Start Time characteristic. */
+ ble_gatts_char_handles_t racp; /**< Handles related to the CGM Record Access Control Point characteristic. */
+ ble_gatts_char_handles_t srt; /**< Handles related to the CGM Session Run Time characteristic. */
+ ble_gatts_char_handles_t socp; /**< Handles related to the CGM Specific Operations Control Point characteristic. */
+ ble_gatts_char_handles_t status; /**< Handles related to the CGM Status characteristic. */
+} nrf_ble_cgms_char_handler_t;
+
+
+/**@brief Status information for the CGM Service. */
+struct ble_cgms_s
+{
+ ble_cgms_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the CGM Service. */
+ ble_srv_error_handler_t error_handler; /**< Function to be called if an error occurs. */
+ uint16_t service_handle; /**< Handle of the CGM Service (as provided by the BLE stack). */
+ nrf_ble_cgms_char_handler_t char_handles; /**< GATTS characteristic handles for the different characteristics in the service. */
+ uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack; @ref BLE_CONN_HANDLE_INVALID if not in a connection). */
+ nrf_ble_cgms_feature_t feature; /**< Structure to store the value of the feature characteristic. */
+ uint8_t comm_interval; /**< Variable to keep track of the communication interval. */
+ ble_socp_rsp_t socp_response; /**< Structure containing reponse data to be indicated to the peer device. */
+ nrf_ble_cgms_calib_t calibration_val[NRF_BLE_CGMS_CALIBS_NB_MAX]; /**< Calibration value. Can be read from and written to SOCP. */
+ bool is_session_started; /**< Indicator if we are currently in a session. */
+ uint8_t nb_run_session; /**< Variable to keep track of the number of sessions that were run. */
+ uint16_t session_run_time; /**< Variable to store the expected run time of a session. */
+ nrf_ble_cgm_status_t sensor_status; /**< Structure to keep track of the sensor status. */
+ nrf_ble_cgms_com_state_t cgms_com_state; /**< Current communication state. */
+ nrf_ble_cgms_racp_t racp_data; /**< Structure to manage Record Access requests. */
+};
+
+/** @} */
+
+
+/**
+ * @defgroup nrf_ble_cgms_functions Functions
+ * @{
+ */
+
+/**@brief Function for updating the status.
+ *
+ * @param[in] p_cgms Instance of the CGM Service.
+ * @param[in] p_status New status.
+ *
+ * @retval NRF_SUCCESS If the status was updated successfully.
+ * @return If functions from other modules return errors to this function,
+ * the @ref nrf_error are propagated.
+ */
+ret_code_t nrf_ble_cgms_update_status(nrf_ble_cgms_t * p_cgms, nrf_ble_cgm_status_t * p_status);
+
+
+/**@brief Function for initializing the CGM Service.
+ *
+ * @param[out] p_cgms CGM Service structure. This structure must be supplied by
+ * the application. It is initialized by this function and will later
+ * be used to identify this particular service instance.
+ * @param[in] p_cgms_init Information needed to initialize the service.
+ *
+ * @retval NRF_SUCCESS If the service was initialized successfully.
+ * @retval NRF_ERROR_NULL If any of the input parameters are NULL.
+ * @return If functions from other modules return errors to this function,
+ * the @ref nrf_error are propagated.
+ */
+ret_code_t nrf_ble_cgms_init(nrf_ble_cgms_t * p_cgms, const nrf_ble_cgms_init_t * p_cgms_init);
+
+
+/**@brief Function for handling the application's BLE stack events.
+ *
+ * @details Handles all events from the BLE stack that are of interest to the CGM Service.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Instance of the CGM Service.
+ */
+void nrf_ble_cgms_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for reporting a new glucose measurement to the CGM Service module.
+ *
+ * @details The application calls this function after having performed a new glucose measurement.
+ * The new measurement is recorded in the RACP database.
+ *
+ * @param[in] p_cgms Instance of the CGM Service.
+ * @param[in] p_rec Pointer to the glucose record (measurement plus context).
+ *
+ * @retval NRF_SUCCESS If a measurement was successfully created.
+ * @return If functions from other modules return errors to this function,
+ * the @ref nrf_error are propagated.
+ */
+ret_code_t nrf_ble_cgms_meas_create(nrf_ble_cgms_t * p_cgms, ble_cgms_rec_t * p_rec);
+
+
+/**@brief Function for assigning a connection handle to a CGM Service instance.
+ *
+ * @param[in] p_cgms Instance of the CGM Service.
+ * @param[in] conn_handle Connection Handle to use for this instance of the CGM Service.
+ *
+ * @retval NRF_SUCCESS If the connection handle was successfully stored in the CGM Service instance.
+ * @retval NRF_ERROR_NULL If any of the input parameters are NULL.
+ */
+ret_code_t nrf_ble_cgms_conn_handle_assign(nrf_ble_cgms_t * p_cgms, uint16_t conn_handle);
+
+
+/**@brief Function for setting the Session Run Time attribute value.
+ *
+ * @param[in] p_cgms Instance of the CGM Service.
+ * @param[in] run_time Run Time that will be displayed in the Session Run Time
+ * attribute value.
+ *
+ * @retval NRF_SUCCESS If the Session Run Time attribute value was set successfully.
+ * @return If functions from other modules return errors to this function,
+ * the @ref nrf_error are propagated.
+ */
+ret_code_t nrf_ble_cgms_srt_set(nrf_ble_cgms_t * p_cgms, uint16_t run_time);
+
+/** @} */ // End tag for Function group.
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // NRF_BLE_CGMS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c.c
new file mode 100644
index 0000000..aa5c6ee
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c.c
@@ -0,0 +1,374 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_OTS_C)
+#include <stdlib.h>
+#include "nrf_ble_ots_c.h"
+#include "nrf_ble_ots_c_oacp.h"
+#include "nrf_ble_ots_c_l2cap.h"
+#include "ble.h"
+
+#define NRF_LOG_MODULE_NAME ble_ots_c
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#include "sdk_common.h"
+
+
+#define BLE_OTS_OACP_SUPPORT_FEATURE_CREATE_bp 0
+#define BLE_OTS_OACP_SUPPORT_FEATURE_DELETE_bp 1
+#define BLE_OTS_OACP_SUPPORT_FEATURE_CALC_CHECKSUM_bp 2
+#define BLE_OTS_OACP_SUPPORT_FEATURE_EXECUTE_bp 3
+#define BLE_OTS_OACP_SUPPORT_FEATURE_READ_bp 4
+#define BLE_OTS_OACP_SUPPORT_FEATURE_WRITE_bp 5
+#define BLE_OTS_OACP_SUPPORT_FEATURE_APPEND_bp 6
+#define BLE_OTS_OACP_SUPPORT_FEATURE_TRUNCATE_bp 7
+#define BLE_OTS_OACP_SUPPORT_FEATURE_PATCH_bp 8
+#define BLE_OTS_OACP_SUPPORT_FEATURE_ABORT_bp 9
+
+#define BLE_OTS_OLCP_SUPPORT_FEATURE_GOTO_bp 0
+#define BLE_OTS_OLCP_SUPPORT_FEATURE_ORDER_bp 1
+#define BLE_OTS_OLCP_SUPPORT_FEATURE_REQ_NUM_OBJECTS_bp 2
+#define BLE_OTS_OLCP_SUPPORT_FEATURE_CLEAR_MARKING_bp 3
+
+#define MODULE_INITIALIZED (p_ots_c->initialized) /**< Macro designating whether the module has been initialized properly. */
+
+static const ble_uuid_t m_ots_uuid = {BLE_UUID_OTS_SERVICE, BLE_UUID_TYPE_BLE}; /**< Object Transfer Service UUID. */
+
+
+ret_code_t nrf_ble_ots_c_init(nrf_ble_ots_c_t * p_ots_c,
+ nrf_ble_ots_c_init_t * p_ots_c_init)
+{
+ ret_code_t err_code = NRF_SUCCESS;
+ VERIFY_PARAM_NOT_NULL(p_ots_c);
+ VERIFY_PARAM_NOT_NULL(p_ots_c_init);
+ VERIFY_PARAM_NOT_NULL(p_ots_c_init->evt_handler);
+ memset (p_ots_c, 0, sizeof(nrf_ble_ots_c_t));
+
+ p_ots_c->conn_handle = BLE_CONN_HANDLE_INVALID;
+ p_ots_c->evt_handler = p_ots_c_init->evt_handler;
+
+ err_code = ble_db_discovery_evt_register(&m_ots_uuid);
+ VERIFY_SUCCESS(err_code);
+
+ p_ots_c->initialized = true;
+ return err_code;
+}
+
+
+/**@brief Function for checking whether the peer's Object Transfer Service instance has been discovered.
+
+ @param[in] p_ots_c Pointer to the GATT Service client structure instance.
+
+ @return True if the Object Transfer service handles are valid.
+ @return False if the Object Transfer service handles are invalid
+ */
+static bool ots_gatt_handles_are_valid(const nrf_ble_ots_c_t * const p_ots_c)
+{
+ return (p_ots_c->service.object_prop_char.handle_value != BLE_GATT_HANDLE_INVALID
+ && p_ots_c->service.object_size_char.handle_value != BLE_GATT_HANDLE_INVALID
+ && p_ots_c->service.object_type_char.handle_value != BLE_GATT_HANDLE_INVALID
+ && p_ots_c->service.ots_feature_char.handle_value != BLE_GATT_HANDLE_INVALID);
+}
+
+
+ret_code_t nrf_ble_ots_c_feature_read(nrf_ble_ots_c_t * const p_ots_c)
+{
+ VERIFY_MODULE_INITIALIZED();
+
+ ret_code_t err_code;
+ err_code = sd_ble_gattc_read(p_ots_c->conn_handle,
+ p_ots_c->service.ots_feature_char.handle_value,
+ 0);
+ return err_code;
+}
+
+
+ret_code_t nrf_ble_ots_c_obj_size_read(nrf_ble_ots_c_t * const p_ots_c)
+{
+ VERIFY_MODULE_INITIALIZED();
+
+ if( p_ots_c->service.object_size_char.handle_value == BLE_GATT_HANDLE_INVALID)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+ ret_code_t err_code;
+ err_code = sd_ble_gattc_read(p_ots_c->conn_handle,
+ p_ots_c->service.object_size_char.handle_value,
+ 0);
+ return err_code;
+}
+
+/**@brief Function for handling read response events.
+ *
+ * @details This function will validate the read response and raise the appropriate
+ * event to the application.
+ *
+ * @param[in] p_bas_c Pointer to the Battery Service Client Structure.
+ * @param[in] p_ble_evt Pointer to the SoftDevice event.
+ */
+static void on_read_rsp(nrf_ble_ots_c_t * p_ots_c, const ble_evt_t * p_ble_evt)
+{
+ const ble_gattc_evt_read_rsp_t * p_response;
+
+ // Check if the event is on the link for this instance
+ if (p_ots_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
+ {
+ return;
+ }
+
+ p_response = &p_ble_evt->evt.gattc_evt.params.read_rsp;
+
+ if (p_response->handle == p_ots_c->service.ots_feature_char.handle_value)
+ {
+ nrf_ble_ots_c_evt_t evt;
+
+ evt.conn_handle = p_ble_evt->evt.gattc_evt.conn_handle;
+ evt.evt_type = NRF_BLE_OTS_C_EVT_FEATURE_READ_RESP;
+
+ uint32_t oacp_features;
+ oacp_features = uint32_decode(&p_response->data[0]);
+ evt.params.feature.oacp_create = oacp_features >> BLE_OTS_OACP_SUPPORT_FEATURE_CREATE_bp;
+ evt.params.feature.oacp_delete = oacp_features >> BLE_OTS_OACP_SUPPORT_FEATURE_DELETE_bp;
+ evt.params.feature.oacp_crc = oacp_features >> BLE_OTS_OACP_SUPPORT_FEATURE_CALC_CHECKSUM_bp;
+ evt.params.feature.oacp_execute = oacp_features >> BLE_OTS_OACP_SUPPORT_FEATURE_EXECUTE_bp;
+ evt.params.feature.oacp_read = oacp_features >> BLE_OTS_OACP_SUPPORT_FEATURE_READ_bp;
+ evt.params.feature.oacp_write = oacp_features >> BLE_OTS_OACP_SUPPORT_FEATURE_WRITE_bp;
+ evt.params.feature.oacp_append = oacp_features >> BLE_OTS_OACP_SUPPORT_FEATURE_APPEND_bp;
+ evt.params.feature.oacp_truncate = oacp_features >> BLE_OTS_OACP_SUPPORT_FEATURE_TRUNCATE_bp;
+ evt.params.feature.oacp_patch = oacp_features >> BLE_OTS_OACP_SUPPORT_FEATURE_PATCH_bp;
+ evt.params.feature.oacp_abort = oacp_features >> BLE_OTS_OACP_SUPPORT_FEATURE_ABORT_bp;
+
+ uint32_t olcp_features;
+/*lint --e{415} --e{416} -save suppress Warning 415: Likely access of out-of-bounds pointer */
+ olcp_features = uint32_decode(&p_response->data[sizeof(uint32_t)]);
+/*lint -restore*/
+ evt.params.feature.olcp_goto = olcp_features >> BLE_OTS_OLCP_SUPPORT_FEATURE_GOTO_bp;
+ evt.params.feature.olcp_order = olcp_features >> BLE_OTS_OLCP_SUPPORT_FEATURE_ORDER_bp;
+ evt.params.feature.olcp_req_num = olcp_features >> BLE_OTS_OLCP_SUPPORT_FEATURE_REQ_NUM_OBJECTS_bp;
+ evt.params.feature.olcp_clear = olcp_features >> BLE_OTS_OLCP_SUPPORT_FEATURE_CLEAR_MARKING_bp;
+
+ p_ots_c->evt_handler(&evt);
+ }
+ if (p_response->handle == p_ots_c->service.object_size_char.handle_value)
+ {
+ nrf_ble_ots_c_evt_t evt;
+
+ evt.conn_handle = p_ble_evt->evt.gattc_evt.conn_handle;
+ evt.evt_type = NRF_BLE_OTS_C_EVT_SIZE_READ_RESP;
+
+ uint8_t len = 0;
+ evt.params.size.current_size = uint32_decode(&p_response->data[len]);
+ len += sizeof(uint32_t);
+/*lint --e{415} --e{416} -save suppress Warning 415: Likely access of out-of-bounds pointer */
+ evt.params.size.allocated_size = uint32_decode(&p_response->data[len]);
+/*lint -restore*/
+
+/*lint --e{438} -save */
+ len += sizeof(uint32_t);
+/*lint -restore*/
+
+ p_ots_c->evt_handler(&evt);
+ }
+}
+
+
+void nrf_ble_ots_c_on_db_disc_evt(nrf_ble_ots_c_t const * const p_ots_c,
+ ble_db_discovery_evt_t * const p_evt)
+{
+ VERIFY_MODULE_INITIALIZED_VOID();
+
+ nrf_ble_ots_c_evt_t evt;
+ ble_gatt_db_char_t* p_chars;
+
+ p_chars = p_evt->params.discovered_db.charateristics;
+ evt.evt_type = NRF_BLE_OTS_C_EVT_DISCOVERY_FAILED;
+
+ if ((p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE) &&
+ (p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_OTS_SERVICE) &&
+ (p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE))
+ {
+ // Find the handles of the ANCS characteristic.
+ for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
+ {
+ switch (p_chars[i].characteristic.uuid.uuid)
+ {
+ case BLE_UUID_OTS_FEATURES:
+ NRF_LOG_DEBUG("OTS Feature Characteristic found.\r\n");
+ memcpy(&evt.params.handles.ots_feature_char,
+ &p_chars[i].characteristic,
+ sizeof(ble_gattc_char_t));
+ break;
+
+ case BLE_UUID_OTS_OBJECT_NAME:
+ NRF_LOG_DEBUG("Object Name Characteristic found.\r\n");
+ memcpy(&evt.params.handles.object_name_char,
+ &p_chars[i].characteristic,
+ sizeof(ble_gattc_char_t));
+ break;
+
+ case BLE_UUID_OTS_OBJECT_TYPE:
+ NRF_LOG_DEBUG("Object Type Characteristic found.\r\n");
+ memcpy(&evt.params.handles.object_type_char,
+ &p_chars[i].characteristic,
+ sizeof(ble_gattc_char_t));
+ break;
+
+ case BLE_UUID_OTS_OBJECT_SIZE:
+ NRF_LOG_DEBUG("Object Size Characteristic found.\r\n");
+ memcpy(&evt.params.handles.object_size_char,
+ &p_chars[i].characteristic,
+ sizeof(ble_gattc_char_t));
+ break;
+
+ case BLE_UUID_OTS_OBJECT_PROPERTIES:
+ NRF_LOG_DEBUG("Object Properties Characteristic found.\r\n");
+ memcpy(&evt.params.handles.object_prop_char,
+ &p_chars[i].characteristic,
+ sizeof(ble_gattc_char_t));
+ break;
+
+ case BLE_UUID_OTS_OACP:
+ NRF_LOG_DEBUG("Object Action Control Point found. CCCD Handle %x\r\n", p_chars[i].cccd_handle);
+ memcpy(&evt.params.handles.object_action_cp_char,
+ &p_chars[i].characteristic,
+ sizeof(ble_gattc_char_t));
+ evt.params.handles.object_action_cp_cccd.handle = p_chars[i].cccd_handle;
+ break;
+
+ default:
+ break;
+ }
+ }
+ evt.evt_type = NRF_BLE_OTS_C_EVT_DISCOVERY_COMPLETE;
+ evt.conn_handle = p_evt->conn_handle;
+ p_ots_c->evt_handler(&evt);
+ }
+ else
+ {
+ evt.evt_type = NRF_BLE_OTS_C_EVT_DISCOVERY_FAILED;
+ p_ots_c->evt_handler(&evt);
+ }
+}
+
+
+/**@brief Function for handling the Disconnect event.
+
+ @param[in] p_cts Pointer to the GATT Service client structure instance.
+ @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_disconnect(nrf_ble_ots_c_t * const p_ots_c, ble_evt_t const * const p_ble_evt)
+{
+ if (p_ots_c->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
+ {
+ p_ots_c->conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ if (ots_gatt_handles_are_valid(p_ots_c))
+ {
+ // There was a valid instance of ots on the peer. Send an event to the
+ // application, so that it can do any clean up related to this module.
+ nrf_ble_ots_c_evt_t evt;
+
+ evt.evt_type = NRF_BLE_OTS_C_EVT_DISCONN_COMPLETE;
+
+ p_ots_c->evt_handler(&evt);
+ memset(&p_ots_c->service, 0, sizeof(nrf_ble_ots_c_service_t));
+ }
+ }
+}
+
+
+void nrf_ble_ots_c_on_ble_evt(ble_evt_t const * const p_ble_evt,
+ void * p_context)
+{
+ nrf_ble_ots_c_t * p_ots_c;
+ p_ots_c = (nrf_ble_ots_c_t*) p_context;
+
+ VERIFY_MODULE_INITIALIZED_VOID();
+ VERIFY_PARAM_NOT_NULL_VOID(p_ots_c);
+ VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnect(p_ots_c, p_ble_evt);
+ break;
+
+ case BLE_GATTC_EVT_READ_RSP:
+ on_read_rsp(p_ots_c, p_ble_evt);
+ break;
+
+ case BLE_GATTC_EVT_WRITE_RSP:
+ //on_write_rsp()
+ NRF_LOG_DEBUG("error handle write response: %x\r\n", p_ble_evt->evt.gattc_evt.error_handle);
+ break;
+
+ default:
+ break;
+ }
+ ots_c_l2cap_on_ble_evt(p_ots_c, p_ble_evt);
+ ots_c_oacp_on_ble_evt(p_ots_c, p_ble_evt);
+}
+
+
+ret_code_t nrf_ble_ots_c_handles_assign(nrf_ble_ots_c_t * const p_ots_c,
+ uint16_t const conn_handle,
+ nrf_ble_ots_c_service_t const * const p_peer_handles)
+{
+ VERIFY_MODULE_INITIALIZED();
+ VERIFY_PARAM_NOT_NULL(p_ots_c);
+
+ p_ots_c->conn_handle = conn_handle;
+ if (p_peer_handles != NULL)
+ {
+ p_ots_c->service.ots_feature_char.handle_value = p_peer_handles->ots_feature_char.handle_value;
+ p_ots_c->service.object_type_char.handle_value = p_peer_handles->object_type_char.handle_value;
+ p_ots_c->service.object_size_char.handle_value = p_peer_handles->object_size_char.handle_value;
+ p_ots_c->service.object_prop_char.handle_value = p_peer_handles->object_prop_char.handle_value;
+ p_ots_c->service.object_action_cp_char.handle_value = p_peer_handles->object_action_cp_char.handle_value;
+ p_ots_c->service.object_action_cp_cccd.handle = p_peer_handles->object_action_cp_cccd.handle;
+
+ }
+ return NRF_SUCCESS;
+}
+
+
+#endif // NRF_MODULE_ENABLED(BLE_OTS_C)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c.h
new file mode 100644
index 0000000..01e13ba
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c.h
@@ -0,0 +1,320 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+ /**@file
+ *
+ * @defgroup nrf_ble_ots_c Object Transfer Service Client
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Object Transfer Service client module
+ *
+ * @details This is the main module of the Object Transfer Service (OTS) client.
+ */
+
+#ifndef NRF_BLE_OTS_C_H__
+#define NRF_BLE_OTS_C_H__
+
+#include <stdint.h>
+#include "ble_gattc.h"
+#include "ble.h"
+#include "nrf_error.h"
+#include "ble_srv_common.h"
+#include "ble_db_discovery.h"
+#include "sdk_errors.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a ble_ots instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define NRF_BLE_OTS_C_DEF(_name) \
+static nrf_ble_ots_c_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _ble_obs, \
+ BLE_OTS_C_BLE_OBSERVER_PRIO, \
+ nrf_ble_ots_c_on_ble_evt, &_name) \
+
+/** @brief Macro for defining multiple ble_ots instances.
+ *
+ * @param _name Name of the array of instances.
+ * @param _cnt Number of instances to define.
+ * @hideinitializer
+ */
+#define NRF_BLE_OTS_C_ARRAY_DEF(_name, _cnt) \
+static nrf_ble_ots_c_t _name[_cnt]; \
+NRF_SDH_BLE_OBSERVERS(_name ## _ble_obs, \
+ BLE_OTS_C_BLE_OBSERVER_PRIO, \
+ nrf_ble_ots_c_on_ble_evt, &_name, _cnt)
+
+
+/** @brief Types of Object Action Control Point Procedures. */
+typedef enum
+{
+ NRF_BLE_OTS_C_OACP_PROC_CREATE = 0x01, //!< Create object.
+ NRF_BLE_OTS_C_OACP_PROC_DELETE = 0x02, //!< Delete object.
+ NRF_BLE_OTS_C_OACP_PROC_CALC_CHKSUM = 0x03, //!< Calculate Checksum.
+ NRF_BLE_OTS_C_OACP_PROC_EXECUTE = 0x04, //!< Execute Object.
+ NRF_BLE_OTS_C_OACP_PROC_READ = 0x05, //!< Read object.
+ NRF_BLE_OTS_C_OACP_PROC_WRITE = 0x06, //!< Write object.
+ NRF_BLE_OTS_C_OACP_PROC_ABORT = 0x07, //!< Abort object.
+ NRF_BLE_OTS_C_OACP_PROC_RESP = 0x60 //!< Procedure response.
+} ble_ots_c_oacp_proc_type_t;
+
+/** @brief Object Action Control Point return codes. */
+typedef enum
+{
+ NRF_BLE_OTS_C_OACP_RES_SUCCESS = 0x01, //!< Success.
+ NRF_BLE_OTS_C_OACP_RES_OPCODE_NOT_SUP = 0x02, //!< Not supported
+ NRF_BLE_OTS_C_OACP_RES_INV_PARAM = 0x03, //!< Invalid parameter
+ NRF_BLE_OTS_C_OACP_RES_INSUFF_RES = 0x04, //!< Insufficient resources.
+ NRF_BLE_OTS_C_OACP_RES_INV_OBJ = 0x05, //!< Invalid object.
+ NRF_BLE_OTS_C_OACP_RES_CHAN_UNAVAIL = 0x06, //!< Channel unavailable.
+ NRF_BLE_OTS_C_OACP_RES_UNSUP_TYPE = 0x07, //!< Unsupported procedure.
+ NRF_BLE_OTS_C_OACP_RES_NOT_PERMITTED = 0x08, //!< Procedure not permitted.
+ NRF_BLE_OTS_C_OACP_RES_OBJ_LOCKED = 0x09, //!< Object locked.
+ NRF_BLE_OTS_C_OACP_RES_OPER_FAILED = 0x0A //!< Operation Failed.
+} ble_ots_c_oacp_res_code_t;
+
+/**@brief Type of the Object Transfer Service client event.
+ */
+typedef enum
+{
+ NRF_BLE_OTS_C_EVT_DISCOVERY_FAILED, //!< Event indicating that the Object Transfer Service has not been found on the peer.
+ NRF_BLE_OTS_C_EVT_DISCOVERY_COMPLETE, //!< Event indicating that the Object Transfer Service is present on the peer device.
+ NRF_BLE_OTS_C_EVT_DISCONN_COMPLETE, //!< Event indicating that the Object Transfer Service client module has finished processing the BLE_GAP_EVT_DISCONNECTED event. The event can be used by the application to do clean up related to the Object Transfer Service client.
+ NRF_BLE_OTS_C_EVT_FEATURE_READ_RESP, //!< Event indicating that the feature characteristic was read, The available features of the peer will be provided in the event.
+ NRF_BLE_OTS_C_EVT_OACP_RESP, //!< Event indicating that a response was received (result of a write to the OACP).
+ NRF_BLE_OTS_C_EVT_OBJ_READ, //!< Event indicating that the Object Transfer Service client finished reading object from the peer
+ NRF_BLE_OTS_C_EVT_CHANNEL_RELEASED, //!< Event indicating that the L2CAP Connection Oriented Channel has been disconnected
+ NRF_BLE_OTS_C_EVT_SIZE_READ_RESP //!< Event indicating that the object size characteristic was read.
+} nrf_ble_ots_c_evt_type_t;
+
+/** @brief Structure to hold the features of a server */
+typedef struct
+{
+ uint8_t oacp_create : 1;
+ uint8_t oacp_delete : 1;
+ uint8_t oacp_crc : 1;
+ uint8_t oacp_execute : 1;
+ uint8_t oacp_read : 1;
+ uint8_t oacp_write : 1;
+ uint8_t oacp_append : 1;
+ uint8_t oacp_truncate : 1;
+ uint8_t oacp_patch : 1;
+ uint8_t oacp_abort : 1;
+ uint8_t olcp_goto : 1;
+ uint8_t olcp_order : 1;
+ uint8_t olcp_req_num : 1;
+ uint8_t olcp_clear : 1;
+} nrf_ble_ots_c_feature_t;
+
+/**@brief Structure used for holding the Apple Notification Center Service found during the
+ discovery process.
+ */
+typedef struct
+{
+ ble_gattc_service_t service; //!< The Object Transfer Service holding the discovered Object Transfer Service. (0x1825).
+ ble_gattc_char_t ots_feature_char; //!< OTS Feature (0x2ABD)
+ ble_gattc_char_t object_name_char; //!< Object Name (0x2ABE)
+ ble_gattc_char_t object_type_char; //!< Object Type (0x2ABF)
+ ble_gattc_char_t object_size_char; //!< Object Size (0x2AC0)
+ ble_gattc_char_t object_prop_char; //!< Object Properties (0x2AC4)
+ ble_gattc_char_t object_action_cp_char; //!< Object Action Control Point (0x2AC5)
+ ble_gattc_desc_t object_action_cp_cccd; //!< Object Action Control Point Descriptor. Enables or disables Object Transfer notifications.
+} nrf_ble_ots_c_service_t;
+
+
+typedef struct
+{
+ ble_ots_c_oacp_proc_type_t request_op_code;
+ ble_ots_c_oacp_res_code_t result_code;
+} nrf_ble_ots_c_oacp_response_t;
+
+typedef struct
+{
+ uint32_t current_size;
+ uint32_t allocated_size;
+} nrf_ble_ots_c_obj_size;
+
+/**@brief Structure containing the event from the Object Transfer client module to the application.
+ */
+typedef struct
+{
+ nrf_ble_ots_c_evt_type_t evt_type; /**< Type of event. See @ref nrf_ble_ots_c_evt_type_t. */
+ uint16_t conn_handle; /**< Handle of the connection for which this event has occurred. */
+ union
+ {
+ nrf_ble_ots_c_feature_t feature; /**< Will be provided if the event type is @ref NRF_BLE_OTS_C_EVT_FEATURE_READ_RESP.*/
+ nrf_ble_ots_c_service_t handles; /**< Handles that the Object Transfer service occupies in the peer device. Will be filled if the event type is @ref NRF_BLE_OTS_C_EVT_DISCOVERY_COMPLETE.*/
+ nrf_ble_ots_c_oacp_response_t response; /**< Will be provided if the event type is @ref NRF_BLE_OTS_C_EVT_OACP_RESP. */
+ ble_data_t object; /**< Will be provided if the event type is @ref NRF_BLE_OTS_C_EVT_OBJ_READ. */
+ nrf_ble_ots_c_obj_size size; /**< Will be provided if the event type is @ref NRF_BLE_OTS_C_EVT_SIZE_READ_RESP. */
+ } params;
+} nrf_ble_ots_c_evt_t;
+
+
+/**@brief Object Transfer handler type. */
+typedef void (* nrf_ble_ots_c_evt_handler_t)(nrf_ble_ots_c_evt_t * p_evt);
+
+
+/**@brief Structure for holding the information related to the Object Transfer Service.
+
+ @warning This structure must be zero-initialized.
+*/
+typedef struct
+{
+ bool initialized; /**< Boolean telling whether the context has been initialized or not. */
+ uint16_t conn_handle; /**< Active connection handle */
+ nrf_ble_ots_c_service_t service; /**< Structure to store the different handles and UUIDs related to the service. */
+ nrf_ble_ots_c_evt_handler_t evt_handler; /**< Pointer to event handler function. */
+ ble_srv_error_handler_t err_handler; /**< Pointer to error handler function. */
+ uint16_t local_cid;
+ ble_l2cap_evt_ch_setup_t ch_setup; /**< L2CAP Channel Setup Completed Event Parameters. */
+ uint32_t current_credits;
+ uint32_t remaining_bytes;
+ uint32_t transmitted_bytes;
+ uint32_t received_bytes;
+ ble_data_t * current_obj;
+} nrf_ble_ots_c_t;
+
+
+/**@brief Initialization parameters, these must be supplied when calling @ref nrf_ble_ots_c_init. */
+typedef struct
+{
+ nrf_ble_ots_c_evt_handler_t evt_handler; /**< The event handler that is called by the Object Transfer client module when any related event occurs. */
+ ble_srv_error_handler_t err_handler; /**< the error handler that is called by the Object Transfer client module if any error occurs. */
+} nrf_ble_ots_c_init_t;
+
+/**@brief Function for initializing the Object Transfer client module.
+
+ @param[in,out] p_ots_c Pointer to the Object Transfer Service client structure instance.
+ @param[in] p_ots_c_init Init parameters contraining the event handler that is called by
+ the Object Transfer client module when any related event occurs.
+
+ @retval NRF_SUCCESS If the service was initialized successfully.
+ @retval NRF_ERROR_NULL If any of the input parameters are NULL.
+ @return If functions from other modules return errors to this function,
+ the @ref nrf_error are propagated.
+*/
+ret_code_t nrf_ble_ots_c_init(nrf_ble_ots_c_t * p_ots_c,
+ nrf_ble_ots_c_init_t * p_ots_c_init);
+
+
+/**@brief Function for handling events from the database discovery module.
+
+ @details This function will handle an event from the database discovery module, and determine
+ if it relates to the discovery of Object Transfer Service at the peer. If so,
+ it will call the application's event handler indicating that Object Transfer Service
+ has been discovered at the peer.
+
+ @param[in,out] p_ots_c Pointer to the Object Transfer Service client structure instance.
+ @param[in] p_evt Pointer to the event received from the database discovery module.
+*/
+void nrf_ble_ots_c_on_db_disc_evt(nrf_ble_ots_c_t const * const p_ots_c,
+ ble_db_discovery_evt_t * const p_evt);
+
+
+/**@brief Function for reading the features characteristic (@ref BLE_UUID_OTS_FEATURES) on the server.
+
+ @param[in,out] p_ots_c Pointer to Object Transfer client structure.
+
+ @retval NRF_SUCCESS Operation success.
+ @return If functions from other modules return errors to this function,
+ the @ref nrf_error are propagated.
+*/
+ret_code_t nrf_ble_ots_c_feature_read(nrf_ble_ots_c_t * const p_ots_c);
+
+
+/**@brief Function for reading the Object Size characteristic (@ref BLE_UUID_OTS_FEATURES) on the server.
+
+ @param[in,out] p_ots_c Pointer to Object Transfer client structure.
+
+ @retval NRF_SUCCESS Operation success.
+ @return NRF_ERROR_INVALID_STATE if the Object Size characteristic has not been discovered. If functions from other modules return errors to this function,
+ the @ref nrf_error are propagated.
+*/
+ret_code_t nrf_ble_ots_c_obj_size_read(nrf_ble_ots_c_t * const p_ots_c);
+
+
+/**@brief Function for handling the Application's BLE Stack events.
+
+ @param[in] p_ble_evt Pointer to the BLE event received.
+ @param[in,out] p_context Pointer to the Object Transfer Service client structure instance.
+*/
+void nrf_ble_ots_c_on_ble_evt(const ble_evt_t * const p_ble_evt,
+ void * p_context);
+
+
+ret_code_t nrf_ble_ots_c_obj_name_read(nrf_ble_ots_c_t * const p_ots_c, ble_data_t * p_obj);
+ret_code_t nrf_ble_ots_c_obj_name_write(nrf_ble_ots_c_t * const p_ots_c, ble_data_t * p_obj);
+ret_code_t nrf_ble_ots_c_obj_type_read(nrf_ble_ots_c_t * const p_ots_c);
+ret_code_t nrf_ble_ots_c_obj_size_read(nrf_ble_ots_c_t * const p_ots_c);
+ret_code_t nrf_ble_ots_c_obj_properties_read(nrf_ble_ots_c_t * const p_ots_c);
+
+
+/**@brief Function for assigning handles to a Object Transfer Service client instance.
+
+ @details Call this function when a link has been established with a peer to
+ associate this link to an instance of the module. This makes it
+ possible to handle several link and associate each link to a particular
+ instance of the Object Transfer Service client module. The connection handle and
+ attribute handles will be provided from the discovery event
+ @ref NRF_BLE_OTS_C_EVT_DISCOVERY_COMPLETE.
+
+ @param[in,out] p_ots_c Pointer to the Object Transfer Service client structure instance to associate
+ with the handles.
+ @param[in] conn_handle Connection handle to be associated with the given Object Transfer Service client
+ Instance.
+ @param[in] p_peer_handles Attribute handles on the Object Transfer Service server that you want this
+ Object Transfer Service client to interact with.
+
+ @retval NRF_SUCCESS If the connection handle was successfully stored in the Object Transfer Service instance.
+ @retval NRF_ERROR_NULL If any of the input parameters are NULL.
+*/
+ret_code_t nrf_ble_ots_c_handles_assign(nrf_ble_ots_c_t * const p_ots_c,
+ uint16_t const conn_handle,
+ nrf_ble_ots_c_service_t const * const p_peer_handles);
+
+#endif // NRF_BLE_OTS_C_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c_l2cap.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c_l2cap.c
new file mode 100644
index 0000000..8509329
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c_l2cap.c
@@ -0,0 +1,244 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_OTS_C_L2CAP)
+#include <stdlib.h>
+#include "nrf_ble_ots_c.h"
+#include "nrf_ble_ots_c_oacp.h"
+#include "nrf_ble_ots_c_l2cap.h"
+#include "ble.h"
+
+#define NRF_LOG_MODULE_NAME ble_ots_c_l2cap
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#include "sdk_common.h"
+
+#define MODULE_INITIALIZED (p_ots_c->initialized) /**< Macro designating whether the module has been initialized properly. */
+
+
+static void on_l2cap_setup_complete(nrf_ble_ots_c_t * const p_ots_c,
+ ble_evt_t const * const p_ble_evt)
+{
+ p_ots_c->local_cid = p_ble_evt->evt.l2cap_evt.local_cid;
+ p_ots_c->ch_setup.tx_params.peer_mps = p_ble_evt->evt.l2cap_evt.params.ch_setup.tx_params.peer_mps;
+ p_ots_c->ch_setup.tx_params.tx_mps = p_ble_evt->evt.l2cap_evt.params.ch_setup.tx_params.tx_mps;
+ p_ots_c->ch_setup.tx_params.tx_mtu = p_ble_evt->evt.l2cap_evt.params.ch_setup.tx_params.tx_mtu;
+ p_ots_c->ch_setup.tx_params.credits = p_ble_evt->evt.l2cap_evt.params.ch_setup.tx_params.credits;
+ p_ots_c->current_credits = p_ots_c->ch_setup.tx_params.credits;
+}
+
+
+static void send_next_mtu(nrf_ble_ots_c_t * const p_ots_c)
+{
+ // Remaining bytes to transmit.
+ if(p_ots_c->transmitted_bytes < p_ots_c->current_obj->len)
+ {
+ ret_code_t err_code;
+ uint16_t tx_size;
+
+ tx_size = MIN((p_ots_c->current_obj->len - p_ots_c->transmitted_bytes),
+ p_ots_c->ch_setup.tx_params.tx_mtu);
+ ble_data_t obj;
+ obj.len = tx_size;
+ obj.p_data = &p_ots_c->current_obj->p_data[p_ots_c->transmitted_bytes];
+ err_code = sd_ble_l2cap_ch_tx(p_ots_c->conn_handle, p_ots_c->local_cid, &obj);
+ if (err_code == NRF_ERROR_RESOURCES)
+ {
+ return; // Too many SDUs queued for transmission, the transmission will be tried again on the next BLE_L2CAP_EVT_CH_TX event.
+ }
+ if(err_code != NRF_SUCCESS && p_ots_c->err_handler != NULL)
+ {
+ p_ots_c->err_handler(err_code);
+ }
+ }
+}
+
+
+static void on_l2cap_ch_tx(nrf_ble_ots_c_t * const p_ots_c,
+ ble_evt_t const * const p_ble_evt)
+{
+ NRF_LOG_INFO("Bytes sent: %i", p_ble_evt->evt.l2cap_evt.params.tx.sdu_buf.len);
+ NRF_LOG_HEXDUMP_INFO(p_ble_evt->evt.l2cap_evt.params.tx.sdu_buf.p_data,
+ p_ble_evt->evt.l2cap_evt.params.tx.sdu_buf.len);
+
+ p_ots_c->transmitted_bytes += p_ble_evt->evt.l2cap_evt.params.tx.sdu_buf.len;
+
+ NRF_LOG_INFO("\r\n Remaining bytes to send: %i",
+ (p_ots_c->current_obj->len - p_ots_c->transmitted_bytes));
+ p_ots_c->current_credits --;
+ NRF_LOG_INFO("\r\n Remaining Credits: %i",
+ (p_ots_c->current_credits));
+ if (p_ots_c->current_credits > 0)
+ {
+ send_next_mtu(p_ots_c);
+ }
+}
+
+
+static void on_l2cap_ch_rx(nrf_ble_ots_c_t * const p_ots_c,
+ ble_evt_t const * const p_ble_evt)
+{
+ NRF_LOG_INFO("Bytes received: %i", p_ble_evt->evt.l2cap_evt.params.rx.sdu_len);
+ NRF_LOG_HEXDUMP_INFO(p_ble_evt->evt.l2cap_evt.params.rx.sdu_buf.p_data,
+ p_ble_evt->evt.l2cap_evt.params.rx.sdu_len);
+
+ memcpy(&p_ots_c->current_obj->p_data[p_ots_c->received_bytes],
+ p_ble_evt->evt.l2cap_evt.params.rx.sdu_buf.p_data,
+ p_ble_evt->evt.l2cap_evt.params.rx.sdu_len);
+ p_ots_c->received_bytes += p_ble_evt->evt.l2cap_evt.params.rx.sdu_len;
+ NRF_LOG_INFO("Remaining bytes to received: %i", (p_ots_c->current_obj->len - p_ots_c->received_bytes));
+
+ if(p_ots_c->received_bytes >= p_ots_c->current_obj->len)
+ {
+ nrf_ble_ots_c_evt_t evt;
+
+ evt.evt_type = NRF_BLE_OTS_C_EVT_OBJ_READ;
+ evt.params.object.len = p_ots_c->current_obj->len;
+ evt.params.object.p_data = p_ots_c->current_obj->p_data;
+ p_ots_c->evt_handler(&evt);
+ }
+ else
+ {
+ ret_code_t err_code;
+
+ ble_data_t sdu_buf;
+ sdu_buf.p_data = &p_ots_c->current_obj->p_data[p_ots_c->received_bytes];
+ sdu_buf.len = p_ots_c->current_obj->len;
+
+ err_code = sd_ble_l2cap_ch_rx(p_ots_c->conn_handle,
+ p_ots_c->local_cid,
+ &sdu_buf);
+ UNUSED_PARAMETER(err_code);
+ }
+
+}
+
+
+static void on_l2cap_credit(nrf_ble_ots_c_t * const p_ots_c,
+ ble_evt_t const * const p_ble_evt)
+{
+ p_ots_c->current_credits = p_ble_evt->evt.l2cap_evt.params.credit.credits;
+ send_next_mtu(p_ots_c);
+}
+
+
+static void on_l2cap_released(nrf_ble_ots_c_t * const p_ots_c,
+ ble_evt_t const * const p_ble_evt)
+{
+ nrf_ble_ots_c_evt_t evt;
+
+ evt.evt_type = NRF_BLE_OTS_C_EVT_CHANNEL_RELEASED;
+ p_ots_c->evt_handler(&evt);
+}
+
+
+void ots_c_l2cap_on_ble_evt(nrf_ble_ots_c_t * const p_ots_c,
+ ble_evt_t const * const p_ble_evt)
+{
+
+ VERIFY_MODULE_INITIALIZED_VOID();
+ VERIFY_PARAM_NOT_NULL_VOID(p_ots_c);
+ VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
+
+ if (p_ble_evt->evt.l2cap_evt.local_cid != p_ots_c->local_cid)
+ {
+ return;
+ }
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_L2CAP_EVT_CH_SETUP:
+ NRF_LOG_DEBUG("BLE_L2CAP_EVT_CH_SETUP");
+ on_l2cap_setup_complete(p_ots_c, p_ble_evt);
+ break;
+
+ case BLE_L2CAP_EVT_CH_TX:
+ NRF_LOG_DEBUG("BLE_L2CAP_EVT_CH_TX");
+ on_l2cap_ch_tx(p_ots_c, p_ble_evt);
+ break;
+
+ case BLE_L2CAP_EVT_CH_RX:
+ NRF_LOG_DEBUG("BLE_L2CAP_EVT_CH_RX");
+ on_l2cap_ch_rx(p_ots_c, p_ble_evt);
+ break;
+
+ case BLE_L2CAP_EVT_CH_CREDIT:
+ NRF_LOG_DEBUG("BLE_L2CAP_EVT_CH_CREDIT");
+ on_l2cap_credit(p_ots_c, p_ble_evt);
+ break;
+ case BLE_L2CAP_EVT_CH_RELEASED:
+ NRF_LOG_DEBUG("BLE_L2CAP_EVT_CH_RELEASED");
+ on_l2cap_released(p_ots_c, p_ble_evt);
+ break;
+ default:
+ break;
+ }
+}
+
+
+ret_code_t nrf_ble_ots_c_l2cap_obj_send(nrf_ble_ots_c_t * const p_ots_c, ble_data_t * p_obj)
+{
+ ret_code_t err_code;
+ uint16_t tx_size;
+ p_ots_c->transmitted_bytes = 0;
+ tx_size = MIN(p_obj->len, p_ots_c->ch_setup.tx_params.tx_mtu);
+ p_ots_c->current_obj = p_obj;
+
+ ble_data_t obj;
+ obj.len = tx_size;
+ obj.p_data = p_obj->p_data;
+ err_code = sd_ble_l2cap_ch_tx(p_ots_c->conn_handle, p_ots_c->local_cid, &obj);
+ return err_code;
+}
+
+
+ret_code_t nrf_ble_ots_c_l2cap_obj_receive(nrf_ble_ots_c_t * const p_ots_c, ble_data_t * p_obj)
+{
+ uint32_t err_code;
+ p_ots_c->received_bytes = 0;
+ p_ots_c->current_obj = p_obj;
+ err_code = sd_ble_l2cap_ch_rx(p_ots_c->conn_handle,
+ p_ots_c->local_cid,
+ p_ots_c->current_obj);
+ return err_code;
+}
+
+#endif // NRF_MODULE_ENABLED(BLE_OTS_C_L2CAP)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c_l2cap.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c_l2cap.h
new file mode 100644
index 0000000..3d76920
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c_l2cap.h
@@ -0,0 +1,101 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+ /**@file
+ *
+ * @defgroup nrf_ble_ots_c_l2cap Object Transfer Service Client
+ * @{
+ * @ingroup nrf_ble_ots_c
+ * @brief Object Transfer Service client module
+ *
+ * @details This is the main module of the Object Transfer Service (OTS) client.
+ */
+
+#ifndef NRF_BLE_OTS_C_L2CAP_H__
+#define NRF_BLE_OTS_C_L2CAP_H__
+
+#include <stdint.h>
+#include "ble_gattc.h"
+#include "ble.h"
+#include "nrf_error.h"
+#include "ble_srv_common.h"
+#include "ble_db_discovery.h"
+#include "sdk_errors.h"
+#include "nrf_ble_ots_c.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**@brief Function for handling the Application's BLE Stack events.
+
+ @param[in,out] p_ots_c Pointer to Object Transfer client structure.
+ @param[in] p_ble_evt Pointer to the BLE event received.
+*/
+void ots_c_l2cap_on_ble_evt(nrf_ble_ots_c_t * const p_ots_c,
+ ble_evt_t const * const p_ble_evt);
+
+
+/**@brief Function sending an object.
+
+ @details This Function will only succeed in sending an object if the peer is in a state to
+ receive it. call @ref nrf_ble_ots_c_oacp_write_object before this function.
+
+ @param[in,out] p_ots_c Pointer to Object Transfer client structure.
+ @param[in,out] p_obj Pointer to object that will be sent to the peer.
+*/
+ret_code_t nrf_ble_ots_c_l2cap_obj_send(nrf_ble_ots_c_t * const p_ots_c, ble_data_t * p_obj);
+
+
+/**@brief Function for receiving an object.
+
+ @details This Function will only succeed in receiving an object if the peer is in a state to
+ send it. call @ref nrf_ble_ots_c_oacp_read_object before this function.
+
+ @param[in,out] p_ots_c Pointer to Object Transfer client structure.
+ @param[in,out] p_obj Pointer to buffer where the received data will be stored.
+*/
+ret_code_t nrf_ble_ots_c_l2cap_obj_receive(nrf_ble_ots_c_t * const p_ots_c, ble_data_t * p_obj);
+
+
+#endif // NRF_BLE_OTS_C_L2CAP_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c_oacp.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c_oacp.c
new file mode 100644
index 0000000..dd6547f
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c_oacp.c
@@ -0,0 +1,253 @@
+/**
+ * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_OTS_C_OACP)
+#include <stdlib.h>
+#include "nrf_ble_ots_c_oacp.h"
+#include "ble.h"
+
+#define NRF_LOG_MODULE_NAME ble_ots_c_oacp
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#include "sdk_common.h"
+
+#define BLE_OTS_OACP_WRITE_OP_SIZE 10
+#define BLE_OTS_OACP_READ_OP_SIZE 9
+
+#define MODULE_INITIALIZED (p_ots_c->initialized)
+
+static void oacp_response(nrf_ble_ots_c_t const * const p_ots_c,
+ ble_gattc_evt_t const * const p_ble_gattc_evt)
+{
+ nrf_ble_ots_c_evt_t evt;
+ nrf_ble_ots_c_evt_handler_t evt_handler = p_ots_c->evt_handler;
+
+/*lint --e{415} --e{416} -save suppress Warning 415: Likely access of out-of-bounds pointer */
+ evt.params.response.request_op_code = (ble_ots_c_oacp_proc_type_t) p_ble_gattc_evt->params.hvx.data[sizeof(uint8_t)];
+ evt.params.response.result_code = (ble_ots_c_oacp_res_code_t) p_ble_gattc_evt->params.hvx.data[2*sizeof(uint8_t)];
+/*lint -restore*/
+ evt.evt_type = NRF_BLE_OTS_C_EVT_OACP_RESP;
+ evt.conn_handle = p_ble_gattc_evt->conn_handle;
+ evt_handler(&evt);
+}
+
+/**@brief Function for handling the indication and notifications from the GATT Service Server.
+
+ @param[in] p_ots_c Pointer to Object Transfer client structure.
+ @param[in] p_ble_gattc_evt Pointer to a gattc event.
+*/
+static void on_hvx(nrf_ble_ots_c_t const * const p_ots_c,
+ ble_gattc_evt_t const * const p_ble_gattc_evt)
+{
+
+
+ uint16_t oacp_handle = p_ots_c->service.object_action_cp_char.handle_value;
+
+ if ((p_ble_gattc_evt->params.hvx.handle == oacp_handle)
+ && (p_ots_c->evt_handler != NULL))
+ {
+ ret_code_t err_code = sd_ble_gattc_hv_confirm(p_ble_gattc_evt->conn_handle,
+ oacp_handle);
+
+ if ((err_code != NRF_SUCCESS) && (p_ots_c->err_handler != NULL))
+ {
+ p_ots_c->err_handler(err_code);
+ }
+ uint8_t op_code = p_ble_gattc_evt->params.hvx.data[0];
+
+ if(op_code == NRF_BLE_OTS_C_OACP_PROC_RESP)
+ {
+ oacp_response(p_ots_c, p_ble_gattc_evt);
+ }
+ }
+}
+
+/**@brief Function for checking whether the peer's Object Transfer Service instance has been discovered.
+
+ @param[in] p_ots_c Pointer to the GATT Service client structure instance.
+
+ @return True if the Object Transfer service handles are valid.
+ @return False if the Object Transfer service handles are invalid
+ */
+static bool ots_gatt_handles_are_valid(const nrf_ble_ots_c_t * const p_ots_c)
+{
+ return (p_ots_c->service.object_prop_char.handle_value != BLE_GATT_HANDLE_INVALID
+ && p_ots_c->service.object_size_char.handle_value != BLE_GATT_HANDLE_INVALID
+ && p_ots_c->service.object_type_char.handle_value != BLE_GATT_HANDLE_INVALID
+ && p_ots_c->service.ots_feature_char.handle_value != BLE_GATT_HANDLE_INVALID);
+}
+
+
+ret_code_t nrf_ble_ots_c_indication_enable(nrf_ble_ots_c_t * const p_ots_c,
+ bool const enable)
+{
+ VERIFY_MODULE_INITIALIZED();
+ VERIFY_TRUE(ots_gatt_handles_are_valid(p_ots_c), NRF_ERROR_INVALID_STATE);
+
+ if (p_ots_c->conn_handle == BLE_CONN_HANDLE_INVALID)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ ret_code_t err_code = NRF_SUCCESS;
+
+ ble_gattc_write_params_t gattc_params;
+
+ memset(&gattc_params, 0x00, sizeof(gattc_params));
+ uint16_t cccd_val = (enable) ? BLE_GATT_HVX_INDICATION : 0;
+
+ gattc_params.handle = p_ots_c->service.object_action_cp_cccd.handle;
+ gattc_params.len = BLE_CCCD_VALUE_LEN;
+ gattc_params.p_value = (uint8_t *)&cccd_val;
+ gattc_params.offset = 0;
+ gattc_params.write_op = BLE_GATT_OP_WRITE_REQ;
+
+ err_code = sd_ble_gattc_write(p_ots_c->conn_handle, &gattc_params);
+ return err_code;
+}
+
+
+ret_code_t nrf_ble_ots_c_oacp_write_object(nrf_ble_ots_c_t * const p_ots_c, uint32_t offset, uint32_t len, bool truncate)
+{
+ VERIFY_MODULE_INITIALIZED();
+ VERIFY_TRUE(ots_gatt_handles_are_valid(p_ots_c), NRF_ERROR_INVALID_STATE);
+
+ if (p_ots_c->conn_handle == BLE_CONN_HANDLE_INVALID)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ ret_code_t err_code = NRF_SUCCESS;
+
+ uint8_t val[BLE_OTS_OACP_WRITE_OP_SIZE];
+ memset(val, 0, sizeof(val));
+
+ uint32_t i = 0;
+
+ // OP Code
+ val[i++] = NRF_BLE_OTS_C_OACP_PROC_WRITE;
+
+ //Offset
+ i += uint32_encode(offset, &val[i]);
+
+ //Len
+ i += uint32_encode(len, &val[i]);
+
+ val[i] |= (truncate << 0);
+ ble_gattc_write_params_t gattc_params;
+ memset(&gattc_params, 0, sizeof(ble_gattc_write_params_t));
+
+ gattc_params.handle = p_ots_c->service.object_action_cp_char.handle_value;
+ gattc_params.len = i;
+ gattc_params.p_value = (uint8_t *)val;
+ gattc_params.offset = 0;
+ gattc_params.write_op = BLE_GATT_OP_WRITE_REQ;
+
+ err_code = sd_ble_gattc_write(p_ots_c->conn_handle, &gattc_params);
+ if(err_code != NRF_SUCCESS)
+ {
+ p_ots_c->err_handler(err_code);
+ }
+ return err_code;
+}
+
+ret_code_t nrf_ble_ots_c_oacp_read_object(nrf_ble_ots_c_t * const p_ots_c, uint32_t offset, uint32_t len)
+{
+ VERIFY_MODULE_INITIALIZED();
+ VERIFY_TRUE(ots_gatt_handles_are_valid(p_ots_c), NRF_ERROR_INVALID_STATE);
+
+ if (p_ots_c->conn_handle == BLE_CONN_HANDLE_INVALID)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ ret_code_t err_code = NRF_SUCCESS;
+
+ uint8_t val[BLE_OTS_OACP_READ_OP_SIZE];
+ memset(val, 0, sizeof(val));
+
+ uint32_t i = 0;
+
+ // OP Code
+ val[i++] = NRF_BLE_OTS_C_OACP_PROC_READ;
+
+ //Offset
+ i += uint32_encode(offset, &val[i]);
+
+ //Len
+ i += uint32_encode(len, &val[i]);
+
+ ble_gattc_write_params_t gattc_params;
+ memset(&gattc_params, 0, sizeof(ble_gattc_write_params_t));
+
+ gattc_params.handle = p_ots_c->service.object_action_cp_char.handle_value;
+ gattc_params.len = sizeof(val);
+ gattc_params.p_value = (uint8_t *)val;
+ gattc_params.offset = 0;
+ gattc_params.write_op = BLE_GATT_OP_WRITE_REQ;
+
+ err_code = sd_ble_gattc_write(p_ots_c->conn_handle, &gattc_params);
+ return err_code;
+}
+
+
+
+void ots_c_oacp_on_ble_evt(nrf_ble_ots_c_t * const p_ots_c,
+ ble_evt_t const * const p_ble_evt)
+{
+ VERIFY_MODULE_INITIALIZED_VOID();
+ VERIFY_PARAM_NOT_NULL_VOID(p_ots_c);
+ VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
+
+ switch (p_ble_evt->header.evt_id)
+ {
+
+ case BLE_GATTC_EVT_HVX:
+ on_hvx(p_ots_c, &(p_ble_evt->evt.gattc_evt));
+ break;
+
+ default:
+ break;
+ }
+}
+
+#endif // NRF_MODULE_ENABLED(BLE_OTS_C)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c_oacp.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c_oacp.h
new file mode 100644
index 0000000..a2eb31e
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/nrf_ble_ots_c_oacp.h
@@ -0,0 +1,126 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+ /**@file
+ *
+ * @defgroup nrf_ble_ots_c_oacp Object Transfer Service Client Object Action Control Point
+ * @{
+ * @ingroup nrf_ble_ots_c
+ * @brief Object Action Control Point module
+ *
+ * @details This is the Object Action Control Point module of the Object Transfer Service (OTS) client.
+ */
+
+#ifndef NRF_BLE_OTS_C_OACP_H__
+#define NRF_BLE_OTS_C_OACP_H__
+
+#include <stdint.h>
+#include "ble_gattc.h"
+#include "ble.h"
+#include "nrf_error.h"
+#include "ble_srv_common.h"
+#include "ble_db_discovery.h"
+#include "sdk_errors.h"
+#include "nrf_ble_ots_c.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**@brief Function for enabling remote indication.
+
+ @param[in,out] p_ots_c Pointer to Object Transfer client structure.
+ @param[in] enable True to enable Object Action Control Point (OACP) indication, false to disable.
+
+ @retval NRF_SUCCESS Operation success.
+ @return If functions from other modules return errors to this function,
+ the @ref nrf_error are propagated.
+*/
+ret_code_t nrf_ble_ots_c_indication_enable(nrf_ble_ots_c_t * const p_ots_c,
+ bool const enable);
+
+
+/**@brief Function for requesting a write of an object.
+
+ @details With this function we let the peer know the length of the object we want to write.
+ (The object itself is not written by this function.)
+ The peer will indicate a response on the Object Action Control Point.
+ If the write is accepted (the event NRF_BLE_OTS_C_OACP_RES_SUCCESS ), an object can be
+ transfered with @ref nrf_ble_ots_c_l2cap_obj_send.
+
+ @param[in,out] p_ots_c Pointer to Object Transfer client structure.
+ @param[in] offset Offset of the write.
+ @param[in] len length of the object to write.
+ @param[in] truncate True to let the write truncate on the object.
+
+ @retval NRF_SUCCESS Operation success.
+ @retval NRF_ERROR_INVALID_STATE Module is not initialized, or the handles of the peer OACP
+ are invalid.
+ @return If functions from other modules return errors to this function,
+ the @ref nrf_error are propagated.
+*/
+ret_code_t nrf_ble_ots_c_oacp_write_object(nrf_ble_ots_c_t * const p_ots_c, uint32_t offset, uint32_t len, bool truncate);
+
+/**@brief Function for requesting a read of an object.
+
+ @param[in,out] p_ots_c Pointer to Object Transfer client structure.
+ @param[in] offset Offset of the read.
+ @param[in] len length of the read.
+
+ @retval NRF_SUCCESS Operation success.
+ @return If functions from other modules return errors to this function,
+ the @ref nrf_error are propagated.
+*/
+ret_code_t nrf_ble_ots_c_oacp_read_object(nrf_ble_ots_c_t * const p_ots_c, uint32_t offset, uint32_t len);
+
+
+/**@brief Function for handling the Application's BLE Stack events.
+
+ @param[in,out] p_ots_c Pointer to Object Transfer client structure.
+ @param[in] p_ble_evt Pointer to the BLE event received.
+*/
+void ots_c_oacp_on_ble_evt(nrf_ble_ots_c_t * const p_ots_c,
+ ble_evt_t const * const p_ble_evt);
+
+
+#endif // NRF_BLE_OTS_C_OACP_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/ots_tx_buffer.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/ots_tx_buffer.c
new file mode 100644
index 0000000..0ce1816
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/ots_tx_buffer.c
@@ -0,0 +1,113 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Disclaimer: This client implementation of the Apple Notification Center Service can and will be changed at any time by Nordic Semiconductor ASA.
+ * Server implementations such as the ones found in iOS can be changed at any time by Apple and may cause this client implementation to stop working.
+ */
+
+ #include "nrf_ble_ots_c.h"
+ #include "ancs_tx_buffer.h"
+ #include "sdk_macros.h"
+ #include "nrf_log.h"
+ #include "string.h"
+
+
+static tx_message_t m_tx_buffer[TX_BUFFER_SIZE]; /**< Transmit buffer for messages to be transmitted to the Notification Provider. */
+static uint32_t m_tx_insert_index = 0; /**< Current index in the transmit buffer where the next message should be inserted. */
+static uint32_t m_tx_index = 0; /**< Current index in the transmit buffer from where the next message to be transmitted resides. */
+
+
+void tx_buffer_init(void)
+{
+ memset(m_tx_buffer, 0, sizeof(m_tx_buffer));
+}
+
+
+void tx_buffer_insert(tx_message_t * p_msg)
+{
+
+ memset(&(m_tx_buffer[m_tx_insert_index]), 0, sizeof(m_tx_buffer)/sizeof(tx_message_t));
+
+ m_tx_buffer[m_tx_insert_index].conn_handle = p_msg->conn_handle;
+ m_tx_buffer[m_tx_insert_index].type = p_msg->type;
+
+ m_tx_buffer[m_tx_insert_index].req.write_req.gattc_params.handle = p_msg->req.write_req.gattc_params.handle;
+ m_tx_buffer[m_tx_insert_index].req.write_req.gattc_params.len = p_msg->req.write_req.gattc_params.len;
+ m_tx_buffer[m_tx_insert_index].req.write_req.gattc_params.write_op = p_msg->req.write_req.gattc_params.write_op;
+ m_tx_buffer[m_tx_insert_index].req.write_req.gattc_params.flags = p_msg->req.write_req.gattc_params.flags;
+ m_tx_buffer[m_tx_insert_index].req.write_req.gattc_params.p_value = m_tx_buffer[m_tx_insert_index].req.write_req.gattc_value;
+ m_tx_buffer[m_tx_insert_index].req.write_req.gattc_params.offset = p_msg->req.write_req.gattc_params.offset;
+
+ if(p_msg->type == WRITE_REQ)
+ {
+ memcpy(m_tx_buffer[m_tx_insert_index].req.write_req.gattc_value,
+ p_msg->req.write_req.gattc_value,
+ WRITE_MESSAGE_LENGTH);
+ }
+
+ m_tx_insert_index++;
+ m_tx_insert_index &= TX_BUFFER_MASK;
+}
+
+
+
+void tx_buffer_process(void)
+{
+ if (m_tx_index != m_tx_insert_index)
+ {
+ uint32_t err_code;
+
+ if (m_tx_buffer[m_tx_index].type == READ_REQ)
+ {
+ err_code = sd_ble_gattc_read(m_tx_buffer[m_tx_index].conn_handle,
+ m_tx_buffer[m_tx_index].req.read_handle,
+ 0);
+ }
+ else
+ {
+ err_code = sd_ble_gattc_write(m_tx_buffer[m_tx_index].conn_handle,
+ &m_tx_buffer[m_tx_index].req.write_req.gattc_params);
+ }
+ if (err_code == NRF_SUCCESS)
+ {
+ ++m_tx_index;
+ m_tx_index &= TX_BUFFER_MASK;
+ }
+ }
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/ots_tx_buffer.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/ots_tx_buffer.h
new file mode 100644
index 0000000..6953438
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/experimental_nrf_ble_ots_c/ots_tx_buffer.h
@@ -0,0 +1,103 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef ANCS_TX_BUFFER_H__
+#define ANCS_TX_BUFFER_H__
+
+#include "nrf_ble_ancs_c.h"
+
+/** @file
+ *
+ * @addtogroup ble_ancs_c
+ * @{
+ */
+
+#define TX_BUFFER_MASK 0x07 //!< TX buffer mask. Must be a mask of contiguous zeroes followed by a contiguous sequence of ones: 000...111.
+#define TX_BUFFER_SIZE (TX_BUFFER_MASK + 1) //!< Size of the send buffer, which is 1 bigger than the mask.
+#define WRITE_MESSAGE_LENGTH 20 //!< Length of the write message for the CCCD/control point.
+
+/**@brief ANCS request types.
+ */
+typedef enum
+{
+ READ_REQ = 1, /**< Type identifying that this TX message is a read request. */
+ WRITE_REQ /**< Type identifying that this TX message is a write request. */
+} tx_request_t;
+
+
+/**@brief Structure for writing a message to the central, thus the Control Point or CCCD.
+ */
+typedef struct
+{
+ uint8_t gattc_value[WRITE_MESSAGE_LENGTH]; //!< The message to write.
+ ble_gattc_write_params_t gattc_params; //!< GATTC parameters for this message.
+} write_params_t;
+
+
+/**@brief Data to be transmitted to the connected master.
+ */
+typedef struct
+{
+ uint16_t conn_handle; //!< Connection handle to be used when transmitting this message.
+ tx_request_t type; //!< Type of this message (read or write message).
+ union
+ {
+ uint16_t read_handle; //!< Read request message.
+ write_params_t write_req; //!< Write request message.
+ } req;
+} tx_message_t;
+
+/**@brief Function for clearing the TX buffer.
+ *
+ * @details Always call this function before using the TX buffer.
+*/
+void tx_buffer_init(void);
+
+/**@brief Function for moving the pointer of the ring buffer to the next element.
+*/
+void tx_buffer_insert(tx_message_t * p_msg);
+
+/**@brief Function for passing any pending request from the buffer to the stack.
+*/
+void tx_buffer_process(void);
+
+/** @} */
+
+#endif // ANCS_TX_BUFFER_H__
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/nrf_ble_bms/nrf_ble_bms.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/nrf_ble_bms/nrf_ble_bms.c
new file mode 100644
index 0000000..5757750
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/nrf_ble_bms/nrf_ble_bms.c
@@ -0,0 +1,622 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <string.h>
+
+#include "nrf_ble_bms.h"
+#include "ble_srv_common.h"
+
+#define NRF_LOG_MODULE_NAME ble_bms
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+/*@brief Check if a returned error code is NRF_SUCCESS, and call the error handler if not.
+ *
+ * @param[in] err_code Error code that should be checked.
+ * @param[in] err_handler Error handler that should be called.
+ */
+static void error_check(ret_code_t err_code, ble_srv_error_handler_t err_handler)
+{
+ if (err_code != NRF_SUCCESS)
+ {
+ err_handler(err_code);
+ }
+}
+
+
+/**@brief Function for adding the Bond Management Control Point characteristic.
+ *
+ * @param[in] p_bms Bond Management Service structure.
+ * @param[in] p_bms_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code returned by @ref characteristic_add.
+ */
+static ret_code_t ctrlpt_char_add(nrf_ble_bms_t * p_bms, nrf_ble_bms_init_t const * p_bms_init)
+{
+ ble_add_char_params_t add_char_params;
+
+ memset(&add_char_params, 0, sizeof(add_char_params));
+ add_char_params.uuid = BLE_UUID_BMS_CTRLPT;
+ add_char_params.char_props.write = 1;
+ add_char_params.is_defered_write = true;
+ add_char_params.is_var_len = true;
+ add_char_params.max_len = NRF_BLE_BMS_CTRLPT_MAX_LEN;
+ add_char_params.read_access = SEC_NO_ACCESS;
+ add_char_params.write_access = p_bms_init->bms_ctrlpt_sec_req;
+
+ if (p_bms_init->p_qwr != NULL)
+ {
+ add_char_params.char_ext_props.reliable_wr = 1;
+ }
+
+ return characteristic_add(p_bms->service_handle, &add_char_params, &p_bms->ctrlpt_handles);
+}
+
+
+/**@brief Forward an authorization request to the application, if necessary.
+ *
+ * @param[in] p_bms Bond Management Service structure.
+ * @param[in] p_ctrlpt Pointer to the received Control Point value.
+ */
+static void ctrlpt_auth(nrf_ble_bms_t * p_bms, nrf_ble_bms_ctrlpt_t * p_ctrlpt)
+{
+ nrf_ble_bms_features_t * p_feature = &p_bms->feature;
+
+ p_bms->auth_status = NRF_BLE_BMS_AUTH_STATUS_ALLOWED;
+
+ /* Check if the authorization feature is enabled for this op code. */
+ if ((
+ (p_ctrlpt->op_code == NRF_BLE_BMS_OP_DEL_BOND_REQ_DEVICE_LE_ONLY) &&
+ (p_feature->delete_requesting_auth)
+ ) ||
+ (
+ (p_ctrlpt->op_code == NRF_BLE_BMS_OP_DEL_ALL_BONDS_ON_SERVER_LE_ONLY) &&
+ (p_feature->delete_all_auth)
+ ) ||
+ (
+ (p_ctrlpt->op_code == NRF_BLE_BMS_OP_DEL_ALL_BUT_ACTIVE_BOND_LE_ONLY) &&
+ (p_feature->delete_all_but_requesting_auth)
+ )
+ )
+ {
+ if (p_bms->evt_handler != NULL)
+ {
+ nrf_ble_bms_evt_t bms_evt;
+
+ memset(&bms_evt, 0, sizeof(bms_evt));
+ bms_evt.evt_type = NRF_BLE_BMS_EVT_AUTH;
+ bms_evt.auth_code.len = p_ctrlpt->auth_code.len;
+ memcpy(bms_evt.auth_code.code, p_ctrlpt->auth_code.code, p_ctrlpt->auth_code.len);
+
+ p_bms->auth_status = NRF_BLE_BMS_AUTH_STATUS_PENDING;
+
+ p_bms->evt_handler(p_bms, &bms_evt);
+ }
+ else
+ {
+ p_bms->auth_status = NRF_BLE_BMS_AUTH_STATUS_DENIED;
+ }
+ }
+}
+
+
+/**@brief Decode an incoming Control Point write.
+ *
+ * @param[in] p_rcvd_val Received write value.
+ * @param[in] len Value length.
+ * @param[out] p_ctrlpt Decoded control point structure.
+ *
+ * @retval NRF_ERROR_INVALID_LENGTH The supplied value length is invalid.
+ * @retval NRF_ERROR_NOT_SUPPORTED The supplied op code is not supported.
+ * @retval NRF_SUCCESS Operation successful.
+ */
+static ret_code_t ctrlpt_decode(uint8_t const * p_rcvd_val,
+ uint16_t len,
+ nrf_ble_bms_ctrlpt_t * p_ctrlpt)
+{
+ uint16_t pos = 0;
+
+ VERIFY_TRUE(len >= NRF_BLE_BMS_CTRLPT_MIN_LEN, NRF_ERROR_INVALID_LENGTH);
+ VERIFY_TRUE(len <= NRF_BLE_BMS_CTRLPT_MAX_LEN, NRF_ERROR_INVALID_LENGTH);
+
+ p_ctrlpt->op_code = (nrf_ble_bms_op_t) p_rcvd_val[pos++];
+ p_ctrlpt->auth_code.len = (len - pos);
+ memcpy(p_ctrlpt->auth_code.code, &(p_rcvd_val[pos]), p_ctrlpt->auth_code.len);
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for performing an operation requested through the Control Point.
+ *
+ * @param[in] p_bms Bond Management Service structure.
+ * @param[in] op_code Op code to execute.
+ */
+static void ctrlpt_execute(nrf_ble_bms_t * p_bms, nrf_ble_bms_op_t op_code)
+{
+ switch (op_code)
+ {
+ case NRF_BLE_BMS_OP_DEL_BOND_REQ_DEVICE_LE_ONLY:
+ /* Delete single bond */
+ p_bms->bond_callbacks.delete_requesting(p_bms);
+ break; // NRF_BLE_BMS_OP_DEL_BOND_REQ_DEVICE_LE_ONLY
+
+ case NRF_BLE_BMS_OP_DEL_ALL_BONDS_ON_SERVER_LE_ONLY:
+ /* Delete all bonds */
+ p_bms->bond_callbacks.delete_all(p_bms);
+ break; // NRF_BLE_BMS_OP_DEL_ALL_BONDS_ON_SERVER_LE_ONLY
+
+ case NRF_BLE_BMS_OP_DEL_ALL_BUT_ACTIVE_BOND_LE_ONLY:
+ /* Delete all but current bond */
+ p_bms->bond_callbacks.delete_all_except_requesting(p_bms);
+ break; // NRF_BLE_BMS_OP_DEL_ALL_BUT_ACTIVE_BOND_LE_ONLY
+
+ default:
+ /* No implemementation needed. */
+ break;
+ }
+}
+
+
+/*@brief Validate an incoming Control Point write.
+ *
+ * @param[in] op_code Received op code.
+ * @param[in] p_feature Supported features.
+ *
+ * @returns True if the op code is supported, or false.
+ */
+static bool ctrlpt_validate(nrf_ble_bms_ctrlpt_t * p_ctrlpt, nrf_ble_bms_features_t * p_feature)
+{
+ switch (p_ctrlpt->op_code)
+ {
+ case NRF_BLE_BMS_OP_DEL_BOND_REQ_DEVICE_LE_ONLY:
+ if (p_feature->delete_requesting || p_feature->delete_requesting_auth)
+ {
+ return true;
+ }
+ break;
+
+ case NRF_BLE_BMS_OP_DEL_ALL_BONDS_ON_SERVER_LE_ONLY:
+ if (p_feature->delete_all || p_feature->delete_all_auth)
+ {
+ return true;
+ }
+ break;
+
+ case NRF_BLE_BMS_OP_DEL_ALL_BUT_ACTIVE_BOND_LE_ONLY:
+ if (p_feature->delete_all_but_requesting || p_feature->delete_all_but_requesting_auth)
+ {
+ return true;
+ }
+ break;
+
+ default:
+ /* No implementation needed. */
+ break;
+ }
+
+ return false;
+}
+
+
+/**@brief Function for processing a write to the Control Point.
+ *
+ * @param[in] p_bms Bond Management Service structure.
+ * @param[in] p_rcvd_val Received write value.
+ * @param[in] len Value length.
+ * @param[out] p_ctrlpt Decoded control point structure.
+ */
+static uint16_t ctrlpt_process(nrf_ble_bms_t * p_bms,
+ uint8_t const * p_rcvd_val,
+ uint16_t len,
+ nrf_ble_bms_ctrlpt_t * p_ctrlpt)
+{
+ ret_code_t err_code;
+
+ /* Decode operation */
+ err_code = ctrlpt_decode(p_rcvd_val, len, p_ctrlpt);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Control point write: Operation failed.");
+ return NRF_BLE_BMS_OPERATION_FAILED;
+ }
+
+ /* Verify that the operation is allowed. */
+ if (!ctrlpt_validate(p_ctrlpt, &p_bms->feature))
+ {
+ NRF_LOG_ERROR("Control point write: Invalid op code.");
+ return NRF_BLE_BMS_OPCODE_NOT_SUPPORTED;
+ }
+
+ /* Request authorization */
+ ctrlpt_auth(p_bms, p_ctrlpt);
+ if (p_bms->auth_status != NRF_BLE_BMS_AUTH_STATUS_ALLOWED)
+ {
+ NRF_LOG_ERROR("Control point long write: Invalid auth.");
+ return BLE_GATT_STATUS_ATTERR_INSUF_AUTHORIZATION;
+ }
+
+ return BLE_GATT_STATUS_SUCCESS;
+}
+
+
+/**@brief Function for encoding the Bond Management Feature characteristic.
+ *
+ * @param[in] p_bms Bond Management Service structure.
+ * @param[out] p_encoded_feature Encoded features.
+ *
+ * @return Size of the encoded feature.
+ */
+static uint8_t feature_encode(nrf_ble_bms_features_t const * p_feature, uint8_t * p_encoded_feature)
+{
+ uint32_t data = 0;
+
+ if (p_feature->delete_all_auth)
+ {
+ data |= NRF_BLE_BMS_ALL_BONDS_LE_AUTH_CODE;
+ }
+ if (p_feature->delete_all_but_requesting_auth)
+ {
+ data |= NRF_BLE_BMS_ALL_EXCEPT_REQUESTING_DEVICE_LE_AUTH_CODE;
+ }
+ if (p_feature->delete_all_but_requesting)
+ {
+ data |= NRF_BLE_BMS_ALL_EXCEPT_REQUESTING_DEVICE_LE;
+ }
+ if (p_feature->delete_all)
+ {
+ data |= NRF_BLE_BMS_ALL_BONDS_LE;
+ }
+ if (p_feature->delete_requesting_auth)
+ {
+ data |= NRF_BLE_BMS_REQUESTING_DEVICE_LE_AUTH_CODE;
+ }
+ if (p_feature->delete_requesting)
+ {
+ data |= NRF_BLE_BMS_REQUESTING_DEVICE_LE;
+ }
+
+ return (uint24_encode(data, p_encoded_feature));
+}
+
+
+/**@brief Function for adding the Bond Management Feature characteristic.
+ *
+ * @param[in] p_bms Bond Management Service structure.
+ * @param[in] p_bms_init Information needed to initialize the service.
+ *
+ * @return NRF_SUCCESS on success, otherwise an error code returned by @ref characteristic_add.
+ */
+static ret_code_t feature_char_add(nrf_ble_bms_t * p_bms, nrf_ble_bms_init_t const * p_bms_init)
+{
+ uint8_t encoded_feature[NRF_BLE_BMS_FEATURE_LEN];
+ uint8_t init_value_len;
+ ble_add_char_params_t add_char_params;
+ nrf_ble_bms_features_t * p_feature = &p_bms->feature;
+
+ if ((p_feature->delete_all_auth) ||
+ (p_feature->delete_all_but_requesting_auth) ||
+ (p_feature->delete_requesting_auth))
+ {
+ VERIFY_PARAM_NOT_NULL(p_bms_init->evt_handler);
+ }
+
+ if ((p_feature->delete_requesting_auth) ||
+ (p_feature->delete_requesting))
+ {
+ VERIFY_PARAM_NOT_NULL(p_bms_init->bond_callbacks.delete_requesting);
+ }
+
+ if ((p_feature->delete_all) ||
+ (p_feature->delete_all_auth))
+ {
+ VERIFY_PARAM_NOT_NULL(p_bms_init->bond_callbacks.delete_all);
+ }
+
+ if ((p_feature->delete_all_but_requesting) ||
+ (p_feature->delete_all_but_requesting_auth))
+ {
+ VERIFY_PARAM_NOT_NULL(p_bms_init->bond_callbacks.delete_all_except_requesting);
+ }
+
+ init_value_len = feature_encode(&p_bms->feature, encoded_feature);
+
+ memset(&add_char_params, 0, sizeof(add_char_params));
+ add_char_params.uuid = BLE_UUID_BMS_FEATURE;
+ add_char_params.char_props.read = true;
+ add_char_params.max_len = init_value_len;
+ add_char_params.p_init_value = encoded_feature;
+ add_char_params.init_len = init_value_len;
+ add_char_params.read_access = p_bms_init->bms_feature_sec_req;
+ add_char_params.write_access = SEC_NO_ACCESS;
+
+ return characteristic_add(p_bms->service_handle, &add_char_params, &p_bms->feature_handles);
+}
+
+
+/**@brief Handle a write event to the Bond Management Service Control Point.
+ *
+ * @param[in] p_bms Bond Management Service structure.
+ * @param[in] p_evt_write WRITE event to be handled.
+ */
+static void on_ctrlpt_write(nrf_ble_bms_t * p_bms,
+ ble_gatts_evt_write_t const * p_evt_write,
+ ble_gatts_authorize_params_t * p_auth_params)
+{
+ ret_code_t err_code;
+ nrf_ble_bms_ctrlpt_t ctrlpt;
+
+ err_code = ctrlpt_process(p_bms, p_evt_write->data, p_evt_write->len, &ctrlpt);
+ if (err_code != NRF_SUCCESS)
+ {
+ p_auth_params->gatt_status = err_code;
+ p_auth_params->update = 0;
+
+ return;
+ }
+
+ p_auth_params->gatt_status = BLE_GATT_STATUS_SUCCESS;
+ p_auth_params->update = 1;
+
+ NRF_LOG_INFO("Control point write: Success");
+
+ /* Execute the requested operation. */
+ ctrlpt_execute(p_bms, ctrlpt.op_code);
+}
+
+
+/**@brief Authorize WRITE request event handler.
+ *
+ * @details Handles WRITE events from the BLE stack.
+ *
+ * @param[in] p_bms Bond Management Service structure.
+ * @param[in] p_gatts_evt GATTS Event received from the BLE stack.
+ *
+ */
+static void on_rw_auth_req(nrf_ble_bms_t * p_bms, ble_gatts_evt_t const * p_gatts_evt)
+{
+ ret_code_t err_code;
+ ble_gatts_rw_authorize_reply_params_t auth_reply;
+
+ ble_gatts_evt_rw_authorize_request_t const * p_auth_req =
+ &p_gatts_evt->params.authorize_request;
+
+ memset(&auth_reply, 0, sizeof(auth_reply));
+
+ if ((p_auth_req->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE) &&
+ (p_auth_req->request.write.op == BLE_GATTS_OP_WRITE_REQ) &&
+ (p_auth_req->request.write.handle == p_bms->ctrlpt_handles.value_handle))
+ {
+ auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
+ on_ctrlpt_write(p_bms, &p_auth_req->request.write, &auth_reply.params.write);
+
+ /* Send authorization reply */
+ err_code = sd_ble_gatts_rw_authorize_reply(p_bms->conn_handle, &auth_reply);
+ error_check(err_code, p_bms->error_handler);
+ }
+
+}
+
+
+/**@brief Handle authorization request events from the Queued Write module.
+ *
+ * @param[in] p_bms Bond Management Service structure.
+ * @param[in] p_qwr Queued Write Structure.
+ * @param[in] p_evt Event received from the Queued Writes module.
+ *
+ * @retval BLE_GATT_STATUS_SUCCESS If the received event is accepted.
+ * @retval BLE_BMS_OPCODE_OPERATION_FAILED If the received event is not relevant for any of this module's attributes.
+ * @retval BLE_BMS_OPCODE_NOT_SUPPORTED If the received opcode is not supported.
+ * @retval BLE_GATT_STATUS_ATTERR_INSUF_AUTHORIZATION If the application handler returns that the authorization code is not valid.
+ */
+uint16_t on_qwr_auth_req(nrf_ble_bms_t * p_bms, nrf_ble_qwr_t * p_qwr, nrf_ble_qwr_evt_t * p_evt)
+{
+ ret_code_t err_code;
+ uint16_t len = NRF_BLE_BMS_CTRLPT_MAX_LEN;
+ uint8_t mem_buffer[NRF_BLE_BMS_CTRLPT_MAX_LEN];
+ nrf_ble_bms_ctrlpt_t ctrlpt;
+
+ err_code = nrf_ble_qwr_value_get(p_qwr, p_evt->attr_handle, mem_buffer, &len);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Control point write: Operation failed.");
+ return NRF_BLE_BMS_OPERATION_FAILED;
+ }
+
+ return ctrlpt_process(p_bms, mem_buffer, len, &ctrlpt);
+}
+
+
+/**@brief Handle execute write events to from the Queued Write module.
+ *
+ * @param[in] p_bms Bond Management Service structure.
+ * @param[in] p_qwr Queued Write Structure.
+ * @param[in] p_evt Event received from the Queued Writes module.
+ *
+ * @retval BLE_GATT_STATUS_SUCCESS If the received event is accepted.
+ * @retval BLE_BMS_OPCODE_OPERATION_FAILED If the received event is not relevant for any of this module's attributes.
+ * @retval BLE_BMS_OPCODE_NOT_SUPPORTED If the received opcode is not supported.
+ */
+uint16_t on_qwr_exec_write(nrf_ble_bms_t * p_bms, nrf_ble_qwr_t * p_qwr, nrf_ble_qwr_evt_t * p_evt)
+{
+ ret_code_t err_code;
+ uint16_t len = NRF_BLE_BMS_CTRLPT_MAX_LEN;
+ uint8_t mem_buffer[NRF_BLE_BMS_CTRLPT_MAX_LEN];
+ nrf_ble_bms_ctrlpt_t ctrlpt;
+ ble_gatts_value_t ctrlpt_value;
+
+ ctrlpt_value.len = NRF_BLE_BMS_CTRLPT_MAX_LEN;
+ ctrlpt_value.offset = 0;
+ ctrlpt_value.p_value = mem_buffer;
+
+ const uint16_t ctrlpt_handle = p_bms->ctrlpt_handles.value_handle;
+ err_code = sd_ble_gatts_value_get(p_bms->conn_handle, ctrlpt_handle, &ctrlpt_value);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Control point write: Operation failed.");
+ return NRF_BLE_BMS_OPERATION_FAILED;
+ }
+
+ /* Decode operation */
+ err_code = ctrlpt_decode(ctrlpt_value.p_value, len, &ctrlpt);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Control point write: Operation failed.");
+ return NRF_BLE_BMS_OPERATION_FAILED;
+ }
+
+ /* Execute the requested operation. */
+ ctrlpt_execute(p_bms, ctrlpt.op_code);
+
+ /* Reset authorization status */
+ p_bms->auth_status = NRF_BLE_BMS_AUTH_STATUS_DENIED;
+
+ return BLE_GATT_STATUS_SUCCESS;
+}
+
+
+uint16_t nrf_ble_bms_on_qwr_evt(nrf_ble_bms_t * p_bms,
+ nrf_ble_qwr_t * p_qwr,
+ nrf_ble_qwr_evt_t * p_evt)
+{
+ VERIFY_TRUE(p_bms != NULL, (NRF_BLE_QWR_REJ_REQUEST_ERR_CODE));
+ VERIFY_TRUE(p_qwr != NULL, (NRF_BLE_QWR_REJ_REQUEST_ERR_CODE));
+ VERIFY_TRUE(p_evt != NULL, (NRF_BLE_QWR_REJ_REQUEST_ERR_CODE));
+ VERIFY_TRUE(p_evt->attr_handle == p_bms->ctrlpt_handles.value_handle,
+ (NRF_BLE_QWR_REJ_REQUEST_ERR_CODE));
+
+ if (p_evt->evt_type == NRF_BLE_QWR_EVT_AUTH_REQUEST)
+ {
+ return on_qwr_auth_req(p_bms, p_qwr, p_evt);
+ }
+ else if ((p_evt->evt_type == NRF_BLE_QWR_EVT_EXECUTE_WRITE) &&
+ (p_bms->auth_status == NRF_BLE_BMS_AUTH_STATUS_ALLOWED))
+ {
+ return on_qwr_exec_write(p_bms, p_qwr, p_evt);
+ }
+
+ return BLE_GATT_STATUS_SUCCESS;
+}
+
+
+void nrf_ble_bms_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ VERIFY_PARAM_NOT_NULL_VOID(p_context);
+ VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
+
+ nrf_ble_bms_t * p_bms = (nrf_ble_bms_t *)p_context;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
+ on_rw_auth_req(p_bms, &p_ble_evt->evt.gatts_evt);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+ret_code_t nrf_ble_bms_set_conn_handle(nrf_ble_bms_t * p_bms, uint16_t conn_handle)
+{
+ VERIFY_PARAM_NOT_NULL(p_bms);
+
+ p_bms->conn_handle = conn_handle;
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t nrf_ble_bms_init(nrf_ble_bms_t * p_bms, nrf_ble_bms_init_t * p_bms_init)
+{
+ ret_code_t err_code;
+ ble_uuid_t ble_uuid;
+
+ VERIFY_PARAM_NOT_NULL(p_bms_init);
+ VERIFY_PARAM_NOT_NULL(p_bms);
+
+ // Add service
+ BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_BMS_SERVICE);
+
+ p_bms->evt_handler = p_bms_init->evt_handler;
+ p_bms->error_handler = p_bms_init->error_handler;
+ p_bms->feature = p_bms_init->feature;
+ p_bms->bond_callbacks = p_bms_init->bond_callbacks;
+ p_bms->conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
+ &ble_uuid,
+ &p_bms->service_handle);
+ VERIFY_SUCCESS(err_code);
+
+ err_code = feature_char_add(p_bms, p_bms_init);
+ VERIFY_SUCCESS(err_code);
+
+ err_code = ctrlpt_char_add(p_bms, p_bms_init);
+ VERIFY_SUCCESS(err_code);
+
+ if (p_bms_init->p_qwr != NULL)
+ {
+ return nrf_ble_qwr_attr_register(p_bms_init->p_qwr, p_bms->ctrlpt_handles.value_handle);
+ }
+
+ NRF_LOG_INFO("Init complete.");
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t nrf_ble_bms_auth_response(nrf_ble_bms_t * p_bms, bool authorize)
+{
+ VERIFY_PARAM_NOT_NULL(p_bms);
+ VERIFY_TRUE(p_bms->auth_status == NRF_BLE_BMS_AUTH_STATUS_PENDING, NRF_ERROR_INVALID_STATE);
+
+ if (authorize)
+ {
+ p_bms->auth_status = NRF_BLE_BMS_AUTH_STATUS_ALLOWED;
+ }
+ else
+ {
+ p_bms->auth_status = NRF_BLE_BMS_AUTH_STATUS_DENIED;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/nrf_ble_bms/nrf_ble_bms.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/nrf_ble_bms/nrf_ble_bms.h
new file mode 100644
index 0000000..1aa6abb
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/ble_services/nrf_ble_bms/nrf_ble_bms.h
@@ -0,0 +1,316 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_bms Bond Management Service
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Bond Management Service (BMS) module.
+ *
+ * @details This module implements the Bond Management Service (BMS).
+ * By writing to the Bond Management Control Point, the connected peer can request the deletion of
+ * bond information from the device.
+ * If authorization is configured, the application must supply an event handler for receiving Bond
+ * Management Service events. Using this handler, the service requests authorization when
+ * a procedure is requested by writing to the Bond Management Control Point.
+ *
+ * @msc
+ * hscale = "1.3";
+ * APP,BMS,PEER;
+ * |||;
+ * APP rbox PEER [label="Connection established"];
+ * |||;
+ * BMS<=PEER [label="BMCP write request {procedure}"];
+ * APP<-BMS [label="NRF_BLE_BMS_EVT_AUTH {auth_code}"];
+ * --- [label="Variant #1: app grants authorization"];
+ * APP->BMS [label="nrf_ble_bms_auth_reponse (true)"];
+ * BMS>>APP [label="NRF_SUCCESS"];
+ * BMS=>PEER [label="BMCP write response"];
+ * BMS rbox BMS [label="Procedure initiated"];
+ * --- [label="Variant #2: app denies authorization"];
+ * APP->BMS [label="nrf_ble_bms_auth_reponse (false)"];
+ * BMS>>APP [label="NRF_SUCCESS"];
+ * BMS=>PEER [label="BMCP error response"];
+ * @endmsc
+ *
+ * @note The application must register this module as BLE event observer using the
+ * NRF_SDH_BLE_OBSERVER macro. Example:
+ * @code
+ * nrf_ble_bms_t instance;
+ * NRF_SDH_BLE_OBSERVER(anything, NRF_BLE_BMS_BLE_OBSERVER_PRIO,
+ * nrf_ble_bms_on_ble_evt, &instance);
+ * @endcode
+ */
+
+#ifndef NRF_BLE_BMS_H__
+#define NRF_BLE_BMS_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "nrf_ble_qwr.h"
+#include "nrf_sdh_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a nrf_ble_bms instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define NRF_BLE_BMS_DEF(_name) \
+static nrf_ble_bms_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ NRF_BLE_BMS_BLE_OBSERVER_PRIO, \
+ nrf_ble_bms_on_ble_evt, &_name)
+
+#define NRF_BLE_BMS_FEATURE_LEN 3 //!< Length of the Feature Characteristic (in bytes).
+#define NRF_BLE_BMS_CTRLPT_MAX_LEN 128 //!< Maximum length of the Bond Management Control Point Characteristic (in bytes).
+#define NRF_BLE_BMS_CTRLPT_MIN_LEN 1 //!< Minimum length of the Bond Management Control Point Characteristic (in bytes).
+#define NRF_BLE_BMS_AUTH_CODE_MAX_LEN NRF_BLE_BMS_CTRLPT_MAX_LEN - 1 //!< Maximum length of the Bond Management Control Point Authorization Code (in bytes).
+
+/** @defgroup NRF_BLE_BMS_FEATURES BMS feature bits
+ * @{ */
+#define NRF_BLE_BMS_REQUESTING_DEVICE_BR_LE (0x01 << 0) //!< Delete bond of the requesting device (BR/EDR and LE).
+#define NRF_BLE_BMS_REQUESTING_DEVICE_BR_LE_AUTH_CODE (0x01 << 1) //!< Delete bond of the requesting device (BR/EDR and LE) with an authorization code.
+#define NRF_BLE_BMS_REQUESTING_DEVICE_BR (0x01 << 2) //!< Delete bond of the requesting device (BR/EDR transport only).
+#define NRF_BLE_BMS_REQUESTING_DEVICE_BR_AUTH_CODE (0x01 << 3) //!< Delete bond of the requesting device (BR/EDR transport only) with an authorization code.
+#define NRF_BLE_BMS_REQUESTING_DEVICE_LE (0x01 << 4) //!< Delete bond of the requesting device (LE transport only).
+#define NRF_BLE_BMS_REQUESTING_DEVICE_LE_AUTH_CODE (0x01 << 5) //!< Delete bond of the requesting device (LE transport only) with an authorization code.
+#define NRF_BLE_BMS_ALL_BONDS_BR_LE (0x01 << 6) //!< Delete all bonds on the device (BR/EDR and LE).
+#define NRF_BLE_BMS_ALL_BONDS_BR_LE_AUTH_CODE (0x01 << 7) //!< Delete all bonds on the device (BR/EDR and LE) with an authorization code.
+#define NRF_BLE_BMS_ALL_BONDS_BR (0x01 << 8) //!< Delete all bonds on the device (BR/EDR transport only).
+#define NRF_BLE_BMS_ALL_BONDS_BR_AUTH_CODE (0x01 << 9) //!< Delete all bonds on the device (BR/EDR transport only) with an authorization code.
+#define NRF_BLE_BMS_ALL_BONDS_LE (0x01 << 10) //!< Delete all bonds on the device (LE transport only).
+#define NRF_BLE_BMS_ALL_BONDS_LE_AUTH_CODE (0x01 << 11) //!< Delete all bonds on the device (LE transport only) with an authorization code.
+#define NRF_BLE_BMS_ALL_EXCEPT_REQUESTING_DEVICE_BR_LE (0x01 << 12) //!< Delete all bonds on the device except for the bond of the requesting device (BR/EDR and LE).
+#define NRF_BLE_BMS_ALL_EXCEPT_REQUESTING_DEVICE_BR_LE_AUTH_CODE (0x01 << 13) //!< Delete all bonds on the device except for the bond of the requesting device (BR/EDR and LE) with an authorization code.
+#define NRF_BLE_BMS_ALL_EXCEPT_REQUESTING_DEVICE_BR (0x01 << 14) //!< Delete all bonds on the device except for the bond of the requesting device (BR/EDR transport only).
+#define NRF_BLE_BMS_ALL_EXCEPT_REQUESTING_DEVICE_BR_AUTH_CODE (0x01 << 15) //!< Delete all bonds on the device except for the bond of the requesting device (BR/EDR transport only) with an authorization code.
+#define NRF_BLE_BMS_ALL_EXCEPT_REQUESTING_DEVICE_LE (0x01 << 16) //!< Delete all bonds on the device except for the bond of the requesting device (LE transport only).
+#define NRF_BLE_BMS_ALL_EXCEPT_REQUESTING_DEVICE_LE_AUTH_CODE (0x01 << 17) //!< Delete all bonds on the device except for the bond of the requesting device (LE transport only) with an authorization code.
+/** @} */
+
+#define NRF_BLE_BMS_OPCODE_NOT_SUPPORTED (BLE_GATT_STATUS_ATTERR_APP_BEGIN + 0) //!< Error sent back when receiving a control point write with an unsupported opcode.
+#define NRF_BLE_BMS_OPERATION_FAILED (BLE_GATT_STATUS_ATTERR_APP_BEGIN + 1) //!< Error sent back when a control point operation fails.
+
+
+/**@brief Supported features. */
+typedef struct
+{
+ bool delete_all : 1; //!< Indicates whether the application wants to support the operation to delete all bonds.
+ bool delete_all_auth : 1; //!< Indicates whether the application wants to support the operation to delete all bonds with authorization code.
+ bool delete_requesting : 1; //!< Indicates whether the application wants to support the operation to delete the bonds of the requesting device.
+ bool delete_requesting_auth : 1; //!< Indicates whether the application wants to support the operation to delete the bonds of the requesting device with authorization code.
+ bool delete_all_but_requesting : 1; //!< Indicates whether the application wants to support the operation to delete all bonds except for the bond of the requesting device.
+ bool delete_all_but_requesting_auth : 1; //!< Indicates whether the application wants to support the operation to delete all bonds except for the bond of the requesting device with authorization code.
+} nrf_ble_bms_features_t;
+
+/**@brief BMS Control Point opcodes. */
+typedef enum
+{
+ NRF_BLE_BMS_OP_DEL_BOND_REQ_DEVICE_BR_LE = 0x01, //!< Initiates the procedure to delete the bond of the requesting device on BR/EDR and LE transports.
+ NRF_BLE_BMS_OP_DEL_BOND_REQ_DEVICE_BR_ONLY = 0x02, //!< Initiates the procedure to delete the bond of the requesting device on BR/EDR transport.
+ NRF_BLE_BMS_OP_DEL_BOND_REQ_DEVICE_LE_ONLY = 0x03, //!< Initiates the procedure to delete the bond of the requesting device on LE transport.
+ NRF_BLE_BMS_OP_DEL_ALL_BONDS_ON_SERVER_BR_LE = 0x04, //!< Initiates the procedure to delete all bonds on the device on BR/EDR and LE transports.
+ NRF_BLE_BMS_OP_DEL_ALL_BONDS_ON_SERVER_BR_ONLY = 0x05, //!< Initiates the procedure to delete all bonds on the device on BR/EDR transport.
+ NRF_BLE_BMS_OP_DEL_ALL_BONDS_ON_SERVER_LE_ONLY = 0x06, //!< Initiates the procedure to delete all bonds on the device on LE transport.
+ NRF_BLE_BMS_OP_DEL_ALL_BUT_ACTIVE_BOND_BR_LE = 0x07, //!< Initiates the procedure to delete all bonds except for the one of the requesting device on BR/EDR and LE transports.
+ NRF_BLE_BMS_OP_DEL_ALL_BUT_ACTIVE_BOND_BR_ONLY = 0x08, //!< Initiates the procedure to delete all bonds except for the one of the requesting device on BR/EDR transport.
+ NRF_BLE_BMS_OP_DEL_ALL_BUT_ACTIVE_BOND_LE_ONLY = 0x09, //!< Initiates the procedure to delete all bonds except for the one of the requesting device on LE transport.
+ NRF_BLE_BMS_OP_NONE = 0xFF //!< Indicates an invalid opcode or no pending opcode.
+} nrf_ble_bms_op_t;
+
+/**@brief Authorization status values. */
+typedef enum
+{
+ NRF_BLE_BMS_AUTH_STATUS_ALLOWED, //!< Authorization is granted.
+ NRF_BLE_BMS_AUTH_STATUS_DENIED, //!< Authorization is denied.
+ NRF_BLE_BMS_AUTH_STATUS_PENDING //!< Authorization is pending.
+} nrf_ble_bms_auth_status_t;
+
+/**@brief Received authorization codes. */
+typedef struct
+{
+ uint8_t code[NRF_BLE_BMS_AUTH_CODE_MAX_LEN]; //!< Authorization code.
+ uint16_t len; //!< Length of the authorization code.
+} nrf_ble_bms_auth_code_t;
+
+/**@brief BMS event types. */
+typedef enum
+{
+ NRF_BLE_BMS_EVT_AUTH, //!< Event that indicates that the application shall verify the supplied authentication code.
+} nrf_ble_bms_evt_type_t;
+
+/**@brief BMS events. */
+typedef struct
+{
+ nrf_ble_bms_evt_type_t evt_type; //!< Type of event.
+ nrf_ble_bms_auth_code_t auth_code; //!< Received authorization code.
+} nrf_ble_bms_evt_t;
+
+/**@brief BMS control points. */
+typedef struct
+{
+ nrf_ble_bms_op_t op_code; //!< Control Point Op Code.
+ nrf_ble_bms_auth_code_t auth_code; //!< Control Point Authorization Code.
+} nrf_ble_bms_ctrlpt_t;
+
+// Forward declaration of the nrf_ble_bms_t type.
+typedef struct nrf_ble_bms_s nrf_ble_bms_t;
+
+/**@brief BMS event handler type. */
+typedef void (* nrf_ble_bms_bond_handler_t) (nrf_ble_bms_t const * p_bms);
+
+/**@brief BMS bond management callbacks. */
+typedef struct
+{
+ nrf_ble_bms_bond_handler_t delete_requesting; //!< Function to be called to delete the bonding information of the requesting device.
+ nrf_ble_bms_bond_handler_t delete_all; //!< Function to be called to delete the bonding information of all bonded devices.
+ nrf_ble_bms_bond_handler_t delete_all_except_requesting; //!< Function to be called to delete the bonding information of all bonded devices except for the requesting device.
+} nrf_ble_bms_bond_cbs_t;
+
+/**@brief BMS event handler type. The event handler returns a @ref BLE_GATT_STATUS_CODES "BLE GATT status code". */
+typedef void (* ble_bms_evt_handler_t) (nrf_ble_bms_t * p_bms, nrf_ble_bms_evt_t * p_evt);
+
+/**@brief BMS initialization structure that contains all information needed to initialize the service. */
+typedef struct
+{
+ ble_bms_evt_handler_t evt_handler; //!< Event handler to be called for handling events in the Bond Management Service.
+ ble_srv_error_handler_t error_handler; //!< Function to be called if an error occurs.
+ nrf_ble_bms_features_t feature; //!< Initial value for features of the service.
+ security_req_t bms_feature_sec_req; //!< Initial security level for the Feature characteristic.
+ security_req_t bms_ctrlpt_sec_req; //!< Initial security level for the Control Point characteristic.
+ nrf_ble_qwr_t * p_qwr; //!< Pointer to the initialized Queued Write context.
+ nrf_ble_bms_bond_cbs_t bond_callbacks; //!< Callback functions for deleting bonds.
+} nrf_ble_bms_init_t;
+
+/**@brief Status information for the service. */
+struct nrf_ble_bms_s
+{
+ uint16_t service_handle; //!< Handle of the Bond Management Service (as provided by the BLE stack).
+ uint16_t conn_handle; //!< Handle of the current connection (as provided by the BLE stack). @ref BLE_CONN_HANDLE_INVALID if not in a connection.
+ ble_bms_evt_handler_t evt_handler; //!< Event handler to be called for handling events in the Bond Management Service.
+ ble_srv_error_handler_t error_handler; //!< Function to be called if an error occurs.
+ nrf_ble_bms_features_t feature; //!< Value for features of the service (see @ref NRF_BLE_BMS_FEATURES).
+ ble_gatts_char_handles_t feature_handles; //!< Handles related to the Bond Management Feature characteristic.
+ ble_gatts_char_handles_t ctrlpt_handles; //!< Handles related to the Bond Management Control Point characteristic.
+ nrf_ble_bms_bond_cbs_t bond_callbacks; //!< Callback functions for deleting bonds.
+ nrf_ble_bms_auth_status_t auth_status; //!< Authorization status.
+};
+
+
+/**@brief Function for responding to an authorization request.
+ *
+ * @details This function should be called when receiving the @ref NRF_BLE_BMS_EVT_AUTH event to
+ * respond to the service with an authorization result.
+ *
+ * @param[in] p_bms BMS structure.
+ * @param[in] authorize Authorization response. True if the authorization is considered successful.
+ *
+ * @retval NRF_ERROR_NULL If @p p_bms was NULL.
+ * @retval NRF_ERROR_INVALID_STATE If no authorization request was pending.
+ * @retval NRF_SUCCESS If the response was received successfully.
+ */
+ret_code_t nrf_ble_bms_auth_response(nrf_ble_bms_t * p_bms, bool authorize);
+
+
+/**@brief Function for initializing the Bond Management Service.
+ *
+ * @param[out] p_bms BMS structure.
+ * @param[in] p_bms_init Information needed to initialize the service.
+ *
+ * @retval NRF_ERROR_NULL If @p p_bms or @p p_bms_init was NULL.
+ * @retval NRF_SUCCESS If the service was initialized successfully.
+ * Otherwise, an error code is returned.
+ */
+ret_code_t nrf_ble_bms_init(nrf_ble_bms_t * p_bms, nrf_ble_bms_init_t * p_bms_init);
+
+
+/**@brief Function for assigning handles to the Bond Management Service instance.
+ *
+ * @details Call this function when a link with a peer has been established to
+ * associate the link to this instance of the module.
+ *
+ * @param[in] p_bms Pointer to the BMS structure instance to associate.
+ * @param[in] conn_handle Connection handle to be associated with the given BMS instance.
+ *
+ * @retval NRF_ERROR_NULL If @p p_bms was NULL.
+ * @retval NRF_SUCCESS If the operation was successful.
+ */
+ret_code_t nrf_ble_bms_set_conn_handle(nrf_ble_bms_t * p_bms, uint16_t conn_handle);
+
+
+/**@brief Function for handling Bond Management BLE stack events.
+ *
+ * @details This function handles all events from the BLE stack that are of interest to the Bond Management Service.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context BMS structure.
+ */
+void nrf_ble_bms_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for handling events from the @ref nrf_ble_qwr.
+ *
+ * @param[in] p_bms BMS structure.
+ * @param[in] p_qwr Queued Write structure.
+ * @param[in] p_evt Event received from the Queued Writes module.
+ *
+ * @retval BLE_GATT_STATUS_SUCCESS If the received event is accepted.
+ * @retval NRF_BLE_QWR_REJ_REQUEST_ERR_CODE If the received event is not relevant for any of this module's attributes.
+ * @retval BLE_BMS_OPCODE_NOT_SUPPORTED If the received opcode is not supported.
+ * @retval BLE_GATT_STATUS_ATTERR_INSUF_AUTHORIZATION If the application handler returns that the authorization code is not valid.
+ */
+uint16_t nrf_ble_bms_on_qwr_evt(nrf_ble_bms_t * p_bms,
+ nrf_ble_qwr_t * p_qwr,
+ nrf_ble_qwr_evt_t * p_evt);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // NRF_BLE_BMS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_advdata.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_advdata.c
new file mode 100644
index 0000000..894a5e9
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_advdata.c
@@ -0,0 +1,827 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "ble_advdata.h"
+#include "ble_gap.h"
+#include "ble_srv_common.h"
+#include "sdk_common.h"
+
+// NOTE: For now, Security Manager Out of Band Flags (OOB) are omitted from the advertising data.
+
+
+// Types of LE Bluetooth Device Address AD type
+#define AD_TYPE_BLE_DEVICE_ADDR_TYPE_PUBLIC 0UL
+#define AD_TYPE_BLE_DEVICE_ADDR_TYPE_RANDOM 1UL
+
+#define UUID16_SIZE 2 /**< Size of 16 bit UUID. */
+#define UUID32_SIZE 4 /**< Size of 32 bit UUID. */
+#define UUID128_SIZE 16 /**< Size of 128 bit UUID. */
+
+#define N_AD_TYPES 2 /**< The number of Advertising data types to search for at a time. */
+
+
+static ret_code_t ble_device_addr_encode(uint8_t * p_encoded_data,
+ uint16_t * p_offset,
+ uint16_t max_size)
+{
+ ret_code_t err_code;
+ ble_gap_addr_t device_addr;
+
+ // Check for buffer overflow.
+ if (((*p_offset) + AD_TYPE_BLE_DEVICE_ADDR_SIZE) > max_size)
+ {
+ return NRF_ERROR_DATA_SIZE;
+ }
+
+ // Get BLE address.
+ err_code = sd_ble_gap_addr_get(&device_addr);
+ VERIFY_SUCCESS(err_code);
+
+ // Encode LE Bluetooth Device Address.
+ p_encoded_data[*p_offset] = (uint8_t)(AD_TYPE_FIELD_SIZE +
+ AD_TYPE_BLE_DEVICE_ADDR_DATA_SIZE);
+ *p_offset += AD_LENGTH_FIELD_SIZE;
+ p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS;
+ *p_offset += AD_TYPE_FIELD_SIZE;
+ memcpy(&p_encoded_data[*p_offset], &device_addr.addr[0], BLE_GAP_ADDR_LEN);
+ *p_offset += BLE_GAP_ADDR_LEN;
+ if (BLE_GAP_ADDR_TYPE_PUBLIC == device_addr.addr_type)
+ {
+ p_encoded_data[*p_offset] = AD_TYPE_BLE_DEVICE_ADDR_TYPE_PUBLIC;
+ }
+ else
+ {
+ p_encoded_data[*p_offset] = AD_TYPE_BLE_DEVICE_ADDR_TYPE_RANDOM;
+ }
+ *p_offset += AD_TYPE_BLE_DEVICE_ADDR_TYPE_SIZE;
+
+ return NRF_SUCCESS;
+}
+
+static ret_code_t name_encode(const ble_advdata_t * p_advdata,
+ uint8_t * p_encoded_data,
+ uint16_t * p_offset,
+ uint16_t max_size)
+{
+ ret_code_t err_code;
+ uint16_t rem_adv_data_len;
+ uint16_t actual_length;
+ uint8_t adv_data_format;
+
+
+ // Validate parameters
+ if ((BLE_ADVDATA_SHORT_NAME == p_advdata->name_type) && (0 == p_advdata->short_name_len))
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ // Check for buffer overflow.
+ if ( (((*p_offset) + AD_DATA_OFFSET) > max_size) ||
+ ( (BLE_ADVDATA_SHORT_NAME == p_advdata->name_type) &&
+ (((*p_offset) + AD_DATA_OFFSET + p_advdata->short_name_len) > max_size)))
+ {
+ return NRF_ERROR_DATA_SIZE;
+ }
+
+ rem_adv_data_len = max_size - (*p_offset) - AD_DATA_OFFSET;
+ actual_length = rem_adv_data_len;
+
+ // Get GAP device name and length
+ err_code = sd_ble_gap_device_name_get(&p_encoded_data[(*p_offset) + AD_DATA_OFFSET],
+ &actual_length);
+ VERIFY_SUCCESS(err_code);
+
+ // Check if device intend to use short name and it can fit available data size.
+ if ((p_advdata->name_type == BLE_ADVDATA_FULL_NAME) && (actual_length <= rem_adv_data_len))
+ {
+ // Complete device name can fit, setting Complete Name in Adv Data.
+ adv_data_format = BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME;
+ }
+ else
+ {
+ // Else short name needs to be used. Or application has requested use of short name.
+ adv_data_format = BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME;
+
+ // If application has set a preference on the short name size, it needs to be considered,
+ // else fit what can be fit.
+ if ((BLE_ADVDATA_SHORT_NAME == p_advdata->name_type) &&
+ (p_advdata->short_name_len <= rem_adv_data_len))
+ {
+ // Short name fits available size.
+ actual_length = p_advdata->short_name_len;
+ }
+ // Else whatever can fit the data buffer will be packed.
+ else
+ {
+ actual_length = rem_adv_data_len;
+ }
+ }
+
+ // There is only 1 byte intended to encode length which is (actual_length + AD_TYPE_FIELD_SIZE)
+ if (actual_length > (0x00FF - AD_TYPE_FIELD_SIZE))
+ {
+ return NRF_ERROR_DATA_SIZE;
+ }
+
+ // Complete name field in encoded data.
+ p_encoded_data[*p_offset] = (uint8_t)(AD_TYPE_FIELD_SIZE + actual_length);
+ *p_offset += AD_LENGTH_FIELD_SIZE;
+ p_encoded_data[*p_offset] = adv_data_format;
+ *p_offset += AD_TYPE_FIELD_SIZE;
+ *p_offset += actual_length;
+
+ return NRF_SUCCESS;
+}
+
+
+static ret_code_t appearance_encode(uint8_t * p_encoded_data,
+ uint16_t * p_offset,
+ uint16_t max_size)
+{
+ ret_code_t err_code;
+ uint16_t appearance;
+
+ // Check for buffer overflow.
+ if (((*p_offset) + AD_TYPE_APPEARANCE_SIZE) > max_size)
+ {
+ return NRF_ERROR_DATA_SIZE;
+ }
+
+ // Get GAP appearance field.
+ err_code = sd_ble_gap_appearance_get(&appearance);
+ VERIFY_SUCCESS(err_code);
+
+ // Encode Length, AD Type and Appearance.
+ p_encoded_data[*p_offset] = (uint8_t)(AD_TYPE_FIELD_SIZE + AD_TYPE_APPEARANCE_DATA_SIZE);
+ *p_offset += AD_LENGTH_FIELD_SIZE;
+ p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_APPEARANCE;
+ *p_offset += AD_TYPE_FIELD_SIZE;
+ *p_offset += uint16_encode(appearance, &p_encoded_data[*p_offset]);
+
+ return NRF_SUCCESS;
+}
+
+static ret_code_t flags_encode(int8_t flags,
+ uint8_t * p_encoded_data,
+ uint16_t * p_offset,
+ uint16_t max_size)
+{
+ // Check for buffer overflow.
+ if (((*p_offset) + AD_TYPE_FLAGS_SIZE) > max_size)
+ {
+ return NRF_ERROR_DATA_SIZE;
+ }
+
+ // Encode flags.
+ p_encoded_data[*p_offset] = (uint8_t)(AD_TYPE_FIELD_SIZE + AD_TYPE_FLAGS_DATA_SIZE);
+ *p_offset += AD_LENGTH_FIELD_SIZE;
+ p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_FLAGS;
+ *p_offset += AD_TYPE_FIELD_SIZE;
+ p_encoded_data[*p_offset] = flags;
+ *p_offset += AD_TYPE_FLAGS_DATA_SIZE;
+
+ return NRF_SUCCESS;
+}
+
+static ret_code_t tx_power_level_encode(int8_t tx_power_level,
+ uint8_t * p_encoded_data,
+ uint16_t * p_offset,
+ uint16_t max_size)
+{
+ // Check for buffer overflow.
+ if (((*p_offset) + AD_TYPE_TX_POWER_LEVEL_SIZE) > max_size)
+ {
+ return NRF_ERROR_DATA_SIZE;
+ }
+
+ // Encode TX Power Level.
+ p_encoded_data[*p_offset] = (uint8_t)(AD_TYPE_FIELD_SIZE +
+ AD_TYPE_TX_POWER_LEVEL_DATA_SIZE);
+ *p_offset += AD_LENGTH_FIELD_SIZE;
+ p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_TX_POWER_LEVEL;
+ *p_offset += AD_TYPE_FIELD_SIZE;
+ p_encoded_data[*p_offset] = tx_power_level;
+ *p_offset += AD_TYPE_TX_POWER_LEVEL_DATA_SIZE;
+
+ return NRF_SUCCESS;
+}
+
+
+static ret_code_t uuid_list_sized_encode(const ble_advdata_uuid_list_t * p_uuid_list,
+ uint8_t adv_type,
+ uint8_t uuid_size,
+ uint8_t * p_encoded_data,
+ uint16_t * p_offset,
+ uint16_t max_size)
+{
+ int i;
+ bool is_heading_written = false;
+ uint16_t start_pos = *p_offset;
+ uint16_t length;
+
+ for (i = 0; i < p_uuid_list->uuid_cnt; i++)
+ {
+ ret_code_t err_code;
+ uint8_t encoded_size;
+ ble_uuid_t uuid = p_uuid_list->p_uuids[i];
+
+ // Find encoded uuid size.
+ err_code = sd_ble_uuid_encode(&uuid, &encoded_size, NULL);
+ VERIFY_SUCCESS(err_code);
+
+ // Check size.
+ if (encoded_size == uuid_size)
+ {
+ uint8_t heading_bytes = (is_heading_written) ? 0 : AD_DATA_OFFSET;
+
+ // Check for buffer overflow
+ if (((*p_offset) + encoded_size + heading_bytes) > max_size)
+ {
+ return NRF_ERROR_DATA_SIZE;
+ }
+
+ if (!is_heading_written)
+ {
+ // Write AD structure heading.
+ *p_offset += AD_LENGTH_FIELD_SIZE;
+ p_encoded_data[*p_offset] = adv_type;
+ *p_offset += AD_TYPE_FIELD_SIZE;
+ is_heading_written = true;
+ }
+
+ // Write UUID.
+ err_code = sd_ble_uuid_encode(&uuid, &encoded_size, &p_encoded_data[*p_offset]);
+ VERIFY_SUCCESS(err_code);
+ *p_offset += encoded_size;
+ }
+ }
+
+ if (is_heading_written)
+ {
+ // Write length.
+ length = (*p_offset) - (start_pos + AD_LENGTH_FIELD_SIZE);
+ // There is only 1 byte intended to encode length
+ if (length > 0x00FF)
+ {
+ return NRF_ERROR_DATA_SIZE;
+ }
+ p_encoded_data[start_pos] = (uint8_t)length;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+static ret_code_t uuid_list_encode(const ble_advdata_uuid_list_t * p_uuid_list,
+ uint8_t adv_type_16,
+ uint8_t adv_type_128,
+ uint8_t * p_encoded_data,
+ uint16_t * p_offset,
+ uint16_t max_size)
+{
+ ret_code_t err_code;
+
+ // Encode 16 bit UUIDs.
+ err_code = uuid_list_sized_encode(p_uuid_list,
+ adv_type_16,
+ sizeof(uint16_le_t),
+ p_encoded_data,
+ p_offset,
+ max_size);
+ VERIFY_SUCCESS(err_code);
+
+ // Encode 128 bit UUIDs.
+ err_code = uuid_list_sized_encode(p_uuid_list,
+ adv_type_128,
+ sizeof(ble_uuid128_t),
+ p_encoded_data,
+ p_offset,
+ max_size);
+ VERIFY_SUCCESS(err_code);
+
+ return NRF_SUCCESS;
+}
+
+
+static ret_code_t conn_int_check(const ble_advdata_conn_int_t *p_conn_int)
+{
+ // Check Minimum Connection Interval.
+ if ((p_conn_int->min_conn_interval < 0x0006) ||
+ (
+ (p_conn_int->min_conn_interval > 0x0c80) &&
+ (p_conn_int->min_conn_interval != 0xffff)
+ )
+ )
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ // Check Maximum Connection Interval.
+ if ((p_conn_int->max_conn_interval < 0x0006) ||
+ (
+ (p_conn_int->max_conn_interval > 0x0c80) &&
+ (p_conn_int->max_conn_interval != 0xffff)
+ )
+ )
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ // Make sure Minimum Connection Interval is not bigger than Maximum Connection Interval.
+ if ((p_conn_int->min_conn_interval != 0xffff) &&
+ (p_conn_int->max_conn_interval != 0xffff) &&
+ (p_conn_int->min_conn_interval > p_conn_int->max_conn_interval)
+ )
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+static ret_code_t conn_int_encode(const ble_advdata_conn_int_t * p_conn_int,
+ uint8_t * p_encoded_data,
+ uint16_t * p_offset,
+ uint16_t max_size)
+{
+ ret_code_t err_code;
+
+ // Check for buffer overflow.
+ if (((*p_offset) + AD_TYPE_CONN_INT_SIZE) > max_size)
+ {
+ return NRF_ERROR_DATA_SIZE;
+ }
+
+ // Check parameters.
+ err_code = conn_int_check(p_conn_int);
+ VERIFY_SUCCESS(err_code);
+
+ // Encode Length and AD Type.
+ p_encoded_data[*p_offset] = (uint8_t)(AD_TYPE_FIELD_SIZE + AD_TYPE_CONN_INT_DATA_SIZE);
+ *p_offset += AD_LENGTH_FIELD_SIZE;
+ p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE;
+ *p_offset += AD_TYPE_FIELD_SIZE;
+
+ // Encode Minimum and Maximum Connection Intervals.
+ *p_offset += uint16_encode(p_conn_int->min_conn_interval, &p_encoded_data[*p_offset]);
+ *p_offset += uint16_encode(p_conn_int->max_conn_interval, &p_encoded_data[*p_offset]);
+
+ return NRF_SUCCESS;
+}
+
+
+static ret_code_t manuf_specific_data_encode(const ble_advdata_manuf_data_t * p_manuf_sp_data,
+ uint8_t * p_encoded_data,
+ uint16_t * p_offset,
+ uint16_t max_size)
+{
+ uint32_t data_size = AD_TYPE_MANUF_SPEC_DATA_ID_SIZE + p_manuf_sp_data->data.size;
+
+ // Check for buffer overflow.
+ if (((*p_offset) + AD_DATA_OFFSET + data_size) > max_size)
+ {
+ return NRF_ERROR_DATA_SIZE;
+ }
+
+ // There is only 1 byte intended to encode length which is (data_size + AD_TYPE_FIELD_SIZE)
+ if (data_size > (0x00FF - AD_TYPE_FIELD_SIZE))
+ {
+ return NRF_ERROR_DATA_SIZE;
+ }
+
+ // Encode Length and AD Type.
+ p_encoded_data[*p_offset] = (uint8_t)(AD_TYPE_FIELD_SIZE + data_size);
+ *p_offset += AD_LENGTH_FIELD_SIZE;
+ p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA;
+ *p_offset += AD_TYPE_FIELD_SIZE;
+
+ // Encode Company Identifier.
+ *p_offset += uint16_encode(p_manuf_sp_data->company_identifier, &p_encoded_data[*p_offset]);
+
+ // Encode additional manufacturer specific data.
+ if (p_manuf_sp_data->data.size > 0)
+ {
+ if (p_manuf_sp_data->data.p_data == NULL)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ memcpy(&p_encoded_data[*p_offset], p_manuf_sp_data->data.p_data, p_manuf_sp_data->data.size);
+ *p_offset += p_manuf_sp_data->data.size;
+ }
+
+ return NRF_SUCCESS;
+}
+
+// Implemented only for 16-bit UUIDs
+static ret_code_t service_data_encode(const ble_advdata_t * p_advdata,
+ uint8_t * p_encoded_data,
+ uint16_t * p_offset,
+ uint16_t max_size)
+{
+ uint8_t i;
+
+ // Check parameter consistency.
+ if (p_advdata->p_service_data_array == NULL)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ for (i = 0; i < p_advdata->service_data_count; i++)
+ {
+ ble_advdata_service_data_t * p_service_data;
+ uint32_t data_size;
+
+ p_service_data = &p_advdata->p_service_data_array[i];
+ // For now implemented only for 16-bit UUIDs
+ data_size = AD_TYPE_SERV_DATA_16BIT_UUID_SIZE + p_service_data->data.size;
+
+ // There is only 1 byte intended to encode length which is (data_size + AD_TYPE_FIELD_SIZE)
+ if (data_size > (0x00FF - AD_TYPE_FIELD_SIZE))
+ {
+ return NRF_ERROR_DATA_SIZE;
+ }
+
+ // Encode Length and AD Type.
+ p_encoded_data[*p_offset] = (uint8_t)(AD_TYPE_FIELD_SIZE + data_size);
+ *p_offset += AD_LENGTH_FIELD_SIZE;
+ p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_SERVICE_DATA;
+ *p_offset += AD_TYPE_FIELD_SIZE;
+
+ // Encode service 16-bit UUID.
+ *p_offset += uint16_encode(p_service_data->service_uuid, &p_encoded_data[*p_offset]);
+
+ // Encode additional service data.
+ if (p_service_data->data.size > 0)
+ {
+ if (p_service_data->data.p_data == NULL)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ memcpy(&p_encoded_data[*p_offset], p_service_data->data.p_data, p_service_data->data.size);
+ *p_offset += p_service_data->data.size;
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+ret_code_t ble_advdata_encode(ble_advdata_t const * const p_advdata,
+ uint8_t * const p_encoded_data,
+ uint16_t * const p_len)
+{
+ ret_code_t err_code = NRF_SUCCESS;
+ uint16_t max_size = *p_len;
+ *p_len = 0;
+
+ // Encode LE Bluetooth Device Address
+ if (p_advdata->include_ble_device_addr)
+ {
+ err_code = ble_device_addr_encode(p_encoded_data, p_len, max_size);
+ VERIFY_SUCCESS(err_code);
+ }
+
+ // Encode appearance.
+ if (p_advdata->include_appearance)
+ {
+ err_code = appearance_encode(p_encoded_data, p_len, max_size);
+ VERIFY_SUCCESS(err_code);
+ }
+
+ //Encode Flags
+ if (p_advdata->flags != 0 )
+ {
+ err_code = flags_encode(p_advdata->flags, p_encoded_data, p_len, max_size);
+ VERIFY_SUCCESS(err_code);
+ }
+
+ // Encode TX power level.
+ if (p_advdata->p_tx_power_level != NULL)
+ {
+ err_code = tx_power_level_encode(*p_advdata->p_tx_power_level,
+ p_encoded_data,
+ p_len,
+ max_size);
+ VERIFY_SUCCESS(err_code);
+ }
+
+ // Encode 'more available' uuid list.
+ if (p_advdata->uuids_more_available.uuid_cnt > 0)
+ {
+ err_code = uuid_list_encode(&p_advdata->uuids_more_available,
+ BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE,
+ BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE,
+ p_encoded_data,
+ p_len,
+ max_size);
+ VERIFY_SUCCESS(err_code);
+ }
+
+ // Encode 'complete' uuid list.
+ if (p_advdata->uuids_complete.uuid_cnt > 0)
+ {
+ err_code = uuid_list_encode(&p_advdata->uuids_complete,
+ BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE,
+ BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE,
+ p_encoded_data,
+ p_len,
+ max_size);
+ VERIFY_SUCCESS(err_code);
+ }
+
+ // Encode 'solicited service' uuid list.
+ if (p_advdata->uuids_solicited.uuid_cnt > 0)
+ {
+ err_code = uuid_list_encode(&p_advdata->uuids_solicited,
+ BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT,
+ BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT,
+ p_encoded_data,
+ p_len,
+ max_size);
+ VERIFY_SUCCESS(err_code);
+ }
+
+ // Encode Slave Connection Interval Range.
+ if (p_advdata->p_slave_conn_int != NULL)
+ {
+ err_code = conn_int_encode(p_advdata->p_slave_conn_int, p_encoded_data, p_len, max_size);
+ VERIFY_SUCCESS(err_code);
+ }
+
+ // Encode Manufacturer Specific Data.
+ if (p_advdata->p_manuf_specific_data != NULL)
+ {
+ err_code = manuf_specific_data_encode(p_advdata->p_manuf_specific_data,
+ p_encoded_data,
+ p_len,
+ max_size);
+ VERIFY_SUCCESS(err_code);
+ }
+
+ // Encode Service Data.
+ if (p_advdata->service_data_count > 0)
+ {
+ err_code = service_data_encode(p_advdata, p_encoded_data, p_len, max_size);
+ VERIFY_SUCCESS(err_code);
+ }
+
+ // Encode name. WARNING: it is encoded last on purpose since too long device name is truncated.
+ if (p_advdata->name_type != BLE_ADVDATA_NO_NAME)
+ {
+ err_code = name_encode(p_advdata, p_encoded_data, p_len, max_size);
+ VERIFY_SUCCESS(err_code);
+ }
+
+ return err_code;
+}
+
+
+uint16_t ble_advdata_search(uint8_t const * p_encoded_data,
+ uint16_t data_len,
+ uint16_t * p_offset,
+ uint8_t ad_type)
+{
+ if ((p_encoded_data == NULL) || (p_offset == NULL))
+ {
+ return 0;
+ }
+
+ uint16_t i = 0;
+
+ while (((i < *p_offset) || (p_encoded_data[i + 1] != ad_type)) && (i < data_len))
+ {
+ // Jump to next data.
+ i += (p_encoded_data[i] + 1);
+ }
+
+ if (i >= data_len)
+ {
+ return 0;
+ }
+ else
+ {
+ *p_offset = i + 2;
+ return (p_encoded_data[i] - 1);
+ }
+}
+
+
+uint8_t * ble_advdata_parse(uint8_t * p_encoded_data,
+ uint16_t data_len,
+ uint8_t ad_type)
+{
+ uint16_t offset = 0;
+ uint16_t len = ble_advdata_search(p_encoded_data, data_len, &offset, ad_type);
+
+ if (len == 0)
+ {
+ return NULL;
+ }
+ else
+ {
+ return &p_encoded_data[offset];
+ }
+}
+
+
+bool ble_advdata_name_find(uint8_t const * p_encoded_data,
+ uint16_t data_len,
+ char const * p_target_name)
+{
+ uint16_t parsed_name_len;
+ uint8_t const * p_parsed_name;
+ uint16_t data_offset = 0;
+
+ if (p_target_name == NULL)
+ {
+ return false;
+ }
+
+
+ parsed_name_len = ble_advdata_search(p_encoded_data,
+ data_len,
+ &data_offset,
+ BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME);
+
+ p_parsed_name = &p_encoded_data[data_offset];
+
+ if ( (data_offset != 0)
+ && (parsed_name_len != 0)
+ && (strlen(p_target_name) == parsed_name_len)
+ && (memcmp(p_target_name, p_parsed_name, parsed_name_len) == 0))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+
+bool ble_advdata_short_name_find(uint8_t const * p_encoded_data,
+ uint16_t data_len,
+ char const * p_target_name,
+ uint8_t const short_name_min_len)
+{
+ uint16_t parsed_name_len;
+ uint8_t const * p_parsed_name;
+ uint16_t data_offset = 0;
+
+ if (p_target_name == NULL)
+ {
+ return false;
+ }
+
+ parsed_name_len = ble_advdata_search(p_encoded_data,
+ data_len,
+ &data_offset,
+ BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME);
+
+ p_parsed_name = &p_encoded_data[data_offset];
+
+ if ( (data_offset != 0)
+ && (parsed_name_len != 0)
+ && (parsed_name_len >= short_name_min_len)
+ && (parsed_name_len < strlen(p_target_name))
+ && (memcmp(p_target_name, p_parsed_name, parsed_name_len) == 0))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+
+bool ble_advdata_uuid_find(uint8_t const * p_encoded_data,
+ uint16_t data_len,
+ ble_uuid_t const * p_target_uuid)
+{
+
+ ret_code_t err_code;
+ uint16_t data_offset = 0;
+ uint8_t raw_uuid_len = UUID128_SIZE;
+ uint8_t const * p_parsed_uuid;
+ uint16_t parsed_uuid_len = data_len;
+ uint8_t raw_uuid[UUID128_SIZE];
+ uint8_t ad_types[N_AD_TYPES];
+
+ err_code = sd_ble_uuid_encode(p_target_uuid, &raw_uuid_len, raw_uuid);
+
+ if ((p_encoded_data == NULL) || (err_code != NRF_SUCCESS))
+ {
+ // Invalid p_encoded_data or p_target_uuid.
+ return false;
+ }
+
+ switch (raw_uuid_len)
+ {
+ case UUID16_SIZE:
+ ad_types[0] = BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE;
+ ad_types[1] = BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE;
+ break;
+
+ case UUID32_SIZE:
+ // Not currently supported by sd_ble_uuid_encode().
+ ad_types[0] = BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_COMPLETE;
+ ad_types[1] = BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE;
+ break;
+
+ case UUID128_SIZE:
+ ad_types[0] = BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE;
+ ad_types[1] = BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE;
+ break;
+
+ default:
+ return false;
+ }
+
+ for (uint8_t i = 0; (i < N_AD_TYPES) && (data_offset == 0); i++)
+ {
+ parsed_uuid_len = ble_advdata_search(p_encoded_data, data_len, &data_offset, ad_types[i]);
+ }
+
+ if (data_offset == 0)
+ {
+ // Could not find any relevant UUIDs in the encoded data.
+ return false;
+ }
+
+ p_parsed_uuid = &p_encoded_data[data_offset];
+
+ // Verify if any UUID matches the given UUID.
+ for (uint16_t list_offset = 0; list_offset < parsed_uuid_len; list_offset += raw_uuid_len)
+ {
+ if (memcmp(&p_parsed_uuid[list_offset], raw_uuid, raw_uuid_len) == 0)
+ {
+ return true;
+ }
+ }
+
+ // Could not find the UUID among the encoded data.
+ return false;
+}
+
+
+bool ble_advdata_appearance_find(uint8_t const * p_encoded_data,
+ uint16_t data_len,
+ uint16_t const * p_target_appearance)
+{
+ uint16_t data_offset = 0;
+ uint8_t appearance_len;
+ uint16_t decoded_appearance;
+
+ appearance_len = ble_advdata_search(p_encoded_data, data_len, &data_offset, BLE_GAP_AD_TYPE_APPEARANCE);
+
+ if ( (data_offset == 0)
+ || (p_target_appearance == NULL)
+ || (appearance_len == 0))
+ {
+ // Could not find any Appearance in the encoded data, or invalid p_target_appearance.
+ return false;
+ }
+
+ decoded_appearance = uint16_decode(&p_encoded_data[data_offset]);
+
+ if (decoded_appearance == *p_target_appearance)
+ {
+ return true;
+ }
+
+ // Could not find the appearance among the encoded data.
+ return false;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_advdata.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_advdata.h
new file mode 100644
index 0000000..ad15efc
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_advdata.h
@@ -0,0 +1,326 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_sdk_lib_advdata Advertising and Scan Response Data Encoder
+ * @{
+ * @ingroup ble_sdk_lib
+ * @brief Functions for encoding data in the Advertising and Scan Response Data format,
+ * and for passing the data to the stack.
+ */
+
+#ifndef BLE_ADVDATA_H__
+#define BLE_ADVDATA_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include "ble.h"
+#include "sdk_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define AD_LENGTH_FIELD_SIZE 1UL /**< Advertising Data and Scan Response format contains 1 octet for the length. */
+#define AD_TYPE_FIELD_SIZE 1UL /**< Advertising Data and Scan Response format contains 1 octet for the AD type. */
+#define AD_DATA_OFFSET (AD_LENGTH_FIELD_SIZE + AD_TYPE_FIELD_SIZE) /**< Offset for the AD data field of the Advertising Data and Scan Response format. */
+
+#define AD_TYPE_BLE_DEVICE_ADDR_TYPE_SIZE 1UL /**< Data size (in octets) of the Address type of the LE Bluetooth Device Address AD type. */
+#define AD_TYPE_BLE_DEVICE_ADDR_DATA_SIZE (BLE_GAP_ADDR_LEN + \
+ AD_TYPE_BLE_DEVICE_ADDR_TYPE_SIZE) /**< Data size (in octets) of the LE Bluetooth Device Address AD type. */
+#define AD_TYPE_BLE_DEVICE_ADDR_SIZE (AD_DATA_OFFSET + \
+ AD_TYPE_BLE_DEVICE_ADDR_DATA_SIZE) /**< Size (in octets) of the LE Bluetooth Device Address AD type. */
+#define AD_TYPE_APPEARANCE_DATA_SIZE 2UL /**< Data size (in octets) of the Appearance AD type. */
+#define AD_TYPE_APPEARANCE_SIZE (AD_DATA_OFFSET + \
+ AD_TYPE_APPEARANCE_DATA_SIZE) /**< Size (in octets) of the Appearance AD type. */
+#define AD_TYPE_FLAGS_DATA_SIZE 1UL /**< Data size (in octets) of the Flags AD type. */
+#define AD_TYPE_FLAGS_SIZE (AD_DATA_OFFSET + \
+ AD_TYPE_FLAGS_DATA_SIZE) /**< Size (in octets) of the Flags AD type. */
+#define AD_TYPE_TX_POWER_LEVEL_DATA_SIZE 1UL /**< Data size (in octets) of the TX Power Level AD type. */
+#define AD_TYPE_TX_POWER_LEVEL_SIZE (AD_DATA_OFFSET + \
+ AD_TYPE_TX_POWER_LEVEL_DATA_SIZE) /**< Size (in octets) of the TX Power Level AD type. */
+#define AD_TYPE_CONN_INT_DATA_SIZE 4UL /**< Data size (in octets) of the Slave Connection Interval Range AD type. */
+#define AD_TYPE_CONN_INT_SIZE (AD_DATA_OFFSET + \
+ AD_TYPE_CONN_INT_DATA_SIZE) /**< Data size (in octets) of the Slave Connection Interval Range AD type. */
+#define AD_TYPE_MANUF_SPEC_DATA_ID_SIZE 2UL /**< Size (in octets) of the Company Identifier Code, which is a part of the Manufacturer Specific Data AD type. */
+#define AD_TYPE_SERV_DATA_16BIT_UUID_SIZE 2UL /**< Size (in octets) of the 16-bit UUID, which is a part of the Service Data AD type. */
+
+#define BLE_ADV_DATA_MATCH_FULL_NAME 0xff
+
+
+/**@brief Security Manager TK value. */
+typedef struct
+{
+ uint8_t tk[BLE_GAP_SEC_KEY_LEN]; /**< Array containing TK value in little-endian format. */
+} ble_advdata_tk_value_t;
+
+/**@brief Advertising data LE Role types. This enumeration contains the options available for the LE role inside
+ * the advertising data. */
+typedef enum
+{
+ BLE_ADVDATA_ROLE_NOT_PRESENT = 0, /**< LE Role AD structure not present. */
+ BLE_ADVDATA_ROLE_ONLY_PERIPH, /**< Only Peripheral Role supported. */
+ BLE_ADVDATA_ROLE_ONLY_CENTRAL, /**< Only Central Role supported. */
+ BLE_ADVDATA_ROLE_BOTH_PERIPH_PREFERRED, /**< Peripheral and Central Role supported. Peripheral Role preferred for connection establishment. */
+ BLE_ADVDATA_ROLE_BOTH_CENTRAL_PREFERRED /**< Peripheral and Central Role supported. Central Role preferred for connection establishment */
+} ble_advdata_le_role_t;
+
+/**@brief Advertising data name type. This enumeration contains the options available for the device name inside
+ * the advertising data. */
+typedef enum
+{
+ BLE_ADVDATA_NO_NAME, /**< Include no device name in advertising data. */
+ BLE_ADVDATA_SHORT_NAME, /**< Include short device name in advertising data. */
+ BLE_ADVDATA_FULL_NAME /**< Include full device name in advertising data. */
+} ble_advdata_name_type_t;
+
+/**@brief UUID list type. */
+typedef struct
+{
+ uint16_t uuid_cnt; /**< Number of UUID entries. */
+ ble_uuid_t * p_uuids; /**< Pointer to UUID array entries. */
+} ble_advdata_uuid_list_t;
+
+/**@brief Connection interval range structure. */
+typedef struct
+{
+ uint16_t min_conn_interval; /**< Minimum connection interval, in units of 1.25 ms, range 6 to 3200 (7.5 ms to 4 s). */
+ uint16_t max_conn_interval; /**< Maximum connection interval, in units of 1.25 ms, range 6 to 3200 (7.5 ms to 4 s). The value 0xFFFF indicates no specific maximum. */
+} ble_advdata_conn_int_t;
+
+/**@brief Manufacturer specific data structure. */
+typedef struct
+{
+ uint16_t company_identifier; /**< Company identifier code. */
+ uint8_array_t data; /**< Additional manufacturer specific data. */
+} ble_advdata_manuf_data_t;
+
+/**@brief Service data structure. */
+typedef struct
+{
+ uint16_t service_uuid; /**< Service UUID. */
+ uint8_array_t data; /**< Additional service data. */
+} ble_advdata_service_data_t;
+
+/**@brief Advertising data structure. This structure contains all options and data needed for encoding and
+ * setting the advertising data. */
+typedef struct
+{
+ ble_advdata_name_type_t name_type; /**< Type of device name. */
+ uint8_t short_name_len; /**< Length of short device name (if short type is specified). */
+ bool include_appearance; /**< Determines if Appearance shall be included. */
+ uint8_t flags; /**< Advertising data Flags field. */
+ int8_t * p_tx_power_level; /**< TX Power Level field. */
+ ble_advdata_uuid_list_t uuids_more_available; /**< List of UUIDs in the 'More Available' list. */
+ ble_advdata_uuid_list_t uuids_complete; /**< List of UUIDs in the 'Complete' list. */
+ ble_advdata_uuid_list_t uuids_solicited; /**< List of solicited UUIDs. */
+ ble_advdata_conn_int_t * p_slave_conn_int; /**< Slave Connection Interval Range. */
+ ble_advdata_manuf_data_t * p_manuf_specific_data; /**< Manufacturer specific data. */
+ ble_advdata_service_data_t * p_service_data_array; /**< Array of Service data structures. */
+ uint8_t service_data_count; /**< Number of Service data structures. */
+ bool include_ble_device_addr; /**< Determines if LE Bluetooth Device Address shall be included. */
+ ble_advdata_le_role_t le_role; /**< LE Role field. Included when different from @ref BLE_ADVDATA_ROLE_NOT_PRESENT. @warning This field can be used only for NFC. For BLE advertising, set it to NULL. */
+ ble_advdata_tk_value_t * p_tk_value; /**< Security Manager TK value field. Included when different from NULL. @warning This field can be used only for NFC. For BLE advertising, set it to NULL.*/
+ uint8_t * p_sec_mgr_oob_flags; /**< Security Manager Out Of Band Flags field. Included when different from NULL. @warning This field can be used only for NFC. For BLE advertising, set it to NULL.*/
+ ble_gap_lesc_oob_data_t * p_lesc_data; /**< LE Secure Connections OOB data. Included when different from NULL. @warning This field can be used only for NFC. For BLE advertising, set it to NULL.*/
+} ble_advdata_t;
+
+/**@brief Function for encoding data in the Advertising and Scan Response data format (AD structures).
+ *
+ * @details This function encodes data into the Advertising and Scan Response data format
+ * (AD structures) based on the fields in the supplied structures. This function can be
+ * used to create a payload of Advertising packet or Scan Response packet, or a payload of
+ * NFC message intended for initiating the Out-of-Band pairing.
+ *
+ * @param[in] p_advdata Pointer to the structure for specifying the content of encoded data.
+ * @param[out] p_encoded_data Pointer to the buffer where encoded data will be returned.
+ * @param[in,out] p_len \c in: Size of \p p_encoded_data buffer.
+ * \c out: Length of encoded data.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_INVALID_PARAM If the operation failed because a wrong parameter was provided in
+ * \p p_advdata.
+ * @retval NRF_ERROR_DATA_SIZE If the operation failed because not all the requested data could
+ * fit into the provided buffer or some encoded AD structure is too
+ * long and its length cannot be encoded with one octet.
+ *
+ * @warning This API may override the application's request to use the long name and use a short name
+ * instead. This truncation will occur in case the long name does not fit the provided buffer size.
+ * The application can specify a preferred short name length if truncation is required.
+ * For example, if the complete device name is ABCD_HRMonitor, the application can specify the short name
+ * length to be 8, so that the short device name appears as ABCD_HRM instead of ABCD_HRMo or ABCD_HRMoni
+ * if the available size for the short name is 9 or 12 respectively, to have a more appropriate short name.
+ * However, it should be noted that this is just a preference that the application can specify, and
+ * if the preference is too large to fit in the provided buffer, the name can be truncated further.
+ */
+ret_code_t ble_advdata_encode(ble_advdata_t const * const p_advdata,
+ uint8_t * const p_encoded_data,
+ uint16_t * const p_len);
+
+
+/**@brief Function for searching encoded Advertising or Scan Response data for specific data types.
+ *
+ * @details This function searches through encoded data e.g. the data produced by
+ * @ref ble_advdata_encode, or the data found in Advertising reports
+ * (@ref BLE_GAP_EVT_ADV_REPORT), and gives the offset of the data within the data buffer.
+ * The data with type \p ad_type can be found at p_encoded_data[*p_offset] after calling
+ * the function. This function can iterate through multiple instances of data of one
+ * type by calling it again with the offset provided by the previous call.
+ *
+ * Example code for finding multiple instances of one type of data:
+ * offset = 0;
+ * ble_advdata_search(&data, len, &offset, AD_TYPE);
+ * first_instance_of_data = data[offset];
+ * ble_advdata_search(&data, len, &offset, AD_TYPE);
+ * second_instance_of_data = data[offset];
+ *
+ * @param[in] p_encoded_data The data buffer containing the encoded Advertising data.
+ * @param[in] data_len The length of the data buffer \p p_encoded_data.
+ * @param[inout] p_offset \c in: The offset to start searching from.
+ * \c out: The offset the data type can be found at.
+ * This value is not changed if the call returns 0.
+ * @param[in] ad_type The type of data to search for.
+ *
+ * @return The length of the found data, or 0 if no data was found with the the type \p ad_type,
+ * or if \p p_encoded_data or \p p_offset were NULL.
+ */
+uint16_t ble_advdata_search(uint8_t const * p_encoded_data,
+ uint16_t data_len,
+ uint16_t * p_offset,
+ uint8_t ad_type);
+
+/**@brief Function for getting specific data from encoded Advertising or Scan Response data.
+ *
+ * @details This function searches through encoded data e.g. the data produced by
+ * @ref ble_advdata_encode, or the data found in Advertising reports
+ * (@ref BLE_GAP_EVT_ADV_REPORT), and returns a pointer directly to the data within the
+ * data buffer.
+ *
+ * Example code:
+ * ad_type_data = ble_advdata_parse(&data, len, AD_TYPE);
+ *
+ * @param[in] p_encoded_data Data buffer containing the encoded Advertising data.
+ * @param[in] data_len Length of the data buffer \p p_encoded_data.
+ * @param[in] ad_type Type of data to search for.
+ *
+ * @return Pointer to the found data, or NULL if no data was found with the type \p ad_type,
+ * or if \p p_encoded_data or \p p_data_len were NULL.
+ */
+uint8_t * ble_advdata_parse(uint8_t * p_encoded_data,
+ uint16_t data_len,
+ uint8_t ad_type);
+
+
+/**@brief Function for searching through encoded Advertising data for a complete local name.
+ *
+ * @param[in] p_encoded_data Data buffer containing the encoded Advertising data.
+ * @param[in] data_len Length of the data buffer \p p_encoded_data.
+ * @param[in] p_target_name Name to search for.
+ *
+ * @retval true If \p p_target_name was found among \p p_encoded_data, as a complete local name.
+ * @retval false If \p p_target_name was not found among \p p_encoded_data, or if \p p_encoded_data
+ * or \p p_target_name was NULL.
+ */
+bool ble_advdata_name_find(uint8_t const * p_encoded_data,
+ uint16_t data_len,
+ char const * p_target_name);
+
+
+/**@brief Function for searching through encoded Advertising data for a device shortened name.
+ *
+ * @param[in] p_encoded_data Data buffer containing the encoded Advertising data.
+ * @param[in] data_len Length of the data buffer \p p_encoded_data.
+ * @param[in] p_target_name Name to search for.
+ * @param[in] short_name_min_len Minimum length of the shortened name.
+ * For example, if the advertising data has a shortened name 'No' and this parameter is
+ * set to 4 with a target_name set to Nordic_XXX it will return false, but if
+ * the shortened name in the advertising data is 'Nord', it will return true.
+ * @note: If the shortened name in the Advertising data has the same length as the target name,
+ * this function will return false, since this means that the complete name is actually
+ * longer, thus different than the target name.
+ *
+ * @retval true If \p p_target_name was found among \p p_encoded_data, as short local name.
+ * @retval false If \p p_target_name was not found among \p p_encoded_data, or if \p p_encoded_data
+ * or \p p_target_name was NULL.
+ */
+bool ble_advdata_short_name_find(uint8_t const * p_encoded_data,
+ uint16_t data_len,
+ char const * p_target_name,
+ uint8_t const short_name_min_len);
+
+/**@brief Function for searching through encoded Advertising data for a UUID (16-bit or 128-bit).
+ *
+ * @param[in] p_encoded_data Data buffer containing the encoded Advertising data.
+ * @param[in] data_len Length of the data buffer \p p_encoded_data.
+ * @param[in] p_target_uuid UUID to search for.
+ *
+ * @retval true If \p p_target_uuid was found among \p p_encoded_data.
+ * @retval false If \p p_target_uuid was not found among \p p_encoded_data, or if \p p_encoded_data
+ * or \p p_target_uuid was NULL.
+ */
+bool ble_advdata_uuid_find(uint8_t const * p_encoded_data,
+ uint16_t data_len,
+ ble_uuid_t const * p_target_uuid);
+
+
+/**@brief Function for searching through encoded Advertising data for an appearance.
+ *
+ * @param[in] p_encoded_data Data buffer containing the encoded Advertising data.
+ * @param[in] data_len Length of the data buffer \p p_encoded_data.
+ * @param[in] p_target_appearance Appearance to search for.
+ *
+ * @retval true If \p p_target_appearance was found among \p p_encoded_data.
+ * @retval false If \p p_target_appearance was not found among \p p_encoded_data, or if \p p_encoded_data
+ * or \p p_target_appearance was NULL.
+ */
+bool ble_advdata_appearance_find(uint8_t const * p_encoded_data,
+ uint16_t data_len,
+ uint16_t const * p_target_appearance);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_ADVDATA_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_conn_params.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_conn_params.c
new file mode 100644
index 0000000..4cb78f4
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_conn_params.c
@@ -0,0 +1,572 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(NRF_BLE_CONN_PARAMS)
+#include <stdlib.h>
+#include "nrf.h"
+#include "sdk_errors.h"
+#include "ble_hci.h"
+#include "ble_err.h"
+#include "ble_conn_params.h"
+#include "ble_srv_common.h"
+#include "ble_conn_state.h"
+#include "nrf_sdh_ble.h"
+#include "app_timer.h"
+#include "app_util.h"
+
+
+#define NRF_BLE_CONN_PARAMS_INSTANCE_COUNT NRF_SDH_BLE_PERIPHERAL_LINK_COUNT //!< The number of @ref ble_conn_params_instance_t instances kept by the conn_params module.
+
+#if (NRF_BLE_CONN_PARAMS_INSTANCE_COUNT < 1)
+#error Invalid NRF_SDH_BLE_PERIPHERAL_LINK_COUNT value. Set it in SDK config (nrf_sdh_ble).
+#endif
+
+/** @brief Each peripheral link has such an instance associated with it.
+ */
+typedef struct
+{
+ uint16_t conn_handle; //!< The connection handle of this link. If this is @ref BLE_CONN_HANDLE_INVALID, the instance is free.
+ app_timer_id_t timer_id; //!< The ID of the timer associated with this link.
+ uint8_t update_count; //!< The number of times the connection parameters have been attempted negotiated on this link.
+ uint8_t params_ok; //!< Whether the current connection parameters on this link are acceptable according to the @p preferred_conn_params, and configured maximum deviations.
+ ble_gap_conn_params_t preferred_conn_params; //!< The desired connection parameters for this link.
+} ble_conn_params_instance_t;
+
+static app_timer_t m_timer_data[NRF_BLE_CONN_PARAMS_INSTANCE_COUNT] = {{{0}}}; //!< Data needed for timers.
+static ble_conn_params_instance_t m_conn_params_instances[NRF_BLE_CONN_PARAMS_INSTANCE_COUNT] = {{0}}; //!< Configuration data for each connection.
+static ble_conn_params_init_t m_conn_params_config; //!< Configuration as provided by the application during intialization.
+static ble_gap_conn_params_t m_preferred_conn_params; //!< The preferred connection parameters as specified during initialization.
+//lint -esym(551, m_preferred_conn_params) "Not accessed"
+
+
+/**@brief Function for retrieving the conn_params instance belonging to a conn_handle
+ *
+ * @params[in] conn_handle The connection handle to retrieve the instance of.
+ *
+ * @return A pointer to the instance, or NULL if no instance was found with that conn_handle.
+ */
+static ble_conn_params_instance_t * instance_get(uint16_t conn_handle)
+{
+ //lint -save -e681 "Loop not entered" when NRF_BLE_CONN_PARAMS_INSTANCE_COUNT is 0
+ for (uint32_t i = 0; i < NRF_BLE_CONN_PARAMS_INSTANCE_COUNT; i++)
+ {
+ if (m_conn_params_instances[i].conn_handle == conn_handle)
+ {
+ return &m_conn_params_instances[i];
+ }
+ }
+ //lint -restore
+ return NULL;
+}
+
+
+/**@brief Function for initializing an instance, and associating it with a conn_handle.
+ *
+ * @params[in] p_instance The instance to initialize and associate.
+ * @params[in] conn_handle The connection handle to associate with.
+ */
+static __INLINE void instance_claim(ble_conn_params_instance_t * p_instance, uint16_t conn_handle)
+{
+ p_instance->conn_handle = conn_handle;
+ p_instance->update_count = 0;
+ p_instance->preferred_conn_params = m_preferred_conn_params;
+}
+
+
+/**@brief Function for freeing an instance.
+ *
+ * @params[in] p_instance The instance to free.
+ */
+static __INLINE void instance_free(ble_conn_params_instance_t * p_instance)
+{
+ p_instance->conn_handle = BLE_CONN_HANDLE_INVALID;
+}
+
+
+/**@brief Function for validating a set of connection parameters against the preferred parameters.
+ *
+ * @param[in] p_preferred_conn_params The desired parameters.
+ * @param[in] p_actual_conn_params The parameters to validate.
+ * @param[in] max_slave_latency_err The amount of discrepancy in slave latency, in number of
+ * connection intervals, that will be accepted.
+ * @param[in] max_sup_timeout_err The amount of discrepancy in supervision timeout, in tens of
+ * milliseconds, that will be accepted.
+ *
+ * @return Whether the params in @p p_actual_conn_params are acceptable given the other parameters.
+ */
+static bool is_conn_params_ok(ble_gap_conn_params_t const * p_preferred_conn_params,
+ ble_gap_conn_params_t const * p_actual_conn_params,
+ uint16_t max_slave_latency_err,
+ uint16_t max_sup_timeout_err)
+{
+ uint32_t max_allowed_sl = p_preferred_conn_params->slave_latency + max_slave_latency_err;
+ uint32_t min_allowed_sl = p_preferred_conn_params->slave_latency
+ - MIN(max_slave_latency_err, p_preferred_conn_params->slave_latency);
+ uint32_t max_allowed_to = p_preferred_conn_params->conn_sup_timeout + max_sup_timeout_err;
+ uint32_t min_allowed_to = p_preferred_conn_params->conn_sup_timeout
+ - MIN(max_sup_timeout_err, p_preferred_conn_params->conn_sup_timeout);
+
+ // Check if interval is within the acceptable range.
+ // NOTE: Using max_conn_interval in the received event data because this contains
+ // the client's connection interval.
+ if ((p_actual_conn_params->max_conn_interval < p_preferred_conn_params->min_conn_interval)
+ || (p_actual_conn_params->max_conn_interval > p_preferred_conn_params->max_conn_interval))
+ {
+ return false;
+ }
+
+ // Check if slave latency is within the acceptable deviation.
+ if ((p_actual_conn_params->slave_latency < min_allowed_sl)
+ || (p_actual_conn_params->slave_latency > max_allowed_sl))
+ {
+ return false;
+ }
+
+ // Check if supervision timeout is within the acceptable deviation.
+ if ((p_actual_conn_params->conn_sup_timeout < min_allowed_to)
+ || (p_actual_conn_params->conn_sup_timeout > max_allowed_to))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+
+static void send_error_evt(ret_code_t err_code)
+{
+ if (m_conn_params_config.error_handler != NULL)
+ {
+ m_conn_params_config.error_handler(err_code);
+ }
+}
+
+
+/**@brief Function for sending a conn_param_update request on-air, and handling errors.
+ *
+ * @param[in] conn_handle Connection to send request on.
+ * @param[in] p_new_conn_params Connection parameters to request.
+ *
+ * @return Whether the request was successfully sent.
+ */
+static bool send_update_request(uint16_t conn_handle, ble_gap_conn_params_t * p_new_conn_params)
+{
+ ret_code_t err_code;
+
+ err_code = sd_ble_gap_conn_param_update(conn_handle, p_new_conn_params);
+ if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_BUSY)) // NRF_ERROR_BUSY means another conn_param_update request is pending.
+ {
+ send_error_evt(err_code);
+ }
+
+ return (err_code == NRF_SUCCESS);
+}
+
+
+/**@brief Function called after conn_params_update_delay has happened. This is triggered by app_timer.
+ *
+ * @param[in] p_context Context identifying which connection this is for.
+ */
+static void update_timeout_handler(void * p_context)
+{
+ uint32_t conn_handle = (uint32_t)p_context;
+ ble_conn_params_instance_t * p_instance = instance_get(conn_handle);
+
+ if (p_instance != NULL)
+ {
+ // Check if we have reached the maximum number of attempts
+ if (p_instance->update_count < m_conn_params_config.max_conn_params_update_count)
+ {
+ bool update_sent = send_update_request(conn_handle, &p_instance->preferred_conn_params);
+ if (update_sent)
+ {
+ p_instance->update_count++;
+ }
+ }
+ else
+ {
+ p_instance->update_count = 0;
+
+ // Negotiation failed, disconnect automatically if this has been configured
+ if (m_conn_params_config.disconnect_on_fail)
+ {
+ ret_code_t err_code;
+
+ err_code = sd_ble_gap_disconnect(conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
+ if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_INVALID_STATE)) // NRF_ERROR_INVALID_STATE means disconnect is already in progress.
+ {
+ send_error_evt(err_code);
+ }
+ }
+
+ // Notify the application that the procedure has failed
+ if (m_conn_params_config.evt_handler != NULL)
+ {
+ ble_conn_params_evt_t evt;
+
+ evt.evt_type = BLE_CONN_PARAMS_EVT_FAILED;
+ evt.conn_handle = conn_handle;
+ m_conn_params_config.evt_handler(&evt);
+ }
+ }
+ }
+}
+
+
+ret_code_t ble_conn_params_init(const ble_conn_params_init_t * p_init)
+{
+ ret_code_t err_code;
+
+ VERIFY_PARAM_NOT_NULL(p_init);
+
+ m_conn_params_config = *p_init;
+ m_conn_params_config.p_conn_params = &m_preferred_conn_params;
+
+ if (p_init->p_conn_params != NULL)
+ {
+ // Set the connection params in stack.
+ err_code = sd_ble_gap_ppcp_set(p_init->p_conn_params);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ m_preferred_conn_params = *p_init->p_conn_params;
+ }
+ else
+ {
+ // Get the (default) connection params from stack.
+ err_code = sd_ble_gap_ppcp_get(&m_preferred_conn_params);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ //lint -save -e681 "Loop not entered" when NRF_BLE_CONN_PARAMS_INSTANCE_COUNT is 0
+ for (uint32_t i = 0; i < NRF_BLE_CONN_PARAMS_INSTANCE_COUNT; i++)
+ {
+ ble_conn_params_instance_t * p_instance = &m_conn_params_instances[i];
+
+ instance_free(p_instance);
+ p_instance->timer_id = &m_timer_data[i];
+
+ err_code = app_timer_create(&p_instance->timer_id,
+ APP_TIMER_MODE_SINGLE_SHOT,
+ update_timeout_handler);
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+ }
+ //lint -restore
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t ble_conn_params_stop(void)
+{
+ ret_code_t err_code;
+
+ //lint -save -e681 "Loop not entered" when NRF_BLE_CONN_PARAMS_INSTANCE_COUNT is 0
+ for (uint32_t i = 0; i < NRF_BLE_CONN_PARAMS_INSTANCE_COUNT; i++)
+ {
+ err_code = app_timer_stop(m_conn_params_instances[i].timer_id);
+ switch (err_code)
+ {
+ case NRF_SUCCESS:
+ /* do nothing */
+ break;
+
+ case NRF_ERROR_INVALID_STATE:
+ /* do nothing */
+ break;
+
+ case NRF_ERROR_NO_MEM:
+ return NRF_ERROR_BUSY;
+
+ case NRF_ERROR_INVALID_PARAM:
+ /* fallthrough */
+ default:
+ return NRF_ERROR_INTERNAL;
+ }
+ }
+ //lint -restore
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for taking appropriate action based on the current state of connection parameters.
+ *
+ * @param[in] conn_handle Connection to handle.
+ * @param[in] p_instance Configuration for the connection.
+ */
+static void conn_params_negotiation(uint16_t conn_handle, ble_conn_params_instance_t * p_instance)
+ {
+ // Start negotiation if the received connection parameters are not acceptable
+ if (!p_instance->params_ok)
+ {
+ ret_code_t err_code;
+ uint32_t timeout_ticks;
+
+ if (p_instance->update_count == 0)
+ {
+ // First connection parameter update
+ timeout_ticks = m_conn_params_config.first_conn_params_update_delay;
+ }
+ else
+ {
+ timeout_ticks = m_conn_params_config.next_conn_params_update_delay;
+ }
+
+ err_code = app_timer_start(p_instance->timer_id, timeout_ticks, (void *)(uint32_t)conn_handle);
+ if (err_code != NRF_SUCCESS)
+ {
+ send_error_evt(err_code);
+ }
+ }
+ else
+ {
+ p_instance->update_count = 0;
+
+ // Notify the application that the procedure has succeeded
+ if (m_conn_params_config.evt_handler != NULL)
+ {
+ ble_conn_params_evt_t evt;
+
+ evt.evt_type = BLE_CONN_PARAMS_EVT_SUCCEEDED;
+ evt.conn_handle = conn_handle;
+ m_conn_params_config.evt_handler(&evt);
+ }
+ }
+}
+
+
+/**@brief Function for handling a connection event from the SoftDevice.
+ *
+ * @param[in] p_ble_evt Event from the SoftDevice.
+ */
+static void on_connect(ble_evt_t const * p_ble_evt)
+{
+ uint8_t role = p_ble_evt->evt.gap_evt.params.connected.role;
+ uint16_t conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+
+ if (role != BLE_GAP_ROLE_PERIPH)
+ {
+ return;
+ }
+
+ ble_conn_params_instance_t * p_instance = instance_get(BLE_CONN_HANDLE_INVALID);
+
+ if (p_instance == NULL)
+ {
+ send_error_evt(NRF_ERROR_NO_MEM);
+ return;
+ }
+
+ instance_claim(p_instance, conn_handle);
+ p_instance->params_ok = is_conn_params_ok(&p_instance->preferred_conn_params,
+ &p_ble_evt->evt.gap_evt.params.connected.conn_params,
+ NRF_BLE_CONN_PARAMS_MAX_SLAVE_LATENCY_DEVIATION,
+ NRF_BLE_CONN_PARAMS_MAX_SUPERVISION_TIMEOUT_DEVIATION);
+
+ // Check if we shall handle negotiation on connect
+ if (m_conn_params_config.start_on_notify_cccd_handle == BLE_GATT_HANDLE_INVALID)
+ {
+ conn_params_negotiation(conn_handle, p_instance);
+ }
+}
+
+
+/**@brief Function for handling a disconnection event from the SoftDevice.
+ *
+ * @param[in] p_ble_evt Event from the SoftDevice.
+ */
+static void on_disconnect(ble_evt_t const * p_ble_evt)
+{
+ ret_code_t err_code;
+ uint16_t conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+ ble_conn_params_instance_t * p_instance = instance_get(conn_handle);
+
+ if (p_instance != NULL)
+ {
+ // Stop timer if running
+ err_code = app_timer_stop(p_instance->timer_id);
+ if (err_code != NRF_SUCCESS)
+ {
+ send_error_evt(err_code);
+ }
+
+ instance_free(p_instance);
+ }
+}
+
+
+/**@brief Function for handling a GATT write event from the SoftDevice.
+ *
+ * @details To provide the start_on_notify_cccd_handle functionality.
+ *
+ * @param[in] p_ble_evt Event from the SoftDevice.
+ */
+static void on_write(ble_evt_t const * p_ble_evt)
+{
+ ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+ // Check if this is the correct CCCD
+ if (
+ (p_evt_write->handle == m_conn_params_config.start_on_notify_cccd_handle)
+ &&
+ (p_evt_write->len == 2)
+ )
+ {
+ uint16_t conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+ ble_conn_params_instance_t * p_instance = instance_get(conn_handle);
+
+ if (p_instance != NULL)
+ {
+ // Check if this is a 'start notification'
+ if (ble_srv_is_notification_enabled(p_evt_write->data))
+ {
+ // Do connection parameter negotiation if necessary
+ conn_params_negotiation(conn_handle, p_instance);
+ }
+ else
+ {
+ ret_code_t err_code;
+
+ // Stop timer if running
+ err_code = app_timer_stop(p_instance->timer_id);
+ if (err_code != NRF_SUCCESS)
+ {
+ send_error_evt(err_code);
+ }
+ }
+ }
+ }
+}
+
+
+/**@brief Function for handling a connection parameter update event from the SoftDevice.
+ *
+ * @details This event means the peer central has changed the connection parameters or declined our
+ * request.
+ *
+ * @param[in] p_ble_evt Event from the SoftDevice.
+ */
+static void on_conn_params_update(ble_evt_t const * p_ble_evt)
+{
+ uint16_t conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+ ble_conn_params_instance_t * p_instance = instance_get(conn_handle);
+
+ if (p_instance != NULL)
+ {
+ p_instance->params_ok = is_conn_params_ok(
+ &p_instance->preferred_conn_params,
+ &p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params,
+ NRF_BLE_CONN_PARAMS_MAX_SLAVE_LATENCY_DEVIATION,
+ NRF_BLE_CONN_PARAMS_MAX_SUPERVISION_TIMEOUT_DEVIATION);
+
+ conn_params_negotiation(conn_handle, p_instance);
+ }
+}
+
+
+/**
+ * @brief Function for handling BLE events.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Context.
+ */
+static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ on_connect(p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnect(p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_WRITE:
+ on_write(p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_CONN_PARAM_UPDATE:
+ on_conn_params_update(p_ble_evt);
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+
+ret_code_t ble_conn_params_change_conn_params(uint16_t conn_handle,
+ ble_gap_conn_params_t * p_new_params)
+{
+ ret_code_t err_code = BLE_ERROR_INVALID_CONN_HANDLE;
+ ble_conn_params_instance_t * p_instance = instance_get(conn_handle);
+
+ if (p_new_params == NULL)
+ {
+ p_new_params = &m_preferred_conn_params;
+ }
+
+ if (p_instance != NULL)
+ {
+ // Send request to central.
+ err_code = sd_ble_gap_conn_param_update(conn_handle, p_new_params);
+ if (err_code == NRF_SUCCESS)
+ {
+ p_instance->params_ok = false;
+ p_instance->update_count = 1;
+ p_instance->preferred_conn_params = *p_new_params;
+ }
+ }
+
+ return err_code;
+}
+
+NRF_SDH_BLE_OBSERVER(m_ble_observer, BLE_CONN_PARAMS_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
+
+#endif //ENABLED
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_conn_params.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_conn_params.h
new file mode 100644
index 0000000..d76db72
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_conn_params.h
@@ -0,0 +1,156 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_conn_params Connection Parameters Negotiation
+ * @{
+ * @ingroup ble_sdk_lib
+ * @brief Module for initiating and executing a connection parameters negotiation procedure.
+ */
+
+#ifndef BLE_CONN_PARAMS_H__
+#define BLE_CONN_PARAMS_H__
+
+#include <stdint.h>
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "sdk_errors.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Connection Parameters Module event type. */
+typedef enum
+{
+ BLE_CONN_PARAMS_EVT_FAILED, //!< Negotiation procedure failed.
+ BLE_CONN_PARAMS_EVT_SUCCEEDED //!< Negotiation procedure succeeded.
+} ble_conn_params_evt_type_t;
+
+/**@brief Connection Parameters Module event. */
+typedef struct
+{
+ ble_conn_params_evt_type_t evt_type; //!< Type of event.
+ uint16_t conn_handle; //!< Connection the event refers to.
+} ble_conn_params_evt_t;
+
+/**@brief Connection Parameters Module event handler type. */
+typedef void (*ble_conn_params_evt_handler_t) (ble_conn_params_evt_t * p_evt);
+
+/**@brief Connection Parameters Module init structure. This contains all options and data needed for
+ * initialization of the connection parameters negotiation module. */
+typedef struct
+{
+ ble_gap_conn_params_t * p_conn_params; //!< Pointer to the connection parameters desired by the application. When calling ble_conn_params_init, if this parameter is set to NULL, the connection parameters will be fetched from host.
+ uint32_t first_conn_params_update_delay; //!< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (in number of timer ticks).
+ uint32_t next_conn_params_update_delay; //!< Time between each call to sd_ble_gap_conn_param_update after the first (in number of timer ticks). Recommended value 30 seconds as per BLUETOOTH SPECIFICATION Version 4.0.
+ uint8_t max_conn_params_update_count; //!< Number of attempts before giving up the negotiation.
+ uint16_t start_on_notify_cccd_handle; //!< If procedure is to be started when notification is started, set this to the handle of the corresponding CCCD. Set to BLE_GATT_HANDLE_INVALID if procedure is to be started on connect event.
+ bool disconnect_on_fail; //!< Set to TRUE if a failed connection parameters update shall cause an automatic disconnection, set to FALSE otherwise.
+ ble_conn_params_evt_handler_t evt_handler; //!< Event handler to be called for handling events in the Connection Parameters.
+ ble_srv_error_handler_t error_handler; //!< Function to be called in case of an error.
+} ble_conn_params_init_t;
+
+
+/**@brief Function for initializing the Connection Parameters module.
+ *
+ * @note If the negotiation procedure should be triggered when notification/indication of
+ * any characteristic is enabled by the peer, then this function must be called after
+ * having initialized the services.
+ *
+ * @param[in] p_init This contains information needed to initialize this module.
+ *
+ * @retval NRF_SUCCESS Successful initialization.
+ * @retval NRF_ERROR_INVALID_ADDR The provided Connection Parameters pointer is invalid.
+ * @retval NRF_ERROR_INVALID_PARAM The provided Connection Parameters are not valid.
+ * @retval NRF_ERROR_NULL @p p_init was NULL.
+ * @retval NRF_ERROR_INTERNAL An unexpected error occurred.
+ */
+ret_code_t ble_conn_params_init(const ble_conn_params_init_t * p_init);
+
+/**@brief Function for stopping the Connection Parameters module.
+ *
+ * @details This function is intended to be used by the application to clean up the connection
+ * parameters update module. This will stop the connection parameters update timer if
+ * running, thereby preventing any impending connection parameters update procedure. This
+ * function must be called by the application when it needs to clean itself up (for
+ * example, before disabling the bluetooth SoftDevice) so that an unwanted timer expiry
+ * event can be avoided.
+ *
+ * @retval NRF_SUCCESS Successfully stopped module.
+ * @retval NRF_ERROR_BUSY Could not complete operation at this time. Try again later.
+ Note that some timers may have been disabled.
+ * @retval NRF_ERROR_INTERNAL An unexpected error occurred.
+ */
+ret_code_t ble_conn_params_stop(void);
+
+/**@brief Function for changing the current connection parameters to a new set.
+ *
+ * @details Use this function to change the connection parameters to a new set of parameter
+ * (ie different from the ones given at init of the module).
+ * This function is useful for scenario where most of the time the application
+ * needs a relatively big connection interval, and just sometimes, for a temporary
+ * period requires shorter connection interval, for example to transfer a higher
+ * amount of data.
+ * If the given parameters does not match the current connection's parameters
+ * this function initiates a new negotiation.
+ *
+ * @param[in] conn_handle The connection to change connection parameters on.
+ * @param[in] p_new_params This contains the new connections parameters to setup.
+ *
+ * @retval NRF_SUCCESS Successfully started Connection Parameter update procedure.
+ * @retval NRF_ERROR_INVALID_ADDR The provided Connection Parameters pointer is invalid.
+ * @retval NRF_ERROR_INVALID_PARAM The provided Connection Parameters are not valid.
+ * @retval BLE_ERROR_INVALID_CONN_HANDLE The provided connection handle is invalid.
+ * @retval NRF_ERROR_INVALID_STATE The connection is not in a state where this operation can
+ * performed.
+ * @retval NRF_ERROR_BUSY Could not start operation at this time. Try again later.
+ * @retval NRF_ERROR_NO_MEM The SoftDevice lacks the memory to perform the action.
+ */
+ret_code_t ble_conn_params_change_conn_params(uint16_t conn_handle,
+ ble_gap_conn_params_t * p_new_params);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_CONN_PARAMS_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_conn_state.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_conn_state.c
new file mode 100644
index 0000000..32c6b96
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_conn_state.c
@@ -0,0 +1,481 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "ble_conn_state.h"
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include "ble.h"
+#include "nrf_atflags.h"
+#include "app_error.h"
+#include "nrf_sdh_ble.h"
+#include "app_util_platform.h"
+
+
+
+#define DEFAULT_FLAG_COLLECTION_COUNT 5 /**< The number of flags kept for each connection, excluding user flags. */
+#define TOTAL_FLAG_COLLECTION_COUNT (DEFAULT_FLAG_COLLECTION_COUNT \
+ + BLE_CONN_STATE_USER_FLAG_COUNT) /**< The number of flags kept for each connection, including user flags. */
+
+/**@brief Structure containing all the flag collections maintained by the Connection State module.
+ */
+typedef struct
+{
+ nrf_atflags_t valid_flags; /**< Flags indicating which connection handles are valid. */
+ nrf_atflags_t connected_flags; /**< Flags indicating which connections are connected, since disconnected connection handles will not immediately be invalidated. */
+ nrf_atflags_t central_flags; /**< Flags indicating in which connections the local device is the central. */
+ nrf_atflags_t encrypted_flags; /**< Flags indicating which connections are encrypted. */
+ nrf_atflags_t mitm_protected_flags; /**< Flags indicating which connections have encryption with protection from man-in-the-middle attacks. */
+ nrf_atflags_t user_flags[BLE_CONN_STATE_USER_FLAG_COUNT]; /**< Flags that can be reserved by the user. The flags will be cleared when a connection is invalidated, otherwise, the user is wholly responsible for the flag states. */
+} ble_conn_state_flag_collections_t;
+
+
+ANON_UNIONS_ENABLE;
+
+/**@brief Structure containing the internal state of the Connection State module.
+ */
+typedef struct
+{
+ nrf_atflags_t acquired_flags; /**< Bitmap for keeping track of which user flags have been acquired. */
+ union
+ {
+ ble_conn_state_flag_collections_t flags; /**< Flag collections kept by the Connection State module. */
+ nrf_atflags_t flag_array[TOTAL_FLAG_COLLECTION_COUNT]; /**< Flag collections as array to allow iterating over all flag collections. */
+ };
+} ble_conn_state_t;
+
+ANON_UNIONS_DISABLE;
+
+
+static ble_conn_state_t m_bcs = {0}; /**< Instantiation of the internal state. */
+
+
+/**@brief Function for resetting all internal memory to the values it had at initialization.
+ */
+void bcs_internal_state_reset(void)
+{
+ memset( &m_bcs, 0, sizeof(ble_conn_state_t) );
+}
+
+
+ble_conn_state_conn_handle_list_t conn_handle_list_get(nrf_atflags_t flags)
+{
+ ble_conn_state_conn_handle_list_t conn_handle_list;
+ conn_handle_list.len = 0;
+
+ if (flags != 0)
+ {
+ for (uint32_t i = 0; i < BLE_CONN_STATE_MAX_CONNECTIONS; i++)
+ {
+ if (nrf_atflags_get(&flags, i))
+ {
+ conn_handle_list.conn_handles[conn_handle_list.len++] = i;
+ }
+ }
+ }
+
+ return conn_handle_list;
+}
+
+
+uint32_t active_flag_count(nrf_atflags_t flags)
+{
+ uint32_t set_flag_count = 0;
+
+ for (uint32_t i = 0; i < BLE_CONN_STATE_MAX_CONNECTIONS; i++)
+ {
+ if (nrf_atflags_get(&flags, i))
+ {
+ set_flag_count += 1;
+ }
+ }
+ return set_flag_count;
+}
+
+
+/**@brief Function for activating a connection record.
+ *
+ * @param p_record The record to activate.
+ * @param conn_handle The connection handle to copy into the record.
+ * @param role The role of the connection.
+ *
+ * @return whether the record was activated successfully.
+ */
+static bool record_activate(uint16_t conn_handle)
+{
+ if (conn_handle >= BLE_CONN_STATE_MAX_CONNECTIONS)
+ {
+ return false;
+ }
+ nrf_atflags_set(&m_bcs.flags.connected_flags, conn_handle);
+ nrf_atflags_set(&m_bcs.flags.valid_flags, conn_handle);
+ return true;
+}
+
+
+/**@brief Function for marking a connection record as invalid and resetting the values.
+ *
+ * @param p_record The record to invalidate.
+ */
+static void record_invalidate(uint16_t conn_handle)
+{
+ for (uint32_t i = 0; i < TOTAL_FLAG_COLLECTION_COUNT; i++)
+ {
+ nrf_atflags_clear(&m_bcs.flag_array[i], conn_handle);
+ }
+}
+
+
+/**@brief Function for marking a connection as disconnected. See @ref BLE_CONN_STATUS_DISCONNECTED.
+ *
+ * @param p_record The record of the connection to set as disconnected.
+ */
+static void record_set_disconnected(uint16_t conn_handle)
+{
+ nrf_atflags_clear(&m_bcs.flags.connected_flags, conn_handle);
+}
+
+
+/**@brief Function for invalidating records with a @ref BLE_CONN_STATUS_DISCONNECTED
+ * connection status
+ */
+static void record_purge_disconnected()
+{
+ nrf_atflags_t disconnected_flags = ~m_bcs.flags.connected_flags;
+ ble_conn_state_conn_handle_list_t disconnected_list;
+
+ UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&disconnected_flags, m_bcs.flags.valid_flags));
+ disconnected_list = conn_handle_list_get(disconnected_flags);
+
+ for (uint32_t i = 0; i < disconnected_list.len; i++)
+ {
+ record_invalidate(disconnected_list.conn_handles[i]);
+ }
+}
+
+
+/**@brief Function for checking if a user flag has been acquired.
+ *
+ * @param[in] flag_id Which flag to check.
+ *
+ * @return Whether the flag has been acquired.
+ */
+static bool user_flag_is_acquired(ble_conn_state_user_flag_id_t flag_id)
+{
+ return nrf_atflags_get(&m_bcs.acquired_flags, flag_id);
+}
+
+
+void ble_conn_state_init(void)
+{
+ bcs_internal_state_reset();
+}
+
+/**
+ * @brief Function for handling BLE events.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Context.
+ */
+static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ uint16_t conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ record_purge_disconnected();
+
+ if ( !record_activate(conn_handle) )
+ {
+ // No more records available. Should not happen.
+ APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
+ }
+ else if ((p_ble_evt->evt.gap_evt.params.connected.role != BLE_GAP_ROLE_PERIPH))
+ {
+ // Central
+ nrf_atflags_set(&m_bcs.flags.central_flags, conn_handle);
+ }
+
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ record_set_disconnected(conn_handle);
+ break;
+
+ case BLE_GAP_EVT_CONN_SEC_UPDATE:
+ {
+ bool encrypted = (p_ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec.sec_mode.lv > 1);
+ bool mitm = (p_ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec.sec_mode.lv > 2);
+
+ if (encrypted)
+ {
+ nrf_atflags_set(&m_bcs.flags.encrypted_flags, conn_handle);
+ if (mitm)
+ {
+ nrf_atflags_set(&m_bcs.flags.mitm_protected_flags, conn_handle);
+ }
+ else
+ {
+ nrf_atflags_clear(&m_bcs.flags.mitm_protected_flags, conn_handle);
+ }
+ }
+ else
+ {
+ nrf_atflags_clear(&m_bcs.flags.encrypted_flags, conn_handle);
+ nrf_atflags_clear(&m_bcs.flags.mitm_protected_flags, conn_handle);
+ }
+ break;
+ }
+ }
+}
+
+NRF_SDH_BLE_OBSERVER(m_ble_evt_observer, BLE_CONN_STATE_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
+
+
+bool ble_conn_state_valid(uint16_t conn_handle)
+{
+ if (conn_handle >= BLE_CONN_STATE_MAX_CONNECTIONS)
+ {
+ return false;
+ }
+ return nrf_atflags_get(&m_bcs.flags.valid_flags, conn_handle);
+}
+
+
+uint8_t ble_conn_state_role(uint16_t conn_handle)
+{
+ uint8_t role = BLE_GAP_ROLE_INVALID;
+
+ if (ble_conn_state_valid(conn_handle))
+ {
+#if !defined (S112)
+ bool central = nrf_atflags_get(&m_bcs.flags.central_flags, conn_handle);
+ role = central ? BLE_GAP_ROLE_CENTRAL : BLE_GAP_ROLE_PERIPH;
+#else
+ role = BLE_GAP_ROLE_PERIPH;
+#endif // !defined (S112)
+ }
+
+ return role;
+}
+
+
+ble_conn_state_status_t ble_conn_state_status(uint16_t conn_handle)
+{
+ ble_conn_state_status_t conn_status = BLE_CONN_STATUS_INVALID;
+
+ if (ble_conn_state_valid(conn_handle))
+ {
+ bool connected = nrf_atflags_get(&m_bcs.flags.connected_flags, conn_handle);
+ conn_status = connected ? BLE_CONN_STATUS_CONNECTED : BLE_CONN_STATUS_DISCONNECTED;
+ }
+
+ return conn_status;
+}
+
+
+bool ble_conn_state_encrypted(uint16_t conn_handle)
+{
+ if (ble_conn_state_valid(conn_handle))
+ {
+ return nrf_atflags_get(&m_bcs.flags.encrypted_flags, conn_handle);
+ }
+ return false;
+}
+
+
+bool ble_conn_state_mitm_protected(uint16_t conn_handle)
+{
+ if (ble_conn_state_valid(conn_handle))
+ {
+ return nrf_atflags_get(&m_bcs.flags.mitm_protected_flags, conn_handle);
+ }
+ return false;
+}
+
+
+uint32_t ble_conn_state_conn_count(void)
+{
+ return active_flag_count(m_bcs.flags.connected_flags);
+}
+
+
+uint32_t ble_conn_state_central_conn_count(void)
+{
+ nrf_atflags_t central_conn_flags = m_bcs.flags.central_flags;
+ UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&central_conn_flags, m_bcs.flags.connected_flags));
+
+ return active_flag_count(central_conn_flags);
+}
+
+
+uint32_t ble_conn_state_peripheral_conn_count(void)
+{
+ nrf_atflags_t peripheral_conn_flags = ~m_bcs.flags.central_flags;
+ UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&peripheral_conn_flags, m_bcs.flags.connected_flags));
+
+ return active_flag_count(peripheral_conn_flags);
+}
+
+
+ble_conn_state_conn_handle_list_t ble_conn_state_conn_handles(void)
+{
+ return conn_handle_list_get(m_bcs.flags.valid_flags);
+}
+
+
+ble_conn_state_conn_handle_list_t ble_conn_state_central_handles(void)
+{
+ nrf_atflags_t central_conn_flags = m_bcs.flags.central_flags;
+ UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&central_conn_flags, m_bcs.flags.connected_flags));
+
+ return conn_handle_list_get(central_conn_flags);
+}
+
+
+ble_conn_state_conn_handle_list_t ble_conn_state_periph_handles(void)
+{
+ nrf_atflags_t peripheral_conn_flags = ~m_bcs.flags.central_flags;
+ UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&peripheral_conn_flags, m_bcs.flags.connected_flags));
+
+ return conn_handle_list_get(peripheral_conn_flags);
+}
+
+
+uint16_t ble_conn_state_conn_idx(uint16_t conn_handle)
+{
+ if (ble_conn_state_valid(conn_handle))
+ {
+ return conn_handle;
+ }
+ else
+ {
+ return BLE_CONN_STATE_MAX_CONNECTIONS;
+ }
+}
+
+
+ble_conn_state_user_flag_id_t ble_conn_state_user_flag_acquire(void)
+{
+ uint32_t acquired_flag = nrf_atflags_find_and_set_flag(&m_bcs.acquired_flags,
+ BLE_CONN_STATE_USER_FLAG_COUNT);
+
+ if (acquired_flag == BLE_CONN_STATE_USER_FLAG_COUNT)
+ {
+ return BLE_CONN_STATE_USER_FLAG_INVALID;
+ }
+ return (ble_conn_state_user_flag_id_t)acquired_flag;
+}
+
+
+bool ble_conn_state_user_flag_get(uint16_t conn_handle, ble_conn_state_user_flag_id_t flag_id)
+{
+ if (user_flag_is_acquired(flag_id) && ble_conn_state_valid(conn_handle))
+ {
+ return nrf_atflags_get(&m_bcs.flags.user_flags[flag_id], conn_handle);
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+void ble_conn_state_user_flag_set(uint16_t conn_handle,
+ ble_conn_state_user_flag_id_t flag_id,
+ bool value)
+{
+ if (user_flag_is_acquired(flag_id) && ble_conn_state_valid(conn_handle))
+ {
+ if (value)
+ {
+ nrf_atflags_set(&m_bcs.flags.user_flags[flag_id], conn_handle);
+ }
+ else
+ {
+ nrf_atflags_clear(&m_bcs.flags.user_flags[flag_id], conn_handle);
+ }
+ }
+}
+
+
+static uint32_t for_each_set_flag(nrf_atflags_t flags,
+ ble_conn_state_user_function_t user_function,
+ void * p_context)
+{
+ if (user_function == NULL)
+ {
+ return 0;
+ }
+
+ uint32_t call_count = 0;
+
+ if (flags != 0)
+ {
+ for (uint32_t i = 0; i < BLE_CONN_STATE_MAX_CONNECTIONS; i++)
+ {
+ if (nrf_atflags_get(&flags, i))
+ {
+ user_function(i, p_context);
+ call_count += 1;
+ }
+ }
+ }
+ return call_count;
+}
+
+
+uint32_t ble_conn_state_for_each_connected(ble_conn_state_user_function_t user_function,
+ void * p_context)
+{
+ return for_each_set_flag(m_bcs.flags.connected_flags, user_function, p_context);
+}
+
+
+uint32_t ble_conn_state_for_each_set_user_flag(ble_conn_state_user_flag_id_t flag_id,
+ ble_conn_state_user_function_t user_function,
+ void * p_context)
+{
+ if (!user_flag_is_acquired(flag_id))
+ {
+ return 0;
+ }
+
+ return for_each_set_flag(m_bcs.flags.user_flags[flag_id], user_function, p_context);
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_conn_state.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_conn_state.h
new file mode 100644
index 0000000..8d1efc4
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_conn_state.h
@@ -0,0 +1,345 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/**
+ * @file
+ *
+ * @defgroup ble_conn_state Connection state
+ * @ingroup ble_sdk_lib
+ * @{
+ * @brief Module for storing data on BLE connections.
+ *
+ * @details This module stores certain states for each connection, which can be queried by
+ * connection handle. The module uses BLE events to keep the states updated.
+ *
+ * In addition to the preprogrammed states, this module can also keep track of a number of
+ * binary user states, or <i>user flags</i>. These are reset to 0 for new connections, but
+ * otherwise not touched by this module.
+ *
+ * This module uses the @ref nrf_atomic module to make the flag operations thread-safe.
+ *
+ * @note A connection handle is not immediately invalidated when it is disconnected. Certain states,
+ * such as the role, can still be queried until the next time a new connection is established
+ * to any device.
+ *
+ */
+
+#ifndef BLE_CONN_STATE_H__
+#define BLE_CONN_STATE_H__
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "ble.h"
+#include "ble_gap.h"
+#include "nrf_atomic.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Connection handle statuses.
+ */
+typedef enum
+{
+ BLE_CONN_STATUS_INVALID, /**< The connection handle is invalid. */
+ BLE_CONN_STATUS_DISCONNECTED, /**< The connection handle refers to a connection that has been disconnected, but not yet invalidated. */
+ BLE_CONN_STATUS_CONNECTED, /**< The connection handle refers to an active connection. */
+} ble_conn_state_status_t;
+
+#define BLE_CONN_STATE_MAX_CONNECTIONS BLE_GAP_ROLE_COUNT_COMBINED_MAX /**< The maximum number of connections supported. */
+#define BLE_CONN_STATE_USER_FLAG_COUNT 24 /**< The number of available user flags. */
+
+
+/**@brief Type used to present a list of conn_handles.
+ */
+typedef struct
+{
+ uint32_t len; /**< The length of the list. */
+ uint16_t conn_handles[BLE_CONN_STATE_MAX_CONNECTIONS]; /**< The list of handles. */
+} ble_conn_state_conn_handle_list_t;
+
+/**@brief One ID for each user flag collection.
+ *
+ * @details These IDs are used to identify user flag collections in the API calls.
+ */
+typedef enum
+{
+ BLE_CONN_STATE_USER_FLAG0 = 0,
+ BLE_CONN_STATE_USER_FLAG1,
+ BLE_CONN_STATE_USER_FLAG2,
+ BLE_CONN_STATE_USER_FLAG3,
+ BLE_CONN_STATE_USER_FLAG4,
+ BLE_CONN_STATE_USER_FLAG5,
+ BLE_CONN_STATE_USER_FLAG6,
+ BLE_CONN_STATE_USER_FLAG7,
+ BLE_CONN_STATE_USER_FLAG8,
+ BLE_CONN_STATE_USER_FLAG9,
+ BLE_CONN_STATE_USER_FLAG10,
+ BLE_CONN_STATE_USER_FLAG11,
+ BLE_CONN_STATE_USER_FLAG12,
+ BLE_CONN_STATE_USER_FLAG13,
+ BLE_CONN_STATE_USER_FLAG14,
+ BLE_CONN_STATE_USER_FLAG15,
+ BLE_CONN_STATE_USER_FLAG16,
+ BLE_CONN_STATE_USER_FLAG17,
+ BLE_CONN_STATE_USER_FLAG18,
+ BLE_CONN_STATE_USER_FLAG19,
+ BLE_CONN_STATE_USER_FLAG20,
+ BLE_CONN_STATE_USER_FLAG21,
+ BLE_CONN_STATE_USER_FLAG22,
+ BLE_CONN_STATE_USER_FLAG23,
+ BLE_CONN_STATE_USER_FLAG_INVALID,
+} ble_conn_state_user_flag_id_t;
+
+
+/**@brief Function to be called when a flag ID is set. See @ref ble_conn_state_for_each_set_user_flag.
+ *
+ * @param[in] conn_handle The connection the flag is set for.
+ * @param[in] p_context Arbitrary pointer provided by the caller of
+ * @ref ble_conn_state_for_each_set_user_flag.
+ */
+typedef void (*ble_conn_state_user_function_t)(uint16_t conn_handle, void * p_context);
+
+
+/**
+ * @defgroup ble_conn_state_functions BLE connection state functions
+ * @{
+ */
+
+
+/**@brief Function for initializing or resetting the module.
+ *
+ * @details This function sets all states to their default, removing all records of connection handles.
+ */
+void ble_conn_state_init(void);
+
+
+/**@brief Function for querying whether a connection handle represents a valid connection.
+ *
+ * @details A connection might be valid and have a BLE_CONN_STATUS_DISCONNECTED status.
+ * Those connections are invalidated after a new connection occurs.
+ *
+ * @param[in] conn_handle Handle of the connection.
+ *
+ * @retval true If conn_handle represents a valid connection, thus a connection for which
+ we have a record.
+ * @retval false If conn_handle is @ref BLE_GAP_ROLE_INVALID, or if it has never been recorded.
+ */
+bool ble_conn_state_valid(uint16_t conn_handle);
+
+
+/**@brief Function for querying the role of the local device in a connection.
+ *
+ * @param[in] conn_handle Handle of the connection to get the role for.
+ *
+ * @return The role of the local device in the connection (see @ref BLE_GAP_ROLES).
+ * If conn_handle is not valid, the function returns BLE_GAP_ROLE_INVALID.
+ */
+uint8_t ble_conn_state_role(uint16_t conn_handle);
+
+
+/**@brief Function for querying the status of a connection.
+ *
+ * @param[in] conn_handle Handle of the connection.
+ *
+ * @return The status of the connection.
+ * If conn_handle is not valid, the function returns BLE_CONN_STATE_INVALID.
+ */
+ble_conn_state_status_t ble_conn_state_status(uint16_t conn_handle);
+
+
+/**@brief Function for querying whether a connection is encrypted.
+ *
+ * @param[in] conn_handle Handle of connection to get the encryption state for.
+ *
+ * @retval true If the connection is encrypted.
+ * @retval false If the connection is not encrypted or conn_handle is invalid.
+ */
+bool ble_conn_state_encrypted(uint16_t conn_handle);
+
+
+/**@brief Function for querying whether a connection encryption is protected from Man in the Middle
+ * attacks.
+ *
+ * @param[in] conn_handle Handle of connection to get the MITM state for.
+ *
+ * @retval true If the connection is encrypted with MITM protection.
+ * @retval false If the connection is not encrypted, or encryption is not MITM protected, or
+ * conn_handle is invalid.
+ */
+bool ble_conn_state_mitm_protected(uint16_t conn_handle);
+
+
+/**@brief Function for querying the total number of connections.
+ *
+ * @return The total number of valid connections for which the module has a record.
+ */
+uint32_t ble_conn_state_conn_count(void);
+
+
+/**@brief Function for querying the total number of connections in which the role of the local
+ * device is @ref BLE_GAP_ROLE_CENTRAL.
+ *
+ * @return The number of connections in which the role of the local device is
+ * @ref BLE_GAP_ROLE_CENTRAL.
+ */
+uint32_t ble_conn_state_central_conn_count(void);
+
+
+/**@brief Function for querying the total number of connections in which the role of the local
+ * device is @ref BLE_GAP_ROLE_PERIPH.
+ *
+ * @return The number of connections in which the role of the local device is
+ * @ref BLE_GAP_ROLE_PERIPH.
+ */
+uint32_t ble_conn_state_peripheral_conn_count(void);
+
+
+/**@brief Function for obtaining a list of all connection handles for which the module has a record.
+ *
+ * @details This function takes into account connections whose state is BLE_CONN_STATUS_DISCONNECTED.
+ *
+ * @return A list of all valid connection handles for which the module has a record.
+ */
+ble_conn_state_conn_handle_list_t ble_conn_state_conn_handles(void);
+
+
+/**@brief Function for obtaining a list of connection handles in which the role of the local
+ * device is @ref BLE_GAP_ROLE_CENTRAL.
+ *
+ * @details This function takes into account connections whose state is BLE_CONN_STATUS_DISCONNECTED.
+ *
+ * @return A list of all valid connection handles for which the module has a record and in which
+ * the role of local device is @ref BLE_GAP_ROLE_CENTRAL.
+ */
+ble_conn_state_conn_handle_list_t ble_conn_state_central_handles(void);
+
+
+/**@brief Function for obtaining the handle for the connection in which the role of the local device
+ * is @ref BLE_GAP_ROLE_PERIPH.
+ *
+ * @details This function takes into account connections whose state is BLE_CONN_STATUS_DISCONNECTED.
+ *
+ * @return A list of all valid connection handles for which the module has a record and in which
+ * the role of local device is @ref BLE_GAP_ROLE_PERIPH.
+ */
+ble_conn_state_conn_handle_list_t ble_conn_state_periph_handles(void);
+
+
+/**@brief Function for translating a connection handle to a value that can be used as an array index.
+ *
+ * @details Function for mapping connection handles onto the range <0 - MAX_CONNECTIONS>.
+ *
+ * @note The index will be the same as long as a connection is invalid. A subsequent connection with
+ * the same connection handle might have a different index.
+ *
+ * @param[in] conn_handle The connection for which to retrieve an index.
+ *
+ * @return An index unique to this connection. Or @ref BLE_CONN_STATE_MAX_CONNECTIONS if
+ * @p conn_handle refers to an invalid connection.
+ */
+uint16_t ble_conn_state_conn_idx(uint16_t conn_handle);
+
+
+/**@brief Function for obtaining exclusive access to one of the user flag collections.
+ *
+ * @details The acquired collection contains one flag for each connection. These flags can be set
+ * and read individually for each connection.
+ *
+ * The state of user flags will not be modified by the connection state module, except to
+ * set it to 0 for a connection when that connection is invalidated.
+ *
+ * @return The ID of the acquired flag, or BLE_CONN_STATE_USER_FLAG_INVALID if none are available.
+ */
+ble_conn_state_user_flag_id_t ble_conn_state_user_flag_acquire(void);
+
+
+/**@brief Function for reading the value of a user flag.
+ *
+ * @param[in] conn_handle Handle of connection to get the flag state for.
+ * @param[in] flag_id Which flag to get the state for.
+ *
+ * @return The state of the flag. If conn_handle is invalid, the function returns false.
+ */
+bool ble_conn_state_user_flag_get(uint16_t conn_handle, ble_conn_state_user_flag_id_t flag_id);
+
+
+/**@brief Function for setting the value of a user flag.
+ *
+ * @param[in] conn_handle Handle of connection to set the flag state for.
+ * @param[in] flag_id Which flag to set the state for.
+ * @param[in] value Value to set the flag state to.
+ */
+void ble_conn_state_user_flag_set(uint16_t conn_handle,
+ ble_conn_state_user_flag_id_t flag_id,
+ bool value);
+
+
+/**@brief Function for running a function for each active connection.
+ *
+ * @param[in] user_function The function to run for each connection.
+ * @param[in] p_context Arbitrary context to be passed to \p user_function.
+ *
+ * @return The number of times \p user_function was run.
+ */
+uint32_t ble_conn_state_for_each_connected(ble_conn_state_user_function_t user_function,
+ void * p_context);
+
+
+/**@brief Function for running a function for each flag that is set in a user flag collection.
+ *
+ * @param[in] flag_id Which flags to check.
+ * @param[in] user_function The function to run when a flag is set.
+ * @param[in] p_context Arbitrary context to be passed to \p user_function.
+ *
+ * @return The number of times \p user_function was run.
+ */
+uint32_t ble_conn_state_for_each_set_user_flag(ble_conn_state_user_flag_id_t flag_id,
+ ble_conn_state_user_function_t user_function,
+ void * p_context);
+
+/** @} */
+/** @} */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BLE_CONN_STATE_H__ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_date_time.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_date_time.h
new file mode 100644
index 0000000..72dd8b8
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_date_time.h
@@ -0,0 +1,113 @@
+/**
+ * Copyright (c) 2011 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Attention!
+* To maintain compliance with Nordic Semiconductor ASA’s Bluetooth profile
+* qualification listings, this section of source code must not be modified.
+*/
+
+/** @file
+ * @brief Contains definition of ble_date_time structure.
+ */
+
+/** @file
+ *
+ * @defgroup ble_sdk_srv_date_time BLE Date Time characteristic type
+ * @{
+ * @ingroup ble_sdk_lib
+ * @brief Definition of ble_date_time_t type.
+ */
+
+#ifndef BLE_DATE_TIME_H__
+#define BLE_DATE_TIME_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Date and Time structure. */
+typedef struct
+{
+ uint16_t year;
+ uint8_t month;
+ uint8_t day;
+ uint8_t hours;
+ uint8_t minutes;
+ uint8_t seconds;
+} ble_date_time_t;
+
+static __INLINE uint8_t ble_date_time_encode(const ble_date_time_t * p_date_time,
+ uint8_t * p_encoded_data)
+{
+ uint8_t len = uint16_encode(p_date_time->year, p_encoded_data);
+
+ p_encoded_data[len++] = p_date_time->month;
+ p_encoded_data[len++] = p_date_time->day;
+ p_encoded_data[len++] = p_date_time->hours;
+ p_encoded_data[len++] = p_date_time->minutes;
+ p_encoded_data[len++] = p_date_time->seconds;
+
+ return len;
+}
+
+static __INLINE uint8_t ble_date_time_decode(ble_date_time_t * p_date_time,
+ const uint8_t * p_encoded_data)
+{
+ uint8_t len = sizeof(uint16_t);
+
+ p_date_time->year = uint16_decode(p_encoded_data);
+ p_date_time->month = p_encoded_data[len++];
+ p_date_time->day = p_encoded_data[len++];
+ p_date_time->hours = p_encoded_data[len++];
+ p_date_time->minutes = p_encoded_data[len++];
+ p_date_time->seconds = p_encoded_data[len++];
+
+ return len;
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_DATE_TIME_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_gatt_db.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_gatt_db.h
new file mode 100644
index 0000000..314c2b8
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_gatt_db.h
@@ -0,0 +1,92 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/**@file
+ *
+ * @defgroup ble_sdk_lib_gatt_db GATT Database Service Structure
+ * @{
+ * @ingroup ble_sdk_lib
+ */
+
+#ifndef BLE_GATT_DB_H__
+#define BLE_GATT_DB_H__
+
+#include <stdint.h>
+#include "ble.h"
+#include "ble_gattc.h"
+#include "sdk_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef BLE_GATT_DB_MAX_CHARS
+#define BLE_GATT_DB_MAX_CHARS 6 /**< The maximum number of characteristics present in a service record. */
+#endif // BLE_GATT_DB_MAX_CHARS
+
+/**@brief Structure for holding the characteristic and the handle of its CCCD present on a server.
+ */
+typedef struct
+{
+ ble_gattc_char_t characteristic; /**< Structure containing information about the characteristic. */
+ uint16_t cccd_handle; /**< CCCD Handle value for this characteristic. This will be set to BLE_GATT_HANDLE_INVALID if a CCCD is not present at the server. */
+ uint16_t ext_prop_handle; /**< Extended Properties Handle value for this characteristic. This will be set to BLE_GATT_HANDLE_INVALID if an Extended Properties descriptor is not present at the server. */
+ uint16_t user_desc_handle; /**< User Description Handle value for this characteristic. This will be set to BLE_GATT_HANDLE_INVALID if a User Description descriptor is not present at the server. */
+ uint16_t report_ref_handle; /**< Report Reference Handle value for this characteristic. This will be set to BLE_GATT_HANDLE_INVALID if a Report Reference descriptor is not present at the server. */
+} ble_gatt_db_char_t;
+
+/**@brief Structure for holding information about the service and the characteristics present on a
+ * server.
+ */
+typedef struct
+{
+ ble_uuid_t srv_uuid; /**< UUID of the service. */
+ uint8_t char_count; /**< Number of characteristics present in the service. */
+ ble_gattc_handle_range_t handle_range; /**< Service Handle Range. */
+ ble_gatt_db_char_t charateristics[BLE_GATT_DB_MAX_CHARS]; /**< Array of information related to the characteristics present in the service. This list can extend further than one. */
+} ble_gatt_db_srv_t;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BLE_GATT_DB_H__ */
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_sensor_location.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_sensor_location.h
new file mode 100644
index 0000000..b54bdac
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_sensor_location.h
@@ -0,0 +1,76 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Attention!
+* To maintain compliance with Nordic Semiconductor ASA’s Bluetooth profile
+* qualification listings, this section of source code must not be modified.
+*/
+
+#ifndef BLE_SENSOR_LOCATION_H__
+#define BLE_SENSOR_LOCATION_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ BLE_SENSOR_LOCATION_OTHER = 0 , /**<-- Other */
+ BLE_SENSOR_LOCATION_TOP_OF_SHOE = 1 , /**<-- Top of shoe */
+ BLE_SENSOR_LOCATION_IN_SHOE = 2 , /**<-- In shoe */
+ BLE_SENSOR_LOCATION_HIP = 3 , /**<-- Hip */
+ BLE_SENSOR_LOCATION_FRONT_WHEEL = 4 , /**<-- Front Wheel */
+ BLE_SENSOR_LOCATION_LEFT_CRANK = 5 , /**<-- Left Crank */
+ BLE_SENSOR_LOCATION_RIGHT_CRANK = 6 , /**<-- Right Crank */
+ BLE_SENSOR_LOCATION_LEFT_PEDAL = 7 , /**<-- Left Pedal */
+ BLE_SENSOR_LOCATION_RIGHT_PEDAL = 8 , /**<-- Right Pedal */
+ BLE_SENSOR_LOCATION_FRONT_HUB = 9 , /**<-- Front Hub */
+ BLE_SENSOR_LOCATION_REAR_DROPOUT = 10, /**<-- Rear Dropout */
+ BLE_SENSOR_LOCATION_CHAINSTAY = 11, /**<-- Chainstay */
+ BLE_SENSOR_LOCATION_REAR_WHEEL = 12, /**<-- Rear Wheel */
+ BLE_SENSOR_LOCATION_REAR_HUB = 13, /**<-- Rear Hub */
+}ble_sensor_location_t;
+
+#define BLE_NB_MAX_SENSOR_LOCATIONS 14
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_SENSOR_LOCATION_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_srv_common.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_srv_common.c
new file mode 100644
index 0000000..473d2b9
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_srv_common.c
@@ -0,0 +1,237 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Attention!
+ * To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+
+#include "ble_srv_common.h"
+#include <string.h>
+#include "nordic_common.h"
+#include "app_error.h"
+#include "ble.h"
+
+bool ble_srv_is_notification_enabled(uint8_t const * p_encoded_data)
+{
+ uint16_t cccd_value = uint16_decode(p_encoded_data);
+ return ((cccd_value & BLE_GATT_HVX_NOTIFICATION) != 0);
+}
+
+bool ble_srv_is_indication_enabled(uint8_t const * p_encoded_data)
+{
+ uint16_t cccd_value = uint16_decode(p_encoded_data);
+ return ((cccd_value & BLE_GATT_HVX_INDICATION) != 0);
+}
+
+uint8_t ble_srv_report_ref_encode(uint8_t * p_encoded_buffer,
+ const ble_srv_report_ref_t * p_report_ref)
+{
+ uint8_t len = 0;
+
+ p_encoded_buffer[len++] = p_report_ref->report_id;
+ p_encoded_buffer[len++] = p_report_ref->report_type;
+
+ APP_ERROR_CHECK_BOOL(len == BLE_SRV_ENCODED_REPORT_REF_LEN);
+ return len;
+}
+
+
+void ble_srv_ascii_to_utf8(ble_srv_utf8_str_t * p_utf8, char * p_ascii)
+{
+ p_utf8->length = (uint16_t)strlen(p_ascii);
+ p_utf8->p_str = (uint8_t *)p_ascii;
+}
+
+
+/**@brief Function for setting security requirements of a characteristic.
+ *
+ * @param[in] level required security level.
+ * @param[out] p_perm Characteristic security requirements.
+ *
+ * @return encoded security level and security mode.
+ */
+static inline void set_security_req(security_req_t level, ble_gap_conn_sec_mode_t * p_perm)
+{
+
+
+ BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(p_perm);
+ switch (level)
+ {
+ case SEC_NO_ACCESS:
+ BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(p_perm);
+ break;
+ case SEC_OPEN:
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(p_perm);
+ break;
+ case SEC_JUST_WORKS:
+ BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(p_perm);
+ break;
+ case SEC_MITM:
+ BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(p_perm);
+ break;
+ case SEC_SIGNED:
+ BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(p_perm);
+ break;
+ case SEC_SIGNED_MITM:
+ BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(p_perm);
+ break;
+ }
+ return;
+}
+
+
+uint32_t characteristic_add(uint16_t service_handle,
+ ble_add_char_params_t * p_char_props,
+ ble_gatts_char_handles_t * p_char_handle)
+{
+ ble_gatts_char_md_t char_md;
+ ble_gatts_attr_t attr_char_value;
+ ble_uuid_t char_uuid;
+ ble_gatts_attr_md_t attr_md;
+ ble_gatts_attr_md_t user_descr_attr_md;
+ ble_gatts_attr_md_t cccd_md;
+
+ if (p_char_props->uuid_type == 0)
+ {
+ char_uuid.type = BLE_UUID_TYPE_BLE;
+ }
+ else
+ {
+ char_uuid.type = p_char_props->uuid_type;
+ }
+ char_uuid.uuid = p_char_props->uuid;
+
+ memset(&attr_md, 0, sizeof(ble_gatts_attr_md_t));
+ set_security_req(p_char_props->read_access, &attr_md.read_perm);
+ set_security_req(p_char_props->write_access, & attr_md.write_perm);
+ attr_md.rd_auth = (p_char_props->is_defered_read ? 1 : 0);
+ attr_md.wr_auth = (p_char_props->is_defered_write ? 1 : 0);
+ attr_md.vlen = (p_char_props->is_var_len ? 1 : 0);
+ attr_md.vloc = (p_char_props->is_value_user ? BLE_GATTS_VLOC_USER : BLE_GATTS_VLOC_STACK);
+
+
+ memset(&char_md, 0, sizeof(ble_gatts_char_md_t));
+ if ((p_char_props->char_props.notify == 1)||(p_char_props->char_props.indicate == 1))
+ {
+
+ memset(&cccd_md, 0, sizeof(cccd_md));
+ set_security_req(p_char_props->cccd_write_access, &cccd_md.write_perm);
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
+
+ cccd_md.vloc = BLE_GATTS_VLOC_STACK;
+
+ char_md.p_cccd_md = &cccd_md;
+ }
+ char_md.char_props = p_char_props->char_props;
+ char_md.char_ext_props = p_char_props->char_ext_props;
+
+ memset(&attr_char_value, 0, sizeof(ble_gatts_attr_t));
+ attr_char_value.p_uuid = &char_uuid;
+ attr_char_value.p_attr_md = &attr_md;
+ attr_char_value.max_len = p_char_props->max_len;
+ if (p_char_props->p_init_value != NULL)
+ {
+ attr_char_value.init_len = p_char_props->init_len;
+ attr_char_value.p_value = p_char_props->p_init_value;
+ }
+ if (p_char_props->p_user_descr != NULL)
+ {
+ memset(&user_descr_attr_md, 0, sizeof(ble_gatts_attr_md_t));
+ char_md.char_user_desc_max_size = p_char_props->p_user_descr->max_size;
+ char_md.char_user_desc_size = p_char_props->p_user_descr->size;
+ char_md.p_char_user_desc = p_char_props->p_user_descr->p_char_user_desc;
+
+ char_md.p_user_desc_md = &user_descr_attr_md;
+
+ set_security_req(p_char_props->p_user_descr->read_access, &user_descr_attr_md.read_perm);
+ set_security_req(p_char_props->p_user_descr->write_access, &user_descr_attr_md.write_perm);
+
+ user_descr_attr_md.rd_auth = (p_char_props->p_user_descr->is_defered_read ? 1 : 0);
+ user_descr_attr_md.wr_auth = (p_char_props->p_user_descr->is_defered_write ? 1 : 0);
+ user_descr_attr_md.vlen = (p_char_props->p_user_descr->is_var_len ? 1 : 0);
+ user_descr_attr_md.vloc = (p_char_props->p_user_descr->is_value_user ? BLE_GATTS_VLOC_USER : BLE_GATTS_VLOC_STACK);
+ }
+ if (p_char_props->p_presentation_format != NULL)
+ {
+ char_md.p_char_pf = p_char_props->p_presentation_format;
+ }
+ return sd_ble_gatts_characteristic_add(service_handle,
+ &char_md,
+ &attr_char_value,
+ p_char_handle);
+}
+
+
+uint32_t descriptor_add(uint16_t char_handle,
+ ble_add_descr_params_t * p_descr_props,
+ uint16_t * p_descr_handle)
+{
+ ble_gatts_attr_t descr_params;
+ ble_uuid_t desc_uuid;
+ ble_gatts_attr_md_t attr_md;
+
+ memset(&descr_params, 0, sizeof(descr_params));
+ if (p_descr_props->uuid_type == 0)
+ {
+ desc_uuid.type = BLE_UUID_TYPE_BLE;
+ }
+ else
+ {
+ desc_uuid.type = p_descr_props->uuid_type;
+ }
+ desc_uuid.uuid = p_descr_props->uuid;
+ descr_params.p_uuid = &desc_uuid;
+
+ set_security_req(p_descr_props->read_access, &attr_md.read_perm);
+ set_security_req(p_descr_props->write_access,&attr_md.write_perm);
+
+ attr_md.rd_auth = (p_descr_props->is_defered_read ? 1 : 0);
+ attr_md.wr_auth = (p_descr_props->is_defered_write ? 1 : 0);
+ attr_md.vlen = (p_descr_props->is_var_len ? 1 : 0);
+ attr_md.vloc = (p_descr_props->is_value_user ? BLE_GATTS_VLOC_USER : BLE_GATTS_VLOC_STACK);
+ descr_params.p_attr_md = &attr_md;
+
+ descr_params.init_len = p_descr_props->init_len;
+ descr_params.init_offs = p_descr_props->init_offs;
+ descr_params.max_len = p_descr_props->max_len;
+ descr_params.p_value = p_descr_props->p_value;
+
+ return sd_ble_gatts_descriptor_add(char_handle, &descr_params, p_descr_handle);
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_srv_common.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_srv_common.h
new file mode 100644
index 0000000..285cbed
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/common/ble_srv_common.h
@@ -0,0 +1,409 @@
+/**
+ * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_sdk_srv_common Common service definitions
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Constants, type definitions, and functions that are common to all services.
+ */
+
+#ifndef BLE_SRV_COMMON_H__
+#define BLE_SRV_COMMON_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ble_types.h"
+#include "app_util.h"
+#include "ble.h"
+#include "ble_gap.h"
+#include "ble_gatt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @defgroup UUID_SERVICES Service UUID definitions
+ * @{ */
+#define BLE_UUID_ALERT_NOTIFICATION_SERVICE 0x1811 /**< Alert Notification service UUID. */
+#define BLE_UUID_BATTERY_SERVICE 0x180F /**< Battery service UUID. */
+#define BLE_UUID_BLOOD_PRESSURE_SERVICE 0x1810 /**< Blood Pressure service UUID. */
+#define BLE_UUID_CURRENT_TIME_SERVICE 0x1805 /**< Current Time service UUID. */
+#define BLE_UUID_CYCLING_SPEED_AND_CADENCE 0x1816 /**< Cycling Speed and Cadence service UUID. */
+#define BLE_UUID_LOCATION_AND_NAVIGATION_SERVICE 0x1819 /**< Location and Navigation service UUID. */
+#define BLE_UUID_DEVICE_INFORMATION_SERVICE 0x180A /**< Device Information service UUID. */
+#define BLE_UUID_GLUCOSE_SERVICE 0x1808 /**< Glucose service UUID. */
+#define BLE_UUID_HEALTH_THERMOMETER_SERVICE 0x1809 /**< Health Thermometer service UUID. */
+#define BLE_UUID_HEART_RATE_SERVICE 0x180D /**< Heart Rate service UUID. */
+#define BLE_UUID_HUMAN_INTERFACE_DEVICE_SERVICE 0x1812 /**< Human Interface Device service UUID. */
+#define BLE_UUID_IMMEDIATE_ALERT_SERVICE 0x1802 /**< Immediate Alert service UUID. */
+#define BLE_UUID_LINK_LOSS_SERVICE 0x1803 /**< Link Loss service UUID. */
+#define BLE_UUID_NEXT_DST_CHANGE_SERVICE 0x1807 /**< Next Dst Change service UUID. */
+#define BLE_UUID_PHONE_ALERT_STATUS_SERVICE 0x180E /**< Phone Alert Status service UUID. */
+#define BLE_UUID_REFERENCE_TIME_UPDATE_SERVICE 0x1806 /**< Reference Time Update service UUID. */
+#define BLE_UUID_RUNNING_SPEED_AND_CADENCE 0x1814 /**< Running Speed and Cadence service UUID. */
+#define BLE_UUID_SCAN_PARAMETERS_SERVICE 0x1813 /**< Scan Parameters service UUID. */
+#define BLE_UUID_TX_POWER_SERVICE 0x1804 /**< TX Power service UUID. */
+#define BLE_UUID_IPSP_SERVICE 0x1820 /**< Internet Protocol Support service UUID. */
+#define BLE_UUID_BMS_SERVICE 0x181E /**< BOND MANAGEMENT service UUID*/
+#define BLE_UUID_CGM_SERVICE 0x181F /**< Continuous Glucose Monitoring service UUID*/
+#define BLE_UUID_PLX_SERVICE 0x1822 /**< Pulse Oximeter Service UUID*/
+#define BLE_UUID_OTS_SERVICE 0x1825 /**< Object Transfer Service UUID*/
+
+/** @} */
+
+/** @defgroup UUID_CHARACTERISTICS Characteristic UUID definitions
+ * @{ */
+#define BLE_UUID_REMOVABLE_CHAR 0x2A3A /**< Removable characteristic UUID. */
+#define BLE_UUID_SERVICE_REQUIRED_CHAR 0x2A3B /**< Service Required characteristic UUID. */
+#define BLE_UUID_ALERT_CATEGORY_ID_CHAR 0x2A43 /**< Alert Category Id characteristic UUID. */
+#define BLE_UUID_ALERT_CATEGORY_ID_BIT_MASK_CHAR 0x2A42 /**< Alert Category Id Bit Mask characteristic UUID. */
+#define BLE_UUID_ALERT_LEVEL_CHAR 0x2A06 /**< Alert Level characteristic UUID. */
+#define BLE_UUID_ALERT_NOTIFICATION_CONTROL_POINT_CHAR 0x2A44 /**< Alert Notification Control Point characteristic UUID. */
+#define BLE_UUID_ALERT_STATUS_CHAR 0x2A3F /**< Alert Status characteristic UUID. */
+#define BLE_UUID_BATTERY_LEVEL_CHAR 0x2A19 /**< Battery Level characteristic UUID. */
+#define BLE_UUID_BLOOD_PRESSURE_FEATURE_CHAR 0x2A49 /**< Blood Pressure Feature characteristic UUID. */
+#define BLE_UUID_BLOOD_PRESSURE_MEASUREMENT_CHAR 0x2A35 /**< Blood Pressure Measurement characteristic UUID. */
+#define BLE_UUID_BODY_SENSOR_LOCATION_CHAR 0x2A38 /**< Body Sensor Location characteristic UUID. */
+#define BLE_UUID_BOOT_KEYBOARD_INPUT_REPORT_CHAR 0x2A22 /**< Boot Keyboard Input Report characteristic UUID. */
+#define BLE_UUID_BOOT_KEYBOARD_OUTPUT_REPORT_CHAR 0x2A32 /**< Boot Keyboard Output Report characteristic UUID. */
+#define BLE_UUID_BOOT_MOUSE_INPUT_REPORT_CHAR 0x2A33 /**< Boot Mouse Input Report characteristic UUID. */
+#define BLE_UUID_CURRENT_TIME_CHAR 0x2A2B /**< Current Time characteristic UUID. */
+#define BLE_UUID_DATE_TIME_CHAR 0x2A08 /**< Date Time characteristic UUID. */
+#define BLE_UUID_DAY_DATE_TIME_CHAR 0x2A0A /**< Day Date Time characteristic UUID. */
+#define BLE_UUID_DAY_OF_WEEK_CHAR 0x2A09 /**< Day Of Week characteristic UUID. */
+#define BLE_UUID_DST_OFFSET_CHAR 0x2A0D /**< Dst Offset characteristic UUID. */
+#define BLE_UUID_EXACT_TIME_256_CHAR 0x2A0C /**< Exact Time 256 characteristic UUID. */
+#define BLE_UUID_FIRMWARE_REVISION_STRING_CHAR 0x2A26 /**< Firmware Revision String characteristic UUID. */
+#define BLE_UUID_GLUCOSE_FEATURE_CHAR 0x2A51 /**< Glucose Feature characteristic UUID. */
+#define BLE_UUID_GLUCOSE_MEASUREMENT_CHAR 0x2A18 /**< Glucose Measurement characteristic UUID. */
+#define BLE_UUID_GLUCOSE_MEASUREMENT_CONTEXT_CHAR 0x2A34 /**< Glucose Measurement Context characteristic UUID. */
+#define BLE_UUID_HARDWARE_REVISION_STRING_CHAR 0x2A27 /**< Hardware Revision String characteristic UUID. */
+#define BLE_UUID_HEART_RATE_CONTROL_POINT_CHAR 0x2A39 /**< Heart Rate Control Point characteristic UUID. */
+#define BLE_UUID_HEART_RATE_MEASUREMENT_CHAR 0x2A37 /**< Heart Rate Measurement characteristic UUID. */
+#define BLE_UUID_HID_CONTROL_POINT_CHAR 0x2A4C /**< Hid Control Point characteristic UUID. */
+#define BLE_UUID_HID_INFORMATION_CHAR 0x2A4A /**< Hid Information characteristic UUID. */
+#define BLE_UUID_IEEE_REGULATORY_CERTIFICATION_DATA_LIST_CHAR 0x2A2A /**< IEEE Regulatory Certification Data List characteristic UUID. */
+#define BLE_UUID_INTERMEDIATE_CUFF_PRESSURE_CHAR 0x2A36 /**< Intermediate Cuff Pressure characteristic UUID. */
+#define BLE_UUID_INTERMEDIATE_TEMPERATURE_CHAR 0x2A1E /**< Intermediate Temperature characteristic UUID. */
+#define BLE_UUID_LOCAL_TIME_INFORMATION_CHAR 0x2A0F /**< Local Time Information characteristic UUID. */
+#define BLE_UUID_MANUFACTURER_NAME_STRING_CHAR 0x2A29 /**< Manufacturer Name String characteristic UUID. */
+#define BLE_UUID_MEASUREMENT_INTERVAL_CHAR 0x2A21 /**< Measurement Interval characteristic UUID. */
+#define BLE_UUID_MODEL_NUMBER_STRING_CHAR 0x2A24 /**< Model Number String characteristic UUID. */
+#define BLE_UUID_UNREAD_ALERT_CHAR 0x2A45 /**< Unread Alert characteristic UUID. */
+#define BLE_UUID_NEW_ALERT_CHAR 0x2A46 /**< New Alert characteristic UUID. */
+#define BLE_UUID_PNP_ID_CHAR 0x2A50 /**< PNP Id characteristic UUID. */
+#define BLE_UUID_PROTOCOL_MODE_CHAR 0x2A4E /**< Protocol Mode characteristic UUID. */
+#define BLE_UUID_RECORD_ACCESS_CONTROL_POINT_CHAR 0x2A52 /**< Record Access Control Point characteristic UUID. */
+#define BLE_UUID_REFERENCE_TIME_INFORMATION_CHAR 0x2A14 /**< Reference Time Information characteristic UUID. */
+#define BLE_UUID_REPORT_CHAR 0x2A4D /**< Report characteristic UUID. */
+#define BLE_UUID_REPORT_MAP_CHAR 0x2A4B /**< Report Map characteristic UUID. */
+#define BLE_UUID_RINGER_CONTROL_POINT_CHAR 0x2A40 /**< Ringer Control Point characteristic UUID. */
+#define BLE_UUID_RINGER_SETTING_CHAR 0x2A41 /**< Ringer Setting characteristic UUID. */
+#define BLE_UUID_SCAN_INTERVAL_WINDOW_CHAR 0x2A4F /**< Scan Interval Window characteristic UUID. */
+#define BLE_UUID_SCAN_REFRESH_CHAR 0x2A31 /**< Scan Refresh characteristic UUID. */
+#define BLE_UUID_SERIAL_NUMBER_STRING_CHAR 0x2A25 /**< Serial Number String characteristic UUID. */
+#define BLE_UUID_SOFTWARE_REVISION_STRING_CHAR 0x2A28 /**< Software Revision String characteristic UUID. */
+#define BLE_UUID_SUPPORTED_NEW_ALERT_CATEGORY_CHAR 0x2A47 /**< Supported New Alert Category characteristic UUID. */
+#define BLE_UUID_SUPPORTED_UNREAD_ALERT_CATEGORY_CHAR 0x2A48 /**< Supported Unread Alert Category characteristic UUID. */
+#define BLE_UUID_SYSTEM_ID_CHAR 0x2A23 /**< System Id characteristic UUID. */
+#define BLE_UUID_TEMPERATURE_MEASUREMENT_CHAR 0x2A1C /**< Temperature Measurement characteristic UUID. */
+#define BLE_UUID_TEMPERATURE_TYPE_CHAR 0x2A1D /**< Temperature Type characteristic UUID. */
+#define BLE_UUID_TIME_ACCURACY_CHAR 0x2A12 /**< Time Accuracy characteristic UUID. */
+#define BLE_UUID_TIME_SOURCE_CHAR 0x2A13 /**< Time Source characteristic UUID. */
+#define BLE_UUID_TIME_UPDATE_CONTROL_POINT_CHAR 0x2A16 /**< Time Update Control Point characteristic UUID. */
+#define BLE_UUID_TIME_UPDATE_STATE_CHAR 0x2A17 /**< Time Update State characteristic UUID. */
+#define BLE_UUID_TIME_WITH_DST_CHAR 0x2A11 /**< Time With Dst characteristic UUID. */
+#define BLE_UUID_TIME_ZONE_CHAR 0x2A0E /**< Time Zone characteristic UUID. */
+#define BLE_UUID_TX_POWER_LEVEL_CHAR 0x2A07 /**< TX Power Level characteristic UUID. */
+#define BLE_UUID_CSC_FEATURE_CHAR 0x2A5C /**< Cycling Speed and Cadence Feature characteristic UUID. */
+#define BLE_UUID_CSC_MEASUREMENT_CHAR 0x2A5B /**< Cycling Speed and Cadence Measurement characteristic UUID. */
+#define BLE_UUID_RSC_FEATURE_CHAR 0x2A54 /**< Running Speed and Cadence Feature characteristic UUID. */
+#define BLE_UUID_SC_CTRLPT_CHAR 0x2A55 /**< Speed and Cadence Control Point UUID. */
+#define BLE_UUID_RSC_MEASUREMENT_CHAR 0x2A53 /**< Running Speed and Cadence Measurement characteristic UUID. */
+#define BLE_UUID_SENSOR_LOCATION_CHAR 0x2A5D /**< Sensor Location characteristic UUID. */
+#define BLE_UUID_EXTERNAL_REPORT_REF_DESCR 0x2907 /**< External Report Reference descriptor UUID. */
+#define BLE_UUID_REPORT_REF_DESCR 0x2908 /**< Report Reference descriptor UUID. */
+#define BLE_UUID_LN_FEATURE_CHAR 0x2A6A /**< Location Navigation Service, Feature characteristic UUID. */
+#define BLE_UUID_LN_POSITION_QUALITY_CHAR 0x2A69 /**< Location Navigation Service, Position quality UUID. */
+#define BLE_UUID_LN_LOCATION_AND_SPEED_CHAR 0x2A67 /**< Location Navigation Service, Location and Speed characteristic UUID. */
+#define BLE_UUID_LN_NAVIGATION_CHAR 0x2A68 /**< Location Navigation Service, Navigation characteristic UUID. */
+#define BLE_UUID_LN_CONTROL_POINT_CHAR 0x2A6B /**< Location Navigation Service, Control point characteristic UUID. */
+#define BLE_UUID_BMS_CTRLPT 0x2AA4 /**< BMS Control Point characteristic UUID. */
+#define BLE_UUID_BMS_FEATURE 0x2AA5 /**< BMS Feature characteristic UUID. */
+#define BLE_UUID_CGM_MEASUREMENT 0x2AA7 /**< CGM Service, Measurement characteristic UUID*/
+#define BLE_UUID_CGM_FEATURE 0x2AA8 /**< CGM Service, Feature characteristic UUID*/
+#define BLE_UUID_CGM_STATUS 0x2AA9 /**< CGM Service, Status characteristic UUID*/
+#define BLE_UUID_CGM_SESSION_START_TIME 0x2AAA /**< CGM Service, session start time characteristic UUID*/
+#define BLE_UUID_CGM_SESSION_RUN_TIME 0x2AAB /**< CGM Service, session run time characteristic UUID*/
+#define BLE_UUID_CGM_SPECIFIC_OPS_CTRLPT 0x2AAC /**< CGM Service, specific ops ctrlpt characteristic UUID*/
+#define BLE_UUID_PLX_SPOT_CHECK_MEAS 0x2A5E /**< PLX Service, spot check measurement characteristic UUID*/
+#define BLE_UUID_PLX_CONTINUOUS_MEAS 0x2A5F /**< PLX Service, continuous measurement characteristic UUID*/
+#define BLE_UUID_PLX_FEATURES 0x2A60 /**< PLX Service, feature characteristic UUID*/
+#define BLE_UUID_OTS_FEATURES 0x2ABD /**< OTS Service, feature characteristic UUID*/
+#define BLE_UUID_OTS_OBJECT_NAME 0x2ABE /**< OTS Service, Object Name characteristic UUID*/
+#define BLE_UUID_OTS_OBJECT_TYPE 0x2ABF /**< OTS Service, Object Type characteristic UUID*/
+#define BLE_UUID_OTS_OBJECT_SIZE 0x2AC0 /**< OTS Service, Object Size characteristic UUID*/
+#define BLE_UUID_OTS_OBJECT_FIRST_CREATED 0x2AC1 /**< OTS Service, Object First Created characteristic UUID*/
+#define BLE_UUID_OTS_OBJECT_LAST_MODIFIED 0x2AC2 /**< OTS Service, Object Last Modified characteristic UUID*/
+#define BLE_UUID_OTS_OBJECT_ID 0x2AC3 /**< OTS Service, Object ID characteristic UUID*/
+#define BLE_UUID_OTS_OBJECT_PROPERTIES 0x2AC4 /**< OTS Service, Object Properties characteristic UUID*/
+#define BLE_UUID_OTS_OACP 0x2AC5 /**< OTS Service, Object Action Control Point characteristic UUID*/
+#define BLE_UUID_OTS_OLCP 0x2AC6 /**< OTS Service, Object List Control Point characteristic UUID*/
+#define BLE_UUID_OTS_LF 0x2AC7 /**< OTS Service, Object List Filter characteristic UUID*/
+#define BLE_UUID_OTS_OBJECT_CHANGED 0x2AC8 /**< OTS Service, Object Changed characteristic UUID*/
+
+
+
+
+/** @} */
+
+/** @defgroup ALERT_LEVEL_VALUES Definitions for the Alert Level characteristic values
+ * @{ */
+#define BLE_CHAR_ALERT_LEVEL_NO_ALERT 0x00 /**< No Alert. */
+#define BLE_CHAR_ALERT_LEVEL_MILD_ALERT 0x01 /**< Mild Alert. */
+#define BLE_CHAR_ALERT_LEVEL_HIGH_ALERT 0x02 /**< High Alert. */
+/** @} */
+
+#define BLE_SRV_ENCODED_REPORT_REF_LEN 2 /**< The length of an encoded Report Reference Descriptor. */
+#define BLE_CCCD_VALUE_LEN 2 /**< The length of a CCCD value. */
+
+/**@brief Type definition for error handler function that will be called in case of an error in
+ * a service or a service library module. */
+typedef void (*ble_srv_error_handler_t) (uint32_t nrf_error);
+
+
+
+/**@brief Value of a Report Reference descriptor.
+ *
+ * @details This is mapping information that maps the parent characteristic to the Report ID(s) and
+ * Report Type(s) defined within a Report Map characteristic.
+ */
+typedef struct
+{
+ uint8_t report_id; /**< Non-zero value if there is more than one instance of the same Report Type */
+ uint8_t report_type; /**< Type of Report characteristic (see @ref BLE_HIDS_REPORT_TYPE) */
+} ble_srv_report_ref_t;
+
+/**@brief UTF-8 string data type.
+ *
+ * @note The type can only hold a pointer to the string data (i.e. not the actual data).
+ */
+typedef struct
+{
+ uint16_t length; /**< String length. */
+ uint8_t * p_str; /**< String data. */
+} ble_srv_utf8_str_t;
+
+
+/**@brief Security settings structure.
+ * @details This structure contains the security options needed during initialization of the
+ * service.
+ */
+typedef struct
+{
+ ble_gap_conn_sec_mode_t read_perm; /**< Read permissions. */
+ ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */
+} ble_srv_security_mode_t;
+
+/**@brief Security settings structure.
+ * @details This structure contains the security options needed during initialization of the
+ * service. It can be used when the characteristics contains a CCCD.
+ */
+typedef struct
+{
+ ble_gap_conn_sec_mode_t cccd_write_perm; /**< Write permissions for Client Characteristic Configuration Descriptor. */
+ ble_gap_conn_sec_mode_t read_perm; /**< Read permissions. */
+ ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */
+} ble_srv_cccd_security_mode_t;
+
+/**@brief Function for decoding a CCCD value, and then testing if notification is
+ * enabled.
+ *
+ * @param[in] p_encoded_data Buffer where the encoded CCCD is stored.
+ *
+ * @retval TRUE If notification is enabled.
+ * @retval FALSE Otherwise.
+ */
+bool ble_srv_is_notification_enabled(uint8_t const * p_encoded_data);
+
+
+/**@brief Function for decoding a CCCD value, and then testing if indication is
+ * enabled.
+ *
+ * @param[in] p_encoded_data Buffer where the encoded CCCD is stored.
+ *
+ * @retval TRUE If indication is enabled.
+ * @retval FALSE Otherwise.
+ */
+bool ble_srv_is_indication_enabled(uint8_t const * p_encoded_data);
+
+
+/**@brief Function for encoding a Report Reference Descriptor.
+ *
+ * @param[in] p_encoded_buffer The buffer of the encoded data.
+ * @param[in] p_report_ref Report Reference value to be encoded.
+ *
+ * @return Length of the encoded data.
+ */
+uint8_t ble_srv_report_ref_encode(uint8_t * p_encoded_buffer,
+ const ble_srv_report_ref_t * p_report_ref);
+
+/**@brief Function for making a UTF-8 structure refer to an ASCII string.
+ *
+ * @param[out] p_utf8 UTF-8 structure to be set.
+ * @param[in] p_ascii ASCII string to be referred to.
+ */
+void ble_srv_ascii_to_utf8(ble_srv_utf8_str_t * p_utf8, char * p_ascii);
+
+
+/**@brief Security Access enumeration.
+ * @details This enumeration gives the possible requirements for accessing a characteristic value.
+ */
+typedef enum
+{
+ SEC_NO_ACCESS = 0, /**< Not possible to access. */
+ SEC_OPEN = 1, /**< Access open. */
+ SEC_JUST_WORKS = 2, /**< Access possible with 'Just Works' security at least. */
+ SEC_MITM = 3, /**< Access possible with 'MITM' security at least. */
+ SEC_SIGNED = 4, /**< Access possible with 'signed' security at least. */
+ SEC_SIGNED_MITM = 5 /**< Access possible with 'signed and MITM' security at least. */
+}security_req_t;
+
+
+/**@brief Characteristic User Descriptor parameters.
+ * @details This structure contains the parameters for User Descriptor.
+ */
+typedef struct
+{
+ uint16_t max_size; /**< Maximum size of the user descriptor*/
+ uint16_t size; /**< Size of the user descriptor*/
+ uint8_t *p_char_user_desc; /**< User descriptor content, pointer to a UTF-8 encoded string (non-NULL terminated)*/
+ bool is_var_len; /**< Indicates if the user descriptor has variable length.*/
+ ble_gatt_char_props_t char_props; /**< user descriptor properties.*/
+ bool is_defered_read; /**< Indicate if deferred read operations are supported.*/
+ bool is_defered_write; /**< Indicate if deferred write operations are supported.*/
+ security_req_t read_access; /**< Security requirement for reading the user descriptor.*/
+ security_req_t write_access; /**< Security requirement for writing the user descriptor.*/
+ bool is_value_user; /**< Indicate if the content of the characteristic is to be stored in the application (user) or in the stack.*/
+}ble_add_char_user_desc_t;
+
+
+/**@brief Add characteristic parameters structure.
+ * @details This structure contains the parameters needed to use the @ref characteristic_add function.
+ */
+typedef struct
+{
+ uint16_t uuid; /**< Characteristic UUID (16 bits UUIDs).*/
+ uint8_t uuid_type; /**< Base UUID. If 0, the Bluetooth SIG UUID will be used. Otherwise, this should be a value returned by @ref sd_ble_uuid_vs_add when adding the base UUID.*/
+ uint16_t max_len; /**< Maximum length of the characteristic value.*/
+ uint16_t init_len; /**< Initial length of the characteristic value.*/
+ uint8_t * p_init_value; /**< Initial encoded value of the characteristic.*/
+ bool is_var_len; /**< Indicates if the characteristic value has variable length.*/
+ ble_gatt_char_props_t char_props; /**< Characteristic properties.*/
+ ble_gatt_char_ext_props_t char_ext_props; /**< Characteristic extended properties.*/
+ bool is_defered_read; /**< Indicate if deferred read operations are supported.*/
+ bool is_defered_write; /**< Indicate if deferred write operations are supported.*/
+ security_req_t read_access; /**< Security requirement for reading the characteristic value.*/
+ security_req_t write_access; /**< Security requirement for writing the characteristic value.*/
+ security_req_t cccd_write_access; /**< Security requirement for writing the characteristic's CCCD.*/
+ bool is_value_user; /**< Indicate if the content of the characteristic is to be stored in the application (user) or in the stack.*/
+ ble_add_char_user_desc_t *p_user_descr; /**< Pointer to user descriptor if needed*/
+ ble_gatts_char_pf_t *p_presentation_format; /**< Pointer to characteristic format if needed*/
+} ble_add_char_params_t;
+
+
+/**@brief Add descriptor parameters structure.
+ * @details This structure contains the parameters needed to use the @ref descriptor_add function.
+ */
+typedef struct
+{
+ uint16_t uuid; /**< descriptor UUID (16 bits UUIDs).*/
+ uint8_t uuid_type; /**< Base UUID. If 0, the Bluetooth SIG UUID will be used. Otherwise, this should be a value returned by @ref sd_ble_uuid_vs_add when adding the base UUID.*/
+ bool is_defered_read; /**< Indicate if deferred read operations are supported.*/
+ bool is_defered_write; /**< Indicate if deferred write operations are supported.*/
+ bool is_var_len; /**< Indicates if the descriptor value has variable length.*/
+ security_req_t read_access; /**< Security requirement for reading the descriptor value.*/
+ security_req_t write_access; /**< Security requirement for writing the descriptor value.*/
+ bool is_value_user; /**< Indicate if the content of the characteristic is to be stored in the application (user) or in the stack.*/
+ uint16_t init_len; /**< Initial descriptor value length in bytes. */
+ uint16_t init_offs; /**< Initial descriptor value offset in bytes. If different from zero, the first init_offs bytes of the attribute value will be left uninitialized. */
+ uint16_t max_len; /**< Maximum descriptor value length in bytes, see @ref BLE_GATTS_ATTR_LENS_MAX for maximum values. */
+ uint8_t* p_value; /**< Pointer to the value of the descriptor*/
+} ble_add_descr_params_t;
+
+
+/**@brief Function for adding a characteristic to a given service.
+ *
+ * If no pointer is given for the initial value,
+ * the initial length parameter will be ignored and the initial length will be 0.
+ *
+ * @param[in] service_handle Handle of the service to which the characteristic is to be added.
+ * @param[in] p_char_props Information needed to add the characteristic.
+ * @param[out] p_char_handle Handle of the added characteristic.
+ *
+ * @retval NRF_SUCCESS If the characteristic was added successfully. Otherwise, an error code is returned.
+ */
+uint32_t characteristic_add(uint16_t service_handle,
+ ble_add_char_params_t * p_char_props,
+ ble_gatts_char_handles_t * p_char_handle);
+
+
+/**@brief Function for adding a characteristic's descriptor to a given characteristic.
+ *
+ * @param[in] char_handle Handle of the characteristic to which the descriptor is to be added, if @ref BLE_GATT_HANDLE_INVALID is used, it will be placed sequentially.
+ * @param[in] p_descr_props Information needed to add the descriptor.
+ * @param[out] p_descr_handle Handle of the added descriptor.
+ *
+ * @retval NRF_SUCCESS If the characteristic was added successfully. Otherwise, an error code is returned.
+ */
+uint32_t descriptor_add(uint16_t char_handle,
+ ble_add_descr_params_t * p_descr_props,
+ uint16_t * p_descr_handle);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_SRV_COMMON_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/nrf_ble_gatt/nrf_ble_gatt.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/nrf_ble_gatt/nrf_ble_gatt.c
new file mode 100644
index 0000000..51a5250
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/nrf_ble_gatt/nrf_ble_gatt.c
@@ -0,0 +1,550 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(NRF_BLE_GATT)
+
+#include "nrf_ble_gatt.h"
+
+#define NRF_LOG_MODULE_NAME nrf_ble_gatt
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#include "nrf_strerror.h"
+
+#define BLE_GAP_DATA_LENGTH_DEFAULT 27 //!< The stack's default data length.
+#define BLE_GAP_DATA_LENGTH_MAX 251 //!< Maximum data length.
+
+
+STATIC_ASSERT(NRF_SDH_BLE_GAP_DATA_LENGTH < 252);
+
+
+/**@brief Initialize a link's parameters to defaults. */
+static void link_init(nrf_ble_gatt_link_t * p_link)
+{
+ p_link->att_mtu_desired = NRF_SDH_BLE_GATT_MAX_MTU_SIZE;
+ p_link->att_mtu_effective = BLE_GATT_ATT_MTU_DEFAULT;
+ p_link->att_mtu_exchange_pending = false;
+ p_link->att_mtu_exchange_requested = false;
+#if !defined (S112)
+ p_link->data_length_desired = NRF_SDH_BLE_GAP_DATA_LENGTH;
+ p_link->data_length_effective = BLE_GAP_DATA_LENGTH_DEFAULT;
+#endif // !defined (S112)
+}
+
+/**@brief Start a data length update request procedure on a given connection. */
+#if !defined (S112)
+static ret_code_t data_length_update(uint16_t conn_handle, uint16_t data_length)
+{
+ NRF_LOG_DEBUG("Updating data length to %u on connection 0x%x.",
+ data_length, conn_handle);
+
+ ble_gap_data_length_params_t const dlp =
+ {
+ .max_rx_octets = data_length,
+ .max_tx_octets = data_length,
+ .max_rx_time_us = BLE_GAP_DATA_LENGTH_AUTO,
+ .max_tx_time_us = BLE_GAP_DATA_LENGTH_AUTO,
+ };
+
+ ble_gap_data_length_limitation_t dll = {0};
+
+ ret_code_t err_code = sd_ble_gap_data_length_update(conn_handle, &dlp, &dll);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("sd_ble_gap_data_length_update() (request) on connection 0x%x returned %s.",
+ conn_handle, nrf_strerror_get(err_code));
+
+ if ( (dll.tx_payload_limited_octets != 0)
+ || (dll.rx_payload_limited_octets != 0))
+ {
+ NRF_LOG_ERROR("The requested TX/RX packet length is too long by %u/%u octets.",
+ dll.tx_payload_limited_octets, dll.rx_payload_limited_octets);
+ }
+
+ if (dll.tx_rx_time_limited_us != 0)
+ {
+ NRF_LOG_ERROR("The requested combination of TX and RX packet lengths "
+ "is too long by %u microseconds.",
+ dll.tx_rx_time_limited_us);
+ }
+ }
+
+ return err_code;
+}
+#endif // !defined (S112)
+
+
+/**@brief Handle a connected event.
+ *
+ * Begins an ATT MTU exchange procedure, followed by a data length update request as necessary.
+ *
+ * @param[in] p_gatt GATT structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_connected_evt(nrf_ble_gatt_t * p_gatt, ble_evt_t const * p_ble_evt)
+{
+ ret_code_t err_code;
+ uint16_t conn_handle = p_ble_evt->evt.common_evt.conn_handle;
+ nrf_ble_gatt_link_t * p_link = &p_gatt->links[conn_handle];
+
+ // Update the link desired settings to reflect the current global settings.
+#if !defined (S112)
+ p_link->data_length_desired = p_gatt->data_length;
+#endif // !defined (S112)
+
+ switch (p_ble_evt->evt.gap_evt.params.connected.role)
+ {
+ case BLE_GAP_ROLE_PERIPH:
+ p_link->att_mtu_desired = p_gatt->att_mtu_desired_periph;
+ break;
+
+#if !defined (S112)
+ case BLE_GAP_ROLE_CENTRAL:
+ p_link->att_mtu_desired = p_gatt->att_mtu_desired_central;
+ break;
+#endif // !defined (S112)
+
+ default:
+ // Ignore.
+ break;
+ }
+
+ // Begin an ATT MTU exchange if necessary.
+ if (p_link->att_mtu_desired > p_link->att_mtu_effective)
+ {
+ NRF_LOG_DEBUG("Requesting to update ATT MTU to %u bytes on connection 0x%x.",
+ p_link->att_mtu_desired, conn_handle);
+
+ err_code = sd_ble_gattc_exchange_mtu_request(conn_handle, p_link->att_mtu_desired);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ p_link->att_mtu_exchange_requested = true;
+ }
+ else if (err_code == NRF_ERROR_BUSY)
+ {
+ p_link->att_mtu_exchange_pending = true;
+ NRF_LOG_DEBUG("sd_ble_gattc_exchange_mtu_request()"
+ " on connection 0x%x returned busy, will retry.", conn_handle);
+ }
+ else
+ {
+ NRF_LOG_ERROR("sd_ble_gattc_exchange_mtu_request() returned %s.",
+ nrf_strerror_get(err_code));
+ }
+ }
+
+#if !defined (S112)
+ // Send a data length update request if necessary.
+ if (p_link->data_length_desired > p_link->data_length_effective)
+ {
+ (void) data_length_update(conn_handle, p_link->data_length_desired);
+ }
+#endif // !defined (S112)
+}
+
+
+static void on_disconnected_evt(nrf_ble_gatt_t * p_gatt, ble_evt_t const * p_ble_evt)
+{
+ // Reset connection parameters.
+ link_init(&p_gatt->links[p_ble_evt->evt.gap_evt.conn_handle]);
+}
+
+
+/**@brief Handle a BLE_GATTC_EVT_EXCHANGE_MTU_RSP event.
+ *
+ * @details The effective ATT MTU is set to the lowest between what we requested and the peer's
+ * response. This events concludes the ATT MTU exchange. An event is sent to the user
+ * and a data length update procedure is started if necessary.
+ *
+ * @param[in] p_gatt GATT structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_exchange_mtu_rsp_evt(nrf_ble_gatt_t * p_gatt, ble_evt_t const * p_ble_evt)
+{
+ uint16_t conn_handle = p_ble_evt->evt.gattc_evt.conn_handle;
+ uint16_t server_rx_mtu = p_ble_evt->evt.gattc_evt.params.exchange_mtu_rsp.server_rx_mtu;
+
+ nrf_ble_gatt_link_t * p_link = &p_gatt->links[conn_handle];
+
+ // Determine the lowest MTU between our own desired MTU and the peer's.
+ // The MTU may not be less than BLE_GATT_ATT_MTU_DEFAULT.
+ p_link->att_mtu_effective = MIN(server_rx_mtu, p_link->att_mtu_desired);
+ p_link->att_mtu_effective = MAX(p_link->att_mtu_effective, BLE_GATT_ATT_MTU_DEFAULT);
+
+ NRF_LOG_DEBUG("ATT MTU updated to %u bytes on connection 0x%x (response).",
+ p_link->att_mtu_effective, conn_handle);
+
+ // Trigger an event indicating that the ATT MTU size has changed.
+ // Send an event to the application only if an ATT MTU exchange was requested.
+ if ((p_gatt->evt_handler != NULL) && (p_link->att_mtu_exchange_requested))
+ {
+ nrf_ble_gatt_evt_t const evt =
+ {
+ .evt_id = NRF_BLE_GATT_EVT_ATT_MTU_UPDATED,
+ .conn_handle = conn_handle,
+ .params.att_mtu_effective = p_link->att_mtu_effective,
+ };
+
+ p_gatt->evt_handler(p_gatt, &evt);
+ }
+
+ p_link->att_mtu_exchange_requested = false;
+ p_link->att_mtu_exchange_pending = false;
+}
+
+
+/**@brief Handle a BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST event.
+ *
+ * @param[in] p_gatt GATT structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_exchange_mtu_request_evt(nrf_ble_gatt_t * p_gatt, ble_evt_t const * p_ble_evt)
+{
+ ret_code_t err_code;
+ uint16_t conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
+ uint16_t client_mtu = p_ble_evt->evt.gatts_evt.params.exchange_mtu_request.client_rx_mtu;
+
+ nrf_ble_gatt_link_t * p_link = &p_gatt->links[conn_handle];
+
+ NRF_LOG_DEBUG("Peer on connection 0x%x requested an ATT MTU of %u bytes.",
+ conn_handle, client_mtu);
+
+ client_mtu = MAX(client_mtu, BLE_GATT_ATT_MTU_DEFAULT);
+ p_link->att_mtu_effective = MIN(client_mtu, p_link->att_mtu_desired);
+ p_link->att_mtu_exchange_pending = false;
+
+ NRF_LOG_DEBUG("Updating ATT MTU to %u bytes (desired: %u) on connection 0x%x.",
+ p_link->att_mtu_effective, p_link->att_mtu_desired, conn_handle);
+
+ err_code = sd_ble_gatts_exchange_mtu_reply(conn_handle, p_link->att_mtu_desired);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("sd_ble_gatts_exchange_mtu_reply() returned %s.", nrf_strerror_get(err_code));
+ }
+
+ // If an ATT_MTU exchange was requested to the peer, defer sending
+ // the data length update request and the event to the application until
+ // the response for that request is received.
+ if (p_link->att_mtu_exchange_requested)
+ {
+ return;
+ }
+
+ // The ATT MTU exchange has finished. Send an event to the application.
+ if (p_gatt->evt_handler != NULL)
+ {
+ nrf_ble_gatt_evt_t const evt =
+ {
+ .evt_id = NRF_BLE_GATT_EVT_ATT_MTU_UPDATED,
+ .conn_handle = conn_handle,
+ .params.att_mtu_effective = p_link->att_mtu_effective,
+ };
+
+ p_gatt->evt_handler(p_gatt, &evt);
+ }
+}
+
+
+/**@brief Handle a BLE_GAP_EVT_DATA_LENGTH_UPDATE event.
+ *
+ * @details Update the connection data length and send an event to the user.
+ *
+ * @param[in] p_gatt GATT structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+#if !defined (S112)
+static void on_data_length_update_evt(nrf_ble_gatt_t * p_gatt, ble_evt_t const * p_ble_evt)
+{
+ ble_gap_evt_t const gap_evt = p_ble_evt->evt.gap_evt;
+ uint16_t const conn_handle = gap_evt.conn_handle;
+
+ // Update the connection data length.
+ // The SoftDevice only supports symmetric RX/TX data length settings.
+ p_gatt->links[conn_handle].data_length_effective =
+ gap_evt.params.data_length_update.effective_params.max_tx_octets;
+
+ NRF_LOG_DEBUG("Data length updated to %u on connection 0x%0x.",
+ p_gatt->links[conn_handle].data_length_effective,
+ conn_handle);
+
+ NRF_LOG_DEBUG("max_rx_octets: %u",
+ gap_evt.params.data_length_update.effective_params.max_rx_octets);
+ NRF_LOG_DEBUG("max_tx_octets: %u",
+ gap_evt.params.data_length_update.effective_params.max_tx_octets);
+ NRF_LOG_DEBUG("max_rx_time: %u",
+ gap_evt.params.data_length_update.effective_params.max_rx_time_us);
+ NRF_LOG_DEBUG("max_tx_time: %u",
+ gap_evt.params.data_length_update.effective_params.max_tx_time_us);
+
+ if (p_gatt->evt_handler != NULL)
+ {
+ nrf_ble_gatt_evt_t const evt =
+ {
+ .evt_id = NRF_BLE_GATT_EVT_DATA_LENGTH_UPDATED,
+ .conn_handle = conn_handle,
+ .params.data_length = p_gatt->links[conn_handle].data_length_effective,
+ };
+
+ p_gatt->evt_handler(p_gatt, &evt);
+ }
+}
+
+
+/**@brief Handle a BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST event.
+ *
+ *@details Reply with a sd_ble_gap_data_length_update() call, using the minimum between the
+ * link's preferred data length, and what requested by the peer.
+ * The link preferred data length is set to the global preferred data length
+ * upon connection and can be overridden by calling nrf_ble_gatt_data_length_set().
+ * The default is NRF_SDH_BLE_GAP_DATA_LENGTH.
+ *
+ *@note The SoftDevice will not send any BLE_GAP_EVT_DATA_LENGTH_UPDATE events on this side.
+ * Therefore, the connection data length is updated immediately and an event is sent
+ * to the user.
+ *
+ * @param[in] p_gatt GATT structure.
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ */
+static void on_data_length_update_request_evt(nrf_ble_gatt_t * p_gatt, ble_evt_t const * p_ble_evt)
+{
+ ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;
+ nrf_ble_gatt_link_t * p_link = &p_gatt->links[p_gap_evt->conn_handle];
+
+ // The SoftDevice only supports symmetric RX/TX data length settings.
+ uint8_t const data_length_requested =
+ p_gap_evt->params.data_length_update_request.peer_params.max_tx_octets;
+
+ NRF_LOG_DEBUG("Peer on connection 0x%x requested a data length of %u bytes.",
+ p_gap_evt->conn_handle, data_length_requested);
+
+ uint8_t const data_length_effective = MIN(p_link->data_length_desired, data_length_requested);
+
+ (void) data_length_update(p_gap_evt->conn_handle, data_length_effective);
+}
+#endif // !defined (S112)
+
+
+ret_code_t nrf_ble_gatt_init(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_handler_t evt_handler)
+{
+ VERIFY_PARAM_NOT_NULL(p_gatt);
+
+ p_gatt->evt_handler = evt_handler;
+ p_gatt->att_mtu_desired_periph = NRF_SDH_BLE_GATT_MAX_MTU_SIZE;
+ p_gatt->att_mtu_desired_central = NRF_SDH_BLE_GATT_MAX_MTU_SIZE;
+ p_gatt->data_length = NRF_SDH_BLE_GAP_DATA_LENGTH;
+
+ for (uint32_t i = 0; i < NRF_BLE_GATT_LINK_COUNT; i++)
+ {
+ link_init(&p_gatt->links[i]);
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t nrf_ble_gatt_att_mtu_periph_set(nrf_ble_gatt_t * p_gatt, uint16_t desired_mtu)
+{
+ VERIFY_PARAM_NOT_NULL(p_gatt);
+
+ if ((desired_mtu < BLE_GATT_ATT_MTU_DEFAULT) || (desired_mtu > NRF_SDH_BLE_GATT_MAX_MTU_SIZE))
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ p_gatt->att_mtu_desired_periph = desired_mtu;
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t nrf_ble_gatt_att_mtu_central_set(nrf_ble_gatt_t * p_gatt, uint16_t desired_mtu)
+{
+ VERIFY_PARAM_NOT_NULL(p_gatt);
+
+ if ((desired_mtu < BLE_GATT_ATT_MTU_DEFAULT) || (desired_mtu > NRF_SDH_BLE_GATT_MAX_MTU_SIZE))
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ p_gatt->att_mtu_desired_central = desired_mtu;
+ return NRF_SUCCESS;
+}
+
+
+uint16_t nrf_ble_gatt_eff_mtu_get(nrf_ble_gatt_t const * p_gatt, uint16_t conn_handle)
+{
+ if ((p_gatt == NULL) || (conn_handle >= NRF_BLE_GATT_LINK_COUNT))
+ {
+ return 0;
+ }
+
+ return p_gatt->links[conn_handle].att_mtu_effective;
+}
+
+#if !defined (S112)
+ret_code_t nrf_ble_gatt_data_length_set(nrf_ble_gatt_t * p_gatt,
+ uint16_t conn_handle,
+ uint8_t data_length)
+{
+ if (p_gatt == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ // Check early to avoid requesting an invalid data length for upcoming connections.
+ if ( (data_length > BLE_GAP_DATA_LENGTH_MAX)
+ || (data_length < BLE_GAP_DATA_LENGTH_DEFAULT))
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ if (conn_handle == BLE_CONN_HANDLE_INVALID)
+ {
+ // Save value and request upon connection.
+ p_gatt->data_length = data_length;
+ return NRF_SUCCESS;
+ }
+
+ if (conn_handle >= NRF_BLE_GATT_LINK_COUNT)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ // Request data length on existing link.
+ p_gatt->links[conn_handle].data_length_desired = data_length;
+
+ return data_length_update(conn_handle, data_length);
+}
+
+
+ret_code_t nrf_ble_gatt_data_length_get(nrf_ble_gatt_t const * p_gatt,
+ uint16_t conn_handle,
+ uint8_t * p_data_length)
+{
+ if ((p_gatt == NULL) || (p_data_length == NULL))
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ if (conn_handle == BLE_CONN_HANDLE_INVALID)
+ {
+ *p_data_length = p_gatt->data_length;
+ return NRF_SUCCESS;
+ }
+
+ if (conn_handle >= NRF_BLE_GATT_LINK_COUNT)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ *p_data_length = p_gatt->links[conn_handle].data_length_effective;
+ return NRF_SUCCESS;
+}
+#endif // !defined (S112)
+
+
+void nrf_ble_gatt_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ nrf_ble_gatt_t * p_gatt = (nrf_ble_gatt_t *)p_context;
+ uint16_t conn_handle = p_ble_evt->evt.common_evt.conn_handle;
+
+ if (conn_handle >= NRF_BLE_GATT_LINK_COUNT)
+ {
+ return;
+ }
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ on_connected_evt(p_gatt, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ on_disconnected_evt(p_gatt, p_ble_evt);
+ break;
+
+ case BLE_GATTC_EVT_EXCHANGE_MTU_RSP:
+ on_exchange_mtu_rsp_evt(p_gatt, p_ble_evt);
+ break;
+
+ case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST:
+ on_exchange_mtu_request_evt(p_gatt, p_ble_evt);
+ break;
+
+#if !defined (S112)
+ case BLE_GAP_EVT_DATA_LENGTH_UPDATE:
+ on_data_length_update_evt(p_gatt, p_ble_evt);
+ break;
+
+ case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST:
+ on_data_length_update_request_evt(p_gatt, p_ble_evt);
+ break;
+#endif // !defined (S112)
+
+ default:
+ break;
+ }
+
+ if (p_gatt->links[conn_handle].att_mtu_exchange_pending)
+ {
+ ret_code_t err_code;
+
+ err_code = sd_ble_gattc_exchange_mtu_request(conn_handle,
+ p_gatt->links[conn_handle].att_mtu_desired);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ p_gatt->links[conn_handle].att_mtu_exchange_pending = false;
+ p_gatt->links[conn_handle].att_mtu_exchange_requested = true;
+
+ NRF_LOG_DEBUG("Requesting to update ATT MTU to %u bytes on connection 0x%x (retry).",
+ p_gatt->links[conn_handle].att_mtu_desired, conn_handle);
+ }
+ else if (err_code != NRF_ERROR_BUSY)
+ {
+ NRF_LOG_ERROR("sd_ble_gattc_exchange_mtu_request() returned %s.",
+ nrf_strerror_get(err_code));
+ }
+ }
+}
+
+#endif //NRF_BLE_GATT_ENABLED
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/nrf_ble_gatt/nrf_ble_gatt.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/nrf_ble_gatt/nrf_ble_gatt.h
new file mode 100644
index 0000000..2970671
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/nrf_ble_gatt/nrf_ble_gatt.h
@@ -0,0 +1,242 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup nrf_ble_gatt GATT module
+ * @{
+ * @ingroup ble_sdk_lib
+ * @brief Module for negotiating and keeping track of GATT connection parameters and updating the data length.
+ */
+
+#ifndef NRF_BLE_GATT_H__
+#define NRF_BLE_GATT_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include "ble.h"
+#include "ble_gatt.h"
+#include "sdk_config.h"
+#include "sdk_errors.h"
+#include "app_util.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Macro for defining a nrf_ble_gatt instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define NRF_BLE_GATT_DEF(_name) \
+static nrf_ble_gatt_t _name; \
+NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ NRF_BLE_GATT_BLE_OBSERVER_PRIO, \
+ nrf_ble_gatt_on_ble_evt, &_name)
+
+/**@brief The maximum number of peripheral and central connections combined.
+ * This value is based on what is configured in the SoftDevice handler sdk_config.
+ */
+#define NRF_BLE_GATT_LINK_COUNT (NRF_SDH_BLE_PERIPHERAL_LINK_COUNT + NRF_SDH_BLE_CENTRAL_LINK_COUNT)
+
+
+/**@brief GATT module event types. */
+typedef enum
+{
+ NRF_BLE_GATT_EVT_ATT_MTU_UPDATED = 0xA77, //!< The ATT_MTU size was updated.
+ NRF_BLE_GATT_EVT_DATA_LENGTH_UPDATED = 0xDA7A, //!< The data length was updated.
+} nrf_ble_gatt_evt_id_t;
+
+/**@brief GATT module event. */
+typedef struct
+{
+ nrf_ble_gatt_evt_id_t evt_id; //!< Event ID.
+ uint16_t conn_handle; //!< Connection handle on which the event happened.
+ union
+ {
+ uint16_t att_mtu_effective; //!< Effective ATT_MTU.
+#if !defined (S112)
+ uint8_t data_length; //!< Data length value.
+#endif // !defined (S112)
+ } params;
+} nrf_ble_gatt_evt_t;
+
+// Forward declaration of the nrf_ble_gatt_t type.
+typedef struct nrf_ble_gatt_s nrf_ble_gatt_t;
+
+/**@brief GATT module event handler type.
+ *
+ * The GATT module calls a function of this type when a parameter value is changed.
+ */
+typedef void (*nrf_ble_gatt_evt_handler_t) (nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_t const * p_evt);
+
+/**@brief GATT information for each connection. */
+typedef struct
+{
+ uint16_t att_mtu_desired; //!< Requested ATT_MTU size (in bytes).
+ uint16_t att_mtu_effective; //!< Effective ATT_MTU size (in bytes).
+ bool att_mtu_exchange_pending; //!< Indicates that an ATT_MTU exchange request is pending (the call to @ref sd_ble_gattc_exchange_mtu_request returned @ref NRF_ERROR_BUSY).
+ bool att_mtu_exchange_requested; //!< Indicates that an ATT_MTU exchange request was made.
+#if !defined (S112)
+ uint8_t data_length_desired; //!< Desired data length (in bytes).
+ uint8_t data_length_effective; //!< Requested data length (in bytes).
+#endif // !defined (S112)
+} nrf_ble_gatt_link_t;
+
+
+/**@brief GATT structure that contains status information for the GATT module. */
+struct nrf_ble_gatt_s
+{
+ uint16_t att_mtu_desired_periph; //!< Requested ATT_MTU size for the next peripheral connection that is established.
+ uint16_t att_mtu_desired_central; //!< Requested ATT_MTU size for the next central connection that is established.
+ uint8_t data_length; //!< Data length to use for the next connection that is established.
+ nrf_ble_gatt_link_t links[NRF_BLE_GATT_LINK_COUNT]; //!< GATT related information for all active connections.
+ nrf_ble_gatt_evt_handler_t evt_handler; //!< GATT event handler.
+};
+
+
+/**@brief Function for initializing the GATT module.
+ *
+ * @param[in] evt_handler Event handler.
+ * @param[out] p_gatt Pointer to the GATT structure.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_NULL If @p p_gatt is NULL.
+ */
+ret_code_t nrf_ble_gatt_init(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_handler_t evt_handler);
+
+
+/**@brief Function for setting the ATT_MTU size for the next connection that is established as peripheral.
+ *
+ * @param[in] p_gatt Pointer to the GATT structure.
+ * @param[in] desired_mtu Requested ATT_MTU size.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_NULL If @p p_gatt is NULL.
+ * @retval NRF_ERROR_INVALID_PARAM If the size of @p desired_mtu is bigger than
+ * @ref NRF_SDH_BLE_GATT_MAX_MTU_SIZE or smaller than
+ * @ref BLE_GATT_ATT_MTU_DEFAULT.
+ */
+ret_code_t nrf_ble_gatt_att_mtu_periph_set(nrf_ble_gatt_t * p_gatt, uint16_t desired_mtu);
+
+
+/**@brief Function for setting the ATT_MTU size for the next connection that is established as central.
+ *
+ * @param[in,out] p_gatt Pointer to the GATT structure.
+ * @param[in] desired_mtu Requested ATT_MTU size.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_NULL If @p p_gatt is NULL.
+ * @retval NRF_ERROR_INVALID_PARAM If the size of @p desired_mtu is bigger than
+ * @ref NRF_SDH_BLE_GATT_MAX_MTU_SIZE or smaller
+ * than @ref BLE_GATT_ATT_MTU_DEFAULT.
+ */
+ret_code_t nrf_ble_gatt_att_mtu_central_set(nrf_ble_gatt_t * p_gatt, uint16_t desired_mtu);
+
+
+/**@brief Function for setting the data length for a connection.
+ *
+ * @details If @p conn_handle is a handle to an existing connection, a data length update
+ * request is sent on that connection.
+ * If @p conn_handle is @ref BLE_CONN_HANDLE_INVALID, a data length update request
+ * is sent on the next connection that is established after the ATT_MTU
+ * exchange has completed. If no ATT_MTU exchange procedure is carried
+ * out (for example, if a default ATT_MTU size is used), the data length
+ * is not changed.
+ */
+#if !defined (S112)
+ret_code_t nrf_ble_gatt_data_length_set(nrf_ble_gatt_t * p_gatt,
+ uint16_t conn_handle,
+ uint8_t data_length);
+#endif // !defined (S112)
+
+/**@brief Function for retrieving the data length of a connection.
+ *
+ * @details If @p conn_handle is @ref BLE_CONN_HANDLE_INVALID, the function retrieves the data
+ * length that will be requested for the next connection.
+ * If @p conn_handle is a handle to an existing connection, the function retrieves
+ * the effective data length that was negotiated for that connection.
+ *
+ * @param[in,out] p_gatt Pointer to the GATT structure.
+ * @param[in] conn_handle The connection for which to retrieve the data length, or
+ * @ref BLE_CONN_HANDLE_INVALID to retrieve the requested data length
+ * for the next connection.
+ * @param[out] p_data_length The connection data length.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_NULL If @p p_gatt or @p p_data_length is NULL.
+ * @retval NRF_ERROR_INVALID_PARAM If @p conn_handle is larger than @ref NRF_BLE_GATT_LINK_COUNT.
+ */
+#if !defined (S112)
+ret_code_t nrf_ble_gatt_data_length_get(nrf_ble_gatt_t const * p_gatt,
+ uint16_t conn_handle,
+ uint8_t * p_data_length);
+#endif // !defined (S112)
+
+/**@brief Function for handling BLE stack events.
+ *
+ * @details This function handles events from the BLE stack that are of interest to the module.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Pointer to the GATT structure.
+ */
+void nrf_ble_gatt_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+/**@brief Function for getting the current ATT_MTU size for a given connection.
+ *
+ * @param[in] p_gatt Pointer to the GATT structure.
+ * @param[in] conn_handle Connection handle of the connection.
+ *
+ * @return ATT_MTU size for the given connection.
+ * @retval 0 If @p p_gatt is NULL or if @p conn_handle is larger than
+ * the supported maximum number of connections.
+ */
+uint16_t nrf_ble_gatt_eff_mtu_get(nrf_ble_gatt_t const * p_gatt, uint16_t conn_handle);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // NRF_BLE_GATT_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/nrf_ble_qwr/nrf_ble_qwr.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/nrf_ble_qwr/nrf_ble_qwr.c
new file mode 100644
index 0000000..0f06372
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/nrf_ble_qwr/nrf_ble_qwr.c
@@ -0,0 +1,488 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(NRF_BLE_QWR)
+#include <stdlib.h>
+#include "nrf_ble_qwr.h"
+#include "ble.h"
+#include "ble_srv_common.h"
+
+
+#define NRF_BLE_QWR_INITIALIZED 0xDE // Non-zero value used to make sure the given structure has been initialized by the module.
+#define MODULE_INITIALIZED (p_qwr->initialized == NRF_BLE_QWR_INITIALIZED)
+#include "sdk_macros.h"
+
+ret_code_t nrf_ble_qwr_init(nrf_ble_qwr_t * p_qwr,
+ nrf_ble_qwr_init_t const * p_qwr_init)
+{
+ VERIFY_PARAM_NOT_NULL(p_qwr);
+ VERIFY_PARAM_NOT_NULL(p_qwr_init);
+ if (MODULE_INITIALIZED)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ p_qwr->error_handler = p_qwr_init->error_handler;
+ p_qwr->initialized = NRF_BLE_QWR_INITIALIZED;
+ p_qwr->conn_handle = BLE_CONN_HANDLE_INVALID;
+#if (NRF_BLE_QWR_MAX_ATTR > 0)
+ memset(p_qwr->attr_handles, 0, sizeof(p_qwr->attr_handles));
+ p_qwr->nb_registered_attr = 0;
+ p_qwr->is_user_mem_reply_pending = false;
+ p_qwr->mem_buffer = p_qwr_init->mem_buffer;
+ p_qwr->callback = p_qwr_init->callback;
+ p_qwr->nb_written_handles = 0;
+#endif
+ return NRF_SUCCESS;
+}
+
+
+#if (NRF_BLE_QWR_MAX_ATTR > 0)
+ret_code_t nrf_ble_qwr_attr_register(nrf_ble_qwr_t * p_qwr, uint16_t attr_handle)
+{
+ VERIFY_PARAM_NOT_NULL(p_qwr);
+ VERIFY_MODULE_INITIALIZED();
+
+ if ((p_qwr->nb_registered_attr == NRF_BLE_QWR_MAX_ATTR)
+ || (p_qwr->mem_buffer.p_mem == NULL)
+ || (p_qwr->mem_buffer.len == 0))
+ {
+ return (NRF_ERROR_NO_MEM);
+ }
+
+ if (attr_handle == BLE_GATT_HANDLE_INVALID)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ p_qwr->attr_handles[p_qwr->nb_registered_attr] = attr_handle;
+ p_qwr->nb_registered_attr++;
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t nrf_ble_qwr_value_get(nrf_ble_qwr_t * p_qwr,
+ uint16_t attr_handle,
+ uint8_t * p_mem,
+ uint16_t * p_len)
+{
+ VERIFY_PARAM_NOT_NULL(p_qwr);
+ VERIFY_PARAM_NOT_NULL(p_mem);
+ VERIFY_PARAM_NOT_NULL(p_len);
+ VERIFY_MODULE_INITIALIZED();
+
+ uint16_t i = 0;
+ uint16_t handle = BLE_GATT_HANDLE_INVALID;
+ uint16_t val_len = 0;
+ uint16_t val_offset = 0;
+ uint16_t cur_len = 0;
+
+ do
+ {
+ handle = uint16_decode(&(p_qwr->mem_buffer.p_mem[i]));
+
+ if (handle == BLE_GATT_HANDLE_INVALID)
+ {
+ break;
+ }
+
+ i += sizeof(uint16_t);
+ val_offset = uint16_decode(&(p_qwr->mem_buffer.p_mem[i]));
+ i += sizeof(uint16_t);
+ val_len = uint16_decode(&(p_qwr->mem_buffer.p_mem[i]));
+ i += sizeof(uint16_t);
+
+ if (handle == attr_handle)
+ {
+ cur_len = val_offset + val_len;
+ if (cur_len <= *p_len)
+ {
+ memcpy((p_mem + val_offset), &(p_qwr->mem_buffer.p_mem[i]), val_len);
+ }
+ else
+ {
+ return NRF_ERROR_NO_MEM;
+ }
+ }
+
+ i += val_len;
+ }
+ while (i < p_qwr->mem_buffer.len);
+
+ *p_len = cur_len;
+ return NRF_SUCCESS;
+}
+#endif
+
+
+ret_code_t nrf_ble_qwr_conn_handle_assign(nrf_ble_qwr_t * p_qwr,
+ uint16_t conn_handle)
+{
+ VERIFY_PARAM_NOT_NULL(p_qwr);
+ VERIFY_MODULE_INITIALIZED();
+ p_qwr->conn_handle = conn_handle;
+ return NRF_SUCCESS;
+}
+
+
+/**@brief checks if a user_mem_reply is pending, if so attempts to send it.
+ *
+ * @param[in] p_qwr QWR structure.
+ */
+static void user_mem_reply(nrf_ble_qwr_t * p_qwr)
+{
+ if (p_qwr->is_user_mem_reply_pending)
+ {
+ ret_code_t err_code;
+#if (NRF_BLE_QWR_MAX_ATTR == 0)
+ err_code = sd_ble_user_mem_reply(p_qwr->conn_handle, NULL);
+#else
+ err_code = sd_ble_user_mem_reply(p_qwr->conn_handle, &p_qwr->mem_buffer);
+#endif
+ if (err_code == NRF_SUCCESS)
+ {
+ p_qwr->is_user_mem_reply_pending = false;
+ }
+ else if (err_code == NRF_ERROR_BUSY)
+ {
+ p_qwr->is_user_mem_reply_pending = true;
+ }
+ else
+ {
+ p_qwr->error_handler(err_code);
+ }
+ }
+}
+
+
+/**@brief Handle a user memory request event.
+ *
+ * @param[in] p_qwr QWR structure.
+ * @param[in] p_common_evt User_mem_request event to be handled.
+ */
+static void on_user_mem_request(nrf_ble_qwr_t * p_qwr,
+ ble_common_evt_t const * p_common_evt)
+{
+ if ((p_common_evt->params.user_mem_request.type == BLE_USER_MEM_TYPE_GATTS_QUEUED_WRITES) &&
+ (p_common_evt->conn_handle == p_qwr->conn_handle))
+ {
+ p_qwr->is_user_mem_reply_pending = true;
+ user_mem_reply(p_qwr);
+ }
+}
+
+
+/**@brief Handle a user memory release event.
+ *
+ * @param[in] p_qwr QWR structure.
+ * @param[in] p_common_evt User_mem_release event to be handled.
+ */
+static void on_user_mem_release(nrf_ble_qwr_t * p_qwr,
+ ble_common_evt_t const * p_common_evt)
+{
+#if (NRF_BLE_QWR_MAX_ATTR > 0)
+ if ((p_common_evt->params.user_mem_release.type == BLE_USER_MEM_TYPE_GATTS_QUEUED_WRITES) &&
+ (p_common_evt->conn_handle == p_qwr->conn_handle))
+ {
+ // Cancel the current operation.
+ p_qwr->nb_written_handles = 0;
+ }
+#endif
+}
+
+
+#if (NRF_BLE_QWR_MAX_ATTR > 0)
+/**@brief Handle a prepare write event.
+ *
+ * @param[in] p_qwr QWR structure.
+ * @param[in] p_evt_write WRITE event to be handled.
+ */
+static void on_prepare_write(nrf_ble_qwr_t * p_qwr,
+ ble_gatts_evt_write_t const * p_evt_write)
+{
+ uint32_t err_code;
+ ble_gatts_rw_authorize_reply_params_t auth_reply;
+ memset(&auth_reply, 0, sizeof(auth_reply));
+
+ auth_reply.params.write.gatt_status = NRF_BLE_QWR_REJ_REQUEST_ERR_CODE;
+ auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
+
+ uint32_t i;
+
+ for (i = 0; i < p_qwr->nb_written_handles; i++)
+ {
+ if (p_qwr->written_attr_handles[i] == p_evt_write->handle)
+ {
+ auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ break;
+ }
+ }
+
+ if (auth_reply.params.write.gatt_status != BLE_GATT_STATUS_SUCCESS)
+ {
+ for (i = 0; i < p_qwr->nb_registered_attr; i++)
+ {
+ if (p_qwr->attr_handles[i] == p_evt_write->handle)
+ {
+ auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ p_qwr->written_attr_handles[p_qwr->nb_written_handles++] = p_evt_write->handle;
+ break;
+ }
+ }
+ }
+
+ err_code = sd_ble_gatts_rw_authorize_reply(p_qwr->conn_handle, &auth_reply);
+ if (err_code != NRF_SUCCESS)
+ {
+ // Cancel the current operation.
+ p_qwr->nb_written_handles = 0;
+
+ // Report error to application.
+ p_qwr->error_handler(err_code);
+ }
+
+}
+
+
+/**@brief Handle an execute write event.
+ *
+ * @param[in] p_qwr QWR structure.
+ * @param[in] p_evt_write EXEC WRITE event to be handled.
+ */
+static void on_execute_write(nrf_ble_qwr_t * p_qwr,
+ ble_gatts_evt_write_t const * p_evt_write)
+{
+ uint32_t err_code;
+ ble_gatts_rw_authorize_reply_params_t auth_reply;
+ memset(&auth_reply, 0, sizeof(auth_reply));
+
+ auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
+
+ if (p_qwr->nb_written_handles == 0)
+ {
+ auth_reply.params.write.gatt_status = NRF_BLE_QWR_REJ_REQUEST_ERR_CODE;
+ err_code = sd_ble_gatts_rw_authorize_reply(p_qwr->conn_handle, &auth_reply);
+ if (err_code != NRF_SUCCESS)
+ {
+ // Report error to application.
+ p_qwr->error_handler(err_code);
+ }
+ return;
+ }
+
+ for (uint16_t i = 0; i < p_qwr->nb_written_handles; i++)
+ {
+ nrf_ble_qwr_evt_t evt;
+ uint16_t ret_val;
+
+ evt.evt_type = NRF_BLE_QWR_EVT_AUTH_REQUEST;
+ evt.attr_handle = p_qwr->written_attr_handles[i];
+ ret_val = p_qwr->callback(p_qwr, &evt);
+ if (ret_val != BLE_GATT_STATUS_SUCCESS)
+ {
+ auth_reply.params.write.gatt_status = ret_val;
+ }
+ }
+
+ err_code = sd_ble_gatts_rw_authorize_reply(p_qwr->conn_handle, &auth_reply);
+ if (err_code != NRF_SUCCESS)
+ {
+ // Report error to application.
+ p_qwr->error_handler(err_code);
+ }
+
+ // If the execute has not been rejected by any of the registered applications, propagate execute write event to all written handles. */
+ if (auth_reply.params.write.gatt_status == BLE_GATT_STATUS_SUCCESS)
+ {
+ for (uint16_t i = 0; i < p_qwr->nb_written_handles; i++)
+ {
+ nrf_ble_qwr_evt_t evt;
+ evt.evt_type = NRF_BLE_QWR_EVT_EXECUTE_WRITE;
+ evt.attr_handle = p_qwr->written_attr_handles[i];
+ /*lint -e534 -save "Ignoring return value of function" */
+ p_qwr->callback(p_qwr, &evt);
+ /*lint -restore*/
+
+ auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ }
+ }
+ p_qwr->nb_written_handles = 0;
+}
+
+
+/**@brief Handle a cancel write event.
+ *
+ * @param[in] p_qwr QWR structure.
+ * @param[in] p_evt_write EXEC WRITE event to be handled.
+ */
+static void on_cancel_write(nrf_ble_qwr_t * p_qwr,
+ ble_gatts_evt_write_t const * p_evt_write)
+{
+ uint32_t err_code;
+ ble_gatts_rw_authorize_reply_params_t auth_reply;
+ memset(&auth_reply, 0, sizeof(auth_reply));
+
+ auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
+ auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+
+ err_code = sd_ble_gatts_rw_authorize_reply(p_qwr->conn_handle, &auth_reply);
+ if (err_code != NRF_SUCCESS)
+ {
+ // Report error to application.
+ p_qwr->error_handler(err_code);
+ }
+ p_qwr->nb_written_handles = 0;
+}
+#endif
+
+/**@brief Handle a rw_authorize_request event.
+ *
+ * @param[in] p_qwr QWR structure.
+ * @param[in] p_gatts_evt RW_authorize_request event to be handled.
+ */
+static void on_rw_authorize_request(nrf_ble_qwr_t * p_qwr,
+ ble_gatts_evt_t const * p_gatts_evt)
+{
+ if (p_gatts_evt->conn_handle != p_qwr->conn_handle)
+ {
+ return;
+ }
+
+ ble_gatts_evt_rw_authorize_request_t const * p_auth_req = &p_gatts_evt->params.authorize_request;
+
+ if (p_auth_req->type != BLE_GATTS_AUTHORIZE_TYPE_WRITE)
+ {
+ return;
+ }
+
+#if (NRF_BLE_QWR_MAX_ATTR == 0)
+ // Handle only queued write related operations.
+ if ((p_auth_req->request.write.op != BLE_GATTS_OP_PREP_WRITE_REQ) &&
+ (p_auth_req->request.write.op != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW) &&
+ (p_auth_req->request.write.op != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL))
+ {
+ return;
+ }
+
+ // Prepare the response.
+ ble_gatts_rw_authorize_reply_params_t auth_reply = {0};
+
+ auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
+ auth_reply.params.write.gatt_status = NRF_BLE_QWR_REJ_REQUEST_ERR_CODE;
+ if (p_auth_req->request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)
+ {
+ auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
+ }
+
+ ret_code_t err_code = sd_ble_gatts_rw_authorize_reply(p_gatts_evt->conn_handle, &auth_reply);
+ if (err_code != NRF_SUCCESS)
+ {
+ // Report error to application.
+ p_qwr->error_handler(err_code);
+ }
+#else
+ switch (p_auth_req->request.write.op)
+ {
+ case BLE_GATTS_OP_PREP_WRITE_REQ:
+ on_prepare_write(p_qwr, &p_auth_req->request.write);
+ break; // BLE_GATTS_OP_PREP_WRITE_REQ
+
+ case BLE_GATTS_OP_EXEC_WRITE_REQ_NOW:
+ on_execute_write(p_qwr, &p_auth_req->request.write);
+ break; // BLE_GATTS_OP_EXEC_WRITE_REQ_NOW
+
+ case BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL:
+ on_cancel_write(p_qwr, &p_auth_req->request.write);
+ break; // BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL
+
+ default:
+ // No implementation needed.
+ break;
+ }
+#endif
+}
+
+
+void nrf_ble_qwr_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ VERIFY_PARAM_NOT_NULL_VOID(p_context);
+ VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
+
+ nrf_ble_qwr_t * p_qwr = (nrf_ble_qwr_t *)p_context;
+
+ VERIFY_MODULE_INITIALIZED_VOID();
+
+ if (p_ble_evt->evt.common_evt.conn_handle == p_qwr->conn_handle)
+ {
+ user_mem_reply(p_qwr);
+ }
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_EVT_USER_MEM_REQUEST:
+ on_user_mem_request(p_qwr, &p_ble_evt->evt.common_evt);
+ break; // BLE_EVT_USER_MEM_REQUEST
+
+ case BLE_EVT_USER_MEM_RELEASE:
+ on_user_mem_release(p_qwr, &p_ble_evt->evt.common_evt);
+ break; // BLE_EVT_USER_MEM_REQUEST
+
+ case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
+ on_rw_authorize_request(p_qwr, &p_ble_evt->evt.gatts_evt);
+ break; // BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ if (p_ble_evt->evt.gap_evt.conn_handle == p_qwr->conn_handle)
+ {
+ p_qwr->conn_handle = BLE_CONN_HANDLE_INVALID;
+#if (NRF_BLE_QWR_MAX_ATTR > 0)
+ p_qwr->nb_written_handles = 0;
+#endif
+ }
+ break; // BLE_GAP_EVT_DISCONNECTED
+
+ default:
+ break;
+ }
+
+}
+#endif // NRF_MODULE_ENABLED(NRF_BLE_QWR)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/nrf_ble_qwr/nrf_ble_qwr.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/nrf_ble_qwr/nrf_ble_qwr.h
new file mode 100644
index 0000000..6ec27cb
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/nrf_ble_qwr/nrf_ble_qwr.h
@@ -0,0 +1,246 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup nrf_ble_qwr Queued Writes module
+ * @{
+ * @ingroup ble_sdk_lib
+ * @brief Module for handling Queued Write operations.
+ *
+ * @details This module handles prepare write, execute write, and cancel write
+ * commands. It also manages memory requests related to these operations.
+ *
+ * @note The application must propagate BLE stack events to this module by calling
+ * @ref nrf_ble_qwr_on_ble_evt().
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef NRF_BLE_QUEUED_WRITES_H__
+#define NRF_BLE_QUEUED_WRITES_H__
+
+#include <stdint.h>
+#include "nordic_common.h"
+#include "sdk_common.h"
+#include "ble.h"
+#include "ble_srv_common.h"
+
+/**@brief Macro for defining a nrf_ble_qwr instance.
+ *
+ * @param _name Name of the instance.
+ * @hideinitializer
+ */
+#define NRF_BLE_QWR_DEF(_name) \
+ static nrf_ble_qwr_t _name; \
+ NRF_SDH_BLE_OBSERVER(_name ## _obs, \
+ NRF_BLE_QWR_BLE_OBSERVER_PRIO, \
+ nrf_ble_qwr_on_ble_evt, \
+ &_name)
+
+/**@brief Macro for defining an array of nrf_ble_qwr instance.
+ *
+ * @param _name Name of the array.
+ * @param _cnt Size of the array.
+ * @hideinitializer
+ */
+#define NRF_BLE_QWRS_DEF(_name, _cnt) \
+ static nrf_ble_qwr_t _name[_cnt]; \
+ NRF_SDH_BLE_OBSERVERS(_name ## _obs, \
+ NRF_BLE_QWR_BLE_OBSERVER_PRIO, \
+ nrf_ble_qwr_on_ble_evt, \
+ &_name, \
+ _cnt)
+
+
+#define NRF_BLE_QWR_REJ_REQUEST_ERR_CODE BLE_GATT_STATUS_ATTERR_APP_BEGIN + 0 //!< Error code used by the module to reject prepare write requests on non-registered attributes.
+
+
+/**@brief Queued Writes module event types. */
+typedef enum
+{
+ NRF_BLE_QWR_EVT_EXECUTE_WRITE, //!< Event that indicates that an execute write command was received for a registered handle and that the received data was actually written and is now ready.
+ NRF_BLE_QWR_EVT_AUTH_REQUEST, //!< Event that indicates that an execute write command was received for a registered handle and that the write request must now be accepted or rejected.
+} nrf_ble_qwr_evt_type_t;
+
+/**@brief Queued Writes module events. */
+typedef struct
+{
+ nrf_ble_qwr_evt_type_t evt_type; //!< Type of the event.
+ uint16_t attr_handle; //!< Handle of the attribute to which the event relates.
+} nrf_ble_qwr_evt_t;
+
+// Forward declaration of the nrf_ble_qwr_t type.
+struct nrf_ble_qwr_t;
+
+/**@brief Queued Writes module event handler type.
+ *
+ * If the provided event is of type @ref NRF_BLE_QWR_EVT_AUTH_REQUEST,
+ * this function must accept or reject the execute write request by returning
+ * one of the @ref BLE_GATT_STATUS_CODES.*/
+typedef uint16_t (* nrf_ble_qwr_evt_handler_t) (struct nrf_ble_qwr_t * p_qwr,
+ nrf_ble_qwr_evt_t * p_evt);
+
+/**@brief Queued Writes structure.
+ * @details This structure contains status information for the Queued Writes module. */
+typedef struct nrf_ble_qwr_t
+{
+ uint8_t initialized; //!< Flag that indicates whether the module has been initialized.
+ uint16_t conn_handle; //!< Connection handle.
+ ble_srv_error_handler_t error_handler; //!< Error handler.
+ bool is_user_mem_reply_pending; //!< Flag that indicates whether a mem_reply is pending (because a previous attempt returned busy).
+#if (NRF_BLE_QWR_MAX_ATTR > 0)
+ uint16_t attr_handles[NRF_BLE_QWR_MAX_ATTR]; //!< List of handles for registered attributes, for which the module accepts and handles prepare write operations.
+ uint8_t nb_registered_attr; //!< Number of registered attributes.
+ uint16_t written_attr_handles[NRF_BLE_QWR_MAX_ATTR]; //!< List of attribute handles that have been written to during the current prepare write or execute write operation.
+ uint8_t nb_written_handles; //!< Number of attributes that have been written to during the current prepare write or execute write operation.
+ ble_user_mem_block_t mem_buffer; //!< Memory buffer that is provided to the SoftDevice on an ON_USER_MEM_REQUEST event.
+ nrf_ble_qwr_evt_handler_t callback; //!< Event handler function that is called for events concerning the handles of all registered attributes.
+#endif
+} nrf_ble_qwr_t;
+
+/**@brief Queued Writes init structure.
+ * @details This structure contains all information
+ * that is needed to initialize the Queued Writes module. */
+typedef struct
+{
+ ble_srv_error_handler_t error_handler; //!< Error handler.
+#if (NRF_BLE_QWR_MAX_ATTR > 0)
+ ble_user_mem_block_t mem_buffer; //!< Memory buffer that is provided to the SoftDevice on an ON_USER_MEM_REQUEST event.
+ nrf_ble_qwr_evt_handler_t callback; //!< Event handler function that is called for events concerning the handles of all registered attributes.
+#endif
+} nrf_ble_qwr_init_t;
+
+
+/**@brief Function for initializing the Queued Writes module.
+ *
+ * @details Call this function in the main entry of your application to
+ * initialize the Queued Writes module. It must be called only once with a
+ * given Queued Writes structure.
+ *
+ * @param[out] p_qwr Queued Writes structure. This structure must be
+ * supplied by the application. It is initialized by this function
+ * and is later used to identify the particular Queued Writes instance.
+ * @param[in] p_qwr_init Initialization structure.
+ *
+ * @retval NRF_SUCCESS If the Queued Writes module was initialized successfully.
+ * @retval NRF_ERROR_NULL If any of the given pointers is NULL.
+ * @retval NRF_ERROR_INVALID_STATE If the given context has already been initialized.
+ */
+ret_code_t nrf_ble_qwr_init(nrf_ble_qwr_t * p_qwr,
+ nrf_ble_qwr_init_t const * p_qwr_init);
+
+
+/**@brief Function for assigning a connection handle to a given instance of the Queued Writes module.
+ *
+ * @details Call this function when a link with a peer has been established to
+ * associate this link to the instance of the module. This makes it
+ * possible to handle several links and associate each link to a particular
+ * instance of this module.
+ *
+ * @param[in] p_qwr Queued Writes structure.
+ * @param[in] conn_handle Connection handle to be associated with the given Queued Writes instance.
+ *
+ * @retval NRF_SUCCESS If the assignment was successful.
+ * @retval NRF_ERROR_NULL If any of the given pointers is NULL.
+ * @retval NRF_ERROR_INVALID_STATE If the given context has not been initialized.
+ */
+ret_code_t nrf_ble_qwr_conn_handle_assign(nrf_ble_qwr_t * p_qwr,
+ uint16_t conn_handle);
+
+
+/**@brief Function for handling BLE stack events.
+ *
+ * @details Handles all events from the BLE stack that are of interest to the Queued Writes module.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Queued Writes structure.
+ */
+void nrf_ble_qwr_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+
+#if (NRF_BLE_QWR_MAX_ATTR > 0)
+/**@brief Function for registering an attribute with the Queued Writes module.
+ *
+ * @details Call this function for each attribute that you want to enable for
+ * Queued Writes (thus a series of prepare write and execute write operations).
+ *
+ * @param[in] p_qwr Queued Writes structure.
+ * @param[in] attr_handle Handle of the attribute to register.
+ *
+ * @retval NRF_SUCCESS If the registration was successful.
+ * @retval NRF_ERROR_NO_MEM If no more memory is available to add this registration.
+ * @retval NRF_ERROR_NULL If any of the given pointers is NULL.
+ * @retval NRF_ERROR_INVALID_STATE If the given context has not been initialized.
+ */
+ret_code_t nrf_ble_qwr_attr_register(nrf_ble_qwr_t * p_qwr, uint16_t attr_handle);
+
+
+/**@brief Function for retrieving the received data for a given attribute.
+ *
+ * @details Call this function after receiving an @ref NRF_BLE_QWR_EVT_AUTH_REQUEST
+ * event to retrieve a linear copy of the data that was received for the given attribute.
+ *
+ * @param[in] p_qwr Queued Writes structure.
+ * @param[in] attr_handle Handle of the attribute.
+ * @param[out] p_mem Pointer to the application buffer where the received data will be copied.
+ * @param[in,out] p_len Input: length of the input buffer. Output: length of the received data.
+ *
+ *
+ * @retval NRF_SUCCESS If the data was retrieved and stored successfully.
+ * @retval NRF_ERROR_NO_MEM If the provided buffer was smaller than the received data.
+ * @retval NRF_ERROR_NULL If any of the given pointers is NULL.
+ * @retval NRF_ERROR_INVALID_STATE If the given context has not been initialized.
+ */
+ret_code_t nrf_ble_qwr_value_get(nrf_ble_qwr_t * p_qwr,
+ uint16_t attr_handle,
+ uint8_t * p_mem,
+ uint16_t * p_len);
+#endif // (NRF_BLE_QWR_MAX_ATTR > 0)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // NRF_BLE_QUEUED_WRITES_H__
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatt_cache_manager.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatt_cache_manager.c
new file mode 100644
index 0000000..053a389
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatt_cache_manager.c
@@ -0,0 +1,578 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "gatt_cache_manager.h"
+
+#include "ble_gap.h"
+#include "ble_err.h"
+#include "ble_conn_state.h"
+#include "peer_manager_types.h"
+#include "peer_manager_internal.h"
+#include "id_manager.h"
+#include "gatts_cache_manager.h"
+#include "peer_database.h"
+#include "pm_mutex.h"
+
+
+// The number of registered event handlers.
+#define GCM_EVENT_HANDLERS_CNT (sizeof(m_evt_handlers) / sizeof(m_evt_handlers[0]))
+
+// GATT Cache Manager event handler in Peer Manager.
+extern void pm_gcm_evt_handler(pm_evt_t * p_gcm_evt);
+
+// GATT Cache Manager events' handlers.
+// The number of elements in this array is GCM_EVENT_HANDLERS_CNT.
+static pm_evt_handler_internal_t m_evt_handlers[] =
+{
+ pm_gcm_evt_handler
+};
+
+static bool m_module_initialized;
+static uint8_t m_db_update_in_progress_mutex; /**< Mutex indicating whether a local DB write operation is ongoing. */
+static ble_conn_state_user_flag_id_t m_flag_local_db_update_pending; /**< Flag ID for flag collection to keep track of which connections need a local DB update procedure. */
+static ble_conn_state_user_flag_id_t m_flag_local_db_apply_pending; /**< Flag ID for flag collection to keep track of which connections need a local DB apply procedure. */
+static ble_conn_state_user_flag_id_t m_flag_service_changed_pending; /**< Flag ID for flag collection to keep track of which connections need to be sent a service changed indication. */
+static ble_conn_state_user_flag_id_t m_flag_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. */
+
+#ifdef PM_SERVICE_CHANGED_ENABLED
+ STATIC_ASSERT(PM_SERVICE_CHANGED_ENABLED || !NRF_SDH_BLE_SERVICE_CHANGED,
+ "PM_SERVICE_CHANGED_ENABLED should be enabled if NRF_SDH_BLE_SERVICE_CHANGED is enabled.");
+#else
+ #define PM_SERVICE_CHANGED_ENABLED 1
+#endif
+
+/**@brief Function for resetting the module variable(s) of the GSCM module.
+ *
+ * @param[out] The instance to reset.
+ */
+static void internal_state_reset()
+{
+ m_module_initialized = false;
+}
+
+
+static void evt_send(pm_evt_t * p_gcm_evt)
+{
+ p_gcm_evt->peer_id = im_peer_id_get_by_conn_handle(p_gcm_evt->conn_handle);
+
+ for (uint32_t i = 0; i < GCM_EVENT_HANDLERS_CNT; i++)
+ {
+ m_evt_handlers[i](p_gcm_evt);
+ }
+}
+
+
+/**@brief Function for checking a write event for whether a CCCD was written during the write
+ * operation.
+ *
+ * @param[in] p_write_evt The parameters of the write event.
+ *
+ * @return Whether the write was on a CCCD.
+ */
+static bool cccd_written(ble_gatts_evt_write_t const * p_write_evt)
+{
+ return ( (p_write_evt->op == BLE_GATTS_OP_WRITE_REQ)
+ && (p_write_evt->uuid.type == BLE_UUID_TYPE_BLE)
+ && (p_write_evt->uuid.uuid == BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG)
+ );
+}
+
+
+/**@brief Function for sending an PM_EVT_ERROR_UNEXPECTED event.
+ *
+ * @param[in] conn_handle The connection handle the event pertains to.
+ * @param[in] err_code The unexpected error that occurred.
+ */
+static void send_unexpected_error(uint16_t conn_handle, ret_code_t err_code)
+{
+ pm_evt_t error_evt =
+ {
+ .evt_id = PM_EVT_ERROR_UNEXPECTED,
+ .conn_handle = conn_handle,
+ .params =
+ {
+ .error_unexpected =
+ {
+ .error = err_code,
+ }
+ }
+ };
+ evt_send(&error_evt);
+}
+
+
+/**@brief Function for performing the local DB update procedure in an event context, where no return
+ * code can be given.
+ *
+ * @details This function will do the procedure, and check the result, set a flag if needed, and
+ * send an event if needed.
+ *
+ * @param[in] conn_handle The connection to perform the procedure on.
+ */
+static void local_db_apply_in_evt(uint16_t conn_handle)
+{
+ bool set_procedure_as_pending = false;
+ ret_code_t err_code;
+ pm_evt_t event =
+ {
+ .conn_handle = conn_handle,
+ };
+
+ if (conn_handle == BLE_CONN_HANDLE_INVALID)
+ {
+ return;
+ }
+
+ err_code = gscm_local_db_cache_apply(conn_handle);
+
+ switch (err_code)
+ {
+ case NRF_SUCCESS:
+ event.evt_id = PM_EVT_LOCAL_DB_CACHE_APPLIED;
+
+ evt_send(&event);
+ break;
+
+ case NRF_ERROR_BUSY:
+ set_procedure_as_pending = true;
+ break;
+
+ case NRF_ERROR_INVALID_DATA:
+ event.evt_id = PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED;
+
+ evt_send(&event);
+ break;
+
+ case BLE_ERROR_INVALID_CONN_HANDLE:
+ /* Do nothing */
+ break;
+
+ default:
+ send_unexpected_error(conn_handle, err_code);
+ break;
+ }
+
+ ble_conn_state_user_flag_set(conn_handle, m_flag_local_db_apply_pending, set_procedure_as_pending);
+}
+
+
+/**@brief Function for asynchronously starting a DB update procedure.
+ *
+ * @note This procedure can only be started asynchronously.
+ *
+ * @param[in] conn_handle The connection to perform the procedure on.
+ * @param[in] update Whether to perform the procedure.
+ */
+static __INLINE void local_db_update(uint16_t conn_handle, bool update)
+{
+ ble_conn_state_user_flag_set(conn_handle, m_flag_local_db_update_pending, update);
+}
+
+
+/**@brief Function for performing the local DB update procedure in an event context, where no return
+ * code can be given.
+ *
+ * @details This function will do the procedure, and check the result, set a flag if needed, and
+ * send an event if needed.
+ *
+ * @param[in] conn_handle The connection to perform the procedure on.
+ */
+static bool local_db_update_in_evt(uint16_t conn_handle)
+{
+ bool set_procedure_as_pending = false;
+ bool success = false;
+ ret_code_t err_code = gscm_local_db_cache_update(conn_handle);
+
+ switch (err_code)
+ {
+ case NRF_SUCCESS:
+ success = true;
+ break;
+
+ case BLE_ERROR_INVALID_CONN_HANDLE:
+ /* Do nothing */
+ break;
+
+ case NRF_ERROR_BUSY:
+ set_procedure_as_pending = true;
+ break;
+
+ case NRF_ERROR_STORAGE_FULL:
+ {
+ pm_evt_t event =
+ {
+ .evt_id = PM_EVT_STORAGE_FULL,
+ .conn_handle = conn_handle,
+ };
+
+ evt_send(&event);
+ break;
+ }
+
+ default:
+ send_unexpected_error(conn_handle, err_code);
+ break;
+ }
+
+ local_db_update(conn_handle, set_procedure_as_pending);
+
+ return success;
+}
+
+#if PM_SERVICE_CHANGED_ENABLED
+/**@brief Function for sending a service changed indication in an event context, where no return
+ * code can be given.
+ *
+ * @details This function will do the procedure, and check the result, set a flag if needed, and
+ * send an event if needed.
+ *
+ * @param[in] conn_handle The connection to perform the procedure on.
+ */
+static void service_changed_send_in_evt(uint16_t conn_handle)
+{
+ bool sc_pending_state = true;
+ bool sc_sent_state = false;
+ ret_code_t err_code = gscm_service_changed_ind_send(conn_handle);
+
+ switch (err_code)
+ {
+ case NRF_SUCCESS:
+ {
+ pm_evt_t event =
+ {
+ .evt_id = PM_EVT_SERVICE_CHANGED_IND_SENT,
+ .conn_handle = conn_handle,
+ };
+
+ sc_sent_state = true;
+
+ evt_send(&event);
+ break;
+ }
+
+ case NRF_ERROR_BUSY:
+ // Do nothing.
+ break;
+
+ case NRF_ERROR_INVALID_STATE:
+ // CCCDs not enabled. Drop indication.
+ // Fallthrough.
+
+ case NRF_ERROR_NOT_SUPPORTED:
+ // Service changed not supported. Drop indication.
+ sc_pending_state = false;
+ gscm_db_change_notification_done(im_peer_id_get_by_conn_handle(conn_handle));
+ break;
+
+ case BLE_ERROR_GATTS_SYS_ATTR_MISSING:
+ local_db_apply_in_evt(conn_handle);
+ break;
+
+ case BLE_ERROR_INVALID_CONN_HANDLE:
+ // Do nothing.
+ break;
+
+ default:
+ send_unexpected_error(conn_handle, err_code);
+ break;
+ }
+
+ ble_conn_state_user_flag_set(conn_handle, m_flag_service_changed_pending, sc_pending_state);
+ ble_conn_state_user_flag_set(conn_handle, m_flag_service_changed_sent, sc_sent_state);
+}
+#endif
+
+static void apply_pending_handle(uint16_t conn_handle, void * p_context)
+{
+ UNUSED_PARAMETER(p_context);
+ local_db_apply_in_evt(conn_handle);
+}
+
+
+static __INLINE void apply_pending_flags_check(void)
+{
+ UNUSED_RETURN_VALUE(ble_conn_state_for_each_set_user_flag(m_flag_local_db_apply_pending,
+ apply_pending_handle,
+ NULL));
+}
+
+
+static void db_update_pending_handle(uint16_t conn_handle, void * p_context)
+{
+ UNUSED_PARAMETER(p_context);
+ if (pm_mutex_lock(&m_db_update_in_progress_mutex, 0))
+ {
+ if (local_db_update_in_evt(conn_handle))
+ {
+ // Successfully started writing to flash.
+ return;
+ }
+ else
+ {
+ pm_mutex_unlock(&m_db_update_in_progress_mutex, 0);
+ }
+ }
+}
+
+
+static __INLINE void update_pending_flags_check(void)
+{
+ UNUSED_RETURN_VALUE(ble_conn_state_for_each_set_user_flag(m_flag_local_db_update_pending,
+ db_update_pending_handle,
+ NULL));
+}
+
+
+#if PM_SERVICE_CHANGED_ENABLED
+static void sc_send_pending_handle(uint16_t conn_handle, void * p_context)
+{
+ UNUSED_PARAMETER(p_context);
+ if (!ble_conn_state_user_flag_get(conn_handle, m_flag_service_changed_sent))
+ {
+ service_changed_send_in_evt(conn_handle);
+ }
+}
+
+
+static __INLINE void service_changed_pending_flags_check(void)
+{
+ UNUSED_RETURN_VALUE(ble_conn_state_for_each_set_user_flag(m_flag_service_changed_pending,
+ sc_send_pending_handle,
+ NULL));
+}
+#endif
+
+
+/**@brief Callback function for events from the ID Manager module.
+ * This function is registered in the ID Manager module.
+ *
+ * @param[in] p_event The event from the ID Manager module.
+ */
+void gcm_im_evt_handler(pm_evt_t * p_event)
+{
+ switch (p_event->evt_id)
+ {
+ case PM_EVT_BONDED_PEER_CONNECTED:
+ local_db_apply_in_evt(p_event->conn_handle);
+#if (PM_SERVICE_CHANGED_ENABLED == 1)
+ if (gscm_service_changed_ind_needed(p_event->conn_handle))
+ {
+ ble_conn_state_user_flag_set(p_event->conn_handle, m_flag_service_changed_pending, true);
+ }
+#endif
+ break;
+ default:
+ break;
+ }
+}
+
+
+/**@brief Callback function for events from the Peer Database module.
+ * This handler is extern in Peer Database.
+ *
+ * @param[in] p_event The event from the Security Dispatcher module.
+ */
+void gcm_pdb_evt_handler(pm_evt_t * p_event)
+{
+ if ( p_event->evt_id == PM_EVT_PEER_DATA_UPDATE_SUCCEEDED
+ && p_event->params.peer_data_update_succeeded.action == PM_PEER_DATA_OP_UPDATE)
+ {
+ switch (p_event->params.peer_data_update_succeeded.data_id)
+ {
+ case PM_PEER_DATA_ID_BONDING:
+ {
+ uint16_t conn_handle = im_conn_handle_get(p_event->peer_id);
+
+ if (conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ local_db_update(conn_handle, true);
+ }
+ break;
+ }
+
+#if PM_SERVICE_CHANGED_ENABLED
+ case PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING:
+ {
+ ret_code_t err_code;
+ pm_peer_data_flash_t peer_data;
+
+ err_code = pdb_peer_data_ptr_get(p_event->peer_id,
+ PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING,
+ &peer_data);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ if (*peer_data.p_service_changed_pending)
+ {
+ uint16_t conn_handle = im_conn_handle_get(p_event->peer_id);
+ if (conn_handle != BLE_CONN_HANDLE_INVALID)
+ {
+ ble_conn_state_user_flag_set(conn_handle, m_flag_service_changed_pending, true);
+ service_changed_pending_flags_check();
+ }
+ }
+ }
+ break;
+ }
+#endif
+
+ case PM_PEER_DATA_ID_GATT_LOCAL:
+ pm_mutex_unlock(&m_db_update_in_progress_mutex, 0);
+ // Expecting a call to update_pending_flags_check() immediately.
+ break;
+
+ default:
+ /* No action */
+ break;
+ }
+ }
+
+ update_pending_flags_check();
+}
+
+
+ret_code_t gcm_init()
+{
+ NRF_PM_DEBUG_CHECK(!m_module_initialized);
+
+ internal_state_reset();
+
+ m_flag_local_db_update_pending = ble_conn_state_user_flag_acquire();
+ m_flag_local_db_apply_pending = ble_conn_state_user_flag_acquire();
+ m_flag_service_changed_pending = ble_conn_state_user_flag_acquire();
+ m_flag_service_changed_sent = ble_conn_state_user_flag_acquire();
+
+ if ((m_flag_local_db_update_pending == BLE_CONN_STATE_USER_FLAG_INVALID)
+ || (m_flag_local_db_apply_pending == BLE_CONN_STATE_USER_FLAG_INVALID)
+ || (m_flag_service_changed_pending == BLE_CONN_STATE_USER_FLAG_INVALID)
+ || (m_flag_service_changed_sent == BLE_CONN_STATE_USER_FLAG_INVALID)
+ )
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ pm_mutex_init(&m_db_update_in_progress_mutex, 1);
+
+ m_module_initialized = true;
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Callback function for BLE events from the SoftDevice.
+ *
+ * @param[in] p_ble_evt The BLE event from the SoftDevice.
+ */
+void gcm_ble_evt_handler(ble_evt_t const * p_ble_evt)
+{
+ uint16_t conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GATTS_EVT_SYS_ATTR_MISSING:
+ local_db_apply_in_evt(conn_handle);
+ break;
+
+#if PM_SERVICE_CHANGED_ENABLED
+ case BLE_GATTS_EVT_SC_CONFIRM:
+ {
+ pm_evt_t event =
+ {
+ .evt_id = PM_EVT_SERVICE_CHANGED_IND_CONFIRMED,
+ .peer_id = im_peer_id_get_by_conn_handle(conn_handle),
+ .conn_handle = conn_handle,
+ };
+
+ gscm_db_change_notification_done(event.peer_id);
+
+ ble_conn_state_user_flag_set(conn_handle, m_flag_service_changed_sent, false);
+ ble_conn_state_user_flag_set(conn_handle, m_flag_service_changed_pending, false);
+ evt_send(&event);
+ break;
+ }
+#endif
+
+ case BLE_GATTS_EVT_WRITE:
+ if (cccd_written(&p_ble_evt->evt.gatts_evt.params.write))
+ {
+ local_db_update(conn_handle, true);
+ update_pending_flags_check();
+ }
+ break;
+ }
+
+ apply_pending_flags_check();
+#if PM_SERVICE_CHANGED_ENABLED
+ service_changed_pending_flags_check();
+#endif
+}
+
+
+ret_code_t gcm_local_db_cache_update(uint16_t conn_handle)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ local_db_update(conn_handle, true);
+ update_pending_flags_check();
+
+ return NRF_SUCCESS;
+}
+
+
+#if PM_SERVICE_CHANGED_ENABLED
+void gcm_local_database_has_changed(void)
+{
+ gscm_local_database_has_changed();
+
+ ble_conn_state_conn_handle_list_t conn_handles = ble_conn_state_conn_handles();
+
+ for (uint16_t i = 0; i < conn_handles.len; i++)
+ {
+ if (im_peer_id_get_by_conn_handle(conn_handles.conn_handles[i]) == PM_PEER_ID_INVALID)
+ {
+ ble_conn_state_user_flag_set(conn_handles.conn_handles[i], m_flag_service_changed_pending, true);
+ }
+ }
+
+ service_changed_pending_flags_check();
+}
+#endif
+#endif // NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatt_cache_manager.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatt_cache_manager.h
new file mode 100644
index 0000000..0cb508a
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatt_cache_manager.h
@@ -0,0 +1,113 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef GATT_CACHE_MANAGER_H__
+#define GATT_CACHE_MANAGER_H__
+
+#include <stdint.h>
+#include "sdk_errors.h"
+#include "ble.h"
+#include "ble_gap.h"
+#include "peer_manager_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+/**
+ * @cond NO_DOXYGEN
+ * @defgroup gatt_cache_manager GATT Cache Manager
+ * @ingroup peer_manager
+ * @{
+ * @brief An internal module of @ref peer_manager. A module for managing persistent storing of GATT
+ * attributes.
+ */
+
+
+/**@brief Function for initializing the GATT Cache Manager module.
+ *
+ * @retval NRF_SUCCESS Initialization was successful.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t gcm_init(void);
+
+
+/**@brief Function for dispatching SoftDevice events to the GATT Cache Manager module.
+ *
+ * @param[in] p_ble_evt The SoftDevice event.
+ */
+void gcm_ble_evt_handler(ble_evt_t const * p_ble_evt);
+
+
+/**@brief Function for triggering local GATT database data to be stored persistently.
+ *
+ * @details Values are retrieved from SoftDevice and written to persistent storage.
+ *
+ * @note This operation happens asynchronously, so any errors are reported as events.
+ *
+ * @note This function is only needed when you want to override the regular functionality of the
+ * module, e.g. to immediately store to flash instead of waiting for the native logic to
+ * perform the update.
+ *
+ * @param[in] conn_handle Connection handle to perform update on.
+ *
+ * @retval NRF_SUCCESS Store operation started.
+ */
+ret_code_t gcm_local_db_cache_update(uint16_t conn_handle);
+
+
+/**@brief Function for manually informing that the local database has changed.
+ *
+ * @details This causes a service changed notification to be sent to all bonded peers that
+ * subscribe to it.
+ */
+void gcm_local_database_has_changed(void);
+
+/** @}
+ * @endcond
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GATT_CACHE_MANAGER_H__ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatts_cache_manager.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatts_cache_manager.c
new file mode 100644
index 0000000..3b70837
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatts_cache_manager.c
@@ -0,0 +1,347 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "gatts_cache_manager.h"
+
+#include <string.h>
+#include "ble_gap.h"
+#include "ble_err.h"
+#include "peer_manager_types.h"
+#include "peer_manager_internal.h"
+#include "peer_database.h"
+#include "id_manager.h"
+
+
+// Syntactic sugar, two spoons.
+#define SYS_ATTR_SYS (BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS)
+#define SYS_ATTR_USR (BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS)
+#define SYS_ATTR_BOTH (SYS_ATTR_SYS | SYS_ATTR_USR)
+
+static bool m_module_initialized;
+static pm_peer_id_t m_current_sc_store_peer_id;
+
+
+/**@brief Function for resetting the module variable(s) of the GSCM module.
+ */
+static void internal_state_reset()
+{
+ m_module_initialized = false;
+ m_current_sc_store_peer_id = PM_PEER_ID_INVALID;
+
+ // If PM_SERVICE_CHANGED_ENABLED is 0, this variable is unused.
+ UNUSED_VARIABLE(m_current_sc_store_peer_id);
+}
+
+
+#if !defined(PM_SERVICE_CHANGED_ENABLED) || (PM_SERVICE_CHANGED_ENABLED == 1)
+//lint -save -e550
+/**@brief Function for storing service_changed_pending = true to flash for all peers, in sequence.
+ *
+ * This function aborts if it gets @ref NRF_ERROR_BUSY when trying to store. A subsequent call will
+ * continue where the last call was aborted.
+ */
+static void service_changed_pending_set(void)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ ret_code_t err_code;
+ // Use a uint32_t to enforce 4-byte alignment.
+ static const uint32_t service_changed_pending = true;
+
+ //lint -save -e65 -e64
+ pm_peer_data_const_t peer_data =
+ {
+ .data_id = PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING,
+ .length_words = PM_SC_STATE_N_WORDS(),
+ .p_service_changed_pending = (bool*)&service_changed_pending,
+ };
+ //lint -restore
+
+ err_code = pdb_raw_store(m_current_sc_store_peer_id, &peer_data, NULL);
+ while ((m_current_sc_store_peer_id != PM_PEER_ID_INVALID) && (err_code != NRF_ERROR_BUSY))
+ {
+ m_current_sc_store_peer_id = pdb_next_peer_id_get(m_current_sc_store_peer_id);
+ err_code = pdb_raw_store(m_current_sc_store_peer_id, &peer_data, NULL);
+ }
+}
+//lint -restore
+
+
+
+/**@brief Event handler for events from the Peer Database module.
+ * This function is extern in Peer Database.
+ *
+ * @param[in] p_event The event that has happend with peer id and flags.
+ */
+void gscm_pdb_evt_handler(pm_evt_t * p_event)
+{
+ if (m_current_sc_store_peer_id != PM_PEER_ID_INVALID)
+ {
+ service_changed_pending_set();
+ }
+}
+#endif
+
+
+ret_code_t gscm_init()
+{
+ NRF_PM_DEBUG_CHECK(!m_module_initialized);
+
+ internal_state_reset();
+ m_module_initialized = true;
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t gscm_local_db_cache_update(uint16_t conn_handle)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ pm_peer_id_t peer_id = im_peer_id_get_by_conn_handle(conn_handle);
+ ret_code_t err_code;
+
+ if (peer_id == PM_PEER_ID_INVALID)
+ {
+ return BLE_ERROR_INVALID_CONN_HANDLE;
+ }
+ else
+ {
+ pm_peer_data_t peer_data;
+ uint16_t n_bufs = 1;
+ bool retry_with_bigger_buffer = false;
+
+ do
+ {
+ retry_with_bigger_buffer = false;
+
+ err_code = pdb_write_buf_get(peer_id, PM_PEER_DATA_ID_GATT_LOCAL, n_bufs++, &peer_data);
+ if (err_code == NRF_SUCCESS)
+ {
+ pm_peer_data_local_gatt_db_t * p_local_gatt_db = peer_data.p_local_gatt_db;
+
+ p_local_gatt_db->flags = SYS_ATTR_BOTH;
+
+ err_code = sd_ble_gatts_sys_attr_get(conn_handle, &p_local_gatt_db->data[0], &p_local_gatt_db->len, p_local_gatt_db->flags);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = pdb_write_buf_store(peer_id, PM_PEER_DATA_ID_GATT_LOCAL, peer_id);
+ }
+ else
+ {
+ if (err_code == NRF_ERROR_DATA_SIZE)
+ {
+ // The sys attributes are bigger than the requested write buffer.
+ retry_with_bigger_buffer = true;
+ }
+ else if (err_code == NRF_ERROR_NOT_FOUND)
+ {
+ // There are no sys attributes in the GATT db, so nothing needs to be stored.
+ err_code = NRF_SUCCESS;
+ }
+
+ ret_code_t err_code_release = pdb_write_buf_release(peer_id, PM_PEER_DATA_ID_GATT_LOCAL);
+ if (err_code_release != NRF_SUCCESS)
+ {
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ }
+ }
+ else if (err_code == NRF_ERROR_INVALID_PARAM)
+ {
+ // The sys attributes are bigger than the entire write buffer.
+ err_code = NRF_ERROR_DATA_SIZE;
+ }
+ } while (retry_with_bigger_buffer);
+ }
+
+ return err_code;
+}
+
+
+ret_code_t gscm_local_db_cache_apply(uint16_t conn_handle)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ pm_peer_id_t peer_id = im_peer_id_get_by_conn_handle(conn_handle);
+ ret_code_t err_code;
+ pm_peer_data_flash_t peer_data;
+ uint8_t const * p_sys_attr_data = NULL;
+ uint16_t sys_attr_len = 0;
+ uint32_t sys_attr_flags = (SYS_ATTR_BOTH);
+ bool all_attributes_applied = true;
+
+ if (peer_id != PM_PEER_ID_INVALID)
+ {
+ err_code = pdb_peer_data_ptr_get(peer_id, PM_PEER_DATA_ID_GATT_LOCAL, &peer_data);
+ if (err_code == NRF_SUCCESS)
+ {
+ pm_peer_data_local_gatt_db_t const * p_local_gatt_db;
+
+ p_local_gatt_db = peer_data.p_local_gatt_db;
+ p_sys_attr_data = p_local_gatt_db->data;
+ sys_attr_len = p_local_gatt_db->len;
+ sys_attr_flags = p_local_gatt_db->flags;
+ }
+ }
+
+ do
+ {
+ err_code = sd_ble_gatts_sys_attr_set(conn_handle, p_sys_attr_data, sys_attr_len, sys_attr_flags);
+
+ if (err_code == NRF_ERROR_NO_MEM)
+ {
+ err_code = NRF_ERROR_BUSY;
+ }
+ else if (err_code == NRF_ERROR_INVALID_STATE)
+ {
+ err_code = NRF_SUCCESS;
+ }
+ else if (err_code == NRF_ERROR_INVALID_DATA)
+ {
+ all_attributes_applied = false;
+
+ if (sys_attr_flags & SYS_ATTR_USR)
+ {
+ // Try setting only system attributes.
+ sys_attr_flags = SYS_ATTR_SYS;
+ }
+ else if (p_sys_attr_data || sys_attr_len)
+ {
+ // Try reporting that none exist.
+ p_sys_attr_data = NULL;
+ sys_attr_len = 0;
+ sys_attr_flags = SYS_ATTR_BOTH;
+ }
+ else
+ {
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ }
+ } while (err_code == NRF_ERROR_INVALID_DATA);
+
+ if (!all_attributes_applied)
+ {
+ err_code = NRF_ERROR_INVALID_DATA;
+ }
+
+ return err_code;
+}
+
+#if !defined(PM_SERVICE_CHANGED_ENABLED) || (PM_SERVICE_CHANGED_ENABLED == 1)
+void gscm_local_database_has_changed(void)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ m_current_sc_store_peer_id = pdb_next_peer_id_get(PM_PEER_ID_INVALID);
+ service_changed_pending_set();
+}
+
+
+bool gscm_service_changed_ind_needed(uint16_t conn_handle)
+{
+ ret_code_t err_code;
+ bool service_changed_state;
+ pm_peer_data_flash_t peer_data;
+
+ peer_data.p_service_changed_pending = &service_changed_state;
+ pm_peer_id_t peer_id = im_peer_id_get_by_conn_handle(conn_handle);
+
+ err_code = pdb_peer_data_ptr_get(peer_id, PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING, &peer_data);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return false;
+ }
+
+ return *peer_data.p_service_changed_pending;
+}
+
+
+ret_code_t gscm_service_changed_ind_send(uint16_t conn_handle)
+{
+ static uint16_t start_handle;
+ const uint16_t end_handle = 0xFFFF;
+ ret_code_t err_code;
+
+ err_code = sd_ble_gatts_initial_user_handle_get(&start_handle);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ do
+ {
+ err_code = sd_ble_gatts_service_changed(conn_handle, start_handle, end_handle);
+ if (err_code == BLE_ERROR_INVALID_ATTR_HANDLE)
+ {
+ start_handle += 1;
+ }
+ } while (err_code == BLE_ERROR_INVALID_ATTR_HANDLE);
+
+ return err_code;
+}
+
+
+void gscm_db_change_notification_done(pm_peer_id_t peer_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ // Use a uint32_t to enforce 4-byte alignment.
+ static const uint32_t service_changed_pending = false;
+
+ //lint -save -e65 -e64
+ pm_peer_data_const_t peer_data =
+ {
+ .data_id = PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING,
+ .length_words = PM_SC_STATE_N_WORDS(),
+ .p_service_changed_pending = (bool*)&service_changed_pending,
+ };
+ //lint -restore
+
+ // Don't need to check return code, because all error conditions can be ignored.
+ //lint -save -e550
+ (void) pdb_raw_store(peer_id, &peer_data, NULL);
+ //lint -restore
+}
+#endif
+#endif // NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatts_cache_manager.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatts_cache_manager.h
new file mode 100644
index 0000000..b1303df
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/gatts_cache_manager.h
@@ -0,0 +1,163 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef GATTS_CACHE_MANAGER_H__
+#define GATTS_CACHE_MANAGER_H__
+
+#include <stdint.h>
+#include "sdk_errors.h"
+#include "ble.h"
+#include "ble_gap.h"
+#include "peer_manager_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+/**
+ * @cond NO_DOXYGEN
+ * @defgroup gatts_cache_manager GATT Server Cache Manager
+ * @ingroup peer_manager
+ * @{
+ * @brief An internal module of @ref peer_manager. A module for managing persistent storing of GATT
+ * attributes pertaining to the GATT server role of the local device.
+ */
+
+
+/**@brief Function for initializing the GATT Server Cache Manager module.
+ *
+ * @retval NRF_SUCCESS Initialization was successful.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t gscm_init(void);
+
+
+/**@brief Function for triggering local GATT database data to be stored persistently. Values are
+ * retrieved from the SoftDevice and written to persistent storage.
+ *
+ * @param[in] conn_handle Connection handle to perform update on.
+ *
+ * @retval NRF_SUCCESS Store operation started.
+ * @retval BLE_ERROR_INVALID_CONN_HANDLE conn_handle does not refer to an active connection with a
+ * bonded peer.
+ * @retval NRF_ERROR_BUSY Unable to perform operation at this time. Reattempt later.
+ * @retval NRF_ERROR_DATA_SIZE Write buffer not large enough. Call will never work with
+ * this GATT database.
+ * @retval NRF_ERROR_STORAGE_FULL No room in persistent_storage. Free up space; the
+ * operation will be automatically reattempted after the
+ * next FDS garbage collection procedure.
+ */
+ret_code_t gscm_local_db_cache_update(uint16_t conn_handle);
+
+
+/**@brief Function for applying stored local GATT database data to the SoftDevice. Values are
+ * retrieved from persistent storage and given to the SoftDevice.
+ *
+ * @param[in] conn_handle Connection handle to apply values to.
+ *
+ * @retval NRF_SUCCESS Store operation started.
+ * @retval BLE_ERROR_INVALID_CONN_HANDLE conn_handle does not refer to an active connection with a
+ * bonded peer.
+ * @retval NRF_ERROR_INVALID_DATA The stored data was rejected by the SoftDevice, which
+ * probably means that the local database has changed. The
+ * system part of the sys_attributes was attempted applied,
+ * so service changed indications can be sent to subscribers.
+ * @retval NRF_ERROR_BUSY Unable to perform operation at this time. Reattempt later.
+ * @return An unexpected return value from an internal function call.
+ */
+ret_code_t gscm_local_db_cache_apply(uint16_t conn_handle);
+
+
+/**@brief Function for storing the fact that the local database has changed, for all currently
+ * bonded peers.
+ *
+ * @note This will cause a later call to @ref gscm_service_changed_ind_needed to return true for
+ * a connection with a currently bonded peer.
+ */
+void gscm_local_database_has_changed(void);
+
+
+/**@brief Function for checking if a service changed indication should be sent.
+ *
+ * @param[in] conn_handle The connection to check.
+ *
+ * @return true if a service changed indication should be sent, false if not.
+ */
+bool gscm_service_changed_ind_needed(uint16_t conn_handle);
+
+
+/**@brief Function for sending a service changed indication to a connected peer.
+ *
+ * @param[in] conn_handle The connection to send the indication on.
+ *
+ * @retval NRF_SUCCESS Indication sent or not needed.
+ * @retval BLE_ERROR_INVALID_CONN_HANDLE conn_handle does not refer to an active connection.
+ * @retval NRF_ERROR_BUSY Unable to send indication at this time. Reattempt later.
+ * @retval BLE_ERROR_GATTS_SYS_ATTR_MISSING Information missing. Apply local cache, then reattempt.
+ * @retval NRF_ERROR_INVALID_PARAM From @ref sd_ble_gatts_service_changed. Unexpected.
+ * @retval NRF_ERROR_NOT_SUPPORTED Service changed characteristic is not present.
+ * @retval NRF_ERROR_INVALID_STATE Service changed cannot be indicated to this peer
+ * because the peer has not subscribed to it.
+ * @retval NRF_ERROR_INTERNAL An unexpected error happened.
+ */
+ret_code_t gscm_service_changed_ind_send(uint16_t conn_handle);
+
+
+/**@brief Function for specifying that a peer has been made aware of the latest local database
+ * change.
+ *
+ * @note After calling this, a later call to @ref gscm_service_changed_ind_needed will to return
+ * false for this peer unless @ref gscm_local_database_has_changed is called again.
+ *
+ * @param[in] peer_id The connection to send the indication on.
+ */
+void gscm_db_change_notification_done(pm_peer_id_t peer_id);
+
+/** @}
+ * @endcond
+*/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GATTS_CACHE_MANAGER_H__ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/id_manager.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/id_manager.c
new file mode 100644
index 0000000..bbe7702
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/id_manager.c
@@ -0,0 +1,890 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "id_manager.h"
+
+#include <string.h>
+#include "ble.h"
+#include "ble_gap.h"
+#include "ble_err.h"
+#include "ble_conn_state.h"
+#include "peer_manager_types.h"
+#include "peer_database.h"
+#include "peer_data_storage.h"
+#include "nrf_soc.h"
+
+
+#define IM_MAX_CONN_HANDLES (20)
+#define IM_NO_INVALID_CONN_HANDLES (0xFF)
+#define IM_ADDR_CLEARTEXT_LENGTH (3)
+#define IM_ADDR_CIPHERTEXT_LENGTH (3)
+
+// The number of registered event handlers.
+#define IM_EVENT_HANDLERS_CNT (sizeof(m_evt_handlers) / sizeof(m_evt_handlers[0]))
+
+
+// Identity Manager event handlers in Peer Manager and GATT Cache Manager.
+extern void pm_im_evt_handler(pm_evt_t * p_event);
+extern void gcm_im_evt_handler(pm_evt_t * p_event);
+
+// Identity Manager events' handlers.
+// The number of elements in this array is IM_EVENT_HANDLERS_CNT.
+static pm_evt_handler_internal_t const m_evt_handlers[] =
+{
+ pm_im_evt_handler,
+ gcm_im_evt_handler
+};
+
+
+typedef struct
+{
+ pm_peer_id_t peer_id;
+ uint16_t conn_handle;
+ ble_gap_addr_t peer_address;
+} im_connection_t;
+
+static bool m_module_initialized;
+static im_connection_t m_connections[IM_MAX_CONN_HANDLES];
+static ble_conn_state_user_flag_id_t m_conn_state_user_flag_id;
+
+static uint8_t m_wlisted_peer_cnt;
+static pm_peer_id_t m_wlisted_peers[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
+
+
+static void internal_state_reset()
+{
+ m_conn_state_user_flag_id = BLE_CONN_STATE_USER_FLAG_INVALID;
+
+ for (uint32_t i = 0; i < IM_MAX_CONN_HANDLES; i++)
+ {
+ m_connections[i].conn_handle = BLE_CONN_HANDLE_INVALID;
+ }
+}
+
+
+/**@brief Function for sending an event to all registered event handlers.
+ *
+ * @param[in] p_event The event to distribute.
+ */
+static void evt_send(pm_evt_t * p_event)
+{
+ for (uint32_t i = 0; i < IM_EVENT_HANDLERS_CNT; i++)
+ {
+ m_evt_handlers[i](p_event);
+ }
+}
+
+/**@brief Function finding a free position in m_connections.
+ *
+ * @detail All connection handles in the m_connections array are checked against the connection
+ * state module. The index of the first one that is not a connection handle for a current
+ * connection is returned. This position in the array can safely be used for a new connection.
+ *
+ * @return Either the index of a free position in the array or IM_NO_INVALID_CONN_HANDLES if no free
+ position exists.
+ */
+uint8_t get_free_connection()
+{
+ for (uint32_t i = 0; i < IM_MAX_CONN_HANDLES; i++)
+ {
+ // Query the connection state module to check if the
+ // connection handle does not belong to a valid connection.
+ if (!ble_conn_state_user_flag_get(m_connections[i].conn_handle, m_conn_state_user_flag_id))
+ {
+ return i;
+ }
+ }
+ // If all connection handles belong to a valid connection, return IM_NO_INVALID_CONN_HANDLES.
+ return IM_NO_INVALID_CONN_HANDLES;
+}
+
+
+/**@brief Function finding a particular connection handle m_connections.
+ *
+ * @param[in] conn_handle The handle to find.
+ *
+ * @return Either the index of the conn_handle in the array or IM_NO_INVALID_CONN_HANDLES if the
+ * handle was not found.
+ */
+uint8_t get_connection_by_conn_handle(uint16_t conn_handle)
+{
+ if (ble_conn_state_user_flag_get(conn_handle, m_conn_state_user_flag_id))
+ {
+ for (uint32_t i = 0; i < IM_MAX_CONN_HANDLES; i++)
+ {
+ if (m_connections[i].conn_handle == conn_handle)
+ {
+ return i;
+ }
+ }
+ }
+ // If all connection handles belong to a valid connection, return IM_NO_INVALID_CONN_HANDLES.
+ return IM_NO_INVALID_CONN_HANDLES;
+}
+
+
+/**@brief Function for registering a new connection instance.
+ *
+ * @param[in] conn_handle The handle of the new connection.
+ * @param[in] p_ble_addr The address used to connect.
+ *
+ * @return Either the index of the new connection in the array or IM_NO_INVALID_CONN_HANDLES if no
+ * free position exists.
+ */
+uint8_t new_connection(uint16_t conn_handle, ble_gap_addr_t * p_ble_addr)
+{
+ uint8_t conn_index = IM_NO_INVALID_CONN_HANDLES;
+
+ if ((p_ble_addr != NULL) && (conn_handle != BLE_CONN_HANDLE_INVALID))
+ {
+ ble_conn_state_user_flag_set(conn_handle, m_conn_state_user_flag_id, true);
+
+ conn_index = get_connection_by_conn_handle(conn_handle);
+ if (conn_index == IM_NO_INVALID_CONN_HANDLES)
+ {
+ conn_index = get_free_connection();
+ }
+
+ if (conn_index != IM_NO_INVALID_CONN_HANDLES)
+ {
+ m_connections[conn_index].conn_handle = conn_handle;
+ m_connections[conn_index].peer_id = PM_PEER_ID_INVALID;
+ m_connections[conn_index].peer_address = *p_ble_addr;
+ }
+ }
+ return conn_index;
+}
+
+
+/**@brief Function checking the validity of an IRK
+ *
+ * @detail An all-zero IRK is not valid. This function will check if a given IRK is valid.
+ *
+ * @param[in] p_irk The IRK for which the validity is going to be checked.
+ *
+ * @retval true The IRK is valid.
+ * @retval false The IRK is invalid.
+ */
+bool is_valid_irk(ble_gap_irk_t const * p_irk)
+{
+ NRF_PM_DEBUG_CHECK(p_irk != NULL);
+
+ for (uint32_t i = 0; i < BLE_GAP_SEC_KEY_LEN; i++)
+ {
+ if (p_irk->irk[i] != 0)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/**@brief Function for comparing two addresses to determine if they are identical
+ *
+ * @note The address type need to be identical, as well as every bit in the address itself.
+ *
+ * @param[in] p_addr1 The first address to be compared.
+ * @param[in] p_addr2 The second address to be compared.
+ *
+ * @retval true The addresses are identical.
+ * @retval false The addresses are not identical.
+ */
+bool addr_compare(ble_gap_addr_t const * p_addr1, ble_gap_addr_t const * p_addr2)
+{
+ // @note emdi: use NRF_PM_DEBUG_CHECK ?
+ if ((p_addr1 == NULL) || (p_addr2 == NULL))
+ {
+ return false;
+ }
+
+ // Check that the addr type is identical, return false if it is not
+ if (p_addr1->addr_type != p_addr2->addr_type)
+ {
+ return false;
+ }
+
+ // Check if the addr bytes are is identical
+ return (memcmp(p_addr1->addr, p_addr2->addr, BLE_GAP_ADDR_LEN) == 0);
+}
+
+
+void im_ble_evt_handler(ble_evt_t const * ble_evt)
+{
+ ble_gap_evt_t gap_evt;
+ pm_peer_id_t bonded_matching_peer_id;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ if (ble_evt->header.evt_id != BLE_GAP_EVT_CONNECTED)
+ {
+ // Nothing to do.
+ return;
+ }
+
+ gap_evt = ble_evt->evt.gap_evt;
+ bonded_matching_peer_id = PM_PEER_ID_INVALID;
+
+ if ( gap_evt.params.connected.peer_addr.addr_type
+ != BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE)
+ {
+ /* Search the database for bonding data matching the one that triggered the event.
+ * Public and static addresses can be matched on address alone, while resolvable
+ * random addresses can be resolved agains known IRKs. Non-resolvable random addresses
+ * are never matching because they are not longterm form of identification.
+ */
+
+ pm_peer_id_t peer_id;
+ pm_peer_data_flash_t peer_data;
+
+ pds_peer_data_iterate_prepare();
+
+ switch (gap_evt.params.connected.peer_addr.addr_type)
+ {
+ case BLE_GAP_ADDR_TYPE_PUBLIC:
+ case BLE_GAP_ADDR_TYPE_RANDOM_STATIC:
+ {
+ while (pds_peer_data_iterate(PM_PEER_DATA_ID_BONDING, &peer_id, &peer_data))
+ {
+ if (addr_compare(&gap_evt.params.connected.peer_addr,
+ &peer_data.p_bonding_data->peer_ble_id.id_addr_info))
+ {
+ bonded_matching_peer_id = peer_id;
+ break;
+ }
+ }
+ }
+ break;
+
+ case BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE:
+ {
+ while (pds_peer_data_iterate(PM_PEER_DATA_ID_BONDING, &peer_id, &peer_data))
+ {
+ if (im_address_resolve(&gap_evt.params.connected.peer_addr,
+ &peer_data.p_bonding_data->peer_ble_id.id_info))
+ {
+ bonded_matching_peer_id = peer_id;
+ break;
+ }
+ }
+ }
+ break;
+
+ default:
+ NRF_PM_DEBUG_CHECK(false);
+ break;
+ }
+ }
+
+ uint8_t new_index = new_connection(gap_evt.conn_handle,
+ &gap_evt.params.connected.peer_addr);
+ UNUSED_VARIABLE(new_index);
+
+ if (bonded_matching_peer_id != PM_PEER_ID_INVALID)
+ {
+ im_new_peer_id(gap_evt.conn_handle, bonded_matching_peer_id);
+
+ // Send a bonded peer event
+ pm_evt_t im_evt;
+ im_evt.conn_handle = gap_evt.conn_handle;
+ im_evt.peer_id = bonded_matching_peer_id;
+ im_evt.evt_id = PM_EVT_BONDED_PEER_CONNECTED;
+ evt_send(&im_evt);
+ }
+}
+
+
+/**@brief Function to compare two sets of bonding data to check if they belong to the same device.
+ * @note Invalid irks will never match even though they are identical.
+ *
+ * @param[in] p_bonding_data1 First bonding data for comparison
+ * @param[in] p_bonding_data2 Second bonding data for comparison
+ *
+ * @return True if the input matches, false if it does not.
+ */
+bool im_is_duplicate_bonding_data(pm_peer_data_bonding_t const * p_bonding_data1,
+ pm_peer_data_bonding_t const * p_bonding_data2)
+{
+ NRF_PM_DEBUG_CHECK(p_bonding_data1 != NULL);
+ NRF_PM_DEBUG_CHECK(p_bonding_data2 != NULL);
+
+ ble_gap_addr_t const * p_addr1 = &p_bonding_data1->peer_ble_id.id_addr_info;
+ ble_gap_addr_t const * p_addr2 = &p_bonding_data2->peer_ble_id.id_addr_info;
+
+ bool duplicate_irk = ((memcmp(p_bonding_data1->peer_ble_id.id_info.irk,
+ p_bonding_data2->peer_ble_id.id_info.irk,
+ BLE_GAP_SEC_KEY_LEN) == 0)
+ && is_valid_irk(&p_bonding_data1->peer_ble_id.id_info)
+ && is_valid_irk(&p_bonding_data2->peer_ble_id.id_info));
+
+ bool duplicate_addr = addr_compare(p_addr1, p_addr2);
+
+ bool id_addrs = ((p_addr1->addr_type != BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE)
+ && (p_addr1->addr_type != BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE)
+ && (p_addr2->addr_type != BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE)
+ && (p_addr2->addr_type != BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE));
+
+ return (duplicate_addr && id_addrs) || (duplicate_irk && !id_addrs);
+}
+
+
+pm_peer_id_t im_find_duplicate_bonding_data(pm_peer_data_bonding_t const * p_bonding_data,
+ pm_peer_id_t peer_id_skip)
+{
+ pm_peer_id_t peer_id;
+ pm_peer_data_flash_t peer_data_duplicate;
+
+ NRF_PM_DEBUG_CHECK(p_bonding_data != NULL);
+
+ pds_peer_data_iterate_prepare();
+
+ while (pds_peer_data_iterate(PM_PEER_DATA_ID_BONDING, &peer_id, &peer_data_duplicate))
+ {
+ if ( (peer_id != peer_id_skip)
+ && im_is_duplicate_bonding_data(p_bonding_data,
+ peer_data_duplicate.p_bonding_data))
+ {
+ return peer_id;
+ }
+ }
+ return PM_PEER_ID_INVALID;
+}
+
+
+ret_code_t im_init(void)
+{
+ NRF_PM_DEBUG_CHECK(!m_module_initialized);
+
+ internal_state_reset();
+
+ m_conn_state_user_flag_id = ble_conn_state_user_flag_acquire();
+ if (m_conn_state_user_flag_id == BLE_CONN_STATE_USER_FLAG_INVALID)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ m_module_initialized = true;
+
+ return NRF_SUCCESS;
+}
+
+
+pm_peer_id_t im_peer_id_get_by_conn_handle(uint16_t conn_handle)
+{
+ uint8_t conn_index;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ conn_index = get_connection_by_conn_handle(conn_handle);
+
+ if (conn_index != IM_NO_INVALID_CONN_HANDLES)
+ {
+ return m_connections[conn_index].peer_id;
+ }
+
+ return PM_PEER_ID_INVALID;
+}
+
+
+ret_code_t im_ble_addr_get(uint16_t conn_handle, ble_gap_addr_t * p_ble_addr)
+{
+ uint8_t conn_index;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_ble_addr != NULL);
+
+ conn_index = get_connection_by_conn_handle(conn_handle);
+
+ if (conn_index != IM_NO_INVALID_CONN_HANDLES)
+ {
+ *p_ble_addr = m_connections[conn_index].peer_address;
+ return NRF_SUCCESS;
+ }
+
+ return NRF_ERROR_NOT_FOUND;
+}
+
+
+bool im_master_ids_compare(ble_gap_master_id_t const * p_master_id1,
+ ble_gap_master_id_t const * p_master_id2)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_master_id1 != NULL);
+ NRF_PM_DEBUG_CHECK(p_master_id2 != NULL);
+
+ if (!im_master_id_is_valid(p_master_id1))
+ {
+ return false;
+ }
+
+ if (p_master_id1->ediv != p_master_id2->ediv)
+ {
+ return false;
+ }
+
+ return (memcmp(p_master_id1->rand, p_master_id2->rand, BLE_GAP_SEC_RAND_LEN) == 0);
+}
+
+
+pm_peer_id_t im_peer_id_get_by_master_id(ble_gap_master_id_t const * p_master_id)
+{
+ pm_peer_id_t peer_id;
+ pm_peer_data_flash_t peer_data;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_master_id != NULL);
+
+ pds_peer_data_iterate_prepare();
+
+ // For each stored peer, check if the master_id matches p_master_id
+ while (pds_peer_data_iterate(PM_PEER_DATA_ID_BONDING, &peer_id, &peer_data))
+ {
+ if (im_master_ids_compare(p_master_id, &peer_data.p_bonding_data->own_ltk.master_id) ||
+ im_master_ids_compare(p_master_id, &peer_data.p_bonding_data->peer_ltk.master_id))
+ {
+ // If a matching master ID is found then return the peer ID.
+ return peer_id;
+ }
+ }
+
+ // If no matching master ID is found return PM_PEER_ID_INVALID.
+ return PM_PEER_ID_INVALID;
+}
+
+
+uint16_t im_conn_handle_get(pm_peer_id_t peer_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ for (uint32_t i = 0; i < IM_MAX_CONN_HANDLES; i++)
+ {
+ if (peer_id == m_connections[i].peer_id)
+ {
+ return m_connections[i].conn_handle;
+ }
+ }
+ return BLE_CONN_HANDLE_INVALID;
+}
+
+
+bool im_master_id_is_valid(ble_gap_master_id_t const * p_master_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ if (p_master_id->ediv != 0)
+ {
+ return true;
+ }
+
+ for (uint32_t i = 0; i < BLE_GAP_SEC_RAND_LEN; i++)
+ {
+ if (p_master_id->rand[i] != 0)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/**@brief Function to set the peer ID associated with a connection handle.
+ *
+ * @param[in] conn_handle The connection handle.
+ * @param[in] peer_id The peer ID to associate with @c conn_handle.
+ */
+static void peer_id_set(uint16_t conn_handle, pm_peer_id_t peer_id)
+{
+ uint8_t conn_index = get_connection_by_conn_handle(conn_handle);
+ if (conn_index != IM_NO_INVALID_CONN_HANDLES)
+ {
+ m_connections[conn_index].peer_id = peer_id;
+ }
+}
+
+
+void im_new_peer_id(uint16_t conn_handle, pm_peer_id_t peer_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ peer_id_set(conn_handle, peer_id);
+}
+
+
+ret_code_t im_peer_free(pm_peer_id_t peer_id)
+{
+ uint16_t conn_handle;
+ ret_code_t ret;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ conn_handle = im_conn_handle_get(peer_id);
+ ret = pdb_peer_free(peer_id);
+
+ if ((conn_handle != BLE_CONN_HANDLE_INVALID) && (ret == NRF_SUCCESS))
+ {
+ peer_id_set(conn_handle, PM_PEER_ID_INVALID);
+ }
+ return ret;
+}
+
+
+/**@brief Given a list of peers, loads their GAP address and IRK into the provided buffers.
+ */
+static ret_code_t peers_id_keys_get(pm_peer_id_t const * p_peers,
+ uint32_t peer_cnt,
+ ble_gap_addr_t * p_gap_addrs,
+ uint32_t * p_addr_cnt,
+ ble_gap_irk_t * p_gap_irks,
+ uint32_t * p_irk_cnt)
+{
+ ret_code_t ret;
+
+ pm_peer_data_bonding_t bond_data;
+ pm_peer_data_t peer_data;
+
+ uint32_t const buf_size = sizeof(bond_data);
+
+ bool copy_addrs = false;
+ bool copy_irks = false;
+
+ NRF_PM_DEBUG_CHECK(p_peers != NULL);
+
+ // One of these two has to be provided.
+ NRF_PM_DEBUG_CHECK((p_gap_addrs != NULL) || (p_gap_irks != NULL));
+
+ if ((p_gap_addrs != NULL) && (p_addr_cnt != NULL))
+ {
+ NRF_PM_DEBUG_CHECK((*p_addr_cnt) >= peer_cnt);
+
+ copy_addrs = true;
+ *p_addr_cnt = 0;
+ }
+
+ if ((p_gap_irks != NULL) && (p_irk_cnt != NULL))
+ {
+ NRF_PM_DEBUG_CHECK((*p_irk_cnt) >= peer_cnt);
+
+ copy_irks = true;
+ *p_irk_cnt = 0;
+ }
+
+ memset(&peer_data, 0x00, sizeof(peer_data));
+ peer_data.p_bonding_data = &bond_data;
+
+ // Read through flash memory and look for peers ID keys.
+
+ for (uint32_t i = 0; i < peer_cnt; i++)
+ {
+ memset(&bond_data, 0x00, sizeof(bond_data));
+
+ // Read peer data from flash.
+ ret = pds_peer_data_read(p_peers[i], PM_PEER_DATA_ID_BONDING,
+ &peer_data, &buf_size);
+
+ if ((ret == NRF_ERROR_NOT_FOUND) || (ret == NRF_ERROR_INVALID_PARAM))
+ {
+ // Peer data coulnd't be found in flash or peer ID is not valid.
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ uint8_t const addr_type = bond_data.peer_ble_id.id_addr_info.addr_type;
+
+ if ((addr_type != BLE_GAP_ADDR_TYPE_PUBLIC) &&
+ (addr_type != BLE_GAP_ADDR_TYPE_RANDOM_STATIC))
+ {
+ // The address shared by the peer during bonding can't be used for whitelisting.
+ return BLE_ERROR_GAP_INVALID_BLE_ADDR;
+ }
+
+ // Copy the GAP address.
+ if (copy_addrs)
+ {
+ memcpy(&p_gap_addrs[i], &bond_data.peer_ble_id.id_addr_info, sizeof(ble_gap_addr_t));
+ (*p_addr_cnt)++;
+ }
+
+ // Copy the IRK.
+ if (copy_irks)
+ {
+ memcpy(&p_gap_irks[i], bond_data.peer_ble_id.id_info.irk, BLE_GAP_SEC_KEY_LEN);
+ (*p_irk_cnt)++;
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t im_device_identities_list_set(pm_peer_id_t const * p_peers,
+ uint32_t peer_cnt)
+{
+ ret_code_t ret;
+ pm_peer_data_t peer_data;
+ pm_peer_data_bonding_t bond_data;
+
+ ble_gap_id_key_t keys[BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT];
+ ble_gap_id_key_t const * key_ptrs[BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT];
+
+ if ((p_peers == NULL) || (peer_cnt == 0))
+ {
+ // Clear the device identities list.
+ return sd_ble_gap_device_identities_set(NULL, NULL, 0);
+ }
+
+ peer_data.p_bonding_data = &bond_data;
+ uint32_t const buf_size = sizeof(bond_data);
+
+ memset(keys, 0x00, sizeof(keys));
+ for (uint32_t i = 0; i < BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT; i++)
+ {
+ key_ptrs[i] = &keys[i];
+ }
+
+ for (uint32_t i = 0; i < peer_cnt; i++)
+ {
+ memset(&bond_data, 0x00, sizeof(bond_data));
+
+ // Read peer data from flash.
+ ret = pds_peer_data_read(p_peers[i], PM_PEER_DATA_ID_BONDING,
+ &peer_data, &buf_size);
+
+ if ((ret == NRF_ERROR_NOT_FOUND) || (ret == NRF_ERROR_INVALID_PARAM))
+ {
+ // Peer data coulnd't be found in flash or peer ID is not valid.
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ uint8_t const addr_type = bond_data.peer_ble_id.id_addr_info.addr_type;
+
+ if ((addr_type != BLE_GAP_ADDR_TYPE_PUBLIC) &&
+ (addr_type != BLE_GAP_ADDR_TYPE_RANDOM_STATIC))
+ {
+ // The address shared by the peer during bonding can't be whitelisted.
+ return BLE_ERROR_GAP_INVALID_BLE_ADDR;
+ }
+
+ // Copy data to the buffer.
+ memcpy(&keys[i], &bond_data.peer_ble_id, sizeof(ble_gap_id_key_t));
+ }
+
+ return sd_ble_gap_device_identities_set(key_ptrs, NULL, peer_cnt);
+}
+
+
+ret_code_t im_id_addr_set(ble_gap_addr_t const * p_addr)
+{
+ return sd_ble_gap_addr_set(p_addr);
+}
+
+
+ret_code_t im_id_addr_get(ble_gap_addr_t * p_addr)
+{
+ NRF_PM_DEBUG_CHECK(p_addr != NULL);
+
+ return sd_ble_gap_addr_get(p_addr);
+}
+
+
+ret_code_t im_privacy_set(pm_privacy_params_t const * p_privacy_params)
+{
+ return sd_ble_gap_privacy_set(p_privacy_params);
+}
+
+
+ret_code_t im_privacy_get(pm_privacy_params_t * p_privacy_params)
+{
+ return sd_ble_gap_privacy_get(p_privacy_params);
+}
+
+
+/* Create a whitelist for the user using the cached list of peers.
+ * This whitelist is meant to be provided by the application to the Advertising module.
+ */
+ret_code_t im_whitelist_get(ble_gap_addr_t * p_addrs,
+ uint32_t * p_addr_cnt,
+ ble_gap_irk_t * p_irks,
+ uint32_t * p_irk_cnt)
+{
+ // One of the two buffers has to be provided.
+ NRF_PM_DEBUG_CHECK((p_addrs != NULL) || (p_irks != NULL));
+ NRF_PM_DEBUG_CHECK((p_addr_cnt != NULL) || (p_irk_cnt != NULL));
+
+ if (((p_addr_cnt != NULL) && (m_wlisted_peer_cnt > *p_addr_cnt)) ||
+ ((p_irk_cnt != NULL) && (m_wlisted_peer_cnt > *p_irk_cnt)))
+ {
+ // The size of the cached list of peers is larger than the provided buffers.
+ return NRF_ERROR_NO_MEM;
+ }
+
+ // NRF_SUCCESS or
+ // NRF_ERROR_NOT_FOUND, if a peer or its data were not found.
+ // BLE_ERROR_GAP_INVALID_BLE_ADDR, if a peer address can not be used for whitelisting.
+ return peers_id_keys_get(m_wlisted_peers, m_wlisted_peer_cnt,
+ p_addrs, p_addr_cnt,
+ p_irks, p_irk_cnt);
+}
+
+
+/* Copies the peers to whitelist into a local cache.
+ * The cached list will be used by im_whitelist_get() to retrieve the active whitelist.
+ * For SoftDevices 3x, also loads the peers' GAP addresses and whitelists them using
+ * sd_ble_gap_whitelist_set().
+ */
+ret_code_t im_whitelist_set(pm_peer_id_t const * p_peers,
+ uint32_t peer_cnt)
+{
+ // Clear the cache of whitelisted peers.
+ memset(m_wlisted_peers, 0x00, sizeof(m_wlisted_peers));
+
+ if ((p_peers == NULL) || (peer_cnt == 0))
+ {
+ // Clear the current whitelist.
+ m_wlisted_peer_cnt = 0;
+
+ // NRF_SUCCESS, or
+ // BLE_GAP_ERROR_WHITELIST_IN_USE
+ return sd_ble_gap_whitelist_set(NULL, 0);
+ }
+
+ // @todo emdi: should not ever cache more than BLE_GAP_WHITELIST_ADDR_MAX_COUNT...
+
+ // Copy the new whitelisted peers.
+ m_wlisted_peer_cnt = peer_cnt;
+ memcpy(m_wlisted_peers, p_peers, sizeof(pm_peer_id_t) * peer_cnt);
+
+ ret_code_t ret;
+ uint32_t wlist_addr_cnt = 0;
+
+ ble_gap_addr_t const * addr_ptrs[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
+ ble_gap_addr_t addrs[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
+
+ memset(addrs, 0x00, sizeof(addrs));
+
+ // Fetch GAP addresses for these peers, but don't fetch IRKs.
+ ret = peers_id_keys_get(p_peers, peer_cnt, addrs, &wlist_addr_cnt, NULL, NULL);
+
+ if (ret != NRF_SUCCESS)
+ {
+ // NRF_ERROR_NOT_FOUND, if a peer or its data were not found.
+ // BLE_ERROR_GAP_INVALID_BLE_ADDR, if a peer address can not be used for whitelisting.
+ return ret;
+ }
+
+ for (uint32_t i = 0; i < BLE_GAP_WHITELIST_ADDR_MAX_COUNT; i++)
+ {
+ addr_ptrs[i] = &addrs[i];
+ }
+
+ // NRF_ERROR_DATA_SIZE, if peer_cnt > BLE_GAP_WHITELIST_ADDR_MAX_COUNT.
+ // BLE_ERROR_GAP_WHITELIST_IN_USE, if a whitelist is in use.
+ return sd_ble_gap_whitelist_set(addr_ptrs, peer_cnt);
+}
+
+
+/**@brief Function for calculating the ah() hash function described in Bluetooth core specification
+ * 4.2 section 3.H.2.2.2.
+ *
+ * @detail BLE uses a hash function to calculate the first half of a resolvable address
+ * from the second half of the address and an irk. This function will use the ECB
+ * periferal to hash these data acording to the Bluetooth core specification.
+ *
+ * @note The ECB expect little endian input and output.
+ * This function expect big endian and will reverse the data as necessary.
+ *
+ * @param[in] p_k The key used in the hash function.
+ * For address resolution this is should be the irk.
+ * The array must have a length of 16.
+ * @param[in] p_r The rand used in the hash function. For generating a new address
+ * this would be a random number. For resolving a resolvable address
+ * this would be the last half of the address being resolved.
+ * The array must have a length of 3.
+ * @param[out] p_local_hash The result of the hash operation. For address resolution this
+ * will match the first half of the address being resolved if and only
+ * if the irk used in the hash function is the same one used to generate
+ * the address.
+ * The array must have a length of 16.
+ */
+void ah(uint8_t const * p_k, uint8_t const * p_r, uint8_t * p_local_hash)
+{
+ nrf_ecb_hal_data_t ecb_hal_data;
+
+ for (uint32_t i = 0; i < SOC_ECB_KEY_LENGTH; i++)
+ {
+ ecb_hal_data.key[i] = p_k[SOC_ECB_KEY_LENGTH - 1 - i];
+ }
+
+ memset(ecb_hal_data.cleartext, 0, SOC_ECB_KEY_LENGTH - IM_ADDR_CLEARTEXT_LENGTH);
+
+ for (uint32_t i = 0; i < IM_ADDR_CLEARTEXT_LENGTH; i++)
+ {
+ ecb_hal_data.cleartext[SOC_ECB_KEY_LENGTH - 1 - i] = p_r[i];
+ }
+
+ // Can only return NRF_SUCCESS.
+ (void) sd_ecb_block_encrypt(&ecb_hal_data);
+
+ for (uint32_t i = 0; i < IM_ADDR_CIPHERTEXT_LENGTH; i++)
+ {
+ p_local_hash[i] = ecb_hal_data.ciphertext[SOC_ECB_KEY_LENGTH - 1 - i];
+ }
+}
+
+
+bool im_address_resolve(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ uint8_t hash[IM_ADDR_CIPHERTEXT_LENGTH];
+ uint8_t local_hash[IM_ADDR_CIPHERTEXT_LENGTH];
+ uint8_t prand[IM_ADDR_CLEARTEXT_LENGTH];
+
+ if (p_addr->addr_type != BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE)
+ {
+ return false;
+ }
+
+ memcpy(hash, p_addr->addr, IM_ADDR_CIPHERTEXT_LENGTH);
+ memcpy(prand, &p_addr->addr[IM_ADDR_CIPHERTEXT_LENGTH], IM_ADDR_CLEARTEXT_LENGTH);
+ ah(p_irk->irk, prand, local_hash);
+
+ return (memcmp(hash, local_hash, IM_ADDR_CIPHERTEXT_LENGTH) == 0);
+}
+#endif // NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/id_manager.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/id_manager.h
new file mode 100644
index 0000000..fc73958
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/id_manager.h
@@ -0,0 +1,327 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef PEER_ID_MANAGER_H__
+#define PEER_ID_MANAGER_H__
+
+#include <stdint.h>
+#include "sdk_errors.h"
+#include "ble.h"
+#include "ble_gap.h"
+#include "peer_manager_types.h"
+#include "peer_manager_internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @cond NO_DOXYGEN
+ * @defgroup id_manager ID Manager
+ * @ingroup peer_manager
+ * @{
+ * @brief An internal module of @ref peer_manager. A module for keeping track of peer identities
+ * (IRK and peer address).
+ */
+
+
+/**@brief Function for initializing the Identity manager.
+ *
+ * @retval NRF_SUCCESS If initialization was successful.
+ * @retval NRF_ERROR_INTERNAL If an error occurred.
+ */
+ret_code_t im_init(void);
+
+
+/**@brief Function for dispatching SoftDevice events to the ID Manager module.
+ *
+ * @param[in] p_ble_evt The SoftDevice event.
+ */
+void im_ble_evt_handler(ble_evt_t const * p_ble_evt);
+
+
+/**@brief Function for getting the corresponding peer ID from a connection handle.
+ *
+ * @param[in] conn_handle The connection handle.
+ *
+ * @return The corresponding peer ID, or @ref PM_PEER_ID_INVALID if none could be resolved.
+ */
+pm_peer_id_t im_peer_id_get_by_conn_handle(uint16_t conn_handle);
+
+
+/**@brief Function for getting the corresponding peer ID from a master ID (EDIV and rand).
+ *
+ * @param[in] p_master_id The master ID.
+ *
+ * @return The corresponding peer ID, or @ref PM_PEER_ID_INVALID if none could be resolved.
+ */
+pm_peer_id_t im_peer_id_get_by_master_id(ble_gap_master_id_t const * p_master_id);
+
+
+/**@brief Function for getting the corresponding connection handle from a peer ID.
+ *
+ * @param[in] peer_id The peer ID.
+ *
+ * @return The corresponding connection handle, or @ref BLE_CONN_HANDLE_INVALID if none could be
+ * resolved.
+ */
+uint16_t im_conn_handle_get(pm_peer_id_t peer_id);
+
+
+/**@brief Function for comparing two master ids
+ * @note Two invalid master IDs will not match.
+ *
+ * @param[in] p_master_id1 First master id for comparison
+ * @param[in] p_master_id2 Second master id for comparison
+ *
+ * @return True if the input matches, false if it does not.
+ */
+bool im_master_ids_compare(ble_gap_master_id_t const * p_master_id1,
+ ble_gap_master_id_t const * p_master_id2);
+
+
+/**@brief Function for getting the BLE address used by the peer when connecting.
+ *
+ * @param[in] conn_handle The connection handle.
+ * @param[out] p_ble_addr The BLE address used by the peer when the connection specified by
+ * conn_handle was established.
+ *
+ * @retval NRF_SUCCESS The address was found and copied.
+ * @retval BLE_ERROR_CONN_HANDLE_INVALID conn_handle does not refer to an active connection.
+ * @retval NRF_ERROR_NULL p_ble_addr was NULL.
+ */
+ret_code_t im_ble_addr_get(uint16_t conn_handle, ble_gap_addr_t * p_ble_addr);
+
+
+/**@brief Function for checking if a master ID is valid or invalid
+ *
+ * @param[in] p_master_id The master ID.
+ *
+ * @retval true The master id is valid.
+ * @retval false The master id is invalid (i.e. all zeros).
+ */
+bool im_master_id_is_valid(ble_gap_master_id_t const * p_master_id);
+
+
+/**@brief Function for checking if two pieces of bonding data correspond to the same peer.
+ *
+ * @param[in] p_bonding_data1 The first piece of bonding data to check.
+ * @param[in] p_bonding_data2 The second piece of bonding data to check.
+ *
+ * @retval true The bonding data correspond to the same peer.
+ * @retval false The bonding data do not correspond to the same peer.
+ */
+bool im_is_duplicate_bonding_data(pm_peer_data_bonding_t const * p_bonding_data1,
+ pm_peer_data_bonding_t const * p_bonding_data2);
+
+
+/**@brief Function for finding if we are already bonded to a peer.
+ *
+ * @param[in] p_bonding_data The bonding data to check.
+ * @param[in] peer_id_skip Optional peer to ignore when searching for duplicates.
+ *
+ * @return An existing peer ID for the peer, or PM_PEER_ID_INVALID if none was found.
+ */
+pm_peer_id_t im_find_duplicate_bonding_data(pm_peer_data_bonding_t const * p_bonding_data,
+ pm_peer_id_t peer_id_skip);
+
+
+/**@brief Function for reporting that a new peer ID has been allocated for a specified connection.
+ *
+ * @param[in] conn_handle The connection.
+ * @param[in] peer_id The new peer ID.
+ */
+void im_new_peer_id(uint16_t conn_handle, pm_peer_id_t peer_id);
+
+
+/**@brief Function for deleting all of a peer's data from flash and disassociating it from any
+ * connection handles it is associated with.
+ *
+ * @param[in] peer_id The peer to free.
+ *
+ * @return Any error code returned by @ref pdb_peer_free.
+ */
+ret_code_t im_peer_free(pm_peer_id_t peer_id);
+
+
+/**@brief Function to set the local Bluetooth identity address.
+ *
+ * @details The local Bluetooth identity address is the address that identifies this device to other
+ * peers. The address type must be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref
+ * BLE_GAP_ADDR_TYPE_RANDOM_STATIC. The identity address cannot be changed while roles are
+ * running.
+ *
+ * @note This address will be distributed to the peer during bonding.
+ * If the address changes, the address stored in the peer device will not be valid and the
+ * ability to reconnect using the old address will be lost.
+ *
+ * @note By default the SoftDevice will set an address of type @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC
+ * upon being enabled. The address is a random number populated during the IC manufacturing
+ * process and remains unchanged for the lifetime of each IC.
+ *
+ * @param[in] p_addr Pointer to address structure.
+ *
+ * @retval NRF_SUCCESS Address successfully set.
+ * @retval BLE_ERROR_GAP_INVALID_BLE_ADDR If the GAP address is invalid.
+ * @retval NRF_ERROR_BUSY Could not process at this time. Process SoftDevice events
+ * and retry.
+ * @retval NRF_ERROR_INVALID_STATE The identity address cannot be changed while advertising,
+ * scanning, or while in a connection.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t im_id_addr_set(ble_gap_addr_t const * p_addr);
+
+
+/**@brief Function to get the local Bluetooth identity address.
+ *
+ * @note This will always return the identity address irrespective of the privacy settings,
+ * i.e. the address type will always be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref
+ * BLE_GAP_ADDR_TYPE_RANDOM_STATIC.
+ *
+ * @param[out] p_addr Pointer to address structure to be filled in.
+ *
+ * @retval NRF_SUCCESS If the address was successfully retrieved.
+ */
+ret_code_t im_id_addr_get(ble_gap_addr_t * p_addr);
+
+
+/**@brief Function to set privacy settings.
+ *
+ * @details Privacy settings cannot be set while advertising, scanning, or while in a connection.
+ *
+ * @param[in] p_privacy_params Privacy settings.
+ *
+ * @retval NRF_SUCCESS If privacy options were set successfully.
+ * @retval NRF_ERROR_NULL If @p p_privacy_params is NULL.
+ * @retval NRF_ERROR_INVALID_PARAM If the address type is not valid.
+ * @retval NRF_ERROR_BUSY If the request could not be processed at this time.
+ * Process SoftDevice events and retry.
+ * @retval NRF_ERROR_INVALID_STATE Privacy settings cannot be changed while BLE roles using
+ * privacy are enabled.
+ */
+ret_code_t im_privacy_set(pm_privacy_params_t const * p_privacy_params);
+
+
+/**@brief Function to retrieve the current privacy settings.
+ *
+ * @details The privacy settings returned include the current device irk as well.
+ *
+ * @param[in] p_privacy_params Privacy settings.
+ *
+ * @retval NRF_SUCCESS Successfully retrieved privacy settings.
+ * @retval NRF_ERROR_NULL @c p_privacy_params is NULL.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t im_privacy_get(pm_privacy_params_t * p_privacy_params);
+
+
+/**@brief Function for resolving a resolvable address with an identity resolution key (IRK).
+ *
+ * @details This function will use the ECB peripheral to resolve a resolvable address.
+ * This can be used to resolve the identity of a device distributing a random
+ * resolvable address based on any IRKs you have received earlier. If an address is
+ * resolved by an IRK, the device distributing the address must also know the IRK.
+ *
+ * @param[in] p_addr A random resolvable address.
+ * @param[in] p_irk An identity resolution key (IRK).
+ *
+ * @retval true The irk used matched the one used to create the address.
+ * @retval false The irk used did not match the one used to create the address, or an argument was
+ * NULL.
+ */
+bool im_address_resolve(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk);
+
+
+/**@brief Function for setting / clearing the whitelist.
+ *
+ * @param p_peers The peers to whitelist. Pass NULL to clear the whitelist.
+ * @param peer_cnt The number of peers to whitelist. Pass zero to clear the whitelist.
+ *
+ * @retval NRF_SUCCESS If the whitelist was successfully set or cleared.
+ * @retval BLE_GAP_ERROR_WHITELIST_IN_USE If a whitelist is in use.
+ * @retval BLE_ERROR_GAP_INVALID_BLE_ADDR If any peer has an address which can not be used
+ * for whitelisting.
+ * @retval NRF_ERROR_NOT_FOUND If any peer or its data could not be found.
+ * @retval NRF_ERROR_DATA_SIZE If @p peer_cnt is greater than
+ * @ref BLE_GAP_WHITELIST_ADDR_MAX_COUNT.
+ */
+ret_code_t im_whitelist_set(pm_peer_id_t const * p_peers,
+ uint32_t const peer_cnt);
+
+
+/**@brief Retrieves the current whitelist, set by a previous call to @ref im_whitelist_set.
+ *
+ * @param[out] A buffer where to copy the GAP addresses.
+ * @param[inout] In: the size of the @p p_addrs buffer.
+ * Out: the number of address copied into the buffer.
+ * @param[out] A buffer where to copy the IRKs.
+ * @param[inout] In: the size of the @p p_irks buffer.
+ * Out: the number of IRKs copied into the buffer.
+ *
+ * @retval NRF_SUCCESS If the whitelist was successfully retreived.
+ * @retval BLE_ERROR_GAP_INVALID_BLE_ADDR If any peer has an address which can not be used for
+ * whitelisting.
+ * @retval NRF_ERROR_NOT_FOUND If the data for any of the cached whitelisted peers
+ * can not be found anymore. It might have been deleted in
+ * the meanwhile.
+ * @retval NRF_ERROR_NO_MEM If the provided buffers are too small.
+ */
+ret_code_t im_whitelist_get(ble_gap_addr_t * p_addrs,
+ uint32_t * p_addr_cnt,
+ ble_gap_irk_t * p_irks,
+ uint32_t * p_irk_cnt);
+
+
+/**@brief Set the device identities list.
+ */
+ret_code_t im_device_identities_list_set(pm_peer_id_t const * p_peers,
+ uint32_t peer_cnt);
+
+
+/** @}
+ * @endcond
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PEER_ID_MANAGER_H__ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_data_storage.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_data_storage.c
new file mode 100644
index 0000000..12058d7
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_data_storage.c
@@ -0,0 +1,678 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "peer_data_storage.h"
+
+#include <stdint.h>
+#include <string.h>
+#include "sdk_errors.h"
+#include "peer_manager_types.h"
+#include "peer_manager_internal.h"
+#include "peer_id.h"
+#include "fds.h"
+
+
+// Macro for verifying that the peer id is within a valid range.
+#define VERIFY_PEER_ID_IN_RANGE(id) VERIFY_FALSE((id >= PM_PEER_ID_N_AVAILABLE_IDS), \
+ NRF_ERROR_INVALID_PARAM)
+
+// Macro for verifying that the peer data id is withing a valid range.
+#define VERIFY_PEER_DATA_ID_IN_RANGE(id) VERIFY_TRUE(peer_data_id_is_valid(id), \
+ NRF_ERROR_INVALID_PARAM)
+
+// The number of registered event handlers.
+#define PDS_EVENT_HANDLERS_CNT (sizeof(m_evt_handlers) / sizeof(m_evt_handlers[0]))
+
+
+// Peer Data Storage event handler in Peer Database.
+extern void pdb_pds_evt_handler(pm_evt_t *);
+
+// Peer Data Storage events' handlers.
+// The number of elements in this array is PDS_EVENT_HANDLERS_CNT.
+static pm_evt_handler_internal_t const m_evt_handlers[] =
+{
+ pdb_pds_evt_handler,
+};
+
+static bool m_module_initialized = false;
+static volatile bool m_peer_delete_deferred = false;
+
+// A token used for Flash Data Storage searches.
+static fds_find_token_t m_fds_ftok;
+
+
+// Function for dispatching events to all registered event handlers.
+static void pds_evt_send(pm_evt_t * p_event)
+{
+ p_event->conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ for (uint32_t i = 0; i < PDS_EVENT_HANDLERS_CNT; i++)
+ {
+ m_evt_handlers[i](p_event);
+ }
+}
+
+
+// Function to convert peer IDs to file IDs.
+static uint16_t peer_id_to_file_id(pm_peer_id_t peer_id)
+{
+ return (uint16_t)(peer_id + PEER_ID_TO_FILE_ID);
+}
+
+
+// Function to convert peer data id to type id.
+static pm_peer_id_t file_id_to_peer_id(uint16_t file_id)
+{
+ return (pm_peer_id_t)(file_id + FILE_ID_TO_PEER_ID);
+}
+
+
+// Function to convert peer data IDs to record keys.
+static uint16_t peer_data_id_to_record_key(pm_peer_data_id_t peer_data_id)
+{
+ return (uint16_t)(peer_data_id + DATA_ID_TO_RECORD_KEY);
+}
+
+
+// Function to convert record keys to peer data IDs.
+static pm_peer_data_id_t record_key_to_peer_data_id(uint16_t record_key)
+{
+ return (pm_peer_data_id_t)(record_key + RECORD_KEY_TO_DATA_ID);
+}
+
+
+// Function for checking whether a file ID is relevant for the Peer Manager.
+static bool file_id_within_pm_range(uint16_t file_id)
+{
+ return ((PDS_FIRST_RESERVED_FILE_ID <= file_id)
+ && (file_id <= PDS_LAST_RESERVED_FILE_ID));
+}
+
+
+// Function for checking whether a record key is relevant for the Peer Manager.
+static bool record_key_within_pm_range(uint16_t record_key)
+{
+ return ((PDS_FIRST_RESERVED_RECORD_KEY <= record_key)
+ && (record_key <= PDS_LAST_RESERVED_RECORD_KEY));
+}
+
+
+static bool peer_data_id_is_valid(pm_peer_data_id_t data_id)
+{
+ return ((data_id == PM_PEER_DATA_ID_BONDING) ||
+ (data_id == PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING) ||
+ (data_id == PM_PEER_DATA_ID_GATT_LOCAL) ||
+ (data_id == PM_PEER_DATA_ID_GATT_REMOTE) ||
+ (data_id == PM_PEER_DATA_ID_PEER_RANK) ||
+ (data_id == PM_PEER_DATA_ID_APPLICATION));
+}
+
+
+/**@brief Function for sending a PM_EVT_ERROR_UNEXPECTED event.
+ *
+ * @param[in] peer_id The peer the event pertains to.
+ * @param[in] err_code The unexpected error that occurred.
+ */
+static void send_unexpected_error(pm_peer_id_t peer_id, ret_code_t err_code)
+{
+ pm_evt_t error_evt =
+ {
+ .evt_id = PM_EVT_ERROR_UNEXPECTED,
+ .peer_id = peer_id,
+ .params =
+ {
+ .error_unexpected =
+ {
+ .error = err_code,
+ }
+ }
+ };
+ pds_evt_send(&error_evt);
+}
+
+
+// Function for deleting all data beloning to a peer.
+// These operations will be sent to FDS one at a time.
+static void peer_data_delete_process()
+{
+ ret_code_t ret;
+ pm_peer_id_t peer_id;
+ uint16_t file_id;
+ fds_record_desc_t desc;
+ fds_find_token_t ftok;
+
+ m_peer_delete_deferred = false;
+
+ memset(&ftok, 0x00, sizeof(fds_find_token_t));
+ peer_id = peer_id_get_next_deleted(PM_PEER_ID_INVALID);
+
+ while ( (peer_id != PM_PEER_ID_INVALID)
+ && (fds_record_find_in_file(peer_id_to_file_id(peer_id), &desc, &ftok)
+ == FDS_ERR_NOT_FOUND))
+ {
+ peer_id_free(peer_id);
+ peer_id = peer_id_get_next_deleted(peer_id);
+ }
+
+ if (peer_id != PM_PEER_ID_INVALID)
+ {
+ file_id = peer_id_to_file_id(peer_id);
+ ret = fds_file_delete(file_id);
+
+ if (ret == FDS_ERR_NO_SPACE_IN_QUEUES)
+ {
+ m_peer_delete_deferred = true;
+ }
+ else if (ret != FDS_SUCCESS)
+ {
+ send_unexpected_error(peer_id, ret);
+ }
+ }
+}
+
+
+static ret_code_t peer_data_find(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ fds_record_desc_t * const p_desc)
+{
+ ret_code_t ret;
+ fds_find_token_t ftok;
+
+ NRF_PM_DEBUG_CHECK(peer_id < PM_PEER_ID_N_AVAILABLE_IDS);
+ NRF_PM_DEBUG_CHECK(peer_data_id_is_valid(data_id));
+ NRF_PM_DEBUG_CHECK(p_desc != NULL);
+
+ memset(&ftok, 0x00, sizeof(fds_find_token_t));
+
+ uint16_t file_id = peer_id_to_file_id(peer_id);
+ uint16_t record_key = peer_data_id_to_record_key(data_id);
+
+ ret = fds_record_find(file_id, record_key, p_desc, &ftok);
+
+ if (ret != FDS_SUCCESS)
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+static void peer_ids_load()
+{
+ fds_record_desc_t record_desc;
+ fds_flash_record_t record;
+ fds_find_token_t ftok;
+
+ memset(&ftok, 0x00, sizeof(fds_find_token_t));
+
+ uint16_t const record_key = peer_data_id_to_record_key(PM_PEER_DATA_ID_BONDING);
+
+ while (fds_record_find_by_key(record_key, &record_desc, &ftok) == FDS_SUCCESS)
+ {
+ pm_peer_id_t peer_id;
+
+ // It is safe to ignore the return value since the descriptor was
+ // just obtained and also 'record' is different from NULL.
+ (void)fds_record_open(&record_desc, &record);
+ peer_id = file_id_to_peer_id(record.p_header->file_id);
+ (void)fds_record_close(&record_desc);
+
+ (void)peer_id_allocate(peer_id);
+ }
+}
+
+
+static void fds_evt_handler(fds_evt_t const * const p_fds_evt)
+{
+ pm_evt_t pds_evt =
+ {
+ .peer_id = file_id_to_peer_id(p_fds_evt->write.file_id)
+ };
+
+ switch (p_fds_evt->id)
+ {
+ case FDS_EVT_WRITE:
+ case FDS_EVT_UPDATE:
+ case FDS_EVT_DEL_RECORD:
+ if ( file_id_within_pm_range(p_fds_evt->write.file_id)
+ || record_key_within_pm_range(p_fds_evt->write.record_key))
+ {
+ pds_evt.params.peer_data_update_succeeded.data_id
+ = record_key_to_peer_data_id(p_fds_evt->write.record_key);
+ pds_evt.params.peer_data_update_succeeded.action
+ = (p_fds_evt->id == FDS_EVT_DEL_RECORD) ? PM_PEER_DATA_OP_DELETE
+ : PM_PEER_DATA_OP_UPDATE;
+ pds_evt.params.peer_data_update_succeeded.token = p_fds_evt->write.record_id;
+
+ if (p_fds_evt->result == FDS_SUCCESS)
+ {
+ pds_evt.evt_id = PM_EVT_PEER_DATA_UPDATE_SUCCEEDED;
+ pds_evt.params.peer_data_update_succeeded.flash_changed = true;
+ }
+ else
+ {
+ pds_evt.evt_id = PM_EVT_PEER_DATA_UPDATE_FAILED;
+ pds_evt.params.peer_data_update_failed.error = p_fds_evt->result;
+ }
+
+ pds_evt_send(&pds_evt);
+ }
+ break;
+
+ case FDS_EVT_DEL_FILE:
+ if ( file_id_within_pm_range(p_fds_evt->del.file_id)
+ && (p_fds_evt->del.record_key == FDS_RECORD_KEY_DIRTY))
+ {
+ if (p_fds_evt->result == FDS_SUCCESS)
+ {
+ pds_evt.evt_id = PM_EVT_PEER_DELETE_SUCCEEDED;
+ peer_id_free(pds_evt.peer_id);
+ }
+ else
+ {
+ pds_evt.evt_id = PM_EVT_PEER_DELETE_FAILED;
+ }
+
+ m_peer_delete_deferred = true; // Trigger remaining deletes.
+
+ pds_evt_send(&pds_evt);
+ }
+ break;
+
+ case FDS_EVT_GC:
+ pds_evt.evt_id = PM_EVT_FLASH_GARBAGE_COLLECTED;
+ pds_evt.peer_id = PM_PEER_ID_INVALID;
+
+ pds_evt_send(&pds_evt);
+ break;
+
+ default:
+ // No action.
+ break;
+ }
+
+ if (m_peer_delete_deferred)
+ {
+ peer_data_delete_process();
+ }
+}
+
+
+ret_code_t pds_init()
+{
+ ret_code_t ret;
+
+ // Check for re-initialization if debugging.
+ NRF_PM_DEBUG_CHECK(!m_module_initialized);
+
+ ret = fds_register(fds_evt_handler);
+ if (ret != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ ret = fds_init();
+ if (ret != NRF_SUCCESS)
+ {
+ return NRF_ERROR_STORAGE_FULL;
+ }
+
+ peer_id_init();
+ peer_ids_load();
+
+ m_module_initialized = true;
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t pds_peer_data_read(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ pm_peer_data_t * const p_data,
+ uint32_t const * const p_buf_len)
+{
+ ret_code_t ret;
+ fds_record_desc_t rec_desc;
+ fds_flash_record_t rec_flash;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_data != NULL);
+
+ VERIFY_PEER_ID_IN_RANGE(peer_id);
+ VERIFY_PEER_DATA_ID_IN_RANGE(data_id);
+
+ ret = peer_data_find(peer_id, data_id, &rec_desc);
+
+ if (ret != NRF_SUCCESS)
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ // Shouldn't fail, unless the record was deleted in the meanwhile or the CRC check has failed.
+ ret = fds_record_open(&rec_desc, &rec_flash);
+
+ if (ret != NRF_SUCCESS)
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ p_data->data_id = data_id;
+ p_data->length_words = rec_flash.p_header->length_words;
+
+ // If p_buf_len is NULL, provide a pointer to data in flash, otherwise,
+ // check that the buffer is large enough and copy the data in flash into the buffer.
+ if (p_buf_len == NULL)
+ {
+ // The cast is necessary because if no buffer is provided, we just copy the pointer,
+ // but in that case it should be considered a pointer to const data by the caller,
+ // since it is a pointer to data in flash.
+ p_data->p_all_data = (void*)rec_flash.p_data;
+ }
+ else
+ {
+ uint32_t const data_len_bytes = (p_data->length_words * sizeof(uint32_t));
+
+ if ((*p_buf_len) >= data_len_bytes)
+ {
+ memcpy(p_data->p_all_data, rec_flash.p_data, data_len_bytes);
+ }
+ else
+ {
+ return NRF_ERROR_NO_MEM;
+ }
+ }
+
+ // Shouldn't fail unless the record was already closed, in which case it can be ignored.
+ (void)fds_record_close(&rec_desc);
+
+ return NRF_SUCCESS;
+}
+
+
+void pds_peer_data_iterate_prepare(void)
+{
+ memset(&m_fds_ftok, 0x00, sizeof(fds_find_token_t));
+}
+
+
+bool pds_peer_data_iterate(pm_peer_data_id_t data_id,
+ pm_peer_id_t * const p_peer_id,
+ pm_peer_data_flash_t * const p_data)
+{
+ ret_code_t ret;
+ uint16_t rec_key;
+ fds_record_desc_t rec_desc;
+ fds_flash_record_t rec_flash;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_peer_id != NULL);
+ NRF_PM_DEBUG_CHECK(p_data != NULL);
+
+ VERIFY_PEER_DATA_ID_IN_RANGE(data_id);
+
+ rec_key = peer_data_id_to_record_key(data_id);
+
+ if (fds_record_find_by_key(rec_key, &rec_desc, &m_fds_ftok) != NRF_SUCCESS)
+ {
+ return false;
+ }
+
+ ret = fds_record_open(&rec_desc, &rec_flash);
+
+ if (ret != NRF_SUCCESS)
+ {
+ // It can only happen if the record was deleted after the call to fds_record_find_by_key(),
+ // before we could open it, or if CRC support was enabled in Flash Data Storage at compile
+ // time and the CRC check failed.
+ return false;
+ }
+
+ p_data->data_id = data_id;
+ p_data->length_words = rec_flash.p_header->length_words;
+ p_data->p_all_data = rec_flash.p_data;
+
+ *p_peer_id = file_id_to_peer_id(rec_flash.p_header->file_id);
+
+ (void)fds_record_close(&rec_desc);
+
+ return true;
+}
+
+
+ret_code_t pds_space_reserve(pm_peer_data_const_t const * p_peer_data,
+ pm_prepare_token_t * p_prepare_token)
+{
+ ret_code_t ret;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_peer_data != NULL);
+ NRF_PM_DEBUG_CHECK(p_prepare_token != NULL);
+
+ VERIFY_PEER_DATA_ID_IN_RANGE(p_peer_data->data_id);
+
+ ret = fds_reserve((fds_reserve_token_t*)p_prepare_token, p_peer_data->length_words);
+
+ switch (ret)
+ {
+ case FDS_SUCCESS:
+ return NRF_SUCCESS;
+
+ case FDS_ERR_RECORD_TOO_LARGE:
+ return NRF_ERROR_INVALID_LENGTH;
+
+ case FDS_ERR_NO_SPACE_IN_FLASH:
+ return NRF_ERROR_STORAGE_FULL;
+
+ default:
+ return NRF_ERROR_INTERNAL;
+ }
+}
+
+
+ret_code_t pds_space_reserve_cancel(pm_prepare_token_t prepare_token)
+{
+ ret_code_t ret;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(prepare_token != PDS_PREPARE_TOKEN_INVALID);
+
+ ret = fds_reserve_cancel((fds_reserve_token_t*)&prepare_token);
+
+ if (ret != FDS_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t pds_peer_data_store(pm_peer_id_t peer_id,
+ pm_peer_data_const_t const * p_peer_data,
+ pm_prepare_token_t prepare_token,
+ pm_store_token_t * p_store_token)
+{
+ ret_code_t ret;
+ fds_record_t rec;
+ fds_record_desc_t rec_desc;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_peer_data != NULL);
+
+ VERIFY_PEER_ID_IN_RANGE(peer_id);
+ VERIFY_PEER_DATA_ID_IN_RANGE(p_peer_data->data_id);
+
+ // Prepare the record to be stored in flash.
+ rec.file_id = peer_id_to_file_id(peer_id);
+ rec.key = peer_data_id_to_record_key(p_peer_data->data_id);
+ rec.data.p_data = (void*)p_peer_data->p_all_data;
+ rec.data.length_words = p_peer_data->length_words;
+
+ ret = peer_data_find(peer_id, p_peer_data->data_id, &rec_desc);
+
+ if (ret == NRF_ERROR_NOT_FOUND)
+ {
+ // No previous data exists in flash.
+ if (prepare_token == PDS_PREPARE_TOKEN_INVALID)
+ {
+ // No space was previously reserved.
+ ret = fds_record_write(&rec_desc, &rec);
+ }
+ else
+ {
+ // Space for this record was previously reserved.
+ ret = fds_record_write_reserved(&rec_desc, &rec, (fds_reserve_token_t*)&prepare_token);
+ }
+ }
+ else // NRF_SUCCESS
+ {
+ if (prepare_token != PDS_PREPARE_TOKEN_INVALID)
+ {
+ (void)fds_reserve_cancel((fds_reserve_token_t*)&prepare_token);
+ }
+
+ // Update existing record.
+ ret = fds_record_update(&rec_desc, &rec);
+ }
+
+ switch (ret)
+ {
+ case FDS_SUCCESS:
+ if (p_store_token != NULL)
+ {
+ // Update the store token.
+ (void)fds_record_id_from_desc(&rec_desc, (uint32_t*)p_store_token);
+ }
+ return NRF_SUCCESS;
+
+ case FDS_ERR_BUSY:
+ case FDS_ERR_NO_SPACE_IN_QUEUES:
+ return NRF_ERROR_BUSY;
+
+ case FDS_ERR_NO_SPACE_IN_FLASH:
+ return NRF_ERROR_STORAGE_FULL;
+
+ default:
+ return NRF_ERROR_INTERNAL;
+ }
+}
+
+
+ret_code_t pds_peer_data_delete(pm_peer_id_t peer_id, pm_peer_data_id_t data_id)
+{
+ ret_code_t ret;
+ fds_record_desc_t record_desc;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ VERIFY_PEER_ID_IN_RANGE(peer_id);
+ VERIFY_PEER_DATA_ID_IN_RANGE(data_id);
+
+ ret = peer_data_find(peer_id, data_id, &record_desc);
+
+ if (ret != NRF_SUCCESS)
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ ret = fds_record_delete(&record_desc);
+
+ switch (ret)
+ {
+ case FDS_SUCCESS:
+ return NRF_SUCCESS;
+
+ case FDS_ERR_NO_SPACE_IN_QUEUES:
+ return NRF_ERROR_BUSY;
+
+ default:
+ return NRF_ERROR_INTERNAL;
+ }
+}
+
+
+pm_peer_id_t pds_peer_id_allocate(void)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return peer_id_allocate(PM_PEER_ID_INVALID);
+}
+
+
+ret_code_t pds_peer_id_free(pm_peer_id_t peer_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ VERIFY_PEER_ID_IN_RANGE(peer_id);
+
+ (void)peer_id_delete(peer_id);
+ peer_data_delete_process();
+
+ return NRF_SUCCESS;
+}
+
+
+bool pds_peer_id_is_allocated(pm_peer_id_t peer_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return peer_id_is_allocated(peer_id);
+}
+
+
+pm_peer_id_t pds_next_peer_id_get(pm_peer_id_t prev_peer_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return peer_id_get_next_used(prev_peer_id);
+}
+
+
+pm_peer_id_t pds_next_deleted_peer_id_get(pm_peer_id_t prev_peer_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return peer_id_get_next_deleted(prev_peer_id);
+}
+
+
+uint32_t pds_peer_count_get(void)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return peer_id_n_ids();
+}
+#endif // NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_data_storage.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_data_storage.h
new file mode 100644
index 0000000..fccfabc
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_data_storage.h
@@ -0,0 +1,270 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef PEER_DATA_STORAGE_H__
+#define PEER_DATA_STORAGE_H__
+
+
+#include <stdint.h>
+#include "sdk_errors.h"
+#include "ble_gap.h"
+#include "peer_manager_types.h"
+#include "peer_manager_internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @cond NO_DOXYGEN
+ * @defgroup peer_data_storage Peer Data Storage
+ * @ingroup peer_manager
+ * @{
+ * @brief An internal module of @ref peer_manager. This module provides a Peer Manager-specific API
+ * to the persistent storage.
+ *
+ * @details This module uses Flash Data Storage (FDS) to interface with persistent storage.
+ */
+
+#define PDS_PREPARE_TOKEN_INVALID (0) /**< Invalid value for prepare token. */
+#define PDS_FIRST_RESERVED_FILE_ID (0xC000) /**< The beginning of the range of file IDs reserved for Peer Manager. */
+#define PDS_LAST_RESERVED_FILE_ID (0xFFFE) /**< The end of the range of file IDs reserved for Peer Manager. */
+#define PDS_FIRST_RESERVED_RECORD_KEY (0xC000) /**< The beginning of the range of record keys reserved for Peer Manager. */
+#define PDS_LAST_RESERVED_RECORD_KEY (0xFFFE) /**< The end of the range of record keys reserved for Peer Manager. */
+
+#define PEER_ID_TO_FILE_ID ( PDS_FIRST_RESERVED_FILE_ID) //!< Macro for converting a @ref pm_peer_id_t to an FDS file ID.
+#define FILE_ID_TO_PEER_ID (-PDS_FIRST_RESERVED_FILE_ID) //!< Macro for converting an FDS file ID to a @ref pm_peer_id_t.
+#define DATA_ID_TO_RECORD_KEY ( PDS_FIRST_RESERVED_RECORD_KEY) //!< Macro for converting a @ref pm_peer_data_id_t to an FDS record ID.
+#define RECORD_KEY_TO_DATA_ID (-PDS_FIRST_RESERVED_RECORD_KEY) //!< Macro for converting an FDS record ID to a @ref pm_peer_data_id_t.
+
+
+/**@brief Function for initializing the module.
+ *
+ * @retval NRF_SUCCESS If initialization was successful.
+ * @retval NRF_ERROR_STORAGE_FULL If no flash pages were available for use.
+ * @retval NRF_ERROR_INTERNAL If the module couldn't register with the flash filesystem.
+ */
+ret_code_t pds_init(void);
+
+
+/**@brief Function for reading peer data in flash.
+ *
+ * @param[in] peer_id The peer the data belongs to.
+ * @param[in] data_id The data to retrieve.
+ * @param[out] p_data The peer data. May not be @c NULL.
+ * @param[in] p_buf_len Length of the provided buffer, in bytes. Pass @c NULL to only copy
+ * a pointer to the data in flash.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_INVALID_PARAM If @p peer_id or @p data_id are invalid.
+ * @retval NRF_ERROR_NOT_FOUND If the data was not found in flash.
+ * @retval NRF_ERROR_NO_MEM If the provided buffer is too small.
+ */
+ret_code_t pds_peer_data_read(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ pm_peer_data_t * const p_data,
+ uint32_t const * const p_buf_len);
+
+
+/**@brief Function to prepare iterating over peer data in flash using @ref pds_peer_data_iterate.
+ * Call this function once each time before iterating using @ref pds_peer_data_iterate.
+ */
+void pds_peer_data_iterate_prepare(void);
+
+
+/**@brief Function for iterating peers' data in flash.
+ * Always call @ref pds_peer_data_iterate_prepare before starting iterating.
+ *
+ * @param[in] data_id The peer data to iterate over.
+ * @param[out] p_peer_id The peer the data belongs to.
+ * @param[out] p_data The peer data in flash.
+ *
+ * @retval true If the operation was successful.
+ * @retval false If the data was not found in flash, or another error occurred.
+ */
+bool pds_peer_data_iterate(pm_peer_data_id_t data_id,
+ pm_peer_id_t * const p_peer_id,
+ pm_peer_data_flash_t * const p_data);
+
+
+/**@brief Function for reserving space in flash to store data.
+ *
+ * @param[in] p_peer_data The data to be stored in flash. Only data length and type (ID) are
+ * relevant for this operation. May not be @c NULL.
+ * @param[out] p_prepare_token A token identifying the reserved space. May not be @c NULL.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_INVALID_PARAM If the data ID in @p p_peer_data is invalid.
+ * @retval NRF_ERROR_INVALID_LENGTH If data length exceeds the maximum allowed length.
+ * @retval NRF_ERROR_STORAGE_FULL If no space is available in flash.
+ * @retval NRF_ERROR_INTERNAL If an unexpected error occurred.
+ */
+ret_code_t pds_space_reserve(pm_peer_data_const_t const * p_peer_data,
+ pm_prepare_token_t * p_prepare_token);
+
+
+/**@brief Function for undoing a previous call to @ref pds_space_reserve.
+ *
+ * @param[in] prepare_token A token identifying the reservation to cancel.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_INTERNAL If an unexpected error occurred.
+ */
+ret_code_t pds_space_reserve_cancel(pm_prepare_token_t prepare_token);
+
+
+/**@brief Function for storing peer data in flash. If the same piece of data already exists for the
+ * given peer, it will be updated. This operation is asynchronous.
+ * Expect a @ref PM_EVT_PEER_DATA_UPDATE_SUCCEEDED or @ref PM_EVT_PEER_DATA_UPDATE_FAILED
+ * event.
+ *
+ * @param[in] peer_id The peer the data belongs to.
+ * @param[in] p_peer_data The peer data. May not be @c NULL.
+ * @param[in] prepare_token A token identifying the reservation made in flash to store the data.
+ * Pass @ref PDS_PREPARE_TOKEN_INVALID if no space was reserved.
+ * @param[out] p_store_token A token identifying this particular store operation. The token can be
+ * used to identify events pertaining to this operation. Pass @p NULL
+ * if not used.
+ *
+ * @retval NRF_SUCCESS If the operation was initiated successfully.
+ * @retval NRF_ERROR_INVALID_PARAM If @p peer_id or the data ID in @p_peer_data are invalid.
+ * @retval NRF_ERROR_STORAGE_FULL If no space is available in flash. This can only happen if
+ * @p p_prepare_token is @ref PDS_PREPARE_TOKEN_INVALID.
+ * @retval NRF_ERROR_BUSY If the flash filesystem was busy.
+ * @retval NRF_ERROR_INTERNAL If an unexpected error occurred.
+ */
+ret_code_t pds_peer_data_store(pm_peer_id_t peer_id,
+ pm_peer_data_const_t const * p_peer_data,
+ pm_prepare_token_t prepare_token,
+ pm_store_token_t * p_store_token);
+
+
+/**@brief Function for deleting peer data in flash. This operation is asynchronous.
+ * Expect a @ref PM_EVT_PEER_DATA_UPDATE_SUCCEEDED or @ref PM_EVT_PEER_DATA_UPDATE_FAILED
+ * event.
+ *
+ * @param[in] peer_id The peer the data belongs to
+ * @param[in] data_id The data to delete.
+ *
+ * @retval NRF_SUCCESS If the operation was initiated successfully.
+ * @retval NRF_ERROR_INVALID_PARAM If @p peer_id or @p data_id are invalid.
+ * @retval NRF_ERROR_NOT_FOUND If data was not found in flash.
+ * @retval NRF_ERROR_BUSY If the flash filesystem was busy.
+ * @retval NRF_ERROR_INTERNAL If an unexpected error occurred.
+ */
+ret_code_t pds_peer_data_delete(pm_peer_id_t peer_id, pm_peer_data_id_t data_id);
+
+
+/**@brief Function for claiming an unused peer ID.
+ *
+ * @retval PM_PEER_ID_INVALID If no peer ID was available.
+ */
+pm_peer_id_t pds_peer_id_allocate(void);
+
+
+/**@brief Function for freeing a peer ID and deleting all data associated with it in flash.
+ *
+ * @param[in] peer_id The ID of the peer to free.
+ *
+ * @retval NRF_SUCCESS The operation was initiated successfully.
+ * @retval NRF_ERROR_INVALID_PARAM If @p peer_id is invalid.
+ */
+ret_code_t pds_peer_id_free(pm_peer_id_t peer_id);
+
+
+/**@brief Function for finding out whether a peer ID is in use.
+ *
+ * @param[in] peer_id The peer ID to inquire about.
+ *
+ * @retval true @p peer_id is in use.
+ * @retval false @p peer_id is free.
+ */
+bool pds_peer_id_is_allocated(pm_peer_id_t peer_id);
+
+
+/**@brief Function for getting the next peer ID in the sequence of all used peer IDs. Can be
+ * used to loop through all used peer IDs.
+ *
+ * @note @ref PM_PEER_ID_INVALID is considered to be before the first and after the last ordinary
+ * peer ID.
+ *
+ * @param[in] prev_peer_id The previous peer ID.
+ *
+ * @return The first ordinary peer ID If @p prev_peer_id is @ref PM_PEER_ID_INVALID.
+ * @retval PM_PEER_ID_INVALID If @p prev_peer_id is the last ordinary peer ID or the module
+ * is not initialized.
+ */
+pm_peer_id_t pds_next_peer_id_get(pm_peer_id_t prev_peer_id);
+
+
+/**@brief Function for getting the next peer ID in the sequence of all peer IDs pending deletion.
+ * Can be used to loop through all used peer IDs.
+ *
+ * @note @ref PM_PEER_ID_INVALID is considered to be before the first and after the last ordinary
+ * peer ID.
+ *
+ * @param[in] prev_peer_id The previous peer ID.
+ *
+ * @return The next peer ID pending deletion.
+ * @return The first ordinary peer ID if prev_peer_id was @ref PM_PEER_ID_INVALID.
+ * @retval PM_PEER_ID_INVALID if prev_peer_id was the last ordinary peer ID or the module
+ * is not initialized.
+ */
+pm_peer_id_t pds_next_deleted_peer_id_get(pm_peer_id_t prev_peer_id);
+
+
+/**@brief Function for querying the number of valid peer IDs available. I.E the number of peers
+ * in persistent storage.
+ *
+ * @return The number of valid peer IDs.
+ */
+uint32_t pds_peer_count_get(void);
+
+
+/** @}
+ * @endcond
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PEER_DATA_STORAGE_H__ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_database.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_database.c
new file mode 100644
index 0000000..53b6680
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_database.c
@@ -0,0 +1,814 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "peer_database.h"
+
+#include <string.h>
+#include "peer_manager_types.h"
+#include "peer_manager_internal.h"
+#include "peer_data_storage.h"
+#include "pm_buffer.h"
+
+
+/**@brief Macro for verifying that the data ID is among the values eligible for using the write buffer.
+ *
+ * @param[in] data_id The data ID to verify.
+ */
+// @note emdi: could this maybe be a function?
+#define VERIFY_DATA_ID_WRITE_BUF(data_id) \
+do \
+{ \
+ if (((data_id) != PM_PEER_DATA_ID_BONDING) && ((data_id) != PM_PEER_DATA_ID_GATT_LOCAL)) \
+ { \
+ return NRF_ERROR_INVALID_PARAM; \
+ } \
+} while (0)
+
+
+// The number of registered event handlers.
+#define PDB_EVENT_HANDLERS_CNT (sizeof(m_evt_handlers) / sizeof(m_evt_handlers[0]))
+
+
+// Peer Database event handlers in other Peer Manager submodules.
+extern void pm_pdb_evt_handler(pm_evt_t * p_event);
+extern void sm_pdb_evt_handler(pm_evt_t * p_event);
+#if !defined(PM_SERVICE_CHANGED_ENABLED) || (PM_SERVICE_CHANGED_ENABLED == 1)
+extern void gscm_pdb_evt_handler(pm_evt_t * p_event);
+#endif
+extern void gcm_pdb_evt_handler(pm_evt_t * p_event);
+
+// Peer Database events' handlers.
+// The number of elements in this array is PDB_EVENT_HANDLERS_CNT.
+static pm_evt_handler_internal_t const m_evt_handlers[] =
+{
+ pm_pdb_evt_handler,
+ sm_pdb_evt_handler,
+#if !defined(PM_SERVICE_CHANGED_ENABLED) || (PM_SERVICE_CHANGED_ENABLED == 1)
+ gscm_pdb_evt_handler,
+#endif
+ gcm_pdb_evt_handler,
+};
+
+
+/**@brief Struct for keeping track of one write buffer, from allocation, until it is fully written
+ * or cancelled.
+ */
+typedef struct
+{
+ pm_peer_id_t peer_id; /**< The peer ID this buffer belongs to. */
+ pm_peer_data_id_t data_id; /**< The data ID this buffer belongs to. */
+ pm_prepare_token_t prepare_token; /**< Token given by Peer Data Storage if room in flash has been reserved. */
+ pm_store_token_t store_token; /**< Token given by Peer Data Storage when a flash write has been successfully requested. This is used as the check for whether such an operation has been successfully requested. */
+ uint8_t n_bufs; /**< The number of buffer blocks containing peer data. */
+ uint8_t buffer_block_id; /**< The index of the first (or only) buffer block containing peer data. */
+ uint8_t store_flash_full : 1; /**< Flag indicating that the buffer was attempted written to flash, but a flash full error was returned and the operation should be retried after room has been made. */
+ uint8_t store_busy : 1; /**< Flag indicating that the buffer was attempted written to flash, but a busy error was returned and the operation should be retried. */
+} pdb_buffer_record_t;
+
+
+static bool m_module_initialized;
+static pm_buffer_t m_write_buffer; /**< The internal states of the write buffer. */
+static pdb_buffer_record_t m_write_buffer_records[PM_FLASH_BUFFERS]; /**< The available write buffer records. */
+static bool m_pending_store = false; /**< Whether there are any pending (Not yet successfully requested in Peer Data Storage) store operations. This flag is for convenience only. The real bookkeeping is in the records (@ref m_write_buffer_records). */
+
+
+
+/**@brief Function for invalidating a record of a write buffer allocation.
+ *
+ * @param[in] p_record The record to invalidate.
+ */
+static void write_buffer_record_invalidate(pdb_buffer_record_t * p_record)
+{
+ p_record->peer_id = PM_PEER_ID_INVALID;
+ p_record->data_id = PM_PEER_DATA_ID_INVALID;
+ p_record->buffer_block_id = PM_BUFFER_INVALID_ID;
+ p_record->store_busy = false;
+ p_record->store_flash_full = false;
+ p_record->n_bufs = 0;
+ p_record->prepare_token = PDS_PREPARE_TOKEN_INVALID;
+ p_record->store_token = PM_STORE_TOKEN_INVALID;
+}
+
+
+/**@brief Function for finding a record of a write buffer allocation.
+ *
+ * @param[in] peer_id The peer ID in the record.
+ * @param[inout] p_index In: The starting index, out: The index of the record
+ *
+ * @return A pointer to the matching record, or NULL if none was found.
+ */
+static pdb_buffer_record_t * write_buffer_record_find_next(pm_peer_id_t peer_id, uint32_t * p_index)
+{
+ for (uint32_t i = *p_index; i < PM_FLASH_BUFFERS; i++)
+ {
+ if ((m_write_buffer_records[i].peer_id == peer_id))
+ {
+ *p_index = i;
+ return &m_write_buffer_records[i];
+ }
+ }
+ return NULL;
+}
+
+
+/**@brief Function for finding a record of a write buffer allocation.
+ *
+ * @param[in] peer_id The peer ID in the record.
+ * @param[in] data_id The data ID in the record.
+ *
+ * @return A pointer to the matching record, or NULL if none was found.
+ */
+static pdb_buffer_record_t * write_buffer_record_find(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id)
+{
+ uint32_t index = 0;
+ pdb_buffer_record_t * p_record = write_buffer_record_find_next(peer_id, &index);
+
+ while ((p_record != NULL) && ( (p_record->data_id != data_id)
+ || (p_record->store_busy)
+ || (p_record->store_flash_full)
+ || (p_record->store_token != PM_STORE_TOKEN_INVALID)))
+ {
+ index++;
+ p_record = write_buffer_record_find_next(peer_id, &index);
+ }
+
+ return p_record;
+}
+
+
+/**@brief Function for finding a record of a write buffer allocation that has been sent to be stored.
+ *
+ * @param[in] store_token The store token received when store was called for the record.
+ *
+ * @return A pointer to the matching record, or NULL if none was found.
+ */
+static pdb_buffer_record_t * write_buffer_record_find_stored(pm_store_token_t store_token)
+{
+ for (int i = 0; i < PM_FLASH_BUFFERS; i++)
+ {
+ if (m_write_buffer_records[i].store_token == store_token)
+ {
+ return &m_write_buffer_records[i];
+ }
+ }
+ return NULL;
+}
+
+
+/**@brief Function for finding an available record for write buffer allocation.
+ *
+ * @return A pointer to the available record, or NULL if none was found.
+ */
+static pdb_buffer_record_t * write_buffer_record_find_unused(void)
+{
+ return write_buffer_record_find(PM_PEER_ID_INVALID, PM_PEER_DATA_ID_INVALID);
+}
+
+
+/**@brief Function for gracefully deactivating a write buffer record.
+ *
+ * @details This function will first release any buffers, then invalidate the record.
+ *
+ * @param[inout] p_write_buffer_record The record to release.
+ *
+ * @return A pointer to the matching record, or NULL if none was found.
+ */
+static void write_buffer_record_release(pdb_buffer_record_t * p_write_buffer_record)
+{
+ for (uint32_t i = 0; i < p_write_buffer_record->n_bufs; i++)
+ {
+ pm_buffer_release(&m_write_buffer, p_write_buffer_record->buffer_block_id + i);
+ }
+
+ write_buffer_record_invalidate(p_write_buffer_record);
+}
+
+
+/**@brief Function for claiming and activating a write buffer record.
+ *
+ * @param[out] pp_write_buffer_record The claimed record.
+ * @param[in] peer_id The peer ID this record should have.
+ * @param[in] data_id The data ID this record should have.
+ */
+static void write_buffer_record_acquire(pdb_buffer_record_t ** pp_write_buffer_record,
+ pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id)
+{
+ if (pp_write_buffer_record == NULL)
+ {
+ return;
+ }
+ *pp_write_buffer_record = write_buffer_record_find_unused();
+ if (*pp_write_buffer_record == NULL)
+ {
+ // This also means the buffer is full.
+ return;
+ }
+ (*pp_write_buffer_record)->peer_id = peer_id;
+ (*pp_write_buffer_record)->data_id = data_id;
+}
+
+
+/**@brief Function for dispatching outbound events to all registered event handlers.
+ *
+ * @param[in] p_event The event to dispatch.
+ */
+static void pdb_evt_send(pm_evt_t * p_event)
+{
+ for (uint32_t i = 0; i < PDB_EVENT_HANDLERS_CNT; i++)
+ {
+ m_evt_handlers[i](p_event);
+ }
+}
+
+
+/**@brief Function for resetting the internal state of the Peer Database module.
+ *
+ * @param[out] p_event The event to dispatch.
+ */
+static void internal_state_reset()
+{
+ for (uint32_t i = 0; i < PM_FLASH_BUFFERS; i++)
+ {
+ write_buffer_record_invalidate(&m_write_buffer_records[i]);
+ }
+}
+
+
+static void peer_data_point_to_buffer(pm_peer_data_t * p_peer_data, pm_peer_data_id_t data_id, uint8_t * p_buffer_memory, uint16_t n_bufs)
+{
+ uint16_t n_bytes = n_bufs * PDB_WRITE_BUF_SIZE;
+ p_peer_data->data_id = data_id;
+
+ p_peer_data->p_all_data = (pm_peer_data_bonding_t *)p_buffer_memory;
+ p_peer_data->length_words = BYTES_TO_WORDS(n_bytes);
+}
+
+
+static void peer_data_const_point_to_buffer(pm_peer_data_const_t * p_peer_data, pm_peer_data_id_t data_id, uint8_t * p_buffer_memory, uint32_t n_bufs)
+{
+ peer_data_point_to_buffer((pm_peer_data_t*)p_peer_data, data_id, p_buffer_memory, n_bufs);
+}
+
+
+static void write_buf_length_words_set(pm_peer_data_const_t * p_peer_data)
+{
+ switch (p_peer_data->data_id)
+ {
+ case PM_PEER_DATA_ID_BONDING:
+ p_peer_data->length_words = PM_BONDING_DATA_N_WORDS();
+ break;
+ case PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING:
+ p_peer_data->length_words = PM_SC_STATE_N_WORDS();
+ break;
+ case PM_PEER_DATA_ID_PEER_RANK:
+ p_peer_data->length_words = PM_USAGE_INDEX_N_WORDS();
+ break;
+ case PM_PEER_DATA_ID_GATT_LOCAL:
+ p_peer_data->length_words = PM_LOCAL_DB_N_WORDS(p_peer_data->p_local_gatt_db->len);
+ break;
+ default:
+ // No action needed.
+ break;
+ }
+}
+
+
+/**@brief Function for writing data into persistent storage. Writing happens asynchronously.
+ *
+ * @note This will unlock the data after it has been written.
+ *
+ * @param[in] p_write_buffer_record The write buffer record to write into persistent storage.
+ *
+ * @retval NRF_SUCCESS Data storing was successfully started.
+ * @retval NRF_ERROR_STORAGE_FULL No space available in persistent storage. Please clear some
+ * space, the operation will be reattempted after the next compress
+ * procedure. This error will not happen if
+ * @ref pdb_write_buf_store_prepare is called beforehand.
+ * @retval NRF_ERROR_INVALID_PARAM Data ID was invalid.
+ * @retval NRF_ERROR_INVALID_STATE Module is not initialized.
+ * @retval NRF_ERROR_INTERNAL Unexpected internal error.
+ */
+ret_code_t write_buf_store(pdb_buffer_record_t * p_write_buffer_record)
+{
+ ret_code_t err_code = NRF_SUCCESS;
+ pm_peer_data_const_t peer_data = {.data_id = p_write_buffer_record->data_id};
+ uint8_t * p_buffer_memory;
+
+ p_buffer_memory = pm_buffer_ptr_get(&m_write_buffer, p_write_buffer_record->buffer_block_id);
+ if (p_buffer_memory == NULL)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ peer_data_const_point_to_buffer(&peer_data,
+ p_write_buffer_record->data_id,
+ p_buffer_memory,
+ p_write_buffer_record->n_bufs);
+ write_buf_length_words_set(&peer_data);
+
+ err_code = pds_peer_data_store(p_write_buffer_record->peer_id,
+ &peer_data,
+ p_write_buffer_record->prepare_token,
+ &p_write_buffer_record->store_token);
+
+
+ switch (err_code)
+ {
+ case NRF_SUCCESS:
+ p_write_buffer_record->store_busy = false;
+ p_write_buffer_record->store_flash_full = false;
+ break;
+
+ case NRF_ERROR_BUSY:
+ p_write_buffer_record->store_busy = true;
+ p_write_buffer_record->store_flash_full = false;
+ m_pending_store = true;
+
+ err_code = NRF_SUCCESS;
+ break;
+
+ case NRF_ERROR_STORAGE_FULL:
+ p_write_buffer_record->store_busy = false;
+ p_write_buffer_record->store_flash_full = true;
+ m_pending_store = true;
+ break;
+
+ case NRF_ERROR_INVALID_PARAM:
+ // No action.
+ break;
+
+ default:
+ err_code = NRF_ERROR_INTERNAL;
+ break;
+ }
+
+ return err_code;
+}
+
+
+/**@brief This calls @ref write_buf_store and sends events based on the return value.
+ *
+ * See @ref write_buf_store for more info.
+ *
+ * @return Whether or not the store operation succeeded.
+ */
+static bool write_buf_store_in_event(pdb_buffer_record_t * p_write_buffer_record)
+{
+ ret_code_t err_code;
+ pm_evt_t event;
+
+ err_code = write_buf_store(p_write_buffer_record);
+ if (err_code != NRF_SUCCESS)
+ {
+ event.conn_handle = BLE_CONN_HANDLE_INVALID;
+ event.peer_id = p_write_buffer_record->peer_id;
+
+ if (err_code == NRF_ERROR_STORAGE_FULL)
+ {
+ event.evt_id = PM_EVT_STORAGE_FULL;
+ }
+ else
+ {
+ event.evt_id = PM_EVT_ERROR_UNEXPECTED;
+ event.params.error_unexpected.error = err_code;
+ }
+
+ pdb_evt_send(&event);
+
+ return false;
+ }
+
+ return true;
+}
+
+
+/**@brief This reattempts store operations on write buffers, that previously failed because of @ref
+ * NRF_ERROR_BUSY or @ref NRF_ERROR_STORAGE_FULL errors.
+ *
+ * param[in] retry_flash_full Whether to retry operations that failed because of an
+ * @ref NRF_ERROR_STORAGE_FULL error.
+ */
+static void reattempt_previous_operations(bool retry_flash_full)
+{
+ bool found_pending_operation = false;
+
+ if (!m_pending_store)
+ {
+ return;
+ }
+
+ for (uint32_t i = 0; i < PM_FLASH_BUFFERS; i++)
+ {
+ if ((m_write_buffer_records[i].store_busy)
+ || (m_write_buffer_records[i].store_flash_full && retry_flash_full))
+ {
+ found_pending_operation = true;
+
+ bool success = write_buf_store_in_event(&m_write_buffer_records[i]);
+
+ if (!success)
+ {
+ return;
+ }
+ }
+ }
+
+ if (!found_pending_operation)
+ {
+ // All records have been searched and none were pending.
+ // Clear flag so records aren't searched.
+ m_pending_store = false;
+ }
+}
+
+
+/**@brief Function for handling events from the Peer Data Storage module.
+ * This function is extern in Peer Data Storage.
+ *
+ * @param[in] p_event The event to handle.
+ */
+void pdb_pds_evt_handler(pm_evt_t * p_event)
+{
+ pdb_buffer_record_t * p_write_buffer_record;
+ bool evt_send = true;
+ bool retry_flash_full = false;
+
+ p_write_buffer_record = write_buffer_record_find_stored(p_event->params.peer_data_update_succeeded.token);
+
+ switch (p_event->evt_id)
+ {
+ case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
+ if ( (p_event->params.peer_data_update_succeeded.action == PM_PEER_DATA_OP_UPDATE)
+ && (p_write_buffer_record != NULL))
+ {
+ // The write came from PDB.
+ write_buffer_record_release(p_write_buffer_record);
+ }
+ break;
+
+ case PM_EVT_PEER_DATA_UPDATE_FAILED:
+ if ( (p_event->params.peer_data_update_succeeded.action == PM_PEER_DATA_OP_UPDATE)
+ && (p_write_buffer_record != NULL))
+ {
+ // The write came from PDB, retry.
+ p_write_buffer_record->store_token = PM_STORE_TOKEN_INVALID;
+ p_write_buffer_record->store_busy = true;
+ m_pending_store = true;
+ evt_send = false;
+ }
+ break;
+
+ case PM_EVT_FLASH_GARBAGE_COLLECTED:
+ retry_flash_full = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (evt_send)
+ {
+ // Forward the event to all registered Peer Database event handlers.
+ pdb_evt_send(p_event);
+ }
+
+ reattempt_previous_operations(retry_flash_full);
+}
+
+
+ret_code_t pdb_init()
+{
+ ret_code_t ret;
+
+ NRF_PM_DEBUG_CHECK(!m_module_initialized);
+
+ internal_state_reset();
+
+ PM_BUFFER_INIT(&m_write_buffer, PM_FLASH_BUFFERS, PDB_WRITE_BUF_SIZE, ret);
+
+ if (ret != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ m_module_initialized = true;
+
+ return NRF_SUCCESS;
+}
+
+
+pm_peer_id_t pdb_peer_allocate(void)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return pds_peer_id_allocate();
+}
+
+
+ret_code_t pdb_peer_free(pm_peer_id_t peer_id)
+{
+ ret_code_t err_code_in = NRF_SUCCESS;
+ ret_code_t err_code_out = NRF_SUCCESS;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ uint32_t index = 0;
+ pdb_buffer_record_t * p_record = write_buffer_record_find_next(peer_id, &index);
+
+ while (p_record != NULL)
+ {
+ err_code_in = pdb_write_buf_release(peer_id, p_record->data_id);
+
+ if ( (err_code_in != NRF_SUCCESS)
+ && (err_code_in != NRF_ERROR_NOT_FOUND))
+ {
+ err_code_out = NRF_ERROR_INTERNAL;
+ }
+
+ index++;
+ p_record = write_buffer_record_find_next(peer_id, &index);
+ }
+
+ if (err_code_out == NRF_SUCCESS)
+ {
+ err_code_in = pds_peer_id_free(peer_id);
+
+ if (err_code_in == NRF_SUCCESS)
+ {
+ // No action needed.
+ }
+ else if (err_code_in == NRF_ERROR_INVALID_PARAM)
+ {
+ err_code_out = NRF_ERROR_INVALID_PARAM;
+ }
+ else
+ {
+ err_code_out = NRF_ERROR_INTERNAL;
+ }
+ }
+
+ return err_code_out;
+}
+
+
+ret_code_t pdb_peer_data_ptr_get(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ pm_peer_data_flash_t * const p_peer_data)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_peer_data != NULL);
+
+ // Pass NULL to only retrieve a pointer.
+ return pds_peer_data_read(peer_id, data_id, (pm_peer_data_t*)p_peer_data, NULL);
+}
+
+
+
+ret_code_t pdb_write_buf_get(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ uint32_t n_bufs,
+ pm_peer_data_t * p_peer_data)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ VERIFY_PARAM_NOT_NULL(p_peer_data);
+ VERIFY_DATA_ID_WRITE_BUF(data_id);
+
+ if ( (n_bufs == 0)
+ || (n_bufs > PM_FLASH_BUFFERS)
+ || !pds_peer_id_is_allocated(peer_id))
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ pdb_buffer_record_t * p_write_buffer_record;
+ uint8_t * p_buffer_memory;
+ bool new_record = false;
+
+ p_write_buffer_record = write_buffer_record_find(peer_id, data_id);
+
+ if (p_write_buffer_record == NULL)
+ {
+ // No buffer exists.
+ write_buffer_record_acquire(&p_write_buffer_record, peer_id, data_id);
+ if (p_write_buffer_record == NULL)
+ {
+ return NRF_ERROR_BUSY;
+ }
+ }
+ else if (p_write_buffer_record->n_bufs != n_bufs)
+ {
+ // Buffer exists with a different n_bufs from what was requested.
+ return NRF_ERROR_FORBIDDEN;
+ }
+
+ if (p_write_buffer_record->buffer_block_id == PM_BUFFER_INVALID_ID)
+ {
+ p_write_buffer_record->buffer_block_id = pm_buffer_block_acquire(&m_write_buffer, n_bufs);
+
+ if (p_write_buffer_record->buffer_block_id == PM_BUFFER_INVALID_ID)
+ {
+ write_buffer_record_invalidate(p_write_buffer_record);
+ return NRF_ERROR_BUSY;
+ }
+
+ new_record = true;
+ }
+
+ p_write_buffer_record->n_bufs = n_bufs;
+
+ p_buffer_memory = pm_buffer_ptr_get(&m_write_buffer, p_write_buffer_record->buffer_block_id);
+
+ if (p_buffer_memory == NULL)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ peer_data_point_to_buffer(p_peer_data, data_id, p_buffer_memory, n_bufs);
+ if (new_record && (data_id == PM_PEER_DATA_ID_GATT_LOCAL))
+ {
+ p_peer_data->p_local_gatt_db->len = PM_LOCAL_DB_LEN(p_peer_data->length_words);
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t pdb_write_buf_release(pm_peer_id_t peer_id, pm_peer_data_id_t data_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ ret_code_t err_code = NRF_SUCCESS;
+ pdb_buffer_record_t * p_write_buffer_record;
+ p_write_buffer_record = write_buffer_record_find(peer_id, data_id);
+
+ if (p_write_buffer_record == NULL)
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ if (p_write_buffer_record->prepare_token != PDS_PREPARE_TOKEN_INVALID)
+ {
+ err_code = pds_space_reserve_cancel(p_write_buffer_record->prepare_token);
+ if (err_code != NRF_SUCCESS)
+ {
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ }
+
+ write_buffer_record_release(p_write_buffer_record);
+
+ return err_code;
+}
+
+
+ret_code_t pdb_write_buf_store_prepare(pm_peer_id_t peer_id, pm_peer_data_id_t data_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ VERIFY_DATA_ID_WRITE_BUF(data_id);
+
+ ret_code_t err_code = NRF_SUCCESS;
+ pdb_buffer_record_t * p_write_buffer_record;
+ p_write_buffer_record = write_buffer_record_find(peer_id, data_id);
+
+ if (p_write_buffer_record == NULL)
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ if (p_write_buffer_record->prepare_token == PDS_PREPARE_TOKEN_INVALID)
+ {
+ uint8_t * p_buffer_memory = pm_buffer_ptr_get(&m_write_buffer,
+ p_write_buffer_record->buffer_block_id);
+ pm_peer_data_const_t peer_data = {.data_id = data_id};
+
+ if (p_buffer_memory == NULL)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ peer_data_const_point_to_buffer(&peer_data, data_id, p_buffer_memory, p_write_buffer_record->n_bufs);
+
+ write_buf_length_words_set(&peer_data);
+
+ err_code = pds_space_reserve(&peer_data, &p_write_buffer_record->prepare_token);
+ if (err_code == NRF_ERROR_INVALID_LENGTH)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+ }
+
+ return err_code;
+}
+
+
+ret_code_t pdb_write_buf_store(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ pm_peer_id_t new_peer_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ VERIFY_DATA_ID_WRITE_BUF(data_id);
+
+ pdb_buffer_record_t * p_write_buffer_record = write_buffer_record_find(peer_id, data_id);
+
+ if (p_write_buffer_record == NULL)
+ {
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ p_write_buffer_record->peer_id = new_peer_id;
+ p_write_buffer_record->data_id = data_id;
+ return write_buf_store(p_write_buffer_record);
+}
+
+
+ret_code_t pdb_clear(pm_peer_id_t peer_id, pm_peer_data_id_t data_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return pds_peer_data_delete(peer_id, data_id);
+}
+
+
+uint32_t pdb_n_peers(void)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return pds_peer_count_get();
+}
+
+
+pm_peer_id_t pdb_next_peer_id_get(pm_peer_id_t prev_peer_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return pds_next_peer_id_get(prev_peer_id);
+}
+
+
+pm_peer_id_t pdb_next_deleted_peer_id_get(pm_peer_id_t prev_peer_id)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return pds_next_deleted_peer_id_get(prev_peer_id);
+}
+
+
+ret_code_t pdb_peer_data_load(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ pm_peer_data_t * const p_peer_data)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_peer_data != NULL);
+
+ // Provide the buffer length in bytes.
+ uint32_t const data_len_bytes = (p_peer_data->length_words * sizeof(uint32_t));
+ return pds_peer_data_read(peer_id, data_id, p_peer_data, &data_len_bytes);
+}
+
+
+ret_code_t pdb_raw_store(pm_peer_id_t peer_id,
+ pm_peer_data_const_t * p_peer_data,
+ pm_store_token_t * p_store_token)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ return pds_peer_data_store(peer_id, p_peer_data, PDS_PREPARE_TOKEN_INVALID, p_store_token);
+}
+#endif // NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_database.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_database.h
new file mode 100644
index 0000000..819a9eb
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_database.h
@@ -0,0 +1,309 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef PEER_DATABASE_H__
+#define PEER_DATABASE_H__
+
+#include <stdint.h>
+#include "peer_manager_types.h"
+#include "peer_manager_internal.h"
+#include "sdk_errors.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @cond NO_DOXYGEN
+ * @defgroup peer_database Peer Database
+ * @ingroup peer_manager
+ * @{
+ * @brief An internal module of @ref peer_manager. A module for simple management of reading and
+ * writing of peer data into persistent storage.
+ *
+ */
+
+#define PDB_WRITE_BUF_SIZE (sizeof(pm_peer_data_bonding_t)) //!< The size (in bytes) of each block in the internal buffer accessible via @ref pdb_write_buf_get.
+
+
+/**@brief Function for initializing the module.
+ *
+ * @retval NRF_SUCCESS If initialization was successful.
+ * @retval NRF_ERROR_INTERNAL An unexpected error happened.
+ */
+ret_code_t pdb_init(void);
+
+
+/**@brief Function for allocating persistent bond storage for a peer.
+ *
+ * @return The ID of the newly allocated storage.
+ * @retval PM_PEER_ID_INVALID If no peer ID is available.
+ */
+pm_peer_id_t pdb_peer_allocate(void);
+
+
+/**@brief Function for freeing a peer's persistent bond storage.
+ *
+ * @note This function will call @ref pdb_write_buf_release on the data for this peer.
+ *
+ * @param[in] peer_id ID to be freed.
+ *
+ * @retval NRF_SUCCESS Peer ID was released and clear operation was initiated successfully.
+ * @retval NRF_ERROR_INVALID_PARAM Peer ID was invalid.
+ */
+ret_code_t pdb_peer_free(pm_peer_id_t peer_id);
+
+
+/**@brief Function for retrieving a pointer to peer data in flash (read-only).
+ *
+ * @note Dereferencing this pointer is not the safest thing to do if interrupts are enabled,
+ * because Flash Data Storage garbage collection might move the data around. Either disable
+ * interrupts while using the data, or use @ref pdb_peer_data_load.
+ *
+ * @param[in] peer_id The peer the data belongs to.
+ * @param[in] data_id The data to read.
+ * @param[out] p_peer_data The peer data, read-only.
+ *
+ * @retval NRF_SUCCESS If the pointer to the data was retrieved successfully.
+ * @retval NRF_ERROR_INVALID_PARAM If either @p peer_id or @p data_id are invalid.
+ * @retval NRF_ERROR_NOT_FOUND If data was not found in flash.
+ */
+ret_code_t pdb_peer_data_ptr_get(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ pm_peer_data_flash_t * const p_peer_data);
+
+
+/**@brief Function for retrieving pointers to a write buffer for peer data.
+ *
+ * @details This function will provide pointers to a buffer of the data. The data buffer will not be
+ * written to persistent storage until @ref pdb_write_buf_store is called. The buffer is
+ * released by calling either @ref pdb_write_buf_release, @ref pdb_write_buf_store, or
+ * @ref pdb_peer_free.
+ *
+ * When the data_id refers to a variable length data type, the available size is written
+ * to the data, both the top-level, and any internal length fields.
+ *
+ * @note Calling this function on a peer_id/data_id pair that already has a buffer created will
+ * give the same buffer, not create a new one. If n_bufs was increased since last time, the
+ * buffer might be relocated to be able to provide additional room. In this case, the data
+ * will be copied. If n_bufs was increased since last time, this function might return @ref
+ * NRF_ERROR_BUSY. In that case, the buffer is automatically released.
+ *
+ * @param[in] peer_id ID of peer to get a write buffer for.
+ * @param[in] data_id Which piece of data to get.
+ * @param[in] n_bufs The number of contiguous buffers needed.
+ * @param[out] p_peer_data Pointers to mutable peer data.
+ *
+ * @retval NRF_SUCCESS Data retrieved successfully.
+ * @retval NRF_ERROR_INVALID_PARAM Data ID or Peer ID was invalid or unallocated, or n_bufs was 0
+ * or more than the total available buffers.
+ * @retval NRF_ERROR_FORBIDDEN n_bufs was higher or lower than the existing buffer. If needed,
+ * release the existing buffer with @ref pdb_write_buf_release, and
+ * call this function again.
+ * @retval NRF_ERROR_NULL p_peer_data was NULL.
+ * @retval NRF_ERROR_BUSY Not enough buffer(s) available.
+ * @retval NRF_ERROR_INTERNAL Unexpected internal error.
+ */
+ret_code_t pdb_write_buf_get(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ uint32_t n_bufs,
+ pm_peer_data_t * p_peer_data);
+
+
+/**@brief Function for freeing a write buffer allocated with @ref pdb_write_buf_get.
+ *
+ * @note This function will not write peer data to persistent memory. Data in released buffer will
+ * be lost.
+ *
+ * @note This function will undo any previous call to @ref pdb_write_buf_store_prepare for this
+ * piece of data.
+ *
+ * @param[in] peer_id ID of peer to release buffer for.
+ * @param[in] data_id Which piece of data to release buffer for.
+ *
+ * @retval NRF_SUCCESS Successfully released buffer.
+ * @retval NRF_ERROR_NOT_FOUND No buffer was allocated for this peer ID/data ID pair.
+ * @retval NRF_ERROR_INTERNAL Unexpected internal error.
+ */
+ret_code_t pdb_write_buf_release(pm_peer_id_t peer_id, pm_peer_data_id_t data_id);
+
+
+/**@brief Function for reserving space in persistent storage for data in a buffer.
+ *
+ * @note This function only works for data which has a write buffer allocated. If the write buffer
+ * is released, this prepare is undone.
+ *
+ * @note If space has already been reserved for this data, nothing is done.
+ *
+ * @param[in] peer_id The peer whose data to reserve space for.
+ * @param[in] data_id The type of data to reserve space for.
+ *
+ * @retval NRF_SUCCESS Successfully reserved space in persistent storage.
+ * @retval NRF_ERROR_STORAGE_FULL Not enough room in persistent storage.
+ * @retval NRF_ERROR_NOT_FOUND No buffer has been allocated for this peer ID/data ID pair.
+ * @retval NRF_ERROR_INVALID_PARAM Data ID or Peer ID was invalid or unallocated.
+ */
+ret_code_t pdb_write_buf_store_prepare(pm_peer_id_t peer_id, pm_peer_data_id_t data_id);
+
+
+/**@brief Function for writing data into persistent storage. Writing happens asynchronously.
+ *
+ * @note This will unlock the data after it has been written.
+ *
+ * @param[in] peer_id The ID used to address the write buffer.
+ * @param[in] data_id Which piece of data to store.
+ * @param[in] new_peer_id The ID to put in flash. This will usually be the same as peer_id.
+ *
+ * @retval NRF_SUCCESS Data storing was successfully started.
+ * @retval NRF_ERROR_STORAGE_FULL No space available in persistent storage. Please clear some
+ * space, the operation will be reattempted after the next compress
+ * procedure. This error will not happen if
+ * @ref pdb_write_buf_store_prepare is called beforehand.
+ * @retval NRF_ERROR_INVALID_PARAM Data ID was invalid.
+ * @retval NRF_ERROR_NOT_FOUND No buffer has been allocated for this peer ID/data ID pair.
+ * @retval NRF_ERROR_INTERNAL Unexpected internal error.
+ */
+ret_code_t pdb_write_buf_store(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ pm_peer_id_t new_peer_id);
+
+
+/**@brief Function for clearing data from persistent storage.
+ *
+ * @param[in] peer_id ID of peer to clear data for.
+ * @param[in] data_id Which piece of data to clear.
+ *
+ * @retval NRF_SUCCESS The clear was initiated successfully.
+ * @retval NRF_ERROR_INVALID_PARAM Data ID or peer ID was invalid.
+ * @retval NRF_ERROR_NOT_FOUND Nothing to clear for this peer ID/data ID combination.
+ * @retval NRF_ERROR_BUSY Underlying modules are busy and can't take any more requests at
+ * this moment.
+ * @retval NRF_ERROR_INTERNAL Internal error.
+ */
+ret_code_t pdb_clear(pm_peer_id_t peer_id, pm_peer_data_id_t data_id);
+
+
+/**@brief Function for querying the number of valid peer IDs available. I.E the number of peers
+ * in persistent storage.
+ *
+ * @return The number of valid peer IDs.
+ */
+uint32_t pdb_n_peers(void);
+
+
+/**@brief Function for getting the next peer ID in the sequence of all used peer IDs. Can be
+ * used to loop through all used peer IDs.
+ *
+ * @note @ref PM_PEER_ID_INVALID is considered to be before the first and after the last ordinary
+ * peer ID.
+ *
+ * @param[in] prev_peer_id The previous peer ID.
+ *
+ * @return The next peer ID.
+ * @return The first ordinary peer ID if prev_peer_id was @ref PM_PEER_ID_INVALID.
+ * @retval PM_PEER_ID_INVALID if prev_peer_id was the last ordinary peer ID.
+ */
+pm_peer_id_t pdb_next_peer_id_get(pm_peer_id_t prev_peer_id);
+
+
+/**@brief Function for getting the next peer ID in the sequence of all peer IDs pending deletion.
+ * Can be used to loop through all used peer IDs.
+ *
+ * @note @ref PM_PEER_ID_INVALID is considered to be before the first and after the last ordinary
+ * peer ID.
+ *
+ * @param[in] prev_peer_id The previous peer ID.
+ *
+ * @return The next peer ID pending deletion.
+ * @return The first ordinary peer ID if prev_peer_id was @ref PM_PEER_ID_INVALID.
+ * @retval PM_PEER_ID_INVALID if prev_peer_id was the last ordinary peer ID.
+ */
+pm_peer_id_t pdb_next_deleted_peer_id_get(pm_peer_id_t prev_peer_id);
+
+
+/**@brief Function for copy peer data from flash into a provided buffer.
+ *
+ * @param[in] peer_id The peer the data belongs to.
+ * @param[in] data_id The data to read.
+ * @param[inout] p_peer_data The buffer where to copy data into. The field @c length_words in this
+ * parameter must represent the buffer length in words.
+ *
+ * @note Actually, it represents the buffer length in bytes upon entering the function,
+ * and upon exit it represents the length of the data in words.. not good. Fix this.
+ *
+ * @retval NRF_SUCCESS If the operation was successful.
+ * @retval NRF_ERROR_INVALID_PARAM If @p peer_id or @p data_id are invalid.
+ * @retval NRF_ERROR_NOT_FOUND If the data was not found in flash.
+ * @retval NRF_ERROR_NO_MEM If the provided buffer is too small.
+ */
+ret_code_t pdb_peer_data_load(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ pm_peer_data_t * const p_peer_data);
+
+
+/**@brief Function for writing data directly to persistent storage from external memory.
+ *
+ * @param[in] peer_id ID of peer to write data for.
+ * @param[in] p_peer_data Data to store.
+ * @param[out] p_store_token A token identifying this particular store operation. The token can be
+ * used to identify events pertaining to this operation.
+ *
+ * @retval NRF_SUCCESS Data successfully written.
+ * @retval NRF_ERROR_INVALID_PARAM Data ID or Peer ID was invalid or unallocated.
+ * @retval NRF_ERROR_NULL p_peer_data contained a NULL pointer.
+ * @retval NRF_ERROR_STORAGE_FULL No space available in persistent storage.
+ * @retval NRF_ERROR_INVALID_LENGTH Data length above the maximum allowed.
+ * @retval NRF_ERROR_BUSY Unable to perform operation at this time.
+ */
+ret_code_t pdb_raw_store(pm_peer_id_t peer_id,
+ pm_peer_data_const_t * p_peer_data,
+ pm_store_token_t * p_store_token);
+
+/** @}
+ * @endcond
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PEER_DATABASE_H__ */
+
+
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_id.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_id.c
new file mode 100644
index 0000000..a5f5475
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_id.c
@@ -0,0 +1,202 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "peer_id.h"
+
+#include <stdint.h>
+#include <string.h>
+#include "sdk_errors.h"
+#include "peer_manager_types.h"
+#include "pm_mutex.h"
+
+
+typedef struct
+{
+ uint8_t used_peer_ids[MUTEX_STORAGE_SIZE(PM_PEER_ID_N_AVAILABLE_IDS)]; /**< Bitmap designating which peer IDs are in use. */
+ uint8_t deleted_peer_ids[MUTEX_STORAGE_SIZE(PM_PEER_ID_N_AVAILABLE_IDS)]; /**< Bitmap designating which peer IDs are marked for deletion. */
+} pi_t;
+
+
+static pi_t m_pi = {{0}, {0}};
+
+
+static void internal_state_reset(pi_t * p_pi)
+{
+ memset(p_pi, 0, sizeof(pi_t));
+}
+
+
+void peer_id_init(void)
+{
+ internal_state_reset(&m_pi);
+ pm_mutex_init(m_pi.used_peer_ids, PM_PEER_ID_N_AVAILABLE_IDS);
+ pm_mutex_init(m_pi.deleted_peer_ids, PM_PEER_ID_N_AVAILABLE_IDS);
+}
+
+
+static pm_peer_id_t claim(pm_peer_id_t peer_id, uint8_t * mutex_group)
+{
+ pm_peer_id_t allocated_peer_id = PM_PEER_ID_INVALID;
+ if (peer_id == PM_PEER_ID_INVALID)
+ {
+ allocated_peer_id = pm_mutex_lock_first_available(mutex_group, PM_PEER_ID_N_AVAILABLE_IDS);
+ if (allocated_peer_id == PM_PEER_ID_N_AVAILABLE_IDS)
+ {
+ allocated_peer_id = PM_PEER_ID_INVALID;
+ }
+ }
+ else if (peer_id < PM_PEER_ID_N_AVAILABLE_IDS)
+ {
+ bool lock_success = pm_mutex_lock(mutex_group, peer_id);
+ allocated_peer_id = lock_success ? peer_id : PM_PEER_ID_INVALID;
+ }
+ return allocated_peer_id;
+}
+
+
+static void release(pm_peer_id_t peer_id, uint8_t * mutex_group)
+{
+ if (peer_id < PM_PEER_ID_N_AVAILABLE_IDS)
+ {
+ pm_mutex_unlock(mutex_group, peer_id);
+ }
+}
+
+
+pm_peer_id_t peer_id_allocate(pm_peer_id_t peer_id)
+{
+ return claim(peer_id, m_pi.used_peer_ids);
+}
+
+
+bool peer_id_delete(pm_peer_id_t peer_id)
+{
+ pm_peer_id_t deleted_peer_id;
+
+ if (peer_id == PM_PEER_ID_INVALID)
+ {
+ return false;
+ }
+
+ deleted_peer_id = claim(peer_id, m_pi.deleted_peer_ids);
+
+ return (deleted_peer_id == peer_id);
+}
+
+
+void peer_id_free(pm_peer_id_t peer_id)
+{
+ release(peer_id, m_pi.used_peer_ids);
+ release(peer_id, m_pi.deleted_peer_ids);
+}
+
+
+bool peer_id_is_allocated(pm_peer_id_t peer_id)
+{
+ if (peer_id < PM_PEER_ID_N_AVAILABLE_IDS)
+ {
+ return pm_mutex_lock_status_get(m_pi.used_peer_ids, peer_id);
+ }
+ return false;
+}
+
+
+bool peer_id_is_deleted(pm_peer_id_t peer_id)
+{
+ if (peer_id < PM_PEER_ID_N_AVAILABLE_IDS)
+ {
+ return pm_mutex_lock_status_get(m_pi.deleted_peer_ids, peer_id);
+ }
+ return false;
+}
+
+
+pm_peer_id_t next_id_get(pm_peer_id_t prev_peer_id, uint8_t * mutex_group)
+{
+ pm_peer_id_t i = (prev_peer_id == PM_PEER_ID_INVALID) ? 0 : (prev_peer_id + 1);
+ for (; i < PM_PEER_ID_N_AVAILABLE_IDS; i++)
+ {
+ if (pm_mutex_lock_status_get(mutex_group, i))
+ {
+ return i;
+ }
+ }
+
+ return PM_PEER_ID_INVALID;
+}
+
+
+pm_peer_id_t peer_id_get_next_used(pm_peer_id_t peer_id)
+{
+ peer_id = next_id_get(peer_id, m_pi.used_peer_ids);
+
+ while (peer_id != PM_PEER_ID_INVALID)
+ {
+ if (!peer_id_is_deleted(peer_id))
+ {
+ return peer_id;
+ }
+
+ peer_id = next_id_get(peer_id, m_pi.used_peer_ids);
+ }
+
+ return peer_id;
+}
+
+
+pm_peer_id_t peer_id_get_next_deleted(pm_peer_id_t prev_peer_id)
+{
+ return next_id_get(prev_peer_id, m_pi.deleted_peer_ids);
+}
+
+
+uint32_t peer_id_n_ids(void)
+{
+ uint32_t n_ids = 0;
+
+ for (pm_peer_id_t i = 0; i < PM_PEER_ID_N_AVAILABLE_IDS; i++)
+ {
+ n_ids += pm_mutex_lock_status_get(m_pi.used_peer_ids, i);
+ }
+
+ return n_ids;
+}
+#endif // NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_id.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_id.h
new file mode 100644
index 0000000..04c99ff
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_id.h
@@ -0,0 +1,167 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef PEER_ID_H__
+#define PEER_ID_H__
+
+
+#include <stdint.h>
+#include "sdk_errors.h"
+#include "ble_gap.h"
+#include "peer_manager_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @cond NO_DOXYGEN
+ * @defgroup peer_id Peer IDs
+ * @ingroup peer_manager
+ * @{
+ * @brief An internal module of @ref peer_manager. This module keeps track of which peer IDs are in
+ * use and which are free.
+ */
+
+
+/**@brief Function for initializing the module.
+ */
+void peer_id_init(void);
+
+
+/**@brief Function for claiming an unused peer ID.
+ *
+ * @param peer_id The peer ID to allocate. If this is @ref PM_PEER_ID_INVALID, the first available
+ * will be allocated.
+ *
+ * @return The allocated peer ID.
+ * @retval PM_PEER_ID_INVALID If no peer ID could be allocated or module is not initialized.
+ */
+pm_peer_id_t peer_id_allocate(pm_peer_id_t peer_id);
+
+
+/**@brief Function for marking a peer ID for deletion.
+ *
+ * @param peer_id The peer ID to delete.
+ *
+ * @retval true Deletion was successful.
+ * @retval false Peer ID already marked for deletion, peer_id was PM_PEER_ID_INVALID, or module is
+ * not initialized.
+ */
+bool peer_id_delete(pm_peer_id_t peer_id);
+
+
+/**@brief Function for freeing a peer ID and clearing all data associated with it in persistent
+ * storage.
+ *
+ * @param[in] peer_id Peer ID to free.
+ */
+void peer_id_free(pm_peer_id_t peer_id);
+
+
+/**@brief Function for finding out whether a peer ID is marked for deletion.
+ *
+ * @param[in] peer_id The peer ID to inquire about.
+ *
+ * @retval true peer_id is in marked for deletion.
+ * @retval false peer_id is not marked for deletion, or the module is not initialized.
+ */
+bool peer_id_is_deleted(pm_peer_id_t peer_id);
+
+
+/**@brief Function for finding out whether a peer ID is in use.
+ *
+ * @param[in] peer_id The peer ID to inquire about.
+ *
+ * @retval true peer_id is in use.
+ * @retval false peer_id is free, or the module is not initialized.
+ */
+bool peer_id_is_allocated(pm_peer_id_t peer_id);
+
+
+/**@brief Function for getting the next peer ID in the sequence of all used peer IDs. Can be
+ * used to loop through all used peer IDs.
+ *
+ * @note @ref PM_PEER_ID_INVALID is considered to be before the first and after the last ordinary
+ * peer ID.
+ *
+ * @param[in] prev_peer_id The previous peer ID.
+ *
+ * @return The next peer ID.
+ * @return The first used peer ID if prev_peer_id was @ref PM_PEER_ID_INVALID.
+ * @retval PM_PEER_ID_INVALID if prev_peer_id was the last ordinary peer ID or the module is
+ * not initialized.
+ */
+pm_peer_id_t peer_id_get_next_used(pm_peer_id_t prev_peer_id);
+
+
+/**@brief Function for getting the next peer ID in the sequence of all peer IDs marked for deletion.
+ * Can be used to loop through all peer IDs marked for deletion.
+ *
+ * @note @ref PM_PEER_ID_INVALID is considered to be before the first and after the last ordinary
+ * peer ID.
+ *
+ * @param[in] prev_peer_id The previous peer ID.
+ *
+ * @return The next peer ID.
+ * @return The first used peer ID if prev_peer_id was @ref PM_PEER_ID_INVALID.
+ * @retval PM_PEER_ID_INVALID if prev_peer_id was the last ordinary peer ID or the module is
+ * not initialized.
+ */
+pm_peer_id_t peer_id_get_next_deleted(pm_peer_id_t prev_peer_id);
+
+
+/**@brief Function for querying the number of valid peer IDs available. I.E the number of peers
+ * in persistent storage.
+ *
+ * @return The number of valid peer IDs, or 0 if module is not initialized.
+ */
+uint32_t peer_id_n_ids(void);
+
+/** @}
+ * @endcond
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PEER_ID_H__ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager.c
new file mode 100644
index 0000000..7de5793
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager.c
@@ -0,0 +1,983 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "ble_err.h"
+#include "peer_manager.h"
+#include <string.h>
+#include "security_manager.h"
+#include "security_dispatcher.h"
+#include "gatt_cache_manager.h"
+#include "gatts_cache_manager.h"
+#include "peer_database.h"
+#include "peer_data_storage.h"
+#include "id_manager.h"
+#include "ble_conn_state.h"
+#include "peer_manager_internal.h"
+#include "nrf_sdh_ble.h"
+
+#ifndef PM_PEER_RANKS_ENABLED
+ #define PM_PEER_RANKS_ENABLED 1
+#endif
+
+#define MODULE_INITIALIZED (m_module_initialized) /**< Macro indicating whether the module has been initialized properly. */
+
+
+static bool m_module_initialized; /**< Whether or not @ref pm_init has been called successfully. */
+static bool m_peer_rank_initialized; /**< Whether or not @ref rank_init has been called successfully. */
+static bool m_deleting_all; /**< True from when @ref pm_peers_delete is called until all peers have been deleted. */
+static pm_store_token_t m_peer_rank_token; /**< The store token of an ongoing peer rank update via a call to @ref pm_peer_rank_highest. If @ref PM_STORE_TOKEN_INVALID, there is no ongoing update. */
+static uint32_t m_current_highest_peer_rank; /**< The current highest peer rank. Used by @ref pm_peer_rank_highest. */
+static pm_peer_id_t m_highest_ranked_peer; /**< The peer with the highest peer rank. Used by @ref pm_peer_rank_highest. */
+static pm_evt_handler_t m_evt_handlers[PM_MAX_REGISTRANTS];/**< The subscribers to Peer Manager events, as registered through @ref pm_register. */
+static uint8_t m_n_registrants; /**< The number of event handlers registered through @ref pm_register. */
+
+
+/**@brief Function for sending a Peer Manager event to all subscribers.
+ *
+ * @param[in] p_pm_evt The event to send.
+ */
+static void evt_send(pm_evt_t const * p_pm_evt)
+{
+ for (int i = 0; i < m_n_registrants; i++)
+ {
+ m_evt_handlers[i](p_pm_evt);
+ }
+}
+
+
+#if PM_PEER_RANKS_ENABLED == 1
+/**@brief Function for initializing peer rank static variables.
+ */
+static void rank_vars_update(void)
+{
+ ret_code_t err_code = pm_peer_ranks_get(&m_highest_ranked_peer,
+ &m_current_highest_peer_rank,
+ NULL,
+ NULL);
+
+ m_peer_rank_initialized = ((err_code == NRF_SUCCESS) || (err_code == NRF_ERROR_NOT_FOUND));
+}
+#endif
+
+
+/**@brief Event handler for events from the Peer Database module.
+ * This handler is extern in the Peer Database module.
+ *
+ * @param[in] p_pdb_evt The incoming Peer Database event.
+ */
+void pm_pdb_evt_handler(pm_evt_t * p_pdb_evt)
+{
+ bool send_evt = true;
+
+ p_pdb_evt->conn_handle = im_conn_handle_get(p_pdb_evt->peer_id);
+
+ switch (p_pdb_evt->evt_id)
+ {
+#if PM_PEER_RANKS_ENABLED == 1
+ case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
+ if (p_pdb_evt->params.peer_data_update_succeeded.action == PM_PEER_DATA_OP_UPDATE)
+ {
+ if ( (m_peer_rank_token != PM_STORE_TOKEN_INVALID)
+ && (m_peer_rank_token == p_pdb_evt->params.peer_data_update_succeeded.token))
+ {
+ m_peer_rank_token = PM_STORE_TOKEN_INVALID;
+ m_highest_ranked_peer = p_pdb_evt->peer_id;
+
+ p_pdb_evt->params.peer_data_update_succeeded.token = PM_STORE_TOKEN_INVALID;
+ }
+ else if ( m_peer_rank_initialized
+ && (p_pdb_evt->peer_id == m_highest_ranked_peer)
+ && (p_pdb_evt->params.peer_data_update_succeeded.data_id
+ == PM_PEER_DATA_ID_PEER_RANK))
+ {
+ // Update peer rank variable if highest ranked peer has changed its rank.
+ rank_vars_update();
+ }
+ }
+ else if (p_pdb_evt->params.peer_data_update_succeeded.action == PM_PEER_DATA_OP_DELETE)
+ {
+ if ( m_peer_rank_initialized
+ && (p_pdb_evt->peer_id == m_highest_ranked_peer)
+ && (p_pdb_evt->params.peer_data_update_succeeded.data_id == PM_PEER_DATA_ID_PEER_RANK))
+ {
+ // Update peer rank variable if highest ranked peer has deleted its rank.
+ rank_vars_update();
+ }
+ }
+ break;
+
+ case PM_EVT_PEER_DATA_UPDATE_FAILED:
+ if (p_pdb_evt->params.peer_data_update_succeeded.action == PM_PEER_DATA_OP_UPDATE)
+ {
+ if ( (m_peer_rank_token != PM_STORE_TOKEN_INVALID)
+ && (m_peer_rank_token == p_pdb_evt->params.peer_data_update_failed.token))
+ {
+ m_peer_rank_token = PM_STORE_TOKEN_INVALID;
+ m_current_highest_peer_rank -= 1;
+
+ p_pdb_evt->params.peer_data_update_succeeded.token = PM_STORE_TOKEN_INVALID;
+ }
+ }
+ break;
+#endif
+
+ case PM_EVT_PEER_DELETE_SUCCEEDED:
+ // Check that no peers marked for deletion are left.
+ if (m_deleting_all
+ && (pdb_next_peer_id_get(PM_PEER_ID_INVALID) == PM_PEER_ID_INVALID)
+ && (pdb_next_deleted_peer_id_get(PM_PEER_ID_INVALID) == PM_PEER_ID_INVALID))
+ {
+ // pm_peers_delete() has been called and this is the last peer to be deleted.
+ m_deleting_all = false;
+
+ pm_evt_t pm_delete_all_evt;
+ memset(&pm_delete_all_evt, 0, sizeof(pm_evt_t));
+ pm_delete_all_evt.evt_id = PM_EVT_PEERS_DELETE_SUCCEEDED;
+ pm_delete_all_evt.peer_id = PM_PEER_ID_INVALID;
+ pm_delete_all_evt.conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ send_evt = false;
+
+ // Forward the event to all registered Peer Manager event handlers.
+ evt_send(p_pdb_evt); // Ensure that PEER_DELETE_SUCCEEDED arrives before PEERS_DELETE_SUCCEEDED.
+ evt_send(&pm_delete_all_evt);
+ }
+
+#if PM_PEER_RANKS_ENABLED == 1
+ if (m_peer_rank_initialized && (p_pdb_evt->peer_id == m_highest_ranked_peer))
+ {
+ // Update peer rank variable if highest ranked peer has been deleted.
+ rank_vars_update();
+ }
+#endif
+ break;
+
+ case PM_EVT_PEER_DELETE_FAILED:
+ if (m_deleting_all)
+ {
+ // pm_peers_delete() was called and has thus failed.
+
+ m_deleting_all = false;
+
+ pm_evt_t pm_delete_all_evt;
+ memset(&pm_delete_all_evt, 0, sizeof(pm_evt_t));
+ pm_delete_all_evt.evt_id = PM_EVT_PEERS_DELETE_FAILED;
+ pm_delete_all_evt.peer_id = PM_PEER_ID_INVALID;
+ pm_delete_all_evt.conn_handle = BLE_CONN_HANDLE_INVALID;
+ pm_delete_all_evt.params.peers_delete_failed_evt.error
+ = p_pdb_evt->params.peer_delete_failed.error;
+
+ send_evt = false;
+
+ // Forward the event to all registered Peer Manager event handlers.
+ evt_send(p_pdb_evt); // Ensure that PEER_DELETE_FAILED arrives before PEERS_DELETE_FAILED.
+ evt_send(&pm_delete_all_evt);
+ }
+ break;
+
+ default:
+ // Do nothing.
+ break;
+ }
+
+ if (send_evt)
+ {
+ // Forward the event to all registered Peer Manager event handlers.
+ evt_send(p_pdb_evt);
+ }
+}
+
+
+/**@brief Event handler for events from the Security Manager module.
+ * This handler is extern in the Security Manager module.
+ *
+ * @param[in] p_sm_evt The incoming Security Manager event.
+ */
+void pm_sm_evt_handler(pm_evt_t * p_sm_evt)
+{
+ VERIFY_PARAM_NOT_NULL_VOID(p_sm_evt);
+
+ // Forward the event to all registered Peer Manager event handlers.
+ evt_send(p_sm_evt);
+}
+
+
+/**@brief Event handler for events from the GATT Cache Manager module.
+ * This handler is extern in GATT Cache Manager.
+ *
+ * @param[in] p_gcm_evt The incoming GATT Cache Manager event.
+ */
+void pm_gcm_evt_handler(pm_evt_t * p_gcm_evt)
+{
+ // Forward the event to all registered Peer Manager event handlers.
+ evt_send(p_gcm_evt);
+}
+
+
+/**@brief Event handler for events from the ID Manager module.
+ * This function is registered in the ID Manager.
+ *
+ * @param[in] p_im_evt The incoming ID Manager event.
+ */
+void pm_im_evt_handler(pm_evt_t * p_im_evt)
+{
+ // Forward the event to all registered Peer Manager event handlers.
+ evt_send(p_im_evt);
+}
+
+/**
+ * @brief Function for handling BLE events.
+ *
+ * @param[in] p_ble_evt Event received from the BLE stack.
+ * @param[in] p_context Context.
+ */
+static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
+{
+ VERIFY_MODULE_INITIALIZED_VOID();
+
+ im_ble_evt_handler(p_ble_evt);
+ sm_ble_evt_handler(p_ble_evt);
+ gcm_ble_evt_handler(p_ble_evt);
+}
+
+NRF_SDH_BLE_OBSERVER(m_ble_evt_observer, PM_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
+
+
+/**@brief Function for resetting the internal state of this module.
+ */
+static void internal_state_reset()
+{
+ m_highest_ranked_peer = PM_PEER_ID_INVALID;
+ m_peer_rank_token = PM_STORE_TOKEN_INVALID;
+}
+
+
+ret_code_t pm_init(void)
+{
+ ret_code_t err_code;
+
+ err_code = pds_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ err_code = pdb_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ err_code = sm_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ err_code = smd_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ err_code = gcm_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ err_code = gscm_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ err_code = im_init();
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ internal_state_reset();
+
+ m_peer_rank_initialized = false;
+ m_module_initialized = true;
+
+ // If PM_PEER_RANKS_ENABLED is 0, these variables are unused.
+ UNUSED_VARIABLE(m_peer_rank_initialized);
+ UNUSED_VARIABLE(m_peer_rank_token);
+ UNUSED_VARIABLE(m_current_highest_peer_rank);
+ UNUSED_VARIABLE(m_highest_ranked_peer);
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t pm_register(pm_evt_handler_t event_handler)
+{
+ VERIFY_MODULE_INITIALIZED();
+
+ if (m_n_registrants >= PM_MAX_REGISTRANTS)
+ {
+ return NRF_ERROR_NO_MEM;
+ }
+
+ m_evt_handlers[m_n_registrants] = event_handler;
+ m_n_registrants += 1;
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t pm_sec_params_set(ble_gap_sec_params_t * p_sec_params)
+{
+ VERIFY_MODULE_INITIALIZED();
+
+ ret_code_t err_code;
+
+ err_code = sm_sec_params_set(p_sec_params);
+
+ // NRF_ERROR_INVALID_PARAM if parameters are invalid,
+ // NRF_SUCCESS otherwise.
+ return err_code;
+}
+
+
+ret_code_t pm_conn_secure(uint16_t conn_handle, bool force_repairing)
+{
+ VERIFY_MODULE_INITIALIZED();
+
+ ret_code_t err_code;
+
+ err_code = sm_link_secure(conn_handle, force_repairing);
+
+ if (err_code == NRF_ERROR_INVALID_STATE)
+ {
+ err_code = NRF_ERROR_BUSY;
+ }
+
+ return err_code;
+}
+
+
+void pm_conn_sec_config_reply(uint16_t conn_handle, pm_conn_sec_config_t * p_conn_sec_config)
+{
+ if (p_conn_sec_config != NULL)
+ {
+ sm_conn_sec_config_reply(conn_handle, p_conn_sec_config);
+ }
+}
+
+
+ret_code_t pm_conn_sec_params_reply(uint16_t conn_handle,
+ ble_gap_sec_params_t * p_sec_params,
+ void const * p_context)
+{
+ VERIFY_MODULE_INITIALIZED();
+
+ return sm_sec_params_reply(conn_handle, p_sec_params, p_context);
+}
+
+
+void pm_local_database_has_changed(void)
+{
+#if !defined(PM_SERVICE_CHANGED_ENABLED) || (PM_SERVICE_CHANGED_ENABLED == 1)
+ VERIFY_MODULE_INITIALIZED_VOID();
+
+ gcm_local_database_has_changed();
+#endif
+}
+
+
+ret_code_t pm_id_addr_set(ble_gap_addr_t const * p_addr)
+{
+ VERIFY_MODULE_INITIALIZED();
+ return im_id_addr_set(p_addr);
+}
+
+
+ret_code_t pm_id_addr_get(ble_gap_addr_t * p_addr)
+{
+ VERIFY_MODULE_INITIALIZED();
+ VERIFY_PARAM_NOT_NULL(p_addr);
+ return im_id_addr_get(p_addr);
+}
+
+
+ret_code_t pm_privacy_set(pm_privacy_params_t const * p_privacy_params)
+{
+ VERIFY_MODULE_INITIALIZED();
+ VERIFY_PARAM_NOT_NULL(p_privacy_params);
+ return im_privacy_set(p_privacy_params);
+}
+
+
+ret_code_t pm_privacy_get(pm_privacy_params_t * p_privacy_params)
+{
+ VERIFY_MODULE_INITIALIZED();
+ VERIFY_PARAM_NOT_NULL(p_privacy_params);
+ VERIFY_PARAM_NOT_NULL(p_privacy_params->p_device_irk);
+ return im_privacy_get(p_privacy_params);
+}
+
+
+bool pm_address_resolve(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk)
+{
+ VERIFY_MODULE_INITIALIZED();
+
+ if ((p_addr == NULL) || (p_irk == NULL))
+ {
+ return false;
+ }
+ else
+ {
+ return im_address_resolve(p_addr, p_irk);
+ }
+}
+
+
+ret_code_t pm_whitelist_set(pm_peer_id_t const * p_peers,
+ uint32_t peer_cnt)
+{
+ VERIFY_MODULE_INITIALIZED();
+ return im_whitelist_set(p_peers, peer_cnt);
+}
+
+
+ret_code_t pm_whitelist_get(ble_gap_addr_t * p_addrs,
+ uint32_t * p_addr_cnt,
+ ble_gap_irk_t * p_irks,
+ uint32_t * p_irk_cnt)
+{
+ VERIFY_MODULE_INITIALIZED();
+
+ if (((p_addrs == NULL) && (p_irks == NULL)) ||
+ ((p_addrs != NULL) && (p_addr_cnt == NULL)) ||
+ ((p_irks != NULL) && (p_irk_cnt == NULL)))
+ {
+ // The buffers can't be both NULL, and if a buffer is provided its size must be specified.
+ return NRF_ERROR_NULL;
+ }
+
+ return im_whitelist_get(p_addrs, p_addr_cnt, p_irks, p_irk_cnt);
+}
+
+
+ret_code_t pm_device_identities_list_set(pm_peer_id_t const * p_peers,
+ uint32_t peer_cnt)
+{
+ VERIFY_MODULE_INITIALIZED();
+ return im_device_identities_list_set(p_peers, peer_cnt);
+}
+
+
+ret_code_t pm_conn_sec_status_get(uint16_t conn_handle, pm_conn_sec_status_t * p_conn_sec_status)
+{
+ VERIFY_MODULE_INITIALIZED();
+ VERIFY_PARAM_NOT_NULL(p_conn_sec_status);
+
+ ble_conn_state_status_t status = ble_conn_state_status(conn_handle);
+
+ if (status == BLE_CONN_STATUS_INVALID)
+ {
+ return BLE_ERROR_INVALID_CONN_HANDLE;
+ }
+
+ p_conn_sec_status->connected = (status == BLE_CONN_STATUS_CONNECTED);
+ p_conn_sec_status->bonded = (im_peer_id_get_by_conn_handle(conn_handle) != PM_PEER_ID_INVALID);
+ p_conn_sec_status->encrypted = ble_conn_state_encrypted(conn_handle);
+ p_conn_sec_status->mitm_protected = ble_conn_state_mitm_protected(conn_handle);
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t pm_lesc_public_key_set(ble_gap_lesc_p256_pk_t * p_public_key)
+{
+ VERIFY_MODULE_INITIALIZED();
+ return sm_lesc_public_key_set(p_public_key);
+}
+
+
+ret_code_t pm_conn_handle_get(pm_peer_id_t peer_id, uint16_t * p_conn_handle)
+{
+ VERIFY_MODULE_INITIALIZED();
+ VERIFY_PARAM_NOT_NULL(p_conn_handle);
+ *p_conn_handle = im_conn_handle_get(peer_id);
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t pm_peer_id_get(uint16_t conn_handle, pm_peer_id_t * p_peer_id)
+{
+ VERIFY_MODULE_INITIALIZED();
+ VERIFY_PARAM_NOT_NULL(p_peer_id);
+ *p_peer_id = im_peer_id_get_by_conn_handle(conn_handle);
+ return NRF_SUCCESS;
+}
+
+
+uint32_t pm_peer_count(void)
+{
+ if (!MODULE_INITIALIZED)
+ {
+ return 0;
+ }
+ return pdb_n_peers();
+}
+
+
+pm_peer_id_t pm_next_peer_id_get(pm_peer_id_t prev_peer_id)
+{
+ if (!MODULE_INITIALIZED)
+ {
+ return PM_PEER_ID_INVALID;
+ }
+ return pdb_next_peer_id_get(prev_peer_id);
+}
+
+
+ret_code_t pm_peer_data_load(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ void * p_data,
+ uint16_t * p_length)
+{
+ VERIFY_MODULE_INITIALIZED();
+ VERIFY_PARAM_NOT_NULL(p_data);
+ VERIFY_PARAM_NOT_NULL(p_length);
+ if (ALIGN_NUM(4, *p_length) != *p_length)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ pm_peer_data_t peer_data;
+ memset(&peer_data, 0, sizeof(peer_data));
+ peer_data.length_words = BYTES_TO_WORDS(*p_length);
+ peer_data.data_id = data_id;
+ peer_data.p_all_data = p_data;
+
+ ret_code_t err_code = pdb_peer_data_load(peer_id, data_id, &peer_data);
+
+ *p_length = peer_data.length_words * BYTES_PER_WORD;
+
+ return err_code;
+}
+
+
+ret_code_t pm_peer_data_bonding_load(pm_peer_id_t peer_id,
+ pm_peer_data_bonding_t * p_data)
+{
+ uint16_t length = sizeof(pm_peer_data_bonding_t);
+ return pm_peer_data_load(peer_id,
+ PM_PEER_DATA_ID_BONDING,
+ p_data,
+ &length);
+}
+
+
+ret_code_t pm_peer_data_remote_db_load(pm_peer_id_t peer_id,
+ ble_gatt_db_srv_t * p_data,
+ uint16_t * p_length)
+{
+ return pm_peer_data_load(peer_id,
+ PM_PEER_DATA_ID_GATT_REMOTE,
+ p_data,
+ p_length);
+}
+
+
+ret_code_t pm_peer_data_app_data_load(pm_peer_id_t peer_id,
+ void * p_data,
+ uint16_t * p_length)
+{
+ return pm_peer_data_load(peer_id,
+ PM_PEER_DATA_ID_APPLICATION,
+ p_data,
+ p_length);
+}
+
+
+ret_code_t pm_peer_data_store(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ void const * p_data,
+ uint16_t length,
+ pm_store_token_t * p_token)
+{
+ VERIFY_MODULE_INITIALIZED();
+ VERIFY_PARAM_NOT_NULL(p_data);
+ if (ALIGN_NUM(4, length) != length)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ if (data_id == PM_PEER_DATA_ID_BONDING)
+ {
+ pm_peer_id_t dupl_peer_id;
+ dupl_peer_id = im_find_duplicate_bonding_data((pm_peer_data_bonding_t *) p_data, peer_id);
+
+ if (dupl_peer_id != PM_PEER_ID_INVALID)
+ {
+ return NRF_ERROR_FORBIDDEN;
+ }
+ }
+
+ pm_peer_data_flash_t peer_data;
+ memset(&peer_data, 0, sizeof(peer_data));
+ peer_data.length_words = BYTES_TO_WORDS(length);
+ peer_data.data_id = data_id;
+ peer_data.p_all_data = p_data;
+
+ return pdb_raw_store(peer_id, &peer_data, p_token);
+}
+
+
+ret_code_t pm_peer_data_bonding_store(pm_peer_id_t peer_id,
+ pm_peer_data_bonding_t const * p_data,
+ pm_store_token_t * p_token)
+{
+ return pm_peer_data_store(peer_id,
+ PM_PEER_DATA_ID_BONDING,
+ p_data,
+ ALIGN_NUM(4, sizeof(pm_peer_data_bonding_t)),
+ p_token);
+}
+
+
+ret_code_t pm_peer_data_remote_db_store(pm_peer_id_t peer_id,
+ ble_gatt_db_srv_t const * p_data,
+ uint16_t length,
+ pm_store_token_t * p_token)
+{
+ return pm_peer_data_store(peer_id,
+ PM_PEER_DATA_ID_GATT_REMOTE,
+ p_data,
+ length,
+ p_token);
+}
+
+
+ret_code_t pm_peer_data_app_data_store(pm_peer_id_t peer_id,
+ void const * p_data,
+ uint16_t length,
+ pm_store_token_t * p_token)
+{
+ return pm_peer_data_store(peer_id,
+ PM_PEER_DATA_ID_APPLICATION,
+ p_data,
+ length,
+ p_token);
+}
+
+
+ret_code_t pm_peer_data_delete(pm_peer_id_t peer_id, pm_peer_data_id_t data_id)
+{
+ VERIFY_MODULE_INITIALIZED();
+
+ if (data_id == PM_PEER_DATA_ID_BONDING)
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ return pdb_clear(peer_id, data_id);
+}
+
+
+ret_code_t pm_peer_new(pm_peer_id_t * p_new_peer_id,
+ pm_peer_data_bonding_t * p_bonding_data,
+ pm_store_token_t * p_token)
+{
+ ret_code_t err_code;
+ pm_peer_id_t peer_id;
+ pm_peer_data_flash_t peer_data;
+
+ VERIFY_MODULE_INITIALIZED();
+ VERIFY_PARAM_NOT_NULL(p_bonding_data);
+ VERIFY_PARAM_NOT_NULL(p_new_peer_id);
+
+ memset(&peer_data, 0, sizeof(pm_peer_data_flash_t));
+
+ // Search through existing bonds to look for a duplicate.
+ pds_peer_data_iterate_prepare();
+
+ // @note emdi: should maybe use a critical section, since data is not copied while iterating.
+ while (pds_peer_data_iterate(PM_PEER_DATA_ID_BONDING, &peer_id, &peer_data))
+ {
+ if (im_is_duplicate_bonding_data(p_bonding_data, peer_data.p_bonding_data))
+ {
+ *p_new_peer_id = peer_id;
+ return NRF_SUCCESS;
+ }
+ }
+
+ // If no duplicate data is found, prepare to write a new bond to flash.
+
+ *p_new_peer_id = pdb_peer_allocate();
+
+ if (*p_new_peer_id == PM_PEER_ID_INVALID)
+ {
+ return NRF_ERROR_NO_MEM;
+ }
+
+ memset(&peer_data, 0, sizeof(pm_peer_data_flash_t));
+
+ peer_data.data_id = PM_PEER_DATA_ID_BONDING;
+ peer_data.p_bonding_data = p_bonding_data;
+ peer_data.length_words = BYTES_TO_WORDS(sizeof(pm_peer_data_bonding_t));
+
+ err_code = pdb_raw_store(*p_new_peer_id, &peer_data, p_token);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ if (im_peer_free(*p_new_peer_id) != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ // NRF_ERROR_STORAGE_FULL, if no space in flash.
+ // NRF_ERROR_BUSY, if flash filesystem was busy.
+ // NRF_ERROR_INTENRAL, on internal error.
+ return err_code;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t pm_peer_delete(pm_peer_id_t peer_id)
+{
+ VERIFY_MODULE_INITIALIZED();
+
+ return im_peer_free(peer_id);
+}
+
+
+ret_code_t pm_peers_delete(void)
+{
+ VERIFY_MODULE_INITIALIZED();
+
+ m_deleting_all = true;
+
+ pm_peer_id_t current_peer_id = pdb_next_peer_id_get(PM_PEER_ID_INVALID);
+
+ if (current_peer_id == PM_PEER_ID_INVALID)
+ {
+ // No peers bonded.
+ m_deleting_all = false;
+
+ pm_evt_t pm_delete_all_evt;
+ memset(&pm_delete_all_evt, 0, sizeof(pm_evt_t));
+ pm_delete_all_evt.evt_id = PM_EVT_PEERS_DELETE_SUCCEEDED;
+ pm_delete_all_evt.peer_id = PM_PEER_ID_INVALID;
+ pm_delete_all_evt.conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ evt_send(&pm_delete_all_evt);
+ }
+
+ while (current_peer_id != PM_PEER_ID_INVALID)
+ {
+ ret_code_t err_code = pm_peer_delete(current_peer_id);
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ current_peer_id = pdb_next_peer_id_get(current_peer_id);
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t pm_peer_ranks_get(pm_peer_id_t * p_highest_ranked_peer,
+ uint32_t * p_highest_rank,
+ pm_peer_id_t * p_lowest_ranked_peer,
+ uint32_t * p_lowest_rank)
+{
+#if PM_PEER_RANKS_ENABLED == 0
+ return NRF_ERROR_NOT_SUPPORTED;
+#else
+ VERIFY_MODULE_INITIALIZED();
+
+ pm_peer_id_t peer_id = pdb_next_peer_id_get(PM_PEER_ID_INVALID);
+ uint32_t peer_rank = 0;
+ //lint -save -e65 -e64
+ pm_peer_data_t peer_data = {.length_words = BYTES_TO_WORDS(sizeof(peer_rank)),
+ .p_peer_rank = &peer_rank};
+ //lint -restore
+ ret_code_t err_code = pdb_peer_data_load(peer_id, PM_PEER_DATA_ID_PEER_RANK, &peer_data);
+ uint32_t highest_rank = 0;
+ uint32_t lowest_rank = 0xFFFFFFFF;
+ pm_peer_id_t highest_ranked_peer = PM_PEER_ID_INVALID;
+ pm_peer_id_t lowest_ranked_peer = PM_PEER_ID_INVALID;
+
+ if (err_code == NRF_ERROR_INVALID_PARAM)
+ {
+ // No peer IDs exist.
+ return NRF_ERROR_NOT_FOUND;
+ }
+
+ while ((err_code == NRF_SUCCESS) || (err_code == NRF_ERROR_NOT_FOUND))
+ {
+ if (err_code == NRF_ERROR_NOT_FOUND)
+ {
+ peer_rank = 0;
+ }
+ if (peer_rank >= highest_rank)
+ {
+ highest_rank = peer_rank;
+ highest_ranked_peer = peer_id;
+ }
+ if (peer_rank < lowest_rank)
+ {
+ lowest_rank = peer_rank;
+ lowest_ranked_peer = peer_id;
+ }
+ peer_id = pdb_next_peer_id_get(peer_id);
+ err_code = pdb_peer_data_load(peer_id, PM_PEER_DATA_ID_PEER_RANK, &peer_data);
+ }
+ if (peer_id == PM_PEER_ID_INVALID)
+ {
+ err_code = NRF_SUCCESS;
+ if (p_highest_ranked_peer != NULL)
+ {
+ *p_highest_ranked_peer = highest_ranked_peer;
+ }
+ if (p_highest_rank != NULL)
+ {
+ *p_highest_rank = highest_rank;
+ }
+ if (p_lowest_ranked_peer != NULL)
+ {
+ *p_lowest_ranked_peer = lowest_ranked_peer;
+ }
+ if (p_lowest_rank != NULL)
+ {
+ *p_lowest_rank = lowest_rank;
+ }
+ }
+ else
+ {
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ return err_code;
+#endif
+}
+
+
+#if PM_PEER_RANKS_ENABLED == 1
+/**@brief Function for initializing peer rank functionality.
+ */
+static void rank_init(void)
+{
+ rank_vars_update();
+}
+#endif
+
+
+ret_code_t pm_peer_rank_highest(pm_peer_id_t peer_id)
+{
+#if PM_PEER_RANKS_ENABLED == 0
+ return NRF_ERROR_NOT_SUPPORTED;
+#else
+ VERIFY_MODULE_INITIALIZED();
+
+ ret_code_t err_code;
+ //lint -save -e65 -e64
+ pm_peer_data_flash_t peer_data = {.length_words = BYTES_TO_WORDS(sizeof(m_current_highest_peer_rank)),
+ .data_id = PM_PEER_DATA_ID_PEER_RANK,
+ .p_peer_rank = &m_current_highest_peer_rank};
+ //lint -restore
+
+
+ if (!m_peer_rank_initialized)
+ {
+ rank_init();
+ }
+
+ if (!m_peer_rank_initialized || (m_peer_rank_token != PM_STORE_TOKEN_INVALID))
+ {
+ err_code = NRF_ERROR_BUSY;
+ }
+ else
+ {
+ if ((peer_id == m_highest_ranked_peer) && (m_current_highest_peer_rank > 0))
+ {
+ pm_evt_t pm_evt;
+
+ // The reported peer is already regarded as highest (provided it has an index at all)
+ err_code = NRF_SUCCESS;
+
+ memset(&pm_evt, 0, sizeof(pm_evt));
+ pm_evt.evt_id = PM_EVT_PEER_DATA_UPDATE_SUCCEEDED;
+ pm_evt.conn_handle = im_conn_handle_get(peer_id);
+ pm_evt.peer_id = peer_id;
+ pm_evt.params.peer_data_update_succeeded.data_id = PM_PEER_DATA_ID_PEER_RANK;
+ pm_evt.params.peer_data_update_succeeded.action = PM_PEER_DATA_OP_UPDATE;
+ pm_evt.params.peer_data_update_succeeded.token = PM_STORE_TOKEN_INVALID;
+ pm_evt.params.peer_data_update_succeeded.flash_changed = false;
+
+ evt_send(&pm_evt);
+ }
+ else
+ {
+ if (m_current_highest_peer_rank == UINT32_MAX)
+ {
+ err_code = NRF_ERROR_RESOURCES;
+ }
+ else
+ {
+ m_current_highest_peer_rank += 1;
+ err_code = pdb_raw_store(peer_id, &peer_data, &m_peer_rank_token);
+ if (err_code != NRF_SUCCESS)
+ {
+ m_peer_rank_token = PM_STORE_TOKEN_INVALID;
+ m_current_highest_peer_rank -= 1;
+ {
+ if ((err_code != NRF_ERROR_BUSY) && (err_code != NRF_ERROR_STORAGE_FULL))
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ }
+ }
+ }
+ }
+ return err_code;
+#endif
+}
+#endif // NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager.h
new file mode 100644
index 0000000..c320101
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager.h
@@ -0,0 +1,781 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/**
+ * @file peer_manager.h
+ *
+ * @defgroup peer_manager Peer Manager
+ * @ingroup ble_sdk_lib
+ * @{
+ * @brief Module for managing BLE bonding, which includes controlling encryption and pairing
+ * procedures as well as persistently storing different pieces of data that must be stored
+ * when bonded.
+ *
+ * @details The API consists of functions for configuring the pairing and encryption behavior of the
+ * device and functions for manipulating the stored data.
+ *
+ * This module uses Flash Data Storage (FDS) to interface with persistent storage. The
+ * Peer Manager needs exclusive use of certain FDS file IDs and record keys. See
+ * @ref lib_fds_functionality_keys for more information.
+ */
+
+
+#ifndef PEER_MANAGER_H__
+#define PEER_MANAGER_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "sdk_common.h"
+#include "ble.h"
+#include "ble_gap.h"
+#include "peer_manager_types.h"
+#include "peer_database.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+/**@brief Security status of a connection.
+ */
+typedef struct
+{
+ uint8_t connected : 1; /**< @brief The connection is active (not disconnected). */
+ uint8_t encrypted : 1; /**< @brief Communication on this link is encrypted. */
+ uint8_t mitm_protected : 1; /**< @brief The encrypted communication is also protected against man-in-the-middle attacks. */
+ uint8_t bonded : 1; /**< @brief The peer is bonded with us. */
+} pm_conn_sec_status_t;
+
+
+/**@brief Function for initializing the Peer Manager.
+ *
+ * @details You must initialize the Peer Manager before you can call any other Peer Manager
+ * functions.
+ *
+ * @retval NRF_SUCCESS If initialization was successful.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t pm_init(void);
+
+
+/**@brief Function for registering an event handler with the Peer Manager.
+ *
+ * @param[in] event_handler Callback for events from the @ref peer_manager module. @p event_handler
+ * is called for every event that the Peer Manager sends after this
+ * function is called.
+ *
+ * @retval NRF_SUCCESS If initialization was successful.
+ * @retval NRF_ERROR_NULL If @p event_handler was NULL.
+ * @retval NRF_ERROR_NO_MEM If no more registrations can happen.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_register(pm_evt_handler_t event_handler);
+
+
+/**@brief Function for providing pairing and bonding parameters to use for pairing procedures.
+ *
+ * @details Until this function is called, all bonding procedures that are initiated by the
+ * peer are rejected.
+ *
+ * This function can be called multiple times with different parameters, even with NULL as
+ * @p p_sec_params, in which case the Peer Manager starts rejecting all procedures again.
+ *
+ * @param[in] p_sec_params Security parameters to be used for subsequent security procedures.
+ *
+ * @retval NRF_SUCCESS If the parameters were set successfully.
+ * @retval NRF_ERROR_INVALID_PARAM If the combination of parameters is invalid.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t pm_sec_params_set(ble_gap_sec_params_t * p_sec_params);
+
+
+/**@brief Function for establishing encryption on a connection, and optionally establishing a bond.
+ *
+ * @details This function attempts to secure the link that is specified by @p conn_handle. It uses
+ * the parameters that were previously provided in a call to @ref pm_sec_params_set.
+ *
+ * If the connection is a master connection, calling this function starts a security
+ * procedure on the link. If we have keys from a previous bonding procedure with this peer
+ * and the keys meet the security requirements in the currently active security parameters,
+ * the function attempts to establish encryption with the existing keys. If no key exists,
+ * the function attempts to perform pairing and bonding according to the currently active
+ * security parameters.
+ *
+ * If the function completes successfully, a @ref PM_EVT_CONN_SEC_START event is sent.
+ * The procedure might be queued, in which case the @ref PM_EVT_CONN_SEC_START event is
+ * delayed until the procedure is initiated in the SoftDevice.
+ *
+ * If the connection is a slave connection, the function sends a security request to
+ * the peer (master). It is up to the peer then to initiate pairing or encryption.
+ * If the peer ignores the request, a @ref BLE_GAP_EVT_AUTH_STATUS event occurs
+ * with the status @ref BLE_GAP_SEC_STATUS_TIMEOUT. Otherwise, the peer initiates
+ * security, in which case things happen as if the peer had initiated security itself.
+ * See @ref PM_EVT_CONN_SEC_START for information about peer-initiated security.
+ *
+ * @param[in] conn_handle Connection handle of the link as provided by the SoftDevice.
+ * @param[in] force_repairing Whether to force a pairing procedure even if there is an existing
+ * encryption key. This argument is relevant only for
+ * the central role. Recommended value: false.
+ *
+ * @retval NRF_SUCCESS If the operation completed successfully.
+ * @retval NRF_ERROR_BUSY If a security procedure is already in progress on the link,
+ * or if the link is disconnecting or disconnected.
+ * @retval NRF_ERROR_TIMEOUT If there was an SMP time-out, so that no more security
+ * operations can be performed on this link.
+ * @retval BLE_ERROR_INVALID_CONN_HANDLE If the connection handle is invalid.
+ * @retval NRF_ERROR_NOT_FOUND If the security parameters have not been set, either by
+ * @ref pm_sec_params_set or by @ref pm_conn_sec_params_reply.
+ * @retval NRF_ERROR_INVALID_DATA If the peer is bonded, but no LTK was found in the stored
+ * bonding data. Repairing was not requested.
+ * @retval NRF_ERROR_STORAGE_FULL If there is no more space in persistent storage.
+ * @retval NRF_ERROR_NO_MEM If no more authentication procedures can run in parallel
+ * for the given role. See @ref sd_ble_gap_authenticate.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t pm_conn_secure(uint16_t conn_handle, bool force_repairing);
+
+
+/**@brief Function for providing security configuration for a link.
+ *
+ * @details This function is optional, and must be called in reply to a @ref
+ * PM_EVT_CONN_SEC_CONFIG_REQ event, before the Peer Manager event handler returns. If it
+ * is not called in time, a default configuration is used. See @ref pm_conn_sec_config_t
+ * for the value of the default.
+ *
+ * @param[in] conn_handle The connection to set the configuration for.
+ * @param[in] p_conn_sec_config The configuration.
+ */
+void pm_conn_sec_config_reply(uint16_t conn_handle, pm_conn_sec_config_t * p_conn_sec_config);
+
+
+/**@brief Function for providing security parameters for a link.
+ *
+ * @details This function is optional, and must be called in reply to a @ref
+ * PM_EVT_CONN_SEC_PARAMS_REQ event, before the Peer Manager event handler returns. If it
+ * is not called in time, the parameters given in @ref pm_sec_params_set are used. See @ref
+ * pm_conn_sec_config_t for the value of the default.
+ *
+ * @param[in] conn_handle The connection to set the parameters for.
+ * @param[in] p_sec_params The parameters. If NULL, the security procedure is rejected.
+ * @param[in] p_context The context found in the request event that this function replies to.
+ *
+ * @retval NRF_SUCCESS Successful reply.
+ * @retval NRF_ERROR_NULL p_sec_params or p_context was null.
+ * @retval NRF_ERROR_INVALID_PARAM Value of p_sec_params was invalid.
+ * @retval NRF_ERROR_INVALID_STATE This module is not initialized.
+ */
+ret_code_t pm_conn_sec_params_reply(uint16_t conn_handle,
+ ble_gap_sec_params_t * p_sec_params,
+ void const * p_context);
+
+
+/**@brief Function for manually informing that the local database has changed.
+ *
+ * @details This function sends a service changed indication to all bonded and/or connected peers
+ * that subscribe to this indication. If a bonded peer is not connected, the indication is
+ * sent when it reconnects. Every time an indication is sent, a @ref
+ * PM_EVT_SERVICE_CHANGED_IND_SENT event occurs, followed by a @ref
+ * PM_EVT_SERVICE_CHANGED_IND_CONFIRMED when the peer sends its confirmation. Peers that
+ * are not subscribed to the service changed indication when this function is called do not
+ * receive an indication, and no events are sent to the user. Likewise, if the service
+ * changed characteristic is not present in the local database, or if the @ref
+ * PM_SERVICE_CHANGED_ENABLED is set to 0, no indications are sent peers, and no events are
+ * sent to the user.
+ */
+void pm_local_database_has_changed(void);
+
+
+/**@brief Function for getting the security status of a connection.
+ *
+ * @param[in] conn_handle Connection handle of the link as provided by the SoftDevice.
+ * @param[out] p_conn_sec_status Security status of the link.
+ *
+ * @retval NRF_SUCCESS If pairing was initiated successfully.
+ * @retval BLE_ERROR_INVALID_CONN_HANDLE If the connection handle is invalid.
+ * @retval NRF_ERROR_NULL If @p p_conn_sec_status was NULL.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_conn_sec_status_get(uint16_t conn_handle, pm_conn_sec_status_t * p_conn_sec_status);
+
+
+/**@brief Experimental function for specifying the public key to use for LESC operations.
+ *
+ * @details This function can be called multiple times. The specified public key will be used for
+ * all subsequent LESC (LE Secure Connections) operations until the next time this function
+ * is called.
+ *
+ * @note The key must continue to reside in application memory as it is not copied by Peer Manager.
+ *
+ * @param[in] p_public_key The public key to use for all subsequent LESC operations.
+ *
+ * @retval NRF_SUCCESS If pairing was initiated successfully.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_lesc_public_key_set(ble_gap_lesc_p256_pk_t * p_public_key);
+
+
+/**@brief Function for setting or clearing the whitelist.
+ *
+ * When using the S13x SoftDevice v3.x, this function sets or clears the whitelist.
+ * When using the S13x SoftDevice v2.x, this function caches a list of
+ * peers that can be retrieved later by @ref pm_whitelist_get to pass to the @ref lib_ble_advertising.
+ *
+ * To clear the current whitelist, pass either NULL as @p p_peers or zero as @p peer_cnt.
+ *
+ * @param[in] p_peers The peers to add to the whitelist. Pass NULL to clear the current whitelist.
+ * @param[in] peer_cnt The number of peers to add to the whitelist. The number must not be greater than
+ * @ref BLE_GAP_WHITELIST_ADDR_MAX_COUNT. Pass zero to clear the current
+ * whitelist.
+ *
+ * @retval NRF_SUCCESS If the whitelist was successfully set or cleared.
+ * @retval BLE_GAP_ERROR_WHITELIST_IN_USE If a whitelist is already in use and cannot be set.
+ * @retval BLE_ERROR_GAP_INVALID_BLE_ADDR If a peer in @p p_peers has an address that cannot
+ * be used for whitelisting.
+ * @retval NRF_ERROR_NOT_FOUND If any of the peers in @p p_peers cannot be found.
+ * @retval NRF_ERROR_DATA_SIZE If @p peer_cnt is greater than
+ * @ref BLE_GAP_WHITELIST_ADDR_MAX_COUNT.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_whitelist_set(pm_peer_id_t const * p_peers,
+ uint32_t peer_cnt);
+
+
+/**@brief Function for retrieving the previously set whitelist.
+ *
+ * The function retrieves the whitelist of GAP addresses and IRKs that was
+ * previously set by @ref pm_whitelist_set.
+ *
+ * To retrieve only GAP addresses or only IRKs, provide only one of the
+ * buffers. If a buffer is provided, its size must be specified.
+ *
+ * @param[out] p_addrs The buffer where to store GAP addresses. Pass NULL to retrieve
+ * only IRKs (in that case, @p p_irks must not be NULL).
+ * @param[in,out] p_addr_cnt In: The size of the @p p_addrs buffer.
+ * May be NULL if and only if @p p_addrs is NULL.
+ * Out: The number of GAP addresses copied into the buffer.
+ * If @p p_addrs is NULL, this parameter remains unchanged.
+ * @param[out] p_irks The buffer where to store IRKs. Pass NULL to retrieve
+ * only GAP addresses (in that case, @p p_addrs must not NULL).
+ * @param[in,out] p_irk_cnt In: The size of the @p p_irks buffer.
+ * May be NULL if and only if @p p_irks is NULL.
+ * Out: The number of IRKs copied into the buffer.
+ * If @p p_irks is NULL, this paramater remains unchanged.
+ *
+ * @retval NRF_SUCCESS If the whitelist was successfully retrieved.
+ * @retval BLE_ERROR_GAP_INVALID_BLE_ADDR If a peer has an address that cannot be used for
+ * whitelisting (this error can occur only
+ * when using the S13x SoftDevice v2.x).
+ * @retval NRF_ERROR_NULL If a required parameter is NULL.
+ * @retval NRF_ERROR_NO_MEM If the provided buffers are too small.
+ * @retval NRF_ERROR_NOT_FOUND If the data for any of the cached whitelisted peers
+ * cannot be found. It might have been deleted.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_whitelist_get(ble_gap_addr_t * p_addrs,
+ uint32_t * p_addr_cnt,
+ ble_gap_irk_t * p_irks,
+ uint32_t * p_irk_cnt);
+
+
+/**@brief Function for setting and clearing the device identities list.
+ *
+ * @param[in] p_peers The peers to add to the device identities list. Pass NULL to clear
+ * the device identities list.
+ * @param[in] peer_cnt The number of peers. Pass zero to clear the device identities list.
+ *
+ * @retval NRF_SUCCESS If the device identities list was successfully
+ * set or cleared.
+ * @retval NRF_ERROR_NOT_FOUND If a peer is invalid or its data could not
+ * be found in flash.
+ * @retval BLE_ERROR_GAP_INVALID_BLE_ADDR If a peer has an address that cannot be
+ * used for whitelisting.
+ * @retval BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE If the device identities list is in use and
+ * cannot be set.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ * @retval NRF_ERROR_NOT_SUPPORTED If using a SoftDevice that does not support
+ * device identities, e.g. S130 v2.0.
+ */
+ret_code_t pm_device_identities_list_set(pm_peer_id_t const * p_peers,
+ uint32_t peer_cnt);
+
+
+/**@brief Function for setting the local <em>Bluetooth</em> identity address.
+ *
+ * @details The local <em>Bluetooth</em> identity address is the address that identifies the device
+ * to other peers. The address type must be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref
+ * BLE_GAP_ADDR_TYPE_RANDOM_STATIC. The identity address cannot be changed while roles are running.
+ *
+ * The SoftDevice sets a default address of type @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC when it is
+ * enabled. This default address is a random number that is populated during the IC manufacturing
+ * process. It remains unchanged for the lifetime of each IC, but the application can use this
+ * function to assign a different identity address.
+ *
+ * The identity address is distributed to the peer during bonding. Changing the identity address
+ * means bonded devices might not recognize us.
+ *
+ * @note The SoftDevice functions @ref sd_ble_gap_addr_set and @ref sd_ble_gap_privacy_set must not
+ * be called when using the Peer Manager. Use the Peer Manager equivalents instead.
+ *
+ * @param[in] p_addr The GAP address to be set.
+ *
+ * @retval NRF_SUCCESS If the identity address was set successfully.
+ * @retval NRF_ERROR_NULL If @p p_addr is NULL.
+ * @retval NRF_ERROR_INVALID_ADDR If the @p p_addr pointer is invalid.
+ * @retval BLE_ERROR_GAP_INVALID_BLE_ADDR If the BLE address is invalid.
+ * @retval NRF_ERROR_BUSY If the SoftDevice was busy. Process SoftDevice events
+ * and retry.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized or if this function
+ * was called while advertising, scanning, or while connected.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t pm_id_addr_set(ble_gap_addr_t const * p_addr);
+
+
+/**@brief Function for retrieving the local <em>Bluetooth</em> identity address.
+ *
+ * This function always returns the identity address, irrespective of the privacy settings.
+ * This means that the address type will always be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref
+ * BLE_GAP_ADDR_TYPE_RANDOM_STATIC.
+ *
+ * @param[out] p_addr Pointer to the address structure to be filled in.
+ *
+ * @retval NRF_SUCCESS If the address was retrieved successfully.
+ * @retval NRF_ERROR_NULL If @p p_addr is NULL.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_id_addr_get(ble_gap_addr_t * p_addr);
+
+
+/**@brief Function for configuring privacy settings.
+ *
+ * The privacy settings cannot be configured while advertising, scanning, or while in a connection.
+ *
+ * @note The SoftDevice functions @ref sd_ble_gap_addr_set
+ * and @ref sd_ble_gap_privacy_set must not be called when using the Peer Manager.
+ * Use this function instead.
+ *
+ * @param[in] p_privacy_params Privacy settings.
+ *
+ * @retval NRF_SUCCESS If the privacy settings were configured successfully.
+ * @retval NRF_ERROR_NULL If @p p_privacy_params is NULL.
+ * @retval NRF_ERROR_BUSY If the operation could not be performed at this time.
+ * Process SoftDevice events and retry.
+ * @retval NRF_ERROR_INVALID_PARAM If the address type is invalid.
+ * @retval NRF_ERROR_INVALID_STATE If this function is called while BLE roles using
+ * privacy are enabled.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_privacy_set(pm_privacy_params_t const * p_privacy_params);
+
+
+/**@brief Function for retrieving privacy settings.
+ *
+ * The privacy settings that are returned include the current IRK as well.
+ *
+ * @param[out] p_privacy_params Privacy settings.
+ *
+ * @retval NRF_SUCCESS If the privacy settings were retrieved successfully.
+ * @retval NRF_ERROR_NULL If @p p_privacy_params or @p p_privacy_params->p_device_irk is
+ * NULL.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_privacy_get(pm_privacy_params_t * p_privacy_params);
+
+
+/**@brief Function for resolving a resolvable address with an identity resolution key (IRK).
+ *
+ * @param[in] p_addr A private random resolvable address.
+ * @param[in] p_irk An identity resolution key (IRK).
+ *
+ * @retval true The IRK used matched the one used to create the address.
+ * @retval false The IRK used did not match the one used to create the address, or an argument was
+ * NULL or invalid.
+ */
+bool pm_address_resolve(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk);
+
+
+/**@brief Function for getting the connection handle of the connection with a bonded peer.
+ *
+ * @param[in] peer_id The peer ID of the bonded peer.
+ * @param[out] p_conn_handle Connection handle, or @ref BLE_ERROR_INVALID_CONN_HANDLE if the peer
+ * is not connected.
+ *
+ * @retval NRF_SUCCESS If the connection handle was retrieved successfully.
+ * @retval NRF_ERROR_NULL If @p p_conn_handle was NULL.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_conn_handle_get(pm_peer_id_t peer_id, uint16_t * p_conn_handle);
+
+
+/**@brief Function for retrieving the ID of a peer, given its connection handle.
+ *
+ * @param[in] conn_handle The connection handle of the peer.
+ * @param[out] p_peer_id The peer ID, or @ref PM_PEER_ID_INVALID if the peer is not bonded or
+ * @p conn_handle does not refer to a valid connection.
+ *
+ * @retval NRF_SUCCESS If the peer ID was retrieved successfully.
+ * @retval NRF_ERROR_NULL If @p p_peer_id was NULL.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_peer_id_get(uint16_t conn_handle, pm_peer_id_t * p_peer_id);
+
+
+/**@brief Function for getting the next peer ID in the sequence of all used peer IDs.
+ *
+ * @details This function can be used to loop through all used peer IDs. The order in which
+ * peer IDs are returned should be considered unpredictable. @ref PM_PEER_ID_INVALID
+ * is considered to be before the first and after the last used peer ID.
+ *
+ * @details To loop through all peer IDs exactly once, use the following constuct:
+ * @code{c}
+ * pm_peer_id_t current_peer_id = pm_next_peer_id_get(PM_PEER_ID_INVALID);
+ * while (current_peer_id != PM_PEER_ID_INVALID)
+ * {
+ * // Do something with current_peer_id.
+ * current_peer_id = pm_next_peer_id_get(current_peer_id)
+ * }
+ * @endcode
+ *
+ * @param[in] prev_peer_id The previous peer ID.
+ *
+ * @return The next peer ID. If @p prev_peer_id was @ref PM_PEER_ID_INVALID, the
+ * next peer ID is the first used peer ID. If @p prev_peer_id was the last
+ * used peer ID, the function returns @ref PM_PEER_ID_INVALID.
+ */
+pm_peer_id_t pm_next_peer_id_get(pm_peer_id_t prev_peer_id);
+
+
+/**@brief Function for querying the number of valid peer IDs that are available.
+ *
+ * @details This function returns the number of peers for which there is data in persistent storage.
+ *
+ * @return The number of valid peer IDs.
+ */
+uint32_t pm_peer_count(void);
+
+
+
+
+/**@anchor PM_PEER_DATA_FUNCTIONS
+ * @name Functions (Peer Data)
+ * Functions for manipulating peer data.
+ * @{
+ */
+
+/**
+ * @{
+ */
+
+/**@brief Function for retrieving stored data of a peer.
+ *
+ * @note The length of the provided buffer must be a multiple of 4.
+ *
+ * @param[in] peer_id Peer ID to get data for.
+ * @param[in] data_id Which type of data to read.
+ * @param[out] p_data Where to put the retrieved data. The documentation for
+ * @ref pm_peer_data_id_t specifies what data type each data ID is stored as.
+ * @param[inout] p_len In: The length in bytes of @p p_data.
+ * Out: The length in bytes of the read data, if the read was successful.
+ *
+ * @retval NRF_SUCCESS If the data was read successfully.
+ * @retval NRF_ERROR_INVALID_PARAM If the the data type or the peer ID was invalid or unallocated,
+ * or if the length in @p p_length was not a multiple of 4.
+ * @retval NRF_ERROR_NULL If a pointer parameter was NULL.
+ * @retval NRF_ERROR_NOT_FOUND If no stored data was found for this peer ID/data ID combination.
+ * @retval NRF_ERROR_DATA_SIZE If the provided buffer was not large enough.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_peer_data_load(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ void * p_data,
+ uint16_t * p_len);
+
+/**@brief Function for reading a peer's bonding data (@ref PM_PEER_DATA_ID_BONDING).
+ * @details See @ref pm_peer_data_load for parameters and return values. */
+ret_code_t pm_peer_data_bonding_load(pm_peer_id_t peer_id,
+ pm_peer_data_bonding_t * p_data);
+
+/**@brief Function for reading a peer's remote DB values. (@ref PM_PEER_DATA_ID_GATT_REMOTE).
+ * @details See @ref pm_peer_data_load for parameters and return values. */
+ret_code_t pm_peer_data_remote_db_load(pm_peer_id_t peer_id,
+ ble_gatt_db_srv_t * p_data,
+ uint16_t * p_len);
+
+/**@brief Function for reading a peer's application data. (@ref PM_PEER_DATA_ID_APPLICATION).
+ * @details See @ref pm_peer_data_load for parameters and return values. */
+ret_code_t pm_peer_data_app_data_load(pm_peer_id_t peer_id,
+ void * p_data,
+ uint16_t * p_len);
+/** @}*/
+
+
+/**
+ * @{
+ */
+
+/**@brief Function for setting or updating stored data of a peer.
+ *
+ * @note Writing the data to persistent storage happens asynchronously. Therefore, the buffer
+ * that contains the data must be kept alive until the operation has completed.
+ *
+ * @note The data written using this function might later be overwritten as a result of internal
+ * operations in the Peer Manager. A Peer Manager event is sent each time data is updated,
+ * regardless of whether the operation originated internally or from action by the user.
+ *
+ * @param[in] peer_id Peer ID to set data for.
+ * @param[in] data_id Which type of data to set.
+ * @param[in] p_data New value to set. The documentation for @ref pm_peer_data_id_t specifies
+ * what data type each data ID should be stored as.
+ * @param[in] len The length in bytes of @p p_data.
+ * @param[out] p_token A token that identifies this particular store operation. The token can be
+ * used to identify events that pertain to this operation. This parameter can
+ * be NULL.
+ *
+ * @retval NRF_SUCCESS If the data is scheduled to be written to persistent storage.
+ * @retval NRF_ERROR_NULL If @p p_data is NULL.
+ * @retval NRF_ERROR_NOT_FOUND If no peer was found for the peer ID.
+ * @retval NRF_ERROR_BUSY If the underlying flash handler is busy with other flash
+ * operations. Try again after receiving a Peer Manager event.
+ * @retval NRF_ERROR_FORBIDDEN If data ID is @ref PM_PEER_DATA_ID_BONDING and the new bonding
+ * data also corresponds to another bonded peer. No data is written
+ * so duplicate entries are avoided.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_peer_data_store(pm_peer_id_t peer_id,
+ pm_peer_data_id_t data_id,
+ void const * p_data,
+ uint16_t len,
+ pm_store_token_t * p_token);
+
+/**@brief Function for setting or updating a peer's bonding data (@ref PM_PEER_DATA_ID_BONDING).
+ * @details See @ref pm_peer_data_store for parameters and return values. */
+ret_code_t pm_peer_data_bonding_store(pm_peer_id_t peer_id,
+ pm_peer_data_bonding_t const * p_data,
+ pm_store_token_t * p_token);
+
+/**@brief Function for setting or updating a peer's remote DB values. (@ref PM_PEER_DATA_ID_GATT_REMOTE).
+ * @details See @ref pm_peer_data_store for parameters and return values. */
+ret_code_t pm_peer_data_remote_db_store(pm_peer_id_t peer_id,
+ ble_gatt_db_srv_t const * p_data,
+ uint16_t len,
+ pm_store_token_t * p_token);
+
+/**@brief Function for setting or updating a peer's application data. (@ref PM_PEER_DATA_ID_APPLICATION).
+ * @details See @ref pm_peer_data_store for parameters and return values. */
+ret_code_t pm_peer_data_app_data_store(pm_peer_id_t peer_id,
+ void const * p_data,
+ uint16_t len,
+ pm_store_token_t * p_token);
+/** @}*/
+
+
+/**
+ * @{
+ */
+
+/**@brief Function for deleting a peer's stored pieces of data.
+ *
+ * @details This function deletes specific data that is stored for a peer. Note that bonding data
+ * cannot be cleared separately.
+ *
+ * To delete all data for a peer (including bonding data), use @ref pm_peer_delete.
+ *
+ * @note Clearing data in persistent storage happens asynchronously.
+ *
+ * @param[in] peer_id Peer ID to clear data for.
+ * @param[in] data_id Which data to clear.
+ *
+ * @retval NRF_SUCCESS If the clear procedure was initiated successfully.
+ * @retval NRF_ERROR_INVALID_PARAM If @p data_id was PM_PEER_DATA_ID_BONDING or invalid, or
+ * @p peer_id was invalid.
+ * @retval NRF_ERROR_NOT_FOUND If there was no data to clear for this peer ID/data ID combination.
+ * @retval NRF_ERROR_BUSY If the underlying flash handler is busy with other flash
+ * operations. Try again after receiving a Peer Manager event.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t pm_peer_data_delete(pm_peer_id_t peer_id, pm_peer_data_id_t data_id);
+
+
+/**@brief Function for manually adding a peer to the persistent storage.
+ *
+ * @details This function allocates a new peer ID and stores bonding data for the new peer. The
+ * bonding data is necessary to prevent ambiguity/inconsistency in peer data.
+ *
+ * @param[in] p_bonding_data The bonding data of the new peer (must contain a public/static
+ * address or a non-zero IRK).
+ * @param[out] p_new_peer_id Peer ID for the new peer, or an existing peer if a match was found.
+ * @param[out] p_token A token that identifies this particular store operation (storing the
+ * bonding data). The token can be used to identify events that pertain
+ * to this operation. This parameter can be NULL.
+ *
+ * @retval NRF_SUCCESS If the store operation for bonding data was initiated successfully.
+ * @retval NRF_ERROR_NULL If @p p_bonding_data or @p p_new_peer_id is NULL.
+ * @retval NRF_ERROR_STORAGE_FULL If there is no more space in persistent storage.
+ * @retval NRF_ERROR_NO_MEM If there are no more available peer IDs.
+ * @retval NRF_ERROR_BUSY If the underlying flash filesystem is busy with other flash
+ * operations. Try again after receiving a Peer Manager event.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t pm_peer_new(pm_peer_id_t * p_new_peer_id,
+ pm_peer_data_bonding_t * p_bonding_data,
+ pm_store_token_t * p_token);
+
+
+/**@brief Function for freeing persistent storage for a peer.
+ *
+ * @details This function deletes every piece of data that is associated with the specified peer and
+ * frees the peer ID to be used for another peer. The deletion happens asynchronously, and
+ * the peer ID is not freed until the data is deleted. When the operation finishes, a @ref
+ * PM_EVT_PEER_DELETE_SUCCEEDED or @ref PM_EVT_PEER_DELETE_FAILED event is sent.
+ *
+ * @warning Use this function only when not connected to or connectable for the peer that is being
+ * deleted. If the peer is or becomes connected or data is manually written in flash during
+ * this procedure (until the success or failure event happens), the behavior is undefined.
+ *
+ * @param[in] peer_id Peer ID to be freed and have all associated data deleted.
+ *
+ * @retval NRF_SUCCESS If the operation was initiated successfully.
+ * @retval NRF_ERROR_INVALID_PARAM If the peer ID was not valid.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ */
+ret_code_t pm_peer_delete(pm_peer_id_t peer_id);
+
+
+/**@brief Function for deleting all data stored for all peers.
+ *
+ * @details This function sends either a @ref PM_EVT_PEERS_DELETE_SUCCEEDED or a @ref
+ * PM_EVT_PEERS_DELETE_FAILED event. In addition, a @ref PM_EVT_PEER_DELETE_SUCCEEDED or
+ * @ref PM_EVT_PEER_DELETE_FAILED event is sent for each deleted peer.
+ *
+ * @note When there is no peer data in flash the @ref PM_EVT_PEER_DELETE_SUCCEEDED event is sent synchronously.
+ *
+ * @warning Use this function only when not connected or connectable. If a peer is or becomes
+ * connected or a @ref PM_PEER_DATA_FUNCTIONS function is used during this procedure (until
+ * the success or failure event happens), the behavior is undefined.
+ *
+ * @retval NRF_SUCCESS If the deletion process was initiated successfully.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ */
+ret_code_t pm_peers_delete(void);
+/** @}*/
+
+
+/**
+ * @{
+ */
+
+
+/**@brief Function for finding the highest and lowest ranked peers.
+ *
+ * @details The rank is saved in persistent storage under the data ID @ref PM_PEER_DATA_ID_PEER_RANK.
+ *
+ * @details The interpretation of rank is up to the user, because the rank is only updated by
+ * calling @ref pm_peer_rank_highest or by manipulating the value using a @ref
+ * PM_PEER_DATA_FUNCTIONS function.
+ *
+ * @note Any argument that is NULL is ignored.
+ *
+ * @param[out] p_highest_ranked_peer The peer ID with the highest rank of all peers, for example,
+ * the most recently used peer.
+ * @param[out] p_highest_rank The highest rank.
+ * @param[out] p_lowest_ranked_peer The peer ID with the lowest rank of all peers, for example,
+ * the least recently used peer.
+ * @param[out] p_lowest_rank The lowest rank.
+ *
+ * @retval NRF_SUCCESS If the operation completed successfully.
+ * @retval NRF_ERROR_NOT_FOUND If no peers were found.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ * @retval NRF_ERROR_NOT_SUPPORTED If peer rank functionality has been disabled via the @ref
+ * PM_PEER_RANKS_ENABLED configuration option.
+ */
+ret_code_t pm_peer_ranks_get(pm_peer_id_t * p_highest_ranked_peer,
+ uint32_t * p_highest_rank,
+ pm_peer_id_t * p_lowest_ranked_peer,
+ uint32_t * p_lowest_rank);
+
+
+/**@brief Function for updating the rank of a peer to be highest among all stored peers.
+ *
+ * @details If this function returns @ref NRF_SUCCESS, either a @ref PM_EVT_PEER_DATA_UPDATE_SUCCEEDED or a
+ * @ref PM_EVT_PEER_DATA_UPDATE_FAILED event is sent with a @ref
+ * PM_STORE_TOKEN_INVALID store token when the operation is complete. Until the operation
+ * is complete, this function returns @ref NRF_ERROR_BUSY.
+ *
+ * When the operation is complete, the peer is the highest ranked peer as reported by
+ * @ref pm_peer_ranks_get.
+ *
+ * @note The @ref PM_EVT_PEER_DATA_UPDATE_SUCCEEDED event can arrive before the function returns if the peer
+ * is already ranked highest. In this case, the @ref pm_peer_data_update_succeeded_evt_t::flash_changed flag
+ * in the event will be false.
+ *
+ * @param[in] peer_id The peer to rank highest.
+ *
+ * @retval NRF_SUCCESS If the peer's rank is, or will be updated to be highest.
+ * @retval NRF_ERROR_BUSY If the underlying flash handler is busy with other flash
+ * operations, or if a previous call to this function has not
+ * completed. Try again after receiving a Peer Manager event.
+ * @retval NRF_ERROR_INVALID_STATE If the Peer Manager is not initialized.
+ * @retval NRF_ERROR_RESOURCES If the highest rank is UINT32_MAX, so the new rank would wrap
+ * around to 0. To fix this, manually update all ranks to smaller
+ * values, while still keeping their order.
+ * @retval NRF_ERROR_INTERNAL If an internal error occurred.
+ * @retval NRF_ERROR_NOT_SUPPORTED If peer rank functionality has been disabled via the @ref
+ * PM_PEER_RANKS_ENABLED configuration option.
+ */
+ret_code_t pm_peer_rank_highest(pm_peer_id_t peer_id);
+
+/** @}*/
+
+/** @} */
+
+/** @} */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // PEER_MANAGER_H__
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager_internal.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager_internal.h
new file mode 100644
index 0000000..59bb811
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager_internal.h
@@ -0,0 +1,207 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef PEER_MANAGER_INTERNAL_H__
+#define PEER_MANAGER_INTERNAL_H__
+
+#include <stdint.h>
+#include "sdk_errors.h"
+#include "ble.h"
+#include "ble_gap.h"
+#include "peer_manager_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @cond NO_DOXYGEN
+ * @file peer_manager_types.h
+ *
+ * @addtogroup peer_manager
+ * @brief File containing definitions used solely inside the Peer Manager's modules.
+ * @{
+ */
+
+ANON_UNIONS_ENABLE;
+
+/**@brief One piece of data associated with a peer, together with its type.
+ *
+ * @note This type is deprecated.
+ */
+typedef struct
+{
+ uint16_t length_words; /**< @brief The length of the data in words. */
+ pm_peer_data_id_t data_id; /**< @brief ID that specifies the type of data (defines which member of the union is used). */
+ union
+ {
+ pm_peer_data_bonding_t * p_bonding_data; /**< @brief The exchanged bond information in addition to metadata of the bonding. */
+ uint32_t * p_peer_rank; /**< @brief A value locally assigned to this peer. Its interpretation is up to the user. The rank is not set automatically by the Peer Manager, but it is assigned by the user using either @ref pm_peer_rank_highest or a @ref PM_PEER_DATA_FUNCTIONS function. */
+ bool * p_service_changed_pending; /**< @brief Whether a service changed indication should be sent to the peer. */
+ pm_peer_data_local_gatt_db_t * p_local_gatt_db; /**< @brief Persistent information pertaining to a peer GATT client. */
+ ble_gatt_db_srv_t * p_remote_gatt_db; /**< @brief Persistent information pertaining to a peer GATT server. */
+ uint8_t * p_application_data; /**< @brief Arbitrary data to associate with the peer. This data can be freely used by the application. */
+ void * p_all_data; /**< @brief Generic access pointer to the data. It is used only to handle the data without regard to type. */
+ }; /**< @brief The data. */
+} pm_peer_data_t;
+
+
+/**@brief Immutable version of @ref pm_peer_data_t.
+ *
+ * @note This type is deprecated.
+ */
+typedef struct
+{
+ uint16_t length_words; /**< @brief The length of the data in words. */
+ pm_peer_data_id_t data_id; /**< @brief ID that specifies the type of data (defines which member of the union is used). */
+ union
+ {
+ pm_peer_data_bonding_t const * p_bonding_data; /**< @brief Immutable @ref pm_peer_data_t::p_bonding_data. */
+ uint32_t const * p_peer_rank; /**< @brief Immutable @ref pm_peer_data_t::p_peer_rank. */
+ bool const * p_service_changed_pending; /**< @brief Immutable @ref pm_peer_data_t::p_service_changed_pending. */
+ pm_peer_data_local_gatt_db_t const * p_local_gatt_db; /**< @brief Immutable @ref pm_peer_data_t::p_local_gatt_db. */
+ ble_gatt_db_srv_t const * p_remote_gatt_db; /**< @brief Immutable @ref pm_peer_data_t::p_remote_gatt_db. */
+ uint8_t const * p_application_data; /**< @brief Immutable @ref pm_peer_data_t::p_application_data. */
+ void const * p_all_data; /**< @brief Immutable @ref pm_peer_data_t::p_all_data. */
+ }; /**< @brief The data. */
+} pm_peer_data_const_t;
+
+ANON_UNIONS_DISABLE;
+
+
+/**@brief Version of @ref pm_peer_data_t that reflects the structure of peer data in flash.
+ *
+ * @note This type is deprecated.
+ */
+typedef pm_peer_data_const_t pm_peer_data_flash_t;
+
+
+/**@brief Event handler for events from the @ref peer_manager module.
+ *
+ * @sa pm_register
+ *
+ * @param[in] p_event The event that has occurred.
+ */
+typedef void (*pm_evt_handler_internal_t)(pm_evt_t * p_event);
+
+
+/**@brief Macro for calculating the flash size of bonding data.
+ *
+ * @return The number of words that the data takes in flash.
+ */
+#define PM_BONDING_DATA_N_WORDS() BYTES_TO_WORDS(sizeof(pm_peer_data_bonding_t))
+
+
+/**@brief Macro for calculating the flash size of service changed pending state.
+ *
+ * @return The number of words that the data takes in flash.
+ */
+#define PM_SC_STATE_N_WORDS() BYTES_TO_WORDS(sizeof(bool))
+
+
+/**@brief Macro for calculating the flash size of local GATT database data.
+ *
+ * @param[in] local_db_len The length, in bytes, of the database as reported by the SoftDevice.
+ *
+ * @return The number of words that the data takes in flash.
+ */
+#define PM_LOCAL_DB_N_WORDS(local_db_len) \
+ BYTES_TO_WORDS((local_db_len) + PM_LOCAL_DB_LEN_OVERHEAD_BYTES)
+
+
+/**@brief Macro for calculating the length of a local GATT database attribute array.
+ *
+ * @param[in] n_words The number of words that the data takes in flash.
+ *
+ * @return The length of the database attribute array.
+ */
+#define PM_LOCAL_DB_LEN(n_words) (((n_words) * BYTES_PER_WORD) - PM_LOCAL_DB_LEN_OVERHEAD_BYTES)
+
+
+/**@brief Macro for calculating the flash size of remote GATT database data.
+ *
+ * @param[in] service_count The number of services in the service array.
+ *
+ * @return The number of words that the data takes in flash.
+ */
+#define PM_REMOTE_DB_N_WORDS(service_count) BYTES_TO_WORDS(sizeof(ble_gatt_db_srv_t) * (service_count))
+
+
+/**@brief Macro for calculating the flash size of remote GATT database data.
+ *
+ * @param[in] n_words The length in number of words.
+ *
+ * @return The number of words that the data takes in flash.
+ */
+#define PM_REMOTE_DB_N_SERVICES(n_words) (((n_words) * BYTES_PER_WORD) / sizeof(ble_gatt_db_srv_t))
+
+
+/**@brief Function for calculating the flash size of the usage index.
+ *
+ * @return The number of words that the data takes in flash.
+ */
+#define PM_USAGE_INDEX_N_WORDS() BYTES_TO_WORDS(sizeof(uint32_t))
+
+/** @}
+ * @endcond
+ */
+
+
+#ifdef NRF_PM_DEBUG
+
+ #define NRF_PM_DEBUG_CHECK(condition) \
+ if (!(condition)) \
+ { \
+ __asm("bkpt #0"); \
+ }
+
+#else
+
+ // Prevent "variable set but never used" compiler warnings.
+ #define NRF_PM_DEBUG_CHECK(condition) (void)(condition)
+
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PEER_MANAGER_INTERNAL_H__ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager_types.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager_types.h
new file mode 100644
index 0000000..34fd328
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/peer_manager_types.h
@@ -0,0 +1,354 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/**
+ * @file peer_manager_types.h
+ *
+ * @addtogroup peer_manager
+ * @{
+ */
+
+#ifndef PEER_MANAGER_TYPES_H__
+#define PEER_MANAGER_TYPES_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include "nrf.h"
+#include "ble_gap.h"
+#include "ble_hci.h"
+#include "ble_gatt_db.h"
+#include "app_util.h"
+#include "app_util_platform.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**@brief Handle to uniquely identify a peer for which we have persistently stored data.
+ */
+typedef uint16_t pm_peer_id_t;
+
+/**@brief Type that is used for write prepares (used to reserve space in flash).
+ */
+typedef uint32_t pm_prepare_token_t;
+
+/**@brief Type that is used to hold a reference to a stored item in flash.
+ */
+typedef uint32_t pm_store_token_t;
+
+/**@brief Errors from security procedures in Peer Manager.
+ *
+ * @details Possible values are defined in @ref PM_SEC_ERRORS and @ref BLE_GAP_SEC_STATUS.
+ */
+typedef uint16_t pm_sec_error_code_t;
+
+
+//lint -emacro(516,PM_LOCAL_DB_LEN_OVERHEAD_BYTES)
+
+#define PM_PEER_ID_INVALID 0xFFFF /**< @brief Invalid value for @ref pm_peer_id_t. */
+#define PM_STORE_TOKEN_INVALID 0 /**< @brief Invalid value for store token. */
+#define PM_PEER_ID_N_AVAILABLE_IDS 256 /**< @brief The number of available peer IDs. */
+#define PM_LOCAL_DB_LEN_OVERHEAD_BYTES offsetof(pm_peer_data_local_gatt_db_t, data) /**< @brief The static-length part of the local GATT data struct. */
+
+
+#define PM_CONN_SEC_ERROR_BASE 0x1000 /**< @brief The base for Peer Manager defined errors. See @ref PM_SEC_ERRORS and @ref pm_sec_error_code_t. */
+
+
+/**@defgroup PM_SEC_ERRORS Peer Manager defined security errors
+ *
+ * @details The first 256 numbers in this range correspond to the status codes in
+ * @ref BLE_HCI_STATUS_CODES.
+ * @{ */
+#define PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING (PM_CONN_SEC_ERROR_BASE + 0x06) /**< @brief Encryption failed because the peripheral has lost the LTK for this bond. See also @ref BLE_HCI_STATUS_CODE_PIN_OR_KEY_MISSING and Table 3.7 ("Pairing Failed Reason Codes") in the Bluetooth Core Specification 4.2, section 3.H.3.5.5 (@linkBLEcore). */
+#define PM_CONN_SEC_ERROR_MIC_FAILURE (PM_CONN_SEC_ERROR_BASE + 0x3D) /**< @brief Encryption ended with disconnection because of mismatching keys or a stray packet during a procedure. See the SoftDevice GAP Message Sequence Charts on encryption (@linkBLEMSCgap), the Bluetooth Core Specification 4.2, sections 6.B.5.1.3.1 and 3.H.3.5.5 (@linkBLEcore), and @ref BLE_HCI_CONN_TERMINATED_DUE_TO_MIC_FAILURE. */
+#define PM_CONN_SEC_ERROR_DISCONNECT (PM_CONN_SEC_ERROR_BASE + 0x100) /**< @brief Pairing or encryption did not finish before the link disconnected for an unrelated reason. */
+#define PM_CONN_SEC_ERROR_SMP_TIMEOUT (PM_CONN_SEC_ERROR_BASE + 0x101) /**< @brief Pairing/bonding could not start because an SMP time-out has already happened on this link. This means that no more pairing or bonding can happen on this link. To be able to pair or bond, the link must be disconnected and then reconnected. See Bluetooth Core Specification 4.2 section 3.H.3.4 (@linkBLEcore). */
+ /** @} */
+
+
+
+/**@defgroup PM_PEER_ID_VERSIONS All versions of Peer IDs.
+ * @brief The data ID for each iteration of the data formats in flash.
+ * @details Each time the format (in flash) of a piece of peer data changes, the data ID will also
+ * be updated. This list of defines is a record of each data ID that has ever existed, and
+ * code that caters to legacy formats can find the relevant IDs here.
+ * @{ */
+#define PM_PEER_DATA_ID_FIRST_VX 0 /**< @brief The smallest data ID. */
+#define PM_PEER_DATA_ID_BONDING_V1 0 /**< @brief The data ID of the first version of bonding data. */
+#define PM_PEER_DATA_ID_BONDING_V2 7 /**< @brief The data ID of the second version of bonding data. */
+#define PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING_V1 1 /**< @brief The data ID of the first version of the service changed pending flag. */
+#define PM_PEER_DATA_ID_GATT_LOCAL_V1 2 /**< @brief The data ID of the first version of local GATT data. */
+#define PM_PEER_DATA_ID_GATT_LOCAL_V2 8 /**< @brief The data ID of the second version of local GATT data. */
+#define PM_PEER_DATA_ID_GATT_REMOTE_V1 3 /**< @brief The data ID of the first version of remote GATT data. */
+#define PM_PEER_DATA_ID_APPLICATION_V1 4 /**< @brief The data ID of the first version of application data. */
+#define PM_PEER_DATA_ID_GATT_REMOTE_V2 5 /**< @brief The data ID of the second version of remote GATT data. */
+#define PM_PEER_DATA_ID_PEER_RANK_V1 6 /**< @brief The data ID of the first version of the rank. */
+#define PM_PEER_DATA_ID_LAST_VX 9 /**< @brief The data ID after the last valid one. */
+#define PM_PEER_DATA_ID_INVALID_VX 0xFF /**< @brief A data ID guaranteed to be invalid. */
+/**@}*/
+
+
+/**@brief The different types of data associated with a peer.
+ */
+typedef enum
+{
+ PM_PEER_DATA_ID_FIRST = PM_PEER_DATA_ID_FIRST_VX, /**< @brief The smallest data ID. */
+ PM_PEER_DATA_ID_BONDING = PM_PEER_DATA_ID_BONDING_V2, /**< @brief The data ID for bonding data. Type: @ref pm_peer_data_bonding_t. */
+ PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING = PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING_V1, /**< @brief The data ID for service changed state. Type: bool. */
+ PM_PEER_DATA_ID_GATT_LOCAL = PM_PEER_DATA_ID_GATT_LOCAL_V2, /**< @brief The data ID for local GATT data (sys attributes). Type: @ref pm_peer_data_local_gatt_db_t. */
+ PM_PEER_DATA_ID_GATT_REMOTE = PM_PEER_DATA_ID_GATT_REMOTE_V2, /**< @brief The data ID for remote GATT data. Type: uint8_t array. */
+ PM_PEER_DATA_ID_PEER_RANK = PM_PEER_DATA_ID_PEER_RANK_V1, /**< @brief The data ID for peer rank. See @ref pm_peer_rank_highest. Type: uint32_t. */
+ PM_PEER_DATA_ID_APPLICATION = PM_PEER_DATA_ID_APPLICATION_V1, /**< @brief The data ID for application data. Type: uint8_t array. */
+ PM_PEER_DATA_ID_LAST = PM_PEER_DATA_ID_LAST_VX, /**< @brief One more than the highest data ID. */
+ PM_PEER_DATA_ID_INVALID = PM_PEER_DATA_ID_INVALID_VX, /**< @brief A data ID guaranteed to be invalid. */
+} pm_peer_data_id_t;
+
+
+/**@brief Different procedures that can lead to an encrypted link.
+ */
+typedef enum
+{
+ PM_CONN_SEC_PROCEDURE_ENCRYPTION, /**< @brief Using an LTK that was shared during a previous bonding procedure to encrypt the link. */
+ PM_CONN_SEC_PROCEDURE_BONDING, /**< @brief A pairing procedure, followed by a bonding procedure. */
+ PM_CONN_SEC_PROCEDURE_PAIRING, /**< @brief A pairing procedure with no bonding. */
+} pm_conn_sec_procedure_t;
+
+
+/**@brief Configuration of a security procedure.
+ */
+typedef struct
+{
+ bool allow_repairing; /** @brief Whether to allow the peer to pair if it wants to, but is already bonded. If this is false, the procedure is rejected, and no more events are sent. Default: false. */
+} pm_conn_sec_config_t;
+
+
+/**@brief Data associated with a bond to a peer.
+ */
+typedef struct
+{
+ uint8_t own_role; /**< @brief The BLE role of the local device during bonding. See @ref BLE_GAP_ROLES. */
+ ble_gap_id_key_t peer_ble_id; /**< @brief The peer's Bluetooth address and identity resolution key (IRK). */
+ ble_gap_enc_key_t peer_ltk; /**< @brief The peer's long-term encryption key (LTK) and master ID. */
+ ble_gap_enc_key_t own_ltk; /**< @brief Locally generated long-term encryption key (LTK) and master ID, distributed to the peer. */
+} pm_peer_data_bonding_t;
+
+
+/**@brief Data on a local GATT database.
+ */
+typedef struct
+{
+ uint32_t flags; /**< @brief Flags that describe the database attributes. */
+ uint16_t len; /**< @brief Size of the attribute array. */
+ uint8_t data[1]; /**< @brief Array to hold the database attributes. */
+} pm_peer_data_local_gatt_db_t;
+
+
+/**@brief Device Privacy.
+ *
+ * The privacy feature provides a way for the device to avoid being tracked over a period of
+ * time. The privacy feature, when enabled, hides the local device identity and replaces it
+ * with a private address that is automatically refreshed at a specified interval.
+ *
+ * If a device still wants to be recognized by other peers, it needs to share it's Identity
+ * Resolving Key (IRK). With this key, a device can generate a random private address that
+ * can only be recognized by peers in possession of that key, and devices can establish
+ * connections without revealing their real identities.
+ *
+ * @note If the device IRK is updated, the new IRK becomes the one to be distributed in all
+ * bonding procedures performed after @ref sd_ble_gap_privacy_set returns.
+ * The IRK distributed during bonding procedure is the device IRK that is active when @ref
+ * sd_ble_gap_sec_params_reply is called.
+ */
+typedef ble_gap_privacy_params_t pm_privacy_params_t;
+
+
+/**@brief Types of events that can come from the @ref peer_manager module.
+ */
+typedef enum
+{
+ PM_EVT_BONDED_PEER_CONNECTED, /**< @brief A connected peer has been identified as one with which we have a bond. When performing bonding with a peer for the first time, this event will not be sent until a new connection is established with the peer. When we are central, this event is always sent when the Peer Manager receives the @ref BLE_GAP_EVT_CONNECTED event. When we are peripheral, this event might in rare cases arrive later. */
+ PM_EVT_CONN_SEC_START, /**< @brief A security procedure has started on a link, initiated either locally or remotely. The security procedure is using the last parameters provided via @ref pm_sec_params_set. This event is always followed by either a @ref PM_EVT_CONN_SEC_SUCCEEDED or a @ref PM_EVT_CONN_SEC_FAILED event. This is an informational event; no action is needed for the procedure to proceed. */
+ PM_EVT_CONN_SEC_SUCCEEDED, /**< @brief A link has been encrypted, either as a result of a call to @ref pm_conn_secure or a result of an action by the peer. The event structure contains more information about the circumstances. This event might contain a peer ID with the value @ref PM_PEER_ID_INVALID, which means that the peer (central) used an address that could not be identified, but it used an encryption key (LTK) that is present in the database. */
+ PM_EVT_CONN_SEC_FAILED, /**< @brief A pairing or encryption procedure has failed. In some cases, this means that security is not possible on this link (temporarily or permanently). How to handle this error depends on the application. */
+ PM_EVT_CONN_SEC_CONFIG_REQ, /**< @brief The peer (central) has requested pairing, but a bond already exists with that peer. Reply by calling @ref pm_conn_sec_config_reply before the event handler returns. If no reply is sent, a default is used. */
+ PM_EVT_CONN_SEC_PARAMS_REQ, /**< @brief Security parameters (@ref ble_gap_sec_params_t) are needed for an ongoing security procedure. Reply with @ref pm_conn_sec_params_reply before the event handler returns. If no reply is sent, the parameters given in @ref pm_sec_params_set are used. If a peripheral connection, the central's sec_params will be available in the event. */
+ PM_EVT_STORAGE_FULL, /**< @brief There is no more room for peer data in flash storage. To solve this problem, delete data that is not needed anymore and run a garbage collection procedure in FDS. */
+ PM_EVT_ERROR_UNEXPECTED, /**< @brief An unrecoverable error happened inside Peer Manager. An operation failed with the provided error. */
+ PM_EVT_PEER_DATA_UPDATE_SUCCEEDED, /**< @brief A piece of peer data was stored, updated, or cleared in flash storage. This event is sent for all successful changes to peer data, also those initiated internally in Peer Manager. To identify an operation, compare the store token in the event with the store token received during the initiating function call. Events from internally initiated changes might have invalid store tokens. */
+ PM_EVT_PEER_DATA_UPDATE_FAILED, /**< @brief A piece of peer data could not be stored, updated, or cleared in flash storage. This event is sent instead of @ref PM_EVT_PEER_DATA_UPDATE_SUCCEEDED for the failed operation. */
+ PM_EVT_PEER_DELETE_SUCCEEDED, /**< @brief A peer was cleared from flash storage, for example because a call to @ref pm_peer_delete succeeded. This event can also be sent as part of a call to @ref pm_peers_delete or internal cleanup. */
+ PM_EVT_PEER_DELETE_FAILED, /**< @brief A peer could not be cleared from flash storage. This event is sent instead of @ref PM_EVT_PEER_DELETE_SUCCEEDED for the failed operation. */
+ PM_EVT_PEERS_DELETE_SUCCEEDED, /**< @brief A call to @ref pm_peers_delete has completed successfully. Flash storage now contains no peer data. */
+ PM_EVT_PEERS_DELETE_FAILED, /**< @brief A call to @ref pm_peers_delete has failed, which means that at least one of the peers could not be deleted. Other peers might have been deleted, or might still be queued to be deleted. No more @ref PM_EVT_PEERS_DELETE_SUCCEEDED or @ref PM_EVT_PEERS_DELETE_FAILED events are sent until the next time @ref pm_peers_delete is called. */
+ PM_EVT_LOCAL_DB_CACHE_APPLIED, /**< @brief Local database values for a peer (taken from flash storage) have been provided to the SoftDevice. */
+ PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED, /**< @brief Local database values for a peer (taken from flash storage) were rejected by the SoftDevice, which means that either the database has changed or the user has manually set the local database to an invalid value (using @ref pm_peer_data_store). */
+ PM_EVT_SERVICE_CHANGED_IND_SENT, /**< @brief A service changed indication has been sent to a peer, as a result of a call to @ref pm_local_database_has_changed. This event will be followed by a @ref PM_EVT_SERVICE_CHANGED_IND_CONFIRMED event if the peer acknowledges the indication. */
+ PM_EVT_SERVICE_CHANGED_IND_CONFIRMED, /**< @brief A service changed indication that was sent has been confirmed by a peer. The peer can now be considered aware that the local database has changed. */
+ PM_EVT_SLAVE_SECURITY_REQ, /**< @brief The peer (peripheral) has requested link encryption, which has been enabled. */
+ PM_EVT_FLASH_GARBAGE_COLLECTED, /**< @brief The flash has been garbage collected (By FDS), possibly freeing up space. */
+} pm_evt_id_t;
+
+
+/**@brief Events parameters specific to the @ref PM_EVT_CONN_SEC_START event.
+ */
+typedef struct
+{
+ pm_conn_sec_procedure_t procedure; /**< @brief The procedure that has started. */
+} pm_conn_sec_start_evt_t;
+
+
+/**@brief Parameters specific to the @ref PM_EVT_CONN_SEC_SUCCEEDED event.
+ */
+typedef struct
+{
+ pm_conn_sec_procedure_t procedure; /**< @brief The procedure that led to securing the link. */
+ bool data_stored; /**< @brief Whether bonding data was successfully requested to be stored. This is false if: No bonding happened, or an internal error occurred when trying to store the data, or if the data was rejected via @ref pm_conn_sec_config_reply. */
+} pm_conn_secured_evt_t;
+
+
+/**@brief Parameters specific to the @ref PM_EVT_CONN_SEC_FAILED event.
+ */
+typedef struct
+{
+ pm_conn_sec_procedure_t procedure; /**< @brief The procedure that failed. */
+ pm_sec_error_code_t error; /**< @brief An error code that describes the failure. */
+ uint8_t error_src; /**< @brief The party that raised the error, see @ref BLE_GAP_SEC_STATUS_SOURCES. */
+} pm_conn_secure_failed_evt_t;
+
+
+/**@brief Parameters specific to the @ref PM_EVT_CONN_SEC_PARAMS_REQ event.
+ */
+typedef struct
+{
+ ble_gap_sec_params_t const * p_peer_params; /**< @brief Peer security parameters, if role is peripheral. Otherwise, this is NULL. */
+ void const * p_context; /**< @brief This pointer must be provided in the reply if the reply function takes a p_context argument. */
+} pm_conn_sec_params_req_evt_t;
+
+
+/**@brief Actions that can be performed to peer data in persistent storage.
+ */
+typedef enum
+{
+ PM_PEER_DATA_OP_UPDATE, /**< @brief Writing or overwriting the data. */
+ PM_PEER_DATA_OP_DELETE, /**< @brief Removing the data. */
+} pm_peer_data_op_t;
+
+
+/**@brief Parameters specific to the @ref PM_EVT_PEER_DATA_UPDATE_SUCCEEDED event.
+ */
+typedef struct
+{
+ pm_peer_data_id_t data_id; /**< @brief The type of the data that was changed. */
+ pm_peer_data_op_t action; /**< @brief What happened to the data. */
+ pm_store_token_t token; /**< @brief Token that identifies the operation. For @ref PM_PEER_DATA_OP_DELETE actions, this token can be disregarded. For @ref PM_PEER_DATA_OP_UPDATE actions, compare this token with the token that is received from a call to a @ref PM_PEER_DATA_FUNCTIONS function. */
+ uint8_t flash_changed : 1; /**< @brief If this is false, no operation was done in flash, because the value was already what it should be. Please note that in certain scenarios, this flag will be true even if the new value is the same as the old. */
+} pm_peer_data_update_succeeded_evt_t;
+
+
+/**@brief Parameters specific to the @ref PM_EVT_PEER_DATA_UPDATE_FAILED event.
+ */
+typedef struct
+{
+ pm_peer_data_id_t data_id; /**< @brief The type of the data that was supposed to be changed. */
+ pm_peer_data_op_t action; /**< @brief The action that failed. */
+ pm_store_token_t token; /**< @brief Token that identifies the operation. For @ref PM_PEER_DATA_OP_DELETE actions, this token can be disregarded. For @ref PM_PEER_DATA_OP_UPDATE actions, compare this token with the token that is received from a call to a @ref PM_PEER_DATA_FUNCTIONS function. */
+ ret_code_t error; /**< @brief An error code that describes the failure. */
+} pm_peer_data_update_failed_t;
+
+
+/**@brief Standard parameters for failure events.
+ */
+typedef struct
+{
+ ret_code_t error; /**< @brief The error that occurred. */
+} pm_failure_evt_t;
+
+
+/**@brief Events parameters specific to the @ref PM_EVT_SLAVE_SECURITY_REQ event.
+ */
+typedef struct
+{
+ bool bond; /**< @brief Whether the peripheral requested bonding. */
+ bool mitm; /**< @brief Whether the peripheral requested man-in-the-middle protection. */
+} pm_evt_slave_security_req_t;
+
+
+/**@brief An event from the @ref peer_manager module.
+ *
+ * @details The structure contains both standard parameters and parameters that are specific to some events.
+ */
+typedef struct
+{
+ pm_evt_id_t evt_id; /**< @brief The type of the event. */
+ uint16_t conn_handle; /**< @brief The connection that this event pertains to, or @ref BLE_CONN_HANDLE_INVALID. */
+ pm_peer_id_t peer_id; /**< @brief The bonded peer that this event pertains to, or @ref PM_PEER_ID_INVALID. */
+ union
+ {
+ pm_conn_sec_start_evt_t conn_sec_start; /**< @brief Parameters specific to the @ref PM_EVT_CONN_SEC_START event. */
+ pm_conn_secured_evt_t conn_sec_succeeded; /**< @brief Parameters specific to the @ref PM_EVT_CONN_SEC_SUCCEEDED event. */
+ pm_conn_secure_failed_evt_t conn_sec_failed; /**< @brief Parameters specific to the @ref PM_EVT_CONN_SEC_FAILED event. */
+ pm_conn_sec_params_req_evt_t conn_sec_params_req; /**< @brief Parameters specific to the @ref PM_EVT_CONN_SEC_PARAMS_REQ event. */
+ pm_peer_data_update_succeeded_evt_t peer_data_update_succeeded; /**< @brief Parameters specific to the @ref PM_EVT_PEER_DATA_UPDATE_SUCCEEDED event. */
+ pm_peer_data_update_failed_t peer_data_update_failed; /**< @brief Parameters specific to the @ref PM_EVT_PEER_DATA_UPDATE_FAILED event. */
+ pm_failure_evt_t peer_delete_failed; /**< @brief Parameters specific to the @ref PM_EVT_PEER_DELETE_FAILED event. */
+ pm_failure_evt_t peers_delete_failed_evt; /**< @brief Parameters specific to the @ref PM_EVT_PEERS_DELETE_FAILED event. */
+ pm_failure_evt_t error_unexpected; /**< @brief Parameters specific to the @ref PM_EVT_ERROR_UNEXPECTED event. */
+ pm_evt_slave_security_req_t slave_security_req; /**< @brief Parameters specific to the @ref PM_EVT_SLAVE_SECURITY_REQ event. */
+ } params;
+} pm_evt_t;
+
+
+/**@brief Event handler for events from the @ref peer_manager module.
+ *
+ * @sa pm_register
+ *
+ * @param[in] p_event The event that has occurred.
+ */
+typedef void (*pm_evt_handler_t)(pm_evt_t const * p_event);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PEER_MANAGER_TYPES_H__ */
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_buffer.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_buffer.c
new file mode 100644
index 0000000..4fdbb34
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_buffer.c
@@ -0,0 +1,151 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "pm_buffer.h"
+
+#include <stdbool.h>
+#include <string.h>
+#include "nrf_error.h"
+#include "pm_mutex.h"
+
+
+#define BUFFER_IS_VALID(p_buffer) ((p_buffer != NULL) \
+ && (p_buffer->p_memory != NULL) \
+ && (p_buffer->p_mutex != NULL))
+
+
+
+ret_code_t pm_buffer_init(pm_buffer_t * p_buffer,
+ uint8_t * p_buffer_memory,
+ uint32_t buffer_memory_size,
+ uint8_t * p_mutex_memory,
+ uint32_t mutex_memory_size,
+ uint32_t n_blocks,
+ uint32_t block_size)
+{
+ if ( (p_buffer != NULL)
+ && (p_buffer_memory != NULL)
+ && (p_mutex_memory != NULL)
+ && (buffer_memory_size >= (n_blocks * block_size))
+ && (mutex_memory_size >= MUTEX_STORAGE_SIZE(n_blocks))
+ && (n_blocks != 0)
+ && (block_size != 0))
+ {
+ p_buffer->p_memory = p_buffer_memory;
+ p_buffer->p_mutex = p_mutex_memory;
+ p_buffer->n_blocks = n_blocks;
+ p_buffer->block_size = block_size;
+ pm_mutex_init(p_buffer->p_mutex, n_blocks);
+
+ return NRF_SUCCESS;
+ }
+ else
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+}
+
+
+uint8_t pm_buffer_block_acquire(pm_buffer_t * p_buffer, uint32_t n_blocks)
+{
+ if (!BUFFER_IS_VALID(p_buffer))
+ {
+ return ( PM_BUFFER_INVALID_ID );
+ }
+
+ uint8_t first_locked_mutex = PM_BUFFER_INVALID_ID;
+
+ for (uint8_t i = 0; i < p_buffer->n_blocks; i++)
+ {
+ if (pm_mutex_lock(p_buffer->p_mutex, i))
+ {
+ if (first_locked_mutex == PM_BUFFER_INVALID_ID)
+ {
+ first_locked_mutex = i;
+ }
+ if ((i - first_locked_mutex + 1) == n_blocks)
+ {
+ return first_locked_mutex;
+ }
+ }
+ else if (first_locked_mutex != PM_BUFFER_INVALID_ID)
+ {
+ for (uint8_t j = first_locked_mutex; j < i; j++)
+ {
+ pm_buffer_release(p_buffer, j);
+ }
+ first_locked_mutex = PM_BUFFER_INVALID_ID;
+ }
+ }
+
+ return ( PM_BUFFER_INVALID_ID );
+}
+
+
+uint8_t * pm_buffer_ptr_get(pm_buffer_t * p_buffer, uint8_t id)
+{
+ if (!BUFFER_IS_VALID(p_buffer))
+ {
+ return ( NULL );
+ }
+
+ if ( (id != PM_BUFFER_INVALID_ID)
+ && pm_mutex_lock_status_get(p_buffer->p_mutex, id) )
+ {
+ return ( &p_buffer->p_memory[id * p_buffer->block_size] );
+ }
+ else
+ {
+ return ( NULL );
+ }
+}
+
+
+void pm_buffer_release(pm_buffer_t * p_buffer, uint8_t id)
+{
+ if ( BUFFER_IS_VALID(p_buffer)
+ && (id != PM_BUFFER_INVALID_ID)
+ && pm_mutex_lock_status_get(p_buffer->p_mutex, id))
+ {
+ pm_mutex_unlock(p_buffer->p_mutex, id);
+ }
+}
+#endif // NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_buffer.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_buffer.h
new file mode 100644
index 0000000..619af1d
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_buffer.h
@@ -0,0 +1,159 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef BUFFER_H__
+#define BUFFER_H__
+
+#include <stdint.h>
+#include "compiler_abstraction.h"
+#include "sdk_errors.h"
+#include "pm_mutex.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @cond NO_DOXYGEN
+ * @defgroup pm_buffer Buffer
+ * @ingroup peer_manager
+ * @{
+ * @brief An internal module of @ref peer_manager. This module provides a simple buffer.
+ */
+
+
+#define PM_BUFFER_INVALID_ID 0xFF //!< Invalid buffer block ID.
+
+
+/**@brief Convenience macro for declaring memory and initializing a buffer instance.
+ *
+ * @param[out] p_buffer The buffer instance to initialize.
+ * @param[in] n_blocks The desired number of blocks in the buffer.
+ * @param[in] block_size The desired block size of the buffer.
+ * @param[out] err_code The return code from @ref pm_buffer_init.
+ */
+#define PM_BUFFER_INIT(p_buffer, n_blocks, block_size, err_code) \
+do \
+{ \
+ __ALIGN(4) static uint8_t buffer_memory[(n_blocks) * (block_size)]; \
+ static uint8_t mutex_memory[MUTEX_STORAGE_SIZE(n_blocks)]; \
+ err_code = pm_buffer_init((p_buffer), \
+ buffer_memory, \
+ (n_blocks) * (block_size), \
+ mutex_memory, \
+ MUTEX_STORAGE_SIZE(n_blocks), \
+ (n_blocks), \
+ (block_size)); \
+} while (0)
+
+
+typedef struct
+{
+ uint8_t * p_memory; /**< The storage for all buffer entries. The size of the buffer must be n_blocks*block_size. */
+ uint8_t * p_mutex; /**< A mutex group with one mutex for each buffer entry. */
+ uint32_t n_blocks; /**< The number of allocatable blocks in the buffer. */
+ uint32_t block_size; /**< The size of each block in the buffer. */
+} pm_buffer_t;
+
+/**@brief Function for initializing a buffer instance.
+ *
+ * @param[out] p_buffer The buffer instance to initialize.
+ * @param[in] p_buffer_memory The memory this buffer will use.
+ * @param[in] buffer_memory_size The size of p_buffer_memory. This must be at least
+ * n_blocks*block_size.
+ * @param[in] p_mutex_memory The memory for the mutexes. This must be at least
+ * @ref MUTEX_STORAGE_SIZE(n_blocks).
+ * @param[in] mutex_memory_size The size of p_mutex_memory.
+ * @param[in] n_blocks The number of blocks in the buffer.
+ * @param[in] block_size The size of each block.
+ *
+ * @retval NRF_SUCCESS Successfully initialized buffer instance.
+ * @retval NRF_ERROR_INVALID_PARAM A parameter was 0 or NULL or a size was too small.
+ */
+ret_code_t pm_buffer_init(pm_buffer_t * p_buffer,
+ uint8_t * p_buffer_memory,
+ uint32_t buffer_memory_size,
+ uint8_t * p_mutex_memory,
+ uint32_t mutex_memory_size,
+ uint32_t n_blocks,
+ uint32_t block_size);
+
+
+/**@brief Function for acquiring a buffer block in a buffer.
+ *
+ * @param[in] p_buffer The buffer instance acquire from.
+ * @param[in] n_blocks The number of contiguous blocks to acquire.
+ *
+ * @return The id of the acquired block, if successful.
+ * @retval PM_BUFFER_INVALID_ID If unsuccessful.
+ */
+uint8_t pm_buffer_block_acquire(pm_buffer_t * p_buffer, uint32_t n_blocks);
+
+
+/**@brief Function for getting a pointer to a specific buffer block.
+ *
+ * @param[in] p_buffer The buffer instance get from.
+ * @param[in] id The id of the buffer to get the pointer for.
+ *
+ * @return A pointer to the buffer for the specified id, if the id is valid.
+ * @retval NULL If the id is invalid.
+ */
+uint8_t * pm_buffer_ptr_get(pm_buffer_t * p_buffer, uint8_t id);
+
+
+/**@brief Function for releasing a buffer block.
+ *
+ * @param[in] p_buffer The buffer instance containing the block to release.
+ * @param[in] id The id of the block to release.
+ */
+void pm_buffer_release(pm_buffer_t * p_buffer, uint8_t id);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BUFFER_H__
+
+/**
+ * @}
+ * @endcond
+ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_mutex.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_mutex.c
new file mode 100644
index 0000000..543a99b
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_mutex.c
@@ -0,0 +1,144 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "pm_mutex.h"
+
+#include <stdbool.h>
+#include <string.h>
+#include "nrf_error.h"
+#include "app_util_platform.h"
+
+
+
+/**@brief Locks the mutex defined by the mask.
+ *
+ * @param p_mutex pointer to the mutex storage.
+ * @param mutex_mask the mask identifying the mutex position.
+ *
+ * @retval true if the mutex could be locked.
+ * @retval false if the mutex was already locked.
+ */
+static bool lock_by_mask(uint8_t * p_mutex, uint8_t mutex_mask)
+{
+ bool success = false;
+
+ if ( (*p_mutex & mutex_mask) == 0 )
+ {
+ CRITICAL_REGION_ENTER();
+ if ( (*p_mutex & mutex_mask) == 0 )
+ {
+ *p_mutex |= mutex_mask;
+
+ success = true;
+ }
+ CRITICAL_REGION_EXIT();
+ }
+
+ return ( success );
+}
+
+
+void pm_mutex_init(uint8_t * p_mutex, uint16_t mutex_size)
+{
+ if (p_mutex != NULL)
+ {
+ memset(&p_mutex[0], 0, MUTEX_STORAGE_SIZE(mutex_size));
+ }
+}
+
+
+bool pm_mutex_lock(uint8_t * p_mutex, uint16_t mutex_id)
+{
+ if (p_mutex != NULL)
+ {
+ return ( lock_by_mask(&(p_mutex[mutex_id >> 3]), (1 << (mutex_id & 0x07))) );
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+void pm_mutex_unlock(uint8_t * p_mutex, uint16_t mutex_id)
+{
+ uint8_t mutex_base = mutex_id >> 3;
+ uint8_t mutex_mask = (1 << (mutex_id & 0x07));
+
+ if ((p_mutex != NULL)
+ && (p_mutex[mutex_base] & mutex_mask))
+ {
+ CRITICAL_REGION_ENTER();
+ p_mutex[mutex_base] &= ~mutex_mask;
+ CRITICAL_REGION_EXIT();
+ }
+}
+
+
+uint16_t pm_mutex_lock_first_available(uint8_t * p_mutex, uint16_t mutex_size)
+{
+ if (p_mutex != NULL)
+ {
+ for ( uint16_t i = 0; i < mutex_size; i++ )
+ {
+ if ( lock_by_mask(&(p_mutex[i >> 3]), 1 << (i & 0x07)) )
+ {
+ return ( i );
+ }
+ }
+ }
+
+ return ( mutex_size );
+}
+
+
+bool pm_mutex_lock_status_get(uint8_t * p_mutex, uint16_t mutex_id)
+{
+ if (p_mutex != NULL)
+ {
+ return ( (p_mutex[mutex_id >> 3] & (1 << (mutex_id & 0x07))) );
+ }
+ else
+ {
+ return true;
+ }
+}
+#endif // NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_mutex.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_mutex.h
new file mode 100644
index 0000000..c598d3d
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/pm_mutex.h
@@ -0,0 +1,125 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef MUTEX_H__
+#define MUTEX_H__
+
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @cond NO_DOXYGEN
+ * @defgroup pm_mutex Mutex
+ * @ingroup peer_manager
+ * @{
+ * @brief An internal module of @ref peer_manager. This module provides thread-safe mutexes.
+ */
+
+
+/**@brief Defines the storage size of a specified mutex group.
+ *
+ * @param number_of_mutexes the number of mutexes in the group.
+ */
+#define MUTEX_STORAGE_SIZE(number_of_mutexes) ((7 + (number_of_mutexes)) >> 3)
+
+
+/**@brief Initializes a mutex group.
+ *
+ * @param[in] p_mutex Pointer to the mutex group. See @ref MUTEX_STORAGE_SIZE().
+ * @param[in] mutex_size The size of the mutex group in number of mutexes.
+ */
+void pm_mutex_init(uint8_t * p_mutex, uint16_t mutex_size);
+
+
+/**@brief Locks the mutex specified by the bit id.
+ *
+ * @param[inout] p_mutex Pointer to the mutex group.
+ * @param[in] mutex_bit_id The bit id of the mutex.
+ *
+ * @retval true if it was possible to lock the mutex.
+ * @retval false otherwise.
+ */
+bool pm_mutex_lock(uint8_t * p_mutex, uint16_t mutex_bit_id);
+
+
+/**@brief Locks the first unlocked mutex within the mutex group.
+ *
+ * @param[in, out] p_mutex Pointer to the mutex group.
+ * @param[in] mutex_size The size of the mutex group.
+ *
+ * @return The first unlocked mutex id in the group.
+ * @retval group-size if there was no unlocked mutex available.
+ */
+uint16_t pm_mutex_lock_first_available(uint8_t * p_mutex, uint16_t mutex_size);
+
+
+/**@brief Unlocks the mutex specified by the bit id.
+ *
+ * @param[in, out] p_mutex Pointer to the mutex group.
+ * @param[in] mutex_bit_id The bit id of the mutex.
+ */
+void pm_mutex_unlock(uint8_t * p_mutex, uint16_t mutex_bit_id);
+
+
+/**@brief Gets the locking status of the specified mutex.
+ *
+ * @param[in, out] p_mutex Pointer to the mutex group.
+ * @param[in] mutex_bit_id The bit id of the mutex.
+ *
+ * @retval true if the mutex was locked.
+ * @retval false otherwise.
+ */
+bool pm_mutex_lock_status_get(uint8_t * p_mutex, uint16_t mutex_bit_id);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MUTEX_H__
+
+/** @}
+ * @endcond
+ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_dispatcher.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_dispatcher.c
new file mode 100644
index 0000000..462bd62
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_dispatcher.c
@@ -0,0 +1,1110 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "security_dispatcher.h"
+
+#include <string.h>
+#include "ble.h"
+#include "ble_gap.h"
+#include "ble_err.h"
+#include "ble_conn_state.h"
+#include "peer_manager_types.h"
+#include "peer_database.h"
+#include "id_manager.h"
+
+#ifndef PM_CENTRAL_ENABLED
+ #define PM_CENTRAL_ENABLED 1
+#endif
+
+// The number of registered event handlers.
+#define SMD_EVENT_HANDLERS_CNT (sizeof(m_evt_handlers) / sizeof(m_evt_handlers[0]))
+
+STATIC_ASSERT((NRF_SDH_BLE_CENTRAL_LINK_COUNT == 0) || PM_CENTRAL_ENABLED,
+ "Peer Manager Central operation must be enabled when using central links.");
+
+// Security Dispacher event handlers in Security Manager and GATT Cache Manager.
+extern void sm_smd_evt_handler(pm_evt_t * p_event);
+
+// Security Dispatcher events' handlers.
+// The number of elements in this array is SMD_EVENT_HANDLERS_CNT.
+static pm_evt_handler_internal_t const m_evt_handlers[] =
+{
+ sm_smd_evt_handler
+};
+
+static bool m_module_initialized;
+
+static ble_conn_state_user_flag_id_t m_flag_sec_proc = BLE_CONN_STATE_USER_FLAG_INVALID;
+static ble_conn_state_user_flag_id_t m_flag_sec_proc_pairing = BLE_CONN_STATE_USER_FLAG_INVALID;
+static ble_conn_state_user_flag_id_t m_flag_sec_proc_bonding = BLE_CONN_STATE_USER_FLAG_INVALID;
+static ble_conn_state_user_flag_id_t m_flag_sec_proc_new_peer = BLE_CONN_STATE_USER_FLAG_INVALID;
+static ble_conn_state_user_flag_id_t m_flag_allow_repairing = BLE_CONN_STATE_USER_FLAG_INVALID;
+
+static ble_gap_lesc_p256_pk_t m_peer_pk;
+
+
+static __INLINE bool sec_procedure(uint16_t conn_handle)
+{
+ return ble_conn_state_user_flag_get(conn_handle, m_flag_sec_proc);
+}
+
+static __INLINE bool pairing(uint16_t conn_handle)
+{
+ return ble_conn_state_user_flag_get(conn_handle, m_flag_sec_proc_pairing);
+}
+
+static __INLINE bool bonding(uint16_t conn_handle)
+{
+ return ble_conn_state_user_flag_get(conn_handle, m_flag_sec_proc_bonding);
+}
+
+static __INLINE bool peer_created(uint16_t conn_handle)
+{
+ return ble_conn_state_user_flag_get(conn_handle, m_flag_sec_proc_new_peer);
+}
+
+static __INLINE bool allow_repairing(uint16_t conn_handle)
+{
+ return ble_conn_state_user_flag_get(conn_handle, m_flag_allow_repairing);
+}
+
+
+/**@brief Function for sending an SMD event to all event handlers.
+ *
+ * @param[in] p_event The event to pass to all event handlers.
+ */
+static void evt_send(pm_evt_t * p_event)
+{
+ p_event->peer_id = im_peer_id_get_by_conn_handle(p_event->conn_handle);
+
+ for (uint32_t i = 0; i < SMD_EVENT_HANDLERS_CNT; i++)
+ {
+ m_evt_handlers[i](p_event);
+ }
+}
+
+
+/**@brief Function for sending a PM_EVT_CONN_SEC_START event.
+ *
+ * @param[in] conn_handle The connection handle the event pertains to.
+ * @param[in] procedure The procedure that has started on the connection.
+ */
+static void sec_start_send(uint16_t conn_handle,
+ pm_conn_sec_procedure_t procedure)
+{
+ pm_evt_t evt =
+ {
+ .evt_id = PM_EVT_CONN_SEC_START,
+ .conn_handle = conn_handle,
+ .params = {.conn_sec_start = {.procedure = procedure}}
+ };
+ evt_send(&evt);
+}
+
+
+/**@brief Function for sending a PM_EVT_ERROR_UNEXPECTED event.
+ *
+ * @param[in] conn_handle The connection handle the event pertains to.
+ * @param[in] err_code The unexpected error that occurred.
+ */
+static void send_unexpected_error(uint16_t conn_handle, ret_code_t err_code)
+{
+ pm_evt_t error_evt =
+ {
+ .evt_id = PM_EVT_ERROR_UNEXPECTED,
+ .conn_handle = conn_handle,
+ .params =
+ {
+ .error_unexpected =
+ {
+ .error = err_code,
+ }
+ }
+ };
+ evt_send(&error_evt);
+}
+
+
+/**@brief Function for cleaning up after a failed security procedure.
+ *
+ * @param[in] conn_handle The handle of the connection the security procedure happens on.
+ * @param[in] procedure The procedure that failed.
+ * @param[in] error The error the procedure failed with.
+ * @param[in] error_src The party that raised the error. See @ref BLE_GAP_SEC_STATUS_SOURCES.
+ */
+static void conn_sec_failure(uint16_t conn_handle,
+ pm_conn_sec_procedure_t procedure,
+ pm_sec_error_code_t error,
+ uint8_t error_src)
+{
+ pm_evt_t evt =
+ {
+ .evt_id = PM_EVT_CONN_SEC_FAILED,
+ .conn_handle = conn_handle,
+ .params =
+ {
+ .conn_sec_failed =
+ {
+ .procedure = procedure,
+ .error = error,
+ .error_src = error_src,
+ }
+ }
+ };
+
+ ble_conn_state_user_flag_set(conn_handle, m_flag_sec_proc, false);
+
+ evt_send(&evt);
+ return;
+}
+
+
+/**@brief Function for cleaning up after a failed pairing procedure.
+ *
+ * @param[in] conn_handle The handle of the connection the pairing procedure happens on.
+ * @param[in] error The error the procedure failed with.
+ * @param[in] error_src The source of the error (local or remote). See @ref
+ * BLE_GAP_SEC_STATUS_SOURCES.
+ */
+static void pairing_failure(uint16_t conn_handle,
+ pm_sec_error_code_t error,
+ uint8_t error_src)
+{
+ ret_code_t err_code = NRF_SUCCESS;
+ pm_peer_id_t peer_id = im_peer_id_get_by_conn_handle(conn_handle);
+ pm_conn_sec_procedure_t procedure = bonding(conn_handle) ? PM_CONN_SEC_PROCEDURE_BONDING
+ : PM_CONN_SEC_PROCEDURE_PAIRING;
+
+ if (peer_created(conn_handle))
+ {
+ // The peer_id was created during the procedure, and should be freed, because no data is
+ // stored under it.
+ err_code = im_peer_free(peer_id); // Attempt to free allocated peer.
+ UNUSED_VARIABLE(err_code);
+ }
+ else if(peer_id != PM_PEER_ID_INVALID)
+ {
+ err_code = pdb_write_buf_release(peer_id, PM_PEER_DATA_ID_BONDING);
+ if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_NOT_FOUND /* No buffer was allocated */))
+ {
+ send_unexpected_error(conn_handle, err_code);
+ }
+ }
+
+ conn_sec_failure(conn_handle, procedure, error, error_src);
+
+ return;
+}
+
+
+/**@brief Function for cleaning up after a failed encryption procedure.
+ *
+ * @param[in] conn_handle The handle of the connection the encryption procedure happens on.
+ * @param[in] error The error the procedure failed with.
+ * @param[in] error_src The party that raised the error. See @ref BLE_GAP_SEC_STATUS_SOURCES.
+ */
+static __INLINE void encryption_failure(uint16_t conn_handle,
+ pm_sec_error_code_t error,
+ uint8_t error_src)
+{
+ conn_sec_failure(conn_handle, PM_CONN_SEC_PROCEDURE_ENCRYPTION, error, error_src);
+
+ return;
+}
+
+
+/**@brief Function for possibly cleaning up after a failed pairing or encryption procedure.
+ *
+ * @param[in] conn_handle The handle of the connection the pairing procedure happens on.
+ * @param[in] error The error the procedure failed with.
+ * @param[in] error_src The party that raised the error. See @ref BLE_GAP_SEC_STATUS_SOURCES.
+ */
+static void link_secure_failure(uint16_t conn_handle,
+ pm_sec_error_code_t error,
+ uint8_t error_src)
+{
+ if (sec_procedure(conn_handle))
+ {
+ if (pairing(conn_handle))
+ {
+ pairing_failure(conn_handle, error, error_src);
+ }
+ else
+ {
+ encryption_failure(conn_handle, error, error_src);
+ }
+ }
+}
+
+
+/**@brief Function for administrative actions to be taken when a security process has started.
+ *
+ * @param[in] conn_handle The connection the security process was attempted on.
+ * @param[in] success Whether the procedure was started successfully.
+ * @param[in] procedure The procedure that was started.
+ */
+static void sec_proc_start(uint16_t conn_handle,
+ bool success,
+ pm_conn_sec_procedure_t procedure)
+{
+ ble_conn_state_user_flag_set(conn_handle, m_flag_sec_proc, success);
+ if (success)
+ {
+ ble_conn_state_user_flag_set(conn_handle,
+ m_flag_sec_proc_pairing,
+ (procedure != PM_CONN_SEC_PROCEDURE_ENCRYPTION));
+ ble_conn_state_user_flag_set(conn_handle,
+ m_flag_sec_proc_bonding,
+ (procedure == PM_CONN_SEC_PROCEDURE_BONDING));
+ ble_conn_state_user_flag_set(conn_handle, m_flag_sec_proc_new_peer, false);
+ sec_start_send(conn_handle, procedure);
+ }
+}
+
+
+
+/**@brief Function for administrative actions to be taken during the course of a security process.
+ *
+ * @param[in] conn_handle The connection the security process was attempted on.
+ * @param[in] peer_id The peer ID given to the connected peer.
+ * @param[in] success Whether the process was started successfully.
+ * @param[in] new_peer_created Whether a new peer was created during the process attempt.
+ */
+static void sec_proc_housekeeping(uint16_t conn_handle,
+ pm_peer_id_t peer_id,
+ bool success,
+ bool new_peer_created)
+{
+ if (success)
+ {
+ if (new_peer_created)
+ {
+ ble_conn_state_user_flag_set(conn_handle, m_flag_sec_proc_new_peer, true);
+ im_new_peer_id(conn_handle, peer_id);
+ }
+ }
+ else
+ {
+ if (new_peer_created)
+ {
+ ret_code_t err_code = im_peer_free(peer_id); // Attempt to free allocated peer.
+ UNUSED_VARIABLE(err_code);
+ }
+ }
+}
+
+
+
+/**@brief Function for processing the @ref BLE_GAP_EVT_SEC_INFO_REQUEST event from the SoftDevice.
+ *
+ * @param[in] p_gap_evt The event from the SoftDevice.
+ */
+static void sec_info_request_process(ble_gap_evt_t const * p_gap_evt)
+{
+ ret_code_t err_code;
+ ble_gap_enc_info_t const * p_enc_info = NULL;
+ pm_peer_data_flash_t peer_data;
+ pm_peer_id_t peer_id = im_peer_id_get_by_master_id(
+ &p_gap_evt->params.sec_info_request.master_id);
+
+ if (peer_id == PM_PEER_ID_INVALID)
+ {
+ peer_id = im_peer_id_get_by_conn_handle(p_gap_evt->conn_handle);
+ }
+ else
+ {
+ // The peer might have been unrecognized until now (since connecting). E.g. if using a
+ // random non-resolvable advertising address. Report the discovered peer ID just in case.
+ im_new_peer_id(p_gap_evt->conn_handle, peer_id);
+ }
+
+ sec_proc_start(p_gap_evt->conn_handle, true, PM_CONN_SEC_PROCEDURE_ENCRYPTION);
+
+ if (peer_id != PM_PEER_ID_INVALID)
+ {
+ err_code = pdb_peer_data_ptr_get(peer_id, PM_PEER_DATA_ID_BONDING, &peer_data);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // There is stored bonding data for this peer.
+ ble_gap_enc_key_t const * p_existing_key = &peer_data.p_bonding_data->own_ltk;
+
+ if ( p_existing_key->enc_info.lesc
+ || (im_master_ids_compare(&p_existing_key->master_id,
+ &p_gap_evt->params.sec_info_request.master_id)))
+ {
+ p_enc_info = &p_existing_key->enc_info;
+ }
+ }
+ }
+
+ err_code = sd_ble_gap_sec_info_reply(p_gap_evt->conn_handle, p_enc_info, NULL, NULL);
+
+ if (err_code != NRF_SUCCESS)
+ {
+ sec_proc_housekeeping(p_gap_evt->conn_handle, peer_id, false, false);
+ send_unexpected_error(p_gap_evt->conn_handle, err_code);
+ }
+ else if (p_enc_info == NULL)
+ {
+ sec_proc_housekeeping(p_gap_evt->conn_handle, peer_id, false, false);
+ encryption_failure(p_gap_evt->conn_handle,
+ PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING,
+ BLE_GAP_SEC_STATUS_SOURCE_LOCAL);
+ }
+
+ return;
+}
+
+
+/**@brief Function for sending a CONFIG_REQ event.
+ *
+ * @param[in] conn_handle The connection the sec parameters are needed for.
+ */
+static void send_config_req(uint16_t conn_handle)
+{
+ pm_evt_t evt;
+ memset(&evt, 0, sizeof(evt));
+
+ evt.evt_id = PM_EVT_CONN_SEC_CONFIG_REQ;
+ evt.conn_handle = conn_handle;
+
+ evt_send(&evt);
+}
+
+
+void smd_conn_sec_config_reply(uint16_t conn_handle, pm_conn_sec_config_t * p_conn_sec_config)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_conn_sec_config != NULL);
+
+ ble_conn_state_user_flag_set(conn_handle,
+ m_flag_allow_repairing,
+ p_conn_sec_config->allow_repairing);
+}
+
+
+/**@brief Function for processing the @ref BLE_GAP_EVT_DISCONNECT event from the SoftDevice.
+ *
+ * @param[in] p_gap_evt The event from the SoftDevice.
+ */
+static void disconnect_process(ble_gap_evt_t const * p_gap_evt)
+{
+ pm_sec_error_code_t error = (p_gap_evt->params.disconnected.reason
+ == BLE_HCI_CONN_TERMINATED_DUE_TO_MIC_FAILURE)
+ ? PM_CONN_SEC_ERROR_MIC_FAILURE : PM_CONN_SEC_ERROR_DISCONNECT;
+
+ link_secure_failure(p_gap_evt->conn_handle, error, BLE_GAP_SEC_STATUS_SOURCE_LOCAL);
+}
+
+
+/**@brief Function for sending a PARAMS_REQ event.
+ *
+ * @param[in] conn_handle The connection the security parameters are needed for.
+ * @param[in] p_peer_params The security parameters from the peer. Can be NULL if the peer's parameters
+ * are not yet available.
+ */
+static void send_params_req(uint16_t conn_handle, ble_gap_sec_params_t const * p_peer_params)
+{
+ pm_evt_t evt =
+ {
+ .evt_id = PM_EVT_CONN_SEC_PARAMS_REQ,
+ .conn_handle = conn_handle,
+ .params =
+ {
+ .conn_sec_params_req =
+ {
+ .p_peer_params = p_peer_params
+ },
+ },
+ };
+
+ evt_send(&evt);
+}
+
+
+/**@brief Function for processing the @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST event from the SoftDevice.
+ *
+ * @param[in] p_gap_evt The event from the SoftDevice.
+ */
+static void sec_params_request_process(ble_gap_evt_t const * p_gap_evt)
+{
+ if (ble_conn_state_role(p_gap_evt->conn_handle) == BLE_GAP_ROLE_PERIPH)
+ {
+ sec_proc_start(p_gap_evt->conn_handle,
+ true,
+ p_gap_evt->params.sec_params_request.peer_params.bond
+ ? PM_CONN_SEC_PROCEDURE_BONDING
+ : PM_CONN_SEC_PROCEDURE_PAIRING);
+ }
+
+ send_params_req(p_gap_evt->conn_handle, &p_gap_evt->params.sec_params_request.peer_params);
+ return;
+}
+
+
+/**@brief Function for processing the @ref BLE_GAP_EVT_AUTH_STATUS event from the SoftDevice, when
+ * the auth_status is success.
+ *
+ * @param[in] p_gap_evt The event from the SoftDevice.
+ */
+static void auth_status_success_process(ble_gap_evt_t const * p_gap_evt)
+{
+ ret_code_t err_code = NRF_SUCCESS;
+ uint16_t conn_handle = p_gap_evt->conn_handle;
+ pm_peer_id_t peer_id = im_peer_id_get_by_conn_handle(conn_handle);
+ pm_peer_id_t new_peer_id = peer_id;
+ pm_peer_data_t peer_data;
+ bool data_stored = false;
+
+ ble_conn_state_user_flag_set(conn_handle, m_flag_sec_proc, false);
+
+ if (p_gap_evt->params.auth_status.bonded)
+ {
+ pm_peer_id_t duplicate_peer_id = PM_PEER_ID_INVALID;
+ data_stored = true;
+
+ err_code = pdb_write_buf_get(peer_id, PM_PEER_DATA_ID_BONDING, 1, &peer_data);
+ if (err_code != NRF_SUCCESS)
+ {
+ send_unexpected_error(conn_handle, err_code);
+ data_stored = false;
+ }
+ else
+ {
+ duplicate_peer_id = im_find_duplicate_bonding_data(peer_data.p_bonding_data,
+ PM_PEER_ID_INVALID);
+ }
+
+ if (duplicate_peer_id != PM_PEER_ID_INVALID)
+ {
+ // The peer has been identified as someone we have already bonded with.
+ new_peer_id = duplicate_peer_id;
+ im_new_peer_id(conn_handle, new_peer_id);
+
+ // If the flag is true, the configuration has been requested before.
+ if (!allow_repairing(conn_handle))
+ {
+ send_config_req(conn_handle);
+ if (!allow_repairing(conn_handle))
+ {
+ data_stored = false;
+ }
+ }
+ }
+
+ if (data_stored)
+ {
+ err_code = pdb_write_buf_store(peer_id, PM_PEER_DATA_ID_BONDING, new_peer_id);
+ if (err_code != NRF_SUCCESS)
+ {
+ /* Unexpected */
+ send_unexpected_error(conn_handle, err_code);
+ data_stored = false;
+ }
+ }
+
+ if ((duplicate_peer_id != PM_PEER_ID_INVALID) && peer_created(conn_handle))
+ {
+ // We already have a bond with the peer. Now that the data has been stored for the
+ // existing peer, the peer created for this bonding procedure can be freed.
+ ret_code_t err_code_free = im_peer_free(peer_id);
+ UNUSED_VARIABLE(err_code_free); // Errors can be safely ignored.
+ }
+ }
+ else if (peer_created(conn_handle))
+ {
+ ret_code_t err_code_free = im_peer_free(peer_id);
+ UNUSED_VARIABLE(err_code_free); // Errors can be safely ignored.
+ }
+ else
+ {
+ // No action.
+ }
+
+ pm_evt_t pairing_success_evt;
+
+ pairing_success_evt.evt_id = PM_EVT_CONN_SEC_SUCCEEDED;
+ pairing_success_evt.conn_handle = conn_handle;
+ pairing_success_evt.params.conn_sec_succeeded.procedure = p_gap_evt->params.auth_status.bonded
+ ? PM_CONN_SEC_PROCEDURE_BONDING
+ : PM_CONN_SEC_PROCEDURE_PAIRING;
+ pairing_success_evt.params.conn_sec_succeeded.data_stored = data_stored;
+
+ evt_send(&pairing_success_evt);
+
+ return;
+}
+
+
+/**@brief Function for processing the @ref BLE_GAP_EVT_AUTH_STATUS event from the SoftDevice, when
+ * the auth_status is failure.
+ *
+ * @param[in] p_gap_evt The event from the SoftDevice.
+ */
+static void auth_status_failure_process(ble_gap_evt_t const * p_gap_evt)
+{
+ link_secure_failure(p_gap_evt->conn_handle,
+ p_gap_evt->params.auth_status.auth_status,
+ p_gap_evt->params.auth_status.error_src);
+}
+
+
+/**@brief Function for processing the @ref BLE_GAP_EVT_AUTH_STATUS event from the SoftDevice.
+ *
+ * @param[in] p_gap_evt The event from the SoftDevice.
+ */
+static void auth_status_process(ble_gap_evt_t const * p_gap_evt)
+{
+ switch (p_gap_evt->params.auth_status.auth_status)
+ {
+ case BLE_GAP_SEC_STATUS_SUCCESS:
+ auth_status_success_process(p_gap_evt);
+ break;
+
+ default:
+ auth_status_failure_process(p_gap_evt);
+ break;
+ }
+}
+
+
+/**@brief Function for processing the @ref BLE_GAP_EVT_CONN_SEC_UPDATE event from the SoftDevice.
+ *
+ * @param[in] p_gap_evt The event from the SoftDevice.
+ */
+static void conn_sec_update_process(ble_gap_evt_t const * p_gap_evt)
+{
+ if (!pairing(p_gap_evt->conn_handle))
+ {
+ // This is an encryption procedure (not pairing), so this event marks the end of the procedure.
+
+ if (!ble_conn_state_encrypted(p_gap_evt->conn_handle))
+ {
+ encryption_failure(p_gap_evt->conn_handle,
+ PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING,
+ BLE_GAP_SEC_STATUS_SOURCE_REMOTE);
+ }
+ else
+ {
+ ble_conn_state_user_flag_set(p_gap_evt->conn_handle, m_flag_sec_proc, false);
+
+ pm_evt_t evt;
+
+ evt.evt_id = PM_EVT_CONN_SEC_SUCCEEDED;
+ evt.conn_handle = p_gap_evt->conn_handle;
+ evt.params.conn_sec_succeeded.procedure = PM_CONN_SEC_PROCEDURE_ENCRYPTION;
+ evt.params.conn_sec_succeeded.data_stored = false;
+
+ evt_send(&evt);
+ }
+ }
+}
+
+
+/**@brief Funtion for initializing a BLE Connection State user flag.
+ *
+ * @param[out] flag_id The flag to initialize.
+ */
+static void flag_id_init(ble_conn_state_user_flag_id_t * p_flag_id)
+{
+ if (*p_flag_id == BLE_CONN_STATE_USER_FLAG_INVALID)
+ {
+ *p_flag_id = ble_conn_state_user_flag_acquire();
+ }
+}
+
+
+ret_code_t smd_init(void)
+{
+ NRF_PM_DEBUG_CHECK(!m_module_initialized);
+
+ flag_id_init(&m_flag_sec_proc);
+ flag_id_init(&m_flag_sec_proc_pairing);
+ flag_id_init(&m_flag_sec_proc_bonding);
+ flag_id_init(&m_flag_sec_proc_new_peer);
+ flag_id_init(&m_flag_allow_repairing);
+
+ if ((m_flag_sec_proc == BLE_CONN_STATE_USER_FLAG_INVALID) ||
+ (m_flag_sec_proc_pairing == BLE_CONN_STATE_USER_FLAG_INVALID) ||
+ (m_flag_sec_proc_bonding == BLE_CONN_STATE_USER_FLAG_INVALID) ||
+ (m_flag_sec_proc_new_peer == BLE_CONN_STATE_USER_FLAG_INVALID) ||
+ (m_flag_allow_repairing == BLE_CONN_STATE_USER_FLAG_INVALID))
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ m_module_initialized = true;
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for putting retrieving a buffer and putting pointers into a @ref ble_gap_sec_keyset_t.
+ *
+ * @param[in] conn_handle The connection the security procedure is happening on.
+ * @param[in] peer_id The peer the security procedure is happening with.
+ * @param[in] role Our role in the connection.
+ * @param[in] p_public_key Pointer to a buffer holding the public key, or NULL.
+ * @param[out] p_sec_keyset Pointer to the keyset to be filled.
+ *
+ * @retval NRF_SUCCESS Success.
+ * @retval NRF_ERROR_STORAGE_FULL Not enough room in persistent storage.
+ * @retval NRF_ERROR_BUSY Could not process request at this time. Reattempt later.
+ * @retval NRF_ERROR_INVALID_PARAM Data ID or Peer ID was invalid or unallocated.
+ * @retval NRF_ERROR_INTERNAL Fatal error.
+ */
+static ret_code_t sec_keyset_fill(uint16_t conn_handle,
+ pm_peer_id_t peer_id,
+ uint8_t role,
+ ble_gap_lesc_p256_pk_t * p_public_key,
+ ble_gap_sec_keyset_t * p_sec_keyset)
+{
+ ret_code_t err_code;
+ pm_peer_data_t peer_data;
+
+ if (p_sec_keyset == NULL)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ // Acquire a memory buffer to receive bonding data into.
+ err_code = pdb_write_buf_get(peer_id, PM_PEER_DATA_ID_BONDING, 1, &peer_data);
+
+ if (err_code == NRF_ERROR_BUSY)
+ {
+ // No action.
+ }
+ else if (err_code != NRF_SUCCESS)
+ {
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ else /* if (err_code == NRF_SUCCESS) */
+ {
+ memset(peer_data.p_bonding_data, 0, sizeof(pm_peer_data_bonding_t));
+
+ peer_data.p_bonding_data->own_role = role;
+
+ p_sec_keyset->keys_own.p_enc_key = &peer_data.p_bonding_data->own_ltk;
+ p_sec_keyset->keys_own.p_pk = p_public_key;
+ p_sec_keyset->keys_peer.p_enc_key = &peer_data.p_bonding_data->peer_ltk;
+ p_sec_keyset->keys_peer.p_id_key = &peer_data.p_bonding_data->peer_ble_id;
+ p_sec_keyset->keys_peer.p_pk = &m_peer_pk;
+
+ // Retrieve the address the peer used during connection establishment.
+ // This address will be overwritten if ID is shared. Should not fail.
+ err_code = im_ble_addr_get(conn_handle, &peer_data.p_bonding_data->peer_ble_id.id_addr_info);
+ if (err_code != NRF_SUCCESS)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ // Buffer is OK, reserve room in flash for the data.
+ err_code = pdb_write_buf_store_prepare(peer_id, PM_PEER_DATA_ID_BONDING);
+ if (err_code == NRF_ERROR_NOT_FOUND)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+ }
+
+ return err_code;
+}
+
+
+ret_code_t smd_params_reply(uint16_t conn_handle,
+ ble_gap_sec_params_t * p_sec_params,
+ ble_gap_lesc_p256_pk_t * p_public_key)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ uint8_t role = ble_conn_state_role(conn_handle);
+ pm_peer_id_t peer_id = PM_PEER_ID_INVALID;
+ ret_code_t err_code = NRF_SUCCESS;
+ uint8_t sec_status = BLE_GAP_SEC_STATUS_SUCCESS;
+ bool new_peer_created = peer_created(conn_handle);
+ ble_gap_sec_keyset_t sec_keyset;
+
+ memset(&sec_keyset, 0, sizeof(ble_gap_sec_keyset_t));
+ if (role == BLE_GAP_ROLE_PERIPH)
+ {
+ // Set the default value for allowing repairing at the start of the sec proc. (for peripheral)
+ ble_conn_state_user_flag_set(conn_handle, m_flag_allow_repairing, false);
+ }
+
+ if (role == BLE_GAP_ROLE_INVALID)
+ {
+ return BLE_ERROR_INVALID_CONN_HANDLE;
+ }
+
+ if (p_sec_params == NULL)
+ {
+ // NULL params means reject pairing.
+ sec_status = BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP;
+ }
+ else if (!p_sec_params->bond)
+ {
+ // Pairing, no bonding.
+
+ sec_keyset.keys_own.p_pk = p_public_key;
+ sec_keyset.keys_peer.p_pk = &m_peer_pk;
+ }
+ else
+ {
+ // Bonding is to be performed, prepare to receive bonding data.
+
+ peer_id = im_peer_id_get_by_conn_handle(conn_handle);
+
+ if (peer_id == PM_PEER_ID_INVALID)
+ {
+ // Peer is unknown to us, allocate a new peer ID for it.
+ peer_id = pdb_peer_allocate();
+ if (peer_id != PM_PEER_ID_INVALID)
+ {
+ new_peer_created = true;
+ }
+ else
+ {
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ }
+ else if (role == BLE_GAP_ROLE_PERIPH && !allow_repairing(conn_handle))
+ {
+ // Bond already exists. Reject the pairing request if the user doesn't intervene.
+ // send_config_req(conn_handle, peer_id);
+ send_config_req(conn_handle);
+ if (!allow_repairing(conn_handle))
+ {
+ // Reject pairing.
+ sec_status = BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP;
+ }
+ }
+
+ if ((sec_status != BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP) && (err_code == NRF_SUCCESS))
+ {
+ err_code = sec_keyset_fill(conn_handle, peer_id, role, p_public_key, &sec_keyset);
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Everything OK, reply to SoftDevice. If an error happened, the user is given an
+ // opportunity to change the parameters and retry the call.
+ if (role == BLE_GAP_ROLE_PERIPH)
+ {
+ err_code = sd_ble_gap_sec_params_reply(conn_handle, sec_status, p_sec_params, &sec_keyset);
+ }
+ else
+ {
+ err_code = sd_ble_gap_sec_params_reply(conn_handle, sec_status, NULL, &sec_keyset);
+ }
+ }
+
+ sec_proc_housekeeping(conn_handle,
+ peer_id,
+ (err_code == NRF_SUCCESS) && (sec_status == BLE_GAP_SEC_STATUS_SUCCESS),
+ new_peer_created);
+
+ return err_code;
+}
+
+
+#if PM_CENTRAL_ENABLED
+/**@brief Function for initiating encryption as a central. See @ref smd_link_secure for more info.
+ */
+static ret_code_t link_secure_central_encryption(uint16_t conn_handle,
+ pm_peer_id_t peer_id)
+{
+ pm_peer_data_flash_t peer_data;
+ ret_code_t err_code;
+ ble_gap_enc_key_t const * p_existing_key = NULL;
+ bool lesc = false;
+
+ err_code = pdb_peer_data_ptr_get(peer_id, PM_PEER_DATA_ID_BONDING, &peer_data);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // Use peer's key since they are peripheral.
+ p_existing_key = &(peer_data.p_bonding_data->peer_ltk);
+
+ lesc = peer_data.p_bonding_data->own_ltk.enc_info.lesc;
+ if (lesc) // LESC was used during bonding.
+ {
+ // For LESC, always use own key.
+ p_existing_key = &(peer_data.p_bonding_data->own_ltk);
+ }
+ }
+
+ if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_NOT_FOUND))
+ {
+ if (err_code != NRF_ERROR_BUSY)
+ {
+ // Unexpected error code.
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ }
+ else if (p_existing_key == NULL) /* There is no bonding data stored. This means that a bonding
+ procedure is in ongoing, or that the records in flash are
+ in a bad state. */
+ {
+ err_code = NRF_ERROR_BUSY;
+ }
+ else if (!lesc && !im_master_id_is_valid(&(p_existing_key->master_id))) /* There is no valid LTK stored. */
+ {
+ // No LTK to encrypt with.
+ err_code = NRF_ERROR_INVALID_DATA;
+ }
+ else
+ {
+ // Encrypt with existing LTK.
+ err_code = sd_ble_gap_encrypt(conn_handle,
+ &(p_existing_key->master_id),
+ &(p_existing_key->enc_info));
+ }
+
+ sec_proc_start(conn_handle, err_code == NRF_SUCCESS, PM_CONN_SEC_PROCEDURE_ENCRYPTION);
+ sec_proc_housekeeping(conn_handle, peer_id, (err_code == NRF_SUCCESS), false);
+
+ return err_code;
+}
+
+
+/**@brief Function for intiating pairing as a central. See @ref smd_link_secure for more info.
+ */
+static ret_code_t link_secure_central_pairing(uint16_t conn_handle,
+ pm_peer_id_t peer_id,
+ ble_gap_sec_params_t * p_sec_params)
+{
+ pm_conn_sec_procedure_t procedure = PM_CONN_SEC_PROCEDURE_PAIRING;
+ bool new_peer_created = false;
+ ret_code_t err_code = NRF_SUCCESS;
+ pm_peer_data_t dummy_peer_data;
+
+ if (p_sec_params == NULL)
+ {
+ err_code = sd_ble_gap_authenticate(conn_handle, NULL);
+ }
+ else
+ {
+ if (p_sec_params->bond)
+ {
+ procedure = PM_CONN_SEC_PROCEDURE_BONDING;
+
+ if (peer_id == PM_PEER_ID_INVALID)
+ {
+ // New peer is required.
+ peer_id = pdb_peer_allocate();
+ new_peer_created = true;
+ }
+
+ if (peer_id == PM_PEER_ID_INVALID)
+ {
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ else
+ {
+ err_code = pdb_write_buf_get(peer_id, PM_PEER_DATA_ID_BONDING, 1, &dummy_peer_data);
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = pdb_write_buf_store_prepare(peer_id, PM_PEER_DATA_ID_BONDING);
+ }
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = sd_ble_gap_authenticate(conn_handle, p_sec_params);
+ }
+
+ if (err_code != NRF_SUCCESS)
+ {
+ ret_code_t err_code_free = pdb_write_buf_release(peer_id, PM_PEER_DATA_ID_BONDING);
+ if ((err_code_free != NRF_SUCCESS) && (err_code_free != NRF_ERROR_NOT_FOUND))
+ {
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ }
+ }
+
+ if (err_code == NRF_ERROR_NO_MEM)
+ {
+ // sd_ble_gap_authenticate() returned NRF_ERROR_NO_MEM. Too many other sec procedures running.
+ err_code = NRF_ERROR_BUSY;
+ }
+
+ sec_proc_start(conn_handle, err_code == NRF_SUCCESS, procedure);
+ sec_proc_housekeeping(conn_handle, peer_id, (err_code == NRF_SUCCESS), new_peer_created);
+
+ return err_code;
+}
+
+
+
+/**@brief Function for intiating security as a central. See @ref smd_link_secure for more info.
+ */
+static ret_code_t link_secure_central(uint16_t conn_handle,
+ ble_gap_sec_params_t * p_sec_params,
+ bool force_repairing)
+{
+ ret_code_t err_code;
+ pm_peer_id_t peer_id;
+
+ if (p_sec_params == NULL)
+ {
+ return sd_ble_gap_authenticate(conn_handle, NULL);
+ }
+
+ // Set the default value for allowing repairing at the start of the sec proc. (for central)
+ ble_conn_state_user_flag_set(conn_handle, m_flag_allow_repairing, force_repairing);
+
+ peer_id = im_peer_id_get_by_conn_handle(conn_handle);
+
+ if ((peer_id != PM_PEER_ID_INVALID) && !force_repairing)
+ {
+ // There is already data in flash for this peer, and repairing has not been requested, so
+ // link will be encrypted with the existing keys.
+ err_code = link_secure_central_encryption(conn_handle, peer_id);
+ }
+ else
+ {
+ // There are no existing keys, or repairing has been explicitly requested, so pairing
+ // (possibly including bonding) will be performed to encrypt the link.
+ err_code = link_secure_central_pairing(conn_handle, peer_id, p_sec_params);
+ }
+
+ return err_code;
+}
+
+/**@brief Function for processing the @ref BLE_GAP_EVT_SEC_REQUEST event from the SoftDevice.
+ *
+ * @param[in] p_gap_evt The event from the SoftDevice.
+ */
+static void sec_request_process(ble_gap_evt_t const * p_gap_evt)
+{
+ pm_evt_t evt =
+ {
+ .evt_id = PM_EVT_SLAVE_SECURITY_REQ,
+ .conn_handle = p_gap_evt->conn_handle,
+ .params =
+ {
+ .slave_security_req =
+ {
+ .bond = p_gap_evt->params.sec_request.bond,
+ .mitm = p_gap_evt->params.sec_request.mitm,
+ }
+ }
+ };
+ evt_send(&evt);
+ return;
+}
+#endif // PM_CENTRAL_ENABLED
+
+
+/**@brief Function for asking the central to secure the link. See @ref smd_link_secure for more info.
+ */
+static ret_code_t link_secure_peripheral(uint16_t conn_handle, ble_gap_sec_params_t * p_sec_params)
+{
+ ret_code_t err_code = NRF_SUCCESS;
+
+ if (p_sec_params != NULL)
+ {
+ err_code = sd_ble_gap_authenticate(conn_handle, p_sec_params);
+ }
+
+ return err_code;
+}
+
+
+ret_code_t smd_link_secure(uint16_t conn_handle,
+ ble_gap_sec_params_t * p_sec_params,
+ bool force_repairing)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ uint8_t role = ble_conn_state_role(conn_handle);
+
+ switch (role)
+ {
+#if PM_CENTRAL_ENABLED
+ case BLE_GAP_ROLE_CENTRAL:
+ return link_secure_central(conn_handle, p_sec_params, force_repairing);
+#endif
+
+ case BLE_GAP_ROLE_PERIPH:
+ return link_secure_peripheral(conn_handle, p_sec_params);
+
+ default:
+ return BLE_ERROR_INVALID_CONN_HANDLE;
+ }
+}
+
+
+void smd_ble_evt_handler(ble_evt_t const * p_ble_evt)
+{
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_DISCONNECTED:
+ disconnect_process(&(p_ble_evt->evt.gap_evt));
+ break;
+
+ case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
+ sec_params_request_process(&(p_ble_evt->evt.gap_evt));
+ break;
+
+ case BLE_GAP_EVT_SEC_INFO_REQUEST:
+ sec_info_request_process(&(p_ble_evt->evt.gap_evt));
+ break;
+
+#if PM_CENTRAL_ENABLED
+ case BLE_GAP_EVT_SEC_REQUEST:
+ sec_request_process(&(p_ble_evt->evt.gap_evt));
+ break;
+#endif
+
+ case BLE_GAP_EVT_AUTH_STATUS:
+ auth_status_process(&(p_ble_evt->evt.gap_evt));
+ break;
+
+ case BLE_GAP_EVT_CONN_SEC_UPDATE:
+ conn_sec_update_process(&(p_ble_evt->evt.gap_evt));
+ break;
+ };
+}
+#endif //NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_dispatcher.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_dispatcher.h
new file mode 100644
index 0000000..0699276
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_dispatcher.h
@@ -0,0 +1,166 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef SECURITY_DISPATCHER_H__
+#define SECURITY_DISPATCHER_H__
+
+#include <stdint.h>
+#include "sdk_errors.h"
+#include "ble.h"
+#include "ble_gap.h"
+#include "peer_manager_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @cond NO_DOXYGEN
+ * @defgroup security_dispatcher Security Dispatcher
+ * @ingroup peer_manager
+ * @{
+ * @brief An internal module of @ref peer_manager. A module for streamlining pairing, bonding, and
+ * encryption, including flash storage of shared data.
+ *
+ */
+
+
+/**@brief Function for initializing the Security Dispatcher module.
+ *
+ * @retval NRF_SUCCESS Initialization was successful.
+ * @retval NRF_ERROR_INTERNAL An unexpected fatal error occurred.
+ */
+ret_code_t smd_init(void);
+
+
+/**@brief Function for dispatching SoftDevice events to the Security Dispatcher module.
+ *
+ * @param[in] ble_evt The SoftDevice event.
+ */
+void smd_ble_evt_handler(ble_evt_t const * ble_evt);
+
+
+/**@brief Function for providing security configuration for a link.
+ *
+ * @details This function is optional, and must be called in reply to a @ref
+ * PM_EVT_CONN_SEC_CONFIG_REQ event, before the Peer Manager event handler returns. If it
+ * is not called in time, a default configuration is used. See @ref pm_conn_sec_config_t
+ * for the value of the default.
+ *
+ * @param[in] conn_handle The connection to set the configuration for.
+ * @param[in] p_conn_sec_config The configuration.
+ */
+void smd_conn_sec_config_reply(uint16_t conn_handle, pm_conn_sec_config_t * p_conn_sec_config);
+
+
+/**@brief Function for providing pairing and bonding parameters to use for the current pairing
+ * procedure on a connection.
+ *
+ * @note If this function returns an @ref NRF_ERROR_NULL, @ref NRF_ERROR_INVALID_PARAM, @ref
+ * BLE_ERROR_INVALID_CONN_HANDLE, or @ref NRF_ERROR_STORAGE_FULL, this function can be called
+ * again after corrective action.
+ *
+ * @note To reject a request, call this function with NULL p_sec_params.
+ *
+ * @param[in] conn_handle The connection handle of the connection the pairing is happening on.
+ * @param[in] p_sec_params The security parameters to use for this link.
+ * @param[in] p_public_key A pointer to the public key to use if using LESC, or NULL.
+ *
+ * @retval NRF_SUCCESS Success.
+ * @retval NRF_ERROR_INVALID_STATE No parameters have been requested on that conn_handle, or
+ * the link is disconnecting.
+ * @retval NRF_ERROR_INVALID_PARAM Invalid combination of parameters (not including conn_handle).
+ * @retval NRF_ERROR_TIMEOUT There has been an SMP timeout, so no more SMP operations
+ * can be performed on this link.
+ * @retval BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle.
+ * @retval NRF_ERROR_STORAGE_FULL No more room in flash. Fix and reattempt after the next
+ * FDS garbage collection procedure.
+ * @retval NRF_ERROR_BUSY No write buffer. Reattempt later.
+ * @retval NRF_ERROR_INTERNAL A fatal error occurred.
+ */
+ret_code_t smd_params_reply(uint16_t conn_handle,
+ ble_gap_sec_params_t * p_sec_params,
+ ble_gap_lesc_p256_pk_t * p_public_key);
+
+
+/**@brief Function for initiating security on the link, with the specified parameters.
+ *
+ * @note If the connection is a peripheral connection, this will send a security request to the
+ * master, but the master is not obligated to initiate pairing or encryption in response.
+ * @note If the connection is a central connection and a key is available, the parameters will be
+ * used to determine whether to re-pair or to encrypt using the existing key. If no key is
+ * available, pairing will be started.
+ *
+ * @param[in] conn_handle Handle of the connection to initiate pairing on.
+ * @param[in] p_sec_params The security parameters to use for this link. As a central, this can
+ * be NULL to reject a slave security request.
+ * @param[in] force_repairing Whether to force a pairing procedure to happen regardless of whether
+ * an encryption key already exists. This argument is only relevant for
+ * the central role. Recommended value: false
+ *
+ * @retval NRF_SUCCESS Success.
+ * @retval NRF_ERROR_NULL p_sec_params was NULL (peripheral only).
+ * @retval NRF_ERROR_INVALID_STATE A security procedure is already in progress on the link,
+ * or the link is disconnecting.
+ * @retval NRF_ERROR_INVALID_PARAM Invalid combination of parameters (not including conn_handle).
+ * @retval NRF_ERROR_INVALID_DATA Peer is bonded, but no LTK was found, and repairing was
+ * not requested.
+ * @retval NRF_ERROR_BUSY Unable to initiate procedure at this time.
+ * @retval NRF_ERROR_TIMEOUT There has been an SMP timeout, so no more SMP operations
+ * can be performed on this link.
+ * @retval BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle.
+ * @retval NRF_ERROR_STORAGE_FULL No more room in flash. Fix and reattempt after the next
+ * FDS garbage collection procedure.
+ * @retval NRF_ERROR_INTERNAL No more available peer IDs.
+ */
+ret_code_t smd_link_secure(uint16_t conn_handle,
+ ble_gap_sec_params_t * p_sec_params,
+ bool force_repairing);
+
+/** @}
+ * @endcond
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SECURITY_DISPATCHER_H__ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_manager.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_manager.c
new file mode 100644
index 0000000..86da8a0
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_manager.c
@@ -0,0 +1,675 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(PEER_MANAGER)
+#include "security_manager.h"
+
+#include <string.h>
+#include "ble_err.h"
+#include "security_dispatcher.h"
+#include "peer_database.h"
+#include "ble_conn_state.h"
+#include "id_manager.h"
+#include "sdk_common.h"
+
+
+// The number of registered event handlers.
+#define SM_EVENT_HANDLERS_CNT (sizeof(m_evt_handlers) / sizeof(m_evt_handlers[0]))
+
+
+// Security Manager event handler in Peer Manager.
+extern void pm_sm_evt_handler(pm_evt_t * p_sm_evt);
+
+// Security Manager events' handlers.
+// The number of elements in this array is SM_EVENT_HANDLERS_CNT.
+static pm_evt_handler_internal_t const m_evt_handlers[] =
+{
+ pm_sm_evt_handler
+};
+
+
+// The context type that is used in PM_EVT_CONN_SEC_PARAMS_REQ events and in calls to sm_sec_params_reply().
+typedef struct
+{
+ ble_gap_sec_params_t * p_sec_params; //!< The security parameters to use in the call to the security_dispatcher
+ ble_gap_sec_params_t sec_params_mem; //!< The buffer for holding the security parameters.
+ bool params_reply_called; //!< Whether @ref sm_sec_params_reply has been called for this context instance.
+} sec_params_reply_context_t;
+
+static bool m_module_initialized; //!< Whether the Security Manager module has been initialized.
+
+static ble_gap_sec_params_t m_sec_params; //!< The buffer for the default security parameters set by @ref sm_sec_params_set.
+static ble_gap_sec_params_t * mp_sec_params = NULL; //!< The default security parameters set by @ref sm_sec_params_set.
+static bool m_sec_params_set = false; //!< Whether @ref sm_sec_params_set has been called.
+
+static ble_gap_lesc_p256_pk_t * m_p_public_key; //!< Pointer, provided by the user, to the public key to use for LESC procedures.
+
+static ble_conn_state_user_flag_id_t m_flag_link_secure_pending_busy = BLE_CONN_STATE_USER_FLAG_INVALID; //!< User flag indicating whether a connection has a pending call to @ref sm_link_secure because it returned @ref NRF_ERROR_BUSY.
+static ble_conn_state_user_flag_id_t m_flag_link_secure_pending_flash_full = BLE_CONN_STATE_USER_FLAG_INVALID; //!< User flag indicating whether a connection has a pending call to @ref sm_link_secure because it returned @ref NRF_ERROR_STORAGE_FULL.
+static ble_conn_state_user_flag_id_t m_flag_link_secure_force_repairing = BLE_CONN_STATE_USER_FLAG_INVALID; //!< User flag indicating whether a pending call to @ref sm_link_secure should be called with true for the force_repairing parameter.
+static ble_conn_state_user_flag_id_t m_flag_link_secure_null_params = BLE_CONN_STATE_USER_FLAG_INVALID; //!< User flag indicating whether a pending call to @ref sm_link_secure should be called with NULL security parameters.
+static ble_conn_state_user_flag_id_t m_flag_params_reply_pending_busy = BLE_CONN_STATE_USER_FLAG_INVALID; //!< User flag indicating whether a connection has a pending call to @ref sm_sec_params_reply because it returned @ref NRF_ERROR_BUSY.
+static ble_conn_state_user_flag_id_t m_flag_params_reply_pending_flash_full = BLE_CONN_STATE_USER_FLAG_INVALID; //!< User flag indicating whether a connection has a pending call to @ref sm_sec_params_reply because it returned @ref NRF_ERROR_STORAGE_FULL.
+
+
+/**@brief Function for sending an SM event to all registered event handlers.
+ *
+ * @param[in] p_event The event to send.
+ */
+static void evt_send(pm_evt_t * p_event)
+{
+ for (uint32_t i = 0; i < SM_EVENT_HANDLERS_CNT; i++)
+ {
+ m_evt_handlers[i](p_event);
+ }
+}
+
+
+/**@brief Function for setting or clearing user flags based on error codes returned from @ref
+ * smd_link_secure or @ref smd_params_reply.
+ *
+ * @param[in] conn_handle The connection the call pertained to.
+ * @param[in] err_code The error code returned from @ref smd_link_secure or
+ * @ref smd_params_reply.
+ * @param[in] params_reply Whether the call was to @ref smd_params_reply.
+ */
+static void flags_set_from_err_code(uint16_t conn_handle, ret_code_t err_code, bool params_reply)
+{
+ bool flag_value_flash_full = false;
+ bool flag_value_busy = false;
+
+ if ((err_code == NRF_ERROR_STORAGE_FULL))
+ {
+ flag_value_busy = false;
+ flag_value_flash_full = true;
+ }
+ else if (err_code == NRF_ERROR_BUSY)
+ {
+ flag_value_busy = true;
+ flag_value_flash_full = false;
+ }
+ else
+ {
+ flag_value_busy = false;
+ flag_value_flash_full = false;
+ }
+
+ if (params_reply)
+ {
+ ble_conn_state_user_flag_set(conn_handle,
+ m_flag_params_reply_pending_flash_full,
+ flag_value_flash_full);
+ ble_conn_state_user_flag_set(conn_handle,
+ m_flag_params_reply_pending_busy,
+ flag_value_busy);
+ ble_conn_state_user_flag_set(conn_handle,
+ m_flag_link_secure_pending_flash_full,
+ false);
+ ble_conn_state_user_flag_set(conn_handle,
+ m_flag_link_secure_pending_busy,
+ false);
+ }
+ else
+ {
+ ble_conn_state_user_flag_set(conn_handle,
+ m_flag_link_secure_pending_flash_full,
+ flag_value_flash_full);
+ ble_conn_state_user_flag_set(conn_handle,
+ m_flag_link_secure_pending_busy,
+ flag_value_busy);
+ }
+}
+
+
+/**@brief Function for sending an event based on error codes returned from @ref smd_link_secure or
+ * @ref smd_params_reply.
+ *
+ * @param[in] conn_handle The connection the event pertains to.
+ * @param[in] err_code The error code returned from @ref smd_link_secure or
+ * @ref smd_params_reply.
+ * @param[in] p_sec_params The security parameters attempted to pass in the call to
+ * @ref smd_link_secure or @ref smd_params_reply.
+ */
+static void events_send_from_err_code(uint16_t conn_handle,
+ ret_code_t err_code,
+ ble_gap_sec_params_t * p_sec_params)
+{
+ if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_BUSY) && (err_code != NRF_ERROR_INVALID_STATE))
+ {
+ pm_evt_t evt =
+ {
+ .conn_handle = conn_handle,
+ .peer_id = im_peer_id_get_by_conn_handle(conn_handle),
+ };
+ if (err_code == NRF_ERROR_TIMEOUT)
+ {
+ evt.evt_id = PM_EVT_CONN_SEC_FAILED;
+ evt.params.conn_sec_failed.procedure = ((p_sec_params != NULL) && p_sec_params->bond)
+ ? PM_CONN_SEC_PROCEDURE_BONDING
+ : PM_CONN_SEC_PROCEDURE_PAIRING;
+ evt.params.conn_sec_failed.error_src = BLE_GAP_SEC_STATUS_SOURCE_LOCAL;
+ evt.params.conn_sec_failed.error = PM_CONN_SEC_ERROR_SMP_TIMEOUT;
+ }
+ else if (err_code == NRF_ERROR_STORAGE_FULL)
+ {
+ evt.evt_id = PM_EVT_STORAGE_FULL;
+ }
+ else
+ {
+ evt.evt_id = PM_EVT_ERROR_UNEXPECTED;
+ evt.params.error_unexpected.error = err_code;
+ }
+ evt_send(&evt);
+ }
+}
+
+
+/**@brief Function for sending an PM_EVT_CONN_SEC_PARAMS_REQ event.
+ *
+ * @param[in] conn_handle The connection the event pertains to.
+ * @param[in] p_peer_params The peer's security parameters to include in the event. Can be NULL.
+ * @param[in] p_context Pointer to a context that the user must include in the call to @ref
+ * sm_sec_params_reply().
+ */
+static void params_req_send(uint16_t conn_handle,
+ ble_gap_sec_params_t const * p_peer_params,
+ sec_params_reply_context_t * p_context)
+{
+ pm_evt_t evt;
+ evt.evt_id = PM_EVT_CONN_SEC_PARAMS_REQ;
+ evt.conn_handle = conn_handle;
+ evt.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
+ evt.params.conn_sec_params_req.p_peer_params = p_peer_params;
+ evt.params.conn_sec_params_req.p_context = p_context;
+
+ evt_send(&evt);
+}
+
+
+/**@brief Function for creating a new @ref sec_params_reply_context_t with the correct initial values.
+ *
+ * @return The new context.
+ */
+static sec_params_reply_context_t new_context_get(void)
+{
+ sec_params_reply_context_t new_context =
+ {
+ .p_sec_params = mp_sec_params,
+ .params_reply_called = false
+ };
+ return new_context;
+}
+
+
+/**@brief Internal function corresponding to @ref sm_link_secure.
+ *
+ * @param[in] conn_handle The connection to secure.
+ * @param[in] null_params Whether to pass NULL security parameters to the security_dispatcher.
+ * @param[in] force_repairing Whether to force rebonding if peer exists.
+ * @param[in] send_events Whether to send events based on the result of @ref smd_link_secure.
+ *
+ * @return Same return codes as @ref sm_link_secure.
+ */
+static ret_code_t link_secure(uint16_t conn_handle,
+ bool null_params,
+ bool force_repairing,
+ bool send_events)
+{
+ ret_code_t err_code;
+ ret_code_t return_err_code;
+ ble_gap_sec_params_t * p_sec_params;
+
+ if (null_params)
+ {
+ p_sec_params = NULL;
+ }
+ else
+ {
+ sec_params_reply_context_t context = new_context_get();
+ params_req_send(conn_handle, NULL, &context);
+ p_sec_params = context.p_sec_params;
+
+ if (!m_sec_params_set && !context.params_reply_called)
+ {
+ // Security parameters have not been set.
+ return NRF_ERROR_NOT_FOUND;
+ }
+ }
+
+
+ err_code = smd_link_secure(conn_handle, p_sec_params, force_repairing);
+
+ flags_set_from_err_code(conn_handle, err_code, false);
+
+ switch (err_code)
+ {
+ case NRF_ERROR_BUSY:
+ ble_conn_state_user_flag_set(conn_handle, m_flag_link_secure_null_params, null_params);
+ ble_conn_state_user_flag_set(conn_handle, m_flag_link_secure_force_repairing, force_repairing);
+ return_err_code = NRF_SUCCESS;
+ break;
+ case NRF_ERROR_STORAGE_FULL:
+ ble_conn_state_user_flag_set(conn_handle, m_flag_link_secure_null_params, null_params);
+ ble_conn_state_user_flag_set(conn_handle, m_flag_link_secure_force_repairing, force_repairing);
+ /* fallthrough */
+ case NRF_SUCCESS:
+ case NRF_ERROR_TIMEOUT:
+ case BLE_ERROR_INVALID_CONN_HANDLE:
+ case NRF_ERROR_INVALID_STATE:
+ case NRF_ERROR_INVALID_DATA:
+ return_err_code = err_code;
+ break;
+ default:
+ return_err_code = NRF_ERROR_INTERNAL;
+ break;
+ }
+
+ if (send_events)
+ {
+ events_send_from_err_code(conn_handle, err_code, p_sec_params);
+ }
+
+ return return_err_code;
+}
+
+
+/**@brief Function for requesting security parameters from the user and passing them to the security_dispatcher.
+ *
+ * @param[in] conn_handle The connection that needs security parameters.
+ * @param[in] p_peer_params The peer's security parameters if present. Otherwise NULL.
+ */
+static void smd_params_reply_perform(uint16_t conn_handle, ble_gap_sec_params_t const * p_peer_params)
+{
+ ret_code_t err_code;
+ sec_params_reply_context_t context = new_context_get();
+
+ params_req_send(conn_handle, p_peer_params, &context);
+
+ err_code = smd_params_reply(conn_handle, context.p_sec_params, m_p_public_key);
+
+ flags_set_from_err_code(conn_handle, err_code, true);
+ events_send_from_err_code(conn_handle, err_code, context.p_sec_params);
+}
+
+
+/**@brief Function for handling @ref PM_EVT_CONN_SEC_PARAMS_REQ events.
+ *
+ * @param[in] p_event The @ref PM_EVT_CONN_SEC_PARAMS_REQ event.
+ */
+static __INLINE void params_req_process(pm_evt_t const * p_event)
+{
+ smd_params_reply_perform(p_event->conn_handle, p_event->params.conn_sec_params_req.p_peer_params);
+}
+
+
+/**@brief Function for handling @ref PM_EVT_SLAVE_SECURITY_REQ events.
+ *
+ * @param[in] p_event The @ref PM_EVT_SLAVE_SECURITY_REQ event.
+ */
+static void sec_req_process(pm_evt_t const * p_event)
+{
+ bool null_params = false;
+ if (mp_sec_params == NULL)
+ {
+ null_params = true;
+ }
+ else if ((bool)m_sec_params.bond < (bool)p_event->params.slave_security_req.bond)
+ {
+ null_params = true;
+ }
+ else if ((bool)m_sec_params.mitm < (bool)p_event->params.slave_security_req.mitm)
+ {
+ null_params = true;
+ }
+ else
+ {
+ // No action.
+ }
+ ret_code_t err_code = link_secure(p_event->conn_handle, null_params, false, true);
+ UNUSED_VARIABLE(err_code); // It is acceptable to ignore the return code because it is
+ // acceptable to ignore a security request.
+}
+
+
+/**@brief Function for translating an SMD event to an SM event and passing it on to SM event handlers.
+ *
+ * @param[in] p_event The event to forward.
+ */
+static void evt_forward(pm_evt_t * p_event)
+{
+ evt_send(p_event);
+}
+
+
+/**@brief Event handler for events from the Security Dispatcher module.
+ * This handler is extern in Security Dispatcher.
+ *
+ * @param[in] p_event The event that has happened.
+ */
+void sm_smd_evt_handler(pm_evt_t * p_event)
+{
+ switch (p_event->evt_id)
+ {
+ case PM_EVT_CONN_SEC_PARAMS_REQ:
+ params_req_process(p_event);
+ break;
+ case PM_EVT_SLAVE_SECURITY_REQ:
+ sec_req_process(p_event);
+ /* fallthrough */
+ default:
+ // Forward the event to all registered Security Manager event handlers.
+ evt_forward(p_event);
+ break;
+ }
+}
+
+
+/**@brief Function handling a pending params_reply. See @ref ble_conn_state_user_function_t.
+ */
+static void params_reply_pending_handle(uint16_t conn_handle, void * p_context)
+{
+ UNUSED_PARAMETER(p_context);
+ smd_params_reply_perform(conn_handle, NULL);
+}
+
+
+/**@brief Function handling a pending link_secure. See @ref ble_conn_state_user_function_t.
+ */
+static void link_secure_pending_handle(uint16_t conn_handle, void * p_context)
+{
+ UNUSED_PARAMETER(p_context);
+
+ bool force_repairing = ble_conn_state_user_flag_get(conn_handle, m_flag_link_secure_force_repairing);
+ bool null_params = ble_conn_state_user_flag_get(conn_handle, m_flag_link_secure_null_params);
+
+ // If this fails, it will be automatically retried.
+ ret_code_t err_code = link_secure(conn_handle, null_params, force_repairing, true);
+ UNUSED_VARIABLE(err_code);
+}
+
+
+/**@brief Event handler for events from the Peer Database module.
+ * This handler is extern in Peer Database.
+ *
+ * @param[in] p_event The event that has happened.
+ */
+void sm_pdb_evt_handler(pm_evt_t * p_event)
+{
+ switch (p_event->evt_id)
+ {
+ case PM_EVT_FLASH_GARBAGE_COLLECTED:
+ (void) ble_conn_state_for_each_set_user_flag(m_flag_params_reply_pending_flash_full,
+ params_reply_pending_handle,
+ NULL);
+ (void) ble_conn_state_for_each_set_user_flag(m_flag_link_secure_pending_flash_full,
+ link_secure_pending_handle,
+ NULL);
+ /* fallthrough */
+ case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
+ case PM_EVT_PEER_DATA_UPDATE_FAILED:
+ case PM_EVT_PEER_DELETE_SUCCEEDED:
+ case PM_EVT_PEER_DELETE_FAILED:
+ (void) ble_conn_state_for_each_set_user_flag(m_flag_params_reply_pending_busy,
+ params_reply_pending_handle,
+ NULL);
+ (void) ble_conn_state_for_each_set_user_flag(m_flag_link_secure_pending_busy,
+ link_secure_pending_handle,
+ NULL);
+ break;
+ default:
+ // Do nothing.
+ break;
+ }
+}
+
+
+/**@brief Funtion for initializing a BLE Connection State user flag.
+ *
+ * @param[out] flag_id The flag to initialize.
+ */
+static void flag_id_init(ble_conn_state_user_flag_id_t * p_flag_id)
+{
+ if (*p_flag_id == BLE_CONN_STATE_USER_FLAG_INVALID)
+ {
+ *p_flag_id = ble_conn_state_user_flag_acquire();
+ }
+}
+
+
+ret_code_t sm_init(void)
+{
+ NRF_PM_DEBUG_CHECK(!m_module_initialized);
+
+ flag_id_init(&m_flag_link_secure_pending_busy);
+ flag_id_init(&m_flag_link_secure_pending_flash_full);
+ flag_id_init(&m_flag_link_secure_force_repairing);
+ flag_id_init(&m_flag_link_secure_null_params);
+ flag_id_init(&m_flag_params_reply_pending_busy);
+ flag_id_init(&m_flag_params_reply_pending_flash_full);
+
+ if (m_flag_params_reply_pending_flash_full == BLE_CONN_STATE_USER_FLAG_INVALID)
+ {
+ return NRF_ERROR_INTERNAL;
+ }
+
+ m_module_initialized = true;
+
+ return NRF_SUCCESS;
+}
+
+
+void sm_ble_evt_handler(ble_evt_t const * p_ble_evt)
+{
+ NRF_PM_DEBUG_CHECK(p_ble_evt != NULL);
+
+ smd_ble_evt_handler(p_ble_evt);
+ (void) ble_conn_state_for_each_set_user_flag(m_flag_link_secure_pending_busy,
+ link_secure_pending_handle,
+ NULL);
+}
+
+
+/**@brief Funtion for checking whether security parameters are valid.
+ *
+ * @param[out] p_sec_params The security parameters to verify.
+ *
+ * @return Whether the security parameters are valid.
+ */
+static bool sec_params_verify(ble_gap_sec_params_t * p_sec_params)
+{
+ // NULL check.
+ if (p_sec_params == NULL)
+ {
+ return false;
+ }
+
+ // OOB not allowed unless MITM.
+ if (!p_sec_params->mitm && p_sec_params->oob)
+ {
+ return false;
+ }
+
+ // IO Capabilities must be one of the valid values from @ref BLE_GAP_IO_CAPS.
+ if (p_sec_params->io_caps > BLE_GAP_IO_CAPS_KEYBOARD_DISPLAY)
+ {
+ return false;
+ }
+
+ // Must have either IO capabilities or OOB if MITM.
+ if (p_sec_params->mitm && (p_sec_params->io_caps == BLE_GAP_IO_CAPS_NONE) && !p_sec_params->oob)
+ {
+ return false;
+ }
+
+ // Minimum key size cannot be larger than maximum key size.
+ if (p_sec_params->min_key_size > p_sec_params->max_key_size)
+ {
+ return false;
+ }
+
+ // Key size cannot be below 7 bytes.
+ if (p_sec_params->min_key_size < 7)
+ {
+ return false;
+ }
+
+ // Key size cannot be above 16 bytes.
+ if (p_sec_params->max_key_size > 16)
+ {
+ return false;
+ }
+
+ // Signing is not supported.
+ if (p_sec_params->kdist_own.sign || p_sec_params->kdist_peer.sign)
+ {
+ return false;
+ }
+
+ // link bit must be 0.
+ if (p_sec_params->kdist_own.link || p_sec_params->kdist_peer.link)
+ {
+ return false;
+ }
+
+ // If bonding is not enabled, no keys can be distributed.
+ if (!p_sec_params->bond && ( p_sec_params->kdist_own.enc
+ || p_sec_params->kdist_own.id
+ || p_sec_params->kdist_peer.enc
+ || p_sec_params->kdist_peer.id))
+ {
+ return false;
+ }
+
+ // If bonding is enabled, one or more keys must be distributed.
+ if ( p_sec_params->bond
+ && !p_sec_params->kdist_own.enc
+ && !p_sec_params->kdist_own.id
+ && !p_sec_params->kdist_peer.enc
+ && !p_sec_params->kdist_peer.id)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+
+ret_code_t sm_sec_params_set(ble_gap_sec_params_t * p_sec_params)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ if (p_sec_params == NULL)
+ {
+ mp_sec_params = NULL;
+ m_sec_params_set = true;
+ return NRF_SUCCESS;
+ }
+ else if (sec_params_verify(p_sec_params))
+ {
+ m_sec_params = *p_sec_params;
+ mp_sec_params = &m_sec_params;
+ m_sec_params_set = true;
+ return NRF_SUCCESS;
+ }
+ else
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+}
+
+
+void sm_conn_sec_config_reply(uint16_t conn_handle, pm_conn_sec_config_t * p_conn_sec_config)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ NRF_PM_DEBUG_CHECK(p_conn_sec_config != NULL);
+
+ smd_conn_sec_config_reply(conn_handle, p_conn_sec_config);
+}
+
+
+ret_code_t sm_sec_params_reply(uint16_t conn_handle,
+ ble_gap_sec_params_t * p_sec_params,
+ void const * p_context)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+ VERIFY_PARAM_NOT_NULL(p_context);
+
+ sec_params_reply_context_t * p_sec_params_reply_context = (sec_params_reply_context_t *)p_context;
+ if (p_sec_params == NULL)
+ {
+ // Set the store pointer to NULL, so that NULL is passed to the SoftDevice.
+ p_sec_params_reply_context->p_sec_params = NULL;
+ }
+ else if (sec_params_verify(p_sec_params))
+ {
+ // Copy the provided sec_params into the store.
+ p_sec_params_reply_context->sec_params_mem = *p_sec_params;
+ p_sec_params_reply_context->p_sec_params = &p_sec_params_reply_context->sec_params_mem;
+ }
+ else
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ p_sec_params_reply_context->params_reply_called = true;
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t sm_lesc_public_key_set(ble_gap_lesc_p256_pk_t * p_public_key)
+{
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ m_p_public_key = p_public_key;
+
+ return NRF_SUCCESS;
+}
+
+
+ret_code_t sm_link_secure(uint16_t conn_handle, bool force_repairing)
+{
+ ret_code_t ret;
+
+ NRF_PM_DEBUG_CHECK(m_module_initialized);
+
+ ret = link_secure(conn_handle, false, force_repairing, false);
+ return ret;
+}
+#endif // NRF_MODULE_ENABLED(PEER_MANAGER)
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_manager.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_manager.h
new file mode 100644
index 0000000..a91c15d
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/ble/peer_manager/security_manager.h
@@ -0,0 +1,181 @@
+/**
+ * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef SECURITY_MANAGER_H__
+#define SECURITY_MANAGER_H__
+
+#include <stdint.h>
+#include "sdk_errors.h"
+#include "ble.h"
+#include "ble_gap.h"
+#include "peer_manager_types.h"
+#include "security_dispatcher.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @cond NO_DOXYGEN
+ * @defgroup security_manager Security Manager
+ * @ingroup peer_manager
+ * @{
+ * @brief An internal module of @ref peer_manager. A module for streamlining pairing, bonding, and
+ * encryption, including flash storage of shared data.
+ */
+
+
+/**@brief Function for initializing the Security Manager module.
+ *
+ * @retval NRF_SUCCESS If initialization was successful.
+ * @retval NRF_ERROR_INTERNAL If an unexpected error occurred.
+ */
+ret_code_t sm_init(void);
+
+
+/**@brief Function for dispatching SoftDevice events to the Security Manager module.
+ *
+ * @param[in] ble_evt The SoftDevice event.
+ */
+void sm_ble_evt_handler(ble_evt_t const * ble_evt);
+
+
+/**@brief Function for providing pairing and bonding parameters to use for pairing procedures.
+ *
+ * @details Until this is called, all bonding procedures initiated by the peer will be rejected.
+ * This function can be called multiple times, even with NULL p_sec_params, in which case
+ * it will go back to rejecting all procedures.
+ *
+ * @param[in] p_sec_params The security parameters to use for this link. Can be NULL to reject
+ * all pairing procedures.
+ *
+ * @retval NRF_SUCCESS Success.
+ * @retval NRF_ERROR_INVALID_PARAM Invalid combination of parameters.
+ */
+ret_code_t sm_sec_params_set(ble_gap_sec_params_t * p_sec_params);
+
+
+/**@brief Function for providing security configuration for a link.
+ *
+ * @details This function is optional, and must be called in reply to a @ref
+ * PM_EVT_CONN_SEC_CONFIG_REQ event, before the Peer Manager event handler returns. If it
+ * is not called in time, a default configuration is used. See @ref pm_conn_sec_config_t
+ * for the value of the default.
+ *
+ * @param[in] conn_handle The connection to set the configuration for.
+ * @param[in] p_conn_sec_config The configuration.
+ */
+void sm_conn_sec_config_reply(uint16_t conn_handle, pm_conn_sec_config_t * p_conn_sec_config);
+
+
+/**@brief Function for providing security parameters for a link.
+ *
+ * @details This function is optional, and must be called in reply to a @ref
+ * PM_EVT_CONN_SEC_PARAMS_REQ event, before the Security Manager event handler returns. If
+ * it is not called in time, the parameters given in @ref sm_sec_params_set are used. See
+ * @ref pm_conn_sec_config_t for the value of the default.
+ *
+ * @param[in] conn_handle The connection to set the parameters for.
+ * @param[in] p_sec_params The parameters. If NULL, the security procedure is rejected.
+ * @param[in] p_context The context found in the request event that this function replies to.
+ *
+ * @retval NRF_SUCCESS Successful reply.
+ * @retval NRF_ERROR_NULL p_context was null.
+ * @retval NRF_ERROR_INVALID_PARAM Value of p_sec_params was invalid.
+ * @retval NRF_ERROR_INVALID_STATE This module is not initialized.
+ */
+ret_code_t sm_sec_params_reply(uint16_t conn_handle,
+ ble_gap_sec_params_t * p_sec_params,
+ void const * p_context);
+
+
+/**@brief Experimental function for specifying the public key to use for LESC operations.
+ *
+ * @details This function can be called multiple times. The specified public key will be used for
+ * all subsequent LESC (LE Secure Connections) operations until the next time this function
+ * is called.
+ *
+ * @note The key must continue to reside in application memory as it is not copied by Peer Manager.
+ *
+ * @param[in] p_public_key The public key to use for all subsequent LESC operations.
+ *
+ * @retval NRF_SUCCESS Pairing initiated successfully.
+ * @retval NRF_ERROR_INVALID_STATE This module is not initialized.
+ */
+ret_code_t sm_lesc_public_key_set(ble_gap_lesc_p256_pk_t * p_public_key);
+
+
+
+/**@brief Function for initiating security on the link, with the specified parameters.
+ *
+ * @note If the connection is a peripheral connection, this will send a security request to the
+ * master, but the master is not obligated to initiate pairing or encryption in response.
+ * @note If the connection is a central connection and a key is available, the parameters will be
+ * used to determine whether to re-pair or to encrypt using the existing key. If no key is
+ * available, pairing will be started.
+ *
+ * @param[in] conn_handle Handle of the connection to initiate pairing on.
+ * @param[in] force_repairing Whether to force a pairing procedure to happen regardless of whether
+ * an encryption key already exists. This argument is only relevant for
+ * the central role. Recommended value: false
+ *
+ * @retval NRF_SUCCESS Success.
+ * @retval NRF_ERROR_TIMEOUT There has been an SMP timeout, so no more SMP operations
+ * can be performed on this link.
+ * @retval BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle.
+ * @retval NRF_ERROR_INVALID_DATA Peer is bonded, but no LTK was found, and repairing was
+ * not requested.
+ * @retval NRF_ERROR_NOT_FOUND Security parameters have not been set.
+ * @retval NRF_ERROR_INVALID_STATE A security procedure is already in progress on the link,
+ * or the link is disconnecting.
+ * @retval NRF_ERROR_INTERNAL An unexpected error occurred.
+ */
+ret_code_t sm_link_secure(uint16_t conn_handle, bool force_repairing);
+
+/** @}
+ * @endcond
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SECURITY_MANAGER_H__ */