From 8c11751b2b70f35ca225b2ac8eaac67da491f97e Mon Sep 17 00:00:00 2001 From: Phil Olynyk Date: Thu, 18 Jul 2019 19:36:35 -0400 Subject: [PATCH] Re-arrange edf-parser code - and fix it --- oscar/SleepLib/loader_plugins/edfparser.cpp | 442 +++++++++--------- oscar/SleepLib/loader_plugins/edfparser.h | 146 +++--- .../SleepLib/loader_plugins/resmed_loader.cpp | 192 ++++---- oscar/oscar.pro | 6 + 4 files changed, 391 insertions(+), 395 deletions(-) diff --git a/oscar/SleepLib/loader_plugins/edfparser.cpp b/oscar/SleepLib/loader_plugins/edfparser.cpp index 589c4bd9..fccbca8b 100644 --- a/oscar/SleepLib/loader_plugins/edfparser.cpp +++ b/oscar/SleepLib/loader_plugins/edfparser.cpp @@ -1,5 +1,6 @@ /* EDF Parser Implementation * + * Copyright (c) 2019 The OSCAR Team * Copyright (c) 2011-2018 Mark Watkins * * This file is subject to the terms and conditions of the GNU General Public @@ -20,16 +21,226 @@ EDFParser::EDFParser(QString name) { - buffer = nullptr; + filesize = 0; + datasize = 0; + signalPtr = nullptr; + hdrPtr = nullptr; + fileData.clear(); if (!name.isEmpty()) Open(name); } EDFParser::~EDFParser() { for (auto & s : edfsignals) { - if (s.data) { delete [] s.data; } + if (s.value) + delete [] s.value; } } + +bool EDFParser::Open(const QString & name) +{ + if (hdrPtr != nullptr) { + qWarning() << "EDFParser::Open() called with file already open" << name; + return false; + } + QFile fi(name); + if (!fi.open(QFile::ReadOnly)) { + qDebug() << "EDFParser::Open() Couldn't open file" << name; + return false; + } + if (name.endsWith(STR_ext_gz)) { + fileData = gUncompress(fi.readAll()); // Open and decompress file + } else { + fileData = fi.readAll(); // Open and read uncompressed file + } + fi.close(); + if (fileData.size() <= EDFHeaderSize) { + qDebug() << "EDFParser::Open() File too short" << name; + return false; + } + hdrPtr = (EDFHeaderRaw *)fileData.constData(); + signalPtr = (char *)fileData.constData() + EDFHeaderSize; + filename = name; + filesize = fileData.size(); + datasize = filesize - EDFHeaderSize; + pos = 0; + return true; +} + +bool EDFParser::Parse() +{ + bool ok; + + if (hdrPtr == nullptr) { + qWarning() << "EDFParser::Parse() called without valid EDF data" << filename; + return false; + } + + eof = false; + edfHdr.version = QString::fromLatin1(hdrPtr->version, 8).toLong(&ok); + if (!ok) { + return false; + } + + //patientident=QString::fromLatin1(header.patientident,80); + edfHdr.recordingident = QString::fromLatin1(hdrPtr->recordingident, 80); // Serial number is in here.. + 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]; + } + + edfHdr.startdate_orig = QDateTime::fromString(QString::fromLatin1(hdrPtr->datetime, 16), "dd.MM.yyHH.mm.ss"); + + 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; + return false; + } + + startdate = qint64(edfHdr.startdate_orig.toTime_t()) * 1000L; + //startdate-=timezoneOffset(); + if (startdate == 0) { + qDebug() << "Invalid startdate = 0 in EDF File" << filename; + return false; + } + + qDebug() << edfHdr.startdate_orig.toString("yyyy-MMM-dd HH:mm:ss") << "in" << filename; + + edfHdr.num_header_bytes = QString::fromLatin1(hdrPtr->num_header_bytes, 8).toLong(&ok); + + if (!ok) { + return false; + } + + edfHdr.reserved44=QString::fromLatin1(hdrPtr->reserved, 44); + edfHdr.num_data_records = QString::fromLatin1(hdrPtr->num_data_records, 8).toLong(&ok); + + if (!ok) { + return false; + } + + edfHdr.duration_Seconds = QString::fromLatin1(hdrPtr->dur_data_records, 8).toLong(&ok); + + if (!ok) { + return false; + } + dur_data_record = (edfHdr.duration_Seconds * 1000.0L); + + edfHdr.num_signals = QString::fromLatin1(hdrPtr->num_signals, 4).toLong(&ok); + + if (!ok) { + return false; + } + + enddate = startdate + dur_data_record * qint64(edfHdr.num_data_records); + // if (dur_data_record==0) + // return false; + + // this could be loaded quicker by transducer_type[signal] etc.. + + // Initialize fixed-size signal list. + edfsignals.resize(edfHdr.num_signals); + + for (auto & sig : edfsignals) { + sig.value = nullptr; + sig.label = Read(16); + + signal_labels.push_back(sig.label); + signalList[sig.label].push_back(&sig); + if (eof) + return false; + } + + for (auto & sig : edfsignals) { + sig.transducer_type = Read(80); + } + for (auto & sig : edfsignals) { + sig.physical_dimension = Read(8); + } + for (auto & sig : edfsignals) { + sig.physical_minimum = Read(8).toDouble(&ok); + } + for (auto & sig : edfsignals) { + sig.physical_maximum = Read(8).toDouble(&ok); + } + for (auto & sig : edfsignals) { + sig.digital_minimum = Read(8).toDouble(&ok); + } + for (auto & sig : edfsignals) { + sig.digital_maximum = Read(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); + } + for (auto & sig : edfsignals) { + sig.nr = Read(8).toLong(&ok); + } + for (auto & sig : edfsignals) { + sig.reserved = Read(32); + } + + // could do it earlier, but it won't crash from > EOF Reads + if (eof) + return false; + + // Now check the file isn't truncated before allocating all the memory + long allocsize = 0; + for (auto & sig : edfsignals) { + if (edfHdr.num_data_records > 0) { + allocsize += sig.nr * edfHdr.num_data_records * 2; + } + } + 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!"; + return false; + } + + // allocate the buffers for the signal values + for (auto & sig : edfsignals) { + long recs = sig.nr * edfHdr.num_data_records; + if (edfHdr.num_data_records <= 0) { + sig.value = nullptr; + continue; + } + sig.value = new qint16 [recs]; + sig.pos = 0; + } + for (int x = 0; x < edfHdr.num_data_records; x++) { + for (auto & sig : edfsignals) { +#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; +#else + // Big endian safe + for (int j=0;jversion, 8).toLong(&ok); - if (!ok) { - return false; - } - - //patientident=QString::fromLatin1(header.patientident,80); - recordingident = QString::fromLatin1(header->recordingident, 80); // Serial number is in here.. - int snp = recordingident.indexOf("SRN="); - serialnumber.clear(); - - for (int i = snp + 4; i < recordingident.length(); i++) { - if (recordingident[i] == ' ') { - break; - } - - serialnumber += recordingident[i]; - } - - startdate_orig = QDateTime::fromString(QString::fromLatin1(header->datetime, 16), "dd.MM.yyHH.mm.ss"); - - QDate d2 = startdate_orig.date(); - - if (d2.year() < 2000) { - d2.setDate(d2.year() + 100, d2.month(), d2.day()); - startdate_orig.setDate(d2); - } - - if (!startdate_orig.isValid()) { - qDebug() << "Invalid date time retreieved parsing EDF File" << filename; - return false; - } - - startdate = qint64(startdate_orig.toTime_t()) * 1000L; - //startdate-=timezoneOffset(); - if (startdate == 0) { - qDebug() << "Invalid startdate = 0 in EDF File" << filename; - return false; - } - - //qDebug() << startDate.toString("yyyy-MM-dd HH:mm:ss"); - - num_header_bytes = QString::fromLatin1(header->num_header_bytes, 8).toLong(&ok); - - if (!ok) { - return false; - } - - //reserved44=QString::fromLatin1(header.reserved,44); - num_data_records = QString::fromLatin1(header->num_data_records, 8).toLong(&ok); - - if (!ok) { - return false; - } - - dur_data_record = (QString::fromLatin1(header->dur_data_records, 8).toDouble(&ok) * 1000.0L); - - if (!ok) { - return false; - } - - num_signals = QString::fromLatin1(header->num_signals, 4).toLong(&ok); - - if (!ok) { - return false; - } - - enddate = startdate + dur_data_record * qint64(num_data_records); - // if (dur_data_record==0) - // return false; - - // this could be loaded quicker by transducer_type[signal] etc.. - - // Initialize fixed-size signal list. - edfsignals.resize(num_signals); - - for (auto & sig : edfsignals) { - sig.data = nullptr; - sig.label = Read(16); - - signal_labels.push_back(sig.label); - signalList[sig.label].push_back(&sig); - if (eof) return false; - } - - for (auto & sig : edfsignals) { sig.transducer_type = Read(80); } - for (auto & sig : edfsignals) { sig.physical_dimension = Read(8); } - for (auto & sig : edfsignals) { sig.physical_minimum = Read(8).toDouble(&ok); } - for (auto & sig : edfsignals) { sig.physical_maximum = Read(8).toDouble(&ok); } - for (auto & sig : edfsignals) { sig.digital_minimum = Read(8).toDouble(&ok); } - for (auto & sig : edfsignals) { sig.digital_maximum = Read(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); } - for (auto & sig : edfsignals) { sig.nr = Read(8).toLong(&ok); } - for (auto & sig : edfsignals) { sig.reserved = Read(32); } - - // could do it earlier, but it won't crash from > EOF Reads - if (eof) return false; - - // Now check the file isn't truncated before allocating all the memory - long allocsize = 0; - for (auto & sig : edfsignals) { - if (num_data_records > 0) { - allocsize += sig.nr * num_data_records * 2; - } - } - 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 truncated!"; - return false; - } - - // allocate the buffers - for (auto & sig : edfsignals) { - long recs = sig.nr * num_data_records; - - if (num_data_records <= 0) { - sig.data = nullptr; - continue; - } - - sig.data = new qint16 [recs]; - sig.pos = 0; - } - - - for (int x = 0; x < num_data_records; x++) { - for (auto & sig : edfsignals) { -#ifdef Q_LITTLE_ENDIAN - // Intel x86, etc.. - memcpy((char *)&sig.data[sig.pos], (char *)&buffer[pos], sig.nr * 2); - sig.pos += sig.nr; - pos += sig.nr * 2; -#else - // Big endian safe - for (int j=0;j EDFHeaderSize) { - header = (EDFHeader *)data.constData(); - buffer = (char *)data.constData() + EDFHeaderSize; - datasize = filesize - EDFHeaderSize; - } else goto badfile; - - pos = 0; - return true; - -badfile: - filesize = 0; - datasize = 0; - buffer = nullptr; - header = nullptr; - data.clear(); - qDebug() << "EDFParser::Open() Couldn't open file" << name; - return false; -} EDFSignal *EDFParser::lookupLabel(const QString & name, int index) { auto it = signalList.find(name); - if (it == signalList.end()) return nullptr; + if (it == signalList.end()) + return nullptr; - if (index >= it.value().size()) return nullptr; + if (index >= it.value().size()) + return nullptr; return it.value()[index]; } -//QMutex EDFParser::EDFMutex; diff --git a/oscar/SleepLib/loader_plugins/edfparser.h b/oscar/SleepLib/loader_plugins/edfparser.h index c19278fd..9247b56e 100644 --- a/oscar/SleepLib/loader_plugins/edfparser.h +++ b/oscar/SleepLib/loader_plugins/edfparser.h @@ -1,5 +1,6 @@ /* EDF Parser Header * + * Copyright (c) 2019 The OSCAR Team * Copyright (c) 2011-2018 Mark Watkins * * This file is subject to the terms and conditions of the GNU General Public @@ -13,7 +14,6 @@ #include #include #include -#include #include "SleepLib/common.h" @@ -24,7 +24,7 @@ const QString STR_ext_gz = ".gz"; \brief Represents the EDF+ header structure, used as a place holder while processing the text data. \note More information on the EDF+ file format can be obtained from http://edfplus.info */ -struct EDFHeader { +struct EDFHeaderRaw { char version[8]; char patientident[80]; char recordingident[80]; @@ -39,8 +39,23 @@ struct EDFHeader { __attribute__((packed)) #endif ; +const int EDFHeaderSize = sizeof(EDFHeaderRaw); -const int EDFHeaderSize = sizeof(EDFHeader); +/*! \struct EDFHeaderQT + \brief Contains the QT version of the EDF header information + */ +struct EDFHeaderQT { + public: + long version; + QString patientident; + QString recordingident; + QDateTime startdate_orig; + long num_header_bytes; + QString reserved44; + long num_data_records; + long duration_Seconds; + long num_signals; +}; /*! \struct EDFSignal \brief Contains information about a single EDF+ Signal @@ -48,47 +63,20 @@ const int EDFHeaderSize = sizeof(EDFHeader); */ struct EDFSignal { public: - //! \brief Name of this Signal - QString label; - - //! \brief Tranducer Type (source of the data, usually blank) - QString transducer_type; - - //! \brief The units of measurements represented by this signal - QString physical_dimension; - - //! \brief The minimum limits of the ungained data - EventDataType physical_minimum; - - //! \brief The maximum limits of the ungained data - EventDataType physical_maximum; - - //! \brief The minimum limits of the data with gain and offset applied - EventDataType digital_minimum; - - //! \brief The maximum limits of the data with gain and offset applied - EventDataType digital_maximum; - - //! \brief Raw integer data is multiplied by this value - EventDataType gain; - - //! \brief This value is added to the raw data - EventDataType offset; - - //! \brief Any prefiltering methods used (usually blank) - QString prefiltering; - - //! \brief Number of records - long nr; - - //! \brief Reserved (usually blank) - QString reserved; - - //! \brief Pointer to the signals sample data - qint16 *data; - - //! \brief a non-EDF extra used internally to count the signal data - int pos; + 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 }; @@ -108,62 +96,62 @@ class EDFParser //! \brief Open the EDF+ file, and read it's header bool Open(const QString & name); + //! \brief Parse the EDF+ file into the list of EDFSignals.. Must be call Open(..) first. + bool Parse(); + //! \brief Read n bytes of 8 bit data from the EDF+ data stream QString Read(unsigned n); //! \brief Read 16 bit word of data from the EDF+ data stream qint16 Read16(); + //! \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); + + //! \brief Returns the number of signals contained in this EDF file + long GetNumSignals() { return edfHdr.num_signals; } + + //! \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; } + +// The data members follow + + //! \brief The header in a QT friendly form + EDFHeaderQT edfHdr; + //! \brief Vector containing the list of EDFSignals contained in this edf file QVector edfsignals; //! \brief An by-name indexed into the EDFSignal data QStringList signal_labels; - //! \brief ResMed likes to use the SAME signal name + //! \brief ResMed sometimes re-uses the SAME signal name QHash > signalList; - EDFSignal *lookupLabel(const QString & name, int index=0); - - //! \brief Returns the number of signals contained in this EDF file - long GetNumSignals() { return num_signals; } - - //! \brief Returns the number of data records contained per signal. - long GetNumDataRecords() { return 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 patientident; } - - //! \brief Parse the EDF+ file into the list of EDFSignals.. Must be call Open(..) first. - bool Parse(); - char *buffer; + //! \brief The following are computed from the edfHdr data + QString serialnumber; + qint64 dur_data_record; + qint64 startdate; + qint64 enddate; +// the following could be private + //! \brief This is the array holding the EDF file data + QByteArray fileData; //! \brief The EDF+ files header structure, used as a place holder while processing the text data. - EDFHeader *header; - QByteArray data; + EDFHeaderRaw *hdrPtr; + //! \brief This is the array of signal descriptors and values + char *signalPtr; QString filename; long filesize; long datasize; long pos; - - long version; - long num_header_bytes; - long num_data_records; - qint64 dur_data_record; - long num_signals; - - QString patientident; - QString recordingident; - QString serialnumber; - QDateTime startdate_orig; - qint64 startdate; - qint64 enddate; - QString reserved44; -// static QMutex EDFMutex; bool eof; }; diff --git a/oscar/SleepLib/loader_plugins/resmed_loader.cpp b/oscar/SleepLib/loader_plugins/resmed_loader.cpp index 9f4d9717..263a85a6 100644 --- a/oscar/SleepLib/loader_plugins/resmed_loader.cpp +++ b/oscar/SleepLib/loader_plugins/resmed_loader.cpp @@ -132,7 +132,7 @@ void ResmedLoader::ParseSTR(Machine *mach, QMap & STRmap) QString & strfile = file.filename; ResMedEDFParser & str = *file.edf; - QDate date = str.startdate_orig.date(); // each STR.edf record starts at 12 noon + QDate date = str.edfHdr.startdate_orig.date(); // each STR.edf record starts at 12 noon qDebug() << "Parsing" << strfile << date << str.GetNumDataRecords() << str.GetNumSignals(); @@ -171,8 +171,8 @@ void ResmedLoader::ParseSTR(Machine *mach, QMap & STRmap) bool validday = false; for (int s = 0; s < maskon->nr; ++s) { - qint32 on = maskon->data[recstart + s]; - qint32 off = maskoff->data[recstart + s]; + qint32 on = maskon->value[recstart + s]; + qint32 off = maskoff->value[recstart + s]; if ((on >= 0) && (off >= 0)) validday=true; } @@ -196,8 +196,8 @@ void ResmedLoader::ParseSTR(Machine *mach, QMap & STRmap) R.maskon.resize(maskon->nr); R.maskoff.resize(maskoff->nr); for (int s = 0; s < maskon->nr; ++s) { - qint32 on = maskon->data[recstart + s]; - qint32 off = maskoff->data[recstart + s]; + qint32 on = maskon->value[recstart + s]; + qint32 off = maskoff->value[recstart + s]; R.maskon[s] = (on>0) ? (timestamp + (on * 60)) : 0; R.maskoff[s] = (off>0) ? (timestamp + (off * 60)) : 0; @@ -216,7 +216,7 @@ void ResmedLoader::ParseSTR(Machine *mach, QMap & STRmap) CPAPMode mode = MODE_UNKNOWN; if ((sig = str.lookupSignal(CPAP_Mode))) { - int mod = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + int mod = EventDataType(sig->value[rec]) * sig->gain + sig->offset; R.rms9_mode = mod; if (mod == 11) { @@ -241,184 +241,184 @@ void ResmedLoader::ParseSTR(Machine *mach, QMap & STRmap) // Settings.CPAP.Starting Pressure if ((mod == 0) && (sig = str.lookupLabel("S.C.StartPress"))) { - R.ramp_pressure = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.ramp_pressure = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } // Settings.Adaptive Starting Pressure? // mode 11 = APAP for her? if (((mod == 1) || (mod == 11)) && (sig = str.lookupLabel("S.AS.StartPress"))) { - R.ramp_pressure = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.ramp_pressure = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((R.mode == MODE_BILEVEL_FIXED) && (sig = str.lookupLabel("S.BL.StartPress"))) { // Bilevel Starting Pressure - R.ramp_pressure = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.ramp_pressure = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if (((R.mode == MODE_ASV) || (R.mode == MODE_ASV_VARIABLE_EPAP)) && (sig = str.lookupLabel("S.VA.StartPress"))) { // Bilevel Starting Pressure - R.ramp_pressure = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.ramp_pressure = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } } if ((sig = str.lookupLabel("Mask Dur"))) { - R.maskdur = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.maskdur = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("Leak Med")) || (sig = str.lookupLabel("Leak.50"))) { float gain = sig->gain * 60.0; - R.leak50 = EventDataType(sig->data[rec]) * gain; + R.leak50 = EventDataType(sig->value[rec]) * gain; } if ((sig = str.lookupLabel("Leak Max"))|| (sig = str.lookupLabel("Leak.Max"))) { float gain = sig->gain * 60.0; - R.leakmax = EventDataType(sig->data[rec]) * gain; + R.leakmax = EventDataType(sig->value[rec]) * gain; } if ((sig = str.lookupLabel("Leak 95")) || (sig = str.lookupLabel("Leak.95"))) { float gain = sig->gain * 60.0; - R.leak95 = EventDataType(sig->data[rec]) * gain; + R.leak95 = EventDataType(sig->value[rec]) * gain; } if ((sig = str.lookupLabel("RespRate.50")) || (sig = str.lookupLabel("RR Med"))) { - R.rr50 = EventDataType(sig->data[rec]) * sig->gain; + R.rr50 = EventDataType(sig->value[rec]) * sig->gain; } if ((sig = str.lookupLabel("RespRate.Max")) || (sig = str.lookupLabel("RR Max"))) { - R.rrmax = EventDataType(sig->data[rec]) * sig->gain; + R.rrmax = EventDataType(sig->value[rec]) * sig->gain; } if ((sig = str.lookupLabel("RespRate.95")) || (sig = str.lookupLabel("RR 95"))) { - R.rr95 = EventDataType(sig->data[rec]) * sig->gain; + R.rr95 = EventDataType(sig->value[rec]) * sig->gain; } if ((sig = str.lookupLabel("MinVent.50")) || (sig = str.lookupLabel("Min Vent Med"))) { - R.mv50 = EventDataType(sig->data[rec]) * sig->gain; + R.mv50 = EventDataType(sig->value[rec]) * sig->gain; } if ((sig = str.lookupLabel("MinVent.Max")) || (sig = str.lookupLabel("Min Vent Max"))) { - R.mvmax = EventDataType(sig->data[rec]) * sig->gain; + R.mvmax = EventDataType(sig->value[rec]) * sig->gain; } if ((sig = str.lookupLabel("MinVent.95")) || (sig = str.lookupLabel("Min Vent 95"))) { - R.mv95 = EventDataType(sig->data[rec]) * sig->gain; + R.mv95 = EventDataType(sig->value[rec]) * sig->gain; } if ((sig = str.lookupLabel("TidVol.50")) || (sig = str.lookupLabel("Tid Vol Med"))) { - R.tv50 = EventDataType(sig->data[rec]) * (sig->gain*1000.0); + R.tv50 = EventDataType(sig->value[rec]) * (sig->gain*1000.0); } if ((sig = str.lookupLabel("TidVol.Max")) || (sig = str.lookupLabel("Tid Vol Max"))) { - R.tvmax = EventDataType(sig->data[rec]) * (sig->gain*1000.0); + R.tvmax = EventDataType(sig->value[rec]) * (sig->gain*1000.0); } if ((sig = str.lookupLabel("TidVol.95")) || (sig = str.lookupLabel("Tid Vol 95"))) { - R.tv95 = EventDataType(sig->data[rec]) * (sig->gain*1000.0); + R.tv95 = EventDataType(sig->value[rec]) * (sig->gain*1000.0); } if ((sig = str.lookupLabel("MaskPress.50")) || (sig = str.lookupLabel("Mask Pres Med"))) { - R.mp50 = EventDataType(sig->data[rec]) * sig->gain; + R.mp50 = EventDataType(sig->value[rec]) * sig->gain; } if ((sig = str.lookupLabel("MaskPress.Max")) || (sig = str.lookupLabel("Mask Pres Max"))) { - R.mpmax = EventDataType(sig->data[rec]) * sig->gain ; + R.mpmax = EventDataType(sig->value[rec]) * sig->gain ; } if ((sig = str.lookupLabel("MaskPress.95")) || (sig = str.lookupLabel("Mask Pres 95"))) { - R.mp95 = EventDataType(sig->data[rec]) * sig->gain ; + R.mp95 = EventDataType(sig->value[rec]) * sig->gain ; } if ((sig = str.lookupLabel("TgtEPAP.50")) || (sig = str.lookupLabel("Exp Pres Med"))) { - R.tgtepap50 = EventDataType(sig->data[rec]) * sig->gain; + R.tgtepap50 = EventDataType(sig->value[rec]) * sig->gain; } if ((sig = str.lookupLabel("TgtEPAP.Max")) || (sig = str.lookupLabel("Exp Pres Max"))) { - R.tgtepapmax = EventDataType(sig->data[rec]) * sig->gain; + R.tgtepapmax = EventDataType(sig->value[rec]) * sig->gain; } if ((sig = str.lookupLabel("TgtEPAP.95")) || (sig = str.lookupLabel("Exp Pres 95"))) { - R.tgtepap95 = EventDataType(sig->data[rec]) * sig->gain; + R.tgtepap95 = EventDataType(sig->value[rec]) * sig->gain; } if ((sig = str.lookupLabel("TgtIPAP.50")) || (sig = str.lookupLabel("Insp Pres Med"))) { - R.tgtipap50 = EventDataType(sig->data[rec]) * sig->gain; + R.tgtipap50 = EventDataType(sig->value[rec]) * sig->gain; } if ((sig = str.lookupLabel("TgtIPAP.Max")) || (sig = str.lookupLabel("Insp Pres Max"))) { - R.tgtipapmax = EventDataType(sig->data[rec]) * sig->gain; + R.tgtipapmax = EventDataType(sig->value[rec]) * sig->gain; } if ((sig = str.lookupLabel("TgtIPAP.95")) || (sig = str.lookupLabel("Insp Pres 95"))) { - R.tgtipap95 = EventDataType(sig->data[rec]) * sig->gain; + R.tgtipap95 = EventDataType(sig->value[rec]) * sig->gain; } if ((sig = str.lookupLabel("I:E Med"))) { - R.ie50 = EventDataType(sig->data[rec]) * sig->gain; + R.ie50 = EventDataType(sig->value[rec]) * sig->gain; } if ((sig = str.lookupLabel("I:E Max"))) { - R.iemax = EventDataType(sig->data[rec]) * sig->gain; + R.iemax = EventDataType(sig->value[rec]) * sig->gain; } if ((sig = str.lookupLabel("I:E 95"))) { - R.ie95 = EventDataType(sig->data[rec]) * sig->gain; + R.ie95 = EventDataType(sig->value[rec]) * sig->gain; } bool haveipap = false; // if (R.mode == MODE_BILEVEL_FIXED) { if ((sig = str.lookupSignal(CPAP_IPAP))) { - R.ipap = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.ipap = EventDataType(sig->value[rec]) * sig->gain + sig->offset; haveipap = true; } if ((sig = str.lookupSignal(CPAP_EPAP))) { - R.epap = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.epap = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if (R.mode == MODE_ASV) { if ((sig = str.lookupLabel("S.AV.StartPress"))) { - EventDataType sp = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + EventDataType sp = EventDataType(sig->value[rec]) * sig->gain + sig->offset; R.ramp_pressure = sp; } if ((sig = str.lookupLabel("S.AV.EPAP"))) { - R.min_epap = R.max_epap = R.epap = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.min_epap = R.max_epap = R.epap = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("S.AV.MinPS"))) { - R.min_ps = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.min_ps = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("S.AV.MaxPS"))) { - R.max_ps = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.max_ps = EventDataType(sig->value[rec]) * sig->gain + sig->offset; R.max_ipap = R.epap + R.max_ps; R.min_ipap = R.epap + R.min_ps; } } if (R.mode == MODE_ASV_VARIABLE_EPAP) { if ((sig = str.lookupLabel("S.AA.StartPress"))) { - EventDataType sp = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + EventDataType sp = EventDataType(sig->value[rec]) * sig->gain + sig->offset; R.ramp_pressure = sp; } if ((sig = str.lookupLabel("S.AA.MinEPAP"))) { - R.min_epap = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.min_epap = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("S.AA.MaxEPAP"))) { - R.max_epap = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.max_epap = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("S.AA.MinPS"))) { - R.min_ps = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.min_ps = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("S.AA.MaxPS"))) { - R.max_ps = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.max_ps = EventDataType(sig->value[rec]) * sig->gain + sig->offset; R.max_ipap = R.max_epap + R.max_ps; R.min_ipap = R.min_epap + R.min_ps; } } if ((sig = str.lookupSignal(CPAP_PressureMax))) { - R.max_pressure = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.max_pressure = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupSignal(CPAP_PressureMin))) { - R.min_pressure = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.min_pressure = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupSignal(RMS9_SetPressure))) { - R.set_pressure = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.set_pressure = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupSignal(CPAP_EPAPHi))) { - R.max_epap = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.max_epap = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupSignal(CPAP_EPAPLo))) { - R.min_epap = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.min_epap = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupSignal(CPAP_IPAPHi))) { - R.max_ipap = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.max_ipap = EventDataType(sig->value[rec]) * sig->gain + sig->offset; haveipap = true; } if ((sig = str.lookupSignal(CPAP_IPAPLo))) { - R.min_ipap = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.min_ipap = EventDataType(sig->value[rec]) * sig->gain + sig->offset; haveipap = true; } if ((sig = str.lookupSignal(CPAP_PS))) { - R.ps = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.ps = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } // } @@ -428,10 +428,10 @@ void ResmedLoader::ParseSTR(Machine *mach, QMap & STRmap) int psvar = (mode == MODE_ASV_VARIABLE_EPAP) ? 1 : 0; if ((sig = str.lookupLabel("Max PS", psvar))) { - R.max_ps = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.max_ps = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("Min PS", psvar))) { - R.min_ps = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.min_ps = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if (!haveipap) { @@ -449,25 +449,25 @@ void ResmedLoader::ParseSTR(Machine *mach, QMap & STRmap) bool a10 = false; if ((mode == MODE_CPAP) || (mode == MODE_APAP)) { if ((sig = str.lookupSignal(RMS9_EPR))) { - epr= EventDataType(sig->data[rec]) * sig->gain + sig->offset; + epr= EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupSignal(RMS9_EPRLevel))) { - epr_level= EventDataType(sig->data[rec]) * sig->gain + sig->offset; + epr_level= EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("S.EPR.EPRType"))) { a10 = true; - epr = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + epr = EventDataType(sig->value[rec]) * sig->gain + sig->offset; epr += 1; } int epr_on=0, clin_epr_on=0; if ((sig = str.lookupLabel("S.EPR.EPREnable"))) { // first check machines opinion a10 = true; - epr_on = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + epr_on = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if (epr_on && (sig = str.lookupLabel("S.EPR.ClinEnable"))) { a10 = true; - clin_epr_on = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + clin_epr_on = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if (a10 && !(epr_on && clin_epr_on)) { epr = 0; @@ -495,71 +495,71 @@ void ResmedLoader::ParseSTR(Machine *mach, QMap & STRmap) } if ((sig = str.lookupLabel("AHI"))) { - R.ahi = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.ahi = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("AI"))) { - R.ai = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.ai = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("HI"))) { - R.hi = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.hi = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("UAI"))) { - R.uai = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.uai = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("CAI"))) { - R.cai = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.cai = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("OAI"))) { - R.oai = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.oai = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("CSR"))) { - R.csr = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.csr = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("S.RampTime"))) { - R.s_RampTime = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.s_RampTime = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("S.RampEnable"))) { - R.s_RampEnable = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.s_RampEnable = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("S.EPR.ClinEnable"))) { - R.s_EPR_ClinEnable = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.s_EPR_ClinEnable = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("S.EPR.EPREnable"))) { - R.s_EPREnable = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.s_EPREnable = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("S.ABFilter"))) { - R.s_ABFilter = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.s_ABFilter = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("S.ClimateControl"))) { - R.s_ClimateControl = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.s_ClimateControl = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("S.Mask"))) { - R.s_Mask = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.s_Mask = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("S.PtAccess"))) { - R.s_PtAccess = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.s_PtAccess = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("S.SmartStart"))) { - R.s_SmartStart = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.s_SmartStart = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("S.HumEnable"))) { - R.s_HumEnable = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.s_HumEnable = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("S.HumLevel"))) { - R.s_HumLevel = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.s_HumLevel = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("S.TempEnable"))) { - R.s_TempEnable = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.s_TempEnable = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("S.Temp"))) { - R.s_Temp = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.s_Temp = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } if ((sig = str.lookupLabel("S.Tube"))) { - R.s_Tube = EventDataType(sig->data[rec]) * sig->gain + sig->offset; + R.s_Tube = EventDataType(sig->value[rec]) * sig->gain + sig->offset; } } } @@ -715,7 +715,7 @@ int PeekAnnotations(const QString & path, quint32 &start, quint32 &end) for (int s = 0; s < edf.GetNumSignals(); s++) { recs = edf.edfsignals[s].nr * edf.GetNumDataRecords() * 2; - data = (char *)edf.edfsignals[s].data; + data = (char *)edf.edfsignals[s].value; pos = 0; tt = edf.startdate; //duration = 0; @@ -1791,7 +1791,7 @@ int ResmedLoader::Open(const QString & dirpath) continue; } - QDate date = stredf->startdate_orig.date(); + QDate date = stredf->edfHdr.startdate_orig.date(); date = QDate(date.year(), date.month(), 1); if (STRmap.contains(date)) { delete stredf; @@ -1869,7 +1869,7 @@ int ResmedLoader::Open(const QString & dirpath) } // Don't trust the filename date, pick the one inside the STR... - date = stredf->startdate_orig.date(); + date = stredf->edfHdr.startdate_orig.date(); date = QDate(date.year(), date.month(), 1); STRmap[date] = STRFile(fi.canonicalFilePath(), stredf); @@ -2145,7 +2145,7 @@ bool ResmedLoader::LoadCSL(Session *sess, const QString & path) for (int s = 0; s < edf.GetNumSignals(); s++) { recs = edf.edfsignals[s].nr * edf.GetNumDataRecords() * 2; - data = (char *)edf.edfsignals[s].data; + data = (char *)edf.edfsignals[s].value; pos = 0; tt = edf.startdate; // sess->updateFirst(tt); @@ -2312,7 +2312,7 @@ bool ResmedLoader::LoadEVE(Session *sess, const QString & path) for (int s = 0; s < edf.GetNumSignals(); s++) { recs = edf.edfsignals[s].nr * edf.GetNumDataRecords() * 2; - data = (char *)edf.edfsignals[s].data; + data = (char *)edf.edfsignals[s].value; pos = 0; tt = edf.startdate; @@ -2495,7 +2495,7 @@ bool ResmedLoader::LoadBRP(Session *sess, const QString & path) #ifdef DEBUG_EFFICIENCY time2.start(); #endif - a->AddWaveform(edf.startdate, es.data, recs, duration); + a->AddWaveform(edf.startdate, es.value, recs, duration); #ifdef DEBUG_EFFICIENCY AddWavetime+= time2.elapsed(); #endif @@ -2552,7 +2552,7 @@ void ResmedLoader::ToTimeDelta(Session *sess, ResMedEDFParser &edf, EDFSignal &e tt += rate * startpos; } - qint16 *sptr = es.data; + qint16 *sptr = es.value; qint16 *eptr = sptr + recs; sptr += startpos; @@ -2709,7 +2709,7 @@ bool ResmedLoader::LoadSAD(Session *sess, const QString & path) bool hasdata = false; for (int i = 0; i < recs; ++i) { - if (es.data[i] != -1) { + if (es.value[i] != -1) { hasdata = true; break; } @@ -2810,7 +2810,7 @@ bool ResmedLoader::LoadPLD(Session *sess, const QString & path) } else if (matchSignal(CPAP_RespRate, es.label)) { code = CPAP_RespRate; a = sess->AddEventList(code, EVL_Waveform, es.gain, es.offset, 0, 0, rate); - a->AddWaveform(edf.startdate, es.data, recs, duration); + a->AddWaveform(edf.startdate, es.value, recs, duration); } else if (matchSignal(CPAP_TidalVolume, es.label)) { code = CPAP_TidalVolume; es.gain *= 1000.0; @@ -2845,9 +2845,9 @@ bool ResmedLoader::LoadPLD(Session *sess, const QString & path) // es.physical_maximum /= 100.0; // es.physical_minimum /= 100.0; // qDebug() << "IE Gain, Max, Min" << es.gain << es.physical_maximum << es.physical_minimum; -// qDebug() << "IE count, data..." << es.nr << es.data[0] << es.data[1] << es.data[2] << es.data[3] << es.data[4]; +// qDebug() << "IE count, data..." << es.nr << es.value[0] << es.value[1] << es.value[2] << es.value[3] << es.value[4]; a = sess->AddEventList(code, EVL_Waveform, es.gain, es.offset, 0, 0, rate); - a->AddWaveform(edf.startdate, es.data, recs, duration); + a->AddWaveform(edf.startdate, es.value, recs, duration); //a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0); } else if (matchSignal(CPAP_Ti, es.label)) { code = CPAP_Ti; @@ -2857,7 +2857,7 @@ bool ResmedLoader::LoadPLD(Session *sess, const QString & path) continue; } a = sess->AddEventList(code, EVL_Waveform, es.gain, es.offset, 0, 0, rate); - a->AddWaveform(edf.startdate, es.data, recs, duration); + a->AddWaveform(edf.startdate, es.value, recs, duration); //a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0); } else if (matchSignal(CPAP_Te, es.label)) { code = CPAP_Te; @@ -2866,12 +2866,12 @@ bool ResmedLoader::LoadPLD(Session *sess, const QString & path) continue; } a = sess->AddEventList(code, EVL_Waveform, es.gain, es.offset, 0, 0, rate); - a->AddWaveform(edf.startdate, es.data, recs, duration); + a->AddWaveform(edf.startdate, es.value, recs, duration); //a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0); } else if (matchSignal(CPAP_TgMV, es.label)) { code = CPAP_TgMV; a = sess->AddEventList(code, EVL_Waveform, es.gain, es.offset, 0, 0, rate); - a->AddWaveform(edf.startdate, es.data, recs, duration); + a->AddWaveform(edf.startdate, es.value, recs, duration); //a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0); } else if (es.label == "") { // What the hell resmed?? if (emptycnt == 0) { diff --git a/oscar/oscar.pro b/oscar/oscar.pro index 990dd9bb..464c9814 100644 --- a/oscar/oscar.pro +++ b/oscar/oscar.pro @@ -459,7 +459,13 @@ test { CONFIG -= app_bundle !win32 { # add memory checking on Linux and macOS test builds QMAKE_CFLAGS += -Werror -fsanitize=address -fno-omit-frame-pointer -fno-common -fsanitize-address-use-after-scope + lessThan(QT_MAJOR_VERSION,5)|lessThan(QT_MINOR_VERSION,9) { + QMAKE_CFLAGS -= -fsanitize-address-use-after-scope + } QMAKE_CXXFLAGS += -Werror -fsanitize=address -fno-omit-frame-pointer -fno-common -fsanitize-address-use-after-scope + lessThan(QT_MAJOR_VERSION,5)|lessThan(QT_MINOR_VERSION,9) { + QMAKE_CXXFLAGS -= -fsanitize-address-use-after-scope + } QMAKE_LFLAGS += -fsanitize=address }