Merge branch 'master' into vAuto-Settings

This commit is contained in:
Phil Olynyk 2022-11-05 16:31:41 -04:00
commit 394f733c4b
58 changed files with 43019 additions and 29767 deletions

View File

@ -30,7 +30,7 @@
<p>
<b>Developers</b>
<br>
Phil Olynyk (pholynyk) (<i>Lead Developer</i>), GuyScharf, sawinglogz</p>
Phil Olynyk (pholynyk) (<i>Lead Developer</i>), GuyScharf, sawinglogz, Ray Elliott (LoudSnorer), untoutseul05</p>
<p>
<b>Reporters</b>
<br>AlanE, BrandonA, Crimson Nape, foxfire, Heyns, jeremieb, jaswilliams, palerider, patl</p>
@ -41,11 +41,11 @@
unidee</p>
<p>
<b>Advisors</b>
<br>aviB, SkepticDoc, Sleeprider, SleepyProgrammer, srlevine1, LunaFerret, harre, mdhamptom, mitchcampbell, rtannerf</p>
<br>aviB, SkepticDoc, Sleeprider, SleepyProgrammer, srlevine1, LunaFerret, harre, mdhamptom, mitchcampbell, rhashimoto, rtannerf</p>
<p>
<b>Translators</b>
<br>
Arie Klerk (A KLERK) (<i>Translations Team Coordinator, Dutch</i>), 1st.qwerty (<i>Polish</i>), C Chan (<i>Trad.Chinese)</i>, Caniss (<i>Swedish</i>), delta (<i>Romanian</i>), dolceitalia (<i>Italian</i>), drmaestro (<i>Turkish</i>), drol (<i>French</i>), FaureCourtet (<i>French</i>), GregK (<i>Russian, Hebrew</i>), hearsay73 (<i>Filipino</i>), Heyns (<i>Afrikaans</i>), Hypoxic (<i>Greek</i>), jaswilliams (<i>British</i>), johanh (<i>Finnish</i>), k2boys (<i>Korean</i>), Lazer1234 (<i>Swedish</i>), Mac_Sheepcounter (<i>German</i>), mazingas65 (<i>Italian</i>), Ppja (<i>Spanish</i>), pstrjds (<i>Bulgarian</i>), refurbished (<i>Polish</i>), Ristraus (<i>Brazilian Portugese</i>), rlabs (<i>Russian</i>), ShaunBlake (<i>British</i>), steffenreitz (<i>German</i>), tolnaiz (<i>Hungarian</i>), unidee (<i>Finnish</i>), untoutseul05 (<i>French</i>), yrnkrn (<i>Hebrew</i>), N-A-N (<i>Thai</i>). <br>
Arie Klerk (A KLERK) (<i>Translations Team Coordinator, Dutch</i>), 1st.qwerty (<i>Polish</i>), C Chan (<i>Trad.Chinese)</i>, delta (<i>Romanian</i>), dolceitalia (<i>Italian</i>), drmaestro (<i>Turkish</i>), drol (<i>French</i>), FaureCourtet (<i>French</i>), GregK (<i>Russian, Hebrew</i>), hearsay73 (<i>Filipino</i>), Heyns (<i>Afrikaans</i>), Hypoxic (<i>Greek</i>), k2boys (<i>Korean</i>), Lazer1234 (<i>Swedish</i>), mazingas65 (<i>Italian</i>), Ppja (<i>Spanish</i>), pstrjds (<i>Bulgarian</i>), refurbished (<i>Polish</i>), Ristraus (<i>Portugese and Brazilian Portugese</i>), rlabs (<i>Russian</i>), ShaunBlake (<i>British</i>), steffenreitz (<i>German</i>), tolnaiz (<i>Hungarian</i>), unidee (<i>Finnish</i>), untoutseul05 (<i>French</i>), yrnkrn (<i>Hebrew</i>), N-A-N (<i>Thai</i>). <br>
<b>Thank you all very much for your continuous effort!</b></p>
<p>
<b>OSCAR is always looking for help: programmers, testers, or translators. If you are interested, please PM &#39;Gideon&#39; on the Apnea Board Forum.</b>

View File

@ -11,46 +11,40 @@
<b>This page in other languages:</b>
<br><a href=http://www.apneaboard.com/wiki/index.php/OSCAR_Release_Notes>http://www.apneaboard.com/wiki/index.php/OSCAR_Release_Notes</a></p>
<p>
<b>Changes and fixes in OSCAR v1.3.5-alpha.X</b>
<b>Changes and fixes in OSCAR v1.4.1-xxxx</b>
<br>Portions of OSCAR are © 2019-2022 by
<i>The OSCAR Team</i></p>
<ul>
<li>[new] Additional Philips Respironics devices tested and fully supported:
<li>[fix] Allow Graph and Event combo boxes to remain open after changes.<li>
<li>[fix] Overview display of ResMed Oximeter events now works.<li>
</ul>
<p>
<b>Changes and fixes in OSCAR v1.4.0</b>
<br>Portions of OSCAR are © 2019-2022 by
<i>The OSCAR Team</i></p>
<ul>
<li>[new] Support for Philips Respironics DreamStation 2:
<ul>
<li>DreamStation 2 CPAP (410X150C)</li>
<li>DreamStation 2 Auto CPAP Advanced (520X130C)</li>
<li>DreamStation 2 Advanced CPAP (420X150C)</li>
<li>DreamStation 2 Auto CPAP Advanced (520X110C, 520X130C, 520X150C)</li>
<li>DreamStation 2 Auto CPAP Advanced with P-Flex (521X120C, 521X140C)</li>
</ul>
</li>
<li>[new] Additional Philips Respironics devices tested and fully supported:
<ul>
<li>BiPAP Auto (System One 60 Series) (761P)</li>
<li>BiPAP autoSV Advanced 30 (System One 60 Series) (961TCA)</li>
<li>REMstar Auto (System One) (552P)</li>
</ul>
</li>
<li>[new] For AutoSet 11, two models were added to the tested list: 39421 and 39485.</li>
<li>[fix] Added support for pressure pulse, CA, and VS on BiPAP autoSV Advanced 30 (System One 60 Series) (960T).</li>
<li>[fix] Fixed pressure settings scale on BiPAP autoSV Advanced 30 (System One 60 Series) (960T).</li>
</ul>
<p>
<b>Changes and fixes in OSCAR v1.3.5-alpha.2</b>
<br>Portions of OSCAR are © 2019-2022 by
<i>The OSCAR Team</i></p>
<ul>
<li>[new] Additional Philips Respironics devices tested and fully supported:
<ul>
<li>DreamStation 2 Auto CPAP Advanced with P-Flex (521X120C)</li>
</ul>
</li>
<li>[fix] For all ResMed devices, square plot (no smoothing) has been forced on all 2 second pressure graphs.</li>
<li>[fix] File Export Sessions now exports statistics session data properly.</li>
<li>[fix] Fixed a rare crash on import when encountering corrupted Philips Respironics directories.</li>
</ul>
<p>
<b>Changes and fixes in OSCAR v1.3.5-alpha.0</b>
<br>Portions of OSCAR are © 2019-2022 by
<i>The OSCAR Team</i></p>
<ul>
<li>[new] Additional Philips Respironics devices tested and fully supported:
<ul>
<li>DreamStation 2 Auto CPAP Advanced (520X110C, 520X150C)</li>
</ul>
</li>
<li>[new] Test Mantis integration.</li>
<li>[fix] Fixed an incorrect warning message when importing some CheckMe O2 Max data.</li>
</ul>
<p>
<b>Changes and fixes in OSCAR v1.3.1</b>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

