#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SylvacDial.h"


ClassImp(SylvacDial)

SylvacDial::SylvacDial()

////////////////////////////////////////////////////////////
// This class implements control and readout of a         //
// Sylvac dial gauge S_Dial Work equipped with a          //
// FTDI FT232 USB-Serial converter identified by its      // 
// USB ID:  0403:6001                                     //
// The software makes use of libftdi.so provided by       //
// e.g. the Ubuntu package libftdi-dev                    //
//                                                        //
// In a root session you can do:                          //
//                                                        // 
// gSystem->Load("/usr/lib/x86_64-linux-gnu/libftdi.so"); //
// gROOT->ProcessLine(".L SylvacDial.cxx+");              //
// SylvacDial *sd = new SylvacDial();                     //
////////////////////////////////////////////////////////////

{
	int ret; 
//	struct ftdi_context *ftdi;
//	struct ftdi_version_info version;
	if ((ftdi = ftdi_new()) == 0)
	{
		fprintf(stderr, "ftdi_new failed\n");
		return;
	}
// Sylvac S_Dial work, VendorId, DeviceId
	if ((ret = ftdi_usb_open(ftdi, 0x0403, 0x6001)) < 0)
	{
		fprintf(stderr, "unable to open ftdi device: %d (%s)\n", ret, ftdi_get_error_string(ftdi));
		ftdi_free(ftdi);
		return;
	}
	// Read out FTDIChip-ID of R type chips
	if (ftdi->type == TYPE_R)
	{
		unsigned int chipid;
		ret = ftdi_read_chipid(ftdi, &chipid);
		if ( ret == 0 )
			printf("FTDI chipid: %X\n", chipid);
		else
			printf("Error reading FTDI chipid: %d\n", ret );
	}
	// Set serial RS232 properties
	ret = ftdi_set_baudrate(ftdi, 4800);
	ret = ftdi_set_line_property2 (ftdi, BITS_7,  STOP_BIT_2, EVEN, BREAK_OFF);
	ret = ftdi_setflowctrl(ftdi, 1);
	//
	SetVerbose(1);
	SetMode("NOR");
	GetSense();
	GetFunCache();
	GetUnit();
	GetKeyLock();
	GetMulFac();
	GetPresetValue();
	GetReference();
	GetHold();
	GetTolLimits();
	GetLCal();
	GetNCal();
	GetMode();
	GetMainParams();
	GetId();
	
	GetBatt();
	GetFwVersion();
	fTolLimitsActiveState = kFALSE;
	
	GetValue();
}
//______________________________________________________________	

SylvacDial::~SylvacDial()
{	
	int ret;
	if ((ret = ftdi_usb_close(ftdi) ) < 0)
	{
		fprintf(stderr, "Unable to close ftdi device: %d (%s)\n", 
		ret, ftdi_get_error_string(ftdi));
		ftdi_free(ftdi);
	}
	ftdi_free(ftdi);
}
//_________________________________________________________

int SylvacDial::GetData(TString *str, const char *tit)
{
	usleep(200000);   // 200 msec
	ClearBuf();
	int rsize=ftdi_read_data(ftdi, fBuf, MAXBUF);
	if (rsize > 0 ) {
		for (int i=0; i 0 ) {
			printf("%s %s\n", tit, str->Data());
//			PrintData(fBuf, rsize);
		}
		ClearBuf();
	}
	return rsize;
}
//_________________________________________________________

const char * SylvacDial::GetSense()
{
	// Get measurement direction +-
	ftdi_write_data(ftdi, (unsigned char*)"CHA?\r", 5);
   int rsize = GetData(&fSense, "Measurement sense");
	if (rsize > 0 ) {
		return fSense.Data();
	} else {
		printf("GetSense(): Error\n");
		return NULL;
	}
}
//_________________________________________________________

