├── KSPSerialIO ├── SerialPort.dll ├── Properties │ └── AssemblyInfo.cs ├── KSPSerialIO.csproj └── KSPIO.cs ├── .gitattributes ├── settings ├── KSPSerialIO.sln └── .gitignore /KSPSerialIO/SerialPort.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zitron-git/KSPSerialIO/HEAD/KSPSerialIO/SerialPort.dll -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /settings: -------------------------------------------------------------------------------- 1 | var config = KSP.IO.PluginConfiguration.CreateForType(); 2 | [23:23:52] zitron FA: do you need to specify a file name? 3 | [23:23:57] nick.noether: then config.load() / config.save() 4 | [23:23:57] nick.noether: no 5 | [23:24:02] nick.noether: you do that via the classname 6 | [23:24:13] zitron FA: where is it saved then? 7 | [23:24:28] nick.noether: it looks up the assembly your class belongs to (i.e. your dll) then adds PluginData/ as a folder and creates a config file there 8 | [23:24:41] zitron FA: ah 9 | [23:24:58] zitron FA: it is editable or some binary file? 10 | [23:25:02] nick.noether: editable 11 | [23:25:13] zitron FA: perfect thanks alot! 12 | [23:25:33] nick.noether: simple xml file 13 | [23:25:53] nick.noether: you can just do config.SetValue(name,value) and done 14 | [23:26:02] zitron FA: very nice -------------------------------------------------------------------------------- /KSPSerialIO.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KSPSerialIO", "KSPSerialIO\KSPSerialIO.csproj", "{296C85FA-800F-4630-9663-ACC934D444CD}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {296C85FA-800F-4630-9663-ACC934D444CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {296C85FA-800F-4630-9663-ACC934D444CD}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {296C85FA-800F-4630-9663-ACC934D444CD}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {296C85FA-800F-4630-9663-ACC934D444CD}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /KSPSerialIO/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("KSPSerialIO")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("KSPSerialIO")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("b6cf99b2-97d1-4f84-a488-6af5a94cac71")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | 131 | # NuGet Packages Directory 132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 133 | #packages/ 134 | 135 | # Windows Azure Build Output 136 | csx 137 | *.build.csdef 138 | 139 | # Windows Store app package directory 140 | AppPackages/ 141 | 142 | # Others 143 | sql/ 144 | *.Cache 145 | ClientBin/ 146 | [Ss]tyle[Cc]op.* 147 | ~$* 148 | *~ 149 | *.dbmdl 150 | *.[Pp]ublish.xml 151 | *.pfx 152 | *.publishsettings 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | App_Data/*.mdf 166 | App_Data/*.ldf 167 | 168 | ############# 169 | ## Windows detritus 170 | ############# 171 | 172 | # Windows image file caches 173 | Thumbs.db 174 | ehthumbs.db 175 | 176 | # Folder config file 177 | Desktop.ini 178 | 179 | # Recycle Bin used on file shares 180 | $RECYCLE.BIN/ 181 | 182 | # Mac crap 183 | .DS_Store 184 | 185 | 186 | ############# 187 | ## Python 188 | ############# 189 | 190 | *.py[co] 191 | 192 | # Packages 193 | *.egg 194 | *.egg-info 195 | dist/ 196 | build/ 197 | eggs/ 198 | parts/ 199 | var/ 200 | sdist/ 201 | develop-eggs/ 202 | .installed.cfg 203 | 204 | # Installer logs 205 | pip-log.txt 206 | 207 | # Unit test / coverage reports 208 | .coverage 209 | .tox 210 | 211 | #Translations 212 | *.mo 213 | 214 | #Mr Developer 215 | .mr.developer.cfg 216 | -------------------------------------------------------------------------------- /KSPSerialIO/KSPSerialIO.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {296C85FA-800F-4630-9663-ACC934D444CD} 8 | Library 9 | Properties 10 | KSPSerialIO 11 | KSPSerialIO 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | none 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | AnyCPU 32 | false 33 | true 34 | 35 | 36 | 37 | False 38 | ..\..\..\..\..\..\..\Games\KSP_win64\KSP_x64_Data\Managed\Assembly-CSharp.dll 39 | 40 | 41 | .\SerialPort.dll 42 | False 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | ..\..\..\..\..\..\..\Games\KSP_win64\KSP_x64_Data\Managed\UnityEngine.dll 53 | 54 | 55 | ..\..\..\..\..\..\..\Games\KSP_win64\KSP_x64_Data\Managed\UnityEngine.CoreModule.dll 56 | 57 | 58 | False 59 | ..\..\..\..\..\..\..\Games\KSP_win64\KSP_x64_Data\Managed\UnityEngine.UI.dll 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 78 | -------------------------------------------------------------------------------- /KSPSerialIO/KSPIO.cs: -------------------------------------------------------------------------------- 1 | 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Reflection; 7 | using System.Threading; 8 | using Microsoft.Win32; 9 | using System.Runtime.InteropServices; 10 | 11 | using System.Text.RegularExpressions; 12 | using OpenNETCF.IO.Ports; 13 | using UnityEngine; 14 | using KSP.IO; 15 | using KSP.UI.Screens; 16 | 17 | namespace KSPSerialIO 18 | { 19 | #region Structs 20 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 21 | public struct VesselData 22 | { 23 | public byte id; //1 24 | public float AP; //2 25 | public float PE; //3 26 | public float SemiMajorAxis; //4 27 | public float SemiMinorAxis; //5 28 | public float VVI; //6 29 | public float e; //7 30 | public float inc; //8 31 | public float G; //9 32 | public int TAp; //10 33 | public int TPe; //11 34 | public float TrueAnomaly; //12 35 | public float Density; //13 36 | public int period; //14 37 | public float RAlt; //15 38 | public float Alt; //16 39 | public float Vsurf; //17 40 | public float Lat; //18 41 | public float Lon; //19 42 | public float LiquidFuelTot; //20 43 | public float LiquidFuel; //21 44 | public float OxidizerTot; //22 45 | public float Oxidizer; //23 46 | public float EChargeTot; //24 47 | public float ECharge; //25 48 | public float MonoPropTot; //26 49 | public float MonoProp; //27 50 | public float IntakeAirTot; //28 51 | public float IntakeAir; //29 52 | public float SolidFuelTot; //30 53 | public float SolidFuel; //31 54 | public float XenonGasTot; //32 55 | public float XenonGas; //33 56 | public float LiquidFuelTotS; //34 57 | public float LiquidFuelS; //35 58 | public float OxidizerTotS; //36 59 | public float OxidizerS; //37 60 | public UInt32 MissionTime; //38 61 | public float deltaTime; //39 62 | public float VOrbit; //40 63 | public UInt32 MNTime; //41 64 | public float MNDeltaV; //42 65 | public float Pitch; //43 66 | public float Roll; //44 67 | public float Heading; //45 68 | public UInt16 ActionGroups; //46 status bit order:SAS, RCS, Light, Gear, Brakes, Abort, Custom01 - 10 69 | public byte SOINumber; //47 SOI Number (decimal format: sun-planet-moon e.g. 130 = kerbin, 131 = mun) 70 | public byte MaxOverHeat; //48 Max part overheat (% percent) 71 | public float MachNumber; //49 72 | public float IAS; //50 Indicated Air Speed 73 | public byte CurrentStage; //51 Current stage number 74 | public byte TotalStage; //52 TotalNumber of stages 75 | public float TargetDist; //53 Distance to targeted vessel (m) 76 | public float TargetV; //54 Target vessel relative velocity (m/s) 77 | public byte NavballSASMode; //55 Combined byte for navball target mode and SAS mode 78 | // First four bits indicate AutoPilot mode: 79 | // 0 SAS is off //1 = Regular Stability Assist //2 = Prograde 80 | // 3 = RetroGrade //4 = Normal //5 = Antinormal //6 = Radial In 81 | // 7 = Radial Out //8 = Target //9 = Anti-Target //10 = Maneuver node 82 | // Last 4 bits set navball mode. (0=ignore,1=ORBIT,2=SURFACE,3=TARGET) 83 | public short ProgradePitch; //56 Pitch Of the Prograde Vector; int_16 ***Changed: now fix point, actual angle = angle/50*** used to be (-0x8000(-360 degrees) to 0x7FFF(359.99ish degrees)); 84 | public short ProgradeHeading;//57 Heading Of the Prograde Vector; see above for range (Prograde vector depends on navball mode, eg Surface/Orbit/Target) 85 | public short ManeuverPitch; //58 Pitch Of the Maneuver Vector; see above for range; (0 if no Maneuver node) 86 | public short ManeuverHeading;//59 Heading Of the Maneuver Vector; see above for range; (0 if no Maneuver node) 87 | public short TargetPitch; //60 Pitch Of the Target Vector; see above for range; (0 if no Target) 88 | public short TargetHeading; //61 Heading Of the Target Vector; see above for range; (0 if no Target) 89 | public short NormalHeading; //62 Normal Of the Prograde Vector; see above for range; (Pitch of the Heading Vector is always 0) 90 | } 91 | 92 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 93 | public struct HandShakePacket 94 | { 95 | public byte id; 96 | public byte M1; 97 | public byte M2; 98 | public byte M3; 99 | } 100 | 101 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 102 | public struct ControlPacket 103 | { 104 | public byte id; 105 | public byte MainControls; //SAS RCS Lights Gear Brakes Precision Abort Stage 106 | public byte Mode; //0 = stage, 1 = docking, 2 = map 107 | public ushort ControlGroup; //control groups 1-10 in 2 bytes 108 | public byte NavballSASMode; //AutoPilot mode (See above for AutoPilot modes)(Ignored if the equal to zero or out of bounds (>10)) //Navball mode 109 | public byte AdditionalControlByte1; 110 | public short Pitch; //-1000 -> 1000 111 | public short Roll; //-1000 -> 1000 112 | public short Yaw; //-1000 -> 1000 113 | public short TX; //-1000 -> 1000 114 | public short TY; //-1000 -> 1000 115 | public short TZ; //-1000 -> 1000 116 | public short WheelSteer; //-1000 -> 1000 117 | public short Throttle; // 0 -> 1000 118 | public short WheelThrottle; // 0 -> 1000 119 | }; 120 | 121 | public struct VesselControls 122 | { 123 | public Boolean SAS; 124 | public Boolean RCS; 125 | public Boolean Lights; 126 | public Boolean Gear; 127 | public Boolean Brakes; 128 | public Boolean Precision; 129 | public Boolean Abort; 130 | public Boolean Stage; 131 | public int Mode; 132 | public int SASMode; 133 | public int SpeedMode; 134 | public Boolean[] ControlGroup; 135 | public float Pitch; 136 | public float Roll; 137 | public float Yaw; 138 | public float TX; 139 | public float TY; 140 | public float TZ; 141 | public float WheelSteer; 142 | public float Throttle; 143 | public float WheelThrottle; 144 | }; 145 | 146 | public struct IOResource 147 | { 148 | public float Max; 149 | public float Current; 150 | } 151 | 152 | public struct NavHeading 153 | { 154 | public float Pitch, Heading; 155 | /* public NavHeading(float Pitch, float Heading) 156 | { 157 | this.Pitch = Pitch; 158 | this.Heading = Heading; 159 | }*/ 160 | } 161 | 162 | #endregion 163 | 164 | enum enumAG : int 165 | { 166 | SAS, 167 | RCS, 168 | Light, 169 | Gear, 170 | Brakes, 171 | Abort, 172 | Custom01, 173 | Custom02, 174 | Custom03, 175 | Custom04, 176 | Custom05, 177 | Custom06, 178 | Custom07, 179 | Custom08, 180 | Custom09, 181 | Custom10, 182 | }; 183 | 184 | [KSPAddon(KSPAddon.Startup.MainMenu, false)] 185 | public class SettingsNStuff : MonoBehaviour 186 | { 187 | 188 | public static PluginConfiguration cfg = PluginConfiguration.CreateForType(); 189 | public static string DefaultPort; 190 | public static double refreshrate; 191 | public static int HandshakeDelay; 192 | public static int HandshakeDisable; 193 | public static int BaudRate; 194 | // Throttle and axis controls have the following settings: 195 | // 0: The internal value (supplied by KSP) is always used. 196 | // 1: The external value (read from serial packet) is always used. 197 | // 2: If the internal value is not zero use it, otherwise use the external value. 198 | // 3: If the external value is not zero use it, otherwise use the internal value. 199 | public static int PitchEnable; 200 | public static int RollEnable; 201 | public static int YawEnable; 202 | public static int TXEnable; 203 | public static int TYEnable; 204 | public static int TZEnable; 205 | public static int WheelSteerEnable; 206 | public static int ThrottleEnable; 207 | public static int WheelThrottleEnable; 208 | public static double SASTol; 209 | 210 | void Awake() 211 | { 212 | //cfg["refresh"] = 0.08; 213 | //cfg["DefaultPort"] = "COM1"; 214 | //cfg["HandshakeDelay"] = 2500; 215 | print("KSPSerialIO: Loading settings..."); 216 | 217 | cfg.load(); 218 | DefaultPort = cfg.GetValue("DefaultPort"); 219 | print("KSPSerialIO: Default Port = " + DefaultPort); 220 | 221 | refreshrate = cfg.GetValue("refresh"); 222 | print("KSPSerialIO: Refreshrate = " + refreshrate.ToString()); 223 | 224 | BaudRate = cfg.GetValue("BaudRate"); 225 | print("KSPSerialIO: BaudRate = " + BaudRate.ToString()); 226 | 227 | HandshakeDelay = cfg.GetValue("HandshakeDelay"); 228 | print("KSPSerialIO: Handshake Delay = " + HandshakeDelay.ToString()); 229 | 230 | HandshakeDisable = cfg.GetValue("HandshakeDisable"); 231 | print("KSPSerialIO: Handshake Disable = " + HandshakeDisable.ToString()); 232 | 233 | PitchEnable = cfg.GetValue("PitchEnable"); 234 | print("KSPSerialIO: Pitch Enable = " + PitchEnable.ToString()); 235 | 236 | RollEnable = cfg.GetValue("RollEnable"); 237 | print("KSPSerialIO: Roll Enable = " + RollEnable.ToString()); 238 | 239 | YawEnable = cfg.GetValue("YawEnable"); 240 | print("KSPSerialIO: Yaw Enable = " + YawEnable.ToString()); 241 | 242 | TXEnable = cfg.GetValue("TXEnable"); 243 | print("KSPSerialIO: Translate X Enable = " + TXEnable.ToString()); 244 | 245 | TYEnable = cfg.GetValue("TYEnable"); 246 | print("KSPSerialIO: Translate Y Enable = " + TYEnable.ToString()); 247 | 248 | TZEnable = cfg.GetValue("TZEnable"); 249 | print("KSPSerialIO: Translate Z Enable = " + TZEnable.ToString()); 250 | 251 | WheelSteerEnable = cfg.GetValue("WheelSteerEnable"); 252 | print("KSPSerialIO: Wheel Steering Enable = " + WheelSteerEnable.ToString()); 253 | 254 | ThrottleEnable = cfg.GetValue("ThrottleEnable"); 255 | print("KSPSerialIO: Throttle Enable = " + ThrottleEnable.ToString()); 256 | 257 | WheelThrottleEnable = cfg.GetValue("WheelThrottleEnable"); 258 | print("KSPSerialIO: Wheel Throttle Enable = " + WheelThrottleEnable.ToString()); 259 | 260 | SASTol = cfg.GetValue("SASTol"); 261 | print("KSPSerialIO: SAS Tol = " + SASTol.ToString()); 262 | } 263 | } 264 | 265 | [KSPAddon(KSPAddon.Startup.Flight, false)] 266 | public class KSPSerialPort : MonoBehaviour 267 | { 268 | public static SerialPort Port; 269 | public static string PortNumber; 270 | public static string Win32PortName; 271 | public static Boolean DisplayFound = false; 272 | public static Boolean ControlReceived = false; 273 | 274 | public static VesselData VData; 275 | public static ControlPacket CPacket; 276 | private static HandShakePacket HPacket; 277 | 278 | public static VesselControls VControls = new VesselControls(); 279 | public static VesselControls VControlsOld = new VesselControls(); 280 | 281 | private static byte[] buffer = new byte[255]; 282 | private static byte rx_len; 283 | private static byte rx_array_inx; 284 | private static int structSize; 285 | private static byte id = 255; 286 | 287 | private const byte HSPid = 0, VDid = 1, Cid = 101; //hard coded values for packet IDS 288 | 289 | 290 | public static void sendPacket(object anything) 291 | { 292 | byte[] Payload = StructureToByteArray(anything); 293 | byte header1 = 0xBE; 294 | byte header2 = 0xEF; 295 | byte size = (byte)Payload.Length; 296 | byte checksum = size; 297 | 298 | byte[] Packet = new byte[size + 4]; 299 | 300 | //Packet = [header][size][payload][checksum]; 301 | //Header = [Header1=0xBE][Header2=0xEF] 302 | //size = [payload.length (0-255)] 303 | 304 | for (int i = 0; i < size; i++) 305 | { 306 | checksum ^= Payload[i]; 307 | } 308 | 309 | Payload.CopyTo(Packet, 3); 310 | Packet[0] = header1; 311 | Packet[1] = header2; 312 | Packet[2] = size; 313 | Packet[Packet.Length - 1] = checksum; 314 | 315 | Port.Write(Packet, 0, Packet.Length); 316 | } 317 | 318 | private void Begin() 319 | { 320 | Port = new SerialPort(Win32PortName, SettingsNStuff.BaudRate, Parity.None, 8, StopBits.One); 321 | //Port = new SerialPort(); 322 | Port.ReceivedBytesThreshold = 3; 323 | Port.ReceivedEvent += Port_ReceivedEvent; 324 | } 325 | 326 | //these are copied from the intarwebs, converts struct to byte array 327 | private static byte[] StructureToByteArray(object obj) 328 | { 329 | int len = Marshal.SizeOf(obj); 330 | byte[] arr = new byte[len]; 331 | IntPtr ptr = Marshal.AllocHGlobal(len); 332 | Marshal.StructureToPtr(obj, ptr, true); 333 | Marshal.Copy(ptr, arr, 0, len); 334 | Marshal.FreeHGlobal(ptr); 335 | return arr; 336 | } 337 | 338 | private static object ByteArrayToStructure(byte[] bytearray, object obj) 339 | { 340 | int len = Marshal.SizeOf(obj); 341 | 342 | IntPtr i = Marshal.AllocHGlobal(len); 343 | 344 | Marshal.Copy(bytearray, 0, i, len); 345 | 346 | obj = Marshal.PtrToStructure(i, obj.GetType()); 347 | 348 | Marshal.FreeHGlobal(i); 349 | 350 | return obj; 351 | } 352 | /* 353 | private static T ReadUsingMarshalUnsafe(byte[] data) where T : struct 354 | { 355 | unsafe 356 | { 357 | fixed (byte* p = &data[0]) 358 | { 359 | return (T)Marshal.PtrToStructure(new IntPtr(p), typeof(T)); 360 | } 361 | } 362 | } 363 | */ 364 | void initializeDataPackets() 365 | { 366 | VData = new VesselData(); 367 | VData.id = VDid; 368 | 369 | HPacket = new HandShakePacket(); 370 | HPacket.id = HSPid; 371 | HPacket.M1 = 1; 372 | HPacket.M2 = 2; 373 | HPacket.M3 = 3; 374 | 375 | CPacket = new ControlPacket(); 376 | 377 | VControls.ControlGroup = new Boolean[11]; 378 | VControlsOld.ControlGroup = new Boolean[11]; 379 | } 380 | 381 | void Awake() 382 | { 383 | if (DisplayFound) 384 | { 385 | Debug.Log("KSPSerialIO: running..."); 386 | Begin(); 387 | } 388 | else 389 | { 390 | Debug.Log("KSPSerialIO: Version 0.19.3b"); 391 | Debug.Log("KSPSerialIO: Getting serial ports..."); 392 | Debug.Log("KSPSerialIO: Output packet size: " + Marshal.SizeOf(VData).ToString() + "/255"); 393 | initializeDataPackets(); 394 | 395 | try 396 | { 397 | //Use registry hack to get a list of serial ports until we get system.io.ports 398 | RegistryKey SerialCOMSKey = Registry.LocalMachine.OpenSubKey(@"HARDWARE\\DEVICEMAP\\SERIALCOMM\\"); 399 | 400 | Begin(); 401 | 402 | //print("KSPSerialIO: receive threshold " + Port.ReceivedBytesThreshold.ToString()); 403 | 404 | if (SerialCOMSKey == null) 405 | { 406 | Debug.Log("KSPSerialIO: Dude do you even win32 serial port??"); 407 | } 408 | else 409 | { 410 | String[] realports = SerialCOMSKey.GetValueNames(); // get list of all serial devices 411 | String[] names = new string[realports.Length + 1]; // make a new list with 1 extra, we put the default port first 412 | realports.CopyTo(names, 1); 413 | 414 | Debug.Log("KSPSerialIO: Found " + names.Length.ToString() + " serial ports"); 415 | 416 | //look through all found ports for our display 417 | int j = 0; 418 | 419 | foreach (string PortName in names) 420 | { 421 | if (j == 0) // try default port first 422 | { 423 | PortNumber = SettingsNStuff.DefaultPort; 424 | Debug.Log("KSPSerialIO: trying default port " + PortNumber); 425 | } 426 | else 427 | { 428 | PortNumber = (string)SerialCOMSKey.GetValue(PortName); 429 | Debug.Log("KSPSerialIO: trying port " + PortName + " - " + PortNumber); 430 | } 431 | 432 | Win32PortName = @"\\.\" + PortNumber; // add @"\\.\" to PortNumber to have win10 compatibility for com ports > 9 --- Jimbofarrar 433 | 434 | Port.PortName = Win32PortName; 435 | 436 | //Port.PortName = PortNumber; // Original ---Zitron 437 | 438 | j++; 439 | 440 | if (!Port.IsOpen) 441 | { 442 | try 443 | { 444 | Port.Open(); 445 | } 446 | catch (Exception e) 447 | { 448 | Debug.Log("Error opening serial port " + Win32PortName + ": " + e.Message); 449 | } 450 | 451 | //secret handshake 452 | if (Port.IsOpen && (SettingsNStuff.HandshakeDisable == 0)) 453 | { 454 | Thread.Sleep(SettingsNStuff.HandshakeDelay); 455 | //Port.DiscardOutBuffer(); 456 | //Port.DiscardInBuffer(); 457 | 458 | sendPacket(HPacket); 459 | 460 | //wait for reply 461 | int k = 0; 462 | 463 | while (Port.BytesToRead == 0 && k < 15 && !DisplayFound) 464 | { 465 | Thread.Sleep(100); 466 | k++; 467 | } 468 | 469 | Port.Close(); 470 | if (DisplayFound) 471 | { 472 | Debug.Log("KSPSerialIO: found KSP Display at " + Win32PortName); 473 | break; 474 | } 475 | else 476 | { 477 | Debug.Log("KSPSerialIO: KSP Display not found"); 478 | } 479 | } 480 | else if (Port.IsOpen && (SettingsNStuff.HandshakeDisable == 1)) 481 | { 482 | DisplayFound = true; 483 | Debug.Log("KSPSerialIO: Handshake disabled, using " + Win32PortName); 484 | break; 485 | } 486 | } 487 | else 488 | { 489 | Debug.Log("KSPSerialIO: " + Win32PortName + "is already being used."); 490 | } 491 | } 492 | } 493 | 494 | } 495 | catch (Exception e) 496 | { 497 | print(e.Message); 498 | } 499 | } 500 | } 501 | 502 | private string readline() 503 | { 504 | string result = null; 505 | char c; 506 | int j = 0; 507 | 508 | c = (char)Port.ReadByte(); 509 | while (c != '\n' && j < 255) 510 | { 511 | result += c; 512 | c = (char)Port.ReadByte(); 513 | j++; 514 | } 515 | return result; 516 | } 517 | 518 | private void Port_ReceivedEvent(object sender, SerialReceivedEventArgs e) 519 | { 520 | while (Port.BytesToRead > 0) 521 | { 522 | if (processCOM()) 523 | { 524 | switch (id) 525 | { 526 | case HSPid: 527 | HPacket = (HandShakePacket)ByteArrayToStructure(buffer, HPacket); 528 | Invoke("HandShake", 0); 529 | 530 | if ((HPacket.M1 == 3) && (HPacket.M2 == 1) && (HPacket.M3 == 4)) 531 | { 532 | DisplayFound = true; 533 | } 534 | 535 | else 536 | { 537 | DisplayFound = false; 538 | } 539 | break; 540 | case Cid: 541 | VesselControls(); 542 | //Invoke("VesselControls", 0); 543 | break; 544 | default: 545 | Invoke("Unimplemented", 0); 546 | break; 547 | } 548 | } 549 | } 550 | } 551 | 552 | private static bool processCOM() 553 | { 554 | byte calc_CS; 555 | 556 | if (rx_len == 0) 557 | { 558 | while (Port.ReadByte() != 0xBE) 559 | { 560 | if (Port.BytesToRead == 0) 561 | return false; 562 | } 563 | 564 | if (Port.ReadByte() == 0xEF) 565 | { 566 | rx_len = (byte)Port.ReadByte(); 567 | id = (byte)Port.ReadByte(); 568 | rx_array_inx = 1; 569 | 570 | switch (id) 571 | { 572 | case HSPid: 573 | structSize = Marshal.SizeOf(HPacket); 574 | break; 575 | case Cid: 576 | structSize = Marshal.SizeOf(CPacket); 577 | break; 578 | } 579 | 580 | //make sure the binary structs on both Arduino and plugin are the same size. 581 | if (rx_len != structSize || rx_len == 0) 582 | { 583 | SizeWrong(rx_len, structSize); //Debug option ================== 584 | rx_len = 0; 585 | return false; 586 | } 587 | } 588 | else 589 | { 590 | return false; 591 | } 592 | } 593 | else 594 | { 595 | while (Port.BytesToRead > 0 && rx_array_inx <= rx_len) 596 | { 597 | buffer[rx_array_inx++] = (byte)Port.ReadByte(); 598 | } 599 | buffer[0] = id; 600 | 601 | if (rx_len == (rx_array_inx - 1)) 602 | { 603 | //seem to have got whole message 604 | //last uint8_t is CS 605 | calc_CS = rx_len; 606 | for (int i = 0; i < rx_len; i++) 607 | { 608 | calc_CS ^= buffer[i]; 609 | } 610 | 611 | if (calc_CS == buffer[rx_array_inx - 1]) 612 | {//CS good 613 | rx_len = 0; 614 | rx_array_inx = 1; 615 | 616 | CheckSumPass(); //Debug option ================== 617 | return true; 618 | } 619 | else 620 | { 621 | //failed checksum, need to clear this out anyway 622 | rx_len = 0; 623 | rx_array_inx = 1; 624 | 625 | CheckSumFail(); //Debug option ================== 626 | return false; 627 | } 628 | } 629 | } 630 | 631 | return false; 632 | } 633 | 634 | private void HandShake() 635 | { 636 | Debug.Log("KSPSerialIO: Handshake received - " + HPacket.M1.ToString() + HPacket.M2.ToString() + HPacket.M3.ToString()); 637 | } 638 | 639 | private static void SizeWrong(int R, int P) 640 | { 641 | Debug.Log("KSPSerialIO: Packet Size ERROR - " + R.ToString() + "/" + P.ToString()); 642 | } 643 | 644 | private static void CheckSumFail() 645 | { 646 | Debug.Log("KSPSerialIO: CS FAIL - " + BitConverter.ToString(buffer)); 647 | } 648 | 649 | private static void CheckSumPass() 650 | { 651 | Debug.Log("KSPSerialIO: CS PASS - " + BitConverter.ToString(buffer)); 652 | } 653 | 654 | private void VesselControls() 655 | { 656 | CPacket = (ControlPacket)ByteArrayToStructure(buffer, CPacket); 657 | 658 | VControls.SAS = BitMathByte(CPacket.MainControls, 7); 659 | VControls.RCS = BitMathByte(CPacket.MainControls, 6); 660 | VControls.Lights = BitMathByte(CPacket.MainControls, 5); 661 | VControls.Gear = BitMathByte(CPacket.MainControls, 4); 662 | VControls.Brakes = BitMathByte(CPacket.MainControls, 3); 663 | VControls.Precision = BitMathByte(CPacket.MainControls, 2); 664 | VControls.Abort = BitMathByte(CPacket.MainControls, 1); 665 | VControls.Stage = BitMathByte(CPacket.MainControls, 0); 666 | VControls.Pitch = (float)CPacket.Pitch / 1000.0F; 667 | VControls.Roll = (float)CPacket.Roll / 1000.0F; 668 | VControls.Yaw = (float)CPacket.Yaw / 1000.0F; 669 | VControls.TX = (float)CPacket.TX / 1000.0F; 670 | VControls.TY = (float)CPacket.TY / 1000.0F; 671 | VControls.TZ = (float)CPacket.TZ / 1000.0F; 672 | VControls.WheelSteer = (float)CPacket.WheelSteer / 1000.0F; 673 | VControls.Throttle = (float)CPacket.Throttle / 1000.0F; 674 | VControls.WheelThrottle = (float)CPacket.WheelThrottle / 1000.0F; 675 | VControls.SASMode = (int)CPacket.NavballSASMode & 0x0F; 676 | VControls.SpeedMode = (int)(CPacket.NavballSASMode >> 4); 677 | 678 | for (int j = 1; j <= 10; j++) 679 | { 680 | VControls.ControlGroup[j] = BitMathUshort(CPacket.ControlGroup, j); 681 | } 682 | 683 | ControlReceived = true; 684 | //Debug.Log("KSPSerialIO: ControlPacket received"); 685 | } 686 | 687 | private Boolean BitMathByte(byte x, int n) 688 | { 689 | return ((x >> n) & 1) == 1; 690 | } 691 | 692 | private Boolean BitMathUshort(ushort x, int n) 693 | { 694 | return ((x >> n) & 1) == 1; 695 | } 696 | 697 | private void Unimplemented() 698 | { 699 | Debug.Log("KSPSerialIO: Packet id unimplemented"); 700 | } 701 | 702 | private static void debug() 703 | { 704 | Debug.Log(Port.BytesToRead.ToString() + "BTR"); 705 | } 706 | 707 | 708 | public static void ControlStatus(int n, bool s) 709 | { 710 | if (s) 711 | VData.ActionGroups |= (UInt16)(1 << n); // forces nth bit of x to be 1. all other bits left alone. 712 | else 713 | VData.ActionGroups &= (UInt16)~(1 << n); // forces nth bit of x to be 0. all other bits left alone. 714 | } 715 | 716 | void OnDestroy() 717 | { 718 | if (KSPSerialPort.Port.IsOpen) 719 | { 720 | KSPSerialPort.Port.Close(); 721 | Port.ReceivedEvent -= Port_ReceivedEvent; 722 | Debug.Log("KSPSerialIO: Port closed"); 723 | } 724 | } 725 | } 726 | 727 | [KSPAddon(KSPAddon.Startup.Flight, false)] 728 | public class KSPSerialIO : MonoBehaviour 729 | { 730 | private double lastUpdate = 0.0f; 731 | private double deltaT = 1.0f; 732 | private double missionTime = 0; 733 | private double missionTimeOld = 0; 734 | private double theTime = 0; 735 | 736 | public double refreshrate = 1.0f; 737 | public static Vessel ActiveVessel = new Vessel(); 738 | 739 | public Guid VesselIDOld; 740 | 741 | IOResource TempR = new IOResource(); 742 | 743 | private static Boolean wasSASOn = false; 744 | 745 | private ScreenMessageStyle KSPIOScreenStyle = ScreenMessageStyle.UPPER_RIGHT; 746 | 747 | void Awake() 748 | { 749 | ScreenMessages.PostScreenMessage("IO awake", 10f, KSPIOScreenStyle); 750 | refreshrate = SettingsNStuff.refreshrate; 751 | } 752 | 753 | void Start() 754 | { 755 | if (KSPSerialPort.DisplayFound) 756 | { 757 | if (!KSPSerialPort.Port.IsOpen) 758 | { 759 | ScreenMessages.PostScreenMessage("Starting serial port " + KSPSerialPort.Win32PortName, 10f, KSPIOScreenStyle); 760 | 761 | try 762 | { 763 | KSPSerialPort.Port.PortName = KSPSerialPort.Win32PortName; 764 | KSPSerialPort.Port.Open(); 765 | Thread.Sleep(SettingsNStuff.HandshakeDelay); 766 | } 767 | catch (Exception e) 768 | { 769 | ScreenMessages.PostScreenMessage("Error opening serial port " + KSPSerialPort.Win32PortName, 10f, KSPIOScreenStyle); 770 | ScreenMessages.PostScreenMessage(e.Message, 10f, KSPIOScreenStyle); 771 | } 772 | } 773 | else 774 | { 775 | ScreenMessages.PostScreenMessage("Using serial port " + KSPSerialPort.Win32PortName, 10f, KSPIOScreenStyle); 776 | 777 | if (SettingsNStuff.HandshakeDisable == 1) 778 | ScreenMessages.PostScreenMessage("Handshake disabled"); 779 | } 780 | 781 | Thread.Sleep(200); 782 | 783 | ActiveVessel.OnPostAutopilotUpdate -= AxisInput; 784 | ActiveVessel = FlightGlobals.ActiveVessel; 785 | ActiveVessel.OnPostAutopilotUpdate += AxisInput; 786 | 787 | //sync inputs at start 788 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.RCS, KSPSerialPort.VControls.RCS); 789 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.SAS, KSPSerialPort.VControls.SAS); 790 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Light, KSPSerialPort.VControls.Lights); 791 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Gear, KSPSerialPort.VControls.Gear); 792 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, KSPSerialPort.VControls.Brakes); 793 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Abort, KSPSerialPort.VControls.Abort); 794 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Stage, KSPSerialPort.VControls.Stage); 795 | 796 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Custom01, KSPSerialPort.VControls.ControlGroup[1]); 797 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Custom02, KSPSerialPort.VControls.ControlGroup[2]); 798 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Custom03, KSPSerialPort.VControls.ControlGroup[3]); 799 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Custom04, KSPSerialPort.VControls.ControlGroup[4]); 800 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Custom05, KSPSerialPort.VControls.ControlGroup[5]); 801 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Custom06, KSPSerialPort.VControls.ControlGroup[6]); 802 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Custom07, KSPSerialPort.VControls.ControlGroup[7]); 803 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Custom08, KSPSerialPort.VControls.ControlGroup[8]); 804 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Custom09, KSPSerialPort.VControls.ControlGroup[9]); 805 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Custom10, KSPSerialPort.VControls.ControlGroup[10]); 806 | 807 | /* 808 | ActiveVessel.OnFlyByWire -= new FlightInputCallback(AxisInput); 809 | ActiveVessel.OnFlyByWire += new FlightInputCallback(AxisInput); 810 | 811 | ActiveVessel.OnPostAutopilotUpdate -= AxisInput; 812 | ActiveVessel.OnPostAutopilotUpdate += AxisInput; 813 | */ 814 | } 815 | else 816 | { 817 | ScreenMessages.PostScreenMessage("No display found", 10f, KSPIOScreenStyle); 818 | } 819 | } 820 | 821 | void Update() 822 | { 823 | if (FlightGlobals.ActiveVessel != null && KSPSerialPort.Port.IsOpen) 824 | { 825 | //Debug.Log("KSPSerialIO: 1"); 826 | //If the current active vessel is not what we were using, we need to remove controls from the old 827 | //vessel and attache it to the current one 828 | if (ActiveVessel.id != FlightGlobals.ActiveVessel.id) 829 | { 830 | ActiveVessel.OnPostAutopilotUpdate -= AxisInput; 831 | ActiveVessel = FlightGlobals.ActiveVessel; 832 | ActiveVessel.OnPostAutopilotUpdate += AxisInput; 833 | //sync some inputs on vessel switch 834 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.RCS, KSPSerialPort.VControls.RCS); 835 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.SAS, KSPSerialPort.VControls.SAS); 836 | Debug.Log("KSPSerialIO: ActiveVessel changed"); 837 | } 838 | else 839 | { 840 | ActiveVessel = FlightGlobals.ActiveVessel; 841 | } 842 | 843 | #region outputs 844 | theTime = Time.unscaledTime; 845 | if ((theTime - lastUpdate) > refreshrate) 846 | { 847 | //Debug.Log("KSPSerialIO: 2"); 848 | 849 | lastUpdate = theTime; 850 | 851 | List ActiveEngines = new List(); 852 | ActiveEngines = GetListOfActivatedEngines(ActiveVessel); 853 | 854 | KSPSerialPort.VData.AP = (float)ActiveVessel.orbit.ApA; 855 | KSPSerialPort.VData.PE = (float)ActiveVessel.orbit.PeA; 856 | KSPSerialPort.VData.SemiMajorAxis = (float)ActiveVessel.orbit.semiMajorAxis; 857 | KSPSerialPort.VData.SemiMinorAxis = (float)ActiveVessel.orbit.semiMinorAxis; 858 | KSPSerialPort.VData.e = (float)ActiveVessel.orbit.eccentricity; 859 | KSPSerialPort.VData.inc = (float)ActiveVessel.orbit.inclination; 860 | KSPSerialPort.VData.VVI = (float)ActiveVessel.verticalSpeed; 861 | KSPSerialPort.VData.G = (float)ActiveVessel.geeForce; 862 | KSPSerialPort.VData.TAp = (int)Math.Round(ActiveVessel.orbit.timeToAp); 863 | KSPSerialPort.VData.TPe = (int)Math.Round(ActiveVessel.orbit.timeToPe); 864 | KSPSerialPort.VData.Density = (float)ActiveVessel.atmDensity; 865 | KSPSerialPort.VData.TrueAnomaly = (float)ActiveVessel.orbit.trueAnomaly; 866 | KSPSerialPort.VData.period = (int)Math.Round(ActiveVessel.orbit.period); 867 | 868 | //Debug.Log("KSPSerialIO: 3"); 869 | double ASL = ActiveVessel.mainBody.GetAltitude(ActiveVessel.CoM); 870 | double AGL = (ASL - ActiveVessel.terrainAltitude); 871 | 872 | if (AGL < ASL) 873 | KSPSerialPort.VData.RAlt = (float)AGL; 874 | else 875 | KSPSerialPort.VData.RAlt = (float)ASL; 876 | 877 | KSPSerialPort.VData.Alt = (float)ASL; 878 | KSPSerialPort.VData.Vsurf = (float)ActiveVessel.srfSpeed; 879 | KSPSerialPort.VData.Lat = (float)ActiveVessel.latitude; 880 | KSPSerialPort.VData.Lon = (float)ActiveVessel.longitude; 881 | 882 | TempR = GetResourceTotal(ActiveVessel, "LiquidFuel"); 883 | KSPSerialPort.VData.LiquidFuelTot = TempR.Max; 884 | KSPSerialPort.VData.LiquidFuel = TempR.Current; 885 | 886 | KSPSerialPort.VData.LiquidFuelTotS = (float)ProspectForResourceMax("LiquidFuel", ActiveEngines); 887 | KSPSerialPort.VData.LiquidFuelS = (float)ProspectForResource("LiquidFuel", ActiveEngines); 888 | 889 | TempR = GetResourceTotal(ActiveVessel, "Oxidizer"); 890 | KSPSerialPort.VData.OxidizerTot = TempR.Max; 891 | KSPSerialPort.VData.Oxidizer = TempR.Current; 892 | 893 | KSPSerialPort.VData.OxidizerTotS = (float)ProspectForResourceMax("Oxidizer", ActiveEngines); 894 | KSPSerialPort.VData.OxidizerS = (float)ProspectForResource("Oxidizer", ActiveEngines); 895 | 896 | TempR = GetResourceTotal(ActiveVessel, "ElectricCharge"); 897 | KSPSerialPort.VData.EChargeTot = TempR.Max; 898 | KSPSerialPort.VData.ECharge = TempR.Current; 899 | TempR = GetResourceTotal(ActiveVessel, "MonoPropellant"); 900 | KSPSerialPort.VData.MonoPropTot = TempR.Max; 901 | KSPSerialPort.VData.MonoProp = TempR.Current; 902 | TempR = GetResourceTotal(ActiveVessel, "IntakeAir"); 903 | KSPSerialPort.VData.IntakeAirTot = TempR.Max; 904 | KSPSerialPort.VData.IntakeAir = TempR.Current; 905 | TempR = GetResourceTotal(ActiveVessel, "SolidFuel"); 906 | KSPSerialPort.VData.SolidFuelTot = TempR.Max; 907 | KSPSerialPort.VData.SolidFuel = TempR.Current; 908 | TempR = GetResourceTotal(ActiveVessel, "XenonGas"); 909 | KSPSerialPort.VData.XenonGasTot = TempR.Max; 910 | KSPSerialPort.VData.XenonGas = TempR.Current; 911 | 912 | missionTime = ActiveVessel.missionTime; 913 | deltaT = missionTime - missionTimeOld; 914 | missionTimeOld = missionTime; 915 | 916 | KSPSerialPort.VData.MissionTime = (UInt32)Math.Round(missionTime); 917 | KSPSerialPort.VData.deltaTime = (float)deltaT; 918 | 919 | KSPSerialPort.VData.VOrbit = (float)ActiveVessel.orbit.GetVel().magnitude; 920 | 921 | KSPSerialPort.VData.MNTime = 0; 922 | KSPSerialPort.VData.MNDeltaV = 0; 923 | 924 | KSPSerialPort.VData.TargetDist = 0; 925 | KSPSerialPort.VData.TargetV = 0; 926 | 927 | //Debug.Log("KSPSerialIO: 5"); 928 | 929 | Vector3d CoM, north, up, east; 930 | Quaternion rotationSurface; 931 | CoM = ActiveVessel.CoM; 932 | up = (CoM - ActiveVessel.mainBody.position).normalized; 933 | north = Vector3d.Exclude(up, (ActiveVessel.mainBody.position + ActiveVessel.mainBody.transform.up * (float)ActiveVessel.mainBody.Radius) - CoM).normalized; 934 | east = Vector3d.Cross(up, north); 935 | rotationSurface = Quaternion.LookRotation(north, up); 936 | Vector3d attitude = Quaternion.Inverse(Quaternion.Euler(90, 0, 0) * Quaternion.Inverse(ActiveVessel.GetTransform().rotation) * rotationSurface).eulerAngles; 937 | 938 | KSPSerialPort.VData.Roll = (float)((attitude.z > 180) ? (attitude.z - 360.0) : attitude.z); 939 | KSPSerialPort.VData.Pitch = (float)((attitude.x > 180) ? (360.0 - attitude.x) : -attitude.x); 940 | KSPSerialPort.VData.Heading = (float)attitude.y; 941 | 942 | Vector3d prograde = new Vector3d(0, 0, 0); 943 | switch (FlightGlobals.speedDisplayMode) 944 | { 945 | case FlightGlobals.SpeedDisplayModes.Surface: 946 | prograde = ActiveVessel.srf_velocity.normalized; 947 | break; 948 | case FlightGlobals.SpeedDisplayModes.Orbit: 949 | prograde = ActiveVessel.obt_velocity.normalized; 950 | break; 951 | case FlightGlobals.SpeedDisplayModes.Target: 952 | prograde = FlightGlobals.ship_tgtVelocity; 953 | break; 954 | } 955 | 956 | NavHeading zeroHeading; zeroHeading.Pitch = zeroHeading.Heading = 0; 957 | NavHeading Prograde = WorldVecToNavHeading(up, north, east, prograde), Target = zeroHeading, Maneuver = zeroHeading; 958 | 959 | KSPSerialPort.VData.ProgradeHeading = FloatAngleToFixed_16(Prograde.Heading); 960 | KSPSerialPort.VData.ProgradePitch = FloatAngleToFixed_16(Prograde.Pitch); 961 | 962 | if (TargetExists()) 963 | { 964 | KSPSerialPort.VData.TargetDist = (float)Vector3.Distance(FlightGlobals.fetch.VesselTarget.GetVessel().transform.position, ActiveVessel.transform.position); 965 | KSPSerialPort.VData.TargetV = (float)FlightGlobals.ship_tgtVelocity.magnitude; 966 | Target = WorldVecToNavHeading(up, north, east, ActiveVessel.targetObject.GetTransform().position - ActiveVessel.transform.position); 967 | } 968 | KSPSerialPort.VData.TargetHeading = FloatAngleToFixed_16(Target.Heading); 969 | KSPSerialPort.VData.TargetPitch = FloatAngleToFixed_16(Target.Pitch); 970 | 971 | KSPSerialPort.VData.NormalHeading = FloatAngleToFixed_16(WorldVecToNavHeading(up, north, east, Vector3d.Cross(ActiveVessel.obt_velocity.normalized, up)).Heading); 972 | 973 | if (ActiveVessel.patchedConicSolver != null) 974 | { 975 | if (ActiveVessel.patchedConicSolver.maneuverNodes != null) 976 | { 977 | if (ActiveVessel.patchedConicSolver.maneuverNodes.Count > 0) 978 | { 979 | KSPSerialPort.VData.MNTime = (UInt32)Math.Round(ActiveVessel.patchedConicSolver.maneuverNodes[0].UT - Planetarium.GetUniversalTime()); 980 | KSPSerialPort.VData.MNDeltaV = (float)ActiveVessel.patchedConicSolver.maneuverNodes[0].GetBurnVector(ActiveVessel.patchedConicSolver.maneuverNodes[0].patch).magnitude; //Added JS 981 | 982 | Maneuver = WorldVecToNavHeading(up, north, east, ActiveVessel.patchedConicSolver.maneuverNodes[0].GetBurnVector(ActiveVessel.patchedConicSolver.maneuverNodes[0].patch)); 983 | } 984 | } 985 | } 986 | KSPSerialPort.VData.ManeuverHeading = FloatAngleToFixed_16(Maneuver.Heading); 987 | KSPSerialPort.VData.ManeuverPitch = FloatAngleToFixed_16(Maneuver.Pitch); 988 | 989 | KSPSerialPort.ControlStatus((int)enumAG.SAS, ActiveVessel.ActionGroups[KSPActionGroup.SAS]); 990 | KSPSerialPort.ControlStatus((int)enumAG.RCS, ActiveVessel.ActionGroups[KSPActionGroup.RCS]); 991 | KSPSerialPort.ControlStatus((int)enumAG.Light, ActiveVessel.ActionGroups[KSPActionGroup.Light]); 992 | KSPSerialPort.ControlStatus((int)enumAG.Gear, ActiveVessel.ActionGroups[KSPActionGroup.Gear]); 993 | KSPSerialPort.ControlStatus((int)enumAG.Brakes, ActiveVessel.ActionGroups[KSPActionGroup.Brakes]); 994 | KSPSerialPort.ControlStatus((int)enumAG.Abort, ActiveVessel.ActionGroups[KSPActionGroup.Abort]); 995 | KSPSerialPort.ControlStatus((int)enumAG.Custom01, ActiveVessel.ActionGroups[KSPActionGroup.Custom01]); 996 | KSPSerialPort.ControlStatus((int)enumAG.Custom02, ActiveVessel.ActionGroups[KSPActionGroup.Custom02]); 997 | KSPSerialPort.ControlStatus((int)enumAG.Custom03, ActiveVessel.ActionGroups[KSPActionGroup.Custom03]); 998 | KSPSerialPort.ControlStatus((int)enumAG.Custom04, ActiveVessel.ActionGroups[KSPActionGroup.Custom04]); 999 | KSPSerialPort.ControlStatus((int)enumAG.Custom05, ActiveVessel.ActionGroups[KSPActionGroup.Custom05]); 1000 | KSPSerialPort.ControlStatus((int)enumAG.Custom06, ActiveVessel.ActionGroups[KSPActionGroup.Custom06]); 1001 | KSPSerialPort.ControlStatus((int)enumAG.Custom07, ActiveVessel.ActionGroups[KSPActionGroup.Custom07]); 1002 | KSPSerialPort.ControlStatus((int)enumAG.Custom08, ActiveVessel.ActionGroups[KSPActionGroup.Custom08]); 1003 | KSPSerialPort.ControlStatus((int)enumAG.Custom09, ActiveVessel.ActionGroups[KSPActionGroup.Custom09]); 1004 | KSPSerialPort.ControlStatus((int)enumAG.Custom10, ActiveVessel.ActionGroups[KSPActionGroup.Custom10]); 1005 | 1006 | if (ActiveVessel.orbit.referenceBody != null) 1007 | { 1008 | KSPSerialPort.VData.SOINumber = GetSOINumber(ActiveVessel.orbit.referenceBody.name); 1009 | } 1010 | 1011 | KSPSerialPort.VData.MaxOverHeat = GetMaxOverHeat(ActiveVessel); 1012 | KSPSerialPort.VData.MachNumber = (float)ActiveVessel.mach; 1013 | KSPSerialPort.VData.IAS = (float)ActiveVessel.indicatedAirSpeed; 1014 | 1015 | KSPSerialPort.VData.CurrentStage = (byte)StageManager.CurrentStage; 1016 | KSPSerialPort.VData.TotalStage = (byte)StageManager.StageCount; 1017 | 1018 | KSPSerialPort.VData.NavballSASMode = (byte)(((int)FlightGlobals.speedDisplayMode + 1) << 4); //get navball speed display mode 1019 | if (ActiveVessel.ActionGroups[KSPActionGroup.SAS]) 1020 | { 1021 | KSPSerialPort.VData.NavballSASMode = (byte)(((int)FlightGlobals.ActiveVessel.Autopilot.Mode + 1) | KSPSerialPort.VData.NavballSASMode); 1022 | } 1023 | 1024 | #region debugjunk 1025 | 1026 | /* 1027 | Debug.Log("KSPSerialIO: Stage " + KSPSerialPort.VData.CurrentStage.ToString() + ' ' + 1028 | KSPSerialPort.VData.TotalStage.ToString()); 1029 | Debug.Log("KSPSerialIO: Overheat " + KSPSerialPort.VData.MaxOverHeat.ToString()); 1030 | Debug.Log("KSPSerialIO: Mach " + KSPSerialPort.VData.MachNumber.ToString()); 1031 | Debug.Log("KSPSerialIO: IAS " + KSPSerialPort.VData.IAS.ToString()); 1032 | 1033 | Debug.Log("KSPSerialIO: SOI " + ActiveVessel.orbit.referenceBody.name + KSPSerialPort.VData.SOINumber.ToString()); 1034 | 1035 | ScreenMessages.PostScreenMessage(KSPSerialPort.VData.OxidizerS.ToString() + "/" + KSPSerialPort.VData.OxidizerTotS + 1036 | " " + KSPSerialPort.VData.Oxidizer.ToString() + "/" + KSPSerialPort.VData.OxidizerTot); 1037 | */ 1038 | //KSPSerialPort.VData.Roll = Mathf.Atan2(2 * (x * y + w * z), w * w + x * x - y * y - z * z) * 180 / Mathf.PI; 1039 | //KSPSerialPort.VData.Pitch = Mathf.Atan2(2 * (y * z + w * x), w * w - x * x - y * y + z * z) * 180 / Mathf.PI; 1040 | //KSPSerialPort.VData.Heading = Mathf.Asin(-2 * (x * z - w * y)) *180 / Mathf.PI; 1041 | //Debug.Log("KSPSerialIO: Roll " + KSPSerialPort.VData.Roll.ToString()); 1042 | //Debug.Log("KSPSerialIO: Pitch " + KSPSerialPort.VData.Pitch.ToString()); 1043 | //Debug.Log("KSPSerialIO: Heading " + KSPSerialPort.VData.Heading.ToString()); 1044 | //Debug.Log("KSPSerialIO: VOrbit" + KSPSerialPort.VData.VOrbit.ToString()); 1045 | //ScreenMessages.PostScreenMessage(ActiveVessel.ActionGroups[KSPActionGroup.RCS].ToString()); 1046 | //Debug.Log("KSPSerialIO: MNTime" + KSPSerialPort.VData.MNTime.ToString() + " MNDeltaV" + KSPSerialPort.VData.MNDeltaV.ToString()); 1047 | //Debug.Log("KSPSerialIO: Time" + KSPSerialPort.VData.MissionTime.ToString() + " Delta Time" + KSPSerialPort.VData.deltaTime.ToString()); 1048 | //Debug.Log("KSPSerialIO: Throttle = " + KSPSerialPort.CPacket.Throttle.ToString()); 1049 | //ScreenMessages.PostScreenMessage(KSPSerialPort.VData.Fuelp.ToString()); 1050 | //ScreenMessages.PostScreenMessage(KSPSerialPort.VData.RAlt.ToString()); 1051 | //KSPSerialPort.Port.WriteLine("Success!"); 1052 | /* 1053 | ScreenMessages.PostScreenMessage(KSPSerialPort.VData.LiquidFuelS.ToString() + "/" + KSPSerialPort.VData.LiquidFuelTotS + 1054 | " " + KSPSerialPort.VData.LiquidFuel.ToString() + "/" + KSPSerialPort.VData.LiquidFuelTot); 1055 | 1056 | ScreenMessages.PostScreenMessage("MNTime " + KSPSerialPort.VData.MNTime.ToString() + " MNDeltaV " + KSPSerialPort.VData.MNDeltaV.ToString()); 1057 | ScreenMessages.PostScreenMessage("TargetDist " + KSPSerialPort.VData.TargetDist.ToString() + " TargetV " + KSPSerialPort.VData.TargetV.ToString()); 1058 | */ 1059 | #endregion 1060 | KSPSerialPort.sendPacket(KSPSerialPort.VData); 1061 | } //end refresh 1062 | #endregion 1063 | #region inputs 1064 | if (KSPSerialPort.ControlReceived) 1065 | { 1066 | /* 1067 | ScreenMessages.PostScreenMessage("Nav Mode " + KSPSerialPort.CPacket.NavballSASMode.ToString()); 1068 | 1069 | ScreenMessages.PostScreenMessage("SAS: " + KSPSerialPort.VControls.SAS.ToString() + 1070 | ", RCS: " + KSPSerialPort.VControls.RCS.ToString() + 1071 | ", Lights: " + KSPSerialPort.VControls.Lights.ToString() + 1072 | ", Gear: " + KSPSerialPort.VControls.Gear.ToString() + 1073 | ", Brakes: " + KSPSerialPort.VControls.Brakes.ToString() + 1074 | ", Precision: " + KSPSerialPort.VControls.Precision.ToString() + 1075 | ", Abort: " + KSPSerialPort.VControls.Abort.ToString() + 1076 | ", Stage: " + KSPSerialPort.VControls.Stage.ToString(), 10f, KSPIOScreenStyle); 1077 | 1078 | Debug.Log("KSPSerialIO: SAS: " + KSPSerialPort.VControls.SAS.ToString() + 1079 | ", RCS: " + KSPSerialPort.VControls.RCS.ToString() + 1080 | ", Lights: " + KSPSerialPort.VControls.Lights.ToString() + 1081 | ", Gear: " + KSPSerialPort.VControls.Gear.ToString() + 1082 | ", Brakes: " + KSPSerialPort.VControls.Brakes.ToString() + 1083 | ", Precision: " + KSPSerialPort.VControls.Precision.ToString() + 1084 | ", Abort: " + KSPSerialPort.VControls.Abort.ToString() + 1085 | ", Stage: " + KSPSerialPort.VControls.Stage.ToString()); 1086 | */ 1087 | 1088 | //if (FlightInputHandler.RCSLock != KSPSerialPort.VControls.RCS) 1089 | if (KSPSerialPort.VControls.RCS != KSPSerialPort.VControlsOld.RCS) 1090 | { 1091 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.RCS, KSPSerialPort.VControls.RCS); 1092 | KSPSerialPort.VControlsOld.RCS = KSPSerialPort.VControls.RCS; 1093 | //ScreenMessages.PostScreenMessage("RCS: " + KSPSerialPort.VControls.RCS.ToString(), 10f, KSPIOScreenStyle); 1094 | } 1095 | 1096 | //if (ActiveVessel.ctrlState.killRot != KSPSerialPort.VControls.SAS) 1097 | if (KSPSerialPort.VControls.SAS != KSPSerialPort.VControlsOld.SAS) 1098 | { 1099 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.SAS, KSPSerialPort.VControls.SAS); 1100 | KSPSerialPort.VControlsOld.SAS = KSPSerialPort.VControls.SAS; 1101 | //ScreenMessages.PostScreenMessage("SAS: " + KSPSerialPort.VControls.SAS.ToString(), 10f, KSPIOScreenStyle); 1102 | } 1103 | 1104 | if (KSPSerialPort.VControls.Lights != KSPSerialPort.VControlsOld.Lights) 1105 | { 1106 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Light, KSPSerialPort.VControls.Lights); 1107 | KSPSerialPort.VControlsOld.Lights = KSPSerialPort.VControls.Lights; 1108 | } 1109 | 1110 | if (KSPSerialPort.VControls.Gear != KSPSerialPort.VControlsOld.Gear) 1111 | { 1112 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Gear, KSPSerialPort.VControls.Gear); 1113 | KSPSerialPort.VControlsOld.Gear = KSPSerialPort.VControls.Gear; 1114 | } 1115 | 1116 | if (KSPSerialPort.VControls.Brakes != KSPSerialPort.VControlsOld.Brakes) 1117 | { 1118 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, KSPSerialPort.VControls.Brakes); 1119 | KSPSerialPort.VControlsOld.Brakes = KSPSerialPort.VControls.Brakes; 1120 | } 1121 | 1122 | if (KSPSerialPort.VControls.Abort != KSPSerialPort.VControlsOld.Abort) 1123 | { 1124 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Abort, KSPSerialPort.VControls.Abort); 1125 | KSPSerialPort.VControlsOld.Abort = KSPSerialPort.VControls.Abort; 1126 | } 1127 | 1128 | if (KSPSerialPort.VControls.Stage != KSPSerialPort.VControlsOld.Stage) 1129 | { 1130 | if (KSPSerialPort.VControls.Stage) 1131 | StageManager.ActivateNextStage(); 1132 | 1133 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Stage, KSPSerialPort.VControls.Stage); 1134 | KSPSerialPort.VControlsOld.Stage = KSPSerialPort.VControls.Stage; 1135 | } 1136 | 1137 | //================ control groups 1138 | 1139 | if (KSPSerialPort.VControls.ControlGroup[1] != KSPSerialPort.VControlsOld.ControlGroup[1]) 1140 | { 1141 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Custom01, KSPSerialPort.VControls.ControlGroup[1]); 1142 | KSPSerialPort.VControlsOld.ControlGroup[1] = KSPSerialPort.VControls.ControlGroup[1]; 1143 | } 1144 | 1145 | if (KSPSerialPort.VControls.ControlGroup[2] != KSPSerialPort.VControlsOld.ControlGroup[2]) 1146 | { 1147 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Custom02, KSPSerialPort.VControls.ControlGroup[2]); 1148 | KSPSerialPort.VControlsOld.ControlGroup[2] = KSPSerialPort.VControls.ControlGroup[2]; 1149 | } 1150 | 1151 | if (KSPSerialPort.VControls.ControlGroup[3] != KSPSerialPort.VControlsOld.ControlGroup[3]) 1152 | { 1153 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Custom03, KSPSerialPort.VControls.ControlGroup[3]); 1154 | KSPSerialPort.VControlsOld.ControlGroup[3] = KSPSerialPort.VControls.ControlGroup[3]; 1155 | } 1156 | 1157 | if (KSPSerialPort.VControls.ControlGroup[4] != KSPSerialPort.VControlsOld.ControlGroup[4]) 1158 | { 1159 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Custom04, KSPSerialPort.VControls.ControlGroup[4]); 1160 | KSPSerialPort.VControlsOld.ControlGroup[4] = KSPSerialPort.VControls.ControlGroup[4]; 1161 | } 1162 | 1163 | if (KSPSerialPort.VControls.ControlGroup[5] != KSPSerialPort.VControlsOld.ControlGroup[5]) 1164 | { 1165 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Custom05, KSPSerialPort.VControls.ControlGroup[5]); 1166 | KSPSerialPort.VControlsOld.ControlGroup[5] = KSPSerialPort.VControls.ControlGroup[5]; 1167 | } 1168 | 1169 | if (KSPSerialPort.VControls.ControlGroup[6] != KSPSerialPort.VControlsOld.ControlGroup[6]) 1170 | { 1171 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Custom06, KSPSerialPort.VControls.ControlGroup[6]); 1172 | KSPSerialPort.VControlsOld.ControlGroup[6] = KSPSerialPort.VControls.ControlGroup[6]; 1173 | } 1174 | 1175 | if (KSPSerialPort.VControls.ControlGroup[7] != KSPSerialPort.VControlsOld.ControlGroup[7]) 1176 | { 1177 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Custom07, KSPSerialPort.VControls.ControlGroup[7]); 1178 | KSPSerialPort.VControlsOld.ControlGroup[7] = KSPSerialPort.VControls.ControlGroup[7]; 1179 | } 1180 | 1181 | if (KSPSerialPort.VControls.ControlGroup[8] != KSPSerialPort.VControlsOld.ControlGroup[8]) 1182 | { 1183 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Custom08, KSPSerialPort.VControls.ControlGroup[8]); 1184 | KSPSerialPort.VControlsOld.ControlGroup[8] = KSPSerialPort.VControls.ControlGroup[8]; 1185 | } 1186 | 1187 | if (KSPSerialPort.VControls.ControlGroup[9] != KSPSerialPort.VControlsOld.ControlGroup[9]) 1188 | { 1189 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Custom09, KSPSerialPort.VControls.ControlGroup[9]); 1190 | KSPSerialPort.VControlsOld.ControlGroup[9] = KSPSerialPort.VControls.ControlGroup[9]; 1191 | } 1192 | 1193 | if (KSPSerialPort.VControls.ControlGroup[10] != KSPSerialPort.VControlsOld.ControlGroup[10]) 1194 | { 1195 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.Custom10, KSPSerialPort.VControls.ControlGroup[10]); 1196 | KSPSerialPort.VControlsOld.ControlGroup[10] = KSPSerialPort.VControls.ControlGroup[10]; 1197 | } 1198 | 1199 | //Set sas mode 1200 | if (KSPSerialPort.VControls.SASMode != KSPSerialPort.VControlsOld.SASMode) 1201 | { 1202 | if (KSPSerialPort.VControls.SASMode != 0 && KSPSerialPort.VControls.SASMode < 11) 1203 | { 1204 | if (!ActiveVessel.Autopilot.CanSetMode((VesselAutopilot.AutopilotMode)(KSPSerialPort.VControls.SASMode - 1))) 1205 | { 1206 | ScreenMessages.PostScreenMessage("KSPSerialIO: SAS mode " + KSPSerialPort.VControls.SASMode.ToString() + " not avalible"); 1207 | } 1208 | else 1209 | { 1210 | ActiveVessel.Autopilot.SetMode((VesselAutopilot.AutopilotMode)KSPSerialPort.VControls.SASMode - 1); 1211 | } 1212 | } 1213 | KSPSerialPort.VControlsOld.SASMode = KSPSerialPort.VControls.SASMode; 1214 | } 1215 | 1216 | //set navball mode 1217 | if (KSPSerialPort.VControls.SpeedMode != KSPSerialPort.VControlsOld.SpeedMode) 1218 | { 1219 | if (!((KSPSerialPort.VControls.SpeedMode == 0) || ((KSPSerialPort.VControls.SpeedMode == 3) && !TargetExists()))) 1220 | { 1221 | FlightGlobals.SetSpeedMode((FlightGlobals.SpeedDisplayModes)(KSPSerialPort.VControls.SpeedMode - 1)); 1222 | } 1223 | KSPSerialPort.VControlsOld.SpeedMode = KSPSerialPort.VControls.SpeedMode; 1224 | } 1225 | 1226 | 1227 | /* Getting rid of this per c4ooo suggestions 1228 | if (Math.Abs(KSPSerialPort.VControls.Pitch) > SettingsNStuff.SASTol || 1229 | Math.Abs(KSPSerialPort.VControls.Roll) > SettingsNStuff.SASTol || 1230 | Math.Abs(KSPSerialPort.VControls.Yaw) > SettingsNStuff.SASTol) 1231 | { 1232 | //ActiveVessel.Autopilot.SAS.ManualOverride(true); 1233 | 1234 | if ((ActiveVessel.ActionGroups[KSPActionGroup.SAS]) && (wasSASOn == false)) 1235 | { 1236 | wasSASOn = true; 1237 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.SAS, false); 1238 | } 1239 | 1240 | //ScreenMessages.PostScreenMessage("KSPSerialIO: SAS mode " + wasSASOn); 1241 | 1242 | 1243 | //if (wasSASOn == true) 1244 | //{ 1245 | //ActiveVessel.Autopilot.SAS.lockedMode = false; 1246 | //ActiveVessel.Autopilot.SAS.dampingMode = true; 1247 | //} 1248 | 1249 | 1250 | //if (KSPSerialPort.VControls.SAS == true) 1251 | //{ 1252 | // KSPSerialPort.VControls.SAS = false; 1253 | // KSPSerialPort.VControlsOld.SAS = false; 1254 | //} 1255 | 1256 | //KSPSerialPort.VControlsOld.Pitch = KSPSerialPort.VControls.Pitch; 1257 | //KSPSerialPort.VControlsOld.Roll = KSPSerialPort.VControls.Roll; 1258 | //KSPSerialPort.VControlsOld.Yaw = KSPSerialPort.VControls.Yaw; 1259 | } 1260 | else 1261 | { 1262 | if (wasSASOn == true) 1263 | { 1264 | wasSASOn = false; 1265 | ActiveVessel.ActionGroups.SetGroup(KSPActionGroup.SAS, true); 1266 | //ActiveVessel.Autopilot.SAS.lockedMode = true; 1267 | //ActiveVessel.Autopilot.SAS.dampingMode = false; 1268 | } 1269 | } 1270 | */ 1271 | 1272 | 1273 | KSPSerialPort.ControlReceived = false; 1274 | } //end ControlReceived 1275 | #endregion 1276 | 1277 | 1278 | }//end if null and same vessel 1279 | else 1280 | { 1281 | //Debug.Log("KSPSerialIO: ActiveVessel not found"); 1282 | //ActiveVessel.OnFlyByWire -= new FlightInputCallback(AxisInput); 1283 | } 1284 | 1285 | } 1286 | 1287 | #region utilities 1288 | 1289 | //lazy version 1290 | private static short FloatAngleToFixed_16(float f) //convert a number in the range of [-360,360) to [-0x8000,0x7FFF) 1291 | { 1292 | return (short)Math.Round(f * 50.0f); 1293 | } 1294 | 1295 | /* 1296 | private static short FloatAngleToFixed_16(float f) //convert a number in the range of [-360,360) to [-0x8000,0x7FFF) 1297 | { 1298 | return (short)(((int)(f / 360.0f * (float)(0x8000))) & 0xFFFF); 1299 | } 1300 | */ 1301 | private static NavHeading WorldVecToNavHeading(Vector3d up, Vector3d north, Vector3d east, Vector3d v) 1302 | { 1303 | NavHeading ret = new NavHeading(); 1304 | ret.Pitch = (float)-((Vector3d.Angle(up, v)) - 90.0f); 1305 | Vector3d progradeFlat = Vector3d.Exclude(up, v); 1306 | float NAngle = (float)Vector3d.Angle(north, progradeFlat); 1307 | float EAngle = (float)Vector3d.Angle(east, progradeFlat); 1308 | if (EAngle < 90) 1309 | ret.Heading = NAngle; 1310 | else 1311 | ret.Heading = -NAngle + 360; 1312 | return ret; 1313 | } 1314 | 1315 | private Boolean TargetExists() 1316 | { 1317 | return (FlightGlobals.fetch.VesselTarget != null) && (FlightGlobals.fetch.VesselTarget.GetVessel() != null); //&& is short circuiting 1318 | } 1319 | 1320 | private byte GetMaxOverHeat(Vessel V) 1321 | { 1322 | byte percent = 0; 1323 | double sPercent = 0, iPercent = 0; 1324 | double percentD = 0, percentP = 0; 1325 | 1326 | foreach (Part p in ActiveVessel.parts) 1327 | { 1328 | //internal temperature 1329 | iPercent = p.temperature / p.maxTemp; 1330 | //skin temperature 1331 | sPercent = p.skinTemperature / p.skinMaxTemp; 1332 | 1333 | if (iPercent > sPercent) 1334 | percentP = iPercent; 1335 | else 1336 | percentP = sPercent; 1337 | 1338 | if (percentD < percentP) 1339 | percentD = percentP; 1340 | } 1341 | 1342 | percent = (byte)Math.Round(percentD * 100); 1343 | return percent; 1344 | } 1345 | 1346 | 1347 | private IOResource GetResourceTotal(Vessel V, string resourceName) 1348 | { 1349 | IOResource R = new IOResource(); 1350 | 1351 | foreach (Part p in V.parts) 1352 | { 1353 | foreach (PartResource pr in p.Resources) 1354 | { 1355 | if (pr.resourceName.Equals(resourceName)) 1356 | { 1357 | R.Current += (float)pr.amount; 1358 | R.Max += (float)pr.maxAmount; 1359 | 1360 | /* shit doesn't work 1361 | int stageno = p.inverseStage; 1362 | 1363 | Debug.Log(pr.resourceName + " " + stageno.ToString() + " " + Staging.CurrentStage.ToString()); 1364 | //if (p.inverseStage == Staging.CurrentStage + 1) 1365 | if (stageno == Staging.CurrentStage) 1366 | { 1367 | R.CurrentStage += (float)pr.amount; 1368 | R.MaxStage += (float)pr.maxAmount; 1369 | } 1370 | */ 1371 | break; 1372 | } 1373 | } 1374 | } 1375 | 1376 | if (R.Max == 0) 1377 | R.Current = 0; 1378 | 1379 | return R; 1380 | } 1381 | 1382 | private void AxisInput(FlightCtrlState s) 1383 | { 1384 | switch (SettingsNStuff.ThrottleEnable) 1385 | { 1386 | case 1: 1387 | s.mainThrottle = KSPSerialPort.VControls.Throttle; 1388 | break; 1389 | case 2: 1390 | if (s.mainThrottle == 0) 1391 | { 1392 | s.mainThrottle = KSPSerialPort.VControls.Throttle; 1393 | } 1394 | break; 1395 | case 3: 1396 | if (KSPSerialPort.VControls.Throttle != 0) 1397 | { 1398 | s.mainThrottle = KSPSerialPort.VControls.Throttle; 1399 | } 1400 | break; 1401 | default: 1402 | break; 1403 | } 1404 | 1405 | switch (SettingsNStuff.PitchEnable) 1406 | { 1407 | case 1: 1408 | s.pitch = KSPSerialPort.VControls.Pitch; 1409 | break; 1410 | case 2: 1411 | if (s.pitch == 0) 1412 | s.pitch = KSPSerialPort.VControls.Pitch; 1413 | break; 1414 | case 3: 1415 | if (KSPSerialPort.VControls.Pitch != 0) 1416 | s.pitch = KSPSerialPort.VControls.Pitch; 1417 | break; 1418 | default: 1419 | break; 1420 | } 1421 | 1422 | switch (SettingsNStuff.RollEnable) 1423 | { 1424 | case 1: 1425 | s.roll = KSPSerialPort.VControls.Roll; 1426 | break; 1427 | case 2: 1428 | if (s.roll == 0) 1429 | s.roll = KSPSerialPort.VControls.Roll; 1430 | break; 1431 | case 3: 1432 | if (KSPSerialPort.VControls.Roll != 0) 1433 | s.roll = KSPSerialPort.VControls.Roll; 1434 | break; 1435 | default: 1436 | break; 1437 | } 1438 | 1439 | switch (SettingsNStuff.YawEnable) 1440 | { 1441 | case 1: 1442 | s.yaw = KSPSerialPort.VControls.Yaw; 1443 | break; 1444 | case 2: 1445 | if (s.yaw == 0) 1446 | s.yaw = KSPSerialPort.VControls.Yaw; 1447 | break; 1448 | case 3: 1449 | if (KSPSerialPort.VControls.Yaw != 0) 1450 | s.yaw = KSPSerialPort.VControls.Yaw; 1451 | break; 1452 | default: 1453 | break; 1454 | } 1455 | /* 1456 | if (ActiveVessel.Autopilot.SAS.lockedMode == true) 1457 | { 1458 | } 1459 | */ 1460 | switch (SettingsNStuff.TXEnable) 1461 | { 1462 | case 1: 1463 | s.X = KSPSerialPort.VControls.TX; 1464 | break; 1465 | case 2: 1466 | if (s.X == 0) 1467 | s.X = KSPSerialPort.VControls.TX; 1468 | break; 1469 | case 3: 1470 | if (KSPSerialPort.VControls.TX != 0) 1471 | s.X = KSPSerialPort.VControls.TX; 1472 | break; 1473 | default: 1474 | break; 1475 | } 1476 | 1477 | switch (SettingsNStuff.TYEnable) 1478 | { 1479 | case 1: 1480 | s.Y = KSPSerialPort.VControls.TY; 1481 | break; 1482 | case 2: 1483 | if (s.Y == 0) 1484 | s.Y = KSPSerialPort.VControls.TY; 1485 | break; 1486 | case 3: 1487 | if (KSPSerialPort.VControls.TY != 0) 1488 | s.Y = KSPSerialPort.VControls.TY; 1489 | break; 1490 | default: 1491 | break; 1492 | } 1493 | 1494 | switch (SettingsNStuff.TZEnable) 1495 | { 1496 | case 1: 1497 | s.Z = KSPSerialPort.VControls.TZ; 1498 | break; 1499 | case 2: 1500 | if (s.Z == 0) 1501 | s.Z = KSPSerialPort.VControls.TZ; 1502 | break; 1503 | case 3: 1504 | if (KSPSerialPort.VControls.TZ != 0) 1505 | s.Z = KSPSerialPort.VControls.TZ; 1506 | break; 1507 | default: 1508 | break; 1509 | } 1510 | 1511 | switch (SettingsNStuff.WheelSteerEnable) 1512 | { 1513 | case 1: 1514 | s.wheelSteer = KSPSerialPort.VControls.WheelSteer; 1515 | break; 1516 | case 2: 1517 | if (s.wheelSteer == 0) 1518 | { 1519 | s.wheelSteer = KSPSerialPort.VControls.WheelSteer; 1520 | } 1521 | break; 1522 | case 3: 1523 | if (KSPSerialPort.VControls.WheelSteer != 0) 1524 | { 1525 | s.wheelSteer = KSPSerialPort.VControls.WheelSteer; 1526 | } 1527 | break; 1528 | default: 1529 | break; 1530 | } 1531 | 1532 | switch (SettingsNStuff.WheelThrottleEnable) 1533 | { 1534 | case 1: 1535 | s.wheelThrottle = KSPSerialPort.VControls.WheelThrottle; 1536 | break; 1537 | case 2: 1538 | if (s.wheelThrottle == 0) 1539 | { 1540 | s.wheelThrottle = KSPSerialPort.VControls.WheelThrottle; 1541 | } 1542 | break; 1543 | case 3: 1544 | if (KSPSerialPort.VControls.WheelThrottle != 0) 1545 | { 1546 | s.wheelThrottle = KSPSerialPort.VControls.WheelThrottle; 1547 | } 1548 | break; 1549 | default: 1550 | break; 1551 | } 1552 | } 1553 | 1554 | private byte GetSOINumber(string name) 1555 | { 1556 | byte SOI; 1557 | 1558 | switch (name.ToLower()) 1559 | { 1560 | case "sun": 1561 | SOI = 100; 1562 | break; 1563 | case "moho": 1564 | SOI = 110; 1565 | break; 1566 | case "eve": 1567 | SOI = 120; 1568 | break; 1569 | case "gilly": 1570 | SOI = 121; 1571 | break; 1572 | case "kerbin": 1573 | SOI = 130; 1574 | break; 1575 | case "mun": 1576 | SOI = 131; 1577 | break; 1578 | case "minmus": 1579 | SOI = 132; 1580 | break; 1581 | case "duna": 1582 | SOI = 140; 1583 | break; 1584 | case "ike": 1585 | SOI = 141; 1586 | break; 1587 | case "dres": 1588 | SOI = 150; 1589 | break; 1590 | case "jool": 1591 | SOI = 160; 1592 | break; 1593 | case "laythe": 1594 | SOI = 161; 1595 | break; 1596 | case "vall": 1597 | SOI = 162; 1598 | break; 1599 | case "tylo": 1600 | SOI = 163; 1601 | break; 1602 | case "bop": 1603 | SOI = 164; 1604 | break; 1605 | case "pol": 1606 | SOI = 165; 1607 | break; 1608 | case "eeloo": 1609 | SOI = 170; 1610 | break; 1611 | default: 1612 | SOI = 0; 1613 | break; 1614 | } 1615 | return SOI; 1616 | } 1617 | 1618 | // this recursive stage look up stuff stolen and modified from KOS and others 1619 | public static List GetListOfActivatedEngines(Vessel vessel) 1620 | { 1621 | var retList = new List(); 1622 | 1623 | foreach (var part in vessel.Parts) 1624 | { 1625 | foreach (PartModule module in part.Modules) 1626 | { 1627 | var engineModule = module as ModuleEngines; 1628 | if (engineModule != null) 1629 | { 1630 | if (engineModule.getIgnitionState) 1631 | { 1632 | retList.Add(part); 1633 | } 1634 | } 1635 | 1636 | var engineModuleFx = module as ModuleEnginesFX; 1637 | if (engineModuleFx != null) 1638 | { 1639 | var engineMod = engineModuleFx; 1640 | if (engineModuleFx.getIgnitionState) 1641 | { 1642 | retList.Add(part); 1643 | } 1644 | } 1645 | } 1646 | } 1647 | 1648 | return retList; 1649 | } 1650 | 1651 | public static double ProspectForResource(String resourceName, List engines) 1652 | { 1653 | List visited = new List(); 1654 | double total = 0; 1655 | 1656 | foreach (var part in engines) 1657 | { 1658 | total += ProspectForResource(resourceName, part, ref visited); 1659 | } 1660 | 1661 | return total; 1662 | } 1663 | 1664 | public static double ProspectForResource(String resourceName, Part engine) 1665 | { 1666 | List visited = new List(); 1667 | 1668 | return ProspectForResource(resourceName, engine, ref visited); 1669 | } 1670 | 1671 | public static double ProspectForResource(String resourceName, Part part, ref List visited) 1672 | { 1673 | double ret = 0; 1674 | 1675 | if (visited.Contains(part)) 1676 | { 1677 | return 0; 1678 | } 1679 | 1680 | visited.Add(part); 1681 | 1682 | foreach (PartResource resource in part.Resources) 1683 | { 1684 | if (resource.resourceName.ToLower() == resourceName.ToLower()) 1685 | { 1686 | ret += resource.amount; 1687 | } 1688 | } 1689 | 1690 | foreach (AttachNode attachNode in part.attachNodes) 1691 | { 1692 | if (attachNode.attachedPart != null //if there is a part attached here 1693 | && attachNode.nodeType == AttachNode.NodeType.Stack //and the attached part is stacked (rather than surface mounted) 1694 | && (attachNode.attachedPart.fuelCrossFeed //and the attached part allows fuel flow 1695 | ) 1696 | && !(part.NoCrossFeedNodeKey.Length > 0 //and this part does not forbid fuel flow 1697 | && attachNode.id.Contains(part.NoCrossFeedNodeKey))) // through this particular node 1698 | { 1699 | 1700 | 1701 | ret += ProspectForResource(resourceName, attachNode.attachedPart, ref visited); 1702 | } 1703 | } 1704 | 1705 | return ret; 1706 | } 1707 | 1708 | public static double ProspectForResourceMax(String resourceName, List engines) 1709 | { 1710 | List visited = new List(); 1711 | double total = 0; 1712 | 1713 | foreach (var part in engines) 1714 | { 1715 | total += ProspectForResourceMax(resourceName, part, ref visited); 1716 | } 1717 | 1718 | return total; 1719 | } 1720 | 1721 | public static double ProspectForResourceMax(String resourceName, Part engine) 1722 | { 1723 | List visited = new List(); 1724 | 1725 | return ProspectForResourceMax(resourceName, engine, ref visited); 1726 | } 1727 | 1728 | public static double ProspectForResourceMax(String resourceName, Part part, ref List visited) 1729 | { 1730 | double ret = 0; 1731 | 1732 | if (visited.Contains(part)) 1733 | { 1734 | return 0; 1735 | } 1736 | 1737 | visited.Add(part); 1738 | 1739 | foreach (PartResource resource in part.Resources) 1740 | { 1741 | if (resource.resourceName.ToLower() == resourceName.ToLower()) 1742 | { 1743 | ret += resource.maxAmount; 1744 | } 1745 | } 1746 | 1747 | foreach (AttachNode attachNode in part.attachNodes) 1748 | { 1749 | if (attachNode.attachedPart != null //if there is a part attached here 1750 | && attachNode.nodeType == AttachNode.NodeType.Stack //and the attached part is stacked (rather than surface mounted) 1751 | && (attachNode.attachedPart.fuelCrossFeed //and the attached part allows fuel flow 1752 | ) 1753 | && !(part.NoCrossFeedNodeKey.Length > 0 //and this part does not forbid fuel flow 1754 | && attachNode.id.Contains(part.NoCrossFeedNodeKey))) // through this particular node 1755 | { 1756 | 1757 | 1758 | ret += ProspectForResourceMax(resourceName, attachNode.attachedPart, ref visited); 1759 | } 1760 | } 1761 | 1762 | return ret; 1763 | } 1764 | 1765 | #endregion 1766 | 1767 | void FixedUpdate() 1768 | { 1769 | } 1770 | 1771 | void OnDestroy() 1772 | { 1773 | if (KSPSerialPort.Port.IsOpen) 1774 | { 1775 | KSPSerialPort.Port.Close(); 1776 | ScreenMessages.PostScreenMessage("Port closed", 10f, KSPIOScreenStyle); 1777 | } 1778 | 1779 | ActiveVessel.OnFlyByWire -= new FlightInputCallback(AxisInput); 1780 | } 1781 | } 1782 | } 1783 | --------------------------------------------------------------------------------