urg_serial_linux.c
Go to the documentation of this file.
00001 
00010 #include "urg_c/urg_ring_buffer.h"
00011 #include <fcntl.h>
00012 #include <unistd.h>
00013 
00014 
00015 enum {
00016     INVALID_FD = -1,
00017 };
00018 
00019 
00020 static void serial_initialize(urg_serial_t *serial)
00021 {
00022     serial->fd = INVALID_FD;
00023     serial->has_last_ch = False;
00024 
00025     ring_initialize(&serial->ring, serial->buffer, RING_BUFFER_SIZE_SHIFT);
00026 }
00027 
00028 
00029 static void serial_clear(urg_serial_t* serial)
00030 {
00031     tcdrain(serial->fd);
00032     tcflush(serial->fd, TCIOFLUSH);
00033     ring_clear(&serial->ring);
00034     serial->has_last_ch = False;
00035 }
00036 
00037 
00038 int serial_open(urg_serial_t *serial, const char *device, long baudrate)
00039 {
00040     int flags = 0;
00041     int ret = 0;
00042 
00043     serial_initialize(serial);
00044 
00045 #ifndef URG_MAC_OS
00046     enum { O_EXLOCK = 0x0 }; /* Linux では使えないのでダミーを作成しておく */
00047 #endif
00048     serial->fd = open(device, O_RDWR | O_EXLOCK | O_NONBLOCK | O_NOCTTY);
00049     if (serial->fd < 0) {
00050         /* 接続に失敗 */
00051         //strerror_r(errno, serial->error_string, ERROR_MESSAGE_SIZE);
00052         return -1;
00053     }
00054 
00055     flags = fcntl(serial->fd, F_GETFL, 0);
00056     fcntl(serial->fd, F_SETFL, flags & ~O_NONBLOCK);
00057 
00058     /* シリアル通信の初期化 */
00059     tcgetattr(serial->fd, &serial->sio);
00060     serial->sio.c_iflag = 0;
00061     serial->sio.c_oflag = 0;
00062     serial->sio.c_cflag &= ~(CSIZE | PARENB | CSTOPB);
00063     serial->sio.c_cflag |= CS8 | CREAD | CLOCAL;
00064     serial->sio.c_lflag &= ~(ICANON | ECHO | ISIG | IEXTEN);
00065 
00066     serial->sio.c_cc[VMIN] = 0;
00067     serial->sio.c_cc[VTIME] = 0;
00068 
00069     /* ボーレートの変更 */
00070     ret = serial_set_baudrate(serial, baudrate);
00071     if (ret < 0) {
00072         return ret;
00073     }
00074 
00075     /* シリアル制御構造体の初期化 */
00076     serial->has_last_ch = False;
00077 
00078     return 0;
00079 }
00080 
00081 
00082 void serial_close(urg_serial_t *serial)
00083 {
00084     if (serial->fd >= 0) {
00085         close(serial->fd);
00086         serial->fd = INVALID_FD;
00087     }
00088 }
00089 
00090 
00091 int serial_set_baudrate(urg_serial_t *serial, long baudrate)
00092 {
00093     long baudrate_value = -1;
00094 
00095     switch (baudrate) {
00096     case 4800:
00097         baudrate_value = B4800;
00098         break;
00099 
00100     case 9600:
00101         baudrate_value = B9600;
00102         break;
00103 
00104     case 19200:
00105         baudrate_value = B19200;
00106         break;
00107 
00108     case 38400:
00109         baudrate_value = B38400;
00110         break;
00111 
00112     case 57600:
00113         baudrate_value = B57600;
00114         break;
00115 
00116     case 115200:
00117         baudrate_value = B115200;
00118         break;
00119 
00120     default:
00121         return -1;
00122     }
00123 
00124     /* ボーレート変更 */
00125     cfsetospeed(&serial->sio, baudrate_value);
00126     cfsetispeed(&serial->sio, baudrate_value);
00127     tcsetattr(serial->fd, TCSADRAIN, &serial->sio);
00128     serial_clear(serial);
00129 
00130     return 0;
00131 }
00132 
00133 
00134 int serial_write(urg_serial_t *serial, const char *data, int size)
00135 {
00136     if (serial->fd == INVALID_FD) {
00137         return -1;
00138     }
00139     return write(serial->fd, data, size);
00140 }
00141 
00142 
00143 static int wait_receive(urg_serial_t* serial, int timeout)
00144 {
00145     fd_set rfds;
00146     struct timeval tv;
00147 
00148     // タイムアウト設定
00149     FD_ZERO(&rfds);
00150     FD_SET(serial->fd, &rfds);
00151 
00152     tv.tv_sec = timeout / 1000;
00153     tv.tv_usec = (timeout % 1000) * 1000;
00154 
00155     if (select(serial->fd + 1, &rfds, NULL, NULL,
00156                (timeout < 0) ? NULL : &tv) <= 0) {
00157         /* タイムアウト発生 */
00158         return 0;
00159     }
00160     return 1;
00161 }
00162 
00163 
00164 static int internal_receive(char data[], int data_size_max,
00165                             urg_serial_t* serial, int timeout)
00166 {
00167     int filled = 0;
00168 
00169     if (data_size_max <= 0) {
00170         return 0;
00171     }
00172 
00173     while (filled < data_size_max) {
00174         int require_n;
00175         int read_n;
00176 
00177         if (! wait_receive(serial, timeout)) {
00178             break;
00179         }
00180 
00181         require_n = data_size_max - filled;
00182         read_n = read(serial->fd, &data[filled], require_n);
00183         if (read_n <= 0) {
00184             /* 読み出しエラー。現在までの受信内容で戻る */
00185             break;
00186         }
00187         filled += read_n;
00188     }
00189     return filled;
00190 }
00191 
00192 
00193 int serial_read(urg_serial_t *serial, char *data, int max_size, int timeout)
00194 {
00195     int buffer_size;
00196     int read_n;
00197     int filled = 0;
00198 
00199     if (max_size <= 0) {
00200         return 0;
00201     }
00202 
00203     /* 書き戻した1文字があれば、書き出す */
00204     if (serial->has_last_ch != False) {
00205         data[0] = serial->last_ch;
00206         serial->has_last_ch = False;
00207         ++filled;
00208     }
00209     if (serial->fd == INVALID_FD) {
00210         if (filled > 0) {
00211             return filled;
00212         } else {
00213             return -1;
00214         }
00215     }
00216 
00217     buffer_size = ring_size(&serial->ring);
00218     read_n = max_size - filled;
00219     if (buffer_size < read_n) {
00220         // リングバッファ内のデータで足りなければ、データを読み足す
00221         char buffer[RING_BUFFER_SIZE];
00222         int n = internal_receive(buffer,
00223                                  ring_capacity(&serial->ring) - buffer_size,
00224                                  serial, 0);
00225         if (n > 0) {
00226             ring_write(&serial->ring, buffer, n);
00227             buffer_size += n;
00228         }
00229     }
00230 
00231     // リングバッファ内のデータを返す
00232     if (read_n > buffer_size) {
00233         read_n = buffer_size;
00234     }
00235     if (read_n > 0) {
00236         ring_read(&serial->ring, &data[filled], read_n);
00237         filled += read_n;
00238     }
00239 
00240     // データをタイムアウト付きで読み出す
00241     filled += internal_receive(&data[filled], max_size - filled,
00242                                serial, timeout);
00243     return filled;
00244 }


urg_c
Author(s): Satofumi Kamimura , Katsumi Kimoto, Adrian Boeing
autogenerated on Wed Aug 26 2015 16:38:27