#include "gimbaldata.h"
#include "comm.h"
#include "operatorDialog.h"
#include <sys/timeb.h>
#include <qglobal.h>
#include <stdio.h>

//	-----------------------------------------------------------
//	Globals
//	-----------------------------------------------------------

	extern int newOperatorSettings;
	extern int shift;

//	-----------------------------------------------------------
//	Globals
//	-----------------------------------------------------------

	controls_t controls;

	unsigned int camRecordReq;
	unsigned int shutdownRedReq;
	unsigned int shutdownStandbyReq;
	unsigned int shutdownPiReq;
	unsigned int targetReq;
	unsigned int altReq;
	unsigned int steerAltReq;

//	-----------------------------------------------------------
//	Globals
//	-----------------------------------------------------------

	const char *DL_bool[] = {"False","True",""};
	const char *DL_onoff[] = {"Off","On",""};
	const char *DL_plot[] = {PLOT_STRINGSx,""};
	const char *DL_filt[] = {FILT_STRINGSx,""};
	const char *DL_bd[] = {BD_STRINGS,""};
	const char *DL_mode[] = {MODE_STRINGS,""};
	const char *DL_modeX[] = {MODEX_STRINGS,""};
	const char *DL_ModeX[] = {MODEX_STRCAPS,""};
	const char *DL_omode[] = {OSEQ_STRINGS,""};
	const char *DL_type[] = {TYPE_STRINGS,""};
	const char *DL_axes[] = {"Yaw","Pitch","Roll",""};
	const char *DL_nrv[] = {"Norm","Rev",""};

//	----------------------------------------------------------------------------
//	macros
//	----------------------------------------------------------------------------

	#define _max(a,b)  (((a) > (b)) ? (a) : (b))
	#define _min(a,b)  (((a) < (b)) ? (a) : (b))

//	-----------------------------------------------------------
//	Global Functions
//	-----------------------------------------------------------

	extern void setAltitude(double alt);
	extern void setTarget(double lat, double lon, double alt);
	extern void setTarget(double (*lla)[3]);
	extern void saveSettings();
	extern void setL1();
	extern void setL2();

//	----------------------------------------------------------------------------
//	messageLen
//	----------------------------------------------------------------------------

int messageLen(int id){

	switch(id)
	{
		MESSAGE_LENGTH_CASES
	};
	return 0;
}

//	----------------------------------------------------------------------------
//	gimbalData (Construct)
//	----------------------------------------------------------------------------

gimbalData::gimbalData(QObject *parent):QThread(parent)
{
//	memset(&steering,0,sizeof(steering));
	memset(&state,0,sizeof(state));
	memset(&bwRes,0,sizeof(bwRes));
	memset(&bwPar,0,sizeof(bwPar));
	memset(guiIpAddress,0,sizeof(guiIpAddress));
	memset(guiComPort,0,sizeof(guiComPort));
	memset(imuBuf,0,sizeof(imuBuf));
	memset(imuBuf2,0,sizeof(imuBuf2));
	memset(&jscmd,0,sizeof(jscmd));
	memset(&jsbutton,0,sizeof(jsbutton));
	memset(&lensCommand,0,sizeof(lensCommand));
	guiConnect = 0;
	guiReconnect = 0;
	guiIpPort = 0;
	guiBaud = 0;
	connected = 0;
	connectedX = 0;
	hwmode = 0;
	gimbalPresent = 0;
	quit = 0;
	gim = NULL;
	cons = NULL;
	imuBufIndex = 0;
	logAddress = 0;
	idTbl = 0;
	utilityTbl = 0;
	controlsTbl = 0;
	steeringTbl = 0;
	steeringAxisTbl = 0;
	controlsAxisTbl = 0;
	stateGyroTbl = 0;
	stateCommTbl = 0;
	stateNavTbl = 0;
	stateGeoTbl = 0;
	stateInputTbl = 0;
	stateAxisTbl = 0;
	stateOuterCmd = 0;
	stateOuterFb = 0;
	stateOdinTbl = 0;
	navboxTbl = 0;
	masterStatusTbl = 0;
	bwParTbl = 0;
	bwResTbl = 0;
	pidPTbl = 0;
	filtP0Tbl = 0;
	filtP1Tbl = 0;
	filtP2Tbl = 0;
	outerPTbl = 0;
	geoPTbl = 0;
	posPTbl = 0;
	lensPTbl = 0;
	gimReadoutsTbl = 0;
	operControlsTbl = 0;
	operSettingsTbl = 0;
	joystickTbl = 0;
	consInputTbl = 0;
	lensFeedbackTbl = 0;
	cmdAutonull = 0;
	cmdGeo = 0;
	memset(editVString,0,sizeof(editVString));
	editKey = 0;
	editAxis = 0;
	editFilt = 0;
	editPar = 0;
	editType = 0;
#if defined(_CONSOLE)
	controlsReady = 1;
#else
	controlsReady = 0;
#endif
	refPidPTbl = 0;
	refFiltP0Tbl = 0;
	refFiltP1Tbl = 0;
	refFiltP2Tbl = 0;
	refOuterPTbl = 0;
	refGeoPTbl = 0;
	refPosPTbl = 0;
	refLensPTbl = 0;
	initRef = 1;

	#if defined(_CINE)
		steeringOut.connect = 1;
		for(int i=0;i<NiAXES;i++){
			steeringOut.axis[i].sinAmp = 2;
			steeringOut.axis[i].sinFreq = 2;
			steeringOut.axis[i].remote = 1;
			steeringOut.axis[i].enable = 1;
			steeringOut.axis[i].enableO = 1;
		}
		steeringOut.standby = 1;
		steeringOut.unused = 0x1234;
	#endif
}

//	----------------------------------------------------------------------------
//	~gimbalData
//	----------------------------------------------------------------------------

gimbalData::~gimbalData()
{
//	mutex.lock();
	quit = true;
//	cond.wakeOne();
//	mutex.unlock();
//	wait();
}

//	----------------------------------------------------------------------------
//	run
//	----------------------------------------------------------------------------

void gimbalData::run()
{
	QTcpSocket *socket = new QTcpSocket;
	QSerialPort *serial = new QSerialPort;
	gim = new comm(socket,serial);

	QSerialPort *serial2 = new QSerialPort;
	cons = new comm(NULL,serial2);

	initDatabase();

	connect(gim, SIGNAL(error(int,QString)),this, SLOT(sendCommError(int,QString)));
	while(!quit){
		pollGimbalRx();
	}
	gim->closePort();
	cons->closePort();
}

//	----------------------------------------------------------------------------
//	Sleep
//	----------------------------------------------------------------------------

void gimbalData::Sleep(int millisec){
	usleep(millisec*1000);
}

//	----------------------------------------------------------------------------
//	parseGyro
//	----------------------------------------------------------------------------

void gimbalData::parseGyro(unsigned char *m,int len)
{
	static int16_t count = 0;
	msgGyroBuf_t *g = (msgGyroBuf_t *)m;

	if(len != sizeof(msgGyroBuf_t)){
		util.gyroBuffErr++;
		return;
	}

	if(g->head.count == count){
		util.gyroBuffErr++;
		return;
	}
	count = g->head.count;

	util.gyroBuffGood++;
	g->head.count = 0;
	g->head.id = 0;

	for(int ii=0;ii<NSAMP;ii++){
		if(imuBufIndex<(uint32_t)IMU_BUF_COUNT){
			float vmax = g->maxval;
			float vmin = g->minval;
			float k = (vmax-vmin)/65535.0f;
			float fval = (float)(g->samples[ii]);
			imuBuf2[ii] = vmin + k*fval;
			imuBufIndex++;
		}
	}

	int i1 = NSAMP;
	int i2 = IMU_BUF_COUNT;
	int i3 = i2-i1;

	size_t s1 = NSAMP*sizeof(float);
	size_t s2 = sizeof(imuBuf);
	size_t s3 = s2-s1;

	memcpy(imuBuf,&imuBuf[i1],s3);
	memcpy(&imuBuf[i3],imuBuf2,s1);

	if(imuBufIndex<IMU_BUF_COUNT){
		emit newImuData();
	}else{
		imuBufIndex = 0;
		memset(imuBuf2,0,sizeof(imuBuf2));
		emit newImuData();
	}
	emit newTableData(MSG_UTIL);
	dbase.newTableData(utilityTbl);
}

//	----------------------------------------------------------------------------
//	parseControls
//	----------------------------------------------------------------------------

void gimbalData::parseControls(unsigned char *m,int len)
{
	if(len != sizeof(msgControls_t))return;

	msgControls_t *mc = (msgControls_t *)m;

	if(different(&(controls),&(mc->controls),sizeof(controls))){
		dbase.newTableData(controlsTbl);
		dbase.newTableData(controlsAxisTbl);
	}
	controls = mc->controls;
	if(!controlsReady){
		controlsReady = 1;
		#if defined(_CINE)
			steeringOut.mode = mc->controls.mode;
			steeringOut.standby = mc->controls.standby;
			for(int i=0;i<NiAXES;i++){
				steeringOut.axis[i].sinAmp = mc->controls.axis[i].sinAmp;
				steeringOut.axis[i].sinFreq = mc->controls.axis[i].sinFreq;
				steeringOut.axis[i].remote = mc->controls.axis[i].remote;
				steeringOut.axis[i].enable = mc->controls.axis[i].enable;
				steeringOut.axis[i].enableO = mc->controls.axis[i].enableO;
			}
		#endif
		emit errorx(0,0,"controls received");
	}
}

//	----------------------------------------------------------------------------
//	parseState
//	----------------------------------------------------------------------------

void gimbalData::parseState(unsigned char *m,int len)
{
	if(len != sizeof(msgState_t))return;

	msgState_t *ms = (msgState_t *)m;

	state = ms->state;
	emit newTableData(ms->head.id);
	dbase.newTableData(idTbl);
	dbase.newTableData(stateGyroTbl);
	dbase.newTableData(stateCommTbl);
	dbase.newTableData(stateNavTbl);
	dbase.newTableData(stateGeoTbl);
	dbase.newTableData(stateInputTbl);
	dbase.newTableData(stateAxisTbl);
	dbase.newTableData(stateOuterCmd);
	dbase.newTableData(stateOuterFb);
	dbase.newTableData(lensFeedbackTbl);
	dbase.newTableData(stateOdinTbl);
	dbase.newTableData(navboxTbl);

	for(int i=0;i<3;i++){
		extern float innerDrive[3];
		innerDrive[i] += 0.01f*(state.axis[i].drive-innerDrive[i]);
	}
}

//	----------------------------------------------------------------------------
//	parseMasterStatus
//	----------------------------------------------------------------------------

void gimbalData::parseMasterStatus(unsigned char *m,int len)
{
	if(len != sizeof(msgNavToGim_t))return;

	msgNavToGim_t *ms = (msgNavToGim_t *)m;
	dbase.newTableData(masterStatusTbl);

	masterStatus = ms->nav;

}

//	----------------------------------------------------------------------------
//	parseLog
//	----------------------------------------------------------------------------

void gimbalData::parseLog(unsigned char *m,int len)
{
	if(len != sizeof(msgLog_t))return;

	msgLog_t *ms = (msgLog_t *)m;
	log_t *entry = (log_t *)(&ms->entry);
	emit errorx(0,1,entry->s);
}

//	----------------------------------------------------------------------------
//	parseConsInput
//	----------------------------------------------------------------------------

void gimbalData::parseConsInput(unsigned char *m,int len)
{
	if(len != sizeof(msgConsInput_t))return;

	msgConsInput_t *ms = (msgConsInput_t *)m;

//	if(different(&(consInput),&(ms->consInput),sizeof(consInput))){
		consInput = ms->consInput;
		if(!consInputRxCount)emit errorx(0,0,"consInput received");
		consInputRxCount++;
		emit newTableData(ms->head.id);
		dbase.newTableData(consInputTbl);
//	}
}

//	----------------------------------------------------------------------------
//	parseBwPar
//	----------------------------------------------------------------------------

void gimbalData::parseBwPar(unsigned char *m,int len)
{
	if(len != sizeof(msgBwPar_t))return;

	msgBwPar_t *mc = (msgBwPar_t *)m;
	if(different(&(bwPar),&(mc->bwPar),sizeof(bwPar))){
		dbase.newTableData(bwParTbl);
	}
	bwPar = mc->bwPar;
}

//	----------------------------------------------------------------------------
//	parseBwRes
//	----------------------------------------------------------------------------

void gimbalData::parseBwRes(unsigned char *m,int len)
{
	if(len != sizeof(msgBwRes_t))return;

	msgBwRes_t *mc = (msgBwRes_t *)m;
	if(different(&(bwRes),&(mc->bwRes),sizeof(bwRes))){
		dbase.newTableData(bwResTbl);
	}
	bwRes = mc->bwRes;
//	parseBwx();
}

//	----------------------------------------------------------------------------
//	parseTunings
//	----------------------------------------------------------------------------

void gimbalData::parseTunings(unsigned char *m,int len)
{
	int expectedLen = sizeof(msgTunings_t);

	if(len==expectedLen){

		msgTunings_t *tt = (msgTunings_t *)m;
		tunings_t *t = &(tt->t);


		int dif1 = different(&(gimTun.pidP),&(t->pidP),sizeof(	gimTun.pidP));

		int dif2 = different(&(gimTun.filt.filtP),&(t->filtP),sizeof( gimTun.filt.filtP));
		int dif3 = different(&(gimTun.outerP),&(t->outerP),sizeof( gimTun.outerP));
		int diff[3] = {
			different(&(gimTun.filt.filtP[0]),&(t->filtP[0]),sizeof( gimTun.filt.filtP[0])),
			different(&(gimTun.filt.filtP[1]),&(t->filtP[1]),sizeof( gimTun.filt.filtP[1])),
			different(&(gimTun.filt.filtP[2]),&(t->filtP[2]),sizeof( gimTun.filt.filtP[2]))
		};
		int dif4 = different(&(gimTun.geoP ),&(t->geoP ),sizeof(	gimTun.geoP ));
		int dif5 = different(&(gimTun.posP ),&(t->posP ),sizeof(	gimTun.posP ));
		int dif6 = different(&(gimTun.lensP),&(t->lensP),sizeof(	gimTun.lensP));

		int dif = dif1 | dif2 | dif3 | dif4 | dif5| dif6;

		if(dif){
			for(int i=0;i<NiAXES;i++){
				gimTun.pidP[i] = t->pidP[i];
				gimTun.geoP[i] = t->geoP[i];
				gimTun.posP[i] = t->posP[i];
				for(int f=0;f<NiFILT;f++){
					gimTun.filt.filtP[i][f] = t->filtP[i][f];
				}
				if(diff[i]){
					gimTun.filt.initFilters(i);
					gimTun.filterBode(i,NiFILT);
				}
			}
			emit newTuneData();
		}

		for(int i=0;i<NoAXES;i++){
			gimTun.outerP[i] = t->outerP[i];
		}

		for(int i=0;i<NLENS;i++){
			gimTun.lensP[i] = t->lensP[i];
		}

		if(dif){
			dbase.newTableData(pidPTbl);
			dbase.newTableData(filtP0Tbl);
			dbase.newTableData(filtP1Tbl);
			dbase.newTableData(filtP2Tbl);
			dbase.newTableData(outerPTbl);
			dbase.newTableData(geoPTbl);
			dbase.newTableData(posPTbl);
			dbase.newTableData(lensPTbl);
			if(initRef){
				refTun.copy(gimTun);
				dbase.newTableData(refPidPTbl);
				dbase.newTableData(refFiltP0Tbl);
				dbase.newTableData(refFiltP1Tbl);
				dbase.newTableData(refFiltP2Tbl);
				dbase.newTableData(refOuterPTbl);
				dbase.newTableData(refGeoPTbl);
				dbase.newTableData(refPosPTbl);
				dbase.newTableData(refLensPTbl);
				initRef = 0;
			}
		}
	}
}

