// pc-dasDlg.cpp : implementation file
//

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include "pc-das.h"
#include "pc-dasDlg.h"
#include "UTM.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CpcdasDlg dialog

#define RED_BUTTON RGB(255,65,65)
#define GRN_BUTTON RGB(20,255,20)
#define YLW_BUTTON RGB(244,244,0)
#define BLK_TEXT   RGB(0,0,0)

extern double radToDeg(double rad);
extern double degToRad(double deg);

CpcdasDlg::CpcdasDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CpcdasDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CpcdasDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CpcdasDlg, CDialog)
	ON_WM_TIMER()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()

	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_parosciPortSet, OnBnClickedparosciPortSet)
	ON_BN_CLICKED(IDC_kftPortSet, OnBnClickedkftPortSet)
	ON_BN_CLICKED(IDC_wfPortSet, OnBnClickedwfPortSet)
	ON_BN_CLICKED(IDC_resonAddrSet, OnBnClickedresonAddrSet)
	ON_BN_CLICKED(IDC_rockAddrSet, OnBnClickedRockAddrSet)
	ON_BN_CLICKED(IDC_3DaddrSet, OnBnClicked3DAddrSet)
	ON_BN_CLICKED(IDOK, OnBnClickedOk)

	ON_BN_CLICKED(IDC_gianAddrSet, OnBnClickedGianAddrSet)
END_MESSAGE_MAP()


// CpcdasDlg message handlers

BOOL CpcdasDlg::OnInitDialog()
{
	CDialog::OnInitDialog();
    CComboBox *portList;

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	// TODO: Add extra initialization here
	WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);

	_timerId = SetTimer(1, 0xA, NULL); //25 msec timer period for sampling serial ports
	_gpsList = (CListCtrl *)GetDlgItem(IDC_gpsList);
	_gpsList->InsertColumn(0, "GPS Data", LVCFMT_LEFT, 400);
	_parosciList = (CListCtrl *)GetDlgItem(IDC_parosciList);
	_parosciList->InsertColumn(0, "Parosci Data", LVCFMT_LEFT, 400);

	_winfrogList = (CListCtrl *)GetDlgItem(IDC_wfList);
	_winfrogList->InsertColumn(0, "Winfrog Data", LVCFMT_LEFT, 400);

	portList = (CComboBox *)GetDlgItem(IDC_kftPort);
	portList->AddString("1");
	portList->AddString("2");
	portList->AddString("3");
	portList->AddString("4");
	portList->AddString("5");
	portList->AddString("6");
	portList->AddString("7");
	portList->AddString("8");
	portList->SetCurSel(3);

	portList = (CComboBox *)GetDlgItem(IDC_parosciPort);
	portList->AddString("1");
	portList->AddString("2");
	portList->AddString("3");
	portList->AddString("4");
	portList->SetCurSel(2);

	portList = (CComboBox *)GetDlgItem(IDC_winfrogPort);
	portList->AddString("1");
	portList->AddString("2");
	portList->AddString("3");
	portList->AddString("4");
	portList->AddString("5");
	portList->AddString("6");
	portList->AddString("7");
	portList->AddString("8");
	portList->SetCurSel(7);

	_kearfottBtn.SubclassDlgItem(IDC_kftPortSet, this);
	_kearfottBtn.SetColor(BLK_TEXT, RED_BUTTON);
	_kearfottConnected = FALSE;
	_kearfott = NULL;

	_parosciBtn.SubclassDlgItem(IDC_parosciPortSet, this);
	_parosciBtn.SetColor(BLK_TEXT, RED_BUTTON);
	_parosciConnected = FALSE;

	_winfrogBtn.SubclassDlgItem(IDC_wfPortSet, this);
	_winfrogBtn.SetColor(BLK_TEXT, RED_BUTTON);
	_winfrogConnected = FALSE;

	_resonAddrBtn.SubclassDlgItem(IDC_resonAddrSet, this);
	_resonAddrBtn.SetColor(BLK_TEXT, RED_BUTTON);
	_resonConnected = FALSE;
	SetDlgItemText(IDC_resonIPAddrs, (LPCTSTR)("134.89.32.108"));
    _reson7K = NULL;

	_rockAddrBtn.SubclassDlgItem(IDC_rockAddrSet, this);
	_rockAddrBtn.SetColor(BLK_TEXT, RED_BUTTON);
	_rockConnected = FALSE;
	SetDlgItemText(IDC_rockIPAddrs, (LPCTSTR)("134.89.21.5"));
    _rockSocket = NULL;

	_3DAddrBtn.SubclassDlgItem(IDC_3DaddrSet, this);
	_3DAddrBtn.SetColor(BLK_TEXT, RED_BUTTON);
	_3DConnected = FALSE;
	SetDlgItemText(IDC_3DipAddress, (LPCTSTR)("192.168.168.130"));
    _3DSocket = NULL;

    _gianAddrBtn.SubclassDlgItem(IDC_gianAddrSet, this);
	_gianAddrBtn.SetColor(BLK_TEXT, RED_BUTTON);
	_gianConnected = FALSE;
	SetDlgItemText(IDC_GianipAddress, (LPCSTR)("134.89.20.76"));
	_gianSocket = NULL;

	_ctdSocket = NULL;
	_ctdConnected = FALSE;

    _pressureValid = FALSE; _pressureDepth = 0.;
	_usblValid = FALSE;
	_salinityValid = FALSE;
    _zeroRock = TRUE;

	_gpsAidEnableCBox.SubclassDlgItem(IDC_gpsAidEnable, this);
	_dopAidEnableCBox.SubclassDlgItem(IDC_dopAidEnable, this);
	_dopPingEnableCBox.SubclassDlgItem(IDC_dopPingEnable, this);
	_latLonCBox.SubclassDlgItem(IDC_lat_lon_valid, this);

	return TRUE;  // return TRUE  unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CpcdasDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CpcdasDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

