SickBufferMonitor.hh
Go to the documentation of this file.
1 
16 #ifndef SICK_BUFFER_MONITOR
17 #define SICK_BUFFER_MONITOR
18 
19 /* Dependencies */
20 #include <iostream>
21 #include <pthread.h>
22 #include <unistd.h>
23 #include "SickException.hh"
24 
25 /* Associate the namespace */
26 namespace SickToolbox {
27 
31  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
33 
34  public:
35 
37  SickBufferMonitor( SICK_MONITOR_CLASS * const monitor_instance ) throw( SickThreadException );
38 
40  void SetDataStream( const unsigned int sick_fd ) throw( SickThreadException );
41 
43  void StartMonitor( const unsigned int sick_fd ) throw( SickThreadException );
44 
46  bool GetNextMessageFromMonitor( SICK_MSG_CLASS &sick_message ) throw( SickThreadException );
47 
49  void StopMonitor( ) throw( SickThreadException );
50 
52  void AcquireDataStream( ) throw( SickThreadException );
53 
55  void GetNextMessageFromDataStream( SICK_MSG_CLASS &sick_message );
56 
58  void ReleaseDataStream( ) throw( SickThreadException );
59 
62 
63  protected:
64 
66  unsigned int _sick_fd;
67 
69  void _readBytes( uint8_t * const dest_buffer, const int num_bytes_to_read, const unsigned int timeout_value = 0 ) const throw ( SickTimeoutException, SickIOException );
70 
71  private:
72 
74  SICK_MONITOR_CLASS *_sick_monitor_instance;
75 
78 
80  pthread_t _monitor_thread_id;
81 
83  pthread_mutex_t _container_mutex;
84 
86  pthread_mutex_t _stream_mutex;
87 
89  SICK_MSG_CLASS _recv_msg_container;
90 
93 
95  void _releaseMessageContainer( ) throw( SickThreadException );
96 
98  static void * _bufferMonitorThread( void * thread_args );
99 
100  };
101 
106  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
107  SickBufferMonitor< SICK_MONITOR_CLASS, SICK_MSG_CLASS >::SickBufferMonitor( SICK_MONITOR_CLASS * const monitor_instance ) throw( SickThreadException ) :
108  _sick_monitor_instance(monitor_instance), _continue_grabbing(true), _monitor_thread_id(0) {
109 
110  /* Initialize the shared message buffer mutex */
111  if (pthread_mutex_init(&_container_mutex,NULL) != 0) {
112  throw SickThreadException("SickBufferMonitor::SickBufferMonitor: pthread_mutex_init() failed!");
113  }
114 
115  /* Initialize the shared data stream mutex */
116  if (pthread_mutex_init(&_stream_mutex,NULL) != 0) {
117  throw SickThreadException("SickBufferMonitor::SickBufferMonitor: pthread_mutex_init() failed!");
118  }
119 
120  }
121 
126  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
128 
129  try {
130 
131  /* Attempt to acquire the data stream */
133 
134  /* Assign the data stream fd */
135  _sick_fd = sick_fd;
136 
137  /* Attempt to release the data stream */
139 
140  }
141 
142  /* Handle thread exception */
143  catch(SickThreadException &sick_thread_exception) {
144  std::cerr << sick_thread_exception.what() << std::endl;
145  }
146 
147  /* A safety net */
148  catch(...) {
149  std::cerr << "SickBufferMonitor::SetDataStream: Unknown exception!" << std::endl;
150  throw;
151  }
152 
153  }
154 
159  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
161 
162  /* Assign the fd associated with the data stream */
163  _sick_fd = sick_fd;
164 
165  /* Start the buffer monitor */
167  throw SickThreadException("SickBufferMonitor::StartMonitor: pthread_create() failed!");
168  }
169 
170  /* Set the flag to continue grabbing data */
171  _continue_grabbing = true;
172 
173  }
174 
180  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
182 
183  bool acquired_message = false;
184 
185  try {
186 
187  /* Acquire a lock on the message buffer */
189 
190  /* Check whether the object is populated */
191  if (_recv_msg_container.IsPopulated()) {
192 
193  /* Copy the shared message */
194  sick_message = _recv_msg_container;
195  _recv_msg_container.Clear();
196 
197  /* Set the flag indicating success */
198  acquired_message = true;
199  }
200 
201  /* Release message container */
203 
204  }
205 
206  /* Handle a thread exception */
207  catch(SickThreadException &sick_thread_exception) {
208  std::cerr << sick_thread_exception.what() << std::endl;
209  throw;
210  }
211 
212  /* Handle an unknown exception */
213  catch(...) {
214  std::cerr << "SickBufferMonitor::CheckMessageContainer: Unknown exception!" << std::endl;
215  throw;
216  }
217 
218  /* Return the flag */
219  return acquired_message;
220  }
221 
226  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
228 
229  try {
230 
231  /* Return results from the thread */
232  void *monitor_result = NULL;
233 
234  /* Tell the thread to quit working */
236  _continue_grabbing = false;
238 
239  /* Wait for the buffer monitor to exit */
240  if (pthread_join(_monitor_thread_id,&monitor_result) != 0) {
241  throw SickThreadException("SickBufferMonitor::StopMonitor: pthread_join() failed!");
242  }
243 
244  }
245 
246  /* Handle thread exception */
247  catch(SickThreadException &sick_thread_exception) {
248  std::cerr << sick_thread_exception.what() << std::endl;
249  }
250 
251  /* A safety net */
252  catch(...) {
253  std::cerr << "SickBufferMonitor::StopMonitor: Unknown exception!" << std::endl;
254  throw;
255  }
256 
257  }
258 
262  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
264 
265  /* Attempt to lock the stream mutex */
266  if (pthread_mutex_lock(&_stream_mutex) != 0) {
267  throw SickThreadException("SickBufferMonitor::AcquireDataStream: pthread_mutex_lock() failed!");
268  }
269 
270  }
271 
275  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
277 
278  /* Attempt to lock the stream mutex */
279  if (pthread_mutex_unlock(&_stream_mutex) != 0) {
280  throw SickThreadException("SickBufferMonitor::ReleaseDataStream: pthread_mutex_unlock() failed!");
281  }
282 
283  }
284 
288  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
290 
291  /* Destroy the message container mutex */
292  if (pthread_mutex_destroy(&_container_mutex) != 0) {
293  throw SickThreadException("SickBufferMonitor::~SickBufferMonitor: pthread_mutex_destroy() failed!");
294  }
295 
296  /* Destroy the data stream container mutex */
297  if (pthread_mutex_destroy(&_stream_mutex) != 0) {
298  throw SickThreadException("SickBufferMonitor::~SickBufferMonitor: pthread_mutex_destroy() failed!");
299  }
300 
301  }
302 
306  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
308 
309  /* Lock the mutex */
310  if (pthread_mutex_lock(&_container_mutex) != 0) {
311  throw SickThreadException("SickBufferMonitor::_acquireMessageContainer: pthread_mutex_lock() failed!");
312  }
313 
314  }
315 
319  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
321 
322  /* Unlock the mutex */
323  if (pthread_mutex_unlock(&_container_mutex) != 0) {
324  throw SickThreadException("SickBufferMonitor::_releaseMessageContainer: pthread_mutex_unlock() failed!");
325  }
326 
327  }
328 
336  template< class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
337  void SickBufferMonitor< SICK_MONITOR_CLASS, SICK_MSG_CLASS >::_readBytes( uint8_t * const dest_buffer, const int num_bytes_to_read, const unsigned int timeout_value ) const
339 
340  /* Some helpful variables */
341  int num_bytes_read = 0;
342  int total_num_bytes_read = 0;
343  int num_active_files = 0;
344 
345  struct timeval timeout_val; // This structure will be used for setting our timeout values
346  fd_set file_desc_set; // File descriptor set for monitoring I/O
347 
348  /* Attempt to fetch the bytes */
349  while ( total_num_bytes_read < num_bytes_to_read ) {
350 
351  /* Initialize and set the file descriptor set for select */
352  FD_ZERO(&file_desc_set);
353  FD_SET(_sick_fd,&file_desc_set);
354 
355  /* Setup the timeout structure */
356  memset(&timeout_val,0,sizeof(timeout_val)); // Initialize the buffer
357  timeout_val.tv_usec = timeout_value; // Wait for specified time before throwing a timeout
358 
359  /* Wait for the OS to tell us that data is waiting! */
360  num_active_files = select(getdtablesize(),&file_desc_set,0,0,(timeout_value > 0) ? &timeout_val : 0);
361 
362  /* Figure out what to do based on the output of select */
363  if (num_active_files > 0) {
364 
365  /* A file is ready for reading!
366  *
367  * NOTE: The following conditional is just a sanity check. Since
368  * the file descriptor set only contains the sick device fd,
369  * it likely unnecessary to use FD_ISSET
370  */
371  if (FD_ISSET(_sick_fd,&file_desc_set)) {
372 
373  /* Read a single byte from the stream! */
374  num_bytes_read = read(_sick_fd,&dest_buffer[total_num_bytes_read],1);
375 
376  /* Decide what to do based on the output of read */
377  if (num_bytes_read > 0) { //Update the number of bytes read so far
378  total_num_bytes_read += num_bytes_read;
379  }
380  else {
381  /* If this happens, something is wrong */
382  throw SickIOException("SickBufferMonitor::_readBytes: read() failed!");
383  }
384 
385  }
386 
387  }
388  else if (num_active_files == 0) {
389 
390  /* A timeout has occurred! */
391  throw SickTimeoutException("SickBufferMonitor::_readBytes: select() timeout!");
392 
393  }
394  else {
395 
396  /* An error has occurred! */
397  throw SickIOException("SickBufferMonitor::_readBytes: select() failed!");
398 
399  }
400 
401  }
402 
403  }
404 
409  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
411 
412  /* Declare a Sick LD receive object */
413  SICK_MSG_CLASS curr_message;
414 
415  /* Acquire the Sick device instance */
416  SICK_MONITOR_CLASS *buffer_monitor = (SICK_MONITOR_CLASS *)thread_args;
417 
418  /* The main thread control loop */
419  for (;;) {
420 
421  try {
422 
423  /* Reset the sick message object */
424  curr_message.Clear();
425 
426  /* Acquire the most recent message */
427  buffer_monitor->AcquireDataStream();
428 
429  if (!buffer_monitor->_continue_grabbing) { // should the thread continue grabbing
430  buffer_monitor->ReleaseDataStream();
431  break;
432  }
433 
434  buffer_monitor->GetNextMessageFromDataStream(curr_message);
435  buffer_monitor->ReleaseDataStream();
436 
437  /* Update message container contents */
438  buffer_monitor->_acquireMessageContainer();
439  buffer_monitor->_recv_msg_container = curr_message;
440  buffer_monitor->_releaseMessageContainer();
441 
442  }
443 
444  /* Make sure there wasn't a serious error reading from the buffer */
445  catch(SickIOException &sick_io_exception) {
446  std::cerr << sick_io_exception.what() << std::endl;
447  }
448 
449  /* Catch any thread exceptions */
450  catch(SickThreadException &sick_thread_exception) {
451  std::cerr << sick_thread_exception.what() << std::endl;
452  }
453 
454  /* A failsafe */
455  catch(...) {
456  std::cerr << "SickBufferMonitor::_bufferMonitorThread: Unknown exception!" << std::endl;
457  }
458 
459  /* sleep a bit! */
460  usleep(1000);
461 
462  }
463 
464  /* Thread is done */
465  return NULL;
466 
467  }
468 
469 } /* namespace SickToolbox */
470 
471 #endif /* SICK_BUFFER_MONITOR */
void StopMonitor()
Cancels the buffer monitor thread.
void AcquireDataStream()
Acquires a lock on the data stream.
~SickBufferMonitor()
The destructor (kills the mutex)
bool GetNextMessageFromMonitor(SICK_MSG_CLASS &sick_message)
Checks the message container for the next available Sick message.
Contains some simple exception classes.
void _readBytes(uint8_t *const dest_buffer, const int num_bytes_to_read, const unsigned int timeout_value=0) const
Attempt to read a certain number of bytes from the stream.
SICK_MONITOR_CLASS * _sick_monitor_instance
void SetDataStream(const unsigned int sick_fd)
A method for setting/changing the current data stream.
void ReleaseDataStream()
Releases a lock on the data stream.
virtual const char * what() const
From the standard exception library.
void _releaseMessageContainer()
Unlocks access to the message container.
SickBufferMonitor(SICK_MONITOR_CLASS *const monitor_instance)
Primary constructor.
void GetNextMessageFromDataStream(SICK_MSG_CLASS &sick_message)
void StartMonitor(const unsigned int sick_fd)
Creates and starts the buffer monitor thread.
Encapsulates the Sick LIDAR Matlab/C++ toolbox.
Definition: SickLD.cc:44
Thrown instance where the driver can&#39;t read,write,drain,flush,... the buffers.
static void * _bufferMonitorThread(void *thread_args)
The monitor thread.
void _acquireMessageContainer()
Locks access to the message container.
Makes handling timeouts much easier.
Thrown when error occurs during thread initialization, and uninitialization.


sicktoolbox
Author(s): Jason Derenick , Thomas Miller
autogenerated on Tue Sep 10 2019 03:37:34