From bdc10744fb338ae197692713a0b48a7ccc36f566 Mon Sep 17 00:00:00 2001 From: JF Date: Sun, 26 Apr 2020 10:25:59 +0200 Subject: Add Nimble in libs directory --- src/libs/mynewt-nimble/apps/blecsc/README.md | 9 + src/libs/mynewt-nimble/apps/blecsc/pkg.yml | 40 +++ .../mynewt-nimble/apps/blecsc/src/blecsc_sens.h | 105 ++++++ src/libs/mynewt-nimble/apps/blecsc/src/gatt_svr.c | 385 +++++++++++++++++++++ src/libs/mynewt-nimble/apps/blecsc/src/main.c | 310 +++++++++++++++++ src/libs/mynewt-nimble/apps/blecsc/syscfg.yml | 38 ++ 6 files changed, 887 insertions(+) create mode 100644 src/libs/mynewt-nimble/apps/blecsc/README.md create mode 100644 src/libs/mynewt-nimble/apps/blecsc/pkg.yml create mode 100644 src/libs/mynewt-nimble/apps/blecsc/src/blecsc_sens.h create mode 100644 src/libs/mynewt-nimble/apps/blecsc/src/gatt_svr.c create mode 100644 src/libs/mynewt-nimble/apps/blecsc/src/main.c create mode 100644 src/libs/mynewt-nimble/apps/blecsc/syscfg.yml (limited to 'src/libs/mynewt-nimble/apps/blecsc') diff --git a/src/libs/mynewt-nimble/apps/blecsc/README.md b/src/libs/mynewt-nimble/apps/blecsc/README.md new file mode 100644 index 00000000..bccf176a --- /dev/null +++ b/src/libs/mynewt-nimble/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/src/libs/mynewt-nimble/apps/blecsc/pkg.yml b/src/libs/mynewt-nimble/apps/blecsc/pkg.yml new file mode 100644 index 00000000..828ff301 --- /dev/null +++ b/src/libs/mynewt-nimble/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: "mjurczak@gmail.com" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + +pkg.deps: + - "@apache-mynewt-core/kernel/os" + - "@apache-mynewt-core/sys/console/full" + - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/log/modlog" + - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/sysinit" + - "@apache-mynewt-core/sys/id" + - nimble/controller + - nimble/host + - nimble/host/services/gap + - nimble/host/services/gatt + - nimble/host/store/config + - nimble/transport diff --git a/src/libs/mynewt-nimble/apps/blecsc/src/blecsc_sens.h b/src/libs/mynewt-nimble/apps/blecsc/src/blecsc_sens.h new file mode 100644 index 00000000..99addc0f --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blecsc/src/blecsc_sens.h @@ -0,0 +1,105 @@ +/* + * 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 "modlog/modlog.h" +#include "nimble/ble.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* 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/src/libs/mynewt-nimble/apps/blecsc/src/gatt_svr.c b/src/libs/mynewt-nimble/apps/blecsc/src/gatt_svr.c new file mode 100644 index 00000000..e66aa9a8 --- /dev/null +++ b/src/libs/mynewt-nimble/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 +#include +#include +#include "os/mynewt.h" +#include "host/ble_hs.h" +#include "host/ble_uuid.h" +#include "blecsc_sens.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) { + MODLOG_DFLT(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; + } + MODLOG_DFLT(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); + + MODLOG_DFLT(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; + } + + MODLOG_DFLT(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: + MODLOG_DFLT(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: + MODLOG_DFLT(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: + MODLOG_DFLT(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/src/libs/mynewt-nimble/apps/blecsc/src/main.c b/src/libs/mynewt-nimble/apps/blecsc/src/main.c new file mode 100644 index 00000000..60f0b3d8 --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blecsc/src/main.c @@ -0,0 +1,310 @@ +/* + * 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 +#include +#include +#include + +#include "os/mynewt.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 + +/* 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) { + MODLOG_DFLT(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) { + MODLOG_DFLT(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(void) +{ + 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; + } + + MODLOG_DFLT(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 */ + MODLOG_DFLT(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: + MODLOG_DFLT(INFO, "disconnect; reason=%d\n", event->disconnect.reason); + conn_handle = 0; + /* Connection terminated; resume advertising */ + blecsc_advertise(); + break; + + case BLE_GAP_EVENT_ADV_COMPLETE: + MODLOG_DFLT(INFO, "adv complete\n"); + break; + + case BLE_GAP_EVENT_SUBSCRIBE: + MODLOG_DFLT(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; + MODLOG_DFLT(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); + MODLOG_DFLT(INFO, "csc control point indicate state = %d\n", + event->subscribe.cur_indicate); + } + break; + + case BLE_GAP_EVENT_MTU: + MODLOG_DFLT(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 NimBLE host configuration */ + 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/src/libs/mynewt-nimble/apps/blecsc/syscfg.yml b/src/libs/mynewt-nimble/apps/blecsc/syscfg.yml new file mode 100644 index 00000000..2f41785b --- /dev/null +++ b/src/libs/mynewt-nimble/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 -- cgit v1.2.3