OSCAR-code/sleepyhead/SleepLib/loader_plugins/resmed_loader.h

498 lines
13 KiB
C++

/* SleepLib RESMED Loader Header
*
* Copyright (C) 2011-2018 Mark Watkins <mark@jedimark.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 RESMED_LOADER_H
#define RESMED_LOADER_H
#include <QVector>
#include "SleepLib/machine.h" // Base class: MachineLoader
#include "SleepLib/machine_loader.h"
#include "SleepLib/profiles.h"
#include "SleepLib/loader_plugins/edfparser.h"
//********************************************************************************************
/// IMPORTANT!!!
//********************************************************************************************
// Please INCREMENT the following value when making changes to this loaders implementation.
//
const int resmed_data_version = 11;
//
//********************************************************************************************
enum EDFType { EDF_UNKNOWN, EDF_BRP, EDF_PLD, EDF_SAD, EDF_EVE, EDF_CSL };
EDFType lookupEDFType(const QString & text);
const QString resmed_class_name = STR_MACH_ResMed;
class ResMedEDFParser:public EDFParser
{
public:
ResMedEDFParser(QString filename = "");
~ResMedEDFParser();
EDFSignal *lookupSignal(ChannelID ch);
};
struct STRRecord
{
STRRecord() {
maskon.clear();
maskoff.clear();
maskdur = 0;
maskevents = -1;
mode = -1;
rms9_mode = -1;
set_pressure = -1;
epap = -1;
max_pressure = -1;
min_pressure = -1;
max_epap = -1;
min_epap = -1;
max_ps = -1;
min_ps = -1;
ps = -1;
ipap = -1;
max_ipap = -1;
min_ipap = -1;
epr = -1;
epr_level = -1;
sessionid = 0;
ahi = -1;
oai = -1;
ai = -1;
hi = -1;
uai = -1;
cai = -1;
csr = -1;
leak50 = -1;
leak95 = -1;
leakmax = -1;
rr50 = -1;
rr95 = -1;
rrmax = -1;
mv50 = -1;
mv95 = -1;
mvmax = -1;
ie50 = -1;
ie95 = -1;
iemax = -1;
tv50 = -1;
tv95 = -1;
tvmax = -1;
mp50 = -1;
mp95 = -1;
mpmax = -1;
tgtepap50 = -1;
tgtepap95 = -1;
tgtepapmax = -1;
tgtipap50 = -1;
tgtipap95 = -1;
tgtipapmax = -1;
s_RampTime = -1;
s_RampEnable = -1;
s_EPR_ClinEnable = -1;
s_EPREnable = -1;
s_PtAccess = -1;
s_ABFilter = -1;
s_Mask = -1;
s_Tube = -1;
s_ClimateControl = -1;
s_HumEnable = -1;
s_HumLevel = -1;
s_TempEnable = -1;
s_Temp = -1;
s_SmartStart = -1;
ramp_pressure = -1;
date=QDate();
}
STRRecord(const STRRecord & copy) {
maskon = copy.maskon;
maskoff = copy.maskoff;
maskdur = copy.maskdur;
maskevents = copy.maskevents;
mode = copy.mode;
rms9_mode = copy.rms9_mode;
set_pressure = copy.set_pressure;
epap = copy.epap;
max_pressure = copy.max_pressure;
min_pressure = copy.min_pressure;
max_ps = copy.max_ps;
min_ps = copy.min_ps;
ps = copy.ps;
max_epap = copy.max_epap;
min_epap = copy.min_epap;
ipap = copy.ipap;
max_ipap = copy.max_ipap;
min_ipap = copy.min_ipap;
epr = copy.epr;
epr_level = copy.epr_level;
sessionid = copy.sessionid;
ahi = copy.ahi;
ai = copy.ai;
oai = copy.oai;
hi = copy.hi;
uai = copy.uai;
cai = copy.cai;
csr = copy.csr;
date = copy.date;
leak50 = copy.leak50;
leak95 = copy.leak95;
leakmax = copy.leakmax;
rr50 = copy.rr50;
rr95 = copy.rr95;
rrmax = copy.rrmax;
mv50 = copy.mv50;
mv95 = copy.mv95;
mvmax = copy.mvmax;
ie50 = copy.ie50;
ie95 = copy.ie95;
iemax = copy.iemax;
tv50 = copy.tv50;
tv95 = copy.tv95;
tvmax = copy.tvmax;
mp50 = copy.mp50;
mp95 = copy.mp95;
mpmax = copy.mpmax;
tgtepap50 = copy.tgtepap50;
tgtepap95 = copy.tgtepap95;
tgtepapmax = copy.tgtepapmax;
tgtipap50 = copy.tgtipap50;
tgtipap95 = copy.tgtipap95;
tgtipapmax = copy.tgtipapmax;
s_EPREnable = copy.s_EPREnable;
s_EPR_ClinEnable = copy.s_EPREnable;
s_RampEnable = copy.s_RampEnable;
s_RampTime = copy.s_RampTime;
s_SmartStart = copy.s_SmartStart;
s_PtAccess = copy.s_PtAccess;
s_ABFilter = copy.s_ABFilter;
s_Mask = copy.s_Mask;
s_Tube = copy.s_Tube;
s_ClimateControl = copy.s_ClimateControl;
s_HumEnable = copy.s_HumEnable;
s_HumLevel = copy.s_HumLevel;
s_TempEnable = copy.s_TempEnable;
s_Temp = copy.s_Temp;
ramp_pressure = copy.ramp_pressure;
}
QVector<quint32> maskon;
QVector<quint32> maskoff;
EventDataType maskdur;
EventDataType maskevents;
EventDataType mode;
EventDataType rms9_mode;
EventDataType set_pressure;
EventDataType max_pressure;
EventDataType min_pressure;
EventDataType epap;
EventDataType max_ps;
EventDataType min_ps;
EventDataType ps;
EventDataType max_epap;
EventDataType min_epap;
EventDataType ipap;
EventDataType max_ipap;
EventDataType min_ipap;
EventDataType epr;
EventDataType epr_level;
quint32 sessionid;
EventDataType ahi;
EventDataType oai;
EventDataType ai;
EventDataType hi;
EventDataType uai;
EventDataType cai;
EventDataType csr;
EventDataType leak50;
EventDataType leak95;
EventDataType leakmax;
EventDataType rr50;
EventDataType rr95;
EventDataType rrmax;
EventDataType mv50;
EventDataType mv95;
EventDataType mvmax;
EventDataType tv50;
EventDataType tv95;
EventDataType tvmax;
EventDataType mp50;
EventDataType mp95;
EventDataType mpmax;
EventDataType ie50;
EventDataType ie95;
EventDataType iemax;
EventDataType tgtepap50;
EventDataType tgtepap95;
EventDataType tgtepapmax;
EventDataType tgtipap50;
EventDataType tgtipap95;
EventDataType tgtipapmax;
EventDataType ramp_pressure;
QDate date;
EventDataType s_RampTime;
int s_RampEnable;
int s_EPR_ClinEnable;
int s_EPREnable;
int s_PtAccess;
int s_ABFilter;
int s_Mask;
int s_Tube;
int s_ClimateControl;
int s_HumEnable;
EventDataType s_HumLevel;
int s_TempEnable;
EventDataType s_Temp;
int s_SmartStart;
};
class ResmedLoader;
struct EDFGroup {
EDFGroup() { }
EDFGroup(QString &brp, QString &eve, QString &pld, QString &sad, QString &csl) {
BRP = brp;
EVE = eve;
CSL = csl;
PLD = pld;
SAD = sad;
}
EDFGroup(const EDFGroup & copy) {
BRP = copy.BRP;
EVE = copy.EVE;
CSL = copy.CSL;
PLD = copy.PLD;
SAD = copy.SAD;
}
QString BRP;
QString EVE;
QString CSL;
QString PLD;
QString SAD;
};
struct EDFduration {
EDFduration() { start = end = 0; type = EDF_UNKNOWN; }
EDFduration(const EDFduration & copy) {
path = copy.path;
start = copy.start;
end = copy.end;
type = copy.type;
filename = copy.filename;
}
EDFduration(quint32 start, quint32 end, QString path) :
start(start), end(end), path(path) {}
quint32 start;
quint32 end;
QString path;
QString filename;
EDFType type;
};
struct ResMedDay {
QDate date;
STRRecord str;
QHash<QString, QString> files;
// QHash<QString, EDFduration> durations;
};
class ResDayTask:public ImportTask
{
public:
ResDayTask(ResmedLoader * l, Machine * m, ResMedDay * d): reimporting(false), loader(l), mach(m), resday(d) {}
virtual ~ResDayTask() {}
virtual void run();
bool reimporting;
protected:
ResmedLoader * loader;
Machine * mach;
ResMedDay * resday;
};
struct STRFile {
STRFile() :
filename(QString()), edf(nullptr) {}
STRFile(QString name, ResMedEDFParser *str) :
filename(name), edf(str) {}
STRFile(const STRFile & copy) {
filename = copy.filename;
edf = copy.edf;
}
~STRFile() {
}
QString filename;
ResMedEDFParser * edf;
};
/*class ResmedImport:public ImportTask
{
public:
ResmedImport(ResmedLoader * l, SessionID s, QHash<EDFType, QStringList> grp, Machine * m): loader(l), sessionid(s), files(grp), mach(m) {}
virtual ~ResmedImport() {}
virtual void run();
protected:
ResmedLoader * loader;
SessionID sessionid;
QHash<EDFType, QStringList> files;
Machine * mach;
};
class ResmedImportStage2:public ImportTask
{
public:
ResmedImportStage2(ResmedLoader * l, STRRecord r, Machine * m): loader(l), R(r), mach(m) {}
virtual ~ResmedImportStage2() {}
virtual void run();
protected:
ResmedLoader * loader;
STRRecord R;
Machine * mach;
}; */
/*! \class ResmedLoader
\brief Importer for ResMed S9 Data
*/
class ResmedLoader : public CPAPLoader
{
Q_OBJECT
friend class ResmedImport;
friend class ResmedImportStage2;
public:
ResmedLoader();
virtual ~ResmedLoader();
//! \brief Detect if the given path contains a valid Folder structure
virtual bool Detect(const QString & path);
//! \brief Look up machine model information of ResMed file structure stored at path
virtual MachineInfo PeekInfo(const QString & path);
//! \brief Scans for ResMed SD folder structure signature, and loads any new data if found
virtual int Open(const QString &);
//! \brief Returns the version number of this ResMed loader
virtual int Version() { return resmed_data_version; }
//! \brief Returns the Machine class name of this loader. ("ResMed")
virtual const QString &loaderName() { return resmed_class_name; }
//! \brief Converts EDFSignal data to time delta packed EventList, and adds to Session
void ToTimeDelta(Session *sess, ResMedEDFParser &edf, EDFSignal &es, ChannelID code, long recs,
qint64 duration, EventDataType min = 0, EventDataType max = 0, bool square = false);
//! \brief Register the ResmedLoader with the list of other machine loaders
static void Register();
//! \brief Parse the EVE Event annotation data, and save to Session * sess
//! This contains all Hypopnea, Obstructive Apnea, Central and Apnea codes
bool LoadEVE(Session *sess, const QString & path);
//! \brief Parse the CSL Event annotation data, and save to Session * sess
//! This contains Cheyne Stokes Respiration flagging on the AirSense 10
bool LoadCSL(Session *sess, const QString & path);
//! \brief Parse the BRP High Resolution data, and save to Session * sess
//! This contains Flow Rate, Mask Pressure, and Resp. Event data
bool LoadBRP(Session *sess, const QString & path);
//! \brief Parse the SAD Pulse oximetry attachment data, and save to Session * sess
//! This contains Pulse Rate and SpO2 Oxygen saturation data
bool LoadSAD(Session *sess, const QString & path);
//! \brief Parse the PRD low resolution data, and save to Session * sess
//! This contains the Pressure, Leak, Respiratory Rate, Minute Ventilation, Tidal Volume, etc..
bool LoadPLD(Session *sess, const QString & path);
virtual MachineInfo newInfo() {
return MachineInfo(MT_CPAP, 0, resmed_class_name, QObject::tr("ResMed"), QString(), QString(), QString(), QObject::tr("S9"), QDateTime::currentDateTime(), resmed_data_version);
}
virtual void initChannels();
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Now for some CPAPLoader overrides
////////////////////////////////////////////////////////////////////////////////////////////////////////////
virtual QString PresReliefLabel() { return QObject::tr("EPR: "); }
virtual ChannelID PresReliefMode();
virtual ChannelID PresReliefLevel();
virtual ChannelID CPAPModeChannel();
////////////////////////////////////////////////////////////////////////////////////////////////////////////
volatile int sessionCount;
protected:
void ParseSTR(Machine *, QMap<QDate, STRFile> &);
//! \brief Scan for new files to import, group into sessions and add to task que
int scanFiles(Machine * mach, const QString & datalog_path);
QString backup(const QString & file, const QString & backup_path);
QMap<SessionID, QStringList> sessfiles;
QMap<quint32, STRRecord> strsess;
QMap<QDate, QList<STRRecord *> > strdate;
QMap<QDate, ResMedDay> resdayList;
#ifdef DEBUG_EFFICIENCY
QHash<ChannelID, qint64> channel_efficiency;
QHash<ChannelID, qint64> channel_time;
volatile qint64 timeInLoadBRP;
volatile qint64 timeInLoadPLD;
volatile qint64 timeInLoadEVE;
volatile qint64 timeInLoadCSL;
volatile qint64 timeInLoadSAD;
volatile qint64 timeInEDFOpen;
volatile qint64 timeInEDFParser;
volatile qint64 timeInAddWaveform;
volatile qint64 timeInTimeDelta;
QMutex timeMutex;
#endif
};
#endif // RESMED_LOADER_H