void CpcdasDlg::OnBnClickedkftPortSet()
{
	// TODO: Add your control notification handler code here
    CString s;
	GetDlgItemText(IDC_kftPort, s);
	
	if (_kearfottPort.Open(atoi(s.GetString()), 115200, ODDPARITY, 8, ONESTOPBIT))
	{
	  _kearfottBtn.SetColor(BLK_TEXT, GRN_BUTTON);
	}
	_kearfott = new Kearfott(&_kearfottPort);
	_kearfottConnected = TRUE;
}

void CpcdasDlg::OnBnClickedparosciPortSet()
{
	// TODO: Add your control notification handler code here
    CString s;
	GetDlgItemText(IDC_parosciPort, s);
	if (_parosciPort.Open(atoi(s.GetString()), 115200, NOPARITY, 8, ONESTOPBIT) ) {
		_parosciConnected = TRUE;
		_parosciBtn.SetColor(BLK_TEXT, GRN_BUTTON);
	}
/*
	_parosciSocket = new SimpleSocket();
	(void)_parosciSocket->createConnectedStreamClient(4001, "134.89.32.108");
    //ADDED EJM
	//createConnectedStreamClient(4001,"134.89.32.108");

	if (_parosciSocket->ready())
		{
		_parosciConnected = TRUE;
		_parosciBtn.SetColor(BLK_TEXT, GRN_BUTTON);
        //ADDED EJM
		_parosciSocket->setOptionsTimeout(SimpleSocket::SS_RECEIVE,0,1000);
		}
*/
   _ctdSocket = new SimpleSocket();
   (void)_ctdSocket->createConnectedStreamClient(5040,"134.89.21.5"); //western flyer CTD
   //(void)_ctdSocket->createConnectedStreamClient(5014,"134.89.22.19");
   if (_ctdSocket->ready()) {
		_ctdConnected = TRUE;	
   }
}

void CpcdasDlg::OnBnClickedwfPortSet()
{
	// TODO: Add your control notification handler code here
	CString s;
	GetDlgItemText(IDC_winfrogPort, s);
	
	if (_winfrogPort.Open(atoi(s.GetString()), 9600))
	{
	  _winfrogConnected = TRUE;
	  _winfrogBtn.SetColor(BLK_TEXT, GRN_BUTTON);
	}
}

