You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

252 lines
6.3 KiB

  1. #include <stdio.h> /* Standard input/output definitions */
  2. #include <stdlib.h>
  3. #include <stdint.h> /* Standard types */
  4. #include <string.h> /* String function definitions */
  5. #include <unistd.h> /* UNIX standard function definitions */
  6. #include <fcntl.h> /* File control definitions */
  7. #include <errno.h> /* Error number definitions */
  8. #include <termios.h> /* POSIX terminal control definitions */
  9. #include <sys/ioctl.h>
  10. #ifdef __APPLE__
  11. // define 460k baud rate, seems not to be available in headers on osx
  12. #define B460800 460800
  13. #endif
  14. void help(void);
  15. int serialport_init(const char* serialport, unsigned int baud);
  16. int serialport_read_until(int fd, unsigned int until);
  17. // Checks for an argument (characters with a leading '-')
  18. // Returns 0 if argument does not exist or the index of argument
  19. // type in the argv[] array
  20. int parArgTypExists (int argc, char *argv[], char argType)
  21. {
  22. char tmp[3];
  23. tmp[0] = '-';
  24. tmp[1] = argType;
  25. tmp[2] = 0;
  26. if (argc > 1) {
  27. for (int i = 1; i < argc; i++) {
  28. if (!strcmp (argv[i], tmp))
  29. return i;
  30. }
  31. }
  32. return 0;
  33. }
  34. // Get string argument value
  35. // Returns 0 in error case, returns 1 if OK
  36. // (string is limited to max. 4096 characters)
  37. int parGetString (int argc, char *argv[], char argType, char *value)
  38. {
  39. int a = parArgTypExists(argc, argv, argType);
  40. // Check for errors
  41. if (a == 0) return 0;
  42. if (a >= (argc -1)) return 0;
  43. if (strlen(argv[a+1]) > 256) return 0;
  44. strcpy(value, argv[a+1]);
  45. return 1;
  46. }
  47. // Get unsigned int argument value
  48. // Returns 0 in error case, 1 if OK
  49. int parGetUnsignedInt (int argc, char *argv[], char argType,
  50. unsigned int *value)
  51. {
  52. int a = parArgTypExists (argc, argv, argType);
  53. /* error checking */
  54. if (a == 0) return 0;
  55. if (a >= (argc -1)) return 0;
  56. a = sscanf(argv[a+1], "%iu", value);
  57. return a;
  58. }
  59. void help(void) {
  60. printf("Usage: uart_trng -p <serialport> [OPTIONS]\n"
  61. "\n"
  62. "Options:\n"
  63. " -h, --help Print this help message\n"
  64. " -p, --port=serialport Serial port where the uart_trng device is plugged on\n"
  65. " -b, --baud=baudrate Baudrate (bps) of uart_trng device, default = 9600\n"
  66. " -s, --size number of bytes to receive from uart_trng device,\n"
  67. " 0 for reading until break with Ctrl-c, default = 1024\n"
  68. "\n");
  69. }
  70. int main(int argc, char *argv[])
  71. {
  72. int fd = 0;
  73. int r = 0;
  74. char serialport[256];
  75. unsigned int baudrate = 9600;
  76. unsigned int size = 1024;
  77. // check for command line arguments
  78. if (argc == 1) {
  79. help();
  80. return 1;
  81. }
  82. else {
  83. if (parArgTypExists (argc, argv, 'h')) {
  84. help();
  85. return 1;
  86. }
  87. // get serial port
  88. if (parArgTypExists (argc, argv, 'p')) {
  89. r = parGetString (argc, argv, 'p', serialport);
  90. if (r == 0) {
  91. return (1);
  92. }
  93. } else {
  94. help();
  95. return (1);
  96. }
  97. // get baud rate
  98. if (parArgTypExists (argc, argv, 'b')) {
  99. r = parGetUnsignedInt (argc, argv, 'b', &baudrate);
  100. if (r == 0) {
  101. return (1);
  102. }
  103. }
  104. // get read size in bytes
  105. if (parArgTypExists (argc, argv, 's')) {
  106. r = parGetUnsignedInt (argc, argv, 's', &size);
  107. if (r == 0) {
  108. return (1);
  109. }
  110. }
  111. }
  112. fd = serialport_init(serialport, baudrate);
  113. if (fd == -1)
  114. return -1;
  115. serialport_read_until(fd, size);
  116. exit(EXIT_SUCCESS);
  117. }
  118. int serialport_read_until(int fd, unsigned int until)
  119. {
  120. char b[1];
  121. int index = 0;
  122. int n;
  123. while (1) {
  124. while (1) {
  125. // read one char
  126. n = read(fd, b, 1);
  127. // we had a read error
  128. // check if there were no bytes to read or if it was a real error
  129. if (n == -1) {
  130. if (errno != EAGAIN) {
  131. fprintf(stderr,"serial read error at byte %d", index);
  132. return -1;
  133. }
  134. } else {
  135. break;
  136. }
  137. }
  138. // we got no byte, so wait 10 ms for the next try
  139. if (n == 0) {
  140. usleep (10 * 1000);
  141. continue;
  142. }
  143. printf("%c",b[0]);
  144. if (until == 0) {
  145. continue;
  146. } else {
  147. index++;
  148. if (index == until) {
  149. break;
  150. }
  151. }
  152. };
  153. fprintf(stderr,"uart_trng: read %d random bytes from device\n", until);
  154. return 0;
  155. }
  156. // takes the string name of the serial port (e.g. "/dev/tty.usbserial","COM1")
  157. // and a baud rate (bps) and connects to that port at that speed and 8N1.
  158. // opens the port in fully raw mode so you can send binary data.
  159. // returns valid fd, or -1 on error
  160. int serialport_init(const char* serialport, unsigned int baud)
  161. {
  162. struct termios toptions;
  163. int fd;
  164. fprintf(stderr,"init_serialport: opening port %s @ %u bps\n",
  165. serialport, baud);
  166. fd = open(serialport, O_RDWR | O_NOCTTY | O_NDELAY);
  167. if (fd == -1) {
  168. perror("init_serialport: Unable to open port ");
  169. return -1;
  170. }
  171. if (tcgetattr(fd, &toptions) < 0) {
  172. perror("init_serialport: Couldn't get term attributes");
  173. return -1;
  174. }
  175. speed_t brate = baud; // let you override switch below if needed
  176. switch(baud) {
  177. case 4800: brate=B4800; break;
  178. case 9600: brate=B9600; break;
  179. #ifdef B14400
  180. case 14400: brate=B14400; break;
  181. #endif
  182. case 19200: brate=B19200; break;
  183. #ifdef B28800
  184. case 28800: brate=B28800; break;
  185. #endif
  186. case 38400: brate=B38400; break;
  187. case 57600: brate=B57600; break;
  188. case 115200: brate=B115200; break;
  189. case 230400: brate=B230400; break;
  190. case 460800: brate=B460800; break;
  191. }
  192. cfsetispeed(&toptions, brate);
  193. cfsetospeed(&toptions, brate);
  194. // 8N1
  195. toptions.c_cflag &= ~PARENB;
  196. toptions.c_cflag &= ~CSTOPB;
  197. toptions.c_cflag &= ~CSIZE;
  198. toptions.c_cflag |= CS8;
  199. // no flow control
  200. toptions.c_cflag &= ~CRTSCTS;
  201. toptions.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
  202. toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
  203. toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
  204. toptions.c_oflag &= ~OPOST; // make raw
  205. // see: http://unixwiz.net/techtips/termios-vmin-vtime.html
  206. toptions.c_cc[VMIN] = 0;
  207. toptions.c_cc[VTIME] = 20;
  208. if( tcsetattr(fd, TCSANOW, &toptions) < 0) {
  209. perror("init_serialport: Couldn't set term attributes");
  210. return -1;
  211. }
  212. return fd;
  213. }