357 lines
11 KiB
C++
357 lines
11 KiB
C++
|
|
#include "headfile.h"
|
|||
|
|
#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;
|
|||
|
|
|
|||
|
|
// 解析EEG数据 (6通道 × 14采样点)
|
|||
|
|
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) {
|
|||
|
|
int16_t adc_value = read_le<int16_t>(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<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;
|
|||
|
|
channels.back().push_back(static_cast<float>(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<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;
|
|||
|
|
channels[ch].push_back(adc_value); // raw_data
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 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;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 数字听诊解析 (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;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 统一解析入口函数 - 修改为处理多个数据包
|
|||
|
|
std::vector<SensorData> parse_device_data(const std::vector<uint8_t>& file_data) {
|
|||
|
|
const size_t PACKET_SIZE = 238; // 每个数据包固定大小
|
|||
|
|
const size_t file_size = file_data.size();
|
|||
|
|
|
|||
|
|
if (file_size % PACKET_SIZE != 0) {
|
|||
|
|
throw std::runtime_error("文件大小不是238字节的整数倍,可能已损坏");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const size_t packet_count = file_size / PACKET_SIZE;
|
|||
|
|
std::vector<SensorData> results;
|
|||
|
|
results.reserve(packet_count);
|
|||
|
|
|
|||
|
|
const uint8_t* ptr = file_data.data();
|
|||
|
|
for (size_t i = 0; i < packet_count; i++) {
|
|||
|
|
// 读取数据类型标识
|
|||
|
|
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));
|
|||
|
|
// 其他设备类型可以继续添加
|
|||
|
|
default:
|
|||
|
|
throw std::runtime_error("未知设备类型");
|
|||
|
|
}
|
|||
|
|
ptr += PACKET_SIZE;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return results;
|
|||
|
|
}
|