AirCurve series detection (icon fix) and some cleanups

This commit is contained in:
Mark Watkins 2016-03-02 12:09:32 +10:00
parent f69eda1101
commit 29581ebc88
4 changed files with 76 additions and 65 deletions

View File

@ -1066,10 +1066,16 @@ bool PRS1Import::ParseF5Events()
session->updateLast(t);
session->m_cnt.clear();
session->m_cph.clear();
session->settings[CPAP_IPAPLo] = session->Min(CPAP_IPAPLo);
session->settings[CPAP_IPAPHi] = session->Max(CPAP_IPAPHi);
session->settings[CPAP_PSMax] = session->Max(CPAP_IPAPHi) - session->Min(CPAP_EPAP);
session->settings[CPAP_PSMin] = session->Min(CPAP_IPAPLo) - session->Min(CPAP_EPAP);
EventDataType minEpap = session->Min(CPAP_EPAP);
EventDataType minIpapLo = session->Min(CPAP_IPAPLo);
EventDataType maxIpapHi = session->Max(CPAP_IPAPHi);
session->settings[CPAP_IPAPLo] = minIpapLo;
session->settings[CPAP_IPAPHi] = maxIpapHi;
session->settings[CPAP_PSMax] = maxIpapHi - minEpap;
session->settings[CPAP_PSMin] = minIpapLo - minEpap;
session->m_valuesummary[CPAP_Pressure].clear();
session->m_valuesummary.erase(session->m_valuesummary.find(CPAP_Pressure));
@ -1164,7 +1170,6 @@ bool PRS1Import::ParseF0Events()
EventDataType data[10];
int cnt = 0;
short delta;
int tdata;
int pos;
qint64 t = qint64(event->timestamp) * 1000L, tt;
@ -1193,17 +1198,12 @@ bool PRS1Import::ParseF0Events()
EventList *IPAP = nullptr;
EventList *PS = nullptr;
EventList *Code15 = nullptr;
//session->AddEventList(CPAP_VSnore, EVL_Event);
//EventList * VS=session->AddEventList(CPAP_Obstructive, EVL_Event);
unsigned char lastcode3 = 0, lastcode2 = 0, lastcode = 0;
int lastpos = 0, startpos = 0, lastpos2 = 0, lastpos3 = 0;
int size = event->m_data.size();
bool FV3 = (event->fileVersion == 3);
// if (FV3) size -= 2;
unsigned char * buffer = (unsigned char *)event->m_data.data();
CPAPMode mode = (CPAPMode) session->settings[CPAP_Mode].toInt();
@ -1322,7 +1322,6 @@ bool PRS1Import::ParseF0Events()
case 0x04: // Pressure Pulse
data[0] = buffer[pos++];
//tt = t - (qint64(data[0]) * 1000L);
PP->AddEvent(t, data[0]);
break;
@ -1369,16 +1368,13 @@ bool PRS1Import::ParseF0Events()
break;
case 0x0d: // Vibratory Snore
// if (event->fileVersion == 3) {
// } else {
VS->AddEvent(t, 0);
// }
VS->AddEvent(t, 0);
break;
case 0x0e: // Unknown
data[0] = buffer[pos + 1] << 8 | buffer[pos];
if (event->familyVersion >= 4) {
// might not doublerize on older machines
// might not doublerize on older machines?
data[0] *= 2;
}
@ -1386,23 +1382,8 @@ bool PRS1Import::ParseF0Events()
data[1] = buffer[pos++];
tt = t - qint64(data[1]) * 1000L;
//LL->AddEvent(tt, data[0]);
Code[17]->AddEvent(t, data[0]);
// data[0] = ((char *)buffer)[pos++];
// data[1] = buffer[pos++]; //(buffer[pos+1] << 8) | buffer[pos];
// //data[0]/=10.0;
// //pos+=2;
// data[2] = buffer[pos++];
// tdata = unsigned(data[1]) << 8 | unsigned(data[0]);
// Code[17]->AddEvent(t, tdata);
//qDebug() << hex << data[0] << data[1] << data[2];
//session->AddEvent(new Event(t,cpapcode, 0, data, 3));
//tt-=data[1]*1000;
//session->AddEvent(new Event(t,CPAP_PB, data, 2));
break;
case 0x0f: // Cheyne Stokes Respiration
@ -1416,6 +1397,7 @@ bool PRS1Import::ParseF0Events()
tt = t - qint64(data[1]) * 1000L;
PB->AddEvent(tt, data[0]);
break;
case 0x10: // Large Leak
data[0] = buffer[pos + 1] << 8 | buffer[pos];
if (event->familyVersion >= 4) {
@ -1440,11 +1422,16 @@ bool PRS1Import::ParseF0Events()
VS2->AddEvent(t, data[1]);
}
if (((event->family == 0) && (event->familyVersion >= 4)) || (event->fileVersion == 3)) {
if ((event->family == 0) && (event->familyVersion >= 4)) {
// EPAP / Flex Pressure
data[0] = buffer[pos++];
//if (!(EPAP = session->AddEventList(CPAP_EPAP, EVL_Event, 0.1F))) { return false; }
//EPAP->AddEvent(t, data[0]);
// Perhaps this check is not necessary, as it will theoretically add extra resolution to pressure chart
// for bipap models and above???
if (mode <= MODE_BILEVEL_FIXED) {
if (!(EPAP = session->AddEventList(CPAP_EPAP, EVL_Event, 0.1F))) { return false; }
EPAP->AddEvent(t, data[0]);
}
}
break;
@ -1455,11 +1442,8 @@ bool PRS1Import::ParseF0Events()
data[2] = buffer[pos + 1] << 8 | buffer[pos];
pos += 2;
// if (!Code[24]) {
// if (!(Code[24] = session->AddEventList(PRS1_12, EVL_Event))) { return false; }
// }
// Could end here, but I've seen data sets valid data after!!!
// Code[24]->AddEvent(t, data[0]);
break;
case 0x14: // DreamStation Hypopnea
@ -1468,20 +1452,10 @@ bool PRS1Import::ParseF0Events()
HY->AddEvent(tt, data[0]);
break;
case 0x15: // DreamStation Hypopnea // Also a hypopnea.. Hmmm. grouped together by encore.
case 0x15: // DreamStation Hypopnea
data[0] = buffer[pos++];
tt = t - (qint64(data[0]) * 1000L);
HY->AddEvent(tt, data[0]);
// This will create an ugly overlay... :/
// if (!Code15) {
// Code15 = session->AddEventList(CPAP_Pressure, EVL_Event, 0.1F);
// if (!Code15) { return false; }
// }
// Code15->AddEvent(t, data[0]);
break;
default:
@ -2552,6 +2526,7 @@ void PRS1Import::run()
session->Store(mach->getDataPath());
loader->saveMutex.unlock();
// Unload them from memory
session->TrashEvents();
}
@ -2787,7 +2762,8 @@ QList<PRS1DataChunk *> PRS1Loader::ParseFile(QString path)
#endif
}
if ((chunk->ext == 5) || (chunk->ext == 6)){
if ((chunk->ext == 5) || (chunk->ext == 6)) { // if Flow/MaskPressure Waveform or OXI Waveform file
if (lastchunk != nullptr) {
Q_ASSERT(lastchunk->sessionid == chunk->sessionid);

View File

@ -50,6 +50,8 @@ struct PRS1Waveform {
};
/*! \class PRS1DataChunk
* \brief Representing a chunk of event/summary/waveform data after the header is parsed. */
class PRS1DataChunk
{
friend class PRS1DataGroup;
@ -87,7 +89,8 @@ public:
class PRS1Loader;
/*! \class PRS1Import
* \brief Contains the functions to parse a single session... multithreaded */
class PRS1Import:public ImportTask
{
public:
@ -101,9 +104,10 @@ public:
delete compliance;
delete summary;
delete event;
for (int i=0;i < waveforms.size(); ++i) {delete waveforms.at(i); }
for (int i=0;i < waveforms.size(); ++i) { delete waveforms.at(i); }
}
//! \brief PRS1Import thread starts execution here.
virtual void run();
PRS1DataChunk * compliance;
@ -115,27 +119,39 @@ public:
QString wavefile;
QString oxifile;
//! \brief As it says on the tin.. Parses .001 files for bricks.
bool ParseCompliance();
//! \brief Figures out which Summary Parser to call, based on machine family/version and calls it.
bool ParseSummary();
//! \brief Figures out which Event Parser to call, based on machine family/version and calls it.
bool ParseEvents();
//! \brief Takes the parsed list of Flow/MaskPressure waveform chunks and adds them to the database
bool ParseWaveforms();
//! \brief Takes the parsed list of oximeter waveform chunks and adds them to the database.
bool ParseOximetery();
//! \brief Summary parser for 50 series Family 0 CPAP/APAP models
bool ParseSummaryF0();
//! \brief Summary parser for 60 series Family 0 CPAP/APAP models
bool ParseSummaryF0V4();
//! \brief Summary parser for 1060 series AVAPS models
bool ParseSummaryF3();
//! \brief Summary parser for 50 series Family 0 BiPAP/AutoSV models
bool ParseSummaryF5V0();
//! \brief Summary parser for 60 series Family 0 BiPAP/AutoSV models
bool ParseSummaryF5V1();
//! \brief Summary parser for DreamStation series CPAP/APAP models
bool ParseSummaryF0V6();
//! \brief Parse a single data chunk from a .002 file containing event data for a standard system one machine
bool ParseF0Events();
//! \brief Parse a single data chunk from a .002 file containing event data for a AVAPS 1060P machine
bool ParseF3Events();
//! \brief Parse a single data chunk from a .002 file containing event data for a family 5 ASV machine (which has a different format)
bool ParseF5Events();
@ -157,13 +173,16 @@ class PRS1Loader : public CPAPLoader
PRS1Loader();
virtual ~PRS1Loader();
//! \brief Examine path and return it back if it contains what looks to be a valid PRS1 SD card structure
QString checkDir(const QString & path);
bool PeekProperties(MachineInfo & info, QString path, Machine * mach = nullptr);
//! \brief Peek into PROP.TXT or properties.txt at given path, and use it to fill MachineInfo structure
bool PeekProperties(MachineInfo & info, QString path, Machine * mach = nullptr);
//! \brief Detect if the given path contains a valid Folder structure
virtual bool Detect(const QString & path);
//! \brief Wrapper for PeekProperties that creates the MachineInfo structure.
virtual MachineInfo PeekInfo(const QString & path);
//! \brief Scans directory path for valid PRS1 signature
@ -175,23 +194,30 @@ class PRS1Loader : public CPAPLoader
//! \brief Return the loaderName, in this case "PRS1"
virtual const QString &loaderName() { return prs1_class_name; }
//! \brief Parse a PRS1 summary/event/waveform file and break into invidivual session or waveform chunks
QList<PRS1DataChunk *> ParseFile(QString path);
//! \brief Register this Module to the list of Loaders, so it knows to search for PRS1 data.
static void Register();
//! \brief Generate a generic MachineInfo structure, with basic PRS1 info to be expanded upon.
virtual MachineInfo newInfo() {
return MachineInfo(MT_CPAP, 0, prs1_class_name, QObject::tr("Philips Respironics"), QString(), QString(), QString(), QObject::tr("System One"), QDateTime::currentDateTime(), prs1_data_version);
}
virtual QString PresReliefLabel() { return QObject::tr(""); }
//! \brief Returns the PRS1 specific code for Pressure Relief Mode
virtual ChannelID PresReliefMode() { return PRS1_FlexMode; }
//! \brief Returns the PRS1 specific code for Pressure Relief Setting
virtual ChannelID PresReliefLevel() { return PRS1_FlexLevel; }
//! \brief Returns the PRS1 specific code for Humidifier Connected
virtual ChannelID HumidifierConnected() { return PRS1_HumidStatus; }
//! \brief Returns the PRS1 specific code for Humidifier Level
virtual ChannelID HumidifierLevel() { return PRS1_HumidLevel; }
//! \brief Called at application init, to set up any custom PRS1 Channels
void initChannels();

View File

@ -35,6 +35,7 @@ const QString STR_UnknownModel = "Resmed S9 ???";
ChannelID RMS9_EPR, RMS9_EPRLevel, RMS9_Mode;
const QString STR_ResMed_AirSense10 = "AirSense 10";
const QString STR_ResMed_AirCurve10= "AirCurve 10";
const QString STR_ResMed_S9 = "S9";
@ -983,12 +984,14 @@ ResmedLoader::ResmedLoader()
{
const QString RMS9_ICON = ":/icons/rms9.png";
const QString RM10_ICON = ":/icons/airsense10.png";
const QString RM10C_ICON = ":/icons/airsense10.png";
m_pixmaps[STR_ResMed_S9] = QPixmap(RMS9_ICON);
m_pixmaps[STR_ResMed_AirSense10] = QPixmap(RM10_ICON);
m_pixmap_paths[STR_ResMed_S9] = RMS9_ICON;
m_pixmaps[STR_ResMed_AirSense10] = QPixmap(RM10_ICON);
m_pixmap_paths[STR_ResMed_AirSense10] = RM10_ICON;
m_pixmaps[STR_ResMed_AirCurve10] = QPixmap(RM10_ICON);
m_pixmap_paths[STR_ResMed_AirCurve10] = RM10_ICON;
m_type = MT_CPAP;
}
ResmedLoader::~ResmedLoader()
@ -1198,6 +1201,9 @@ MachineInfo ResmedLoader::PeekInfo(const QString & path)
} else if (value.contains(STR_ResMed_AirSense10)) {
value.replace(STR_ResMed_AirSense10, "");
info.series = STR_ResMed_AirSense10;
} else if (value.contains(STR_ResMed_AirCurve10)) {
value.replace(STR_ResMed_AirCurve10, "");
info.series = STR_ResMed_AirCurve10;
}
value.replace("(","");
value.replace(")","");
@ -1922,12 +1928,15 @@ int ResmedLoader::Open(QString path)
} else if (key == "PNA") { // Product Name
value.replace("_"," ");
if (value.contains("S9")) {
value.replace("S9", "");
info.series = "S9";
} else if (value.contains("AirSense 10")) {
value.replace("AirSense 10", "");
info.series = "AirSense 10";
if (value.contains(STR_ResMed_S9)) {
value.replace(STR_ResMed_S9, "");
info.series = STR_ResMed_S9;
} else if (value.contains(STR_ResMed_AirSense10)) {
value.replace(STR_ResMed_AirSense10, "");
info.series = STR_ResMed_AirSense10;
} else if (value.contains(STR_ResMed_AirCurve10)) {
value.replace(STR_ResMed_AirCurve10, "");
info.series = STR_ResMed_AirCurve10;
}
value.replace("(","");
value.replace(")","");

View File

@ -121,7 +121,7 @@ void init()
// Pressure Related Settings
schema::channel.add(GRP_CPAP, new Channel(CPAP_Pressure = 0x110C, WAVEFORM, MT_CPAP, SESSION, "Pressure",
STR_TR_Pressure, QObject::tr("Therapy Pressure"), STR_TR_Pressure,
STR_UNIT_CMH2O, DEFAULT, QColor("dark green")));
STR_UNIT_CMH2O, DEFAULT, QColor("red")));
schema::channel.add(GRP_CPAP, new Channel(CPAP_IPAP = 0x110D, WAVEFORM, MT_CPAP, SESSION, "IPAP",
STR_TR_IPAP, QObject::tr("Inspiratory Pressure"), STR_TR_IPAP,