Commit e7e51bee by yiannis

Latest

parent ed1be620
...@@ -51,7 +51,6 @@ CDaqChannelInfo::GetItemSize() const ...@@ -51,7 +51,6 @@ CDaqChannelInfo::GetItemSize() const
} }
////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////
/// ///
/// This function allows user to specify error and progress callbacks. The /// This function allows user to specify error and progress callbacks. The
...@@ -95,6 +94,93 @@ NearDump(FILE* p, int ofs) ...@@ -95,6 +94,93 @@ NearDump(FILE* p, int ofs)
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/// ///
/// Utility function that writes ASCII data given an untyped pointer to it.
///
///
static bool
WriteAsciiLine(
FILE* pFile,
CDaqChannelInfo& chInf,
const void* pData,
TConvertOptions options)
{
assert(pFile);
int sample;
if ( chInf.GetType() == 'c' ) {
for (sample=0; sample < chInf.GetItemCount(); sample++) {
// skip strings for now
}
}
else if ( chInf.GetType() == 'f' ) {
float *p = (float *)pData;
for (sample=0; sample < (int)chInf.GetItemCount(); sample++) {
fprintf(pFile, "%E ", *p);
p++;
}
}
else if ( chInf.GetType() == 'i' ) {
int *p = (int *)pData;
for (sample=0; sample < (int)chInf.GetItemCount(); sample++) {
fprintf(pFile, "%d ", *p);
p++;
}
}
else if ( chInf.GetType() == 'd' ) {
double *p = (double *)pData;
for (sample=0; sample < (int)chInf.GetItemCount(); sample++) {
fprintf(pFile, "%E ", *p);
p++;
}
}
else if ( chInf.GetType() == 's' ) {
int *p = (int *)pData;
for (sample=0; sample < (int)chInf.GetItemCount(); sample++) {
fprintf(pFile, "%d ", *p);
p++;
}
}
else {
assert(0);
}
return true;
}
/////////////////////////////////////////////////////////////////////////////
///
/// This function determines if a frame was dropped by the DAQ. The
/// function requires that integrity testing has taken place (i.e., a TOC
/// exists.
///
bool
CDaqLowLevelIo::FrameDropped(int frm)
{
vector<int>::const_iterator pDrpFrm; // iterates list of dropped frames
for (pDrpFrm = m_DroppedFrames.begin(); pDrpFrm != m_DroppedFrames.end(); pDrpFrm++){
if ( frm == *pDrpFrm )return true;
}
return false;
}
/////////////////////////////////////////////////////////////////////////////
///
/// This function determines if data was logged for a given frame
///
bool
CDaqLowLevelIo::FrameHasData(int frm)
{
map<int, int>::const_iterator p;
p = m_Toc.find(frm);
return p != m_Toc.end();
}
/////////////////////////////////////////////////////////////////////////////
///
/// Reads the header of the DAQ file, independent of its version, and /// Reads the header of the DAQ file, independent of its version, and
/// stores the information in variables local to the class instance. /// stores the information in variables local to the class instance.
/// Values that are not provided in the specific file version are set /// Values that are not provided in the specific file version are set
...@@ -518,7 +604,7 @@ CDaqLowLevelIo::WriteTocFile( ...@@ -518,7 +604,7 @@ CDaqLowLevelIo::WriteTocFile(
if ( fwrite(&d1, sizeof(int), 1, p) != 1 ) return false; if ( fwrite(&d1, sizeof(int), 1, p) != 1 ) return false;
// first frame // first frame
d1 = this->m_FirstFrame; d1 = m_FirstFrame;
if ( fwrite(&d1, sizeof(int), 1, p) != 1 ) return false; if ( fwrite(&d1, sizeof(int), 1, p) != 1 ) return false;
// last frame // last frame
...@@ -616,11 +702,12 @@ CDaqLowLevelIo::ReadTocFile( ...@@ -616,11 +702,12 @@ CDaqLowLevelIo::ReadTocFile(
// we don't need the offset now, it's for future compatibility // we don't need the offset now, it's for future compatibility
if ( fread(&d1, sizeof(int), 1, p) != 1 ) return false; if ( fread(&d1, sizeof(int), 1, p) != 1 ) return false;
// Let the TOC contents override auto-calc for first/last frame
if ( fread(&d1, sizeof(int), 1, p) != 1 ) return false; if ( fread(&d1, sizeof(int), 1, p) != 1 ) return false;
if ( m_FirstFrame != d1 ) return false; m_FirstFrame = d1;
if ( fread(&d1, sizeof(int), 1, p) != 1 ) return false; if ( fread(&d1, sizeof(int), 1, p) != 1 ) return false;
if ( m_LastFrame != d1 ) return false; m_LastFrame = d1;
if ( fread(&d1, sizeof(int), 1, p) != 1 ) return false; if ( fread(&d1, sizeof(int), 1, p) != 1 ) return false;
numEntries = d1; numEntries = d1;
...@@ -747,6 +834,7 @@ CDaqLowLevelIo::CheckIntegrity( ...@@ -747,6 +834,7 @@ CDaqLowLevelIo::CheckIntegrity(
int numFrames = 0; int numFrames = 0;
map<int, TFrameInfo> tempToc; map<int, TFrameInfo> tempToc;
bool done = false; bool done = false;
int largestFrame = -1;
// //
// Go through the file and build the TOC. Only frames with data that // Go through the file and build the TOC. Only frames with data that
...@@ -768,6 +856,8 @@ CDaqLowLevelIo::CheckIntegrity( ...@@ -768,6 +856,8 @@ CDaqLowLevelIo::CheckIntegrity(
if ( (numFrames % 720) == 0 ) (*m_UserProgrFunc)(m_Filename.c_str(), if ( (numFrames % 720) == 0 ) (*m_UserProgrFunc)(m_Filename.c_str(),
numFrames, m_LastFrame - m_FirstFrame); numFrames, m_LastFrame - m_FirstFrame);
if ( curFrame > largestFrame ) largestFrame = curFrame;
frameOffset = ftell(m_pFile) - 12; frameOffset = ftell(m_pFile) - 12;
numFrames++; numFrames++;
...@@ -892,6 +982,15 @@ CDaqLowLevelIo::CheckIntegrity( ...@@ -892,6 +982,15 @@ CDaqLowLevelIo::CheckIntegrity(
int old = -1; int old = -1;
int curFrame; int curFrame;
// We have to be careful in messed up files because the m_LastFrame calculated
// by the Open... is the last frame found in the file; In messed up files, the
// last frame found is not necessarily the last frame with data
if ( largestFrame > m_LastFrame ) {
sprintf(buf, "Highest number frame (%d) wasn't last one in file,"
"which was %d", largestFrame, m_LastFrame);
(*m_UserErrorFunc)(m_Filename.c_str(), buf);
m_LastFrame = largestFrame;
}
while ( frm < m_LastFrame ) { while ( frm < m_LastFrame ) {
if ( tempToc.find(frm) != tempToc.end() ) {// if it's in the map, it was in the file if ( tempToc.find(frm) != tempToc.end() ) {// if it's in the map, it was in the file
curFrame = frm; curFrame = frm;
...@@ -916,6 +1015,7 @@ CDaqLowLevelIo::CheckIntegrity( ...@@ -916,6 +1015,7 @@ CDaqLowLevelIo::CheckIntegrity(
if ( pTempToc->second.numChan > 0 ) m_Toc[pTempToc->first] = pTempToc->second.ofs; if ( pTempToc->second.numChan > 0 ) m_Toc[pTempToc->first] = pTempToc->second.ofs;
} }
m_HaveToc = true; m_HaveToc = true;
if ( writeTocFile ) { if ( writeTocFile ) {
...@@ -953,7 +1053,8 @@ CDaqLowLevelIo::CheckIntegrity( ...@@ -953,7 +1053,8 @@ CDaqLowLevelIo::CheckIntegrity(
bool bool
CDaqLowLevelIo::LowLevelDataRead( CDaqLowLevelIo::LowLevelDataRead(
const vector<int>* pWhichChannels, const vector<int>* pWhichChannels,
vector<CDaqBuffer>& userStorage vector<CDaqBuffer>& userStorage,
vector<TIntVec>* pFrameList
) )
{ {
// //
...@@ -964,7 +1065,12 @@ CDaqLowLevelIo::LowLevelDataRead( ...@@ -964,7 +1065,12 @@ CDaqLowLevelIo::LowLevelDataRead(
return false; return false;
} }
if ( pWhichChannels && pWhichChannels->size() != userStorage.size() ) { bool haveChansBadSize;
bool noChansBadSize;
haveChansBadSize = pWhichChannels && pWhichChannels->size() != userStorage.size();
noChansBadSize = pWhichChannels == 0 && userStorage.size() != m_NumEntries;
if ( haveChansBadSize || noChansBadSize ) {
m_LastError = "inconsistently sized input arguments"; m_LastError = "inconsistently sized input arguments";
return false; return false;
} }
...@@ -989,6 +1095,8 @@ CDaqLowLevelIo::LowLevelDataRead( ...@@ -989,6 +1095,8 @@ CDaqLowLevelIo::LowLevelDataRead(
needChan.resize(m_NumEntries, -1); needChan.resize(m_NumEntries, -1);
for (i=0; i<pWhichChannels->size(); i++) { for (i=0; i<pWhichChannels->size(); i++) {
if ( (*pWhichChannels)[i] < 0 || (*pWhichChannels)[i] >= m_NumEntries) { if ( (*pWhichChannels)[i] < 0 || (*pWhichChannels)[i] >= m_NumEntries) {
sprintf(buf, "Invalid channel %d", (*pWhichChannels)[i]);
m_LastError = buf;
return false; return false;
} }
needChan[(*pWhichChannels)[i]] = i; needChan[(*pWhichChannels)[i]] = i;
...@@ -1000,16 +1108,23 @@ CDaqLowLevelIo::LowLevelDataRead( ...@@ -1000,16 +1108,23 @@ CDaqLowLevelIo::LowLevelDataRead(
needChan.push_back(i); needChan.push_back(i);
} }
TIntVec empty;
if ( pFrameList ) pFrameList->resize(needChan.size(), empty);
// //
// Go through the file collecting the data we need. // Go through the file collecting the data we need.
// //
int numFrames = 0; int numFrames = 0;
int curFrame = -1; // frame for current record
fseek(m_pFile, m_DataOffset, SEEK_SET); fseek(m_pFile, m_DataOffset, SEEK_SET);
while ( 1 ) { while ( 1 ) {
int recHead[3]; // (Code, Frame, Count) int recHead[3]; // (Code, Frame, Count)
int curFrame = -1; // frame for current record
int numChan; // number of channels in current record int numChan; // number of channels in current record
// If we have an end frame, use it as a loop termination criteria
if ( m_EofStatus != eDAQ_EOF_NOTFOUND && m_EofStatus != eDAQ_EOF_UNDEFINED ) {
if ( curFrame >= m_LastFrame ) break;
}
if ( fread(recHead, sizeof(int), 3, m_pFile) != 3 ) { if ( fread(recHead, sizeof(int), 3, m_pFile) != 3 ) {
sprintf(buf, "Couldn't read file, premature end or messed up file"); sprintf(buf, "Couldn't read file, premature end or messed up file");
m_LastError = buf; m_LastError = buf;
...@@ -1024,12 +1139,11 @@ CDaqLowLevelIo::LowLevelDataRead( ...@@ -1024,12 +1139,11 @@ CDaqLowLevelIo::LowLevelDataRead(
// print info every 30 seconds of collection (30*240=720) // print info every 30 seconds of collection (30*240=720)
if ( (numFrames % 720) == 0 ) if ( (numFrames % 720) == 0 )
(*m_UserProgrFunc)(m_Filename.c_str(), numFrames, m_LastFrame - m_FirstFrame); (*m_UserProgrFunc)(m_Filename.c_str(), numFrames, m_LastFrame - m_FirstFrame);
} }
else if ( recHead[0] == -2 ) { // This is an end marker else if ( recHead[0] == -2 ) { // This is an end marker
curFrame = recHead[1]; curFrame = recHead[1];
if ( recHead[2] == DAQ_END_MARK ) { if ( recHead[2] == DAQ_END_MARK ) {
break; break; // successfully found EOF
} }
else { else {
sprintf(buf, "Unexpected secondary code %d at line %d", recHead[0], sprintf(buf, "Unexpected secondary code %d at line %d", recHead[0],
...@@ -1061,11 +1175,17 @@ CDaqLowLevelIo::LowLevelDataRead( ...@@ -1061,11 +1175,17 @@ CDaqLowLevelIo::LowLevelDataRead(
int chId; int chId;
if ( fread(&chId, sizeof(int), 1, m_pFile) != 1 ) { if ( fread(&chId, sizeof(int), 1, m_pFile) != 1 ) {
sprintf(buf, "Couldn't read file, premature end"); sprintf(buf, "Couldn't read file, premature end, frm=%d, ofs=%d", curFrame, ftell(m_pFile));
m_LastError = buf; m_LastError = buf;
return false; return false;
} }
if ( chId >= m_NumEntries ) { if ( chId >= m_NumEntries || chId < 0 ) {
int dummy;
int rcode = ResyncChannel(curFrame, dummy);
if ( rcode == eRESYNC_CHANNEL || rcode == eRESYNC_FRAME ) {
printf("ERROR, ofs %d\n", ftell(m_pFile));
break;
}
sprintf(buf, "Encountered invalid channel %d in data area", chId); sprintf(buf, "Encountered invalid channel %d in data area", chId);
m_LastError = buf; m_LastError = buf;
return false; return false;
...@@ -1090,6 +1210,7 @@ CDaqLowLevelIo::LowLevelDataRead( ...@@ -1090,6 +1210,7 @@ CDaqLowLevelIo::LowLevelDataRead(
return false; return false;
} }
daqBuf.Append(pTempSpace, size, ch.GetItemCount()); daqBuf.Append(pTempSpace, size, ch.GetItemCount());
if ( pFrameList ) (*pFrameList)[needChan[chId]].push_back(curFrame);
} }
else { else {
// skip the data // skip the data
...@@ -1104,9 +1225,9 @@ CDaqLowLevelIo::LowLevelDataRead( ...@@ -1104,9 +1225,9 @@ CDaqLowLevelIo::LowLevelDataRead(
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
/// ///
/// This function is similar to LowLevelDataRead but instead of reading the data /// This function copies data from a DAQ file into a set of output files for which the
/// into memory buffers it copies the data into a set of output files for which the /// user has already obtained FILE handles. The function can optionally fill in
/// user has already obtained FILE handles. /// missing data and provides options on how to handle differentially stored data.
/// ///
/// The function will scan the whole file and store the samples of each channel /// The function will scan the whole file and store the samples of each channel
/// specified in chans into the corresponding file. The options argument controls /// specified in chans into the corresponding file. The options argument controls
...@@ -1121,8 +1242,7 @@ CDaqLowLevelIo::LowLevelDataRead( ...@@ -1121,8 +1242,7 @@ CDaqLowLevelIo::LowLevelDataRead(
/// If the eFILL_MISSING option is set, then the function will detect dropped /// If the eFILL_MISSING option is set, then the function will detect dropped
/// frames and write out replacement values to ensure that all the output file(s) /// frames and write out replacement values to ensure that all the output file(s)
/// contain the appropriate number of samples. Data for dropped frames is generated /// contain the appropriate number of samples. Data for dropped frames is generated
/// by using the most recent data of the same channel (eFILL_MISSING_ORDER_0), linear /// by using the most recent data of the same channel.
/// interpolation (eFILL_MISSING_ORDER_1) or cubic interpolation (eFILL_MISSING_ORDER_2).
/// ///
/// The output files can be written in ASCII or binary. The argument FileHandles /// The output files can be written in ASCII or binary. The argument FileHandles
/// is a vector of FILE pointers that should already have been opened successfully. /// is a vector of FILE pointers that should already have been opened successfully.
...@@ -1210,14 +1330,18 @@ CDaqLowLevelIo::LowLevelDataCopy( ...@@ -1210,14 +1330,18 @@ CDaqLowLevelIo::LowLevelDataCopy(
} }
int frm = m_FirstFrame; int frm = m_FirstFrame;
bool NoExpandDiff = (options & eEXPAND_DIFFERENTIAL) == 0;
vector<bool> gotData;
gotData.resize(m_NumEntries, false);
while ( frm <= m_LastFrame ) { while ( frm <= m_LastFrame ) {
map<int, int>::const_iterator pTocEn; map<int, int>::const_iterator pTocEn; // iterates list of frames for which we have data
vector<int>::const_iterator pDrpFrm; vector<int>::const_iterator pDrpFrm; // iterates list of dropped frames
bool curFrameLost = false; bool curFrameLost = false;
int numChan; int numChan;
// determine if this is a frame that was dropped // determine if this is a frame that was dropped by searching through the
// list of dropped frames calculated during the integrity verification phase
for (pDrpFrm = m_DroppedFrames.begin(); pDrpFrm != m_DroppedFrames.end(); pDrpFrm++){ for (pDrpFrm = m_DroppedFrames.begin(); pDrpFrm != m_DroppedFrames.end(); pDrpFrm++){
if ( frm == *pDrpFrm ) { if ( frm == *pDrpFrm ) {
curFrameLost = true; curFrameLost = true;
...@@ -1227,7 +1351,7 @@ CDaqLowLevelIo::LowLevelDataCopy( ...@@ -1227,7 +1351,7 @@ CDaqLowLevelIo::LowLevelDataCopy(
if ( curFrameLost == false ) { if ( curFrameLost == false ) {
pTocEn = m_Toc.find(frm); // does it have data ? pTocEn = m_Toc.find(frm); // does it have data ?
if ( pTocEn == m_Toc.end() ) { // no data for this frame if ( pTocEn == m_Toc.end() ) { // no data collected for this frame
// do nothing // do nothing
} }
else { else {
...@@ -1243,32 +1367,79 @@ CDaqLowLevelIo::LowLevelDataCopy( ...@@ -1243,32 +1367,79 @@ CDaqLowLevelIo::LowLevelDataCopy(
} }
assert(frm == actualFrameRead); assert(frm == actualFrameRead);
ReadDataForOneFrame(numChan, needChan, latestData, pTempSpace); for (int ii=0; ii<m_NumEntries; ii++) gotData[ii] = false;
ReadDataForOneFrame(numChan, needChan, latestData, pTempSpace, gotData);
for (int ch=0; ch < m_NumEntries; ch++) { for (int ch=0; ch < m_NumEntries; ch++) {
CDaqChannelInfo& chInf = m_Channels[ch]; CDaqChannelInfo& chInf = m_Channels[ch];
int size = chInf.GetRecSize(); int size = chInf.GetRecSize();
size_t out; size_t out;
int nn = needChan[ch]; int nn = needChan[ch];
if ( options & eASCII_FORMAT ) {
WriteAsciiLine(FileHandles[needChan[ch]],chInf,
latestData[needChan[ch]].GetDataPtr(), options);
}
else { // binary format
// if this is a differentially stored channel, we must
// take into account the user option
bool NoNewData = latestData[needChan[ch]].GetSize() == 0;
bool differential = chInf.GetCapRate() < 0;
if ( differential && NoExpandDiff && NoNewData )
continue;
if ( options & eINCLUDE_FRAME ) {
fwrite(&frm, sizeof(int), 1, FileHandles[needChan[ch]]);
}
out = fwrite(latestData[needChan[ch]].GetDataPtr(), size, 1, out = fwrite(latestData[needChan[ch]].GetDataPtr(), size, 1,
FileHandles[needChan[ch]]); FileHandles[needChan[ch]]);
if ( out != 1 ) {
sprintf(buf, "Write error while outputing channel %d", ch);
m_LastError = buf;
return false;
}
}
} }
} }
} }
else { // current frame lost else { // current frame lost
if ( options & eFILL_MISSING ) {
// Produce data for current frame based on prior values // Produce data for current frame based on prior values
for (int ch=0; ch < m_NumEntries; ch++) { for (int ch=0; ch < m_NumEntries; ch++) {
CDaqChannelInfo& chInf = m_Channels[ch]; CDaqChannelInfo& chInf = m_Channels[ch];
int size = chInf.GetRecSize(); int size = chInf.GetRecSize();
size_t out; size_t out;
bool NoNewData = latestData[needChan[ch]].GetSize() == 0;
bool differential = chInf.GetCapRate() < 0;
if ( differential && NoExpandDiff && NoNewData )
continue;
if ( options & eASCII_FORMAT ) {
WriteAsciiLine(FileHandles[needChan[ch]], chInf,
latestData[needChan[ch]].GetDataPtr(), options);
}
else {
if ( options & eINCLUDE_FRAME ) {
fwrite(&frm, sizeof(int), 1, FileHandles[needChan[ch]]);
}
out = fwrite(latestData[needChan[ch]].GetDataPtr(), size, 1, out = fwrite(latestData[needChan[ch]].GetDataPtr(), size, 1,
FileHandles[needChan[ch]]); FileHandles[needChan[ch]]);
if ( out != 1 ) {
sprintf(buf, "Write error while outputing channel %d", ch);
m_LastError = buf;
return false;
}
}
}
} }
} }
frm++; frm++;
} }
return true; return true;
} }
...@@ -1279,64 +1450,35 @@ CDaqLowLevelIo::LowLevelDataCopy( ...@@ -1279,64 +1450,35 @@ CDaqLowLevelIo::LowLevelDataCopy(
/// data management and selection of a range of frames to read. Also, unlike /// data management and selection of a range of frames to read. Also, unlike
/// LowLevelDataRead, this function can only be called if the class has access /// LowLevelDataRead, this function can only be called if the class has access
/// to the table of contents (either built with the CheckDataIntegrity function or /// to the table of contents (either built with the CheckDataIntegrity function or
/// read from a prior run). Finally, the function always expands differentially /// read from a prior run). Finally, the function can expand differentially
/// stored channels. /// stored channels or write them out in compressed format, according to user options
/// ///
/// The function reads the specified list of channels into memory buffers, /// The function reads the specified list of channels into memory buffers,
/// fills in data for dropped frames, can optionally re-sample the data, and /// expands differentially stored data, and fills in data for dropped frames.
/// if specified, read a subset of the data based on a start and end frame. /// If specified, it can read a subset of the data based on a start and end frame.
/// ///
/// The chans vector lists the identifiers for which channels to read. The /// The chans vector lists the identifiers for which channels to read. The
/// data vector contains data buffers onto which to store the samples of the /// data vector contains data buffers onto which to store the samples of the
/// corresponding channels. /// corresponding channels.
/// ///
/// The subsample vector indicates if the corresponding
/// channel should be sub-sampled. The number should be an integer greater than
/// or equal to 0. It is interpreted as follows:
/// If 0, then a data sample is written as often as it was collected in the file
/// If greater than zero, the function will output data every so many fbs
/// frames, starting with the first frame on which the channel was collected,
/// independent of how often data was sampled. The corresponding entry in the
/// options array specifies how to interpolate or extrapolate data.
///
/// Consider the following example. The first line indicates during which
/// fbs frames a channel was collected. The second line shows the actual
/// fbs frame numbers. The remaining lines have an X at each frame at which
/// data would be output depending on the value of the respective subsample
/// element. Note that each time during which the function outputs a value
/// but there was no corresponding collection at runtime will result in
/// the application of interpolation according to the options array.
///
/// Sample collected : X X X X
/// FBS frm : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/// subsample = 0 : X X X X
/// subsample = 1 : X X X X X X X X X X X X X X
/// subsample = 2 : X X X X X X X
/// subsample = 3 : X X X X X
/// subsample = 4 : X X X X
///
/// Finally, note that for differentially stored data, the extrapolation /// Finally, note that for differentially stored data, the extrapolation
/// method defaults to zero-hold, no matter what specification is given. /// method defaults to zero-hold.
///
/// The options argument is used to specify how to deal with dropped frames
/// and as such, the function is only concerned with the eFILL_MISSING_XXXXXX
/// options. In particular, specifying eFILL_MISSING will fill in dropped
/// frames by using a zero-hold technique by default. Specify any
/// of eFILL_MISSING_ORDER_? constants to modify the default behavior.
/// ///
/// The frm1 and frm2 arguments specify the first/last frame to read, inclusively. /// The frm1 and frm2 arguments specify the first/last frame to read, inclusively.
/// Specify -1 for either, to read from the start or to the end of file respectively. /// Specify -1 to read from the start or to the end of file respectively.
/// The frame numbers are 0 based, so the first frame would be 0. /// The frame numbers are 0 based, so the first frame would be 0.
/// ///
bool bool
CDaqLowLevelIo::GetFullData( CDaqLowLevelIo::GetFullData(
const TIntVec* pWhichChannels, const TIntVec* pWhichChannels,
TDataVec& data, TDataVec& userDataStorage, ///< Where to store the data
const TIntVec& subsample, TConvertOptions option,
TConvertOptions options, int frm1, ///< First frame to sample, or -1 for first in file
int frm1, int frm2, ///< Last frame to sample, or -1 for last in file
int frm2) vector<TIntVec>* pFrmList) ///< Where to store frame sequences
{ {
char buf[256]; // buffer for writing messages
// //
// Standard error checking // Standard error checking
// //
...@@ -1344,19 +1486,18 @@ CDaqLowLevelIo::GetFullData( ...@@ -1344,19 +1486,18 @@ CDaqLowLevelIo::GetFullData(
m_LastError = "uninitialized class instance"; m_LastError = "uninitialized class instance";
return false; return false;
} }
if ( m_HaveToc == false ) {
m_LastError = "need to buld table of contents first";
return false;
}
if ( frm1 > GetFrames() || frm2 > GetFrames() ) { if ( frm1 > GetFrames() || frm2 > GetFrames() ) {
m_LastError = "invalid frame range"; m_LastError = "invalid frame range";
return false; return false;
} }
if ( (option & eINCLUDE_FRAME) && pFrmList == 0 ) {
// m_LastError = "must provide storage for frames when eINCLUDE_FRAME is specified";
// Adjust frame numbers so they reflect fbs frames return false;
// }
if ( frm1 < 0 ) frm1 = GetFirstFrame(); else frm1 += GetFirstFrame();
if ( frm2 < 0 ) frm2 = GetLastFrame(); else frm2 += GetLastFrame();
char buf[256]; // buffer for writing messages
// //
// Create a faster data structure to tell us which channels are needed. // Create a faster data structure to tell us which channels are needed.
...@@ -1365,21 +1506,35 @@ CDaqLowLevelIo::GetFullData( ...@@ -1365,21 +1506,35 @@ CDaqLowLevelIo::GetFullData(
// //
vector<int> needChan; vector<int> needChan;
if ( pWhichChannels ) { if ( pWhichChannels ) {
unsigned i;
needChan.resize(m_NumEntries, -1); needChan.resize(m_NumEntries, -1);
for (i=0; i<pWhichChannels->size(); i++) { for (unsigned i=0; i<pWhichChannels->size(); i++) {
if ( (*pWhichChannels)[i] < 0 || (*pWhichChannels)[i] >= m_NumEntries) { if ( (*pWhichChannels)[i] < 0 || (*pWhichChannels)[i] >= m_NumEntries) {
sprintf(buf, "invalid channel id %d ", (*pWhichChannels)[i]);
m_LastError = buf;
return false; return false;
} }
needChan[(*pWhichChannels)[i]] = i; needChan[(*pWhichChannels)[i]] = i;
} }
} }
else { else {
int i; for (int i=0; i<m_NumEntries; i++) needChan.push_back(i);
for (i=0; i<m_NumEntries; i++) }
needChan.push_back(i);
vector<bool> gotData; // keep track of which channel has data
const vector<int>* pChnList;
vector<int> fullList;
gotData.resize(m_NumEntries, false);
if ( pWhichChannels ) {
pChnList = pWhichChannels;
} }
else {
fullList.resize(m_NumEntries);
for (int idx=0; idx < m_NumEntries; idx++) fullList[idx] = idx;
pChnList = &fullList;
}
// temporary storage; use a vector so we don't have to worry about // temporary storage; use a vector so we don't have to worry about
// memory leaks // memory leaks
vector<unsigned char> tempSpace; vector<unsigned char> tempSpace;
...@@ -1390,35 +1545,111 @@ CDaqLowLevelIo::GetFullData( ...@@ -1390,35 +1545,111 @@ CDaqLowLevelIo::GetFullData(
// Various other variables // Various other variables
// //
vector<CDaqBuffer> latestData; // latest sample of data vector<CDaqBuffer> latestData; // latest sample of data
vector<int> notNeededNow; // helps maintain when a sample is needed CDaqBuffer temBuf; // empty buffer to be used as template for latestData
vector<bool> latestFromThisFrm; // when true, latestData defined on this frame
// int startOfs;
map<int, int>::const_iterator mapIter;
int curFrame; int curFrame;
int numChan; // number of channels in current record int numChan; // number of channels in current record
int bytesSkipped; int bytesSkipped;
TIntVec empty;
if ( pFrmList) pFrmList->resize(userDataStorage.size(), empty);
latestData.resize(pChnList->size(), temBuf);
CDaqLowLevelIo::TReadErrorCode rcode; CDaqLowLevelIo::TReadErrorCode rcode;
//
// Adjust frame numbers so they reflect fbs frames
//
if ( frm1 < 0 ) frm1 = GetFirstFrame(); else frm1 += GetFirstFrame();
if ( frm2 < 0 ) frm2 = GetLastFrame(); else frm2 += GetLastFrame();
//
// If the first frame to read is not the first one in the file, and if
// there are differential channels, we must find the most recent value
// of all differential channels, otherwise we may need to output data nad
// have none
//
if ( frm1 == GetFirstFrame() ) {
for (size_t idx=0; idx < pChnList->size(); idx++) {
if ( m_Channels[(*pChnList)[idx]].GetCapRate() < 0 ) {
// here search backwards from frame frm1 until
// we find data for the specific channel. Store
// its values in latestData[idx]
}
}
}
// Seek to the first frame we need
rcode = ReadFrameHeader(frm1, curFrame, numChan, bytesSkipped); rcode = ReadFrameHeader(frm1, curFrame, numChan, bytesSkipped);
if ( rcode != eDAQ_READ_OK ) { if ( rcode != eDAQ_READ_OK ) {
sprintf(buf, "ReadFrameHeader returned %d", rcode); sprintf(buf, "First ReadFrameHeader() returned %d", rcode);
m_LastError = buf; m_LastError = buf;
return false; return false;
} }
// -> Read data into latestData, make sure we have read one of everything while ( curFrame < frm2 ) {
bool curFrameLost = FrameDropped(curFrame);
while ( curFrame <= frm2 ) { if ( curFrameLost ) {
size_t chan; if ( option & eFILL_MISSING ) {
// Re-use the most recent data
for (size_t idx=0; idx < pChnList->size(); idx++) {
CDaqChannelInfo& chInf = m_Channels[(*pChnList)[idx]];
int size = chInf.GetRecSize();
userDataStorage[idx].Append(latestData[idx].GetDataPtr(), size,
chInf.GetItemCount());
if ( pFrmList ) (*pFrmList)[idx].push_back(curFrame);
}
}
}
else {
if ( numChan > 0 ) {
for (int ii=0; ii < m_NumEntries; ii++) gotData[ii] = false;
for (chan = 0; chan < m_Channels.size(); chan++) { ReadDataForOneFrame(numChan, needChan, latestData, pTempSpace, gotData);
ReadDataForOneFrame(numChan, needChan, latestData, pTempSpace); for (size_t idx=0; idx < pChnList->size(); idx++) {
CDaqChannelInfo& chInf = m_Channels[(*pChnList)[idx]];
int size = chInf.GetRecSize();
bool diffChan = chInf.GetCapRate() < 0;
const void* pSrc = latestData[idx].GetDataPtr();
if ( diffChan && (option & eEXPAND_DIFFERENTIAL) ) {
userDataStorage[idx].Append(pSrc, size, chInf.GetItemCount());
if ( pFrmList) (*pFrmList)[idx].push_back(curFrame);
}
else if ( !diffChan && gotData[(*pChnList)[idx]] ) {
userDataStorage[idx].Append(pSrc, size, chInf.GetItemCount());
if ( pFrmList) (*pFrmList)[idx].push_back(curFrame);
} }
} }
}
else { // no data for that frame
if ( option & eEXPAND_DIFFERENTIAL ) {
// when expanding differential data, we output samples for each frame
for (size_t idx=0; idx < pChnList->size(); idx++) {
int chId = (*pChnList)[idx];
if ( m_Channels[chId].GetCapRate() < 0 ) {
int size = m_Channels[chId].GetRecSize();
const void* pSrc = latestData[idx].GetDataPtr();
userDataStorage[idx].Append(pSrc, size, m_Channels[chId].GetItemCount());
if ( pFrmList ) (*pFrmList) [idx].push_back(curFrame);
}
}
}
else {
// Do nothing
}
}
}
rcode = ReadFrameHeader(-1, curFrame, numChan, bytesSkipped);
if ( rcode != eDAQ_READ_OK && rcode != eDAQ_READ_EOF) {
sprintf(buf, "ReadFrameHeader returned %d (curFrame=%d, last=%d)", rcode, curFrame, frm2);
m_LastError = buf;
return false; return false;
}
}
return true;
} }
...@@ -1454,7 +1685,8 @@ CDaqLowLevelIo::ReadDataForOneFrame( ...@@ -1454,7 +1685,8 @@ CDaqLowLevelIo::ReadDataForOneFrame(
int numEntriesInThisRecord, int numEntriesInThisRecord,
vector<int> needChannel, vector<int> needChannel,
TDataVec& storage, TDataVec& storage,
void* pTempSpace void* pTempSpace,
vector<bool>& gotData
) )
{ {
int idx; int idx;
...@@ -1464,7 +1696,7 @@ CDaqLowLevelIo::ReadDataForOneFrame( ...@@ -1464,7 +1696,7 @@ CDaqLowLevelIo::ReadDataForOneFrame(
int chId; int chId;
if ( fread(&chId, sizeof(int), 1, m_pFile) != 1 ) return eDAQ_READ_ERROR; if ( fread(&chId, sizeof(int), 1, m_pFile) != 1 ) return eDAQ_READ_ERROR;
if ( chId >= m_NumEntries ) { if ( chId >= m_NumEntries || chId < 0 ) {
sprintf(buf, "Encountered invalid channel %d in data area", chId); sprintf(buf, "Encountered invalid channel %d in data area", chId);
m_LastError = buf; m_LastError = buf;
return eDAQ_READ_BAD_DATA; return eDAQ_READ_BAD_DATA;
...@@ -1475,7 +1707,6 @@ CDaqLowLevelIo::ReadDataForOneFrame( ...@@ -1475,7 +1707,6 @@ CDaqLowLevelIo::ReadDataForOneFrame(
if ( needChannel[chId] != -1 ) { // it is -1 when we don't need it if ( needChannel[chId] != -1 ) { // it is -1 when we don't need it
CDaqBuffer& daqBuf = storage[needChannel[chId]]; CDaqBuffer& daqBuf = storage[needChannel[chId]];
daqBuf.AllocSpace(0); // clear contents
if ( size > cMaxDaqRec ) { if ( size > cMaxDaqRec ) {
sprintf(buf, "Daq record size too big, increase \"cMaxDaqRec\""); sprintf(buf, "Daq record size too big, increase \"cMaxDaqRec\"");
m_LastError = buf; m_LastError = buf;
...@@ -1488,7 +1719,8 @@ CDaqLowLevelIo::ReadDataForOneFrame( ...@@ -1488,7 +1719,8 @@ CDaqLowLevelIo::ReadDataForOneFrame(
m_LastError = buf; m_LastError = buf;
return eDAQ_READ_ERROR; return eDAQ_READ_ERROR;
} }
daqBuf.Append(pTempSpace, size, ch.GetItemCount()); daqBuf.Replace(pTempSpace, size, ch.GetItemCount());
gotData[chId] = true;
} }
else { else {
// skip the data // skip the data
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment