xref: /nrf52832-nimble/packages/NimBLE-latest/apps/blecsc/src/gatt_svr.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 <stdio.h>
22 #include <string.h>
23 #include <rtthread.h>
24 #include "host/ble_hs.h"
25 #include "host/ble_uuid.h"
26 #include "blecsc_sens.h"
27 
28 #define CSC_ERR_CCC_DESC_IMPROPERLY_CONFIGURED  0x81
29 
30 static const char *manuf_name = "Apache Mynewt";
31 static const char *model_num = "Mynewt CSC Sensor";
32 
33 static const uint8_t csc_supported_sensor_locations[] = {
34     SENSOR_LOCATION_FRONT_WHEEL,
35     SENSOR_LOCATION_REAR_DROPOUT,
36     SENSOR_LOCATION_CHAINSTAY,
37     SENSOR_LOCATION_REAR_WHEEL
38 };
39 
40 static uint8_t sensor_location = SENSOR_LOCATION_REAR_DROPOUT;
41 static struct ble_csc_measurement_state * measurement_state;
42 uint16_t csc_measurement_handle;
43 uint16_t csc_control_point_handle;
44 uint8_t csc_cp_indication_status;
45 
46 static int
47 gatt_svr_chr_access_csc_measurement(uint16_t conn_handle,
48                                     uint16_t attr_handle,
49                                     struct ble_gatt_access_ctxt *ctxt,
50                                     void *arg);
51 
52 static int
53 gatt_svr_chr_access_csc_feature(uint16_t conn_handle,
54                                 uint16_t attr_handle,
55                                 struct ble_gatt_access_ctxt *ctxt,
56                                 void *arg);
57 
58 static int
59 gatt_svr_chr_access_sensor_location(uint16_t conn_handle,
60                                     uint16_t attr_handle,
61                                     struct ble_gatt_access_ctxt *ctxt,
62                                     void *arg);
63 
64 static int
65 gatt_svr_chr_access_sc_control_point(uint16_t conn_handle,
66                                      uint16_t attr_handle,
67                                      struct ble_gatt_access_ctxt *ctxt,
68                                      void *arg);
69 
70 static int
71 gatt_svr_chr_access_device_info(uint16_t conn_handle,
72                                 uint16_t attr_handle,
73                                 struct ble_gatt_access_ctxt *ctxt,
74                                 void *arg);
75 
76 static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
77     {
78         /* Service: Cycling Speed and Cadence */
79         .type = BLE_GATT_SVC_TYPE_PRIMARY,
80         .uuid = BLE_UUID16_DECLARE(GATT_CSC_UUID),
81         .characteristics = (struct ble_gatt_chr_def[]) { {
82             /* Characteristic: Cycling Speed and Cadence Measurement */
83             .uuid = BLE_UUID16_DECLARE(GATT_CSC_MEASUREMENT_UUID),
84             .access_cb = gatt_svr_chr_access_csc_measurement,
85             .val_handle = &csc_measurement_handle,
86             .flags = BLE_GATT_CHR_F_NOTIFY,
87         }, {
88             /* Characteristic: Cycling Speed and Cadence features */
89             .uuid = BLE_UUID16_DECLARE(GATT_CSC_FEATURE_UUID),
90             .access_cb = gatt_svr_chr_access_csc_feature,
91             .flags = BLE_GATT_CHR_F_READ,
92         }, {
93             /* Characteristic: Sensor Location */
94             .uuid = BLE_UUID16_DECLARE(GATT_SENSOR_LOCATION_UUID),
95             .access_cb = gatt_svr_chr_access_sensor_location,
96             .flags = BLE_GATT_CHR_F_READ,
97         }, {
98             /* Characteristic: SC Control Point*/
99             .uuid = BLE_UUID16_DECLARE(GATT_SC_CONTROL_POINT_UUID),
100             .access_cb = gatt_svr_chr_access_sc_control_point,
101             .val_handle = &csc_control_point_handle,
102             .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_INDICATE,
103         }, {
104             0, /* No more characteristics in this service */
105         }, }
106     },
107 
108     {
109         /* Service: Device Information */
110         .type = BLE_GATT_SVC_TYPE_PRIMARY,
111         .uuid = BLE_UUID16_DECLARE(GATT_DEVICE_INFO_UUID),
112         .characteristics = (struct ble_gatt_chr_def[]) { {
113             /* Characteristic: * Manufacturer name */
114             .uuid = BLE_UUID16_DECLARE(GATT_MANUFACTURER_NAME_UUID),
115             .access_cb = gatt_svr_chr_access_device_info,
116             .flags = BLE_GATT_CHR_F_READ,
117         }, {
118             /* Characteristic: Model number string */
119             .uuid = BLE_UUID16_DECLARE(GATT_MODEL_NUMBER_UUID),
120             .access_cb = gatt_svr_chr_access_device_info,
121             .flags = BLE_GATT_CHR_F_READ,
122         }, {
123             0, /* No more characteristics in this service */
124         }, }
125     },
126 
127     {
128         0, /* No more services */
129     },
130 };
131 
132 static int
gatt_svr_chr_access_csc_measurement(uint16_t conn_handle,uint16_t attr_handle,struct ble_gatt_access_ctxt * ctxt,void * arg)133 gatt_svr_chr_access_csc_measurement(uint16_t conn_handle, uint16_t attr_handle,
134                                   struct ble_gatt_access_ctxt *ctxt, void *arg)
135 {
136     return BLE_ATT_ERR_READ_NOT_PERMITTED;
137 }
138 
139 static int
gatt_svr_chr_access_csc_feature(uint16_t conn_handle,uint16_t attr_handle,struct ble_gatt_access_ctxt * ctxt,void * arg)140 gatt_svr_chr_access_csc_feature(uint16_t conn_handle, uint16_t attr_handle,
141                                 struct ble_gatt_access_ctxt *ctxt, void *arg)
142 {
143     static const uint16_t csc_feature = CSC_FEATURES;
144     int rc;
145 
146     assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
147     rc = os_mbuf_append(ctxt->om, &csc_feature, sizeof(csc_feature));
148 
149     return (rc == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
150 }
151 
152 static int
gatt_svr_chr_access_sensor_location(uint16_t conn_handle,uint16_t attr_handle,struct ble_gatt_access_ctxt * ctxt,void * arg)153 gatt_svr_chr_access_sensor_location(uint16_t conn_handle, uint16_t attr_handle,
154                                   struct ble_gatt_access_ctxt *ctxt, void *arg)
155 {
156     int rc;
157 
158     assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
159     rc = os_mbuf_append(ctxt->om, &sensor_location, sizeof(sensor_location));
160 
161     return (rc == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
162 }
163 
164 static int
gatt_svr_chr_access_sc_control_point(uint16_t conn_handle,uint16_t attr_handle,struct ble_gatt_access_ctxt * ctxt,void * arg)165 gatt_svr_chr_access_sc_control_point(uint16_t conn_handle,
166                                      uint16_t attr_handle,
167                                      struct ble_gatt_access_ctxt *ctxt,
168                                      void *arg)
169 {
170     uint8_t op_code;
171     uint8_t new_sensor_location;
172     uint8_t new_cumulative_wheel_rev_arr[4];
173     struct os_mbuf *om_indication;
174     uint8_t response = SC_CP_RESPONSE_OP_NOT_SUPPORTED;
175     int ii;
176     int rc;
177 
178     assert(ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR);
179 
180     if (!csc_cp_indication_status) {
181         MODLOG_DFLT(INFO, "SC Control Point; CCC descriptor "
182                           "improperly configured");
183         return CSC_ERR_CCC_DESC_IMPROPERLY_CONFIGURED;
184     }
185 
186     /* Read control point op code*/
187     rc = os_mbuf_copydata(ctxt->om, 0, sizeof(op_code), &op_code);
188     if (rc != 0){
189         return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
190     }
191     MODLOG_DFLT(INFO, "SC Control Point; opcode=%d\n", op_code);
192 
193     /* Allocate response buffer */
194     om_indication = ble_hs_mbuf_att_pkt();
195 
196     switch(op_code){
197 #if (CSC_FEATURES & CSC_FEATURE_WHEEL_REV_DATA)
198     case SC_CP_OP_SET_CUMULATIVE_VALUE:
199         /* Read new cumulative wheel revolutions value*/
200         rc = os_mbuf_copydata(ctxt->om, 1,
201                               sizeof(new_cumulative_wheel_rev_arr),
202                               new_cumulative_wheel_rev_arr);
203         if (rc != 0){
204             return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
205         }
206 
207         measurement_state->cumulative_wheel_rev =
208                            get_le32(new_cumulative_wheel_rev_arr);
209 
210         MODLOG_DFLT(INFO, "SC Control Point; Set cumulative value = %d\n",
211                     measurement_state->cumulative_wheel_rev);
212 
213         response = SC_CP_RESPONSE_SUCCESS;
214         break;
215 #endif
216 
217 #if (CSC_FEATURES & CSC_FEATURE_MULTIPLE_SENSOR_LOC)
218     case SC_CP_OP_UPDATE_SENSOR_LOCATION:
219         /* Read new sensor location value*/
220         rc = os_mbuf_copydata(ctxt->om, 1, 1, &new_sensor_location);
221         if (rc != 0){
222           return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
223         }
224 
225         MODLOG_DFLT(INFO, "SC Control Point; Sensor location update = %d\n",
226                     new_sensor_location);
227 
228         /* Verify if requested new location is on supported locations list */
229         response = SC_CP_RESPONSE_INVALID_PARAM;
230         for (ii = 0; ii < sizeof(csc_supported_sensor_locations); ii++){
231             if (new_sensor_location == csc_supported_sensor_locations[ii]){
232                 sensor_location = new_sensor_location;
233                 response = SC_CP_RESPONSE_SUCCESS;
234                 break;
235             }
236         }
237         break;
238 
239     case SC_CP_OP_REQ_SUPPORTED_SENSOR_LOCATIONS:
240         response = SC_CP_RESPONSE_SUCCESS;
241         break;
242 #endif
243 
244     default:
245         break;
246     }
247 
248     /* Append response value */
249     rc = os_mbuf_append(om_indication, &response, sizeof(response));
250 
251     if (rc != 0){
252       return BLE_ATT_ERR_INSUFFICIENT_RES;
253     }
254 
255 #if (CSC_FEATURES & CSC_FEATURE_MULTIPLE_SENSOR_LOC)
256     /* In case of supported locations request append locations list */
257     if (op_code == SC_CP_OP_REQ_SUPPORTED_SENSOR_LOCATIONS){
258       rc = os_mbuf_append(om_indication, &csc_supported_sensor_locations,
259                           sizeof(csc_supported_sensor_locations));
260     }
261 
262     if (rc != 0){
263       return BLE_ATT_ERR_INSUFFICIENT_RES;
264     }
265 #endif
266 
267     rc = ble_gattc_indicate_custom(conn_handle, csc_control_point_handle,
268                                    om_indication);
269 
270     return rc;
271 }
272 
273 static int
gatt_svr_chr_access_device_info(uint16_t conn_handle,uint16_t attr_handle,struct ble_gatt_access_ctxt * ctxt,void * arg)274 gatt_svr_chr_access_device_info(uint16_t conn_handle, uint16_t attr_handle,
275                                 struct ble_gatt_access_ctxt *ctxt, void *arg)
276 {
277     uint16_t uuid;
278     int rc;
279 
280     uuid = ble_uuid_u16(ctxt->chr->uuid);
281 
282     if (uuid == GATT_MODEL_NUMBER_UUID) {
283         rc = os_mbuf_append(ctxt->om, model_num, strlen(model_num));
284         return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
285     }
286 
287     if (uuid == GATT_MANUFACTURER_NAME_UUID) {
288         rc = os_mbuf_append(ctxt->om, manuf_name, strlen(manuf_name));
289         return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
290     }
291 
292     assert(0);
293     return BLE_ATT_ERR_UNLIKELY;
294 }
295 
296 int
gatt_svr_chr_notify_csc_measurement(uint16_t conn_handle)297 gatt_svr_chr_notify_csc_measurement(uint16_t conn_handle)
298 {
299     int rc;
300     struct os_mbuf *om;
301     uint8_t data_buf[11];
302     uint8_t data_offset = 1;
303 
304     memset(data_buf, 0, sizeof(data_buf));
305 
306 #if (CSC_FEATURES & CSC_FEATURE_WHEEL_REV_DATA)
307     data_buf[0] |= CSC_MEASUREMENT_WHEEL_REV_PRESENT;
308     put_le16(&(data_buf[5]), measurement_state->last_wheel_evt_time);
309     put_le32(&(data_buf[1]), measurement_state->cumulative_wheel_rev);
310     data_offset += 6;
311 #endif
312 
313 #if (CSC_FEATURES & CSC_FEATURE_CRANK_REV_DATA)
314     data_buf[0] |= CSC_MEASUREMENT_CRANK_REV_PRESENT;
315     put_le16(&(data_buf[data_offset]),
316              measurement_state->cumulative_crank_rev);
317     put_le16(&(data_buf[data_offset + 2]),
318              measurement_state->last_crank_evt_time);
319     data_offset += 4;
320 #endif
321 
322     om = ble_hs_mbuf_from_flat(data_buf, data_offset);
323 
324     rc = ble_gattc_notify_custom(conn_handle, csc_measurement_handle, om);
325     return rc;
326 }
327 
328 void
gatt_svr_set_cp_indicate(uint8_t indication_status)329 gatt_svr_set_cp_indicate(uint8_t indication_status)
330 {
331   csc_cp_indication_status = indication_status;
332 }
333 
334 void
gatt_svr_register_cb(struct ble_gatt_register_ctxt * ctxt,void * arg)335 gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
336 {
337     char buf[BLE_UUID_STR_LEN];
338 
339     switch (ctxt->op) {
340     case BLE_GATT_REGISTER_OP_SVC:
341         MODLOG_DFLT(DEBUG, "registered service %s with handle=%d\n",
342                     ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf),
343                     ctxt->svc.handle);
344         break;
345 
346     case BLE_GATT_REGISTER_OP_CHR:
347         MODLOG_DFLT(DEBUG, "registering characteristic %s with "
348                            "def_handle=%d val_handle=%d\n",
349                     ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
350                     ctxt->chr.def_handle,
351                     ctxt->chr.val_handle);
352         break;
353 
354     case BLE_GATT_REGISTER_OP_DSC:
355         MODLOG_DFLT(DEBUG, "registering descriptor %s with handle=%d\n",
356                     ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf),
357                     ctxt->dsc.handle);
358         break;
359 
360     default:
361         assert(0);
362         break;
363     }
364 }
365 
366 int
gatt_svr_init(struct ble_csc_measurement_state * csc_measurement_state)367 gatt_svr_init(struct ble_csc_measurement_state * csc_measurement_state)
368 {
369     int rc;
370 
371     rc = ble_gatts_count_cfg(gatt_svr_svcs);
372     if (rc != 0) {
373         return rc;
374     }
375 
376     rc = ble_gatts_add_svcs(gatt_svr_svcs);
377     if (rc != 0) {
378         return rc;
379     }
380 
381     measurement_state = csc_measurement_state;
382 
383     return 0;
384 }
385