//*****************************************************************************
//! @file       lcd_dogm128_6.c
//! @brief      TrxEB specific implementation for DOGM128-6 LCD display driver.
//!             @warning This file will be removed. Include trxeb_msp5438a BSP
//!             in your project instead of this file!
//!
//! Revised     $Date: 2012-04-19 15:52:03 +0200 (to, 19 apr 2012) $
//! Revision    $Revision: 7290 $
//
//  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.
//****************************************************************************/


/**************************************************************************//**
* @addtogroup lcd_dogm128w6_api LCD API (DOGM128W-6)
* @{
******************************************************************************/


/******************************************************************************
* INCLUDES
*/
#include "msp430f5438a.h"
#include "lcd_dogm128_6.h"
#include "hal_mcu.h"                // Using halMcuWaitMs()


/******************************************************************************
* DEFINES
*/
/* Port to use for display */
#define LCD_PORT_OUT_CS_A0  P9OUT
#define LCD_PORT_DIR_CS_A0  P9DIR
#define LCD_PORT_SEL_CS_A0  P9SEL

#define LCD_PORT_OUT_RST    P7OUT
#define LCD_PORT_DIR_RST    P7DIR
#define LCD_PORT_SEL_RST    P7SEL

#define LCD_PORT_SEL_SPI    P9SEL

#define LCD_PORT_OUT_POWER  P7OUT
#define LCD_PORT_DIR_POWER  P7DIR
#define LCD_PORT_SEL_POWER  P7SEL
#define LCD_PORT_DS_POWER   P7DS

/* Signal to pin mapping (SPI and GPIO) */
#define LCD_CS              6   // Chip Select (GPIO)
#define LCD_SI              1   // Slave Input (SPI MOSI)
#define LCD_SO              2   // Slave Output (SPI MISO), not in use
#define LCD_SCL             3   // SPI Clock
#define LCD_A0              7   // Controls if bit-stream is data/command (GPIO)
#define LCD_RST             3   // Reset LCD (GPIO)
#define LCD_POWER           7   // LCD power (GPIO)

/* Condition for SPI TX-buffer to be ready */
#define TX_BUF_READY()      (UCB2IFG & UCTXIFG)

//! Macro for asserting LCD CSn (set low)
#define LCD_SPI_BEGIN()     (LCD_PORT_OUT_CS_A0 &= ~(1<<LCD_CS))
//! Macro for deasserting LCD CSn (set high)
#define LCD_SPI_END()       (LCD_PORT_OUT_CS_A0 |= (1<<LCD_CS))
//! Macro for setting LCD mode signal low (command)
#define LCD_MODE_SET_CMD()  (LCD_PORT_OUT_CS_A0 &= ~(1<<LCD_A0))
//! Macro for setting LCD mode signal (data)
#define LCD_MODE_SET_DATA() (LCD_PORT_OUT_CS_A0 |= (1<<LCD_A0))


/* LCD initialization command sequence */
static const char lcdInitCmd[] =
{
                            0x40,   /*Display start line 0              */
                            0xa1,   /*ADC reverse, 6 oclock viewing direction */
                            0xc0,   /*Normal COM0...COM63                     */
                            0xa6,   /*Display normal, not mirrored            */
                            0xa2,   /*Set Bias 1/9 (Duty 1/65)                */
                            0x2f,   /*Booster, Regulator and Follower On      */
                            0xf8,   /*Set internal Booster to 4x              */
                            0x00,   /*                                        */
                            0x27,   /*Contrast set                            */
                            0x81,   /*                                        */
                            0x16,   /* <- use value from LCD-MODULE .doc guide*/
                                    /*    for better contrast (not 0x10)      */
                            0xac,   /*No indicator                            */
                            0x00,   /*                                        */
                            0xaf,   /*Display on                              */
                            0xb0,   /*Page 0 einstellen                       */
                            0x10,   /*High-Nibble of column address           */
                            0x00    /*Low-Nibble of column address            */
 };


/******************************************************************************
 * LOCAL VARIABLES
 */


/******************************************************************************
 * LOCAL FUNCTION PROTOTYPES
 */
static void lcdSendArray(char* pArray, uint16 size);


/******************************************************************************
 * @fn          lcdInit
 *
 * @brief       Initializes the SPI interface, the port used for the display and
 *              the display itself. This must be run before you can use the LCD.
 *
 * input parameters
 *
 * output parameters
 *
 * @return      none
 */
