Wiselib
wiselib.testing/external_interface/pc/pc_com_uart_file.h
Go to the documentation of this file.
00001 // vim: set noexpandtab ts=4 sw=4:
00002 
00003 #ifndef PC_COM_UART_H
00004 #define PC_COM_UART_H
00005 
00006 #include "util/base_classes/uart_base.h"
00007 
00008 #include <stdlib.h>
00009 #include <stdio.h>
00010 #include <signal.h>
00011 #include <pthread.h>
00012 #include <unistd.h>
00013 #include <fcntl.h>
00014 #include <termios.h>
00015 #include <err.h>
00016 #include <errno.h>
00017 #include <sys/ioctl.h>
00018 
00019 /*
00020  * PC_COM_UART_DEBUG
00021  * 
00022  * undefined or 0 -> No debugging
00023  * >= 1           -> Basic state changes like successful connection will be
00024  *                   reported
00025  * >= 100         -> Hardcore debug output
00026  */
00027 
00028 #if PC_COM_UART_DEBUG
00029    #include <iostream>
00030    #include <iomanip>
00031 #endif
00032 
00033 namespace wiselib {
00034    
00035    namespace {
00036       enum { BUFFER_SIZE = 256 }; // should be enough for 19200 Baud (technically 20 should suffice)
00037    }
00038    
00049    template<
00050       typename OsModel_P,
00051       const char* address_,
00052       const bool isense_reset_ = false,
00053       typename Timer_P = typename OsModel_P::Timer
00054    >
00055    class PCComUartModel
00056       : public UartBase<OsModel_P, typename OsModel_P::size_t, typename OsModel_P::block_data_t>
00057    {
00058       public:
00059          typedef OsModel_P OsModel;
00060          typedef Timer_P Timer;
00061          typedef typename OsModel::size_t size_t;
00062          typedef typename OsModel::block_data_t block_data_t;
00063          typedef PCComUartModel<OsModel_P, address_, isense_reset_, Timer_P> self_type;
00064          typedef self_type* self_pointer_t;
00065          
00066          enum ErrorCodes
00067          {
00068             SUCCESS = OsModel::SUCCESS,
00069             ERR_UNSPEC = OsModel::ERR_UNSPEC
00070          };
00071          
00072          PCComUartModel();
00073          PCComUartModel(PCOs& os);
00074          
00075          void set_baudrate(uint32_t baudrate) {
00076             switch(baudrate) {
00077                case 9600: baudrate_ = B9600; break;
00078                case 19200: baudrate_ = B19200; break;
00079                case 38400: baudrate_ = B38400; break;
00080                case 57600: baudrate_ = B57600; break;
00081                case 115200: baudrate_ = B115200; break;
00082                default:
00083                   assert(false);
00084             }
00085          }
00086          
00087          int enable_serial_comm();
00088          int disable_serial_comm();
00089          
00090          int write(size_t len, char* buf);
00091          void try_read(void* userdata);
00092          
00093          const char* address() { return address_; }
00094          
00095       private:
00096          Timer timer_;
00097          ::speed_t baudrate_;
00098          
00099          int port_fd_;
00100          
00101          void try_read();
00102    }; // class PCComUartModel
00103    
00104    template<typename OsModel_P, const char* address_, const bool isense_reset_, typename Timer_P>
00105    PCComUartModel<OsModel_P, address_, isense_reset_, Timer_P>::
00106 	PCComUartModel(PCOs& os) : timer_(os), baudrate_(B9600) {
00107    }
00108    
00109    template<typename OsModel_P, const char* address_, const bool isense_reset_, typename Timer_P>
00110    PCComUartModel<OsModel_P, address_, isense_reset_, Timer_P>::
00111 	PCComUartModel() : baudrate_(B9600) {
00112    }
00113 
00114    template<typename OsModel_P, const char* address_, const bool isense_reset_, typename Timer_P>
00115    int PCComUartModel<OsModel_P, address_, isense_reset_, Timer_P>::enable_serial_comm() {
00116       // source: http://en.wikibooks.org/wiki/Serial_Programming/Serial_Linux
00117       
00118       struct termios attr;
00119       //memset(&attr, 0, sizeof(attr));
00120       bzero(&attr, sizeof(attr));
00121       //tcgetattr(port_fd_, &attr);
00122       attr.c_cflag = baudrate_|CS8|CREAD|CLOCAL; // 8N1
00123       attr.c_iflag = 0;
00124       attr.c_oflag = 0;
00125       attr.c_lflag = 0;
00126       attr.c_cc[VMIN] = 1; // try to read at least 1 char
00127       attr.c_cc[VTIME] = 0; // time out after 800ms
00128       
00129       #if PC_COM_UART_DEBUG
00130       std::cout << "[pc_com_uart] Opening: " << address_ << "\n";
00131       #endif
00132       
00133       port_fd_ = open(address_, O_RDWR | O_NONBLOCK | O_NOCTTY);
00134       if(port_fd_ < 0) {
00135          err(1, "Error opening UART %s", address_);
00136       }
00137       
00138       if( ( cfsetospeed(&attr, baudrate_) == -1 ) ||
00139          ( cfsetispeed(&attr, baudrate_) == -1 ) )
00140       {
00141          perror( "Could not set baudrate:" );
00142       }
00143 
00144       tcflush(port_fd_, TCOFLUSH);
00145       tcflush(port_fd_, TCIFLUSH);
00146       if(tcsetattr(port_fd_, TCSANOW, &attr) == -1) {
00147          err(1, "Error during tcsetattr() on %s", address_);
00148       }
00149       
00150       if(isense_reset_) {
00151          #if PC_COM_UART_DEBUG
00152          std::cout << "[pc_com_uart] Executing isense reset" << std::endl;
00153          #endif
00154          
00155          int status = TIOCM_RTS | TIOCM_DTR;
00156          ioctl(port_fd_, TIOCMSET, &status);
00157          timer_.sleep(100);
00158          status = 0;
00159          ioctl(port_fd_, TIOCMSET, &status);
00160          timer_.sleep(100);
00161       }
00162       
00163       timer_.template set_timer<self_type, &self_type::try_read>(100, this, 0);
00164       
00165       return SUCCESS;
00166    }
00167    
00168    template<typename OsModel_P, const char* address_, const bool isense_reset_, typename Timer_P>
00169    int PCComUartModel<OsModel_P, address_, isense_reset_, Timer_P>::disable_serial_comm() {
00170       //close(port_fd_);
00171       //port_fd_ = -1;
00172       return SUCCESS;
00173    }
00174    
00175    template<typename OsModel_P, const char* address_, const bool isense_reset_, typename Timer_P>
00176    int PCComUartModel<OsModel_P, address_, isense_reset_, Timer_P>::
00177 	write(size_t len, char* buf) {
00178       // Block SIGALRM to avoid interrupting call of timer_handler.
00179       sigset_t signal_set, old_signal_set;
00180       if ( ( sigemptyset( &signal_set ) == -1 ) ||
00181             ( sigaddset( &signal_set, SIGALRM ) == -1 ) ||
00182             pthread_sigmask( SIG_BLOCK, &signal_set, &old_signal_set ) )
00183       {
00184          perror( "Failed to block SIGALRM" );
00185       }
00186 
00187       static const int max_retries = 100;
00188       int retries = max_retries, r;
00189       size_t written = 0;
00190       
00191       do {
00192          r = ::write(port_fd_, reinterpret_cast<void*>(buf+written), len-written);
00193          if(r < 0) {
00194             if( ( errno != EAGAIN ) && ( errno != EWOULDBLOCK ) && ( errno != EINTR ) ) {
00195                warn("Error writing to UART %s (%d more retries)", address_, retries);
00196                if(retries == 0) {
00197                   err(1, "Couldnt write to UART %s", address_);
00198                }
00199                else {
00200                   retries--;
00201                }
00202             }
00203          } else {
00204             written += r;
00205             retries = max_retries;
00206          }
00207       } while(written < len);
00208       
00209       #if PC_COM_UART_DEBUG >= 100
00210       std::cout << "[pc_com_uart] wrote: " << len << " bytes." << std::endl;
00211       #endif
00212       
00213       // Unblock SIGALRM.
00214       if( sigismember( &old_signal_set, SIGALRM ) == 0 )
00215       {
00216          if ( ( sigemptyset( &signal_set ) == -1 ) ||
00217                ( sigaddset( &signal_set, SIGALRM ) == -1 ) ||
00218                pthread_sigmask( SIG_UNBLOCK, &signal_set, 0 ) )
00219          {
00220             perror( "Failed to unblock SIGALRM" );
00221          }
00222       }
00223 
00224       return SUCCESS;
00225    } // write
00226 
00227    template<typename OsModel_P, const char* address_, const bool isense_reset_, typename Timer_P>
00228    void PCComUartModel<OsModel_P, address_, isense_reset_, Timer_P>::
00229 	try_read(void* userdata) {
00230       
00231       // Block SIGALRM to avoid interrupting call of timer_handler.
00232       sigset_t signal_set, old_signal_set;
00233       if ( ( sigemptyset( &signal_set ) == -1 ) ||
00234             ( sigaddset( &signal_set, SIGALRM ) == -1 ) ||
00235             pthread_sigmask( SIG_BLOCK, &signal_set, &old_signal_set ) )
00236       {
00237          perror( "Failed to block SIGALRM" );
00238       }
00239 
00240       uint8_t buffer[BUFFER_SIZE];
00241       int bytes = ::read(port_fd_, static_cast<void*>(buffer), BUFFER_SIZE);
00242       
00243       if(bytes == -1) {
00244          if(errno != EAGAIN && errno != EWOULDBLOCK) {
00245             err(1, "Couldnt read from UART %s", address_);
00246          }
00247       }
00248       else if(bytes > 0) {
00249          // <debug>
00250          /*
00251          for(size_t i=0; i<bytes; i++) {
00252             std::cout << (char)buffer[i] << " (" << std::hex << (int)buffer[i] << ") ";
00253          }
00254          std::cout << "\n";
00255          std::cout << std::dec;
00256          */
00257          // </debug>
00258       
00259          self_type::notify_receivers(bytes, buffer);
00260          
00261          #if PC_COM_UART_DEBUG >= 100
00262          std::cout << "[pc_com_uart] try_read read " << bytes << " bytes.\n";
00263          #endif
00264       
00265       }
00266 
00267       // Unblock SIGALRM.
00268       if( sigismember( &old_signal_set, SIGALRM ) == 0 )
00269       {
00270          if ( ( sigemptyset( &signal_set ) == -1 ) ||
00271                ( sigaddset( &signal_set, SIGALRM ) == -1 ) ||
00272                pthread_sigmask( SIG_UNBLOCK, &signal_set, 0 ) )
00273          {
00274             perror( "Failed to unblock SIGALRM" );
00275          }
00276       }
00277 
00278       timer_.template set_timer<self_type, &self_type::try_read>(10, this, 0);
00279    } // try_read
00280    
00281 } // ns wiselib
00282 
00283 #endif // PC_COM_UART_H
00284 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines