From 429fcb64a11e1c4f7934654f518591cc89bc9b44 Mon Sep 17 00:00:00 2001 From: Mark Watkins Date: Tue, 30 Sep 2014 00:41:31 +1000 Subject: [PATCH] Some machine pixmap stuff, use gzip compatible Summaries.xml, preliminary PRS1 .006 oximetery parser --- sleepyhead/Graphs/gGraphView.cpp | 1 + sleepyhead/Graphs/gGraphView.h | 4 +- sleepyhead/Graphs/gLineChart.h | 2 +- sleepyhead/Graphs/gSessionTimesChart.cpp | 133 +++++++-- sleepyhead/Graphs/gSessionTimesChart.h | 58 +++- sleepyhead/Resources.qrc | 1 + sleepyhead/SleepLib/common.cpp | 112 +++++++ sleepyhead/SleepLib/common.h | 3 + .../SleepLib/loader_plugins/cms50_loader.cpp | 5 + .../SleepLib/loader_plugins/prs1_loader.cpp | 282 +++++++++++++++--- .../SleepLib/loader_plugins/prs1_loader.h | 12 +- sleepyhead/SleepLib/machine.cpp | 122 +++++++- sleepyhead/SleepLib/machine.h | 5 + sleepyhead/SleepLib/machine_loader.h | 9 +- sleepyhead/SleepLib/schema.cpp | 2 + sleepyhead/SleepLib/session.cpp | 16 +- sleepyhead/SleepLib/session.h | 11 +- sleepyhead/daily.cpp | 8 +- sleepyhead/icons/prs1_60s.png | Bin 0 -> 81511 bytes sleepyhead/mainwindow.cpp | 22 +- sleepyhead/mainwindow.h | 4 + sleepyhead/mainwindow.ui | 25 +- sleepyhead/oximeterimport.cpp | 1 + sleepyhead/sessionbar.cpp | 14 +- sleepyhead/sessionbar.h | 4 +- sleepyhead/statistics.cpp | 1 + 26 files changed, 715 insertions(+), 142 deletions(-) create mode 100644 sleepyhead/icons/prs1_60s.png diff --git a/sleepyhead/Graphs/gGraphView.cpp b/sleepyhead/Graphs/gGraphView.cpp index 3012e965..e71dee9b 100644 --- a/sleepyhead/Graphs/gGraphView.cpp +++ b/sleepyhead/Graphs/gGraphView.cpp @@ -3170,6 +3170,7 @@ const quint16 gvversion = 4; void gGraphView::SaveSettings(QString title) { + qDebug() << "Saving" << title << "settings"; QString filename = p_profile->Get("{DataFolder}/") + title.toLower() + ".shg"; QFile f(filename); f.open(QFile::WriteOnly); diff --git a/sleepyhead/Graphs/gGraphView.h b/sleepyhead/Graphs/gGraphView.h index d0c4c72f..729f5072 100644 --- a/sleepyhead/Graphs/gGraphView.h +++ b/sleepyhead/Graphs/gGraphView.h @@ -521,7 +521,7 @@ class gGraphView int strings_drawn_this_frame; int strings_cached_this_frame; - QList history; + QVector history; protected: @@ -621,7 +621,7 @@ class gGraphView qint64 m_minx, m_maxx; - QList fwd_history; + QVector fwd_history; float print_scaleX, print_scaleY; QPixmap previous_day_snapshot; diff --git a/sleepyhead/Graphs/gLineChart.h b/sleepyhead/Graphs/gLineChart.h index 2ef8e7c9..4895bda1 100644 --- a/sleepyhead/Graphs/gLineChart.h +++ b/sleepyhead/Graphs/gLineChart.h @@ -121,7 +121,7 @@ class gLineChart: public Layer QString getMetaString(qint64 time); void addDotLine(DottedLine dot) { m_dotlines.append(dot); } - QList m_dotlines; + QVector m_dotlines; QHash m_flags_enabled; QHash > m_dot_enabled; diff --git a/sleepyhead/Graphs/gSessionTimesChart.cpp b/sleepyhead/Graphs/gSessionTimesChart.cpp index 0dcdaf0f..79b67ded 100644 --- a/sleepyhead/Graphs/gSessionTimesChart.cpp +++ b/sleepyhead/Graphs/gSessionTimesChart.cpp @@ -162,13 +162,14 @@ void gSummaryChart::preCalc() } } -void gSummaryChart::customCalc(Day *day, QList & slices) +void gSummaryChart::customCalc(Day *day, QVector & slices) { - if (slices.size() != calcitems.size()) { + int size = slices.size(); + if (size != calcitems.size()) { return; } float hour = day->hours(m_machtype); - for (int i=0; i & slices = cache[idx]; + QVector & slices = cache[idx]; QString txt; for (int i=0; i< slices.size(); ++i) { SummaryChartSlice & slice = slices[i]; @@ -320,7 +321,7 @@ void gSummaryChart::populate(Day * day, int idx) } if (!good) return; - QList & slices = cache[idx]; + QVector & slices = cache[idx]; float hours = day->hours(m_machtype); float base = 0; @@ -476,7 +477,7 @@ void gSummaryChart::paint(QPainter &painter, gGraph &graph, const QRegion ®io day->OpenSummary(); - QHash >::iterator cit = cache.find(i); + QHash >::iterator cit = cache.find(i); if (cit == cache.end()) { populate(day, i); @@ -484,7 +485,7 @@ void gSummaryChart::paint(QPainter &painter, gGraph &graph, const QRegion ®io } if (cit != cache.end()) { - QList & list = cit.value(); + QVector & list = cit.value(); float base = 0, val; int listsize = list.size(); for (int j=0; j < listsize; ++j) { @@ -549,7 +550,7 @@ void gSummaryChart::paint(QPainter &painter, gGraph &graph, const QRegion ®io hlday = true; } - QHash >::iterator cit = cache.find(idx); + QHash >::iterator cit = cache.find(idx); if (cit == cache.end()) { populate(day, idx); @@ -561,7 +562,7 @@ void gSummaryChart::paint(QPainter &painter, gGraph &graph, const QRegion ®io ///////////////////////////////////////////////////////////////////////////////////// /// Draw pressure settings ///////////////////////////////////////////////////////////////////////////////////// - QList & list = cit.value(); + QVector & list = cit.value(); customCalc(day, list); int listsize = list.size(); @@ -651,7 +652,7 @@ QString gUsageChart::tooltipData(Day * day, int) void gUsageChart::populate(Day *day, int idx) { - QList & slices = cache[idx]; + QVector & slices = cache[idx]; float hours = day->hours(); @@ -675,7 +676,7 @@ void gUsageChart::preCalc() calc.reset(idx_end - idx_start); } -void gUsageChart::customCalc(Day *, QList &list) +void gUsageChart::customCalc(Day *, QVector &list) { if (list.size() == 0) { incompdays++; @@ -738,7 +739,7 @@ void gSessionTimesChart::preCalc() { calc2.reset(idx_end - idx_start); } -void gSessionTimesChart::customCalc(Day *, QList & slices) { +void gSessionTimesChart::customCalc(Day *, QVector & slices) { int size = slices.size(); num_slices += size; @@ -867,7 +868,7 @@ void gSessionTimesChart::paint(QPainter &painter, gGraph &graph, const QRegion & continue; } - QHash >::iterator cit = cache.find(i); + QHash >::iterator cit = cache.find(i); if (cit == cache.end()) { day->OpenSummary(); @@ -875,7 +876,7 @@ void gSessionTimesChart::paint(QPainter &painter, gGraph &graph, const QRegion & splittime = QDateTime(date, split); QList::iterator si; - QList & slices = cache[i]; + QVector & slices = cache[i]; bool haveoxi = day->hasMachine(MT_OXIMETER); @@ -923,7 +924,7 @@ void gSessionTimesChart::paint(QPainter &painter, gGraph &graph, const QRegion & } if (cit != cache.end()) { - QList & list = cit.value(); + QVector & list = cit.value(); int listsize = list.size(); float peak = 0, base = 999; @@ -981,7 +982,7 @@ void gSessionTimesChart::paint(QPainter &painter, gGraph &graph, const QRegion & continue; } - QHash >::iterator cit = cache.find(idx); + QHash >::iterator cit = cache.find(idx); float x1 = lastx1 + barw; @@ -995,7 +996,7 @@ void gSessionTimesChart::paint(QPainter &painter, gGraph &graph, const QRegion & } if (cit != cache.end()) { - QList & slices = cit.value(); + QVector & slices = cit.value(); customCalc(day, slices); int size = slices.size(); @@ -1055,7 +1056,7 @@ void gTTIAChart::preCalc() { gSummaryChart::preCalc(); } -void gTTIAChart::customCalc(Day *, QList & slices) +void gTTIAChart::customCalc(Day *, QVector & slices) { if (slices.size() == 0) return; const SummaryChartSlice & slice = slices.at(0); @@ -1069,8 +1070,8 @@ void gTTIAChart::afterDraw(QPainter &, gGraph &graph, QRect rect) for (int i=0; i < num_channels; ++i) { SummaryCalcItem & calc = calcitems[i]; - ChannelID code = calc.code; - schema::Channel & chan = schema::channel[code]; + //ChannelID code = calc.code; + //schema::Channel & chan = schema::channel[code]; float mid = 0; switch (midcalc) { case 0: @@ -1097,7 +1098,7 @@ void gTTIAChart::afterDraw(QPainter &, gGraph &graph, QRect rect) } void gTTIAChart::populate(Day *day, int idx) { - QList & slices = cache[idx]; + QVector & slices = cache[idx]; float ttia = day->sum(CPAP_Obstructive) + day->sum(CPAP_ClearAirway) + day->sum(CPAP_Apnea) + day->sum(CPAP_Hypopnea); int h = ttia / 3600; int m = int(ttia) / 60 % 60; @@ -1108,7 +1109,7 @@ void gTTIAChart::populate(Day *day, int idx) } QString gTTIAChart::tooltipData(Day *, int idx) { - QList & slices = cache[idx]; + QVector & slices = cache[idx]; if (slices.size() == 0) return QString(); const SummaryChartSlice & slice = slices.at(0); @@ -1132,7 +1133,7 @@ void gAHIChart::preCalc() ahi_data.clear(); ahi_data.reserve(idx_end-idx_start); } -void gAHIChart::customCalc(Day *day, QList &list) +void gAHIChart::customCalc(Day *day, QVector &list) { int size = list.size(); if (size == 0) return; @@ -1181,27 +1182,31 @@ void gAHIChart::afterDraw(QPainter & /*painter */, gGraph &graph, QRect rect) //int size = idx_end - idx_start; + bool skip = true; float med = 0; switch (midcalc) { case 0: if (ahi_data.size() > 0) { med = median(ahi_data.begin(), ahi_data.end()); + skip = false; } break; case 1: // wavg if (total_hours > 0) { med = ahi_wavg / total_hours; + skip = false; } break; case 2: // avg if (calc_cnt > 0) { med = ahi_avg / calc_cnt; + skip = false; } break; } QStringList txtlist; - txtlist.append(QObject::tr("%1 %2 / %3 / %4").arg(STR_TR_AHI).arg(min_ahi, 0, 'f', 2).arg(med, 0, 'f', 2).arg(max_ahi, 0, 'f', 2)); + if (!skip) txtlist.append(QObject::tr("%1 %2 / %3 / %4").arg(STR_TR_AHI).arg(min_ahi, 0, 'f', 2).arg(med, 0, 'f', 2).arg(max_ahi, 0, 'f', 2)); int num_channels = calcitems.size(); @@ -1210,25 +1215,29 @@ void gAHIChart::afterDraw(QPainter & /*painter */, gGraph &graph, QRect rect) ChannelID code = calc.code; schema::Channel & chan = schema::channel[code]; float mid = 0; + skip = true; switch (midcalc) { case 0: if (calc.median_data.size() > 0) { mid = median(calc.median_data.begin(), calc.median_data.end()); + skip = false; } break; case 1: if (calc.divisor > 0) { mid = calc.wavg_sum / calc.divisor; + skip = false; } break; case 2: - if (calc.divisor > 0) { - mid = calc.avg_sum / calc.divisor; + if (calc.cnt > 0) { + mid = calc.avg_sum / calc.cnt; + skip = false; } break; } - txtlist.append(QString("%1 %2 / %3 / %4").arg(chan.label()).arg(calc.min, 0, 'f', 2).arg(mid, 0, 'f', 2).arg(calc.max, 0, 'f', 2)); + if (!skip) txtlist.append(QString("%1 %2 / %3 / %4").arg(chan.label()).arg(calc.min, 0, 'f', 2).arg(mid, 0, 'f', 2).arg(calc.max, 0, 'f', 2)); } QString txt = txtlist.join(", "); graph.renderText(txt, rect.left(), rect.top()-5*graph.printScaleY(), 0); @@ -1236,7 +1245,7 @@ void gAHIChart::afterDraw(QPainter & /*painter */, gGraph &graph, QRect rect) void gAHIChart::populate(Day *day, int idx) { - QList & slices = cache[idx]; + QVector & slices = cache[idx]; float hours = day->hours(); int num_channels = calcitems.size(); @@ -1254,7 +1263,7 @@ void gAHIChart::populate(Day *day, int idx) } QString gAHIChart::tooltipData(Day *day, int idx) { - QList & slices = cache[idx]; + QVector & slices = cache[idx]; float total = 0; float hour = day->hours(m_machtype); QString txt; @@ -1290,12 +1299,76 @@ gPressureChart::gPressureChart() addCalc(CPAP_IPAP, ST_90P, brighten(schema::channel[CPAP_IPAP].defaultColor(),1.33)); // 12 } +void gPressureChart::afterDraw(QPainter &, gGraph &graph, QRect rect) +{ + int pressure_cnt = calcitems[0].cnt; + int pressuremin_cnt = calcitems[3].cnt; + int epap_cnt = calcitems[5].cnt; + int ipap_cnt = calcitems[6].cnt; + int ipaphi_cnt = calcitems[8].cnt; + int epaplo_cnt = calcitems[7].cnt; + + QStringList presstr; + + float mid = 0; + + if (pressure_cnt > 0) { + mid = calcitems[0].mid(); + presstr.append(QString("%1 %2/%3/%4"). + arg(STR_TR_CPAP). + arg(calcitems[0].min,0,'f',1). + arg(mid, 0, 'f', 1). + arg(calcitems[0].max,0,'f',1)); + } + if (pressuremin_cnt > 0) { + presstr.append(QString("%1 %2/%3/%4/%5"). + arg(STR_TR_APAP). + arg(calcitems[3].min,0,'f',1). + arg(calcitems[1].mid(), 0, 'f', 1). + arg(calcitems[2].mid(),0,'f',1). + arg(calcitems[4].max, 0, 'f', 1)); + + } + if (epap_cnt > 0) { + presstr.append(QString("%1 %2/%3/%4"). + arg(STR_TR_EPAP). + arg(calcitems[5].min,0,'f',1). + arg(calcitems[5].mid(), 0, 'f', 1). + arg(calcitems[5].max, 0, 'f', 1)); + } + if (ipap_cnt > 0) { + presstr.append(QString("%1 %2/%3/%4"). + arg(STR_TR_IPAP). + arg(calcitems[6].min,0,'f',1). + arg(calcitems[6].mid(), 0, 'f', 1). + arg(calcitems[6].max, 0, 'f', 1)); + } + if (epaplo_cnt > 0) { + presstr.append(QString("%1 %2/%3/%4"). + arg(STR_TR_EPAPLo). + arg(calcitems[7].min,0,'f',1). + arg(calcitems[7].mid(), 0, 'f', 1). + arg(calcitems[7].max, 0, 'f', 1)); + } + + if (ipaphi_cnt > 0) { + presstr.append(QString("%1 %2/%3/%4"). + arg(STR_TR_IPAPHi). + arg(calcitems[8].min,0,'f',1). + arg(calcitems[8].mid(), 0, 'f', 1). + arg(calcitems[8].max, 0, 'f', 1)); + } + QString txt = presstr.join(" "); + graph.renderText(txt, rect.left(), rect.top()-5*graph.printScaleY(), 0); + +} + void gPressureChart::populate(Day * day, int idx) { float tmp; CPAPMode mode = (CPAPMode)(int)qRound(day->settings_wavg(CPAP_Mode)); - QList & slices = cache[idx]; + QVector & slices = cache[idx]; if (mode == MODE_CPAP) { float pr = day->settings_max(CPAP_Pressure); diff --git a/sleepyhead/Graphs/gSessionTimesChart.h b/sleepyhead/Graphs/gSessionTimesChart.h index 94c2442b..fa41c309 100644 --- a/sleepyhead/Graphs/gSessionTimesChart.h +++ b/sleepyhead/Graphs/gSessionTimesChart.h @@ -58,20 +58,35 @@ struct SummaryCalcItem { SummaryCalcItem(ChannelID code, SummaryType type, QColor color) :code(code), type(type), color(color) { } - - inline void update(float value, float weight) { + float mid() + { + float val = 0; switch (midcalc) { case 0: - median_data.append(value); + if (median_data.size() > 0) + val = median(median_data.begin(), median_data.end()); break; case 1: - wavg_sum += value * weight; - divisor += weight; + if (divisor > 0) + val = wavg_sum / divisor; break; - default: - avg_sum += value; - cnt++; + case 2: + if (cnt > 0) + val = avg_sum / cnt; } + return val; + } + + + inline void update(float value, float weight) { + if (midcalc == 0) { + median_data.append(value); + } + + avg_sum += value; + cnt++; + wavg_sum += value * weight; + divisor += weight; min = qMin(min, value); max = qMax(max, value); } @@ -161,7 +176,7 @@ public: virtual void preCalc(); //! \brief Override to call stuff in main loop - virtual void customCalc(Day *, QList &); + virtual void customCalc(Day *, QVector &); //! \brief Override to call stuff after draw is complete virtual void afterDraw(QPainter &, gGraph &, QRect); @@ -232,8 +247,8 @@ protected: QMap dayindex; QList daylist; - QHash > cache; - QList calcitems; + QHash > cache; + QVector calcitems; int expected_slices; @@ -273,7 +288,7 @@ public: } virtual void preCalc(); - virtual void customCalc(Day *, QList & slices); + virtual void customCalc(Day *, QVector & slices); virtual void afterDraw(QPainter &, gGraph &, QRect); //! \brief Renders the graph to the QPainter object @@ -309,7 +324,7 @@ public: virtual ~gUsageChart() {} virtual void preCalc(); - virtual void customCalc(Day *, QList &); + virtual void customCalc(Day *, QVector &); virtual void afterDraw(QPainter &, gGraph &, QRect); virtual void populate(Day *day, int idx); @@ -343,7 +358,7 @@ public: virtual ~gTTIAChart() {} virtual void preCalc(); - virtual void customCalc(Day *, QList &); + virtual void customCalc(Day *, QVector &); virtual void afterDraw(QPainter &, gGraph &, QRect); virtual void populate(Day *day, int idx); virtual QString tooltipData(Day * day, int); @@ -376,7 +391,7 @@ public: virtual ~gAHIChart() {} virtual void preCalc(); - virtual void customCalc(Day *, QList &); + virtual void customCalc(Day *, QVector &); virtual void afterDraw(QPainter &, gGraph &, QRect); virtual void populate(Day *, int idx); @@ -426,7 +441,18 @@ public: return sc; } -// virtual void afterDraw(QPainter &, gGraph &, QRect); +// virtual void preCalc(); + virtual void customCalc(Day *day, QVector &slices) { + int size = slices.size(); + float hour = day->hours(m_machtype); + for (int i=0; i < size; ++i) { + SummaryChartSlice & slice = slices[i]; + SummaryCalcItem * calc = slices[i].calc; + + calc->update(slice.value, hour); + } + } + virtual void afterDraw(QPainter &, gGraph &, QRect); virtual void populate(Day * day, int idx); diff --git a/sleepyhead/Resources.qrc b/sleepyhead/Resources.qrc index d0189be0..5eb0d2f4 100644 --- a/sleepyhead/Resources.qrc +++ b/sleepyhead/Resources.qrc @@ -51,5 +51,6 @@ icons/intellipap.png icons/pushpin.png icons/eye.png + icons/prs1_60s.png diff --git a/sleepyhead/SleepLib/common.cpp b/sleepyhead/SleepLib/common.cpp index 1b3f1bbb..e58ed01b 100644 --- a/sleepyhead/SleepLib/common.cpp +++ b/sleepyhead/SleepLib/common.cpp @@ -8,6 +8,7 @@ #include #include +#include #include "profiles.h" @@ -507,3 +508,114 @@ void initializeStrings() STR_TR_Avg = QObject::tr("Avg"); // Average STR_TR_WAvg = QObject::tr("W-Avg"); // Weighted Average } + + + + +quint32 CRC32(const char * data, quint32 length) +{ + quint32 crc32 = 0xffffffff; + + for (quint32 idx=0; idx 0; j--) { + if (i & 1) { + i = (i >> 1) ^ 0xedb88320; + } else { + i >>= 1; + } + } + + crc32 = ((crc32) >> 8) ^ i; + } + + return ~crc32; +} + +quint32 crc32buf(const QByteArray& data) +{ + return CRC32(data.constData(), data.size()); +} + +// Gzip function +QByteArray gCompress(const QByteArray& data) +{ + QByteArray compressedData = qCompress(data); + // Strip the first six bytes (a 4-byte length put on by qCompress and a 2-byte zlib header) + // and the last four bytes (a zlib integrity check). + compressedData.remove(0, 6); + compressedData.chop(4); + + QByteArray header; + QDataStream ds1(&header, QIODevice::WriteOnly); + // Prepend a generic 10-byte gzip header (see RFC 1952), + ds1 << quint16(0x1f8b) + << quint16(0x0800) + << quint16(0x0000) + << quint16(0x0000) + << quint16(0x000b); + + // Append a four-byte CRC-32 of the uncompressed data + // Append 4 bytes uncompressed input size modulo 2^32 + QByteArray footer; + QDataStream ds2(&footer, QIODevice::WriteOnly); + ds2.setByteOrder(QDataStream::LittleEndian); + ds2 << crc32buf(data) + << quint32(data.size()); + + return header + compressedData + footer; +} + + +// Pinched from http://stackoverflow.com/questions/2690328/qt-quncompress-gzip-data +QByteArray gUncompress(const QByteArray &data) +{ + if (data.size() <= 4) { + qWarning("gUncompress: Input data is truncated"); + return QByteArray(); + } + + QByteArray result; + + int ret; + z_stream strm; + static const int CHUNK_SIZE = 1024; + char out[CHUNK_SIZE]; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = data.size(); + strm.next_in = (Bytef*)(data.data()); + + ret = inflateInit2(&strm, 15 + 32); // gzip decoding + if (ret != Z_OK) + return QByteArray(); + + // run inflate() + do { + strm.avail_out = CHUNK_SIZE; + strm.next_out = (Bytef*)(out); + + ret = inflate(&strm, Z_NO_FLUSH); + Q_ASSERT(ret != Z_STREAM_ERROR); // state not clobbered + + switch (ret) { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; // and fall through + case Z_DATA_ERROR: + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + return QByteArray(); + } + + result.append(out, CHUNK_SIZE - strm.avail_out); + } while (strm.avail_out == 0); + + // clean up and return + inflateEnd(&strm); + return result; +} diff --git a/sleepyhead/SleepLib/common.h b/sleepyhead/SleepLib/common.h index 71a98c92..d0ed158d 100644 --- a/sleepyhead/SleepLib/common.h +++ b/sleepyhead/SleepLib/common.h @@ -19,6 +19,9 @@ #endif +QByteArray gCompress(const QByteArray& data); +QByteArray gUncompress(const QByteArray &data); + const quint16 filetype_summary = 0; const quint16 filetype_data = 1; const quint16 filetype_sessenabled = 5; diff --git a/sleepyhead/SleepLib/loader_plugins/cms50_loader.cpp b/sleepyhead/SleepLib/loader_plugins/cms50_loader.cpp index eb3f8780..89f03315 100644 --- a/sleepyhead/SleepLib/loader_plugins/cms50_loader.cpp +++ b/sleepyhead/SleepLib/loader_plugins/cms50_loader.cpp @@ -262,6 +262,11 @@ int CMS50Loader::doImportMode() // Either a CMS50D+, has a bad header, or it's really midnight, set a flag anyway for later to help choose the right sync time cms50dplus = (hour == 0) && (minute == 0); + MachineInfo info = newInfo(); + info.model = cms50dplus ? QObject::tr("CMS50D+") : QObject::tr("CMS50E/F"); + info.serial = QString(); + Machine * mach = CreateMachine(info); + qDebug() << QString("Receiving Oximeter transmission %1:%2").arg(hour).arg(minute); // set importing to true or whatever.. diff --git a/sleepyhead/SleepLib/loader_plugins/prs1_loader.cpp b/sleepyhead/SleepLib/loader_plugins/prs1_loader.cpp index 03f64651..bf6c01d6 100644 --- a/sleepyhead/SleepLib/loader_plugins/prs1_loader.cpp +++ b/sleepyhead/SleepLib/loader_plugins/prs1_loader.cpp @@ -121,10 +121,13 @@ struct WaveHeaderList { PRS1Loader::PRS1Loader() { const QString PRS1_ICON = ":/icons/prs1.png"; + const QString PRS1_60_ICON = ":/icons/prs1_60s.png"; QString s = newInfo().series; - m_pixmap_paths[s] = PRS1_ICON; - m_pixmaps[s] = QPixmap(PRS1_ICON); + m_pixmap_paths["System One"] = PRS1_ICON; + m_pixmaps["System One"] = QPixmap(PRS1_ICON); + m_pixmap_paths["System One (60 Series)"] = PRS1_60_ICON; + m_pixmaps["System One (60 Series)"] = QPixmap(PRS1_60_ICON); //genCRCTable(); // find what I did with this.. m_buffer = nullptr; @@ -147,6 +150,14 @@ const QString PR_STR_PSeries = "P-Series"; // Tests path to see if it has (what looks like) a valid PRS1 folder structure bool PRS1Loader::Detect(const QString & path) +{ + QString newpath = checkDir(path); + + return !newpath.isEmpty(); +} + + +QString PRS1Loader::checkDir(const QString & path) { QString newpath = path; @@ -159,33 +170,133 @@ bool PRS1Loader::Detect(const QString & path) QDir dir(newpath); if ((!dir.exists() || !dir.isReadable())) { - return false; + return QString(); } qDebug() << "PRS1Loader::Detect path=" << newpath; QFile lastfile(newpath+"/last.txt"); - if (!lastfile.exists()) { - return false; + + QString machpath; + if (lastfile.exists()) { + if (!lastfile.open(QIODevice::ReadOnly)) { + qDebug() << "PRS1Loader: last.txt exists but I couldn't open it!"; + } else { + QTextStream ts(&lastfile); + QString serial = ts.readLine(64).trimmed(); + lastfile.close(); + + machpath = newpath+"/"+serial; + + if (!QDir(machpath).exists()) { + machpath = QString(); + } + } } - if (!lastfile.open(QIODevice::ReadOnly)) { - qDebug() << "PRS1Loader: last.txt exists but I couldn't open it!"; - return false; + if (machpath.isEmpty()) { + QDir dir(newpath); + QStringList dirs = dir.entryList(QDir::NoDotAndDotDot | QDir::Dirs); + if (dirs.size() > 0) { + machpath = dirs[0]; + } } - QString last = lastfile.readLine(64); - last = last.trimmed(); - lastfile.close(); - QFile f(newpath+"/"+last); - if (!f.exists()) { - qDebug() << "in PRS1Loader::Detect():" << last << "does not exist, despite last.txt saying it does"; + return machpath; +} + +void parseModel(MachineInfo & info, QString modelnum) +{ + info.modelnumber = modelnum; + if (!modelnum.endsWith("P")) { + qDebug() << "Weird PRS1 Model number" << modelnum; + } + modelnum.chop(1); + int country = modelnum[modelnum.length() - 1].digitValue(); + modelnum.chop(1); + int ser = modelnum[modelnum.length() - 1].digitValue(); + modelnum.chop(1); + bool ok; + int typ = modelnum.toInt(&ok); + + switch (typ) { + case 4: // cpap + info.model = QObject::tr("RemStar Plus with C-Flex+"); + break; + case 5: // apap + info.model = QObject::tr("RemStar Auto with A-Flex"); + break; + case 6: // bipap + info.model = QObject::tr("RemStar BiPAP Pro with Bi-Flex"); + break; + case 7: // bipap auto + info.model = QObject::tr("RemStar BiPAP Auto with Bi-Flex"); + break; + case 9: // asv + info.model = QObject::tr("BiPAP autoSV Advanced"); + break; + case 10: // Avaps + info.model = QObject::tr("BiPAP AVAPS"); + break; + default: + info.model = QObject::tr("Unknown Model"); + } + + switch (ser) { + case 5: + info.series = QObject::tr("System One"); + break; + case 6: + info.series = QObject::tr("System One (60 Series)"); + break; + default: + info.series = QObject::tr("unknown"); + break; + + } + switch (country) { + case '0': + break; + case '1': + break; + default: + break; + } +} + +bool PRS1Loader::PeekProperties(MachineInfo & info, QString filename) +{ + QFile f(filename); + if (!f.open(QFile::ReadOnly)) { return false; } - // newpath is a valid path + QTextStream in(&f); + do { + QString line = in.readLine(); + QStringList pair = line.split("="); + + if (pair[0].compare("ModelNumber", Qt::CaseInsensitive) == 0) { + QString modelnum = pair[1]; + parseModel(info, modelnum); + } + } while (!in.atEnd()); return true; } + +MachineInfo PRS1Loader::PeekInfo(const QString & path) +{ + QString newpath = checkDir(path); + if (newpath.isEmpty()) + return MachineInfo(); + + MachineInfo info = newInfo(); + info.serial = newpath.section("/", -1); + PeekProperties(info, newpath+"/properties.txt"); + return info; +} + + int PRS1Loader::Open(QString path) { QString newpath; @@ -216,9 +327,7 @@ int PRS1Loader::Open(QString path) QFileInfo fi = flist.at(i); QString filename = fi.fileName(); - if ((filename[0] == 'P') && (isdigit(filename[1])) && (isdigit(filename[2]))) { - SerialNumbers.push_back(filename); - } else if (isdigit(filename[0]) && isdigit(filename[1])) { + if (fi.isDir() && (filename.size() > 4) && (isdigit(filename[1])) && (isdigit(filename[2]))) { SerialNumbers.push_back(filename); } else if (filename.toLower() == "last.txt") { // last.txt points to the current serial number QString file = fi.canonicalFilePath(); @@ -302,12 +411,12 @@ bool PRS1Loader::ParseProperties(Machine *m, QString filename) if (value == s) { continue; } - if (key.toLower() == "serialnumber") { + if (key.contains("serialnumber",Qt::CaseInsensitive)) { info.serial = value; - } else if (key.toLower() == "modelnumber") { - info.modelnumber = value; + } else if (key.contains("modelnumber",Qt::CaseInsensitive)) { + parseModel(info, value); } else { - if (key.toLower() == "producttype") { + if (key.contains("producttype", Qt::CaseInsensitive)) { int i = value.toInt(&ok, 16); if (ok) { @@ -344,11 +453,6 @@ int PRS1Loader::OpenMachine(Machine *m, QString path) if (!dir.exists() || (!dir.isReadable())) { return 0; } - QString backupPath = m->getBackupPath() + path.section("/", -2); - - if (QDir::cleanPath(path).compare(QDir::cleanPath(backupPath)) != 0) { - copyPath(path, backupPath); - } dir.setFilter(QDir::NoDotAndDotDot | QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoSymLinks); dir.setSorting(QDir::Name); @@ -360,21 +464,35 @@ int PRS1Loader::OpenMachine(Machine *m, QString path) QStringList paths; + int sessionid_base = 10; + for (int i = 0; i < flist.size(); i++) { QFileInfo fi = flist.at(i); filename = fi.fileName(); - if ((filename[0].toLower() == 'p') && (isdigit(filename[1]))) { - // p0, p1, p2.. etc.. folders contain the session data - paths.push_back(fi.canonicalFilePath()); - } else if ((filename.toLower() == "properties.txt") || (filename.toLower() == "prop.txt")) { + if (fi.isDir()) { + if ((filename[0].toLower() == 'p') && (isdigit(filename[1]))) { + // p0, p1, p2.. etc.. folders contain the session data + paths.push_back(fi.canonicalFilePath()); + } else if (filename.toLower() == "e") { + // Error files.. + // Reminder: I have been given some info about these. should check it over. + } + } else if (filename.compare("properties.txt",Qt::CaseInsensitive) == 0) { + ParseProperties(m, fi.canonicalFilePath()); + } else if (filename.compare("PROP.TXT",Qt::CaseInsensitive) == 0) { + sessionid_base = 16; ParseProperties(m, fi.canonicalFilePath()); - } else if (filename.toLower() == "e") { - // Error files.. - // Reminder: I have been given some info about these. should check it over. } } + QString backupPath = m->getBackupPath() + path.section("/", -2); + + if (QDir::cleanPath(path).compare(QDir::cleanPath(backupPath)) != 0) { + copyPath(path, backupPath); + } + + QString modelstr = m->modelnumber(); if (modelstr.endsWith("P")) @@ -430,7 +548,7 @@ int PRS1Loader::OpenMachine(Machine *m, QString path) } QString session_s = fi.fileName().section(".", 0, -2); - sid = session_s.toInt(&ok); + sid = session_s.toInt(&ok, sessionid_base); if (!ok) { // not a numerical session ID continue; @@ -441,7 +559,7 @@ int PRS1Loader::OpenMachine(Machine *m, QString path) continue; } - if (ext == 5) { + if ((ext == 5) || (ext == 6)) { // Waveform files aren't grouped... so we just want to add the filename for later QHash::iterator it = sesstasks.find(sid); if (it != sesstasks.end()) { @@ -453,8 +571,13 @@ int PRS1Loader::OpenMachine(Machine *m, QString path) queTask(task); } - if (!task->waveform.isEmpty()) continue; - task->waveform = fi.canonicalFilePath(); + if (ext == 5) { + if (!task->wavefile.isEmpty()) continue; + task->wavefile = fi.canonicalFilePath(); + } else if (ext == 6) { + if (!task->oxifile.isEmpty()) continue; + task->oxifile = fi.canonicalFilePath(); + } continue; } @@ -464,6 +587,16 @@ int PRS1Loader::OpenMachine(Machine *m, QString path) for (int i=0; i < Chunks.size(); ++i) { PRS1DataChunk * chunk = Chunks.at(i); + + if (ext <= 1) { + const unsigned char * data = (unsigned char *)chunk->m_data.constData(); + + if (data[0x00] != 0) { + delete chunk; + continue; + } + } + sid = chunk->sessionid; task = nullptr; @@ -500,7 +633,8 @@ int PRS1Loader::OpenMachine(Machine *m, QString path) int tasks = countTasks(); runTasks(p_profile->session->multithreading()); finishAddingSessions(); - return tasks; + + return m->unsupported() ? -1 : tasks; } bool PRS1Import::ParseF5Events() @@ -1138,7 +1272,7 @@ bool PRS1Import::ParseCompliance() session->settings[CPAP_Mode] = (int)MODE_CPAP; EventDataType min_pressure = float(data[0x03]) / 10.0; - EventDataType max_pressure = float(data[0x04]) / 10.0; + // EventDataType max_pressure = float(data[0x04]) / 10.0; session->settings[CPAP_Pressure] = min_pressure; @@ -1638,7 +1772,6 @@ bool PRS1Import::ParseSummary() session->setPhysMax(CPAP_PS, 25); session->setPhysMin(CPAP_PS, 0); - switch (summary->family) { case 0: if (summary->familyVersion == 4) { @@ -1647,7 +1780,8 @@ bool PRS1Import::ParseSummary() return ParseSummaryF0(); } case 3: - return ParseSummaryF3(); + // return ParseSummaryF3(); + break; case 5: if (summary->familyVersion == 0) { return ParseSummaryF5V0(); @@ -1656,7 +1790,12 @@ bool PRS1Import::ParseSummary() } } - // Else machine is unsupported + this->loader->saveMutex.lock(); + if (!mach->unsupported()) { + this->loader->unsupported(mach); + } + this->loader->saveMutex.unlock(); + return false; const unsigned char * data = (unsigned char *)summary->m_data.constData(); @@ -1865,6 +2004,50 @@ bool PRS1Import::ParseEvents() return res; } +bool PRS1Import::ParseOximetery() +{ + int size = oximetery.size(); + + for (int i=0; i < size; ++i) { + PRS1DataChunk * oxi = oximetery.at(i); + int num = oxi->waveformInfo.size(); + + int size = oxi->m_data.size(); + if (size == 0) { + continue; + } + quint64 ti = quint64(oxi->timestamp) * 1000L; + qint64 dur = qint64(oxi->duration) * 1000L; + + if (num > 1) { + // Process interleaved samples + QVector data; + data.resize(num); + + int pos = 0; + do { + for (int n=0; n < num; n++) { + int interleave = oxi->waveformInfo.at(n).interleave; + data[n].append(oxi->m_data.mid(pos, interleave)); + pos += interleave; + } + } while (pos < size); + + if (data[0].size() > 0) { + EventList * pulse = session->AddEventList(OXI_Pulse, EVL_Waveform, 1.0, 0.0, 0.0, 0.0, dur / data[0].size()); + pulse->AddWaveform(ti, (unsigned char *)data[0].data(), data[0].size(), dur); + } + + if (data[1].size() > 0) { + EventList * spo2 = session->AddEventList(OXI_SPO2, EVL_Waveform, 1.0, 0.0, 0.0, 0.0, dur / data[1].size()); + spo2->AddWaveform(ti, (unsigned char *)data[1].data(), data[1].size(), dur); + } + + } + } + return true; +} + bool PRS1Import::ParseWaveforms() { int size = waveforms.size(); @@ -1915,14 +2098,19 @@ bool PRS1Import::ParseWaveforms() void PRS1Import::run() { + if (mach->unsupported()) + return; session = new Session(mach, sessionid); if ((compliance && ParseCompliance()) || (summary && ParseSummary())) { if (event && !ParseEvents()) { } - waveforms = loader->ParseFile(waveform); + waveforms = loader->ParseFile(wavefile); ParseWaveforms(); + oximetery = loader->ParseFile(oxifile); + ParseOximetery(); + if (session->first() > 0) { if (session->last() < session->first()) { // if last isn't set, duration couldn't be gained from summary, parsing events or waveforms.. @@ -2012,7 +2200,7 @@ QList PRS1Loader::ParseFile(QString path) && (lastchunk->htype != chunk->htype)) { QByteArray junk = f.read(lastblocksize - 16); - + Q_UNUSED(junk) if (lastchunk->ext == 5) { // The data is random crap // lastchunk->m_data.append(junk.mid(lastheadersize-16)); @@ -2032,7 +2220,7 @@ QList PRS1Loader::ParseFile(QString path) ////////////////////////////////////////////////////////// // Waveform Header ////////////////////////////////////////////////////////// - if (chunk->ext == 5) { + if ((chunk->ext == 5) || (chunk->ext == 6)) { // Get extra 8 bytes in waveform header. QByteArray extra = f.read(4); if (extra.size() != 4) { @@ -2107,7 +2295,7 @@ QList PRS1Loader::ParseFile(QString path) } #endif - if (chunk->ext == 5) { + if ((chunk->ext == 5) || (chunk->ext == 6)){ if (lastchunk != nullptr) { Q_ASSERT(lastchunk->sessionid == chunk->sessionid); diff --git a/sleepyhead/SleepLib/loader_plugins/prs1_loader.h b/sleepyhead/SleepLib/loader_plugins/prs1_loader.h index 3571433e..e1418f9f 100644 --- a/sleepyhead/SleepLib/loader_plugins/prs1_loader.h +++ b/sleepyhead/SleepLib/loader_plugins/prs1_loader.h @@ -109,13 +109,17 @@ public: PRS1DataChunk * summary; PRS1DataChunk * event; QList waveforms; + QList oximetery; - QString waveform; + QString wavefile; + QString oxifile; bool ParseCompliance(); bool ParseSummary(); bool ParseEvents(); bool ParseWaveforms(); + bool ParseOximetery(); + bool ParseSummaryF0(); bool ParseSummaryF0V4(); @@ -148,9 +152,15 @@ class PRS1Loader : public CPAPLoader PRS1Loader(); virtual ~PRS1Loader(); + QString checkDir(const QString & path); + bool PeekProperties(MachineInfo & info, QString path); + + //! \brief Detect if the given path contains a valid Folder structure virtual bool Detect(const QString & path); + virtual MachineInfo PeekInfo(const QString & path); + //! \brief Scans directory path for valid PRS1 signature virtual int Open(QString path); diff --git a/sleepyhead/SleepLib/machine.cpp b/sleepyhead/SleepLib/machine.cpp index d4adb7f2..12159020 100644 --- a/sleepyhead/SleepLib/machine.cpp +++ b/sleepyhead/SleepLib/machine.cpp @@ -43,6 +43,7 @@ Machine::Machine(MachineID id) { day.clear(); highest_sessionid = 0; + m_unsupported = false; if (!id) { srand(time(nullptr)); @@ -79,8 +80,15 @@ const quint16 sessinfo_version = 1; bool Machine::saveSessionInfo() { - QFile file(getDataPath() + "Sessions.info"); - file.open(QFile::WriteOnly); + if (info.type == MT_JOURNAL) return false; + + qDebug() << "Saving" << info.brand << "session info" << info.loadername; + QString filename = getDataPath() + "Sessions.info"; + QFile file(filename); + if (!file.open(QFile::WriteOnly)) { + qDebug() << "Couldn't open" << filename << "for writing"; + return false; + } QDataStream out(&file); out.setByteOrder(QDataStream::LittleEndian); @@ -99,12 +107,19 @@ bool Machine::saveSessionInfo() Session * sess = s.value(); out << (quint32) sess->session(); out << (bool)(sess->enabled()); + + //out << sess->m_availableChannels; } + qDebug() << "Done Saving" << info.brand << "session info"; + return true; } bool Machine::loadSessionInfo() { + if (info.type == MT_JOURNAL) + return true; + QHash::iterator s; QFile file(getDataPath() + "Sessions.info"); if (!file.open(QFile::ReadOnly)) { @@ -146,12 +161,20 @@ bool Machine::loadSessionInfo() for (int i=0; i< size; ++i) { in >> sid; in >> b; +// QList avail_channels; +// if (version >= 2) { +// in >> avail_channels; +// } + s = sessionlist.find(sid); if (s != sessionlist.end()) { Session * sess = s.value(); sess->setEnabled(b); +// if (version >= 2) { +// sess->m_availableChannels = avail_channels; +// } } } return true; @@ -846,6 +869,7 @@ bool Machine::hasModifiedSessions() } const QString summaryFileName = "Summaries.xml"; +const int summaryxml_version=1; bool Machine::LoadSummary(QProgressBar * progress) { @@ -853,7 +877,7 @@ bool Machine::LoadSummary(QProgressBar * progress) time.start(); qDebug() << "Loading Summaries"; - QString filename = getDataPath() + summaryFileName; + QString filename = getDataPath() + summaryFileName + ".gz"; QDomDocument doc; QFile file(filename); @@ -864,9 +888,9 @@ bool Machine::LoadSummary(QProgressBar * progress) return false; } - QByteArray data=file.readAll(); + QByteArray data = file.readAll(); - QByteArray uncompressed = qUncompress(data); + QByteArray uncompressed = gUncompress(data); QString errorMsg; int errorLine; @@ -879,8 +903,18 @@ bool Machine::LoadSummary(QProgressBar * progress) file.close(); - QDomElement root = doc.documentElement(); + + if (root.tagName().compare("sessions", Qt::CaseInsensitive) != 0) { + qDebug() << "Summaries cache messed up, recreating..."; + return false; + } + bool ok; + int version = root.attribute("version", "").toInt(&ok); + if (!ok || (version != summaryxml_version)) { + qDebug() << "Summaries cache outdated, recreating..."; + return false; + } QDomNode node; bool s_ok; @@ -906,6 +940,37 @@ bool Machine::LoadSummary(QProgressBar * progress) sess->setEnabled(enabled); sess->setSummaryOnly(!events); + if (e.hasChildNodes()) { + QList available_channels; + QList available_settings; + + QDomElement chans = e.firstChildElement("channels"); + if (chans.isElement()) { + QDomNode node = chans.firstChild(); + QString txt = node.nodeValue(); + QStringList channels = txt.split(","); + for (int i=0; im_availableChannels = available_channels; + + QDomElement sete = e.firstChildElement("settings"); + if (sete.isElement()) { + QString sets = sete.firstChild().nodeValue(); + QStringList settings = sets.split(","); + for (int i=0; im_availableSettings = available_settings; + } + + sess_order[first] = sess; } } @@ -935,11 +1000,9 @@ bool Machine::LoadSummary(QProgressBar * progress) return true; } -const int summaryxml_version=0; - bool Machine::SaveSummary() { - qDebug() << "Saving Summaries"; + qDebug() << "Saving" << info.brand << info.model << "Summaries"; QString filename = getDataPath() + summaryFileName; QDomDocument doc("SleepyHeadSessionIndex"); @@ -967,18 +1030,49 @@ bool Machine::SaveSummary() el.setAttribute("last", sess->realLast()); el.setAttribute("enabled", sess->enabled() ? "1" : "0"); el.setAttribute("events", sess->summaryOnly() ? "0" : "1"); + + QHash >::iterator ev; + QHash >::iterator ev_end = sess->eventlist.end(); + QStringList chanlist; + for (ev = sess->eventlist.begin(); ev != ev_end; ++ev) { + chanlist.append(QString::number(ev.key(), 16)); + } + if (chanlist.size() == 0) { + for (int i=0; im_availableChannels.size(); i++) { + ChannelID code = sess->m_availableChannels.at(i); + chanlist.append(QString::number(code, 16)); + } + } + + QDomElement chans = doc.createElement("channels"); + chans.appendChild(doc.createTextNode(chanlist.join(","))); + el.appendChild(chans); + + chanlist.clear(); + QHash::iterator si; + QHash::iterator set_end = sess->settings.end(); + for (si = sess->settings.begin(); si != set_end; ++si) { + chanlist.append(QString::number(si.key(), 16)); + } + QDomElement settings = doc.createElement("settings"); + settings.appendChild(doc.createTextNode(chanlist.join(","))); + el.appendChild(settings); + root.appendChild(el); if (sess->IsChanged()) sess->StoreSummary(); } - QFile file(filename); - file.open(QIODevice::WriteOnly); + QString xmltext; + QTextStream ts(&xmltext); + doc.save(ts, 1); - QByteArray ba = qCompress(doc.toByteArray()); - file.write(ba); + QByteArray data = gCompress(xmltext.toUtf8()); - file.close(); + QFile file(filename + ".gz"); + + file.open(QFile::WriteOnly); + file.write(data); return true; } diff --git a/sleepyhead/SleepLib/machine.h b/sleepyhead/SleepLib/machine.h index c0f0d568..5ba7dc49 100644 --- a/sleepyhead/SleepLib/machine.h +++ b/sleepyhead/SleepLib/machine.h @@ -173,6 +173,11 @@ class Machine QMutex listMutex; QSemaphore *savelistSem; + bool m_unsupported; + + bool unsupported() { return m_unsupported; } + void setUnsupported(bool b) { m_unsupported = b; } + void lockSaveMutex() { listMutex.lock(); } void unlockSaveMutex() { listMutex.unlock(); } void skipSaveTask() { lockSaveMutex(); m_donetasks++; unlockSaveMutex(); } diff --git a/sleepyhead/SleepLib/machine_loader.h b/sleepyhead/SleepLib/machine_loader.h index 7d5199d2..2ab2b126 100644 --- a/sleepyhead/SleepLib/machine_loader.h +++ b/sleepyhead/SleepLib/machine_loader.h @@ -59,6 +59,12 @@ class MachineLoader: public QObject virtual const QString &loaderName() = 0; inline MachineType type() { return m_type; } + void unsupported(Machine * m) { + Q_ASSERT(m != nullptr); + m->setUnsupported(true); + emit machineUnsupported(m); + } + void queTask(ImportTask * task); void addSession(Session * sess) @@ -104,8 +110,9 @@ class MachineLoader: public QObject signals: void updateProgress(int cnt, int total); + void machineUnsupported(Machine *); - protected: +protected: //! \brief Contains a list of Machine records known by this loader QList m_machlist; diff --git a/sleepyhead/SleepLib/schema.cpp b/sleepyhead/SleepLib/schema.cpp index ab317d35..a554347a 100644 --- a/sleepyhead/SleepLib/schema.cpp +++ b/sleepyhead/SleepLib/schema.cpp @@ -860,6 +860,7 @@ void ChannelList::add(QString group, Channel *chan) bool ChannelList::Save(QString filename) { + qDebug() << "Saving Channels.xml"; if (filename.isEmpty()) { filename = p_profile->Get("{DataFolder}/") + "channels.xml"; } @@ -924,6 +925,7 @@ bool ChannelList::Save(QString filename) ts << doc.toString(); file.close(); + return true; } diff --git a/sleepyhead/SleepLib/session.cpp b/sleepyhead/SleepLib/session.cpp index 2502b793..0242a893 100644 --- a/sleepyhead/SleepLib/session.cpp +++ b/sleepyhead/SleepLib/session.cpp @@ -23,7 +23,7 @@ using namespace std; // 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 = 16; +const quint16 summary_version = 17; const quint16 events_version = 10; Session::Session(Machine *m, SessionID session) @@ -164,7 +164,7 @@ bool Session::Store(QString path) return a; } -QDataStream & operator<<(QDataStream & out, const Session & session) +/*QDataStream & operator<<(QDataStream & out, const Session & session) { session.StoreSummaryData(out); return out; @@ -201,6 +201,7 @@ void Session::StoreSummaryData(QDataStream & out) const out << m_gain; out << m_availableChannels; + out << m_timeAboveTheshold; out << m_upperThreshold; out << m_timeBelowTheshold; @@ -259,7 +260,7 @@ void Session::LoadSummaryData(QDataStream & in) in >> s_summaryOnly; s_enabled = 1; -} +} */ QDataStream & operator>>(QDataStream & in, SessionSlice & slice) { @@ -593,7 +594,14 @@ bool Session::LoadSummary() in >> s_summaryOnly; } - if (version >= 16) { + if (version == 16) { + QList slices; + in >> slices; + m_slices.clear(); + for (int i=0;i= 17) { in >> m_slices; } } diff --git a/sleepyhead/SleepLib/session.h b/sleepyhead/SleepLib/session.h index e1d24c1b..a072a5a0 100644 --- a/sleepyhead/SleepLib/session.h +++ b/sleepyhead/SleepLib/session.h @@ -73,16 +73,16 @@ class Session //! \brief Writes the Sessions Summary Indexes to filename, in SleepLibs custom data format. bool StoreSummary(); - //! \brief Save the Sessions Summary Indexes to the stream - void StoreSummaryData(QDataStream & out) const; +// //! \brief Save the Sessions Summary Indexes to the stream +// void StoreSummaryData(QDataStream & out) const; //! \brief Writes the Sessions EventLists to filename, in SleepLibs custom data format. bool StoreEvents(); //bool Load(QString path); - //! \brief Loads the Sessions Summary Indexes from stream - void LoadSummaryData(QDataStream & in); +// //! \brief Loads the Sessions Summary Indexes from stream +// void LoadSummaryData(QDataStream & in); //! \brief Loads the Sessions Summary Indexes from filename, from SleepLibs custom data format. bool LoadSummary(); @@ -238,8 +238,9 @@ class Session QHash m_timeAboveTheshold; QList m_availableChannels; + QList m_availableSettings; - QList m_slices; + QVector m_slices; //! \brief Generates sum and time data for each distinct value in 'code' events.. void updateCountSummary(ChannelID code); diff --git a/sleepyhead/daily.cpp b/sleepyhead/daily.cpp index 2152274c..b0e18534 100644 --- a/sleepyhead/daily.cpp +++ b/sleepyhead/daily.cpp @@ -184,10 +184,10 @@ Daily::Daily(QWidget *parent,gGraphView * shared) graphlist[schema::channel[code].code()] = new gGraph(schema::channel[code].code(), GraphView, schema::channel[code].label(), channelInfo(code), default_height); } - int oxigrp=p_profile->ExistsAndTrue("SyncOximetry") ? 0 : 1; // Contemplating killing this setting... + //int oxigrp=p_profile->ExistsAndTrue("SyncOximetry") ? 0 : 1; // Contemplating killing this setting... for (int i=0; i < oxisize; ++i) { ChannelID code = oxicodes[i]; - graphlist[schema::channel[code].code()] = new gGraph(schema::channel[code].code(), GraphView, schema::channel[code].label(), channelInfo(code), default_height, oxigrp); + graphlist[schema::channel[code].code()] = new gGraph(schema::channel[code].code(), GraphView, schema::channel[code].label(), channelInfo(code), default_height); } if (p_profile->general->calculateRDI()) { @@ -1123,8 +1123,8 @@ QString Daily::getCPAPInformation(Day * day) html="\n"; - html+="
"+info.series+" "+info.model+""; - QString tooltip=(info.brand+"\n"+info.series+" "+info.modelnumber+"\n"+info.serial); + html+="
"+info.brand + " "+ info.series+"
"+info.model+""; + QString tooltip=("Model "+info.modelnumber+" - "+info.serial); tooltip=tooltip.replace(" "," "); html+=tooltip; diff --git a/sleepyhead/icons/prs1_60s.png b/sleepyhead/icons/prs1_60s.png new file mode 100644 index 0000000000000000000000000000000000000000..88274aeeb41a10775c93c94c60ba99750a1485ff GIT binary patch literal 81511 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 + QList loaders = GetLoaders(); + for (int i=0; igraphView()); @@ -860,10 +865,16 @@ QList MainWindow::detectCPAPCards() progress.setVisible(true); popup.show(); QApplication::processEvents(); + QString lastpath = (*p_profile)[STR_PREF_LastCPAPPath].toString(); do { // Rescan in case card inserted QStringList AutoScannerPaths = getDriveList(); + //AutoScannerPaths.push_back(lastpath); + + if (!AutoScannerPaths.contains(lastpath)) { + AutoScannerPaths.append(lastpath); + } Q_FOREACH(const QString &path, AutoScannerPaths) { // Scan through available machine loaders and test if this folder contains valid folder structure @@ -883,6 +894,7 @@ QList MainWindow::detectCPAPCards() // needs a slight delay here QThread::msleep(200); } while (detectedCards.size() == 0); + popup.hide(); popup.disconnect(&skipbtn, SIGNAL(clicked()), &popup, SLOT(hide())); @@ -934,7 +946,7 @@ void MainWindow::on_action_Import_Data_triggered() mbox.setDefaultButton(QMessageBox::Yes); mbox.setButtonText(QMessageBox::No, tr("Specify")); - QPixmap pixmap = datacards[0].loader->getPixmap(datacards[0].loader->PeekInfo(datacards[0].path).series); + QPixmap pixmap = datacards[0].loader->getPixmap(datacards[0].loader->PeekInfo(datacards[0].path).series).scaled(64,64); //QPixmap pixmap = QPixmap(getCPAPPixmap(datacards[0].loader->loaderName())).scaled(64,64); mbox.setIconPixmap(pixmap); @@ -1051,7 +1063,7 @@ void MainWindow::on_action_Import_Data_triggered() if (c >= 0) { // goodlocations.push_back(dir); - QDir d(dir.section("/",0,-2)); + QDir d(dir.section("/",0,-1)); (*p_profile)[STR_PREF_LastCPAPPath] = d.absolutePath(); } @@ -2308,6 +2320,12 @@ void MainWindow::FreeSessions() } while (date >= first); } +void MainWindow::MachineUnsupported(Machine * m) +{ + Q_ASSERT(m != nullptr); + QMessageBox::information(this, STR_MessageBox_Error, QObject::tr("Sorry, your %1 %2 machine is not currently supported.").arg(m->brand()).arg(m->model()), QMessageBox::Ok); +} + void MainWindow::doReprocessEvents() { if (p_profile->countDays(MT_CPAP, p_profile->FirstDay(), p_profile->LastDay()) == 0) { diff --git a/sleepyhead/mainwindow.h b/sleepyhead/mainwindow.h index 7d073476..01e6a70a 100644 --- a/sleepyhead/mainwindow.h +++ b/sleepyhead/mainwindow.h @@ -92,6 +92,7 @@ class MainWindow : public QMainWindow //! \brief Start the automatic update checker process void CheckForUpdates(); + /*! \fn Notify(QString s,int ms=5000, QString title="SleepyHead v"+VersionString()); \brief Pops up a message box near the system tray \param QString string @@ -144,6 +145,9 @@ class MainWindow : public QMainWindow //! \brief Recalculate all event summaries and flags void doReprocessEvents(); + void MachineUnsupported(Machine * m); + + protected: virtual void closeEvent(QCloseEvent *); virtual void keyPressEvent(QKeyEvent *event); diff --git a/sleepyhead/mainwindow.ui b/sleepyhead/mainwindow.ui index c4366c11..e0b17f98 100644 --- a/sleepyhead/mainwindow.ui +++ b/sleepyhead/mainwindow.ui @@ -3132,12 +3132,20 @@ border-radius: 10px; &File + + + Exp&ort Data + + + + + - + @@ -3366,11 +3374,6 @@ border-radius: 10px; &Edit Profile - - - Exp&ort Data - - Online Users &Guide @@ -3521,6 +3524,16 @@ border-radius: 10px; Show Performance Information + + + Export as CSV + + + + + Export for Review + + diff --git a/sleepyhead/oximeterimport.cpp b/sleepyhead/oximeterimport.cpp index a91ad724..da00760c 100644 --- a/sleepyhead/oximeterimport.cpp +++ b/sleepyhead/oximeterimport.cpp @@ -993,6 +993,7 @@ void OximeterImport::on_saveButton_clicked() mach->AddSession(session); mach->Save(); mach->SaveSummary(); + p_profile->StoreMachines(); mainwin->getDaily()->LoadDate(mainwin->getDaily()->getDate()); mainwin->getOverview()->ReloadGraphs(); diff --git a/sleepyhead/sessionbar.cpp b/sleepyhead/sessionbar.cpp index bc0a5e7c..d71880c7 100644 --- a/sleepyhead/sessionbar.cpp +++ b/sleepyhead/sessionbar.cpp @@ -48,7 +48,7 @@ SessionBar::SessionBar(QWidget *parent) : // :QWidget(this) //{ // timer.setParent(this); -// QList::const_iterator i; +// QVector::const_iterator i; // for (i=copy.segments.begin();i!=copy.segments.end();++i) { // segments.push_back(*i); // } @@ -60,7 +60,7 @@ SessionBar::~SessionBar() void SessionBar::updateTimer() { if (!underMouse()) { - QList::iterator i; + QVector::iterator i; for (i = segments.begin(); i != segments.end(); ++i) { (*i).highlight = false; @@ -78,7 +78,7 @@ SegType SessionBar::min() return 0; } - QList::iterator i = segments.begin(); + QVector::iterator i = segments.begin(); SegType min = (*i).session->first(); i++; @@ -101,7 +101,7 @@ SegType SessionBar::max() return 0; } - QList::iterator i = segments.begin(); + QVector::iterator i = segments.begin(); SegType max = (*i).session->last(); i++; qint64 val; @@ -132,7 +132,7 @@ void SessionBar::mousePressEvent(QMouseEvent *ev) double px = double(width() ) / double(total); double sx, ex; - QList::iterator i; + QVector::iterator i; int cnt = 0; @@ -174,7 +174,7 @@ void SessionBar::mouseMoveEvent(QMouseEvent *ev) double px = double(width() - 5) / double(total); double sx, ex; - QList::iterator i; + QVector::iterator i; for (i = segments.begin(); i != segments.end(); ++i) { SBSeg &seg = *i; @@ -216,7 +216,7 @@ void SessionBar::paintEvent(QPaintEvent *) double px = double(width() - 5) / double(total); double sx, ex; - QList::iterator i; + QVector::iterator i; QRect selectRect; int cnt = 0; diff --git a/sleepyhead/sessionbar.h b/sleepyhead/sessionbar.h index 67f85aeb..96297960 100644 --- a/sleepyhead/sessionbar.h +++ b/sleepyhead/sessionbar.h @@ -9,7 +9,7 @@ #ifndef SESSIONBAR_H #define SESSIONBAR_H -#include +#include #include #include #include @@ -60,7 +60,7 @@ class SessionBar : public QWidget SegType min(); SegType max(); - QList segments; + QVector segments; QTimer timer; int m_selectIDX; bool m_selectMode; diff --git a/sleepyhead/statistics.cpp b/sleepyhead/statistics.cpp index aa163003..a399dae9 100644 --- a/sleepyhead/statistics.cpp +++ b/sleepyhead/statistics.cpp @@ -76,6 +76,7 @@ QDataStream & operator<<(QDataStream & out, const RXItem & rx) out << rx.machine->loaderName(); out << rx.machine->serial(); + out << rx.relief; out << rx.mode; out << rx.pressure;