Archived

This topic is now archived and is closed to further replies.

Parallel Port Access Under Win32 C++

This topic is 5619 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Platform: PC Windows 32 Application Language: C++ Compiler: MSVC++ 6.0 API:DirectX 7.0 I just ran into a problem with a project of mine, hope someone can help. I am writing a game that will make use of an electronic device that is connected to the parallel port. I needed to be able to use Data lines 0-7 as sources of +5v to drive some led''s. This was no problem for me while testing under a console application as I used the _outp(0x378, [int/hex value]) function to control the data lines. Upon moving the program to a win32/directX environment I was dismayed that this function causes the window to collapse and the application to hault. I assume that this is because the function only works under DOS and console apps. So my question is, how can I gain control of the data lines of the parallel port under a win32 app. Does DirectX contain contexts for a printer device? I know that I can create different apps using the wizard in MsvC++ but i can''t throw away the rest of my game. This is how it worked under Console app: #include <dos.h> #include <stdio.h> #include <conio.h> #define DATA 0x378 // Address of parallel port void main() { _outp(DATA, 10); // outputs a binary 10 on data lines // under Borland this function is // outport(DATA, [int/hex value]) } so the above would put 00001010 on the data lines and drive tha anode side of my 8bar led display with +5v.

Share this post


Link to post
Share on other sites
It''s likely that a console prog would collapse on NT as well, due to more robust restrictions on accessing ring0 from ring3. Look into GDI for printer device contexts. Also take a look at the winio dll at internals.com for accessing the parallel port. In the worse case, you might have to write a small device driver of somekind.

Share this post


Link to post
Share on other sites
Writing a device driver means getting the Device Driver Kit specific to the target platform - W95, W98, WME, WNT, W2K, WXP - each of them are large, but not as large as the PSDK. I have a copy of the DDK for W2K. It even comes with a compiler! cl.exe because you can''t use the MSVC compiler. Most of the DDK consists of special headers for kernel mode. There are a couple of interesting newsgroups related to the topic.

But you don''t need to do any of that. The winio dll will let you access the parallel port with a command as simple as "GetPortVal(0x378,&dwPortVal,4);". Internals.com

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
IIRC, in NT you can access the parallel port using CreateFile("\\\\.\\LPT",...). Look on MSDN.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
You can probably use the parallellport pretty much as you would a COM-port.

CreateFile("LPT1" . . . . .) or whatever port it is.
GetCommState(. . .)
SetCommState(. . .)
WriteFile(. . . .)
CloseHandle(. . . .)

Just fill in the dots with a trip to MSDN.

Share this post


Link to post
Share on other sites
quote:
Original post by Anonymous Poster
You can probably use the parallellport pretty much as you would a COM-port.

CreateFile("LPT1" . . . . .) or whatever port it is.
GetCommState(. . .)
SetCommState(. . .)
WriteFile(. . . .)
CloseHandle(. . . .)


Man, wouldn''t that be nice?
Try searching MSDN for it...

quote:
Anonymous Poster
IIRC, in NT you can access the parallel port using CreateFile("\\\\.\\LPT",...). Look on MSDN.


Did a quick search, hoping you were right... 0 hits

The only information I found on MSDN last time I checked for this, was info about making a driver to do what you needed. From what I''ve gathered, you have to handle the ISR for the port, since parallel transfers are unbuffered (unlike serial).
I wasn''t that hot on the project, and dropped it when it started to get hard...

I''d be happy to hear (and see) contrary information...

Another alternative, is to search for an NT driver that provides a serial-like interface.

Share this post


Link to post
Share on other sites
I´ve found a driver on the the internet for free. The webpage is: http://www.driverlinx.com//DownLoad/DLPortIO.htm?ID=1027728744560 . I haven´t tested it yet with the multimeter, but I´m pretty sure it works. Oh! I tested it with a DX App (making a couple of functions calls inside the main loop) and the program didn´t crash at all.

Share this post


Link to post
Share on other sites
Hey guys/gals
Thanks for the replies. I will check out LessBread's suggestion as well as Ignacio's link today. I did check out the MSDN disks, but I didn't find anything promising with regard to LPT1, it seems that I would be better off using the serial(COM) port intstead. I tried using "outfile" and this did send a print job , that coincidentally errored, to the default printer device (Generic IBM Text Only). This obviously did not work since the driver is not compatible and I haven't done anything with the electronics to send back as ready to RCV or ACK signal.

