[834] | 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 */
|
---|