7. Preparing the Central cntd

7.1. Code Modifications cont.

7.1.1. GAP Event Handlers

7.1.1.1. handle_evt_gap_connected()

Upon connection, the central will request information about supported services and their characteristics. This is known as Service Browse and usually involves several data exchanges that need to be serviced fast. For that purpose, during GAP event connected, the parameters of the connection are switched to reflect a very short connection interval as is needed. Another thing that happens at this point is the negotiation between central and peripheral for the MTU to be used for this connection. Thus, the highlighted lines of code should be added to handle_evt_gap_connected():

static void handle_evt_gap_connected(ble_evt_gap_connected_t *evt)
{

        printf("%s: conn_idx=%04x\r\n", __func__, evt->conn_idx);

        const gap_conn_params_t cp = {
                .interval_min = BLE_CONN_INTERVAL_FROM_MS(40),
                .interval_max = BLE_CONN_INTERVAL_FROM_MS(60),
                .slave_latency = 0,
                .sup_timeout = BLE_SUPERVISION_TMO_FROM_MS(400),
        };

        ble_gap_conn_param_update( 0x0,&cp);

        ble_gattc_exchange_mtu(0x0);

        // notify main thread, we'll start discovery from there
        OS_TASK_NOTIFY(ble_central_task_handle, DISCOVER_NOTIF, eSetBits);
}

7.1.1.2. handle_evt_gap_disconnected()

When the central gets disconnected timer with handle write_no_response_timer_h should be stopped. Add the highlighted lines to the function.

static void handle_evt_gap_disconnected(ble_evt_gap_disconnected_t *evt)
{
#if(USER_WRITE_NO_RESPONSE_BLE_OP_EN == 1)

        OS_TIMER_STOP(write_no_response_timer_h,OS_TIMER_FOREVER);
#endif
        printf("%s: conn_idx=%04x address=%s reason=%d\r\n", __func__, evt->conn_idx,
                                                format_bd_address(&evt->address), evt->reason);

#if (!CFG_USE_BROWSE_API)
        queue_remove_all(&services, OS_FREE_FUNC);
        queue_remove_all(&characteristics, OS_FREE_FUNC);
#endif

        // notify main thread, we'll start reconnect from there
        OS_TASK_NOTIFY(ble_central_task_handle, RECONNECT_NOTIF, eSetBits);
}

7.1.1.3. handle_evt_gattc_browse_svc()

Add the highlighted lines so NOTIFICATIONS mode can request or ignore notifications/indications of every characteristic that allows them through the corresponding bit of the characteristic’s properties.

static void handle_evt_gattc_browse_svc(ble_evt_gattc_browse_svc_t *evt)
{
#if (USER_BLE_NOTIFICATIONS_EN == 1)
        uint8_t prop = 0;
#endif
        int i;

        printf("%s: conn_idx=%04x start_h=%04x end_h=%04x\r\n", __func__, evt->conn_idx,
                                                                        evt->start_h, evt->end_h);

        printf("\t%04x serv %s\r\n", evt->start_h, format_uuid(&evt->uuid));

        for (i = 0; i < evt->num_items; i++) {
                gattc_item_t *item = &evt->items[i];
                att_uuid_t uuid;

                switch (item->type) {
                case GATTC_ITEM_TYPE_INCLUDE:
                        printf("\t%04x incl %s\r\n", item->handle, format_uuid(&item->uuid));
                        break;
                case GATTC_ITEM_TYPE_CHARACTERISTIC:
                        printf("\t%04x char %s prop=%02x (%s)\r\n", item->handle,
                                                format_uuid(&evt->uuid), item->c.properties,
                                                format_properties(item->c.properties));

                        printf("\t%04x ---- %s\r\n", item->c.value_handle, format_uuid(&item->uuid));

#if(USER_BLE_NOTIFICATIONS_EN == 1)
                        prop = item->c.properties;
#endif
                        break;
                case GATTC_ITEM_TYPE_DESCRIPTOR:
                        printf("\t%04x desc %s\r\n", item->handle, format_uuid(&item->uuid));

                        ble_uuid_create16(UUID_GATT_CLIENT_CHAR_CONFIGURATION, &uuid);
                        if (ble_uuid_equal(&uuid, &item->uuid)) {
#if(USER_BLE_NOTIFICATIONS_EN == 1)
                                if (prop & GATT_PROP_NOTIFY) {
                                        uint16_t ccc = GATT_CCC_NOTIFICATIONS;
                                        ble_gattc_write(evt->conn_idx, item->handle, 0,
                                                                        sizeof(ccc), (uint8_t *) &ccc);
                                }

                                if (prop & GATT_PROP_INDICATE) {
                                        uint16_t ccc = GATT_CCC_INDICATIONS;
                                        ble_gattc_write(evt->conn_idx, item->handle, 0,
                                                                        sizeof(ccc), (uint8_t *) &ccc);
                                }
#endif
                        }
                        break;
                default:
                        printf("\t%04x ????\r\n", item->handle);
                        break;
                }
        }




}