void lcdInit(void)
{

  lcdSpiInit();  // Initialize SPI interface (USCI controller + MOSI, CLK pins)

  // IO pins
  LCD_PORT_SEL_CS_A0 &= ~((1<<LCD_CS) | (1<<LCD_A0));
  LCD_PORT_SEL_RST   &= ~(1<<LCD_RST);
  LCD_PORT_SEL_POWER &= ~(1<<LCD_POWER);

  // Output
  LCD_PORT_DIR_CS_A0 |=   (1<<LCD_CS) | (1<<LCD_A0);
  LCD_PORT_DIR_RST   |=   (1<<LCD_RST);
  LCD_PORT_DIR_POWER |=   (1<<LCD_POWER);

  // Set LCD_POWER=1 with high drive strength
  LCD_PORT_OUT_POWER |=   (1<<LCD_POWER);
  LCD_PORT_DS_POWER  |=   (1<<LCD_POWER);

  // Set RSTn=0, A0=1, CSn=1
  LCD_PORT_OUT_CS_A0 |=   (1<<LCD_CS) | (1<<LCD_A0);
  LCD_PORT_OUT_RST   &=   ~(1<<LCD_RST);

  // Wait ~ 100 ms (@ 16 MHz) and clear reset
  __delay_cycles(1600000);
  LCD_PORT_OUT_RST   |=   (1<<LCD_RST);

  // Send init command sequence
  lcdSendCommand((char*)lcdInitCmd, sizeof(lcdInitCmd));
}


/**************************************************************************//**
* @brief    Initializes the LCD SPI interface. Quicker for reconfiguring
*           the SPI interface than lcdInit() if the LCD display has
*           already been initialized.
*
* @return   None
******************************************************************************/
void lcdSpiInit(void)
{
    // Configure USCI B2 for SPI master
    UCB2CTL1 |= UCSWRST;                        // Disable SPI interface
    UCB2CTL0  = UCSYNC | UCMST | UCCKPL | UCMSB;// Synchronous mode, 3-pin SPI,
                                                // master, 8-bit, MSB first,
                                                // clock pol=1(inactive=high),
                                                // cloch pha=0(setup=first edge)
    UCB2CTL1 |= UCSSEL1 | UCSSEL0;              // Set clock source = 11 = SMCLK

    UCB2BR0  = 1;   // Bit rate control registers (set clock divider = 1)
    UCB2BR1  = 0;   // The maximal clock speed for the LCD is 20MHz

    // Configure ports and pins
    // SPI pins
    LCD_PORT_SEL_SPI |=   (1<<LCD_SI) | (1<<LCD_SCL);

    // Enable SPI interface
    UCB2CTL1 &= ~UCSWRST;
}


/**************************************************************************//**
* @brief       Sends an array of length \c ucLen of commands to the LCD
*              controller.
*
* @param       pcCmd   The array of commands to be sent to the LCD
* @param       ucLen   Number of elements/bytes in command
*
* @return      none
******************************************************************************/
void lcdSendCommand(const char *pcCmd, unsigned char ucLen)
{
    LCD_SPI_BEGIN();                    // Chip Select LOW
    LCD_MODE_SET_CMD();                 // A0 LOW => command
    lcdSendArray((char*)pcCmd, ucLen);  // Send command
    LCD_SPI_END();                      // Chip Select HIGH
}


/**************************************************************************//**
* @brief       Sends an array of \c ucLen size of data to the LCD.
*
* @param       pcCmd   The array of commands to be sent to the LCD
* @param       ucLen   Number of elements/bytes in command
*
* @return      none
******************************************************************************/
void lcdSendData(const char *pcCmd, unsigned short usLen)
{
    LCD_SPI_BEGIN();                    // Chip Select LOW
    LCD_MODE_SET_DATA();                // A0 LOW => command
    lcdSendArray((char*)pcCmd, usLen);  // Send command
    LCD_SPI_END();                      // Chip Select HIGH
}


