| /* |
| * 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 <string.h> |
| #include <errno.h> |
| #include "testutil/testutil.h" |
| #include "host/ble_uuid.h" |
| #include "host/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(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); |
| |
| } |
| |
| TEST_CASE(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); |
| } |
| |
| TEST_SUITE(ble_gatts_read_test_suite) |
| { |
| tu_suite_set_post_test_cb(ble_hs_test_util_post_test, NULL); |
| |
| ble_gatts_read_test_case_basic(); |
| ble_gatts_read_test_case_long(); |
| } |