From 4027304aea85d9698b3d3571c8bb1a5d286241c4 Mon Sep 17 00:00:00 2001
From: Mark Watkins <jedimark@users.sourceforge.net>
Date: Mon, 2 Jan 2012 00:14:18 +1000
Subject: [PATCH] PRS1 Importer Fixes, BIPAP/VPAP stuff, Overview Pressure
 Chart fixes (a different issue to print line problem)

---
 Graphs/gGraphView.cpp                     |   2 +-
 Graphs/gSummaryChart.cpp                  | 123 ++++++--
 SleepLib/common.h                         |   2 +
 SleepLib/loader_plugins/prs1_loader.cpp   | 329 ++--------------------
 SleepLib/loader_plugins/prs1_loader.h     |   2 +-
 SleepLib/loader_plugins/resmed_loader.cpp |  37 +--
 SleepLib/loader_plugins/resmed_loader.h   |  12 +-
 SleepLib/machine.cpp                      |   5 -
 SleepLib/profiles.cpp                     |  25 +-
 docs/channels.xml                         |   6 +-
 mainwindow.cpp                            |  68 ++---
 overview.cpp                              |  39 +--
 12 files changed, 225 insertions(+), 425 deletions(-)

diff --git a/Graphs/gGraphView.cpp b/Graphs/gGraphView.cpp
index 6c112f1d..639cb148 100644
--- a/Graphs/gGraphView.cpp
+++ b/Graphs/gGraphView.cpp
@@ -2457,8 +2457,8 @@ bool gGraphView::renderGraphs()
     for (int i=0;i<m_graphs.size();i++) {
         m_graphs[i]->drawGLBuf();
     }
-    lines->draw();
     quads->draw();
+    lines->draw();
 //    lines->setSize(linesize);
 
     DrawTextQue();
diff --git a/Graphs/gSummaryChart.cpp b/Graphs/gSummaryChart.cpp
index 24a373a2..ca43cdec 100644
--- a/Graphs/gSummaryChart.cpp
+++ b/Graphs/gSummaryChart.cpp
@@ -52,15 +52,46 @@ void SummaryChart::SetDay(Day * nullday)
     m_maxx=0;
 
 
-
     int dn;
     EventDataType tmp,tmp2,total;
     ChannelID code;
+    if (m_label==STR_TR_Pressure) {
+        CPAPMode mode=(CPAPMode)(int)PROFILE.calcSettingsMax(CPAP_Mode,MT_CPAP,PROFILE.FirstDay(MT_CPAP),PROFILE.LastDay(MT_CPAP));
+        m_codes.clear();
+        m_colors.clear();
+        m_type.clear();
+        m_zeros.clear();
+        m_typeval.clear();
+
+        if (mode>=MODE_ASV) {
+            addSlice(CPAP_EPAP,QColor("green"),ST_SETMIN,true);
+
+            addSlice(CPAP_IPAPLo,QColor("light blue"),ST_SETMIN,true);
+            addSlice(CPAP_IPAPHi,QColor("blue"),ST_SETMAX,true);
+        } else if (mode>=MODE_BIPAP) {
+            addSlice(CPAP_EPAP,QColor("green"),ST_SETMIN,true);
+            addSlice(CPAP_EPAP,QColor("light green"),ST_PERC,true,0.95);
+
+            addSlice(CPAP_IPAP,QColor("light blue"),ST_PERC,true,0.95);
+            addSlice(CPAP_IPAP,QColor("blue"),ST_SETMAX,true);
+        } else if (mode>=MODE_APAP) {
+            addSlice(CPAP_PressureMin,QColor("orange"),ST_SETMIN,true);
+            addSlice(CPAP_Pressure,QColor("dark green"),ST_WAVG,true);
+            addSlice(CPAP_Pressure,QColor("grey"),ST_PERC,true,0.95);
+            addSlice(CPAP_PressureMax,QColor("red"),ST_SETMAX,true);
+        } else {
+            addSlice(CPAP_Pressure,QColor("dark green"),ST_SETWAVG,true);
+        }
+
+    }
+
 
     m_goodcodes.resize(m_codes.size());
     for (int i=0;i<m_codes.size();i++) {
         m_goodcodes[i]=false;
     }
+
+
     m_fday=0;
     qint64 tt,zt;
     m_empty=true;
@@ -138,6 +169,7 @@ void SummaryChart::SetDay(Day * nullday)
                 EventDataType typeval=m_typeval[j];
                 for (int i=0;i<d.value().size();i++) { // for each machine object for this day
                     day=d.value()[i];
+                    CPAPMode mode=(CPAPMode)(int)day->settings_max(CPAP_Mode);
                     if (day->machine_type()!=m_machinetype) continue;
                     //m_values[dn][j+1]=0;
 
@@ -147,6 +179,19 @@ void SummaryChart::SetDay(Day * nullday)
                             day->settingExists(code) ||
                             day->hasData(code,type);
 
+                    if (code==CPAP_Pressure) {
+                        if (mode==MODE_CPAP) {
+                            if (type==ST_PERC)
+                                hascode=false;
+                            else if (type==ST_WAVG) {
+                                //hascode=false;
+                                type=ST_SETWAVG;
+                            }
+
+                        } else {
+                            type=m_type[j];
+                        }
+                    }
                     if (hascode) {
                         m_days[dn]=day;
                         switch(m_type[j]) {
@@ -180,10 +225,6 @@ void SummaryChart::SetDay(Day * nullday)
                         m_goodcodes[j]=true;
                         fnd=true;
                         break;
-                    } else {
-                        if (code==CPAP_PressureMin) {
-                            int i=5;
-                        }
                     }
                 }
             }
@@ -196,10 +237,10 @@ void SummaryChart::SetDay(Day * nullday)
                     if (total>m_maxy) m_maxy=total;
                 }
                 //m_empty=false;
-           } else m_hours[dn]=0;
+           }// else m_hours[dn]=0;
         }
     }
