Bluetooth: Host: Define bt_att_err_to_str()

This can be useful if application developers
want to print them in the applications.

Later we can also use them in
the host to improve debuggability.

Signed-off-by: Rubin Gerritsen <rubin.gerritsen@nordicsemi.no>
This commit is contained in:
Rubin Gerritsen 2024-06-14 10:25:50 +02:00 committed by Alberto Escolar
commit 94d712e5cf
3 changed files with 92 additions and 0 deletions

View file

@ -101,6 +101,22 @@ extern "C" {
#define BT_ATT_LAST_ATTRIBUTE_HANDLE 0xffff
#define BT_ATT_LAST_ATTTRIBUTE_HANDLE __DEPRECATED_MACRO BT_ATT_LAST_ATTRIBUTE_HANDLE
/** Converts a ATT error to string.
*
* The error codes are described in the Bluetooth Core specification,
* Vol 3, Part F, Section 3.4.1.1 and in
* The Supplement to the Bluetooth Core Specification (CSS), v11,
* Part B, Section 1.2.
*
* The ATT and GATT documentation found in Vol 4, Part F and
* Part G describe when the different error codes are used.
*
* See also the defined BT_ATT_ERR_* macros.
*
* @return The string representation of the ATT error code.
*/
const char *bt_att_err_to_str(uint8_t att_err);
#if defined(CONFIG_BT_EATT)
#if defined(CONFIG_BT_TESTING)

View file

@ -185,6 +185,61 @@ static struct bt_att_tx_meta_data tx_meta_data_storage[CONFIG_BT_ATT_TX_COUNT];
struct bt_att_tx_meta_data *bt_att_get_tx_meta_data(const struct net_buf *buf);
static void att_on_sent_cb(struct bt_att_tx_meta_data *meta);
const char *bt_att_err_to_str(uint8_t att_err)
{
/* To mapping tables are used to avoid a big gap with NULL-entries. */
#define ATT_ERR(err) [err] = #err
#define ATT_ERR_SECOND(err) [err - BT_ATT_ERR_WRITE_REQ_REJECTED] = #err
const char * const first_mapping_table[] = {
ATT_ERR(BT_ATT_ERR_SUCCESS),
ATT_ERR(BT_ATT_ERR_INVALID_HANDLE),
ATT_ERR(BT_ATT_ERR_READ_NOT_PERMITTED),
ATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED),
ATT_ERR(BT_ATT_ERR_INVALID_PDU),
ATT_ERR(BT_ATT_ERR_AUTHENTICATION),
ATT_ERR(BT_ATT_ERR_NOT_SUPPORTED),
ATT_ERR(BT_ATT_ERR_INVALID_OFFSET),
ATT_ERR(BT_ATT_ERR_AUTHORIZATION),
ATT_ERR(BT_ATT_ERR_PREPARE_QUEUE_FULL),
ATT_ERR(BT_ATT_ERR_ATTRIBUTE_NOT_FOUND),
ATT_ERR(BT_ATT_ERR_ATTRIBUTE_NOT_LONG),
ATT_ERR(BT_ATT_ERR_ENCRYPTION_KEY_SIZE),
ATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN),
ATT_ERR(BT_ATT_ERR_UNLIKELY),
ATT_ERR(BT_ATT_ERR_INSUFFICIENT_ENCRYPTION),
ATT_ERR(BT_ATT_ERR_UNSUPPORTED_GROUP_TYPE),
ATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES),
ATT_ERR(BT_ATT_ERR_DB_OUT_OF_SYNC),
ATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED),
};
const char * const second_mapping_table[] = {
ATT_ERR_SECOND(BT_ATT_ERR_WRITE_REQ_REJECTED),
ATT_ERR_SECOND(BT_ATT_ERR_CCC_IMPROPER_CONF),
ATT_ERR_SECOND(BT_ATT_ERR_PROCEDURE_IN_PROGRESS),
ATT_ERR_SECOND(BT_ATT_ERR_OUT_OF_RANGE),
};
if (att_err < ARRAY_SIZE(first_mapping_table) && first_mapping_table[att_err]) {
return first_mapping_table[att_err];
} else if (att_err >= BT_ATT_ERR_WRITE_REQ_REJECTED) {
const uint8_t second_index = att_err - BT_ATT_ERR_WRITE_REQ_REJECTED;
if (second_index < ARRAY_SIZE(second_mapping_table) &&
second_mapping_table[second_index]) {
return second_mapping_table[second_index];
}
}
return "(unknown)";
#undef ATT_ERR
#undef ATT_ERR_SECOND
}
static void att_tx_destroy(struct net_buf *buf)
{
struct bt_att_tx_meta_data *p_meta = bt_att_get_tx_meta_data(buf);

View file

@ -274,3 +274,24 @@ ZTEST(test_gatt, test_gatt_write)
zassert_mem_equal(value, test_value, ret,
"Attribute write value don't match");
}
ZTEST(test_gatt, test_bt_att_err_to_str)
{
/* Test a couple of entries */
zassert_str_equal(bt_att_err_to_str(BT_ATT_ERR_SUCCESS),
"BT_ATT_ERR_SUCCESS");
zassert_str_equal(bt_att_err_to_str(BT_ATT_ERR_INSUFFICIENT_ENCRYPTION),
"BT_ATT_ERR_INSUFFICIENT_ENCRYPTION");
zassert_str_equal(bt_att_err_to_str(BT_ATT_ERR_OUT_OF_RANGE),
"BT_ATT_ERR_OUT_OF_RANGE");
/* Test a entries that is not used */
zassert_mem_equal(bt_att_err_to_str(0x14),
"(unknown)", strlen("(unknown)"));
zassert_mem_equal(bt_att_err_to_str(0xFB),
"(unknown)", strlen("(unknown)"));
for (uint16_t i = 0; i <= UINT8_MAX; i++) {
zassert_not_null(bt_att_err_to_str(i), ": %d", i);
}
}