Hello,

I've got a question about timing incoming IR signals and decoding them
in Windows.

Here's my story. I've built a device which detects IR signals at 38KhZ
and sends interrupts to the parallel port. Then I created (well, I
didn't write it entirely, but I edited one I found on the internet) a
driver to catch those interrupts and I created a usermode program to
interact with the driver. So far so good, everything seemed to work
fine. I receive interrupts when I press a button on my remote control
or when I just connect a wire between pin 2-9 and 10 of the parallel
port.

But there's also a problem. For some reason, I receive way too few
interrupts when I press a button on my remote control, and the time
between the interrupts always is nearly identical. My only guess is
that for some reason processing an interrupt hasn't finished yet when
the next interrupt arrives and that therefore that interrupt doesn't
get handled. That should also explain why the time between logged
interrupts is nearly identical; it always takes the same time to
complete one interrupt and after that it can handle another. But I
don't get why handling the interrupt would take that long. My pc
should be fast enough to handle it.

Here's my isr and dpc routine and after that the part in DriverEntry
where I connect the interrupt to my driver. When an interrupt occurs,
first the isr gets called and then the dpcroutine.

I hope any of you have an idea why it doesn't handle all interrupts or
what the problem is and how it can be fixed.

Thanks in advance,
Floris van Nee

BOOLEAN hwinterfaceIsr(IN PKINTERRUPT Interrupt, IN OUT PVOID Context)
{
PDEVICE_OBJECT DeviceObject = Context;

//KdPrint( ("hwinterface.sys: Interrupt Service Routine\n") );
/* We should check if the interrupt comes from us and return */

IoRequestDpc(DeviceObject,
DeviceObject->CurrentIrp,
NULL);

return TRUE;
}

VOID hwinterfaceDpcRoutine(IN PKDPC Dpc, PDEVICE_OBJECT DeviceObject,
IN PIRP Irp, IN PVOID Context)
{
PLOCAL_DEVICE_INFO DeviceExtension;
PIRP pIrp;

pIrp = DeviceObject->CurrentIrp;
DeviceExtension = DeviceObject->DeviceExtension;

//Get the current 'time' and print it to kernel debug
KeQueryTickCount((PLARGE_INTEGER)&TickCount);
KdPrint(("Interrupt: %d", TickCount));

return;
}





DeviceExtension = DeviceObject->DeviceExtension;

DeviceExtension->Level = 7;
DeviceExtension->Vector = DeviceExtension->Level;

MappedVector = HalGetInterruptVector(Isa,
0,
DeviceExtension->Level,
DeviceExtension->Vector,
&Irql,
&DeviceExtension->Affinity);
if (MappedVector == 0) DbgPrint("hwinterface.sys:
HalGetInterruptVector failed\n");

IoInitializeDpcRequest(DeviceObject,hwinterfaceDpcRoutine);
KdPrint(("%d", &DeviceExtension->InterruptObject));
status = IoConnectInterrupt(&DeviceExtension->InterruptObject, //
InterruptObject
hwinterfaceIsr, // ServiceRoutine
DeviceObject, // ServiceContext
NULL, // SpinLock
MappedVector, // Vector
Irql, // Irql
Irql, // SynchronizeIrql
Latched, // InterruptMode
FALSE, // ShareVector
DeviceExtension->Affinity, // ProcessorEnableMask
FALSE); // FloatingSave

if (!NT_SUCCESS (status)) DbgPrint("hwinterface.sys:
IoConnectInterrupt Failed\n");

RE: handling parallel port interrupts by AntonBassov

AntonBassov
Tue Apr 17 23:08:09 CDT 2007

I just have no words here - your code is a "masterpiece" in absolutely all
respects.....

Look at the code below:

> DeviceExtension->Level = 7;
> DeviceExtension->Vector = DeviceExtension->Level;

> MappedVector = HalGetInterruptVector(Isa,
> 0,
> DeviceExtension->Level,
> DeviceExtension->Vector,
> &Irql,
> &DeviceExtension->Affinity);

You assign interrupt vector yourself, and then ask HalGetInterruptVector()
to map it. Brilliant!!! What if untranslated vector has been already assigned
to some other device??? If your driver supports legacy hardware, it must call
IoReportResourceForDetection() to claim hardware resources before it attempts
to detect the device - you have to make sure that there is no conflict
detected before you can do anything. Please note that
HalGetInterruptVector() does not care about the conflicts - it just returns
IRQ-to-vector mapping, even if vector is already in use. Furthermore, don't
forget that IOAPIC allows the OS to map IRQs to vectors in any way it likes,
so that a single vector may service multiple IRQs on APIC HAL. IRQ-to-vector
mapping is done by the system with interrupt priority implied by vector
number, so that you have no control over it whatsoever.
However, you assign priority to interrupt yourself (this is how it works on
PIC HAL-
interrupt priority is implied by IRQ). Therefore, if mapped vector is meant
to be shared and you try to get it for the exclusive use, or if priority is
wrong, IoConnectInterrupt() may fail. If it succeeds, things are even worse
- you may eventually hijack vector, effectively screwing up operations of its
legitimate owner(s). Even it all "works" (you will see why I used quotation
marks shortly) without screwing up any other devices , you can think of it
just as of some miracle....

> My only guess is
> that for some reason processing an interrupt hasn't finished yet when
> the next interrupt arrives and that therefore that interrupt doesn't
> get handled.

My guess is rather different - once you are trying to assign priority to
your interrupt yourself, it may well happen that you are just losing
interrupts, especially if you run your code on APIC HAL. I believe everything
would work fine if you did things properly, i.e. in system-defined manner.....


> IoInitializeDpcRequest(DeviceObject,hwinterfaceDpcRoutine);

DpcForIsr() is good only for per-request, interrupt-driven I/O operations on
a device that does one operation at a time. Why do you assume one-to-one
correspondence between the order in which IRPs are queued and the sequence of
interrupts??? If there is no such correspondence, you should use a custom DPC
routine, KeInitializeDpc() and KeInsertQueueDpc(), rather than DpcForIsr(),
IoInitializeDpcRequest() and IoRequestDpc().


Anton Bassov

"Mystret" wrote:

> Hello,
>
> I've got a question about timing incoming IR signals and decoding them
> in Windows.
>
> Here's my story. I've built a device which detects IR signals at 38KhZ
> and sends interrupts to the parallel port. Then I created (well, I
> didn't write it entirely, but I edited one I found on the internet) a
> driver to catch those interrupts and I created a usermode program to
> interact with the driver. So far so good, everything seemed to work
> fine. I receive interrupts when I press a button on my remote control
> or when I just connect a wire between pin 2-9 and 10 of the parallel
> port.
>
> But there's also a problem. For some reason, I receive way too few
> interrupts when I press a button on my remote control, and the time
> between the interrupts always is nearly identical. My only guess is
> that for some reason processing an interrupt hasn't finished yet when
> the next interrupt arrives and that therefore that interrupt doesn't
> get handled. That should also explain why the time between logged
> interrupts is nearly identical; it always takes the same time to
> complete one interrupt and after that it can handle another. But I
> don't get why handling the interrupt would take that long. My pc
> should be fast enough to handle it.
>
> Here's my isr and dpc routine and after that the part in DriverEntry
> where I connect the interrupt to my driver. When an interrupt occurs,
> first the isr gets called and then the dpcroutine.
>
> I hope any of you have an idea why it doesn't handle all interrupts or
> what the problem is and how it can be fixed.
>
> Thanks in advance,
> Floris van Nee
>
> BOOLEAN hwinterfaceIsr(IN PKINTERRUPT Interrupt, IN OUT PVOID Context)
> {
> PDEVICE_OBJECT DeviceObject = Context;
>
> //KdPrint( ("hwinterface.sys: Interrupt Service Routine\n") );
> /* We should check if the interrupt comes from us and return */
>
> IoRequestDpc(DeviceObject,
> DeviceObject->CurrentIrp,
> NULL);
>
> return TRUE;
> }
>
> VOID hwinterfaceDpcRoutine(IN PKDPC Dpc, PDEVICE_OBJECT DeviceObject,
> IN PIRP Irp, IN PVOID Context)
> {
> PLOCAL_DEVICE_INFO DeviceExtension;
> PIRP pIrp;
>
> pIrp = DeviceObject->CurrentIrp;
> DeviceExtension = DeviceObject->DeviceExtension;
>
> //Get the current 'time' and print it to kernel debug
> KeQueryTickCount((PLARGE_INTEGER)&TickCount);
> KdPrint(("Interrupt: %d", TickCount));
>
> return;
> }
>
>
>
>
>
> DeviceExtension = DeviceObject->DeviceExtension;
>
> DeviceExtension->Level = 7;
> DeviceExtension->Vector = DeviceExtension->Level;
>
> MappedVector = HalGetInterruptVector(Isa,
> 0,
> DeviceExtension->Level,
> DeviceExtension->Vector,
> &Irql,
> &DeviceExtension->Affinity);
> if (MappedVector == 0) DbgPrint("hwinterface.sys:
> HalGetInterruptVector failed\n");
>
> IoInitializeDpcRequest(DeviceObject,hwinterfaceDpcRoutine);
> KdPrint(("%d", &DeviceExtension->InterruptObject));
> status = IoConnectInterrupt(&DeviceExtension->InterruptObject, //
> InterruptObject
> hwinterfaceIsr, // ServiceRoutine
> DeviceObject, // ServiceContext
> NULL, // SpinLock
> MappedVector, // Vector
> Irql, // Irql
> Irql, // SynchronizeIrql
> Latched, // InterruptMode
> FALSE, // ShareVector
> DeviceExtension->Affinity, // ProcessorEnableMask
> FALSE); // FloatingSave
>
> if (!NT_SUCCESS (status)) DbgPrint("hwinterface.sys:
> IoConnectInterrupt Failed\n");
>

RE: handling parallel port interrupts by Mystret

Mystret
Wed Apr 18 09:56:03 CDT 2007

Thanks for the reply

"Anton Bassov" wrote:

> I just have no words here - your code is a "masterpiece" in absolutely all
> respects.....
Well, thanks for the compliment, I think..
>
> Look at the code below:
>
> > DeviceExtension->Level = 7;
> > DeviceExtension->Vector = DeviceExtension->Level;
>
> > MappedVector = HalGetInterruptVector(Isa,
> > 0,
> > DeviceExtension->Level,
> > DeviceExtension->Vector,
> > &Irql,
> > &DeviceExtension->Affinity);
>
> You assign interrupt vector yourself, and then ask HalGetInterruptVector()
> to map it. Brilliant!!! What if untranslated vector has been already assigned
> to some other device??? If your driver supports legacy hardware, it must call
> IoReportResourceForDetection() to claim hardware resources before it attempts
> to detect the device - you have to make sure that there is no conflict
> detected before you can do anything. Please note that
> HalGetInterruptVector() does not care about the conflicts - it just returns
> IRQ-to-vector mapping, even if vector is already in use. Furthermore, don't
> forget that IOAPIC allows the OS to map IRQs to vectors in any way it likes,
> so that a single vector may service multiple IRQs on APIC HAL. IRQ-to-vector
> mapping is done by the system with interrupt priority implied by vector
> number, so that you have no control over it whatsoever.
> However, you assign priority to interrupt yourself (this is how it works on
> PIC HAL-
> interrupt priority is implied by IRQ). Therefore, if mapped vector is meant
> to be shared and you try to get it for the exclusive use, or if priority is
> wrong, IoConnectInterrupt() may fail. If it succeeds, things are even worse
> - you may eventually hijack vector, effectively screwing up operations of its
> legitimate owner(s). Even it all "works" (you will see why I used quotation
> marks shortly) without screwing up any other devices , you can think of it
> just as of some miracle....

So you are saying I should call IoReportResourceForDetection first - before
CreateDevice - and after that IoConnectInterrupt? I've spent the whole day
searching for a good example on how to use IoReportResourceForDetection, but
I can't find any. The problem is I don't know what I should fill in as the
DriverList or DeviceList parameters. The MSDN documentation also isn't very
clear about it.

The reason why I set the interrupt vector to 7 is, because the LPT1 port has
that IRQ. And since the driver has to handle the interrupts coming from LPT1,
I thought it had to be 7. I didn't know at all that it could be causing
problems.

> > My only guess is
> > that for some reason processing an interrupt hasn't finished yet when
> > the next interrupt arrives and that therefore that interrupt doesn't
> > get handled.
>
> My guess is rather different - once you are trying to assign priority to
> your interrupt yourself, it may well happen that you are just losing
> interrupts, especially if you run your code on APIC HAL. I believe everything
> would work fine if you did things properly, i.e. in system-defined manner.....

And the system defined manner is? Something like?
DriverEntry
Call IoReportResourceDetection
Call IoCreateDevice
Call KeInitializeDpc
Call IoConnectInterrupt

>
> > IoInitializeDpcRequest(DeviceObject,hwinterfaceDpcRoutine);
>
> DpcForIsr() is good only for per-request, interrupt-driven I/O operations on
> a device that does one operation at a time. Why do you assume one-to-one
> correspondence between the order in which IRPs are queued and the sequence of
> interrupts??? If there is no such correspondence, you should use a custom DPC
> routine, KeInitializeDpc() and KeInsertQueueDpc(), rather than DpcForIsr(),
> IoInitializeDpcRequest() and IoRequestDpc().

I don't really understand this part. You're saying that DpcForIsr should
only be used when interrupts don't occur so shortly after each other, and
that KeInsertQueueDpc doesn't have that problem? I don't really get why.

I feel kinda stupid that I don't understand all this, but I haven't done
much driver programming so I'm not exactly an expert at it. Thanks for
helping me out.

Floris
>
> Anton Bassov

Re: handling parallel port interrupts by Tim

Tim
Thu Apr 19 00:08:55 CDT 2007

Mystret <Mystret@discussions.microsoft.com> wrote:
>
>The reason why I set the interrupt vector to 7 is, because the LPT1 port has
>that IRQ. And since the driver has to handle the interrupts coming from LPT1,
>I thought it had to be 7. I didn't know at all that it could be causing
>problems.

Maybe it does, but the plug-n-play system has probably already assigned
interrupt vector 7 to the parallel port driver, parport.sys. It's getting
your interrupts, too.
--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Re: handling parallel port interrupts by Mystret

Mystret
Thu Apr 19 01:46:01 CDT 2007

Okay, so you're saying that calling IoReportResourceForDetection also won't
work, because it will always return that it has detected problems. Instead,
I'd have to disable the parport.sys driver and then call
IoReportResourceForDetection? But do you know which parameters to pass to
IoReportResourceForDetection? I still have no idea how to fill the
CM_RESOURCE_LIST struct.

Thanks,
Floris

"Tim Roberts" wrote:

> Maybe it does, but the plug-n-play system has probably already assigned
> interrupt vector 7 to the parallel port driver, parport.sys. It's getting
> your interrupts, too.
> --
> Tim Roberts, timr@probo.com
> Providenza & Boekelheide, Inc.
>

Re: handling parallel port interrupts by already5chosen

already5chosen
Thu Apr 19 11:20:15 CDT 2007

On Apr 19, 8:46 am, Mystret <Myst...@discussions.microsoft.com> wrote:
> Okay, so you're saying that calling IoReportResourceForDetection also won't
> work, because it will always return that it has detected problems. Instead,
> I'd have to disable the parport.sys driver and then call
> IoReportResourceForDetection? But do you know which parameters to pass to
> IoReportResourceForDetection? I still have no idea how to fill the
> CM_RESOURCE_LIST struct.
>
> Thanks,
> Floris
>
>
>
> "Tim Roberts" wrote:
> > Maybe it does, but the plug-n-play system has probably already assigned
> > interrupt vector 7 to the parallel port driver, parport.sys. It's getting
> > your interrupts, too.
> > --
> > Tim Roberts, t...@probo.com
> > Providenza & Boekelheide, Inc.- Hide quoted text -
>
> - Show quoted text -

Parallel port interrupts are unsupported except for printing. End of
story.

Want reliable hardware? Either use polling or abandon parallel port
altogether. For example, use serial port DSR and/or CTS signals. They
are fine for generating interrupts and don't require kerner
programming at all.

Fortunately, parallel ports are going the way of dodo. Unfurtunately,
serial ports are likely follow.


Re: handling parallel port interrupts by Tim

Tim
Sat Apr 21 13:22:55 CDT 2007

Mystret <Mystret@discussions.microsoft.com> wrote:
>
>Okay, so you're saying that calling IoReportResourceForDetection also won't
>work, because it will always return that it has detected problems. Instead,
>I'd have to disable the parport.sys driver and then call
>IoReportResourceForDetection? But do you know which parameters to pass to
>IoReportResourceForDetection? I still have no idea how to fill the
>CM_RESOURCE_LIST struct.

I can think of a couple of alternatives. One is to stack yourself on TOP
of parport.sys; it offers ioctl services to other drivers. You could
behave like a printer driver. That's probably the cleanest way.

Another is to disable parport.sys and claim the interrupt yourself with an
INF file. You couldn't do that for general clients, but for a test machine
it might work.
--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.