const char * SylvacDial::GetFunCache()
{
	// Current function cache
	ftdi_write_data(ftdi, (unsigned char*)"FCT?\r", 5);
   int rsize = GetData(&fFunCache, "Function cache active");
	if (rsize > 0 ) {
		return fId.Data();
	} else {
		printf("GetFunCache: Error\n");
		return NULL;
	}
}
//_________________________________________________________

const char * SylvacDial::GetUnit()
{
	// Active measurement unit mm/inch
	ftdi_write_data(ftdi, (unsigned char*)"UNI?\r", 5);
   int rsize = GetData(&fUnit, "Measurement unit active");
	if (rsize > 0 ) {
		return fId.Data();
	} else {
		printf("Unit: Error\n");
		return NULL;
	}
}
//_________________________________________________________

const char * SylvacDial::GetKeyLock()
{
	// Keypad locked?
	ftdi_write_data(ftdi, (unsigned char*)"KEY?\r", 5);
   int rsize = GetData(&fKeyLock, "Keypad locked");
	if (rsize > 0 ) {
		return fId.Data();
	} else {
		printf("GetKeyLock: Error\n");
		return NULL;
	}
}
//_________________________________________________________

const char * SylvacDial::GetMulFac()
{
	// Get Multiplication factor
	ftdi_write_data(ftdi, (unsigned char*)"MUL?\r", 5);
   int rsize = GetData(&fMulFac, "Multiplication factor");
	if (rsize > 0 ) {
		return fId.Data();
	} else {
		printf("GetMulFac: Error\n");
		return NULL;
	}
}
//_________________________________________________________

const char * SylvacDial::GetPresetValue()
{
	// Get Preset value
	ftdi_write_data(ftdi, (unsigned char*)"PRE?\r", 5);
   int rsize = GetData(&fPresetValue, "Preset value");
	if (rsize > 0 ) {
		return fId.Data();
	} else {
		printf("GetPresetValue: Error\n");
		return NULL;
	}
}
//_________________________________________________________

const char * SylvacDial::GetReference()
{
	// Reference activ?
	ftdi_write_data(ftdi, (unsigned char*)"REF?\r", 5);
   int rsize = GetData(&fReference, "Reference activ");
	if (rsize > 0 ) {
		return fId.Data();
	} else {
		printf("GetReference(): Error\n");
		return NULL;
	}
}
//_________________________________________________________

const char * SylvacDial::GetHold()
{
	// Status of hold function
	ftdi_write_data(ftdi, (unsigned char*)"STO?\r", 5);
   int rsize = GetData(&fHold, "Status of hold function");
	if (rsize > 0 ) {
		return fId.Data();
	} else {
		printf("GetHold: Error\n");
		return NULL;
	}
}
//_________________________________________________________

const char * SylvacDial::GetTolLimits()
{
	//Current tolerance limit values
	ftdi_write_data(ftdi, (unsigned char*)"TOL?\r", 5);
   int rsize = GetData(&fTolLimits, "Current tolerance limit values");
	if (rsize > 0 ) {
		return fTolLimits.Data();
	} else {
		printf("GetTol: Error\n");
		return NULL;
	}
}
//_________________________________________________________

const char * SylvacDial::GetLCal()
{
	// last calibration
	ftdi_write_data(ftdi, (unsigned char*)"LCAL?\r", 6);
   int rsize = GetData(&fLCal, "Last calibration");
	if (rsize > 0 ) {
		return fLCal.Data();
	} else {
		printf("GetLcal(): Error\n");
		return NULL;
	}
}
//_________________________________________________________

const char * SylvacDial::GetNCal()
{
	// Next calibration
	ftdi_write_data(ftdi, (unsigned char*)"NCAL?\r", 6);
   int rsize = GetData(&fNCal, "Next calibration");
	if (rsize > 0 ) {
		return fNCal.Data();
	} else {
		printf("GetNCal(): Error\n");
		return NULL;
	}
}
//_________________________________________________________

