medical_SDK/src/data_receiver/protocol_adapter/device_praser.cpp

445 lines
15 KiB
C++
Raw Normal View History

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;
// 解析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;
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;
}
// 数字听诊解析 (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) {
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-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-07-29 15:21:28 +08:00
2025-07-28 11:56:50 +08:00
return results;
}