/*******************************************************************************
* Name: misc.c 
* 
* Description: Miscellaneous functions for accessing other peripherals. 
* 
* Texas Instruments, Inc
* 
* Version: 1.0
*******************************************************************************/

/*
 * Copyright (C) {2011} Texas Instruments Incorporated - http://www.ti.com/ 
 * 
 * 
 *  Redistribution and use in source and binary forms, with or without 
 *  modification, are permitted provided that the following conditions 
 *  are met:
 *
 *    Redistributions of source code must retain the above copyright 
 *    notice, this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the 
 *    documentation and/or other materials provided with the   
 *    distribution.
 *
 *    Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
*/

// Include Library Headers
#include "device.h"
#include "misc.h"
#include "init.h"

// Structure definition for Fan control
typedef struct								
{
	unsigned int PortOutAddr;					// Which Port?
	unsigned int PortDirAddr;					// Which Direction? Inp or Out?
	unsigned int PortBit;						// Which Bit on the Port?
} FanDescription_t;

// Initialize Fan control structure for this board
FanDescription_t Fan = FAN_DEFAULT_STATE;

// Structure definition for ADC
typedef struct								
{
	unsigned char BatteryNum;				// Battery Number
	unsigned char ChannelType;				// Voltage or Current?
	unsigned int PortSelAddr;					// Which Port Select Address?
	unsigned int PortBit;						// Which Bit on the Port?
	unsigned char InputChanNum;				// ADC Input Channel Number
} ADCDescription_t;

// Initialize ADC structure for this board
ADCDescription_t ADC[NUM_ADC_CHANNELS] = ADC_DEFAULT_STATE;

// Universal Tick Counter keeps track of TIMER_TICKs when used in a delay
// function. Each TIMER_TICK is defined as the period for Timer A0 to expire. 
volatile int UniversalTickCounter = -1;	

/* ****************************************************************************
 * Function Name: Fan_Init
 * 
 * Description: Set up the Fan Port Pin as an output. 
 * ***************************************************************************/
void Fan_Init(void)
{
	// Set the Port to output
	*(unsigned int *) Fan.PortDirAddr |= Fan.PortBit;			// Set Port Direction bit HIGH
}

/* ****************************************************************************
 * Function Name: Fan_Control
 * 
 * Description: Toggles the Fan on or off with a GPIO pin. 
 * 
 * Inputs:
 * o on_off: FAN_ON, FAN_OFF
 * ***************************************************************************/
void Fan_Control(unsigned char on_off)
{	
	if(on_off == FAN_ON) 
	{
		*(unsigned int *) Fan.PortOutAddr |= Fan.PortBit;		// Set Port Bit -> Turn Fan On
		
	}
	else
	{
		*(unsigned int *) Fan.PortOutAddr &= ~(Fan.PortBit);	// Clear Port Bit -> Turn Fan off
	}	
}

/* ****************************************************************************
 * Function Name: VI_ADC_Read
 * 
 * Description: Convert the resistor-divided Voltage/Current analog signal
 * into digital representation. 
 * 
 * Inputs:
 * o battery_num: BATT_1, BATT_2
 * o channel_vi: CHANNEL_VOLTAGE, CHANNEL_CURRENT
 * 
 * Outputs:
 * o Digital value of the voltage/current
 * ***************************************************************************/
unsigned int VI_ADC_Read(unsigned char batt_num, unsigned char channel_vi)
{
	unsigned int conversion_value = 0;			// Store the ADC conversion value
	unsigned int index = 0;
	
	// Find the appropriate battery number & channel type 
	for(index = 0; index < NUM_ADC_CHANNELS; index++)
	{
		if(ADC[index].BatteryNum == batt_num)		// Which Battery?
		{
			if(ADC[index].ChannelType == channel_vi)	// Which Channel Type?
			{
				// Setup the ADC for this channel
				ADC10MCTL0 = ADC10SREF_0 +			// VR+ = AVCC | VR- = AVSS
							 ADC[index].InputChanNum;		// Input Channel Ax
				
				// Select PORT.BIT as ADC Input Ax						 
				*(unsigned int *) ADC[index].PortSelAddr |= ADC[index].PortBit;						
	
			    ADC10CTL0 |= ADC10ENC + ADC10SC;    // Sampling and conversion start
			    __bis_SR_register(LPM0_bits + GIE); // LPM0, ADC10_ISR will force exit			
										 
				conversion_value = ADC10MEM0;		// Store the conversion value
				
				// Reset all of the ADC settings
				ADC10CTL0 &= ~(ADC10ENC + ADC10SC);
				*(unsigned int *) ADC[index].PortSelAddr &= ~(ADC[index].PortBit);
				ADC10MCTL0 &= ~(ADC10SREF_0 + ADC[index].InputChanNum);
			}
		}
	}
	return conversion_value;					// Return ADC value	
}

/* ****************************************************************************
 * Function Name: Calibrate_Battery
 * 
 * Description: Turns on the discharge resistors for the battery pack for 
 * calibration purposes. 
 * 
 * Inputs:
 * o on_off: CAL_ON, CAL_OFF
 * o batt_num: BATT_1, BATT_2
 * ***************************************************************************/
void Calibrate_Battery(unsigned char batt_num, unsigned char on_off)
{	

	// P4.6 - CAL Channel 1 | P4.7 - CAL Channel 2
	P4DIR |= (BIT6 + BIT7);				// Set P4.6 & P4.7 to outputs
	
	if(batt_num == BATT_1)
	{
		if(on_off == CAL_ON)
		{
			P4OUT |= BIT6;				// Set P4.6 (CAL-CH1) HIGH/ON
		}
		else 
		{
			P4OUT &= ~(BIT6);			// Set P4.6 (CAL-CH1) LOW/OFF
		}
	}
	else if(batt_num == BATT_2)
	{
		if(on_off == CAL_ON)
		{
			P4OUT |= BIT7;				// Set P4.7 (CAL-CH2) HIGH/ON
		}
		else 
		{
			P4OUT &= ~(BIT7);			// Set P4.7 (CAL-CH2) LOW/OFF
		}
	}		
	
}

/* ****************************************************************************
 * Function Name: Delay_Timer
 * 
 * Description: A simple function which implements a fixed delay in program
 * execution. Rather than consume CPU cycles, it simply counts the number
 * of TIMER_TICKs (employing Timer A1) and puts the CPU in sleep mode.
 * When the desired number of ticks have been reached, the CPU is woken back 
 * up and execution resumes. 
 * ***************************************************************************/
void Delay_Timer(int number_of_ticks)
{
	UniversalTickCounter = number_of_ticks;
	
	TA1CTL = TASSEL__ACLK + TACLR + MC__UP;			// Begin Timer A1 to measure timer tick
	
	__bis_SR_register(LPM0_bits + GIE);         // Enter LPM0 w/ interrupts	
		
}

