Start of PRS1 DFV3 Summary Parsing cleanup

This commit is contained in:
Mark Watkins 2018-05-06 01:48:32 +10:00
parent b9e1af63da
commit cc2a80e4c3
3 changed files with 95 additions and 185 deletions

View File

@ -23,7 +23,9 @@
// Disable this to cut excess debug messages
//#define DEBUG_IMPORTER
#define DEBUG_SUMMARY
//const int PRS1_MAGIC_NUMBER = 2;
//const int PRS1_SUMMARY_FILE=1;
@ -1439,8 +1441,8 @@ bool PRS1Import::ParseF3EventsV3()
code = data[pos++];
delta = (data[pos+1] < 8) | data[pos];
pos += 2;
#ifdef DEBUG_IMPORTER
if (code == 0x02) {
#ifdef DEBUG_EVENTS
if (code == 0x00) {
if (!loader->unknownCodes.contains(code)) {
loader->unknownCodes.insert(code, QStringList());
}
@ -2152,12 +2154,6 @@ bool PRS1Import::ParseSummaryF0()
{
const unsigned char * data = (unsigned char *)summary->m_data.constData();
if (data[0x00] > 0) {
return false;
}
session->set_first(qint64(summary->timestamp) * 1000L);
CPAPMode cpapmode = MODE_UNKNOWN;
switch (data[0x02]) { // PRS1 mode // 0 = CPAP, 2 = APAP
@ -2265,12 +2261,6 @@ bool PRS1Import::ParseSummaryF0V4()
{
const unsigned char * data = (unsigned char *)summary->m_data.constData();
if (data[0x00] > 0) {
return false;
}
session->set_first(qint64(summary->timestamp) * 1000L);
CPAPMode cpapmode = MODE_UNKNOWN;
switch (data[0x02]) { // PRS1 mode // 0 = CPAP, 2 = APAP
@ -2360,153 +2350,44 @@ bool PRS1Import::ParseSummaryF0V4()
bool PRS1Import::ParseSummaryF3()
{
CPAPMode mode = MODE_UNKNOWN;
EventDataType epap, ipap;
int duration;
const unsigned char * data = (unsigned char *)summary->m_data.constData();
int size = summary->m_data.size();
if (session->session() > 0xae) {
// event->m_headerblock.
qDebug() << "Dumping session" << (int)session->session() << "summary file";
QString hexstr = QString("%1@0000: ").arg(session->session(),8,16,QChar('0'));
for (int i=0; i<size; ++i) {
unsigned char val = data[i];
hexstr += QString(" %1").arg((short)val, 2, 16, QChar('0'));
if ((i % 0x10) == 0x0f) {
qDebug() << hexstr;
hexstr = QString("%1@%2: ").arg(session->session(),8,16,QChar('0')).arg(i+1, 4, 16, QChar('0'));
}
}
QMap<unsigned char, QByteArray>::iterator it;
if ((it=mainblock.find(0x0a)) != mainblock.end()) {
mode = MODE_CPAP;
session->settings[CPAP_Pressure] = EventDataType(it.value()[0]/10.0f);
} else if ((it=mainblock.find(0x0d)) != mainblock.end()) {
mode = MODE_APAP;
session->settings[CPAP_PressureMin] = EventDataType(it.value()[0]/10.0f);
session->settings[CPAP_PressureMax] = EventDataType(it.value()[1]/10.0f);
} else if ((it=mainblock.find(0x0e)) != mainblock.end()) {
mode = MODE_BILEVEL_FIXED;
session->settings[CPAP_EPAP] = ipap = EventDataType(it.value()[0] / 10.0f);
session->settings[CPAP_IPAP] = epap = EventDataType(it.value()[1] / 10.0f);
session->settings[CPAP_PS] = ipap - epap;
} else if ((it=mainblock.find(0x0f)) != mainblock.end()) {
mode = MODE_BILEVEL_AUTO_VARIABLE_PS;
session->settings[CPAP_EPAPLo] = EventDataType(it.value()[0]/10.0f);
session->settings[CPAP_IPAPHi] = EventDataType(it.value()[1]/10.0f);
session->settings[CPAP_PSMin] = EventDataType(it.value()[2]/10.0f);
session->settings[CPAP_PSMax] = EventDataType(it.value()[3]/10.0f);
} else if ((it=mainblock.find(0x10)) != mainblock.end()) {
mode = MODE_APAP; // Disgusting APAP "IQ" trial
session->settings[CPAP_PressureMin] = EventDataType(it.value()[0]/10.0f);
session->settings[CPAP_PressureMax] = EventDataType(it.value()[1]/10.0f);
}
int pos = 0;
if (data[pos++] != 0) {
qDebug() << "Non zero hblock[0] indicator";
return false;
session->settings[CPAP_Mode] = (int)mode;
if ((it=hbdata.find(5)) != hbdata.end()) {
duration = (it.value()[1] << 8 ) + it.value()[0];
}
pos += summary->hblock[0];
QString str;
unsigned char code;
unsigned char length;
qint64 duration = 0;
if (!summary->hblock.contains(1) || (data[pos++] != 1)) {
qDebug() << session->session() << "Missing hblock 1 data";
return false;
}
int hBlockSize = summary->hblock[1];
EventDataType min_pressure, max_pressure, imin_epap, imin_ps, imax_ps;
CPAPMode cpapmode = MODE_UNKNOWN;
do {
code = data[pos++];
length = data[pos++];
switch(code) {
case 10: // 0x0a
cpapmode = MODE_CPAP;
if (length != 1) qDebug() << "PRS1Loader::ParseSummaryF3" << "Bad CPAP value";
imin_epap = data[pos];
break;
case 13: // 0x0d
cpapmode = MODE_APAP;
if (length != 2) qDebug() << "PRS1Loader::ParseSummaryF3" << "Bad APAP value";
min_pressure = data[pos];
max_pressure = data[pos+1];
break;
case 14: // 0x0e // <--- this is a total guess.. might be 3 and have a pressure support value
cpapmode = MODE_BILEVEL_FIXED;
if (length != 2) qDebug() << "PRS1Loader::ParseSummaryF3" << "Bad APAP value";
min_pressure = data[pos];
max_pressure = data[pos+1];
imin_ps = max_pressure - min_pressure;
break;
case 15: // 0x0f
cpapmode = MODE_BILEVEL_AUTO_VARIABLE_PS; //might be C_CHECK?
if (length != 4) qDebug() << "PRS1Loader::ParseSummaryF3" << "Bad APAP value";
min_pressure = data[pos+0];
max_pressure = data[pos+1];
imin_ps = data[pos+2];
imax_ps = data[pos+3];
break;
case 0x10: // Auto Trial mode
cpapmode = MODE_APAP;
if (length != 3) qDebug() << "PRS1Loader::ParseSummaryF3" << "Bad APAP value";
min_pressure = data[pos+0];
max_pressure = data[pos+1];
break;
/*case 0x35:
duration = ( data[pos+1] << 8 ) + data[pos+0];
break;*/
default:
str = QString("%1: [%2] [%3]")
.arg(session->session(), 8, 16, QChar('0'))
.arg(code, 2, 16, QChar('0'))
.arg(length, 2, 16, QChar('0'));
for (int i=0;i<length; ++i) {
str += QString(" %1").arg((short)data[pos+i], 2, 16, QChar('0'));
}
qDebug() << str;
break;
}
pos += length;
} while (pos <= hBlockSize);
if (!summary->hblock.contains(2) || (data[pos++] != 2)) {
qDebug() << session->session() << "Missing hblock 2 data";
return false;
}
pos += summary->hblock[2];
if (!summary->hblock.contains(3)) {
qDebug() << session->session() << "Missing hblock 3 data";
return false;
}
hBlockSize = summary->hblock[3];
int len = data[pos++];
pos+=len;
if (data[pos++] != 5) {
qDebug() << "Expected length after 0x05" << session->session();
return false;
}
duration = ( data[pos+1] << 8 ) + data[pos+0];
session->set_first(qint64(summary->timestamp) * 1000L);
//session->set_last(session->first() + (duration * 1000L));
summary_duration = duration;
session->settings[CPAP_Mode] = (int)cpapmode;
if (cpapmode == MODE_CPAP) {
session->settings[CPAP_Pressure] = imin_epap/10.0f;
} else if (cpapmode == MODE_APAP) {
session->settings[CPAP_PressureMin] = min_pressure/10.0f;
session->settings[CPAP_PressureMax] = max_pressure/10.0f;
} else if (cpapmode == MODE_BILEVEL_FIXED) {
// Guessing here.. haven't seen BIPAP data.
session->settings[CPAP_EPAP] = min_pressure/10.0f;
session->settings[CPAP_IPAP] = max_pressure/10.0f;
session->settings[CPAP_PS] = imin_ps/10.0f;
} else if (cpapmode == MODE_BILEVEL_AUTO_VARIABLE_PS) {
session->settings[CPAP_EPAPLo] = min_pressure/10.0f;
session->settings[CPAP_IPAPHi] = max_pressure/10.0f;
session->settings[CPAP_PSMin] = imin_ps/10.0f;
session->settings[CPAP_PSMax] = imax_ps/10.0f;
}
return true;
}
@ -2515,12 +2396,6 @@ bool PRS1Import::ParseSummaryF5V0()
{
const unsigned char * data = (unsigned char *)summary->m_data.constData();
if (data[0x00] > 0) {
return false;
}
session->set_first(qint64(summary->timestamp) * 1000L);
CPAPMode cpapmode = MODE_UNKNOWN;
int imin_epap = data[0x3];
@ -2601,12 +2476,6 @@ bool PRS1Import::ParseSummaryF5V1()
{
const unsigned char * data = (unsigned char *)summary->m_data.constData();
if (data[0x00] > 0) {
return false;
}
session->set_first(qint64(summary->timestamp) * 1000L);
CPAPMode cpapmode = MODE_UNKNOWN;
int imin_epap = data[0x3];
@ -2687,12 +2556,6 @@ bool PRS1Import::ParseSummaryF5V2()
{
const unsigned char * data = (unsigned char *)summary->m_data.constData();
if (data[0x00] > 0) {
return false;
}
session->set_first(qint64(summary->timestamp) * 1000L);
//CPAPMode cpapmode = MODE_UNKNOWN;
summary_duration = data[0x18] | data[0x19] << 8;
@ -2724,12 +2587,6 @@ bool PRS1Import::ParseSummaryF0V6()
const unsigned char * data = (unsigned char *)summary->m_data.constData();
if (data[0x00] > 0) {
return false;
}
session->set_first(qint64(summary->timestamp) * 1000L);
CPAPMode cpapmode = MODE_UNKNOWN;
int imin_epap = 0;
@ -2881,13 +2738,62 @@ bool PRS1Import::ParseSummaryF0V6()
bool PRS1Import::ParseSummary()
{
if (!summary) return false;
// All machines have a first byte zero for clean summary
if (summary->m_data.constData()[0] != 0) {
qDebug() << "Non zero hblock[0] indicator";
return false;
}
session->set_first(qint64(summary->timestamp) * 1000L);
/* Example data block
000000c6@0000: 00 [10] 01 [00 01 02 01 01 00 02 01 00 04 01 40 07
000000c6@0010: 01 60 1e 03 02 0c 14 2c 01 14 2d 01 40 2e 01 02
000000c6@0020: 2f 01 00 35 02 28 68 36 01 00 38 01 00 39 01 00
000000c6@0030: 3b 01 01 3c 01 80] 02 [00 01 00 01 01 00 02 01 00]
000000c6@0040: 04 [00 00 28 68] 0c [78 00 2c 6c] 05 [e4 69] 07 [40 40]
000000c6@0050: 08 [61 60] 0a [00 00 00 00 03 00 00 00 02 00 02 00
000000c6@0060: 05 00 2b 11 00 10 2b 5c 07 12 00 00] 03 [00 00 01
000000c6@0070: 1a 00 38 04] */
if (summary->fileVersion == 3) {
// Parse summary structures into bytearray map according to size given in header block
const unsigned char * data = (unsigned char *)summary->m_data.constData();
int size = summary->m_data.size();
int pos = 0;
int bsize;
short val, len;
do {
val = data[pos++];
auto it = summary->hblock.find(val);
if (it == summary->hblock.end()) {
qDebug() << "Block parse error in ParseSummary" << session->session();
break;
}
bsize = it.value();
if (val != 1) {
hbdata[val] = QByteArray((const char *)(&data[pos]), bsize);
} else {
// Parse nested data structure which contains pressure block
int p2 = 0;
do {
val = data[pos + p2++];
len = data[pos + p2++];
mainblock[val] = QByteArray((const char *)(&data[pos+p2]), len);
p2 += len;
} while ((p2 < bsize) && ((pos+p2) < size));
}
pos += bsize;
} while (pos < size);
}
// Family 0 = XPAP
// Family 3 = BIPAP AVAPS
// Family 5 = BIPAP AutoSV
if (!summary) return false;
session->setPhysMax(CPAP_LeakTotal, 120);
session->setPhysMin(CPAP_LeakTotal, 0);

View File

@ -18,8 +18,8 @@
//********************************************************************************************
/// IMPORTANT!!!
//********************************************************************************************
// Please INCREMENT the following value when making changes to this loaders implementation.
//
// Please INCREMENT the following value when making changes to this loaders implementation
// BEFORE making a release
const int prs1_data_version = 15;
//
//********************************************************************************************
@ -85,7 +85,7 @@ public:
quint16 duration;
QList<PRS1Waveform> waveformInfo;
QHash<unsigned char, short> hblock;
QMap<unsigned char, short> hblock;
};
class PRS1Loader;
@ -117,6 +117,10 @@ public:
QList<PRS1DataChunk *> waveforms;
QList<PRS1DataChunk *> oximetery;
QMap<unsigned char, QByteArray> mainblock;
QMap<unsigned char, QByteArray> hbdata;
QString wavefile;
QString oxifile;

View File

@ -2,11 +2,11 @@
<b>Changes and fixes in v1.1.0-unstable-0</b>
<version number="1.1.0-unstable-0">
<list>
<li>Added brand new live Profile switcher</li>
<li>Added brand new live Profile switcher and cleaned up a lot of forced restart conditions</li>
<li>[DeVilbiss] Added DV6 Import capability (Thanks Heynes and Brian)</li>
<li>[PR Dreamstation] Added spuport for 960T F5V3 machines</li>
<li>[PR Dreamstation] Added spuport for newer 960T (DF3 F5V3) and 1030 (DFV3 F3V3) machines</li>
<li>Fix language change glitch affecting Channel names</li>
<li>Fix a few miscellanious crash conditions</li>
<li>Fix a heap of miscellanious crash conditions</li>
<li>Cleaned up Welcome page removing what could be constituted as dodgy advice</li>
<li>Added Afrikaans language support</li>
<li>Applied a bunch of bugfixes that were provided by the community (Thanks Pholy, h-uchiy, François Revol & Kevin Lewis)</li>