#include "service_sport.h" #include "TjdUiMsgCenter.h" #include "cmsis_os2.h" #include "common_def.h" #include "cwm_data_deal.h" #include "hr_api.h" #include "rtc_api.h" #include "securec.h" #include "service_hrsensor.h" #include "soc_osal.h" #include "sql_fit.h" #include "sql_setting.h" #include "sys_config.h" #include "sys_typedef.h" #include "task_service_timer.h" #include #include #include #define ENABLE_PRINT_INFO 1 #if ENABLE_PRINT_INFO #define static_print_info(...) sys_ui_log_i(__VA_ARGS__) // 一般信息打印宏控制 #define static_print_warn(...) sys_ui_log_w(__VA_ARGS__) // 警告信息打印一般常开 #define static_print_error(...) sys_ui_log_e(__VA_ARGS__) // 错误信息打印一般常开 #else #define static_print_info(...) #define static_print_warn(...) #define static_print_error(...) #endif #define SUCCESS 0 #define ERROR 1 pthread_mutex_t data_mutex = PTHREAD_MUTEX_INITIALIZER; bool if_popup = false; // 定义和初始化变量 static bool serviceIfOpen = false; static bool ifSuspend = false; static uint64_t last_ms_time_stamp = 0; //(ms) static uint64_t current_ms_time_stamp = 0; //(ms) static uint64_t pause_start_time_stamp = 0; // 记录暂停开始时间(ms) static uint64_t pause_duration = 0; // 暂停时长(ms) static SportData lastData; // 上次运动数据 static SportData curData; // 当前运动数据 static float curDistance = 0; static uint32_t recent_steps = 0; // 最近一次运动步数 static uint32_t exerciseDuration = 0; // 运动时长(s) static uint32_t end_remind_time_stamp = 0; // 记录运动结束提醒时间戳(ms) // static uint32_t suspendDuration = 1; static struct rtc_time localTime; static Reminder sport_end_remind; // 记录运动结束提醒信息 static SportType_E sport_type = SPORT_TYPE_MAX; // 记录当前运动类型 static uint32_t heartRateValue = 0; // 心率值 static uint32_t heart_rate_trigger_time = 0; // 记录心率触发时间 static bool heart_rate_first_triggered = false; static SportMsgType end_remind_type = SPORT_MSG_TYPE_END_30_MIN_REMIND; static uint32_t MILLISEC_TO_NANOSEC = 1000000; static uint16_t SEC_TO_MILLISEC = 1000; static bool movement_force_remind_need_trigger = true; // 记录运动强制提醒是否需要触发标志位 static bool movement_auto_end_need_trigger = true; // 记录运动强制提醒是否需要触发标志位 // motion_recognition_entry:用于识别是否是从运动识别开始运动的标志位,其中高位表示是否是从运动识别开始运动,低位表示运动类型 uint8_t motion_recognition_entry = 0x00; //============================================= // 运动数据结构体定义 uint8_t g_cur_sport_type = 0; int g_goal_sport_time = 3600; //目标运动时长: s double g_goal_sport_dist = 3000; //目标运动距离:m double g_current_sport_dist; //当前运动距离:m int g_goal_sport_calorie = 100; //目标运动卡路里消耗:kcal int g_current_sport_calorie; //当前运动卡路里消耗:kcal int g_current_heart_rate_value; //当前心率值: bpm bool g_sport_popup_flag_arry[3] = {0}; //运动弹窗标志 void service_set_cur_sport_type(uint8_t type) { g_cur_sport_type = type; } void service_reset_sport_pop_up_flag(void) { for (int i = 0; i < 3; i++) { g_sport_popup_flag_arry[i] = 0; } } void service__set_pop_up_flag(uint8_t index, bool value) { g_sport_popup_flag_arry[index] = value; } void service_set_pop_up_flag(uint8_t index, bool value) { g_sport_popup_flag_arry[index] = value; } void service_set_sport_goal_time(int timestamp) { g_goal_sport_time = timestamp; } int service_get_sport_goal_time(void) { return g_goal_sport_time; } double service_get_goal_sport_dist(void) { return g_goal_sport_dist; } void service_set_goal_sport_dist(double value) { g_goal_sport_dist = value; } int service_get_goal_sport_calorie(void) { return g_goal_sport_calorie; } void service_set_goal_sport_calorie(int value) { g_goal_sport_calorie = value; } //============================================= uint8_t getmotion_recognition_entry(void) { return motion_recognition_entry; } //外部引用调用 void setmotion_recognition_entry(uint8_t motion) { motion_recognition_entry = motion; } //外部引用调用 void set_movement_force_remind_need_trigger(uint8_t state) { movement_force_remind_need_trigger = state; } void set_movement_auto_end_need_trigger(uint8_t state) { movement_auto_end_need_trigger = state; } uint32_t GetTime(void) { struct timespec time; clock_gettime(CLOCK_MONOTONIC, &time); return time.tv_sec * SEC_TO_MILLISEC + time.tv_nsec / MILLISEC_TO_NANOSEC; } uint32_t GetElapseTime(uint32_t startTime) { uint32_t currentTime = GetTime(); uint32_t elapseTime; if (currentTime > startTime) { elapseTime = currentTime - startTime; } else { elapseTime = (UINT32_MAX - startTime) + currentTime + 1; } // printf("startTime = %d, currentTime = %d, elapseTime = %d\n", startTime, currentTime, elapseTime); return elapseTime; } uint8_t sporting_hr_control_handler(SportingHrAction action, void *param) { uint8_t ret = 0; hr_api_info_t hr_api_info = {HR_SERVICE_UI_SPORT, 0xffffffff}; service_hrs_api *hrsensorInfo = tjd_service_hrs_get_ops(); switch (action) { case HrStart: hrsensorInfo->open(hr_api_info); break; case HrStop: hrsensorInfo->close(); break; case HrGetStatus: // ret = HeartRateGetWearStatus(); break; default: break; } return ret; } // 获取运动数据函数 int tjd_sql_sport_get_data(SportData *sportData) { if (sportData != NULL) { tjd_driver_rtc_get_ops()->get_rtc_time(&localTime); sportData->steps = sql_fit_get_day_step(localTime.tm_wday); sportData->calories = sql_fit_get_day_calorie(localTime.tm_wday); sportData->distance = sql_fit_get_day_distance(localTime.tm_wday); return SUCCESS; } return ERROR; } // 检查并发布弹窗 void check_and_publish_popup(bool *sport_status, uint8_t *heart_rate_array, int curSportTime, SportData curData) { for (int i = 0; i < 3; i++) { static_print_info("sport_status[%d] = %d\n", i, sport_status[i]); } Reminder reminders[4] = {{SPORT_MSG_TYPE_NONE, PRIORITY_GOAL, 0, false, NULL}, {SPORT_MSG_TYPE_NONE, PRIORITY_HEART_RATE, 0, false, NULL}, {SPORT_MSG_TYPE_NONE, PRIORITY_DISTANCE, 0, false, NULL}, {SPORT_MSG_TYPE_NONE, PRIORITY_TIME, 0, false, NULL}}; // 目标提醒 if (sport_status[0] && !if_popup) { reminders[PRIORITY_GOAL].msgType = SPORT_MSG_TYPE_DISTANCE; reminders[PRIORITY_GOAL].value = g_goal_sport_dist; static_print_info("line = %d ,curSportDist=%d,g_goal_sport_dist=%d\n", __LINE__, curData.distance, g_goal_sport_dist); reminders[PRIORITY_GOAL].isGoalReached = (curData.distance >= g_goal_sport_dist); if (reminders[PRIORITY_GOAL].isGoalReached) { g_sport_popup_flag_arry[0] = false; // 已发布,清除状态 // 已发布,清除状态 } } if (sport_status[1] && !if_popup) { reminders[PRIORITY_GOAL].msgType = SPORT_MSG_TYPE_TIME; reminders[PRIORITY_GOAL].value = g_goal_sport_time; static_print_info("line = %d ,curSportTime=%d,g_goal_sport_time()=%d\n", __LINE__, curSportTime, g_goal_sport_time); reminders[PRIORITY_GOAL].isGoalReached = (curSportTime >= g_goal_sport_time); if (reminders[PRIORITY_GOAL].isGoalReached) { g_sport_popup_flag_arry[1] = false; // 已发布,清除状态 } } if (sport_status[2] && !if_popup) { reminders[PRIORITY_GOAL].msgType = SPORT_MSG_TYPE_CALORIE; reminders[PRIORITY_GOAL].value = g_goal_sport_calorie; reminders[PRIORITY_GOAL].isGoalReached = (curData.calories >= g_goal_sport_calorie); if (reminders[PRIORITY_GOAL].isGoalReached) { g_sport_popup_flag_arry[2] = false; // 已发布,清除状态; // 已发布,清除状态 } } // 心率提醒 heartRateValue = tjd_service_hrsensor_get_cur_hrvalue(); // static_print_info("heartRateValue = %d\n", heartRateValue); for (size_t j = 0; j < 5; j++) { // static_print_info("heart_rate_array[%d] = %d\n", j, heart_rate_array[j]); if (heart_rate_array[j] && j != 4) { switch (heartRateValue) { // case 60 ... 150: case 139 ... 150: reminders[PRIORITY_HEART_RATE].msgType = SPORT_MSG_TYPE_HEART_RATE_1; // sql_fit_set_sport_heart_rate_remind_value(0, 0); reminders[PRIORITY_HEART_RATE].isGoalReached = true; break; case 151 ... 162: reminders[PRIORITY_HEART_RATE].msgType = SPORT_MSG_TYPE_HEART_RATE_2; // sql_fit_set_sport_heart_rate_remind_value(1, 0); reminders[PRIORITY_HEART_RATE].isGoalReached = true; break; case 163 ... 174: reminders[PRIORITY_HEART_RATE].msgType = SPORT_MSG_TYPE_HEART_RATE_3; // sql_fit_set_sport_heart_rate_remind_value(2, 0); reminders[PRIORITY_HEART_RATE].isGoalReached = true; break; case 175 ... 999: reminders[PRIORITY_HEART_RATE].msgType = SPORT_MSG_TYPE_HEART_RATE_4; // sql_fit_set_sport_heart_rate_remind_value(3, 0); reminders[PRIORITY_HEART_RATE].isGoalReached = true; break; default: reminders[PRIORITY_HEART_RATE].isGoalReached = false; break; } } } // static_print_info("line = %d ,curSportDist = %d, sql_fit_get_sport_dist_remind_value() = %d ", __LINE__, // curData.distance, sql_fit_get_sport_dist_remind_value()); // 单段距离提醒 if ((curData.distance != 0) && sql_fit_get_sport_dist_remind_value() != 0 && (curData.distance % sql_fit_get_sport_dist_remind_value() == 0) && (sql_fit_get_sport_dist_remind_value() != 99999)) { reminders[PRIORITY_DISTANCE].msgType = SPORT_MSG_TYPE_DISTANCE_REMIND; reminders[PRIORITY_DISTANCE].value = curData.distance; reminders[PRIORITY_DISTANCE].isGoalReached = true; } // // 时间提醒 // static_print_info("line = %d ,curSportTime = %d, sql_fit_get_sport_time_remind_value() = %d ", __LINE__, // curData.distance, sql_fit_get_sport_time_remind_value()); if (curSportTime != 0 && sql_fit_get_sport_time_remind_value() != 0 && (curSportTime % sql_fit_get_sport_time_remind_value() == 0) && (sql_fit_get_sport_time_remind_value() != 99999)) { reminders[PRIORITY_TIME].msgType = SPORT_MSG_TYPE_TIME_REMIND; reminders[PRIORITY_TIME].value = curSportTime; reminders[PRIORITY_TIME].isGoalReached = true; } // printf("exerciseDuration = %d, heart_rate_trigger_time = %d, value = %d, heart_rate_first_triggered = %d\n", // exerciseDuration, heart_rate_trigger_time, exerciseDuration - heart_rate_trigger_time, // heart_rate_first_triggered); for (int i = 0; i < 4; ++i) { if (reminders[i].msgType != SPORT_MSG_TYPE_NONE) { if (heart_rate_first_triggered && (reminders[i].priority == PRIORITY_HEART_RATE) && ((exerciseDuration - heart_rate_trigger_time) < 60)) continue; publish_reminder(&reminders[i]); } } } void check_and_pop_sport_end_reminder(uint32_t steps) { if (recent_steps == steps) { end_remind_time_stamp++; recent_steps == steps; switch (end_remind_type) { case SPORT_MSG_TYPE_END_30_MIN_REMIND: if (end_remind_time_stamp == 30 * 60) { // 30*60 end_remind_type++; sport_end_remind.value = 30; sport_end_remind.isGoalReached = true; sport_end_remind.msgType = SPORT_MSG_TYPE_END_30_MIN_REMIND; } else sport_end_remind.isGoalReached = false; break; case SPORT_MSG_TYPE__END_50_MIN_REMIND: if (end_remind_time_stamp == 50 * 60) { // 50*60 end_remind_type++; sport_end_remind.value = 50; sport_end_remind.isGoalReached = true; sport_end_remind.msgType = SPORT_MSG_TYPE__END_50_MIN_REMIND; } else sport_end_remind.isGoalReached = false; break; case SPORT_MSG_TYPE__END_60_MIN_REMIND: if (end_remind_time_stamp == 60 * 60) { // 60*60 end_remind_type++; sport_end_remind.value = 60; sport_end_remind.isGoalReached = true; sport_end_remind.msgType = SPORT_MSG_TYPE__END_60_MIN_REMIND; } else sport_end_remind.isGoalReached = false; break; case SPORT_MSG_TYPE__END_65_MIN_REMIND: if (end_remind_time_stamp == 65 * 60) { // 65*60 end_remind_type++; sport_end_remind.value = 65; sport_end_remind.isGoalReached = true; sport_end_remind.msgType = SPORT_MSG_TYPE__END_65_MIN_REMIND; } else sport_end_remind.isGoalReached = false; break; case SPORT_MSG_TYPE__END_70_MIN_REMIND: if (end_remind_time_stamp == 70 * 60) { // 70*60 end_remind_type++; sport_end_remind.value = 70; sport_end_remind.isGoalReached = true; sport_end_remind.msgType = SPORT_MSG_TYPE__END_70_MIN_REMIND; } else sport_end_remind.isGoalReached = false; break; default: sport_end_remind.isGoalReached = false; break; } if (sport_end_remind.isGoalReached) { sport_end_remind.priority = PRIORITY_SPORT_END; sport_end_remind.content = NULL; publish_reminder(&sport_end_remind); } } else { recent_steps = steps; end_remind_time_stamp = 0; end_remind_type = SPORT_MSG_TYPE_END_30_MIN_REMIND; } printf("func = %s, steps = %d\n", __func__, steps); } // 发布提醒 void publish_reminder(Reminder *reminder) { if (reminder->isGoalReached) { // 目标达成,显示目标达成界面 // if (reminder->priority == PRIORITY_DISTANCE || reminder->priority == PRIORITY_TIME) { // reminder->isGoalReached = false; // } TjdUiMsgEventPublish(TJDUI_TOPIC_EVENT_SPORT, &reminder, sizeof(reminder)); tjd_service_sport_set_screen_on(5); heart_rate_trigger_time = exerciseDuration; heart_rate_first_triggered = true; reminder->isGoalReached = false; } if_popup = false; // 重置弹窗状态,以便下一次提醒可以触发 } // int curSportDist = 0; // int curSportTime = 0; static signed int tjd_service_sport_handle(void *param) { // static_print_info("==sport_service==sql_fit_get_sport_goal_time()=%d===%d===\n", sql_fit_get_sport_goal_time(), // sql_fit_get_current_sport_goal_time()); pthread_mutex_lock(&data_mutex); // 锁定互斥锁 int msgType = 0; SportData totalData; uint8_t *heart_rate_array; sql_fit_get_heart_rate_arry(&heart_rate_array); // int curSportTime = sql_fit_get_current_sport_goal_time(); // curSportTime = curSportTime + 300; // int curSportDist = sql_fit_get_current_sport_dist() * 1000; // sql_fit_get_pop_up_flag(&sport_status); // sql_fit_get_heart_rate_arry(&heart_rate_array); // static_print_info("line = %d==curSportTime===%d===curSportDist=%d==sql_fit_get_current_sport_dist=%d====\n", // __LINE__, curSportTime, curSportDist, sql_fit_get_current_sport_dist()); if (!tjd_sql_sport_get_data(&totalData)) { static_print_info("tjd_sql_sport_get_data get cur data success"); curData.steps = totalData.steps - lastData.steps; curData.calories = totalData.calories - lastData.calories; curData.distance = totalData.distance - lastData.distance; // curSportDist++; // curData.distance = curSportDist; static_print_info("curSteps=%d,curCalories=%d,curDistance=%d\n", curData.steps, curData.calories, curData.distance); printf("recent_steps = %d,sql_setting_get_motion_end_enable = %d\n", recent_steps, sql_setting_get_motion_end_enable()); if (sql_setting_get_motion_end_enable() && sport_type == SPORT_TYPE_1) { check_and_pop_sport_end_reminder(curData.steps); } // 弹窗逻辑 check_and_publish_popup(g_sport_popup_flag_arry, heart_rate_array, exerciseDuration, curData); } if (sql_setting_get_motion_end_enable() && motion_recognition_entry >> 4) { if (sql_setting_get_motion_out_time() == exerciseDuration) { uint8_t msg_data = MOVEMENT_TIMEOUT_REMINDER | sql_setting_get_motion_out_time() / 3600; TjdUiMsgEventPublish(TJDUI_TOPIC_EVENT_ACTIVITY_RECOGNITION, &msg_data, sizeof(msg_data)); }; if ((sql_setting_get_motion_out_time() + 300000) == exerciseDuration && movement_force_remind_need_trigger) { uint8_t msg_data = MOVEMENT_TIMEOUT_FORCED_END_REMINDER | sql_setting_get_motion_out_time() / 3600; TjdUiMsgEventPublish(TJDUI_TOPIC_EVENT_ACTIVITY_RECOGNITION, &msg_data, sizeof(msg_data)); }; if ((sql_setting_get_motion_out_time() + 350000) == exerciseDuration && movement_auto_end_need_trigger) { uint8_t msg_data = MOVEMENT_AUTO_END_REMINDER; TjdUiMsgEventPublish(TJDUI_TOPIC_EVENT_ACTIVITY_RECOGNITION, &msg_data, sizeof(msg_data)); }; } if (!ifSuspend) { current_ms_time_stamp = GetTime(); update_exercise_duration(current_ms_time_stamp); } pthread_mutex_unlock(&data_mutex); // 解锁互斥锁 // static_print_info("==sport_service==exerciseDuration=%d==\n", exerciseDuration); return 250; } // 运动服务开始函数 static void tjd_service_sport_start_send(void) { serviceIfOpen = true; if (tjd_sql_sport_get_data(&lastData)) { static_print_error("tjd_sql_sport_get_data get last data fail"); } last_ms_time_stamp = GetTime(); printf("last_ms_time_stamp = %d\n", last_ms_time_stamp); // sporting_hr_control_handler(HrStart, NULL); queue_default_info_t msg_data = {tjd_service_sport_handle, NULL, 250, NULL}; osal_msg_queue_write_copy(tjd_task_service_timer_get_queue_id(), (void *)&msg_data, sizeof(queue_default_info_t), 0); } void tjd_service_sport_data_reset(void) { ifSuspend = false; serviceIfOpen = false; heart_rate_first_triggered = false; exerciseDuration = 0; end_remind_time_stamp = 0; heart_rate_trigger_time = 0; pause_duration = 0; // 清空暂停时长 motion_recognition_entry = 0x00; movement_force_remind_need_trigger = true; movement_auto_end_need_trigger = true; // sporting_hr_control_handler(HrStop, NULL); } // 运动服务结束函数 static void tjd_service_sport_end_send(void) { tjd_service_sport_data_reset(); queue_default_info_t msg_data = {tjd_service_sport_handle, NULL, 0, NULL}; osal_msg_queue_write_copy(tjd_task_service_timer_get_queue_id(), (void *)&msg_data, sizeof(queue_default_info_t), 0); } void tjd_service_sport_open(void) { tjd_service_sport_start_send(); } void tjd_service_sport_close(void) { tjd_service_sport_end_send(); } bool tjd_get_service_if_open(void) { return serviceIfOpen; } // 获取运动数据函数 SportingData_t tjd_service_sport_get_data(void) { // pthread_mutex_lock(&data_mutex); // 锁定互斥锁 SportingData_t sportData; sportData.heartRate = tjd_service_hrsensor_get_cur_hrvalue(); sportData.exerciseDuration = exerciseDuration; sportData.steps = curData.steps; sportData.calories = curData.calories; // sportData.distance = (curDistance ++)/1000; sportData.distance = curData.distance; // pthread_mutex_unlock(&data_mutex); // 解锁互斥锁 return sportData; } // 计算并更新运动时长的函数 void update_exercise_duration(uint64_t current_ms_time_stamp) { uint64_t elapsedTime = 0; if (!pause_duration) { elapsedTime = current_ms_time_stamp - pause_duration - last_ms_time_stamp; pause_duration = 0; // 清空暂停时长 } else { elapsedTime = current_ms_time_stamp - last_ms_time_stamp; } exerciseDuration = elapsedTime / 1000; // 累加总运动时长(秒) // last_ms_time_stamp = current_ms_time_stamp; // 更新上次时间戳 } // 暂停功能 void pause_exercise(void) { pause_start_time_stamp = GetTime(); } // 恢复功能 void resume_exercise(void) { pause_duration = GetElapseTime(pause_start_time_stamp); // 更新暂停时长 pause_start_time_stamp = 0; // 清空暂停开始时间戳 F last_ms_time_stamp = last_ms_time_stamp + pause_duration; // 更新上次时间戳 } bool tjd_service_sport_get_if_suspend(void) { return ifSuspend; } void tjd_service_sport_set_if_suspend(bool state) { if (state) { pause_exercise(); } else { resume_exercise(); } ifSuspend = state; } void tjd_service_sport_set_if_popup(bool state) { if_popup = state; } void tjd_service_sport_set_end_remind_type(uint8_t type) { end_remind_type = (SportMsgType)type; } SportType_E tjd_service_sport_get_sport_type(void) { return sport_type; } void tjd_service_sport_set_sport_type(uint8_t type) { sport_type = type; } SportMsgType tjd_service_sport_get_end_remind_type(void) { return end_remind_type; } static void tjd_service_sport_set_screen_on(int32_t timeout) { const power_display_svr_api_t *display_api = power_display_svr_get_api(); if (display_api->get_screen_state() != SCREEN_ON) { display_api->turn_on_screen(); } // display_api->set_screen_set_keepon_timeout(timeout); return; }