9260
Translations/Japanese.ja.ts Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ja_JP">
<context>
<name>QShortcut</name>
<message>
<source>No</source>
<translation></translation>
</message>
<message>
<source>Yes</source>
<translation></translation>
</message>
</context>
<context>
<name>QPlatformTheme</name>
<message>
<source>OK</source>
<translation></translation>
</message>
<message>
<source>&amp;No</source>
<translation></translation>
</message>
<message>
<source>&amp;Yes</source>
<translation></translation>
</message>
<message>
<source>Help</source>
<translation></translation>
</message>
<message>
<source>Open</source>
<translation></translation>
</message>
<message>
<source>Save</source>
<translation></translation>
</message>
<message>
<source>Abort</source>
<translation></translation>
</message>
<message>
<source>Apply</source>
<translation></translation>
</message>
<message>
<source>Close</source>
<translation></translation>
</message>
<message>
<source>Reset</source>
<translation></translation>
</message>
<message>
<source>Retry</source>
<translation></translation>
</message>
<message>
<source>Restore Defaults</source>
<translation></translation>
</message>
<message>
<source>Cancel</source>
<translation></translation>
</message>
<message>
<source>Ignore</source>
<translation></translation>
</message>
<message>
<source>N&amp;o to All</source>
<translation></translation>
</message>
<message>
<source>Save All</source>
<translation></translation>
</message>
<message>
<source>Discard</source>
<translation></translation>
</message>
<message>
<source>Yes to &amp;All</source>
<translation></translation>
</message>
</context>
</TS>

View File

@ -116,6 +116,7 @@ void gToolTip::display(QString text, int x, int y, ToolTipAlignment align, int t
m_alignment = align;
m_text = text;
// for testing add mouse position to tooltip. QString("%1:(%2,%3)").arg(text).arg(m_graphview->currentMousePos().x()).arg(m_graphview->currentMousePos().y());
m_visible = true;
// TODO: split multiline here
//calcSize(m_text,tw,th);
@ -139,53 +140,62 @@ void gToolTip::cancel()
timer->stop();
}
QRect gToolTip::calculateRect(QPainter &painter)
QRect gToolTip::calculateRect(QPainter &painter)
{
int x = m_pos.x();
int y = m_pos.y();
// calcualte size of tooltip
QRect rect(x, y, 0, 0);
painter.setFont(*m_font);
rect = painter.boundingRect(rect, Qt::AlignCenter, m_text);
// Set preffered locations
rect.moveTo(m_pos);
// Add borders arround text area
// add space around rectangle horizontilally left & right sides.
int w = rect.width() + m_spacer * 2;
int xx = rect.x() - m_spacer;
if (xx < 0) { xx = 0; }
rect.setLeft(xx);
rect.setTop(rect.y() - 15);
rect.setWidth(w);
int z = rect.x() + rect.width();
// add space around rectangle vertically
int h = rect.height() + m_spacer * 2;
rect.setHeight(h);
if (z > m_graphview->width() - 10) {
rect.setLeft(m_graphview->width() - 2 - rect.width());
rect.setRight(m_graphview->width() - 2);
/*
now must verify that the tooltip must fit inti the display area.
if part of the display can not be displayed (outside the bounding rectangle of the graph then
the tool tip will be moved to fit.
If the tooltip is too big . (does not fit) then preference is giver to the top and left sides.
the following checks are executed in the order.
1) do right side
2) do left side
3) do bottom
4) do top.
these checks are independant of alignment requirements.
*/
// get display area
QRect displayRect = m_graphview->geometry();
int right = displayRect.right() -2; // allow tooltip border to be displayed
int left = displayRect.left();
int top = displayRect.top();
int bottom = displayRect.bottom();
if (rect.right() > right ) {
rect.moveRight(right);
}
if (rect.left() < left ) {
rect.moveLeft(left);
}
if (rect.bottom() > bottom ) {
rect.moveBottom(bottom);
}
if (rect.top() < top ) {
rect.moveTop(top);
}
int h = rect.height();
if (rect.y() < 0) {
rect.setY(0);
rect.setHeight(h);
}
if (m_alignment == TT_AlignRight) {
rect.moveTopRight(m_pos);
if ((x-w) < 0) {
rect.moveLeft(0);
}
} else if (m_alignment == TT_AlignLeft) {
rect.moveTopLeft(m_pos);
}
int bot = rect.bottom() - m_graphview->height();
if (bot > 0) {
rect.setTop(rect.top()-bot);
rect.setBottom(m_graphview->height());
}
return rect;
}

View File

@ -350,6 +350,7 @@ void gSummaryChart::populate(Day * day, int idx)
auto & slices = cache[idx];
float hours = day->hours(m_machtype);
if ((hours==0) && (m_machtype != MT_CPAP)) hours = day->hours();
float base = 0;
for (auto & item : calcitems) {
@ -1323,3 +1324,4 @@ QString gAHIChart::tooltipData(Day *day, int idx)
}
return QString("\n%1: %2").arg(STR_TR_AHI).arg(float(total) / hour,0,'f',2)+txt;
}

View File

@ -283,7 +283,7 @@ QString weightString(float kg, UnitSystem us)
if (us == US_Metric) {
return QString("%1kg").arg(kg, 0, 'f', 2);
} else if (us == US_English) {
int oz = (kg * 1000.0) / (float)ounce_convert;
int oz = (kg * 1000.0) * (float)gram_ounce_convert;
int lb = oz / 16.0;
oz = oz % 16;
return QString("%1lb %2oz").arg(lb, 0, 10).arg(oz);
@ -526,6 +526,7 @@ QString STR_TR_CPAP; // Constant Positive Airway Pressure
QString STR_TR_BIPAP; // Bi-Level Positive Airway Pressure
QString STR_TR_BiLevel; // Another name for BiPAP
QString STR_TR_EPAP; // Expiratory Positive Airway Pressure
QString STR_TR_EEPAP; // End Expiratory Positive Airway Pressure
QString STR_TR_EPAPLo; // Expiratory Positive Airway Pressure, Low
QString STR_TR_EPAPHi; // Expiratory Positive Airway Pressure, High
QString STR_TR_IPAP; // Inspiratory Positive Airway Pressure
@ -735,6 +736,7 @@ void initializeStrings()
STR_TR_BIPAP = QObject::tr("BiPAP"); // Bi-Level Positive Airway Pressure
STR_TR_BiLevel = QObject::tr("Bi-Level"); // Another name for BiPAP
STR_TR_EPAP = QObject::tr("EPAP"); // Expiratory Positive Airway Pressure
STR_TR_EEPAP = QObject::tr("EEPAP"); // Expiratory Positive Airway Pressure
STR_TR_EPAPLo = QObject::tr("Min EPAP"); // Lower Expiratory Positive Airway Pressure
STR_TR_EPAPHi = QObject::tr("Max EPAP"); // Higher Expiratory Positive Airway Pressure
STR_TR_IPAP = QObject::tr("IPAP"); // Inspiratory Positive Airway Pressure

View File

@ -83,6 +83,7 @@ bool operator <(const ValueCount &a, const ValueCount &b);
const float ounce_convert = 28.3495231F; // grams
const float pound_convert = ounce_convert * 16;
const float gram_ounce_convert = 0.0352754; // ounces in a gram
QString weightString(float kg, UnitSystem us = US_Undefined);
@ -162,6 +163,7 @@ const QString STR_MACH_SleepStyle = "SleepStyle";
const QString STR_MACH_MSeries = "MSeries";
const QString STR_MACH_CMS50 = "CMS50";
const QString STR_MACH_ZEO = "Zeo";
const QString STR_MACH_Prisma = "Prisma";
const QString STR_PREF_Language = "Language";
@ -249,6 +251,7 @@ extern QString STR_TR_CPAP; // Constant Positive Airway Pressure
extern QString STR_TR_BIPAP; // Bi-Level Positive Airway Pressure
extern QString STR_TR_BiLevel; // Another name for BiPAP
extern QString STR_TR_EPAP; // Expiratory Positive Airway Pressure
extern QString STR_TR_EEPAP; // Expiratory Positive Airway Pressure
extern QString STR_TR_EPAPLo; // Expiratory Positive Airway Pressure, Low
extern QString STR_TR_EPAPHi; // Expiratory Positive Airway Pressure, High
extern QString STR_TR_IPAP; // Inspiratory Positive Airway Pressure

View File

@ -96,6 +96,20 @@ bool EDFInfo::Open(const QString & name)
return true;
}
bool EDFInfo::Open(const QByteArray &data)
{
fileData = data;
if (fileData.size() <= EDFHeaderSize) {
fileData.clear();;
qDebug() << "EDFInfo::Open() buffer too short";
return false;
}
// TODO AXT
filename = "bytearray";
return true;
}
QDateTime EDFInfo::getStartDT( QString dateTimeStr )
{
// edfHdr.startdate_orig = QDateTime::fromString(QString::fromLatin1(hdrPtr->datetime, 16), "dd.MM.yyHH.mm.ss");
@ -146,14 +160,15 @@ bool EDFInfo::parseHeader( EDFHeaderRaw *hdrPtr )
}
edfHdr.reserved44=QString::fromLatin1(hdrPtr->reserved, 44).trimmed();
edfHdr.num_data_records = QString::fromLatin1(hdrPtr->num_data_records, 8).toLong(&ok);
if ( (! ok) || (edfHdr.num_data_records < 1) ) {
#ifdef EDF_DEBUG
qWarning() << "EDFInfo::Parse() Bad data record count " << filename;
// sleep(1);
#endif
fileData.clear();
return false;
}
// TODO AXT
// if ( (! ok) || (edfHdr.num_data_records < 1) ) {
//#ifdef EDF_DEBUG
// qWarning() << "EDFInfo::Parse() Bad data record count " << filename;
// // sleep(1);
//#endif
// fileData.clear();
// return false;
// }
edfHdr.duration_Seconds = QString::fromLatin1(hdrPtr->dur_data_records, 8).toDouble(&ok);
if (!ok) {
#ifdef EDF_DEBUG
@ -250,6 +265,12 @@ bool EDFInfo::Parse() {
return false;
}
bool ret = ParseSignalData();
fileData.clear();
return ret;
}
bool EDFInfo::ParseSignalData() {
// Now check the file isn't truncated before allocating space for the values
long allocsize = 0;
for (auto & sig : edfsignals) {
@ -265,7 +286,6 @@ bool EDFInfo::Parse() {
fileData.clear();
return false;
}
// allocate the arrays for the signal values
for (auto & sig : edfsignals) {
long samples = sig.sampleCnt * edfHdr.num_data_records;
@ -289,7 +309,7 @@ bool EDFInfo::Parse() {
}
}
}
fileData.clear();
return true;
}

