Introduction
Top Next

TVicLPT 1.3

Programmer's toolkit for directly accessing LPT hardware from a
Win32-application

Copyright(c) Victor Ishikeev 2001-2003
http://www.entechtaiwan.com/tools.htm
tools@entechtaiwan.com


What is TVicLPT?
Previous Top Next

The TVicLPT is a programming tool that gives you easy access to and control over parallel port hardware (LPT) directly from a Win32 application.
TVicLPT is available as a TVicLPT ActiveX Control Module (OCX) as well as native Borland TVicLPT VCL component.

TVicLPT's main capabilities are:

· (NEW in 1.3 version!) detection of all LPT ports (even on non standart addresses)

· detecting all possible LPT modes including SPP, PS/2, Fast Centronix, EPP, ECP

· simple switching to any possible mode without the bit manipulation

· direct access "by name" to any hardware port of current LPT

· mass input/output in EPP mode

· simple direct access to any bit of any port of current LPT

· direct access and manipulation of any pin on LPT D-25 connector

· handling of hardware interrupts incoming from the LPT ACK line

Contact info:

This tool is maintained at http://www.entechtaiwan.com/tools.htm , e-mail: tools@entechtaiwan.com


Programming Languages Supported

At this time TVicLPT includes test examples for the following languages:

· Borland Delphi (versions 2-7)

· Borland C++Builder (versions 1-6)

· Microsoft Visual Basic 6.0

· Microsoft Visual C++ 6.0

Of course, you can try TVicLPT with any other programming language providing OLE container capability.


TVicLPT Demo Version and Registration

To evaluate TVicLPT's functionality, simply download and install the TVicLPT demo version (700 KB). This demo includes many test examples showing how to use TVicLPT with each programming language listed above. The TVicLPT demo version is fully functional so you can write and debug your application before you buy one of the following licenses to use or distribute the drivers and OCX.

Single License is $65 U.S., purchase online..

Commercial License is $195 U.S., purchase online. This license grants you the right to distribute TVicLPT drivers and OCX as part of your software without having to pay royalties and gives you the option of e-mailing us with a new name for the drivers and OCX so it appears you wrote these yourself.

Phone and Fax Orders:

Single and Commercial licenses can also be ordered over the phone or by fax.

US customers call toll-free 1-888-REG-IT-80.

International customers call 770-497-9126.

Fax orders are sent to 770-497-9234.

When placing your order, please refer to the following product IDs:

· TVicLPT Single License: 41124

· TVicLPT Commercial License: 42772


Installation

There are two main parts of installation process:

· Common part of installation (full software package installation)

· Compiler specific installation

Common part of installation

Run TVicLptDemoInstall.exe or TVicLptReg.exe. This is a Windows-based application you can run from either the Start or Run button, or from an MS-DOS prompt. Read the Software License Agreement and, if you agree with its terms, click I agree with the above terms and conditions to accept the Agreement and click Next . Select the drive and directory where you want to install the TVicLPT and then click Start . After the installation of components is completed, click OK . Click Yes button to reboot your PC after installation.

Compiler specific installation

Note:
Information below is applicable only for demo version of TVicLPT. Registered users refer to install.txt file provided in distributive.

Visual Basic: No additional installation required because the TVicLPT ActiveX Control was already registered by the installation program. Just go to <TVicLPT>/VB/ directory, then load and run any test application.

Visual C++: Menu->Project->Add to project->Files->.. browse to \Component\MSVC\VicLPT.obj, VicLPT.h..Ok.

Borland Delphi 2.0: Menu->Component->Install->Add->.. browse to \Component\Delphi2\LptUnit.dcu..->Ok.

Borland Delphi 3.0-7.0: File->Open->Delphi Package Source(*.dpk)->..browse to \Component\DelphiX\lpt_dX.dpk->Open, where "X" is a Delphi version number. Press "Compile" then press "Install".

Borland C++Builder 1.0: Menu->Component->Install->Add->.. browse to \Component\Builder1\LptUnit.obj..->Ok.

Borland C++Builder 3.0-6.0: Menu->Component->Install Packages->Add->lpt_bX.bpl->Ok, where "X" is a C++Builder version number.

Notes:

· For all Delphi/C++Builder versions: The TVicLPT component should appear at the "Drivers" tab page of the components palette.
· Files required for commercial users are included in Component\Kernel folder


TVicLPT Properties And Methods

TVicLPT.OCX

TVicLPT VCL Component
for Borland Delphi and C++Builder

Properties and Methods

Copyright(c) Victor Ishikeev 1997-2002
http://www.entechtaiwan.com/tools.htm
tools@entechtaiwan.com


Read this first!

Important Notes:

· All TVicLPT properties/methods/events are the same for the TVicLPT VCL component and for the TVicLPT ActiveX Control (OCX).

· The Delphi syntax is applicable for TVicLPT VCL component

· The C++Builder syntax is applicable for TVicLPT VCL component

· The Visual Basic syntax is applicable for TVicLPT ActiveX Control (OCX)

· Visual C++ use it's own methods defined in VicLPT.h


Common Properties and Methods

· Active Property

· NumLPTs Property

· AddCustomPort Method

· Acquired Property


Active Property

Data Type : Integer

Sets and returns the state of the TVicLPT device driver (open or closed).

BC++ syntax (VCL): object->Active [ = value ];

Delphi syntax (VCL): object.Active [:= value ];

VB syntax (OCX): object.Active [ = value ]

VC syntax : object.SetActive ( value );

The settings for value are:

1 - open the first TVicLPT driver instance
2 - open the second TVicLPT driver instance
0 - close TVicLPT driver instance

Returns:

1 - if the driver was opened
0 - if closed, not opened, or fails

Remarks:

Opens/closes the tviclpt.vxd virtual device driver under Windows 95/98/ME or tviclpt.sys kernel mode device driver under Windows NT/2000/XP, providing direct access to the LPT hardware. TVicLPT can be used by two applications at same time.
To check if the driver was successfully opened, you must read the Active property value back. If returns 1 or 2 then the driver was opened, if 0 - fails. Here is a Delphi example:

TVicLPT1.Active := 1; // Try to open the first driver instance
If TVicLPT1.Active = 0 then
  ShowMessage('Can''t open TVicLPT driver!')
else
[..success..]

Keep the driver opened then close at end of your application by setting the Active property to 0.


NumLPTs Property

Data Type : Integer

Returns how many LPT ports are installed on your PC.

BC++ syntax (VCL): object->NumLPTs;

Delphi syntax (VCL): object.NumLPTs;

VB syntax (OCX): object.NumLPTs

VC syntax : object.GetNumLPTs ();

Returns:

How many LPTs are installed on PC

Remarks:

Initially shows how many "standard" ports was founded on your PC. You can enter an address of a user port with a non-standard address later (see AddCustomPort method)


AddCustomPort Method

Allows to enter an address of a user "non-standard" port.

BC++ syntax (VCL): object->AddCustomPort(CustomBaseAddress);

Delphi syntax (VCL): object.AddCustomPort(CustomBaseAddress);

VB syntax (OCX): object.AddCustomPort(CustomBaseAddress As Integer)

VC syntax : object.AddCustomPort ( short CustomBaseAddress );

Parameters:

CustomBaseAddress - single-precision integer value (word) indicating the base address of custom LPT port.

Remarks:

Check out whether or not the port with the same base address already exists! In other case you will have two ports with the same base addresses.


Acquired Property

Data Type : Integer

Windows 95/98/ME only! Allows to prevent other applications (include printing system) to use current LPT port.

BC++ syntax (VCL): object->Acquired() [ = value ];

Delphi syntax (VCL): object.Acquired [ := value ];

VB syntax (OCX): object.Acquired [ = value ]

VC syntax : object.Acquired ( value );

The settings for value are:

1 - lock the current LPT
0 - unlock the current LPT

Returns:

LPT_NOT_ACQUIRED
LPT_ACQUIRE_SUCCESS
LPT_ACQUIRE_REFUSED (already acquired by other application)
LPT_ACQUIRE_BAD_PORT (bad LPT number or Windows NT detected)
LPT_ACQUIRE_NOT_OPENED (TVicLPT driver was not opened);


Current LPT and Mode

· CurrentLPT Property

· MaxLptMode Property

· CurrentLptMode Property

· EPPEnabled Property


CurrentLPT Property

Data Type: Integer

Sets and returns the current LPT number.

BC++ syntax (VCL): object->CurrentLPT [ = value ];

Delphi syntax (VCL): object.CurrentLPT [:= value ];

VB syntax (OCX): object.CurrentLPT [= value ]

VC syntax : object.SetCurrentLPT ( value ); / short object.GetCurrentLPT ();

The settings for value are:

1,2,... - LPT number (LPT1, LPT2 and so on).

Returns:

The current LPT number

Remarks:

Almost all TVicLPT properties and methods are applicable to the current LPT. That is why you need to select a current LPT number before use any other TVicLPT capabilities.


CurrentLptMode Property

Data Type : Integer

Sets and returns the current mode of current LPT.

BC++ syntax (VCL): object.CurrentLptMode[ = value ];

Delphi syntax (VCL): object.CurrentLptMode [:= value ];

VB syntax (OCX): object.CurrentLptMode [= value ]

VC syntax : object.SetCurrentLptMode ( value ); / short object.GetCurrentLptMode ();

The settings for value are:

LPT_SPP_MODE
LPT_PS2_MODE
LPT_EPP_MODE
LPT_FAST_CENTRONIX
LPT_ECP_MODE

Returns:

One value from the list:

LPT_SPP_MODE
LPT_PS2_MODE
LPT_EPP_MODE
LPT_FAST_CENTRONIX
LPT_ECP_MODE

Remarks:

You must read the value back immediately after you set the new LPT mode to make sure the selected mode is supported by current LPT.


MaxLptMode Property

Data Type: Integer

Returns the "maximal" possible mode of current LPT.

BC++ syntax (VCL): object->MaxLptMode;

Delphi syntax (VCL): object.MaxLptMode;

VB syntax (OCX): object.MaxLptMode

VC syntax : object.GetMaxLptMode ( value );

Returns:

Value from the following list:

· LPT_NOT_PRESENT
· LPT_SPP_MODE
· LPT_PS2_MODE
· LPT_EPP_MODE
· LPT_FAST_CENTRONIX
· LPT_ECP_MODE

Remarks:

Remember that ECP printer port can be switched to the following "lower" modes: Fast Centronix, PS/2, SPP and even EPP (if our LPT was configured as ECP+EPP in BIOS setup program).


EPPEnabled Property

Data Type : Boolean

Check if the EPP mode is supported by current LPT.

C++ syntax: object->EPPEnabled;

Delphi syntax (VCL): object.EPPEnabled;

VB syntax (OCX): object.EPPEnabled

VC syntax : short object.GetEPPEnabled ( );

Returns:

TRUE - EPP mode is supported
FALSE - EPP mode not supported

Remarks:

You can enable the EPP or ECP+EPP capability in BIOS Setup Program at PC boot time


Work with Ports

· BasePortAddress Property

· ReadMode Property

· DataPort Property

· StatusPort Property

· ControlPort Property

· EcrPort Property

· CfgaPort Property

· CfgbPort Property

· FifoPort Property

· EPPAddressPort Property

· EPPDataPort Property


BasePortAddress Property

Data Type : Integer

Returns the base port address (data register) of current LPT.

BC++ syntax (VCL): object->BasePortAddress;

Delphi syntax (VCL): object.BasePortAddress;

VB syntax (OCX): object.BasePortAddress

VC syntax : short object.GetBasePortAddress ( );

Returns:

Base port address value of current LPT


ReadMode Property

Data Type: Boolean

Allows to switch the data register of current LPT to "read" or "write" mode.

BC++ syntax (VCL): object->ReadMode [ = value ];

Delphi syntax (VCL): object.ReadMode [:= value ];

VB syntax (OCX): object.ReadMode [= value ]

VC syntax : short object.GetReadMode ( ); / object.SetReadMode ( value);

The settings for value are:

0 - sets the data register to "write only" mode (default).
1 - sets the data register to "read only" mode (not supported by SPP!).

Returns:

FALSE - "write" mode enabled
TRUE - "read" mode enabled


DataPort Property

Data Type: Integer

Allows to read one byte from or write one byte to the Data Register of current LPT.

BC++ syntax (VCL): object-> DataPort [ = value ];

Delphi syntax (VCL): object.DataPort [:= value ];

VB syntax (OCX): object.DataPort [= value ]

VC syntax : short object.GetDataPort ( ); / object.SetDataPort ( value);

The settings for value are:

One byte value to write to the LPT Data Register

Returns:

The byte read from the LPT Data Register.

Remarks:

The current LPT must be in corresponding mode - read or write, see ReadMode property.


StatusPort Property

Data Type: Integer

Allows to read one byte from or write one byte to the Status Register of current LPT.

BC++ syntax (VCL): object->StatusPort [ = value ];

Delphi syntax (VCL): object.StatusPort [:= value ];

VB syntax (OCX): object.StatusPort [= value ]

VC syntax : short object.GetStatusPort ( ); / object.SetStatusPort ( value);

The settings for value are:

One byte value to write to the LPT Status Register

Returns:

The byte read from the LPT Status Register.


ControlPort Property

Data Type: Integer

Allows to read one byte from or write one byte to the Control Register of current LPT.

BC++ syntax (VCL): object->ControlPort [ = value ];

Delphi syntax (VCL): object.ControlPort [:= value ];

VB syntax (OCX): object.ControlPort [= value ]

VC syntax : short object.GetControlPort ( ); / object.SetControlPort ( value);

The settings for value are:

One byte value to write to the LPT Control Register

Returns:

The byte read from the LPT Control Register.


EcrPort Property

Data Type: Integer

Allows to read one byte from or write one byte to the ECR Register of current LPT.

BC++ syntax (VCL): object. EcrPort[ = value ];

Delphi syntax (VCL): object.EcrPort [:= value ];

VB syntax (OCX): object.EcrPort [= value ]

VC syntax : short object.GetEcrPort ( ); / object.SetEcrPort ( value);

The settings for value are:

One byte value to write to the ECR Register of current LPT

Returns:

The byte read from the ECR Register of current LPT


CfgaPort Property

Data Type: Integer

Allows to read one byte from or write one byte to the CFGA register of current LPT.

BC++ syntax (VCL): object-> CfgaPort[ = value ];

Delphi syntax (VCL): object.CfgaPort [:= value ];

VB syntax (OCX): object.CfgaPort [= value ]

VC syntax : short object.GetCfgaPort ( ); / object.SetCfgaPort ( value);

The settings for value are:

One byte value to write to the CFGA Register of current LPT

Returns:

The byte read from the CFGA Register of current LPT


CfgbPort Property

Data Type: Integer

Allows to read one byte from or write one byte to the CFGB register of current LPT.

BC++ syntax (VCL): object-> CfgbPort[ = value ];

Delphi syntax (VCL): object.CfgbPort [:= value ];

VB syntax (OCX): object.CfgbPort [= value ]

VC syntax : short object.GetCfgbPort ( ); / object.SetCfgbPort ( value);

The settings for value are:

One byte value to write to the CFGB Register of current LPT

Returns:
The byte read from the CFGB Register of current LPT


FifoPort Property

Data Type: Integer

Allows to read one byte from or write one byte to the FIFO register of current LPT.

BC++ syntax (VCL): object-> FifoPort[ = value ];

Delphi syntax (VCL): object.FifoPort [:= value ];

VB syntax (OCX): object.FifoPort [= value ]

VC syntax : short object.GetFifoPort ( ); / object.SetFifoPort ( value);

The settings for value are:

One byte value to write to the FIFO Register of current LPT

Returns:

The byte read from the FIFO Register of current LPT


EPPAddressPort Property

Data Type: Integer

Allows to read one byte from or write one byte to the EPP Address register of current LPT.

BC++ syntax (VCL): object-> EPPAddressPort[ = value ];

Delphi syntax (VCL): object.EPPAddressPort [:= value ];

VB syntax (OCX): object.EPPAddressPort [= value ]

VC syntax : short object.GetEPPAddressPort ( ); / object.SetEPPAddressPort ( value);

The settings for value are:

One byte value to write to the EPP Address Register of current LPT

Returns:

The byte read from the EPP Address Register of current LPT


EPPDataPort Property

Data Type: Integer

Allows to read one byte from or write one byte to the EPP Data register of current LPT.

BC++ syntax (VCL): object-> EPPDataPort[ = value ];

Delphi syntax (VCL): object.EPPDataPort [:= value ];

VB syntax (OCX): object.EPPDataPort [= value ]

VC syntax : short object.GetEPPDataPort ( ); / object.SetEPPDataPort ( value);

The settings for value are:

One byte value to write to the EPP Data Register of current LPT

Returns:

The byte read from the EPP Data Register of current LPT


Work with Bits

· DataPortBit Property

· StatusPortBit Property

· ControlPortBit Property

· EcrPortBit Property

· CfgaPortBit Property

· CfgbPortBit Property


