xref: /btstack/src/ble/gatt-service/link_loss_service_server.c (revision daa5f023ef40927147f1a414e0ebef2ed425824c)
1*daa5f023SMatthias Ringwald /*
2*daa5f023SMatthias Ringwald  * Copyright (C) 2021 BlueKitchen GmbH
3*daa5f023SMatthias Ringwald  *
4*daa5f023SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5*daa5f023SMatthias Ringwald  * modification, are permitted provided that the following conditions
6*daa5f023SMatthias Ringwald  * are met:
7*daa5f023SMatthias Ringwald  *
8*daa5f023SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9*daa5f023SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10*daa5f023SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*daa5f023SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*daa5f023SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13*daa5f023SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*daa5f023SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15*daa5f023SMatthias Ringwald  *    from this software without specific prior written permission.
16*daa5f023SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*daa5f023SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18*daa5f023SMatthias Ringwald  *    monetary gain.
19*daa5f023SMatthias Ringwald  *
20*daa5f023SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*daa5f023SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*daa5f023SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*daa5f023SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24*daa5f023SMatthias Ringwald  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*daa5f023SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*daa5f023SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*daa5f023SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*daa5f023SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*daa5f023SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*daa5f023SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*daa5f023SMatthias Ringwald  * SUCH DAMAGE.
32*daa5f023SMatthias Ringwald  *
33*daa5f023SMatthias Ringwald  * Please inquire about commercial licensing options at
34*daa5f023SMatthias Ringwald  * [email protected]
35*daa5f023SMatthias Ringwald  *
36*daa5f023SMatthias Ringwald  */
37*daa5f023SMatthias Ringwald 
38*daa5f023SMatthias Ringwald #define BTSTACK_FILE__ "link_loss_service_server.c"
39*daa5f023SMatthias Ringwald 
40*daa5f023SMatthias Ringwald /**
41*daa5f023SMatthias Ringwald  * Implementation of the GATT Battery Service Server
42*daa5f023SMatthias Ringwald  * To use with your application, add '#import <link_loss_service.gatt' to your .gatt file
43*daa5f023SMatthias Ringwald  */
44*daa5f023SMatthias Ringwald 
45*daa5f023SMatthias Ringwald #ifdef ENABLE_TESTING_SUPPORT
46*daa5f023SMatthias Ringwald #include <stdio.h>
47*daa5f023SMatthias Ringwald #endif
48*daa5f023SMatthias Ringwald 
49*daa5f023SMatthias Ringwald #include "btstack_defines.h"
50*daa5f023SMatthias Ringwald #include "btstack_event.h"
51*daa5f023SMatthias Ringwald #include "ble/att_db.h"
52*daa5f023SMatthias Ringwald #include "ble/att_server.h"
53*daa5f023SMatthias Ringwald #include "btstack_util.h"
54*daa5f023SMatthias Ringwald #include "bluetooth_gatt.h"
55*daa5f023SMatthias Ringwald #include "btstack_debug.h"
56*daa5f023SMatthias Ringwald 
57*daa5f023SMatthias Ringwald #include "ble/gatt-service/link_loss_service_server.h"
58*daa5f023SMatthias Ringwald #include "btstack_run_loop.h"
59*daa5f023SMatthias Ringwald #include "hci.h"
60*daa5f023SMatthias Ringwald 
61*daa5f023SMatthias Ringwald static att_service_handler_t    link_loss_service;
62*daa5f023SMatthias Ringwald static btstack_packet_handler_t lls_server_callback;
63*daa5f023SMatthias Ringwald static btstack_packet_callback_registration_t lls_server_hci_event_callback_registration;
64*daa5f023SMatthias Ringwald 
65*daa5f023SMatthias Ringwald typedef enum {
66*daa5f023SMatthias Ringwald     LLS_SERVER_ALERT_STATE_IDLE = 0,
67*daa5f023SMatthias Ringwald     LLS_SERVER_ALERT_STATE_ALERTING
68*daa5f023SMatthias Ringwald } lls_server_alert_state_t;
69*daa5f023SMatthias Ringwald 
70*daa5f023SMatthias Ringwald static uint16_t 				lls_server_alert_level_handle;
71*daa5f023SMatthias Ringwald static lls_alert_level_t 		lls_server_alert_level;
72*daa5f023SMatthias Ringwald 
73*daa5f023SMatthias Ringwald static lls_server_alert_state_t lls_server_alert_state;
74*daa5f023SMatthias Ringwald static uint32_t                 lls_server_alert_timeout_ms;
75*daa5f023SMatthias Ringwald static btstack_timer_source_t   lls_server_alert_timer;
76*daa5f023SMatthias Ringwald 
77*daa5f023SMatthias Ringwald 
lls_server_emit_alarm_started(void)78*daa5f023SMatthias Ringwald static void lls_server_emit_alarm_started(void){
79*daa5f023SMatthias Ringwald     btstack_assert(lls_server_callback != NULL);
80*daa5f023SMatthias Ringwald 
81*daa5f023SMatthias Ringwald     uint8_t event[4];
82*daa5f023SMatthias Ringwald     uint8_t pos = 0;
83*daa5f023SMatthias Ringwald     event[pos++] = HCI_EVENT_GATTSERVICE_META;
84*daa5f023SMatthias Ringwald     event[pos++] = sizeof(event) - 2;
85*daa5f023SMatthias Ringwald     event[pos++] = GATTSERVICE_SUBEVENT_LLS_SERVER_START_ALERTING;
86*daa5f023SMatthias Ringwald     event[pos++] = (uint8_t)lls_server_alert_level;
87*daa5f023SMatthias Ringwald     (*lls_server_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
88*daa5f023SMatthias Ringwald }
89*daa5f023SMatthias Ringwald 
lls_server_emit_alarm_stopped(bool stopped_due_timeout)90*daa5f023SMatthias Ringwald static void lls_server_emit_alarm_stopped(bool stopped_due_timeout){
91*daa5f023SMatthias Ringwald     btstack_assert(lls_server_callback != NULL);
92*daa5f023SMatthias Ringwald 
93*daa5f023SMatthias Ringwald     uint8_t event[5];
94*daa5f023SMatthias Ringwald     uint8_t pos = 0;
95*daa5f023SMatthias Ringwald     event[pos++] = HCI_EVENT_GATTSERVICE_META;
96*daa5f023SMatthias Ringwald     event[pos++] = sizeof(event) - 2;
97*daa5f023SMatthias Ringwald     event[pos++] = GATTSERVICE_SUBEVENT_LLS_SERVER_STOP_ALERTING;
98*daa5f023SMatthias Ringwald     event[pos++] = (uint8_t)lls_server_alert_level;
99*daa5f023SMatthias Ringwald     event[pos++] = stopped_due_timeout ? 1u : 0u;
100*daa5f023SMatthias Ringwald 
101*daa5f023SMatthias Ringwald     (*lls_server_callback)(HCI_EVENT_PACKET, 0, event, sizeof(event));
102*daa5f023SMatthias Ringwald }
103*daa5f023SMatthias Ringwald 
lls_server_stop_alerting(void)104*daa5f023SMatthias Ringwald static void lls_server_stop_alerting(void){
105*daa5f023SMatthias Ringwald     btstack_run_loop_remove_timer(&lls_server_alert_timer);
106*daa5f023SMatthias Ringwald 
107*daa5f023SMatthias Ringwald     if (lls_server_alert_state == LLS_SERVER_ALERT_STATE_ALERTING){
108*daa5f023SMatthias Ringwald         lls_server_emit_alarm_stopped(false);
109*daa5f023SMatthias Ringwald         lls_server_alert_state = LLS_SERVER_ALERT_STATE_IDLE;
110*daa5f023SMatthias Ringwald     }
111*daa5f023SMatthias Ringwald }
112*daa5f023SMatthias Ringwald 
lls_server_timer_timeout_handler(btstack_timer_source_t * timer)113*daa5f023SMatthias Ringwald static void lls_server_timer_timeout_handler(btstack_timer_source_t * timer){
114*daa5f023SMatthias Ringwald     UNUSED(timer);
115*daa5f023SMatthias Ringwald     lls_server_emit_alarm_stopped(true);
116*daa5f023SMatthias Ringwald     lls_server_alert_state = LLS_SERVER_ALERT_STATE_IDLE;
117*daa5f023SMatthias Ringwald }
118*daa5f023SMatthias Ringwald 
lls_server_start_alerting(void)119*daa5f023SMatthias Ringwald static void lls_server_start_alerting(void){
120*daa5f023SMatthias Ringwald     if (lls_server_alert_state == LLS_SERVER_ALERT_STATE_ALERTING){
121*daa5f023SMatthias Ringwald         return;
122*daa5f023SMatthias Ringwald     }
123*daa5f023SMatthias Ringwald     if (lls_server_alert_level == LLS_ALERT_LEVEL_NO_ALERT){
124*daa5f023SMatthias Ringwald         return;
125*daa5f023SMatthias Ringwald     }
126*daa5f023SMatthias Ringwald 
127*daa5f023SMatthias Ringwald     lls_server_alert_state = LLS_SERVER_ALERT_STATE_ALERTING;
128*daa5f023SMatthias Ringwald     lls_server_emit_alarm_started();
129*daa5f023SMatthias Ringwald 
130*daa5f023SMatthias Ringwald     if (lls_server_alert_timeout_ms == 0){
131*daa5f023SMatthias Ringwald         return;
132*daa5f023SMatthias Ringwald     }
133*daa5f023SMatthias Ringwald 
134*daa5f023SMatthias Ringwald     btstack_run_loop_set_timer_handler(&lls_server_alert_timer, lls_server_timer_timeout_handler);
135*daa5f023SMatthias Ringwald     btstack_run_loop_set_timer(&lls_server_alert_timer, lls_server_alert_timeout_ms);
136*daa5f023SMatthias Ringwald     btstack_run_loop_add_timer(&lls_server_alert_timer);
137*daa5f023SMatthias Ringwald }
138*daa5f023SMatthias Ringwald 
lls_server_read_callback(hci_con_handle_t con_handle,uint16_t attribute_handle,uint16_t offset,uint8_t * buffer,uint16_t buffer_size)139*daa5f023SMatthias Ringwald static uint16_t lls_server_read_callback(hci_con_handle_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t * buffer, uint16_t buffer_size){
140*daa5f023SMatthias Ringwald 	UNUSED(con_handle);
141*daa5f023SMatthias Ringwald 
142*daa5f023SMatthias Ringwald 	if (attribute_handle == lls_server_alert_level_handle){
143*daa5f023SMatthias Ringwald 		return att_read_callback_handle_byte((uint8_t)lls_server_alert_level, offset, buffer, buffer_size);
144*daa5f023SMatthias Ringwald 	}
145*daa5f023SMatthias Ringwald 	return 0;
146*daa5f023SMatthias Ringwald }
147*daa5f023SMatthias Ringwald 
lls_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)148*daa5f023SMatthias Ringwald static int lls_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){
149*daa5f023SMatthias Ringwald 	UNUSED(transaction_mode);
150*daa5f023SMatthias Ringwald 	UNUSED(offset);
151*daa5f023SMatthias Ringwald 	UNUSED(con_handle);
152*daa5f023SMatthias Ringwald 
153*daa5f023SMatthias Ringwald 
154*daa5f023SMatthias Ringwald 	if (attribute_handle == lls_server_alert_level_handle){
155*daa5f023SMatthias Ringwald 		if (buffer_size != 1){
156*daa5f023SMatthias Ringwald 			return ATT_ERROR_VALUE_NOT_ALLOWED;
157*daa5f023SMatthias Ringwald 		}
158*daa5f023SMatthias Ringwald 
159*daa5f023SMatthias Ringwald 		lls_alert_level_t alert_level = (lls_alert_level_t)buffer[0];
160*daa5f023SMatthias Ringwald 		switch (alert_level){
161*daa5f023SMatthias Ringwald 			case LLS_ALERT_LEVEL_NO_ALERT:
162*daa5f023SMatthias Ringwald     		case LLS_ALERT_LEVEL_MILD_ALERT:
163*daa5f023SMatthias Ringwald     		case LLS_ALERT_LEVEL_HIGH_ALERT:
164*daa5f023SMatthias Ringwald     			lls_server_alert_level = alert_level;
165*daa5f023SMatthias Ringwald 				break;
166*daa5f023SMatthias Ringwald 			default:
167*daa5f023SMatthias Ringwald 				return ATT_ERROR_VALUE_NOT_ALLOWED;
168*daa5f023SMatthias Ringwald 		}
169*daa5f023SMatthias Ringwald 	}
170*daa5f023SMatthias Ringwald 	return 0;
171*daa5f023SMatthias Ringwald }
172*daa5f023SMatthias Ringwald 
lls_server_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)173*daa5f023SMatthias Ringwald static void lls_server_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
174*daa5f023SMatthias Ringwald     UNUSED(channel);
175*daa5f023SMatthias Ringwald     UNUSED(packet);
176*daa5f023SMatthias Ringwald     UNUSED(size);
177*daa5f023SMatthias Ringwald 
178*daa5f023SMatthias Ringwald     if (packet_type != HCI_EVENT_PACKET){
179*daa5f023SMatthias Ringwald         return;
180*daa5f023SMatthias Ringwald     }
181*daa5f023SMatthias Ringwald 
182*daa5f023SMatthias Ringwald     uint8_t reason;
183*daa5f023SMatthias Ringwald 
184*daa5f023SMatthias Ringwald     switch (hci_event_packet_get_type(packet)){
185*daa5f023SMatthias Ringwald     	case HCI_EVENT_CONNECTION_COMPLETE:
186*daa5f023SMatthias Ringwald 	        // ignore if connection failed
187*daa5f023SMatthias Ringwald 	        if (hci_event_connection_complete_get_status(packet) != ERROR_CODE_SUCCESS){
188*daa5f023SMatthias Ringwald 	        	return;
189*daa5f023SMatthias Ringwald 	        }
190*daa5f023SMatthias Ringwald 	        lls_server_stop_alerting();
191*daa5f023SMatthias Ringwald             break;
192*daa5f023SMatthias Ringwald 
193*daa5f023SMatthias Ringwald         case HCI_EVENT_DISCONNECTION_COMPLETE:
194*daa5f023SMatthias Ringwald             reason = hci_event_disconnection_complete_get_reason(packet);
195*daa5f023SMatthias Ringwald             if (reason == ERROR_CODE_REMOTE_USER_TERMINATED_CONNECTION){
196*daa5f023SMatthias Ringwald                 lls_server_stop_alerting();
197*daa5f023SMatthias Ringwald             } else {
198*daa5f023SMatthias Ringwald                 lls_server_start_alerting();
199*daa5f023SMatthias Ringwald             }
200*daa5f023SMatthias Ringwald             break;
201*daa5f023SMatthias Ringwald         default:
202*daa5f023SMatthias Ringwald             break;
203*daa5f023SMatthias Ringwald     }
204*daa5f023SMatthias Ringwald }
205*daa5f023SMatthias Ringwald 
link_loss_service_server_init(void)206*daa5f023SMatthias Ringwald void link_loss_service_server_init(void){
207*daa5f023SMatthias Ringwald 	// get service handle range
208*daa5f023SMatthias Ringwald 	uint16_t start_handle = 0;
209*daa5f023SMatthias Ringwald 	uint16_t end_handle   = 0xffff;
210*daa5f023SMatthias Ringwald 	int service_found = gatt_server_get_handle_range_for_service_with_uuid16(ORG_BLUETOOTH_SERVICE_LINK_LOSS, &start_handle, &end_handle);
211*daa5f023SMatthias Ringwald 	btstack_assert(service_found != 0);
212*daa5f023SMatthias Ringwald 	UNUSED(service_found);
213*daa5f023SMatthias Ringwald 
214*daa5f023SMatthias Ringwald 	lls_server_alert_level   = LLS_ALERT_LEVEL_NO_ALERT;
215*daa5f023SMatthias Ringwald     lls_server_alert_timeout_ms = 0;
216*daa5f023SMatthias Ringwald     lls_server_alert_state = LLS_SERVER_ALERT_STATE_IDLE;
217*daa5f023SMatthias Ringwald 
218*daa5f023SMatthias Ringwald 	// get characteristic value handle and client configuration handle
219*daa5f023SMatthias Ringwald 	lls_server_alert_level_handle = gatt_server_get_value_handle_for_characteristic_with_uuid16(start_handle, end_handle, ORG_BLUETOOTH_CHARACTERISTIC_ALERT_LEVEL);
220*daa5f023SMatthias Ringwald 
221*daa5f023SMatthias Ringwald #ifdef ENABLE_TESTING_SUPPORT
222*daa5f023SMatthias Ringwald     printf("LLS 0x%02x - 0x%02x \n", start_handle, end_handle);
223*daa5f023SMatthias Ringwald     printf("    alert_level            0x%02x \n", lls_server_alert_level_handle);
224*daa5f023SMatthias Ringwald #endif
225*daa5f023SMatthias Ringwald 	log_info("Link Loss Service Server 0x%02x-0x%02x", start_handle, end_handle);
226*daa5f023SMatthias Ringwald 
227*daa5f023SMatthias Ringwald     // register service with ATT Server
228*daa5f023SMatthias Ringwald 	link_loss_service.start_handle   = start_handle;
229*daa5f023SMatthias Ringwald 	link_loss_service.end_handle     = end_handle;
230*daa5f023SMatthias Ringwald 	link_loss_service.read_callback  = &lls_server_read_callback;
231*daa5f023SMatthias Ringwald 	link_loss_service.write_callback = &lls_server_write_callback;
232*daa5f023SMatthias Ringwald 
233*daa5f023SMatthias Ringwald 	att_server_register_service_handler(&link_loss_service);
234*daa5f023SMatthias Ringwald 
235*daa5f023SMatthias Ringwald 	lls_server_hci_event_callback_registration.callback = &lls_server_packet_handler;
236*daa5f023SMatthias Ringwald     hci_add_event_handler(&lls_server_hci_event_callback_registration);
237*daa5f023SMatthias Ringwald }
238*daa5f023SMatthias Ringwald 
link_loss_service_server_register_packet_handler(btstack_packet_handler_t packet_handler)239*daa5f023SMatthias Ringwald void link_loss_service_server_register_packet_handler(btstack_packet_handler_t packet_handler){
240*daa5f023SMatthias Ringwald 	btstack_assert(packet_handler != NULL);
241*daa5f023SMatthias Ringwald 	lls_server_callback = packet_handler;
242*daa5f023SMatthias Ringwald }
243*daa5f023SMatthias Ringwald 
link_loss_service_server_set_alert_level(lls_alert_level_t alert_level)244*daa5f023SMatthias Ringwald uint8_t link_loss_service_server_set_alert_level(lls_alert_level_t alert_level){
245*daa5f023SMatthias Ringwald     if (alert_level >= LLS_ALERT_LEVEL_RFU){
246*daa5f023SMatthias Ringwald         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
247*daa5f023SMatthias Ringwald     }
248*daa5f023SMatthias Ringwald 	lls_server_alert_level = alert_level;
249*daa5f023SMatthias Ringwald     return ERROR_CODE_SUCCESS;
250*daa5f023SMatthias Ringwald }
251*daa5f023SMatthias Ringwald 
link_loss_service_server_set_alert_timeout(uint32_t alert_timeout_ms)252*daa5f023SMatthias Ringwald uint8_t link_loss_service_server_set_alert_timeout(uint32_t alert_timeout_ms){
253*daa5f023SMatthias Ringwald     if (lls_server_alert_state != LLS_SERVER_ALERT_STATE_IDLE){
254*daa5f023SMatthias Ringwald         return BTSTACK_BUSY;
255*daa5f023SMatthias Ringwald     }
256*daa5f023SMatthias Ringwald     lls_server_alert_timeout_ms = alert_timeout_ms;
257*daa5f023SMatthias Ringwald     return ERROR_CODE_SUCCESS;
258*daa5f023SMatthias Ringwald }
259*daa5f023SMatthias Ringwald 
link_loss_service_server_stop_alerting(void)260*daa5f023SMatthias Ringwald void link_loss_service_server_stop_alerting(void){
261*daa5f023SMatthias Ringwald     lls_server_stop_alerting();
262*daa5f023SMatthias Ringwald }
263