-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathserial.c
More file actions
353 lines (276 loc) · 9 KB
/
serial.c
File metadata and controls
353 lines (276 loc) · 9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
//
// serial.c
// lpcflash
//
// Created by ths on 2011-01-16.
//
// Authors:
// Thorsten Schroeder
// David Gullasch
//
// Copyright 2011 ths @ dev.io. All rights reserved.
//
/*
#
# Copyright 2011 Thorsten Schroeder < ths (at) dev (dot) io >. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are
# permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of
# conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
# of conditions and the following disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THORSTEN SCHROEDER ``AS IS'' AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THORSTEN SCHROEDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# The views and conclusions contained in the software and documentation are those of the
# authors and should not be interpreted as representing official policies, either expressed
# or implied, of Thorsten Schroeder.
#
*
* */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <err.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <ctype.h>
#include "msg.h"
#include "serial.h"
#include "serial_cmd.h"
#ifdef WITH_MAGIC_SLEEP
// this function is (by now) necessary on linux, since we ran into trouble without
// this break. This is completely stupid, since using this sleep, it does not even matter
// wether we use 115200 or 38400 baud... therefore we have a new
// XXX TODO: find a solution for the strange behavior on linux
static void magic(void)
{
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 10000000;
nanosleep(&ts,NULL);
}
#endif
int serial_readline(char *buf, int len, int serial_fd)
{
char *p = buf;
size_t remaining = len;
ssize_t nread;
memset(buf, 0, remaining);
while(remaining>0) {
// need to read one character at a time to detect '\n'
nread = read(serial_fd, p, 1);
switch (nread) {
case -1:
if (errno == EAGAIN || errno == EINTR) {
WARN("read interrupted");
continue;
}
err(1, "read(): ");
break;
case 0:
errx(1, "unexpected EOF read");
break;
}
remaining -= nread;
p += nread;
if (p[-1] == '\n')
break;
}
if(p-buf <= 2)
WARN("short line");
else if (p[-2] != '\r' || p[-1] != '\n')
WARN("no CR NL at end of line%s", remaining ? "" : " (buffer too small?)");
return p - buf;
}
int serial_send(int serial_fd, int len, char *data)
{
ssize_t nwritten;
char *p = data;
size_t remaining = len;
#ifdef WITH_MAGIC_SLEEP
// linux problem??
magic();
#endif
while (remaining > 0) {
errno = 0;
nwritten = write(serial_fd, (unsigned char *)p, remaining);
switch (nwritten) {
case -1:
if (errno == EAGAIN || errno == EINTR) {
WARN("write interrupted");
continue;
}
err(1,"write(): ");
break;
case 0:
warn("write(): ");
break;
}
p += nwritten;
remaining -= nwritten;
}
return p - data;
}
int serial_open(char *device, int baudrate)
{
struct termios ttyio;
speed_t speed;
int fd;
fd=open(device, O_RDWR);
if(fd<0)
err(1,"serial_open: open(): ");
//DEBUG("fd = %d\n", fd);
if(tcgetattr(fd,&ttyio)<0)
err(1,"tcgetattr(): ");
/*
* c_iflag
*/
CLR(ttyio.c_iflag,IGNBRK);
// Ignore BREAK condition on input.
CLR(ttyio.c_iflag,BRKINT);
// If IGNBRK is set, a BREAK is ignored. If it is not set but BRKINT
// is set, then a BREAK causes the input and output queues to be
// flushed, and if the terminal is the controlling terminal of a
// foreground process group, it will cause a SIGINT to be sent to
// this foreground process group. When neither IGNBRK nor BRKINT are
// set, a BREAK reads as a null byte ('\0'), except when PARMRK is
// set, in which case it reads as the sequence \377 \0 \0.
SET(ttyio.c_iflag,IGNPAR);
// Ignore framing errors and parity errors.
CLR(ttyio.c_iflag,PARMRK);
// If IGNPAR is not set, prefix a character with a parity error or
// framing error with \377 \0. If neither IGNPAR nor PARMRK is set,
// read a character with a parity error or framing error as \0.
CLR(ttyio.c_iflag,INPCK);
// Enable input parity checking.
CLR(ttyio.c_iflag,ISTRIP);
// Strip off eighth bit.
CLR(ttyio.c_iflag,INLCR);
// Translate NL to CR on input.
CLR(ttyio.c_iflag,IGNCR);
// Ignore carriage return on input.
CLR(ttyio.c_iflag,ICRNL);
// Translate carriage return to newline on input (unless IGNCR is
// set).
SET(ttyio.c_iflag,IXON);
// Enable XON/XOFF flow control on output.
CLR(ttyio.c_iflag,IXANY);
// (XSI) Typing any character will restart stopped output. (The
// default is to allow just the START character to restart output.)
SET(ttyio.c_iflag,IXOFF);
// Enable XON/XOFF flow control on input.
/*
* c_oflag
*/
CLR(ttyio.c_oflag,OPOST);
// Enable implementation-defined output processing.
CLR(ttyio.c_oflag,ONLCR);
// (XSI) Map NL to CR-NL on output.
CLR(ttyio.c_oflag,OCRNL);
// Map CR to NL on output.
CLR(ttyio.c_oflag,ONOCR);
// Don't output CR at column 0.
CLR(ttyio.c_oflag,ONLRET);
// Don't output CR.
CLR(ttyio.c_oflag,OFILL);
// Send fill characters for a delay, rather than using a timed delay.
/*
* c_cflag
*/
CLR(ttyio.c_cflag,CSIZE);
SET(ttyio.c_cflag,CS8);
// Character size mask. Values are CS5, CS6, CS7, or CS8.
CLR(ttyio.c_cflag,CSTOPB);
// Set two stop bits, rather than one.
SET(ttyio.c_cflag,CREAD);
// Enable receiver.
CLR(ttyio.c_cflag,PARENB);
// Enable parity generation on output and parity checking for input.
CLR(ttyio.c_cflag,PARODD);
// If set, then parity for input and output is odd; otherwise even
// parity is used.
CLR(ttyio.c_cflag,HUPCL);
// Lower modem control lines after last process closes the device
// (hang up).
SET(ttyio.c_cflag,CLOCAL);
// Ignore modem control lines.
/*
* c_lflag
*/
CLR(ttyio.c_cflag,ISIG);
// When any of the characters INTR, QUIT, SUSP, or DSUSP are
// received, generate the corresponding signal.
SET(ttyio.c_cflag,ICANON);
// Enable canonical mode (described below).
CLR(ttyio.c_cflag,ECHO);
// Echo input characters.
CLR(ttyio.c_cflag,ECHOE);
// If ICANON is also set, the ERASE character erases the preceding
// input character, and WERASE erases the preceding word.
CLR(ttyio.c_cflag,ECHOK);
// If ICANON is also set, the KILL character erases the current line.
CLR(ttyio.c_cflag,ECHONL);
// If ICANON is also set, echo the NL character even if ECHO is not
// set.
CLR(ttyio.c_cflag,NOFLSH);
// Disable flushing the input and output queues when generating
// signals for the INT, QUIT, and SUSP characters.
CLR(ttyio.c_cflag,TOSTOP);
// Send the SIGTTOU signal to the process group of a background
// process which tries to write to its controlling terminal.
CLR(ttyio.c_cflag,IEXTEN);
// Enable implementation-defined input processing. This flag, as well
// as ICANON must be enabled for the special characters EOL2, LNEXT,
// REPRINT, WERASE to be interpreted, and for the IUCLC flag to be
// effective.
/* set baudrate */
switch(baudrate) {
case 115200:
speed=B115200;
break;
case 57600:
speed=B57600;
break;
case 38400:
speed=B38400;
break;
case 19200:
speed=B19200;
break;
default:
MSG("invalid baud rate (%d)\n",baudrate);
baudrate=9600;
// fallthrough
case 9600:
speed=B9600;
break;
case 4800:
speed=B4800;
break;
}
if(cfsetispeed(&ttyio,speed)<0)
err(1,"cfsetispeed(): ");
if(cfsetospeed(&ttyio,speed)<0)
err(1,"cfsetospeed(): ");
//INFO("baud rate set to %d\n",baudrate);
if(tcsetattr(fd, TCSANOW, &ttyio)<0)
err(1,"tcsetattr(): ");
return(fd);
}