/** ***************************************************************************************** * Copyright(c) 2017, Realtek Semiconductor Corporation. All rigbcs reserved. ***************************************************************************************** * @file bcs.h * @brief Variables and interfaces for using Body Composition Service. * @details Body Composition Service data structs and functions. * @author * @date 2017-09-20 * @version v1.0 * ************************************************************************************* */ /* define to prevent recursive inclusion */ #ifndef _BCS_H_ #define _BCS_H_ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* Add Includes here */ #include "stdint.h" #include "profile_server.h" #include "rtl876x.h" /** @defgroup BCS Body Composition Service * @brief Body Composition service * @details The Body Composition service exposes data related to body composition from a body composition analyzer intended for consumer healthcare and sports/fitness applications. Application shall register Body Composition service when initialization through @ref bcs_add_service function. The Body Composition Feature characteristic shall be used to describe the supported features of the Server. Application can set a body composition feature through @ref bcs_set_parameter function. The Body Composition Measurement characteristic is used to send body composition-related data to the Client. for display purposes while the measurement is in progress. Application can send body composition measurement values through @ref bcs_body_composition_measurement_value_indicate function. * @{ */ /*============================================================================* * Macros *============================================================================*/ /** @defgroup BCS_Exported_Macros BCS Exported Macros * @brief * @{ */ #define GATT_UUID_BODY_COMPOSITION 0x181B #define GATT_UUID_CHAR_BODY_COMPOSITION_FEATURE 0x2A9B #define GATT_UUID_CHAR_BODY_COMPOSITION_MEASUREMENT 0x2A9C /** @brief The Maximum Length of Body Composition Measurement Value*/ #define BCS_MEASUREMENT_VALUE_MAX_LEN 30 /** * @brief Body Composition Feature field bit 11 to 14 * bcs_Weight_measurement_resolution_bit */ #define BCS_FEATURE_WEIGHT_MEAS_RES_NOT_SPECIFIED 0x00 #define BCS_FEATURE_WEIGHT_MEAS_RES_0_5_KG_OR_1_LB 0x01 #define BCS_FEATURE_WEIGHT_MEAS_RES_0_2_KG_OR_0_5_LB 0x02 #define BCS_FEATURE_WEIGHT_MEAS_RES_0_1_KG_OR_0_2_LB 0x03 #define BCS_FEATURE_WEIGHT_MEAS_RES_0_05_KG_OR_0_1_LB 0x04 #define BCS_FEATURE_WEIGHT_MEAS_RES_0_02_KG_OR_0_05_LB 0x05 #define BCS_FEATURE_WEIGHT_MEAS_RES_0_01_KG_OR_0_02_LB 0x06 #define BCS_FEATURE_WEIGHT_MEAS_RES_0_005_KG_OR_0_01_LB 0x07 /** * @brief Body Composition Feature field bit 15 to 17 * bcs_height_measurement_resolution_bit */ #define BCS_FEATURE_HEIGHT_MEAS_RES_NOT_SPECIFIED 0x00 #define BCS_FEATURE_HEIGHT_MEAS_RES_0_01_METER_OR_1_INCH 0x01 #define BCS_FEATURE_WEIGHT_MEAS_RES_0_005_METER_OR_5_INCH 0x02 #define BCS_FEATURE_WEIGHT_MEAS_RES_0_001_METER_OR_0_1_INCH 0x03 /** @defgroup BCS_Notify_Indicate_Info BCS Notify Indicate Info * @brief Parameter for enable or disable notification or indication. * @{ */ #define BCS_INDICATE_BODY_COMPOSITIONT_MEASUREMENT_ENABLE 1 #define BCS_INDICATE_BODY_COMPOSITIONT_MEASUREMENT_DISABLE 2 /** @} */ /** * @brief Body Composition Measurement flags field * bcs_measurement_units_bit */ #define BCS_MEASUREMENT_UNITS_SI 0 /* Weight and Mass in units of kilogram (kg) and Height in units of meter */ #define BCS_MEASUREMENT_UNITS_IMPERIAL 1 /* Weight and Mass in units of pound (lb) and Height in units of inch (in) */ #define BCS_MEASUREMENT_BODY_FAT_PCT_UNSUCCESS 0xffff /* body_fat_percentage field: measurement unsuccessful */ #define BCS_MEASUREMENT_USER_ID_UNKNOW 0xff /* user_id field: unknown user */ /** End of BCS_Exported_Macros * @} */ /*============================================================================* * Types *============================================================================*/ /** @defgroup BCS_Exported_Types BCS Exported Types * @brief * @{ */ /** * @brief Body Composition parameter type */ typedef enum { BCS_PARAM_BODY_COMPOSITION_FEATURE } T_BCS_PARAM_TYPE; /** * @brief Body Composition Feature */ typedef struct { uint32_t bcs_feature_time_stamp_support_bit: 1; uint32_t bcs_feature_multiple_users_support_bit: 1; uint32_t bcs_feature_basal_metabolism_support_bit: 1; uint32_t bcs_feature_muscle_percentage_support_bit: 1; uint32_t bcs_feature_muscle_mass_support_bit: 1; uint32_t bcs_feature_fat_free_mass_support_bit: 1; uint32_t bcs_feature_soft_lean_mass_support_bit: 1; uint32_t bcs_feature_body_water_mass_support_bit: 1; uint32_t bcs_feature_impedance_support_bit: 1; uint32_t bcs_feature_weight_support_bit: 1; uint32_t bcs_feature_height_support_bit: 1; uint32_t bcs_weight_measurement_resolution_bit: 4; uint32_t bcs_height_measurement_resolution_bit: 3; uint32_t rfu: 14; } T_BODY_COMPOSITION_FEATURE; /** * @brief Body Composition Measurement Flag */ typedef struct { uint16_t bcs_measurement_units_bit: 1; uint16_t bcs_time_stamp_present_bit: 1; uint16_t bcs_user_id_bit: 1; uint16_t bcs_basal_metabolism_present_bit: 1; uint16_t bcs_muscle_percentage_present_bit: 1; uint16_t bcs_muscle_mass_present_bit: 1; uint16_t bcs_fat_free_mass_present_bit: 1; uint16_t bcs_soft_lean_mass_present_bit: 1; uint16_t bcs_body_water_mass_present_bit: 1; uint16_t bcs_impedance_present_bit: 1; uint16_t bcs_weight_present_bit: 1; uint16_t bcs_height_present_bit: 1; uint16_t bcs_multiple_packet_measurement_bit: 1; uint16_t rfu: 3; } T_BODY_COMPOSITION_MEASUREMENT_FLAG; typedef struct { uint16_t year; uint8_t month; uint8_t day; uint8_t hours; uint8_t minutes; uint8_t seconds; } T_BCS_TIME_STAMP; typedef struct { T_BODY_COMPOSITION_MEASUREMENT_FLAG bcs_measurement_flag; uint16_t body_fat_percentage; T_BCS_TIME_STAMP time_stamp; uint8_t user_id; uint16_t basal_metabolism; uint16_t muscle_percentage; uint16_t muscle_mass; uint16_t fat_free_mass; uint16_t soft_lean_mass; uint16_t body_water_mass; uint16_t impedance; uint16_t weight; uint16_t height; } T_BCS_BODY_COMPOSITION_MEASUREMENT; /** * @brief Body Composition service upper stream message data */ typedef union { uint8_t notification_indification_index; uint8_t read_value_index; } T_BCS_UPSTREAM_MSG_DATA; /** * @brief Body Composition service callback data */ typedef struct { uint8_t conn_id; T_SERVICE_CALLBACK_TYPE msg_type; T_BCS_UPSTREAM_MSG_DATA msg_data; } T_BCS_CALLBACK_DATA; /** End of BCS_Exported_Types * @} */ /*============================================================================* * Functions *============================================================================*/ /** @defgroup BCS_Exported_Functions BCS Exported Functions * @brief * @{ */ /** * @brief Add body composition service to the BLE stack database. * * * @param[in] p_func Callback when service attribute was read, write or cccd update. * @return Service id generated by the BLE stack: @ref T_SERVER_ID. * @retval 0xFF Operation failure. * @retval others Service id assigned by stack. * * Example usage * \code{.c} void profile_init() { server_init(1); bcs_id = bcs_add_service(app_handle_profile_message); } * \endcode */ uint8_t bcs_add_service(void *p_func); /** * @brief Set a body composition service parameter. * * NOTE: You can call this function with a body composition service parameter type and it will set the * body composition service parameter. Body Composition service parameters are defined * in @ref T_BCS_PARAM_TYPE. * If the "len" field sets to the size of a "uint16_t", the * "p_value" field must point to a data with type of "uint16_t". * * @param[in] param_type Body composition service parameter type: @ref T_BCS_PARAM_TYPE * @param[in] len Length of data to write * @param[in] p_value Pointer to data to write. This is dependent on * the parameter type and WILL be cast to the appropriate * data type (For example: if data type of param is uint16_t, p_value will be cast to * pointer of uint16_t). * * @return Operation result. * @retval true Operation success. * @retval false Operation failure. * * Example usage * \code{.c} void test(void) { uint32_t bcs_body_composition_feature = 0x000007ff; bcs_set_parameter(BCS_PARAM_BODY_COMPOSITION_FEATURE, sizeof(bcs_body_composition_feature), &bcs_body_composition_feature); } * \endcode */ bool bcs_set_parameter(T_BCS_PARAM_TYPE param_type, uint8_t len, void *p_value); /** * @brief Send measurement value indication data . * * @param[in] conn_id Connection id. * @param[in] service_id Service id. * @param[in] p_value Pointer to data to indicate. Type is @ref T_BCS_BODY_COMPOSITION_MEASUREMENT. * * @return Operation result. * @retval true Operation success. * @retval false Operation failure. * * Example usage * \code{.c} void test(void) { T_BCS_BODY_COMPOSITION_MEASUREMENT bcs_meas_value = {0}; uint8_t conn_id = 0; uint16_t bcs_measurement_flag = 0x7f; memcpy(&bcs_meas_value.bcs_measurement_flag, &bcs_measurement_flag, 2); bcs_meas_value.body_fat_percentage = 20; bcs_meas_value.time_stamp = (T_BCS_TIME_STAMP) {2017, 9, 20, 20, 6, 8}; bcs_meas_value.user_id = 0; bcs_meas_value.basal_metabolism = 50; bcs_meas_value.muscle_percentage = 30; bcs_meas_value.muscle_mass = 10; bcs_meas_value.fat_free_mass = 10; bcs_body_composition_measurement_value_indicate(conn_id, bcs_id, &bcs_meas_value); } * \endcode */ bool bcs_body_composition_measurement_value_indicate(uint8_t conn_id, T_SERVER_ID service_id, T_BCS_BODY_COMPOSITION_MEASUREMENT *p_data); /** * @brief Send consecutive measurement value indications data. * * NOTE:If the measurement value indication data exceeds the current MTU size, * the remaining optional fields shall be sent in the subsequent indication * (also known as a 'continuation packet'). * You shall call this function when processing the complete event callback * of the first indication @ref PROFILE_EVT_SEND_DATA_COMPLETE after calling * function @ref bcs_body_composition_measurement_value_indicate. * * * @param[in] conn_id Connection id. * @param[in] service_id Service id. * @param[in] p_value Pointer to data to indicate. Type is @ref T_BCS_BODY_COMPOSITION_MEASUREMENT. * * @return Operation result. * @retval true Operation success. * @retval false Operation failure. * * Example usage * \code{.c} void test(void) { T_BCS_BODY_COMPOSITION_MEASUREMENT bcs_meas_value = {0}; uint8_t conn_id = 0; uint16_t bcs_measurement_flag = 0x1fff; memcpy(&bcs_meas_value.bcs_measurement_flag, &bcs_measurement_flag, 2); bcs_meas_value.body_fat_percentage = 20; bcs_meas_value.time_stamp = (T_BCS_TIME_STAMP) {2017, 9, 20, 20, 6, 8}; bcs_meas_value.user_id = 0; bcs_meas_value.basal_metabolism = 50; bcs_meas_value.muscle_percentage = 30; bcs_meas_value.muscle_mass = 10; bcs_meas_value.fat_free_mass = 10; bcs_meas_value.soft_lean_mass = 20; bcs_meas_value.body_water_mass = 70; bcs_meas_value.impedance = 10; bcs_meas_value.weight = 100; bcs_meas_value.height = 163; bcs_body_composition_measurement_value_indicate(conn_id, bcs_id, &bcs_meas_value); } T_APP_RESULT app_handle_bcs_notify_indicate_cb_message(T_SERVER_ID service_id, void *p_data) { T_APP_RESULT result = APP_RESULT_SUCCESS; if (service_id == SERVICE_PROFILE_GENERAL_ID) { T_SERVER_APP_CB_DATA *p_para = (T_SERVER_APP_CB_DATA *)p_data; switch (p_para->eventId) { case PROFILE_EVT_SEND_DATA_COMPLETE: if (p_para->event_data.send_data_result.service_id == bcs_id) { uint8_t conn_id = p_para->event_data.send_data_result.conn_id; uint8_t serv_id = p_para->event_data.send_data_result.service_id; if (bcs_measurement_value_consecutive_indicate(conn_id, serv_id)) { //data exceeds, send first indication complete //sending second indication app_bcs_measurement_value_consecutive_indicate = true; APP_PRINT_INFO1("PROFILE_EVT_SEND_DATA_COMPLETE sending second indication app_bcs_measurement_value_consecutive_indicate %d", app_bcs_measurement_value_consecutive_indicate); } else if (app_bcs_measurement_value_consecutive_indicate) { //data exceeds, send second indication complete APP_PRINT_INFO1("PROFILE_EVT_SEND_DATA_COMPLETE send second indication complete app_bcs_measurement_value_consecutive_indicate %d", app_bcs_measurement_value_consecutive_indicate); app_bcs_measurement_value_consecutive_indicate = false; } else { //data doesn't exceed, send whole indication complete APP_PRINT_INFO1("PROFILE_EVT_SEND_DATA_COMPLETE send only one indication app_bcs_measurement_value_consecutive_indicate %d", app_bcs_measurement_value_consecutive_indicate); } } break; default: break; } } return result; } T_APP_RESULT app_handle_profile_message(T_SERVER_ID service_id, void *p_data) { T_APP_RESULT result = APP_RESULT_SUCCESS; if (service_id == SERVICE_PROFILE_GENERAL_ID) { T_SERVER_APP_CB_DATA *p_para = (T_SERVER_APP_CB_DATA *)p_data; switch (p_para->eventId) { case PROFILE_EVT_SEND_DATA_COMPLETE: if (p_para->event_data.send_data_result.service_id == bcs_id) { return app_handle_bcs_notify_indicate_cb_message(service_id, p_para); } break; default: break; } ... } } * \endcode */ bool bcs_measurement_value_consecutive_indicate(uint8_t conn_id, T_SERVER_ID service_id); /** @} End of BCS_Exported_Functions */ /** @} End of BCS */ #ifdef __cplusplus } #endif #endif // _BCS_H_