serial.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  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. * serial.c - Atheros Serial Line Command Buffer Management;
  44. *
  45. * serial.h
  46. *
  47. * this module contains a serial line command buffer and functions
  48. * to encode and decode it in different formats and send or receive
  49. * it over the serial line;
  50. *
  51. * Contributor(s):
  52. * Charles Maier
  53. *
  54. *--------------------------------------------------------------------*/
  55. #ifndef SERIAL_SOURCE
  56. #define SERIAL_SOURCE
  57. /*====================================================================*
  58. * system header files;
  59. *--------------------------------------------------------------------*/
  60. #include <unistd.h>
  61. #include <stdlib.h>
  62. #include <stdint.h>
  63. #include <memory.h>
  64. #include <errno.h>
  65. #if defined (WIN32)
  66. #include <Windows.h>
  67. #else
  68. #include <sys/select.h>
  69. #endif
  70. /*====================================================================*
  71. * custom header files;
  72. *--------------------------------------------------------------------*/
  73. #include "../serial/serial.h"
  74. #include "../tools/number.h"
  75. #include "../tools/types.h"
  76. #include "../tools/flags.h"
  77. #include "../tools/error.h"
  78. /*====================================================================*
  79. * private variables;
  80. *--------------------------------------------------------------------*/
  81. struct command command;
  82. /*====================================================================*
  83. *
  84. * void clearcommand ();
  85. *
  86. * serial.h
  87. *
  88. * erase the current command by writing 0s;
  89. *
  90. *--------------------------------------------------------------------*/
  91. void clearcommand ()
  92. {
  93. extern struct command command;
  94. memset (&command, 0, sizeof (command));
  95. return;
  96. }
  97. /*====================================================================*
  98. *
  99. * void sendcommand (struct _file_ * port, flag_t flags);
  100. *
  101. * serial.h
  102. *
  103. * echo then send the command;
  104. *
  105. *--------------------------------------------------------------------*/
  106. void sendcommand (struct _file_ * port, flag_t flags)
  107. {
  108. extern struct command command;
  109. if (_anyset (flags, UART_VERBOSE))
  110. {
  111. write (STDERR_FILENO, command.buffer, command.length);
  112. write (STDERR_FILENO, "\n", sizeof (char));
  113. }
  114. if (write (port->file, command.buffer, command.length) != (signed)(command.length))
  115. {
  116. error (1, errno, "Can't write to %s", port->name);
  117. }
  118. clearcommand ();
  119. return;
  120. }
  121. /*====================================================================*
  122. *
  123. * void readcommand (struct _file_ * port, flag_t flags);
  124. *
  125. * serial.h
  126. *
  127. * read response serial line and log the response;
  128. *
  129. *--------------------------------------------------------------------*/
  130. void readcommand (struct _file_ * port, flag_t flags)
  131. {
  132. extern struct command command;
  133. ssize_t tmp;
  134. #if defined (WIN32)
  135. PAUSE (250);
  136. memset (&command, 0, sizeof (command));
  137. tmp = read (port->file, command.buffer, sizeof (command.buffer));
  138. if (tmp < 0)
  139. {
  140. error (1, errno, "Bad response from %s", port->name);
  141. }
  142. if (tmp == 0)
  143. {
  144. error (1, errno, "No response from %s", port->name);
  145. }
  146. command.length = tmp;
  147. #else
  148. struct timeval tv;
  149. fd_set rfd;
  150. memset (&command, 0, sizeof (command));
  151. while (!strchr (command.buffer, '\r'))
  152. {
  153. tv.tv_sec = 1;
  154. tv.tv_usec = 0;
  155. FD_ZERO (&rfd);
  156. FD_SET (port->file, &rfd);
  157. if (select (port->file + 1, &rfd, NULL, NULL, &tv) != 1)
  158. {
  159. error (1, errno, "Read timeout");
  160. }
  161. tmp = read (port->file, command.buffer + command.length, sizeof (command.buffer) - command.length - 1);
  162. if (tmp < 0)
  163. {
  164. error (1, errno, "Could not read %s", port->name);
  165. }
  166. command.length += tmp;
  167. command.buffer [command.length] = '\0';
  168. }
  169. #endif
  170. if (_anyset (flags, UART_VERBOSE))
  171. {
  172. write (STDERR_FILENO, command.buffer, command.length);
  173. write (STDERR_FILENO, "\n", sizeof (char));
  174. }
  175. if (!memcmp (command.buffer, "ERROR", 5))
  176. {
  177. error (1, ECANCELED, "Device refused request");
  178. }
  179. return;
  180. }
  181. /*====================================================================*
  182. *
  183. * void insert (char c);
  184. *
  185. * serial.h
  186. *
  187. * insert a character into the command buffer at the current buffer
  188. * position then increment the buffer position pointer;
  189. *
  190. *--------------------------------------------------------------------*/
  191. void insert (char c)
  192. {
  193. extern struct command command;
  194. if (command.length < sizeof (command.buffer))
  195. {
  196. command.buffer [command.length++] = c;
  197. }
  198. return;
  199. }
  200. /*====================================================================*
  201. *
  202. * unsigned readframe (signed fd, void * memory, size_t extent);
  203. *
  204. * serial.h
  205. *
  206. * read a file and convert hexadecimal octets to binary bytes then
  207. * store them in consecutive memory locations up to a given length;
  208. * return the actual number of bytes stored;
  209. *
  210. * digits may be consecutive or separated by white space consisting
  211. * of spaces, tabs, linefeeds, carriage returns, formfeeds or other
  212. * characters such as punctuation; script-style comments are treated
  213. * as white space;
  214. *
  215. *--------------------------------------------------------------------*/
  216. static signed fdgetc (signed fd)
  217. {
  218. char c;
  219. return ((read (fd, &c, sizeof (c)) == sizeof (c))? c: EOF);
  220. }
  221. size_t readframe (signed fd, void * memory, size_t extent)
  222. {
  223. unsigned digits = 0;
  224. uint8_t * origin = (uint8_t *)(memory);
  225. uint8_t * offset = (uint8_t *)(memory);
  226. signed c = EOF;
  227. while ((extent) && ((c = fdgetc (fd)) != EOF) && (c != ';'))
  228. {
  229. if (isspace (c))
  230. {
  231. continue;
  232. }
  233. if (c == '#')
  234. {
  235. do
  236. {
  237. c = fdgetc (fd);
  238. }
  239. while ((c != '\n') && (c != EOF));
  240. continue;
  241. }
  242. if (c == '/')
  243. {
  244. c = fdgetc (fd);
  245. if (c == '/')
  246. {
  247. do
  248. {
  249. c = fdgetc (fd);
  250. }
  251. while ((c != '\n') && (c != EOF));
  252. continue;
  253. }
  254. if (c == '*')
  255. {
  256. while ((c != '/') && (c != EOF))
  257. {
  258. while ((c != '*') && (c != EOF))
  259. {
  260. c = fdgetc (fd);
  261. }
  262. c = fdgetc (fd);
  263. }
  264. continue;
  265. }
  266. continue;
  267. }
  268. if (isxdigit (c))
  269. {
  270. *offset = c;
  271. offset++;
  272. digits++;
  273. extent--;
  274. continue;
  275. }
  276. error (1, ENOTSUP, "Illegal hex digit '%c' (0x%02X) in source", c, c);
  277. }
  278. if (digits & 1)
  279. {
  280. error (1, ENOTSUP, "Odd number of hex digits (%d) in source", digits);
  281. }
  282. return (offset - origin);
  283. }
  284. /*====================================================================*
  285. *
  286. * void decode (void const * memory, size_t extent);
  287. *
  288. * serial.h
  289. *
  290. * copy a memory region into command buffer at the current position
  291. * and increment the buffer position pointer; convert bytes to hex
  292. * octets;
  293. *
  294. *--------------------------------------------------------------------*/
  295. void decode (void const * memory, size_t extent)
  296. {
  297. extern struct command command;
  298. register byte * binary = (byte *)(memory);
  299. while ((command.length < sizeof (command.buffer)) && (extent--))
  300. {
  301. insert (DIGITS_HEX [(*binary >> 4) & 0x0F]);
  302. insert (DIGITS_HEX [(*binary >> 0) & 0x0F]);
  303. binary++;
  304. }
  305. return;
  306. }
  307. /*====================================================================*
  308. *
  309. * void encode (void * memory, size_t extent);
  310. *
  311. * serial.h
  312. *
  313. * encode a memory region from the current command buffer position
  314. * and increment the command buffer position pointer;
  315. *
  316. *--------------------------------------------------------------------*/
  317. void encode (void * memory, size_t extent)
  318. {
  319. extern struct command command;
  320. register byte * binary = (byte *)(memory);
  321. unsigned digit;
  322. while ((command.offset < command.length) && (extent--))
  323. {
  324. *binary = 0;
  325. if ((digit = todigit (command.buffer [command.offset++])) > 0x0F)
  326. {
  327. command.buffer [command.offset] = (char)(0);
  328. error (1, EINVAL, "[%s]1", command.buffer);
  329. }
  330. *binary |= digit << 4;
  331. if ((digit = todigit (command.buffer [command.offset++])) > 0x0F)
  332. {
  333. command.buffer [command.offset] = (char)(0);
  334. error (1, EINVAL, "[%s]2", command.buffer);
  335. }
  336. *binary |= digit;
  337. binary++;
  338. }
  339. return;
  340. }
  341. /*====================================================================*
  342. *
  343. * void string (char * string);
  344. *
  345. * serial.h
  346. *
  347. * extract the contents of a quoted string string from the command
  348. * buffer; it assumes that the current char is a quote character;
  349. *
  350. * copy command buffer characters to an external string; start a the
  351. * current buffer position and continue until the buffer exhausts or
  352. * a closing quote is encountered; NUL terminate the string;
  353. *
  354. *--------------------------------------------------------------------*/
  355. void string (char * string)
  356. {
  357. extern struct command command;
  358. while ((command.offset < command.length) && (command.buffer [command.offset] != '\"'))
  359. {
  360. *string++ = command.buffer [command.offset++];
  361. }
  362. *string = (char)(0);
  363. return;
  364. }
  365. /*====================================================================*
  366. *
  367. * uint64_t hextoint (unsigned bytes);
  368. *
  369. * serial.h
  370. *
  371. * this function is used to extract a hexadecimal integer string as
  372. * an integer of specified length; an error occurs of the string is
  373. * to long for the specified integer size in bytes;
  374. *
  375. *--------------------------------------------------------------------*/
  376. uint64_t hextoint (unsigned bytes)
  377. {
  378. extern struct command command;
  379. uint64_t limit = -1;
  380. uint64_t value = 0;
  381. unsigned radix = 16;
  382. unsigned digit = 0;
  383. if (bytes < sizeof (limit))
  384. {
  385. limit <<= (bytes << 3);
  386. limit = ~limit;
  387. }
  388. while ((digit = todigit (command.buffer [command.offset])) < radix)
  389. {
  390. value *= radix;
  391. value += digit;
  392. command.offset++;
  393. if (value > limit)
  394. {
  395. command.buffer [command.offset] = (char)(0);
  396. error (1, EINVAL, "[%s] exceeds %d bits", command.buffer, (bytes << 3));
  397. }
  398. }
  399. return (value);
  400. }
  401. /*====================================================================*
  402. *
  403. * void mustbe (char c);
  404. *
  405. * serial.h
  406. *
  407. * test the character at the current buffer position; advance the
  408. * buffer position pointer and return true on match; terminate the
  409. * program on mismatch or exhausted buffer;
  410. *
  411. *--------------------------------------------------------------------*/
  412. void mustbe (char c)
  413. {
  414. extern struct command command;
  415. if (command.offset >= command.length)
  416. {
  417. command.buffer [command.offset] = (char)(0);
  418. error (1, EINVAL, "[%s]: overflow", command.buffer);
  419. }
  420. if (command.buffer [command.offset++] != (c))
  421. {
  422. command.buffer [command.offset] = (char)(0);
  423. error (1, EINVAL, "[%s]: expecting 0x%02X", command.buffer, c);
  424. }
  425. return;
  426. }
  427. /*====================================================================*
  428. *
  429. *--------------------------------------------------------------------*/
  430. #endif