]> rtime.felk.cvut.cz Git - eurobot/public.git/blob - src/hokuyo/lib/serial_ctrl_lin.c
Merge branch 'maint-demo'
[eurobot/public.git] / src / hokuyo / lib / serial_ctrl_lin.c
1 /*!
2   \file
3   \brief �V���A���ʐM (Linux, Mac ���)
4
5   Serial Communication Interface ����
6
7
8   \author Satofumi KAMIMURA
9
10   $Id: serial_ctrl_lin.c 1559 2009-12-01 13:13:08Z satofumi $
11 */
12
13 #include "serial_errno.h"
14 #include "ring_buffer.h"
15 #include <unistd.h>
16 #include <stdio.h>
17 #include <fcntl.h>
18 #include <errno.h>
19 #include <string.h>
20 #include <sys/select.h>
21 #include <time.h>
22 #include <sys/types.h>
23
24
25 //#include <ctype.h>
26
27 enum {
28   False = 0,
29   True,
30 };
31
32
33 enum {
34   InvalidFd = -1,
35 };
36
37
38 void serial_initialize(serial_t *serial)
39 {
40   serial->fd_ = InvalidFd;
41   serial->errno_ = SerialNoError;
42   serial->has_last_ch_ = False;
43
44   ring_initialize(&serial->ring_, serial->buffer_, RingBufferSizeShift);
45 }
46
47
48 /* �ڑ� */
49 int serial_connect(serial_t *serial, const char *device, long baudrate)
50 {
51   int flags = 0;
52   int ret = 0;
53
54   serial_initialize(serial);
55
56 #ifndef MAC_OS
57   enum { O_EXLOCK = 0x0 }; /* Linux �ł͎g���Ȃ��̂Ń_�~�[���쐬���Ă��� */
58 #endif
59   serial->fd_ = open(device, O_RDWR | O_EXLOCK | O_NONBLOCK | O_NOCTTY);
60   if (serial->fd_ < 0) {
61     /* �ڑ��Ɏ��s */
62     strerror_r(errno, serial->error_string_, SerialErrorStringSize);
63     return SerialConnectionFail;
64   }
65
66   flags = fcntl(serial->fd_, F_GETFL, 0);
67   fcntl(serial->fd_, F_SETFL, flags & ~O_NONBLOCK);
68
69   /* �V���A���ʐM�̏����� */
70   tcgetattr(serial->fd_, &serial->sio_);
71   serial->sio_.c_iflag = 0;
72   serial->sio_.c_oflag = 0;
73   serial->sio_.c_cflag &= ~(CSIZE | PARENB | CSTOPB);
74   serial->sio_.c_cflag |= CS8 | CREAD | CLOCAL;
75   serial->sio_.c_lflag &= ~(ICANON | ECHO | ISIG | IEXTEN);
76
77   serial->sio_.c_cc[VMIN] = 0;
78   serial->sio_.c_cc[VTIME] = 0;
79
80   /* �{�[���[�g�̕ύX */
81   ret = serial_setBaudrate(serial, baudrate);
82   if (ret < 0) {
83     return ret;
84   }
85
86   /* �V���A�������\���̂̏����� */
87   serial->has_last_ch_ = False;
88
89   return 0;
90 }
91
92
93 /* �ؒf */
94 void serial_disconnect(serial_t *serial)
95 {
96   if (serial->fd_ >= 0) {
97     close(serial->fd_);
98     serial->fd_ = InvalidFd;
99   }
100 }
101
102
103 int serial_isConnected(const serial_t *serial)
104 {
105   return ((serial == NULL) || (serial->fd_ == InvalidFd)) ? 0 : 1;
106 }
107
108
109 /* �{�[���[�g�̐ݒ� */
110 int serial_setBaudrate(serial_t *serial, long baudrate)
111 {
112   long baudrate_value = -1;
113
114   switch (baudrate) {
115   case 4800:
116     baudrate_value = B4800;
117     break;
118
119   case 9600:
120     baudrate_value = B9600;
121     break;
122
123   case 19200:
124     baudrate_value = B19200;
125     break;
126
127   case 38400:
128     baudrate_value = B38400;
129     break;
130
131   case 57600:
132     baudrate_value = B57600;
133     break;
134
135   case 115200:
136     baudrate_value = B115200;
137     break;
138
139   default:
140     return SerialSetBaudrateFail;
141   }
142
143   /* �{�[���[�g�ύX */
144   cfsetospeed(&serial->sio_, baudrate_value);
145   cfsetispeed(&serial->sio_, baudrate_value);
146   tcsetattr(serial->fd_, TCSADRAIN, &serial->sio_);
147   serial_clear(serial);
148
149   return 0;
150 }
151
152
153 /* ���M */
154 int serial_send(serial_t *serial, const char *data, int data_size)
155 {
156   if (! serial_isConnected(serial)) {
157     return SerialConnectionFail;
158   }
159   return write(serial->fd_, data, data_size);
160 }
161
162
163 static int waitReceive(serial_t* serial, int timeout)
164 {
165   fd_set rfds;
166   struct timeval tv;
167
168   // �^�C���A�E�g�ݒ�
169   FD_ZERO(&rfds);
170   FD_SET(serial->fd_, &rfds);
171
172   tv.tv_sec = timeout / 1000;
173   tv.tv_usec = (timeout % 1000) * 1000;
174
175   if (select(serial->fd_ + 1, &rfds, NULL, NULL,
176              (timeout < 0) ? NULL : &tv) <= 0) {
177     /* �^�C���A�E�g���� */
178     return 0;
179   }
180   return 1;
181 }
182
183
184 static int internal_receive(char data[], int data_size_max,
185                             serial_t* serial, int timeout)
186 {
187   int filled = 0;
188
189   if (data_size_max <= 0) {
190     return 0;
191   }
192
193   while (filled < data_size_max) {
194     int require_n;
195     int read_n;
196
197     if (! waitReceive(serial, timeout)) {
198       break;
199     }
200
201     require_n = data_size_max - filled;
202     read_n = read(serial->fd_, &data[filled], require_n);
203     if (read_n <= 0) {
204       /* �ǂݏo���G���[�B���݂܂ł̎��M���e�Ŗ߂� */
205       break;
206     }
207     filled += read_n;
208   }
209   return filled;
210 }
211
212
213 /* ���M */
214 int serial_recv(serial_t *serial, char* data, int data_size_max, int timeout)
215 {
216   int filled;
217   int read_n;
218   int buffer_size;
219
220   if (data_size_max <= 0) {
221     return 0;
222   }
223
224   /* �����߂����P�����������΁A�����o�� */
225   filled = 0;
226   if (serial->has_last_ch_ != False) {
227     data[0] = serial->last_ch_;
228     serial->has_last_ch_ = False;
229     ++filled;
230   }
231
232   if (! serial_isConnected(serial)) {
233     if (filled > 0) {
234       return filled;
235     }
236     return SerialConnectionFail;
237   }
238
239   buffer_size = ring_size(&serial->ring_);
240   read_n = data_size_max - filled;
241   if (buffer_size < read_n) {
242     // �����O�o�b�t�@���̃f�[�^�ő����Ȃ����΁A�f�[�^���ǂݑ���
243     char buffer[RingBufferSize];
244     int n = internal_receive(buffer,
245                              ring_capacity(&serial->ring_) - buffer_size,
246                              serial, 0);
247     ring_write(&serial->ring_, buffer, n);
248   }
249   buffer_size = ring_size(&serial->ring_);
250
251   // �����O�o�b�t�@���̃f�[�^���Ԃ�
252   if (read_n > buffer_size) {
253     read_n = buffer_size;
254   }
255   if (read_n > 0) {
256     ring_read(&serial->ring_, &data[filled], read_n);
257     filled += read_n;
258   }
259
260   // �f�[�^���^�C���A�E�g�t���œǂݏo��
261   filled += internal_receive(&data[filled],
262                              data_size_max - filled, serial, timeout);
263   return filled;
264 }
265
266
267 /* �P���������߂� */
268 void serial_ungetc(serial_t *serial, char ch)
269 {
270   serial->has_last_ch_ = True;
271   serial->last_ch_ = ch;
272 }
273
274
275 void serial_clear(serial_t* serial)
276 {
277   tcdrain(serial->fd_);
278   tcflush(serial->fd_, TCIOFLUSH);
279   ring_clear(&serial->ring_);
280   serial->has_last_ch_ = False;
281 }