diff --git a/nimble/host/services/gap/include/services/gap/ble_svc_gap.h b/nimble/host/services/gap/include/services/gap/ble_svc_gap.h index 29bbf4863..d31a3b892 100644 --- a/nimble/host/services/gap/include/services/gap/ble_svc_gap.h +++ b/nimble/host/services/gap/include/services/gap/ble_svc_gap.h @@ -41,6 +41,7 @@ void ble_svc_gap_set_chr_changed_cb(ble_svc_gap_chr_changed_fn *cb); const char *ble_svc_gap_device_name(void); int ble_svc_gap_device_name_set(const char *name); uint16_t ble_svc_gap_device_appearance(void); +int ble_svc_gap_device_appearance_set(uint16_t appearance); void ble_svc_gap_init(void); diff --git a/nimble/host/services/gap/src/ble_svc_gap.c b/nimble/host/services/gap/src/ble_svc_gap.c index 7f2818cab..bfdd0cf49 100644 --- a/nimble/host/services/gap/src/ble_svc_gap.c +++ b/nimble/host/services/gap/src/ble_svc_gap.c @@ -39,8 +39,7 @@ static ble_svc_gap_chr_changed_fn *ble_svc_gap_chr_changed_cb_fn; static char ble_svc_gap_name[BLE_SVC_GAP_NAME_MAX_LEN + 1] = MYNEWT_VAL(BLE_SVC_GAP_DEVICE_NAME); -static const uint16_t ble_svc_gap_appearance = - MYNEWT_VAL(BLE_SVC_GAP_APPEARANCE); +static uint16_t ble_svc_gap_appearance = MYNEWT_VAL(BLE_SVC_GAP_APPEARANCE); static int ble_svc_gap_access(uint16_t conn_handle, uint16_t attr_handle, @@ -65,7 +64,12 @@ static const struct ble_gatt_svc_def ble_svc_gap_defs[] = { /*** Characteristic: Appearance. */ .uuid = BLE_UUID16_DECLARE(BLE_SVC_GAP_CHR_UUID16_APPEARANCE), .access_cb = ble_svc_gap_access, - .flags = BLE_GATT_CHR_F_READ, + .flags = BLE_GATT_CHR_F_READ | +#if MYNEWT_VAL(BLE_SVC_GAP_APPEARANCE_WRITE_PERM) >= 0 + BLE_GATT_CHR_F_WRITE | + MYNEWT_VAL(BLE_SVC_GAP_APPEARANCE_WRITE_PERM) | +#endif + 0, }, { #if PPCP_ENABLED /*** Characteristic: Peripheral Preferred Connection Parameters. */ @@ -131,12 +135,52 @@ ble_svc_gap_device_name_write_access(struct ble_gatt_access_ctxt *ctxt) #endif } +static int +ble_svc_gap_appearance_read_access(struct ble_gatt_access_ctxt *ctxt) +{ + uint16_t appearance = htole16(ble_svc_gap_appearance); + int rc; + + rc = os_mbuf_append(ctxt->om, &appearance, sizeof(appearance)); + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_gap_appearance_write_access(struct ble_gatt_access_ctxt *ctxt) +{ +#if MYNEWT_VAL(BLE_SVC_GAP_APPEARANCE_WRITE_PERM) < 0 + assert(0); + return 0; +#else + uint16_t om_len; + int rc; + + om_len = OS_MBUF_PKTLEN(ctxt->om); + if (om_len != sizeof(ble_svc_gap_appearance)) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + + rc = ble_hs_mbuf_to_flat(ctxt->om, ble_svc_gap_appearance, om_len, NULL); + if (rc != 0) { + return BLE_ATT_ERR_UNLIKELY; + } + + ble_svc_gap_appearance = le16toh(ble_svc_gap_appearance); + + if (ble_svc_gap_chr_changed_cb_fn) { + ble_svc_gap_chr_changed_cb_fn(BLE_SVC_GAP_CHR_UUID16_APPEARANCE); + } + + return rc; +#endif +} + static int ble_svc_gap_access(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { uint16_t uuid16; - uint16_t appearance = htole16(ble_svc_gap_appearance); #if MYNEWT_VAL(BLE_SVC_GAP_CENTRAL_ADDRESS_RESOLUTION) >= 0 uint8_t central_ar = MYNEWT_VAL(BLE_SVC_GAP_CENTRAL_ADDRESS_RESOLUTION); #endif @@ -165,9 +209,14 @@ ble_svc_gap_access(uint16_t conn_handle, uint16_t attr_handle, return rc; case BLE_SVC_GAP_CHR_UUID16_APPEARANCE: - assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); - rc = os_mbuf_append(ctxt->om, &appearance, sizeof(appearance)); - return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = ble_svc_gap_appearance_read_access(ctxt); + } else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + rc = ble_svc_gap_appearance_write_access(ctxt); + } else { + assert(0); + } + return rc; #if PPCP_ENABLED case BLE_SVC_GAP_CHR_UUID16_PERIPH_PREF_CONN_PARAMS: @@ -217,6 +266,14 @@ ble_svc_gap_device_appearance(void) return ble_svc_gap_appearance; } +int +ble_svc_gap_device_appearance_set(uint16_t appearance) +{ + ble_svc_gap_appearance = appearance; + + return 0; +} + void ble_svc_gap_set_chr_changed_cb(ble_svc_gap_chr_changed_fn *cb) { diff --git a/nimble/host/services/gap/syscfg.yml b/nimble/host/services/gap/syscfg.yml index c9c93805a..11aeaa94c 100644 --- a/nimble/host/services/gap/syscfg.yml +++ b/nimble/host/services/gap/syscfg.yml @@ -36,6 +36,15 @@ syscfg.defs: BLE_SVC_GAP_APPEARANCE: description: 'Device appearance' value: 0 + BLE_SVC_GAP_APPEARANCE_WRITE_PERM: + description: > + Defines permissions for writing "Appearance" characteristics. Can + be zero to allow write without extra permissions or combination of: + BLE_GATT_CHR_F_WRITE_ENC + BLE_GATT_CHR_F_WRITE_AUTHEN + BLE_GATT_CHR_F_WRITE_AUTHOR + Set to '-1' to make characteristic read only. + value: -1 # Setting all values for PPCP to '0' will disable characteristic! BLE_SVC_GAP_PPCP_MIN_CONN_INTERVAL: