00001
00016 #ifndef SICK_BUFFER_MONITOR
00017 #define SICK_BUFFER_MONITOR
00018
00019
00020 #include <iostream>
00021 #include <pthread.h>
00022 #include <unistd.h>
00023 #include "SickException.hh"
00024
00025
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
00111 if (pthread_mutex_init(&_container_mutex,NULL) != 0) {
00112 throw SickThreadException("SickBufferMonitor::SickBufferMonitor: pthread_mutex_init() failed!");
00113 }
00114
00115
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
00132 AcquireDataStream();
00133
00134
00135 _sick_fd = sick_fd;
00136
00137
00138 ReleaseDataStream();
00139
00140 }
00141
00142
00143 catch(SickThreadException &sick_thread_exception) {
00144 std::cerr << sick_thread_exception.what() << std::endl;
00145 }
00146
00147
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
00163 _sick_fd = sick_fd;
00164
00165
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
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
00188 _acquireMessageContainer();
00189
00190
00191 if (_recv_msg_container.IsPopulated()) {
00192
00193
00194 sick_message = _recv_msg_container;
00195 _recv_msg_container.Clear();
00196
00197
00198 acquired_message = true;
00199 }
00200
00201
00202 _releaseMessageContainer();
00203
00204 }
00205
00206
00207 catch(SickThreadException &sick_thread_exception) {
00208 std::cerr << sick_thread_exception.what() << std::endl;
00209 throw;
00210 }
00211
00212
00213 catch(...) {
00214 std::cerr << "SickBufferMonitor::CheckMessageContainer: Unknown exception!" << std::endl;
00215 throw;
00216 }
00217
00218
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
00232 void *monitor_result = NULL;
00233
00234
00235 AcquireDataStream();
00236 _continue_grabbing = false;
00237 ReleaseDataStream();
00238
00239
00240 if (pthread_join(_monitor_thread_id,&monitor_result) != 0) {
00241 throw SickThreadException("SickBufferMonitor::StopMonitor: pthread_join() failed!");
00242 }
00243
00244 }
00245
00246
00247 catch(SickThreadException &sick_thread_exception) {
00248 std::cerr << sick_thread_exception.what() << std::endl;
00249 }
00250
00251
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
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
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
00292 if (pthread_mutex_destroy(&_container_mutex) != 0) {
00293 throw SickThreadException("SickBufferMonitor::~SickBufferMonitor: pthread_mutex_destroy() failed!");
00294 }
00295
00296
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
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
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
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;
00346 fd_set file_desc_set;
00347
00348
00349 while ( total_num_bytes_read < num_bytes_to_read ) {
00350
00351
00352 FD_ZERO(&file_desc_set);
00353 FD_SET(_sick_fd,&file_desc_set);
00354
00355
00356 memset(&timeout_val,0,sizeof(timeout_val));
00357 timeout_val.tv_usec = timeout_value;
00358
00359
00360 num_active_files = select(getdtablesize(),&file_desc_set,0,0,(timeout_value > 0) ? &timeout_val : 0);
00361
00362
00363 if (num_active_files > 0) {
00364
00365
00366
00367
00368
00369
00370
00371 if (FD_ISSET(_sick_fd,&file_desc_set)) {
00372
00373
00374 num_bytes_read = read(_sick_fd,&dest_buffer[total_num_bytes_read],1);
00375
00376
00377 if (num_bytes_read > 0) {
00378 total_num_bytes_read += num_bytes_read;
00379 }
00380 else {
00381
00382 throw SickIOException("SickBufferMonitor::_readBytes: read() failed!");
00383 }
00384
00385 }
00386
00387 }
00388 else if (num_active_files == 0) {
00389
00390
00391 throw SickTimeoutException("SickBufferMonitor::_readBytes: select() timeout!");
00392
00393 }
00394 else {
00395
00396
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
00413 SICK_MSG_CLASS curr_message;
00414
00415
00416 SICK_MONITOR_CLASS *buffer_monitor = (SICK_MONITOR_CLASS *)thread_args;
00417
00418
00419 for (;;) {
00420
00421 try {
00422
00423
00424 curr_message.Clear();
00425
00426
00427 buffer_monitor->AcquireDataStream();
00428
00429 if (!buffer_monitor->_continue_grabbing) {
00430 buffer_monitor->ReleaseDataStream();
00431 break;
00432 }
00433
00434 buffer_monitor->GetNextMessageFromDataStream(curr_message);
00435 buffer_monitor->ReleaseDataStream();
00436
00437
00438 buffer_monitor->_acquireMessageContainer();
00439 buffer_monitor->_recv_msg_container = curr_message;
00440 buffer_monitor->_releaseMessageContainer();
00441
00442 }
00443
00444
00445 catch(SickIOException &sick_io_exception) {
00446 std::cerr << sick_io_exception.what() << std::endl;
00447 }
00448
00449
00450 catch(SickThreadException &sick_thread_exception) {
00451 std::cerr << sick_thread_exception.what() << std::endl;
00452 }
00453
00454
00455 catch(...) {
00456 std::cerr << "SickBufferMonitor::_bufferMonitorThread: Unknown exception!" << std::endl;
00457 }
00458
00459
00460 usleep(1000);
00461
00462 }
00463
00464
00465 return NULL;
00466
00467 }
00468
00469 }
00470
00471 #endif