Additionaly,
for the time being I decided to Write [Virtual Parallel Port Emulator and 10-bar Led] Classes. Hence my next question. the _outp() function was great because it converted my decimal "decval" to binary and set the corresponding bits on LPT1. So as 'decval' increased the the function would automatically give me a binary counting clock on the LED display.
How should I model these objects in my class, and how can i convert the decimal index to binary for the pins.

assume:
int decvalue=0 ; decimal value initalized will increment to 128

for simplicity lets say that the Class acts more like a struct and everything is public and assume that other variables are global. My first bad idea was to model the data ports in array; short int port[8] = {0,0,0,0,0,0,0,0} // data line 0-7 set to off

Then I index into this array to change the bits, which eventually drives the (sprites showing the value of the ports) on the display. This obviously takes more memory than bit fields
, but it works. The problem is: decvalue will be a decimal number staring at 0 and incrementing to 128. What is the best method to take the decimal value and change the corresponding array elements to give the binary equivalent. I have a brute force method, but it just looks ugly.

It contains ints that hold the binary place holders.
eg. 1,2,4,8,16,32,64,128
I use an 'if else' to first check if decval is = to one of these
then set the bit that corresponds to the index. Next I look into the array checking to see if decval is less than each place holder. eg. if (decval<128){}; if(decval<64) etc. and when this is true I perform a division, set the current bit, and repeat this process until the decval = 0. (There are other steps like adding the values and such but you get the idea).

There has to be an easier way. Should I do a recursive solution? Is there a function that can handle this for me? Is my structure completely wrong? Should I use bit fields? If so, How can access and change each bit in the field to correspond to decval?

