0

this is basically a follow up to a previous question (Triggering an event in c# from c++ and declaring LPCWSTR). I've revised my code based on the answers and comments I have received and I solved the initial issue, which was passing the event to the GpioSetupInterruptPin from a gpio api. I don't have a lot of documentation on the api but what i'm trying to achieve is: have a form with a white label; after pressing a switch, the label turns yellow. The problem i'm having now is the event seems to trigger as soon as it's created (the "execute" message is passed to the debug dialog and the label turns yellow) but it doesn't do anything when i toggle the switch. I was told in the last question to use WaitForSingleObject but i'm not really sure where to call it and this article only added to my confusion.

public partial class Form1 : Form
{
    // P/Invoke CreateEvent and WaitForSingleObject
    private void GPIO_Open() //get handle for gpio
    private void GPIO_Output() //output pin declaration

    private void button1_Click(object sender, EventArgs e)
    {
        Interrupt_Setup();
    }

    private void Interrupt_Setup()
    {
        hGPIO = GPIOapi.GpioOpenHandle(); //returns a handle to the gpio
        GIPO_ON = true;
        Debug.WriteLine("Driver open \n" + hGPIO);
        GPIO_Output(); //set output pins
        GPIO_Interrupt(Trigger); //configure interrupt
    }

    private void GPIO_Interrupt(string trigger)
    {
        bool ok;
        _Main();
        //INTERRUPT DECALRATION
        ok = GPIOapi.GpioSetupInterruptPin(hGPIO, port6, 4, GPIOapi.INT_TRIGGER_MODE.TRIGGER_MODE_EDGE,
            GPIOapi.INT_TRIGGER_POLARITY.TRIGGER_POL_HIGH_RISING, trigger, true);
        Thread waitThread=new Thread(WaitForTrigger);
        waitThread.Start();
        if (!ok)
            Debug.WriteLine("NO interrupt");
        else
            Debug.WriteLine("Interrupt set for:" + port6 + "04" + " at " + hGPIO);
    }

    public static string Trigger = "InputProcessUpdateHandler";
    public static IntPtr handle = CreateEvent(IntPtr.Zero, false, false, Trigger); //used P/Invoke 
    private static InputProcessor inputProcessor = null;

    public Color[] color =
    {
        Color.Orchid, Color.DarkOrchid, Color.GreenYellow, Color.CornflowerBlue, Color.SteelBlue,Color.Crimson
    };

    public int i = 0;

    public void WaitForTrigger()
    {
        while(true)
        {try
        {
            if (WaitForSingleObject(handle, 0xFFFFFFFF) == false)
            {
                BeginInvoke(((System.Action)(() =>label2.BackColor = color[i])));
                i++;
                if (i > 4)
                    i = 0;
            }
            Thread.Sleep(300);
        }
        catch (Exception e)
        { Debug.WriteLine("exception: " + e); }}
        }
    }

    private void _Main()
    {
        inputProcessor = new InputProcessor();
        ShowToggle showToggle = new ShowToggle(inputProcessor);
        inputProcessor.Process(label1);
    }

    public class ShowToggle
    {
        private InputProcessor _inputProcessor = null;

        public ShowToggle(InputProcessor inputProcessor)
        {
            _inputProcessor = inputProcessor;
            _inputProcessor.updateHandledBy += InputProcessUpdateHandler;
        }

        private void InputProcessUpdateHandler(Label label)
        {
            label.BackColor = Color.Yellow;
            Debug.Write("execute");
        }
   }

   public class InputProcessor
   {
       public delegate void InputProcessUpdateHandler(Label label);
       public event InputProcessUpdateHandler updateHandledBy = null;

       public void Process(Label label)
      {
          if (updateHandledBy != null)
            updateHandledBy(label);
      }
   }

If anyone could help me with this, I would be very grateful.

*** I got it working but it looks a right mess. Could anyone help me straighten it out?

Community
  • 1
  • 1
  • It's not clear to me why you have the extra two classes, which seem to do little more than encapsulate the event and the handler. The event arguably should reside in the same class that encapsulates the GPIO functionality (it's not clear whether you actually have one of these), and the handler itself can just be in the `Form1` class. That said, the biggest issue here seems to be that you lack any mechanism to receive a signal from the GPIO implementation. The closest you seem to get is creating the `handle` instance, but that doesn't appear to be used at all, never mind passed to GPIO. – Peter Duniho Nov 28 '14 at 23:04
  • Sorry for the long delay in me replying (family emergency and a lot of work). The code is rather messy because I started doing some examples for delegates and events and the above code is just my attempt at combining them – Vlad Stefan Dec 05 '14 at 09:35

1 Answers1

0

You code is really confusing to me. I think what you want is something like this. Bear in mind I'm typing this into the SO text editor, so don't expect it to compile and just work - it's a guide. Consider it a step above pseudocode.

public class DeviceInterrupt
{
    IntPtr m_gpio;
    string m_eventName;

    public event EventHandler OnInterrupt;

    public DeviceInterrupt(int port)
    {
        // get a driver handle
        m_gpio = GPIO_Open();

        // generate some unique event name
        m_eventName = "GPIO_evt_" + port;

        // wire up the interrupt
        GpioSetupInterruptPin(m_gpio, port, m_eventName, ...);

        // start a listener
        new Thread(EventListenerProc)
        {
            IsBackground = true,
            Name = "gpio listener"
        }
        .Start();
    }

    public void Dispose()
    {
        // TODO: release the handle
    }

    private void EventListenerProc()
    {
        // create the event with the name we sent to the driver
        var wh = new WaitHandle(false, m_eventName);

        while (true)
        {
            // wait for it to get set by the driver
            if (wh.WaitOne(1000))
            {
                // we have an interrupt
                OnInterrupt.Fire(this, EventArgs.Empty);
            }
        }
    }
}

Usage would then be something like this:

var intr = new DeviceInterrupt(4);
intr.OnInterrupt += MyHandler;
....
void MyHandler(object sender, EventArgs a)
{
    Debug.WriteLine("Interrupt occurred!");
}

Note

The Compact Framework doesn't support actual named system events, so the named WaitHandle I use in my code above is not a CF-supplied WaitHandle. Instead I'm using the one from the Smart Device Framework. You could also P/Invoke to CreateEvent and WaitForSingleObject yourself.

ctacke
  • 66,480
  • 18
  • 94
  • 155
  • Hi, thank you for the guide as it made things a bit cleared. Would you mind giving me a bit of extra help with the WaitHandle() please? I've tried using it but I get an error "cannot access protected constructor here". I've tried using EventWaitHandle() instead but i couldn't get it working – Vlad Stefan Dec 05 '14 at 09:56
  • You can't use the CF-supplied WaitHandle. Infinite stupidity on the CF team's part led them to not support actual named events so you either must use P/Invoke to call the APIs yourself, or use the (free, open-source) SDF version - found at http://opennetcf.codeplex.com – ctacke Dec 05 '14 at 15:43