1 /* 2 * Copyright (C) 2018 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 /** 39 * @title Cycling Power Service Server 40 * 41 */ 42 43 #ifndef CYCLING_POWER_SERVICE_SERVER_H 44 #define CYCLING_POWER_SERVICE_SERVER_H 45 46 #include <stdint.h> 47 48 #if defined __cplusplus 49 extern "C" { 50 #endif 51 52 /** 53 * @text The Cycling Power Service allows to query device's power- and 54 * force-related data and optionally speed- and cadence-related data for 55 * use in sports and fitness applications. 56 * 57 * To use with your application, add `#import <cycling_power_service.gatt>` 58 * to your .gatt file. 59 */ 60 61 /* API_START */ 62 #define CYCLING_POWER_MANUFACTURER_SPECIFIC_DATA_MAX_SIZE 16 63 64 typedef enum { 65 CP_PEDAL_POWER_BALANCE_REFERENCE_UNKNOWN = 0, 66 CP_PEDAL_POWER_BALANCE_REFERENCE_LEFT, 67 CP_PEDAL_POWER_BALANCE_REFERENCE_NOT_SUPPORTED 68 } cycling_power_pedal_power_balance_reference_t; 69 70 typedef enum { 71 CP_TORQUE_SOURCE_WHEEL = 0, 72 CP_TORQUE_SOURCE_CRANK, 73 CP_TORQUE_SOURCE_NOT_SUPPORTED 74 } cycling_power_torque_source_t; 75 76 typedef enum { 77 CP_SENSOR_MEASUREMENT_CONTEXT_FORCE = 0, 78 CP_SENSOR_MEASUREMENT_CONTEXT_TORQUE 79 } cycling_power_sensor_measurement_context_t; 80 81 typedef enum { 82 CP_DISTRIBUTED_SYSTEM_UNSPECIFIED = 0, 83 CP_DISTRIBUTED_SYSTEM_NOT_SUPPORTED, 84 CP_DISTRIBUTED_SYSTEM_SUPPORTED 85 } cycling_power_distributed_system_t; 86 87 typedef enum { 88 CP_MEASUREMENT_FLAG_PEDAL_POWER_BALANCE_PRESENT = 0, 89 CP_MEASUREMENT_FLAG_PEDAL_POWER_BALANCE_REFERENCE, // 0 - unknown, 1 - left 90 CP_MEASUREMENT_FLAG_ACCUMULATED_TORQUE_PRESENT, 91 CP_MEASUREMENT_FLAG_ACCUMULATED_TORQUE_SOURCE, // 0 - wheel based, 1 - crank based 92 CP_MEASUREMENT_FLAG_WHEEL_REVOLUTION_DATA_PRESENT, 93 CP_MEASUREMENT_FLAG_CRANK_REVOLUTION_DATA_PRESENT, 94 CP_MEASUREMENT_FLAG_EXTREME_FORCE_MAGNITUDES_PRESENT, 95 CP_MEASUREMENT_FLAG_EXTREME_TORQUE_MAGNITUDES_PRESENT, 96 CP_MEASUREMENT_FLAG_EXTREME_ANGLES_PRESENT, 97 CP_MEASUREMENT_FLAG_TOP_DEAD_SPOT_ANGLE_PRESENT, 98 CP_MEASUREMENT_FLAG_BOTTOM_DEAD_SPOT_ANGLE_PRESENT, 99 CP_MEASUREMENT_FLAG_ACCUMULATED_ENERGY_PRESENT, 100 CP_MEASUREMENT_FLAG_OFFSET_COMPENSATION_INDICATOR, 101 CP_MEASUREMENT_FLAG_RESERVED 102 } cycling_power_measurement_flag_t; 103 104 typedef enum { 105 CP_INSTANTANEOUS_MEASUREMENT_DIRECTION_UNKNOWN = 0, 106 CP_INSTANTANEOUS_MEASUREMENT_DIRECTION_TANGENTIAL_COMPONENT, 107 CP_INSTANTANEOUS_MEASUREMENT_DIRECTION_RADIAL_COMPONENT, 108 CP_INSTANTANEOUS_MEASUREMENT_DIRECTION_LATERAL_COMPONENT 109 } cycling_power_instantaneous_measurement_direction_t; 110 111 typedef enum { 112 CP_VECTOR_FLAG_CRANK_REVOLUTION_DATA_PRESENT = 0, 113 CP_VECTOR_FLAG_FIRST_CRANK_MEASUREMENT_ANGLE_PRESENT, 114 CP_VECTOR_FLAG_INSTANTANEOUS_FORCE_MAGNITUDE_ARRAY_PRESENT, 115 CP_VECTOR_FLAG_INSTANTANEOUS_TORQUE_MAGNITUDE_ARRAY_PRESENT, 116 CP_VECTOR_FLAG_INSTANTANEOUS_MEASUREMENT_DIRECTION = 4, // 2 bit 117 CP_VECTOR_FLAG_RESERVED = 6 118 } cycling_power_vector_flag_t; 119 120 typedef enum { 121 CP_SENSOR_LOCATION_OTHER, 122 CP_SENSOR_LOCATION_TOP_OF_SHOE, 123 CP_SENSOR_LOCATION_IN_SHOE, 124 CP_SENSOR_LOCATION_HIP, 125 CP_SENSOR_LOCATION_FRONT_WHEEL, 126 CP_SENSOR_LOCATION_LEFT_CRANK, 127 CP_SENSOR_LOCATION_RIGHT_CRANK, 128 CP_SENSOR_LOCATION_LEFT_PEDAL, 129 CP_SENSOR_LOCATION_RIGHT_PEDAL, 130 CP_SENSOR_LOCATION_FRONT_HUB, 131 CP_SENSOR_LOCATION_REAR_DROPOUT, 132 CP_SENSOR_LOCATION_CHAINSTAY, 133 CP_SENSOR_LOCATION_REAR_WHEEL, 134 CP_SENSOR_LOCATION_REAR_HUB, 135 CP_SENSOR_LOCATION_CHEST, 136 CP_SENSOR_LOCATION_SPIDER, 137 CP_SENSOR_LOCATION_CHAIN_RING, 138 CP_SENSOR_LOCATION_RESERVED 139 } cycling_power_sensor_location_t; 140 141 typedef enum { 142 CP_FEATURE_FLAG_PEDAL_POWER_BALANCE_SUPPORTED = 0, 143 CP_FEATURE_FLAG_ACCUMULATED_TORQUE_SUPPORTED, 144 CP_FEATURE_FLAG_WHEEL_REVOLUTION_DATA_SUPPORTED, 145 CP_FEATURE_FLAG_CRANK_REVOLUTION_DATA_SUPPORTED, 146 CP_FEATURE_FLAG_EXTREME_MAGNITUDES_SUPPORTED, 147 CP_FEATURE_FLAG_EXTREME_ANGLES_SUPPORTED, 148 CP_FEATURE_FLAG_TOP_AND_BOTTOM_DEAD_SPOT_ANGLE_SUPPORTED, 149 CP_FEATURE_FLAG_ACCUMULATED_ENERGY_SUPPORTED, 150 CP_FEATURE_FLAG_OFFSET_COMPENSATION_INDICATOR_SUPPORTED, 151 CP_FEATURE_FLAG_OFFSET_COMPENSATION_SUPPORTED, 152 CP_FEATURE_FLAG_CYCLING_POWER_MEASUREMENT_CHARACTERISTIC_CONTENT_MASKING_SUPPORTED, 153 CP_FEATURE_FLAG_MULTIPLE_SENSOR_LOCATIONS_SUPPORTED, 154 CP_FEATURE_FLAG_CRANK_LENGTH_ADJUSTMENT_SUPPORTED, 155 CP_FEATURE_FLAG_CHAIN_LENGTH_ADJUSTMENT_SUPPORTED, 156 CP_FEATURE_FLAG_CHAIN_WEIGHT_ADJUSTMENT_SUPPORTED, 157 CP_FEATURE_FLAG_SPAN_LENGTH_ADJUSTMENT_SUPPORTED, 158 CP_FEATURE_FLAG_SENSOR_MEASUREMENT_CONTEXT, // 0-force based, 1-torque based 159 CP_FEATURE_FLAG_INSTANTANEOUS_MEASUREMENT_DIRECTION_SUPPORTED, 160 CP_FEATURE_FLAG_FACTORY_CALIBRATION_DATE_SUPPORTED, 161 CP_FEATURE_FLAG_ENHANCED_OFFSET_COMPENSATION_SUPPORTED, 162 CP_FEATURE_FLAG_DISTRIBUTED_SYSTEM_SUPPORT = 20, // 0-unspecified, 1-not for use in distr. system, 2-used in distr. system, 3-reserved 163 CP_FEATURE_FLAG_RESERVED = 22 164 } cycling_power_feature_flag_t; 165 166 typedef enum { 167 CP_CALIBRATION_STATUS_INCORRECT_CALIBRATION_POSITION = 0x01, 168 CP_CALIBRATION_STATUS_MANUFACTURER_SPECIFIC_ERROR_FOLLOWS = 0xFF 169 } cycling_power_calibration_status_t; 170 171 172 /** 173 * @brief Init Server with ATT DB 174 * 175 * @param feature_flags 176 * @param pedal_power_balance_reference 177 * @param torque_source 178 * @param supported_sensor_locations 179 * @param num_supported_sensor_locations 180 * @param current_sensor_location 181 */ 182 void cycling_power_service_server_init(uint32_t feature_flags, 183 cycling_power_pedal_power_balance_reference_t pedal_power_balance_reference, cycling_power_torque_source_t torque_source, 184 cycling_power_sensor_location_t * supported_sensor_locations, uint16_t num_supported_sensor_locations, 185 cycling_power_sensor_location_t current_sensor_location); 186 187 /** 188 * @brief Setup measurement as advertisement data 189 * @param adv_interval 190 * @param adv_buffer 191 * @param adv_size 192 * @return 193 */ 194 int cycling_power_get_measurement_adv(uint16_t adv_interval, uint8_t * adv_buffer, uint16_t adv_size); 195 196 /** 197 * @brief Register callback for the calibration and broadcast updates. 198 * 199 * @param callback 200 */ 201 void cycling_power_service_server_packet_handler(btstack_packet_handler_t callback); 202 203 /** 204 * @brief Report calibration done. 205 * @param measurement_type 206 * @param calibrated_value 207 */ 208 void cycling_power_server_calibration_done(cycling_power_sensor_measurement_context_t measurement_type, uint16_t calibrated_value); 209 210 /** 211 * @brief Report enhanced calibration done. 212 * 213 * @param measurement_type 214 * @param calibrated_value 215 * @param manufacturer_company_id 216 * @param num_manufacturer_specific_data 217 * @param manufacturer_specific_data 218 */ 219 void cycling_power_server_enhanced_calibration_done(cycling_power_sensor_measurement_context_t measurement_type, 220 uint16_t calibrated_value, uint16_t manufacturer_company_id, 221 uint8_t num_manufacturer_specific_data, uint8_t * manufacturer_specific_data); 222 223 /** 224 * @brief Set factory calibration date. 225 * @param date 226 * @return 1 if successful 227 */ 228 int cycling_power_service_server_set_factory_calibration_date(gatt_date_time_t date); 229 230 /** 231 * @brief Set sampling rate. 232 * @param sampling_rate_Hz 233 */ 234 void cycling_power_service_server_set_sampling_rate(uint8_t sampling_rate_Hz); 235 236 /** 237 * @brief Accumulate torque value. 238 * @param torque_Nm 239 */ 240 void cycling_power_service_server_add_torque(int16_t torque_Nm); 241 242 /** 243 * @brief Accumulate wheel revolution value and set the time of the last measurement. 244 * @param wheel_revolution 245 * @param wheel_event_time_s unit: seconds 246 */ 247 void cycling_power_service_server_add_wheel_revolution(int32_t wheel_revolution, uint16_t wheel_event_time_s); 248 249 /** 250 * @brief Accumulate crank revolution value and set the time of the last measurement. 251 * @param crank_revolution 252 * @param crank_event_time_s unit: seconds 253 */ 254 void cycling_power_service_server_add_crank_revolution(uint16_t crank_revolution, uint16_t crank_event_time_s); 255 256 /** 257 * @brief Accumulate energy. 258 * @param energy_kJ unit: kilo Joule 259 */ 260 void cycling_power_service_add_energy(uint16_t energy_kJ); 261 262 /** 263 * @brief Set the value of the power. The Instantaneous Power field represents either 264 * the total power the user is producing or a part of the total power depending on the 265 * type of sensor (e.g., single sensor or distributed power sensor system). 266 * 267 * @param instantaneous_power_W unit: watt 268 */ 269 void cycling_power_service_server_set_instantaneous_power(int16_t instantaneous_power_W); 270 271 /** 272 * @brief Set the pedal power balance value. The Pedal Power Balance field represents the ratio between 273 * the total amount of power measured by the sensor and a reference (either unknown or left). 274 * 275 * @param pedal_power_balance_percentage 276 */ 277 void cycling_power_service_server_set_pedal_power_balance(uint8_t pedal_power_balance_percentage); 278 279 /** 280 * @brief Set the minimum and maximum force value measured in a single crank revolution. 281 * 282 * This, so called, Extreme Force Magnitude field pair will be included in the Cycling Power Measurement 283 * characteristic only if the device supports the Extreme Magnitudes feature and 284 * the Sensor Measurement Context of the Cycling Power Feature characteristic is set to 0 (Force-based). 285 * 286 * @param min_force_magnitude_N unit: newton 287 * @param max_force_magnitude_N unit: newton 288 */ 289 void cycling_power_service_server_set_force_magnitude(int16_t min_force_magnitude_N, int16_t max_force_magnitude_N); 290 291 /** 292 * @brief Set the minimum and maximum torque value measured in a single crank revolution. 293 * 294 * This, so called, Extreme Torque Magnitude field pair will be included in the Cycling Power Measurement 295 * characteristic only if the device supports the Extreme Magnitudes feature and 296 * the Sensor Measurement Context of the Cycling Power Feature characteristic is set to 1 (Torque-based). 297 * 298 * @param min_torque_magnitude_Nm unit: newton meter 299 * @param max_torque_magnitude_Nm unit: newton meter 300 */ 301 void cycling_power_service_server_set_torque_magnitude(int16_t min_torque_magnitude_Nm, int16_t max_torque_magnitude_Nm); 302 303 /** 304 * @brief Set the minimum and maximum angle of the crank measured in a single crank revolution (unit: degree). 305 * 306 * This, so called, Extreme Angles Magnitude field pair will be included in the Cycling Power Measurement 307 * characteristic only if the device supports the Extreme Angles feature. 308 * 309 * @param min_angle_degree 310 * @param max_angle_degree 311 */ 312 void cycling_power_service_server_set_angle(uint16_t min_angle_degree, uint16_t max_angle_degree); 313 314 /** 315 * @brief Set the value of the crank angle measured when the value of the Instantaneous Power value becomes positive. 316 * 317 * This field will be included in the Cycling Power Measurement characteristic 318 * only if the device supports the Top and Bottom Dead Spot Angles feature. 319 * 320 * @param top_dead_spot_angle_degree 321 */ 322 void cycling_power_service_server_set_top_dead_spot_angle(uint16_t top_dead_spot_angle_degree); 323 324 /** 325 * @brief Set the value of the crank angle measured when the value of the Instantaneous Power value becomes negative. 326 * 327 * This field will be included in the Cycling Power Measurement characteristic 328 * only if the device supports the Top and Bottom Dead Spot Angles feature. 329 * 330 * @param bottom_dead_spot_angle_degree 331 */ 332 void cycling_power_service_server_set_bottom_dead_spot_angle(uint16_t bottom_dead_spot_angle_degree); 333 334 /** 335 * @brief Set the raw sensor force magnitude measurements. 336 * 337 * @param force_magnitude_count 338 * @param force_magnitude_N_array unit: newton 339 */ 340 void cycling_power_service_server_set_force_magnitude_values(int force_magnitude_count, int16_t * force_magnitude_N_array); 341 342 /** 343 * @brief Set the raw sensor torque magnitude measurements. 344 * 345 * @param force_magnitude_count 346 * @param force_magnitude_N_array unit: newton meter 347 */ 348 void cycling_power_service_server_set_torque_magnitude_values(int torque_magnitude_count, int16_t * torque_magnitude_Nm_array); 349 350 /** 351 * @brief Set the instantaneous measurement direction. The field describes 352 * the direction of the Instantaneous Magnitude values the Server measures 353 * (e.g., Unknown, Tangential Component, Radial Component, or Lateral Component). 354 * 355 * @param direction 356 */ 357 void cycling_power_service_server_set_instantaneous_measurement_direction(cycling_power_instantaneous_measurement_direction_t direction); 358 359 /** 360 * Set first crank measurement angle. The value will be present only in the first packet of 361 * the Cycling Power Vector notification. 362 * 363 * @param first_crank_measurement_angle_degree 364 */ 365 void cycling_power_service_server_set_first_crank_measurement_angle(uint16_t first_crank_measurement_angle_degree); 366 367 /** 368 * Get measurement flags bitmask. 369 * @return measurement_flags_bitmask, see cycling_power_measurement_flag_t 370 */ 371 uint16_t cycling_power_service_measurement_flags(void); 372 373 /** 374 * Get vector flags bitmask. 375 * @return vector_flags_bitmask, see cycling_power_vector_flag_t 376 */ 377 uint8_t cycling_power_service_vector_flags(void); 378 379 /** 380 * @brief Trigger notification if subscribed 381 */ 382 void cycling_power_service_server_update_values(void); 383 384 /* API_END */ 385 386 #if defined __cplusplus 387 } 388 #endif 389 390 #endif 391 392