Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8894339
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 14, 20262026-06-14T23:28:17+00:00 2026-06-14T23:28:17+00:00

I have two laptops with a serial port. How do I test the actual

  • 0

I have two laptops with a serial port. How do I test the actual bandwidth of the serial port between the two machines using a simple, small C program?

In reality, I need to do this on an embedded Linux system which is why the utility must be a small, simple C program (because the embedded environment only has limited library support meaning it doesn’t have python, perl, or any other fancy libraries).

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-14T23:28:19+00:00Added an answer on June 14, 2026 at 11:28 pm

    I started this as a new question because I didn’t want to take this question off topic: Serial port loopback test

    That question was regarding testing the bandwidth of a serial port in loopback mode, so that you don’t have to plug in an actual serial cable. The author (sdaau) put a lot of time into creating a multi-threaded serial bandwidth test program to answer his own question. I then used his simple C program and extended it to be used between two different physical machines connected with a serial cable.

    It is necessary to start the “remote” side which will wait for the “initiator” side (the local side) to send a go byte, in which both will proceed to transfer data asynchronously. The program (which sdaau calls writeread.c) spawns 2 threads: one which writes data and the other which reads data. In this way, you are fully utilizing the serial port. You can pass in a datafile as a command-line argument.

    As an example, here is the “remote” side:

    ./writeread /dev/ttyUSB0 115200 ./datafile.dat 3> output
    

    As an example, here is the “local” (or initiator) side:

    ./writeread /dev/ttyUSB0 115200 ./datafile.dat -I 3> output
    

    Note that I had some trouble redirecting the output on the remote side, meaning that 3> output didn’t really work. I’m not sure whats going on with that, but my local side worked fine. Also, note the remote side’s output timing is skewed because it has a timer running while it is waiting for the initiator. This means you should only trust the bandwidth printout from the local initiator side (see the original question for output results details).

    Since both sides are sending the same datafile in this example, you should be able to compare the “output” file with the datafile:

    diff output datafile.dat
    

    Complie the code with:

    gcc -c -Wall writeread.c
    gcc writeread.o -lpthread -o writeread
    

    Here is the modified writeread.c code:

    /*
        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 -lpthread -Wall -g writeread.c
    */
    
    #include <stdio.h>
    #include <string.h>
    #include <stddef.h>
    
    #include <stdlib.h>
    #include <sys/time.h>
    
    #include <pthread.h>
    
    #include "writeread.h"
    
    
    int serport_fd;
    
    //POSIX Threads Programming - https://computing.llnl.gov/tutorials/pthreads/#PassingArguments
    struct write_thread_data{
       int  fd;
       char* comm; //string to send
       int bytesToSend;
       int writtenBytes;
       int iator; // Initiator.  0 = False, 1 = True
    };
    
    void usage(char **argv)
    {
        fprintf(stdout, "Usage:\n"); 
        fprintf(stdout, "%s port baudrate file/string [-I]\n", argv[0]); 
        fprintf(stdout, "   The -I is for initiator.  Run on the remote side which "
                        "will wait, then start locally with -I which will initiate "
                        "the test.\n");
        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]); 
    }
    
    // POSIX threads explained - http://www.ibm.com/developerworks/library/l-posix1.html
    // instead of writeport
    void *write_thread_function(void *arg) {
        int go = 0;
        int lastBytesWritten;
        struct write_thread_data *my_data;
        my_data = (struct write_thread_data *) arg;
    
        fprintf(stdout, "write_thread_function spawned\n");
    
        // Are we the initiator?
        if (my_data->iator == 1) {
            // We are the initiator, send the start command
            go = 0xde;
            write(my_data->fd, &go, 1);
        } else {
            // We wait for the initiator to send us the start command
            fprintf(stdout, "Waiting for initiator (start other end with -I)...\n");
            read(my_data->fd, &go, 1);
            if (go == 0xde) {
                fprintf(stdout, "Go!\n");
            } else {
                fprintf(stdout, "Error: Did not receive start command [0x%x]\n", go);
                return NULL;
            }
        }
    
        my_data->writtenBytes = 0; 
        while(my_data->writtenBytes < my_data->bytesToSend)
        {
            lastBytesWritten = write( my_data->fd, my_data->comm + my_data->writtenBytes, my_data->bytesToSend - my_data->writtenBytes );   
            my_data->writtenBytes += lastBytesWritten;  
            if ( lastBytesWritten < 0 ) 
            {
                fprintf(stdout, "write failed!\n");
                return 0;
            }
            fprintf(stderr, "   write: %d - %d\n", lastBytesWritten, my_data->writtenBytes);
        }
        return NULL; //pthread_exit(NULL)
    }
    
    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 sentBytes; 
        int readChars;
        int recdBytes, totlBytes; 
    
        char* sResp;
        char* sRespTotal;
    
        struct timeval timeStart, timeEnd, timeDelta;
        float deltasec, expectBps, measReadBps, measWriteBps; 
    
        struct write_thread_data wrdata;
        pthread_t myWriteThread;
    
        /* 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];
    
        // Are we the initiator?
        if (argc == 5 &&
            strncmp(argv[4], "-I", 3) == 0 )
        {
            wrdata.iator = 1; // Initiator.  0 = False, 1 = True
        } else {
            wrdata.iator = 0; // Initiator.  0 = False, 1 = True
        }
    
        serf_fd = open( serfstr, O_RDONLY );
        fprintf(stdout, "Got file/string '%s'; ", serfstr);
        if (serf_fd < 0) {
            wrdata.bytesToSend = strlen(serfstr);
            wrdata.comm = serfstr; //pointer already defined 
            fprintf(stdout, "interpreting as string (%d).\n", wrdata.bytesToSend);
        } else {
            struct stat st;
            stat(serfstr, &st);
            wrdata.bytesToSend = st.st_size;
            wrdata.comm = (char *)calloc(wrdata.bytesToSend, sizeof(char));
            read(serf_fd, wrdata.comm, wrdata.bytesToSend);
            fprintf(stdout, "opened as file (%d).\n", wrdata.bytesToSend);
        }
    
        sResp = (char *)calloc(wrdata.bytesToSend, sizeof(char));
        sRespTotal = (char *)calloc(wrdata.bytesToSend, sizeof(char));
    
        // 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 );
    
        wrdata.fd = serport_fd;
    
        sentBytes = 0; recdBytes = 0;
    
        gettimeofday( &timeStart, NULL );
    
        // start the thread for writing.. 
        if ( pthread_create( &myWriteThread, NULL, write_thread_function, (void *) &wrdata) ) {
            printf("error creating thread.");
            abort();
        }
    
        // run read loop 
        while ( recdBytes < wrdata.bytesToSend )
        {
    
            while ( wait_flag == TRUE );
    
            if ( (readChars = read( serport_fd, sResp, wrdata.bytesToSend)) >= 0 ) 
            {
                //~ fprintf(stdout, "InVAL: (%d) %s\n", readChars, sResp);
                // binary safe - add sResp chunk to sRespTotal
                memmove(sRespTotal+recdBytes, sResp+0, readChars*sizeof(char));
                /* // text safe, but not binary:
                sResp[readChars] = '\0'; 
                fprintf(stdalt, "%s", sResp);
                */
                recdBytes += readChars;
            } else {
                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;
                }           
            }
            fprintf(stderr, "   read: %d\n", recdBytes);        
    
            wait_flag = TRUE; // was ==
            //~ usleep(50000);
        }
    
        if ( pthread_join ( myWriteThread, NULL ) ) {
            printf("error joining thread.");
            abort();
        }
    
        gettimeofday( &timeEnd, NULL );
    
        // binary safe - dump sRespTotal to stdalt
        fwrite(sRespTotal, sizeof(char), recdBytes, stdalt);
    
        // Close the open port
        close( serport_fd );
        if (!(serf_fd < 0)) { 
            close( serf_fd );
            free(wrdata.comm); 
        } 
        free(sResp);
        free(sRespTotal);
    
        fprintf(stdout, "\n+++DONE+++\n");
    
        sentBytes = wrdata.writtenBytes; 
        totlBytes = sentBytes + recdBytes;
        timeval_subtract(&timeDelta, &timeEnd, &timeStart);
        deltasec = timeDelta.tv_sec+timeDelta.tv_usec*1e-6;
        expectBps = atoi(serspeed)/10.0f; 
        measWriteBps = sentBytes/deltasec;
        measReadBps = recdBytes/deltasec;
    
        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, (int)expectBps);
        fprintf(stdout, "Measured: write %.02f Bps (%.02f%%), read %.02f Bps (%.02f%%), total %.02f Bps.\n", measWriteBps, (measWriteBps/expectBps)*100, measReadBps, (measReadBps/expectBps)*100, totlBytes/deltasec);
    
        return 0;
    }
    

    And here is the .h file which I have renamed from the original question to writeread.h:

    /* writeread.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;
    }
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have connected my two laptops using a cat5 cross ethernet cable. Both have
I have two dev machines. My code is synced between the two with dropbox
I have an experiment set-up using two laptop machines , one acting as a
My scenario is I have two laptops with fresh installation of windows . Now
I got trouble on Member Description show up. For example, I have two laptops.
I have project in Dropbox and two running laptops: one with Ubuntu and one
I have two laptops here. One is running Vista, the other Windows 7. I
I have two machines, one is an old toshiba laptop that I use at
OK so I'm tracking a remote repo on two machines so both have the
I'm using Eclipse to develop an app and I have two computers (a desktop

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.