DeviceLogSorted.cpp
Go to the documentation of this file.
1 /*
2 MIT LICENSE
3 
4 Copyright (c) 2014-2020 Inertial Sense, Inc. - http://inertialsense.com
5 
6 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
7 
8 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9 
10 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11 */
12 
13 #include <ctime>
14 #include <string>
15 #include <sstream>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <iomanip>
19 #include <iostream>
20 #include <fstream>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stddef.h>
24 #include <limits.h>
25 
26 #include "DeviceLogSorted.h"
27 #include "ISLogger.h"
28 #include "ISLogFileFactory.h"
29 
30 
32 {
33  for (uint32_t i = 0; i < DID_COUNT; i++)
34  {
35  m_chunks[i] = NULLPTR;
36  }
37 }
38 
39 
40 void cDeviceLogSorted::InitDeviceForWriting(int pHandle, std::string timestamp, std::string directory, uint64_t maxDiskSpace, uint32_t maxFileSize)
41 {
42  for (uint32_t i = 0; i < DID_COUNT; i++)
43  {
44  if (m_chunks[i])
45  {
46  delete m_chunks[i];
47  m_chunks[i] = NULLPTR;
48  }
49  }
50  m_dataSerNum = 0;
51  m_lastSerNum = 0xFFFFFFFF;
52  cDeviceLog::InitDeviceForWriting(pHandle, timestamp, directory, maxDiskSpace, maxFileSize);
53 }
54 
55 
57 {
58  for (uint32_t i = 0; i < DID_COUNT; i++)
59  {
60  if (m_chunks[i])
61  {
62  delete m_chunks[i];
63  m_chunks[i] = NULLPTR;
64  }
65  }
66  m_dataSerNum = 0;
67  m_lastSerNum = 0xFFFFFFFF;
69 }
70 
71 
73 {
75 
76  // Write to file and clear any non-empty chunks to file
77  for (uint32_t id = 0; id < DID_COUNT; id++)
78  {
80 
81  if (chunk != NULLPTR && chunk->GetDataSize() != 0)
82  {
83  // Create new file if needed
84  if (m_pFile == NULLPTR && !OpenNewSaveFile())
85  {
86  return false;
87  }
88 
89  // Write to file and clear chunk
90  if (chunk->WriteToFile(m_pFile, 1) <= 0)
91  {
92  return false;
93  }
94  }
95  }
96 
97  // Close existing file
99 
100  return true;
101 }
102 
103 
104 bool cDeviceLogSorted::SaveData(p_data_hdr_t* dataHdr, const uint8_t* dataBuf)
105 {
106  cDeviceLog::SaveData(dataHdr, dataBuf);
107 
108  uint32_t id = dataHdr->id;
109 
110  if (id >= DID_COUNT)
111  {
112  return false;
113  }
114 
115  if (m_chunks[id] == NULLPTR)
116  {
117  m_chunks[id] = new cSortedDataChunk();
118  // First time saving to this chunk
119  m_chunks[id]->m_subHdr.dHdr = *dataHdr;
122  }
123  cSortedDataChunk* currentChunk = m_chunks[id];
124 
125  // Add serial number if available
126  if (id == DID_DEV_INFO)
127  {
128  if (!copyDataPToStructP2(&m_devInfo, dataHdr, dataBuf, sizeof(dev_info_t)))
129  {
130  int start = dataHdr->offset;
131  int end = dataHdr->offset + dataHdr->size;
132  int snOffset = offsetof(dev_info_t, serialNumber);
133 
134  // Did we get the serial number portion of devInfo?
135  if (start <= snOffset && (int)(snOffset + sizeof(uint32_t)) <= end)
136  {
137  currentChunk->m_hdr.devSerialNum = m_devInfo.serialNumber;
138  }
139  }
140  }
141 
142  // depending on devices and sources, some logs may have different size for the same id
143  // if the size changes, flush the chunk and start a new one with the new size
144  uint32_t dataBytes;
145  if (currentChunk->m_subHdr.dHdr.size != dataHdr->size || currentChunk->m_subHdr.dHdr.offset != dataHdr->offset)
146  {
147  // force a flush of the chunk and start a new chunk with the new size
148  dataBytes = UINT_MAX;
149  }
150  else
151  {
152  dataBytes = sizeof(int32_t) + dataHdr->size;
153  }
154  if (dataBytes > currentChunk->GetBuffFree())
155  {
156  // Create new file if needed
157  if (m_pFile == NULLPTR && !OpenNewSaveFile())
158  {
159  return false;
160  }
161 
162  // Byte size
163  int nBytes = currentChunk->GetDataSize();
164 
165  if (nBytes != 0)
166  {
167  // Write to file and clear chunk
168  if ((nBytes = currentChunk->WriteToFile(m_pFile, 1)) <= 0)
169  {
170  return false;
171  }
172  }
173 
174  m_fileSize += nBytes;
175  m_logSize += nBytes;
176 
177  // File is large enough to be closed
178  if (m_fileSize >= m_maxFileSize)
179  {
180  // Write and clear remaining chunks to file and close file
181  if (!CloseAllFiles())
182  {
183  return false;
184  }
185  }
186  }
187 
188  // reset data header if it changed
189  if (dataBytes == UINT_MAX)
190  {
191  currentChunk->m_subHdr.dHdr = *dataHdr;
192  }
193 
194  // Add data header and data buffer to chunk
195  if (!currentChunk->PushBack((unsigned char*)&(m_dataSerNum), sizeof(int32_t), (unsigned char*)dataBuf, dataHdr->size))
196  {
197  return false;
198  }
199  currentChunk->m_subHdr.dCount++;
200  m_dataSerNum++;
201 
202  return true;
203 }
204 
205 
206 // Re-serialize data to original order
207 // Consider using a queue where data from chunks are added on one end and the serial order # is checked on the other end.
208 // This function needs to scan across all chunk queues and find the next lowest data to pop off.
209 
210 // Read serialized data
212 {
213  p_data_t* data;
214 
215  while (1)
216  {
217  data = SerializeDataFromChunks();
218 
219  if (data)
220  { // Found data
221  cDeviceLog::OnReadData(data); // Record statistics
222 
223  return data;
224  }
225 
226  // No more data. Clear existing chunk array
227  for (uint32_t id = 0; id < DID_COUNT; id++)
228  {
229  if (m_chunks[id] != NULLPTR)
230  {
231  delete m_chunks[id];
232  m_chunks[id] = NULLPTR;
233  }
234  }
235 
236  while (!ReadAllChunksFromFile())
237  {
238  if (!OpenNextReadFile())
239  {
240  // No more files or data
241  return NULL;
242  }
243  }
244  }
245 }
246 
247 
249 {
250 
251 tryAgain:
252 
253  uint32_t foundId = UINT_MAX;
254  uint32_t minSerialNum = UINT_MAX;
256  p_cnk_data_t* cnkData;
257 
258  // while there is data in any chunk, find the chunk with the next id
259  for (uint32_t id = 0; id < DID_COUNT; id++)
260  {
261  chunk = m_chunks[id];
262  if (chunk == NULLPTR || chunk->GetDataSize() == 0)
263  {
264  continue;
265  }
266  cnkData = (p_cnk_data_t*)chunk->GetDataPtr();
267  if (cnkData == NULLPTR)
268  {
269  continue;
270  }
271  if (cnkData->dataSerNum < minSerialNum)
272  {
273  foundId = id;
274  minSerialNum = cnkData->dataSerNum;
275  }
276  }
277 
278  if (foundId == UINT_MAX)
279  {
280  // No more data left
281  return NULL;
282  }
283 
284  chunk = m_chunks[foundId];
285  cnkData = (p_cnk_data_t*)chunk->GetDataPtr();
286 
287 #if 0 // Error check for gap data serial number. Verify we didn't drop any data.
288 
289  if (m_lastSerNum == UINT_MAX)
290  {
292  }
293  if (m_dataSerNum - m_lastSerNum > 1)
294  {
295  cout << endl << "Gap in data: " << foundId << "\t" << m_dataSerNum;
296  }
298 
299 #endif
300 
301  // Increment data serial number to one larger than current
302  m_dataSerNum = cnkData->dataSerNum + 1;
303 
304 
305  if (chunk->m_subHdr.dHdr.size <= MAX_DATASET_SIZE)
306  {
307  // Data fits in temp buf
308 
309  // Copy data header
310  m_data.hdr = chunk->m_subHdr.dHdr;
311 
312  // Copy data buffer, ensure not to overrun chunk memory in case of corrupt data
313  memcpy(m_data.buf, cnkData->buf, _MIN(chunk->GetDataSize(), m_data.hdr.size));
314 
315  // Size = serial number plus data size
316  int pSize = chunk->m_subHdr.dHdr.size + sizeof(uint32_t);
317 
318  chunk->PopFront(pSize);
319  return &m_data;
320  }
321  else
322  {
323  perror("Data is larger than max data set size");
324  }
325 
326  goto tryAgain;
327 }
328 
329 // This function reads all chunks from a file and appends them to an existing chuck list
331 {
332  unsigned int id;
333 
334  // Reset data serial number and file data size
335  m_fileSize = 0;
336 
337  // Read chunk and append it to existing chunks of same type
339  {
341 
342  // Error check ID
343  if (id >= DID_COUNT || id == DID_NULL)
344  {
345  continue;
346  }
347 
348  if (m_chunks[id] == NULLPTR)
349  {
350  m_chunks[id] = new cSortedDataChunk();
351  }
352 
354 
355  if (chunk->GetDataSize() == 0)
356  {
357  // Empty source chunk, copy Header
358  chunk->m_subHdr = m_readChunk.m_subHdr;
359 
360  // Find lowest serial number (used for sorting data)
363  }
364 
365  // add data count
367 
368  // Resize chunk if necessary
369 // if (m_readChunk.GetDataSize() > chunk->GetBuffFree())
370 // {
371 // chunk->Resize(chunk->GetDataSize() + m_readChunk.GetDataSize());
372 // }
373 
374  // Append data
376  }
377 
378  return m_fileSize != 0;
379 }
380 
381 
383 {
384  if (m_pFile == NULLPTR || chunk == NULLPTR)
385  {
386  return false;
387  }
388 
389  // Read chunk from file
390  int nBytes = chunk->ReadFromFile(m_pFile);
391 
392  // Validate chunk: non-zero size and is sorted type
393  int hdrSize = sizeof(p_data_hdr_t);
394  if (nBytes < hdrSize || chunk->m_hdr.grpNum != 1)
395  {
396  return false;
397  }
398 
399  // Update stats
400  m_fileSize += nBytes;
401  m_logSize += nBytes;
402 
403  return true;
404 }
405 
406 
407 void cDeviceLogSorted::SetSerialNumber(uint32_t serialNumber)
408 {
409  m_devInfo.serialNumber = serialNumber;
410  if (m_chunks[DID_DEV_INFO] == NULLPTR)
411  {
413  }
414  m_chunks[DID_DEV_INFO]->m_hdr.devSerialNum = serialNumber;
415 }
416 
417 
418 
419 
420 
421 
422 
#define _MIN(a, b)
Definition: ISConstants.h:298
bool CloseAllFiles() OVERRIDE
p_data_t * SerializeDataFromChunks()
ROSCPP_DECL void start()
void OnReadData(p_data_t *data)
Definition: DeviceLog.cpp:267
virtual bool CloseAllFiles()
Definition: DeviceLog.cpp:77
uint64_t m_logSize
Definition: DeviceLog.h:78
uint32_t id
Definition: ISComm.h:375
cISLogFileBase * m_pFile
Definition: DeviceLog.h:71
uint32_t size
Definition: ISComm.h:378
not_this_one end(...)
cSortedDataChunk * m_chunks[DID_COUNT]
GeneratorWrapper< std::vector< T > > chunk(size_t size, GeneratorWrapper< T > &&generator)
Definition: catch.hpp:3900
uint32_t GetBuffFree()
Definition: DataChunk.h:83
int32_t WriteToFile(cISLogFileBase *pFile, int groupNumber=0)
Definition: DataChunk.cpp:124
#define DID_COUNT
Definition: data_sets.h:138
#define DID_DEV_INFO
Definition: data_sets.h:35
#define NULL
Definition: nm_bsp.h:52
uint32_t devSerialNum
Device serial number.
Definition: DataChunk.h:51
bool PushBack(uint8_t *d1, uint32_t d1Size, uint8_t *d2=NULL, uint32_t d2Size=0)
Definition: DataChunk.cpp:59
dev_info_t m_devInfo
Definition: DeviceLog.h:75
virtual bool SaveData(p_data_hdr_t *dataHdr, const uint8_t *dataBuf)
Definition: DeviceLog.cpp:106
void CloseISLogFile(cISLogFileBase *&logFile)
#define NULLPTR
Definition: ISConstants.h:426
uint32_t GetDataSize()
Definition: DataChunk.h:84
std::ostream & cout()
uint32_t m_maxFileSize
Definition: DeviceLog.h:81
bool SaveData(p_data_hdr_t *dataHdr, const uint8_t *dataBuf) OVERRIDE
cSortedDataChunk m_readChunk
int32_t ReadFromFile(cISLogFileBase *pFile)
Definition: DataChunk.cpp:167
bool OpenNextReadFile()
Definition: DeviceLog.cpp:198
virtual void InitDeviceForWriting(int pHandle, string timestamp, string directory, uint64_t maxDiskSpace, uint32_t maxFileSize)
Definition: DeviceLog.cpp:57
uint8_t buf[MAX_P_DATA_BODY_SIZE]
bool ReadChunkFromFile(cSortedDataChunk *chunk)
p_data_hdr_t hdr
Definition: ISComm.h:388
void InitDeviceForReading() OVERRIDE
bool OpenNewSaveFile()
Definition: DeviceLog.cpp:137
USBInterfaceDescriptor data
virtual void InitDeviceForReading()
Definition: DeviceLog.cpp:69
uint64_t m_fileSize
Definition: DeviceLog.h:77
uint32_t serialNumber
Definition: data_sets.h:442
uint32_t pHandle
Device port handle.
Definition: DataChunk.h:52
int m_pHandle
Definition: DeviceLog.h:76
p_data_t * ReadData() OVERRIDE
void SetSerialNumber(uint32_t serialNumber) OVERRIDE
uint8_t * GetDataPtr()
Definition: DataChunk.cpp:85
p_data_hdr_t dHdr
#define DID_NULL
Definition: data_sets.h:34
void InitDeviceForWriting(int pHandle, std::string timestamp, std::string directory, uint64_t maxDiskSpace, uint32_t maxFileSize) OVERRIDE
uint8_t buf[MAX_DATASET_SIZE]
Definition: ISComm.h:391
uint32_t offset
Definition: ISComm.h:381
uint32_t dataSerNum
#define MAX_DATASET_SIZE
Definition: ISComm.h:91
bool PopFront(uint32_t size)
Definition: DataChunk.cpp:91
sChunkHeader m_hdr
Definition: DataChunk.h:94
char copyDataPToStructP2(void *sptr, const p_data_hdr_t *dataHdr, const uint8_t *dataBuf, const unsigned int maxsize)
Definition: ISComm.c:989
sChunkSubHeader m_subHdr


inertial_sense_ros
Author(s):
autogenerated on Sat Sep 19 2020 03:19:04