// motordlg.cpp : implementation file
//

#include "stdafx.h"
#include "resource.h"
#include "types.h"
#include "instrumentcfg.h"
#include "axis.h"
#include "cal.h"
#include "atod.h"
#include "errorlog.h"
#include "datamgr.h"
#include "encoder.h"
#include "motiondef.h"
#include "configfile.h"
#include "dmcwin.h"
#include "MotorIndicator.h"
#include "motordlg.h"
#include "..\include\motordlg.h"

Boolean CMotorDlg::_bitmapsLoaded = FALSE;
CBitmap CMotorDlg::_flsBitmap;
CBitmap CMotorDlg::_rlsBitmap;
CBitmap CMotorDlg::_homeBitmap;
CBitmap CMotorDlg::_clrBitmap;
CBitmap CMotorDlg::_stopBitmap;
CBitmap CMotorDlg::_goBitmap;
CBitmap CMotorDlg::_rPosBitmap;
CBitmap CMotorDlg::_rNegBitmap;
CBitmap CMotorDlg::_zPosBitmap;
CBitmap CMotorDlg::_zNegBitmap;
CBitmap CMotorDlg::_ledOffBitmap;
CBitmap CMotorDlg::_ledOnBitmap;

static int CALLBACK
PositionListSort(LPARAM lp1, LPARAM lp2, LPARAM list)
{
   CListCtrl* pListCtrl = (CListCtrl*) list;
   CString    strItem1 = pListCtrl->GetItemText(lp1, 3);
   CString    strItem2 = pListCtrl->GetItemText(lp2, 3);

   return strcmp(strItem1, strItem2);
}

/////////////////////////////////////////////////////////////////////////////
// CMotorDlg dialog
/////////////////////////////////////////////////////////////////////////////
CMotorDlg::CMotorDlg(CWnd* pParent, Axis *zAxis, Nat16 zid, Axis *rAxis,
					 Nat16 rid, AtoD *pAtoD)
	: CDialog(CMotorDlg::IDD, pParent)
	, _jogZPosition(0)
	, _jogRPosition(0)
	, _indicatorR(0)
	, _indicatorZ(0)
	, _ctrlCommand("")
	, _ctrlOutput("")
	, _increment(0)
	, _connectBitmap(0)
	, _pDataMgr(0)
	,_plChanged(FALSE)
	,_lightsOn(FALSE)
	,_cameraOn(FALSE)
	,_lasersOn(FALSE)
	,_dorissOn(FALSE)
	,_initHome(FALSE)
{
	//{{AFX_DATA_INIT(CMotorDlg)
	//_jogIncrement = 16500;
	//}}AFX_DATA_INIT

	CString s;
	_zaxis = zAxis;
	_raxis = rAxis;
	_zmotor = (Motor *)zAxis;
	_rmotor = (Motor *)rAxis;
	_zmotorID = zid;
	_rmotorID = rid;
	_atod = pAtoD;
	_allAxes.Format("%c %c", _zmotor->channel()->axis,
		                     _rmotor->channel()->axis);



	MotionChannel *c = _zmotor->channel();
	_servo = (CDMCWin *)c->motiondriver;
	m_pDialog = pParent;	

	
	if (!_bitmapsLoaded) {
		// First CMotorDlg constructed must load static bitmaps
		_clrBitmap.LoadBitmap(IDB_CLRBMP);
		_flsBitmap.LoadBitmap(IDB_FLSBMP);
		_rlsBitmap.LoadBitmap(IDB_RLSBMP);
		_homeBitmap.LoadBitmap(IDB_HOMEBMP);
		_stopBitmap.LoadBitmap(IDB_STOPBMP);
		_goBitmap.LoadBitmap(IDB_GOBMP);
		_rPosBitmap.LoadBitmap(IDB_RPOSARROW);
		_rNegBitmap.LoadBitmap(IDB_RNEGARROW);
		_zPosBitmap.LoadBitmap(IDB_ZPOSARROW);
		_zNegBitmap.LoadBitmap(IDB_ZNEGARROW);
		_ledOnBitmap.LoadBitmap(IDB_LED_ON);
		_ledOffBitmap.LoadBitmap(IDB_LED_OFF);
		_bitmapsLoaded = TRUE;
	}
	_indicatorZ = 
		new CMotorIndicator(IDC_STATUS_LED, _zmotor, this, IDB_LED_OFF, IDB_LED_ON);
	_indicatorR = 
		new CMotorIndicator(IDC_STATUS_LED, _rmotor, this, IDB_LED_OFF, IDB_LED_ON);

}
CMotorDlg::~CMotorDlg()
{
	if (_indicatorR) delete _indicatorR;
	if (_indicatorZ) delete _indicatorZ;
}


void CMotorDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CMotorDlg)
//	DDX_Text(pDX, IDC_DESIREDPOS, _jogIncrement);
	//}}AFX_DATA_MAP
