2011-06-26 08:30:44 +00:00
/*
SleepLib PRS1 Loader Implementation
Author : Mark Watkins < jedimark64 @ users . sourceforge . net >
License : GPL
*/
# include <QString>
# include <QDateTime>
# include <QDir>
# include <QFile>
# include <QMessageBox>
# include <QProgressBar>
2011-07-01 10:10:44 +00:00
# include <QDebug>
2011-06-26 08:30:44 +00:00
# include "prs1_loader.h"
# include "SleepLib/session.h"
2011-07-10 14:23:07 +00:00
const int PRS1_MAGIC_NUMBER = 2 ;
const int PRS1_SUMMARY_FILE = 1 ;
const int PRS1_EVENT_FILE = 2 ;
const int PRS1_WAVEFORM_FILE = 5 ;
2011-06-26 08:30:44 +00:00
//********************************************************************************************
/// IMPORTANT!!!
//********************************************************************************************
// Please INCREMENT the prs1_data_version in prs1_loader.h when making changes to this loader
// that change loader behaviour or modify channels.
//********************************************************************************************
extern QProgressBar * qprogress ;
map < int , QString > ModelMap ;
PRS1 : : PRS1 ( Profile * p , MachineID id ) : CPAP ( p , id )
{
m_class = prs1_class_name ;
properties [ " Brand " ] = " Philips Respironics " ;
properties [ " Model " ] = " System One " ;
//SleepFlags= { CPAP_RERA, PRS1_VSnore2, CPAP_FlowLimit, CPAP_Hypopnea, CPAP_Obstructive, CPAP_ClearAirway, CPAP_CSR };
}
PRS1 : : ~ PRS1 ( )
{
}
PRS1Loader : : PRS1Loader ( )
{
m_buffer = new unsigned char [ max_load_buffer_size ] ; //allocate once and reuse.
}
PRS1Loader : : ~ PRS1Loader ( )
{
for ( map < QString , Machine * > : : iterator i = PRS1List . begin ( ) ; i ! = PRS1List . end ( ) ; i + + ) {
delete i - > second ;
}
delete [ ] m_buffer ;
}
Machine * PRS1Loader : : CreateMachine ( QString serial , Profile * profile )
{
2011-07-01 10:10:44 +00:00
qDebug ( ) < < " Create Machine " < < serial ;
2011-06-26 08:30:44 +00:00
assert ( profile ! = NULL ) ;
vector < Machine * > ml = profile - > GetMachines ( MT_CPAP ) ;
bool found = false ;
for ( vector < Machine * > : : iterator i = ml . begin ( ) ; i ! = ml . end ( ) ; i + + ) {
if ( ( ( * i ) - > GetClass ( ) = = " PRS1 " ) & & ( ( * i ) - > properties [ " Serial " ] = = serial ) ) {
PRS1List [ serial ] = * i ; //static_cast<CPAP *>(*i);
found = true ;
break ;
}
}
if ( found ) return PRS1List [ serial ] ;
//assert(PRS1List.find(serial)==PRS1List.end())
Machine * m = new PRS1 ( profile , 0 ) ;
PRS1List [ serial ] = m ;
profile - > AddMachine ( m ) ;
m - > properties [ " Serial " ] = serial ;
return m ;
}
bool isdigit ( QChar c )
{
if ( ( c > = ' 0 ' ) & & ( c < = ' 9 ' ) ) return true ;
return false ;
}
2011-07-15 13:30:41 +00:00
int PRS1Loader : : Open ( QString & path , Profile * profile )
2011-06-26 08:30:44 +00:00
{
QString newpath ;
QString pseries = " P-Series " ;
if ( path . endsWith ( " / " + pseries ) ) {
newpath = path ;
} else {
newpath = path + " / " + pseries ;
}
QDir dir ( newpath ) ;
if ( ( ! dir . exists ( ) | | ! dir . isReadable ( ) ) )
return 0 ;
2011-07-01 10:10:44 +00:00
qDebug ( ) < < " PRS1Loader::Open newpath= " < < newpath ;
2011-06-26 08:30:44 +00:00
dir . setFilter ( QDir : : NoDotAndDotDot | QDir : : Dirs | QDir : : Files | QDir : : Hidden | QDir : : NoSymLinks ) ;
dir . setSorting ( QDir : : Name ) ;
QFileInfoList flist = dir . entryInfoList ( ) ;
list < QString > SerialNumbers ;
list < QString > : : iterator sn ;
for ( int i = 0 ; i < flist . size ( ) ; i + + ) {
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 ( filename . toLower ( ) = = " last.txt " ) { // last.txt points to the current serial number
QString file = fi . canonicalFilePath ( ) ;
QFile f ( file ) ;
if ( ! fi . isReadable ( ) ) {
2011-07-01 10:10:44 +00:00
qDebug ( ) < < " PRS1Loader: last.txt exists but I couldn't read it! " ;
2011-06-26 08:30:44 +00:00
continue ;
}
if ( ! f . open ( QIODevice : : ReadOnly ) ) {
2011-07-01 10:10:44 +00:00
qDebug ( ) < < " PRS1Loader: last.txt exists but I couldn't open it! " ;
2011-06-26 08:30:44 +00:00
continue ;
}
last = f . readLine ( 64 ) ;
last = last . trimmed ( ) ;
f . close ( ) ;
}
}
if ( SerialNumbers . empty ( ) ) return 0 ;
Machine * m ;
for ( sn = SerialNumbers . begin ( ) ; sn ! = SerialNumbers . end ( ) ; sn + + ) {
QString s = * sn ;
m = CreateMachine ( s , profile ) ;
try {
if ( m ) OpenMachine ( m , newpath + " / " + ( * sn ) , profile ) ;
} catch ( OneTypePerDay e ) {
profile - > DelMachine ( m ) ;
PRS1List . erase ( s ) ;
QMessageBox : : warning ( NULL , " Import Error " , " This Machine Record cannot be imported in this profile. \n The Day records overlap with already existing content. " , QMessageBox : : Ok ) ;
delete m ;
}
}
return PRS1List . size ( ) ;
}
2011-07-15 13:30:41 +00:00
2011-06-26 08:30:44 +00:00
bool PRS1Loader : : ParseProperties ( Machine * m , QString filename )
{
QFile f ( filename ) ;
if ( ! f . open ( QIODevice : : ReadOnly ) )
return false ;
QString line ;
map < QString , QString > prop ;
QString s = f . readLine ( ) ;
QChar sep = ' = ' ;
QString key , value ;
while ( ! f . atEnd ( ) ) {
key = s . section ( sep , 0 , 0 ) ; //BeforeFirst(sep);
if ( key = = s ) continue ;
value = s . section ( sep , 1 ) . trimmed ( ) ; //AfterFirst(sep).Strip();
if ( value = = s ) continue ;
prop [ key ] = value ;
s = f . readLine ( ) ;
}
bool ok ;
2011-07-11 01:58:51 +00:00
QString pt = prop [ " ProductType " ] ;
int i = pt . toInt ( & ok , 0 ) ;
2011-06-26 08:30:44 +00:00
if ( ok ) {
if ( ModelMap . find ( i ) ! = ModelMap . end ( ) ) {
m - > properties [ " SubModel " ] = ModelMap [ i ] ;
}
}
if ( prop [ " SerialNumber " ] ! = m - > properties [ " Serial " ] ) {
2011-07-01 10:10:44 +00:00
qDebug ( ) < < " Serial Number in PRS1 properties.txt doesn't match directory structure " ;
2011-06-26 08:30:44 +00:00
} else prop . erase ( " SerialNumber " ) ; // already got it stored.
for ( map < QString , QString > : : iterator i = prop . begin ( ) ; i ! = prop . end ( ) ; i + + ) {
m - > properties [ i - > first ] = i - > second ;
}
f . close ( ) ;
return true ;
}
int PRS1Loader : : OpenMachine ( Machine * m , QString path , Profile * profile )
{
2011-07-01 10:10:44 +00:00
qDebug ( ) < < " Opening PRS1 " < < path ;
2011-06-26 08:30:44 +00:00
QDir dir ( path ) ;
if ( ! dir . exists ( ) | | ( ! dir . isReadable ( ) ) )
return false ;
dir . setFilter ( QDir : : NoDotAndDotDot | QDir : : Dirs | QDir : : Files | QDir : : Hidden | QDir : : NoSymLinks ) ;
dir . setSorting ( QDir : : Name ) ;
QFileInfoList flist = dir . entryInfoList ( ) ;
QString filename ;
if ( qprogress ) qprogress - > setValue ( 0 ) ;
list < QString > paths ;
for ( int i = 0 ; i < flist . size ( ) ; i + + ) {
QFileInfo fi = flist . at ( i ) ;
filename = fi . fileName ( ) ;
if ( ( filename [ 0 ] . toLower ( ) = = ' p ' ) & & ( isdigit ( filename [ 1 ] ) ) ) {
paths . push_back ( fi . canonicalFilePath ( ) ) ;
} else if ( filename . toLower ( ) = = " properties.txt " ) {
ParseProperties ( m , fi . canonicalFilePath ( ) ) ;
} else if ( filename . toLower ( ) = = " e " ) {
// don't really give a crap about .004 files yet.
}
//if (qprogress) qprogress->Pulse();
}
SessionID session ;
long ext ;
typedef vector < QString > StringList ;
map < SessionID , StringList > sessfiles ;
int size = paths . size ( ) ;
int cnt = 0 ;
bool ok ;
for ( list < QString > : : iterator p = paths . begin ( ) ; p ! = paths . end ( ) ; p + + ) {
dir . setPath ( * p ) ;
if ( ! dir . exists ( ) | | ! dir . isReadable ( ) ) continue ;
flist = dir . entryInfoList ( ) ;
for ( int i = 0 ; i < flist . size ( ) ; i + + ) {
QFileInfo fi = flist . at ( i ) ;
2011-07-03 09:13:54 +00:00
QString ext_s = fi . fileName ( ) . section ( " . " , - 1 ) ;
QString session_s = fi . fileName ( ) . section ( " . " , 0 , - 2 ) ;
2011-06-26 08:30:44 +00:00
ext = ext_s . toLong ( & ok ) ;
if ( ! ok ) continue ;
session = session_s . toLong ( & ok ) ;
if ( ! ok ) continue ;
if ( sessfiles [ session ] . capacity ( ) = = 0 ) sessfiles [ session ] . resize ( 3 ) ;
if ( ext = = 1 ) {
sessfiles [ session ] [ 0 ] = fi . canonicalFilePath ( ) ;
} else if ( ext = = 2 ) {
sessfiles [ session ] [ 1 ] = fi . canonicalFilePath ( ) ;
} else if ( ext = = 5 ) {
sessfiles [ session ] [ 2 ] = fi . canonicalFilePath ( ) ;
}
cnt + + ;
//if (qprogress) qprogress->Pulse(); //Update((float(cnt)/float(size)*25));
2011-06-30 10:56:22 +00:00
if ( qprogress ) qprogress - > setValue ( ( float ( cnt ) / float ( size ) * 33.0 ) ) ;
2011-06-26 08:30:44 +00:00
}
}
size = sessfiles . size ( ) ;
if ( size = = 0 )
return 0 ;
cnt = 0 ;
for ( map < SessionID , StringList > : : iterator s = sessfiles . begin ( ) ; s ! = sessfiles . end ( ) ; s + + ) {
session = s - > first ;
cnt + + ;
2011-06-30 10:56:22 +00:00
if ( qprogress ) qprogress - > setValue ( 33.0 + ( float ( cnt ) / float ( size ) * 33.0 ) ) ;
2011-06-26 08:30:44 +00:00
if ( m - > SessionExists ( session ) ) continue ;
if ( s - > second [ 0 ] . isEmpty ( ) ) continue ;
Session * sess = new Session ( m , session ) ;
if ( ! OpenSummary ( sess , s - > second [ 0 ] ) ) {
2011-07-01 10:10:44 +00:00
qWarning ( ) < < " PRS1Loader: Could'nt open summary file " < < s - > second [ 0 ] ;
2011-06-26 08:30:44 +00:00
delete sess ;
continue ;
}
//sess->SetSessionID(sess->start().GetTicks());
if ( ! s - > second [ 1 ] . isEmpty ( ) ) {
if ( ! OpenEvents ( sess , s - > second [ 1 ] ) ) {
2011-07-01 10:10:44 +00:00
qWarning ( ) < < " PRS1Loader: Couldn't open event file " < < s - > second [ 1 ] ;
2011-06-26 08:30:44 +00:00
}
}
if ( ! s - > second [ 2 ] . isEmpty ( ) ) {
if ( ! OpenWaveforms ( sess , s - > second [ 2 ] ) ) {
2011-07-01 10:10:44 +00:00
qWarning ( ) < < " PRS1Loader: Couldn't open event file " < < s - > second [ 2 ] ;
2011-06-26 08:30:44 +00:00
}
}
const double ignore_thresh = 300.0 / 3600.0 ; // Ignore useless sessions under 5 minute
if ( sess - > hours ( ) < = ignore_thresh ) {
delete sess ;
continue ;
}
m - > AddSession ( sess , profile ) ;
//if (sess->summary.find(CPAP_Obstructive)==sess->summary.end()) {
sess - > summary [ CPAP_Obstructive ] = sess - > count_events ( CPAP_Obstructive ) ;
sess - > summary [ CPAP_Hypopnea ] = sess - > count_events ( CPAP_Hypopnea ) ;
sess - > summary [ CPAP_ClearAirway ] = sess - > count_events ( CPAP_ClearAirway ) ;
sess - > summary [ CPAP_RERA ] = sess - > count_events ( CPAP_RERA ) ;
sess - > summary [ CPAP_FlowLimit ] = sess - > count_events ( CPAP_FlowLimit ) ;
2011-07-12 14:20:49 +00:00
sess - > summary [ CPAP_VSnore ] = sess - > count_events ( CPAP_VSnore ) ;
2011-06-26 08:30:44 +00:00
//}
sess - > summary [ CPAP_CSR ] = sess - > sum_event_field ( CPAP_CSR , 0 ) ;
2011-06-29 20:30:23 +00:00
sess - > summary [ CPAP_Snore ] = sess - > sum_event_field ( CPAP_Snore , 0 ) ;
2011-06-26 08:30:44 +00:00
if ( sess - > count_events ( CPAP_IAP ) > 0 ) {
2011-07-12 12:43:10 +00:00
//sess->summary[CPAP_Mode]!=MODE_ASV)
2011-06-26 08:30:44 +00:00
sess - > summary [ CPAP_Mode ] = MODE_BIPAP ;
2011-07-12 12:43:10 +00:00
sess - > summary [ BIPAP_PSAverage ] = sess - > weighted_avg_event_field ( CPAP_PS , 0 ) ;
sess - > summary [ BIPAP_PSMin ] = sess - > min_event_field ( CPAP_PS , 0 ) ;
sess - > summary [ BIPAP_PSMax ] = sess - > max_event_field ( CPAP_PS , 0 ) ;
2011-06-26 08:30:44 +00:00
if ( sess - > summary [ CPAP_PressureReliefType ] . toInt ( ) ! = PR_NONE ) {
sess - > summary [ CPAP_PressureReliefType ] = PR_BIFLEX ;
}
sess - > summary [ CPAP_PressureMedian ] = ( sess - > avg_event_field ( CPAP_EAP , 0 ) + sess - > avg_event_field ( CPAP_IAP , 0 ) ) / 2.0 ;
sess - > summary [ CPAP_PressureAverage ] = ( sess - > weighted_avg_event_field ( CPAP_IAP , 0 ) + sess - > weighted_avg_event_field ( CPAP_EAP , 0 ) ) / 2.0 ;
sess - > summary [ CPAP_PressureMinAchieved ] = sess - > min_event_field ( CPAP_IAP , 0 ) ;
sess - > summary [ CPAP_PressureMaxAchieved ] = sess - > max_event_field ( CPAP_EAP , 0 ) ;
sess - > summary [ BIPAP_EAPAverage ] = sess - > weighted_avg_event_field ( CPAP_EAP , 0 ) ;
sess - > summary [ BIPAP_EAPMin ] = sess - > min_event_field ( CPAP_EAP , 0 ) ;
sess - > summary [ BIPAP_EAPMax ] = sess - > max_event_field ( CPAP_EAP , 0 ) ;
sess - > summary [ BIPAP_IAPAverage ] = sess - > weighted_avg_event_field ( CPAP_IAP , 0 ) ;
sess - > summary [ BIPAP_IAPMin ] = sess - > min_event_field ( CPAP_IAP , 0 ) ;
sess - > summary [ BIPAP_IAPMax ] = sess - > max_event_field ( CPAP_IAP , 0 ) ;
2011-07-12 12:43:10 +00:00
2011-06-26 08:30:44 +00:00
} else {
2011-07-12 14:20:49 +00:00
sess - > summary [ CPAP_PressureMedian ] = sess - > weighted_avg_event_field ( CPAP_Pressure , 0 ) ;
sess - > summary [ CPAP_PressureAverage ] = sess - > weighted_avg_event_field ( CPAP_Pressure , 0 ) ;
2011-06-26 08:30:44 +00:00
sess - > summary [ CPAP_PressureMinAchieved ] = sess - > min_event_field ( CPAP_Pressure , 0 ) ;
sess - > summary [ CPAP_PressureMaxAchieved ] = sess - > max_event_field ( CPAP_Pressure , 0 ) ;
if ( sess - > summary . find ( CPAP_PressureMin ) = = sess - > summary . end ( ) ) {
sess - > summary [ CPAP_BrokenSummary ] = true ;
2011-07-03 02:43:50 +00:00
//sess->set_last(sess->first());
2011-06-26 08:30:44 +00:00
if ( sess - > summary [ CPAP_PressureMinAchieved ] = = sess - > summary [ CPAP_PressureMaxAchieved ] ) {
sess - > summary [ CPAP_Mode ] = MODE_CPAP ;
} else {
sess - > summary [ CPAP_Mode ] = MODE_UNKNOWN ;
}
sess - > summary [ CPAP_PressureReliefType ] = PR_UNKNOWN ;
}
}
if ( sess - > summary [ CPAP_Mode ] = = MODE_CPAP ) {
sess - > summary [ CPAP_PressureAverage ] = sess - > summary [ CPAP_PressureMin ] ;
sess - > summary [ CPAP_PressureMax ] = sess - > summary [ CPAP_PressureMin ] ;
}
sess - > summary [ CPAP_LeakMinimum ] = sess - > min_event_field ( CPAP_Leak , 0 ) ;
sess - > summary [ CPAP_LeakMaximum ] = sess - > max_event_field ( CPAP_Leak , 0 ) ; // should be merged..
sess - > summary [ CPAP_LeakMedian ] = sess - > avg_event_field ( CPAP_Leak , 0 ) ;
sess - > summary [ CPAP_LeakAverage ] = sess - > weighted_avg_event_field ( CPAP_Leak , 0 ) ;
2011-06-30 09:37:24 +00:00
sess - > summary [ CPAP_SnoreMinimum ] = sess - > min_event_field ( CPAP_Snore , 0 ) ;
sess - > summary [ CPAP_SnoreMaximum ] = sess - > max_event_field ( CPAP_Snore , 0 ) ;
sess - > summary [ CPAP_SnoreMedian ] = sess - > avg_event_field ( CPAP_Snore , 0 ) ;
2011-06-29 20:30:23 +00:00
sess - > summary [ CPAP_SnoreAverage ] = sess - > weighted_avg_event_field ( CPAP_Snore , 0 ) ;
2011-06-26 08:30:44 +00:00
//Printf(sess->start().Format()+wxT(" avgsummary=%.3f avgmine=%.3f\n"),sess->summary[CPAP_PressureAverage].GetDouble(),sess->weighted_avg_event_field(CPAP_Pressure,0));
sess - > SetChanged ( true ) ;
}
QString s ;
s . sprintf ( " %i " , prs1_data_version ) ;
m - > properties [ " DataVersion " ] = s ;
m - > Save ( ) ; // Save any new sessions to disk in our format
if ( qprogress ) qprogress - > setValue ( 100 ) ;
return true ;
}
bool PRS1Loader : : OpenSummary ( Session * session , QString filename )
{
2011-07-18 02:33:25 +00:00
int size , seconds , br , htype , version , sequence ;
2011-07-02 14:35:50 +00:00
qint64 timestamp ;
2011-06-26 08:30:44 +00:00
unsigned char header [ 24 ] ;
unsigned char ext , sum ;
2011-07-01 10:10:44 +00:00
//qDebug() << "Opening PRS1 Summary " << filename;
2011-06-26 08:30:44 +00:00
QFile f ( filename ) ;
2011-07-10 14:23:07 +00:00
2011-06-26 08:30:44 +00:00
if ( ! f . open ( QIODevice : : ReadOnly ) )
return false ;
if ( ! f . exists ( ) )
return false ;
int hl = 16 ;
br = f . read ( ( char * ) header , hl ) ;
2011-07-10 14:23:07 +00:00
if ( header [ 0 ] ! = PRS1_MAGIC_NUMBER )
2011-06-26 08:30:44 +00:00
return false ;
sequence = size = timestamp = seconds = ext = 0 ;
sequence = ( header [ 10 ] < < 24 ) | ( header [ 9 ] < < 16 ) | ( header [ 8 ] < < 8 ) | header [ 7 ] ;
timestamp = ( header [ 14 ] < < 24 ) | ( header [ 13 ] < < 16 ) | ( header [ 12 ] < < 8 ) | header [ 11 ] ;
size = ( header [ 2 ] < < 8 ) | header [ 1 ] ;
ext = header [ 6 ] ;
2011-07-10 14:23:07 +00:00
htype = header [ 3 ] ; // 00 = normal // 01=waveform // could be a bool?
version = header [ 4 ] ;
2011-06-26 08:30:44 +00:00
2011-07-18 02:33:25 +00:00
sequence = sequence ;
version = version ; // don't need it here?
htype = htype ; // shut the warning up.. this is useless.
2011-07-10 14:23:07 +00:00
if ( ext ! = PRS1_SUMMARY_FILE )
2011-06-26 08:30:44 +00:00
return false ;
size - = ( hl + 2 ) ;
2011-07-10 14:23:07 +00:00
// Calculate header checksum and compare to verify header
2011-06-26 08:30:44 +00:00
sum = 0 ;
for ( int i = 0 ; i < hl - 1 ; i + + ) sum + = header [ i ] ;
if ( sum ! = header [ hl - 1 ] )
return false ;
if ( size < = 19 ) {
2011-07-01 10:10:44 +00:00
qDebug ( ) < < " Ignoring short session file " < < filename ;
2011-06-26 08:30:44 +00:00
return false ;
}
2011-07-02 14:35:50 +00:00
qint64 date = timestamp * 1000 ;
2011-06-26 08:30:44 +00:00
2011-07-10 14:23:07 +00:00
//memset(m_buffer,0,size);
2011-06-26 08:30:44 +00:00
unsigned char * buffer = m_buffer ;
br = f . read ( ( char * ) buffer , size ) ;
if ( br < size ) {
return false ;
}
if ( size < 0x30 )
return true ;
session - > set_first ( date ) ;
2011-07-10 14:23:07 +00:00
2011-06-26 08:30:44 +00:00
//session->set_last(date);
double max ;
session - > summary [ CPAP_PressureMin ] = ( double ) buffer [ 0x03 ] / 10.0 ;
session - > summary [ CPAP_PressureMax ] = max = ( double ) buffer [ 0x04 ] / 10.0 ;
2011-07-10 14:23:07 +00:00
int offset = 0 ;
if ( buffer [ 0x05 ] ! = 0 ) { // This is a time value for ASV stuff
// non zero adds extra fields..
offset = 4 ;
}
session - > summary [ CPAP_RampTime ] = ( int ) buffer [ offset + 0x06 ] ; // Minutes. Convert to seconds/hours here?
session - > summary [ CPAP_RampStartingPressure ] = ( double ) buffer [ offset + 0x07 ] / 10.0 ;
2011-06-26 08:30:44 +00:00
if ( max > 0 ) { // Ignoring bipap until I see some more data.
session - > summary [ CPAP_Mode ] = ( int ) MODE_APAP ;
} else session - > summary [ CPAP_Mode ] = ( int ) MODE_CPAP ;
// This is incorrect..
2011-07-10 14:23:07 +00:00
if ( buffer [ offset + 0x08 ] & 0x80 ) { // Flex Setting
if ( buffer [ offset + 0x08 ] & 0x08 ) {
2011-06-26 08:30:44 +00:00
if ( max > 0 ) session - > summary [ CPAP_PressureReliefType ] = ( int ) PR_AFLEX ;
else session - > summary [ CPAP_PressureReliefType ] = ( int ) PR_CFLEXPLUS ;
} else session - > summary [ CPAP_PressureReliefType ] = ( int ) PR_CFLEX ;
} else session - > summary [ CPAP_PressureReliefType ] = ( int ) PR_NONE ;
2011-07-10 14:23:07 +00:00
session - > summary [ CPAP_PressureReliefSetting ] = ( int ) buffer [ offset + 0x08 ] & 3 ;
session - > summary [ CPAP_HumidifierSetting ] = ( int ) buffer [ offset + 0x09 ] & 0x0f ;
session - > summary [ CPAP_HumidifierStatus ] = ( buffer [ offset + 0x09 ] & 0x80 ) = = 0x80 ;
session - > summary [ PRS1_SystemLockStatus ] = ( buffer [ offset + 0x0a ] & 0x80 ) = = 0x80 ;
session - > summary [ PRS1_SystemResistanceStatus ] = ( buffer [ offset + 0x0a ] & 0x40 ) = = 0x40 ;
session - > summary [ PRS1_SystemResistanceSetting ] = ( int ) buffer [ offset + 0x0a ] & 7 ;
session - > summary [ PRS1_HoseDiameter ] = ( int ) ( ( buffer [ offset + 0x0a ] & 0x08 ) ? 15 : 22 ) ;
session - > summary [ PRS1_AutoOff ] = ( buffer [ offset + 0x0c ] & 0x10 ) = = 0x10 ;
session - > summary [ PRS1_MaskAlert ] = ( buffer [ offset + 0x0c ] & 0x08 ) = = 0x08 ;
session - > summary [ PRS1_ShowAHI ] = ( buffer [ offset + 0x0c ] & 0x04 ) = = 0x04 ;
unsigned char * b = & buffer [ offset + 0x14 ] ;
2011-06-26 08:30:44 +00:00
quint16 bb = * ( quint16 * ) b ;
unsigned duration = bb ; // | (buffer[0x15] << 8);
session - > summary [ CPAP_Duration ] = ( int ) duration ;
2011-07-01 10:10:44 +00:00
//qDebug() << "ID: " << session->session() << " " << duration;
2011-07-02 14:35:50 +00:00
//float hours=float(duration)/3600.0;
//session->set_hours(hours);
2011-07-10 14:23:07 +00:00
if ( ! duration )
return false ;
2011-07-03 02:43:50 +00:00
session - > set_last ( date + qint64 ( duration ) * 1000L ) ;
2011-06-26 08:30:44 +00:00
2011-07-10 14:23:07 +00:00
session - > summary [ CPAP_PressureMinAchieved ] = buffer [ offset + 0x16 ] / 10.0 ;
session - > summary [ CPAP_PressureMaxAchieved ] = buffer [ offset + 0x17 ] / 10.0 ;
session - > summary [ CPAP_PressureAverage ] = buffer [ offset + 0x18 ] / 10.0 ;
session - > summary [ CPAP_PressurePercentValue ] = buffer [ offset + 0x19 ] / 10.0 ;
2011-06-26 08:30:44 +00:00
session - > summary [ CPAP_PressurePercentName ] = 90.0 ;
if ( max = = 0 ) {
session - > summary [ CPAP_PressureAverage ] = session - > summary [ CPAP_PressureMin ] ;
}
if ( size = = 0x4d ) {
2011-07-10 14:23:07 +00:00
session - > summary [ CPAP_Obstructive ] = ( int ) buffer [ offset + 0x1C ] | ( buffer [ offset + 0x1D ] < < 8 ) ;
session - > summary [ CPAP_ClearAirway ] = ( int ) buffer [ offset + 0x20 ] | ( buffer [ offset + 0x21 ] < < 8 ) ;
session - > summary [ CPAP_Hypopnea ] = ( int ) buffer [ offset + 0x2A ] | ( buffer [ offset + 0x2B ] < < 8 ) ;
session - > summary [ CPAP_RERA ] = ( int ) buffer [ offset + 0x2E ] | ( buffer [ offset + 0x2F ] < < 8 ) ;
session - > summary [ CPAP_FlowLimit ] = ( int ) buffer [ offset + 0x30 ] | ( buffer [ offset + 0x31 ] < < 8 ) ;
2011-06-26 08:30:44 +00:00
}
return true ;
}
2011-07-10 14:23:07 +00:00
// v2 event parser.
2011-07-18 02:33:25 +00:00
bool PRS1Loader : : Parse002 ( Session * session , unsigned char * buffer , int size , qint64 timestamp )
2011-06-26 08:30:44 +00:00
{
MachineCode Codes [ ] = {
PRS1_Unknown00 , PRS1_Unknown01 , CPAP_Pressure , CPAP_EAP , PRS1_PressurePulse , CPAP_RERA , CPAP_Obstructive , CPAP_ClearAirway ,
PRS1_Unknown08 , PRS1_Unknown09 , CPAP_Hypopnea , PRS1_Unknown0B , CPAP_FlowLimit , CPAP_VSnore , PRS1_Unknown0E , CPAP_CSR , PRS1_Unknown10 ,
CPAP_Leak , PRS1_Unknown12
} ;
int ncodes = sizeof ( Codes ) / sizeof ( MachineCode ) ;
2011-07-10 14:23:07 +00:00
EventDataType data [ 10 ] ;
2011-06-26 08:30:44 +00:00
2011-07-18 02:33:25 +00:00
//qint64 start=timestamp;
2011-07-02 14:35:50 +00:00
qint64 t = timestamp ;
qint64 tt ;
2011-06-26 08:30:44 +00:00
int pos = 0 ;
int cnt = 0 ;
2011-07-18 02:33:25 +00:00
short delta ; //,duration;
2011-06-26 08:30:44 +00:00
while ( pos < size ) {
2011-07-10 14:23:07 +00:00
unsigned char code = buffer [ pos + + ] ;
if ( code > = ncodes ) {
qDebug ( ) < < " Illegal PRS1 code " < < hex < < int ( code ) < < " appeared at " < < hex < < pos + 16 ;
return false ;
}
//assert(code<ncodes);
// QDateTime d=QDateTime::fromMSecsSinceEpoch(t);
// qDebug()<< d.toString("yyyy-MM-dd HH:mm:ss") << ": " << hex << pos+15 << " " << hex << int(code) ;
2011-06-26 08:30:44 +00:00
if ( code ! = 0x12 ) {
2011-07-10 14:23:07 +00:00
delta = buffer [ pos ] ;
2011-07-18 02:33:25 +00:00
//duration=buffer[pos+1];
2011-07-10 14:23:07 +00:00
//delta=buffer[pos+1] << 8 | buffer[pos];
2011-06-26 08:30:44 +00:00
pos + = 2 ;
2011-07-02 14:35:50 +00:00
t + = delta * 1000 ;
2011-06-26 08:30:44 +00:00
}
MachineCode cpapcode = Codes [ ( int ) code ] ;
2011-07-02 14:35:50 +00:00
tt = t ;
2011-06-26 08:30:44 +00:00
cnt + + ;
2011-07-18 02:33:25 +00:00
//int fc=0;
2011-06-26 08:30:44 +00:00
switch ( code ) {
2011-07-10 14:23:07 +00:00
case 0x01 : // Unknown
session - > AddEvent ( new Event ( t , cpapcode , data , 0 ) ) ;
break ;
case 0x00 : // Unknown (ASV Pressure value) // could this be RLE?
// offset?
data [ 0 ] = buffer [ pos + + ] ;
session - > AddEvent ( new Event ( t , cpapcode , data , 1 ) ) ;
break ;
2011-06-26 08:30:44 +00:00
case 0x02 : // Pressure
data [ 0 ] = buffer [ pos + + ] / 10.0 ;
session - > AddEvent ( new Event ( t , cpapcode , data , 1 ) ) ;
break ;
2011-07-12 12:43:10 +00:00
case 0x03 : // BIPAP Pressure
data [ 0 ] = buffer [ pos + + ] ;
data [ 1 ] = buffer [ pos + + ] ;
data [ 0 ] / = 10.0 ;
data [ 1 ] / = 10.0 ;
session - > AddEvent ( new Event ( t , CPAP_EAP , data , 1 ) ) ;
session - > AddEvent ( new Event ( t , CPAP_IAP , & data [ 1 ] , 1 ) ) ;
data [ 1 ] - = data [ 0 ] ;
session - > AddEvent ( new Event ( t , CPAP_PS , & data [ 1 ] , 1 ) ) ;
break ;
2011-06-26 08:30:44 +00:00
case 0x04 : // Pressure Pulse
data [ 0 ] = buffer [ pos + + ] ;
session - > AddEvent ( new Event ( t , cpapcode , data , 1 ) ) ;
break ;
case 0x05 : // RERA
case 0x06 : // Obstructive Apoanea
case 0x07 : // Clear Airway
2011-07-12 12:43:10 +00:00
case 0x0a : // Hypopnea
2011-06-26 08:30:44 +00:00
case 0x0c : // Flow Limitation
2011-07-10 14:23:07 +00:00
data [ 0 ] = buffer [ pos + + ] ;
tt - = data [ 0 ] * 1000 ; // Subtract Time Offset
2011-06-26 08:30:44 +00:00
session - > AddEvent ( new Event ( tt , cpapcode , data , 1 ) ) ;
break ;
2011-07-11 05:46:12 +00:00
case 0x0b : // ASV Codes
data [ 0 ] = buffer [ pos + + ] ;
data [ 1 ] = buffer [ pos + + ] ;
session - > AddEvent ( new Event ( tt , cpapcode , data , 2 ) ) ;
break ;
2011-06-26 08:30:44 +00:00
case 0x0d : // Vibratory Snore
session - > AddEvent ( new Event ( t , cpapcode , data , 0 ) ) ;
break ;
case 0x11 : // Leak Rate
data [ 0 ] = buffer [ pos + + ] ;
data [ 1 ] = buffer [ pos + + ] ;
2011-07-10 14:23:07 +00:00
session - > AddEvent ( new Event ( t , cpapcode , data , 1 ) ) ;
session - > AddEvent ( new Event ( t , CPAP_Snore , & data [ 1 ] , 1 ) ) ;
if ( data [ 1 ] > 0 ) {
session - > AddEvent ( new Event ( t , PRS1_VSnore2 , & data [ 1 ] , 1 ) ) ;
2011-06-26 08:30:44 +00:00
}
break ;
case 0x0e : // Unknown
2011-07-15 10:01:28 +00:00
data [ 0 ] = buffer [ pos + + ] ;
data [ 1 ] = buffer [ pos + + ] ; //(buffer[pos+1] << 8) | buffer[pos];
//data[0]/=10.0;
//pos+=2;
2011-07-10 14:23:07 +00:00
data [ 2 ] = buffer [ pos + + ] ;
session - > AddEvent ( new Event ( t , cpapcode , data , 3 ) ) ;
2011-07-15 10:01:28 +00:00
//tt-=data[1]*1000;
//session->AddEvent(new Event(t,CPAP_CSR, data, 2));
2011-07-10 14:23:07 +00:00
break ;
2011-06-26 08:30:44 +00:00
case 0x10 : // Unknown
data [ 0 ] = buffer [ pos + + ] ; // << 8) | buffer[pos];
data [ 1 ] = buffer [ pos + + ] ;
data [ 2 ] = buffer [ pos + + ] ;
session - > AddEvent ( new Event ( t , cpapcode , data , 3 ) ) ;
break ;
case 0x0f : // Cheyne Stokes Respiration
data [ 0 ] = buffer [ pos + 1 ] < < 8 | buffer [ pos ] ;
pos + = 2 ;
data [ 1 ] = buffer [ pos + + ] ;
2011-07-02 14:35:50 +00:00
tt - = data [ 1 ] * 1000 ;
2011-06-26 08:30:44 +00:00
session - > AddEvent ( new Event ( tt , cpapcode , data , 2 ) ) ;
break ;
case 0x12 : // Summary
data [ 0 ] = buffer [ pos + + ] ;
data [ 1 ] = buffer [ pos + + ] ;
data [ 2 ] = buffer [ pos + 1 ] < < 8 | buffer [ pos ] ;
pos + = 2 ;
session - > AddEvent ( new Event ( t , cpapcode , data , 3 ) ) ;
break ;
default :
// ERROR!!!
2011-07-10 14:23:07 +00:00
qWarning ( ) < < " Some new fandangled PRS1 code detected " < < hex < < int ( code ) < < " at " < < pos + 15 ;
2011-07-03 11:49:47 +00:00
return false ;
2011-06-26 08:30:44 +00:00
}
}
return true ;
}
2011-07-18 02:33:25 +00:00
bool PRS1Loader : : Parse002ASV ( Session * session , unsigned char * buffer , int size , qint64 timestamp )
2011-07-10 14:23:07 +00:00
{
MachineCode Codes [ ] = {
PRS1_Unknown00 , PRS1_Unknown01 , CPAP_Pressure , CPAP_EAP , PRS1_PressurePulse , CPAP_Obstructive , CPAP_ClearAirway , CPAP_Hypopnea ,
PRS1_Unknown08 , CPAP_FlowLimit , PRS1_Unknown0A , CPAP_CSR , PRS1_Unknown0C , CPAP_VSnore , PRS1_Unknown0E , PRS1_Unknown0F , PRS1_Unknown10 ,
CPAP_Leak , PRS1_Unknown12
} ;
int ncodes = sizeof ( Codes ) / sizeof ( MachineCode ) ;
EventDataType data [ 10 ] ;
2011-07-18 02:33:25 +00:00
//qint64 start=timestamp;
2011-07-10 14:23:07 +00:00
qint64 t = timestamp ;
qint64 tt ;
int pos = 0 ;
int cnt = 0 ;
2011-07-18 02:33:25 +00:00
short delta ; //,duration;
2011-07-10 16:20:51 +00:00
QDateTime d ;
2011-07-10 14:23:07 +00:00
while ( pos < size ) {
unsigned char code = buffer [ pos + + ] ;
if ( code > = ncodes ) {
qDebug ( ) < < " Illegal PRS1 code " < < hex < < int ( code ) < < " appeared at " < < hex < < pos + 16 ;
return false ;
}
2011-07-10 16:20:51 +00:00
//QDateTime d=QDateTime::fromMSecsSinceEpoch(t);
//qDebug()<< d.toString("yyyy-MM-dd HH:mm:ss") << ": " << hex << pos+15 << " " << hex << int(code) ;
2011-07-10 14:23:07 +00:00
if ( code ! = 0x12 ) {
delta = buffer [ pos ] ;
2011-07-18 02:33:25 +00:00
//duration=buffer[pos+1];
2011-07-10 14:23:07 +00:00
//delta=buffer[pos+1] << 8 | buffer[pos];
pos + = 2 ;
t + = delta * 1000 ;
}
MachineCode cpapcode = Codes [ ( int ) code ] ;
2011-07-18 02:33:25 +00:00
//EventDataType PS;
2011-07-10 14:23:07 +00:00
tt = t ;
cnt + + ;
int fc = 0 ;
switch ( code ) {
case 0x01 : // Unknown
session - > AddEvent ( new Event ( t , cpapcode , data , 0 ) ) ;
break ;
2011-07-10 16:20:51 +00:00
case 0x00 : // Unknown (ASV Pressure value)
2011-07-10 14:23:07 +00:00
// offset?
data [ 0 ] = buffer [ pos + + ] ;
fc + + ;
2011-07-10 16:20:51 +00:00
if ( ! buffer [ pos - 1 ] ) { // WTH???
2011-07-10 14:23:07 +00:00
data [ 1 ] = buffer [ pos + + ] ;
fc + + ;
}
if ( ! buffer [ pos - 1 ] ) {
data [ 2 ] = buffer [ pos + + ] ;
fc + + ;
}
session - > AddEvent ( new Event ( t , cpapcode , data , 2 ) ) ;
break ;
case 0x02 : // Pressure
2011-07-10 16:20:51 +00:00
data [ 0 ] = buffer [ pos + + ] / 10.0 ; // crappy EPAP pressure value.
//session->AddEvent(new Event(t,cpapcode, data,1));
2011-07-10 14:23:07 +00:00
break ;
case 0x04 : // Pressure Pulse
data [ 0 ] = buffer [ pos + + ] ;
session - > AddEvent ( new Event ( t , cpapcode , data , 1 ) ) ;
break ;
case 0x0a :
code = 0x0a ;
case 0x05 :
case 0x06 :
case 0x07 :
case 0x0c :
data [ 0 ] = buffer [ pos + + ] ;
tt - = data [ 0 ] * 1000 ; // Subtract Time Offset
session - > AddEvent ( new Event ( tt , cpapcode , data , 1 ) ) ;
break ;
case 0x0b : // Cheyne Stokes
data [ 0 ] = ( ( unsigned char * ) buffer ) [ pos + 1 ] < < 8 | ( ( unsigned char * ) buffer ) [ pos ] ;
data [ 0 ] * = 2 ;
pos + = 2 ;
data [ 1 ] = ( ( unsigned char * ) buffer ) [ pos ] ; //|buffer[pos+1] << 8
pos + = 1 ;
//tt-=delta;
tt - = data [ 1 ] * 1000 ;
session - > AddEvent ( new Event ( tt , cpapcode , data , 2 ) ) ;
//tt+=delta;
break ;
case 0x08 : // ASV Codes
case 0x09 : // ASV Codes
data [ 0 ] = buffer [ pos ] ;
tt - = buffer [ pos + + ] * 1000 ; // Subtract Time Offset
session - > AddEvent ( new Event ( tt , cpapcode , data , 1 ) ) ;
break ;
case 0x0d : // All the other ASV graph stuff.
2011-07-10 16:20:51 +00:00
d = QDateTime : : fromMSecsSinceEpoch ( t ) ;
data [ 0 ] = buffer [ pos + + ] / 10.0 ;
session - > AddEvent ( new Event ( t , CPAP_IAP , & data [ 0 ] , 1 ) ) ; //correct
data [ 1 ] = buffer [ pos + + ] / 10.0 ; // Low IPAP
session - > AddEvent ( new Event ( t , CPAP_IAPLO , & data [ 1 ] , 1 ) ) ; //correct
data [ 2 ] = buffer [ pos + + ] / 10.0 ; // Hi IPAP
session - > AddEvent ( new Event ( t , CPAP_IAPHI , & data [ 2 ] , 1 ) ) ; //correct
data [ 3 ] = buffer [ pos + + ] ; //Leak
session - > AddEvent ( new Event ( t , CPAP_Leak , & data [ 3 ] , 1 ) ) ; // correct
data [ 4 ] = buffer [ pos + + ] ; //Breaths Per Minute
session - > AddEvent ( new Event ( t , CPAP_RespiratoryRate , & data [ 4 ] , 1 ) ) ; //correct
data [ 5 ] = buffer [ pos + + ] ; //Patient Triggered Breaths
session - > AddEvent ( new Event ( t , CPAP_PatientTriggeredBreaths , & data [ 5 ] , 1 ) ) ; //correct
data [ 6 ] = buffer [ pos + + ] ; //Minute Ventilation
session - > AddEvent ( new Event ( t , CPAP_MinuteVentilation , & data [ 6 ] , 1 ) ) ; //correct
data [ 7 ] = buffer [ pos + + ] * 10.0 ; // Tidal Volume
session - > AddEvent ( new Event ( t , CPAP_TidalVolume , & data [ 7 ] , 1 ) ) ; //correct
data [ 8 ] = buffer [ pos + + ] ;
session - > AddEvent ( new Event ( t , CPAP_Snore , & data [ 8 ] , 1 ) ) ; //correct
if ( data [ 8 ] > 0 ) {
session - > AddEvent ( new Event ( t , CPAP_VSnore , & data [ 8 ] , 1 ) ) ; //correct
2011-07-10 14:23:07 +00:00
}
2011-07-12 12:43:10 +00:00
data [ 9 ] = buffer [ pos + + ] / 10.0 ; // EPAP
2011-07-10 16:20:51 +00:00
session - > AddEvent ( new Event ( t , CPAP_EAP , & data [ 9 ] , 1 ) ) ; //correct
2011-07-12 12:43:10 +00:00
data [ 2 ] - = data [ 9 ] ; // Pressure Support
session - > AddEvent ( new Event ( t , CPAP_PS , & data [ 2 ] , 1 ) ) ; //correct
2011-07-10 16:20:51 +00:00
qDebug ( ) < < d . toString ( " yyyy-MM-dd HH:mm:ss " ) < < hex < < session - > session ( ) < < pos + 15 < < hex < < int ( code ) < < " : " < < hex < < int ( data [ 0 ] ) < < " " < < int ( data [ 1 ] ) < < " " < < int ( data [ 2 ] ) < < " " < < int ( data [ 3 ] ) < < " " < < int ( data [ 4 ] ) < < " " < < int ( data [ 5 ] ) < < " " < < int ( data [ 6 ] ) < < " " < < int ( data [ 7 ] ) < < " " < < int ( data [ 8 ] ) < < " " < < int ( data [ 9 ] ) ;
2011-07-10 14:23:07 +00:00
break ;
case 0x03 : // BIPAP Pressure
data [ 0 ] = buffer [ pos + + ] ;
data [ 1 ] = buffer [ pos + + ] ;
data [ 0 ] / = 10.0 ;
data [ 1 ] / = 10.0 ;
session - > AddEvent ( new Event ( t , CPAP_EAP , data , 1 ) ) ;
session - > AddEvent ( new Event ( t , CPAP_IAP , & data [ 1 ] , 1 ) ) ;
break ;
case 0x11 : // Leak Rate
data [ 0 ] = buffer [ pos + + ] ;
session - > AddEvent ( new Event ( t , cpapcode , data , 1 ) ) ;
break ;
case 0x0e : // Unknown
data [ 0 ] = buffer [ pos + + ] ; // << 8) | buffer[pos];
session - > AddEvent ( new Event ( t , cpapcode , data , 1 ) ) ;
break ;
case 0x10 : // Unknown
data [ 0 ] = buffer [ pos + + ] ; // << 8) | buffer[pos];
data [ 1 ] = buffer [ pos + + ] ;
data [ 2 ] = buffer [ pos + + ] ;
session - > AddEvent ( new Event ( t , cpapcode , data , 3 ) ) ;
break ;
case 0x0f :
data [ 0 ] = buffer [ pos + 1 ] < < 8 | buffer [ pos ] ;
pos + = 2 ;
data [ 1 ] = buffer [ pos ] ; //|buffer[pos+1] << 8
pos + = 1 ;
tt - = data [ 1 ] * 1000 ;
session - > AddEvent ( new Event ( tt , cpapcode , data , 2 ) ) ;
break ;
case 0x12 : // Summary
data [ 0 ] = buffer [ pos + + ] ;
data [ 1 ] = buffer [ pos + + ] ;
data [ 2 ] = buffer [ pos + 1 ] < < 8 | buffer [ pos ] ;
pos + = 2 ;
session - > AddEvent ( new Event ( t , cpapcode , data , 3 ) ) ;
break ;
default :
// ERROR!!!
qWarning ( ) < < " Some new fandangled PRS1 code detected " < < hex < < int ( code ) < < " at " < < pos + 15 ;
return false ;
}
}
return true ;
}
2011-06-26 08:30:44 +00:00
bool PRS1Loader : : OpenEvents ( Session * session , QString filename )
{
2011-07-10 14:23:07 +00:00
int size , sequence , seconds , br , version ;
2011-07-02 14:35:50 +00:00
qint64 timestamp ;
2011-06-26 08:30:44 +00:00
unsigned char header [ 24 ] ; // use m_buffer?
2011-07-10 14:23:07 +00:00
unsigned char ext , htype ;
2011-06-26 08:30:44 +00:00
QFile f ( filename ) ;
if ( ! f . open ( QIODevice : : ReadOnly ) )
return false ;
int hl = 16 ;
br = f . read ( ( char * ) header , hl ) ;
2011-07-10 14:23:07 +00:00
if ( header [ 0 ] ! = PRS1_MAGIC_NUMBER )
2011-06-26 08:30:44 +00:00
return false ;
sequence = size = timestamp = seconds = ext = 0 ;
sequence = ( header [ 10 ] < < 24 ) | ( header [ 9 ] < < 16 ) | ( header [ 8 ] < < 8 ) | header [ 7 ] ;
timestamp = ( header [ 14 ] < < 24 ) | ( header [ 13 ] < < 16 ) | ( header [ 12 ] < < 8 ) | header [ 11 ] ;
size = ( header [ 2 ] < < 8 ) | header [ 1 ] ;
ext = header [ 6 ] ;
2011-07-10 14:23:07 +00:00
htype = header [ 3 ] ; // 00 = normal // 01=waveform // could be a bool?
version = header [ 4 ] ; // | header[4];
2011-06-26 08:30:44 +00:00
2011-07-18 02:33:25 +00:00
htype = htype ;
sequence = sequence ;
2011-07-10 14:23:07 +00:00
if ( ext ! = PRS1_EVENT_FILE ) // 2 == Event file
2011-06-26 08:30:44 +00:00
return false ;
//size|=(header[3]<<16) | (header[4]<<24); // the jury is still out on the 32bitness of one. doesn't matter here anyway.
size - = ( hl + 2 ) ;
unsigned char sum = 0 ;
for ( int i = 0 ; i < hl - 1 ; i + + ) sum + = header [ i ] ;
if ( sum ! = header [ hl - 1 ] ) return false ;
unsigned char * buffer = ( unsigned char * ) m_buffer ;
br = f . read ( ( char * ) buffer , size ) ;
if ( br < size ) {
return false ;
}
2011-07-10 14:23:07 +00:00
if ( version = = 0 ) {
2011-07-18 02:33:25 +00:00
if ( ! Parse002 ( session , buffer , size , timestamp * 1000L ) ) {
2011-07-10 14:23:07 +00:00
qDebug ( ) < < " Couldn't Parse PRS1 Event File " < < filename ;
return false ;
}
} else if ( version = = 5 ) {
2011-07-18 02:33:25 +00:00
if ( ! Parse002ASV ( session , buffer , size , timestamp * 1000L ) ) {
2011-07-10 14:23:07 +00:00
qDebug ( ) < < " Couldn't Parse PRS1 (ASV) Event File " < < filename ;
return false ;
}
}
2011-06-26 08:30:44 +00:00
return true ;
}
bool PRS1Loader : : OpenWaveforms ( Session * session , QString filename )
{
2011-07-10 14:23:07 +00:00
int size , sequence , seconds , br , htype , version , numsignals ;
2011-06-26 08:30:44 +00:00
unsigned cnt = 0 ;
2011-07-02 14:35:50 +00:00
qint64 timestamp ;
2011-06-26 08:30:44 +00:00
2011-07-02 14:35:50 +00:00
qint64 start = 0 ;
2011-07-10 14:23:07 +00:00
unsigned char header [ 20 ] ;
2011-06-26 08:30:44 +00:00
unsigned char ext ;
QFile f ( filename ) ;
if ( ! f . open ( QIODevice : : ReadOnly ) )
return false ;
2011-07-10 14:23:07 +00:00
const int max_signals = 16 ;
static qint16 interleave [ max_signals ] = { 0 } ;
static char sampletype [ max_signals ] = { 0 } ;
2011-06-26 08:30:44 +00:00
2011-07-16 13:34:39 +00:00
int hl = 0 ;
2011-06-26 08:30:44 +00:00
long samples = 0 ;
2011-07-02 14:35:50 +00:00
qint64 duration = 0 ;
2011-06-26 08:30:44 +00:00
char * buffer = ( char * ) m_buffer ;
2011-07-18 02:33:25 +00:00
//bool first2=true;
2011-07-16 13:34:39 +00:00
long fpos = 0 ;
2011-07-18 02:33:25 +00:00
//int bsize=0;
2011-07-16 13:34:39 +00:00
int lasthl = 0 ;
2011-06-26 08:30:44 +00:00
while ( true ) {
2011-07-16 13:34:39 +00:00
lasthl = hl ;
2011-07-10 14:23:07 +00:00
hl = 20 ;
2011-06-26 08:30:44 +00:00
br = f . read ( ( char * ) header , hl ) ;
2011-07-16 13:34:39 +00:00
fpos + = hl ;
2011-06-26 08:30:44 +00:00
if ( br < hl ) {
if ( cnt = = 0 )
return false ;
break ;
}
2011-07-10 14:23:07 +00:00
if ( header [ 0 ] ! = PRS1_MAGIC_NUMBER ) {
2011-06-26 08:30:44 +00:00
if ( cnt = = 0 )
return false ;
2011-07-16 13:34:39 +00:00
qDebug ( ) < < " Corrupt waveform, trying to recover " ;
// read the damn bytes anyway..
br = f . read ( ( char * ) header , lasthl - hl + 1 ) ; // last bit of the header
if ( br < lasthl - hl + 1 ) {
qDebug ( ) < < " End of file, couldn't recover " ;
break ;
}
hl = lasthl ;
br = f . read ( ( char * ) & buffer [ samples ] , size ) ;
if ( br < size ) {
//delete [] buffer;
break ;
}
samples + = size ;
duration + = seconds ;
br = f . read ( ( char * ) header , 2 ) ;
fpos + = size + 3 + lasthl - hl ;
continue ;
2011-06-26 08:30:44 +00:00
}
2011-07-10 14:23:07 +00:00
//sequence=size=timestamp=seconds=ext=0;
2011-07-18 02:33:25 +00:00
size = ( header [ 2 ] < < 8 ) | header [ 1 ] ;
2011-07-10 14:23:07 +00:00
version = header [ 4 ] ;
htype = header [ 3 ] ;
2011-06-26 08:30:44 +00:00
ext = header [ 6 ] ;
2011-07-10 14:23:07 +00:00
sequence = ( header [ 10 ] < < 24 ) | ( header [ 9 ] < < 16 ) | ( header [ 8 ] < < 8 ) | header [ 7 ] ;
timestamp = ( header [ 14 ] < < 24 ) | ( header [ 13 ] < < 16 ) | ( header [ 12 ] < < 8 ) | header [ 11 ] ;
seconds = ( header [ 16 ] < < 8 ) | header [ 15 ] ;
numsignals = header [ 19 ] < < 8 | header [ 18 ] ;
2011-07-18 02:33:25 +00:00
sequence = sequence ;
version = version ;
//htype=htype;
2011-07-10 14:23:07 +00:00
unsigned char sum = 0 , hchk ;
for ( int i = 0 ; i < hl ; i + + ) sum + = header [ i ] ;
2011-07-19 15:31:51 +00:00
if ( numsignals > = max_signals ) {
qWarning ( ) < < " PRS1Loader::OpenWaveforms() numsignals >= max_signals " ;
return false ;
}
2011-07-10 14:23:07 +00:00
char buf [ 3 ] ;
for ( int i = 0 ; i < numsignals ; i + + ) {
f . read ( buf , 3 ) ;
2011-07-16 13:34:39 +00:00
fpos + = 3 ;
2011-07-10 14:23:07 +00:00
if ( br < 3 ) {
if ( cnt = = 0 )
return false ;
break ;
}
sum + = buf [ 0 ] + buf [ 1 ] + buf [ 2 ] ;
sampletype [ i ] = buf [ 2 ] ;
interleave [ i ] = buf [ 1 ] < < 8 | buf [ 0 ] ;
hl + = 3 ;
}
2011-06-26 08:30:44 +00:00
2011-07-10 14:23:07 +00:00
if ( f . read ( ( char * ) & hchk , 1 ) ! = 1 ) { // Read Header byte.
if ( cnt = = 0 )
return false ;
break ;
2011-06-26 08:30:44 +00:00
}
2011-07-16 13:34:39 +00:00
fpos + = 1 ;
2011-07-10 14:23:07 +00:00
if ( sum ! = hchk )
return false ;
size - = ( hl + 3 ) ; // 3 == the 8 bit checksum on the end of the header, and the 16bit at the end of the block
2011-06-26 08:30:44 +00:00
2011-07-10 14:23:07 +00:00
if ( ! htype ) {
qDebug ( ) < < " PRS1 Waveform data has htype set differently " ;
}
2011-06-26 08:30:44 +00:00
2011-07-10 14:23:07 +00:00
if ( ! start ) start = timestamp * 1000 ; //convert from epoch to msecs since epoch
if ( ext ! = PRS1_WAVEFORM_FILE ) {
2011-06-26 08:30:44 +00:00
if ( cnt = = 0 )
return false ;
break ;
}
if ( samples + size > = max_load_buffer_size ) {
qWarning ( " max_load_buffer_size is too small in PRS1 Loader " ) ;
if ( cnt = = 0 )
return false ;
break ;
}
br = f . read ( ( char * ) & buffer [ samples ] , size ) ;
if ( br < size ) {
delete [ ] buffer ;
break ;
}
2011-07-16 13:34:39 +00:00
fpos + = size ;
2011-06-26 08:30:44 +00:00
cnt + + ;
duration + = seconds ;
samples + = size ;
char chkbuf [ 2 ] ;
qint16 chksum ;
br = f . read ( chkbuf , 2 ) ;
2011-07-16 13:34:39 +00:00
fpos + = 2 ;
2011-06-26 08:30:44 +00:00
if ( br < 2 )
return false ;
chksum = chkbuf [ 0 ] < < 8 | chkbuf [ 1 ] ;
2011-07-18 02:33:25 +00:00
chksum = chksum ;
2011-06-26 08:30:44 +00:00
}
if ( samples = = 0 )
return false ;
2011-07-10 14:23:07 +00:00
// Create the buffers for real sample data
SampleFormat * data [ numsignals ] ;
SampleFormat min [ numsignals ] , max [ numsignals ] ;
bool first [ numsignals ] ;
int pos [ numsignals ] ;
int samplespersignal = samples / numsignals ; // TODO: divide by type?
int ichunksize = 0 ; // interleave chunk size
for ( int i = 0 ; i < numsignals ; i + + ) {
ichunksize + = interleave [ i ] ;
data [ i ] = new SampleFormat [ samplespersignal ] ;
min [ i ] = max [ i ] = 0 ;
first [ i ] = true ;
pos [ i ] = 0 ;
}
2011-06-26 08:30:44 +00:00
2011-07-10 14:23:07 +00:00
// Deinterleave the samples
2011-06-26 08:30:44 +00:00
SampleFormat c ;
2011-07-10 14:23:07 +00:00
unsigned char * ucbuffer = ( unsigned char * ) buffer ;
int k = 0 ;
for ( int i = 0 ; i < samples / ichunksize ; i + + ) {
for ( int s = 0 ; s < numsignals ; s + + ) {
for ( int j = 0 ; j < interleave [ numsignals - 1 - s ] ; j + + ) {
if ( sampletype [ numsignals - 1 - s ] = = 0 )
c = buffer [ k + + ] ;
2011-07-11 01:58:51 +00:00
else if ( sampletype [ numsignals - 1 - s ] = = 1 ) {
2011-07-10 14:23:07 +00:00
c = ucbuffer [ k + + ] ;
2011-07-11 01:58:51 +00:00
if ( c < 40 ) {
c = min [ s ] ;
//int q=0;
}
}
2011-07-10 14:23:07 +00:00
if ( first [ s ] ) {
min [ s ] = max [ s ] = c ;
first [ s ] = false ;
2011-07-11 01:58:51 +00:00
} else {
if ( min [ s ] > c ) min [ s ] = c ;
if ( max [ s ] < c ) max [ s ] = c ;
2011-07-10 14:23:07 +00:00
}
data [ s ] [ pos [ s ] + + ] = c ;
}
2011-06-26 08:30:44 +00:00
}
}
2011-07-10 14:23:07 +00:00
duration * = 1000 ;
Waveform * w = new Waveform ( start , CPAP_FlowRate , data [ 0 ] , pos [ 0 ] , duration , min [ 0 ] , max [ 0 ] ) ; //FlowRate
session - > AddWaveform ( w ) ;
if ( numsignals > 1 ) {
Waveform * w = new Waveform ( start , CPAP_MaskPressure , data [ 1 ] , pos [ 1 ] , duration , min [ 1 ] , max [ 1 ] ) ;
session - > AddWaveform ( w ) ;
}
2011-06-26 08:30:44 +00:00
return true ;
}
void InitModelMap ( )
{
ModelMap [ 34 ] = " RemStar Pro with C-Flex+ " ;
ModelMap [ 35 ] = " RemStar Auto with A-Flex " ;
2011-07-11 04:54:53 +00:00
ModelMap [ 37 ] = " RemStar BiPAP Auto with Bi-Flex " ;
2011-07-11 01:58:51 +00:00
ModelMap [ 0x41 ] = " BiPAP autoSV Advanced " ;
2011-06-26 08:30:44 +00:00
} ;
bool initialized = false ;
void PRS1Loader : : Register ( )
{
if ( initialized ) return ;
2011-07-01 10:10:44 +00:00
qDebug ( ) < < " Registering PRS1Loader " ;
2011-06-26 08:30:44 +00:00
RegisterLoader ( new PRS1Loader ( ) ) ;
InitModelMap ( ) ;
initialized = true ;
}