More unfinished ResMed stuff

This commit is contained in:
Mark Watkins 2011-06-30 00:19:38 +10:00
parent 52aa96b9af
commit c6c7cda0fc
8 changed files with 320 additions and 11 deletions

View File

@ -693,8 +693,8 @@ void gGraphWindow::Render(float w, float h)
glEnd(); glEnd();
} else { } else {
glClearColor(255,255,255,255); glClearColor(255,255,255,0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT ); //| GL_DEPTH_BUFFER_BIT
// glClear(GL_COLOR_BUFFER_BIT); // glClear(GL_COLOR_BUFFER_BIT);
} }

View File

@ -16,6 +16,120 @@ License: GPL
#include "resmed_loader.h" #include "resmed_loader.h"
#include "SleepLib/session.h" #include "SleepLib/session.h"
EDFParser::EDFParser(QString name)
{
buffer=NULL;
Open(name);
}
EDFParser::~EDFParser()
{
vector<EDFSignal *>::iterator s;
for (s=edfsignals.begin();s!=edfsignals.end();s++) {
if ((*s)->data) delete [] (*s)->data;
if ((*s)->adata) delete [] (*s)->adata;
delete *s;
}
if (buffer) delete [] buffer;
}
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;
version=Read(8).toLong(&ok);
if (!ok)
return false;
patientident=Read(80);
recordingident=Read(80); // Serial number is in here..
int snp=recordingident.indexOf("SRN=");
for (int i=snp+4;i<recordingident.length();i++) {
if (recordingident[i]==' ')
break;
serialnumber+=recordingident[i];
}
temp=Read(8);
temp+=" "+Read(8);
startdate.fromString(temp,"dd.MM.yy HH.mm.ss");
num_header_bytes=Read(8).toLong(&ok);
if (!ok)
return false;
reserved44=Read(44);
num_data_records=Read(8).toLong(&ok);
if (!ok)
return false;
temp=Read(8);
// temp="0.00";
dur_data_record=temp.toDouble(&ok);
if (!ok)
return false;
num_signals=Read(4).toLong(&ok);
if (!ok)
return false;
for (int i=0;i<num_signals;i++) {
EDFSignal *signal=new EDFSignal;
edfsignals.push_back(signal);
signal->data=NULL;
signal->adata=NULL;
edfsignals[i]->label=Read(16);
}
for (int i=0;i<num_signals;i++) edfsignals[i]->transducer_type=Read(80);
for (int i=0;i<num_signals;i++) edfsignals[i]->physical_dimension=Read(8);
for (int i=0;i<num_signals;i++) edfsignals[i]->physical_minimum=Read(8).toLong(&ok);
for (int i=0;i<num_signals;i++) edfsignals[i]->physical_maximum=Read(8).toLong(&ok);
for (int i=0;i<num_signals;i++) edfsignals[i]->digital_minimum=Read(8).toLong(&ok);
for (int i=0;i<num_signals;i++) edfsignals[i]->digital_maximum=Read(8).toLong(&ok);
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);
for (int i=0;i<num_signals;i++) {
//qDebug//cout << "Reading signal " << signals[i]->label << endl;
if (edfsignals[i]->label!="EDF Annotations") {
// Waveforms
edfsignals[i]->data=new qint16 [edfsignals[i]->nr];
for (int j=0;j<edfsignals[i]->nr;j++){
long t;
t=Read(2).toLong(&ok);
if (!ok)
return false;
edfsignals[i]->data[j]=t & 0xffff;
}
} else { // Annotation data..
edfsignals[i]->adata=(char *) new char [edfsignals[i]->nr*2];
//cout << signals[i]->nr << endl;;
for (int j=0;j<edfsignals[i]->nr*2;j++)
edfsignals[i]->adata[j]=buffer[pos++];
}
//cout << "Read Signal" << endl;
}
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();
buffer=new char [filesize];
f.read(buffer,filesize);
f.close();
pos=0;
}
ResmedLoader::ResmedLoader() ResmedLoader::ResmedLoader()
{ {
} }
@ -25,12 +139,11 @@ ResmedLoader::~ResmedLoader()
Machine *ResmedLoader::CreateMachine(QString serial,Profile *profile) Machine *ResmedLoader::CreateMachine(QString serial,Profile *profile)
{ {
qDebug(("Create ResMed Machine "+serial).toLatin1());
assert(profile!=NULL); assert(profile!=NULL);
vector<Machine *> ml=profile->GetMachines(MT_CPAP); vector<Machine *> ml=profile->GetMachines(MT_CPAP);
bool found=false; bool found=false;
for (vector<Machine *>::iterator i=ml.begin(); i!=ml.end(); i++) { for (vector<Machine *>::iterator i=ml.begin(); i!=ml.end(); i++) {
if (((*i)->GetClass()=="ResMed") && ((*i)->properties["Serial"]==serial)) { if (((*i)->GetClass()==resmed_class_name) && ((*i)->properties["Serial"]==serial)) {
ResmedList[serial]=*i; //static_cast<CPAP *>(*i); ResmedList[serial]=*i; //static_cast<CPAP *>(*i);
found=true; found=true;
break; break;
@ -38,12 +151,15 @@ Machine *ResmedLoader::CreateMachine(QString serial,Profile *profile)
} }
if (found) return ResmedList[serial]; if (found) return ResmedList[serial];
qDebug(("Create ResMed Machine %s"+serial).toLatin1());
Machine *m=new CPAP(profile,0); Machine *m=new CPAP(profile,0);
m->SetClass(resmed_class_name);
ResmedList[serial]=m; ResmedList[serial]=m;
profile->AddMachine(m); profile->AddMachine(m);
m->properties["Serial"]=serial; m->properties["Serial"]=serial;
m->properties["Brand"]="ResMed";
return m; return m;
@ -67,20 +183,82 @@ bool ResmedLoader::Open(QString & path,Profile *profile)
return 0; return 0;
qDebug(("ResmedLoader::Open newpath="+newpath).toLatin1()); qDebug(("ResmedLoader::Open newpath="+newpath).toLatin1());
dir.setFilter(QDir::NoDotAndDotDot | QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoSymLinks); dir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks);
dir.setSorting(QDir::Name); dir.setSorting(QDir::Name);
QFileInfoList flist=dir.entryInfoList(); QFileInfoList flist=dir.entryInfoList();
map<SessionID,vector<QString> > sessfiles;
QString ext,rest,datestr,s,codestr;
list<QString> SerialNumbers; SessionID sessionid;
list<QString>::iterator sn; QDateTime date;
map<SessionID,Session *> sessions;
Session *sess;
Machine *m;
for (int i=0;i<flist.size();i++) { for (int i=0;i<flist.size();i++) {
QFileInfo fi=flist.at(i); QFileInfo fi=flist.at(i);
QString filename=fi.fileName(); QString filename=fi.fileName();
ext=filename.section(".",1).toLower();
if (ext!="edf") continue;
rest=filename.section(".",0,0);
datestr=filename.section("_",0,1);
date=QDateTime::fromString(datestr,"yyyyMMdd_HHmmss");
sessionid=date.toTime_t();
s.sprintf("%li",sessionid);
codestr=rest.section("_",2).toUpper();
int code;
if (codestr=="EVE") code=0;
else if (codestr=="PLD") code=1;
else if (codestr=="BRP") code=2;
else if (codestr=="SAD") code=3;
else {
qDebug(("Unknown file EDF type"+filename).toLatin1());
continue;
}
qDebug(("Parsing "+filename).toLatin1());
EDFParser edf(fi.canonicalFilePath());
if (!edf.Parse()) continue;
Machine *m=CreateMachine(edf.serialnumber,profile);
if (sessions.find(sessionid)==sessions.end()) {
sessions[sessionid]=new Session(m,sessionid);
}
sess=sessions[sessionid];
sess->SetChanged(true);
switch(code) {
case 0: LoadEVE(m,sess,edf);
break;
case 1: LoadPLD(m,sess,edf);
break;
case 2: LoadBRP(m,sess,edf);
break;
case 3: LoadSAD(m,sess,edf);
break;
}
} }
return 0; return 0;
} }
bool ResmedLoader::LoadEVE(Machine *mach,Session *sess,EDFParser &edf)
{
QString t;
for (int s=0;s<edf.GetNumSignals();s++) {
t.sprintf("%i",edf.edfsignals[s]->nr);
qDebug((edf.edfsignals[s]->label+" "+t).toLatin1());
if (edf.edfsignals[s]->adata) {
}
}
}
bool ResmedLoader::LoadBRP(Machine *mach,Session *sess,EDFParser &edf)
{
}
bool ResmedLoader::LoadSAD(Machine *mach,Session *sess,EDFParser &edf)
{
}
bool ResmedLoader::LoadPLD(Machine *mach,Session *sess,EDFParser &edf)
{
}
void ResInitModelMap() void ResInitModelMap()
{ {

View File

@ -10,6 +10,7 @@ License: GPL
#define RESMED_LOADER_H #define RESMED_LOADER_H
//#include <map> //#include <map>
//using namespace std; //using namespace std;
#include <vector>
#include "SleepLib/machine.h" // Base class: MachineLoader #include "SleepLib/machine.h" // Base class: MachineLoader
#include "SleepLib/machine_loader.h" #include "SleepLib/machine_loader.h"
#include "SleepLib/profiles.h" #include "SleepLib/profiles.h"
@ -25,6 +26,56 @@ const int resmed_data_version=1;
const QString resmed_class_name="ResMed"; const QString resmed_class_name="ResMed";
struct EDFSignal {
public:
QString label;
QString transducer_type;
QString physical_dimension;
long physical_minimum;
long physical_maximum;
long digital_minimum;
long digital_maximum;
QString prefiltering;
long nr;
QString reserved;
qint16 * data;
char *adata;
};
class EDFParser
{
public:
EDFParser(QString filename);
~EDFParser();
bool Open(QString name);
QString Read(int si);
vector<EDFSignal *> edfsignals;
long GetNumSignals() { return num_signals; };
long GetNumDataRecords() { return num_data_records; };
long GetDuration() { return dur_data_record; };
QString GetPatient() { return patientident; };
bool Parse();
char *buffer;
QString filename;
int filesize;
int pos;
long version;
long num_header_bytes;
long num_data_records;
double dur_data_record;
long num_signals;
QString patientident;
QString recordingident;
QString serialnumber;
QDateTime startdate;
QString reserved44;
};
class ResmedLoader : public MachineLoader class ResmedLoader : public MachineLoader
{ {
public: public:
@ -39,6 +90,11 @@ public:
static void Register(); static void Register();
protected: protected:
map<QString,Machine *> ResmedList; map<QString,Machine *> ResmedList;
bool LoadEVE(Machine *mach,Session *sess,EDFParser &edf);
bool LoadBRP(Machine *mach,Session *sess,EDFParser &edf);
bool LoadSAD(Machine *mach,Session *sess,EDFParser &edf);
bool LoadPLD(Machine *mach,Session *sess,EDFParser &edf);
}; };
#endif // RESMED_LOADER_H #endif // RESMED_LOADER_H

View File

@ -443,7 +443,7 @@ void Daily::Load(QDate date)
QString submodel=tr("Unknown Model"); QString submodel=tr("Unknown Model");
html=html+"<tr><td colspan=4 align=center><i>"+tr("Machine Information")+"</i></td></tr>\n"; //html=html+"<tr><td colspan=4 align=center><i>"+tr("Machine Information")+"</i></td></tr>\n";
if (cpap->machine->properties.find("SubModel")!=cpap->machine->properties.end()) if (cpap->machine->properties.find("SubModel")!=cpap->machine->properties.end())
submodel=" <br>"+cpap->machine->properties["SubModel"]; submodel=" <br>"+cpap->machine->properties["SubModel"];
html=html+"<tr><td colspan=4 align=center><b>"+cpap->machine->properties["Brand"]+"</b> <br>"+cpap->machine->properties["Model"]+" "+cpap->machine->properties["ModelNumber"]+submodel+"</td></tr>\n"; html=html+"<tr><td colspan=4 align=center><b>"+cpap->machine->properties["Brand"]+"</b> <br>"+cpap->machine->properties["Model"]+" "+cpap->machine->properties["ModelNumber"]+submodel+"</td></tr>\n";
@ -484,7 +484,7 @@ void Daily::Load(QDate date)
html=html+("<tr><td colspan=4 align=center><i>")+tr("Event Breakdown")+("</i></td></tr>\n"); html=html+("<tr><td colspan=4 align=center><i>")+tr("Event Breakdown")+("</i></td></tr>\n");
{ {
G_AHI->setFixedSize(gwwidth,gwheight); G_AHI->setFixedSize(gwwidth,gwheight);
QPixmap pixmap=G_AHI->renderPixmap(200,200,false); //gwwidth,gwheight,false); QPixmap pixmap=G_AHI->renderPixmap(120,120,false); //gwwidth,gwheight,false);
QByteArray byteArray; QByteArray byteArray;
QBuffer buffer(&byteArray); // use buffer to store pixmap into byteArray QBuffer buffer(&byteArray); // use buffer to store pixmap into byteArray
buffer.open(QIODevice::WriteOnly); buffer.open(QIODevice::WriteOnly);
@ -823,3 +823,50 @@ void Daily::on_JournalNotesUnderline_clicked()
cursor.mergeCharFormat(format); cursor.mergeCharFormat(format);
//ui->JournalNotes->mergeCurrentCharFormat(format); //ui->JournalNotes->mergeCurrentCharFormat(format);
} }
AHIGraph::AHIGraph(QObject * parent)
{
}
AHIGraph::~AHIGraph()
{
}
QObject * AHIGraph::create(const QString & mimeType, const QUrl & url, const QStringList & argumentNames, const QStringList & argumentValues) const
{
gGraphWindow * ahi;
ahi=new gGraphWindow(NULL,"",(QGLWidget *)NULL);
ahi->SetMargins(0,0,0,0);
gPointData *g_ahi=new AHIData();
//gCandleStick *l=new gCandleStick(g_ahi);
gPieChart *l=new gPieChart(g_ahi);
l->AddName(tr("H"));
l->AddName(tr("OA"));
l->AddName(tr("CA"));
l->AddName(tr("RE"));
l->AddName(tr("FL"));
l->AddName(tr("CSR"));
l->color.clear();
l->color.push_back(QColor("blue"));
l->color.push_back(QColor(0x40,0xaf,0xbf,0xff)); //#40afbf
l->color.push_back(QColor(0xb2,0x54,0xcd,0xff)); //b254cd; //wxPURPLE);
l->color.push_back(QColor("yellow"));
l->color.push_back(QColor(0x40,0x40,0x40,255));
l->color.push_back(QColor(0x60,0xff,0x60,0xff)); //80ff80
return ahi;
}
QList<QWebPluginFactory::Plugin> AHIGraph::plugins() const
{
QWebPluginFactory::MimeType mimeType;
mimeType.name = "text/csv";
mimeType.description = "Comma-separated values";
mimeType.fileExtensions = QStringList() << "csv";
QWebPluginFactory::Plugin plugin;
plugin.name = "Pie Chart";
plugin.description = "A Pie Chart Web plugin.";
plugin.mimeTypes = QList<MimeType>() << mimeType;
return QList<QWebPluginFactory::Plugin>() << plugin;
}

11
daily.h
View File

@ -14,6 +14,7 @@
#include <QTreeWidget> #include <QTreeWidget>
#include <QLabel> #include <QLabel>
#include <QtOpenGL/QGLContext> #include <QtOpenGL/QGLContext>
#include <QWebPluginFactory>
#include <SleepLib/profiles.h> #include <SleepLib/profiles.h>
#include <Graphs/graphwindow.h> #include <Graphs/graphwindow.h>
#include <Graphs/graphdata.h> #include <Graphs/graphdata.h>
@ -82,4 +83,14 @@ private:
QLabel *NoData; QLabel *NoData;
}; };
class AHIGraph:public QWebPluginFactory
{
public:
AHIGraph(QObject * parent = 0);
virtual ~AHIGraph();
virtual QObject * create ( const QString & mimeType, const QUrl & url, const QStringList & argumentNames, const QStringList & argumentValues) const;
virtual QList<Plugin> plugins () const;
//virtual void refreshPlugins ();
};
#endif // DAILY_H #endif // DAILY_H

View File

@ -77,6 +77,11 @@ MainWindow::~MainWindow()
delete ui; delete ui;
Profiles::Done(); Profiles::Done();
} }
void MainWindow::showEvent(QShowEvent * event)
{
if (daily)
daily->RedrawGraphs();
}
void MainWindow::Startup() void MainWindow::Startup()
{ {

View File

@ -59,6 +59,7 @@ private slots:
void on_action_Link_Graphs_triggered(bool checked); void on_action_Link_Graphs_triggered(bool checked);
void on_actionUse_AntiAliasing_triggered(bool checked); void on_actionUse_AntiAliasing_triggered(bool checked);
void showEvent(QShowEvent * event);
private: private:
Ui::MainWindow *ui; Ui::MainWindow *ui;

View File

@ -575,6 +575,17 @@
<addaction name="menu_Help"/> <addaction name="menu_Help"/>
</widget> </widget>
<widget class="QStatusBar" name="statusbar"/> <widget class="QStatusBar" name="statusbar"/>
<widget class="QToolBar" name="toolBar">
<property name="windowTitle">
<string>toolBar</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<action name="action_Import_Data"> <action name="action_Import_Data">
<property name="text"> <property name="text">
<string>&amp;Import Data</string> <string>&amp;Import Data</string>