/* --COPYRIGHT--,BSD_EX
 * Copyright (c) 2014, Texas Instruments Incorporated
 * All rights reserved.
 *
 * 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.
 *
 *******************************************************************************
 *
 *                       MSP430 CODE EXAMPLE DISCLAIMER
 *
 * MSP430 code examples are self-contained low-level programs that typically
 * demonstrate a single peripheral function or device feature in a highly
 * concise manner. For this the code may rely on the device's power-on default
 * register values and settings such as the clock configuration and care must
 * be taken when combining code from several examples to avoid potential side
 * effects. Also see www.ti.com/grace for a GUI- and www.ti.com/msp430ware
 * for an API functional library-approach to peripheral configuration.
 *
 * --/COPYRIGHT--*/

/*
 * LCD.c
 *
 *  Created on: May 25, 2020
 *      Author: JD Crutchfield
 *
 *  CCS version 9.3
 */

#include <msp430.h>
#include "mcu.h"
#include "LCD.h"

void LCD_WriteCharacter(unsigned int, unsigned int);
void ClearLCDMemoryTable(void);

enum LCD_Waveform_timing LcdTiming_state;

/*
 * LETTERS AND NUMBERS MAPPING DEFINITION for FH-1139P
 * Layout for this LCD:
 *
 *          -------A
 *         |F\H|J/K|B
 *   --neg  ---G---M
 *         |E/Q|P\N|C
 *          -------D   .DP
 */

/* this variable corresponds to MEM variable documented in Figure6 of application note slaa516*/
/*
 * COMx number is represented by the index
 * SEGx Pin - represented by each bit
 *
 *                              bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
 *
 * LCD_MEMRegisters[0] = COM0   SEG7 SEG6 SEG5 SEG4 SEG3 SEG2 SEG1 SEG0
 * LCD_MEMRegisters[1] = COM1   SEG7 SEG6 SEG5 SEG4 SEG3 SEG2 SEG1 SEG0
 * LCD_MEMRegisters[2] = COM2   SEG7 SEG6 SEG5 SEG4 SEG3 SEG2 SEG1 SEG0
 * LCD_MEMRegisters[3] = COM3   SEG7 SEG6 SEG5 SEG4 SEG3 SEG2 SEG1 SEG0
 */
char LCD_MEMRegisters[NUMBER_OF_COMx_CHANNELS] = {0};

const char LCDNumberMap[10]=
{   // Segment order ABCDEFGM for FH-1139P LCD
  /* 0    1    2    3    4    5    6    7    8    9 */
  0xFC,0x60,0xDB,0xF3,0x67,0xB7,0xBF,0xE0,0xFF,0xE7
};


void InitLCD(void){
    // MCU IO for COM connections
    COMportOUT &= ~(COM0_BIT +COM1_BIT +COM2_BIT +COM3_BIT);
    COMportDIR |=   COM0_BIT +COM1_BIT +COM2_BIT +COM3_BIT;

#ifdef HARDWARE_I2C
    //SEG0-5
    P1OUT &= ~(BIT0 +BIT1 +BIT2 +BIT3 +BIT4 +BIT5);
    P1DIR |=   BIT0 +BIT1 +BIT2 +BIT3 +BIT4 +BIT5;             // MCU IO for SEG connections in output mode

    //SEG6-7
    P2OUT &= ~(BIT0 +BIT1);
    P2DIR |=   BIT0 +BIT1;
#else
    //SEG0-7
    P1OUT = 0x00;
    P1DIR |= BIT0 +BIT1 +BIT2 +BIT3 +BIT4 +BIT5 +BIT6 +BIT7;             // MCU IO for SEG connections in output mode
#endif

    /*Clearing LCD_MEMRegisters */
    ClearLCDMemoryTable();

    //Timing waveform is showing in Figure 3 of appnote SLAA516a
    LcdTiming_state = T0;
}


void ClearLCDMemoryTable(void){
    char COMx=0;

    for (COMx=0; COMx<NUMBER_OF_COMx_CHANNELS; COMx++){
        LCD_MEMRegisters[COMx]=0;
    }
}


