3

I have a device that sends data to COM port. And I'd like to simulate this device when it's not plugged in. I thought that this can be accomplished by simply sending data to a specific COM port:

int main() {
    char *port = "\\\\.\\COM40";

    HANDLE hCom = CreateFile(port, GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
    if (hCom==INVALID_HANDLE_VALUE) return 0;

    DWORD writeBytes;
    int buffer = 0xDEADBEAF;
    BOOL success = WriteFile(hCom, &buffer, 4, &writeBytes, NULL);

    FlushFileBuffers(hCom);
    Sleep(1000);

    HANDLE hCom2 = CreateFile(port, GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
    if (hCom2==INVALID_HANDLE_VALUE) return 0; // Exit. GetLastError() == 5

    DWORD readBytes;
    success = ReadFile(hCom2, &buffer, 4, &readBytes, NULL);

    CloseHandle(hCom);
    CloseHandle(hCom2);
    return 0;
}

Unfortunately that doesn't work and second CreateFile() sets last error to ERROR_ACCESS_DENIED. What am I missing?

AlexP
  • 1,416
  • 1
  • 19
  • 26
  • are you sure you have COM40 port on your system? Are you sure some other application is not using it right now? something like a serial terminal or Hyper terminal? – Kamyar Souri Mar 22 '12 at 01:10
  • If I plug in the device, everything works. Also first CreateFile() is called successfully. – AlexP Mar 22 '12 at 01:15
  • Use one createfile to open the port once. Connect pin 2 and 3 of serial port together. This connects tx pin to rx pin. use WriteFile to write the simulated data to tx pin of the port, and use ReadFile to read the simulated data from the port. – Kamyar Souri Mar 22 '12 at 02:24

4 Answers4

6

For simulation, install a virtual COM port driver, such as com0com. You can then define 2 COM ports that are linked together in the driver. No hardware needed. Anything written to one port is readable on the other port. You can then open a handle to each port with separate calls to CreateFile().

I use this technique myself, it works very well. When I need to write an app that communicates with a device, I usually write a separate simulation app that generates data for the main app to read, and consumes data the main app sends. The main app doesn't know it is not communicating with a real device, so you don't have to change any code in the main app to support simulations .

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I use the app for simulation and when i write `"AB"` to one and read 2 bytes from another, I see first `B` then `A` is read because the number is `0100001001000001`. Please , is it normal? Thanks – Code-Lover Sep 09 '19 at 14:50
  • 1
    @Code-Lover the only way that could happen is if you are writing/reading that data as a 2-byte integer instead of as a 2-char string. Multi-byte integers are subject to **endian** which dictates byte ordering. Sender and Receiver have to agree on the same endian – Remy Lebeau Sep 09 '19 at 14:58
0

You can't send things on a serial port by opening the same port twice. The serial port has two different physical wires, one for transmit and one for receive. With nothing plugged in to the port, those two wires go nowhere and signals don't automatically move from one to the other.

Having said that, it is possible to build a dongle that connects the TX and RX pins together, and receive the same bytes that you write. That's a physical component though, you can't do it only in software (well, unless you created a "loopback device" COM port driver that need not even talk to hardware).

A quick Google search indicates that both the physical dongle, and a loopback driver, aren't hard to obtain.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • Well, the device is plugged in via USB. Does that mean that this device's driver uses "loopback device" COM port? – AlexP Mar 22 '12 at 01:19
  • No, the USB serial driver is not a loopback driver. With the USB plug unplugged, your COM40 port probably doesn't even exist (it will be dynamically created by the driver when you plug the USB in). – Greg Hewgill Mar 22 '12 at 01:22
0

you can use two different COM ports for this test. use one as device simulator and the other on as host system receiving the data. Doing that you do not have to CreateFile on same port twice.

Kamyar Souri
  • 1,871
  • 19
  • 29
0

A serial port isn't an IPC pipe. If you want loopback, that either has to be simulated in the driver, or you have to enable a hardware loopback mode. I think the driver is preventing two handles from being open on the device in spite of the sharing flags passed to CreateFile. (I've never been able to get two serial applications on Windows to both open the same serial port.)

http://msdn.microsoft.com/en-us/library/ms810467.aspx

I don't see any flags in the DCB structure to configure loopback even though chips like the 16550 UARTS have the capability.

Thus, extenal loopback via null modem cable is it.

Kaz
  • 55,781
  • 9
  • 100
  • 149