#include "uicomponents/UIComponents.h"
#include "wearable_log.h"
#include <cmsis_os2.h>
+#include <cstdint>
#include <fstream>
#include <iomanip>
#include <iostream>
uint8_t heart = *((u_int8_t *)(request->data)); // 进行类型转换
TraingModel::GetInstance()->AnalysisHeartData(heart);
}
+#if 0
+ //使用随机数来进行测试
+ srand(time(NULL));
+ // 纬度范围: 22.45° 到 22.87° ,适当扩大一点范围
+ float lat = (rand() % 420) / 10.0f + 224.5;
+ lat = lat / 10.0f;
+ // 经度范围: 113.75° 到 114.64° ,适当扩大一点范围
+ float lng = (rand() % 890) / 10.0f + 1137.5;
+ lng = lng / 10.0f;
+ TraingModel::GetInstance()->AddGPSData(0, lat, lng);
+ return;
+#endif
#if defined(SUPPORT_GNSS)
//训练GPS
gps_data_t *gps_data = getGPSGlobaldata();
}
//判断是否定位成功
if (send_gps_data.status > 1) {
- //添加经纬度 时间戳?
- TraingModel::GetInstance()->AddGPSData(0,send_gps_data.location.lat,
+ //添加经纬度
+ uint32_t time = TraingModel::GetInstance()->get_current_time();
+ TraingModel::GetInstance()->AddGPSData(time, send_gps_data.location.lat,
send_gps_data.location.lng);
}
+ return;
#endif
}
#ifdef __cplusplus
sportdata->spc = data->spc;
sportdata->std = data->std;
sportdata->cdc = data->cdc;
- printf_data(data); //打印该运动数据
- IsSpecialSport(sportdata->sportId); // 配置训练特殊性
+ sportdata->starttime = data->starttime; //更新开始时间
+ printf_data(data); //打印该运动数据
+ IsSpecialSport(sportdata->sportId); // 配置训练特殊性
}
}
/*获取训练卡路里*/
/* 设置训练强度 */
void TraingModel::SetIntensity(int heart) {
// sportdata->intensity = active_state;
-#if 1
/*
训练强度
220-年龄=最高心率
WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,
"maxHeartRate: %d, heartRate: %d, intensityPercentage: %.2f",
maxHeartRate, heart, intensityPercentage);
-#endif
}
/*获取训练强度STR*/
UIResourceTextId TraingModel::GetIntensity() {
// uapi_dev_runtime_set_train_storage_status(0); // 恢复状态
// return false;
}
+ // 保存GPS数据
+ if (!SaveCanvasData()) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SaveGpsData is error!");
+ // uapi_dev_runtime_set_train_storage_status(0); // 恢复状态
+ // return false;
+ }
}
// 如果所有操作成功,则恢复训练存储状态
cJSON_AddNumberToObject(sportData, "cdc", data->cdc); // 训练步频
cJSON_AddNumberToObject(sportData, "std", data->std); // 训练步幅
cJSON_AddNumberToObject(sportData, "calories", data->calories); //卡路里
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "starttime is %d", data->starttime);
+ cJSON_AddNumberToObject(sportData, "start_time",
+ data->starttime); // 开始时间戳
// 添加运动数据节点到数组并限制数量
cJSON_AddItemToArray(dataArray, sportData);
return true;
}
+/* 加载训练数据函数 */
/* 加载训练数据函数 */
bool TraingModel::LoadDataFormJson(std::vector<SportData> &sportDataVector) {
+ // 清空输出向量,避免旧数据干扰
+ sportDataVector.clear();
+
+ // 打开JSON文件
std::ifstream file(TRAINING_RECORD_FILE);
if (!file.is_open()) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to open file");
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to open file: %s",
+ TRAINING_RECORD_FILE);
return false;
}
+ // 读取文件内容到字符串
std::string jsonData((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
file.close();
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Read %zu bytes from JSON file",
+ jsonData.size());
+
+ // 解析JSON根对象
cJSON *root = cJSON_Parse(jsonData.c_str());
if (root == NULL) {
+ const char *errorPtr = cJSON_GetErrorPtr();
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Failed to parse JSON: %s",
- cJSON_GetErrorPtr());
+ errorPtr ? errorPtr : "Unknown error");
return false;
}
+ // 查找并验证data数组
cJSON *dataArray = cJSON_GetObjectItem(root, "data");
- if (dataArray == NULL || !cJSON_IsArray(dataArray)) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
- "Invalid or missing 'data' array in JSON");
+ if (dataArray == NULL) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Missing 'data' array in JSON");
+ cJSON_Delete(root);
+ return false;
+ }
+ if (!cJSON_IsArray(dataArray)) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "'data' is not an array in JSON");
cJSON_Delete(root);
return false;
}
+ // 检查数组大小
int dataCount = cJSON_GetArraySize(dataArray);
if (dataCount == 0) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "error dataCount is 0");
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Empty 'data' array in JSON");
cJSON_Delete(root);
return false;
}
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "dataCount is %d", dataCount);
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Found %d items in 'data' array",
+ dataCount);
+ // 遍历解析每个数据项
for (int i = 0; i < dataCount; i++) {
cJSON *item = cJSON_GetArrayItem(dataArray, i);
if (item == NULL) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid item at index %d", i);
- continue; // 跳过无效项目
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+ "Null item at index %d in 'data' array", i);
+ continue; // 跳过无效项,继续处理其他项
}
SportData sportData;
- bool isValid = true; // 用于标记 sportData 是否有效
+ bool isValid = true;
+ std::string missingFields; // 记录缺失的字段
- // 检查并获取每个字段,确保其存在且类型正确
- if (cJSON *sportTypeIdItem = cJSON_GetObjectItem(item, "sportTypeId");
- sportTypeIdItem && cJSON_IsNumber(sportTypeIdItem))
- sportData.sportType = (Exercisetype)sportTypeIdItem->valueint;
- else
+ // 解析sportTypeId字段
+ if (cJSON *sportTypeIdItem = cJSON_GetObjectItem(item, "sportTypeId")) {
+ if (cJSON_IsNumber(sportTypeIdItem)) {
+ sportData.sportType = (Exercisetype)sportTypeIdItem->valueint;
+ } else {
+ isValid = false;
+ missingFields += "sportTypeId ";
+ }
+ } else {
isValid = false;
+ missingFields += "sportTypeId ";
+ }
- if (cJSON *sportIdItem = cJSON_GetObjectItem(item, "sportId");
- sportIdItem && cJSON_IsNumber(sportIdItem))
- sportData.sportId = (UIResourceTextId)sportIdItem->valueint;
- else
+ // 解析sportId字段
+ if (cJSON *sportIdItem = cJSON_GetObjectItem(item, "sportId")) {
+ if (cJSON_IsNumber(sportIdItem)) {
+ sportData.sportId = (UIResourceTextId)sportIdItem->valueint;
+ } else {
+ isValid = false;
+ missingFields += "sportId ";
+ }
+ } else {
isValid = false;
+ missingFields += "sportId ";
+ }
- if (cJSON *startDateItem = cJSON_GetObjectItem(item, "startDate");
- startDateItem && cJSON_IsString(startDateItem))
- sportData.start_date = startDateItem->valuestring;
- else
+ // 解析startDate字段
+ if (cJSON *startDateItem = cJSON_GetObjectItem(item, "startDate")) {
+ if (cJSON_IsString(startDateItem) && startDateItem->valuestring) {
+ sportData.start_date = startDateItem->valuestring;
+ } else {
+ isValid = false;
+ missingFields += "startDate ";
+ }
+ } else {
isValid = false;
+ missingFields += "startDate ";
+ }
- if (cJSON *startTimeItem = cJSON_GetObjectItem(item, "startTime");
- startTimeItem && cJSON_IsString(startTimeItem))
- sportData.start_time = startTimeItem->valuestring;
- else
+ // 解析startTime字段
+ if (cJSON *startTimeItem = cJSON_GetObjectItem(item, "startTime")) {
+ if (cJSON_IsString(startTimeItem) && startTimeItem->valuestring) {
+ sportData.start_time = startTimeItem->valuestring;
+ } else {
+ isValid = false;
+ missingFields += "startTime ";
+ }
+ } else {
isValid = false;
+ missingFields += "startTime ";
+ }
- if (cJSON *endTimeItem = cJSON_GetObjectItem(item, "endTime");
- endTimeItem && cJSON_IsString(endTimeItem))
- sportData.end_time = endTimeItem->valuestring;
- else
+ // 解析endTime字段
+ if (cJSON *endTimeItem = cJSON_GetObjectItem(item, "endTime")) {
+ if (cJSON_IsString(endTimeItem) && endTimeItem->valuestring) {
+ sportData.end_time = endTimeItem->valuestring;
+ } else {
+ isValid = false;
+ missingFields += "endTime ";
+ }
+ } else {
isValid = false;
+ missingFields += "endTime ";
+ }
- if (cJSON *goalDegreeItem = cJSON_GetObjectItem(item, "goalDegree");
- goalDegreeItem && cJSON_IsNumber(goalDegreeItem))
- sportData.goaldegree = goalDegreeItem->valueint;
- else
+ // 解析goalDegree字段
+ if (cJSON *goalDegreeItem = cJSON_GetObjectItem(item, "goalDegree")) {
+ if (cJSON_IsNumber(goalDegreeItem)) {
+ sportData.goaldegree = goalDegreeItem->valueint;
+ } else {
+ isValid = false;
+ missingFields += "goalDegree ";
+ }
+ } else {
isValid = false;
+ missingFields += "goalDegree ";
+ }
- if (cJSON *durationItem = cJSON_GetObjectItem(item, "duration");
- durationItem && cJSON_IsNumber(durationItem))
- sportData.duration = durationItem->valueint;
- else
+ // 解析duration字段
+ if (cJSON *durationItem = cJSON_GetObjectItem(item, "duration")) {
+ if (cJSON_IsNumber(durationItem)) {
+ sportData.duration = durationItem->valueint;
+ } else {
+ isValid = false;
+ missingFields += "duration ";
+ }
+ } else {
isValid = false;
+ missingFields += "duration ";
+ }
- if (cJSON *distanceItem = cJSON_GetObjectItem(item, "distance");
- distanceItem && cJSON_IsNumber(distanceItem))
- sportData.distance = distanceItem->valueint;
- else
+ // 解析distance字段
+ if (cJSON *distanceItem = cJSON_GetObjectItem(item, "distance")) {
+ if (cJSON_IsNumber(distanceItem)) {
+ sportData.distance = distanceItem->valueint;
+ } else {
+ isValid = false;
+ missingFields += "distance ";
+ }
+ } else {
isValid = false;
+ missingFields += "distance ";
+ }
- if (cJSON *avgHeartRateItem = cJSON_GetObjectItem(item, "avgHeartRate");
- avgHeartRateItem && cJSON_IsNumber(avgHeartRateItem))
- sportData.avgheart = avgHeartRateItem->valueint;
- else
+ // 解析avgHeartRate字段
+ if (cJSON *avgHeartRateItem = cJSON_GetObjectItem(item, "avgHeartRate")) {
+ if (cJSON_IsNumber(avgHeartRateItem)) {
+ sportData.avgheart = avgHeartRateItem->valueint;
+ } else {
+ isValid = false;
+ missingFields += "avgHeartRate ";
+ }
+ } else {
isValid = false;
+ missingFields += "avgHeartRate ";
+ }
- if (cJSON *stepsItem = cJSON_GetObjectItem(item, "steps");
- stepsItem && cJSON_IsNumber(stepsItem))
- sportData.steps = stepsItem->valueint;
- else
+ // 解析steps字段
+ if (cJSON *stepsItem = cJSON_GetObjectItem(item, "steps")) {
+ if (cJSON_IsNumber(stepsItem)) {
+ sportData.steps = stepsItem->valueint;
+ } else {
+ isValid = false;
+ missingFields += "steps ";
+ }
+ } else {
isValid = false;
+ missingFields += "steps ";
+ }
- if (cJSON *intensityItem = cJSON_GetObjectItem(item, "intensity");
- intensityItem && cJSON_IsNumber(intensityItem))
- sportData.intensity = intensityItem->valueint;
- else
+ // 解析intensity字段
+ if (cJSON *intensityItem = cJSON_GetObjectItem(item, "intensity")) {
+ if (cJSON_IsNumber(intensityItem)) {
+ sportData.intensity = intensityItem->valueint;
+ } else {
+ isValid = false;
+ missingFields += "intensity ";
+ }
+ } else {
isValid = false;
+ missingFields += "intensity ";
+ }
- if (cJSON *apcItem = cJSON_GetObjectItem(item, "apc");
- apcItem && cJSON_IsNumber(apcItem))
- sportData.apc = apcItem->valueint;
- else
+ // 解析apc字段
+ if (cJSON *apcItem = cJSON_GetObjectItem(item, "apc")) {
+ if (cJSON_IsNumber(apcItem)) {
+ sportData.apc = apcItem->valueint;
+ } else {
+ isValid = false;
+ missingFields += "apc ";
+ }
+ } else {
isValid = false;
+ missingFields += "apc ";
+ }
- if (cJSON *cdcItem = cJSON_GetObjectItem(item, "cdc");
- cdcItem && cJSON_IsNumber(cdcItem))
- sportData.cdc = cdcItem->valueint;
- else
+ // 解析cdc字段
+ if (cJSON *cdcItem = cJSON_GetObjectItem(item, "cdc")) {
+ if (cJSON_IsNumber(cdcItem)) {
+ sportData.cdc = cdcItem->valueint;
+ } else {
+ isValid = false;
+ missingFields += "cdc ";
+ }
+ } else {
isValid = false;
+ missingFields += "cdc ";
+ }
- if (cJSON *stdItem = cJSON_GetObjectItem(item, "std");
- stdItem && cJSON_IsNumber(stdItem))
- sportData.std = stdItem->valueint;
- else
+ // 解析std字段
+ if (cJSON *stdItem = cJSON_GetObjectItem(item, "std")) {
+ if (cJSON_IsNumber(stdItem)) {
+ sportData.std = stdItem->valueint;
+ } else {
+ isValid = false;
+ missingFields += "std ";
+ }
+ } else {
isValid = false;
+ missingFields += "std ";
+ }
- if (cJSON *caloriesItem = cJSON_GetObjectItem(item, "calories");
- caloriesItem && cJSON_IsNumber(caloriesItem))
- sportData.calories = caloriesItem->valueint;
- else
+ // 解析calories字段
+ if (cJSON *caloriesItem = cJSON_GetObjectItem(item, "calories")) {
+ if (cJSON_IsNumber(caloriesItem)) {
+ sportData.calories = caloriesItem->valueint;
+ } else {
+ isValid = false;
+ missingFields += "calories ";
+ }
+ } else {
isValid = false;
+ missingFields += "calories ";
+ }
- // 只有在所有字段都有效的情况下才添加 sportData 到向量中
+ // 解析starttime字段(时间戳)
+ if (cJSON *starttimeItem = cJSON_GetObjectItem(item, "start_time")) {
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Found starttime field. Type: %d",
+ starttimeItem->type);
+ if (cJSON_IsNumber(starttimeItem)) {
+ sportData.starttime = starttimeItem->valueint;
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Parsed starttime: %d",
+ sportData.starttime);
+ } else {
+ // 打印详细信息,帮助定位问题
+ const char *valueStr =
+ starttimeItem->valuestring ? starttimeItem->valuestring : "null";
+ WEARABLE_LOGE(
+ WEARABLE_LOG_MODULE_APP,
+ "Invalid starttime type. Expected number, got type %d (value: %s)",
+ starttimeItem->type, valueStr);
+ isValid = false;
+ }
+ } else {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Missing starttime field");
+ isValid = false;
+ }
+
+ // 处理解析结果
if (isValid) {
sportDataVector.push_back(sportData);
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Successfully parsed item %d", i);
} else {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid data in item %d", i);
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+ "Invalid data in item %d. Missing fields: %s", i,
+ missingFields.c_str());
}
}
cJSON_Delete(root);
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "LoadDataFormJson is ok");
+
+ // 检查是否成功解析了任何数据
+ if (sportDataVector.empty()) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "No valid data items found in JSON");
+ return false;
+ }
+
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,
+ "Successfully loaded %zu valid data items",
+ sportDataVector.size());
return true;
}
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid GPS data");
return;
}
+ // 校验时间戳是不是重复 比较最后一个?
+ if (gpsData.size() > 0 && timestamp <= gpsData.back().timestamp) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Timestamp is not increasing");
+ return;
+ }
// 添加数据
- gpsData.push_back({latitude, longitude});
+ gpsData.push_back({timestamp, latitude, longitude});
}
-// //保存
-// bool SaveCanvasData()
-// {
+//保存gps数据
+bool TraingModel::SaveCanvasData() {
-// }
+ //打印一下gps的数据
+ for (const auto &point : gpsData) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+ "GPS Data: Latitude = %f, Longitude = %f", point.latitude,
+ point.longitude);
+ }
-// void ClearCanvasData()
+ if (canvasData.size() == 0) {
+ WEARABLE_LOGE(WEARING_LOG_MODULE_APP, "canvasData is empty");
+ return false;
+ }
+
+ CreateDirectoryIfNotExists(TRAINING_GPS_FILE);
-// std::string GetGPSDataPath(uint32_t timestamp)
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "canvasData.size() = %zu",
+ canvasData.size());
+
+ std::string filePath =
+ TRAINING_GPS_FILE + std::to_string(sportdata->starttime) + ".bin";
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SaveCanvasData filePath: %s",
+ filePath.c_str());
+ std::ofstream gpsFile(filePath, std::ios::binary);
+ if (!gpsFile) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "无法打开文件: %s",
+ filePath.c_str());
+ return false; // 返回失败
+ }
+ // 写入gps数据
+ if (!gpsFile.write(reinterpret_cast<const char *>(canvasData.data()),
+ canvasData.size() * sizeof(Point))) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "写入GPS数据失败。");
+ return false; // 返回失败
+ }
+
+ gpsFile.close();
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "SaveGPSData Success.");
+ return true; // 返回成功
+}
+void TraingModel::ClearCanvasData() { canvasData.clear(); }
+
+std::string TraingModel::GetGPSDataPath(uint32_t timestamp) {
+ // 首先检查完全匹配的时间戳
+ std::string exactFilePath =
+ TRAINING_GPS_FILE + std::to_string(timestamp) + ".bin";
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "gps表: %s", exactFilePath.c_str());
+ if (IsFileAccessibleAndNotEmpty(exactFilePath)) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "找到gps表: %s",
+ exactFilePath.c_str());
+ return exactFilePath; // 返回完全匹配的文件路径
+ }
+
+ // 如果未找到,检查时间戳相差1到2秒的文件
+ for (int i = -2; i <= 2; ++i) {
+ uint32_t checkTimestamp = timestamp + i;
+ std::string filePath =
+ TRAINING_GPS_FILE + std::to_string(checkTimestamp) + ".bin";
+ if (IsFileAccessibleAndNotEmpty(filePath)) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "找到gps表: %s", filePath.c_str());
+ return filePath; // 返回找到的文件路径
+ }
+ }
+
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "未找到与时间戳相关的找到gps表。");
+ return ""; // 未找到文件
+}
+// 加载GPS数据
+bool TraingModel::LoadGPSData(const std::string &filePath) {
+ std::ifstream gpsFile(filePath, std::ios::binary);
+ if (!gpsFile) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "无法打开文件: %s",
+ filePath.c_str());
+ return false;
+ }
+
+ // 清空现有数据
+ canvasData.clear();
+
+ // 动态读取数据(假设文件格式允许逐点读取)
+ Point point;
+ while (gpsFile.read(reinterpret_cast<char *>(&point), sizeof(Point))) {
+ canvasData.push_back(point);
+ }
+
+ gpsFile.close();
+
+ if (canvasData.empty()) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "未读取到有效数据: %s",
+ filePath.c_str());
+ return false;
+ }
+
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "LoadGPSData Success. 加载了 %zu 个点",
+ canvasData.size());
+ return true;
+}
// 获取轨迹点集
std::vector<Point> TraingModel::GetCanvasData() const { return canvasData; }
}
//开启gps
void TraingModel::OpenGPS() {
- // 开启GPS的代码逻辑
- #if defined(SUPPORT_GNSS)
+// 开启GPS的代码逻辑
+#if defined(SUPPORT_GNSS)
gnss_start();
- #endif
+#endif
}
//关闭gps
void TraingModel::CloseGPS() {
- // 关闭GPS的代码逻辑
- #if defined(SUPPORT_GNSS)
+// 关闭GPS的代码逻辑
+#if defined(SUPPORT_GNSS)
gnss_stop();
- #endif
+#endif
}
//运动心率、gps开启准备
void TraingModel::start_heart_gps() { OpenGPS(); }
// TraingModel::GetInstance()->Traing_timer_callback_out();
// return;
}
- #if defined(SUPPORT_GNSS)
- gps_data_t *gps_data = getGPSGlobaldata();
- if (gps_data == NULL) {
- PRINT("gps_data == NULL \n");
- return;
- }
- //判断是否为第一次定位
- if (gps_data->last_gps_time_ms > 0) {
- memcpy_s(&send_gps_data, sizeof(gps_data_t), gps_data, sizeof(gps_data_t));
- }
- //判断是否定位成功
- if (send_gps_data.status > 1) {
- //定位成功
- TraingModel::GetInstance()->SetGPSConnectState(true);
- } else {
- TraingModel::GetInstance()->SetGPSConnectState(false);
- }
- #endif
+#if defined(SUPPORT_GNSS)
+
+ TraingModel::GetInstance()->;
+
+#endif
}
/*
* @brief 回调函数