mirror of
https://gitlab.com/pholy/OSCAR-code.git
synced 2025-04-05 10:40:42 +00:00
Interim commit - resmed_loader still needs work
This commit is contained in:
parent
93b363465f
commit
531edc6ad2
@ -19,100 +19,104 @@
|
||||
|
||||
#include "edfparser.h"
|
||||
|
||||
EDFParser::EDFParser(QString name)
|
||||
EDFInfo::EDFInfo()
|
||||
{
|
||||
filesize = 0;
|
||||
datasize = 0;
|
||||
signalPtr = nullptr;
|
||||
hdrPtr = nullptr;
|
||||
fileData.clear();
|
||||
if (!name.isEmpty())
|
||||
Open(name);
|
||||
fileData = nullptr;
|
||||
}
|
||||
EDFParser::~EDFParser()
|
||||
|
||||
EDFInfo::~EDFInfo()
|
||||
{
|
||||
for (auto & s : edfsignals) {
|
||||
if (s.value)
|
||||
delete [] s.value;
|
||||
}
|
||||
// for (auto & a : annotations)
|
||||
// delete a;
|
||||
}
|
||||
|
||||
bool EDFParser::Open(const QString & name)
|
||||
QByteArray * EDFInfo::Open(const QString & name)
|
||||
{
|
||||
if (hdrPtr != nullptr) {
|
||||
qWarning() << "EDFParser::Open() called with file already open " << name;
|
||||
qWarning() << "EDFInfo::Open() called with file already open " << name;
|
||||
sleep(1);
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
QFile fi(name);
|
||||
if (!fi.open(QFile::ReadOnly)) {
|
||||
qDebug() << "EDFParser::Open() Couldn't open file " << name;
|
||||
qDebug() << "EDFInfo::Open() Couldn't open file " << name;
|
||||
sleep(1);
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
fileData = new QByteArray();
|
||||
if (name.endsWith(STR_ext_gz)) {
|
||||
fileData = gUncompress(fi.readAll()); // Open and decompress file
|
||||
*fileData = gUncompress(fi.readAll()); // Open and decompress file
|
||||
} else {
|
||||
fileData = fi.readAll(); // Open and read uncompressed file
|
||||
*fileData = fi.readAll(); // Open and read uncompressed file
|
||||
}
|
||||
fi.close();
|
||||
if (fileData.size() <= EDFHeaderSize) {
|
||||
qDebug() << "EDFParser::Open() File too short " << name;
|
||||
if (fileData->size() <= EDFHeaderSize) {
|
||||
delete fileData;
|
||||
qDebug() << "EDFInfo::Open() File too short " << name;
|
||||
sleep(1);
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
hdrPtr = (EDFHeaderRaw *)fileData.constData();
|
||||
signalPtr = (char *)fileData.constData() + EDFHeaderSize;
|
||||
filename = name;
|
||||
filesize = fileData.size();
|
||||
datasize = filesize - EDFHeaderSize;
|
||||
pos = 0;
|
||||
return true;
|
||||
return fileData;
|
||||
}
|
||||
|
||||
bool EDFParser::Parse()
|
||||
bool EDFInfo::Parse(QByteArray * fileData )
|
||||
{
|
||||
bool ok;
|
||||
|
||||
if (hdrPtr == nullptr) {
|
||||
qWarning() << "EDFParser::Parse() called without valid EDF data " << filename;
|
||||
if (fileData == nullptr) {
|
||||
qWarning() << "EDFInfo::Parse() called without valid EDF data " << filename;
|
||||
sleep(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
hdrPtr = (EDFHeaderRaw *)(*fileData).constData();
|
||||
signalPtr = (char *)(*fileData).constData() + EDFHeaderSize;
|
||||
filesize = (*fileData).size();
|
||||
datasize = filesize - EDFHeaderSize;
|
||||
pos = 0;
|
||||
|
||||
eof = false;
|
||||
edfHdr.version = QString::fromLatin1(hdrPtr->version, 8).toLong(&ok);
|
||||
if (!ok) {
|
||||
qWarning() << "EDFParser::Parser() Bad Version " << filename;
|
||||
qWarning() << "EDFInfo::Parse() Bad Version " << filename;
|
||||
sleep(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
//patientident=QString::fromLatin1(header.patientident,80);
|
||||
edfHdr.patientident=QString::fromLatin1(hdrPtr->patientident,80);
|
||||
edfHdr.recordingident = QString::fromLatin1(hdrPtr->recordingident, 80); // Serial number is in here..
|
||||
edfHdr.startdate_orig = QDateTime::fromString(QString::fromLatin1(hdrPtr->datetime, 16), "dd.MM.yyHH.mm.ss");
|
||||
edfHdr.num_header_bytes = QString::fromLatin1(hdrPtr->num_header_bytes, 8).toLong(&ok);
|
||||
if (!ok) {
|
||||
qWarning() << "EDFParser::Parde() Bad header byte count " << filename;
|
||||
qWarning() << "EDFInfo::Parse() Bad header byte count " << filename;
|
||||
sleep(1);
|
||||
return false;
|
||||
}
|
||||
edfHdr.reserved44=QString::fromLatin1(hdrPtr->reserved, 44);
|
||||
edfHdr.num_data_records = QString::fromLatin1(hdrPtr->num_data_records, 8).toLong(&ok);
|
||||
if (!ok) {
|
||||
qWarning() << "EDFParser::Parse() Bad data record count " << filename;
|
||||
qWarning() << "EDFInfo::Parse() Bad data record count " << filename;
|
||||
sleep(1);
|
||||
return false;
|
||||
}
|
||||
edfHdr.duration_Seconds = QString::fromLatin1(hdrPtr->dur_data_records, 8).toDouble(&ok);
|
||||
if (!ok) {
|
||||
qWarning() << "EDFParser::Parse() Bad duration " << filename;
|
||||
qWarning() << "EDFInfo::Parse() Bad duration " << filename;
|
||||
sleep(1);
|
||||
return false;
|
||||
}
|
||||
edfHdr.num_signals = QString::fromLatin1(hdrPtr->num_signals, 4).toLong(&ok);
|
||||
if (!ok) {
|
||||
qWarning() << "EDFParser::Parse() Bad number of signals " << filename;
|
||||
qWarning() << "EDFInfo::Parse() Bad number of signals " << filename;
|
||||
sleep(1);
|
||||
return false;
|
||||
}
|
||||
@ -123,49 +127,49 @@ bool EDFParser::Parse()
|
||||
// Now copy all the Signal descriptives into edfsignals
|
||||
for (auto & sig : edfsignals) {
|
||||
sig.value = nullptr;
|
||||
sig.label = Read(16);
|
||||
sig.label = ReadBytes(16);
|
||||
|
||||
signal_labels.push_back(sig.label);
|
||||
signalList[sig.label].push_back(&sig);
|
||||
if (eof) {
|
||||
qWarning() << "EDFParser::Parse() Early end of file " << filename;
|
||||
qWarning() << "EDFInfo::Parse() Early end of file " << filename;
|
||||
sleep(1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (auto & sig : edfsignals) {
|
||||
sig.transducer_type = Read(80);
|
||||
sig.transducer_type = ReadBytes(80);
|
||||
}
|
||||
for (auto & sig : edfsignals) {
|
||||
sig.physical_dimension = Read(8);
|
||||
sig.physical_dimension = ReadBytes(8);
|
||||
}
|
||||
for (auto & sig : edfsignals) {
|
||||
sig.physical_minimum = Read(8).toDouble(&ok);
|
||||
sig.physical_minimum = ReadBytes(8).toDouble(&ok);
|
||||
}
|
||||
for (auto & sig : edfsignals) {
|
||||
sig.physical_maximum = Read(8).toDouble(&ok);
|
||||
sig.physical_maximum = ReadBytes(8).toDouble(&ok);
|
||||
}
|
||||
for (auto & sig : edfsignals) {
|
||||
sig.digital_minimum = Read(8).toDouble(&ok);
|
||||
sig.digital_minimum = ReadBytes(8).toDouble(&ok);
|
||||
}
|
||||
for (auto & sig : edfsignals) {
|
||||
sig.digital_maximum = Read(8).toDouble(&ok);
|
||||
sig.digital_maximum = ReadBytes(8).toDouble(&ok);
|
||||
sig.gain = (sig.physical_maximum - sig.physical_minimum) / (sig.digital_maximum - sig.digital_minimum);
|
||||
sig.offset = 0;
|
||||
}
|
||||
for (auto & sig : edfsignals) {
|
||||
sig.prefiltering = Read(80);
|
||||
sig.prefiltering = ReadBytes(80);
|
||||
}
|
||||
for (auto & sig : edfsignals) {
|
||||
sig.nr = Read(8).toLong(&ok);
|
||||
sig.nr = ReadBytes(8).toLong(&ok);
|
||||
}
|
||||
for (auto & sig : edfsignals) {
|
||||
sig.reserved = Read(32);
|
||||
sig.reserved = ReadBytes(32);
|
||||
}
|
||||
|
||||
// could do it earlier, but it won't crash from > EOF Reads
|
||||
if (eof) {
|
||||
qWarning() << "EDFParser::Parse() Early end of file " << filename;
|
||||
qWarning() << "EDFInfo::Parse() Early end of file " << filename;
|
||||
sleep(1);
|
||||
return false;
|
||||
}
|
||||
@ -180,7 +184,7 @@ bool EDFParser::Parse()
|
||||
if (allocsize > (datasize - pos)) {
|
||||
// Space required more than the remainder left to read,
|
||||
// so abort and let the user clean up the corrupted file themselves
|
||||
qWarning() << "EDFParser::Parse(): " << filename << " is too short!";
|
||||
qWarning() << "EDFInfo::Parse(): " << filename << " is too short!";
|
||||
sleep(1);
|
||||
return false;
|
||||
}
|
||||
@ -197,61 +201,120 @@ bool EDFParser::Parse()
|
||||
}
|
||||
for (int x = 0; x < edfHdr.num_data_records; x++) {
|
||||
for (auto & sig : edfsignals) {
|
||||
if ( sig.label.contains("ANNOTATIONS") ) {
|
||||
annotations.push_back(ReadAnnotations( (char *)&signalPtr[pos], sig.nr*2));
|
||||
pos += sig.nr * 2;
|
||||
} else { // it's got genuine 16-bit values
|
||||
#ifdef Q_LITTLE_ENDIAN
|
||||
// Intel x86, etc..
|
||||
memcpy((char *)&sig.value[sig.pos], (char *)&signalPtr[pos], sig.nr * 2);
|
||||
sig.pos += sig.nr;
|
||||
pos += sig.nr * 2;
|
||||
// Intel x86, etc..
|
||||
memcpy((char *)&sig.value[sig.pos], (char *)&signalPtr[pos], sig.nr * 2);
|
||||
sig.pos += sig.nr;
|
||||
pos += sig.nr * 2;
|
||||
#else
|
||||
// Big endian safe
|
||||
for (int j=0;j<sig.nr;j++) {
|
||||
qint16 t=Read16();
|
||||
sig.value[sig.pos++]=t;
|
||||
}
|
||||
// Big endian safe
|
||||
for (int j=0;j<sig.nr;j++) {
|
||||
qint16 t=Read16();
|
||||
sig.value[sig.pos++]=t;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Now massage some stuff into OSCAR's layout
|
||||
int snp = edfHdr.recordingident.indexOf("SRN=");
|
||||
serialnumber.clear();
|
||||
// Parse the EDF file to get the annotations out of it.
|
||||
QVector<Annotation> * EDFInfo::ReadAnnotations(const char * data, int charLen)
|
||||
{
|
||||
QVector<Annotation> * annoVec = new QVector<Annotation>;
|
||||
|
||||
for (int i = snp + 4; i < edfHdr.recordingident.length(); i++) {
|
||||
if (edfHdr.recordingident[i] == ' ') {
|
||||
// Process event annotation record
|
||||
|
||||
long pos = 0;
|
||||
double offset;
|
||||
double duration;
|
||||
|
||||
while (pos < charLen) {
|
||||
QString text;
|
||||
bool sign, ok;
|
||||
char c = data[pos];
|
||||
|
||||
if ((c != '+') && (c != '-')) // Annotaion must start with a +/- sign
|
||||
break;
|
||||
sign = (data[pos++] == '+');
|
||||
|
||||
text = "";
|
||||
c = data[pos];
|
||||
|
||||
do { // collect the offset
|
||||
text += c;
|
||||
pos++;
|
||||
c = data[pos];
|
||||
} while ((c != AnnoSep) && (c != AnnoDurMark)); // a duration is optional
|
||||
|
||||
offset = text.toDouble(&ok);
|
||||
if (!ok) {
|
||||
qDebug() << "Faulty offset in annotation record ";
|
||||
// sleep(1);
|
||||
break;
|
||||
}
|
||||
serialnumber += edfHdr.recordingident[i];
|
||||
|
||||
if (!sign)
|
||||
offset = -offset;
|
||||
|
||||
duration = -1.0; // This indicates no duration supplied
|
||||
// First entry
|
||||
if (data[pos] == AnnoDurMark) { // get duration.(preceded by decimal 21 byte)
|
||||
pos++;
|
||||
text = "";
|
||||
|
||||
do { // collect the duration
|
||||
text += data[pos];
|
||||
pos++;
|
||||
} while ((data[pos] != AnnoSep) && (pos < charLen)); // separator code
|
||||
|
||||
duration = text.toDouble(&ok);
|
||||
if (!ok) {
|
||||
qDebug() << "Faulty duration in annotation record ";
|
||||
// sleep(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while ((data[pos] == AnnoSep) && (pos < charLen)) {
|
||||
int textLen = 0;
|
||||
pos++;
|
||||
const char * textStart = &data[pos];
|
||||
if (data[pos] == AnnoEnd)
|
||||
break;
|
||||
if (data[pos] == AnnoSep) {
|
||||
pos++;
|
||||
break;
|
||||
}
|
||||
do { // collect the annotation text
|
||||
pos++; // officially UTF-8 is allowed here, so don't mangle it
|
||||
textLen++;
|
||||
} while ((data[pos] != AnnoSep) && (pos < charLen)); // separator code
|
||||
text.fromUtf8(textStart, textLen);
|
||||
annoVec->push_back( Annotation( offset, duration, text) );
|
||||
if (pos >= charLen) {
|
||||
qDebug() << "Short EDF Annotations record";
|
||||
// sleep(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while ((pos < charLen) && (data[pos] == AnnoEnd))
|
||||
pos++;
|
||||
|
||||
if (pos >= charLen)
|
||||
break;
|
||||
}
|
||||
|
||||
QDate d2 = edfHdr.startdate_orig.date();
|
||||
if (d2.year() < 2000) {
|
||||
d2.setDate(d2.year() + 100, d2.month(), d2.day());
|
||||
edfHdr.startdate_orig.setDate(d2);
|
||||
}
|
||||
|
||||
if (!edfHdr.startdate_orig.isValid()) {
|
||||
qDebug() << "Invalid date time retreieved parsing EDF File " << filename;
|
||||
sleep(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
startdate = qint64(edfHdr.startdate_orig.toTime_t()) * 1000LL;
|
||||
//startdate-=timezoneOffset();
|
||||
if (startdate == 0) {
|
||||
qDebug() << "Invalid startdate = 0 in EDF File " << filename;
|
||||
sleep(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
dur_data_record = (edfHdr.duration_Seconds * 1000.0L);
|
||||
|
||||
enddate = startdate + dur_data_record * qint64(edfHdr.num_data_records);
|
||||
|
||||
return true;
|
||||
return annoVec;
|
||||
}
|
||||
|
||||
// Read a 16 bits integer
|
||||
qint16 EDFParser::Read16()
|
||||
qint16 EDFInfo::Read16()
|
||||
{
|
||||
if ((pos + 2) > datasize) {
|
||||
eof = true;
|
||||
@ -266,7 +329,7 @@ qint16 EDFParser::Read16()
|
||||
return res;
|
||||
}
|
||||
|
||||
QString EDFParser::Read(unsigned n)
|
||||
QString EDFInfo::ReadBytes(unsigned n)
|
||||
{
|
||||
if ((pos + long(n)) > datasize) {
|
||||
eof = true;
|
||||
@ -277,7 +340,7 @@ QString EDFParser::Read(unsigned n)
|
||||
return buf.trimmed();
|
||||
}
|
||||
|
||||
EDFSignal *EDFParser::lookupLabel(const QString & name, int index)
|
||||
EDFSignal *EDFInfo::lookupLabel(const QString & name, int index)
|
||||
{
|
||||
auto it = signalList.find(name);
|
||||
if (it == signalList.end())
|
||||
|
@ -57,8 +57,8 @@ struct EDFHeaderQT {
|
||||
long num_header_bytes;
|
||||
QString reserved44;
|
||||
long num_data_records;
|
||||
long duration_Seconds;
|
||||
long num_signals;
|
||||
double duration_Seconds;
|
||||
int num_signals;
|
||||
};
|
||||
|
||||
/*! \struct EDFSignal
|
||||
@ -67,92 +67,100 @@ struct EDFHeaderQT {
|
||||
*/
|
||||
struct EDFSignal {
|
||||
public:
|
||||
QString label; //! \brief Name of this Signal
|
||||
QString transducer_type; //! \brief Tranducer Type (source of the data, usually blank)
|
||||
QString physical_dimension; //! \brief The units of measurements represented by this signal
|
||||
EventDataType physical_minimum; //! \brief The minimum limits of the ungained data
|
||||
EventDataType physical_maximum; //! \brief The maximum limits of the ungained data
|
||||
EventDataType digital_minimum; //! \brief The minimum limits of the data with gain and offset applied
|
||||
EventDataType digital_maximum; //! \brief The maximum limits of the data with gain and offset applied
|
||||
EventDataType gain; //! \brief Raw integer data is multiplied by this value
|
||||
EventDataType offset; //! \brief This value is added to the raw data
|
||||
QString prefiltering; //! \brief Any prefiltering methods used (usually blank)
|
||||
long nr; //! \brief Number of records
|
||||
QString reserved; //! \brief Reserved (usually blank)
|
||||
qint16 *value; //! \brief Pointer to the signals sample data
|
||||
int pos; //! \brief a non-EDF extra used internally to count the signal data
|
||||
QString label; //! \brief Name of this Signal
|
||||
QString transducer_type; //! \brief Tranducer Type (source of the data, usually blank)
|
||||
QString physical_dimension; //! \brief The units of measurements represented by this signal
|
||||
EventDataType physical_minimum; //! \brief The minimum limits of the ungained data
|
||||
EventDataType physical_maximum; //! \brief The maximum limits of the ungained data
|
||||
EventDataType digital_minimum; //! \brief The minimum limits of the data with gain and offset applied
|
||||
EventDataType digital_maximum; //! \brief The maximum limits of the data with gain and offset applied
|
||||
EventDataType gain; //! \brief Raw integer data is multiplied by this value
|
||||
EventDataType offset; //! \brief This value is added to the raw data
|
||||
QString prefiltering; //! \brief Any prefiltering methods used (usually blank)
|
||||
long nr; //! \brief Number of records
|
||||
QString reserved; //! \brief Reserved (usually blank)
|
||||
qint16 *value; //! \brief Pointer to the signals sample data
|
||||
|
||||
int pos; //! \brief a non-EDF extra used internally to count the signal data
|
||||
};
|
||||
|
||||
/*! \class Annotation
|
||||
\author Phil Olynyk
|
||||
\brief Hold the annotation text from an EDF file
|
||||
*/
|
||||
class Annotation
|
||||
{
|
||||
public:
|
||||
Annotation() { duration = -1.0; };
|
||||
Annotation( double off, double dur, QString tx ) {
|
||||
offset = off;
|
||||
duration = dur;
|
||||
text = tx;
|
||||
};
|
||||
virtual ~Annotation() {};
|
||||
|
||||
/*! \class EDFParser
|
||||
double offset;
|
||||
double duration;
|
||||
QString text;
|
||||
};
|
||||
|
||||
/*! \class EDFInfo
|
||||
\author Phil Olynyk
|
||||
\author Mark Watkins <mark@jedimark.net>
|
||||
\brief Parse an EDF+ data file into a list of EDFSignal's
|
||||
\note More information on the EDF+ file format can be obtained from http://edfplus.info
|
||||
*/
|
||||
class EDFParser
|
||||
class EDFInfo
|
||||
{
|
||||
public:
|
||||
//! \brief Constructs an EDFParser object, opening the filename if one supplied
|
||||
EDFParser(QString filename = "");
|
||||
EDFInfo();
|
||||
|
||||
~EDFParser();
|
||||
virtual ~EDFInfo();
|
||||
|
||||
//! \brief Open the EDF+ file, and read it's header
|
||||
bool Open(const QString & name);
|
||||
virtual QByteArray * Open(const QString & name); //! \brief Open the EDF+ file, and read it's header
|
||||
|
||||
//! \brief Parse the EDF+ file into the list of EDFSignals.. Must be call Open(..) first.
|
||||
bool Parse();
|
||||
virtual bool Parse(QByteArray * fileData); //! \brief Parse the EDF+ file into the EDFheaderQT. Must call Open(..) first.
|
||||
|
||||
//! \brief Read n bytes of 8 bit data from the EDF+ data stream
|
||||
QString Read(unsigned n);
|
||||
virtual EDFSignal *lookupLabel(const QString & name, int index=0); //! \brief Return a ptr to the i'th signal with that name
|
||||
|
||||
//! \brief Read 16 bit word of data from the EDF+ data stream
|
||||
qint16 Read16();
|
||||
virtual long GetNumSignals() { return edfHdr.num_signals; } //! \brief Returns the number of signals contained in this EDF file
|
||||
|
||||
//! \brief Return a ptr to the i'th signal with the given name (if multiple signal with the same name(?!))
|
||||
EDFSignal *lookupLabel(const QString & name, int index=0);
|
||||
virtual long GetNumDataRecords() { return edfHdr.num_data_records; } //! \brief Returns the number of data records contained per signal.
|
||||
|
||||
//! \brief Returns the number of signals contained in this EDF file
|
||||
long GetNumSignals() { return edfHdr.num_signals; }
|
||||
virtual double GetDuration() { return edfHdr.duration_Seconds; } //! \brief Returns the duration represented by this EDF file
|
||||
|
||||
//! \brief Returns the number of data records contained per signal.
|
||||
long GetNumDataRecords() { return edfHdr.num_data_records; }
|
||||
|
||||
//! \brief Returns the duration represented by this EDF file (in milliseconds)
|
||||
qint64 GetDuration() { return dur_data_record; }
|
||||
|
||||
//! \brief Returns the patientid field from the EDF header
|
||||
QString GetPatient() { return edfHdr.patientident; }
|
||||
virtual QString GetPatient() { return edfHdr.patientident; } //! \brief Returns the patientid field from the EDF header
|
||||
|
||||
// The data members follow
|
||||
|
||||
//! \brief The header in a QT friendly form
|
||||
EDFHeaderQT edfHdr;
|
||||
QString filename; //! \brief For debug and error messages
|
||||
|
||||
//! \brief Vector containing the list of EDFSignals contained in this edf file
|
||||
QVector<EDFSignal> edfsignals;
|
||||
EDFHeaderQT edfHdr; //! \brief The header in a QT friendly form
|
||||
|
||||
//! \brief An by-name indexed into the EDFSignal data
|
||||
QStringList signal_labels;
|
||||
QVector<EDFSignal> edfsignals; //! \brief Holds the EDFSignals contained in this edf file
|
||||
|
||||
//! \brief ResMed sometimes re-uses the SAME signal name
|
||||
QHash<QString, QList<EDFSignal *> > signalList;
|
||||
QVector< QVector<Annotation> * > annotations; //! \brief Holds the Annotaions for this EDF file
|
||||
|
||||
//! \brief The following are computed from the edfHdr data
|
||||
QString serialnumber;
|
||||
qint64 dur_data_record;
|
||||
qint64 startdate;
|
||||
qint64 enddate;
|
||||
QStringList signal_labels; //! \brief An by-name indexed into the EDFSignal data
|
||||
|
||||
QHash<QString, QList<EDFSignal *> > signalList; //! \brief ResMed sometimes re-uses the SAME signal name
|
||||
|
||||
// the following could be private
|
||||
private:
|
||||
QVector<Annotation> * ReadAnnotations( const char * data, int charLen ); //! \brief Create an Annotaion vector from the signal values
|
||||
|
||||
QString ReadBytes(unsigned n); //! \brief Read n bytes of 8 bit data from the EDF+ data stream
|
||||
|
||||
qint16 Read16(); //! \brief Read 16 bit word of data from the EDF+ data stream
|
||||
|
||||
//! \brief This is the array holding the EDF file data
|
||||
QByteArray fileData;
|
||||
QByteArray * fileData;
|
||||
//! \brief The EDF+ files header structure, used as a place holder while processing the text data.
|
||||
EDFHeaderRaw *hdrPtr;
|
||||
//! \brief This is the array of signal descriptors and values
|
||||
char *signalPtr;
|
||||
|
||||
QString filename;
|
||||
long filesize;
|
||||
long datasize;
|
||||
long pos;
|
||||
|
@ -59,11 +59,54 @@ const QString STR_ext_TGT = "tgt";
|
||||
const QString STR_ext_CRC = "crc";
|
||||
|
||||
|
||||
ResMedEDFParser::ResMedEDFParser(QString filename) :EDFParser(filename) { }
|
||||
ResMedEDFParser::~ResMedEDFParser() { }
|
||||
ResMedEDFInfo::ResMedEDFInfo() :EDFInfo() { }
|
||||
ResMedEDFInfo::~ResMedEDFInfo() { }
|
||||
|
||||
bool ResMedEDFInfo::Parse(QByteArray * fileData ) // overrides and calls the super's Parse
|
||||
{
|
||||
EDFInfo::Parse( fileData );
|
||||
|
||||
// Now massage some stuff into OSCAR's layout
|
||||
int snp = edfHdr.recordingident.indexOf("SRN=");
|
||||
serialnumber.clear();
|
||||
|
||||
for (int i = snp + 4; i < edfHdr.recordingident.length(); i++) {
|
||||
if (edfHdr.recordingident[i] == ' ') {
|
||||
break;
|
||||
}
|
||||
serialnumber += edfHdr.recordingident[i];
|
||||
}
|
||||
|
||||
QDate d2 = edfHdr.startdate_orig.date();
|
||||
if (d2.year() < 2000) {
|
||||
d2.setDate(d2.year() + 100, d2.month(), d2.day());
|
||||
edfHdr.startdate_orig.setDate(d2);
|
||||
}
|
||||
|
||||
if (!edfHdr.startdate_orig.isValid()) {
|
||||
qDebug() << "Invalid date time retreieved parsing EDF File " << filename;
|
||||
sleep(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
startdate = qint64(edfHdr.startdate_orig.toTime_t()) * 1000LL;
|
||||
//startdate-=timezoneOffset();
|
||||
if (startdate == 0) {
|
||||
qDebug() << "Invalid startdate = 0 in EDF File " << filename;
|
||||
sleep(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
dur_data_record = (edfHdr.duration_Seconds * 1000.0L);
|
||||
|
||||
enddate = startdate + dur_data_record * qint64(edfHdr.num_data_records);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// Looks up foreign language Signal names that match this channelID
|
||||
EDFSignal *ResMedEDFParser::lookupSignal(ChannelID ch)
|
||||
EDFSignal *ResMedEDFInfo::lookupSignal(ChannelID ch)
|
||||
{
|
||||
// Get list of all known foreign language names for this channel
|
||||
auto channames = resmed_codes.find(ch);
|
||||
@ -113,7 +156,7 @@ void ResmedLoader::ParseSTR(Machine *mach, QMap<QDate, STRFile> & STRmap)
|
||||
int totalRecs = 0;
|
||||
for (auto it=STRmap.begin(), end=STRmap.end(); it != end; ++it) {
|
||||
STRFile & file = it.value();
|
||||
ResMedEDFParser & str = *file.edf;
|
||||
ResMedEDFInfo & str = *file.edf;
|
||||
totalRecs += str.GetNumDataRecords();
|
||||
}
|
||||
|
||||
@ -126,7 +169,7 @@ void ResmedLoader::ParseSTR(Machine *mach, QMap<QDate, STRFile> & STRmap)
|
||||
for (auto it=STRmap.begin(), end=STRmap.end(); it != end; ++it) {
|
||||
STRFile & file = it.value();
|
||||
QString & strfile = file.filename;
|
||||
ResMedEDFParser & str = *file.edf;
|
||||
ResMedEDFInfo & str = *file.edf;
|
||||
|
||||
QDate date = str.edfHdr.startdate_orig.date(); // each STR.edf record starts at 12 noon
|
||||
|
||||
@ -569,7 +612,7 @@ ResmedLoader::ResmedLoader() {
|
||||
m_type = MT_CPAP;
|
||||
|
||||
timeInTimeDelta = timeInLoadBRP = timeInLoadPLD = timeInLoadEVE = 0;
|
||||
timeInLoadCSL = timeInLoadSAD = timeInEDFParser = timeInEDFOpen = timeInAddWaveform = 0;
|
||||
timeInLoadCSL = timeInLoadSAD = timeInEDFInfo = timeInEDFOpen = timeInAddWaveform = 0;
|
||||
|
||||
}
|
||||
|
||||
@ -675,8 +718,9 @@ EDFType lookupEDFType(const QString & text)
|
||||
// Pretend to parse the EVE file to get the duration out of it.
|
||||
int PeekAnnotations(const QString & path, quint32 &start, quint32 &end)
|
||||
{
|
||||
ResMedEDFParser edf(path);
|
||||
if (!edf.Parse())
|
||||
ResMedEDFInfo edf;
|
||||
QByteArray * fileData = edf.Open(path);
|
||||
if (!edf.Parse(fileData))
|
||||
return -1;
|
||||
|
||||
QString t;
|
||||
@ -895,7 +939,7 @@ EDFduration getEDFDuration(const QString & filename)
|
||||
// Have to get the actual duration of the EVE file by parsing the annotations. :(
|
||||
|
||||
|
||||
// Can we cache the stupid EDFParser file for later ???
|
||||
// Can we cache the stupid EDFInfo file for later ???
|
||||
|
||||
int recs = PeekAnnotations(filename, st2, en2);
|
||||
if (recs > 0) {
|
||||
@ -1764,8 +1808,9 @@ int ResmedLoader::Open(const QString & dirpath)
|
||||
|
||||
// Now place any of these files in the Backup folder sorted by the file date
|
||||
for (auto & filename : strfiles) {
|
||||
ResMedEDFParser * stredf = new ResMedEDFParser(filename);
|
||||
if ( ! stredf->Parse()) {
|
||||
ResMedEDFInfo * stredf = new ResMedEDFInfo();
|
||||
QByteArray * fileData = stredf->Open(filename);
|
||||
if ( ! stredf->Parse(fileData)) {
|
||||
qDebug() << "Faulty STR file" << filename;
|
||||
delete stredf;
|
||||
continue;
|
||||
@ -1838,8 +1883,9 @@ int ResmedLoader::Open(const QString & dirpath)
|
||||
if (STRmap.contains(date))
|
||||
continue;
|
||||
|
||||
ResMedEDFParser * stredf = new ResMedEDFParser(fi.canonicalFilePath());
|
||||
if (!stredf->Parse()) {
|
||||
ResMedEDFInfo * stredf = new ResMedEDFInfo();
|
||||
QByteArray * fileData = stredf->Open(fi.canonicalFilePath() );
|
||||
if (!stredf->Parse(fileData)) {
|
||||
qDebug() << "Faulty STR file" << filename;
|
||||
delete stredf;
|
||||
continue;
|
||||
@ -2002,7 +2048,7 @@ int ResmedLoader::Open(const QString & dirpath)
|
||||
qDebug() << "Total toTimeDelta function usage:" << totalbytes << "in" << double(totalns) / 1000000000.0 << "seconds";
|
||||
|
||||
qDebug() << "Total CPU time in EDF Open" << timeInEDFOpen;
|
||||
qDebug() << "Total CPU time in EDF Parser" << timeInEDFParser;
|
||||
qDebug() << "Total CPU time in EDF Parser" << timeInEDFInfo;
|
||||
qDebug() << "Total CPU time in LoadBRP" << timeInLoadBRP;
|
||||
qDebug() << "Total CPU time in LoadPLD" << timeInLoadPLD;
|
||||
qDebug() << "Total CPU time in LoadSAD" << timeInLoadSAD;
|
||||
@ -2013,10 +2059,10 @@ int ResmedLoader::Open(const QString & dirpath)
|
||||
}
|
||||
#endif
|
||||
|
||||
sessfiles.clear();
|
||||
strsess.clear();
|
||||
// sessfiles.clear();
|
||||
// strsess.clear();
|
||||
// strdate.clear();
|
||||
|
||||
strdate.clear();
|
||||
channel_efficiency.clear();
|
||||
channel_time.clear();
|
||||
|
||||
@ -2098,14 +2144,15 @@ bool ResmedLoader::LoadCSL(Session *sess, const QString & path)
|
||||
time.start();
|
||||
#endif
|
||||
|
||||
ResMedEDFParser edf(path);
|
||||
ResMedEDFInfo edf;
|
||||
QByteArray * fileData = edf.Open(path);
|
||||
|
||||
#ifdef DEBUG_EFFICIENCY
|
||||
int edfopentime = time.elapsed();
|
||||
time.start();
|
||||
#endif
|
||||
|
||||
if (!edf.Parse())
|
||||
if (!edf.Parse(fileData))
|
||||
return false;
|
||||
|
||||
#ifdef DEBUG_EFFICIENCY
|
||||
@ -2249,7 +2296,7 @@ bool ResmedLoader::LoadCSL(Session *sess, const QString & path)
|
||||
timeMutex.lock();
|
||||
timeInLoadCSL += time.elapsed();
|
||||
timeInEDFOpen += edfopentime;
|
||||
timeInEDFParser += edfparsetime;
|
||||
timeInEDFInfo += edfparsetime;
|
||||
timeMutex.unlock();
|
||||
#endif
|
||||
|
||||
@ -2262,12 +2309,13 @@ bool ResmedLoader::LoadEVE(Session *sess, const QString & path)
|
||||
QTime time;
|
||||
time.start();
|
||||
#endif
|
||||
ResMedEDFParser edf(path);
|
||||
ResMedEDFInfo edf;
|
||||
QByteArray * fileData = edf.Open(path);
|
||||
#ifdef DEBUG_EFFICIENCY
|
||||
int edfopentime = time.elapsed();
|
||||
time.start();
|
||||
#endif
|
||||
if (!edf.Parse())
|
||||
if (!edf.Parse(fileData))
|
||||
return false;
|
||||
#ifdef DEBUG_EFFICIENCY
|
||||
int edfparsetime = time.elapsed();
|
||||
@ -2422,7 +2470,7 @@ bool ResmedLoader::LoadEVE(Session *sess, const QString & path)
|
||||
timeMutex.lock();
|
||||
timeInLoadEVE += time.elapsed();
|
||||
timeInEDFOpen += edfopentime;
|
||||
timeInEDFParser += edfparsetime;
|
||||
timeInEDFInfo += edfparsetime;
|
||||
timeMutex.unlock();
|
||||
#endif
|
||||
|
||||
@ -2435,12 +2483,13 @@ bool ResmedLoader::LoadBRP(Session *sess, const QString & path)
|
||||
QTime time;
|
||||
time.start();
|
||||
#endif
|
||||
ResMedEDFParser edf(path);
|
||||
ResMedEDFInfo edf;
|
||||
QByteArray * fileData = edf.Open(path);
|
||||
#ifdef DEBUG_EFFICIENCY
|
||||
int edfopentime = time.elapsed();
|
||||
time.start();
|
||||
#endif
|
||||
if (!edf.Parse())
|
||||
if (!edf.Parse(fileData))
|
||||
return false;
|
||||
#ifdef DEBUG_EFFICIENCY
|
||||
int edfparsetime = time.elapsed();
|
||||
@ -2450,7 +2499,7 @@ bool ResmedLoader::LoadBRP(Session *sess, const QString & path)
|
||||
sess->updateFirst(edf.startdate);
|
||||
|
||||
QTime time2;
|
||||
qint64 duration = edf.GetNumDataRecords() * edf.GetDuration();
|
||||
qint64 duration = edf.GetNumDataRecords() * edf.GetDurationMillis();
|
||||
sess->updateLast(edf.startdate + duration);
|
||||
|
||||
for (auto & es : edf.edfsignals) {
|
||||
@ -2510,7 +2559,7 @@ bool ResmedLoader::LoadBRP(Session *sess, const QString & path)
|
||||
timeMutex.lock();
|
||||
timeInLoadBRP += time.elapsed();
|
||||
timeInEDFOpen += edfopentime;
|
||||
timeInEDFParser += edfparsetime;
|
||||
timeInEDFInfo += edfparsetime;
|
||||
timeInAddWaveform += AddWavetime;
|
||||
timeMutex.unlock();
|
||||
#endif
|
||||
@ -2519,7 +2568,7 @@ bool ResmedLoader::LoadBRP(Session *sess, const QString & path)
|
||||
}
|
||||
|
||||
// Convert EDFSignal data to OSCAR's Time-Delta Event format
|
||||
void ResmedLoader::ToTimeDelta(Session *sess, ResMedEDFParser &edf, EDFSignal &es, ChannelID code,
|
||||
void ResmedLoader::ToTimeDelta(Session *sess, ResMedEDFInfo &edf, EDFSignal &es, ChannelID code,
|
||||
long recs, qint64 duration, EventDataType t_min, EventDataType t_max, bool square)
|
||||
{
|
||||
if (t_min == t_max) {
|
||||
@ -2569,9 +2618,7 @@ void ResmedLoader::ToTimeDelta(Session *sess, ResMedEDFParser &edf, EDFSignal &e
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
tt += rate;
|
||||
|
||||
} while (sptr < eptr);
|
||||
|
||||
if (!el)
|
||||
@ -2585,13 +2632,11 @@ void ResmedLoader::ToTimeDelta(Session *sess, ResMedEDFParser &edf, EDFSignal &e
|
||||
tmp = EventDataType(last) * es.gain;
|
||||
|
||||
if ((tmp >= t_min) && (tmp <= t_max)) {
|
||||
if (tmp < min) {
|
||||
if (tmp < min)
|
||||
min = tmp;
|
||||
}
|
||||
|
||||
if (tmp > max) {
|
||||
if (tmp > max)
|
||||
max = tmp;
|
||||
}
|
||||
|
||||
el->AddEvent(tt, last);
|
||||
} else {
|
||||
@ -2601,22 +2646,18 @@ void ResmedLoader::ToTimeDelta(Session *sess, ResMedEDFParser &edf, EDFSignal &e
|
||||
el->setDimension(es.physical_dimension);
|
||||
|
||||
el = sess->AddEventList(code, EVL_Event, es.gain, es.offset, 0, 0);
|
||||
} else {
|
||||
} else
|
||||
el->clear(); // reuse the object
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tmp = EventDataType(c) * es.gain;
|
||||
|
||||
if ((tmp >= t_min) && (tmp <= t_max)) {
|
||||
if (tmp < min) {
|
||||
if (tmp < min)
|
||||
min = tmp;
|
||||
}
|
||||
|
||||
if (tmp > max) {
|
||||
if (tmp > max)
|
||||
max = tmp;
|
||||
}
|
||||
|
||||
el->AddEvent(tt, c);
|
||||
} else {
|
||||
@ -2625,7 +2666,8 @@ void ResmedLoader::ToTimeDelta(Session *sess, ResMedEDFParser &edf, EDFSignal &e
|
||||
|
||||
// Create and attach new EventList
|
||||
el = sess->AddEventList(code, EVL_Event, es.gain, es.offset, 0, 0);
|
||||
} else { el->clear(); }
|
||||
} else
|
||||
el->clear();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2636,9 +2678,8 @@ void ResmedLoader::ToTimeDelta(Session *sess, ResMedEDFParser &edf, EDFSignal &e
|
||||
|
||||
tmp = EventDataType(c) * es.gain;
|
||||
|
||||
if ((tmp >= t_min) && (tmp <= t_max)) {
|
||||
if ((tmp >= t_min) && (tmp <= t_max))
|
||||
el->AddEvent(tt, c);
|
||||
}
|
||||
|
||||
sess->setMin(code, min);
|
||||
sess->setMax(code, max);
|
||||
@ -2667,7 +2708,7 @@ void ResmedLoader::ToTimeDelta(Session *sess, ResMedEDFParser &edf, EDFSignal &e
|
||||
timeInTimeDelta += time.elapsed();
|
||||
timeMutex.unlock();
|
||||
#endif
|
||||
}
|
||||
} // end ResMedLoader::ToTimeDelta
|
||||
|
||||
// Load SAD Oximetry Signals
|
||||
bool ResmedLoader::LoadSAD(Session *sess, const QString & path)
|
||||
@ -2677,14 +2718,15 @@ bool ResmedLoader::LoadSAD(Session *sess, const QString & path)
|
||||
time.start();
|
||||
#endif
|
||||
|
||||
ResMedEDFParser edf(path);
|
||||
ResMedEDFInfo edf;
|
||||
QByteArray * fileData = edf.Open(path);
|
||||
|
||||
#ifdef DEBUG_EFFICIENCY
|
||||
int edfopentime = time.elapsed();
|
||||
time.start();
|
||||
#endif
|
||||
|
||||
if (!edf.Parse())
|
||||
if (!edf.Parse(fileData))
|
||||
return false;
|
||||
|
||||
#ifdef DEBUG_EFFICIENCY
|
||||
@ -2693,7 +2735,7 @@ bool ResmedLoader::LoadSAD(Session *sess, const QString & path)
|
||||
#endif
|
||||
|
||||
sess->updateFirst(edf.startdate);
|
||||
qint64 duration = edf.GetNumDataRecords() * edf.GetDuration();
|
||||
qint64 duration = edf.GetNumDataRecords() * edf.GetDurationMillis();
|
||||
sess->updateLast(edf.startdate + duration);
|
||||
|
||||
for (auto & es : edf.edfsignals) {
|
||||
@ -2732,7 +2774,7 @@ bool ResmedLoader::LoadSAD(Session *sess, const QString & path)
|
||||
timeMutex.lock();
|
||||
timeInLoadSAD += time.elapsed();
|
||||
timeInEDFOpen += edfopentime;
|
||||
timeInEDFParser += edfparsetime;
|
||||
timeInEDFInfo += edfparsetime;
|
||||
timeMutex.unlock();
|
||||
#endif
|
||||
return true;
|
||||
@ -2745,12 +2787,13 @@ bool ResmedLoader::LoadPLD(Session *sess, const QString & path)
|
||||
QTime time;
|
||||
time.start();
|
||||
#endif
|
||||
ResMedEDFParser edf(path);
|
||||
ResMedEDFInfo edf;
|
||||
QByteArray * fileData = edf.Open(path);
|
||||
#ifdef DEBUG_EFFICIENCY
|
||||
int edfopentime = time.elapsed();
|
||||
time.start();
|
||||
#endif
|
||||
if (!edf.Parse())
|
||||
if (!edf.Parse(fileData))
|
||||
return false;
|
||||
#ifdef DEBUG_EFFICIENCY
|
||||
int edfparsetime = time.elapsed();
|
||||
@ -2760,7 +2803,7 @@ bool ResmedLoader::LoadPLD(Session *sess, const QString & path)
|
||||
// Is it safe to assume the order does not change here?
|
||||
enum PLDType { MaskPres = 0, TherapyPres, ExpPress, Leak, RR, Vt, Mv, SnoreIndex, FFLIndex, U1, U2 };
|
||||
|
||||
qint64 duration = edf.GetNumDataRecords() * edf.GetDuration();
|
||||
qint64 duration = edf.GetNumDataRecords() * edf.GetDurationMillis();
|
||||
sess->updateFirst(edf.startdate);
|
||||
sess->updateLast(edf.startdate + duration);
|
||||
QString t;
|
||||
@ -2896,7 +2939,7 @@ bool ResmedLoader::LoadPLD(Session *sess, const QString & path)
|
||||
timeMutex.lock();
|
||||
timeInLoadPLD += time.elapsed();
|
||||
timeInEDFOpen += edfopentime;
|
||||
timeInEDFParser += edfparsetime;
|
||||
timeInEDFInfo += edfparsetime;
|
||||
timeMutex.unlock();
|
||||
#endif
|
||||
|
||||
|
@ -30,18 +30,46 @@ EDFType lookupEDFType(const QString & text);
|
||||
|
||||
const QString resmed_class_name = STR_MACH_ResMed;
|
||||
|
||||
class ResMedEDFParser:public EDFParser
|
||||
class ResMedEDFInfo : public EDFInfo
|
||||
{
|
||||
public:
|
||||
ResMedEDFParser(QString filename = "");
|
||||
~ResMedEDFParser();
|
||||
ResMedEDFInfo();
|
||||
~ResMedEDFInfo();
|
||||
|
||||
virtual bool Parse(QByteArray * fileData) override; // overrides and calls the super's Parse
|
||||
|
||||
virtual qint64 GetDurationMillis() { return dur_data_record; } // overrides the super
|
||||
|
||||
EDFSignal *lookupSignal(ChannelID ch);
|
||||
|
||||
|
||||
|
||||
//! \brief The following are computed from the edfHdr data
|
||||
QString serialnumber;
|
||||
qint64 dur_data_record;
|
||||
qint64 startdate;
|
||||
qint64 enddate;
|
||||
|
||||
};
|
||||
|
||||
class EDFduration
|
||||
{
|
||||
public:
|
||||
EDFduration() { start = end = 0; type = EDF_UNKNOWN; }
|
||||
EDFduration(quint32 start, quint32 end, QString path) :
|
||||
start(start), end(end), path(path) {}
|
||||
|
||||
quint32 start;
|
||||
quint32 end;
|
||||
QString path;
|
||||
QString filename;
|
||||
EDFType type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct STRRecord
|
||||
class STRRecord
|
||||
{
|
||||
public:
|
||||
STRRecord() {
|
||||
maskon.clear();
|
||||
maskoff.clear();
|
||||
@ -125,82 +153,8 @@ struct STRRecord
|
||||
|
||||
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;
|
||||
}
|
||||
// All the data members
|
||||
QVector<quint32> maskon;
|
||||
QVector<quint32> maskoff;
|
||||
|
||||
@ -279,47 +233,6 @@ struct STRRecord
|
||||
|
||||
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;
|
||||
@ -342,50 +255,19 @@ protected:
|
||||
ResMedDay * resday;
|
||||
};
|
||||
|
||||
struct STRFile {
|
||||
class STRFile
|
||||
{
|
||||
public:
|
||||
STRFile() :
|
||||
filename(QString()), edf(nullptr) {}
|
||||
STRFile(QString name, ResMedEDFParser *str) :
|
||||
STRFile(QString name, ResMedEDFInfo *str) :
|
||||
filename(name), edf(str) {}
|
||||
STRFile(const STRFile & copy) {
|
||||
filename = copy.filename;
|
||||
edf = copy.edf;
|
||||
}
|
||||
~STRFile() {
|
||||
}
|
||||
virtual ~STRFile() {}
|
||||
|
||||
QString filename;
|
||||
ResMedEDFParser * edf;
|
||||
ResMedEDFInfo * 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
|
||||
@ -416,7 +298,7 @@ class ResmedLoader : public CPAPLoader
|
||||
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,
|
||||
void ToTimeDelta(Session *sess, ResMedEDFInfo &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
|
||||
@ -443,7 +325,8 @@ class ResmedLoader : public CPAPLoader
|
||||
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);
|
||||
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();
|
||||
@ -463,17 +346,20 @@ class ResmedLoader : public CPAPLoader
|
||||
volatile int sessionCount;
|
||||
|
||||
protected:
|
||||
//! \brief The STR.edf file is a unique edf file with many signals
|
||||
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);
|
||||
|
||||
//! \brief Write a backup copy to the backup path
|
||||
QString backup(const QString & file, const QString & backup_path);
|
||||
|
||||
QMap<SessionID, QStringList> sessfiles;
|
||||
QMap<quint32, STRRecord> strsess;
|
||||
QMap<QDate, QList<STRRecord *> > strdate;
|
||||
// The data members
|
||||
// QMap<SessionID, QStringList> sessfiles;
|
||||
// QMap<quint32, STRRecord> strsess;
|
||||
// QMap<QDate, QList<STRRecord *> > strdate;
|
||||
|
||||
QMap<QDate, ResMedDay> resdayList;
|
||||
|
||||
#ifdef DEBUG_EFFICIENCY
|
||||
@ -485,7 +371,7 @@ protected:
|
||||
volatile qint64 timeInLoadCSL;
|
||||
volatile qint64 timeInLoadSAD;
|
||||
volatile qint64 timeInEDFOpen;
|
||||
volatile qint64 timeInEDFParser;
|
||||
volatile qint64 timeInEDFInfo;
|
||||
volatile qint64 timeInAddWaveform;
|
||||
volatile qint64 timeInTimeDelta;
|
||||
QMutex timeMutex;
|
||||
|
Loading…
Reference in New Issue
Block a user