sjanc closed pull request #819: Feature/blecsc app: Cycling Speed and Cadence 
app
URL: https://github.com/apache/mynewt-core/pull/819
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/apps/blecsc/README.md b/apps/blecsc/README.md
new file mode 100644
index 000000000..bccf176a1
--- /dev/null
+++ b/apps/blecsc/README.md
@@ -0,0 +1,9 @@
+# BLE Cycling Speed and Cadence peripheral app.
+
+The source files are located in the src/ directory.
+
+pkg.yml contains the base definition of the app.
+
+syscfg.yml contains setting definitions and overrides.
+
+
diff --git a/apps/blecsc/pkg.yml b/apps/blecsc/pkg.yml
new file mode 100644
index 000000000..860ec4a34
--- /dev/null
+++ b/apps/blecsc/pkg.yml
@@ -0,0 +1,40 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+pkg.name: apps/blecsc
+pkg.type: app
+pkg.description: BLE peripheral cycling speed and cadence sensor.
+pkg.author: "Maciej Jurczak"
+pkg.email: "mjurc...@gmail.com"
+pkg.homepage: "http://mynewt.apache.org/";
+pkg.keywords:
+
+pkg.deps:
+    - boot/bootutil
+    - kernel/os
+    - net/nimble/controller
+    - net/nimble/host
+    - net/nimble/host/services/gap
+    - net/nimble/host/services/gatt
+    - net/nimble/host/store/config
+    - net/nimble/transport
+    - sys/console/full
+    - sys/log/full
+    - sys/stats/full
+    - sys/sysinit
+    - sys/id
diff --git a/apps/blecsc/src/blecsc_sens.h b/apps/blecsc/src/blecsc_sens.h
new file mode 100644
index 000000000..a73a3b8be
--- /dev/null
+++ b/apps/blecsc/src/blecsc_sens.h
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef H_BLECSC_SENSOR_
+#define H_BLECSC_SENSOR_
+
+#include "log/log.h"
+#include "nimble/ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct log blecsc_log;
+
+/* blecsc uses the first "peruser" log module */
+#define BLECSC_LOG_MODULE (LOG_MODULE_PERUSER + 0)
+
+/* Convenience macro for logging to the blerh module */
+#define BLECSC_LOG(lvl, ...) \
+    LOG_ ## lvl(&blecsc_log, BLECSC_LOG_MODULE, __VA_ARGS__)
+
+/* Cycling Speed and Cadence configuration */
+#define GATT_CSC_UUID                           0x1816
+#define GATT_CSC_MEASUREMENT_UUID               0x2A5B
+#define GATT_CSC_FEATURE_UUID                   0x2A5C
+#define GATT_SENSOR_LOCATION_UUID               0x2A5D
+#define GATT_SC_CONTROL_POINT_UUID              0x2A55
+/* Device Information configuration */
+#define GATT_DEVICE_INFO_UUID                   0x180A
+#define GATT_MANUFACTURER_NAME_UUID             0x2A29
+#define GATT_MODEL_NUMBER_UUID                  0x2A24
+
+/*CSC Measurement flags*/
+#define CSC_MEASUREMENT_WHEEL_REV_PRESENT       0x01
+#define CSC_MEASUREMENT_CRANK_REV_PRESENT       0x02
+
+/* CSC feature flags */
+#define CSC_FEATURE_WHEEL_REV_DATA              0x01
+#define CSC_FEATURE_CRANK_REV_DATA              0x02
+#define CSC_FEATURE_MULTIPLE_SENSOR_LOC         0x04
+
+/* Sensor location enum */
+#define SENSOR_LOCATION_OTHER                   0
+#define SENSOR_LOCATION_TOP_OF_SHOE             1
+#define SENSOR_LOCATION_IN_SHOE                 2
+#define SENSOR_LOCATION_HIP                     3
+#define SENSOR_LOCATION_FRONT_WHEEL             4
+#define SENSOR_LOCATION_LEFT_CRANK              5
+#define SENSOR_LOCATION_RIGHT_CRANK             6
+#define SENSOR_LOCATION_LEFT_PEDAL              7
+#define SENSOR_LOCATION_RIGHT_PEDAL             8
+#define SENSOR_LOCATION_FROT_HUB                9
+#define SENSOR_LOCATION_REAR_DROPOUT            10
+#define SENSOR_LOCATION_CHAINSTAY               11
+#define SENSOR_LOCATION_REAR_WHEEL              12
+#define SENSOR_LOCATION_REAR_HUB                13
+#define SENSOR_LOCATION_CHEST                   14
+#define SENSOR_LOCATION_SPIDER                  15
+#define SENSOR_LOCATION_CHAIN_RING              16
+
+/* SC Control Point op codes */
+#define SC_CP_OP_SET_CUMULATIVE_VALUE           1
+#define SC_CP_OP_START_SENSOR_CALIBRATION       2
+#define SC_CP_OP_UPDATE_SENSOR_LOCATION         3
+#define SC_CP_OP_REQ_SUPPORTED_SENSOR_LOCATIONS 4
+#define SC_CP_OP_RESPONSE                       16
+
+/*SC Control Point response values */
+#define SC_CP_RESPONSE_SUCCESS                  1
+#define SC_CP_RESPONSE_OP_NOT_SUPPORTED         2
+#define SC_CP_RESPONSE_INVALID_PARAM            3
+#define SC_CP_RESPONSE_OP_FAILED                4
+
+/* CSC simulation configuration */
+#define CSC_FEATURES                         (CSC_FEATURE_WHEEL_REV_DATA | \
+                                              CSC_FEATURE_CRANK_REV_DATA |\
+                                              CSC_FEATURE_MULTIPLE_SENSOR_LOC)
+                                              
+struct ble_csc_measurement_state {
+    uint32_t cumulative_wheel_rev;
+    uint16_t last_wheel_evt_time;
+    uint16_t cumulative_crank_rev;
+    uint16_t last_crank_evt_time;
+};
+
+extern uint16_t csc_measurement_handle;
+extern uint16_t csc_control_point_handle;
+
+int gatt_svr_init(struct ble_csc_measurement_state * csc_measurement_state);
+int gatt_svr_chr_notify_csc_measurement(uint16_t conn_handle);
+void gatt_svr_set_cp_indicate(uint8_t indication_status);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/apps/blecsc/src/gatt_svr.c b/apps/blecsc/src/gatt_svr.c
new file mode 100644
index 000000000..2767787b9
--- /dev/null
+++ b/apps/blecsc/src/gatt_svr.c
@@ -0,0 +1,385 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include "host/ble_hs.h"
+#include "host/ble_uuid.h"
+#include "blecsc_sens.h"
+#include "os/endian.h"
+
+#define CSC_ERR_CCC_DESC_IMPROPERLY_CONFIGURED  0x81
+
+static const char *manuf_name = "Apache Mynewt";
+static const char *model_num = "Mynewt CSC Sensor";
+
+static const uint8_t csc_supported_sensor_locations[] = {
+    SENSOR_LOCATION_FRONT_WHEEL,
+    SENSOR_LOCATION_REAR_DROPOUT,
+    SENSOR_LOCATION_CHAINSTAY,
+    SENSOR_LOCATION_REAR_WHEEL
+};
+
+static uint8_t sensor_location = SENSOR_LOCATION_REAR_DROPOUT;
+static struct ble_csc_measurement_state * measurement_state;
+uint16_t csc_measurement_handle;
+uint16_t csc_control_point_handle;
+uint8_t csc_cp_indication_status;
+
+static int
+gatt_svr_chr_access_csc_measurement(uint16_t conn_handle, 
+                                    uint16_t attr_handle,
+                                    struct ble_gatt_access_ctxt *ctxt, 
+                                    void *arg);
+                                  
+static int
+gatt_svr_chr_access_csc_feature(uint16_t conn_handle, 
+                                uint16_t attr_handle,
+                                struct ble_gatt_access_ctxt *ctxt, 
+                                void *arg);                                  
+                                
+static int
+gatt_svr_chr_access_sensor_location(uint16_t conn_handle, 
+                                    uint16_t attr_handle,
+                                    struct ble_gatt_access_ctxt *ctxt, 
+                                    void *arg);
+                                  
+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);                               
        