-    if (m_graphtype!=GT_SESSIONS)
+   /* if (m_graphtype!=GT_SESSIONS)
     for (int j=0;j<m_codes.size();j++) { // for each code slice
         ChannelID code=m_codes[j];
         if (type==ST_HOURS || type==ST_SESSIONS || m_zeros[j]) continue;
@@ -223,7 +264,7 @@ void SummaryChart::SetDay(Day * nullday)
                 break;
            }
         }
-    }
+    } */
     m_empty=true;
     for (int i=0;i<m_goodcodes.size();i++) {
         if (m_goodcodes[i]) {
@@ -330,6 +371,9 @@ void SummaryChart::paint(gGraph & w,int left, int top, int width, int height)
     int zd=minx/86400000L;
     zd--;
     QHash<int,QHash<short,EventDataType> >::iterator d=m_values.find(zd);
+
+    QVector<bool> goodcodes;
+    goodcodes.resize(m_goodcodes.size());
 //    if (d==m_values.end()) {
 //        d=m_values.find(zd--);
  //   }
@@ -343,10 +387,12 @@ void SummaryChart::paint(gGraph & w,int left, int top, int width, int height)
         } else {
             totalvalues[i]=0;
         }
+        goodcodes[i]=false;
         if (!m_goodcodes[i]) continue;
        // lastvalues[i]=0;
         lastX[i]=px;
-        if (d!=m_values.end()) {
+        if (d!=m_values.end() && d.value().contains(i+1)) {
+
             tmp=d.value()[i+1];
             h=tmp*ymult;
         } else {
@@ -370,9 +416,14 @@ void SummaryChart::paint(gGraph & w,int left, int top, int width, int height)
         d=m_values.find(zd);
 
         qint64 extra=86400000;
-        if (Q<minx) continue;
+        if (Q<minx)
+            goto jumpnext;
+            //continue;
         if (d!=m_values.end()) {
             day=m_days[zd];
+            if (!m_hours.contains(zd))
+                goto jumpnext;
+                //continue;
             hours=m_hours[zd];
 
             int x1=px;
@@ -381,7 +432,9 @@ void SummaryChart::paint(gGraph & w,int left, int top, int width, int height)
 
             if (x1<left) x1=left;
             if (x2>left+width) x2=left+width;
-            if (x2<x1) continue;
+            if (x2<x1)
+                goto jumpnext;
+                //continue;
             ChannelID code;
 
             if (m_graphtype==GT_SESSIONS) {
@@ -419,6 +472,7 @@ void SummaryChart::paint(gGraph & w,int left, int top, int width, int height)
                 total_val+=hours;
                 total_days++;
             } else {
+                if (!d.value().contains(0)) goto jumpnext;
                 total=d.value()[0];
                 //if (total>0) {
                 if (day) {
@@ -428,11 +482,16 @@ void SummaryChart::paint(gGraph & w,int left, int top, int width, int height)
                 py=top+height;
 
                 //}
+                bool good;
                 for (QHash<short,EventDataType>::iterator g=d.value().begin();g!=d.value().end();g++) {
                     short j=g.key();
                     if (!j) continue;
                     j--;
-                    if (!m_goodcodes[j]) continue;
+                    good=m_goodcodes[j];
+                    if (!good)
+                        continue;
+
+                    goodcodes[j]=good;
 
                     tmp=g.value();
 
@@ -477,7 +536,12 @@ void SummaryChart::paint(gGraph & w,int left, int top, int width, int height)
                         col.setAlpha(128);
                         px2=px+barw;
                         py2=(top+height-2)-h;
-                        py2+=j;
+                        //py2+=j;
+
+                        // If more than 1 day between records, skip the vertical crud.
+                        if ((px2-lastX[j])>barw+1) {
+                            lastdaygood=false;
+                        }
                         if (lastdaygood) {
                             if (lastY[j]!=py2) // vertical line
                                 lines->add(lastX[j],lastY[j],px,py2,m_colors[j]);
@@ -487,7 +551,6 @@ void SummaryChart::paint(gGraph & w,int left, int top, int width, int height)
                         }
                         lastX[j]=px2;
                         lastY[j]=py2;
-
                         //}
                     }
                 }  // for(QHash<short
@@ -499,6 +562,7 @@ void SummaryChart::paint(gGraph & w,int left, int top, int width, int height)
                 incompliant++;
             lastdaygood=false;
         }
+jumpnext:
         px+=barw;
         daynum++;
         //lastQ=Q;
@@ -514,7 +578,8 @@ void SummaryChart::paint(gGraph & w,int left, int top, int width, int height)
 
     bool ishours=false;
     for (int j=0;j<m_codes.size();j++) {
-        if (!m_goodcodes[j]) continue;
+        if (!goodcodes[j]) continue;
+
         ChannelID code=m_codes[j];
         EventDataType tval=m_typeval[j];
         switch(m_type[j]) {
@@ -524,12 +589,15 @@ void SummaryChart::paint(gGraph & w,int left, int top, int width, int height)
                 case ST_PERC: b=QString("%1%").arg(tval*100.0,0,'f',0); break;
                 case ST_MIN:  b="Min"; break;
                 case ST_MAX:  b="Max"; break;
+                case ST_SETMIN:  b="Min"; break;
+                case ST_SETMAX:  b="Max"; break;
                 case ST_CPH:  b=""; break;
                 case ST_SPH:  b="%"; break;
                 case ST_HOURS: b=STR_UNIT_Hours; break;
                 case ST_SESSIONS: b="Sessions"; break;
 
                 default:
+                    b="";
                     break;
         }
         a=schema::channel[code].label();
@@ -648,6 +716,9 @@ bool SummaryChart::mouseMoveEvent(QMouseEvent *event)
         graph->Trigger(2000);
 
         QHash<int,QHash<short,EventDataType> >::iterator d=m_values.find(hl_day);
+
+        QHash<short,EventDataType> & valhash=d.value();
+
         x+=gYAxis::Margin+gGraphView::titleWidth; //graph->m_marginleft+
         int y=event->y()+rtop-15;
         //QDateTime dt1=QDateTime::fromTime_t(hl_day*86400).toLocalTime();
@@ -669,7 +740,7 @@ bool SummaryChart::mouseMoveEvent(QMouseEvent *event)
             if (m_graphtype==GT_SESSIONS) {
                 if (m_type[0]==ST_HOURS) {
 
-                    int t=day->hours()*3600.0;
+                    int t=m_hours[zd]*3600.0;
                     int h=t/3600;
                     int m=(t / 60) % 60;
                     //int s=t % 60;
@@ -705,7 +776,10 @@ bool SummaryChart::mouseMoveEvent(QMouseEvent *event)
             } else {
                 QString a;
                 for (int i=0;i<m_type.size();i++) {
-                    if (!m_goodcodes[i]) continue;
+                    if (!m_goodcodes[i])
+                        continue;
+                    if (!valhash.contains(i+1))
+                        continue;
                     EventDataType tval=m_typeval[i];
                     switch(m_type[i]) {
                             case ST_WAVG: a="W-avg"; break;
@@ -718,7 +792,10 @@ bool SummaryChart::mouseMoveEvent(QMouseEvent *event)
                             case ST_SPH:  a="%"; break;
                             case ST_HOURS: a=STR_UNIT_Hours; break;
                             case ST_SESSIONS: a="Sessions"; break;
+                            case ST_SETMIN:  a="Min"; break;
+                            case ST_SETMAX:  a="Max"; break;
                             default:
+                                a="";
                                 break;
                     }
                     if (m_type[i]==ST_SESSIONS) {
@@ -727,10 +804,16 @@ bool SummaryChart::mouseMoveEvent(QMouseEvent *event)
                     } else {
                         //if (day && (day->channelExists(m_codes[i]) || day->settingExists(m_codes[i]))) {
                             schema::Channel & chan=schema::channel[m_codes[i]];
+                            EventDataType v;
+                            if (valhash.contains(i+1))
+                                v=valhash[i+1];
+                            else v=0;
+
                             if (m_codes[i]==Journal_Weight) {
-                                val=weightString(d.value()[i+1],PROFILE.general->unitSystem());
-                            } else
-                                val=QString::number(d.value()[i+1],'f',2);
+                                val=weightString(v,PROFILE.general->unitSystem());
+                            } else {
+                                val=QString::number(v,'f',2);
+                            }
                             z+="\r\n"+chan.label()+" "+a+"="+val;
                         //}
                     }
diff --git a/SleepLib/common.h b/SleepLib/common.h
index a3934c12..de261d39 100644
--- a/SleepLib/common.h
+++ b/SleepLib/common.h
@@ -40,6 +40,7 @@ const QString STR_PROP_SubModel="SubModel";
 const QString STR_PROP_Serial="Serial";
 const QString STR_PROP_DataVersion="DataVersion";
 const QString STR_PROP_Path="Path";
+const QString STR_PROP_LastImported="LastImported";
 
 const QString STR_MACH_ResMed="ResMed";
 const QString STR_MACH_PRS1="PRS1";
@@ -54,6 +55,7 @@ const QString STR_TR_PulseRate=QObject::tr("Pulse Rate");
 const QString STR_TR_SpO2=QObject::tr("SpO2");
 const QString STR_TR_Plethy=QObject::tr("Plethy");
 const QString STR_TR_FlowRate=QObject::tr("Flow Rate");
+const QString STR_TR_Pressure=QObject::tr("Pressure");
 
 const QString STR_TR_Daily=QObject::tr("Daily");
 const QString STR_TR_Overview=QObject::tr("Overview");
diff --git a/SleepLib/loader_plugins/prs1_loader.cpp b/SleepLib/loader_plugins/prs1_loader.cpp
index 7c7fa535..216bdb0a 100644
--- a/SleepLib/loader_plugins/prs1_loader.cpp
+++ b/SleepLib/loader_plugins/prs1_loader.cpp
@@ -384,22 +384,18 @@ int PRS1Loader::OpenMachine(Machine *m,QString path,Profile *profile)
                 sess->settings[CPAP_PresReliefType]=PR_BIFLEX;
             }
 
-            sess->setAvg(CPAP_Pressure,(sess->avg(CPAP_EPAP)+sess->avg(CPAP_IPAP))/2.0);
-            sess->setWavg(CPAP_Pressure,(sess->wavg(CPAP_EPAP)+sess->wavg(CPAP_IPAP))/2.0);
-            sess->setMin(CPAP_Pressure,sess->Min(CPAP_EPAP));
-            sess->setMax(CPAP_Pressure,sess->Max(CPAP_IPAP));
-            sess->set90p(CPAP_Pressure,(sess->p90(CPAP_IPAP)+sess->p90(CPAP_EPAP))/2.0);
-            //sess->p90(CPAP_EPAP);
-            //sess->p90(CPAP_IPAP);
-        } else {
-            //sess->avg(CPAP_Pressure);
-            //sess->wavg(CPAP_Pressure);
-            //sess->p90(CPAP_Pressure);
-            //sess->Min(CPAP_Pressure);
-            //sess->Max(CPAP_Pressure);
-            //sess->cph(CPAP_Pressure);
+            EventDataType min=sess->settings[CPAP_PressureMin].toDouble();
+            EventDataType max=sess->settings[CPAP_PressureMax].toDouble();
+            sess->settings[CPAP_EPAP]=min;
+            sess->settings[CPAP_IPAP]=max;
+            sess->settings[CPAP_PS]=max-min;
+            sess->settings.erase(sess->settings.find(CPAP_PressureMin));
+            sess->settings.erase(sess->settings.find(CPAP_PressureMax));
 
-            if (!sess->settings.contains(CPAP_PressureMin)) {
+
+        } else {
+
+            if (!sess->settings.contains(CPAP_Pressure) && !sess->settings.contains(CPAP_PressureMin)) {
                 sess->settings[CPAP_BrokenSummary]=true;
                 //sess->set_last(sess->first());
                 if (sess->Min(CPAP_Pressure)==sess->Max(CPAP_Pressure)) {
@@ -411,7 +407,7 @@ int PRS1Loader::OpenMachine(Machine *m,QString path,Profile *profile)
             }
 
         }
-        if (sess->settings[CPAP_Mode]==MODE_CPAP) {
+        if (sess->settings[CPAP_Mode].toInt()==(int)MODE_CPAP) {
             //sess->settings[CPAP_PressureMax]=sess->settings[CPAP_PressureMin];
         }
 
@@ -424,7 +420,7 @@ int PRS1Loader::OpenMachine(Machine *m,QString path,Profile *profile)
     }
 
     m->properties[STR_PROP_DataVersion]=QString().sprintf("%i",prs1_data_version);
-    m->properties["LastImported"]=QDateTime::currentDateTime().toString(Qt::ISODate);
+    m->properties[STR_PROP_LastImported]=QDateTime::currentDateTime().toString(Qt::ISODate);
     m->Save(); // Save any new sessions to disk in our format
     if (qprogress) qprogress->setValue(100);
 
@@ -466,13 +462,13 @@ bool PRS1Loader::ParseSummary(Machine *mach, qint32 sequence, quint32 timestamp,
     session->settings[CPAP_RampTime]=(int)data[offset+0x06]; // Minutes. Convert to seconds/hours here?
     session->settings[CPAP_RampPressure]=(EventDataType)data[offset+0x07]/10.0;
 
-    if (max>0) { // Ignoring bipap until I see some more data.
+    if (max>0) { // Ignoring bipap until we see some more data during import
         session->settings[CPAP_Mode]=(int)MODE_APAP;
-        session->settings[CPAP_PressureMin]=(double)min;
-        session->settings[CPAP_PressureMax]=(double)max;
+        session->settings[CPAP_PressureMin]=(EventDataType)min;
+        session->settings[CPAP_PressureMax]=(EventDataType)max;
     } else {
         session->settings[CPAP_Mode]=(int)MODE_CPAP;
-        session->settings[CPAP_Pressure]=(double)min;
+        session->settings[CPAP_Pressure]=(EventDataType)min;
     }
 
     // This is incorrect..
@@ -486,7 +482,7 @@ bool PRS1Loader::ParseSummary(Machine *mach, qint32 sequence, quint32 timestamp,
     session->settings[CPAP_PresReliefMode]=(int)PM_FullTime; // only has one mode
 
 
-    session->settings[PRS1_FlexSet]=(int)(data[offset+0x08] & 3);
+    session->settings[CPAP_PresReliefSet]=(int)(data[offset+0x08] & 3);
     session->settings[PRS1_HumidSetting]=(int)data[offset+0x09]&0x0f;
     session->settings[PRS1_HumidStatus]=(data[offset+0x09]&0x80)==0x80;
     session->settings[PRS1_SysLock]=(data[offset+0x0a]&0x80)==0x80;
@@ -508,8 +504,8 @@ bool PRS1Loader::ParseSummary(Machine *mach, qint32 sequence, quint32 timestamp,
         if (max>0) {
             session->setMin(CPAP_Pressure,min);
             session->setMax(CPAP_Pressure,max);
+            session->setWavg(CPAP_Pressure,min);
         }
-        session->setWavg(CPAP_Pressure,min);
     } else {
         // 0X28 & 0X29 is length on r5
 
@@ -530,12 +526,12 @@ bool PRS1Loader::ParseSummary(Machine *mach, qint32 sequence, quint32 timestamp,
         p90p=float(data[offset+0x18])/10.0;
         avgp=float(data[offset+0x19])/10.0;
 
-        if (minp>0) session->setMin(CPAP_Pressure,minp); else session->setMin(CPAP_Pressure,min);
-        if (maxp>0) session->setMax(CPAP_Pressure,maxp); else session->setMax(CPAP_Pressure,min);
-        if (avgp>0) session->setWavg(CPAP_Pressure,avgp); else session->setWavg(CPAP_Pressure,min);
-        if (p90p>0) session->set90p(CPAP_Pressure,p90p); else session->set90p(CPAP_Pressure,min);
-
-
+        if (minp>0) session->setMin(CPAP_Pressure,minp);
+        if (maxp>0) session->setMax(CPAP_Pressure,maxp);
+        if (avgp>0) session->setWavg(CPAP_Pressure,avgp);
+        if (p90p>0) {
+            session->set90p(CPAP_Pressure,p90p);
+        }
 
         int oc, cc, hc, rc, fc;
         session->setCount(CPAP_Obstructive,oc=(int)data[offset+0x1C] | (data[offset+0x1D] << 8));
@@ -1155,281 +1151,6 @@ bool PRS1Loader::OpenFile(Machine *mach, QString filename)
 }
 
 
-
-
-/*// v2 event parser.
-bool PRS1Loader::Parse002(Session *session,unsigned char *buffer,int size,qint64 timestamp,long fpos)
-{
-//    ChannelID Codes[]={
-//        PRS1_Unknown00, PRS1_Unknown01, CPAP_Pressure, CPAP_EPAP, CPAP_PressurePulse, CPAP_RERA, CPAP_Obstructive, CPAP_ClearAirway,
-//        PRS1_Unknown08, PRS1_Unknown09, CPAP_Hypopnea, PRS1_Unknown0B, CPAP_FlowLimit, CPAP_VSnore, PRS1_Unknown0E, CPAP_CSR, PRS1_Unknown10,
-//        CPAP_LeakTotal, PRS1_Unknown12
-//    };
-//    int ncodes=sizeof(Codes)/sizeof(ChannelID);
-
-    //QHash<ChannelID,EventList *> Code;
-    EventList * Code[0x20]={NULL};
-
-    EventDataType data[10];
-
-    session->updateFirst(timestamp);
-    //qint64 start=timestamp;
-    qint64 t=timestamp;
-    qint64 tt;
-    int pos=0;
-    while (pos<size) {
-        unsigned char code=buffer[pos++];
-        if (code>0x12) {
-        }
-        delta=0;
-        if (code!=0x12) {
-            delta=buffer[pos+1] << 8 | buffer[pos];
-            pos+=2;
-            t+=qint64(delta)*1000L;
-            tt=t;
-        }
-
-    session->updateLast(t);
-
-    return true;
-}
-
-bool PRS1Loader::Parse002ASV(Session *session,unsigned char *buffer,int size,qint64 timestamp,long fpos)
-{
-}
-
-bool PRS1Loader::OpenSummary(Session *session,QString filename) // Read .001/.000 file
-{
-    int size,seconds,br,htype,version,sequence;
-    qint64 timestamp;
-    unsigned char header[24];
-    unsigned char ext,sum;
-
-    //qDebug() << "Opening PRS1 Summary " << filename;
-    QFile f(filename);
-
-    if (!f.open(QIODevice::ReadOnly))
-          return false;
-
-    if (!f.exists())
-        return false;
-
-    int hl=16;
-
-    br=f.read((char *)header,hl);
-
-    if (header[0]!=PRS1_MAGIC_NUMBER)
-        return false;
-
-    sequence=size=timestamp=seconds=ext=0;
-    sequence=(header[10] << 24) | (header[9] << 16) | (header[8] << 8) | header[7];
-    timestamp=(header[14] << 24) | (header[13] << 16) | (header[12] << 8) | header[11];
-    size=(header[2] << 8) | header[1];
-    ext=header[6]; // 0 = compliance only, 1 = has data
-
-    htype=header[3]; // 00 = normal // 01=waveform // could be a bool?
-    version=header[4];
-    sequence=sequence;
-    version=version; // don't need it here?
-
-    htype=htype; // shut the warning up.. this is useless.
-
-    if (ext!=PRS1_SUMMARY_FILE)
-        return false;
-
-    size-=(hl+2);
-
-    // Calculate header checksum and compare to verify header
-    sum=0;
-    for (int i=0; i<hl-1; i++) sum+=header[i];
-    if (sum!=header[hl-1])
-        return false;
-
-    if (size<=19) {
-      //  qDebug() << "Ignoring short session file " << filename;
-        return false;
-    }
-
-    qint64 date=timestamp*1000;
-
-
-    //memset(m_buffer,0,size);
-    unsigned char * buffer=m_buffer;
-    br=f.read((char *)buffer,size);
-    if (br<size) {
-        return false;
-    }
-
-    unsigned char crcbytes[2];
-    if (f.read((char *)crcbytes,2)!=2) {
-        qDebug() << "No ending CRC bytes in" << filename;
-    }
-    quint16 crc=(crcbytes[1] << 8) | crcbytes[0];
-    quint16 c16=CRC16(buffer,size);
-    if (crc!=c16) {
-        qDebug() << "Summary CRC check failed, wanted" << crc << "got" << c16;
-    }
-
-    if ((ext==1) && size<0x30)
-        return true;
-
-    session->set_first(date);
-
-    double max;
-    session->settings[CPAP_PressureMin]=(EventDataType)buffer[0x03]/10.0;
-    session->settings[CPAP_PressureMax]=max=(EventDataType)buffer[0x04]/10.0;
-    int offset=0;
-    if (buffer[0x05]!=0) { // This is a time value for ASV stuff
-        // non zero adds extra fields..
-        offset=4;
-    }
-
-    session->settings[CPAP_RampTime]=(int)buffer[offset+0x06]; // Minutes. Convert to seconds/hours here?
-    session->settings[CPAP_RampPressure]=(EventDataType)buffer[offset+0x07]/10.0;
-
-    if (max>0) { // Ignoring bipap until I see some more data.
-        session->settings[CPAP_Mode]=(int)MODE_APAP;
-    } else session->settings[CPAP_Mode]=(int)MODE_CPAP;
-
-    // This is incorrect..
-    if (buffer[offset+0x08] & 0x80) { // Flex Setting
-        if (buffer[offset+0x08] & 0x08) {
-            if (max>0) session->settings[PRS1_FlexMode]=(int)PR_AFLEX;
-            else session->settings[PRS1_FlexMode]=(int)PR_CFLEXPLUS;
-        } else session->settings[PRS1_FlexMode]=(int)PR_CFLEX;
-    } else session->settings[PRS1_FlexMode]=(int)PR_NONE;
-
-    session->settings["FlexSet"]=(int)buffer[offset+0x08] & 3;
-    session->settings["HumidSet"]=(int)buffer[offset+0x09]&0x0f;
-    session->settings["HumidStat"]=(buffer[offset+0x09]&0x80)==0x80;
-    session->settings["SysLock"]=(buffer[offset+0x0a]&0x80)==0x80;
-    session->settings["SysOneResistStat"]=(buffer[offset+0x0a]&0x40)==0x40;
-    session->settings["SysOneResistSet"]=(int)buffer[offset+0x0a]&7;
-    session->settings["HoseDiam"]=((buffer[offset+0x0a]&0x08)?"15mm":"22mm");
-    session->settings["AutoOff"]=(buffer[offset+0x0c]&0x10)==0x10;
-    session->settings["MaskAlert"]=(buffer[offset+0x0c]&0x08)==0x08;
-    session->settings["ShowAHI"]=(buffer[offset+0x0c]&0x04)==0x04;
-
-    unsigned duration=buffer[offset+0x14] | (buffer[0x15] << 8);
-    //session->settings[CPAP_Duration]=(int)duration;
-    //qDebug() << "ID: " << session->session() << " " << duration;
-    //float hours=float(duration)/3600.0;
-    //session->set_hours(hours);
-    if (!duration)
-        return false;
-
-    session->set_last(date+qint64(duration)*1000L);
-    //session->settings[PRS1_PressureMinAchieved]=buffer[offset+0x16]/10.0;
-    //session->settings[PRS1_PressureMaxAchieved]=buffer[offset+0x17]/10.0;
-    //session->settings[PRS1_PressureAvg]=buffer[offset+0x18]/10.0;
-    //session->settings[PRS1_Pressure90]=buffer[offset+0x19]/10.0;
-
-    if (max==0) {
-      //  session->settings[PRS1_PressureAvg]=session->settings[PRS1_PressureMin];
-    }
-
-
-
-
-//   if (size==0x4d) {
-
-//        session->settings[CPAP_Obstructive]=(int)buffer[offset+0x1C] | (buffer[offset+0x1D] << 8);
-//        session->settings[CPAP_ClearAirway]=(int)buffer[offset+0x20] | (buffer[offset+0x21] << 8);
-//        session->settings[CPAP_Hypopnea]=(int)buffer[offset+0x2A] | (buffer[offset+0x2B] << 8);
-//        session->settings[CPAP_RERA]=(int)buffer[offset+0x2E] | (buffer[offset+0x2F] << 8);
-//        session->settings[CPAP_FlowLimit]=(int)buffer[offset+0x30] | (buffer[offset+0x31] << 8);
-//    }
-    return true;
-}
-
-bool PRS1Loader::OpenEvents(Session *session,QString filename)
-{
-    int size,sequence,seconds,br,version;
-    qint64 timestamp;
-    unsigned char header[24]; // use m_buffer?
-    unsigned char ext,htype;
-
-    QFile f(filename);
-    if (!f.open(QIODevice::ReadOnly))
-        return false;
-
-    int hl=16;
-    int chunk=0;
-
-    // Who'd of thought this chunked.. it does on certain ASV machines..
-
-    long pos=0;
-    do {
-        br=f.read((char *)header,hl);
-
-        if (header[0]!=PRS1_MAGIC_NUMBER) {
-            if (chunk==0)
-                return false;
-            break;
-        }
-        sequence=size=timestamp=seconds=ext=0;
-        sequence=(header[10] << 24) | (header[9] << 16) | (header[8] << 8) | header[7];
-        timestamp=(header[14] << 24) | (header[13] << 16) | (header[12] << 8) | header[11];
-        size=(header[2] << 8) | header[1];
-        ext=header[6];
-        htype=header[3]; // 00 = normal // 01=waveform // could be a bool?
-        version=header[4];// == 5
-
-        htype=htype;
-        sequence=sequence;
-        if (ext!=PRS1_EVENT_FILE) { // 2 == Event file
-            if (chunk==0)
-                return false;
-            break; // just end and take what we got..
-        }
-
-        //size|=(header[3]<<16) | (header[4]<<24); // the jury is still out on the 32bitness of one. doesn't matter here anyway.
-
-        size-=(hl+2);
-
-        unsigned char sum=0;
-        for (int i=0; i<hl-1; i++) sum+=header[i];
-        if (sum!=header[hl-1]) {
-            if (chunk==0)
-                return false;
-            break;
-        }
-        pos+=hl;
-
-        unsigned char *buffer=(unsigned char *)m_buffer;
-        br=f.read((char *)buffer,size);
-        if (br<size) {
-            if (chunk==0)
-                return false;
-            break;
-        }
-        unsigned char crcbytes[2];
-        if (f.read((char *)crcbytes,2)!=2) {
-            qDebug() << "No ending CRC bytes in" << filename;
-        }
-        quint16 crc=(crcbytes[1] << 8) | crcbytes[0];
-        quint16 c16=CRC16(buffer,size);
-        if (crc!=c16) {
-            qDebug() << "CRC check failed, wanted" << crc << "got" << c16;
-        }
-
-
-        if (version==0) {
-            if (!Parse002(session,buffer,size,timestamp*1000L,pos)) {
-                qDebug() << "Couldn't Parse chunk" << chunk << "of PRS1 Event File " << filename;
-            }
-        } else if (version==5) {
-            if (!Parse002ASV(session,buffer,size,timestamp*1000L,pos)) {
-                qDebug() << "Couldn't Parse chunk" << chunk << "PRS1 (ASV) Event File " << filename;
-            }
-        }
-        pos+=size+2;
-        chunk++;
-    } while(1);
-    return true;
-} */
-
-
 bool PRS1Loader::OpenWaveforms(SessionID sid, QString filename)
 {
     Session * session=new_sessions[sid];
diff --git a/SleepLib/loader_plugins/prs1_loader.h b/SleepLib/loader_plugins/prs1_loader.h
index 7d4b4926..e3989ea8 100644
--- a/SleepLib/loader_plugins/prs1_loader.h
+++ b/SleepLib/loader_plugins/prs1_loader.h
@@ -21,7 +21,7 @@ License: GPL
 //********************************************************************************************
 // Please INCREMENT the following value when making changes to this loaders implementation.
 //
-const int prs1_data_version=9;
+const int prs1_data_version=10;
 //
 //********************************************************************************************
 
diff --git a/SleepLib/loader_plugins/resmed_loader.cpp b/SleepLib/loader_plugins/resmed_loader.cpp
index 3ae10ab5..35beba74 100644
--- a/SleepLib/loader_plugins/resmed_loader.cpp
+++ b/SleepLib/loader_plugins/resmed_loader.cpp
@@ -633,6 +633,7 @@ int ResmedLoader::Open(QString & path,Profile *profile)
                     EventDataType tmp,epap=0,ipap=0;
                     if (stredf.lookup.contains("EPAP")) {
                         sig=stredf.lookup["EPAP"];
+                        //div=50; //1.0/sig->gain;
                         epap=sig->data[dn]*sig->gain;
                         sess->settings[CPAP_EPAP]=epap;
                         sess->setMin(CPAP_EPAP,epap);
@@ -704,7 +705,7 @@ int ResmedLoader::Open(QString & path,Profile *profile)
                 valmed=sig->data[dn];
                 sess->setMedian(CPAP_Leak,valmed*sig->gain*60.0);
                 sess->m_gain[CPAP_Leak]=sig->gain*60.0;
-                sess->m_valuesummary[CPAP_Leak][valmed]=50;
+                sess->m_valuesummary[CPAP_Leak][valmed]=51;
             }
             if (stredf.lookup.contains("Leak 95")) {
                 sig=stredf.lookup["Leak 95"];
@@ -716,7 +717,7 @@ int ResmedLoader::Open(QString & path,Profile *profile)
                 sig=stredf.lookup["Leak Max"];
                 valmax=sig->data[dn];
                 sess->setMax(CPAP_Leak,valmax*sig->gain*60.0);
-                sess->m_valuesummary[CPAP_Leak][valmax]=5;
+                sess->m_valuesummary[CPAP_Leak][valmax]=4;
             }
 
             if (stredf.lookup.contains("Min Vent Med")) {
@@ -724,7 +725,7 @@ int ResmedLoader::Open(QString & path,Profile *profile)
                 valmed=sig->data[dn];
                 sess->setMedian(CPAP_MinuteVent,valmed*sig->gain);
                 sess->m_gain[CPAP_MinuteVent]=sig->gain;
-                sess->m_valuesummary[CPAP_MinuteVent][valmed]=50;
+                sess->m_valuesummary[CPAP_MinuteVent][valmed]=51;
             }
             if (stredf.lookup.contains("Min Vent 95")) {
                 sig=stredf.lookup["Min Vent 95"];
@@ -736,14 +737,14 @@ int ResmedLoader::Open(QString & path,Profile *profile)
                 sig=stredf.lookup["Min Vent Max"];
                 valmax=sig->data[dn];
                 sess->setMax(CPAP_MinuteVent,valmax*sig->gain);
-                sess->m_valuesummary[CPAP_MinuteVent][valmax]=5;
+                sess->m_valuesummary[CPAP_MinuteVent][valmax]=4;
             }
             if (stredf.lookup.contains("RR Med")) {
                 sig=stredf.lookup["RR Med"];
                 valmed=sig->data[dn];
                 sess->setMedian(CPAP_RespRate,valmed*sig->gain);
                 sess->m_gain[CPAP_RespRate]=sig->gain;
-                sess->m_valuesummary[CPAP_RespRate][valmed]=50;
+                sess->m_valuesummary[CPAP_RespRate][valmed]=51;
             }
             if (stredf.lookup.contains("RR 95")) {
                 sig=stredf.lookup["RR 95"];
@@ -755,7 +756,7 @@ int ResmedLoader::Open(QString & path,Profile *profile)
                 sig=stredf.lookup["RR Max"];
                 valmax=sig->data[dn];
                 sess->setMax(CPAP_RespRate,valmax*sig->gain);
-                sess->m_valuesummary[CPAP_RespRate][valmax]=5;
+                sess->m_valuesummary[CPAP_RespRate][valmax]=4;
             }
 
             if (stredf.lookup.contains("Tid Vol Med")) {
@@ -763,7 +764,7 @@ int ResmedLoader::Open(QString & path,Profile *profile)
                 valmed=sig->data[dn];
                 sess->setMedian(CPAP_TidalVolume,valmed*sig->gain);
                 sess->m_gain[CPAP_TidalVolume]=sig->gain;
-                sess->m_valuesummary[CPAP_TidalVolume][valmed]=50;
+                sess->m_valuesummary[CPAP_TidalVolume][valmed]=51;
             }
             if (stredf.lookup.contains("Tid Vol 95")) {
                 sig=stredf.lookup["Tid Vol 95"];
@@ -775,7 +776,7 @@ int ResmedLoader::Open(QString & path,Profile *profile)
                 sig=stredf.lookup["Tid Vol Max"];
                 valmax=sig->data[dn];
                 sess->setMax(CPAP_TidalVolume,valmax*sig->gain);
-                sess->m_valuesummary[CPAP_TidalVolume][valmax]=5;
+                sess->m_valuesummary[CPAP_TidalVolume][valmax]=4;
             }
 
             if (stredf.lookup.contains("Targ Vent Med")) {
@@ -783,7 +784,7 @@ int ResmedLoader::Open(QString & path,Profile *profile)
                 valmed=sig->data[dn];
                 sess->setMedian(CPAP_TgMV,valmed*sig->gain);
                 sess->m_gain[CPAP_TgMV]=sig->gain;
-                sess->m_valuesummary[CPAP_TgMV][valmed]=50;
+                sess->m_valuesummary[CPAP_TgMV][valmed]=51;
             }
             if (stredf.lookup.contains("Targ Vent 95")) {
                 sig=stredf.lookup["Targ Vent 95"];
@@ -795,7 +796,7 @@ int ResmedLoader::Open(QString & path,Profile *profile)
                 sig=stredf.lookup["Targ Vent Max"];
                 valmax=sig->data[dn];
                 sess->setMax(CPAP_TgMV,valmax*sig->gain);
-                sess->m_valuesummary[CPAP_TgMV][valmax]=5;
+                sess->m_valuesummary[CPAP_TgMV][valmax]=4;
             }
 
 
@@ -804,7 +805,7 @@ int ResmedLoader::Open(QString & path,Profile *profile)
                 valmed=sig->data[dn];
                 sess->setMedian(CPAP_IE,valmed*sig->gain);
                 sess->m_gain[CPAP_IE]=sig->gain;
-                sess->m_valuesummary[CPAP_IE][valmed]=50;
+                sess->m_valuesummary[CPAP_IE][valmed]=51;
             }
             if (stredf.lookup.contains("I:E 95")) {
                 sig=stredf.lookup["I:E 95"];
@@ -816,7 +817,7 @@ int ResmedLoader::Open(QString & path,Profile *profile)
                 sig=stredf.lookup["I:E Max"];
                 valmax=sig->data[dn];
                 sess->setMax(CPAP_IE,valmax*sig->gain);
-                sess->m_valuesummary[CPAP_IE][valmax]=5;
+                sess->m_valuesummary[CPAP_IE][valmax]=4;
             }
 
 
@@ -826,7 +827,7 @@ int ResmedLoader::Open(QString & path,Profile *profile)
                 valmed=sig->data[dn];
                 sess->setMedian(CPAP_Pressure,valmed*sig->gain);
                 sess->m_gain[CPAP_Pressure]=sig->gain;
-                sess->m_valuesummary[CPAP_Pressure][valmed]=50;
+                sess->m_valuesummary[CPAP_Pressure][valmed]=51;
             }
             if (stredf.lookup.contains("Mask Pres 95")) {
                 sig=stredf.lookup["Mask Pres 95"];
@@ -838,7 +839,7 @@ int ResmedLoader::Open(QString & path,Profile *profile)
                 sig=stredf.lookup["Mask Pres Max"];
                 valmax=sig->data[dn];
                 sess->setMax(CPAP_Pressure,valmax*sig->gain);
-                sess->m_valuesummary[CPAP_Pressure][valmax]=5;
+                sess->m_valuesummary[CPAP_Pressure][valmax]=4;
             }
 
             if (stredf.lookup.contains("Insp Pres Med")) {
@@ -846,7 +847,7 @@ int ResmedLoader::Open(QString & path,Profile *profile)
                 valmed=sig->data[dn];
                 sess->setMedian(CPAP_IPAP,valmed*sig->gain);
                 sess->m_gain[CPAP_IPAP]=sig->gain;
-                sess->m_valuesummary[CPAP_IPAP][valmed]=50;
+                sess->m_valuesummary[CPAP_IPAP][valmed]=51;
             }
             if (stredf.lookup.contains("Insp Pres 95")) {
                 sig=stredf.lookup["Insp Pres 95"];
@@ -858,14 +859,14 @@ int ResmedLoader::Open(QString & path,Profile *profile)
                 sig=stredf.lookup["Insp Pres Max"];
                 valmax=sig->data[dn];
                 sess->setMax(CPAP_IPAP,valmax*sig->gain);
-                sess->m_valuesummary[CPAP_IPAP][valmax]=5;
+                sess->m_valuesummary[CPAP_IPAP][valmax]=4;
             }
             if (stredf.lookup.contains("Exp Pres Med")) {
                 sig=stredf.lookup["Exp Pres Med"];
                 valmed=sig->data[dn];
                 sess->setMedian(CPAP_EPAP,valmed*sig->gain);
                 sess->m_gain[CPAP_EPAP]=sig->gain;
-                sess->m_valuesummary[CPAP_EPAP][valmed]=50;
+                sess->m_valuesummary[CPAP_EPAP][valmed]=51;
             }
             if (stredf.lookup.contains("Exp Pres 95")) {
                 sig=stredf.lookup["Exp Pres 95"];
@@ -877,7 +878,7 @@ int ResmedLoader::Open(QString & path,Profile *profile)
                 sig=stredf.lookup["Exp Pres Max"];
                 valmax=sig->data[dn];
                 sess->setMax(CPAP_EPAP,valmax*sig->gain);
-                sess->m_valuesummary[CPAP_EPAP][valmax]=5;
+                sess->m_valuesummary[CPAP_EPAP][valmax]=4;
             }
 
             if (stredf.lookup.contains("Mask Dur")) {
diff --git a/SleepLib/loader_plugins/resmed_loader.h b/SleepLib/loader_plugins/resmed_loader.h
index c52f1058..6093da6e 100644
--- a/SleepLib/loader_plugins/resmed_loader.h
+++ b/SleepLib/loader_plugins/resmed_loader.h
@@ -64,22 +64,22 @@ public:
     QString physical_dimension;
 
     //! \brief The minimum limits of the ungained data
-    double  physical_minimum;
+    EventDataType physical_minimum;
 
     //! \brief The maximum limits of the ungained data
-    double physical_maximum;
+    EventDataType physical_maximum;
 
     //! \brief The minimum limits of the data with gain and offset applied
-    double digital_minimum;
+    EventDataType digital_minimum;
 
     //! \brief The maximum limits of the data with gain and offset applied
-    double digital_maximum;
+    EventDataType digital_maximum;
 
     //! \brief Raw integer data is multiplied by this value
-    double gain;
+    EventDataType gain;
 
     //! \brief This value is added to the raw data
-    double offset;
+    EventDataType offset;
 
     //! \brief Any prefiltering methods used (usually blank)
     QString prefiltering;
diff --git a/SleepLib/machine.cpp b/SleepLib/machine.cpp
index 831ce91f..d81c7096 100644
--- a/SleepLib/machine.cpp
+++ b/SleepLib/machine.cpp
@@ -10,7 +10,6 @@
 #include <QDebug>
 #include <QString>
 #include <QObject>
-//#include <tr1/random>
 #include <time.h>
 
 #include "machine.h"
@@ -30,13 +29,9 @@ Machine::Machine(Profile *p,MachineID id)
     profile=p;
     if (!id) {
         srand(time(NULL));
-        //std::tr1::minstd_rand gen;
-        //std::tr1::uniform_int<MachineID> unif(1, 0x7fffffff);
-        //gen.seed((unsigned int) time(NULL));
         MachineID temp;
         do {
             temp = rand();
-            //temp = unif(gen); //unif(gen) << 32 |
         } while (profile->machlist.find(temp)!=profile->machlist.end());
 
         m_id=temp;
diff --git a/SleepLib/profiles.cpp b/SleepLib/profiles.cpp
index cd71f275..7235925e 100644
--- a/SleepLib/profiles.cpp
+++ b/SleepLib/profiles.cpp
@@ -581,8 +581,12 @@ const char * US_STR_CalculateRDI="CalculateRDI";
 
 int Profile::countDays(MachineType mt, QDate start, QDate end)
 {
-    if (!start.isValid()) start=LastDay(mt);
-    if (!end.isValid()) end=LastDay(mt);
+    if (!start.isValid())
+        return 0;
+    //start=LastDay(mt);
+    if (!end.isValid())
+        return 0;
+    //end=LastDay(mt);
     QDate date=start;
     int days=0;
     do {
@@ -780,15 +784,17 @@ EventDataType Profile::calcPercentile(ChannelID code, EventDataType percent, Mac
     QVector<EventDataType> array;
 
     QHash<ChannelID,QHash<EventStoreType, EventStoreType> >::iterator vsi;
-    float gain;
+    EventDataType val,gain;
     bool setgain=false;
+
     //double val=0,tmp,hours=0;
     do {
         Day * day=GetGoodDay(date,mt);
         if (day) {
             for (int i=0;i<day->size();i++) {
                 for (QVector<Session *>::iterator s=day->begin();s!=day->end();s++) {
-                    if (!(*s)->enabled()) continue;
+                    if (!(*s)->enabled())
+                        continue;
 
                     Session *sess=*s;
                     gain=sess->m_gain[code];
@@ -801,7 +807,10 @@ EventDataType Profile::calcPercentile(ChannelID code, EventDataType percent, Mac
 
                     for (QHash<EventStoreType, EventStoreType>::iterator k=vsum.begin();k!=vsum.end();k++) {
                         for (int z=0;z<k.value();z++) {
-                            array.push_back(float(k.key())*gain);
+                            val=k.key();
+                            val*=gain;
+
+                            array.push_back(val);
                         }
                         /*sumi=summary.find(k.key());
                         if (sumi==summary.end()) summary[k.key()]=k.value();
@@ -821,7 +830,7 @@ EventDataType Profile::calcPercentile(ChannelID code, EventDataType percent, Mac
             }
         }
         date=date.addDays(1);
-    } while (date<end);
+    } while (date<=end);
 //    for (QHash<EventStoreType, EventStoreType>::iterator k=summary.begin();k!=summary.end();k++) {
 //        for (int i=0;i<k.value();i++)  {
 //            array.push_back(k.key());
@@ -845,7 +854,7 @@ EventDataType Profile::calcPercentile(ChannelID code, EventDataType percent, Mac
     int p=EventDataType(size)*percent;
     float p2=EventDataType(size)*percent;
     float diff=p2-p;
-    EventDataType val=array[p];
+    val=array[p];
     if (diff>0) {
         int s=p+1;
         if (s>size-1) s=size-1;
@@ -892,6 +901,8 @@ QDate Profile::FirstGoodDay(MachineType mt)
 
     QDate d=FirstDay(mt);
     QDate l=LastDay(mt);
+    if (!d.isValid() || !l.isValid())
+        return QDate();
     do {
         if (GetGoodDay(d,mt)!=NULL) return d;
         d=d.addDays(1);
diff --git a/docs/channels.xml b/docs/channels.xml
index 12e38623..fba680dd 100644
--- a/docs/channels.xml
+++ b/docs/channels.xml
@@ -24,8 +24,8 @@ Important: One id code per item, DO NOT CHANGE ID NUMBERS!!!
   <channel id="0x101e" class="data" name="UserFlag1" details="User Flag #1" label="UF1" unit="events/hour" color="dark cyan"/>
   <channel id="0x101f" class="data" name="UserFlag2" details="User Flag #2" label="UF2" unit="events/hour" color="dark cyan"/>
 
-  <channel id="0x1020" class="data" name="PressureMin" details="Min Therapy Pressure" label="PMin" color="black"/>
-  <channel id="0x1021" class="data" name="PressureMax" details="Max Therapy Pressure" label="PMax" color="black"/>
+  <channel id="0x1020" class="data" name="PressureMin" details="Min Therapy Pressure" label="Pressure" color="black"/>
+  <channel id="0x1021" class="data" name="PressureMax" details="Max Therapy Pressure" label="Pressure" color="black"/>
   <channel id="0x1022" class="data" name="RampTime" details="Ramp Time" label="Ramp Time" color="black"/>
   <channel id="0x1023" class="data" name="RampPressure" details="Ramp Starting Pressure" label="Ramp Pr." color="black"/>
 
@@ -101,7 +101,7 @@ Important: One id code per item, DO NOT CHANGE ID NUMBERS!!!
     <Option id="1" value="Ramp"/>
     <Option id="2" value="Full Time"/>
   </channel>
-  <channel id="0x1203" class="setting" scope="!session" name="PresResSet" details="Pressure Relief Setting" label="Pres. Rel. Set"/>
+  <channel id="0x1203" class="setting" scope="!session" name="PresRelSet" details="Pressure Relief Setting" label="Pres. Rel. Set" type="integer"/>
 
  </group>
  <group name="OXI">
diff --git a/mainwindow.cpp b/mainwindow.cpp
index 941e100e..2af2d641 100644
--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -403,7 +403,12 @@ EventDataType calcAHI(QDate start, QDate end)
               +p_profile->calcCount(CPAP_Apnea,MT_CPAP,start,end));
     if (PROFILE.general->calculateRDI())
         val+=p_profile->calcCount(CPAP_RERA,MT_CPAP,start,end);
-    val/=p_profile->calcHours(MT_CPAP,start,end);
+    EventDataType hours=p_profile->calcHours(MT_CPAP,start,end);
+
+    if (hours>0)
+        val/=hours;
+    else
+        val=0;
 
     return val;
 }
@@ -449,38 +454,6 @@ enum RXSortMode { RX_first, RX_last, RX_days, RX_ahi, RX_mode, RX_min, RX_max, R
 RXSortMode RXsort=RX_first;
 bool RXorder=false;
 
-//bool operator<(const RXChange & comp1, const RXChange & comp2) {
-//    if (RXorder) {
-//        switch (RXsort) {
-//        case RX_ahi: return comp1.ahi < comp2.ahi;
-//        case RX_days: return comp1.days < comp2.days;
-//        case RX_first: return comp1.first < comp2.first;
-//        case RX_last: return comp1.last < comp2.last;
-//        case RX_mode: return comp1.mode < comp2.mode;
-//        case RX_min:  return comp1.min < comp2.min;
-//        case RX_max:  return comp1.max < comp2.max;
-//        case RX_maxhi: return comp1.maxhi < comp2.maxhi;
-//        case RX_per1:  return comp1.per1 < comp2.per1;
-//        case RX_per2:  return comp1.per2 < comp2.per2;
-//        case RX_weighted:  return comp1.weighted < comp2.weighted;
-//        };
-//    } else {
-//        switch (RXsort) {
-//        case RX_ahi: return comp1.ahi > comp2.ahi;
-//        case RX_days: return comp1.days > comp2.days;
-//        case RX_first: return comp1.first > comp2.first;
-//        case RX_last: return comp1.last > comp2.last;
-//        case RX_mode: return comp1.mode > comp2.mode;
-//        case RX_min:  return comp1.min > comp2.min;
-//        case RX_max:  return comp1.max > comp2.max;
-//        case RX_maxhi: return comp1.maxhi > comp2.maxhi;
-//        case RX_per1:  return comp1.per1 > comp2.per1;
-//        case RX_per2:  return comp1.per2 > comp2.per2;
-//        case RX_weighted:  return comp1.weighted > comp2.weighted;
-//        };
-//    }
-//    return true;
-//}
 bool RXSort(const RXChange * comp1, const RXChange * comp2) {
     if (RXorder) {
         switch (RXsort) {
@@ -805,8 +778,8 @@ void MainWindow::on_summaryButton_clicked()
         CPAPMode mode,cmode=MODE_UNKNOWN;
         EventDataType cmin=0,cmax=0,cmaxhi=0, min,max,maxhi;
         Machine *mach,*lastmach=NULL;
-        PRTypes prelief=PR_UNKNOWN;
-        short prelset=0;
+        PRTypes lastpr, prelief=PR_UNKNOWN;
+        short prelset, lastprelset=-1;
         QDate date=lastcpap;
         Day * day;
         bool lastchanged=false;
@@ -833,7 +806,8 @@ void MainWindow::on_summaryButton_clicked()
                         bestAHIdate=date;
                     }
                 }
-
+                prelief=(PRTypes)round(day->settings_wavg(CPAP_PresReliefType));
+                prelset=round(day->settings_wavg(CPAP_PresReliefSet));
                 mode=(CPAPMode)round(day->settings_wavg(CPAP_Mode));
                 if (mode>=MODE_ASV) {
                     min=day->settings_min(CPAP_EPAP);
@@ -848,7 +822,7 @@ void MainWindow::on_summaryButton_clicked()
                 } else {
                     min=day->settings_min(CPAP_Pressure);
                 }
-                if ((mode!=cmode) || (min!=cmin) || (max!=cmax) || (maxhi!=cmaxhi) || (day->machine!=lastmach))  {
+                if ((mode!=cmode) || (min!=cmin) || (max!=cmax) || (maxhi!=cmaxhi) || (day->machine!=lastmach) || (prelief!=lastpr))  {
                     if (cmode!=MODE_UNKNOWN) {
                         first=date.addDays(1);
                         int days=PROFILE.countDays(MT_CPAP,first,last);
@@ -861,8 +835,8 @@ void MainWindow::on_summaryButton_clicked()
                         rx.min=cmin;
                         rx.max=cmax;
                         rx.maxhi=cmaxhi;
-                        rx.prelief=prelief;
-                        rx.prelset=prelset;
+                        rx.prelief=lastpr;
+                        rx.prelset=lastprelset;
 
                         if (mode<MODE_BIPAP) {
                             rx.per1=p_profile->calcPercentile(CPAP_Pressure,percentile,MT_CPAP,first,last);
@@ -881,6 +855,8 @@ void MainWindow::on_summaryButton_clicked()
                     cmin=min;
                     cmax=max;
                     cmaxhi=maxhi;
+                    lastpr=prelief;
+                    lastprelset=prelset;
                     last=date;
                     lastmach=day->machine;
                     lastchanged=true;
@@ -890,6 +866,7 @@ void MainWindow::on_summaryButton_clicked()
             date=date.addDays(-1);
         } while (date>=firstcpap);
 
+        lastchanged=false;
         if (!lastchanged) {
            // last=date.addDays(1);
             first=firstcpap;
@@ -903,6 +880,8 @@ void MainWindow::on_summaryButton_clicked()
             rx.min=min;
             rx.max=max;
             rx.maxhi=maxhi;
+            rx.prelief=prelief;
+            rx.prelset=prelset;
             if (mode<MODE_BIPAP) {
                 rx.per1=p_profile->calcPercentile(CPAP_Pressure,0.9,MT_CPAP,first,last);
                 rx.per2=0;
@@ -1040,12 +1019,13 @@ void MainWindow::on_summaryButton_clicked()
             extratxt=QString("<td><b>%1</b></td>")
                 .arg(tr("Pressure"));
         }
-        html+=QString("<tr><td><b>%1</b></td><td><b>%2</b></td><td><b>%3</b></td><td><b>%4</b></td><td><b>%5</b></td>%6</tr>")
+        html+=QString("<tr><td><b>%1</b></td><td><b>%2</b></td><td><b>%3</b></td><td><b>%4</b></td><td><b>%5</b></td><td><b>%6</b></td>%7</tr>")
                   .arg(tr("First"))
                   .arg(tr("Last"))
                   .arg(tr("Days"))
                   .arg(ahitxt)
                   .arg(tr("Mode"))
+                  .arg(tr("Pr. Rel."))
                   .arg(extratxt);
 
         for (int i=0;i<rxchange.size();i++) {
@@ -1068,7 +1048,12 @@ void MainWindow::on_summaryButton_clicked()
             } else if (cpapmode>MODE_CPAP) {
                 extratxt=QString("<td>%1</td><td>%2</td>").arg(rx.max,0,'f',2).arg(rx.per1,0,'f',2);
             } else extratxt="";
-            html+=QString("<tr bgcolor='"+color+"' onmouseover='ChangeColor(this, \"#dddddd\");' onmouseout='ChangeColor(this, \""+color+"\");' onclick='tabwidget.setCurrentIndex(3); print \"%1 %2\";'><td>%3</td><td>%4</td><td>%5</td><td>%6</td><td>%7</td><td>%8</td>%9</tr>")
+            QString presrel;
+            if (rx.prelset>0) {
+                presrel=schema::channel[CPAP_PresReliefType].option(int(rx.prelief));
+                presrel+=QString(" x%1").arg(rx.prelset);
+            } else presrel="None";
+            html+=QString("<tr bgcolor='"+color+"' onmouseover='ChangeColor(this, \"#dddddd\");' onmouseout='ChangeColor(this, \""+color+"\");' onclick='tabwidget.setCurrentIndex(3); print \"%1 %2\";'><td>%3</td><td>%4</td><td>%5</td><td>%6</td><td>%7</td><td>%8</td><td>%9</td>%10</tr>")
                     .arg(rx.first.toString(Qt::ISODate))
                     .arg(rx.last.toString(Qt::ISODate))
                     .arg(rx.first.toString(Qt::SystemLocaleShortDate))
@@ -1076,6 +1061,7 @@ void MainWindow::on_summaryButton_clicked()
                     .arg(rx.days)
                     .arg(rx.ahi,0,'f',2)
                     .arg(schema::channel[CPAP_Mode].option(int(rx.mode)-1))
+                    .arg(presrel)
                     .arg(rx.min,0,'f',2)
                     .arg(extratxt);
         }
diff --git a/overview.cpp b/overview.cpp
index e87b8439..f243b42d 100644
--- a/overview.cpp
+++ b/overview.cpp
@@ -99,7 +99,7 @@ Overview::Overview(QWidget *parent,gGraphView * shared) :
 
 
     US=createGraph(tr("Session Times"),tr("Session Times\n(hours)"),YT_Time);
-    PR=createGraph(tr("Pressure"),tr("Pressure\n(cmH2O)"));
+    PR=createGraph(STR_TR_Pressure,tr("Pressure\n(cmH2O)"));
     SET=createGraph(tr("Settings"),("Settings"));
     LK=createGraph(tr("Leaks"),tr("Leak Rate\n(L/min)"));
     NPB=createGraph(tr("% in PB"),tr("Periodic\nBreathing\n(% of night)"));
@@ -179,9 +179,9 @@ Overview::Overview(QWidget *parent,gGraphView * shared) :
     set=new SummaryChart("",GT_LINE);
     //set->addSlice(PRS1_SysOneResistSet,QColor("grey"),ST_SETAVG);
     set->addSlice(PRS1_HumidSetting,QColor("blue"),ST_SETWAVG,true);
-    set->addSlice(PRS1_FlexSet,QColor("red"),ST_SETWAVG,true);
-    set->addSlice(RMS9_EPRSet,QColor("green"),ST_SETWAVG,true);
-    set->addSlice(INTP_SmartFlex,QColor("purple"),ST_SETWAVG,true);
+    set->addSlice(CPAP_PresReliefSet,QColor("red"),ST_SETWAVG,true);
+    //set->addSlice(RMS9_EPRSet,QColor("green"),ST_SETWAVG,true);
+    //set->addSlice(INTP_SmartFlex,QColor("purple"),ST_SETWAVG,true);
     SET->setRecMinY(0);
     SET->setRecMaxY(5);
     SET->AddLayer(set);
@@ -190,6 +190,7 @@ Overview::Overview(QWidget *parent,gGraphView * shared) :
     rr->addSlice(CPAP_RespRate,QColor("light blue"),ST_MIN,true);
     rr->addSlice(CPAP_RespRate,QColor("light green"),ST_PERC,true,0.95);
     rr->addSlice(CPAP_RespRate,QColor("blue"),ST_WAVG,true);
+    rr->addSlice(CPAP_RespRate,QColor("green"),ST_MAX,true);
     RR->AddLayer(rr);
 
     tv=new SummaryChart(tr("L/b"),GT_LINE);
@@ -211,28 +212,28 @@ Overview::Overview(QWidget *parent,gGraphView * shared) :
     ptb->addSlice(CPAP_PTB,QColor("orange"),ST_WAVG,true);
     PTB->AddLayer(ptb);
 
-    pr=new SummaryChart(STR_UNIT_CMH2O,GT_LINE);
+    pr=new SummaryChart(STR_TR_Pressure,GT_LINE);
     //PR->setRecMinY(4.0);
     //PR->setRecMaxY(12.0);
 
     CPAPMode mode=(CPAPMode)(int)PROFILE.calcSettingsMax(CPAP_Mode,MT_CPAP,PROFILE.FirstDay(MT_CPAP),PROFILE.LastDay(MT_CPAP));
 
-    if (mode>=MODE_BIPAP) {
-        pr->addSlice(CPAP_EPAP,QColor("green"),ST_MIN,true);
-        pr->addSlice(CPAP_EPAP,QColor("light green"),ST_PERC,true,0.95);
+//    //if (mode>=MODE_BIPAP) {
+//        pr->addSlice(CPAP_EPAP,QColor("green"),ST_SETMIN,true);
+//        pr->addSlice(CPAP_EPAP,QColor("light green"),ST_PERC,true,0.95);
 
-        pr->addSlice(CPAP_IPAP,QColor("light blue"),ST_PERC,true,0.95);
-        pr->addSlice(CPAP_IPAP,QColor("blue"),ST_MAX,true);
-    } else if (mode>MODE_CPAP) {
-        pr->addSlice(CPAP_Pressure,QColor("dark green"),ST_WAVG,true);
-        pr->addSlice(CPAP_Pressure,QColor("orange"),ST_MIN,true);
-        pr->addSlice(CPAP_Pressure,QColor("red"),ST_MAX,true);
-    //pr->addSlice(CPAP_Pressure,QColor("grey"),ST_90P,true);
-        pr->addSlice(CPAP_Pressure,QColor("grey"),ST_PERC,true,0.95);
-    } else {
+//        pr->addSlice(CPAP_IPAP,QColor("light blue"),ST_PERC,true,0.95);
+//        pr->addSlice(CPAP_IPAP,QColor("blue"),ST_SETMAX,true);
+//    //} else if (mode>MODE_CPAP) {
+//        pr->addSlice(CPAP_PressureMin,QColor("orange"),ST_SETMIN,true);
+//        pr->addSlice(CPAP_Pressure,QColor("dark green"),ST_WAVG,true);
+//    //pr->addSlice(CPAP_Pressure,QColor("grey"),ST_90P,true);
+//        pr->addSlice(CPAP_Pressure,QColor("grey"),ST_PERC,true,0.95);
+//        pr->addSlice(CPAP_PressureMax,QColor("red"),ST_SETMAX,true);
+//    //} else {
 
-        pr->addSlice(CPAP_Pressure,QColor("grey"),ST_SETWAVG,true);
-    }
+//        pr->addSlice(CPAP_Pressure,QColor("dark green"),ST_SETWAVG,true);
+//    //}
     PR->AddLayer(pr);
 
     lk=new SummaryChart(tr("Avg Leak"),GT_LINE);