Split parsing from importing for F3V6 events.

This commit is contained in:
sawinglogz 2019-05-24 19:41:42 -04:00
parent a4612a4f24
commit 5a88887cc3
2 changed files with 177 additions and 65 deletions

View File

@ -956,6 +956,7 @@ void PRS1Loader::ScanFiles(const QStringList & paths, int sessionid_base, Machin
enum PRS1ParsedEventType enum PRS1ParsedEventType
{ {
EV_PRS1_RAW = -1, // these only get logged
EV_PRS1_UNKNOWN = 0, // these have their value graphed EV_PRS1_UNKNOWN = 0, // these have their value graphed
EV_PRS1_TB, EV_PRS1_TB,
EV_PRS1_OA, EV_PRS1_OA,
@ -975,6 +976,10 @@ enum PRS1ParsedEventType
EV_PRS1_TV, EV_PRS1_TV,
EV_PRS1_SNORE, EV_PRS1_SNORE,
EV_PRS1_EPAP, EV_PRS1_EPAP,
EV_PRS1_RERA,
EV_PRS1_NRI,
EV_PRS1_TEST1,
EV_PRS1_TEST2,
EV_PRS1_SETTING, 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; } 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 class PRS1PressureEvent : public PRS1ParsedValueEvent
{ {
public: public:
@ -1186,6 +1207,30 @@ public:
PRS1EPAPEvent(int start, int value) : PRS1PressureEvent(EV_PRS1_EPAP, start, value) {} 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) void PRS1DataChunk::AddEvent(PRS1ParsedEvent* const event)
{ {
m_parsedData.push_back(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! :/) // 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 *OA = session->AddEventList(CPAP_Obstructive, EVL_Event);
EventList *HY = session->AddEventList(CPAP_Hypopnea, EVL_Event); EventList *HY = session->AddEventList(CPAP_Hypopnea, EVL_Event);
EventList *ZZ = session->AddEventList(CPAP_NRI, 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 *IPAP = session->AddEventList(CPAP_IPAP, EVL_Event, 0.1f);
EventList *FLOW = session->AddEventList(CPAP_Test2, EVL_Event); 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; i<unk->m_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 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 char code;
unsigned short delta; unsigned short delta;
bool failed = false; bool failed = false;
@ -1958,29 +2106,13 @@ bool PRS1Import::ParseF3EventsV3()
QString dump; QString dump;
do { do {
int startpos = pos;
code = data[pos++]; code = data[pos++];
delta = (data[pos+1] < 8) | data[pos]; delta = (data[pos+1] < 8) | data[pos];
pos += 2; pos += 2;
#ifdef DEBUG_EVENTS #ifdef DEBUG_EVENTS
if (code == 0x00) { if (code == 0x00) {
if (!loader->unknownCodes.contains(code)) { this->AddEvent(new PRS1UnknownDataEvent(this->m_data, startpos));
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());
} }
#endif #endif
unsigned short epap; unsigned short epap;
@ -1988,95 +2120,72 @@ bool PRS1Import::ParseF3EventsV3()
switch(code) { switch(code) {
case 0x01: // Who knows case 0x01: // Who knows
val = data[pos++]; val = data[pos++];
PP->AddEvent(t, val); this->AddEvent(new PRS1TimedBreathEvent(t, val));
break; break;
case 0x02: case 0x02:
LEAK->AddEvent(t, data[pos+3]); this->AddEvent(new PRS1LeakEvent(t, data[pos+3]));
PTB->AddEvent(t, data[pos+5]); this->AddEvent(new PRS1PatientTriggeredBreathsEvent(t, data[pos+5]));
MV->AddEvent(t, data[pos+6]); this->AddEvent(new PRS1MinuteVentilationEvent(t, data[pos+6]));
TV->AddEvent(t, data[pos+7]); this->AddEvent(new PRS1TidalVolumeEvent(t, data[pos+7]));
EPAP->AddEvent(t, epap=data[pos+0]); this->AddEvent(new PRS1EPAPEvent(t, epap=data[pos+0]));
IPAP->AddEvent(t, data[pos+1]); this->AddEvent(new PRS1IPAPEvent(t, data[pos+1]));
FLOW->AddEvent(t, data[pos+4]); this->AddEvent(new PRS1Test2Event(t, data[pos+4])); // Flow???
TMV->AddEvent(t, data[pos+8]); this->AddEvent(new PRS1Test1Event(t, data[pos+8])); // TMV???
RR->AddEvent(t, data[pos+9]); this->AddEvent(new PRS1RespiratoryRateEvent(t, data[pos+9]));
pos += 12; pos += 12;
break; break;
case 0x04: // ??? case 0x04: // ???
val = data[pos++]; val = data[pos++];
PP->AddEvent(t, val); this->AddEvent(new PRS1TimedBreathEvent(t, val));
break; break;
case 0x05: // ??? case 0x05: // ???
val = data[pos++]; val = data[pos++];
CA->AddEvent(t, val); this->AddEvent(new PRS1ClearAirwayEvent(t, val));
break; break;
case 0x06: // Obstructive Apnea case 0x06: // Obstructive Apnea
val = data[pos++]; val = data[pos++];
val2 = 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; break;
case 0x07: // PB case 0x07: // PB
val = data[pos+1] << 8 | data[pos]; val = data[pos+1] << 8 | data[pos];
pos += 2; pos += 2;
val2 = data[pos++]; val2 = data[pos++];
PB->AddEvent(t - (qint64(val2)*1000L), val); this->AddEvent(new PRS1PeriodicBreathingEvent(t - val2, val));
break; break;
case 0x08: // RERA case 0x08: // RERA
val = data[pos++]; val = data[pos++];
RE->AddEvent(t, val); this->AddEvent(new PRS1RERAEvent(t, val));
break; break;
case 0x09: // ??? case 0x09: // ???
val = data[pos+1] << 8 | data[pos]; val = data[pos+1] << 8 | data[pos];
pos += 2; pos += 2;
val2 = data[pos++]; val2 = data[pos++];
LL->AddEvent(t - (qint64(val)*1000L), val2); this->AddEvent(new PRS1LargeLeakEvent(t - val, val2));
break; break;
case 0x0a: // ??? case 0x0a: // ???
val = data[pos++]; val = data[pos++];
ZZ->AddEvent(t, val); this->AddEvent(new PRS1NonRespondingEvent(t, val));
break; break;
case 0x0b: // Hypopnea case 0x0b: // Hypopnea
val = data[pos++]; val = data[pos++];
if (session->session() == 239) { this->AddEvent(new PRS1HypopneaEvent(t, val));
if (HY->count() == 0) {
qDebug() << t << delta << val << "hypopnea";
}
}
HY->AddEvent(t, val);
break; break;
default: default:
if (!loader->unknownCodes.contains(code)) { this->AddEvent(new PRS1UnknownDataEvent(this->m_data, startpos));
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());
failed = true; failed = true;
break; break;
}; };
t += qint64(delta) * 1000L; t += delta;
} while ((pos < datasize) && !failed); } while ((pos < datasize) && !failed);
if (failed) { if (failed) {
// Clean up this shit...
return false; return false;
} }
return true; return true;

View File

@ -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 //! \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 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 //! \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); bool ParseEventsF5V012(void);