DataPortBit Property

Data Type: Integer

Set or returns the value (0 or 1) of the requested bit in a LPT's Data Register.

BC++ syntax (VCL): object->DataPortBit[int BitNumber] [ = value ];

Delphi syntax (VCL): object.DataPortBit[BitNumber:Integer] [:= value ];

VB syntax (OCX): object.DataPortBit(BitNumber As Integer) [= value ]

VC syntax : short object.GetDataPortBit ( short BitNumber); / object.SetDataPortBit ( short BitNumber,short value);

Parameters:

BitNumber - requested bit number (0..7);
value - 1 to set or 0 to reset bit

Returns:

The value (0 or 1) of the requested bit.

Remarks:

The current LPT must be in corresponding mode - read or write, see ReadMode property.


StatusPortBit Property

Data Type: Integer

Set or returns the value (0 or 1) of the requested bit in a LPT's Status Register.

BC++ syntax (VCL): object->StatusPortBit[int BitNumber] [ = value ];

Delphi syntax (VCL): object.StatusPortBit[BitNumber:Integer] [:= value ];

VB syntax (OCX): object.StatusPortBit(BitNumber As Integer) [= value ];

VC syntax : short object.GetStatusPortBit ( short BitNumber); / object.SetStatusPortBit ( short BitNumber,short value);

Parameters:

BitNumber - requested bit number (0..7);
value - 1 to set or 0 to reset bit

Returns:

The value (0 or 1) of the requested bit.


ControlPortBit Property

Data Type: Integer

Set or returns the value (0 or 1) of the requested bit in a LPT's Control Register.

BC++ syntax (VCL): object->ControlPortBit[int BitNumber] [ = value ];

Delphi syntax (VCL): object.ControlPortBit[BitNumber:Integer] [:= value ];

VB syntax (OCX): object.ControlPortBit(BitNumber As Integer) [= value ]

VC syntax : short object.GetControlPortBit ( short BitNumber); / object.SetControlPortBit ( short BitNumber,short value);

Parameters:

BitNumber - requested bit number (0..7);
value - 1 to set or 0 to reset bit

Returns:

The value (0 or 1) of the requested bit.


EcrPortBit Property

Data Type: Integer

Set or returns the value (0 or 1) of the requested bit in a LPT's ECR Register.

BC++ syntax (VCL): object->EcrPortBit[int BitNumber] [ = value ];

Delphi syntax (VCL): object.EcrPortBit[BitNumber:Integer] [:= value ];

VB syntax (OCX): object.EcrPortBit(BitNumber As Integer) [= value ]

VC syntax : short object.GetEcrPortBit ( short BitNumber); / object.SetEcrPortBit ( short BitNumber,short value);

Parameters:

BitNumber - requested bit number (0..7);
value - 1 to set or 0 to reset bit

Returns:

The value (0 or 1) of the requested bit.


CfgaPortBit Property

Data Type: Integer

Set or returns the value (0 or 1) of the requested bit in a LPT's CFGA Register.

BC++ syntax (VCL): object->CfgaPortBit[int BitNumber] [ = value ];

Delphi syntax (VCL): object.CfgaPortBit[BitNumber:Integer] [:= value ];

VB syntax (OCX): object.CfgaPortBit(BitNumber As Integer) [= value ]

VC syntax : short object.GetCfgaPortBit ( short BitNumber); / object.SetCfgaPortBit ( short BitNumber,short value);

Parameters:

BitNumber - requested bit number (0..7);
value - 1 to set or 0 to reset bit

Returns:

The value (0 or 1) of the requested bit.


CfgbPortBit Property

Data Type: Integer

Set or returns the value (0 or 1) of the requested bit in a LPT's CFGB Register.

BC++ syntax (VCL): object->CfgbPortBit[int BitNumber] [ = value ];

Delphi syntax (VCL): object.CfgbPortBit[BitNumber:Integer] [:= value ];

VB syntax (OCX): object.CfgbPortBit(BitNumber As Integer) [= value ]

VC syntax : short object.GetCfgbPortBit ( short BitNumber); / object.SetCfgbPortBit ( short BitNumber,short value);

Parameters:

BitNumber - requested bit number (0..7);
value - 1 to set or 0 to reset bit

Returns:

The value (0 or 1) of the requested bit.


Work with the Pins

· Pin Property

· PulseStrobe Method

· PulseStrobeAndWaitBusy Method


Pin Property

Data Type: Boolean

Set or returns an electrical level from the select pin of curren LPT's D25 connector.

BC++ syntax (VCL): object->Pin[int PinNumber] [ = value ];

Delphi syntax (VCL): object.Pin[PinNumber:Integer] [:= value ];

VB syntax (OCX): object.Pin(PinNumber As Integer] [= value ]

VC syntax : short object.GetPin ( short PinNumber); / object.SetPin ( short PinNumber, short value);

Parameters:

PinNumber - requested pin number (1..25);
value - TRUE to set an electrical level high, or FALSE to set low.

Returns:

FALSE - if an electrican level on requested pin is low
TRUE - if an electrican level on requested pin is high

Remarks:

1. The current LPT must be in corresponding mode - read or write, see ReadMode property.
2. Not all pins are accessible for this operation. Read LPT documentation or run Bits example for more info.


PulseStrobe Method

Generate a short impulse (strobe signal) at LPT's STROBE line (Pin 1).

BC++ syntax (VCL): object->PulseStrobe(ULONG DelayCycles);

Delphi syntax (VCL): object.PulseStrobe(DelayCycles: Longint);

VB syntax (OCX): object.PulseStrobe(ByVal DelayCycles As Long)

VC syntax : object.PulseStrobe ( short DelayCycles);

Parameters:

DelayCycles - the length of strobe in relative time units. 0 value means the strobe should be as short as possible.


PulseStrobeAndWaitBusy Method

Generate an impulse (strobe signal) at LPT's STROBE line (Pin 1) but the level goes low only when the BUSY signal becomes active from an external device.

BC++ syntax (VCL): [value=] object->PulseStrobeAndWaitBusy(int TimeOut);

Delphi syntax (VCL): [value:=] object.PulseStrobeAndWaitBus(TimeOut: Integer);

VB syntax (OCX): [value:=] object.PulseStrobeAndWaitBus(TimeOut As Integer)

VC syntax : short object.PulseStrobeAndWaitBusy ( short TimeOut);

Parameters:

TimeOut - the timeout in relative time units to prevent an infinite loop

Returns:

Boolean value (TRUE- success, FALSE-timeout expired)

Remarks:

None


LPT Hardware Interruptions

· IrqNumber Property

· LptInterrupt Event

· UnmaskIRQ Method

· MaskIRQ Method

· IrqCounter Property


IrqNumber Property

Data Type: Integer

Sets and returns which hardware interrupt (Iusually 7 for LPT1 and 5 for LPT2) is to be unmasked/masked for processing.

C++ syntax: object.IrqNumber [ = value ];

Delphi syntax (VCL): object.IrqNumber [:= value ];

VB syntax (OCX): object.IrqNumber [= value ]

VC syntax : short object.GetIrqNumber ( short TimeOut);/ object.SetIrqNumber ( value);

The settings for value are:

Irq number (1..15). Note that IRQ0 (the system timer) is *not* supported under all Windows versions and IRQ9 (RTC) is not supported in Windows NT/2000/XP

Returns:

Current Irq number

Remarks:


LptInterrupt Event

Fired when a hardware interrupt occurs.

BC++ syntax (VCL): void __fastcall ::VicLPT1LptInterrupt(BYTE DataPort, BYTE StatusPort, int TimeStampLo, int TimeStampHi)

Delphi syntax (VCL): procedure TMainForm.VicLPT1LptInterrupt(DataPort, StatusPort: Byte; TimeStampLo, TimeStampHi: Integer);

VB syntax (OCX): procedure VicLPT1LptInterrupt(ByVal DataPort As Integer, ByVal StatusPort As Integer, ByVal TimeStampLo As Long, ByVal TimeStampHi As Long)

Parameters:

DataPort - single byte value read from LPT data port
StatusPort - single byte value read from LPT status port
TimeStampLo - low part of time stamp (see QueryPerformanceCounter API function)
TimeStampHi - high part of time stamp

Remarks:

1. DataPort and StatusPort value was read immediately when a hardware interrupt occurs inside of the driver;
2. TimeStampLo, TimeStampHi - timestamp shows when a hardware interrupt occurs in the driver, created with RDTSC assembler instruction.
3. Just double-click at TVicLPT icon on the form to install the interrupt handler.


UnmaskIRQ Method

Unmasks the hardware interrupt specified by the IrqNumber property, so that an LptInterrupt event will be generated when a hardware interrupt occurs.

C++ syntax: object.UnmaskIRQ();

Delphi syntax (VCL): object.UnmaskIRQ;

VB syntax (OCX): object.UnmaskIRQ

VC syntax : short object.UnmaskIrq ( );


MaskIRQ Method

Masks the hardware interrupt specified by the IrqNumber property. Works as oppsite to UnmaskIRQ method.

BC++ syntax (VCL): object->MaskIRQ();

Delphi syntax (VCL): object.MaskIRQ;

VB syntax (OCX): object.MaskIRQ

VC syntax : short object.MaskIrq ( );


IrqCounter Property

Data Type: Integer

Returns how many interruption was processed in the driver.

BC++ syntax (VCL): object->IrqCounter;

Delphi syntax (VCL): object.IrqCounter;

VB syntax (OCX): object.IrqCounter

VC syntax : long object.GetIrqCounter ( );


Mass input/ouptput in EPP mode

Mass input/output in EPP mode

· ReadEppByteArray

· ReadEppWordArray

· ReadEppLongArray

· WriteEppByteArray

· WriteEppWordArray


ReadEppByteArray Method

Read an array of bytes through the LPT in EPP mode.

BC++ syntax (VCL): object->ReadEppByteArray(long int NumOfBytes, void * ByteBuffer);

Delphi syntax (VCL): object.ReadEppByteArray(NumOfBytes: Longint; var ByteBuffer);

VB syntax (OCX): object.ReadEppByteArray(ByVal NumOfBytes As Long, ByRef ByteBuffer As Any)

VC syntax : object.ReadEppByteArray(long NumOfBytes, const VRIANT FAR& ByteBuffer );

Parameters:

NumOfBytes - number of bytes to read,
ByteBuffer - data buffer.


ReadEppWordArray Method

Read an array of 16-bit words through the LPT in EPP mode.

BC++ syntax (VCL): object->ReadEppWordArray(long int NumOfBytes, void * WordBuffer);

Delphi syntax (VCL): object.ReadEppWordArray(NumOfWords: Longint; var WordBuffer);

VB syntax (OCX): object.ReadEppWordArray(ByVal NumOfWords As Long, ByRef WordBuffer As Any)

VC syntax : object.ReadEppWordArray(long NumOfWords, const VRIANT FAR& WordBuffer );

Parameters:

NumOfWords - number of words to read,
WordBuffer - data buffer.


ReadEppLongArray Method

Read an array of 32-bit double words through the LPT in EPP mode.

BC++ syntax (VCL): object->ReadEppLongArray(long int NumOfDWords, void * LongBuffer);

Delphi syntax (VCL): object.ReadEppLongArray(NumOfDWords: Longint; var LongBuffer);

VB syntax (OCX): object.ReadEppLongArray(ByVal NumOfDWords As Long, ByRef LongBuffer As Any)

VC syntax : object.ReadEppLongArray(long NumOfDWords, const VRIANT FAR& LongBuffer );

Parameters:

NumOfDWords - number of double words to read,
LongBuffer - data buffer.


WriteEppByteArray Method

Write an array of bytes through the LPT in EPP mode.

BC++ syntax (VCL): object->WriteEppByteArray(long int NumOfBytes, void * ByteBuffer);

Delphi syntax (VCL): object.WriteEppByteArray(NumOfBytes: Longint; var ByteBuffer);

VB syntax (OCX): object.WriteEppByteArray(ByVal NumOfBytes As Long, ByRef ByteBuffer As Any)

VC syntax : object.WriteEppByteArray(long NumOfBytes, const VRIANT FAR& ByteBuffer );

Parameters:

NumOfBytes - number of bytes to write,
ByteBuffer - data buffer.


WriteEppWordArray Method

Write an array of 16-bit words through the LPT in EPP mode.

BC++ syntax (VCL): object->WriteEppWordArray(long int NumOfBytes, void * WordBuffer);

Delphi syntax (VCL): object.WriteEppWordArray(NumOfWords: Longint; var WordBuffer);

VB syntax (OCX): object.WriteEppWordArray(ByVal NumOfWords As Long, ByRef WordBuffer As Any)

VC syntax : object.WriteEppWordArray(long NumOfWords, const VRIANT FAR& WordBuffer );

Parameters:

NumOfWords - number of words to write,
WordBuffer - data buffer.

Remarks:

None


WriteEppLongArray Method

Write an array of 32-bit double words through the LPT in EPP mode.

BC++ syntax (VCL): object->WriteEppLongArray(long int NumOfDWords, void * LongBuffer);

Delphi syntax (VCL): object.WriteEppLongArray(NumOfDWords: Longint; var LongBuffer);

VB syntax (OCX): object.WriteEppLongArray(ByVal NumOfDWords As Long, ByRef LongBuffer As Any)

VC syntax : object.WriteEppLongArray(long NumOfDWords, const VRIANT FAR& LongBuffer );

Parameters:

NumOfDWords - number of double words to write,
LongBuffer - data buffer.

Remarks:

None


Third Party Parallel Port F.A.Q.s

Jan's Parallel Port FAQ , http://www.lvr.com/jansfaq.htm

The parallel port FAQ . Basics about the parallel port and how to use it, by Zhahai Stewart, http://www.lvr.com/files/ibmlpt.txt


Jan's Parallel Port FAQ

Answers to some frequently asked questions
about the PC's parallel port by Jan Axelson

This FAQ contains my answers to parallel-port questions that I have answered in newsgroups, forums, or direct email. Because many of the same topics come up again and again, I've collected the most common ones in this document.

Most are specific, technical questions relating to programming, interfacing, or using the parallel port. For more basic information about the parallel port and its many modes, see the other information and links at Lakeview Research's web site: http://www.lvr.com

Thanks to the questioners for some thought-provoking queries!

Latest update: 11/3/01

You may distribute this FAQ if you distribute the entire document and charge nothing except minimal download or media charges.

Jan Axelson
jan@lvr.com

Table Of Content

· General Interfacing

· Speed

· Using Interrupts

· Bidirectional Ports

· Using EPP & ECP

· Mode Problems

· Accessing Ports Under Windows

· What Type Of Port?

· ECP Modes

· Cables

· General Printer Problems


General Interfacing

Q: When I write a byte to a port address, I don't see the value at the connector/cable/peripheral.

Q: When I read a port, the value I read doesn't match the value at the connector/cable/peripheral.

Q: I need to make an interface to emulate a printer that is on-line and with paper. I have a program that needs three printers, but two of the outputs don't interest me and if I don't have the printers connected, the program doesn't work.

Q: I'm trying to input a stream of data into pin 12 but I get garbage on other computers and mine works fine. I'm using the output pin number 8 on a 74F299 to serially load the data into the computer. I use the data and control ports for control signals, and these work fine.

Q: The status register on the parallel port is used for input. Why do I read a logic "1" with a logic probe at these pins on the DB25 connector?

Q: Is the parallel port based on the 8255 Programmable Peripheral Interface?

Q: We have a device that sends data to a line printer. We'd like to send the data to a PC instead. How can we do this?

Q: I am in need of a parallel to serial to parallel conversion for a data acquisition application. The data acquisition is controlled through a centronics parallel port. The application requires a wireless connection between the DAQ and conputer and this is to be accomplished using 19.2kbps wireless modems that is RS-232 connected. Commercially available products seem only to provide conversions one way OR the other based on dip switch settings. Is there something availalbe that I have missed which is smart enough to know what direction to convert on the fly? The data acquisition system interprets the control and data lines and drives the status lines, is it possible to split the signals and then rejoin them?

Q: I'd like to power a low component count device via an output port bit on the pc's parallel port. Does anyone know the current sourcing spec for an output port bit?

Q: When I write a byte to a port address, I don't see the value at the connector/cable/peripheral.

A: If you don't see what you expect at the other end, the reason is probably one of the following:

· You're writing to the wrong address. Remember that 378 in hexadecimal is 888 in decimal.
· You're looking on the wrong pin. Verify the wiring of any cable you're using.
· You're running NT and trying to access a port directly. NT requires a kernel-mode driver.
· External circuits connected to the port are preventing the bits from toggling. Disconnect the circuits and measure again.
· You forgot that Control port bits 0, 1, and 3 are inverted between the port register and the connector pins. When you write to the Control port, these bits will be the inverse of what you write.
· The port supports PS/2 mode and you've written 1 to Control port, bit 5, disabling the Data port's outputs. Write 0 to this bit to enable the outputs.
· You're trying to connect two PCs' parallel ports and you aren't using the required LapLink-type cable and software that transmits four bits at a time.
· A low-level Windows driver has prevented access to the port. This is rarely a problem with the parallel port, however.

