-
Notifications
You must be signed in to change notification settings - Fork 8.2k
Bluetooth: Immediate Alert Client #44794
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,10 +17,23 @@ | |
| * as a part of ongoing development. | ||
| */ | ||
|
|
||
| #include <zephyr/bluetooth/conn.h> | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| enum bt_ias_alert_lvl { | ||
| /** No alerting should be done on device */ | ||
| BT_IAS_ALERT_LVL_NO_ALERT, | ||
|
|
||
| /** Device shall alert */ | ||
| BT_IAS_ALERT_LVL_MILD_ALERT, | ||
|
|
||
| /** Device should alert in strongest possible way */ | ||
| BT_IAS_ALERT_LVL_HIGH_ALERT, | ||
| }; | ||
|
|
||
| /** @brief Immediate Alert Service callback structure. */ | ||
| struct bt_ias_cb { | ||
| /** | ||
|
|
@@ -59,6 +72,42 @@ int bt_ias_local_alert_stop(void); | |
| #define BT_IAS_CB_DEFINE(_name) \ | ||
| static const STRUCT_SECTION_ITERABLE(bt_ias_cb, _CONCAT(bt_ias_cb_, _name)) | ||
|
|
||
| struct bt_ias_client_cb { | ||
| /** @brief Callback function for bt_ias_discover. | ||
| * | ||
| * This callback is called when discovery procedure is complete. | ||
| * | ||
| * @param conn Bluetooth connection object. | ||
| * @param err 0 on success, ATT error or negative errno otherwise | ||
| */ | ||
| void (*discover)(struct bt_conn *conn, int err); | ||
| }; | ||
|
|
||
| /** @brief Set alert level | ||
| * | ||
| * @param conn Bluetooth connection object | ||
| * @param bt_ias_alert_lvl Level of alert to write | ||
| * | ||
| * @return Zero in case of success and error code in case of error. | ||
| */ | ||
| int bt_ias_client_alert_write(struct bt_conn *conn, enum bt_ias_alert_lvl); | ||
|
|
||
| /** @brief Discover Immediate Alert Service | ||
| * | ||
| * @param conn Bluetooth connection object | ||
| * | ||
| * @return Zero in case of success and error code in case of error. | ||
| */ | ||
| int bt_ias_discover(struct bt_conn *conn); | ||
|
|
||
| /** @brief Register Immediate Alert Client callbacks | ||
| * | ||
| * @param cb The callback structure | ||
| * | ||
| * @return Zero in case of success and error code in case of error. | ||
| */ | ||
| int bt_ias_client_cb_register(const struct bt_ias_client_cb *cb); | ||
|
||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| zephyr_sources_ifdef( | ||
| CONFIG_BT_IAS | ||
| ias.c) | ||
|
|
||
| zephyr_library_sources_ifdef( | ||
| CONFIG_BT_IAS_CLIENT | ||
| ias_client.c) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,12 +31,6 @@ LOG_MODULE_REGISTER(ias); | |
| #define IAS_ALERT_LEVEL_PERM BT_GATT_PERM_WRITE | ||
|
||
| #endif | ||
|
|
||
| enum bt_ias_alert_lvl { | ||
| BT_IAS_ALERT_LVL_NO_ALERT, | ||
| BT_IAS_ALERT_LVL_MILD_ALERT, | ||
| BT_IAS_ALERT_LVL_HIGH_ALERT, | ||
| }; | ||
|
|
||
| struct alerting_device { | ||
| enum bt_ias_alert_lvl alert_level; | ||
| }; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,193 @@ | ||
| /* | ||
| * Copyright (c) 2022 Codecoup | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| #include <errno.h> | ||
| #include <stdint.h> | ||
| #include <zephyr/sys/check.h> | ||
| #include <zephyr/logging/log.h> | ||
| #include <zephyr/bluetooth/gatt.h> | ||
| #include <zephyr/bluetooth/conn.h> | ||
| #include <zephyr/bluetooth/services/ias.h> | ||
|
|
||
| #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_IAS_CLIENT) | ||
| #define LOG_MODULE_NAME bt_ias_client | ||
| #include "../../common/log.h" | ||
|
|
||
| enum { | ||
| IAS_DISCOVER_IN_PROGRESS, | ||
|
|
||
| IAS_NUM_FLAGS, /* keep as last */ | ||
| }; | ||
|
|
||
| struct bt_ias_client { | ||
| /* Handle for alert writes */ | ||
| uint16_t alert_level_handle; | ||
|
|
||
| /** Internal flags **/ | ||
| ATOMIC_DEFINE(flags, IAS_NUM_FLAGS); | ||
|
|
||
| /* Gatt discover procedure parameters */ | ||
| struct bt_gatt_discover_params discover; | ||
| }; | ||
|
|
||
| static const struct bt_uuid *alert_lvl_uuid = BT_UUID_ALERT_LEVEL; | ||
| static const struct bt_uuid *ias_uuid = BT_UUID_IAS; | ||
|
|
||
| static const struct bt_ias_client_cb *ias_client_cb; | ||
| static struct bt_ias_client client_list[CONFIG_BT_MAX_CONN]; | ||
|
|
||
| static struct bt_ias_client *client_by_conn(struct bt_conn *conn) | ||
| { | ||
| return &client_list[bt_conn_index(conn)]; | ||
| } | ||
|
|
||
| static void client_cleanup(struct bt_ias_client *ias_client) | ||
| { | ||
| (void)memset(ias_client, 0, sizeof(*ias_client)); | ||
| } | ||
|
|
||
| static void discover_complete(struct bt_conn *conn, int err) | ||
| { | ||
| BT_DBG("conn %p", (void *)conn); | ||
|
|
||
| if (err) { | ||
| client_cleanup(client_by_conn(conn)); | ||
| BT_DBG("Discover failed (err %d\n)", err); | ||
| } | ||
|
|
||
| if (ias_client_cb != NULL && ias_client_cb->discover != NULL) { | ||
| ias_client_cb->discover(conn, err); | ||
| } | ||
| } | ||
|
|
||
| int bt_ias_client_alert_write(struct bt_conn *conn, enum bt_ias_alert_lvl lvl) | ||
| { | ||
| int err; | ||
| uint8_t lvl_u8; | ||
|
|
||
| CHECKIF(conn == NULL) { | ||
| return -ENOTCONN; | ||
| } | ||
|
|
||
| if (client_by_conn(conn)->alert_level_handle == 0) { | ||
| return -EINVAL; | ||
| } | ||
|
|
||
| lvl_u8 = (uint8_t)lvl; | ||
|
|
||
| if (lvl_u8 < BT_IAS_ALERT_LVL_NO_ALERT || lvl_u8 > BT_IAS_ALERT_LVL_HIGH_ALERT) { | ||
| BT_ERR("Invalid alert value: %u", lvl_u8); | ||
| return -EINVAL; | ||
| } | ||
|
|
||
| err = bt_gatt_write_without_response(conn, | ||
| client_by_conn(conn)->alert_level_handle, | ||
| &lvl_u8, sizeof(lvl_u8), false); | ||
| if (err < 0) { | ||
| BT_ERR("IAS client level %d write failed: %d", lvl, err); | ||
| } | ||
|
|
||
| return err; | ||
| } | ||
|
|
||
| static uint8_t bt_ias_alert_lvl_disc_cb(struct bt_conn *conn, | ||
| const struct bt_gatt_attr *attr, | ||
| struct bt_gatt_discover_params *discover) | ||
| { | ||
| const struct bt_gatt_chrc *chrc = (struct bt_gatt_chrc *)attr->user_data; | ||
|
|
||
| atomic_clear_bit(client_by_conn(conn)->flags, IAS_DISCOVER_IN_PROGRESS); | ||
|
|
||
| if (attr == NULL) { | ||
| discover_complete(conn, -ENOENT); | ||
|
|
||
| return BT_GATT_ITER_STOP; | ||
| } | ||
|
|
||
| client_by_conn(conn)->alert_level_handle = chrc->value_handle; | ||
| discover_complete(conn, 0); | ||
|
|
||
| return BT_GATT_ITER_STOP; | ||
| } | ||
|
|
||
| static uint8_t bt_ias_prim_disc_cb(struct bt_conn *conn, | ||
| const struct bt_gatt_attr *attr, | ||
| struct bt_gatt_discover_params *discover) | ||
| { | ||
| int err; | ||
| const struct bt_gatt_service_val *data; | ||
| struct bt_ias_client *client = client_by_conn(conn); | ||
|
|
||
| if (!attr) { | ||
| discover_complete(conn, -ENOENT); | ||
|
|
||
| return BT_GATT_ITER_STOP; | ||
| } | ||
|
|
||
| data = attr->user_data; | ||
|
|
||
| client->discover.uuid = alert_lvl_uuid; | ||
| client->discover.start_handle = attr->handle + 1; | ||
| client->discover.end_handle = data->end_handle; | ||
| client->discover.type = BT_GATT_DISCOVER_CHARACTERISTIC; | ||
| client->discover.func = bt_ias_alert_lvl_disc_cb; | ||
|
|
||
| err = bt_gatt_discover(conn, &client->discover); | ||
| if (err) { | ||
| discover_complete(conn, err); | ||
| } | ||
|
|
||
| return BT_GATT_ITER_STOP; | ||
| } | ||
|
|
||
| int bt_ias_discover(struct bt_conn *conn) | ||
| { | ||
| int err; | ||
| struct bt_ias_client *client = client_by_conn(conn); | ||
|
|
||
MariuszSkamra marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| CHECKIF(!conn || !ias_client_cb || !ias_client_cb->discover) { | ||
| return -EINVAL; | ||
| } | ||
|
|
||
| if (atomic_test_bit(client->flags, IAS_DISCOVER_IN_PROGRESS)) { | ||
| return -EBUSY; | ||
| } | ||
|
|
||
| client_cleanup(client); | ||
| atomic_set_bit(client->flags, IAS_DISCOVER_IN_PROGRESS); | ||
|
|
||
| client->discover.uuid = ias_uuid; | ||
| client->discover.func = bt_ias_prim_disc_cb; | ||
| client->discover.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; | ||
| client->discover.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; | ||
| client->discover.type = BT_GATT_DISCOVER_PRIMARY; | ||
|
|
||
| err = bt_gatt_discover(conn, &client->discover); | ||
| if (err < 0) { | ||
Thalley marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| discover_complete(conn, err); | ||
| } | ||
|
|
||
| return err; | ||
| } | ||
|
|
||
| int bt_ias_client_cb_register(const struct bt_ias_client_cb *cb) | ||
| { | ||
| CHECKIF(!cb) { | ||
| return -EINVAL; | ||
| } | ||
|
|
||
| CHECKIF(cb->discover == NULL) { | ||
| return -EINVAL; | ||
| } | ||
|
|
||
| CHECKIF(ias_client_cb) { | ||
| return -EALREADY; | ||
| } | ||
MariuszSkamra marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ias_client_cb = cb; | ||
|
|
||
| return 0; | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.