1 //Simplified BSD License (BSD-2-Clause) 2 // 3 //Copyright (c) 2020-2021, Marc Riera, The OpenBVE Project 4 // 5 //Redistribution and use in source and binary forms, with or without 6 //modification, are permitted provided that the following conditions are met: 7 // 8 //1. Redistributions of source code must retain the above copyright notice, this 9 // list of conditions and the following disclaimer. 10 //2. Redistributions in binary form must reproduce the above copyright notice, 11 // this list of conditions and the following disclaimer in the documentation 12 // and/or other materials provided with the distribution. 13 // 14 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 //ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 //WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 //DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 //ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 //(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 //ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 //(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 //SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 25 using System; 26 using System.Collections.Generic; 27 using OpenTK.Input; 28 29 namespace DenshaDeGoInput 30 { 31 /// <summary> 32 /// Class representing a PlayStation 2 controller 33 /// </summary> 34 internal class Ps2Controller : Controller 35 { 36 /// <summary>A cached list of supported connected controllers.</summary> 37 private static Dictionary<Guid, Controller> cachedControllers = new Dictionary<Guid, Controller>(); 38 39 private static string[] controllerIds = 40 { 41 // TCPP-20009 (Type II) 42 "0ae4:0004", 43 // TCPP-20011 (Shinkansen) 44 "0ae4:0005", 45 // TCPP-20014 (Ryojouhen) 46 "0ae4:0007" 47 }; 48 49 /// <summary>The min/max byte for each brake notch, from Released to Emergency. Each notch consists of two bytes.</summary> 50 private readonly byte[] brakeBytes; 51 52 /// <summary>The min/max byte for each power notch, from Released to maximum. Each notch consists of two bytes.</summary> 53 private readonly byte[] powerBytes; 54 55 /// <summary>The button mask for the buttons. Follows order in InputTranslator.</summary> 56 private readonly byte[] buttonMask; 57 58 /// <summary>An array with raw input data from the controller.</summary> 59 private byte[] inputBuffer; 60 61 /// <summary>An array with raw output data for the controller.</summary> 62 private byte[] outputBuffer; 63 64 /// <summary> 65 /// Initializes an Unbalance controller. 66 /// </summary> Ps2Controller(ControllerButtons buttons, byte[] buttonBytes, byte[] brake, byte[] power)67 internal Ps2Controller(ControllerButtons buttons, byte[] buttonBytes, byte[] brake, byte[] power) 68 { 69 ControllerName = string.Empty; 70 IsConnected = false; 71 RequiresCalibration = false; 72 BrakeNotches = brake.Length / 2 - 2; 73 PowerNotches = power.Length / 2 - 1; 74 brakeBytes = brake; 75 powerBytes = power; 76 Buttons = buttons; 77 buttonMask = buttonBytes; 78 } 79 80 /// <summary> 81 /// Reads the input from the controller. 82 /// </summary> ReadInput()83 internal override void ReadInput() 84 { 85 // Sync input/output data 86 LibUsb.SyncController(Guid, inputBuffer, outputBuffer); 87 88 byte brakeData; 89 byte powerData; 90 byte buttonData; 91 byte dpadData; 92 byte pedalData; 93 switch (Id) 94 { 95 // TCPP-20009 (Type II) 96 case "0ae4:0004": 97 brakeData = inputBuffer[1]; 98 powerData = inputBuffer[2]; 99 buttonData = inputBuffer[5]; 100 dpadData = inputBuffer[4]; 101 pedalData = inputBuffer[3]; 102 break; 103 // TCPP-20011 (Shinkansen) 104 // TCPP-20014 (Ryojouhen) 105 default: 106 brakeData = inputBuffer[0]; 107 powerData = inputBuffer[1]; 108 buttonData = inputBuffer[4]; 109 dpadData = inputBuffer[3]; 110 pedalData = inputBuffer[2]; 111 break; 112 } 113 114 for (int i = 0; i < brakeBytes.Length; i+=2) 115 { 116 // Each notch uses two bytes, minimum value and maximum value 117 if (brakeData >= brakeBytes[i] && brakeData <= brakeBytes[i + 1]) 118 { 119 if (brakeBytes.Length == i + 2) 120 { 121 // Last notch should be Emergency 122 InputTranslator.BrakeNotch = InputTranslator.BrakeNotches.Emergency; 123 } 124 else 125 { 126 // Regular brake notch 127 InputTranslator.BrakeNotch = (InputTranslator.BrakeNotches)(i / 2); 128 } 129 break; 130 } 131 } 132 for (int i = 0; i < powerBytes.Length; i+=2) 133 { 134 // Each notch uses two bytes, minimum value and maximum value 135 if (powerData >= powerBytes[i] && powerData <= powerBytes[i + 1]) 136 { 137 InputTranslator.PowerNotch = (InputTranslator.PowerNotches)(i / 2); 138 break; 139 } 140 } 141 142 // Standard buttons 143 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.Select] = (buttonData & buttonMask[(int)InputTranslator.ControllerButton.Select]) != 0 ? ButtonState.Pressed : ButtonState.Released; 144 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.Start] = (buttonData & buttonMask[(int)InputTranslator.ControllerButton.Start]) != 0 ? ButtonState.Pressed : ButtonState.Released; 145 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.A] = (buttonData & buttonMask[(int)InputTranslator.ControllerButton.A]) != 0 ? ButtonState.Pressed : ButtonState.Released; 146 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.B] = (buttonData & buttonMask[(int)InputTranslator.ControllerButton.B]) != 0 ? ButtonState.Pressed : ButtonState.Released; 147 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.C] = (buttonData & buttonMask[(int)InputTranslator.ControllerButton.C]) != 0 ? ButtonState.Pressed : ButtonState.Released; 148 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.D] = (buttonData & buttonMask[(int)InputTranslator.ControllerButton.D]) != 0 ? ButtonState.Pressed : ButtonState.Released; 149 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.LDoor] = (buttonData & buttonMask[(int)InputTranslator.ControllerButton.LDoor]) != 0 ? ButtonState.Pressed : ButtonState.Released; 150 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.RDoor] = (buttonData & buttonMask[(int)InputTranslator.ControllerButton.RDoor]) != 0 ? ButtonState.Pressed : ButtonState.Released; 151 152 // D-pad 153 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.Up] = (dpadData <= 1 || dpadData == 7) ? ButtonState.Pressed : ButtonState.Released; 154 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.Right] = (dpadData >= 1 && dpadData <= 3) ? ButtonState.Pressed : ButtonState.Released; 155 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.Down] = (dpadData >= 3 && dpadData <= 5) ? ButtonState.Pressed : ButtonState.Released; 156 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.Left] = (dpadData >= 5 && dpadData <= 7) ? ButtonState.Pressed : ButtonState.Released; 157 158 // Horn pedal 159 InputTranslator.ControllerButtons[(int)InputTranslator.ControllerButton.Pedal] = pedalData == 0x0 ? ButtonState.Pressed : ButtonState.Released; 160 161 switch (Id) 162 { 163 // TCPP-20009 (Type II) 164 case "0ae4:0004": 165 outputBuffer = new byte[] { 0x0, 0x3 }; 166 if (DenshaDeGoInput.Ingame) 167 { 168 // Door lamp 169 outputBuffer[1] = (byte)(DenshaDeGoInput.TrainDoorsClosed ? 1 : 0); 170 } 171 break; 172 // TCPP-20011 (Shinkansen) 173 case "0ae4:0005": 174 double speed = Math.Round(DenshaDeGoInput.CurrentTrainSpeed, 0); 175 double limit = Math.Round(DenshaDeGoInput.CurrentSpeedLimit, 0); 176 int speed1 = (int)(speed % 10); 177 int speed2 = (int)(speed % 100 / 10); 178 int speed3 = (int)(speed % 1000 / 100); 179 int limit1 = (int)(limit % 10); 180 int limit2 = (int)(limit % 100 / 10); 181 int limit3 = (int)(limit % 1000 / 100); 182 int limit_approach = 0; 183 if (speed >= limit) 184 { 185 limit_approach = 10; 186 } 187 else if (speed > limit - 10) 188 { 189 limit_approach = -(int)(limit - speed - 10); 190 } 191 // Specially crafted array that blanks the display 192 outputBuffer = new byte[] { 0x0, 0x0, 0x0, 0x0, 0xFF, 0xFF, 0xFF, 0xFF }; 193 if (DenshaDeGoInput.Ingame) 194 { 195 if (DenshaDeGoInput.CurrentSpeedLimit >= 0 && DenshaDeGoInput.ATCSection) 196 { 197 // Door lamp + limit approach 198 outputBuffer[2] = (byte)((128 * (DenshaDeGoInput.TrainDoorsClosed ? 1 : 0)) + limit_approach); 199 // Route limit 200 outputBuffer[6] = (byte)(16 * limit2 + limit1); 201 outputBuffer[7] = (byte)limit3; 202 } 203 else 204 { 205 // Door lamp 206 outputBuffer[2] = (byte)(128 * (DenshaDeGoInput.TrainDoorsClosed ? 1 : 0)); 207 } 208 209 // Speed gauge 210 outputBuffer[3] = (byte)Math.Ceiling(Math.Round(DenshaDeGoInput.CurrentTrainSpeed) / 15); 211 // Train speed 212 outputBuffer[4] = (byte)(16 * speed2 + speed1); 213 outputBuffer[5] = (byte)speed3; 214 } 215 break; 216 } 217 } 218 219 /// <summary> 220 /// Configures the supported controllers with LibUsb. 221 /// </summary> ConfigureControllers()222 internal static void ConfigureControllers() 223 { 224 LibUsb.AddSupportedControllers(controllerIds); 225 } 226 227 /// <summary> 228 /// Gets the list of connected controllers 229 /// </summary> 230 /// <returns>The list of controllers handled by this class.</returns> GetControllers()231 internal static Dictionary<Guid, Controller> GetControllers() 232 { 233 foreach (KeyValuePair<Guid, LibUsb.UsbController> usbController in LibUsb.GetSupportedControllers()) 234 { 235 Guid guid = usbController.Key; 236 string id = GetControllerID(guid); 237 string name = usbController.Value.ControllerName; 238 239 if (!cachedControllers.ContainsKey(guid)) 240 { 241 // TCPP-20009 (Type II) 242 if (id == "0ae4:0004") 243 { 244 ControllerButtons buttons = ControllerButtons.Select | ControllerButtons.Start | ControllerButtons.A | ControllerButtons.B | ControllerButtons.C | ControllerButtons.D | ControllerButtons.Pedal | ControllerButtons.DPad; 245 byte[] buttonBytes = { 0x10, 0x20, 0x2, 0x1, 0x4, 0x8, 0x0, 0x0 }; 246 byte[] brakeBytes = { 0x79, 0x79, 0x8A, 0x8A, 0x94, 0x94, 0x9A, 0x9A, 0xA2, 0xA2, 0xA8, 0xA8, 0xAF, 0xAF, 0xB2, 0xB2, 0xB5, 0xB5, 0xB9, 0xB9 }; 247 byte[] powerBytes = { 0x81, 0x81, 0x6D, 0x6D, 0x54, 0x54, 0x3F, 0x3F, 0x21, 0x21, 0x00, 0x00 }; 248 Ps2Controller newcontroller = new Ps2Controller(buttons, buttonBytes, brakeBytes, powerBytes) 249 { 250 // 6 bytes for input, 2 for output 251 Guid = guid, 252 Id = id, 253 ControllerName = name, 254 inputBuffer = new byte[] { 0x1, 0x0, 0x0, 0xFF, 0x8, 0x0 }, 255 outputBuffer = new byte[] { 0x0, 0x3 } 256 }; 257 cachedControllers.Add(guid, newcontroller); 258 } 259 // TCPP-20011 (Shinkansen) 260 if (id == "0ae4:0005") 261 { 262 ControllerButtons buttons = ControllerButtons.Select | ControllerButtons.Start | ControllerButtons.A | ControllerButtons.B | ControllerButtons.C | ControllerButtons.D | ControllerButtons.Pedal | ControllerButtons.DPad; 263 byte[] buttonBytes = { 0x10, 0x20, 0x8, 0x4, 0x2, 0x1, 0x0, 0x0 }; 264 byte[] brakeBytes = { 0x1C, 0x1C, 0x38, 0x38, 0x54, 0x54, 0x70, 0x70, 0x8B, 0x8B, 0xA7, 0xA7, 0xC3, 0xC3, 0xDF, 0xDF, 0xFB, 0xFB }; 265 byte[] powerBytes = { 0x12, 0x12, 0x24, 0x24, 0x36, 0x36, 0x48, 0x48, 0x5A, 0x5A, 0x6C, 0x6C, 0x7E, 0x7E, 0x90, 0x90, 0xA2, 0xA2, 0xB4, 0xB4, 0xC6, 0xC6, 0xD7, 0xD7, 0xE9, 0xE9, 0xFB, 0xFB }; 266 Ps2Controller newcontroller = new Ps2Controller(buttons, buttonBytes, brakeBytes, powerBytes) 267 { 268 // 6 bytes for input, 8 for output 269 Guid = guid, 270 Id = id, 271 ControllerName = name, 272 inputBuffer = new byte[] { 0x0, 0x0, 0xFF, 0x8, 0x0, 0x0 }, 273 outputBuffer = new byte[] { 0x0, 0x0, 0x0, 0x0, 0xFF, 0xFF, 0xFF, 0xFF } 274 }; 275 cachedControllers.Add(guid, newcontroller); 276 } 277 // TCPP-20014 (Ryojouhen) 278 if (id == "0ae4:0007") 279 { 280 ControllerButtons buttons = ControllerButtons.Select | ControllerButtons.Start | ControllerButtons.A | ControllerButtons.B | ControllerButtons.C | ControllerButtons.Pedal | ControllerButtons.LDoor | ControllerButtons.RDoor | ControllerButtons.DPad; 281 byte[] buttonBytes = { 0x20, 0x40, 0x4, 0x2, 0x1, 0x0, 0x10, 0x8 }; 282 byte[] brakeBytes = { 0x23, 0x2C, 0x2D, 0x3E, 0x3F, 0x4E, 0x4F, 0x63, 0x64, 0x8A, 0x8B, 0xB0, 0xB1, 0xD4, 0xD5, 0xDF }; 283 byte[] powerBytes = { 0x0, 0x0, 0x3C, 0x3C, 0x78, 0x78, 0xB4, 0xB4, 0xF0, 0xF0 }; 284 Ps2Controller newcontroller = new Ps2Controller(buttons, buttonBytes, brakeBytes, powerBytes) 285 { 286 // 8 bytes for input, no output 287 Guid = guid, 288 Id = id, 289 ControllerName = name, 290 inputBuffer = new byte[] { 0x0, 0x0, 0xFF, 0x8, 0x0, 0x0, 0x0, 0x0 }, 291 outputBuffer = new byte[0] 292 }; 293 cachedControllers.Add(guid, newcontroller); 294 } 295 } 296 297 // Update connection status and name 298 cachedControllers[guid].IsConnected = usbController.Value.IsConnected; 299 cachedControllers[guid].ControllerName = name; 300 } 301 return cachedControllers; 302 } 303 } 304 } 305