::iterator di;
for (di=profile->daylist[date].begin();di!=profile->daylist[date].end();di++) {
- if ((*di)->machine_type()==MT_CPAP) {
+ if (!d && ((*di)->machine_type()==MT_CPAP)) {
d=(*di);
- break;
+ UpdateCPAPGraphs(d);
+ }
+ if ((*di)->machine_type()==MT_OXIMETER) {
+ oxi=(*di);
+ UpdateOXIGraphs(oxi);
}
}
}
- UpdateGraphs(d);
if (d) {
CPAPMode mode=(CPAPMode)d->summary_max(CPAP_Mode);
if (mode!=MODE_BIPAP) {
@@ -765,8 +787,6 @@ void Daily::RefreshData()
EventTree->SortChildren(root);
EventTree->Expand(root);
- fgSizer->Layout();
- ScrolledWindow->FitInside();
PRTypes pr=(PRTypes)d->summary_max(CPAP_PressureReliefType);
wxString epr=PressureReliefNames[pr]+wxString::Format(wxT(" x%i"),(int)d->summary_max(CPAP_PressureReliefSetting));
@@ -834,6 +854,25 @@ void Daily::RefreshData()
}
html=html+wxT("")+_("Avg Leak")+wxT(" | ")+wxString::Format(wxT("%.2f"),d->summary_weighted_avg(CPAP_LeakAverage))+wxT(" |
\n");
+ html=html+wxT(" | |
\n");
+
+ if (oxi) {
+ html=html+wxT("")+_("Oximeter Information")+wxT(" |
\n");
+ html=html+wxT("")+_("Pulse Avg")+wxT(" | ")+wxString::Format(wxT("%.1fcmH2O"),d->summary_avg(OXI_PulseAverage))+wxT(" |
\n");
+ html=html+wxT("")+_("Pulse Min")+wxT(" | ")+wxString::Format(wxT("%.1fcmH2O"),d->summary_min(OXI_PulseMin))+wxT(" |
\n");
+ html=html+wxT("")+_("Pulse Max")+wxT(" | ")+wxString::Format(wxT("%.1fcmH2O"),d->summary_max(OXI_PulseMax))+wxT(" |
\n");
+ html=html+wxT("")+_("SpO2 Avg")+wxT(" | ")+wxString::Format(wxT("%.1fcmH2O"),d->summary_avg(OXI_SPO2Average))+wxT(" |
\n");
+ html=html+wxT("")+_("SpO2 Min")+wxT(" | ")+wxString::Format(wxT("%.1fcmH2O"),d->summary_min(OXI_SPO2Min))+wxT(" |
\n");
+ html=html+wxT("")+_("SpO2 Max")+wxT(" | ")+wxString::Format(wxT("%.1fcmH2O"),d->summary_max(OXI_SPO2Max))+wxT(" |
\n");
+ PULSE->Show(true);
+ SPO2->Show(true);
+ } else {
+ PULSE->Show(false);
+ SPO2->Show(false);
+ }
+ fgSizer->Layout();
+// fgSizer->Layout();
+ ScrolledWindow->FitInside();
html=html+wxT(" | |
\n");
@@ -906,18 +945,31 @@ void Daily::OnCalendarDay( wxCalendarEvent& event )
}
RefreshData();
}
-void Daily::UpdateGraphs(Day *day)
+void Daily::UpdateCPAPGraphs(Day *day)
{
//if (!day) return;
if (day) {
day->OpenEvents();
day->OpenWaveforms();
}
- for (list::iterator g=Data.begin();g!=Data.end();g++) {
+ for (list::iterator g=CPAPData.begin();g!=CPAPData.end();g++) {
(*g)->Update(day);
}
};
+void Daily::UpdateOXIGraphs(Day *day)
+{
+ //if (!day) return;
+ if (day) {
+ day->OpenEvents();
+ day->OpenWaveforms();
+ }
+ for (list::iterator g=OXIData.begin();g!=OXIData.end();g++) {
+ (*g)->Update(day);
+ }
+};
+
+
void Daily::OnCalendarMonth( wxCalendarEvent& event )
{
wxDateTime et=event.GetDate();
diff --git a/src/SleepyHeadMain.h b/src/SleepyHeadMain.h
index aca65c95..10b81b08 100644
--- a/src/SleepyHeadMain.h
+++ b/src/SleepyHeadMain.h
@@ -66,16 +66,20 @@ protected:
virtual void OnSelectSession( wxCommandEvent& event );
virtual void OnEventTreeSelection( wxTreeEvent& event );
- void AddData(gPointData *d) { Data.push_back(d); };
- void UpdateGraphs(Day *day);
+ void AddCPAPData(gPointData *d) { CPAPData.push_back(d); };
+ void AddOXIData(gPointData *d) { OXIData.push_back(d); };
+ void UpdateCPAPGraphs(Day *day);
+ void UpdateOXIGraphs(Day *day);
bool foobar_datehack;
gPointData *tap,*tap_eap,*tap_iap,*g_ahi,*frw,*prd,*leakdata,*pressure_iap,*pressure_eap;
+ gPointData *pulse,*spo2;
gPointData *flags[10];
- gGraphWindow *PRD,*FRW,*G_AHI,*TAP,*LEAK,*SF,*TAP_EAP,*TAP_IAP;
+ gGraphWindow *PRD,*FRW,*G_AHI,*TAP,*LEAK,*SF,*TAP_EAP,*TAP_IAP,*PULSE,*SPO2;
Profile *profile;
- list Data;
+ list OXIData;
+ list CPAPData;
wxHtmlWindow *HTMLInfo;
wxTreeCtrl *EventTree;
diff --git a/src/graphs/graph.cpp b/src/graphs/graph.cpp
index 17b223cb..4477587e 100644
--- a/src/graphs/graph.cpp
+++ b/src/graphs/graph.cpp
@@ -1602,8 +1602,8 @@ void FlowData::Reload(Day *day)
//graph->Refresh(false);
}
-PressureData::PressureData(MachineCode _code,int _field)
-:gPointData(1024),code(_code),field(_field)
+PressureData::PressureData(MachineCode _code,int _field,int _size)
+:gPointData(_size),code(_code),field(_field)
{
}
PressureData::~PressureData()
@@ -1616,6 +1616,7 @@ void PressureData::Reload(Day *day)
m_ready=false;
return;
}
+
min_x=day->first().GetMJD();
max_x=day->last().GetMJD();
assert(min_x
+#include
#include "cms50_loader.h"
#include "sleeplib/machine.h"
+extern wxProgressDialog *loader_progress;
+
CMS50Loader::CMS50Loader()
{
//ctor
@@ -25,8 +28,154 @@ bool CMS50Loader::Open(wxString & path,Profile *profile)
// Not sure whether to both supporting SpO2 files here, as the timestamps are utterly useless for overlay purposes.
// May just ignore the crap and support my CMS50 logger
+ // Contains three files
+ // Data Folder
+ // SpO2 Review.ini
+ // SpO2.ini
+
+ wxString tmp=path+wxFileName::GetPathSeparator()+wxT("Data");
+ if ((wxFileExists(path+wxFileName::GetPathSeparator()+wxT("SpO2 Review.ini")))
+ && (wxFileExists(path+wxFileName::GetPathSeparator()+wxT("SpO2.ini")))
+ && (wxDirExists(tmp))) {
+ // Their software
+
+ return OpenCMS50(tmp,profile);
+ } else {
+ // My Logger
+ }
+
return false;
}
+bool CMS50Loader::OpenCMS50(wxString & path, Profile *profile)
+{
+ wxDir dir;
+ if (!dir.Open(path)) return false;
+ list files;
+
+ wxString filename,pathname;
+
+ bool cont=dir.GetFirst(&filename);
+
+ while (cont) {
+ if (filename.EndsWith(wxT(".spoR"))) {
+ pathname=path+wxFileName::GetPathSeparator()+filename;
+ files.push_back(pathname);
+ }
+ cont=dir.GetNext(&filename);
+ }
+ int size=files.size();
+ if (size==0) return false;
+
+ Machine *mach=CreateMachine(profile);
+ int cnt=0;
+ for (list::iterator n=files.begin();n!=files.end();n++,++cnt) {
+ if (loader_progress) loader_progress->Update((float(cnt)/float(size)*100.0));
+ OpenSPORFile((*n),mach,profile);
+ }
+ mach->Save();
+ return true;
+}
+bool CMS50Loader::OpenSPORFile(wxString path,Machine *mach,Profile *profile)
+{
+ wxFFile f;
+ unsigned char tmp[256];
+ if (!f.Open(path,wxT("rb"))) return false;
+
+ wxString str=path.AfterLast(wxChar('_'));
+ wxString id=str.BeforeFirst(wxChar('.'));
+ wxDateTime dt;
+ dt.ParseFormat(id,wxT("%Y%m%d%H%M"));
+
+ SessionID sessid=dt.GetTicks(); // Import date becomes session id
+
+ if (mach->SessionExists(sessid))
+ return false; // Already imported
+
+ // Find everything after the last _
+ short data_starts;
+ short some_code;
+ int num_records;
+ short some_more_code;
+ int br;
+
+
+
+ f.Read(tmp,2);
+ data_starts=tmp[0] | (tmp[1] << 8);
+ f.Read(tmp,2);
+ some_code=tmp[0] | (tmp[1] << 8); // == 512
+ f.Read(tmp,2);
+ num_records=tmp[0] | (tmp[1] << 8);
+ num_records <<= 1;
+
+ f.Read(tmp,2);
+ some_more_code=tmp[0] | (tmp[1] << 8); // == 512
+
+ f.Read(tmp,16);
+
+ wxString datestr;
+ for (int i=0;i<16;i+=2) {
+ datestr=datestr+tmp[i];
+ }
+ wxDateTime date;
+ date.ParseFormat(datestr,wxT("%m/%d/%y"));
+
+
+ f.Seek(data_starts,wxFromStart);
+ buffer=new char [num_records*2];
+ br=f.Read(buffer,num_records);
+ if (br!=num_records) {
+ wxLogDebug(wxT("Short .spoR File: ")+path);
+ }
+ char last_pulse=buffer[0];
+ char last_spo2=buffer[1];
+ EventDataType data[2];
+ wxDateTime last_pulse_time=date;
+ wxDateTime last_spo2_time=date;
+ data[0]=last_pulse;
+ data[1]=last_spo2;
+
+ Session *sess=new Session(mach,sessid);
+ sess->set_first(date);
+ sess->AddEvent(new Event(date,OXI_Pulse,data,1));
+ sess->AddEvent(new Event(date,OXI_SPO2,&data[1],1));
+ //wxDateTime
+ wxDateTime tt=date;
+ for (int i=2;iAddEvent(new Event(tt,OXI_Pulse,data,1));
+ }
+ if (last_spo2!=buffer[i+1]) {
+ data[1]=buffer[i+1];
+ sess->AddEvent(new Event(tt,OXI_SPO2,&data[1],1));
+ }
+ last_pulse=buffer[i];
+ last_spo2=buffer[i+1];
+ tt+=wxTimeSpan::Seconds(1);
+ }
+ sess->AddEvent(new Event(tt,OXI_Pulse,data,1));
+ sess->AddEvent(new Event(tt,OXI_SPO2,&data[1],1));
+
+ sess->set_last(tt);
+ wxTimeSpan t=sess->last()-sess->first();
+
+ double hours=(t.GetSeconds().GetLo()/3600.0);
+ sess->set_hours(hours);
+
+ sess->summary[OXI_PulseAverage]=sess->weighted_avg_event_field(OXI_Pulse,0);
+ 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_SPO2Average]=sess->weighted_avg_event_field(OXI_SPO2,0);
+ sess->summary[OXI_SPO2Min]=sess->min_event_field(OXI_SPO2,0);
+ sess->summary[OXI_SPO2Max]=sess->max_event_field(OXI_SPO2,0);
+
+ mach->AddSession(sess,profile);
+ sess->SetChanged(true);
+ delete buffer;
+
+ return true;
+}
Machine *CMS50Loader::CreateMachine(Profile *profile)
{
if (!profile) { // shouldn't happen..
diff --git a/src/libs/sleeplib/loader_plugins/cms50_loader.h b/src/libs/sleeplib/loader_plugins/cms50_loader.h
index e8abf149..084be58e 100644
--- a/src/libs/sleeplib/loader_plugins/cms50_loader.h
+++ b/src/libs/sleeplib/loader_plugins/cms50_loader.h
@@ -22,7 +22,11 @@ class CMS50Loader : public MachineLoader
Machine *CreateMachine(Profile *profile);
protected:
+ bool OpenCMS50(wxString & path, Profile *profile);
+ bool OpenSPORFile(wxString path, Machine * machine,Profile *profile);
+
private:
+ char *buffer;
};
#endif // CMS50LOADER_H
diff --git a/src/libs/sleeplib/machine.cpp b/src/libs/sleeplib/machine.cpp
index d7592aff..deec3905 100644
--- a/src/libs/sleeplib/machine.cpp
+++ b/src/libs/sleeplib/machine.cpp
@@ -907,7 +907,7 @@ void Session::AddEvent(Event * e)
{
events[e->code()].push_back(e);
if (e->time()>s_last) s_last=e->time();
- // wxLogMessage(e->time().Format(wxT("%Y-%m-%d %H:%M:%S"))+wxString::Format(wxT(" %04i %02i "),e->code(),e->fields()));
+ // wxLogMessage(e->time().Format(wxT("%Y-%m-%d %H:%M:%S"))+wxString::Format(wxT(" %04i %02i "),e->code(),e->fields()));
}
void Session::AddWaveform(Waveform *w)
{
diff --git a/src/libs/sleeplib/machine.h b/src/libs/sleeplib/machine.h
index 98ced224..3f0a9e44 100644
--- a/src/libs/sleeplib/machine.h
+++ b/src/libs/sleeplib/machine.h
@@ -60,7 +60,7 @@ enum MachineCode//:wxInt16
PRS1_SystemLockStatus, PRS1_SystemResistanceStatus, PRS1_SystemResistanceSetting, PRS1_HoseDiameter, PRS1_AutoOff, PRS1_MaskAlert, PRS1_ShowAHI,
// Oximeter Codes
- OXI_Pulse=0x2000, OXI_SpO2, OXI_Plethy, OXI_Signal2, OXI_SignalGood,
+ OXI_Pulse=0x2000, OXI_SPO2, OXI_Plethy, OXI_Signal2, OXI_SignalGood, OXI_PulseAverage, OXI_PulseMin, OXI_PulseMax, OXI_SPO2Average, OXI_SPO2Min, OXI_SPO2Max,
ZEO_SleepStage=0x2800, ZEO_Waveform,