ble: add immediate alert service server and client

This commit is contained in:
Matthias Ringwald 2024-09-25 12:58:35 +02:00
parent 12879e7550
commit 1663a09d71
8 changed files with 848 additions and 0 deletions

View File

@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- HID Parser: introduce HID Descriptor and HID Descriptor Usage iterators
- HCI Dump Dispatch: allow to use multiple HCI Dump implementations
- HCI Dump: support ISO packets in PacketLogger format
- Immediate Alert Service Server and Client: added
- btstack_util: safe wrappers for snprintf
### Fixed

View File

@ -0,0 +1,4 @@
// Immediate Alert Service 0x1802
PRIMARY_SERVICE, ORG_BLUETOOTH_SERVICE_IMMEDIATE_ALERT
CHARACTERISTIC, ORG_BLUETOOTH_CHARACTERISTIC_ALERT_LEVEL, DYNAMIC | WRITE_WITHOUT_RESPONSE,

View File

@ -0,0 +1,308 @@
/*
* Copyright (C) 2024 BlueKitchen GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* 4. Any redistribution, use, or modification is done solely for
* personal benefit and not for any commercial purpose or for
* monetary gain.
*
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
* GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Please inquire about commercial licensing options at
* contact@bluekitchen-gmbh.com
*
*/
#define BTSTACK_FILE__ "immediate_alert_service_client.c"
#include "btstack_config.h"
#ifdef ENABLE_TESTING_SUPPORT
#include <stdio.h>
#include <unistd.h>
#endif
#include <stdint.h>
#include <string.h>
#include "ble/gatt_service_client.h"
#include "ble/gatt-service/immediate_alert_service_client.h"
#include "bluetooth_gatt.h"
#include "btstack_debug.h"
#include "btstack_event.h"
// IAS Client
static gatt_service_client_t ias_client;
static btstack_linked_list_t ias_connections;
static btstack_context_callback_registration_t ias_client_handle_can_send_now;
static void ias_client_packet_handler_internal(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
static void ias_client_run_for_connection(void * context);
// list of uuids
static const uint16_t ias_uuid16s[IMMEDIATE_ALERT_SERVICE_CLIENT_NUM_CHARACTERISTICS] = {
ORG_BLUETOOTH_CHARACTERISTIC_ALERT_LEVEL
};
typedef enum {
IAS_CLIENT_CHARACTERISTIC_INDEX_ALERT_LEVEL = 0,
IAS_CLIENT_CHARACTERISTIC_INDEX_RFU
} ias_client_characteristic_index_t;
#ifdef ENABLE_TESTING_SUPPORT
static char * ias_client_characteristic_name[] = {
"ALERT_LEVEL",
"RFU"
};
#endif
static ias_client_connection_t * ias_client_get_connection_for_cid(uint16_t connection_cid){
btstack_linked_list_iterator_t it;
btstack_linked_list_iterator_init(&it, &ias_connections);
while (btstack_linked_list_iterator_has_next(&it)){
ias_client_connection_t * connection = (ias_client_connection_t *)btstack_linked_list_iterator_next(&it);
if (gatt_service_client_get_connection_id(&connection->basic_connection) == connection_cid) {
return connection;
}
}
return NULL;
}
static void ias_client_add_connection(ias_client_connection_t * connection){
btstack_linked_list_add(&ias_connections, (btstack_linked_item_t*) connection);
}
static void ias_client_finalize_connection(ias_client_connection_t * connection){
btstack_linked_list_remove(&ias_connections, (btstack_linked_item_t*) connection);
}
static void ias_client_replace_subevent_id_and_emit(btstack_packet_handler_t callback, uint8_t * packet, uint16_t size, uint8_t subevent_id){
UNUSED(size);
btstack_assert(callback != NULL);
// execute callback
packet[2] = subevent_id;
(*callback)(HCI_EVENT_PACKET, 0, packet, size);
}
static void ias_client_connected(ias_client_connection_t * connection, uint8_t status, uint8_t * packet, uint16_t size) {
if (status == ERROR_CODE_SUCCESS){
connection->state = IMMEDIATE_ALERT_SERVICE_CLIENT_STATE_READY;
} else {
connection->state = IMMEDIATE_ALERT_SERVICE_CLIENT_STATE_IDLE;
}
ias_client_replace_subevent_id_and_emit(connection->packet_handler, packet, size,
GATTSERVICE_SUBEVENT_IAS_CLIENT_CONNECTED);
}
static uint16_t ias_client_value_handle_for_index(ias_client_connection_t * connection){
return connection->basic_connection.characteristics[connection->characteristic_index].value_handle;
}
static uint8_t ias_client_can_query_characteristic(ias_client_connection_t * connection, ias_client_characteristic_index_t characteristic_index){
uint8_t status = gatt_service_client_can_query_characteristic(&connection->basic_connection,
(uint8_t) characteristic_index);
if (status != ERROR_CODE_SUCCESS){
return status;
}
return connection->state == IMMEDIATE_ALERT_SERVICE_CLIENT_STATE_READY ? ERROR_CODE_SUCCESS : ERROR_CODE_CONTROLLER_BUSY;
}
static uint8_t ias_client_request_send_gatt_query(ias_client_connection_t * connection, ias_client_characteristic_index_t characteristic_index){
connection->characteristic_index = characteristic_index;
ias_client_handle_can_send_now.context = (void *)(uintptr_t)connection->basic_connection.cid;
uint8_t status = gatt_client_request_to_send_gatt_query(&ias_client_handle_can_send_now, connection->basic_connection.con_handle);
if (status != ERROR_CODE_SUCCESS){
connection->state = IMMEDIATE_ALERT_SERVICE_CLIENT_STATE_READY;
}
return status;
}
static uint8_t ias_client_request_write_without_response_characteristic(ias_client_connection_t * connection, ias_client_characteristic_index_t characteristic_index){
connection->state = IMMEDIATE_ALERT_SERVICE_CLIENT_STATE_W2_WRITE_WITHOUT_RESPONSE_CHARACTERISTIC_VALUE;
return ias_client_request_send_gatt_query(connection, characteristic_index);
}
static void ias_client_packet_handler_internal(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
UNUSED(channel);
UNUSED(size);
if (packet_type != HCI_EVENT_PACKET) return;
ias_client_connection_t * connection;
uint16_t cid;
uint8_t status;
switch(hci_event_packet_get_type(packet)){
case HCI_EVENT_GATTSERVICE_META:
switch (hci_event_gattservice_meta_get_subevent_code(packet)) {
case GATTSERVICE_SUBEVENT_CLIENT_CONNECTED:
cid = gattservice_subevent_client_connected_get_cid(packet);
connection = ias_client_get_connection_for_cid(cid);
btstack_assert(connection != NULL);
#ifdef ENABLE_TESTING_SUPPORT
{
uint8_t i;
for (i = IAS_CLIENT_CHARACTERISTIC_INDEX_ALERT_LEVEL;
i < IAS_CLIENT_CHARACTERISTIC_INDEX_RFU; i++) {
printf("0x%04X %s\n", connection->basic_connection.characteristics[i].value_handle,
ias_client_characteristic_name[i]);
}
};
#endif
status = gattservice_subevent_client_connected_get_status(packet);
ias_client_connected(connection, status, packet, size);
break;
case GATTSERVICE_SUBEVENT_CLIENT_DISCONNECTED:
cid = gattservice_subevent_client_disconnected_get_cid(packet);
connection = ias_client_get_connection_for_cid(cid);
btstack_assert(connection != NULL);
ias_client_finalize_connection(connection);
ias_client_replace_subevent_id_and_emit(connection->packet_handler,
packet, size,
GATTSERVICE_SUBEVENT_IAS_CLIENT_DISCONNECTED);
break;
default:
break;
}
break;
default:
break;
}
}
static uint16_t ias_client_serialize_characteristic_value_for_write(ias_client_connection_t * connection, uint8_t ** out_value){
uint16_t characteristic_uuid16 = gatt_service_client_characteristic_uuid16_for_index(&ias_client,
connection->characteristic_index);
*out_value = (uint8_t *)connection->write_buffer;
switch (characteristic_uuid16){
case ORG_BLUETOOTH_CHARACTERISTIC_ALERT_LEVEL:
return 1;
default:
btstack_assert(false);
break;
}
return 0;
}
static void ias_client_run_for_connection(void * context){
uint16_t connection_id = (uint16_t)(uintptr_t)context;
ias_client_connection_t * connection = ias_client_get_connection_for_cid(connection_id);
btstack_assert(connection != NULL);
uint16_t value_length;
uint8_t * value;
switch (connection->state){
case IMMEDIATE_ALERT_SERVICE_CLIENT_STATE_W2_WRITE_WITHOUT_RESPONSE_CHARACTERISTIC_VALUE:
connection->state = IMMEDIATE_ALERT_SERVICE_CLIENT_STATE_READY;
value_length = ias_client_serialize_characteristic_value_for_write(connection, &value);
gatt_client_write_value_of_characteristic_without_response(
gatt_service_client_get_con_handle(&connection->basic_connection),
ias_client_value_handle_for_index(connection),
value_length, value);
break;
default:
break;
}
}
void immediate_alert_service_client_init(void){
gatt_service_client_register_client(&ias_client, &ias_client_packet_handler_internal, ias_uuid16s, sizeof(ias_uuid16s)/sizeof(uint16_t));
ias_client_handle_can_send_now.callback = &ias_client_run_for_connection;
}
uint8_t immediate_alert_service_client_connect(hci_con_handle_t con_handle,
btstack_packet_handler_t packet_handler,
ias_client_connection_t * ias_connection,
uint16_t * ias_cid
){
btstack_assert(packet_handler != NULL);
btstack_assert(ias_connection != NULL);
*ias_cid = 0;
ias_connection->state = IMMEDIATE_ALERT_SERVICE_CLIENT_STATE_W4_CONNECTION;
ias_connection->packet_handler = packet_handler;
uint8_t status = gatt_service_client_connect_primary_service_with_uuid16(con_handle,
&ias_client,
&ias_connection->basic_connection,
ORG_BLUETOOTH_SERVICE_IMMEDIATE_ALERT, 0,
ias_connection->characteristics_storage,
IMMEDIATE_ALERT_SERVICE_CLIENT_NUM_CHARACTERISTICS);
if (status == ERROR_CODE_SUCCESS){
ias_client_add_connection(ias_connection);
*ias_cid = ias_connection->basic_connection.cid;
}
return status;
}
uint8_t immediate_alert_service_client_write_alert_level(uint16_t ias_cid, ias_alert_level_t alert_level){
ias_client_connection_t * connection = ias_client_get_connection_for_cid(ias_cid);
if (connection == NULL){
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
}
if (alert_level >= IAS_ALERT_LEVEL_RFU){
return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
}
ias_client_characteristic_index_t index = IAS_CLIENT_CHARACTERISTIC_INDEX_ALERT_LEVEL;
uint8_t status = ias_client_can_query_characteristic(connection, index);
if (status != ERROR_CODE_SUCCESS){
return status;
}
connection->write_buffer[0] = (uint8_t)alert_level;
return ias_client_request_write_without_response_characteristic(connection, index);
}
uint8_t immediate_alert_service_client_disconnect(uint16_t ias_cid){
ias_client_connection_t * connection = ias_client_get_connection_for_cid(ias_cid);
if (connection == NULL){
return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
}
return gatt_service_client_disconnect(&connection->basic_connection);
}
void immediate_alert_service_client_deinit(void){
gatt_service_client_unregister_client(&ias_client);
}

View File

@ -0,0 +1,137 @@
/*
* Copyright (C) 2024 BlueKitchen GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* 4. Any redistribution, use, or modification is done solely for
* personal benefit and not for any commercial purpose or for
* monetary gain.
*
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
* GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Please inquire about commercial licensing options at
* contact@bluekitchen-gmbh.com
*
*/
/**
* @title Immediate Alert Service Client
*
*/
#ifndef IMMEDIATE_ALERT_SERVICE_CLIENT_H
#define IMMEDIATE_ALERT_SERVICE_CLIENT_H
#include <stdint.h>
#include "btstack_defines.h"
#include "bluetooth.h"
#include "btstack_linked_list.h"
#include "ble/gatt_client.h"
#include "ble/gatt_service_client.h"
#include "ble/gatt-service/immediate_alert_service_util.h"
#if defined __cplusplus
extern "C" {
#endif
/**
* @text The Immediate Alert Service Client
*/
typedef enum {
IMMEDIATE_ALERT_SERVICE_CLIENT_STATE_IDLE = 0,
IMMEDIATE_ALERT_SERVICE_CLIENT_STATE_W4_CONNECTION,
IMMEDIATE_ALERT_SERVICE_CLIENT_STATE_READY,
IMMEDIATE_ALERT_SERVICE_CLIENT_STATE_W2_WRITE_WITHOUT_RESPONSE_CHARACTERISTIC_VALUE
} immediate_alert_service_client_state_t;
typedef struct {
btstack_linked_item_t item;
gatt_service_client_connection_t basic_connection;
btstack_packet_handler_t packet_handler;
gatt_service_client_characteristic_t characteristics_storage[IMMEDIATE_ALERT_SERVICE_CLIENT_NUM_CHARACTERISTICS];
immediate_alert_service_client_state_t state;
// Used for read characteristic queries
uint8_t characteristic_index;
// Used to store parameters for write characteristic
uint8_t write_buffer[1];
} ias_client_connection_t;
/* API_START */
/**
* @brief Initialize Immediate Alert Service.
*/
void immediate_alert_service_client_init(void);
/**
* @brief Connect to a Immediate Alert Service instance of remote device. The client will automatically register for notifications.
* The mute state is received via GATTSERVICE_SUBEVENT_LLS_CLIENT_MUTE event.
* The mute state can be 0 - off, 1 - on, 2 - disabled and it is valid if the ATT status is equal to ATT_ERROR_SUCCESS,
* see ATT errors (see bluetooth.h) for other values.
*
* Event GATTSERVICE_SUBEVENT_LLS_CLIENT_CONNECTED is emitted with status ERROR_CODE_SUCCESS on success, otherwise
* GATT_CLIENT_IN_WRONG_STATE, ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE if no audio input control service is found, or ATT errors (see bluetooth.h).
*
* @param con_handle
* @param packet_handler
* @param iac_connection
* @param iac_characteristics_storage storage for characteristics
* @param iac_characteristics_num == IMMEDIATE_ALERT_SERVICE_CLIENT_NUM_CHARACTERISTICS
* @return status ERROR_CODE_SUCCESS on success, otherwise ERROR_CODE_COMMAND_DISALLOWED if there is already a client associated with con_handle, or BTSTACK_MEMORY_ALLOC_FAILED
*/
uint8_t immediate_alert_service_client_connect(
hci_con_handle_t con_handle,
btstack_packet_handler_t packet_handler,
ias_client_connection_t * iac_connection,
uint16_t * ias_cid
);
uint8_t immediate_alert_service_client_write_alert_level(uint16_t ias_cid, ias_alert_level_t alert_level);
/**
* @brief Disconnect.
* @param ias_cid
* @return status
*/
uint8_t immediate_alert_service_client_disconnect(uint16_t ias_cid);
/**
* @brief De-initialize Immediate Alert Service.
*/
void immediate_alert_service_client_deinit(void);
/* API_END */
#if defined __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,234 @@
/*
* Copyright (C) 2023 BlueKitchen GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* 4. Any redistribution, use, or modification is done solely for
* personal benefit and not for any commercial purpose or for
* monetary gain.
*
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
* GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Please inquire about commercial licensing options at
* contact@bluekitchen-gmbh.com
*
*/
#define BTSTACK_FILE__ "immediate_alert_service_server.c"
#ifdef ENABLE_TESTING_SUPPORT
#include <stdio.h>
#endif
#include "btstack_defines.h"
#include "btstack_event.h"
#include "ble/att_db.h"
#include "ble/att_server.h"
#include "bluetooth_gatt.h"
#include "btstack_debug.h"
#include "ble/gatt-service/immediate_alert_service_server.h"
#include "btstack_run_loop.h"
#ifdef ENABLE_TESTING_SUPPORT
#include <stdio.h>
#endif
static att_service_handler_t immediate_alert_service;
static btstack_packet_handler_t ias_server_callback;
typedef enum {
IAS_SERVER_ALERT_STATE_IDLE = 0,
IAS_SERVER_ALERT_STATE_ALERTING
} ias_server_alert_state_t;
static uint16_t ias_server_alert_level_handle;
static ias_alert_level_t ias_server_alert_level;
static ias_server_alert_state_t ias_server_alert_state;
static uint32_t ias_server_alert_timeout_ms;
static btstack_timer_source_t ias_server_alert_timer;
static void ias_server_emit_alarm_started(void){
btstack_assert(ias_server_callback != NULL);
uint8_t event[4];
uint8_t pos = 0;
event[pos++] = HCI_EVENT_GATTSERVICE_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = GATTSERVICE_SUBEVENT_IAS_SERVER_START_ALERTING;
event[pos++] = (uint8_t)ias_server_alert_level;
(*ias_server_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
static void ias_server_emit_alarm_stopped(bool stopped_due_timeout){
btstack_assert(ias_server_callback != NULL);
uint8_t event[5];
uint8_t pos = 0;
event[pos++] = HCI_EVENT_GATTSERVICE_META;
event[pos++] = sizeof(event) - 2;
event[pos++] = GATTSERVICE_SUBEVENT_IAS_SERVER_STOP_ALERTING;
event[pos++] = (uint8_t)ias_server_alert_level;
event[pos++] = stopped_due_timeout ? 1u : 0u;
(*ias_server_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
}
static void ias_server_stop_alerting(void){
btstack_run_loop_remove_timer(&ias_server_alert_timer);
if (ias_server_alert_state == IAS_SERVER_ALERT_STATE_ALERTING){
ias_server_emit_alarm_stopped(false);
ias_server_alert_state = IAS_SERVER_ALERT_STATE_IDLE;
}
}
static void ias_server_timer_timeout_handler(btstack_timer_source_t * timer){
UNUSED(timer);
ias_server_emit_alarm_stopped(true);
ias_server_alert_state = IAS_SERVER_ALERT_STATE_IDLE;
}
static void ias_server_start_alerting(void){
if (ias_server_alert_state == IAS_SERVER_ALERT_STATE_ALERTING){
return;
}
ias_server_alert_state = IAS_SERVER_ALERT_STATE_ALERTING;
ias_server_emit_alarm_started();
if (ias_server_alert_timeout_ms == 0){
return;
}
btstack_run_loop_set_timer_handler(&ias_server_alert_timer, ias_server_timer_timeout_handler);
btstack_run_loop_set_timer(&ias_server_alert_timer, ias_server_alert_timeout_ms);
btstack_run_loop_add_timer(&ias_server_alert_timer);
}
static uint16_t ias_server_read_callback(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
UNUSED(con_handle);
if (attribute_handle == ias_server_alert_level_handle){
return att_read_callback_handle_byte((uint8_t)ias_server_alert_level, offset, buffer, buffer_size);
}
return 0;
}
static int ias_server_write_callback(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size){
UNUSED(transaction_mode);
UNUSED(offset);
UNUSED(con_handle);
if (attribute_handle == ias_server_alert_level_handle){
if (buffer_size != 1){
return 0;
}
ias_alert_level_t alert_level = (ias_alert_level_t)buffer[0];
if (alert_level >= IAS_ALERT_LEVEL_RFU){
return 0;
}
ias_server_stop_alerting();
ias_server_alert_level = alert_level;
switch (ias_server_alert_level){
case IAS_ALERT_LEVEL_NO_ALERT:
break;
default:
ias_server_start_alerting();
break;
}
}
return 0;
}
static void ias_server_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
UNUSED(channel);
UNUSED(size);
if (packet_type != HCI_EVENT_PACKET){
return;
}
switch (hci_event_packet_get_type(packet)) {
case HCI_EVENT_DISCONNECTION_COMPLETE:
ias_server_stop_alerting();
break;
default:
break;
}
}
void immediate_alert_service_server_init(void){
uint16_t start_handle = 0;
uint16_t end_handle = 0xffff;
int service_found = gatt_server_get_handle_range_for_service_with_uuid16(ORG_BLUETOOTH_SERVICE_IMMEDIATE_ALERT, &start_handle, &end_handle);
btstack_assert(service_found != 0);
UNUSED(service_found);
ias_server_alert_level = IAS_ALERT_LEVEL_NO_ALERT;
ias_server_alert_timeout_ms = 0;
ias_server_alert_state = IAS_SERVER_ALERT_STATE_IDLE;
// get characteristic value handle and client configuration handle
ias_server_alert_level_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_ALERT_LEVEL);
#ifdef ENABLE_TESTING_SUPPORT
printf("IAS 0x%02x - 0x%02x \n", start_handle, end_handle);
printf(" alert_level 0x%02x \n", ias_server_alert_level_handle);
#endif
log_info("Immediate Alert Service Server 0x%02x-0x%02x", start_handle, end_handle);
// register service with ATT Server
immediate_alert_service.start_handle = start_handle;
immediate_alert_service.end_handle = end_handle;
immediate_alert_service.read_callback = &ias_server_read_callback;
immediate_alert_service.write_callback = &ias_server_write_callback;
immediate_alert_service.packet_handler = ias_server_packet_handler;
att_server_register_service_handler(&immediate_alert_service);
}
void immediate_alert_service_server_register_packet_handler(btstack_packet_handler_t packet_handler){
btstack_assert(packet_handler != NULL);
ias_server_callback = packet_handler;
}
uint8_t immediate_alert_service_server_set_alert_level(const ias_alert_level_t alert_level){
if (alert_level >= IAS_ALERT_LEVEL_RFU){
return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
}
ias_server_alert_level = alert_level;
return ERROR_CODE_SUCCESS;
}
void immediate_alert_service_server_stop_alerting(void){
ias_server_stop_alerting();
}

View File

@ -0,0 +1,95 @@
/*
* Copyright (C) 2023 BlueKitchen GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* 4. Any redistribution, use, or modification is done solely for
* personal benefit and not for any commercial purpose or for
* monetary gain.
*
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
* GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Please inquire about commercial licensing options at
* contact@bluekitchen-gmbh.com
*
*/
/**
* @title Immediate Alert Service Server
*
*/
#ifndef IMMEDIATE_ALERT_SERVICE_SERVER_H
#define IMMEDIATE_ALERT_SERVICE_SERVER_H
#include <stdint.h>
#include "ble/att_db.h"
#include "ble/gatt-service/immediate_alert_service_util.h"
#if defined __cplusplus
extern "C" {
#endif
/**
* @text To use with your application, add `#import <immediate_alert_service.gatt>` to your .gatt file.
*
*/
/* API_START */
/**
* @brief Init Immediate Alert Service Server with ATT DB
* @param mute_state
*/
void immediate_alert_service_server_init(void);
/**
* @brief Register packet handler
*/
void immediate_alert_service_server_register_packet_handler(btstack_packet_handler_t packet_handler);
/**
* @brief Set alert level.
* @param alert_level
*/
uint8_t immediate_alert_service_server_set_alert_level(const ias_alert_level_t alert_level);
/**
* @brief Set alert timeout. Default is 0 that equals to no timeout.
* @param alert_timeout_ms
*/
uint8_t immediate_alert_service_server_set_alert_timeout(uint32_t alert_timeout_ms);
void immediate_alert_service_server_stop_alerting(void);
/* API_END */
#if defined __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,66 @@
/*
* Copyright (C) 2024 BlueKitchen GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* 4. Any redistribution, use, or modification is done solely for
* personal benefit and not for any commercial purpose or for
* monetary gain.
*
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
* GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Please inquire about commercial licensing options at
* contact@bluekitchen-gmbh.com
*
*/
/**
* @title Immediate Alert Service Util
*
*/
#ifndef IMMEDIATE_ALERT_SERVICE_UTIL_H
#define IMMEDIATE_ALERT_SERVICE_UTIL_H
#include <stdint.h>
#if defined __cplusplus
extern "C" {
#endif
// number of characteristics in Immediate Alert Service
#define IMMEDIATE_ALERT_SERVICE_CLIENT_NUM_CHARACTERISTICS 1
typedef enum {
IAS_ALERT_LEVEL_NO_ALERT = 0,
IAS_ALERT_LEVEL_MILD_ALERT,
IAS_ALERT_LEVEL_HIGH_ALERT,
IAS_ALERT_LEVEL_RFU,
} ias_alert_level_t;
#if defined __cplusplus
}
#endif
#endif

View File

@ -94,6 +94,9 @@
#include "ble/gatt-service/heart_rate_service_server.h"
#include "ble/gatt-service/hids_client.h"
#include "ble/gatt-service/hids_device.h"
#include "ble/gatt-service/immediate_alert_service_client.h"
#include "ble/gatt-service/immediate_alert_service_server.h"
#include "ble/gatt-service/immediate_alert_service_util.h"
#include "ble/gatt-service/scan_parameters_service_client.h"
#include "ble/gatt-service/scan_parameters_service_server.h"
#include "ble/gatt-service/tx_power_service_server.h"