Click here to Skip to main content
Click here to Skip to main content

How to use serial port to communicate between two computers

, 30 Sep 2005
Rate this:
Please Sign up or sign in to vote.
Using the serial port and cable to send a file from one computer to another.

Introduction

Very often it is necessary to send a file from one computer to another. There are several ways to do this: you could put it on a disk or send it over a LAN. If the computers are relatively close together and the file is fairly small, it may be quickest to send the file over a serial cable connected to each computer's serial port.

Background

In order to hook up two computers using the serial port, it is necessary to have a null modem cable. If you don't know where to get one, try Jameco Electronics and do a search for null modem cable.

Using the code (Transmitting)

There are two source files included. The first is sertrans.c, which transmits the file over the serial cable. The second is serrecv.c, which receives the file and saves it to the directory where the program is located.

Opening a handle to the serial port

The first step in transmitting the file is to create a handle to the serial port. This is done with the CreateFile function:

/* Open up a handle to the serial port */
serial_port = CreateFile(port_name, GENERIC_READ | GENERIC_WRITE, 
                                      0, 0, OPEN_EXISTING, 0, 0);

The variable port_name is a null-terminated character string containing the name of the serial port, such as "COM1:".

Setting up the serial port

The next step is to set up the properties of the serial port. The most important properties are parity, byte size, stop bits, and baud rate. For this project, I have set the properties to no parity, 8 bits per byte, and one stop bit. The baud rate is 9600 by default, but can be changed by a command line switch to 1200, 2400, 4800, 9600, 14400, 19200, or 38400. The function set_up_serial_port does this. First, the function GetCommState is called to fill in a DCB structure that contains the current properties of the serial port. Most of these properties are advanced and don't need to be messed with. However, we will set the parity, byte size, stop bits, and baud rate. After setting these properties, the SetCommState function is called.

void set_up_serial_port(HANDLE h, long baud)
{
    DCB properties;            /* Properties of serial port */

    /* Get the properties */
    GetCommState(h, &properties);

    /* Set the baud rate */
    switch(baud)
    {
    case 1200:
        properties.BaudRate = CBR_1200;
        break;
    case 2400:
        properties.BaudRate = CBR_2400;
        break;
    case 4800:
        properties.BaudRate = CBR_4800;
        break;
    case 9600:
        properties.BaudRate = CBR_9600;
        break;
    case 14400:
        properties.BaudRate = CBR_14400;
        break;
    case 19200:
        properties.BaudRate = CBR_19200;
        break;
    case 38400:
        properties.BaudRate = CBR_38400;
        break;
    default:
        fprintf(stderr, "Invalid baud rate: %ld", baud);
        usage();
        exit(0);
        break;
    }
    
    /* Set the other properties */
    properties.Parity = NOPARITY;
    properties.ByteSize = 8;
    properties.StopBits = ONESTOPBIT;

    SetCommState(h, &properties);

    return;
}

Getting the file size

Next we must get the size of the file to be transmitted. This step is necessary because before transmitting the file, the size of the file to be received is transmitted so the receiving computer knows how many bytes to receive. To get the file size, a function was written to open the file in binary mode and read it byte-by-byte until we reached the end. This may not be the most efficient way of determining file size, but it's one of the simplest.

Transmitting the file name

Now the name of the file is transmitted over the serial port so that the receiving computer knows the name of the file. To do this, the length of the file name is first transmitted and then the file name itself is transmitted. The transmission over the serial port is done using the WriteFile function.

/* Write file name size to serial port */
file_name_size = (unsigned long)strlen(argv[1]);
WriteFile(serial_port, (void *)&file_name_size, 
          sizeof(unsigned long), &bytes_written, NULL);
if (bytes_written != sizeof(unsigned long))
{
    fprintf(stderr, "Error writing file name size.\n");
    CloseHandle(serial_port);
    exit(0);
}

/* Write file name to serial port */
WriteFile(serial_port, (void *)argv[1], 
          file_name_size, &bytes_written, NULL);
if (bytes_written != file_name_size)
{
    fprintf(stderr, "Error writing file name.\n");
    CloseHandle(serial_port);
    exit(0);
}

Transmitting the file

It is now time to transmit the file. First the size of the file is transmitted so the receiving computer knows how many bytes to expect. This code is similar to the code used to transmit the size of the file name shown in the section above. To transmit the actual file, a function was written. First the file is opened in binary mode on the local computer. Then it is sent 200 bytes at a time to the receiving computer. The variables bytes_left and total_bytes_sent keep track of how many bytes are left to be transmitted and how many have been transmitted. After each 200 byte block is transmitted, a progress indicator is updated and printed to the screen to tell the user how many bytes have been transmitted so far.

void write_file_to_serial_port(HANDLE h, 
     char *file_name, unsigned long file_size)
{
    FILE *data_file;
    unsigned long bytes_left = file_size;
    unsigned long bytes_sent;
    unsigned long bytes_read;
    unsigned long total_bytes_sent = 0;
    size_t bytes_to_send;
    char buffer[200];

    /* Open the file */
    data_file = fopen(file_name, "rb");

    /* Quit if file couldn't be opened */
    if (data_file == NULL)
    {
        fprintf(stderr, "Could not open file %s\n", file_name);
        exit(0);
    }

    while (1)
    {
        /* Determine how many bytes to send */
        if (bytes_left == 0)
        {
            break;
        }
        else if (bytes_left < 200)
        {
            bytes_to_send = bytes_left;
        }
        else
        {
            bytes_to_send = 200;
        }

        /* Read in specified number of bytes */
        bytes_read = (unsigned long)fread((void *)buffer, 1, 
                                  bytes_to_send, data_file);

        /* Send data over serial cable */
        WriteFile(h, (void *)buffer, bytes_read, &bytes_sent, NULL);
        if (bytes_sent != bytes_read)
        {
            fprintf(stderr, "Error writing file.\n");
            CloseHandle(h);
            exit(0);
        }
        
        /* Decrement number of bytes left */
        bytes_left -= bytes_sent;

        /* Increment number of bytes sent */
        total_bytes_sent += bytes_sent;

        /* Print out progress */
        printf("\r%5lu bytes transmitted.", total_bytes_sent);
    }

    fclose(data_file);

    return;
}