7.1.1.4. handle_evt_gattc_browse_completed()

After Service Browse has finished, the connection parameters should change to reflect the parameters defined in the use case tested. Alter handle_evt_gattc_browse_completed() accordingly:

static void handle_evt_gattc_browse_completed(ble_evt_gattc_browse_completed_t *evt)
{
        printf("%s: conn_idx=%04x status=%d\r\n", __func__, evt->conn_idx, evt->status);

        /*Connection Parameters after service browse is completed*/
        const gap_conn_params_t svc_browse_completed_conn_params = {
                .interval_min = BLE_CONN_INTERVAL_FROM_MS(CONNECTION_INTERVAL-10),
                .interval_max = BLE_CONN_INTERVAL_FROM_MS(CONNECTION_INTERVAL),
                .slave_latency = 0,
                .sup_timeout = BLE_SUPERVISION_TMO_FROM_MS(CONNECTION_INTERVAL*4),
        };

        ble_error_t err = ble_gap_conn_param_update( 0x0,&svc_browse_completed_conn_params);
        OS_ASSERT(err == BLE_STATUS_OK);
        printf("\n\rParameters Changed\n\r");

}

7.1.1.5. handle_evt_gattc_read_completed()

Whenever a read request is completed, a new read request should be scheduled to happen. To ensure that any subsequent reads will be triggered only after timer with handle start_measurement_timer_h has expired, start_ble_operations_flag is checked. When a measurement is taking place, USER_SUPPRESS_LOGS_EN should be set to 1. Otherwise, using printf function requires the use of UART, which delays the system resulting in issuing the new operation request later.

static void handle_evt_gattc_read_completed(ble_evt_gattc_read_completed_t *evt)
{
#if CFG_UPDATE_NAME
        static bool devname_written = false;
#endif

#if (USER_SUPPRESS_LOGS_EN == 0)
        printf("%s: conn_idx=%04x handle=%04x status=%d\r\n", __func__, evt->conn_idx, evt->handle,
                                                                                        evt->status);
        if (evt->status == ATT_ERROR_OK) {
                format_value(evt->length, evt->value);
        }
#endif

#if (USER_READ_BLE_OP_EN == 1)
                if(start_ble_operations_flag)
                {
                        ble_gattc_read(0x0,first_char_value_handle,0x0);
                }
#endif

#if CFG_UPDATE_NAME
        if (evt->handle == devname_val_h && !devname_written) {
                static const uint8_t name[] = "DA1468x was here!";
                devname_written = true;
                ble_gattc_write(evt->conn_idx, evt->handle, 0, sizeof(name) - 1, name);
        }
#endif
}

7.1.1.6. handle_evt_gattc_write_completed()

As with handle_evt_gattc_read_completed(), the same thing should happen when write is completed. The only difference is that a new gattc_ble_write() should be issued if WRITE mode is enabled or write_no_response_trigger timer should be restarted if WRITE_NO_RESPONSE is enabled.

static void handle_evt_gattc_write_completed(ble_evt_gattc_write_completed_t *evt)
{
#if (USER_SUPPRESS_LOGS_EN == 0)
        printf("%s: conn_idx=%04x handle=%04x status=%d\r\n", __func__, evt->conn_idx, evt->handle,
                                                                                        evt->status);
#endif

        if (evt->handle == devname_val_h) {
                ble_gattc_read(evt->conn_idx, evt->handle, 0);
        }

#if (USER_WRITE_BLE_OP_EN == 1)
                if(start_ble_operations_flag)
                {
                        ble_gattc_write(0x0, first_char_value_handle, 0, sizeof(written_value), written_value);
                }
#endif
#if (USER_WRITE_NO_RESPONSE_BLE_OP_EN == 1)
                if(start_ble_operations_flag)
                {
                        OS_TIMER_START(write_no_response_timer_h, OS_TIMER_FOREVER);
                }
#endif

}

