ardupilot/Tools/ArdupilotMegaPlanner/Joystick.cs

691 lines
23 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using log4net;
using Microsoft.DirectX.DirectInput;
using System.Reflection;
namespace ArdupilotMega
{
public class Joystick
{
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
Device joystick;
JoystickState state;
public bool enabled = false;
byte[] buttonpressed = new byte[128];
public string name;
public bool elevons = false;
public static Joystick self;
struct JoyChannel
{
public int channel;
public joystickaxis axis;
public bool reverse;
public int expo;
}
struct JoyButton
{
public int buttonno;
public string mode;
}
~Joystick()
{
try
{
joystick.Unacquire();
}
catch { }
}
public Joystick()
{
self = this;
}
JoyChannel[] JoyChannels = new JoyChannel[9]; // we are base 1
JoyButton[] JoyButtons = new JoyButton[128]; // base 0
public static DeviceList getDevices()
{
return Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly);
}
public bool start(string name)
{
self.name = name;
DeviceList joysticklist = Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly);
bool found = false;
foreach (DeviceInstance device in joysticklist)
{
if (device.ProductName == name)
{
joystick = new Device(device.InstanceGuid);
found = true;
break;
}
}
if (!found)
return false;
joystick.SetDataFormat(DeviceDataFormat.Joystick);
joystick.Acquire();
enabled = true;
System.Threading.Thread t11 = new System.Threading.Thread(new System.Threading.ThreadStart(mainloop)) {
Name = "Joystick loop",
Priority = System.Threading.ThreadPriority.AboveNormal,
IsBackground = true
};
t11.Start();
return true;
}
public static joystickaxis getMovingAxis(string name, int threshold)
{
self.name = name;
DeviceList joysticklist = Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly);
bool found = false;
Device joystick = null;
foreach (DeviceInstance device in joysticklist)
{
if (device.ProductName == name)
{
joystick = new Device(device.InstanceGuid);
found = true;
break;
}
}
if (!found)
return joystickaxis.ARx;
joystick.SetDataFormat(DeviceDataFormat.Joystick);
joystick.Acquire();
System.Windows.Forms.CustomMessageBox.Show("Please ensure you have calibrated your joystick in Windows first");
joystick.Poll();
JoystickState obj = joystick.CurrentJoystickState;
Hashtable values = new Hashtable();
Type type = obj.GetType();
PropertyInfo[] properties = type.GetProperties();
foreach (PropertyInfo property in properties)
{
values[property.Name] = int.Parse(property.GetValue(obj, null).ToString());
}
values["Slider1"] = obj.GetSlider()[0];
values["Slider2"] = obj.GetSlider()[1];
System.Windows.Forms.CustomMessageBox.Show("Please move the joystick axis you want assigned to this function after clicking ok");
DateTime start = DateTime.Now;
while (start.AddSeconds(10) > DateTime.Now)
{
joystick.Poll();
JoystickState nextstate = joystick.CurrentJoystickState;
int[] slider = nextstate.GetSlider();
type = nextstate.GetType();
properties = type.GetProperties();
foreach (PropertyInfo property in properties)
{
//Console.WriteLine("Name: " + property.Name + ", Value: " + property.GetValue(obj, null));
log.InfoFormat("test name {0} old {1} new {2} ", property.Name, values[property.Name], int.Parse(property.GetValue(nextstate, null).ToString()));
log.InfoFormat("{0} {1}", (int)values[property.Name], (int.Parse(property.GetValue(nextstate, null).ToString()) + threshold));
if ((int)values[property.Name] > (int.Parse(property.GetValue(nextstate, null).ToString()) + threshold) ||
(int)values[property.Name] < (int.Parse(property.GetValue(nextstate, null).ToString()) - threshold))
{
log.Info(property.Name);
joystick.Unacquire();
return (joystickaxis)Enum.Parse(typeof(joystickaxis), property.Name);
}
}
// slider1
if ((int)values["Slider1"] > (slider[0] + threshold) ||
(int)values["Slider1"] < (slider[0] - threshold))
{
joystick.Unacquire();
return joystickaxis.Slider1;
}
// slider2
if ((int)values["Slider2"] > (slider[1] + threshold) ||
(int)values["Slider2"] < (slider[1] - threshold))
{
joystick.Unacquire();
return joystickaxis.Slider2;
}
}
System.Windows.Forms.CustomMessageBox.Show("No valid option was detected");
return joystickaxis.None;
}
public static int getPressedButton(string name)
{
self.name = name;
DeviceList joysticklist = Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly);
bool found = false;
Device joystick = null;
foreach (DeviceInstance device in joysticklist)
{
if (device.ProductName == name)
{
joystick = new Device(device.InstanceGuid);
found = true;
break;
}
}
if (!found)
return -1;
joystick.SetDataFormat(DeviceDataFormat.Joystick);
joystick.Acquire();
joystick.Poll();
System.Windows.Forms.CustomMessageBox.Show("Please press the joystick button you want assigned to this function after clicking ok");
DateTime start = DateTime.Now;
while (start.AddSeconds(10) > DateTime.Now)
{
joystick.Poll();
JoystickState nextstate = joystick.CurrentJoystickState;
byte[] buttons = nextstate.GetButtons();
for (int a = 0; a < joystick.Caps.NumberButtons; a++)
{
if (buttons[a] > 0)
return a;
}
}
System.Windows.Forms.CustomMessageBox.Show("No valid option was detected");
return -1;
}
public void setReverse(int channel, bool reverse)
{
JoyChannels[channel].reverse = reverse;
}
public void setAxis(int channel, joystickaxis axis)
{
JoyChannels[channel].axis = axis;
}
public void setChannel(int channel, joystickaxis axis, bool reverse, int expo)
{
JoyChannel joy = new JoyChannel();
joy.axis = axis;
joy.channel = channel;
joy.expo = expo;
joy.reverse = reverse;
JoyChannels[channel] = joy;
}
public void setButton(int arrayoffset,int buttonid,string mode1)
{
JoyButtons[arrayoffset] = new JoyButton()
{
buttonno = buttonid,
mode = mode1
};
}
public void changeButton(int buttonid, int newid)
{
JoyButtons[buttonid].buttonno = newid;
}
int BOOL_TO_SIGN(bool input)
{
if (input == true)
{
return -1;
}
else
{
return 1;
}
}
/// <summary>
/// Updates the rcoverride values and controls the mode changes
/// </summary>
void mainloop()
{
while (enabled)
{
try
{
System.Threading.Thread.Sleep(50);
//joystick stuff
joystick.Poll();
state = joystick.CurrentJoystickState;
int[] slider = state.GetSlider();
if (elevons)
{
//g.channel_roll.set_pwm(BOOL_TO_SIGN(g.reverse_elevons) * (BOOL_TO_SIGN(g.reverse_ch2_elevon) * int(ch2_temp - elevon2_trim) - BOOL_TO_SIGN(g.reverse_ch1_elevon) * int(ch1_temp - elevon1_trim)) / 2 + 1500);
//g.channel_pitch.set_pwm( (BOOL_TO_SIGN(g.reverse_ch2_elevon) * int(ch2_temp - elevon2_trim) + BOOL_TO_SIGN(g.reverse_ch1_elevon) * int(ch1_temp - elevon1_trim)) / 2 + 1500);
ushort roll = pickchannel(1, JoyChannels[1].axis, false, JoyChannels[1].expo);
ushort pitch = pickchannel(2, JoyChannels[2].axis, false, JoyChannels[2].expo);
if (getJoystickAxis(1) != Joystick.joystickaxis.None)
MainV2.comPort.MAV.cs.rcoverridech1 = (ushort)(BOOL_TO_SIGN(JoyChannels[1].reverse) * ((int)(pitch - 1500) - (int)(roll - 1500)) / 2 + 1500);
if (getJoystickAxis(2) != Joystick.joystickaxis.None)
MainV2.comPort.MAV.cs.rcoverridech2 = (ushort)(BOOL_TO_SIGN(JoyChannels[2].reverse) * ((int)(pitch - 1500) + (int)(roll - 1500)) / 2 + 1500);
}
else
{
if (getJoystickAxis(1) != Joystick.joystickaxis.None)
MainV2.comPort.MAV.cs.rcoverridech1 = pickchannel(1, JoyChannels[1].axis, JoyChannels[1].reverse, JoyChannels[1].expo);//(ushort)(((int)state.Rz / 65.535) + 1000);
if (getJoystickAxis(2) != Joystick.joystickaxis.None)
MainV2.comPort.MAV.cs.rcoverridech2 = pickchannel(2, JoyChannels[2].axis, JoyChannels[2].reverse, JoyChannels[2].expo);//(ushort)(((int)state.Y / 65.535) + 1000);
}
if (getJoystickAxis(3) != Joystick.joystickaxis.None)
MainV2.comPort.MAV.cs.rcoverridech3 = pickchannel(3, JoyChannels[3].axis, JoyChannels[3].reverse, JoyChannels[3].expo);//(ushort)(1000 - ((int)slider[0] / 65.535) + 1000);
if (getJoystickAxis(4) != Joystick.joystickaxis.None)
MainV2.comPort.MAV.cs.rcoverridech4 = pickchannel(4, JoyChannels[4].axis, JoyChannels[4].reverse, JoyChannels[4].expo);//(ushort)(((int)state.X / 65.535) + 1000);
if (getJoystickAxis(5) != Joystick.joystickaxis.None)
MainV2.comPort.MAV.cs.rcoverridech5 = pickchannel(5, JoyChannels[5].axis, JoyChannels[5].reverse, JoyChannels[5].expo);
if (getJoystickAxis(6) != Joystick.joystickaxis.None)
MainV2.comPort.MAV.cs.rcoverridech6 = pickchannel(6, JoyChannels[6].axis, JoyChannels[6].reverse, JoyChannels[6].expo);
if (getJoystickAxis(7) != Joystick.joystickaxis.None)
MainV2.comPort.MAV.cs.rcoverridech7 = pickchannel(7, JoyChannels[7].axis, JoyChannels[7].reverse, JoyChannels[7].expo);
if (getJoystickAxis(8) != Joystick.joystickaxis.None)
MainV2.comPort.MAV.cs.rcoverridech8 = pickchannel(8, JoyChannels[8].axis, JoyChannels[8].reverse, JoyChannels[8].expo);
foreach (JoyButton but in JoyButtons)
{
if (but.buttonno != -1 && getButtonState(but.buttonno))
{
string mode = but.mode;
MainV2.instance.BeginInvoke((System.Windows.Forms.MethodInvoker)delegate()
{
try
{
MainV2.comPort.setMode(mode);
}
catch { System.Windows.Forms.CustomMessageBox.Show("Failed to change Modes"); }
});
}
}
//Console.WriteLine("{0} {1} {2} {3}", MainV2.comPort.MAV.cs.rcoverridech1, MainV2.comPort.MAV.cs.rcoverridech2, MainV2.comPort.MAV.cs.rcoverridech3, MainV2.comPort.MAV.cs.rcoverridech4);
}
catch (Exception ex) { log.Info("Joystick thread error "+ex.ToString()); } // so we cant fall out
}
}
public enum joystickaxis
{
None,
Pass,
ARx,
ARy,
ARz,
AX,
AY,
AZ,
FRx,
FRy,
FRz,
FX,
FY,
FZ,
Rx,
Ry,
Rz,
VRx,
VRy,
VRz,
VX,
VY,
VZ,
X,
Y,
Z,
Slider1,
Slider2
}
const int RESXu = 1024;
const int RESXul = 1024;
const int RESXl = 1024;
const int RESKul = 100;
/*
ushort expou(ushort x, ushort k)
{
// k*x*x*x + (1-k)*x
return ((ulong)x*x*x/0x10000*k/(RESXul*RESXul/0x10000) + (RESKul-k)*x+RESKul/2)/RESKul;
}
// expo-funktion:
// ---------------
// kmplot
// f(x,k)=exp(ln(x)*k/10) ;P[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
// f(x,k)=x*x*x*k/10 + x*(1-k/10) ;P[0,1,2,3,4,5,6,7,8,9,10]
// f(x,k)=x*x*k/10 + x*(1-k/10) ;P[0,1,2,3,4,5,6,7,8,9,10]
// f(x,k)=1+(x-1)*(x-1)*(x-1)*k/10 + (x-1)*(1-k/10) ;P[0,1,2,3,4,5,6,7,8,9,10]
short expo(short x, short k)
{
if (k == 0) return x;
short y;
bool neg = x < 0;
if (neg) x = -x;
if (k < 0)
{
y = RESXu - expou((ushort)(RESXu - x), (ushort)-k);
}
else
{
y = expou((ushort)x, (ushort)k);
}
return neg ? -y : y;
}
*/
public Device AcquireJoystick(string name)
{
DeviceList joysticklist = Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly);
bool found = false;
foreach (DeviceInstance device in joysticklist)
{
if (device.ProductName == name)
{
joystick = new Device(device.InstanceGuid);
found = true;
break;
}
}
if (!found)
return null;
joystick.SetDataFormat(DeviceDataFormat.Joystick);
joystick.Acquire();
return joystick;
}
public void UnAcquireJoyStick()
{
joystick.Unacquire();
}
bool getButtonState(int buttonno)
{
byte[] buts = state.GetButtons();
bool ans = buts[buttonno] > 0 && buttonpressed[buttonno] == 0; // press check + debounce
buttonpressed[buttonno] = buts[buttonno]; // set only this button
return ans;
}
public int getNumButtons()
{
return joystick.Caps.NumberButtons;
}
public joystickaxis getJoystickAxis(int channel)
{
try
{
return JoyChannels[channel].axis;
}
catch { return joystickaxis.None; }
}
public bool isButtonPressed(int buttonno)
{
byte[] buts = state.GetButtons();
if (buts == null || JoyButtons[buttonno].buttonno < 0)
return false;
return buts[JoyButtons[buttonno].buttonno] > 0;
}
public ushort getValueForChannel(int channel, string name)
{
joystick.Poll();
state = joystick.CurrentJoystickState;
ushort ans = pickchannel(channel, JoyChannels[channel].axis, JoyChannels[channel].reverse, JoyChannels[channel].expo);
log.DebugFormat("{0} = {1} = {2}",channel,ans, state.X);
return ans;
}
ushort pickchannel(int chan, joystickaxis axis, bool rev, int expo)
{
int min, max, trim = 0;
if (MainV2.comPort.MAV.param.Count > 0)
{
try
{
min = (int)(float)(MainV2.comPort.MAV.param["RC" + chan + "_MIN"]);
max = (int)(float)(MainV2.comPort.MAV.param["RC" + chan + "_MAX"]);
trim = (int)(float)(MainV2.comPort.MAV.param["RC" + chan + "_TRIM"]);
}
catch {
min = 1000;
max = 2000;
trim = 1500;
}
}
else
{
min = 1000;
max = 2000;
trim = 1500;
}
if (chan == 3)
{
trim = (min + max) / 2;
// trim = min; // throttle
}
int range = Math.Abs(max - min);
int working = 0;
switch (axis)
{
case joystickaxis.None:
working = ushort.MaxValue / 2;
break;
case joystickaxis.Pass:
working = (int)(((float)(trim - min) / range) * ushort.MaxValue);
break;
case joystickaxis.ARx:
working = state.ARx;
break;
case joystickaxis.ARy:
working = state.ARy;
break;
case joystickaxis.ARz:
working = state.ARz;
break;
case joystickaxis.AX:
working = state.AX;
break;
case joystickaxis.AY:
working = state.AY;
break;
case joystickaxis.AZ:
working = state.AZ;
break;
case joystickaxis.FRx:
working = state.FRx;
break;
case joystickaxis.FRy:
working = state.FRy;
break;
case joystickaxis.FRz:
working = state.FRz;
break;
case joystickaxis.FX:
working = state.FX;
break;
case joystickaxis.FY:
working = state.FY;
break;
case joystickaxis.FZ:
working = state.FZ;
break;
case joystickaxis.Rx:
working = state.Rx;
break;
case joystickaxis.Ry:
working = state.Ry;
break;
case joystickaxis.Rz:
working = state.Rz;
break;
case joystickaxis.VRx:
working = state.VRx;
break;
case joystickaxis.VRy:
working = state.VRy;
break;
case joystickaxis.VRz:
working = state.VRz;
break;
case joystickaxis.VX:
working = state.VX;
break;
case joystickaxis.VY:
working = state.VY;
break;
case joystickaxis.VZ:
working = state.VZ;
break;
case joystickaxis.X:
working = state.X;
break;
case joystickaxis.Y:
working = state.Y;
break;
case joystickaxis.Z:
working = state.Z;
break;
case joystickaxis.Slider1:
int[] slider = state.GetSlider();
working = slider[0];
break;
case joystickaxis.Slider2:
int[] slider1 = state.GetSlider();
working = slider1[1];
break;
}
// between 0 and 65535 - convert to int -500 to 500
working = (int)(working / 65.535) - 500;
if (rev)
working *= -1;
// calc scale from actualy pwm range
float scale = range / 1000.0f;
// save for later
int raw = working;
double B = 4 * (expo / 100.0);
double A = 1 - 0.25*B;
double t_in = working / 1000.0;
double t_out = 0;
double mid = trim / 1000.0;
t_out = A * (t_in) + B * Math.Pow((t_in), 3);
t_out = mid + t_out * scale;
// Console.WriteLine("tin {0} tout {1}",t_in,t_out);
working = (int)(t_out * 1000);
if (expo == 0)
{
working = (int)(raw) + trim;
}
//add limits to movement
working = Math.Max(min, working);
working = Math.Min(max, working);
return (ushort)working;
}
}
}