#include "NativeAbility.h"
#include "AppViewIDs.h"
#include "sport_countdown/CountdownPresenter.h"
-#include "heartrate/include/HeartModel.h"
#if defined(SUPPORT_GNSS)
#include "NMEA0183.h"
// 计算平均心率的函数
double CalculateAverageHeartRate(const std::vector<int> &heartRates) {
if (heartRates.size() <= 2) {
- // 如果心率数据点少于等于2,无法去掉最高和最低值
+ // 如果心率数据点少于等于2,无法去掉最高和最低值
return 0.0; // 或者返回心率的平均值
}
"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
#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())) {
restshock_count++;
shock_count = 0;
if (restshock_count >= 5) {
- restshock_count = 0; /* 休息满 5 次,下一轮可再震 */
+ restshock_count = 0; /* 休息满 5 次,下一轮可再震 */
}
}
}
"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;
"UpdateFastestPace: fpc=%d秒/公里", sportdata->fpc);
}
} else if (cyweeInfo->max_pace != 0) {
- // 如果当前配速为0,使用CYWEE提供的最快配速作为后备
+ // 如果当前配速为0,使用CYWEE提供的最快配速作为后备
sportdata->fpc = cyweeInfo->max_pace;
}
//平均步频
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_);
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SaveSportData error!");
}
#else
- //运动数据达标,存储运动数据
+ //运动数据达标,存储运动数据
if (MomentumFlag) {
// GetGoaldegree(); // 设置目标完成度
if (SaveSportData()) {
maxHeap.push(newHeartRate);
minHeap.push(newHeartRate);
- // 如果超过窗口大小,移除最早的心率
+ // 如果超过窗口大小,移除最早的心率
if (heartRateData.size() > windowSize) {
int oldestRate = heartRateData[0];
totalHeartRate -= oldestRate;
"新心率: %d, 当前心率总和: %d, 心率计数: %d", newHeartRate,
totalHeartRate, countHeartRate);
- // 如果心率数量少于 3,直接返回当前的平均值
+ // 如果心率数量少于 3,直接返回当前的平均值
if (countHeartRate < 3) {
return totalHeartRate / countHeartRate; // 无法去除最大最小值
}
// 将新的心率添加到最近心率列表
recentHeartRates.push_back(newHeartRate);
- // 如果超过窗口大小,移除最早的心率
+ // 如果超过窗口大小,移除最早的心率
if (recentHeartRates.size() > windowSize) {
recentHeartRates.erase(recentHeartRates.begin());
}
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();
}
/*
- 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();
}
}
- // 如果所有操作成功,则恢复训练存储状态
+ // 如果所有操作成功,则恢复训练存储状态
uapi_dev_runtime_set_train_storage_status(0);
return true;
}
MomentumFlag = false;
}
- // 如果是需要GPS定位的运动,需要判断移动距离是否大于100m,不然轨迹可能异常
- // 但是目前轨迹没有距离,先不判断
+ // 如果是需要GPS定位的运动,需要判断移动距离是否大于100m,不然轨迹可能异常
+ // 但是目前轨迹没有距离,先不判断
if ((IsNeedGPS(sportdata->sportId))&&(sportdata->sportId!=UIResourceTextId::STR_EXERCISE_OUTDOORBIKING)) {
if (sportdata->distance < 100) {
MomentumFlag = false;
void TraingModel::PrintHeartRateTable() {
size_t heartRateCount = heartRateTable.size();
if (heartRateCount == 0) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "心率表为空,无法打印。");
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "心率表为空,无法打印。");
return;
}
void TraingModel::PrintPaceTable() {
size_t paceCount = paceTable.size();
if (paceCount == 0) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "配速表为空,无法打印。");
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "配速表为空,无法打印。");
return;
}
size_t heartRateCount = heartRateTable.size();
if (heartRateCount == 0) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "心率表为空,无法保存。");
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "心率表为空,无法保存。");
return false;
}
size_t paceCount = paceTable.size();
if (paceCount == 0) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "配速表为空,无法保存。");
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "配速表为空,无法保存。");
return false;
}
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";
return exactFilePath; // 返回完全匹配的文件路径
}
- // 如果未找到,检查时间戳相差5秒的文件
+ // 如果未找到,检查时间戳相差5秒的文件
for (int i = -5; i <= 5; ++i) {
uint32_t checkTimestamp = timestamp + i;
std::string filePath =
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();
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);
}
// }
// lastCallTime = currentTime; // 更新最后调用时间
- // 如果 g_motionTimes 不为零,进行计算和数据存储
+ // 如果 g_motionTimes 不为零,进行计算和数据存储
if (g_motionTimes > 0) {
sportdata->duration = g_motionTimes; // 设置训练时长
// 获得数据个数
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));
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) {
/* 加载训练数据函数 */
/* 加载训练数据函数 */
bool TraingModel::LoadDataFormJson(std::vector<SportData> &sportDataVector) {
- // 清空输出向量,避免旧数据干扰
+ // 清空输出向量,避免旧数据干扰
sportDataVector.clear();
// 打开JSON文件
if (item == NULL) {
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
"Null item at index %d in 'data' array", i);
- continue; // 跳过无效项,继续处理其他项
+ continue; // 跳过无效项,继续处理其他项
}
SportData sportData;
WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Parsed starttime: %d",
sportData.starttime);
} else {
- // 打印详细信息,帮助定位问题
+ // 打印详细信息,帮助定位问题
const char *valueStr =
starttimeItem->valuestring ? starttimeItem->valuestring : "null";
WEARABLE_LOGE(
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; }
// 线段长度的平方
double len2 = dx * dx + dy * dy;
- // 如果线段退化为一个点,直接计算点到点的距离
+ // 如果线段退化为一个点,直接计算点到点的距离
if (len2 == 0) {
return std::hypot(p.x - p1.x, p.y - p1.y);
}
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);
static void douglasPeucker(const std::vector<Point> &points, double epsilon,
std::vector<Point> &result) {
if (points.size() <= 2) {
- // 点数量不足,直接返回
+ // 点数量不足,直接返回
result = points;
return;
}
}
}
- // 如果最大距离大于阈值,则递归处理
+ // 如果最大距离大于阈值,则递归处理
if (dmax > epsilon) {
std::vector<Point> recResults1, recResults2;
}
}
-// 手表轨迹画布最大点数,控制内存与绘制性能
+// 手表轨迹画布最大点数,控制内存与绘制性能
static const size_t MAX_CANVAS_POINTS = 300;
/**
- * @brief 将画布点集均匀采样至最多 maxPoints 个点(保留首尾,中间等间隔取点)
+ * @brief 将画布点集均匀采样至最多 maxPoints 个点(保留首尾,中间等间隔取点)
*/
static void uniformSampleToMax(std::vector<Point> &points, size_t maxPoints) {
if (points.size() <= maxPoints) return;
}
/**
- * @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;
}
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,
gpsData.size(), canvasData.size());
}
-// 地球平均半径(米),用于Haversine公式
+// 地球平均半径(米),用于Haversine公式
static const double EARTH_RADIUS_M = 6371000.0;
static const double DEG_TO_RAD = 3.141592653589793 / 180.0;
/**
* @brief 根据GPS轨迹点逐段累加计算总距离(米)
- * 用于骑行等CYWEE不输出距离时,用GPS点位补算
- * @return 总距离(米),点数<2时返回0
+ * 用于骑行等CYWEE不输出距离时,用GPS点位补算
+ * @return 总距离(米),点数<2时返回0
*/
uint32_t TraingModel::CalculateDistanceFromGPSTrack(void) {
if (gpsData.size() < 2) {
return exactFilePath; // 返回完全匹配的文件路径
}
- // 如果未找到,检查时间戳相差1到2秒的文件
+ // 如果未找到,检查时间戳相差1到2秒的文件
for (int i = -2; i <= 2; ++i) {
uint32_t checkTimestamp = timestamp + i;
std::string filePath =
return exactFilePath; // 返回完全匹配的文件路径
}
- // 如果未找到,检查时间戳相差1到2秒的文件
+ // 如果未找到,检查时间戳相差1到2秒的文件
for (int i = -2; i <= 2; ++i) {
uint32_t checkTimestamp = timestamp + i;
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);
}
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);
/////////////////////////////////////位置服务定时器/////////////////////////////////////
/*
* 位置服务定时器说明:
- * - 功能:负责获取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();
});
return;
}
- // 如果定位成功,添加经纬度数据
+ // 如果定位成功,添加经纬度数据
if (isGpsConnected) {
uint32_t time = TraingModel::GetInstance()->get_current_time();
TraingModel::GetInstance()->AddGPSData(time, send_gps_data.location.lat,
/*
* @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(
/*
* @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.创建位置服务定时器
* -------------------------------- */
* -------------------------------- */
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,
// 检查位置服务定时器是否存在
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);
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定时器停止流程结束(无需停止) ===");
}
///////////////////////////////////////运动数据采集定时器//////////////////////////////////
/*
* 运动数据采集定时器说明:
- * - 功能:负责获取运动数据(步数、距离、卡路里、心率等),更新训练目标完成度
- * - 频率: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 获取运动基础数据
/*
* @brief 获取心率数据
- * @return 获取到的心率值,如果服务不支持则返回0
+ * @return 获取到的心率值,如果服务不支持则返回0
*/
uint8_t TraingModel::GetHeartRateData(void) {
uint8_t hrs = 0;
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;
"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;
}
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;
* 1. 位置服务定时器 (g_location_timer)
* - 频率:1秒间隔
* - 功能:GPS定位、连接状态更新、轨迹数据采集
- * - 特点:中等频率,保证位置数据实时性
+ * - 特点:中等频率,保证位置数据实时性
*
* 2. 运动数据采集定时器 (g_sport_start_data_timer)
* - 频率:300毫秒间隔
* - 功能:运动数据采集、心率监测、目标完成度检查、UI更新
- * - 特点:高频率,保证运动数据实时性和准确性
+ * - 特点:高频率,保证运动数据实时性和准确性
*
- * 数据获取函数封装(职责单一,无耦合):
- * - GetSportActivityData(): 获取运动基础数据,返回是否成功
- * - GetSportExtraData(): 获取运动额外数据,返回是否成功
- * - GetHeartRateData(): 获取心率数据,返回心率值
+ * 数据获取函数封装(职责单一,无耦合):
+ * - GetSportActivityData(): 获取运动基础数据,返回是否成功
+ * - GetSportExtraData(): 获取运动额外数据,返回是否成功
+ * - GetHeartRateData(): 获取心率数据,返回心率值
* - 数据分析和处理逻辑在定时器回调中协调完成
*
- * 两个定时器独立运行,互不干扰,根据各自功能特点选择合适的执行频率
+ * 两个定时器独立运行,互不干扰,根据各自功能特点选择合适的执行频率
*/
} // namespace OHOS