void CpcdasDlg::updateKearfottGUI()
{
	char buf[40];
	char *modeStrings[11] = {
		"Idle",
		"Coarse Stat Align",
		"Fine Stat Align Incomplete",
		"Fine Stat Align Complete",
		"Coarse GPS Align",
		"Fine GPS Align Incomplete",
		"Fine GPS Align Complete",
		"Dop Align Incomplete",
		"Dop Align Complete",
		"Aided Navigation",
		"Go/No Go"
	};

	if (_kearfott->_scaledNavData.mode >=0x00 && _kearfott->_scaledNavData.mode <= 0x0a) {
		SetDlgItemText(IDC_kft_mode, modeStrings[_kearfott->_scaledNavData.mode]);
	} else {
		SetDlgItemText(IDC_kft_mode, "Unknown");
	}

	sprintf(buf, "0x%2X\0", _kearfott->_scaledNavData.monitor);
	SetDlgItemText(IDC_kft_monitor, buf);

	if (_kearfott->_scaledNavData.monitor & DEPTH_LOOP_OPEN) {
		SetDlgItemText(IDC_kft_depthLoopOpen, "True");
	} else {
		SetDlgItemText(IDC_kft_depthLoopOpen, "False");
	}

	if (_kearfott->_scaledNavData.monitor & GPS_DATA_PROCESSED) {
		SetDlgItemText(IDC_kft_gpsProcessFlag, "True");
	} else {
		SetDlgItemText(IDC_kft_gpsProcessFlag, "False");
	}

	if (_kearfott->_scaledNavData.monitor & GPS_DATA_REJECTED) {
		SetDlgItemText(IDC_kft_gpsRejectFlag, "True");
	} else {
		SetDlgItemText(IDC_kft_gpsRejectFlag, "False");
	}

	if (_kearfott->_scaledNavData.monitor & DOP_DATA_PROCESSED) {
		SetDlgItemText(IDC_kft_dvlProcessFlag, "True");
	} else {
		SetDlgItemText(IDC_kft_dvlProcessFlag, "False");
	}

	if (_kearfott->_scaledNavData.monitor & DOP_DATA_REJECTED) {
		SetDlgItemText(IDC_kft_dvlRejectFlag, "True");
	} else {
		SetDlgItemText(IDC_kft_dvlRejectFlag, "False");
	}

	if (_kearfott->_scaledNavData.monitor & ZUPT_PROCESSED) {
		SetDlgItemText(IDC_kft_zuptProcessFlag, "True");
	} else {
		SetDlgItemText(IDC_kft_zuptProcessFlag, "False");
	}

	if (_kearfott->_scaledNavData.monitor & 0x02) {
		SetDlgItemText(IDC_kft_alignNoPosFlag, "True");
	} else {
		SetDlgItemText(IDC_kft_alignNoPosFlag, "False");
	}

	if (_kearfott->_scaledNavData.monitor & VALID_DVL_HEIGHT) {
		SetDlgItemText(IDC_kft_validDVLHeightFlag, "True");
	} else {
		SetDlgItemText(IDC_kft_validDVLHeightFlag, "False");
	}

	SetDlgItemInt(IDC_kft_Counter, _kearfott->_scaledNavData.cycles);

	sprintf(buf,"%20f\0", _kearfott->_scaledNavData.utcTime);
	SetDlgItemText(IDC_kft_UTCSecs, buf);

	sprintf(buf, "%20f\0", radToDeg(_kearfott->_scaledNavData.prate));
	SetDlgItemText(IDC_kft_xrate, buf);

	sprintf(buf, "%20f\0", radToDeg(_kearfott->_scaledNavData.qrate));
	SetDlgItemText(IDC_kft_yrate, buf);

	sprintf(buf, "%20f\0", radToDeg(_kearfott->_scaledNavData.rrate));
	SetDlgItemText(IDC_kft_zrate, buf);

	sprintf(buf, "%20f\0", radToDeg(_kearfott->_scaledNavData.lat));
	SetDlgItemText(IDC_kft_lat, buf);

	sprintf(buf, "%20f\0", radToDeg(_kearfott->_scaledNavData.lon));
	SetDlgItemText(IDC_kft_lon, buf);

	sprintf(buf, "%20f\0", _kearfott->_scaledNavData.depth);
	SetDlgItemText(IDC_kft_depth, buf);

	sprintf(buf, "%20f\0", _kearfott->_scaledNavData.bheight);
	SetDlgItemText(IDC_kft_altitude, buf);

	sprintf(buf, "%20f\0", _kearfott->_scaledNavData.vbodyx*100.0);
	SetDlgItemText(IDC_kft_nxvel, buf);

	sprintf(buf, "%20f\0", _kearfott->_scaledNavData.vbodyy*100.0);
	SetDlgItemText(IDC_kft_nyvel, buf);

	sprintf(buf, "%20f\0", _kearfott->_scaledNavData.vbodyz*100.0);
	SetDlgItemText(IDC_kft_nzvel, buf);

	sprintf(buf, "%20f\0", radToDeg(_kearfott->_scaledNavData.roll));
	SetDlgItemText(IDC_kft_roll, buf);

	sprintf(buf, "%20f\0", radToDeg(_kearfott->_scaledNavData.pitch));
	SetDlgItemText(IDC_kft_pitch, buf);

	sprintf(buf, "%20f\0", radToDeg(_kearfott->_scaledNavData.heading));
	SetDlgItemText(IDC_kft_heading, buf);

	sprintf(buf, "%20f\0", _kearfott->_scaledNavData.accelx);
	SetDlgItemText(IDC_kft_xacc, buf);

	sprintf(buf, "%20f\0", _kearfott->_scaledNavData.accely);
	SetDlgItemText(IDC_kft_yacc, buf);

	sprintf(buf, "%20f\0", _kearfott->_scaledNavData.accelz);
	SetDlgItemText(IDC_kft_zacc, buf);

	
	if (_gpsList && _kearfott->_ggaValid){
		_gpsList->InsertItem(0, _kearfott->_ggaStr);
		_kearfott->_ggaValid = FALSE;
	}

	//set dvl values
	SetDlgItemInt(IDC_dvl_Counter, _kearfott->_dopplerPD4.ktnav);

	sprintf(buf, "%20f\0", (float)_kearfott->_dopplerPD4.xvelbtm);
	SetDlgItemText(IDC_dvl_xvel, buf);

	sprintf(buf, "%20f\0", (float)_kearfott->_dopplerPD4.yvelbtm);
	SetDlgItemText(IDC_dvl_yvel, buf);

	sprintf(buf, "%20f\0", (float)_kearfott->_dopplerPD4.zvelbtm);
	SetDlgItemText(IDC_dvl_zvel, buf);

	sprintf(buf, "%20f\0", (float)_kearfott->_dopplerPD4.evelbtm);
	SetDlgItemText(IDC_dvl_evel, buf);

	sprintf(buf, "%20f\0", (float)_kearfott->_dopplerPD4.bm1);
	SetDlgItemText(IDC_dvl_bm1, buf);

	sprintf(buf, "%20f\0", (float)_kearfott->_dopplerPD4.bm2);
	SetDlgItemText(IDC_dvl_bm2, buf);

	sprintf(buf, "%20f\0", (float)_kearfott->_dopplerPD4.bm3);
	SetDlgItemText(IDC_dvl_bm3, buf);

	sprintf(buf, "%20f\0", (float)_kearfott->_dopplerPD4.bm4);
	SetDlgItemText(IDC_dvl_bm4, buf);

	sprintf(buf, "%20f\0", (float)_kearfott->_dopplerPD4.toping_hr);
	SetDlgItemText(IDC_dvl_top_hr, buf);

	sprintf(buf, "%20f\0", (float)_kearfott->_dopplerPD4.toping_min);
	SetDlgItemText(IDC_dvl_top_min, buf);

	sprintf(buf, "%20f\0", _kearfott->_dopplerPD4.toping_sec+(float)(_kearfott->_dopplerPD4.toping_hun/100.0));
	SetDlgItemText(IDC_dvl_top_sec, buf);
}

