Compute Graph Framework SDK Reference  5.10
dwSensorDrainerTemplate.hpp
Go to the documentation of this file.
1
2// This code contains NVIDIA Confidential Information and is disclosed
3// under the Mutual Non-Disclosure Agreement.
4//
5// Notice
6// ALL NVIDIA DESIGN SPECIFICATIONS AND CODE ("MATERIALS") ARE PROVIDED "AS IS" NVIDIA MAKES
7// NO REPRESENTATIONS, WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
8// THE MATERIALS, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES OF NONINFRINGEMENT,
9// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
10//
11// NVIDIA Corporation assumes no responsibility for the consequences of use of such
12// information or for any infringement of patents or other rights of third parties that may
13// result from its use. No license is granted by implication or otherwise under any patent
14// or patent rights of NVIDIA Corporation. No third party distribution is allowed unless
15// expressly authorized by NVIDIA. Details are subject to change without notice.
16// This code supersedes and replaces all information previously supplied.
17// NVIDIA Corporation products are not authorized for use as critical
18// components in life support devices or systems without express written approval of
19// NVIDIA Corporation.
20//
21// Copyright (c) 2020-2022 NVIDIA Corporation. All rights reserved.
22//
23// NVIDIA Corporation and its licensors retain all intellectual property and proprietary
24// rights in and to this software and related documentation and any modifications thereto.
25// Any use, reproduction, disclosure or distribution of this software and related
26// documentation without an express license agreement from NVIDIA Corporation is
27// strictly prohibited.
28//
30#ifndef DWFRAMEWORK_DWNODES_SENSORS_DWSENSORNODE_DWSENSORDRAINERTEMPLATE_HPP_
31#define DWFRAMEWORK_DWNODES_SENSORS_DWSENSORNODE_DWSENSORDRAINERTEMPLATE_HPP_
32
43#include <dw/core/base/Types.h>
44#include <dw/sensors/Sensors.h>
45#include <dw/sensors/canbus/CAN.h>
46#include <dw/sensors/radar/Radar.h>
47#include <dwcgf/Exception.hpp>
48#include <dwcgf/node/Node.hpp>
49#include <memory>
50#include <unistd.h>
51#if defined(DW_SDK_BUILD_EXPERIMENTAL) && defined(LINUX)
52#include <dwexperimental/sensors/lockstep/Lockstep.h>
53#include <dwexperimental/sensors/Sensors.h>
54#endif
55
56namespace dw
57{
58namespace framework
59{
60
62{
63 const char* nodeName;
64 dwTime_t blockingTimeout; // Blocking timeout must be > 1/f_sensor
65 dwTime_t nonBlockingTimeout; // Nonblocking timeout must be < 1/f_sensor
66 bool isVirtual; // true if this sensor reads from dataset
67 bool autoReset; // true to reset the sensor at the end of stream (for playback loop option)
68 bool drainStaleData; // true if drainer should read from sensor until DW SAL is empty
69 bool waitForNewData; // true if drainer should block until new data is available
71 const char* frameReadMask;
72};
73
74template <typename ProcessedDataType, typename ReadProcessedDataFunc, typename DataSourceType>
76{
77public:
78 static constexpr char LOG_TAG[] = "dwBaseDrainerTemplate";
79
80 // WAR: This is a guard for drain out sensor data, avoid huge sensor data make too long loop time, eg: drain out can msg > 100 ms, current find 50 is good enough
81 static constexpr int32_t DRAIN_SENSOR_DATA_COUNT_MAX = 50;
82 using OnDataDropped = dw::core::Function<void(dwTime_t const)>;
83
84 explicit dwBaseDrainerTemplate(dwSensorDrainerParams params, std::unique_ptr<ReadProcessedDataFunc> readProcessedDataFunc, DataSourceType dataSource)
85 : m_dataSource(dataSource)
86 , m_name(params.nodeName)
87 , m_blockingTimeout(params.blockingTimeout)
88 , m_nonBlockingTimeout(params.nonBlockingTimeout)
89 , m_isVirtual(params.isVirtual)
90 , m_dropStaleData(params.drainStaleData)
91 , m_waitForNewData(params.waitForNewData)
92 , m_readProcessedDataFunc(std::move(readProcessedDataFunc))
93 , m_frameReadMask(params.frameReadMask)
94 , m_isLockstep(params.isLockstep)
95 {
96 if (m_frameReadMask.size() > 0)
97 {
98 m_frameSkipEnabled = true;
99 }
100 }
101
102 void setOnDataDropped(OnDataDropped onDataDropped)
103 {
104 m_onDataDropped = onDataDropped;
105 }
106
107 virtual dwStatus getNextTimestamp(dwTime_t& timestamp, dwTime_t timeout)
108 {
109 // If dwSensor_getNextTimestamp API not available, get timestamp by looking ahead in dataset
110 if (!m_nextDataReady)
111 {
113 {
114 dwStatus status = m_readProcessedDataFunc->readNextData(timeout, m_dataSource);
115 if (status != DW_SUCCESS)
116 {
117 m_nextDataReady = false;
118 return status;
119 }
120 m_framesRead++;
121 m_nextDataReady = true;
122 }
123 else
124 {
125 auto ret = readNextWithFrameMask(timeout);
126 if (ret != DW_SUCCESS)
127 {
128 return ret;
129 }
130 }
131 }
132
133 return m_readProcessedDataFunc->getNextDataTimestamp(timestamp);
134 }
135
136 virtual dwStatus getNextData(ProcessedDataType* outFrame, dwTime_t timeout)
137 {
138 if (!m_nextDataReady)
139 {
141 {
142 // Do the read here if look ahead did not happen
143 dwStatus status = m_readProcessedDataFunc->readNextData(timeout, m_dataSource);
144 if (status != DW_SUCCESS)
145 {
146 DW_LOGE << "getNextData: readNextData error!" << Logger::State::endl;
147 m_nextDataReady = false;
148 return status;
149 }
150 m_framesRead++;
151 m_nextDataReady = true;
152 }
153 else
154 {
155 auto ret = readNextWithFrameMask(timeout);
156 if (ret != DW_SUCCESS)
157 {
158 DW_LOGE << "getNextData: readNextData error!" << Logger::State::endl;
159 return ret;
160 }
161 }
162 }
163 return m_readProcessedDataFunc->getNextData(outFrame, m_dataSource);
164 }
165
166 dwStatus readNextWithFrameMask(dwTime_t timeout)
167 {
168 // Keep reading until a valid frame is found (1 in the frame mask)
169 do
170 {
171 dwStatus status = m_readProcessedDataFunc->readNextData(timeout, m_dataSource);
172 if (status != DW_SUCCESS)
173 {
174 m_nextDataReady = false;
175 return status;
176 }
177 m_framesRead++;
178 m_nextDataReady = true;
179 } while (m_frameReadMask[(m_framesRead - 1) % m_frameReadMask.size()] == '0');
180
181 return DW_SUCCESS;
182 }
183
184 virtual dwStatus tryRead(ProcessedDataType* outFrame,
185 dwTime_t& latestTimestamp,
186 dwTime_t timeout,
187 bool isDroppingData = false)
188 {
189 dwStatus status = DW_FAILURE;
190 dwTime_t nextTime{};
192 {
194 {
195 return DW_TIME_OUT;
196 }
197 nextTime = m_stashedNextTime;
199 }
200 else
201 {
202 dwStatus status = getNextTimestamp(nextTime, timeout);
203 if (status != DW_SUCCESS)
204 {
205 return status;
206 }
207 }
208
209 // Check if next data is ready. If not, mimic Live Sensor DW SAL buffer empty with a DW_TIME_OUT
210 if (m_isVirtual && !isVirtualDataReady(nextTime, timeout))
211 {
212 m_stashedNextTime = nextTime;
213 return DW_TIME_OUT;
214 }
215
216 status = getNextData(outFrame, timeout);
217 if (status != DW_SUCCESS)
218 {
219 DW_LOGE << "tryRead: getNextData error!" << Logger::State::endl;
220 return status;
221 }
222
223 if (isDroppingData)
224 {
225 DW_LOGW << m_name << " Dropping data" << Logger::State::endl;
226 if (m_onDataDropped)
227 {
228 m_onDataDropped(latestTimestamp);
229 }
230 }
231
232 latestTimestamp = nextTime;
233 m_nextDataReady = false;
234 m_outputAvailable = true;
235
236 return status;
237 }
238
239 virtual dwStatus reset()
240 {
242 m_nextDataReady = false;
244 return DW_SUCCESS;
245 }
246
247 virtual dwTime_t getReadTimeout() const
248 {
250 }
251
252 virtual void setVirtualSyncTime(dwTime_t virtualSyncTime)
253 {
254 m_virtualSyncTime = virtualSyncTime;
255 }
256
258 {
260 }
261
262 // This function is original designed for mimicing real time live sensors for non-determinisitc mode.
263 // But now removed the sleep before return as deterministic mode is the only supported dataset mode.
264 // Returns true if the next sensor data should be available
265 virtual bool isVirtualDataReady(dwTime_t dataTime, dwTime_t timeout)
266 {
268 {
269 if (dataTime <= m_virtualSyncTime)
270 {
271 return true;
272 }
273 return false;
274 }
275
276 dwTime_t timeToNextData = dataTime - m_virtualSyncTime;
277
278 // For dataset, the first frame's m_virtualSyncTime is 0. Return true directly and set m_virtualSyncTime = -1
279 // so that the second round tryRead will return DW_TIME_OUT and use the first frame.
280 if (m_virtualSyncTime == 0)
281 {
282 // WAR, fix this
284 return true;
285 }
286 if (timeToNextData >= timeout)
287 {
288 // Next sensor data is far in the future. Timeout specified not sufficient to reach next sensor data
289 // Technically, we should still usleep(timeout) to mimic live sensor, but can skip this for perf
290 // TODO(Oven): WAR to guarantee some data must be read when timeout is m_blockingTimeout,
291 // otherwise we may send out uninitialized sensor data to downstreams
292 if (timeout == m_blockingTimeout)
293 {
294 DW_LOGD << "isVirtualDataReady: timeToNextData is larger than m_blockingTimeout, must read some data. "
295 << "timeToNextData: " << timeToNextData << ", dataTime: " << dataTime << Logger::State::endl;
296 }
297 else
298 {
299 return false;
300 }
301 }
302 if (timeToNextData <= 0)
303 {
304 // Next sensor data is in the past. Should be available.
305 return true;
306 }
307 return true;
308 }
309
310 // Utility to read Sensor data from DW SAL in a consistent way across live/virtual sensor
311 // May block on new sensor data, or drop stale data. See dwSensorDrainerParams
312 // Retuns DW_SUCCESS if processedOutput and timestampOutput is valid
313 // nextTimestampOutput will always be valid for virtual case
314 //
315 // [out] processedOutput the latest valid sensor frame
316 // [out] timestampOutput timestamp associated with the latest valid sensor frame
317 // [out] nextTimestampOutput timestamp associated with the next sensor frame. Only available in virtual case
318 // [in] virtualSyncTime current timestamp to decide whether virtual data is ready to be sent
319 // [in] sensor handle to sensor
320 virtual dwStatus drainProcessedData(ProcessedDataType* processedOutput,
321 dwTime_t& timestampOutput,
322 dwTime_t& nextTimestampOutput,
323 dwTime_t virtualSyncTime)
324 {
325 m_virtualSyncTime = virtualSyncTime;
326
327 dwStatus status = DW_SUCCESS;
328 m_outputAvailable = false;
329
330 // Blocking read guarantees some data is read, and slows processing down to data rate
331 dwTime_t readTimeout = getReadTimeout();
332 int32_t drainCount = 0;
333
334 // For determinisitic mode, camera/radar/imugps will always return available frame at the first loop with longer readTimeout.
335 // They will return DW_TIME_OUT with shorter m_nonBlockingTimeout to guarentee deterministic for each frame at second loop.
336 // Note: This do-while has different behavior when reach EndOfStream for flag m_dropStaleData. Assume dataset has 0~100 frames.
337 // If true, the first loop will read frame 100 successfully. Then enter the second loop and hit EndOfStream. It will reset
338 // the sensor and tryRead again. Which means it will return frame 0 and drop frame 100. Later, getNextTimestamp will return
339 // frame 1's timestamp. So the final result is: processedOutput = frame 0, nextTimestampOutput = frame 1' timestamp
340 // If false, the first loop will read frame 100 successfully and exit do-while loop directly. Later, nextTimestampOutput is
341 // reset to 0 and failed getNextTimestamp. So the final result is: processedOutput = frame 100, nextTimestampOutput = 0
342 do
343 {
344 status = readProcessedData(processedOutput, timestampOutput, readTimeout, drainCount > 0);
345 // Non-blocking read and drop stale data to drain the DW SAL buffer, send newest available data
346 readTimeout = m_nonBlockingTimeout;
347
348#if defined(DW_SDK_BUILD_EXPERIMENTAL) && defined(LINUX)
349 isLockstepDataAvailable(status, readTimeout);
350#endif
351 } while (status == DW_SUCCESS && m_dropStaleData && (drainCount++ < DRAIN_SENSOR_DATA_COUNT_MAX));
352
354 {
355 DW_LOGE << m_name << " blockingTimeout not sufficient to successfully waitForNewData. No data available!" << Logger::State::endl;
356 }
357 else if (status == DW_TIME_OUT && m_outputAvailable)
358 {
359 // DW_TIME_OUT indicates that DW SAL has been successfully drained
360 status = DW_SUCCESS;
361 }
362
363 populateNextTimestamp(nextTimestampOutput);
364 return status;
365 }
366
367 virtual dwStatus readProcessedData(ProcessedDataType* outFrame, dwTime_t& latestTimestamp, dwTime_t timeout, bool isDroppingData = false) = 0;
368
369 virtual void isLockstepDataAvailable(dwStatus& status, dwTime_t& readTimeout) {}
370
371 void populateNextTimestamp(dwTime_t& nextTimestampOutput)
372 {
374 {
375 // In virtual case, send out the timestamp of next sensor data
376 nextTimestampOutput = 0;
377 const dwStatus nextTimeStatus = getNextTimestamp(nextTimestampOutput, m_blockingTimeout);
378 if (nextTimeStatus != DW_SUCCESS)
379 {
380 DW_LOGD << m_name << " Failed to get next timestamp: " << dwGetStatusName(nextTimeStatus);
381 }
382 }
383 }
384
385protected:
386 DataSourceType m_dataSource;
387
388 std::unique_ptr<ReadProcessedDataFunc> m_readProcessedDataFunc;
389
390 dwTime_t m_blockingTimeout = 60000;
391 dwTime_t m_nonBlockingTimeout = 100;
392 dwTime_t m_virtualSyncTime = 0;
393 dwTime_t m_stashedNextTime = -1;
395 bool m_outputAvailable = false;
396 bool m_nextDataReady = false;
397 bool m_isVirtual = false;
398 bool m_dropStaleData = false;
399 bool m_waitForNewData = false;
400 bool m_frameSkipEnabled = false;
401 uint32_t m_framesRead = 0;
402 FixedString<32> m_frameReadMask;
403 bool m_isLockstep = false;
405
407
408 static constexpr dwTime_t REPLAY_SENSOR_READ_TIMEOUT = 10000000;
409};
410
411template <typename ProcessedDataType, typename ReadProcessedDataFunc>
412class dwSensorDrainerTemplate : public dwBaseDrainerTemplate<ProcessedDataType, ReadProcessedDataFunc, dwSensorHandle_t>
413{
414public:
415 static constexpr char LOG_TAG[] = "dwSensorDrainerTemplate";
417
418 explicit dwSensorDrainerTemplate(dwSensorDrainerParams params, std::unique_ptr<ReadProcessedDataFunc> readProcessedDataFunc, dwSensorHandle_t hsensor)
419 : dwBaseDrainerTemplate<ProcessedDataType, ReadProcessedDataFunc, dwSensorHandle_t>(params, std::move(readProcessedDataFunc), hsensor), m_autoReset(params.autoReset), m_isLockstep(params.isLockstep)
420 {
421 }
422
423 virtual ~dwSensorDrainerTemplate() = default;
424
425 dwStatus getNextTimestamp(dwTime_t& timestamp,
426 dwTime_t timeout) override
427 {
428#if defined(DW_SDK_BUILD_EXPERIMENTAL) && defined(LINUX)
430 {
431 dwStatus nextStatus = dwSensor_getNextTimestamp(&timestamp, Base::m_dataSource);
432 if (nextStatus == DW_SUCCESS || nextStatus == DW_END_OF_STREAM)
433 {
434 return nextStatus;
435 }
436 }
437#endif
438
439 return Base::getNextTimestamp(timestamp, timeout);
440 }
441
442 virtual dwStatus reset() override
443 {
444 dwStatus res = Base::reset();
445 if (res != DW_SUCCESS)
446 {
447 return res;
448 }
449 return dwSensor_reset(Base::m_dataSource);
450 }
451
452 // Reads a piece of sensor data from sensor
453 // In virtual sensor case, uses m_virtualSyncTime and timeout to determine
454 // whether next piece of sensor data should be available
455 //
456 // [out] outFrame output sensor frame
457 // [in/out] latestTimestamp timestamp associated with the sensor frame
458 // [in] timeout sensor reading timeout in microseconds
459 // [in] isDroppingData indicates if data is being dropped
460 dwStatus readProcessedData(ProcessedDataType* outFrame,
461 dwTime_t& latestTimestamp,
462 dwTime_t timeout,
463 bool isDroppingData = false) override
464 {
465 dwStatus status = Base::tryRead(outFrame, latestTimestamp, timeout, isDroppingData);
466 if (status == DW_END_OF_STREAM && m_autoReset)
467 {
468 // Reset the sensor and try to read again, but propagate the DW_END_OF_STREAM
469 // Use blocking read after reset since camera prefetch may not be ready
470 reset();
471 timeout = Base::m_blockingTimeout;
472 Base::tryRead(outFrame, latestTimestamp, timeout);
473 }
474 return status;
475 }
476
477 // Utility to drop sensor frames according to the events to be replayed
478 // until the next non-drop event is read or there are no more replay events
479 // @param [output] processedOutput the latest frame read from the sensor
480 // @param [output] dataEvent the next non-drop event to be replayed.
481 // @param [input] sensor the sensor to replay frames from
482 // @param [input] readCb the callback to read replay events
483 dwStatus replayDroppedFrames(ProcessedDataType* processedOutput,
484 SensorNode::DataEvent& dataEvent,
486 {
487 // Process any number of drop events.
488 bool isDropEvent;
489 do
490 {
491 // Read next data event
492 if (!readCb(dataEvent)) // no more events to be replayed
493 {
494 DW_LOGW << "replayDroppedFrames: Trace cannot be read." << Logger::State::endl;
495 return DW_END_OF_STREAM;
496 }
497
498 // Drop the sensor frame (if applicable)
499 isDropEvent = dataEvent.dataEventType == SensorNode::DataEventType::DROP;
500 if (isDropEvent)
501 {
502 dwTime_t timestampOutput{};
503 dwStatus status = readProcessedData(processedOutput, timestampOutput, Base::REPLAY_SENSOR_READ_TIMEOUT);
504 if (status == DW_END_OF_STREAM)
505 {
506 return status;
507 }
508 else if (status == DW_SUCCESS)
509 {
510 // For now we assume that the timestamps read from the sensor need to match the trace exactly
511 // so if there isn't a match then there is no valid way to continue, throw an exception.
512 if (timestampOutput != dataEvent.timestamp)
513 {
514 DW_LOGE << "replayDroppedFrames: Data/trace mismatch: current: " << timestampOutput << " recorded: " << dataEvent.timestamp << Logger::State::endl;
515 throw Exception(DW_FAILURE, "dwSensorDrainerTemplate: replayDroppedFrames: data/trace mismatch.");
516 }
517 }
518 else
519 {
520 DW_LOGE << "replayDroppedFrames: Cannot read next data." << Logger::State::endl;
521 throw Exception(DW_FAILURE, "dwSensorDrainerTemplate: replayDroppedFrames: cannot read next data.");
522 }
523 }
524 } while (isDropEvent);
525
526 return DW_SUCCESS;
527 }
528
529 // Replay the next event for the sensor node-run.
530 // @param [output] processedOutput the frame replayed from the sensor
531 // @param [output] timestampOutput the timestamp of the frame replayed from the sensor
532 // @param [input] sensor the sensor to replay frames from
533 // @param [input] readCb the callback to read replay events
534 virtual dwStatus replayProcessedData(ProcessedDataType* processedOutput,
535 dwTime_t& timestampOutput,
537 {
538 // First drop frames according to the replay event
539 // also, retrieve the first non-drop event.
541 dwStatus status = replayDroppedFrames(processedOutput, de, readCb);
542
543 // When end of stream was reached, just read the next frame and ignore the replay event.
544 if (status == DW_END_OF_STREAM)
545 {
546 readProcessedData(processedOutput, timestampOutput, Base::REPLAY_SENSOR_READ_TIMEOUT);
547 return status;
548 }
549
550 // If some unexpected status was returned from the sensor just return the status as this is an error.
551 if (status != DW_SUCCESS)
552 {
553 return status;
554 }
555
556 // otherwise, if no data was produced for this event, then just return the status that was recorded
557 // (usually this is DW_NOT_AVAILABLE or DW_TIME_OUT)
558 if (de.dataEventType == SensorNode::DataEventType::NONE)
559 {
560 status = de.status;
561 }
562 // if data was produced, read the next data from the sensor and make sure it has the timetamp we expect.
563 else if (de.dataEventType == SensorNode::DataEventType::PRODUCE)
564 {
565 status = readProcessedData(processedOutput, timestampOutput, Base::REPLAY_SENSOR_READ_TIMEOUT);
566 if (status != DW_SUCCESS && status != DW_END_OF_STREAM)
567 {
568 DW_LOGE << "replayProcessedData: Cannot read next data." << Logger::State::endl;
569 throw Exception(DW_FAILURE, "dwSensorDrainerTemplate: replayProcessedData: cannot read next data.");
570 }
571 // For now we assume that the timestamps read from the sensor need to match the trace exactly
572 // so if there isn't a match then there is no valid way to continue, throw an exception.
573 if (timestampOutput != de.timestamp)
574 {
575 DW_LOGE << "replayProcessedData: Data/trace mismatch." << Logger::State::endl;
576 throw Exception(DW_FAILURE, "dwSensorDrainerTemplate: replayProcessedData: data/trace mismatch.");
577 }
578 }
579 else
580 {
581 DW_LOGE << "replayProcessedData: UnhandledEventType." << Logger::State::endl;
582 throw Exception(DW_FAILURE, "dwSensorDrainerTemplate: unhandled event type");
583 }
584
585 return status;
586 }
587
588#if defined(DW_SDK_BUILD_EXPERIMENTAL) && defined(LINUX)
589 void isLockstepDataAvailable(dwStatus& status, dwTime_t& readTimeout) override
590 {
592 {
593 bool isDataAvailable = false;
594 if (dwLockstep_isDataAvailable(&isDataAvailable, Base::m_dataSource) != DW_SUCCESS)
595 {
596 char8_t const* protocol;
597 dwSensor_getProtocol(&protocol, Base::m_dataSource);
598 throw Exception(DW_FAILURE, "dwSensorDrainerTemplate: can't get the data available flag from:", protocol, " sensor");
599 }
600
601 if (!isDataAvailable && status != DW_SUCCESS)
602 {
603 status = DW_TIME_OUT;
604 }
605 else
606 {
607 status = DW_SUCCESS;
608 readTimeout = Base::m_blockingTimeout;
609 }
610 }
611 }
612#endif
613
614protected:
615 bool m_autoReset = false;
616 bool m_isLockstep = false;
617};
618
619template <typename ProcessedDataType, typename ReadProcessedDataFunc, typename DataSourceType>
621
622template <typename ProcessedDataType, typename ReadProcessedDataFunc>
624} // namespace framework
625} // namespace dw
626
627#endif // DWFRAMEWORK_DWNODES_SENSORS_DWSENSORNODE_DWSENSORDRAINERTEMPLATE_HPP_
FixedString< MAX_NAME_LEN > Name_t
Definition: Node.hpp:68
ISensorNode::DataEventReadCallback DataEventReadCallback
Definition: Node.hpp:398
void populateNextTimestamp(dwTime_t &nextTimestampOutput)
virtual dwStatus tryRead(ProcessedDataType *outFrame, dwTime_t &latestTimestamp, dwTime_t timeout, bool isDroppingData=false)
static constexpr int32_t DRAIN_SENSOR_DATA_COUNT_MAX
void setOnDataDropped(OnDataDropped onDataDropped)
dw::core::Function< void(dwTime_t const)> OnDataDropped
virtual dwStatus getNextTimestamp(dwTime_t &timestamp, dwTime_t timeout)
virtual dwStatus getNextData(ProcessedDataType *outFrame, dwTime_t timeout)
virtual void setLockstepDeterministicMode(bool enable)
dwBaseDrainerTemplate(dwSensorDrainerParams params, std::unique_ptr< ReadProcessedDataFunc > readProcessedDataFunc, DataSourceType dataSource)
virtual dwStatus drainProcessedData(ProcessedDataType *processedOutput, dwTime_t &timestampOutput, dwTime_t &nextTimestampOutput, dwTime_t virtualSyncTime)
virtual void setVirtualSyncTime(dwTime_t virtualSyncTime)
virtual bool isVirtualDataReady(dwTime_t dataTime, dwTime_t timeout)
virtual void isLockstepDataAvailable(dwStatus &status, dwTime_t &readTimeout)
std::unique_ptr< ReadProcessedDataFunc > m_readProcessedDataFunc
virtual dwStatus readProcessedData(ProcessedDataType *outFrame, dwTime_t &latestTimestamp, dwTime_t timeout, bool isDroppingData=false)=0
static constexpr dwTime_t REPLAY_SENSOR_READ_TIMEOUT
dwStatus readNextWithFrameMask(dwTime_t timeout)
dwStatus readProcessedData(ProcessedDataType *outFrame, dwTime_t &latestTimestamp, dwTime_t timeout, bool isDroppingData=false) override
dwSensorDrainerTemplate(dwSensorDrainerParams params, std::unique_ptr< ReadProcessedDataFunc > readProcessedDataFunc, dwSensorHandle_t hsensor)
virtual dwStatus replayProcessedData(ProcessedDataType *processedOutput, dwTime_t &timestampOutput, SensorNode::DataEventReadCallback readCb)
dwStatus getNextTimestamp(dwTime_t &timestamp, dwTime_t timeout) override
dwStatus replayDroppedFrames(ProcessedDataType *processedOutput, SensorNode::DataEvent &dataEvent, SensorNode::DataEventReadCallback readCb)
Definition: Buffer.hpp:40