Initial Weinmann Support, Pressure Relief Fixes, Pressure String Fixes

This commit is contained in:
Mark Watkins 2014-08-03 23:00:13 +10:00
parent 740de82170
commit 5e5bcd9e4a
37 changed files with 1540 additions and 412 deletions

View File

@ -12,4 +12,5 @@ TRANSLATIONS += \
Translations/Svenska.se.ts \
Translations/Espaniol.es.ts \
Translations/Bulgarian.bg.ts \
Translations/English.en_UK.ts
Translations/English.en_UK.ts \
Translations/Portugues.pt.ts

View File

@ -95,6 +95,7 @@ const QString STR_MACH_ResMed = "ResMed";
const QString STR_MACH_PRS1 = "PRS1";
const QString STR_MACH_Journal = "Journal";
const QString STR_MACH_Intellipap = "Intellipap";
const QString STR_MACH_Weinmann= "Weinmann";
const QString STR_MACH_FPIcon = "FPIcon";
const QString STR_MACH_MSeries = "MSeries";
const QString STR_MACH_CMS50 = "CMS50";

View File

@ -959,7 +959,9 @@ bool Day::removeSession(Session *sess)
QString Day::getCPAPMode()
{
CPAPMode mode = (CPAPMode)(int)settings_max(CPAP_Mode);
Q_ASSERT(machine_type() == MT_CPAP);
CPAPMode mode = (CPAPMode)(int)qRound(settings_wavg(CPAP_Mode));
if (mode == MODE_CPAP) {
return QObject::tr("Fixed");
} else if (mode == MODE_APAP) {
@ -968,31 +970,59 @@ QString Day::getCPAPMode()
return QObject::tr("Fixed Bi-Level");
} else if (mode == MODE_BILEVEL_AUTO_FIXED_PS) {
return QObject::tr("Auto Bi-Level (Fixed PS)");
} else if (mode == MODE_ASV) {
} else if (mode == MODE_BILEVEL_AUTO_VARIABLE_PS) {
return QObject::tr("Auto Bi-Level (Variable PS)");
} else if (mode == MODE_ASV) {
return QObject::tr("ASV Fixed EPAP");
} else if (mode == MODE_ASV_VARIABLE_EPAP) {
} else if (mode == MODE_ASV_VARIABLE_EPAP) {
return QObject::tr("ASV Variable EPAP");
}
return STR_TR_Unknown;
}
QString Day::getPressureRelief()
{
CPAPLoader * loader = qobject_cast<CPAPLoader *>(machine->loader());
if (!loader) return STR_MessageBox_Error;
QString pr_str;
ChannelID pr_level_chan = loader->PresReliefLevel();
ChannelID pr_mode_chan = loader->PresReliefMode();
if ((pr_level_chan != NoChannel) && settingExists(pr_level_chan)) {
int pr_level = qRound(settings_wavg(pr_level_chan));
int pr_mode = qRound(settings_wavg(pr_mode_chan));
pr_str = QObject::tr("%1%2").arg(loader->PresReliefLabel()).
arg(schema::channel[pr_mode_chan].option(pr_mode));
if (pr_mode > 0) pr_str += QString(" %1").arg(schema::channel[pr_level_chan].option(pr_level));
} else pr_str = STR_TR_None;
return pr_str;
}
QString Day::getPressureSettings()
{
Q_ASSERT(machine_type() == MT_CPAP);
CPAPMode mode = (CPAPMode)(int)settings_max(CPAP_Mode);
QString units = schema::channel[CPAP_Pressure].units();
if (mode == MODE_CPAP) {
return QObject::tr("%1 %2").arg(settings_min(CPAP_Pressure)).arg(units);
return QObject::tr("Fixed %1 (%2)").arg(settings_min(CPAP_Pressure)).arg(units);
} else if (mode == MODE_APAP) {
return QObject::tr("%1-%2 %3").arg(settings_min(CPAP_PressureMin)).arg(settings_max(CPAP_PressureMax)).arg(units);
return QObject::tr("Min %1 Max %2 (%3)").arg(settings_min(CPAP_PressureMin)).arg(settings_max(CPAP_PressureMax)).arg(units);
} else if (mode == MODE_BILEVEL_FIXED ) {
return QObject::tr("%1-%2 %3").arg(settings_min(CPAP_EPAP),0,'f',1).arg(settings_max(CPAP_IPAP),0,'f',1).arg(units);
return QObject::tr("IPAP %1 EPAP %2 (%3)").arg(settings_min(CPAP_EPAP),0,'f',1).arg(settings_max(CPAP_IPAP),0,'f',1).arg(units);
} else if (mode == MODE_BILEVEL_AUTO_FIXED_PS) {
return QObject::tr("PS %3 over %1-%2 %4 ").arg(settings_min(CPAP_EPAPLo),0,'f',1).arg(settings_max(CPAP_IPAPHi),0,'f',1).arg(settings_max(CPAP_PS),0,'f',1).arg(units);
return QObject::tr("PS %3 over %1-%2 (%4)").arg(settings_min(CPAP_EPAPLo),0,'f',1).arg(settings_max(CPAP_IPAPHi),0,'f',1).arg(settings_max(CPAP_PS),0,'f',1).arg(units);
} else if (mode == MODE_BILEVEL_AUTO_VARIABLE_PS) {
return QObject::tr("Min EPAP %3 Max IPAP %4 PS %1-%2 (%5)").arg(settings_min(CPAP_PSMin),0,'f',1).arg(settings_max(CPAP_PSMax),0,'f',1).arg(settings_min(CPAP_EPAPLo),0,'f',1).arg(settings_max(CPAP_IPAPHi),0,'f',1).arg(units);
} else if (mode == MODE_ASV) {
return QObject::tr("PS %4-%5 over %1-%3 %6").arg(settings_min(CPAP_EPAP),0,'f',1).arg(settings_max(CPAP_IPAP),0,'f',1).arg(settings_min(CPAP_PSMin),0,'f',1).arg(settings_max(CPAP_PSMax),0,'f',1).arg(units);
return QObject::tr("PS %4-%5 over %1-%3 (%6)").arg(settings_min(CPAP_EPAP),0,'f',1).arg(settings_max(CPAP_IPAP),0,'f',1).arg(settings_min(CPAP_PSMin),0,'f',1).arg(settings_max(CPAP_PSMax),0,'f',1).arg(units);
} else if (mode == MODE_ASV_VARIABLE_EPAP) {
return QObject::tr("PS %4-%5 over EPAP %1-%2 Max %3 %6").arg(settings_min(CPAP_EPAPLo),0,'f',1).arg(settings_max(CPAP_EPAPHi),0,'f',1).arg(settings_max(CPAP_IPAPHi),0,'f',1).arg(settings_min(CPAP_PSMin),0,'f',1).arg(settings_max(CPAP_PSMax),0,'f',1).arg(units);
return QObject::tr("PS %4-%5 over EPAP %1-%2 Max %3 (%6)").arg(settings_min(CPAP_EPAPLo),0,'f',1).arg(settings_max(CPAP_EPAPHi),0,'f',1).arg(settings_max(CPAP_IPAPHi),0,'f',1).arg(settings_min(CPAP_PSMin),0,'f',1).arg(settings_max(CPAP_PSMax),0,'f',1).arg(units);
}
return STR_TR_Unknown;

View File

@ -179,8 +179,11 @@ class Day
bool removeSession(Session *sess);
// Some ugly CPAP specific stuff
QString getCPAPMode();
QString getPressureRelief();
QString getPressureSettings();
QList<Session *> sessions;
protected:

View File

@ -39,7 +39,7 @@ Q_OBJECT
virtual const QString &loaderName() { return cms50_class_name; }
virtual MachineInfo newInfo() {
return MachineInfo(MT_OXIMETER, cms50_class_name, QObject::tr("Contec"), QObject::tr("CMS50"), QString(), QString(), QObject::tr("CMS50"), QDateTime::currentDateTime(), cms50_data_version);
return MachineInfo(MT_OXIMETER, 0, cms50_class_name, QObject::tr("Contec"), QObject::tr("CMS50"), QString(), QString(), QObject::tr("CMS50"), QDateTime::currentDateTime(), cms50_data_version);
}

View File

@ -537,6 +537,7 @@ bool FPIconLoader::OpenFLW(Machine *mach, QString filename)
const int samples_per_block = 50;
const double rate = 1000.0 / double(samples_per_block);
// F&P Overwrites this file, not appends to it.
flow = new EventList(EVL_Waveform, 1.0F, 0, 0, 0, rate);
pressure = new EventList(EVL_Event, 0.01F, 0, 0, 0, rate * double(samples_per_block));

View File

@ -48,7 +48,7 @@ const QString fpicon_class_name = STR_MACH_FPIcon;
This is only relatively recent addition and still needs more work
*/
class FPIconLoader : public MachineLoader
class FPIconLoader : public CPAPLoader
{
public:
FPIconLoader();
@ -76,13 +76,23 @@ class FPIconLoader : public MachineLoader
//Machine *CreateMachine(QString serial);
virtual MachineInfo newInfo() {
return MachineInfo(MT_CPAP, fpicon_class_name, QObject::tr("Fisher & Paykel"), QString(), QString(), QString(), QObject::tr("ICON"), QDateTime::currentDateTime(), fpicon_data_version);
return MachineInfo(MT_CPAP, 0, fpicon_class_name, QObject::tr("Fisher & Paykel"), QString(), QString(), QString(), QObject::tr("ICON"), QDateTime::currentDateTime(), fpicon_data_version);
}
//! \brief Registers this MachineLoader with the master list, so F&P Icon data can load
static void Register();
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Now for some CPAPLoader overrides
////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual QString presRelType() { return QObject::tr(""); } // might not need this one
virtual ChannelID presRelSet() { return NoChannel; }
virtual ChannelID presRelLevel() { return NoChannel; }
////////////////////////////////////////////////////////////////////////////////////////////////////////////
protected:
QDateTime readFPDateTime(quint8 *data);

View File

@ -17,6 +17,8 @@
extern QProgressBar *qprogress;
ChannelID INTP_SmartFlexMode, INTP_SmartFlexLevel;
Intellipap::Intellipap(MachineID id)
: CPAP(id)
{
@ -339,6 +341,7 @@ int IntellipapLoader::Open(QString path)
sess->AddEventList(CPAP_Snore, EVL_Event);
sess->AddEventList(CPAP_Obstructive, EVL_Event);
sess->AddEventList(CPAP_VSnore, EVL_Event);
sess->AddEventList(CPAP_Hypopnea, EVL_Event);
sess->AddEventList(CPAP_NRI, EVL_Event);
sess->AddEventList(CPAP_LeakFlag, EVL_Event);
@ -371,6 +374,8 @@ int IntellipapLoader::Open(QString path)
sid = 0;
SessionID lastsid = 0;
int last_minp=0, last_maxp=0, last_ps=0, last_pres = 0;
for (int i = 0; i < recs; i++) {
// convert timestamp to real epoch
ts1 = ((m_buffer[pos] << 24) | (m_buffer[pos + 1] << 16) | (m_buffer[pos + 2] << 8) | m_buffer[pos + 3]) + ep;
@ -393,32 +398,21 @@ int IntellipapLoader::Open(QString path)
int pres = m_buffer[pos + 0xd];
if (mode >= MODE_BILEVEL_FIXED) {
sess->settings[CPAP_EPAP] = float(minp) / 10.0;
sess->settings[CPAP_IPAP] = float(maxp) / 10.0;
sess->settings[CPAP_PS] = float(ps) / 10.0;
sess->eventlist[CPAP_IPAP][0]->AddEvent(time, float(pres) / 10.0);
sess->eventlist[CPAP_EPAP][0]->AddEvent(time, float(pres-ps) / 10.0);
rampval = maxp;
} else {
sess->eventlist[CPAP_Pressure][0]->AddEvent(time, float(pres) / 10.0); // current pressure
rampval = minp;
if (mode == MODE_APAP) {
sess->settings[CPAP_PressureMin] = float(minp) / 10.0;
sess->settings[CPAP_PressureMax] = float(maxp) / 10.0;
} else if (mode == MODE_CPAP) {
sess->settings[CPAP_Pressure] = float(maxp) / 10.0;
}
}
qint64 rs = rampstart[sid];
if (pres < rampval) {
if (!rs) {
// ramp started
// int rv = pres-rampval;
// double ramp =
rampstart[sid] = time;
}
rampend[sid] = time;
@ -430,8 +424,34 @@ int IntellipapLoader::Open(QString path)
int duration = (time - rs) / 1000L;
sess->eventlist[CPAP_Ramp][0]->AddEvent(time, duration);
rampstart[sid] = 0;
//rampend[sid] = 0; // don't need to
rampstart.remove(sid);
rampend.remove(sid);
}
}
// Do this after ramp, because ramp calcs might need to insert interpolated pressure samples
if (mode >= MODE_BILEVEL_FIXED) {
sess->settings[CPAP_EPAP] = float(minp) / 10.0;
sess->settings[CPAP_IPAP] = float(maxp) / 10.0;
sess->settings[CPAP_PS] = float(ps) / 10.0;
sess->eventlist[CPAP_IPAP][0]->AddEvent(time, float(pres) / 10.0);
sess->eventlist[CPAP_EPAP][0]->AddEvent(time, float(pres-ps) / 10.0);
// rampval = maxp;
} else {
sess->eventlist[CPAP_Pressure][0]->AddEvent(time, float(pres) / 10.0); // current pressure
// rampval = minp;
if (mode == MODE_APAP) {
sess->settings[CPAP_PressureMin] = float(minp) / 10.0;
sess->settings[CPAP_PressureMax] = float(maxp) / 10.0;
} else if (mode == MODE_CPAP) {
sess->settings[CPAP_Pressure] = float(maxp) / 10.0;
}
}
@ -446,6 +466,10 @@ int IntellipapLoader::Open(QString path)
sess->eventlist[CPAP_Snore][0]->AddEvent(time, m_buffer[pos + 0x4]); //4/5??
if (m_buffer[pos+0x4] > 0) {
sess->eventlist[CPAP_VSnore][0]->AddEvent(time, m_buffer[pos + 0x5]);
}
// 0x0f == Leak Event
// 0x04 == Snore?
if (m_buffer[pos + 0xf] > 0) { // Leak Event
@ -477,6 +501,7 @@ int IntellipapLoader::Open(QString path)
EventDataType mv = tv * rr; // MinuteVent=TidalVolume * Respiratory Rate
sess->eventlist[CPAP_MinuteVent][0]->AddEvent(time, mv / 1000.0);
break;
} else {
}
lastsid = sid;
}
@ -521,14 +546,12 @@ int IntellipapLoader::Open(QString path)
// sess->really_set_last(last);
sess->settings[CPAP_PresReliefType] = (PRTypes)PR_SMARTFLEX;
sess->settings[CPAP_PresReliefSet] = smartflex;
sess->settings[INTP_SmartFlexLevel] = smartflex;
if (smartflexmode == 0) {
sess->settings[CPAP_PresReliefMode] = PM_FullTime;
sess->settings[INTP_SmartFlexMode] = PM_FullTime;
} else {
sess->settings[CPAP_PresReliefMode] = PM_RampOnly;
sess->settings[INTP_SmartFlexMode] = PM_RampOnly;
}
sess->settings[CPAP_RampPressure] = ramp_pressure;
@ -567,4 +590,23 @@ void IntellipapLoader::Register()
RegisterLoader(new IntellipapLoader());
//InitModelMap();
intellipap_initialized = true;
using namespace schema;
Channel * chan = nullptr;
channel.add(GRP_CPAP, chan = new Channel(INTP_SmartFlexMode = 0x1165, SETTING, SESSION,
"INTPSmartFlexMode", QObject::tr("SmartFlex Mode"),
QObject::tr("Intellipap pressure relief mode."),
QObject::tr("SmartFlex Mode"),
"", DEFAULT, Qt::green));
chan->addOption(0, STR_TR_Off);
chan->addOption(1, QObject::tr("Ramp Only"));
chan->addOption(2, QObject::tr("Full Time"));
channel.add(GRP_CPAP, chan = new Channel(INTP_SmartFlexLevel = 0x1169, SETTING, SESSION,
"INTPSmartFlexLevel", QObject::tr("SmartFlex Level"),
QObject::tr("Intellipap pressure relief level."),
QObject::tr("SmartFlex Level"),
"", DEFAULT, Qt::green));
}

View File

@ -39,6 +39,8 @@ class Intellipap: public CPAP
const int intellipap_load_buffer_size = 1024 * 1024;
extern ChannelID INTP_SmartFlexMode;
extern ChannelID INTP_SmartFlexLevel;
const QString intellipap_class_name = STR_MACH_Intellipap;
@ -46,7 +48,7 @@ const QString intellipap_class_name = STR_MACH_Intellipap;
\brief Loader for DeVilbiss Intellipap Auto data
This is only relatively recent addition and still needs more work
*/
class IntellipapLoader : public MachineLoader
class IntellipapLoader : public CPAPLoader
{
public:
IntellipapLoader();
@ -71,8 +73,18 @@ class IntellipapLoader : public MachineLoader
static void Register();
virtual MachineInfo newInfo() {
return MachineInfo(MT_CPAP, intellipap_class_name, QObject::tr("DeVilbiss"), QString(), QString(), QString(), QObject::tr("Intellipap"), QDateTime::currentDateTime(), intellipap_data_version);
return MachineInfo(MT_CPAP, 0, intellipap_class_name, QObject::tr("DeVilbiss"), QString(), QString(), QString(), QObject::tr("Intellipap"), QDateTime::currentDateTime(), intellipap_data_version);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Now for some CPAPLoader overrides
////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual QString presRelLabel() { return QObject::tr("SmartFlex Settings"); } // might not need this one
virtual ChannelID presReliefMode() { return INTP_SmartFlexMode; }
virtual ChannelID presRelLevel() { return INTP_SmartFlexLevel; }
////////////////////////////////////////////////////////////////////////////////////////////////////////////
protected:
QString last;

View File

@ -41,7 +41,7 @@ Q_OBJECT
// Machine *CreateMachine();
virtual MachineInfo newInfo() {
return MachineInfo(MT_OXIMETER, md300w1_class_name, QObject::tr("ChoiceMMed"), QString(), QString(), QString(), QObject::tr("MD300"), QDateTime::currentDateTime(), md300w1_data_version);
return MachineInfo(MT_OXIMETER, 0, md300w1_class_name, QObject::tr("ChoiceMMed"), QString(), QString(), QString(), QObject::tr("MD300"), QDateTime::currentDateTime(), md300w1_data_version);
}

View File

@ -63,7 +63,7 @@ class MSeriesLoader : public MachineLoader
// Machine *CreateMachine(QString serial);
virtual MachineInfo newInfo() {
return MachineInfo(MT_CPAP, mseries_class_name, QObject::tr("Respironics"), QString(), QString(), QString(), QObject::tr("M-Series"), QDateTime::currentDateTime(), mseries_data_version);
return MachineInfo(MT_CPAP, 0, mseries_class_name, QObject::tr("Respironics"), QString(), QString(), QString(), QObject::tr("M-Series"), QDateTime::currentDateTime(), mseries_data_version);
}
//! \brief Register this Module to the list of Loaders, so it knows to search for PRS1 data.

View File

@ -99,6 +99,10 @@ crc_t CRC16(const unsigned char *data, size_t data_len)
}
#endif
enum FlexMode { FLEX_None, FLEX_CFlex, FLEX_CFlexPlus, FLEX_AFlex, FLEX_RiseTime, FLEX_BiFlex, FLEX_Unknown };
PRS1::PRS1(MachineID id): CPAP(id)
{
}
@ -213,6 +217,8 @@ int PRS1Loader::Open(QString path)
if ((filename[0] == 'P') && (isdigit(filename[1])) && (isdigit(filename[2]))) {
SerialNumbers.push_back(filename);
} else if (isdigit(filename[0]) && isdigit(filename[1])) {
SerialNumbers.push_back(filename);
} else if (filename.toLower() == "last.txt") { // last.txt points to the current serial number
QString file = fi.canonicalFilePath();
QFile f(file);
@ -359,7 +365,7 @@ int PRS1Loader::OpenMachine(Machine *m, QString path)
if ((filename[0].toLower() == 'p') && (isdigit(filename[1]))) {
// p0, p1, p2.. etc.. folders contain the session data
paths.push_back(fi.canonicalFilePath());
} else if (filename.toLower() == "properties.txt") {
} else if ((filename.toLower() == "properties.txt") || (filename.toLower() == "prop.txt")) {
ParseProperties(m, fi.canonicalFilePath());
} else if (filename.toLower() == "e") {
// Error files..
@ -839,19 +845,22 @@ bool PRS1SessionData::ParseF0Events()
EventList *LEAK = session->AddEventList(CPAP_LeakTotal, EVL_Event);
EventList *SNORE = session->AddEventList(CPAP_Snore, EVL_Event);
EventList *CA = nullptr; //session->AddEventList(CPAP_ClearAirway, EVL_Event);
EventList *VS = nullptr;
EventList *VS2 = nullptr;
EventList *FL = nullptr;
EventList *RE = nullptr;
EventList *PP = session->AddEventList(CPAP_PressurePulse, EVL_Event);
EventList *RE = session->AddEventList(CPAP_RERA, EVL_Event);
EventList *CA = session->AddEventList(CPAP_ClearAirway, EVL_Event);
EventList *FL = session->AddEventList(CPAP_FlowLimit, EVL_Event);
EventList *VS = session->AddEventList(CPAP_VSnore, EVL_Event);
EventList *VS2 = session->AddEventList(CPAP_VSnore2, EVL_Event);
Code[12] = session->AddEventList(PRS1_0B, EVL_Event);
Code[17] = session->AddEventList(PRS1_0E, EVL_Event);
Code[20] = session->AddEventList(CPAP_LargeLeak, EVL_Event);
EventList *PRESSURE = nullptr;
EventList *EPAP = nullptr;
EventList *IPAP = nullptr;
EventList *PS = nullptr;
EventList *PP = nullptr;
//session->AddEventList(CPAP_VSnore, EVL_Event);
//EventList * VS=session->AddEventList(CPAP_Obstructive, EVL_Event);
unsigned char lastcode3 = 0, lastcode2 = 0, lastcode = 0;
@ -961,9 +970,6 @@ bool PRS1SessionData::ParseF0Events()
break;
case 0x04: // Pressure Pulse
if (!PP) {
if (!(PP = session->AddEventList(CPAP_PressurePulse, EVL_Event))) { return false; }
}
PP->AddEvent(t, buffer[pos++]);
break;
@ -972,10 +978,6 @@ bool PRS1SessionData::ParseF0Events()
data[0] = buffer[pos++];
tt = t - (qint64(data[0]) * 1000L);
if (!RE) {
if (!(RE = session->AddEventList(CPAP_RERA, EVL_Event))) { return false; }
}
RE->AddEvent(tt, data[0]);
break;
@ -989,10 +991,6 @@ bool PRS1SessionData::ParseF0Events()
data[0] = buffer[pos++];
tt = t - (qint64(data[0]) * 1000L);
if (!CA) {
if (!(CA = session->AddEventList(CPAP_ClearAirway, EVL_Event))) { return false; }
}
CA->AddEvent(tt, data[0]);
break;
@ -1006,10 +1004,6 @@ bool PRS1SessionData::ParseF0Events()
data[0] = buffer[pos++];
tt = t - (qint64(data[0]) * 1000L);
if (!FL) {
if (!(FL = session->AddEventList(CPAP_FlowLimit, EVL_Event))) { return false; }
}
FL->AddEvent(tt, data[0]);
break;
@ -1017,19 +1011,11 @@ bool PRS1SessionData::ParseF0Events()
data[0] = buffer[pos++];
data[1] = buffer[pos++];
if (!Code[12]) {
if (!(Code[12] = session->AddEventList(PRS1_0B, EVL_Event))) { return false; }
}
// FIXME
Code[12]->AddEvent(t, data[0]);
break;
case 0x0d: // Vibratory Snore
if (!VS) {
if (!(VS = session->AddEventList(CPAP_VSnore, EVL_Event))) { return false; }
}
VS->AddEvent(t, 0);
break;
@ -1041,10 +1027,6 @@ bool PRS1SessionData::ParseF0Events()
SNORE->AddEvent(t, data[1]);
if (data[1] > 0) {
if (!VS2) {
if (!(VS2 = session->AddEventList(CPAP_VSnore2, EVL_Event))) { return false; }
}
VS2->AddEvent(t, data[1]);
}
@ -1061,10 +1043,6 @@ bool PRS1SessionData::ParseF0Events()
//pos+=2;
data[2] = buffer[pos++];
if (!Code[17]) {
if (!(Code[17] = session->AddEventList(PRS1_0E, EVL_Event))) { return false; }
}
tdata = unsigned(data[1]) << 8 | unsigned(data[0]);
Code[17]->AddEvent(t, tdata);
//qDebug() << hex << data[0] << data[1] << data[2];
@ -1078,10 +1056,6 @@ bool PRS1SessionData::ParseF0Events()
pos += 2;
data[1] = buffer[pos++];
if (!Code[20]) {
if (!(Code[20] = session->AddEventList(CPAP_LargeLeak, EVL_Event))) { return false; }
}
tt = t - qint64(data[1]) * 1000L;
Code[20]->AddEvent(tt, data[0]);
break;
@ -1129,20 +1103,193 @@ bool PRS1SessionData::ParseF0Events()
bool PRS1SessionData::ParseCompliance()
{
// Bleh!! There is probably 10 different formats for these useless piece of junk machines
if (!compliance) return false;
return true;
}
bool PRS1SessionData::ParseSummary()
bool PRS1SessionData::ParseSummaryF0()
{
if (!summary) return false;
if (summary->m_data.size() < 59) {
return false;
}
const unsigned char * data = (unsigned char *)summary->m_data.constData();
CPAPMode cpapmode = MODE_UNKNOWN;
switch (data[0x02]) { // PRS1 mode // 0 = CPAP, 2 = APAP
case 0x00:
cpapmode = MODE_CPAP;
break;
case 0x01:
cpapmode = MODE_BILEVEL_FIXED;
break;
case 0x02:
cpapmode = MODE_APAP;
break;
case 0x03:
cpapmode = MODE_BILEVEL_AUTO_VARIABLE_PS;
}
EventDataType min_pressure = float(data[0x03]) / 10.0;
EventDataType max_pressure = float(data[0x04]) / 10.0;
EventDataType ps = float(data[0x05]) / 10.0; // pressure support
if (cpapmode == MODE_CPAP) {
session->settings[CPAP_Pressure] = min_pressure;
} else if (cpapmode == MODE_APAP) {
session->settings[CPAP_PressureMin] = min_pressure;
session->settings[CPAP_PressureMax] = max_pressure;
} else if (cpapmode == MODE_BILEVEL_FIXED) {
session->settings[CPAP_EPAP] = min_pressure;
session->settings[CPAP_IPAP] = max_pressure;
session->settings[CPAP_PS] = ps;
} else if (cpapmode == MODE_BILEVEL_AUTO_VARIABLE_PS) {
session->settings[CPAP_EPAPLo] = min_pressure;
session->settings[CPAP_EPAPHi] = max_pressure - 2.0;
session->settings[CPAP_IPAPLo] = min_pressure + 2.0;
session->settings[CPAP_IPAPHi] = max_pressure;
session->settings[CPAP_PSMin] = 2.0f;
session->settings[CPAP_PSMax] = ps;
}
session->settings[CPAP_Mode] = (int)cpapmode;
int ramp_time = data[0x06];
EventDataType ramp_pressure = float(data[0x07]) / 10.0;
session->settings[CPAP_RampTime] = (int)ramp_time;
session->settings[CPAP_RampPressure] = ramp_pressure;
// Tubing lock has no setting byte
// int SysOneResistance = (data[0x0a] & 7);
// bool SysOneResistanceOn = (data[0x0a] & 0x40) ? true : false;
// bool SysOneResistanceLock = (data[0x0a] & 0x80) ? true : false;
// int humidifier = (data[0x09] & 7);
// bool autoOn = (data[0x0b] & 0x40) ? true : false; //?
// Menu Options
session->settings[PRS1_SysLock] = (bool) (data[0x0a] & 0x80); // System One Resistance Lock Setting
session->settings[PRS1_SysOneResistSet] = (int)data[0x0a] & 7; // SYstem One Resistance setting value
session->settings[PRS1_SysOneResistStat] = (bool) (data[0x0a] & 0x40); // System One Resistance Status bit
session->settings[PRS1_HoseDiam] = (data[0x0a] & 0x08) ? QObject::tr("15mm") : QObject::tr("22mm");
session->settings[PRS1_AutoOn] = (bool) (data[0x0b] & 0x40);
session->settings[PRS1_AutoOff] = (bool) (data[0x0c] & 0x10);
session->settings[PRS1_MaskAlert] = (bool) (data[0x0c] & 0x08);
session->settings[PRS1_ShowAHI] = (bool) (data[0x0c] & 0x04);
session->settings[PRS1_HumidStatus] = (bool)(data[0x09] & 0x80); // Humidifier Connected
session->settings[PRS1_HumitSetting] = (int)(data[0x09] & 7); // Humidifier Value
// session->
quint8 flex = data[0x08];
int flexlevel = flex & 0x03;
FlexMode flexmode = FLEX_Unknown;
// 88 CFlex+ / AFlex (depending on CPAP mode)
// 80 CFlex
// 00 NoFlex
// c0 Split CFlex then None
// c8 Split CFlex+ then None
flex &= 0xf8;
bool split = false;
if (flex & 0x40) { // This bit defines the Flex setting for the CPAP component of the Split night
split = true;
}
if (flex & 0x80) { // CFlex bit
if (flex & 0x10) {
flexmode = FLEX_RiseTime;
} else if (flex & 8) { // Plus bit
if (split || (cpapmode == MODE_CPAP)) {
flexmode = FLEX_CFlexPlus;
} else if (cpapmode == MODE_APAP) {
flexmode = FLEX_AFlex;
}
} else {
// CFlex bits refer to Rise Time on BiLevel machines
flexmode = (cpapmode >= MODE_BILEVEL_FIXED) ? FLEX_BiFlex : FLEX_CFlex;
}
} else flexmode = FLEX_None;
session->settings[PRS1_FlexMode] = (int)flexmode;
session->settings[PRS1_FlexLevel] = (int)flexlevel;
int duration = data[0x14] | data[0x15] << 8;
session->set_last(qint64(summary->timestamp+duration) * 1000L);
return true;
}
bool PRS1SessionData::ParseSummaryF0V4()
{
return true;
}
bool PRS1SessionData::ParseSummaryF3()
{
const unsigned char * data = (unsigned char *)summary->m_data.constData();
EventDataType epap = data[0x04] | (data[0x05] << 8);
EventDataType ipap = data[0x06] | (data[0x07] << 8);
EventDataType f1 = data[0x08] | (data[0x09] << 8);
return true;
}
bool PRS1SessionData::ParseSummaryF5()
{
return true;
}
bool PRS1SessionData::ParseSummary()
{
// Family 0 = XPAP
// Family 3 = BIPAP AVAPS
// Family 5 = BIPAP AutoSV
if (!summary) return false;
if (summary->m_data.size() < 59) {
//return false;
}
session->setPhysMax(CPAP_LeakTotal, 120);
session->setPhysMin(CPAP_LeakTotal, 0);
session->setPhysMax(CPAP_Pressure, 25);
session->setPhysMin(CPAP_Pressure, 4);
session->setPhysMax(CPAP_IPAP, 25);
session->setPhysMin(CPAP_IPAP, 4);
session->setPhysMax(CPAP_EPAP, 25);
session->setPhysMin(CPAP_EPAP, 4);
session->setPhysMax(CPAP_PS, 25);
session->setPhysMin(CPAP_PS, 0);
session->set_first(qint64(summary->timestamp) * 1000L);
if (this->session->session() == 3880) {
int i=5;
}
switch (summary->family) {
case 0:
return ParseSummaryF0();
case 3:
return ParseSummaryF3();
case 5:
return ParseSummaryF5();
}
const unsigned char * data = (unsigned char *)summary->m_data.constData();
//////////////////////////////////////////////////////////////////////////////////////////
// ASV Codes (Family 5) Recheck 17/10/2013
// These are all confirmed off Encore reports
@ -1226,22 +1373,23 @@ bool PRS1SessionData::ParseSummary()
session->settings[CPAP_Pressure] = (EventDataType)min;
}
if (data[offset + 0x08] & 0x80) { // Flex Setting
if (data[offset + 0x08] & 0x08) {
if (max > 0) {
if (summary->family == 5) {
session->settings[CPAP_PresReliefType] = (int)PR_BIFLEX;
session->settings[PRS1_FlexMode] = (int)PR_BIFLEX;
} else {
session->settings[CPAP_PresReliefType] = (int)PR_AFLEX;
session->settings[PRS1_FlexMode] = (int)PR_AFLEX;
}
} else { session->settings[CPAP_PresReliefType] = (int)PR_CFLEXPLUS; }
} else { session->settings[CPAP_PresReliefType] = (int)PR_CFLEX; }
} else { session->settings[CPAP_PresReliefType] = (int)PR_NONE; }
} else { session->settings[PRS1_FlexMode] = (int)PR_CFLEXPLUS; }
} else { session->settings[PRS1_FlexMode] = (int)PR_CFLEX; }
} else { session->settings[PRS1_FlexMode] = (int)PR_NONE; }
session->settings[CPAP_PresReliefMode] = (int)PM_FullTime; // only has one mode
// Map the channels
session->settings[PRS1_FlexLevel] = (int)(data[offset + 0x08] & 7);
session->settings[CPAP_PresReliefSet] = (int)(data[offset + 0x08] & 7);
session->settings[PRS1_SysLock] = (data[offset + 0x0a] & 0x80) == 0x80;
session->settings[PRS1_HoseDiam] = ((data[offset + 0x0a] & 0x08) ? "15mm" : "22mm");
session->settings[PRS1_AutoOff] = (data[offset + 0x0c] & 0x10) == 0x10;
@ -1274,16 +1422,7 @@ bool PRS1SessionData::ParseSummary()
// Set recommended Graph values..
session->setPhysMax(CPAP_LeakTotal, 120);
session->setPhysMin(CPAP_LeakTotal, 0);
session->setPhysMax(CPAP_Pressure, 25);
session->setPhysMin(CPAP_Pressure, 4);
session->setPhysMax(CPAP_IPAP, 25);
session->setPhysMin(CPAP_IPAP, 4);
session->setPhysMax(CPAP_EPAP, 25);
session->setPhysMin(CPAP_EPAP, 4);
session->setPhysMax(CPAP_PS, 25);
session->setPhysMin(CPAP_PS, 0);
if (summary->family == 0 && summary->familyVersion == 0) {
@ -1307,32 +1446,34 @@ bool PRS1SessionData::ParseEvents()
qDebug() << "Unknown PRS1 familyVersion" << event->familyVersion;
return false;
}
if (res) {
if (session->count(CPAP_IPAP) > 0) {
if (session->settings[CPAP_Mode].toInt() != (int)MODE_ASV) {
session->settings[CPAP_Mode] = MODE_BILEVEL_FIXED;
}
// if (session->settings[CPAP_Mode].toInt() != (int)MODE_ASV) {
// session->settings[CPAP_Mode] = MODE_BILEVEL_FIXED;
// }
if (session->settings[CPAP_PresReliefType].toInt() != PR_NONE) {
session->settings[CPAP_PresReliefType] = PR_BIFLEX;
}
// if (session->settings[CPAP_PresReliefType].toInt() != PR_NONE) {
// session->settings[CPAP_PresReliefType] = PR_BIFLEX;
// }
EventDataType min = session->settings[CPAP_PressureMin].toDouble();
EventDataType max = session->settings[CPAP_PressureMax].toDouble();
session->settings[CPAP_EPAP] = min;
session->settings[CPAP_IPAP] = max;
// EventDataType min = session->settings[CPAP_PressureMin].toDouble();
// EventDataType max = session->settings[CPAP_PressureMax].toDouble();
// session->settings[CPAP_EPAP] = min;
// session->settings[CPAP_IPAP] = max;
session->settings[CPAP_PS] = max - min;
session->settings.erase(session->settings.find(CPAP_PressureMin));
session->settings.erase(session->settings.find(CPAP_PressureMax));
// session->settings[CPAP_PS] = max - min;
// session->settings.erase(session->settings.find(CPAP_PressureMin));
// session->settings.erase(session->settings.find(CPAP_PressureMax));
session->m_valuesummary.erase(session->m_valuesummary.find(CPAP_Pressure));
session->m_wavg.erase(session->m_wavg.find(CPAP_Pressure));
session->m_min.erase(session->m_min.find(CPAP_Pressure));
session->m_max.erase(session->m_max.find(CPAP_Pressure));
session->m_gain.erase(session->m_gain.find(CPAP_Pressure));
// session->m_valuesummary.erase(session->m_valuesummary.find(CPAP_Pressure));
// session->m_wavg.erase(session->m_wavg.find(CPAP_Pressure));
// session->m_min.erase(session->m_min.find(CPAP_Pressure));
// session->m_max.erase(session->m_max.find(CPAP_Pressure));
// session->m_gain.erase(session->m_gain.find(CPAP_Pressure));
} else {
session->setSummaryOnly(true);
if (!session->settings.contains(CPAP_Pressure) && !session->settings.contains(CPAP_PressureMin)) {
session->settings[CPAP_BrokenSummary] = true;
@ -1691,6 +1832,7 @@ void InitModelMap()
ModelMap[0x37] = "RemStar BiPAP Auto with Bi-Flex";
ModelMap[0x38] = "RemStar Plus :("; // 150/250P/260P
ModelMap[0x41] = "BiPAP autoSV Advanced";
ModelMap[0x4E] = "BiPAP AVAPS";
}
bool initialized = false;
@ -1709,11 +1851,41 @@ void PRS1Loader::Register()
initialized = true;
channel.add(GRP_CPAP, new Channel(CPAP_PressurePulse = 0x1009, MINOR_FLAG, SESSION,
"PressurePulse", QObject::tr("Pressure Pulse"),
"PressurePulse",
QObject::tr("Pressure Pulse"),
QObject::tr("A pulse of pressure 'pinged' to detect a closed airway."),
QObject::tr("PP"), STR_UNIT_EventsPerHour, DEFAULT, QColor("dark red")));
QObject::tr("PP"),
STR_UNIT_EventsPerHour, DEFAULT, QColor("dark red")));
Channel * chan = nullptr;
channel.add(GRP_CPAP, chan = new Channel(PRS1_FlexMode = 0xe105, SETTING, SESSION,
"PRS1FlexMode", QObject::tr("Flex Mode"),
QObject::tr("PRS1 pressure relief mode."),
QObject::tr("Flex Mode"),
"", DEFAULT, Qt::green));
chan->addOption(FLEX_None, STR_TR_None);
chan->addOption(FLEX_CFlex, QObject::tr("C-Flex"));
chan->addOption(FLEX_CFlexPlus, QObject::tr("C-Flex+"));
chan->addOption(FLEX_AFlex, QObject::tr("A-Flex"));
chan->addOption(FLEX_RiseTime, QObject::tr("Rise Time"));
chan->addOption(FLEX_BiFlex, QObject::tr("Bi-Flex"));
channel.add(GRP_CPAP, chan = new Channel(PRS1_FlexLevel = 0xe106, SETTING, SESSION,
"PRS1FlexSet",
QObject::tr("Flex Level"),
QObject::tr("PRS1 pressure relief setting."),
QObject::tr("Flex Level"),
"", DEFAULT, Qt::blue));
chan->addOption(0, STR_TR_Off);
chan->addOption(1, QObject::tr("x1"));
chan->addOption(2, QObject::tr("x2"));
chan->addOption(3, QObject::tr("x3"));
QString unknowndesc=QObject::tr("Unknown PRS1 Code %1");
QString unknownname=QObject::tr("PRS1_%1");
QString unknownshort=QObject::tr("PRS1_%1");

View File

@ -115,6 +115,12 @@ public:
bool ParseEvents();
bool ParseWaveforms();
bool ParseSummaryF0();
bool ParseSummaryF0V4();
bool ParseSummaryF3();
bool ParseSummaryF5();
//! \brief Parse a single data chunk from a .002 file containing event data for a standard system one machine
bool ParseF0Events();
@ -174,7 +180,7 @@ protected:
/*! \class PRS1Loader
\brief Philips Respironics System One Loader Module
*/
class PRS1Loader : public MachineLoader
class PRS1Loader : public CPAPLoader
{
public:
PRS1Loader();
@ -199,9 +205,12 @@ class PRS1Loader : public MachineLoader
static void Register();
virtual MachineInfo newInfo() {
return MachineInfo(MT_CPAP, prs1_class_name, QObject::tr("Philips Respironics"), QString(), QString(), QString(), QObject::tr("System One"), QDateTime::currentDateTime(), prs1_data_version);
return MachineInfo(MT_CPAP, 0, prs1_class_name, QObject::tr("Philips Respironics"), QString(), QString(), QString(), QObject::tr("System One"), QDateTime::currentDateTime(), prs1_data_version);
}
virtual QString PresReliefLabel() { return QObject::tr(""); }
virtual ChannelID PresReliefMode() { return PRS1_FlexMode; }
virtual ChannelID PresReliefLevel() { return PRS1_FlexLevel; }
QHash<SessionID, PRS1FileGroup*> prs1sessions;

View File

@ -34,6 +34,9 @@ QHash<QString, QList<quint16> > Resmed_Model_Map;
const QString STR_UnknownModel = "Resmed S9 ???";
ChannelID RMS9_EPR, RMS9_EPRLevel;
// Return the model name matching the supplied model number.
const QString & lookupModel(quint16 model)
{
@ -274,26 +277,38 @@ void ResmedLoader::ParseSTR(Machine *mach, QStringList strfiles)
if ((sig = str.lookupSignal(CPAP_PSMin))) {
R.min_ps = EventDataType(sig->data[rec]) * sig->gain + sig->offset;
}
EventDataType epr = -1, epr_level = -1;
if ((sig = str.lookupSignal(RMS9_EPR))) {
R.epr = EventDataType(sig->data[rec]) * sig->gain + sig->offset;
epr= EventDataType(sig->data[rec]) * sig->gain + sig->offset;
}
if ((sig = str.lookupSignal(RMS9_EPRLevel))) {
R.epr_level = EventDataType(sig->data[rec]) * sig->gain + sig->offset;
epr_level= EventDataType(sig->data[rec]) * sig->gain + sig->offset;
}
if ((epr >= 0) && (epr_level >= 0)) {
R.epr_level = epr_level;
R.epr = epr;
} else {
if (epr >= 0) {
static bool warn=false;
if (!warn) { // just nag once
qDebug() << "If you can read this, please tell Jedimark you found a ResMed with EPR but no EPR_LEVEL so he can remove this warning";
warn = true;
}
R.epr = (epr > 0) ? 1 : 0;
R.epr_level = epr;
} else if (epr_level >= 0) {
R.epr_level = epr_level;
R.epr = (epr_level > 0) ? 1 : 0;
}
}
if ((sig = str.lookupSignal(CPAP_Mode))) {
int mod = EventDataType(sig->data[rec]) * sig->gain + sig->offset;
CPAPMode mode;
// if (R.epap > 0) {
// if (R.max_epap < 0) R.max_epap = R.epap;
// if (R.min_epap < 0) R.min_epap = R.epap;
// }
// if (R.ipap > 0) {
// if (R.max_ipap < 0) R.max_ipap = R.ipap;
// if (R.min_ipap < 0) R.min_ipap = R.ipap;
// }
if (mod >= 8) { // mod 8 == vpap adapt variable epap
mode = MODE_ASV_VARIABLE_EPAP;
if (!haveipap) {
@ -720,12 +735,9 @@ void ResmedImport::run()
if (R.epr >= 0) {
sess->settings[RMS9_EPR] = (int)R.epr;
sess->settings[CPAP_PresReliefType] = (int)PR_EPR;
sess->settings[CPAP_PresReliefSet] = (int)R.epr;
}
if (R.epr_level >= 0) {
sess->settings[RMS9_EPRLevel] = (int)R.epr_level;
sess->settings[CPAP_PresReliefMode] = (int)R.epr_level;
}
// Ignore all the rest of the sumary data, because there is enough available to calculate it with higher accuracy.
@ -788,12 +800,9 @@ void ResmedImportStage2::run()
if (R.mode >= 0) sess->settings[CPAP_Mode] = R.mode;
if (R.epr >= 0) {
sess->settings[RMS9_EPR] = (int)R.epr;
sess->settings[CPAP_PresReliefType] = (int)PR_EPR;
sess->settings[CPAP_PresReliefSet] = (int)R.epr;
}
if (R.epr_level >= 0) {
sess->settings[RMS9_EPRLevel] = (int)R.epr_level;
sess->settings[CPAP_PresReliefMode] = (int)R.epr_level;
}
if (R.leakmax >= 0) sess->setMax(CPAP_Leak, R.leakmax);
if (R.leakmax >= 0) sess->setMin(CPAP_Leak, 0);
@ -2341,6 +2350,21 @@ void ResInitModelMap()
resmed_codes[CPAP_PressureMin].push_back("Min tryck");
}
//<channel id="0xe201" class="setting" scope="!session" name="EPR" details="EPR Mode" label="EPR Mode" type="integer">
// <Option id="0" value="Off"/>
// <Option id="1" value="Ramp Only"/>
// <Option id="2" value="Full Time"/>
// <Option id="3" value="EPR?"/>
//</channel>
//<channel id="0xe202" class="setting" scope="!session" name="EPRLevel" details="EPR Setting" label="EPR Setting" type="integer">
// <Option id="0" value="0"/>
// <Option id="1" value="1"/>
// <Option id="2" value="2"/>
// <Option id="3" value="3"/>
//</channel>
ChannelID ResmedLoader::PresReliefMode() { return RMS9_EPR; }
ChannelID ResmedLoader::PresReliefLevel() { return RMS9_EPRLevel; }
bool resmed_initialized = false;
void ResmedLoader::Register()
@ -2351,6 +2375,31 @@ void ResmedLoader::Register()
RegisterLoader(new ResmedLoader());
ResInitModelMap();
resmed_initialized = true;
using namespace schema;
Channel * chan = nullptr;
channel.add(GRP_CPAP, chan = new Channel(RMS9_EPR = 0xe201, SETTING, SESSION,
"EPR", QObject::tr("EPR Mode"),
QObject::tr("ResMed Exhale Pressure Relief Mode."),
QObject::tr("EPR Mode"),
"", DEFAULT, Qt::green));
chan->addOption(0, STR_TR_Off);
chan->addOption(1, QObject::tr("Ramp Only"));
chan->addOption(2, QObject::tr("Full Time"));
channel.add(GRP_CPAP, chan = new Channel(RMS9_EPRLevel = 0xe202, SETTING, SESSION,
"EPRLevel", QObject::tr("EPR Level"),
QObject::tr("Exhale Pressure Relief Level"),
QObject::tr("EPR Level"),
"", DEFAULT, Qt::blue));
chan->addOption(0, QObject::tr("0cmH2O"));
chan->addOption(1, QObject::tr("1cmH2O"));
chan->addOption(2, QObject::tr("2cmH2O"));
chan->addOption(3, QObject::tr("3cmH2O"));
chan->addOption(4, QObject::tr("Patient"));
}
////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -328,7 +328,7 @@ protected:
/*! \class ResmedLoader
\brief Importer for ResMed S9 Data
*/
class ResmedLoader : public MachineLoader
class ResmedLoader : public CPAPLoader
{
friend class ResmedImport;
friend class ResmedImportStage2;
@ -377,10 +377,20 @@ class ResmedLoader : public MachineLoader
bool LoadPLD(Session *sess, const QString & path);
virtual MachineInfo newInfo() {
return MachineInfo(MT_CPAP, resmed_class_name, QObject::tr("ResMed"), QString(), QString(), QString(), QObject::tr("S9"), QDateTime::currentDateTime(), resmed_data_version);
return MachineInfo(MT_CPAP, 0, resmed_class_name, QObject::tr("ResMed"), QString(), QString(), QString(), QObject::tr("S9"), QDateTime::currentDateTime(), resmed_data_version);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Now for some CPAPLoader overrides
////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual QString PresReliefLabel() { return QObject::tr("EPR: "); }
virtual ChannelID PresReliefMode();
virtual ChannelID PresReliefLevel();
////////////////////////////////////////////////////////////////////////////////////////////////////////////
protected:
void ParseSTR(Machine *mach, QStringList strfiles);

View File

@ -36,7 +36,7 @@ class SomnoposeLoader : public MachineLoader
virtual const QString &loaderName() { return somnopose_class_name; }
virtual MachineInfo newInfo() {
return MachineInfo(MT_POSITION, somnopose_class_name, QObject::tr("Somnopose"), QString(), QString(), QString(), QObject::tr("Somnopose Software"), QDateTime::currentDateTime(), somnopose_data_version);
return MachineInfo(MT_POSITION, 0, somnopose_class_name, QObject::tr("Somnopose"), QString(), QString(), QString(), QObject::tr("Somnopose Software"), QDateTime::currentDateTime(), somnopose_data_version);
}

View File

@ -0,0 +1,556 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
*
* SleepLib (DeVilbiss) Weinmann Loader Implementation
* Notes: Weinmann requires the SmartLink attachment to access this data.
*
* Copyright (c) 2011-2014 Mark Watkins <jedimark@users.sourceforge.net>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of the Linux
* distribution for more details. */
#include <QDir>
#include <QFile>
#include <QProgressBar>
#include <QDomDocument>
#include <QDomElement>
#include <QDomNode>
#include "weinmann_loader.h"
extern QProgressBar *qprogress;
Weinmann::Weinmann(MachineID id)
: CPAP(id)
{
}
Weinmann::~Weinmann()
{
}
WeinmannLoader::WeinmannLoader()
{
m_buffer = nullptr;
m_type = MT_CPAP;
}
WeinmannLoader::~WeinmannLoader()
{
}
bool WeinmannLoader::Detect(const QString & givenpath)
{
QDir dir(givenpath);
if (!dir.exists()) {
return false;
}
// Weinman has a...
if (!dir.cd("SOMNOsoft2")) {
return false;
}
// Check for the settings file inside the .. folder
if (!dir.exists("WM_DATA.TDF")) {
return false;
}
return true;
}
int WeinmannLoader::ParseIndex(QFile & wmdata)
{
QByteArray xml;
do {
xml += wmdata.readLine(250);
} while (!wmdata.atEnd());
QDomDocument index_xml("weinmann");
index_xml.setContent(xml);
QDomElement docElem = index_xml.documentElement();
QDomNode n = docElem.firstChild();
index.clear();
while (!n.isNull()) {
QDomElement e = n.toElement();
if (!e.isNull()) {
bool ok;
int val = e.attribute("val").toInt(&ok);
if (ok) {
index[e.attribute("name")] = val;
qDebug() << e.attribute("name") << "=" << hex << val;
}
}
n = n.nextSibling();
}
return index.size();
}
const QString DayComplianceCount = "DayComplianceCount";
const QString CompOffset = "DayComplianceOffset";
const QString FlowOffset = "TID_Flow_Offset";
const QString StatusOffset = "TID_Status_Offset";
const QString PresOffset = "TID_P_Offset";
const QString AMVOffset = "TID_AMV_Offset";
const QString EventsOffset = "TID_Events_Offset";
void HighPass(char * data, int samples, float cutoff, float dt)
{
float Y[samples];
for (int i=0; i < samples; ++i) Y[i] = 0.0f;
Y[0] = ((unsigned char *)data)[0] ;
float RC = 1.0 / (cutoff * 2 * 3.1415926);
float alpha = RC / (RC + dt);
for (int i=1; i < samples; ++i) {
float x = ((unsigned char *)data)[i] ;
float x1 = ((unsigned char *)data)[i-1] ;
Y[i] = alpha * (Y[i-1] + x - x1);
}
for (int i=0; i< samples; ++i) {
data[i] = Y[i];
}
}
int WeinmannLoader::Open(QString path)
{
QString newpath;
path = path.replace("\\", "/");
QString dirtag = "SOMNOsoft2";
if (path.endsWith("/" + dirtag)) {
return -1;
} else {
newpath = path + "/" + dirtag;
}
QFile wmdata(newpath + "/WM_DATA.TDF");
if (!wmdata.open(QFile::ReadOnly)) {
return -1;
}
int res = ParseIndex(wmdata);
if (res < 0) return -1;
MachineInfo info = newInfo();
info.serial = "141819";
Machine * mach = CreateMachine(info);
//////////////////////////////////////////////////////////////////////
// Read Day Compliance Information....
//////////////////////////////////////////////////////////////////////
int comp_start = index[CompOffset];
int comp_end = index[FlowOffset];
int comp_size = comp_end - comp_start;
unsigned char comp[comp_size];
memset((char *)comp, 0, comp_size);
wmdata.seek(comp_start);
wmdata.read((char *)comp, comp_size);
unsigned char * p = comp;
QDateTime dt_epoch(QDate(2000,1,1), QTime(0,0,0));
int epoch = dt_epoch.toTime_t();
epoch = 0;
float flow_sample_duration = 1000.0 / 5;
float pressure_sample_duration = 1000.0 / 2;
float amv_sample_duration = 200 * 10;
int c = index[DayComplianceCount];
for (int i=0; i < 5; i++) {
int year = QString().sprintf("%02i%02i", p[0], p[1]).toInt();
int month = p[2];
int day = p[3];
int hour = p[5];
int minute = p[6];
int second = p[7];
QDateTime date = QDateTime(QDate(year,month,day), QTime(hour,minute,second));
quint32 ts = date.toTime_t();
if (mach->SessionExists(ts)) continue;
Session * sess = new Session(mach, ts);
// Flow Waveform
quint32 fs = p[8] | p[9] << 8 | p[10] << 16 | p[11] << 24;
quint32 fl = p[0x44] | p[0x45] << 8 | p[0x46] << 16 | p[0x47] << 24;
// Status
quint32 ss = p[12] | p[13] << 8 | p[14] << 16 | p[15] << 24;
quint32 sl = p[0x48] | p[0x49] << 8 | p[0x4a] << 16 | p[0x4b] << 24;
// Pressure
quint32 ps = p[16] | p[17] << 8 | p[18] << 16 | p[19] << 24;
quint32 pl = p[0x4c] | p[0x4d] << 8 | p[0x4e] << 16 | p[0x4f] << 24;
// AMV
quint32 ms = p[20] | p[21] << 8 | p[22] << 16 | p[23] << 24;
quint32 ml = p[0x50] | p[0x51] << 8 | p[0x52] << 16 | p[0x53] << 24;
// Events
quint32 es = p[24] | p[25] << 8 | p[26] << 16 | p[27] << 24;
quint32 er = p[0x54] | p[0x55] << 8 | p[0x56] << 16 | p[0x57] << 24; // number of records
compinfo.append(CompInfo(sess, date, fs, fl, ss, sl, ps, pl, ms, ml, es, er));
int dur = fl / 5;
sess->really_set_first(qint64(ts) * 1000L);
sess->really_set_last(qint64(ts+dur) * 1000L);
sessions[ts] = sess;
qDebug() << date << ts << dur << QString().sprintf("%02i:%02i:%02i", dur / 3600, dur/60 % 60, dur % 60);
p += 0xd6;
}
//////////////////////////////////////////////////////////////////////
// Read Flow Waveform....
//////////////////////////////////////////////////////////////////////
int flowstart = index[FlowOffset];
int flowend = index[StatusOffset];
wmdata.seek(flowstart);
int flowsize = flowend - flowstart;
char data[flowsize];
memset((char *)data, 0, flowsize);
wmdata.read((char *)data, flowsize);
float dt = 1.0 / (1000.0 / flow_sample_duration); // samples per second
// Centre Waveform using High Pass Filter
HighPass(data, flowsize, 0.6, dt);
//////////////////////////////////////////////////////////////////////
// Read Status....
//////////////////////////////////////////////////////////////////////
int st_start = index[StatusOffset];
int st_end = index[PresOffset];
int st_size = st_end - st_start;
char st[st_size];
memset(st, 0, st_size);
wmdata.seek(st_start);
wmdata.read(st, st_size);
//////////////////////////////////////////////////////////////////////
// Read Mask Pressure....
//////////////////////////////////////////////////////////////////////
int pr_start = index[PresOffset];
int pr_end = index[AMVOffset];
int pr_size = pr_end - pr_start;
char pres[pr_size];
memset(pres, 0, pr_size);
wmdata.seek(pr_start);
wmdata.read(pres, pr_size);
//////////////////////////////////////////////////////////////////////
// Read AMV....
//////////////////////////////////////////////////////////////////////
int mv_start = index[AMVOffset];
int mv_end = index[EventsOffset];
int mv_size = mv_end - mv_start;
char mv[mv_size];
memset(mv, 0, mv_size);
wmdata.seek(mv_start);
wmdata.read(mv, mv_size);
//////////////////////////////////////////////////////////////////////
// Read Events....
//////////////////////////////////////////////////////////////////////
int ev_start = index[EventsOffset];
int ev_end = wmdata.size();
int ev_size = ev_end - ev_start;
unsigned char ev[ev_size];
memset((char *) ev, 0, ev_size);
wmdata.seek(ev_start);
wmdata.read((char *) ev, ev_size);
//////////////////////////////////////////////////////////////////////
// Process sessions
//////////////////////////////////////////////////////////////////////
for (int i=0; i< compinfo.size(); ++i) {
const CompInfo & ci = compinfo.at(i);
Session * sess = ci.session;
qint64 ti = sess->first();
EventList * flow = sess->AddEventList(CPAP_FlowRate, EVL_Waveform, 1.0, 0.0, 0.0, 0.0, flow_sample_duration);
flow->AddWaveform(ti, &data[ci.flow_start], ci.flow_size, (ci.flow_size/(1000.0/flow_sample_duration)) * 1000.0);
EventList * PR = sess->AddEventList(CPAP_MaskPressure, EVL_Waveform, 0.1f, 0.0, 0.0, 0.0, pressure_sample_duration);
PR->AddWaveform(ti, (unsigned char *)&pres[ci.pres_start], ci.pres_size, (ci.pres_size/(1000.0/pressure_sample_duration)) * 1000.0);
// Weinmann's MV graph is pretty dodgy... commenting this out and using my flow calced ones instead (the code below is mapped to snore for comparison purposes)
//EventList * MV = sess->AddEventList(CPAP_Snore, EVL_Waveform, 1.0f, 0.0, 0.0, 0.0, amv_sample_duration);
//MV->AddWaveform(ti, (unsigned char *)&mv[ci.amv_start], ci.amv_size, (ci.amv_size/(1000/amv_sample_duration)) * 1000L);
EventList * L = sess->AddEventList(CPAP_Leak, EVL_Event);
EventList * S = sess->AddEventList(CPAP_Snore, EVL_Event);
EventList * OA = sess->AddEventList(CPAP_Obstructive, EVL_Event);
EventList * A = sess->AddEventList(CPAP_Apnea, EVL_Event);
EventList * H = sess->AddEventList(CPAP_Hypopnea, EVL_Event);
EventList * FL = sess->AddEventList(CPAP_FlowLimit, EVL_Event);
EventList * VS = sess->AddEventList(CPAP_VSnore, EVL_Event);
quint64 tt = ti;
quint64 step = sess->length() / ci.event_recs;
unsigned char *p = &ev[ci.event_start];
for (quint32 j=0; j < ci.event_recs; ++j) {
QDate evdate = ci.time.date();
QTime evtime(p[1], p[2], p[3]);
if (evtime < ci.time.time()) {
evdate = evdate.addDays(1);
}
quint64 ts = QDateTime(evdate, evtime).toMSecsSinceEpoch();
// I think p[0] is amount of flow restriction..
unsigned char evcode = p[0];
EventStoreType data = p[4] | p[5] << 8;
if (evcode == '@') {
OA->AddEvent(ts,data/10.0);
} else if (evcode =='A') {
A->AddEvent(ts,data/10.0);
} else if (evcode == 'F') {
FL->AddEvent(ts,data/10.0);
} else if (evcode == '*') {
H->AddEvent(ts,data/10.0);
}
/* switch (evcode) {
case 0x03:
break;
case 0x04:
break;
case 0x08:
break;
case 0x09:
break;
case 0x0a:
break;
case 0x0b:
break;
case 0x0c:
break;
case 0x10:
break;
case 0x11:
break;
case 0x12:
break;
case 0x13:
S->AddEvent(ts, data);
break;
case 0x22:
// VS->AddEvent(ts, data/10.0);
break;
case 0x28:
VS->AddEvent(ts, data/10.0);
break;
case 'F':
FL->AddEvent(ts, data/10.0);
break;
case '@':
OA->AddEvent(ts, data/10.0);
break;
case '\'':
//A->AddEvent(ts, data/10.0);
break;
case 'a':
A->AddEvent(ts, data/10.0);
break;
case 'A':
// A->AddEvent(ts, data/10.0);
break;
case '*':
H->AddEvent(ts, data/10.0);
break;
case 'd':
break;
case 0x91:
break;
case 0x96:
break;
case 0x84:
break;
default:
qDebug() << (int)evcode << endl;
}*/
// S->AddEvent(ts, p[5]);
// p[5] == 0 corresponds to peak events
// p[5] == 1 corresponds to hypopnea/bstructive events
//if (p[5] == 2) OA->AddEvent(ts, p[4]);
// This is ugggggly...
tt += step;
p += 6;
}
sess->UpdateSummaries();
mach->AddSession(sess);
}
return 1;
/*
// Center the waveform
HighPass(data, flowsize, 0.6, dt);
EventList * flow = sess->AddEventList(CPAP_FlowRate, EVL_Waveform, 1.0, 0.0, 0.0, 0.0, sample_duration);
flow->AddWaveform(tt, (char *)data, flowsize, (flowsize/(1000/sample_duration)) * 1000L);
qint64 ti = tt;
for (int i=0; i < pr_size; ++i) {
EventStoreType c = ((unsigned char *)pres)[i];
PR->AddEvent(ti, c);
ti += sample_duration * 2.5; //46296296296296;
}
// Their calcs is uglier than mine!
EventList * MV = sess->AddEventList(CPAP_Snore, EVL_Event, 1.0);
ti = tt;
for (int i=0; i < mv_size; ++i) {
EventStoreType c = ((unsigned char *)mv)[i];
MV->AddEvent(ti, c);
ti += sample_duration * 9;
}
// Their calcs is uglier than mine!
EventList * ST = sess->AddEventList(CPAP_Leak, EVL_Event, 1.0);
int st_start = index[StatusOffset];
int st_end = index[PresOffset];
int st_size = st_end - st_start;
char st[st_size];
memset(st, 0, st_size);
wmdata.seek(st_start);
wmdata.read(st, st_size);
ti = tt;
for (int i=0; i < st_size; ++i) {
EventStoreType c = ((unsigned char *)st)[i];
// if (c & 0x80) {
ST->AddEvent(ti, c & 0x10);
// }
ti += sample_duration*4; // *9
}
// EventList * LEAK = sess->AddEventList(CPAP_Leak, EVL_Event);
// EventList * SNORE = sess->AddEventList(CPAP_Snore, EVL_Event);
// int ev_start = index[EventsOffset];
// int ev_end = wmdata.size();
// int ev_size = ev_end - ev_start;
// int recs = ev_size / 0x12;
// unsigned char ev[ev_size];
// memset((char *) ev, 0, ev_size);
// wmdata.seek(ev_start);
// wmdata.read((char *) ev, ev_size);
sess->really_set_last(flow->last());
// int pos = 0;
// ti = tt;
// // 6 byte repeating structure.. No Leaks :(
// do {
// //EventStoreType c = ((unsigned char*)ev)[pos+0]; // TV?
// //c = ((unsigned char*)ev)[pos+6]; // MV?
// EventStoreType c = ((EventStoreType*)ev)[pos+0];
// LEAK->AddEvent(ti, c);
// SNORE->AddEvent(ti, ((unsigned char*)ev)[pos+2]);
// pos += 0x6;
// ti += 30000;
// if (ti > sess->last())
// break;
// } while (pos < (ev_size - 0x12));
m->AddSession(sess);
sess->UpdateSummaries();
return 1;*/
}
bool weinmann_initialized = false;
void WeinmannLoader::Register()
{
if (weinmann_initialized) { return; }
qDebug() << "Registering WeinmannLoader";
RegisterLoader(new WeinmannLoader());
//InitModelMap();
weinmann_initialized = true;
using namespace schema;
Channel * chan = nullptr;
// channel.add(GRP_CPAP, chan = new Channel(INTP_SmartFlex = 0x1165, SETTING, SESSION,
// "INTPSmartFlex", QObject::tr("SmartFlex"),
// QObject::tr("Weinmann pressure relief setting."),
// QObject::tr("SmartFlex"),
// "", DEFAULT, Qt::green));
// chan->addOption(1, STR_TR_None);
}

View File

@ -0,0 +1,142 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
*
* Weiman Loader Header
*
* Copyright (c) 2011-2014 Mark Watkins <jedimark@users.sourceforge.net>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of the Linux
* distribution for more details. */
#ifndef WEINMANN_LOADER_H
#define WEINMANN_LOADER_H
#include "SleepLib/machine.h" // Base class: MachineLoader
#include "SleepLib/machine_loader.h"
#include "SleepLib/profiles.h"
//********************************************************************************************
/// IMPORTANT!!!
//********************************************************************************************
// Please INCREMENT the following value when making changes to this loaders implementation.
//
const int weinmann_data_version = 3;
//
//********************************************************************************************
/*! \class Weinmann
\brief Weinmann customized machine object
*/
class Weinmann: public CPAP
{
public:
Weinmann(MachineID id = 0);
virtual ~Weinmann();
};
struct CompInfo
{
CompInfo() {
session = nullptr;
flow_start = 0; flow_size = 0;
stat_start = 0; stat_size = 0;
pres_start = 0; pres_size = 0;
amv_start = 0; amv_size =0;
event_start = 0; event_recs = 0;
}
CompInfo(const CompInfo & copy) {
session = copy.session;
time = copy.time;
flow_start = copy.flow_start;
flow_size= copy.flow_size;
stat_start = copy.flow_start;
stat_size= copy.flow_size;
pres_start = copy.pres_start;
pres_size = copy.pres_size;
amv_start = copy.amv_start;
amv_size = copy.amv_size;
event_start = copy.event_start;
event_recs = copy.event_recs;
}
CompInfo(Session * sess, QDateTime dt, quint32 fs, quint32 fl, quint32 ss, quint32 sl,quint32 ps, quint32 pl, quint32 ms, quint32 ml, quint32 es, quint32 er):
session(sess), time(dt),
flow_start(fs), flow_size(fl),
stat_start(ss), stat_size(sl),
pres_start(ps), pres_size(pl),
amv_start(ms), amv_size(ml),
event_start(es), event_recs(er) {}
Session * session;
QDateTime time;
quint32 flow_start;
quint32 flow_size;
quint32 stat_start;
quint32 stat_size;
quint32 pres_start;
quint32 pres_size;
quint32 amv_start;
quint32 amv_size;
quint32 event_start;
quint32 event_recs;
};
const QString weinmann_class_name = STR_MACH_Weinmann;
/*! \class WeinmannLoader
\brief Loader for Weinmann CPAP data
This is only relatively recent addition and still needs more work
*/
class WeinmannLoader : public CPAPLoader
{
public:
WeinmannLoader();
virtual ~WeinmannLoader();
//! \brief Detect if the given path contains a valid Folder structure
virtual bool Detect(const QString & path);
//! \brief Scans path for Weinmann data signature, and Loads any new data
virtual int Open(QString path);
//! \brief Returns SleepLib database version of this Weinmann loader
virtual int Version() { return weinmann_data_version; }
//! \brief Returns the machine loader name of this class
virtual const QString &loaderName() { return weinmann_class_name; }
int ParseIndex(QFile & wmdata);
//! \brief Creates a machine object, indexed by serial number
// Machine *CreateMachine(QString serial);
//! \brief Registers this MachineLoader with the master list, so Weinmann data can load
static void Register();
virtual MachineInfo newInfo() {
return MachineInfo(MT_CPAP, 0, weinmann_class_name, QObject::tr("Weinmann"), QString(), QString(), QString(), QObject::tr("Weinmann"), QDateTime::currentDateTime(), weinmann_data_version);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Now for some CPAPLoader overrides
////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual QString presRelType() { return QObject::tr("Unknown"); } // might not need this one
virtual ChannelID presRelSet() { return NoChannel; }
virtual ChannelID presRelLevel() { return NoChannel; }
////////////////////////////////////////////////////////////////////////////////////////////////////////////
protected:
QHash<QString, int> index;
QList<CompInfo> compinfo;
QMap<SessionID, Session *> sessions;
QString last;
unsigned char *m_buffer;
};
#endif // WEINMANN_LOADER_H

View File

@ -37,7 +37,7 @@ class ZEOLoader : public MachineLoader
//Machine *CreateMachine();
virtual MachineInfo newInfo() {
return MachineInfo(MT_SLEEPSTAGE, zeo_class_name, QObject::tr("Zeo"), QString(), QString(), QString(), QObject::tr("Personal Sleep Coach"), QDateTime::currentDateTime(), zeo_data_version);
return MachineInfo(MT_SLEEPSTAGE, 0, zeo_class_name, QObject::tr("Zeo"), QString(), QString(), QString(), QObject::tr("Personal Sleep Coach"), QDateTime::currentDateTime(), zeo_data_version);
}
protected:

View File

@ -45,6 +45,7 @@ Machine::Machine(MachineID id)
m_id = temp;
} else { m_id = id; }
m_loader = nullptr;
// qDebug() << "Create Machine: " << hex << m_id; //%lx",m_id);
m_type = MT_UNKNOWN;
@ -363,6 +364,19 @@ bool Machine::Purge(int secret)
return true;
}
void Machine::setLoaderName(QString value)
{
info.loadername = value;
m_loader = GetLoader(value);
}
void Machine::setInfo(MachineInfo inf)
{
info = inf;
m_loader = GetLoader(inf.loadername);
}
//const quint32 channel_version=1;
const QString Machine::getDataPath()
@ -701,44 +715,3 @@ PositionSensor::PositionSensor(MachineID id): Machine(id)
PositionSensor::~PositionSensor()
{
}
ChannelID NoChannel, SESSION_ENABLED, CPAP_SummaryOnly;
ChannelID CPAP_IPAP, CPAP_IPAPLo, CPAP_IPAPHi, CPAP_EPAP, CPAP_EPAPLo, CPAP_EPAPHi, CPAP_Pressure,
CPAP_PS, CPAP_Mode, CPAP_AHI,
CPAP_PressureMin, CPAP_PressureMax, CPAP_Ramp, CPAP_RampTime, CPAP_RampPressure, CPAP_Obstructive,
CPAP_Hypopnea,
CPAP_ClearAirway, CPAP_Apnea, CPAP_CSR, CPAP_LeakFlag, CPAP_ExP, CPAP_NRI, CPAP_VSnore,
CPAP_VSnore2,
CPAP_RERA, CPAP_PressurePulse, CPAP_FlowLimit, CPAP_SensAwake, CPAP_FlowRate, CPAP_MaskPressure,
CPAP_MaskPressureHi,
CPAP_RespEvent, CPAP_Snore, CPAP_MinuteVent, CPAP_RespRate, CPAP_TidalVolume, CPAP_PTB, CPAP_Leak,
CPAP_LeakMedian, CPAP_LeakTotal, CPAP_MaxLeak, CPAP_FLG, CPAP_IE, CPAP_Te, CPAP_Ti, CPAP_TgMV,
CPAP_UserFlag1, CPAP_UserFlag2, CPAP_UserFlag3, CPAP_BrokenSummary, CPAP_BrokenWaveform, CPAP_RDI,
CPAP_PresReliefSet, CPAP_PresReliefMode, CPAP_PresReliefType, CPAP_PSMin, CPAP_PSMax, CPAP_Test1,
CPAP_Test2;
ChannelID RMS9_E01, RMS9_E02, RMS9_EPR, RMS9_EPRLevel, RMS9_SetPressure, RMS9_MaskOnTime;
ChannelID INTP_SmartFlex;
ChannelID INTELLIPAP_Unknown1, INTELLIPAP_Unknown2;
ChannelID PRS1_00, PRS1_01, PRS1_08, PRS1_0A, PRS1_0B, PRS1_0C, PRS1_0E, PRS1_0F, CPAP_LargeLeak, PRS1_12,
PRS1_FlexMode, PRS1_FlexSet, PRS1_HumidStatus, CPAP_HumidSetting, PRS1_SysLock,
PRS1_SysOneResistStat,
PRS1_SysOneResistSet, PRS1_HoseDiam, PRS1_AutoOn, PRS1_AutoOff, PRS1_MaskAlert, PRS1_ShowAHI;
ChannelID OXI_Pulse, OXI_SPO2, OXI_PulseChange, OXI_SPO2Drop, OXI_Plethy;
ChannelID Journal_Notes, Journal_Weight, Journal_BMI, Journal_ZombieMeter, Bookmark_Start,
Bookmark_End, Bookmark_Notes;
ChannelID ZEO_SleepStage, ZEO_ZQ, ZEO_TotalZ, ZEO_TimeToZ, ZEO_TimeInWake, ZEO_TimeInREM,
ZEO_TimeInLight, ZEO_TimeInDeep, ZEO_Awakenings,
ZEO_AlarmReason, ZEO_SnoozeTime, ZEO_WakeTone, ZEO_WakeWindow, ZEO_AlarmType, ZEO_MorningFeel,
ZEO_FirmwareVersion,
ZEO_FirstAlarmRing, ZEO_LastAlarmRing, ZEO_FirstSnoozeTime, ZEO_LastSnoozeTime, ZEO_SetAlarmTime,
ZEO_RiseTime;
ChannelID POS_Orientation, POS_Inclination;

View File

@ -68,7 +68,7 @@ public:
virtual void run() {}
};
class MachineLaoder;
class MachineLoader;
/*! \class Machine
\brief This Machine class is the Heart of SleepyLib, representing a single Machine and holding it's data
@ -182,20 +182,26 @@ class Machine
inline QString modelnumber() const { return info.modelnumber; }
inline QString serial() const { return info.serial; }
inline QString series() const { return info.series; }
inline quint32 cap() const { return info.cap; }
inline int version() const { return info.version; }
inline QDateTime lastImported() const { return info.lastimported; }
inline void setModel(QString value) { info.model = value; }
inline void setSerial(QString value) { info.serial = value; }
inline void setType(MachineType type) { info.type = type; }
inline void setLoaderName(QString value) { info.loadername = value; }
inline void setCap(quint32 value) { info.cap = value; }
void setLoaderName(QString value);
MachineLoader * loader() { return m_loader; }
// much more simpler multithreading...
void queTask(ImportTask * task);
void runTasks();
QMutex saveMutex;
void setInfo(MachineInfo inf) { info = inf; }
void setInfo(MachineInfo inf);
const MachineInfo getInfo() { return info; }
protected:
@ -206,6 +212,8 @@ class Machine
MachineType m_type;
QString m_path;
MachineLoader * m_loader;
bool changed;
bool firstsession;
int m_totaltasks;
@ -226,6 +234,7 @@ class CPAP: public Machine
public:
CPAP(MachineID id = 0);
virtual ~CPAP();
};

View File

@ -0,0 +1,53 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
*
* SleepLib Common Machine Stuff
*
* Copyright (c) 2011-2014 Mark Watkins <jedimark@users.sourceforge.net>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of the Linux
* distribution for more details. */
#include "machine_common.h"
ChannelID NoChannel, SESSION_ENABLED, CPAP_SummaryOnly;
ChannelID CPAP_IPAP, CPAP_IPAPLo, CPAP_IPAPHi, CPAP_EPAP, CPAP_EPAPLo, CPAP_EPAPHi, CPAP_Pressure,
CPAP_PS, CPAP_Mode, CPAP_AHI,
CPAP_PressureMin, CPAP_PressureMax, CPAP_Ramp, CPAP_RampTime, CPAP_RampPressure, CPAP_Obstructive,
CPAP_Hypopnea,
CPAP_ClearAirway, CPAP_Apnea, CPAP_CSR, CPAP_LeakFlag, CPAP_ExP, CPAP_NRI, CPAP_VSnore,
CPAP_VSnore2,
CPAP_RERA, CPAP_PressurePulse, CPAP_FlowLimit, CPAP_SensAwake, CPAP_FlowRate, CPAP_MaskPressure,
CPAP_MaskPressureHi,
CPAP_RespEvent, CPAP_Snore, CPAP_MinuteVent, CPAP_RespRate, CPAP_TidalVolume, CPAP_PTB, CPAP_Leak,
CPAP_LeakMedian, CPAP_LeakTotal, CPAP_MaxLeak, CPAP_FLG, CPAP_IE, CPAP_Te, CPAP_Ti, CPAP_TgMV,
CPAP_UserFlag1, CPAP_UserFlag2, CPAP_UserFlag3, CPAP_BrokenSummary, CPAP_BrokenWaveform, CPAP_RDI,
CPAP_PresReliefMode, CPAP_PresReliefLevel, CPAP_PSMin, CPAP_PSMax, CPAP_Test1,
CPAP_Test2, CPAP_HumidSetting;
ChannelID RMS9_E01, RMS9_E02, RMS9_SetPressure, RMS9_MaskOnTime;
ChannelID INTELLIPAP_Unknown1, INTELLIPAP_Unknown2;
ChannelID PRS1_00, PRS1_01, PRS1_08, PRS1_0A, PRS1_0B, PRS1_0C, PRS1_0E, PRS1_0F, CPAP_LargeLeak, PRS1_12,
PRS1_FlexMode, PRS1_FlexLevel, PRS1_HumidStatus, PRS1_HumitSetting, PRS1_SysLock,
PRS1_SysOneResistStat,
PRS1_SysOneResistSet, PRS1_HoseDiam, PRS1_AutoOn, PRS1_AutoOff, PRS1_MaskAlert, PRS1_ShowAHI;
ChannelID OXI_Pulse, OXI_SPO2, OXI_PulseChange, OXI_SPO2Drop, OXI_Plethy;
ChannelID Journal_Notes, Journal_Weight, Journal_BMI, Journal_ZombieMeter, Bookmark_Start,
Bookmark_End, Bookmark_Notes;
ChannelID ZEO_SleepStage, ZEO_ZQ, ZEO_TotalZ, ZEO_TimeToZ, ZEO_TimeInWake, ZEO_TimeInREM,
ZEO_TimeInLight, ZEO_TimeInDeep, ZEO_Awakenings,
ZEO_AlarmReason, ZEO_SnoozeTime, ZEO_WakeTone, ZEO_WakeWindow, ZEO_AlarmType, ZEO_MorningFeel,
ZEO_FirmwareVersion,
ZEO_FirstAlarmRing, ZEO_LastAlarmRing, ZEO_FirstSnoozeTime, ZEO_LastSnoozeTime, ZEO_SetAlarmTime,
ZEO_RiseTime;
ChannelID POS_Orientation, POS_Inclination;

View File

@ -1,7 +1,7 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
*
* SleepLib Machine Loader Class Header
* SleepLib Common Machine Header
*
* Copyright (c) 2011-2014 Mark Watkins <jedimark@users.sourceforge.net>
*
@ -54,12 +54,31 @@ enum SummaryType { ST_CNT, ST_SUM, ST_AVG, ST_WAVG, ST_PERC, ST_90P, ST_MIN, ST_
enum MachineType { MT_UNKNOWN = 0, MT_CPAP, MT_OXIMETER, MT_SLEEPSTAGE, MT_JOURNAL, MT_POSITION };
//void InitMapsWithoutAwesomeInitializerLists();
// PAP Device Capabilities
const quint32 CAP_Fixed = 0x0000001; // Constant PAP
const quint32 CAP_Variable = 0x0000002; // Variable Base (EPAP) pressure
const quint32 CAP_BiLevel = 0x0000004; // Fixed Pressure Support
const quint32 CAP_Variable_PS = 0x0000008; // Pressure support can range
const quint32 CAP_PressureRelief = 0x0000010; // Device has a pressure relief mode (EPR; Flex; SmartFlex)
const quint32 CAP_Humidification = 0x0000020; // Device has a humidifier attached
// PAP Mode Capabilities
const quint32 PAP_CPAP = 0x0001; // Fixed Pressure PAP
const quint32 PAP_APAP = 0x0002; // Auto Ranging PAP
const quint32 PAP_BiLevelFixed = 0x0004; // Fixed BiLevel
const quint32 PAP_BiLevelAutoFixed = 0x0008; // Auto BiLevel with Fixed EPAP
const quint32 PAP_BiLevelAutoVariable = 0x0010; // Auto BiLevel with full ranging capabilities
const quint32 PAP_ASV_Fixed = 0x0020; // ASV with fixed EPAP
const quint32 PAP_ASV_Variable = 0x0040; // ASV with full ranging capabilities
const quint32 PAP_SplitNight = 0x8000; // Split night capabilities
/*! \enum CPAPMode
\brief CPAP Machines mode of operation
*/
enum CPAPMode { //:short
MODE_UNKNOWN = 0, MODE_CPAP, MODE_APAP, MODE_BILEVEL_FIXED, MODE_BILEVEL_AUTO_FIXED_PS, MODE_ASV, MODE_ASV_VARIABLE_EPAP
MODE_UNKNOWN = 0, MODE_CPAP, MODE_APAP, MODE_BILEVEL_FIXED, MODE_BILEVEL_AUTO_FIXED_PS, MODE_BILEVEL_AUTO_VARIABLE_PS, MODE_ASV, MODE_ASV_VARIABLE_EPAP
};
/*! \enum PRTypes
@ -68,13 +87,13 @@ enum CPAPMode { //:short
enum PRTypes { //:short
PR_UNKNOWN = 0, PR_NONE, PR_CFLEX, PR_CFLEXPLUS, PR_AFLEX, PR_BIFLEX, PR_EPR, PR_SMARTFLEX, PR_EASYBREATHE, PR_SENSAWAKE
};
enum PRModes { //:short
enum PRTimeModes { //:short
PM_UNKNOWN = 0, PM_RampOnly, PM_FullTime
};
struct MachineInfo {
MachineInfo() { type = MT_UNKNOWN; version = 0; }
MachineInfo() { type = MT_UNKNOWN; version = 0; cap=0; }
MachineInfo(const MachineInfo & copy) {
type = copy.type;
loadername = copy.loadername;
@ -85,12 +104,14 @@ struct MachineInfo {
series = copy.series;
version = copy.version;
lastimported = copy.lastimported;
cap = copy.cap;
}
MachineInfo(MachineType type, QString loadername, QString brand, QString model, QString modelnumber, QString serial, QString series, QDateTime lastimported, int version) :
type(type), loadername(loadername), brand(brand), model(model), modelnumber(modelnumber), serial(serial), series(series), lastimported(lastimported), version(version) {}
MachineInfo(MachineType type, quint32 cap, QString loadername, QString brand, QString model, QString modelnumber, QString serial, QString series, QDateTime lastimported, int version) :
type(type), cap(cap), loadername(loadername), brand(brand), model(model), modelnumber(modelnumber), serial(serial), series(series), lastimported(lastimported), version(version) {}
MachineType type;
quint32 cap;
QString loadername;
QString brand;
QString model;
@ -128,13 +149,12 @@ extern ChannelID CPAP_IPAP, CPAP_IPAPLo, CPAP_IPAPHi, CPAP_EPAP, CPAP_EPAPLo, CP
CPAP_RespEvent, CPAP_Snore, CPAP_MinuteVent, CPAP_RespRate, CPAP_TidalVolume, CPAP_PTB, CPAP_Leak,
CPAP_LeakMedian, CPAP_LeakTotal, CPAP_MaxLeak, CPAP_FLG, CPAP_IE, CPAP_Te, CPAP_Ti, CPAP_TgMV,
CPAP_UserFlag1, CPAP_UserFlag2, CPAP_UserFlag3, CPAP_BrokenSummary, CPAP_BrokenWaveform, CPAP_RDI,
CPAP_PresReliefSet, CPAP_PresReliefMode, CPAP_PresReliefType, CPAP_Test1, CPAP_Test2;
CPAP_PresReliefMode, CPAP_PresReliefLevel, CPAP_Test1, CPAP_Test2;
extern ChannelID RMS9_E01, RMS9_E02, RMS9_EPR, RMS9_EPRLevel, RMS9_SetPressure, RMS9_MaskOnTime;
extern ChannelID INTP_SmartFlex;
extern ChannelID RMS9_E01, RMS9_E02, RMS9_SetPressure, RMS9_MaskOnTime;
extern ChannelID PRS1_00, PRS1_01, PRS1_08, PRS1_0A, PRS1_0B, PRS1_0C, PRS1_0E, PRS1_0F, CPAP_LargeLeak,
PRS1_12,
PRS1_FlexMode, PRS1_FlexSet, PRS1_HumidStatus, CPAP_HumidSetting, PRS1_SysLock,
PRS1_FlexMode, PRS1_FlexLevel, PRS1_HumidStatus, PRS1_HumitSetting, CPAP_HumidSetting, PRS1_SysLock,
PRS1_SysOneResistStat,
PRS1_SysOneResistSet, PRS1_HoseDiam, PRS1_AutoOn, PRS1_AutoOff, PRS1_MaskAlert, PRS1_ShowAHI;

View File

@ -221,6 +221,26 @@ void MachineLoader::runTasks(bool threaded)
}
}
QList<ChannelID> CPAPLoader::eventFlags(Day * day)
{
Machine * mach = day->machine;
QList<ChannelID> list;
if (mach->loader() != this) {
qDebug() << "Trying to ask" << loaderName() << "for" << mach->loaderName() << "data";
return list;
}
list.push_back(CPAP_ClearAirway);
list.push_back(CPAP_Obstructive);
list.push_back(CPAP_Hypopnea);
list.push_back(CPAP_Apnea);
return list;
}
/*const QString machine_profile_name="MachineList.xml";
void MachineLoader::LoadMachineList()

View File

@ -59,15 +59,6 @@ class MachineLoader: public QObject
virtual const QString &loaderName() = 0;
inline MachineType type() { return m_type; }
// virtual bool openDevice() { return false; }
// virtual void closeDevice() {}
// virtual bool scanDevice(QString keyword="", quint16 vendor_id=0, quint16 product_id=0) {
// Q_UNUSED(keyword)
// Q_UNUSED(vendor_id)
// Q_UNUSED(product_id)
// return false;
// }
void queTask(ImportTask * task);
void addSession(Session * sess)
@ -77,7 +68,6 @@ class MachineLoader: public QObject
sessionMutex.unlock();
}
//! \brief Process Task list using all available threads.
void runTasks(bool threaded=true);
@ -96,16 +86,6 @@ class MachineLoader: public QObject
signals:
void updateProgress(int cnt, int total);
// void updateDisplay(MachineLoader *);
//protected slots:
// virtual void dataAvailable() {}
// virtual void resetImportTimeout() {}
// virtual void startImportTimeout() {}
//protected:
// virtual void killTimers(){}
// virtual void resetDevice(){}
protected:
//! \brief Contains a list of Machine records known by this loader
@ -130,6 +110,21 @@ signals:
};
class CPAPLoader:public MachineLoader
{
Q_OBJECT
public:
CPAPLoader() : MachineLoader() {}
virtual ~CPAPLoader() {}
virtual QList<ChannelID> eventFlags(Day * day);
virtual QString PresReliefLabel() { return QString(""); }
virtual ChannelID PresReliefMode() { return NoChannel; }
virtual ChannelID PresReliefLevel() { return NoChannel; }
};
struct ImportPath
{
ImportPath() {

View File

@ -218,7 +218,7 @@ bool Preferences::Open(QString filename)
if (!e.isNull()) {
QString name = e.tagName();
QString type = e.attribute("type").toLower();
QString value = e.text();;
QString value = e.text();
if (type == "double") {
double d;

View File

@ -686,7 +686,7 @@ int Profile::Import(QString path)
MachineLoader *GetLoader(QString name)
{
QList<MachineLoader *>loaders = GetLoaders(MT_CPAP);
QList<MachineLoader *>loaders = GetLoaders();
Q_FOREACH(MachineLoader * loader, loaders) {
if (loader->loaderName() == name) {
@ -848,7 +848,7 @@ Profile *Create(QString name)
p_profile->Set(STR_GEN_DataFolder, QString("{home}/Profiles/{") + QString(STR_UI_UserName) + QString("}"));
Machine *m = new Machine(0);
MachineInfo info(MT_JOURNAL, STR_MACH_Journal, "SleepyHead", STR_MACH_Journal, QString(), m->hexid(), QString(), QDateTime::currentDateTime(), 0);
MachineInfo info(MT_JOURNAL, 0, STR_MACH_Journal, "SleepyHead", STR_MACH_Journal, QString(), m->hexid(), QString(), QDateTime::currentDateTime(), 0);
m->setInfo(info);
p_profile->AddMachine(m);

View File

@ -392,9 +392,34 @@ void init()
schema::channel.add(GRP_CPAP, new Channel(CPAP_SummaryOnly = 0x1026, SETTING, SESSION,
"SummaryOnly", QObject::tr("Summary Only"),
QObject::tr("CPAP Session contains summary data onlyf"), QObject::tr("Summary Only"), STR_UNIT_Unknown,
QObject::tr("CPAP Session contains summary data only"), QObject::tr("Summary Only"), STR_UNIT_Unknown,
DEFAULT, Qt::black));
Channel *ch;
schema::channel.add(GRP_CPAP, ch = new Channel(CPAP_Mode = 0x1200, SETTING, SESSION,
"PAPMode", QObject::tr("PAP Mode"),
QObject::tr("PAP Mode"), QObject::tr("PAP_Mode"), STR_UNIT_Unknown,
LOOKUP, Qt::black));
ch->addOption(0, STR_TR_Unknown);
ch->addOption(1, STR_TR_CPAP);
ch->addOption(2, STR_TR_APAP);
ch->addOption(3, QObject::tr("Fixed Bi-Level"));
ch->addOption(4, QObject::tr("Auto Bi-Level (Fixed PS)"));
ch->addOption(5, QObject::tr("Auto Bi-Level (Variable PS)"));
ch->addOption(6, QObject::tr("ASV (Fixed EPAP)"));
ch->addOption(7, QObject::tr("ASV (Variable EPAP)"));
// <channel id="0x1200" class="setting" scope="!session" name="PAPMode" details="PAP Mode" label="PAP Mode" type="integer">
// <option id="0" value="CPAP"/>
// <option id="1" value="Auto"/>
// <option id="2" value="Fixed Bi-Level"/>
// <option id="3" value="Auto Bi-Level"/>
// <option id="4" value="ASV"/>
// <option id="5" value="ASV Auto EPAP"/>
// </channel>
NoChannel = 0;
// CPAP_IPAP=schema::channel["IPAP"].id();
@ -405,7 +430,7 @@ void init()
// CPAP_PS=schema::channel["PS"].id();
// CPAP_PSMin=schema::channel["PSMin"].id();
// CPAP_PSMax=schema::channel["PSMax"].id();
CPAP_Mode = schema::channel["PAPMode"].id();
// CPAP_Mode = schema::channel["PAPMode"].id();
CPAP_BrokenSummary = schema::channel["BrokenSummary"].id();
CPAP_BrokenWaveform = schema::channel["BrokenWaveform"].id();
// CPAP_PressureMin=schema::channel["PressureMin"].id();
@ -446,20 +471,12 @@ void init()
CPAP_Test1 = schema::channel["TestChan1"].id();
CPAP_Test2 = schema::channel["TestChan2"].id();
CPAP_PresReliefSet = schema::channel["PresRelSet"].id();
CPAP_PresReliefMode = schema::channel["PresRelMode"].id();
CPAP_PresReliefType = schema::channel["PresRelType"].id();
// CPAP_UserFlag1=schema::channel["UserFlag1"].id();
// CPAP_UserFlag2=schema::channel["UserFlag2"].id();
// CPAP_UserFlag3=schema::channel["UserFlag3"].id();
RMS9_E01 = schema::channel["RMS9_E01"].id();
RMS9_E02 = schema::channel["RMS9_E02"].id();
RMS9_EPR = schema::channel["EPR"].id();
RMS9_EPRLevel = schema::channel["EPRLevel"].id();
RMS9_SetPressure = schema::channel["SetPressure"].id();
PRS1_FlexMode = schema::channel["FlexMode"].id();
PRS1_FlexSet = schema::channel["FlexSet"].id();
RMS9_SetPressure = schema::channel["SetPressure"].id(); // TODO: this isn't needed anymore
PRS1_HumidStatus = schema::channel["HumidStat"].id();
CPAP_HumidSetting = schema::channel["HumidSet"].id();
PRS1_SysLock = schema::channel["SysLock"].id();

View File

@ -38,7 +38,7 @@ enum ChanType {
};
enum DataType {
DEFAULT = 0, INTEGER, BOOL, DOUBLE, STRING, RICHTEXT, DATE, TIME, DATETIME
DEFAULT = 0, INTEGER, BOOL, DOUBLE, STRING, RICHTEXT, DATE, TIME, DATETIME, LOOKUP
};
enum ScopeType {
GLOBAL = 0, MACHINE, DAY, SESSION

View File

@ -48,7 +48,7 @@ public:
virtual int Version()=0;
virtual const QString &loaderName()=0;
virtual MachineInfo newInfo() {
return MachineInfo(MT_OXIMETER, "", QString(), QString(), QString(), QString(), "Generic", QDateTime::currentDateTime(), 0);
return MachineInfo(MT_OXIMETER, 0, "", QString(), QString(), QString(), QString(), "Generic", QDateTime::currentDateTime(), 0);
}
// Serial Stuff

View File

@ -154,13 +154,13 @@ Daily::Daily(QWidget *parent,gGraphView * shared)
for (int i=0; i < cpapsize; ++i) {
ChannelID code = cpapcodes[i];
graphlist[schema::channel[code].label()] = new gGraph(schema::channel[code].code(), GraphView, schema::channel[code].label(), channelInfo(code), default_height);
graphlist[schema::channel[code].code()] = new gGraph(schema::channel[code].code(), GraphView, schema::channel[code].label(), channelInfo(code), default_height);
}
int oxigrp=p_profile->ExistsAndTrue("SyncOximetry") ? 0 : 1; // Contemplating killing this setting...
for (int i=0; i < oxisize; ++i) {
ChannelID code = oxicodes[i];
graphlist[schema::channel[code].label()] = new gGraph(schema::channel[code].code(), GraphView, schema::channel[code].label(), channelInfo(code), default_height, oxigrp);
graphlist[schema::channel[code].code()] = new gGraph(schema::channel[code].code(), GraphView, schema::channel[code].label(), channelInfo(code), default_height, oxigrp);
}
if (p_profile->general->calculateRDI()) {
@ -251,7 +251,7 @@ Daily::Daily(QWidget *parent,gGraphView * shared)
gLineOverlaySummary *los=new gLineOverlaySummary(tr("Selection AHI"),5,-4);
AddCPAP(l);
gGraph *FRW = graphlist[schema::channel[CPAP_FlowRate].label()];
gGraph *FRW = graphlist[schema::channel[CPAP_FlowRate].code()];
// Draw layer is important... spans first..
FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_CSR, COLOR_CSR, STR_TR_CSR, FT_Span)));
@ -294,7 +294,10 @@ Daily::Daily(QWidget *parent,gGraphView * shared)
bool square=p_profile->appearance->squareWavePlots();
gLineChart *pc=new gLineChart(CPAP_Pressure, COLOR_Pressure, square);
graphlist[schema::channel[CPAP_Pressure].label()]->AddLayer(AddCPAP(pc));
graphlist[schema::channel[CPAP_Pressure].code()]->AddLayer(AddCPAP(pc));
graphlist[schema::channel[CPAP_Pressure].code()]->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_Ramp, COLOR_Ramp, schema::channel[CPAP_Ramp].label(), FT_Span)));
pc->addPlot(CPAP_EPAP, COLOR_EPAP, square);
pc->addPlot(CPAP_IPAPLo, COLOR_IPAPLo, square);
pc->addPlot(CPAP_IPAP, COLOR_IPAP, square);
@ -310,54 +313,54 @@ Daily::Daily(QWidget *parent,gGraphView * shared)
// this is class wide because the leak redline can be reset in preferences..
// Better way would be having a search for linechart layers in graphlist[...]
gLineChart *leakchart=new gLineChart(CPAP_Leak, COLOR_LeakTotal, square);
graphlist[schema::channel[CPAP_Leak].label()]->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_LargeLeak, COLOR_LargeLeak, STR_TR_LL, FT_Span)));
graphlist[schema::channel[CPAP_Leak].code()]->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_LargeLeak, COLOR_LargeLeak, STR_TR_LL, FT_Span)));
leakchart->addPlot(CPAP_LeakTotal, COLOR_Leak, square);
leakchart->addPlot(CPAP_MaxLeak, COLOR_MaxLeak, square);
schema::channel[CPAP_Leak].setUpperThresholdColor(Qt::red);
schema::channel[CPAP_Leak].setLowerThresholdColor(Qt::green);
graphlist[schema::channel[CPAP_Leak].label()]->AddLayer(AddCPAP(leakchart));
graphlist[schema::channel[CPAP_Leak].code()]->AddLayer(AddCPAP(leakchart));
//LEAK->AddLayer(AddCPAP(new gLineChart(CPAP_Leak, COLOR_Leak,square)));
//LEAK->AddLayer(AddCPAP(new gLineChart(CPAP_MaxLeak, COLOR_MaxLeak,square)));
graphlist[schema::channel[CPAP_Snore].label()]->AddLayer(AddCPAP(new gLineChart(CPAP_Snore, COLOR_Snore, true)));
graphlist[schema::channel[CPAP_Snore].code()]->AddLayer(AddCPAP(new gLineChart(CPAP_Snore, COLOR_Snore, true)));
graphlist[schema::channel[CPAP_PTB].label()]->AddLayer(AddCPAP(new gLineChart(CPAP_PTB, COLOR_PTB, square)));
graphlist[schema::channel[CPAP_PTB].code()]->AddLayer(AddCPAP(new gLineChart(CPAP_PTB, COLOR_PTB, square)));
gLineChart *lc = nullptr;
graphlist[schema::channel[CPAP_MaskPressure].label()]->AddLayer(AddCPAP(new gLineChart(CPAP_MaskPressure, COLOR_MaskPressure, false)));
graphlist[schema::channel[CPAP_RespRate].label()]->AddLayer(AddCPAP(lc=new gLineChart(CPAP_RespRate, COLOR_RespRate, square)));
graphlist[schema::channel[CPAP_MaskPressure].code()]->AddLayer(AddCPAP(new gLineChart(CPAP_MaskPressure, COLOR_MaskPressure, false)));
graphlist[schema::channel[CPAP_RespRate].code()]->AddLayer(AddCPAP(lc=new gLineChart(CPAP_RespRate, COLOR_RespRate, square)));
graphlist[schema::channel[POS_Inclination].label()]->AddLayer(AddPOS(new gLineChart(POS_Inclination)));
graphlist[schema::channel[POS_Orientation].label()]->AddLayer(AddPOS(new gLineChart(POS_Orientation)));
graphlist[schema::channel[POS_Inclination].code()]->AddLayer(AddPOS(new gLineChart(POS_Inclination)));
graphlist[schema::channel[POS_Orientation].code()]->AddLayer(AddPOS(new gLineChart(POS_Orientation)));
graphlist[schema::channel[CPAP_MinuteVent].label()]->AddLayer(AddCPAP(lc=new gLineChart(CPAP_MinuteVent, COLOR_MinuteVent, square)));
graphlist[schema::channel[CPAP_MinuteVent].code()]->AddLayer(AddCPAP(lc=new gLineChart(CPAP_MinuteVent, COLOR_MinuteVent, square)));
lc->addPlot(CPAP_TgMV,COLOR_TgMV,square);
graphlist[schema::channel[CPAP_TidalVolume].label()]->AddLayer(AddCPAP(lc=new gLineChart(CPAP_TidalVolume,COLOR_TidalVolume,square)));
graphlist[schema::channel[CPAP_TidalVolume].code()]->AddLayer(AddCPAP(lc=new gLineChart(CPAP_TidalVolume,COLOR_TidalVolume,square)));
//lc->addPlot(CPAP_Test2,COLOR_DarkYellow,square);
//graphlist[schema::channel[CPAP_TidalVolume].label()]->AddLayer(AddCPAP(new gLineChart("TidalVolume2",COLOR_Magenta,square)));
graphlist[schema::channel[CPAP_FLG].label()]->AddLayer(AddCPAP(new gLineChart(CPAP_FLG, COLOR_FLG, true)));
//graphlist[schema::channel[CPAP_RespiratoryEvent].label()]->AddLayer(AddCPAP(new gLineChart(CPAP_RespiratoryEvent,COLOR_Magenta,true)));
graphlist[schema::channel[CPAP_IE].label()]->AddLayer(AddCPAP(lc=new gLineChart(CPAP_IE, COLOR_IE, square)));
graphlist[schema::channel[CPAP_Te].label()]->AddLayer(AddCPAP(lc=new gLineChart(CPAP_Te, COLOR_Te, square)));
graphlist[schema::channel[CPAP_Ti].label()]->AddLayer(AddCPAP(lc=new gLineChart(CPAP_Ti, COLOR_Ti, square)));
//graphlist[schema::channel[CPAP_TidalVolume].code()]->AddLayer(AddCPAP(new gLineChart("TidalVolume2",COLOR_Magenta,square)));
graphlist[schema::channel[CPAP_FLG].code()]->AddLayer(AddCPAP(new gLineChart(CPAP_FLG, COLOR_FLG, true)));
//graphlist[schema::channel[CPAP_RespiratoryEvent].code()]->AddLayer(AddCPAP(new gLineChart(CPAP_RespiratoryEvent,COLOR_Magenta,true)));
graphlist[schema::channel[CPAP_IE].code()]->AddLayer(AddCPAP(lc=new gLineChart(CPAP_IE, COLOR_IE, square)));
graphlist[schema::channel[CPAP_Te].code()]->AddLayer(AddCPAP(lc=new gLineChart(CPAP_Te, COLOR_Te, square)));
graphlist[schema::channel[CPAP_Ti].code()]->AddLayer(AddCPAP(lc=new gLineChart(CPAP_Ti, COLOR_Ti, square)));
//lc->addPlot(CPAP_Test2,COLOR:DarkYellow,square);
graphlist[schema::channel[ZEO_SleepStage].label()]->AddLayer(AddSTAGE(new gLineChart(ZEO_SleepStage, COLOR_SleepStage, true)));
graphlist[schema::channel[ZEO_SleepStage].code()]->AddLayer(AddSTAGE(new gLineChart(ZEO_SleepStage, COLOR_SleepStage, true)));
gLineOverlaySummary *los1=new gLineOverlaySummary(STR_UNIT_EventsPerHour,5,-4);
gLineOverlaySummary *los2=new gLineOverlaySummary(STR_UNIT_EventsPerHour,5,-4);
graphlist[schema::channel[OXI_Pulse].label()]->AddLayer(AddOXI(los1->add(new gLineOverlayBar(OXI_PulseChange, COLOR_PulseChange, STR_TR_PC,FT_Span))));
graphlist[schema::channel[OXI_Pulse].label()]->AddLayer(AddOXI(los1));
graphlist[schema::channel[OXI_SPO2].label()]->AddLayer(AddOXI(los2->add(new gLineOverlayBar(OXI_SPO2Drop, COLOR_SPO2Drop, STR_TR_O2,FT_Span))));
graphlist[schema::channel[OXI_SPO2].label()]->AddLayer(AddOXI(los2));
graphlist[schema::channel[OXI_Pulse].code()]->AddLayer(AddOXI(los1->add(new gLineOverlayBar(OXI_PulseChange, COLOR_PulseChange, STR_TR_PC,FT_Span))));
graphlist[schema::channel[OXI_Pulse].code()]->AddLayer(AddOXI(los1));
graphlist[schema::channel[OXI_SPO2].code()]->AddLayer(AddOXI(los2->add(new gLineOverlayBar(OXI_SPO2Drop, COLOR_SPO2Drop, STR_TR_O2,FT_Span))));
graphlist[schema::channel[OXI_SPO2].code()]->AddLayer(AddOXI(los2));
graphlist[schema::channel[OXI_Pulse].label()]->AddLayer(AddOXI(new gLineChart(OXI_Pulse, COLOR_Pulse, square)));
graphlist[schema::channel[OXI_SPO2].label()]->AddLayer(AddOXI(new gLineChart(OXI_SPO2, COLOR_SPO2, true)));
graphlist[schema::channel[OXI_Plethy].label()]->AddLayer(AddOXI(new gLineChart(OXI_Plethy, COLOR_Plethy,false)));
graphlist[schema::channel[OXI_Pulse].code()]->AddLayer(AddOXI(new gLineChart(OXI_Pulse, COLOR_Pulse, square)));
graphlist[schema::channel[OXI_SPO2].code()]->AddLayer(AddOXI(new gLineChart(OXI_SPO2, COLOR_SPO2, true)));
graphlist[schema::channel[OXI_Plethy].code()]->AddLayer(AddOXI(new gLineChart(OXI_Plethy, COLOR_Plethy,false)));
// Fix me
@ -370,8 +373,8 @@ Daily::Daily(QWidget *parent,gGraphView * shared)
graphlist["INTSPO2"]->AddLayer(AddCPAP(los4));
graphlist["INTSPO2"]->AddLayer(AddCPAP(new gLineChart(OXI_SPO2, COLOR_SPO2, true)));
graphlist[schema::channel[CPAP_PTB].label()]->setForceMaxY(100);
graphlist[schema::channel[OXI_SPO2].label()]->setForceMaxY(100);
graphlist[schema::channel[CPAP_PTB].code()]->setForceMaxY(100);
graphlist[schema::channel[OXI_SPO2].code()]->setForceMaxY(100);
for (it = graphlist.begin(); it != graphlist.end(); ++it) {
if (skipgraph.contains(it.key())) continue;
@ -967,23 +970,23 @@ QString Daily::getMachineSettings(Day * cpap) {
return html;
}
if (cpap->settingExists(CPAP_PresReliefType)) {
int i=cpap->settings_max(CPAP_PresReliefType);
int j=cpap->settings_max(CPAP_PresReliefMode);
QString flexstr;
ChannelID pr_level_chan = NoChannel;
ChannelID pr_mode_chan = NoChannel;
CPAPLoader * loader = dynamic_cast<CPAPLoader *>(cpap->machine->loader());
if (loader) {
pr_level_chan = loader->PresReliefLevel();
pr_mode_chan = loader->PresReliefMode();
}
if (cpap->machine->loaderName() == STR_MACH_ResMed) {
// this is temporary..
flexstr = QString(tr("EPR:%1 EPR_LEVEL:%2")).arg(cpap->settings_max(RMS9_EPR)).arg(cpap->settings_max(RMS9_EPRLevel));
} else {
flexstr = (i>1) ? schema::channel[CPAP_PresReliefType].option(i)+" x"+QString::number(j) : STR_TR_None;
}
if ((pr_level_chan != NoChannel) && (cpap->settingExists(pr_level_chan))) {
QString flexstr = cpap->getPressureRelief();
html+=QString("<tr><td><a class='info' href='#'>%1<span>%2</span></a></td><td colspan=4>%3</td></tr>")
.arg(STR_TR_PrRelief)
.arg(schema::channel[CPAP_PresReliefType].description())
.arg(schema::channel[pr_mode_chan].label())
.arg(schema::channel[pr_mode_chan].description())
.arg(flexstr);
}
QString mclass=cpap->machine->loaderName();
if (mclass==STR_MACH_PRS1 || mclass==STR_MACH_FPIcon) {
int humid=round(cpap->settings_wavg(CPAP_HumidSetting));

View File

@ -20,19 +20,10 @@ Important: One id code per item, DO NOT CHANGE ID NUMBERS!!!
<channel id="0x1163" class="data" name="BrokenSummary" details="Broken Summary" label="Broken Summary" unit="" color="black"/>
<channel id="0x1164" class="data" name="BrokenWaveform" details="Broken Waveform" label="Broken Waveform" unit="" color="black"/>
<channel id="0x1165" class="setting" scope="!session" name="SmartFlex" details="SmartFlex" label="SmartFlex" type="integer"/>
<channel id="0x1166" class="data" name="PRS1_0F" details="Unknown 0F" label="U0F" unit="?" color="dark green"/>
<channel id="0x1167" class="data" name="IntUnk1" details="Unknown 1" label="Unknown 1" unit="?" color="dark green"/>
<channel id="0x1168" class="data" name="IntUnk2" details="Unknown 2" label="Unknown 2" unit="?" color="dark green"/>
<channel id="0x1200" class="setting" scope="!session" name="PAPMode" details="PAP Mode" label="PAP Mode" type="integer">
<option id="0" value="CPAP"/>
<option id="1" value="Auto"/>
<option id="2" value="Fixed Bi-Level"/>
<option id="3" value="Auto Bi-Level"/>
<option id="4" value="ASV"/>
<option id="5" value="ASV Auto EPAP"/>
</channel>
<channel id="0x1201" class="setting" scope="!session" name="PresRelType" details="Pressure Relief" label="Pres. Relief" type="integer">
<Option id="0" value=""/>
<Option id="1" value="None"/>
@ -105,19 +96,6 @@ Important: One id code per item, DO NOT CHANGE ID NUMBERS!!!
<Option id="4" value="x4"/>
<Option id="5" value="x5"/>
</channel>
<channel id="0xe105" class="setting" scope="!session" name="FlexMode" details="Pressure Relief Mode" label="Flex Mode" type="integer">
<Option id="1" value="None"/>
<Option id="2" value="C-Flex"/>
<Option id="3" value="C-Flex+"/>
<Option id="4" value="A-Flex"/>
<Option id="5" value="Bi-Flex"/>
</channel>
<channel id="0xe106" class="setting" scope="!session" name="FlexSet" details="Pressure Relief Setting" label="Flex Set." type="integer">
<Option id="0" value=""/>
<Option id="1" value="x1"/>
<Option id="2" value="x2"/>
<Option id="3" value="x3"/>
</channel>
<channel id="0xe107" class="setting" scope="!session" name="HoseDiam" details="Hose Diameter" label="Hose Diameter" type="bool">
<Option id="0" value="22mm"/>
<Option id="1" value="15mm"/>
@ -158,18 +136,6 @@ Important: One id code per item, DO NOT CHANGE ID NUMBERS!!!
<Option id="2" value="VPAP"/>
<Option id="3" value="ASV"/>
</channel>
<channel id="0xe201" class="setting" scope="!session" name="EPR" details="EPR Mode" label="EPR Mode" type="integer">
<Option id="0" value="Off"/>
<Option id="1" value="Ramp Only"/>
<Option id="2" value="Full Time"/>
<Option id="3" value="EPR?"/>
</channel>
<channel id="0xe202" class="setting" scope="!session" name="EPRLevel" details="EPR Setting" label="EPR Setting" type="integer">
<Option id="0" value="0"/>
<Option id="1" value="1"/>
<Option id="2" value="2"/>
<Option id="3" value="3"/>
</channel>
</group>
<group name="MACHINE">
<!-- General Per Machine Settings -->

View File

@ -46,6 +46,7 @@
#include "SleepLib/loader_plugins/resmed_loader.h"
#include "SleepLib/loader_plugins/intellipap_loader.h"
#include "SleepLib/loader_plugins/icon_loader.h"
#include "SleepLib/loader_plugins/weinmann_loader.h"
#ifdef Q_WS_X11
#include <X11/Xlib.h>
@ -267,6 +268,7 @@ retry_directory:
ResmedLoader::Register();
IntellipapLoader::Register();
FPIconLoader::Register();
WeinmannLoader::Register();
CMS50Loader::Register();
MD300W1Loader::Register();
//ZEOLoader::Register(); // Use outside of directory importer..

View File

@ -232,8 +232,9 @@ Overview::Overview(QWidget *parent, gGraphView *shared) :
set = new SummaryChart("", GT_POINTS);
//set->addSlice(PRS1_SysOneResistSet,COLOR_Gray,ST_SETAVG);
set->addSlice(CPAP_HumidSetting, COLOR_Blue, ST_SETWAVG);
set->addSlice(CPAP_PresReliefSet, COLOR_Red, ST_SETWAVG);
set->addSlice(RMS9_EPRLevel,COLOR_Green,ST_SETWAVG);
set->addSlice(CPAP_PresReliefLevel, COLOR_Red, ST_SETWAVG);
set->addSlice(CPAP_PresReliefMode, COLOR_Red, ST_SETWAVG);
// set->addSlice(RMS9_EPRLevel,COLOR_Green,ST_SETWAVG);
//set->addSlice(INTP_SmartFlex,COLOR_Purple,ST_SETWAVG);
SET->AddLayer(set);

View File

@ -425,7 +425,7 @@ SleepyHead can keep a copy of this data if you ever need to reinstall.
(Highly recomended, unless your short on disk space or don't care about the graph data)</string>
</property>
<property name="text">
<string>Create SD Card Backups during Import (This is fairly important for ResMed and FP ICON)</string>
<string>Create SD Card Backups during Import (Turn this off at your own peril!)</string>
</property>
</widget>
</item>

View File

@ -177,7 +177,9 @@ SOURCES += \
SleepLib/loader_plugins/md300w1_loader.cpp \
Graphs/gSessionTimesChart.cpp \
logger.cpp \
welcome.cpp
welcome.cpp \
SleepLib/machine_common.cpp \
SleepLib/loader_plugins/weinmann_loader.cpp
HEADERS += \
common_gui.h \
@ -232,7 +234,8 @@ HEADERS += \
SleepLib/serialoximeter.h \
SleepLib/loader_plugins/md300w1_loader.h \
Graphs/gSessionTimesChart.h \
logger.h
logger.h \
SleepLib/loader_plugins/weinmann_loader.h
FORMS += \
daily.ui \

View File

@ -261,8 +261,8 @@ struct RXChange {
per2 = copy.per2;
highlight = copy.highlight;
weighted = copy.weighted;
prelief = copy.prelief;
prelset = copy.prelset;
pressure_string = copy.pressure_string;
pr_relief_string = copy.pr_relief_string;
}
QDate first;
QDate last;
@ -270,6 +270,8 @@ struct RXChange {
EventDataType ahi;
EventDataType fl;
CPAPMode mode;
QString pressure_string;
QString pr_relief_string;
EventDataType min;
EventDataType max;
EventDataType ps;
@ -278,9 +280,7 @@ struct RXChange {
EventDataType per1;
EventDataType per2;
EventDataType weighted;
PRTypes prelief;
Machine *machine;
short prelset;
short highlight;
};
@ -744,8 +744,7 @@ QString Statistics::GenerateHTML()
EventDataType cmin = 0, cmax = 0, cps = 0, cpshi = 0, cmaxipap = 0, min = 0, max = 0, maxipap = 0,
ps = 0, pshi = 0;
Machine *mach = nullptr, *lastmach = nullptr;
PRTypes lastpr = PR_UNKNOWN, prelief = PR_UNKNOWN;
short prelset = 0, lastprelset = -1;
QString last_prel_str, last_pressure_str, prel_str, pressure_str;
QDate date = lastcpap;
Day *day;
bool lastchanged = false;
@ -757,7 +756,12 @@ QString Statistics::GenerateHTML()
do {
day = p_profile->GetGoodDay(date, MT_CPAP);
if (day) {
CPAPLoader * loader = nullptr;
if (day) loader = dynamic_cast<CPAPLoader *>(day->machine->loader());
if (day && loader) {
lastchanged = false;
hours = day->hours();
@ -766,17 +770,20 @@ QString Statistics::GenerateHTML()
compliant++;
}
EventDataType ahi = day->count(CPAP_Obstructive) + day->count(CPAP_Hypopnea) + day->count(
CPAP_Apnea) + day->count(CPAP_ClearAirway);
EventDataType ahi = day->count(CPAP_Obstructive) + day->count(CPAP_Hypopnea) + day->count(CPAP_Apnea) + day->count(CPAP_ClearAirway);
if (p_profile->general->calculateRDI()) { ahi += day->count(CPAP_RERA); }
ahi /= hours;
AHI.push_back(UsageData(date, ahi, hours));
prelief = (PRTypes)(int)round(day->settings_wavg(CPAP_PresReliefType));
prelset = round(day->settings_max(CPAP_PresReliefSet));
prel_str = day->getPressureRelief();
pressure_str = day->getPressureSettings();
mode = (CPAPMode)(int)round(day->settings_wavg(CPAP_Mode));
if (mode ==0) {
mode = (CPAPMode)(int)round(day->settings_wavg(CPAP_Mode));
}
mach = day->machine;
min = max = ps = pshi = maxipap = 0;
@ -794,6 +801,12 @@ QString Statistics::GenerateHTML()
min = day->settings_min(CPAP_EPAPLo);
maxipap = max = day->settings_max(CPAP_IPAPHi);
ps = day->settings_min(CPAP_PS);
} else if (mode == MODE_BILEVEL_AUTO_VARIABLE_PS) { // Similar pressure control as ASV Variable EPAP
min = day->settings_min(CPAP_EPAPLo);
max = day->settings_min(CPAP_EPAPHi);
ps = day->settings_min(CPAP_PSMin);
pshi = day->settings_max(CPAP_PSMax);
maxipap = max = day->settings_max(CPAP_IPAPHi);
} else if (mode == MODE_ASV) {
min = day->settings_min(CPAP_EPAPLo);
ps = day->settings_min(CPAP_PSMin);
@ -805,57 +818,66 @@ QString Statistics::GenerateHTML()
ps = day->settings_min(CPAP_PSMin);
pshi = day->settings_max(CPAP_PSMax);
maxipap = max + pshi;
}
if ((mode != cmode) || (min != cmin) || (max != cmax) || (ps != cps) || (pshi != cpshi)
|| (maxipap != cmaxipap) || (mach != lastmach) || (prelset != lastprelset)) {
if ((cmode != MODE_UNKNOWN) && (lastmach != nullptr)) {
first = date.addDays(1);
int days = p_profile->countDays(MT_CPAP, first, last);
RXChange rx;
rx.first = first;
rx.last = last;
rx.days = days;
rx.ahi = calcAHI(first, last);
rx.fl = calcFL(first, last);
rx.mode = cmode;
rx.min = cmin;
rx.max = cmax;
rx.ps = cps;
rx.pshi = cpshi;
rx.maxipap = cmaxipap;
rx.prelief = lastpr;
rx.prelset = lastprelset;
rx.machine = lastmach;
rx.per1 = 0;
if (lastmach == nullptr) {
lastmach = mach;
cmode = mode;
last_pressure_str = pressure_str;
last_prel_str = prel_str;
}
if ((mode != cmode) || (pressure_str != last_pressure_str) || (prel_str != last_prel_str) || (mach != lastmach)) {
first = date.addDays(1);
int days = p_profile->countDays(MT_CPAP, first, last);
RXChange rx;
rx.first = first;
rx.last = last;
rx.days = days;
rx.ahi = calcAHI(first, last);
rx.fl = calcFL(first, last);
rx.mode = cmode;
rx.pressure_string = last_pressure_str;
rx.pr_relief_string = last_prel_str;
rx.min = cmin;
rx.max = cmax;
rx.ps = cps;
rx.pshi = cpshi;
rx.maxipap = cmaxipap;
rx.machine = lastmach;
rx.per1 = 0;
rx.per2 = 0;
if (mode == MODE_APAP) {
rx.per1 = p_profile->calcPercentile(CPAP_Pressure, percentile, MT_CPAP, first, last);
rx.per2 = 0;
if (mode == MODE_APAP) {
rx.per1 = p_profile->calcPercentile(CPAP_Pressure, percentile, MT_CPAP, first, last);
rx.per2 = 0;
} else if (mode == MODE_BILEVEL_AUTO_FIXED_PS) {
rx.per1 = p_profile->calcPercentile(CPAP_EPAP, percentile, MT_CPAP, first, last);
rx.per2 = p_profile->calcPercentile(CPAP_IPAP, percentile, MT_CPAP, first, last);
} else if (mode == MODE_ASV) {
rx.per1 = p_profile->calcPercentile(CPAP_PS, percentile, MT_CPAP, first, last);
rx.per2 = p_profile->calcPercentile(CPAP_PS, percentile, MT_CPAP, first, last);
} else if (mode == MODE_ASV_VARIABLE_EPAP) {
rx.per1 = p_profile->calcPercentile(CPAP_EPAP, percentile, MT_CPAP, first, last);
rx.per2 = p_profile->calcPercentile(CPAP_PS, percentile, MT_CPAP, first, last);
}
rx.weighted = float(rx.days) / float(cpapdays) * rx.ahi;
rxchange.push_back(rx);
} else if (mode == MODE_BILEVEL_AUTO_FIXED_PS) {
rx.per1 = p_profile->calcPercentile(CPAP_EPAP, percentile, MT_CPAP, first, last);
rx.per2 = p_profile->calcPercentile(CPAP_IPAP, percentile, MT_CPAP, first, last);
} else if (mode == MODE_BILEVEL_AUTO_VARIABLE_PS) {
rx.per1 = p_profile->calcPercentile(CPAP_EPAP, percentile, MT_CPAP, first, last);
rx.per2 = p_profile->calcPercentile(CPAP_PS, percentile, MT_CPAP, first, last);
} else if (mode == MODE_ASV) {
rx.per1 = p_profile->calcPercentile(CPAP_PS, percentile, MT_CPAP, first, last);
rx.per2 = p_profile->calcPercentile(CPAP_PS, percentile, MT_CPAP, first, last);
} else if (mode == MODE_ASV_VARIABLE_EPAP) {
rx.per1 = p_profile->calcPercentile(CPAP_EPAP, percentile, MT_CPAP, first, last);
rx.per2 = p_profile->calcPercentile(CPAP_PS, percentile, MT_CPAP, first, last);
}
rx.weighted = float(rx.days) / float(cpapdays) * rx.ahi;
rxchange.push_back(rx);
cmode = mode;
cmin = min;
cmax = max;
cps = ps;
cpshi = pshi;
cmaxipap = maxipap;
lastpr = prelief;
lastprelset = prelset;
last_prel_str = prel_str;
last_pressure_str = pressure_str;
last = date;
lastmach = mach;
lastchanged = true;
@ -869,8 +891,9 @@ QString Statistics::GenerateHTML()
// Sort list by AHI
qSort(AHI);
lastchanged = false;
lastchanged = false;
// Add the final entry
if (!lastchanged && (mach != nullptr)) {
// last=date.addDays(1);
first = firstcpap;
@ -887,16 +910,20 @@ QString Statistics::GenerateHTML()
rx.ps = ps;
rx.pshi = pshi;
rx.maxipap = maxipap;
rx.prelief = prelief;
rx.prelset = prelset;
rx.machine = mach;
rx.pressure_string = pressure_str;
rx.pr_relief_string = prel_str;
// Todo: Clean up by Calculating this crap later..
if (mode == MODE_APAP) {
rx.per1 = p_profile->calcPercentile(CPAP_Pressure, percentile, MT_CPAP, first, last);
rx.per2 = 0;
} else if (mode == MODE_BILEVEL_AUTO_FIXED_PS) {
rx.per1 = p_profile->calcPercentile(CPAP_EPAP, percentile, MT_CPAP, first, last);
rx.per2 = p_profile->calcPercentile(CPAP_IPAP, percentile, MT_CPAP, first, last);
} else if (mode == MODE_BILEVEL_AUTO_VARIABLE_PS) {
rx.per1 = p_profile->calcPercentile(CPAP_EPAP, percentile, MT_CPAP, first, last);
rx.per2 = p_profile->calcPercentile(CPAP_PS, percentile, MT_CPAP, first, last);
} else if (mode == MODE_ASV) {
rx.per1 = p_profile->calcPercentile(CPAP_PS, percentile, MT_CPAP, first, last);
rx.per2 = p_profile->calcPercentile(CPAP_PS, percentile, MT_CPAP, first, last);
@ -1013,12 +1040,15 @@ QString Statistics::GenerateHTML()
modestr = STR_TR_BiLevel;
} else if (mode == MODE_BILEVEL_AUTO_FIXED_PS) {
modestr = QObject::tr("Auto Bi-Level");
} else if (mode == MODE_BILEVEL_AUTO_VARIABLE_PS) {
modestr = QObject::tr("Auto Bi-Level");
} else if (mode == MODE_ASV) {
modestr = QObject::tr("ASV");
modestr = QObject::tr("ASV Fixed EPAP");
} else if (mode == MODE_ASV_VARIABLE_EPAP) {
modestr = QObject::tr("ASV AutoEPAP");
modestr = QObject::tr("ASV Auto EPAP");
} else modestr = STR_TR_Unknown;
recbox += QString("<tr><td colspan=2><table width=100% border=0 cellpadding=1 cellspacing=0><tr><td colspan=2 align=center><b>%3</b></td></tr>")
.arg(idxstr[i]);
recbox += QString("<tr><td valign=top>") + STR_TR_Start + "<br/>" + STR_TR_End +
@ -1080,7 +1110,7 @@ QString Statistics::GenerateHTML()
hdrlist.push_back(STR_TR_SA);
}
hdrlist.push_back(STR_TR_Machine);
hdrlist.push_back(tr("Pr. Rel."));
hdrlist.push_back(tr("Pressure Relief"));
hdrlist.push_back(STR_TR_Mode);
hdrlist.push_back(tr("Pressure Settings"));
@ -1135,40 +1165,38 @@ QString Statistics::GenerateHTML()
// QString("=%1<br/>%2% ").arg(rx.per1,0,'f',decimals).arg(percentile*100.0)+
// STR_TR_IPAP+QString("=%1").arg(rx.per2,0,'f',decimals);
tooltip = QString("%1").arg(machstr);
if (mode == MODE_CPAP) {
extratxt += "<td colspan=2>"+QString(tr("Fixed %1 %2")+"</td>").arg(rx.min, 4, 'f', 1).arg(schema::channel[CPAP_Pressure].units());
} else if (mode == MODE_APAP) {
extratxt += "<td colspan=2>"+QString(tr("%1 - %2 %3")+"</td>").arg(rx.min, 4, 'f', 1).arg(rx.max, 4, 'f', 1).arg(schema::channel[CPAP_Pressure].units());
} else if (mode == MODE_BILEVEL_FIXED) {
extratxt += "<td colspan=2>"+QString(tr("EPAP %1 %3 IPAP %2 %3")+"</td>").arg(rx.min, 4, 'f', 1).arg(rx.max, 4, 'f', 1).arg(schema::channel[CPAP_Pressure].units());
} else if (mode == MODE_BILEVEL_AUTO_FIXED_PS) {
extratxt += "<td colspan=2>"+QString(tr("PS %4 over %1 - %2 %3")+"</td>").arg(rx.min, 4, 'f', 1).arg(rx.max, 4, 'f', 1).arg(schema::channel[CPAP_Pressure].units()).arg(rx.ps, 4, 'f', 1);
} else if (mode == MODE_ASV) {
extratxt += "<td colspan=2>"+QString(tr("EPAP %1, PS %2-%3 %4")+"</td>").arg(rx.min, 4, 'f', 1).arg(rx.ps, 4, 'f', 1).arg(rx.pshi, 4, 'f', 1).arg(schema::channel[CPAP_Pressure].units());
tooltip = QString("%1 %2% ").arg(machstr).arg(percentile * 100.0) +
STR_TR_EPAP +
QString("=%1<br/>%2% ").arg(rx.per1, 0, 'f', decimals)
.arg(percentile * 100.0)
+ STR_TR_IPAP + QString("=%1").arg(rx.per2, 0, 'f', decimals);
} else if (mode == MODE_ASV_VARIABLE_EPAP) {
extratxt += "<td colspan=2>"+QString(tr("EPAP %1-%2, PS %3-%4 %5")+"</td>").arg(rx.min, 4, 'f', 1).arg(rx.max, 4, 'f', 1).arg(rx.ps, 4, 'f', 1).arg(rx.pshi, 4, 'f', 1).arg(schema::channel[CPAP_Pressure].units());
tooltip = QString("%1 %2% ").arg(machstr).arg(percentile * 100.0) +
STR_TR_EPAP +
QString("=%1<br/>%2% ").arg(rx.per1, 0, 'f', decimals)
.arg(percentile * 100.0)
+ STR_TR_IPAP + QString("=%1").arg(rx.per2, 0, 'f', decimals);
} else {
extratxt += "";
tooltip = "";
}
extratxt += "<td colspan=2>"+rx.pressure_string+"</td>";
// if (mode == MODE_CPAP) {
// extratxt += "<td colspan=2>"+QString(tr("Fixed %1 %2")+"</td>").arg(rx.min, 4, 'f', 1).arg(schema::channel[CPAP_Pressure].units());
// } else if (mode == MODE_APAP) {
// extratxt += "<td colspan=2>"+QString(tr("%1 - %2 %3")+"</td>").arg(rx.min, 4, 'f', 1).arg(rx.max, 4, 'f', 1).arg(schema::channel[CPAP_Pressure].units());
// } else if (mode == MODE_BILEVEL_FIXED) {
// extratxt += "<td colspan=2>"+QString(tr("EPAP %1 %3 IPAP %2 %3")+"</td>").arg(rx.min, 4, 'f', 1).arg(rx.max, 4, 'f', 1).arg(schema::channel[CPAP_Pressure].units());
// } else if (mode == MODE_BILEVEL_AUTO_FIXED_PS) {
// extratxt += "<td colspan=2>"+QString(tr("PS %4 over %1 - %2 %3")+"</td>").arg(rx.min, 4, 'f', 1).arg(rx.max, 4, 'f', 1).arg(schema::channel[CPAP_Pressure].units()).arg(rx.ps, 4, 'f', 1);
// } else if (mode == MODE_BILEVEL_AUTO_VARIABLE_PS) {
// extratxt += "<td colspan=2>"+QString(tr("EPAP %1-%2, PS %3-%4 %5")+"</td>").arg(rx.min, 4, 'f', 1).arg(rx.max, 4, 'f', 1).arg(rx.ps, 4, 'f', 1).arg(rx.pshi, 4, 'f', 1).arg(schema::channel[CPAP_Pressure].units());
// } else if (mode == MODE_ASV) {
// extratxt += "<td colspan=2>"+QString(tr("EPAP %1, PS %2-%3 %4")+"</td>").arg(rx.min, 4, 'f', 1).arg(rx.ps, 4, 'f', 1).arg(rx.pshi, 4, 'f', 1).arg(schema::channel[CPAP_Pressure].units());
// tooltip = QString("%1 %2% ").arg(machstr).arg(percentile * 100.0) +
// STR_TR_EPAP +
// QString("=%1<br/>%2% ").arg(rx.per1, 0, 'f', decimals)
// .arg(percentile * 100.0)
// + STR_TR_IPAP + QString("=%1").arg(rx.per2, 0, 'f', decimals);
// } else if (mode == MODE_ASV_VARIABLE_EPAP) {
// extratxt += "<td colspan=2>"+QString(tr("EPAP %1-%2, PS %3-%4 %5")+"</td>").arg(rx.min, 4, 'f', 1).arg(rx.max, 4, 'f', 1).arg(rx.ps, 4, 'f', 1).arg(rx.pshi, 4, 'f', 1).arg(schema::channel[CPAP_Pressure].units());
// tooltip = QString("%1 %2% ").arg(machstr).arg(percentile * 100.0) +
// STR_TR_EPAP +
// QString("=%1<br/>%2% ").arg(rx.per1, 0, 'f', decimals)
// .arg(percentile * 100.0)
// + STR_TR_IPAP + QString("=%1").arg(rx.per2, 0, 'f', decimals);
// } else {
// extratxt += "";
// tooltip = "";
// }
extratxt += "</tr></table>";
QString presrel;
if (rx.prelset > 0) {
presrel = schema::channel[CPAP_PresReliefType].option(int(rx.prelief));
presrel += QString(" x%1").arg(rx.prelset);
} else { presrel = STR_TR_None; }
QString tooltipshow, tooltiphide;
@ -1198,8 +1226,8 @@ QString Statistics::GenerateHTML()
html += QString("<td>%1</td>").arg(calcSA(rx.first, rx.last), 0, 'f', decimals);
}
html += QString("<td>%1</td>").arg(rx.machine->loaderName());
html += QString("<td>%1</td>").arg(presrel);
html += QString("<td>%1</td>").arg(schema::channel[CPAP_Mode].option(int(rx.mode) - 1));
html += QString("<td>%1</td>").arg(rx.pr_relief_string);
html += QString("<td>%1</td>").arg(schema::channel[CPAP_Mode].option(int(rx.mode)));
html += QString("<td>%1</td>").arg(extratxt);
html += "</tr>";
}