Page 1 of 1

PhidgetInterfaceKit 0/16/16 and Unity

Posted: Fri Apr 11, 2025 9:55 am
by drumminhands
I'm trying to get the Interface Kit to be controlled by Unity. Right now I have a series of arcade buttons wired up. Input 0 properly triggers and output 0 properly lights an LED in the Phidgets Control Panel. Same for all the other outputs (12 total buttons). I'm using the 5v power from the input channel to send signal to all the inputs. I'm using an external 12v power source to light all the LEDs. All of that works fine in the Phidgets Control Panel.

I'm trying to get just one button to work in Unity to start. I have phidget22.dll in the right place.

Here is my button class:

Code: Select all

using UnityEngine;
using Phidget22;
using System.Collections;

// https://www.phidgets.com/education/learn/projects/unity/buttons/
// https://www.phidgets.com/?prodid=1226#Tab_Code_Samples

public class PhidgetButton : MonoBehaviour
{
    [SerializeField, Tooltip("The port numbers on the Phidget board")]
    private int btnPort = 0, ledPort = 0;
    [SerializeField] private bool initActive = true; // should the button be active at start?
    [SerializeField] private float debounce = 0.25f; // how long to wait after a button press before registering a true press
    private bool debounced = true;
    private DigitalInput btn;
    private DigitalOutput led;
    private bool active = true; // true means input is measured

    private void Start()
    {
        // button setup
        btn = new DigitalInput();
        btn.Channel = btnPort; // set the channel to the port number
        // btn = new DigitalInput
        // {
        //     HubPort = btnPort,
        //     IsHubPortDevice = true
        // };
        btn.Open(5000);

        // led setup
        led = new DigitalOutput();
        led.Channel = ledPort; // set the channel to the port number
        // led = new DigitalOutput
        // {
        //     HubPort = ledPort,
        //     IsHubPortDevice = true
        // };
        led.Open(5000);

        active = initActive; // init
    }

    private void Update()
    {
        if (active)
        {
            // light the LED if not pressing the button
            led.State = !btn.State;
        } else
        {
            led.State = false; // keep light off when not active
        }
    }

    public void ActivateButton()
    {
        active = true;
    }

    public void DeactivateButton()
    {
        active = false;
    }

    public bool GetBtnState()
    {
        bool b = false; // default to false

        if (active)
        {
            if (debounced)
            {
                b = btn.State; // report the current state

                if (b) // if debounced and now it's true again, then start a new debounce delay
                {
                    StartCoroutine(DebounceBtn());
                }
            }
        }

        return b;
    }

    private IEnumerator DebounceBtn()
    {
        debounced = false;
        yield return new WaitForSeconds(debounce);
        debounced = true;
    }

    //Required for Unity and Phidgets
    private void OnApplicationQuit()
    {
        btn.Close();
        btn = null;
        led.Close();
        led = null;
        if (Application.isEditor)
        {
            Phidget.ResetLibrary();
        }
        else
        {
            Phidget.FinalizeLibrary(0);
        }
    }
}

With this, somehow LED1 is on at the start, and pressing button 0 will turn off LED1 until I release button 0.

Instead if I use this as my start function I get no lights at all:

Code: Select all

    private void Start()
    {
        // button setup
        btn = new DigitalInput();
        // btn.Channel = btnPort; // set the channel to the port number
        btn = new DigitalInput
        {
            HubPort = btnPort,
            IsHubPortDevice = false
        };
        btn.Open(5000);

        // led setup
        led = new DigitalOutput();
        // led.Channel = ledPort; // set the channel to the port number
        led = new DigitalOutput
        {
            HubPort = ledPort,
            IsHubPortDevice = false
        };
        led.Open(5000);

        active = initActive; // init
    }
    
What am I doing wrong? Do I need to tell Unity that this is an Interface Kit instead of a Unity Hub or something else?

Attached are the properties of my interface kit.
phidget control panel.png
phidget control panel.png (25.09 KiB) Viewed 3379 times

Re: PhidgetInterfaceKit 0/16/16 and Unity

Posted: Fri Apr 11, 2025 1:24 pm
by drumminhands
I think I had the wrong version of the .net dll. And this works. For all those future folks looking at this post--enjoy.

Code: Select all

using UnityEngine;
using Phidget22;
using System.Collections;

// https://www.phidgets.com/education/learn/projects/unity/buttons/
// https://www.phidgets.com/?prodid=1226#Tab_Code_Samples