//	DDX_Text(pDX, IDC_DESIREDPOSZ, _jogZPosition);
//	DDX_Text(pDX, IDC_DESIREDPOSR, _jogRPosition);
//	DDV_MinMaxLong(pDX, _jogRPosition, 0, 250000);
//	DDV_MinMaxLong(pDX, _jogZPosition, 0, 250000);
//	DDV_MinMaxInt(pDX, _jogIncrement, 0, 250000);
}


BEGIN_MESSAGE_MAP(CMotorDlg, CDialog)
	//{{AFX_MSG_MAP(CMotorDlg)
	ON_WM_TIMER()
	ON_BN_CLICKED(IDC_JOG, OnJog)
	ON_BN_CLICKED(IDC_FINDHOME, OnFindHome)
	ON_BN_CLICKED(IDC_STOP, OnStop)
	ON_WM_CLOSE()
	ON_COMMAND_RANGE(IDC_POSMAP0, IDC_POSMAP4, OnIncrementSelect)
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_ZNEG, OnBnClickedZneg)
	ON_BN_CLICKED(IDC_ZPOS, OnBnClickedZpos)
	ON_BN_CLICKED(IDC_RPOS, OnBnClickedRpos)
	ON_BN_CLICKED(IDC_RNEG, OnBnClickedRneg)
	ON_EN_CHANGE(IDC_CON_INPUT, OnEnChangeConInput)
	ON_COMMAND_RANGE(IDC_POSMAP5, IDC_POSMAP9, OnSpeedSelect)
	ON_BN_CLICKED(IDC_STOREPOSITION, OnBnClickedStoreposition)
	ON_BN_CLICKED(IDC_RECALLPOSITION, OnBnClickedRecallposition)
	ON_BN_CLICKED(IDC_DELETEPOSITION, OnBnClickedDeleteposition)
	ON_BN_CLICKED(IDC_LIGHTS, OnBnClickedLights)
	ON_BN_CLICKED(IDC_CAMERA, OnBnClickedCamera)
	ON_BN_CLICKED(IDC_LASERS, OnBnClickedLasers)
	ON_EN_CHANGE(IDC_INCREMENT, OnEnChangeIncrement)
	ON_EN_KILLFOCUS(IDC_INCREMENT, OnEnKillfocusIncrement)
	ON_NOTIFY(NM_DBLCLK, IDC_POSITIONLIST, OnNMDblclkPositionlist)
	ON_BN_CLICKED(IDC_DORISS, OnBnClickedDoriss)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMotorDlg message handlers