View File

@ -126,9 +126,13 @@ class EDFInfo
virtual ~EDFInfo();
virtual bool Open(const QString & name); //! \brief Open the EDF+ file, and read it's header
virtual bool Open(const QByteArray &data);
virtual bool Parse(); //! \brief Parse the EDF+ file into the EDFheaderQT. Must call Open(..) first.
virtual bool ParseSignalData(); //! \brief Parse the signal data
virtual bool parseHeader( EDFHeaderRaw * hdrPtr ); //! \brief parse just the edf header for duration, etc
virtual EDFSignal * lookupLabel(const QString & name, int index=0); //! \brief Return a ptr to the i'th signal with that name
@ -166,24 +170,27 @@ class EDFInfo
QHash<QString, QList<EDFSignal *> > signalList; //! \brief ResMed sometimes re-uses the SAME signal name
// the following could be private
protected:
//! \brief This is the array of signal descriptors and values
char *signalPtr;
long filesize;
long datasize;
long pos;
bool eof;
//! \brief This is the array holding the EDF file data
QByteArray fileData;
//! \brief Read 16 bit word of data from the EDF+ data stream
qint16 Read16();
private:
QVector<Annotation> ReadAnnotations( const char * data, int charLen ); //! \brief Create an Annotaion vector from the signal values
QString ReadBytes(unsigned n); //! \brief Read n bytes of 8 bit data from the EDF+ data stream
qint16 Read16(); //! \brief Read 16 bit word of data from the EDF+ data stream
//! \brief This is the array holding the EDF file data
QByteArray fileData;
//! \brief The EDF+ files header structure, used as a place holder while processing the text data.
EDFHeaderRaw *hdrPtr;
//! \brief This is the array of signal descriptors and values
char *signalPtr;
long filesize;
long datasize;
long pos;
bool eof;
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,286 @@
/* SleepLib Löwenstein Prisma Loader Header
*
* Copyright (c) 2019-2022 The OSCAR Team
* Copyright (C) 2011-2018 Mark Watkins <mark@jedimark.net>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of the source code
* for more details. */
#ifndef PRISMA_LOADER_H
#define PRISMA_LOADER_H
#include "SleepLib/machine_loader.h"
#include "SleepLib/loader_plugins/edfparser.h"
#include <QDir>
#ifdef UNITTEST_MODE
#define private public
#define protected public
#endif
//********************************************************************************************
/// IMPORTANT!!!
//********************************************************************************************
// Please INCREMENT the following value when making changes to this loaders implementation
// BEFORE making a release
const int prisma_data_version = 1;
//
//********************************************************************************************
const QString prisma_class_name = STR_MACH_Prisma;
//********************************************************************************************
// NOTE: Prisma Smart and Prisma Line devices use distinct parameter id-s, but the correct solution
// would be to transform these, into separate enums / parsers.
enum Prisma_Parameters {
PRISMA_SMART_MODE = 6,
PRISMA_SMART_PRESSURE = 9,
PRISMA_SMART_PRESSURE_MAX = 10,
PRISMA_SMART_PSOFT_MIN = 11,
PRISMA_SMART_PSOFT = 12,
PRISMA_SMART_SOFTPAP = 13,
PRISMA_SMART_APAP_DYNAMIC = 15,
PRISMA_SMART_HUMIDLEVEL = 16,
PRISMA_SMART_AUTOSTART = 17,
PRISMA_SMART_SOFTSTART_TIME_MAX = 18,
PRISMA_SMART_SOFTSTART_TIME = 19,
PRISMA_SMART_TUBE_TYPE = 21,
PRISMA_SMART_PMAXOA = 38,
PRISMA_LINE_MODE = 1003,
PRISMA_LINE_TI = 1011,
PRISMA_LINE_TE = 1012,
PRISMA_LINE_TARGET_VOLUME = 1016,
PRISMA_LINE_IPAP_SPEED = 1017,
PRISMA_LINE_HUMIDLEVEL = 1083,
PRISMA_LINE_AUTOSTART = 1084,
PRISMA_LINE_TUBE_TYPE = 1091,
PRISMA_LINE_BACTERIUMFILTER = 1092,
PRISMA_LINE_SOFT_PAP_LEVEL = 1123,
PRISMA_LINE_SOFT_START_PRESS = 1125,
PRISMA_LINE_SOFT_START_TIME = 1127,
PRISMA_LINE_EEPAP_MIN = 1138,
PRISMA_LINE_EEPAP_MAX = 1139,
PRISMA_LINE_PDIFF_NORM = 1140,
PRISMA_LINE_PDIFF_MAX = 1141,
PRISMA_LINE_IPAP_MAX = 1199,
PRISMA_LINE_IPAP = 1200,
PRISMA_LINE_EPAP = 1201,
// PRISMA_LINE_ALARM_LEAK_ACTIVE = 1202,
// PRISMA_LINE_ALARM_DISCONNECTION_ACTIVE = 1203,
PRISMA_LINE_APAP_DYNAMIC = 1209
};
// NOTE: Modes should be reverse engineered. Based on the samples we had, for now I didn't saw any overlap,
// so I assumed, the mode settings is generic between the two device lines. If you run into an overlap, the
// above mentioned parsers should be introduced. Enum values are coming from the prisma data files.
enum Prisma_Mode {
// Prisma Smart
PRISMA_MODE_CPAP = 1,
PRISMA_MODE_APAP = 2,
// Prisma Line
PRISMA_MODE_ACSV = 3,
PRISMA_MODE_AUTO_S = 9,
PRISMA_MODE_AUTO_ST = 10,
};
enum Prisma_APAP_Mode {
PRISMA_APAP_MODE_STANDARD = 1,
PRISMA_APAP_MODE_DYNAMIC = 2,
};
enum Prisma_SoftPAP_Mode {
Prisma_SoftPAP_OFF = 0,
Prisma_SoftPAP_SLIGHT = 1,
Prisma_SoftPAP_STANDARD = 2
};
// NOTE: This enum represents a "virtual mode" which combines the main mode of the device with the APAP submode,
// if it makes sense. The reason for this is, that we can see the Standard and Dynamic APAP modes on the statistics
// page. Enum values are internal to the loader. We use -1 to indicate a mode that is not recognized.
enum Prisma_Combined_Mode {
PRISMA_COMBINED_MODE_CPAP = 1,
PRISMA_COMBINED_MODE_APAP_STD = 2,
PRISMA_COMBINED_MODE_APAP_DYN = 3,
PRISMA_COMBINED_MODE_AUTO_S = 4,
PRISMA_COMBINED_MODE_AUTO_ST = 5,
PRISMA_COMBINED_MODE_ACSV = 6,
PRISMA_COMBINED_MODE_UNKNOWN = -1,
};
enum Prisma_Event_Type {
PRISMA_EVENT_EPOCH_SEVERE_OBSTRUCTION = 1,
PRISMA_EVENT_EPOCH_MILD_OBSTRUCTION = 2,
PRISMA_EVENT_EPOCH_FLOW_LIMITATION = 3,
PRISMA_EVENT_EPOCH_SNORE = 4,
PRISMA_EVENT_EPOCH_PERIODIC_BREATHING = 5,
PRISMA_EVENT_OBSTRUCTIVE_APNEA = 101,
PRISMA_EVENT_CENTRAL_APNEA = 102,
PRISMA_EVENT_APNEA_LEAKAGE = 103,
PRISMA_EVENT_APNEA_HIGH_PRESSURE = 105,
PRISMA_EVENT_APNEA_MOVEMENT = 106,
PRISMA_EVENT_OBSTRUCTIVE_HYPOPNEA= 111,
PRISMA_EVENT_CENTRAL_HYPOPNEA = 112,
PRISMA_EVENT_HYPOPNEA_LEAKAGE = 113,
PRISMA_EVENT_RERA = 121,
PRISMA_EVENT_SNORE = 131,
PRISMA_EVENT_ARTIFACT = 141,
PRISMA_EVENT_FLOW_LIMITATION = 151,
PRISMA_EVENT_CRITICAL_LEAKAGE = 161,
PRISMA_EVENT_CS_RESPIRATION = 181,
PRISMA_EVENT_TIMED_BREATH = 221,
PRISMA_EVENT_EPOCH_DEEPSLEEP = 261,
};
//********************************************************************************************
// Prisma WMEDF differs from the original EDF, by introducing 8 bit signal data channels.
class WMEDFInfo : public EDFInfo {
virtual bool ParseSignalData();
protected:
qint8 Read8S();
quint8 Read8U();
};
//********************************************************************************************
class PrismaLoader;
class PrismaEventFile;
/*! \class PrismaImport
* \brief Contains the functions to parse a single session... multithreaded */
class PrismaImport:public ImportTask
{
public:
PrismaImport(PrismaLoader * l, const MachineInfo& m, SessionID s, QByteArray e, QByteArray d): loader(l), machineInfo(m), sessionid(s), eventData(e), signalData(d) {}
virtual ~PrismaImport() {};
//! \brief PrismaImport thread starts execution here.
virtual void run();
protected:
PrismaLoader * loader;
const MachineInfo & machineInfo;
SessionID sessionid;
QByteArray eventData;
QByteArray signalData;
qint64 startdate;
qint64 enddate;
WMEDFInfo wmedf;
PrismaEventFile * eventFile;
Session * session;
void AddWaveform(ChannelID code, QString edfLabel);
void AddEvents(ChannelID channel, Prisma_Event_Type eventType) {
QList<Prisma_Event_Type> eventTypes = { eventType };
AddEvents(channel, eventTypes);
}
void AddEvents(ChannelID channel, QList<Prisma_Event_Type> eventTypes);
};
//********************************************************************************************
/*! \class PrismaLoader
\brief Löwenstein Prisma Loader Module
*/
class PrismaLoader : public CPAPLoader
{
Q_OBJECT
static bool initialized;
public:
PrismaLoader();
virtual ~PrismaLoader();
//! \brief Detect if the given path contains a valid Folder structure
virtual bool Detect(const QString & path);
//! \brief Load MachineInfo structure.
virtual MachineInfo PeekInfo(const QString & path);
//! \brief Scans directory path for valid Prisma signature
virtual int Open(const QString & path);
//! \brief Returns the database version of this loader
virtual int Version() { return prisma_data_version; }
//! \brief Return the loaderName, in this case "Prisma"
virtual const QString &loaderName() { return prisma_class_name; }
//! \brief Register this Module to the list of Loaders, so it knows to search for Prisma data.
static void Register();
//! \brief Generate a generic MachineInfo structure, with basic Prisma info to be expanded upon.
virtual MachineInfo newInfo() {
return MachineInfo(MT_CPAP, 0, prisma_class_name, QObject::tr("Löwenstein"), QObject::tr("Prisma Smart"), QString(), QString(), QObject::tr(""), QDateTime::currentDateTime(), prisma_data_version);
}
virtual QString PresReliefLabel();
virtual ChannelID CPAPModeChannel();
virtual ChannelID PresReliefMode();
//! \brief Called at application init, to set up any custom Prisma Channels
virtual void initChannels();
QHash<SessionID, PrismaImport*> sesstasks;
protected:
MachineInfo PeekInfoFromConfig(const QString & selectedPath);
void ImportDataDir(QDir& dataDir, QSet<SessionID>& sessions, QHash<SessionID, QString>& eventFiles, QHash<SessionID, QString>& signalFiles);
//! \brief Scans the given directories for session data and create an import task for each logical session.
void ScanFiles(const MachineInfo& info, const QString & path);
};
//********************************************************************************************
class PrismaEvent
{
public:
PrismaEvent(int endTime, int duration, int pressure, int strength) : m_endTime(endTime), m_duration(duration), m_pressure(pressure), m_strenght(strength) {}
int endTime() { return m_endTime; }
int duration() { return m_duration; }
int strength() { return m_strenght; }
protected:
int m_endTime;
int m_duration;
int m_pressure;
int m_strenght;
};
class PrismaEventFile
{
public:
PrismaEventFile(QByteArray &buffer);
QHash<int, int> getParameters() {return m_parameters; }
QList<PrismaEvent> getEvents(int eventId) {return m_events.contains(eventId) ? m_events[eventId] : QList<PrismaEvent>(); }
protected:
QHash<int, int> m_parameters;
QHash<int, QList<PrismaEvent>> m_events;
};
//********************************************************************************************
class PrismaModelInfo
{
protected:
QHash<QString,const char*> m_modelNames;
public:
PrismaModelInfo();
bool IsTested(const QString & deviceId) const;
const char* Name(const QString & deviceId) const;
};
#endif // PRISMA_LOADER_H