void CpcdasDlg::updateReson7k()
{
	char recordData[512];  
	char *ptrToData = recordData;
	char *ptrs = ptrToData;

	if (_reson7K && _kearfott) {
		//send position data
		U32 __ival = 0; //WGS84
		memcpy((void*)ptrs, &__ival, sizeof(U32)); ptrs += sizeof(U32);  // datum identifier
		F32 __fval = 0.0;
		memcpy((void*)ptrs, &__fval, sizeof(F32)); ptrs += sizeof(F32); // latency
		memcpy((void*)ptrs, &(_kearfott->_scaledNavData.lat), sizeof(F64)); ptrs += sizeof(F64); //lat in radians
		memcpy((void*)ptrs, &(_kearfott->_scaledNavData.lon), sizeof(F64)); ptrs += sizeof(F64); //lon in radians
		F64 __dval = 0.0;
		memcpy((void*)ptrs, &__dval, sizeof(F64)); ptrs += sizeof(F64); //height; set to 0.0 since we use the depth record for this
		U8 __cval = 0;
		memcpy((void*)ptrs, &__cval, sizeof(U8)); ptrs += sizeof(U8); //position type flag, 0 = lat/lon
		memcpy((void*)ptrs, &__cval, sizeof(U8)); ptrs += sizeof(U8); //UTM zone, meaningless
		memcpy((void*)ptrs, &__cval, sizeof(U8)); ptrs += sizeof(U8); //quality flag, 0 = navigation data
		memcpy((void*)ptrs, &__cval, sizeof(U8)); ptrs += sizeof(U8); //positioning flag, set to 0 for now
		memcpy((void*)ptrs, &__cval, sizeof(U8)); ptrs += sizeof(U8); //positioning flag, set to 0 for now
		_reson7K->MB_RemoteCommand(Reson6046Command::Position, ptrToData);
		ptrs = ptrToData; //reset pointer

		//send altitude if valid
		if (_kearfott->_scaledNavData.monitor & VALID_DVL_HEIGHT) {
			__fval = _kearfott->_scaledNavData.bheight;
			_reson7K->MB_RemoteCommand(Reson6046Command::Altitude, (char *)&__fval);
		}

		//roll, pitch & heave
		__fval = _kearfott->_scaledNavData.roll;
		memcpy((void*)ptrs, &__fval, sizeof(F32)); ptrs += sizeof(F32); // roll
		__fval = _kearfott->_scaledNavData.pitch;
		memcpy((void*)ptrs, &__fval, sizeof(F32)); ptrs += sizeof(F32); // pitch
		__fval = 0.0; //no heave from kearfott (for now!)
		memcpy((void*)ptrs, &__fval, sizeof(F32)); ptrs += sizeof(F32); // heave
		_reson7K->MB_RemoteCommand(Reson6046Command::RollPitchHeave, ptrToData);

		//heading
		__fval = _kearfott->_scaledNavData.heading;
		_reson7K->MB_RemoteCommand(Reson6046Command::Heading, (char *)&__fval);
	}
}

void CpcdasDlg::updateRock()
{
static double initNorthing = 0.0, initEasting = 0.0;

	if (_rockSocket) {
		double lat = _kearfott->_scaledNavData.lat*180.0/M_PI;
		double lon = _kearfott->_scaledNavData.lon*180.0/M_PI;
		double northing, easting;
		char zone[5];
		char buf[1024];

		UTM::LLtoUTM(lat, lon, northing, easting, zone);
		if (_zeroRock) {
			initNorthing = northing; initEasting = easting;
			_zeroRock = FALSE;
		}
		northing -= initNorthing; easting -= initEasting;
		sprintf(buf, "[%g, %g, %g, %g, %g, %g, %g, %g, %g]",
			northing, easting, _pressureDepth,
			_kearfott->_scaledNavData.vbodyx,
			_kearfott->_scaledNavData.vbodyy,
			_kearfott->_scaledNavData.vbodyz,
			_kearfott->_scaledNavData.prate,
			_kearfott->_scaledNavData.qrate,
			_kearfott->_scaledNavData.rrate);
		_rockSocket->broadcast(buf, (unsigned int)strlen(buf));
		//_winfrogList->InsertItem(0, buf);
		//printf(buf);
		//printf("\n\r");

	}

}

void CpcdasDlg::updateGian()
{
	if (_gianSocket) _gianSocket->broadcast(&(_kearfott->_scaledNavData), sizeof(_kearfott->_scaledNavData));
}


//2 byte project code 0x3d03
//1 byte version 1
//3 doubles - temp (C), salinity (PSU), pressure (dbar)
void CpcdasDlg::update3D()
{
char buf[27];
char *ptr;

	if (_3DSocket) {
		buf[0] = 0x03; buf[1] = 0x3d; buf[2] = 0x01;
        ptr = buf+3;
		double value = _ctdTemp;
		memcpy(ptr, &value, sizeof(double)); ptr += sizeof(double);
		value = _ctdSalinity;
		memcpy(ptr, &value, sizeof(double)); ptr += sizeof(double);
		value = _pressureDepth;
		memcpy(ptr, &value, sizeof(double)); ptr += sizeof(double);
		_3DSocket->sending(buf, ptr-buf);
	}
}

