diff --git a/src/W800_SDK_v1.00.10/app/ble/ble_service.c b/src/W800_SDK_v1.00.10/app/ble/ble_service.c index 83a489e..dc2b7f5 100644 --- a/src/W800_SDK_v1.00.10/app/ble/ble_service.c +++ b/src/W800_SDK_v1.00.10/app/ble/ble_service.c @@ -12,10 +12,12 @@ static volatile ble_service_state_e _ble_service_state = BLE_SERVICE_MODE_STOPPED; static nus_data_rx_fn_t _ble_service_nus_data_rx_cb = NULL; static ble_service_state_change_fn_t _ble_service_state_change_cb = NULL; +static uint32_t _pairing_passkey = 0; /* Connection handle to the connected device : only one simultaneous connection */ static uint16_t ble_device_conn_handle = BLE_HS_CONN_HANDLE_NONE; static uint16_t usable_mtu = USABLE_DEFAULT_MTU; +static uint8_t _device_mac_address[6] = {0x00}; /** * @brief Structure used to store the various data to carry out a chunked notification or indication data transfer @@ -30,7 +32,8 @@ typedef struct bool transfer_in_progress; // Is a transfer already in progress ? } data_being_sent_t; -// Only one transfer of a type () can occur at any given time +// Only one transfer of a type can occur at any given time ie +// one notification and one indication can happen at the same time but not more. static data_being_sent_t notification_data = {.data = NULL, .length = 0, .offset = 0, .transfer_in_progress = false}; static data_being_sent_t indication_data = {.data = NULL, .length = 0, .offset = 0, .transfer_in_progress = false}; @@ -102,6 +105,7 @@ static bool ble_service_define_gatt(const struct ble_gatt_svc_def *gatt_svc); static bool ble_service_advertise(bool enable); static int ble_gap_event_cb(struct ble_gap_event *event, void *arg); static int ble_advertise_gap_event_cb(struct ble_gap_event *event, void *arg); +static int ble_conn_gap_event_cb(struct ble_gap_event *event, void *arg); static void print_conn_desc(const struct ble_gap_conn_desc *desc); // Raw because it doesn't handle payload fragmentation if mtu size is smaller than the payload size static bool ble_service_send_raw_custom_notification(uint16_t characteristic_handle, const uint8_t *data, uint16_t length); @@ -271,6 +275,28 @@ bool ble_service_is_device_connected(void) return _ble_service_state == BLE_SERVICE_MODE_CONNECTED; } +const uint8_t *ble_service_get_device_mac_address(void) +{ + // We only need to read from efuse section once. + if( + _device_mac_address[0] == 0 && + _device_mac_address[1] == 0 && + _device_mac_address[2] == 0 && + _device_mac_address[3] == 0 && + _device_mac_address[4] == 0 && + _device_mac_address[5] == 0 + ) + { + extern int tls_get_bt_mac_addr(u8 *mac); + tls_get_bt_mac_addr(_device_mac_address); + + // Make sure the device address is compliant with the random address specification : + _device_mac_address[5] |= 0xC0; + } + + return _device_mac_address; +} + void ble_service_register_state_change_cb(ble_service_state_change_fn_t ble_service_state_change_cb) { _ble_service_state_change_cb = ble_service_state_change_cb; @@ -281,6 +307,16 @@ ble_service_state_e ble_service_get_state(void) return _ble_service_state; } +void ble_service_set_pairing_passkey(uint32_t passkey) +{ + _pairing_passkey = passkey; +} + +uint32_t ble_service_get_active_pairing_passkey(void) +{ + return _pairing_passkey; +} + bool ble_service_update_connection_parameters( uint16_t itvl_min, uint16_t itvl_max, @@ -470,15 +506,9 @@ static bool ble_service_advertise(bool enable) advertisement_fields.appearance = ble_svc_gap_device_appearance(); advertisement_fields.appearance_is_present = 1; - // Set the name of a watch supported by GB - #ifdef GADGETBRIDGE_SUPPORT - static const char dev_name[12] = "Bangle.js 2"; - advertisement_fields.name = (uint8_t *)dev_name;//ble_svc_gap_device_name(); - advertisement_fields.name_len = 11;//strlen(ble_svc_gap_device_name()); - #else + // Set the name of the BLE device advertisement_fields.name = (uint8_t *)ble_svc_gap_device_name(); advertisement_fields.name_len = strlen(ble_svc_gap_device_name()); - #endif advertisement_fields.name_is_complete = 1; @@ -496,15 +526,10 @@ static bool ble_service_advertise(bool enable) return false; } - // We the device address - uint8_t device_addr[6] = {0}; - extern int tls_get_bt_mac_addr(u8 *mac); - tls_get_bt_mac_addr(device_addr); + // We set the device address + const uint8_t *device_mac_address = ble_service_get_device_mac_address(); - // Make sure the the device address is compliant with the random address specification : - device_addr[5] |= 0xC0; - - if((status = ble_hs_id_set_rnd(device_addr)) != BLE_HS_ENOERR) + if((status = ble_hs_id_set_rnd(device_mac_address)) != BLE_HS_ENOERR) { TLS_BT_APPL_TRACE_ERROR("%s, ble_hs_id_set_rnd failed : %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status)); return false; @@ -513,12 +538,12 @@ static bool ble_service_advertise(bool enable) { TLS_BT_APPL_TRACE_VERBOSE("addr type : %s"NEW_LINE"device addr : %02X:%02X:%02X:%02X:%02X:%02X"NEW_LINE, tls_bt_addr_type_2_str(own_addr_type), - device_addr[5], - device_addr[4], - device_addr[3], - device_addr[2], - device_addr[1], - device_addr[0]); + device_mac_address[5], + device_mac_address[4], + device_mac_address[3], + device_mac_address[2], + device_mac_address[1], + device_mac_address[0]); } // We are now ready to configure the advertisement parameters @@ -575,6 +600,12 @@ static int ble_gap_event_cb(struct ble_gap_event *event, void *arg) usable_mtu = USABLE_DEFAULT_MTU; ble_device_conn_handle = event->connect.conn_handle; + // We register an event callback on the connection, + // this allows to be notified on the passkey action event + if((status = ble_gap_set_event_cb(event->connect.conn_handle, &(ble_conn_gap_event_cb), NULL)) != BLE_HS_ENOERR) + { + TLS_BT_APPL_TRACE_WARNING("%s, ble_gap_set_event_cb %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status)); + } //We call the state change callback if registered if(_ble_service_state_change_cb)_ble_service_state_change_cb(_ble_service_state); } @@ -645,7 +676,7 @@ static int ble_gap_event_cb(struct ble_gap_event *event, void *arg) if(_ble_service_state_change_cb)_ble_service_state_change_cb(_ble_service_state); break; case BLE_GAP_EVENT_CONN_UPDATE: - TLS_BT_APPL_TRACE_DEBUG("Conn update status : %d"NEW_LINE, event->conn_update.status); + TLS_BT_APPL_TRACE_DEBUG("Conn update status : %s"NEW_LINE, tls_bt_rc_2_str(event->conn_update.status)); if((status = ble_gap_conn_find(event->connect.conn_handle, &desc)) == BLE_HS_ENOERR) { print_conn_desc(&desc); @@ -680,7 +711,6 @@ static int ble_gap_event_cb(struct ble_gap_event *event, void *arg) //We call the state change callback if registered if(_ble_service_state_change_cb)_ble_service_state_change_cb(BLE_SERVICE_MODE_UNSUBSCRIBED); } - } break; case BLE_GAP_EVENT_MTU: @@ -739,6 +769,136 @@ static int ble_advertise_gap_event_cb(struct ble_gap_event *event, void *arg) return BLE_HS_ENOERR; } +static int ble_conn_gap_event_cb(struct ble_gap_event *event, void *arg) +{ + int status = BLE_HS_ENOERR; + struct ble_gap_conn_desc desc; + + TLS_BT_APPL_TRACE_EVENT("%s : %s"NEW_LINE, __FUNCTION__, tls_bt_gap_evt_2_str(event->type)); + + switch(event->type) + { + case BLE_GAP_EVENT_PASSKEY_ACTION: + TLS_BT_APPL_TRACE_VERBOSE("conn_handle : %u"NEW_LINE + "action : %s"NEW_LINE, + event->passkey.conn_handle, + tls_bt_sm_ioact_2_str(event->passkey.params.action)); + + if(BLE_SM_IOACT_NUMCMP == event->passkey.params.action) + { + TLS_BT_APPL_TRACE_VERBOSE("numcmp : %u"NEW_LINE, + event->passkey.params.numcmp); + } + + struct ble_sm_io sm_io = { + .action = BLE_SM_IOACT_DISP, + .passkey = _pairing_passkey, + }; + + if((status = ble_sm_inject_io(event->passkey.conn_handle, &sm_io)) != BLE_HS_ENOERR) + { + TLS_BT_APPL_TRACE_ERROR("%s, ble_sm_inject_io %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status)); + } + break; + case BLE_GAP_EVENT_CONN_UPDATE: + TLS_BT_APPL_TRACE_DEBUG("Conn update status : %s"NEW_LINE, tls_bt_rc_2_str(event->conn_update.status)); + if((status = ble_gap_conn_find(event->connect.conn_handle, &desc)) == BLE_HS_ENOERR) + { + print_conn_desc(&desc); + } + else + { + TLS_BT_APPL_TRACE_WARNING("%s, ble_gap_conn_find %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status)); + } + break; + case BLE_GAP_EVENT_ENC_CHANGE: + TLS_BT_APPL_TRACE_DEBUG("Enc change status : (%u) -> %s"NEW_LINE, event->enc_change.status, tls_bt_rc_2_str(event->enc_change.status)); + break; + case BLE_GAP_EVENT_REPEAT_PAIRING: + { + // If this event is triggered, then we shall remove the device from the bonded device list + // and tell it to pair again. + uint16_t conn_handle = event->repeat_pairing.conn_handle; + TLS_BT_APPL_TRACE_VERBOSE("conn_handle : %u"NEW_LINE + "cur_key_size : %u"NEW_LINE + "cur_authenticated : %u"NEW_LINE + "cur_sc : %u"NEW_LINE + "new_key_size : %u"NEW_LINE + "new_authenticated : %u"NEW_LINE + "new_sc : %u"NEW_LINE + "new_bonding : %u"NEW_LINE, + event->repeat_pairing.conn_handle, + event->repeat_pairing.cur_key_size, + event->repeat_pairing.cur_authenticated, + event->repeat_pairing.cur_sc, + event->repeat_pairing.new_key_size, + event->repeat_pairing.new_authenticated, + event->repeat_pairing.new_sc, + event->repeat_pairing.new_bonding); + + if((status = ble_gap_conn_find(conn_handle, &desc)) != BLE_HS_ENOERR) + { + TLS_BT_APPL_TRACE_ERROR("%s, ble_gap_conn_find %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status)); + return status; + } + + TLS_BT_APPL_TRACE_VERBOSE("sec_state_encrypted : %u"NEW_LINE + "sec_state_authenticated : %u"NEW_LINE + "sec_state_bonded : %u"NEW_LINE + "sec_state_key_size : %u"NEW_LINE + "our_id_addr(%u) : %02X:%02X:%02X:%02X:%02X:%02X"NEW_LINE + "our_ota_addr(%u) : %02X:%02X:%02X:%02X:%02X:%02X"NEW_LINE + "peer_id_addr(%u) : %02X:%02X:%02X:%02X:%02X:%02X"NEW_LINE + "peer_ota_addr(%u) : %02X:%02X:%02X:%02X:%02X:%02X"NEW_LINE, + desc.sec_state.encrypted, + desc.sec_state.authenticated, + desc.sec_state.bonded, + desc.sec_state.key_size, + desc.our_id_addr.type, + desc.our_id_addr.val[5], + desc.our_id_addr.val[4], + desc.our_id_addr.val[3], + desc.our_id_addr.val[2], + desc.our_id_addr.val[1], + desc.our_id_addr.val[0], + desc.our_ota_addr.type, + desc.our_ota_addr.val[5], + desc.our_ota_addr.val[4], + desc.our_ota_addr.val[3], + desc.our_ota_addr.val[2], + desc.our_ota_addr.val[1], + desc.our_ota_addr.val[0], + desc.peer_id_addr.type, + desc.peer_id_addr.val[5], + desc.peer_id_addr.val[4], + desc.peer_id_addr.val[3], + desc.peer_id_addr.val[2], + desc.peer_id_addr.val[1], + desc.peer_id_addr.val[0], + desc.peer_ota_addr.type, + desc.peer_ota_addr.val[5], + desc.peer_ota_addr.val[4], + desc.peer_ota_addr.val[3], + desc.peer_ota_addr.val[2], + desc.peer_ota_addr.val[1], + desc.peer_ota_addr.val[0]); + + if((status = ble_gap_unpair(&desc.peer_id_addr)) != BLE_HS_ENOERR) + { + TLS_BT_APPL_TRACE_ERROR("%s, ble_gap_unpair %s"NEW_LINE, __FUNCTION__, tls_bt_rc_2_str(status)); + return status; + } + + return BLE_GAP_REPEAT_PAIRING_RETRY; + } + break; + default: + TLS_BT_APPL_TRACE_WARNING("unhandled event !"NEW_LINE); + } + + return BLE_HS_ENOERR; +} + static int battery_level_char_access_cb(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { int status = BLE_HS_ENOERR; diff --git a/src/W800_SDK_v1.00.10/app/ble/ble_service.h b/src/W800_SDK_v1.00.10/app/ble/ble_service.h index 8cfe4a4..df12d16 100644 --- a/src/W800_SDK_v1.00.10/app/ble/ble_service.h +++ b/src/W800_SDK_v1.00.10/app/ble/ble_service.h @@ -63,6 +63,13 @@ bool ble_service_is_started(void); */ bool ble_service_is_device_connected(void); +/** + * @brief Returns the MAC address of the BLE device. + * + * @return a pointer to a constant array of size 6 containing the address. + */ +const uint8_t *ble_service_get_device_mac_address(void); + /** * @brief Registers a callback function called every time the state of the BLE service changes. * For example, you can register a callback to know if a device connected to the service, or disconnected @@ -72,12 +79,27 @@ bool ble_service_is_device_connected(void); void ble_service_register_state_change_cb(ble_service_state_change_fn_t ble_service_state_change_cb); /** - * @brief Returns the current state of the ble service + * @brief Returns the current state of the ble service. * - * @return ble_service_state_e + * @return ble_service_state_e enum value */ ble_service_state_e ble_service_get_state(void); +/** + * @brief Sets the passkey which is asked by the phone when trying to pair the device for the first time. + * + * @param passkey the passkey to set, might be mandatory to be a 6 digit number. + */ +void ble_service_set_pairing_passkey(uint32_t passkey); + +/** + * @brief Returns the passkey needed for pairing which was previously set by the @ref ble_service_set_pairing_passkey + * function. + * + * @return uint32_t the number representing the passkey. + */ +uint32_t ble_service_get_active_pairing_passkey(void); + /** * @brief Asks to update the current connection parameters * /!\ A connection should be already active before calling this function.