All Classes Namespaces Files Functions Variables Enumerations Enumerator
libs/connection/c/serial_ctrl_win.c
Go to the documentation of this file.
00001 
00012 #include "serial_ctrl.h"
00013 #include "serial_errno.h"
00014 #include "ring_buffer.h"
00015 #include <stdio.h>
00016 
00017 
00018 enum {
00019   False = 0,
00020   True,
00021 };
00022 
00023 
00024 static void setTimeout(serial_t *serial, int timeout)
00025 {
00026   COMMTIMEOUTS timeouts;
00027   GetCommTimeouts(serial->hCom_, &timeouts);
00028 
00029   timeouts.ReadIntervalTimeout = (timeout == 0) ? MAXDWORD : 0;
00030   timeouts.ReadTotalTimeoutConstant = timeout;
00031   timeouts.ReadTotalTimeoutMultiplier = 0;
00032 
00033   SetCommTimeouts(serial->hCom_, &timeouts);
00034 }
00035 
00036 
00037 void serial_initialize(serial_t *serial)
00038 {
00039   serial->hCom_ = INVALID_HANDLE_VALUE;
00040   serial->errno_ = SerialNoError;
00041   serial->has_last_ch_ = False;
00042 
00043   ring_initialize(&serial->ring_, serial->buffer_, RingBufferSizeShift);
00044 }
00045 
00046 
00047 /* 接続 */
00048 int serial_connect(serial_t *serial, const char *device, long baudrate)
00049 {
00050   // COM10 以降への対応用
00051   enum { NameLength = 11 };
00052   char adjusted_device[NameLength];
00053 
00054   serial_initialize(serial);
00055 
00056   /* COM ポートを開く */
00057   _snprintf(adjusted_device, NameLength, "\\\\.\\%s", device);
00058   serial->hCom_ = CreateFileA(adjusted_device, GENERIC_READ | GENERIC_WRITE, 0,
00059                               NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
00060 
00061   if (serial->hCom_ == INVALID_HANDLE_VALUE) {
00062     printf("open failed: %s\n", device);
00063     return -1;
00064   }
00065 
00066   /* 通信サイズの更新 */
00067   SetupComm(serial->hCom_, 4096 * 8, 4096);
00068 
00069   /* ボーレートの変更 */
00070   serial_setBaudrate(serial, baudrate);
00071 
00072   /* シリアル制御構造体の初期化 */
00073   serial->has_last_ch_ = False;
00074 
00075   /* タイムアウトの設定 */
00076   serial->current_timeout_ = 0;
00077   setTimeout(serial, serial->current_timeout_);
00078 
00079   return 0;
00080 }
00081 
00082 
00083 /* 切断 */
00084 void serial_disconnect(serial_t *serial)
00085 {
00086   if (serial->hCom_ != INVALID_HANDLE_VALUE) {
00087     CloseHandle(serial->hCom_);
00088     serial->hCom_ = INVALID_HANDLE_VALUE;
00089   }
00090 }
00091 
00092 
00093 int serial_isConnected(const serial_t *serial)
00094 {
00095   return (serial->hCom_ == INVALID_HANDLE_VALUE) ? 0 : 1;
00096 }
00097 
00098 
00099 /* ボーレートの変更 */
00100 int serial_setBaudrate(serial_t *serial, long baudrate)
00101 {
00102   long baudrate_value;
00103   DCB dcb;
00104 
00105   switch (baudrate) {
00106 
00107   case 4800:
00108     baudrate_value = CBR_4800;
00109     break;
00110 
00111   case 9600:
00112     baudrate_value = CBR_9600;
00113     break;
00114 
00115   case 19200:
00116     baudrate_value = CBR_19200;
00117     break;
00118 
00119   case 38400:
00120     baudrate_value = CBR_38400;
00121     break;
00122 
00123   case 57600:
00124     baudrate_value = CBR_57600;
00125     break;
00126 
00127   case 115200:
00128     baudrate_value = CBR_115200;
00129     break;
00130 
00131   default:
00132     baudrate_value = baudrate;
00133   }
00134 
00135   GetCommState(serial->hCom_, &dcb);
00136   dcb.BaudRate = baudrate_value;
00137   dcb.ByteSize = 8;
00138   dcb.Parity = NOPARITY;
00139   dcb.fParity = FALSE;
00140   dcb.StopBits = ONESTOPBIT;
00141   SetCommState(serial->hCom_, &dcb);
00142 
00143   return 0;
00144 }
00145 
00146 
00147 /* 送信 */
00148 int serial_send(serial_t *serial, const char *data, int data_size)
00149 {
00150   DWORD n;
00151 
00152   if (data_size < 0) {
00153     return 0;
00154   }
00155 
00156   if (! serial_isConnected(serial)) {
00157     return SerialConnectionFail;
00158   }
00159 
00160   WriteFile(serial->hCom_, data, (DWORD)data_size, &n, NULL);
00161   return n;
00162 }
00163 
00164 
00165 static int internal_receive(char data[], int data_size_max,
00166                             serial_t* serial, int timeout)
00167 {
00168   int filled = 0;
00169   DWORD n;
00170 
00171   if (timeout != serial->current_timeout_) {
00172     setTimeout(serial, timeout);
00173     serial->current_timeout_ = timeout;
00174   }
00175 
00176   ReadFile(serial->hCom_, &data[filled],
00177            (DWORD)data_size_max - filled, &n, NULL);
00178 
00179   return filled + n;
00180 }
00181 
00182 
00183 /* 受信 */
00184 int serial_recv(serial_t *serial, char* data, int data_size_max, int timeout)
00185 {
00186   int filled = 0;
00187   int buffer_size;
00188   int read_n;
00189 
00190   if (data_size_max <= 0) {
00191     return 0;
00192   }
00193 
00194   /* 書き戻した1文字があれば、書き出す */
00195   if (serial->has_last_ch_) {
00196     data[0] = serial->last_ch_;
00197     serial->has_last_ch_ = False;
00198     ++filled;
00199   }
00200 
00201   if (! serial_isConnected(serial)) {
00202     if (filled > 0) {
00203       return filled;
00204     }
00205     return SerialConnectionFail;
00206   }
00207 
00208   buffer_size = ring_size(&serial->ring_);
00209   read_n = data_size_max - filled;
00210   if (buffer_size < read_n) {
00211     // リングバッファ内のデータで足りなければ、データを読み足す
00212     char buffer[RingBufferSize];
00213     int n = internal_receive(buffer,
00214                              ring_capacity(&serial->ring_) - buffer_size,
00215                              serial, 0);
00216     ring_write(&serial->ring_, buffer, n);
00217   }
00218   buffer_size = ring_size(&serial->ring_);
00219 
00220   // リングバッファ内のデータを返す
00221   if (read_n > buffer_size) {
00222     read_n = buffer_size;
00223   }
00224   if (read_n > 0) {
00225     ring_read(&serial->ring_, &data[filled], read_n);
00226     filled += read_n;
00227   }
00228 
00229   // データをタイムアウト付きで読み出す
00230   filled += internal_receive(&data[filled],
00231                              data_size_max - filled, serial, timeout);
00232   return filled;
00233 }
00234 
00235 
00236 /* 1文字書き戻す */
00237 void serial_ungetc(serial_t *serial, char ch)
00238 {
00239   serial->has_last_ch_ = True;
00240   serial->last_ch_ = ch;
00241 }
00242 
00243 
00244 void serial_clear(serial_t* serial)
00245 {
00246   PurgeComm(serial->hCom_,
00247             PURGE_RXABORT | PURGE_TXABORT | PURGE_RXCLEAR | PURGE_TXCLEAR);
00248 
00249   serial->has_last_ch_ = False;
00250 }