#include "device_praser.h" #include // 添加 memcpy 头文件 // 辅助函数:从字节数组读取小端整数 template T read_le(const uint8_t* data) { T value = 0; for (size_t i = 0; i < sizeof(T); ++i) { value |= static_cast(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(data); // 跳过 DataType(2) 和 data_len(2) const uint8_t* payload = data + 6; // 导联状态 std::memcpy(result.lead_status.status, payload, 2); payload += 2; // 解析EEG数据 (6通道 × 14采样点) auto& eeg_data = result.channel_data.emplace>>(); eeg_data.resize(6); for (int ch = 0; ch < 6; ++ch) { eeg_data[ch].reserve(14); for (int i = 0; i < 14; ++i) { int16_t adc_value = read_le(payload); 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(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(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>>(); // ECG1 (25采样点) channels.push_back({}); for (int i = 0; i < 25; ++i) { int16_t adc_value = read_le(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(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(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(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(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(payload); payload += 2; channels.back().push_back(static_cast(imp_value)); // 原始值 } // 呼吸阻抗2 (5采样点) channels.push_back({}); for (int i = 0; i < 5; ++i) { int16_t imp_value = read_le(payload); payload += 2; channels.back().push_back(static_cast(imp_value)); // 原始值 } // 赋值原始二进制数据 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(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(payload); result.additional.temperature = static_cast(temp_raw) / 100.0f; payload += 2; // 解析红光数据 (57采样点) auto& channels = result.channel_data.emplace>>(); channels.push_back({}); for (int i = 0; i < 57; ++i) { int16_t adc_value = read_le(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(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(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>>(); 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(payload); payload += 2; channels[ch].push_back(adc_value * 0.318f); //原始数据进行量纲转换 } } // 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; } // 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>>(); 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; } // 数字听诊解析 (0x1102) SensorData parse_stethoscope(const uint8_t* data) { SensorData result; result.data_type = DataType::STETHOSCOPE; result.packet_sn = read_le(data); // 跳过 DataType(2) 和 data_len(2) const uint8_t* payload = data + 6; // 解析双通道音频数据 auto& channels = result.channel_data.emplace>>(); channels.resize(2); // 通道1数据 (116采样点) for (int i = 0; i < 116; ++i) { int8_t sample = static_cast(*payload++); channels[0].push_back(sample * 0.146f); // mV } // 通道2数据 (116采样点) for (int i = 0; i < 116; ++i) { int8_t sample = static_cast(*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(data); // 跳过 DataType(2) + data_len(2) const uint8_t* payload = data + 6; // 解析鼾声数据 (232字节) auto& channels = result.channel_data.emplace>(); // 高效转换: 直接使用 reinterpret_cast const int8_t* snore_data = reinterpret_cast(payload); for (int i = 0; i < 232; ++i) { channels.push_back(static_cast(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(data); // 跳过 DataType(2) 和 data_len(2) const uint8_t* payload = data + 6; // 解析呼吸气流数据 (114采样点) auto& channels = result.channel_data.emplace>>(); channels.push_back({}); for (int i = 0; i < 114; ++i) { int16_t adc_value = read_le(payload); payload += 2; channels.back().push_back(adc_value * 0.1f); // 实际单位 } // 解析附加数据 result.additional.movement = read_le(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; } // 统一解析入口函数 - 支持多个帧头和数据包组 std::vector parse_device_data(const std::vector& file_data) { FileManager manager_; const size_t PACKET_SIZE = 238; // 每个数据包固定大小 const size_t RESPONSE_HEADER_SIZE = 10; // 响应帧头大小 (2功能码 + 2数据长度 + 4实际采集点数+crc校验) const uint16_t FUNCTION_CODE = 0x0010; // 获取数据功能码 const size_t file_size = file_data.size(); const uint8_t* ptr = file_data.data(); const uint8_t* end_ptr = ptr + file_size; std::map> grouped_data; std::vector results; 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(ptr); // 读取数据长度 (小端) uint16_t data_len = read_le(ptr + 2); // 检查是否符合0x0010响应帧特征 if (func_code == FUNCTION_CODE && data_len == 0x0004) { has_response_header = true; // 读取实际数据点数 (小端) uint32_t actual_points = read_le(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(PACKET_SIZE)) { throw std::runtime_error("数据包不完整"); } // 读取数据类型标识 const uint16_t data_type = read_le(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; } } } // 如果没有检测到响应帧头,尝试按纯数据包处理 if (!has_response_header) { // 检查是否有完整的数据包 if (remaining >= PACKET_SIZE) { // 读取数据类型标识 const uint16_t data_type = read_le(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; // 结束处理 } } } // 将解析的结果按数据类型分组 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>(); // 获取通道数量 size_t num_channels = 0; if (auto* channels = std::get_if>>(&packets[0].channel_data)) { num_channels = channels->size(); full_data.channel_data.emplace>>(num_channels); } // 合并所有数据包中的通道数据 auto& full_channels = std::get>>(full_data.channel_data); for (size_t ch = 0; ch < num_channels; ch++) { for (auto& packet : packets) { if (auto* channels = std::get_if>>(&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); } return results; }