apache-mynewt-bot commented on pull request #845: URL: https://github.com/apache/mynewt-nimble/pull/845#issuecomment-660970294
<!-- style-bot --> ## Style check summary ### Our coding style is [here!](https://github.com/apache/mynewt-core/blob/master/CODING_STANDARDS.md) #### apps/bttester/src/bttester.h <details> ```diff @@ -657,53 +647,63 @@ u8_t data[0]; } __packed; -#define GATT_CFG_NOTIFY 0x1a -#define GATT_CFG_INDICATE 0x1b +#define GATT_RELIABLE_WRITE 0x19 +struct gatt_reliable_write_cmd { + u8_t address_type; + u8_t address[6]; + u16_t handle; + u16_t offset; + u16_t data_length; + u8_t data[0]; +} __packed; + +#define GATT_CFG_NOTIFY 0x1a +#define GATT_CFG_INDICATE 0x1b struct gatt_cfg_notify_cmd { - u8_t address_type; - u8_t address[6]; - u8_t enable; - u16_t ccc_handle; -} __packed; - -#define GATT_GET_ATTRIBUTES 0x1c + u8_t address_type; + u8_t address[6]; + u8_t enable; + u16_t ccc_handle; +} __packed; + +#define GATT_GET_ATTRIBUTES 0x1c struct gatt_get_attributes_cmd { - u16_t start_handle; - u16_t end_handle; - u8_t type_length; - u8_t type[0]; + u16_t start_handle; + u16_t end_handle; + u8_t type_length; + u8_t type[0]; } __packed; struct gatt_get_attributes_rp { - u8_t attrs_count; - u8_t attrs[0]; + u8_t attrs_count; + u8_t attrs[0]; } __packed; struct gatt_attr { - u16_t handle; - u8_t permission; - u8_t type_length; - u8_t type[0]; -} __packed; - -#define GATT_GET_ATTRIBUTE_VALUE 0x1d + u16_t handle; + u8_t permission; + u8_t type_length; + u8_t type[0]; +} __packed; + +#define GATT_GET_ATTRIBUTE_VALUE 0x1d struct gatt_get_attribute_value_cmd { - u8_t address_type; - u8_t address[6]; - u16_t handle; + u8_t address_type; + u8_t address[6]; + u16_t handle; } __packed; struct gatt_get_attribute_value_rp { - u8_t att_response; - u16_t value_length; - u8_t value[0]; -} __packed; - -#define GATT_CHANGE_DATABASE 0x1e + u8_t att_response; + u16_t value_length; + u8_t value[0]; +} __packed; + +#define GATT_CHANGE_DATABASE 0x1e struct gatt_change_database { u16_t start_handle; u16_t end_handle; u8_t visibility; } __packed; -#define GATT_READ_MULTIPLE_VAR 0x20 +#define GATT_READ_MULTIPLE_VAR 0x20 struct gatt_read_multiple_var_cmd { u8_t address_type; u8_t address[6]; @@ -712,88 +712,90 @@ } __packed; /* GATT events */ -#define GATT_EV_NOTIFICATION 0x80 +#define GATT_EV_NOTIFICATION 0x80 struct gatt_notification_ev { - u8_t address_type; - u8_t address[6]; - u8_t type; - u16_t handle; - u16_t data_length; - u8_t data[0]; -} __packed; - -#define GATT_EV_ATTR_VALUE_CHANGED 0x81 + u8_t address_type; + u8_t address[6]; + u8_t type; + u16_t handle; + u16_t data_length; + u8_t data[0]; +} __packed; + +#define GATT_EV_ATTR_VALUE_CHANGED 0x81 struct gatt_attr_value_changed_ev { - u16_t handle; - u16_t data_length; - u8_t data[0]; -} __packed; - -static inline void tester_set_bit(u8_t *addr, unsigned int bit) + u16_t handle; + u16_t data_length; + u8_t data[0]; +} __packed; + +static inline void +tester_set_bit(u8_t *addr, unsigned int bit) { - u8_t *p = addr + (bit / 8); - - *p |= BIT(bit % 8); + u8_t *p = addr + (bit / 8); + + *p |= BIT(bit % 8); } -static inline u8_t tester_test_bit(const u8_t *addr, unsigned int bit) +static inline u8_t +tester_test_bit(const u8_t *addr, unsigned int bit) { - const u8_t *p = addr + (bit / 8); - - return *p & BIT(bit % 8); + const u8_t *p = addr + (bit / 8); + + return *p & BIT(bit % 8); } /* L2CAP Service */ /* commands */ -#define L2CAP_READ_SUPPORTED_COMMANDS 0x01 +#define L2CAP_READ_SUPPORTED_COMMANDS 0x01 struct l2cap_read_supported_commands_rp { - u8_t data[0]; -} __packed; - -#define L2CAP_CONNECT 0x02 + u8_t data[0]; +} __packed; + +#define L2CAP_CONNECT 0x02 struct l2cap_connect_cmd { - u8_t address_type; - u8_t address[6]; - u16_t psm; - u16_t mtu; - u8_t num; + u8_t address_type; + u8_t address[6]; + u16_t psm; + u16_t mtu; + u8_t num; } __packed; struct l2cap_connect_rp { - u8_t num; - u8_t chan_ids[0]; -} __packed; - -#define L2CAP_DISCONNECT 0x03 + u8_t num; + u8_t chan_ids[0]; +} __packed; + +#define L2CAP_DISCONNECT 0x03 struct l2cap_disconnect_cmd { - u8_t chan_id; -} __packed; - -#define L2CAP_SEND_DATA 0x04 + u8_t chan_id; +} __packed; + +#define L2CAP_SEND_DATA 0x04 struct l2cap_send_data_cmd { - u8_t chan_id; - u16_t data_len; - u8_t data[]; -} __packed; - -#define L2CAP_TRANSPORT_BREDR 0x00 -#define L2CAP_TRANSPORT_LE 0x01 - -#define L2CAP_LISTEN 0x05 + u8_t chan_id; + u16_t data_len; + u8_t data[]; +} __packed; + +#define L2CAP_TRANSPORT_BREDR 0x00 +#define L2CAP_TRANSPORT_LE 0x01 + +#define L2CAP_LISTEN 0x05 struct l2cap_listen_cmd { - u16_t psm; - u8_t transport; - u16_t mtu; - u16_t response; -} __packed; - -#define L2CAP_ACCEPT_CONNECTION 0x06 + u16_t psm; + u8_t transport; + u16_t mtu; + u16_t response; +} __packed; + +#define L2CAP_ACCEPT_CONNECTION 0x06 struct l2cap_accept_connection_cmd { - u8_t chan_id; - u16_t result; -} __packed; - -#define L2CAP_RECONFIGURE 0x07 + u8_t chan_id; + u16_t result; +} __packed; + +#define L2CAP_RECONFIGURE 0x07 struct l2cap_reconfigure_cmd { u8_t address_type; u8_t address[6]; ``` </details> #### apps/bttester/src/gatt.c <details> ```diff @@ -614,233 +643,244 @@ * It is not intended to be used by client and server at the same time. */ static struct { - u16_t len; - u8_t buf[MAX_BUFFER_SIZE]; + u16_t len; + u8_t buf[MAX_BUFFER_SIZE]; } gatt_buf; -static void *gatt_buf_add(const void *data, size_t len) -{ - void *ptr = gatt_buf.buf + gatt_buf.len; - - if ((len + gatt_buf.len) > MAX_BUFFER_SIZE) { - return NULL; - } - - if (data) { - memcpy(ptr, data, len); - } else { - (void)memset(ptr, 0, len); - } - - gatt_buf.len += len; - - SYS_LOG_DBG("%d/%d used", gatt_buf.len, MAX_BUFFER_SIZE); - - return ptr; -} - -static void *gatt_buf_reserve(size_t len) -{ - return gatt_buf_add(NULL, len); -} - -static void gatt_buf_clear(void) -{ - (void)memset(&gatt_buf, 0, sizeof(gatt_buf)); -} - -static void discover_destroy(void) -{ - gatt_buf_clear(); -} - -static void read_destroy() -{ - gatt_buf_clear(); -} - -static int read_cb(uint16_t conn_handle, - const struct ble_gatt_error *error, - struct ble_gatt_attr *attr, - void *arg) -{ - struct gatt_read_rp *rp = (void *) gatt_buf.buf; - u8_t btp_opcode = (uint8_t) (int) arg; - - SYS_LOG_DBG("status=%d", error->status); - - if (error->status != 0 && error->status != BLE_HS_EDONE) { - rp->att_response = (uint8_t) BLE_HS_ATT_ERR(error->status); - tester_send(BTP_SERVICE_ID_GATT, btp_opcode, - CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); - read_destroy(); - return 0; - } - - if (!gatt_buf_add(attr->om->om_data, attr->om->om_len)) { - tester_rsp(BTP_SERVICE_ID_GATT, btp_opcode, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - read_destroy(); - return 0; - } - - rp->data_length += attr->om->om_len; - tester_send(BTP_SERVICE_ID_GATT, btp_opcode, - CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); - read_destroy(); - - return 0; -} - -static void read(u8_t *data, u16_t len) -{ - const struct gatt_read_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - /* Clear buffer */ - read_destroy(); - - if (!gatt_buf_reserve(sizeof(struct gatt_read_rp))) { - goto fail; - } - - if (ble_gattc_read(conn.conn_handle, sys_le16_to_cpu(cmd->handle), - read_cb, (void *)GATT_READ)) { - read_destroy(); - goto fail; - } - - return; +static void * +gatt_buf_add(const void *data, size_t len) +{ + void *ptr = gatt_buf.buf + gatt_buf.len; + + if ((len + gatt_buf.len) > MAX_BUFFER_SIZE) { + return NULL; + } + + if (data) { + memcpy(ptr, data, len); + } else { + (void)memset(ptr, 0, len); + } + + gatt_buf.len += len; + + SYS_LOG_DBG("%d/%d used", gatt_buf.len, MAX_BUFFER_SIZE); + + return ptr; +} + +static void * +gatt_buf_reserve(size_t len) +{ + return gatt_buf_add(NULL, len); +} + +static void +gatt_buf_clear(void) +{ + (void)memset(&gatt_buf, 0, sizeof(gatt_buf)); +} + +static void +discover_destroy(void) +{ + gatt_buf_clear(); +} + +static void +read_destroy() +{ + gatt_buf_clear(); +} + +static int +read_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + struct gatt_read_rp *rp = (void *) gatt_buf.buf; + u8_t btp_opcode = (uint8_t) (int) arg; + + SYS_LOG_DBG("status=%d", error->status); + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + rp->att_response = (uint8_t) BLE_HS_ATT_ERR(error->status); + tester_send(BTP_SERVICE_ID_GATT, btp_opcode, + CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); + read_destroy(); + return 0; + } + + if (!gatt_buf_add(attr->om->om_data, attr->om->om_len)) { + tester_rsp(BTP_SERVICE_ID_GATT, btp_opcode, + CONTROLLER_INDEX, BTP_STATUS_FAILED); + read_destroy(); + return 0; + } + + rp->data_length += attr->om->om_len; + tester_send(BTP_SERVICE_ID_GATT, btp_opcode, + CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); + read_destroy(); + + return 0; +} + +static void +read(u8_t *data, u16_t len) +{ + const struct gatt_read_cmd *cmd = (void *) data; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); + if (rc) { + goto fail; + } + + /* Clear buffer */ + read_destroy(); + + if (!gatt_buf_reserve(sizeof(struct gatt_read_rp))) { + goto fail; + } + + if (ble_gattc_read(conn.conn_handle, sys_le16_to_cpu(cmd->handle), + read_cb, (void *)GATT_READ)) { + read_destroy(); + goto fail; + } + + return; fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_READ, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static int read_long_cb(uint16_t conn_handle, - const struct ble_gatt_error *error, - struct ble_gatt_attr *attr, - void *arg) -{ - struct gatt_read_rp *rp = (void *) gatt_buf.buf; - u8_t btp_opcode = (uint8_t) (int) arg; - - SYS_LOG_DBG("status=%d", error->status); - - if (error->status != 0 && error->status != BLE_HS_EDONE) { - rp->att_response = (uint8_t) BLE_HS_ATT_ERR(error->status); - tester_send(BTP_SERVICE_ID_GATT, btp_opcode, - CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); - read_destroy(); - return 0; - } - - if (error->status == BLE_HS_EDONE) { - tester_send(BTP_SERVICE_ID_GATT, btp_opcode, - CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); - read_destroy(); - return 0; - } - - if (gatt_buf_add(attr->om->om_data, attr->om->om_len) == NULL) { - tester_rsp(BTP_SERVICE_ID_GATT, btp_opcode, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - read_destroy(); - return BLE_HS_ENOMEM; - } - - rp->data_length += attr->om->om_len; - - return 0; -} - -static void read_long(u8_t *data, u16_t len) -{ - const struct gatt_read_long_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - /* Clear buffer */ - read_destroy(); - - if (!gatt_buf_reserve(sizeof(struct gatt_read_rp))) { - goto fail; - } - - if (ble_gattc_read_long(conn.conn_handle, - sys_le16_to_cpu(cmd->handle), - sys_le16_to_cpu(cmd->offset), - read_long_cb, (void *)GATT_READ_LONG)) { - read_destroy(); - goto fail; - } - - return; + tester_rsp(BTP_SERVICE_ID_GATT, GATT_READ, CONTROLLER_INDEX, + BTP_STATUS_FAILED); +} + +static int +read_long_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + struct gatt_read_rp *rp = (void *) gatt_buf.buf; + u8_t btp_opcode = (uint8_t) (int) arg; + + SYS_LOG_DBG("status=%d", error->status); + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + rp->att_response = (uint8_t) BLE_HS_ATT_ERR(error->status); + tester_send(BTP_SERVICE_ID_GATT, btp_opcode, + CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); + read_destroy(); + return 0; + } + + if (error->status == BLE_HS_EDONE) { + tester_send(BTP_SERVICE_ID_GATT, btp_opcode, + CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); + read_destroy(); + return 0; + } + + if (gatt_buf_add(attr->om->om_data, attr->om->om_len) == NULL) { + tester_rsp(BTP_SERVICE_ID_GATT, btp_opcode, + CONTROLLER_INDEX, BTP_STATUS_FAILED); + read_destroy(); + return BLE_HS_ENOMEM; + } + + rp->data_length += attr->om->om_len; + + return 0; +} + +static void +read_long(u8_t *data, u16_t len) +{ + const struct gatt_read_long_cmd *cmd = (void *) data; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); + if (rc) { + goto fail; + } + + /* Clear buffer */ + read_destroy(); + + if (!gatt_buf_reserve(sizeof(struct gatt_read_rp))) { + goto fail; + } + + if (ble_gattc_read_long(conn.conn_handle, + sys_le16_to_cpu(cmd->handle), + sys_le16_to_cpu(cmd->offset), + read_long_cb, (void *)GATT_READ_LONG)) { + read_destroy(); + goto fail; + } + + return; fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_READ_LONG, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static void read_multiple(u8_t *data, u16_t len) -{ - const struct gatt_read_multiple_cmd *cmd = (void *) data; - u16_t handles[cmd->handles_count]; - struct ble_gap_conn_desc conn; - int rc, i; - - SYS_LOG_DBG(""); - - for (i = 0; i < ARRAY_SIZE(handles); i++) { - handles[i] = sys_le16_to_cpu(cmd->handles[i]); - } - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - /* Clear buffer */ - read_destroy(); - - if (!gatt_buf_reserve(sizeof(struct gatt_read_rp))) { - goto fail; - } - - if (ble_gattc_read_mult(conn.conn_handle, handles, - cmd->handles_count, read_cb, - (void *)GATT_READ_MULTIPLE)) { - read_destroy(); - goto fail; - } - - return; + tester_rsp(BTP_SERVICE_ID_GATT, GATT_READ_LONG, CONTROLLER_INDEX, + BTP_STATUS_FAILED); +} + +static void +read_multiple(u8_t *data, u16_t len) +{ + const struct gatt_read_multiple_cmd *cmd = (void *) data; + u16_t handles[cmd->handles_count]; + struct ble_gap_conn_desc conn; + int rc, i; + + SYS_LOG_DBG(""); + + for (i = 0; i < ARRAY_SIZE(handles); i++) { + handles[i] = sys_le16_to_cpu(cmd->handles[i]); + } + + rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); + if (rc) { + goto fail; + } + + /* Clear buffer */ + read_destroy(); + + if (!gatt_buf_reserve(sizeof(struct gatt_read_rp))) { + goto fail; + } + + if (ble_gattc_read_mult(conn.conn_handle, handles, + cmd->handles_count, read_cb, + (void *)GATT_READ_MULTIPLE)) { + read_destroy(); + goto fail; + } + + return; fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_READ_MULTIPLE, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static int read_var_cb(uint16_t conn_handle, - const struct ble_gatt_error *error, - struct ble_gatt_attr *attr, - uint8_t num_attrs, - void *arg) + tester_rsp(BTP_SERVICE_ID_GATT, GATT_READ_MULTIPLE, CONTROLLER_INDEX, + BTP_STATUS_FAILED); +} + +static int +read_var_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + uint8_t num_attrs, + void *arg) { struct gatt_read_rp *rp = (void *) gatt_buf.buf; u8_t btp_opcode = (uint8_t) (int) arg; @@ -874,7 +914,8 @@ return 0; } -static void read_multiple_var(u8_t *data, u16_t len) +static void +read_multiple_var(u8_t *data, u16_t len) { const struct gatt_read_multiple_var_cmd *cmd = (void *) data; u16_t handles[cmd->handles_count]; @@ -885,23 +926,23 @@ for (i = 0; i < ARRAY_SIZE(handles); i++) { handles[i] = sys_le16_to_cpu(cmd->handles[i]); - } + } rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); if (rc) { goto fail; - } - - /* Clear buffer */ + } + + /* Clear buffer */ read_destroy(); if (!gatt_buf_reserve(sizeof(struct gatt_read_rp))) { goto fail; - } + } if (ble_gattc_read_mult_var(conn.conn_handle, handles, cmd->handles_count, read_var_cb, - (void *)GATT_READ_MULTIPLE_VAR)) { + (void *)GATT_READ_MULTIPLE_VAR)) { read_destroy(); goto fail; } @@ -913,773 +954,795 @@ BTP_STATUS_FAILED); } -static void write_without_rsp(u8_t *data, u16_t len, u8_t op, bool sign) -{ - const struct gatt_write_without_rsp_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - u8_t status = BTP_STATUS_SUCCESS; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - status = BTP_STATUS_FAILED; - goto rsp; - } - - if (ble_gattc_write_no_rsp_flat(conn.conn_handle, - sys_le16_to_cpu(cmd->handle), cmd->data, - sys_le16_to_cpu(cmd->data_length))) { - status = BTP_STATUS_FAILED; - } +static void +write_without_rsp(u8_t *data, u16_t len, u8_t op, bool sign) +{ + const struct gatt_write_without_rsp_cmd *cmd = (void *) data; + struct ble_gap_conn_desc conn; + u8_t status = BTP_STATUS_SUCCESS; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); + if (rc) { + status = BTP_STATUS_FAILED; + goto rsp; + } + + if (ble_gattc_write_no_rsp_flat(conn.conn_handle, + sys_le16_to_cpu(cmd->handle), cmd->data, + sys_le16_to_cpu(cmd->data_length))) { + status = BTP_STATUS_FAILED; + } rsp: - tester_rsp(BTP_SERVICE_ID_GATT, op, CONTROLLER_INDEX, status); -} - -static int write_rsp(uint16_t conn_handle, const struct ble_gatt_error *error, - struct ble_gatt_attr *attr, - void *arg) -{ - uint8_t err = (uint8_t) error->status; - u8_t btp_opcode = (uint8_t) (int) arg; - - SYS_LOG_DBG(""); - - tester_send(BTP_SERVICE_ID_GATT, btp_opcode, - CONTROLLER_INDEX, &err, sizeof(err)); - return 0; -} - -static void write(u8_t *data, u16_t len) -{ - const struct gatt_write_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - if (ble_gattc_write_flat(conn.conn_handle, sys_le16_to_cpu(cmd->handle), - cmd->data, sys_le16_to_cpu(cmd->data_length), - write_rsp, (void *) GATT_WRITE)) { - goto fail; - } - - return; + tester_rsp(BTP_SERVICE_ID_GATT, op, CONTROLLER_INDEX, status); +} + +static int +write_rsp(uint16_t conn_handle, const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + uint8_t err = (uint8_t) error->status; + u8_t btp_opcode = (uint8_t) (int) arg; + + SYS_LOG_DBG(""); + + tester_send(BTP_SERVICE_ID_GATT, btp_opcode, + CONTROLLER_INDEX, &err, sizeof(err)); + return 0; +} + +static void +write(u8_t *data, u16_t len) +{ + const struct gatt_write_cmd *cmd = (void *) data; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); + if (rc) { + goto fail; + } + + if (ble_gattc_write_flat(conn.conn_handle, sys_le16_to_cpu(cmd->handle), + cmd->data, sys_le16_to_cpu(cmd->data_length), + write_rsp, (void *) GATT_WRITE)) { + goto fail; + } + + return; fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_WRITE, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static void write_long(u8_t *data, u16_t len) -{ - const struct gatt_write_long_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - struct os_mbuf *om = NULL; - int rc = 0; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - om = ble_hs_mbuf_from_flat(cmd->data, sys_le16_to_cpu(cmd->data_length)); - if (!om) { - SYS_LOG_ERR("Insufficient resources"); - goto fail; - } - - rc = ble_gattc_write_long(conn.conn_handle, - sys_le16_to_cpu(cmd->handle), - sys_le16_to_cpu(cmd->offset), - om, write_rsp, - (void *) GATT_WRITE_LONG); - if (!rc) { - return; - } + tester_rsp(BTP_SERVICE_ID_GATT, GATT_WRITE, CONTROLLER_INDEX, + BTP_STATUS_FAILED); +} + +static void +write_long(u8_t *data, u16_t len) +{ + const struct gatt_write_long_cmd *cmd = (void *) data; + struct ble_gap_conn_desc conn; + struct os_mbuf *om = NULL; + int rc = 0; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); + if (rc) { + goto fail; + } + + om = ble_hs_mbuf_from_flat(cmd->data, sys_le16_to_cpu(cmd->data_length)); + if (!om) { + SYS_LOG_ERR("Insufficient resources"); + goto fail; + } + + rc = ble_gattc_write_long(conn.conn_handle, + sys_le16_to_cpu(cmd->handle), + sys_le16_to_cpu(cmd->offset), + om, write_rsp, + (void *) GATT_WRITE_LONG); + if (!rc) { + return; + } fail: - SYS_LOG_ERR("Failed to send Write Long request, rc=%d", rc); - os_mbuf_free_chain(om); - tester_rsp(BTP_SERVICE_ID_GATT, GATT_WRITE_LONG, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static int reliable_write_rsp(uint16_t conn_handle, - const struct ble_gatt_error *error, - struct ble_gatt_attr *attrs, - uint8_t num_attrs, - void *arg) -{ - uint8_t err = (uint8_t) error->status; - - SYS_LOG_DBG("Reliable write status %d", err); - - tester_send(BTP_SERVICE_ID_GATT, GATT_RELIABLE_WRITE, - CONTROLLER_INDEX, &err, sizeof(err)); - return 0; -} - -static void reliable_write(u8_t *data, u16_t len) -{ - const struct gatt_reliable_write_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - struct ble_gatt_attr attr; - struct os_mbuf *om = NULL; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - om = ble_hs_mbuf_from_flat(cmd->data, sys_le16_to_cpu(cmd->data_length)); - /* This is required, because Nimble checks if - * the data is longer than offset - */ - if (os_mbuf_extend(om, sys_le16_to_cpu(cmd->offset) + 1) == NULL) { - goto fail; - } - - attr.handle = sys_le16_to_cpu(cmd->handle); - attr.offset = sys_le16_to_cpu(cmd->offset); - attr.om = om; - - if (ble_gattc_write_reliable(conn.conn_handle, &attr, 1, - reliable_write_rsp, NULL)) { - goto fail; - } - - return; + SYS_LOG_ERR("Failed to send Write Long request, rc=%d", rc); + os_mbuf_free_chain(om); + tester_rsp(BTP_SERVICE_ID_GATT, GATT_WRITE_LONG, CONTROLLER_INDEX, + BTP_STATUS_FAILED); +} + +static int +reliable_write_rsp(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attrs, + uint8_t num_attrs, + void *arg) +{ + uint8_t err = (uint8_t) error->status; + + SYS_LOG_DBG("Reliable write status %d", err); + + tester_send(BTP_SERVICE_ID_GATT, GATT_RELIABLE_WRITE, + CONTROLLER_INDEX, &err, sizeof(err)); + return 0; +} + +static void +reliable_write(u8_t *data, u16_t len) +{ + const struct gatt_reliable_write_cmd *cmd = (void *) data; + struct ble_gap_conn_desc conn; + struct ble_gatt_attr attr; + struct os_mbuf *om = NULL; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); + if (rc) { + goto fail; + } + + om = ble_hs_mbuf_from_flat(cmd->data, sys_le16_to_cpu(cmd->data_length)); + /* This is required, because Nimble checks if + * the data is longer than offset + */ + if (os_mbuf_extend(om, sys_le16_to_cpu(cmd->offset) + 1) == NULL) { + goto fail; + } + + attr.handle = sys_le16_to_cpu(cmd->handle); + attr.offset = sys_le16_to_cpu(cmd->offset); + attr.om = om; + + if (ble_gattc_write_reliable(conn.conn_handle, &attr, 1, + reliable_write_rsp, NULL)) { + goto fail; + } + + return; fail: - os_mbuf_free_chain(om); - - tester_rsp(BTP_SERVICE_ID_GATT, GATT_WRITE_LONG, CONTROLLER_INDEX, - BTP_STATUS_FAILED); + os_mbuf_free_chain(om); + + tester_rsp(BTP_SERVICE_ID_GATT, GATT_WRITE_LONG, CONTROLLER_INDEX, + BTP_STATUS_FAILED); } static struct bt_gatt_subscribe_params { - u16_t ccc_handle; - u16_t value; - u16_t value_handle; + u16_t ccc_handle; + u16_t value; + u16_t value_handle; } subscribe_params; -static void read_uuid(u8_t *data, u16_t len) -{ - const struct gatt_read_uuid_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - ble_uuid_any_t uuid; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - if (btp2bt_uuid(cmd->uuid, cmd->uuid_length, &uuid)) { - goto fail; - } - - /* Clear buffer */ - read_destroy(); - - if (!gatt_buf_reserve(sizeof(struct gatt_read_rp))) { - goto fail; - } - - if (ble_gattc_read_by_uuid(conn.conn_handle, - sys_le16_to_cpu(cmd->start_handle), - sys_le16_to_cpu(cmd->end_handle), &uuid.u, - read_long_cb, (void *)GATT_READ_UUID)) { - read_destroy(); - goto fail; - } - - return; +static void +read_uuid(u8_t *data, u16_t len) +{ + const struct gatt_read_uuid_cmd *cmd = (void *) data; + struct ble_gap_conn_desc conn; + ble_uuid_any_t uuid; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); + if (rc) { + goto fail; + } + + if (btp2bt_uuid(cmd->uuid, cmd->uuid_length, &uuid)) { + goto fail; + } + + /* Clear buffer */ + read_destroy(); + + if (!gatt_buf_reserve(sizeof(struct gatt_read_rp))) { + goto fail; + } + + if (ble_gattc_read_by_uuid(conn.conn_handle, + sys_le16_to_cpu(cmd->start_handle), + sys_le16_to_cpu(cmd->end_handle), &uuid.u, + read_long_cb, (void *)GATT_READ_UUID)) { + read_destroy(); + goto fail; + } + + return; fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_READ, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static int disc_prim_uuid_cb(uint16_t conn_handle, - const struct ble_gatt_error *error, - const struct ble_gatt_svc *gatt_svc, void *arg) -{ - struct gatt_disc_prim_uuid_rp *rp = (void *) gatt_buf.buf; - struct gatt_service *service; - const ble_uuid_any_t *uuid; - u8_t uuid_length; - u8_t opcode = (u8_t) (int) arg; - - SYS_LOG_DBG(""); - - if (error->status != 0 && error->status != BLE_HS_EDONE) { - tester_rsp(BTP_SERVICE_ID_GATT, opcode, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - discover_destroy(); - return 0; - } - - if (error->status == BLE_HS_EDONE) { - tester_send(BTP_SERVICE_ID_GATT, opcode, - CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); - discover_destroy(); - return 0; - } - - uuid = &gatt_svc->uuid; - uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); - - service = gatt_buf_reserve(sizeof(*service) + uuid_length); - if (!service) { - tester_rsp(BTP_SERVICE_ID_GATT, opcode, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - discover_destroy(); - return BLE_HS_ENOMEM; - } - - service->start_handle = sys_cpu_to_le16(gatt_svc->start_handle); - service->end_handle = sys_cpu_to_le16(gatt_svc->end_handle); - service->uuid_length = uuid_length; - - if (uuid->u.type == BLE_UUID_TYPE_16) { - u16_t u16 = sys_cpu_to_le16(BLE_UUID16(uuid)->value); - memcpy(service->uuid, &u16, uuid_length); - } else { - memcpy(service->uuid, BLE_UUID128(uuid)->value, - uuid_length); - } - - rp->services_count++; - - return 0; -} - -static int disc_all_desc_cb(uint16_t conn_handle, - const struct ble_gatt_error *error, - uint16_t chr_val_handle, - const struct ble_gatt_dsc *gatt_dsc, - void *arg) -{ - struct gatt_disc_all_desc_rp *rp = (void *) gatt_buf.buf; - struct gatt_descriptor *dsc; - const ble_uuid_any_t *uuid; - u8_t uuid_length; - - SYS_LOG_DBG(""); - - if (error->status != 0 && error->status != BLE_HS_EDONE) { - tester_rsp(BTP_SERVICE_ID_GATT, GATT_DISC_ALL_DESC, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - discover_destroy(); - return 0; - } - - if (error->status == BLE_HS_EDONE) { - tester_send(BTP_SERVICE_ID_GATT, GATT_DISC_ALL_DESC, - CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); - discover_destroy(); - return 0; - } - - uuid = &gatt_dsc->uuid; - uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); - - dsc = gatt_buf_reserve(sizeof(*dsc) + uuid_length); - if (!dsc) { - tester_rsp(BTP_SERVICE_ID_GATT, GATT_DISC_ALL_DESC, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - discover_destroy(); - return BLE_HS_ENOMEM; - } - - dsc->descriptor_handle = sys_cpu_to_le16(gatt_dsc->handle); - dsc->uuid_length = uuid_length; - - if (uuid->u.type == BLE_UUID_TYPE_16) { - u16_t u16 = sys_cpu_to_le16(BLE_UUID16(uuid)->value); - memcpy(dsc->uuid, &u16, uuid_length); - } else { - memcpy(dsc->uuid, BLE_UUID128(uuid)->value, uuid_length); - } - - rp->descriptors_count++; - - return 0; -} - -static void disc_all_prim_svcs(u8_t *data, u16_t len) -{ - struct ble_gap_conn_desc conn; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - if (!gatt_buf_reserve(sizeof(struct gatt_disc_all_prim_svcs_rp))) { - goto fail; - } - - if (ble_gattc_disc_all_svcs(conn.conn_handle, disc_prim_uuid_cb, - (void *) GATT_DISC_ALL_PRIM_SVCS)) { - discover_destroy(); - goto fail; - } - - return; + tester_rsp(BTP_SERVICE_ID_GATT, GATT_READ, CONTROLLER_INDEX, + BTP_STATUS_FAILED); +} + +static int +disc_prim_uuid_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *gatt_svc, void *arg) +{ + struct gatt_disc_prim_uuid_rp *rp = (void *) gatt_buf.buf; + struct gatt_service *service; + const ble_uuid_any_t *uuid; + u8_t uuid_length; + u8_t opcode = (u8_t) (int) arg; + + SYS_LOG_DBG(""); + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + tester_rsp(BTP_SERVICE_ID_GATT, opcode, + CONTROLLER_INDEX, BTP_STATUS_FAILED); + discover_destroy(); + return 0; + } + + if (error->status == BLE_HS_EDONE) { + tester_send(BTP_SERVICE_ID_GATT, opcode, + CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); + discover_destroy(); + return 0; + } + + uuid = &gatt_svc->uuid; + uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); + + service = gatt_buf_reserve(sizeof(*service) + uuid_length); + if (!service) { + tester_rsp(BTP_SERVICE_ID_GATT, opcode, + CONTROLLER_INDEX, BTP_STATUS_FAILED); + discover_destroy(); + return BLE_HS_ENOMEM; + } + + service->start_handle = sys_cpu_to_le16(gatt_svc->start_handle); + service->end_handle = sys_cpu_to_le16(gatt_svc->end_handle); + service->uuid_length = uuid_length; + + if (uuid->u.type == BLE_UUID_TYPE_16) { + u16_t u16 = sys_cpu_to_le16(BLE_UUID16(uuid)->value); + memcpy(service->uuid, &u16, uuid_length); + } else { + memcpy(service->uuid, BLE_UUID128(uuid)->value, + uuid_length); + } + + rp->services_count++; + + return 0; +} + +static int +disc_all_desc_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + uint16_t chr_val_handle, + const struct ble_gatt_dsc *gatt_dsc, + void *arg) +{ + struct gatt_disc_all_desc_rp *rp = (void *) gatt_buf.buf; + struct gatt_descriptor *dsc; + const ble_uuid_any_t *uuid; + u8_t uuid_length; + + SYS_LOG_DBG(""); + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + tester_rsp(BTP_SERVICE_ID_GATT, GATT_DISC_ALL_DESC, + CONTROLLER_INDEX, BTP_STATUS_FAILED); + discover_destroy(); + return 0; + } + + if (error->status == BLE_HS_EDONE) { + tester_send(BTP_SERVICE_ID_GATT, GATT_DISC_ALL_DESC, + CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); + discover_destroy(); + return 0; + } + + uuid = &gatt_dsc->uuid; + uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); + + dsc = gatt_buf_reserve(sizeof(*dsc) + uuid_length); + if (!dsc) { + tester_rsp(BTP_SERVICE_ID_GATT, GATT_DISC_ALL_DESC, + CONTROLLER_INDEX, BTP_STATUS_FAILED); + discover_destroy(); + return BLE_HS_ENOMEM; + } + + dsc->descriptor_handle = sys_cpu_to_le16(gatt_dsc->handle); + dsc->uuid_length = uuid_length; + + if (uuid->u.type == BLE_UUID_TYPE_16) { + u16_t u16 = sys_cpu_to_le16(BLE_UUID16(uuid)->value); + memcpy(dsc->uuid, &u16, uuid_length); + } else { + memcpy(dsc->uuid, BLE_UUID128(uuid)->value, uuid_length); + } + + rp->descriptors_count++; + + return 0; +} + +static void +disc_all_prim_svcs(u8_t *data, u16_t len) +{ + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); + if (rc) { + goto fail; + } + + if (!gatt_buf_reserve(sizeof(struct gatt_disc_all_prim_svcs_rp))) { + goto fail; + } + + if (ble_gattc_disc_all_svcs(conn.conn_handle, disc_prim_uuid_cb, + (void *) GATT_DISC_ALL_PRIM_SVCS)) { + discover_destroy(); + goto fail; + } + + return; fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_DISC_ALL_PRIM_SVCS, - CONTROLLER_INDEX, BTP_STATUS_FAILED); -} - -static void disc_all_desc(u8_t *data, u16_t len) -{ - const struct gatt_disc_all_desc_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - uint16_t start_handle, end_handle; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - if (!gatt_buf_reserve(sizeof(struct gatt_disc_all_desc_rp))) { - goto fail; - } - - start_handle = sys_le16_to_cpu(cmd->start_handle) - 1; - end_handle = sys_le16_to_cpu(cmd->end_handle); - - rc = ble_gattc_disc_all_dscs(conn.conn_handle, start_handle, end_handle, - disc_all_desc_cb, NULL); - - SYS_LOG_DBG("rc=%d", rc); - - if (rc) { - discover_destroy(); - goto fail; - } - - return; + tester_rsp(BTP_SERVICE_ID_GATT, GATT_DISC_ALL_PRIM_SVCS, + CONTROLLER_INDEX, BTP_STATUS_FAILED); +} + +static void +disc_all_desc(u8_t *data, u16_t len) +{ + const struct gatt_disc_all_desc_cmd *cmd = (void *) data; + struct ble_gap_conn_desc conn; + uint16_t start_handle, end_handle; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); + if (rc) { + goto fail; + } + + if (!gatt_buf_reserve(sizeof(struct gatt_disc_all_desc_rp))) { + goto fail; + } + + start_handle = sys_le16_to_cpu(cmd->start_handle) - 1; + end_handle = sys_le16_to_cpu(cmd->end_handle); + + rc = ble_gattc_disc_all_dscs(conn.conn_handle, start_handle, end_handle, + disc_all_desc_cb, NULL); + + SYS_LOG_DBG("rc=%d", rc); + + if (rc) { + discover_destroy(); + goto fail; + } + + return; fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_DISC_ALL_DESC, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static int find_included_cb(uint16_t conn_handle, - const struct ble_gatt_error *error, - const struct ble_gatt_svc *gatt_svc, void *arg) -{ - struct gatt_find_included_rp *rp = (void *) gatt_buf.buf; - struct gatt_included *included; - const ble_uuid_any_t *uuid; - int service_handle = (int) arg; - u8_t uuid_length; - - SYS_LOG_DBG(""); - - if (error->status != 0 && error->status != BLE_HS_EDONE) { - tester_rsp(BTP_SERVICE_ID_GATT, GATT_FIND_INCLUDED, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - discover_destroy(); - return 0; - } - - if (error->status == BLE_HS_EDONE) { - tester_send(BTP_SERVICE_ID_GATT, GATT_FIND_INCLUDED, - CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); - discover_destroy(); - return 0; - } - - uuid = &gatt_svc->uuid; - uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); - - - included = gatt_buf_reserve(sizeof(*included) + uuid_length); - if (!included) { - tester_rsp(BTP_SERVICE_ID_GATT, GATT_FIND_INCLUDED, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - discover_destroy(); - return BLE_HS_ENOMEM; - } - - /* FIXME */ - included->included_handle = sys_cpu_to_le16(service_handle + 1 + - rp->services_count); - included->service.start_handle = sys_cpu_to_le16(gatt_svc->start_handle); - included->service.end_handle = sys_cpu_to_le16(gatt_svc->end_handle); - included->service.uuid_length = uuid_length; - - if (uuid->u.type == BLE_UUID_TYPE_16) { - u16_t u16 = sys_cpu_to_le16(BLE_UUID16(uuid)->value); - memcpy(included->service.uuid, &u16, uuid_length); - } else { - memcpy(included->service.uuid, BLE_UUID128(uuid)->value, - uuid_length); - } - - rp->services_count++; - - return 0; -} - -static int disc_chrc_cb(uint16_t conn_handle, - const struct ble_gatt_error *error, - const struct ble_gatt_chr *gatt_chr, void *arg) -{ - struct gatt_disc_chrc_rp *rp = (void *) gatt_buf.buf; - struct gatt_characteristic *chrc; - const ble_uuid_any_t *uuid; - u8_t btp_opcode = (uint8_t) (int) arg; - u8_t uuid_length; - - SYS_LOG_DBG(""); - - if (error->status != 0 && error->status != BLE_HS_EDONE) { - tester_rsp(BTP_SERVICE_ID_GATT, btp_opcode, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - discover_destroy(); - return 0; - } - - if (error->status == BLE_HS_EDONE) { - tester_send(BTP_SERVICE_ID_GATT, btp_opcode, - CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); - discover_destroy(); - return 0; - } - - uuid = &gatt_chr->uuid; - uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); - - chrc = gatt_buf_reserve(sizeof(*chrc) + uuid_length); - if (!chrc) { - tester_rsp(BTP_SERVICE_ID_GATT, btp_opcode, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - discover_destroy(); - return BLE_HS_ENOMEM; - } - - chrc->characteristic_handle = sys_cpu_to_le16(gatt_chr->def_handle); - chrc->properties = gatt_chr->properties; - chrc->value_handle = sys_cpu_to_le16(gatt_chr->val_handle); - chrc->uuid_length = uuid_length; - - if (uuid->u.type == BLE_UUID_TYPE_16) { - u16_t u16 = sys_cpu_to_le16(BLE_UUID16(uuid)->value); - memcpy(chrc->uuid, &u16, uuid_length); - } else { - memcpy(chrc->uuid, BLE_UUID128(uuid)->value, - uuid_length); - } - - rp->characteristics_count++; - - return 0; -} - -static void disc_chrc_uuid(u8_t *data, u16_t len) -{ - const struct gatt_disc_chrc_uuid_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - uint16_t start_handle, end_handle; - ble_uuid_any_t uuid; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - if (btp2bt_uuid(cmd->uuid, cmd->uuid_length, &uuid)) { - goto fail; - } - - if (!gatt_buf_reserve(sizeof(struct gatt_disc_chrc_rp))) { - goto fail; - } - - start_handle = sys_le16_to_cpu(cmd->start_handle); - end_handle = sys_le16_to_cpu(cmd->end_handle); - - if (ble_gattc_disc_chrs_by_uuid(conn.conn_handle, start_handle, - end_handle, &uuid.u, disc_chrc_cb, - (void *)GATT_DISC_CHRC_UUID)) { - discover_destroy(); - goto fail; - } - - return; + tester_rsp(BTP_SERVICE_ID_GATT, GATT_DISC_ALL_DESC, CONTROLLER_INDEX, + BTP_STATUS_FAILED); +} + +static int +find_included_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *gatt_svc, void *arg) +{ + struct gatt_find_included_rp *rp = (void *) gatt_buf.buf; + struct gatt_included *included; + const ble_uuid_any_t *uuid; + int service_handle = (int) arg; + u8_t uuid_length; + + SYS_LOG_DBG(""); + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + tester_rsp(BTP_SERVICE_ID_GATT, GATT_FIND_INCLUDED, + CONTROLLER_INDEX, BTP_STATUS_FAILED); + discover_destroy(); + return 0; + } + + if (error->status == BLE_HS_EDONE) { + tester_send(BTP_SERVICE_ID_GATT, GATT_FIND_INCLUDED, + CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); + discover_destroy(); + return 0; + } + + uuid = &gatt_svc->uuid; + uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); + + + included = gatt_buf_reserve(sizeof(*included) + uuid_length); + if (!included) { + tester_rsp(BTP_SERVICE_ID_GATT, GATT_FIND_INCLUDED, + CONTROLLER_INDEX, BTP_STATUS_FAILED); + discover_destroy(); + return BLE_HS_ENOMEM; + } + + /* FIXME */ + included->included_handle = sys_cpu_to_le16(service_handle + 1 + + rp->services_count); + included->service.start_handle = sys_cpu_to_le16(gatt_svc->start_handle); + included->service.end_handle = sys_cpu_to_le16(gatt_svc->end_handle); + included->service.uuid_length = uuid_length; + + if (uuid->u.type == BLE_UUID_TYPE_16) { + u16_t u16 = sys_cpu_to_le16(BLE_UUID16(uuid)->value); + memcpy(included->service.uuid, &u16, uuid_length); + } else { + memcpy(included->service.uuid, BLE_UUID128(uuid)->value, + uuid_length); + } + + rp->services_count++; + + return 0; +} + +static int +disc_chrc_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_chr *gatt_chr, void *arg) +{ + struct gatt_disc_chrc_rp *rp = (void *) gatt_buf.buf; + struct gatt_characteristic *chrc; + const ble_uuid_any_t *uuid; + u8_t btp_opcode = (uint8_t) (int) arg; + u8_t uuid_length; + + SYS_LOG_DBG(""); + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + tester_rsp(BTP_SERVICE_ID_GATT, btp_opcode, + CONTROLLER_INDEX, BTP_STATUS_FAILED); + discover_destroy(); + return 0; + } + + if (error->status == BLE_HS_EDONE) { + tester_send(BTP_SERVICE_ID_GATT, btp_opcode, + CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); + discover_destroy(); + return 0; + } + + uuid = &gatt_chr->uuid; + uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); + + chrc = gatt_buf_reserve(sizeof(*chrc) + uuid_length); + if (!chrc) { + tester_rsp(BTP_SERVICE_ID_GATT, btp_opcode, + CONTROLLER_INDEX, BTP_STATUS_FAILED); + discover_destroy(); + return BLE_HS_ENOMEM; + } + + chrc->characteristic_handle = sys_cpu_to_le16(gatt_chr->def_handle); + chrc->properties = gatt_chr->properties; + chrc->value_handle = sys_cpu_to_le16(gatt_chr->val_handle); + chrc->uuid_length = uuid_length; + + if (uuid->u.type == BLE_UUID_TYPE_16) { + u16_t u16 = sys_cpu_to_le16(BLE_UUID16(uuid)->value); + memcpy(chrc->uuid, &u16, uuid_length); + } else { + memcpy(chrc->uuid, BLE_UUID128(uuid)->value, + uuid_length); + } + + rp->characteristics_count++; + + return 0; +} + +static void +disc_chrc_uuid(u8_t *data, u16_t len) +{ + const struct gatt_disc_chrc_uuid_cmd *cmd = (void *) data; + struct ble_gap_conn_desc conn; + uint16_t start_handle, end_handle; + ble_uuid_any_t uuid; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); + if (rc) { + goto fail; + } + + if (btp2bt_uuid(cmd->uuid, cmd->uuid_length, &uuid)) { + goto fail; + } + + if (!gatt_buf_reserve(sizeof(struct gatt_disc_chrc_rp))) { + goto fail; + } + + start_handle = sys_le16_to_cpu(cmd->start_handle); + end_handle = sys_le16_to_cpu(cmd->end_handle); + + if (ble_gattc_disc_chrs_by_uuid(conn.conn_handle, start_handle, + end_handle, &uuid.u, disc_chrc_cb, + (void *)GATT_DISC_CHRC_UUID)) { + discover_destroy(); + goto fail; + } + + return; fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_DISC_CHRC_UUID, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static void disc_prim_uuid(u8_t *data, u16_t len) -{ - const struct gatt_disc_prim_uuid_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - ble_uuid_any_t uuid; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - if (btp2bt_uuid(cmd->uuid, cmd->uuid_length, &uuid)) { - goto fail; - } - - if (!gatt_buf_reserve(sizeof(struct gatt_disc_prim_uuid_rp))) { - goto fail; - } - - if (ble_gattc_disc_svc_by_uuid(conn.conn_handle, - &uuid.u, disc_prim_uuid_cb, - (void *) GATT_DISC_PRIM_UUID)) { - discover_destroy(); - goto fail; - } - - return; + tester_rsp(BTP_SERVICE_ID_GATT, GATT_DISC_CHRC_UUID, CONTROLLER_INDEX, + BTP_STATUS_FAILED); +} + +static void +disc_prim_uuid(u8_t *data, u16_t len) +{ + const struct gatt_disc_prim_uuid_cmd *cmd = (void *) data; + struct ble_gap_conn_desc conn; + ble_uuid_any_t uuid; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); + if (rc) { + goto fail; + } + + if (btp2bt_uuid(cmd->uuid, cmd->uuid_length, &uuid)) { + goto fail; + } + + if (!gatt_buf_reserve(sizeof(struct gatt_disc_prim_uuid_rp))) { + goto fail; + } + + if (ble_gattc_disc_svc_by_uuid(conn.conn_handle, + &uuid.u, disc_prim_uuid_cb, + (void *) GATT_DISC_PRIM_UUID)) { + discover_destroy(); + goto fail; + } + + return; fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_DISC_PRIM_UUID, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static void disc_all_chrc(u8_t *data, u16_t len) -{ - const struct gatt_disc_all_chrc_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - uint16_t start_handle, end_handle; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - SYS_LOG_DBG("Conn find failed"); - goto fail; - } - - if (!gatt_buf_reserve(sizeof(struct gatt_disc_chrc_rp))) { - SYS_LOG_DBG("Buf reserve failed"); - goto fail; - } - - start_handle = sys_le16_to_cpu(cmd->start_handle); - end_handle = sys_le16_to_cpu(cmd->end_handle); - - rc = ble_gattc_disc_all_chrs(conn.conn_handle, start_handle, end_handle, - disc_chrc_cb, (void *)GATT_DISC_ALL_CHRC); - if (rc) { - discover_destroy(); - goto fail; - } - - return; + tester_rsp(BTP_SERVICE_ID_GATT, GATT_DISC_PRIM_UUID, CONTROLLER_INDEX, + BTP_STATUS_FAILED); +} + +static void +disc_all_chrc(u8_t *data, u16_t len) +{ + const struct gatt_disc_all_chrc_cmd *cmd = (void *) data; + struct ble_gap_conn_desc conn; + uint16_t start_handle, end_handle; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); + if (rc) { + SYS_LOG_DBG("Conn find failed"); + goto fail; + } + + if (!gatt_buf_reserve(sizeof(struct gatt_disc_chrc_rp))) { + SYS_LOG_DBG("Buf reserve failed"); + goto fail; + } + + start_handle = sys_le16_to_cpu(cmd->start_handle); + end_handle = sys_le16_to_cpu(cmd->end_handle); + + rc = ble_gattc_disc_all_chrs(conn.conn_handle, start_handle, end_handle, + disc_chrc_cb, (void *)GATT_DISC_ALL_CHRC); + if (rc) { + discover_destroy(); + goto fail; + } + + return; fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_DISC_ALL_CHRC, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static void find_included(u8_t *data, u16_t len) -{ - const struct gatt_find_included_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - uint16_t start_handle, end_handle; - int service_handle_arg; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - if (!gatt_buf_reserve(sizeof(struct gatt_find_included_rp))) { - goto fail; - } - - start_handle = sys_le16_to_cpu(cmd->start_handle); - end_handle = sys_le16_to_cpu(cmd->end_handle); - service_handle_arg = start_handle; - - if (ble_gattc_find_inc_svcs(conn.conn_handle, start_handle, end_handle, - find_included_cb, - (void *)service_handle_arg)) { - discover_destroy(); - goto fail; - } - - return; + tester_rsp(BTP_SERVICE_ID_GATT, GATT_DISC_ALL_CHRC, CONTROLLER_INDEX, + BTP_STATUS_FAILED); +} + +static void +find_included(u8_t *data, u16_t len) +{ + const struct gatt_find_included_cmd *cmd = (void *) data; + struct ble_gap_conn_desc conn; + uint16_t start_handle, end_handle; + int service_handle_arg; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); + if (rc) { + goto fail; + } + + if (!gatt_buf_reserve(sizeof(struct gatt_find_included_rp))) { + goto fail; + } + + start_handle = sys_le16_to_cpu(cmd->start_handle); + end_handle = sys_le16_to_cpu(cmd->end_handle); + service_handle_arg = start_handle; + + if (ble_gattc_find_inc_svcs(conn.conn_handle, start_handle, end_handle, + find_included_cb, + (void *)service_handle_arg)) { + discover_destroy(); + goto fail; + } + + return; fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_FIND_INCLUDED, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static int exchange_func(uint16_t conn_handle, - const struct ble_gatt_error *error, - uint16_t mtu, void *arg) -{ - SYS_LOG_DBG(""); - - if (error->status) { - tester_rsp(BTP_SERVICE_ID_GATT, GATT_EXCHANGE_MTU, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - - return 0; -} - - tester_rsp(BTP_SERVICE_ID_GATT, GATT_EXCHANGE_MTU, CONTROLLER_INDEX, - BTP_STATUS_SUCCESS); - - return 0; -} - -static void exchange_mtu(u8_t *data, u16_t len) -{ - struct ble_gap_conn_desc conn; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - if (ble_gattc_exchange_mtu(conn.conn_handle, exchange_func, NULL)) { - goto fail; - } - - return; + tester_rsp(BTP_SERVICE_ID_GATT, GATT_FIND_INCLUDED, CONTROLLER_INDEX, + BTP_STATUS_FAILED); +} + +static int +exchange_func(uint16_t conn_handle, + const struct ble_gatt_error *error, + uint16_t mtu, void *arg) +{ + SYS_LOG_DBG(""); + + if (error->status) { + tester_rsp(BTP_SERVICE_ID_GATT, GATT_EXCHANGE_MTU, + CONTROLLER_INDEX, BTP_STATUS_FAILED); + + return 0; + } + + tester_rsp(BTP_SERVICE_ID_GATT, GATT_EXCHANGE_MTU, CONTROLLER_INDEX, + BTP_STATUS_SUCCESS); + + return 0; +} + +static void +exchange_mtu(u8_t *data, u16_t len) +{ + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); + if (rc) { + goto fail; + } + + if (ble_gattc_exchange_mtu(conn.conn_handle, exchange_func, NULL)) { + goto fail; + } + + return; fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_EXCHANGE_MTU, - CONTROLLER_INDEX, BTP_STATUS_FAILED); -} - -static int enable_subscription(u16_t conn_handle, u16_t ccc_handle, - u16_t value) -{ - u8_t op; - - SYS_LOG_DBG(""); - - op = (uint8_t) (value == 0x0001 ? GATT_CFG_NOTIFY : GATT_CFG_INDICATE); - - if (ble_gattc_write_flat(conn_handle, ccc_handle, - &value, sizeof(value), NULL, NULL)) { - return -EINVAL; - } - - subscribe_params.ccc_handle = value; - - tester_rsp(BTP_SERVICE_ID_GATT, op, CONTROLLER_INDEX, - BTP_STATUS_SUCCESS); - return 0; -} - -static int disable_subscription(u16_t conn_handle, u16_t ccc_handle) -{ - u16_t value = 0x00; - - SYS_LOG_DBG(""); - - /* Fail if CCC handle doesn't match */ - if (ccc_handle != subscribe_params.ccc_handle) { - SYS_LOG_ERR("CCC handle doesn't match"); - return -EINVAL; - } - - if (ble_gattc_write_no_rsp_flat(conn_handle, ccc_handle, - &value, sizeof(value))) { - return -EINVAL; - } - - subscribe_params.ccc_handle = 0; - return 0; -} - -static void config_subscription(u8_t *data, u16_t len, u8_t op) -{ - const struct gatt_cfg_notify_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - u16_t ccc_handle = sys_le16_to_cpu(cmd->ccc_handle); - u8_t status; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - tester_rsp(BTP_SERVICE_ID_GATT, op, CONTROLLER_INDEX, - BTP_STATUS_FAILED); - return; - } - - if (cmd->enable) { - u16_t value; - - if (op == GATT_CFG_NOTIFY) { - value = 0x0001; - } else { - value = 0x0002; - } - - /* on success response will be sent from callback */ - if (enable_subscription(conn.conn_handle, - ccc_handle, value) == 0) { - return; - } - - status = BTP_STATUS_FAILED; - } else { - if (disable_subscription(conn.conn_handle, ccc_handle) < 0) { - status = BTP_STATUS_FAILED; - } else { - status = BTP_STATUS_SUCCESS; - } - } - - SYS_LOG_DBG("Config subscription (op %u) status %u", op, status); - - tester_rsp(BTP_SERVICE_ID_GATT, op, CONTROLLER_INDEX, status); + tester_rsp(BTP_SERVICE_ID_GATT, GATT_EXCHANGE_MTU, + CONTROLLER_INDEX, BTP_STATUS_FAILED); +} + +static int +enable_subscription(u16_t conn_handle, u16_t ccc_handle, + u16_t value) +{ + u8_t op; + + SYS_LOG_DBG(""); + + op = (uint8_t) (value == 0x0001 ? GATT_CFG_NOTIFY : GATT_CFG_INDICATE); + + if (ble_gattc_write_flat(conn_handle, ccc_handle, + &value, sizeof(value), NULL, NULL)) { + return -EINVAL; + } + + subscribe_params.ccc_handle = value; + + tester_rsp(BTP_SERVICE_ID_GATT, op, CONTROLLER_INDEX, + BTP_STATUS_SUCCESS); + return 0; +} + +static int +disable_subscription(u16_t conn_handle, u16_t ccc_handle) +{ + u16_t value = 0x00; + + SYS_LOG_DBG(""); + + /* Fail if CCC handle doesn't match */ + if (ccc_handle != subscribe_params.ccc_handle) { + SYS_LOG_ERR("CCC handle doesn't match"); + return -EINVAL; + } + + if (ble_gattc_write_no_rsp_flat(conn_handle, ccc_handle, + &value, sizeof(value))) { + return -EINVAL; + } + + subscribe_params.ccc_handle = 0; + return 0; +} + +static void +config_subscription(u8_t *data, u16_t len, u8_t op) +{ + const struct gatt_cfg_notify_cmd *cmd = (void *) data; + struct ble_gap_conn_desc conn; + u16_t ccc_handle = sys_le16_to_cpu(cmd->ccc_handle); + u8_t status; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); + if (rc) { + tester_rsp(BTP_SERVICE_ID_GATT, op, CONTROLLER_INDEX, + BTP_STATUS_FAILED); + return; + } + + if (cmd->enable) { + u16_t value; + + if (op == GATT_CFG_NOTIFY) { + value = 0x0001; + } else { + value = 0x0002; + } + + /* on success response will be sent from callback */ + if (enable_subscription(conn.conn_handle, + ccc_handle, value) == 0) { + return; + } + + status = BTP_STATUS_FAILED; + } else { + if (disable_subscription(conn.conn_handle, ccc_handle) < 0) { + status = BTP_STATUS_FAILED; + } else { + status = BTP_STATUS_SUCCESS; + } + } + + SYS_LOG_DBG("Config subscription (op %u) status %u", op, status); + + tester_rsp(BTP_SERVICE_ID_GATT, op, CONTROLLER_INDEX, status); } #define BTP_PERM_F_READ 0x01 @@ -1692,488 +1755,502 @@ #define BTP_PERM_F_WRITE_AUTHOR 0x80 static int flags_hs2btp_map[] = { - BTP_PERM_F_READ, - BTP_PERM_F_WRITE, - BTP_PERM_F_READ_ENC, - BTP_PERM_F_READ_AUTHEN, - BTP_PERM_F_READ_AUTHOR, - BTP_PERM_F_WRITE_ENC, - BTP_PERM_F_WRITE_AUTHEN, - BTP_PERM_F_WRITE_AUTHOR, + BTP_PERM_F_READ, + BTP_PERM_F_WRITE, + BTP_PERM_F_READ_ENC, + BTP_PERM_F_READ_AUTHEN, + BTP_PERM_F_READ_AUTHOR, + BTP_PERM_F_WRITE_ENC, + BTP_PERM_F_WRITE_AUTHEN, + BTP_PERM_F_WRITE_AUTHOR, }; -static u8_t flags_hs2btp(u8_t flags) -{ - int i; - u8_t ret = 0; - - for (i = 0; i < 8; ++i) { - if (flags & BIT(i)) { - ret |= flags_hs2btp_map[i]; - } - } - - return ret; -} - -static void get_attrs(u8_t *data, u16_t len) -{ - const struct gatt_get_attributes_cmd *cmd = (void *) data; - struct gatt_get_attributes_rp *rp; - struct gatt_attr *gatt_attr; - struct os_mbuf *buf = os_msys_get(0, 0); - u16_t start_handle, end_handle; - struct ble_att_svr_entry *entry = NULL; - ble_uuid_any_t uuid; - ble_uuid_t *uuid_ptr = NULL; - u8_t count = 0; - char str[BLE_UUID_STR_LEN]; - - SYS_LOG_DBG(""); - - memset(str, 0, sizeof(str)); - memset(&uuid, 0, sizeof(uuid)); - start_handle = sys_le16_to_cpu(cmd->start_handle); - end_handle = sys_le16_to_cpu(cmd->end_handle); - - if (cmd->type_length) { - if (btp2bt_uuid(cmd->type, cmd->type_length, &uuid)) { - goto fail; - } - - ble_uuid_to_str(&uuid.u, str); - SYS_LOG_DBG("start 0x%04x end 0x%04x, uuid %s", start_handle, - end_handle, str); - - uuid_ptr = &uuid.u; - } else { - SYS_LOG_DBG("start 0x%04x end 0x%04x", start_handle, end_handle); - } - - net_buf_simple_init(buf, 0); - rp = net_buf_simple_add(buf, sizeof(*rp)); - - entry = ble_att_svr_find_by_uuid(entry, uuid_ptr, end_handle); - while (entry) { - - if (entry->ha_handle_id < start_handle) { - entry = ble_att_svr_find_by_uuid(entry, - uuid_ptr, end_handle); - continue; - } - - gatt_attr = net_buf_simple_add(buf, sizeof(*gatt_attr)); - gatt_attr->handle = sys_cpu_to_le16(entry->ha_handle_id); - gatt_attr->permission = flags_hs2btp(entry->ha_flags); - - if (entry->ha_uuid->type == BLE_UUID_TYPE_16) { - gatt_attr->type_length = 2; - net_buf_simple_add_le16(buf, - BLE_UUID16(entry->ha_uuid)->value); - } else { - gatt_attr->type_length = 16; - net_buf_simple_add_mem(buf, - BLE_UUID128(entry->ha_uuid)->value, - gatt_attr->type_length); - } - - count++; - - entry = ble_att_svr_find_by_uuid(entry, uuid_ptr, end_handle); - } - - rp->attrs_count = count; - - tester_send_buf(BTP_SERVICE_ID_GATT, GATT_GET_ATTRIBUTES, - CONTROLLER_INDEX, buf); - - goto free; +static u8_t +flags_hs2btp(u8_t flags) +{ + int i; + u8_t ret = 0; + + for (i = 0; i < 8; ++i) { + if (flags & BIT(i)) { + ret |= flags_hs2btp_map[i]; + } + } + + return ret; +} + +static void +get_attrs(u8_t *data, u16_t len) +{ + const struct gatt_get_attributes_cmd *cmd = (void *) data; + struct gatt_get_attributes_rp *rp; + struct gatt_attr *gatt_attr; + struct os_mbuf *buf = os_msys_get(0, 0); + u16_t start_handle, end_handle; + struct ble_att_svr_entry *entry = NULL; + ble_uuid_any_t uuid; + ble_uuid_t *uuid_ptr = NULL; + u8_t count = 0; + char str[BLE_UUID_STR_LEN]; + + SYS_LOG_DBG(""); + + memset(str, 0, sizeof(str)); + memset(&uuid, 0, sizeof(uuid)); + start_handle = sys_le16_to_cpu(cmd->start_handle); + end_handle = sys_le16_to_cpu(cmd->end_handle); + + if (cmd->type_length) { + if (btp2bt_uuid(cmd->type, cmd->type_length, &uuid)) { + goto fail; + } + + ble_uuid_to_str(&uuid.u, str); + SYS_LOG_DBG("start 0x%04x end 0x%04x, uuid %s", start_handle, + end_handle, str); + + uuid_ptr = &uuid.u; + } else { + SYS_LOG_DBG("start 0x%04x end 0x%04x", start_handle, end_handle); + } + + net_buf_simple_init(buf, 0); + rp = net_buf_simple_add(buf, sizeof(*rp)); + + entry = ble_att_svr_find_by_uuid(entry, uuid_ptr, end_handle); + while (entry) { + + if (entry->ha_handle_id < start_handle) { + entry = ble_att_svr_find_by_uuid(entry, + uuid_ptr, end_handle); + continue; + } + + gatt_attr = net_buf_simple_add(buf, sizeof(*gatt_attr)); + gatt_attr->handle = sys_cpu_to_le16(entry->ha_handle_id); + gatt_attr->permission = flags_hs2btp(entry->ha_flags); + + if (entry->ha_uuid->type == BLE_UUID_TYPE_16) { + gatt_attr->type_length = 2; + net_buf_simple_add_le16(buf, + BLE_UUID16(entry->ha_uuid)->value); + } else { + gatt_attr->type_length = 16; + net_buf_simple_add_mem(buf, + BLE_UUID128(entry->ha_uuid)->value, + gatt_attr->type_length); + } + + count++; + + entry = ble_att_svr_find_by_uuid(entry, uuid_ptr, end_handle); + } + + rp->attrs_count = count; + + tester_send_buf(BTP_SERVICE_ID_GATT, GATT_GET_ATTRIBUTES, + CONTROLLER_INDEX, buf); + + goto free; fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_GET_ATTRIBUTES, CONTROLLER_INDEX, - BTP_STATUS_FAILED); + tester_rsp(BTP_SERVICE_ID_GATT, GATT_GET_ATTRIBUTES, CONTROLLER_INDEX, + BTP_STATUS_FAILED); free: - os_mbuf_free_chain(buf); -} - -static void get_attr_val(u8_t *data, u16_t len) -{ - const struct gatt_get_attribute_value_cmd *cmd = (void *) data; - struct gatt_get_attribute_value_rp *rp; - struct ble_gap_conn_desc conn; - struct os_mbuf *buf = os_msys_get(0, 0); - u16_t handle = sys_cpu_to_le16(cmd->handle); - uint8_t out_att_err; - int conn_status; - - conn_status = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - - if (conn_status) { - net_buf_simple_init(buf, 0); - rp = net_buf_simple_add(buf, sizeof(*rp)); - - ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, - handle, 0, buf, - &out_att_err); - - rp->att_response = out_att_err; - rp->value_length = os_mbuf_len(buf) - sizeof(*rp); - - tester_send_buf(BTP_SERVICE_ID_GATT, GATT_GET_ATTRIBUTE_VALUE, - CONTROLLER_INDEX, buf); - - goto free; - } else { - net_buf_simple_init(buf, 0); - rp = net_buf_simple_add(buf, sizeof(*rp)); - - ble_att_svr_read_handle(conn.conn_handle, - handle, 0, buf, - &out_att_err); - - rp->att_response = out_att_err; - rp->value_length = os_mbuf_len(buf) - sizeof(*rp); - - tester_send_buf(BTP_SERVICE_ID_GATT, GATT_GET_ATTRIBUTE_VALUE, - CONTROLLER_INDEX, buf); - - goto free; - } + os_mbuf_free_chain(buf); +} + +static void +get_attr_val(u8_t *data, u16_t len) +{ + const struct gatt_get_attribute_value_cmd *cmd = (void *) data; + struct gatt_get_attribute_value_rp *rp; + struct ble_gap_conn_desc conn; + struct os_mbuf *buf = os_msys_get(0, 0); + u16_t handle = sys_cpu_to_le16(cmd->handle); + uint8_t out_att_err; + int conn_status; + + conn_status = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); + + if (conn_status) { + net_buf_simple_init(buf, 0); + rp = net_buf_simple_add(buf, sizeof(*rp)); + + ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, + handle, 0, buf, + &out_att_err); + + rp->att_response = out_att_err; + rp->value_length = os_mbuf_len(buf) - sizeof(*rp); + + tester_send_buf(BTP_SERVICE_ID_GATT, GATT_GET_ATTRIBUTE_VALUE, + CONTROLLER_INDEX, buf); + + goto free; + } else { + net_buf_simple_init(buf, 0); + rp = net_buf_simple_add(buf, sizeof(*rp)); + + ble_att_svr_read_handle(conn.conn_handle, + handle, 0, buf, + &out_att_err); + + rp->att_response = out_att_err; + rp->value_length = os_mbuf_len(buf) - sizeof(*rp); + + tester_send_buf(BTP_SERVICE_ID_GATT, GATT_GET_ATTRIBUTE_VALUE, + CONTROLLER_INDEX, buf); + + goto free; + } free: - os_mbuf_free_chain(buf); -} - -static void change_database(u8_t *data, u16_t len) -{ - const struct gatt_change_database *cmd = (void *) data; - - SYS_LOG_DBG("") - - ble_gatts_show_local(); - - ble_svc_gatt_changed(cmd->start_handle, cmd->end_handle); - - tester_rsp(BTP_SERVICE_ID_GATT, GATT_CHANGE_DATABASE, CONTROLLER_INDEX, - BTP_STATUS_SUCCESS); - - return; -} - -static void supported_commands(u8_t *data, u16_t len) -{ - u8_t cmds[4]; - struct gatt_read_supported_commands_rp *rp = (void *) cmds; - - SYS_LOG_DBG(""); - - memset(cmds, 0, sizeof(cmds)); - - tester_set_bit(cmds, GATT_READ_SUPPORTED_COMMANDS); - tester_set_bit(cmds, GATT_START_SERVER); - tester_set_bit(cmds, GATT_EXCHANGE_MTU); - tester_set_bit(cmds, GATT_DISC_ALL_PRIM_SVCS); - tester_set_bit(cmds, GATT_DISC_PRIM_UUID); - tester_set_bit(cmds, GATT_FIND_INCLUDED); - tester_set_bit(cmds, GATT_DISC_ALL_CHRC); - tester_set_bit(cmds, GATT_DISC_CHRC_UUID); - tester_set_bit(cmds, GATT_DISC_ALL_DESC); - tester_set_bit(cmds, GATT_READ); - tester_set_bit(cmds, GATT_READ_LONG); - tester_set_bit(cmds, GATT_READ_MULTIPLE); + os_mbuf_free_chain(buf); +} + +static void +change_database(u8_t *data, u16_t len) +{ + const struct gatt_change_database *cmd = (void *) data; + + SYS_LOG_DBG("") + + ble_gatts_show_local(); + + ble_svc_gatt_changed(cmd->start_handle, cmd->end_handle); + + tester_rsp(BTP_SERVICE_ID_GATT, GATT_CHANGE_DATABASE, CONTROLLER_INDEX, + BTP_STATUS_SUCCESS); + + return; +} + +static void +supported_commands(u8_t *data, u16_t len) +{ + u8_t cmds[4]; + struct gatt_read_supported_commands_rp *rp = (void *) cmds; + + SYS_LOG_DBG(""); + + memset(cmds, 0, sizeof(cmds)); + + tester_set_bit(cmds, GATT_READ_SUPPORTED_COMMANDS); + tester_set_bit(cmds, GATT_START_SERVER); + tester_set_bit(cmds, GATT_EXCHANGE_MTU); + tester_set_bit(cmds, GATT_DISC_ALL_PRIM_SVCS); + tester_set_bit(cmds, GATT_DISC_PRIM_UUID); + tester_set_bit(cmds, GATT_FIND_INCLUDED); + tester_set_bit(cmds, GATT_DISC_ALL_CHRC); + tester_set_bit(cmds, GATT_DISC_CHRC_UUID); + tester_set_bit(cmds, GATT_DISC_ALL_DESC); + tester_set_bit(cmds, GATT_READ); + tester_set_bit(cmds, GATT_READ_LONG); + tester_set_bit(cmds, GATT_READ_MULTIPLE); tester_set_bit(cmds, GATT_READ_MULTIPLE_VAR); - tester_set_bit(cmds, GATT_WRITE_WITHOUT_RSP); + tester_set_bit(cmds, GATT_WRITE_WITHOUT_RSP); #if 0 - tester_set_bit(cmds, GATT_SIGNED_WRITE_WITHOUT_RSP); + tester_set_bit(cmds, GATT_SIGNED_WRITE_WITHOUT_RSP); #endif - tester_set_bit(cmds, GATT_WRITE); - tester_set_bit(cmds, GATT_WRITE_LONG); - tester_set_bit(cmds, GATT_CFG_NOTIFY); - tester_set_bit(cmds, GATT_CFG_INDICATE); - tester_set_bit(cmds, GATT_GET_ATTRIBUTES); - tester_set_bit(cmds, GATT_GET_ATTRIBUTE_VALUE); - tester_set_bit(cmds, GATT_CHANGE_DATABASE); - - tester_send(BTP_SERVICE_ID_GATT, GATT_READ_SUPPORTED_COMMANDS, - CONTROLLER_INDEX, (u8_t *) rp, sizeof(cmds)); + tester_set_bit(cmds, GATT_WRITE); + tester_set_bit(cmds, GATT_WRITE_LONG); + tester_set_bit(cmds, GATT_CFG_NOTIFY); + tester_set_bit(cmds, GATT_CFG_INDICATE); + tester_set_bit(cmds, GATT_GET_ATTRIBUTES); + tester_set_bit(cmds, GATT_GET_ATTRIBUTE_VALUE); + tester_set_bit(cmds, GATT_CHANGE_DATABASE); + + tester_send(BTP_SERVICE_ID_GATT, GATT_READ_SUPPORTED_COMMANDS, + CONTROLLER_INDEX, (u8_t *) rp, sizeof(cmds)); } enum attr_type { - BLE_GATT_ATTR_SVC = 0, - BLE_GATT_ATTR_CHR, - BLE_GATT_ATTR_DSC, + BLE_GATT_ATTR_SVC = 0, + BLE_GATT_ATTR_CHR, + BLE_GATT_ATTR_DSC, }; -void tester_handle_gatt(u8_t opcode, u8_t index, u8_t *data, - u16_t len) -{ - switch (opcode) { - case GATT_READ_SUPPORTED_COMMANDS: - supported_commands(data, len); - return; - case GATT_START_SERVER: - start_server(data, len); - return; - case GATT_EXCHANGE_MTU: - exchange_mtu(data, len); - return; - case GATT_DISC_ALL_PRIM_SVCS: - disc_all_prim_svcs(data, len); - return; - case GATT_DISC_PRIM_UUID: - disc_prim_uuid(data, len); - return; - case GATT_FIND_INCLUDED: - find_included(data, len); - return; - case GATT_DISC_ALL_CHRC: - disc_all_chrc(data, len); - return; - case GATT_DISC_CHRC_UUID: - disc_chrc_uuid(data, len); - return; - case GATT_DISC_ALL_DESC: - disc_all_desc(data, len); - return; - case GATT_CHANGE_DATABASE: - change_database(data, len); - return; - case GATT_READ: - read(data, len); - return; - case GATT_READ_UUID: - read_uuid(data, len); - return; - case GATT_READ_LONG: - read_long(data, len); - return; - case GATT_READ_MULTIPLE: - read_multiple(data, len); - return; - case GATT_READ_MULTIPLE_VAR: - read_multiple_var(data, len); - return; - case GATT_WRITE_WITHOUT_RSP: - write_without_rsp(data, len, opcode, false); - return; +void +tester_handle_gatt(u8_t opcode, u8_t index, u8_t *data, + u16_t len) +{ + switch (opcode) { + case GATT_READ_SUPPORTED_COMMANDS: + supported_commands(data, len); + return; + case GATT_START_SERVER: + start_server(data, len); + return; + case GATT_EXCHANGE_MTU: + exchange_mtu(data, len); + return; + case GATT_DISC_ALL_PRIM_SVCS: + disc_all_prim_svcs(data, len); + return; + case GATT_DISC_PRIM_UUID: + disc_prim_uuid(data, len); + return; + case GATT_FIND_INCLUDED: + find_included(data, len); + return; + case GATT_DISC_ALL_CHRC: + disc_all_chrc(data, len); + return; + case GATT_DISC_CHRC_UUID: + disc_chrc_uuid(data, len); + return; + case GATT_DISC_ALL_DESC: + disc_all_desc(data, len); + return; + case GATT_CHANGE_DATABASE: + change_database(data, len); + return; + case GATT_READ: + read(data, len); + return; + case GATT_READ_UUID: + read_uuid(data, len); + return; + case GATT_READ_LONG: + read_long(data, len); + return; + case GATT_READ_MULTIPLE: + read_multiple(data, len); + return; + case GATT_READ_MULTIPLE_VAR: + read_multiple_var(data, len); + return; + case GATT_WRITE_WITHOUT_RSP: + write_without_rsp(data, len, opcode, false); + return; #if 0 - case GATT_SIGNED_WRITE_WITHOUT_RSP: - write_without_rsp(data, len, opcode, true); - return; + case GATT_SIGNED_WRITE_WITHOUT_RSP: + write_without_rsp(data, len, opcode, true); + return; #endif - case GATT_WRITE: - write(data, len); - return; - case GATT_WRITE_LONG: - write_long(data, len); - return; - case GATT_RELIABLE_WRITE: - reliable_write(data, len); - return; - case GATT_CFG_NOTIFY: - case GATT_CFG_INDICATE: - config_subscription(data, len, opcode); - return; - case GATT_GET_ATTRIBUTES: - get_attrs(data, len); - return; - case GATT_GET_ATTRIBUTE_VALUE: - get_attr_val(data, len); - return; - default: - tester_rsp(BTP_SERVICE_ID_GATT, opcode, index, - BTP_STATUS_UNKNOWN_CMD); - return; - } -} - -int tester_gatt_notify_rx_ev(u16_t conn_handle, u16_t attr_handle, - u8_t indication, struct os_mbuf *om) -{ - struct gatt_notification_ev *ev; - struct ble_gap_conn_desc conn; - struct os_mbuf *buf = os_msys_get(0, 0); - const ble_addr_t *addr; - - SYS_LOG_DBG(""); - - if (!subscribe_params.ccc_handle) { - goto fail; - } - - if (ble_gap_conn_find(conn_handle, &conn)) { - goto fail; - } - - net_buf_simple_init(buf, 0); - ev = net_buf_simple_add(buf, sizeof(*ev)); - - addr = &conn.peer_ota_addr; - - ev->address_type = addr->type; - memcpy(ev->address, addr->val, sizeof(ev->address)); - ev->type = (u8_t) (indication ? 0x02 : 0x01); - ev->handle = sys_cpu_to_le16(attr_handle); - ev->data_length = sys_cpu_to_le16(os_mbuf_len(om)); - os_mbuf_appendfrom(buf, om, 0, os_mbuf_len(om)); - - tester_send_buf(BTP_SERVICE_ID_GATT, GATT_EV_NOTIFICATION, - CONTROLLER_INDEX, buf); + case GATT_WRITE: + write(data, len); + return; + case GATT_WRITE_LONG: + write_long(data, len); + return; + case GATT_RELIABLE_WRITE: + reliable_write(data, len); + return; + case GATT_CFG_NOTIFY: + case GATT_CFG_INDICATE: + config_subscription(data, len, opcode); + return; + case GATT_GET_ATTRIBUTES: + get_attrs(data, len); + return; + case GATT_GET_ATTRIBUTE_VALUE: + get_attr_val(data, len); + return; + default: + tester_rsp(BTP_SERVICE_ID_GATT, opcode, index, + BTP_STATUS_UNKNOWN_CMD); + return; + } +} + +int +tester_gatt_notify_rx_ev(u16_t conn_handle, u16_t attr_handle, + u8_t indication, struct os_mbuf *om) +{ + struct gatt_notification_ev *ev; + struct ble_gap_conn_desc conn; + struct os_mbuf *buf = os_msys_get(0, 0); + const ble_addr_t *addr; + + SYS_LOG_DBG(""); + + if (!subscribe_params.ccc_handle) { + goto fail; + } + + if (ble_gap_conn_find(conn_handle, &conn)) { + goto fail; + } + + net_buf_simple_init(buf, 0); + ev = net_buf_simple_add(buf, sizeof(*ev)); + + addr = &conn.peer_ota_addr; + + ev->address_type = addr->type; + memcpy(ev->address, addr->val, sizeof(ev->address)); + ev->type = (u8_t) (indication ? 0x02 : 0x01); + ev->handle = sys_cpu_to_le16(attr_handle); + ev->data_length = sys_cpu_to_le16(os_mbuf_len(om)); + os_mbuf_appendfrom(buf, om, 0, os_mbuf_len(om)); + + tester_send_buf(BTP_SERVICE_ID_GATT, GATT_EV_NOTIFICATION, + CONTROLLER_INDEX, buf); fail: - os_mbuf_free_chain(buf); - return 0; -} - -void notify_test_stop(void) -{ - os_callout_stop(¬ify_tx_timer); -} - -void notify_test_reset(void) -{ - int rc; - - rc = os_callout_reset(¬ify_tx_timer, OS_TICKS_PER_SEC); - assert(rc == 0); -} - -void notify_test(struct os_event *ev) -{ - static uint8_t ntf[1]; - struct os_mbuf *om; - int rc; - - if (!notify_state && !indicate_state) { - notify_test_stop(); - notify_value = 90; - return; - } - - ntf[0] = notify_value; - - notify_value++; - if (notify_value == 160) { - notify_value = 90; - } - - om = ble_hs_mbuf_from_flat(ntf, sizeof(ntf)); - - if (notify_state) { - rc = ble_gattc_notify_custom(myconn_handle, notify_handle, om); - assert(rc == 0); - } - - if (indicate_state) { - rc = ble_gattc_indicate_custom(myconn_handle, notify_handle, om); - assert(rc == 0); - } -} - -int tester_gatt_subscribe_ev(u16_t conn_handle, u16_t attr_handle, u8_t reason, - u8_t prev_notify, u8_t cur_notify, - u8_t prev_indicate, u8_t cur_indicate) -{ - SYS_LOG_DBG(""); - myconn_handle = conn_handle; - - if (cur_notify == 0 && cur_indicate == 0) { - SYS_LOG_INF("Unsubscribed"); - memset(&subscribe_params, 0, sizeof(subscribe_params)); - return 0; - } - - if (cur_notify) { - SYS_LOG_INF("Subscribed to notifications"); - if (attr_handle == notify_handle) { - notify_state = cur_notify; - } - } - - if (cur_indicate) { - SYS_LOG_INF("Subscribed to indications"); - if (attr_handle == notify_handle) { - indicate_state = cur_indicate; - } - } - - - if (notify_state || indicate_state) { - notify_test_reset(); - } else { - notify_test_stop(); - } - - return 0; + os_mbuf_free_chain(buf); + return 0; +} + +void +notify_test_stop(void) +{ + os_callout_stop(¬ify_tx_timer); +} + +void +notify_test_reset(void) +{ + int rc; + + rc = os_callout_reset(¬ify_tx_timer, OS_TICKS_PER_SEC); + assert(rc == 0); +} + +void +notify_test(struct os_event *ev) +{ + static uint8_t ntf[1]; + struct os_mbuf *om; + int rc; + + if (!notify_state && !indicate_state) { + notify_test_stop(); + notify_value = 90; + return; + } + + ntf[0] = notify_value; + + notify_value++; + if (notify_value == 160) { + notify_value = 90; + } + + om = ble_hs_mbuf_from_flat(ntf, sizeof(ntf)); + + if (notify_state) { + rc = ble_gattc_notify_custom(myconn_handle, notify_handle, om); + assert(rc == 0); + } + + if (indicate_state) { + rc = ble_gattc_indicate_custom(myconn_handle, notify_handle, om); + assert(rc == 0); + } +} + +int +tester_gatt_subscribe_ev(u16_t conn_handle, u16_t attr_handle, u8_t reason, + u8_t prev_notify, u8_t cur_notify, + u8_t prev_indicate, u8_t cur_indicate) +{ + SYS_LOG_DBG(""); + myconn_handle = conn_handle; + + if (cur_notify == 0 && cur_indicate == 0) { + SYS_LOG_INF("Unsubscribed"); + memset(&subscribe_params, 0, sizeof(subscribe_params)); + return 0; + } + + if (cur_notify) { + SYS_LOG_INF("Subscribed to notifications"); + if (attr_handle == notify_handle) { + notify_state = cur_notify; + } + } + + if (cur_indicate) { + SYS_LOG_INF("Subscribed to indications"); + if (attr_handle == notify_handle) { + indicate_state = cur_indicate; + } + } + + + if (notify_state || indicate_state) { + notify_test_reset(); + } else { + notify_test_stop(); + } + + return 0; } void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) { - char buf[BLE_UUID_STR_LEN]; - - switch (ctxt->op) { - case BLE_GATT_REGISTER_OP_SVC: - MODLOG_DFLT(DEBUG, "registered service %s with handle=%d\n", - ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf), - ctxt->svc.handle); - break; - - case BLE_GATT_REGISTER_OP_CHR: - MODLOG_DFLT(DEBUG, "registering characteristic %s with " - "def_handle=%d val_handle=%d\n", - ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf), - ctxt->chr.def_handle, - ctxt->chr.val_handle); - break; - - case BLE_GATT_REGISTER_OP_DSC: - MODLOG_DFLT(DEBUG, "registering descriptor %s with handle=%d\n", - ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf), - ctxt->dsc.handle); - break; - - default: - assert(0); - break; - } -} - -int gatt_svr_init(void) -{ - int rc; - - rc = ble_gatts_count_cfg(gatt_svr_inc_svcs); - if (rc != 0) { - return rc; - } - - rc = ble_gatts_add_svcs(gatt_svr_inc_svcs); - if (rc != 0) { - return rc; - } - - rc = ble_gatts_count_cfg(gatt_svr_svcs); - if (rc != 0) { - return rc; - } - - rc = ble_gatts_add_svcs(gatt_svr_svcs); - if (rc != 0) { - return rc; - } - - return 0; -} - -u8_t tester_init_gatt(void) -{ - os_callout_init(¬ify_tx_timer, os_eventq_dflt_get(), - notify_test, NULL); - - return BTP_STATUS_SUCCESS; -} - -u8_t tester_unregister_gatt(void) -{ - return BTP_STATUS_SUCCESS; -} + char buf[BLE_UUID_STR_LEN]; + + switch (ctxt->op) { + case BLE_GATT_REGISTER_OP_SVC: + MODLOG_DFLT(DEBUG, "registered service %s with handle=%d\n", + ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf), + ctxt->svc.handle); + break; + + case BLE_GATT_REGISTER_OP_CHR: + MODLOG_DFLT(DEBUG, "registering characteristic %s with " + "def_handle=%d val_handle=%d\n", + ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf), + ctxt->chr.def_handle, + ctxt->chr.val_handle); + break; + + case BLE_GATT_REGISTER_OP_DSC: + MODLOG_DFLT(DEBUG, "registering descriptor %s with handle=%d\n", + ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf), + ctxt->dsc.handle); + break; + + default: + assert(0); + break; + } +} + +int +gatt_svr_init(void) +{ + int rc; + + rc = ble_gatts_count_cfg(gatt_svr_inc_svcs); + if (rc != 0) { + return rc; + } + + rc = ble_gatts_add_svcs(gatt_svr_inc_svcs); + if (rc != 0) { + return rc; + } + + rc = ble_gatts_count_cfg(gatt_svr_svcs); + if (rc != 0) { + return rc; + } + + rc = ble_gatts_add_svcs(gatt_svr_svcs); + if (rc != 0) { + return rc; + } + + return 0; +} + +u8_t +tester_init_gatt(void) +{ + os_callout_init(¬ify_tx_timer, os_eventq_dflt_get(), + notify_test, NULL); + + return BTP_STATUS_SUCCESS; +} + +u8_t +tester_unregister_gatt(void) +{ + return BTP_STATUS_SUCCESS; +} ``` </details> ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: [email protected]
