mirror of
https://gitlab.com/pholy/OSCAR-code.git
synced 2025-04-08 20:20:44 +00:00
Add initial support for DreamStation Auto-Trial and CPAP-Check modes.
This resolves many of the unexpected value warnings in the sample data, but there are still a bunch to tackle.
This commit is contained in:
parent
99cbe89f3e
commit
d0903ce3bd
@ -3901,7 +3901,7 @@ void PRS1DataChunk::ParseHumidifierSettingF0V6(unsigned char byte1, unsigned cha
|
|||||||
CHECK_VALUE(humidlevel, ((byte2 >> 2) & 7));
|
CHECK_VALUE(humidlevel, ((byte2 >> 2) & 7));
|
||||||
int tubelevel = (byte2 >> 5) & 7;
|
int tubelevel = (byte2 >> 5) & 7;
|
||||||
if (humidifier_present) {
|
if (humidifier_present) {
|
||||||
if (humidlevel > 5 || humidlevel < 1) UNEXPECTED_VALUE(humidlevel, "1-5");
|
if (humidlevel > 5 || humidlevel < 0) UNEXPECTED_VALUE(humidlevel, "0-5"); // 0=off is valid when a humidifier is attached
|
||||||
if (humid == 2) { // heated tube
|
if (humid == 2) { // heated tube
|
||||||
if (tubelevel > 5 || tubelevel < 1) UNEXPECTED_VALUE(tubelevel, "1-5"); // TODO: maybe this is only if heated tube?
|
if (tubelevel > 5 || tubelevel < 1) UNEXPECTED_VALUE(tubelevel, "1-5"); // TODO: maybe this is only if heated tube?
|
||||||
}
|
}
|
||||||
@ -3926,20 +3926,14 @@ void PRS1DataChunk::ParseHumidifierSettingF0V6(unsigned char byte1, unsigned cha
|
|||||||
// looks like a pressure in compliance files.
|
// looks like a pressure in compliance files.
|
||||||
bool PRS1DataChunk::ParseSettingsF0V6(const unsigned char* data, int size)
|
bool PRS1DataChunk::ParseSettingsF0V6(const unsigned char* data, int size)
|
||||||
{
|
{
|
||||||
static const QMap<int,int> expected_lengths = { {0x0d,2}, {0x0e,2}, {0x0f,4}, {0x35,2} };
|
static const QMap<int,int> expected_lengths = { {0x0c,3}, {0x0d,2}, {0x0e,2}, {0x0f,4}, {0x10,3}, {0x35,2} };
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
|
|
||||||
CPAPMode cpapmode = MODE_UNKNOWN;
|
CPAPMode cpapmode = MODE_UNKNOWN;
|
||||||
|
|
||||||
int imin_epap = 0;
|
int pressure = 0;
|
||||||
/*
|
|
||||||
//int imax_epap = 0;
|
|
||||||
*/
|
|
||||||
int imin_ps = 0;
|
int imin_ps = 0;
|
||||||
int imax_ps = 0;
|
int imax_ps = 0;
|
||||||
/*
|
|
||||||
//int imax_pressure = 0;
|
|
||||||
*/
|
|
||||||
int min_pressure = 0;
|
int min_pressure = 0;
|
||||||
int max_pressure = 0;
|
int max_pressure = 0;
|
||||||
|
|
||||||
@ -3973,6 +3967,7 @@ bool PRS1DataChunk::ParseSettingsF0V6(const unsigned char* data, int size)
|
|||||||
case 2: cpapmode = MODE_APAP; break;
|
case 2: cpapmode = MODE_APAP; break;
|
||||||
case 1: cpapmode = MODE_BILEVEL_FIXED; break;
|
case 1: cpapmode = MODE_BILEVEL_FIXED; break;
|
||||||
case 3: cpapmode = MODE_BILEVEL_AUTO_VARIABLE_PS; break;
|
case 3: cpapmode = MODE_BILEVEL_AUTO_VARIABLE_PS; break;
|
||||||
|
case 4: cpapmode = MODE_CPAP; break; // "CPAP-Check" in report, but seems like CPAP
|
||||||
default:
|
default:
|
||||||
UNEXPECTED_VALUE(data[pos], "known device mode");
|
UNEXPECTED_VALUE(data[pos], "known device mode");
|
||||||
break;
|
break;
|
||||||
@ -3980,15 +3975,25 @@ bool PRS1DataChunk::ParseSettingsF0V6(const unsigned char* data, int size)
|
|||||||
this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_CPAP_MODE, (int) cpapmode));
|
this->AddEvent(new PRS1ParsedSettingEvent(PRS1_SETTING_CPAP_MODE, (int) cpapmode));
|
||||||
break;
|
break;
|
||||||
case 1: // ???
|
case 1: // ???
|
||||||
CHECK_VALUE(data[pos], 0);
|
if (data[pos] != 0) {
|
||||||
|
CHECK_VALUES(data[pos], 1, 2); // 1 when EZ-Start is enabled? 2 when Auto-Trial?
|
||||||
|
}
|
||||||
if (len == 2) { // 400G has extra byte
|
if (len == 2) { // 400G has extra byte
|
||||||
CHECK_VALUE(data[pos+1], 0);
|
CHECK_VALUE(data[pos+1], 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x0a: // CPAP pressure setting
|
case 0x0a: // CPAP pressure setting
|
||||||
CHECK_VALUE(cpapmode, MODE_CPAP);
|
CHECK_VALUE(cpapmode, MODE_CPAP);
|
||||||
imin_epap = data[pos];
|
pressure = data[pos];
|
||||||
this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PRESSURE, imin_epap));
|
this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PRESSURE, pressure));
|
||||||
|
break;
|
||||||
|
case 0x0c: // CPAP-Check pressure setting
|
||||||
|
CHECK_VALUE(cpapmode, MODE_CPAP);
|
||||||
|
min_pressure = data[pos]; // Min Setting on pressure graph
|
||||||
|
max_pressure = data[pos+1]; // Max Setting on pressure graph
|
||||||
|
pressure = data[pos+2]; // CPAP on pressure graph and CPAP-Check Pressure on settings detail
|
||||||
|
CHECK_VALUE(pressure, 0x5a);
|
||||||
|
this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PRESSURE, pressure));
|
||||||
break;
|
break;
|
||||||
case 0x0d: // AutoCPAP pressure setting
|
case 0x0d: // AutoCPAP pressure setting
|
||||||
CHECK_VALUE(cpapmode, MODE_APAP);
|
CHECK_VALUE(cpapmode, MODE_APAP);
|
||||||
@ -4017,14 +4022,18 @@ bool PRS1DataChunk::ParseSettingsF0V6(const unsigned char* data, int size)
|
|||||||
this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PS_MIN, imin_ps));
|
this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PS_MIN, imin_ps));
|
||||||
this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PS_MAX, imax_ps));
|
this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PS_MAX, imax_ps));
|
||||||
break;
|
break;
|
||||||
/*
|
case 0x10: // Auto-Trial mode
|
||||||
case 0x10: // Auto Trial mode
|
CHECK_VALUE(cpapmode, MODE_CPAP); // the mode setting is CPAP, even though it's operating in APAP mode
|
||||||
cpapmode = MODE_APAP;
|
cpapmode = MODE_APAP; // but categorize it now as APAP, since that's what it's really doing
|
||||||
if (dataPtr[1] != 3) qDebug() << "PRS1DataChunk::ParseSummaryF0V6=" << "Bad APAP value";
|
CHECK_VALUE(data[pos], 30); // Auto-Trial Duration
|
||||||
min_pressure = dataPtr[3];
|
min_pressure = data[pos+1];
|
||||||
max_pressure = dataPtr[4];
|
max_pressure = data[pos+2];
|
||||||
|
this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PRESSURE_MIN, min_pressure));
|
||||||
|
this->AddEvent(new PRS1PressureSettingEvent(PRS1_SETTING_PRESSURE_MAX, max_pressure));
|
||||||
|
break;
|
||||||
|
case 0x2a: // EZ-Start
|
||||||
|
CHECK_VALUE(data[pos], 0x80); // EZ-Start enabled
|
||||||
break;
|
break;
|
||||||
*/
|
|
||||||
case 0x2b: // Ramp Type
|
case 0x2b: // Ramp Type
|
||||||
CHECK_VALUES(data[pos], 0, 0x80); // 0 == "Linear", 0x80 = "SmartRamp"
|
CHECK_VALUES(data[pos], 0, 0x80); // 0 == "Linear", 0x80 = "SmartRamp"
|
||||||
break;
|
break;
|
||||||
@ -4059,7 +4068,7 @@ bool PRS1DataChunk::ParseSettingsF0V6(const unsigned char* data, int size)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x39:
|
case 0x39:
|
||||||
CHECK_VALUE(data[pos], 0);
|
CHECK_VALUES(data[pos], 0, 0x80); // 0x80 maybe auto-trial?
|
||||||
break;
|
break;
|
||||||
case 0x3b:
|
case 0x3b:
|
||||||
if (data[pos] != 0) {
|
if (data[pos] != 0) {
|
||||||
@ -4106,26 +4115,18 @@ bool PRS1DataChunk::ParseSummaryF0V6(void)
|
|||||||
qWarning() << "ParseSummaryF0V6 called with family" << this->family << "familyVersion" << this->familyVersion;
|
qWarning() << "ParseSummaryF0V6 called with family" << this->family << "familyVersion" << this->familyVersion;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// TODO: hardcoding this is ugly, think of a better approach
|
|
||||||
if (this->m_data.size() < 68) {
|
|
||||||
qWarning() << this->sessionid << "summary data too short:" << this->m_data.size();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const unsigned char * data = (unsigned char *)this->m_data.constData();
|
const unsigned char * data = (unsigned char *)this->m_data.constData();
|
||||||
int chunk_size = this->m_data.size();
|
int chunk_size = this->m_data.size();
|
||||||
static const int minimum_sizes[] = { 1, 0x2b, 9, 4, 2, 4, 1, 4, 0x1b, 2, 4, 0x0b, 1, 2, 6 };
|
static const int minimum_sizes[] = { 1, 0x2b, 9, 4, 2, 4, 1, 4, 0x1b, 2, 4, 0x0b, 1, 2, 6 };
|
||||||
static const int ncodes = sizeof(minimum_sizes) / sizeof(int);
|
static const int ncodes = sizeof(minimum_sizes) / sizeof(int);
|
||||||
/*
|
// NOTE: The sizes contained in hblock can vary, even within a single machine, as can the length of hblock itself!
|
||||||
for (int i = 0; i < ncodes; i++) {
|
|
||||||
if (this->hblock.contains(i)) {
|
// TODO: hardcoding this is ugly, think of a better approach
|
||||||
// These values can vary, interestingly.
|
if (chunk_size < minimum_sizes[0] + minimum_sizes[1] + minimum_sizes[2]) {
|
||||||
//CHECK_VALUE(this->hblock[i], minimum_sizes[i]);
|
qWarning() << this->sessionid << "summary data too short:" << chunk_size;
|
||||||
} else {
|
return false;
|
||||||
// Even the length of hblock can vary.
|
|
||||||
//UNEXPECTED_VALUE(this->hblock.contains(i), true);
|
|
||||||
}
|
}
|
||||||
}
|
if (chunk_size < 60) UNEXPECTED_VALUE(chunk_size, ">= 60");
|
||||||
*/
|
|
||||||
|
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
@ -4191,8 +4192,8 @@ bool PRS1DataChunk::ParseSummaryF0V6(void)
|
|||||||
CHECK_VALUE(data[pos+0xb], 0x00);
|
CHECK_VALUE(data[pos+0xb], 0x00);
|
||||||
//CHECK_VALUES(data[pos+0xc], 0x15, 0x02); // probably 16-bit value
|
//CHECK_VALUES(data[pos+0xc], 0x15, 0x02); // probably 16-bit value
|
||||||
CHECK_VALUE(data[pos+0xd], 0x00);
|
CHECK_VALUE(data[pos+0xd], 0x00);
|
||||||
//CHECK_VALUES(data[pos+0xe], 0x01, 0x00); // probably 16-bit value
|
//CHECK_VALUES(data[pos+0xe], 0x01, 0x00); // 16-bit VS count
|
||||||
CHECK_VALUE(data[pos+0xf], 0x00);
|
//CHECK_VALUE(data[pos+0xf], 0x00);
|
||||||
//CHECK_VALUES(data[pos+0x10], 0x21, 5); // probably 16-bit value, maybe H count?
|
//CHECK_VALUES(data[pos+0x10], 0x21, 5); // probably 16-bit value, maybe H count?
|
||||||
CHECK_VALUE(data[pos+0x11], 0x00);
|
CHECK_VALUE(data[pos+0x11], 0x00);
|
||||||
//CHECK_VALUES(data[pos+0x12], 0x13, 0); // probably 16-bit value
|
//CHECK_VALUES(data[pos+0x12], 0x13, 0); // probably 16-bit value
|
||||||
@ -4256,6 +4257,24 @@ bool PRS1DataChunk::ParseSummaryF0V6(void)
|
|||||||
//CHECK_VALUE(data[pos+2], 0x4b); // seems to match 90% EPAP
|
//CHECK_VALUE(data[pos+2], 0x4b); // seems to match 90% EPAP
|
||||||
//CHECK_VALUE(data[pos+3], 0x64); // seems to match 90% IPAP
|
//CHECK_VALUE(data[pos+3], 0x64); // seems to match 90% IPAP
|
||||||
break;
|
break;
|
||||||
|
case 0x0b:
|
||||||
|
// CPAP-Check related? follows 3, so first two bytes may be time delta
|
||||||
|
CHECK_VALUE(data[pos], 3);
|
||||||
|
CHECK_VALUE(data[pos+1], 0);
|
||||||
|
CHECK_VALUE(data[pos+2], 0);
|
||||||
|
CHECK_VALUE(data[pos+3], 0);
|
||||||
|
CHECK_VALUE(data[pos+4], 0);
|
||||||
|
CHECK_VALUE(data[pos+5], 0);
|
||||||
|
CHECK_VALUE(data[pos+6], 0);
|
||||||
|
CHECK_VALUE(data[pos+7], 0);
|
||||||
|
CHECK_VALUE(data[pos+8], 0);
|
||||||
|
CHECK_VALUE(data[pos+9], 0);
|
||||||
|
CHECK_VALUE(data[pos+0xa], 0);
|
||||||
|
break;
|
||||||
|
case 0x06:
|
||||||
|
// CPAP-Check related? follows 4, before 8, looks like a pressure value
|
||||||
|
CHECK_VALUES(data[pos], 90, 60); // maybe CPAP-Check pressure, also matches EZ-Start Pressure
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
UNEXPECTED_VALUE(code, "known slice code");
|
UNEXPECTED_VALUE(code, "known slice code");
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user