BOOL CpcdasDlg::getParosciData() {
	char buf[41];
    int nbytes = 0;
    double pressure;

	if (_parosciPort.ReadDataWaiting() ) {
		do {
			nbytes = _parosciPort.ReadData(buf, 1);
		} while (buf[0] != '*');

		do {
			nbytes += _parosciPort.ReadData(buf+nbytes, 40-nbytes);
		} while (nbytes != 40 && buf[nbytes-1] != 0x0a);
		//nbytes = _parosciPort.ReadData(buf+1, 13);
        if (nbytes == 40) return FALSE;
		if (strncmp("*0001", buf, 5) || buf[nbytes-1] != 0x0a ) {
			_pressureValid = FALSE;
			return FALSE;
		}
		if (sscanf(buf+6, "%lf", &pressure) != 1) {
			_pressureValid = FALSE;
			return FALSE;
		}

		//pressure = pressure/.6838530; //pressure in PSI
		//pressure = pressure * 0.068948; //pressure now in bar
		
		//convert to meters SW
		double dbar, C, gr;
		static double st2, init_pressure;
		static int first=1;
		if (first) // calc & store sin^2(latitude)
			{
			st2 = sin ( degToRad(37.0));
			st2 *= st2;
			init_pressure = .97;
			first = 0;
			}
		//convert to dbar
		dbar = _pressureDbar = 10*(pressure - init_pressure);
		C = (((-1.8200e-15*dbar + 2.279e-10)*dbar - 2.5212e-05)*dbar + 9.72659)
			* dbar;
		gr = 9.780318*((2.3600e-05*st2 + 5.2788e-3)*st2 + 1) + 1.092e-06*dbar;

		_pressureDepth = C/gr;
		_pressureValid = TRUE;
		return TRUE;
	}

	return FALSE;
}

double CpcdasDlg::calcSalinity(double conductivity, // S/m * 10 (see PSS 1978 notes)
			     double temp,         // degrees C
			     double pressure)     // decibars
{
  double cond_35_15_0 = 42.914;
  double A1 = 0.0000207;
  double A2 = -6.370e-10;
  double A3 = 3.989e-15;
  double B1 = 0.03426;
  double B2 = 0.0004464;
  double B3 = 0.4215;
  double B4 = -0.003107;
  double c0 = 0.6766097;
  double c1 = 0.0200564;
  double c2 = 0.0001104259;
  double c3 = -6.9698e-7;
  double c4 = 1.0031e-9;

  double a0 = 0.0080;
  double a1 = -0.1692;
  double a2 = 25.3851;
  double a3 = 14.0941;
  double a4 = -7.0261;
  double a5 = 2.7081;
  double b0 = 0.0005;
  double b1 = -0.0056;
  double b2 = -0.0066;
  double b3 = -0.0375;
  double b4 = 0.0636;
  double b5 = -0.0144;
  double k = 0.0162;

  double R = conductivity / cond_35_15_0;
  double Rp = 1 + (pressure*(A1 + A2*pressure + A3*pressure*pressure))
                         / (1 + B1*temp + B2*temp*temp + B3*R + B4*R*temp);
  double rT = c0 + c1*temp + c2*temp*temp + c3*pow(temp,3) + c4*pow(temp,4);
  double Rt = R / (Rp*rT);
  double Rtx = sqrt(Rt);

//  double salA = a0*pow(Rt,0.5) + a1*pow(Rt,0.5) + a2*pow(Rt,0.5) + a3*pow(Rt,0.5)
//                               + a4*pow(Rt,0.5) + a5*pow(Rt,0.5);
//  double salB = b0*pow(Rt,0.5) + b1*pow(Rt,0.5) + b2*pow(Rt,0.5) + b3*pow(Rt,0.5)
//                               + b4*pow(Rt,0.5) + b5*pow(Rt,0.5);

   double salA = a0 +
                 a1*Rtx + 
                 a2*Rtx*Rtx + 
                 a3*Rtx*Rtx*Rtx + 
                 a4*Rtx*Rtx*Rtx*Rtx +
                 a5*Rtx*Rtx*Rtx*Rtx*Rtx;
   double salB = b0 +
		 b1*Rtx +
		 b2*Rtx*Rtx +
	 	 b3*Rtx*Rtx*Rtx +
		 b4*Rtx*Rtx*Rtx*Rtx +
		 b5*Rtx*Rtx*Rtx*Rtx;
  double t_factor = (temp - 15)/(1 + k*(temp - 15));
  double sal = salA + t_factor*salB;

  return sal;
}

