1*1663a09dSMatthias Ringwald /*
2*1663a09dSMatthias Ringwald * Copyright (C) 2023 BlueKitchen GmbH
3*1663a09dSMatthias Ringwald *
4*1663a09dSMatthias Ringwald * Redistribution and use in source and binary forms, with or without
5*1663a09dSMatthias Ringwald * modification, are permitted provided that the following conditions
6*1663a09dSMatthias Ringwald * are met:
7*1663a09dSMatthias Ringwald *
8*1663a09dSMatthias Ringwald * 1. Redistributions of source code must retain the above copyright
9*1663a09dSMatthias Ringwald * notice, this list of conditions and the following disclaimer.
10*1663a09dSMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright
11*1663a09dSMatthias Ringwald * notice, this list of conditions and the following disclaimer in the
12*1663a09dSMatthias Ringwald * documentation and/or other materials provided with the distribution.
13*1663a09dSMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of
14*1663a09dSMatthias Ringwald * contributors may be used to endorse or promote products derived
15*1663a09dSMatthias Ringwald * from this software without specific prior written permission.
16*1663a09dSMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for
17*1663a09dSMatthias Ringwald * personal benefit and not for any commercial purpose or for
18*1663a09dSMatthias Ringwald * monetary gain.
19*1663a09dSMatthias Ringwald *
20*1663a09dSMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*1663a09dSMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*1663a09dSMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*1663a09dSMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24*1663a09dSMatthias Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*1663a09dSMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*1663a09dSMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*1663a09dSMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*1663a09dSMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*1663a09dSMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*1663a09dSMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*1663a09dSMatthias Ringwald * SUCH DAMAGE.
32*1663a09dSMatthias Ringwald *
33*1663a09dSMatthias Ringwald * Please inquire about commercial licensing options at
34*1663a09dSMatthias Ringwald * [email protected]
35*1663a09dSMatthias Ringwald *
36*1663a09dSMatthias Ringwald */
37*1663a09dSMatthias Ringwald
38*1663a09dSMatthias Ringwald #define BTSTACK_FILE__ "immediate_alert_service_server.c"
39*1663a09dSMatthias Ringwald
40*1663a09dSMatthias Ringwald #ifdef ENABLE_TESTING_SUPPORT
41*1663a09dSMatthias Ringwald #include <stdio.h>
42*1663a09dSMatthias Ringwald #endif
43*1663a09dSMatthias Ringwald
44*1663a09dSMatthias Ringwald #include "btstack_defines.h"
45*1663a09dSMatthias Ringwald #include "btstack_event.h"
46*1663a09dSMatthias Ringwald #include "ble/att_db.h"
47*1663a09dSMatthias Ringwald #include "ble/att_server.h"
48*1663a09dSMatthias Ringwald #include "bluetooth_gatt.h"
49*1663a09dSMatthias Ringwald #include "btstack_debug.h"
50*1663a09dSMatthias Ringwald
51*1663a09dSMatthias Ringwald #include "ble/gatt-service/immediate_alert_service_server.h"
52*1663a09dSMatthias Ringwald #include "btstack_run_loop.h"
53*1663a09dSMatthias Ringwald
54*1663a09dSMatthias Ringwald #ifdef ENABLE_TESTING_SUPPORT
55*1663a09dSMatthias Ringwald #include <stdio.h>
56*1663a09dSMatthias Ringwald #endif
57*1663a09dSMatthias Ringwald
58*1663a09dSMatthias Ringwald static att_service_handler_t immediate_alert_service;
59*1663a09dSMatthias Ringwald static btstack_packet_handler_t ias_server_callback;
60*1663a09dSMatthias Ringwald
61*1663a09dSMatthias Ringwald typedef enum {
62*1663a09dSMatthias Ringwald IAS_SERVER_ALERT_STATE_IDLE = 0,
63*1663a09dSMatthias Ringwald IAS_SERVER_ALERT_STATE_ALERTING
64*1663a09dSMatthias Ringwald } ias_server_alert_state_t;
65*1663a09dSMatthias Ringwald
66*1663a09dSMatthias Ringwald static uint16_t ias_server_alert_level_handle;
67*1663a09dSMatthias Ringwald static ias_alert_level_t ias_server_alert_level;
68*1663a09dSMatthias Ringwald
69*1663a09dSMatthias Ringwald static ias_server_alert_state_t ias_server_alert_state;
70*1663a09dSMatthias Ringwald static uint32_t ias_server_alert_timeout_ms;
71*1663a09dSMatthias Ringwald static btstack_timer_source_t ias_server_alert_timer;
72*1663a09dSMatthias Ringwald
73*1663a09dSMatthias Ringwald
ias_server_emit_alarm_started(void)74*1663a09dSMatthias Ringwald static void ias_server_emit_alarm_started(void){
75*1663a09dSMatthias Ringwald btstack_assert(ias_server_callback != NULL);
76*1663a09dSMatthias Ringwald
77*1663a09dSMatthias Ringwald uint8_t event[4];
78*1663a09dSMatthias Ringwald uint8_t pos = 0;
79*1663a09dSMatthias Ringwald event[pos++] = HCI_EVENT_GATTSERVICE_META;
80*1663a09dSMatthias Ringwald event[pos++] = sizeof(event) - 2;
81*1663a09dSMatthias Ringwald event[pos++] = GATTSERVICE_SUBEVENT_IAS_SERVER_START_ALERTING;
82*1663a09dSMatthias Ringwald event[pos++] = (uint8_t)ias_server_alert_level;
83*1663a09dSMatthias Ringwald (*ias_server_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
84*1663a09dSMatthias Ringwald }
85*1663a09dSMatthias Ringwald
ias_server_emit_alarm_stopped(bool stopped_due_timeout)86*1663a09dSMatthias Ringwald static void ias_server_emit_alarm_stopped(bool stopped_due_timeout){
87*1663a09dSMatthias Ringwald btstack_assert(ias_server_callback != NULL);
88*1663a09dSMatthias Ringwald
89*1663a09dSMatthias Ringwald uint8_t event[5];
90*1663a09dSMatthias Ringwald uint8_t pos = 0;
91*1663a09dSMatthias Ringwald event[pos++] = HCI_EVENT_GATTSERVICE_META;
92*1663a09dSMatthias Ringwald event[pos++] = sizeof(event) - 2;
93*1663a09dSMatthias Ringwald event[pos++] = GATTSERVICE_SUBEVENT_IAS_SERVER_STOP_ALERTING;
94*1663a09dSMatthias Ringwald event[pos++] = (uint8_t)ias_server_alert_level;
95*1663a09dSMatthias Ringwald event[pos++] = stopped_due_timeout ? 1u : 0u;
96*1663a09dSMatthias Ringwald
97*1663a09dSMatthias Ringwald (*ias_server_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
98*1663a09dSMatthias Ringwald }
99*1663a09dSMatthias Ringwald
ias_server_stop_alerting(void)100*1663a09dSMatthias Ringwald static void ias_server_stop_alerting(void){
101*1663a09dSMatthias Ringwald btstack_run_loop_remove_timer(&ias_server_alert_timer);
102*1663a09dSMatthias Ringwald
103*1663a09dSMatthias Ringwald if (ias_server_alert_state == IAS_SERVER_ALERT_STATE_ALERTING){
104*1663a09dSMatthias Ringwald ias_server_emit_alarm_stopped(false);
105*1663a09dSMatthias Ringwald ias_server_alert_state = IAS_SERVER_ALERT_STATE_IDLE;
106*1663a09dSMatthias Ringwald }
107*1663a09dSMatthias Ringwald }
108*1663a09dSMatthias Ringwald
ias_server_timer_timeout_handler(btstack_timer_source_t * timer)109*1663a09dSMatthias Ringwald static void ias_server_timer_timeout_handler(btstack_timer_source_t * timer){
110*1663a09dSMatthias Ringwald UNUSED(timer);
111*1663a09dSMatthias Ringwald ias_server_emit_alarm_stopped(true);
112*1663a09dSMatthias Ringwald ias_server_alert_state = IAS_SERVER_ALERT_STATE_IDLE;
113*1663a09dSMatthias Ringwald }
114*1663a09dSMatthias Ringwald
ias_server_start_alerting(void)115*1663a09dSMatthias Ringwald static void ias_server_start_alerting(void){
116*1663a09dSMatthias Ringwald if (ias_server_alert_state == IAS_SERVER_ALERT_STATE_ALERTING){
117*1663a09dSMatthias Ringwald return;
118*1663a09dSMatthias Ringwald }
119*1663a09dSMatthias Ringwald
120*1663a09dSMatthias Ringwald ias_server_alert_state = IAS_SERVER_ALERT_STATE_ALERTING;
121*1663a09dSMatthias Ringwald ias_server_emit_alarm_started();
122*1663a09dSMatthias Ringwald
123*1663a09dSMatthias Ringwald if (ias_server_alert_timeout_ms == 0){
124*1663a09dSMatthias Ringwald return;
125*1663a09dSMatthias Ringwald }
126*1663a09dSMatthias Ringwald
127*1663a09dSMatthias Ringwald btstack_run_loop_set_timer_handler(&ias_server_alert_timer, ias_server_timer_timeout_handler);
128*1663a09dSMatthias Ringwald btstack_run_loop_set_timer(&ias_server_alert_timer, ias_server_alert_timeout_ms);
129*1663a09dSMatthias Ringwald btstack_run_loop_add_timer(&ias_server_alert_timer);
130*1663a09dSMatthias Ringwald }
131*1663a09dSMatthias Ringwald
132*1663a09dSMatthias Ringwald
ias_server_read_callback(hci_con_handle_t con_handle,uint16_t attribute_handle,uint16_t offset,uint8_t * buffer,uint16_t buffer_size)133*1663a09dSMatthias Ringwald 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){
134*1663a09dSMatthias Ringwald UNUSED(con_handle);
135*1663a09dSMatthias Ringwald
136*1663a09dSMatthias Ringwald if (attribute_handle == ias_server_alert_level_handle){
137*1663a09dSMatthias Ringwald return att_read_callback_handle_byte((uint8_t)ias_server_alert_level, offset, buffer, buffer_size);
138*1663a09dSMatthias Ringwald }
139*1663a09dSMatthias Ringwald return 0;
140*1663a09dSMatthias Ringwald }
141*1663a09dSMatthias Ringwald
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)142*1663a09dSMatthias Ringwald 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){
143*1663a09dSMatthias Ringwald UNUSED(transaction_mode);
144*1663a09dSMatthias Ringwald UNUSED(offset);
145*1663a09dSMatthias Ringwald UNUSED(con_handle);
146*1663a09dSMatthias Ringwald
147*1663a09dSMatthias Ringwald
148*1663a09dSMatthias Ringwald if (attribute_handle == ias_server_alert_level_handle){
149*1663a09dSMatthias Ringwald if (buffer_size != 1){
150*1663a09dSMatthias Ringwald return 0;
151*1663a09dSMatthias Ringwald }
152*1663a09dSMatthias Ringwald
153*1663a09dSMatthias Ringwald ias_alert_level_t alert_level = (ias_alert_level_t)buffer[0];
154*1663a09dSMatthias Ringwald if (alert_level >= IAS_ALERT_LEVEL_RFU){
155*1663a09dSMatthias Ringwald return 0;
156*1663a09dSMatthias Ringwald }
157*1663a09dSMatthias Ringwald
158*1663a09dSMatthias Ringwald ias_server_stop_alerting();
159*1663a09dSMatthias Ringwald ias_server_alert_level = alert_level;
160*1663a09dSMatthias Ringwald
161*1663a09dSMatthias Ringwald switch (ias_server_alert_level){
162*1663a09dSMatthias Ringwald case IAS_ALERT_LEVEL_NO_ALERT:
163*1663a09dSMatthias Ringwald break;
164*1663a09dSMatthias Ringwald default:
165*1663a09dSMatthias Ringwald ias_server_start_alerting();
166*1663a09dSMatthias Ringwald break;
167*1663a09dSMatthias Ringwald }
168*1663a09dSMatthias Ringwald }
169*1663a09dSMatthias Ringwald return 0;
170*1663a09dSMatthias Ringwald }
171*1663a09dSMatthias Ringwald
ias_server_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)172*1663a09dSMatthias Ringwald static void ias_server_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
173*1663a09dSMatthias Ringwald UNUSED(channel);
174*1663a09dSMatthias Ringwald UNUSED(size);
175*1663a09dSMatthias Ringwald
176*1663a09dSMatthias Ringwald if (packet_type != HCI_EVENT_PACKET){
177*1663a09dSMatthias Ringwald return;
178*1663a09dSMatthias Ringwald }
179*1663a09dSMatthias Ringwald
180*1663a09dSMatthias Ringwald switch (hci_event_packet_get_type(packet)) {
181*1663a09dSMatthias Ringwald case HCI_EVENT_DISCONNECTION_COMPLETE:
182*1663a09dSMatthias Ringwald ias_server_stop_alerting();
183*1663a09dSMatthias Ringwald break;
184*1663a09dSMatthias Ringwald default:
185*1663a09dSMatthias Ringwald break;
186*1663a09dSMatthias Ringwald }
187*1663a09dSMatthias Ringwald }
188*1663a09dSMatthias Ringwald
immediate_alert_service_server_init(void)189*1663a09dSMatthias Ringwald void immediate_alert_service_server_init(void){
190*1663a09dSMatthias Ringwald uint16_t start_handle = 0;
191*1663a09dSMatthias Ringwald uint16_t end_handle = 0xffff;
192*1663a09dSMatthias Ringwald int service_found = gatt_server_get_handle_range_for_service_with_uuid16(ORG_BLUETOOTH_SERVICE_IMMEDIATE_ALERT, &start_handle, &end_handle);
193*1663a09dSMatthias Ringwald btstack_assert(service_found != 0);
194*1663a09dSMatthias Ringwald UNUSED(service_found);
195*1663a09dSMatthias Ringwald
196*1663a09dSMatthias Ringwald ias_server_alert_level = IAS_ALERT_LEVEL_NO_ALERT;
197*1663a09dSMatthias Ringwald ias_server_alert_timeout_ms = 0;
198*1663a09dSMatthias Ringwald ias_server_alert_state = IAS_SERVER_ALERT_STATE_IDLE;
199*1663a09dSMatthias Ringwald
200*1663a09dSMatthias Ringwald // get characteristic value handle and client configuration handle
201*1663a09dSMatthias Ringwald ias_server_alert_level_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_ALERT_LEVEL);
202*1663a09dSMatthias Ringwald
203*1663a09dSMatthias Ringwald #ifdef ENABLE_TESTING_SUPPORT
204*1663a09dSMatthias Ringwald printf("IAS 0x%02x - 0x%02x \n", start_handle, end_handle);
205*1663a09dSMatthias Ringwald printf(" alert_level 0x%02x \n", ias_server_alert_level_handle);
206*1663a09dSMatthias Ringwald #endif
207*1663a09dSMatthias Ringwald log_info("Immediate Alert Service Server 0x%02x-0x%02x", start_handle, end_handle);
208*1663a09dSMatthias Ringwald
209*1663a09dSMatthias Ringwald // register service with ATT Server
210*1663a09dSMatthias Ringwald immediate_alert_service.start_handle = start_handle;
211*1663a09dSMatthias Ringwald immediate_alert_service.end_handle = end_handle;
212*1663a09dSMatthias Ringwald immediate_alert_service.read_callback = &ias_server_read_callback;
213*1663a09dSMatthias Ringwald immediate_alert_service.write_callback = &ias_server_write_callback;
214*1663a09dSMatthias Ringwald immediate_alert_service.packet_handler = ias_server_packet_handler;
215*1663a09dSMatthias Ringwald att_server_register_service_handler(&immediate_alert_service);
216*1663a09dSMatthias Ringwald }
217*1663a09dSMatthias Ringwald
immediate_alert_service_server_register_packet_handler(btstack_packet_handler_t packet_handler)218*1663a09dSMatthias Ringwald void immediate_alert_service_server_register_packet_handler(btstack_packet_handler_t packet_handler){
219*1663a09dSMatthias Ringwald btstack_assert(packet_handler != NULL);
220*1663a09dSMatthias Ringwald ias_server_callback = packet_handler;
221*1663a09dSMatthias Ringwald }
222*1663a09dSMatthias Ringwald
immediate_alert_service_server_set_alert_level(const ias_alert_level_t alert_level)223*1663a09dSMatthias Ringwald uint8_t immediate_alert_service_server_set_alert_level(const ias_alert_level_t alert_level){
224*1663a09dSMatthias Ringwald if (alert_level >= IAS_ALERT_LEVEL_RFU){
225*1663a09dSMatthias Ringwald return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
226*1663a09dSMatthias Ringwald }
227*1663a09dSMatthias Ringwald
228*1663a09dSMatthias Ringwald ias_server_alert_level = alert_level;
229*1663a09dSMatthias Ringwald return ERROR_CODE_SUCCESS;
230*1663a09dSMatthias Ringwald }
231*1663a09dSMatthias Ringwald
immediate_alert_service_server_stop_alerting(void)232*1663a09dSMatthias Ringwald void immediate_alert_service_server_stop_alerting(void){
233*1663a09dSMatthias Ringwald ias_server_stop_alerting();
234*1663a09dSMatthias Ringwald }