gpt4 book ai didi

c - 串口环回/双工测试,用 Bash 还是 C? (过程替换)

转载 作者:IT王子 更新时间:2023-10-29 00:20:15 24 4
gpt4 key购买 nike

我有一个设置为环回的串行设备(意味着它只会回显它接收到的任何字符),我想测量有效的吞吐量速度。为此,我希望我可以使用 time ,如

time bash -c '...'

其中“ ... ”将是我可以运行的一些命令。

现在,第一个问题是我想以 2000000 bps 使用设备,所以我不能使用 ttylogscreen(它们似乎都只能达到 115200 bps)。但是,将 /dev/ttyUSB0 作为文件使用(使用文件重定向和 cat )似乎工作正常:
# initialize serial port
stty 2000000 -ixon icanon </dev/ttyUSB0

# check settings
stty -a -F /dev/ttyUSB0

# in one terminal - read from serial port
while (true) do cat -A /dev/ttyUSB0 ; done

# in other terminal - write to serial port
echo "1234567890" > /dev/ttyUSB0

# back to first terminal, I now have:
# $ while (true) do cat -A /dev/ttyUSB0 ; done
# 1234567890$
# ...

现在,我想做一些类似的事情——我想将一个文件 cat 编码到串行端口,并让串行端口读回——但是来自一个终端命令(所以我可以将它用作 time 的参数)。

我想我可以使用 Bash 进程替换,让“写作”和“阅读”部分在“并行”中进行——如果我尝试使用命名管道,它会起作用:
# mkfifo my.pipe # same as below:
$ mknod my.pipe p

$ comm <(echo -e "test\ntest\ntest\n" > my.pipe) <(cat my.pipe)
test
test
test
comm: file 2 is not in sorted order

在那里,我没有将 comm 用于任何其他目的,而不是(某种程度上)将两个进程合并为一个命令(我想,我也可以使用 echo 代替)。

不幸的是,这个技巧似乎不适用于串行端口,因为当我尝试它时,我有时会得到:
$ comm <(echo "1234567890" > /dev/ttyUSB0) <(while (true) do cat -A /dev/ttyUSB0 ; done)
cat: /dev/ttyUSB0: Invalid argument

...,但是,通常我只是没有得到任何输出。这告诉我:要么无法控制哪个进程首先启动,因此 cat 可能会在端口准备好之前开始读取(但是,在上面的第一个示例中,这似乎不是问题);或者在 Linux/Bash 中,您不能同时读取和写入串行端口,因此在读取和写入似乎同时发生的那些时刻会出现“ Invalid argument”。