+
+static int
+gatt_svr_chr_access_device_info(uint16_t conn_handle, 
+                                uint16_t attr_handle,
+                                struct ble_gatt_access_ctxt *ctxt, 
+                                void *arg);
+
+static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
+    {
+        /* Service: Cycling Speed and Cadence */
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid = BLE_UUID16_DECLARE(GATT_CSC_UUID),
+        .characteristics = (struct ble_gatt_chr_def[]) { {
+            /* Characteristic: Cycling Speed and Cadence Measurement */
+            .uuid = BLE_UUID16_DECLARE(GATT_CSC_MEASUREMENT_UUID),
+            .access_cb = gatt_svr_chr_access_csc_measurement,
+            .val_handle = &csc_measurement_handle,
+            .flags = BLE_GATT_CHR_F_NOTIFY,
+        }, {
+            /* Characteristic: Cycling Speed and Cadence features */
+            .uuid = BLE_UUID16_DECLARE(GATT_CSC_FEATURE_UUID),
+            .access_cb = gatt_svr_chr_access_csc_feature,
+            .flags = BLE_GATT_CHR_F_READ,
+        }, {
+            /* Characteristic: Sensor Location */
+            .uuid = BLE_UUID16_DECLARE(GATT_SENSOR_LOCATION_UUID),
+            .access_cb = gatt_svr_chr_access_sensor_location,
+            .flags = BLE_GATT_CHR_F_READ,
+        }, {
+            /* Characteristic: SC Control Point*/
+            .uuid = BLE_UUID16_DECLARE(GATT_SC_CONTROL_POINT_UUID),
+            .access_cb = gatt_svr_chr_access_sc_control_point,
+            .val_handle = &csc_control_point_handle,
+            .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_INDICATE,
+        }, {          
+            0, /* No more characteristics in this service */
+        }, }
+    },
+
+    {
+        /* Service: Device Information */
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid = BLE_UUID16_DECLARE(GATT_DEVICE_INFO_UUID),
+        .characteristics = (struct ble_gatt_chr_def[]) { {
+            /* Characteristic: * Manufacturer name */
+            .uuid = BLE_UUID16_DECLARE(GATT_MANUFACTURER_NAME_UUID),
+            .access_cb = gatt_svr_chr_access_device_info,
+            .flags = BLE_GATT_CHR_F_READ,
+        }, {
+            /* Characteristic: Model number string */
+            .uuid = BLE_UUID16_DECLARE(GATT_MODEL_NUMBER_UUID),
+            .access_cb = gatt_svr_chr_access_device_info,
+            .flags = BLE_GATT_CHR_F_READ,
+        }, {
+            0, /* No more characteristics in this service */
+        }, }
+    },
+
+    {
+        0, /* No more services */
+    },
+};
+
+static int
+gatt_svr_chr_access_csc_measurement(uint16_t conn_handle, uint16_t attr_handle,
+                                  struct ble_gatt_access_ctxt *ctxt, void *arg)
+{
+    return BLE_ATT_ERR_READ_NOT_PERMITTED;
+}
+
+static int
+gatt_svr_chr_access_csc_feature(uint16_t conn_handle, uint16_t attr_handle,
+                                struct ble_gatt_access_ctxt *ctxt, void *arg)
+{
+    static const uint16_t csc_feature = CSC_FEATURES;
+    int rc;
+
+    assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
+    rc = os_mbuf_append(ctxt->om, &csc_feature, sizeof(csc_feature));
+
+    return (rc == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+}
+
+static int
+gatt_svr_chr_access_sensor_location(uint16_t conn_handle, uint16_t attr_handle,
+                                  struct ble_gatt_access_ctxt *ctxt, void *arg)
+{
+    int rc;
+    
+    assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
+    rc = os_mbuf_append(ctxt->om, &sensor_location, sizeof(sensor_location));
+
+    return (rc == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+}
+
+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)
+{
+    uint8_t op_code;
+    uint8_t new_sensor_location;
+    uint8_t new_cumulative_wheel_rev_arr[4];
+    struct os_mbuf *om_indication;
+    uint8_t response = SC_CP_RESPONSE_OP_NOT_SUPPORTED;
+    int ii;
+    int rc;
+    
+    assert(ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR);
+
+    if (!csc_cp_indication_status) {
+        BLECSC_LOG(INFO, "SC Control Point; CCC descriptor "
+                         "improperly configured");
+        return CSC_ERR_CCC_DESC_IMPROPERLY_CONFIGURED;
+    }
+    
+    /* Read control point op code*/
+    rc = os_mbuf_copydata(ctxt->om, 0, sizeof(op_code), &op_code);
+    if (rc != 0){
+        return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
+    }
+    BLECSC_LOG(INFO, "SC Control Point; opcode=%d\n", op_code);  
+ 
+    /* Allocate response buffer */
+    om_indication = ble_hs_mbuf_att_pkt();
+    
+    switch(op_code){
+#if (CSC_FEATURES & CSC_FEATURE_WHEEL_REV_DATA)          
+    case SC_CP_OP_SET_CUMULATIVE_VALUE:
+        /* Read new cumulative wheel revolutions value*/
+        rc = os_mbuf_copydata(ctxt->om, 1, 
+                              sizeof(new_cumulative_wheel_rev_arr), 
+                              new_cumulative_wheel_rev_arr);
+        if (rc != 0){
+            return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
+        }
+
+        measurement_state->cumulative_wheel_rev = 
+                           get_le32(new_cumulative_wheel_rev_arr);
+        
+        BLECSC_LOG(INFO, "SC Control Point; Set cumulative value = %d\n", 
+                          measurement_state->cumulative_wheel_rev);  
+                        
+        response = SC_CP_RESPONSE_SUCCESS;                         
+        break;
+#endif  
+
+#if (CSC_FEATURES & CSC_FEATURE_MULTIPLE_SENSOR_LOC) 
+    case SC_CP_OP_UPDATE_SENSOR_LOCATION:
+        /* Read new sensor location value*/
+        rc = os_mbuf_copydata(ctxt->om, 1, 1, &new_sensor_location);
+        if (rc != 0){
+          return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
+        }
+        
+        BLECSC_LOG(INFO, "SC Control Point; Sensor location update = %d\n", 
+                         new_sensor_location);         
+        
+        /* Verify if requested new location is on supported locations list */
+        response = SC_CP_RESPONSE_INVALID_PARAM;
+        for (ii = 0; ii < sizeof(csc_supported_sensor_locations); ii++){
+            if (new_sensor_location == csc_supported_sensor_locations[ii]){
+                sensor_location = new_sensor_location;                 
+                response = SC_CP_RESPONSE_SUCCESS;
+                break;
+            }
+        }
+        break;
+
+    case SC_CP_OP_REQ_SUPPORTED_SENSOR_LOCATIONS:
+        response = SC_CP_RESPONSE_SUCCESS;
+        break;
+#endif
+     
+    default:
+        break;
+    }
+    
+    /* Append response value */
+    rc = os_mbuf_append(om_indication, &response, sizeof(response));    
+    
+    if (rc != 0){
+      return BLE_ATT_ERR_INSUFFICIENT_RES;
+    }
+
+#if (CSC_FEATURES & CSC_FEATURE_MULTIPLE_SENSOR_LOC)     
+    /* In case of supported locations request append locations list */
+    if (op_code == SC_CP_OP_REQ_SUPPORTED_SENSOR_LOCATIONS){
+      rc = os_mbuf_append(om_indication, &csc_supported_sensor_locations, 
+                          sizeof(csc_supported_sensor_locations));
+    }
+    
+    if (rc != 0){
+      return BLE_ATT_ERR_INSUFFICIENT_RES;
+    }
+#endif
+
+    rc = ble_gattc_indicate_custom(conn_handle, csc_control_point_handle,
+                                   om_indication);    
+    
+    return rc;
+}
+
+static int
+gatt_svr_chr_access_device_info(uint16_t conn_handle, uint16_t attr_handle,
+                                struct ble_gatt_access_ctxt *ctxt, void *arg)
+{
+    uint16_t uuid;
+    int rc;
+
+    uuid = ble_uuid_u16(ctxt->chr->uuid);
+
+    if (uuid == GATT_MODEL_NUMBER_UUID) {
+        rc = os_mbuf_append(ctxt->om, model_num, strlen(model_num));
+        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+    }
+
+    if (uuid == GATT_MANUFACTURER_NAME_UUID) {
+        rc = os_mbuf_append(ctxt->om, manuf_name, strlen(manuf_name));
+        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+    }
+
+    assert(0);
+    return BLE_ATT_ERR_UNLIKELY;
+}
+
+int
+gatt_svr_chr_notify_csc_measurement(uint16_t conn_handle)
+{
+    int rc;
+    struct os_mbuf *om;
+    uint8_t data_buf[11];
+    uint8_t data_offset = 1;
+
+    memset(data_buf, 0, sizeof(data_buf));
+    
+#if (CSC_FEATURES & CSC_FEATURE_WHEEL_REV_DATA)
+    data_buf[0] |= CSC_MEASUREMENT_WHEEL_REV_PRESENT;
+    put_le16(&(data_buf[5]), measurement_state->last_wheel_evt_time);
+    put_le32(&(data_buf[1]), measurement_state->cumulative_wheel_rev);
+    data_offset += 6;
+#endif
+
+#if (CSC_FEATURES & CSC_FEATURE_CRANK_REV_DATA)
+    data_buf[0] |= CSC_MEASUREMENT_CRANK_REV_PRESENT;
+    put_le16(&(data_buf[data_offset]), 
+             measurement_state->cumulative_crank_rev);  
+    put_le16(&(data_buf[data_offset + 2]),
+             measurement_state->last_crank_evt_time);
+    data_offset += 4;                         
+#endif  
+    
+    om = ble_hs_mbuf_from_flat(data_buf, data_offset);
+
+    rc = ble_gattc_notify_custom(conn_handle, csc_measurement_handle, om);
+    return rc;
+}
+
+void 
+gatt_svr_set_cp_indicate(uint8_t indication_status)
+{
+  csc_cp_indication_status = indication_status;
+}
+
+void
+gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
+{
+    char buf[BLE_UUID_STR_LEN];
+
+    switch (ctxt->op) {
+    case BLE_GATT_REGISTER_OP_SVC:
+        BLECSC_LOG(DEBUG, "registered service %s with handle=%d\n",
+                    ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf),
+                    ctxt->svc.handle);
+        break;
+
+    case BLE_GATT_REGISTER_OP_CHR:
+        BLECSC_LOG(DEBUG, "registering characteristic %s with "
+                           "def_handle=%d val_handle=%d\n",
+                    ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
+                    ctxt->chr.def_handle,
+                    ctxt->chr.val_handle);
+        break;
+
+    case BLE_GATT_REGISTER_OP_DSC:
+        BLECSC_LOG(DEBUG, "registering descriptor %s with handle=%d\n",
+                    ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf),
+                    ctxt->dsc.handle);
+        break;
+
+    default:
+        assert(0);
+        break;
+    }
+}
+
+int
+gatt_svr_init(struct ble_csc_measurement_state * csc_measurement_state)
+{
+    int rc;
+
+    rc = ble_gatts_count_cfg(gatt_svr_svcs);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = ble_gatts_add_svcs(gatt_svr_svcs);
+    if (rc != 0) {
+        return rc;
+    }
+    
+    measurement_state = csc_measurement_state;
+
+    return 0;
+}
+
diff --git a/apps/blecsc/src/main.c b/apps/blecsc/src/main.c
new file mode 100644
index 000000000..9d91eb9e4
--- /dev/null
+++ b/apps/blecsc/src/main.c
@@ -0,0 +1,320 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "sysinit/sysinit.h"
+#include "os/os.h"
+#include "console/console.h"
+#include "config/config.h"
+#include "nimble/ble.h"
+#include "host/ble_hs.h"
+#include "services/gap/ble_svc_gap.h"
+#include "blecsc_sens.h"
+
+/* Wheel size for simulation calculations */
+#define CSC_SIM_WHEEL_CIRCUMFERENCE_MM            2000
+/* Simulated cadence lower limit */
+#define CSC_SIM_CRANK_RPM_MIN                     20
+/* Simulated cadence upper limit */
+#define CSC_SIM_CRANK_RPM_MAX                     100
+/* Simulated speed lower limit */
+#define CSC_SIM_SPEED_KPH_MIN                     0
+/* Simulated speed upper limit */
+#define CSC_SIM_SPEED_KPH_MAX                     35
+
+/* Log data */
+struct log blecsc_log;
+
+/* Noticication status */
+static bool notify_state = false;
+
+/* Connection handle */
+static uint16_t conn_handle;
+
+static uint8_t blecsc_addr_type;
+
+/* Advertised device name  */
+static const char *device_name = "blecsc_sensor";
+
+/* Measurement and notification timer */
+static struct os_callout blecsc_measure_timer;
+
+/* Variable holds current CSC measurement state */
+static struct ble_csc_measurement_state csc_measurement_state;
+
+/* Variable holds simulted speed (kilometers per hour) */
+static uint16_t csc_sim_speed_kph = CSC_SIM_SPEED_KPH_MIN;
+
+/* Variable holds simulated cadence (RPM) */
+static uint8_t csc_sim_crank_rpm = CSC_SIM_CRANK_RPM_MIN;
+
+static int blecsc_gap_event(struct ble_gap_event *event, void *arg);
+
+
+/*
+ * Enables advertising with parameters:
+ *     o General discoverable mode
+ *     o Undirected connectable mode
+ */
+static void
+blecsc_advertise(void)
+{
+    struct ble_gap_adv_params adv_params;
+    struct ble_hs_adv_fields fields;
+    int rc;
+
+    /*
+     *  Set the advertisement data included in our advertisements:
+     *     o Flags (indicates advertisement type and other general info)
+     *     o Advertising tx power
+     *     o Device name
+     */
+    memset(&fields, 0, sizeof(fields));
+
+    /*
+     * Advertise two flags:
+     *      o Discoverability in forthcoming advertisement (general)
+     *      o BLE-only (BR/EDR unsupported)
+     */
+    fields.flags = BLE_HS_ADV_F_DISC_GEN |
+                   BLE_HS_ADV_F_BREDR_UNSUP;
+
+    /*
+     * Indicate that the TX power level field should be included; have the
+     * stack fill this value automatically.  This is done by assigning the
+     * special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
+     */
+    fields.tx_pwr_lvl_is_present = 1;
+    fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
+
+    fields.name = (uint8_t *)device_name;
+    fields.name_len = strlen(device_name);
+    fields.name_is_complete = 1;
+    
+    /*
+     * Set appearance.
+     */    
+    fields.appearance = ble_svc_gap_device_appearance();
+    fields.appearance_is_present = 1;
+
+    rc = ble_gap_adv_set_fields(&fields);
+    if (rc != 0) {
+        BLECSC_LOG(ERROR, "error setting advertisement data; rc=%d\n", rc);
+        return;
+    }
+
+    /* Begin advertising */
+    memset(&adv_params, 0, sizeof(adv_params));
+    adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
+    adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
+    rc = ble_gap_adv_start(blecsc_addr_type, NULL, BLE_HS_FOREVER,
+                           &adv_params, blecsc_gap_event, NULL);
+    if (rc != 0) {
+        BLECSC_LOG(ERROR, "error enabling advertisement; rc=%d\n", rc);
+        return;
+    }
+}
+
+
+/* Update simulated CSC measurements.
+ * Each call increments wheel and crank revolution counters by one and
+ * computes last event time in order to match simulated candence and speed.
+ * Last event time is expressedd in 1/1024th of second units.
+ *
+ *                 60 * 1024
+ * crank_dt =    --------------
+ *                cadence[RPM]
+ *
+ *
+ *                circumference[mm] * 1024 * 60 * 60
+ * wheel_dt =    -------------------------------------
+ *                         10^6 * speed [kph] 
+ */
+static void 
+blecsc_simulate_speed_and_cadence()
+{
+    uint16_t wheel_rev_period;
+    uint16_t crank_rev_period;
+
+    /* Update simulated crank and wheel rotation speed */
+    csc_sim_speed_kph++;
+    if (csc_sim_speed_kph >= CSC_SIM_SPEED_KPH_MAX) {
+         csc_sim_speed_kph = CSC_SIM_SPEED_KPH_MIN;
+    }
+    
+    csc_sim_crank_rpm++;
+    if (csc_sim_crank_rpm >= CSC_SIM_CRANK_RPM_MAX) {
+         csc_sim_crank_rpm = CSC_SIM_CRANK_RPM_MIN;
+    }
+    
+    /* Calculate simulated measurement values */
+    if (csc_sim_speed_kph > 0){
+        wheel_rev_period = (36*64*CSC_SIM_WHEEL_CIRCUMFERENCE_MM) / 
+                           (625*csc_sim_speed_kph);
+        csc_measurement_state.cumulative_wheel_rev++;
+        csc_measurement_state.last_wheel_evt_time += wheel_rev_period;
+    }
+    
+    if (csc_sim_crank_rpm > 0){
+        crank_rev_period = (60*1024) / csc_sim_crank_rpm;
+        csc_measurement_state.cumulative_crank_rev++;
+        csc_measurement_state.last_crank_evt_time += crank_rev_period; 
+    }    
+    
+    BLECSC_LOG(INFO, "CSC simulated values: speed = %d kph, cadence = %d \n",
+                    csc_sim_speed_kph, csc_sim_crank_rpm);  
+}
+
+/* Run CSC measurement simulation and notify it to the client */
+static void
+blecsc_measurement(struct os_event *ev)
+{
+    int rc;
+
+    rc = os_callout_reset(&blecsc_measure_timer, OS_TICKS_PER_SEC);
+    assert(rc == 0);    
+    
+    blecsc_simulate_speed_and_cadence();
+    
+    if (notify_state) {
+        rc = gatt_svr_chr_notify_csc_measurement(conn_handle);
+        assert(rc == 0);
+    }    
+}
+
+static int
+blecsc_gap_event(struct ble_gap_event *event, void *arg)
+{
+    switch (event->type) {
+    case BLE_GAP_EVENT_CONNECT:
+        /* A new connection was established or a connection attempt failed */
+        BLECSC_LOG(INFO, "connection %s; status=%d\n",
+                    event->connect.status == 0 ? "established" : "failed",
+                    event->connect.status);
+
+        if (event->connect.status != 0) {
+            /* Connection failed; resume advertising */
+            blecsc_advertise();
+            conn_handle = 0;
+        }
+        else {
+          conn_handle = event->connect.conn_handle;
+        }
+        break;
+
+    case BLE_GAP_EVENT_DISCONNECT:
+        BLECSC_LOG(INFO, "disconnect; reason=%d\n", event->disconnect.reason);
+        conn_handle = 0;
+        /* Connection terminated; resume advertising */
+        blecsc_advertise();
+        break;
+
+    case BLE_GAP_EVENT_ADV_COMPLETE:
+        BLECSC_LOG(INFO, "adv complete\n");
+        break;
+
+    case BLE_GAP_EVENT_SUBSCRIBE:
+        BLECSC_LOG(INFO, "subscribe event attr_handle=%d\n",
+                         event->subscribe.attr_handle);
+
+        if (event->subscribe.attr_handle == csc_measurement_handle) {
+            notify_state = event->subscribe.cur_notify;
+            BLECSC_LOG(INFO, "csc measurement notify state = %d\n",
+                              notify_state);
+        } 
+        else if (event->subscribe.attr_handle == csc_control_point_handle) {
+            gatt_svr_set_cp_indicate(event->subscribe.cur_indicate);
+            BLECSC_LOG(INFO, "csc control point indicate state = %d\n",
+                              event->subscribe.cur_indicate);            
+        }
+        break;
+
+    case BLE_GAP_EVENT_MTU:
+        BLECSC_LOG(INFO, "mtu update event; conn_handle=%d mtu=%d\n",
+                    event->mtu.conn_handle,
+                    event->mtu.value);
+        break;
+
+    }
+
+    return 0;
+}
+
+static void
+blecsc_on_sync(void)
+{
+    int rc;
+
+    /* Figure out address to use while advertising (no privacy) */
+    rc = ble_hs_id_infer_auto(0, &blecsc_addr_type);
+    assert(rc == 0);
+
+    /* Begin advertising */
+    blecsc_advertise();
+}
+
+/*
+ * main
+ *
+ * The main task for the project. This function initializes the packages,
+ * then starts serving events from default event queue.
+ *
+ * @return int NOTE: this function should never return!
+ */
+int
+main(void)
+{
+    int rc;
+
+    /* Initialize OS */
+    sysinit();
+
+    /* Initialize the blecsc log */
+    log_register("blecsc_sens_log", &blecsc_log, &log_console_handler, NULL,
+                    LOG_SYSLEVEL);
+
+    /* Initialize the NimBLE host configuration */
+    log_register("blecsc_sens", &ble_hs_log, &log_console_handler, NULL,
+                    LOG_SYSLEVEL);
+    ble_hs_cfg.sync_cb = blecsc_on_sync;
+
+    /* Initialize measurement and notification timer */
+    os_callout_init(&blecsc_measure_timer, os_eventq_dflt_get(),
+                    blecsc_measurement, NULL);
+    rc = os_callout_reset(&blecsc_measure_timer, OS_TICKS_PER_SEC);
+    assert(rc == 0); 
+
+    rc = gatt_svr_init(&csc_measurement_state);
+    assert(rc == 0);
+
+    /* Set the default device name */
+    rc = ble_svc_gap_device_name_set(device_name);
+    assert(rc == 0);
+
+    /* As the last thing, process events from default event queue */
+    while (1) {
+        os_eventq_run(os_eventq_dflt_get());
+    }
+    return 0;
+}
+
diff --git a/apps/blecsc/syscfg.yml b/apps/blecsc/syscfg.yml
new file mode 100644
index 000000000..0b4651faf
--- /dev/null
+++ b/apps/blecsc/syscfg.yml
@@ -0,0 +1,38 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+
+syscfg.vals:
+    # Disable central and observer roles.
+    BLE_ROLE_BROADCASTER: 1
+    BLE_ROLE_CENTRAL: 0
+    BLE_ROLE_OBSERVER: 0
+    BLE_ROLE_PERIPHERAL: 1
+
+    # Disable unused eddystone feature.
+    BLE_EDDYSTONE: 0
+
+    # Log reboot messages to a flash circular buffer.
+    REBOOT_LOG_FCB: 1
+    LOG_FCB: 1
+    CONFIG_FCB: 1
+
+    # Set public device address.
+    BLE_PUBLIC_DEV_ADDR: ((uint8_t[6]){0xcc, 0xbb, 0xaa, 0x33, 0x22, 0x11})
+    
+    # Set device appearance to Cycling Speed and Cadence Sensor
+    BLE_SVC_GAP_APPEARANCE: BLE_SVC_GAP_APPEARANCE_CYC_SPEED_AND_CADENCE_SENSOR
diff --git a/net/nimble/host/services/gap/include/services/gap/ble_svc_gap.h 
b/net/nimble/host/services/gap/include/services/gap/ble_svc_gap.h
index cb8d62593..7f8a8e7e8 100644
--- a/net/nimble/host/services/gap/include/services/gap/ble_svc_gap.h
+++ b/net/nimble/host/services/gap/include/services/gap/ble_svc_gap.h
@@ -33,10 +33,13 @@ struct ble_hs_cfg;
 #define BLE_SVC_GAP_CHR_UUID16_RECONNECT_ADDR               0x2a03
 #define BLE_SVC_GAP_CHR_UUID16_PERIPH_PREF_CONN_PARAMS      0x2a04
 
