Building OnChange event to listen the parallel port

Friday, April 3rd, 2009 by Pablo Romano

The parallel port, like most of the hardware, is becoming each day more unknown to the developers. We are getting used to languages that encapsulate all these low level things for us.

Well, recently I found myself needing to wake up an application of mine when the signal of the parallel port changed. This is what I did!

Intro

When I started sketching the behavior of my ParallelPortListener I decided not to go deeper into the OS trying to reach the IRQs. I preferred a code not as optimal but much cleaner and maintainable.

Here is the Source Code.

Code Arrangement

The code is composed of two classes: the ParallelPortListener I told you before and an internal class I called PortAccess whose only task is to call a method, Input(int address), from a dll I’ll talk about later.

ParallelPortListener Class

ParallelPortListener is also composed of many portions of code, each one with a very different purpose:

  • The implementation of a Singleton.
    This class is a Singleton because I didn’t want simultaneous reads to the port (another possibility was to use the locking mechanisms)
  • A delegate OnPortChangedHandler
  • A public event OnPortChanged where outsiders can subscribe methods matching the signature of OnPortChangedHandler
  • A Listener section which contains a Timer that invokes the PortAccess class, and two methods to control this Timer: Start and Stop

Ok, too much introduction, let’s see some code!

Port Access

using System.Runtime.InteropServices; //This namespace contains DllImportAttribute

namespace Utilities
{
	public class PortAccess
	{
		[DllImport("inpout32.dll", EntryPoint = "Out32")]
		public static extern void Output(int adress, int value);

		[DllImport("inpout32.dll", EntryPoint = "Inp32")]
		public static extern int Input(int adress);
	}
}

I call the external function “Out32″ in the dll “inpout32.dll” by adding the attribute System.Runtime.InteropServices.DllImport to my method Output.
The external function name is set in EntryPoint, I also had to set the dll name, in this case “inpout32.dll”.

Note: It’s important to remember that inpout32.dll must be on the same location where the application is running.

The best way to be sure you won’t forget is letting VS take care of it.

  1. Add inpout32.dll to your solution
  2. Right click on the file and go to properties
  3. Set “Build Action” to “Content”
  4. Set “Copy to Output Directory” to “Copy if newer”

ParallelPortListener

Public Properties

The setter is private, only the class can set the value

public int PortValue { get; private set; }

Singleton

private ParallelPortListener() { }

private static readonly ParallelPortListener _instance = new ParallelPortListener();
public static ParallelPortListener Instance { get { return _instance; } }

I like this way of implementing the pattern but there are others

Delegate

Delegate to handle the event

public delegate void PortChangedHandler(int portValue);

Event

And here we have some interesting code, how to create an event.

private event PortChangedHandler _portChanged;
public event PortChangedHandler OnPortChanged
{
	add
	{
		_portChanged += value;
		Start();
	}
	remove
	{
		_portChanged -= value;
		if (_portChanged.GetInvocationList().Length == 0) { Stop(); }
	}
}

private void PortChanged()
{
	if (_portChanged != null)
	{
		_portChanged(PortValue);
	}
}

Instead of Start I could have used “if (_portChanged.GetInvocationList().Length == 1) { Start(); }”, but I know my method and checking that is more expensive  than calling it.
When I call Stop checking is mandatory.

OnPortChanged is where handlers register themselves to observe the port, when someone registers I Start the ParallelPortListener.
The private method PortChanged is called by the Listen method (keep reading) when the PortValue changes.

Listener section

Let’s define two constants: LISTEN_FREQUENCY and PORT_ADDRESS

private const UInt32 LISTEN_FREQUENCY = 100; //100ms
private const Int32 PORT_ADDRESS = 889;

The address 889 is for reading the parallel port.

private Timer _timerListen;

//Starts the Timer
private void Start()
{
	if (_timerListen == null)
	{
		_timerListen = new Timer(Listen, null, 0, LISTEN_FREQUENCY);
	}
}

//Stops the Timer
private void Stop()
{
	if (_timerListen != null)
	{
		_timerListen.Dispose();
		_timerListen = null;
	}
}

