VOID_DataLogger: Added Apo/Peri Altitudes.
[VOID.git] / VOID_DataLogger.cs
blob:a/VOID_DataLogger.cs -> blob:b/VOID_DataLogger.cs
// VOID // VOID
// //
// VOID_DataLogger.cs // VOID_DataLogger.cs
// //
// Copyright © 2014, toadicus // Copyright © 2014, toadicus
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without modification, // Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met: // are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright notice, // 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or other // this list of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution. // materials provided with the distribution.
// //
// 3. Neither the name of the copyright holder nor the names of its contributors may be used // 3. Neither the name of the copyright holder nor the names of its contributors may be used
// to endorse or promote products derived from this software without specific prior written permission. // to endorse or promote products derived from this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   
using KSP; using KSP;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
using ToadicusTools; using ToadicusTools;
  using ToadicusTools.DebugTools;
  using ToadicusTools.GUIUtils;
  using ToadicusTools.Text;
using UnityEngine; using UnityEngine;
   
namespace VOID namespace VOID
{ {
public class VOID_DataLogger : VOID_WindowModule, IVOID_BehaviorModule public class VOID_DataLogger : VOID_WindowModule, IVOID_BehaviorModule
{ {
/* /*
* Fields * Fields
* */ * */
#region Fields #region Fields
   
protected bool _loggingActive; protected bool _loggingActive;
protected bool firstWrite; protected bool firstWrite;
   
[AVOID_SaveValue("waitForLaunch")] [AVOID_SaveValue("waitForLaunch")]
protected VOID_SaveValue<bool> waitForLaunch; protected VOID_SaveValue<bool> waitForLaunch;
   
[AVOID_SaveValue("logInterval")] [AVOID_SaveValue("logInterval")]
protected VOID_SaveValue<float> logInterval; protected VOID_SaveValue<float> logInterval;
protected string logIntervalStr; protected string logIntervalStr;
   
protected float csvCollectTimer; protected float csvCollectTimer;
   
protected List<byte> csvBytes; protected List<byte> csvBytes;
   
protected string _fileName; protected string _fileName;
protected FileStream _outputFile; protected FileStream _outputFile;
   
protected uint outstandingWrites; protected uint outstandingWrites;
   
protected System.Text.UTF8Encoding _utf8Encoding; protected System.Text.UTF8Encoding _utf8Encoding;
   
#endregion #endregion
   
/* /*
* Properties * Properties
* */ * */
   
#region Properties #region Properties
   
// TODO: Add configurable or incremental file names. // TODO: Add configurable or incremental file names.
protected bool loggingActive protected bool loggingActive
{ {
get get
{ {
return this._loggingActive; return this._loggingActive;
} }
set set
{ {
if (value != this._loggingActive) if (value != this._loggingActive)
{ {
if (value) if (value)
{ {
this.csvCollectTimer = 0f; this.csvCollectTimer = 0f;
} }
else else
{ {
this.CloseFileIfOpen(); this.CloseFileIfOpen();
} }
   
this._loggingActive = value; this._loggingActive = value;
} }
} }
} }
   
protected string fileName protected string fileName
{ {
get get
{ {
if (this._fileName == null || this._fileName == string.Empty) if (this._fileName == null || this._fileName == string.Empty)
{ {
this._fileName = KSP.IO.IOUtils.GetFilePathFor( this._fileName = string.Format(
typeof(VOIDCore), "{0}/{1}_{2}",
string.Format( this.core.SaveGamePath,
"{0}_{1}", this.Vessel.vesselName,
this.Vessel.vesselName, "data.csv"
"data.csv"  
),  
null  
); );
} }
   
return this._fileName; return this._fileName;
} }
} }
   
protected FileStream outputFile protected FileStream outputFile
{ {
get get
{ {
if (this._outputFile == null) if (this._outputFile == null)
{ {
Tools.DebugLogger logger = Tools.DebugLogger.New(this); using (PooledDebugLogger logger = PooledDebugLogger.New(this))
logger.AppendFormat("Initializing output file '{0}' with mode ", this.fileName);  
   
if (File.Exists(this.fileName))  
{ {
logger.Append("append"); logger.AppendFormat("Initializing output file '{0}' with mode ", this.fileName);
this._outputFile = new FileStream(  
this.fileName, if (File.Exists(this.fileName))
FileMode.Append, {
FileAccess.Write, logger.Append("append");
FileShare.Read, this._outputFile = new FileStream(
512, this.fileName,
true FileMode.Append,
); FileAccess.Write,
  FileShare.Read,
  512,
  true
  );
  }
  else
  {
  logger.Append("create");
  this._outputFile = new FileStream(
  this.fileName,
  FileMode.Create,
  FileAccess.Write,
  FileShare.Read,
  512,
  true
  );
   
  byte[] byteOrderMark = utf8Encoding.GetPreamble();
   
  logger.Append(" and writing preamble");
  this._outputFile.Write(byteOrderMark, 0, byteOrderMark.Length);
  }
   
  logger.Append('.');
   
  logger.AppendFormat(" File is {0}opened asynchronously.", this._outputFile.IsAsync ? "" : "not ");
   
  logger.Print();
} }
else  
{  
logger.Append("create");  
this._outputFile = new FileStream(  
this.fileName,  
FileMode.Create,  
FileAccess.Write,  
FileShare.Read,  
512,  
true  
);  
   
byte[] byteOrderMark = utf8Encoding.GetPreamble();  
   
logger.Append(" and writing preamble");  
this._outputFile.Write(byteOrderMark, 0, byteOrderMark.Length);  
}  
   
logger.Append('.');  
   
logger.AppendFormat(" File is {0}opened asynchronously.", this._outputFile.IsAsync ? "" : "not ");  
   
logger.Print();  
} }
   
return this._outputFile; return this._outputFile;
} }
} }
   
public UTF8Encoding utf8Encoding public UTF8Encoding utf8Encoding
{ {
get get
{ {
if (this._utf8Encoding == null) if (this._utf8Encoding == null)
{ {
this._utf8Encoding = new UTF8Encoding(true); this._utf8Encoding = new UTF8Encoding(true);
} }
   
return this._utf8Encoding; return this._utf8Encoding;
} }
} }
   
#endregion #endregion
   
/* /*
* Methods * Methods
* */ * */
#region Monobehaviour Lifecycle #region Monobehaviour Lifecycle
public void Update() public void Update()
{ {
if (this.csvBytes != null && this.csvBytes.Count > 0) if (this.csvBytes != null && this.csvBytes.Count > 0)
{ {
// csvList is not empty, write it // csvList is not empty, write it
this.AsyncWriteData(); this.AsyncWriteData();
} }
   
// CSV Logging // CSV Logging
// from ISA MapSat // from ISA MapSat
if (loggingActive && (!waitForLaunch || this.Vessel.situation != Vessel.Situations.PRELAUNCH)) if (loggingActive && (!waitForLaunch || this.Vessel.situation != Vessel.Situations.PRELAUNCH))
{ {
//data logging is on //data logging is on
//increment timers //increment timers
this.csvCollectTimer += Time.deltaTime; this.csvCollectTimer += Time.deltaTime;
   
if (this.csvCollectTimer >= this.logInterval) if (this.csvCollectTimer >= this.logInterval)
{ {
//data logging is on, vessel is not prelaunch, and interval has passed //data logging is on, vessel is not prelaunch, and interval has passed
//write a line to the list //write a line to the list
this.CollectLogData(); this.CollectLogData();
} }
} }
} }
   
public void FixedUpdate() {} public void FixedUpdate() {}
   
public void OnDestroy() public void OnDestroy()
{ {
Tools.DebugLogger logger = Tools.DebugLogger.New(this); using (PooledDebugLogger logger = PooledDebugLogger.New(this))
  {
logger.Append("Destroying..."); logger.Append("Destroying...");
   
this.CloseFileIfOpen(); this.CloseFileIfOpen();
   
logger.Append(" Done."); logger.Append(" Done.");
logger.Print(false); logger.Print(false);
  }
} }
   
#endregion #endregion
   
#region VOID_Module Overrides #region VOID_Module Overrides
   
public override void LoadConfig() public override void LoadConfig(KSP.IO.PluginConfiguration config)
{ {
base.LoadConfig(); base.LoadConfig(config);
   
this.logIntervalStr = this.logInterval.value.ToString("#.0##"); this.logIntervalStr = this.logInterval.value.ToString("#.0##");
} }
   
public override void ModuleWindow(int id) public override void ModuleWindow(int id)
{ {
GUILayout.BeginVertical(); GUILayout.BeginVertical();
   
GUILayout.Label( GUILayout.Label(
string.Format("System time: {0}", DateTime.Now.ToString("HH:mm:ss")), string.Format("System time: {0}", DateTime.Now.ToString("HH:mm:ss")),
GUILayout.ExpandWidth(true) GUILayout.ExpandWidth(true)
); );
GUILayout.Label( GUILayout.Label(
string.Format("Kerbin time: {0}", VOID_Tools.FormatDate(Planetarium.GetUniversalTime())), string.Format("Kerbin time: {0}", VOID_Tools.FormatDate(Planetarium.GetUniversalTime())),
GUILayout.ExpandWidth(true) GUILayout.ExpandWidth(true)
); );
   
GUIStyle activeLabelStyle = VOID_Styles.labelRed; GUIStyle activeLabelStyle = VOID_Styles.labelRed;
string activeLabelText = "Inactive"; string activeLabelText = "Inactive";
if (loggingActive) if (loggingActive)
{ {
activeLabelText = "Active"; activeLabelText = "Active";
activeLabelStyle = VOID_Styles.labelGreen; activeLabelStyle = VOID_Styles.labelGreen;
} }
   
this.loggingActive = GUITools.Toggle( this.loggingActive = Layout.Toggle(
loggingActive, loggingActive,
string.Format("Data logging: {0}", activeLabelText), string.Format("Data logging: {0}", activeLabelText),
null, null,
activeLabelStyle activeLabelStyle
); );
   
this.waitForLaunch.value = GUITools.Toggle( this.waitForLaunch.value = Layout.Toggle(
this.waitForLaunch, this.waitForLaunch,
"Wait for launch" "Wait for launch"
); );
   
GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
   
GUILayout.Label("Interval: ", GUILayout.ExpandWidth(false)); GUILayout.Label("Interval: ", GUILayout.ExpandWidth(false));
   
logIntervalStr = GUILayout.TextField(logIntervalStr, GUILayout.ExpandWidth(true)); logIntervalStr = GUILayout.TextField(logIntervalStr, GUILayout.ExpandWidth(true));
GUILayout.Label("s", GUILayout.ExpandWidth(false)); GUILayout.Label("s", GUILayout.ExpandWidth(false));
   
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
   
float newLogInterval; float newLogInterval;
if (float.TryParse(logIntervalStr, out newLogInterval)) if (float.TryParse(logIntervalStr, out newLogInterval))
{ {
logInterval.value = newLogInterval; logInterval.value = newLogInterval;
this.logIntervalStr = this.logInterval.value.ToString("#.0##"); this.logIntervalStr = this.logInterval.value.ToString("#.0##");
} }
   
GUILayout.EndVertical(); GUILayout.EndVertical();
   
base.ModuleWindow(id); base.ModuleWindow(id);
} }
   
#endregion #endregion
   
#region Data Collection #region Data Collection
   
private void CollectLogData() private void CollectLogData()
{ {
if (this.csvBytes == null) if (this.csvBytes == null)
{ {
this.csvBytes = new List<byte>(); this.csvBytes = new List<byte>();
} }
   
//called if logging is on and interval has passed //called if logging is on and interval has passed
//writes one line to the csvList //writes one line to the csvList
   
StringBuilder line = new StringBuilder(); using (PooledStringBuilder line = PooledStringBuilder.Get())
  {
if (firstWrite) if (firstWrite)
{ {
firstWrite = false; firstWrite = false;
line.Append( line.Append(
"\"Kerbin Universal Time (s)\"," + "\"Kerbin Universal Time (s)\"," +
"\"Mission Elapsed Time (s)\t\"," + "\"Mission Elapsed Time (s)\t\"," +
"\"Altitude ASL (m)\"," + "\"Altitude ASL (m)\"," +
"\"Altitude above terrain (m)\"," + "\"Altitude above terrain (m)\"," +
"\"Surface Latitude (°)\"," + "\"Surface Latitude (°)\"," +
"\"Surface Longitude (°)\"," + "\"Surface Longitude (°)\"," +
"\"Apoapsis Altitude (m)\"" + "\"Apoapsis Altitude (m)\"," +
"\"Periapsis Altitude (m)\"" + "\"Periapsis Altitude (m)\"," +
"\"Orbital Velocity (m/s)\"," + "\"Orbital Inclination (°)\"," +
"\"Surface Velocity (m/s)\"," + "\"Orbital Velocity (m/s)\"," +
"\"Vertical Speed (m/s)\"," + "\"Surface Velocity (m/s)\"," +
"\"Horizontal Speed (m/s)\"," + "\"Vertical Speed (m/s)\"," +
"\"Gee Force (gees)\"," + "\"Horizontal Speed (m/s)\"," +
"\"Temperature (°C)\"," + "\"Current Thrust (kN)\"," +
"\"Gravity (m/s²)\"," + "\"Gee Force (gees)\"," +
"\"Atmosphere Density (g/m³)\"," + "\"Temperature (°C)\"," +
"\"Downrange Distance (m)\"," + "\"Gravity (m/s²)\"," +
"\n" "\"Atmosphere Density (g/m³)\"," +
); "\"Downrange Distance (m)\"," +
} "\"Main Throttle\"," +
  "\n"
// Universal time );
line.Append(Planetarium.GetUniversalTime().ToString("F2")); }
line.Append(',');  
  // Universal time
//Mission time line.Append(Planetarium.GetUniversalTime().ToString("F2"));
line.Append(Vessel.missionTime.ToString("F3")); line.Append(',');
line.Append(',');  
  //Mission time
//Altitude ASL line.Append(Vessel.missionTime.ToString("F3"));
line.Append(VOID_Data.orbitAltitude.Value.ToString("F3")); line.Append(',');
line.Append(',');  
  //Altitude ASL
//Altitude (true) line.Append(VOID_Data.orbitAltitude.Value.ToString("G9"));
line.Append(VOID_Data.trueAltitude.Value.ToString("F3")); line.Append(',');
line.Append(',');  
  //Altitude (true)
// Surface Latitude line.Append(VOID_Data.trueAltitude.Value.ToString("G9"));
line.Append('"'); line.Append(',');
line.Append(VOID_Data.surfLatitude.Value);  
line.Append('"'); // Surface Latitude
line.Append(','); line.Append('"');
  line.Append(VOID_Data.surfLatitude.Value.ToString("F3"));
// Surface Longitude line.Append('"');
line.Append('"'); line.Append(',');
line.Append(VOID_Data.surfLongitude.Value);  
line.Append('"'); // Surface Longitude
line.Append(','); line.Append('"');
  line.Append(VOID_Data.surfLongitude.Value.ToString("F3"));
//Orbital velocity line.Append('"');
line.Append(VOID_Data.orbitVelocity.Value.ToString("F3")); line.Append(',');
line.Append(',');  
  // Apoapsis Altitude
// Apoapsis Altitude line.Append(VOID_Data.orbitApoAlt.Value.ToString("G9"));
line.Append(VOID_Data.orbitApoAlt.Value.ToString("G3")); line.Append(',');
line.Append(',');  
  // Periapsis Altitude
// Periapsis Altitude line.Append(VOID_Data.oribtPeriAlt.Value.ToString("G9"));
line.Append(VOID_Data.oribtPeriAlt.Value.ToString("G3")); line.Append(',');
line.Append(',');  
  // Orbital Inclination
//surface velocity line.Append(VOID_Data.orbitInclination.Value.ToString("F2"));
line.Append(VOID_Data.surfVelocity.Value.ToString("F3")); line.Append(',');
line.Append(',');  
  //Orbital velocity
//vertical speed line.Append(VOID_Data.orbitVelocity.Value.ToString("G9"));
line.Append(VOID_Data.vertVelocity.Value.ToString("F3")); line.Append(',');
line.Append(',');  
  //surface velocity
//horizontal speed line.Append(VOID_Data.surfVelocity.Value.ToString("G9"));
line.Append(VOID_Data.horzVelocity.Value.ToString("F3")); line.Append(',');
line.Append(',');  
  //vertical speed
//gee force line.Append(VOID_Data.vertVelocity.Value.ToString("G9"));
line.Append(VOID_Data.geeForce.Value.ToString("F3")); line.Append(',');
line.Append(',');  
  //horizontal speed
//temperature line.Append(VOID_Data.horzVelocity.Value.ToString("G9"));
line.Append(VOID_Data.temperature.Value.ToString("F2")); line.Append(',');
line.Append(',');  
  // Current Thrust
//gravity line.Append(VOID_Data.currThrust.Value.ToString("G9"));
line.Append(VOID_Data.gravityAccel.Value.ToString("F3")); line.Append(',');
line.Append(',');  
  //gee force
//atm density line.Append(VOID_Data.geeForce.Value.ToString("G9"));
line.Append(VOID_Data.atmDensity.Value.ToString("G3")); line.Append(',');
line.Append(',');  
  //temperature
// Downrange Distance line.Append(VOID_Data.temperature.Value.ToString("F3"));
line.Append((VOID_Data.downrangeDistance.Value.ToString("G3"))); line.Append(',');
   
line.Append('\n'); //gravity
  line.Append(VOID_Data.gravityAccel.Value.ToString("G9"));
csvBytes.AddRange(this.utf8Encoding.GetBytes(line.ToString())); line.Append(',');
   
this.csvCollectTimer = 0f; //atm density
  line.Append(VOID_Data.atmDensity.Value.ToString("G9"));
  line.Append(',');
   
  // Downrange Distance
  line.Append((VOID_Data.downrangeDistance.Value.ToString("G9")));
  line.Append(',');
   
  // Main Throttle
  line.Append(VOID_Data.mainThrottle.Value.ToString("P2"));
   
  line.Append('\n');
   
  csvBytes.AddRange(this.utf8Encoding.GetBytes(line.ToString()));
   
  this.csvCollectTimer = 0f;
  }
} }
   
#endregion #endregion
   
#region File IO Methods #region File IO Methods
   
protected void AsyncWriteCallback(IAsyncResult result) protected void AsyncWriteCallback(IAsyncResult result)
{ {
Tools.PostDebugMessage(this, "Got async callback, IsCompleted = {0}", result.IsCompleted); Logging.PostDebugMessage(this, "Got async callback, IsCompleted = {0}", result.IsCompleted);
   
this.outputFile.EndWrite(result); this.outputFile.EndWrite(result);
this.outstandingWrites--; this.outstandingWrites--;
} }
   
private void AsyncWriteData() private void AsyncWriteData()
{ {
WriteState state = new WriteState(); WriteState state = new WriteState();
   
state.bytes = this.csvBytes.ToArray(); state.bytes = this.csvBytes.ToArray();
state.stream = this.outputFile; state.stream = this.outputFile;
   
this.outstandingWrites++; this.outstandingWrites++;
var writeCallback = new AsyncCallback(this.AsyncWriteCallback); var writeCallback = new AsyncCallback(this.AsyncWriteCallback);
   
this.outputFile.BeginWrite(state.bytes, 0, state.bytes.Length, writeCallback, state); this.outputFile.BeginWrite(state.bytes, 0, state.bytes.Length, writeCallback, state);
   
this.csvBytes.Clear(); this.csvBytes.Clear();
} }
   
private void CloseFileIfOpen() private void CloseFileIfOpen()
{ {
Tools.DebugLogger logger = Tools.DebugLogger.New(this); using (PooledDebugLogger logger = PooledDebugLogger.New(this))
  {
logger.AppendFormat("Cleaning up file {0}...", this.fileName); logger.AppendFormat("Cleaning up file {0}...", this.fileName);
   
if (this.csvBytes != null && this.csvBytes.Count > 0) if (this.csvBytes != null && this.csvBytes.Count > 0)
{ {
logger.Append(" Writing remaining data..."); logger.Append(" Writing remaining data...");
this.AsyncWriteData(); this.AsyncWriteData();
} }
   
logger.Append(" Waiting for writes to finish."); logger.Append(" Waiting for writes to finish.");
while (this.outstandingWrites > 0) while (this.outstandingWrites > 0)
{ {
logger.Append('.'); logger.Append('.');
System.Threading.Thread.Sleep(10); System.Threading.Thread.Sleep(10);
} }
   
if (this._outputFile != null) if (this._outputFile != null)
{ {
this._outputFile.Close(); this._outputFile.Close();
this._outputFile = null; this._outputFile = null;
logger.Append(" File closed."); logger.Append(" File closed.");
} }
   
logger.Print(false); logger.Print(false);
  }
} }
   
#endregion #endregion
   
#region Constructors & Destructors #region Constructors & Destructors
   
public VOID_DataLogger() public VOID_DataLogger()
{ {
this.Name = "CSV Data Logger"; this.Name = "CSV Data Logger";
   
this.loggingActive = false; this.loggingActive = false;
this.firstWrite = true; this.firstWrite = true;
   
this.waitForLaunch = (VOID_SaveValue<bool>)true; this.waitForLaunch = (VOID_SaveValue<bool>)true;
   
this.logInterval = (VOID_SaveValue<float>)0.5f; this.logInterval = (VOID_SaveValue<float>)0.5f;
this.csvCollectTimer = (VOID_SaveValue<float>)0f; this.csvCollectTimer = (VOID_SaveValue<float>)0f;
   
this.outstandingWrites = 0; this.outstandingWrites = 0;
   
this.WindowPos.x = Screen.width - 520f; this.WindowPos.x = Screen.width - 520f;
this.WindowPos.y = 85f; this.WindowPos.y = 85f;
   
this.core.onApplicationQuit += delegate(object sender) this.core.onApplicationQuit += delegate(object sender)
{ {
this.CloseFileIfOpen(); this.CloseFileIfOpen();
}; };
} }
   
~VOID_DataLogger() ~VOID_DataLogger()
{ {
this.OnDestroy(); this.OnDestroy();
} }
   
#endregion #endregion
   
#region Subclasses #region Subclasses
   
private class WriteState private class WriteState
{ {
public byte[] bytes; public byte[] bytes;
public FileStream stream; public FileStream stream;
} }
   
#endregion #endregion
} }
} }