/*
 * main.c
 *
 * MSP-EXP430G2-LaunchPad (v1.5+) User Experience Application for
 *      Communication to ADS1118
 *
 * Copyright (C) 2012 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.
 *
*/


/******************************************************************************
 * MSP-EXP430G2-LaunchPad User Experience Application for Communication to ADS1118
 *
 * 1. Program uses GRACE configuration for Device Configuration;
 * 		- SMCLK, ACLK, DCO at 1MHz
 * 		- USCIA0 as UART, 9600, 8 bits Data, No parity, 1 Stop (Hardware Mode)
 * 		- USCIB0 as 3 line SPI, Master Mode, 50kHz SCLK
 * 		- P2.0 used as CS for ADS1118 ADC device
 *
 * 2. Application Mode
 *   	- Initial start configures device on power up
 *   	- Configures connected ADS1118 device for differential measurement
 *   		pairs of AIN0-AIN1 and AIN2-AIN3
 *   	- Data is transmitted in continuous loop
 *   	- Runs ADS1118 in single shot mode reading first pair, changing mux and then
 *   		second pair storing data in a data array
 *   	- After data is read, data is sent out UART for display as ASCII hex representation
 *
 * Changes:
 * 1.0  Initial Release Version
 *
 * Texas Instruments, Inc.
 ******************************************************************************/



/*
 * ======== Standard MSP430 includes ========
 */
#include <msp430g2553.h>

/*
 * ======== Grace related includes ========
 */
#include <ti/mcu/msp430/csl/CSL.h>


/*
 *  ======== Function Calls ========
 */

void uart_txc(char c);
void uart_txstr(char *c);
/* "hex2asc" Converts a 32-bit integer n into an ASCII string.

digs is the maximum number of digits to display.  Conversion is controlled
by mode, as follows:

- mode = 0: Leading zeroes are not printed.  The string may be
  less than digs digits long.
- mode = 1: Spaces are printed in place of leading zeroes.  The
  string will be digs digits long.
- mode = 2: Leading zeroes are printed.  The string will be digs
  digits long.

If the number is zero, at least one zero is printed in all modes.

This routine works by converting n to an 8-byte BCD number and calling
hex2asc.  No division by 10 is performed.
*/

int hex2asc(void *n, int digs, int mode, char *s);

void ADS_Config(void);
void ADS_Read(int data[]);
void Send_Result(int *data);
void Port_Config(void);
signed int WriteSPI(unsigned int config, int mode);
void delay(void);

#define h2a(d) ((d>9)?(d+'A'-10):(d+'0'))
#define LITTLEENDIAN 1

/*
 *  ======== main ========
 */
int main(int argc, char *argv[])
{
    CSL_init();                     // Activate Grace-generated configuration
    
    // >>>>> Fill-in user code here <<<<<

    // Initialize TC data array

    signed int data[6];

    // Port configuration
    Port_Config();

    // Set ADS1118 configuration
    ADS_Config();
    while (1)
    {
    	// Read the data from both input pairs
    	ADS_Read(data);


    	// Transmit the data out the UART
    	Send_Result(data);
    }


    return (0);
}

void Port_Config(void)
{
	// Set P1.0, P1.3, P1.4, P2.1, P2.2, P2.4, P2.5, P2.6 and P2.7 low

	P1OUT = 0x00;
	P2OUT = 0x01 ;
}


/*
 * Initial configuration routine.  A header file could be created, but the configuration is really rather simple.
 * In this case a 16-bit value representing the register contents is set to variable temp
 */
void ADS_Config(void)
{
	int i;

	unsigned int temp;

	// Set the configuration to AIN0/AIN1, FS=+/-1.024, SS, DR=128sps, PULLUP on DOUT
	temp = 0x78A;


	// Set CS low and write configuration
	P2OUT &= ~BIT0;


	// Write the configuration
	WriteSPI(temp,0);

	// Set CS high to end transaction
	P2OUT |= BIT0;
}