double SylvacDial::GetValue()
{
	// Read value from device depending on active mode: MIN, MAX, DEL, NOR 
	ftdi_write_data(ftdi, (unsigned char*)"?\r", 2);
   usleep(200000);   // 200 msec
   ClearBuf();
	int rsize=ftdi_read_data(ftdi, fBuf, MAXBUF);
	
	if (rsize > 0 ) {
		fValue = atof((char*)fBuf);
		if (fVerbose > 0 ) {
			printf("Value: %f\n", fValue);
		}
		ClearBuf();
		return fValue;
	} else {
		printf("GetValue(): Error\n");
		return 0;
	}
}
//_________________________________________________________

const char * SylvacDial::GetMode()
{
	// Current active mode: MIN, MAX, DEL, NORmal
	ftdi_write_data(ftdi, (unsigned char*)"MOD?\r", 5);
   int rsize = GetData(&fMode, "Current active mode");
	if (rsize > 0 ) {
		return fMode.Data();
	} else {
		printf("GetMode(): Error\n");
		return NULL;
	}
}
//_________________________________________________________

const char * SylvacDial::GetMainParams()
{
	// Get Main instrument parmeters
	ftdi_write_data(ftdi, (unsigned char*)"SET?\r", 5);
   int rsize = GetData(&fMainParams, "Main instrument parmeters");
	if (rsize > 0 ) {
		return fMainParams.Data();
	} else {
		printf("GetSettings(): Error\n");
		return NULL;
	}
}
//_________________________________________________________

const char * SylvacDial::GetId()
{
	// Instrument Id code
	ftdi_write_data(ftdi, (unsigned char*)"ID?\r", 4);
   int rsize = GetData(&fId, "Instrument Id code");
	if (rsize > 0 ) {
		return fId.Data();
	} else {
		printf("GetId(): Error\n");
		return NULL;
	}
}
//_________________________________________________________

const char * SylvacDial::GetBatt()
{
	// "Battery status, BAT1 = ok, BAT0 low
	ftdi_write_data(ftdi, (unsigned char*)"BAT?\r", 5);
   int rsize = GetData(&fBatt, "battery status, BAT1 = ok, BAT0 low");
	if (rsize > 0 ) {
		return fId.Data();
	} else {
		printf("GetBatt(): Error\n");
		return NULL;
	}
}
//_________________________________________________________

const char * SylvacDial::GetFwVersion()
{
	//Version No and date of firmware
	
	ftdi_write_data(ftdi, (unsigned char*)"VER?\r", 5);
   int rsize = GetData(&fFwVersion, "Version No and date of firmware");
	if (rsize > 0 ) {
		return fFwVersion.Data();
	} else {
		printf("GetFwVersion(): Error\n");
		return NULL;
	}
}
//_________________________________________________________

int SylvacDial::SetMode(const char * mode)
{
	//mode: MIN, MAX, DEL, NOR 
	if (strncmp(mode,"MIN",3) != 0 &&  strncmp(mode,"MAX",3) != 0
	 && strncmp(mode,"DEL",3) != 0 &&  strncmp(mode,"NOR",3) != 0 ) {
		printf("SetMode illegal %s\n", mode);
		return -1;;
	}
	char mmm[5];
	strcpy (mmm,mode);
	strcat (mmm,"\r");
	printf ("SetMode: %s\n", mmm);
// 	int wr = ftdi_write_data(ftdi, (unsigned char*)"MAX\r", 4);
 	int wr = ftdi_write_data(ftdi, (unsigned char*)mmm, strlen(mmm));
   usleep(500000);   // 500 msec
   int vsave = fVerbose;
   GetMode();
   fVerbose = vsave;
   return wr;
}
//_________________________________________________________

int SylvacDial::SetSense(const char * sense)
{
// Change Measurement direction "+" / "-"
	if (strncmp(sense,"+",1) != 0 && strncmp(sense,"-",1)) {
		printf("SetSense Illegal: %s\n", sense);
		return -1;;
	}
	TString cmd("CHA");
	cmd += sense;
	int wr = ftdi_write_data(ftdi, (unsigned char*)cmd.Data(), 4);
	if (wr >0) {
		printf("New measurement direction: %s\n",  GetSense());
	}
	return wr;
}	
//_________________________________________________________

int SylvacDial::SetTolLimits(double x, double y)
{
	// Set tolerance limits, 
	// to activate / deactivate use ActivateTolLimits(kTRUE, kFALSE)
	
	int wr = -1;
	TString cmd("TOL ");
	cmd += Form("%+08.3f", x);
	cmd += " ";
	cmd += Form("%+08.3f", y);
	cmd +="\r";
	printf("SetTolLimits: %s\n", cmd.Data());
	wr = ftdi_write_data(ftdi, (unsigned char*)cmd.Data(), cmd.Length());
	if (wr >0) {
		printf("New tolerance limits %s\n",  GetTolLimits());
	} else {
		printf("SetTolLimits Error\n");
	}	
	return wr;
}
//_________________________________________________________

int SylvacDial::ActivateTolLimits(Bool_t active)
{
	// activate / deactivate TolLimits
	TString cmd("TOL");
	if (active ) {
		cmd += "1\r";
	} else {
		cmd += "0\r";
	}
	int wr = ftdi_write_data(ftdi, (unsigned char*)cmd.Data(), cmd.Length());
	if (wr >0) {
		printf("Tolerance limits: ");
		if ( active ) {
			fTolLimitsActiveState = kTRUE;
			printf("activated\n");
		} else {
			fTolLimitsActiveState = kFALSE;
			printf("deactivated\n");
		}
	} else {
		printf("ActivateTolLimits Error\n");
	}	
	return wr;
}	
//_________________________________________________________

void SylvacDial::Reset()
{
	// Reinitialize MIN, MAX, DEL
	usleep(500000);   // 500 msec
	int wr = ftdi_write_data(ftdi, (unsigned char*)"CLE\r" , 4);
	usleep(500000);   // 500 msec
   ClearBuf();
	wr=ftdi_read_data(ftdi, fBuf, MAXBUF);
	if (wr > 0) {
		if (fVerbose > 0) {
			printf("After reset ");
			PrintData(fBuf, wr);
		}
		ClearBuf();
	}
}
//_________________________________________________________

int SylvacDial::SetFunCache(const char * /*func*/)
{
	// Set function cache
	printf("Not yet implemented\n");
	return -1;
}
//_________________________________________________________

int SylvacDial::SetUnit(const char * /*unit*/)
{
	// Set Unit mm/in
	printf("Not yet implemented\n");
	return -1;
}
//_________________________________________________________

int SylvacDial::SetKeyLock(Bool_t /*lock*/)
{
	// Key lock
	printf("Not yet implemented\n");
	return -1;
}
//_________________________________________________________

int SylvacDial::SetMulFac(double /*mul*/)
{
	// Set multiplication factor
	printf("Not yet implemented\n");
	return -1;
}
//_________________________________________________________

int SylvacDial::SetPresetValue(double /*preset*/)
{
	//Set preset value
	printf("Not yet implemented\n");
	return -1;
}
//_________________________________________________________

int SylvacDial::SetReference(const char * /*REF*/)
{
	// Set rererence value
	printf("Not yet implemented\n");
	return -1;
}
//_________________________________________________________

int SylvacDial::SetHold(Bool_t /*hold*/)
{
	// Set HOLD status
	printf("Not yet implemented\n");
	return -1;
}
//_________________________________________________________

//_________________________________________________________

int SylvacDial::SetLCal(const char * /*date*/)
{
	// Set date of last calibration dd.mm.yy
	printf("Not yet implemented\n");
	return -1;
}
//_________________________________________________________

int SylvacDial::SetNCal(const char * /*date*/)
{
	// Set date of next calibration dd.mm.yy
	printf("Not yet implemented\n");
	return -1;
}
//_________________________________________________________

void SylvacDial::PrintData(unsigned char * buf, int rsize)
{
	if (rsize <= 0) {
		printf("ftdi_read_data: %d\n", rsize);
		return;
	}
   for (int i=0; i