Back To Top

Q: When I read a port, the value I read doesn't match the value at the connector/cable/peripheral.

A: If you don't read what you expect, the reason is probably one of the following:

· You're reading the wrong address. Remember that 378 in hexadecimal is 888 in decimal.
· You're looking on the wrong pin. Verify the wiring of any cable you're using.
· You're running NT and trying to access a port directly. NT requires a kernel-mode driver.
· You forgot that Control port bits 0, 1, and 3 and Status port bit 7 are inverted between the port register and the connector pins. When you read these ports, these bits will be the inverse of the logic states at the connector.
· You're reading the data port and your port doesn't support PS/2 mode. You can't disable the data outputs, and will read the last value written to the port, rather than the logic states at the connector.
· The port supports PS/2 mode and you haven't written 1 to Control port, bit 5, disabling the Data port's outputs. Write 1 to this bit to enable reading external signals on the data lines.
· A low-level Windows driver has prevented access to the port. This is rarely a problem with the parallel port, however.

Back To Top

Q: I need to make an interface to emulate a printer that is on-line and with paper. I have a program that needs three printers, but two of the outputs don't interest me and if I don't have the printers connected, the program doesn't work.

A: To fool the software into thinking that a printer is connected, try this: Tie -Error (pin 15) high (+5V). Tie PaperEmpty (pin 12) low (0V). Tie Busy (pin 11) low (0V). Matthew Chapman also recommends tying -Select (pin 17) low and pin 12 (Select In) high.

John Sawyer successfully used this wiring to emulate a printer connection:

1 (data strobe) ---> 10 (Ack)
11(busy) , 12(paper end), 17(select inhibit) --> Ground
13(select) --> 15(!error) --Tied together, but floating

Also from Matthew Chapman: In VB, do not use ' Printer.Print Chr(xxx) ' followed by ' Printer.EndDoc ' (to start printing), because that will start endlessly spooling and won't reach the final stage, which is to output the byte for printing. Use ' Text1.Text = "" ' and ' Text2.Text = Chr(255) ' in the ' Form_Load ' procedure and ' Text1.SelPrint (Printer.hDC) ' followed by ' Text2.SelPrint (Printer.hDC) ' in the ' Command1_Click ' procedure to output the byte value of 255 to the printer port (regardless of which printer driver you are using) whenever you click on the command button.

Back To Top

Q: I'm trying to input a stream of data into pin 12 but I get garbage on other computers and mine works fine. I'm using the output pin number 8 on a 74F299 to serially load the data into the computer. I use the data and control ports for control signals, and these work fine.

A: Sending data at high speeds over a long cable can cause problems. The components used to implement the parallel port can vary from system to system, so a marginal circuit may work with some ports & not others. You might want to try these:

· Use a slower logic family (LSTTL, HCTMOS). (Decreases transmission-line effects.)
· Buffer the inputs and outputs that connect to the cable. Use a 74HC244 or 74LS244 buffer/driver or similar. (For isolation, strong drivers, Schmitt-trigger inputs.)
· Slow the clock that controls the bit transmissions.
· Use a short cable (6 feet or less).

Back To Top

Q: The status register on the parallel port is used for input. Why do I read a logic "1" with a logic probe at these pins on the DB25 connector?

A: This just means that the inputs have pull-up resistors. Not unusual, and not a problem.

Back To Top

Q: Is the parallel port based on the 8255 Programmable Peripheral Interface?

A: There's no relation between the 8255 chip and the parallel port. The original IBM PC did contain an 8255, but it had nothing to do with the parallel-port circuits, which used ordinary logic gates and latches.

Back To Top

Q: We have a device that sends data to a line printer. We'd like to send the data to a PC instead. How can we do this?

A: The easiest solution is to buy a parallel-to-serial converter and read the data at the new PC's serial port. Converters are available from B &B, Jameco, JDR, and other sources. Be sure the converter can convert parallel input to serial output.

Back To Top

Q: I am in need of a parallel to serial to parallel conversion for a data acquisition application. The data acquisition is controlled through a centronics parallel port. The application requires a wireless connection between the DAQ and conputer and this is to be accomplished using 19.2kbps wireless modems that is RS-232 connected. Commercially available products seem only to provide conversions one way OR the other based on dip switch settings. Is there something availalbe that I have missed which is smart enough to know what direction to convert on the fly? The data acquisition system interprets the control and data lines and drives the status lines, is it possible to split the signals and then rejoin them?

A: The Centronics-to-RS-232 converters that I've seen are for use only with a conventional Centronics interface - in other words, they convert the 8 Data bits only, either converting parallel inputs to serial outputs, or a serial input to parallel outputs. Your data-acquisition unit is sending data on the Status lines (probably 4 data bits and a strobe), and the converters can't handle this arrangement. One solution would be to program a microcontroller to do the conversions between the modem and data-acquisition device. Or (if possible) switch to a data-acquistion unit with a serial interface.

Back To Top

Q: I'd like to power a low component count device via an output port bit on the pc's parallel port. Does anyone know the current sourcing spec for an output port bit?

A: The data outputs on the original parallel port were 74LS374 outputs, which can source 2.6 milliamps at 2.4 guaranteed, 3.1V typical. The data outputs on most parallel ports are at least as strong as the original port's, but no guarantees. If you need 5V, you can use one of the high-efficiency step-up regulators from Maxim & others (Max756). The newer port controller chips often have IEEE-1284 Level 2 outputs, which can source 12 milliamps at 2.5V. The Control outputs were originally open-collector TTL with 4.7K pullups, so these are less useful as current sources.

Back To Top


Speed

Q: How can Parallel Port ISA card support quoted rates of data transfer in excess of 1MB/sec ? As far a I know every in/out command for an ISA bus address takes at least 1 microsecond to perform REGARDLESS of processor speed?

A: A simple parallel-port read or write does take one ISA-bus cycle, and on most systems, the bus speed is around 1.3 Mhz, so one cycle is a little under 1 microsecond. A complete data transfer on the original parallel port usually takes at least 4 cycles, however: check the Busy status, write the data, bring Strobe low, then high. On ports that support EPP and ECP modes, in these modes the port hardware does the handshake, and a complete transfer can take place in 1 bus cycle.
There are at least two ways of getting faster data transfers: Some ports support a "fast mode" that uses the ISA bus's NOWS (no wait state) signal to cause the CPU to skip 3 wait states. This mode is twice as fast, or around 2.7 Mhz. ECPs also include hardware support for data decompressing (& sometimes compressing, though that's often left for software), so the effective rate of data transmission can be much faster than the number of bytes written or read per second. Also, ECPs may be able to transfer data between the host's and peripheral's ECP buffers at rates greater than 1 Mhz, though the buffers are typically just 8 bytes.

Back To Top


Using Interrupts

Q: I'm confused about printer ports and IRQs. I've been told several contradictory things. I've been told that device drivers for don't actually use interrupts, so you can set multi-port cards such as byterunner's 4 serial/3 parallel port card to either all use the same IRQ for the parallel ports or none at all and everything should work. I've also been told that every printer port must absolutely use separate IRQ's.

A: You can print from DOS, Windows 3.1, and Windows 95/98 without using parallel-port interrrupts. It's easy enough to test: select no IRQ level on your port, then print to it. But - there are situations where you might need or want to use parallel port interrupts:

1. Under Windows 95/98, if your PC's port and your printer both support ECP transfers, W95 will print using ECP mode (faster) if ECP mode is enabled at the port (for motherboard ports, in the CMOS setup), if the PC's port is identified as ECP in the Device Manager, and if the port has an assigned interrupt and DMA channel (see Control Panel, System, Device Manager, Resources).

2. Drivers for other parallel-port devices (drives, scanners, etc.) may use interrupts, or they may work better (faster) with interrupts.

3. Some alternate print spoolers can use interrupts. LaserTools' PrintCache was one, though I haven't seen recent versions.

Back To Top


Bidirectional Ports

Q: I am trying to obtain the status of 8 switches via the parallel port. What I need is I think first a way to tell if I can tri-state the data-port lines port on my computer, so that I can read external signals on the data lines. Does anyone know how to tell if the port will support setting Control Port bit 5 to tristate the outputs?

Q: I've been searching for info on enabling PS/2, or Byte Mode, as described in the IEEE 1284 specification for all the different chips and boards. They all make the mode possible but the procedure is different for each chip and even for each board brand implementation!

Q: I am trying to interface a device to a parallel port, using PS/2 mode (simple bidirectional) and reading data on the parallel port's Data lines. I have successfully used this device on older AST 386 notebook ports as well as a modified SPP in a desktop computer. When in the PS/2 input mode, the input impedance of the older computers is fairly high, as I would expect if the output latch is truly tri-stated.The problem I am chasing is with a new Toshiba 420 notebook computer, which professes to have a port which can be configured as a standard bi-directional or an ECP. After I have configured (through setup) the Toshiba port for bidirectional, when I switch from the compatibility mode to the byte (PS/2) mode by writing 2Xh to the port's Control register, each data pin is pulled up rather strongly to +5 vdc. It requires less than 270 ohms from any data pin to ground (sinking about 4 ma) to be able to read a 0 at the data register. This is certainly not my idea of "tri-state".Have you ever dealt with such a port and would you believe this could be normal operation?

Q: I am trying to obtain the status of 8 switches via the parallel port. What I need is I think first a way to tell if I can tri-state the data-port lines port on my computer, so that I can read external signals on the data lines. Does anyone know how to tell if the port will support setting Control Port bit 5 to tristate the outputs?

A: To find out if the data port is bidirectional: 1. Set bit 5 of the control register (at base address+2). 2. With nothing connected to the port, write a couple of values to the data port, and read each back after you write it. If the reads DON'T match the writes, your port is probably bidirectional. Setting C5 disabled the data outputs and you're reading the open inputs of the data-port buffer. If the reads DO match the writes, your port isn't bidirectional. The data outputs are still enabled, you're reading back what you wrote, and you won't be able to read external signals.
On many ports, before you can use the data lines for input, you have to configure the port for "PS/2 mode", usually in the CMOS setup or a software utility. This writes to configuration registers in the chip that controls the port. The specifics of how to access the registers vary with the chip, so it's impossible to give a single programming procedure that will work for all. Some parallel ports (usually on expansion boards) have configuration jumpers on the circuit board to set the mode. (Check your board's documentation.) If the port is configured as ECP, select the PS/2 mode in the ECP's ECR (as described below).

Back To Top

Q: I've been searching for info on enabling PS/2, or Byte Mode, as described in the IEEE 1284 specification for all the different chips and boards. They all make the mode possible but the procedure is different for each chip and even for each board brand implementation!

A: If you've created a product that connects to the parallel port, and you have software capable of using Byte ("PS/2") mode, or another of the new modes with your device, you could do the following:
1. Ask users to enable the new modes at their port. It's just about impossible to do this automatically, because there's no way to detect which port-controller chip is used. If the controller chip is on the motherboard, there's normally a parallel-port option in the CMOS setup. If the port is on an expansion card, there should be jumpers or configuration software that came with the board. On some boards, the new modes are hard-wired-enabled, so nothing needs to be done. (The user shouldn't have to select a specific mode, just configure the port so that the advanced modes are available. ) Example: some (or all) Dell XPS P90 motherboard parallel ports allow selecting AT or PS/2 type port. The AT option locks out everything except "original" Centronics-type output. The PS/2 option puts the port in the controller's ECP configuration, with the PS/2 submode selected, so all of the other modes except EPP are available via the ECP's ECR register. The documentation doesn't explain this; the only way to determine it is to select the different options and examine the contents of the configuration registers. To use EPP mode, you do have to access the configuration registers.
2. Once the new modes are enabled, your software can try out the different modes and use the best of the available options.

Back To Top

Q: I am trying to interface a device to a parallel port, using PS/2 mode (simple bidirectional) and reading data on the parallel port's Data lines. I have successfully used this device on older AST 386 notebook ports as well as a modified SPP in a desktop computer. When in the PS/2 input mode, the input impedance of the older computers is fairly high, as I would expect if the output latch is truly tri-stated.
The problem I am chasing is with a new Toshiba 420 notebook computer, which professes to have a port which can be configured as a standard bi-directional or an ECP. After I have configured (through setup) the Toshiba port for bidirectional, when I switch from the compatibility mode to the byte (PS/2) mode by writing 2Xh to the port's Control register, each data pin is pulled up rather strongly to +5 vdc. It requires less than 270 ohms from any data pin to ground (sinking about 4 ma) to be able to read a 0 at the data register. This is certainly not my idea of "tri-state".
Have you ever dealt with such a port and would you believe this could be normal operation?

A: Several people have described this problem to me, always with Toshiba laptops. One possibility is that the Data lines have pullup resistors. The IEEE-1284 standard actually recommends using 1.2K pullups on inputs, "to ensure operation with Level 1 [original] and compatible devices." And an input with a 1.2K pullup would require a driver capable of sinking several milliamperes.

Back To Top


Using EPP & ECP

Q: Does the ECP parallel port specification require the use of a DMA channel?

Q: All the I/O cards I've seen require you to select a DMA channel when you jumper the parallel port in ECP mode. Yet, you can set up the "ECP Port" in Win95 with or without any DMA channel (and with or without any IRQ, for that matter). So, if I set up the parallel port on my I/O card to ECP mode with a DMA channel, but set up the "ECP Port" option in Win95 NOT to use any DMA channel, can I still use that DMA channel for another device?

