source: ntrip/trunk/ntripclient/serial.c @ 9178

Last change on this file since 9178 was 834, checked in by stoecker, 13 years ago

added support for serial output

File size: 8.6 KB
Line 
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"
33enum 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 };
38enum SerialDatabits {
39  SPADATABITS_5 = CS5, SPADATABITS_6 = CS6, SPADATABITS_7 = CS7, SPADATABITS_8 = CS8 };
40enum SerialStopbits {
41  SPASTOPBITS_1 = 0, SPASTOPBITS_2 = CSTOPB };
42enum SerialParity {
43  SPAPARITY_NONE = 0, SPAPARITY_ODD = PARODD | PARENB, SPAPARITY_EVEN = PARENB };
44enum SerialProtocol {
45  SPAPROTOCOL_NONE = 0, SPAPROTOCOL_RTS_CTS = 9999,
46  SPAPROTOCOL_XON_XOFF = IXOFF | IXON };
47
48struct serial
49{
50  struct termios Termios;
51  int            Stream;
52};
53#else /* WINDOWSVERSION */
54#include <windows.h>
55#define SERIALDEFAULTDEVICE "COM1"
56enum 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 };
61enum SerialDatabits {
62  SPADATABITS_5 = 5, SPADATABITS_6 = 6, SPADATABITS_7 = 7, SPADATABITS_8 = 8 };
63enum SerialStopbits {
64  SPASTOPBITS_1 = 1, SPASTOPBITS_2 = 2 };
65enum SerialParity {
66  SPAPARITY_NONE = 'N', SPAPARITY_ODD = 'O', SPAPARITY_EVEN = 'E'};
67enum SerialProtocol {
68  SPAPROTOCOL_NONE, SPAPROTOCOL_RTS_CTS, SPAPROTOCOL_XON_XOFF};
69
70struct serial
71{
72  DCB    Termios;
73  HANDLE Stream;
74};
75#if !defined(__GNUC__)
76int 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
88static 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
110static 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
138static 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
149static const char * SerialInit(struct serial *sn,
150const char *Device, enum SerialBaud Baud, enum SerialStopbits StopBits,
151enum SerialProtocol Protocol, enum SerialParity Parity,
152enum 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
179static 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
192static 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 */
206static 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
217static const char * SerialInit(struct serial *sn, const char *Device,
218enum SerialBaud Baud, enum SerialStopbits StopBits,
219enum SerialProtocol Protocol, enum SerialParity Parity,
220enum 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
270static 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
278static 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 */
Note: See TracBrowser for help on using the repository browser.