所以我的问题是:
  • 有没有办法只在 Bash 中执行这样的操作(cat 将文件配置为环回的串行端口;读回它并查看需要多长时间),而无需编写专用的 C 程序?
  • 如果我需要一个专用的 C 程序,网上有没有我可以使用的源代码示例?

  • 非常感谢您的任何回复,

    干杯!

    编辑:我知道上面写的 while 循环没有退出;该命令行用于初步测试,我使用 Ctrl-C 中断它。 (原则上我可以用 timeout -9 0.1 bash -c 'while (true) do echo AA ; done' 之类的东西中断它,但这会破坏 time 的目的,然后:))
    while 存在的原因,暂时是通过 cat 从设备读取立即退出;有时,我已经设置了设备,以便在发出 cat 时,它​​实际上会阻塞并等待传入​​的数据;但我还不能弄清楚发生了什么(部分原因是我正在寻找一种从命令行进行测试的方法)。

    如果我没有使用 while ,我想为计时,我会使用类似的东西:
    time bash -c 'comm <(echo "1234567890" > /dev/ttyUSB0) <(cat -A /dev/ttyUSB0)'
    ...然而,为了使其正常工作,假设 cat -A /dev/ttyUSB0 首先启动并阻塞;然后 echo 写入串行端口(并退出);然后 cat -A 输出它从串行端口读取的任何内容 - 然后退出。 (而且我不确定串行端口是否可以完全以这种方式运行,也不确定 cat 是否可以像那样任意阻塞和退出)。

    确切的方法真的无关紧要;如果可能的话,我只想避免编写自己的 C 程序来进行这种测试 - 这就是为什么我的主要兴趣是是否可以使用基本的 Bash/以某种方式运行这样的“全双工测试” Linux(即 coreutils ); (如果没有,如果有现成的代码,我可以用于这样的事情)。

    EDIT2:也可能相关:
  • Parallel processes in Bash - Ubuntu Forums
  • 最佳答案

    好吧,这有点像部分答案 - 尽管有关 bash 使用的问题仍然存在。我试图查看一些 C 代码解决方案——这似乎也不是微不足道的! :)

    首先,让我们看看可能是什么没有 适用于这种情况 - 以下是来自“between write and read:serial port. - C”的示例:

    // from: between write and read:serial port. - C - http://www.daniweb.com/forums/thread286634.html
    // gcc -o sertest -Wall -g sertest.c

    #include <stdio.h>
    #include <sys/types.h>
    #include <string.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <termios.h>

    int main(int argc, char *argv[])
    {
    char line[1024];
    int chkin;
    char input[1024];
    char msg[1024];
    char serport[24];

    // argv[1] - serial port
    // argv[2] - file or echo

    sprintf(serport, "%s", argv[1]);

    int file= open(serport, O_RDWR | O_NOCTTY | O_NDELAY);

    if (file == 0)
    {
    sprintf(msg, "open_port: Unable to open %s.\n", serport);
    perror(msg);
    }
    else
    fcntl(file, F_SETFL, FNDELAY); //fcntl(file, F_SETFL, 0);

    while (1)
    {

    printf("enter input data:\n");
    scanf("%s",&input[0]);

    chkin=write(file,input,sizeof input);

    if (chkin<0)
    {
    printf("cannot write to port\n");
    }

    //chkin=read(file,line,sizeof line);

    while ((chkin=read(file,line,sizeof line))>=0)
    {
    if (chkin<0)
    {
    printf("cannot read from port\n");
    }
    else
    {
    printf("bytes: %d, line=%s\n",chkin, line);
    }
    }

    /*CODE TO EXIT THE LOOP GOES HERE*/
    if (input[0] == 'q') break;
    }

    close(file);
    return 0;
    }

    上面代码的问题在于它没有为字符(“原始”)操作显式初始化串行端口;因此,根据之前端口的设置方式, session 可能如下所示:
    $ ./sertest /dev/ttyUSB0 
    enter input data:
    t1
    enter input data:
    t2
    enter input data:
    t3
    enter input data:
    ^C

    ... 换句话说,没有输入数据的 echo 。但是,如果串口设置正确,我们可以得到一个像这样的 session :
    $ ./sertest /dev/ttyUSB0 
    enter input data:
    t1
    enter input data:
    t2
    bytes: 127, line=t1
    enter input data:
    t3
    bytes: 127, line=t2
    enter input data:
    t4
    bytes: 127, line=t3
    enter input data:
    ^C

    ...(但即便如此,这个 sertest 代码在输入大于 3 个字符的单词时失败。)

    最后,通过一些网上的挖掘,我设法找到了“ (SOLVED) Serial Programming, Write-Read Issue”,它提供了一个 writeread.cpp例子。然而,对于这种逐字节的“双工”情况,这还不够——即“ Serial Programming HOWTO”注释:“规范输入处理......是终端的正常处理模式......这意味着一个read 只会返回一整行输入。默认情况下,一行以 NL (ASCII LF) ...";因此我们必须 明确通过 ICANON 在我们的代码中将串行端口设置为“非规范”(或“原始”)模式(换句话说,仅通过 O_NONBLOCK 设置 open 就是 不够 )——“ 3.2 How can I read single characters from the terminal? - Unix Programming Frequently Asked Questions - 3. Terminal I/O”给出了一个例子。完成后,调用 writeread将“正确”设置 serport 的串行端口示例(上),以及。

    所以我改变了一些 writeread代码回到 C,添加了所需的初始化内容,以及时间测量,发送字符串或文件的可能性,以及额外的输出流(用于将读取的串行数据“管道”到一个单独的文件)。代码如下 writeread.cserial.h ,有了它,我可以在下面的 Bash session 中做类似的事情:
    $ ./writeread /dev/ttyUSB0 2000000 writeread.c 3>myout.txt
    stdalt opened; Alternative file descriptor: 3
    Opening port /dev/ttyUSB0;
    Got speed 2000000 (4107/0x100b);
    Got file/string 'writeread.c'; opened as file (4182).

    +++DONE+++
    Wrote: 4182 bytes; Read: 4182 bytes; Total: 8364 bytes.
    Start: 1284422340 s 443302 us; End: 1284422347 s 786999 us; Delta: 7 s 343697 us.
    2000000 baud for 8N1 is 200000 Bps (bytes/sec).
    Measured: write 569.47 Bps, read 569.47 Bps, total 1138.94 Bps.

    $ diff writeread.c myout.txt

    $ ./writeread /dev/ttyUSB0 2000000 writeread.c 3>/dev/null
    stdalt opened; Alternative file descriptor: 3
    Opening port /dev/ttyUSB0;
    Got speed 2000000 (4107/0x100b);
    Got file/string 'writeread.c'; opened as file (4182).

    +++DONE+++
    Wrote: 4182 bytes; Read: 4182 bytes; Total: 8364 bytes.
    Start: 1284422380 s -461710 us; End: 1284422388 s 342977 us; Delta: 8 s 804687 us.
    2000000 baud for 8N1 is 200000 Bps (bytes/sec).
    Measured: write 474.97 Bps, read 474.97 Bps, total 949.95 Bps.

    好:
  • 第一个惊喜 - 如果我正在写入文件,它会比我通过管道发送到 /dev/null 的速度更快!
  • 此外,获得大约 1000 BPS - 而该设备显然设置为 200000 BPS!

  • 在这一点上,我认为减速是因为在 writeread.c 中的每个写入字节之后,在我们继续读取串行缓冲区之前,我们等待读取中断清除标志。可能,如果读取和写入是单独的线程,那么读取和写入都可以尝试在单个 read 中使用更大的字节 block 。或 write通话,因此带宽会更好地使用?! (或者,也许中断处理程序在某种意义上确实像一个并行运行的“线程”一样 - 所以也许可以通过将所有与读取相关的函数移动到中断处理程序来实现类似的事情?!)

    嗯 - 在这一点上,我非常愿意接受现有代码的建议/链接,例如 writeread.c , 但多线程 :) 当然,对于任何其他可能的 Linux 工具,或者可能的 Bash 方法(尽管 Bash 似乎无法施加这种控制......)

    干杯!

    writeread.c :
    /*
    writeread.c - based on writeread.cpp
    [SOLVED] Serial Programming, Write-Read Issue - http://www.linuxquestions.org/questions/programming-9/serial-programming-write-read-issue-822980/

    build with: gcc -o writeread -Wall -g writeread.c
    */

    #include <stdio.h>
    #include <string.h>
    #include <stddef.h>

    #include <stdlib.h>
    #include <sys/time.h>

    #include "serial.h"


    int serport_fd;

    void usage(char **argv)
    {
    fprintf(stdout, "Usage:\n");
    fprintf(stdout, "%s port baudrate file/string\n", argv[0]);
    fprintf(stdout, "Examples:\n");
    fprintf(stdout, "%s /dev/ttyUSB0 115200 /path/to/somefile.txt\n", argv[0]);
    fprintf(stdout, "%s /dev/ttyUSB0 115200 \"some text test\"\n", argv[0]);
    }


    int main( int argc, char **argv )
    {

    if( argc != 4 ) {
    usage(argv);
    return 1;
    }

    char *serport;
    char *serspeed;
    speed_t serspeed_t;
    char *serfstr;
    int serf_fd; // if < 0, then serfstr is a string
    int bytesToSend;
    int sentBytes;
    char byteToSend[2];
    int readChars;
    int recdBytes, totlBytes;

    char sResp[11];

    struct timeval timeStart, timeEnd, timeDelta;
    float deltasec;

    /* Re: connecting alternative output stream to terminal -
    * http://coding.derkeiler.com/Archive/C_CPP/comp.lang.c/2009-01/msg01616.html
    * send read output to file descriptor 3 if open,
    * else just send to stdout
    */
    FILE *stdalt;
    if(dup2(3, 3) == -1) {
    fprintf(stdout, "stdalt not opened; ");
    stdalt = fopen("/dev/tty", "w");
    } else {
    fprintf(stdout, "stdalt opened; ");
    stdalt = fdopen(3, "w");
    }
    fprintf(stdout, "Alternative file descriptor: %d\n", fileno(stdalt));

    // Get the PORT name
    serport = argv[1];
    fprintf(stdout, "Opening port %s;\n", serport);

    // Get the baudrate
    serspeed = argv[2];
    serspeed_t = string_to_baud(serspeed);
    fprintf(stdout, "Got speed %s (%d/0x%x);\n", serspeed, serspeed_t, serspeed_t);

    //Get file or command;
    serfstr = argv[3];
    serf_fd = open( serfstr, O_RDONLY );
    fprintf(stdout, "Got file/string '%s'; ", serfstr);
    if (serf_fd < 0) {
    bytesToSend = strlen(serfstr);
    fprintf(stdout, "interpreting as string (%d).\n", bytesToSend);
    } else {
    struct stat st;
    stat(serfstr, &st);
    bytesToSend = st.st_size;
    fprintf(stdout, "opened as file (%d).\n", bytesToSend);
    }


    // Open and Initialise port
    serport_fd = open( serport, O_RDWR | O_NOCTTY | O_NONBLOCK );
    if ( serport_fd < 0 ) { perror(serport); return 1; }
    initport( serport_fd, serspeed_t );

    sentBytes = 0; recdBytes = 0;
    byteToSend[0]='x'; byteToSend[1]='\0';
    gettimeofday( &timeStart, NULL );

    // write / read loop - interleaved (i.e. will always write
    // one byte at a time, before 'emptying' the read buffer )
    while ( sentBytes < bytesToSend )
    {
    // read next byte from input...
    if (serf_fd < 0) { //interpreting as string
    byteToSend[0] = serfstr[sentBytes];
    } else { //opened as file
    read( serf_fd, &byteToSend[0], 1 );
    }

    if ( !writeport( serport_fd, byteToSend ) ) {
    fprintf(stdout, "write failed\n");
    }
    //~ fprintf(stdout, "written:%s\n", byteToSend );

    while ( wait_flag == TRUE );

    if ( (readChars = readport( serport_fd, sResp, 10)) >= 0 )
    {
    //~ fprintf(stdout, "InVAL: (%d) %s\n", readChars, sResp);
    recdBytes += readChars;
    fprintf(stdalt, "%s", sResp);
    }

    wait_flag = TRUE; // was ==
    //~ usleep(50000);
    sentBytes++;
    }

    gettimeofday( &timeEnd, NULL );

    // Close the open port
    close( serport_fd );
    if (!(serf_fd < 0)) close( serf_fd );

    fprintf(stdout, "\n+++DONE+++\n");

    totlBytes = sentBytes + recdBytes;
    timeval_subtract(&timeDelta, &timeEnd, &timeStart);
    deltasec = timeDelta.tv_sec+timeDelta.tv_usec*1e-6;

    fprintf(stdout, "Wrote: %d bytes; Read: %d bytes; Total: %d bytes. \n", sentBytes, recdBytes, totlBytes);
    fprintf(stdout, "Start: %ld s %ld us; End: %ld s %ld us; Delta: %ld s %ld us. \n", timeStart.tv_sec, timeStart.tv_usec, timeEnd.tv_sec, timeEnd.tv_usec, timeDelta.tv_sec, timeDelta.tv_usec);
    fprintf(stdout, "%s baud for 8N1 is %d Bps (bytes/sec).\n", serspeed, atoi(serspeed)/10);
    fprintf(stdout, "Measured: write %.02f Bps, read %.02f Bps, total %.02f Bps.\n", sentBytes/deltasec, recdBytes/deltasec, totlBytes/deltasec);

    return 0;
    }

    serial.h :
    /* serial.h
    (C) 2004-5 Captain http://www.captain.at

    Helper functions for "ser"

    Used for testing the PIC-MMC test-board
    http://www.captain.at/electronic-index.php
    */

    #include <stdio.h> /* Standard input/output definitions */
    #include <string.h> /* String function definitions */
    #include <unistd.h> /* UNIX standard function definitions */
    #include <fcntl.h> /* File control definitions */
    #include <errno.h> /* Error number definitions */
    #include <termios.h> /* POSIX terminal control definitions */
    #include <sys/signal.h>
    #include <sys/stat.h>
    #include <sys/types.h>

    #define TRUE 1
    #define FALSE 0

    int wait_flag = TRUE; // TRUE while no signal received

    // Definition of Signal Handler
    void DAQ_signal_handler_IO ( int status )
    {
    //~ fprintf(stdout, "received SIGIO signal %d.\n", status);
    wait_flag = FALSE;
    }


    int writeport( int fd, char *comm )
    {
    int len = strlen( comm );
    int n = write( fd, comm, len );

    if ( n < 0 )
    {
    fprintf(stdout, "write failed!\n");
    return 0;
    }

    return n;
    }


    int readport( int fd, char *resp, size_t nbyte )
    {
    int iIn = read( fd, resp, nbyte );
    if ( iIn < 0 )
    {
    if ( errno == EAGAIN )
    {
    fprintf(stdout, "SERIAL EAGAIN ERROR\n");
    return 0;
    }
    else
    {
    fprintf(stdout, "SERIAL read error: %d = %s\n", errno , strerror(errno));
    return 0;
    }
    }

    if ( resp[iIn-1] == '\r' )
    resp[iIn-1] = '\0';
    else
    resp[iIn] = '\0';

    return iIn;
    }


    int getbaud( int fd )
    {
    struct termios termAttr;
    int inputSpeed = -1;
    speed_t baudRate;
    tcgetattr( fd, &termAttr );
    // Get the input speed
    baudRate = cfgetispeed( &termAttr );
    switch ( baudRate )
    {
    case B0: inputSpeed = 0; break;
    case B50: inputSpeed = 50; break;
    case B110: inputSpeed = 110; break;
    case B134: inputSpeed = 134; break;
    case B150: inputSpeed = 150; break;
    case B200: inputSpeed = 200; break;
    case B300: inputSpeed = 300; break;
    case B600: inputSpeed = 600; break;
    case B1200: inputSpeed = 1200; break;
    case B1800: inputSpeed = 1800; break;
    case B2400: inputSpeed = 2400; break;
    case B4800: inputSpeed = 4800; break;
    case B9600: inputSpeed = 9600; break;
    case B19200: inputSpeed = 19200; break;
    case B38400: inputSpeed = 38400; break;
    case B115200: inputSpeed = 115200; break;
    case B2000000: inputSpeed = 2000000; break; //added
    }
    return inputSpeed;
    }


    /* ser.c
    (C) 2004-5 Captain http://www.captain.at

    Sends 3 characters (ABC) via the serial port (/dev/ttyS0) and reads
    them back if they are returned from the PIC.

    Used for testing the PIC-MMC test-board
    http://www.captain.at/electronic-index.php

    */


    int initport( int fd, speed_t baudRate )
    {
    struct termios options;
    struct sigaction saio; // Definition of Signal action

    // Install the signal handler before making the device asynchronous
    saio.sa_handler = DAQ_signal_handler_IO;
    saio.sa_flags = 0;
    saio.sa_restorer = NULL;
    sigaction( SIGIO, &saio, NULL );

    // Allow the process to receive SIGIO
    fcntl( fd, F_SETOWN, getpid() );
    // Make the file descriptor asynchronous (the manual page says only
    // O_APPEND and O_NONBLOCK, will work with F_SETFL...)
    fcntl( fd, F_SETFL, FASYNC );
    //~ fcntl( fd, F_SETFL, FNDELAY); //doesn't work; //fcntl(file, F_SETFL, 0);

    // Get the current options for the port...
    tcgetattr( fd, &options );
    /*
    // Set port settings for canonical input processing
    options.c_cflag = BAUDRATE | CRTSCTS | CLOCAL | CREAD;
    options.c_iflag = IGNPAR | ICRNL;
    //options.c_iflag = IGNPAR;
    options.c_oflag = 0;
    options.c_lflag = ICANON;
    //options.c_lflag = 0;
    options.c_cc[VMIN] = 0;
    options.c_cc[VTIME] = 0;
    */
    /* ADDED - else 'read' will not return, unless it sees LF '\n' !!!!
    * From: Unix Programming Frequently Asked Questions - 3. Terminal I/O -
    * http://www.steve.org.uk/Reference/Unix/faq_4.html
    */
    /* Disable canonical mode, and set buffer size to 1 byte */
    options.c_lflag &= (~ICANON);
    options.c_cc[VTIME] = 0;
    options.c_cc[VMIN] = 1;

    // Set the baud rates to...
    cfsetispeed( &options, baudRate );
    cfsetospeed( &options, baudRate );

    // Enable the receiver and set local mode...
    options.c_cflag |= ( CLOCAL | CREAD );
    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;

    // Flush the input & output...
    tcflush( fd, TCIOFLUSH );

    // Set the new options for the port...
    tcsetattr( fd, TCSANOW, &options );

    return 1;
    }


    /*
    ripped from
    http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/stty.c
    */

    #define STREQ(a, b) (strcmp((a), (b)) == 0)

    struct speed_map
    {
    const char *string; /* ASCII representation. */
    speed_t speed; /* Internal form. */
    unsigned long int value; /* Numeric value. */
    };

    static struct speed_map const speeds[] =
    {
    {"0", B0, 0},
    {"50", B50, 50},
    {"75", B75, 75},
    {"110", B110, 110},
    {"134", B134, 134},
    {"134.5", B134, 134},
    {"150", B150, 150},
    {"200", B200, 200},
    {"300", B300, 300},
    {"600", B600, 600},
    {"1200", B1200, 1200},
    {"1800", B1800, 1800},
    {"2400", B2400, 2400},
    {"4800", B4800, 4800},
    {"9600", B9600, 9600},
    {"19200", B19200, 19200},
    {"38400", B38400, 38400},
    {"exta", B19200, 19200},
    {"extb", B38400, 38400},
    #ifdef B57600
    {"57600", B57600, 57600},
    #endif
    #ifdef B115200
    {"115200", B115200, 115200},
    #endif
    #ifdef B230400
    {"230400", B230400, 230400},
    #endif
    #ifdef B460800
    {"460800", B460800, 460800},
    #endif
    #ifdef B500000
    {"500000", B500000, 500000},
    #endif
    #ifdef B576000
    {"576000", B576000, 576000},
    #endif
    #ifdef B921600
    {"921600", B921600, 921600},
    #endif
    #ifdef B1000000
    {"1000000", B1000000, 1000000},
    #endif
    #ifdef B1152000
    {"1152000", B1152000, 1152000},
    #endif
    #ifdef B1500000
    {"1500000", B1500000, 1500000},
    #endif
    #ifdef B2000000
    {"2000000", B2000000, 2000000},
    #endif
    #ifdef B2500000
    {"2500000", B2500000, 2500000},
    #endif
    #ifdef B3000000
    {"3000000", B3000000, 3000000},
    #endif
    #ifdef B3500000
    {"3500000", B3500000, 3500000},
    #endif
    #ifdef B4000000
    {"4000000", B4000000, 4000000},
    #endif
    {NULL, 0, 0}
    };

    static speed_t
    string_to_baud (const char *arg)
    {
    int i;

    for (i = 0; speeds[i].string != NULL; ++i)
    if (STREQ (arg, speeds[i].string))
    return speeds[i].speed;
    return (speed_t) -1;
    }



    /* http://www.gnu.org/software/libtool/manual/libc/Elapsed-Time.html
    Subtract the `struct timeval' values X and Y,
    storing the result in RESULT.
    Return 1 if the difference is negative, otherwise 0. */
    int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y)
    {
    /* Perform the carry for the later subtraction by updating y. */
    if (x->tv_usec < y->tv_usec) {
    int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
    y->tv_usec -= 1000000 * nsec;
    y->tv_sec += nsec;
    }
    if (x->tv_usec - y->tv_usec > 1000000) {
    int nsec = (x->tv_usec - y->tv_usec) / 1000000;
    y->tv_usec += 1000000 * nsec;
    y->tv_sec -= nsec;
    }

    /* Compute the time remaining to wait.
    tv_usec is certainly positive. */
    result->tv_sec = x->tv_sec - y->tv_sec;
    result->tv_usec = x->tv_usec - y->tv_usec;

    /* Return 1 if result is negative. */
    return x->tv_sec < y->tv_sec;
    }

    关于c - 串口环回/双工测试,用 Bash 还是 C? (过程替换),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3701955/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com