2
votes

I am working on a utility that automates the testing of a legacy application. The legacy application runs on Windows 2000, and uses 3 devices connected via serial (COM) ports.

I have access to the application's source code but don't have the go-ahead to make any changes. However, the source code has allowed me to verify that device COM port names are hard coded into the application as COM1 (a printer), COM2 (a bank note reader) and COM3 (a barcode/OMR reader). I can also see the bytes that are sent to each device, and how the application processes the returns.

For now, I would like to write tests regarding the bank note reader. I read from various questions here (e.g. Faking an RS232 Serial Port) that I can use com0com to fake a serial port. I was hoping that there was a way to send bytes on behalf of a real COM port device that will be picked up by the application.

After installing the utility I configured a pair as "COM2" to "COM6". The COM2 label appears in red, and when I press OK I get the following message:

The port name COM2 is already used for other device \Device\Serial1

I can then press Cancel, Try Again or Continue.

On pressing Continue I get:

The port name COM2 is already logged as "in use" in the COM port database

Again I press Continue.

I wrote a small application in C# to test the COM2 and COM6 port pairing. When I send valid bytes to COM2 I get the expected 11 bytes back (which mirrors a scenario exactly in the legacy application). Nothing is received on COM6. When I send the same bytes to COM6 I get no response from either COM2 or COM6.

I have tried rebooting the machine, setting up the pairing again, trying different COM ports (COM1 to COM6, COM3 to COM6) but never get a response on these virtual ports (COM1 and COM3 are also in red, and give me the same errors via com0com).

The test C# app is as follows:

using System;
using System.IO.Ports;

public class Com
{
    private static byte[] s_pDataSent = new byte[32];
    private static byte[] s_pDataRead = new byte[32];

    private static void port_OnReceivedDatazz(
        object sender,
        SerialDataReceivedEventArgs e)
    {
        var sp = (SerialPort)sender;
        var buffer = new byte[sp.BytesToRead];
        Console.WriteLine("DATA RECEIVED ON " + sp.PortName);
        sp.Read(buffer, 0, buffer.Length);
        foreach(var b in buffer)
        {
            Console.Write(b.ToString() + " ");
        }
        Console.WriteLine();
    }

    public void Do(string portName, string virtualPort)
    {
        var port = new SerialPort(
            portName,
            9600,
            Parity.Even,
            7,
            StopBits.One);
        port.RtsEnable = false;
        port.DtrEnable = false;
        port.DataReceived += port_OnReceivedDatazz;
        port.Open();

        if (!port.IsOpen)
        {
            Console.WriteLine("Port is closed");
        }

        var vport = new SerialPort(
            virtualPort,
            9600,
            Parity.Even,
            7,
            StopBits.One);
                vport.RtsEnable = false;
                vport.DtrEnable = false;
                vport.DataReceived += port_OnReceivedDatazz;
                vport.Open();

        if (!vport.IsOpen)
        {
            Console.WriteLine("VPort is closed");
        }

        for (var i = 0; i < s_pDataSent.Length; ++i)
        {
            s_pDataSent[i] = 0;
        }

        // populate s_pDataSent ...
        // I have left these steps out of this example
        // ...but they do exist in my test app

        port.Write(
            s_pDataSent,
            0,
            8);

        Console.ReadLine();
        Console.WriteLine("Closing");
        port.Close();
    }
}

When I use HyperTerminal, I can see messages being sent between 2 virtual ports but nothing is being sent between a real and virtual port.

Is it possible to pair a real and virtual COM port, via com0com or otherwise?

If so, how can I resolve my problem?

Is there an alternative to faking outputs from a real serial port?

3
Why do you want to pair real and virtual port? what exactly are you trying to do? do yo want to sniff out all messages sent to some serial port on the PC?idanp
@Idank - No, I want to send messages to the connected application on behalf of the real port. I assumed I could pair to a virtual port, and write to this port (so that it becomes output on the real port). Is this wrong?Class Skeleton
Looks ok to me, what's could be wrong with com0com two paired virtual ports? why do you need the second port to be real?idanp
@Idank - these tests are running on a machine with the devices connected. The app is hard coded to connect to specific COM ports, and basically pings these devices every 200ms.Class Skeleton

3 Answers

1
votes

You can change the physical ports to 7, 8 and 9 and leave the ports 1 2 3 hard coded then you can install 3 virtual com pairs, like COM1-COM4, COM2-COM5, COM3-COM6 to wich the "old" app can open and you can monitor then route the read bytes to another port.

OLD APP -> COM1 -> COM4 -> YOUR APP -> COM7(printer)

0
votes

Quick and dirty solution instead of using com0com:

Just plug one of the PC ports (COM6) to another port (COMx) using a crossover cable ("null modem") (swap the Tx and Rx). You can now use two ports that are connected to each other with 2 different application, each byte sent on one port is received on the other and vice-versa.

And both of the ports are real.

You can now emulate your device using another application using COMx.

0
votes

I managed to get a fully automated test system up and running by:

  • Using com0com to set up 2 virtual port pairings (COM6-COMD and COMI-COMJ).
  • Writing a simple application that emulated the device by writing back a set of bytes to COMD when something read on COMD. The bytes written back would be a default set of "nothing to do" bytes unless test bytes were also read on COMJ.
  • Added functionality to my automated test scripts that would be capable of sending specific bytes on COMI. For example, the bytes that represented a £5 note being read or the note being invalid.
  • Modified the legacy executable with an hex editor to replace the "COM2:" ascii string (i.e. hard-coded port) to "COM6:".

I can now have a test terminal set up to use the original legacy application for manual testing. All of the devices work correctly. On the same terminal, the automated test scripts are linked to a modified executable. This executable will use emulated devices.

I need to maintain a "modified" executable until work is done to make the COM ports configurable in the application.

One minor observation was that I needed to use "real" COM port names in the modified exe. I couldn't use "COMA" for example. It needed to be COM1 to COM9.