public class PhidgetInterfaceKitButtonLED : MonoBehaviour
{
    private DigitalInput digitalInput;
    private DigitalOutput digitalOutput;
    [SerializeField] private int btnPort = 0, ledPort = 0; // The port numbers on the Phidget Interface Kit
    [SerializeField] private int attachmentDelay = 5000; // Delay in milliseconds for opening the Phidget
    [SerializeField] private bool lightWithPress = false; // true means light the LED when the button is pressed

    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {
        // Button setup
        digitalInput = new DigitalInput();
        digitalInput.Channel = btnPort; // Set the channel to the port number

        // LED setup
        digitalOutput = new DigitalOutput();
        digitalOutput.Channel = ledPort; // Set the channel to the port number

        // Attach the event handler for state changes
        digitalInput.StateChange += OnDigitalInputStateChange;

        // Open your Phidgets and wait for attachment
        digitalInput.Open(attachmentDelay);
        digitalOutput.Open(attachmentDelay);
    }

    // Event handler for digital input state changes
    private void OnDigitalInputStateChange(object sender, Phidget22.Events.DigitalInputStateChangeEventArgs e)
    {
        Debug.Log($"Digital Input State Changed: {e.State}");

        // If lightWithPress is true, toggle the LED based on the button state
        if (lightWithPress)
        {
            digitalOutput.State = e.State; // Set the LED state to match the button state
        }
        ledState = e.State; // Update the ledState variable
    }

    public bool GetBtnState()
    {
        return digitalInput.State; // Return the current state of the button
    }
    public bool GetLedState()
    {
        return digitalOutput.State; // Return the current state of the LED
    }
    public void SetLedState(bool state)
    {
        digitalOutput.State = state; // Set the LED state
    }

    // Required for Unity and Phidgets
    private void OnApplicationQuit()
    {
        digitalInput.Close();
        digitalInput = null;
        digitalOutput.Close();
        digitalOutput = null;
        if (Application.isEditor)
        {
            Phidget.ResetLibrary();
        }
        else
        {
            Phidget.FinalizeLibrary(0);
        }
    }
}

Re: PhidgetInterfaceKit 0/16/16 and Unity

Posted: Tue Apr 15, 2025 10:36 am
by drumminhands
A followup. I can get this to work great on a Mac, but can't get it to work on a Windows machine. I always get an error when loading the scene "open failed because device is in use. Check that the Phidget is not already open in another program, such as the Phidget Control Panel, or another program you are developing." I do not have any other program running or trying to use the Phidgets.

If I have an empty scene with one empty game object and add the following two scripts to that game object, it will work great on Mac but fail on Windows 11. Why? I am able to use a VINT Hub to control a button on the computer, so the dll and .net file are correct.

Please and thank you for looking at the issue.

Code: Select all

using UnityEngine;

public class InterfaceBtnMgr : MonoBehaviour
{

    [SerializeField] private PhidgetInterfaceKitButtonLED btn;

    // Start is called before the first frame update
    private void start(){
        btn.ActivateButton();
    }

    // Update is called once per frame
    void Update()
    {
        if(btn.StateChanged()){
            print("Button state changed");
            btn.ToggleLedState();
        }
    }
}

Code: Select all

using UnityEngine;
using Phidget22;
using System.Collections;

// https://www.phidgets.com/education/learn/projects/unity/buttons/
// https://www.phidgets.com/?prodid=1226#Tab_Code_Samples

public class PhidgetInterfaceKitButtonLED : MonoBehaviour
{
    private DigitalInput digitalInput;
    private DigitalOutput digitalOutput;
    [SerializeField] private int btnPort = 0, ledPort = 0; // Default port numbers on the Phidget Interface Kit
    [SerializeField] private bool initActive = true; // should the button be active at start?
    [SerializeField] private float debounce = 0.25f; // how long to wait after a button press before registering a true press
    [SerializeField] private int openDelay = 5000; // how long to wait to connect the phidget
    private bool debounced = true;
    private bool active = true; // true means input is measured
    private bool initFlag = true; // if true, run init once
    private bool buttonState = false;         // current state of the button
    private bool lastButtonState = false;     // previous state of the button
    private bool changeLEDFlag = false; // if true, next time through update change LED state
    private bool currentLEDstate = true;
    
    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {
        // Button setup
        digitalInput = new DigitalInput();
        digitalInput.Channel = btnPort; // Set the channel to the port number

        // LED setup
        digitalOutput = new DigitalOutput();
        digitalOutput.Channel = ledPort; // Set the channel to the port number

        // Open your Phidgets and wait for attachment
        //digitalInput.Open(Phidget.DefaultTimeout);
        digitalInput.Open(openDelay);
        digitalOutput.Open(openDelay);

        initFlag = true;
    }

