| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- /**
- * Serial Port Loopback Test Program
- *
- * Function: Send and receive concurrently, exit immediately on successful receive
- *
- * Compile: gcc -std=gnu99 -o hs_serial hs_serial.c -lpthread
- * Run: ./hs_serial [/dev/ttyUSB0] [baudrate]
- */
- #define _POSIX_C_SOURCE 200809L
- #define _DEFAULT_SOURCE
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <termios.h>
- #include <errno.h>
- #include <signal.h>
- #include <sys/select.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <sys/ioctl.h>
- #include <pthread.h>
- #include <time.h>
- #include <ctype.h>
- #define BUF_SIZE 4096
- #define DEFAULT_BAUD 115200
- #define DEFAULT_PORT "/dev/ttyUSB0"
- typedef struct {
- int fd;
- char port[64];
- int baud_rate;
- int data_bits;
- int stop_bits;
- char parity;
- volatile int received; // flag: data received
- volatile int running; // flag: keep running
- } serial_port_t;
- static serial_port_t g_serial;
- static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- void signal_handler(int sig) {
- (void)sig;
- g_serial.running = 0;
- }
- void setup_signal_handler(void) {
- struct sigaction sa;
- sa.sa_handler = signal_handler;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = 0;
- sigaction(SIGINT, &sa, NULL);
- sigaction(SIGTERM, &sa, NULL);
- }
- speed_t get_baud_rate(int baud) {
- switch(baud) {
- case 50: return B50; case 75: return B75; case 110: return B110;
- case 134: return B134; case 150: return B150; case 200: return B200;
- case 300: return B300; case 600: return B600; case 1200: return B1200;
- case 1800: return B1800; case 2400: return B2400; case 4800: return B4800;
- case 9600: return B9600; case 19200: return B19200; case 38400: return B38400;
- case 57600: return B57600; case 115200: return B115200; case 230400: return B230400;
- case 460800: return B460800; case 500000: return B500000; case 576000: return B576000;
- case 921600: return B921600; case 1000000: return B1000000; case 1152000: return B1152000;
- case 1500000: return B1500000; case 2000000: return B2000000; case 2500000: return B2500000;
- case 3000000: return B3000000; case 3500000: return B3500000; case 4000000: return B4000000;
- default: return B115200;
- }
- }
- int serial_open(serial_port_t *serial) {
- struct termios options;
-
- serial->fd = open(serial->port, O_RDWR | O_NOCTTY | O_NDELAY);
- if (serial->fd == -1) {
- perror("Failed to open serial port");
- return -1;
- }
-
- fcntl(serial->fd, F_SETFL, 0);
-
- if (tcgetattr(serial->fd, &options) != 0) {
- perror("Failed to get serial config");
- close(serial->fd);
- return -1;
- }
-
- cfsetispeed(&options, get_baud_rate(serial->baud_rate));
- cfsetospeed(&options, get_baud_rate(serial->baud_rate));
-
- options.c_cflag |= CLOCAL | CREAD;
- options.c_cflag &= ~CSIZE;
- switch(serial->data_bits) {
- case 5: options.c_cflag |= CS5; break;
- case 6: options.c_cflag |= CS6; break;
- case 7: options.c_cflag |= CS7; break;
- default: options.c_cflag |= CS8; break;
- }
-
- if (serial->stop_bits == 2)
- options.c_cflag |= CSTOPB;
- else
- options.c_cflag &= ~CSTOPB;
-
- switch(serial->parity) {
- case 'N': options.c_cflag &= ~PARENB; options.c_iflag &= ~INPCK; break;
- case 'E': options.c_cflag |= PARENB; options.c_cflag &= ~PARODD; options.c_iflag |= INPCK; break;
- case 'O': options.c_cflag |= PARENB; options.c_cflag |= PARODD; options.c_iflag |= INPCK; break;
- default: options.c_cflag &= ~PARENB; options.c_iflag &= ~INPCK; break;
- }
-
- options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
- options.c_oflag &= ~OPOST;
- options.c_cc[VMIN] = 0;
- options.c_cc[VTIME] = 10;
-
- tcflush(serial->fd, TCIOFLUSH);
-
- if (tcsetattr(serial->fd, TCSANOW, &options) != 0) {
- perror("Failed to set serial config");
- close(serial->fd);
- return -1;
- }
-
- return 0;
- }
- void serial_close(serial_port_t *serial) {
- if (serial->fd > 0) {
- close(serial->fd);
- serial->fd = -1;
- }
- }
- int serial_write(serial_port_t *serial, const char *data, int length) {
- int bytes_written = 0;
- int ret;
-
- if (serial->fd < 0) return -1;
-
- while (bytes_written < length) {
- ret = write(serial->fd, data + bytes_written, length - bytes_written);
- if (ret < 0) {
- if (errno == EAGAIN) {
- usleep(1000);
- continue;
- }
- return -1;
- }
- bytes_written += ret;
- }
-
- return bytes_written;
- }
- // ========== Send Thread ==========
- void *send_thread(void *arg) {
- serial_port_t *serial = (serial_port_t *)arg;
- char buffer[BUF_SIZE];
- time_t now;
- time_t start_time = time(NULL); // 记录开始时间
- printf("[Send Thread] Started\n");
- while (serial->running) {
- // 判断是否超过5秒
- if (time(NULL) - start_time >= 2) {
- printf("[Send] 5 seconds reached, exit loop\n");
- break;
- }
- pthread_mutex_lock(&mutex);
- if (!serial->running) {
- pthread_mutex_unlock(&mutex);
- break;
- }
- now = time(NULL);
- int len = snprintf(buffer, BUF_SIZE,
- "%ld Serial Loopback Test\n",
- (long)now);
- printf("[Send] Sending %d bytes...\n", len);
- int ret = serial_write(serial, buffer, len);
- if (ret > 0) {
- printf("[Send] Sent %d bytes successfully\n", ret);
- } else {
- printf("[Send] Send failed\n");
- }
- pthread_mutex_unlock(&mutex);
- usleep(500000); // 500ms
- }
- printf("[Send Thread] Exited\n");
- return NULL;
- }
- // ========== Receive Thread ==========
- void *receive_thread(void *arg) {
- serial_port_t *serial = (serial_port_t *)arg;
- char buffer[BUF_SIZE];
- time_t start_time = time(NULL); // 开始时间
- printf("[Receive Thread] Started\n");
- while (serial->running) {
- // 5秒超时判断
- if (time(NULL) - start_time >= 2) {
- printf("[Receive] FAILED: No data received within 5 seconds\n");
- serial->running = 0;
- break;
- }
- fd_set read_fds;
- struct timeval timeout;
- FD_ZERO(&read_fds);
- FD_SET(serial->fd, &read_fds);
- timeout.tv_sec = 1;
- timeout.tv_usec = 0;
- int ret = select(serial->fd + 1, &read_fds, NULL, NULL, &timeout);
- if (ret > 0 && FD_ISSET(serial->fd, &read_fds)) {
- ret = read(serial->fd, buffer, BUF_SIZE - 1);
- if (ret > 0) {
- buffer[ret] = '\0';
- printf("[Receive] Received %d bytes: %s\n", ret, buffer);
- printf("SUCCESSFUL PASSED - Data received\n");
- serial->running = 0;
- break;
- }
- }
- }
- printf("[Receive Thread] Exited\n");
- return NULL;
- }
- // ========== Main ==========
- int main(int argc, char *argv[]) {
- pthread_t send_tid, recv_tid;
-
- printf("========== Serial Loopback Test ==========\n\n");
-
- // Default settings
- strncpy(g_serial.port, DEFAULT_PORT, sizeof(g_serial.port) - 1);
- g_serial.baud_rate = DEFAULT_BAUD;
- g_serial.data_bits = 8;
- g_serial.stop_bits = 1;
- g_serial.parity = 'N';
- g_serial.fd = -1;
- g_serial.received = 0;
- g_serial.running = 1;
-
- // Parse arguments
- if (argc > 1) strncpy(g_serial.port, argv[1], sizeof(g_serial.port) - 1);
- if (argc > 2) g_serial.baud_rate = atoi(argv[2]);
-
- printf("Serial Port: %s\n", g_serial.port);
- printf("Baud Rate: %d\n", g_serial.baud_rate);
- printf("===========================================\n\n");
-
- setup_signal_handler();
-
- // Open serial port
- if (serial_open(&g_serial) != 0) {
- fprintf(stderr, "Cannot open serial port %s\n", g_serial.port);
- return EXIT_FAILURE;
- }
-
- printf("Serial port opened successfully!\n");
- printf("Note: Please ensure TX/RX pins are connected for loopback test\n\n");
-
- // Create send thread
- if (pthread_create(&send_tid, NULL, send_thread, &g_serial) != 0) {
- perror("Failed to create send thread");
- serial_close(&g_serial);
- return EXIT_FAILURE;
- }
-
- // Create receive thread
- if (pthread_create(&recv_tid, NULL, receive_thread, &g_serial) != 0) {
- perror("Failed to create receive thread");
- g_serial.running = 0;
- pthread_join(send_tid, NULL);
- serial_close(&g_serial);
- return EXIT_FAILURE;
- }
-
- // Wait for threads to finish
- pthread_join(send_tid, NULL);
- pthread_join(recv_tid, NULL);
-
- // Close serial port
- serial_close(&g_serial);
-
- printf("========== Test Finished ==========\n");
-
- return EXIT_SUCCESS;
- }
|