Using the Code (Receiving)

First, a handle to the serial port is opened and then the properties of the serial port are set. This code is identical to the code for the transmitter.

Receiving the file name

The next step is to receive the file name. First, the length of the file name is received. Then, the file name itself is received. The ReadFile function is used to receive the data.

/* Receive file name size from serial port */
ReadFile(serial_port, (void *)&file_name_size, 
         sizeof(unsigned long), &bytes_received, NULL);
if (bytes_received != sizeof(unsigned long))
{
    fprintf(stderr, "Error getting file name size.\n");
    CloseHandle(serial_port);
    exit(0);
}

/* Receive file name from serial port */
ReadFile(serial_port, (void *)file_name, file_name_size, 
                                 &bytes_received, NULL);
if (bytes_received != file_name_size)
{
    fprintf(stderr, "Error retrieving file name.\n");
    CloseHandle(serial_port);
    exit(0);
}

/* Append NULL terminator to end of string */
file_name[bytes_received] = '\0';

Receiving the file

To receive the file, first the size of the file is received, so that the program knows how many bytes to expect over the serial port. After this, the file is created and the data is received in 200 byte increments until there is no more to receive. As the data is received, it is written to the file on the receiving computer.

void get_file_from_serial_port(HANDLE h, char *file_name, unsigned long file_length)
{
    FILE *data_file;                        /* File to create */
    unsigned long bytes_left = file_length;    /* Bytes left to receive */
    unsigned long bytes_received_total = 0;    /* Total bytes received */
    unsigned long bytes_to_receive;            /* Number of bytes to receive */
    unsigned long bytes_received;            /* Number of bytes receive */
    char buffer[200];                        /* Buffer to store data */

    /* Open the file */
    data_file = fopen(file_name, "wb");

    /* Quit if file couldn't be opened */
    if (data_file == NULL)
    {
        fprintf(stderr, "Could not create file %s\n", file_name);
        CloseHandle(h);
        exit(0);
    }

    while (1)
    {
        /* Determine how many bytes to read */
        if (bytes_left == 0)
        {
            break;
        }
        else if (bytes_left < 200)
        {
            bytes_to_receive = bytes_left;
        }
        else
        {
            bytes_to_receive = 200;
        }

        /* Receive data over serial cable */
        ReadFile(h, (void *)buffer, bytes_to_receive, &bytes_received, NULL);
        if (bytes_received != bytes_to_receive)
        {
            fprintf(stderr, "Error reading file.\n");
            CloseHandle(h);
            exit(0);
        }

        /* Save buffer to file */
        fwrite((void *)buffer, 1, bytes_received, data_file);
        
        /* Decrement number of bytes left */
        bytes_left -= bytes_received;

        /* Increment number of bytes received */
        bytes_received_total += bytes_received;

        /* Print out progress */
        printf("\r%5lu bytes received.", bytes_received_total);
    }

    fclose(data_file);

    return;
}

Using the executable files

First, the program serrecv.exe is executed on the receiving computer. This program will just display a blank screen until it receives some data. Then the program sertrans.exe is executed on the transmitting computer. Both computers will show progress as bytes are received until the file transmission is finished.

Using the transmitting program

The syntax for sertrans.exe is: sertrans file_name [-b baud_rate], where file_name is the name of the file to transmit and the optional switch baud_rate specifies which baud rate is desired. If this switch is omitted, the program will execute at a baud rate of 9600. For example, to transmit a file called text.txt at a baud rate of 14400, you would type sertrans text.txt -b 14400. The file to transmit should be located in the same directory as the program, and you can copy and paste it there if it isn't there already.

Using the receiving program

The syntax for serrecv.exe is: serrecv [-b baud_rate]. If the baud rate is omitted, the program will operate at a default baud rate of 9600. The file transmitted over the serial cable will be stored in the directory where the program is located. You can then copy and paste the file to the desired directory.

Selecting a baud rate

The most important thing in selecting a baud rate is to make sure that both the transmitting and receiving computers are using the same baud rate. If not, the file transmission will fail. One important consideration is the length of the serial cable. If it is very long, a high baud rate may not produce reliable communication, and you may be forced to reduce the baud rate.

Points of Interest

On most computers, the serial port is COM1:. This program assumes that you want to use COM1: as your serial port, which is fine for most computers. If the program doesn't seem to be working, it may be that you need to change the serial port. Go under Control Panel on your computer and click on System to determine which serial ports are installed on your computer. For instance, if you discover that you need to use COM2:, change the text char port_name[] = "COM1:"; to char port_name[] = "COM2:";. Then recompile and try the program again.

History

No history yet.

Further Reading

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

gomorgan89

United States United States
No Biography provided

Comments and Discussions

 
Questionabout running this project? Pinmembergold_heart00728-Mar-07 11:15 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141223.1 | Last Updated 30 Sep 2005
Article Copyright 2005 by gomorgan89
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid