medical_SDK/src/data_receiver/protocol_adapter/device_praser.cpp

524 lines
18 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "device_praser.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 * 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<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;
}
// 数字听诊解析 (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) {
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<DataType, std::vector<SensorData>> grouped_data;
std::vector<SensorData> 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<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;
}
}
}
// 如果没有检测到响应帧头,尝试按纯数据包处理
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; // 结束处理
}
}
}
// 将解析的结果按数据类型分组
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);
}
return results;
}