int6kdetect.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. /*====================================================================*
  2. *
  3. * Copyright (c) 2013 Qualcomm Atheros, Inc.
  4. *
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or
  8. * without modification, are permitted (subject to the limitations
  9. * in the disclaimer below) provided that the following conditions
  10. * are met:
  11. *
  12. * * Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * * Redistributions in binary form must reproduce the above
  16. * copyright notice, this list of conditions and the following
  17. * disclaimer in the documentation and/or other materials
  18. * provided with the distribution.
  19. *
  20. * * Neither the name of Qualcomm Atheros nor the names of
  21. * its contributors may be used to endorse or promote products
  22. * derived from this software without specific prior written
  23. * permission.
  24. *
  25. * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
  26. * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE
  27. * COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  28. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  29. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  30. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
  31. * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  32. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  33. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  34. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  36. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  37. * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  38. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  39. *
  40. *--------------------------------------------------------------------*/
  41. /*====================================================================*
  42. *
  43. * int6kdetect.c
  44. *
  45. *
  46. * Contributor(s):
  47. * Nathaniel Houghton
  48. *
  49. *--------------------------------------------------------------------*/
  50. /*====================================================================*
  51. * system header files;
  52. *--------------------------------------------------------------------*/
  53. #include <fcntl.h>
  54. #include <limits.h>
  55. #include <stdio.h>
  56. #include <stdlib.h>
  57. #include <string.h>
  58. #include <unistd.h>
  59. #ifdef WIN32
  60. #include <windows.h>
  61. #else
  62. #include <termios.h>
  63. #endif
  64. /*====================================================================*
  65. * custom header files;
  66. *--------------------------------------------------------------------*/
  67. #include "../tools/error.h"
  68. #include "../tools/files.h"
  69. #include "../tools/flags.h"
  70. #include "../tools/putoptv.h"
  71. #include "../tools/getoptv.h"
  72. #include "../serial/serial.h"
  73. /*====================================================================*
  74. * custom source files;
  75. *--------------------------------------------------------------------*/
  76. #ifndef MAKEFILE
  77. #include "../tools/getoptv.c"
  78. #include "../tools/putoptv.c"
  79. #include "../tools/version.c"
  80. #include "../tools/error.c"
  81. #endif
  82. #ifndef MAKEFILE
  83. #include "../serial/baudrate.c"
  84. #endif
  85. /*====================================================================*
  86. * program constants;
  87. *--------------------------------------------------------------------*/
  88. #define SERIAL_PORT "/dev/ttyS0"
  89. #define INT6KDETECT_QUIET (1 << 0)
  90. #define INT6KDETECT_CMD_MODE (1 << 1)
  91. struct serial
  92. {
  93. #ifdef WIN32
  94. HANDLE h;
  95. #else
  96. int fd;
  97. #endif
  98. };
  99. #define UART_NOPARITY 0
  100. #define UART_EVENPARITY 1
  101. #define UART_ODDPARITY 2
  102. struct serial_mode
  103. {
  104. int baud_rate;
  105. int parity;
  106. int data_bits;
  107. int stop_bits;
  108. };
  109. ssize_t read_serial (struct serial *s, void *buf, size_t nbytes)
  110. {
  111. #ifdef WIN32
  112. DWORD read;
  113. BOOL r;
  114. r = ReadFile (s->h, buf, (DWORD) nbytes, &read, NULL);
  115. if (r) return read;
  116. else return -1;
  117. #else
  118. return (read (s->fd, buf, nbytes));
  119. #endif
  120. }
  121. ssize_t write_serial (struct serial *s, void *buf, size_t nbytes)
  122. {
  123. #ifdef WIN32
  124. DWORD written;
  125. BOOL r;
  126. r = WriteFile (s->h, buf, (DWORD) nbytes, &written, NULL);
  127. if (r) return written;
  128. else return -1;
  129. #else
  130. return (write (s->fd, buf, nbytes));
  131. #endif
  132. }
  133. int open_serial (char const *file, struct serial *s)
  134. {
  135. #ifdef WIN32
  136. s->h = CreateFile (file, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  137. if (s->h == INVALID_HANDLE_VALUE)
  138. {
  139. return (-1);
  140. }
  141. #else
  142. if ((s->fd = open (file, O_RDWR)) == -1)
  143. {
  144. return (-1);
  145. }
  146. #endif
  147. return (0);
  148. }
  149. int close_serial (struct serial *s)
  150. {
  151. #ifdef WIN32
  152. if (CloseHandle (s->h)) return 0;
  153. else return -1;
  154. #else
  155. return (close (s->fd));
  156. #endif
  157. }
  158. int set_serial (struct serial *s, struct serial_mode *serial_mode)
  159. {
  160. #ifdef WIN32
  161. COMMTIMEOUTS timeouts;
  162. DCB dcbSerial;
  163. memset (&dcbSerial, 0, sizeof (dcbSerial));
  164. dcbSerial.DCBlength = sizeof (dcbSerial);
  165. if (!GetCommState (s->h, &dcbSerial))
  166. {
  167. return (-1);
  168. }
  169. dcbSerial.BaudRate = serial_mode->baud_rate;
  170. dcbSerial.ByteSize = serial_mode->data_bits;
  171. switch (serial_mode->stop_bits)
  172. {
  173. case 1:
  174. dcbSerial.StopBits = ONESTOPBIT;
  175. break;
  176. case 2:
  177. dcbSerial.StopBits = TWOSTOPBITS;
  178. break;
  179. default:
  180. error (1, 0, "invalid stop bit setting");
  181. }
  182. switch (serial_mode->parity)
  183. {
  184. case UART_ODDPARITY:
  185. dcbSerial.Parity = ODDPARITY;
  186. dcbSerial.fParity = TRUE;
  187. break;
  188. case UART_EVENPARITY:
  189. dcbSerial.Parity = EVENPARITY;
  190. dcbSerial.fParity = TRUE;
  191. break;
  192. case UART_NOPARITY:
  193. dcbSerial.Parity = NOPARITY;
  194. dcbSerial.fParity = FALSE;
  195. break;
  196. default:
  197. error (1, 0, "invalid parity serial_mode");
  198. }
  199. if (!SetCommState (s->h, &dcbSerial))
  200. {
  201. error (0, 0, "could not set serial port settings");
  202. return (-1);
  203. }
  204. timeouts.ReadIntervalTimeout = 0;
  205. timeouts.ReadTotalTimeoutConstant = 10;
  206. timeouts.ReadTotalTimeoutMultiplier = 0;
  207. timeouts.WriteTotalTimeoutConstant = 10;
  208. timeouts.WriteTotalTimeoutMultiplier = 10;
  209. if (!SetCommTimeouts (s->h, &timeouts))
  210. {
  211. return (-1);
  212. }
  213. #else
  214. struct termios termios;
  215. speed_t speed;
  216. tcgetattr (s->fd, &termios);
  217. cfmakeraw (&termios);
  218. termios.c_cflag &= ~CSIZE;
  219. switch (serial_mode->data_bits)
  220. {
  221. case 8:
  222. termios.c_cflag |= CS8;
  223. break;
  224. case 7:
  225. termios.c_cflag |= CS7;
  226. break;
  227. case 6:
  228. termios.c_cflag |= CS6;
  229. break;
  230. case 5:
  231. termios.c_cflag |= CS5;
  232. break;
  233. default:
  234. error (1, 0, "invalid serial byte size");
  235. }
  236. switch (serial_mode->stop_bits)
  237. {
  238. case 2:
  239. termios.c_cflag |= CSTOPB;
  240. break;
  241. case 1:
  242. termios.c_cflag &= ~CSTOPB;
  243. break;
  244. default:
  245. error (1, 0, "invalid number of stop bits");
  246. }
  247. switch (serial_mode->parity)
  248. {
  249. case UART_ODDPARITY:
  250. termios.c_cflag |= PARENB;
  251. termios.c_cflag |= PARODD;
  252. break;
  253. case UART_EVENPARITY:
  254. termios.c_cflag |= PARENB;
  255. termios.c_cflag &= ~PARODD;
  256. break;
  257. case UART_NOPARITY:
  258. termios.c_cflag &= ~PARENB;
  259. break;
  260. default:
  261. error (1, 0, "invalid parity serial_mode");
  262. }
  263. if (baudrate (serial_mode->baud_rate, &speed) == -1)
  264. {
  265. error (0, 0, "warning: unsupported baud rate: %d", serial_mode->baud_rate);
  266. return (-1);
  267. }
  268. if (cfsetspeed (&termios, speed) == -1) error (1, 0, "could not set serial baud rate");
  269. termios.c_cc [VTIME] = 1;
  270. termios.c_cc [VMIN] = 0;
  271. if (tcsetattr (s->fd, TCSANOW, &termios) == -1) error (1, 0, "could not set serial attributes");
  272. #endif
  273. return (0);
  274. }
  275. int at_cmd (struct serial *s)
  276. {
  277. char buf [32];
  278. ssize_t r;
  279. if (write_serial (s, "AT\r", 3) == -1) error (1, 0, "could not write");
  280. memset (buf, 0, sizeof (buf));
  281. r = read_serial (s, buf, sizeof (buf) - 1);
  282. if (r < 0) return -1;
  283. else if (r == 0) return -1;
  284. if (!strcmp (buf, "OK\r")) return 0;
  285. return (-1);
  286. }
  287. void wakeup (struct serial *s)
  288. {
  289. sleep (1);
  290. if (write_serial (s, "+++", 3) == -1) error (1, 0, "could not write");
  291. sleep (1);
  292. }
  293. void dump_serial_mode (struct serial_mode *serial_mode)
  294. {
  295. printf ("baud_rate = %d\n", serial_mode->baud_rate);
  296. printf ("stop_bits = %d\n", serial_mode->stop_bits);
  297. printf ("data_bits = %d\n", serial_mode->data_bits);
  298. printf ("parity = %d\n", serial_mode->parity);
  299. }
  300. int try_serial_mode (struct serial *s, struct serial_mode *serial_mode, flag_t flags)
  301. {
  302. if (set_serial (s, serial_mode) == -1)
  303. {
  304. error (0, 0, "could not set serial_mode");
  305. return (-1);
  306. }
  307. if (!_anyset (flags, INT6KDETECT_CMD_MODE)) wakeup (s);
  308. at_cmd (s);
  309. return (at_cmd (s));
  310. }
  311. int detect (struct serial *s, struct serial_mode *serial_mode, flag_t flags)
  312. {
  313. static int rate [] =
  314. {
  315. 115200,
  316. 9600,
  317. 460800,
  318. 230400,
  319. 57600,
  320. 38400,
  321. 19200,
  322. 4800,
  323. 2400,
  324. 600,
  325. 300,
  326. 50
  327. };
  328. static int parity [] =
  329. {
  330. UART_NOPARITY,
  331. UART_EVENPARITY,
  332. UART_ODDPARITY
  333. };
  334. size_t i;
  335. size_t j;
  336. unsigned current;
  337. unsigned total;
  338. total = 2 * 2 * 3 * (sizeof (rate) / sizeof (int));
  339. current = 0;
  340. for (serial_mode->stop_bits = 1; serial_mode->stop_bits <= 2; ++serial_mode->stop_bits)
  341. {
  342. for (serial_mode->data_bits = 8; serial_mode->data_bits >= 7; --serial_mode->data_bits)
  343. {
  344. for (i = 0; i < sizeof (parity) / sizeof (int); ++i)
  345. {
  346. serial_mode->parity = parity [i];
  347. for (j = 0; j < sizeof (rate) / sizeof (int); ++j)
  348. {
  349. serial_mode->baud_rate = rate [j];
  350. ++current;
  351. if (!_anyset (flags, INT6KDETECT_QUIET))
  352. {
  353. printf ("\rTesting mode: %03u/%03u (%.01f%%)...", current, total, current * 100.0 / total);
  354. fflush (stdout);
  355. }
  356. if (!try_serial_mode (s, serial_mode, flags))
  357. {
  358. if (!_anyset (flags, INT6KDETECT_QUIET)) printf ("\n");
  359. return (0);
  360. }
  361. }
  362. }
  363. }
  364. }
  365. if (!_anyset (flags, INT6KDETECT_QUIET)) printf ("\n");
  366. return (-1);
  367. }
  368. int main (int argc, char const * argv [])
  369. {
  370. static char const * optv [] =
  371. {
  372. "cl:qv",
  373. "",
  374. "Atheros UART Device Detector",
  375. "c\tassume device is in command mode",
  376. "l f\tserial port is (f) [" SERIAL_PORT "]",
  377. "q\tquiet mode",
  378. "v\tverbose mode",
  379. (char const *) (0)
  380. };
  381. signed c;
  382. char const *line = SERIAL_PORT;
  383. struct serial serial;
  384. struct serial_mode serial_mode;
  385. flag_t flags = 0;
  386. optind = 1;
  387. while ((c = getoptv (argc, argv, optv)) != -1)
  388. {
  389. switch ((char) (c))
  390. {
  391. case 'c':
  392. _setbits (flags, INT6KDETECT_CMD_MODE);
  393. break;
  394. case 'l':
  395. line = optarg;
  396. break;
  397. case 'q':
  398. _setbits (flags, INT6KDETECT_QUIET);
  399. break;
  400. default:
  401. break;
  402. }
  403. }
  404. argc -= optind;
  405. argv += optind;
  406. if (open_serial (line, &serial) == -1) error (1, errno, "could not open %s", line);
  407. if (detect (&serial, &serial_mode, flags) == -1) error (1, 0, "could not detect device");
  408. printf ("Detected the following serial mode:\n");
  409. dump_serial_mode (&serial_mode);
  410. close_serial (&serial);
  411. return (0);
  412. }