[Please dont' suggest that I create 128 arrays to hold the binary equivalent] My firend actually suggested this.

[edited by - zenassem on July 29, 2002 9:30:29 AM]

Share this post


Link to post
Share on other sites
LessBread: Thanks for the reply.

My main issue is not with why _outp() works. I am now emulating a Parallel port and Led display. In the source code I want to represent the 8 data lines of the port by an array. eg pinoutarray[8]. now the diplay function looks at this array to decide which sprites(images) it needs to display. for example if the ellements in the pinoutarray[8] were = to {0,0,1,0,0,1,1,1}; then the display would turn off the bitmap images for pin 0,1,3,4 and turn on the bitmap images for pins 2,5,6,7. This all works. but what i want to do is to create a display of a counting binary clock. eg.
00000000
00000001
00000010
00000011 etc.

To count up to 128 I have a decimal value int named "decval"
"decval" in a loop and counts form 0 to 128. I need some way to have the array elements correspond to "decval" value. so if decval==7 the array elements in pinoutarray[8] would look like this. 00000111 {note i am listing the elements for 7 to 0 so it will match a binary representation}

[edit] My thanks to lessbreead didn't look sincere, and read back it sounded as though I was frustrated.

[edited by - zenassem on July 29, 2002 10:43:09 AM]

Share this post


Link to post
Share on other sites
Ok. That makes more sense! Somehow I thought that you wanted to send that data to the port. Now I see that you want to send it to the gui.

Does the display really need to use individual sprites? I'm thinking that it might be easier to just convert the decimal number to a string representing the binary value and then send that to the display. If you use a fixed sized font the "numbers" will remain aligned.

Alternatively - since there are only two binary digits, you only need to store two sprites - one for 0 and one for 1. Then just check each bit of the byte to see if it's set and if it is display 1 in that slot and 0 otherwise. Too bad you have to go up to 128. If you only needed to go to 127 you could bypass checking the msb.

// Edit
quote:

My thanks to lessbreead didn't look sincere, and read back it sounded as though I was frustrated.

Don't worry about it. I have much thicker skin that that.

[edited by - lessbread on July 29, 2002 10:57:46 AM]

Share this post


Link to post
Share on other sites
yes, it does need to use sprites(blitter objects) because the program graphically depicts the parallel port and the 8bar Led. It graphically shows the pins that are on and the lights up the 8bar led. I don''t have to go up to 128. 127 is fine. But it really isn''t a big deal as 128 is represented pinoutarray[8]={0,0,0,0,0,0,0,1}; [note: this time i am showing the bits as the y would be initalized intto the array.] and so therefore this is an easy test case as you can see from my earliesr post. I have ints that represent the powers. If dec==128 then i just turn bit7 on. The hard part is that the conversions must be done real time. I cannot just have 128 arrays. Because that would just be ugly and brute. Also i will need to be able to run other patterns other than just counting up.














Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Wouldn''t this do the job for decimal to binary conversion? Or is there something wrong with this method I don''t know about?

Don''t laugh at this code too much, hehe.


  
#include <iostream>

using std::cout;
using std::endl;

int main()
{

int test=116;
int binaryValue[8];

cout << "Bit position" << endl;
cout << "7 " << "6 " << "5 " << "4 " << "3 "
<< "2 " << "1 " << "0 " << endl <<
"======================================" << endl;

for (int i=0; i<=7; i++)
{
(test & (1 << i)) ? binaryValue[i] = 1 : binaryValue[i] = 0;
}

for(i=7; i>=0; i--)
{
cout << binaryValue[i] << " ";
}


cout << endl;

if (test & 128)
cout << "Test and 128" << endl << endl;

return 0;
}

Share this post


Link to post
Share on other sites
Well the real time requirement throws things off, but I think it better to first get something working and then work on improving the speed.

I don''t think you''ll need 127 arrays. This is what I would do

First blit the background for all 8 slots
[0|0|0|0|0|0|0|0]

This sprite should cover the entire range and it should be all zeros. Then I would check each bit of the data value to see if it was set and if it was I would blit a smaller sprite [1] in the corresponding slot. (note that I''m using [] to represent a square sprite not an array)

if ( data & 1 << 8 ) { blit [1] in slot 8 } // else blit nothing
if ( data & 1 << 7 ) { blit [1] in slot 7 } // else blit nothing
if ( data & 1 << 6 ) { blit [1] in slot 6 } // else blit nothing
if ( data & 1 << 5 ) { blit [1] in slot 5 } // else blit nothing
...

If you think the conditional check will cost too much, an alternative possibility is to use the result from the and as an index into an array storing two sprites - [0],[1] -

sprite[0] -> [0]
sprite[1] -> [1]

for each slot
blit(slot, sprite[data & 1 << slot])

But i think it more likely that the blit will cost more than the conditional - the first example is worse case 9 blits, the second example is always 9 blits.

If you can only afford one blit - then you''re gonna need 127 sprites. Perhaps you can build them at runtime using one of these approaches and then just use the data value as an index into the sprite array.

Am I in the ball park here?

Share this post


Link to post
Share on other sites
Lessbread,

I think you are in the ball park. I haven''t looked fully through Anon. poster''s code yet. The only part I am confused about with your solution is "data & 1". I am not sure how exactly this works. Is data a decimal number? Just to clarify, I am not concerned about how many times I need to blit. In fact, that''s how my code does it the way it is. I check the array for each bit [index] in a for loop. If the value is 1 I blit. If 0 I hide the sprite. I have no problem with this.
My problem came from how do I set the bits in the array from looking at the decimal #.

example my decimal number (data) is 10.
I need to take the number 10. and now index into the array to set the bits, necessary. [I know how to index into an array. I know how to set any particular bits. I know how to read these bits into the display. !!!!The thing I was unsure of is how to look at "data", then flip the corresponding binary bits!!!. in this example the array would be

pinoutarray[0]=0; //in the actual code this is in an indexed
pinoutarray[1]=1; // for loop
pinoutarray[2]=0;
pinoutarray[3]=1;
//all the rest would be 0

When data increments to 11 pinoutarray[0]=1 as well; but I need an algorithm that will be able to look at the decimal value, then know which bits to set high based on that value. This algorithm needs to work for every possible # from 0 to 128.

In other words I DON''T want to do this: (pseudo code)

if data=0 then pinoutarray[]={0,0,0,0,0,0,0,0}
if data=1 then pinoutarray[]={1,0,0,0,0,0,0,0}
if data=2 then pinoutarray[]={0,1,0,0,0,0,0,0}
if data=3 then pinoutarray[]={1,1,0,0,0,0,0,0}
if data=4 then pinoutarray[]={0,0,1,0,0,0,0,0}
...
if data=127 then pinoutarray[]={1,1,1,1,1,1,1,0}
if data=128 then pinoutarray[]={0,0,0,0,0,0,0,1}


Share this post


Link to post
Share on other sites
Ok. That's good to hear.

What I call "data" is your number 10 - it's just an integer value - you could use an int or a char. What ever value corresponds with to the data that you want to display.

What that code does is check each bit of the char to see if it's set. It does that using a bitwise AND - here's a cut and paste from some old notes of mine

// - snip

AND &
- operates like a 2 bit truth table
- if either bit is zero, yield bit is zero too
- both bits must be one for the yield bit to be one
- x & 0 = 0 | x & 1 = x

0011
& 0101
----
0001


using hex simplifies - to wit
0x80 = 10000000
0x40 = 01000000
0x20 = 00100000
0x10 = 00010000
0x08 = 00001000
0x04 = 00000100
0x02 = 00000010
0x01 = 00000001

// - snip

1 << slot - left shift a bit into "slot"

0x80 == 10000000 == 1 << 7 == 128
0x40 == 01000000 == 1 << 6 == 64
0x20 == 00100000 == 1 << 5 == 32
0x10 == 00010000 == 1 << 4 == 16
0x08 == 00001000 == 1 << 3 == 8
0x04 == 00000100 == 1 << 2 == 4
0x02 == 00000010 == 1 << 1 == 2
0x01 == 00000001 == 1 << 0 == 1



You can save a bit of time by using the hex values explicitly instead of shifting 1 left X number of slots.

Note that the AND returns 0 or 1 - and that those two values correspond with false and true respectively. So if the bit is set, the AND returns 1 indicating that the [1] sprite should be blit - else the AND returned 0 and nothing should be done since the back ground has already been filled with zeros due to the first blit.

The approach should actually be more like - blit the "zero" background to a back buffer, then blit each slot with [1] as needed, then blit the back buffer to the front buffer.

What I'm saying is that the data number itself carries the bit pattern with it.

Decimal 53 Binary 00110101 - from the look of those arrays it appears that you have the bits in reverse order so that 53 would be 10101100. That won't make a difference as far as the logic of whether a given bit in the number is set or not. It does mean that you'll have to take extra care to keep the display offsets in proper corresondence with each bit.


slot 76543210
(53) 00110101
(127) 01111111

slot 01234567
(53) 10101100
(127) 11111110


You don't need to do that array stuff, because the index value/data value contains the bit pattern.

[edited by - lessbread on July 29, 2002 1:09:43 PM]

Share this post


Link to post
Share on other sites
LessBread:
Thanks sooo much! I finally understand what you mean. I didn''t know how to look at the actual bits that make up a decimal number, nor how to express the question, since I didn''t know that this could be done. Sorry for putting you through all of that. I appreciate you staying with me and answering my question. In retrospect, it must have been unnerving for you to figure out why I was having any problem to begin with.

Share this post


Link to post
Share on other sites
Not a problem. I''m glad you didn''t find all that condescending or anything. After I posted it I wondered if you might already have known about bit setting and retrieving, but I guess they don''t teach bitwise stuff that much any more. I didn''t find it unnerving at all.

Here is the rest of my old notes cleaned up a little so you can have a reference if you need it.


  
BITWISE OPS :

merging ops require data items to be of the same type (ie. have the same number of bits)
operates on each corresponding bit in each data item in turn to yield a third bit in the resulting data item
each bit is independent of the others - there is no arithmetical carry over from bit column to bit column

AND &
- operates like a 2 bit truth table
- if either bit is zero, yield bit is zero too
- both bits must be one for the yield bit to be one

0011
& 0101
----
0001

FFTT
& FTFT
----
FFFT

XOR ^
- bitwise exclusive OR
- returns 1 when either bit but not both are 1
- an XOR applied twice yields the original operand

0011
^ 0101
----
0110

FFTT
^ FTFT
----
FTTF

OR |

- two bits ORed yield 1 if either or both bits are 1 and 0 if both bits are 0
- used to combine bits from different variables into a single variable

0011
| 0101
----
0111

FFTT
| FTFT
----
FTTT


BITKEY
X 0011
Y 0101
op====
& 0001
^ 0110
| 0111

BITKEY
X FFTT
Y FTFT
op====
& FFFT
^ FTTF
| FTTT


0x80 == 10000000 == 1 << 7 == 128
0x40 == 01000000 == 1 << 6 == 64
0x20 == 00100000 == 1 << 5 == 32
0x10 == 00010000 == 1 << 4 == 16
0x08 == 00001000 == 1 << 3 == 8
0x04 == 00000100 == 1 << 2 == 4
0x02 == 00000010 == 1 << 1 == 2
0x01 == 00000001 == 1 << 0 == 1


BITWISE LEFT <<
- always shifts in 0 bits from the right discarding left most bits
- each bit shifted is equivalent to multiplying by 2
- so shifting left 3 bits is like muliplying by 8

intVar << x (places)

RIGHT SHIFT >>
- moves each bit in operand to the right the indicated number of places
- shifting right one bit same as dividing operand by 2

intVar >> x (places)

- zeros are shifted from the left and the right most bit disappear
- except in the case of signed types where a 1 in the left most bit indicates a negative number
- 1''s are shifted in to preserve sign

if the signed bit is set in a signed operand, right shifts will shift 1''s in from the left


BITWISE COMPLEMENT ~ (unary)
- reverses each bit
- complementing a number twice returns the orginal number

Share this post


Link to post
Share on other sites