/*
	max547Driver.cpp
	-----------

	Drive code that handles interface to extra MAX547 DAC channel for each arm. For symmetry
	reason, each MAX547 board only provides a single DAC output.

   */

#include <stdio.h>
#include <stdlib.h>
#include <iostream.h>
#include <math.h>
#include <termios.h>
#include <sys/sched.h>
#include <sys/types.h>
#include <unistd.h>

#include "driver/PrTimer.h"
#include "driver/PrSTGDefn.h"
#include "max547Driver.h"
#include "Definitions.h"

#define DELAY_1MS		7159		// 1 ms delay if timer crystal is 7.159 MHz

#define HZ  4000

#define BUFFER_SIZE		120*HZ	// buffer to hold 30 seconds of data	
#define BUFFER_COL		10	

// CONSTRUCTOR FUNCTION
max547Driver::max547Driver(ServoToGo *stgPtr)
{
	int i;
	stg = stgPtr;

	initDriver();

//	writeData(0);
}

// DESTRUCTOR FUNCTION
max547Driver::~max547Driver()
{
	stg->RawDO(0x00, PORTC);
	stg->RawDO(0x00, PORTA);
	stg->RawDO(0x00, PORTB);
	writeData(0);

	stg->RawDO(CLR_BIT, 0, PORTC);	// set CLR bit on MAX547 chip to low to disable output
	delete stg;
}

void max547Driver::initDriver(void)
{
	//set port A,B and C as output and leave port D to whatever it is currently
	stg->DioDirection(PORTA_DIR, OUTPUT);
	stg->DioDirection(PORTB_DIR, OUTPUT);
	stg->DioDirection(PORTCU_DIR, OUTPUT);
	stg->DioDirection(PORTCL_DIR, OUTPUT);

	stg->DioDirection(0x0f);

	stg->RawDO(0x00, PORTC);

	stg->RawDO(CLR_BIT, 1, PORTC);	// set CLR bit on MAX547 chip to high to enable output

	stg->RawDO(0x00, PORTA);
	stg->RawDO(0x10, PORTB);	// 0x1000 is the binary for 0V output
	writeData(0);
}

#define DELAY	1
void max547Driver::pulseLDAB(void)
{
	long int i;
	
	stg->RawDO(LDAB_BIT, 1, PORTC);	// set LDAB to high
//	for(i=0;i<DELAY;i++);
	stg->RawDO(LDAB_BIT, 0, PORTC);	// then set to low
//	for(i=0;i<DELAY;i++);
	stg->RawDO(LDAB_BIT, 1, PORTC);	// set LDAB to high
}

void max547Driver::pulseWR(void)
{
	long int i;
	stg->RawDO(WR_BIT, 1, PORTC);	// set WR to high
//	for(i=0;i<DELAY;i++);
	stg->RawDO(WR_BIT, 0, PORTC);	// then set to low
//	for(i=0;i<DELAY;i++);
	stg->RawDO(WR_BIT, 1, PORTC);	// set WR to high again
}

// Function that takes DAC count from the controller output and converts it 
// to the equivalent Dcount necessary for the MAX547 to generate the correct
// output voltage
void max547Driver::writeData(short int dacCount)
{
	// procedure to write produce analog voltage:
	// 1. pull CS low
	// 2. pulse WR low
	// 3. set ADDR
	// 4. write D0-D12
	// 5. pulse LDAB low

	// the CS bit is hardwired to LOW such that the connected MAX547 is always
	// enabled.

	pulseWR();

	// the address bits are hardwired to specific channel (default CH A) so
	// we dont have to worry about setting address	
	// from the MAX547 datasheet, the following conversion factor is used
	// between dacCount and Dcount
	Dcount = dacCount + 4096;

	lowByte = Dcount & LOWBYTE_MASK;
	highByte = (Dcount & HIGHBYTE_MASK) >> 8;

//	printf("D:%d, %d, %X, h: %X, l: %X \n", dacCount, Dcount, Dcount, highByte, lowByte);
	stg->RawDO(lowByte, PORTA);
	stg->RawDO(highByte, PORTB);

	pulseLDAB();
}

#define TEST_MAIN	0

#if TEST_MAIN

#define START_COUNT	4000
void main(void)
{
	ServoToGo *stgPtr = new ServoToGo(STG_ARM_IRQ, STG_ARM_ADDRESS);

	max547Driver *dacRight = new max547Driver(stgPtr);

	PrTimer timer(HZ);

	timer.start();

	int dataOut = -START_COUNT;
	static int c = 0;
	
	while(!tcischars(1))
	{
		dacRight->writeData(dataOut);	

		dataOut += 5;

		if(dataOut > START_COUNT)
			dataOut = -START_COUNT;
#if 0
		if(c == 20)
		{
			printf("out: %d \n", dataOut);
			c = 0;
		}
		c++;
#endif
		timer.wait();
	}

	delete dacRight;
	delete stgPtr;
}


#endif