-#define BLE_SVC_GAP_APPEARANCE_GEN_COMPUTER                 128
+#define BLE_SVC_GAP_APPEARANCE_GEN_UNKNOWN                         0
+#define BLE_SVC_GAP_APPEARANCE_GEN_COMPUTER                        128
+#define BLE_SVC_GAP_APPEARANCE_CYC_SPEED_AND_CADENCE_SENSOR        1157        
  
 
 const char *ble_svc_gap_device_name(void);
 int ble_svc_gap_device_name_set(const char *name);
+uint16_t ble_svc_gap_device_appearance(void);
 
 void ble_svc_gap_init(void);
 
diff --git a/net/nimble/host/services/gap/src/ble_svc_gap.c 
b/net/nimble/host/services/gap/src/ble_svc_gap.c
index 87de6fb1e..0ca195e83 100644
--- a/net/nimble/host/services/gap/src/ble_svc_gap.c
+++ b/net/nimble/host/services/gap/src/ble_svc_gap.c
@@ -23,12 +23,16 @@
 #include "sysinit/sysinit.h"
 #include "host/ble_hs.h"
 #include "services/gap/ble_svc_gap.h"
+#include "os/endian.h"
 
 /* XXX: This should be configurable. */
 #define BLE_SVC_GAP_NAME_MAX_LEN    31
 
 static char ble_svc_gap_name[BLE_SVC_GAP_NAME_MAX_LEN + 1] = "nimble";