    private void Update()
    {
        if (initFlag)
        {
            if (initActive)
            {
                ActivateButton();
            }
            else
            {
                DeactivateButton();
            }

            initFlag = false;
        }

        if (changeLEDFlag)
        {
            if (digitalOutput != null)
            {
                if (digitalOutput.IsOpen)
                {
                    digitalOutput.State = currentLEDstate;
                }
                changeLEDFlag = false;
            }
        }
    }

   //// a new button is attached
   private void Phidget_Attach(object sender, Phidget22.Events.AttachEventArgs e)
    {
       Debug.Log("Attach Button");
       if(active){
            ActivateButton();
       } else {
            DeactivateButton();
       }
   }

    //// a button is detached
    private void Phidget_Detach(object sender, Phidget22.Events.DetachEventArgs e)
    {
        Debug.Log("Detach Button");
        //DeactivateButton();
    }

    public void ActivateButton()
{
        active = true;
        if(digitalOutput != null)
        {
            if (digitalOutput.IsOpen)
            {
                digitalOutput.State = true;
            }
        }
        currentLEDstate = true;
        debounced = true;
    }

    public void DeactivateButton()
    {
        active = false;
        if (digitalOutput != null)
        {
            if (digitalOutput.IsOpen)
            {
                digitalOutput.State = false;
            }
        }
        currentLEDstate = false;
    }

    public void SetLED(bool b)
    {
        if(currentLEDstate != b)
        {
            changeLEDFlag = true;
            currentLEDstate = b;
        }
    }

    public bool GetBtnState()
    {
        if (StateChanged())
        {
            return digitalInput.State;
        } else
        {
            return lastButtonState;
        }
    }

    public bool StateChanged()
    { // if button has changed since the last time pooled, report yes

        if (!active)
        {
            return false;
        }

        bool b = false;

        if (debounced)
        {
            if (digitalInput.IsOpen)
            {
                buttonState = digitalInput.State;

                // only use the down state changes
                if (buttonState){
                    // compare the buttonState to its previous state
                    if (buttonState != lastButtonState)
                    {
                        b = true;
                    }
                    // Delay a little bit to avoid bouncing
                    StopAllCoroutines();
                    StartCoroutine(DebounceBtn());
                }

            }

            // save the current state as the last state, for next time through the loop
            lastButtonState = buttonState;
        }

        return b;
    }

    private IEnumerator DebounceBtn()
    {
        debounced = false;
        yield return new WaitForSeconds(debounce);
        debounced = true;
    }

    public void SetDebounce(float f)
    {
        debounce = f;
    }

    public bool GetLedState()
    {
        return digitalOutput.State; // Return the current state of the LED
    }

    public void ToggleLedState()
    {
        if(GetLedState()){
            //print("setting LED to false");
            SetLED(false);
        } else {
            //print("setting LED to true");
            SetLED(true);
        }
    }

    public void DestroyButton(){
        CleanUpPhidgets();
        Destroy(gameObject);
    }

    //Required for Unity and Phidgets
    public void CleanUpPhidgets()
        {
            if(digitalInput != null)
            {
                if (digitalInput.IsOpen)
                {
                    digitalInput.Close();
                }
                digitalInput = null;
            }
            if(digitalOutput != null)
            {
                if (digitalOutput.IsOpen)
                {
                    digitalOutput.Close();
                }
                digitalOutput = null;
            }
            Destroy(gameObject);
        }

        private void OnDestroy()
        {
            if(digitalInput != null || digitalOutput != null)
            {
                CleanUpPhidgets();
            }
        }
        private void OnApplicationQuit()
        {
            if (digitalInput != null || digitalOutput != null)
            {
                CleanUpPhidgets();
            }
        if (Application.isEditor)
        {
            Phidget.ResetLibrary();
        }
        else
        {
            Phidget.FinalizeLibrary(0);
        }
    }
}

Re: PhidgetInterfaceKit 0/16/16 and Unity

Posted: Wed Apr 16, 2025 11:07 am
by drumminhands
It looks like Unity 6000.0.43f1 does not play nice with phidgets.dll. Either .Close(), Phidget.ResetLibrary(), or Phidget.FinalizeLibrary(0) is not properly closing out when the application quits, resulting in all the errors when trying to launch again.

I rebuilt in Unity 2021.3.25f1 and it works just fine on both Mac and Windows 11.