SickBufferMonitor.hh
Go to the documentation of this file.
00001 
00016 #ifndef SICK_BUFFER_MONITOR
00017 #define SICK_BUFFER_MONITOR
00018 
00019 /* Dependencies */
00020 #include <iostream>
00021 #include <pthread.h>
00022 #include <unistd.h>
00023 #include "SickException.hh"
00024 
00025 /* Associate the namespace */
00026 namespace SickToolbox {
00027 
00031   template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
00032   class SickBufferMonitor {
00033 
00034   public:
00035 
00037     SickBufferMonitor( SICK_MONITOR_CLASS * const monitor_instance ) throw( SickThreadException );
00038 
00040     void SetDataStream( const unsigned int sick_fd ) throw( SickThreadException );
00041     
00043     void StartMonitor( const unsigned int sick_fd ) throw( SickThreadException );
00044 
00046     bool GetNextMessageFromMonitor( SICK_MSG_CLASS &sick_message ) throw( SickThreadException );
00047     
00049     void StopMonitor( ) throw( SickThreadException );
00050 
00052     void AcquireDataStream( ) throw( SickThreadException );
00053 
00055     void GetNextMessageFromDataStream( SICK_MSG_CLASS &sick_message );
00056     
00058     void ReleaseDataStream( ) throw( SickThreadException );
00059 
00061     ~SickBufferMonitor( ) throw( SickThreadException );
00062 
00063   protected:
00064 
00066     unsigned int _sick_fd;   
00067     
00069     void _readBytes( uint8_t * const dest_buffer, const int num_bytes_to_read, const unsigned int timeout_value = 0 ) const throw ( SickTimeoutException, SickIOException );       
00070     
00071   private:
00072 
00074     SICK_MONITOR_CLASS *_sick_monitor_instance;
00075 
00077     bool _continue_grabbing;
00078     
00080     pthread_t _monitor_thread_id;
00081 
00083     pthread_mutex_t _container_mutex;
00084 
00086     pthread_mutex_t _stream_mutex;
00087     
00089     SICK_MSG_CLASS _recv_msg_container;      
00090 
00092     void _acquireMessageContainer( ) throw( SickThreadException );
00093 
00095     void _releaseMessageContainer( ) throw( SickThreadException );   
00096 
00098     static void * _bufferMonitorThread( void * thread_args );    
00099     
00100   };
00101 
00106   template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
00107   SickBufferMonitor< SICK_MONITOR_CLASS, SICK_MSG_CLASS >::SickBufferMonitor( SICK_MONITOR_CLASS * const monitor_instance ) throw( SickThreadException ) :
00108     _sick_monitor_instance(monitor_instance), _continue_grabbing(true), _monitor_thread_id(0) {
00109     
00110     /* Initialize the shared message buffer mutex */
00111     if (pthread_mutex_init(&_container_mutex,NULL) != 0) {
00112       throw SickThreadException("SickBufferMonitor::SickBufferMonitor: pthread_mutex_init() failed!");
00113     }
00114 
00115     /* Initialize the shared data stream mutex */
00116     if (pthread_mutex_init(&_stream_mutex,NULL) != 0) {
00117       throw SickThreadException("SickBufferMonitor::SickBufferMonitor: pthread_mutex_init() failed!");
00118     }
00119     
00120   }
00121 
00126   template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
00127   void SickBufferMonitor< SICK_MONITOR_CLASS, SICK_MSG_CLASS >::SetDataStream( const unsigned int sick_fd ) throw ( SickThreadException ) {
00128 
00129     try {
00130     
00131       /* Attempt to acquire the data stream */
00132       AcquireDataStream();
00133       
00134       /* Assign the data stream fd */
00135       _sick_fd = sick_fd;
00136       
00137       /* Attempt to release the data stream */
00138       ReleaseDataStream();
00139       
00140     }
00141 
00142     /* Handle thread exception */
00143     catch(SickThreadException &sick_thread_exception) {
00144       std::cerr << sick_thread_exception.what() << std::endl;
00145     }
00146     
00147     /* A safety net */
00148     catch(...) {
00149       std::cerr << "SickBufferMonitor::SetDataStream: Unknown exception!" << std::endl;
00150       throw;
00151     }
00152     
00153   }
00154   
00159   template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
00160   void SickBufferMonitor< SICK_MONITOR_CLASS, SICK_MSG_CLASS >::StartMonitor( const unsigned int sick_fd ) throw ( SickThreadException ) {
00161 
00162     /* Assign the fd associated with the data stream */
00163     _sick_fd = sick_fd;
00164     
00165     /* Start the buffer monitor */
00166     if (pthread_create(&_monitor_thread_id,NULL,SickBufferMonitor< SICK_MONITOR_CLASS, SICK_MSG_CLASS >::_bufferMonitorThread,_sick_monitor_instance) != 0) {
00167       throw SickThreadException("SickBufferMonitor::StartMonitor: pthread_create() failed!");
00168     }
00169 
00170     /* Set the flag to continue grabbing data */
00171     _continue_grabbing = true;
00172     
00173   }
00174 
00180   template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
00181   bool SickBufferMonitor< SICK_MONITOR_CLASS, SICK_MSG_CLASS >::GetNextMessageFromMonitor( SICK_MSG_CLASS &sick_message ) throw( SickThreadException ) {
00182 
00183     bool acquired_message = false;
00184 
00185     try {
00186     
00187       /* Acquire a lock on the message buffer */
00188       _acquireMessageContainer();
00189 
00190       /* Check whether the object is populated */
00191       if (_recv_msg_container.IsPopulated()) {
00192 
00193         /* Copy the shared message */
00194         sick_message = _recv_msg_container;
00195         _recv_msg_container.Clear();
00196         
00197         /* Set the flag indicating success */
00198         acquired_message = true;      
00199       }
00200 
00201       /* Release message container */
00202       _releaseMessageContainer();      
00203 
00204     }
00205 
00206     /* Handle a thread exception */
00207     catch(SickThreadException &sick_thread_exception) {
00208       std::cerr << sick_thread_exception.what() << std::endl;
00209       throw;
00210     }
00211 
00212     /* Handle an unknown exception */
00213     catch(...) {
00214       std::cerr << "SickBufferMonitor::CheckMessageContainer: Unknown exception!" << std::endl;
00215       throw;
00216     }
00217     
00218     /* Return the flag */
00219     return acquired_message;    
00220   }
00221   
00226   template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
00227   void SickBufferMonitor< SICK_MONITOR_CLASS, SICK_MSG_CLASS >::StopMonitor( ) throw ( SickThreadException ) {
00228 
00229     try {
00230 
00231       /* Return results from the thread */
00232       void *monitor_result = NULL;     
00233       
00234       /* Tell the thread to quit working */
00235       AcquireDataStream();      
00236       _continue_grabbing = false;
00237       ReleaseDataStream();
00238 
00239       /* Wait for the buffer monitor to exit */
00240       if (pthread_join(_monitor_thread_id,&monitor_result) != 0) {
00241         throw SickThreadException("SickBufferMonitor::StopMonitor: pthread_join() failed!");      
00242       }
00243 
00244     }
00245 
00246     /* Handle thread exception */
00247     catch(SickThreadException &sick_thread_exception) {
00248       std::cerr << sick_thread_exception.what() << std::endl;
00249     }
00250     
00251     /* A safety net */
00252     catch(...) {
00253       std::cerr << "SickBufferMonitor::StopMonitor: Unknown exception!" << std::endl;
00254       throw;
00255     }
00256     
00257   }
00258 
00262   template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
00263   void SickBufferMonitor< SICK_MONITOR_CLASS, SICK_MSG_CLASS >::AcquireDataStream( ) throw( SickThreadException ) {
00264 
00265     /* Attempt to lock the stream mutex */
00266     if (pthread_mutex_lock(&_stream_mutex) != 0) {
00267       throw SickThreadException("SickBufferMonitor::AcquireDataStream: pthread_mutex_lock() failed!");
00268     }
00269     
00270   }
00271 
00275   template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
00276   void SickBufferMonitor< SICK_MONITOR_CLASS, SICK_MSG_CLASS >::ReleaseDataStream( ) throw( SickThreadException ) {
00277 
00278     /* Attempt to lock the stream mutex */
00279     if (pthread_mutex_unlock(&_stream_mutex) != 0) {
00280       throw SickThreadException("SickBufferMonitor::ReleaseDataStream: pthread_mutex_unlock() failed!");
00281     }
00282     
00283   }
00284   
00288   template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
00289   SickBufferMonitor< SICK_MONITOR_CLASS, SICK_MSG_CLASS >::~SickBufferMonitor( ) throw( SickThreadException ) {
00290 
00291     /* Destroy the message container mutex */
00292     if (pthread_mutex_destroy(&_container_mutex) != 0) {
00293       throw SickThreadException("SickBufferMonitor::~SickBufferMonitor: pthread_mutex_destroy() failed!");
00294     }
00295 
00296     /* Destroy the data stream container mutex */
00297     if (pthread_mutex_destroy(&_stream_mutex) != 0) {
00298       throw SickThreadException("SickBufferMonitor::~SickBufferMonitor: pthread_mutex_destroy() failed!");
00299     }
00300     
00301   }
00302 
00306   template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
00307   void SickBufferMonitor< SICK_MONITOR_CLASS, SICK_MSG_CLASS >::_acquireMessageContainer( ) throw( SickThreadException ) {
00308 
00309     /* Lock the mutex */
00310     if (pthread_mutex_lock(&_container_mutex) != 0) {
00311       throw SickThreadException("SickBufferMonitor::_acquireMessageContainer: pthread_mutex_lock() failed!");
00312     }   
00313   
00314   }
00315 
00319   template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
00320   void SickBufferMonitor< SICK_MONITOR_CLASS, SICK_MSG_CLASS >::_releaseMessageContainer( ) throw( SickThreadException ) {
00321 
00322     /* Unlock the mutex */
00323     if (pthread_mutex_unlock(&_container_mutex) != 0) {
00324       throw SickThreadException("SickBufferMonitor::_releaseMessageContainer: pthread_mutex_unlock() failed!");
00325     }   
00326     
00327   }
00328 
00336   template< class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
00337   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
00338     throw ( SickTimeoutException, SickIOException ) {
00339     
00340     /* Some helpful variables */
00341     int num_bytes_read = 0;
00342     int total_num_bytes_read = 0;
00343     int num_active_files = 0;
00344     
00345     struct timeval timeout_val;                     // This structure will be used for setting our timeout values
00346     fd_set file_desc_set;                           // File descriptor set for monitoring I/O    
00347     
00348     /* Attempt to fetch the bytes */
00349     while ( total_num_bytes_read < num_bytes_to_read ) {
00350       
00351       /* Initialize and set the file descriptor set for select */
00352       FD_ZERO(&file_desc_set);
00353       FD_SET(_sick_fd,&file_desc_set);
00354       
00355       /* Setup the timeout structure */
00356       memset(&timeout_val,0,sizeof(timeout_val));   // Initialize the buffer
00357       timeout_val.tv_usec = timeout_value;          // Wait for specified time before throwing a timeout
00358 
00359       /* Wait for the OS to tell us that data is waiting! */
00360       num_active_files = select(getdtablesize(),&file_desc_set,0,0,(timeout_value > 0) ? &timeout_val : 0);
00361       
00362       /* Figure out what to do based on the output of select */
00363       if (num_active_files > 0) {
00364         
00365         /* A file is ready for reading!
00366          *
00367          * NOTE: The following conditional is just a sanity check. Since
00368          *       the file descriptor set only contains the sick device fd,
00369          *       it likely unnecessary to use FD_ISSET
00370          */
00371         if (FD_ISSET(_sick_fd,&file_desc_set)) {
00372           
00373           /* Read a single byte from the stream! */
00374           num_bytes_read = read(_sick_fd,&dest_buffer[total_num_bytes_read],1);
00375 
00376           /* Decide what to do based on the output of read */
00377           if (num_bytes_read > 0) { //Update the number of bytes read so far
00378             total_num_bytes_read += num_bytes_read;
00379           }
00380           else {
00381             /* If this happens, something is wrong */
00382             throw SickIOException("SickBufferMonitor::_readBytes: read() failed!");
00383           }       
00384           
00385         }
00386         
00387       }
00388       else if (num_active_files == 0) {
00389         
00390         /* A timeout has occurred! */
00391         throw SickTimeoutException("SickBufferMonitor::_readBytes: select() timeout!"); 
00392 
00393       }
00394       else {
00395         
00396         /* An error has occurred! */
00397         throw SickIOException("SickBufferMonitor::_readBytes: select() failed!");       
00398 
00399       }
00400       
00401     }
00402     
00403   }
00404   
00409   template < class SICK_MONITOR_CLASS, class SICK_MSG_CLASS >
00410   void * SickBufferMonitor< SICK_MONITOR_CLASS, SICK_MSG_CLASS >::_bufferMonitorThread( void * thread_args ) {
00411     
00412     /* Declare a Sick LD receive object */
00413     SICK_MSG_CLASS curr_message;
00414     
00415     /* Acquire the Sick device instance */
00416     SICK_MONITOR_CLASS *buffer_monitor = (SICK_MONITOR_CLASS *)thread_args;
00417 
00418     /* The main thread control loop */
00419     for (;;) {
00420 
00421       try {
00422 
00423         /* Reset the sick message object */
00424         curr_message.Clear();   
00425 
00426         /* Acquire the most recent message */
00427         buffer_monitor->AcquireDataStream();      
00428         
00429         if (!buffer_monitor->_continue_grabbing) { // should the thread continue grabbing
00430           buffer_monitor->ReleaseDataStream();
00431           break;
00432         }
00433 
00434         buffer_monitor->GetNextMessageFromDataStream(curr_message);
00435         buffer_monitor->ReleaseDataStream();
00436         
00437         /* Update message container contents */
00438         buffer_monitor->_acquireMessageContainer();     
00439         buffer_monitor->_recv_msg_container = curr_message;
00440         buffer_monitor->_releaseMessageContainer();
00441 
00442       }
00443 
00444       /* Make sure there wasn't a serious error reading from the buffer */
00445       catch(SickIOException &sick_io_exception) {
00446         std::cerr << sick_io_exception.what() << std::endl;
00447       }
00448 
00449       /* Catch any thread exceptions */
00450       catch(SickThreadException &sick_thread_exception) {
00451         std::cerr << sick_thread_exception.what() << std::endl;
00452       }
00453       
00454       /* A failsafe */
00455       catch(...) {
00456         std::cerr << "SickBufferMonitor::_bufferMonitorThread: Unknown exception!" << std::endl;
00457       }
00458 
00459       /* sleep a bit! */
00460       usleep(1000);
00461       
00462     }    
00463 
00464     /* Thread is done */
00465     return NULL;
00466     
00467   }
00468   
00469 } /* namespace SickToolbox */
00470 
00471 #endif /* SICK_BUFFER_MONITOR */


sicktoolbox
Author(s): Jason Derenick , Thomas Miller
autogenerated on Sun May 5 2019 02:28:23