BOOL CpcdasDlg::getCTDData() {
	char buf[80];
    int nbytes = 0;
    int ntokens;

	memset((void *)buf, 0, 80);
	nbytes = _ctdSocket->receiveDatagram(buf, 80);
	if (nbytes < 0) return FALSE;
	ntokens = sscanf(buf,"%f, %f, %f, %f, %f, %f, %f", &_ctdTemp, &_ctdCond, &_ctdPress, &_ctdV1, &_ctdV2, &_ctdV3, &_ctdV4);
	if (ntokens != 7) {
		return FALSE;
	} else {
		_ctdSalinity = calcSalinity(10.0*_ctdCond, _ctdTemp, _ctdPress);
		return TRUE;
	}
}

BOOL CpcdasDlg::getWinfrogData()
{
	if (_winfrogPort.ReadDataWaiting()) {
		int nbytes = 0;
		do {
			nbytes = _winfrogPort.ReadData(_usblData, 1);
		} while (_usblData[0] != '$');
		do {
			nbytes += _winfrogPort.ReadData(_usblData+nbytes, 256-nbytes);
		} while (nbytes != 256 && _usblData[nbytes-1] != 0x0a);

        if (nbytes == 256) return FALSE;
        _usblData[nbytes] = 0x00;

		char msgType[10];
		char n = ' ', w = ' ', *wf = 0;
		int hh = 0, mm = 0, latdd = 0, longdd = 0;
		float ss = 0, latmm = 0, longmm = 0, slant = 0, dum = 0.;
		int oldData;
		int _usblhh, _usblmm;
		float _usblss, _usblSlant;

		wf = strdup(_usblData);
		int ntokens = sscanf(wf, "%6s,%2d%2d%f,%2d%f,%c,%3d%f,%c,%f,%f,%f,%f,%f,%f",
							 msgType,&_usblhh,&_usblmm,&_usblss,
							 &latdd,&latmm,&n,&longdd,&longmm,&w,&dum,&dum,&dum,&dum,&dum,&_usblSlant);
		free((void*)wf);
		if (ntokens == 16) {
			_usblLat = latdd + (latmm/60.f);
			if (n == 'S') _usblLat = 0.f - _usblLat;
			_usblLon = longdd + (longmm/60.f);
			if (w == 'W') _usblLon = 0.f - _usblLon;
		    if ((_latLonCBox.GetState() & 0x003)) {
				_usblValid = TRUE;
			} else {
				_usblValid = FALSE;
				return FALSE;
			}
			return _usblValid;
		}
	return FALSE;
	}
return FALSE;
}