void LCD_WriteCharacter(unsigned int digit,unsigned int position){
    char upper_nibble,lower_nibble;
    char COM;

    upper_nibble =(LCDNumberMap[digit]&0xF0)>>4;
    lower_nibble =LCDNumberMap[digit]&0x0F;

    // converting "digits" on the LCD screen to a parrallel buffer for controling the GPIOs.
    // Each LCD "digit" will requite 2 SEG GPIOs, toggled over 4 COM time slots.
    // This means that each "Digit" will stretch 2 bits over 4 array indexes
    // Each Array block will contain all SEG7-SEG0 for a single COMx time slot.
    // COMx= array index   SEGx GPIO = BITx.  Example: LCD_MEMRegisters[0] = SEG7-SEG0 for COM0
    for(COM=0; COM<4; COM++){
        if(upper_nibble>>COM & 0x01){ //Segments ABCD
          LCD_MEMRegisters[COM] |= (0x01<<(position*2));
        }

        if(lower_nibble>>COM & 0x01){  //Segments EFGM
          LCD_MEMRegisters[COM] |= (0x01<<(position*2+1));
        }
    }
}


void LcdDisplayLowBattery(void){
    //Display "LoB" for low battery on the LCD
    const char LCD_LowBatteryMessage[4] = { // "LoB"
        0b00011111,
        0b00001111,
        0b00100011,
        0b00101011
    };

    int COMx;

    /*Clearing LCD_MEMRegisters */
    ClearLCDMemoryTable();

    for(COMx=0; COMx<NUMBER_OF_COMx_CHANNELS; COMx++){
        LCD_MEMRegisters[COMx] = LCD_LowBatteryMessage[COMx];
    }
}


void LcdDisplayError(void){
    //Display "Err" for low battery on the LCD
    const char LCD_ErrorMessage[4] = { // "Err"
        0b00111010,
        0b00101010,
        0b00100000,
        0b00111010
    };

    int COMx;

    /*Clearing LCD_MEMRegisters */
    ClearLCDMemoryTable();

    for(COMx=0; COMx<NUMBER_OF_COMx_CHANNELS; COMx++){
        LCD_MEMRegisters[COMx] = LCD_ErrorMessage[COMx];
    }
}


void LcdDisplayTemperature(unsigned long Temperature, char Fahr_nCels){
    unsigned int Hundreds,Tens,Ones,Tenths,Hundredths;

    //All temperature is in milli-Celsius
    if(Fahr_nCels){
        //convert to Fahr
        Temperature = ((Temperature*9)/5) + 32000;  // +32000 millicelsius
    }

    //use Hundreds for rounding to nearest tenth of a degree
    Temperature = Temperature/10;
    Hundredths  = Temperature%10;
    if(Hundredths >= 5){
        Temperature += 5;
    }

    //Pull out the temperature digits for display
    Temperature = Temperature/10;
    Tenths      = Temperature%10;

    Temperature = Temperature/10;
    Ones        = Temperature%10;

    Temperature = Temperature/10;
    Tens        = Temperature%10;

    Temperature = Temperature/10;
    Hundreds    = Temperature%10;

    /*Clearing LCD_MEMRegisters */
    ClearLCDMemoryTable();

    /*Updating LCD_MEMRegisters according to data to be put on SEG lines */
    if(Hundreds){
        LCD_WriteCharacter(1, 3);
    }

    LCD_WriteCharacter(Tens, 2);
    LCD_WriteCharacter(Ones, 1);
    LCD_WriteCharacter(Tenths, 0);

    //Write Decimal Point
    LCD_MEMRegisters[COM0] |= DECIMAL_POINT_SEGMENT;
};