//	----------------------------------------------------------------------------
//	parseMsgX
//	----------------------------------------------------------------------------

int gimbalData::parseMsgX(unsigned char *m,int len)
{
	if(len<8)return 0;
	msgGyroBuf_t *g = (msgGyroBuf_t *)m;
	int cmd = g->head.id;
	if(len != messageLen(cmd))return 0;
	switch(cmd){
	case MSG_GYRO:			parseGyro(m,len);			break;
	case MSG_GYRO2:			parseGyro(m,len);			break;
	case MSG_TUNINGS:		parseTunings(m,len);		break;
	case MSG_CONTROLS:		parseControls(m,len);		break;
	case MSG_STATE:			parseState(m,len);			break;
	case MSG_BW_PAR:		parseBwPar(m,len);			break;
	case MSG_BW_RES:		parseBwRes(m,len);			break;
	case MSG_CONS_INPUT:	parseConsInput(m,len);		break;
	case MSG_NAV_TO_GIM:	parseMasterStatus(m,len);	break;
	case MSG_LOG:			parseLog(m,len);			break;
	}
	return 1;
}

//	----------------------------------------------------------------------------
//	commandCheck
//	----------------------------------------------------------------------------

int gimbalData::commandCheck(msgHeader_t *h, uint32_t *len, uint32_t maxlen)
{
	if(messageLen(h->id)){
		if( (messageLen(h->id)) == (int)(h->len) ){
			*len = (h->len);
			return (h->id);
		}else{
			*len = 0;
			return 0;
		}
	}else{
		if( maxlen >= (h->len) ){
			*len = (h->len);
			return (h->id);
		}else{
			*len = 0;
			return 0;
		}
	}
}

//	----------------------------------------------------------------------------
//	different
//	----------------------------------------------------------------------------

int gimbalData::different(void *a,void *b,int len)
{
	char *aa = (char *)a;
	char *bb = (char *)b;
	for(int i=0;i<len;i++){
		if(*aa++ != *bb++){
			return 1;
		}
	}
	return 0;
}

//	---------------------------------------------------------------------------
//	guiConnectReq
//	---------------------------------------------------------------------------

void gimbalData::guiConnectReq(int newstate)
{
	guiConnect = newstate;
	guiReconnect = 1;
}

//	---------------------------------------------------------------------------
//	connectx
//	---------------------------------------------------------------------------

void gimbalData::connectx(int newstate,int reconnect)
{
	while(gim == NULL){
		Sleep(100);
	}

	guiConnect = newstate;

	switch(newstate){
	case CONNECT_232:
		if((reconnect)||(connectedX!=newstate)){
			hwmode = 1;
			emit connectedState(2,"Opening COM");
			if(!gim->openPort(guiComPort,guiBaud,0)){
				connectedX = newstate;
				gimbalPresent = -1;
				gim->wait = 1;
				emit connectedState(1,"COM Opened");
			}else{
				connectedX = CONNECT_FAIL;
				emit connectedState(3,"COM Open Failed");
				Sleep(1000);
			}
		}else{
			if(!(gim->isConnected()))connectedX = CONNECT_FAIL;
		}
		break;
	case CONNECT_LAN:
		if((reconnect)||(connectedX!=newstate)){
			hwmode = 1;
			emit connectedState(2,"Opening LAN");
			if(!gim->openPort(guiIpAddress,0,guiIpPort)){
				emit connectedState(1,"LAN Connected");
				connectedX = newstate;
				gimbalPresent = -1;
			}else{
				connectedX = CONNECT_FAIL;
				emit connectedState(3,"LAN Connect Fail");
				Sleep(1000);
			}
		}else{
			if(!(gim->isConnected()))connectedX = CONNECT_FAIL;
		}
		break;
	case CONNECT_NONE:
		if(connectedX!=newstate){
			emit connectedState(0,"Disconnected");
			connectedX = newstate;
		}
		gim->closePort();
		break;
	}
	int wasconnected = connected;
	connected = (connectedX==CONNECT_232)||(connectedX==CONNECT_LAN);

	if(connected&&!wasconnected){
		setConnect(1);
	}
}

//	----------------------------------------------------------------------------
//	settings
//	----------------------------------------------------------------------------

void gimbalData::settings(const char *reqIpAddress,const char *reqComPort,int reqIpPort,int reqBaud)
{
	if(strlen(reqIpAddress)<sizeof(guiIpAddress))strcpy(guiIpAddress,reqIpAddress);
	if(strlen(reqComPort)<sizeof(guiComPort))strcpy(guiComPort,reqComPort);
	guiIpPort = reqIpPort;
	guiBaud = reqBaud;
}

//	----------------------------------------------------------------------------
//	message
//	----------------------------------------------------------------------------

unsigned char message[RXBUFLEN];
msgTunings_t *mt = (msgTunings_t *)message;


//	----------------------------------------------------------------------------
//	checkSum
//	----------------------------------------------------------------------------

int checkSum(int len, int *sum1,int *sum2)
{
	int len1 = len - sizeof(msgTail_t);
	msgTail_t *t1 = (msgTail_t *)&(message[len1]);;
	msgTail_t t2;
	t2.checksum = 0;
	unsigned char *msg = message;
	for(int i=0;i<len1;i++){
		t2.checksum += *msg++;
	}
	*sum1 = t1->checksum;
	*sum2 = t2.checksum;
	if(t2.checksum == t1->checksum){
		return 1;
	}else{
		return 0;
	}
}

//	----------------------------------------------------------------------------
//	logSerialFilename
//	----------------------------------------------------------------------------

char *logSerialFilename()
{
	QDate d = QDate::currentDate();
	QTime t = QTime::currentTime();
	int yy,mm,dd;
	d.getDate(&yy,&mm,&dd);
	yy %= 100;
	static char s[120];
	sprintf(s,"log%02i%02i%02i-%02i%02i%02i.dat",yy,mm,dd,t.hour(),t.minute(),t.second());
	return s;
}

//	----------------------------------------------------------------------------
//	logSerial
//	----------------------------------------------------------------------------

#ifdef Q_OS_LINUX
	#define serialLogdir "/media/pi/PVL014/Logs"
#else
	#define serialLogdir "D:/Logs"
#endif

QFile serialLogfile;

//	----------------------------------------------------------------------------
//	logSerial
//	----------------------------------------------------------------------------

inline void logSerial(char c)
{
	const int maxcount = 10*1024*1024;
	static int count = 0;
	static int state = 0;
	static int retry = 0;
	int res = 0;
	if(count >= maxcount){
		serialLogfile.close();
		state = 0;
	}
	switch(state){
	case 0:
		if(!(QDir::setCurrent(serialLogdir))){
			state = 4;
			break;
		}
		serialLogfile.setFileName(logSerialFilename());
		if(serialLogfile.open(QIODevice::WriteOnly)){
			state = 1;
			res = 1;
		}else{
			state = 2;
		}
		count = 0;
		break;
	case 1:
		res = 1;
		break;
	case 2:
		retry = 24000*15;
		state = 3;
		break;
	case 3:
		retry--;
		if(retry<1){
			state = 0;
		}
		break;
	case 4:
		break;
	}

	if(res){
		if(!serialLogfile.putChar(c)){
			serialLogfile.close();
			state = 2;
		}
		count++;
	}
}

//	----------------------------------------------------------------------------
//	getMessage
//	----------------------------------------------------------------------------

int gimbalData::getMessage()
{
	char c;
//	uint8_t cx;
//	static int16_t oldCount = 0;
//	static int fpass = 1;
	static int id = 0;
	static uint32_t len = 0;
	static uint32_t index = 0;
	static int state = 0;
//	static int err1 = 0;
//	static int err2 = 0;
//	static int err3 = 0;
	static int sum1 = 0;
	static int sum2 = 0;
	static int good = 0;
	static int maxlenCount = 0;
//	static int goodCount = 0;
	static int crcCount = 0;

	msgHeader_t *g = (msgHeader_t *)message;
	while(1){
		if(1 != gim->readByte(&c)){
			return 0;
		}
		logSerial(c);
//		cx = c;
		util.totalcount++;
		message[index++] = c;
		switch(state){
		case 0:	// header0
			index = 0;
			message[index++] = c;
			if(c != 0x57){
				state = 0;
				util.err1++;
				if(good)maxlenCount++;
			}else{
				state++;
			}
			good = 0;
			break;
		case 1:	// header1
			if(c != 0x19){
				state = 0;
				index = 0;
				util.err2++;
			}else{
				state++;
			}
			break;

		case  2:	// id0
		case  3:	// id1
		case  4:	// cmd0
		case  5:	// cmd1
		case  6:	// count0
		case  7:	// count1
		case  8:	// len0
		case  9:	// len1
		case 10:	// len2
			state++;
			break;
		case 11:	// len3
			id = commandCheck(g,&len,RXBUFLEN);
			if(id){
				state++;
			}else{
				state = 0;
				index = 0;
				util.err3++;
			}
			break;
		case 12:
			if(index>=len){
				index = 0;
				state = 0;
				if(checkSum(len,&sum1,&sum2)){
					util.goodCount++;
					good = 1;
					return len;
				}else{
					crcCount++;
					good = 0;
					return 0;
				}
			}
			break;
		}
	}
}
#if defined(_UTIL41)

//	---------------------------------------------------------------------------
//	sendEdit
//	---------------------------------------------------------------------------

void gimbalData::sendEdit()
{
}

#else

//	---------------------------------------------------------------------------
//	sendEdit
//	---------------------------------------------------------------------------

void gimbalData::sendEdit()
{
	float f = 0;
	if(editType==0){
		int res = sscanf(editVString,"%a",&f);
		if(res != 1)return;
	}
	if(editAxis<0)return;
	if(editAxis>2)return;

	switch(editKey){
		case key_pGain:
		case key_iGain:
		case key_dGain:
		case key_limit:
		case key_kT:
		case key_kC:{
			if(editAxis>=NiAXES)return;
			pidPar_t pp = gimTun.pidP[editAxis];
			int ipid = pidType(controls.mode);
			switch(editKey){
				case key_pGain:		pp.kP[ipid] = f; break;
				case key_iGain:		pp.kI[ipid] = f; break;
				case key_dGain:		pp.kD[ipid] = f; break;
				case key_limit:		pp.kILim[ipid] = f; break;
				case key_kT:		pp.kT = f; break;
				case key_kC:		pp.kC = f; break;
				default: return;
			}
			return sendPidPar(editAxis,&pp);
		}

		case key_geoKP:
		case key_geoKP2:
		case key_geoKI:
		case key_geoKD:
		case key_geoKILim:
		case key_geoKMys2:{
			if(editAxis>=NiAXES)return;
			tunings_t t;
			loadTunings(&t);
			switch(editKey){
				case key_geoKP:		t.geoP[editAxis].kP = f;		break;
				case key_geoKP2:	t.geoP[editAxis].kP2 = f;		break;
				case key_geoKI:		t.geoP[editAxis].kI = f;		break;
				case key_geoKD:		t.geoP[editAxis].kD = f;		break;
				case key_geoKILim:	t.geoP[editAxis].kILim = f;		break;
				case key_geoKMys2:	t.geoP[editAxis].kMystery2 = f;	break;
				default: return;
			}
			return sendTunings(&t);
		}
	case key_posKP:
	case key_posKD:
	case key_posKLim:{
		if(editAxis>=NiAXES)return;
		tunings_t t;
		loadTunings(&t);
		switch(editKey){
		case key_posKP:		t.posP[editAxis].kP = f;		break;
		case key_posKD:		t.posP[editAxis].kD = f;		break;
		case key_posKLim:	t.posP[editAxis].kLim = f;		break;
			default: return;
		}
		return sendTunings(&t);
	}
		case key_kP:
		case key_kFF:
		case key_kTach:
		case key_kI:
		case key_kILim:
		{
			if(editAxis>=NoAXES)return;
			outerPar_t pp = gimTun.outerP[editAxis];
			switch(editKey){
				case key_kP: pp.kP = f; break;
				case key_kFF: pp.kFF = f; break;
				case key_kTach: pp.kTach = f; break;
				#if defined(_CINE)
				case key_kI: pp.kI = f; break;
				case key_kILim: pp.kILim = f; break;
				#endif
				default: return;
			}
			return sendOuterPar(editAxis,&pp);
		}

		case key_fType:
		case key_fFreq:
		case key_fQ:{
			if(editAxis>=NiAXES)return;
			if(editAxis<0)return;
			if(editFilt>=NiFILT)return;
			if(editFilt<0)return;
			filterPar_t pp = gimTun.filt.filtP[editAxis][editFilt];
			switch(editKey){
				case key_fType: pp.ftype = editPar; break;
				case key_fFreq: pp.f1 = f; break;
				case key_fQ: pp.q = f; break;
				default: return;
			}
			return sendFilterPar(editAxis,editFilt,&pp);
		}
		#if defined(_CINE)
			case key_plotRaw:
			case key_plotVar:
			case key_plotAxis:
			case key_enable:
			case key_remote:
			case key_backdrive:
			case key_sinA:
			case key_sinF:
			case key_desiredPos:
			case key_desiredRate:{
				int aok = (editAxis>=0)&&(editAxis<NiAXES);
				switch(editKey){
					case key_plotRaw:		steeringOut.plotRaw = editPar;	break;
					case key_plotVar:		steeringOut.plotType = editPar; break;
					case key_plotAxis:		steeringOut.plotAxis = editPar; break;
					case key_enable:		if(aok)steeringOut.axis[editAxis].enable = editPar; break;
					case key_remote:		if(aok)steeringOut.axis[editAxis].remote = editPar; break;
					case key_backdrive:		if(aok)steeringOut.axis[editAxis].backdrive = editPar; break;
					case key_sinA:			if(aok)steeringOut.axis[editAxis].sinAmp = f; break;
					case key_sinF:			if(aok)steeringOut.axis[editAxis].sinFreq = f; break;
					case key_desiredPos:	if(aok)steeringOut.axis[editAxis].desiredPos = f; break;
					case key_desiredRate:	if(aok)steeringOut.axis[editAxis].desiredRate = f; break;
					default: return;
				}
			}
		#endif
		cmdSteering = 1;
	}
}

