diff --git a/oscar/SleepLib/loader_plugins/prs1_loader.cpp b/oscar/SleepLib/loader_plugins/prs1_loader.cpp index 4e39d9a5..d1b60772 100644 --- a/oscar/SleepLib/loader_plugins/prs1_loader.cpp +++ b/oscar/SleepLib/loader_plugins/prs1_loader.cpp @@ -1075,6 +1075,7 @@ static QString timeStr(int t); static QString byteList(QByteArray data, int limit=-1); static QString hex(int i); static QString parsedSettingTypeName(PRS1ParsedSettingType t); +static QString parsedModeName(int m); class PRS1ParsedEvent @@ -1224,7 +1225,13 @@ public: virtual QMap contents(void) { QMap out; - out[parsedSettingTypeName(m_setting)] = QString::number(value()); + QString v; + if (m_setting == PRS1_SETTING_CPAP_MODE) { + v = parsedModeName(value()); + } else { + v = QString::number(value()); + } + out[parsedSettingTypeName(m_setting)] = v; return out; } @@ -1322,6 +1329,20 @@ PRS1_VALUE_EVENT(PRS1Test1Event, EV_PRS1_TEST1); PRS1_VALUE_EVENT(PRS1Test2Event, EV_PRS1_TEST2); +enum PRS1Mode { + PRS1_MODE_UNKNOWN = -1, + PRS1_MODE_CPAP = 0, // "CPAP" + PRS1_MODE_CPAPCHECK, // "CPAP-Check" + PRS1_MODE_AUTOCPAP, // "AutoCPAP" + PRS1_MODE_BILEVEL, // "Bi-Level" + PRS1_MODE_AUTOBILEVEL, // "AutoBiLevel" + PRS1_MODE_ASV, // "ASV" + PRS1_MODE_S, // "S" + PRS1_MODE_ST, // "S/T" + PRS1_MODE_PC, // "PC" +}; + + //******************************************************************************************** static QString hex(int i) @@ -1413,6 +1434,28 @@ static QString parsedSettingTypeName(PRS1ParsedSettingType t) return s.mid(13).toLower(); // lop off initial PRS1_SETTING_ } +static QString parsedModeName(int m) +{ + 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_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); + default: + s = hex(m); + qDebug() << "Unknown PRS1Mode:" << qPrintable(s); + return s; + } + return s.mid(10).toLower(); // lop off initial PRS1_MODE_ +} + static QString timeStr(int t) { int h = t / 3600; @@ -3526,6 +3569,29 @@ bool PRS1DataChunk::ParseEventsF0V6(CPAPMode /*mode*/) } +CPAPMode PRS1Import::importMode(int prs1mode) +{ + CPAPMode mode; + + switch (prs1mode) { + case PRS1_MODE_CPAP: mode = MODE_CPAP; break; + case PRS1_MODE_CPAPCHECK: mode = MODE_CPAP; break; // "CPAP-Check" in report, but seems like CPAP + case PRS1_MODE_AUTOCPAP: mode = MODE_APAP; break; + case PRS1_MODE_BILEVEL: mode = MODE_BILEVEL_FIXED; break; + case PRS1_MODE_AUTOBILEVEL: mode = MODE_BILEVEL_AUTO_VARIABLE_PS; break; + case PRS1_MODE_ASV: mode = MODE_ASV_VARIABLE_EPAP; break; + case PRS1_MODE_S: mode = MODE_BILEVEL_FIXED; break; // TODO + case PRS1_MODE_ST: mode = MODE_BILEVEL_FIXED; break; // TODO, pressure seems variable + case PRS1_MODE_PC: mode = MODE_AVAPS; break; // TODO, maybe only PC - AVAPS mode + default: mode = MODE_UNKNOWN; break; + } + // TODO: fixed vs. variable PS seems to be independent from ventilator mode, for example + // S/T can be fixed (single IPAP pressure) or variable (IPAP min/max). + + return mode; +} + + bool PRS1Import::ImportCompliance() { bool ok; @@ -3550,7 +3616,7 @@ bool PRS1Import::ImportCompliance() PRS1ParsedSettingEvent* s = (PRS1ParsedSettingEvent*) e; switch (s->m_setting) { case PRS1_SETTING_CPAP_MODE: - session->settings[CPAP_Mode] = e->m_value; + session->settings[CPAP_Mode] = importMode(e->m_value); break; case PRS1_SETTING_PRESSURE: session->settings[CPAP_Pressure] = e->value(); @@ -3640,7 +3706,8 @@ bool PRS1DataChunk::ParseComplianceF0V23(void) CHECK_VALUES(data[0x01], 1, 0); // usually 1, occasionally 0, no visible difference in report CHECK_VALUE(data[0x02], 0); - this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_CPAP_MODE, (int) MODE_CPAP)); + PRS1Mode cpapmode = PRS1_MODE_CPAP; + this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_CPAP_MODE, (int) cpapmode)); int min_pressure = data[0x03]; // EventDataType max_pressure = EventDataType(data[0x04]) / 10.0; @@ -3655,7 +3722,7 @@ bool PRS1DataChunk::ParseComplianceF0V23(void) this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_RAMP_PRESSURE, ramp_pressure)); quint8 flex = data[0x08]; // TODO: why was this 0x09 originally? could the position vary? - this->ParseFlexSetting(flex, MODE_CPAP); + this->ParseFlexSetting(flex, PRS1_MODE_CPAP); int humid = data[0x09]; // TODO: why was this 0x0A originally? could the position vary? this->ParseHumidifierSettingV2(humid, false); @@ -3744,20 +3811,20 @@ bool PRS1DataChunk::ParseSummaryF0V23() CHECK_VALUES(data[0x01] & 0x0F, 3, 0); // TODO: what are these? 0 seems to be related to errors. } - CPAPMode cpapmode = MODE_UNKNOWN; + PRS1Mode cpapmode = PRS1_MODE_UNKNOWN; switch (data[0x02]) { // PRS1 mode // 0 = CPAP, 2 = APAP case 0x00: - cpapmode = MODE_CPAP; + cpapmode = PRS1_MODE_CPAP; break; case 0x01: - cpapmode = MODE_BILEVEL_FIXED; + cpapmode = PRS1_MODE_BILEVEL; break; case 0x02: - cpapmode = MODE_APAP; + cpapmode = PRS1_MODE_AUTOCPAP; break; case 0x03: - cpapmode = MODE_BILEVEL_AUTO_VARIABLE_PS; + cpapmode = PRS1_MODE_AUTOBILEVEL; break; default: qWarning() << this->sessionid << "unknown cpap mode" << data[0x02]; @@ -3770,20 +3837,20 @@ bool PRS1DataChunk::ParseSummaryF0V23() int max_pressure = data[0x04]; int ps = data[0x05]; // max pressure support (for variable), seems to be zero otherwise - if (cpapmode == MODE_CPAP) { + if (cpapmode == PRS1_MODE_CPAP) { this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PRESSURE, min_pressure)); CHECK_VALUE(max_pressure, 0); CHECK_VALUE(ps, 0); - } else if (cpapmode == MODE_APAP) { + } else if (cpapmode == PRS1_MODE_AUTOCPAP) { this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PRESSURE_MIN, min_pressure)); this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PRESSURE_MAX, max_pressure)); CHECK_VALUE(ps, 0); - } else if (cpapmode == MODE_BILEVEL_FIXED) { + } else if (cpapmode == PRS1_MODE_BILEVEL) { this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_EPAP, min_pressure)); this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_IPAP, max_pressure)); this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PS, max_pressure - min_pressure)); CHECK_VALUE(ps, 0); // this seems to be unused on fixed bilevel - } else if (cpapmode == MODE_BILEVEL_AUTO_VARIABLE_PS) { + } else if (cpapmode == PRS1_MODE_AUTOBILEVEL) { int min_ps = 20; // 2.0 cmH2O this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_EPAP_MIN, min_pressure)); this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_EPAP_MAX, max_pressure - min_ps)); // TODO: not yet confirmed @@ -3823,9 +3890,9 @@ bool PRS1DataChunk::ParseSummaryF0V23() CHECK_VALUE(data[0x0d], 0); //CHECK_VALUES(data[0x0e], ramp_pressure, min_pressure); // initial CPAP/EPAP, can be minimum pressure or ramp, or whatever auto decides to use - if (cpapmode == MODE_BILEVEL_FIXED) { // initial IPAP for bilevel modes + if (cpapmode == PRS1_MODE_BILEVEL) { // initial IPAP for bilevel modes CHECK_VALUE(data[0x0f], max_pressure); - } else if (cpapmode == MODE_BILEVEL_AUTO_VARIABLE_PS) { + } else if (cpapmode == PRS1_MODE_AUTOBILEVEL) { CHECK_VALUE(data[0x0f], min_pressure + 20); } @@ -3887,20 +3954,20 @@ bool PRS1DataChunk::ParseSummaryF0V4(void) { const unsigned char * data = (unsigned char *)this->m_data.constData(); - CPAPMode cpapmode = MODE_UNKNOWN; + PRS1Mode cpapmode = PRS1_MODE_UNKNOWN; switch (data[0x02]) { // PRS1 mode // 0 = CPAP, 2 = APAP case 0x00: - cpapmode = MODE_CPAP; + cpapmode = PRS1_MODE_CPAP; break; case 0x20: - cpapmode = MODE_BILEVEL_FIXED; + cpapmode = PRS1_MODE_BILEVEL; break; case 0x40: - cpapmode = MODE_APAP; + cpapmode = PRS1_MODE_AUTOCPAP; break; case 0x60: - cpapmode = MODE_BILEVEL_AUTO_VARIABLE_PS; + cpapmode = PRS1_MODE_AUTOBILEVEL; } int min_pressure = data[0x03]; @@ -3908,16 +3975,16 @@ bool PRS1DataChunk::ParseSummaryF0V4(void) int min_ps = data[0x05]; // pressure support int max_ps = data[0x06]; // pressure support - if (cpapmode == MODE_CPAP) { + if (cpapmode == PRS1_MODE_CPAP) { this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PRESSURE, min_pressure)); - } else if (cpapmode == MODE_APAP) { + } else if (cpapmode == PRS1_MODE_AUTOCPAP) { this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PRESSURE_MIN, min_pressure)); this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PRESSURE_MAX, max_pressure)); - } else if (cpapmode == MODE_BILEVEL_FIXED) { + } else if (cpapmode == PRS1_MODE_BILEVEL) { this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_EPAP, min_pressure)); this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_IPAP, max_pressure)); this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PS, max_pressure - min_pressure)); - } else if (cpapmode == MODE_BILEVEL_AUTO_VARIABLE_PS) { + } else if (cpapmode == PRS1_MODE_AUTOBILEVEL) { this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_EPAP_MIN, min_pressure)); this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_EPAP_MAX, max_pressure)); this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_IPAP_MIN, min_pressure + min_ps)); @@ -3948,7 +4015,8 @@ bool PRS1DataChunk::ParseSummaryF0V4(void) // TODO: Add support for F3V3 (1061T, 1160P). This is just a stub. bool PRS1DataChunk::ParseSummaryF3V3(void) { - this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_CPAP_MODE, (int) MODE_UNKNOWN)); + PRS1Mode cpapmode = PRS1_MODE_UNKNOWN; + this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_CPAP_MODE, (int) cpapmode)); this->duration = 0; return true; } @@ -4103,7 +4171,7 @@ bool PRS1DataChunk::ParseSettingsF3V6(const unsigned char* data, int size) static const QMap expected_lengths = { {0x1e,3}, {0x35,2} }; bool ok = true; - CPAPMode cpapmode = MODE_UNKNOWN; + PRS1Mode cpapmode = PRS1_MODE_UNKNOWN; // F5V3 and F3V6 use a gain of 0.125 rather than 0.1 to allow for a maximum value of 30 cmH2O static const float GAIN = 0.125; // TODO: parameterize this somewhere better @@ -4140,9 +4208,9 @@ bool PRS1DataChunk::ParseSettingsF3V6(const unsigned char* data, int size) CHECK_VALUE(pos, 2); // always first? // TODO: We probably need additional enums for these modes, the below are just a rough guess mapping for now. switch (data[pos]) { - case 1: cpapmode = MODE_BILEVEL_FIXED; break; // "S" mode - case 2: cpapmode = MODE_BILEVEL_FIXED; break; // "S/T" mode; pressure seems variable? - case 4: cpapmode = MODE_AVAPS; break; // "PC" mode? Usually "PC - AVAPS", see setting 1 below + case 1: cpapmode = PRS1_MODE_S; break; // "S" mode + case 2: cpapmode = PRS1_MODE_ST; break; // "S/T" mode; pressure seems variable? + case 4: cpapmode = PRS1_MODE_PC; break; // "PC" mode? Usually "PC - AVAPS", see setting 1 below // TODO: fixed vs. variable PS seems to be independent from ventilator mode, for example // S/T can be fixed (single IPAP pressure) or variable (IPAP min/max). default: @@ -4174,9 +4242,6 @@ bool PRS1DataChunk::ParseSettingsF3V6(const unsigned char* data, int size) break; case 8: // Min IPAP CHECK_VALUE(fixed_ipap, 0); - if (cpapmode == MODE_BILEVEL_FIXED) { - cpapmode = MODE_BILEVEL_AUTO_VARIABLE_PS; // TODO: this isn't quite right, it's actually fixed EPAP with variable PS - } min_ipap = data[pos]; this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_IPAP_MIN, min_ipap, GAIN)); // TODO: We need to revisit whether PS should be shown as a setting. @@ -4260,7 +4325,7 @@ bool PRS1DataChunk::ParseSummaryF5V012(void) { const unsigned char * data = (unsigned char *)this->m_data.constData(); - CPAPMode cpapmode = MODE_UNKNOWN; + PRS1Mode cpapmode = PRS1_MODE_UNKNOWN; int imin_epap = data[0x3]; int imax_epap = data[0x4]; @@ -4268,7 +4333,7 @@ bool PRS1DataChunk::ParseSummaryF5V012(void) int imax_ps = data[0x6]; int imax_pressure = data[0x2]; - cpapmode = MODE_ASV_VARIABLE_EPAP; + cpapmode = PRS1_MODE_ASV; this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_CPAP_MODE, (int) cpapmode)); this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_EPAP_MIN, imin_epap)); @@ -4296,7 +4361,7 @@ bool PRS1DataChunk::ParseSummaryF5V012(void) } -void PRS1DataChunk::ParseFlexSetting(quint8 flex, CPAPMode cpapmode) +void PRS1DataChunk::ParseFlexSetting(quint8 flex, int cpapmode) { int flexlevel = flex & 0x03; FlexMode flexmode = FLEX_Unknown; @@ -4319,14 +4384,28 @@ void PRS1DataChunk::ParseFlexSetting(quint8 flex, CPAPMode cpapmode) if (flex & 0x10) { flexmode = FLEX_RiseTime; } else if (flex & 8) { // Plus bit - if (split || (cpapmode == MODE_CPAP)) { + if (split || (cpapmode == PRS1_MODE_CPAP)) { flexmode = FLEX_CFlexPlus; - } else if (cpapmode == MODE_APAP) { + } else if (cpapmode == PRS1_MODE_AUTOCPAP) { flexmode = FLEX_AFlex; } } else { // CFlex bits refer to Rise Time on BiLevel machines - flexmode = (cpapmode >= MODE_BILEVEL_FIXED) ? FLEX_BiFlex : FLEX_CFlex; + switch ((PRS1Mode) cpapmode) { + case PRS1_MODE_ST: // only seen with None and AVAPS + case PRS1_MODE_PC: // only seen with AVAPS + UNEXPECTED_VALUE(cpapmode, "untested"); + // fall through + case PRS1_MODE_BILEVEL: + case PRS1_MODE_AUTOBILEVEL: + case PRS1_MODE_ASV: + case PRS1_MODE_S: + flexmode = FLEX_BiFlex; + break; + default: + flexmode = FLEX_CFlex; + break; + } } } else flexmode = FLEX_None; @@ -4528,7 +4607,7 @@ bool PRS1DataChunk::ParseSettingsF0V6(const unsigned char* data, int size) static const QMap expected_lengths = { {0x0c,3}, {0x0d,2}, {0x0e,2}, {0x0f,4}, {0x10,3}, {0x35,2} }; bool ok = true; - CPAPMode cpapmode = MODE_UNKNOWN; + PRS1Mode cpapmode = PRS1_MODE_UNKNOWN; int pressure = 0; int imin_ps = 0; @@ -4562,11 +4641,11 @@ bool PRS1DataChunk::ParseSettingsF0V6(const unsigned char* data, int size) case 0: // Device Mode CHECK_VALUE(pos, 2); // always first? switch (data[pos]) { - case 0: cpapmode = MODE_CPAP; break; - case 2: cpapmode = MODE_APAP; break; - case 1: cpapmode = MODE_BILEVEL_FIXED; break; - case 3: cpapmode = MODE_BILEVEL_AUTO_VARIABLE_PS; break; - case 4: cpapmode = MODE_CPAP; break; // "CPAP-Check" in report, but seems like CPAP + case 0: cpapmode = PRS1_MODE_CPAP; break; + case 1: cpapmode = PRS1_MODE_BILEVEL; break; + case 2: cpapmode = PRS1_MODE_AUTOCPAP; break; + case 3: cpapmode = PRS1_MODE_AUTOBILEVEL; break; + case 4: cpapmode = PRS1_MODE_CPAPCHECK; break; default: UNEXPECTED_VALUE(data[pos], "known device mode"); break; @@ -4582,12 +4661,12 @@ bool PRS1DataChunk::ParseSettingsF0V6(const unsigned char* data, int size) } break; case 0x0a: // CPAP pressure setting - CHECK_VALUE(cpapmode, MODE_CPAP); + CHECK_VALUE(cpapmode, PRS1_MODE_CPAP); pressure = data[pos]; this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PRESSURE, pressure)); break; case 0x0c: // CPAP-Check pressure setting - CHECK_VALUE(cpapmode, MODE_CPAP); + CHECK_VALUE(cpapmode, PRS1_MODE_CPAPCHECK); min_pressure = data[pos]; // Min Setting on pressure graph max_pressure = data[pos+1]; // Max Setting on pressure graph pressure = data[pos+2]; // CPAP on pressure graph and CPAP-Check Pressure on settings detail @@ -4598,14 +4677,14 @@ bool PRS1DataChunk::ParseSettingsF0V6(const unsigned char* data, int size) this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PRESSURE, pressure)); break; case 0x0d: // AutoCPAP pressure setting - CHECK_VALUE(cpapmode, MODE_APAP); + CHECK_VALUE(cpapmode, PRS1_MODE_AUTOCPAP); min_pressure = data[pos]; max_pressure = data[pos+1]; this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PRESSURE_MIN, min_pressure)); this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PRESSURE_MAX, max_pressure)); break; case 0x0e: // Bi-Level pressure setting - CHECK_VALUE(cpapmode, MODE_BILEVEL_FIXED); + CHECK_VALUE(cpapmode, PRS1_MODE_BILEVEL); min_pressure = data[pos]; max_pressure = data[pos+1]; imin_ps = max_pressure - min_pressure; @@ -4614,7 +4693,7 @@ bool PRS1DataChunk::ParseSettingsF0V6(const unsigned char* data, int size) this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PS, imin_ps)); break; case 0x0f: // Auto Bi-Level pressure setting - CHECK_VALUE(cpapmode, MODE_BILEVEL_AUTO_VARIABLE_PS); + CHECK_VALUE(cpapmode, PRS1_MODE_AUTOBILEVEL); min_pressure = data[pos]; max_pressure = data[pos+1]; imin_ps = data[pos+2]; @@ -4625,12 +4704,10 @@ bool PRS1DataChunk::ParseSettingsF0V6(const unsigned char* data, int size) this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PS_MAX, imax_ps)); break; case 0x10: // Auto-Trial mode - CHECK_VALUE(cpapmode, MODE_CPAP); // the mode setting is CPAP, even though it's operating in APAP mode - cpapmode = MODE_APAP; // but categorize it now as APAP, since that's what it's really doing + CHECK_VALUE(cpapmode, PRS1_MODE_CPAPCHECK); CHECK_VALUES(data[pos], 30, 5); // Auto-Trial Duration min_pressure = data[pos+1]; max_pressure = data[pos+2]; - this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_CPAP_MODE, (int) cpapmode)); this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PRESSURE_MIN, min_pressure)); this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PRESSURE_MAX, max_pressure)); break; @@ -5052,7 +5129,7 @@ bool PRS1DataChunk::ParseSettingsF5V3(const unsigned char* data, int size) static const QMap expected_lengths = { {0x0a,5}, /*{0x0c,3}, {0x0d,2}, {0x0e,2}, {0x0f,4}, {0x10,3},*/ {0x14,3}, {0x2e,2}, {0x35,2} }; bool ok = true; - CPAPMode cpapmode = MODE_UNKNOWN; + PRS1Mode cpapmode = PRS1_MODE_UNKNOWN; // F5V3 uses a gain of 0.125 rather than 0.1 to allow for a maximum value of 30 cmH2O static const float GAIN = 0.125; // TODO: parameterize this somewhere better @@ -5089,7 +5166,7 @@ bool PRS1DataChunk::ParseSettingsF5V3(const unsigned char* data, int size) case 0: // Device Mode CHECK_VALUE(pos, 2); // always first? switch (data[pos]) { - case 0: cpapmode = MODE_ASV_VARIABLE_EPAP; break; + case 0: cpapmode = PRS1_MODE_ASV; break; default: UNEXPECTED_VALUE(data[pos], "known device mode"); break; @@ -5105,7 +5182,7 @@ bool PRS1DataChunk::ParseSettingsF5V3(const unsigned char* data, int size) */ break; case 0x0a: // ASV with variable EPAP pressure setting - CHECK_VALUE(cpapmode, MODE_ASV_VARIABLE_EPAP); + CHECK_VALUE(cpapmode, PRS1_MODE_ASV); max_pressure = data[pos]; min_epap = data[pos+1]; max_epap = data[pos+2]; @@ -5119,7 +5196,7 @@ bool PRS1DataChunk::ParseSettingsF5V3(const unsigned char* data, int size) this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PS_MAX, max_ps, GAIN)); break; case 0x14: // ASV backup rate - CHECK_VALUE(cpapmode, MODE_ASV_VARIABLE_EPAP); + CHECK_VALUE(cpapmode, PRS1_MODE_ASV); CHECK_VALUES(data[pos], 1, 2); // 1 = auto, 2 = fixed BPM //CHECK_VALUE(data[pos+1], 0); // 0 for auto, BPM for mode 2 //CHECK_VALUE(data[pos+2], 0); // 0 for auto, timed inspiration for mode 2 (gain 0.1) @@ -5238,6 +5315,7 @@ bool PRS1Import::ImportSummary() bool ok; ok = summary->ParseSummary(); + CPAPMode cpapmode = MODE_UNKNOWN; for (int i=0; i < summary->m_parsedData.count(); i++) { PRS1ParsedEvent* e = summary->m_parsedData.at(i); if (e->m_type == PRS1ParsedSliceEvent::TYPE) { @@ -5256,13 +5334,16 @@ bool PRS1Import::ImportSummary() PRS1ParsedSettingEvent* s = (PRS1ParsedSettingEvent*) e; switch (s->m_setting) { case PRS1_SETTING_CPAP_MODE: - session->settings[CPAP_Mode] = e->m_value; + cpapmode = importMode(e->m_value); break; case PRS1_SETTING_PRESSURE: session->settings[CPAP_Pressure] = e->value(); break; case PRS1_SETTING_PRESSURE_MIN: session->settings[CPAP_PressureMin] = e->value(); + if (cpapmode == MODE_CPAP) { // Auto-Trial is reported as CPAP but with a minimum and maximum pressure, + cpapmode = MODE_APAP; // so import it as APAP, since that's what it's really doing. + } break; case PRS1_SETTING_PRESSURE_MAX: session->settings[CPAP_PressureMax] = e->value(); @@ -5284,6 +5365,10 @@ bool PRS1Import::ImportSummary() break; case PRS1_SETTING_IPAP_MIN: session->settings[CPAP_IPAPLo] = e->value(); + // TODO: the below test doesn't work here because the mode setting is happening at the end of the event stream... + if (cpapmode == MODE_BILEVEL_FIXED) { + cpapmode = MODE_BILEVEL_AUTO_VARIABLE_PS; // TODO: this isn't quite right, on ventilators it's actually fixed EPAP with variable PS + } break; case PRS1_SETTING_IPAP_MAX: session->settings[CPAP_IPAPHi] = e->value(); @@ -5348,6 +5433,7 @@ bool PRS1Import::ImportSummary() if (!ok) { return false; } + session->settings[CPAP_Mode] = cpapmode; summary_duration = summary->duration; diff --git a/oscar/SleepLib/loader_plugins/prs1_loader.h b/oscar/SleepLib/loader_plugins/prs1_loader.h index 8c0e21f3..40c79bea 100644 --- a/oscar/SleepLib/loader_plugins/prs1_loader.h +++ b/oscar/SleepLib/loader_plugins/prs1_loader.h @@ -162,7 +162,7 @@ public: bool ParseSummaryF5V3(void); //! \brief Parse a flex setting byte from a .000 or .001 containing compliance/summary data - void ParseFlexSetting(quint8 flex, CPAPMode cpapmode); + void ParseFlexSetting(quint8 flex, int prs1mode); //! \brief Parse an humidifier setting byte from a .000 or .001 containing compliance/summary data for fileversion 2 machines: F0V234, F5V012, and maybe others void ParseHumidifierSettingV2(int humid, bool supportsHeatedTubing=true); @@ -298,6 +298,8 @@ protected: int summary_duration; + //! \brief Translate the PRS1-specific machine mode to the importable vendor-neutral enum. + CPAPMode importMode(int mode); //! \brief Parse all the chunks in a single machine session bool ParseSession(void); //! \brief Save parsed session data to the database