Split ParseFlexSetting into F0V234 and F5V012 versions, begin rewrite based on initial sample data.

These were incorrectly merged, resulting in convoluted logic and
occasionally incorrect results.  ASV is still very much a work in
progress.
This commit is contained in:
sawinglogz 2020-01-12 16:53:43 -05:00
parent 3b1d3028ff
commit 7909a26ab6
2 changed files with 150 additions and 44 deletions

View File

@ -4507,8 +4507,7 @@ bool PRS1DataChunk::ParseSettingsF0V23(const unsigned char* data, int /*size*/)
this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_RAMP_PRESSURE, ramp_pressure));
quint8 flex = data[0x08];
//HEX(flex);
this->ParseFlexSetting(flex, cpapmode);
this->ParseFlexSettingF0V234(flex, cpapmode);
int humid = data[0x09];
this->ParseHumidifierSetting50Series(humid, true);
@ -4614,11 +4613,8 @@ bool PRS1DataChunk::ParseSettingsF0V4(const unsigned char* data, int /*size*/)
this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_RAMP_TIME, ramp_time));
this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_RAMP_PRESSURE, ramp_pressure));
// TODO: flex was wrong for F0V4, so double-check F0V23 (and other users of ParseFlexSetting)
// esp. cpapcheck and autotrial
quint8 flex = data[0x0a];
//HEX(flex);
this->ParseFlexSetting(flex, cpapmode);
this->ParseFlexSettingF0V234(flex, cpapmode);
this->ParseHumidifierSetting60Series(data[0x0b], data[0x0c], true);
@ -5118,7 +5114,6 @@ bool PRS1DataChunk::ParseSettingsF3V3(const unsigned char* data, int /*size*/)
}
this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_CPAP_MODE, (int) cpapmode));
//HEX(data[3]);
switch (data[3]) {
case 0: // 0 = None
flexmode = FLEX_None;
@ -5148,6 +5143,7 @@ bool PRS1DataChunk::ParseSettingsF3V3(const unsigned char* data, int /*size*/)
this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_IPAP_MAX, max_ipap));
// TODO: calculte PS or min/max PS? Create IPAP event when not AVAPS?
// TODO: import rise time, bi-flex level
if (flexmode == FLEX_None || flexmode == FLEX_AVAPS) {
//CHECK_VALUE(data[0xa], 1, 3); // 1 = Rise Time Setting 1, 2 = Rise Time Setting 2, 3 = Rise Time Setting 3
CHECK_VALUES(data[0xb], 0, 1); // 1 = Rise Time Lock (in "None" and AVAPS flex mode)
@ -5533,7 +5529,6 @@ bool PRS1DataChunk::ParseSettingsF3V6(const unsigned char* data, int size)
break;
case 1: // Flex Mode
CHECK_VALUE(len, 1);
//HEX(data[pos]);
switch (data[pos]) {
case 0: // 0 = None
flexmode = FLEX_None;
@ -5722,6 +5717,7 @@ bool PRS1DataChunk::ParseSettingsF5V012(const unsigned char* data, int /*size*/)
this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PS_MIN, imin_ps));
this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PS_MAX, imax_ps));
// TODO: add settings for backup breathing
//CHECK_VALUE(data[0x07], 1, 2); // 1 = backup breath rate "Auto"; 2 = fixed BPM, see below
//CHECK_VALUE(data[0x08], 0); // backup "Breath Rate" in mode 2
//CHECK_VALUE(data[0x09], 0); // backup "Timed Inspiration" (gain 0.1) in mode 2
@ -5731,9 +5727,8 @@ bool PRS1DataChunk::ParseSettingsF5V012(const unsigned char* data, int /*size*/)
this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_RAMP_TIME, ramp_time));
this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_RAMP_PRESSURE, ramp_pressure, GAIN));
quint8 flex = data[0x0c]; // TODO: 82 F5V0 = flex 2, C9 F5V1 = rise time 1 + rise time lock, 8A F5V1 = rise time 2, 02 F5V2 = flex 2!!!
//HEX(flex);
this->ParseFlexSetting(flex, cpapmode); // TODO: check this against all versions, may not be right ever, or only for very specific models
quint8 flex = data[0x0c];
this->ParseFlexSettingF5V012(flex, cpapmode);
int pos;
if (this->familyVersion == 0) { // TODO: either split this into two functions or use size to differentiate like FV3 parsers do
@ -5958,41 +5953,88 @@ bool PRS1DataChunk::ParseSummaryF5V012(void)
// Flex F0V2 confirmed
// 0x00 = None
// 0x81 = C-Flex 1
// 0x82 = Bi-Flex 2
// 0x89 = A-Flex 1
// 0x8A = A-Flex 2
// 0x8B = C-Flex+ 3
// 0x93 = Rise Time 3
// 0x81 = C-Flex 1, lock off (AutoCPAP mode)
// 0x82 = Bi-Flex 2 (Bi-Level mode)
// 0x89 = A-Flex 1 (AutoCPAP mode)
// 0x8A = A-Flex 2, lock off (AutoCPAP mode)
// 0x8B = C-Flex+ 3, lock off (CPAP mode)
// 0x93 = Rise Time 3 (AutoBiLevel mode)
// Flex F0V4 confirmed
// 0x00 = off
// 0x81 = C-Flex 1, Bi-Flex 1
// 0x82 = C-Flex 2
// 0x83 = Bi-Flex 3
// 0x89 = A-Flex 1
// 0x8A = C-Flex+ 2, A-Flex 2
// 0x8B = C-Flex+ 3
// 0x00 = None
// 0x81 = Bi-Flex 1 (AutoBiLevel mode)
// 0x81 = C-Flex 1 (AutoCPAP mode)
// 0x82 = C-Flex 2 (CPAP mode)
// 0x82 = C-Flex 2 (CPAP-Check mode)
// 0x83 = Bi-Flex 3 (Bi-Level mode)
// 0x89 = A-Flex 1 (AutoCPAP mode)
// 0x8A = C-Flex+ 2 (CPAP mode)
// 0x8A = C-Flex+ 2, lock off (CPAP-Check mode)
// 0x8A = A-Flex 2, lock off (Auto-Trial mode)
//
// 0x8A = A-Flex 1 (AutoCPAP mode)
// 0x8B = C-Flex+ 3 (CPAP mode)
// 0x8B = A-Flex 3 (AutoCPAP mode)
// TODO: Review this in more detail, comparing it across all families and versions. It may not be accurate.
// F5V0 0x82 = Bi-Flex 2
// F5V1 0x82 = Bi-Flex 2
// F5V1 0x83 = Bi-Flex 3
// F5V1 0x8A = Rise Time 2
// F5V2 0x02 = Bi-Flex 2
// F5V1 0xC9 = Rise Time 1, Rise Time Lock
void PRS1DataChunk::ParseFlexSetting(quint8 flex, int cpapmode)
// 8 = enabled
// 1 = rise time
// 8 = C-Flex+ / A-Flex (depending on mode)
// 3 = level
// TODO: Check esp. CPAP-Check and auto-trial
void PRS1DataChunk::ParseFlexSettingF0V234(quint8 flex, int cpapmode)
{
//qWarning() << QString("F%1V%2 flex=%3").arg(this->family).arg(this->familyVersion).arg(flex, 2, 16, QChar('0'));
FlexMode flexmode = FLEX_None;
bool enabled = (flex & 0x80) != 0;
bool risetime = (flex & 0x10) != 0;
bool plusmode = (flex & 0x08) != 0;
int flexlevel = flex & 0x03;
FlexMode flexmode = FLEX_Unknown;
// the original code suggested 0x40 was split, but we haven't seen any data with that yet
if (flex & (0x40 | 0x20 | 0x04)) UNEXPECTED_VALUE(flex, "known bits");
HEX(flex);
if (enabled) {
if (flexlevel < 1) UNEXPECTED_VALUE(flexlevel, "!= 0");
if (risetime) {
flexmode = FLEX_RiseTime;
CHECK_VALUE(cpapmode, PRS1_MODE_AUTOBILEVEL);
CHECK_VALUE(plusmode, 0);
} else if (plusmode) {
switch (cpapmode) {
case PRS1_MODE_CPAP:
case PRS1_MODE_CPAPCHECK:
flexmode = FLEX_CFlexPlus;
break;
case PRS1_MODE_AUTOCPAP:
case PRS1_MODE_AUTOTRIAL:
flexmode = FLEX_AFlex;
break;
default:
UNEXPECTED_VALUE(cpapmode, "expected C-Flex+/A-Flex mode");
break;
}
} else {
switch (cpapmode) {
case PRS1_MODE_CPAP:
case PRS1_MODE_CPAPCHECK:
case PRS1_MODE_AUTOCPAP:
flexmode = FLEX_CFlex;
break;
case PRS1_MODE_BILEVEL:
case PRS1_MODE_AUTOBILEVEL:
flexmode = FLEX_BiFlex;
break;
default:
UNEXPECTED_VALUE(cpapmode, "expected mode");
break;
}
}
}
// 88 CFlex+ / AFlex (depending on CPAP mode)
// 80 CFlex
// 00 NoFlex
// c0 Split CFlex then None
// c8 Split CFlex+ then None
/*
if (flex & (0x20 | 0x04)) UNEXPECTED_VALUE(flex, "known bits");
flex &= 0xf8;
@ -6034,10 +6076,73 @@ void PRS1DataChunk::ParseFlexSetting(quint8 flex, int cpapmode)
if (flexmode == FLEX_Unknown) {
qWarning() << this->sessionid << "unknown flex" << flex << "cpapmode" << cpapmode;
}
*/
this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_FLEX_MODE, (int) flexmode));
if (enabled) {
this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_FLEX_LEVEL, flexlevel));
}
}
// Flex F5V0 confirmed
// 0x81 = Bi-Flex 1 (ASV mode)
// 0x82 = Bi-Flex 2 (ASV mode)
// 0x83 = Bi-Flex 3 (ASV mode)
// Flex F5V1 confirmed
// 0x82 = Bi-Flex 2 (ASV mode)
// 0x83 = Bi-Flex 3 (ASV mode)
// 0x8A = Rise Time 2 (ASV mode) (Shows "ASV - None" in mode summary, but then rise time in details)
// 0x08 = Rise Time 2 (ASV mode) (backup breathing off)
// 0xC9 = Rise Time 1, Rise Time Lock (ASV mode)
// Flex F5V2 confirmed
// 0x02 = Bi-Flex 2 (ASV mode) (breath rate auto, but min/max PS=0)
// 8 = ? (once was 0 when rise time was on and backup breathing was off, rise time level was also 0 in that case)
// (was also 0 on F5V2)
// 4 = Rise Time Lock
// 8 = Rise Time (vs. Bi-Flex)
// 3 = level
void PRS1DataChunk::ParseFlexSettingF5V012(quint8 flex, int cpapmode)
{
/*
FlexMode flexmode = FLEX_None;
bool unknown = (flex & 0x80) != 0;
bool lock = (flex & 0x40) != 0;
bool risetime = (flex & 0x08) != 0;
int flexlevel = flex & 0x03;
if (flex & (0x20 | 0x10 | 0x04)) UNEXPECTED_VALUE(flex, "known bits");
CHECK_VALUE(unknown, true);
*/
CHECK_VALUE(cpapmode, PRS1_MODE_ASV);
if (this->familyVersion == 0) {
switch(flex) {
case 0x81: break;
case 0x82: break;
case 0x83: break;
default: HEX(flex); break;
}
} else if (this->familyVersion == 1) {
switch(flex) {
case 0x82: break;
case 0x83: break;
case 0x8A: break;
case 0x08: break;
case 0xC9: break;
default: HEX(flex); break;
}
} else {
switch(flex) {
case 0x02: break;
default: HEX(flex); break;
}
}
}
// Humid F0V2 confirmed
@ -6536,7 +6641,6 @@ bool PRS1DataChunk::ParseSettingsF0V6(const unsigned char* data, int size)
break;
case 0x2e: // Flex mode
CHECK_VALUE(len, 1);
//HEX(data[pos]);
switch (data[pos]) {
case 0:
flexmode = FLEX_None;
@ -6574,7 +6678,6 @@ bool PRS1DataChunk::ParseSettingsF0V6(const unsigned char* data, int size)
break;
case 0x30: // Flex level
CHECK_VALUE(len, 1);
//HEX(data[pos]);
this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_FLEX_LEVEL, data[pos]));
break;
case 0x35: // Humidifier setting
@ -7108,7 +7211,6 @@ bool PRS1DataChunk::ParseSettingsF5V3(const unsigned char* data, int size)
break;
case 0x2e: // Flex mode and level (ASV variant)
CHECK_VALUE(len, 2);
//HEX(data[pos]);
switch (data[pos]) {
case 0: // Bi-Flex
// [0x00, N] for Bi-Flex level N
@ -7117,6 +7219,7 @@ bool PRS1DataChunk::ParseSettingsF5V3(const unsigned char* data, int size)
break;
case 0x20: // Rise Time
// [0x20, 0x03] for no flex, rise time setting = 3, no rise lock
CHECK_VALUE(data[pos+1], 3);
this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_RISE_TIME, data[pos+1]));
break;
default:

View File

@ -165,8 +165,11 @@ 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 flex setting byte from a .000 or .001 containing compliance/summary data
void ParseFlexSetting(quint8 flex, int prs1mode);
//! \brief Parse a flex setting byte from a .000 or .001 containing compliance/summary data for CPAP/APAP family versions 2, 3, or 4
void ParseFlexSettingF0V234(quint8 flex, int prs1mode);
//! \brief Parse a flex setting byte from a .000 or .001 containing compliance/summary data for ASV family versions 0, 1, or 2
void ParseFlexSettingF5V012(quint8 flex, int prs1mode);
//! \brief Parse an humidifier setting byte from a .000 or .001 containing compliance/summary data for original System One (50-Series) machines: F0V23 and F5V0
void ParseHumidifierSetting50Series(int humid, bool add_setting=false);