From 9ecd06df9620f003ddacf47e0d78e27a8fc8f3d9 Mon Sep 17 00:00:00 2001 From: luozheng <1732036298@qq.com> Date: Mon, 30 Mar 2026 20:31:24 +0800 Subject: [PATCH] =?utf8?q?ui=E4=BB=A3=E7=A0=81=E4=BF=AE=E6=94=B9=E4=BC=98?= =?utf8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../nativeui/applist/src/AppItemView.cpp | 3 + .../heartrate/src/HeartRateCardView.cpp | 1 - .../sport_countdown/src/CountdownView.cpp | 16 +- .../nativeui/traing/src/TraingModel.cpp | 297 ++++++++---------- code/sdk/zhihui/services/gnss/src/uart_gnss.c | 3 + 5 files changed, 139 insertions(+), 181 deletions(-) diff --git a/code/sdk/application/wearable/fd272/nativeapp/nativeui/applist/src/AppItemView.cpp b/code/sdk/application/wearable/fd272/nativeapp/nativeui/applist/src/AppItemView.cpp index 87b35c580..2f11487a8 100644 --- a/code/sdk/application/wearable/fd272/nativeapp/nativeui/applist/src/AppItemView.cpp +++ b/code/sdk/application/wearable/fd272/nativeapp/nativeui/applist/src/AppItemView.cpp @@ -173,6 +173,9 @@ namespace OHOS { void ArcScaleListItemView::SetItemInfo(const AppItem &itemInfo) { + if (image_ == nullptr || label_ == nullptr) { + return ; + } itemInfo_ = itemInfo; image_->SetSrc(itemInfo.iconSmall); if(VIEW_EXTERN_APP != itemInfo.id) { diff --git a/code/sdk/application/wearable/fd272/nativeapp/nativeui/heartrate/src/HeartRateCardView.cpp b/code/sdk/application/wearable/fd272/nativeapp/nativeui/heartrate/src/HeartRateCardView.cpp index 5fc8c2430..56fcd44ea 100644 --- a/code/sdk/application/wearable/fd272/nativeapp/nativeui/heartrate/src/HeartRateCardView.cpp +++ b/code/sdk/application/wearable/fd272/nativeapp/nativeui/heartrate/src/HeartRateCardView.cpp @@ -23,7 +23,6 @@ void HeartRateCardView::ClearAll(void) { RemoveAll(); delete heartRateCardView; heartRateCardView = nullptr; - heartRateGroupView = nullptr; WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "HeartRateCardView::ClearAll viewiInitStatus end"); } } diff --git a/code/sdk/application/wearable/fd272/nativeapp/nativeui/sport_countdown/src/CountdownView.cpp b/code/sdk/application/wearable/fd272/nativeapp/nativeui/sport_countdown/src/CountdownView.cpp index 207c95fdd..fb5e8184c 100644 --- a/code/sdk/application/wearable/fd272/nativeapp/nativeui/sport_countdown/src/CountdownView.cpp +++ b/code/sdk/application/wearable/fd272/nativeapp/nativeui/sport_countdown/src/CountdownView.cpp @@ -202,6 +202,11 @@ CountdownView::CountdownView() { CountdownView::~CountdownView() { ScreenAlwaysOnCtr(CANCEL_SCREEN_ALWAYS_ON); // 退出运动倒计时取消常亮屏 + if (group_) { + group_->RemoveAll(); + delete group_; + group_ = nullptr; + } if (countdownAnimator_) { countdownAnimator_->Stop(); delete countdownAnimator_; @@ -219,10 +224,6 @@ CountdownView::~CountdownView() { delete label_; label_ = nullptr; } - if (group_) { - delete group_; - group_ = nullptr; - } g_pCountdownView = nullptr; } @@ -275,8 +276,11 @@ void CountdownView::StopCanvas() { } void CountdownView::OnStart() { - group_ = new UIViewGroup(); - if (!group_) return; + if (group_ == nullptr) + { + group_ = new UIViewGroup(); + if (group_ == nullptr) return; + } group_->SetPosition(0, 0); group_->SetWidth(Screen::GetInstance().GetWidth()); group_->SetHeight(Screen::GetInstance().GetHeight()); diff --git a/code/sdk/application/wearable/fd272/nativeapp/nativeui/traing/src/TraingModel.cpp b/code/sdk/application/wearable/fd272/nativeapp/nativeui/traing/src/TraingModel.cpp index 92b917c67..695811755 100644 --- a/code/sdk/application/wearable/fd272/nativeapp/nativeui/traing/src/TraingModel.cpp +++ b/code/sdk/application/wearable/fd272/nativeapp/nativeui/traing/src/TraingModel.cpp @@ -80,7 +80,6 @@ #include "NativeAbility.h" #include "AppViewIDs.h" #include "sport_countdown/CountdownPresenter.h" -#include "heartrate/include/HeartModel.h" #if defined(SUPPORT_GNSS) #include "NMEA0183.h" @@ -477,7 +476,7 @@ // 计算平均心率的函数 double CalculateAverageHeartRate(const std::vector &heartRates) { if (heartRates.size() <= 2) { - // 如果心率数据点少于等于2,无法去掉最高和最低值 + // 如果心率数据点少于等于2,无法去掉最高和最低值 return 0.0; // 或者返回心率的平均值 } @@ -561,7 +560,7 @@ typedef struct "CalculatePace: distance=%d米, duration=%d秒, pace=%d秒/公里", sportdata->distance, sportdata->duration, calculatedAvgPace); } else if (cyweeInfo->avg_pace != 0) { - // 如果距离或时间为0,使用CYWEE提供的平均配速作为后备 + // 如果距离或时间为0,使用CYWEE提供的平均配速作为后备 sportdata->pc = cyweeInfo->pace; } #else @@ -569,7 +568,7 @@ typedef struct #endif - // 心率提醒 目前取值有问题,暂时关闭 + // 心率提醒 目前取值有问题,暂时关闭 if (sportdata->heart >= user_maxHeart && user_maxHeart != 0) { uapi_set_screen_on_api(); // 亮屏检测 if (true != OHOS::ConfigModel::GetInstance()->GetDnotdisturb() && (!uapi_sleep_mode_flag_get())) { @@ -581,7 +580,7 @@ typedef struct restshock_count++; shock_count = 0; if (restshock_count >= 5) { - restshock_count = 0; /* 休息满 5 次,下一轮可再震 */ + restshock_count = 0; /* 休息满 5 次,下一轮可再震 */ } } } @@ -636,12 +635,12 @@ typedef struct "CalculateAvgPace: distance=%d米, duration=%d秒, avgPace=%d秒/公里", sportdata->distance, sportdata->duration, calculatedAvgPace); } else if (cyweeInfo->avg_pace != 0) { - // 如果距离或时间为0,使用CYWEE提供的平均配速作为后备 + // 如果距离或时间为0,使用CYWEE提供的平均配速作为后备 sportdata->apc = cyweeInfo->avg_pace; } - // 最快配速:配速越小表示速度越快,所以最快配速应该是最小的配速值 - // 如果当前配速不为0且小于之前的最快配速(或最快配速为0),则更新最快配速 + // 最快配速:配速越小表示速度越快,所以最快配速应该是最小的配速值 + // 如果当前配速不为0且小于之前的最快配速(或最快配速为0),则更新最快配速 if (sportdata->pc > 0) { if (sportdata->fpc == 0 || sportdata->pc < sportdata->fpc) { sportdata->fpc = sportdata->pc; @@ -649,7 +648,7 @@ typedef struct "UpdateFastestPace: fpc=%d秒/公里", sportdata->fpc); } } else if (cyweeInfo->max_pace != 0) { - // 如果当前配速为0,使用CYWEE提供的最快配速作为后备 + // 如果当前配速为0,使用CYWEE提供的最快配速作为后备 sportdata->fpc = cyweeInfo->max_pace; } //平均步频 @@ -717,7 +716,7 @@ void TraingModel::SetSportdata(SportData *data) { sportdata->starttime = data->starttime; //更新开始时间 printf_data(data); //打印该运动数据 IsSpecialSport(sportdata->sportId); // 配置训练特殊性 - // 更新sportId_,确保IsNeedGPS()能正确判断是否需要GPS + // 更新sportId_,确保IsNeedGPS()能正确判断是否需要GPS sportId_ = data->sportId; sportType_ = data->sportType; WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SetSportdata: 更新sportId_=%d, sportType_=%d", sportId_, (int)sportType_); @@ -971,7 +970,7 @@ void TraingModel::SetSportdata(SportData *data) { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SaveSportData error!"); } #else - //运动数据达标,存储运动数据 + //运动数据达标,存储运动数据 if (MomentumFlag) { // GetGoaldegree(); // 设置目标完成度 if (SaveSportData()) { @@ -1025,7 +1024,7 @@ void TraingModel::SetSportdata(SportData *data) { maxHeap.push(newHeartRate); minHeap.push(newHeartRate); - // 如果超过窗口大小,移除最早的心率 + // 如果超过窗口大小,移除最早的心率 if (heartRateData.size() > windowSize) { int oldestRate = heartRateData[0]; totalHeartRate -= oldestRate; @@ -1053,7 +1052,7 @@ void TraingModel::SetSportdata(SportData *data) { "新心率: %d, 当前心率总和: %d, 心率计数: %d", newHeartRate, totalHeartRate, countHeartRate); - // 如果心率数量少于 3,直接返回当前的平均值 + // 如果心率数量少于 3,直接返回当前的平均值 if (countHeartRate < 3) { return totalHeartRate / countHeartRate; // 无法去除最大最小值 } @@ -1077,7 +1076,7 @@ void TraingModel::SetSportdata(SportData *data) { // 将新的心率添加到最近心率列表 recentHeartRates.push_back(newHeartRate); - // 如果超过窗口大小,移除最早的心率 + // 如果超过窗口大小,移除最早的心率 if (recentHeartRates.size() > windowSize) { recentHeartRates.erase(recentHeartRates.begin()); } @@ -1305,7 +1304,7 @@ void TraingModel::SetSportdata(SportData *data) { int TraingModel::GetGoaldegree() { if (sportdata->tag == 0) { WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "sportdata->tag is 0"); - return 0; // 如果目标值为 0,返回 0% + return 0; // 如果目标值为 0,返回 0% } int goaldegree = GetSportTagData(); @@ -1433,27 +1432,27 @@ void TraingModel::SetSportdata(SportData *data) { } /* - uint32_t src; // 训练来源:0 - 手表开启的训练,1 - APP开启的训练 - uint32_t bt; // 运动类型:0 - 健身类,1 - 舞蹈类,2 - 休闲运动,3 - 球类,4 - 水上项目,5 - 冰上项目,6 - 极限运动,7 - 其他 + uint32_t src; // 训练来源:0 - 手表开启的训练,1 - APP开启的训练 + uint32_t bt; // 运动类型:0 - 健身类,1 - 舞蹈类,2 - 休闲运动,3 - 球类,4 - 水上项目,5 - 冰上项目,6 - 极限运动,7 - 其他 uint32_t ty; //训练类型:自由训练 uint32_t st; // 开始时间戳(单位:秒) uint32_t sp; // 结束时间戳(单位:秒) - uint32_t tgt; // 训练目标类型:0 - 距离,1 - 卡路里,2- 时间,3 - 步数 - uint32_t tg; //训练目标值:路程(单位:米),卡路里(单位:kcal),时间(单位:分钟),步数(单位:步) + uint32_t tgt; // 训练目标类型:0 - 距离,1 - 卡路里,2- 时间,3 - 步数 + uint32_t tg; //训练目标值:路程(单位:米),卡路里(单位:kcal),时间(单位:分钟),步数(单位:步) uint32_t pg; // 目标完成度(单位:%) uint32_t du; // 训练总时长(单位:秒) uint32_t ca; // 消耗卡路里(单位:kcal) uint32_t di; // 完成的距离(单位:米) uint32_t hr; // 平均心率 uint32_t stp; // 步数 - uint32_t ti; // 训练强度:0 - 较低强度,1 - 中等强度,2 - 高等强度,3 - 超高强度 + uint32_t ti; // 训练强度:0 - 较低强度,1 - 中等强度,2 - 高等强度,3 - 超高强度 uint32_t cir; // 圈数 uint32_t alt; // 最高海拔高度 */ /*保存数据*/ bool TraingModel::SaveSportData() { - // 骑行等需要GPS的运动:CYWEE无距离时,在结束时用GPS轨迹一次性计算,不实时计 + // 骑行等需要GPS的运动:CYWEE无距离时,在结束时用GPS轨迹一次性计算,不实时计 if (sportdata->distance == 0 && IsNeedGPS(sportId_) && gpsData.size() >= 2) { uint32_t gpsDist = CalculateDistanceFromGPSTrack(); @@ -1551,7 +1550,7 @@ void TraingModel::SetSportdata(SportData *data) { } } - // 如果所有操作成功,则恢复训练存储状态 + // 如果所有操作成功,则恢复训练存储状态 uapi_dev_runtime_set_train_storage_status(0); return true; } @@ -1589,8 +1588,8 @@ bool TraingModel::GetMomentum() { MomentumFlag = false; } - // 如果是需要GPS定位的运动,需要判断移动距离是否大于100m,不然轨迹可能异常 - // 但是目前轨迹没有距离,先不判断 + // 如果是需要GPS定位的运动,需要判断移动距离是否大于100m,不然轨迹可能异常 + // 但是目前轨迹没有距离,先不判断 if ((IsNeedGPS(sportdata->sportId))&&(sportdata->sportId!=UIResourceTextId::STR_EXERCISE_OUTDOORBIKING)) { if (sportdata->distance < 100) { MomentumFlag = false; @@ -1691,7 +1690,7 @@ bool TraingModel::GetMomentum() { void TraingModel::PrintHeartRateTable() { size_t heartRateCount = heartRateTable.size(); if (heartRateCount == 0) { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "心率表为空,无法打印。"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "心率表为空,无法打印。"); return; } @@ -1705,7 +1704,7 @@ bool TraingModel::GetMomentum() { void TraingModel::PrintPaceTable() { size_t paceCount = paceTable.size(); if (paceCount == 0) { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "配速表为空,无法打印。"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "配速表为空,无法打印。"); return; } @@ -1725,7 +1724,7 @@ bool TraingModel::GetMomentum() { size_t heartRateCount = heartRateTable.size(); if (heartRateCount == 0) { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "心率表为空,无法保存。"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "心率表为空,无法保存。"); return false; } @@ -1764,7 +1763,7 @@ bool TraingModel::GetMomentum() { size_t paceCount = paceTable.size(); if (paceCount == 0) { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "配速表为空,无法保存。"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "配速表为空,无法保存。"); return false; } @@ -1802,7 +1801,7 @@ bool TraingModel::GetMomentum() { return exactFilePath; // 返回完全匹配的文件路径 } - // 如果未找到,检查时间戳相差5秒的文件 + // 如果未找到,检查时间戳相差5秒的文件 for (int i = -5; i <= 5; ++i) { uint32_t checkTimestamp = timestamp + i; std::string filePath = TRAINING_HEART_FILE + std::to_string(checkTimestamp) + ".bin"; @@ -1827,7 +1826,7 @@ bool TraingModel::GetMomentum() { return exactFilePath; // 返回完全匹配的文件路径 } - // 如果未找到,检查时间戳相差5秒的文件 + // 如果未找到,检查时间戳相差5秒的文件 for (int i = -5; i <= 5; ++i) { uint32_t checkTimestamp = timestamp + i; std::string filePath = @@ -1868,10 +1867,10 @@ bool TraingModel::GetMomentum() { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "id is error"); return; } - // 进入运动倒计时 3 秒,结束后跳转运动卡片 + // 进入运动倒计时 3 秒,结束后跳转运动卡片 CountdownPresenter::SetReturnSlice(VIEW_TRAININGCRAD); NativeAbility::GetInstance().EnterSlice(VIEW_SPORT_COUNTDOWN); - // 配置运动项(先完成配置,再进 3 秒倒计时,倒计时结束进入运动界面) + // 配置运动项(先完成配置,再进 3 秒倒计时,倒计时结束进入运动界面) SetSportEvent(id); // 获取运动项目 ExerciseClass type = GetSportId(); @@ -1879,20 +1878,20 @@ bool TraingModel::GetMomentum() { TraingCardPresenter::GetInstance()->OpenSensor(type); TraingCardPresenter::GetInstance()->ControlSensor(ExerciseState::Start); - TraingModel::GetInstance()->SetSportOpenWay(false); // 运动识别由手表开启,非用户点击 + TraingModel::GetInstance()->SetSportOpenWay(false); // 运动识别由手表开启,非用户点击 //开启心率 TraingModel::GetInstance()->start_training_heart(); // 仅需要GPS的运动才开启GPS定时器(与TraingNomalPresenter::OnStart一致) if (TraingModel::GetInstance()->IsNeedGPS(TraingModel::GetInstance()->GetSportEvent())) { - #if defined(SUPPORT_GNSS) - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "该运动需要GPS,开启gps定时器,频率:2秒/点"); - TraingModel::GetInstance()->gnss_start_timer(2 * 1000); // 2秒一个GPS点 - #endif + #if defined(SUPPORT_GNSS) + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "该运动需要GPS,开启gps定时器,频率:2秒/点"); + TraingModel::GetInstance()->gnss_start_timer(2 * 1000); // 2秒一个GPS点 + #endif } else { - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "该运动不需要GPS,不开启GPS定时器"); + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "该运动不需要GPS,不开启GPS定时器"); } // 快捷训练都属于健身类 - // 运动识别,跑步,走路,骑行,划船机,椭圆机,都属于健身类 + // 运动识别,跑步,走路,骑行,划船机,椭圆机,都属于健身类 SetSportType(Exercisetype::FITNESS); } @@ -1936,7 +1935,7 @@ bool TraingModel::GetMomentum() { // } // lastCallTime = currentTime; // 更新最后调用时间 - // 如果 g_motionTimes 不为零,进行计算和数据存储 + // 如果 g_motionTimes 不为零,进行计算和数据存储 if (g_motionTimes > 0) { sportdata->duration = g_motionTimes; // 设置训练时长 @@ -2186,11 +2185,11 @@ bool TraingModel::GetMomentum() { // 获得数据个数 static int get_Trainingdata_data_num(FILE *fp) { if (fp == NULL) { - return 0; // 如果文件指针为空,返回0 + return 0; // 如果文件指针为空,返回0 } fseek(fp, 0, SEEK_END); // 将文件指针移动到文件末尾 - long size = ftell(fp); // 获取当前文件指针位置,即文件大小 + long size = ftell(fp); // 获取当前文件指针位置,即文件大小 fseek(fp, 0, SEEK_SET); // 将文件指针移回文件开头 return (size / sizeof(Trainingdata)); @@ -2203,7 +2202,7 @@ bool TraingModel::GetMomentum() { uapi_get_YYMMDD_Time(timeday, '_'); snprintf(file_path, sizeof(file_path), "%s%s.bin", TRAINING_PATH, timeday); - // 检查目录是否存在,如果不存在则创建 + // 检查目录是否存在,如果不存在则创建 struct stat st = {0}; if (stat(TRAINING_PATH, &st) == -1) { if (mkdir(TRAINING_PATH, 0700) != 0) { @@ -2399,7 +2398,7 @@ bool TraingModel::GetMomentum() { /* 加载训练数据函数 */ /* 加载训练数据函数 */ bool TraingModel::LoadDataFormJson(std::vector &sportDataVector) { - // 清空输出向量,避免旧数据干扰 + // 清空输出向量,避免旧数据干扰 sportDataVector.clear(); // 打开JSON文件 @@ -2457,7 +2456,7 @@ bool TraingModel::GetMomentum() { if (item == NULL) { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Null item at index %d in 'data' array", i); - continue; // 跳过无效项,继续处理其他项 + continue; // 跳过无效项,继续处理其他项 } SportData sportData; @@ -2668,7 +2667,7 @@ bool TraingModel::GetMomentum() { WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Parsed starttime: %d", sportData.starttime); } else { - // 打印详细信息,帮助定位问题 + // 打印详细信息,帮助定位问题 const char *valueStr = starttimeItem->valuestring ? starttimeItem->valuestring : "null"; WEARABLE_LOGE( @@ -2712,11 +2711,11 @@ bool TraingModel::GetMomentum() { Latitude(纬度):范围:-90° 至 +90°(或南纬 90° 至北纬 90°); Longitude(经度):范围:-180° 至 +180°(或西经 180° 至东经 180°); - -画布数据集使用所有GPS定位坐标,不进行点位限制,确保绘制完整; - -通过映射关系,将经纬度转换为400*400画布上的坐标; - -但是不能靠近400,以免显示不全等问题,350*350; - -如果处理负数,需要将其转换为正数,然后再进行映射? - -如果有正数又有负数,应该怎么处理? + -画布数据集使用所有GPS定位坐标,不进行点位限制,确保绘制完整; + -通过映射关系,将经纬度转换为400*400画布上的坐标; + -但是不能靠近400,以免显示不全等问题,350*350; + -如果处理负数,需要将其转换为正数,然后再进行映射? + -如果有正数又有负数,应该怎么处理? */ static double getmin(double a, double b) { return a < b ? a : b; } @@ -2731,7 +2730,7 @@ bool TraingModel::GetMomentum() { // 线段长度的平方 double len2 = dx * dx + dy * dy; - // 如果线段退化为一个点,直接计算点到点的距离 + // 如果线段退化为一个点,直接计算点到点的距离 if (len2 == 0) { return std::hypot(p.x - p1.x, p.y - p1.y); } @@ -2740,16 +2739,16 @@ bool TraingModel::GetMomentum() { double t = ((p.x - p1.x) * dx + (p.y - p1.y) * dy) / len2; if (t < 0) { - // 投影在p1之前,返回p到p1的距离 + // 投影在p1之前,返回p到p1的距离 return std::hypot(p.x - p1.x, p.y - p1.y); } if (t > 1) { - // 投影在p2之后,返回p到p2的距离 + // 投影在p2之后,返回p到p2的距离 return std::hypot(p.x - p2.x, p.y - p2.y); } - // 投影在线段上,计算投影点并返回距离 + // 投影在线段上,计算投影点并返回距离 double projX = p1.x + t * dx; double projY = p1.y + t * dy; return std::hypot(p.x - projX, p.y - projY); @@ -2759,7 +2758,7 @@ bool TraingModel::GetMomentum() { static void douglasPeucker(const std::vector &points, double epsilon, std::vector &result) { if (points.size() <= 2) { - // 点数量不足,直接返回 + // 点数量不足,直接返回 result = points; return; } @@ -2777,7 +2776,7 @@ bool TraingModel::GetMomentum() { } } - // 如果最大距离大于阈值,则递归处理 + // 如果最大距离大于阈值,则递归处理 if (dmax > epsilon) { std::vector recResults1, recResults2; @@ -2799,11 +2798,11 @@ bool TraingModel::GetMomentum() { } } -// 手表轨迹画布最大点数,控制内存与绘制性能 +// 手表轨迹画布最大点数,控制内存与绘制性能 static const size_t MAX_CANVAS_POINTS = 300; /** - * @brief 将画布点集均匀采样至最多 maxPoints 个点(保留首尾,中间等间隔取点) + * @brief 将画布点集均匀采样至最多 maxPoints 个点(保留首尾,中间等间隔取点) */ static void uniformSampleToMax(std::vector &points, size_t maxPoints) { if (points.size() <= maxPoints) return; @@ -2818,17 +2817,17 @@ static void uniformSampleToMax(std::vector &points, size_t maxPoints) { } /** - * @brief GPS点位映射到画布坐标,并限制画布点数≤300以简化手表显示 + * @brief GPS点位映射到画布坐标,并限制画布点数≤300以简化手表显示 * * 1. 计算边界框并映射所有GPS点到画布 - * 2. 若点数>300则均匀采样至300点,保证轨迹形状不失真 + * 2. 若点数>300则均匀采样至300点,保证轨迹形状不失真 */ void TraingModel::GetPointData() { WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, - "开始GPS到画布映射,GPS点数: %zu", gpsData.size()); + "开始GPS到画布映射,GPS点数: %zu", gpsData.size()); if (gpsData.empty()) { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "GPS数据为空,无法映射"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "GPS数据为空,无法映射"); canvasData.clear(); return; } @@ -2869,7 +2868,7 @@ void TraingModel::GetPointData() { if (canvasData.size() > MAX_CANVAS_POINTS) { uniformSampleToMax(canvasData, MAX_CANVAS_POINTS); WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, - "画布点超限,已均匀采样至 %zu 点(最多300点)", canvasData.size()); + "画布点超限,已均匀采样至 %zu 点(最多300点)", canvasData.size()); } WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, @@ -2877,7 +2876,7 @@ void TraingModel::GetPointData() { gpsData.size(), canvasData.size()); } -// 地球平均半径(米),用于Haversine公式 +// 地球平均半径(米),用于Haversine公式 static const double EARTH_RADIUS_M = 6371000.0; static const double DEG_TO_RAD = 3.141592653589793 / 180.0; @@ -2903,8 +2902,8 @@ static double haversineDistanceM(double lat1, double lon1, double lat2, double l /** * @brief 根据GPS轨迹点逐段累加计算总距离(米) - * 用于骑行等CYWEE不输出距离时,用GPS点位补算 - * @return 总距离(米),点数<2时返回0 + * 用于骑行等CYWEE不输出距离时,用GPS点位补算 + * @return 总距离(米),点数<2时返回0 */ uint32_t TraingModel::CalculateDistanceFromGPSTrack(void) { if (gpsData.size() < 2) { @@ -3033,7 +3032,7 @@ uint32_t TraingModel::CalculateDistanceFromGPSTrack(void) { return exactFilePath; // 返回完全匹配的文件路径 } - // 如果未找到,检查时间戳相差1到2秒的文件 + // 如果未找到,检查时间戳相差1到2秒的文件 for (int i = -2; i <= 2; ++i) { uint32_t checkTimestamp = timestamp + i; std::string filePath = @@ -3120,7 +3119,7 @@ uint32_t TraingModel::CalculateDistanceFromGPSTrack(void) { return exactFilePath; // 返回完全匹配的文件路径 } - // 如果未找到,检查时间戳相差1到2秒的文件 + // 如果未找到,检查时间戳相差1到2秒的文件 for (int i = -2; i <= 2; ++i) { uint32_t checkTimestamp = timestamp + i; std::string filePath = @@ -3188,46 +3187,19 @@ bool TraingModel::LoadGPSData(const std::string &filePath) { // SystemLogModel::GetInstance()->save_gps_status_log_type(gpsconnect); WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "GPS状态变化记录完成"); } else { - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "GPS连接状态未发生变化,保持: %d", + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "GPS连接状态未发生变化,保持: %d", gpsconnect); } WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "=== GPS连接状态设置完成 ==="); } -// 延迟关闭 GNSS:10 秒内若训练重新开启,则取消关闭 -#if defined(SUPPORT_GNSS) -static osTimerId_t g_delayed_gnss_stop_timer = nullptr; -static uint32_t g_gnss_stop_request_token = 0; -static uint32_t g_gnss_stop_execute_token = 0; - -static void gnss_delayed_stop_timer_callback(void *arg) { - unused(arg); - TraingModel *model = TraingModel::GetInstance(); - if (model == nullptr) { - return; - } - // 仅当有新的 GPS 开启动作时取消关闭,避免非GPS运动误取消。 - if (g_gnss_stop_execute_token != g_gnss_stop_request_token) { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, - "取消本次GPS延迟关闭: execute_token=%u request_token=%u", - g_gnss_stop_execute_token, g_gnss_stop_request_token); - return; - } - GraphicService::GetInstance()->PostGraphicEvent([]() { - TraingModel *m = TraingModel::GetInstance(); - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "10s后异步执行gnss_stop()"); - gnss_stop(); - if (m != nullptr) { - m->SetGpsOpen(false); - } - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "gnss_stop()调用完成"); - }); -} -#endif - -//运动心率开启准备 + //运动心率、gps开启准备 void TraingModel::start_training_heart() { - // 心率统一通过 HeartModel 接口控制 - HeartModel::GetInstance()->SwitchPpgHeartSensor(true); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "开始启动GPS定位服务..."); + //开启心率检测 + #ifdef SUPPORT_PPG_SERVICE + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "启动心率检测服务"); + ppg_hr_start(); + #endif //提前设置训练状态为1 uapi_dev_runtime_set_train_status(1); } @@ -3235,37 +3207,24 @@ static void gnss_delayed_stop_timer_callback(void *arg) { void TraingModel::stop_heart_gps() { if (gpsopen == true) { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "开始关闭GPS定位服务..."); + // 关闭gps #if defined(SUPPORT_GNSS) - // 延迟 10 秒再真正执行 gnss_stop;若期间重新打开训练,则取消这次关闭。 - g_gnss_stop_request_token++; - g_gnss_stop_execute_token = g_gnss_stop_request_token; - - if (g_delayed_gnss_stop_timer == nullptr) { - g_delayed_gnss_stop_timer = - osTimerNew((osTimerFunc_t)gnss_delayed_stop_timer_callback, - osTimerOnce, nullptr, nullptr); - } - - if (g_delayed_gnss_stop_timer != nullptr) { - osTimerStop(g_delayed_gnss_stop_timer); - osStatus_t ret = osTimerStart(g_delayed_gnss_stop_timer, osMs2Tick(5 * 1000)); - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, - "已发起GPS延迟关闭(5s), token=%u, ret=%ld", - g_gnss_stop_request_token, (long)ret); - } else { - // 定时器创建失败时兜底:立即关闭,避免资源悬挂 - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "GPS延迟关闭定时器创建失败,立即执行gnss_stop()"); - GraphicService::GetInstance()->PostGraphicEvent([]() { - gnss_stop(); - }); - } - - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, - "GPS延迟关闭已安排,等待10s确认后再真正关闭"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "调用gnss_stop()关闭GPS服务"); + // GraphicService::GetInstance()->PostGraphicEvent([]() { + // WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "异步执行gnss_stop()"); + // gnss_stop(); + // WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "gnss_stop()调用完成"); + // }); + gnss_stop(); + gpsopen = false; + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "GPS定位服务关闭完成,gpsopen设置为false"); #endif } - // 心率统一通过 HeartModel 接口控制,延迟 3 秒关闭防抖 - HeartModel::GetInstance()->SwitchPpgHeartSensor(false); + //关闭心率检测 + #ifdef SUPPORT_PPG_SERVICE + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "关闭心率检测服务"); + ppg_hr_stop(); + #endif //设置训练状态为0 uapi_dev_runtime_set_train_status(0); @@ -3282,34 +3241,33 @@ void TraingModel::SetGpsOpen(bool open) { /////////////////////////////////////位置服务定时器///////////////////////////////////// /* * 位置服务定时器说明: - * - 功能:负责获取GPS定位数据,更新GPS连接状态,添加经纬度数据 - * - 频率:2秒间隔(GPS打点频率),平衡精度与功耗 - * * 2秒频率的优势:比1秒节省约50%电量,轨迹精度足够(跑步/骑行等运动) - * * 参考:专业运动手表通常使用1-2秒频率,消费级手表2-5秒 + * - 功能:负责获取GPS定位数据,更新GPS连接状态,添加经纬度数据 + * - 频率:2秒间隔(GPS打点频率),平衡精度与功耗 + * * 2秒频率的优势:比1秒节省约50%电量,轨迹精度足够(跑步/骑行等运动) + * * 参考:专业运动手表通常使用1-2秒频率,消费级手表2-5秒 * - 触发条件:仅在训练进行中且训练状态非结束时执行 */ static osTimerId_t g_location_timer = nullptr; - static int location_timer_interval = 2; // 位置数据获取间隔,单位秒(GPS打点频率) + static int location_timer_interval = 2; // 位置数据获取间隔,单位秒(GPS打点频率) static int gps_timer_count = 0; /*位置服务定时器到期时的处理*/ static void gnss_timer_callbackProc(int data) { /* GPS数据获取处理 - 1、目前gps注册有问题 ;需要延迟2s 去开启gps; + 1、目前gps注册有问题 ;需要延迟5s 去开启gps; */ gps_timer_count++; - if (gps_timer_count < 2) { + if (gps_timer_count < 5) { return; } #if defined(SUPPORT_GNSS) /* 延迟 2 秒后首次开启 GPS(规避 gps 注册时序问题) */ TraingModel *model = TraingModel::GetInstance(); - if (gps_timer_count == 2 && model != nullptr && !model->GetGpsOpen()) { + if (gps_timer_count == 5 && model != nullptr && !model->GetGpsOpen()) { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "开启gps"); GraphicService::GetInstance()->PostGraphicEvent([]() { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "开始启动GPS定位服务..."); WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "异步执行gnss_start()"); gnss_start(); }); @@ -3345,7 +3303,7 @@ void TraingModel::SetGpsOpen(bool open) { return; } - // 如果定位成功,添加经纬度数据 + // 如果定位成功,添加经纬度数据 if (isGpsConnected) { uint32_t time = TraingModel::GetInstance()->get_current_time(); TraingModel::GetInstance()->AddGPSData(time, send_gps_data.location.lat, @@ -3358,13 +3316,13 @@ void TraingModel::SetGpsOpen(bool open) { /* * @brief 位置服务定时器回调函数 - * 倒计时期间定时器照常触发,但不投递到 GUI、不执行逻辑,避免与倒计时动画抢线程 + * 倒计时期间定时器照常触发,但不投递到 GUI、不执行逻辑,避免与倒计时动画抢线程 */ static void gnss_timer_callback(int data) { WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "gnss_timer_callback %d", data); #if defined(SUPPORT_GNSS) if (NativeAbility::GetInstance().GetCurSliceId() == VIEW_SPORT_COUNTDOWN) { - return; // 当前在运动倒计时 slice,只正常定时,不操作 + return; // 当前在运动倒计时 slice,只正常定时,不操作 } #endif GraphicService::GetInstance()->PostGraphicEvent( @@ -3373,30 +3331,21 @@ static void gnss_timer_callback(int data) { /* * @brief 开启位置服务定时器函数 - * @param interval 时间间隔,单位ms + * @param interval 时间间隔,单位ms */ void TraingModel::gnss_start_timer(uint32_t interval) { WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "=== GPS定时器启动流程开始 ==="); WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "定时器间隔: %u ms", interval); WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "当前定时器状态: %p", g_location_timer); -#if defined(SUPPORT_GNSS) - // 所有真实的 GPS 开启动作都在这里统一取消“延迟关闭” - g_gnss_stop_request_token++; - if (g_delayed_gnss_stop_timer != nullptr) { - osTimerStop(g_delayed_gnss_stop_timer); - } - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "取消待执行的GPS延迟关闭请求, token=%u", - g_gnss_stop_request_token); -#endif - /* -------------------------- 1.检查位置服务定时器是否已经存在,如果存在则返回 + /* -------------------------- 1.检查位置服务定时器是否已经存在,如果存在则返回 * ------------------------- */ if (g_location_timer != nullptr) { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "错误: GPS定时器已存在,跳过创建"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "错误: GPS定时器已存在,跳过创建"); return; } - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "GPS定时器不存在,开始创建..."); + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "GPS定时器不存在,开始创建..."); /* --------------------------------- 2.创建位置服务定时器 * -------------------------------- */ @@ -3421,7 +3370,7 @@ static void gnss_timer_callback(int data) { * -------------------------------- */ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "启动GPS定时器..."); osStatus_t ret = osTimerStart(g_location_timer, tick); - /* -------------------- 5.检查位置服务定时器启动是否成功,如果启动失败,删除定时器并置为 + /* -------------------- 5.检查位置服务定时器启动是否成功,如果启动失败,删除定时器并置为 * nullptr -------------------- */ if (ret != osOK) { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, @@ -3450,7 +3399,7 @@ static void gnss_timer_callback(int data) { // 检查位置服务定时器是否存在 if (g_location_timer != nullptr) { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "GPS定时器存在,开始停止流程..."); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "GPS定时器存在,开始停止流程..."); WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "停止GPS定时器..."); osTimerStop(g_location_timer); @@ -3469,7 +3418,7 @@ static void gnss_timer_callback(int data) { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "GPS定时器指针已置空"); WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "=== GPS定时器停止流程结束 ==="); } else { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "GPS定时器不存在,跳过停止流程"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "GPS定时器不存在,跳过停止流程"); WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "=== GPS定时器停止流程结束(无需停止) ==="); } @@ -3479,15 +3428,15 @@ static void gnss_timer_callback(int data) { ///////////////////////////////////////运动数据采集定时器////////////////////////////////// /* * 运动数据采集定时器说明: - * - 功能:负责获取运动数据(步数、距离、卡路里、心率等),更新训练目标完成度 - * - 频率:300ms间隔,保证运动数据的实时性和准确性 + * - 功能:负责获取运动数据(步数、距离、卡路里、心率等),更新训练目标完成度 + * - 频率:300ms间隔,保证运动数据的实时性和准确性 * - 触发条件:仅在训练进行中且训练状态非结束时执行 * - 包含服务:CYWEE运动数据、PPG心率数据、训练目标检查、UI更新 */ #if SPORT_TIMER_DATA // 声明运动数据采集定时器变量 static osTimerId_t g_sport_start_data_timer = nullptr; - static int sport_start_data_timer_interval = 300; // 运动数据获取间隔,单位毫秒 + static int sport_start_data_timer_interval = 300; // 运动数据获取间隔,单位毫秒 /* * @brief 获取运动基础数据 @@ -3520,7 +3469,7 @@ static void gnss_timer_callback(int data) { /* * @brief 获取心率数据 - * @return 获取到的心率值,如果服务不支持则返回0 + * @return 获取到的心率值,如果服务不支持则返回0 */ uint8_t TraingModel::GetHeartRateData(void) { uint8_t hrs = 0; @@ -3651,7 +3600,7 @@ static void gnss_timer_callback(int data) { WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "获取到的GPS路径: %s", str.c_str()); if (str.length() <= 3) { - WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "错误: GPS路径长度不足,长度: %zu", + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "错误: GPS路径长度不足,长度: %zu", str.length()); WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "=== 获取GPS轨迹路径结束(失败) ==="); return false; @@ -3786,7 +3735,7 @@ static void gnss_timer_callback(int data) { "GPS点数据转换: 时间戳=%u, 纬度=%d, 经度=%d", temp_data, temp_latitude, temp_longitude); } else { - WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "GPS文件读取结束,读取大小: %d", + WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "GPS文件读取结束,读取大小: %d", read_size); break; } @@ -3795,7 +3744,7 @@ static void gnss_timer_callback(int data) { fclose(fp); WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "GPS文件关闭"); WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, - "总共读取 %d 个GPS点,输出数据长度: %d 字节", point_count, len); + "总共读取 %d 个GPS点,输出数据长度: %d 字节", point_count, len); WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "=== 读取GPS数据结束 ==="); return len; @@ -3915,20 +3864,20 @@ static void gnss_timer_callback(int data) { * 1. 位置服务定时器 (g_location_timer) * - 频率:1秒间隔 * - 功能:GPS定位、连接状态更新、轨迹数据采集 - * - 特点:中等频率,保证位置数据实时性 + * - 特点:中等频率,保证位置数据实时性 * * 2. 运动数据采集定时器 (g_sport_start_data_timer) * - 频率:300毫秒间隔 * - 功能:运动数据采集、心率监测、目标完成度检查、UI更新 - * - 特点:高频率,保证运动数据实时性和准确性 + * - 特点:高频率,保证运动数据实时性和准确性 * - * 数据获取函数封装(职责单一,无耦合): - * - GetSportActivityData(): 获取运动基础数据,返回是否成功 - * - GetSportExtraData(): 获取运动额外数据,返回是否成功 - * - GetHeartRateData(): 获取心率数据,返回心率值 + * 数据获取函数封装(职责单一,无耦合): + * - GetSportActivityData(): 获取运动基础数据,返回是否成功 + * - GetSportExtraData(): 获取运动额外数据,返回是否成功 + * - GetHeartRateData(): 获取心率数据,返回心率值 * - 数据分析和处理逻辑在定时器回调中协调完成 * - * 两个定时器独立运行,互不干扰,根据各自功能特点选择合适的执行频率 + * 两个定时器独立运行,互不干扰,根据各自功能特点选择合适的执行频率 */ } // namespace OHOS diff --git a/code/sdk/zhihui/services/gnss/src/uart_gnss.c b/code/sdk/zhihui/services/gnss/src/uart_gnss.c index 129d36413..327d6df1e 100644 --- a/code/sdk/zhihui/services/gnss/src/uart_gnss.c +++ b/code/sdk/zhihui/services/gnss/src/uart_gnss.c @@ -215,7 +215,10 @@ static void uart_event_task(void const *arg) } } if(mail.cmd == GNSS_CMD_READDATA) + { osal_kfree(mail.buffer); //只有接收的缓存需要free,发送的都是静态数组,无需申请缓存 + mail.buffer = NULL; + } } } -- 2.17.1