//	----------------------------------------------------------------------------
//	jsscale
//	----------------------------------------------------------------------------

inline float jsscale(float val,float ofs,float kscale,float kdband)
{
	const float klimit = 1.0f;

	float v = kscale*(val-ofs);					// scale and offset
	v -= _max(-kdband,_min(kdband,v));			// deadband
	v = _max(-klimit,_min(klimit,v));			// limit
	return v;
}

//	----------------------------------------------------------------------------
//	steering
//	----------------------------------------------------------------------------

	const float kymax = 0.507f;		// pan
	const float kymin = 0.486f;
	const float kxmax = 0.489f;		// tilt
	const float kxmin = 0.481f;
	const float kzmax = 0.496f;		// roll
	const float kzmin = 0.486f;

	const float kofsx = (kxmax+kxmin)/2;
	const float kofsy = (kymax+kymin)/2;
	const float kofsz = (kzmax+kzmin)/2;

	const float kscalex = 2.2f;
	const float kscaley = kscalex;
	const float kscalez = kscalex;

	const float kdbandx = 0.025f;
	const float kdbandy = kdbandx;
	const float kdbandz = 0.050f;
	const float kofszoom = 0.4952f;

	const float kdbandzoom = 0.0125f;
	const float kscalezoom = 8;

//	----------------------------------------------------------------------------
//	steering
//	----------------------------------------------------------------------------

	int cmdSteering;
	int unwrapReq;
	int unwrapMode;
	float unwrapTarg;
	double unwrapLLA[3];


#if defined(_CINE)

//	----------------------------------------------------------------------------
//	steering
//	----------------------------------------------------------------------------

void gimbalData::steering()
{

	static int consInputRxCountOld = 0;
	int newFrame = (consInputRxCount != consInputRxCountOld);
	consInputRxCountOld = consInputRxCount;

	if(!newFrame)return;
	if(consInputRxCount<100)return;

	joystickT.jsPan  = jsscale(consInput.jsy, kofsy, -kscaley, kdbandy);
	joystickT.jsTilt = jsscale(consInput.jsx, kofsx, -kscalex, kdbandx);
	joystickT.jsRoll = jsscale(consInput.jsz, kofsz,  kscalez, kdbandz);

	joystickT.button1 = (consInput.buttons & 0x1000)?(0):(1);
	joystickT.button2 = (consInput.buttons & 0x2000)?(0):(1);

	float kzmul;
	if(operSettings.zmultOn){
		kzmul = (1.0f-0.9f*gimReadouts.zoom*operSettings.zmultGain);
	}else{
		kzmul = 1;
	}

	float j[3]		= {	joystickT.jsPan,		joystickT.jsTilt,		joystickT.jsRoll		};
	float g[3]		= {	operSettings.panGain,	operSettings.tiltGain,	operSettings.rollGain	};
	float k[3]		= {	60.0f,					60.0f,					60.0f					};
	float zmuls[3]	= {	kzmul,					kzmul,					1.0f					};
	float unwrap[3]	= {	0,						0,						0						};
	uint32_t rev[3]	= {	operSettings.panRev,	operSettings.tiltRev,	operSettings.rollRev	};

	if(shift){
		steerAltReq = 50;
	}

	if(unwrapReq){
		float y = state.axis[0].pos;
		float p = state.axis[1].pos;
		float pt = -60;
		float pr = 30;
		float yr = 60;
		float tol = 20;
		unwrap[1] = (p<pt)?(pr):(0);
		if(unwrapReq == 1){
			unwrap[0] = yr;
			if( y > (unwrapTarg - tol) ){
				unwrapReq = 0;
			}
		}else {
			unwrap[0] = -yr;
			if( y < (unwrapTarg + tol) ){
				unwrapReq = 0;
			}
		}
		if(!unwrapReq){
			setModeX(unwrapMode);
			if(unwrapMode==MODEX_GEO){
				setTarget(&unwrapLLA);
			}
		}
	}else{
		unwrap[0] = 0;
		unwrap[1] = 0;
	}

	for(int i=0;i<NiAXES;i++){
		steeringOut.axis[i].joystick = j[i];
		float desired = k[i]*zmuls[i]*g[i]*j[i] + unwrap[i];
		if(rev[i])desired = -desired;
		steeringOut.axis[i].desiredRate = desired;
	}

	if(operSettings.dynOn){
		steeringOut.dynamic = operSettings.dynGain;
	}else{
		steeringOut.dynamic = 0;
	}

	float fc = 2*(consInput.focus - 0.5f);
	fc = _max(-1,_min(1,fc));
	fc = (operSettings.focusRev)?(fc):(-fc);
	fc *= operSettings.focusGain;
	fc += (1 - operSettings.focusGain);
	steeringOut.focus = fc;

	float ic = 2*(consInput.iris -0.5f);
	ic = _max(-1,_min(1,ic));
	ic = (operSettings.irisRev)?(ic):(-ic);
	steeringOut.iris  = ic;

	float zc = jsscale(consInput.zoom, kofszoom, kscalezoom, kdbandzoom);
	zc = (operSettings.zoomRev)?(-zc):(zc);
	zc *= operSettings.zoomGain;
	steeringOut.zoom = zc;

	const uint16_t mask1 = 0xfff;
	const uint16_t mask2 = 0xff;

	steeringOut.buttons1 = (~consInput.buttons)&mask1;
	steeringOut.buttons2 = ~gimReadouts.buttons&mask2;
	steeringOut.enc1 = consInput.enc1;
	steeringOut.enc2 = consInput.enc2;
	steeringOut.enc3 = consInput.enc3;
	steeringOut.bits |= SB_DRIFT_KNOB;

	const int redbuttonIsCamRecord = 1;
	if(redbuttonIsCamRecord){
		if(steeringOut.buttons2 & b2_red){
			camRecordReq = 2;
		}
	}

	int shift1 = (steeringOut.buttons2 & b2_yel)?(1):(0);
	if(operSettings.encFunction == XYZ_Altitude){
		if(steeringOut.buttons2 & b2_enter)shift1 = 1;
	}
	if(targetReq)shift1 = 1;

	shift = shift1;

	if(camRecordReq){
		steeringOut.bits |= SB_CAM_RECORD;
		camRecordReq--;
	}else{
		steeringOut.bits &= ~SB_CAM_RECORD;
	}

	if(operSettings.encFunction == XYZ_Camera){
		steeringOut.bits |= SB_RED_MENU;
	}else{
		steeringOut.bits &= ~SB_RED_MENU;
	}

	if(shift){
		steeringOut.bits |= SB_SHIFT;
	}else{
		steeringOut.bits &= ~SB_SHIFT;
	}

	int l12button = (steeringOut.buttons2 & b2_grn)?(1):(0);
	static int oldl12button = l12button;
	if(l12button != oldl12button){
		if(l12button){
			setL1();
		}else{
			setL2();
			setModeX(MODEX_GEO);
		}
	}
	oldl12button = l12button;

	static int oldEnc1 = consInput.enc1;
	if(operSettings.encFunction == XYZ_Altitude){
		int delta = consInput.enc1 - oldEnc1;
		if(delta){
			if(shift)delta *= 10;
			operSettings.geoAlt += delta;
			setAltitude(operSettings.geoAlt);
			newOperatorSettings = 1;
		}
	}
	oldEnc1 = consInput.enc1;

	static int oldButton1 = joystickT.button1;
	if( (joystickT.button1) && (!oldButton1) ){
		if(steeringOut.standby){
			setModeX(MODE_RATE);
		}else if(steeringOut.mode == MODE_RATE){
			setModeX(MODE_GEO);
		}else{
			setModeX(MODE_RATE);
		}
	}
	oldButton1 = joystickT.button1;

	cmdSteering = 1;
	dbase.newTableData(joystickTbl);
}

//	---------------------------------------------------------------------------
//	steeringBits
//	---------------------------------------------------------------------------

void gimbalData::steeringBits()
{
	if(	targetReq||altReq||shutdownRedReq||shutdownStandbyReq){
		cmdSteering = 1;
	}

	if(operSettings.jzFunction == JSZ_Altitude){
		steerAltReq = 1;
	}

	if(util.rxConsInputFrame)	{					steeringOut.bits |= SB_CONS_GOOD;	}else{ steeringOut.bits &= ~SB_CONS_GOOD;	}
	if(targetReq)				{ targetReq--;		steeringOut.bits |= SB_LOAD_TARGET;	}else{ steeringOut.bits &= ~SB_LOAD_TARGET;	}
	if(altReq)					{ altReq--;			steeringOut.bits |= SB_LOAD_ALT;	}else{ steeringOut.bits &= ~SB_LOAD_ALT;	}
	if(steerAltReq)				{ steerAltReq--;	steeringOut.bits |= SB_STEER_ALT;	}else{ steeringOut.bits &= ~SB_STEER_ALT;	}

	if(operSettings.geoAid)		{				steeringOut.bits |= SB_GEO_AID;		}else{ steeringOut.bits &= ~SB_GEO_AID;		}

	if(shutdownRedReq){
		steeringOut.bits |= SB_SHUTDOWN_RED;
		shutdownRedReq--;
		if((0==shutdownRedReq)&&(0==shutdownStandbyReq)&&(shutdownPiReq)){
			extern void shutdownPi();
			shutdownPi();
		}
	}else{
		steeringOut.bits &= ~SB_SHUTDOWN_RED;
	}

	if(shutdownStandbyReq){
		setStandby(1);
		shutdownStandbyReq--;
		if(0==shutdownStandbyReq){
			saveSettings();
			if((0==shutdownRedReq)&&(shutdownPiReq)){
				extern void shutdownPi();
				shutdownPi();
			}
		}
	}
}

#else

//	----------------------------------------------------------------------------
//	steering
//	----------------------------------------------------------------------------

void gimbalData::steering(){}

//	---------------------------------------------------------------------------
//	steeringBits
//	---------------------------------------------------------------------------

void gimbalData::steeringBits(){}

#endif
#endif

//	---------------------------------------------------------------------------
//	pollGimbalTx
//	---------------------------------------------------------------------------

void gimbalData::pollGimbalTx()
{
	steering();
	steeringBits();


	if(controlsReady){
		if(cmdSteering){
			cmdSteering = 0;
			sendSteering(&steeringOut);
			dbase.newTableData(steeringTbl);
			dbase.newTableData(steeringAxisTbl);
		}
	}

	if(editKey){
		sendEdit();
		editKey = 0;
	}
}

//	---------------------------------------------------------------------------
//	pollGimbalRx
//	---------------------------------------------------------------------------

void gimbalData::pollGimbalRx()
{
	extern QElapsedTimer mainTime;
	qint64 tStart = mainTime.elapsed();
	static qint64 tLastGood = mainTime.elapsed();
	connectx(guiConnect,guiReconnect);
	guiReconnect = 0;

	int numread = getMessage();
	if(numread){
		tLastGood = mainTime.elapsed();
		parseMsgX(message,numread);
	}else{
		util.pollTimeout = mainTime.elapsed() - tStart;
		if(!connected){
			Sleep(5);
		}else{
			if((mainTime.elapsed() - tLastGood)>3000){
				setConnect(1);
				tLastGood = mainTime.elapsed();
			}
		}
	}
	util.pollGimbalGet = mainTime.elapsed() - tStart;

	pollGimbalTx();

	dbase.newTableData(utilityTbl);

	if(numread){
		QString ss;
		ss.sprintf("steering: %2i   frame: %u",state.comm[0].steering,state.gyro.gyroFrame);
		emit errorx(3, 1, ss);
	}
}

//	----------------------------------------------------------------------------
//	sendPidPar
//	----------------------------------------------------------------------------

void gimbalData::sendPidPar(int axis,pidPar_t *pPidPar)
{
	const msgHeader_t head = {HEADER,MSG_PID_PAR,0,0,sizeof(msgPidPar_t)};
	msgPidPar_t msg;

	msg.head = head;
	msg.axis = axis;
	msg.pidPar = *pPidPar;
	sendMsg((msgHeader_t *)&msg);
	msg.head.count++;
}

//	----------------------------------------------------------------------------
//	sendOuterPar
//	----------------------------------------------------------------------------

void gimbalData::sendOuterPar(int axis,outerPar_t *pOuterPar)
{
	const msgHeader_t head = {HEADER,MSG_OUTER_PAR,0,0,sizeof(msgOuterPar_t)};
	msgOuterPar_t msg;

	msg.head = head;
	msg.axis = axis;
	msg.outerPar = *pOuterPar;
	sendMsg((msgHeader_t *)&msg);
	msg.head.count++;
}

//	----------------------------------------------------------------------------
//	sendFilterPar
//	----------------------------------------------------------------------------

void gimbalData::sendFilterPar(int axis,int ifilt,filterPar_t *pFilterPar)
{
	const msgHeader_t head = {HEADER,MSG_FILTER_PAR,0,0,sizeof(msgFilterPar_t)};
	msgFilterPar_t msg;

	msg.head = head;
	msg.axis = axis;
	msg.ifilt = ifilt;
	msg.filtPar = *pFilterPar;
	sendMsg((msgHeader_t *)&msg);
	msg.head.count++;
}

//	-------------------------------------------------------------------
//	sendTunings
//	-------------------------------------------------------------------

void gimbalData::sendTunings(tunings_t *t)
{
	msgTunings_t msg;		//{ header,          id, cmd, count,                  len}
	static msgHeader_t head = { HEADER, MSG_TUNINGS,   0,     0, sizeof(msgTunings_t)};
	msg.head = head;
	msg.t = *t;
	sendMsg(&msg.head);
	head.count++;
}

//	-------------------------------------------------------------------
//	loadTunings
//	-------------------------------------------------------------------

