2025-07-29 15:21:28 +08:00
|
|
|
|
#include "device_praser.h"
|
2025-07-28 11:56:50 +08:00
|
|
|
|
#include <cstring> // 添加 memcpy 头文件
|
|
|
|
|
|
|
|
|
|
|
|
// 辅助函数:从字节数组读取小端整数
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
|
T read_le(const uint8_t* data) {
|
|
|
|
|
|
T value = 0;
|
|
|
|
|
|
for (size_t i = 0; i < sizeof(T); ++i) {
|
|
|
|
|
|
value |= static_cast<T>(data[i]) << (i * 8);
|
|
|
|
|
|
}
|
|
|
|
|
|
return value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 脑电设备解析 (0x4230)
|
|
|
|
|
|
SensorData parse_eeg(const uint8_t* data) {
|
|
|
|
|
|
SensorData result;
|
|
|
|
|
|
result.data_type = DataType::EEG;
|
|
|
|
|
|
result.packet_sn = read_le<uint16_t>(data);
|
|
|
|
|
|
|
|
|
|
|
|
// 跳过 DataType(2) 和 data_len(2)
|
|
|
|
|
|
const uint8_t* payload = data + 6;
|
|
|
|
|
|
|
|
|
|
|
|
// 导联状态
|
|
|
|
|
|
std::memcpy(result.lead_status.status, payload, 2);
|
|
|
|
|
|
payload += 2;
|
|
|
|
|
|
|
2025-08-14 11:16:24 +08:00
|
|
|
|
// 解析EEG数据 (6通道 × 14采样点)
|
2025-07-28 11:56:50 +08:00
|
|
|
|
auto& eeg_data = result.channel_data.emplace<std::vector<std::vector<float>>>();
|
|
|
|
|
|
eeg_data.resize(6);
|
|
|
|
|
|
|
|
|
|
|
|
for (int ch = 0; ch < 6; ++ch) {
|
|
|
|
|
|
eeg_data[ch].reserve(14);
|
|
|
|
|
|
for (int i = 0; i < 14; ++i) {
|
2025-08-14 11:16:24 +08:00
|
|
|
|
int16_t adc_value = read_le<int16_t>(payload);
|
2025-07-28 11:56:50 +08:00
|
|
|
|
payload += 2;
|
|
|
|
|
|
eeg_data[ch].push_back(adc_value * 0.318f); // 转换为μV
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 解析EOG数据 (2通道 × 14采样点)
|
|
|
|
|
|
for (int ch = 0; ch < 2; ++ch) {
|
|
|
|
|
|
eeg_data.push_back({}); // 添加新通道
|
|
|
|
|
|
for (int i = 0; i < 14; ++i) {
|
|
|
|
|
|
int16_t adc_value = read_le<int16_t>(payload);
|
|
|
|
|
|
payload += 2;
|
|
|
|
|
|
eeg_data.back().push_back(adc_value * 0.318f); // 转换为μV
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 跳过预留区 (6字节)
|
|
|
|
|
|
payload += 6;
|
|
|
|
|
|
|
|
|
|
|
|
// 赋值原始二进制数据
|
|
|
|
|
|
result.raw_data.assign(data, data + 6 + 2 + 6 * 14 * 2 + 2 * 14 * 2 + 6);
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 胸腹设备解析 (0x4211)
|
|
|
|
|
|
SensorData parse_ecg_emg(const uint8_t* data) {
|
|
|
|
|
|
SensorData result;
|
|
|
|
|
|
result.data_type = DataType::ECG_2LEAD;
|
|
|
|
|
|
result.packet_sn = read_le<uint16_t>(data);
|
|
|
|
|
|
|
|
|
|
|
|
// 跳过 data_type(2) 和 data_len(2)
|
|
|
|
|
|
const uint8_t* payload = data + 6;
|
|
|
|
|
|
|
|
|
|
|
|
// 导联状态
|
|
|
|
|
|
std::memcpy(result.lead_status.status, payload, 2);
|
|
|
|
|
|
payload += 2;
|
|
|
|
|
|
|
|
|
|
|
|
// 解析数据 (多通道混合)
|
|
|
|
|
|
auto& channels = result.channel_data.emplace<std::vector<std::vector<float>>>();
|
|
|
|
|
|
|
|
|
|
|
|
// ECG1 (25采样点)
|
|
|
|
|
|
channels.push_back({});
|
|
|
|
|
|
for (int i = 0; i < 25; ++i) {
|
|
|
|
|
|
int16_t adc_value = read_le<int16_t>(payload);
|
|
|
|
|
|
payload += 2;
|
|
|
|
|
|
channels.back().push_back(adc_value * 0.318f); // μV
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ECG2 (25采样点)
|
|
|
|
|
|
channels.push_back({});
|
|
|
|
|
|
for (int i = 0; i < 25; ++i) {
|
|
|
|
|
|
int16_t adc_value = read_le<int16_t>(payload);
|
|
|
|
|
|
payload += 2;
|
|
|
|
|
|
channels.back().push_back(adc_value * 0.318f); // μV
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// EMG1 (25采样点)
|
|
|
|
|
|
channels.push_back({});
|
|
|
|
|
|
for (int i = 0; i < 25; ++i) {
|
|
|
|
|
|
int16_t adc_value = read_le<int16_t>(payload);
|
|
|
|
|
|
payload += 2;
|
|
|
|
|
|
channels.back().push_back(adc_value * 0.318f); // μV
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// EMG2 (25采样点)
|
|
|
|
|
|
channels.push_back({});
|
|
|
|
|
|
for (int i = 0; i < 25; ++i) {
|
|
|
|
|
|
int16_t adc_value = read_le<int16_t>(payload);
|
|
|
|
|
|
payload += 2;
|
|
|
|
|
|
channels.back().push_back(adc_value * 0.318f); // μV
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 呼吸温度 (5采样点)
|
|
|
|
|
|
channels.push_back({});
|
|
|
|
|
|
for (int i = 0; i < 5; ++i) {
|
|
|
|
|
|
int16_t temp_value = read_le<int16_t>(payload);
|
|
|
|
|
|
payload += 2;
|
|
|
|
|
|
channels.back().push_back(temp_value * 0.477f); // 存储所有采样点
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 呼吸阻抗1 (5采样点)
|
|
|
|
|
|
channels.push_back({});
|
|
|
|
|
|
for (int i = 0; i < 5; ++i) {
|
|
|
|
|
|
int16_t imp_value = read_le<int16_t>(payload);
|
|
|
|
|
|
payload += 2;
|
|
|
|
|
|
channels.back().push_back(static_cast<float>(imp_value)); // 原始值
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 呼吸阻抗2 (5采样点)
|
|
|
|
|
|
channels.push_back({});
|
|
|
|
|
|
for (int i = 0; i < 5; ++i) {
|
|
|
|
|
|
int16_t imp_value = read_le<int16_t>(payload);
|
|
|
|
|
|
payload += 2;
|
2025-08-14 11:16:24 +08:00
|
|
|
|
channels.back().push_back(static_cast<float>(imp_value)); // 原始值
|
2025-07-28 11:56:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 赋值原始二进制数据
|
|
|
|
|
|
result.raw_data.assign(data, data + 238); // 完整238字节
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 血氧设备解析 (0x4302)
|
|
|
|
|
|
SensorData parse_ppg(const uint8_t* data) {
|
|
|
|
|
|
SensorData result;
|
|
|
|
|
|
result.data_type = DataType::PPG;
|
|
|
|
|
|
result.packet_sn = read_le<uint16_t>(data);
|
|
|
|
|
|
|
|
|
|
|
|
// 跳过 DataType(2) 和 data_len(2)
|
|
|
|
|
|
const uint8_t* payload = data + 6;
|
|
|
|
|
|
|
|
|
|
|
|
// 读取生命体征
|
|
|
|
|
|
result.additional.hr = *payload++;
|
|
|
|
|
|
result.additional.spo2 = *payload++;
|
|
|
|
|
|
|
|
|
|
|
|
// 修正:温度值扩大100倍存储,需要除以100
|
|
|
|
|
|
int16_t temp_raw = read_le<int16_t>(payload);
|
|
|
|
|
|
result.additional.temperature = static_cast<float>(temp_raw) / 100.0f;
|
|
|
|
|
|
payload += 2;
|
|
|
|
|
|
|
|
|
|
|
|
// 解析红光数据 (57采样点)
|
|
|
|
|
|
auto& channels = result.channel_data.emplace<std::vector<std::vector<float>>>();
|
|
|
|
|
|
channels.push_back({});
|
|
|
|
|
|
for (int i = 0; i < 57; ++i) {
|
|
|
|
|
|
int16_t adc_value = read_le<int16_t>(payload);
|
|
|
|
|
|
payload += 2;
|
|
|
|
|
|
channels.back().push_back(adc_value * 0.879f); // mV
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 解析红外光数据 (57采样点)
|
|
|
|
|
|
channels.push_back({});
|
|
|
|
|
|
for (int i = 0; i < 57; ++i) {
|
|
|
|
|
|
int16_t adc_value = read_le<int16_t>(payload);
|
|
|
|
|
|
payload += 2;
|
|
|
|
|
|
channels.back().push_back(adc_value * 0.879f); // mV
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 赋值原始二进制数据
|
|
|
|
|
|
result.raw_data.assign(data, data + 6 + 4 + 57 * 2 * 2);
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 12导联心电解析 (0x4402)
|
|
|
|
|
|
SensorData parse_12lead_ecg(const uint8_t* data) {
|
|
|
|
|
|
SensorData result;
|
|
|
|
|
|
result.data_type = DataType::ECG_12LEAD;
|
|
|
|
|
|
result.packet_sn = read_le<uint16_t>(data);
|
|
|
|
|
|
|
|
|
|
|
|
// 跳过 DataType(2) 和 data_len(2)
|
|
|
|
|
|
const uint8_t* payload = data + 6;
|
|
|
|
|
|
|
|
|
|
|
|
// 导联状态 (按文档说明处理STAT寄存器)
|
|
|
|
|
|
uint8_t stat_dh = payload[0]; // STAT.DH
|
|
|
|
|
|
uint8_t stat_dm = payload[1]; // STAT.DM
|
|
|
|
|
|
|
|
|
|
|
|
// 正确拼接方式: (STAT.DH << 4) | (STAT.DM >> 4)
|
|
|
|
|
|
result.lead_status.status[0] = (stat_dh << 4) | (stat_dm >> 4) ;
|
|
|
|
|
|
|
|
|
|
|
|
result.lead_status.status[1] = 0; // 第二个字节未使用
|
|
|
|
|
|
payload += 2;
|
|
|
|
|
|
|
|
|
|
|
|
// 解析8通道ECG数据
|
|
|
|
|
|
auto& channels = result.channel_data.emplace<std::vector<std::vector<float>>>();
|
|
|
|
|
|
channels.resize(8);
|
|
|
|
|
|
|
|
|
|
|
|
for (int ch = 0; ch < 8; ++ch) {
|
|
|
|
|
|
channels[ch].reserve(14);
|
|
|
|
|
|
for (int i = 0; i < 14; ++i) {
|
|
|
|
|
|
int16_t adc_value = read_le<int16_t>(payload);
|
|
|
|
|
|
payload += 2;
|
2025-07-29 15:21:28 +08:00
|
|
|
|
channels[ch].push_back(adc_value * 0.318f); //原始数据进行量纲转换
|
2025-07-28 11:56:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GPIO状态 (取低4位)
|
|
|
|
|
|
result.additional.gpio_state = *payload & 0x0F;
|
|
|
|
|
|
payload += 1;
|
|
|
|
|
|
|
|
|
|
|
|
// 跳过预留区 (5字节)
|
|
|
|
|
|
payload += 5;
|
|
|
|
|
|
|
|
|
|
|
|
// 赋值原始二进制数据
|
|
|
|
|
|
result.raw_data.assign(data, data + 6 + 2 + 8 * 14 * 2 + 1 + 5);
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-14 11:16:24 +08:00
|
|
|
|
// MIT-BIH 212格式解析器
|
|
|
|
|
|
SensorData parse_mit_bih_212(const uint8_t* data, size_t size) {
|
|
|
|
|
|
SensorData result;
|
|
|
|
|
|
result.data_type = DataType::MIT_BIH;
|
|
|
|
|
|
result.packet_sn = 0; // 单文件数据,SN设为0
|
|
|
|
|
|
result.lead_status = {{0}}; // 无导联状态
|
|
|
|
|
|
result.timestamp = 0; // 无时间戳
|
|
|
|
|
|
|
|
|
|
|
|
// 检查文件大小是否合理
|
|
|
|
|
|
if (size < 1024 || size % 2 != 0) {
|
|
|
|
|
|
throw std::runtime_error("无效的MIT-BIH文件大小");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 解析212格式数据
|
|
|
|
|
|
auto& channels = result.channel_data.emplace<std::vector<std::vector<float>>>();
|
|
|
|
|
|
channels.resize(2); // 两个导联
|
|
|
|
|
|
|
|
|
|
|
|
// 212格式: 每2字节包含两个12位样本
|
|
|
|
|
|
for (size_t i = 0; i < size; i += 2) {
|
|
|
|
|
|
uint8_t byte1 = data[i];
|
|
|
|
|
|
uint8_t byte2 = data[i+1];
|
|
|
|
|
|
|
|
|
|
|
|
// 解析第一个通道 (低12位)
|
|
|
|
|
|
int16_t sample1 = ((byte1 & 0x0F) << 8) | byte2;
|
|
|
|
|
|
// 符号扩展 (12位有符号 -> 16位有符号)
|
|
|
|
|
|
if (sample1 & 0x0800) sample1 |= 0xF000;
|
|
|
|
|
|
|
|
|
|
|
|
// 解析第二个通道 (高12位)
|
|
|
|
|
|
int16_t sample2 = ((byte1 & 0xF0) << 4) | (byte2 >> 4);
|
|
|
|
|
|
// 符号扩展 (12位有符号 -> 16位有符号)
|
|
|
|
|
|
if (sample2 & 0x0800) sample2 |= 0xF000;
|
|
|
|
|
|
|
|
|
|
|
|
// 转换为毫伏 (MIT-BIH ADC范围: ±5mV = ±2048)
|
|
|
|
|
|
float mv1 = sample1 * (5.0f / 2048.0f);
|
|
|
|
|
|
float mv2 = sample2 * (5.0f / 2048.0f);
|
|
|
|
|
|
|
|
|
|
|
|
channels[0].push_back(mv1);
|
|
|
|
|
|
channels[1].push_back(mv2);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 存储原始数据
|
|
|
|
|
|
result.raw_data.assign(data, data + size);
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-28 11:56:50 +08:00
|
|
|
|
// 数字听诊解析 (0x1102)
|
|
|
|
|
|
SensorData parse_stethoscope(const uint8_t* data) {
|
|
|
|
|
|
SensorData result;
|
|
|
|
|
|
result.data_type = DataType::STETHOSCOPE;
|
|
|
|
|
|
result.packet_sn = read_le<uint16_t>(data);
|
|
|
|
|
|
|
|
|
|
|
|
// 跳过 DataType(2) 和 data_len(2)
|
|
|
|
|
|
const uint8_t* payload = data + 6;
|
|
|
|
|
|
|
|
|
|
|
|
// 解析双通道音频数据
|
|
|
|
|
|
auto& channels = result.channel_data.emplace<std::vector<std::vector<float>>>();
|
|
|
|
|
|
channels.resize(2);
|
|
|
|
|
|
|
|
|
|
|
|
// 通道1数据 (116采样点)
|
|
|
|
|
|
for (int i = 0; i < 116; ++i) {
|
|
|
|
|
|
int8_t sample = static_cast<int8_t>(*payload++);
|
|
|
|
|
|
channels[0].push_back(sample * 0.146f); // mV
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 通道2数据 (116采样点)
|
|
|
|
|
|
for (int i = 0; i < 116; ++i) {
|
|
|
|
|
|
int8_t sample = static_cast<int8_t>(*payload++);
|
|
|
|
|
|
channels[1].push_back(sample * 0.146f); // mV
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 赋值原始二进制数据
|
|
|
|
|
|
result.raw_data.assign(data, data + 6 + 116 * 2);
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 鼾声解析 (0x4212)
|
|
|
|
|
|
SensorData parse_snore(const uint8_t* data) {
|
|
|
|
|
|
SensorData result;
|
|
|
|
|
|
result.data_type = DataType::SNORE;
|
|
|
|
|
|
result.packet_sn = read_le<uint16_t>(data);
|
|
|
|
|
|
|
|
|
|
|
|
// 跳过 DataType(2) + data_len(2)
|
|
|
|
|
|
const uint8_t* payload = data + 6;
|
|
|
|
|
|
|
|
|
|
|
|
// 解析鼾声数据 (232字节)
|
|
|
|
|
|
auto& channels = result.channel_data.emplace<std::vector<float>>();
|
|
|
|
|
|
|
|
|
|
|
|
// 高效转换: 直接使用 reinterpret_cast
|
|
|
|
|
|
const int8_t* snore_data = reinterpret_cast<const int8_t*>(payload);
|
|
|
|
|
|
for (int i = 0; i < 232; ++i) {
|
|
|
|
|
|
channels.push_back(static_cast<float>(snore_data[i]));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 赋值原始二进制数据
|
|
|
|
|
|
result.raw_data.assign(data, data + 6 + 232);
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 呼吸/姿态/环境光解析 (0x4213)
|
|
|
|
|
|
SensorData parse_respiration(const uint8_t* data) {
|
|
|
|
|
|
SensorData result;
|
|
|
|
|
|
result.data_type = DataType::RESPIRATION;
|
|
|
|
|
|
result.packet_sn = read_le<uint16_t>(data);
|
|
|
|
|
|
|
|
|
|
|
|
// 跳过 DataType(2) 和 data_len(2)
|
|
|
|
|
|
const uint8_t* payload = data + 6;
|
|
|
|
|
|
|
|
|
|
|
|
// 解析呼吸气流数据 (114采样点)
|
|
|
|
|
|
auto& channels = result.channel_data.emplace<std::vector<std::vector<float>>>();
|
|
|
|
|
|
channels.push_back({});
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 114; ++i) {
|
|
|
|
|
|
int16_t adc_value = read_le<int16_t>(payload);
|
|
|
|
|
|
payload += 2;
|
|
|
|
|
|
channels.back().push_back(adc_value * 0.1f); // 实际单位
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 解析附加数据
|
|
|
|
|
|
result.additional.movement = read_le<uint16_t>(payload); // 运动强度
|
|
|
|
|
|
payload += 2;
|
|
|
|
|
|
|
|
|
|
|
|
result.additional.posture = *payload++; // 姿态数据
|
|
|
|
|
|
result.additional.ambient_light = *payload++; // 环境光数据
|
|
|
|
|
|
|
|
|
|
|
|
// 赋值原始二进制数据
|
|
|
|
|
|
result.raw_data.assign(data, data + 6 + 114 * 2 + 2 + 1 + 1);
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-29 15:21:28 +08:00
|
|
|
|
// 统一解析入口函数 - 支持多个帧头和数据包组
|
2025-07-28 11:56:50 +08:00
|
|
|
|
std::vector<SensorData> parse_device_data(const std::vector<uint8_t>& file_data) {
|
2025-08-14 11:16:24 +08:00
|
|
|
|
FileManager manager_;
|
2025-07-28 11:56:50 +08:00
|
|
|
|
const size_t PACKET_SIZE = 238; // 每个数据包固定大小
|
2025-07-29 15:21:28 +08:00
|
|
|
|
const size_t RESPONSE_HEADER_SIZE = 10; // 响应帧头大小 (2功能码 + 2数据长度 + 4实际采集点数+crc校验)
|
|
|
|
|
|
const uint16_t FUNCTION_CODE = 0x0010; // 获取数据功能码
|
|
|
|
|
|
|
2025-07-28 11:56:50 +08:00
|
|
|
|
const size_t file_size = file_data.size();
|
2025-07-29 15:21:28 +08:00
|
|
|
|
const uint8_t* ptr = file_data.data();
|
|
|
|
|
|
const uint8_t* end_ptr = ptr + file_size;
|
2025-08-14 11:16:24 +08:00
|
|
|
|
std::map<DataType, std::vector<SensorData>> grouped_data;
|
2025-07-28 11:56:50 +08:00
|
|
|
|
std::vector<SensorData> results;
|
2025-07-29 15:21:28 +08:00
|
|
|
|
while (ptr < end_ptr) {
|
|
|
|
|
|
// 检查是否有响应帧头
|
|
|
|
|
|
bool has_response_header = false;
|
|
|
|
|
|
size_t remaining = end_ptr - ptr;
|
|
|
|
|
|
|
|
|
|
|
|
// 确保有足够的空间检查帧头
|
|
|
|
|
|
if (remaining >= RESPONSE_HEADER_SIZE) {
|
|
|
|
|
|
// 读取功能码 (小端)
|
|
|
|
|
|
uint16_t func_code = read_le<uint16_t>(ptr);
|
|
|
|
|
|
// 读取数据长度 (小端)
|
|
|
|
|
|
uint16_t data_len = read_le<uint16_t>(ptr + 2);
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否符合0x0010响应帧特征
|
|
|
|
|
|
if (func_code == FUNCTION_CODE && data_len == 0x0004) {
|
|
|
|
|
|
has_response_header = true;
|
|
|
|
|
|
|
|
|
|
|
|
// 读取实际数据点数 (小端)
|
|
|
|
|
|
uint32_t actual_points = read_le<uint32_t>(ptr + 4);
|
|
|
|
|
|
|
|
|
|
|
|
// 计算期望的数据长度 (实际点数 * 包大小)
|
|
|
|
|
|
size_t expected_data_size = actual_points * PACKET_SIZE;
|
|
|
|
|
|
size_t remaining_after_header = remaining - RESPONSE_HEADER_SIZE;
|
|
|
|
|
|
|
|
|
|
|
|
// 验证数据长度是否匹配
|
|
|
|
|
|
if (remaining_after_header < expected_data_size) {
|
|
|
|
|
|
std::string error = "帧头数据不足: 预期 " +
|
|
|
|
|
|
std::to_string(expected_data_size) +
|
|
|
|
|
|
" 字节, 实际 " +
|
|
|
|
|
|
std::to_string(remaining_after_header) +
|
|
|
|
|
|
" 字节";
|
|
|
|
|
|
throw std::runtime_error(error);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 跳过帧头
|
|
|
|
|
|
ptr += RESPONSE_HEADER_SIZE;
|
|
|
|
|
|
|
|
|
|
|
|
// 处理帧头后的数据包
|
|
|
|
|
|
for (uint32_t i = 0; i < actual_points; i++) {
|
|
|
|
|
|
if (end_ptr - ptr < static_cast<ptrdiff_t>(PACKET_SIZE)) {
|
|
|
|
|
|
throw std::runtime_error("数据包不完整");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 读取数据类型标识
|
|
|
|
|
|
const uint16_t data_type = read_le<uint16_t>(ptr + 2);
|
|
|
|
|
|
|
|
|
|
|
|
switch (data_type) {
|
|
|
|
|
|
case 0x4230:
|
|
|
|
|
|
results.push_back(parse_eeg(ptr));
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 0x4211:
|
|
|
|
|
|
results.push_back(parse_ecg_emg(ptr));
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 0x4212:
|
|
|
|
|
|
results.push_back(parse_snore(ptr));
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 0x4213:
|
|
|
|
|
|
results.push_back(parse_respiration(ptr));
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 0x4402:
|
|
|
|
|
|
results.push_back(parse_12lead_ecg(ptr));
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 0x4302:
|
|
|
|
|
|
results.push_back(parse_ppg(ptr));
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 0x1102:
|
|
|
|
|
|
results.push_back(parse_stethoscope(ptr));
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
throw std::runtime_error("未知设备类型: 0x" +
|
|
|
|
|
|
to_hex_string(data_type));
|
|
|
|
|
|
}
|
|
|
|
|
|
ptr += PACKET_SIZE;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-28 11:56:50 +08:00
|
|
|
|
|
2025-07-29 15:21:28 +08:00
|
|
|
|
// 如果没有检测到响应帧头,尝试按纯数据包处理
|
|
|
|
|
|
if (!has_response_header) {
|
|
|
|
|
|
// 检查是否有完整的数据包
|
|
|
|
|
|
if (remaining >= PACKET_SIZE) {
|
|
|
|
|
|
// 读取数据类型标识
|
|
|
|
|
|
const uint16_t data_type = read_le<uint16_t>(ptr + 2);
|
|
|
|
|
|
|
|
|
|
|
|
switch (data_type) {
|
|
|
|
|
|
case 0x4230:
|
|
|
|
|
|
results.push_back(parse_eeg(ptr));
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 0x4211:
|
|
|
|
|
|
results.push_back(parse_ecg_emg(ptr));
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 0x4212:
|
|
|
|
|
|
results.push_back(parse_snore(ptr));
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 0x4213:
|
|
|
|
|
|
results.push_back(parse_respiration(ptr));
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 0x4402:
|
|
|
|
|
|
results.push_back(parse_12lead_ecg(ptr));
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 0x4302:
|
|
|
|
|
|
results.push_back(parse_ppg(ptr));
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 0x1102:
|
|
|
|
|
|
results.push_back(parse_stethoscope(ptr));
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
// 如果不是已知类型,跳过这个包继续处理
|
|
|
|
|
|
ptr += PACKET_SIZE;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
ptr += PACKET_SIZE;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 剩余数据不足一个包,但大于0,发出警告
|
|
|
|
|
|
if (remaining > 0) {
|
|
|
|
|
|
std::cerr << "警告: 文件包含 " << remaining
|
|
|
|
|
|
<< " 字节额外数据,已忽略" << std::endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
break; // 结束处理
|
|
|
|
|
|
}
|
2025-07-28 11:56:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-14 11:16:24 +08:00
|
|
|
|
// 将解析的结果按数据类型分组
|
|
|
|
|
|
for (const auto& result : results) {
|
|
|
|
|
|
grouped_data[result.data_type].push_back(result);
|
|
|
|
|
|
}
|
|
|
|
|
|
for (auto& [data_type, packets] : grouped_data) {
|
|
|
|
|
|
if (packets.empty()) continue;
|
|
|
|
|
|
|
|
|
|
|
|
// 创建新的SensorData对象,包含完整通道数据
|
|
|
|
|
|
SensorData full_data = packets[0];
|
|
|
|
|
|
full_data.channel_data = std::vector<std::vector<float>>();
|
|
|
|
|
|
|
|
|
|
|
|
// 获取通道数量
|
|
|
|
|
|
size_t num_channels = 0;
|
|
|
|
|
|
if (auto* channels = std::get_if<std::vector<std::vector<float>>>(&packets[0].channel_data)) {
|
|
|
|
|
|
num_channels = channels->size();
|
|
|
|
|
|
full_data.channel_data.emplace<std::vector<std::vector<float>>>(num_channels);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 合并所有数据包中的通道数据
|
|
|
|
|
|
auto& full_channels = std::get<std::vector<std::vector<float>>>(full_data.channel_data);
|
|
|
|
|
|
for (size_t ch = 0; ch < num_channels; ch++) {
|
|
|
|
|
|
for (auto& packet : packets) {
|
|
|
|
|
|
if (auto* channels = std::get_if<std::vector<std::vector<float>>>(&packet.channel_data)) {
|
|
|
|
|
|
if (ch < channels->size()) {
|
|
|
|
|
|
full_channels[ch].insert(full_channels[ch].end(),
|
|
|
|
|
|
(*channels)[ch].begin(),
|
|
|
|
|
|
(*channels)[ch].end());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
results.push_back(full_data);
|
|
|
|
|
|
}
|
2025-07-28 11:56:50 +08:00
|
|
|
|
return results;
|
|
|
|
|
|
}
|