Split parsing from importing for F5V0, F5V1, F5V2 events.

This commit is contained in:
sawinglogz 2019-05-24 17:08:51 -04:00
parent a5b4851583
commit a4612a4f24
2 changed files with 186 additions and 110 deletions

View File

@ -956,6 +956,7 @@ void PRS1Loader::ScanFiles(const QStringList & paths, int sessionid_base, Machin
enum PRS1ParsedEventType enum PRS1ParsedEventType
{ {
EV_PRS1_UNKNOWN = 0, // these have their value graphed
EV_PRS1_TB, EV_PRS1_TB,
EV_PRS1_OA, EV_PRS1_OA,
EV_PRS1_CA, EV_PRS1_CA,
@ -965,6 +966,7 @@ enum PRS1ParsedEventType
EV_PRS1_HY, EV_PRS1_HY,
EV_PRS1_IPAP, EV_PRS1_IPAP,
EV_PRS1_TOTLEAK, EV_PRS1_TOTLEAK,
EV_PRS1_LEAK, // F5V2: Is this real or actually TOTLEAK?
EV_PRS1_IPAPLOW, EV_PRS1_IPAPLOW,
EV_PRS1_IPAPHIGH, EV_PRS1_IPAPHIGH,
EV_PRS1_RR, EV_PRS1_RR,
@ -1031,6 +1033,13 @@ protected:
PRS1ParsedValueEvent(PRS1ParsedEventType type, int start, int value) : PRS1ParsedEvent(type, start) { m_value = value; } PRS1ParsedValueEvent(PRS1ParsedEventType type, int start, int value) : PRS1ParsedEvent(type, start) { m_value = value; }
}; };
class PRS1UnknownValueEvent : public PRS1ParsedValueEvent
{
public:
int m_code;
PRS1UnknownValueEvent(int code, int start, int value, float gain=1.0) : PRS1ParsedValueEvent(EV_PRS1_UNKNOWN, start, value), m_code(code) { m_gain = gain; }
};
class PRS1PressureEvent : public PRS1ParsedValueEvent class PRS1PressureEvent : public PRS1ParsedValueEvent
{ {
public: public:
@ -1118,6 +1127,12 @@ public:
PRS1TotalLeakEvent(int start, int value) : PRS1ParsedValueEvent(EV_PRS1_TOTLEAK, start, value) {} PRS1TotalLeakEvent(int start, int value) : PRS1ParsedValueEvent(EV_PRS1_TOTLEAK, start, value) {}
}; };
class PRS1LeakEvent : public PRS1ParsedValueEvent // TODO: F5V2 - is this real or actually TotalLeak?
{
public:
PRS1LeakEvent(int start, int value) : PRS1ParsedValueEvent(EV_PRS1_LEAK, start, value) {}
};
class PRS1IPAPHighEvent : public PRS1PressureEvent class PRS1IPAPHighEvent : public PRS1PressureEvent
{ {
public: public:
@ -1496,9 +1511,7 @@ bool PRS1Import::ParseF5Events()
//EventList * PRESSURE=nullptr; //EventList * PRESSURE=nullptr;
//EventList * PP=nullptr; //EventList * PP=nullptr;
EventDataType data0, data1, data2, data4, data5; EventDataType currentPressure=0, leak, ps=0; //, p;
EventDataType currentPressure=0, leak; //, p;
bool calcLeaks = p_profile->cpap->calculateUnintentionalLeaks(); bool calcLeaks = p_profile->cpap->calculateUnintentionalLeaks();
EventDataType lpm4 = p_profile->cpap->custom4cmH2OLeaks(); EventDataType lpm4 = p_profile->cpap->custom4cmH2OLeaks();
@ -1511,7 +1524,120 @@ bool PRS1Import::ParseF5Events()
//qint64 start=timestamp; //qint64 start=timestamp;
qint64 t = qint64(event->timestamp) * 1000L; qint64 t = qint64(event->timestamp) * 1000L;
session->updateFirst(t); session->updateFirst(t);
qint64 tt;
bool ok;
ok = event->ParseEventsF5V012();
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_FL:
FL->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_IPAP:
IPAP->AddEvent(t, e->m_value);
currentPressure = e->m_value;
break;
case EV_PRS1_IPAPLOW:
IPAPLo->AddEvent(t, e->m_value);
break;
case EV_PRS1_IPAPHIGH:
IPAPHi->AddEvent(t, e->m_value);
break;
case EV_PRS1_TOTLEAK:
TOTLEAK->AddEvent(t, e->m_value);
leak = e->m_value;
if (calcLeaks) { // Much Quicker doing this here than the recalc method.
leak -= (((currentPressure/10.0f) - 4.0) * ppm + lpm4);
if (leak < 0) leak = 0;
LEAK->AddEvent(t, leak);
}
break;
case EV_PRS1_LEAK: // F5V2, 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_SNORE:
SNORE->AddEvent(t, e->m_value);
if (e->m_value > 0) {
VS->AddEvent(t, 0); //data2); // VSnore
}
break;
case EV_PRS1_EPAP:
EPAP->AddEvent(t, e->m_value);
ps = currentPressure - e->m_value;
PS->AddEvent(t, ps); // Pressure Support
break;
case EV_PRS1_UNKNOWN:
{
int code = ((PRS1UnknownValueEvent*) e)->m_code;
Q_ASSERT(code < ncodes);
if (!Code[code]) {
ChannelID cpapcode = Codes[(int)code];
if (!(Code[code] = session->AddEventList(cpapcode, EVL_Event, e->m_gain))) { return false; }
}
Code[code]->AddEvent(t, e->m_value);
break;
}
default:
qWarning() << "Unknown PRS1 event type" << (int) e->m_type;
break;
}
}
if (!ok) {
return false;
}
t = qint64(event->timestamp + event->duration) * 1000L;
session->updateLast(t);
session->m_cnt.clear();
session->m_cph.clear();
session->m_valuesummary[CPAP_Pressure].clear();
session->m_valuesummary.erase(session->m_valuesummary.find(CPAP_Pressure));
return true;
}
// 950P is F5V0, 960P and 961P are F5V1, 960T is F5V2
bool PRS1DataChunk::ParseEventsF5V012(void)
{
EventDataType data0, data1, data2, data4, data5;
int t = 0;
int pos = 0; int pos = 0;
int cnt = 0; int cnt = 0;
short delta;//,duration; short delta;//,duration;
@ -1519,8 +1645,8 @@ bool PRS1Import::ParseF5Events()
unsigned char lastcode3 = 0, lastcode2 = 0, lastcode = 0, code = 0; unsigned char lastcode3 = 0, lastcode2 = 0, lastcode = 0, code = 0;
int lastpos = 0, startpos = 0, lastpos2 = 0, lastpos3 = 0; int lastpos = 0, startpos = 0, lastpos2 = 0, lastpos3 = 0;
int size = event->m_data.size(); int size = this->m_data.size();
unsigned char * buffer = (unsigned char *)event->m_data.data(); unsigned char * buffer = (unsigned char *)this->m_data.data();
while (pos < size) { while (pos < size) {
lastcode3 = lastcode2; lastcode3 = lastcode2;
@ -1532,8 +1658,8 @@ bool PRS1Import::ParseF5Events()
startpos = pos; startpos = pos;
code = buffer[pos++]; code = buffer[pos++];
if (code >= ncodes) { if (code >= 0x13) {
qDebug() << "Illegal PRS1 code " << hex << int(code) << " appeared at " << hex << startpos << "in" << event->sessionid;; qDebug() << "Illegal PRS1 code " << hex << int(code) << " appeared at " << hex << startpos << "in" << this->sessionid;;
qDebug() << "1: (" << int(lastcode) << hex << lastpos << ")"; qDebug() << "1: (" << int(lastcode) << hex << lastpos << ")";
qDebug() << "2: (" << int(lastcode2) << hex << lastpos2 << ")"; qDebug() << "2: (" << int(lastcode2) << hex << lastpos2 << ")";
qDebug() << "3: (" << int(lastcode3) << hex << lastpos3 << ")"; qDebug() << "3: (" << int(lastcode3) << hex << lastpos3 << ")";
@ -1541,17 +1667,16 @@ bool PRS1Import::ParseF5Events()
} }
if (code == 0) { if (code == 0) {
// No delta
} else if (code != 0x12) { } else if (code != 0x12) {
delta = buffer[pos]; delta = buffer[pos];
//duration=buffer[pos+1]; //duration=buffer[pos+1];
//delta=buffer[pos+1] << 8 | buffer[pos]; //delta=buffer[pos+1] << 8 | buffer[pos];
pos += 2; pos += 2;
t += qint64(delta) * 1000L; t += delta;
} }
ChannelID cpapcode = Codes[(int)code];
//EventDataType PS; //EventDataType PS;
tt = t;
cnt++; cnt++;
int fc = 0; int fc = 0;
@ -1574,11 +1699,7 @@ bool PRS1Import::ParseF5Events()
break; break;
case 0x01: // Unknown case 0x01: // Unknown
if (!Code[1]) { this->AddEvent(new PRS1UnknownValueEvent(code, t, 0, 0.1F));
if (!(Code[1] = session->AddEventList(cpapcode, EVL_Event, 0.1F))) { return false; }
}
Code[1]->AddEvent(t, 0);
break; break;
case 0x02: // Pressure ??? case 0x02: // Pressure ???
@ -1602,57 +1723,47 @@ bool PRS1Import::ParseF5Events()
case 0x04: // Timed Breath case 0x04: // Timed Breath
data0 = buffer[pos++]; data0 = buffer[pos++];
TB->AddEvent(t, data0); this->AddEvent(new PRS1TimedBreathEvent(t, data0));
break; break;
case 0x05: case 0x05:
//code=CPAP_Obstructive; //code=CPAP_Obstructive;
data0 = buffer[pos++]; data0 = buffer[pos++];
tt -= qint64(data0) * 1000L; // Subtract Time Offset this->AddEvent(new PRS1ObstructiveApneaEvent(t - data0, data0));
OA->AddEvent(tt, data0);
break; break;
case 0x06: case 0x06:
//code=CPAP_ClearAirway; //code=CPAP_ClearAirway;
data0 = buffer[pos++]; data0 = buffer[pos++];
tt -= qint64(data0) * 1000L; // Subtract Time Offset this->AddEvent(new PRS1ClearAirwayEvent(t - data0, data0));
CA->AddEvent(tt, data0);
break; break;
case 0x07: case 0x07:
//code=CPAP_Hypopnea; //code=CPAP_Hypopnea;
data0 = buffer[pos++]; data0 = buffer[pos++];
tt -= qint64(data0) * 1000L; // Subtract Time Offset this->AddEvent(new PRS1HypopneaEvent(t - data0, data0));
HY->AddEvent(tt, data0);
break; break;
case 0x08: // ??? case 0x08: // ???
data0 = buffer[pos++]; data0 = buffer[pos++];
tt -= qint64(data0) * 1000L; // Subtract Time Offset
//qDebug() << "Code 8 found at " << hex << pos - 1 << " " << tt; //qDebug() << "Code 8 found at " << hex << pos - 1 << " " << tt;
if (event->familyVersion>=2) { if (this->familyVersion>=2) {
HY->AddEvent(tt, data0); this->AddEvent(new PRS1HypopneaEvent(t - data0, data0));
} else { } else {
if (!Code[10]) { this->AddEvent(new PRS1UnknownValueEvent(code, t - data0, data0));
if (!(Code[10] = session->AddEventList(cpapcode, EVL_Event))) { return false; }
}
//???? //????
//data1=buffer[pos++]; // ??? //data1=buffer[pos++]; // ???
Code[10]->AddEvent(tt, data0);
//pos++; //pos++;
} }
break; break;
case 0x09: // ASV Codes case 0x09: // ASV Codes
if (event->familyVersion<2) { if (this->familyVersion<2) {
//code=CPAP_FlowLimit; //code=CPAP_FlowLimit;
data0 = buffer[pos++]; data0 = buffer[pos++];
tt -= qint64(data0) * 1000L; // Subtract Time Offset
FL->AddEvent(tt, data0); this->AddEvent(new PRS1FlowLimitationEvent(t - data0, data0));
} else { } else {
data0 = buffer[pos++]; data0 = buffer[pos++];
data1 = buffer[pos++]; data1 = buffer[pos++];
@ -1662,15 +1773,10 @@ bool PRS1Import::ParseF5Events()
case 0x0a: case 0x0a:
data0 = buffer[pos++]; data0 = buffer[pos++];
tt -= qint64(data0) * 1000L; // Subtract Time Offset if (this->familyVersion>=2) {
if (event->familyVersion>=2) { this->AddEvent(new PRS1FlowLimitationEvent(t - data0, data0));
FL->AddEvent(tt, data0);
} else { } else {
if (!Code[7]) { this->AddEvent(new PRS1UnknownValueEvent(code, t - data0, data0));
if (!(Code[7] = session->AddEventList(cpapcode, EVL_Event))) { return false; }
}
Code[7]->AddEvent(tt, data0);
} }
break; break;
@ -1682,74 +1788,52 @@ bool PRS1Import::ParseF5Events()
data1 = ((unsigned char *)buffer)[pos]; //|buffer[pos+1] << 8 data1 = ((unsigned char *)buffer)[pos]; //|buffer[pos+1] << 8
pos += 1; pos += 1;
//tt-=delta; //tt-=delta;
tt -= qint64(data1) * 1000L; this->AddEvent(new PRS1PeriodicBreathingEvent(t - data1, data0));
PB->AddEvent(tt, data0);
break; break;
case 0x0c: case 0x0c:
if (event->familyVersion>=2) { if (this->familyVersion>=2) {
data0 = (buffer[pos + 1] << 8 | buffer[pos]); data0 = (buffer[pos + 1] << 8 | buffer[pos]);
data0 *= 2; data0 *= 2;
pos += 2; pos += 2;
data1 = buffer[pos++]; data1 = buffer[pos++];
tt = t - qint64(data1) * 1000L; this->AddEvent(new PRS1PeriodicBreathingEvent(t - data1, data0));
PB->AddEvent(tt, data0);
} else { } else {
data0 = buffer[pos++]; data0 = buffer[pos++];
tt -= qint64(data0) * 1000L; // Subtract Time Offset qDebug() << "Code 12 found at " << hex << pos - 1 << " " << t - data0;
qDebug() << "Code 12 found at " << hex << pos - 1 << " " << tt;
this->AddEvent(new PRS1UnknownValueEvent(code, t - data0, data0));
if (!Code[8]) {
if (!(Code[8] = session->AddEventList(cpapcode, EVL_Event))) { return false; }
}
Code[8]->AddEvent(tt, data0);
pos += 2; pos += 2;
} }
break; break;
case 0x0d: // All the other ASV graph stuff. case 0x0d: // All the other ASV graph stuff.
if (event->familyVersion>=2) { if (this->familyVersion>=2) {
data0 = (buffer[pos + 1] << 8 | buffer[pos]); data0 = (buffer[pos + 1] << 8 | buffer[pos]);
data0 *= 2; data0 *= 2;
pos += 2; pos += 2;
data1 = buffer[pos++]; data1 = buffer[pos++];
tt = t - qint64(data1) * 1000L; //tt = t - qint64(data1) * 1000L;
} else { } else {
IPAP->AddEvent(t, currentPressure = data0 = buffer[pos++]); // 00=IAP this->AddEvent(new PRS1IPAPEvent(t, buffer[pos++])); // 00=IAP
data4 = buffer[pos++]; data4 = buffer[pos++];
IPAPLo->AddEvent(t, data4); // 01=IAP Low this->AddEvent(new PRS1IPAPLowEvent(t, data4)); // 01=IAP Low
data5 = buffer[pos++]; data5 = buffer[pos++];
IPAPHi->AddEvent(t, data5); // 02=IAP High this->AddEvent(new PRS1IPAPHighEvent(t, data5)); // 02=IAP High
TOTLEAK->AddEvent(t, leak=buffer[pos++]); // 03=LEAK this->AddEvent(new PRS1TotalLeakEvent(t, buffer[pos++])); // 03=LEAK
if (calcLeaks) { // Much Quicker doing this here than the recalc method.
leak -= (((currentPressure/10.0f) - 4.0) * ppm + lpm4);
if (leak < 0) leak = 0;
LEAK->AddEvent(t, leak); this->AddEvent(new PRS1RespiratoryRateEvent(t, buffer[pos++])); // 04=Breaths Per Minute
} this->AddEvent(new PRS1PatientTriggeredBreathsEvent(t, buffer[pos++])); // 05=Patient Triggered Breaths
this->AddEvent(new PRS1MinuteVentilationEvent(t, buffer[pos++])); // 06=Minute Ventilation
RR->AddEvent(t, buffer[pos++]); // 04=Breaths Per Minute
PTB->AddEvent(t, buffer[pos++]); // 05=Patient Triggered Breaths
MV->AddEvent(t, buffer[pos++]); // 06=Minute Ventilation
//tmp=buffer[pos++] * 10.0; //tmp=buffer[pos++] * 10.0;
TV->AddEvent(t, buffer[pos++]); // 07=Tidal Volume this->AddEvent(new PRS1TidalVolumeEvent(t, buffer[pos++])); // 07=Tidal Volume
SNORE->AddEvent(t, data2 = buffer[pos++]); // 08=Snore this->AddEvent(new PRS1SnoreEvent(t, buffer[pos++])); // 08=Snore
this->AddEvent(new PRS1EPAPEvent(t, data1 = buffer[pos++])); // 09=EPAP
if (data2 > 0) { if (this->familyVersion >= 1) {
VS->AddEvent(t, 0); //data2); // VSnore
}
EPAP->AddEvent(t, data1 = buffer[pos++]); // 09=EPAP
data2 = data0 - data1;
PS->AddEvent(t, data2); // Pressure Support
if (event->familyVersion >= 1) {
data0 = buffer[pos++]; data0 = buffer[pos++];
} }
} }
@ -1757,23 +1841,17 @@ bool PRS1Import::ParseF5Events()
case 0x0e: // Unknown case 0x0e: // Unknown
// Family 5.2 has this code // Family 5.2 has this code
if (event->familyVersion>=2) { if (this->familyVersion>=2) {
EPAP->AddEvent(t, data0=buffer[pos+9]); // 9 this->AddEvent(new PRS1IPAPEvent(t, data1=buffer[pos+0])); // 0
IPAP->AddEvent(t, data1=buffer[pos+0]); // 0 this->AddEvent(new PRS1IPAPLowEvent(t, buffer[pos+1])); // 1
IPAPLo->AddEvent(t, buffer[pos+1]); // 1 this->AddEvent(new PRS1IPAPHighEvent(t, buffer[pos+2])); // 2
IPAPHi->AddEvent(t, buffer[pos+2]); // 2 this->AddEvent(new PRS1LeakEvent(t, buffer[pos+3])); // 3 // F5V2, is this really leak rather than totleak?
LEAK->AddEvent(t, buffer[pos+3]); // 3 this->AddEvent(new PRS1TidalVolumeEvent(t, buffer[pos+7])); // 7
TV->AddEvent(t, buffer[pos+7]); // 7 this->AddEvent(new PRS1RespiratoryRateEvent(t, buffer[pos+4])); // 4
RR->AddEvent(t, buffer[pos+4]); // 4 this->AddEvent(new PRS1PatientTriggeredBreathsEvent(t, buffer[pos+5])); // 5
PTB->AddEvent(t, buffer[pos+5]); // 5 this->AddEvent(new PRS1MinuteVentilationEvent(t, buffer[pos+6])); //6
MV->AddEvent(t, buffer[pos+6]); //6 this->AddEvent(new PRS1SnoreEvent(t, buffer[pos+8])); //??
SNORE->AddEvent(t, data2 = buffer[pos+8]); //?? this->AddEvent(new PRS1EPAPEvent(t, buffer[pos+9])); // 9
if (data2 > 0) {
VS->AddEvent(t, 0); //data2); // VSnore
}
data2 = data1 - data0;
PS->AddEvent(t, data2); // Pressure Support
pos+=11; pos+=11;
} else { } else {
qDebug() << "0x0E Observed in ASV data!!????"; qDebug() << "0x0E Observed in ASV data!!????";
@ -1789,7 +1867,7 @@ bool PRS1Import::ParseF5Events()
pos += 2; pos += 2;
data1 = buffer[pos]; //|buffer[pos+1] << 8 data1 = buffer[pos]; //|buffer[pos+1] << 8
pos += 1; pos += 1;
tt -= qint64(data1) * 1000L; //tt -= qint64(data1) * 1000L;
//session->AddEvent(new Event(tt,cpapcode, 0, data, 2)); //session->AddEvent(new Event(tt,cpapcode, 0, data, 2));
break; break;
@ -1798,8 +1876,7 @@ bool PRS1Import::ParseF5Events()
pos += 2; pos += 2;
data1 = buffer[pos++]; data1 = buffer[pos++];
tt = t - qint64(data1) * 1000L; this->AddEvent(new PRS1LargeLeakEvent(t - data1, data0));
LL->AddEvent(tt, data0);
// qDebug() << "0x10 Observed in ASV data!!????"; // qDebug() << "0x10 Observed in ASV data!!????";
// data0 = buffer[pos++]; // << 8) | buffer[pos]; // data0 = buffer[pos++]; // << 8) | buffer[pos];
@ -1835,13 +1912,7 @@ bool PRS1Import::ParseF5Events()
break; break;
} }
} }
this->duration = t; // The last event might start before t, so record the last delta timestamp.
session->updateLast(t);
session->m_cnt.clear();
session->m_cph.clear();
session->m_valuesummary[CPAP_Pressure].clear();
session->m_valuesummary.erase(session->m_valuesummary.find(CPAP_Pressure));
return true; return true;
@ -2010,6 +2081,8 @@ bool PRS1Import::ParseF3EventsV3()
} }
return true; return true;
} }
bool PRS1Import::ParseF3Events() bool PRS1Import::ParseF3Events()
{ {
qint64 t = qint64(event->timestamp) * 1000L, tt; qint64 t = qint64(event->timestamp) * 1000L, tt;

View File

@ -130,6 +130,9 @@ public:
//! \brief Parse a single data chunk from a .001 file containing summary data for a family 5 ASV family version 3 machine //! \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); bool ParseSummaryF5V3(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);
//! \brief Parse a single data chunk from a .002 file containing event data for a family 5 ASV family version 3 machine //! \brief Parse a single data chunk from a .002 file containing event data for a family 5 ASV family version 3 machine
bool ParseEventsF5V3(void); bool ParseEventsF5V3(void);