OSDN Git Service

Moved the junk codes to junk directory.
[kozos-expbrd/kozos_expbrd.git] / firm / junk / tools / kz_xmodem / serial_linux.c
1 /**
2  * @file serial_linux.c
3  * @author Shinichiro Nakamura
4  * @brief シリアルポートドライバの実装。(Linuxプラットフォーム用)
5  */
6
7 /*
8  * ===============================================================
9  *  Serial interface library
10  *  Version 0.0.4
11  * ===============================================================
12  * Copyright (c) 2010-2012 Shinichiro Nakamura
13  *
14  * Permission is hereby granted, free of charge, to any person
15  * obtaining a copy of this software and associated documentation
16  * files (the "Software"), to deal in the Software without
17  * restriction, including without limitation the rights to use,
18  * copy, modify, merge, publish, distribute, sublicense, and/or
19  * sell copies of the Software, and to permit persons to whom the
20  * Software is furnished to do so, subject to the following
21  * conditions:
22  *
23  * The above copyright notice and this permission notice shall be
24  * included in all copies or substantial portions of the Software.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
28  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
30  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
31  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
33  * OTHER DEALINGS IN THE SOFTWARE.
34  * ===============================================================
35  */
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <stdarg.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <fcntl.h>
43 #include <poll.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <termios.h>
47 #include <limits.h>
48 #include <pthread.h>
49 #include "serial.h"
50
51 #define MUTEX_INIT()    pthread_mutex_init(&(s->mutex), NULL)
52 #define MUTEX_LOCK()    pthread_mutex_lock(&(s->mutex))
53 #define MUTEX_UNLOCK()  pthread_mutex_unlock(&(s->mutex))
54
55 struct serial {
56     char devfile[BUFSIZ];
57     int fd;
58     struct termios termios_old;
59     struct termios termios_new;
60     pthread_mutex_t mutex;
61 };
62
63 /**
64  * シリアルポートをオープンする.
65  *
66  * @param devfile シリアルポートのデバイスファイル名.
67  * @param baud ボーレート.
68  *
69  * @retval !NULL ハンドラ。
70  * @retval NULL 失敗。
71  */
72 SERIAL *serial_open(const char *devfile, const enum SerialBaud baud)
73 {
74     int baudrate = 0;
75
76     /*
77      * シリアルデスクリプタの管理領域を確保する.
78      */
79     SERIAL *s = (SERIAL *) malloc(sizeof(SERIAL));
80     if (s == NULL) {
81         return NULL;
82     }
83
84     /*
85      * ミューテックスを初期化する.
86      */
87     MUTEX_INIT();
88
89     /*
90      * ポートを開く.
91      */
92     strcpy(s->devfile, devfile);
93     s->fd = open(devfile, O_RDWR | O_NOCTTY | O_NDELAY);
94     if (s->fd < 0) {
95         free(s);
96         return NULL;
97     }
98
99     /*
100      * ポート設定を退避する.
101      */
102     tcgetattr(s->fd, &(s->termios_old));
103
104     /*
105      * ポート設定を初期化する.
106      */
107     memset(&(s->termios_new), 0x00, sizeof(s->termios_new));
108
109     /*
110      * Bxxxxx : ボーレートの設定.cfsetispeed と cfsetospeed も使用できる
111      * CS8    : 8n1 (8 ビット,ノンパリティ,ストップビット 1)
112      * CLOCAL : ローカル接続,モデム制御なし
113      * CREAD  : 受信文字(receiving characters)を有効にする
114      */
115     s->termios_new.c_cflag = CS8 | CLOCAL | CREAD;
116     switch (baud) {
117     case SerialBaud2400:
118         s->termios_new.c_cflag |= B2400;
119         baudrate = 2400;
120         break;
121     case SerialBaud4800:
122         s->termios_new.c_cflag |= B4800;
123         baudrate = 4800;
124         break;
125     case SerialBaud9600:
126         s->termios_new.c_cflag |= B9600;
127         baudrate = 9600;
128         break;
129     case SerialBaud19200:
130         s->termios_new.c_cflag |= B19200;
131         baudrate = 19200;
132         break;
133     case SerialBaud38400:
134         s->termios_new.c_cflag |= B38400;
135         baudrate = 38400;
136         break;
137     default:
138         s->termios_new.c_cflag |= B9600;
139         baudrate = 9600;
140         break;
141     }
142     cfsetispeed(&(s->termios_new), baudrate);
143     cfsetospeed(&(s->termios_new), baudrate);
144
145     /*
146      * IGNPAR : パリティエラーのデータは無視する
147      */
148     s->termios_new.c_iflag = IGNPAR;
149
150     /*
151      * Raw モードでの出力
152      */
153     s->termios_new.c_oflag = 0;
154
155     /*
156      * 入力モードをノンカノニカル、ノンエコーに設定する
157      */
158     s->termios_new.c_lflag = 0;
159
160     /*
161      * モデムラインをクリアし,ポートの設定を有効にする
162      */
163     tcflush(s->fd, TCIFLUSH);
164     tcsetpgrp(s->fd, getpgrp());
165     tcsetattr(s->fd, TCSANOW, &(s->termios_new));
166
167     return s;
168 }
169
170 /**
171  * シリアルポートをクローズする.
172  *
173  * @param s シリアルデスクリプタへのポインタ.
174  *
175  * @return 成功したら0を返す.
176  */
177 int serial_close(SERIAL * s)
178 {
179     /*
180      * ポート設定を元に戻す.
181      */
182     tcsetattr(s->fd, TCSANOW, &(s->termios_old));
183
184     /*
185      * ポートを閉じる.
186      */
187     close(s->fd);
188
189     /*
190      * シリアルデスクリプタの管理領域を破棄する.
191      */
192     free(s);
193
194     return 0;
195 }
196
197 /**
198  * シリアルポートから指定バイト数の読み込みを実行する.
199  *
200  * @param s シリアルデスクリプタへのポインタ.
201  * @param buf バッファへのポインタ.
202  * @param size 読み込みバイト数.
203  *
204  * @return 成功したら0を返す.
205  */
206 int serial_read(SERIAL * s, unsigned char *buf, const size_t size)
207 {
208     int e = 0;
209     int rcvcnt = 0;
210
211     MUTEX_LOCK();
212
213     /*
214      * 読み込みを実行する.
215      */
216     while (rcvcnt < size) {
217         int r = read(s->fd, buf + rcvcnt, size - rcvcnt);
218         if (r < 0) {
219             e = 1;
220             break;
221         }
222         rcvcnt += r;
223     }
224
225     MUTEX_UNLOCK();
226
227     return e;
228 }
229
230 /**
231  * シリアルポートから指定バイト数の読み込みを実行する.
232  *
233  * @param s シリアルデスクリプタへのポインタ.
234  * @param buf バッファへのポインタ.
235  * @param size 読み込みバイト数.
236  * @param ms ミリ秒単位のタイムアウト時間.
237  *
238  * @return 成功したら0を返す.
239  */
240 int serial_read_with_timeout(SERIAL * s,
241         unsigned char *buf, const size_t size, const int ms)
242 {
243     int e = 0;
244     int i;
245
246     MUTEX_LOCK();
247
248     /*
249      * タイムアウトを設定して読み込みを実行する.
250      */
251     for (i = 0; i < (int) size; i++) {
252         struct pollfd fds;
253         fds.fd = s->fd;
254         fds.events = POLLIN;
255         poll(&fds, 1, ms);
256         if (fds.revents & POLLIN) {
257             /*
258              * 1バイトの読み込みを実行.
259              */
260             int r = read(s->fd, buf + i, 1);
261             if (r < 0) {
262                 e = 1;
263                 break;
264             }
265         } else {
266             /*
267              * タイムアウトが発生した.
268              */
269             e = 2;
270             break;
271         }
272     }
273
274     MUTEX_UNLOCK();
275
276     return e;
277 }
278
279 /**
280  * シリアルポートへ指定バイト数の書き込みを実行する.
281  *
282  * @param s シリアルデスクリプタへのポインタ.
283  * @param buf バッファへのポインタ.
284  * @param size 書き込みバイト数.
285  *
286  * @return 成功したら0を返す.
287  */
288 int serial_write(SERIAL * s,
289         const unsigned char *buf, const size_t size)
290 {
291     int e = 0;
292     int sndcnt = 0;
293
294     MUTEX_LOCK();
295
296     while (sndcnt < size) {
297         int r = write(s->fd, buf + sndcnt, size - sndcnt);
298         if (r < 0) {
299             e = 1;
300             break;
301         }
302         sndcnt += r;
303     }
304
305     MUTEX_UNLOCK();
306
307     return e;
308 }
309