All Classes Namespaces Files Functions Variables Enumerations Enumerator
libs/connection/SerialDevice_lin.cpp
Go to the documentation of this file.
00001 
00010 #include <fcntl.h>
00011 #include <termios.h>
00012 #include <cerrno>
00013 #include <cstring>
00014 #include <cstdio>
00015 
00016 
00017 class RawSerialDevice
00018 {
00019     enum {
00020         InvalidFd = -1,
00021     };
00022 
00023     string error_message_;
00024     int fd_;
00025     struct termios sio_;        
00026     fd_set rfds_;               
00027 
00028 
00029     bool waitReceive(int timeout)
00030     {
00031         // タイムアウト設定
00032         FD_ZERO(&rfds_);
00033         FD_SET(fd_, &rfds_);
00034 
00035         struct timeval tv;
00036         tv.tv_sec = timeout / 1000;
00037         tv.tv_usec = (timeout % 1000) * 1000;
00038 
00039         if (select(fd_ + 1, &rfds_, NULL, NULL,
00040                    (timeout < 0) ? NULL : &tv) <= 0) {
00041             /* タイムアウト発生 */
00042             return false;
00043         }
00044         return true;
00045     }
00046 
00047 
00048 public:
00049     RawSerialDevice(void) : error_message_("no error."), fd_(InvalidFd)
00050     {
00051     }
00052 
00053 
00054     const char* what(void)
00055     {
00056         return error_message_.c_str();
00057     }
00058 
00059 
00060     bool connect(const char* device, long baudrate)
00061     {
00062 #ifndef MAC_OS
00063         enum { O_EXLOCK = 0x0 }; // Linux では使えないのでダミーを作成しておく
00064 #endif
00065         fd_ = open(device, O_RDWR | O_EXLOCK | O_NONBLOCK | O_NOCTTY);
00066         if (fd_ < 0) {
00067             // 接続に失敗
00068             error_message_ = string(device) + ": " + strerror(errno);
00069             return false;
00070         }
00071         int flags = fcntl(fd_, F_GETFL, 0);
00072         fcntl(fd_, F_SETFL, flags & ~O_NONBLOCK);
00073 
00074         // シリアル通信の初期化
00075         tcgetattr(fd_, &sio_);
00076         sio_.c_iflag = 0;
00077         sio_.c_oflag = 0;
00078         sio_.c_cflag &= ~(CSIZE | PARENB | CSTOPB);
00079         sio_.c_cflag |= CS8 | CREAD | CLOCAL;
00080         sio_.c_lflag &= ~(ICANON | ECHO | ISIG | IEXTEN);
00081 
00082         sio_.c_cc[VMIN] = 0;
00083         sio_.c_cc[VTIME] = 0;
00084 
00085         // ボーレートの変更
00086         if (! setBaudrate(baudrate)) {
00087             return false;
00088         }
00089         return true;
00090     }
00091 
00092 
00093     void disconnect(void)
00094     {
00095         if (fd_ != InvalidFd) {
00096             close(fd_);
00097             fd_ = InvalidFd;
00098         }
00099     }
00100 
00101 
00102     bool isConnected(void)
00103     {
00104         return (fd_ == InvalidFd) ? false : true;
00105     }
00106 
00107 
00108     bool setBaudrate(long baudrate)
00109     {
00110         long baudrate_value = -1;
00111         enum { ErrorMessageSize = 256 };
00112         char error_message[ErrorMessageSize];
00113 
00114         switch (baudrate) {
00115 
00116         case 4800:
00117             baudrate_value = B4800;
00118             break;
00119 
00120         case 9600:
00121             baudrate_value = B9600;
00122             break;
00123 
00124         case 19200:
00125             baudrate_value = B19200;
00126             break;
00127 
00128         case 38400:
00129             baudrate_value = B38400;
00130             break;
00131 
00132         case 57600:
00133             baudrate_value = B57600;
00134             break;
00135 
00136         case 115200:
00137             baudrate_value = B115200;
00138             break;
00139 
00140         default:
00141             sprintf(error_message, "No handle baudrate value: %ld", baudrate);
00142             error_message_ = string(error_message);
00143             return false;
00144         }
00145 
00146         /* ボーレート変更 */
00147         cfsetospeed(&sio_, baudrate_value);
00148         cfsetispeed(&sio_, baudrate_value);
00149         tcsetattr(fd_, TCSANOW, &sio_);
00150         flush();
00151 
00152         return true;
00153     }
00154 
00155 
00156     int send(const char* data, int count)
00157     {
00158         if (! isConnected()) {
00159             error_message_ = "no connection.";
00160             return 0;
00161         }
00162         return write(fd_, data, count);
00163     }
00164 
00165 
00166     int receive(char buffer[], int count, int timeout)
00167     {
00168         int filled = 0;
00169 
00170         // 指定サイズの読み出しを行う
00171         int n = read(fd_, buffer, count);
00172         if (n < 0) {
00173             return n;
00174         }
00175         filled += n;
00176 
00177         // 受信が完了していたら、戻る
00178         if (filled >= count) {
00179             return filled;
00180         }
00181 
00182         // タイムアウト付きで読み出しを行う
00183         while (filled < count) {
00184             if (! waitReceive(timeout)) {
00185                 break;
00186             }
00187 
00188             int required_n = count - filled;
00189             n = read(fd_, &buffer[filled], required_n);
00190             if (n <= 0) {
00191                 /* 読み出しエラー。現在までの受信内容で戻る */
00192                 break;
00193             }
00194             filled += n;
00195         }
00196         return filled;
00197     }
00198 
00199 
00200     void flush(void)
00201     {
00202         tcdrain(fd_);
00203         tcflush(fd_, TCIOFLUSH);
00204     }
00205 };