// TDR_meas.c
// Control program for HP54121T Using MAC ADIOS 488s

// if you are not use NI488.2 please comment out the following-line
#define NI488
// if you are not use IOTech Mac SCSI488 please comment out the following-line
//#define IOTECH


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Sound.h>
#include <Strings.h>

#ifdef IOTECH
#include "IeeeIO.h"
#endif
#ifdef NI488
#include "decl.h"
#endif

#include "TDR_meas.h"

#define GPIB_MESSAGEDLG_ID 850

// in TDR.h 
extern double *TA;
extern double *RS;
extern double *RX;
extern double *RB;
extern double *RC;
extern double *dR;
extern double *dC;
extern double *CHAN1;
extern short GPIBAddress;
extern TDR_OPINFO oinfo;

// entry function  
short  TDR_Get2Data(TDR_PREAMBLE *pre, TDR_OPINFO *oinfo);
short  TDR_Get3Data(TDR_PREAMBLE *pre, TDR_OPINFO *oinfo);
short  TDR_GetM2M3Data(TDR_PREAMBLE *pre, TDR_OPINFO *oinfo);
short  TDR_Get1Data(short memindex, TDR_PREAMBLE *pre, TDR_OPINFO *oinfo);

// local function
static short GetMemory(short no, TDR_PREAMBLE *pre, double *memory);
static void GetPreamble(TDR_PREAMBLE *pre, char *str);
static short CheckMesCond(TDR_PREAMBLE *p1, TDR_PREAMBLE *p2);
static void GetCurrOPInfo(TDR_OPINFO *oinfo);

// from "TDR_connect.cp"
void showIeeeMsg(unsigned char *str0, unsigned char *str1, unsigned char *str2, unsigned char *str3);

#ifdef IOTECH
void ec(int signal);
void isr();
#endif

// return status byte
short gpib_status;

/* get data for time axis, Rs, Rx */
/* memory 1 for RS and memory 2 for RX */
/* causion! calculate  Rs-Rx and put the rexult to dR */
short  TDR_Get2Data(TDR_PREAMBLE *pre, TDR_OPINFO *oinfo)
{
	short i;
	void isr();
	char outcmd[L_GPIBBUF];
	TDR_PREAMBLE pre1, pre2;

#ifdef IOTECH
	if (ieeeinit()!=noErr) {
		showIeeeMsg("\pieeeinit failed!", "\p","\p","\p");
		return -1;
	}

	/* Enable interrupt checking and set up service routine */
	ieee_ckactive = ckactive;
	ieee_isr = isr;

	ieeewt("clear\n");
	ieeewt("remote\n");
	ieeewt("time out 5\n");

	sprintf(outcmd, "remote %02d\n", GPIBAddress);	
	ieeewt(outcmd);
#endif

#ifdef NI488
	SendIFC(0);
	DevClear(0, GPIBAddress);
	if(ibsta & ERR){
		showIeeeMsg("\pDevClear Error", "\p","\p","\p");
	}
#endif

	if(GetMemory(2, &pre2, RX) == -1) return -1;
	if(GetMemory(1, &pre1, RS) == -1) return -1;
	
	/* check measurement condition */
	if(CheckMesCond(&pre1, &pre2) != 0) return -1;
	
	/* make time axis and deffernce*/
	for(i = 0 ; i < N_GPIBDATA ; i++){
		*(TA + i) = (double)i * pre1.xincrement;
		*(dR + i) = *(RS + i) - *(RX + i);
	}
	*pre = pre1;

	GetCurrOPInfo(oinfo);

#ifdef NI488
    ibonl (0,0);		/* to disable hardare and software */
#endif

	return 0;
}

