Parallel port communication

I'm trying to communicate with a device with a parallel port, but I'm having troubles (windows XP x86). The device is not a printer, in fact I don't even have an ICD or even know if the chips on the thing are soldered correctly. I am trying to figure this out by bombarding it with data and seeing what I get as a result.

My first step is to get something reliable running on my end so that I can be assured the any problems exist on the peripheral's side. I've tried the following code, but both the read and write functions return with ERROR_INVALID_HANDLE.

How do I properly open the parallel port (0x378) with CreateFile()? I've tried using the names "\\\\.\\LPT1" and "LPT1" as the first arguments for CreateFile().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <windows.h>
int main(int argc, char* argv[])
{
	OVERLAPPED overlp = {0};

	HANDLE hComm = CreateFileA("\\\\.\\LPT1", GENERIC_READ | GENERIC_WRITE,
		0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);

	if (hComm == NULL || hComm == INVALID_HANDLE_VALUE) 
	{
		std::cout << "Couldn't open handle to comm port" << std::endl;
		return 1;
	}

	unsigned char i = 0
	while (true)
	{
		DWORD bytesWritten, bytesRead;
		unsigned char data;

		if (!ReadFile(hComm, &data, 1, &bytesRead, &overlp)) 
			std::cout << "Failed to read  data " << GetLastError() << std::endl;
		else 
			std::cout << "Data recieved: " << data << std::endl;

		Sleep(250);

		if (!WriteFile(hComm, &i, 1, &bytesWritten, &overlp))
			std::cout << "Failed to write data " << GetLastError()  < " " <<  i << std::endl;

		Sleep(250);

		if (++i == 256) i = 0;
	}
}
Failed to read  data 6
Failed to write data 6 a
Failed to read  data 6
Failed to write data 6 b
Failed to read  data 6
Failed to write data 6 c
Failed to read  data 6
Failed to write data 6 d
...


EDIT: Initialized overlp;
Last edited on
bump
You are using FILE_FLAG_OVERLAPPED.
You need to ZERO out the OVERLAPPED structure object otherwise I have found that you will get the Error 6 (ERROR_INVALID_HANDLE) on the ReadFile even though CreateFile was successful

OVERLAPPED overlp = {0}; //initialise the OVERLAPPED struct
Thanks so much. I'll give it a try when I get to work on Monday.
Getting closer:

Now I get:
Failed to read  data 997
Failed to write data 997 a
Failed to read  data 997
Failed to write data 997 b
Failed to read  data 997
Failed to write data 997 c
Failed to read  data 997
Failed to write data 997 d


Error code 997 represents ERROR_IO_PENDING.
Why do you use overlap? It's for asynchronous operations (i.e. waiting for an event to occur) while you're polling the port.

pending in this context is not an error it's the current state
I tried to get rid of overlap by doing the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <windows.h>

