diff --git a/README b/README
index a7b1d0a3..ac0152fa 100644
--- a/README
+++ b/README
@@ -14,5 +14,6 @@ Licence Stuff
-------------
This software is released under the GNU Public License.
+Exceptions:
Incorporates TinyXML.. see their readme for details in ./libs/tinyxml
-
+Incorporates QextSerialPort. Insert New BSD license here.
diff --git a/mainwindow.ui b/mainwindow.ui
index 5e3071cd..d63dfe5e 100644
--- a/mainwindow.ui
+++ b/mainwindow.ui
@@ -6,8 +6,8 @@
0
0
- 771
- 420
+ 822
+ 468
@@ -555,7 +555,7 @@
0
0
- 771
+ 822
25
diff --git a/oximetry.cpp b/oximetry.cpp
index c4e6a621..2ece7278 100644
--- a/oximetry.cpp
+++ b/oximetry.cpp
@@ -1,13 +1,63 @@
#include
+#include
+
#include "oximetry.h"
#include "ui_oximetry.h"
#include "qextserialport/qextserialenumerator.h"
+#include "SleepLib/loader_plugins/cms50_loader.h"
+#include "Graphs/gXAxis.h"
+#include "Graphs/gBarChart.h"
+#include "Graphs/gLineChart.h"
+#include "Graphs/gYAxis.h"
+#include "Graphs/gFooBar.h"
Oximetry::Oximetry(QWidget *parent) :
QWidget(parent),
ui(new Ui::Oximetry)
{
ui->setupUi(this);
+ port=NULL;
+ QString prof=pref["Profile"].toString();
+ profile=Profiles::Get(prof);
+ if (!profile) {
+ qWarning("Couldn't get profile.. Have to abort!");
+ abort();
+ }
+
+ gSplitter=new QSplitter(Qt::Vertical,ui->scrollArea);
+ gSplitter->setStyleSheet("QSplitter::handle { background-color: 'dark grey'; }");
+ gSplitter->setHandleWidth(2);
+ ui->graphLayout->addWidget(gSplitter);
+
+ AddData(pulse=new WaveData(OXI_Pulse));
+ PULSE=new gGraphWindow(gSplitter,tr("Pulse Rate"),(QGLWidget *)NULL);
+ PULSE->AddLayer(new gXAxis());
+ PULSE->AddLayer(new gYAxis());
+ PULSE->AddLayer(new gFooBar());
+ PULSE->AddLayer(new gLineChart(pulse,Qt::red,65536,false,false,false));
+ PULSE->setMinimumHeight(150);
+
+ AddData(spo2=new WaveData(OXI_SPO2));
+ SPO2=new gGraphWindow(gSplitter,tr("SPO2"),(QGLWidget *)NULL);
+ SPO2->AddLayer(new gXAxis());
+ SPO2->AddLayer(new gYAxis());
+ SPO2->AddLayer(new gFooBar());
+ SPO2->AddLayer(new gLineChart(spo2,Qt::red,65536,false,false,false));
+ SPO2->setMinimumHeight(150);
+
+ AddData(plethy=new WaveData(OXI_Plethy));
+ PLETHY=new gGraphWindow(gSplitter,tr("Plethysomogram"),(QGLWidget *)NULL);
+ PLETHY->AddLayer(new gXAxis());
+ PLETHY->AddLayer(new gYAxis());
+ PLETHY->AddLayer(new gFooBar());
+ PLETHY->AddLayer(new gLineChart(plethy,Qt::red,65536,false,false,false));
+ PLETHY->setMinimumHeight(150);
+
+ portname="";
+
+ gSplitter->addWidget(PULSE);
+ gSplitter->addWidget(SPO2);
+ gSplitter->addWidget(PLETHY);
on_RefreshPortsButton_clicked();
}
@@ -22,9 +72,16 @@ void Oximetry::on_RefreshPortsButton_clicked()
QList ports = QextSerialEnumerator::getPorts();
ui->SerialPortsCombo->clear();
+ int z=0;
+ QString firstport;
+ bool current_found=false;
for (int i = 0; i < ports.size(); i++) {
- if (ports.at(i).friendName.toUpper().contains("USB"))
- ui->SerialPortsCombo->addItem(ports.at(i).portName);
+ if (ports.at(i).friendName.toUpper().contains("USB")) {
+ if (firstport.isEmpty()) firstport=ports.at(i).physName;
+ if (!portname.isEmpty() && ports.at(i).physName==portname) current_found=true;
+ ui->SerialPortsCombo->addItem(ports.at(i).physName);
+ z++;
+ }
//qDebug() << "port name:" << ports.at(i).portName;
qDebug() << "Serial Port:" << ports.at(i).physName << ports.at(i).friendName;
//qDebug() << "enumerator name:" << ports.at(i).enumName;
@@ -32,4 +89,296 @@ void Oximetry::on_RefreshPortsButton_clicked()
//qDebug() << "product ID:" << QString::number(ports.at(i).productID, 16);
//qDebug() << "===================================";
}
+
+ if (z>0) {
+ ui->RunButton->setEnabled(true);
+ ui->ImportButton->setEnabled(true);
+ if (!current_found) portname=firstport;
+ } else {
+ ui->RunButton->setEnabled(false);
+ ui->ImportButton->setEnabled(false);
+ portname="";
+ }
+}
+void Oximetry::RedrawGraphs()
+{
+ for (list::iterator g=Graphs.begin();g!=Graphs.end();g++) {
+ (*g)->updateGL();
+ }
+}
+
+void Oximetry::on_RunButton_toggled(bool checked)
+{
+ if (checked) {
+ ui->RunButton->setText("&Stop");
+ ui->SerialPortsCombo->setEnabled(false);
+ // Disconnect??
+ port=new QextSerialPort(portname,QextSerialPort::EventDriven);
+ port->setBaudRate(BAUD19200);
+ port->setFlowControl(FLOW_OFF);
+ port->setParity(PAR_ODD);
+ port->setDataBits(DATA_8);
+ port->setStopBits(STOP_1);
+ if (port->open(QIODevice::ReadWrite) == true) {
+ connect(port, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
+ connect(port, SIGNAL(dsrChanged(bool)), this, SLOT(onDsrChanged(bool)));
+ if (!(port->lineStatus() & LS_DSR))
+ qDebug() << "warning: device is not turned on";
+ qDebug() << "listening for data on" << port->portName();
+ } else {
+ qDebug() << "device failed to open:" << port->errorString();
+ }
+ portmode=PM_LIVE;
+ } else {
+ ui->RunButton->setText("&Start");
+ ui->SerialPortsCombo->setEnabled(true);
+ delete port;
+ port=NULL;
+
+ }
+}
+
+void Oximetry::on_SerialPortsCombo_activated(const QString &arg1)
+{
+ portname=arg1;
+}
+
+void Oximetry::onReadyRead()
+{
+ static int lastpulse=-1, lastspo2=-1;
+ static int lastsize=-1;
+ QByteArray bytes;
+ int a = port->bytesAvailable();
+ bytes.resize(a);
+ port->read(bytes.data(), bytes.size());
+ /*if (portmode!=PM_RECORDING) {
+ return;
+ }
+ if (bytes.size()==3) { // control & waveform bytes
+ if ((bytes[0]==0xf0) && (bytes[1]==0x80) && (bytes[2]==0x00)) portmode==PM_LIVE;
+ //qDebug() << "A=" << int(bytes[0]) << "B=" << int(bytes[1]) << "C=" << int(bytes[2]);
+ // Pulse data..
+ } else if (bytes.size()==2) { // Data bytes in live mode
+ // Plethy data
+ if (lastpulse!=bytes[0])
+ qDebug() << "Pulse=" << int(bytes[0]);
+ if (lastspo2!=bytes[1])
+ qDebug() << "SpO2=" << int(bytes[1]);
+
+ lastpulse=bytes[0];
+ lastspo2=bytes[1];
+ } else {
+ qDebug() << "bytes read:" << bytes.size(); */
+ QString aa;
+ for (int i=0;iwrite(b);
+ portmode=PM_LIVE;
+ qDebug() << "Killing Record Retrieval Mode";
+
+ } */
+ lastsize=bytes.size();
+}
+void Oximetry::onDsrChanged(bool status)
+{
+ if (status)
+ qDebug() << "device was turned on";
+ else
+ qDebug() << "device was turned off";
+}
+extern QProgressBar *qprogress;
+extern QLabel *qstatus;
+
+// Move this code to CMS50 Importer??
+void Oximetry::on_ImportButton_clicked()
+{
+ Machine *mach=profile->GetMachine(MT_OXIMETER);
+ if (!mach) {
+ CMS50Loader *l=dynamic_cast(GetLoader("CMS50"));
+ if (l) {
+ mach=l->CreateMachine(profile);
+ }
+
+ qDebug() << "Needed to create Oximeter device";
+ }
+ unsigned char b1[2];
+ unsigned char b2[3];
+ unsigned char rb[0x20];
+ b1[0]=0xf5;
+ b1[1]=0xf5;
+ b2[0]=0xf6;
+ b2[1]=0xf6;
+ b2[2]=0xf6;
+ unsigned char * buffer=NULL;
+ ui->SerialPortsCombo->setEnabled(false);
+ ui->RunButton->setText("&Start");
+ ui->RunButton->setChecked(false);
+
+ // port->write((char *)b1,2);
+ // return;
+ if (port) {
+ port->close();
+ delete port;
+ }
+ // Disconnect??
+ //qDebug() << "Initiating Polling Mode";
+ port=new QextSerialPort(portname,QextSerialPort::Polling);
+ port->setBaudRate(BAUD19200);
+ port->setFlowControl(FLOW_OFF);
+ port->setParity(PAR_ODD);
+ port->setDataBits(DATA_8);
+ port->setStopBits(STOP_1);
+ port->setTimeout(500);
+ if (port->open(QIODevice::ReadWrite) == true) {
+ // if (!(port->lineStatus() & LS_DSR))
+ // qDebug() << "warning: device is not turned on"; // CMS50 doesn't do this..
+
+ } else {
+ delete port;
+ port=NULL;
+ ui->SerialPortsCombo->setEnabled(true);
+
+ return;
+ }
+ bool done=false;
+ int res;
+ int blocks=0;
+ unsigned int bytes=0;
+ QString aa;
+ port->flush();
+ bool oneoff=false;
+
+ //qprogress->reset();
+ qstatus->setText("Importing");
+ qprogress->setValue(0);
+ qprogress->show();
+ int fails=0;
+ while (!done) {
+
+ //port->setRts(true);
+ if (port->write((char *)b1,2)==-1) {
+ qDebug() << "Couldn't write 2 lousy bytes to CMS50";
+ }
+ //usleep(500);
+ // port->setRts(false);
+ //qDebug() << "Available " << port->bytesAvailable();
+ blocks=0;
+ int startpos=0;
+ unsigned int length=0;
+ do {
+ bool fnd=false;
+ res=port->read((char *)rb,0x20);
+
+ if (blocks==0) {
+ for (int i=0;isetValue((100.0/length)*bytes);
+ memcpy((char *)&buffer[bytes],(char *)rb,res);
+ bytes+=res;
+ }
+ //aa="";
+ //for (int i=0;i4) break;
+ }
+ if (done) {
+ if (oneoff) bytes--; // this is retarded..
+
+ QDateTime date=QDateTime::currentDateTimeUtc();
+ SessionID sid=date.toTime_t();
+ Session *sess=new Session(mach,sid);
+ qDebug() << "Read " << bytes << "Bytes";
+ qDebug() << "Creating session " << sid;
+ char pulse,spo2,lastpulse=-1,lastspo2=-1;
+
+ qint64 tt=sid-(bytes/3);
+ tt*=1000;
+ sess->set_first(tt);
+ EventDataType data;
+ unsigned i=0;
+ while (iAddEvent(new Event(tt,OXI_Pulse,&data,1));
+ //qDebug() << "Pulse: " << int(pulse);
+ }
+ if (spo2 != 0 && spo2!=lastspo2) {
+ data=spo2;
+ sess->AddEvent(new Event(tt,OXI_SPO2,&data,1));
+ //qDebug() << "SpO2: " << int(spo2);
+ }
+
+ lastpulse=pulse;
+ lastspo2=spo2;
+ tt+=1000;
+ }
+ data=pulse;
+ sess->AddEvent(new Event(tt,OXI_Pulse,&data,1));
+ data=spo2;
+ sess->AddEvent(new Event(tt,OXI_SPO2,&data,1));
+ sess->summary[OXI_PulseMin]=sess->min_event_field(OXI_Pulse,0);
+ sess->summary[OXI_PulseMax]=sess->max_event_field(OXI_Pulse,0);
+ sess->summary[OXI_PulseAverage]=sess->weighted_avg_event_field(OXI_Pulse,0);
+ sess->summary[OXI_SPO2Min]=sess->min_event_field(OXI_SPO2,0);
+ sess->summary[OXI_SPO2Max]=sess->max_event_field(OXI_SPO2,0);
+ sess->summary[OXI_SPO2Average]=sess->weighted_avg_event_field(OXI_SPO2,0);
+ sess->SetChanged(true);
+ mach->AddSession(sess,profile);
+ mach->Save();
+ // Output Pulse & SPO2 here..
+ delete [] buffer;
+ port->write((char *)b2,3);
+ }
+ delete port;
+ port=NULL;
+ qprogress->hide();
+ ui->SerialPortsCombo->setEnabled(true);
+ qstatus->setText("Ready");
}
diff --git a/oximetry.h b/oximetry.h
index 92f87b37..7c64c4bf 100644
--- a/oximetry.h
+++ b/oximetry.h
@@ -2,11 +2,19 @@
#define OXIMETRY_H
#include
+#include
+#include
+
+#include "SleepLib/profiles.h"
+#include "Graphs/graphwindow.h"
+#include "Graphs/graphdata_custom.h"
namespace Ui {
class Oximetry;
}
+enum PORTMODE { PM_LIVE, PM_RECORDING };
+
class Oximetry : public QWidget
{
Q_OBJECT
@@ -15,11 +23,32 @@ public:
explicit Oximetry(QWidget *parent = 0);
~Oximetry();
+ void AddData(gPointData *d) { Data.push_back(d); };
+ void AddGraph(gGraphWindow *w) { Graphs.push_back(w); };
+ void RedrawGraphs();
+
private slots:
void on_RefreshPortsButton_clicked();
+ void on_RunButton_toggled(bool checked);
+
+ void on_SerialPortsCombo_activated(const QString &arg1);
+ void onReadyRead();
+ void onDsrChanged(bool status);
+
+ void on_ImportButton_clicked();
+
private:
Ui::Oximetry *ui;
+ Profile *profile;
+ QSplitter *gSplitter;
+ gPointData *pulse,*spo2,*plethy;
+ gGraphWindow *PULSE,*SPO2,*PLETHY;
+ list Graphs;
+ list Data;
+ QextSerialPort *port;
+ QString portname;
+ PORTMODE portmode;
};
#endif // OXIMETRY_H
diff --git a/oximetry.ui b/oximetry.ui
index 7f3398d4..dbf18b86 100644
--- a/oximetry.ui
+++ b/oximetry.ui
@@ -47,7 +47,7 @@
0
-
-
+
0
@@ -94,6 +94,16 @@
+ -
+
+
+ &Start
+
+
+ true
+
+
+
-
@@ -110,7 +120,7 @@
-
- Import from Device
+ &Import from Device