/* suppose that DC-reference and sample */
short  TDR_GetM2M3Data(TDR_PREAMBLE *pre, TDR_OPINFO *oinfo)
{
	short i;
	void isr();
	char outcmd[L_GPIBBUF];
	TDR_PREAMBLE pre1, pre2;

#ifdef IOTECH
	if (ieeeinit()!=noErr) {
		showIeeeMsg("\pieeeinit failed!", "\p","\p","\p");
		return -1;
	}

	/* Enable interrupt checking and set up service routine */
	ieee_ckactive = ckactive;
	ieee_isr = isr;

	ieeewt("clear\n");
	ieeewt("remote\n");
	ieeewt("time out 5\n");

	sprintf(outcmd, "remote %02d\n", GPIBAddress);	
	ieeewt(outcmd);
#endif

#ifdef NI488
	SendIFC(0);
	DevClear(0, GPIBAddress);
	if(ibsta & ERR){
		showIeeeMsg("\pDevClear Error", "\p","\p","\p");
	}
#endif

	if(GetMemory(3, &pre2, RX) == -1) return -1;
	if(GetMemory(2, &pre1, RS) == -1) return -1;
	
	/* check measurement condition */
	if(CheckMesCond(&pre1, &pre2) != 0) return -1;
	
	/* make time axis */
	for(i = 0 ; i < N_GPIBDATA ; i++){
		*(TA + i) = (double)i * pre1.xincrement;
	}
	*pre = pre1;
	
	GetCurrOPInfo(oinfo);

#ifdef NI488
    ibonl (0,0);		/* to disable hardare and software */
#endif

	return 0;
}



/* get data for time axis, Rs, Rc, Rx */
/* memory 1 for RS ,memory 2 for RC and memory 3 for RX */
/* causion! copy RS value to RB */
short  TDR_Get3Data(TDR_PREAMBLE *pre, TDR_OPINFO *oinfo)
{
	short i;
	void isr();	
	char outcmd[L_GPIBBUF];
	TDR_PREAMBLE pre1, pre2, pre3;

#ifdef IOTECH
	if (ieeeinit()!=noErr) {
		showIeeeMsg("\pieeeinit failed!", "\p","\p","\p");
		return -1;
	}

	/* Enable interrupt checking and set up service routine */
	ieee_ckactive = ckactive;
	ieee_isr = isr;

	ieeewt("clear\n");
	ieeewt("remote\n");
	ieeewt("time out 5\n");

	sprintf(outcmd, "remote %02d\n", GPIBAddress);	
	ieeewt(outcmd);
#endif

#ifdef NI488
	SendIFC(0);
	DevClear(0, GPIBAddress);
	if(ibsta & ERR){
		showIeeeMsg("\pDevClear Error", "\p","\p","\p");
	}
#endif

	if(GetMemory(2, &pre2, RC) == -1) return -1;
	if(GetMemory(1, &pre1, RS) == -1) return -1;
	if(GetMemory(3, &pre3, RX) == -1) return -1;

	if(GetMemory(1, &pre1, RB) == -1) return -1;
	
	/* check measurement condition */
	if(CheckMesCond(&pre1, &pre2) != 0) return -1;
	if(CheckMesCond(&pre2, &pre3) != 0) return -1;
	/* make time axis */
	for(i = 0 ; i < N_GPIBDATA ; i++){
		*(TA + i) = (double)i * pre1.xincrement;
	}
	*pre = pre1;

	GetCurrOPInfo(oinfo);

#ifdef NI488
    ibonl (0,0);		/* to disable hardare and software */
#endif

	return 0;
}

short TDR_Get1Data(short memindex, TDR_PREAMBLE *pre, TDR_OPINFO *oinfo)
{
	short i;
	void isr();
	char outcmd[L_GPIBBUF];

#ifdef IOTECH
	if (ieeeinit()!=noErr) {
		showIeeeMsg("\pieeeinit failed!", "\p","\p","\p");
		return -1;
	}

	/* Enable interrupt checking and set up service routine */
	ieee_ckactive = ckactive;
	ieee_isr = isr;

	ieeewt("clear\n");
	ieeewt("remote\n");
	ieeewt("time out 5\n");

	sprintf(outcmd, "remote %02d\n", GPIBAddress);	
	ieeewt(outcmd);
#endif

#ifdef NI488
	SendIFC(0);
	DevClear(0, GPIBAddress);
	if(ibsta & ERR){
		showIeeeMsg("\pDevClear Error", "\p","\p","\p");
	}
#endif

	if(GetMemory(memindex, pre, CHAN1) == -1) return -1;
	/* make time axis */
	for(i = 0 ; i < N_GPIBDATA ; i++){
		*(TA + i) = (double)i * pre->xincrement;
	}
	
	GetCurrOPInfo(oinfo);

	return 0;
}

