/******************************************************************************
 * BASED ON sample program from ICS ADVENT AIO16 Documentation
 * This program will prompt user for voltage between 0 and 5V
 * Output value on DAC channel 0 and read it back on ADC channel 0
 * setting scan limits (task 1)
 * performing data conversion (tak 3)
 * outputting to DAC (task 15)
 * NOTE:	we are running the system as root, note that if we are
 *		going to run it under user we must implement the following
 *		as a device driver.
 ****************************************************************************/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <asm/io.h>

#ifdef __GLIBC__
	#include <sys/perm.h>
#endif

#define PORT_FILE "/dev/port"


/********************************* write_port_data **************************/

void write_port_data(unsigned char current[3])
{
	unsigned char value;
	int i, j;

	for (i = 0; i < 3; i++) {
		value = current[i];
		for (j = 0; j < 8; j++) {
			if (value % 2)
				putchar('1');
			else
				putchar('0');
			value = value >> 1;
		}
	}
}


void startConversion(int fd)
{
	unsigned int BASEADDRESS = 0x0300; 
	float volts;
	unsigned char b, mask;
	unsigned char loByte, hiByte, channelAddress;
	unsigned char status;
	int intVolt, intHiByte;
	
	
	//*** following output addresses are used *******************

	unsigned int startADconvert = BASEADDRESS; 
	unsigned int ADloByte = BASEADDRESS;
	unsigned int ADhiByte = BASEADDRESS + 1;
	unsigned int startStopChannel = BASEADDRESS + 2;
	unsigned int FourBitDigOut = BASEADDRESS + 3;
	unsigned int DAC_0_lo = BASEADDRESS + 4;
	unsigned int DAC_0_hi = BASEADDRESS + 5;
	unsigned int DAC_1_lo = BASEADDRESS + 6;
	unsigned int DAC_1_hi = BASEADDRESS + 7;
	unsigned int cardStatus = BASEADDRESS + 8;
	unsigned int cardControl = BASEADDRESS + 9;
	unsigned int counterEnable = BASEADDRESS + 10;
	unsigned int counter_0 = BASEADDRESS + 12;
	unsigned int counter_1 = BASEADDRESS + 13;
	unsigned int counter_2 = BASEADDRESS + 14;
	unsigned int counterControl = BASEADDRESS + 15;


	//************ set scan limits for 0 to channel 15 *********

	b = 0x0F;

	lseek(fd, startStopChannel, SEEK_SET);
	if (write(fd, &b, 1) > 0)
		//printf("written start stop bits successfully\n"); 	


	//************ read back and convert on channel. ********

	b = 0x00;	// any write will start A/D conversion 
	lseek(fd, startADconvert, SEEK_SET);
	if (write(fd, &b, 1) < 0) {
		printf("ERROR: start A/D conversion unsuccessfully\n"); 	
	}
	
}


/***************************** readVoltage ************************************/

int readVolt(int fd, unsigned int channel, float& voltage, float& raw)
{

	unsigned int BASEADDRESS = 0x0300; 
	float volts;
	unsigned char b, mask;
	unsigned char loByte, hiByte, channelAddress;
	unsigned char status;
	int intVolt, intHiByte;
	
	
	//*** following output addresses are used *******************

	unsigned int startADconvert = BASEADDRESS; 
	unsigned int ADloByte = BASEADDRESS;
	unsigned int ADhiByte = BASEADDRESS + 1;
	unsigned int startStopChannel = BASEADDRESS + 2;
	unsigned int FourBitDigOut = BASEADDRESS + 3;
	unsigned int DAC_0_lo = BASEADDRESS + 4;
	unsigned int DAC_0_hi = BASEADDRESS + 5;
	unsigned int DAC_1_lo = BASEADDRESS + 6;
	unsigned int DAC_1_hi = BASEADDRESS + 7;
	unsigned int cardStatus = BASEADDRESS + 8;
	unsigned int cardControl = BASEADDRESS + 9;
	unsigned int counterEnable = BASEADDRESS + 10;
	unsigned int counter_0 = BASEADDRESS + 12;
	unsigned int counter_1 = BASEADDRESS + 13;
	unsigned int counter_2 = BASEADDRESS + 14;
	unsigned int counterControl = BASEADDRESS + 15;


	//************ initialization ******************************

	//params[0] =  BASEADDRESS;		// starting board address 
	//params[1] = 5;			// IRQ 5 
	//params[2] = 1;			// DMA channel 1 
	//task = 0;
	// status = call_driver();		

	//printf(" Base Adress is %X in hex.\n", BASEADDRESS);

	//************ set scan limits for 0 to channel 15 *********
	// task = 1;
	// params[0] = 0;			// lower scan limit 
	// params[1] = 0;			// upper scan limit 
	//status = call_driver();

	channel -= 1;
	b = mask = channel & 0x0F;
        mask <<= 4;
        b |= mask;
	
        //printf("readVoltage: reading channel: %X\n", b);

	lseek(fd, startStopChannel, SEEK_SET);
	if (write(fd, &b, 1) > 0)
		//printf("written start stop bits successfully\n"); 	


	//************ read back and convert on channel. ********
/*
	b = 0x00;	// any write will start A/D conversion 
	lseek(fd, startADconvert, SEEK_SET);
	if (write(fd, &b, 1) > 0)
		//printf("start A/D conversion successfully\n"); 	
	
	lseek(fd, cardStatus, SEEK_SET);
	do {
		if (read(fd, &status, 1) < 0) {
			//printf("error reading status register\n");
			return -1;
		}
		//printf("Status: %X\n", status);
		//printf("status & 0x80: %X\n", (status & 0x80));
	} while ( (status & 0x80) != 0);
*/

	// reading the Bytes, low byte first then high
	lseek(fd, ADloByte, SEEK_SET);
	if (read(fd, &loByte, 1) < 0) {
		//printf("error reading lobyte\n");
		return -1;
	}
	else {
		channelAddress = loByte & 0x0f;
		//printf("loByte raw read: %X\n", loByte);
		loByte >>= 4;		
	}

	lseek(fd, ADhiByte, SEEK_SET);
	if (read(fd, &hiByte, 1) < 0) {
		//printf("error reading lobyte\n");
		return -1;
	}
	else {
	//	printf("\nloByte: %X\n", loByte);
	//	printf("hiByte: %X\n", hiByte);
	//	printf("Channel address: %X\n", channelAddress);
		intVolt = loByte;
		intHiByte = hiByte;
		intHiByte <<= 4;
		intVolt |= intHiByte;	
	//	printf("intVolt: %X\n", intVolt);	
	//	printf("intVolt: %d\n", intVolt);
	}

	voltage = (float) intVolt * 5.00 / 4095.00;
	//printf("\nThe value read back is: %5.3f\n", voltage);
	raw = intVolt;

} 