void LCDStatemachineProcess(void){

    char tempPort1, tempPort2 = 0;
    //Timing waveform is showing in Figure 3 of appnote SLAA516a
    switch(LcdTiming_state){
        case T0:/* at instant t2 shown in Figure 1*/
#ifdef HARDWARE_I2C
            //SEG0-5, P1.0-1.5
            //SEG6-7, P2.0, 2.1
            tempPort1 = (P1OUT & 0xC0) +  (LCD_MEMRegisters[COM0] & 0x3F);
            tempPort2 = (P2OUT & 0xFC) + ((LCD_MEMRegisters[COM0] >> 6) & 0x03);

            P1OUT = tempPort1;
            P2OUT = tempPort2;
#else
            P1OUT=(LCD_MEMRegisters[COM0]);
#endif
            SET_COM_LOW(COM0_BIT);
            SET_COM_AS_OUTPUT(COM0_BIT);

            //Next state
            LcdTiming_state=T1;
            break;

        case T1:/* at instant t1V shown in Figure 3*/
#ifdef HARDWARE_I2C
            //SEG0-5, P1.0-1.5
            //SEG6-7, P2.0, 2.1
            P1OUT ^= 0x3F;
            P2OUT ^= 0X03;
#else
            P1OUT^=0xFF; // Toggle all SEG lines
#endif
            SET_COM_HIGH(COM0_BIT);
            SET_COM_AS_OUTPUT(COM0_BIT);

            //Next state
            LcdTiming_state=T2;
            break;

        case T2:/* at instant t2 shown in Figure 3*/
#ifdef HARDWARE_I2C
            //SEG0-5, P1.0-1.5
            //SEG6-7, P2.0, 2.1
            tempPort1 = (P1OUT & 0xC0) +  (LCD_MEMRegisters[COM1] & 0x3F);
            tempPort2 = (P2OUT & 0xFC) + ((LCD_MEMRegisters[COM1] >> 6) & 0x03);

            P1OUT = tempPort1;
            P2OUT = tempPort2;
#else
            P1OUT=(LCD_MEMRegisters[COM1]);
#endif
            SET_COM_LOW(COM1_BIT);
            SET_COM_AS_OUTPUT(COM1_BIT);

            //Next state
            LcdTiming_state=T3;
            break;

        case T3:/* at instant t3 shown in Figure 3*/
#ifdef HARDWARE_I2C
            //SEG0-5, P1.0-1.5
            //SEG6-7, P2.0, 2.1
            P1OUT ^= 0x3F;
            P2OUT ^= 0X03;
#else
            P1OUT^=0xFF; // Toggle all SEG lines
#endif
            SET_COM_HIGH(COM1_BIT);
            SET_COM_AS_OUTPUT(COM1_BIT);

            //Next state
            LcdTiming_state=T4;
            break;

        case T4: /* at instant t4 shown in Figure 3*/
#ifdef HARDWARE_I2C
            //SEG0-5, P1.0-1.5
            //SEG6-7, P2.0, 2.1
            tempPort1 = (P1OUT & 0xC0) +  (LCD_MEMRegisters[COM2] & 0x3F);
            tempPort2 = (P2OUT & 0xFC) + ((LCD_MEMRegisters[COM2] >> 6) & 0x03);

            P1OUT = tempPort1;
            P2OUT = tempPort2;
#else
            P1OUT=(LCD_MEMRegisters[COM2]);
#endif

            P1OUT=(LCD_MEMRegisters[COM2]);

            SET_COM_LOW(COM2_BIT);
            SET_COM_AS_OUTPUT(COM2_BIT);

            //Next state
            LcdTiming_state=T5;
            break;

        case T5:/* at instant t5 shown in Figure 3*/
#ifdef HARDWARE_I2C
            //SEG0-5, P1.0-1.5
            //SEG6-7, P2.0, 2.1
            P1OUT ^= 0x3F;
            P2OUT ^= 0X03;
#else
            P1OUT^=0xFF; // Toggle all SEG lines
#endif
            SET_COM_HIGH(COM2_BIT);
            SET_COM_AS_OUTPUT(COM2_BIT);

            //Next state
            LcdTiming_state=T6;
            break;

        case T6:/* at instant t6 shown in Figure 3*/
#ifdef HARDWARE_I2C
            //SEG0-5, P1.0-1.5
            //SEG6-7, P2.0, 2.1
            tempPort1 = (P1OUT & 0xC0) +  (LCD_MEMRegisters[COM3] & 0x3F);
            tempPort2 = (P2OUT & 0xFC) + ((LCD_MEMRegisters[COM3] >> 6) & 0x03);

            P1OUT = tempPort1;
            P2OUT = tempPort2;
#else
            P1OUT=(LCD_MEMRegisters[COM3]);
#endif
            SET_COM_LOW(COM3_BIT);
            SET_COM_AS_OUTPUT(COM3_BIT);

            //Next state
            LcdTiming_state=T7;
            break;

        case T7:/* at instant t7 shown in Figure 3*/
#ifdef HARDWARE_I2C
            //SEG0-5, P1.0-1.5
            //SEG6-7, P2.0, 2.1
            P1OUT ^= 0x3F;
            P2OUT ^= 0X03;
#else
            P1OUT^=0xFF; // Toggle all SEG lines
#endif
            SET_COM_HIGH(COM3_BIT);
            SET_COM_AS_OUTPUT(COM3_BIT);

            //Next state
            LcdTiming_state=T0;
            break;
    }
}