7.1.1.7. handle_evt_gattc_notification()

Notification GAP events are handled by writing the data they transfered through UART on terminal. For a similar reason to handle_evt_gattc_read_completed() and handle_evt_gattc_write_completed() it is advised to have all printf function calls suppressed.

static void handle_evt_gattc_notification(ble_evt_gattc_notification_t *evt)
{
#if(USER_SUPPRESS_LOGS_EN == 0)
        printf("%s: conn_idx=%04x handle=%04x length=%d\r\n", __func__, evt->conn_idx, evt->handle,
                                                                                       evt->length);

        format_value(evt->length, evt->value);
#endif
}

7.1.1.8. static void handle_evt_gattc_indication()

As with notification handling, indication handling should be altered as well.

static void handle_evt_gattc_indication(ble_evt_gattc_indication_t *evt)
{
#if(USER_SUPPRESS_LOGS_EN == 0)
        printf("%s: conn_idx=%04x handle=%04x length=%d\r\n", __func__, evt->conn_idx, evt->handle,
                                                                                       evt->length);

        format_value(evt->length, evt->value);
#endif
}

7.1.1.9. static void handle_evt_gattc_mtu_changed()

Last but not least, a handler for mtu_changed GAP event should be added after all the GAP event handlers. This handler will be utilized every time the central calls for an MTU_exchange and the MTU value that the connection locks on is different than what it was before the exchange. Since this happens only a limited number of times in non critical parts, the printf is not suppressed but rather prints the new MTU value.

static void handle_evt_gattc_mtu_changed(ble_evt_gattc_mtu_changed_t* evt)
{
        mtu_size = evt->mtu;
        printf("\n\n\n%s: conn_idx=%04x new MTU=%d Bytes\r\n\n\n", __func__, evt->conn_idx, evt->mtu);
}

Additionally, a new case needs to be added to the switch (hdr->evt_code) statement in ble_central_task() in order to be able to capture the mtu_changed event.

case BLE_EVT_GATTC_MTU_CHANGED:
        handle_evt_gattc_mtu_changed((ble_evt_gattc_mtu_changed_t *) hdr);
        break;

7.1.2. Task Notification Handling

Two different timers can, through their callback function, notify ble_central_task(). Add the task notification handlers right after (if notif & RECONNECT_NOTIF) section of the code.

7.1.2.1. WRITE_NO_RESPONSE_T_NOTIF

This handler should issue a new write no response request and stop write_no_response_trigger timer in order for it to be restarted when the write_completed event arrives.

#if(USER_WRITE_NO_RESPONSE_BLE_OP_EN == 1)
                if (notif & WRITE_NO_RESPONSE_T_NOTIF)
                {
                        /* Write the first characteristic of the Service*/
                        ble_error_t err = ble_gattc_write_no_resp(0x0,first_char_value_handle, false, sizeof(written_value), written_value);
                        OS_ASSERT(err == BLE_STATUS_OK);

                        OS_TIMER_STOP(write_no_response_timer_h,OS_TIMER_FOREVER);
                }
#endif

/

7.1.2.2. START_MEASURE_T_NOTIF

This handler will stop start_measurement timer and notify the user through UART that they should start measuring. Optionally, depending on the modes enabled, the first ATT operation which will start the chain reaction is going to be passed to the QUEUE towards the BLE STACK.

if (notif & START_MEASURE_T_NOTIF)
                {
                        OS_TIMER_STOP(start_measurement_timer_h, OS_TIMER_FOREVER);
                        printf("\n\n=============Start Measuring=============\n\n\r");

#if(USER_READ_BLE_OP_EN == 1)
                        ble_gattc_read(0x0,first_char_value_handle,0x0);
#endif
#if(USER_WRITE_BLE_OP_EN == 1)
                        ble_gattc_write(0x0, first_char_value_handle, 0, sizeof(written_value), written_value);
#endif

#if(USER_WRITE_NO_RESPONSE_BLE_OP_EN == 1)

                        ble_gattc_write_no_resp(0x0,first_char_value_handle, false, sizeof(written_value), written_value);
#endif
                }