/**************************************************************************//**
* @brief    Function updates the LCD display by creating an animated transition
*           between two displays. Two animations exists, \c LCD_SLIDE_LEFT and
*           \c LCD_SLIDE_RIGHT whichs slides the new screen in leftwards or
*           rightwards, respectively.
*
* @details  When changing the image on the display with lcdBuffer functions,
*           the buffer is changed immediately. The changes will take affect
*           on the LCD when lcdSendBuffer or lcdSendBufferAnimated are used.
*           lcdSendBuffer will change the display to show the new buffer
*           instantanously. lcdSendBufferAnimated on the other side, will make a
*           smooth transition into showing the new buffer. In order for
*           halLcdAnimate to know what to animate from, it takes in an
*           argument \c pcFromBuffer. It should point to an address containing
*           what was stored on the LCD buffer last time lcdSendBuffer or
*           lcdSendBufferAnimated was used, or in other words, what is presently
*           on the display. This way, lcdSendBufferAnimated will not take any
*           memory unless used.
*
* @details  Example how to think:
*           1. Send a buffer to the display using e.g. lcdSendBuffer.
*           2. Manipulate a second buffer using lcdBuffer functions.
*           3. Run lcdSendBufferAnimated to update display with a
*              smooth transition from the initial to the second buffer.
*
* @param    pcToBuffer      Address to buffer with new display content
* @param    pcFromBuffer    Address to buffer with existing display content
* @param    ucMotion        Which animation to use for transition. Can be one
*                           of the following:
*                           \li \c LCD_SLIDE_LEFT
*                           \li \c LCD_SLIDE_RIGHT
*
* @return   None
******************************************************************************/
void lcdSendBufferAnimated(const char *pcToBuffer, const char *pcFromBuffer,
                           unsigned char ucMotion)
{
    char pcPageData[LCD_COLS];
    unsigned char ucOffset, ucPageIndex, ucI;
    char *pcToBuf = (char *)pcToBuffer;
    char *pcFromBuf = (char *)pcFromBuffer;

    // Buffers are the same, do not animate
    if(pcToBuffer == pcFromBuffer)
    {
        lcdSendBuffer(pcToBuffer);
        return;
    }

#ifndef LCD_NO_DEFAULT_BUFFER
    // Use default buffer if null pointers
    if (!pcToBuf) pcToBuf = lcdDefaultBuffer;
    else if(!pcFromBuf) pcFromBuf = lcdDefaultBuffer;
#endif // LCD_NO_DEFAULT_BUFFER

    for(ucOffset = 0; ucOffset <= LCD_COLS; ucOffset += 4)
    {
        // For each page
        for(ucPageIndex=0; ucPageIndex<8; ucPageIndex++)
        {
            //  Assigning data to this page from both buffers
            for(ucI=0; ucI<LCD_COLS; ucI++)
            {
                if(ucMotion == LCD_SLIDE_LEFT)
                {
                    if(ucI+ucOffset < LCD_COLS)
                    {
                        pcPageData[ucI] = *(pcFromBuf + (ucPageIndex*LCD_COLS + ucI+ucOffset));
                    }
                    else
                    {
                        pcPageData[ucI] = *(pcToBuf + (ucPageIndex*LCD_COLS + ucI+ucOffset - LCD_COLS));
                    }
                }
                else // LCD_SLIDE_RIGHT
                {
                    if(ucI-ucOffset >= 0)
                    {
                        pcPageData[ucI] = *(pcFromBuf + (ucPageIndex*LCD_COLS + ucI-ucOffset));
                    }
                    else
                    {
                        pcPageData[ucI] = *(pcToBuf + (ucPageIndex*LCD_COLS + ucI-ucOffset + LCD_COLS));
                    }
                }
            }

            lcdGotoXY(0, ucPageIndex); // Set pointer to start of row/page
            lcdSendData(pcPageData, LCD_COLS); // Send one page
        }

        // Active state wait
        halMcuWaitUs(1500);
    }
}

/******************************************************************************
* LOCAL FUNCTIONS
*/
/**************************************************************************//**
* @brief    Sends an array of length i of either data or commands (depending
*           on A0) on SPI to the LCD controller. Used as in the
*           functions lcdSendCommand and lcdSendData.
*
* @param    pArray  The array of data or commands to be sent to the LCD
* @param    size    Number of elements/bytes in pArray
*
* @return   none
******************************************************************************/
static void lcdSendArray(char* pArray, unsigned short size)
{
    while(size)
    {
        while (!TX_BUF_READY());    // Transmit buffer ready?
        UCB2TXBUF = *pArray;        // Send data control
        pArray++;                   // Increment pointer to data
        size--;                     // Decrement bytes left
    }
    while (!TX_BUF_READY());  // Wait for transmit buffer to become empty
}


/******************************************************************************
  Copyright 2012 Texas Instruments Incorporated. All rights reserved.

  IMPORTANT: Your use of this Software is limited to those specific rights
  granted under the terms of a software license agreement between the user
  who downloaded the software, his/her employer (which must be your employer)
  and Texas Instruments Incorporated (the "License").  You may not use this
  Software unless you agree to abide by the terms of the License. The License
  limits your use, and you acknowledge, that the Software may not be modified,
  copied or distributed unless embedded on a Texas Instruments microcontroller
  or used solely and exclusively in conjunction with a Texas Instruments radio
  frequency transceiver, which is integrated into your product.  Other than for
  the foregoing purpose, you may not use, reproduce, copy, prepare derivative
  works of, modify, distribute, perform, display or sell this Software and/or
  its documentation for any purpose.

  YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
  PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
  INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
  NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
  TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
  NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
  LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
  INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
  OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
  OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
  (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.

  Should you have any questions regarding your right to use this Software,
  contact Texas Instruments Incorporated at www.TI.com.
*******************************************************************************/