/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include "testutil/testutil.h" #include "host/ble_uuid.h" #include "ble_hs_test.h" #include "ble_hs_test_util.h" #define BLE_GATTS_READ_TEST_CHR_1_UUID 0x1111 #define BLE_GATTS_READ_TEST_CHR_2_UUID 0x2222 static uint8_t ble_gatts_read_test_peer_addr[6] = {2,3,4,5,6,7}; static int ble_gatts_read_test_util_access_1(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); static int ble_gatts_read_test_util_access_2(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); static void ble_gatts_read_test_misc_reg_cb(struct ble_gatt_register_ctxt *ctxt, void *arg); static const struct ble_gatt_svc_def ble_gatts_read_test_svcs[] = { { .type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = BLE_UUID16_DECLARE(0x1234), .characteristics = (struct ble_gatt_chr_def[]) { { .uuid = BLE_UUID16_DECLARE(BLE_GATTS_READ_TEST_CHR_1_UUID), .access_cb = ble_gatts_read_test_util_access_1, .flags = BLE_GATT_CHR_F_READ }, { .uuid = BLE_UUID16_DECLARE(BLE_GATTS_READ_TEST_CHR_2_UUID), .access_cb = ble_gatts_read_test_util_access_2, .flags = BLE_GATT_CHR_F_READ }, { 0 } }, }, { 0 } }; static uint16_t ble_gatts_read_test_chr_1_def_handle; static uint16_t ble_gatts_read_test_chr_1_val_handle; static uint8_t ble_gatts_read_test_chr_1_val[1024]; static int ble_gatts_read_test_chr_1_len; static uint16_t ble_gatts_read_test_chr_2_def_handle; static uint16_t ble_gatts_read_test_chr_2_val_handle; static void ble_gatts_read_test_misc_init(uint16_t *out_conn_handle) { ble_hs_test_util_init(); ble_hs_test_util_reg_svcs(ble_gatts_read_test_svcs, ble_gatts_read_test_misc_reg_cb, NULL); TEST_ASSERT_FATAL(ble_gatts_read_test_chr_1_def_handle != 0); TEST_ASSERT_FATAL(ble_gatts_read_test_chr_1_val_handle == ble_gatts_read_test_chr_1_def_handle + 1); TEST_ASSERT_FATAL(ble_gatts_read_test_chr_2_def_handle != 0); TEST_ASSERT_FATAL(ble_gatts_read_test_chr_2_val_handle == ble_gatts_read_test_chr_2_def_handle + 1); ble_hs_test_util_create_conn(2, ble_gatts_read_test_peer_addr, NULL, NULL); if (out_conn_handle != NULL) { *out_conn_handle = 2; } } static void ble_gatts_read_test_misc_reg_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) { uint16_t uuid16; if (ctxt->op == BLE_GATT_REGISTER_OP_CHR) { uuid16 = ble_uuid_u16(ctxt->chr.chr_def->uuid); switch (uuid16) { case BLE_GATTS_READ_TEST_CHR_1_UUID: ble_gatts_read_test_chr_1_def_handle = ctxt->chr.def_handle; ble_gatts_read_test_chr_1_val_handle = ctxt->chr.val_handle; break; case BLE_GATTS_READ_TEST_CHR_2_UUID: ble_gatts_read_test_chr_2_def_handle = ctxt->chr.def_handle; ble_gatts_read_test_chr_2_val_handle = ctxt->chr.val_handle; break; default: TEST_ASSERT_FATAL(0); break; } } } static int ble_gatts_read_test_util_access_1(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { int rc; TEST_ASSERT_FATAL(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); TEST_ASSERT_FATAL(attr_handle == ble_gatts_read_test_chr_1_val_handle); TEST_ASSERT(ctxt->chr == &ble_gatts_read_test_svcs[0].characteristics[0]); rc = os_mbuf_append(ctxt->om, ble_gatts_read_test_chr_1_val, ble_gatts_read_test_chr_1_len); TEST_ASSERT(rc == 0); return 0; } static int ble_gatts_read_test_util_access_2(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { uint8_t *buf; TEST_ASSERT_FATAL(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); TEST_ASSERT_FATAL(attr_handle == ble_gatts_read_test_chr_2_def_handle + 1); TEST_ASSERT(ctxt->chr == &ble_gatts_read_test_svcs[0].characteristics[1]); buf = os_mbuf_extend(ctxt->om, 6); TEST_ASSERT_FATAL(buf != NULL); buf[0] = 0; buf[1] = 10; buf[2] = 20; buf[3] = 30; buf[4] = 40; buf[5] = 50; return 0; } static void ble_gatts_read_test_once(uint16_t conn_handle, uint16_t attr_id, void *expected_value, uint16_t expected_len) { struct ble_att_read_req read_req; uint8_t buf[BLE_ATT_READ_REQ_SZ]; int rc; read_req.barq_handle = attr_id; ble_att_read_req_write(buf, sizeof buf, &read_req); rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc == 0); ble_hs_test_util_verify_tx_read_rsp(expected_value, expected_len); } TEST_CASE_SELF(ble_gatts_read_test_case_basic) { uint16_t conn_handle; ble_gatts_read_test_misc_init(&conn_handle); /*** Application points attribute at static data. */ ble_gatts_read_test_chr_1_val[0] = 1; ble_gatts_read_test_chr_1_val[1] = 2; ble_gatts_read_test_chr_1_val[2] = 3; ble_gatts_read_test_chr_1_len = 3; ble_gatts_read_test_once(conn_handle, ble_gatts_read_test_chr_1_val_handle, ble_gatts_read_test_chr_1_val, ble_gatts_read_test_chr_1_len); /*** Application uses stack-provided buffer for dynamic attribute. */ ble_gatts_read_test_once(conn_handle, ble_gatts_read_test_chr_2_def_handle + 1, ((uint8_t[6]){0,10,20,30,40,50}), 6); ble_hs_test_util_assert_mbufs_freed(NULL); } TEST_CASE_SELF(ble_gatts_read_test_case_long) { struct ble_att_read_blob_req read_blob_req; struct ble_att_read_req read_req; uint8_t buf[max(BLE_ATT_READ_REQ_SZ, BLE_ATT_READ_BLOB_REQ_SZ)]; uint16_t conn_handle; int rc; int i; ble_gatts_read_test_misc_init(&conn_handle); /*** Prepare characteristic value. */ ble_gatts_read_test_chr_1_len = 40; for (i = 0; i < ble_gatts_read_test_chr_1_len; i++) { ble_gatts_read_test_chr_1_val[i] = i; } /* Receive first read request. */ read_req.barq_handle = ble_gatts_read_test_chr_1_val_handle; ble_att_read_req_write(buf, sizeof buf, &read_req); rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc == 0); ble_hs_test_util_verify_tx_read_rsp(ble_gatts_read_test_chr_1_val, 22); /* Receive follow-up read blob request. */ read_blob_req.babq_handle = ble_gatts_read_test_chr_1_val_handle; read_blob_req.babq_offset = 22; ble_att_read_blob_req_write(buf, sizeof buf, &read_blob_req); rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, buf, sizeof buf); TEST_ASSERT(rc == 0); /* Ensure response starts at appropriate offset (22). */ ble_hs_test_util_verify_tx_read_blob_rsp( ble_gatts_read_test_chr_1_val + 22, 18); ble_hs_test_util_assert_mbufs_freed(NULL); } TEST_SUITE(ble_gatts_read_test_suite) { ble_gatts_read_test_case_basic(); ble_gatts_read_test_case_long(); }