I’m sure the answer to this is so silly I’m going to smack myself but I’ve having an issue here.
Create InterruptPort:
btnRed = new InterruptPort((Cpu.Pin)17, false, Port.ResistorMode.PullDown, Port.InterruptMode.InterruptEdgeBoth);
btnRed.OnInterrupt += new NativeEventHandler(BTN_OnInterrupt);
Fire Event when pressed:
if (state == 0)
RedReleased();
else
RedPressed();
Nicely wrapped up in a class called InputManager.
Now we create an instance and subscribe to the event
InputManager IM = new InputManager();
IM.RedPressed += new InputManager.RedPressedEventHandler(RedPressed);
Works so nice…
Now let’s say I call out to another class and pass over the InputManager. Easy no? First I unsubscribe:
IM.RedPressed += RedPressed;
Then I pass along the instance and subscribe on the new class. When I exit the class I resubscribe. But does that work properly? Noooooo. InputManager holds on to every freaking event and doesn’t fire jack until I get back to the first class. Setting a break point I see the InterruptPort doesn’t even fire?!
Maybe, because of an exception in the handler, the InterruptPort stops working.
Subscribe with code you showed as unsubscribe, so not with that ‘new’ stuff. And unsubscribe with -=. That way you subscribe and unsubscribe with the same instances.
Also in the nativehandler, don’t rely on the state (I’ve seen it fail many times when I was writing my SD card detection class, see code) parameter that is passed in, but reread the actual pin state.
I have the world’s stupidest fix ever for this for now but if anyone comes up with something please let me know.
Is seems no matter what you do once you subscribe to an interruptport that class/thread OWNs it. I’ve tried:
Removing the event subscription
Disabling the interrupt
Disposing of the pin
Nulling the InputManager
Launching in a new thread
And none of it works. I :wall:
You want to hear something funny? If you do all of those things and then exit the class, you can recreate the InputManager on the original class/thread and it gets all those messages it didn’t raise in the second class.
I’ve tried your code. With IO30 and PullUP on Cobra.
The first Pressed state is detected, and after that it stops working. Before I dig into it further, is that your problem?
I also don’t see a reason why you subscribe to the same event currently being handled, this seems not a good thing to do… (it’s like adding a item to a list you are currently iterating) When I comment out the code in the IM_GreenPressed handler, the thing continues to work…
That’s the issue. The reason I’m doing subscribes/unsubscribes is the info is needed by different sections of the engine. Games can be loaded into a new AppDomain, etc, so while they’re running the UI needs to stop processing the buttons and let the engine take over.
For now what I’ve done is simply have the main app (GUI) keep the events and bubble them up using a flag to determine whether to process them or kick em up the line.
You can redirect the handler to whatever you want, but just don’t subscribe/unsubscibe to/from an event while you currently handling it. I can’t see why your game engine would wait to subscribe to button events until the button was pressed once…
using System;
using System.Collections;
using System.Runtime.CompilerServices;
using System.Threading;
using System.IO;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Touch;
using GHIElectronics.NETMF.Hardware;
using GHIElectronics.NETMF.FEZ;
namespace ButtonFreakingTest
{
public class Program
{
private static InputManager IM;
public static void Main()
{
IM = new InputManager();
CaptureEvents();
ReleaseEvents();
SampleClass SC = new SampleClass(IM);
CaptureEvents();
Thread.Sleep(-1);
}
private static void CaptureEvents()
{
IM.GreenPressed += IM_GreenPressed;
}
private static void ReleaseEvents()
{
IM.GreenPressed -= IM_GreenPressed;
}
private static void IM_GreenPressed()
{
Debug.Print("IM_GreenPressed()");
}
}
public class SampleClass
{
private bool bLoop;
public SampleClass(InputManager IM)
{
IM.GreenPressed += IM_GreenPressed;
bLoop = true;
while (bLoop)
;
Debug.Print("Exited");
IM.GreenPressed -= IM_GreenPressed;
}
private void IM_GreenPressed()
{
bLoop = false;
}
}
public class InputManager : MarshalByRefObject
{
private InterruptPort btnGreen;
public InputManager()
{
btnGreen = new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.IO30, false, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeBoth);
btnGreen.OnInterrupt += BTN_OnInterrupt;
}
private GreenPressedEventHandler m_GreenPressedEvent;
public delegate void GreenPressedEventHandler();
public event GreenPressedEventHandler GreenPressed
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
m_GreenPressedEvent = (GreenPressedEventHandler)WeakDelegate.Combine(m_GreenPressedEvent, value);
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
m_GreenPressedEvent = (GreenPressedEventHandler)WeakDelegate.Remove(m_GreenPressedEvent, value);
}
}
private void RaiseGreenPressed()
{
GreenPressedEventHandler t = m_GreenPressedEvent;
if (t != null) t();
}
private GreenReleasedEventHandler m_GreenReleasedEvent;
public delegate void GreenReleasedEventHandler();
public event GreenReleasedEventHandler GreenReleased
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
m_GreenReleasedEvent = (GreenReleasedEventHandler)WeakDelegate.Combine(m_GreenReleasedEvent, value);
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
m_GreenReleasedEvent = (GreenReleasedEventHandler)WeakDelegate.Remove(m_GreenReleasedEvent, value);
}
}
private void RaiseGreenReleased()
{
GreenReleasedEventHandler t = m_GreenReleasedEvent;
if (t != null) t();
}
private void BTN_OnInterrupt(uint pin, uint state, DateTime time)
{
Debug.Print("Pin: " + pin + ", State: " + state);
if (state == 0)
RaiseGreenReleased();
else
RaiseGreenPressed();
}
}
}