1 | /*
|
---|
2 | Serial port access for NTRIP client for POSIX.
|
---|
3 | $Id$
|
---|
4 | Copyright (C) 2008 by Dirk Stöcker <soft@dstoecker.de>
|
---|
5 |
|
---|
6 | This program is free software; you can redistribute it and/or modify
|
---|
7 | it under the terms of the GNU General Public License as published by
|
---|
8 | the Free Software Foundation; either version 2 of the License, or
|
---|
9 | (at your option) any later version.
|
---|
10 |
|
---|
11 | This program is distributed in the hope that it will be useful,
|
---|
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
14 | GNU General Public License for more details.
|
---|
15 |
|
---|
16 | You should have received a copy of the GNU General Public License
|
---|
17 | along with this program; if not, write to the Free Software
|
---|
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
---|
19 | or read http://www.gnu.org/licenses/gpl.txt
|
---|
20 | */
|
---|
21 |
|
---|
22 | /* system includes */
|
---|
23 | #include <stdio.h>
|
---|
24 | #include <string.h>
|
---|
25 |
|
---|
26 | #ifndef WINDOWSVERSION
|
---|
27 | #include <errno.h>
|
---|
28 | #include <fcntl.h>
|
---|
29 | #include <string.h>
|
---|
30 | #include <termios.h>
|
---|
31 | #include <unistd.h>
|
---|
32 | #define SERIALDEFAULTDEVICE "/dev/ttyS0"
|
---|
33 | enum SerialBaud {
|
---|
34 | SPABAUD_50 = B50, SPABAUD_110 = B110, SPABAUD_300 = B300, SPABAUD_600 = B600,
|
---|
35 | SPABAUD_1200 = B1200, SPABAUD_2400 = B2400, SPABAUD_4800 = B4800,
|
---|
36 | SPABAUD_9600 = B9600, SPABAUD_19200 = B19200,
|
---|
37 | SPABAUD_38400 = B38400, SPABAUD_57600 = B57600, SPABAUD_115200 = B115200 };
|
---|
38 | enum SerialDatabits {
|
---|
39 | SPADATABITS_5 = CS5, SPADATABITS_6 = CS6, SPADATABITS_7 = CS7, SPADATABITS_8 = CS8 };
|
---|
40 | enum SerialStopbits {
|
---|
41 | SPASTOPBITS_1 = 0, SPASTOPBITS_2 = CSTOPB };
|
---|
42 | enum SerialParity {
|
---|
43 | SPAPARITY_NONE = 0, SPAPARITY_ODD = PARODD | PARENB, SPAPARITY_EVEN = PARENB };
|
---|
44 | enum SerialProtocol {
|
---|
45 | SPAPROTOCOL_NONE = 0, SPAPROTOCOL_RTS_CTS = 9999,
|
---|
46 | SPAPROTOCOL_XON_XOFF = IXOFF | IXON };
|
---|
47 |
|
---|
48 | struct serial
|
---|
49 | {
|
---|
50 | struct termios Termios;
|
---|
51 | int Stream;
|
---|
52 | };
|
---|
53 | #else /* WINDOWSVERSION */
|
---|
54 | #include <windows.h>
|
---|
55 | #define SERIALDEFAULTDEVICE "COM1"
|
---|
56 | enum SerialBaud {
|
---|
57 | SPABAUD_50 = 50, SPABAUD_110 = 110, SPABAUD_300 = 300, SPABAUD_600 = 600,
|
---|
58 | SPABAUD_1200 = 1200, SPABAUD_2400 = 2400, SPABAUD_4800 = 4800,
|
---|
59 | SPABAUD_9600 = 9600, SPABAUD_19200 = 19200,
|
---|
60 | SPABAUD_38400 = 38400, SPABAUD_57600 = 57600, SPABAUD_115200 = 115200 };
|
---|
61 | enum SerialDatabits {
|
---|
62 | SPADATABITS_5 = 5, SPADATABITS_6 = 6, SPADATABITS_7 = 7, SPADATABITS_8 = 8 };
|
---|
63 | enum SerialStopbits {
|
---|
64 | SPASTOPBITS_1 = 1, SPASTOPBITS_2 = 2 };
|
---|
65 | enum SerialParity {
|
---|
66 | SPAPARITY_NONE = 'N', SPAPARITY_ODD = 'O', SPAPARITY_EVEN = 'E'};
|
---|
67 | enum SerialProtocol {
|
---|
68 | SPAPROTOCOL_NONE, SPAPROTOCOL_RTS_CTS, SPAPROTOCOL_XON_XOFF};
|
---|
69 |
|
---|
70 | struct serial
|
---|
71 | {
|
---|
72 | DCB Termios;
|
---|
73 | HANDLE Stream;
|
---|
74 | };
|
---|
75 | #if !defined(__GNUC__)
|
---|
76 | int strncasecmp(const char *a, const char *b, int len)
|
---|
77 | {
|
---|
78 | while(len-- && *a && tolower(*a) == tolower(*b))
|
---|
79 | {
|
---|
80 | ++a; ++b;
|
---|
81 | }
|
---|
82 | return len ? (tolower(*a) - tolower(*b)) : 0;
|
---|
83 | }
|
---|
84 | #endif /* !__GNUC__ */
|
---|
85 |
|
---|
86 | #endif /* WINDOWSVERSION */
|
---|
87 |
|
---|
88 | static enum SerialParity SerialGetParity(const char *buf, int *ressize)
|
---|
89 | {
|
---|
90 | int r = 0;
|
---|
91 | enum SerialParity p = SPAPARITY_NONE;
|
---|
92 | if(!strncasecmp(buf, "none", 4))
|
---|
93 | { r = 4; p = SPAPARITY_NONE; }
|
---|
94 | else if(!strncasecmp(buf, "no", 2))
|
---|
95 | { r = 2; p = SPAPARITY_NONE; }
|
---|
96 | else if(!strncasecmp(buf, "odd", 3))
|
---|
97 | { r = 3; p = SPAPARITY_ODD; }
|
---|
98 | else if(!strncasecmp(buf, "even", 4))
|
---|
99 | { r = 4; p = SPAPARITY_EVEN; }
|
---|
100 | else if(*buf == 'N' || *buf == 'n')
|
---|
101 | { r = 1; p = SPAPARITY_NONE; }
|
---|
102 | else if(*buf == 'O' || *buf == 'o')
|
---|
103 | { r = 1; p = SPAPARITY_ODD; }
|
---|
104 | else if(*buf == 'E' || *buf == 'e')
|
---|
105 | { r = 1; p = SPAPARITY_EVEN; }
|
---|
106 | if(ressize) *ressize = r;
|
---|
107 | return p;
|
---|
108 | }
|
---|
109 |
|
---|
110 | static enum SerialProtocol SerialGetProtocol(const char *buf, int *ressize)
|
---|
111 | {
|
---|
112 | int r = 0;
|
---|
113 | enum SerialProtocol Protocol = SPAPROTOCOL_NONE;
|
---|
114 | /* try some possible forms for input, be as gentle as possible */
|
---|
115 | if(!strncasecmp("xonxoff",buf,7)){r = 7; Protocol=SPAPROTOCOL_XON_XOFF;}
|
---|
116 | else if(!strncasecmp("xon_xoff",buf,8)){r = 8; Protocol=SPAPROTOCOL_XON_XOFF;}
|
---|
117 | else if(!strncasecmp("xon-xoff",buf,8)){r = 8; Protocol=SPAPROTOCOL_XON_XOFF;}
|
---|
118 | else if(!strncasecmp("xon xoff",buf,8)){r = 8; Protocol=SPAPROTOCOL_XON_XOFF;}
|
---|
119 | else if(!strncasecmp("xoff",buf,4)){r = 4; Protocol=SPAPROTOCOL_XON_XOFF;}
|
---|
120 | else if(!strncasecmp("xon",buf,3)){r = 3; Protocol=SPAPROTOCOL_XON_XOFF;}
|
---|
121 | else if(*buf == 'x' || *buf == 'X'){r = 1; Protocol=SPAPROTOCOL_XON_XOFF;}
|
---|
122 | else if(!strncasecmp("rtscts",buf,6)){r = 6; Protocol=SPAPROTOCOL_RTS_CTS;}
|
---|
123 | else if(!strncasecmp("rts_cts",buf,7)){r = 7; Protocol=SPAPROTOCOL_RTS_CTS;}
|
---|
124 | else if(!strncasecmp("rts-cts",buf,7)){r = 7; Protocol=SPAPROTOCOL_RTS_CTS;}
|
---|
125 | else if(!strncasecmp("rts cts",buf,7)){r = 7; Protocol=SPAPROTOCOL_RTS_CTS;}
|
---|
126 | else if(!strncasecmp("rts",buf,3)){r = 3; Protocol=SPAPROTOCOL_RTS_CTS;}
|
---|
127 | else if(!strncasecmp("cts",buf,3)){r = 3; Protocol=SPAPROTOCOL_RTS_CTS;}
|
---|
128 | else if(*buf == 'r' || *buf == 'R' || *buf == 'c' || *buf == 'C')
|
---|
129 | {r = 1; Protocol=SPAPROTOCOL_RTS_CTS;}
|
---|
130 | else if(!strncasecmp("none",buf,4)){r = 4; Protocol=SPAPROTOCOL_NONE;}
|
---|
131 | else if(!strncasecmp("no",buf,2)){r = 2; Protocol=SPAPROTOCOL_NONE;}
|
---|
132 | else if(*buf == 'n' || *buf == 'N'){r = 1; Protocol=SPAPROTOCOL_NONE;}
|
---|
133 | if(ressize) *ressize = r;
|
---|
134 | return Protocol;
|
---|
135 | }
|
---|
136 |
|
---|
137 | #ifndef WINDOWSVERSION
|
---|
138 | static void SerialFree(struct serial *sn)
|
---|
139 | {
|
---|
140 | if(sn->Stream)
|
---|
141 | {
|
---|
142 | /* reset old settings */
|
---|
143 | tcsetattr(sn->Stream, TCSANOW, &sn->Termios);
|
---|
144 | close(sn->Stream);
|
---|
145 | sn->Stream = 0;
|
---|
146 | }
|
---|
147 | }
|
---|
148 |
|
---|
149 | static const char * SerialInit(struct serial *sn,
|
---|
150 | const char *Device, enum SerialBaud Baud, enum SerialStopbits StopBits,
|
---|
151 | enum SerialProtocol Protocol, enum SerialParity Parity,
|
---|
152 | enum SerialDatabits DataBits, int dowrite
|
---|
153 | #ifdef __GNUC__
|
---|
154 | __attribute__((__unused__))
|
---|
155 | #endif /* __GNUC__ */
|
---|
156 | )
|
---|
157 | {
|
---|
158 | struct termios newtermios;
|
---|
159 |
|
---|
160 | if((sn->Stream = open(Device, O_RDWR | O_NOCTTY | O_NONBLOCK)) <= 0)
|
---|
161 | return "could not open serial port";
|
---|
162 | tcgetattr(sn->Stream, &sn->Termios);
|
---|
163 |
|
---|
164 | memset(&newtermios, 0, sizeof(struct termios));
|
---|
165 | newtermios.c_cflag = Baud | StopBits | Parity | DataBits
|
---|
166 | | CLOCAL | CREAD;
|
---|
167 | if(Protocol == SPAPROTOCOL_RTS_CTS)
|
---|
168 | newtermios.c_cflag |= CRTSCTS;
|
---|
169 | else
|
---|
170 | newtermios.c_cflag |= Protocol;
|
---|
171 | newtermios.c_cc[VMIN] = 1;
|
---|
172 | tcflush(sn->Stream, TCIOFLUSH);
|
---|
173 | tcsetattr(sn->Stream, TCSANOW, &newtermios);
|
---|
174 | tcflush(sn->Stream, TCIOFLUSH);
|
---|
175 | fcntl(sn->Stream, F_SETFL, O_NONBLOCK);
|
---|
176 | return 0;
|
---|
177 | }
|
---|
178 |
|
---|
179 | static int SerialRead(struct serial *sn, char *buffer, size_t size)
|
---|
180 | {
|
---|
181 | int j = read(sn->Stream, buffer, size);
|
---|
182 | if(j < 0)
|
---|
183 | {
|
---|
184 | if(errno == EAGAIN)
|
---|
185 | return 0;
|
---|
186 | else
|
---|
187 | return j;
|
---|
188 | }
|
---|
189 | return j;
|
---|
190 | }
|
---|
191 |
|
---|
192 | static int SerialWrite(struct serial *sn, const char *buffer, size_t size)
|
---|
193 | {
|
---|
194 | int j = write(sn->Stream, buffer, size);
|
---|
195 | if(j < 0)
|
---|
196 | {
|
---|
197 | if(errno == EAGAIN)
|
---|
198 | return 0;
|
---|
199 | else
|
---|
200 | return j;
|
---|
201 | }
|
---|
202 | return j;
|
---|
203 | }
|
---|
204 |
|
---|
205 | #else /* WINDOWSVERSION */
|
---|
206 | static void SerialFree(struct serial *sn)
|
---|
207 | {
|
---|
208 | if(sn->Stream)
|
---|
209 | {
|
---|
210 | SetCommState(sn->Stream, &sn->Termios);
|
---|
211 | /* reset old settings */
|
---|
212 | CloseHandle(sn->Stream);
|
---|
213 | sn->Stream = 0;
|
---|
214 | }
|
---|
215 | }
|
---|
216 |
|
---|
217 | static const char * SerialInit(struct serial *sn, const char *Device,
|
---|
218 | enum SerialBaud Baud, enum SerialStopbits StopBits,
|
---|
219 | enum SerialProtocol Protocol, enum SerialParity Parity,
|
---|
220 | enum SerialDatabits DataBits, int dowrite)
|
---|
221 | {
|
---|
222 | char mydevice[50];
|
---|
223 | if(Device[0] != '\\')
|
---|
224 | snprintf(mydevice, sizeof(mydevice), "\\\\.\\%s", Device);
|
---|
225 | else
|
---|
226 | mydevice[0] = 0;
|
---|
227 |
|
---|
228 | if((sn->Stream = CreateFile(mydevice[0] ? mydevice : Device,
|
---|
229 | dowrite ? GENERIC_WRITE|GENERIC_READ : GENERIC_READ, 0, 0, OPEN_EXISTING,
|
---|
230 | 0, 0)) == INVALID_HANDLE_VALUE)
|
---|
231 | return "could not create file";
|
---|
232 |
|
---|
233 | memset(&sn->Termios, 0, sizeof(sn->Termios));
|
---|
234 | GetCommState(sn->Stream, &sn->Termios);
|
---|
235 |
|
---|
236 | DCB dcb;
|
---|
237 | memset(&dcb, 0, sizeof(dcb));
|
---|
238 | char str[100];
|
---|
239 | snprintf(str,sizeof(str),
|
---|
240 | "baud=%d parity=%c data=%d stop=%d xon=%s octs=%s rts=%s",
|
---|
241 | Baud, Parity, DataBits, StopBits,
|
---|
242 | Protocol == SPAPROTOCOL_XON_XOFF ? "on" : "off",
|
---|
243 | Protocol == SPAPROTOCOL_RTS_CTS ? "on" : "off",
|
---|
244 | Protocol == SPAPROTOCOL_RTS_CTS ? "on" : "off");
|
---|
245 | #ifdef DEBUG
|
---|
246 | fprintf(stderr, "COM Settings: %s\n", str);
|
---|
247 | #endif
|
---|
248 |
|
---|
249 | COMMTIMEOUTS ct = {MAXDWORD, 0, 0, 0, 0};
|
---|
250 |
|
---|
251 | if(!BuildCommDCB(str, &dcb))
|
---|
252 | {
|
---|
253 | CloseHandle(sn->Stream);
|
---|
254 | return "creating device parameters failed";
|
---|
255 | }
|
---|
256 | else if(!SetCommState(sn->Stream, &dcb))
|
---|
257 | {
|
---|
258 | CloseHandle(sn->Stream);
|
---|
259 | return "setting device parameters failed";
|
---|
260 | }
|
---|
261 | else if(!SetCommTimeouts(sn->Stream, &ct))
|
---|
262 | {
|
---|
263 | CloseHandle(sn->Stream);
|
---|
264 | return "setting timeouts failed";
|
---|
265 | }
|
---|
266 |
|
---|
267 | return 0;
|
---|
268 | }
|
---|
269 |
|
---|
270 | static int SerialRead(struct serial *sn, char *buffer, size_t size)
|
---|
271 | {
|
---|
272 | DWORD j = 0;
|
---|
273 | if(!ReadFile(sn->Stream, buffer, size, &j, 0))
|
---|
274 | return -1;
|
---|
275 | return j;
|
---|
276 | }
|
---|
277 |
|
---|
278 | static int SerialWrite(struct serial *sn, const char *buffer, size_t size)
|
---|
279 | {
|
---|
280 | DWORD j = 0;
|
---|
281 | if(!WriteFile(sn->Stream, buffer, size, &j, 0))
|
---|
282 | return -1;
|
---|
283 | return j;
|
---|
284 | }
|
---|
285 | #endif /* WINDOWSVERSION */
|
---|