View File

@ -134,10 +134,12 @@ static const PRS1TestedModel s_PRS1TestedModels[] = {
{ "700X150", 0, 6, "DreamStation Auto BiPAP" },
{ "410X150C", 0, 6, "DreamStation 2 CPAP" },
{ "420X150C", 0, 6, "DreamStation 2 Advanced CPAP" }, // from FDA filing
{ "520X110C", 0, 6, "DreamStation 2 Auto CPAP Advanced" }, // based on bottom label, boot screen says "Advanced Auto CPAP"
{ "520X130C", 0, 6, "DreamStation 2 Auto CPAP Advanced" }, // from user report
{ "520X150C", 0, 6, "DreamStation 2 Auto CPAP Advanced" }, // from user report
{ "521X120C", 0, 6, "DreamStation 2 Auto CPAP Advanced with P-Flex" }, // inferred from 501X120 and presence of "P-Flex" on bottom label
{ "521X140C", 0, 6, "DreamStation 2 avec GSM + Humidificateur" }, // from brochure
{ "950P", 5, 0, "BiPAP AutoSV Advanced System One" },
{ "951P", 5, 0, "BiPAP AutoSV Advanced System One" },

View File

@ -2078,7 +2078,7 @@ bool PRS1DataChunk::ParseSettingsF0V6(const unsigned char* data, int size)
// TODO: Confirm that 4 is 12HT and update ParseTubingTypeV3.
this->ParseTubingTypeV3(data[pos]);
break;
case 0x48: // ??? Seen on DreamStation 2 non-Advanced (410)
case 0x48: // ??? Seen on DreamStation 2 non-Advanced (410) but not either Advanced (420 or 520)
// Appears between 0x2C (ramp time) and 0x2E (flex mode), with a value of 0-4.
CHECK_VALUE(len, 1);
if (data[pos] > 4) {

View File

@ -52,7 +52,7 @@ void ResmedLoader::LogUnexpectedMessage(const QString & message)
m_importMutex.unlock();
}
static const QVector<int> AS11TestedModels {39420, 39423, 0};
static const QVector<int> AS11TestedModels {39420, 39421, 39423, 39485, 0};
ResmedLoader::ResmedLoader() {
#ifndef UNITTEST_MODE

View File

@ -418,19 +418,23 @@ QList<ViatomFile::Record> ViatomFile::ReadData()
QList<ViatomFile::Record> dedup;
bool all_are_duplicated = true;
CHECK_VALUE(records.size() % 2, 0);
for (int i = 0; i < records.size(); i += 2) {
auto & a = records.at(i);
auto & b = records.at(i+1);
if (a.spo2 != b.spo2
|| a.hr != b.hr
|| a.oximetry_invalid != b.oximetry_invalid
|| a.motion != b.motion
|| a.vibration != b.vibration) {
all_are_duplicated = false;
break;
if ((records.size() % 2) != 0) {
// An odd number of samples inherently can't be all duplicates.
all_are_duplicated = false;
} else {
for (int i = 0; i < records.size(); i += 2) {
auto & a = records.at(i);
auto & b = records.at(i+1);
if (a.spo2 != b.spo2
|| a.hr != b.hr
|| a.oximetry_invalid != b.oximetry_invalid
|| a.motion != b.motion
|| a.vibration != b.vibration) {
all_are_duplicated = false;
break;
}
dedup.append(a);
}
dedup.append(a);
}
if (m_sig == 5) {
// Confirm that CheckMe O2 Max is a true 2s sample rate.

View File

@ -27,7 +27,7 @@ ChannelID CPAP_IPAP, CPAP_IPAPLo, CPAP_IPAPHi, CPAP_EPAP, CPAP_EPAPLo, CPAP_EPAP
CPAP_UserFlag1, CPAP_UserFlag2, CPAP_UserFlag3, /*CPAP_BrokenSummary, CPAP_BrokenWaveform,*/ CPAP_RDI,
CPAP_PresReliefMode, CPAP_PresReliefLevel, CPAP_PSMin, CPAP_PSMax, CPAP_Test1,
CPAP_Test2, CPAP_HumidSetting,
CPAP_PressureSet, CPAP_IPAPSet, CPAP_EPAPSet;
CPAP_PressureSet, CPAP_IPAPSet, CPAP_EPAPSet, CPAP_EEPAP;
ChannelID RMS9_E01, RMS9_E02, RMS9_SetPressure, RMS9_MaskOnTime;

View File

@ -149,7 +149,7 @@ extern ChannelID AllAhiChannels;
extern QVector<ChannelID> ahiChannels;
extern ChannelID NoChannel, SESSION_ENABLED, CPAP_SummaryOnly;
extern ChannelID CPAP_IPAP, CPAP_IPAPLo, CPAP_IPAPHi, CPAP_EPAP, CPAP_EPAPLo, CPAP_EPAPHi,
extern ChannelID CPAP_IPAP, CPAP_IPAPLo, CPAP_IPAPHi, CPAP_EPAP, CPAP_EPAPLo, CPAP_EPAPHi, CPAP_EEPAP,
CPAP_Pressure, CPAP_PS, CPAP_PSMin, CPAP_PSMax,
CPAP_Mode, CPAP_AHI,
CPAP_PressureMin, CPAP_PressureMax, CPAP_Ramp, CPAP_RampTime, CPAP_RampPressure, CPAP_Obstructive,

View File

@ -138,6 +138,7 @@ void init()
schema::channel.add(GRP_CPAP, new Channel(CPAP_EPAP = 0x110E, WAVEFORM, MT_CPAP, SESSION, "EPAP", STR_TR_EPAP, QObject::tr("Expiratory Pressure"), STR_TR_EPAP, STR_UNIT_CMH2O, DEFAULT, QColor("green")));
schema::channel.add(GRP_CPAP, new Channel(CPAP_EPAPLo = 0x111C, WAVEFORM, MT_CPAP, SESSION, "EPAPLo", STR_TR_EPAPLo, QObject::tr("Lower Expiratory Pressure"), STR_TR_EPAPLo, STR_UNIT_CMH2O, DEFAULT, QColor("light blue")));
schema::channel.add(GRP_CPAP, new Channel(CPAP_EPAPHi = 0x111D, WAVEFORM, MT_CPAP, SESSION, "EPAPHi", STR_TR_EPAPHi, QObject::tr("Higher Expiratory Pressure"), STR_TR_EPAPHi, STR_UNIT_CMH2O, DEFAULT, QColor("aqua")));
schema::channel.add(GRP_CPAP, new Channel(CPAP_EEPAP = 0x11A7, WAVEFORM, MT_CPAP, SESSION, "EEPAP", STR_TR_EEPAP, QObject::tr("End Expiratory Pressure"), STR_TR_EEPAP, STR_UNIT_CMH2O, DEFAULT, QColor("purple")));
schema::channel.add(GRP_CPAP, new Channel(CPAP_PS = 0x110F, WAVEFORM, MT_CPAP, SESSION, "PS", STR_TR_PS, QObject::tr("Pressure Support"), STR_TR_PS, STR_UNIT_CMH2O, DEFAULT, QColor("grey")));
schema::channel.add(GRP_CPAP, new Channel(CPAP_PSMin = 0x111A, SETTING, MT_CPAP, SESSION, "PSMin", QObject::tr("PS Min") , QObject::tr("Pressure Support Minimum"), QObject::tr("PS Min"), STR_UNIT_CMH2O, DEFAULT, QColor("dark cyan")));
schema::channel.add(GRP_CPAP, new Channel(CPAP_PSMax = 0x111B, SETTING, MT_CPAP, SESSION, "PSMax", QObject::tr("PS Max"), QObject::tr("Pressure Support Maximum"), QObject::tr("PS Max"), STR_UNIT_CMH2O, DEFAULT, QColor("dark magenta")));
@ -172,7 +173,7 @@ void init()
schema::channel.add(GRP_CPAP, new Channel(CPAP_VSnore = 0x1007, FLAG, MT_CPAP, SESSION, "VSnore",
QObject::tr("Vibratory Snore (VS)"), QObject::tr("A vibratory snore"), QObject::tr("VS"), STR_UNIT_EventsPerHour, DEFAULT, QColor("red")));
schema::channel.add(GRP_CPAP, new Channel(CPAP_VSnore2 = 0x1008, FLAG, MT_CPAP, SESSION, "VSnore2",
QObject::tr("Vibratory Snore (VS2) "),QObject::tr("A vibratory snore as detcted by a System One device"),QObject::tr("VS2"), STR_UNIT_EventsPerHour, DEFAULT, QColor("red")));
QObject::tr("Vibratory Snore (VS2) "),QObject::tr("A vibratory snore as detected by a System One device"),QObject::tr("VS2"), STR_UNIT_EventsPerHour, DEFAULT, QColor("red")));
// This Large Leak record is just a flag marker, used by Intellipap for one
schema::channel.add(GRP_CPAP, new Channel(CPAP_LeakFlag = 0x100a, FLAG, MT_CPAP, SESSION, "LeakFlag",
QObject::tr("Leak Flag (LF)"), QObject::tr("A large mask leak affecting device performance."), QObject::tr("LF"), STR_UNIT_EventsPerHour, DEFAULT, QColor("light gray")));

View File

@ -1,4 +1,4 @@
// Update the string below to set OSCAR's version and release status.
// See https://semver.org/spec/v2.0.0.html for details on format.
#define VERSION "1.3.5-alpha.3"
#define VERSION "1.4.1-alpha-1"

View File

@ -50,6 +50,13 @@ const QString STR_GRAPH_Oxi_Plethy = "Plethy";
const QString STR_GRAPH_Oxi_Perf = "Perf. Index";
const QString STR_GRAPH_Oxi_PulseChange = "PulseChange";
const QString STR_GRAPH_Oxi_SPO2Drop = "SPO2Drop";
const QString STR_GRAPH_ObstructLevel = "ObstructLevel";
const QString STR_GRAPH_PressureMeasured = "PressureMeasured";
const QString STR_GRAPH_rRMV = "rRMV";
const QString STR_GRAPH_rMVFluctuation = "rMVFluctuation";
const QString STR_GRAPH_FlowFull = "FlowFull";
const QString STR_GRAPH_SPRStatus = "SPRStatus";
//OXI_Pulse, OXI_SPO2, OXI_Perf, OXI_Plethy

View File

@ -7,6 +7,9 @@
* License. See the file COPYING in the main directory of the source code
* for more details. */
#define TEST_MACROS_ENABLEDoff
#include <test_macros.h>
#include <QTextCharFormat>
#include <QPalette>
#include <QTextBlock>
@ -57,6 +60,7 @@ QString htmlLeftSessionInfo;
QString htmlLeftFooter;
extern ChannelID PRS1_PeakFlow;
extern ChannelID Prisma_ObstructLevel, Prisma_rMVFluctuation, Prisma_rRMV, Prisma_PressureMeasured, Prisma_FlowFull, Prisma_SPRStatus;
// This was Sean Stangl's idea.. but I couldn't apply that patch.
inline QString channelInfo(ChannelID code) {
@ -82,7 +86,8 @@ const QList<QString> standardGraphOrder = {STR_GRAPH_SleepFlags, STR_GRAPH_FlowR
STR_GRAPH_PTB, STR_GRAPH_RespEvent, STR_GRAPH_Ti, STR_GRAPH_Te,
STR_GRAPH_SleepStage, STR_GRAPH_Inclination, STR_GRAPH_Orientation, STR_GRAPH_Motion, STR_GRAPH_TestChan1,
STR_GRAPH_Oxi_Pulse, STR_GRAPH_Oxi_SPO2, STR_GRAPH_Oxi_Perf, STR_GRAPH_Oxi_Plethy,
STR_GRAPH_AHI, STR_GRAPH_TAP
STR_GRAPH_AHI, STR_GRAPH_TAP, STR_GRAPH_ObstructLevel, STR_GRAPH_PressureMeasured, STR_GRAPH_rRMV, STR_GRAPH_rMVFluctuation,
STR_GRAPH_FlowFull, STR_GRAPH_SPRStatus
};
// Advanced graph order
@ -91,7 +96,8 @@ const QList<QString> advancedGraphOrder = {STR_GRAPH_SleepFlags, STR_GRAPH_FlowR
STR_GRAPH_RespRate, STR_GRAPH_PTB, STR_GRAPH_RespEvent,
STR_GRAPH_SleepStage, STR_GRAPH_Inclination, STR_GRAPH_Orientation, STR_GRAPH_Motion, STR_GRAPH_TestChan1,
STR_GRAPH_Oxi_Pulse, STR_GRAPH_Oxi_SPO2, STR_GRAPH_Oxi_Perf, STR_GRAPH_Oxi_Plethy,
STR_GRAPH_AHI, STR_GRAPH_TAP
STR_GRAPH_AHI, STR_GRAPH_TAP, STR_GRAPH_ObstructLevel, STR_GRAPH_PressureMeasured, STR_GRAPH_rRMV, STR_GRAPH_rMVFluctuation,
STR_GRAPH_FlowFull, STR_GRAPH_SPRStatus
};
// CPAP modes that should have Advanced graphs
@ -240,7 +246,8 @@ Daily::Daily(QWidget *parent,gGraphView * shared)
const ChannelID cpapcodes[] = {
CPAP_FlowRate, CPAP_Pressure, CPAP_Leak, CPAP_FLG, CPAP_Snore, CPAP_TidalVolume,
CPAP_MaskPressure, CPAP_RespRate, CPAP_MinuteVent, CPAP_PTB, PRS1_PeakFlow, CPAP_RespEvent, CPAP_Ti, CPAP_Te,
/* CPAP_IE, */ ZEO_SleepStage, POS_Inclination, POS_Orientation, POS_Movement, CPAP_Test1
/* CPAP_IE, */ ZEO_SleepStage, POS_Inclination, POS_Orientation, POS_Movement, CPAP_Test1,
Prisma_ObstructLevel, Prisma_rRMV, Prisma_rMVFluctuation, Prisma_PressureMeasured, Prisma_FlowFull, Prisma_SPRStatus
};
// Create graphs from the cpap code list
@ -355,6 +362,7 @@ Daily::Daily(QWidget *parent,gGraphView * shared)
pc->addPlot(CPAP_IPAPLo, square);
pc->addPlot(CPAP_IPAP, square);
pc->addPlot(CPAP_IPAPHi, square);
pc->addPlot(CPAP_EEPAP, square);
pc->addPlot(CPAP_PressureSet, false);
pc->addPlot(CPAP_EPAPSet, false);
pc->addPlot(CPAP_IPAPSet, false);
@ -393,6 +401,14 @@ Daily::Daily(QWidget *parent,gGraphView * shared)
graphlist[schema::channel[CPAP_PTB].code()]->AddLayer(new gLineChart(CPAP_PTB, square));
graphlist[schema::channel[PRS1_PeakFlow].code()]->AddLayer(new gLineChart(PRS1_PeakFlow, square));
graphlist[schema::channel[Prisma_ObstructLevel].code()]->AddLayer(new gLineChart(Prisma_ObstructLevel, square));
graphlist[schema::channel[Prisma_PressureMeasured].code()]->AddLayer(new gLineChart(Prisma_PressureMeasured, square));
graphlist[schema::channel[Prisma_rRMV].code()]->AddLayer(new gLineChart(Prisma_rRMV, square));
graphlist[schema::channel[Prisma_rMVFluctuation].code()]->AddLayer(new gLineChart(Prisma_rMVFluctuation, square));
graphlist[schema::channel[Prisma_FlowFull].code()]->AddLayer(new gLineChart(Prisma_FlowFull, square));
graphlist[schema::channel[Prisma_SPRStatus].code()]->AddLayer(new gLineChart(Prisma_SPRStatus, square));
graphlist[schema::channel[CPAP_Test1].code()]->AddLayer(new gLineChart(CPAP_Test1, square));
//graphlist[schema::channel[CPAP_Test2].code()]->AddLayer(new gLineChart(CPAP_Test2, square));
@ -1325,6 +1341,7 @@ QString Daily::getStatisticsInfo(Day * day)
ChannelID chans[]={
CPAP_Pressure,CPAP_PressureSet,CPAP_EPAP,CPAP_EPAPSet,CPAP_IPAP,CPAP_IPAPSet,CPAP_PS,CPAP_PTB,
PRS1_PeakFlow,
Prisma_ObstructLevel, Prisma_PressureMeasured, Prisma_rRMV, Prisma_rMVFluctuation,
CPAP_MinuteVent, CPAP_RespRate, CPAP_RespEvent,CPAP_FLG,
CPAP_Leak, CPAP_LeakTotal, CPAP_Snore, /* CPAP_IE, */ CPAP_Ti,CPAP_Te, CPAP_TgMV,
CPAP_TidalVolume, OXI_Pulse, OXI_SPO2, POS_Inclination, POS_Orientation, POS_Movement
@ -2644,6 +2661,7 @@ void Daily::on_graphCombo_activated(int index)
g=GraphView->findGraphTitle(s);
g->setVisible(b);
ui->graphCombo->showPopup();
}
ui->graphCombo->setCurrentIndex(0);
@ -2749,6 +2767,7 @@ void Daily::on_eventsCombo_activated(int index)
bool b = !chan->enabled();
chan->setEnabled(b);
ui->eventsCombo->setItemIcon(index,b ? *icon_on : *icon_off);
ui->eventsCombo->showPopup();
}
ui->eventsCombo->setCurrentIndex(0);

View File

@ -23,23 +23,26 @@ void MyOutputHandler(QtMsgType type, const QMessageLogContext &context, const QS
return;
}
QString msg, typestr;
QString msg, typestr, contextstr;
#ifdef VERBOSE_LOGGING
contextstr = QString(context.file) + " " + context.function + ":" + QString::number(context.line) + " ";
#endif
switch (type) {
case QtWarningMsg:
typestr = QString("Warning: ");
typestr = QString("Warning: ") + contextstr;
break;
case QtFatalMsg:
typestr = QString("Fatal: ");
typestr = QString("Fatal: ") + contextstr;
break;
case QtCriticalMsg:
typestr = QString("Critical: ");
typestr = QString("Critical: ") + contextstr;
break;
default:
typestr = QString("Debug: ");
typestr = QString("Debug: ") + contextstr;
break;
}

View File

@ -46,6 +46,7 @@
#include "SleepLib/loader_plugins/sleepstyle_loader.h"
#include "SleepLib/loader_plugins/weinmann_loader.h"
#include "SleepLib/loader_plugins/viatom_loader.h"
#include "SleepLib/loader_plugins/prisma_loader.h"
MainWindow *mainwin = nullptr;
@ -691,6 +692,7 @@ int main(int argc, char *argv[]) {
CMS50F37Loader::Register();
MD300W1Loader::Register();
ViatomLoader::Register();
PrismaLoader::Register();
// Begin logging device connection activity.
QString connectionsLogDir = GetLogDir() + "/connections";

View File

@ -1993,7 +1993,7 @@ void MainWindow::purgeMachine(Machine * mach)
p_profile->StoreMachines();
} else {
QMessageBox::warning(this, STR_MessageBox_Error,
tr("A file permission error casued the purge process to fail; you will have to delete the following folder manually:") +
tr("A file permission error caused the purge process to fail; you will have to delete the following folder manually:") +
"\n\n" + QDir::toNativeSeparators(mach->getDataPath()), QMessageBox::Ok, QMessageBox::Ok);
if (overview)
@ -2553,9 +2553,15 @@ void MainWindow::on_actionDaily_Calendar_toggled(bool visible)
void MainWindow::on_actionShowPersonalData_toggled(bool visible)
{
AppSetting->setShowPersonalData(visible);
if (!setupRunning)
GenerateStatistics();
// This uses the Prefs routines, which require p_profile to be set
if ( p_profile != nullptr ) {
AppSetting->setShowPersonalData(visible);
if ( ! setupRunning )
GenerateStatistics();
} else {
QMessageBox::information(this, "OSCAR", tr("You must select and open the profile you wish to modify"),
QMessageBox::Ok);
}
}
#include "SleepLib/journal.h"

View File

@ -301,6 +301,7 @@ SOURCES += \
SleepLib/loader_plugins/sleepstyle_EDFinfo.cpp \
SleepLib/loader_plugins/intellipap_loader.cpp \
SleepLib/loader_plugins/mseries_loader.cpp \
SleepLib/loader_plugins/prisma_loader.cpp \
SleepLib/loader_plugins/prs1_loader.cpp \
SleepLib/loader_plugins/prs1_parser.cpp \
SleepLib/loader_plugins/prs1_parser_xpap.cpp \
@ -403,6 +404,7 @@ HEADERS += \
SleepLib/loader_plugins/sleepstyle_EDFinfo.h \
SleepLib/loader_plugins/intellipap_loader.h \
SleepLib/loader_plugins/mseries_loader.h \
SleepLib/loader_plugins/prisma_loader.h \
SleepLib/loader_plugins/prs1_loader.h \
SleepLib/loader_plugins/prs1_parser.h \
SleepLib/loader_plugins/resmed_loader.h \

View File

@ -7,25 +7,8 @@
* License. See the file COPYING in the main directory of the source code
* for more details. */
#define NEWSTUFF
#define xDEBUG_FUNCTIONS
#ifdef DEBUG_FUNCTIONS
#include <QRegularExpression>
#define DEBUGQ qDebug()
#define DEBUGL qDebug()<<QString(basename( __FILE__)).remove(QRegularExpression("\\..*$")) << __LINE__
#define DEBUGF qDebug()<< QString("%1[%2]%3").arg( QString(basename( __FILE__)).remove(QRegularExpression("\\..*$")) ).arg(__LINE__).arg(__func__)
#define DEBUGT qDebug()<<QDateTime::currentDateTime().time().toString("hh:mm:ss.zzz")
#define DEBUGTF qDebug()<<QDateTime::currentDateTime().time().toString("hh:mm:ss.zzz") << QString(basename( __FILE__)).remove(QRegularExpression("\\..*$")) << __LINE__ << __func__
#define O( XX ) " " #XX ":" << XX
#define Q( XX ) << #XX ":" << XX
#define R( XX )
#define OO( XX , YY ) " " #XX ":" << YY
#define NAME( id) schema::channel[ id ].label()
#define DATE( XX ) QDateTime::fromMSecsSinceEpoch(XX).toString("dd MMM yyyy")
#define DATETIME( XX ) QDateTime::fromMSecsSinceEpoch(XX).toString("dd MMM yyyy hh:mm:ss.zzz")
#endif
#define TEST_MACROS_ENABLEDoff
#include <test_macros.h>
// Features enabled by conditional compilation.
#define ENABLE_GENERAL_MODIFICATION_OF_CALENDARS
@ -890,6 +873,7 @@ void Overview::on_graphCombo_activated(int index)
g = GraphView->findGraphTitle(s);
g->setVisible(b);
ui->graphCombo->showPopup();
}
ui->graphCombo->setCurrentIndex(0);
updateCube();
@ -939,3 +923,4 @@ void Overview::on_toggleVisibility_clicked(bool checked)
GraphView->updateScale();
GraphView->redraw();
}

View File

@ -38,74 +38,75 @@ To turn off the the test macros.
#include <QRegularExpression>
#include <QFileInfo>
#define DEBUGL qDebug() <<QString("%1[%2]").arg(QFileInfo( __FILE__).baseName()).arg(__LINE__)
//example:
//12361: Debug: "gGraphView[572]"
#define DEBUGQ qDebug().noquote()
#define DEBUGL DEBUGQ <<QString("%1[%2]").arg(QFileInfo( __FILE__).baseName()).arg(__LINE__)
#define DEBUGF DEBUGQ <<QString("%1[%2]%3").arg(QFileInfo( __FILE__).baseName()).arg(__LINE__).arg(__func__)
#define DEBUGT DEBUGQ <<QString("%1 %2[%3]%4").arg(QDateTime::currentDateTime().time().toString("hh:mm:ss.zzz")).arg(QFileInfo( __FILE__).baseName()).arg(__LINE__)
#define DEBUGTF DEBUGQ <<QString("%1 %2[%3]%4").arg(QDateTime::currentDateTime().time().toString("hh:mm:ss.zzz")).arg(QFileInfo( __FILE__).baseName()).arg(__LINE__).arg(__func__)
#define DEBUGF qDebug() <<QString("%1[%2]%3").arg(QFileInfo( __FILE__).baseName()).arg(__LINE__).arg(__func__)
//example:
//12361: Debug: "gGraphView[572]popoutGraph"
#define DEBUGT qDebug() <<QString("%1 %2[%3]%4").arg(QDateTime::currentDateTime().time().toString("hh:mm:ss.zzz")).arg(QFileInfo( __FILE__).baseName()).arg(__LINE__)
//example:
//12645: Debug: "06:00:18.284 gGraphView[622]"
#define DEBUGTF qDebug() <<QString("%1 %2[%3]%4").arg(QDateTime::currentDateTime().time().toString("hh:mm:ss.zzz")).arg(QFileInfo( __FILE__).baseName()).arg(__LINE__).arg(__func__)
//example:
//12645: Debug: "06:00:18.284 gGraphView[622]popoutGraph"
// Macros to display variables
// Do nothing
#define Z( EXPRESSION ) /* comment out display of variable */
#define ZZ( A ,EXPRESSION ) /* comment out display of variable */
// Macros to display variables
#define O( EXPRESSION ) << EXPRESSION
// return values from functions donr't work - QQ macro instead
#define Q( VALUE ) << "" #VALUE ":" << VALUE
//example:
//
#define Q( VALUE ) << "" #VALUE ":" << VALUE
#define QQ( TEXT , EXPRESSION) << #TEXT ":" << EXPRESSION
//example:
//#define Q( VALUE ) << QString("%1:%2").arg( "" #VALUE).arg(VALUE)
//#define QQ( TEXT , EXPRESSION) << QString("%1:%2").arg( "" #TEXT).arg(VALUE)
#define NAME( SCHEMECODE ) << schema::channel[ SCHEMECODE ].label()
//example:
#define NAME( SCHEMACODE ) << schema::channel[ SCHEMACODE ].label()
#define FULLNAME( SCHEMACODE ) << schema::channel[ SCHEMAcODE ].fullname()
#define FULLNAME( SCHEMECODE ) << schema::channel[ SCHEMEcODE ].fullname()
//example:
//display the date of an epoch time stamp "qint64"
//display the date of an epoch time stamp "qint64"
#define DATE( EPOCH ) << QDateTime::fromMSecsSinceEpoch( EPOCH ).toString("dd MMM yyyy")
//display the date and Time of an epoch time stamp "qint64"
//display the date and Time of an epoch time stamp "qint64"
#define DATETIME( EPOCH ) << QDateTime::fromMSecsSinceEpoch( EPOCH ).toString("dd MMM yyyy hh:mm:ss.zzz")
/*
sample Lines.
code
DEBUGF Q(name) Q(title) QQ("UNITS",units) Q(height) Q(group);
output
00791: Debug: "gGraph[137]gGraph" name: "RespRate" title: "Respiratory Rate" "UNITS": "Rate of breaths per minute" height: 180 group: 0
#ifdef __clang__
#define COMPILER O(QString("clang++:%1").arg(__clang_version__) );
#elif __GNUC_VERSION__
#define COMPILER O(QString("GNUC++:%1").arg("GNUC").arg(__GNUC_VERSION__)) ;
#else
#define COMPILER
#endif
DEBUGTF Q(newname);
12645: Debug: "06:00:18.284 gGraphView[622]popoutGraph" newname: "Pressure - Friday, April 15, 2022"
#if 0
//example: DEBUGL;
//12361: Debug: "gGraphView[572]"
DEBUGF NAME(dot.code) Q(dot.type) QQ(y,(int)y) Q(ratioX) O(QLine(left + 1, y, left + 1 + width, y)) Q(legendx) O(dot.value) ;
92 00917: Debug: "gLineChart[568]paint" "Pressure" dot.type: 4 y: 341 ratioX: 1 QLine(QPoint(91,341),QPoint(464,341)) legendx: 463 12.04
//example: DEBUGF;
//12361: Debug: "gGraphView[572]popoutGraph"
//example: DEBUGT;
//12645: Debug: "06:00:18.284 gGraphView[622]"
*/
//example: DEBUGTF;
//12645: Debug: "06:00:18.284 gGraphView[622]popoutGraph"
//example: DEBUGF Q(name) Q(title) QQ("UNITS",units) Q(height) Q(group);
//00791: Debug: "gGraph[137]gGraph" name: "RespRate" title: "Respiratory Rate" "UNITS": "Rate of breaths per minute" height: 180 group: 0
//example: DEBUGTF Q(newname);
//12645: Debug: "06:00:18.284 gGraphView[622]popoutGraph" newname:"Pressure - Friday, April 15, 2022"
//example: DEBUGF NAME(dot.code) Q(dot.type) QQ(y,(int)y) Q(ratioX) O(QLine(left + 1, y, left + 1 + width, y)) Q(legendx) O(dot.value) ;
//92 00917: Debug: "gLineChart[568]paint" "Pressure" dot.type: 4 y: 341 ratioX: 1 QLine(QPoint(91,341),QPoint(464,341)) legendx: 463 12.04
#endif
#else
// Turn debugging off. macros expands to white space
#define DEBUGQ
#define DEBUGL
#define DEBUGF
#define DEBUGT
#define DEBUGTF
#define Z( XX )
#define ZZ( XX , YY)
#define O( XX )
#define Q( XX )
#define QQ( XX , YY )
@ -113,6 +114,7 @@ DEBUGF NAME(dot.code) Q(dot.type) QQ(y,(int)y) Q(ratioX) O(QLine(left + 1, y, le
#define FULLNAME( id)
#define DATE( XX )
#define DATETIME( XX )
#define COMPILER
#endif
#endif

View File

@ -53,15 +53,16 @@ void initTranslations()
langNames["fi"] = "Suomen kieli";
langNames["fr"] = "Français";
langNames["he"] = "\xd7\xa2\xd7\x91\xd7\xa8\xd7\x99\xd7\xaa";
langNames["hu"] = "Magyar nyelv";
langNames["hu"] = "Magyar";
langNames["ja"] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e";
langNames["ko"] = "\xed\x95\x9c\xea\xb5\xad\xec\x96\xb4";
langNames["nl"] = "Nederlands";
langNames["pt"] = "Português";
langNames["pt_BR"] = "Português (Brazil)";
langNames["ro"] = "Românește";
langNames["tr"] = "Türkçe";
langNames["ru"] = "\xd1\x80\xd1\x83\xd1\x81\xd1\x81\xd0\xba\xd0\xb8\xd0\xb9";
langNames["th"] = "\xe0\xb8\xa0\xe0\xb8\xb2\xe0\xb8\xa9\xe0\xb8\xb2\xe0\xb9\x84\xe0\xb8\x97\xe0\xb8\xa2";
langNames["tr"] = "Türkçe";
langNames["zh_CN"] = "\xe5\x8d\x8e\xe8\xaf\xad\xe7\xae\x80\xe4\xbd\x93\xe5\xad\x97 \x2d \xe4\xb8\xad\xe5\x9b\xbd";
langNames["zh_TW"] = "\xe8\x8f\xaf\xe8\xaa\x9e\xe6\xad\xa3\xe9\xab\x94\xe5\xad\x97 \x2d \xe8\x87\xba\xe7\x81\xa3";

View File

@ -179,6 +179,7 @@ QString Welcome::GenerateCPAPHTML()
QString daystring;
if (daysto == 1) daystring += tr("last night");
else if (daysto == 2) daystring += tr("1 day ago");
else if (daysto == 0) daystring += tr("today");
else daystring += tr("%2 days ago").arg(daysto-1);
html += tr("was %1 (on %2)").arg(daystring).arg(date.toString(Qt::SystemLocaleLongDate)) + "<br/>";