-static uint16_t ble_svc_gap_appearance;
+static const uint8_t ble_svc_gap_appearance[2] = {
+     (MYNEWT_VAL(BLE_SVC_GAP_APPEARANCE)) & 0xFF,
+     ((MYNEWT_VAL(BLE_SVC_GAP_APPEARANCE)) >> 8) & 0xFF
+};
 static uint8_t ble_svc_gap_privacy_flag;
 static uint8_t ble_svc_gap_reconnect_addr[6];
 static uint8_t ble_svc_gap_pref_conn_params[8];
@@ -150,6 +154,12 @@ ble_svc_gap_device_name_set(const char *name)
     return 0;
 }
 
+uint16_t
+ble_svc_gap_device_appearance(void)
+{
+  return get_le16(ble_svc_gap_appearance);
+}
+
 void
 ble_svc_gap_init(void)
 {
diff --git a/net/nimble/host/services/gap/syscfg.yml 
b/net/nimble/host/services/gap/syscfg.yml
new file mode 100644
index 000000000..f686e6762
--- /dev/null
+++ b/net/nimble/host/services/gap/syscfg.yml
@@ -0,0 +1,24 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Package: net/nimble/host/services/gap
+
+syscfg.defs:
+    BLE_SVC_GAP_APPEARANCE:
+        description: 'Device appearance'
+        value: 0


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to