void ADS_Read(int data[])
{
	unsigned int j, temp;

	// Set the configuration to AIN0/AIN1, FS=+/-1.024, SS, DR=128sps, PULLUP on DOUT
	temp = 0x78A;

	// Set CS low and write configuration
	P2OUT &= ~BIT0;

	// First the data is captured by writing to each device to take start a conversion for A0-A1
	WriteSPI(temp,1);

	// Set CS high to end transaction
	P2OUT |= BIT0;

		/*
		 * Now we pause slightly before reading the data, or it is possible to either poll the DOUT/DRDY or enable an interrupt
		 * where the DOUT/DRDY transition from high to low triggers a read.  In this case it is kept quite simple with a delay
		 */

	delay();		// May be needed depending on method

	// When we read the data we restart the conversion with new mux channel A2-A3
	temp = 0x378A;

	// Set CS low and write configuration
	P2OUT &= ~BIT0;

	// Read the earlier conversion result and set to the new configuration
	data[0] = WriteSPI(temp,1);

	delay();		// May be needed depending on method

	// Read second channel data
	data[1]=WriteSPI(temp,0);

	// Set CS high to end transaction
	P2OUT |= BIT0;


}


signed int WriteSPI(unsigned int config, int mode)
{
	signed int msb;
	unsigned int temp;
	char dummy;

	temp = config;

	if (mode==1) temp = config | 0x8000;	// if mode is set to 1, this command should initiate a conversion

/*
 * The process of communication chosen is to always send the configuration and read it back
 * this results in a four byte transaction.  The configuration is 16-bit (or 2 bytes) and is transmitted twice.
 *
 */
	while(!(UC0IFG&UCB0TXIFG));		// Make sure buffer is clear

	/*
	 *  First time configuration is written
	 */

	UCB0TXBUF = (temp >> 8 );		// Write MSB of Config
	while(!(UC0IFG&UCB0RXIFG));
	msb=UCB0RXBUF;					// Read MSB of Result

	while(!(UC0IFG&UCB0TXIFG));

	UCB0TXBUF= (temp & 0xff);		// Write LSB of Config
	while(!(UC0IFG&UCB0RXIFG));
	msb = (msb << 8) | UCB0RXBUF ;	//Read LSB of Result

	/*
	 * Second time configuration is written, although data could be sent as NOP in either transmission, just simplified in this case
	 */

	while(!(UC0IFG&UCB0TXIFG));
	UCB0TXBUF = (temp >> 8 );		// Write MSB of Config

	while(!(UC0IFG&UCB0RXIFG));
	dummy=UCB0RXBUF;				// Read MSB of Config

	/*
	 * One advantage of reading the config data is that DOUT/DRDY is forced high which makes it possible to either poll the state or set an interrupt
	 */
	while(!(UC0IFG&UCB0TXIFG));
	UCB0TXBUF= (temp & 0xff);		// Write LSB of Config

	while(!(UC0IFG&UCB0RXIFG));
	dummy=UCB0RXBUF;				//Read LSB of Config


	return msb;
}




/*
 * Following code relates to formatting the data for transmission on UART
 */

void Send_Result(int *data)
{
	unsigned int i;
	int intval = 0;
	char char_array[5];

	// Poke out data
	uart_txstr("TEMPS:");
	uart_txc('\r');
	uart_txc('\n');
	for (i=0; i<2; i++)
	{
		intval = data[i];
		hex2asc(&intval, 4, 2, char_array);
		uart_txstr(char_array);
		uart_txc('\r');
		uart_txc('\n');
	}
}





int hex2asc(void *npos, int digs, int mode, char *s)
{
	int i,zero;
	char dig;
	char *spos=s;
	char *n=(char *)npos;

	zero=1;
#if LITTLEENDIAN
	n+=(digs-1)>>1;
#else
	n+=(16-digs)>>1;
#endif
	for (i=digs-1;i>=0;--i) {
		if (i&1) {
			dig=(*(char *)n>>4)&15;
		} else {
			dig=*(char *)n&15;
#if LITTLEENDIAN
			--n;
#else
			++n;
#endif
		}
		if (zero&&dig)
			zero=0;
		if (zero) {
			switch(mode) {
			case 1:
				*spos++=' ';
				break;
			case 2:
				*spos++='0';
				break;
			default:
				break;
			}
		} else
			*spos++=h2a(dig);
	}
	if (zero&&mode==1)
		*(spos-1)='0';
	else if (zero&&mode==0)
		*spos++='0';
	*spos=0;
	return spos-s;
}
void uart_txc(char c)
{
	while (!((UC0IFG&UCA0TXIFG)));
	UCA0TXBUF=c;

}

void uart_txstr(char *c)
{
	while (*c) uart_txc(*(c++));
}

void delay(void)
{
	unsigned int k;

	for (k = 8000; k = 0; k--) __no_operation();

}