BOOL CMotorDlg::OnInitDialog() 
{
Nat16 i;
char text[50];
CWnd *pWnd;
CString s;
Int32 cnt = 0;
int initCnts = 0;
Axis::jogMapType type;

	s.Format("MOTION CONTROL DIALOG");

	SetWindowText(s);

	// Place bitmaps on buttons
	//
	SendDlgItemMessage(IDC_STOP, BM_SETIMAGE,IMAGE_BITMAP, (LPARAM)(HBITMAP)_stopBitmap);
	SendDlgItemMessage(IDC_JOG, BM_SETIMAGE,IMAGE_BITMAP, (LPARAM)(HBITMAP)_goBitmap);
	SendDlgItemMessage(IDC_FINDHOME, BM_SETIMAGE,IMAGE_BITMAP, (LPARAM)(HBITMAP)_homeBitmap);
	SendDlgItemMessage(IDC_RPOS, BM_SETIMAGE,IMAGE_BITMAP, (LPARAM)(HBITMAP)_rPosBitmap);
	SendDlgItemMessage(IDC_RNEG, BM_SETIMAGE,IMAGE_BITMAP, (LPARAM)(HBITMAP)_rNegBitmap);
	SendDlgItemMessage(IDC_ZPOS, BM_SETIMAGE,IMAGE_BITMAP, (LPARAM)(HBITMAP)_zPosBitmap);
	SendDlgItemMessage(IDC_ZNEG, BM_SETIMAGE,IMAGE_BITMAP, (LPARAM)(HBITMAP)_zNegBitmap);

	// Initialize actuator positions
	//
	//OnFindHome();

	// Associate increment buttons to motor maps
	//
	for(i=0;i<NUM_POS_MAPS;i++){

		_zaxis->getPosMap(i, text, &cnt, &type);

		if (i == 2)
		{
			// Save the middle option for initialization later
			//
			initCnts = cnt;
		}
		pWnd = GetDlgItem(IDC_POSMAP0 + i);
		if(pWnd != NULL){
			pWnd->EnableWindow(FALSE);	
			if(text != NULL){
				pWnd->SetWindowText(text);		
				pWnd->EnableWindow(TRUE);	
			}
		}

	}

	// Initiailize non-editable fields
	//
	s.Format("%d", _zmotor->encoder()->cntsPerUnit());	
	SetDlgItemText(IDC_CNTSPERUNIT,s);	

	s.Format("%4.1f", cntsTomm(_zmotor->encoder()->cnts()));
	SetDlgItemText(IDC_ACTUALPOSZ,s);	
	s.Format("%d", _zmotor->getPosErr());	
	SetDlgItemText(IDC_POS_ERRZ, s);	

	s.Format("%4.1f", cntsTomm(_rmotor->encoder()->cnts()));
	SetDlgItemText(IDC_ACTUALPOSR,s);	
	s.Format("%d",0);
	SetDlgItemText(IDC_POS_ERRR,s);	

	// Initiailize editable fields
	//
	s.Format("%-4.1f", 0.0);
	SetDlgItemText(IDC_DESIREDPOSZ, s);	
	SetDlgItemText(IDC_DESIREDPOSR, s);	

	// Initialize increment to 1mm (1613counts)
	// and motor speed to 5mm/sec
	//
	CheckRadioButton(IDC_POSMAP0, IDC_POSMAP4, IDC_POSMAP2);
	s.Format("%3.1f",cntsTomm(initCnts));
	SetDlgItemText(IDC_INCREMENT, s);
	_increment = cntsTomm(initCnts);

	CheckRadioButton(IDC_POSMAP5, IDC_POSMAP9, IDC_POSMAP8);
	OnSpeedSelect(IDC_POSMAP8);

	CListCtrl *list = (CListCtrl*)GetDlgItem(IDC_POSITIONLIST);
	list->InsertColumn(0, "Name", LVCFMT_LEFT, 100);
	list->InsertColumn(1, "Z Pos", LVCFMT_LEFT, 42);
	list->InsertColumn(2, "R Pos", LVCFMT_LEFT, 42);
	list->InsertColumn(3, "Date", LVCFMT_LEFT, 150);

	// Read the saved positions from the position file
	//
	ConfigItemWrapper positionItem;
	if (OK ==_plf.initialize("positions.dat"))
	{
		for (int li = 0; _plf.getItemByIndex(li, positionItem); li++)
		{
			// The position name is first in the GUI list
			//
			list->InsertItem(LVIF_TEXT, li, positionItem()->parm(2), 0,0,0,0);

			list->SetItemText(li, 1, positionItem()->parm(0));
			list->SetItemText(li, 2, positionItem()->parm(1));

			// The timestamp is used to ensure uniqueness in the config file,
			// but is shown on the far right in the GUI list
			list->SetItemText(li, 3, positionItem()->name());
		}
	}
	else
		ErrorLog::logError("Unable to open position list file");

	_nTimer = SetTimer(1,500,NULL); //~1/2 second

	// Set up data logging stuff
	//
	_pDataMgr = DataManager::instance();

	if (DATA_OK != _pDataMgr->create(_zposDITEM, "ZPos Counts", DATA_INT32,
		sizeof(Int32)))
		ErrorLog::logError("Failure to create Z cnts DATAITEM");

	if (DATA_OK != _pDataMgr->create(_zmmDITEM, "ZPos mm", DATA_FLT32,
		sizeof(Flt32)))
		ErrorLog::logError("Failure to create Z mm DATAITEM");

	if (DATA_OK != _pDataMgr->create(_rposDITEM, "RPos Counts", DATA_INT32,
		sizeof(Int32)))
		ErrorLog::logError("Failure to create R cnts DATAITEM");

	if (DATA_OK != _pDataMgr->create(_rmmDITEM, "RPos mm", DATA_FLT32,
		sizeof(Flt32)))
		ErrorLog::logError("Failure to create R mm DATAITEM");

	if (DATA_OK != _pDataMgr->create(_tiltXDITEM, "X Tilt", DATA_FLT64,
		sizeof(Flt64)))
		ErrorLog::logError("Failure to create Tilt X DATAITEM");

	if (DATA_OK != _pDataMgr->create(_tiltYDITEM, "Y Tilt", DATA_FLT64,
		sizeof(Flt64)))
		ErrorLog::logError("Failure to create Tilt Y DATAITEM");

	if (DATA_OK != _pDataMgr->create(_tempDITEM, "Temperature", DATA_FLT64,
		sizeof(Flt64)))
		ErrorLog::logError("Failure to create Temperature DATAITEM");

	if (DATA_OK != _pDataMgr->create(_pressDITEM, "Pressure", DATA_FLT64,
		sizeof(Flt64)))
		ErrorLog::logError("Failure to create Pressure DATAITEM");

	if (DATA_OK != _pDataMgr->create(_humidDITEM, "Humidity", DATA_FLT64,
		sizeof(Flt64)))
		ErrorLog::logError("Failure to create Humiditiy DATAITEM");

	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

void CMotorDlg::UpdateBitmap(UINT id, CBitmap & bitmap)
{
	BITMAP bmp;
	CWnd* pWnd;	
	CDC* pDC;
	CDC DC;

	bitmap.GetBitmap(&bmp);

	pWnd = GetDlgItem(id);
	if(pWnd != NULL && &bmp != NULL)
	{
		pDC = pWnd->GetDC();
		DC.CreateCompatibleDC(pDC);
		DC.SelectObject(bitmap);			
		pDC->BitBlt(0,0,bmp.bmWidth,bmp.bmHeight,&DC, 0, 0, SRCCOPY);
		ReleaseDC(pDC);		
	}
}


void CMotorDlg::UpdateStatus()
{
	CString s;
	// Update motor positions
	//

	// Z axis position
	//
	Int32 data32 = _zmotor->encoder()->cnts();
	_pDataMgr->write(_zposDITEM, &data32, sizeof(data32));

	Flt32 pmm = cntsTomm((long)data32);
	_pDataMgr->write(_zposDITEM, &pmm, sizeof(pmm));
	s.Format("%4.1f", pmm);
	SetDlgItemText(IDC_ACTUALPOSZ, s);

	// R Axis position
	//
	data32 = _rmotor->encoder()->cnts();
	_pDataMgr->write(_rposDITEM, &data32, sizeof(data32));

	pmm = cntsTomm((long)data32);
	_pDataMgr->write(_rposDITEM, &pmm, sizeof(pmm));
	s.Format("%4.1f", pmm);			
	SetDlgItemText(IDC_ACTUALPOSR, s);

	// Don't update error positions if we're jogging
	//
	if (!_zmotor->jogging())
	{
		s.Format("%d", _zmotor->getPosErr());	
		SetDlgItemText(IDC_POS_ERRZ, s);	
	}
	if (!_rmotor->jogging())
	{
		s.Format("%d", _rmotor->getPosErr());	
		SetDlgItemText(IDC_POS_ERRR, s);
	}

	// Update environmental sensor windows
	//
	BOOL connected = FALSE;  // If any one of the following atod
	                         // calls succeed, we're connected

	// Water sensor
	//
	Flt64 val = 0.;
	if (_atod->readChan(ATOD_WATER, &val) == 0)
	{
		connected = TRUE;
		if (val < 1.0)
			s.Format("%s", "No");
		else
			s.Format("%s", "Yes");
	}
	else
		s.Format("%s", "Error");
	SetDlgItemText(IDC_WATER, s);

	// X Tilt
	//
	val = 0.;
	if (_atod->readChan(ATOD_TILTX, &val) == 0)
	{
		connected = TRUE;
		s.Format("%3.1f", val);
	}
	else
		s.Format("%s", "Error");
	SetDlgItemText(IDC_TILTX, s);
	_pDataMgr->write(_tiltXDITEM, &val, sizeof(val));

	// Y Tilt
	//
	val = 0.;
	if (_atod->readChan(ATOD_TILTY, &val) == 0)
	{
		connected = TRUE;
		s.Format("%3.1f", val);
	}
	else
		s.Format("%s", "Error");
	SetDlgItemText(IDC_TILTY, s);
	_pDataMgr->write(_tiltYDITEM, &val, sizeof(val));

	// Temp
	//
	val = 0.;
	if (_atod->readChan(ATOD_TEMP, &val) == 0)
	{
		connected = TRUE;
		s.Format("%3.1f", val);
	}
	else
		s.Format("%s", "Error");
	SetDlgItemText(IDC_TEMP, s);
	_pDataMgr->write(_tempDITEM, &val, sizeof(val));

	// Pressure
	//
	val = 0.;
	if (_atod->readChan(ATOD_PRESSURE, &val) == 0)
	{
		connected = TRUE;
		s.Format("%3.2f", val);
	}
	else
		s.Format("%s", "Error");
	SetDlgItemText(IDC_PRESSURE, s);
	_pDataMgr->write(_pressDITEM, &val, sizeof(val));

	// Humidity
	//
	val = 0.;
	if (_atod->readChan(ATOD_HUMIDITY, &val) == 0)
	{
		connected = TRUE;
		s.Format("%3.0f", val);
	}
	else
		s.Format("%s", "Error");
	SetDlgItemText(IDC_HUMIDITY, s);
	_pDataMgr->write(_humidDITEM, &val, sizeof(val));

	CBitmap *bm;
	if (connected)
		bm = &_ledOnBitmap;
	else
		bm = &_ledOffBitmap;  // change back

	// If connect status changed, then switch the bitmap
	//
	//if (bm != _connectBitmap)
	{
		CWnd *canvas = GetDlgItem(IDC_CONNECT_LED);
		if(canvas != NULL)
		{
			CDC *pDC = canvas->GetDC();
			CDC dC;
			dC.CreateCompatibleDC(pDC);
			dC.SelectObject(bm);
			BITMAP bmp;	
			bm->GetBitmap(&bmp);
			pDC->BitBlt(0, 0, bmp.bmWidth, bmp.bmHeight, &dC, 0, 0, SRCCOPY);
			ReleaseDC(pDC);
			_connectBitmap = bm;
		}
	}

	// If in the process of homing, see if we're finished...
	//
	if (_initHome)
	{
		char resp[128];
		double r = 0.;
		int stat = _servo->Command("MGX", resp, sizeof(resp));
		r = atof(resp);

		// Homing script sets 'X' variable to one when finished
		//
		if (r > 0.1)
		{
			_initHome = FALSE;
			_rmotor->jogAbsolute(_rmotor->encoder()->cnts());
			_zmotor->jogAbsolute(_zmotor->encoder()->cnts());
		}
	}

	// Update bitmaps
	if(_zaxis->foundHome())
		UpdateBitmap(IDC_HOME_BITMAP, CMotorDlg::_homeBitmap);				

	UpdateStopCode();
	if (_rmotor->jogging())
		_indicatorR->update();
	else
		_indicatorZ->update();

}


void CMotorDlg::UpdateStopCode()
{
	int stopCode;
	if ((stopCode = _zmotor->getStopCode()) > 0) 
	{
		switch (stopCode) {

			case MOTOR_STOP_BY_FLS:
			UpdateBitmap(IDC_FLS_BITMAP, CMotorDlg::_flsBitmap);		
			break;

			case MOTOR_STOP_BY_RLS:
			UpdateBitmap(IDC_RLS_BITMAP, CMotorDlg::_rlsBitmap);		
			break;

			default:
			UpdateBitmap(IDC_FLS_BITMAP, CMotorDlg::_clrBitmap);
			UpdateBitmap(IDC_RLS_BITMAP, CMotorDlg::_clrBitmap);		
			UpdateBitmap(IDC_HOME_BITMAP, CMotorDlg::_clrBitmap);
			break;
		}
	}

}


void CMotorDlg::OnPaint() 
{
	UpdateStatus();
}

void CMotorDlg::OnTimer(UINT nIDEvent) 
{
	UpdateStatus();
}


void CMotorDlg::OnJog() 
{
	// Get info from dialog and check that desired position is within
	// configured range.
	//
	if (_initHome && IDYES == ContinueHome())
		return;

	UpdateData(TRUE);
	CString posString;
	GetDlgItemText(IDC_DESIREDPOSZ, posString);
	double rpos, zpos = atof(posString);
	posString.Format("%4.1f", zpos);
	SetDlgItemText(IDC_DESIREDPOSZ, posString);

	double maxRange = DEFAULT_AXIS_Z_MAX_RANGE; // Use default if not in config

	InstrumentCfg* config = _zaxis->getConfig();
	if (config != NULL)
	{
		ConfigItemWrapper item;
		if (config->searchForConfigItem("AXISZ.RANGE", item))
		{
			maxRange = atof(item()->parm(0));  // Use configured range
		}
	}

	// Don't move actuators if out of range
	//
	if ( zpos < 0 || zpos > maxRange )
	{
		MessageBox("Target Z position out of range", "Z Axis Range Error");
		return;
	}
	_jogZPosition = mmToCnts(zpos);

	GetDlgItemText(IDC_DESIREDPOSR, posString);
	rpos = atof(posString);
	posString.Format("%4.1f", rpos);
	SetDlgItemText(IDC_DESIREDPOSR, posString);

	maxRange = DEFAULT_AXIS_R_MAX_RANGE;  // Init to default range

	config = _raxis->getConfig();
	if (config != NULL)
	{
		ConfigItemWrapper item;
		if (config->searchForConfigItem("AXISR.RANGE", item))
		{
			maxRange = atof(item()->parm(0));   // Use configured range
		}
	}

	// Don't move actuators if desired position out of range
	//
	if ( rpos < 0 || rpos > maxRange )
	{
		MessageBox("Target R position out of range", "R Axis Range Error");
		return;
	}
	_jogRPosition = mmToCnts(rpos);

	// Everything checks out, so move
	//
	char msg[64];
	sprintf(msg, "PUP Gui::Commanding Z Motor to %4.1fmm and R Motor to %4.1fmm",
		zpos, rpos);
	ErrorLog::logMsg(msg);
	if (_zmotor->encoder()->cnts() != _jogZPosition)
		_zmotor->jogAbsolute((Int32 )_jogZPosition);
	if (_rmotor->encoder()->cnts() != _jogRPosition)
		_rmotor->jogAbsolute((Int32 )_jogRPosition);

}

void CMotorDlg::OnFindHome() 
{
	// Return if already homing...
	//
	if (!_initHome)
		_initHome = TRUE;
	else
		return;

	_rmotor->jogAbsolute(_rmotor->encoder()->cnts());
	_zmotor->jogAbsolute(_zmotor->encoder()->cnts());

	CString homeFile;
	int stat=0;

	homeFile.Format("%s%s", CONFIG_DIR, "HOME.dmc");
	ErrorLog::logMsg("PUP Gui: Downloding and executing HOME.DMC");
	stat = _servo->DownloadFile(homeFile);
	stat = _servo->Command("XQ#HOME,0");

}

void CMotorDlg::OnStop() 
{
	// If in the process of homing, stop the script running on the controler
	//
	if (_initHome)
	{
		int stat = _servo->Command("ST");
		_initHome = FALSE;
		Sleep(500);
	}

	ErrorLog::logMsg("PUP Gui: Commanding motor controller to STOP");
	_zmotor->stop();
	_rmotor->stop();
	UpdateStatus();
}

void CMotorDlg::OnIncrementSelect(UINT nID) 
{
	Nat16 index = (Nat16) nID - IDC_POSMAP0;				//calc index
	Int32 pos = _zmotor->encoder()->cnts();
	Int32 mapCnt;
	Axis::jogMapType type;

	_zaxis->getPosMap(index, NULL, &mapCnt, &type);		//get abosolute cnt from pos map

	if(type == Axis::ABSOLUTE_JOG)
		_increment = cntsTomm(mapCnt - pos);				//calc jog increment; 0-2 maps
	else
		_increment = cntsTomm(mapCnt);					//calc jog increment ccw/cw increment

	CString s;
	s.Format("%3.1f", _increment);
	SetDlgItemText(IDC_INCREMENT, s);

	UpdateData(FALSE);
}

void CMotorDlg::OnClose() 
{
	KillTimer(_nTimer);
	if(m_pDialog != NULL)
		m_pDialog->PostMessage(WM_MODELESSEXIT,IDD_MOTOR_DIALOG, _zmotorID);					

	if (_plChanged)
	{
//		if (IDOK == MessageBox("Save Changes to Position List?", NULL,
//				MB_OKCANCEL | MB_DEFBUTTON1))
		{
			_plf.write();
		}
	}
	CDialog::OnClose();
}


void CMotorDlg::OnBnClickedZneg()
{
	// TODO: Add your control notification handler code here
	if (_initHome && IDYES == ContinueHome())
		return;

	UpdateData(TRUE);

	float targetPos = cntsTomm((long)(_zmotor->encoder()->cnts())) - _increment;
	if (targetPos < 0 || targetPos > DEFAULT_AXIS_Z_MAX_RANGE )
	{
		MessageBox("Target Z position out of range", "Z Axis Range Error");
		return;
	}

	char msg[64];
	sprintf(msg, "PUP Gui: Commanding Z Motor to %4.1fmm", targetPos);
	ErrorLog::logMsg(msg);
	_zmotor->jogRelative((Int32)mmToCnts(0 - _increment));
}

void CMotorDlg::OnBnClickedZpos()
{
	// TODO: Add your control notification handler code here
	if (_initHome && IDYES == ContinueHome())
		return;

	UpdateData(TRUE);

	float targetPos = cntsTomm((long)(_zmotor->encoder()->cnts())) + _increment;
	if (targetPos < 0 || targetPos > DEFAULT_AXIS_Z_MAX_RANGE )
	{
		MessageBox("Target Z position out of range", "Z Axis Range Error");
		return;
	}

	char msg[64];
	sprintf(msg, "PUP Gui::Commanding Z Motor to %4.1fmm", targetPos);
	ErrorLog::logMsg(msg);
	_zmotor->jogRelative((Int32 )mmToCnts(_increment));
}

void CMotorDlg::OnBnClickedRpos()
{
	// TODO: Add your control notification handler code here
	if (_initHome && IDYES == ContinueHome())
		return;

	UpdateData(TRUE);

	float targetPos = cntsTomm((long)(_rmotor->encoder()->cnts())) + _increment;
	if (targetPos < 0 || targetPos > DEFAULT_AXIS_R_CNTS_PER_MM )
	{
		MessageBox("Target R position out of range", "R Axis Range Error");
		return;
	}

	char msg[64];
	sprintf(msg, "PUP Gui::Commanding R Motor to %4.1fmm", targetPos);
	ErrorLog::logMsg(msg);
	_rmotor->jogRelative((Int32 )mmToCnts(_increment));
}

void CMotorDlg::OnBnClickedRneg()
{
	// TODO: Add your control notification handler code here
	if (_initHome && IDYES == ContinueHome())
		return;

	UpdateData(TRUE);

	float targetPos = cntsTomm((long)(_rmotor->encoder()->cnts())) - _increment;
	if (targetPos < 0 || targetPos > DEFAULT_AXIS_R_MAX_RANGE )
	{
		MessageBox("Target R position out of range", "R Axis Range Error");
		return;
	}

	char msg[64];
	sprintf(msg, "PUP Gui::Commanding R Motor to %4.1fmm", targetPos);
	ErrorLog::logMsg(msg);
	_rmotor->jogRelative((Int32 )mmToCnts(0 - _increment));
}

void CMotorDlg::OnEnChangeConInput()
{
	char szDataResponse[256];
	CEdit* pEdit = (CEdit*)GetDlgItem(IDC_CON_INPUT);
	CString InputString;
	pEdit->GetWindowText(InputString);

	// After the user hits the Enter key, send the
	// command to the controller and echo the
	// controller's response.
	//
	CString TempString = InputString.Right(1); // Get last char
	if (TempString.Compare("\n") == 0)
	{
		MotionChannel *c = _zmotor->channel();
		CDMCWin *servo = (CDMCWin *)c->motiondriver;

		char msg[64];
		sprintf(msg, "PUP Gui::Commanding %s through command box", _ctrlCommand);
		ErrorLog::logMsg(msg);
		_servo->Command((char*)((const char*)_ctrlCommand),
			szDataResponse, sizeof(szDataResponse));
		UpdateCmdOutputWnd(szDataResponse);
		_ctrlCommand = "";
	}
	else
	{
		_ctrlCommand.Append(TempString); // Add last char to command
	}
}

// Write the text string to the Command output window
//
void CMotorDlg::UpdateCmdOutputWnd(const char * text)
{
	CEdit *pEdit;
	char CRLF[3];
	CRLF[0] = 13;
	CRLF[1] = 10;
	CRLF[2] = '\0';
	pEdit = (CEdit*)GetDlgItem(IDC_CON_OUTPUT);
	_ctrlOutput.Append(text);
	_ctrlOutput.Append(CRLF);

	pEdit->SetWindowText((const char*)_ctrlOutput);
	pEdit->LineScroll(100000);
}


void CMotorDlg::OnSpeedSelect(UINT nID)
{
	float mmPer = 0.0;
	switch(nID) {
		case IDC_POSMAP5:
			mmPer = 0.5;
			break;

		case IDC_POSMAP6:
			mmPer = 1.0;
			break;

		case IDC_POSMAP7:
			mmPer = 5.0;
			break;

		case IDC_POSMAP8:
			mmPer = 10.0;
			break;

		case IDC_POSMAP9:
			mmPer = 15.0;
			break;

		default:
			break;
	}

	if (mmPer > 0.0)
	{
		_zmotor->setSpeedmm(mmPer);
		_rmotor->setSpeedmm(mmPer);
	}
}

float CMotorDlg::cntsTomm(long cnts)
{
	InstrumentCfg* config = _zaxis->getConfig();
	if (config == NULL)
		return 0;

	ConfigItemWrapper item;
	if (!config->searchForConfigItem("AXISZ.CNTSPERMM", item))
		return 0;

	double cntspermm = atof(item()->parm(0));

	float mm = (float)cnts / cntspermm;
	return mm;
}

long CMotorDlg::mmToCnts(float mm)
{
	InstrumentCfg* config = _zaxis->getConfig();
	if (config == NULL)
		return 0;

	ConfigItemWrapper item;
	if (!config->searchForConfigItem("AXISZ.CNTSPERMM", item))
		return 0;

	double cntspermm = atof(item()->parm(0));

	float cnts = mm * cntspermm;//(float)DEFAULT_AXIS_Z_CNTS_PER_MM;
	return (long)cnts;
}

void CMotorDlg::OnBnClickedStoreposition()
{
	// Capture the R and Z positions, prompt user for name
	CString z, r, pname;
	GetDlgItemText(IDC_NEWPOSITION, pname);
	GetDlgItemText(IDC_ACTUALPOSZ, z);
	GetDlgItemText(IDC_ACTUALPOSR, r);
	pname.Trim(" ");
	z.Trim(" ");
	r.Trim(" ");

	if (pname.GetLength() <= 0)
	{
		MessageBox("Position must have a name");
		return;
	}

	long now;
	time(&now);
	struct tm *_tm = localtime(&now);
	CString timestamp(ctime(&now));
	timestamp.TrimRight("\n");

	const char** argv = (const char**)malloc(3*sizeof(char*));
	argv[0] = strdup(z);
	argv[1] = strdup(r);
	argv[2] = strdup(pname);
	ConfigItem *cfgitem = new ConfigItem(timestamp, 3, argv);

	for (int i = 0; i < 3; i++)
		free((void*)argv[i]);
	free(argv);

	// If added to the config file OK, then show it on the GUI list
	//
	if (_plf.addCfgItem(cfgitem))
	{
		CListCtrl *list = (CListCtrl*)GetDlgItem(IDC_POSITIONLIST);
		int n = list->GetItemCount();
		list->InsertItem(n, pname);
		list->SetItemText(n, 1, z);
		list->SetItemText(n, 2, r);
		list->SetItemText(n, 3, timestamp);
		_plChanged = TRUE;
	}
	pname = "";
	SetDlgItemText(IDC_NEWPOSITION, pname);
}

void CMotorDlg::OnBnClickedRecallposition()
{
	// Place Z and R values of selected position
	// into the desired Z and R controls
	//
	CListCtrl *list = (CListCtrl*)GetDlgItem(IDC_POSITIONLIST);
	int sel = list->GetSelectionMark();

	if (sel >= 0)
	{
		SetDlgItemText(IDC_DESIREDPOSZ, list->GetItemText(sel, 1));
		SetDlgItemText(IDC_DESIREDPOSR, list->GetItemText(sel, 2));
	}
}

void CMotorDlg::OnBnClickedDeleteposition()
{
	// Delete the selected stored position
	CListCtrl *list = (CListCtrl*)GetDlgItem(IDC_POSITIONLIST);
	int sel = list->GetSelectionMark();

	if (sel >= 0)
	{
		CString pname = list->GetItemText(sel, 0);

		CString prompt("Delete Stored Position \"" + pname + "\"?");
		if (IDOK == MessageBox(prompt, "Delete Position",
			MB_OKCANCEL | MB_DEFBUTTON2) )
		{
			if (_plf.removeItem(list->GetItemText(sel,3)))
			{
				list->DeleteItem(sel);
				_plChanged = TRUE;
			}
		}
	}
}

void CMotorDlg::OnBnClickedLights()
{
	// If lights are off, turn them on. Otherwise, turn them off
	int op = _lightsOn? 0 : 2000;
	char *newText = _lightsOn? "Turn Lights On" : "Turn Lights Off";
	ErrorLog::logMsg("PUP Gui: Light switch pressed");

	// Keep the other appliances the same
	op += _lasersOn? 400 : 0;
	op += _cameraOn? 1000 : 0;
	op += _dorissOn? 1 : 0;

	CString cmd;
	cmd.Format("OP$%d", op);

	int err = _servo->Command(cmd);
	if (DMCNOERROR == err)
	{
		SetDlgItemText(IDC_LIGHTS, newText);
		_lightsOn = _lightsOn? FALSE : TRUE;
	}
	else
		ErrorLog::logError("Light switch command not accepted by controller");
}

void CMotorDlg::OnBnClickedCamera()
{
	// If camera is off, turn it on. Otherwise, turn it off
	int op = _cameraOn? 0 : 1000;
	char *newText = _cameraOn? "Turn Camera On" : "Turn Camera Off";
	ErrorLog::logMsg("PUP Gui: Camera switch pressed");

	// Keep the other appliances the same
	op += _lasersOn? 400 : 0;
	op += _lightsOn? 2000 : 0;
	op += _dorissOn? 1 : 0;

	CString cmd;
	cmd.Format("OP$%d", op);
	_servo->Command(cmd);

	if (DMCNOERROR == _servo->Command(cmd))
	{
		SetDlgItemText(IDC_CAMERA, newText);
		_cameraOn = _cameraOn? FALSE : TRUE;
	}
	else
		ErrorLog::logError("Camera switch command not accepted by controller");
}

void CMotorDlg::OnBnClickedLasers()
{
	// If lasers are off, turn them on. Otherwise, turn them off
	int op = _lasersOn? 0 : 400;
	char *newText = _lasersOn? "Turn Lasers On" : "Turn Lasers Off";
	ErrorLog::logMsg("PUP Gui: Laser switch pressed");
	// Keep the other appliances the same
	op += _lightsOn? 2000 : 0;
	op += _cameraOn? 1000 : 0;
	op += _dorissOn? 1 : 0;

	CString cmd;
	cmd.Format("OP$%d", op);
	_servo->Command(cmd);

	if (DMCNOERROR == _servo->Command(cmd))
	{
		SetDlgItemText(IDC_LASERS, newText);
		_lasersOn = _lasersOn? FALSE : TRUE;
	}
	else
		ErrorLog::logError("Laser switch command not accepted by controller");
}

void CMotorDlg::OnEnChangeIncrement()
{
	// TODO:  If this is a RICHEDIT control, the control will not
	// send this notification unless you override the CDialog::OnInitDialog()
	// function and call CRichEditCtrl().SetEventMask()
	// with the ENM_CHANGE flag ORed into the mask.

	// TODO:  Add your control notification handler code here
}

void CMotorDlg::OnEnKillfocusIncrement()
{
	// TODO: Add your control notification handler code here
	CString incString;
	GetDlgItemText(IDC_INCREMENT, incString);
	double inc = atof(incString);
	incString.Format("%4.1f", inc);

	_increment = inc;
}

void CMotorDlg::OnNMDblclkPositionlist(NMHDR *pNMHDR, LRESULT *pResult)
{
	// TODO: Add your control notification handler code here
	OnBnClickedRecallposition();
	*pResult = 0;
}

int CMotorDlg::ContinueHome()
{
	if (!_initHome)
		return IDNO;

	int resp = AfxMessageBox("Homing in process. Continue homing?", MB_YESNO);
	if (resp == IDNO)
	{
		OnStop();
	}
	return resp;
}
void CMotorDlg::OnBnClickedDoriss()
{
	// If DORISS is off, turn it on. Otherwise, turn it off
	int op = _dorissOn? 0 : 1;
	char *newText = _dorissOn? "Turn DORISS On" : "Turn DORISS Off";

	// Keep the other appliances the same
	op += _lightsOn? 2000 : 0;
	op += _cameraOn? 1000 : 0;
	op += _lasersOn? 400  : 0;

	CString cmd;
	cmd.Format("OP$%d", op);
	_servo->Command(cmd);

	if (DMCNOERROR == _servo->Command(cmd))
	{
		SetDlgItemText(IDC_DORISS, newText);
		_dorissOn = _dorissOn? FALSE : TRUE;
	}
	else
		ErrorLog::logError("DORISS switch command not accepted by controller");
}