private void Listen(Object unusedParameter)
{
	int newPortValue = PortAccess.Input(PORT_ADDRESS);
	if (newPortValue != PortValue) //If the value has changed
	{
		PortValue = newPortValue; //Update PortValue
		PortChanged(); //Notify the listeners
	}
}

This Timer is used to Listen the port every LISTEN_FREQUENCY and update PortValue if necessary.

I hope you’ll find this code useful, download it and if you have any doubts or comment feel free to post!

References

How to program a parallel port using c# the way you want
Implementing Singleton in C#
Timer Class

Tags: , , , , , ,

12 Responses to “Building OnChange event to listen the parallel port”

  1. Wilman Says:

    Excellent article! Very complete and neat

  2. Wilman Says:

    I have only one question, i am newbie with Delegates and I would like to see an example showing how to use ParallelPortListener. Thanks a lot in advance

  3. Pablo Romano Says:

    Hi Wilman,
    Thanks, I’m glad you liked it!

    Here is an example, if you have any doubts tell me.

    Greetings from the other side of the Rio de la Plata,
    Pablo

    Example:

    class DemoClass
    {
    public DemoClass()
    {
    PortListener.ParallelPortListener.Instance.OnPortChanged += OnPortChanged;
    }

    void OnPortChanged(int portValue)
    {
    //Do something with portValue
    }
    }

  4. wilman Says:

    Pablo,

    I have already figured it out myself after trying but thanks a lot for typing it since it will be useful for others I think. The project worked great with this. Go ahead, really nice blog!

  5. niraj Says:

    hello is it listen to lpt pin no 10????????? plz replay soon

  6. Pablo Romano Says:

    Hi Niraj,
    The code listens all the pins, it translates the binary number to it’s decimal form.
    If you only need the 10th pin you can mask the others by doing “bool pinState = (readedNumber & (int)Math.Pow(2, 6)) != 0;” (http://www.ctv.es/pckits/tutorial.html#padr)

    Please tell me if this helps or you need more assistance.

  7. Miguel Hidalgo Says:

    Excelent article, but I have a question: Does it works with a USB to parallel cable (1284)? I am looking to access the pins of the this port with the cable.

    Thank you

  8. Pablo Romano Says:

    Hi Miguel,
    I haven’t tried the code with a usb to parallel, I think in the worst case only a change in the PORT_ADDRESS constant will be needed.

    Try it and let me know

  9. bennyben Says:

    how to deactivate a certain pin?
    i know that ‘PortAccess.Output(address, 0)’ is to deactivate all the pins.

  10. Pablo Romano Says:

    Hi Bennyben,
    I guess you want to send a 0 to a particular pin, but when you write to the port you must send 1s or 0s to all the others too.

    Reading and writing can be done through PortAccess.Input and PortAccess.Output. The latter receives the address and a decimal value that is converted to it’s binary form, where each bit correlates to a pin. Here is a link explaining what you can do with each pin.
    http://www.beyondlogic.org/spp/parallel.htm#5

    If you want to change the value of one pin first of all you need the value of the others, the ones that don’t change. If you are working with the bi-directional pins you can read the value, if you are using the write-only ones you must keep the value in your application.

    Let’s suppose the value is 11011011 = 219 dec and you want to send a 0 to the 4th pin (bit 3), then you should make a mask that has a 0 in that position, 1s in all the others and make a bitwise and (&) with the current value. Here is an example:

    int currentValue = 91; //01011011

    int mask = 255 - (int)Math.Pow(2, 3); //11111111 - 1000 = 11110111

    int newValue = currentValue & mask; //01110111 & 11011011 = 01010011

    If you want to send a 1 to a pin you should make a mask with 1 in that pin, 0s in all the others and make a bitwise or (|) with the current value.

    Please tell me if this helps or you need more assistance.

  11. robert hacault Says:

    I have my code working but I have a question on the pins

    I am trying to receive some inputs from the port.

    I know the 8 data pins are used for output
    I can receive the input of the 5 status pins but for some reason I cant find a way to receive input data from the 4 control pins. I though they were I/O. if so , what am I doing wrong?

  12. robert hacault Says:

    got it to work

Leave a Reply

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word