static void prphtest_register_cb(uint8_t op, union ble_gatt_register_ctxt *ctxt, void *arg) { uint16_t uuid16; switch (op) { case BLE_GATT_REGISTER_OP_SVC: uuid16 = ble_uuid_128_to_16(ctxt->svc_reg.svc->uuid128); assert(uuid16 != 0); console_printf("registered service 0x%04x with handle=%d\n", uuid16, ctxt->svc_reg.handle); break; case BLE_GATT_REGISTER_OP_CHR: uuid16 = ble_uuid_128_to_16(ctxt->chr_reg.chr->uuid128); assert(uuid16 != 0); console_printf("registering characteristic 0x%04x with def_handle=%d " "val_handle=%d\n", uuid16, ctxt->chr_reg.def_handle, ctxt->chr_reg.val_handle); break; default: assert(0); break; } }
static void ble_gatt_disc_c_test_misc_verify_chars(struct ble_gatt_disc_c_test_char *chars, int stop_after) { uint16_t uuid16; int i; if (stop_after == 0) { stop_after = INT_MAX; } for (i = 0; i < stop_after && chars[i].decl_handle != 0; i++) { TEST_ASSERT(chars[i].decl_handle == ble_gatt_disc_c_test_chars[i].decl_handle); TEST_ASSERT(chars[i].value_handle == ble_gatt_disc_c_test_chars[i].value_handle); if (chars[i].uuid16 != 0) { uuid16 = ble_uuid_128_to_16(ble_gatt_disc_c_test_chars[i].uuid128); TEST_ASSERT(chars[i].uuid16 == uuid16); } else { TEST_ASSERT(memcmp(chars[i].uuid128, ble_gatt_disc_c_test_chars[i].uuid128, 16) == 0); } } TEST_ASSERT(i == ble_gatt_disc_c_test_num_chars); TEST_ASSERT(ble_gatt_disc_c_test_rx_complete); }
static int ble_gatt_find_s_test_misc_rx_read_type( uint16_t conn_handle, struct ble_gatt_find_s_test_entry *entries) { struct ble_att_read_type_rsp rsp; uint16_t uuid16; uint8_t buf[1024]; int off; int rc; int i; memset(&rsp, 0, sizeof rsp); off = BLE_ATT_READ_TYPE_RSP_BASE_SZ; for (i = 0; entries[i].inc_handle != 0; i++) { if (rsp.batp_length == BLE_GATTS_INC_SVC_LEN_NO_UUID + 2) { break; } uuid16 = ble_uuid_128_to_16(entries[i].uuid128); if (uuid16 == 0) { if (rsp.batp_length != 0) { break; } rsp.batp_length = BLE_GATTS_INC_SVC_LEN_NO_UUID + 2; } else { rsp.batp_length = BLE_GATTS_INC_SVC_LEN_UUID + 2; } TEST_ASSERT_FATAL(off + rsp.batp_length <= sizeof buf); htole16(buf + off, entries[i].inc_handle); off += 2; htole16(buf + off, entries[i].start_handle); off += 2; htole16(buf + off, entries[i].end_handle); off += 2; if (uuid16 != 0) { htole16(buf + off, uuid16); off += 2; } } if (i == 0) { ble_hs_test_util_rx_att_err_rsp(conn_handle, BLE_ATT_OP_READ_TYPE_REQ, BLE_ATT_ERR_ATTR_NOT_FOUND, 0); return 0; } ble_att_read_type_rsp_write(buf + 0, BLE_ATT_READ_TYPE_RSP_BASE_SZ, &rsp); rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, off); TEST_ASSERT(rc == 0); return i; }
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; int rc; uuid16 = ble_uuid_128_to_16(ctxt->chr->uuid128); assert(uuid16 != 0); switch (uuid16) { case BLE_SVC_GAP_CHR_UUID16_DEVICE_NAME: assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); rc = os_mbuf_append(ctxt->om, ble_svc_gap_name, strlen(ble_svc_gap_name)); return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; case BLE_SVC_GAP_CHR_UUID16_APPEARANCE: assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); rc = os_mbuf_append(ctxt->om, &ble_svc_gap_appearance, sizeof ble_svc_gap_appearance); return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; case BLE_SVC_GAP_CHR_UUID16_PERIPH_PRIV_FLAG: assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); rc = os_mbuf_append(ctxt->om, &ble_svc_gap_privacy_flag, sizeof ble_svc_gap_privacy_flag); return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; case BLE_SVC_GAP_CHR_UUID16_RECONNECT_ADDR: assert(ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR); if (OS_MBUF_PKTLEN(ctxt->om) != sizeof ble_svc_gap_reconnect_addr) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; } ble_hs_mbuf_to_flat(ctxt->om, ble_svc_gap_reconnect_addr, sizeof ble_svc_gap_reconnect_addr, NULL); return 0; case BLE_SVC_GAP_CHR_UUID16_PERIPH_PREF_CONN_PARAMS: assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); rc = os_mbuf_append(ctxt->om, &ble_svc_gap_pref_conn_params, sizeof ble_svc_gap_pref_conn_params); return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; default: assert(0); return BLE_ATT_ERR_UNLIKELY; } }
static void ble_gatt_find_s_test_misc_find_inc(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, struct ble_gatt_find_s_test_entry *entries) { struct ble_gatt_service service; int cur_start; int num_found; int idx; int rc; int i; rc = ble_gattc_find_inc_svcs(conn_handle, start_handle, end_handle, ble_gatt_find_s_test_misc_cb, &service); TEST_ASSERT(rc == 0); cur_start = start_handle; idx = 0; while (1) { ble_gatt_find_s_test_misc_verify_tx_read_type(cur_start, end_handle); num_found = ble_gatt_find_s_test_misc_rx_read_type(conn_handle, entries + idx); if (num_found == 0) { break; } if (ble_uuid_128_to_16(entries[idx].uuid128) == 0) { TEST_ASSERT(num_found == 1); ble_gatt_find_s_test_misc_verify_tx_read( entries[idx].start_handle); ble_gatt_find_s_test_misc_rx_read(conn_handle, entries[idx].uuid128); } idx += num_found; cur_start = entries[idx - 1].inc_handle + 1; } TEST_ASSERT(idx == ble_gatt_find_s_test_num_svcs); TEST_ASSERT(ble_gatt_find_s_test_proc_complete); for (i = 0; i < ble_gatt_find_s_test_num_svcs; i++) { TEST_ASSERT(ble_gatt_find_s_test_svcs[i].start_handle == entries[i].start_handle); TEST_ASSERT(ble_gatt_find_s_test_svcs[i].end_handle == entries[i].end_handle); TEST_ASSERT(memcmp(ble_gatt_find_s_test_svcs[i].uuid128, entries[i].uuid128, 16) == 0); } }
static char * gatt_svr_uuid_to_s(const void *uuid128, char *dst) { const uint8_t *u8p; uint16_t uuid16; uuid16 = ble_uuid_128_to_16(uuid128); if (uuid16 != 0) { sprintf(dst, "0x%04x", uuid16); return dst; } u8p = uuid128; sprintf(dst, "%02x%02x%02x%02x-", u8p[15], u8p[14], u8p[13], u8p[12]); sprintf(dst + 9, "%02x%02x-%02x%02x-", u8p[11], u8p[10], u8p[9], u8p[8]); sprintf(dst + 19, "%02x%02x%02x%02x%02x%02x%02x%02x", u8p[7], u8p[6], u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]); return dst; }
void print_uuid(void *uuid128) { uint16_t uuid16; uint8_t *u8p; uuid16 = ble_uuid_128_to_16(uuid128); if (uuid16 != 0) { console_printf("0x%04x", uuid16); return; } u8p = uuid128; /* 00001101-0000-1000-8000-00805f9b34fb */ console_printf("%02x%02x%02x%02x-", u8p[15], u8p[14], u8p[13], u8p[12]); console_printf("%02x%02x-%02x%02x-", u8p[11], u8p[10], u8p[9], u8p[8]); console_printf("%02x%02x%02x%02x%02x%02x%02x%02x", u8p[7], u8p[6], u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]); }
static int prphtest_gatt_cb(uint16_t conn_handle, uint16_t attr_handle, uint8_t op, union ble_gatt_access_ctxt *ctxt, void *arg) { static uint8_t buf[128]; uint16_t uuid16; assert(op == BLE_GATT_ACCESS_OP_READ_CHR); uuid16 = ble_uuid_128_to_16(ctxt->chr_access.chr->uuid128); switch (uuid16) { case PRPHTEST_CHR1_UUID: console_printf("reading characteristic1 value"); memcpy(buf, "char1", 5); ctxt->chr_access.len = 5; break; case PRPHTEST_CHR2_UUID: console_printf("reading characteristic2 value"); memcpy(buf, "char2", 5); ctxt->chr_access.len = 5; break; case PRPHTEST_CHR3_UUID: console_printf("reading characteristic3 value"); memcpy(buf, "char3", 5); ctxt->chr_access.len = 5; break; default: assert(0); break; } ctxt->chr_access.data = buf; return 0; }
int ble_uuid_append(struct os_mbuf *om, void *uuid128) { uint16_t uuid16; void *buf; int rc; uuid16 = ble_uuid_128_to_16(uuid128); if (uuid16 != 0) { buf = os_mbuf_extend(om, 2); if (buf == NULL) { return BLE_HS_ENOMEM; } htole16(buf, uuid16); } else { rc = os_mbuf_append(om, uuid128, 16); if (rc != 0) { return BLE_HS_ENOMEM; } } return 0; }
static int gatt_svr_chr_access_alert(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { uint16_t uuid16; int rc; uuid16 = ble_uuid_128_to_16(ctxt->chr->uuid128); assert(uuid16 != 0); switch (uuid16) { case GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID: assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); rc = os_mbuf_append(ctxt->om, &gatt_svr_new_alert_cat, sizeof gatt_svr_new_alert_cat); return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; case GATT_SVR_CHR_NEW_ALERT: if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { rc = gatt_svr_chr_write(ctxt->om, 0, sizeof gatt_svr_new_alert_val, gatt_svr_new_alert_val, &gatt_svr_new_alert_val_len); return rc; } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { rc = os_mbuf_append(ctxt->om, &gatt_svr_new_alert_val, sizeof gatt_svr_new_alert_val); return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; } case GATT_SVR_CHR_SUP_UNR_ALERT_CAT_UUID: assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); rc = os_mbuf_append(ctxt->om, &gatt_svr_unr_alert_cat, sizeof gatt_svr_unr_alert_cat); return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; case GATT_SVR_CHR_UNR_ALERT_STAT_UUID: if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { rc = gatt_svr_chr_write(ctxt->om, 2, 2, &gatt_svr_unr_alert_stat, NULL); return rc; } else { rc = os_mbuf_append(ctxt->om, &gatt_svr_unr_alert_stat, sizeof gatt_svr_unr_alert_stat); return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; } case GATT_SVR_CHR_ALERT_NOT_CTRL_PT: if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { rc = gatt_svr_chr_write(ctxt->om, 2, 2, &gatt_svr_alert_not_ctrl_pt, NULL); } else { rc = BLE_ATT_ERR_UNLIKELY; } return rc; default: assert(0); return BLE_ATT_ERR_UNLIKELY; } }