void gimbalData::loadTunings(tunings_t *t)
{
	for(int i=0;i<NiAXES;i++){
		 t->pidP[i] = gimTun.pidP[i];
		 t->geoP[i] = gimTun.geoP[i];
		 t->posP[i] = gimTun.posP[i];
		for(int f=0;f<NiFILT;f++){
			t->filtP[i][f] = gimTun.filt.filtP[i][f];
		}
	}
	for(int i=0;i<NoAXES;i++){
		t->outerP[i] = gimTun.outerP[i];
	}
	for(int i=0;i<NLENS;i++){
		t->lensP[i] = gimTun.lensP[i];
	}
}

//	----------------------------------------------------------------------------
//	sendMsg
//	----------------------------------------------------------------------------

void gimbalData::sendMsg(msgHeader_t *message)
{
	// insert checksum
	unsigned char *msg = (unsigned char *)message;
	int len1 = message->len - sizeof(msgTail_t);
	msgTail_t *tail = (msgTail_t *)&(msg[len1]);

	tail->checksum = 0;
	for(int i=0;i<len1;i++){
		tail->checksum += *msg++;
	}
	// send frame
	gim->writePort((unsigned char *)message,message->len);
}

//	----------------------------------------------------------------------------
//	sendSteering
//	----------------------------------------------------------------------------

void gimbalData::sendSteering(steering_t *s)
{
	extern QElapsedTimer mainTime;
	static qint64 tOld = mainTime.elapsed();
	util.onSendSteering = mainTime.elapsed() - tOld;
	tOld = mainTime.elapsed();

	const msgHeader_t head = {HEADER,MSG_STEERING,0,0,sizeof(msgSteering_t)};
	static msgSteering_t msg;

	msg.head = head;
	msg.steering = *s;

#if 0
	float f = 1;
	float pi = 3.24159f;
	float w = 2*pi*f;
	float t = tOld/1000.0f;
	float a = 5;
	float test = a*sinf(w*t);
	msg.steering.axis[0].desiredRate = test;
#endif

	sendMsg((msgHeader_t *)&msg);
	msg.head.count++;
}

//	----------------------------------------------------------------------------
//	sendCommand
//	----------------------------------------------------------------------------

void gimbalData::sendCommand(command_t *c)
{
	const msgHeader_t head = {HEADER,MSG_COMMAND,0,0,sizeof(msgCommand_t)};
	msgCommand_t msg;

	msg.head = head;
	msg.command = *c;
	sendMsg((msgHeader_t *)&msg);
	msg.head.count++;
}

//	----------------------------------------------------------------------------
//	setConnect
//	----------------------------------------------------------------------------

void gimbalData::setConnect(int val)
{
	static command_t c;
	c.command = CMD_CONNECT;
	c.par1 = val;
	c.par2 = 0;
	sendCommand(&c);
}

//	----------------------------------------------------------------------------
//	startBode
//	----------------------------------------------------------------------------

void gimbalData::startBode()
{
//	const msgHeader_t head = {HEADER,MSG_BW_PAR,0,0,sizeof(msgBwPar_t)};
//	msgOuterPar_t msg;


//	bwPar_t bwPar = {
//		1,								// uint8_t start;
//		m_axis,							// uint8_t axis;
//		m_openloop,						// uint8_t openloop;
//		m_plottype == PLOT_OPENLOOP,	// uint8_t opendrive;
//		m_plottype == PLOT_SHAKE,		// uint8_t shake;
//		60,								// uint16_t numfreqs;
//		(float)m_bodeamp,				// float amplitude;
//		(float)m_minfreq,				// float minfreq;
//		(float)m_maxfreq				// float maxfreq;
//	};

//	msg.head = head;
//	msg.bwPar = bwPar;
//	msg.tail.checksum = 0;
//	writePort((unsigned char *)&msg,sizeof(msg));
//	msg.head.count++;

//	bodeAxis = m_axis;

//	switch(m_plottype){
//		case PLOT_NORMAL:
//			gimbal.nbode[bodeAxis] = 0;
//			break;
//		case PLOT_OPENLOOP:
//			gimbal.numOpen[bodeAxis] = 0;
//			break;
//		case PLOT_SHAKE:
//			gimbal.nShake[bodeAxis] = 0;
//			break;
//	}

}

//	----------------------------------------------------------------------------
//	setStandby
//	----------------------------------------------------------------------------

void gimbalData::setStandby(int standby){
	steeringOut.standby = standby;
	cmdSteering = 1;
}

//	----------------------------------------------------------------------------
//	setGeo
//	----------------------------------------------------------------------------

void gimbalData::setGeo(int geo){
	steeringOut.mode = (geo)?(MODE_GEO):(MODE_RATE);
	cmdSteering = 1;
}

//	----------------------------------------------------------------------------
//	setAutonull
//	----------------------------------------------------------------------------

void gimbalData::setAutonull(int autonull)
{
	steeringOut.autonull = autonull;
	cmdSteering = 1;
}

//	----------------------------------------------------------------------------
//	setHsPlot
//	----------------------------------------------------------------------------

void gimbalData::setHsPlot(int plot)
{
	steeringOut.plotType = plot;
	cmdSteering = 1;
}

//	----------------------------------------------------------------------------
//	setHsAxis
//	----------------------------------------------------------------------------

void gimbalData::setHsAxis(int axis){
	steeringOut.plotAxis = axis;
	cmdSteering = 1;
}

//	----------------------------------------------------------------------------
//	setStep
//	----------------------------------------------------------------------------

void gimbalData::setStep(int axis, int step, float amp)
{
	steeringOut.plotAxis = axis;
	steeringOut.axis[axis].sinAmp = amp;
	steeringOut.axis[axis].backdrive = (step)?(BD_STEP):(BD_NONE);
	cmdSteering = 1;
}

//	----------------------------------------------------------------------------
//	cmdToTable
//	----------------------------------------------------------------------------

//int gimbalData::cmdToTable(int cmd)
//{
//	for(int table=0; table<MAXTABLES; table++){
//		if(!dbase.tableExists(table))continue;
//		if(cmdToTable(cmd,table))return table;
//	}
//}

	//	----------------------------------------------------------------------------
	//	cmdToTable
	//	----------------------------------------------------------------------------

//int gimbalData::cmdToTable(int cmd,int table)
//	{
//	if(!dbase.tableExists(table))return 0;

//	int tc = dbase.dbTableS[table]->message;

//	if(tc == cmd){
//		return 1;
//	}else if(cmd==MSG_TUNINGS){
//		switch(tc){
//			case MSG_PID_PAR:
//			case MSG_FILTER_PAR:
//			case MSG_OUTER_PAR:
//			return 1;
//		}
//	}
//	return 0;
//}

//	----------------------------------------------------------------------------
//	initDatabase
//	----------------------------------------------------------------------------

