From 9edfd594762e0cf6f2821f679cb29c62cb4d45ed Mon Sep 17 00:00:00 2001 From: sawinglogz <3787776-sawinglogz@users.noreply.gitlab.com> Date: Sat, 11 Jan 2020 19:14:01 -0500 Subject: [PATCH] Fix PRS1 humidity import. Previously it was reporting spurious information when the humidifier was disconnected. Now it only reports settings details when the humidifier is connected (the only time they're valid.) It also now reports the humidification mode (fixed, adaptive, or heated tube), and the heated tube temperature when appropriate. --- oscar/SleepLib/loader_plugins/prs1_loader.cpp | 143 +++++++++++++----- oscar/tests/prs1tests.cpp | 2 + oscar/tests/sessiontests.cpp | 5 +- 3 files changed, 113 insertions(+), 37 deletions(-) diff --git a/oscar/SleepLib/loader_plugins/prs1_loader.cpp b/oscar/SleepLib/loader_plugins/prs1_loader.cpp index 643e7e80..8b697333 100644 --- a/oscar/SleepLib/loader_plugins/prs1_loader.cpp +++ b/oscar/SleepLib/loader_plugins/prs1_loader.cpp @@ -222,7 +222,9 @@ enum FlexMode { FLEX_None, FLEX_CFlex, FLEX_CFlexPlus, FLEX_AFlex, FLEX_RiseTime enum BackupBreathMode { PRS1Backup_Off, PRS1Backup_Auto, PRS1Backup_Fixed }; -ChannelID PRS1_TimedBreath = 0, PRS1_HeatedTubing = 0; +enum HumidMode { HUMID_Fixed, HUMID_Adaptive, HUMID_HeatedTube }; + +ChannelID PRS1_TimedBreath = 0, PRS1_HumidMode = 0, PRS1_TubeTemp = 0; struct PRS1TestedModel { @@ -1191,8 +1193,9 @@ enum PRS1ParsedSettingType PRS1_SETTING_RAMP_TIME, PRS1_SETTING_RAMP_PRESSURE, PRS1_SETTING_HUMID_STATUS, + PRS1_SETTING_HUMID_MODE, + PRS1_SETTING_HEATED_TUBE_TEMP, PRS1_SETTING_HUMID_LEVEL, - PRS1_SETTING_HEATED_TUBING, PRS1_SETTING_MASK_RESIST_LOCK, PRS1_SETTING_MASK_RESIST_SETTING, PRS1_SETTING_MASK_RESIST_STATUS, @@ -1735,8 +1738,9 @@ static QString parsedSettingTypeName(PRS1ParsedSettingType t) 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_HEATED_TUBING); ENUMSTRING(PRS1_SETTING_MASK_RESIST_LOCK); ENUMSTRING(PRS1_SETTING_MASK_RESIST_SETTING); ENUMSTRING(PRS1_SETTING_MASK_RESIST_STATUS); @@ -4172,6 +4176,12 @@ bool PRS1Import::ImportCompliance() case PRS1_SETTING_HUMID_STATUS: session->settings[PRS1_HumidStatus] = (bool) e->m_value; break; + case PRS1_SETTING_HUMID_MODE: + session->settings[PRS1_HumidMode] = e->m_value; + break; + case PRS1_SETTING_HEATED_TUBE_TEMP: + session->settings[PRS1_TubeTemp] = e->m_value; + break; case PRS1_SETTING_HUMID_LEVEL: session->settings[PRS1_HumidLevel] = e->m_value; break; @@ -4750,10 +4760,26 @@ void PRS1DataChunk::ParseHumidifierSetting60Series(unsigned char humid1, unsigne qWarning() << this->sessionid << (humidclassic ? "classic" : "systemone") << "humidity" << humidlevel; } */ + HumidMode humidmode = HUMID_Fixed; + if (tubepresent) { + humidmode = HUMID_HeatedTube; + } else { + if (humidsystemone + humidclassic > 1) UNEXPECTED_VALUE(humid2, "fixed or adaptive"); + if (humidsystemone) humidmode = HUMID_Adaptive; + } + if (add_setting) { - this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_STATUS, humidlevel != 0)); // TODO: record classic vs. systemone setting - this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HEATED_TUBING, tubepresent)); - this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_LEVEL, tubepresent ? tubehumidlevel : humidlevel)); // TODO: we also need tubetemp, where 0=off + bool humidifier_present = (no_data == 0); + this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_STATUS, humidifier_present)); + if (humidifier_present) { + this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_MODE, humidmode)); + if (humidmode == HUMID_HeatedTube) { + this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HEATED_TUBE_TEMP, tubetemp)); + this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_LEVEL, tubehumidlevel)); + } else { + this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_LEVEL, humidlevel)); + } + } } // Check for previously unseen data that we expect to be normal: @@ -5040,10 +5066,26 @@ void PRS1DataChunk::ParseHumidifierSettingF3V3(unsigned char humid1, unsigned ch qWarning() << this->sessionid << (humidclassic ? "classic" : "systemone") << "humidity" << humidlevel; } */ + HumidMode humidmode = HUMID_Fixed; + if (tubepresent) { + humidmode = HUMID_HeatedTube; + } else { + if (humidsystemone + humidclassic > 1) UNEXPECTED_VALUE(humid2, "fixed or adaptive"); + if (humidsystemone) humidmode = HUMID_Adaptive; + } + if (add_setting) { - this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_STATUS, humidlevel != 0)); // TODO: record classic vs. systemone setting - this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HEATED_TUBING, tubepresent)); - this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_LEVEL, tubepresent ? tubehumidlevel : humidlevel)); // TODO: we also need tubetemp + bool humidifier_present = (no_data == 0); + this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_STATUS, humidifier_present)); + if (humidifier_present) { + this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_MODE, humidmode)); + if (humidmode == HUMID_HeatedTube) { + this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HEATED_TUBE_TEMP, tubetemp)); + this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_LEVEL, tubehumidlevel)); + } else { + this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_LEVEL, humidlevel)); + } + } } // Check for previously unseen data that we expect to be normal: @@ -6010,7 +6052,6 @@ void PRS1DataChunk::ParseFlexSetting(quint8 flex, int cpapmode) // 0x81 = 1, bypass = no // 0x82 = 2, bypass = no -// TODO: PRS1_SETTING_HUMID_STATUS is ambiguous: we probably want connected vs. not, which should be distinct from system one vs. classic, etc. void PRS1DataChunk::ParseHumidifierSetting50Series(int humid, bool add_setting) { if (humid & (0x40 | 0x20 | 0x10 | 0x08)) UNEXPECTED_VALUE(humid, "known bits"); @@ -6018,9 +6059,13 @@ void PRS1DataChunk::ParseHumidifierSetting50Series(int humid, bool add_setting) bool humidifier_present = ((humid & 0x80) != 0); // humidifier connected int humidlevel = humid & 7; // humidification level + HumidMode humidmode = HUMID_Fixed; // 50-Series didn't have adaptive or heated tube humidification if (add_setting) { this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_STATUS, humidifier_present)); - this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_LEVEL, humidlevel)); + if (humidifier_present) { + this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_MODE, humidmode)); + this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_LEVEL, humidlevel)); + } } // Check for truly unexpected values: @@ -6288,13 +6333,24 @@ void PRS1DataChunk::ParseHumidifierSettingV3(unsigned char byte1, unsigned char } } + HumidMode humidmode = HUMID_Fixed; + if (tubepresent) { + humidmode = HUMID_HeatedTube; + } else if (humidadaptive) { + humidmode = HUMID_Adaptive; + } + if (add_setting) { - //this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_STATUS, (humid & 0x80) != 0)); // this is F0V23 version, doesn't match F0V6 - //this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HEATED_TUBING, (humid & 0x10) != 0)); // this is F0V23 version, doesn't match F0V6 - this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_LEVEL, humidlevel)); - - // TODO: add a channel for PRS1 heated tubing - //this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_TUBE_LEVEL, tubelevel)); + this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_STATUS, humidifier_present)); + if (humidifier_present) { + this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_MODE, humidmode)); + if (humidmode == HUMID_HeatedTube) { + this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HEATED_TUBE_TEMP, tubetemp)); + this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_LEVEL, tubehumidlevel)); + } else { + this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_HUMID_LEVEL, humidlevel)); + } + } } // Check for previously unseen data that we expect to be normal: @@ -7232,8 +7288,11 @@ bool PRS1Import::ImportSummary() case PRS1_SETTING_HUMID_STATUS: session->settings[PRS1_HumidStatus] = (bool) e->m_value; break; - case PRS1_SETTING_HEATED_TUBING: - session->settings[PRS1_HeatedTubing] = (bool) e->m_value; + case PRS1_SETTING_HUMID_MODE: + session->settings[PRS1_HumidMode] = e->m_value; + break; + case PRS1_SETTING_HEATED_TUBE_TEMP: + session->settings[PRS1_TubeTemp] = e->m_value; break; case PRS1_SETTING_HUMID_LEVEL: session->settings[PRS1_HumidLevel] = e->m_value; @@ -8340,27 +8399,41 @@ void PRS1Loader::initChannels() chan->addOption(0, QObject::tr("Disconnected")); chan->addOption(1, QObject::tr("Connected")); - channel.add(GRP_CPAP, chan = new Channel(PRS1_HeatedTubing = 0xe10d, SETTING, MT_CPAP, SESSION, - "PRS1HeatedTubing", - QObject::tr("Heated Tubing"), - QObject::tr("Heated Tubing Connected"), - QObject::tr("Heated Tubing"), + channel.add(GRP_CPAP, chan = new Channel(PRS1_HumidMode = 0xe110, SETTING, MT_CPAP, SESSION, + "PRS1HumidMode", + QObject::tr("Humidification Mode"), + QObject::tr("PRS1 Humidification Mode"), + QObject::tr("Humid. Mode"), "", LOOKUP, Qt::green)); - chan->addOption(0, QObject::tr("Yes")); - chan->addOption(1, QObject::tr("No")); + chan->addOption(0, QObject::tr("Fixed (Classic)")); + chan->addOption(1, QObject::tr("Adaptive (System One)")); + chan->addOption(2, QObject::tr("Heated Tube")); + + channel.add(GRP_CPAP, chan = new Channel(PRS1_TubeTemp = 0xe10f, SETTING, MT_CPAP, SESSION, + "PRS1TubeTemp", + QObject::tr("Tube Temperature"), + QObject::tr("PRS1 Heated Tube Temperature"), + QObject::tr("Tube"), + "", LOOKUP, Qt::red)); + chan->addOption(0, STR_TR_Off); + chan->addOption(1, QObject::tr("1")); + chan->addOption(2, QObject::tr("2")); + chan->addOption(3, QObject::tr("3")); + chan->addOption(4, QObject::tr("4")); + chan->addOption(5, QObject::tr("5")); channel.add(GRP_CPAP, chan = new Channel(PRS1_HumidLevel = 0xe102, SETTING, MT_CPAP, SESSION, "PRS1HumidLevel", - QObject::tr("Humidification Level"), - QObject::tr("PRS1 Humidification level"), - QObject::tr("Humid. Lvl."), - "", LOOKUP, Qt::green)); + QObject::tr("Humidifier"), // label varies in reports, "Humidifier Setting" in 50-series, "Humidity Level" in 60-series, "Humidifier" in DreamStation + QObject::tr("PRS1 Humidifier Setting"), + QObject::tr("Humid."), + "", LOOKUP, Qt::blue)); chan->addOption(0, STR_TR_Off); - chan->addOption(1, QObject::tr("x1")); - chan->addOption(2, QObject::tr("x2")); - chan->addOption(3, QObject::tr("x3")); - chan->addOption(4, QObject::tr("x4")); - chan->addOption(5, QObject::tr("x5")); + chan->addOption(1, QObject::tr("1")); + chan->addOption(2, QObject::tr("2")); + chan->addOption(3, QObject::tr("3")); + chan->addOption(4, QObject::tr("4")); + chan->addOption(5, QObject::tr("5")); channel.add(GRP_CPAP, chan = new Channel(PRS1_SysOneResistStat = 0xe103, SETTING, MT_CPAP, SESSION, "SysOneResistStat", diff --git a/oscar/tests/prs1tests.cpp b/oscar/tests/prs1tests.cpp index f00eddb7..25900564 100644 --- a/oscar/tests/prs1tests.cpp +++ b/oscar/tests/prs1tests.cpp @@ -243,6 +243,7 @@ void ChunkToYaml(QTextStream & out, PRS1DataChunk* chunk, bool ok) void parseAndEmitChunkYaml(const QString & path) { + bool FV = false; // set this to true to emit family/familyVersion for this path qDebug() << path; QHash> written; @@ -318,6 +319,7 @@ void parseAndEmitChunkYaml(const QString & path) QList chunks = s_loader->ParseFile(inpath); for (int i=0; i < chunks.size(); i++) { PRS1DataChunk * chunk = chunks.at(i); + if (i == 0 && FV) { qWarning() << QString("F%1V%2").arg(chunk->family).arg(chunk->familyVersion); FV=false; } // Only write unique chunks to the file. if (written[outpath].contains(chunk->hash()) == false) { if (first_chunk_from_file) { diff --git a/oscar/tests/sessiontests.cpp b/oscar/tests/sessiontests.cpp index 589e357f..6651440e 100644 --- a/oscar/tests/sessiontests.cpp +++ b/oscar/tests/sessiontests.cpp @@ -53,7 +53,7 @@ static QString eventListTypeName(EventListType t) // for names, make sure there aren't duplicate values, etc. For now we just fill the // below by hand. #define CHANNELNAME(CH) if (i == CH) { s = #CH; break; } -extern ChannelID PRS1_TimedBreath, PRS1_HeatedTubing; +extern ChannelID PRS1_TimedBreath, PRS1_HumidMode, PRS1_TubeTemp; static QString settingChannel(ChannelID i) { @@ -77,7 +77,8 @@ static QString settingChannel(ChannelID i) CHANNELNAME(PRS1_FlexMode); CHANNELNAME(PRS1_FlexLevel); CHANNELNAME(PRS1_HumidStatus); - CHANNELNAME(PRS1_HeatedTubing); + CHANNELNAME(PRS1_HumidMode); + CHANNELNAME(PRS1_TubeTemp); CHANNELNAME(PRS1_HumidLevel); CHANNELNAME(PRS1_SysLock); CHANNELNAME(PRS1_SysOneResistSet);