/* get data from memory of HP54121T */
/* no is number of memory(from 1 to 4) */
/* return Preamble correspond to memory no */
/*        and memory(in V )                */
static short GetMemory(short no, TDR_PREAMBLE *pre, double *memory)
{
	char buf[L_GPIBBUF];
	char outcmd[L_GPIBBUF];
	short l_size, blocksize, points, i;
	short block[N_GPIBDATA];
	char setmemory[L_GPIBBUF];
	char response[L_GPIBBUF*2];

#ifdef IOTECH
	sprintf(outcmd, "output %02d;:SYSTEM:HEADER OFF;:EOI ON\n", GPIBAddress);
	ieeewt(outcmd);
	
	sprintf(setmemory, "output %02d;:WAVEFORM:SOURCE WMEMORY%d;FORMAT WORD\n", GPIBAddress, no);
	ieeewt(setmemory);	

	sprintf(outcmd, "output %02d;:WAVEFORM:PREAMBLE?\n", GPIBAddress);
	ieeewt(outcmd);
	sprintf(outcmd, "enter %02d #128 EOI\n", GPIBAddress);
	ieeewt(outcmd);
	_ieeerd(ieee, buf, sizeof(char)*128);
#endif

#ifdef NI488
	strcpy(outcmd, ":SYSTEM:HEADER OFF;:EOI ON");
	Send(0, GPIBAddress, outcmd, (long)strlen(outcmd), DABend);
	sprintf(outcmd, ":WAVEFORM:SOURCE WMEMORY%d;FORMAT WORD", no);
	Send(0, GPIBAddress, outcmd, (long)strlen(outcmd), DABend);
	strcpy(outcmd, ":WAVEFORM:PREAMBLE?");
	Send(0, GPIBAddress, outcmd, (long)strlen(outcmd), DABend);
	Receive(0, GPIBAddress, buf, 128L, STOPend);
#endif


	GetPreamble(pre, buf);

	/* get memory data */
#ifdef IOTECH
	sprintf(outcmd, "output %02d;:WAVEFORM:DATA?\n", GPIBAddress);
	ieeewt(outcmd);	
	sprintf(outcmd, "enter %02d\n", GPIBAddress);
	ieeewt(outcmd);
	_ieeerd(ieee, buf, sizeof(char));	/* read '#' (and skip) */
	_ieeerd(ieee, buf, sizeof(char));   /* read number of digit show the size of following data block */
#endif

#ifdef NI488
	strcpy(outcmd, ":WAVEFORM:DATA?");
	Send(0, GPIBAddress, outcmd, (long)strlen(outcmd), DABend);
	Receive(0, GPIBAddress, buf, 1L, STOPend);	/* read '#' (and skip) */
	Receive(0, GPIBAddress, buf, 1L, STOPend);	/* read number of digit show the size of following data block */
#endif

	buf[1] = '\0';						/* null termination */
	l_size = atoi(buf);

#ifdef IOTECH
	_ieeerd(ieee, buf, sizeof(char)*l_size);	/* number of bytes that follows */
#endif

#ifdef NI488
	Receive(0, GPIBAddress, buf, (long)(sizeof(char)*l_size), STOPend);	/* number of bytes that follows */
#endif

	buf[l_size] = '\0';
	blocksize = atoi(buf);
	points = blocksize / 2;		/* WORD is 2 byte. */

	if(points > N_GPIBDATA){
		showIeeeMsg("\p# of data from Preamble is larger than N_GPIBDATA",
					"\p","\p","\p");
		return -1;
	}
	
	/* read data in # no memory */
#ifdef IOTECH
	_ieeerd(ieee, (char *)block, sizeof(short)*points);
#endif

#ifdef NI488
	Receive(0, GPIBAddress, block, (long)(sizeof(short)*points), STOPend);	
#endif

	for(i = 0 ; i < points ; i++){
		*(memory + i) = ((double)block[i] - pre->yreference) * pre->yincrement + pre->yorigin;
	}

#ifdef IOTECH
	/* read response */
	/* I cannot understand why I must read the response at this position */
	ieeerd(response);
#endif


	return 0;
}


static void GetPreamble(TDR_PREAMBLE *pre, char *str)
{
	short i;
	double format, type, points, count;
	double xincrement, xorigin, xreference, yincrement, yorigin, yreference, yrange;

	for(i = 0 ; i < L_GPIBBUF ; i++){
		if(*(str + i) == ',') *(str + i) = ' ';
		if(*(str + i) == CR || *(str + i) == LF) *(str + i) = '\0';
	}
	sscanf(str, "%le %le %le %le %le %le %le %le %le %le %le",
				&format, &type, &points, &count,
				&xincrement, &xorigin, &xreference,
				&yincrement, &yorigin, &yreference, &yrange);

	
	pre->format = (short)format;
	pre->type = (short)type;
	pre->points = (short)points;
	pre->count = (short)count;
	pre->xincrement = xincrement;
	pre->xorigin = xorigin;
	pre->xreference = xreference;
	pre->yincrement = yincrement;
	pre->yorigin = yorigin;
	pre->yreference = yreference;
	pre->yrange = yrange;
}

