static uint32_t name_encode(const ble_advdata_t * p_advdata, uint8_t * p_encoded_data, uint8_t * p_len) { uint32_t err_code; uint16_t name_length = BLE_GAP_ADV_MAX_SIZE - (2 + *p_len); uint8_t adv_data_format; // Get GAP device name err_code = sd_ble_gap_device_name_get(&p_encoded_data[*p_len + 2], &name_length); if (err_code != NRF_SUCCESS) { return err_code; } // Compute length and type of name field if ((p_advdata->short_name_len != 0) && (name_length > p_advdata->short_name_len)) { name_length = p_advdata->short_name_len; adv_data_format = BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME; } else { adv_data_format = BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME; } // Complete name field in encoded data p_encoded_data[(*p_len)++] = name_length + 1; p_encoded_data[(*p_len)++] = adv_data_format; (*p_len) += name_length; return NRF_SUCCESS; }
uint32_t conn_mw_ble_gap_device_name_get(uint8_t const * const p_rx_buf, uint32_t rx_buf_len, uint8_t * const p_tx_buf, uint32_t * const p_tx_buf_len) { SER_ASSERT_NOT_NULL(p_rx_buf); SER_ASSERT_NOT_NULL(p_tx_buf); SER_ASSERT_NOT_NULL(p_tx_buf_len); uint32_t err_code = NRF_SUCCESS; uint32_t sd_err_code; uint8_t dev_name[BLE_GAP_DEVNAME_MAX_LEN]; uint8_t * p_dev_name = dev_name; uint16_t len; uint16_t * p_len = &len; err_code = ble_gap_device_name_get_req_dec(p_rx_buf, rx_buf_len, &p_dev_name, &p_len); SER_ASSERT(err_code == NRF_SUCCESS, err_code); sd_err_code = sd_ble_gap_device_name_get(p_dev_name, p_len); err_code = ble_gap_device_name_get_rsp_enc(sd_err_code, p_dev_name, p_len, p_tx_buf, p_tx_buf_len); SER_ASSERT(err_code == NRF_SUCCESS, err_code); return err_code; }
ble_error_t nRF5xGap::getDeviceName(uint8_t *deviceName, unsigned *lengthP) { if (sd_ble_gap_device_name_get(deviceName, (uint16_t *)lengthP) == NRF_SUCCESS) { return BLE_ERROR_NONE; } else { return BLE_ERROR_PARAM_OUT_OF_RANGE; } }
/**@brief Function for the Advertising functionality initialization. * * @details Encodes the required advertising data and passes it to the stack. * The advertising data encoded here is specific for DFU. * Setting advertising data can by done by calling @ref ble_advdata_set. */ static uint32_t advertising_init(uint8_t adv_flags) { uint32_t err_code; uint16_t len_advdata = 9; uint16_t max_device_name_length = MAX_ADV_DATA_LENGTH - len_advdata; uint16_t actual_device_name_length = max_device_name_length; uint8_t p_encoded_advdata[MAX_ADV_DATA_LENGTH]; // Encode flags. p_encoded_advdata[0] = 0x2; p_encoded_advdata[1] = BLE_GAP_AD_TYPE_FLAGS; p_encoded_advdata[2] = adv_flags; // Encode 'more available' uuid list. p_encoded_advdata[3] = 0x3; p_encoded_advdata[4] = BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE; p_encoded_advdata[5] = LSB_16(BLE_DFU_SERVICE_UUID); p_encoded_advdata[6] = MSB_16(BLE_DFU_SERVICE_UUID); // Get GAP device name and length err_code = sd_ble_gap_device_name_get(&p_encoded_advdata[9], &actual_device_name_length); if (err_code != NRF_SUCCESS) { return err_code; } // Set GAP device in advertising data. if (actual_device_name_length <= max_device_name_length) { p_encoded_advdata[7] = actual_device_name_length + 1; // (actual_length + ADV_AD_TYPE_FIELD_SIZE(1)) p_encoded_advdata[8] = BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME; len_advdata += actual_device_name_length; } else { // Must use a shorter advertising name than the actual name of the device p_encoded_advdata[7] = max_device_name_length + 1; // (length + ADV_AD_TYPE_FIELD_SIZE(1)) p_encoded_advdata[8] = BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME; len_advdata = MAX_ADV_DATA_LENGTH; } return sd_ble_gap_adv_data_set(p_encoded_advdata, len_advdata, NULL, 0); }
/**@brief Function for decoding a command packet with RPC_SD_BLE_GAP_DEVICE_NAME_GET opcode. * * This function will decode the command, call the BLE Stack API, and also send command response * to the peer through the the transport layer. * * @param[in] p_command The encoded structure that needs to be decoded and passed on * to the BLE Stack API. * @param[in] command_len The length of the encoded command read from transport layer. * * @retval NRF_SUCCESS If the decoding of the command was successful, the SoftDevice * API was called, and the command response was sent to peer, * otherwise an error code. * @retval NRF_ERROR_INVALID_LENGTH If the content length of the packet is not conforming to the * codec specification. */ static uint32_t gap_device_name_get_handle(uint8_t * p_command, uint32_t command_len) { uint32_t err_code; uint16_t dev_name_len = 0; uint32_t index = 0; // Two bytes will be reserved for the length of device name. uint8_t resp_data[BLE_GAP_DEVNAME_MAX_LEN + sizeof(dev_name_len)]; // Pointer to the device name length variable. uint8_t * p_dev_name = &(resp_data[2]); // Pointer to the device name target. uint16_t * p_dev_name_len = &(dev_name_len); // Length present. if (p_command[index++] == RPC_BLE_FIELD_PRESENT) { RPC_DECODER_LENGTH_CHECK(command_len, index, SD_BLE_GAP_DEVICE_NAME_GET); // Use the remote buffer size when calling the SoftDevice to make sure the caller has // enough memory allocated. *p_dev_name_len = uint16_decode(&p_command[index]); index += sizeof(uint16_t); RPC_DECODER_LENGTH_CHECK(command_len, index, SD_BLE_GAP_DEVICE_NAME_GET); // Verify that the remote buffer size is smaller or equal to the local buffer size. if (*p_dev_name_len > BLE_GAP_DEVNAME_MAX_LEN) { return ble_rpc_cmd_resp_send(SD_BLE_GAP_DEVICE_NAME_GET, NRF_ERROR_INVALID_LENGTH); } } else { RPC_DECODER_LENGTH_CHECK(command_len, index, SD_BLE_GAP_DEVICE_NAME_GET); p_dev_name_len = NULL; } // Remote result buffer is present. if (p_command[index++] == RPC_BLE_FIELD_NOT_PRESENT) { p_dev_name = NULL; } RPC_DECODER_LENGTH_CHECK(command_len, index, SD_BLE_GAP_DEVICE_NAME_GET); err_code = sd_ble_gap_device_name_get(p_dev_name, p_dev_name_len); if (err_code == NRF_SUCCESS) { // Encode the length. UNUSED_VARIABLE(uint16_encode(*p_dev_name_len, &resp_data[0])); // Calculate the total size of the device name and the device name length bytes. uint16_t total_len = uint16_decode(&resp_data[0]); total_len += sizeof(total_len); return ble_rpc_cmd_resp_data_send(SD_BLE_GAP_DEVICE_NAME_GET, NRF_SUCCESS, resp_data, total_len); } return ble_rpc_cmd_resp_send(SD_BLE_GAP_DEVICE_NAME_GET, err_code); }
static uint32_t name_encode(const ble_advdata_t * p_advdata, uint8_t * p_encoded_data, uint8_t * p_len) { uint32_t err_code; uint16_t rem_adv_data_len; uint16_t actual_length; uint8_t adv_data_format; uint8_t adv_offset; adv_offset = *p_len; // Check for buffer overflow. if ((adv_offset + ADV_DATA_OFFSET > BLE_GAP_ADV_MAX_SIZE) || ((p_advdata->short_name_len + ADV_DATA_OFFSET) > BLE_GAP_ADV_MAX_SIZE)) { return NRF_ERROR_DATA_SIZE; } actual_length = rem_adv_data_len = (BLE_GAP_ADV_MAX_SIZE - adv_offset - ADV_FLAG_OFFSET); // Get GAP device name and length err_code = sd_ble_gap_device_name_get(&p_encoded_data[adv_offset + ADV_DATA_OFFSET], &actual_length); if (err_code != NRF_SUCCESS) { return err_code; } // Check if device internd 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; rem_adv_data_len = actual_length; } 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 ((p_advdata->short_name_len != 0) && (p_advdata->short_name_len <= rem_adv_data_len)) { // Short name fits available size. rem_adv_data_len = p_advdata->short_name_len; } // Else whatever can fit the data buffer will be packed. else { rem_adv_data_len = actual_length; } } // Complete name field in encoded data. p_encoded_data[adv_offset++] = rem_adv_data_len + 1; p_encoded_data[adv_offset++] = adv_data_format; (*p_len) += (rem_adv_data_len + ADV_DATA_OFFSET); return NRF_SUCCESS; }
void simble_adv_start(void) { struct ble_gap_advdata advdata = { .length = 0 }; struct ble_gap_ad_flags flags = { .payload_length = 1, .type = BLE_GAP_AD_TYPE_FLAGS, .flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE, }; simble_add_advdata(&flags, &advdata); struct ble_gap_ad_name name; uint16_t namelen = sizeof(advdata); if (sd_ble_gap_device_name_get(name.name, &namelen) != NRF_SUCCESS) namelen = 0; name.type = BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME; name.payload_length = namelen; simble_add_advdata(&name, &advdata); sd_ble_gap_adv_data_set(advdata.data, advdata.length, NULL, 0); ble_gap_adv_params_t adv_params = { .type = BLE_GAP_ADV_TYPE_ADV_IND, .fp = BLE_GAP_ADV_FP_ANY, .interval = 0x400, }; sd_ble_gap_adv_start(&adv_params); onboard_led(ONBOARD_LED_ON); } static void simble_srv_tx_init(void) { uint16_t srv_handle; ble_uuid_t srv_uuid = {.type = BLE_UUID_TYPE_BLE, .uuid = 0x1804}; sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &srv_uuid, &srv_handle); ble_gatts_char_handles_t chr_handles; ble_gatts_char_md_t char_meta = {.char_props = {.read = 1}}; ble_uuid_t chr_uuid = {.type = BLE_UUID_TYPE_BLE, .uuid = 0x2a07}; ble_gatts_attr_md_t chr_attr_meta = { .vloc = BLE_GATTS_VLOC_STACK, }; BLE_GAP_CONN_SEC_MODE_SET_OPEN(&chr_attr_meta.read_perm); BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&chr_attr_meta.write_perm); uint8_t tx_val = 0; ble_gatts_attr_t chr_attr = { .p_uuid = &chr_uuid, .p_attr_md = &chr_attr_meta, .init_offs = 0, .init_len = sizeof(tx_val), .max_len = sizeof(tx_val), .p_value = &tx_val, }; sd_ble_gatts_characteristic_add(srv_handle, &char_meta, &chr_attr, &chr_handles); } /* DM requires a `app_error_handler` */ void __attribute__((weak)) app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t * p_file_name) { app_trace_log("[simble]: err: %d, line: %d, file: %s\r\n", error_code, line_num, p_file_name); for (;;) { /* NOTHING */ } } void simble_init(const char *name) { app_trace_init(); sd_softdevice_enable(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, NULL); /* XXX assertion handler */ ble_enable_params_t ble_params = { #if defined(SD120) .gap_enable_params = { .role = BLE_GAP_ROLE_PERIPH, }, #endif .gatts_enable_params = { .service_changed = 1, }, }; sd_ble_enable(&ble_params); ble_gap_conn_sec_mode_t mode; BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&mode); sd_ble_gap_device_name_set(&mode, (const uint8_t *)name, strlen(name)); // flash storage pstorage_init(); simble_srv_tx_init(); } uint8_t simble_get_vendor_uuid_class(void) { ble_uuid128_t vendorid = {{0x13,0xb0,0xa0,0x71,0xfe,0x62,0x4c,0x01,0xaa,0x4d,0xd8,0x03,0,0,0x0b,0xd0}}; static uint8_t vendor_type = BLE_UUID_TYPE_UNKNOWN; if (vendor_type != BLE_UUID_TYPE_UNKNOWN) return (vendor_type); sd_ble_uuid_vs_add(&vendorid, &vendor_type); return (vendor_type); } void simble_srv_register(struct service_desc *s) { s->next = services; services = s; sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &s->uuid, &s->handle); for (int i = 0; i < s->char_count; ++i) { struct char_desc *c = &s->chars[i]; ble_gatts_attr_md_t cccd_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; int have_write = c->write_cb != NULL; ble_gatts_char_md_t char_meta = { .char_props = { .broadcast = 0, .read = 1, .write_wo_resp = have_write, .write = have_write, .notify = c->notify, .indicate = c->indicate, .auth_signed_wr = have_write, }, .p_char_user_desc = (uint8_t *)c->desc, .char_user_desc_size = strlen(c->desc), .char_user_desc_max_size = strlen(c->desc), .p_char_pf = c->format.format != 0 ? &c->format : NULL, .p_cccd_md = (c->notify || c->indicate) ? &cccd_md : NULL, }; ble_gatts_attr_md_t chr_attr_meta = { .vlen = 1, .vloc = BLE_GATTS_VLOC_STACK, .rd_auth = 1, .wr_auth = 1, }; BLE_GAP_CONN_SEC_MODE_SET_OPEN(&chr_attr_meta.read_perm); if (have_write) BLE_GAP_CONN_SEC_MODE_SET_OPEN(&chr_attr_meta.write_perm); else BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&chr_attr_meta.write_perm); ble_gatts_attr_t chr_attr = { .p_uuid = &c->uuid, .p_attr_md = &chr_attr_meta, .init_offs = 0, .init_len = 0, .max_len = c->length, }; sd_ble_gatts_characteristic_add(s->handle, &char_meta, &chr_attr, &c->handles); } } void simble_srv_init(struct service_desc *s, uint8_t type, uint16_t id) { *s = (struct service_desc){ .uuid = {.type = type, .uuid = id}, .char_count = 0, }; }; void simble_srv_char_add(struct service_desc *s, struct char_desc *c, uint8_t type, uint16_t id, const char *desc, uint16_t length) { *c = (struct char_desc){ .uuid = { .type = type, .uuid = id }, .desc = desc, .length = length, };
static uint32_t name_encode(const ble_advdata_t * p_advdata, uint8_t * p_encoded_data, uint16_t * p_offset, uint16_t max_size) { uint32_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) + ADV_AD_DATA_OFFSET) > max_size) || ( (BLE_ADVDATA_SHORT_NAME == p_advdata->name_type) && (((*p_offset) + ADV_AD_DATA_OFFSET + p_advdata->short_name_len) > max_size))) { return NRF_ERROR_DATA_SIZE; } rem_adv_data_len = max_size - (*p_offset) - ADV_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) + ADV_AD_DATA_OFFSET], &actual_length); if (err_code != NRF_SUCCESS) { return 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 + ADV_AD_TYPE_FIELD_SIZE) if(actual_length > (0x00FF - ADV_AD_TYPE_FIELD_SIZE)) { return NRF_ERROR_DATA_SIZE; } // Complete name field in encoded data. p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE + actual_length); *p_offset += ADV_LENGTH_FIELD_SIZE; p_encoded_data[*p_offset] = adv_data_format; *p_offset += ADV_AD_TYPE_FIELD_SIZE; *p_offset += actual_length; return NRF_SUCCESS; }