mirror of
https://gitlab.com/pholy/OSCAR-code.git
synced 2025-04-05 10:40:42 +00:00
Migrate F5V012 event loop logic to match F0V4.
No changes were intended in the imported data, but the parsers were fantastically broken, so touching anything in the code results in lots of differences in the output. As a result, the imported data for F5V012 is now unstable. On the plus side, the parser no longer bails on event 8 for F5V1. This will almost certainly need to be split into 3 separate functions.
This commit is contained in:
parent
6992a2f1a9
commit
07aec55d80
@ -1615,6 +1615,24 @@ QMap<QString,QString> _PRS1ParsedEventContents(PRS1ParsedEvent* e)
|
||||
//********************************************************************************************
|
||||
|
||||
|
||||
static QString DumpEvent(int t, int code, const unsigned char* data, int size)
|
||||
{
|
||||
int s = t;
|
||||
int h = s / 3600; s -= h * 3600;
|
||||
int m = s / 60; s -= m * 60;
|
||||
QString dump = QString("%1:%2:%3")
|
||||
.arg(h, 2, 10, QChar('0'))
|
||||
.arg(m, 2, 10, QChar('0'))
|
||||
.arg(s, 2, 10, QChar('0'));
|
||||
dump = dump + " " + hex(code) + ":";
|
||||
for (int i = 0; i < size; i++) {
|
||||
dump = dump + QString(" %1").arg(data[i]);
|
||||
}
|
||||
return dump;
|
||||
}
|
||||
#define DUMP_EVENT() qWarning() << this->sessionid << DumpEvent(t, code, data + pos, size - (pos - startpos)) << "@" << pos
|
||||
|
||||
|
||||
void PRS1DataChunk::AddEvent(PRS1ParsedEvent* const event)
|
||||
{
|
||||
m_parsedData.push_back(event);
|
||||
@ -2104,67 +2122,62 @@ bool PRS1Import::ParseF5Events()
|
||||
// 950P is F5V0, 960P and 961P are F5V1, 960T is F5V2
|
||||
bool PRS1DataChunk::ParseEventsF5V012(void)
|
||||
{
|
||||
EventDataType data0, data1, data4, data5;
|
||||
if (this->family != 5 || this->familyVersion > 2) {
|
||||
qWarning() << "ParseEventsF5V012 called with family" << this->family << "familyVersion" << this->familyVersion;
|
||||
return false;
|
||||
}
|
||||
const unsigned char * data = (unsigned char *)this->m_data.constData();
|
||||
int chunk_size = this->m_data.size();
|
||||
QMap<int,int> event_sizes;
|
||||
// TODO: This probably needs to be split into 3 functions.
|
||||
switch (this->familyVersion) {
|
||||
case 0: event_sizes = { {0,3}, {1,2}, {3,4}, {9,3}, {0xa,2}, {0xb,5}, {0xc,5}, {0xd,0xc}, {0xf,5}, {0x10,5}, {0x11,2}, {0x12,6} }; break;
|
||||
case 1: event_sizes = { {0,4}, {1,2}, {3,4}, {8,4}, {9,3}, {0xa,2}, {0xb,5}, {0xc,5}, {0xd,0xd}, {0xf,5}, {0x10,5}, {0x11,2}, {0x12,6} }; break;
|
||||
case 2: event_sizes = { {0,4}, {1,2}, {3,4}, {9,4}, {0xa,2}, {0xb,5}, {0xc,5}, {0xd,5}, {0xe,0xd}, {0xf,5}, {0x10,5}, {0x11,2}, {0x12,6} }; break;
|
||||
}
|
||||
|
||||
if (chunk_size < 1) {
|
||||
// This does occasionally happen in F0V6.
|
||||
qDebug() << this->sessionid << "Empty event data";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
int pos = 0, startpos;
|
||||
int code, size;
|
||||
int t = 0;
|
||||
int pos = 0;
|
||||
int cnt = 0;
|
||||
short delta;//,duration;
|
||||
bool badcode = false;
|
||||
unsigned char lastcode3 = 0, lastcode2 = 0, lastcode = 0, code = 0;
|
||||
int lastpos = 0, startpos = 0, lastpos2 = 0, lastpos3 = 0;
|
||||
EventDataType data0, data1, data4, data5;
|
||||
//int elapsed, duration, value;
|
||||
do {
|
||||
code = data[pos++];
|
||||
|
||||
int size = this->m_data.size();
|
||||
unsigned char * buffer = (unsigned char *)this->m_data.data();
|
||||
|
||||
while (pos < size) {
|
||||
lastcode3 = lastcode2;
|
||||
lastcode2 = lastcode;
|
||||
lastcode = code;
|
||||
lastpos3 = lastpos2;
|
||||
lastpos2 = lastpos;
|
||||
lastpos = startpos;
|
||||
size = 3; // default size = 2 bytes time delta + 1 byte data
|
||||
if (event_sizes.contains(code)) {
|
||||
size = event_sizes[code];
|
||||
}
|
||||
if (pos + size > chunk_size) {
|
||||
qWarning() << this->sessionid << "event" << code << "@" << pos << "longer than remaining chunk";
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
startpos = pos;
|
||||
code = buffer[pos++];
|
||||
|
||||
if (code >= 0x13) {
|
||||
qDebug() << "Illegal PRS1 code " << hex << int(code) << " appeared at " << hex << startpos << "in" << this->sessionid;;
|
||||
qDebug() << "1: (" << int(lastcode) << hex << lastpos << ")";
|
||||
qDebug() << "2: (" << int(lastcode2) << hex << lastpos2 << ")";
|
||||
qDebug() << "3: (" << int(lastcode3) << hex << lastpos3 << ")";
|
||||
this->AddEvent(new PRS1UnknownDataEvent(m_data, startpos));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (code == 0) {
|
||||
// No delta
|
||||
} else if (code != 0x12) {
|
||||
delta = buffer[pos];
|
||||
//duration=buffer[pos+1];
|
||||
//delta=buffer[pos+1] << 8 | buffer[pos];
|
||||
if (code != 0 && code != 0x12) { // These two codes have no timestamp TODO: verify this applies to F5V012
|
||||
t += data[pos] /*| (data[pos+1] << 8)*/; // TODO: Is this really only 1 byte?
|
||||
pos += 2;
|
||||
t += delta;
|
||||
}
|
||||
|
||||
//EventDataType PS;
|
||||
cnt++;
|
||||
int fc = 0;
|
||||
|
||||
switch (code) {
|
||||
case 0x00: // Unknown (ASV Pressure value)
|
||||
// offset?
|
||||
data0 = buffer[pos++];
|
||||
fc++;
|
||||
data0 = data[pos++];
|
||||
|
||||
if (!buffer[pos - 1]) { // WTH???
|
||||
data1 = buffer[pos++];
|
||||
fc++;
|
||||
if (!data[pos - 1]) { // WTH???
|
||||
data1 = data[pos++];
|
||||
}
|
||||
|
||||
if (!buffer[pos - 1]) {
|
||||
//data2 = buffer[pos++];
|
||||
if (!data[pos - 1]) {
|
||||
//data2 = data[pos++];
|
||||
pos++;
|
||||
fc++;
|
||||
}
|
||||
|
||||
break;
|
||||
@ -2174,7 +2187,7 @@ bool PRS1DataChunk::ParseEventsF5V012(void)
|
||||
break;
|
||||
|
||||
case 0x02: // Pressure ???
|
||||
data0 = buffer[pos++];
|
||||
data0 = data[pos++];
|
||||
// if (!Code[2]) {
|
||||
// if (!(Code[2]=session->AddEventList(cpapcode,EVL_Event,0.1))) return false;
|
||||
// }
|
||||
@ -2183,8 +2196,8 @@ bool PRS1DataChunk::ParseEventsF5V012(void)
|
||||
case 0x03: // BIPAP Pressure
|
||||
qDebug() << "0x03 Observed in ASV data!!????";
|
||||
|
||||
data0 = buffer[pos++];
|
||||
data1 = buffer[pos++];
|
||||
data0 = data[pos++];
|
||||
data1 = data[pos++];
|
||||
// data0/=10.0;
|
||||
// data1/=10.0;
|
||||
// session->AddEvent(new Event(t,CPAP_EAP, 0, data, 1));
|
||||
@ -2192,31 +2205,33 @@ bool PRS1DataChunk::ParseEventsF5V012(void)
|
||||
break;
|
||||
|
||||
case 0x04: // Timed Breath
|
||||
data0 = buffer[pos++];
|
||||
data0 = data[pos++];
|
||||
|
||||
this->AddEvent(new PRS1TimedBreathEvent(t, data0));
|
||||
break;
|
||||
|
||||
case 0x05:
|
||||
//code=CPAP_Obstructive;
|
||||
data0 = buffer[pos++];
|
||||
data0 = data[pos++];
|
||||
this->AddEvent(new PRS1ObstructiveApneaEvent(t - data0, data0));
|
||||
break;
|
||||
|
||||
case 0x06:
|
||||
//code=CPAP_ClearAirway;
|
||||
data0 = buffer[pos++];
|
||||
data0 = data[pos++];
|
||||
this->AddEvent(new PRS1ClearAirwayEvent(t - data0, data0));
|
||||
break;
|
||||
|
||||
case 0x07:
|
||||
//code=CPAP_Hypopnea;
|
||||
data0 = buffer[pos++];
|
||||
data0 = data[pos++];
|
||||
this->AddEvent(new PRS1HypopneaEvent(t - data0, data0));
|
||||
break;
|
||||
|
||||
case 0x08: // ???
|
||||
data0 = buffer[pos++];
|
||||
// This was breaking parsing for F5V1 prior to using fixed lengths.
|
||||
// That means it's probably very wrong.
|
||||
data0 = data[pos++];
|
||||
//qDebug() << "Code 8 found at " << hex << pos - 1 << " " << tt;
|
||||
|
||||
if (this->familyVersion>=2) {
|
||||
@ -2224,7 +2239,7 @@ bool PRS1DataChunk::ParseEventsF5V012(void)
|
||||
} else {
|
||||
this->AddEvent(new PRS1UnknownValueEvent(code, t - data0, data0));
|
||||
//????
|
||||
//data1=buffer[pos++]; // ???
|
||||
//data1=data[pos++]; // ???
|
||||
//pos++;
|
||||
}
|
||||
break;
|
||||
@ -2232,18 +2247,18 @@ bool PRS1DataChunk::ParseEventsF5V012(void)
|
||||
case 0x09: // ASV Codes
|
||||
if (this->familyVersion<2) {
|
||||
//code=CPAP_FlowLimit;
|
||||
data0 = buffer[pos++];
|
||||
data0 = data[pos++];
|
||||
|
||||
this->AddEvent(new PRS1FlowLimitationEvent(t - data0, data0));
|
||||
} else {
|
||||
data0 = buffer[pos++];
|
||||
data1 = buffer[pos++];
|
||||
data0 = data[pos++];
|
||||
data1 = data[pos++];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0x0a:
|
||||
data0 = buffer[pos++];
|
||||
data0 = data[pos++];
|
||||
if (this->familyVersion>=2) {
|
||||
this->AddEvent(new PRS1FlowLimitationEvent(t - data0, data0));
|
||||
} else {
|
||||
@ -2253,10 +2268,10 @@ bool PRS1DataChunk::ParseEventsF5V012(void)
|
||||
|
||||
|
||||
case 0x0b: // Cheyne Stokes
|
||||
data0 = ((unsigned char *)buffer)[pos + 1] << 8 | ((unsigned char *)buffer)[pos];
|
||||
data0 = ((unsigned char *)data)[pos + 1] << 8 | ((unsigned char *)data)[pos];
|
||||
//data0*=2;
|
||||
pos += 2;
|
||||
data1 = ((unsigned char *)buffer)[pos]; //|buffer[pos+1] << 8
|
||||
data1 = ((unsigned char *)data)[pos]; //|data[pos+1] << 8
|
||||
pos += 1;
|
||||
//tt-=delta;
|
||||
this->AddEvent(new PRS1PeriodicBreathingEvent(t - data1, data0));
|
||||
@ -2265,14 +2280,14 @@ bool PRS1DataChunk::ParseEventsF5V012(void)
|
||||
case 0x0c:
|
||||
|
||||
if (this->familyVersion>=2) {
|
||||
data0 = (buffer[pos + 1] << 8 | buffer[pos]);
|
||||
data0 = (data[pos + 1] << 8 | data[pos]);
|
||||
data0 *= 2;
|
||||
pos += 2;
|
||||
data1 = buffer[pos++];
|
||||
data1 = data[pos++];
|
||||
this->AddEvent(new PRS1PeriodicBreathingEvent(t - data1, data0));
|
||||
|
||||
} else {
|
||||
data0 = buffer[pos++];
|
||||
data0 = data[pos++];
|
||||
qDebug() << "Code 12 found at " << hex << pos - 1 << " " << t - data0;
|
||||
|
||||
this->AddEvent(new PRS1UnknownValueEvent(code, t - data0, data0));
|
||||
@ -2283,29 +2298,29 @@ bool PRS1DataChunk::ParseEventsF5V012(void)
|
||||
case 0x0d: // All the other ASV graph stuff.
|
||||
|
||||
if (this->familyVersion>=2) {
|
||||
data0 = (buffer[pos + 1] << 8 | buffer[pos]);
|
||||
data0 = (data[pos + 1] << 8 | data[pos]);
|
||||
data0 *= 2;
|
||||
pos += 2;
|
||||
data1 = buffer[pos++];
|
||||
data1 = data[pos++];
|
||||
//tt = t - qint64(data1) * 1000L;
|
||||
} else {
|
||||
this->AddEvent(new PRS1IPAPAverageEvent(t, buffer[pos++])); // 00=IAP
|
||||
data4 = buffer[pos++];
|
||||
this->AddEvent(new PRS1IPAPAverageEvent(t, data[pos++])); // 00=IAP
|
||||
data4 = data[pos++];
|
||||
this->AddEvent(new PRS1IPAPLowEvent(t, data4)); // 01=IAP Low
|
||||
data5 = buffer[pos++];
|
||||
data5 = data[pos++];
|
||||
this->AddEvent(new PRS1IPAPHighEvent(t, data5)); // 02=IAP High
|
||||
|
||||
this->AddEvent(new PRS1TotalLeakEvent(t, buffer[pos++])); // 03=LEAK
|
||||
this->AddEvent(new PRS1TotalLeakEvent(t, data[pos++])); // 03=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
|
||||
//tmp=buffer[pos++] * 10.0;
|
||||
this->AddEvent(new PRS1TidalVolumeEvent(t, buffer[pos++])); // 07=Tidal Volume
|
||||
this->AddEvent(new PRS1SnoreEvent(t, buffer[pos++])); // 08=Snore
|
||||
this->AddEvent(new PRS1EPAPAverageEvent(t, data1 = buffer[pos++])); // 09=EPAP
|
||||
this->AddEvent(new PRS1RespiratoryRateEvent(t, data[pos++])); // 04=Breaths Per Minute
|
||||
this->AddEvent(new PRS1PatientTriggeredBreathsEvent(t, data[pos++])); // 05=Patient Triggered Breaths
|
||||
this->AddEvent(new PRS1MinuteVentilationEvent(t, data[pos++])); // 06=Minute Ventilation
|
||||
//tmp=data[pos++] * 10.0;
|
||||
this->AddEvent(new PRS1TidalVolumeEvent(t, data[pos++])); // 07=Tidal Volume
|
||||
this->AddEvent(new PRS1SnoreEvent(t, data[pos++])); // 08=Snore
|
||||
this->AddEvent(new PRS1EPAPAverageEvent(t, data1 = data[pos++])); // 09=EPAP
|
||||
if (this->familyVersion >= 1) {
|
||||
data0 = buffer[pos++];
|
||||
data0 = data[pos++];
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -2313,20 +2328,20 @@ bool PRS1DataChunk::ParseEventsF5V012(void)
|
||||
case 0x0e: // Unknown
|
||||
// Family 5.2 has this code
|
||||
if (this->familyVersion>=2) {
|
||||
this->AddEvent(new PRS1IPAPAverageEvent(t, data1=buffer[pos+0])); // 0
|
||||
this->AddEvent(new PRS1IPAPLowEvent(t, buffer[pos+1])); // 1
|
||||
this->AddEvent(new PRS1IPAPHighEvent(t, buffer[pos+2])); // 2
|
||||
this->AddEvent(new PRS1LeakEvent(t, buffer[pos+3])); // 3 // F5V2, is this really unintentional leak rather than total leak?
|
||||
this->AddEvent(new PRS1TidalVolumeEvent(t, buffer[pos+7])); // 7
|
||||
this->AddEvent(new PRS1RespiratoryRateEvent(t, buffer[pos+4])); // 4
|
||||
this->AddEvent(new PRS1PatientTriggeredBreathsEvent(t, buffer[pos+5])); // 5
|
||||
this->AddEvent(new PRS1MinuteVentilationEvent(t, buffer[pos+6])); //6
|
||||
this->AddEvent(new PRS1SnoreEvent(t, buffer[pos+8])); //??
|
||||
this->AddEvent(new PRS1EPAPAverageEvent(t, buffer[pos+9])); // 9
|
||||
this->AddEvent(new PRS1IPAPAverageEvent(t, data1=data[pos+0])); // 0
|
||||
this->AddEvent(new PRS1IPAPLowEvent(t, data[pos+1])); // 1
|
||||
this->AddEvent(new PRS1IPAPHighEvent(t, data[pos+2])); // 2
|
||||
this->AddEvent(new PRS1LeakEvent(t, data[pos+3])); // 3 // F5V2, is this really unintentional leak rather than total leak?
|
||||
this->AddEvent(new PRS1TidalVolumeEvent(t, data[pos+7])); // 7
|
||||
this->AddEvent(new PRS1RespiratoryRateEvent(t, data[pos+4])); // 4
|
||||
this->AddEvent(new PRS1PatientTriggeredBreathsEvent(t, data[pos+5])); // 5
|
||||
this->AddEvent(new PRS1MinuteVentilationEvent(t, data[pos+6])); //6
|
||||
this->AddEvent(new PRS1SnoreEvent(t, data[pos+8])); //??
|
||||
this->AddEvent(new PRS1EPAPAverageEvent(t, data[pos+9])); // 9
|
||||
pos+=11;
|
||||
} else {
|
||||
qDebug() << "0x0E Observed in ASV data!!????";
|
||||
data0 = buffer[pos++]; // << 8) | buffer[pos];
|
||||
data0 = data[pos++]; // << 8) | data[pos];
|
||||
|
||||
}
|
||||
//session->AddEvent(new Event(t,cpapcode, 0, data, 1));
|
||||
@ -2334,25 +2349,25 @@ bool PRS1DataChunk::ParseEventsF5V012(void)
|
||||
case 0x0f:
|
||||
qDebug() << "0x0f Observed in ASV data!!????";
|
||||
|
||||
data0 = buffer[pos + 1] << 8 | buffer[pos];
|
||||
data0 = data[pos + 1] << 8 | data[pos];
|
||||
pos += 2;
|
||||
data1 = buffer[pos]; //|buffer[pos+1] << 8
|
||||
data1 = data[pos]; //|data[pos+1] << 8
|
||||
pos += 1;
|
||||
//tt -= qint64(data1) * 1000L;
|
||||
//session->AddEvent(new Event(tt,cpapcode, 0, data, 2));
|
||||
break;
|
||||
|
||||
case 0x10: // Unknown
|
||||
data0 = buffer[pos + 1] << 8 | buffer[pos];
|
||||
data0 = data[pos + 1] << 8 | data[pos];
|
||||
pos += 2;
|
||||
data1 = buffer[pos++];
|
||||
data1 = data[pos++];
|
||||
|
||||
this->AddEvent(new PRS1LargeLeakEvent(t - data1, data0));
|
||||
|
||||
// qDebug() << "0x10 Observed in ASV data!!????";
|
||||
// data0 = buffer[pos++]; // << 8) | buffer[pos];
|
||||
// data1 = buffer[pos++];
|
||||
// data2 = buffer[pos++];
|
||||
// data0 = data[pos++]; // << 8) | data[pos];
|
||||
// data1 = data[pos++];
|
||||
// data2 = data[pos++];
|
||||
//session->AddEvent(new Event(t,cpapcode, 0, data, 3));
|
||||
break;
|
||||
case 0x11: // Not Leak Rate
|
||||
@ -2360,34 +2375,36 @@ bool PRS1DataChunk::ParseEventsF5V012(void)
|
||||
//if (!Code[24]) {
|
||||
// Code[24]=new EventList(cpapcode,EVL_Event);
|
||||
//}
|
||||
//Code[24]->AddEvent(t,buffer[pos++]);
|
||||
//Code[24]->AddEvent(t,data[pos++]);
|
||||
break;
|
||||
|
||||
|
||||
case 0x12: // Summary
|
||||
qDebug() << "0x12 Observed in ASV data!!????";
|
||||
data0 = buffer[pos++];
|
||||
data1 = buffer[pos++];
|
||||
//data2 = buffer[pos + 1] << 8 | buffer[pos];
|
||||
data0 = data[pos++];
|
||||
data1 = data[pos++];
|
||||
//data2 = data[pos + 1] << 8 | data[pos];
|
||||
pos += 2;
|
||||
//session->AddEvent(new Event(t,cpapcode, 0, data,3));
|
||||
break;
|
||||
|
||||
default: // ERROR!!!
|
||||
qWarning() << "Some new fandangled PRS1 code detected " << hex << int(code) << " at " << pos - 1;
|
||||
this->AddEvent(new PRS1UnknownDataEvent(m_data, startpos));
|
||||
badcode = true;
|
||||
break;
|
||||
default:
|
||||
DUMP_EVENT();
|
||||
UNEXPECTED_VALUE(code, "known event code");
|
||||
this->AddEvent(new PRS1UnknownDataEvent(m_data, startpos));
|
||||
ok = false; // unlike F0V6, we don't know the size of unknown slices, so we can't recover
|
||||
break;
|
||||
}
|
||||
pos = startpos + size;
|
||||
} while (ok && pos < chunk_size);
|
||||
|
||||
if (badcode) {
|
||||
break;
|
||||
}
|
||||
if (ok && pos != chunk_size) {
|
||||
qWarning() << this->sessionid << (this->size() - pos) << "trailing event bytes";
|
||||
}
|
||||
this->duration = t; // The last event might start before t, so record the last delta timestamp.
|
||||
|
||||
return true;
|
||||
this->duration = t;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
@ -3107,23 +3124,6 @@ bool PRS1Import::ParseF0Events()
|
||||
return true;
|
||||
}
|
||||
|
||||
static QString DumpEvent(int t, int code, const unsigned char* data, int size)
|
||||
{
|
||||
int s = t;
|
||||
int h = s / 3600; s -= h * 3600;
|
||||
int m = s / 60; s -= m * 60;
|
||||
QString dump = QString("%1:%2:%3")
|
||||
.arg(h, 2, 10, QChar('0'))
|
||||
.arg(m, 2, 10, QChar('0'))
|
||||
.arg(s, 2, 10, QChar('0'));
|
||||
dump = dump + " " + hex(code) + ":";
|
||||
for (int i = 0; i < size; i++) {
|
||||
dump = dump + QString(" %1").arg(data[i]);
|
||||
}
|
||||
return dump;
|
||||
}
|
||||
#define DUMP_EVENT() qWarning() << this->sessionid << DumpEvent(t, code, data + pos, size - (pos - startpos)) << "@" << pos
|
||||
|
||||
bool PRS1DataChunk::ParseEventsF0V23(CPAPMode /*mode*/)
|
||||
{
|
||||
if (this->family != 0 || this->familyVersion < 2 || this->familyVersion > 3) {
|
||||
|
Loading…
Reference in New Issue
Block a user