2019-05-03 18:45:21 +00:00
/* SleepLib PRS1 Loader Header
2014-04-09 21:01:57 +00:00
*
2020-01-07 02:45:52 +00:00
* Copyright ( c ) 2019 - 2020 The OSCAR Team
2018-03-28 07:10:52 +00:00
* Copyright ( C ) 2011 - 2018 Mark Watkins < mark @ jedimark . net >
2014-04-09 21:01:57 +00:00
*
* This file is subject to the terms and conditions of the GNU General Public
2018-06-04 20:48:38 +00:00
* License . See the file COPYING in the main directory of the source code
* for more details . */
2011-06-26 08:30:44 +00:00
# ifndef PRS1LOADER_H
# define PRS1LOADER_H
//#include <map>
//using namespace std;
# include "SleepLib/machine.h" // Base class: MachineLoader
# include "SleepLib/machine_loader.h"
# include "SleepLib/profiles.h"
2019-05-05 01:50:45 +00:00
# ifdef UNITTEST_MODE
# define private public
# define protected public
# endif
2011-06-26 08:30:44 +00:00
//********************************************************************************************
/// IMPORTANT!!!
//********************************************************************************************
2018-05-05 15:48:32 +00:00
// Please INCREMENT the following value when making changes to this loaders implementation
// BEFORE making a release
2019-12-28 04:10:02 +00:00
const int prs1_data_version = 17 ;
2011-06-26 08:30:44 +00:00
//
//********************************************************************************************
2019-05-27 14:05:16 +00:00
#if 0 // Apparently unused
2011-12-19 05:35:05 +00:00
/*! \class PRS1
\ brief PRS1 customized machine object ( via CPAP )
*/
2014-04-17 05:58:57 +00:00
class PRS1 : public CPAP
2011-06-26 08:30:44 +00:00
{
2014-04-17 05:58:57 +00:00
public :
2018-06-04 23:26:46 +00:00
PRS1 ( Profile * , MachineID id = 0 ) ;
2011-06-26 08:30:44 +00:00
virtual ~ PRS1 ( ) ;
} ;
2014-04-17 05:58:57 +00:00
const int max_load_buffer_size = 1024 * 1024 ;
2019-05-27 14:05:16 +00:00
# endif
2014-05-31 21:25:07 +00:00
const QString prs1_class_name = STR_MACH_PRS1 ;
/*! \struct PRS1Waveform
\ brief Used in PRS1 Waveform Parsing */
struct PRS1Waveform {
PRS1Waveform ( quint16 i , quint8 f ) {
interleave = i ;
sample_format = f ;
}
quint16 interleave ;
quint8 sample_format ;
} ;
2011-06-26 08:30:44 +00:00
2016-03-02 02:09:32 +00:00
/*! \class PRS1DataChunk
* \ brief Representing a chunk of event / summary / waveform data after the header is parsed . */
2014-05-31 21:25:07 +00:00
class PRS1DataChunk
{
public :
2020-01-05 01:47:28 +00:00
/*
2014-05-31 21:25:07 +00:00
PRS1DataChunk ( ) {
2019-05-15 02:49:41 +00:00
fileVersion = 0 ;
blockSize = 0 ;
2014-05-31 21:25:07 +00:00
htype = 0 ;
family = 0 ;
familyVersion = 0 ;
2019-05-18 23:17:55 +00:00
ext = 255 ;
2019-05-15 02:49:41 +00:00
sessionid = 0 ;
2019-05-18 23:17:55 +00:00
timestamp = 0 ;
2019-05-15 02:49:41 +00:00
2014-05-31 21:25:07 +00:00
duration = 0 ;
2019-05-15 12:36:31 +00:00
m_filepos = - 1 ;
m_index = - 1 ;
2014-05-31 21:25:07 +00:00
}
2020-01-05 01:47:28 +00:00
*/
PRS1DataChunk ( class QFile & f , class PRS1Loader * loader ) ;
2019-05-22 15:00:45 +00:00
~ PRS1DataChunk ( ) ;
2014-05-31 21:25:07 +00:00
inline int size ( ) const { return m_data . size ( ) ; }
2019-05-14 22:57:04 +00:00
QByteArray m_header ;
2014-05-31 21:25:07 +00:00
QByteArray m_data ;
2016-01-19 04:26:28 +00:00
QByteArray m_headerblock ;
2019-05-22 15:00:45 +00:00
QList < class PRS1ParsedEvent * > m_parsedData ;
2014-05-31 21:25:07 +00:00
2019-05-14 20:20:32 +00:00
QString m_path ;
qint64 m_filepos ; // file offset
int m_index ; // nth chunk in file
2019-05-15 02:49:41 +00:00
inline void SetIndex ( int index ) { m_index = index ; }
2014-05-31 21:25:07 +00:00
2019-05-18 23:17:55 +00:00
// Common fields
2014-05-31 21:25:07 +00:00
quint8 fileVersion ;
2019-05-14 22:57:04 +00:00
quint16 blockSize ;
2014-05-31 21:25:07 +00:00
quint8 htype ;
quint8 family ;
quint8 familyVersion ;
2019-05-18 23:17:55 +00:00
quint8 ext ;
2019-05-15 02:49:41 +00:00
SessionID sessionid ;
2019-05-18 23:17:55 +00:00
quint32 timestamp ;
2014-05-31 21:25:07 +00:00
2019-05-18 23:17:55 +00:00
// Waveform-specific fields
quint16 interval_count ;
quint8 interval_seconds ;
int duration ;
2014-05-31 21:25:07 +00:00
QList < PRS1Waveform > waveformInfo ;
2019-05-18 23:17:55 +00:00
// V3 normal/non-waveform fields
2018-05-05 15:48:32 +00:00
QMap < unsigned char , short > hblock ;
2019-05-23 00:11:48 +00:00
QMap < unsigned char , QByteArray > mainblock ;
QMap < unsigned char , QByteArray > hbdata ;
2019-05-15 00:47:00 +00:00
2019-05-18 23:17:55 +00:00
// Trailing common fields
2019-05-15 00:47:00 +00:00
quint8 storedChecksum ; // header checksum stored in file, last byte of m_header
2019-05-15 19:16:14 +00:00
quint8 calcChecksum ; // header checksum as calculated when parsing
quint32 storedCrc ; // header + data CRC stored in file, last 2-4 bytes of chunk
quint32 calcCrc ; // header + data CRC as calculated when parsing
2019-05-15 02:49:41 +00:00
2019-10-25 21:27:35 +00:00
//! \brief Calculate a simplistic hash to check whether two chunks are identical.
inline quint64 hash ( void ) const { return ( ( ( ( quint64 ) this - > calcCrc ) < < 32 ) | this - > timestamp ) ; }
2019-05-15 02:49:41 +00:00
//! \brief Parse and return the next chunk from a PRS1 file
2020-01-05 01:47:28 +00:00
static PRS1DataChunk * ParseNext ( class QFile & f , class PRS1Loader * loader ) ;
2019-05-15 02:49:41 +00:00
//! \brief Read and parse the next chunk header from a PRS1 file
bool ReadHeader ( class QFile & f ) ;
2019-05-15 12:36:31 +00:00
//! \brief Read the chunk's data from a PRS1 file and calculate its CRC, must be called after ReadHeader
bool ReadData ( class QFile & f ) ;
2019-05-15 14:26:31 +00:00
2019-06-06 20:08:40 +00:00
//! \brief Figures out which Compliance Parser to call, based on machine family/version and calls it.
2019-05-26 18:17:58 +00:00
bool ParseCompliance ( void ) ;
2019-06-06 20:08:40 +00:00
//! \brief Parse a single data chunk from a .000 file containing compliance data for a P25x brick
bool ParseComplianceF0V23 ( void ) ;
//! \brief Parse a single data chunk from a .000 file containing compliance data for a DreamStation 200X brick
bool ParseComplianceF0V6 ( void ) ;
2019-05-27 15:14:55 +00:00
//! \brief Figures out which Summary Parser to call, based on machine family/version and calls it.
bool ParseSummary ( ) ;
2019-05-26 01:57:29 +00:00
//! \brief Parse a single data chunk from a .001 file containing summary data for a family 0 CPAP/APAP family version 2 or 3 machine
bool ParseSummaryF0V23 ( void ) ;
2019-05-26 01:25:56 +00:00
//! \brief Parse a single data chunk from a .001 file containing summary data for a family 0 CPAP/APAP family version 4 machine
bool ParseSummaryF0V4 ( void ) ;
2019-05-26 01:08:53 +00:00
//! \brief Parse a single data chunk from a .001 file containing summary data for a family 0 CPAP/APAP family version 6 machine
bool ParseSummaryF0V6 ( void ) ;
2019-07-24 00:54:39 +00:00
//! \brief Parse a single data chunk from a .001 file containing summary data for a family 3 ventilator (family version 3) machine
bool ParseSummaryF3V3 ( void ) ;
2019-07-24 00:40:24 +00:00
//! \brief Parse a single data chunk from a .001 file containing summary data for a family 3 ventilator (family version 6) machine
bool ParseSummaryF3V6 ( void ) ;
2019-05-25 23:43:35 +00:00
2019-05-25 23:21:46 +00:00
//! \brief Parse a single data chunk from a .001 file containing summary data for a family 5 ASV family version 0-2 machine
bool ParseSummaryF5V012 ( void ) ;
2019-05-23 00:11:48 +00:00
//! \brief Parse a single data chunk from a .001 file containing summary data for a family 5 ASV family version 3 machine
bool ParseSummaryF5V3 ( void ) ;
2019-05-24 23:41:42 +00:00
2020-01-12 21:53:43 +00:00
//! \brief Parse a flex setting byte from a .000 or .001 containing compliance/summary data for CPAP/APAP family versions 2, 3, or 4
void ParseFlexSettingF0V234 ( quint8 flex , int prs1mode ) ;
//! \brief Parse a flex setting byte from a .000 or .001 containing compliance/summary data for ASV family versions 0, 1, or 2
void ParseFlexSettingF5V012 ( quint8 flex , int prs1mode ) ;
2019-05-26 21:36:12 +00:00
2020-01-10 17:39:54 +00:00
//! \brief Parse an humidifier setting byte from a .000 or .001 containing compliance/summary data for original System One (50-Series) machines: F0V23 and F5V0
2020-01-10 17:57:18 +00:00
void ParseHumidifierSetting50Series ( int humid , bool add_setting = false ) ;
2019-06-07 20:40:26 +00:00
2020-01-10 21:44:00 +00:00
//! \brief Parse an humidifier setting byte from a .000 or .001 containing compliance/summary data for F0V4 and F5V012 (60-Series) machines
void ParseHumidifierSetting60Series ( unsigned char humid1 , unsigned char humid2 , bool add_setting = false ) ;
2019-09-29 00:44:18 +00:00
2020-01-10 21:44:00 +00:00
//! \brief Parse an humidifier setting byte from a .000 or .001 containing compliance/summary data for F3V3 machines (differs from other 60-Series machines)
2019-10-03 16:33:28 +00:00
void ParseHumidifierSettingF3V3 ( unsigned char humid1 , unsigned char humid2 , bool add_setting = false ) ;
2019-06-14 00:31:21 +00:00
//! \brief Parse humidifier setting bytes from a .000 or .001 containing compliance/summary data for fileversion 3 machines
void ParseHumidifierSettingV3 ( unsigned char byte1 , unsigned char byte2 , bool add_setting = false ) ;
2019-06-07 20:40:26 +00:00
2019-09-20 01:29:33 +00:00
//! \brief Parse tubing type from a .001 containing summary data for fileversion 3 machines
void ParseTubingTypeV3 ( unsigned char type ) ;
2019-05-29 15:20:20 +00:00
//! \brief Figures out which Event Parser to call, based on machine family/version and calls it.
2019-10-09 17:35:02 +00:00
bool ParseEvents ( void ) ;
2019-05-29 15:20:20 +00:00
2019-05-25 21:00:44 +00:00
//! \brief Parse a single data chunk from a .002 file containing event data for a family 0 CPAP/APAP machine
2019-10-09 17:35:02 +00:00
bool ParseEventsF0V23 ( void ) ;
2019-10-03 20:50:59 +00:00
//! \brief Parse a single data chunk from a .002 file containing event data for a 60 Series family 0 CPAP/APAP 60machine
2019-10-09 17:35:02 +00:00
bool ParseEventsF0V4 ( void ) ;
2019-05-25 21:00:44 +00:00
2019-08-05 00:36:40 +00:00
//! \brief Parse a single data chunk from a .002 file containing event data for a DreamStation family 0 CPAP/APAP machine
2019-10-09 17:35:02 +00:00
bool ParseEventsF0V6 ( void ) ;
2019-08-05 00:36:40 +00:00
2019-05-25 00:09:53 +00:00
//! \brief Parse a single data chunk from a .002 file containing event data for a family 3 ventilator family version 3 machine
bool ParseEventsF3V3 ( void ) ;
2019-05-24 23:41:42 +00:00
//! \brief Parse a single data chunk from a .002 file containing event data for a family 3 ventilator family version 6 machine
bool ParseEventsF3V6 ( void ) ;
2019-05-23 00:11:48 +00:00
2019-10-05 00:10:35 +00:00
//! \brief Parse a single data chunk from a .002 file containing event data for a family 5 ASV family version 0 machine
bool ParseEventsF5V0 ( void ) ;
//! \brief Parse a single data chunk from a .002 file containing event data for a family 5 ASV family version 1 machine
bool ParseEventsF5V1 ( void ) ;
//! \brief Parse a single data chunk from a .002 file containing event data for a family 5 ASV family version 2 machine
bool ParseEventsF5V2 ( void ) ;
2019-05-24 21:08:51 +00:00
2019-05-22 15:00:45 +00:00
//! \brief Parse a single data chunk from a .002 file containing event data for a family 5 ASV family version 3 machine
2019-05-23 00:11:48 +00:00
bool ParseEventsF5V3 ( void ) ;
2019-05-22 15:00:45 +00:00
2019-05-15 14:26:31 +00:00
protected :
2020-01-05 01:47:28 +00:00
class PRS1Loader * loader ;
2019-05-22 15:00:45 +00:00
//! \brief Add a parsed event to the chunk
void AddEvent ( class PRS1ParsedEvent * event ) ;
2019-05-15 16:32:39 +00:00
//! \brief Read and parse the non-waveform header data from a V2 PRS1 file
bool ReadNormalHeaderV2 ( class QFile & f ) ;
//! \brief Read and parse the non-waveform header data from a V3 PRS1 file
bool ReadNormalHeaderV3 ( class QFile & f ) ;
2019-05-15 14:26:31 +00:00
//! \brief Read and parse the waveform-specific header data from a PRS1 file
bool ReadWaveformHeader ( class QFile & f ) ;
2019-05-15 19:16:14 +00:00
//! \brief Extract the stored CRC from the end of the data of a PRS1 chunk
bool ExtractStoredCrc ( int size ) ;
2019-06-07 00:19:46 +00:00
2019-09-24 20:27:27 +00:00
//! \brief Parse a settings slice from a .000 and .001 file
bool ParseSettingsF0V23 ( const unsigned char * data , int size ) ;
//! \brief Parse a settings slice from a .000 and .001 file
bool ParseSettingsF0V4 ( const unsigned char * data , int size ) ;
2019-06-14 00:31:21 +00:00
//! \brief Parse a settings slice from a .000 and .001 file
2019-06-07 00:19:46 +00:00
bool ParseSettingsF0V6 ( const unsigned char * data , int size ) ;
2019-06-14 00:31:21 +00:00
2019-10-01 15:38:16 +00:00
//! \brief Parse a settings slice from a .000 and .001 file
bool ParseSettingsF5V012 ( const unsigned char * data , int size ) ;
2019-06-14 00:31:21 +00:00
//! \brief Parse a settings slice from a .000 and .001 file
bool ParseSettingsF5V3 ( const unsigned char * data , int size ) ;
2019-07-24 20:50:51 +00:00
2019-10-01 15:38:16 +00:00
//! \brief Parse a settings slice from a .000 and .001 file
bool ParseSettingsF3V3 ( const unsigned char * data , int size ) ;
2019-07-24 20:50:51 +00:00
//! \brief Parse a settings slice from a .000 and .001 file
bool ParseSettingsF3V6 ( const unsigned char * data , int size ) ;
2014-05-31 21:25:07 +00:00
} ;
2019-05-29 16:11:53 +00:00
# if UNITTEST_MODE
QString _PRS1ParsedEventName ( PRS1ParsedEvent * e ) ;
QMap < QString , QString > _PRS1ParsedEventContents ( PRS1ParsedEvent * e ) ;
# endif
2014-08-04 15:40:56 +00:00
class PRS1Loader ;
2016-03-02 02:09:32 +00:00
/*! \class PRS1Import
* \ brief Contains the functions to parse a single session . . . multithreaded */
2014-08-04 15:40:56 +00:00
class PRS1Import : public ImportTask
2014-05-31 21:25:07 +00:00
{
public :
2019-12-01 21:42:54 +00:00
PRS1Import ( PRS1Loader * l , SessionID s , Machine * m , int base ) : loader ( l ) , sessionid ( s ) , mach ( m ) , m_sessionid_base ( base ) {
2014-08-04 15:40:56 +00:00
summary = nullptr ;
compliance = nullptr ;
2014-05-31 21:25:07 +00:00
session = nullptr ;
2019-11-19 17:29:45 +00:00
m_currentSliceInitialized = false ;
2014-05-31 21:25:07 +00:00
}
2014-08-04 15:40:56 +00:00
virtual ~ PRS1Import ( ) {
2014-05-31 21:25:07 +00:00
delete compliance ;
delete summary ;
2019-10-24 20:25:36 +00:00
for ( auto & e : m_event_chunks . values ( ) ) { delete e ; }
2016-03-02 02:09:32 +00:00
for ( int i = 0 ; i < waveforms . size ( ) ; + + i ) { delete waveforms . at ( i ) ; }
2020-01-29 15:43:58 +00:00
for ( auto & c : oximetry ) { delete c ; }
2014-05-31 21:25:07 +00:00
}
2014-09-17 06:59:58 +00:00
2016-03-02 02:09:32 +00:00
//! \brief PRS1Import thread starts execution here.
2014-08-04 15:40:56 +00:00
virtual void run ( ) ;
PRS1DataChunk * compliance ;
PRS1DataChunk * summary ;
2019-10-24 20:25:36 +00:00
QMap < qint64 , PRS1DataChunk * > m_event_chunks ;
2014-08-04 15:40:56 +00:00
QList < PRS1DataChunk * > waveforms ;
2018-06-04 20:48:38 +00:00
QList < PRS1DataChunk * > oximetry ;
2014-08-04 15:40:56 +00:00
2018-05-05 15:48:32 +00:00
2019-10-26 01:17:41 +00:00
QList < QString > m_wavefiles ;
2014-09-29 14:41:31 +00:00
QString oxifile ;
2014-05-31 21:25:07 +00:00
2019-05-31 20:58:58 +00:00
//! \brief Imports .000 files for bricks.
bool ImportCompliance ( ) ;
2016-03-02 02:09:32 +00:00
2019-05-31 20:58:58 +00:00
//! \brief Imports the .001 summary file.
2019-05-27 14:25:57 +00:00
bool ImportSummary ( ) ;
2019-10-24 20:25:36 +00:00
//! \brief Imports the .002 event file(s).
bool ImportEvents ( ) ;
2016-03-02 02:09:32 +00:00
2019-10-26 01:17:41 +00:00
//! \brief Imports the .005 event file(s).
2020-01-28 21:04:34 +00:00
void ImportWaveforms ( ) ;
2019-10-26 01:17:41 +00:00
2019-05-14 01:20:11 +00:00
//! \brief Coalesce contiguous .005 or .006 waveform chunks from the file into larger chunks for import.
QList < PRS1DataChunk * > CoalesceWaveformChunks ( QList < PRS1DataChunk * > & allchunks ) ;
2016-03-02 02:09:32 +00:00
//! \brief Takes the parsed list of Flow/MaskPressure waveform chunks and adds them to the database
2020-01-28 21:04:34 +00:00
void ParseWaveforms ( ) ;
2016-03-02 02:09:32 +00:00
//! \brief Takes the parsed list of oximeter waveform chunks and adds them to the database.
2020-01-28 21:04:34 +00:00
void ParseOximetry ( ) ;
//! \brief Adds a single channel of continuous oximetry data to the database, splitting on any missing samples.
void ImportOximetryChannel ( ChannelID channel , QByteArray & data , quint64 ti , qint64 dur ) ;
2014-09-29 14:41:31 +00:00
2014-05-31 21:25:07 +00:00
protected :
2014-08-04 15:40:56 +00:00
Session * session ;
2014-05-31 21:25:07 +00:00
PRS1Loader * loader ;
SessionID sessionid ;
Machine * mach ;
2019-10-20 21:46:18 +00:00
QHash < ChannelID , EventList * > m_importChannels ; // map channel ID to the session's current EventList*
2014-08-17 12:56:05 +00:00
int summary_duration ;
2019-12-01 21:42:54 +00:00
int m_sessionid_base ; // base for inferring session ID from filename
2019-05-03 18:45:21 +00:00
2019-08-29 01:30:25 +00:00
//! \brief Translate the PRS1-specific machine mode to the importable vendor-neutral enum.
CPAPMode importMode ( int mode ) ;
2019-05-03 18:45:21 +00:00
//! \brief Parse all the chunks in a single machine session
bool ParseSession ( void ) ;
//! \brief Save parsed session data to the database
void SaveSessionToDatabase ( void ) ;
2019-10-20 21:46:18 +00:00
2019-11-09 20:09:02 +00:00
//! \brief Cache a single slice from a summary or compliance chunk.
void AddSlice ( qint64 chunk_start , PRS1ParsedEvent * e ) ;
QVector < SessionSlice > m_slices ;
2019-11-07 22:35:09 +00:00
2019-11-07 19:19:58 +00:00
//! \brief Import a single event from a data chunk.
void ImportEvent ( qint64 t , PRS1ParsedEvent * event ) ;
// State that needs to persist between individual events:
EventDataType m_currentPressure ;
bool m_calcPSfromSet ;
bool m_calcLeaks ;
EventDataType m_lpm4 , m_ppm ;
2019-11-19 17:29:45 +00:00
//! \brief Advance the current mask-on slice if needed and update import data structures accordingly.
bool UpdateCurrentSlice ( PRS1DataChunk * chunk , qint64 t ) ;
bool m_currentSliceInitialized ;
QVector < SessionSlice > : : const_iterator m_currentSlice ;
2020-01-07 02:45:52 +00:00
qint64 m_statIntervalStart , m_prevIntervalStart ;
QList < PRS1ParsedEvent * > m_lastIntervalEvents ;
qint64 m_lastIntervalEnd ;
EventDataType m_intervalPressure ;
//! \brief Write out any pending end-of-slice events.
void FinishSlice ( ) ;
//! \brief Record the beginning timestamp of a new stat interval, and do related housekeeping.
void StartNewInterval ( qint64 t ) ;
2019-11-17 01:07:52 +00:00
//! \brief Identify statistical events that are reported at the end of an interval.
bool IsIntervalEvent ( PRS1ParsedEvent * e ) ;
2019-10-24 01:10:56 +00:00
//! \brief Import a single data chunk from a .002 file containing event data.
2019-10-24 20:25:36 +00:00
bool ImportEventChunk ( PRS1DataChunk * event ) ;
2019-10-20 21:46:18 +00:00
//! \brief Create all supported channels (except for on-demand ones that only get created if an event appears).
2019-11-09 20:09:02 +00:00
void CreateEventChannels ( const PRS1DataChunk * event ) ;
2019-10-20 21:46:18 +00:00
//! \brief Get the EventList* for the import channel, creating it if necessary.
EventList * GetImportChannel ( ChannelID channel ) ;
//! \brief Import a single event to a channel, creating the channel if necessary.
2019-11-09 20:09:02 +00:00
void AddEvent ( ChannelID channel , qint64 t , float value , float gain ) ;
2014-05-31 21:25:07 +00:00
} ;
2011-06-26 08:30:44 +00:00
2011-12-19 05:35:05 +00:00
/*! \class PRS1Loader
\ brief Philips Respironics System One Loader Module
*/
2014-08-03 13:00:13 +00:00
class PRS1Loader : public CPAPLoader
2011-06-26 08:30:44 +00:00
{
2018-06-12 16:32:18 +00:00
Q_OBJECT
2014-04-17 05:58:57 +00:00
public :
2011-06-26 08:30:44 +00:00
PRS1Loader ( ) ;
virtual ~ PRS1Loader ( ) ;
2014-04-26 09:54:08 +00:00
2019-05-27 14:05:16 +00:00
//! \brief Peek into PROP.TXT or properties.txt at given path, and return it as a normalized key/value hash
bool PeekProperties ( const QString & filename , QHash < QString , QString > & props ) ;
2016-03-02 02:09:32 +00:00
//! \brief Peek into PROP.TXT or properties.txt at given path, and use it to fill MachineInfo structure
2018-04-27 04:29:03 +00:00
bool PeekProperties ( MachineInfo & info , const QString & path , Machine * mach = nullptr ) ;
2014-09-29 14:41:31 +00:00
2014-04-26 09:54:08 +00:00
//! \brief Detect if the given path contains a valid Folder structure
virtual bool Detect ( const QString & path ) ;
2016-03-02 02:09:32 +00:00
//! \brief Wrapper for PeekProperties that creates the MachineInfo structure.
2014-09-29 14:41:31 +00:00
virtual MachineInfo PeekInfo ( const QString & path ) ;
2011-12-19 05:35:05 +00:00
//! \brief Scans directory path for valid PRS1 signature
2018-04-27 04:29:03 +00:00
virtual int Open ( const QString & path ) ;
2011-12-19 05:35:05 +00:00
//! \brief Returns the database version of this loader
2011-07-15 13:30:41 +00:00
virtual int Version ( ) { return prs1_data_version ; }
2011-12-19 05:35:05 +00:00
2014-07-28 13:56:29 +00:00
//! \brief Return the loaderName, in this case "PRS1"
virtual const QString & loaderName ( ) { return prs1_class_name ; }
2011-12-19 05:35:05 +00:00
2016-03-02 02:09:32 +00:00
//! \brief Parse a PRS1 summary/event/waveform file and break into invidivual session or waveform chunks
2018-04-27 04:29:03 +00:00
QList < PRS1DataChunk * > ParseFile ( const QString & path ) ;
2014-08-04 15:40:56 +00:00
2011-12-19 05:35:05 +00:00
//! \brief Register this Module to the list of Loaders, so it knows to search for PRS1 data.
2011-06-26 08:30:44 +00:00
static void Register ( ) ;
2014-07-11 06:13:44 +00:00
2016-03-02 02:09:32 +00:00
//! \brief Generate a generic MachineInfo structure, with basic PRS1 info to be expanded upon.
2014-07-28 13:56:29 +00:00
virtual MachineInfo newInfo ( ) {
2014-08-03 13:00:13 +00:00
return MachineInfo ( MT_CPAP , 0 , prs1_class_name , QObject : : tr ( " Philips Respironics " ) , QString ( ) , QString ( ) , QString ( ) , QObject : : tr ( " System One " ) , QDateTime : : currentDateTime ( ) , prs1_data_version ) ;
2014-07-28 13:56:29 +00:00
}
2014-08-04 15:40:56 +00:00
2020-03-24 21:15:29 +00:00
virtual QString PresReliefLabel ( ) ;
2016-03-02 02:09:32 +00:00
//! \brief Returns the PRS1 specific code for Pressure Relief Mode
2020-03-24 21:15:29 +00:00
virtual ChannelID PresReliefMode ( ) ;
2016-03-02 02:09:32 +00:00
//! \brief Returns the PRS1 specific code for Pressure Relief Setting
2020-03-24 21:15:29 +00:00
virtual ChannelID PresReliefLevel ( ) ;
//! \brief Returns the PRS1 specific code for PAP mode
virtual ChannelID CPAPModeChannel ( ) ;
2014-07-28 13:56:29 +00:00
2016-03-02 02:09:32 +00:00
//! \brief Returns the PRS1 specific code for Humidifier Connected
2020-03-24 21:15:29 +00:00
virtual ChannelID HumidifierConnected ( ) ;
2016-03-02 02:09:32 +00:00
//! \brief Returns the PRS1 specific code for Humidifier Level
2020-03-24 21:15:29 +00:00
virtual ChannelID HumidifierLevel ( ) ;
2014-08-04 16:12:49 +00:00
2016-03-02 02:09:32 +00:00
//! \brief Called at application init, to set up any custom PRS1 Channels
2014-08-06 14:06:44 +00:00
void initChannels ( ) ;
2014-08-04 16:12:49 +00:00
2014-08-04 15:40:56 +00:00
QHash < SessionID , PRS1Import * > sesstasks ;
2014-07-11 06:13:44 +00:00
2014-04-17 05:58:57 +00:00
protected :
2011-06-26 08:30:44 +00:00
QString last ;
2014-04-17 05:58:57 +00:00
QHash < QString , Machine * > PRS1List ;
2011-12-19 05:35:05 +00:00
2020-03-09 14:48:10 +00:00
//! \brief Returns the path of the P-Series folder (whatever case) if present on the card
QString GetPSeriesPath ( const QString & path ) ;
2020-03-09 14:28:34 +00:00
//! \brief Returns the path for each machine detected on an SD card, from oldest to newest
QStringList FindMachinesOnCard ( const QString & cardPath ) ;
2011-12-19 05:35:05 +00:00
//! \brief Opens the SD folder structure for this machine, scans for data files and imports any new sessions
2018-04-27 04:29:03 +00:00
int OpenMachine ( const QString & path ) ;
2011-12-19 05:35:05 +00:00
2019-05-03 20:59:26 +00:00
//! \brief Finds the P0,P1,... session paths and property pathname and returns the base (10 or 16) of the session filenames
int FindSessionDirsAndProperties ( const QString & path , QStringList & paths , QString & propertyfile ) ;
//! \brief Reads the model number from the property file, evaluates its capabilities, and returns a machine instance
Machine * CreateMachineFromProperties ( QString propertyfile ) ;
//! \brief Scans the given directories for session data and create an import task for each logical session.
2019-05-03 19:07:15 +00:00
void ScanFiles ( const QStringList & paths , int sessionid_base , Machine * m ) ;
2014-09-30 05:25:11 +00:00
// //! \brief Parses "properties.txt" file containing machine information
// bool ParseProperties(Machine *m, QString filename);
2011-12-19 05:35:05 +00:00
//! \brief Parse a .005 waveform file, extracting Flow Rate waveform (and Mask Pressure data if available)
2018-04-27 04:29:03 +00:00
bool OpenWaveforms ( SessionID sid , const QString & filename ) ;
2011-12-19 05:35:05 +00:00
//! \brief Parse a data chunk from the .000 (brick) and .001 (summary) files.
2014-04-17 05:58:57 +00:00
bool ParseSummary ( Machine * mach , qint32 sequence , quint32 timestamp , unsigned char * data ,
quint16 size , int family , int familyVersion ) ;
2011-12-19 05:35:05 +00:00
2011-12-10 12:14:48 +00:00
2011-12-19 05:35:05 +00:00
//! \brief Open a PRS1 data file, and break into data chunks, delivering them to the correct parser.
2018-04-27 04:29:03 +00:00
bool OpenFile ( Machine * mach , const QString & filename ) ;
2011-12-19 05:35:05 +00:00
2011-12-06 14:39:14 +00:00
QHash < SessionID , Session * > extra_session ;
2011-12-19 05:35:05 +00:00
//! \brief PRS1 Data files can store multiple sessions, so store them in this list for later processing.
2011-12-10 12:14:48 +00:00
QHash < SessionID , Session * > new_sessions ;
2020-01-05 01:47:28 +00:00
// TODO: This really belongs in a generic location that all loaders can use.
// But that will require retooling the overall call structure so that there's
// a top-level import job that's managing a specific import. Right now it's
// essentially managed by the importCPAP method rather than an object instance
// with state.
QMutex m_importMutex ;
QSet < QString > m_unexpectedMessages ;
public :
void LogUnexpectedMessage ( const QString & message ) ;
2011-12-10 12:14:48 +00:00
} ;
2019-05-27 14:05:16 +00:00
//********************************************************************************************
class PRS1ModelInfo
{
protected :
QHash < int , QHash < int , QStringList > > m_testedModels ;
2019-06-20 04:09:28 +00:00
QHash < QString , const char * > m_modelNames ;
2019-06-20 02:19:16 +00:00
QSet < QString > m_bricks ;
2019-05-27 14:05:16 +00:00
public :
PRS1ModelInfo ( ) ;
bool IsSupported ( const QHash < QString , QString > & properties ) const ;
bool IsSupported ( int family , int familyVersion ) const ;
bool IsTested ( const QHash < QString , QString > & properties ) const ;
bool IsTested ( const QString & modelNumber , int family , int familyVersion ) const ;
2019-06-20 02:19:16 +00:00
bool IsBrick ( const QString & model ) const ;
2019-06-20 04:09:28 +00:00
const char * Name ( const QString & model ) const ;
2019-05-27 14:05:16 +00:00
} ;
2011-06-26 08:30:44 +00:00
# endif // PRS1LOADER_H