static void GetCurrOPInfo(TDR_OPINFO *oinfo)
{
	extern char op_name[];			// in TDR.h
	extern char op_comment[];		// in TDR.h
	unsigned long secs;
	Str255 datestr, timestr;
	
	strcpy(oinfo->operator_name, op_name);
	strcpy(oinfo->operation_comment, op_comment);
	GetDateTime(&secs);
	IUDateString(secs, abbrevDate, datestr);
	IUTimeString(secs, true, timestr);
	strcpy(oinfo->acquisition_time, PtoCstr(datestr));
	strcat(oinfo->acquisition_time, PtoCstr(timestr));
	strcpy(oinfo->processing_time, "");
}
	
	

/* if p1 is different from p2 , show error message and return -1 */
/* p1 equals p2, return 0 */
static short CheckMesCond(TDR_PREAMBLE *p1, TDR_PREAMBLE *p2)
{
	if(p1->count != p2->count){
		showIeeeMsg("\pMeasurement Condition Error!",
					"\pAccumulation number of memory1 and memory2 are different.",
					"\p","\p");
		return -1;
	}
	if(p1->xincrement != p2->xincrement){
		showIeeeMsg("\pMeasurement Condition Error!",
					"\pTime scale of memory1 and memory2 are different.",
					"\p","\p");
		return -1;
	}
	if(p1->xorigin != p2->xorigin){
		showIeeeMsg("\pMeasurement Condition Error!",
					"\pTime scale of memory1 and memory2 are different.",
					"\p","\p");
		return -1;
	}
	if(p1->xreference != p2->xreference){
		showIeeeMsg("\pMeasurement Condition Error!",
					"\pxreference of memory1 and memory2 are different.",
					"\p","\p");
		return -1;
	}
	if(p1->yincrement != p2->yincrement){
		showIeeeMsg("\pMeasurement Condition Error!",
					"\pVolt/Div of memory1 and memory2 are different.",
					"\p","\p");
		return -1;
	}
	if(p1->yorigin != p2->yorigin){
		showIeeeMsg("\pMeasurement Condition Error!",
					"\pyoligin of memory1 and memory2 are different.",
					"\p","\p");
		return -1;
	}
	if(p1->yreference != p2->yreference){
		showIeeeMsg("\pMeasurement Condition Error!",
					"\pyreference of memory1 and memory2 are different.",
					"\p","\p");
		return -1;
	}
	if(p1->yrange != p2->yrange){
		showIeeeMsg("\pMeasurement Condition Error!",
					"\pyrange of memory1 and memory2 are different.",
					"\p","\p");
		return -1;
	}

	return 0;
}


#ifdef IOTECH
/* Interrupt service routine for monitored IEEE interface conditions */
void isr()
{	int		sp;
	char str[256];

	/* Turn off interrupt checking during the ISR */
	ieee_ckactive = _false_;

	/* Check if the interrupt was doe to a Service Request */
	ieeewt("spoll\n");
	ieeescnf("%d",&sp);
	gpib_status = sp;	// return value
	if (sp==0) {
		sprintf(str, "Non-SRQ Interrupt!");
		showIeeeMsg("\pInterrupt detected...", C2PStr(str), "\p","\p"); 
		exit(0);
	}

	/* Re-enable interrupt checking */
	ieee_ckactive = ckactive;
}


void ec(int signal)
{	
/* void */
}
#endif


void showIeeeMsg(unsigned char *str0, unsigned char *str1, unsigned char *str2, unsigned char *str3)
{
	DialogPtr dlg;
	short item;
	GrafPtr cptr;
	
	GetPort(&cptr);

	ParamText((unsigned char *)str0,
	          (unsigned char *)str1,
			  (unsigned char *)str2,
			  (unsigned char *)str3);
	
	dlg = GetNewDialog(GPIB_MESSAGEDLG_ID, 0, (WindowPtr)-1);
	SysBeep(1);
	
	SetPort(dlg);
	while(1){
		ModalDialog(0, &item);
		if(item == 1){	/* OK */
			break;
		}
	}
	DisposeDialog(dlg);
	
	SetPort(cptr);

}

