xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/services/lls/src/ble_svc_lls.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *  http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #include <assert.h>
21 #include <string.h>
22 #include "sysinit/sysinit.h"
23 #include "host/ble_hs.h"
24 #include "services/lls/ble_svc_lls.h"
25 
26 /* Callback function */
27 static ble_svc_lls_event_fn *ble_svc_lls_cb_fn;
28 
29 /* Alert level */
30 static uint8_t ble_svc_lls_alert_level;
31 
32 /* Write characteristic function */
33 static int
34 ble_svc_lls_chr_write(struct os_mbuf *om, uint16_t min_len,
35                       uint16_t max_len, void *dst,
36                       uint16_t *len);
37 
38 /* Access function */
39 static int
40 ble_svc_lls_access(uint16_t conn_handle, uint16_t attr_handle,
41                    struct ble_gatt_access_ctxt *ctxt, void *arg);
42 
43 static const struct ble_gatt_svc_def ble_svc_lls_defs[] = {
44     {
45         /*** Service: Link Loss Service (LLS). */
46         .type = BLE_GATT_SVC_TYPE_PRIMARY,
47         .uuid = BLE_UUID16_DECLARE(BLE_SVC_LLS_UUID16),
48         .characteristics = (struct ble_gatt_chr_def[]) { {
49             /*** Characteristic: Alert Level. */
50             .uuid = BLE_UUID16_DECLARE(BLE_SVC_LLS_CHR_UUID16_ALERT_LEVEL),
51             .access_cb = ble_svc_lls_access,
52             .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE,
53         }, {
54             0, /* No more characteristics in this service. */
55         } },
56     },
57 
58     {
59         0, /* No more services. */
60     },
61 };
62 
63 /**
64  * Writes the received value from a characteristic write to
65  * the given destination.
66  */
67 static int
ble_svc_lls_chr_write(struct os_mbuf * om,uint16_t min_len,uint16_t max_len,void * dst,uint16_t * len)68 ble_svc_lls_chr_write(struct os_mbuf *om, uint16_t min_len,
69                       uint16_t max_len, void *dst,
70                       uint16_t *len)
71 {
72     uint16_t om_len;
73     int rc;
74 
75     om_len = OS_MBUF_PKTLEN(om);
76     if (om_len < min_len || om_len > max_len) {
77         return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
78     }
79 
80     rc = ble_hs_mbuf_to_flat(om, dst, max_len, len);
81     if (rc != 0) {
82         return BLE_ATT_ERR_UNLIKELY;
83     }
84 
85     return 0;
86 }
87 
88 /**
89  * Simple read/write access callback for the alert level
90  * characteristic.
91  */
92 static int
ble_svc_lls_access(uint16_t conn_handle,uint16_t attr_handle,struct ble_gatt_access_ctxt * ctxt,void * arg)93 ble_svc_lls_access(uint16_t conn_handle, uint16_t attr_handle,
94                    struct ble_gatt_access_ctxt *ctxt, void *arg)
95 {
96     assert(ctxt->chr == &ble_svc_lls_defs[0].characteristics[0]);
97     int rc;
98     switch (ctxt->op) {
99     case BLE_GATT_ACCESS_OP_READ_CHR:
100         rc = os_mbuf_append(ctxt->om, &ble_svc_lls_alert_level,
101                             sizeof ble_svc_lls_alert_level);
102         return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
103 
104     case BLE_GATT_ACCESS_OP_WRITE_CHR:
105         rc = ble_svc_lls_chr_write(ctxt->om,
106                                    sizeof ble_svc_lls_alert_level,
107                                    sizeof ble_svc_lls_alert_level,
108                                    &ble_svc_lls_alert_level, NULL);
109         return rc;
110 
111     default:
112         assert(0);
113         return BLE_ATT_ERR_UNLIKELY;
114     }
115 
116     return 0;
117 }
118 
119 /**
120  * This function is the crux of the link loss service. The application
121  * developer must call this function inside the gap event callback
122  * function when a BLE_GAP_EVENT_DISCONNECT event is received and
123  * pass the disconnect reason into this function.
124  *
125  * Here, we then check if the disconnect reason is due to a timout, and if
126  * so, we call the ble_svc_lls_event_fn callback with the current
127  * alert level. The actual alert implementation is left up to the
128  * developer.
129  *
130  * @param reason            The reason attatched to the GAP disconnect
131  *                              event.
132  */
133 void
ble_svc_lls_on_gap_disconnect(int reason)134 ble_svc_lls_on_gap_disconnect(int reason)
135 {
136     if (reason == BLE_HS_HCI_ERR(BLE_ERR_CONN_SPVN_TMO)) {
137             ble_svc_lls_cb_fn(ble_svc_lls_alert_level);
138     }
139 }
140 
141 /**
142  * Gets the current alert level.
143  *
144  * @return The current alert level
145  */
146 uint8_t
ble_svc_lls_alert_level_get(void)147 ble_svc_lls_alert_level_get(void)
148 {
149     return ble_svc_lls_alert_level;
150 }
151 
152 /**
153  * Sets the current alert level.
154  *
155  * @return 0 on success, BLE_HS_EINVAL if the given alert level is not valid.
156  */
157 int
ble_svc_lls_alert_level_set(uint8_t alert_level)158 ble_svc_lls_alert_level_set(uint8_t alert_level)
159 {
160     if (alert_level > BLE_SVC_LLS_ALERT_LEVEL_HIGH_ALERT) {
161         return BLE_HS_EINVAL;
162     }
163 
164     memcpy(&ble_svc_lls_alert_level, &alert_level,
165            sizeof alert_level);
166 
167     return 0;
168 }
169 
170 void
ble_svc_lls_set_cb(ble_svc_lls_event_fn * cb)171 ble_svc_lls_set_cb(ble_svc_lls_event_fn *cb)
172 {
173     ble_svc_lls_cb_fn = cb;
174 }
175 
176 /**
177  * Initialize the IAS package.
178  */
179 void
ble_svc_lls_init(void)180 ble_svc_lls_init(void)
181 {
182     int rc;
183 
184     /* Ensure this function only gets called by sysinit. */
185     SYSINIT_ASSERT_ACTIVE();
186 
187     rc = ble_gatts_count_cfg(ble_svc_lls_defs);
188     SYSINIT_PANIC_ASSERT(rc == 0);
189 
190     rc = ble_gatts_add_svcs(ble_svc_lls_defs);
191     SYSINIT_PANIC_ASSERT(rc == 0);
192 }
193