serial.c 8.6 KB

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