SerialInterface.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @package
19 * @author
20 * @date
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24#include "SerialInterface.h"
25
26#include <errno.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30
31#include <iostream>
32
33#include <fcntl.h>
34#include <sys/ioctl.h>
35#include <sys/stat.h>
36#include <sys/types.h>
37#include <termios.h>
38#include <unistd.h>
39
40#include <boost/format.hpp>
41
42static inline tcflag_t
43__bitrate_to_flag(unsigned int bitrate)
44{
45 switch (bitrate)
46 {
47 case 1200:
48 return B1200;
49
50 case 2400:
51 return B2400;
52
53 case 4800:
54 return B4800;
55
56 case 9600:
57 return B9600;
58
59 case 19200:
60 return B19200;
61
62 case 38400:
63 return B38400;
64
65 case 57600:
66 return B57600;
67
68 case 115200:
69 return B115200;
70
71 case 230400:
72 return B230400;
73
74 case 460800:
75 return B460800;
76
77 default:
78 return 0;
79 }
80}
81
82SerialInterface::SerialInterface(const char* device, unsigned int bitrate)
83{
84 this->device = device;
85 this->bitrate = bitrate;
86 this->fd = -1;
87}
88
92
93int
95{
96 // Convert bitrate to flag
97 tcflag_t bitrate = __bitrate_to_flag(this->bitrate);
98
99 if (bitrate == 0)
100 {
101 fprintf(stderr, "Invalid bitrate '%d' for serial device\n", this->bitrate);
102 return -1;
103 }
104
105
106 // Open serial device
107 fd = ::open(device, O_RDWR | O_NOCTTY);
108
109 if (fd < 0)
110 {
111 fprintf(stderr, "Failed to open serial device '%s' (errno: %s)\n", device, strerror(errno));
112 return -1;
113 }
114
115 if (::ioctl(fd, TIOCEXCL))
116 {
117 fprintf(stderr, "Failed to lock serial device '%s' (errno: %s)\n", device, strerror(errno));
118 return -1;
119 }
120
121
122 // Check if device is a terminal device
123 if (!isatty(fd))
124 {
125 fprintf(
126 stderr, "Device '%s' is not a terminal device (errno: %s)!\n", device, strerror(errno));
127 ::close(fd);
128 return -1;
129 }
130
131 struct termios settings;
132
133 // Set input flags
134 settings.c_iflag = IGNBRK // Ignore BREAKS on Input
135 | IGNPAR; // No Parity
136
137 // ICRNL: map CR to NL (otherwise a CR input on the other computer will not terminate input)
138
139 // Set output flags
140 settings.c_oflag = 0; // Raw output
141
142 // Set controlflags
143 settings.c_cflag = bitrate | CS8 // 8 bits per byte
144 | CSTOPB // Stop bit
145 | CREAD // characters may be read
146 | CLOCAL; // ignore modem state, local connection
147
148 // Set local flags
149 settings.c_lflag = 0; // Other option: ICANON = enable canonical input
150
151 // Set maximum wait time on input - cf. Linux Serial Programming HowTo, non-canonical mode
152 // http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html
153 settings.c_cc[VTIME] = 10; // 0 means timer is not uses
154
155 // Set minimum bytes to read
156 settings.c_cc[VMIN] = 0; // 1 means wait until at least 1 character is received
157
158 // Now clean the modem line and activate the settings for the port
159 tcflush(fd, TCIFLUSH);
160
161 tcsetattr(fd, TCSANOW, &settings);
162
163 connected = true;
164
165 return 0;
166}
167
168void
170{
171 if (connected)
172 {
173 ::close(fd);
174 }
175
176 connected = false;
177}
178
179int
180SerialInterface::readInternal(unsigned char* buf, unsigned int len)
181{
182 int res;
183
184 res = blockingReadAll(buf, len);
185
186 if (res < 0)
187 {
188 std::cerr << "Failed to read from serial device" << std::endl;
189 }
190
191 return res;
192}
193
194int
195SerialInterface::blockingReadAll(unsigned char* buf, unsigned int len)
196{
197 int dataToRead = len;
198
199 while (1)
200 {
201 int res = ::read(fd, buf, dataToRead);
202
203 if (res < 0)
204 {
205 return res;
206 }
207
208 dataToRead -= res;
209 buf += res;
210
211 if (dataToRead == 0)
212 {
213 return len;
214 }
215
216 if (dataToRead < 0)
217 {
218 throw new std::runtime_error("Internal error: dataToRead < 0");
219 }
220
221 usleep(1);
222 }
223}
224
225int
226SerialInterface::writeInternal(unsigned char* buf, unsigned int len)
227{
228 return (::write(fd, (void*)buf, len));
229}
230
231std::string
233{
234 return str(boost::format("SerialInterface(connected=%1%, device=%2%, bitrate=%3%, fd=%4%)") %
235 connected % device % bitrate % fd);
236}
std::string str(const T &t)
int write(unsigned char *buf, unsigned int len)
int read(unsigned char *buf, unsigned int len)
int writeInternal(unsigned char *, unsigned int) override
SerialInterface(const char *device, const unsigned int bitrate)
void close() override
int open() override
std::string toString() const override
int readInternal(unsigned char *, unsigned int) override
~SerialInterface() override