OSCAR-code/oscar/SleepLib/loader_plugins/prs1_parser.cpp
sawinglogz daaed2de79 Move PRS1DataChunk into parser header and clean up dependencies.
Also move some previously static functions into their associated classes,
which lets us remove a few unnecessary wrapper functions used for testing.

No change in functionality.

Use git blame dd9a087 to follow the history before this refactoring.
2021-05-31 14:53:23 -04:00

320 lines
10 KiB
C++

/* SleepLib PRS1 Loader Parser Implementation
*
* Copyright (c) 2019-2021 The OSCAR Team
* Portions copyright (c) 2011-2018 Mark Watkins <mark@jedimark.net>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of the source code
* for more details. */
#include "prs1_parser.h"
#include <QDebug>
const PRS1ParsedEventType PRS1TidalVolumeEvent::TYPE;
const PRS1ParsedEventType PRS1SnoresAtPressureEvent::TYPE;
const PRS1ParsedEventType PRS1TimedBreathEvent::TYPE;
const PRS1ParsedEventType PRS1ObstructiveApneaEvent::TYPE;
const PRS1ParsedEventType PRS1ClearAirwayEvent::TYPE;
const PRS1ParsedEventType PRS1FlowLimitationEvent::TYPE;
const PRS1ParsedEventType PRS1PeriodicBreathingEvent::TYPE;
const PRS1ParsedEventType PRS1LargeLeakEvent::TYPE;
const PRS1ParsedEventType PRS1VariableBreathingEvent::TYPE;
const PRS1ParsedEventType PRS1HypopneaEvent::TYPE;
const PRS1ParsedEventType PRS1TotalLeakEvent::TYPE;
const PRS1ParsedEventType PRS1LeakEvent::TYPE;
const PRS1ParsedEventType PRS1AutoPressureSetEvent::TYPE;
const PRS1ParsedEventType PRS1PressureSetEvent::TYPE;
const PRS1ParsedEventType PRS1IPAPSetEvent::TYPE;
const PRS1ParsedEventType PRS1EPAPSetEvent::TYPE;
const PRS1ParsedEventType PRS1PressureAverageEvent::TYPE;
const PRS1ParsedEventType PRS1FlexPressureAverageEvent::TYPE;
const PRS1ParsedEventType PRS1IPAPAverageEvent::TYPE;
const PRS1ParsedEventType PRS1IPAPHighEvent::TYPE;
const PRS1ParsedEventType PRS1IPAPLowEvent::TYPE;
const PRS1ParsedEventType PRS1EPAPAverageEvent::TYPE;
const PRS1ParsedEventType PRS1RespiratoryRateEvent::TYPE;
const PRS1ParsedEventType PRS1PatientTriggeredBreathsEvent::TYPE;
const PRS1ParsedEventType PRS1MinuteVentilationEvent::TYPE;
const PRS1ParsedEventType PRS1SnoreEvent::TYPE;
const PRS1ParsedEventType PRS1VibratorySnoreEvent::TYPE;
const PRS1ParsedEventType PRS1PressurePulseEvent::TYPE;
const PRS1ParsedEventType PRS1RERAEvent::TYPE;
const PRS1ParsedEventType PRS1FlowRateEvent::TYPE;
const PRS1ParsedEventType PRS1Test1Event::TYPE;
const PRS1ParsedEventType PRS1Test2Event::TYPE;
const PRS1ParsedEventType PRS1HypopneaCount::TYPE;
const PRS1ParsedEventType PRS1ClearAirwayCount::TYPE;
const PRS1ParsedEventType PRS1ObstructiveApneaCount::TYPE;
//const PRS1ParsedEventType PRS1DisconnectAlarmEvent::TYPE;
const PRS1ParsedEventType PRS1ApneaAlarmEvent::TYPE;
//const PRS1ParsedEventType PRS1LowMinuteVentilationAlarmEvent::TYPE;
// MARK: Render parsed events as text
static QString hex(int i)
{
return QString("0x") + QString::number(i, 16).toUpper();
}
#define ENUMSTRING(ENUM) case ENUM: s = QStringLiteral(#ENUM); break
QString PRS1ParsedEvent::typeName() const
{
PRS1ParsedEventType t = m_type;
QString s;
switch (t) {
ENUMSTRING(EV_PRS1_RAW);
ENUMSTRING(EV_PRS1_UNKNOWN);
ENUMSTRING(EV_PRS1_TB);
ENUMSTRING(EV_PRS1_OA);
ENUMSTRING(EV_PRS1_CA);
ENUMSTRING(EV_PRS1_FL);
ENUMSTRING(EV_PRS1_PB);
ENUMSTRING(EV_PRS1_LL);
ENUMSTRING(EV_PRS1_VB);
ENUMSTRING(EV_PRS1_HY);
ENUMSTRING(EV_PRS1_OA_COUNT);
ENUMSTRING(EV_PRS1_CA_COUNT);
ENUMSTRING(EV_PRS1_HY_COUNT);
ENUMSTRING(EV_PRS1_TOTLEAK);
ENUMSTRING(EV_PRS1_LEAK);
ENUMSTRING(EV_PRS1_AUTO_PRESSURE_SET);
ENUMSTRING(EV_PRS1_PRESSURE_SET);
ENUMSTRING(EV_PRS1_IPAP_SET);
ENUMSTRING(EV_PRS1_EPAP_SET);
ENUMSTRING(EV_PRS1_PRESSURE_AVG);
ENUMSTRING(EV_PRS1_FLEX_PRESSURE_AVG);
ENUMSTRING(EV_PRS1_IPAP_AVG);
ENUMSTRING(EV_PRS1_IPAPLOW);
ENUMSTRING(EV_PRS1_IPAPHIGH);
ENUMSTRING(EV_PRS1_EPAP_AVG);
ENUMSTRING(EV_PRS1_RR);
ENUMSTRING(EV_PRS1_PTB);
ENUMSTRING(EV_PRS1_MV);
ENUMSTRING(EV_PRS1_TV);
ENUMSTRING(EV_PRS1_SNORE);
ENUMSTRING(EV_PRS1_VS);
ENUMSTRING(EV_PRS1_PP);
ENUMSTRING(EV_PRS1_RERA);
ENUMSTRING(EV_PRS1_FLOWRATE);
ENUMSTRING(EV_PRS1_TEST1);
ENUMSTRING(EV_PRS1_TEST2);
ENUMSTRING(EV_PRS1_SETTING);
ENUMSTRING(EV_PRS1_SLICE);
ENUMSTRING(EV_PRS1_DISCONNECT_ALARM);
ENUMSTRING(EV_PRS1_APNEA_ALARM);
ENUMSTRING(EV_PRS1_LOW_MV_ALARM);
ENUMSTRING(EV_PRS1_SNORES_AT_PRESSURE);
ENUMSTRING(EV_PRS1_INTERVAL_BOUNDARY);
default:
s = hex(t);
qDebug() << "Unknown PRS1ParsedEventType type:" << qPrintable(s);
return s;
}
return s.mid(8).toLower(); // lop off initial EV_PRS1_
}
QString PRS1ParsedSettingEvent::settingName() const
{
PRS1ParsedSettingType t = m_setting;
QString s;
switch (t) {
ENUMSTRING(PRS1_SETTING_CPAP_MODE);
ENUMSTRING(PRS1_SETTING_AUTO_TRIAL);
ENUMSTRING(PRS1_SETTING_PRESSURE);
ENUMSTRING(PRS1_SETTING_PRESSURE_MIN);
ENUMSTRING(PRS1_SETTING_PRESSURE_MAX);
ENUMSTRING(PRS1_SETTING_EPAP);
ENUMSTRING(PRS1_SETTING_EPAP_MIN);
ENUMSTRING(PRS1_SETTING_EPAP_MAX);
ENUMSTRING(PRS1_SETTING_IPAP);
ENUMSTRING(PRS1_SETTING_IPAP_MIN);
ENUMSTRING(PRS1_SETTING_IPAP_MAX);
ENUMSTRING(PRS1_SETTING_PS);
ENUMSTRING(PRS1_SETTING_PS_MIN);
ENUMSTRING(PRS1_SETTING_PS_MAX);
ENUMSTRING(PRS1_SETTING_BACKUP_BREATH_MODE);
ENUMSTRING(PRS1_SETTING_BACKUP_BREATH_RATE);
ENUMSTRING(PRS1_SETTING_BACKUP_TIMED_INSPIRATION);
ENUMSTRING(PRS1_SETTING_TIDAL_VOLUME);
ENUMSTRING(PRS1_SETTING_EZ_START);
ENUMSTRING(PRS1_SETTING_FLEX_LOCK);
ENUMSTRING(PRS1_SETTING_FLEX_MODE);
ENUMSTRING(PRS1_SETTING_FLEX_LEVEL);
ENUMSTRING(PRS1_SETTING_RISE_TIME);
ENUMSTRING(PRS1_SETTING_RISE_TIME_LOCK);
ENUMSTRING(PRS1_SETTING_RAMP_TYPE);
ENUMSTRING(PRS1_SETTING_RAMP_TIME);
ENUMSTRING(PRS1_SETTING_RAMP_PRESSURE);
ENUMSTRING(PRS1_SETTING_HUMID_STATUS);
ENUMSTRING(PRS1_SETTING_HUMID_MODE);
ENUMSTRING(PRS1_SETTING_HEATED_TUBE_TEMP);
ENUMSTRING(PRS1_SETTING_HUMID_LEVEL);
ENUMSTRING(PRS1_SETTING_HUMID_TARGET_TIME);
ENUMSTRING(PRS1_SETTING_MASK_RESIST_LOCK);
ENUMSTRING(PRS1_SETTING_MASK_RESIST_SETTING);
ENUMSTRING(PRS1_SETTING_HOSE_DIAMETER);
ENUMSTRING(PRS1_SETTING_TUBING_LOCK);
ENUMSTRING(PRS1_SETTING_AUTO_ON);
ENUMSTRING(PRS1_SETTING_AUTO_OFF);
ENUMSTRING(PRS1_SETTING_APNEA_ALARM);
ENUMSTRING(PRS1_SETTING_DISCONNECT_ALARM);
ENUMSTRING(PRS1_SETTING_LOW_MV_ALARM);
ENUMSTRING(PRS1_SETTING_LOW_TV_ALARM);
ENUMSTRING(PRS1_SETTING_MASK_ALERT);
ENUMSTRING(PRS1_SETTING_SHOW_AHI);
default:
s = hex(t);
qDebug() << "Unknown PRS1ParsedSettingType type:" << qPrintable(s);
return s;
}
return s.mid(13).toLower(); // lop off initial PRS1_SETTING_
}
QString PRS1ParsedSettingEvent::modeName() const
{
int m = value();
QString s;
switch ((PRS1Mode) m) {
ENUMSTRING(PRS1_MODE_UNKNOWN); // TODO: Remove this when all the parsers are complete.
ENUMSTRING(PRS1_MODE_CPAP);
ENUMSTRING(PRS1_MODE_CPAPCHECK);
ENUMSTRING(PRS1_MODE_AUTOTRIAL);
ENUMSTRING(PRS1_MODE_AUTOCPAP);
ENUMSTRING(PRS1_MODE_BILEVEL);
ENUMSTRING(PRS1_MODE_AUTOBILEVEL);
ENUMSTRING(PRS1_MODE_ASV);
ENUMSTRING(PRS1_MODE_S);
ENUMSTRING(PRS1_MODE_ST);
ENUMSTRING(PRS1_MODE_PC);
ENUMSTRING(PRS1_MODE_ST_AVAPS);
ENUMSTRING(PRS1_MODE_PC_AVAPS);
default:
s = hex(m);
qDebug() << "Unknown PRS1Mode:" << qPrintable(s);
return s;
}
return s.mid(10).toLower(); // lop off initial PRS1_MODE_
}
QString PRS1ParsedEvent::timeStr(int t)
{
int h = t / 3600;
int m = (t - (h * 3600)) / 60;
int s = t % 60;
#if 1
// Optimized after profiling regression tests.
return QString::asprintf("%02d:%02d:%02d", h, m, s);
#else
// Unoptimized original, slows down regression tests.
return QString("%1:%2:%3").arg(h, 2, 10, QChar('0')).arg(m, 2, 10, QChar('0')).arg(s, 2, 10, QChar('0'));
#endif
}
static QString byteList(QByteArray data, int limit=-1)
{
int count = data.size();
if (limit == -1 || limit > count) limit = count;
QStringList l;
for (int i = 0; i < limit; i++) {
l.push_back(QString( "%1" ).arg((int) data[i] & 0xFF, 2, 16, QChar('0') ).toUpper());
}
if (limit < count) l.push_back("...");
QString s = l.join(" ");
return s;
}
QMap<QString,QString> PRS1IntervalBoundaryEvent::contents(void)
{
QMap<QString,QString> out;
out["start"] = timeStr(m_start);
return out;
}
QMap<QString,QString> PRS1ParsedDurationEvent::contents(void)
{
QMap<QString,QString> out;
out["start"] = timeStr(m_start);
out["duration"] = timeStr(m_duration);
return out;
}
QMap<QString,QString> PRS1ParsedValueEvent::contents(void)
{
QMap<QString,QString> out;
out["start"] = timeStr(m_start);
out["value"] = QString::number(value());
return out;
}
QMap<QString,QString> PRS1UnknownDataEvent::contents(void)
{
QMap<QString,QString> out;
out["pos"] = QString::number(m_pos);
out["data"] = byteList(m_data);
return out;
}
QMap<QString,QString> PRS1ParsedSettingEvent::contents(void)
{
QMap<QString,QString> out;
QString v;
if (m_setting == PRS1_SETTING_CPAP_MODE) {
v = modeName();
} else {
v = QString::number(value());
}
out[settingName()] = v;
return out;
}
QMap<QString,QString> PRS1ParsedSliceEvent::contents(void)
{
QMap<QString,QString> out;
out["start"] = timeStr(m_start);
QString s;
switch ((SliceStatus) m_value) {
case MaskOn: s = "MaskOn"; break;
case MaskOff: s = "MaskOff"; break;
case EquipmentOff: s = "EquipmentOff"; break;
case UnknownStatus: s = "Unknown"; break;
}
out["status"] = s;
return out;
}
QMap<QString,QString> PRS1ParsedAlarmEvent::contents(void)
{
QMap<QString,QString> out;
out["start"] = timeStr(m_start);
return out;
}
QMap<QString,QString> PRS1SnoresAtPressureEvent::contents(void)
{
QString label;
switch (m_kind) {
case 0: label = "pressure"; break;
case 1: label = "epap"; break;
case 2: label = "ipap"; break;
default: label = "unknown_pressure"; break;
}
QMap<QString,QString> out;
out["start"] = timeStr(m_start);
out[label] = QString::number(value());
out["count"] = QString::number(m_count);
return out;
}