void CpcdasDlg::OnTimer(UINT nIDEvent)
{
static int _cnt = 0;

	// Check for messages from the parosci and send to reson as necessary
	if (_parosciConnected) {
		if (getParosciData()&& _reson7K) {
			char resonBuffer[20];
			char *ptr = resonBuffer;
			U8 depthDesc = 0, corrFlag = 0;
			U16 reserved = 0;
			F32 __fval = (F32)_pressureDepth;
			memcpy((void*)ptr, &depthDesc, sizeof(U8)); ptr += sizeof(U8);
			memcpy((void*)ptr, &corrFlag, sizeof(U8)); ptr += sizeof(U8);
			memcpy((void*)ptr, &reserved, sizeof(U16)); ptr += sizeof(U16);
			memcpy((void*)ptr, &__fval, sizeof(F32)); // depth
			_reson7K->MB_RemoteCommand(Reson6046Command::Depth, resonBuffer);
			update3D();
		}
	}

	if (_ctdConnected) {
		if (getCTDData()) {
			_salinityValid = TRUE; _salinity = _ctdSalinity;
		} else {
			_salinityValid = FALSE;
		}
	}

	// Check for messages from winfrog
	if (_winfrogConnected) {
		if (getWinfrogData()) {
			_winfrogList->InsertItem(0, _usblData);
		}
	}

	// Check for messages from the kearfott, do any external aiding, send to reson as needed
	if (_kearfottConnected) {
		int kearfottStat;
		do {
			kearfottStat = _kearfott->run();
			if (kearfottStat == 2) {
				updateReson7k();
				updateRock();
				updateGian();
			}
		} while (kearfottStat != 0);

		if (_kearfott->_ggaValid) {
			_gpsList->InsertItem(0, _kearfott->_ggaStr);
			_kearfott->_ggaValid = FALSE;
		}
	}

	if (_cnt++ == 45) {
		int value = _gpsAidEnableCBox.GetState();
		if ((_gpsAidEnableCBox.GetState() & 0x003)) {
			_gpsAidEnable = TRUE;
		} else {
			_gpsAidEnable = FALSE;
		}
		if ((_dopAidEnableCBox.GetState() & 0x003)) {
			_dopAidEnable = TRUE;
		} else {
			_dopAidEnable = FALSE;
		}
		if ((_dopPingEnableCBox.GetState() & 0x003)) {
			_dopPingEnable = TRUE;
		} else {
			_dopPingEnable = FALSE;
		}
		_dopPingEnable = _dopAidEnable = TRUE;

		if (_kearfottConnected) {
			updateKearfottGUI();
			//external updates to Kearfott
			_kearfott->updateExternalSensors(
			_usblValid, _usblLat, _usblLon,
			_pressureValid, _pressureDepth,
			_salinityValid, _salinity,
			_gpsAidEnable, _dopAidEnable, _dopPingEnable);
		}

		if (_parosciConnected && _pressureValid) {
			//update pressure in list box
			char buf1[20];
			sprintf(buf1,"%lf", _pressureDepth);
			_parosciList->InsertItem(0, buf1);
		}

        _usblValid = FALSE;
		_pressureValid = FALSE;
		_salinityValid = FALSE;
		
		_cnt = 0;
	}
}

void CpcdasDlg::OnBnClickedresonAddrSet()
{
	// TODO: Add your control notification handler code here
	CString s;
	GetDlgItemText(IDC_resonIPAddrs, s);
    _reson7K = new Reson7K((char *)(LPCTSTR)s);
	if (_reson7K->_mbDataSocket->ready())
		_resonAddrBtn.SetColor(BLK_TEXT, GRN_BUTTON);
}

void CpcdasDlg::OnBnClickedRockAddrSet()
{
	// TODO: Add your control notification handler code here
	CString s;
	GetDlgItemText(IDC_rockIPAddrs, s);

	if (!_rockSocket) _rockSocket = new SimpleSocket();
	(void)_rockSocket->createBroadcastDatagramSend(7000, (char *)(LPCTSTR)s);
	if (_rockSocket->ready()) {
		_rockAddrBtn.SetColor(BLK_TEXT, GRN_BUTTON);
		_zeroRock = TRUE;
	}
}

void CpcdasDlg::OnBnClicked3DAddrSet()
{
	CString s;
	GetDlgItemText(IDC_3DipAddress, s);
	if (_3DSocket) delete _3DSocket;
	_3DSocket = new SimpleSocket();
	(void)_3DSocket->createConnectedStreamClient(2003,(char *)(LPCTSTR)s);
	if (_3DSocket->ready()) _3DAddrBtn.SetColor(BLK_TEXT, GRN_BUTTON);
}

void CpcdasDlg::OnBnClickedGianAddrSet()
{
	CString s;
	GetDlgItemText(IDC_GianipAddress, s);
	if (_gianSocket) delete _gianSocket;
	_gianSocket = new SimpleSocket();
	(void)_gianSocket->createBroadcastDatagramSend(1975,(char *)(LPCTSTR)s);
	if (_gianSocket->ready()) _gianAddrBtn.SetColor(BLK_TEXT, GRN_BUTTON);
}

void CpcdasDlg::OnBnClickedOk()
{
	// TODO: Add your control notification handler code here
	OnOK();
	delete _kearfott;
	ExitProcess(1);
}

void CpcdasDlg::OnIpnFieldchangedIpaddress2(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMIPADDRESS pIPAddr = reinterpret_cast<LPNMIPADDRESS>(pNMHDR);
	// TODO: Add your control notification handler code here
	*pResult = 0;
}

void CpcdasDlg::OnBnClickedGianaddrset()
{
	// TODO: Add your control notification handler code here
}