int main(int argc, char* argv[])
{
	HANDLE hComm = CreateFileA("LPT1", GENERIC_READ | GENERIC_WRITE, 
		0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

	if (hComm == INVALID_HANDLE_VALUE) 
	{
		std::cout << "Couldn't open handle to comm port " << GetLastError() << std::endl;
		return 1;
	}

	for (int i = 0; true;)
	{
		DWORD bytesWritten, bytesRead;
		unsigned char data;

		if (!ReadFile(hComm, &data, 1, &bytesRead, NULL)) 
			std::cout << "Failed to read  data " << GetLastError() << std::endl;
		else 
			std::cout << "Data recieved: " << data << std::endl;

		Sleep(250);

		if (!WriteFile(hComm, &i, 1, &bytesWritten, NULL))
			std::cout << "Failed to write data " << GetLastError() << "\t" <<  i << std::endl;

		Sleep(250);

		if (++i == 256) i = 0;
	}
}
Failed to read  data 1


The ReadFile() function returns with an error (ERROR_INVALID_FUNCTION) and then the WriteFile() function blocks.

What does this mean?

Note I've also tried using NULL instead of FILE_ATTRIBUTE_NORMAL.

Everything I'm doing seems to be correct according to:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467(v=vs.85).aspx
So I can't figure out what's wrong.
Last edited on
bump
Are you sure there is something available to be read from the port??

Unfortunately I have nothing I can connect to my parallel port to try it out with.

Something is certainly connected to the port, but I don't know how well it works. If this type of issue is related to something on the peripheral side, and my code is solid, then I can be happy.

Let me simplify my question: I want to set voltages on the data pins of the parallel port which I will measure with my multi-meter. There will be no hand-shaking. If I use the following code, it blocks at line 16. I do not want it to block.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <windows.h>

int main(int argc, char* argv[])
{
    HANDLE hComm = CreateFileA("LPT1", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

    if (hComm == INVALID_HANDLE_VALUE)  return 1;

    unsigned char i = 0;
    while (true)
    {
        DWORD bytesWritten, bytesRead;
        unsigned char data;
        
        BOOL nError = WriteFile(hComm, &i, 1, &bytesWritten, NULL);
        
        if (nError) std::cout << "Data sent: " << (int)i << std::endl;
        else        std::cout << "Failed to write data " << GetLastError() << std::endl;

        Sleep(500);

        if (++i == 256) i = 0;
    }
}
Last edited on
The question is: what exactly addresses LPT1? Maybe it's just a logical port and the output goes to the printer? You may try this with e.g. dir *.* > lpt1. I don't know if a device like a parallel port checker exist, but if you may check if something happens on that port.

You can also check what ports exists on your computer with EnumPorts():

http://msdn.microsoft.com/en-us/library/windows/desktop/dd162687%28v=vs.85%29.aspx

if LPT1 indeed addresses the parallel port you might have problems with flow control or something like that. I don't know what low level protocol is required for the parallel port communication. Maybe you try GetCommState():

http://msdn.microsoft.com/en-us/library/windows/desktop/aa363260%28v=vs.85%29.aspx

The best thing would be that you make 2 computers communicate via the parallel port.
Then if you're sure that you mastered the parallel port as such check the unknown device
Thanks for the responses and sorry for getting frustrated. Here are the results. I don't know why the GetCommState() is returning with an error. My guess is that I am not initializing the DCB object correctly. I'll see if I can get this.

For EnumPorts
1
2
3
4
5
6
7
8
9
10
11
12
int main()
{
	PORT_INFO_1A pi[200];
	DWORD bytes, size;

	for (int i = 0; i < 200; i++) pi[i].pName = "                     ";

	EnumPortsA(NULL, 1, (LPBYTE)&pi, 200*sizeof(pi[0]), &bytes, &size);

	for (DWORD i = 0; i < size; i++)
		std::cout << pi[i].pName << std::endl;
}
COM1:
COM2:
COM3:
COM4:
FILE:
LPT1:
LPT2:
LPT3:
XPSPort:


For GetCommState:
1
2
3
4
5
6
7
8
9
10
11
int main()
{
	HANDLE hComm = CreateFileA("LPT1:", GENERIC_READ | GENERIC_WRITE, 
		0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

	DCB status = {0};
	BOOL success = GetCommState(hComm, &status);

	if (!success)
		std::cout << "Failure with code: " << GetLastError();
}
Failure with code: ERROR_INVALID_PARAMETER


Edit: I read on an assembly forum that WriteFile() will block if the recipient hasn't signaled that it is ready to take a signal. I tried to hard-wire this signal by strapping pin 10 and pin 11 to ground with a 560 Ohm resistor, but that made no difference. I think my next step will be to hard-wire the other inputs to 5V if I can't figure out a software solution. It seems a little extreme for a test.

asmcommunity wrote:
pin 10 is ack, active low
pin 11 is busy, active high
pin 12 is pe, active high
pin 13 is Select which would correspnd with the select button on the front of the printer, active high
pin 15 is error, active low
pin 16 is init, active low
Last edited on
Interesting that there are 3 LPT ports. Do you have 3 parallel ports?
There is only one physical parallel port, however the motherboard has 3 reserved memory addresses associated with IRQs that can be chosen 0x0278, 0x0378, 0x03CB. I'll try LPT2.

Edit:
I just tried LPT2 and LPT3 and GetCommState exited with ERROR_INVALID_HANDLE. So it seems to be a step back.
Last edited on
Look at this tutorial for prallel port programming:

http://logix4u.net/component/content/article/14-parallel-port/15-a-tutorial-on-parallel-port-interfacing

seems CreateFile() isn't suitable for this
I've seen that tutorial. That was my original attempt. Unfortunately, it uses _inp() and _outp() which are specific to conio.h on 16-bit compilers and operating systems. It is out of date and not supported in WIN98 and up.

There is another version of these functions that are available in an external library: Inpout32.dll available from http://logix4u.net/index.php. However, the links on this page seem to be broken and I'm not willing to download this DLL from some random "We supply DLLs!" site.

It's a shame, that would have been such a nice solution.

Topic archived. No new replies allowed.