Develop and Download Open Source Software

Browse Subversion Repository

Contents of /connection/SerialCtrl_lin.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 383 - (show annotations) (download) (as text)
Tue Dec 11 07:55:09 2012 UTC (11 years, 4 months ago) by satofumi
File MIME type: text/x-c++src
File size: 5750 byte(s)
fix compile error
1 /*!
2 \file
3 \brief シリアル接続 (Linux)
4
5 \author Satofumi KAMIMURA
6
7 $Id$
8
9 \todo 適切な箇所で tcdrain() を呼び出すべき
10 */
11
12 #include "SerialCtrl.h"
13 #include "RingBuffer.h"
14 #include <unistd.h>
15 //#include <sys/poll.h>
16 #include <termios.h>
17 #include <fcntl.h>
18 #include <errno.h>
19 #include <cstring>
20 #include <cstdio>
21
22 using namespace beego;
23
24
25 /*!
26 \brief SerialCtrl の内部クラス
27 */
28 struct SerialCtrl::pImpl {
29 std::string error_message;
30 int fd;
31 struct termios sio; //!< 通信制御
32 //struct pollfd nfds; //!< タイムアウト制御
33 fd_set rfds; //!< タイムアウト制御
34 RingBuffer<char> ring_buffer;
35 long baudrate_;
36
37
38 pImpl(void) : error_message("not connected."), fd(-1), baudrate_(0) {
39 //nfds.fd = fd;
40 //nfds.events = 0;
41 //nfds.revents = 0;
42 }
43
44 ~pImpl(void) {
45 disconnect();
46 }
47
48 void disconnect(void) {
49 if (fd >= 0) {
50 close(fd);
51 fd = -1;
52 }
53 ring_buffer.clear();
54 error_message = "disconnected.";
55 }
56
57 bool changeBaudrate(long baudrate) {
58 if (baudrate_ == baudrate) {
59 return true;
60 }
61
62 long baudrate_value = -1;
63 switch (baudrate) {
64
65 case 4800:
66 baudrate_value = B4800;
67 break;
68
69 case 9600:
70 baudrate_value = B9600;
71 break;
72
73 case 19200:
74 baudrate_value = B19200;
75 break;
76
77 case 38400:
78 baudrate_value = B38400;
79 break;
80
81 case 57600:
82 baudrate_value = B57600;
83 break;
84
85 case 115200:
86 baudrate_value = B115200;
87 break;
88
89 default:
90 char* message = new char [80 + 12];
91 sprintf(message, "Invalid baudrate value: %ld", baudrate);
92 error_message = message;
93 delete [] message;
94 return false;
95 break;
96 }
97
98 cfsetospeed(&sio, baudrate_value);
99 cfsetispeed(&sio, baudrate_value);
100 tcsetattr(fd, TCSADRAIN, &sio);
101 flush();
102 baudrate_ = baudrate;
103
104 return true;
105 }
106
107 void update(int timeout, int size = 0) {
108 if (fd < 0) {
109 return;
110 }
111
112 enum { BufferSize = 1024 };
113 int require_size = (size > 0) ? size : BufferSize;
114 int filled = 0;
115 while (filled < require_size) {
116
117 // タイムアウト設定
118 FD_ZERO(&rfds);
119 FD_SET(fd, &rfds);
120
121 struct timeval tv;
122 tv.tv_sec = timeout / 1000;
123 tv.tv_usec = (timeout % 1000) * 1000;
124
125 if (select(fd + 1, &rfds, NULL, NULL, &tv) <= 0) {
126 /* タイムアウト発生 */
127 break; // timeout
128 }
129 char data[BufferSize];
130 int read_n = require_size - filled;
131 int n = read(fd, data, (read_n > BufferSize) ? BufferSize : read_n);
132 if (n <= 0) {
133 return;
134 }
135 ring_buffer.put(data, n);
136 filled += n;
137 }
138 }
139
140 bool isLf(char ch) {
141 return ((ch == '\r') || (ch == '\n')) ? true : false;
142 }
143
144 void flush(void) {
145 tcflush(fd, TCIOFLUSH);
146 }
147 };
148
149
150 SerialCtrl::SerialCtrl(void) : pimpl(new pImpl) {
151 }
152
153
154 SerialCtrl::~SerialCtrl(void) {
155 }
156
157
158 const char* SerialCtrl::what(void) {
159 return pimpl->error_message.c_str();
160 }
161
162
163 bool SerialCtrl::connect(const char* device, long baudrate) {
164
165 // デバイスに接続
166 #ifndef MAC_OS
167 enum { O_EXLOCK = 0x0 }; // Linux では使えないのでダミーを作成しておく
168 #endif
169 int fd = open(device, O_RDWR | O_EXLOCK | O_NONBLOCK | O_NOCTTY);
170 if (fd < 0) {
171 pimpl->error_message = std::string(device) + " : " + strerror(errno);
172 return false;
173 }
174 pimpl->fd = fd;
175
176 int flags = fcntl(fd, F_GETFL, 0);
177 fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
178
179 // シリアル設定
180 tcgetattr(fd, &pimpl->sio);
181 pimpl->sio.c_iflag = 0;
182 pimpl->sio.c_oflag = 0;
183 pimpl->sio.c_cflag &= ~(CSIZE | PARENB | CSTOPB);
184 pimpl->sio.c_cflag |= CS8 | CREAD | CLOCAL;
185 pimpl->sio.c_lflag &= ~(ICANON | ECHO | ISIG | IEXTEN);
186
187 pimpl->sio.c_cc[VMIN] = 0;
188 pimpl->sio.c_cc[VTIME] = 0;
189
190 tcsetattr(fd, TCSAFLUSH, &pimpl->sio);
191 clear();
192
193 // ボーレート設定
194 bool ret = pimpl->changeBaudrate(baudrate);
195 if (ret == false) {
196 return false;
197 }
198
199 pimpl->error_message = "no error";
200 return true;
201 }
202
203
204 void SerialCtrl::disconnect(void) {
205 pimpl->disconnect();
206 }
207
208
209 bool SerialCtrl::isConnected(void) {
210 return (pimpl->fd < 0) ? false : true;
211 }
212
213
214 bool SerialCtrl::changeBaudrate(long baudrate) {
215 return pimpl->changeBaudrate(baudrate);
216 }
217
218
219 int SerialCtrl::send(const char* data, int size) {
220 if (isConnected() == false) {
221 return 0;
222 }
223 return write(pimpl->fd, data, size);
224 }
225
226
227 int SerialCtrl::recv(char* data, int size, int timeout) {
228 //printf("lin recv.\n");
229 if ((isConnected() == false) || (size <= 0)) {
230 return 0;
231 }
232
233 // 要求分だけ受信データがあれば、返す
234 int filled = SerialCtrl::size();
235 if (filled >= size) {
236 pimpl->ring_buffer.get(data, size);
237 return size;
238 }
239
240 // 受信できたデータを返す
241 int left = size - filled;
242 pimpl->update(timeout, left);
243
244 // size() を呼ぶと update(0) が呼ばれるため
245 filled = pimpl->ring_buffer.size();
246 pimpl->ring_buffer.get(data, filled);
247
248 return filled;
249 }
250
251
252 int SerialCtrl::getLine(std::string& data, int timeout) {
253
254 data.clear();
255 int n;
256 do {
257 char ch;
258 n = recv(&ch, 1, timeout);
259 if (n <= 0) {
260 break;
261 }
262 if (pimpl->isLf(ch)) {
263 break;
264 }
265 data.push_back(ch);
266 } while (n > 0);
267
268 return data.size();
269 }
270
271
272 int SerialCtrl::size(int timeout) {
273 pimpl->update(timeout);
274 return pimpl->ring_buffer.size();
275 }
276
277
278 void SerialCtrl::clear(void) {
279 flush();
280 pimpl->update(0);
281 pimpl->ring_buffer.clear();
282 }
283
284
285 void SerialCtrl::skip(int timeout) {
286 clear();
287
288 char buffer[BUFSIZ];
289 int total = 0;
290 int n;
291
292 enum { EachTimeout = 10 };
293 do {
294 n = recv(buffer, BUFSIZ, EachTimeout);
295 total += EachTimeout;
296 } while ((n > 0) && ((timeout > 0) && (total < timeout)));
297 }
298
299
300 void SerialCtrl::flush(void) {
301 pimpl->flush();
302 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26