2011-06-26 08:30:44 +00:00
/*
SleepLib PRS1 Loader Implementation
Author : Mark Watkins < jedimark64 @ users . sourceforge . net >
License : GPL
*/
2011-07-30 00:36:31 +00:00
# include <QApplication>
2011-06-26 08:30:44 +00:00
# include <QString>
# include <QDateTime>
# include <QDir>
# include <QFile>
# include <QMessageBox>
# include <QProgressBar>
2011-07-01 10:10:44 +00:00
# include <QDebug>
2011-07-27 09:21:53 +00:00
# include <cmath>
2011-09-17 12:39:00 +00:00
# include "SleepLib/schema.h"
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 ;
2011-07-31 20:24:43 +00:00
QHash < int , QString > ModelMap ;
2011-06-26 08:30:44 +00:00
2011-11-26 04:00:31 +00:00
typedef quint16 crc_t ;
static const crc_t crc_table [ 256 ] = {
0x0000 , 0x1189 , 0x2312 , 0x329b , 0x4624 , 0x57ad , 0x6536 , 0x74bf ,
0x8c48 , 0x9dc1 , 0xaf5a , 0xbed3 , 0xca6c , 0xdbe5 , 0xe97e , 0xf8f7 ,
0x1081 , 0x0108 , 0x3393 , 0x221a , 0x56a5 , 0x472c , 0x75b7 , 0x643e ,
0x9cc9 , 0x8d40 , 0xbfdb , 0xae52 , 0xdaed , 0xcb64 , 0xf9ff , 0xe876 ,
0x2102 , 0x308b , 0x0210 , 0x1399 , 0x6726 , 0x76af , 0x4434 , 0x55bd ,
0xad4a , 0xbcc3 , 0x8e58 , 0x9fd1 , 0xeb6e , 0xfae7 , 0xc87c , 0xd9f5 ,
0x3183 , 0x200a , 0x1291 , 0x0318 , 0x77a7 , 0x662e , 0x54b5 , 0x453c ,
0xbdcb , 0xac42 , 0x9ed9 , 0x8f50 , 0xfbef , 0xea66 , 0xd8fd , 0xc974 ,
0x4204 , 0x538d , 0x6116 , 0x709f , 0x0420 , 0x15a9 , 0x2732 , 0x36bb ,
0xce4c , 0xdfc5 , 0xed5e , 0xfcd7 , 0x8868 , 0x99e1 , 0xab7a , 0xbaf3 ,
0x5285 , 0x430c , 0x7197 , 0x601e , 0x14a1 , 0x0528 , 0x37b3 , 0x263a ,
0xdecd , 0xcf44 , 0xfddf , 0xec56 , 0x98e9 , 0x8960 , 0xbbfb , 0xaa72 ,
0x6306 , 0x728f , 0x4014 , 0x519d , 0x2522 , 0x34ab , 0x0630 , 0x17b9 ,
0xef4e , 0xfec7 , 0xcc5c , 0xddd5 , 0xa96a , 0xb8e3 , 0x8a78 , 0x9bf1 ,
0x7387 , 0x620e , 0x5095 , 0x411c , 0x35a3 , 0x242a , 0x16b1 , 0x0738 ,
0xffcf , 0xee46 , 0xdcdd , 0xcd54 , 0xb9eb , 0xa862 , 0x9af9 , 0x8b70 ,
0x8408 , 0x9581 , 0xa71a , 0xb693 , 0xc22c , 0xd3a5 , 0xe13e , 0xf0b7 ,
0x0840 , 0x19c9 , 0x2b52 , 0x3adb , 0x4e64 , 0x5fed , 0x6d76 , 0x7cff ,
0x9489 , 0x8500 , 0xb79b , 0xa612 , 0xd2ad , 0xc324 , 0xf1bf , 0xe036 ,
0x18c1 , 0x0948 , 0x3bd3 , 0x2a5a , 0x5ee5 , 0x4f6c , 0x7df7 , 0x6c7e ,
0xa50a , 0xb483 , 0x8618 , 0x9791 , 0xe32e , 0xf2a7 , 0xc03c , 0xd1b5 ,
0x2942 , 0x38cb , 0x0a50 , 0x1bd9 , 0x6f66 , 0x7eef , 0x4c74 , 0x5dfd ,
0xb58b , 0xa402 , 0x9699 , 0x8710 , 0xf3af , 0xe226 , 0xd0bd , 0xc134 ,
0x39c3 , 0x284a , 0x1ad1 , 0x0b58 , 0x7fe7 , 0x6e6e , 0x5cf5 , 0x4d7c ,
0xc60c , 0xd785 , 0xe51e , 0xf497 , 0x8028 , 0x91a1 , 0xa33a , 0xb2b3 ,
0x4a44 , 0x5bcd , 0x6956 , 0x78df , 0x0c60 , 0x1de9 , 0x2f72 , 0x3efb ,
0xd68d , 0xc704 , 0xf59f , 0xe416 , 0x90a9 , 0x8120 , 0xb3bb , 0xa232 ,
0x5ac5 , 0x4b4c , 0x79d7 , 0x685e , 0x1ce1 , 0x0d68 , 0x3ff3 , 0x2e7a ,
0xe70e , 0xf687 , 0xc41c , 0xd595 , 0xa12a , 0xb0a3 , 0x8238 , 0x93b1 ,
0x6b46 , 0x7acf , 0x4854 , 0x59dd , 0x2d62 , 0x3ceb , 0x0e70 , 0x1ff9 ,
0xf78f , 0xe606 , 0xd49d , 0xc514 , 0xb1ab , 0xa022 , 0x92b9 , 0x8330 ,
0x7bc7 , 0x6a4e , 0x58d5 , 0x495c , 0x3de3 , 0x2c6a , 0x1ef1 , 0x0f78
} ;
crc_t CRC16 ( const unsigned char * data , size_t data_len )
{
crc_t crc = 0 ;
unsigned int tbl_idx ;
while ( data_len - - ) {
tbl_idx = ( crc ^ * data ) & 0xff ;
crc = ( crc_table [ tbl_idx ] ^ ( crc > > 8 ) ) & 0xffff ;
data + + ;
}
return crc & 0xffff ;
}
2011-06-26 08:30:44 +00:00
PRS1 : : PRS1 ( Profile * p , MachineID id ) : CPAP ( p , id )
{
m_class = prs1_class_name ;
properties [ " Brand " ] = " Philips Respironics " ;
properties [ " Model " ] = " System One " ;
}
PRS1 : : ~ PRS1 ( )
{
}
PRS1Loader : : PRS1Loader ( )
{
2011-11-26 04:00:31 +00:00
//genCRCTable();
2011-07-27 09:21:53 +00:00
m_buffer = NULL ;
2011-06-26 08:30:44 +00:00
}
PRS1Loader : : ~ PRS1Loader ( )
{
2011-07-31 20:24:43 +00:00
for ( QHash < QString , Machine * > : : iterator i = PRS1List . begin ( ) ; i ! = PRS1List . end ( ) ; i + + ) {
delete i . value ( ) ;
2011-06-26 08:30:44 +00:00
}
}
Machine * PRS1Loader : : CreateMachine ( QString serial , Profile * profile )
{
2011-07-24 16:34:53 +00:00
if ( ! profile )
return NULL ;
2011-07-01 10:10:44 +00:00
qDebug ( ) < < " Create Machine " < < serial ;
2011-06-26 08:30:44 +00:00
2011-07-31 20:24:43 +00:00
QVector < Machine * > ml = profile - > GetMachines ( MT_CPAP ) ;
2011-06-26 08:30:44 +00:00
bool found = false ;
2011-07-31 20:24:43 +00:00
QVector < Machine * > : : iterator i ;
for ( i = ml . begin ( ) ; i ! = ml . end ( ) ; i + + ) {
2011-06-26 08:30:44 +00:00
if ( ( ( * i ) - > GetClass ( ) = = " PRS1 " ) & & ( ( * i ) - > properties [ " Serial " ] = = serial ) ) {
PRS1List [ serial ] = * i ; //static_cast<CPAP *>(*i);
found = true ;
break ;
}
}
2011-07-31 20:24:43 +00:00
if ( found ) return * i ;
2011-06-26 08:30:44 +00:00
//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
{
2011-09-10 04:20:45 +00:00
QString newpath , pseries = " P-Series " ;
qDebug ( ) < < " PRS1Loader::Open path= " < < newpath ;
2011-11-21 02:15:10 +00:00
if ( path . endsWith ( QDir : : separator ( ) + pseries ) ) {
2011-06-26 08:30:44 +00:00
newpath = path ;
} else {
2011-11-21 02:15:10 +00:00
newpath = path + QDir : : separator ( ) + pseries ;
2011-06-26 08:30:44 +00:00
}
QDir dir ( newpath ) ;
if ( ( ! dir . exists ( ) | | ! dir . isReadable ( ) ) )
return 0 ;
dir . setFilter ( QDir : : NoDotAndDotDot | QDir : : Dirs | QDir : : Files | QDir : : Hidden | QDir : : NoSymLinks ) ;
dir . setSorting ( QDir : : Name ) ;
QFileInfoList flist = dir . entryInfoList ( ) ;
2011-07-31 20:24:43 +00:00
QList < QString > SerialNumbers ;
QList < QString > : : iterator sn ;
2011-06-26 08:30:44 +00:00
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 ;
2011-07-27 09:21:53 +00:00
m_buffer = new unsigned char [ max_load_buffer_size ] ; //allocate once and reuse.
2011-06-26 08:30:44 +00:00
Machine * m ;
for ( sn = SerialNumbers . begin ( ) ; sn ! = SerialNumbers . end ( ) ; sn + + ) {
QString s = * sn ;
m = CreateMachine ( s , profile ) ;
try {
2011-11-21 02:15:10 +00:00
if ( m ) OpenMachine ( m , newpath + QDir : : separator ( ) + ( * sn ) , profile ) ;
2011-06-26 08:30:44 +00:00
} catch ( OneTypePerDay e ) {
profile - > DelMachine ( m ) ;
2011-07-31 20:24:43 +00:00
PRS1List . erase ( PRS1List . find ( s ) ) ;
2011-06-26 08:30:44 +00:00
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 ;
}
}
2011-07-27 09:21:53 +00:00
delete [ ] m_buffer ;
2011-06-26 08:30:44 +00:00
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 ;
2011-07-31 20:24:43 +00:00
QHash < QString , QString > prop ;
2011-06-26 08:30:44 +00:00
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 " ] ;
2011-10-10 21:29:15 +00:00
int i = pt . toInt ( & ok , 16 ) ;
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-07-31 20:24:43 +00:00
} else prop . erase ( prop . find ( " SerialNumber " ) ) ; // already got it stored.
2011-06-26 08:30:44 +00:00
2011-07-31 20:24:43 +00:00
for ( QHash < QString , QString > : : iterator i = prop . begin ( ) ; i ! = prop . end ( ) ; i + + ) {
m - > properties [ i . key ( ) ] = i . value ( ) ;
2011-06-26 08:30:44 +00:00
}
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 ) ;
2011-07-31 20:24:43 +00:00
QList < QString > paths ;
2011-06-26 08:30:44 +00:00
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 ;
2011-07-31 20:24:43 +00:00
typedef QVector < QString > StringList ;
2011-08-01 08:22:37 +00:00
QMap < SessionID , StringList > sessfiles ;
2011-06-26 08:30:44 +00:00
int size = paths . size ( ) ;
int cnt = 0 ;
bool ok ;
2011-07-31 20:24:43 +00:00
for ( QList < QString > : : iterator p = paths . begin ( ) ; p ! = paths . end ( ) ; p + + ) {
2011-06-26 08:30:44 +00:00
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 + + ;
2011-06-30 10:56:22 +00:00
if ( qprogress ) qprogress - > setValue ( ( float ( cnt ) / float ( size ) * 33.0 ) ) ;
2011-07-30 00:36:31 +00:00
QApplication : : processEvents ( ) ;
2011-06-26 08:30:44 +00:00
}
}
size = sessfiles . size ( ) ;
if ( size = = 0 )
return 0 ;
cnt = 0 ;
2011-08-01 08:22:37 +00:00
for ( QMap < SessionID , StringList > : : iterator s = sessfiles . begin ( ) ; s ! = sessfiles . end ( ) ; s + + ) {
2011-07-31 20:24:43 +00:00
session = s . key ( ) ;
2011-06-26 08:30:44 +00:00
cnt + + ;
2011-06-30 10:56:22 +00:00
if ( qprogress ) qprogress - > setValue ( 33.0 + ( float ( cnt ) / float ( size ) * 33.0 ) ) ;
2011-07-30 00:36:31 +00:00
QApplication : : processEvents ( ) ;
2011-06-26 08:30:44 +00:00
if ( m - > SessionExists ( session ) ) continue ;
2011-07-31 20:24:43 +00:00
if ( s . value ( ) [ 0 ] . isEmpty ( ) ) continue ;
2011-06-26 08:30:44 +00:00
Session * sess = new Session ( m , session ) ;
2011-07-31 20:24:43 +00:00
if ( ! OpenSummary ( sess , s . value ( ) [ 0 ] ) ) {
//qWarning() << "PRS1Loader: Dodgy summary file " << s.value()[0];
2011-06-26 08:30:44 +00:00
2011-07-22 13:46:17 +00:00
delete sess ;
continue ;
2011-06-26 08:30:44 +00:00
}
//sess->SetSessionID(sess->start().GetTicks());
2011-07-31 20:24:43 +00:00
if ( ! s . value ( ) [ 1 ] . isEmpty ( ) ) {
if ( ! OpenEvents ( sess , s . value ( ) [ 1 ] ) ) {
qWarning ( ) < < " PRS1Loader: Couldn't open event file " < < s . value ( ) [ 1 ] ;
2011-06-26 08:30:44 +00:00
}
}
2011-07-31 20:24:43 +00:00
if ( ! s . value ( ) [ 2 ] . isEmpty ( ) ) {
if ( ! OpenWaveforms ( sess , s . value ( ) [ 2 ] ) ) {
qWarning ( ) < < " PRS1Loader: Couldn't open event file " < < s . value ( ) [ 2 ] ;
2011-06-26 08:30:44 +00:00
}
}
2011-08-05 07:52:32 +00:00
if ( ( sess - > last ( ) - sess - > first ( ) ) = = 0 ) {
//const double ignore_thresh=300.0/3600.0;// Ignore useless sessions under 5 minute
//if (sess->hours()<=ignore_thresh) {
qDebug ( ) < < " Ignoring empty session " < < session ; // << "which is only" << (sess->hours()*60.0) << "minute(s) long";
2011-06-26 08:30:44 +00:00
delete sess ;
continue ;
}
2011-09-17 12:39:00 +00:00
2011-07-31 20:24:43 +00:00
if ( sess - > count ( CPAP_IPAP ) > 0 ) {
//sess->summaryCPAP_Mode]!=MODE_ASV)
sess - > settings [ CPAP_Mode ] = MODE_BIPAP ;
2011-07-12 12:43:10 +00:00
2011-09-17 12:39:00 +00:00
if ( sess - > settings [ PRS1_FlexMode ] . toInt ( ) ! = PR_NONE ) {
sess - > settings [ PRS1_FlexMode ] = PR_BIFLEX ;
2011-06-26 08:30:44 +00:00
}
2011-07-31 20:24:43 +00:00
2011-09-17 12:39:00 +00:00
2011-07-31 20:24:43 +00:00
sess - > setAvg ( CPAP_Pressure , ( sess - > avg ( CPAP_EPAP ) + sess - > avg ( CPAP_IPAP ) ) / 2.0 ) ;
sess - > setWavg ( CPAP_Pressure , ( sess - > wavg ( CPAP_EPAP ) + sess - > wavg ( CPAP_IPAP ) ) / 2.0 ) ;
sess - > setMin ( CPAP_Pressure , sess - > min ( CPAP_EPAP ) ) ;
2011-08-07 11:37:56 +00:00
sess - > setMax ( CPAP_Pressure , sess - > max ( CPAP_IPAP ) ) ;
2011-09-17 12:39:00 +00:00
sess - > set90p ( CPAP_Pressure , ( sess - > p90 ( CPAP_IPAP ) + sess - > p90 ( CPAP_EPAP ) ) / 2.0 ) ;
//sess->p90(CPAP_EPAP);
2011-08-07 11:37:56 +00:00
//sess->p90(CPAP_IPAP);
2011-06-26 08:30:44 +00:00
} else {
2011-09-21 14:10:10 +00:00
//sess->avg(CPAP_Pressure);
//sess->wavg(CPAP_Pressure);
//sess->p90(CPAP_Pressure);
//sess->min(CPAP_Pressure);
//sess->max(CPAP_Pressure);
//sess->cph(CPAP_Pressure);
2011-07-31 20:24:43 +00:00
2011-09-17 12:39:00 +00:00
if ( ! sess - > settings . contains ( CPAP_PressureMin ) ) {
2011-07-31 20:24:43 +00:00
sess - > settings [ CPAP_BrokenSummary ] = true ;
2011-07-03 02:43:50 +00:00
//sess->set_last(sess->first());
2011-07-31 20:24:43 +00:00
if ( sess - > min ( CPAP_Pressure ) = = sess - > max ( CPAP_Pressure ) ) {
2011-09-21 14:10:10 +00:00
sess - > settings [ CPAP_Mode ] = MODE_CPAP ; // no ramp
2011-06-26 08:30:44 +00:00
} else {
2011-09-21 14:10:10 +00:00
sess - > settings [ CPAP_Mode ] = MODE_UNKNOWN ;
2011-06-26 08:30:44 +00:00
}
2011-09-17 12:39:00 +00:00
//sess->Set("FlexMode",PR_UNKNOWN);
2011-06-26 08:30:44 +00:00
}
}
2011-07-31 20:24:43 +00:00
if ( sess - > settings [ CPAP_Mode ] = = MODE_CPAP ) {
2011-09-17 12:39:00 +00:00
sess - > settings [ CPAP_PressureMax ] = sess - > settings [ CPAP_PressureMin ] ;
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 ) ;
2011-07-22 13:46:17 +00:00
m - > AddSession ( sess , profile ) ;
2011-06-26 08:30:44 +00:00
}
QString s ;
s . sprintf ( " %i " , prs1_data_version ) ;
m - > properties [ " DataVersion " ] = s ;
2011-07-22 13:46:17 +00:00
m - > Save ( ) ; // Save any new sessions to disk in our format */
2011-06-26 08:30:44 +00:00
if ( qprogress ) qprogress - > setValue ( 100 ) ;
2011-07-30 00:36:31 +00:00
2011-07-22 13:46:17 +00:00
//qDebug() << "OpenMachine Done";
2011-06-26 08:30:44 +00:00
return true ;
}
2011-09-21 14:10:10 +00:00
//bool PRS1Loader::OpenMachine()
//{
//}
2011-06-26 08:30:44 +00:00
2011-11-26 04:00:31 +00:00
bool PRS1Loader : : OpenSummary ( Session * session , QString filename ) // Read .001 file
2011-06-26 08:30:44 +00:00
{
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-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-20 16:48:21 +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 ;
}
2011-11-26 04:00:31 +00:00
unsigned char crcbytes [ 2 ] ;
if ( f . read ( ( char * ) crcbytes , 2 ) ! = 2 ) {
qDebug ( ) < < " No ending CRC bytes in " < < filename ;
}
quint16 crc = ( crcbytes [ 1 ] < < 8 ) | crcbytes [ 0 ] ;
quint16 c16 = CRC16 ( buffer , size ) ;
if ( crc ! = c16 ) {
qDebug ( ) < < " Summary CRC check failed, wanted " < < crc < < " got " < < c16 ;
}
2011-06-26 08:30:44 +00:00
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
double max ;
2011-09-17 12:39:00 +00:00
session - > settings [ CPAP_PressureMin ] = ( EventDataType ) buffer [ 0x03 ] / 10.0 ;
session - > settings [ CPAP_PressureMax ] = max = ( EventDataType ) 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 ;
}
2011-09-17 12:39:00 +00:00
session - > settings [ CPAP_RampTime ] = ( int ) buffer [ offset + 0x06 ] ; // Minutes. Convert to seconds/hours here?
session - > settings [ CPAP_RampPressure ] = ( EventDataType ) buffer [ offset + 0x07 ] / 10.0 ;
2011-06-26 08:30:44 +00:00
if ( max > 0 ) { // Ignoring bipap until I see some more data.
2011-07-31 20:24:43 +00:00
session - > settings [ CPAP_Mode ] = ( int ) MODE_APAP ;
} else session - > settings [ CPAP_Mode ] = ( int ) MODE_CPAP ;
2011-06-26 08:30:44 +00:00
// This is incorrect..
2011-07-10 14:23:07 +00:00
if ( buffer [ offset + 0x08 ] & 0x80 ) { // Flex Setting
if ( buffer [ offset + 0x08 ] & 0x08 ) {
2011-09-17 12:39:00 +00:00
if ( max > 0 ) session - > settings [ PRS1_FlexMode ] = ( int ) PR_AFLEX ;
else session - > settings [ PRS1_FlexMode ] = ( int ) PR_CFLEXPLUS ;
} else session - > settings [ PRS1_FlexMode ] = ( int ) PR_CFLEX ;
} else session - > settings [ PRS1_FlexMode ] = ( int ) PR_NONE ;
session - > settings [ " FlexSet " ] = ( int ) buffer [ offset + 0x08 ] & 3 ;
session - > settings [ " HumidSet " ] = ( int ) buffer [ offset + 0x09 ] & 0x0f ;
session - > settings [ " HumidStat " ] = ( buffer [ offset + 0x09 ] & 0x80 ) = = 0x80 ;
session - > settings [ " SysLock " ] = ( buffer [ offset + 0x0a ] & 0x80 ) = = 0x80 ;
session - > settings [ " SysOneResistStat " ] = ( buffer [ offset + 0x0a ] & 0x40 ) = = 0x40 ;
session - > settings [ " SysOneResistSet " ] = ( int ) buffer [ offset + 0x0a ] & 7 ;
session - > settings [ " HoseDiam " ] = ( ( buffer [ offset + 0x0a ] & 0x08 ) ? " 15mm " : " 22mm " ) ;
session - > settings [ " AutoOff " ] = ( buffer [ offset + 0x0c ] & 0x10 ) = = 0x10 ;
session - > settings [ " MaskAlert " ] = ( buffer [ offset + 0x0c ] & 0x08 ) = = 0x08 ;
session - > settings [ " ShowAHI " ] = ( buffer [ offset + 0x0c ] & 0x04 ) = = 0x04 ;
2011-07-10 14:23:07 +00:00
2011-07-21 02:17:43 +00:00
unsigned duration = buffer [ offset + 0x14 ] | ( buffer [ 0x15 ] < < 8 ) ;
2011-07-31 20:24:43 +00:00
//session->settings[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-09-17 12:39:00 +00:00
//session->settings[PRS1_PressureMinAchieved]=buffer[offset+0x16]/10.0;
//session->settings[PRS1_PressureMaxAchieved]=buffer[offset+0x17]/10.0;
//session->settings[PRS1_PressureAvg]=buffer[offset+0x18]/10.0;
//session->settings[PRS1_Pressure90]=buffer[offset+0x19]/10.0;
2011-06-26 08:30:44 +00:00
if ( max = = 0 ) {
2011-09-17 12:39:00 +00:00
// session->settings[PRS1_PressureAvg]=session->settings[PRS1_PressureMin];
2011-06-26 08:30:44 +00:00
}
2011-07-31 20:24:43 +00:00
// Not using these because sometimes this summary is broken.
2011-07-21 02:17:43 +00:00
/*/if (size==0x4d) {
2011-06-26 08:30:44 +00:00
2011-07-31 20:24:43 +00:00
session - > settings [ CPAP_Obstructive ] = ( int ) buffer [ offset + 0x1C ] | ( buffer [ offset + 0x1D ] < < 8 ) ;
session - > settings [ CPAP_ClearAirway ] = ( int ) buffer [ offset + 0x20 ] | ( buffer [ offset + 0x21 ] < < 8 ) ;
session - > settings [ CPAP_Hypopnea ] = ( int ) buffer [ offset + 0x2A ] | ( buffer [ offset + 0x2B ] < < 8 ) ;
session - > settings [ CPAP_RERA ] = ( int ) buffer [ offset + 0x2E ] | ( buffer [ offset + 0x2F ] < < 8 ) ;
session - > settings [ CPAP_FlowLimit ] = ( int ) buffer [ offset + 0x30 ] | ( buffer [ offset + 0x31 ] < < 8 ) ;
2011-07-21 02:17:43 +00:00
} */
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
{
2011-09-17 12:39:00 +00:00
/*ChannelID Codes[]={
2011-07-31 20:24:43 +00:00
PRS1_Unknown00 , PRS1_Unknown01 , CPAP_Pressure , CPAP_EPAP , CPAP_PressurePulse , CPAP_RERA , CPAP_Obstructive , CPAP_ClearAirway ,
2011-06-26 08:30:44 +00:00
PRS1_Unknown08 , PRS1_Unknown09 , CPAP_Hypopnea , PRS1_Unknown0B , CPAP_FlowLimit , CPAP_VSnore , PRS1_Unknown0E , CPAP_CSR , PRS1_Unknown10 ,
CPAP_Leak , PRS1_Unknown12
} ;
2011-09-17 12:39:00 +00:00
int ncodes = sizeof ( Codes ) / sizeof ( ChannelID ) ; */
2011-06-26 08:30:44 +00:00
2011-09-17 12:39:00 +00:00
//QHash<ChannelID,EventList *> Code;
2011-07-27 09:21:53 +00:00
EventList * Code [ 0x20 ] = { NULL } ;
2011-07-10 14:23:07 +00:00
EventDataType data [ 10 ] ;
2011-06-26 08:30:44 +00:00
2011-07-31 20:24:43 +00:00
session - > updateFirst ( timestamp ) ;
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-08-17 03:06:57 +00:00
short delta ;
2011-11-27 22:36:38 +00:00
int tdata ;
2011-06-26 08:30:44 +00:00
while ( pos < size ) {
2011-07-10 14:23:07 +00:00
unsigned char code = buffer [ pos + + ] ;
2011-09-17 12:39:00 +00:00
if ( code > 0x12 ) {
2011-07-10 14:23:07 +00:00
qDebug ( ) < < " Illegal PRS1 code " < < hex < < int ( code ) < < " appeared at " < < hex < < pos + 16 ;
return false ;
}
2011-07-30 03:52:29 +00:00
delta = 0 ;
2011-06-26 08:30:44 +00:00
if ( code ! = 0x12 ) {
2011-07-20 16:01:31 +00:00
delta = buffer [ pos + 1 ] < < 8 | buffer [ pos ] ;
2011-06-26 08:30:44 +00:00
pos + = 2 ;
2011-08-17 03:06:57 +00:00
t + = qint64 ( delta ) * 1000L ;
2011-09-13 08:12:07 +00:00
tt = t ;
2011-06-26 08:30:44 +00:00
}
2011-07-30 03:52:29 +00:00
2011-06-26 08:30:44 +00:00
cnt + + ;
switch ( code ) {
2011-09-17 12:39:00 +00:00
2011-07-27 09:21:53 +00:00
case 0x00 : // Unknown 00
if ( ! Code [ 0 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 0 ] = session - > AddEventList ( PRS1_00 , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 0 ] - > AddEvent ( t , buffer [ pos + + ] ) ;
2011-07-10 14:23:07 +00:00
break ;
2011-07-27 09:21:53 +00:00
case 0x01 : // Unknown
if ( ! Code [ 1 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 1 ] = session - > AddEventList ( PRS1_01 , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 1 ] - > AddEvent ( t , 0 ) ;
2011-07-10 14:23:07 +00:00
break ;
2011-06-26 08:30:44 +00:00
case 0x02 : // Pressure
2011-07-27 09:21:53 +00:00
if ( ! Code [ 2 ] ) {
2011-09-17 12:39:00 +00:00
Code [ 2 ] = session - > AddEventList ( CPAP_Pressure , EVL_Event , 0.1 ) ;
if ( ! Code [ 2 ] ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 2 ] - > AddEvent ( t , buffer [ pos + + ] ) ;
2011-06-26 08:30:44 +00:00
break ;
2011-07-12 12:43:10 +00:00
case 0x03 : // BIPAP Pressure
2011-07-27 09:21:53 +00:00
if ( ! Code [ 3 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 3 ] = session - > AddEventList ( CPAP_EPAP , EVL_Event , 0.1 ) ) ) return false ;
if ( ! ( Code [ 4 ] = session - > AddEventList ( CPAP_IPAP , EVL_Event , 0.1 ) ) ) return false ;
if ( ! ( Code [ 5 ] = session - > AddEventList ( CPAP_PS , EVL_Event , 0.1 ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 3 ] - > AddEvent ( t , data [ 0 ] = buffer [ pos + + ] ) ;
Code [ 4 ] - > AddEvent ( t , data [ 1 ] = buffer [ pos + + ] ) ;
Code [ 5 ] - > AddEvent ( t , data [ 1 ] - data [ 0 ] ) ;
2011-07-12 12:43:10 +00:00
break ;
2011-06-26 08:30:44 +00:00
case 0x04 : // Pressure Pulse
2011-07-27 09:21:53 +00:00
if ( ! Code [ 6 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 6 ] = session - > AddEventList ( CPAP_PressurePulse , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 6 ] - > AddEvent ( t , buffer [ pos + + ] ) ;
2011-07-20 16:01:31 +00:00
//qDebug() << hex << data[0];
2011-06-26 08:30:44 +00:00
break ;
case 0x05 : // RERA
2011-07-27 09:21:53 +00:00
data [ 0 ] = buffer [ pos + + ] ;
2011-08-17 03:06:57 +00:00
tt = t - ( qint64 ( data [ 0 ] ) * 1000L ) ;
2011-07-27 09:21:53 +00:00
if ( ! Code [ 7 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 7 ] = session - > AddEventList ( CPAP_RERA , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 7 ] - > AddEvent ( tt , data [ 0 ] ) ;
break ;
2011-06-26 08:30:44 +00:00
case 0x06 : // Obstructive Apoanea
2011-07-27 09:21:53 +00:00
data [ 0 ] = buffer [ pos + + ] ;
2011-08-17 03:06:57 +00:00
tt = t - ( qint64 ( data [ 0 ] ) * 1000L ) ;
2011-07-27 09:21:53 +00:00
if ( ! Code [ 8 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 8 ] = session - > AddEventList ( CPAP_Obstructive , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 8 ] - > AddEvent ( tt , data [ 0 ] ) ;
break ;
2011-06-26 08:30:44 +00:00
case 0x07 : // Clear Airway
2011-07-27 09:21:53 +00:00
data [ 0 ] = buffer [ pos + + ] ;
2011-08-17 03:06:57 +00:00
tt = t - ( qint64 ( data [ 0 ] ) * 1000L ) ;
2011-07-27 09:21:53 +00:00
if ( ! Code [ 9 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 9 ] = session - > AddEventList ( CPAP_ClearAirway , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 9 ] - > AddEvent ( tt , data [ 0 ] ) ;
break ;
2011-07-12 12:43:10 +00:00
case 0x0a : // Hypopnea
2011-07-27 09:21:53 +00:00
data [ 0 ] = buffer [ pos + + ] ;
2011-08-17 03:06:57 +00:00
tt = t - ( qint64 ( data [ 0 ] ) * 1000L ) ;
2011-07-27 09:21:53 +00:00
if ( ! Code [ 10 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 10 ] = session - > AddEventList ( CPAP_Hypopnea , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 10 ] - > AddEvent ( tt , data [ 0 ] ) ;
break ;
2011-06-26 08:30:44 +00:00
case 0x0c : // Flow Limitation
2011-07-10 14:23:07 +00:00
data [ 0 ] = buffer [ pos + + ] ;
2011-08-17 03:06:57 +00:00
tt = t - ( qint64 ( data [ 0 ] ) * 1000L ) ;
2011-07-27 09:21:53 +00:00
if ( ! Code [ 11 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 11 ] = session - > AddEventList ( CPAP_FlowLimit , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 11 ] - > AddEvent ( tt , data [ 0 ] ) ;
2011-06-26 08:30:44 +00:00
break ;
2011-07-27 09:21:53 +00:00
case 0x0b : // Hypopnea related code
2011-07-11 05:46:12 +00:00
data [ 0 ] = buffer [ pos + + ] ;
data [ 1 ] = buffer [ pos + + ] ;
2011-07-27 09:21:53 +00:00
if ( ! Code [ 12 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 12 ] = session - > AddEventList ( PRS1_0B , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
// FIXME
Code [ 12 ] - > AddEvent ( t , data [ 0 ] ) ;
2011-07-11 05:46:12 +00:00
break ;
2011-06-26 08:30:44 +00:00
case 0x0d : // Vibratory Snore
2011-07-27 09:21:53 +00:00
if ( ! Code [ 13 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 13 ] = session - > AddEventList ( CPAP_VSnore , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 13 ] - > AddEvent ( t , 0 ) ;
2011-06-26 08:30:44 +00:00
break ;
2011-07-27 09:21:53 +00:00
case 0x11 : // Leak Rate & Snore Graphs
2011-06-26 08:30:44 +00:00
data [ 0 ] = buffer [ pos + + ] ;
data [ 1 ] = buffer [ pos + + ] ;
2011-07-27 09:21:53 +00:00
if ( ! Code [ 14 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 14 ] = session - > AddEventList ( CPAP_Leak , EVL_Event ) ) ) return false ;
if ( ! ( Code [ 15 ] = session - > AddEventList ( CPAP_Snore , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 14 ] - > AddEvent ( t , data [ 0 ] ) ;
Code [ 15 ] - > AddEvent ( t , data [ 1 ] ) ;
2011-07-10 14:23:07 +00:00
if ( data [ 1 ] > 0 ) {
2011-07-27 09:21:53 +00:00
if ( ! Code [ 16 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 16 ] = session - > AddEventList ( CPAP_VSnore2 , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 16 ] - > AddEvent ( t , data [ 1 ] ) ;
2011-06-26 08:30:44 +00:00
}
break ;
case 0x0e : // Unknown
2011-07-20 16:01:31 +00:00
data [ 0 ] = ( ( char * ) buffer ) [ pos + + ] ;
2011-07-15 10:01:28 +00:00
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 + + ] ;
2011-07-27 09:21:53 +00:00
if ( ! Code [ 17 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 17 ] = session - > AddEventList ( PRS1_0E , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
2011-11-27 22:36:38 +00:00
tdata = unsigned ( data [ 1 ] ) < < 8 | unsigned ( data [ 0 ] ) ;
Code [ 17 ] - > AddEvent ( t , tdata ) ;
2011-07-20 16:01:31 +00:00
//qDebug() << hex << data[0] << data[1] << data[2];
2011-07-27 09:21:53 +00:00
//session->AddEvent(new Event(t,cpapcode, 0, 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 + + ] ;
2011-07-27 09:21:53 +00:00
if ( ! Code [ 20 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 20 ] = session - > AddEventList ( PRS1_10 , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 20 ] - > AddEvent ( t , data [ 0 ] ) ;
2011-06-26 08:30:44 +00:00
break ;
case 0x0f : // Cheyne Stokes Respiration
data [ 0 ] = buffer [ pos + 1 ] < < 8 | buffer [ pos ] ;
pos + = 2 ;
data [ 1 ] = buffer [ pos + + ] ;
2011-08-17 03:06:57 +00:00
tt = t - qint64 ( data [ 1 ] ) * 1000L ;
2011-07-27 09:21:53 +00:00
if ( ! Code [ 23 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 23 ] = session - > AddEventList ( CPAP_CSR , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 23 ] - > AddEvent ( tt , data [ 0 ] ) ;
2011-06-26 08:30:44 +00:00
break ;
case 0x12 : // Summary
data [ 0 ] = buffer [ pos + + ] ;
data [ 1 ] = buffer [ pos + + ] ;
data [ 2 ] = buffer [ pos + 1 ] < < 8 | buffer [ pos ] ;
pos + = 2 ;
2011-07-27 09:21:53 +00:00
if ( ! Code [ 24 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 24 ] = session - > AddEventList ( PRS1_12 , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 24 ] - > AddEvent ( t , data [ 0 ] ) ;
2011-06-26 08:30:44 +00:00
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
}
}
2011-07-31 20:24:43 +00:00
session - > updateLast ( t ) ;
2011-07-27 09:21:53 +00:00
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
{
2011-09-17 12:39:00 +00:00
QString Codes [ ] = {
PRS1_00 , PRS1_01 , CPAP_Pressure , CPAP_EPAP , CPAP_PressurePulse , CPAP_Obstructive ,
CPAP_ClearAirway , CPAP_Hypopnea , PRS1_08 , CPAP_FlowLimit , PRS1_0A , CPAP_CSR ,
PRS1_0C , CPAP_VSnore , PRS1_0E , PRS1_0F , PRS1_10 ,
CPAP_Leak , PRS1_12
2011-07-10 14:23:07 +00:00
} ;
2011-09-17 12:39:00 +00:00
int ncodes = sizeof ( Codes ) / sizeof ( QString ) ;
2011-07-10 14:23:07 +00:00
2011-07-27 09:21:53 +00:00
EventList * Code [ 0x20 ] = { NULL } ;
//for (int i=0;i<0x20;i++) Code[i]=NULL;
2011-07-31 20:24:43 +00:00
session - > updateFirst ( timestamp ) ;
2011-07-10 14:23:07 +00:00
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-19 16:44:03 +00:00
if ( code = = 0 ) {
} else
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 ;
2011-08-17 03:06:57 +00:00
t + = qint64 ( delta ) * 1000L ;
2011-07-10 14:23:07 +00:00
}
2011-09-17 12:39:00 +00:00
QString 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 ;
2011-07-27 09:21:53 +00:00
2011-07-10 14:23:07 +00:00
switch ( code ) {
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 + + ;
}
break ;
2011-07-27 09:21:53 +00:00
case 0x01 : // Unknown
if ( ! Code [ 1 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 1 ] = session - > AddEventList ( cpapcode , EVL_Event , 0.1 ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 1 ] - > AddEvent ( t , 0 ) ;
break ;
2011-07-10 14:23:07 +00:00
case 0x02 : // Pressure
2011-07-27 09:21:53 +00:00
data [ 0 ] = buffer [ pos + + ] ;
if ( ! Code [ 2 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 2 ] = session - > AddEventList ( cpapcode , EVL_Event , 0.1 ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 2 ] - > AddEvent ( t , data [ 0 ] ) ;
2011-07-10 14:23:07 +00:00
break ;
case 0x04 : // Pressure Pulse
data [ 0 ] = buffer [ pos + + ] ;
2011-07-27 09:21:53 +00:00
if ( ! Code [ 3 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 3 ] = session - > AddEventList ( cpapcode , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 3 ] - > AddEvent ( t , data [ 0 ] ) ;
2011-07-10 14:23:07 +00:00
break ;
case 0x05 :
2011-07-27 09:21:53 +00:00
data [ 0 ] = buffer [ pos + + ] ;
2011-08-17 03:06:57 +00:00
tt - = qint64 ( data [ 0 ] ) * 1000L ; // Subtract Time Offset
2011-07-27 09:21:53 +00:00
if ( ! Code [ 4 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 4 ] = session - > AddEventList ( cpapcode , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 4 ] - > AddEvent ( tt , data [ 0 ] ) ;
break ;
2011-07-10 14:23:07 +00:00
case 0x06 :
2011-07-27 09:21:53 +00:00
data [ 0 ] = buffer [ pos + + ] ;
2011-08-17 03:06:57 +00:00
tt - = qint64 ( data [ 0 ] ) * 1000L ; // Subtract Time Offset
2011-07-27 09:21:53 +00:00
if ( ! Code [ 5 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 5 ] = session - > AddEventList ( cpapcode , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 5 ] - > AddEvent ( tt , data [ 0 ] ) ;
break ;
2011-07-10 14:23:07 +00:00
case 0x07 :
2011-07-27 09:21:53 +00:00
data [ 0 ] = buffer [ pos + + ] ;
2011-08-17 03:06:57 +00:00
tt - = qint64 ( data [ 0 ] ) * 1000L ; // Subtract Time Offset
2011-07-27 09:21:53 +00:00
if ( ! Code [ 6 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 6 ] = session - > AddEventList ( cpapcode , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 6 ] - > AddEvent ( tt , data [ 0 ] ) ;
break ;
case 0x08 : // ASV Codes
data [ 0 ] = buffer [ pos + + ] ;
2011-08-17 03:06:57 +00:00
tt - = qint64 ( data [ 0 ] ) * 1000L ; // Subtract Time Offset
2011-07-27 09:21:53 +00:00
if ( ! Code [ 10 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 10 ] = session - > AddEventList ( cpapcode , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 10 ] - > AddEvent ( tt , data [ 0 ] ) ;
break ;
case 0x09 : // ASV Codes
data [ 0 ] = buffer [ pos + + ] ;
2011-08-17 03:06:57 +00:00
tt - = qint64 ( data [ 0 ] ) * 1000L ; // Subtract Time Offset
2011-07-27 09:21:53 +00:00
if ( ! Code [ 11 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 11 ] = session - > AddEventList ( cpapcode , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 11 ] - > AddEvent ( tt , data [ 0 ] ) ;
break ;
case 0x0a :
data [ 0 ] = buffer [ pos + + ] ;
2011-08-17 03:06:57 +00:00
tt - = qint64 ( data [ 0 ] ) * 1000L ; // Subtract Time Offset
2011-07-27 09:21:53 +00:00
if ( ! Code [ 7 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 7 ] = session - > AddEventList ( cpapcode , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 7 ] - > AddEvent ( tt , data [ 0 ] ) ;
break ;
2011-07-10 14:23:07 +00:00
case 0x0c :
data [ 0 ] = buffer [ pos + + ] ;
2011-08-17 03:06:57 +00:00
tt - = qint64 ( data [ 0 ] ) * 1000L ; // Subtract Time Offset
2011-07-27 09:21:53 +00:00
if ( ! Code [ 8 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 8 ] = session - > AddEventList ( cpapcode , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 8 ] - > AddEvent ( tt , data [ 0 ] ) ;
2011-07-10 14:23:07 +00:00
break ;
2011-07-27 09:21:53 +00:00
2011-07-10 14:23:07 +00:00
case 0x0b : // Cheyne Stokes
data [ 0 ] = ( ( unsigned char * ) buffer ) [ pos + 1 ] < < 8 | ( ( unsigned char * ) buffer ) [ pos ] ;
2011-07-27 09:21:53 +00:00
//data[0]*=2;
2011-07-10 14:23:07 +00:00
pos + = 2 ;
data [ 1 ] = ( ( unsigned char * ) buffer ) [ pos ] ; //|buffer[pos+1] << 8
pos + = 1 ;
//tt-=delta;
2011-08-17 03:06:57 +00:00
tt - = qint64 ( data [ 1 ] ) * 1000L ;
2011-07-27 09:21:53 +00:00
if ( ! Code [ 9 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 9 ] = session - > AddEventList ( cpapcode , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 9 ] - > AddEvent ( tt , data [ 0 ] ) ;
//session->AddEvent(new Event(tt,cpapcode, data[0], data, 2));
2011-07-10 14:23:07 +00:00
break ;
case 0x0d : // All the other ASV graph stuff.
2011-07-27 09:21:53 +00:00
if ( ! Code [ 12 ] ) {
2011-09-23 03:54:48 +00:00
if ( ! ( Code [ 12 ] = session - > AddEventList ( CPAP_IPAP , EVL_Event ) ) ) return false ;
if ( ! ( Code [ 13 ] = session - > AddEventList ( CPAP_IPAPLo , EVL_Event ) ) ) return false ;
if ( ! ( Code [ 14 ] = session - > AddEventList ( CPAP_IPAPHi , EVL_Event ) ) ) return false ;
if ( ! ( Code [ 15 ] = session - > AddEventList ( CPAP_Leak , EVL_Event ) ) ) return false ;
if ( ! ( Code [ 16 ] = session - > AddEventList ( CPAP_RespRate , EVL_Event ) ) ) return false ;
if ( ! ( Code [ 17 ] = session - > AddEventList ( CPAP_PTB , EVL_Event ) ) ) return false ;
if ( ! ( Code [ 18 ] = session - > AddEventList ( CPAP_MinuteVent , EVL_Event ) ) ) return false ;
if ( ! ( Code [ 19 ] = session - > AddEventList ( CPAP_TidalVolume , EVL_Event ) ) ) return false ;
if ( ! ( Code [ 20 ] = session - > AddEventList ( CPAP_Snore , EVL_Event ) ) ) return false ;
if ( ! ( Code [ 22 ] = session - > AddEventList ( CPAP_EPAP , EVL_Event ) ) ) return false ;
if ( ! ( Code [ 23 ] = session - > AddEventList ( CPAP_PS , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 12 ] - > AddEvent ( t , data [ 0 ] = buffer [ pos + + ] ) ; // IAP
Code [ 13 ] - > AddEvent ( t , buffer [ pos + + ] ) ; // IAP Low
Code [ 14 ] - > AddEvent ( t , buffer [ pos + + ] ) ; // IAP High
Code [ 15 ] - > AddEvent ( t , buffer [ pos + + ] ) ; // LEAK
Code [ 16 ] - > AddEvent ( t , buffer [ pos + + ] ) ; // Breaths Per Minute
Code [ 17 ] - > AddEvent ( t , buffer [ pos + + ] ) ; // Patient Triggered Breaths
Code [ 18 ] - > AddEvent ( t , buffer [ pos + + ] ) ; // Minute Ventilation
Code [ 19 ] - > AddEvent ( t , buffer [ pos + + ] ) ; // Tidal Volume
Code [ 20 ] - > AddEvent ( t , data [ 2 ] = buffer [ pos + + ] ) ; // Snore
if ( data [ 2 ] > 0 ) {
if ( ! Code [ 21 ] ) {
2011-09-17 12:39:00 +00:00
if ( ! ( Code [ 21 ] = session - > AddEventList ( " VSnore " , EVL_Event ) ) ) return false ;
2011-07-27 09:21:53 +00:00
}
Code [ 21 ] - > AddEvent ( t , 0 ) ; //data[2]); // VSnore
}
Code [ 22 ] - > AddEvent ( t , data [ 1 ] = buffer [ pos + + ] ) ; // EPAP
Code [ 23 ] - > AddEvent ( t , data [ 0 ] - data [ 1 ] ) ; // Pressure Support
2011-07-10 14:23:07 +00:00
break ;
case 0x03 : // BIPAP Pressure
2011-07-27 09:21:53 +00:00
qDebug ( ) < < " 0x03 Observed in ASV data!!???? " ;
2011-07-10 14:23:07 +00:00
data [ 0 ] = buffer [ pos + + ] ;
data [ 1 ] = buffer [ pos + + ] ;
2011-07-27 09:21:53 +00:00
/*data[0]/=10.0;
2011-07-10 14:23:07 +00:00
data [ 1 ] / = 10.0 ;
2011-07-27 09:21:53 +00:00
session - > AddEvent ( new Event ( t , CPAP_EAP , 0 , data , 1 ) ) ;
session - > AddEvent ( new Event ( t , CPAP_IAP , 0 , & data [ 1 ] , 1 ) ) ; */
2011-07-10 14:23:07 +00:00
break ;
2011-07-27 09:21:53 +00:00
case 0x11 : // Not Leak Rate
qDebug ( ) < < " 0x11 Observed in ASV data!!???? " ;
//if (!Code[24]) {
// Code[24]=new EventList(cpapcode,EVL_Event);
//}
//Code[24]->AddEvent(t,buffer[pos++]);
2011-07-10 14:23:07 +00:00
break ;
case 0x0e : // Unknown
2011-07-27 09:21:53 +00:00
qDebug ( ) < < " 0x0E Observed in ASV data!!???? " ;
2011-07-10 14:23:07 +00:00
data [ 0 ] = buffer [ pos + + ] ; // << 8) | buffer[pos];
2011-07-27 09:21:53 +00:00
//session->AddEvent(new Event(t,cpapcode, 0, data, 1));
2011-07-10 14:23:07 +00:00
break ;
case 0x10 : // Unknown
2011-07-27 09:21:53 +00:00
qDebug ( ) < < " 0x10 Observed in ASV data!!???? " ;
2011-07-10 14:23:07 +00:00
data [ 0 ] = buffer [ pos + + ] ; // << 8) | buffer[pos];
data [ 1 ] = buffer [ pos + + ] ;
data [ 2 ] = buffer [ pos + + ] ;
2011-07-27 09:21:53 +00:00
//session->AddEvent(new Event(t,cpapcode, 0, data, 3));
2011-07-10 14:23:07 +00:00
break ;
case 0x0f :
2011-07-27 09:21:53 +00:00
qDebug ( ) < < " 0x0f Observed in ASV data!!???? " ;
2011-07-10 14:23:07 +00:00
data [ 0 ] = buffer [ pos + 1 ] < < 8 | buffer [ pos ] ;
pos + = 2 ;
data [ 1 ] = buffer [ pos ] ; //|buffer[pos+1] << 8
pos + = 1 ;
2011-08-17 03:06:57 +00:00
tt - = qint64 ( data [ 1 ] ) * 1000L ;
2011-07-27 09:21:53 +00:00
//session->AddEvent(new Event(tt,cpapcode, 0, data, 2));
2011-07-10 14:23:07 +00:00
break ;
case 0x12 : // Summary
2011-07-27 09:21:53 +00:00
qDebug ( ) < < " 0x12 Observed in ASV data!!???? " ;
2011-07-10 14:23:07 +00:00
data [ 0 ] = buffer [ pos + + ] ;
data [ 1 ] = buffer [ pos + + ] ;
data [ 2 ] = buffer [ pos + 1 ] < < 8 | buffer [ pos ] ;
pos + = 2 ;
2011-07-27 09:21:53 +00:00
//session->AddEvent(new Event(t,cpapcode, 0, data,3));
2011-07-10 14:23:07 +00:00
break ;
default :
// ERROR!!!
qWarning ( ) < < " Some new fandangled PRS1 code detected " < < hex < < int ( code ) < < " at " < < pos + 15 ;
return false ;
}
}
2011-07-31 20:24:43 +00:00
session - > updateLast ( t ) ;
2011-07-10 14:23:07 +00:00
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-11-26 04:00:31 +00:00
unsigned char crcbytes [ 2 ] ;
if ( f . read ( ( char * ) crcbytes , 2 ) ! = 2 ) {
qDebug ( ) < < " No ending CRC bytes in " < < filename ;
}
quint16 crc = ( crcbytes [ 1 ] < < 8 ) | crcbytes [ 0 ] ;
quint16 c16 = CRC16 ( buffer , size ) ;
if ( crc ! = c16 ) {
qDebug ( ) < < " CRC check failed, wanted " < < crc < < " got " < < c16 ;
}
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 ;
}
2011-07-21 11:02:23 +00:00
struct WaveHeaderList {
quint16 interleave ;
quint8 sample_format ;
WaveHeaderList ( quint16 i , quint8 f ) { interleave = i ; sample_format = f ; }
} ;
2011-06-26 08:30:44 +00:00
bool PRS1Loader : : OpenWaveforms ( Session * session , QString filename )
2011-07-21 11:02:23 +00:00
{
//int sequence,seconds,br,htype,version,numsignals;
QFile file ( filename ) ;
if ( ! file . open ( QIODevice : : ReadOnly ) ) {
qWarning ( ) < < " Couldn't open waveform file " < < filename ;
return false ;
}
int pos , br , size = file . size ( ) ;
if ( size > max_load_buffer_size ) {
qWarning ( ) < < " Waveform too big, increase max_load_buffer_size in PRS1Loader sourcecode " < < filename ;
return false ;
}
br = file . read ( ( char * ) m_buffer , size ) ;
if ( br < size ) {
qWarning ( ) < < " Couldn't read waveform data.. Disk error? " < < filename ;
return false ;
}
// Look at the initial header and assume this header size for the lot.
if ( ( m_buffer [ 0 ] ! = 2 ) | | ( m_buffer [ 6 ] ! = 0x05 ) ) {
qWarning ( ) < < " Not correct waveform format " < < filename ;
return false ;
}
2011-07-27 09:21:53 +00:00
//quint8 version=m_buffer[4];
2011-07-21 11:02:23 +00:00
quint32 start = m_buffer [ 0xb ] | m_buffer [ 0xc ] < < 8 | m_buffer [ 0xd ] < < 16 | m_buffer [ 0x0e ] < < 24 ;
2011-07-27 09:21:53 +00:00
2011-07-31 20:24:43 +00:00
session - > updateFirst ( qint64 ( start ) * 1000L ) ;
2011-07-27 09:21:53 +00:00
2011-07-21 11:02:23 +00:00
quint16 num_signals = m_buffer [ 0x12 ] | m_buffer [ 0x13 ] < < 8 ;
if ( num_signals > 2 ) {
qWarning ( ) < < " More than 2 Waveforms in " < < filename ;
return false ;
}
pos = 0x14 + ( num_signals - 1 ) * 3 ;
vector < WaveHeaderList > whl ;
// add the in reverse...
for ( int i = 0 ; i < num_signals ; i + + ) {
quint16 interleave = m_buffer [ pos ] | m_buffer [ pos + 1 ] < < 8 ;
quint8 sample_format = m_buffer [ pos + 2 ] ;
whl . push_back ( WaveHeaderList ( interleave , sample_format ) ) ;
pos - = 3 ;
}
int hl = 15 + 5 + ( num_signals * 3 ) ;
2011-08-17 03:06:57 +00:00
quint16 duration , length = 0 ;
2011-07-21 11:02:23 +00:00
quint32 timestamp , lasttimestamp ;
pos = 0 ;
int block = 0 ;
lasttimestamp = start ;
duration = 0 ;
int corrupt = 0 ;
char waveform [ num_signals ] [ 500000 ] ;
int wlength [ num_signals ] ;
2011-07-27 09:21:53 +00:00
qint64 wdur [ num_signals ] ;
//EventList *evl[num_signals];
2011-07-21 11:02:23 +00:00
for ( int i = 0 ; i < num_signals ; i + + ) {
wlength [ i ] = 0 ;
wdur [ i ] = 0 ;
2011-07-27 09:21:53 +00:00
//evl[i]=NULL;
2011-07-21 11:02:23 +00:00
//waveform[i].resize(500000);
}
2011-07-27 09:21:53 +00:00
//SampleFormat *wf[num_signals];
//EventList *FlowData=EventList(CPAP_FlowRate, EVL_Waveform,1,0,-128,128);
//EventList *MaskData=EventList(CPAP_MaskPressure, EVL_Waveform,1,0,-128,128);
2011-11-27 04:50:22 +00:00
//QString FlowRate=CPAP_FlowRate;
//QString MaskPressure="MaskPressure";
QString wc [ 2 ] = { CPAP_FlowRate , CPAP_MaskPressure } ;
2011-07-21 11:02:23 +00:00
do {
timestamp = m_buffer [ pos + 0xb ] | m_buffer [ pos + 0xc ] < < 8 | m_buffer [ pos + 0xd ] < < 16 | m_buffer [ pos + 0x0e ] < < 24 ;
register unsigned char sum8 = 0 ;
for ( int i = 0 ; i < hl ; i + + ) sum8 + = m_buffer [ pos + i ] ;
if ( m_buffer [ pos + hl ] ! = sum8 ) {
if ( block = = 0 ) {
qDebug ( ) < < " Faulty Header Checksum, aborting " < < filename ;
return false ;
}
if ( + + corrupt > 3 ) {
qDebug ( ) < < " 3 Faulty Waveform Headers in a row.. Aborting " < < filename ;
return false ;
}
qDebug ( ) < < " Faulty Header Checksum, skipping block " < < block ;
pos + = length ;
continue ;
} else {
2011-07-22 13:46:17 +00:00
int diff = timestamp - ( lasttimestamp + duration ) ;
if ( block = = 1 ) {
if ( diff > 0 )
start - = diff ;
}
2011-07-21 11:02:23 +00:00
length = m_buffer [ pos + 0x1 ] | m_buffer [ pos + 0x2 ] < < 8 ; // block length in bytes
duration = m_buffer [ pos + 0xf ] | m_buffer [ pos + 0x10 ] < < 8 ; // block duration in seconds
2011-07-22 16:38:22 +00:00
if ( diff < 0 ) {
qDebug ( ) < < " Padding waveform to keep sync " < < block ;
2011-07-22 13:46:17 +00:00
//diff=abs(diff);
for ( int i = 0 ; i < num_signals ; i + + ) {
for ( int j = 0 ; j < diff ; j + + ) {
for ( int k = 0 ; k < whl [ i ] . interleave ; k + + )
waveform [ i ] [ wlength [ i ] + + ] = 0 ;
}
wdur [ i ] + = diff ;
}
} else
if ( diff > 0 & & wlength [ 0 ] > 0 ) {
2011-07-27 09:21:53 +00:00
qDebug ( ) < < " Timestamp resync " < < block < < diff < < corrupt < < duration < < timestamp - lasttimestamp < < filename ;
2011-07-22 13:46:17 +00:00
2011-07-21 11:02:23 +00:00
for ( int i = 0 ; i < num_signals ; i + + ) {
2011-07-27 09:21:53 +00:00
double rate = ( double ( wdur [ i ] ) * 1000.0 ) / double ( wlength [ i ] ) ;
double gain ;
if ( i = = 1 ) gain = 0.1 ; else gain = 1 ;
2011-09-17 12:39:00 +00:00
EventList * a = session - > AddEventList ( wc [ i ] , EVL_Waveform , gain , 0 , 0 , 0 , rate ) ;
//EventList *a=new EventList(wc[i],EVL_Waveform,gain,0,0,0,rate);
//session->machine()->registerChannel(wc[i]);
2011-07-27 09:21:53 +00:00
if ( whl [ i ] . sample_format )
a - > AddWaveform ( qint64 ( start ) * 1000L , ( unsigned char * ) waveform [ i ] , wlength [ i ] , qint64 ( wdur [ i ] ) * 1000L ) ;
else {
a - > AddWaveform ( qint64 ( start ) * 1000L , ( char * ) waveform [ i ] , wlength [ i ] , qint64 ( wdur [ i ] ) * 1000L ) ;
}
2011-11-27 04:50:22 +00:00
if ( wc [ i ] = = CPAP_FlowRate ) {
2011-07-27 09:21:53 +00:00
a - > setMax ( 120 ) ;
a - > setMin ( - 120 ) ;
2011-11-27 04:50:22 +00:00
} else if ( wc [ i ] = = CPAP_MaskPressure ) {
2011-07-27 09:21:53 +00:00
/* int v=ceil(a->max()/5);
a - > setMax ( v * 5 ) ;
v = floor ( a - > min ( ) / 5 ) ;
a - > setMin ( v * 5 ) ; */
2011-07-21 11:02:23 +00:00
}
2011-07-27 09:21:53 +00:00
2011-07-31 20:24:43 +00:00
session - > updateLast ( start + ( qint64 ( wdur [ i ] ) * 1000L ) ) ;
2011-07-21 11:02:23 +00:00
wlength [ i ] = 0 ;
wdur [ i ] = 0 ;
}
start = timestamp ;
corrupt = 0 ;
2011-07-22 16:38:22 +00:00
}
2011-07-21 11:02:23 +00:00
}
pos + = hl + 1 ;
2011-07-22 13:46:17 +00:00
//qDebug() << (duration*num_signals*whl[0].interleave) << duration;
2011-07-21 11:02:23 +00:00
if ( num_signals = = 1 ) { // no interleave.. this is much quicker.
int bs = duration * whl [ 0 ] . interleave ;
memcpy ( ( char * ) & ( waveform [ 0 ] ) [ wlength [ 0 ] ] , ( char * ) & m_buffer [ pos ] , bs ) ;
wlength [ 0 ] + = bs ;
pos + = bs ;
} else {
for ( int i = 0 ; i < duration ; i + + ) {
for ( int s = 0 ; s < num_signals ; s + + ) {
memcpy ( ( char * ) & ( waveform [ s ] ) [ wlength [ s ] ] , ( char * ) & m_buffer [ pos ] , whl [ s ] . interleave ) ;
wlength [ s ] + = whl [ s ] . interleave ;
pos + = whl [ s ] . interleave ;
}
}
}
for ( int i = 0 ; i < num_signals ; i + + ) wdur [ i ] + = duration ;
pos + = 2 ;
block + + ;
lasttimestamp = timestamp ;
} while ( pos < size ) ;
for ( int i = 0 ; i < num_signals ; i + + ) {
2011-07-27 09:21:53 +00:00
double rate = ( double ( wdur [ i ] ) * 1000.0 ) / double ( wlength [ i ] ) ;
double gain ;
if ( i = = 1 ) gain = 0.1 ; else gain = 1 ;
2011-09-17 12:39:00 +00:00
EventList * a = session - > AddEventList ( wc [ i ] , EVL_Waveform , gain , 0 , 0 , 0 , rate ) ;
2011-07-27 09:21:53 +00:00
if ( whl [ i ] . sample_format )
a - > AddWaveform ( qint64 ( start ) * 1000L , ( unsigned char * ) waveform [ i ] , wlength [ i ] , qint64 ( wdur [ i ] ) * 1000L ) ;
else {
a - > AddWaveform ( qint64 ( start ) * 1000L , ( char * ) waveform [ i ] , wlength [ i ] , qint64 ( wdur [ i ] ) * 1000L ) ;
2011-07-20 16:01:31 +00:00
}
2011-11-27 04:50:22 +00:00
if ( wc [ i ] = = CPAP_FlowRate ) {
2011-07-27 09:21:53 +00:00
a - > setMax ( 120 ) ;
a - > setMin ( - 120 ) ;
2011-11-27 04:50:22 +00:00
} else if ( wc [ i ] = = CPAP_MaskPressure ) {
2011-06-26 08:30:44 +00:00
}
2011-07-31 20:24:43 +00:00
session - > updateLast ( start + qint64 ( wdur [ i ] ) * 1000L ) ;
2011-07-10 14:23:07 +00:00
}
2011-11-27 16:44:13 +00:00
if ( num_signals < 2 ) {
2011-11-27 04:50:22 +00:00
CalcRespiratoryRate ( session ) ;
2011-11-27 16:44:13 +00:00
}
2011-06-26 08:30:44 +00:00
return true ;
2011-07-27 09:21:53 +00:00
}
2011-11-27 04:50:22 +00:00
// Generate RespiratoryRate graph
void PRS1Loader : : CalcRespiratoryRate ( Session * session )
{
EventList * flow , * rr ;
for ( int ws = 0 ; ws < session - > eventlist [ CPAP_FlowRate ] . size ( ) ; ws + + ) {
flow = session - > eventlist [ CPAP_FlowRate ] [ ws ] ;
if ( flow - > count ( ) > 5 ) {
rr = new EventList ( EVL_Event ) ; //EVL_Waveform,1,0,0,0,60000);
2011-11-27 16:44:13 +00:00
session - > eventlist [ CPAP_RespRate ] . push_back ( rr ) ;
2011-11-27 04:50:22 +00:00
filterFlow ( flow , rr ) ;
}
}
}
void PRS1Loader : : filterFlow ( EventList * in , EventList * out )
{
int size = in - > count ( ) ;
EventDataType * stage1 = new EventDataType [ size ] ;
EventDataType * stage2 = new EventDataType [ size ] ;
QVector < EventDataType > med ;
med . reserve ( 8 ) ;
EventDataType r ;
int cnt ;
// Anti-Alias the flow waveform to get rid of jagged edges.
EventDataType c ;
double avg ;
int i ;
/*i=2;
stage1 [ 0 ] = in - > data ( 0 ) ;
stage1 [ 1 ] = in - > data ( 1 ) ;
//stage1[2]=in->data(2);
for ( ; i < size - 2 ; i + + ) {
med . clear ( ) ;
for ( quint32 k = 0 ; k < 5 ; k + + ) {
med . push_back ( in - > data ( i - 2 + k ) ) ;
}
qSort ( med ) ;
stage1 [ i ] = med [ 3 ] ;
}
stage1 [ i ] = in - > data ( i ) ;
i + + ;
stage1 [ i ] = in - > data ( i ) ; */
//i++;
//stage1[i]=in->data(i);
stage2 [ 0 ] = stage1 [ 0 ] ;
stage2 [ 1 ] = stage1 [ 1 ] ;
stage2 [ 2 ] = stage1 [ 2 ] ;
i = 3 ;
for ( ; i < size - 3 ; i + + ) {
cnt = 0 ;
r = 0 ;
for ( quint32 k = 0 ; k < 7 ; k + + ) {
//r+=stage1[i-3+k];
r + = in - > data ( i - 3 + k ) ;
cnt + + ;
}
c = r / float ( cnt ) ;
stage2 [ i ] = c ;
}
stage2 [ i ] = in - > data ( i ) ;
i + + ;
stage2 [ i ] = in - > data ( i ) ;
i + + ;
stage2 [ i ] = in - > data ( i ) ;
//i++;
//stage2[i]=in->data(i);
float weight = 0.6 ;
//stage2[0]=in->data(0);
stage1 [ 0 ] = stage2 [ 0 ] ;
for ( int i = 1 ; i < size ; i + + ) {
//stage2[i]=in->data(i);
stage1 [ i ] = weight * stage2 [ i ] + ( 1.0 - weight ) * stage1 [ i - 1 ] ;
}
qint64 time = in - > first ( ) ;
qint64 u1 = 0 , u2 = 0 , len , l1 = 0 , l2 = 0 ;
EventDataType lastc = 0 , thresh = 0 ;
QVector < int > breaths ;
QVector < qint64 > breaths_start ;
for ( i = 0 ; i < size ; i + + ) {
c = stage1 [ i ] ;
if ( c > thresh ) {
if ( lastc < = thresh ) {
u2 = u1 ;
u1 = time ;
if ( u2 > 0 ) {
len = abs ( u2 - u1 ) ;
//if (len>1500) {
breaths_start . push_back ( time ) ;
breaths . push_back ( len ) ;
//}
}
}
} else {
if ( lastc > thresh ) {
l2 = l1 ;
l1 = time ;
if ( l2 > 0 ) {
len = abs ( l2 - l1 ) ;
//if (len>1500) {
// breaths2_start.push_back(time);
// breaths2.push_back(len);
//}
}
}
}
lastc = c ;
time + = 200 ;
}
qint64 window = 60000 ;
qint64 t1 = in - > first ( ) - window / 2 ;
qint64 t2 = in - > first ( ) + window / 2 ;
qint64 t ;
EventDataType br , q ;
int z = 0 ;
int l ;
QVector < int > breaths2 ;
QVector < qint64 > breaths2_start ;
int fir = 0 ;
do {
br = 0 ;
bool first = true ;
bool cont = false ;
for ( int i = fir ; i < breaths . size ( ) ; i + + ) {
t = breaths_start [ i ] ;
l = breaths [ i ] ;
if ( t + l < t1 ) continue ;
if ( t > t2 ) break ;
if ( first ) {
first = false ;
fir = i ;
}
//q=1;
if ( t < t1 ) {
// move to start of previous breath
t1 = breaths_start [ + + i ] ;
t2 = t1 + window ;
fir = i ;
cont = true ;
break ;
//q=(t+l)-t1;
//br+=(1.0/double(l))*double(q);
} else if ( t + l > t2 ) {
q = t2 - t ;
br + = ( 1.0 / double ( l ) ) * double ( q ) ;
continue ;
} else
br + = 1.0 ;
}
if ( cont ) continue ;
breaths2 . push_back ( br ) ;
breaths2_start . push_back ( t1 + window / 2 ) ;
//out->AddEvent(t,br);
//stage2[z++]=br;
t1 + = window / 2.0 ;
t2 + = window / 2.0 ;
} while ( t2 < in - > last ( ) ) ;
for ( int i = 1 ; i < breaths2 . size ( ) - 2 ; i + + ) {
t = breaths2_start [ i ] ;
med . clear ( ) ;
for ( int j = 0 ; j < 4 ; j + + ) {
med . push_back ( breaths2 [ i + j - 1 ] ) ;
}
qSort ( med ) ;
br = med [ 2 ] ;
out - > AddEvent ( t , br ) ;
}
delete [ ] stage2 ;
delete [ ] stage1 ;
}
2011-07-22 13:46:17 +00:00
2011-06-26 08:30:44 +00:00
void InitModelMap ( )
{
2011-10-10 21:29:15 +00:00
ModelMap [ 0x34 ] = " RemStar Pro with C-Flex+ " ;
ModelMap [ 0x35 ] = " RemStar Auto with A-Flex " ;
2011-11-26 04:00:31 +00:00
ModelMap [ 0x36 ] = " RemStar BiPAP Pro with Bi-Flex " ;
2011-10-10 21:29:15 +00:00
ModelMap [ 0x37 ] = " RemStar BiPAP Auto with Bi-Flex " ;
2011-07-11 01:58:51 +00:00
ModelMap [ 0x41 ] = " BiPAP autoSV Advanced " ;
2011-11-26 04:00:31 +00:00
}
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 ;
}
2011-11-27 04:50:22 +00:00