From 5a88887cc3f3eacd9e581844a4a0151692fe3d4d Mon Sep 17 00:00:00 2001 From: sawinglogz <3787776-sawinglogz@users.noreply.gitlab.com> Date: Fri, 24 May 2019 19:41:42 -0400 Subject: [PATCH] Split parsing from importing for F3V6 events. --- oscar/SleepLib/loader_plugins/prs1_loader.cpp | 239 +++++++++++++----- oscar/SleepLib/loader_plugins/prs1_loader.h | 3 + 2 files changed, 177 insertions(+), 65 deletions(-) diff --git a/oscar/SleepLib/loader_plugins/prs1_loader.cpp b/oscar/SleepLib/loader_plugins/prs1_loader.cpp index 8d46ff6d..33c19f11 100644 --- a/oscar/SleepLib/loader_plugins/prs1_loader.cpp +++ b/oscar/SleepLib/loader_plugins/prs1_loader.cpp @@ -956,6 +956,7 @@ void PRS1Loader::ScanFiles(const QStringList & paths, int sessionid_base, Machin enum PRS1ParsedEventType { + EV_PRS1_RAW = -1, // these only get logged EV_PRS1_UNKNOWN = 0, // these have their value graphed EV_PRS1_TB, EV_PRS1_OA, @@ -975,6 +976,10 @@ enum PRS1ParsedEventType EV_PRS1_TV, EV_PRS1_SNORE, EV_PRS1_EPAP, + EV_PRS1_RERA, + EV_PRS1_NRI, + EV_PRS1_TEST1, + EV_PRS1_TEST2, EV_PRS1_SETTING, }; @@ -1040,6 +1045,22 @@ public: PRS1UnknownValueEvent(int code, int start, int value, float gain=1.0) : PRS1ParsedValueEvent(EV_PRS1_UNKNOWN, start, value), m_code(code) { m_gain = gain; } }; +class PRS1UnknownDataEvent : public PRS1ParsedEvent +{ +public: + int m_pos; + unsigned char m_code; + QByteArray m_data; + PRS1UnknownDataEvent(const QByteArray & data, int pos, int len=18) + : PRS1ParsedEvent(EV_PRS1_RAW, 0) + { + m_pos = pos; + m_data = data.mid(pos, len); + Q_ASSERT(m_data.size() >= 3); + m_code = m_data.at(0); + } +}; + class PRS1PressureEvent : public PRS1ParsedValueEvent { public: @@ -1186,6 +1207,30 @@ public: PRS1EPAPEvent(int start, int value) : PRS1PressureEvent(EV_PRS1_EPAP, start, value) {} }; +class PRS1RERAEvent : public PRS1ParsedValueEvent +{ +public: + PRS1RERAEvent(int start, int value) : PRS1ParsedValueEvent(EV_PRS1_RERA, start, value) {} +}; + +class PRS1NonRespondingEvent : public PRS1ParsedValueEvent // TODO: is this a single event or an index/hour? +{ +public: + PRS1NonRespondingEvent(int start, int value) : PRS1ParsedValueEvent(EV_PRS1_NRI, start, value) {} +}; + +class PRS1Test1Event : public PRS1ParsedValueEvent +{ +public: + PRS1Test1Event(int start, int value) : PRS1ParsedValueEvent(EV_PRS1_TEST1, start, value) {} +}; + +class PRS1Test2Event : public PRS1ParsedValueEvent +{ +public: + PRS1Test2Event(int start, int value) : PRS1ParsedValueEvent(EV_PRS1_TEST2, start, value) {} +}; + void PRS1DataChunk::AddEvent(PRS1ParsedEvent* const event) { m_parsedData.push_back(event); @@ -1922,7 +1967,7 @@ bool PRS1Import::ParseF3EventsV3() { // AVAPS machine... it's delta packed, unlike the older ones?? (double check that! :/) - EventList *PP = session->AddEventList(PRS1_TimedBreath, EVL_Event); + EventList *TB = session->AddEventList(PRS1_TimedBreath, EVL_Event); EventList *OA = session->AddEventList(CPAP_Obstructive, EVL_Event); EventList *HY = session->AddEventList(CPAP_Hypopnea, EVL_Event); EventList *ZZ = session->AddEventList(CPAP_NRI, EVL_Event); @@ -1944,12 +1989,115 @@ bool PRS1Import::ParseF3EventsV3() EventList *IPAP = session->AddEventList(CPAP_IPAP, EVL_Event, 0.1f); EventList *FLOW = session->AddEventList(CPAP_Test2, EVL_Event); - qint64 t = qint64(event->timestamp) * 1000L; //, tt; + qint64 t; + bool ok; + ok = event->ParseEventsF3V6(); + + for (int i=0; i < event->m_parsedData.count(); i++) { + PRS1ParsedEvent* e = event->m_parsedData.at(i); + t = qint64(event->timestamp + e->m_start) * 1000L; + + switch (e->m_type) { + case EV_PRS1_TB: + TB->AddEvent(t, e->m_duration); + break; + case EV_PRS1_OA: + OA->AddEvent(t, e->m_duration); + break; + case EV_PRS1_CA: + CA->AddEvent(t, e->m_duration); + break; + case EV_PRS1_PB: + PB->AddEvent(t, e->m_duration); + break; + case EV_PRS1_LL: + LL->AddEvent(t, e->m_duration); + break; + case EV_PRS1_HY: + HY->AddEvent(t, e->m_duration); + break; + case EV_PRS1_EPAP: + EPAP->AddEvent(t, e->m_value); + break; + case EV_PRS1_IPAP: + IPAP->AddEvent(t, e->m_value); + break; + case EV_PRS1_LEAK: // F3V6, is this really leak rather than totleak? + LEAK->AddEvent(t, e->m_value); + break; + case EV_PRS1_RR: + RR->AddEvent(t, e->m_value); + break; + case EV_PRS1_PTB: + PTB->AddEvent(t, e->m_value); + break; + case EV_PRS1_MV: + MV->AddEvent(t, e->m_value); + break; + case EV_PRS1_TV: + TV->AddEvent(t, e->m_value); + break; + case EV_PRS1_RERA: + RE->AddEvent(t, e->m_value); + break; + case EV_PRS1_NRI: + ZZ->AddEvent(t, e->m_value); + break; + case EV_PRS1_TEST1: + TMV->AddEvent(t, e->m_value); + break; + case EV_PRS1_TEST2: + FLOW->AddEvent(t, e->m_value); + break; + case EV_PRS1_RAW: + { + PRS1UnknownDataEvent* unk = (PRS1UnknownDataEvent*) e; + int code = unk->m_code; + char* data = unk->m_data.data(); + QString dump; + if (!loader->unknownCodes.contains(code)) { + loader->unknownCodes.insert(code, QStringList()); + } + QStringList & str = loader->unknownCodes[code]; + dump = QString("%1@0x%5: [%2] [%3 %4]") + .arg(event->sessionid, 8, 16, QChar('0')) + .arg(data[0], 2, 16, QChar('0')) + .arg(data[1], 2, 16, QChar('0')) + .arg(data[2], 2, 16, QChar('0')) + .arg(unk->m_pos, 5, 16, QChar('0')); + for (int i=3; im_data.size(); i++) { + dump += QString(" %1").arg(data[i], 2, 16, QChar('0')); + } + str.append(dump.trimmed()); + break; + } + default: + qWarning() << "Unknown PRS1 event type" << (int) e->m_type; + break; + } + } + if (!ok) { + return false; + } + + return true; +} + + +// 1030X, 11030X series +bool PRS1DataChunk::ParseEventsF3V6(void) +{ + if (this->family != 3 || this->familyVersion != 6) { + qWarning() << "ParseEventsF3V6 called with family" << this->family << "familyVersion" << this->familyVersion; + //break; // don't break to avoid changing behavior (for now) + } + + int t = 0; int pos = 0; - int datasize = event->m_data.size(); + int datasize = this->m_data.size(); - unsigned char * data = (unsigned char *)event->m_data.data(); + unsigned char * data = (unsigned char *)this->m_data.data(); unsigned char code; unsigned short delta; bool failed = false; @@ -1958,29 +2106,13 @@ bool PRS1Import::ParseF3EventsV3() QString dump; do { + int startpos = pos; code = data[pos++]; delta = (data[pos+1] < 8) | data[pos]; pos += 2; #ifdef DEBUG_EVENTS if (code == 0x00) { - if (!loader->unknownCodes.contains(code)) { - loader->unknownCodes.insert(code, QStringList()); - } - QStringList & str = loader->unknownCodes[code]; - - dump = QString("%1@0x%5: [%2] [%3 %4]") - .arg(session->session(), 8, 16, QChar('0')) - .arg(data[pos-3], 2, 16, QChar('0')) - .arg(data[pos-2], 2, 16, QChar('0')) - .arg(data[pos-1], 2, 16, QChar('0')) - .arg(pos-3, 5, 16, QChar('0')); - - for (int i=0; i<15; i++) { - if ((pos+i) > datasize) break; - dump += QString(" %1").arg(data[pos+i], 2, 16, QChar('0')); - } - str.append(dump.trimmed()); - + this->AddEvent(new PRS1UnknownDataEvent(this->m_data, startpos)); } #endif unsigned short epap; @@ -1988,95 +2120,72 @@ bool PRS1Import::ParseF3EventsV3() switch(code) { case 0x01: // Who knows val = data[pos++]; - PP->AddEvent(t, val); + this->AddEvent(new PRS1TimedBreathEvent(t, val)); break; case 0x02: - LEAK->AddEvent(t, data[pos+3]); - PTB->AddEvent(t, data[pos+5]); - MV->AddEvent(t, data[pos+6]); - TV->AddEvent(t, data[pos+7]); + this->AddEvent(new PRS1LeakEvent(t, data[pos+3])); + this->AddEvent(new PRS1PatientTriggeredBreathsEvent(t, data[pos+5])); + this->AddEvent(new PRS1MinuteVentilationEvent(t, data[pos+6])); + this->AddEvent(new PRS1TidalVolumeEvent(t, data[pos+7])); - EPAP->AddEvent(t, epap=data[pos+0]); - IPAP->AddEvent(t, data[pos+1]); - FLOW->AddEvent(t, data[pos+4]); - TMV->AddEvent(t, data[pos+8]); - RR->AddEvent(t, data[pos+9]); + this->AddEvent(new PRS1EPAPEvent(t, epap=data[pos+0])); + this->AddEvent(new PRS1IPAPEvent(t, data[pos+1])); + this->AddEvent(new PRS1Test2Event(t, data[pos+4])); // Flow??? + this->AddEvent(new PRS1Test1Event(t, data[pos+8])); // TMV??? + this->AddEvent(new PRS1RespiratoryRateEvent(t, data[pos+9])); pos += 12; break; case 0x04: // ??? val = data[pos++]; - PP->AddEvent(t, val); + this->AddEvent(new PRS1TimedBreathEvent(t, val)); break; case 0x05: // ??? val = data[pos++]; - CA->AddEvent(t, val); + this->AddEvent(new PRS1ClearAirwayEvent(t, val)); break; case 0x06: // Obstructive Apnea val = data[pos++]; val2 = data[pos++]; - OA->AddEvent(t + (qint64(val2)*1000L), val); + this->AddEvent(new PRS1ObstructiveApneaEvent(t + val2, val)); // ??? shouldn't this be t - val2? break; case 0x07: // PB val = data[pos+1] << 8 | data[pos]; pos += 2; val2 = data[pos++]; - PB->AddEvent(t - (qint64(val2)*1000L), val); + this->AddEvent(new PRS1PeriodicBreathingEvent(t - val2, val)); break; case 0x08: // RERA val = data[pos++]; - RE->AddEvent(t, val); + this->AddEvent(new PRS1RERAEvent(t, val)); break; case 0x09: // ??? val = data[pos+1] << 8 | data[pos]; pos += 2; val2 = data[pos++]; - LL->AddEvent(t - (qint64(val)*1000L), val2); + this->AddEvent(new PRS1LargeLeakEvent(t - val, val2)); break; case 0x0a: // ??? val = data[pos++]; - ZZ->AddEvent(t, val); + this->AddEvent(new PRS1NonRespondingEvent(t, val)); break; case 0x0b: // Hypopnea val = data[pos++]; - if (session->session() == 239) { - if (HY->count() == 0) { - qDebug() << t << delta << val << "hypopnea"; - } - } - HY->AddEvent(t, val); + this->AddEvent(new PRS1HypopneaEvent(t, val)); break; default: - if (!loader->unknownCodes.contains(code)) { - loader->unknownCodes.insert(code, QStringList()); - } - QStringList & str = loader->unknownCodes[code]; - - dump = QString("%1@0x%5: [%2] [%3 %4]") - .arg(session->session(), 8, 16, QChar('0')) - .arg(data[pos-3], 2, 16, QChar('0')) - .arg(data[pos-2], 2, 16, QChar('0')) - .arg(data[pos-1], 2, 16, QChar('0')) - .arg(pos-3, 5, 16, QChar('0')); - - for (int i=0; i<15; i++) { - if ((pos+i) > datasize) break; - dump += QString(" %1").arg(data[pos+i], 2, 16, QChar('0')); - } - str.append(dump.trimmed()); - + this->AddEvent(new PRS1UnknownDataEvent(this->m_data, startpos)); failed = true; break; }; - t += qint64(delta) * 1000L; + t += delta; } while ((pos < datasize) && !failed); if (failed) { - // Clean up this shit... return false; } return true; diff --git a/oscar/SleepLib/loader_plugins/prs1_loader.h b/oscar/SleepLib/loader_plugins/prs1_loader.h index 97dc9ae1..b56a3325 100644 --- a/oscar/SleepLib/loader_plugins/prs1_loader.h +++ b/oscar/SleepLib/loader_plugins/prs1_loader.h @@ -129,6 +129,9 @@ public: //! \brief Parse a single data chunk from a .001 file containing summary data for a family 5 ASV family version 3 machine bool ParseSummaryF5V3(void); + + //! \brief Parse a single data chunk from a .002 file containing event data for a family 3 ventilator family version 6 machine + bool ParseEventsF3V6(void); //! \brief Parse a single data chunk from a .002 file containing event data for a family 5 ASV family version 0-2 machine bool ParseEventsF5V012(void);