2011-06-28 02:21:38 +00:00
|
|
|
/*
|
|
|
|
|
|
|
|
SleepLib ResMed Loader Implementation
|
|
|
|
|
|
|
|
Author: Mark Watkins <jedimark64@users.sourceforge.net>
|
|
|
|
License: GPL
|
|
|
|
*/
|
|
|
|
|
2011-07-30 00:36:31 +00:00
|
|
|
|
|
|
|
#include <QApplication>
|
2011-06-28 02:21:38 +00:00
|
|
|
#include <QString>
|
|
|
|
#include <QDateTime>
|
|
|
|
#include <QDir>
|
|
|
|
#include <QFile>
|
|
|
|
#include <QMessageBox>
|
|
|
|
#include <QProgressBar>
|
2011-07-01 10:10:44 +00:00
|
|
|
#include <QDebug>
|
2011-07-27 09:21:53 +00:00
|
|
|
#include <cmath>
|
2011-06-28 02:21:38 +00:00
|
|
|
|
|
|
|
#include "resmed_loader.h"
|
|
|
|
#include "SleepLib/session.h"
|
|
|
|
|
2011-06-30 04:55:20 +00:00
|
|
|
extern QProgressBar *qprogress;
|
2011-07-31 20:24:43 +00:00
|
|
|
QHash<int,QString> RMS9ModelMap;
|
2011-09-23 03:54:48 +00:00
|
|
|
QHash<ChannelID, QVector<QString> > resmed_codes;
|
2011-06-30 04:55:20 +00:00
|
|
|
|
2011-11-25 12:13:35 +00:00
|
|
|
EDFSignal * EDFParser::lookupSignal(ChannelID ch)
|
|
|
|
{
|
|
|
|
QHash<ChannelID, QVector<QString> >::iterator ci;
|
|
|
|
QHash<QString,EDFSignal *>::iterator jj;
|
|
|
|
ci=resmed_codes.find(ch);
|
|
|
|
if (ci==resmed_codes.end()) return NULL;
|
|
|
|
for (int i=0;i<ci.value().size();i++) {
|
|
|
|
jj=lookup.find(ci.value()[i]);
|
|
|
|
if (jj==lookup.end()) continue;
|
|
|
|
return jj.value();
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-06-29 14:19:38 +00:00
|
|
|
EDFParser::EDFParser(QString name)
|
|
|
|
{
|
|
|
|
buffer=NULL;
|
|
|
|
Open(name);
|
|
|
|
}
|
|
|
|
EDFParser::~EDFParser()
|
|
|
|
{
|
2011-07-31 20:24:43 +00:00
|
|
|
QVector<EDFSignal *>::iterator s;
|
2011-06-29 14:19:38 +00:00
|
|
|
for (s=edfsignals.begin();s!=edfsignals.end();s++) {
|
|
|
|
if ((*s)->data) delete [] (*s)->data;
|
|
|
|
delete *s;
|
|
|
|
}
|
|
|
|
if (buffer) delete [] buffer;
|
|
|
|
}
|
2011-06-29 16:19:57 +00:00
|
|
|
qint16 EDFParser::Read16()
|
|
|
|
{
|
|
|
|
unsigned char *buf=(unsigned char *)buffer;
|
|
|
|
if (pos>=filesize) return 0;
|
|
|
|
qint16 res=*(qint16 *)&buf[pos];
|
|
|
|
//qint16 res=(buf[pos] ^128)<< 8 | buf[pos+1] ^ 128;
|
|
|
|
pos+=2;
|
|
|
|
return res;
|
|
|
|
}
|
2011-06-29 14:19:38 +00:00
|
|
|
QString EDFParser::Read(int si)
|
|
|
|
{
|
|
|
|
QString str;
|
|
|
|
if (pos>=filesize) return "";
|
|
|
|
for (int i=0;i<si;i++) {
|
|
|
|
str+=buffer[pos++];
|
|
|
|
}
|
|
|
|
return str.trimmed();
|
|
|
|
}
|
|
|
|
bool EDFParser::Parse()
|
|
|
|
{
|
|
|
|
bool ok;
|
|
|
|
QString temp,temp2;
|
2011-07-02 14:35:50 +00:00
|
|
|
|
|
|
|
version=QString::fromAscii(header.version,8).toLong(&ok);
|
2011-06-29 14:19:38 +00:00
|
|
|
if (!ok)
|
|
|
|
return false;
|
|
|
|
|
2011-07-02 14:35:50 +00:00
|
|
|
//patientident=QString::fromAscii(header.patientident,80);
|
2011-07-05 05:37:11 +00:00
|
|
|
recordingident=QString::fromAscii(header.recordingident,80); // Serial number is in here..
|
|
|
|
int snp=recordingident.indexOf("SRN=");
|
2011-07-02 14:35:50 +00:00
|
|
|
serialnumber.clear();
|
2011-07-05 05:37:11 +00:00
|
|
|
/*char * idx=index(header.recordingident,'=');
|
|
|
|
idx++;
|
2011-07-02 14:35:50 +00:00
|
|
|
for (int i=0;i<16;++i) {
|
|
|
|
if (*idx==0x20) break;
|
|
|
|
serialnumber+=*idx;
|
|
|
|
++idx;
|
2011-07-05 05:37:11 +00:00
|
|
|
} */
|
2011-07-02 14:35:50 +00:00
|
|
|
|
2011-07-05 05:37:11 +00:00
|
|
|
for (int i=snp+4;i<recordingident.length();i++) {
|
|
|
|
if (recordingident[i]==' ')
|
|
|
|
break;
|
|
|
|
serialnumber+=recordingident[i];
|
|
|
|
}
|
2011-07-03 06:10:45 +00:00
|
|
|
QDateTime startDate=QDateTime::fromString(QString::fromAscii(header.datetime,16),"dd.MM.yyHH.mm.ss");
|
2011-07-02 14:35:50 +00:00
|
|
|
QDate d2=startDate.date();
|
2011-06-29 16:19:57 +00:00
|
|
|
if (d2.year()<2000) {
|
|
|
|
d2.setYMD(d2.year()+100,d2.month(),d2.day());
|
2011-07-02 14:35:50 +00:00
|
|
|
startDate.setDate(d2);
|
2011-06-29 16:19:57 +00:00
|
|
|
}
|
2011-07-02 14:35:50 +00:00
|
|
|
if (!startDate.isValid()) {
|
2011-07-01 10:10:44 +00:00
|
|
|
qDebug() << "Invalid date time retreieved parsing EDF File " << filename;
|
2011-06-29 16:19:57 +00:00
|
|
|
return false;
|
|
|
|
}
|
2011-09-01 13:07:26 +00:00
|
|
|
startdate=qint64(startDate.toTime_t())*1000L;
|
2011-06-29 16:19:57 +00:00
|
|
|
|
2011-07-21 03:38:17 +00:00
|
|
|
//qDebug() << startDate.toString("yyyy-MM-dd HH:mm:ss");
|
2011-06-29 16:19:57 +00:00
|
|
|
|
2011-07-02 14:35:50 +00:00
|
|
|
num_header_bytes=QString::fromAscii(header.num_header_bytes,8).toLong(&ok);
|
2011-06-29 14:19:38 +00:00
|
|
|
if (!ok)
|
|
|
|
return false;
|
2011-07-02 14:35:50 +00:00
|
|
|
//reserved44=QString::fromAscii(header.reserved,44);
|
|
|
|
num_data_records=QString::fromAscii(header.num_data_records,8).toLong(&ok);
|
2011-06-29 14:19:38 +00:00
|
|
|
if (!ok)
|
|
|
|
return false;
|
2011-07-27 09:21:53 +00:00
|
|
|
|
2011-07-02 14:35:50 +00:00
|
|
|
dur_data_record=QString::fromAscii(header.dur_data_records,8).toDouble(&ok)*1000.0;
|
2011-06-29 14:19:38 +00:00
|
|
|
if (!ok)
|
|
|
|
return false;
|
2011-07-02 14:35:50 +00:00
|
|
|
num_signals=QString::fromAscii(header.num_signals,4).toLong(&ok);
|
2011-06-29 14:19:38 +00:00
|
|
|
if (!ok)
|
|
|
|
return false;
|
|
|
|
|
2011-07-03 02:43:50 +00:00
|
|
|
enddate=startdate+dur_data_record*qint64(num_data_records);
|
2011-07-03 03:53:09 +00:00
|
|
|
// if (dur_data_record==0)
|
|
|
|
// return false;
|
2011-07-02 14:35:50 +00:00
|
|
|
|
|
|
|
// this could be loaded quicker by transducer_type[signal] etc..
|
|
|
|
|
2011-06-29 14:19:38 +00:00
|
|
|
for (int i=0;i<num_signals;i++) {
|
|
|
|
EDFSignal *signal=new EDFSignal;
|
|
|
|
edfsignals.push_back(signal);
|
|
|
|
signal->data=NULL;
|
|
|
|
edfsignals[i]->label=Read(16);
|
2011-09-17 12:39:00 +00:00
|
|
|
lookup[edfsignals[i]->label]=signal;
|
2011-06-29 14:19:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (int i=0;i<num_signals;i++) edfsignals[i]->transducer_type=Read(80);
|
2011-07-27 09:21:53 +00:00
|
|
|
|
2011-06-29 14:19:38 +00:00
|
|
|
for (int i=0;i<num_signals;i++) edfsignals[i]->physical_dimension=Read(8);
|
2011-07-27 09:21:53 +00:00
|
|
|
for (int i=0;i<num_signals;i++) edfsignals[i]->physical_minimum=Read(8).toDouble(&ok);
|
|
|
|
for (int i=0;i<num_signals;i++) edfsignals[i]->physical_maximum=Read(8).toDouble(&ok);
|
|
|
|
for (int i=0;i<num_signals;i++) edfsignals[i]->digital_minimum=Read(8).toDouble(&ok);
|
|
|
|
for (int i=0;i<num_signals;i++) {
|
|
|
|
EDFSignal & e=*edfsignals[i];
|
|
|
|
e.digital_maximum=Read(8).toDouble(&ok);
|
|
|
|
e.gain=(e.physical_maximum-e.physical_minimum)/(e.digital_maximum-e.digital_minimum);
|
|
|
|
e.offset=0;
|
|
|
|
}
|
|
|
|
|
2011-06-29 14:19:38 +00:00
|
|
|
for (int i=0;i<num_signals;i++) edfsignals[i]->prefiltering=Read(80);
|
|
|
|
for (int i=0;i<num_signals;i++) edfsignals[i]->nr=Read(8).toLong(&ok);
|
|
|
|
for (int i=0;i<num_signals;i++) edfsignals[i]->reserved=Read(32);
|
|
|
|
|
2011-06-29 16:19:57 +00:00
|
|
|
// allocate the buffers
|
2011-06-29 14:19:38 +00:00
|
|
|
for (int i=0;i<num_signals;i++) {
|
|
|
|
//qDebug//cout << "Reading signal " << signals[i]->label << endl;
|
2011-06-29 16:19:57 +00:00
|
|
|
EDFSignal & sig=*edfsignals[i];
|
|
|
|
|
|
|
|
long recs=sig.nr * num_data_records;
|
|
|
|
if (num_data_records<0)
|
|
|
|
return false;
|
|
|
|
sig.data=new qint16 [recs];
|
|
|
|
sig.pos=0;
|
|
|
|
}
|
2011-06-29 14:19:38 +00:00
|
|
|
|
2011-06-29 16:19:57 +00:00
|
|
|
for (int x=0;x<num_data_records;x++) {
|
|
|
|
for (int i=0;i<num_signals;i++) {
|
|
|
|
EDFSignal & sig=*edfsignals[i];
|
2011-06-30 10:56:22 +00:00
|
|
|
memcpy((char *)&sig.data[sig.pos],(char *)&buffer[pos],sig.nr*2);
|
|
|
|
sig.pos+=sig.nr;
|
|
|
|
pos+=sig.nr*2;
|
2011-07-02 14:35:50 +00:00
|
|
|
// big endian will screw up without this..
|
2011-06-30 10:56:22 +00:00
|
|
|
/*for (int j=0;j<sig.nr;j++) {
|
2011-06-29 16:19:57 +00:00
|
|
|
qint16 t=Read16();
|
|
|
|
sig.data[sig.pos++]=t;
|
2011-06-30 10:56:22 +00:00
|
|
|
} */
|
2011-06-29 14:19:38 +00:00
|
|
|
}
|
|
|
|
}
|
2011-06-29 16:19:57 +00:00
|
|
|
|
2011-06-29 14:19:38 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool EDFParser::Open(QString name)
|
|
|
|
{
|
|
|
|
QFile f(name);
|
|
|
|
if (!f.open(QIODevice::ReadOnly)) return false;
|
|
|
|
if (!f.isReadable()) return false;
|
|
|
|
filename=name;
|
|
|
|
filesize=f.size();
|
2011-07-02 14:35:50 +00:00
|
|
|
datasize=filesize-EDFHeaderSize;
|
|
|
|
if (datasize<0) return false;
|
|
|
|
f.read((char *)&header,EDFHeaderSize);
|
2011-07-01 10:10:44 +00:00
|
|
|
//qDebug() << "Opening " << name;
|
2011-07-02 14:35:50 +00:00
|
|
|
buffer=new char [datasize];
|
|
|
|
f.read(buffer,datasize);
|
2011-06-29 14:19:38 +00:00
|
|
|
f.close();
|
|
|
|
pos=0;
|
2011-06-29 16:19:57 +00:00
|
|
|
return true;
|
2011-06-29 14:19:38 +00:00
|
|
|
}
|
|
|
|
|
2011-06-28 02:21:38 +00:00
|
|
|
ResmedLoader::ResmedLoader()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
ResmedLoader::~ResmedLoader()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Machine *ResmedLoader::CreateMachine(QString serial,Profile *profile)
|
|
|
|
{
|
2011-07-24 16:34:53 +00:00
|
|
|
if (!profile) return NULL;
|
2011-07-31 20:24:43 +00:00
|
|
|
QVector<Machine *> ml=profile->GetMachines(MT_CPAP);
|
2011-06-28 02:21:38 +00:00
|
|
|
bool found=false;
|
2011-07-31 20:24:43 +00:00
|
|
|
QVector<Machine *>::iterator i;
|
|
|
|
for (i=ml.begin(); i!=ml.end(); i++) {
|
2011-06-29 14:19:38 +00:00
|
|
|
if (((*i)->GetClass()==resmed_class_name) && ((*i)->properties["Serial"]==serial)) {
|
2011-06-28 02:21:38 +00:00
|
|
|
ResmedList[serial]=*i; //static_cast<CPAP *>(*i);
|
|
|
|
found=true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-07-31 20:24:43 +00:00
|
|
|
if (found) return *i;
|
2011-06-28 02:21:38 +00:00
|
|
|
|
2011-07-01 10:10:44 +00:00
|
|
|
qDebug() << "Create ResMed Machine" << serial;
|
2011-06-28 02:21:38 +00:00
|
|
|
Machine *m=new CPAP(profile,0);
|
2011-06-29 14:19:38 +00:00
|
|
|
m->SetClass(resmed_class_name);
|
2011-06-28 02:21:38 +00:00
|
|
|
|
|
|
|
ResmedList[serial]=m;
|
|
|
|
profile->AddMachine(m);
|
|
|
|
|
|
|
|
m->properties["Serial"]=serial;
|
2011-06-29 14:19:38 +00:00
|
|
|
m->properties["Brand"]="ResMed";
|
2011-07-24 17:18:10 +00:00
|
|
|
QString a;
|
|
|
|
a.sprintf("%i",resmed_data_version);
|
|
|
|
m->properties["DataVersion"]=a;
|
2011-06-28 02:21:38 +00:00
|
|
|
|
|
|
|
return m;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-07-02 14:35:50 +00:00
|
|
|
long event_cnt=0;
|
|
|
|
|
2011-07-15 13:30:41 +00:00
|
|
|
int ResmedLoader::Open(QString & path,Profile *profile)
|
2011-06-28 02:21:38 +00:00
|
|
|
{
|
|
|
|
QString newpath;
|
|
|
|
|
|
|
|
QString dirtag="DATALOG";
|
2011-11-21 02:15:10 +00:00
|
|
|
if (path.endsWith(QDir::separator()+dirtag)) {
|
2011-07-15 13:30:41 +00:00
|
|
|
return 0; // id10t user..
|
2011-06-29 19:06:49 +00:00
|
|
|
//newpath=path;
|
2011-06-28 02:21:38 +00:00
|
|
|
} else {
|
2011-11-21 02:15:10 +00:00
|
|
|
newpath=path+QDir::separator()+dirtag;
|
2011-06-28 02:21:38 +00:00
|
|
|
}
|
2011-11-21 02:15:10 +00:00
|
|
|
QString idfile=path+QDir::separator()+"Identification.tgt";
|
2011-06-29 19:06:49 +00:00
|
|
|
QFile f(idfile);
|
2011-07-31 20:24:43 +00:00
|
|
|
QHash<QString,QString> idmap;
|
2011-06-29 19:06:49 +00:00
|
|
|
if (f.open(QIODevice::ReadOnly)) {
|
|
|
|
if (!f.isReadable())
|
2011-07-15 13:30:41 +00:00
|
|
|
return 0;
|
2011-06-30 10:56:22 +00:00
|
|
|
|
2011-06-29 19:06:49 +00:00
|
|
|
while (!f.atEnd()) {
|
|
|
|
QString line=f.readLine().trimmed();
|
|
|
|
QString key,value;
|
|
|
|
if (!line.isEmpty()) {
|
|
|
|
key=line.section(" ",0,0);
|
|
|
|
value=line.section(" ",1);
|
|
|
|
key=key.section("#",1);
|
|
|
|
idmap[key]=value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-11-21 02:15:10 +00:00
|
|
|
QString strfile=path+QDir::separator()+"STR.edf";
|
2011-09-17 12:39:00 +00:00
|
|
|
EDFParser stredf(strfile);
|
|
|
|
|
|
|
|
if (!stredf.Parse()) {
|
|
|
|
qDebug() << "Faulty file" << strfile;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
qint64 duration=stredf.GetNumDataRecords()*stredf.GetDuration();
|
|
|
|
int days=duration/86400000L;
|
|
|
|
|
|
|
|
QDateTime dt1=QDateTime::fromTime_t(stredf.startdate/1000L);
|
|
|
|
QDateTime dt2=QDateTime::fromTime_t(stredf.enddate/1000L);
|
2011-10-21 05:50:31 +00:00
|
|
|
//QDate dd1=dt1.date();
|
|
|
|
//QDate dd2=dt2.date();
|
2011-09-17 12:39:00 +00:00
|
|
|
for (int s=0;s<stredf.GetNumSignals();s++) {
|
2011-10-21 05:50:31 +00:00
|
|
|
//EDFSignal & es=*stredf.edfsignals[s];
|
2011-09-17 12:39:00 +00:00
|
|
|
long recs=stredf.edfsignals[s]->nr*stredf.GetNumDataRecords();
|
|
|
|
|
|
|
|
qDebug() << "STREDF:" << stredf.edfsignals[s]->label << recs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-06-28 02:21:38 +00:00
|
|
|
QDir dir(newpath);
|
|
|
|
|
|
|
|
if ((!dir.exists() || !dir.isReadable()))
|
|
|
|
return 0;
|
|
|
|
|
2011-07-01 10:10:44 +00:00
|
|
|
qDebug() << "ResmedLoader::Open newpath=" << newpath;
|
2011-06-29 14:19:38 +00:00
|
|
|
dir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks);
|
2011-06-28 02:21:38 +00:00
|
|
|
dir.setSorting(QDir::Name);
|
|
|
|
QFileInfoList flist=dir.entryInfoList();
|
2011-08-01 08:22:37 +00:00
|
|
|
QMap<SessionID,QVector<QString> > sessfiles;
|
2011-06-29 16:19:57 +00:00
|
|
|
|
2011-06-29 14:19:38 +00:00
|
|
|
QString ext,rest,datestr,s,codestr;
|
|
|
|
SessionID sessionid;
|
|
|
|
QDateTime date;
|
2011-06-30 10:56:22 +00:00
|
|
|
QString filename;
|
2011-06-30 04:55:20 +00:00
|
|
|
int size=flist.size();
|
|
|
|
for (int i=0;i<size;i++) {
|
2011-06-28 02:21:38 +00:00
|
|
|
QFileInfo fi=flist.at(i);
|
2011-06-30 10:56:22 +00:00
|
|
|
filename=fi.fileName();
|
2011-06-29 14:19:38 +00:00
|
|
|
ext=filename.section(".",1).toLower();
|
|
|
|
if (ext!="edf") continue;
|
2011-06-29 16:19:57 +00:00
|
|
|
|
2011-06-29 14:19:38 +00:00
|
|
|
rest=filename.section(".",0,0);
|
|
|
|
datestr=filename.section("_",0,1);
|
|
|
|
date=QDateTime::fromString(datestr,"yyyyMMdd_HHmmss");
|
|
|
|
sessionid=date.toTime_t();
|
2011-06-29 21:23:00 +00:00
|
|
|
// Resmed bugs up on the session filenames.. 1 second either way
|
|
|
|
if (sessfiles.find(sessionid)==sessfiles.end()) {
|
2011-08-01 08:22:37 +00:00
|
|
|
if (sessfiles.find(sessionid+2)!=sessfiles.end()) sessionid+=2;
|
|
|
|
else if (sessfiles.find(sessionid+1)!=sessfiles.end()) sessionid++;
|
|
|
|
else if (sessfiles.find(sessionid-1)!=sessfiles.end()) sessionid--;
|
|
|
|
else if (sessfiles.find(sessionid-2)!=sessfiles.end()) sessionid-=2;
|
2011-06-29 21:23:00 +00:00
|
|
|
}
|
2011-06-29 14:19:38 +00:00
|
|
|
|
2011-06-29 16:19:57 +00:00
|
|
|
sessfiles[sessionid].push_back(fi.canonicalFilePath());
|
2011-06-30 04:55:20 +00:00
|
|
|
if (qprogress) qprogress->setValue((float(i+1)/float(size)*33.0));
|
2011-07-30 00:36:31 +00:00
|
|
|
QApplication::processEvents();
|
|
|
|
|
2011-06-29 16:19:57 +00:00
|
|
|
}
|
2011-06-29 14:19:38 +00:00
|
|
|
|
2011-06-29 16:19:57 +00:00
|
|
|
Machine *m=NULL;
|
|
|
|
|
2011-06-30 10:56:22 +00:00
|
|
|
QString fn;
|
2011-07-03 03:53:09 +00:00
|
|
|
Session *sess;
|
2011-06-30 04:55:20 +00:00
|
|
|
int cnt=0;
|
|
|
|
size=sessfiles.size();
|
2011-08-01 08:22:37 +00:00
|
|
|
for (QMap<SessionID,QVector<QString> >::iterator si=sessfiles.begin();si!=sessfiles.end();si++) {
|
2011-07-31 20:24:43 +00:00
|
|
|
sessionid=si.key();
|
2011-07-01 10:10:44 +00:00
|
|
|
//qDebug() << "Parsing Session " << sessionid;
|
2011-06-29 16:19:57 +00:00
|
|
|
bool done=false;
|
|
|
|
bool first=true;
|
2011-07-03 03:53:09 +00:00
|
|
|
sess=NULL;
|
2011-07-31 20:24:43 +00:00
|
|
|
for (int i=0;i<si.value().size();++i) {
|
|
|
|
fn=si.value()[i].section("_",-1).toLower();
|
|
|
|
EDFParser edf(si.value()[i]);
|
2011-07-01 10:10:44 +00:00
|
|
|
//qDebug() << "Parsing File " << i << " " << edf.filesize;
|
2011-06-29 16:19:57 +00:00
|
|
|
|
|
|
|
if (!edf.Parse())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (first) { // First EDF file parsed, check if this data set is already imported
|
|
|
|
m=CreateMachine(edf.serialnumber,profile);
|
2011-07-31 20:24:43 +00:00
|
|
|
for (QHash<QString,QString>::iterator i=idmap.begin();i!=idmap.end();i++) {
|
|
|
|
if (i.key()=="SRN") {
|
|
|
|
if (edf.serialnumber!=i.value()) {
|
2011-07-01 10:10:44 +00:00
|
|
|
qDebug() << "edf Serial number doesn't match Identification.tgt";
|
2011-06-29 19:06:49 +00:00
|
|
|
}
|
2011-09-17 12:39:00 +00:00
|
|
|
if (edf.serialnumber!=stredf.serialnumber) {
|
|
|
|
qDebug() << "edf Serial number doesn't match STR.edf!";
|
|
|
|
}
|
2011-07-31 20:24:43 +00:00
|
|
|
} else if (i.key()=="PNA") {
|
|
|
|
m->properties["Model"]=i.value();
|
|
|
|
} else if (i.key()=="PCD") {
|
2011-07-03 04:22:58 +00:00
|
|
|
bool ok;
|
2011-07-31 20:24:43 +00:00
|
|
|
int j=i.value().toInt(&ok);
|
2011-07-03 04:22:58 +00:00
|
|
|
if (RMS9ModelMap.find(j)!=RMS9ModelMap.end()) {
|
|
|
|
m->properties["SubModel"]=RMS9ModelMap[j];
|
|
|
|
}
|
2011-06-29 19:06:49 +00:00
|
|
|
} else {
|
2011-07-31 20:24:43 +00:00
|
|
|
m->properties[i.key()]=i.value();
|
2011-06-29 19:06:49 +00:00
|
|
|
}
|
|
|
|
}
|
2011-06-29 16:19:57 +00:00
|
|
|
if (m->SessionExists(sessionid)) {
|
|
|
|
done=true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
sess=new Session(m,sessionid);
|
2011-07-03 03:53:09 +00:00
|
|
|
first=false;
|
2011-06-29 16:19:57 +00:00
|
|
|
}
|
|
|
|
if (!done) {
|
2011-07-01 10:10:44 +00:00
|
|
|
if (fn=="eve.edf") LoadEVE(sess,edf);
|
|
|
|
else if (fn=="pld.edf") LoadPLD(sess,edf);
|
|
|
|
else if (fn=="brp.edf") LoadBRP(sess,edf);
|
|
|
|
else if (fn=="sad.edf") LoadSAD(sess,edf);
|
2011-07-02 14:35:50 +00:00
|
|
|
|
2011-07-03 03:53:09 +00:00
|
|
|
//if (first) {
|
|
|
|
//first=false;
|
|
|
|
//}
|
2011-06-29 16:19:57 +00:00
|
|
|
}
|
2011-06-29 14:19:38 +00:00
|
|
|
}
|
2011-07-03 03:53:09 +00:00
|
|
|
if (qprogress) qprogress->setValue(33.0+(float(++cnt)/float(size)*33.0));
|
2011-07-30 00:36:31 +00:00
|
|
|
QApplication::processEvents();
|
|
|
|
|
2011-11-25 12:13:35 +00:00
|
|
|
EDFSignal *sig;
|
2011-07-03 03:53:09 +00:00
|
|
|
if (!sess) continue;
|
|
|
|
if (!sess->first()) {
|
|
|
|
delete sess;
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
sess->SetChanged(true);
|
2011-09-17 12:39:00 +00:00
|
|
|
qint64 dif=sess->first()-stredf.startdate;
|
|
|
|
int dn=dif/86400000L;
|
|
|
|
if (dn<days) {
|
|
|
|
int mode;
|
2011-11-25 12:13:35 +00:00
|
|
|
sig=stredf.lookupSignal(CPAP_Mode);
|
|
|
|
if (sig) {
|
|
|
|
mode=sig->data[dn];
|
|
|
|
} else mode=0;
|
2011-10-21 05:50:31 +00:00
|
|
|
|
|
|
|
// AutoSV machines don't have both fields
|
2011-11-25 12:13:35 +00:00
|
|
|
sig=stredf.lookupSignal("EPR");
|
|
|
|
if (sig) {
|
|
|
|
sess->settings["EPR"]=sig->data[dn];
|
|
|
|
}
|
|
|
|
|
|
|
|
sig=stredf.lookupSignal("EPRLevel");
|
|
|
|
if (sig) {
|
|
|
|
sess->settings["EPRSet"]=sig->data[dn];
|
|
|
|
}
|
2011-09-17 12:39:00 +00:00
|
|
|
|
|
|
|
if (mode==0) {
|
2011-09-18 15:43:14 +00:00
|
|
|
sess->settings[CPAP_Mode]=MODE_CPAP;
|
2011-11-25 12:13:35 +00:00
|
|
|
sig=stredf.lookupSignal("Set Pressure");
|
|
|
|
if (sig) {
|
|
|
|
EventDataType pressure=sig->data[dn]*sig->gain;
|
|
|
|
sess->settings[CPAP_Pressure]=pressure;
|
|
|
|
sess->setWavg(CPAP_Pressure,pressure);
|
|
|
|
sess->setAvg(CPAP_Pressure,pressure);
|
|
|
|
sess->set90p(CPAP_Pressure,pressure);
|
|
|
|
sess->setMax(CPAP_Pressure,pressure);
|
|
|
|
sess->setMin(CPAP_Pressure,pressure);
|
|
|
|
}
|
2011-09-17 12:39:00 +00:00
|
|
|
} else {
|
|
|
|
if (mode>5) {
|
|
|
|
sess->settings[CPAP_Mode]=MODE_BIPAP;
|
|
|
|
} else {
|
|
|
|
sess->settings[CPAP_Mode]=MODE_APAP;
|
|
|
|
}
|
2011-11-25 12:13:35 +00:00
|
|
|
|
|
|
|
sig=stredf.lookupSignal(CPAP_PressureMin);
|
2011-09-17 12:39:00 +00:00
|
|
|
if (sig)
|
|
|
|
sess->setMin(CPAP_Pressure,sig->data[dn]*sig->gain);
|
2011-11-25 12:13:35 +00:00
|
|
|
|
|
|
|
sig=stredf.lookupSignal(CPAP_PressureMax);
|
2011-09-17 12:39:00 +00:00
|
|
|
if (sig)
|
|
|
|
sess->setMax(CPAP_Pressure,sig->data[dn]*sig->gain);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2011-07-03 03:53:09 +00:00
|
|
|
m->AddSession(sess,profile); // Adding earlier than I really like here..
|
|
|
|
}
|
2011-09-17 12:39:00 +00:00
|
|
|
}
|
2011-06-30 09:37:24 +00:00
|
|
|
|
2011-09-17 12:39:00 +00:00
|
|
|
if (m) {
|
|
|
|
m->Save();
|
2011-06-28 02:21:38 +00:00
|
|
|
}
|
2011-06-30 04:55:20 +00:00
|
|
|
if (qprogress) qprogress->setValue(100);
|
2011-07-02 14:35:50 +00:00
|
|
|
qDebug() << "Total Events " << event_cnt;
|
2011-07-15 13:30:41 +00:00
|
|
|
return 1;
|
2011-06-28 02:21:38 +00:00
|
|
|
}
|
2011-06-29 17:58:28 +00:00
|
|
|
|
2011-07-01 10:10:44 +00:00
|
|
|
bool ResmedLoader::LoadEVE(Session *sess,EDFParser &edf)
|
2011-06-29 14:19:38 +00:00
|
|
|
{
|
2011-07-27 09:21:53 +00:00
|
|
|
// EVEnt records have useless duration record.
|
|
|
|
|
2011-06-29 14:19:38 +00:00
|
|
|
QString t;
|
2011-06-30 10:56:22 +00:00
|
|
|
long recs;
|
2011-07-27 09:21:53 +00:00
|
|
|
double duration;
|
2011-06-30 10:56:22 +00:00
|
|
|
char * data;
|
|
|
|
char c;
|
|
|
|
long pos;
|
|
|
|
bool sign,ok;
|
|
|
|
double d;
|
2011-07-02 15:48:55 +00:00
|
|
|
double tt;
|
2011-07-31 20:24:43 +00:00
|
|
|
ChannelID code;
|
2011-07-01 10:10:44 +00:00
|
|
|
//Event *e;
|
2011-07-27 09:21:53 +00:00
|
|
|
//totaldur=edf.GetNumDataRecords()*edf.GetDuration();
|
2011-07-02 14:35:50 +00:00
|
|
|
|
2011-07-27 09:21:53 +00:00
|
|
|
EventList *EL[4]={NULL};
|
2011-07-31 20:24:43 +00:00
|
|
|
sess->updateFirst(edf.startdate);
|
2011-07-03 03:53:09 +00:00
|
|
|
//if (edf.enddate>edf.startdate) sess->set_last(edf.enddate);
|
2011-06-29 14:19:38 +00:00
|
|
|
for (int s=0;s<edf.GetNumSignals();s++) {
|
2011-06-30 10:56:22 +00:00
|
|
|
recs=edf.edfsignals[s]->nr*edf.GetNumDataRecords()*2;
|
2011-07-02 09:49:53 +00:00
|
|
|
|
2011-07-01 10:10:44 +00:00
|
|
|
//qDebug() << edf.edfsignals[s]->label << " " << t;
|
2011-06-30 10:56:22 +00:00
|
|
|
data=(char *)edf.edfsignals[s]->data;
|
|
|
|
pos=0;
|
|
|
|
tt=edf.startdate;
|
2011-07-31 20:24:43 +00:00
|
|
|
sess->updateFirst(tt);
|
2011-06-30 10:56:22 +00:00
|
|
|
duration=0;
|
2011-06-29 17:58:28 +00:00
|
|
|
while (pos<recs) {
|
|
|
|
c=data[pos];
|
|
|
|
if ((c!='+') && (c!='-'))
|
|
|
|
break;
|
|
|
|
if (data[pos++]=='+') sign=true; else sign=false;
|
|
|
|
t="";
|
|
|
|
c=data[pos];
|
|
|
|
do {
|
|
|
|
t+=c;
|
|
|
|
pos++;
|
|
|
|
c=data[pos];
|
|
|
|
} while ((c!=20) && (c!=21)); // start code
|
|
|
|
d=t.toDouble(&ok);
|
|
|
|
if (!ok) {
|
2011-07-01 10:10:44 +00:00
|
|
|
qDebug() << "Faulty EDF EVE file " << edf.filename;
|
2011-06-29 17:58:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!sign) d=-d;
|
2011-07-27 09:21:53 +00:00
|
|
|
tt=edf.startdate+qint64(d*1000.0);
|
2011-06-29 17:58:28 +00:00
|
|
|
duration=0;
|
|
|
|
// First entry
|
|
|
|
|
|
|
|
if (data[pos]==21) {
|
|
|
|
pos++;
|
|
|
|
// get duration.
|
|
|
|
t="";
|
|
|
|
do {
|
|
|
|
t+=data[pos];
|
|
|
|
pos++;
|
|
|
|
} while ((data[pos]!=20) && (pos<recs)); // start code
|
2011-07-02 15:48:55 +00:00
|
|
|
duration=t.toDouble(&ok);
|
2011-06-29 17:58:28 +00:00
|
|
|
if (!ok) {
|
2011-07-01 10:10:44 +00:00
|
|
|
qDebug() << "Faulty EDF EVE file (at %" << pos << ") " << edf.filename;
|
2011-06-29 17:58:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while ((data[pos]==20) && (pos<recs)) {
|
|
|
|
t="";
|
|
|
|
pos++;
|
|
|
|
if (data[pos]==0)
|
|
|
|
break;
|
|
|
|
if (data[pos]==20) {
|
|
|
|
pos++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
|
|
|
t+=tolower(data[pos++]);
|
|
|
|
} while ((data[pos]!=20) && (pos<recs)); // start code
|
|
|
|
if (!t.isEmpty()) {
|
2011-07-27 09:21:53 +00:00
|
|
|
if (t=="obstructive apnea") {
|
|
|
|
if (!EL[0]) {
|
2011-09-17 12:39:00 +00:00
|
|
|
if (!(EL[0]=sess->AddEventList(CPAP_Obstructive,EVL_Event))) return false;
|
2011-07-27 09:21:53 +00:00
|
|
|
}
|
|
|
|
EL[0]->AddEvent(tt,duration);
|
|
|
|
} else if (t=="hypopnea") {
|
|
|
|
if (!EL[1]) {
|
2011-09-17 12:39:00 +00:00
|
|
|
if (!(EL[1]=sess->AddEventList(CPAP_Hypopnea,EVL_Event))) return false;
|
2011-07-27 09:21:53 +00:00
|
|
|
}
|
2011-09-08 07:43:04 +00:00
|
|
|
EL[1]->AddEvent(tt,duration+10); // Only Hyponea's Need the extra duration???
|
2011-07-27 09:21:53 +00:00
|
|
|
} else if (t=="apnea") {
|
|
|
|
if (!EL[2]) {
|
2011-09-17 12:39:00 +00:00
|
|
|
if (!(EL[2]=sess->AddEventList(CPAP_Apnea,EVL_Event))) return false;
|
2011-07-27 09:21:53 +00:00
|
|
|
}
|
|
|
|
EL[2]->AddEvent(tt,duration);
|
|
|
|
} else if (t=="central apnea") {
|
|
|
|
code=CPAP_ClearAirway;
|
|
|
|
if (!EL[3]) {
|
2011-09-17 12:39:00 +00:00
|
|
|
if (!(EL[3]=sess->AddEventList(CPAP_ClearAirway,EVL_Event))) return false;
|
2011-07-27 09:21:53 +00:00
|
|
|
}
|
|
|
|
EL[3]->AddEvent(tt,duration);
|
2011-06-29 17:58:28 +00:00
|
|
|
} else {
|
|
|
|
if (t!="recording starts") {
|
2011-08-09 23:44:36 +00:00
|
|
|
qDebug() << "Unobserved ResMed annotation field: " << t;
|
2011-06-29 17:58:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (pos>=recs) {
|
2011-07-01 10:10:44 +00:00
|
|
|
qDebug() << "Short EDF EVE file" << edf.filename;
|
2011-06-29 17:58:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
// pos++;
|
|
|
|
}
|
|
|
|
while ((data[pos]==0) && pos<recs) pos++;
|
|
|
|
if (pos>=recs) break;
|
|
|
|
}
|
2011-07-31 20:24:43 +00:00
|
|
|
sess->updateLast(tt);
|
2011-06-29 17:58:28 +00:00
|
|
|
// qDebug(data);
|
2011-06-29 14:19:38 +00:00
|
|
|
}
|
2011-07-01 10:10:44 +00:00
|
|
|
return true;
|
2011-06-29 14:19:38 +00:00
|
|
|
}
|
2011-07-01 10:10:44 +00:00
|
|
|
bool ResmedLoader::LoadBRP(Session *sess,EDFParser &edf)
|
2011-06-29 14:19:38 +00:00
|
|
|
{
|
2011-06-29 16:19:57 +00:00
|
|
|
QString t;
|
2011-07-31 20:24:43 +00:00
|
|
|
sess->updateFirst(edf.startdate);
|
2011-07-03 02:43:50 +00:00
|
|
|
qint64 duration=edf.GetNumDataRecords()*edf.GetDuration();
|
2011-07-31 20:24:43 +00:00
|
|
|
sess->updateLast(edf.startdate+duration);
|
2011-07-03 02:43:50 +00:00
|
|
|
|
2011-06-29 16:19:57 +00:00
|
|
|
for (int s=0;s<edf.GetNumSignals();s++) {
|
2011-07-27 09:21:53 +00:00
|
|
|
EDFSignal & es=*edf.edfsignals[s];
|
|
|
|
//qDebug() << "BRP:" << es.digital_maximum << es.digital_minimum << es.physical_maximum << es.physical_minimum;
|
2011-06-29 16:19:57 +00:00
|
|
|
long recs=edf.edfsignals[s]->nr*edf.GetNumDataRecords();
|
2011-07-31 20:24:43 +00:00
|
|
|
ChannelID code;
|
2011-07-27 09:21:53 +00:00
|
|
|
if (edf.edfsignals[s]->label=="Flow") {
|
2011-08-07 11:37:56 +00:00
|
|
|
es.gain*=60;
|
2011-08-09 23:44:36 +00:00
|
|
|
es.physical_dimension="L/M";
|
2011-07-27 09:21:53 +00:00
|
|
|
code=CPAP_FlowRate;
|
2011-08-09 23:44:36 +00:00
|
|
|
} else if (edf.edfsignals[s]->label.startsWith("Mask Pres")) {
|
2011-09-17 13:21:18 +00:00
|
|
|
code=CPAP_MaskPressureHi;
|
2011-08-09 23:44:36 +00:00
|
|
|
} else if (es.label.startsWith("Resp Event")) {
|
2011-09-17 12:39:00 +00:00
|
|
|
code=CPAP_RespEvent;
|
2011-07-10 17:49:02 +00:00
|
|
|
} else {
|
2011-08-09 23:44:36 +00:00
|
|
|
qDebug() << "Unobserved ResMed BRP Signal " << edf.edfsignals[s]->label;
|
2011-06-29 17:58:28 +00:00
|
|
|
continue;
|
|
|
|
}
|
2011-07-27 09:21:53 +00:00
|
|
|
double rate=double(duration)/double(recs);
|
2011-09-17 12:39:00 +00:00
|
|
|
EventList *a=sess->AddEventList(code,EVL_Waveform,es.gain,es.offset,0,0,rate);
|
2011-08-09 23:44:36 +00:00
|
|
|
a->setDimension(es.physical_dimension);
|
2011-07-27 09:21:53 +00:00
|
|
|
a->AddWaveform(edf.startdate,es.data,recs,duration);
|
2011-08-01 08:53:26 +00:00
|
|
|
sess->setMin(code,a->min());
|
|
|
|
sess->setMax(code,a->max());
|
2011-07-27 09:21:53 +00:00
|
|
|
//delete edf.edfsignals[s]->data;
|
|
|
|
//edf.edfsignals[s]->data=NULL; // so it doesn't get deleted when edf gets trashed.
|
2011-06-29 16:19:57 +00:00
|
|
|
}
|
2011-07-01 10:10:44 +00:00
|
|
|
return true;
|
2011-06-29 14:19:38 +00:00
|
|
|
}
|
2011-07-31 20:24:43 +00:00
|
|
|
EventList * ResmedLoader::ToTimeDelta(Session *sess,EDFParser &edf, EDFSignal & es, ChannelID code, long recs, qint64 duration,EventDataType min,EventDataType max)
|
2011-06-29 20:30:23 +00:00
|
|
|
{
|
|
|
|
bool first=true;
|
2011-07-02 14:35:50 +00:00
|
|
|
double rate=(duration/recs); // milliseconds per record
|
2011-07-02 15:48:55 +00:00
|
|
|
double tt=edf.startdate;
|
2011-07-27 09:21:53 +00:00
|
|
|
//sess->UpdateFirst(tt);
|
2011-06-29 20:30:23 +00:00
|
|
|
EventDataType c,last;
|
2011-09-17 12:39:00 +00:00
|
|
|
|
|
|
|
EventList *el=sess->AddEventList(code,EVL_Event,es.gain,es.offset,min,max);
|
2011-09-13 08:12:07 +00:00
|
|
|
int startpos=0;
|
|
|
|
|
2011-09-17 12:39:00 +00:00
|
|
|
if ((code==CPAP_Pressure) || (code==CPAP_IPAP) || (code==CPAP_EPAP)) {
|
|
|
|
startpos=20; // Shave the first 20 seconds of pressure data
|
2011-09-13 08:12:07 +00:00
|
|
|
tt+=rate*startpos;
|
2011-09-17 12:39:00 +00:00
|
|
|
}
|
2011-09-13 08:12:07 +00:00
|
|
|
for (int i=startpos;i<recs;i++) {
|
2011-07-27 09:21:53 +00:00
|
|
|
c=es.data[i];
|
2011-06-29 20:30:23 +00:00
|
|
|
|
|
|
|
if (first) {
|
2011-07-27 09:21:53 +00:00
|
|
|
el->AddEvent(tt,c);
|
2011-06-29 20:30:23 +00:00
|
|
|
first=false;
|
|
|
|
} else {
|
|
|
|
if (last!=c) {
|
2011-07-27 09:21:53 +00:00
|
|
|
el->AddEvent(tt,c);
|
2011-06-29 20:30:23 +00:00
|
|
|
}
|
|
|
|
}
|
2011-07-02 14:35:50 +00:00
|
|
|
tt+=rate;
|
2011-06-29 20:30:23 +00:00
|
|
|
|
|
|
|
last=c;
|
|
|
|
}
|
2011-07-27 09:21:53 +00:00
|
|
|
el->AddEvent(tt,c);
|
2011-07-31 20:24:43 +00:00
|
|
|
sess->updateLast(tt);
|
2011-07-27 09:21:53 +00:00
|
|
|
return el;
|
2011-06-29 20:30:23 +00:00
|
|
|
}
|
2011-07-01 10:10:44 +00:00
|
|
|
bool ResmedLoader::LoadSAD(Session *sess,EDFParser &edf)
|
2011-06-29 14:19:38 +00:00
|
|
|
{
|
2011-08-06 13:37:06 +00:00
|
|
|
QString t;
|
|
|
|
sess->updateFirst(edf.startdate);
|
|
|
|
qint64 duration=edf.GetNumDataRecords()*edf.GetDuration();
|
|
|
|
sess->updateLast(edf.startdate+duration);
|
|
|
|
|
|
|
|
for (int s=0;s<edf.GetNumSignals();s++) {
|
|
|
|
EDFSignal & es=*edf.edfsignals[s];
|
2011-08-07 01:26:28 +00:00
|
|
|
//qDebug() << "SAD:" << es.label << es.digital_maximum << es.digital_minimum << es.physical_maximum << es.physical_minimum;
|
2011-08-06 13:37:06 +00:00
|
|
|
long recs=edf.edfsignals[s]->nr*edf.GetNumDataRecords();
|
|
|
|
ChannelID code;
|
2011-11-25 12:13:35 +00:00
|
|
|
if (edf.edfsignals[s]->label.startsWith("Puls")) {
|
2011-09-17 12:39:00 +00:00
|
|
|
code=OXI_Pulse;
|
2011-08-06 13:37:06 +00:00
|
|
|
} else if (edf.edfsignals[s]->label=="SpO2") {
|
2011-09-17 12:39:00 +00:00
|
|
|
code=OXI_SPO2;
|
2011-08-06 13:37:06 +00:00
|
|
|
} else {
|
2011-08-09 23:44:36 +00:00
|
|
|
qDebug() << "Unobserved ResMed SAD Signal " << edf.edfsignals[s]->label;
|
2011-08-06 13:37:06 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
bool hasdata=false;
|
|
|
|
for (int i=0;i<recs;i++) {
|
|
|
|
if (es.data[i]!=-1) {
|
|
|
|
hasdata=true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (hasdata) {
|
|
|
|
EventList *a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
|
|
|
|
if (a) {
|
|
|
|
sess->setMin(code,a->min());
|
|
|
|
sess->setMax(code,a->max());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2011-07-01 10:10:44 +00:00
|
|
|
return true;
|
2011-06-29 14:19:38 +00:00
|
|
|
}
|
2011-06-29 20:30:23 +00:00
|
|
|
|
|
|
|
|
2011-07-01 10:10:44 +00:00
|
|
|
bool ResmedLoader::LoadPLD(Session *sess,EDFParser &edf)
|
2011-06-29 14:19:38 +00:00
|
|
|
{
|
2011-07-01 02:52:02 +00:00
|
|
|
// Is it save to assume the order does not change here?
|
|
|
|
enum PLDType { MaskPres=0, TherapyPres, ExpPress, Leak, RR, Vt, Mv, SnoreIndex, FFLIndex, U1, U2 };
|
|
|
|
|
2011-07-03 02:43:50 +00:00
|
|
|
qint64 duration=edf.GetNumDataRecords()*edf.GetDuration();
|
2011-09-17 12:39:00 +00:00
|
|
|
sess->updateFirst(edf.startdate);
|
2011-07-31 20:24:43 +00:00
|
|
|
sess->updateLast(edf.startdate+duration);
|
2011-06-29 17:58:28 +00:00
|
|
|
QString t;
|
2011-07-21 03:35:59 +00:00
|
|
|
int emptycnt=0;
|
2011-08-01 08:53:26 +00:00
|
|
|
EventList *a;
|
|
|
|
double rate;
|
|
|
|
long recs;
|
|
|
|
ChannelID code;
|
2011-06-29 17:58:28 +00:00
|
|
|
for (int s=0;s<edf.GetNumSignals();s++) {
|
2011-07-27 09:21:53 +00:00
|
|
|
EDFSignal & es=*edf.edfsignals[s];
|
2011-08-01 08:53:26 +00:00
|
|
|
recs=es.nr*edf.GetNumDataRecords();
|
2011-09-17 12:39:00 +00:00
|
|
|
if (recs<=0) continue;
|
2011-08-01 08:53:26 +00:00
|
|
|
rate=double(duration)/double(recs);
|
2011-07-27 09:21:53 +00:00
|
|
|
//qDebug() << "EVE:" << es.digital_maximum << es.digital_minimum << es.physical_maximum << es.physical_minimum << es.gain;
|
|
|
|
if (es.label=="Snore Index") {
|
2011-06-29 20:30:23 +00:00
|
|
|
code=CPAP_Snore;
|
2011-08-01 08:53:26 +00:00
|
|
|
a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
|
2011-11-25 12:13:35 +00:00
|
|
|
} else if (es.label.startsWith("Therapy Pres")) {
|
2011-09-17 12:39:00 +00:00
|
|
|
code=CPAP_Pressure; //TherapyPressure;
|
2011-08-07 12:33:00 +00:00
|
|
|
a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
|
2011-08-09 23:44:36 +00:00
|
|
|
} else if (es.label=="Insp Pressure") {
|
2011-08-07 12:33:00 +00:00
|
|
|
code=CPAP_IPAP; //TherapyPressure;
|
|
|
|
sess->settings[CPAP_Mode]=MODE_BIPAP;
|
2011-08-01 08:53:26 +00:00
|
|
|
a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
|
2011-11-25 12:42:41 +00:00
|
|
|
} else if ((es.label=="MV") || (es.label=="VM")){
|
2011-09-17 12:39:00 +00:00
|
|
|
code=CPAP_MinuteVent;
|
2011-08-01 08:53:26 +00:00
|
|
|
a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
|
2011-11-25 12:42:41 +00:00
|
|
|
} else if ((es.label=="RR") || (es.label=="AF") || (es.label=="FR")) {
|
2011-09-17 12:39:00 +00:00
|
|
|
code=CPAP_RespRate;
|
|
|
|
a=sess->AddEventList(code,EVL_Waveform,es.gain,es.offset,0,0,rate);
|
2011-07-27 09:21:53 +00:00
|
|
|
a->AddWaveform(edf.startdate,es.data,recs,duration);
|
2011-11-25 12:42:41 +00:00
|
|
|
} else if ((es.label=="Vt") || (es.label=="VC")) {
|
2011-06-30 04:55:20 +00:00
|
|
|
code=CPAP_TidalVolume;
|
2011-07-27 09:21:53 +00:00
|
|
|
es.physical_maximum=es.physical_minimum=0;
|
|
|
|
es.gain*=1000.0;
|
2011-08-01 08:53:26 +00:00
|
|
|
a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
|
2011-11-25 12:13:35 +00:00
|
|
|
} else if ((es.label=="Leak") || (es.label.startsWith("Leck"))) {
|
2011-06-29 20:30:23 +00:00
|
|
|
code=CPAP_Leak;
|
2011-08-07 08:52:12 +00:00
|
|
|
es.gain*=60;
|
2011-08-09 23:44:36 +00:00
|
|
|
es.physical_dimension="L/M";
|
2011-08-01 08:53:26 +00:00
|
|
|
a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
|
2011-07-27 09:21:53 +00:00
|
|
|
} else if (es.label=="FFL Index") {
|
2011-09-17 12:39:00 +00:00
|
|
|
code=CPAP_FLG;
|
2011-08-01 08:53:26 +00:00
|
|
|
a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
|
2011-08-09 23:44:36 +00:00
|
|
|
} else if (es.label.startsWith("Mask Pres")) {
|
2011-09-17 12:39:00 +00:00
|
|
|
code=CPAP_MaskPressure;
|
2011-08-01 08:53:26 +00:00
|
|
|
a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
|
2011-08-09 23:44:36 +00:00
|
|
|
} else if (es.label.startsWith("Exp Press")) {
|
2011-11-14 09:26:58 +00:00
|
|
|
code=CPAP_EPAP;//ExpiratoryPressure
|
2011-08-01 08:53:26 +00:00
|
|
|
a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
|
2011-08-09 23:44:36 +00:00
|
|
|
} else if (es.label.startsWith("I:E")) {
|
2011-11-14 09:26:58 +00:00
|
|
|
code=CPAP_IE;//I:E ratio?
|
2011-09-17 12:39:00 +00:00
|
|
|
a=sess->AddEventList(code,EVL_Waveform,es.gain,es.offset,0,0,rate);
|
2011-08-09 23:44:36 +00:00
|
|
|
a->AddWaveform(edf.startdate,es.data,recs,duration);
|
|
|
|
//a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
|
|
|
|
} else if (es.label.startsWith("Ti")) {
|
2011-11-14 09:26:58 +00:00
|
|
|
code=CPAP_Ti;
|
2011-09-17 12:39:00 +00:00
|
|
|
a=sess->AddEventList(code,EVL_Waveform,es.gain,es.offset,0,0,rate);
|
2011-08-09 23:44:36 +00:00
|
|
|
a->AddWaveform(edf.startdate,es.data,recs,duration);
|
|
|
|
//a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
|
|
|
|
} else if (es.label.startsWith("Te")) {
|
2011-11-14 09:26:58 +00:00
|
|
|
code=CPAP_Te;
|
|
|
|
a=sess->AddEventList(code,EVL_Waveform,es.gain,es.offset,0,0,rate);
|
|
|
|
a->AddWaveform(edf.startdate,es.data,recs,duration);
|
|
|
|
//a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
|
|
|
|
} else if (es.label.startsWith("TgMV")) {
|
|
|
|
code=CPAP_TgMV;
|
2011-09-17 12:39:00 +00:00
|
|
|
a=sess->AddEventList(code,EVL_Waveform,es.gain,es.offset,0,0,rate);
|
2011-08-09 23:44:36 +00:00
|
|
|
a->AddWaveform(edf.startdate,es.data,recs,duration);
|
|
|
|
//a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
|
2011-07-27 09:21:53 +00:00
|
|
|
} else if (es.label=="") {
|
2011-07-21 03:35:59 +00:00
|
|
|
if (emptycnt==0) {
|
2011-09-17 12:39:00 +00:00
|
|
|
code=RMS9_E01;
|
2011-08-01 08:53:26 +00:00
|
|
|
a=ToTimeDelta(sess,edf,es, code,recs,duration);
|
2011-07-21 03:35:59 +00:00
|
|
|
} else if (emptycnt==1) {
|
2011-09-17 12:39:00 +00:00
|
|
|
code=RMS9_E02;
|
2011-08-01 08:53:26 +00:00
|
|
|
a=ToTimeDelta(sess,edf,es, code,recs,duration);
|
2011-07-21 03:35:59 +00:00
|
|
|
} else {
|
2011-07-27 09:21:53 +00:00
|
|
|
qDebug() << "Unobserved Empty Signal " << es.label;
|
2011-07-21 03:35:59 +00:00
|
|
|
}
|
|
|
|
emptycnt++;
|
2011-06-30 09:37:24 +00:00
|
|
|
} else {
|
2011-08-09 23:44:36 +00:00
|
|
|
qDebug() << "Unobserved ResMed PLD Signal " << es.label;
|
2011-08-01 08:53:26 +00:00
|
|
|
a=NULL;
|
|
|
|
}
|
|
|
|
if (a) {
|
2011-09-04 12:25:11 +00:00
|
|
|
sess->setMin(code,a->min());
|
|
|
|
sess->setMax(code,a->max());
|
2011-08-09 23:44:36 +00:00
|
|
|
a->setDimension(es.physical_dimension);
|
2011-06-29 20:30:23 +00:00
|
|
|
}
|
2011-06-29 17:58:28 +00:00
|
|
|
}
|
2011-07-01 10:10:44 +00:00
|
|
|
return true;
|
2011-06-29 14:19:38 +00:00
|
|
|
}
|
2011-06-28 02:21:38 +00:00
|
|
|
|
|
|
|
void ResInitModelMap()
|
|
|
|
{
|
2011-07-03 04:22:58 +00:00
|
|
|
// Courtesy Troy Schultz
|
|
|
|
RMS9ModelMap[36001]="ResMed S9 Escape";
|
|
|
|
RMS9ModelMap[36002]="ResMed S9 Escape Auto";
|
|
|
|
RMS9ModelMap[36003]="ResMed S9 Elite";
|
|
|
|
RMS9ModelMap[36004]="ResMed S9 VPAP S";
|
|
|
|
RMS9ModelMap[36005]="ResMed S9 AutoSet";
|
|
|
|
RMS9ModelMap[36006]="ResMed S9 VPAP Auto";
|
|
|
|
RMS9ModelMap[36007]="ResMed S9 VPAP Adapt";
|
|
|
|
RMS9ModelMap[36008]="ResMed S9 VPAP ST";
|
|
|
|
// S8 Series
|
|
|
|
RMS9ModelMap[33007]="ResMed S8 Escape";
|
|
|
|
RMS9ModelMap[33039]="ResMed S8 Elite II";
|
|
|
|
RMS9ModelMap[33051]="ResMed S8 Escape II";
|
|
|
|
RMS9ModelMap[33064]="ResMed S8 Escape II AutoSet";
|
|
|
|
RMS9ModelMap[33064]="ResMed S8 Escape II AutoSet";
|
|
|
|
RMS9ModelMap[33129]="ResMed S8 AutoSet II";
|
2011-09-23 03:54:48 +00:00
|
|
|
|
|
|
|
resmed_codes[CPAP_FlowRate].push_back("Flow");
|
|
|
|
resmed_codes[CPAP_MaskPressureHi].push_back("Mask Pres");
|
|
|
|
resmed_codes[CPAP_MaskPressureHi].push_back("Mask Pressure"); // vpap
|
|
|
|
resmed_codes[CPAP_RespEvent].push_back("Resp Event");
|
|
|
|
|
|
|
|
resmed_codes[CPAP_MaskPressure].push_back("Mask Pres");
|
|
|
|
resmed_codes[CPAP_MaskPressure].push_back("Mask Pressure"); // vpap
|
|
|
|
|
|
|
|
resmed_codes[CPAP_Pressure].push_back("Therapy Pres"); // not on vpap
|
|
|
|
resmed_codes[CPAP_IPAP].push_back("Insp Pressure"); // on vpap
|
|
|
|
|
|
|
|
resmed_codes[CPAP_EPAP].push_back("Exp Press");
|
|
|
|
resmed_codes[CPAP_EPAP].push_back("Exp Pressure"); // vpap
|
2011-11-25 12:13:35 +00:00
|
|
|
|
2011-09-23 03:54:48 +00:00
|
|
|
resmed_codes[CPAP_Leak].push_back("Leak");
|
2011-11-25 12:13:35 +00:00
|
|
|
resmed_codes[CPAP_Leak].push_back("Leck.");
|
|
|
|
|
2011-09-23 03:54:48 +00:00
|
|
|
resmed_codes[CPAP_RespRate].push_back("RR");
|
2011-11-25 12:13:35 +00:00
|
|
|
resmed_codes[CPAP_RespRate].push_back("AF");
|
2011-11-25 12:42:41 +00:00
|
|
|
resmed_codes[CPAP_RespRate].push_back("FR");
|
2011-11-25 12:13:35 +00:00
|
|
|
|
2011-09-23 03:54:48 +00:00
|
|
|
resmed_codes[CPAP_TidalVolume].push_back("Vt");
|
2011-11-25 12:42:41 +00:00
|
|
|
resmed_codes[CPAP_TidalVolume].push_back("VC");
|
|
|
|
|
2011-09-23 03:54:48 +00:00
|
|
|
resmed_codes[CPAP_MinuteVent].push_back("MV");
|
2011-11-25 12:42:41 +00:00
|
|
|
resmed_codes[CPAP_MinuteVent].push_back("VM");
|
|
|
|
|
2011-09-23 03:54:48 +00:00
|
|
|
resmed_codes[CPAP_IE].push_back("I:E"); // vpap
|
|
|
|
resmed_codes[CPAP_Snore].push_back("Snore Index");
|
|
|
|
resmed_codes[CPAP_FLG].push_back("FFL Index");
|
|
|
|
|
|
|
|
resmed_codes[CPAP_RespEvent].push_back("RE");
|
|
|
|
resmed_codes[CPAP_Ti].push_back("Ti");
|
|
|
|
resmed_codes[CPAP_Te].push_back("Te");
|
|
|
|
|
|
|
|
// Sad (oximetry)
|
|
|
|
resmed_codes[OXI_Pulse].push_back("Pulse");
|
2011-11-25 12:13:35 +00:00
|
|
|
resmed_codes[OXI_Pulse].push_back("Puls");
|
2011-09-23 03:54:48 +00:00
|
|
|
resmed_codes[OXI_SPO2].push_back("SpO2");
|
|
|
|
|
|
|
|
// Event annotations
|
|
|
|
resmed_codes[CPAP_Obstructive].push_back("Obstructive apnea");
|
|
|
|
resmed_codes[CPAP_Hypopnea].push_back("Hypopnea");
|
|
|
|
resmed_codes[CPAP_Apnea].push_back("Apnea");
|
|
|
|
resmed_codes[CPAP_ClearAirway].push_back("Central apnea");
|
|
|
|
|
2011-11-25 12:13:35 +00:00
|
|
|
resmed_codes[CPAP_Mode].push_back("Mode");
|
|
|
|
resmed_codes[CPAP_Mode].push_back("Modus");
|
|
|
|
resmed_codes["Set Pressure"].push_back("Eingest. Druck");
|
2011-11-25 12:42:41 +00:00
|
|
|
resmed_codes["Set Pressure"].push_back("Set Pressure"); // Prescription
|
|
|
|
resmed_codes["Set Pressure"].push_back("Pres. prescrite");
|
2011-11-25 12:13:35 +00:00
|
|
|
resmed_codes["EPR"].push_back("EPR");
|
|
|
|
resmed_codes["EPRLevel"].push_back("EPR Level");
|
|
|
|
resmed_codes["EPRLevel"].push_back("EPR-Stufe");
|
2011-11-25 12:42:41 +00:00
|
|
|
resmed_codes["EPRLevel"].push_back("Niveau EPR");
|
2011-11-25 12:13:35 +00:00
|
|
|
resmed_codes[CPAP_PressureMax].push_back("Max Pressure");
|
|
|
|
resmed_codes[CPAP_PressureMax].push_back("Max. Druck");
|
2011-11-25 12:42:41 +00:00
|
|
|
resmed_codes[CPAP_PressureMax].push_back("Pression max.");
|
|
|
|
|
2011-11-25 12:13:35 +00:00
|
|
|
resmed_codes[CPAP_PressureMin].push_back("Min Pressure");
|
|
|
|
resmed_codes[CPAP_PressureMin].push_back("Min. Druck");
|
2011-11-25 12:42:41 +00:00
|
|
|
resmed_codes[CPAP_PressureMin].push_back("Pression min.");
|
2011-11-25 12:13:35 +00:00
|
|
|
|
2011-09-23 03:54:48 +00:00
|
|
|
// STR.edf
|
|
|
|
}
|
2011-06-28 02:21:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
bool resmed_initialized=false;
|
|
|
|
void ResmedLoader::Register()
|
|
|
|
{
|
|
|
|
if (resmed_initialized) return;
|
2011-07-01 10:10:44 +00:00
|
|
|
qDebug() << "Registering ResmedLoader";
|
2011-06-28 02:21:38 +00:00
|
|
|
RegisterLoader(new ResmedLoader());
|
|
|
|
ResInitModelMap();
|
|
|
|
resmed_initialized=true;
|
|
|
|
}
|
|
|
|
|