changed low freq. clock source to IRC
Dependencies: BLE_API mbed nRF51822_IRC
Fork of BLE_ANCS_SDAPI by
main.cpp@2:6d0f581488b6, 2014-07-06 (annotated)
- Committer:
- ytsuboi
- Date:
- Sun Jul 06 13:10:16 2014 +0000
- Revision:
- 2:6d0f581488b6
- Parent:
- 1:f0edc06f2d29
changed low freq. clock source to IRC
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
devsar | 0:1f985a7c0a8b | 1 | #include <stdbool.h> |
devsar | 0:1f985a7c0a8b | 2 | #include <stdint.h> |
devsar | 0:1f985a7c0a8b | 3 | #include <string.h> |
devsar | 0:1f985a7c0a8b | 4 | |
devsar | 0:1f985a7c0a8b | 5 | #include "mbed.h" |
devsar | 0:1f985a7c0a8b | 6 | #include "nRF51822n.h" |
devsar | 0:1f985a7c0a8b | 7 | |
devsar | 0:1f985a7c0a8b | 8 | #include "nordic_common.h" |
devsar | 0:1f985a7c0a8b | 9 | //#include "nrf.h" |
devsar | 0:1f985a7c0a8b | 10 | #include "app_error.h" |
devsar | 0:1f985a7c0a8b | 11 | #include "ble_hci.h" |
devsar | 0:1f985a7c0a8b | 12 | #include "ble_gap.h" |
devsar | 0:1f985a7c0a8b | 13 | #include "ble_advdata.h" |
devsar | 0:1f985a7c0a8b | 14 | #include "ble_error_log.h" |
devsar | 0:1f985a7c0a8b | 15 | #include "nrf_gpio.h" |
devsar | 0:1f985a7c0a8b | 16 | #include "ble_srv_common.h" |
devsar | 0:1f985a7c0a8b | 17 | #include "ble_conn_params.h" |
devsar | 0:1f985a7c0a8b | 18 | #include "nrf51_bitfields.h" |
devsar | 0:1f985a7c0a8b | 19 | #include "ble_bondmngr.h" |
devsar | 0:1f985a7c0a8b | 20 | #include "app_timer.h" |
devsar | 0:1f985a7c0a8b | 21 | #include "ble_radio_notification.h" |
devsar | 0:1f985a7c0a8b | 22 | #include "ble_flash.h" |
devsar | 0:1f985a7c0a8b | 23 | #include "ble_debug_assert_handler.h" |
devsar | 0:1f985a7c0a8b | 24 | #include "pstorage.h" |
devsar | 0:1f985a7c0a8b | 25 | #include "nrf_soc.h" |
devsar | 0:1f985a7c0a8b | 26 | #include "softdevice_handler.h" |
devsar | 0:1f985a7c0a8b | 27 | |
devsar | 0:1f985a7c0a8b | 28 | #include "debug.h" |
devsar | 0:1f985a7c0a8b | 29 | |
devsar | 0:1f985a7c0a8b | 30 | |
devsar | 0:1f985a7c0a8b | 31 | #define DEVICE_NAME "ANCC" /**< Name of device. Will be included in the advertising data. */ |
devsar | 0:1f985a7c0a8b | 32 | #define APP_ADV_INTERVAL 40 /**< The advertising interval (in units of 0.625 ms. This value corresponds to 25 ms). */ |
devsar | 0:1f985a7c0a8b | 33 | #define APP_ADV_INTERVAL_SLOW 3200 /**< Slow advertising interval (in units of 0.625 ms. This value corresponds to 2 seconds). */ |
devsar | 0:1f985a7c0a8b | 34 | #define APP_ADV_TIMEOUT_IN_SECONDS 180 /**< The advertising timeout in units of seconds. */ |
devsar | 0:1f985a7c0a8b | 35 | #define ADV_INTERVAL_FAST_PERIOD 30 /**< The duration of the fast advertising period (in seconds). */ |
devsar | 0:1f985a7c0a8b | 36 | |
devsar | 0:1f985a7c0a8b | 37 | #define APP_TIMER_PRESCALER 0 /**< Value of the RTC1 PRESCALER register. */ |
devsar | 0:1f985a7c0a8b | 38 | #define APP_TIMER_MAX_TIMERS 2 /**< Maximum number of simultaneously created timers. */ |
devsar | 0:1f985a7c0a8b | 39 | #define APP_TIMER_OP_QUEUE_SIZE 4 /**< Size of timer operation queues. */ |
devsar | 0:1f985a7c0a8b | 40 | |
devsar | 0:1f985a7c0a8b | 41 | #define MIN_CONN_INTERVAL MSEC_TO_UNITS(500, UNIT_1_25_MS) /**< Minimum acceptable connection interval (0.5 seconds). */ |
devsar | 0:1f985a7c0a8b | 42 | #define MAX_CONN_INTERVAL MSEC_TO_UNITS(1000, UNIT_1_25_MS) /**< Maximum acceptable connection interval (1 second). */ |
devsar | 0:1f985a7c0a8b | 43 | #define SLAVE_LATENCY 0 /**< Slave latency. */ |
devsar | 0:1f985a7c0a8b | 44 | #define CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) /**< Connection supervisory timeout (4 seconds). */ |
devsar | 0:1f985a7c0a8b | 45 | |
devsar | 0:1f985a7c0a8b | 46 | #define FIRST_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(20 * 1000, APP_TIMER_PRESCALER) /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (20 seconds). */ |
devsar | 0:1f985a7c0a8b | 47 | #define NEXT_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(5 * 1000, APP_TIMER_PRESCALER) /**< Time between each call to sd_ble_gap_conn_param_update after the first (5 seconds). */ |
devsar | 0:1f985a7c0a8b | 48 | #define MAX_CONN_PARAMS_UPDATE_COUNT 3 /**< Number of attempts before giving up the connection parameter negotiation. */ |
devsar | 0:1f985a7c0a8b | 49 | |
devsar | 0:1f985a7c0a8b | 50 | |
devsar | 0:1f985a7c0a8b | 51 | #define SEC_PARAM_TIMEOUT 30 /**< Timeout for Pairing Request or Security Request (in seconds). */ |
devsar | 0:1f985a7c0a8b | 52 | #define SEC_PARAM_BOND 0 /**< Perform bonding. */ |
devsar | 0:1f985a7c0a8b | 53 | #define SEC_PARAM_MITM 0 /**< Man In The Middle protection not required. */ |
devsar | 0:1f985a7c0a8b | 54 | #define SEC_PARAM_IO_CAPABILITIES BLE_GAP_IO_CAPS_NONE /**< No I/O capabilities. */ |
devsar | 0:1f985a7c0a8b | 55 | #define SEC_PARAM_OOB 0 /**< Out Of Band data not available. */ |
devsar | 0:1f985a7c0a8b | 56 | #define SEC_PARAM_MIN_KEY_SIZE 7 /**< Minimum encryption key size. */ |
devsar | 0:1f985a7c0a8b | 57 | #define SEC_PARAM_MAX_KEY_SIZE 16 /**< Maximum encryption key size. */ |
devsar | 0:1f985a7c0a8b | 58 | |
devsar | 0:1f985a7c0a8b | 59 | #define BLE_UUID_APPLE_NOTIFICATION_CENTER_SERVICE 0xf431 /*<< ANCS service UUID. */ |
devsar | 0:1f985a7c0a8b | 60 | #define BLE_UUID_ANCS_CONTROL_POINT_CHAR 0xd8f3 /*<< Control point UUID. */ |
devsar | 0:1f985a7c0a8b | 61 | #define BLE_UUID_ANCS_NOTIFICATION_SOURCE_CHAR 0x120d /*<< Notification source UUID. */ |
devsar | 0:1f985a7c0a8b | 62 | #define BLE_UUID_ANCS_DATA_SOURCE_CHAR 0xc6e9 /*<< Data source UUID. */ |
devsar | 0:1f985a7c0a8b | 63 | |
devsar | 0:1f985a7c0a8b | 64 | #define BLE_CCCD_NOTIFY_BIT_MASK 0x0001 /**< Enable Notification bit. */ |
devsar | 0:1f985a7c0a8b | 65 | |
devsar | 0:1f985a7c0a8b | 66 | |
devsar | 0:1f985a7c0a8b | 67 | typedef enum |
devsar | 0:1f985a7c0a8b | 68 | { |
devsar | 0:1f985a7c0a8b | 69 | BLE_NO_ADVERTISING, /**< No advertising running. */ |
devsar | 0:1f985a7c0a8b | 70 | BLE_SLOW_ADVERTISING, /**< Slow advertising running. */ |
devsar | 0:1f985a7c0a8b | 71 | BLE_FAST_ADVERTISING /**< Fast advertising running. */ |
devsar | 0:1f985a7c0a8b | 72 | } ble_advertising_mode_t; |
devsar | 0:1f985a7c0a8b | 73 | |
devsar | 0:1f985a7c0a8b | 74 | typedef enum |
devsar | 0:1f985a7c0a8b | 75 | { |
devsar | 0:1f985a7c0a8b | 76 | STATE_UNINITIALIZED, // Program start. |
devsar | 0:1f985a7c0a8b | 77 | STATE_ADVERTISING, // Advertising. See Settings>Bluetooth on iPhone then connect to "ANCC" |
devsar | 0:1f985a7c0a8b | 78 | STATE_CONNECTED, // iPhone connected to us. |
devsar | 0:1f985a7c0a8b | 79 | STATE_DISCOVERY_SERVICE, // Searching for ANCS Service. |
devsar | 0:1f985a7c0a8b | 80 | STATE_DISCOVERY_CHARACTERISTICS, // Searching for ANCS Characteristics. |
devsar | 0:1f985a7c0a8b | 81 | STATE_PAIRING, // Got all we need. Now pair before subscribe. Should see pairing dialog on iPhone |
devsar | 0:1f985a7c0a8b | 82 | STATE_SUBSCRIBING, // Subscribe to CCC, for notification. |
devsar | 0:1f985a7c0a8b | 83 | STATE_LISTENING, // Listening... |
devsar | 0:1f985a7c0a8b | 84 | STATE_NOTIFIED, // Got notification, now retrieve other info and print log out. back to listening. |
devsar | 0:1f985a7c0a8b | 85 | STATE_DISCONNECTED, // Disconnected? |
devsar | 0:1f985a7c0a8b | 86 | STATE_ERROR |
devsar | 0:1f985a7c0a8b | 87 | } state_t; |
devsar | 0:1f985a7c0a8b | 88 | |
devsar | 0:1f985a7c0a8b | 89 | |
devsar | 0:1f985a7c0a8b | 90 | |
devsar | 0:1f985a7c0a8b | 91 | DigitalOut led_adv(LED1); |
devsar | 0:1f985a7c0a8b | 92 | DigitalOut led_conn(LED2); |
devsar | 0:1f985a7c0a8b | 93 | |
devsar | 0:1f985a7c0a8b | 94 | Serial pc(USBTX, USBRX); |
devsar | 0:1f985a7c0a8b | 95 | |
devsar | 0:1f985a7c0a8b | 96 | const ble_uuid128_t ble_ancs_base_uuid128 = |
devsar | 0:1f985a7c0a8b | 97 | { |
devsar | 0:1f985a7c0a8b | 98 | { |
devsar | 0:1f985a7c0a8b | 99 | // 7905F431-B5CE-4E99-A40F-4B1E122D00D0 |
devsar | 0:1f985a7c0a8b | 100 | 0xd0, 0x00, 0x2d, 0x12, 0x1e, 0x4b, 0x0f, 0xa4, |
devsar | 0:1f985a7c0a8b | 101 | 0x99, 0x4e, 0xce, 0xb5, 0x31, 0xf4, 0x05, 0x79 |
devsar | 0:1f985a7c0a8b | 102 | } |
devsar | 0:1f985a7c0a8b | 103 | }; |
devsar | 0:1f985a7c0a8b | 104 | |
devsar | 0:1f985a7c0a8b | 105 | |
devsar | 0:1f985a7c0a8b | 106 | const ble_uuid128_t ble_ancs_cp_base_uuid128 = |
devsar | 0:1f985a7c0a8b | 107 | { |
devsar | 0:1f985a7c0a8b | 108 | { |
devsar | 0:1f985a7c0a8b | 109 | // 69d1d8f3-45e1-49a8-9821-9bbdfdaad9d9 |
devsar | 0:1f985a7c0a8b | 110 | 0xd9, 0xd9, 0xaa, 0xfd, 0xbd, 0x9b, 0x21, 0x98, |
devsar | 0:1f985a7c0a8b | 111 | 0xa8, 0x49, 0xe1, 0x45, 0xf3, 0xd8, 0xd1, 0x69 |
devsar | 0:1f985a7c0a8b | 112 | |
devsar | 0:1f985a7c0a8b | 113 | } |
devsar | 0:1f985a7c0a8b | 114 | }; |
devsar | 0:1f985a7c0a8b | 115 | |
devsar | 0:1f985a7c0a8b | 116 | const ble_uuid128_t ble_ancs_ns_base_uuid128 = |
devsar | 0:1f985a7c0a8b | 117 | { |
devsar | 0:1f985a7c0a8b | 118 | { |
devsar | 0:1f985a7c0a8b | 119 | // 9FBF120D-6301-42D9-8C58-25E699A21DBD |
devsar | 0:1f985a7c0a8b | 120 | 0xbd, 0x1d, 0xa2, 0x99, 0xe6, 0x25, 0x58, 0x8c, |
devsar | 0:1f985a7c0a8b | 121 | 0xd9, 0x42, 0x01, 0x63, 0x0d, 0x12, 0xbf, 0x9f |
devsar | 0:1f985a7c0a8b | 122 | |
devsar | 0:1f985a7c0a8b | 123 | } |
devsar | 0:1f985a7c0a8b | 124 | }; |
devsar | 0:1f985a7c0a8b | 125 | |
devsar | 0:1f985a7c0a8b | 126 | const ble_uuid128_t ble_ancs_ds_base_uuid128 = |
devsar | 0:1f985a7c0a8b | 127 | { |
devsar | 0:1f985a7c0a8b | 128 | { |
devsar | 0:1f985a7c0a8b | 129 | // 22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB |
devsar | 0:1f985a7c0a8b | 130 | 0xfb, 0x7b, 0x7c, 0xce, 0x6a, 0xb3, 0x44, 0xbe, |
devsar | 0:1f985a7c0a8b | 131 | 0xb5, 0x4b, 0xd6, 0x24, 0xe9, 0xc6, 0xea, 0x22 |
devsar | 0:1f985a7c0a8b | 132 | |
devsar | 0:1f985a7c0a8b | 133 | } |
devsar | 0:1f985a7c0a8b | 134 | }; |
devsar | 0:1f985a7c0a8b | 135 | |
devsar | 0:1f985a7c0a8b | 136 | static state_t m_state = STATE_UNINITIALIZED; |
devsar | 0:1f985a7c0a8b | 137 | |
devsar | 0:1f985a7c0a8b | 138 | static ble_gap_adv_params_t m_adv_params; /**< Parameters to be passed to the stack when starting advertising. */ |
devsar | 0:1f985a7c0a8b | 139 | static ble_advertising_mode_t m_advertising_mode; /**< Variable to keep track of when we are advertising. */ |
devsar | 0:1f985a7c0a8b | 140 | |
devsar | 0:1f985a7c0a8b | 141 | static ble_gap_sec_params_t m_sec_params; /**< Security requirements for this application. */ |
devsar | 0:1f985a7c0a8b | 142 | |
devsar | 0:1f985a7c0a8b | 143 | // ANCS Characteristic... |
devsar | 0:1f985a7c0a8b | 144 | static uint16_t m_notification_source_handle = 0; |
devsar | 0:1f985a7c0a8b | 145 | static uint16_t m_notification_source_handle_cccd = 0; |
devsar | 0:1f985a7c0a8b | 146 | static uint16_t m_control_point_handle = 0; |
devsar | 0:1f985a7c0a8b | 147 | static uint16_t m_data_source_handle = 0; |
devsar | 0:1f985a7c0a8b | 148 | static uint16_t m_data_source_handle_cccd = 0; |
devsar | 0:1f985a7c0a8b | 149 | |
devsar | 0:1f985a7c0a8b | 150 | static void err_check(uint32_t error_code, char *method) |
devsar | 0:1f985a7c0a8b | 151 | { |
devsar | 0:1f985a7c0a8b | 152 | if(error_code != NRF_SUCCESS) { |
devsar | 0:1f985a7c0a8b | 153 | pc.printf("ERROR: %d (%s) on %s\r\n", error_code, error2string(error_code), method); |
devsar | 0:1f985a7c0a8b | 154 | // } else { |
devsar | 0:1f985a7c0a8b | 155 | // pc.printf("SUCCESS: %s\r\n", method); |
devsar | 0:1f985a7c0a8b | 156 | } |
devsar | 0:1f985a7c0a8b | 157 | APP_ERROR_CHECK(error_code); |
devsar | 0:1f985a7c0a8b | 158 | } |
devsar | 0:1f985a7c0a8b | 159 | |
devsar | 0:1f985a7c0a8b | 160 | |
devsar | 0:1f985a7c0a8b | 161 | static void advertising_start(void) |
devsar | 0:1f985a7c0a8b | 162 | { |
devsar | 0:1f985a7c0a8b | 163 | uint32_t err_code; |
devsar | 0:1f985a7c0a8b | 164 | |
devsar | 0:1f985a7c0a8b | 165 | if (m_advertising_mode == BLE_NO_ADVERTISING) |
devsar | 0:1f985a7c0a8b | 166 | { |
devsar | 0:1f985a7c0a8b | 167 | m_advertising_mode = BLE_FAST_ADVERTISING; |
devsar | 0:1f985a7c0a8b | 168 | } |
devsar | 0:1f985a7c0a8b | 169 | else |
devsar | 0:1f985a7c0a8b | 170 | { |
devsar | 0:1f985a7c0a8b | 171 | m_advertising_mode = BLE_SLOW_ADVERTISING; |
devsar | 0:1f985a7c0a8b | 172 | } |
devsar | 0:1f985a7c0a8b | 173 | |
devsar | 0:1f985a7c0a8b | 174 | memset(&m_adv_params, 0, sizeof(m_adv_params)); |
devsar | 0:1f985a7c0a8b | 175 | |
devsar | 0:1f985a7c0a8b | 176 | m_adv_params.type = BLE_GAP_ADV_TYPE_ADV_IND; |
devsar | 0:1f985a7c0a8b | 177 | m_adv_params.p_peer_addr = NULL; // Undirected advertisement. |
devsar | 0:1f985a7c0a8b | 178 | m_adv_params.fp = BLE_GAP_ADV_FP_ANY; |
devsar | 0:1f985a7c0a8b | 179 | |
devsar | 0:1f985a7c0a8b | 180 | if (m_advertising_mode == BLE_FAST_ADVERTISING) |
devsar | 0:1f985a7c0a8b | 181 | { |
devsar | 0:1f985a7c0a8b | 182 | m_adv_params.interval = APP_ADV_INTERVAL; |
devsar | 0:1f985a7c0a8b | 183 | m_adv_params.timeout = ADV_INTERVAL_FAST_PERIOD; |
devsar | 0:1f985a7c0a8b | 184 | } |
devsar | 0:1f985a7c0a8b | 185 | else |
devsar | 0:1f985a7c0a8b | 186 | { |
devsar | 0:1f985a7c0a8b | 187 | m_adv_params.interval = APP_ADV_INTERVAL_SLOW; |
devsar | 0:1f985a7c0a8b | 188 | m_adv_params.timeout = APP_ADV_TIMEOUT_IN_SECONDS; |
devsar | 0:1f985a7c0a8b | 189 | } |
devsar | 0:1f985a7c0a8b | 190 | |
devsar | 0:1f985a7c0a8b | 191 | err_code = sd_ble_gap_adv_start(&m_adv_params); |
devsar | 0:1f985a7c0a8b | 192 | err_check(err_code, "sd_ble_gap_adv_start"); |
devsar | 0:1f985a7c0a8b | 193 | |
devsar | 0:1f985a7c0a8b | 194 | led_adv = 1; |
devsar | 0:1f985a7c0a8b | 195 | m_state = STATE_ADVERTISING; |
devsar | 0:1f985a7c0a8b | 196 | } |
devsar | 0:1f985a7c0a8b | 197 | |
devsar | 0:1f985a7c0a8b | 198 | |
devsar | 0:1f985a7c0a8b | 199 | |
devsar | 0:1f985a7c0a8b | 200 | |
devsar | 0:1f985a7c0a8b | 201 | static void ble_event_handler(ble_evt_t * p_ble_evt) |
devsar | 0:1f985a7c0a8b | 202 | { |
devsar | 0:1f985a7c0a8b | 203 | uint32_t err_code = NRF_SUCCESS; |
devsar | 0:1f985a7c0a8b | 204 | static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID; |
devsar | 0:1f985a7c0a8b | 205 | ble_uuid_t ancs_uuid; |
devsar | 0:1f985a7c0a8b | 206 | static ble_gattc_handle_range_t handle_range; |
devsar | 0:1f985a7c0a8b | 207 | |
devsar | 0:1f985a7c0a8b | 208 | pc.printf("Event: %s\r\n", event2string(p_ble_evt)); |
devsar | 0:1f985a7c0a8b | 209 | // ble_bondmngr_on_ble_evt(p_ble_evt); |
devsar | 0:1f985a7c0a8b | 210 | // ble_conn_params_on_ble_evt(p_ble_evt); |
devsar | 0:1f985a7c0a8b | 211 | |
devsar | 0:1f985a7c0a8b | 212 | switch (p_ble_evt->header.evt_id) |
devsar | 0:1f985a7c0a8b | 213 | { |
devsar | 0:1f985a7c0a8b | 214 | case BLE_GAP_EVT_CONNECTED: |
devsar | 0:1f985a7c0a8b | 215 | { |
devsar | 0:1f985a7c0a8b | 216 | m_state = STATE_CONNECTED; |
devsar | 0:1f985a7c0a8b | 217 | |
devsar | 0:1f985a7c0a8b | 218 | m_advertising_mode = BLE_NO_ADVERTISING; |
devsar | 0:1f985a7c0a8b | 219 | m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle; |
devsar | 0:1f985a7c0a8b | 220 | led_conn = 1; |
devsar | 0:1f985a7c0a8b | 221 | |
devsar | 0:1f985a7c0a8b | 222 | m_state = STATE_DISCOVERY_SERVICE; |
devsar | 0:1f985a7c0a8b | 223 | |
devsar | 0:1f985a7c0a8b | 224 | BLE_UUID_BLE_ASSIGN(ancs_uuid, BLE_UUID_APPLE_NOTIFICATION_CENTER_SERVICE); |
devsar | 0:1f985a7c0a8b | 225 | ancs_uuid.type = BLE_UUID_TYPE_VENDOR_BEGIN; |
devsar | 0:1f985a7c0a8b | 226 | |
devsar | 0:1f985a7c0a8b | 227 | err_code = sd_ble_gattc_primary_services_discover(m_conn_handle, 0x0001, &ancs_uuid); |
devsar | 0:1f985a7c0a8b | 228 | err_check(err_code, "sd_ble_gattc_primary_services_discover"); |
devsar | 0:1f985a7c0a8b | 229 | |
devsar | 0:1f985a7c0a8b | 230 | |
devsar | 0:1f985a7c0a8b | 231 | break; |
devsar | 0:1f985a7c0a8b | 232 | } |
devsar | 0:1f985a7c0a8b | 233 | case BLE_GAP_EVT_AUTH_STATUS: |
devsar | 0:1f985a7c0a8b | 234 | { |
devsar | 0:1f985a7c0a8b | 235 | m_state = STATE_SUBSCRIBING; |
devsar | 0:1f985a7c0a8b | 236 | |
devsar | 0:1f985a7c0a8b | 237 | // Subscribe to NS |
devsar | 0:1f985a7c0a8b | 238 | uint16_t cccd_val = true ? BLE_CCCD_NOTIFY_BIT_MASK : 0; |
devsar | 0:1f985a7c0a8b | 239 | static ble_gattc_write_params_t m_write_params; |
devsar | 0:1f985a7c0a8b | 240 | uint8_t gattc_value[2]; |
devsar | 0:1f985a7c0a8b | 241 | |
devsar | 0:1f985a7c0a8b | 242 | gattc_value[0] = LSB(cccd_val); |
devsar | 0:1f985a7c0a8b | 243 | gattc_value[1] = MSB(cccd_val); |
devsar | 0:1f985a7c0a8b | 244 | |
devsar | 0:1f985a7c0a8b | 245 | m_write_params.handle = m_notification_source_handle_cccd; |
devsar | 0:1f985a7c0a8b | 246 | m_write_params.len = 2; |
devsar | 0:1f985a7c0a8b | 247 | m_write_params.p_value = &gattc_value[0]; |
devsar | 0:1f985a7c0a8b | 248 | m_write_params.offset = 0; |
devsar | 0:1f985a7c0a8b | 249 | m_write_params.write_op = BLE_GATT_OP_WRITE_REQ; |
devsar | 0:1f985a7c0a8b | 250 | |
devsar | 0:1f985a7c0a8b | 251 | |
devsar | 0:1f985a7c0a8b | 252 | err_code = sd_ble_gattc_write(m_conn_handle, &m_write_params); |
devsar | 0:1f985a7c0a8b | 253 | err_check(err_code, "sd_ble_gattc_write"); |
devsar | 0:1f985a7c0a8b | 254 | |
devsar | 0:1f985a7c0a8b | 255 | break; |
devsar | 0:1f985a7c0a8b | 256 | } |
devsar | 0:1f985a7c0a8b | 257 | case BLE_GAP_EVT_DISCONNECTED: |
devsar | 0:1f985a7c0a8b | 258 | { |
devsar | 0:1f985a7c0a8b | 259 | m_conn_handle = BLE_CONN_HANDLE_INVALID; |
devsar | 0:1f985a7c0a8b | 260 | |
devsar | 0:1f985a7c0a8b | 261 | advertising_start(); |
devsar | 0:1f985a7c0a8b | 262 | led_conn = 0; |
devsar | 0:1f985a7c0a8b | 263 | break; |
devsar | 0:1f985a7c0a8b | 264 | } |
devsar | 0:1f985a7c0a8b | 265 | case BLE_GAP_EVT_SEC_PARAMS_REQUEST: |
devsar | 0:1f985a7c0a8b | 266 | { |
devsar | 0:1f985a7c0a8b | 267 | err_code = sd_ble_gap_sec_params_reply(m_conn_handle, |
devsar | 0:1f985a7c0a8b | 268 | BLE_GAP_SEC_STATUS_SUCCESS, |
devsar | 0:1f985a7c0a8b | 269 | &m_sec_params); |
devsar | 0:1f985a7c0a8b | 270 | err_check(err_code, "sd_ble_gap_sec_params_reply"); |
devsar | 0:1f985a7c0a8b | 271 | break; |
devsar | 0:1f985a7c0a8b | 272 | } |
devsar | 0:1f985a7c0a8b | 273 | case BLE_GAP_EVT_TIMEOUT: |
devsar | 0:1f985a7c0a8b | 274 | { |
devsar | 0:1f985a7c0a8b | 275 | if (p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_ADVERTISEMENT) |
devsar | 0:1f985a7c0a8b | 276 | { |
devsar | 0:1f985a7c0a8b | 277 | if (m_advertising_mode == BLE_FAST_ADVERTISING) |
devsar | 0:1f985a7c0a8b | 278 | { |
devsar | 0:1f985a7c0a8b | 279 | advertising_start(); |
devsar | 0:1f985a7c0a8b | 280 | } |
devsar | 0:1f985a7c0a8b | 281 | else |
devsar | 0:1f985a7c0a8b | 282 | { |
devsar | 0:1f985a7c0a8b | 283 | err_code = sd_power_system_off(); |
devsar | 0:1f985a7c0a8b | 284 | } |
devsar | 0:1f985a7c0a8b | 285 | } |
devsar | 0:1f985a7c0a8b | 286 | break; |
devsar | 0:1f985a7c0a8b | 287 | } |
devsar | 0:1f985a7c0a8b | 288 | case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP: |
devsar | 0:1f985a7c0a8b | 289 | { |
devsar | 0:1f985a7c0a8b | 290 | if (p_ble_evt->evt.gattc_evt.gatt_status != BLE_GATT_STATUS_SUCCESS) { |
devsar | 0:1f985a7c0a8b | 291 | // Error. |
devsar | 0:1f985a7c0a8b | 292 | pc.printf("Error: %s\r\n", "BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP"); |
devsar | 0:1f985a7c0a8b | 293 | } else { |
devsar | 0:1f985a7c0a8b | 294 | if (p_ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp.count > 0) { |
devsar | 0:1f985a7c0a8b | 295 | const ble_gattc_service_t * p_service; |
devsar | 0:1f985a7c0a8b | 296 | |
devsar | 0:1f985a7c0a8b | 297 | p_service = &(p_ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp.services[0]); |
devsar | 0:1f985a7c0a8b | 298 | |
devsar | 0:1f985a7c0a8b | 299 | pc.printf("Found ANCS service, start handle: %d, end handle: %d\r\n", |
devsar | 0:1f985a7c0a8b | 300 | p_service->handle_range.start_handle, p_service->handle_range.end_handle); |
devsar | 0:1f985a7c0a8b | 301 | |
devsar | 0:1f985a7c0a8b | 302 | handle_range.start_handle = p_service->handle_range.start_handle; |
devsar | 0:1f985a7c0a8b | 303 | handle_range.end_handle = p_service->handle_range.end_handle; |
devsar | 0:1f985a7c0a8b | 304 | |
devsar | 0:1f985a7c0a8b | 305 | err_code = sd_ble_gattc_characteristics_discover(m_conn_handle, &handle_range); |
devsar | 0:1f985a7c0a8b | 306 | err_check(err_code, "sd_ble_gattc_characteristics_discover"); |
devsar | 0:1f985a7c0a8b | 307 | |
devsar | 0:1f985a7c0a8b | 308 | m_state = STATE_DISCOVERY_CHARACTERISTICS; |
devsar | 0:1f985a7c0a8b | 309 | |
devsar | 0:1f985a7c0a8b | 310 | } else { |
devsar | 0:1f985a7c0a8b | 311 | pc.printf("Error: discovery failure, no ANCS\r\n"); |
devsar | 0:1f985a7c0a8b | 312 | } |
devsar | 0:1f985a7c0a8b | 313 | } |
devsar | 0:1f985a7c0a8b | 314 | |
devsar | 0:1f985a7c0a8b | 315 | break; |
devsar | 0:1f985a7c0a8b | 316 | } |
devsar | 0:1f985a7c0a8b | 317 | case BLE_GATTC_EVT_CHAR_DISC_RSP: |
devsar | 0:1f985a7c0a8b | 318 | { |
devsar | 0:1f985a7c0a8b | 319 | // End of characteristics searching...no more attribute or no more handle. |
devsar | 0:1f985a7c0a8b | 320 | // We got error as response, but this is normal for gatt attribute searching. |
devsar | 0:1f985a7c0a8b | 321 | if (p_ble_evt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND || |
devsar | 0:1f985a7c0a8b | 322 | p_ble_evt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_ATTERR_INVALID_HANDLE) { |
devsar | 0:1f985a7c0a8b | 323 | |
devsar | 0:1f985a7c0a8b | 324 | if(m_notification_source_handle == 0) { |
devsar | 0:1f985a7c0a8b | 325 | pc.printf("Error: NS not found.\r\n"); |
devsar | 0:1f985a7c0a8b | 326 | } else if(m_control_point_handle == 0) { |
devsar | 0:1f985a7c0a8b | 327 | pc.printf("Error: CP not found.\r\n"); |
devsar | 0:1f985a7c0a8b | 328 | } else if(m_data_source_handle == 0) { |
devsar | 0:1f985a7c0a8b | 329 | pc.printf("Error: DS not found.\r\n"); |
devsar | 0:1f985a7c0a8b | 330 | } |
devsar | 0:1f985a7c0a8b | 331 | // OK, we got all char handles. Next, find CCC. |
devsar | 0:1f985a7c0a8b | 332 | else { |
devsar | 0:1f985a7c0a8b | 333 | // Start with NS CCC |
devsar | 0:1f985a7c0a8b | 334 | handle_range.start_handle = m_notification_source_handle + 1; |
devsar | 0:1f985a7c0a8b | 335 | handle_range.end_handle = m_notification_source_handle + 1; |
devsar | 0:1f985a7c0a8b | 336 | |
devsar | 0:1f985a7c0a8b | 337 | err_code = sd_ble_gattc_descriptors_discover(m_conn_handle, &handle_range); |
devsar | 0:1f985a7c0a8b | 338 | err_check(err_code, "sd_ble_gattc_descriptors_discover"); |
devsar | 0:1f985a7c0a8b | 339 | } |
devsar | 0:1f985a7c0a8b | 340 | |
devsar | 0:1f985a7c0a8b | 341 | } else if (p_ble_evt->evt.gattc_evt.gatt_status != BLE_GATT_STATUS_SUCCESS) { |
devsar | 0:1f985a7c0a8b | 342 | pc.printf("Error: %s\r\n", "BLE_GATTC_EVT_CHAR_DISC_RSP"); |
devsar | 0:1f985a7c0a8b | 343 | } else { |
devsar | 0:1f985a7c0a8b | 344 | uint32_t i; |
devsar | 0:1f985a7c0a8b | 345 | const ble_gattc_char_t * p_char_resp = NULL; |
devsar | 0:1f985a7c0a8b | 346 | |
devsar | 0:1f985a7c0a8b | 347 | // Iterate trough the characteristics and find the correct one. |
devsar | 0:1f985a7c0a8b | 348 | for (i = 0; i < p_ble_evt->evt.gattc_evt.params.char_disc_rsp.count; i++) { |
devsar | 0:1f985a7c0a8b | 349 | p_char_resp = &(p_ble_evt->evt.gattc_evt.params.char_disc_rsp.chars[i]); |
devsar | 0:1f985a7c0a8b | 350 | switch (p_char_resp->uuid.uuid) { |
devsar | 0:1f985a7c0a8b | 351 | case BLE_UUID_ANCS_CONTROL_POINT_CHAR: |
devsar | 0:1f985a7c0a8b | 352 | pc.printf("Found char: Control Point"); |
devsar | 0:1f985a7c0a8b | 353 | m_control_point_handle = p_char_resp->handle_value; |
devsar | 0:1f985a7c0a8b | 354 | break; |
devsar | 0:1f985a7c0a8b | 355 | |
devsar | 0:1f985a7c0a8b | 356 | case BLE_UUID_ANCS_NOTIFICATION_SOURCE_CHAR: |
devsar | 0:1f985a7c0a8b | 357 | pc.printf("Found char: Notification Source"); |
devsar | 0:1f985a7c0a8b | 358 | m_notification_source_handle = p_char_resp->handle_value; |
devsar | 0:1f985a7c0a8b | 359 | break; |
devsar | 0:1f985a7c0a8b | 360 | |
devsar | 0:1f985a7c0a8b | 361 | case BLE_UUID_ANCS_DATA_SOURCE_CHAR: |
devsar | 0:1f985a7c0a8b | 362 | pc.printf("Found char: Data Source"); |
devsar | 0:1f985a7c0a8b | 363 | m_data_source_handle = p_char_resp->handle_value; |
devsar | 0:1f985a7c0a8b | 364 | break; |
devsar | 0:1f985a7c0a8b | 365 | |
devsar | 0:1f985a7c0a8b | 366 | default: |
devsar | 0:1f985a7c0a8b | 367 | break; |
devsar | 0:1f985a7c0a8b | 368 | } |
devsar | 0:1f985a7c0a8b | 369 | } |
devsar | 0:1f985a7c0a8b | 370 | |
devsar | 0:1f985a7c0a8b | 371 | if(p_char_resp!=NULL) { |
devsar | 0:1f985a7c0a8b | 372 | |
devsar | 0:1f985a7c0a8b | 373 | handle_range.start_handle = p_char_resp->handle_value + 1; |
devsar | 0:1f985a7c0a8b | 374 | |
devsar | 0:1f985a7c0a8b | 375 | err_code = sd_ble_gattc_characteristics_discover(m_conn_handle, &handle_range); |
devsar | 0:1f985a7c0a8b | 376 | err_check(err_code, "sd_ble_gattc_characteristics_discover"); |
devsar | 0:1f985a7c0a8b | 377 | |
devsar | 0:1f985a7c0a8b | 378 | } else { |
devsar | 0:1f985a7c0a8b | 379 | err_code = sd_ble_gattc_characteristics_discover(m_conn_handle, &handle_range); |
devsar | 0:1f985a7c0a8b | 380 | err_check(err_code, "sd_ble_gattc_characteristics_discover"); |
devsar | 0:1f985a7c0a8b | 381 | } |
devsar | 0:1f985a7c0a8b | 382 | |
devsar | 0:1f985a7c0a8b | 383 | } |
devsar | 0:1f985a7c0a8b | 384 | |
devsar | 0:1f985a7c0a8b | 385 | break; |
devsar | 0:1f985a7c0a8b | 386 | } |
devsar | 0:1f985a7c0a8b | 387 | case BLE_GATTC_EVT_DESC_DISC_RSP: |
devsar | 0:1f985a7c0a8b | 388 | { |
devsar | 0:1f985a7c0a8b | 389 | if (p_ble_evt->evt.gattc_evt.gatt_status != BLE_GATT_STATUS_SUCCESS) { |
devsar | 0:1f985a7c0a8b | 390 | pc.printf("Error: %s\r\n", "BLE_GATTC_EVT_DESC_DISC_RSP"); |
devsar | 0:1f985a7c0a8b | 391 | } else { |
devsar | 0:1f985a7c0a8b | 392 | if (p_ble_evt->evt.gattc_evt.params.desc_disc_rsp.count > 0) { |
devsar | 0:1f985a7c0a8b | 393 | const ble_gattc_desc_t * p_desc_resp = &(p_ble_evt->evt.gattc_evt.params.desc_disc_rsp.descs[0]); |
devsar | 0:1f985a7c0a8b | 394 | if (p_desc_resp->uuid.uuid == BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG) { |
devsar | 0:1f985a7c0a8b | 395 | if(p_desc_resp->handle == m_notification_source_handle + 1) { |
devsar | 0:1f985a7c0a8b | 396 | |
devsar | 0:1f985a7c0a8b | 397 | m_notification_source_handle_cccd = p_desc_resp->handle; |
devsar | 0:1f985a7c0a8b | 398 | pc.printf("Found NS CCC\r\n"); |
devsar | 0:1f985a7c0a8b | 399 | |
devsar | 0:1f985a7c0a8b | 400 | // Next, find CCC for data source. |
devsar | 0:1f985a7c0a8b | 401 | handle_range.start_handle = m_data_source_handle + 1; |
devsar | 0:1f985a7c0a8b | 402 | handle_range.end_handle = m_data_source_handle + 1; |
devsar | 0:1f985a7c0a8b | 403 | |
devsar | 0:1f985a7c0a8b | 404 | err_code = sd_ble_gattc_descriptors_discover(m_conn_handle, &handle_range); |
devsar | 0:1f985a7c0a8b | 405 | err_check(err_code, "sd_ble_gattc_descriptors_discover"); |
devsar | 0:1f985a7c0a8b | 406 | |
devsar | 0:1f985a7c0a8b | 407 | } else if(p_desc_resp->handle == m_data_source_handle + 1) { |
devsar | 0:1f985a7c0a8b | 408 | |
devsar | 0:1f985a7c0a8b | 409 | m_data_source_handle_cccd = p_desc_resp->handle; |
devsar | 0:1f985a7c0a8b | 410 | pc.printf("Found DS CCC\r\n"); |
devsar | 0:1f985a7c0a8b | 411 | |
devsar | 0:1f985a7c0a8b | 412 | // Got all we need, now before subscribing we'll do pairing. |
devsar | 0:1f985a7c0a8b | 413 | // request encryption...., we are in peripheral role. |
devsar | 0:1f985a7c0a8b | 414 | |
devsar | 0:1f985a7c0a8b | 415 | m_state = STATE_PAIRING; |
devsar | 0:1f985a7c0a8b | 416 | |
devsar | 0:1f985a7c0a8b | 417 | err_code = sd_ble_gap_authenticate(m_conn_handle, &m_sec_params); |
devsar | 0:1f985a7c0a8b | 418 | err_check(err_code, "sd_ble_gap_authenticate"); |
devsar | 0:1f985a7c0a8b | 419 | } |
devsar | 0:1f985a7c0a8b | 420 | } |
devsar | 0:1f985a7c0a8b | 421 | } |
devsar | 0:1f985a7c0a8b | 422 | } |
devsar | 0:1f985a7c0a8b | 423 | break; |
devsar | 0:1f985a7c0a8b | 424 | } |
devsar | 0:1f985a7c0a8b | 425 | case BLE_GATTC_EVT_WRITE_RSP: |
devsar | 0:1f985a7c0a8b | 426 | { |
devsar | 0:1f985a7c0a8b | 427 | if (p_ble_evt->evt.gattc_evt.gatt_status != BLE_GATT_STATUS_SUCCESS) { |
devsar | 0:1f985a7c0a8b | 428 | pc.printf("Error: %s\r\n", "BLE_GATTC_EVT_WRITE_RSP"); |
devsar | 0:1f985a7c0a8b | 429 | |
devsar | 0:1f985a7c0a8b | 430 | if(p_ble_evt->evt.gattc_evt.params.write_rsp.handle == m_control_point_handle) { |
devsar | 0:1f985a7c0a8b | 431 | m_state = STATE_LISTENING; |
devsar | 0:1f985a7c0a8b | 432 | } |
devsar | 0:1f985a7c0a8b | 433 | } else { |
devsar | 0:1f985a7c0a8b | 434 | if(p_ble_evt->evt.gattc_evt.params.write_rsp.handle == m_notification_source_handle_cccd) { |
devsar | 0:1f985a7c0a8b | 435 | pc.printf("NS subscribe success.\r\n"); |
devsar | 0:1f985a7c0a8b | 436 | |
devsar | 0:1f985a7c0a8b | 437 | // Next, subscribe to DS. |
devsar | 0:1f985a7c0a8b | 438 | uint16_t cccd_val = true ? BLE_CCCD_NOTIFY_BIT_MASK : 0; |
devsar | 0:1f985a7c0a8b | 439 | static ble_gattc_write_params_t m_write_params; |
devsar | 0:1f985a7c0a8b | 440 | uint8_t gattc_value[2]; |
devsar | 0:1f985a7c0a8b | 441 | |
devsar | 0:1f985a7c0a8b | 442 | gattc_value[0] = LSB(cccd_val); |
devsar | 0:1f985a7c0a8b | 443 | gattc_value[1] = MSB(cccd_val); |
devsar | 0:1f985a7c0a8b | 444 | |
devsar | 0:1f985a7c0a8b | 445 | m_write_params.handle = m_data_source_handle_cccd; |
devsar | 0:1f985a7c0a8b | 446 | m_write_params.len = 2; |
devsar | 0:1f985a7c0a8b | 447 | m_write_params.p_value = &gattc_value[0]; |
devsar | 0:1f985a7c0a8b | 448 | m_write_params.offset = 0; |
devsar | 0:1f985a7c0a8b | 449 | m_write_params.write_op = BLE_GATT_OP_WRITE_REQ; |
devsar | 0:1f985a7c0a8b | 450 | |
devsar | 0:1f985a7c0a8b | 451 | err_code = sd_ble_gattc_write(m_conn_handle, &m_write_params); |
devsar | 0:1f985a7c0a8b | 452 | err_check(err_code, "sd_ble_gattc_write"); |
devsar | 0:1f985a7c0a8b | 453 | } |
devsar | 0:1f985a7c0a8b | 454 | |
devsar | 0:1f985a7c0a8b | 455 | if(p_ble_evt->evt.gattc_evt.params.write_rsp.handle == m_data_source_handle_cccd) { |
devsar | 0:1f985a7c0a8b | 456 | pc.printf("DS subscribe success.\r\n"); |
devsar | 0:1f985a7c0a8b | 457 | |
devsar | 0:1f985a7c0a8b | 458 | // Now, we just waiting for NS notification. |
devsar | 0:1f985a7c0a8b | 459 | m_state = STATE_LISTENING; |
devsar | 0:1f985a7c0a8b | 460 | } |
devsar | 0:1f985a7c0a8b | 461 | |
devsar | 0:1f985a7c0a8b | 462 | if(p_ble_evt->evt.gattc_evt.params.write_rsp.handle == m_control_point_handle) { |
devsar | 0:1f985a7c0a8b | 463 | pc.printf("CP write success.\r\n"); |
devsar | 0:1f985a7c0a8b | 464 | // We'll receive data from DS notification |
devsar | 0:1f985a7c0a8b | 465 | } |
devsar | 0:1f985a7c0a8b | 466 | |
devsar | 0:1f985a7c0a8b | 467 | } |
devsar | 0:1f985a7c0a8b | 468 | |
devsar | 0:1f985a7c0a8b | 469 | break; |
devsar | 0:1f985a7c0a8b | 470 | } |
devsar | 0:1f985a7c0a8b | 471 | case BLE_GATTC_EVT_HVX: |
devsar | 0:1f985a7c0a8b | 472 | { |
devsar | 0:1f985a7c0a8b | 473 | if (p_ble_evt->evt.gattc_evt.gatt_status != BLE_GATT_STATUS_SUCCESS) { |
devsar | 0:1f985a7c0a8b | 474 | pc.printf("Error: %s\r\n", "BLE_GATTC_EVT_HVX"); |
devsar | 0:1f985a7c0a8b | 475 | } else { |
devsar | 0:1f985a7c0a8b | 476 | |
devsar | 0:1f985a7c0a8b | 477 | // Got notification... |
devsar | 0:1f985a7c0a8b | 478 | if(p_ble_evt->evt.gattc_evt.params.hvx.handle == m_notification_source_handle) { |
devsar | 0:1f985a7c0a8b | 479 | ble_gattc_evt_hvx_t *p_hvx = &p_ble_evt->evt.gattc_evt.params.hvx; |
devsar | 0:1f985a7c0a8b | 480 | if(p_hvx->len == 8) { |
devsar | 0:1f985a7c0a8b | 481 | pc.printf("Event ID: %x (%s)\r\n", p_hvx->data[0], eventid2string(p_hvx->data[0])); |
devsar | 0:1f985a7c0a8b | 482 | pc.printf("Event Flags: %x (%s)\r\n", p_hvx->data[1], eventflags2string(p_hvx->data[1])); |
devsar | 0:1f985a7c0a8b | 483 | pc.printf("Category ID: %x (%s)\r\n", p_hvx->data[2], categoryid2string(p_hvx->data[2])); |
devsar | 0:1f985a7c0a8b | 484 | pc.printf("Category Count: %x\r\n", p_hvx->data[3]); |
devsar | 0:1f985a7c0a8b | 485 | pc.printf("Notification ID: %x %x %x %x\r\n", p_hvx->data[4], p_hvx->data[5], p_hvx->data[6], p_hvx->data[7]); |
devsar | 0:1f985a7c0a8b | 486 | |
devsar | 0:1f985a7c0a8b | 487 | // if we are still processing, we can not do another write |
devsar | 0:1f985a7c0a8b | 488 | // with soft device (limitation?). Real implementation should use |
devsar | 0:1f985a7c0a8b | 489 | // queue to synchronized operation. Since this is a POC... just ignore. |
devsar | 0:1f985a7c0a8b | 490 | if(m_state == STATE_NOTIFIED) { |
devsar | 0:1f985a7c0a8b | 491 | pc.printf("Still retrieving data for another notification. ignoring this one.\r\n"); |
devsar | 0:1f985a7c0a8b | 492 | } else if(p_hvx->data[0] == 0) { |
devsar | 0:1f985a7c0a8b | 493 | // we only retrieved data for added notification. |
devsar | 0:1f985a7c0a8b | 494 | m_state = STATE_NOTIFIED; |
devsar | 0:1f985a7c0a8b | 495 | // write control point to get another data. |
devsar | 0:1f985a7c0a8b | 496 | |
devsar | 0:1f985a7c0a8b | 497 | // We only retrieve the title, with 16 bytes buffer... see ANCS spec for more |
devsar | 0:1f985a7c0a8b | 498 | static ble_gattc_write_params_t m_write_params; |
devsar | 0:1f985a7c0a8b | 499 | uint8_t gattc_value[8]; |
devsar | 0:1f985a7c0a8b | 500 | |
devsar | 0:1f985a7c0a8b | 501 | gattc_value[0] = 0; // CommandIDGetNotificationAttributes |
devsar | 0:1f985a7c0a8b | 502 | gattc_value[1] = p_hvx->data[4]; |
devsar | 0:1f985a7c0a8b | 503 | gattc_value[2] = p_hvx->data[5]; |
devsar | 0:1f985a7c0a8b | 504 | gattc_value[3] = p_hvx->data[6]; |
devsar | 0:1f985a7c0a8b | 505 | gattc_value[4] = p_hvx->data[7]; |
devsar | 0:1f985a7c0a8b | 506 | gattc_value[5] = 1; // Title |
devsar | 0:1f985a7c0a8b | 507 | gattc_value[6] = 16; // Length, 2 bytes, MSB first. |
devsar | 0:1f985a7c0a8b | 508 | gattc_value[7] = 0; |
devsar | 0:1f985a7c0a8b | 509 | |
devsar | 0:1f985a7c0a8b | 510 | m_write_params.handle = m_control_point_handle; |
devsar | 0:1f985a7c0a8b | 511 | m_write_params.len = 8; |
devsar | 0:1f985a7c0a8b | 512 | m_write_params.p_value = &gattc_value[0]; |
devsar | 0:1f985a7c0a8b | 513 | m_write_params.offset = 0; |
devsar | 0:1f985a7c0a8b | 514 | m_write_params.write_op = BLE_GATT_OP_WRITE_REQ; |
devsar | 0:1f985a7c0a8b | 515 | |
devsar | 0:1f985a7c0a8b | 516 | err_code = sd_ble_gattc_write(m_conn_handle, &m_write_params); |
devsar | 0:1f985a7c0a8b | 517 | err_check(err_code, "sd_ble_gattc_write"); |
devsar | 0:1f985a7c0a8b | 518 | |
devsar | 0:1f985a7c0a8b | 519 | } |
devsar | 0:1f985a7c0a8b | 520 | |
devsar | 0:1f985a7c0a8b | 521 | } else { |
devsar | 0:1f985a7c0a8b | 522 | pc.printf("NS data len not 8\r\n"); |
devsar | 0:1f985a7c0a8b | 523 | } |
devsar | 0:1f985a7c0a8b | 524 | } |
devsar | 0:1f985a7c0a8b | 525 | |
devsar | 0:1f985a7c0a8b | 526 | // Got data |
devsar | 0:1f985a7c0a8b | 527 | if(p_ble_evt->evt.gattc_evt.params.hvx.handle == m_data_source_handle) { |
devsar | 0:1f985a7c0a8b | 528 | ble_gattc_evt_hvx_t *p_hvx = &p_ble_evt->evt.gattc_evt.params.hvx; |
devsar | 0:1f985a7c0a8b | 529 | pc.printf("Title:"); |
devsar | 0:1f985a7c0a8b | 530 | // we only set size on MSB... |
devsar | 0:1f985a7c0a8b | 531 | uint16_t len = p_hvx->data[6]; |
devsar | 0:1f985a7c0a8b | 532 | pc.printf("(%d)", len); |
devsar | 0:1f985a7c0a8b | 533 | |
devsar | 0:1f985a7c0a8b | 534 | // the data itself start from index 8 to 8+len; |
devsar | 0:1f985a7c0a8b | 535 | uint16_t pos; |
devsar | 0:1f985a7c0a8b | 536 | for(pos=8; pos<=8+len; pos++) { |
devsar | 0:1f985a7c0a8b | 537 | pc.printf("%c", p_hvx->data[pos]); |
devsar | 0:1f985a7c0a8b | 538 | } |
devsar | 0:1f985a7c0a8b | 539 | pc.printf("\r\n"); |
devsar | 0:1f985a7c0a8b | 540 | |
devsar | 0:1f985a7c0a8b | 541 | // Back to listening... |
devsar | 0:1f985a7c0a8b | 542 | m_state = STATE_LISTENING; |
devsar | 0:1f985a7c0a8b | 543 | } |
devsar | 0:1f985a7c0a8b | 544 | |
devsar | 0:1f985a7c0a8b | 545 | } |
devsar | 0:1f985a7c0a8b | 546 | break; |
devsar | 0:1f985a7c0a8b | 547 | } |
devsar | 0:1f985a7c0a8b | 548 | case BLE_GATTC_EVT_TIMEOUT: |
devsar | 0:1f985a7c0a8b | 549 | case BLE_GATTS_EVT_TIMEOUT: |
devsar | 0:1f985a7c0a8b | 550 | { |
devsar | 0:1f985a7c0a8b | 551 | // Disconnect on GATT Server and Client timeout events. |
devsar | 0:1f985a7c0a8b | 552 | err_code = sd_ble_gap_disconnect(m_conn_handle, |
devsar | 0:1f985a7c0a8b | 553 | BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); |
devsar | 0:1f985a7c0a8b | 554 | err_check(err_code, "sd_ble_gap_disconnect"); |
devsar | 0:1f985a7c0a8b | 555 | break; |
devsar | 0:1f985a7c0a8b | 556 | } |
devsar | 0:1f985a7c0a8b | 557 | default: |
devsar | 0:1f985a7c0a8b | 558 | { |
devsar | 0:1f985a7c0a8b | 559 | //No implementation needed |
devsar | 0:1f985a7c0a8b | 560 | break; |
devsar | 0:1f985a7c0a8b | 561 | } |
devsar | 0:1f985a7c0a8b | 562 | } |
devsar | 0:1f985a7c0a8b | 563 | |
devsar | 0:1f985a7c0a8b | 564 | } |
devsar | 0:1f985a7c0a8b | 565 | |
devsar | 0:1f985a7c0a8b | 566 | |
devsar | 0:1f985a7c0a8b | 567 | static void sys_event_handler(uint32_t sys_evt) |
devsar | 0:1f985a7c0a8b | 568 | { |
devsar | 0:1f985a7c0a8b | 569 | pc.printf("Event: system event\r\n"); |
devsar | 0:1f985a7c0a8b | 570 | pstorage_sys_event_handler(sys_evt); |
devsar | 0:1f985a7c0a8b | 571 | } |
devsar | 0:1f985a7c0a8b | 572 | |
devsar | 0:1f985a7c0a8b | 573 | |
devsar | 0:1f985a7c0a8b | 574 | static void timers_init(void) |
devsar | 0:1f985a7c0a8b | 575 | { |
devsar | 0:1f985a7c0a8b | 576 | // Initialize timer module. |
devsar | 0:1f985a7c0a8b | 577 | APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, false); |
devsar | 0:1f985a7c0a8b | 578 | } |
devsar | 0:1f985a7c0a8b | 579 | |
devsar | 0:1f985a7c0a8b | 580 | |
devsar | 0:1f985a7c0a8b | 581 | static void ble_stack_init(void) |
devsar | 0:1f985a7c0a8b | 582 | { |
devsar | 0:1f985a7c0a8b | 583 | uint32_t err_code; |
devsar | 0:1f985a7c0a8b | 584 | |
devsar | 0:1f985a7c0a8b | 585 | // Initialize the SoftDevice handler module. |
ytsuboi | 1:f0edc06f2d29 | 586 | // SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, false); |
ytsuboi | 1:f0edc06f2d29 | 587 | SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_RC_250_PPM_4000MS_CALIBRATION, false); |
devsar | 0:1f985a7c0a8b | 588 | |
devsar | 0:1f985a7c0a8b | 589 | |
devsar | 0:1f985a7c0a8b | 590 | // Register with the SoftDevice handler module for BLE events. |
devsar | 0:1f985a7c0a8b | 591 | err_code = softdevice_ble_evt_handler_set(ble_event_handler); |
devsar | 0:1f985a7c0a8b | 592 | err_check(err_code, "softdevice_ble_evt_handler_set"); |
devsar | 0:1f985a7c0a8b | 593 | |
devsar | 0:1f985a7c0a8b | 594 | // Register with the SoftDevice handler module for System events. |
devsar | 0:1f985a7c0a8b | 595 | err_code = softdevice_sys_evt_handler_set(sys_event_handler); |
devsar | 0:1f985a7c0a8b | 596 | err_check(err_code, "softdevice_sys_evt_handler_set"); |
devsar | 0:1f985a7c0a8b | 597 | } |
devsar | 0:1f985a7c0a8b | 598 | |
devsar | 0:1f985a7c0a8b | 599 | static void set_128_uuid() |
devsar | 0:1f985a7c0a8b | 600 | { |
devsar | 0:1f985a7c0a8b | 601 | uint32_t err_code; |
devsar | 0:1f985a7c0a8b | 602 | uint8_t temp_type; // All ANCS is vendor type... so we ignore this. |
devsar | 0:1f985a7c0a8b | 603 | |
devsar | 0:1f985a7c0a8b | 604 | |
devsar | 0:1f985a7c0a8b | 605 | err_code = sd_ble_uuid_vs_add(&ble_ancs_base_uuid128, &temp_type); |
devsar | 0:1f985a7c0a8b | 606 | err_check(err_code, "sd_ble_uuid_vs_add"); |
devsar | 0:1f985a7c0a8b | 607 | |
devsar | 0:1f985a7c0a8b | 608 | err_code = sd_ble_uuid_vs_add(&ble_ancs_cp_base_uuid128, &temp_type); |
devsar | 0:1f985a7c0a8b | 609 | err_check(err_code, "sd_ble_uuid_vs_add"); |
devsar | 0:1f985a7c0a8b | 610 | |
devsar | 0:1f985a7c0a8b | 611 | err_code = sd_ble_uuid_vs_add(&ble_ancs_ns_base_uuid128, &temp_type); |
devsar | 0:1f985a7c0a8b | 612 | err_check(err_code, "sd_ble_uuid_vs_add"); |
devsar | 0:1f985a7c0a8b | 613 | |
devsar | 0:1f985a7c0a8b | 614 | err_code = sd_ble_uuid_vs_add(&ble_ancs_ds_base_uuid128, &temp_type); |
devsar | 0:1f985a7c0a8b | 615 | err_check(err_code, "sd_ble_uuid_vs_add"); |
devsar | 0:1f985a7c0a8b | 616 | } |
devsar | 0:1f985a7c0a8b | 617 | |
devsar | 0:1f985a7c0a8b | 618 | |
devsar | 0:1f985a7c0a8b | 619 | static void conn_params_error_handler(uint32_t nrf_error) |
devsar | 0:1f985a7c0a8b | 620 | { |
devsar | 0:1f985a7c0a8b | 621 | err_check(nrf_error, "Error: conn params error"); |
devsar | 0:1f985a7c0a8b | 622 | } |
devsar | 0:1f985a7c0a8b | 623 | |
devsar | 0:1f985a7c0a8b | 624 | |
devsar | 0:1f985a7c0a8b | 625 | static void conn_params_init(void) |
devsar | 0:1f985a7c0a8b | 626 | { |
devsar | 0:1f985a7c0a8b | 627 | uint32_t err_code; |
devsar | 0:1f985a7c0a8b | 628 | ble_conn_params_init_t cp_init; |
devsar | 0:1f985a7c0a8b | 629 | |
devsar | 0:1f985a7c0a8b | 630 | memset(&cp_init, 0, sizeof(cp_init)); |
devsar | 0:1f985a7c0a8b | 631 | |
devsar | 0:1f985a7c0a8b | 632 | cp_init.p_conn_params = NULL; |
devsar | 0:1f985a7c0a8b | 633 | cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY; |
devsar | 0:1f985a7c0a8b | 634 | cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY; |
devsar | 0:1f985a7c0a8b | 635 | cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT; |
devsar | 0:1f985a7c0a8b | 636 | cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID; |
devsar | 0:1f985a7c0a8b | 637 | cp_init.disconnect_on_fail = true; |
devsar | 0:1f985a7c0a8b | 638 | cp_init.evt_handler = NULL; |
devsar | 0:1f985a7c0a8b | 639 | cp_init.error_handler = conn_params_error_handler; |
devsar | 0:1f985a7c0a8b | 640 | |
devsar | 0:1f985a7c0a8b | 641 | err_code = ble_conn_params_init(&cp_init); |
devsar | 0:1f985a7c0a8b | 642 | err_check(err_code, "ble_conn_params_init"); |
devsar | 0:1f985a7c0a8b | 643 | } |
devsar | 0:1f985a7c0a8b | 644 | |
devsar | 0:1f985a7c0a8b | 645 | |
devsar | 0:1f985a7c0a8b | 646 | static void sec_params_init(void) |
devsar | 0:1f985a7c0a8b | 647 | { |
devsar | 0:1f985a7c0a8b | 648 | m_sec_params.timeout = SEC_PARAM_TIMEOUT; |
devsar | 0:1f985a7c0a8b | 649 | m_sec_params.bond = SEC_PARAM_BOND; |
devsar | 0:1f985a7c0a8b | 650 | m_sec_params.mitm = SEC_PARAM_MITM; |
devsar | 0:1f985a7c0a8b | 651 | m_sec_params.io_caps = SEC_PARAM_IO_CAPABILITIES; |
devsar | 0:1f985a7c0a8b | 652 | m_sec_params.oob = SEC_PARAM_OOB; |
devsar | 0:1f985a7c0a8b | 653 | m_sec_params.min_key_size = SEC_PARAM_MIN_KEY_SIZE; |
devsar | 0:1f985a7c0a8b | 654 | m_sec_params.max_key_size = SEC_PARAM_MAX_KEY_SIZE; |
devsar | 0:1f985a7c0a8b | 655 | } |
devsar | 0:1f985a7c0a8b | 656 | |
devsar | 0:1f985a7c0a8b | 657 | |
devsar | 0:1f985a7c0a8b | 658 | static void gap_params_init(void) |
devsar | 0:1f985a7c0a8b | 659 | { |
devsar | 0:1f985a7c0a8b | 660 | uint32_t err_code; |
devsar | 0:1f985a7c0a8b | 661 | ble_gap_conn_params_t gap_conn_params; |
devsar | 0:1f985a7c0a8b | 662 | ble_gap_conn_sec_mode_t sec_mode; |
devsar | 0:1f985a7c0a8b | 663 | |
devsar | 0:1f985a7c0a8b | 664 | BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); |
devsar | 0:1f985a7c0a8b | 665 | |
devsar | 0:1f985a7c0a8b | 666 | err_code = sd_ble_gap_device_name_set(&sec_mode, |
devsar | 0:1f985a7c0a8b | 667 | (const uint8_t *)DEVICE_NAME, |
devsar | 0:1f985a7c0a8b | 668 | strlen(DEVICE_NAME)); |
devsar | 0:1f985a7c0a8b | 669 | err_check(err_code, "sd_ble_gap_device_name_set"); |
devsar | 0:1f985a7c0a8b | 670 | |
devsar | 0:1f985a7c0a8b | 671 | memset(&gap_conn_params, 0, sizeof(gap_conn_params)); |
devsar | 0:1f985a7c0a8b | 672 | |
devsar | 0:1f985a7c0a8b | 673 | gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL; |
devsar | 0:1f985a7c0a8b | 674 | gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL; |
devsar | 0:1f985a7c0a8b | 675 | gap_conn_params.slave_latency = SLAVE_LATENCY; |
devsar | 0:1f985a7c0a8b | 676 | gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT; |
devsar | 0:1f985a7c0a8b | 677 | |
devsar | 0:1f985a7c0a8b | 678 | err_code = sd_ble_gap_ppcp_set(&gap_conn_params); |
devsar | 0:1f985a7c0a8b | 679 | err_check(err_code, "sd_ble_gap_ppcp_set"); |
devsar | 0:1f985a7c0a8b | 680 | } |
devsar | 0:1f985a7c0a8b | 681 | |
devsar | 0:1f985a7c0a8b | 682 | |
devsar | 0:1f985a7c0a8b | 683 | static void advertising_init(void) |
devsar | 0:1f985a7c0a8b | 684 | { |
devsar | 0:1f985a7c0a8b | 685 | uint32_t err_code; |
devsar | 0:1f985a7c0a8b | 686 | ble_advdata_t advdata; |
devsar | 0:1f985a7c0a8b | 687 | uint8_t flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE; |
devsar | 0:1f985a7c0a8b | 688 | ble_uuid_t ancs_uuid; |
devsar | 0:1f985a7c0a8b | 689 | |
devsar | 0:1f985a7c0a8b | 690 | // err_code = sd_ble_uuid_vs_add(&ble_ancs_base_uuid128, &m_ancs_uuid_type); |
devsar | 0:1f985a7c0a8b | 691 | // err_check(err_code, "sd_ble_uuid_vs_add"); |
devsar | 0:1f985a7c0a8b | 692 | |
devsar | 0:1f985a7c0a8b | 693 | // ancs_uuid.uuid = ((ble_ancs_base_uuid128.uuid128[12]) | (ble_ancs_base_uuid128.uuid128[13] << 8)); |
devsar | 0:1f985a7c0a8b | 694 | // ancs_uuid.type = m_ancs_uuid_type; |
devsar | 0:1f985a7c0a8b | 695 | BLE_UUID_BLE_ASSIGN(ancs_uuid, BLE_UUID_APPLE_NOTIFICATION_CENTER_SERVICE); |
devsar | 0:1f985a7c0a8b | 696 | ancs_uuid.type = BLE_UUID_TYPE_VENDOR_BEGIN; |
devsar | 0:1f985a7c0a8b | 697 | |
devsar | 0:1f985a7c0a8b | 698 | // Build and set advertising data. |
devsar | 0:1f985a7c0a8b | 699 | memset(&advdata, 0, sizeof(advdata)); |
devsar | 0:1f985a7c0a8b | 700 | |
devsar | 0:1f985a7c0a8b | 701 | advdata.name_type = BLE_ADVDATA_FULL_NAME; |
devsar | 0:1f985a7c0a8b | 702 | advdata.include_appearance = true; |
devsar | 0:1f985a7c0a8b | 703 | advdata.flags.size = sizeof(flags); |
devsar | 0:1f985a7c0a8b | 704 | advdata.flags.p_data = &flags; |
devsar | 0:1f985a7c0a8b | 705 | advdata.uuids_complete.uuid_cnt = 0; |
devsar | 0:1f985a7c0a8b | 706 | advdata.uuids_complete.p_uuids = NULL; |
devsar | 0:1f985a7c0a8b | 707 | advdata.uuids_solicited.uuid_cnt = 1; |
devsar | 0:1f985a7c0a8b | 708 | advdata.uuids_solicited.p_uuids = &ancs_uuid; |
devsar | 0:1f985a7c0a8b | 709 | |
devsar | 0:1f985a7c0a8b | 710 | err_code = ble_advdata_set(&advdata, NULL); |
devsar | 0:1f985a7c0a8b | 711 | err_check(err_code, "ble_advdata_set"); |
devsar | 0:1f985a7c0a8b | 712 | |
devsar | 0:1f985a7c0a8b | 713 | } |
devsar | 0:1f985a7c0a8b | 714 | |
devsar | 0:1f985a7c0a8b | 715 | |
devsar | 0:1f985a7c0a8b | 716 | /**************************************************************************/ |
devsar | 0:1f985a7c0a8b | 717 | /*! |
devsar | 0:1f985a7c0a8b | 718 | @brief Program entry point |
devsar | 0:1f985a7c0a8b | 719 | */ |
devsar | 0:1f985a7c0a8b | 720 | /**************************************************************************/ |
devsar | 0:1f985a7c0a8b | 721 | int main(void) |
devsar | 0:1f985a7c0a8b | 722 | { |
devsar | 0:1f985a7c0a8b | 723 | uint32_t err_code; |
devsar | 0:1f985a7c0a8b | 724 | // uint32_t soc_event; |
devsar | 0:1f985a7c0a8b | 725 | // uint32_t evt_id; |
devsar | 0:1f985a7c0a8b | 726 | |
devsar | 0:1f985a7c0a8b | 727 | pc.printf("Program started\n\r"); |
ytsuboi | 1:f0edc06f2d29 | 728 | |
devsar | 0:1f985a7c0a8b | 729 | led_adv = 0; |
devsar | 0:1f985a7c0a8b | 730 | led_conn = 0; |
devsar | 0:1f985a7c0a8b | 731 | |
devsar | 0:1f985a7c0a8b | 732 | |
devsar | 0:1f985a7c0a8b | 733 | pc.printf("timers_init()\r\n"); |
devsar | 0:1f985a7c0a8b | 734 | timers_init(); |
devsar | 0:1f985a7c0a8b | 735 | |
devsar | 0:1f985a7c0a8b | 736 | pc.printf("ble_stack_init()\r\n"); |
devsar | 0:1f985a7c0a8b | 737 | ble_stack_init(); |
devsar | 0:1f985a7c0a8b | 738 | |
ytsuboi | 1:f0edc06f2d29 | 739 | /* Make sure we get a clean start */ |
ytsuboi | 1:f0edc06f2d29 | 740 | wait(0.5); |
ytsuboi | 1:f0edc06f2d29 | 741 | wait(1); |
ytsuboi | 1:f0edc06f2d29 | 742 | |
devsar | 0:1f985a7c0a8b | 743 | pc.printf("gap_params_init()\r\n"); |
devsar | 0:1f985a7c0a8b | 744 | gap_params_init(); |
devsar | 0:1f985a7c0a8b | 745 | |
devsar | 0:1f985a7c0a8b | 746 | pc.printf("set_128_uuid()\r\n"); |
devsar | 0:1f985a7c0a8b | 747 | set_128_uuid(); |
devsar | 0:1f985a7c0a8b | 748 | |
devsar | 0:1f985a7c0a8b | 749 | pc.printf("advertising_init()\r\n"); |
devsar | 0:1f985a7c0a8b | 750 | advertising_init(); |
devsar | 0:1f985a7c0a8b | 751 | |
devsar | 0:1f985a7c0a8b | 752 | |
devsar | 0:1f985a7c0a8b | 753 | pc.printf("conn_params_init()\r\n"); |
devsar | 0:1f985a7c0a8b | 754 | conn_params_init(); |
devsar | 0:1f985a7c0a8b | 755 | |
devsar | 0:1f985a7c0a8b | 756 | pc.printf("sec_params_init()\r\n"); |
devsar | 0:1f985a7c0a8b | 757 | sec_params_init(); |
devsar | 0:1f985a7c0a8b | 758 | |
devsar | 0:1f985a7c0a8b | 759 | pc.printf("advertising_start()\r\n"); |
devsar | 0:1f985a7c0a8b | 760 | advertising_start(); |
devsar | 0:1f985a7c0a8b | 761 | |
devsar | 0:1f985a7c0a8b | 762 | |
devsar | 0:1f985a7c0a8b | 763 | // while(1) { wait(1.0); }; |
devsar | 0:1f985a7c0a8b | 764 | |
devsar | 0:1f985a7c0a8b | 765 | for (;;) |
devsar | 0:1f985a7c0a8b | 766 | { |
devsar | 0:1f985a7c0a8b | 767 | err_code = sd_app_evt_wait(); |
devsar | 0:1f985a7c0a8b | 768 | err_check(err_code, "sd_app_evt_wait"); |
devsar | 0:1f985a7c0a8b | 769 | |
devsar | 0:1f985a7c0a8b | 770 | /* |
devsar | 0:1f985a7c0a8b | 771 | do { |
devsar | 0:1f985a7c0a8b | 772 | soc_event = sd_evt_get(&evt_id); |
devsar | 0:1f985a7c0a8b | 773 | pc.printf("soc_event: %d\r\n", evt_id); |
devsar | 0:1f985a7c0a8b | 774 | } while(soc_event != NRF_ERROR_NOT_FOUND); |
devsar | 0:1f985a7c0a8b | 775 | */ |
devsar | 0:1f985a7c0a8b | 776 | } |
devsar | 0:1f985a7c0a8b | 777 | |
devsar | 0:1f985a7c0a8b | 778 | } |