This is an automated email from the ASF dual-hosted git repository. janc pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-documentation.git
The following commit(s) were added to refs/heads/master by this push: new 2b5a015 Fixed BLE Peripheral Project - Characteristic Access 2b5a015 is described below commit 2b5a01588ec7b87a343e58cc281f9a1c297d0cad Author: Krzysztof Kopyściński <krzysztof.kopyscin...@codecoup.pl> AuthorDate: Wed Mar 18 13:21:13 2020 +0100 Fixed BLE Peripheral Project - Characteristic Access - Tutorial accomodated to changes from commit 8fe77a4 - Functions updated to current version of mynewt-nimble/apps/bleprph - Edited table contents to fit rest of changes - Tutorial text changes commenting new syntax - Tutorial text deletions commenting removed/swapped code snippets - bleprph is part of nimble, not core --- .../ble/bleprph/bleprph-sections/bleprph-app.rst | 2 +- .../bleprph-sections/bleprph-chr-access.rst | 248 +++++++++------------ docs/tutorials/ble/bleprph/bleprph.rst | 2 +- 3 files changed, 106 insertions(+), 146 deletions(-) diff --git a/docs/tutorials/ble/bleprph/bleprph-sections/bleprph-app.rst b/docs/tutorials/ble/bleprph/bleprph-sections/bleprph-app.rst index 9ded59d..4bd8498 100644 --- a/docs/tutorials/ble/bleprph/bleprph-sections/bleprph-app.rst +++ b/docs/tutorials/ble/bleprph/bleprph-sections/bleprph-app.rst @@ -34,7 +34,7 @@ Peripheral $ newt target set myperiph bsp=@apache-mynewt-core/hw/bsp/nrf52dk Target targets/myperiph successfully set target.bsp to @apache-mynewt-core/hw/bsp/nrf52dk $ newt target set myperiph app=@apache-mynewt-core/apps/bleprph - Target targets/myperiph successfully set target.app to @apache-mynewt-core/apps/bleprph + Target targets/myperiph successfully set target.app to @apache-mynewt-nimble/apps/bleprph $ newt target set myperiph build_profile=optimized Target targets/myperiph successfully set target.build_profile to optimized $ newt build myperiph diff --git a/docs/tutorials/ble/bleprph/bleprph-sections/bleprph-chr-access.rst b/docs/tutorials/ble/bleprph/bleprph-sections/bleprph-chr-access.rst index 0e34078..b2beacf 100644 --- a/docs/tutorials/ble/bleprph/bleprph-sections/bleprph-chr-access.rst +++ b/docs/tutorials/ble/bleprph/bleprph-sections/bleprph-chr-access.rst @@ -23,19 +23,20 @@ few characteristics in this service. static const struct ble_gatt_svc_def gatt_svr_svcs[] = { { - /*** Service: GAP. */ + /*** Service: Security test. */ .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid128 = BLE_UUID16(BLE_GAP_SVC_UUID16), + .uuid = &gatt_svr_svc_sec_test_uuid.u, .characteristics = (struct ble_gatt_chr_def[]) { { - /*** Characteristic: Device Name. */ - .uuid128 = BLE_UUID16(BLE_GAP_CHR_UUID16_DEVICE_NAME), - .access_cb = gatt_svr_chr_access_gap, - .flags = BLE_GATT_CHR_F_READ, + /*** Characteristic: Random number generator. */ + .uuid = &gatt_svr_chr_sec_test_rand_uuid.u, + .access_cb = gatt_svr_chr_access_sec_test, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC, }, { - /*** Characteristic: Appearance. */ - .uuid128 = BLE_UUID16(BLE_GAP_CHR_UUID16_APPEARANCE), - .access_cb = gatt_svr_chr_access_gap, - .flags = BLE_GATT_CHR_F_READ, + /*** Characteristic: Static value. */ + .uuid = gatt_svr_chr_sec_test_static_uuid.u, + .access_cb = gatt_svr_chr_access_sec_test, + .flags = BLE_GATT_CHR_F_READ | + BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC, }, { // [...] @@ -48,55 +49,55 @@ characteristics use: .. code:: c static int - gatt_svr_chr_access_gap(uint16_t conn_handle, uint16_t attr_handle, uint8_t op, - union ble_gatt_access_ctxt *ctxt, void *arg) + gatt_svr_chr_access_sec_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) { - uint16_t uuid16; - - uuid16 = ble_uuid_128_to_16(ctxt->chr_access.chr->uuid128); - assert(uuid16 != 0); - - switch (uuid16) { - case BLE_GAP_CHR_UUID16_DEVICE_NAME: - assert(op == BLE_GATT_ACCESS_OP_READ_CHR); - ctxt->chr_access.data = (void *)bleprph_device_name; - ctxt->chr_access.len = strlen(bleprph_device_name); - break; - - case BLE_GAP_CHR_UUID16_APPEARANCE: - assert(op == BLE_GATT_ACCESS_OP_READ_CHR); - ctxt->chr_access.data = (void *)&bleprph_appearance; - ctxt->chr_access.len = sizeof bleprph_appearance; - break; - - case BLE_GAP_CHR_UUID16_PERIPH_PRIV_FLAG: - assert(op == BLE_GATT_ACCESS_OP_READ_CHR); - ctxt->chr_access.data = (void *)&bleprph_privacy_flag; - ctxt->chr_access.len = sizeof bleprph_privacy_flag; - break; - - case BLE_GAP_CHR_UUID16_RECONNECT_ADDR: - assert(op == BLE_GATT_ACCESS_OP_WRITE_CHR); - if (ctxt->chr_access.len != sizeof bleprph_reconnect_addr) { - return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + const ble_uuid_t *uuid; + int rand_num; + int rc; + + uuid = ctxt->chr->uuid; + + /* Determine which characteristic is being accessed by examining its + * 128-bit UUID. + */ + + if (ble_uuid_cmp(uuid, &gatt_svr_chr_sec_test_rand_uuid.u) == 0) { + assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); + + /* Respond with a 32-bit random number. */ + rand_num = rand(); + rc = os_mbuf_append(ctxt->om, &rand_num, sizeof rand_num); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + + if (ble_uuid_cmp(uuid, &gatt_svr_chr_sec_test_static_uuid.u) == 0) { + switch (ctxt->op) { + case BLE_GATT_ACCESS_OP_READ_CHR: + rc = os_mbuf_append(ctxt->om, &gatt_svr_sec_test_static_val, + sizeof gatt_svr_sec_test_static_val); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + + case BLE_GATT_ACCESS_OP_WRITE_CHR: + rc = gatt_svr_chr_write(ctxt->om, + sizeof gatt_svr_sec_test_static_val, + sizeof gatt_svr_sec_test_static_val, + &gatt_svr_sec_test_static_val, NULL); + return rc; + + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; } - memcpy(bleprph_reconnect_addr, ctxt->chr_access.data, - sizeof bleprph_reconnect_addr); - break; - - case BLE_GAP_CHR_UUID16_PERIPH_PREF_CONN_PARAMS: - assert(op == BLE_GATT_ACCESS_OP_READ_CHR); - ctxt->chr_access.data = (void *)&bleprph_pref_conn_params; - ctxt->chr_access.len = sizeof bleprph_pref_conn_params; - break; - - default: - assert(0); - break; } - return 0; - } + /* Unknown characteristic; the nimble stack should not have called this + * function. + */ + assert(0); + return BLE_ATT_ERR_UNLIKELY; +} After you've taken a moment to examine the structure of this function, let's explore some details. @@ -107,8 +108,8 @@ Function signature .. code:: c static int - gatt_svr_chr_access_gap(uint16_t conn_handle, uint16_t attr_handle, uint8_t op, - union ble_gatt_access_ctxt *ctxt, void *arg) + gatt_svr_chr_access_sec_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) A characteristic access function always takes this same set of parameters and always returns an int. The parameters to this function @@ -141,17 +142,6 @@ type are documented below. | | | a UUID | | | | lookup. | +----------------+--------------+------------+ -| op | Indicates | Valid | -| | whether this | values | -| | is a read or | are:\ *BLE | -| | write | \_GATT\_AC | -| | operation | CESS\_OP\_ | -| | | READ\_CHR* | -| | | \ \ *BLE\_ | -| | | GATT\_ACCE | -| | | SS\_OP\_WR | -| | | ITE\_CHR* | -+----------------+--------------+------------+ | ctxt | Contains the | For | | | characterist | characteri | | | ic | stic | @@ -181,18 +171,11 @@ Determine characteristic being accessed .. code:: c - { - uint16_t uuid16; - - uuid16 = ble_uuid_128_to_16(ctxt->chr_access.chr->uuid128); - assert(uuid16 != 0); - - switch (uuid16) { - // [...] + ble_uuid_cmp(uuid, &gatt_svr_chr_sec_test_rand_uuid.u) -This function uses the UUID to determine which characteristic is being -accessed. There are two alternative methods *bleprph* could have used to -accomplish this task: +The function compares UUID with UUIDs of characteristic - if it fits, +characteristic is being accessed. There are two alternative methods *bleprph* +could have used to accomplish this task: - Map characteristics to ATT handles during service registration; use the *attr\_handle* parameter as a key into this table during @@ -200,87 +183,64 @@ accomplish this task: - Implement a dedicated function for each characteristic; each function inherently knows which characteristic it corresponds to. -All the GAP service characteristics have 16-bit UUIDs, so this function -uses the *ble\_uuid\_128\_to\_16()* function to convert the 128-bit UUID -to its corresponding 16-bit UUID. This conversion function returns the -corresponding 16-bit UUID on success, or 0 on failure. Success is -asserted here to ensure the NimBLE stack is doing its job properly; the -stack should only call this function for accesses to characteristics -that it is registered with, and all GAP service characteristics have -valid 16-bit UUIDs. - Read access ^^^^^^^^^^^ .. code:: c - case BLE_GAP_CHR_UUID16_DEVICE_NAME: - assert(op == BLE_GATT_ACCESS_OP_READ_CHR); - ctxt->chr_access.data = (void *)bleprph_device_name; - ctxt->chr_access.len = strlen(bleprph_device_name); - break; + case BLE_GATT_ACCESS_OP_READ_CHR: + rc = os_mbuf_append(ctxt->om, &gatt_svr_sec_test_static_val, + sizeof gatt_svr_sec_test_static_val); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + -This code excerpt handles read accesses to the device name -characteristic. The *assert()* here is another case of making sure the +This code excerpt handles read accesses to the device characteristic. +*ctxt->om* is chained memory buffer that for reads is being populated +with characteristic data. Returned value is either 0 for success or +*BLE_ATT_ERR_INSUFFICIENT_RES* if failed. The check makes sure the NimBLE stack is doing its job; this characteristic was registered as read-only, so the stack should have prevented write accesses. -To fulfill a characteristic read request, the application needs to -assign the *ctxt->chr\_access.data* field to point to the attribute data -to respond with, and fill the *ctxt->chr\_access.len* field with the -length of the attribute data. *bleprph* stores the device name in -read-only memory as follows: - -.. code:: c - - const char *bleprph_device_name = "nimble-bleprph"; - -The cast to pointer-to-void is a necessary annoyance to remove the -*const* qualifier from the device name variable. You will need to "cast -away const" whenever you respond to read requests with read-only data. - -It is not shown in the above snippet, but this function ultimately -returns 0. By returning 0, *bleprph* indicates that the characteristic -data in *ctxt->chr\_access* is valid and that NimBLE should include it -in its response to the peer. - -**A word of warning:** The attribute data that *ctxt->chr\_access.data* -points to must remain valid after the access function returns, as the -NimBLE stack needs to use it to form a GATT read response. In other -words, you must not allocate the characteristic value data on the stack -of the access function. Two characteristic accesses never occur at the -same time, so it is OK to use the same memory for repeated accesses. - Write access ^^^^^^^^^^^^ .. code:: c + + static int + gatt_svr_chr_write(struct os_mbuf *om, uint16_t min_len, uint16_t max_len, + void *dst, uint16_t *len) + { + uint16_t om_len; + int rc; - case BLE_GAP_CHR_UUID16_RECONNECT_ADDR: - assert(op == BLE_GATT_ACCESS_OP_WRITE_CHR); - if (ctxt->chr_access.len != sizeof bleprph_reconnect_addr) { - return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; - } - memcpy(bleprph_reconnect_addr, ctxt->chr_access.data, - sizeof bleprph_reconnect_addr); - break; + om_len = OS_MBUF_PKTLEN(om); + if (om_len < min_len || om_len > max_len) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } -This code excerpt handles writes to the reconnect address -characteristic. This characteristic was registered as write-only, so the -*assert()* here is just a safety precaution to ensure the NimBLE stack + rc = ble_hs_mbuf_to_flat(om, dst, max_len, len); + if (rc != 0) { + return BLE_ATT_ERR_UNLIKELY; + } + + return 0; + } + // [...] + case BLE_GATT_ACCESS_OP_WRITE_CHR: + rc = gatt_svr_chr_write(ctxt->om, + sizeof gatt_svr_sec_test_static_val, + sizeof gatt_svr_sec_test_static_val, + &gatt_svr_sec_test_static_val, NULL); + return rc; + +This code excerpt handles writes to the Static value +characteristic. This characteristic was registered as read-write, so the +*return rc* here is just a safety precaution to ensure the NimBLE stack is doing its job. -For writes, the roles of the *ctxt->chr\_access.data* and -*ctxt->chr\_access.len* fields are the reverse of the read case. The -NimBLE stack uses these fields to indicate the data written by the peer. +Data is written to the *ctxt->om* buffer from *gatt_svr_sec_test_static_val* +by ``ble_hs_mbuf_to_flat()`` function. If length of written data greater or +smaller than length of *gatt_svr_sec_test_static_val*, function return error. Many characteristics have strict length requirements for write -operations. This characteristic has such a restriction; if the written -data is not a 48-bit BR address, the application tells NimBLE to respond -with an invalid attribute value length error. - -For writes, the *ctxt->chr\_access.data* pointer is only valid for the -duration of the access function. If the application needs to save the -written data, it should store it elsewhere before the function returns. -In this case, *bleprph* stores the specified address in a global -variable called *bleprph\_reconnect\_addr*. +operations. \ No newline at end of file diff --git a/docs/tutorials/ble/bleprph/bleprph.rst b/docs/tutorials/ble/bleprph/bleprph.rst index 0295535..84b37aa 100644 --- a/docs/tutorials/ble/bleprph/bleprph.rst +++ b/docs/tutorials/ble/bleprph/bleprph.rst @@ -20,7 +20,7 @@ Introduction Overview ^^^^^^^^ -*bleprph* is an example app included in the apache-mynewt-core +*bleprph* is an example app included in the apache-mynewt-nimble repository. This app implements a simple BLE peripheral with the following properties: