Search Unity

Object reference not set to an instance of an object - Wiimote API

Discussion in 'Scripting' started by nickjennett_, Feb 22, 2017.

  1. nickjennett_

    nickjennett_

    Joined:
    Feb 22, 2017
    Posts:
    12
    Hi everyone, I'm currently working on a project using a Nintendo wii controller, and this API https://github.com/Flafla2/Unity-Wiimote.
    I'm being thrown the object reference error on the line I marked with the big <--- and I can't get my head around why. If anyone has any experience with this API your help would be appreciated :)

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using WiimoteApi;
    4.  
    5.  
    6.  
    7. public class wiidetect : MonoBehaviour
    8. {
    9.     public Wiimote wiimote;
    10.     private Vector3 wmpOffset = Vector3.zero;
    11.  
    12.     // Use this for initialization
    13.  
    14.     void InitialiseWiimote()
    15.     {
    16.         Debug.Log("This code runs");
    17.         WiimoteManager.FindWiimotes(); // Poll native bluetooth drivers to find Wiimotes
    18.         foreach (Wiimote remote in WiimoteManager.Wiimotes)
    19.         {
    20.             Debug.Log("We found a mote");
    21.             remote.SendPlayerLED(true, false, false, true);
    22.  
    23.             remote.SendStatusInfoRequest();
    24.             remote.SendDataReportMode(InputDataType.REPORT_BUTTONS_ACCEL_EXT16);
    25.         }
    26.     }
    27.     void Start()
    28.     {
    29.  
    30.         InitialiseWiimote();
    31.  
    32.  
    33.  
    34.     }
    35.  
    36.  
    37.  
    38.  
    39.     //capturing button input
    40.  
    41.  
    42.  
    43.  
    44.  
    45.  
    46.     // Update is called once per frame
    47.     void Update()
    48.     {
    49.            int ret;
    50.            do
    51.            {
    52.                ret = wiimote.ReadWiimoteData(); <--------------Error thrown here ( )
    53.             } while (ret > 0);
    54.  
    55.         Debug.Log("we have some data here");
    56.  
    57.         //    //float[] data = wiimote.Accel.GetCalibratedAccelData();
    58.         //    //float x = data[0];
    59.         //    //float y = data[1];
    60.         //    //float z = data[2];
    61.  
    62.  
    63.  
    64.     }
    65.  
    66. }
     
  2. Mordus

    Mordus

    Joined:
    Jun 18, 2015
    Posts:
    174
    Maybe i'm just not seeing it, but are you actually assigning anything to wiimote before you start calling its functions? It's public, i'm assuming you meant to assign it in the editor?
     
  3. nickjennett_

    nickjennett_

    Joined:
    Feb 22, 2017
    Posts:
    12
    It was private, I just set it to public to see if that would solve the problem
     
  4. Mordus

    Mordus

    Joined:
    Jun 18, 2015
    Posts:
    174
    Making it public won't magically assign a value to it :p. You're not assigning it anywhere. You can't call a function on a variable you've never assigned.
     
  5. nickjennett_

    nickjennett_

    Joined:
    Feb 22, 2017
    Posts:
    12
    From what I can understand, Wiimote refers to this file called Wiimote.CS, which is one of the API files
    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using WiimoteApi.Internal;
    4. using WiimoteApi.Util;
    5.  
    6. namespace WiimoteApi {
    7.  
    8.     public delegate void ReadResponder(byte[] data);
    9.  
    10. public class Wiimote
    11. {
    12.     /// Represents whether or not to turn on rumble when sending reports to
    13.     /// the Wii Remote.  This will only be applied when a data report is sent.
    14.     /// That is, simply setting this flag will not instantly enable rumble.
    15.     public bool RumbleOn = false;
    16.  
    17.     /// Accelerometer data component
    18.     public AccelData     Accel      { get { return _Accel; } }
    19.     private AccelData   _Accel;
    20.  
    21.     /// If a Nunchuck is currently connected to the Wii Remote's extension port,
    22.     /// this contains all relevant Nunchuck controller data as it is reported by
    23.     /// the Wiimote.  If no Nunchuck is connected, this is \c null.
    24.     ///
    25.     /// \sa current_ext
    26.     public NunchuckData Nunchuck {
    27.         get {
    28.             if(current_ext == ExtensionController.NUNCHUCK)
    29.                 return (NunchuckData)_Extension;
    30.             return null;
    31.         }
    32.     }
    33.  
    34.     /// If a Classic Controller is currently connected to the Wii Remote's extension port,
    35.     /// this contains all relevant Classic Controller data as it is reported by
    36.     /// the Wiimote.  If no Classic Controller is connected, this is \c null.
    37.     ///
    38.     /// \sa current_ext
    39.     public ClassicControllerData ClassicController {
    40.         get {
    41.             if(current_ext == ExtensionController.CLASSIC)
    42.                 return (ClassicControllerData)_Extension;
    43.             return null;
    44.         }
    45.     }
    46.  
    47.     /// If a Wii Motion Plus is currently connected to the Wii Remote's extension port,
    48.     /// and has been activated by ActivateWiiMotionPlus(), this contains all relevant
    49.     /// Wii Motion Plus controller data as it is reported by the Wiimote.  If no
    50.     /// WMP is connected, this is \c null.
    51.     ///
    52.     /// \sa current_ext, wmp_attached, ActivateWiiMotionPlus()
    53.     public MotionPlusData MotionPlus {
    54.         get {
    55.             if(current_ext == ExtensionController.MOTIONPLUS)
    56.                 return (MotionPlusData)_Extension;
    57.             return null;
    58.         }
    59.     }
    60.  
    61.     /// If this Wiimote is a Wii U Pro Controller,
    62.     /// this contains all relevant Pro Controller data as it is reported by
    63.     /// the Controller.  If this Wiimote is not a Wii U Pro Controller, this is \c null.
    64.     ///
    65.     /// \sa current_ext
    66.     public WiiUProData WiiUPro {
    67.         get {
    68.             if(current_ext == ExtensionController.WIIU_PRO)
    69.                 return (WiiUProData)_Extension;
    70.             return null;
    71.         }
    72.     }
    73.  
    74.     private WiimoteData _Extension;
    75.  
    76.     /// Button data component.
    77.     public ButtonData    Button     { get { return _Button; } }
    78.     private ButtonData  _Button;
    79.     /// IR data component.
    80.     public IRData        Ir         { get { return _Ir; } }
    81.     private IRData      _Ir;
    82.     /// Status info data component.
    83.     public StatusData    Status     { get { return _Status; } }
    84.     private StatusData  _Status;
    85.  
    86.     /// A pointer representing HIDApi's low-level device handle to this
    87.     /// Wii Remote.  Use this when interfacing directly with HIDApi.
    88.     public IntPtr hidapi_handle { get { return _hidapi_handle; } }
    89.     private IntPtr _hidapi_handle = IntPtr.Zero;
    90.  
    91.     /// The RAW (unprocessesed) extension data reported by the Wii Remote.  This could
    92.     /// be used for debugging new / undocumented extension controllers.
    93.     public ReadOnlyArray<byte> RawExtension { get { return _RawExtension; } }
    94.     private ReadOnlyArray<byte> _RawExtension = null;
    95.  
    96.     /// The low-level bluetooth HID path of this Wii Remote.  Use this
    97.     /// when interfacing directly with HIDApi.
    98.     public string hidapi_path { get { return _hidapi_path; } }
    99.     private string _hidapi_path;
    100.  
    101.     public WiimoteType Type { get { return _Type; } }
    102.     private WiimoteType _Type;
    103.  
    104.     private RegisterReadData CurrentReadData = null;
    105.  
    106.     private InputDataType last_report_type = InputDataType.REPORT_BUTTONS;
    107.     private bool expecting_status_report = false;
    108.  
    109.     /// True if a Wii Motion Plus is attached to the Wii Remote, and it
    110.     /// has NOT BEEN ACTIVATED.  When the WMP is activated this value is
    111.     /// false.  This is only updated when WMP state is requested from
    112.     /// Wii Remote registers (see: RequestIdentifyWiiMotionPlus())
    113.     public bool wmp_attached { get { return _wmp_attached; } }
    114.     private bool _wmp_attached = false;
    115.  
    116.     /// The current extension connected to the Wii Remote.  This is only updated
    117.     /// when the Wii Remote reports an extension change (this should update
    118.     /// automatically).
    119.     public ExtensionController current_ext { get { return _current_ext; } }
    120.     private ExtensionController _current_ext = ExtensionController.NONE;
    121.  
    122.  
    123.     private byte[] InterleavedDataBuffer = new byte[18];
    124.     private bool ExpectingSecondInterleavedPacket = false;
    125.  
    126.     private bool ExpectingWiiMotionPlusSwitch = false;
    127.  
    128.     public Wiimote(IntPtr hidapi_handle, string hidapi_path, WiimoteType Type)
    129.     {
    130.         _hidapi_handle  = hidapi_handle;
    131.         _hidapi_path    = hidapi_path;
    132.         _Type    = Type;
    133.  
    134.         _Accel  = new AccelData(this);
    135.         _Button = new ButtonData(this);
    136.         _Ir     = new IRData(this);
    137.         _Status = new StatusData(this);
    138.         _Extension = null;
    139.  
    140.         //RequestIdentifyWiiMotionPlus(); // why not?
    141.     }
    142.  
    143.     private static byte[] ID_InactiveMotionPlus  = new byte[] {0x00, 0x00, 0xA6, 0x20, 0x00, 0x05};
    144.  
    145.     private void RespondIdentifyWiiMotionPlus(byte[] data)
    146.     {
    147.         if (data.Length != ID_InactiveMotionPlus.Length)
    148.         {
    149.             _wmp_attached = false;
    150.             return;
    151.         }
    152.  
    153.         if (data[0] == 0x01)                    // This is a weird inconsistency with some Wii Remote Pluses.  They don't have the -TR suffix
    154.             _Type = WiimoteType.WIIMOTEPLUS;    // or a different PID as an identifier.  Instead they have a different WMP extension identifier.
    155.                                                 // It occurs on some of the oldest Wii Remote Pluses available (pre-2012).
    156.  
    157.         for (int x = 0; x < data.Length; x++)
    158.         {
    159.             // [x != 4] is necessary because byte 5 of the identifier changes based on the state of the remote
    160.             // It is 0x00 on startup, 0x04 when deactivated, 0x05 when deactivated nunchuck passthrough,
    161.             // and 0x07 when deactivated classic passthrough
    162.             //
    163.             // [x != 0] is necessary due to the inconsistency noted above.
    164.             if (x != 4 && x != 0 && data[x] != ID_InactiveMotionPlus[x])
    165.             {
    166.                 _wmp_attached = false;
    167.                 return;
    168.             }
    169.         }
    170.         _wmp_attached = true;
    171.     }
    172.  
    173.     private const long ID_ActiveMotionPlus          = 0x0000A4200405;
    174.     private const long ID_ActiveMotionPlus_Nunchuck = 0x0000A4200505;
    175.     private const long ID_ActiveMotionPlus_Classic  = 0x0000A4200705;
    176.     private const long ID_Nunchuck                  = 0x0000A4200000;
    177.     private const long ID_Classic                   = 0x0000A4200101;
    178.     private const long ID_ClassicPro                = 0x0100A4200101;
    179.     private const long ID_WiiUPro                   = 0x0000A4200120;
    180.  
    181.  
    182.     private void RespondIdentifyExtension(byte[] data)
    183.     {
    184.         if (data.Length != 6)
    185.             return;
    186.  
    187.         byte[] resized = new byte[8];
    188.         for (int x = 0; x < 6; x++) resized[x] = data[5-x];
    189.         long val = BitConverter.ToInt64(resized, 0);
    190.  
    191.         // Disregard bytes 0 and 5 - see RespondIdentifyWiiMotionPlus()
    192.         if ((val | 0xff000000ff00) == (ID_ActiveMotionPlus | 0xff000000ff00))
    193.         {
    194.             _current_ext = ExtensionController.MOTIONPLUS;
    195.             if(_Extension == null || _Extension.GetType() != typeof(MotionPlusData))
    196.                 _Extension = new MotionPlusData(this);
    197.         }
    198.         else if (val == ID_ActiveMotionPlus_Nunchuck)
    199.         {
    200.             _current_ext = ExtensionController.MOTIONPLUS_NUNCHUCK;
    201.             _Extension = null;
    202.         }
    203.         else if (val == ID_ActiveMotionPlus_Classic)
    204.         {
    205.             _current_ext = ExtensionController.MOTIONPLUS_CLASSIC;
    206.             _Extension = null;
    207.         }
    208.         else if (val == ID_ClassicPro)
    209.         {
    210.             _current_ext = ExtensionController.CLASSIC_PRO;
    211.             _Extension = null;
    212.         }
    213.         else if (val == ID_Nunchuck)
    214.         {
    215.             _current_ext = ExtensionController.NUNCHUCK;
    216.             if (_Extension == null || _Extension.GetType() != typeof(NunchuckData))
    217.                 _Extension = new NunchuckData(this);
    218.         }
    219.         else if (val == ID_Classic)
    220.         {
    221.             _current_ext = ExtensionController.CLASSIC;
    222.             if (_Extension == null || _Extension.GetType() != typeof(ClassicControllerData))
    223.                 _Extension = new ClassicControllerData(this);
    224.         }
    225.         else if (val == ID_WiiUPro)
    226.         {
    227.             _current_ext = ExtensionController.WIIU_PRO;
    228.             _Type = WiimoteType.PROCONTROLLER;
    229.             if (_Extension == null || _Extension.GetType() != typeof(WiiUProData))
    230.                 _Extension = new WiiUProData(this);
    231.         }
    232.         else
    233.         {
    234.             _current_ext = ExtensionController.NONE;
    235.             _Extension = null;
    236.         }
    237.     }
    238.  
    239.     #region Setups
    240.  
    241.     /// \brief Performs a series of coperations to initialize the IR camera.
    242.     /// \param type The IR Report type you want to use.
    243.     /// \return If all IR setup commands were successfully sent to the Wii Remote.
    244.     ///
    245.     /// This performs the following steps in order to set up the IR camera:
    246.     /// 1. Enable IR Camera (Send \c 0x04 to Output Report \c 0x13)
    247.     /// 2. Enable IR Camera 2 (Send \c 0x04 to Output Report \c 0x1a)
    248.     /// 3. Write 0x08 to register \c 0xb00030
    249.     /// 4. Write Sensitivity Block 1 to registers at \c 0xb00000
    250.     /// 5. Write Sensitivity Block 2 to registers at \c 0xb0001a
    251.     /// 6. Write Mode Number to register \c 0xb00033
    252.     /// 7. Write 0x08 to register \c 0xb00030 (again)
    253.     /// 8. Update the Wii Remote's data reporting mode based on \c type
    254.     public bool SetupIRCamera(IRDataType type = IRDataType.EXTENDED)
    255.     {
    256.         int res;
    257.         // 1. Enable IR Camera (Send 0x04 to Output Report 0x13)
    258.         // 2. Enable IR Camera 2 (Send 0x04 to Output Report 0x1a)
    259.         res = SendIRCameraEnable(true);
    260.         if (res < 0) return false;
    261.         // 3. Write 0x08 to register 0xb00030
    262.         res = SendRegisterWriteRequest(RegisterType.CONTROL, 0xb00030, new byte[] { 0x08 });
    263.         if (res < 0) return false;
    264.         // 4. Write Sensitivity Block 1 to registers at 0xb00000
    265.         // Wii sensitivity level 3:
    266.         // 02 00 00 71 01 00 aa 00 64
    267.         // High Sensitivity:
    268.         // 00 00 00 00 00 00 90 00 41
    269.         res = SendRegisterWriteRequest(RegisterType.CONTROL, 0xb00000,
    270.             new byte[] { 0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0xaa, 0x00, 0x64 });
    271.         //new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x41});
    272.         if (res < 0) return false;
    273.         // 5. Write Sensitivity Block 2 to registers at 0xb0001a
    274.         // Wii sensitivity level 3:
    275.         // 63 03
    276.         // High Sensitivity:
    277.         // 40 00
    278.         res = SendRegisterWriteRequest(RegisterType.CONTROL, 0xb0001a, new byte[] { 0x63, 0x03 });
    279.         if (res < 0) return false;
    280.         // 6. Write Mode Number to register 0xb00033
    281.         res = SendRegisterWriteRequest(RegisterType.CONTROL, 0xb00033, new byte[] { (byte)type });
    282.         if (res < 0) return false;
    283.         // 7. Write 0x08 to register 0xb00030 (again)
    284.         res = SendRegisterWriteRequest(RegisterType.CONTROL, 0xb00030, new byte[] { 0x08 });
    285.         if (res < 0) return false;
    286.  
    287.         switch (type)
    288.         {
    289.             case IRDataType.BASIC:
    290.                 res = SendDataReportMode(InputDataType.REPORT_BUTTONS_ACCEL_IR10_EXT6);
    291.                 break;
    292.             case IRDataType.EXTENDED:
    293.                 res = SendDataReportMode(InputDataType.REPORT_BUTTONS_ACCEL_IR12);
    294.                 break;
    295.             case IRDataType.FULL:
    296.                 res = SendDataReportMode(InputDataType.REPORT_INTERLEAVED);
    297.                 break;
    298.         }
    299.  
    300.         if (res < 0) return false;
    301.         return true;
    302.     }
    303.  
    304.     /// \brief Attempts to identify whether or not a Wii Motion Plus is connected, but NOT activated.
    305.     /// \sa RequestIdentifyExtension(), ActivateWiiMotionPlus()
    306.     /// \return If the Identification request was successfully sent to the Wii Remote.
    307.     ///
    308.     /// When the Wii Remote reports back if a Wii Motion Plus is connected, wmp_attached will be updated.
    309.     /// \note If the Wii Motion Plus is activated (using ActivateWiiMotionPlus()) the Wii Remote will report false
    310.     public bool RequestIdentifyWiiMotionPlus()
    311.     {
    312.         int res;
    313.         res = SendRegisterReadRequest(RegisterType.CONTROL, 0xA600FA, 6, RespondIdentifyWiiMotionPlus);
    314.         return res > 0;
    315.     }
    316.  
    317.     /// \brief Attempts to identify what (if any) ACTIVE extension is currently connected to the Wii Remote.
    318.     /// \sa RequestIdentifyWiiMotionPlus(), ActivateExtension()
    319.     /// \return If the identification request was successfully sent to the Wii Remote.
    320.     ///
    321.     /// When the Wii Remote reports back what extension is connected, current_ext will be updated.
    322.     /// \note If the Extension has not been activated yet (using ActivateExtension) the Wii Remote will report ExtensionController::NONE.
    323.     private bool RequestIdentifyExtension()
    324.     {
    325.         int res = SendRegisterReadRequest(RegisterType.CONTROL, 0xA400FA, 6, RespondIdentifyExtension);
    326.         return res > 0;
    327.     }
    328.  
    329.     /// \brief Attempts to activate the Wii Motion Plus.
    330.     /// \sa RequestIdentifyWiiMotionPlus(), wmp_attached
    331.     /// \return If the activation request was successfully sent to the Wii Remote.
    332.     ///
    333.     /// When the Wii Remote reports that the Wii Motion Plus has been activated, current_ext will be updated to ExtensionController::MOTIONPLUS
    334.     /// If there is no Wii Motion Plus connected, undefined behavior may occur on the Wii Remote.
    335.     public bool ActivateWiiMotionPlus()
    336.     {
    337.         if (!wmp_attached)
    338.             Debug.LogWarning("There is a request to activate the Wii Motion Plus even though it has not been confirmed to exist!  Trying anyway.");
    339.  
    340.         // Initialize the Wii Motion Plus by writing 0x55 to register 0xA600F0
    341.         int res = SendRegisterWriteRequest(RegisterType.CONTROL, 0xA600F0, new byte[] { 0x55 });
    342.         if (res < 0) return false;
    343.  
    344.         // Activate the Wii Motion Plus as the active extension by writing 0x04 to register 0xA600FE
    345.         // This does 3 things:
    346.         // 1. A status report (0x20) will be sent, which indicates that an extension has been
    347.         //    plugged in - IF there is no extension plugged into the passthrough port.
    348.         // 2. The standard extension identifier at 0xA400FA now reads 00 00 A4 20 04 05
    349.         // 3. Extension reports now contain Wii Motion Plus data.
    350.         res = SendRegisterWriteRequest(RegisterType.CONTROL, 0xA600FE, new byte[] { 0x04 });
    351.         if (res < 0) return false;
    352.  
    353.         _current_ext = ExtensionController.MOTIONPLUS;
    354.         if (_Extension == null || _Extension.GetType() != typeof(MotionPlusData))
    355.             _Extension = new MotionPlusData(this);
    356.         ExpectingWiiMotionPlusSwitch = true;
    357.  
    358.         return true;
    359.     }
    360.  
    361.     public bool DeactivateWiiMotionPlus()
    362.     {
    363.         if (current_ext != ExtensionController.MOTIONPLUS && current_ext != ExtensionController.MOTIONPLUS_CLASSIC && current_ext != ExtensionController.MOTIONPLUS_NUNCHUCK)
    364.             Debug.LogWarning("There is a request to deactivate the Wii Motion Plus even though it has not been activated!  Trying anyway.");
    365.         int res = SendRegisterWriteRequest(RegisterType.CONTROL, 0xA400F0, new byte[] { 0x55 });
    366.         return res > 0;
    367.     }
    368.  
    369.     /// \brief Attempts to activate any connected extension controller
    370.     /// \sa RequestIdentifyExtension(), StatusData::ext_connected
    371.     /// \return If the activation request was successfully sent to the Wii Remote.
    372.     ///
    373.     /// If there is no extension connected, undefined behavior may occur on the Wii Remote.
    374.     private bool ActivateExtension()
    375.     {
    376.         if (!Status.ext_connected)
    377.             Debug.LogWarning("There is a request to activate an Extension controller even though it has not been confirmed to exist!  Trying anyway.");
    378.  
    379.         // 1. Initialize the Extension by writing 0x55 to register 0xA400F0
    380.         int res = SendRegisterWriteRequest(RegisterType.CONTROL, 0xA400F0, new byte[] { 0x55 });
    381.         if (res < 0) return false;
    382.  
    383.         // 2. Activate the Extension by writing 0x00 to register 0xA400FB
    384.         res = SendRegisterWriteRequest(RegisterType.CONTROL, 0xA400FB, new byte[] { 0x00 });
    385.         if (res < 0) return false;
    386.         return true;
    387.     }
    388.  
    389.     #endregion
    390.  
    391.     #region Write
    392.     /// \brief Sends a generic block of data to the Wii Remote using the specified Output Report.
    393.     /// \param type The output report type you would like to send
    394.     /// \param data The raw data you would like to send using the specified \c type.
    395.     /// \return On success, the total size of the data written, -1 if HIDApi reports an error, or < -1 if there is an invalid input.
    396.     ///
    397.     /// This should only be used to send custom data to the Wii Remote that is currently unimplemented by WiimoteApi.
    398.     /// In any average use case you can use any of the higher-level output functions provided by WiimoteApi.
    399.     ///
    400.     /// The Wii Remote rumble settings are also updated based on RumbleOn.
    401.     public int SendWithType(OutputDataType type, byte[] data)
    402.     {
    403.         byte[] final = new byte[data.Length + 1];
    404.         final[0] = (byte)type;
    405.  
    406.         for (int x = 0; x < data.Length; x++)
    407.             final[x + 1] = data[x];
    408.  
    409.         if (RumbleOn)
    410.             final[1] |= 0x01;
    411.  
    412.         int res = WiimoteManager.SendRaw(hidapi_handle, final);
    413.  
    414.         if (res < -1) Debug.LogError("Incorrect Input to HIDAPI.  No data has been sent.");
    415.  
    416.  
    417.         return res;
    418.     }
    419.  
    420.     /// \brief Updates the Player LEDs on the bottom of the Wii Remote
    421.     /// \param led1,led2,led3,led4 If this LED should be turned on
    422.     /// \return On success, the total size of the data written (> 0), <= 0 on failure.
    423.     /// \sa SendWithType(OutputDataType, byte[])
    424.     /// \note More than one LED can be on at a time, but this may confuse players.  Use this with caution.
    425.     ///
    426.     /// If you are willing to use up a lot of bluetooth bandwith, pulse-width modulation (PWM) is also possible
    427.     /// to lower the intensity of the LEDs.
    428.     public int SendPlayerLED(bool led1, bool led2, bool led3, bool led4)
    429.     {
    430.         byte mask = 0;
    431.         if (led1) mask |= 0x10;
    432.         if (led2) mask |= 0x20;
    433.         if (led3) mask |= 0x40;
    434.         if (led4) mask |= 0x80;
    435.  
    436.         return SendWithType(OutputDataType.LED, new byte[] { mask });
    437.     }
    438.  
    439.     /// \brief Sets the Data Reporting mode of the Wii Remote.
    440.     /// \param mode The data reporting mode desired.  This can be any InputDataType except for
    441.     ///         InputDataType::STATUS_INFO, InputDataType::READ_MEMORY_REGISTERS, or InputDataType::ACKNOWLEDGE_OUTPUT_REPORT.
    442.     ///         Said data types are not data reporting modes so it doesn't make sense to use them here.
    443.     /// \return On success, the total size of the data written (> 0), <= 0 on failure.
    444.     /// \sa SendWithType(OutputDataType, byte[])
    445.     public int SendDataReportMode(InputDataType mode)
    446.     {
    447.         if (mode == InputDataType.STATUS_INFO || mode == InputDataType.READ_MEMORY_REGISTERS || mode == InputDataType.ACKNOWLEDGE_OUTPUT_REPORT)
    448.         {
    449.             Debug.LogError("Passed " + mode.ToString() + " to SendDataReportMode!");
    450.             return -2;
    451.         }
    452.  
    453.         last_report_type = mode;
    454.  
    455.         ExpectingSecondInterleavedPacket = false;
    456.  
    457.         return SendWithType(OutputDataType.DATA_REPORT_MODE, new byte[] { 0x00, (byte)mode });
    458.     }
    459.  
    460.     private int SendIRCameraEnable(bool enabled)
    461.     {
    462.         byte[] mask = new byte[] { (byte)(enabled ? 0x04 : 0x00) };
    463.  
    464.         int first = SendWithType(OutputDataType.IR_CAMERA_ENABLE, mask);
    465.         if (first < 0) return first;
    466.  
    467.         int second = SendWithType(OutputDataType.IR_CAMERA_ENABLE_2, mask);
    468.         if (second < 0) return second;
    469.  
    470.         return first + second; // success
    471.     }
    472.  
    473.     private int SendSpeakerEnabled(bool enabled)
    474.     {
    475.         byte[] mask = new byte[] { (byte)(enabled ? 0x04 : 0x00) };
    476.  
    477.         return SendWithType(OutputDataType.SPEAKER_ENABLE, mask);
    478.     }
    479.  
    480.     private int SendSpeakerMuted(bool muted)
    481.     {
    482.         byte[] mask = new byte[] { (byte)(muted ? 0x04 : 0x00) };
    483.  
    484.         return SendWithType(OutputDataType.SPEAKER_MUTE, mask);
    485.     }
    486.  
    487.     /// \brief Request a Wii Remote Status update.
    488.     /// \return On success > 0, <= 0 on failure.
    489.     /// \sa Status, StatusData
    490.     ///
    491.     /// This will update the data in Status when the Wii Remote reports back.
    492.     public int SendStatusInfoRequest()
    493.     {
    494.         expecting_status_report = true;
    495.         return SendWithType(OutputDataType.STATUS_INFO_REQUEST, new byte[] { 0x00 });
    496.     }
    497.  
    498.     /// \brief Requests the Wii Remote to report data from its internal registers.
    499.     /// \param type The type of register you would like to read from
    500.     /// \param offset The starting offset of the block of data you would like to read
    501.     /// \param size The size of the block of data you would like to read
    502.     /// \param Responder This will be called when the Wii Remote finishes reporting the requested data.
    503.     /// \return On success, > 0, <= 0 on failure.
    504.     /// \sa SendRegisterWriteRequest(RegisterType, int, byte[])
    505.     ///
    506.     /// \warning Do not attempt to read from the registers when another read is pending (that is, data is being
    507.     ///          recieved by the Wii Remote).  If you attempt to do this, the new read request will be ignored.
    508.     ///
    509.     /// Reading from the Wii Remote's internal registers can give important data not available through normal output reports.
    510.     /// This can, for example, be used to read saved Mii data from the Wii Remote's EEPROM registers.  It is also used by some
    511.     /// of WiimoteApi's setup functions.
    512.     ///
    513.     /// If you use this incorrectly (for example, if you attempt to read from an invalid block of data), \c Responder will not be called.
    514.     public int SendRegisterReadRequest(RegisterType type, int offset, int size, ReadResponder Responder)
    515.     {
    516.         if (CurrentReadData != null)
    517.         {
    518.             Debug.LogWarning("Aborting read request; There is already a read request pending!");
    519.             return -2;
    520.         }
    521.  
    522.  
    523.         CurrentReadData = new RegisterReadData(offset, size, Responder);
    524.  
    525.         byte address_select = (byte)type;
    526.         byte[] offsetArr = IntToBigEndian(offset, 3);
    527.         byte[] sizeArr = IntToBigEndian(size, 2);
    528.  
    529.         byte[] total = new byte[] { address_select, offsetArr[0], offsetArr[1], offsetArr[2],
    530.             sizeArr[0], sizeArr[1] };
    531.  
    532.         return SendWithType(OutputDataType.READ_MEMORY_REGISTERS, total);
    533.     }
    534.  
    535.     /// \brief Attempts to write a block of data to the Wii Remote's internal registers.
    536.     /// \param type The type of register you would like to write to
    537.     /// \param offset The starting offset of the block of data you would like to write
    538.     /// \param data Data to write to registers at \c offset.  This must have a maximum length of 16.
    539.     /// \return On success, > 0, <= 0 on failure.
    540.     /// \warning If data.Length > 16 the write request will be ignored.
    541.     ///
    542.     /// Writing to the Wii Remote's internal registers allows you to access advanced functions of the remote, such as
    543.     /// the speakers or the IR camera.  It is used by some of WiimoteApi's setup functions (SetupIRCamera()
    544.     /// for example).
    545.     ///
    546.     /// If you use this incorrectly (for example, if you attempt to write to a read-only register) the Wii Remote handles this gracefully
    547.     /// and nothing happens.
    548.     public int SendRegisterWriteRequest(RegisterType type, int offset, byte[] data)
    549.     {
    550.         if (data.Length > 16) return -2;
    551.  
    552.  
    553.         byte address_select = (byte)type;
    554.         byte[] offsetArr = IntToBigEndian(offset, 3);
    555.  
    556.         byte[] total = new byte[21];
    557.         total[0] = address_select;
    558.         for (int x = 0; x < 3; x++) total[x + 1] = offsetArr[x];
    559.         total[4] = (byte)data.Length;
    560.         for (int x = 0; x < data.Length; x++) total[x + 5] = data[x];
    561.  
    562.         return SendWithType(OutputDataType.WRITE_MEMORY_REGISTERS, total);
    563.     }
    564.     #endregion
    565.  
    566.     #region Read
    567.     /// \brief Reads and interprets data reported by the Wii Remote.
    568.     /// \return On success, > 0, < 0 on failure, 0 if nothing has been recieved.
    569.     ///
    570.     /// Wii Remote reads function similarly to a Queue, in FIFO (first in, first out) order.
    571.     /// For example, if two reports were sent since the last \c ReadWiimoteData() call,
    572.     /// this call will only read and interpret the first of those two (and "pop" it off
    573.     /// of the queue).  So, in order to make sure you don't fall behind the Wiimote's update
    574.     /// frequency, you can do something like this (in a game loop for example):
    575.     ///
    576.     /// \code
    577.     /// Wii Remote wiimote;
    578.     /// int ret;
    579.     /// do
    580.     /// {
    581.     ///     ret = wiimote.ReadWiimoteData();
    582.     /// } while (ret > 0);
    583.     /// \endcode
    584.     public int ReadWiimoteData()
    585.     {
    586.         byte[] buf = new byte[22];
    587.         int status = WiimoteManager.RecieveRaw(hidapi_handle, buf);
    588.         if (status <= 0) return status; // Either there is some sort of error or we haven't recieved anything
    589.  
    590.         int typesize = GetInputDataTypeSize((InputDataType)buf[0]);
    591.         byte[] data = new byte[typesize];
    592.         for (int x = 0; x < data.Length; x++)
    593.             data[x] = buf[x + 1];
    594.  
    595.         if (WiimoteManager.Debug_Messages)
    596.             Debug.Log("Recieved: [" + buf[0].ToString("X").PadLeft(2, '0') + "] " + BitConverter.ToString(data));
    597.  
    598.         // Variable names used throughout the switch/case block
    599.         byte[] buttons;
    600.         byte[] accel;
    601.         byte[] ext = null;
    602.         byte[] ir;
    603.  
    604.         switch ((InputDataType)buf[0]) // buf[0] is the output ID byte
    605.         {
    606.             case InputDataType.STATUS_INFO: // done.
    607.                 buttons = new byte[] { data[0], data[1] };
    608.                 byte flags = data[2];
    609.                 byte battery_level = data[5];
    610.  
    611.                 Button.InterpretData(buttons);
    612.  
    613.                 bool old_ext_connected = Status.ext_connected;
    614.  
    615.                 byte[] total = new byte[] { flags, battery_level };
    616.                 Status.InterpretData(total);
    617.  
    618.                 if (expecting_status_report)
    619.                 {
    620.                     expecting_status_report = false;
    621.                 }
    622.                 else                                        // We haven't requested any data report type, meaning a controller has connected.
    623.                 {
    624.                     SendDataReportMode(last_report_type);   // If we don't update the data report mode, no updates will be sent
    625.                 }
    626.  
    627.                 if (Status.ext_connected != old_ext_connected && Type != WiimoteType.PROCONTROLLER)
    628.                 {
    629.                     if (Status.ext_connected)                // The Wii Remote doesn't allow reading from the extension identifier
    630.                     {                                        // when nothing is connected.
    631.                         Debug.Log("An extension has been connected.");
    632.                         if (current_ext != ExtensionController.MOTIONPLUS)
    633.                         {
    634.                             ActivateExtension();
    635.                             RequestIdentifyExtension();         // Identify what extension was connected.
    636.                         }
    637.                         else
    638.                             ExpectingWiiMotionPlusSwitch = false;
    639.                     }
    640.                     else
    641.                     {
    642.                         if (!ExpectingWiiMotionPlusSwitch)
    643.                             _current_ext = ExtensionController.NONE;
    644.                         Debug.Log("An extension has been disconnected.");
    645.                     }
    646.                 }
    647.                 break;
    648.             case InputDataType.READ_MEMORY_REGISTERS: // done.
    649.                 buttons = new byte[] { data[0], data[1] };
    650.                 Button.InterpretData(buttons);
    651.  
    652.                 if (CurrentReadData == null)
    653.                 {
    654.                     Debug.LogWarning("Recived Register Read Report when none was expected.  Ignoring.");
    655.                     return status;
    656.                 }
    657.  
    658.                 byte size = (byte)((data[2] >> 4) + 0x01);
    659.                 byte error = (byte)(data[2] & 0x0f);
    660.                 // Error 0x07 means reading from a write-only register
    661.                 // Offset 0xa600fa is for the Wii Motion Plus.  This error code can be expected behavior in this case.
    662.                 if (error == 0x07)
    663.                 {
    664.                     if(CurrentReadData.Offset != 0xa600fa)
    665.                         Debug.LogError("Wiimote reports Read Register error 7: Attempting to read from a write-only register ("+CurrentReadData.Offset.ToString("x")+").  Aborting read.");
    666.  
    667.                     CurrentReadData = null;
    668.                     return status;
    669.                 }
    670.                 // lowOffset is reversed because the Wii Remote reports are in Big Endian order
    671.                 ushort lowOffset = BitConverter.ToUInt16(new byte[] { data[4], data[3] }, 0);
    672.                 ushort expected = (ushort)CurrentReadData.ExpectedOffset;
    673.                 if (expected != lowOffset)
    674.                     Debug.LogWarning("Expected Register Read Offset (" + expected + ") does not match reported offset from Wii Remote (" + lowOffset + ")");
    675.                 byte[] read = new byte[size];
    676.                 for (int x = 0; x < size; x++)
    677.                     read[x] = data[x + 5];
    678.  
    679.                 CurrentReadData.AppendData(read);
    680.                 if (CurrentReadData.ExpectedOffset >= CurrentReadData.Offset + CurrentReadData.Size)
    681.                     CurrentReadData = null;
    682.  
    683.                 break;
    684.             case InputDataType.ACKNOWLEDGE_OUTPUT_REPORT:
    685.                 buttons = new byte[] { data[0], data[1] };
    686.                 Button.InterpretData(buttons);
    687.                 // TODO: doesn't do any actual error handling, or do any special code about acknowledging the output report.
    688.                 break;
    689.             case InputDataType.REPORT_BUTTONS: // done.
    690.                 buttons = new byte[] { data[0], data[1] };
    691.                 Button.InterpretData(buttons);
    692.                 break;
    693.             case InputDataType.REPORT_BUTTONS_ACCEL: // done.
    694.                 buttons = new byte[] { data[0], data[1] };
    695.                 Button.InterpretData(buttons);
    696.  
    697.                 accel = new byte[] { data[0], data[1], data[2], data[3], data[4] };
    698.                 Accel.InterpretData(accel);
    699.                 break;
    700.             case InputDataType.REPORT_BUTTONS_EXT8: // done.
    701.                 buttons = new byte[] { data[0], data[1] };
    702.                 Button.InterpretData(buttons);
    703.  
    704.                 ext = new byte[8];
    705.                 for (int x = 0; x < ext.Length; x++)
    706.                     ext[x] = data[x + 2];
    707.  
    708.                 if (_Extension != null)
    709.                     _Extension.InterpretData(ext);
    710.                 break;
    711.             case InputDataType.REPORT_BUTTONS_ACCEL_IR12: // done.
    712.                 buttons = new byte[] { data[0], data[1] };
    713.                 Button.InterpretData(buttons);
    714.  
    715.                 accel = new byte[] { data[0], data[1], data[2], data[3], data[4] };
    716.                 Accel.InterpretData(accel);
    717.  
    718.                 ir = new byte[12];
    719.                 for (int x = 0; x < 12; x++)
    720.                     ir[x] = data[x + 5];
    721.                 Ir.InterpretData(ir);
    722.                 break;
    723.             case InputDataType.REPORT_BUTTONS_EXT19: // done.
    724.                 buttons = new byte[] { data[0], data[1] };
    725.                 Button.InterpretData(buttons);
    726.  
    727.                 ext = new byte[19];
    728.                 for (int x = 0; x < ext.Length; x++)
    729.                     ext[x] = data[x + 2];
    730.  
    731.                 if (_Extension != null)
    732.                     _Extension.InterpretData(ext);
    733.                 break;
    734.             case InputDataType.REPORT_BUTTONS_ACCEL_EXT16: // done.
    735.                 buttons = new byte[] { data[0], data[1] };
    736.                 Button.InterpretData(buttons);
    737.  
    738.                 accel = new byte[] { data[0], data[1], data[2], data[3], data[4] };
    739.                 Accel.InterpretData(accel);
    740.  
    741.                 ext = new byte[16];
    742.                 for (int x = 0; x < ext.Length; x++)
    743.                     ext[x] = data[x + 5];
    744.  
    745.                 if (_Extension != null)
    746.                     _Extension.InterpretData(ext);
    747.                 break;
    748.             case InputDataType.REPORT_BUTTONS_IR10_EXT9: // done.
    749.                 buttons = new byte[] { data[0], data[1] };
    750.                 Button.InterpretData(buttons);
    751.  
    752.                 ir = new byte[10];
    753.                 for (int x = 0; x < 10; x++)
    754.                     ir[x] = data[x + 2];
    755.                 Ir.InterpretData(ir);
    756.  
    757.                 ext = new byte[9];
    758.                 for (int x = 0; x < 9; x++)
    759.                     ext[x] = data[x + 12];
    760.  
    761.                 if (_Extension != null)
    762.                     _Extension.InterpretData(ext);
    763.                 break;
    764.             case InputDataType.REPORT_BUTTONS_ACCEL_IR10_EXT6: // done.
    765.                 buttons = new byte[] { data[0], data[1] };
    766.                 Button.InterpretData(buttons);
    767.  
    768.                 accel = new byte[] { data[0], data[1], data[2], data[3], data[4] };
    769.                 Accel.InterpretData(accel);
    770.  
    771.                 ir = new byte[10];
    772.                 for (int x = 0; x < 10; x++)
    773.                     ir[x] = data[x + 5];
    774.                 Ir.InterpretData(ir);
    775.  
    776.                 ext = new byte[6];
    777.                 for (int x = 0; x < 6; x++)
    778.                     ext[x] = data[x + 15];
    779.  
    780.                 if (_Extension != null)
    781.                     _Extension.InterpretData(ext);
    782.                 break;
    783.             case InputDataType.REPORT_EXT21: // done.
    784.                 ext = new byte[21];
    785.                 for (int x = 0; x < ext.Length; x++)
    786.                     ext[x] = data[x];
    787.  
    788.                 if (_Extension != null)
    789.                     _Extension.InterpretData(ext);
    790.                 break;
    791.             case InputDataType.REPORT_INTERLEAVED:
    792.                 if (!ExpectingSecondInterleavedPacket)
    793.                 {
    794.                     ExpectingSecondInterleavedPacket = true;
    795.                     InterleavedDataBuffer = data;
    796.                 } else if(WiimoteManager.Debug_Messages) {
    797.                     Debug.LogWarning(
    798.                         "Recieved two REPORT_INTERLEAVED ("+InputDataType.REPORT_INTERLEAVED.ToString("x")+") reports in a row!  "
    799.                         + "Expected REPORT_INTERLEAVED_ALT ("+InputDataType.REPORT_INTERLEAVED_ALT.ToString("x")+").  Ignoring!"
    800.                     );
    801.                 }
    802.                
    803.                 break;
    804.             case InputDataType.REPORT_INTERLEAVED_ALT:
    805.                 if (ExpectingSecondInterleavedPacket)
    806.                 {
    807.                     ExpectingSecondInterleavedPacket = false;
    808.  
    809.                     buttons = new byte[] { data[0], data[1] };
    810.                     Button.InterpretData(buttons);
    811.  
    812.                     byte[] ir1 = new byte[18];
    813.                     byte[] ir2 = new byte[18];
    814.  
    815.                     for (int x = 0; x < 18; x++)
    816.                     {
    817.                         ir1[x] = InterleavedDataBuffer[x + 3];
    818.                         ir2[x] = data[x + 3];
    819.                     }
    820.  
    821.                     Ir.InterpretDataInterleaved(ir1, ir2);
    822.                     Accel.InterpretDataInterleaved(InterleavedDataBuffer, data);
    823.                 }
    824.                 else if(WiimoteManager.Debug_Messages)
    825.                 {
    826.                     Debug.LogWarning(
    827.                         "Recieved two REPORT_INTERLEAVED_ALT ("+InputDataType.REPORT_INTERLEAVED_ALT.ToString("x")+") reports in a row!  "
    828.                         + "Expected REPORT_INTERLEAVED ("+InputDataType.REPORT_INTERLEAVED.ToString("x")+").  Ignoring!"
    829.                     );
    830.                 }
    831.                 break;
    832.         }
    833.  
    834.         if(ext == null)
    835.             _RawExtension = null;
    836.         else
    837.             _RawExtension = new ReadOnlyArray<byte>(ext);
    838.  
    839.         return status;
    840.     }
    841.  
    842.     /// The size, in bytes, of a given Wii Remote InputDataType when reported by the Wiimote.
    843.     ///
    844.     /// This is at most 21 bytes.
    845.     public static int GetInputDataTypeSize(InputDataType type)
    846.     {
    847.         switch (type)
    848.         {
    849.             case InputDataType.STATUS_INFO:
    850.                 return 6;
    851.             case InputDataType.READ_MEMORY_REGISTERS:
    852.                 return 21;
    853.             case InputDataType.ACKNOWLEDGE_OUTPUT_REPORT:
    854.                 return 4;
    855.             case InputDataType.REPORT_BUTTONS:
    856.                 return 2;
    857.             case InputDataType.REPORT_BUTTONS_ACCEL:
    858.                 return 5;
    859.             case InputDataType.REPORT_BUTTONS_EXT8:
    860.                 return 10;
    861.             case InputDataType.REPORT_BUTTONS_ACCEL_IR12:
    862.                 return 17;
    863.             case InputDataType.REPORT_BUTTONS_EXT19:
    864.                 return 21;
    865.             case InputDataType.REPORT_BUTTONS_ACCEL_EXT16:
    866.                 return 21;
    867.             case InputDataType.REPORT_BUTTONS_IR10_EXT9:
    868.                 return 21;
    869.             case InputDataType.REPORT_BUTTONS_ACCEL_IR10_EXT6:
    870.                 return 21;
    871.             case InputDataType.REPORT_EXT21:
    872.                 return 21;
    873.             case InputDataType.REPORT_INTERLEAVED:
    874.                 return 21;
    875.             case InputDataType.REPORT_INTERLEAVED_ALT:
    876.                 return 21;
    877.         }
    878.         return 0;
    879.     }
    880.  
    881.  
    882.     #endregion
    883.  
    884.     // ------------- UTILITY ------------- //
    885.     public static byte[] IntToBigEndian(int input, int len)
    886.     {
    887.         byte[] intBytes = BitConverter.GetBytes(input);
    888.         Array.Resize(ref intBytes, len);
    889.         if (BitConverter.IsLittleEndian)
    890.             Array.Reverse(intBytes);
    891.  
    892.         return intBytes;
    893.     }
    894. }
    895. }
     
  6. Mordus

    Mordus

    Joined:
    Jun 18, 2015
    Posts:
    174
    You're declaring a variable called wiimote. The type of that variable is the class Wiimote. You have to actually assign something to the variable before you can start using it.

    I can't help you with the specifics of programming for the wii but i'm guessing that nifty InitialiseWiimote() function where you find wiimotes and iterate over them in a foreach loop would be a good place to pick one of them and stick it in that variable so you can use it.
     
  7. nickjennett_

    nickjennett_

    Joined:
    Feb 22, 2017
    Posts:
    12
    In my head that makes sense but I can't work out how to do that haha
     
  8. IngeJones

    IngeJones

    Joined:
    Dec 11, 2013
    Posts:
    129
    In Start or some such suitable event say for instance
    wiimote = new Wiimote();

    If it was a class derived from MonoBehaviour or ScriptableObject you would instead use
    wiimote = CreateInstance<Wiimote>();

    From then on, wiimote *is* actually *something* rather than just a rumour in your code.
     
  9. nickjennett_

    nickjennett_

    Joined:
    Feb 22, 2017
    Posts:
    12
    Ahh, that makes sense, Don't know why I couldn't get my head around that, hadn't had my morning coffee, that could be why
     
    IngeJones likes this.
  10. nickjennett_

    nickjennett_

    Joined:
    Feb 22, 2017
    Posts:
    12
    I implementedthat like you said, and Im now being thrown an error ive never seen before There is no argument given that corresponds to the required formal parameter 'hidapi_handle' of 'Wiimote.Wiimote(IntPtr, string, WiimoteType)'. Any ideas?
     
  11. IngeJones

    IngeJones

    Joined:
    Dec 11, 2013
    Posts:
    129
    Ok, you can't just put exacly what I said, because the constructor for Wiimote goes like:

    public Wiimote(IntPtr hidapi_handle, string hidapi_path, WiimoteType Type)

    So where I had the empty brackets after new Wiimote() you have to put in suitable parameters. The alternative would be to have a parameterless constructor. But I guess you had good reasons to require parameters so that wouldn't help :)

    Edit: Oh that Wiimote class isn't one of yours anyway, so yeah you have to go along with what it wants.
     
  12. Mordus

    Mordus

    Joined:
    Jun 18, 2015
    Posts:
    174
    He doesn't need to instantiate new wiimote objects, they're provided for him by the system. And he's already finding them in his InitialiseWiimote() function and iterating over them in a foreach loop, so i have no idea why there's confusion about just taking one of them and sticking it in that variable to use.
     
  13. IngeJones

    IngeJones

    Joined:
    Dec 11, 2013
    Posts:
    129
    Oh well I have no clue into the world of the Wii, so I was just taking the C# at face value. For all I knew he might have been iterating over zero results :)

    So assuming foreach WiimoteManager.Wiimotes is a List type, he'd go
    if (WiimoteManager.Wiimotes.Count > 0)
    {
    wiimote = WiimoteManager.Wiimotes[0];
    }

    Or else test for the right one in the loop and when he's found it go
    wiimote = remote;
    return;
     
    Last edited: Feb 23, 2017
  14. Mordus

    Mordus

    Joined:
    Jun 18, 2015
    Posts:
    174
    Could be, i had that thought as well. But since he's not ever actually trying to assign anything from that list to the variable either way it would be an unrelated issue.
     
  15. IngeJones

    IngeJones

    Joined:
    Dec 11, 2013
    Posts:
    129
    Yeah there are dead ends in the code, definitely.