void gimbalData::initDatabase()
{
	idTbl = dbase.addTable("id",DB_RAM,1,0,MSG_STATE);
	dbase.addRow(D_string,		&state.id.name,				"name",				"",sizeof(state.id.name));
	dbase.addRow(D_uint16_t,	&state.id.serno,			"serno",			"");
	dbase.addRow(D_uint16_t,	&state.id.type,				"type",				"",DL_type);
	dbase.addRow(D_string,		&state.id.build,			"build",			"",sizeof(state.id.build));

	utilityTbl = dbase.addTable("utility",DB_RAM,1,0,MSG_UTIL);
	dbase.addRow(D_uint32_t,	&util.gyroBuffGood,			"gyroBuffGood\t",	"");
	dbase.addRow(D_uint32_t,	&util.gyroBuffErr,			"gyroBuffErr\t",	"");
	dbase.addRow(D_uint32_t,	&util.totalcount,			"totalcount\t",		"");
	dbase.addRow(D_uint32_t,	&util.err1,					"err1\t",			"");
	dbase.addRow(D_uint32_t,	&util.err2,					"err2\t",			"");
	dbase.addRow(D_uint32_t,	&util.err3,					"err3\t",			"");
	dbase.addRow(D_uint32_t,	&util.goodCount,			"goodCount\t",		"");
	dbase.addRow(D_uint32_t,	&util.onTimer,				"onTimer\t",		"");
	dbase.addRow(D_uint32_t,	&util.onTimer2,				"onTimer2\t",		"");
	dbase.addRow(D_uint32_t,	&util.onSendSteering,		"onSendSteering\t",	"");
	dbase.addRow(D_uint32_t,	&util.guiTimed,				"guiTimed\t",		"");
	dbase.addRow(D_uint32_t,	&util.guiTimedMax,			"guiTimedMax\t",	"");
	dbase.addRow(D_uint32_t,	&util.guiTimedIball,		"guiTimedIball\t",	"");
	dbase.addRow(D_uint32_t,	&util.rxConsInputFrame,		"rxConsInputFrame",	"");
	dbase.addRow(D_uint32_t,	&util.pollGimbalGet,		"pollGimbalGet\t",	"");
	dbase.addRow(D_uint32_t,	&util.pollTimeout,			"pollTimeout\t",	"");

	gimReadoutsTbl = dbase.addTable("gimReadouts",DB_RAM,1,sizeof(gimReadouts_t),0);
	dbase.addRow(D_float,		&gimReadouts.zoom,			"zoom",		"",		2);
	dbase.addRow(D_float,		&gimReadouts.iris,			"iris",		"",		2);
	dbase.addRow(D_float,		&gimReadouts.focus,			"focus",	"",		2);
	dbase.addRow(D_float,		&gimReadouts.yaw,			"yaw",		"",		2);
	dbase.addRow(D_float,		&gimReadouts.pitch,			"pitch",	"",		2);
	dbase.addRow(D_float,		&gimReadouts.roll,			"roll",		"",		2);
	dbase.addRow(D_float,		&gimReadouts.losPan,		"losPan",	"",		2);
	dbase.addRow(D_float,		&gimReadouts.losTilt,		"losTilt",	"",		2);
	dbase.addRow(D_float,		&gimReadouts.wrap,			"wrap",		"",		2);
	dbase.addRow(D_uint32_t,	&gimReadouts.buttons,		"buttons",	"",		FM_HEX);
	dbase.addRow(D_double,		&gimReadouts.lat,			"lat",		"",		8);
	dbase.addRow(D_double,		&gimReadouts.lon,			"lon",		"",		8);
	dbase.addRow(D_double,		&gimReadouts.alt,			"alt",		"",		1);
	dbase.addRow(D_double,		&gimReadouts.passiveLat,	"passiveLat",	"",		8);
	dbase.addRow(D_double,		&gimReadouts.passiveLon,	"passiveLon",	"",		8);
	dbase.addRow(D_float,		&gimReadouts.ypr[0],		"ypr[0]",		"",		2);
	dbase.addRow(D_float,		&gimReadouts.ypr[1],		"ypr[1]",		"",		2);
	dbase.addRow(D_float,		&gimReadouts.ypr[2],		"ypr[2]",		"",		2);
	dbase.addRow(D_float,		&gimReadouts.yprA[0],		"yprA[0]",		"",		2);
	dbase.addRow(D_float,		&gimReadouts.yprA[1],		"yprA[1]",		"",		2);
	dbase.addRow(D_float,		&gimReadouts.yprA[2],		"yprA[2]",		"",		2);
	dbase.addRow(D_float,		&gimReadouts.range,			"range",		"",		1);
//	float xyCamera[2];
//	float xyTarget[2];
//	float range;

	operControlsTbl = dbase.addTable("operControls",DB_RAM,1,sizeof(operControls_t),0);
	dbase.addRow(D_float,		&operControls.zoom,			"zoom",		"",		5);
	dbase.addRow(D_float,		&operControls.iris,			"iris",		"",		5);
	dbase.addRow(D_float,		&operControls.focus,		"focus",	"",		5);
	dbase.addRow(D_uint32_t,	&operControls.stow,			"stow",		"",		DL_bool);
	dbase.addRow(D_uint32_t,	&operControls.slave,		"slave",	"",		DL_bool);
	dbase.addRow(D_uint32_t,	&operControls.zmult,		"zmult",	"",		DL_bool);

	joystickTbl = dbase.addTable("joystick",DB_RAM,1,sizeof(joystickT_t),0);
	dbase.addRow(D_float,		&joystickT.jsPan,			"jsPan",	"",		5);
	dbase.addRow(D_float,		&joystickT.jsTilt,			"jsTilt",	"",		5);
	dbase.addRow(D_float,		&joystickT.jsRoll,			"jsRoll",	"",		5);
	dbase.addRow(D_uint32_t,	&joystickT.button1,			"button1",	"",		DL_bool);
	dbase.addRow(D_uint32_t,	&joystickT.button2,			"button2",	"",		DL_bool);

	consInputTbl = dbase.addTable("consInput",DB_RAM,1,sizeof(consInput_t),0);
	dbase.addRow(D_int32_t,		&consInput.buttons,			"buttons",	"",		FM_HEX);
	dbase.addRow(D_int32_t,		&consInput.enc1,			"enc1",		""		);
	dbase.addRow(D_int32_t,		&consInput.enc2,			"enc2",		""		);
	dbase.addRow(D_int32_t,		&consInput.enc3,			"enc3",		""		);
	dbase.addRow(D_float,		&consInput.zoom,			"zoom",		"",		4);
	dbase.addRow(D_float,		&consInput.focus,			"focus",	"",		4);
	dbase.addRow(D_float,		&consInput.iris,			"iris",		"",		4);
	dbase.addRow(D_float,		&consInput.jsx,				"jsx",		"",		4);
	dbase.addRow(D_float,		&consInput.jsy,				"jsy",		"",		4);
	dbase.addRow(D_float,		&consInput.jsz,				"jsz",		"",		4);

	operSettingsTbl = dbase.addTable("operSettings",DB_RAM,1,sizeof(operSettings_t),0);
	dbase.addRow(D_float,		&operSettings.panGain,			"panGain",		"",		2);
	dbase.addRow(D_float,		&operSettings.tiltGain,			"tiltGain",		"",		2);
	dbase.addRow(D_float,		&operSettings.rollGain,			"rollGain",		"",		2);
	dbase.addRow(D_float,		&operSettings.dynGain,			"dynGain",		"",		2);
	dbase.addRow(D_float,		&operSettings.zoomGain,			"zoomGain",		"",		2);
	dbase.addRow(D_float,		&operSettings.focusGain,		"focusGain",	"",		2);
	dbase.addRow(D_float,		&operSettings.zmultGain,		"zmultGain",	"",		2);
	dbase.addRow(D_double,		&operSettings.geoLat,			"geoLat",		"",		9);
	dbase.addRow(D_double,		&operSettings.geoLon,			"geoLon",		"",		9);
	dbase.addRow(D_float,		&operSettings.geoAlt,			"geoAlt",		"",		2);
	dbase.addRow(D_uint32_t,	&operSettings.panRev,			"panRev",		"",		DL_nrv);
	dbase.addRow(D_uint32_t,	&operSettings.tiltRev,			"tiltRev",		"",		DL_nrv);
	dbase.addRow(D_uint32_t,	&operSettings.rollRev,			"rollRev",		"",		DL_nrv);
	dbase.addRow(D_uint32_t,	&operSettings.zoomRev,			"zoomRev",		"",		DL_nrv);
	dbase.addRow(D_uint32_t,	&operSettings.irisRev,			"irisRev",		"",		DL_nrv);
	dbase.addRow(D_uint32_t,	&operSettings.focusRev,			"focusRev",		"",		DL_nrv);
	dbase.addRow(D_uint32_t,	&operSettings.dynOn,			"dynOn",		"",		DL_bool);
	dbase.addRow(D_uint32_t,	&operSettings.zmultOn,			"zmultOn",		"",		DL_bool);
	dbase.addRow(D_uint32_t,	&operSettings.mode,				"mode",			"" 		);
	dbase.addRow(D_uint32_t,	&operSettings.encFunction,		"encFunction",	"" 		);
	dbase.addRow(D_uint32_t,	&operSettings.jzFunction,		"jzFunction",	"" 		);

	controlsTbl = dbase.addTable("controls",DB_RAM,1,0,MSG_CONTROLS);
	dbase.addRow(D_int32_t,		&controls.connect,				"connect",		"connect to utility",		DL_bool);
	dbase.addRow(D_int32_t,		&controls.standby,				"standby",		"disable drives",			DL_bool);
	dbase.addRow(D_int32_t,		&controls.autonull,				"autonull",		"null gyro and joystick",	DL_bool);
	dbase.addRow(D_int32_t,		&controls.mode,					"mode",			"steering mode",			DL_mode);
	dbase.addRow(D_int32_t,		&controls.plotType,				"plotType",		"plot variable",			DL_plot);
	dbase.addRow(D_int32_t,		&controls.plotAxis,				"plotAxis",		"plot axis",				DL_axes);
	dbase.addRow(D_int32_t,		&controls.plotRaw,				"plotRaw",		"plot unfiltered signal",	DL_bool);

	steeringTbl = dbase.addTable("steering",DB_RAM,1,0,MSG_STEERING);
	dbase.addRow(D_int16_t,		&steeringOut.connect,				"connect",		"",		DL_bool);
	dbase.addRow(D_int16_t,		&steeringOut.mode,					"mode",			"",		DL_mode);
	dbase.addRow(D_int16_t,		&steeringOut.standby,				"standby",		"",		DL_bool);
	dbase.addRow(D_int16_t,		&steeringOut.autonull,				"autonull",		"",		DL_bool);
	dbase.addRow(D_int16_t,		&steeringOut.plotRaw,				"plotRaw",		"",		DL_bool);
	dbase.addRow(D_int16_t,		&steeringOut.plotType,				"plotType",		"",		DL_plot);
	dbase.addRow(D_int16_t,		&steeringOut.plotAxis,				"plotAxis",		"",		DL_axes);
	dbase.addRow(D_uint16_t,	&steeringOut.bits,					"bits",			"",		FM_HEX);
	dbase.addRow(D_float,		&steeringOut.focus,					"focus",		"",		5);
	dbase.addRow(D_float,		&steeringOut.iris,					"iris",			"",		5);
	dbase.addRow(D_float,		&steeringOut.zoom,					"zoom",			"",		5);
	dbase.addRow(D_double,		&steeringOut.latitude,			 	"latitude",		"",		9);
	dbase.addRow(D_double,		&steeringOut.longitude,			 	"longitude",	"",		9);
	dbase.addRow(D_float,		&steeringOut.altitude,				"altitude",		"",		2);
	dbase.addRow(D_float,		&steeringOut.dynamic,				"dynamic",		"",		3);
	dbase.addRow(D_uint16_t,	&steeringOut.buttons1,				"buttons1",		"",		FM_HEX);
	dbase.addRow(D_uint16_t,	&steeringOut.buttons2,				"buttons2",		"",		FM_HEX);
	dbase.addRow(D_int16_t,		&steeringOut.enc1,					"enc1",			""		);
	dbase.addRow(D_int16_t,		&steeringOut.enc2,					"enc2",			""		);
	dbase.addRow(D_int16_t,		&steeringOut.enc3,					"enc3",			""		);
	dbase.addRow(D_int16_t,		&steeringOut.sim.mode,				"sim.mode",		""		);
	dbase.addRow(D_double,		&steeringOut.sim.lla1[0],			"sim.lat1",		"",		8);
	dbase.addRow(D_double,		&steeringOut.sim.lla1[1],			"sim.lon1",		"",		8);
	dbase.addRow(D_double,		&steeringOut.sim.lla1[2],			"sim.alt1",		"",		1);
	dbase.addRow(D_double,		&steeringOut.sim.lla2[0],			"sim.lat2",		"",		8);
	dbase.addRow(D_double,		&steeringOut.sim.lla2[1],			"sim.lon2",		"",		8);
	dbase.addRow(D_double,		&steeringOut.sim.lla2[2],			"sim.alt2",		"",		1);
	dbase.addRow(D_double,		&steeringOut.sim.alt,				"sim.alt",		"",		1);
	dbase.addRow(D_float,		&steeringOut.sim.ypr[0],			"sim.ypr[0]",	"",		2);
	dbase.addRow(D_float,		&steeringOut.sim.ypr[1],			"sim.ypr[1]",	"",		2);
	dbase.addRow(D_float,		&steeringOut.sim.ypr[2],			"sim.ypr[2]",	"",		2);
	dbase.addRow(D_double,		&steeringOut.sim.speed,				"sim.speed",	"",		2);

	steeringAxisTbl = dbase.addTable("steering.axis",DB_RAM,NiAXES,sizeof(axisSteering_t),MSG_STEERING);
	dbase.addRow(D_int16_t,		&steeringOut.axis[0].enable,		"enable",		"",		DL_bool);
	dbase.addRow(D_int16_t,		&steeringOut.axis[0].enableO,		"enableO",		"",		DL_bool);
	dbase.addRow(D_int16_t,		&steeringOut.axis[0].remote,		"remote",		"",		DL_bool);
	dbase.addRow(D_int16_t,		&steeringOut.axis[0].backdrive,		"backdrive",	"",		DL_bd);
	dbase.addRow(D_float,		&steeringOut.axis[0].joystick,		"joystick",		"",		5);
	dbase.addRow(D_float,		&steeringOut.axis[0].desiredRate,	"desiredRate",	"",		5);
	dbase.addRow(D_float,		&steeringOut.axis[0].desiredPos,	"desiredPos",	"",		2);
	dbase.addRow(D_float,		&steeringOut.axis[0].desiredRate,	"desiredRate",	"",		2);
	dbase.addRow(D_float,		&steeringOut.axis[0].sinAmp,		"sinAmp",		"",		4);
	dbase.addRow(D_float,		&steeringOut.axis[0].sinFreq,		"sinFreq",		"",		2);

	controlsAxisTbl = dbase.addTable("controls.axis",DB_RAM,NiAXES,sizeof(axisControls_t),MSG_CONTROLS);
	dbase.addRow(D_int32_t,		&controls.axis[0].enable,		"enable",		"enable drive",				DL_bool);
	dbase.addRow(D_int32_t,		&controls.axis[0].enableO,		"enableO",		"enable outer drive",		DL_bool);
	dbase.addRow(D_int32_t,		&controls.axis[0].remote,		"remote",		"steer via remote command",	DL_bool);
	dbase.addRow(D_int32_t,		&controls.axis[0].backdrive,	"backdrive",	"engage backdrive",			DL_bd);
	dbase.addRow(D_int32_t,		&controls.axis[0].jsNull,		"jsNull",		"null the joystick",		DL_bool);
	dbase.addRow(D_int32_t,		&controls.axis[0].gyroNull,		"gyroNull",		"null the gyro",			DL_bool);
	dbase.addRow(D_float,		&controls.axis[0].desiredRate,	"desiredRate",	"steering rate command",	2);
	dbase.addRow(D_float,		&controls.axis[0].sinAmp,		"sinAmp",		"backdrive amplitude",		4);
	dbase.addRow(D_float,		&controls.axis[0].sinFreq,		"sinFreq",		"backdrive frequency",		2);
	dbase.addRow(D_float,		&controls.axis[0].desiredPos,	"desiredPos",	"desired position",			2);

	stateGyroTbl = dbase.addTable("state.gyro",DB_RAM,1,sizeof(gyroState_t),MSG_STATE);
	dbase.addRow(D_int32_t,		&state.gyro.gyroFrame,			"gyroFrame",	"");
	dbase.addRow(D_int32_t,		&state.gyro.gyroFreq,			"gyroFreq",		"");
	dbase.addRow(D_int32_t,		&state.gyro.consFrame,			"consFrame",	"");
	dbase.addRow(D_int32_t,		&state.gyro.mainFrame,			"mainFrame",	"");
	dbase.addRow(D_int32_t,		&state.gyro.misc0,				"misc0",		"");
	dbase.addRow(D_int32_t,		&state.gyro.misc1,				"misc1",		"");
	dbase.addRow(D_int32_t,		&state.gyro.misc2,				"misc2",		"");
	dbase.addRow(D_int32_t,		&state.gyro.misc3,				"misc3",		"");

	stateCommTbl = dbase.addTable("state.comm",DB_RAM,3,sizeof(commState_t),MSG_STATE);
	dbase.addRow(D_int32_t,		&state.comm[0].gyro,			"gyro",		"");
	dbase.addRow(D_int32_t,		&state.comm[0].vn200,			"vn200",	"");
	dbase.addRow(D_int32_t,		&state.comm[0].main422,			"main422",	"");
	dbase.addRow(D_int32_t,		&state.comm[0].outer,			"outer",	"");
	dbase.addRow(D_int32_t,		&state.comm[0].navbox,			"navbox",	"");
	dbase.addRow(D_int32_t,		&state.comm[0].navCs,			"navCs",	"");
	dbase.addRow(D_int32_t,		&state.comm[0].odin,			"odin",		"");
	dbase.addRow(D_int32_t,		&state.comm[0].sim,				"sim",		"");
	dbase.addRow(D_int32_t,		&state.comm[0].console,			"console",	"");
	dbase.addRow(D_int32_t,		&state.comm[0].util,			"util",		"");
	dbase.addRow(D_int32_t,		&state.comm[0].lens,			"lens",		"");
	dbase.addRow(D_int32_t,		&state.comm[0].steering,		"steering",	"");

	stateNavTbl = dbase.addTable("state.nav",DB_RAM,1,sizeof(navState_t),MSG_STATE);
	dbase.addRow(D_uint64_t,	&state.nav.TimeGps,				"TimeGps",		""		 );	//	0
	dbase.addRow(D_float,		&state.nav.Ypr[0],				"Ypr[Y]",		"",		2);	//	1
	dbase.addRow(D_float,		&state.nav.Ypr[1],				"Ypr[P]",		"",		2);	//	2
	dbase.addRow(D_float,		&state.nav.Ypr[2],				"Ypr[R]",		"",		2);	//	3
	dbase.addRow(D_float,		&state.nav.AngularRate[0],		"AngRate[Y]",	"",		2);	//	4
	dbase.addRow(D_float,		&state.nav.AngularRate[1],		"AngRate[P]",	"",		2);	//	5
	dbase.addRow(D_float,		&state.nav.AngularRate[2],		"AngRate[R]",	"",		2);	//	6
	dbase.addRow(D_double,		&state.nav.PosLla[0],			"Lat",			"",		9);	//	7
	dbase.addRow(D_double,		&state.nav.PosLla[1],			"Lon",			"",		9);	//	8
	dbase.addRow(D_double,		&state.nav.PosLla[2],			"Alt",			"",		2);	//	9
	dbase.addRow(D_float,		&state.nav.VelNed[0],			"VelNed[N]",	"",		2);	// 10
	dbase.addRow(D_float,		&state.nav.VelNed[1],			"VelNed[E]",	"",		2);	// 11
	dbase.addRow(D_float,		&state.nav.VelNed[2],		 	"VelNed[D]",	"",		2);	// 12
	dbase.addRow(D_uint16_t,	&state.nav.InsStatus,			"InsStatus",	"",FM_HEX);	// 13

	stateGeoTbl = dbase.addTable("state.geo",DB_RAM,1,sizeof(navState_t),MSG_STATE);
	dbase.addRow(D_double3,		&state.geo.cameraL[0],			"cameraL",		"",		9);
	dbase.addRow(D_double3,		&state.geo.targetL[0],			"targetL",		"",		9);
	dbase.addRow(D_double3,		&state.geo.passiveL[0],			"passiveL",		"",		9);
	dbase.addRow(D_float3,		&state.geo.losError[0],		 	"losError",		"",		2);
	dbase.addRow(D_float3,		&state.geo.losErrorRate[0],		"losErrRate",	"",		2);
	dbase.addRow(D_float,		&state.geo.range,				"range",		"",		0);
	dbase.addRow(D_float,		&state.geo.rangeP,				"rangeP",		"",		0);
	dbase.addRow(D_float3,		&state.geo.ypr[0],				"ypr",			"",		2);
	dbase.addRow(D_float3,		&state.geo.targetAngle[0],		"targetAngle",	"",		2);
	dbase.addRow(D_float3,		&state.geo.targetRate[0],		"targetRate",	"",		2);
	dbase.addRow(D_float3,		&state.geo.losError2[0],		"losError2",	"",		2);
	dbase.addRow(D_float3,		&state.geo.losErrorRate2[0],	"losErrorRate2","",		2);
	dbase.addRow(D_float3,		&state.geo.vprofile[0],			"vprofile",		"",		2);
	dbase.addRow(D_float,		&state.geo.rangeRate,			"rangeRate",	"",		2);
	dbase.addRow(D_float3,		&state.geo.passiveRate[0],		"passiveRate",	"",		2);

	stateInputTbl = dbase.addTable("state.input",DB_RAM,NiAXES,sizeof(axisState_t),MSG_STATE);
	dbase.addRow(D_float,		&state.axis[0].gyro.val,		"gyro.val",		"",		3);
	dbase.addRow(D_float,		&state.axis[0].gyro.raw,		"gyro.raw",		"",		3);
	dbase.addRow(D_float,		&state.axis[0].gyro.ofs,		"gyro.ofs",		"",		3);
	dbase.addRow(D_float,		&state.axis[0].angle.val,		"angle.val",	"",		3);
	dbase.addRow(D_float,		&state.axis[0].angle.raw,		"angle.raw",	"",		3);
	dbase.addRow(D_float,		&state.axis[0].angle.ofs,		"angle.ofs",	"",		3);
	dbase.addRow(D_float,		&state.axis[0].tach.val,		"tach.val",		"",		3);
	dbase.addRow(D_float,		&state.axis[0].tach.raw,		"tach.raw",		"",		3);
	dbase.addRow(D_float,		&state.axis[0].tach.ofs,		"tach.ofs",		"",		3);
	dbase.addRow(D_float,		&state.axis[0].enc.val,			"enc.val",		"",		3);
	dbase.addRow(D_float,		&state.axis[0].enc.ofs,			"enc.ofs",		"",		3);
	dbase.addRow(D_int32_t,		&state.axis[0].enc.count,		"enc.count",	"");
	dbase.addRow(D_int32_t,		&state.axis[0].enc.indexed,		"enc.indexed",	"");

	stateAxisTbl = dbase.addTable("state.axis",DB_RAM,NiAXES,sizeof(axisState_t),MSG_STATE);
	dbase.addRow(D_float,		&state.axis[0].rateCommand,		"rateCommand",	"",		3);			//	0
	dbase.addRow(D_float,		&state.axis[0].r,				"r",			"",		3);			//	1
	dbase.addRow(D_float,		&state.axis[0].rE,				"rE",			"",		3);			//	2
	dbase.addRow(D_float,		&state.axis[0].rEr,				"rEr",			"",		3);			//	3
	dbase.addRow(D_float,		&state.axis[0].err,				"err",			"",		3);			//	4
	dbase.addRow(D_float,		&state.axis[0].erI,				"erI",			"",		3);			//	5
	dbase.addRow(D_float,		&state.axis[0].drive,			"drive",		"",		3);			//	6
	dbase.addRow(D_float,		&state.axis[0].current,			"current",		"",		2);			//	7
	dbase.addRow(D_float,		&state.axis[0].jitter,			"jitter",		"",		1);			//	8
	dbase.addRow(D_int32_t,		&state.axis[0].pwm,				"pwm",			""		 );			//	9
	dbase.addRow(D_int32_t,		&state.axis[0].pwmOuter,		"pwmOuter",		""		 );			// 10
	dbase.addRow(D_float,		&state.axis[0].pos,				"pos",			"",		3);			// 11
	dbase.addRow(D_float,		&state.axis[0].outerDemandedRate,"outerDemRate","",		3);			// 12
	dbase.addRow(D_float,		&state.axis[0].outerRe,			"outerRe","",			3);			// 13
	dbase.addRow(D_float,		&state.axis[0].outerReI,		"outerReI","",			3);			// 14
	dbase.addRow(D_float,		&state.axis[0].outerDrive,		"outerDrive",	"",		3);			// 15
	dbase.addRow(D_float,		&state.axis[0].outerAngle,		"outerAngle",	"",		1);			// 16
	dbase.addRow(D_float,		&state.axis[0].outerAngleDif,	"outerAngleDif","",		1);			// 17
	dbase.addRow(D_int8_t,		&state.axis[0].outerInDeadband,	"outerInDband",	"",		DL_bool);	// 18
	dbase.addRow(D_int8_t,		&state.axis[0].profile,			"profile",		""		 );			// 19
	dbase.addRow(D_int8_t,		&state.axis[0].settled,			"settled",		"",		DL_bool);	// 20
	dbase.addRow(D_int8_t,		&state.axis[0].logic1,			"logic1",		"",		DL_bool);	// 21
	dbase.addRow(D_float,		&state.axis[0].geoInt,			"geoInt",		"",		1);			// 22
	dbase.addRow(D_float,		&state.axis[0].cur,				"cur",			"",		2);			// 23

	stateOuterCmd = dbase.addTable("state.outerCmd",DB_RAM,1,sizeof(axisState_t),MSG_STATE);
	dbase.addRow(D_float,		&state.outerCmd.drive[0],		"drive[0]",	"",		2);			//	0
	dbase.addRow(D_float,		&state.outerCmd.drive[1],		"drive[1]",	"",		2);			//	1
	dbase.addRow(D_float,		&state.outerCmd.drive[2],		"drive[2]",	"",		2);			//	2
	dbase.addRow(D_int16_t,		&state.outerCmd.focus,			"focus",	"");				//	3
	dbase.addRow(D_int16_t,		&state.outerCmd.iris,			"iris",		"");				//	4
	dbase.addRow(D_int16_t,		&state.outerCmd.lensbits,		"lensbits",	"",		FM_HEX);	//	5
	dbase.addRow(D_int16_t,		&state.outerCmd.bits,			"bits",		"",		FM_HEX);	//	6

	stateOuterFb = dbase.addTable("state.outerFb",DB_RAM,1,sizeof(axisState_t),MSG_STATE);
#if 1
	dbase.addRow(D_float,		&state.outerFb.tach[0],		"tach[0]",		"",		1);			//	0
	dbase.addRow(D_float,		&state.outerFb.tach[1],		"tach[1]",		"",		1);			//	1
	dbase.addRow(D_float,		&state.outerFb.tach[2],		"tach[2]",		"",		1);			//	2
	dbase.addRow(D_float,		&state.outerFb.angle[0],	"angle[0]",		"",		2);			//	3
	dbase.addRow(D_float,		&state.outerFb.angle[1],	"angle[1]",		"",		2);			//	4
	dbase.addRow(D_float,		&state.outerFb.angle[2],	"angle[2]",		"",		2);			//	5
	dbase.addRow(D_int32_t,		&state.outerFb.encoder[0],	"encoder[0]",	"");				//	6
	dbase.addRow(D_int32_t,		&state.outerFb.encoder[1],	"encoder[1]",	"");				//	7
	dbase.addRow(D_int32_t,		&state.outerFb.encoder[2],	"encoder[2]",	"");				//	8
	dbase.addRow(D_int8_t,		&state.outerFb.indexed[0],	"indexed[0]",	"");				//	9
	dbase.addRow(D_int8_t,		&state.outerFb.indexed[1],	"indexed[1]",	"");				// 10
	dbase.addRow(D_int8_t,		&state.outerFb.indexed[2],	"indexed[2]",	"");				// 11
	dbase.addRow(D_int8_t,		&state.outerFb.lasterr,		"lasterr",		"");				// 12
	dbase.addRow(D_int16_t,		&state.outerFb.focus,		"focus",		"");				// 13
	dbase.addRow(D_int16_t,		&state.outerFb.iris,		"iris",			"");				// 14
	dbase.addRow(D_int16_t,		&state.outerFb.lensbits,	"lensbits",		"",		FM_HEX);	// 15
	dbase.addRow(D_int16_t,		&state.outerFb.bits,		"bits",			"",		FM_HEX);	// 16
#else
	dbase.addRow(D_float,		&state.outerFb.tach[0],		"tach[0]",		"",		1);			//	0
	dbase.addRow(D_float,		&state.outerFb.tach[1],		"tach[1]",		"",		1);			//	1
	dbase.addRow(D_float,		&state.outerFb.tach[2],		"tach[2]",		"",		1);			//	2
	dbase.addRow(D_int32_t,		&state.outerFb.encoder[0],	"encoder[0]",	"");				//	3
	dbase.addRow(D_int32_t,		&state.outerFb.encoder[1],	"encoder[1]",	"");				//	4
	dbase.addRow(D_int32_t,		&state.outerFb.encoder[2],	"encoder[2]",	"");				//	5
	dbase.addRow(D_int8_t,		&state.outerFb.indexed[0],	"indexed[0]",	"");				//	6
	dbase.addRow(D_int8_t,		&state.outerFb.indexed[1],	"indexed[1]",	"");				//	7
	dbase.addRow(D_int8_t,		&state.outerFb.indexed[2],	"indexed[2]",	"");				//	8
	dbase.addRow(D_int8_t,		&state.outerFb.lasterr,		"lasterr",		"");				//  9
	dbase.addRow(D_int16_t,		&state.outerFb.focus,		"focus",		"");				// 10
	dbase.addRow(D_int16_t,		&state.outerFb.iris,		"iris",			"");				// 11
	dbase.addRow(D_int16_t,		&state.outerFb.lensbits,	"lensbits",		"",		FM_HEX);	// 12
	dbase.addRow(D_int16_t,		&state.outerFb.bits,		"bits",			"",		FM_HEX);	// 13
#endif

	stateOdinTbl = dbase.addTable("state.odin",DB_RAM,1,sizeof(odinState_t),MSG_STATE);
	dbase.addRow(D_int32_t,		&state.odin.u32RXBytes,			"u32RXBytes\t",			"");
	dbase.addRow(D_int32_t,		&state.odin.u32RXPackets,		"u32RXPackets\t",		"");
	dbase.addRow(D_int32_t,		&state.odin.u32RXExtra,			"u32RXExtra\t",			"");
	dbase.addRow(D_int32_t,		&state.odin.u32RXErrors,		"u32RXErrors\t",		"");
	dbase.addRow(D_int32_t,		&state.odin.u32RXBadHeaderChk,	"u32RXBadHeaderChk",	"");
	dbase.addRow(D_int32_t,		&state.odin.u32RXBadPayloadCRC,	"u32RXBadPayloadCRC",	"");
	dbase.addRow(D_int32_t,		&state.odin.u32RXSeqErrors,		"u32RXSeqErrors",		"");
	dbase.addRow(D_int32_t,		&state.odin.u32TXPackets,		"u32TXPackets\t",		"");
	dbase.addRow(D_int32_t,		&state.odin.rxGIMBAL_CTRL,		"rxGIMBAL_CTRL",		"");
	dbase.addRow(D_int32_t,		&state.odin.rxGIMBAL_CONFIG,	"rxGIMBAL_CONFIG",		"");
	dbase.addRow(D_int32_t,		&state.odin.rxGPS_STATUS,		"rxGPS_STATUS\t",		"");
	dbase.addRow(D_int32_t,		&state.odin.rxGEO_POINT,		"rxGEO_POINT\t",		"");
	dbase.addRow(D_int32_t,		&state.odin.rxLENS_CTRL,		"rxLENS_CTRL\t",		"");
	dbase.addRow(D_int32_t,		&state.odin.rxLENS_CAL,			"rxLENS_CAL\t",			"");
	dbase.addRow(D_int32_t,		&state.odin.txGIMBAL_CONFIG,	"txGIMBAL_CONFIG",		"");
	dbase.addRow(D_int32_t,		&state.odin.txMASTER_STATUS,	"txMASTER_STATUS",		"");
	dbase.addRow(D_int32_t,		&state.odin.txLENS_STATUS,		"txLENS_STATUS",		"");
	dbase.addRow(D_float,		&state.odin.fYawHdgT,			"fYawHdgT\t",			"",		2);
	dbase.addRow(D_float,		&state.odin.fMinRng,			"fMinRng\t",			"",		2);
	dbase.addRow(D_float,		&state.odin.fMaxRng,			"fMaxRng\t",			"",		2);
	dbase.addRow(D_float,		&state.odin.fMinAz,				"fMinAz\t",				"",		2);
	dbase.addRow(D_float,		&state.odin.fMaxAz,				"fMaxAz\t",				"",		2);
	dbase.addRow(D_double,		&state.odin.dLatitude,			"dLatitude\t",			"",		9);
	dbase.addRow(D_double,		&state.odin.dLongitude,			"dLongitude\t",			"",		9);
	dbase.addRow(D_float,		&state.odin.fAltELL,			"fAltELL\t",			"",		1);
	dbase.addRow(D_float,		&state.odin.losJitter,			"losJitter\t",			"",		4);

	dbase.addRow(D_uint32_t,	&state.odin.targets,			"targets\t",		"");
	dbase.addRow(D_uint32_t,	&state.odin.frameCount,			"frameCount\t",		"");
	dbase.addRow(D_uint32_t,	&state.odin.fireCount,			"fireCount\t",		"");
	dbase.addRow(D_uint32_t,	&state.odin.clusterID,			"clusterID\t",		"");
	dbase.addRow(D_uint32_t,	&state.odin.targetID,			"targetID\t",		"");
	dbase.addRow(D_uint32_t,	&state.odin.geoEvent,			"geoEvent\t",		"");
	dbase.addRow(D_uint32_t,	&state.odin.gimbalMode,			"gimbalMode\t",		"");
	dbase.addRow(D_uint32_t,	&state.odin.geoStatus,			"geoStatus\t",		"");
	dbase.addRow(D_uint32_t,	&state.odin.gimStatus,			"gimStatus\t",		"");
	dbase.addRow(D_uint32_t,	&state.odin.camPulse,			"camPulse\t",		"");
	dbase.addRow(D_uint32_t,	&state.odin.camReady,			"camReady\t",		"");
	dbase.addRow(D_uint32_t,	&state.odin.camTimeout,			"camTimeout\t",		"");
	dbase.addRow(D_uint32_t,	&state.odin.targetSeqIndex,		"targetSeqIndex\t",	"",	DL_omode);
	dbase.addRow(D_uint32_t,	&state.odin.targetResult,		"targetResult\t",	"");

	bwParTbl = dbase.addTable("bwPar",DB_RAM,1,sizeof(bwPar_t),MSG_BW_PAR);
	dbase.addRow(D_uint32_t,	&bwPar.start,					"start",		"",		DL_bool);
	dbase.addRow(D_uint32_t,	&bwPar.axis,					"axis",			"",		DL_axes);
	dbase.addRow(D_uint32_t,	&bwPar.openloop,				"openloop",		"",		DL_bool);
	dbase.addRow(D_uint32_t,	&bwPar.opendrive,				"opendrive",	"",		DL_bool);
	dbase.addRow(D_uint32_t,	&bwPar.shake,					"shake",		"",		DL_bool);
	dbase.addRow(D_uint32_t,	&bwPar.numfreqs,				"numfreqs",		"");
	dbase.addRow(D_float,		&bwPar.amplitude,				"amplitude",	"",		2);
	dbase.addRow(D_float,		&bwPar.minfreq,					"minfreq",		"",		2);
	dbase.addRow(D_float,		&bwPar.maxfreq,					"maxfreq",		"",		2);

	bwResTbl = dbase.addTable("bwRes",DB_RAM,1,sizeof(bwRes_t),MSG_BW_RES);
	dbase.addRow(D_uint32_t,	&bwRes.index,					"index",		"");
	dbase.addRow(D_int32_t,		&bwRes.bwState,					"bwState",		"");
	dbase.addRow(D_float,		&bwRes.drive,					"drive",		"",		2);
	dbase.addRow(D_float,		&bwRes.output,					"output",		"",		2);
	dbase.addRow(D_float,		&bwRes.time,					"time",			"",		2);
	dbase.addRow(D_float,		&bwRes.cycles,					"cycles",		"",		2);
	dbase.addRow(D_float,		&bwRes.freq[0],					"freq[0]",		"",		2);
	dbase.addRow(D_float,		&bwRes.gain[0],					"gain[0]",		"",		2);
	dbase.addRow(D_float,		&bwRes.phase[0],				"phase[0]",		"",		2);
	dbase.addRow(D_float,		&bwRes.freq[10],				"freq[10]",		"",		2);
	dbase.addRow(D_float,		&bwRes.gain[10],				"gain[10]",		"",		2);
	dbase.addRow(D_float,		&bwRes.phase[10],				"phase[10]",	"",		2);

	pidPTbl = dbase.addTable("pidP",DB_FLASH,NiAXES,sizeof(pidPar_t),MSG_PID_PAR);
	dbase.addRow(D_float,		&gimTun.pidP[0].kP[0],			"kP[0]",		"",		3);
	dbase.addRow(D_float,		&gimTun.pidP[0].kP[1],			"kP[1]",		"",		3);
	dbase.addRow(D_float,		&gimTun.pidP[0].kP[2],			"kP[2]",		"",		3);
	dbase.addRow(D_float,		&gimTun.pidP[0].kI[0],			"kI[0]",		"",		3);
	dbase.addRow(D_float,		&gimTun.pidP[0].kI[1],			"kI[1]",		"",		3);
	dbase.addRow(D_float,		&gimTun.pidP[0].kI[2],			"kI[2]",		"",		3);
	dbase.addRow(D_float,		&gimTun.pidP[0].kD[0],			"kD[0]",		"",		3);
	dbase.addRow(D_float,		&gimTun.pidP[0].kD[1],			"kD[1]",		"",		3);
	dbase.addRow(D_float,		&gimTun.pidP[0].kD[2],			"kD[2]",		"",		3);
	dbase.addRow(D_float,		&gimTun.pidP[0].kILim[0],		"kILim[0]",		"",		3);
	dbase.addRow(D_float,		&gimTun.pidP[0].kILim[1],		"kILim[1]",		"",		3);
	dbase.addRow(D_float,		&gimTun.pidP[0].kILim[2],		"kILim[2]",		"",		3);
	dbase.addRow(D_float,		&gimTun.pidP[0].kT,				"kT",			"",		3);
	dbase.addRow(D_float,		&gimTun.pidP[0].kC,				"kC",			"",		3);

	filtP0Tbl = dbase.addTable("filtP[0]",DB_FLASH,NiFILT,sizeof(filterPar_t),MSG_FILTER_PAR);
	dbase.addRow(D_int32_t,		&gimTun.filt.filtP[0][0].ftype,	"ftype",		"",		DL_filt);
	dbase.addRow(D_float,		&gimTun.filt.filtP[0][0].f1,	"f1",			"",		2);
	dbase.addRow(D_float,		&gimTun.filt.filtP[0][0].q,		"q",			"",		2);

	filtP1Tbl = dbase.addTable("filtP[1]",DB_FLASH,NiFILT,sizeof(filterPar_t),MSG_FILTER_PAR);
	dbase.addRow(D_int32_t,		&gimTun.filt.filtP[1][0].ftype,	"ftype",		"",		DL_filt);
	dbase.addRow(D_float,		&gimTun.filt.filtP[1][0].f1,	"f1",			"",		2);
	dbase.addRow(D_float,		&gimTun.filt.filtP[1][0].q,		"q",			"",		2);

	filtP2Tbl = dbase.addTable("filtP[2]",DB_FLASH,NiFILT,sizeof(filterPar_t),MSG_FILTER_PAR);
	dbase.addRow(D_int32_t,		&gimTun.filt.filtP[2][0].ftype,	"ftype",		"",		DL_filt);
	dbase.addRow(D_float,		&gimTun.filt.filtP[2][0].f1,	"f1",			"",		2);
	dbase.addRow(D_float,		&gimTun.filt.filtP[2][0].q,		"q",			"",		2);

	outerPTbl = dbase.addTable("outerP",DB_FLASH,NoAXES,sizeof(outerPar_t),MSG_OUTER_PAR);
	dbase.addRow(D_float,		&gimTun.outerP[0].kP,			"kP",			"",		4);
	dbase.addRow(D_float,		&gimTun.outerP[0].kFF,			"kFF",			"",		4);
	dbase.addRow(D_float,		&gimTun.outerP[0].kTach,		"kTach",		"",		4);
	dbase.addRow(D_float,		&gimTun.outerP[0].kI,			"kI",			"",		4);
	dbase.addRow(D_float,		&gimTun.outerP[0].kILim,		"kILim",		"",		4);

	geoPTbl = dbase.addTable("geoP",DB_FLASH,NiAXES,sizeof(geoPar_t),MSG_TUNINGS);
	dbase.addRow(D_float,		&gimTun.geoP[0].kP,				"kP",			"",		3);
	dbase.addRow(D_float,		&gimTun.geoP[0].kP2,			"kP2",			"",		3);
	dbase.addRow(D_float,		&gimTun.geoP[0].kI,				"kI",			"",		3);
	dbase.addRow(D_float,		&gimTun.geoP[0].kD,				"kD",			"",		3);
	dbase.addRow(D_float,		&gimTun.geoP[0].kILim,			"kILim",		"",		3);
	dbase.addRow(D_float,		&gimTun.geoP[0].kMystery2,		"kMystery2",	"",		3);

	posPTbl = dbase.addTable("posP",DB_FLASH,NiAXES,sizeof(posPar_t),MSG_TUNINGS);
	dbase.addRow(D_float,		&gimTun.posP[0].kP,				"kP",			"",		3);
	dbase.addRow(D_float,		&gimTun.posP[0].kD,				"kD",			"",		3);
	dbase.addRow(D_float,		&gimTun.posP[0].kLim,			"kLim",			"",		3);

	lensPTbl = dbase.addTable("lensP",DB_FLASH,NLENS,sizeof(lensPar_t),MSG_TUNINGS);
	dbase.addRow(D_int32_t,		&gimTun.lensP[0].enable,		"enable",		"",		DL_bool);
	dbase.addRow(D_float,		&gimTun.lensP[0].kP,			"kP",			"",		3);
	dbase.addRow(D_float,		&gimTun.lensP[0].kI,			"kI",			"",		3);
	dbase.addRow(D_float,		&gimTun.lensP[0].kD,			"kD",			"",		3);
	dbase.addRow(D_float,		&gimTun.lensP[0].kFF,			"kFF",			"",		3);
	dbase.addRow(D_float,		&gimTun.lensP[0].kTach,			"kTach",		"",		3);
	dbase.addRow(D_float,		&gimTun.lensP[0].kPwm,			"kPwm",			"",		3);
	dbase.addRow(D_float,		&gimTun.lensP[0].kPwmLim,		"kPwmLim",		"",		3);
	dbase.addRow(D_float,		&gimTun.lensP[0].kPmin,			"kPmin",		"",		3);
	dbase.addRow(D_float,		&gimTun.lensP[0].kPmax,			"kPmax",		"",		3);
	dbase.addRow(D_float,		&gimTun.lensP[0].kSpan0,		"kSpan0",		"",		3);
	dbase.addRow(D_float,		&gimTun.lensP[0].kSpan1,		"kSpan1",		"",		3);

	lensFeedbackTbl = dbase.addTable("lensStates",DB_RAM,NLENS,sizeof(lensState_t),MSG_LENS_FB);
	dbase.addRow(D_float,		&state.lens.lensState[0].pos,	"pos",			"",		3);
	dbase.addRow(D_float,		&state.lens.lensState[0].err,	"err",			"",		3);
	dbase.addRow(D_float,		&state.lens.lensState[0].drive,	"drive",		"",		3);
	dbase.addRow(D_int32_t,		&state.lens.lensState[0].pwm,	"pwm",			"");

	refPidPTbl = dbase.addTable("refPidP",DB_RAM,NiAXES,sizeof(pidPar_t),0);
	dbase.addRow(D_float,		&refTun.pidP[0].kP[0],			"kP[0]",		"",		3);
	dbase.addRow(D_float,		&refTun.pidP[0].kP[1],			"kP[1]",		"",		3);
	dbase.addRow(D_float,		&refTun.pidP[0].kP[2],			"kP[2]",		"",		3);
	dbase.addRow(D_float,		&refTun.pidP[0].kI[0],			"kI[0]",		"",		3);
	dbase.addRow(D_float,		&refTun.pidP[0].kI[1],			"kI[1]",		"",		3);
	dbase.addRow(D_float,		&refTun.pidP[0].kI[2],			"kI[2]",		"",		3);
	dbase.addRow(D_float,		&refTun.pidP[0].kD[0],			"kD[0]",		"",		3);
	dbase.addRow(D_float,		&refTun.pidP[0].kD[1],			"kD[1]",		"",		3);
	dbase.addRow(D_float,		&refTun.pidP[0].kD[2],			"kD[2]",		"",		3);
	dbase.addRow(D_float,		&refTun.pidP[0].kILim[0],		"kILim[0]",		"",		3);
	dbase.addRow(D_float,		&refTun.pidP[0].kILim[1],		"kILim[1]",		"",		3);
	dbase.addRow(D_float,		&refTun.pidP[0].kILim[2],		"kILim[2]",		"",		3);
	dbase.addRow(D_float,		&refTun.pidP[0].kT,				"kT",			"",		3);
	dbase.addRow(D_float,		&refTun.pidP[0].kC,				"kC",			"",		3);

	refFiltP0Tbl = dbase.addTable("refFiltP[0]",DB_RAM,NiFILT,sizeof(filterPar_t),MSG_FILTER_PAR);
	dbase.addRow(D_int32_t,		&refTun.filt.filtP[0][0].ftype,	"ftype",		"",		DL_filt);
	dbase.addRow(D_float,		&refTun.filt.filtP[0][0].f1,	"f1",			"",		2);
	dbase.addRow(D_float,		&refTun.filt.filtP[0][0].q,		"q",			"",		2);

	refFiltP1Tbl = dbase.addTable("refFiltP[1]",DB_RAM,NiFILT,sizeof(filterPar_t),MSG_FILTER_PAR);
	dbase.addRow(D_int32_t,		&refTun.filt.filtP[1][0].ftype,	"ftype",		"",		DL_filt);
	dbase.addRow(D_float,		&refTun.filt.filtP[1][0].f1,	"f1",			"",		2);
	dbase.addRow(D_float,		&refTun.filt.filtP[1][0].q,		"q",			"",		2);

	refFiltP2Tbl = dbase.addTable("refFiltP[2]",DB_RAM,NiFILT,sizeof(filterPar_t),MSG_FILTER_PAR);
	dbase.addRow(D_int32_t,		&refTun.filt.filtP[2][0].ftype,	"ftype",		"",		DL_filt);
	dbase.addRow(D_float,		&refTun.filt.filtP[2][0].f1,	"f1",			"",		2);
	dbase.addRow(D_float,		&refTun.filt.filtP[2][0].q,		"q",			"",		2);

	refOuterPTbl = dbase.addTable("refOuterP",DB_FLASH,NoAXES,sizeof(outerPar_t),MSG_OUTER_PAR);
	dbase.addRow(D_float,		&refTun.outerP[0].kP,			"kP",			"",		4);
	dbase.addRow(D_float,		&refTun.outerP[0].kFF,			"kFF",			"",		4);
	dbase.addRow(D_float,		&refTun.outerP[0].kTach,		"kTach",		"",		4);
	dbase.addRow(D_float,		&refTun.outerP[0].kI,			"kI",			"",		4);
	dbase.addRow(D_float,		&refTun.outerP[0].kILim,		"kILim",		"",		4);

	refGeoPTbl = dbase.addTable("refGeoP",DB_FLASH,NiAXES,sizeof(geoPar_t),MSG_TUNINGS);
	dbase.addRow(D_float,		&refTun.geoP[0].kP,				"kP",			"",		3);
	dbase.addRow(D_float,		&refTun.geoP[0].kP2,			"kP2",			"",		3);
	dbase.addRow(D_float,		&refTun.geoP[0].kI,				"kI",			"",		3);
	dbase.addRow(D_float,		&refTun.geoP[0].kD,				"kD",			"",		3);
	dbase.addRow(D_float,		&refTun.geoP[0].kILim,			"kILim",		"",		3);
	dbase.addRow(D_float,		&refTun.geoP[0].kMystery2,		"kMystery2",	"",		3);

	refPosPTbl = dbase.addTable("refPosP",DB_FLASH,NiAXES,sizeof(posPar_t),MSG_TUNINGS);
	dbase.addRow(D_float,		&refTun.posP[0].kP,				"kP",			"",		3);
	dbase.addRow(D_float,		&refTun.posP[0].kD,				"kD",			"",		3);
	dbase.addRow(D_float,		&refTun.posP[0].kLim,			"kLim",			"",		3);

	refLensPTbl = dbase.addTable("refLensP",DB_FLASH,NLENS,sizeof(lensPar_t),MSG_TUNINGS);
	dbase.addRow(D_int32_t,		&refTun.lensP[0].enable,		"enable",		"",		DL_bool);
	dbase.addRow(D_float,		&refTun.lensP[0].kP,			"kP",			"",		3);
	dbase.addRow(D_float,		&refTun.lensP[0].kI,			"kI",			"",		3);
	dbase.addRow(D_float,		&refTun.lensP[0].kD,			"kD",			"",		3);
	dbase.addRow(D_float,		&refTun.lensP[0].kFF,			"kFF",			"",		3);
	dbase.addRow(D_float,		&refTun.lensP[0].kTach,			"kTach",		"",		3);
	dbase.addRow(D_float,		&refTun.lensP[0].kPwm,			"kPwm",			"",		3);
	dbase.addRow(D_float,		&refTun.lensP[0].kPwmLim,		"kPwmLim",		"",		3);
	dbase.addRow(D_float,		&refTun.lensP[0].kPmin,			"kPmin",		"",		3);
	dbase.addRow(D_float,		&refTun.lensP[0].kPmax,			"kPmax",		"",		3);
	dbase.addRow(D_float,		&refTun.lensP[0].kSpan0,		"kSpan0",		"",		3);
	dbase.addRow(D_float,		&refTun.lensP[0].kSpan1,		"kSpan1",		"",		3);

	navboxTbl = dbase.addTable("navbox",DB_RAM,1,sizeof(bwPar_t),MSG_STATE);
	dbase.addRow(D_float,		&state.navbox.LeverArmGimToImu[0],		"LeverArmGimToImu[0]",		"",		2);
	dbase.addRow(D_float,		&state.navbox.LeverArmGimToImu[1],		"LeverArmGimToImu[1]",		"",		2);
	dbase.addRow(D_float,		&state.navbox.LeverArmGimToImu[2],		"LeverArmGimToImu[2]",		"",		2);
	dbase.addRow(D_float,		&state.navbox.LeverArmGimToPrimAnt[0],	"LeverArmGimToPrimAnt[0]",	"",		2);
	dbase.addRow(D_float,		&state.navbox.LeverArmGimToPrimAnt[1],	"LeverArmGimToPrimAnt[1]",	"",		2);
	dbase.addRow(D_float,		&state.navbox.LeverArmGimToPrimAnt[2],	"LeverArmGimToPrimAnt[2]",	"",		2);
	dbase.addRow(D_float,		&state.navbox.LeverArmGimToSecAnt[0],	"LeverArmGimToSecAnt[0]",	"",		2);
	dbase.addRow(D_float,		&state.navbox.LeverArmGimToSecAnt[1],	"LeverArmGimToSecAnt[1]",	"",		2);
	dbase.addRow(D_float,		&state.navbox.LeverArmGimToSecAnt[2],	"LeverArmGimToSecAnt[2]",	"",		2);
	dbase.addRow(D_uint32_t,	&state.navbox.NovatelCrcCount,			"NovatelCrcCount",			"");
	dbase.addRow(D_uint32_t,	&state.navbox.VectorNavCrcCount,		"VectorNavCrcCount",		"");
	dbase.addRow(D_string,		&state.navbox.NavBoxVerGitSha,			"NavBoxVerGitSha",			"");
	dbase.addRow(D_string,		&state.navbox.NavBoxVerHuman,			"NavBoxVerHuman",			"",sizeof(state.navbox.NavBoxVerHuman));
	dbase.addRow(D_string,		&state.navbox.GimbalVerHuman,			"GimbalVerHuman",			"",sizeof(state.navbox.NavBoxVerHuman));
	dbase.addRow(D_uint16_t,	&state.navbox.NovatelHz,				"NovatelHz\t",				"",sizeof(state.navbox.GimbalVerHuman));
	dbase.addRow(D_uint16_t,	&state.navbox.VectorNavHz,				"VectorNavHz\t",				"");
	dbase.addRow(D_uint16_t,	&state.navbox.GimbalAnglesInHz,			"GimbalAnglesInHz",			"");
	dbase.addRow(D_uint16_t,	&state.navbox.MasterStatusOutHz,		"MasterStatusOutHz",		"");
	dbase.addRow(D_uint16_t,	&state.navbox.ConfigStatusOutHz,		"ConfigStatusOutHz",		"");

	masterStatusTbl = dbase.addTable("masterStatus",DB_RAM,1,sizeof(navToGim_t),MSG_NAV_TO_GIM);
	dbase.addRow(D_uint8_t,		&masterStatus.u8Version,			"u8Version\t",				"");
	dbase.addRow(D_uint8_t,		&masterStatus.u8GeoEvent,			"u8GeoEvent\t",				"");
	dbase.addRow(D_uint8_t,		&masterStatus.u8GimbalMode,			"u8GimbalMode",				"");
	dbase.addRow(D_uint8_t,		&masterStatus.u8SensorStatus,		"u8SensorStatus",			"");
	dbase.addRow(D_uint32_t,	&masterStatus.u32GimSystemTime_us,	"u32GimSystemTime_us",		"");
	dbase.addRow(D_uint32_t,	&masterStatus.u32Frame,				"u32Frame\t",				"");
	dbase.addRow(D_uint16_t,	&masterStatus.u16ClusterID,			"u16ClusterID\t",			"");
	dbase.addRow(D_uint16_t,	&masterStatus.u16TargetID,			"u16TargetID\t",			"");
	dbase.addRow(D_uint16_t,	&masterStatus.u16TotalPower,		"u16TotalPower\t",			"");
	dbase.addRow(D_uint16_t,	&masterStatus.u16GeoStatus,			"u16GeoStatus\t",			"");
	dbase.addRow(D_uint64_t,	&masterStatus.u64GPSTime1980_ms,	"u64GPSTime1980_ms",		"");
	dbase.addRow(D_double,		&masterStatus.dGPSLat,				"dGPSLat\t",				"",9);
	dbase.addRow(D_double,		&masterStatus.dGPSLng,				"dGPSLng\t",				"",9);
	dbase.addRow(D_double,		&masterStatus.dGPSAltELL,			"dGPSAltELL\t",				"",1);
	dbase.addRow(D_float,		&masterStatus.fGPSLatAccu,			"fGPSLatAccu\t",			"",2);
	dbase.addRow(D_float,		&masterStatus.fGPSLngAccu,			"fGPSLngAccu\t",			"",2);
	dbase.addRow(D_float,		&masterStatus.fGPSAltAccu,			"fGPSAltAccu\t",			"",2);
	dbase.addRow(D_float,		&masterStatus.fGPSVelNED[0],		"fGPSVelNED[0]\t",			"",2);
	dbase.addRow(D_float,		&masterStatus.fGPSVelNED[1],		"fGPSVelNED[1]\t",			"",2);
	dbase.addRow(D_float,		&masterStatus.fGPSVelNED[2],		"fGPSVelNED[2]\t",			"",2);
	dbase.addRow(D_uint8_t,		&masterStatus.u8GPSSolutionStatus,	"u8GPSSolutionStatus",		"");
	dbase.addRow(D_uint8_t,		&masterStatus.u8GPSPositionType,	"u8GPSPositionType",		"");
	dbase.addRow(D_uint8_t,		&masterStatus.u8GPSNumOfSat,		"u8GPSNumOfSat",			"");
	dbase.addRow(D_uint8_t,		&masterStatus.u8GPSScaledPDOP,		"u8GPSScaledPDOP",			"");
	dbase.addRow(D_float,		&masterStatus.fGPSHeadingT,			"fGPSHeadingT\t",			"",2);
	dbase.addRow(D_float,		&masterStatus.fGPSPitch,			"fGPSPitch\t",				"",2);
	dbase.addRow(D_float,		&masterStatus.fGPSHeadingAccu,		"fGPSHeadingAccu",			"",2);
	dbase.addRow(D_float,		&masterStatus.fINSYaw,				"fINSYaw\t",				"",2);
	dbase.addRow(D_float,		&masterStatus.fINSPitch,			"fINSPitch\t",				"",2);
	dbase.addRow(D_float,		&masterStatus.fINSRoll,				"fINSRoll\t",				"",2);
	dbase.addRow(D_float,		&masterStatus.fINSYawAccu,			"fINSYawAccu\t",			"",2);
	dbase.addRow(D_float,		&masterStatus.fINSPitchAccu,		"fINSPitchAccu\t",			"",2);
	dbase.addRow(D_float,		&masterStatus.fINSRollAccu,			"fINSRollAccu\t",			"",2);
	dbase.addRow(D_double,		&masterStatus.dINSLat,				"dINSLat\t",				"",9);
	dbase.addRow(D_double,		&masterStatus.dINSLng,				"dINSLng\t",				"",9);
	dbase.addRow(D_double,		&masterStatus.dINSAltELL,			"dINSAltELL\t",				"",1);
	dbase.addRow(D_float,		&masterStatus.fINSPosStdev,			"fINSPosStdev\t",			"",2);
	dbase.addRow(D_float,		&masterStatus.fINSVelStdev,			"fINSVelStdev\t",			"",2);
	dbase.addRow(D_float,		&masterStatus.fINSVelNED[0],		"fINSVelNED[0]\t",			"",2);
	dbase.addRow(D_float,		&masterStatus.fINSVelNED[1],		"fINSVelNED[1]\t",			"",2);
	dbase.addRow(D_float,		&masterStatus.fINSVelNED[2],		"fINSVelNED[2]\t",			"",2);
	dbase.addRow(D_float,		&masterStatus.fINSAngRate[0],		"fINSAngRate[0]",			"",2);
	dbase.addRow(D_float,		&masterStatus.fINSAngRate[1],		"fINSAngRate[1]",			"",2);
	dbase.addRow(D_float,		&masterStatus.fINSAngRate[2],		"fINSAngRate[2]",			"",2);
	dbase.addRow(D_float,		&masterStatus.fPlatformHdgT,		"fPlatformHdgT",			"",2);
	dbase.addRow(D_float,		&masterStatus.fGIMOuter[0],			"fGIMOuter[0]\t",			"",2);
	dbase.addRow(D_float,		&masterStatus.fGIMOuter[1],			"fGIMOuter[1]\t",			"",2);
	dbase.addRow(D_float,		&masterStatus.fGIMOuter[2],			"fGIMOuter[2]\t",			"",2);
	dbase.addRow(D_float,		&masterStatus.fGIMInner[0],			"fGIMInner[0]\t",			"",2);
	dbase.addRow(D_float,		&masterStatus.fGIMInner[1],			"fGIMInner[1]\t",			"",2);
	dbase.addRow(D_float,		&masterStatus.fGIMInner[2],			"fGIMInner[2]\t",			"",2);
	dbase.addRow(D_float,		&masterStatus.fGIMOuterAngRate[0],	"fGIMOuterAngRate[0]",		"",2);
	dbase.addRow(D_float,		&masterStatus.fGIMInnerAngRate[1],	"fGIMInnerAngRate[1]",		"",2);
	dbase.addRow(D_float,		&masterStatus.fGIMInnerAngRate[2],	"fGIMInnerAngRate[2]",		"",2);
	dbase.addRow(D_float,		&masterStatus.fGIMInnerAngRate[0],	"fGIMInnerAngRate[0]",		"",2);
	dbase.addRow(D_float,		&masterStatus.fGIMInnerAngRate[1],	"fGIMInnerAngRate[1]",		"",2);
	dbase.addRow(D_float,		&masterStatus.fGIMInnerAngRate[2],	"fGIMInnerAngRate[2]",		"",2);
	dbase.addRow(D_float,		&masterStatus.fGIMLosJitter,		"fGIMLosJitter\t",			"",2);
	dbase.addRow(D_uint16_t,	&masterStatus.u16GimStatus,			"u16GimStatus\t",			"");
	dbase.addRow(D_int16_t,		&masterStatus.s16GPSBaselineLength,	"s16GPSBaselineLength",		"");
	dbase.addRow(D_double,		&masterStatus.dTargetLat,			"dTargetLat\t",				"",9);
	dbase.addRow(D_double,		&masterStatus.dTargetLng,			"dTargetLng\t",				"",9);
	dbase.addRow(D_double,		&masterStatus.fTargetAltELL,		"fTargetAltELL\t",			"",1);

	emit lastTable();
}
/*
typedef struct {
	float LeverArmGimToImu[3];		// gimbal center to IMU center
	float LeverArmGimToPrimAnt[3];	// gimbal center to primary antenna
	float LeverArmGimToSecAnt[3];	// gimbal center to secondary antenna
	int32_t NovatelCrcCount;		// Novatel CRC error count
	int32_t VectorNavCrcCount;		// VectorNav CRC error count
	char NavBoxVerGitSha[8];		// Version control commit SHA hash, null terminated
	char NavBoxVerHuman[8];			// NavBox human readable version, like v1.2.2, null terminated
	char GimbalVerHuman[8];			// Gimbal human-readable version, null terminated
	uint16_t NovatelHz;				// Novatel incoming packets per second, and VectorNav VNGPE outgoing updates
	uint16_t VectorNavHz;			// VectorNav incoming packets per second
	uint16_t GimbalAnglesInHz;		// Gimbal angles incoming packets per second
	uint16_t MasterStatusOutHz;		// Gimbal MasterStatusDEF outgoing packets per second (as requested by gimbal)
} navBoxConfigStatus_t;
*/
//	---------------------------------------------------------------------------
//	edit
//	---------------------------------------------------------------------------

