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 "SickException.hh"
23 
24 /* Associate the namespace */
25 namespace SickToolbox {
26 
30  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
32 
33  public:
34 
36  SickBufferMonitor( SICK_MONITOR_CLASS * const monitor_instance ) throw( SickThreadException );
37 
39  void SetDataStream( const unsigned int sick_fd ) throw( SickThreadException );
40 
42  void StartMonitor( const unsigned int sick_fd ) throw( SickThreadException );
43 
45  bool GetNextMessageFromMonitor( SICK_MSG_CLASS &sick_message ) throw( SickThreadException );
46 
48  void StopMonitor( ) throw( SickThreadException );
49 
51  void AcquireDataStream( ) throw( SickThreadException );
52 
54  void GetNextMessageFromDataStream( SICK_MSG_CLASS &sick_message );
55 
57  void ReleaseDataStream( ) throw( SickThreadException );
58 
61 
62  protected:
63 
65  unsigned int _sick_fd;
66 
68  void _readBytes( uint8_t * const dest_buffer, const int num_bytes_to_read, const unsigned int timeout_value = 0 ) const throw ( SickTimeoutException, SickIOException );
69 
70  private:
71 
73  SICK_MONITOR_CLASS *_sick_monitor_instance;
74 
77 
79  pthread_t _monitor_thread_id;
80 
82  pthread_mutex_t _container_mutex;
83 
85  pthread_mutex_t _stream_mutex;
86 
88  SICK_MSG_CLASS _recv_msg_container;
89 
92 
94  void _releaseMessageContainer( ) throw( SickThreadException );
95 
97  static void * _bufferMonitorThread( void * thread_args );
98 
99  };
100 
105  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
106  SickBufferMonitor< SICK_MONITOR_CLASS, SICK_MSG_CLASS >::SickBufferMonitor( SICK_MONITOR_CLASS * const monitor_instance ) throw( SickThreadException ) :
107  _sick_monitor_instance(monitor_instance), _continue_grabbing(true), _monitor_thread_id(0) {
108 
109  /* Initialize the shared message buffer mutex */
110  if (pthread_mutex_init(&_container_mutex,NULL) != 0) {
111  throw SickThreadException("SickBufferMonitor::SickBufferMonitor: pthread_mutex_init() failed!");
112  }
113 
114  /* Initialize the shared data stream mutex */
115  if (pthread_mutex_init(&_stream_mutex,NULL) != 0) {
116  throw SickThreadException("SickBufferMonitor::SickBufferMonitor: pthread_mutex_init() failed!");
117  }
118 
119  }
120 
125  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
127 
128  try {
129 
130  /* Attempt to acquire the data stream */
132 
133  /* Assign the data stream fd */
134  _sick_fd = sick_fd;
135 
136  /* Attempt to release the data stream */
138 
139  }
140 
141  /* Handle thread exception */
142  catch(SickThreadException &sick_thread_exception) {
143  std::cerr << sick_thread_exception.what() << std::endl;
144  }
145 
146  /* A safety net */
147  catch(...) {
148  std::cerr << "SickBufferMonitor::SetDataStream: Unknown exception!" << std::endl;
149  throw;
150  }
151 
152  }
153 
158  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
160 
161  /* Assign the fd associated with the data stream */
162  _sick_fd = sick_fd;
163 
164  /* Start the buffer monitor */
166  throw SickThreadException("SickBufferMonitor::StartMonitor: pthread_create() failed!");
167  }
168 
169  /* Set the flag to continue grabbing data */
170  _continue_grabbing = true;
171 
172  }
173 
179  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
181 
182  bool acquired_message = false;
183 
184  try {
185 
186  /* Acquire a lock on the message buffer */
188 
189  /* Check whether the object is populated */
190  if (_recv_msg_container.IsPopulated()) {
191 
192  /* Copy the shared message */
193  sick_message = _recv_msg_container;
194  _recv_msg_container.Clear();
195 
196  /* Set the flag indicating success */
197  acquired_message = true;
198  }
199 
200  /* Release message container */
202 
203  }
204 
205  /* Handle a thread exception */
206  catch(SickThreadException &sick_thread_exception) {
207  std::cerr << sick_thread_exception.what() << std::endl;
208  throw;
209  }
210 
211  /* Handle an unknown exception */
212  catch(...) {
213  std::cerr << "SickBufferMonitor::CheckMessageContainer: Unknown exception!" << std::endl;
214  throw;
215  }
216 
217  /* Return the flag */
218  return acquired_message;
219  }
220 
225  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
227 
228  try {
229 
230  /* Return results from the thread */
231  void *monitor_result = NULL;
232 
233  /* Tell the thread to quit working */
235  _continue_grabbing = false;
237 
238  /* Wait for the buffer monitor to exit */
239  if (pthread_join(_monitor_thread_id,&monitor_result) != 0) {
240  throw SickThreadException("SickBufferMonitor::StopMonitor: pthread_join() failed!");
241  }
242 
243  }
244 
245  /* Handle thread exception */
246  catch(SickThreadException &sick_thread_exception) {
247  std::cerr << sick_thread_exception.what() << std::endl;
248  }
249 
250  /* A safety net */
251  catch(...) {
252  std::cerr << "SickBufferMonitor::StopMonitor: Unknown exception!" << std::endl;
253  throw;
254  }
255 
256  }
257 
261  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
263 
264  /* Attempt to lock the stream mutex */
265  if (pthread_mutex_lock(&_stream_mutex) != 0) {
266  throw SickThreadException("SickBufferMonitor::AcquireDataStream: pthread_mutex_lock() failed!");
267  }
268 
269  }
270 
274  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
276 
277  /* Attempt to lock the stream mutex */
278  if (pthread_mutex_unlock(&_stream_mutex) != 0) {
279  throw SickThreadException("SickBufferMonitor::ReleaseDataStream: pthread_mutex_unlock() failed!");
280  }
281 
282  }
283 
287  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
289 
290  /* Destroy the message container mutex */
291  if (pthread_mutex_destroy(&_container_mutex) != 0) {
292  throw SickThreadException("SickBufferMonitor::~SickBufferMonitor: pthread_mutex_destroy() failed!");
293  }
294 
295  /* Destroy the data stream container mutex */
296  if (pthread_mutex_destroy(&_stream_mutex) != 0) {
297  throw SickThreadException("SickBufferMonitor::~SickBufferMonitor: pthread_mutex_destroy() failed!");
298  }
299 
300  }
301 
305  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
307 
308  /* Lock the mutex */
309  if (pthread_mutex_lock(&_container_mutex) != 0) {
310  throw SickThreadException("SickBufferMonitor::_acquireMessageContainer: pthread_mutex_lock() failed!");
311  }
312 
313  }
314 
318  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
320 
321  /* Unlock the mutex */
322  if (pthread_mutex_unlock(&_container_mutex) != 0) {
323  throw SickThreadException("SickBufferMonitor::_releaseMessageContainer: pthread_mutex_unlock() failed!");
324  }
325 
326  }
327 
335  template< class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
336  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
338 
339  /* Some helpful variables */
340  int num_bytes_read = 0;
341  int total_num_bytes_read = 0;
342  int num_active_files = 0;
343 
344  struct timeval timeout_val; // This structure will be used for setting our timeout values
345  fd_set file_desc_set; // File descriptor set for monitoring I/O
346 
347  /* Attempt to fetch the bytes */
348  while ( total_num_bytes_read < num_bytes_to_read ) {
349 
350  /* Initialize and set the file descriptor set for select */
351  FD_ZERO(&file_desc_set);
352  FD_SET(_sick_fd,&file_desc_set);
353 
354  /* Setup the timeout structure */
355  memset(&timeout_val,0,sizeof(timeout_val)); // Initialize the buffer
356  timeout_val.tv_usec = timeout_value; // Wait for specified time before throwing a timeout
357 
358  /* Wait for the OS to tell us that data is waiting! */
359  num_active_files = select(getdtablesize(),&file_desc_set,0,0,(timeout_value > 0) ? &timeout_val : 0);
360 
361  /* Figure out what to do based on the output of select */
362  if (num_active_files > 0) {
363 
364  /* A file is ready for reading!
365  *
366  * NOTE: The following conditional is just a sanity check. Since
367  * the file descriptor set only contains the sick device fd,
368  * it likely unnecessary to use FD_ISSET
369  */
370  if (FD_ISSET(_sick_fd,&file_desc_set)) {
371 
372  /* Read a single byte from the stream! */
373  num_bytes_read = read(_sick_fd,&dest_buffer[total_num_bytes_read],1);
374 
375  /* Decide what to do based on the output of read */
376  if (num_bytes_read > 0) { //Update the number of bytes read so far
377  total_num_bytes_read += num_bytes_read;
378  }
379  else {
380  /* If this happens, something is wrong */
381  throw SickIOException("SickBufferMonitor::_readBytes: read() failed!");
382  }
383 
384  }
385 
386  }
387  else if (num_active_files == 0) {
388 
389  /* A timeout has occurred! */
390  throw SickTimeoutException("SickBufferMonitor::_readBytes: select() timeout!");
391 
392  }
393  else {
394 
395  /* An error has occurred! */
396  throw SickIOException("SickBufferMonitor::_readBytes: select() failed!");
397 
398  }
399 
400  }
401 
402  }
403 
408  template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
410 
411  /* Declare a Sick LD receive object */
412  SICK_MSG_CLASS curr_message;
413 
414  /* Acquire the Sick device instance */
415  SICK_MONITOR_CLASS *buffer_monitor = (SICK_MONITOR_CLASS *)thread_args;
416 
417  /* The main thread control loop */
418  for (;;) {
419 
420  try {
421 
422  /* Reset the sick message object */
423  curr_message.Clear();
424 
425  /* Acquire the most recent message */
426  buffer_monitor->AcquireDataStream();
427 
428  if (!buffer_monitor->_continue_grabbing) { // should the thread continue grabbing
429  buffer_monitor->ReleaseDataStream();
430  break;
431  }
432 
433  buffer_monitor->GetNextMessageFromDataStream(curr_message);
434  buffer_monitor->ReleaseDataStream();
435 
436  /* Update message container contents */
437  buffer_monitor->_acquireMessageContainer();
438  buffer_monitor->_recv_msg_container = curr_message;
439  buffer_monitor->_releaseMessageContainer();
440 
441  }
442 
443  /* Make sure there wasn't a serious error reading from the buffer */
444  catch(SickIOException &sick_io_exception) {
445  std::cerr << sick_io_exception.what() << std::endl;
446  }
447 
448  /* Catch any thread exceptions */
449  catch(SickThreadException &sick_thread_exception) {
450  std::cerr << sick_thread_exception.what() << std::endl;
451  }
452 
453  /* A failsafe */
454  catch(...) {
455  std::cerr << "SickBufferMonitor::_bufferMonitorThread: Unknown exception!" << std::endl;
456  }
457 
458  /* sleep a bit! */
459  usleep(1000);
460 
461  }
462 
463  /* Thread is done */
464  return NULL;
465 
466  }
467 
468 } /* namespace SickToolbox */
469 
470 #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.
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.


asr_mild_base_laserscanner
Author(s): Aumann Florian, Borella Jocelyn, Dehmani Souheil, Marek Felix, Reckling Reno
autogenerated on Mon Jun 10 2019 12:41:37