blob: 92ef8b189c7b774828dd61c7a6c1b11f873a89de [file] [log] [blame]
/*
* 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();
}