Q: Alternatively, if I jumper my I/O card to EPP mode (which doesn't use DMA channel), should I still set it up in Win95 as an "ECP Port", or as a regular "Printer Port"?

Q: Which mode (ECP or EPP) would work best with parallel port devices such as the Snappy and the QuickCam Color?

Q: Do I need to use parallel cables and switchboxes which are SPECIFICALLY labeled to support ECP/EPP to connect my parallel devices, or will any cable and switchbox work with all ECP/EPP ports and devices (as long as they have the 25 pins wired straight-through)?

Q: I have been communicating in ECP mode with another device. PC to peripheral transfers work fine. However in peripheral-to-PC transfers, sometimes the data repeats four times. For instance, If my peripheral sends a 0, I get four 0s instead of one.

Q: Does the ECP parallel port specification require the use of a DMA channel?

A: No, but a specific device driver may make use of it if available. For example, if your PC and printer both support ECP mode, but your printer's port has no DMA channel assigned, the Windows 95 printer driver will use Fast Centronics mode instead of ECP. This is faster than SPP (original) mode, but not as fast as ECP mode.

Back To Top

Q: All the I/O cards I've seen require you to select a DMA channel when you jumper the parallel port in ECP mode. Yet, you can set up the "ECP Port" in Win95 with or without any DMA channel (and with or without any IRQ, for that matter). So, if I set up the parallel port on my I/O card to ECP mode with a DMA channel, but set up the "ECP Port" option in Win95 NOT to use any DMA channel, can I still use that DMA channel for another device?

A: Yes.

Back To Top

Q: Alternatively, if I jumper my I/O card to EPP mode (which doesn't use DMA channel), should I still set it up in Win95 as an "ECP Port", or as a regular "Printer Port"?

A: Use the ECP setting unless you have problems with it.

Back To Top

Q: Which mode (ECP or EPP) would work best with parallel port devices such as the Snappy and the QuickCam Color?

A: As a general rule, because of its FIFOs and DMA support, ECP is good at transferrring big blocks of data quickly (scanners, printers). EPP is good for links that switch directions frequently (drives). Specifically, it depends on the driver for the device, so you might want to experiment if both options are available.

Back To Top

Q: Do I need to use parallel cables and switchboxes which are SPECIFICALLY labeled to support ECP/EPP to connect my parallel devices, or will any cable and switchbox work with all ECP/EPP ports and devices (as long as they have the 25 pins wired straight-through)?

A: A cable that is "IEEE 1284-compliant" meets certain standards for shielding, cable capacitance, etc. Over short links (5-6 feet), any cable will usually work, but you can run into problems with longer cables and higher speeds. Get the better cable if you have a choice.

Back To Top

Q: I have been communicating in ECP mode with another device. PC to peripheral transfers work fine. However in peripheral-to-PC transfers, sometimes the data repeats four times. For instance, If my peripheral sends a 0, I get four 0s instead of one.

A: My ECP controller on the PC side was configured for RLE data compression. RLE is enabled depending of the state of S7: S7 low is RLE disable, and S7 high is RLE enable. With RLE, the sending device sends the number of times to repeat a byte followed by the byte, and the receiving device automatically creates the requested number of repetitions. Francois Blouin provided this question and the answer.

Back To Top


Mode Problems

Q: I am having a problem using a parallel port device I designed and built,with the newer bidirectional parallel ports. The device works fine with the old IBM style ports but gags when I try to use it with the newer styleprinter ports. Is there a standard way to force a printer port into the old IBM configuration ?

A: There is no single standard. There are a couple of different approaches you could take.

One way is to disable the newer modes entirely. Depending on the port, you can do this in the CMOS setup, or with a jumper, or a utility on disk. Select "AT" type, not PS/2, ECP, or EPP. You can do the same thing by programming the port chip directly, but how to do it varies with the chip. This method is fine if you use the port only for your OScope. If you use the same port with other devices, they won't be able to use the newer modes unless you re-enable them.

The second option is to get a PS/2, EPP, or ECP port to act like an old-style, "original," SPP, without disabling the new modes entirely. A PS/2 (simple bidirectional) port or EPP will act like an SPP as long as you don't set bit 5 of the control port (at base address + 2) to 1. Setting this bit to 1 disables the data outputs and enables you to read external signals at the data port. On an SPP, the bit has no effect. (EPP transfers are done by writing to different port addresses; if you write to the base address, it acts like an SPP.)

ECPs are a little more complicated. An ECP can operate in several modes. You select the mode by writing to bits 7, 6, and 5 of the ECR (extended control register) at (base address + 402h). (Example: for a port at 378h, the ECR is at 77Ah.) If you want the port to act like an SPP, use mode 000 (SPP). In mode 011 (ECP), writing to the data port (the base address) causes the port to try to do an ECP Address Write cycle, with automatic handshaking, which you don't want.

To test if a port is ECP, read the ECR at (base address + 402h) and verify that bit 0 (fifo empty) =1 and bit 1 (fifo full) =0. Then write 34h to the ECR and read it back. Bits 0 and 1 are read-only, so if you read 35h, you almost certainly have an ECP. (This is the test described in Microsoft's ECP document, on the MS developer's CD-ROM.)

So what can you do if you have an unknown port and want it to emulate an SPP? First, test for the presence of an ECP and if it exists, select mode 000 in the ECR. Otherwise, just remember to keep control bit 5 = 0.

One other thing: in the advanced modes, for faster performance, the control-port outputs often change from open-collector/open-drain type to push-pull (totem-pole) type. This means that in an EPP, and in all of the ECP modes except SPP, you can't count on being able to write "1" to a control output and then use it as an input bit (as some projects do). Also, some ports apparently have push-pull control outputs in all of the modes, so for compatibility with all ports, don't use the control bits as inputs.

Back To Top


Accessing Ports Under Windows

Q: How do you output a byte to the parallel port under Windows 95? I'm using Delphi/Visual C++/Visual Basic. The faqs I've found say to write directly to the portregister, but I understand that Windows prevents this. Is this correct?

Q: In Visual Basic, I use MSComm to read and write to serial ports. How do I do the same for parallel ports?

Q: I need to use the parallel port to control a device. I'm told that the best way is to use a driver like printers and data acquisition cards use. How do I write a driver for use with Visual Basic?

Q: My company has a product that connects to the parallel port. The process of finding the port address via WIN95's properties window is too much for some customers - we'd like the program to be able to find the address itself without needing the customer to find and enter the port ddress. How can we find a parallel port's address under software control?

Q: How can I access ports using Perl?

Q: How do you output a byte to the parallel port under Windows 95? I'm using Delphi/Visual C++/Visual Basic. The faqs I've found say to write directly to the portregister, but I understand that Windows prevents this. Is this correct?

A: You can write directly to the port registers under Window 95/98 (but not under NT). If the port isn't being used by anything else, there should be no problem. Here's how to read and write to ports in various languages:

Visual Basic has no built-in way to access ports. A solution is to use a DLL written in Delphi or C that enables you to use inp and out routines in Visual-Basic programs. See http://www.lvr.com for inpout32 and other options.

In 16-bit Delphi, use inport and outport. In 32-bit Delphi (Delphi 2 and higher), use in-line assembly code. Here is Delphi source code for routines for reading and writing to ports.

library inpout32;
uses SysUtils;

{write a byte to a port}
procedure Out32(PortAddress:smallint;Value:smallint);stdcall;export;
var
  ByteValue:Byte;
begin
  ByteValue:=Byte(Value);
  {in-line assembly code begins here}
  asm
    {preserve the contents of the dx register}
    push dx
    {write ByteValue to PortAddress}
    mov dx,PortAddress
    mov al, ByteValue
    out dx,al
    {restore the contents of dx}
    pop dx
  end;
end;

{read a byte from a port}
function Inp32(PortAddress:smallint):smallint;stdcall;export;
var
  ByteValue:byte;
begin
  {in-line assembly code begins here}
  asm
    {preserve the contents of the dx register}
    push dx
    {read ByteValue from PortAddress}
    mov dx, PortAddress
    in al,dx
    mov ByteValue,al
    {restore the contents of dx}
    pop dx
  end;
  Inp32:=smallint(ByteValue) and $00FF;
end;

Exports
  Inp32,
  Out32;
begin
end.

In C, use inp and outp, if available. Some 32-bit compilers don't support these. In that case, use in-line assembly code, or an inpout DLL.

Jody Rice has provided this code for using inpout32 with Visual C++ v6:

typedef UINT (CALLBACK* LPFNDLLFUNC1)(INT,INT);
typedef UINT (CALLBACK* LPFNDLLFUNC2)(INT);
HINSTANCE hDLL; // Handle to DLL
LPFNDLLFUNC1 Output; // Function pointer
LPFNDLLFUNC2 Input; // Function pointer
INT Addr;
INT AddrIn;
INT Value;

hDLL = LoadLibrary("Inpout32");

if (hDLL != NULL)
{
  Output = (LPFNDLLFUNC1)GetProcAddress(hDLL,"Out32");
  Input = (LPFNDLLFUNC2)GetProcAddress(hDLL,"Inp32");
  if (!Output || !Input)
  {
    // handle the error FreeLibrary(hDLL);
  }
}

Addr = 0x378;
AddrIn = 0x379;
Value = 0;
Output(Addr, Value);
INT somenum = Input(Addr);

Back To Top

Q: In Visual Basic, I use MSComm to read and write to serial ports. How do I do the same for parallel ports?

A: Unfortunately, things aren't as simple with the parallel port. If all you need is simple line-printer-type output (check the status lines and send each byte with a strobe), you may be able to use the Generic printer object, or the Createfile and Writefile API calls, or (16-bit only) Open "LPT1".

From Chris Wells: The lpt.vxd driver for Windows 9x may enable you read external signals on the data lines. Use SetCommTimeouts() to specify a ReadTotalTimeoutConstant of 1000 or so and call ReadFile.

For anything more complicated (PC-to-PC transfer or anything that requires reading the port), you're pretty much on your own. Windows and VB have no built-in support. There are a few vendors of parallel-port drivers, but these tend to be very expensive (thousands of $$) and are limited to the IEEE-1284 modes.

To write your own driver (which can be as simple as a routine in your application), there are various tools that enable reading and writing to ports. Under W3.x and W95, you can use an inpout DLL, though this offers no system-level protection. The alternative is a Vxd (W95), kernel-mode driver (NT), or an Ocx or Active-X Control that can communicate with these.

Back To Top

Q: I need to use the parallel port to control a device. I'm told that the best way is to use a driver like printers and data acquisition cards use. How do I write a driver for use with Visual Basic?

A: In the most general sense, a driver is just a program or set of routines that communicates with a specific piece of hardware, such as a parallel port. It can be as simple or sophisticated as you like. Under Windows 3.x or Windows 95, driver often means a VxD (virtual device driver). Advantages of using a VxD are the ability to protect a port by controlling access, and faster hardware-interrupt response. There's no way to write a VxD in Visual Basic. Most developers use Microsoft's Device Developers Kit (DDK), which includes an assembler, examples, and much information about driver development. Some C compilers also support VxD creation. To write a VxD, you need to be an experienced C or assembly-language programmer with a good understanding of Windows programming - or you will be when you're finished!

If all you need is the ability to register a port in the system registry (to control access to it), to read and write to the port, and to detect hardware interrupts, you can use one of the commercial OCX's designed for use with (32-bit) Visual Basic.

Back To Top

Q: My company has a product that connects to the parallel port. The process of finding the port address via WIN95's properties window is too much for some customers - we'd like the program to be able to find the address itself without needing the customer to find and enter the portaddress. How can we find a parallel port's address under software control?

Here are three options:

1. Write a couple of values to each of the addresses and read back the result. If the values match, the port exists. This won't detect a port where access is denied by a system-level driver, or a port in PS/2-input mode (though you can also test for this). Requires an Inpout DLL or other driver for port I/O.

2. 16-bit it only: Use Vbasm's Peek function to read the addresses stored in the BIOS data area at 40:08 through 40:0D. May not include all ports.

3. Under Windows 95, the port addresses are stored in the registry, under

[HKEY_LOCAL_MACHINE\Enum\Root\
[HKEY_LOCAL_MACHINE\Enum\BIOS\
[HKEY_DYN_DATA\Config Manager\Enum\

You can read the registry data with API calls.

From Dominic On: Option 3 is difficult in Windows 95. I tested many PCs and found that the byte location of the port address is different from one PC to another. But in windows NT it's OK. Based on the 3 options above, I came up with a solution:

1. Use an API call to detect which platform is running. (95 or NT)
2. If 95, use Toolhelp32ReadProcessMemory() function to find the port address.
3. If NT, read the port address from the registry.

My application/DLL runs OK in windows 95. But when it runs in NT, I receive an error that Toolhelp32ReadProcessMemory() is not found in the Kernel32. Therefore, when I release my program/DLL, I have to compile conditionally in 2 versions (Windows 95 and NT).

And Bill McCarthy contributes this code that shows how to use Toolhelp32ReadProcessMemory to obtain port addresses:

Declare Function Toolhelp32ReadProcessMemory Lib "KERNEL32" _
    (ByVal th32ProcessID As Long, _
     ByVal lpBaseAddress As Long, _
     lpBuffer As Any, _
     ByVal cbRead As Long, _
     ByRef lpNumberOfBytesRead As Long) As Long

Sub Main()
  Dim i As Long, rtn As Long
  Dim portAddresses(3) As Integer
  Dim cbLen As Long
  cbLen = 8
  rtn = Toolhelp32ReadProcessMemory _
         (0&, _
          &H408&, _
          portAddresses(0), _
          8, _
          cbLen)
  'Debug.Print rtn, cbLen
  For i = 0 To 3
    If portAddresses(i) = 0 Then Exit For
    Debug.Print _
      "port address " & i & " = &H" & Hex$(portAddresses(i))
  Next i
End Sub

Peter Burke offers this code that dynamically loads the Toolhelp32ReadProcessMemory function under WIN9X only, thus allowing a single binary for both WIN9X/NT.

#include <windows.h>
#define TEST_WINDOWS_NT (!(GetVersion() & 0x80000000))

/***********************************************************/
int GetParallelControllerKey(char *parKey)
{
HKEY hKey;
char myData[255];
LONG res;
DWORD mySize;
FILETIME ftLastWriteTime;

if (NULL==parKey)
  return(-1);

*parKey=0;

char myKey[255];

sprintf(myKey,"HARDWARE\\DESCRIPTION\\System");

res = RegOpenKeyEx(HKEY_LOCAL_MACHINE,myKey, 0, KEY_READ, &hKey);

if (res!=ERROR_SUCCESS)
  return(-1);

DWORD dwIndex1;
char myKey1[255];

for (dwIndex1=0;dwIndex1<=10;dwIndex1++)
{
mySize=sizeof(myData);
res = RegEnumKeyEx(hKey,dwIndex1,myData,&mySize,NULL,NULL,NULL,&ftLastWriteTime);

if (res==ERROR_SUCCESS) // ERROR_SUCCESS 1
{
strcpy(myKey1,myKey);
strcat(myKey1,"\\");
strcat(myKey1,myData);

HKEY hKey1;
res = RegOpenKeyEx(HKEY_LOCAL_MACHINE,myKey1, 0, KEY_READ, &hKey1);

if (res!=ERROR_SUCCESS)
   return(-1);

DWORD dwIndex2;
char myKey2[255];
for (dwIndex2=0;dwIndex2<=10;dwIndex2++)
{
mySize=sizeof(myData);
res = RegEnumKeyEx(hKey1,dwIndex2,myData,&mySize,NULL,NULL,NULL,&ftLastWriteTime);

if (res==ERROR_SUCCESS) // ERROR_SUCCESS 2
{
strcpy(myKey2,myKey1);
strcat(myKey2,"\\");
strcat(myKey2,myData);

HKEY hKey2;
res = RegOpenKeyEx(HKEY_LOCAL_MACHINE,myKey2, 0, KEY_READ, &hKey2);

if (res!=ERROR_SUCCESS)
  return(-1);

DWORD dwIndex3;
for (dwIndex3=0;dwIndex3<=10;dwIndex3++)
{
mySize=sizeof(myData);
res = RegEnumKeyEx(hKey2,dwIndex3,myData,&mySize,NULL,NULL,NULL,&ftLastWriteTime);

if (res==ERROR_SUCCESS) // ERROR_SUCCESS 3
{
if 0==strcmp(myData,"ParallelController") )
{
strcpy(parKey,myKey2);
strcat(parKey,"\\");
strcat(parKey,myData);
return(0);
}
} // ERROR_SUCCESS 3

} // for (dwIndex3

} // // ERROR_SUCCESS 2

} // for (dwIndex2

} // ERROR_SUCCESS 1

} // for (dwIndex1

return(-1);
} //GetParallelControllerKey

/*******************************************************************/
int GetAddressLptPortInTheRegistry(int myPort)
{
HKEY phkResult;
char myKey[255];
char myData[255];
LONG res;
DWORD mySize;
DWORD myType;

res=GetParallelControllerKey(myKey);
if (res < 0)
  return(-1);

sprintf(myData,"%s\\%d",myKey,myPort-1);

res = RegOpenKeyEx(HKEY_LOCAL_MACHINE,myData, 0, KEY_READ, &phkResult);

if (res != ERROR_SUCCESS)
  return(-1);

mySize=sizeof(myData);
myType=REG_BINARY;

res=RegQueryValueEx(
phkResult, // handle to key to query
"Configuration Data", // address of name of value to query
NULL, // reserved
&myType, // address of buffer for value type
(unsigned char *)myData, // address of data buffer
&mySize // address of data buffer size
);

if (res != ERROR_SUCCESS)
  return(-1);

//printf("config data port %d 0x14 = 0x%02X 0x15 =
0x%02X\n",myPort,myData[0x14],myData[0x15]);
return(myData[0x14] | myData[0x15]<<8 );

}

typedef BOOL (CALLBACK * PROCTYPE_Toolhelp32ReadProcessMemory)( DWORD, LPCVOID, LPVOID, DWORD ,LPDWORD);

/*****************************************************************************/
int GetAddressLptPortInTheMemory(int myPort)
{
HINSTANCE hDLL=NULL; // Handle to DLL
PROCTYPE_Toolhelp32ReadProcessMemory myProcPointer=NULL;

hDLL = LoadLibrary("kernel32");
if (hDLL==NULL)
  return(-1);

myProcPointer=(PROCTYPE_Toolhelp32ReadProcessMemory)GetProcAddress(hDLL,"Toolhelp32ReadProcessMemory");
if (myProcPointer==NULL) /*handle the error*/
{
FreeLibrary(hDLL);
return -1;
}

int portAddresses[]={0,0,0,0,0};
BOOL rtn=0;
DWORD cbLen=0;
//rtn = Toolhelp32ReadProcessMemory
rtn = myProcPointer(0,(LPCVOID *) 0x408,portAddresses,8,NULL) ;

FreeLibrary(hDLL);

if (rtn==0)
  return(-1);

if (portAddresses[myPort-1]<=0)
  return(-1);

if (portAddresses[myPort-1]>=0x1000)
  return(-1);

return(portAddresses[myPort-1]);
}

/*********************************************************************/
int GetAddressLptPort(int myPort)
{
if(myPort<1)
  return(-1);

if(myPort>3)
  return(-1);

if (TEST_WINDOWS_NT)
  return(GetAddressLptPortInTheRegistry(myPort));

return(GetAddressLptPortInTheMemory(myPort));
}

Back To Top

Q: How can I access ports using Perl?

A: (from Ron Glick) You must have the Win32::API module (available at www.cpan.org) installed.

use Win32::API; #load API module to interface DLL's
$GetPortVal= new Win32::API("inpout32", "Inp32", [I], I); #import Inp32 from DLL
$SetPortVal= new Win32::API("inpout32", "Out32", [I,I], I); #import Out32 from DLL
$input= $GetPortVal->Call(0x378) & 255; #get and display current value of address 378 hex
print "$input\n";
$return=$SetPortVal->Call(0x378,35); #set pins 2,3,7
$input= $GetPortVal->Call(0x378) & 255; #get and display updated value of address 378 hex
print "$input\n";

Back To Top


What Type of Port?

Q: How can I tell what type of port I have?

· Detecting an ECP
· Detecting an EPP
· Detecting an SPP
· Detecting a PS/2-type Port

Q: How can I tell what type of port I have?

A: These are some ways to detect what type of port a system has: SPP (original), PS/2 (simple bidirectional), EPP, or ECP. The explanations assume that you have some familiarity with the different port types and how to access port registers. These tests detect only what type of port is currently enabled! If the advanced modes are disabled on the port controller chip, the tests won't detect them.

On many ports that support advanced modes, you can configure the port either in the CMOS setup, or with jumpers, or with configuration software that comes with the port. Most have an option that causes the port to emulate the original SPP, plus one or more options that enable the advanced modes. If the port is configured as an SPP, the advanced modes will be locked out and the port will fail any tests for PS/2, EPP, or ECP abilities.

Back To Top

Detecting an ECP

In testing a port, you might think that the first step would be to test for an SPP, and work your way on up from there. But if the port is an ECP, and it happens to be in its internal SPP-emulation mode, the port will fail the PS/2 (bidirectional) test. For this reason, I begin by testing for an ECP, and work down from there. This is the method Microsoft's ECP document (in the Developer's Network CD-ROM) recommends for detecting an ECP: 1. Read the ECP's extended control register (ECR) at base address + 402h and verify that bit 0 (fifo empty) =1 and bit 1 (fifo full) =0. These bits should be distinct from bits 0 and 1 in the port's control register (at base address + 2). You can verify this by toggling one of the bits in the control register, and seeing that the corresponding bit in the ECR doesn't change. 2. A further test is to write 34h to the ECR and read it back. Bits 0 and 1 in the ECR are read-only, so if you read 35h, you almost certainly have an ECP. If an ECP exists, you can read and set the ECP's internal mode in the ECR. (See below.)

Back To Top

Detecting an EPP

In addition to the SPP's three registers, an EPP has four additional registers, at base address + 3 through base address + 6. These additional registers provide a way to test for the presence of an EPP, by writing a couple of values to one of the EPP registers and reading them back, much like you would test for an SPP. If the reads are successful, the register exists and you probably have an EPP. I'm not sure if this test works on all EPPs. Because the EPP handshake doesn't complete, there's no guarantee of the contents of the register after the transfer times out. But on the tests I've done, I was able to read back the values written. Be sure to clear the EPP timeout bit (bit 0 of the status port, at base address + 1) after each read or write. Unfortunately, the method for clearing the bit varies with the controller chip. On some ports, you clear the bit by writing 1 to it. On others, simply reading the status register clears the bit. And, though I haven't seen any controllers that clear the bit in the conventional way, by writing 0 to it, you may as well do that too, just to be safe.

Beware #1: on SMC's chips (& maybe others), a set timeout bit can make the port unusable in any mode, until a hard reset (or clearing the bit)!

Beware #2: Don't test for an EPP at address 3BCh. The added EPP registers aren't available at this address, and may be used for video.

Back To Top

Detecting an SPP

To test for an SPP, use the tried and true method of writing two values to the data port and reading them back. If the values match, the port exists. Otherwise, the port doesn't exist, or it's not working properly. Also note that the port-test routine only verifies the existence of the data port. It doesn't test the status and control lines. The other port types (EPP, ECP. PS/2) should also pass this test.

Back To Top

Detecting a PS/2-type Port

To test for simple bidirectional ability, first try to put the port in input mode by writing 1 to bit 5 in the port's control register (at base address + 2). If the port is bidirectional, this tri-states the data port's outputs. Then write two values to the data port and read each back. If the outputs have been tri-stated, the reads won't match what was written, and the port is almost certainly bidirectional. If the reads do match the values written, you're reading back what you wrote, which tells you that the data-port outputs weren't disabled and the port isn't bidirectional. An ECP in its internal PS/2 mode and some EPPs will pass this bidirectional test. Test for a PS/2-type port only after you've verified that an SPP, EPP, or ECP exists. Because the PS/2 test uses the failure of a port read to determine that a port is bidirectional, a non-existent port will pass the test!

Back To Top


ECP Modes

Q: Can an ECP emulate other port types?

A: An ECP has several internal modes. In addition to ECP mode, an ECP can emulate an SPP (original) or PS/2-type (Byte-mode, or simple bidirectional) port. Many ECPs also support EPP emulation. Fast Centronics is an additional mode that gives faster performance with many SPP-type peripherals.

ECP internal modes:

000 SPP
001 Byte
010 Fast Centronics
011 ECP
100 EPP
101 Reserved
110 Test
111 Config

Set the mode in bits 7, 6, and 5 of the ECR at base address + 402h. For example, to set an ECP at 378h to ECP mode in Basic:

'The ECR is at 77Ah (378h + 402h)
EcrAddress=&h77A
'The code for the selected mode (EPP) from the table above:
EcpMode=3
'Read the ECR
ECRData=Inp(EcrAddress)
'Set the highest 3 bits to match the selected mode.
ECRData=(ECRData AND &h1F) + EcpMode * &h20
'Write the result back to the ECR.
Out EcrAddress, ECRData

Back To Top


Cables

Q: I am tring to find the pin-outs and pin descriptions for an IEEE-1284 cable or ECP cable.

Q: Where can I find the wiring diagram of an ECP parallel cable for connecting a pair of computers to do file transfer at ECP port speed ?

Q: I’m experiencing some problems with my printer which may be caused by the fact that I do not use a BI-directional cable. I just bought a new cable, but I do not know for sure that it’s indeed a BI-directional cable. Does anyone have the specs (pin-layout), so that I can check it, or is there another 'trick' to see whether the cable is BI-directional?

Q: Where can I get the new IEEE-1284-C connectors?

Q: I am tring to find the pin-outs and pin descriptions for an IEEE-1284 cable or ECP cable.

A: It depends on what you mean:

1. A cable labeled "IEEE-1284 compliant" has to meet certain standards defined in the IEEE 1284 standard, such as double shielding and having each signal wire in a twisted pair with its ground return. The connectors may be the traditional 25-pin D-subs, 36-contact Centronics-type, or the new, more compact 36-contact IEEE-1284C type. If the connectors are D-subs or Centronics, some of the pins have multiple ground wires. (The Centronics connector has 36 contacts, but the conventional use of it doesn't allow a ground return for every signal wire.)

2. If you're just looking for a cable that will do ECP transfers, you don't need an IEEE-1284-compliant cable, but it may give you faster transfers or allow a longer link.

3. See Lakeview Research's web site for the connector pinouts.

Back to Top

Q: Where can I find the wiring diagram of an ECP parallel cable for connecting a pair of computers to do file transfer at ECP port speed ?

A: The PC's parallel port was designed for PC-to-peripheral links, where the ports on the PC and peripheral complement each other. On the PC's port, the data and control bits are outputs, and the status bits are inputs, and on the peripheral, the data and control bits are inputs, and the status bits are outputs. If you want to connect the parallel ports of two PCs, you need a special cable that connects inputs on one port to outputs on the other. With old-style ports, the conventional way to do this is to cross-connect the status lines with 5 of the data lines, and have the software write a nibble at a time to the data lines and read the data on the status lines. (The other two lines do handshaking.)

Parallel ports that support ECP mode (or PS/2 (Byte) mode or EPP mode) have bidirectional data lines, and it would be nice to be able to use these for faster data transfers between PCs. For the handshake, you would need to cross-connect the status and control lines so that each output connects to an appropriate input.

One problem is that the default state for the data lines on both of the PCs' ports is output. If you connect the data lines of two ports to each other, you have outputs connected to outputs, and the resulting currents may destroy the port circuits. Some port controllers have protected outputs, but relying on this isn't the greatest solution. Other possibilities: Add an electronic switch that keeps the data lines from connecting until the software explicitly requests it. Be very, very careful not to plug in the cable until at least one data port has been configured as input. Use Parallel Technologies' Universal Cable (http://www.lpt.com/lpt/) which contains active circuits that handle the signal switching for you.

With that said, there is a document on the Microsoft Developer's Network CD-ROM titled, "Extended Capabilities Port: Specifications." A lot of the information in it is reprinted word-for-word in the controllers' data sheets, but it does also describe a method of connecting two PC-side ECPs to perform a "compliance test." This is the recommended wiring from this document:

Make these connections (PC "A" to PC "B"):

· nStrobe (pin 1) to nAck (pin 10)
· nAck (pin 10) to nStrobe (pin 1)
· Busy (pin 11) to nAutoFd (pin 14)
· nAutoFd (pin 14) to Busy (pin 11)
· Data (pins 2-9) to Data (pins 2-9)
· *nInit (pin 16) to PError (pin 12)
· *PError (pin 12) to nInit (pin 16)
· *nFault (pin 15) to nSelectIn (pin 17)
· *nSelectIn (pin 17) to nFault (pin 15)
· *SelectIn (pin 17) to Select (pin 13) on both PC A and PC B

* indicates a connection that isn't essential for data transfer. Pin numbers are for 25-pin D-subs.

Back to Top

Q: I’m experiencing some problems with my printer which may be caused by the fact that I do not use a BI-directional cable. I just bought a new cable, but I do not know for sure that it’s indeed a BI-directional cable. Does anyone have the specs (pin-layout), so that I can check it, or is there another 'trick' to see whether the cable is BI-directional?

A: The term Bidirectional printer cable is confusing, because all PC printer cables have the same 17 signal lines. A PC with a bidirectional Data port can receive as well as send data over the 8 Data lines. Some printers can use a bidirectional port to send detailed status information back to the PC. But the signal lines are the same.

All printer cables should have at least 25 wires and be shielded. There are 17 signal lines and 8 ground wires. Some cheaper cables skimp by using just one ground wire, but even the cheap cables usually work OK if the printer doesn't use high-speed modes.

Some printers support a high-speed ECP mode, and other peripherals may use a different high-speed mode called EPP. A cable labeled "IEEE-1284-compliant" is designed to guarantee performance at ECP and EPP speeds. (Each signal wire forms a twisted pair with its ground return, and the cable has two shielding layers.) These cables might also be advertised as "bidirectional" cables, because ECP and EPP are bidirectional interfaces. But don't confuse this type of cable with a "Laplink" cable, which is used to connect two PCs' parallel ports and is a different animal altogether. Also, some printers and other peripherals support an older, slower bidirectional mode called "PS/2-type."

Back to Top

Q: Where can I get the new IEEE-1284-C connectors?

A: These are some manufacturers and part numbers listed in the IEEE-1284 standard:

PC mount Receptacle

· AMP
2-175925-2
2-176971-5
2-178238-5

· 3M
10236-52A2VC
10236-5202VC

· Molex
52311-3611
52311-3621

Cable Plug

· AMP
2-175677-5

· 3M
10136-6000EC

· Molex
52316-3611

Back to Top


General Printer Problems

Q: I am having trouble getting my printer to work. Everytime I try to print a test page I get a three line mess of numbers. I have a Panasonic KX-P4410 LASER PRINTER. I have tried many times to install a new driver for it. I have uninstalled and then installed it again but I keep getting the same getting that same message of some sorts everytime. I am working under Win95

Q: How can I determine printer status (on/off-line, paper out, etc.)?

Q: I am having trouble getting my printer to work. Everytime I try to print a test page I get a three line mess of numbers. I have a Panasonic KX-P4410 LASER PRINTER. I have tried many times to install a new driver for it. I have uninstalled and then installed it again but I keep getting the same getting that same message of some sorts everytime. I am working under Win95

A: I had a similar problem - a newly installed HP 6MP printer that spewed out a few lines of garbage on every bootup. A search of Dejanews brought up the advice to rename or delete this file:

\windows\system\iosubsys\drvwppqt.vxd

& it solved the problem. The file is apparently used by Microsoft Backup. If you don't use Backup, you don't need the file.

Back To Top

Q: How can I determine printer status (on/off-line, paper out, etc.)?

A: You can do this with an API call that retrieves a PRINTER_INFO_2 structure. To find out how, see article Q160129, HOW TO: Get the Status of a Printer and a Print Job, at http://support.microsoft.com/support .

However, you can read the status only after sending a job to the print spooler:

"The Spooler does not query for the state of a physical printer to which a Printer is connected. Instead, the state of a physical printer determines the success of a print job at the time it is despooled over the port monitor. If some error occurs in this process, the error is reported by the port monitor and recorded in a print job's status information. The Spooler, in turn, propagates reasonable error information to the Printer Queue. Consequently, a system Printer reports no status when the Printer queue is empty. In this state, the Printer is assumed ready to accept print jobs."

Back To Top


Zhahai Stewart's FAQ

Interfacing the IBM PC Parallel Printer Port

by Zhahai Stewart zstewart@hisys.com

Version 0.96 9/1/94

Table Of Content

1. Overview
2. Conventions used in this document
3. Addresses, naming, BIOS and DOS
4. Registers addresses within the parallel printer port
5. Pin signals and register bits
6. Electrical
7. Timing
8. How to Print to a standard printer
9. BIOS Printer Support
10. IRQ's
11. Bidirectional Ports
12. Enhanced Ports
13. Copy Protection Dongles
14. Other devices:
15. Transferring Data Via Ports
16. Transfer Modes and Cables
17. Capturing "printed" data from another machine
18. Controlling Outputs
19. Sensing switches
20. Optocoupled inputs
21. Matrix scanning
22. Tutorial on TTL outputs
23. Contributors and Information Needed for future revisions
24. Differences


Overview

This document is called an FAQ because it answers many commonly asked questions about the IBM parallel port, but it is formatted more as a brief tutorial. Read it twice before asking for more info; some stuff comes late.

Most of this I puzzled out for myself from various documention and experiences. The IBM documentation has some errors; I've had to cross correlate various sources including schematics to get a consistent and workable picture. Since the first version, others have contributed information, proofreading, and suggestions (see acknowledgements).

Starting with the original IBM PC, IBM defined a standard parallel printer port which has become very widespread. This port uses a female DB-25S connector on the computer, and a special male DB-25P to Centronics male 36 pin "IBM Printer cable" is used to connect to standard Centronics parallel printers. This DB-25 connector is possible because about half of the Centronics pins carry just electrical ground.

The original definition was embodied in the "IBM Printer Adaptor", and the "IBM Monochrome Display and Printer Adaptor" cards.


Conventions used in this document

An electrical "high" (on a pin or line) is TTL high, +2.4 to +5 volts.
An electrical "low" is TTL low, 0 to +0.8 volts.

A data high is a 1, a data low is a 0.

The connection between data (eg: a register bit) and pins is direct if a data 1 is associated with an electical TTL high, and inverted if data 1 is associated with TTL low. An overall connection (data to TTL to data) is considered direct if outputing a 1 produces a 1 on input at the other end, or inverted if outputting a 1 produces a 0 on the other end.

Pin labels, like "-Strobe" or "+Busy", are as defined by the printers and by IBM. The prefix "-" (or draw a line over the name) implies that the signal is "active low"; that is, that when the signal is in its active state when electically low. The "+" prefix means "active high", just the opposite.

I have labeled the Data Out register bits as D0 to D7, with D0 being the least significant bit and D7 the most signficant. The Control Out bits are labeled C0 to C3 (for the ones which go to pins) and C4 (for IRQ enable), and maybe C5 (for bidirection ports only, controls direction). The Status In bits are labeled S3 to S7 (corresponding to data and CPU bit positions). Often I will suffix C0 to C3 and S3 to S7 with a "+" or "-" as a reminder of whether or not that register bit is inverted as compared to the output or input pin it is associated with; "-" is for inverted, of course. All the Data Out bits are direct (not inverted); likewise data in for bidirectional printer ports, but I have not bothered to suffix a "+".

Hexadecimal numbers are prededed by "0x", the C convention.

A "tristated" or disabled electical output basically disconnects the output from the line or pin (high impedance), neither driving it high nor low.


Addresses, naming, BIOS and DOS

IBM defined three standard port base addresses (in 80x86 IO address space). The Printer Adaptor could use base address 0x378, or later 0x278, while the Monochrome Display and Printer Adaptor used base address 0x3BC.

The IBM BIOS defines RAM space for 4 parallel printer port base addresses, stored as 4 16 bit words starting at main memory address 0x408. During bootup, the BIOS will check for parallel printer ports at base addresses 0x3BC, 0x378, and 0x278, in order, and store the base addresses of any that are found in consecutive locations in this table. Unused entries may be 0, or some BIOSes fill them with the first port address found. Some software may ignore this table, but it is used by at least the BIOS itself (eg: INT 17, Printer I/O), and by DOS, as described below.

The BIOS detects these ports by writing 0xAA to the Data Out register (at I/O address Base+0), reading the Data Feedback register (same address), and deciding there is a port installed if it reads 0xAA. This could be confused if any lines are externally pulled up or down (or if the port defaulted to tristate, or if there is another readback device register at that address). The BIOS also counts the number of parallel ports it found and stores this count in the upper two bits of the byte at 0x411 (yes, the table can hold up to 4 entries, but the BIOS equipment flag printer count only goes to 3).

Warning: Just before this table there are 4 words at 0x400 which contain up to 4 entries for base addresses for serial COM ports. At least some serial port software is known to store more than 4 entries, thus overlapping the parallel port table. Hopefully this is rare!

DOS (MSDOS and IBM DOS) maps these as LPTn devices. Unlike COMn devices and comm ports, the name mapping varies depending on whether or not there is a Monochrome Display and Printer Adaptor card or not. The first entry in the BIOS table at 0x408 becomes LPT1, the second entry LPT2, and the third entry LPT3 (if there are that many). The DOS device "PRN" is really software alias for another port, by default LPT1; use the MODE command to change this aliasing. The following table has "typical" assignments.

Note that by swapping the entries in the BIOS table at 0x408, you can change which physical ports are assigned to LPT1, LPT2, etc. Several "printer swap" programs do just that.

Typical Assignments

Addr   MDPA  no MDPA

0x3BC  LPT1   n/a     Monochrome Display and Printer Adapter (MDPA)
0x378  LPT2   LPT1    Primary Printer Adapter
0x278  LPT3   LPT2    Secondary Printer Adapter

Name   MDPA  no MDPA

LPT1   0x3BC  0x378
LPT2   0x378  0x278
LPT3   0x278  n/a


Registers addresses within the parallel printer port

Port | R/W | IOAddr | Bits | Function
Data Out | W | Base+0 | D0-D7 | 8 LS TTL outputs
Status In | R | Base+1 | S3-S7 | 5 LS TTL inputs
Control Out | W | Base+2 | C0-C3 | 4 TTL Open Collector outputs
- " - | " | " | C4 | internal, IRQ enable
- " - | " | " | C5 | internal, Tristate data [PS/2]
Data Feedback | R | Base+0 | D0-D7 | matches Data Out
Control Feedback | R | Base+2 | C0-C3 | matches Control Out
- " - | " | " | C4 | internal IRQ enable readback

The Feedback registers are for diagnostic purposes (except in bidirectional ports, where Data Feedback is used for data input; and the IRQ enable C4).


Pin signals and register bits

<= in => out | DB25 pin | Cent pin | Name of Signal | Reg bit | Function Notes
=> | 1 | 1 | -Strobe | C0- | Set Low pulse >0.5 us to send
=> | 2 | 2 | Data 0 | D0 | Set to least significant data
=> | 3 | 3 | Data 1 | D1 | ...
=> | 4 | 4 | Data 2 | D2 | ...
=> | 5 | 5 | Data 3 | D3 | ...
=> | 6 | 6 | Data 4 | D4 | ...
=> | 7 | 7 | Data 5 | D5 | ...
=> | 8 | 8 | Data 6 | D6 | ...
=> | 9 | 9 | Data 7 | D7 | Set to most significant data
<= | 10 | 10 | -Ack | S6+ | (IRQ) Low Pulse ~ 5 uS, after accept
<= | 11 | 11 | +Busy | S7- | High for Busy/Offline/Error
<= | 12 | 12 | +PaperEnd | S5+ | High for out of paper
<= | 13 | 13 | +SelectIn | S4+ | High for printer selected
=> | 14 | 14 | -AutoFd | C1- | Set Low to autofeed one line
<= | 15 | 32 | -Error | S3+ | Low for Error/Offline/PaperEnd
=> | 16 | 31 | -Init | C2+ | Set Low pulse > 50uS to init
=> | 17 | 36 | -Select | C3- | Set Low to select printer
== | 18-25 | 19-30, 33,17,16 | Ground |  |

Note: Some cables, ports, or connectors may not connect all grounds. Centronics pins 19-30 and 33 are "twisted pair return" grounds, while 17 is "chassis ground" and 16 is "logic ground".

"<= In" and "=> Out" are defined from the viewpoint of the PC, not the printer. The IRQ line (-Ack/S6+) is positive edge triggered, but only enabled if C4 is 1.

Here's the same data grouped for ease of reference by Control Out and Status In registers and pins. (Data Out is straightforward in previous table).

<= in => out | DB25 pin | Cent pin | Name of Signal | Reg bit | Function Notes
=> | 17 | 36 | -Select | C3- | Set Low to select printer
=> | 16 | 31 | -Init | C2+ | Set Low pulse > 50 us to init
=> | 14 | 14 | -AutoFd | C1- | Set Low to autofeed one line
=> | 1 | 1 | -Strobe | C0- | Set Low pulse > 0.5 us to send
<= | 11 | 11 | +Busy | S7 | High for Busy/Offline/Error
<= | 10 | 10 | -Ack | S6+ | IRQ. Low pulse ~5us, after accept
<= | 12 | 12 | +PaperEnd | S5+ | High for out of paper
<= | 13 | 13 | +SelectIn | S4+ | High for printer selected
<= | 15 | 32 | -Error | S3+ | Low for Error/Offline/PaperEnd


Electrical

See also the tutorial section below on TTL outputs.

The Data Out pins were orginally driven by a 74LS374 octal latch, which could source 2.6 mA and sink 24 mA. There were 0.0022uF capacitors between each line and ground to reduce transients. The manual warns "It is essential that the external device not try to pull these lines to ground", as this might cause the 74LS374 to source more current than it could handle without damage.

The Feedback input port for the Data Out register consisted of a 74LS244 *tri-state buffer*; it is uninverted. Note that this port is only for diagnostics - if at any time the feedback *buffer* for the data port does not match the data being output, there is an error (eg: a line stuck high or low). Exception: bidirectional printer ports allow the 74LS374 (or equivalent) driver chip to be tri*-*stated, which makes the data feedback port into a legitimate unlatched input port.

The Control Out pins were driven by 7405 inverting open collector buffers, pulled to +5 volts via 4.7K resistors. All data lines except C2 are inverted before going to output pins; data line C2 is double inverted before going to pin 16 (ie: is not inverted).

The Feedback input for the Control Out register also inverted all but C2, which was passed through uninverted. It is possible to use some or all of the control out port bits for input, by programming the corresponding control out to high (remembering the inversion on C0, C1, and C3), in which case the open collector outputs are pulled high by the 4.7K resistors; any externally applied high will retain the high state, while an externally applied low will pull down the electical level to low. This can be read via the corresponding feedback bit(s). If either the output from the control register, or an externally applied signal, are low, then the input will below. Remember the inversions between this electrical level and the bits, tho.

The Status In register is inverted for only pin 10, register bit S7.

ESD (from Steven M. Scharf <scharf@mirage.nsc.com>)

LSI implementations of the parallel port have often had serious ESD (electrostatic discharge; includes static electricity) problems. National and other high-end manufacturers have added extensive anti-ESD circuitry to the parallel port signal lines; on cheap parallel port designs on some other SuperIO clones ESD can easily destroy the parallel port circuit when you turn the printer on when the computer is off or the printer is on a switchbox.


Timing

The original IBM Printer Adapter which came out along with the PC (floppy disks, pre XT) was built from TTL MSI parts. They (and their clones) were fast enough to work with the later AT bus, now called ISA, and still do. I've yet to hear of a TTL printer adapter which is too slow for an ISA bus. Partly this is because it was simple and fast in bus access (unlike the serial port 8250 chip), and partly this is because even fast 486's slow their ISA bus down to 8-11 MHz typically.


How to Print to a standard printer

This is as defined for early IBM printers, and more or less compatible with most others that use the Centronics 36 pin interface.

Wait for not +Busy (+Busy low)
Set Data Out bits
  at least 0.5 uS delay
Pulse -Strobe low for at least 0.5 uS
  hold Data Out for at least 0.5 uS after end of -Strobe pulse
Some time later, printer will pulse -Ack low for at least 5 uS
Printer may lower +Busy when it raises -Ack at end of pulse
Set other Control outputs or check Status inputs as desired.


BIOS Printer Support

The PC ROM BIOS detects and initializes the printer ports on bootup, and provides printer support via INT 17 (and indirectly uses this in INT 5
"Print Screen"). The detection and building of a printer port base address table is described in the Soft Addresses section above.

To control the printer via the BIOS, call INT 17 with the printer number in DX (0 to 3, indexing into the four entry table at 0x408 mentioned in the
Soft Addresses section above), and the desired function in AH.

Functions:

AH = 0: print the character in AL
AH = 1: reinitialize the port, return status in AH
AH = 2: return status in AH

BIOS operation notes follow.

The BIOS normally keeps the Control register value as 0x0C:

C5 = 0 => output enabled (for bidirectional only)
C4 = 0 => IRQ disabled
C3 = 1 => -Select pin low (Printer Selected)
C2 = 1 => -Init pin high (Printer not being initialized)
C1 = 0 => -AutoFeed pin high (No Auto Feed)
C0 = 0 => -Strobe pin high (No Stobe)

The BIOS prints a character (function AH = 0) as follows:

(Uses only Status in S7/+Busy and Control out C0/-Strobe)
Write character to Data Out (D0-D7)
Wait for bit S7 to go to 1 (-Busy pin to go high/low?)
Timeout and return if this takes too long
Set C0 to 1 for a few microseconds (-Strobe pin pulsed low)

This assumes that the printer was already ready.

The BIOS handles reinitializing the printer (function AH = 1) thus:

Set C2 = 0 for a few hundred microseconds (-Init pin pulsed low)

The BIOS returns status in AH (functions AH = 1 or 2) is as follows:

__________________________________
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| | | | | not used |___ 1 = "Time Out" (software)
| | | | |________________ 1 = "I/O Error" (inv C3+; -Error pin low)
| | | |____________________ 1 = "Selected" (C4+; +SelectIn pin high)
| | |________________________ 1 = "Paper Out" (C5+; +PaperEnd pin high)
| |____________________________ 1 = "Acknowledge" (inv C6+; -Ack pin low)
|________________________________ 1 = "Not Busy" (C7-; +Busy pin low)

The high 5 bits of this are essentially the Status In register from the printer port, with bits 6 and 3 inverted (ie: XORed with 0x48). The low bit is generated by BIOS software after a timeout. In the original PC, timeout delays were generated by delay loops.


IRQ's

The primary IBM Printer Adapter (base 0x378) and the IBM Monochrome Display and Printer Adapter (base 0x3BC) are allocated hardware interrupt 7 (IRQ 7), which is wired to INT 0x0F. If bit C4 of the Control Out register is high, then input line "-ACK" (DB 25 pin 10, Status Register bit S6) will be wired to the IRQ 7 bus line. A rising edge (low to high) on -Acknowledge will be cause a rising edge on IRQ 7, which will trigger an interrupt if that IRQ is enabled in the 8259 interrupt controller chip. (Note: the MCA bus is level sensitive rather than edge triggered). Both cards use the same interrupt, and the ISA bus does not share interrupts correctly, so no more than one of these ports should be enabled at the same time (or the 74LS125 chips driving the PC bus will fight).

Secondary Printer Adapters (base 0x278) are supposed to use IRQ 5 (INT 0x0D) for their interrupt; note that on the PC (pre-AT) this would have conflicted with the floppy disk controller. This IRQ is even more commonly "stolen" for other usage: EGA, soundcards, network cards, etc.

The idea was apparently to use this IRQ as part of the printer driver, much as the serial port IRQs can be used as part of comm drivers. Unfortunately, typical timing on printers did not allow this, so most (nearly all) DOS software does not use the printer port IRQ for driving printers. It's often considered "up for grabs" and some soundcards like to use IRQ 7. Some other operating systems may use it for the printer port, as may some parallel port transfer programs.


Bidirectional Ports

The IBM PS/2 series added one feature to the parallel ports: bidirectional support. This was done by using one more bit in the Control Out register to control tristating of the Data Out port. When bit C5 is 0, the Data Out port operates as it did for earlier parallel ports (driver enabled); when C5 is set to 1, though, the Data Out port is tristated, which means that it is essentially electically disconnected from the pins (high impedance state), not driving them high nor low. This allows the data feedback register to correctly read any externally applied TTL signals
on the corresponding data pins, effectively making this an input port.

Interestingly, the original IBM Printer Adapter, and many early clones, had everything needed to become bidirectional. The 74LS374 chip has a chip enable pin which can tristate the 8 data outputs, but it is usually wired to ground to always enable the output drivers. The 74LS174
latch used for C0-C4 is actually a hex latch and processor data bus line 5 is attached to the sixth latch input; that bit IS latched when you
write to the Control Out register - but the output (Q6 on the 74LS174) is not used by anything. If you cut the trace from pin 1 (/OE) of the 74LS374 to ground, and connect this pin instead to pin 15 (Q6) of the 74LS174, voila - you have a PS/2 compatible bidirectional parallel port. This only works on the older discrete TTL parallel ports, including the IBM Printer Adapter and at least some clones of that era. One theory is that IBM had a bidirectional port in mind initially, but decided to omit that aspect at the last moment (even while still latching the C5 bit from the processor into the LS174 hex latch).

There are now PS/2 compatible third party bidirectional parallel ports. The cost for a TTL bidirectional port should have been identical, but now that parallel ports are done with one LSI chip (or a fraction of one), this will require an appropriate LSI chip. Apparently some of them now have bidirectional ports, some do not.

Note that some people have for many years been using the standard (not bidirectional) data out port as an input port. They output data 0xFF, that is, all high. Any pins which are externally pulled low via TTL or switches will probably read as low (0) in the data feedback register, because TTL low (sinking current) tends to be stronger than TTL high (sourcing current), and tend to "win" when there two drivers fighting on the same line. An external high signal, or no signal, will allow the pin (and data bit) to remain high (1). This is NOT reccommended, as it stresses the 74LS374 (or equivalent) beyond its safe margins and could cause chip failure. However, some people report doing this for years without problem. Note that all recent parallel ports are implemented with single chip LSI controllers rather than the MSI TTL originals, which means that they may have different drive capacities, electical margins, and replacement costs, should you attempt this approach. Sometimes the LSI controller also includes other functions, such as serial ports or a monochrome display port; if it overheats, more than just the parallel port could be damaged. Beware. However, if you have an old TTL parallel port (with a 74LS374 chip, preferably socketed), it may be easy and cheap to replace if that chip should die.

I bought TTL parallel port card clones, fully socketed (all chips!), for about $15 mail order about 5 years ago. The bidirectional conversion was a trace cut and a wire jumper. The 74LS374 was easily replaced, if it were damaged or if one wanted a better chip like the 74ACT374. You could even strap it for any base address (including non standard ones, so as not to conflict). I wish I could get more; there must have been scads of these on the market. You may find old TTL printer ports used; latch onto them if you want to experiment with parallel port interfaces (pun acknowledged).

One last electrical note: if you use any sort of bidirectional parallel port for inputs, be sure to tristate it whenever it is connected to external devices which will drive it. When I'm running it this way, I put a small routine in my autoexec.bat which tristates the port in question on every bootup. Or use inline resistors to at least limit the current to a safe value.

Steven M. Scharf <scharf@mirage.nsc.com> notes that some higher end parallel port chips "lock" the direction control bit C5 to keep certain naive software from accidentally changing the port direction. In particular, he says that "PTR bit 7" of the National Semiconductor SuperI/O chip must be 1 before you can change the direction control bit. I don't have documentation on this chip, so I'm not sure what register PTR is; for now, consider this just a warning. He says that other chips may lock the direction control differently.


Enhanced Ports

There are at least two specs for further enhanced parallel ports, the EPP (Enhanced Parallel Port) and the ECP (Enhanced Capability Port), with the latter being more ambitious. I would appreciate any specs that can be forwarded to me (or references) on either of these.

Steven M. Scharf <scharf@mirage.nsc.com> gave this table:

Different Parallel Ports on NSC Parts
----------------------------------

PC87311 Bidirectional Parallel Port (16450 UARTS)
PC87312 Bidirectional Parallel Port (16550 UARTS)
PC87322 Enhanced Parallel Port (EPP) (16550 UARTS)*
PC87332 Enhanced Capabilities Port (ECP) also EPP 1.7 and 1.9 (16550 UARTS)*

*Floppy controller signals can be redirected out the parallel port pins via an internal multiplexor. This feature is used in some sub-notebooks with external floppy drives.


Copy Protection Dongles

(From info provided by Steven M. Scharf <scharf@mirage.nsc.com>)

Copy protection dongles typically watch the data lines for patterns of data without any -strobe signal (pin 1, controlled by C0-). That is, the copy protection software writes various patterns to the data lines without every pulsing the -strobe line. Without a pulse on -strobe, any printer also attached to the port should ignore this data. Not all dongles work on all ports; this strobeless method is a bit more temperamental than
regular printer output.

Steven M. Scharf: "I heard one dongle manufacturer complain to me about a parallel port from Taiwan that tristated all the data lines between every write to the data lines. This presented a pattern of FF to the dongle, but had no effect on the printer since there was no strobe. In this case the software was writing a sequence of bytes to the dongle and it didn't work due to the FF in between each expected real byte."

"The dongle also draws power from the signal lines--a definite no-no. Dongles should be designed to operate all the way down to the minimum TTL low or at least to minimum Vout High of 2.4V. If your dongle doesn't work but your printer works fine then it is almost certainly the fault of the dongle--not the parallel port. Software with an incompatible dongle to the parallel port on a machine will not be usable on that machine--one more reason to not penalize the legitimate buyers of software."


Other devices

From: geo@netcom.com (George Pontis)

"Another area that might be of interest in your document would be some comment on the parallel port extenders. I have a xmit/rcv pair from LinkSys that I bought from Fry's Electronics for about $70. They convert the parallel signal to a serial data stream, using the signal and control lines for power. My set was working fine until I added a hardware dongle for an expensive Windows application. Then, printing ceased to work reliably. I took the transmitter apart and partially traced the schematic. They have used 7 diodes to suck power from pins 13, 14, 15, 17, 1, 2, and 3. Also, they connected pins 15 (ERR) to 16 (INIT). The strobe line is coupled in to a flip-flop, which starts clocking the parallel loaded data."

Comment from Zhahai - with both a dongle and a parallel port extender trying to draw power from the port's data or control (not power) lines, it's not surprising if things don't always work! It must be really pushing the specs.


Transferring Data Via Ports

There are three basic ways to wire IBM printer ports together to transfer data between them. The most common is to wire D0 - D4 (or D3-D7) from one port to S3 - S7 from the other port, and vice versa. In this way, 4 bits of data can be put out by one (eg: D0 - D3) and read by the other (eg: S3 - S6); the other bit (eg: D4/S7) can be used for synchronizing (eg: Data Ready). If data is transferring one way, the Dn/Sn path the other direction can be used for acknowledgements. In this scheme, you must remember that S3 - S6 read the inverse of the other computer's D0 - D3 data bits, but S7 has the same value as D4 (or D3 - D6 and D7 respectively, for the alternate wiring). Also remember that S6 and S7's mapping to pins is swapped in order from the others.


Transfer Modes and Cables

Mode 1A: nibble mode, using Data Out to Status In connection
Mode 1B: nibble mode, using Data Out to Status In connection
Mode 1C: nibble mode, using Data Out to Status In connection
Mode 2: 8 bits, using bidirectional parallel port
Mode 3A: 8 bits, using Open Collector Control Outputs as inputs
Mode 3B: 8 bits, using Open Collector Control Outputs as inputs

Mode 1A: nibble mode, using Data Out to Status In connection. This version works with all parallel ports; commercial xfer software style.

Side 1   Pin     dir     Pin    Side 2   connection
    ------   ---     ---     ---    ------   ----------
     D0       2       =>     15      S3+     direct
     D1       3       =>     13      S4+     direct
     D2       4       =>     12      S5+     direct
     D3       5       =>     10      S6+     direct
     D4       6       =>     11      S7-     inverted

     S7-     11      <=       6      D4      inverted
     S6+     10      <=       5      D3      direct
     S5+     12      <=       4      D2      direct
     S4+     13      <=       3      D1      direct
     S3+     15      <=       2      D0      direct

     Gnd     25      ===     25      Gnd     (ground)

Mode 1B: nibble mode, using Data Out to Status In connection. This version works with all parallel ports; bit positions matched.

    Side 1   Pin     dir     Pin    Side 2   connection
    ------   ---     ---     ---    ------   ----------
     D3       5       =>     15      S3+     direct
     D4       6       =>     13      S4+     direct
     D5       7       =>     12      S5+     direct
     D6       8       =>     10      S6+     direct
     D7       9       =>     11      S7-     inverted

     S7-     11      <=       9      D7      inverted
     S6+     10      <=       8      D6      direct
     S5+     12      <=       7      D5      direct
     S4+     13      <=       6      D4      direct
     S3+     15      <=       5      D3      direct

     Gnd     25      ===     25      Gnd     (ground)

Mode 1C: nibble mode, using Data Out to Status In connection; Controls wired for additional interfaces. This version works with all parallel ports.

    Side 1   Pin     dir     Pin    Side 2   connection
    ------   ---     ---     ---    ------   ----------
     D3       5       =>     15      S3+     direct
     D4       6       =>     13      S4+     direct
     D5       7       =>     12      S5+     direct
     D6       8       =>     10      S6+     direct
     D7       9       =>     11      S7-     inverted

     S7-     11      <=       9      D7      inverted
     S6+     10      <=       8      D6      direct
     S5+     12      <=       7      D5      direct
     S4+     13      <=       6      D4      direct
     S3+     15      <=       5      D3      direct

     C0-      1      <=>*     1      C0-     direct
     C1-     14      <=>*    14      C1-     direct
     C2+     16      <=>*    16      C2+     direct
     C3-     17      <=>*    17      C3-     direct

     Gnd     25      ===     25      Gnd     (ground)

* Note: Control Out bits on receiver set high (including inversion, ie: C0,C1,C3=0; C2=1). Control feedback on receiver can read control out from sender. Can use some lines each way, and could switch C0 - C2 and C1 - C3 for symmetry if we want two lines each way, or other variations.

Mode 2: 8 bits, using bidirectional parallel port

This version works only with bidirectional parallel port whose Data Out can be tristated; the receiving side must tristate its Data Out port to
use its feedback register as an 8 bit input port.

    Side 1   Pin     dir     Pin    Side 2   connection
    ------   ---     ---     ---    ------   ----------
     D0       2      <=>*     2      D0      direct
     D1       3      <=>*     3      D1      direct
     D2       4      <=>*     4      D2      direct
     D3       5      <=>*     5      D3      direct
     D4       6      <=>*     6      D4      direct
     D5       7      <=>*     7      D5      direct
     D6       8      <=>*     8      D6      direct
     D7       9      <=>*     9      D7      direct

     C0-      1       =>     13      S4+     inverted
     C1-     14       =>     12      S5+     inverted
     C2+     16       =>     10      S6+     direct
     C3-     17       =>     11      S7-     direct

     S4+     13      <=       1      C0-     inverted
     S5+     12      <=      14      C1-     inverted
     S6+     10      <=      16      C2+     direct
     S7-     11      <=      17      C3-     direct

     Gnd     25      ===     25      Gnd     (ground)

* Note: bidirectional cards only; receiving side must tri-state with C5=1

If a two bidirectional ports are left connected in this fashion, and they are both enabled (eg: after powerup or reset) with different data outputs, then the 74LS374 driver chips could be "fighting". Just to be careful, when I created a cable like this (actually, a DB25 jumper box usually sold for RS-232 jumpering, along with straight through 25 line DB-25 cables), I used 8 10K resistors between the corresponding Data lines, to limit current in this case. (Actually, a DIP resistor pack fit perfectly on the PC board inside the DB-25 jumper box). The resistors are large enough to keep TTL output from overstressing another one if both enabled, but when one is disabled and the other enabled, the resistors are low enough to allow the TTL output to drive a TTL input well enough.

Mode 3A: 8 bits, using Open Collector Control Outputs as inputs
This version uses 4 control outputs as inputs, plus 4 status inputs.

  Side 1   Pin     dir     Pin    Side 2   connection
    ------   ---     ---     ---    ------   ----------
     D0       2       =>*     1      C0-     inverted
     D1       3       =>*    14      C1-     inverted
     D2       4       =>*    16      C2+     direct
     D3       5       =>*    17      C3-     inverted
     D4       6       =>     13      S4+     direct
     D5       7       =>     12      S5+     direct
     D6       8       =>     10      S6+     direct
     D7       9       =>     11      S7-     inverted

     C0-      1      <=*      2      D0      inverted
     C1-     14      <=*      3      D1      inverted
     C2+     16      <=*      4      D2      direct
     C3-     17      <=*      5      D3      inverted
     S4+     13      <=       6      D4      direct
     S5+     12      <=       7      D5      direct
     S6+     10      <=       8      D6      direct
     S7-     11      <=       9      D7      inverted

     Gnd     25      ===     25      Gnd     (ground)

* Note: Control outputs used as inputs must be programmed high: C0, C1, C3 = 0 and C2 = 1

Mode 3B: 8 bits, using Open Collector Control Outputs as inputs
This version uses 3 control outputs as inputs, plus 5 status inputs; remaining control output is bidirectional - if left high by default, either side can pull low (remember inverted logic).

    Side 1   Pin     dir     Pin    Side 2   connection
    ------   ---     ---     ---    ------   ----------
     D0       2       =>*     1      C0-     inverted
     D1       3       =>*    14      C1-     inverted
     D2       4       =>*    16      C2+     direct
     D3       5       =>*    15      S3+     direct
     D4       6       =>     13      S4+     direct
     D5       7       =>     12      S5+     direct
     D6       8       =>     10      S6+     direct
     D7       9       =>     11      S7-     inverted

     C0-      1      <=*      2      D0      inverted
     C1-     14      <=*      3      D1      inverted
     C2+     16      <=*      4      D2      direct
     S3+     15      <=*      5      D3      direct
     S4+     13      <=       6      D4      direct
     S5+     12      <=       7      D5      direct
     S6+     10      <=       8      D6      direct
     S7-     11      <=       9      D7      inverted
     C3-     17      <=>     17      C3-     direct (OC shared)

     Gnd     25      ===     25      Gnd     (ground)

* Note: Control outputs used as inputs must be programmed high: C0, C1, C3 = 0 and C2 = 1

[A future version of this document may sketch out the code to send and receive data through these connections]


Capturing "printed" data from another machine

A computer with a bidirectional printer port, connected with a Mode 2 cable to any standard port, could potentially pretend to be a printer so as to capture the "printed" information. It would configure its Data port for input, and set appropriate values on its Control Out to mimic a printer on the other computer's Status In lines. In the general case, the problem would be detecting the very brief -Strobe pulse; this would either require an external TTL latch triggered by -Strobe (either edge), or some way to sense a quick pulse on that line. In the latter case, a revised connection (call it Mode 2B) could connect the "printing" computer's -Strobe (C0-) line to the receiving computer's -Ack (S6+) line; the trailing edge of the printing computer's -Stobe would generate an interrupt on the receiving computer. I have not tried this. Of course,
the +Busy line would also be needed to avoid data overflow; perhaps it could be kept high (busy) most of the time, but pulsed low after reading the data (which would be handled by the IRQ routine).

[If anybody has had some success with this, let me know.]


Controlling Outputs

This can be easy; just use the Data Out TTL signals to control TTL level items. Unfortunately, they cannot source much current (providing positive voltage on the pin, relative to ground) - be careful of the 2.6 mA limit. Some LSI implementations might allow more or less than this (likely less).

      Dn Out ------+
                  |+
Sourcing         Load (up to 2.6 mA @ 2.4 v)
                     |-
      Ground ------+

If you have an external +5 volt supply, you have two options: use the Data Out pins to sink up to 24 mA from your +5 volt supply, or use buffer chips to control (source or sink) more current (or higher voltages). I have used an exteranl 5 Volt supply (regulated wall wart) plus optocoupled solid state relays as the "load", to control AC voltages (keep the high AC voltages away from any of this logic level stuff, obviously).

                   +------------------------ (+5 v)
                   |+
 Sinking         Load (up to 24 mA @ 4.2v)
                   |-                       Power Supply
      Dn Out ------+

      Ground ------------------------------- ( Gnd)

Use limiting resistors if you need to limit the current.

If the load were an LED (or optocoupler) through which you wished to put 20 mA, do the calculations. The Dn Output will probably be around 0.7 volts, so you have about 4.3 volts of drop; the LED will drop about 1.9 v (check specs!), leaving 2.4 V to be dropped by a resister at 20 mA: 120
ohms. Test and measure, adjust to fit.

You can also use the Control Out pins. They can't source much of anything (about 1 mA through the 4.7K resistors to +5), and can only sink about 7mA. (The LS TTL gate actually sinks 8 mA, but one is taken up by the 4.7 K resistor to +5). Again, check on clones with different electical specs. This can control TTL inputs fine, and might be able to run an optocoupler or solid state relay in sink mode (depends on the device).

In one application, I used two 74ACT374 latches, which can source 48 mA or sink 64 mA. I connected the 8 inputs of each to the Data Out, and the latch clocks to two Cn outputs. In software, I put out 8 bits of data on the Data Out port, pulsed a Cn bit to latch it into one 74ACT374, put the next 8 bits out on Data Out, and used the other Cn bit to latch it into the other 74ACT374 - voila, 16 bits of 64mA output control. Of course, this took a separate +5 V power supply ($5 surplus regulated wall wart).

If you can still find an old TTL parallel port (especially with sockets), you can substitute the 74ACT374 chip for the original 74LS374 and get better drive capability. The back of magazine suppliers were selling *fully socketed* TTL based parallel ports for about $15 a few years back; by cutting a trace and soldering a jumper you could make them bidirectional; by plugging in a $1 chip you could make them source/sink 48/64 mA. You might still find such TTL parallel port cards in old PCs. Typically, one designed for the original PC will still work fine on the ISA bus of your 486DX2-66, so don't worry about that.


Sensing switches

There are several ways to sense external switches via a parallel printer port. If you are dealing with naked switches, the simplest is actually to connect up to 4 switches between the control outputs (pins 1,14,16, and 17) and ground, program the control outputs high (counting inversions), and use the control feedback register to read switch state (counting inversions). This is because the pull-up resisters are already implemented for the open collector Control Out pins.

  Cn Out ------+    (Program output high; read feedback)
               |
             switch
               |
  Ground ------+

Another simple method would be to use up to 5 pullup resistors (4.7K) from the Status inputs to +5 volts, and use switches to pull these down to ground. One disadvantage of this is that it uses an external +5 supply. TTL inputs tend somewhat to float high, so you *might* get by without the pullup resistors, but you are pushing it.

                 4.7K
  Sn In -------+-^^^^^--- (+5 v)  (Read status register)
               |
             switch
               |
  Ground ------+---------- (gnd)

You could use this same scheme for 8 inputs on the data lines of a bidirectional printer port - but you have to be sure that the outputs are tristated beforehand, or your switches may damage the 74LS374 (or equiv). This latter may be a problem after booting or rebooting. One approach is to use current limiting resistors in series "just in case". You should ideally still have pullup resistors too. (The 1K value is chosen for LS TTL, to keep the 2.4 V output at no more than 2.4 mA sourcing).

             1K        4.7K
  Dn Out ---^^^^^---+--^^^^^--- (+5v)
                    |
                  Switch
                    |
  Ground -----------+---------- (Gnd)


Optocoupled inputs

To be written.


Matrix scanning

In an upcoming project, I want to use a 4x4 keypad as an input. In this type of keypad (warning: there are other types), each key makes a connection from one row to one column, when pressed. My first design has the "columns" connected to the 4 Control Out pins, while the "rows" are connected to 4 of the Status Inputs. Normally, all 4 control outputs were programmed high, but to scan the keypad, I would lower one control output at a time, and read the 4 status inputs at that time. The 4 status inputs are each pulled high to +5 volts via a 10K resistor, or left to float. (Use Dn plus resistors rather than +5 external supply?) This scheme could be expanded to as large as 4x5 (4 Cn outputs, 5 Sn inputs).

                         10 K
 S4 ------------X X X X--^^^^^--+--- (+5)
 S5 ------------X X X X--^^^^^--+
 S6 ------------X X X X--^^^^^--+     (these pullups optional?)
 S7 ------------X X X X--^^^^^--+
                | | | |
 C3 ------------+ | | |  Scan one Cn low at a time,
 C2 --------------+ | |  read Sn each time
 C1 ----------------+ |
 C0 ------------------+

Alternate scheme. Use Dn's for scanning output rows, through diodes which will isolate them from each other if two keys in the same column are pressed. (Otherwise we have drivers fighting, and indeterminate voltage levels). Germanium small signal diodes have less voltage drop. Use the Cn pins as inputs (with existing pullups) - program Control Out for high TTL levels, and read the feedback register for input (counting inversions). No extra power supply is needed. The diode between TTL output low and TTL input low will push the TTL noise margins, but you can usually get by with it. This scheme could be expanded up to 8x4 (8 Dn outputs, 4 Cn used as inputs). If we know that only one key (or one key per column) will be pressed at a time, the diodes can be omitted.

       1N914
 D0 ----|<|-----X X X X  (Set all Cn high),
 D1 ----|<|-----X X X X  Scan one Dn low at a time,
 D2 ----|<|-----X X X X  read all Cn
 D3 ----|<|-----X X X X
                | | | |
 C3 ------------+ | | |
 C2 --------------+ | |
 C1 ----------------+ |
 C0 ------------------+

Note that if we press three switches in the matrix which form 3 corners of a box, it will appear as if all 4 corners are pressed; this is true of any such matrix, unless each switch has its own diode.

I hope to have some results to share in a later revision of this doc.


Tutorial on TTL outputs

In response to requests, here is a brief tutorial on chip outputs. As a preface, it is conventional to discuss current as flowing from positive to negative, even though we know full well that electrons actually move in the opposite directions; it's just a convention, not ignorance.

      +5                             +5
     /                                \
 ---H              external resistor  /
     \                                \
      |_____               ___________/
      |   out              |   out
     /                    /
 ---L                 ---L
     \                    \
     Gnd                  Gnd

Totem Pole Open Collector

Regular TTL outputs basically consist of a two "stacked" transistor in series between +5 volts and ground, with the output coming from the connection between them. This is called a "totem pole output". At any given time one of these transistors is conducting and the other is not. To pull the output "high", the transistor from +5 to the output conducts (H), which "sources" positive current from the output to ground (that is, an external device between the output and ground will get power). To pull the output low, only the lower transistor (L) conducts, "sinking" current to ground; an external device between +5 volts and the output can be energized. Current flows into the chip for low, out of it for high.

      +5
     /    |
 ---H on  V
     \      -->
      |________  TTL output on = 1 = high, "sourcing" current
      |   out  \
     /         / |
 ---L off      \ V
     \_________/
     Gnd

    +5_________
     /         \
 ---H off      / |
     \         \ V
      |________/ TTL output off = 0 = low, "sinking" current
      |  <-- out
     /
 ---L on |
     \   V
     Gnd

The 0 / pull low current capacity (sinking) is larger than the 1 / pull high capacity (sourcing). If you want to drive something like an LED, or a solid state relay, you can get more current from the TTL outputs by connecting it between +5 and the gate output (second picture) - *if* it's electrically isolated from ground. You still have to check the current and voltage ratings, tho.

One key here is that the chip is always trying to pull either high or low, and the currently conducting transistor has voltage and current limits, beyond which it can be damaged. It is not good design to connect two such outputs which may have different states - one pulling high and one low - because this will exceed the current specs. However, if you do, the one pulling low will "win", since TTL can sink (pull low) more strongly
than it can source (pull high). And there is some slack in the specs, so this does not always immediately damage the chip; we'll get back to this.
These are the type of outputs on the DATA lines on the original IBM parallel port. (Well, not exactly, but I'll get back to that too).

Another type of output is the "open collector". In this case, there is a transistor from the output pin to ground, but none to +5 volts. The two states are 0, "conducting to ground" (pulling low), and 1, "not conducting" (floating, not pulled either way). Externally, you can connect a resistor of proper value between the line and +5 volts to pull the line high when the chip output is floating. The value is chosen such that when the output is conducting to ground, it overpowers the external resistor and the line goes low. The advantage of this scheme is that you can connect multiple open collector outputs together (or even slip in one totem pole). Every output that is floating is ignored (and the resistor will pull the line high if and only if all outputs are floating); multiple outputs pulling low cause no conflict. This is the type of output used for CONTROL lines in the original IBM parallel port.

Since each parallel port control output line has a corresponding feedback bit that can be read (mainly for diagnostics, to see if the line really goes high or low), it is possible to program these CONTROL outputs "high" (really floating), and then allow external signals control the high or low state of the line. An external open collector output, or a totem pole one, is capable of pulling the line high (reinforcing the pullup resistor) or low
(overpowring it) without exceeding current specs. In this way you can use the control lines as inputs. If there is no external signal, it will read
high. However, you must program the CONTROL outputs high (taking into account any logical inversions between the register bits and the electrical outputs); if the open collector output is low (conducting to ground), the external signal won't be able to pull it high (or at least not without exceeding the specs).

The same thing can be done with totem pole outputs - program them high, and let external logic pull them high (no problem, both pulling up) or low (overpowering the attempt to pull high), but in this case you are overloading the H transistor, rather than a pullup resistor, and exceeding spec, with possible unreliability or damage. However, this has been successfully done with the data outputs of a conventional parallel port, and some people claim not to have seen any damage yet. Don't blame me if you do it and something dies.

A third type of gate is a totem pole in which both high and low transistors can be non-conducting at once, creating a third, floating state (this is often called a tri-state output). When it is in this third state, the line is not being pulled high nor low by this device, and thus can be safely controlled by some other device. No pullup resistor is used. The 74LS374 chip used for the standard parallel port DATA outputs actually has tristate ability, but as described elsewhere the third state is not used, and it is always trying to pull high or low - thus my initial description of the DATA lines as totem pole drivers.

The way true bidirectional parallel ports work is to allow the software to selectively put the DATA outputs into the third, undriven state. Then you can use the data feedback register to read whatever highs or lows are put onto the data lines externally.

Non-TTL logic, like CMOS, has the equivalents of these, but with a different type of transistor, and different voltage and current values. If your parallel port uses a single chip or otherwise differs from the original IBM parallel port, the above electrical description cannot be guaranteed, but it is probably pretty analogous. Let me know if you have specific knowledge about the electical specs of your single chip parallel port, for future versions of this document.

Note again that high and low in this description are electrical levels, as would me measured by a voltmeter on the pins; high is associated with TTL logic 1, but whether a given CONTROL output line is high when the corresponding register bit is 1 or 0 varies with the line, as is described elsewhere in this document. The DATA lines are straight through, with no inversions, so a 1 bit produces a high output.


Contributors and Information Needed for future revisions

My thanks for information, proofreading and suggestions from:

scharf@mirage.nsc.com (Steven M. Scharf)
cgd@ecmwf.co.uk (Dick Dixon)
rstevew@armory.com (Richard Steven Walz)
geo@netcom.com (George Pontis)
jmorriso@bogomips.ee.ubc.ca (John Paul Morrison)

For the future:

· I would like specs on the various enhanced printer ports and chipsets.

· I would appreciate information on how parallel port connected Ethernet interfaces, SCSI interfaces, tape backup units, sound cards, modems, and copy protection devices work (which pins used how), including how "transparency" is achieved (or not) on those with "passthrough".

· I would appreciate info on data transfer programs, cables, and protocols.

· I would like to hear about interrupt driven PC printer drivers, for DOS or Unix or whatever (or why they don't work).

· I would like to hear of "printer capture" software and hardware that uses printer ports.

· I would like to know about differences between "old standard" TTL parallel ports and the LSI implementations (specific chip specs included).

· I would like to hear of your interfacing projects, sucessful or not.

· And of course, I'd like to hear about bugs and inaccuracies in this document. (Gently)


Differences
Previous Top

· Version 0.92 corrected two minor typos which were kindly brought to my attention (D2 in place of C2 in one place, and 7505 in place of 7405), and reformatted some long lines.

· Version 0.94 added a tutorial on TTL outputs.

· Version 0.95 corrected the section on data xfer cables for Laplink style programs.

· Version 0.96 fixed yet more errors.

= end of Version 0.96 9/1/94 Zhahai Stewart zstewart@hisys.com


.topic 1001
There are two main parts of installation process:

Common part of installation (full software package installation)

Compiler specific installation

Common part of installation

Run TVicLptDemoInstall.exe  or TVicLptReg.exe.  This is a Windows-based application you can run from either the Start  or Run  button, or  from an MS-DOS prompt. Read the Software License Agreement and, if you agree with its terms, click I agree with the above terms and conditions to accept the Agreement and click Next . Select the drive and directory where you want to install the TVicLPT and then click Start . After the installation of components is completed, click OK . Click Yes button to reboot your PC   after installation.

Compiler specific installation

Note:
Information below is applicable only for demo version of TVicLPT. Registered users refer to install.txt file provided in distributive.

Visual Basic: No additional installation required because the TVicLPT ActiveX Control  was already registered by the installation program. Just go to <TVicLPT>/VB/ directory, then load and run any test application.

Visual C++:  Menu->Project->Add to project->Files->.. browse to \Component\MSVC\VicLPT.obj, VicLPT.h..Ok.

Borland Delphi 2.0: Menu->Component->Install->Add->.. browse to \Component\Delphi2\LptUnit.dcu..->Ok.

Borland Delphi 3.0-7.0: File->Open->Delphi Package Source(*.dpk)->..browse to \Component\DelphiX\lpt_dX.dpk->Open, where  "X" is a Delphi version number. Press "Compile" then press "Install".

Borland C++Builder 1.0: Menu->Component->Install->Add->.. browse to \Component\Builder1\LptUnit.obj..->Ok.

Borland C++Builder 3.0-6.0: Menu->Component->Install Packages->Add->lpt_bX.bpl->Ok, where "X" is a C++Builder version number.

Notes:

For all Delphi/C++Builder versions:  The TVicLPT  component should appear at the "Drivers" tab page of the components palette.
Files required for commercial users are included in Component\Kernel folder


Introduction
Top

What is TVicLPT?

·

Programming Languages Supported


LptAckwl

LptAckwl Property (Read Only)
Data Type :
Integer
Returns
ACKWL state from the current parallel port.
VB syntax:
object .LptAckwl
++ syntax:
object .LptAckwl;
Delphi syntax (VCL):
object .LptAckwl;
Returns:
1 - active state
0 - not active
Remarks:


LptAutofd
Property (write
only)
Data Type :
Integer
Sets AUTOFD state of the current parallel
port.
VB syntax:
object .Autofd [ = value
]
C++ syntax: object .Autofd [ = value ];

Delphi syntax (VCL):
object .Autofd [:= value
];
The settings for value are :
1 - set
active state
0 - reset state
Returns:
None
Remarks:


LptBusy

LptBusy Property (Read Only)
Data Type :
Integer
Returns
BUSY state from the current parallel port.
VB syntax:
object .LptBusy
++ syntax:
object .LptBusy;
Delphi syntax (VCL):
object .LptBusy;
Returns:
1 - active state
0 - not active
Remarks:


LptError

LptError Property (Read Only)
Data Type :
Integer
Returns
SLCT state from the current parallel port.
VB syntax: object . LptError
++ syntax:
object .LptError;
Delphi syntax (VCL): object .LptError;
Returns:
1 - active
state
0 - not
active
Remarks:


LptPaperEnd

LptPaperEnd Property (Read Only)
Data Type :
Integer
Returns
Paper
End state from the current parallel port.
VB syntax:
object .LptPaperEnd
++ syntax:
object .LptPaperEnd;
Delphi syntax (VCL):
object .LptPaperEnd;
Returns:
1 - active state
0 - not active
Remarks:


LptSlct

LptSlct Property (Read Only)
Data Type :
Integer
Returns
SLCT state from the current parallel port.

VB syntax:
object .
LptSlct
++ syntax:
object .LptSlct;
Delphi syntax (VCL): object .LptSlct;
Returns:
1 - active
state
0 - not
active
Remarks:


Transfer Modes and Cables
Top

Mode 1A: nibble mode, using Data Out to Status In connection
Mode 1B: nibble mode, using Data Out to Status In connection
Mode 1C: nibble mode, using Data Out to Status In connection
Mode 2: 8 bits, using bidirectional parallel port
Mode 3A: 8 bits, using Open Collector Control Outputs as inputs
Mode 3B: 8 bits, using Open Collector Control Outputs as inputs

Mode 1A: nibble mode, using Data Out to Status In connection
This version works with all parallel ports; commercial xfer software style.

Side 1 Pin dir Pin Side 2 connection
------ --- --- --- ------ ----------
D0 2 => 15 S3+ direct
D1 3 => 13 S4+ direct
D2 4 => 12 S5+ direct
D3 5 => 10 S6+ direct
D4 6 => 11 S7- inverted

S7- 11 <= 6 D4 inverted
S6+ 10 <= 5 D3 direct
S5+ 12 <= 4 D2 direct
S4+ 13 <= 3 D1 direct
S3+ 15 <= 2 D0 direct

Gnd 25 === 25 Gnd (ground)

Mode 1B: nibble mode, using Data Out to Status In connection
This version works with all parallel ports; bit positions matched.

Side 1 Pin dir Pin Side 2 connection
------ --- --- --- ------ ----------
D3 5 => 15 S3+ direct
D4 6 => 13 S4+ direct
D5 7 => 12 S5+ direct
D6 8 => 10 S6+ direct
D7 9 => 11 S7- inverted

S7- 11 <= 9 D7 inverted
S6+ 10 <= 8 D6 direct
S5+ 12 <= 7 D5 direct
S4+ 13 <= 6 D4 direct
S3+ 15 <= 5 D3 direct

Gnd 25 === 25 Gnd (ground)

Mode 1C: nibble mode, using Data Out to Status In connection; Controls wired
for additional interfaces. This version works with all parallel ports.

Side 1 Pin dir Pin Side 2 connection
------ --- --- --- ------ ----------
D3 5 => 15 S3+ direct
D4 6 => 13 S4+ direct
D5 7 => 12 S5+ direct
D6 8 => 10 S6+ direct
D7 9 => 11 S7- inverted

S7- 11 <= 9 D7 inverted
S6+ 10 <= 8 D6 direct
S5+ 12 <= 7 D5 direct
S4+ 13 <= 6 D4 direct
S3+ 15 <= 5 D3 direct

C0- 1 <=>* 1 C0- direct
C1- 14 <=>* 14 C1- direct
C2+ 16 <=>* 16 C2+ direct
C3- 17 <=>* 17 C3- direct

Gnd 25 === 25 Gnd (ground)

* Note: Control Out bits on receiver set high (including inversion, ie:
C0,C1,C3=0; C2=1). Control feedback on receiver can read control out from
sender. Can use some lines each way, and could switch C0 - C2 and C1 - C3
for symmetry if we want two lines each way, or other variations.

Mode 2: 8 bits, using bidirectional parallel port

This version works only with bidirectional parallel port whose Data Out
can be tristated; the receiving side must tristate its Data Out port to
use its feedback register as an 8 bit input port.

Side 1 Pin dir Pin Side 2 connection
------ --- --- --- ------ ----------
D0 2 <=>* 2 D0 direct
D1 3 <=>* 3 D1 direct
D2 4 <=>* 4 D2 direct
D3 5 <=>* 5 D3 direct
D4 6 <=>* 6 D4 direct
D5 7 <=>* 7 D5 direct
D6 8 <=>* 8 D6 direct
D7 9 <=>* 9 D7 direct

C0- 1 => 13 S4+ inverted
C1- 14 => 12 S5+ inverted
C2+ 16 => 10 S6+ direct
C3- 17 => 11 S7- direct

S4+ 13 <= 1 C0- inverted
S5+ 12 <= 14 C1- inverted
S6+ 10 <= 16 C2+ direct
S7- 11 <= 17 C3- direct

Gnd 25 === 25 Gnd (ground)

* Note: bidirectional cards only; receiving side must tri-state with C5=1

If a two bidirectional ports are left connected in this fashion, and they
are both enabled (eg: after powerup or reset) with different data outputs,
then the 74LS374 driver chips could be "fighting". Just to be careful,
when I created a cable like this (actually, a DB25 jumper box usually sold
for RS-232 jumpering, along with straight through 25 line DB-25 cables), I
used 8 10K resistors between the corresponding Data lines, to limit current
in this case. (Actually, a DIP resistor pack fit perfectly on the PC board
inside the DB-25 jumper box). The resistors are large enough to keep TTL
output from overstressing another one if both enabled, but when one is
disabled and the other enabled, the resistors are low enough to allow the
TTL output to drive a TTL input well enough.

Mode 3A: 8 bits, using Open Collector Control Outputs as inputs
This version uses 4 control outputs as inputs, plus 4 status inputs.

Side 1 Pin dir Pin Side 2 connection
------ --- --- --- ------ ----------
D0 2 =>* 1 C0- inverted
D1 3 =>* 14 C1- inverted
D2 4 =>* 16 C2+ direct
D3 5 =>* 17 C3- inverted
D4 6 => 13 S4+ direct
D5 7 => 12 S5+ direct
D6 8 => 10 S6+ direct
D7 9 => 11 S7- inverted

C0- 1 <=* 2 D0 inverted
C1- 14 <=* 3 D1 inverted
C2+ 16 <=* 4 D2 direct
C3- 17 <=* 5 D3 inverted
S4+ 13 <= 6 D4 direct
S5+ 12 <= 7 D5 direct
S6+ 10 <= 8 D6 direct
S7- 11 <= 9 D7 inverted

Gnd 25 === 25 Gnd (ground)

* Note: Control outputs used as inputs must be programmed high:
C0, C1, C3 = 0 and C2 = 1

Mode 3B: 8 bits, using Open Collector Control Outputs as inputs
This version uses 3 control outputs as inputs, plus 5 status inputs;
remaining control output is bidirectional - if left high by default,
either side can pull low (remember inverted logic).

Side 1 Pin dir Pin Side 2 connection
------ --- --- --- ------ ----------
D0 2 =>* 1 C0- inverted
D1 3 =>* 14 C1- inverted
D2 4 =>* 16 C2+ direct
D3 5 =>* 15 S3+ direct
D4 6 => 13 S4+ direct
D5 7 => 12 S5+ direct
D6 8 => 10 S6+ direct
D7 9 => 11 S7- inverted

C0- 1 <=* 2 D0 inverted
C1- 14 <=* 3 D1 inverted
C2+ 16 <=* 4 D2 direct
S3+ 15 <=* 5 D3 direct
S4+ 13 <= 6 D4 direct
S5+ 12 <= 7 D5 direct
S6+ 10 <= 8 D6 direct
S7- 11 <= 9 D7 inverted
C3- 17 <=> 17 C3- direct (OC shared)

Gnd 25 === 25 Gnd (ground)

* Note: Control outputs used as inputs must be programmed high:
C0, C1, C3 = 0 and C2 = 1

[A future version of this document may sketch out the code to send and
receive data through these connections]