hs_serial.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. /**
  2. * Serial Port Loopback Test Program
  3. *
  4. * Function: Send and receive concurrently, exit immediately on successful receive
  5. *
  6. * Compile: gcc -std=gnu99 -o hs_serial hs_serial.c -lpthread
  7. * Run: ./hs_serial [/dev/ttyUSB0] [baudrate]
  8. */
  9. #define _POSIX_C_SOURCE 200809L
  10. #define _DEFAULT_SOURCE
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <unistd.h>
  15. #include <fcntl.h>
  16. #include <termios.h>
  17. #include <errno.h>
  18. #include <signal.h>
  19. #include <sys/select.h>
  20. #include <sys/time.h>
  21. #include <sys/types.h>
  22. #include <sys/ioctl.h>
  23. #include <pthread.h>
  24. #include <time.h>
  25. #include <ctype.h>
  26. #define BUF_SIZE 4096
  27. #define DEFAULT_BAUD 115200
  28. #define DEFAULT_PORT "/dev/ttyUSB0"
  29. typedef struct {
  30. int fd;
  31. char port[64];
  32. int baud_rate;
  33. int data_bits;
  34. int stop_bits;
  35. char parity;
  36. volatile int received; // flag: data received
  37. volatile int running; // flag: keep running
  38. } serial_port_t;
  39. static serial_port_t g_serial;
  40. static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  41. void signal_handler(int sig) {
  42. (void)sig;
  43. g_serial.running = 0;
  44. }
  45. void setup_signal_handler(void) {
  46. struct sigaction sa;
  47. sa.sa_handler = signal_handler;
  48. sigemptyset(&sa.sa_mask);
  49. sa.sa_flags = 0;
  50. sigaction(SIGINT, &sa, NULL);
  51. sigaction(SIGTERM, &sa, NULL);
  52. }
  53. speed_t get_baud_rate(int baud) {
  54. switch(baud) {
  55. case 50: return B50; case 75: return B75; case 110: return B110;
  56. case 134: return B134; case 150: return B150; case 200: return B200;
  57. case 300: return B300; case 600: return B600; case 1200: return B1200;
  58. case 1800: return B1800; case 2400: return B2400; case 4800: return B4800;
  59. case 9600: return B9600; case 19200: return B19200; case 38400: return B38400;
  60. case 57600: return B57600; case 115200: return B115200; case 230400: return B230400;
  61. case 460800: return B460800; case 500000: return B500000; case 576000: return B576000;
  62. case 921600: return B921600; case 1000000: return B1000000; case 1152000: return B1152000;
  63. case 1500000: return B1500000; case 2000000: return B2000000; case 2500000: return B2500000;
  64. case 3000000: return B3000000; case 3500000: return B3500000; case 4000000: return B4000000;
  65. default: return B115200;
  66. }
  67. }
  68. int serial_open(serial_port_t *serial) {
  69. struct termios options;
  70. serial->fd = open(serial->port, O_RDWR | O_NOCTTY | O_NDELAY);
  71. if (serial->fd == -1) {
  72. perror("Failed to open serial port");
  73. return -1;
  74. }
  75. fcntl(serial->fd, F_SETFL, 0);
  76. if (tcgetattr(serial->fd, &options) != 0) {
  77. perror("Failed to get serial config");
  78. close(serial->fd);
  79. return -1;
  80. }
  81. cfsetispeed(&options, get_baud_rate(serial->baud_rate));
  82. cfsetospeed(&options, get_baud_rate(serial->baud_rate));
  83. options.c_cflag |= CLOCAL | CREAD;
  84. options.c_cflag &= ~CSIZE;
  85. switch(serial->data_bits) {
  86. case 5: options.c_cflag |= CS5; break;
  87. case 6: options.c_cflag |= CS6; break;
  88. case 7: options.c_cflag |= CS7; break;
  89. default: options.c_cflag |= CS8; break;
  90. }
  91. if (serial->stop_bits == 2)
  92. options.c_cflag |= CSTOPB;
  93. else
  94. options.c_cflag &= ~CSTOPB;
  95. switch(serial->parity) {
  96. case 'N': options.c_cflag &= ~PARENB; options.c_iflag &= ~INPCK; break;
  97. case 'E': options.c_cflag |= PARENB; options.c_cflag &= ~PARODD; options.c_iflag |= INPCK; break;
  98. case 'O': options.c_cflag |= PARENB; options.c_cflag |= PARODD; options.c_iflag |= INPCK; break;
  99. default: options.c_cflag &= ~PARENB; options.c_iflag &= ~INPCK; break;
  100. }
  101. options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
  102. options.c_oflag &= ~OPOST;
  103. options.c_cc[VMIN] = 0;
  104. options.c_cc[VTIME] = 10;
  105. tcflush(serial->fd, TCIOFLUSH);
  106. if (tcsetattr(serial->fd, TCSANOW, &options) != 0) {
  107. perror("Failed to set serial config");
  108. close(serial->fd);
  109. return -1;
  110. }
  111. return 0;
  112. }
  113. void serial_close(serial_port_t *serial) {
  114. if (serial->fd > 0) {
  115. close(serial->fd);
  116. serial->fd = -1;
  117. }
  118. }
  119. int serial_write(serial_port_t *serial, const char *data, int length) {
  120. int bytes_written = 0;
  121. int ret;
  122. if (serial->fd < 0) return -1;
  123. while (bytes_written < length) {
  124. ret = write(serial->fd, data + bytes_written, length - bytes_written);
  125. if (ret < 0) {
  126. if (errno == EAGAIN) {
  127. usleep(1000);
  128. continue;
  129. }
  130. return -1;
  131. }
  132. bytes_written += ret;
  133. }
  134. return bytes_written;
  135. }
  136. // ========== Send Thread ==========
  137. void *send_thread(void *arg) {
  138. serial_port_t *serial = (serial_port_t *)arg;
  139. char buffer[BUF_SIZE];
  140. time_t now;
  141. time_t start_time = time(NULL); // 记录开始时间
  142. printf("[Send Thread] Started\n");
  143. while (serial->running) {
  144. // 判断是否超过5秒
  145. if (time(NULL) - start_time >= 2) {
  146. printf("[Send] 5 seconds reached, exit loop\n");
  147. break;
  148. }
  149. pthread_mutex_lock(&mutex);
  150. if (!serial->running) {
  151. pthread_mutex_unlock(&mutex);
  152. break;
  153. }
  154. now = time(NULL);
  155. int len = snprintf(buffer, BUF_SIZE,
  156. "%ld Serial Loopback Test\n",
  157. (long)now);
  158. printf("[Send] Sending %d bytes...\n", len);
  159. int ret = serial_write(serial, buffer, len);
  160. if (ret > 0) {
  161. printf("[Send] Sent %d bytes successfully\n", ret);
  162. } else {
  163. printf("[Send] Send failed\n");
  164. }
  165. pthread_mutex_unlock(&mutex);
  166. usleep(500000); // 500ms
  167. }
  168. printf("[Send Thread] Exited\n");
  169. return NULL;
  170. }
  171. // ========== Receive Thread ==========
  172. void *receive_thread(void *arg) {
  173. serial_port_t *serial = (serial_port_t *)arg;
  174. char buffer[BUF_SIZE];
  175. time_t start_time = time(NULL); // 开始时间
  176. printf("[Receive Thread] Started\n");
  177. while (serial->running) {
  178. // 5秒超时判断
  179. if (time(NULL) - start_time >= 2) {
  180. printf("[Receive] FAILED: No data received within 5 seconds\n");
  181. serial->running = 0;
  182. break;
  183. }
  184. fd_set read_fds;
  185. struct timeval timeout;
  186. FD_ZERO(&read_fds);
  187. FD_SET(serial->fd, &read_fds);
  188. timeout.tv_sec = 1;
  189. timeout.tv_usec = 0;
  190. int ret = select(serial->fd + 1, &read_fds, NULL, NULL, &timeout);
  191. if (ret > 0 && FD_ISSET(serial->fd, &read_fds)) {
  192. ret = read(serial->fd, buffer, BUF_SIZE - 1);
  193. if (ret > 0) {
  194. buffer[ret] = '\0';
  195. printf("[Receive] Received %d bytes: %s\n", ret, buffer);
  196. printf("SUCCESSFUL PASSED - Data received\n");
  197. serial->running = 0;
  198. break;
  199. }
  200. }
  201. }
  202. printf("[Receive Thread] Exited\n");
  203. return NULL;
  204. }
  205. // ========== Main ==========
  206. int main(int argc, char *argv[]) {
  207. pthread_t send_tid, recv_tid;
  208. printf("========== Serial Loopback Test ==========\n\n");
  209. // Default settings
  210. strncpy(g_serial.port, DEFAULT_PORT, sizeof(g_serial.port) - 1);
  211. g_serial.baud_rate = DEFAULT_BAUD;
  212. g_serial.data_bits = 8;
  213. g_serial.stop_bits = 1;
  214. g_serial.parity = 'N';
  215. g_serial.fd = -1;
  216. g_serial.received = 0;
  217. g_serial.running = 1;
  218. // Parse arguments
  219. if (argc > 1) strncpy(g_serial.port, argv[1], sizeof(g_serial.port) - 1);
  220. if (argc > 2) g_serial.baud_rate = atoi(argv[2]);
  221. printf("Serial Port: %s\n", g_serial.port);
  222. printf("Baud Rate: %d\n", g_serial.baud_rate);
  223. printf("===========================================\n\n");
  224. setup_signal_handler();
  225. // Open serial port
  226. if (serial_open(&g_serial) != 0) {
  227. fprintf(stderr, "Cannot open serial port %s\n", g_serial.port);
  228. return EXIT_FAILURE;
  229. }
  230. printf("Serial port opened successfully!\n");
  231. printf("Note: Please ensure TX/RX pins are connected for loopback test\n\n");
  232. // Create send thread
  233. if (pthread_create(&send_tid, NULL, send_thread, &g_serial) != 0) {
  234. perror("Failed to create send thread");
  235. serial_close(&g_serial);
  236. return EXIT_FAILURE;
  237. }
  238. // Create receive thread
  239. if (pthread_create(&recv_tid, NULL, receive_thread, &g_serial) != 0) {
  240. perror("Failed to create receive thread");
  241. g_serial.running = 0;
  242. pthread_join(send_tid, NULL);
  243. serial_close(&g_serial);
  244. return EXIT_FAILURE;
  245. }
  246. // Wait for threads to finish
  247. pthread_join(send_tid, NULL);
  248. pthread_join(recv_tid, NULL);
  249. // Close serial port
  250. serial_close(&g_serial);
  251. printf("========== Test Finished ==========\n");
  252. return EXIT_SUCCESS;
  253. }