/*******************************************************************************
* Name: led.c 
* 
* Description: LED control functions. Use these functions to turn LEDs on or off
* or blink. The blink frequency is adjustable. Use the compiler directive in this
* sample program to switch between the 48- or 64-pin version of the boards or
* if the LED assignments are different altogether. 
* 
* 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 "led.h"
#include "init.h"

// Structure definition for LEDs
typedef struct								
{
	unsigned int PortOutAddr;					// Which Port?
	unsigned int PortDirAddr;					// Which Direction? Inp or Out?
	unsigned int PortBit;						// Which Bit on the Port?
	unsigned char LEDVirtualTimer;				// Virtual timer for this LED
	unsigned char LEDBlinkPeriod;				// Blink Rate for this LED
} LEDDescription_t;	

// Initialize LED structure for this board
LEDDescription_t LEDs[MAX_NUM_LEDS] = LED_DEFAULT_STATE;

/* ****************************************************************************
 * Function Name: LED_Control
 * 
 * Description: Ability to control the LEDs on the controller board with 
 * options for which LED, whether to turn it HIGH or LOW or BLINK (at a 
 * particular rate).
 * 
 * Inputs:
 * o led_num: Which LED to turn on? Notation: LED_NUM_0, ... LED_NUM_6
 * o led_mode: Notation: LED_MODE_OFF, LED_MODE_ON, LED_MODE_BLINK
 * o led_blink_rate: Notation: LED_BLINK_RATE_SLOW, LED_BLINK_RATE_MEDIUM,
 * LED_BLINK_RATE_FAST
 * ***************************************************************************/
void LED_Control(unsigned char led_num, unsigned char led_mode, unsigned char \
	led_blink_rate)
{
	// If LED on, then set the associated port bit LOW to enable LED
	// and set blink period to zero	
	if (led_mode == LED_MODE_ON)
	{
		*(unsigned int *)(LEDs[led_num].PortOutAddr) &= ~(LEDs[led_num].PortBit);
		LEDs[led_num].LEDBlinkPeriod = 0;
	}
	// If LED blink, then enable LED virtual timer and set the rate of update so
	// that the LED state will get updated every TIMER_TICK	duration
	else if (led_mode == LED_MODE_BLINK)
	{
		LEDs[led_num].LEDVirtualTimer = 1;
		if (led_blink_rate == LED_BLINK_RATE_FAST)
		  // Fast Blink Rate
		  LEDs[led_num].LEDBlinkPeriod = LED_BLINK_PERIOD_FAST;
		else if (led_blink_rate == LED_BLINK_RATE_MEDIUM)
		  // Medium Blink Rate
		  LEDs[led_num].LEDBlinkPeriod = LED_BLINK_PERIOD_MEDIUM;
		else 
		  // Default Case: Slow Blink Rate
		  LEDs[led_num].LEDBlinkPeriod = LED_BLINK_PERIOD_SLOW;
	}
	// If LED off, then set the associated port bit HIGH to disable LED
	// and set blink period to zero
	else
	{
		*(unsigned int *)(LEDs[led_num].PortOutAddr) |= LEDs[led_num].PortBit;
		LEDs[led_num].LEDBlinkPeriod = 0;
	}	

}

/* ****************************************************************************
 * Function Name: LEDTimerISR
 * 
 * Description: This ISR is called by the Timer A0 ISR. It updates the status 
 * of the LED's every TIMER_TICK.
 * ***************************************************************************/
void LEDTimerISR(void)
{

  int index = 0;							// Loop Counter
  for (index=0 ; index < MAX_NUM_LEDS; index++)
  {
  	// If the LED virtual timer has counted down to zero and if the blink period
  	// is non-zero (i.e., supposed to blink), then toggle the LED and reset the
  	// virtual LED timer to the blink period.
  	if((--LEDs[index].LEDVirtualTimer == 0) && (LEDs[index].LEDBlinkPeriod != 0))
  	{
  		*(unsigned int *)(LEDs[index].PortOutAddr) ^= LEDs[index].PortBit;
  		LEDs[index].LEDVirtualTimer = LEDs[index].LEDBlinkPeriod;
  	}
  }
}

/* ****************************************************************************
 * Function Name: LED_Init
 * 
 * Description: Initialize all of the ports with LEDs. 
 * 
 * Default State for all LEDs = OFF
 * ***************************************************************************/
void LED_Init(void)
{
	/* Please make note that the port logic and LED operation is inverted;
	 * setting port pin HIGH causes LED to be OFF and vice-versa. 
	 */
	
	unsigned int index = 0;							// Loop Counter
	
	for (index = 0; index < MAX_NUM_LEDS; index++)
	{
		// Set the Port Pin HIGH - Disable LED
		*(unsigned int *)(LEDs[index].PortOutAddr) |= LEDs[index].PortBit;
		
		// Set the Port Pin direction to output 
		*(unsigned int *)(LEDs[index].PortDirAddr) |= LEDs[index].PortBit;
	}
	
}
