/* SleepLib Session Implementation This stuff contains the base calculation smarts Copyright (c)2011 Mark Watkins License: GPL */ #include "session.h" #include "math.h" #include #include #include #include #include using namespace std; Session::Session(Machine * m,SessionID session) { if (!session) { session=m->CreateSessionID(); } s_machine=m; s_session=session; s_changed=false; s_events_loaded=false; _first_session=true; s_first=s_last=0; s_eventfile=""; } Session::~Session() { TrashEvents(); } void Session::TrashEvents() // Trash this sessions Events and release memory. { map >::iterator i; vector::iterator j; for (i=eventlist.begin(); i!=eventlist.end(); i++) { for (j=i->second.begin(); j!=i->second.end(); j++) { delete *j; } } eventlist.clear(); } //const int max_pack_size=128; bool Session::OpenEvents() { if (s_events_loaded) return true; bool b; b=LoadEvents(s_eventfile); if (!b) { qWarning() << "Error Unkpacking Events" << s_eventfile; return false; } return s_events_loaded=true; }; bool Session::Store(QString path) // Storing Session Data in our format // {DataDir}/{MachineID}/{SessionID}.{ext} { QDir dir(path); if (!dir.exists(path)) dir.mkpath(path); QString base; base.sprintf("%08lx",s_session); base=path+"/"+base; //qDebug() << "Storing Session: " << base; bool a; a=StoreSummary(base+".000"); // if actually has events //qDebug() << " Summary done"; if (eventlist.size()>0) StoreEvents(base+".001"); //qDebug() << " Events done"; if (a) { s_changed=false; } return a; } const quint32 magic=0xC73216AB; bool IsPlatformLittleEndian() { quint32 j=1; *((char*)&j) = 0; return j!=1; } bool Session::StoreSummary(QString filename) { QFile file(filename); file.open(QIODevice::WriteOnly); QDataStream out(&file); out.setVersion(QDataStream::Qt_4_6); out << (quint32)magic; out << (quint32)s_machine->id(); out << (quint32)s_session; out << (quint16)0 << (quint16)0; quint32 starttime=s_first/1000L; quint32 duration=(s_last-s_first)/1000L; out << (quint32)starttime; // Session Start Time out << (quint32)duration; // Duration of sesion in seconds. out << (quint16)summary.size(); map mctype; // First output the Machine Code and type for each summary record map::iterator i; for (i=summary.begin(); i!=summary.end(); i++) { MachineCode mc=i->first; QMetaType::Type type=(QMetaType::Type)i->second.type(); // Urkk.. this is a mess. if (type==QMetaType::Bool) { mctype[mc]=MC_bool; } else if (type==QMetaType::Int) { mctype[mc]=MC_int; } else if (type==QMetaType::LongLong) { mctype[mc]=MC_long; } else if (type==QMetaType::Double) { mctype[mc]=MC_double; } else if (type==QMetaType::Float) { mctype[mc]=MC_float; } else if (type==QMetaType::QString) { mctype[mc]=MC_string; } else if (type==QMetaType::QDateTime) { mctype[mc]=MC_datetime; } else { QString t=i->second.typeToName((QVariant::Type)type); qWarning() << "Error in Session->StoreSummary: Can't pack variant type " << t; return false; //exit(1); } out << (qint16)mc; out << (qint8)mctype[mc]; } // Then dump out the actual data, according to format. for (i=summary.begin(); i!=summary.end(); i++) { MachineCode mc=i->first; if (mctype[mc]==MC_bool) { out << i->second.toBool(); } else if (mctype[mc]==MC_int) { out << (qint32)i->second.toInt(); } else if (mctype[mc]==MC_long) { out << (qint64)i->second.toLongLong(); } else if (mctype[mc]==MC_double) { out << (double)i->second.toDouble(); } else if (mctype[mc]==MC_float) { float f=(float)i->second.toDouble(); // check me. out << f; } else if (mctype[mc]==MC_string) { out << i->second.toString(); } else if (mctype[mc]==MC_datetime) { out << i->second.toDateTime(); } } file.close(); return true; } bool Session::LoadSummary(QString filename) { if (filename.isEmpty()) return false; //qDebug() << "Loading Summary " << filename; QFile file(filename); if (!file.open(QIODevice::ReadOnly)) { qDebug() << "Couldn't open file" << filename; return false; } QDataStream in(&file); in.setVersion(QDataStream::Qt_4_6); quint64 t64; quint32 t32; quint16 t16; quint8 t8; qint16 sumsize; map mctype; vector mcorder; in >> t32; if (t32!=magic) { qDebug() << "Wrong magic number in " << filename; return false; } in >> t32; // MachineID (dont need this result) in >> t32; // Sessionid; s_session=t32; in >> t16; // File Type if (t16!=0) { qDebug() << "Wrong file type"; //wrong file type return false; } in >> t16; // File Version // dont care yet in >> t32; // Start time s_first=qint64(t32)*1000L; in >> t32; // Duration // (16bit==Limited to 18 hours) s_last=s_first+qint64(t32)*1000L; in >> sumsize; // Summary size (number of Machine Code lists) for (int i=0; i> t16; // Machine Code MachineCode mc=(MachineCode)t16; in >> t8; // Data Type mctype[mc]=(MCDataType)t8; mcorder.push_back(mc); } for (int i=0; i> b; summary[mc]=b; } else if (mctype[mc]==MC_int) { in >> t32; summary[mc]=(qint32)t32; } else if (mctype[mc]==MC_long) { in >> t64; summary[mc]=(qint64)t64; } else if (mctype[mc]==MC_double) { double dl; in >> dl; summary[mc]=(double)dl; } else if (mctype[mc]==MC_float) { float fl; in >> fl; summary[mc]=(float)fl; } else if (mctype[mc]==MC_string) { QString s; in >> s; summary[mc]=s; } else if (mctype[mc]==MC_datetime) { QDateTime dt; in >> dt; summary[mc]=dt; } } return true; } bool Session::StoreEvents(QString filename) { QFile file(filename); file.open(QIODevice::WriteOnly); QDataStream out(&file); out.setVersion(QDataStream::Qt_4_6); out << (quint32)magic; // Magic Number out << (quint32)s_machine->id(); // Machine ID out << (quint32)s_session; // This session's ID out << (quint16)1; // File type 1 == Event out << (quint16)0; // File Version out << s_first; out << s_last; out << (qint16)eventlist.size(); // Number of event categories map >::iterator i; vector::iterator j; for (i=eventlist.begin(); i!=eventlist.end(); i++) { out << (qint16)i->first; // MachineCode out << (qint16)i->second.size(); for (unsigned j=0;jsecond.size();j++) { EventList &e=*i->second[j]; out << e.first(); out << e.last(); out << (qint32)e.count(); out << (qint8)e.type(); out << e.rate(); out << e.gain(); out << e.offset(); //if (!e.update_minmax()) { out << e.min(); out << e.max(); //} else { // out << (EventDataType)0; // out << (EventDataType)0; //} } } qint64 t,last; quint32 x; for (i=eventlist.begin(); i!=eventlist.end(); i++) { for (unsigned j=0;jsecond.size();j++) { EventList &e=*i->second[j]; for (int c=0;c> t32; // Magic Number if (t32!=magic) { qWarning() << "Wrong Magic number in " << filename; return false; } in >> t32; // MachineID in >> t32; // Sessionid; s_session=t32; in >> t16; // File Type if (t16!=1) { qDebug() << "Wrong File Type in " << filename; return false; } in >> t16; // File Version // dont give a crap yet.. in >> s_first; in >> s_last; qint16 mcsize; in >> mcsize; // Summary size (number of Machine Code lists) MachineCode code; qint64 ts1,ts2; qint32 evcount; EventListType elt; EventDataType rate,gain,offset,mn,mx; qint16 size2; vector mcorder; vector sizevec; for (int i=0;i> t16; code=(MachineCode)t16; mcorder.push_back(code); in >> size2; sizevec.push_back(size2); for (int j=0;j> ts1; //UpdateFirst(ts1); in >> ts2; //UpdateLast(ts2); in >> evcount; in >> t8; elt=(EventListType)t8; in >> rate; in >> gain; in >> offset; in >> mn; in >> mx; EventList *elist=new EventList(code,elt,gain,offset,mn,mx,rate); eventlist[code].push_back(elist); elist->m_count=evcount; elist->m_first=ts1; elist->m_last=ts2; } } EventStoreType t; qint64 last; quint32 x; for (int i=0;i> t; evec.m_data[c]=t; } last=evec.first(); if (evec.type()!=EVL_Waveform) { evec.m_time.resize(evec.m_count); for (int c=0;c> x; last+=x; evec.m_time[c]=last; } } } } return true; } EventDataType Session::min(MachineCode code) { if (eventlist.find(code)==eventlist.end()) return 0; vector & evec=eventlist[code]; bool first=true; EventDataType min,t1; for (unsigned i=0;imin(); if (t1==evec[i]->max()) continue; if (first) { min=t1; first=false; } else { if (min>t1) min=t1; } } return min; } EventDataType Session::max(MachineCode code) { if (eventlist.find(code)==eventlist.end()) return 0; vector & evec=eventlist[code]; bool first=true; EventDataType max,t1; for (unsigned i=0;imax(); if (t1==evec[i]->min()) continue; if (first) { max=t1; first=false; } else { if (max & evec=eventlist[code]; bool first=true; qint64 min,t1; for (unsigned i=0;ifirst(); if (first) { min=t1; first=false; } else { if (min>t1) min=t1; } } return min; } qint64 Session::last(MachineCode code) { if (eventlist.find(code)==eventlist.end()) return 0; vector & evec=eventlist[code]; bool first=true; qint64 max,t1; for (unsigned i=0;ilast(); if (first) { max=t1; first=false; } else { if (max & evec=eventlist[code]; int sum=0; for (unsigned i=0;icount(); } return sum; } double Session::sum(MachineCode mc) { if (eventlist.find(mc)==eventlist.end()) return 0; vector & evec=eventlist[mc]; double sum=0; for (unsigned i=0;icount();j++) { sum+=evec[i]->data(j); } } return sum; } EventDataType Session::avg(MachineCode mc) { if (eventlist.find(mc)==eventlist.end()) return 0; double cnt=count(mc); if (cnt==0) return 0; EventDataType val=sum(mc)/cnt; return val; } bool sortfunction (double i,double j) { return (i array; vector & evec=eventlist[mc]; for (unsigned i=0;icount();j++) { array.push_back(evec[i]->data(j)); } } std::sort(array.begin(),array.end(),sortfunction); int size=array.size(); if (!size) return 0; double i=size*percent; double t; modf(i,&t); int j=t; //if (j>=size-1) return array[j]; return array[j]; } EventDataType Session::weighted_avg(MachineCode mc) { if (eventlist.find(mc)==eventlist.end()) return 0; int cnt=0; bool first=true; qint64 last; int lastval=0,val; const int max_slots=4096; qint64 vtime[max_slots]={0}; double mult=10.0; //if ((mc==CPAP_Pressure) || (mc==CPAP_EAP) || (mc==CPAP_IAP) | (mc==CPAP_PS)) { // mult=10.0; //} else mult=10.0; // vector::iterator i; vector & evec=eventlist[mc]; for (unsigned i=0;icount();j++) { val=evec[i]->data(j)*mult; if (first) { first=false; } else { int d=(evec[i]->time(j)-last)/1000L; if (lastval>max_slots) { qWarning("max_slots to small in Session::weighted_avg()"); return 0; } vtime[lastval]+=d; } cnt++; last=evec[i]->time(j); lastval=val; } } qint64 total=0; for (int i=0; i 0) { s0=vtime[i]; s1+=i*s0; s2+=s0; } } double j=double(s1)/double(total); return j/mult; }