void gimbalData::edit(int key, int axis, int filter, const char *vstring)
{
	if(strlen(vstring)<sizeof(editVString)){
		strcpy(editVString,vstring);
		editKey = key;
		editAxis = axis;
		editFilt = filter;
		editType = 0;
	}else{
		editKey = 0;
	}
}

//	---------------------------------------------------------------------------
//	edit
//	---------------------------------------------------------------------------

void gimbalData::editI(int key, int axis, int filter, int value)
{
	editKey = key;
	editAxis = axis;
	editFilt = filter;
	editPar = value;
	editType = 1;
}

//	---------------------------------------------------------------------------
//	sendError
//	---------------------------------------------------------------------------

void gimbalData::sendError(int socketError,const QString &message){
	emit errorx(0, socketError, message);
}

//	---------------------------------------------------------------------------
//	sendCommError
//	---------------------------------------------------------------------------

void gimbalData::sendCommError(int socketError,const QString &message)
{
	if(socketError == -1){
		emit errorx(0, socketError, message);
	}else{
		emit errorx(1, socketError, message);
	}
}

//	----------------------------------------------------------------------------
//	stop
//	----------------------------------------------------------------------------

void gimbalData::stop()
{
	quit = 1;
	gim->closePort();
	cons->closePort();
	//	deleteLater();
}

//	----------------------------------------------------------------------------
//	newMsg
//	----------------------------------------------------------------------------

void gimbalData::newMsg(unsigned char *message, int numread)
{
	parseMsgX(message,numread);
}


//  ---------------------------------------------------------------------------------
//  pidType
//  ---------------------------------------------------------------------------------

int pidType(int mode)
{
	int ipid = PID_RATE;

	switch(mode){

	case MODE_RATE:
		ipid = PID_RATE;
		break;

	case MODE_GEO:
		ipid = PID_GEO;
		break;

	case MODE_SLAVE:
	case MODE_OUTER:
	case MODE_STOW:
		ipid = PID_POSN;
		break;
	}
	return ipid;
}

//	----------------------------------------------------------------------------
//	setModeX
//	----------------------------------------------------------------------------

void setModeX(int modeX)
{
	switch(modeX){
		case MODEX_RATE:
		case MODEX_SLAVE:
		case MODEX_GEO:
		case MODEX_OUTER:
		case MODEX_STOW:
			steeringOut.mode = modeX;
			steeringOut.standby = 0;
			break;
		case MODEX_STANDBY:
			steeringOut.standby = 1;
		break;
	}
	cmdSteering = 1;
}
