using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Collections;
using System.Windows.Forms;
namespace ArcMapNav
{
///
/// Control for connecting to UDP datagrams to get ship and ROV position depth and headings.
///
public sealed class NavViaSocket
{
private static byte[] messageSent = new byte[1024];
private static byte[] dataReturned = new byte[1024];
private static IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
private static EndPoint Remote = (EndPoint)sender;
private static int size = 30;
private Socket m_server;
private static IPEndPoint m_ipep;
private static string m_headerString;
PositionSingleton posInstance = PositionSingleton.Instance;
private string m_hostName;
private int m_socketNum;
///
/// Get Navigation data thru UDP socket connection
///
///
public NavViaSocket(string connectionStr)
{
try
{
string[] parts = connectionStr.Split(new char[] { ':' }, 2);
m_hostName = parts[0];
m_socketNum = Convert.ToInt32(parts[1]);
}
catch
{
string msg = "Invalid connection string: " + connectionStr;
System.Diagnostics.Trace.TraceError(msg);
MessageBox.Show(msg, "Error");
}
// Initial position for debugging
//posInstance.RovLat = 36.80216;
//posInstance.RovLon = -121.787198;
//posInstance.RovHeading = 293;
}
///
/// Connect to UPD server and begin getting data
///
public void connect()
{
try
{
string dataString;
int recv = 0;
IPHostEntry iphe = null;
try
{
// Try first assuming m_hostName is an IP address string
m_ipep = new IPEndPoint(IPAddress.Parse(m_hostName), m_socketNum);
}
catch (FormatException)
{
iphe = Dns.GetHostEntry(m_hostName);
m_ipep = new IPEndPoint(iphe.AddressList[0], m_socketNum);
}
m_server = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram, ProtocolType.Udp);
int sockopt = (int)m_server.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout);
m_server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 3000);
sockopt = (int)m_server.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout);
//Send "HEADER" until we get back header string,
DateTime startTime = DateTime.Now;
TimeSpan ts;
int timeOutPeriod = 10; // time to wait in seconds
do
{
messageSent = Encoding.ASCII.GetBytes("HEADER");
recv = AdvSndRcvData(m_server, messageSent, m_ipep);
ts = DateTime.Now - startTime;
}
while (recv == 0 && ts.Seconds < timeOutPeriod);
// If we don't get a header after this then there is a connectivity problem
m_headerString = Encoding.ASCII.GetString(dataReturned, 0, recv);
if ("".Equals(m_headerString) || m_headerString.StartsWith("\0"))
{
string msg = "No response from " + m_hostName + ":" + m_socketNum + ". Is there a network problem?";
System.Diagnostics.Trace.TraceError(msg);
MessageBox.Show(msg, "Error");
disconnect();
}
else if (m_server != null)
{
// Send anything else (in this case "DATA") to get a data record
while (true)
{
messageSent = Encoding.ASCII.GetBytes("DATA");
recv = AdvSndRcvData(m_server, dataReturned, m_ipep);
if (recv > 0)
{
dataString = Encoding.ASCII.GetString(dataReturned, 0, recv);
parseData(m_headerString, dataString);
}
Thread.Sleep(Properties.Settings.Default.updateRate * 1000);
}
}
}
catch (System.Net.Sockets.SocketException e)
{
// This needs to be a Singleton or have some other mechanism to not generate so many pupups should the network go away
string msg = "Cannot connect to host " + m_hostName + " (" + e.Message + ")";
System.Diagnostics.Trace.TraceError(msg);
MessageBox.Show(msg, "Error");
disconnect();
}
catch (System.Threading.ThreadAbortException e)
{
//System.Windows.Forms.MessageBox.Show("Warning: switching data feed connection to the " + Properties.Settings.Default.selectedShip);
string msg = "NavViaSocket and DataFeedThread aborted for host = " + m_hostName + " (" + e.Message + ")";
System.Diagnostics.Trace.TraceError(msg);
}
catch (ArgumentOutOfRangeException e)
{
string msg = "ArgumentOutOfRangeException for host = " + m_hostName + " (" + e.Message + ")";
System.Diagnostics.Trace.TraceError(msg);
MessageBox.Show(msg + "\n\n" + e.StackTrace, "Error");
disconnect();
}
catch (NullReferenceException e)
{
string msg = "NullReferenceException for host = " + m_hostName + " (" + e.Message + ")";
System.Diagnostics.Trace.TraceError(msg);
MessageBox.Show(msg + "\n\n" + e.StackTrace, "Error");
disconnect();
}
catch (IndexOutOfRangeException e)
{
string msg = "IndexOutOfRangeException for host = " + m_hostName + " (" + e.Message + ")";
System.Diagnostics.Trace.TraceError(msg);
MessageBox.Show(msg + "\n\n" + e.StackTrace, "Error");
disconnect();
}
} // End connect()
///
/// To call before closing window
///
public void disconnect()
{
try
{
if (m_server != null)
m_server.Close();
}
catch (Exception e)
{
string msg = "Cannot connect to host " + m_hostName + " (" + e.Message + ")";
System.Diagnostics.Trace.TraceError(msg);
MessageBox.Show(msg, "Error");
disconnect();
}
}
#region private methods
private static int AdvSndRcvData(Socket s, byte[] message, EndPoint rmtdevice)
{
int recv = 0;
int retry = 0;
while (true)
{
try
{
s.SendTo(message, message.Length, SocketFlags.None, rmtdevice);
dataReturned = new byte[size];
recv = s.ReceiveFrom(dataReturned, ref Remote);
}
catch (SocketException e)
{
if (e.ErrorCode == 10054)
recv = 0;
else if (e.ErrorCode == 10040)
{
size += 10;
recv = 0;
}
}
catch (ObjectDisposedException e)
{
if (!s.Connected)
{
return -1;
}
System.Windows.Forms.MessageBox.Show("AdvSndRcvData() Exception caught: " + e.ToString(), "Error");
}
if (recv > 0)
{
return recv;
}
else
{
retry++;
if (retry > 4)
{
return 0;
}
}
}
} // End AdvSndRcvData()
private void parseData(String headerStr, String dataStr)
{
// str = "1194626433,1194630032,0.10, 0.5,36.802155,-121.787207,1,NO_ITEM,0.9,1194626441,292.8,NO_ITEM,NO_ITEM,NO_ITEM,1194570065,36.746427,-122.048790,-0.240000,23.209999,0.374000,0.540000,-1.138000,2007,313,08:40:33,+0"
// navlogr1167782400,1167785999,0.13, 0.3,36.802152,-121.787205,1,NO_PROV,1.0,1167782400,291.0,NO_ITEM,NO_ITEM,NO_ITEM,1167782400,36.710313,-122.184227,-0.200000,45.020000,1.454000,-0.228000,-1.138000,2007,002,16:00:00,+0
/*
*
0. #LOG LOGHOST.SYSTEM.UTC %d AUTO
1. #LOG PT_LOBOS.GPS.TIME %d SLAVE
2. #LOG VENTANA.PRESSURE %4.2f SLAVE
3. #LOG VENTANA.SENSOR.PRESSURE.DBAR %5.1lf SLAVE
4. #LOG PT_LOBOS.GPS.LATITUDE %3.6lf SLAVE
5. #LOG PT_LOBOS.GPS.LONGITUDE %4.6lf SLAVE
6. #LOG PT_LOBOS.GPS.DIFFERENTIAL %d SLAVE
7. #LOG PT_LOBOS.GPS.HORIZONTAL_VELOCITY %lf SLAVE
8. #LOG PT_LOBOS.GPS.HDOP %3.1f SLAVE
9. #LOG PT_LOBOS.GYRO.DEGREES.UTC %d AUTO
10. #LOG PT_LOBOS.GYRO.DEGREES %3.1f SLAVE
11. #LOG PT_LOBOS.WIND.TRUE_SPEED.UTC %d AUTO
12. #LOG PT_LOBOS.WIND.TRUE_SPEED %lf SLAVE
13. #LOG PT_LOBOS.WIND.TRUE_DIRECTION %lf SLAVE
14. #LOG VENTANA.LATITUDE.UTC %d AUTO
15. #LOG VENTANA.LATITUDE %lf SLAVE
16. #LOG VENTANA.LONGITUDE %lf SLAVE
17. #LOG VENTANA.DEPTH %lf SLAVE
18. #LOG VENTANA.HEADING %lf SLAVE
19. #LOG VENTANA.PITCH %lf SLAVE
20. #LOG VENTANA.ROLL %lf SLAVE
21. #LOG VENTANA.ALTITUDE %lf SLAVE
22. #LOG LOGHOST.SYSTEM.CLOCKTIME.YEAR %d AUTO
23. #LOG LOGHOST.SYSTEM.CLOCKTIME.YEARDAY %d AUTO
24. #LOG LOGHOST.SYSTEM.CLOCKTIME.TIMESTRING %2d:%2d:%2d AUTO
25. #LOG LOGHOST.SYSTEM.CLOCKTIME.TIMEZONE %+d AUTO
*
*
0. #LOG LOGHOST.SYSTEM.UTC %d AUTO
1. #LOG WESTERN_FLYER.GPS.TIME %d SLAVE
2. #LOG TIBURON.VEHICLE.IN_WATER %1d SLAVE
3. #LOG WESTERN_FLYER.GPS.LATITUDE %3.6lf SLAVE
4. #LOG WESTERN_FLYER.GPS.LONGITUDE %4.6lf SLAVE
5. #LOG WESTERN_FLYER.GPS.DIFFERENTIAL %d SLAVE
6. #LOG WESTERN_FLYER.GPS.QUALITY %d SLAVE
7. #LOG WESTERN_FLYER.GPS.HDOP %3.1f SLAVE
8. #LOG WESTERN_FLYER.GYRO.DEGREES.UTC %d AUTO
9. #LOG WESTERN_FLYER.GYRO.DEGREES %3.1f SLAVE
10. #LOG WESTERN_FLYER.WIND.TRUE_SPEED.UTC %d AUTO
11. #LOG WESTERN_FLYER.WIND.TRUE_SPEED %lf SLAVE
12. #LOG WESTERN_FLYER.WIND.TRUE_DIRECTION %lf SLAVE
13. #LOG TIBURON.POSITION.LATITUDE.UTC %d AUTO
14. #LOG TIBURON.POSITION.LATITUDE %lf SLAVE
15. #LOG TIBURON.POSITION.LONGITUDE %lf SLAVE
16. #LOG TIBURON.SENSOR_IBC.PRESSURE %lf SLAVE
17. #LOG TIBURON.SENSOR.FOG.HEADING.DEGREES %lf SLAVE
18. #LOG TIBURON.SENSOR.PITCH.DEGREES %lf SLAVE
19. #LOG TIBURON.SENSOR.ROLL.DEGREES %lf SLAVE
20. #LOG TIBURON.SENSOR.ALTITUDE.METERS %lf SLAVE
21. #LOG LOGHOST.SYSTEM.CLOCKTIME.YEAR %d AUTO
22. #LOG LOGHOST.SYSTEM.CLOCKTIME.YEARDAY %d AUTO
23. #LOG LOGHOST.SYSTEM.CLOCKTIME.TIMESTRING %2d:%2d:%2d AUTO
24. #LOG LOGHOST.SYSTEM.CLOCKTIME.TIMEZONE %+d AUTO
*/
// Strings delivered by DataView - Headers on both ships now use Ship and ROV, use something else to tell which is which
// Case 1 Rachel Carson:
//"LOGHOST.SYSTEM.UTC,SHIP.GPS.TIME,ROV.PRESSURE,ROV.CTD.PRESSURE,SHIP.GPS.LAT,SHIP.GPS.LON,SHIP.GPS.DIFFERENTIAL,SHIP.GPS.HORIZONTAL_VELOCITY,SHIP.GPS.HDOP,SHIP.GYRO.DEGREES.UTC,SHIP.GYRO.DEGREES,SHIP.WIND.TRUE_SPEED.UTC,SHIP.WIND.TRUE_SPEED,SHIP.WIND.TRUE_DIRECTION,ROV.POSITION.LAT.UTC,ROV.POSITION.LAT,ROV.POSITION.LON,ROV.MBARI.DEPTH,ROV.HEADING,ROV.PITCH,ROV.ROLL,ROV.ALTITUDE,LOGHOST.SYSTEM.CLOCKTIME.YEAR,LOGHOST.SYSTEM.CLOCKTIME.YEARDAY,LOGHOST.SYSTEM.CLOCKTIME.TIMESTRING,LOGHOST.SYSTEM.CLOCKTIME.TIMEZONE"
// (fieldNames[2].StartsWith('ROV.PRESSURE')
//string vnta = "ROV"; // The Rachel Carson / Ventana now has "ROV" in the item names.
// Case 2 Western Flyer:
//string wfly = "WESTERN FLYER";
// "LOGHOST.SYSTEM.UTC,SHIP.GPS.TIME,ROV.CTD.INWATER,SHIP.GPS.LAT,SHIP.GPS.LON,SHIP.GPS.DIFFERENTIAL,SHIP.GPS.QUALITY,SHIP.GPS.HDOP,SHIP.GYRO.DEGREES.UTC,SHIP.GYRO.DEGREES,SHIP.WIND.TRUE_SPEED.UTC,SHIP.WIND.TRUE_SPEED,SHIP.WIND.TRUE_DIRECTION,ROV.POSITION.LAT.UTC,ROV.POSITION.LAT,ROV.POSITION.LON,ROV.DIGIQ.SCALED_PRESSURE,ROV.DVECS.HEADING,ROV.DVECS.PITCH,ROV.DVECS.ROLL,ROV.DVECS.ALTITUDE,ROV.CTD.PRESSURE,ROV.MBARI.DEPTH,ROV.SURVEY.POD_UP,ROV.SURVEY.DIGIQ_UP,ROV.SURVEY.OCTANS_UP,ROV.SURVEY.DVL_UP,ROV.SURVEY.ALTIMETER_UP,LOGHOST.SYSTEM.CLOCKTIME.YEAR,LOGHOST.SYSTEM.CLOCKTIME.YEARDAY,LOGHOST.SYSTEM.CLOCKTIME.TIMESTRING,LOGHOST.SYSTEM.CLOCKTIME.TIMEZONE"
string tibr = "TIBURON";
string rov = "ROV"; // The Doc Ricketts field names are not name specific, just 'Ship' and 'ROV'
// Case 3:
string drifter = "DRIFTER"; // For Gene Massion's special Hawaii ESP app
double pressure;
string[] lines = dataStr.Split('\n');
string[] fieldNames = headerStr.Split(',');
string[] fieldValues = dataStr.Split(',');
if (fieldValues.Length > 1)
{
// Case 1:
if (fieldNames[2].EndsWith("PRESSURE"))
{
// Rachel Carson / Ventana
posInstance.ShipName = MBARIEnvironment.RACHELCARSON;
posInstance.RovName = MBARIEnvironment.VENTANA;
if (fieldValues[1].StartsWith("NO")) // NO_PROV, NO_ITEM, etc.
{
posInstance.ShipTime = "";
posInstance.ShipDate = "";
}
else
{
DateTime sdt = new DateTime(1970, 1, 1).AddSeconds(double.Parse(fieldValues[0])); // Use System becasue GPS doesn't adjust for PST.89=\
//sdt = sdt.AddMinutes(-10); // Subtract 10 minutes for testing thread restart
posInstance.ShipEsecs = double.Parse(fieldValues[0]);
posInstance.ShipDateTime = sdt;
posInstance.ShipTime = String.Format("{0}", sdt.TimeOfDay);
posInstance.ShipDate = String.Format("{0:yyyy-MM-dd}", sdt);
posInstance.ShipLat = double.Parse(fieldValues[4]); // PL
posInstance.ShipLon = double.Parse(fieldValues[5]);
posInstance.ShipHeading = float.Parse(fieldValues[10]);
}
if (fieldValues[14].StartsWith("NO"))
{
posInstance.RovTime = "";
posInstance.RovDate = "";
}
else
{
DateTime rdt = new DateTime(1970, 1, 1).AddSeconds(double.Parse(fieldValues[14]));
posInstance.RovTime = String.Format("{0}", rdt.TimeOfDay);
posInstance.RovDate = String.Format("{0:yyyy-MM-dd}", rdt);
}
// Ventana
posInstance.RovLat = (fieldValues[15].StartsWith("NO")) ? double.NaN : double.Parse(fieldValues[15]);
posInstance.RovLon = (fieldValues[16].StartsWith("NO")) ? double.NaN : double.Parse(fieldValues[16]);
posInstance.RovHeading = (fieldValues[18].StartsWith("NO")) ? float.NaN : float.Parse(fieldValues[18]);
pressure = (fieldValues[17].StartsWith("NO")) ? double.NaN : double.Parse(fieldValues[17]);
posInstance.RovDepth = (float)dbarToMeters(pressure, posInstance.ShipLat);
} // End Case 1
// Case 2:
else if (fieldNames[2].StartsWith(tibr) || fieldNames[2].StartsWith(rov))
{
// Western Flyer / Tiburon / Doc Ricketts
posInstance.ShipName = MBARIEnvironment.WESTERNFLYER;
//posInstance.RovName = MBARIEnvironment.TIBURON;
posInstance.RovName = MBARIEnvironment.DOCRICKETTS;
if (fieldValues[1].StartsWith("NO"))
{
posInstance.ShipTime = "";
posInstance.ShipDate = "";
}
else
{
DateTime sdt = new DateTime(1970, 1, 1).AddSeconds(double.Parse(fieldValues[1]));
posInstance.ShipEsecs = double.Parse(fieldValues[1]);
posInstance.ShipDateTime = sdt;
posInstance.ShipTime = String.Format("{0}", sdt.TimeOfDay);
posInstance.ShipDate = String.Format("{0:yyyy-MM-dd}", sdt);
posInstance.ShipLat = double.Parse(fieldValues[3]); // WF
posInstance.ShipLon = double.Parse(fieldValues[4]);
posInstance.ShipHeading = float.Parse(fieldValues[9]);
}
if (fieldValues[14].StartsWith("NO"))
{
posInstance.RovTime = "";
posInstance.RovDate = "";
}
else
{
DateTime rdt = new DateTime(1970, 1, 1).AddSeconds(double.Parse(fieldValues[13]));
posInstance.RovTime = String.Format("{0}", rdt.TimeOfDay);
posInstance.RovDate = String.Format("{0:yyyy-MM-dd}", rdt);
}
// Tiburon or Doc Ricketts
posInstance.RovLat = (fieldValues[14].StartsWith("NO")) ? double.NaN : double.Parse(fieldValues[14]);
posInstance.RovLon = (fieldValues[15].StartsWith("NO")) ? double.NaN : double.Parse(fieldValues[15]);
posInstance.RovHeading = (fieldValues[17].StartsWith("NO")) ? float.NaN : float.Parse(fieldValues[17]);
pressure = (fieldValues[16].StartsWith("NO")) ? double.NaN : double.Parse(fieldValues[16]);
posInstance.RovDepth = (float)dbarToMeters(pressure, posInstance.ShipLat);
if (Properties.Settings.Default.testWithRandomROVPos)
{
// Generate some random data so that this can be tested with a production install by changing the testWithRandomROVPos value to True in the user.config file
Random random = new Random();
posInstance.RovLat = posInstance.RovLat + (random.NextDouble() - 0.5) * 0.005;
posInstance.RovLon = posInstance.RovLon + (random.NextDouble() - 0.5) * 0.005;
posInstance.RovHeading = (float) random.NextDouble() * 360;
}
} // End Case 2
// str = "1194626433,1194630032,0.10, 0.5,36.802155,-121.787207,1,NO_ITEM,0.9,1194626441,292.8,NO_ITEM,NO_ITEM,NO_ITEM,1194570065,36.746427,-122.048790,-0.240000,23.209999,0.374000,0.540000,-1.138000,2007,313,08:40:33,+0"
// Case 3:
else if (fieldNames[5].StartsWith(drifter))
{
// 0. body = "LOGHOST.SYSTEM.UTC"
// 1. body = body + ",SHIP.GPS.UTC"
// 2. body = body + ",SHIP.GPS.LAT"
// 3. body = body + ",SHIP.GPS.LON"
// 4. body = body + ",SHIP.HEADING.DEGREES"
// 5. body = body + ",DRIFTER.POSITION.UTC"
// 6. body = body + ",DRIFTER.POSITION.LAT"
// 7. body = body + ",DRIFTER.POSITION.LON"
// 8. body = body + ",DRIFTER.PRESSURE"
// 9. body = body + ",DRIFTER.HEADING"
// Western Flyer / Tiburon / Doc Ricketts
posInstance.ShipName = MBARIEnvironment.SHIP;
posInstance.RovName = MBARIEnvironment.DRIFTER;
if (fieldValues[1].StartsWith("NO"))
{
posInstance.ShipTime = "";
posInstance.ShipDate = "";
}
else
{
DateTime sdt = new DateTime(1970, 1, 1).AddSeconds(double.Parse(fieldValues[1]));
posInstance.ShipEsecs = double.Parse(fieldValues[1]);
posInstance.ShipDateTime = sdt;
posInstance.ShipTime = String.Format("{0}", sdt.TimeOfDay);
posInstance.ShipDate = String.Format("{0:yyyy-MM-dd}", sdt);
posInstance.ShipLat = double.Parse(fieldValues[2]); // Drifter
posInstance.ShipLon = double.Parse(fieldValues[3]);
posInstance.ShipHeading = float.Parse(fieldValues[4]);
}
// Drifter - but we still use the Rov fields...
if (fieldValues[5].StartsWith("NO"))
{
posInstance.RovTime = "";
posInstance.RovDate = "";
}
else
{
DateTime rdt = new DateTime(1970, 1, 1).AddSeconds(double.Parse(fieldValues[5]));
posInstance.RovTime = String.Format("{0}", rdt.TimeOfDay);
posInstance.RovDate = String.Format("{0:yyyy-MM-dd}", rdt);
}
posInstance.RovLat = (fieldValues[6].StartsWith("NO")) ? double.NaN : double.Parse(fieldValues[6]);
posInstance.RovLon = (fieldValues[7].StartsWith("NO")) ? double.NaN : double.Parse(fieldValues[7]);
posInstance.RovHeading = (fieldValues[9].StartsWith("NO")) ? float.NaN : float.Parse(fieldValues[9]);
pressure = (fieldValues[8].StartsWith("NO")) ? double.NaN : double.Parse(fieldValues[8]);
posInstance.RovDepth = (float)dbarToMeters(pressure, posInstance.ShipLat);
} // End Case 3
if (Properties.Settings.Default.testWithRandomROVPos)
{
// Generate some random data so that this can be tested with a production install by changing the testWithRandomROVPos value to True in the Setup dialog
Random random = new Random();
posInstance.RovLat = posInstance.RovLat + (random.NextDouble() - 0.5) * 0.005;
posInstance.RovLon = posInstance.RovLon + (random.NextDouble() - 0.5) * 0.005;
posInstance.RovHeading = (float)random.NextDouble() * 360;
}
} // End if (fieldValues.Length > 1)
}
private double dbarToMeters(double pressure, double latitude)
{
// Test values for pressure to depth calculation
// Pressure Depth Depth Depth Depth Depth
// (Lat=0 (lat=30) (lat=45) (lat=60) (lat=90)
//
// 500.0 496.65 496.00 495.34 494.69 494.03
// 1000.0 992.12 990.81 989.50 988.19 986.88
// 2000.0 1979.55 1976.94 1974.33 1971.72 1969.11
// 3000.0 2962.43 2958.52 2954.61 2950.71 2946.81
// 4000.0 3940.88 3935.68 3930.49 3925.30 3920.10
// 5000.0 4915.04 4908.56 4902.08 4895.60 4889.13
// 6000.0 5885.03 5877.27 5869.51 5861.76 5854.01
// 7000.0 6850.95 6841.92 6832.89 6823.86 6814.84
// 8000.0 7812.93 7802.63 7792.33 7782.04 7771.76
// 9000.0 8771.07 8759.51 8747.95 8736.40 8724.85
//10000.0 9725.47 9712.65 9699.84 9687.03 9674.23
//
double C1, C2, C3, C4, G0, G1, G2, Gamma, X, gravity, Z;
double PI = 3.14159265358979;
double depth;
if (pressure == double.NaN || latitude == double.NaN)
{
return double.NaN;
}
C1 = 9.72659;
C2 = -0.000022512;
C3 = 0.0000000002279;
C4 = -1.82E-15;
G0 = 9.780318;
G1 = 0.0052788;
G2 = 0.0000236;
Gamma = 0.000002184;
//X = (Math.Sin(PI * latitude / 180.0));
X = Math.Pow((Math.Sin(PI * latitude / 180.0)), 2);
gravity = G0 * (1 + (G1 + G2 * X) * X) + (Gamma / 2) * pressure;
Z = (C1 + (C2 + (C3 + C4 * pressure) * pressure) * pressure) * pressure;
depth = Z / gravity;
return depth;
} // End dbarToMeters()
#endregion
} // End class NavViaSocket
} // End namespace