From 19e9528c4be0d5a1e4a7b71c81808bbe909a2920 Mon Sep 17 00:00:00 2001
From: Mark Watkins
Date: Fri, 2 Dec 2011 15:54:25 +1000
Subject: [PATCH] Added optional second EventList data field, upgraded Session
Load/Store code, Modified oximetery Pulse/SPO2 flag to record extra field,
Retain mask info in Preferences Tab
---
SleepLib/calcs.cpp | 17 ++++---
SleepLib/event.cpp | 28 +++++++---
SleepLib/event.h | 18 +++++--
SleepLib/machine_common.h | 4 +-
SleepLib/preferences.cpp | 4 +-
SleepLib/session.cpp | 69 ++++++++++++++++++++-----
SleepLib/session.h | 3 +-
daily.cpp | 2 +-
daily.ui | 104 ++++++++++++++++++--------------------
docs/release_notes.html | 15 +++---
oximetry.cpp | 24 ++++++---
preferencesdialog.cpp | 25 +++++++--
preferencesdialog.ui | 27 ++++++++--
13 files changed, 222 insertions(+), 118 deletions(-)
diff --git a/SleepLib/calcs.cpp b/SleepLib/calcs.cpp
index 9b601e99..d98b0697 100644
--- a/SleepLib/calcs.cpp
+++ b/SleepLib/calcs.cpp
@@ -410,12 +410,13 @@ int calcPulseChange(Session *session)
change=5;
}
- EventList *pc=new EventList(EVL_Event);
+ EventList *pc=new EventList(EVL_Event,1,0,0,0,0,true);
pc->setFirst(session->first(OXI_Pulse));
qint64 lastt;
EventDataType lv=0;
int li=0;
+ int max;
for (int e=0;e lv) {
lastt=time2;
+ if (tmp>max) max=tmp;
//lv=tmp;
li=j;
}
}
if (lastt>0) {
qint64 len=(lastt-time)/1000.0;
- pc->AddEvent(lastt,len);
+ pc->AddEvent(lastt,len,tmp);
i=li;
}
@@ -481,7 +484,7 @@ int calcSPO2Drop(Session *session)
change=3;
}
- EventList *pc=new EventList(EVL_Event);
+ EventList *pc=new EventList(EVL_Event,1,0,0,0,0,true);
qint64 lastt;
EventDataType lv=0;
int li=0;
@@ -489,10 +492,9 @@ int calcSPO2Drop(Session *session)
const unsigned ringsize=10;
EventDataType ring[ringsize];
int rp=0;
-
+ int min;
for (int e=0;e0) {
qint64 len=(lastt-time);
if (len>=window) {
- pc->AddEvent(lastt,len/1000);
+ pc->AddEvent(lastt,len/1000,val-min);
i=li;
}
diff --git a/SleepLib/event.cpp b/SleepLib/event.cpp
index e468ee21..11e4f477 100644
--- a/SleepLib/event.cpp
+++ b/SleepLib/event.cpp
@@ -7,16 +7,17 @@
#include
#include "event.h"
-EventList::EventList(EventListType et,EventDataType gain, EventDataType offset, EventDataType min, EventDataType max,double rate)
- :m_type(et),m_gain(gain),m_offset(offset),m_min(min),m_max(max),m_rate(rate)
+EventList::EventList(EventListType et,EventDataType gain, EventDataType offset, EventDataType min, EventDataType max,double rate,bool second_field)
+ :m_type(et),m_gain(gain),m_offset(offset),m_min(min),m_max(max),m_rate(rate),m_second_field(second_field)
{
m_first=m_last=0;
m_count=0;
if (min==max) { // Update Min & Max unless forceably set here..
m_update_minmax=true;
- m_min=999999999;
- m_max=-999999999;
+ m_min2=m_min=999999999;
+ m_max2=m_max=-999999999;
+
} else {
m_update_minmax=false;
}
@@ -39,11 +40,22 @@ EventDataType EventList::data(quint32 i)
{
return EventDataType(m_data[i])*m_gain;
}
+EventDataType EventList::data2(quint32 i)
+{
+ return EventDataType(m_data2[i]);
+}
-void EventList::AddEvent(qint64 time, EventStoreType data)
+void EventList::AddEvent(qint64 time, EventStoreType data, EventStoreType data2)
{
// Apply gain & offset
m_data.push_back(data);
+
+ if (m_second_field) {
+ m_data2.push_back(data2);
+ if (m_min2>data2) m_min2=data2;
+ if (m_max2val) m_min=val;
@@ -58,14 +70,14 @@ void EventList::AddEvent(qint64 time, EventStoreType data)
// Crud.. Update all the previous records
// This really shouldn't happen.
- qint64 t=(m_first-time);
+ qint32 t=(m_first-time);
for (quint32 i=0;i & getData() { return m_data; }
+ QVector & getData2() { return m_data2; }
QVector & getTime() { return m_time; }
protected:
QVector m_time; // 32bitalize this.. add offsets to m_first
QVector m_data;
+ QVector m_data2;
//ChannelID m_code;
EventListType m_type;
quint32 m_count;
EventDataType m_gain;
EventDataType m_offset;
- EventDataType m_min;
- EventDataType m_max;
+ EventDataType m_min,m_min2;
+ EventDataType m_max,m_max2;
EventDataType m_rate; // Waveform sample rate
QString m_dimension;
qint64 m_first,m_last;
bool m_update_minmax;
+ bool m_second_field;
};
diff --git a/SleepLib/machine_common.h b/SleepLib/machine_common.h
index 30e82e9e..d76cf83d 100644
--- a/SleepLib/machine_common.h
+++ b/SleepLib/machine_common.h
@@ -24,9 +24,7 @@ typedef qint16 EventStoreType;
class BoundsError {};
class OldDBVersion {};
-// This is the uber important database version for SleepyHeads internal storage
-// Increment this after stuffing with Session's save & load code.
-const quint16 dbversion=6;
+const quint32 magic=0xC73216AB; // Magic number for Sleepyhead Data Files.. Don't touch!
//const int max_number_event_fields=10;
diff --git a/SleepLib/preferences.cpp b/SleepLib/preferences.cpp
index 2ee02420..45e394d8 100644
--- a/SleepLib/preferences.cpp
+++ b/SleepLib/preferences.cpp
@@ -68,7 +68,7 @@ Preference::Preference(Preferences * pref,QString code, PrefType type, QString l
void Preference::setValue(QVariant v)
{
if (!m_pref) {
- qDebug() << "Bad Preferences object";
+ qDebug() << "Bad Preferences object" << m_code;
return;
}
if (m_pref)
@@ -76,7 +76,7 @@ void Preference::setValue(QVariant v)
}
QVariant & Preference::value() {
if (!m_pref) {
- qDebug() << "Bad Preferences object";
+ qDebug() << "Bad Preferences object" << m_code;
return m_defaultValue;
}
QHash::iterator i=m_pref->find(m_code);
diff --git a/SleepLib/session.cpp b/SleepLib/session.cpp
index 208b3283..8c03b5a2 100644
--- a/SleepLib/session.cpp
+++ b/SleepLib/session.cpp
@@ -16,6 +16,15 @@
using namespace std;
+
+const quint16 filetype_summary=0;
+const quint16 filetype_data=1;
+
+// This is the uber important database version for SleepyHeads internal storage
+// Increment this after stuffing with Session's save & load code.
+const quint16 summary_version=6;
+const quint16 events_version=7;
+
Session::Session(Machine * m,SessionID session)
{
if (!session) {
@@ -103,9 +112,6 @@ bool Session::Store(QString path)
return a;
}
-const quint16 filetype_summary=0;
-const quint16 filetype_data=1;
-
bool Session::StoreSummary(QString filename)
{
@@ -117,7 +123,7 @@ bool Session::StoreSummary(QString filename)
out.setByteOrder(QDataStream::LittleEndian);
out << (quint32)magic;
- out << (quint16)dbversion;
+ out << (quint16)summary_version;
out << (quint16)filetype_summary;
out << (quint32)s_machine->id();
@@ -180,7 +186,7 @@ bool Session::LoadSummary(QString filename)
}
in >> t16; // DB Version
- if (t16!=dbversion) {
+ if (t16!=summary_version) {
throw OldDBVersion();
//qWarning() << "Old dbversion "<< t16 << "summary file.. Sorry, you need to purge and reimport";
return false;
@@ -241,7 +247,7 @@ bool Session::StoreEvents(QString filename)
out.setByteOrder(QDataStream::LittleEndian);
out << (quint32)magic; // Magic Number
- out << (quint16)dbversion; // File Version
+ out << (quint16)events_version; // File Version
out << (quint16)filetype_data; // File type 1 == Event
out << (quint32)s_machine->id();// Machine ID
@@ -269,6 +275,11 @@ bool Session::StoreEvents(QString filename)
out << e.min();
out << e.max();
out << e.dimension();
+ out << e.hasSecondField();
+ if (e.hasSecondField()) {
+ out << e.min2();
+ out << e.max2();
+ }
}
}
for (i=eventlist.begin(); i!=eventlist.end(); i++) {
@@ -278,6 +289,11 @@ bool Session::StoreEvents(QString filename)
for (quint32 c=0;c> t32; // Magic Number
if (t32!=magic) {
qWarning() << "Wrong Magic number in " << filename;
return false;
}
- in >> t16; // File Version
- if (t16!=dbversion) {
+
+ in >> version; // File Version
+
+ if (version<6) { // prior to version 6 is too old to deal with
throw OldDBVersion();
//qWarning() << "Old dbversion "<< t16 << "summary file.. Sorry, you need to purge and reimport";
return false;
@@ -367,18 +386,31 @@ bool Session::LoadEvents(QString filename)
in >> mn;
in >> mx;
in >> dim;
- EventList *elist=AddEventList(code,elt,gain,offset,mn,mx,rate);
+ bool second_field=false;
+ if (version>=7) // version 7 added this field
+ in >> second_field;
+
+ EventList *elist=AddEventList(code,elt,gain,offset,mn,mx,rate,second_field);
elist->setDimension(dim);
//eventlist[code].push_back(elist);
elist->m_count=evcount;
elist->m_first=ts1;
elist->m_last=ts2;
+
+ if (second_field) {
+ EventDataType min,max;
+ in >> min;
+ in >> max;
+ elist->setMin2(min);
+ elist->setMax2(max);
+ }
}
}
EventStoreType t;
quint32 x;
+
for (int i=0;i> t;
- //evec.m_data[c]=t;
evec.m_data.push_back(t);
}
+ if (evec.hasSecondField()) {
+ evec.m_data2.reserve(evec.m_count);
+ for (quint32 c=0;c> t;
+ evec.m_data2.push_back(t);
+ }
+ }
//last=evec.first();
if (evec.type()!=EVL_Waveform) {
evec.m_time.reserve(evec.m_count);
@@ -402,6 +440,13 @@ bool Session::LoadEvents(QString filename)
}
}
}
+ file.close();
+
+ if (versionregisterChannel(chan);
return el;
diff --git a/SleepLib/session.h b/SleepLib/session.h
index f38fb1e4..48b9aa17 100644
--- a/SleepLib/session.h
+++ b/SleepLib/session.h
@@ -17,7 +17,6 @@
#include "SleepLib/event.h"
//class EventList;
class Machine;
-const quint32 magic=0xC73216AB;
enum SummaryType { ST_CNT, ST_SUM, ST_AVG, ST_WAVG, ST_90P, ST_MIN, ST_MAX, ST_CPH, ST_SPH, ST_FIRST, ST_LAST, ST_HOURS, ST_SESSIONS, ST_SETMIN, ST_SETAVG, ST_SETMAX, ST_SETWAVG, ST_SETSUM };
@@ -137,7 +136,7 @@ public:
qint64 last(ChannelID code);
void UpdateSummaries();
- EventList * AddEventList(QString chan, EventListType et, EventDataType gain=1.0, EventDataType offset=0.0, EventDataType min=0.0, EventDataType max=0.0, EventDataType rate=0.0);
+ EventList * AddEventList(QString chan, EventListType et, EventDataType gain=1.0, EventDataType offset=0.0, EventDataType min=0.0, EventDataType max=0.0, EventDataType rate=0.0, bool second_field=false);
Machine * machine() { return s_machine; }
protected:
SessionID s_session;
diff --git a/daily.cpp b/daily.cpp
index ec0771d2..536120a7 100644
--- a/daily.cpp
+++ b/daily.cpp
@@ -162,7 +162,7 @@ Daily::Daily(QWidget *parent,gGraphView * shared, MainWindow *mw)
FRW->AddLayer(AddCPAP(los->add(new gLineOverlayBar(CPAP_Obstructive,QColor("#40c0ff"),"OA"))));
FRW->AddLayer(AddCPAP(los->add(new gLineOverlayBar(CPAP_ClearAirway,QColor("purple"),"CA"))));
FRW->AddLayer(AddOXI(new gLineOverlayBar(OXI_SPO2Drop,QColor("red"),"O2")));
- FRW->AddLayer(AddOXI(new gLineOverlayBar(OXI_PulseChange,QColor("blue"),"PC")));
+ FRW->AddLayer(AddOXI(new gLineOverlayBar(OXI_PulseChange,QColor("blue"),"PC",FT_Dot)));
FRW->AddLayer(AddCPAP(los));
diff --git a/daily.ui b/daily.ui
index 9fc5d67c..43fb69fc 100644
--- a/daily.ui
+++ b/daily.ui
@@ -7,7 +7,7 @@
0
0
671
- 315
+ 433
@@ -19,7 +19,7 @@
Form
-
+
0
@@ -670,66 +670,60 @@
-
-
-
- 5
+
+
+ Qt::Vertical
+
+
+
+
+ 1
+ 0
+
- -
-
-
-
- 1
- 0
-
+
+
+
+
+ 16777215
+ 50
+
+
+
+ Qt::ScrollBarAlwaysOff
+
+
+ Qt::ScrollBarAlwaysOn
+
+
+ true
+
+
+
+
+ 0
+ 0
+ 82
+ 33
+
+
+
+
+ 2
-
-
- -
-
-
-
- 16777215
- 50
-
+
+ 0
-
- Qt::ScrollBarAlwaysOff
-
-
- Qt::ScrollBarAlwaysOn
-
-
- true
-
-
-
-
- 0
- 0
- 82
- 33
-
-
-
+
-
+
2
-
- 0
-
-
-
-
-
- 2
-
-
-
-
-
-
-
+
+
+
+
diff --git a/docs/release_notes.html b/docs/release_notes.html
index 626293c1..9578b8bf 100644
--- a/docs/release_notes.html
+++ b/docs/release_notes.html
@@ -10,18 +10,19 @@
What's New?
Intellipap Support
+Print Support in Daily View, Overview and Oximetry
+New Graph tab in Preferences for changing individual graph settings, visibility, etc.
+New Respiratory Rate, Tidal Volume and Minute Ventilation graphs for PRS1 users.
Complete rewrite of Oximetery Tab, it's now (hopefully) working much better
-Sync problems with Live serial CMS50 recording fixed.
-Preference option to Skip Login Window
-Can now change how much data is shown around events selected in the Event List.
+Oximetry PulseChange & SPO2Drop event flagging.. (Options in Preferences)
+Clock problems with Live serial CMS50 recording fixed.
Import now remembers your locations.. There is a preferences tab to edit common locations
-New Respiratory Rate graph for PRS1 users
-New Graph tab in Preferences for changing individual graph settings
+Can now change how much data is shown around events selected in the Event List.
+Preference option to Skip Login Window
Quite a few other little bugfixes I've forgotten about.
What's still missing/broken?
-Daily report printing still needs doing.
-Plenty more I'm sure of it..
+Plenty of bugs, I'm sure of it..
Problems & Stuff?
diff --git a/oximetry.cpp b/oximetry.cpp
index 43650485..b0207d9e 100644
--- a/oximetry.cpp
+++ b/oximetry.cpp
@@ -353,8 +353,9 @@ void CMS50Serial::on_import_process()
unsigned char a,pl,o2,lastpl=0,lasto2=0;
int i=0;
int size=data.size();
- EventList * pulse=NULL; //(session->eventlist[OXI_Pulse][0]);
- EventList * spo2=NULL; // (session->eventlist[OXI_SPO2][0]);
+
+ EventList * pulse=(session->eventlist[OXI_Pulse][0]);
+ EventList * spo2=(session->eventlist[OXI_SPO2][0]);
lasttime=f2time[0].toTime_t();
session->SetSessionID(lasttime);
lasttime*=1000;
@@ -379,8 +380,12 @@ void CMS50Serial::on_import_process()
}
if (plcnt==0)
session->setFirst(OXI_Pulse,lasttime);
- pulse=new EventList(EVL_Event);
- session->eventlist[OXI_Pulse].push_back(pulse);
+ if (pulse && pulse->count()==0) {
+
+ } else {
+ pulse=new EventList(EVL_Event);
+ session->eventlist[OXI_Pulse].push_back(pulse);
+ }
}
lastpltime=lasttime;
pulse->AddEvent(lasttime,pl);
@@ -398,8 +403,11 @@ void CMS50Serial::on_import_process()
}
if (o2cnt==0)
session->setFirst(OXI_SPO2,lasttime);
- spo2=new EventList(EVL_Event);
- session->eventlist[OXI_SPO2].push_back(spo2);
+ if (spo2 && spo2->count()==0) {
+ } else {
+ spo2=new EventList(EVL_Event);
+ session->eventlist[OXI_SPO2].push_back(spo2);
+ }
}
lasto2time=lasttime;
spo2->AddEvent(lasttime,o2);
@@ -988,8 +996,8 @@ void Oximetry::on_import_complete(Session * session)
qDebug() << "Oximetry import complete";
import_finished();
- calcSPO2Drop(session);
- calcPulseChange(session);
+ //calcSPO2Drop(session);
+ //calcPulseChange(session);
ui->pulseLCD->display(session->min(OXI_Pulse));
ui->spo2LCD->display(session->min(OXI_SPO2));
diff --git a/preferencesdialog.cpp b/preferencesdialog.cpp
index 2acaa718..ad908309 100644
--- a/preferencesdialog.cpp
+++ b/preferencesdialog.cpp
@@ -48,10 +48,10 @@ PreferencesDialog::PreferencesDialog(QWidget *parent,Profile * _profile) :
for (int i=0;imaskTypeCombo->addItem(masks[i].name);
- if (masktype==masks[i].name) {
+ /*if (masktype==masks[i].name) {
ui->maskTypeCombo->setCurrentIndex(i);
on_maskTypeCombo_activated(i);
- }
+ }*/
}
QLocale locale=QLocale::system();
QString shortformat=locale.dateFormat(QLocale::ShortFormat);
@@ -71,6 +71,7 @@ PreferencesDialog::PreferencesDialog(QWidget *parent,Profile * _profile) :
ui->startedUsingMask->calendarWidget()->setWeekdayTextFormat(Qt::Sunday, format);
+
//ui->leakProfile->setColumnWidth(1,ui->leakProfile->width()/2);
{
@@ -168,11 +169,25 @@ PreferencesDialog::PreferencesDialog(QWidget *parent,Profile * _profile) :
general["MemoryHog"]=Preference(p_profile,"MemoryHog",PT_Checkbox,"Cache Session Data","Keep session data in memory to improve load speed revisiting the date.",false);
general["GraphHeight"]=Preference(p_profile,"GraphHeight",PT_Checkbox,"Graph Height","Default Graph Height",160);
general["MaskDescription"]=Preference(p_profile,"MaskDescription",PT_Checkbox,"Mask Description","Whatever you want to record about your mask.",QString());
- general["MaskStartDate"]=Preference(p_profile,"GraphHeight",PT_Checkbox,"Graph Height","Default Graph Height",QDate::currentDate());
+
+ if (!(p_profile)->Exists("MaskStartDate")) {
+ (PROFILE["MaskStartDate"]=PROFILE.FirstDay());
+ }
+ ui->startedUsingMask->setDate((*profile)["MaskStartDate"].toDate());
+
+ if (!(p_profile)->Exists("ShowLeaksMode")) {
+ PROFILE["ShowLeaksMode"]=0;
+ }
+ ui->leakModeCombo->setCurrentIndex((*profile)["ShowLeaksMode"].toInt());
+ if (!(p_profile)->Exists("MaskType")) {
+ PROFILE["MaskType"]=0;
+ }
+ int mt=(*profile)["MaskType"].toInt();
+ ui->maskTypeCombo->setCurrentIndex(mt);
+ on_maskTypeCombo_activated(mt);
ui->maskDescription->setText(general["MaskDescription"].value().toString());
- ui->startedUsingMask->setDate(general["MaskStartDate"].value().toDate());
ui->useAntiAliasing->setChecked(general["UseAntiAliasing"].value().toBool());
ui->useSquareWavePlots->setChecked(general["SquareWavePlots"].value().toBool());
@@ -311,6 +326,8 @@ void PreferencesDialog::Save()
(*profile)["DaySplitTime"]=ui->timeEdit->time();
(*profile)["AlwaysShowOverlayBars"]=ui->overlayFlagsCombo->currentIndex();
+ (*profile)["ShowLeaksMode"]=ui->leakModeCombo->currentIndex();
+ (*profile)["MaskType"]=ui->maskTypeCombo->currentIndex();
//(*profile)["UseAntiAliasing"]=ui->genOpWidget->item(0)->checkState()==Qt::Checked;
//(*profile)["MemoryHog"]=ui->memoryHogCheckbox->isChecked();
//(*profile)["EnableGraphSnapshots"]=ui->genOpWidget->item(2)->checkState()==Qt::Checked;
diff --git a/preferencesdialog.ui b/preferencesdialog.ui
index 2f724378..6059ed68 100644
--- a/preferencesdialog.ui
+++ b/preferencesdialog.ui
@@ -38,7 +38,7 @@
-
- 4
+ 0
@@ -567,7 +567,20 @@ p, li { white-space: pre-wrap; }
Hmmm... Empty Space
-Mask History could go here one day
+Mask History could go here one day
+
+For now a reminder for PRS1 Users
+The lower leak does not yet show unintentional
+leaks. It currently showns the leak line
+subtracted from the 0% percentile
+(aka the minimum value)
+
+<--- None of this data is being used yet!
+
+To solve this properly requires some fairly
+complex forumulae derived from the
+Mask Leak Profiles
+(Believe it or not, I am not a maths geek)
Qt::AlignCenter
@@ -909,11 +922,15 @@ Mask History could go here one day
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
p, li { white-space: pre-wrap; }
</style></head><body style=" font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;">
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Please Note:<span style=" font-style:italic;"> It is impossible to sync oximetry data with CPAP data without a valid timestamp.</span></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Syncing Oximetry and CPAP Data</span></p>
<p align="justify" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
-<p align="justify" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">CMS50 data imported from SpO2Review (from .spoR files) or the serial import method does <span style=" font-weight:600; text-decoration: underline;">not</span> have the correct timestamp needed to do this.</p>
+<p align="justify" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">CMS50 data imported from SpO2Review (from .spoR files) or the serial import method does <span style=" font-weight:600; text-decoration: underline;">not</span> have the correct timestamp needed to sync.</p>
<p align="justify" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
-<p align="justify" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Live view mode (using a serial cable) is the only way to acheive an accurate sync on CMS50 oximeters.</p></body></html>
+<p align="justify" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Live view mode (using a serial cable) is one way to acheive an accurate sync on CMS50 oximeters, but does not counter for CPAP clock drift.</p>
+<p align="justify" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
+<p align="justify" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If you start your Oximeters recording mode at <span style=" font-style:italic;">exactly </span>the same time you start your CPAP machine, you can now also achieve sync. </p>
+<p align="justify" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p>
+<p align="justify" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The serial import process takes the starting time from last nights first CPAP session. (Remember to import your CPAP data first!)</p></body></html>