/* btp_has.c - Bluetooth HAS Tester */ /* * Copyright (c) 2023 Oticon * * SPDX-License-Identifier: Apache-2.0 */ #include #include "btp/btp.h" #include #include #include #include #define LOG_MODULE_NAME bttester_has LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_BTTESTER_LOG_LEVEL); static uint8_t has_supported_commands(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) { struct btp_has_read_supported_commands_rp *rp = rsp; tester_set_bit(rp->data, BTP_HAS_READ_SUPPORTED_COMMANDS); tester_set_bit(rp->data, BTP_HAS_SET_ACTIVE_INDEX); tester_set_bit(rp->data, BTP_HAS_SET_PRESET_NAME); tester_set_bit(rp->data, BTP_HAS_REMOVE_PRESET); tester_set_bit(rp->data, BTP_HAS_ADD_PRESET); tester_set_bit(rp->data, BTP_HAS_SET_PROPERTIES); *rsp_len = sizeof(*rp) + 1; return BTP_STATUS_SUCCESS; } static uint8_t has_set_active_index(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) { const struct btp_has_set_active_index_cmd *cp = cmd; int err = bt_has_preset_active_set(cp->index); return BTP_STATUS_VAL(err); } static uint16_t has_presets; static char temp_name[BT_HAS_PRESET_NAME_MAX + 1]; static uint8_t has_set_preset_name(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) { const struct btp_has_set_preset_name_cmd *cp = cmd; const uint16_t fixed_size = sizeof(*cp); int err = -1; if (cmd_len >= fixed_size && cmd_len >= (fixed_size + cp->length)) { int name_len = MIN(cp->length, BT_HAS_PRESET_NAME_MAX); memcpy(temp_name, cp->name, name_len); temp_name[name_len] = '\0'; err = bt_has_preset_name_change(cp->index, temp_name); } return BTP_STATUS_VAL(err); } static uint8_t has_remove_preset(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) { const struct btp_has_remove_preset_cmd *cp = cmd; int err = 0; if (cp->index == BT_HAS_PRESET_INDEX_NONE) { while (has_presets) { uint8_t index = find_lsb_set(has_presets); err = bt_has_preset_unregister(index); if (err) { break; } has_presets &= ~(1 << (index - 1)); } } else { err = bt_has_preset_unregister(cp->index); if (!err) { has_presets &= ~(1 << (cp->index - 1)); } } return BTP_STATUS_VAL(err); } static int has_preset_selected(unsigned char index, bool sync) { return BTP_STATUS_SUCCESS; } static const struct bt_has_preset_ops has_preset_ops = { has_preset_selected, NULL }; static uint8_t has_add_preset(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) { const struct btp_has_add_preset_cmd *cp = cmd; const uint16_t fixed_size = sizeof(*cp); int err = -1; if (cmd_len >= fixed_size && cmd_len >= (fixed_size + cp->length)) { int name_len = MIN(cp->length, BT_HAS_PRESET_NAME_MAX); memcpy(temp_name, cp->name, name_len); temp_name[name_len] = '\0'; struct bt_has_preset_register_param preset_params = { cp->index, cp->props, temp_name, &has_preset_ops }; err = bt_has_preset_register(&preset_params); if (!err) { has_presets |= 1 << (cp->index - 1); } } return BTP_STATUS_VAL(err); } static uint8_t has_set_properties(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) { const struct btp_has_set_properties_cmd *cp = cmd; int err = (cp->props & BT_HAS_PROP_AVAILABLE) ? bt_has_preset_available(cp->index) : bt_has_preset_unavailable(cp->index); return BTP_STATUS_VAL(err); } static const struct btp_handler has_handlers[] = { { .opcode = BTP_HAS_READ_SUPPORTED_COMMANDS, .index = BTP_INDEX_NONE, .expect_len = 0, .func = has_supported_commands }, { .opcode = BTP_HAS_SET_ACTIVE_INDEX, .expect_len = sizeof(struct btp_has_set_active_index_cmd), .func = has_set_active_index }, { .opcode = BTP_HAS_SET_PRESET_NAME, .expect_len = BTP_HANDLER_LENGTH_VARIABLE, .func = has_set_preset_name }, { .opcode = BTP_HAS_REMOVE_PRESET, .expect_len = sizeof(struct btp_has_remove_preset_cmd), .func = has_remove_preset }, { .opcode = BTP_HAS_ADD_PRESET, .expect_len = BTP_HANDLER_LENGTH_VARIABLE, .func = has_add_preset }, { .opcode = BTP_HAS_SET_PROPERTIES, .expect_len = sizeof(struct btp_has_set_properties_cmd), .func = has_set_properties } }; uint8_t tester_init_has(void) { tester_register_command_handlers(BTP_SERVICE_ID_HAS, has_handlers, ARRAY_SIZE(has_handlers)); struct bt_has_features_param params = { .type = BT_HAS_HEARING_AID_TYPE_BINAURAL, .preset_sync_support = false, .independent_presets = IS_ENABLED(CONFIG_BT_HAS_PRESET_SUPPORT) }; int err = bt_has_register(¶ms); return BTP_STATUS_VAL(err); } uint8_t tester_unregister_has(void) { return BTP_STATUS_SUCCESS; }