/****************************************************************************/
/* Copyright 2010 NorCal Avionics                                                   */
/* Norcal Avionics Proprietary Information. All rights reserved.                      */
/****************************************************************************/
// Version  1.2 3/19/2011

#include <p24fxxxx.h>
//#include "p24FJ64GA002.h"
#include <stdio.h>
#include <string.h>

#include "errors.h"
#include "serial.h"
#include "spi.h"
#include "mcp.h"
#include "sys_defs.h"
#include "sys_timer.h"
#include <libpic30.h>
#include "delay.h"
// #include "encode.h"
#define DSW              PORTAbits.RA4
#define RS_HIGH()        LATBbits.LATB10 = 1
#define RS_LOW()         LATBbits.LATB10 = 0

#define E_HIGH()         LATBbits.LATB11 = 1
#define E_LOW()          LATBbits.LATB11 = 0

#define MR_HIGH()        LATBbits.LATB0 = 1
#define MR_LOW()         LATBbits.LATB0 = 0

#define LCD4          LATBbits.LATB12
#define LCD5          LATBbits.LATB13
#define LCD6          LATBbits.LATB14
#define LCD7          LATBbits.LATB15

#define MAX_CHARS   80  /* maximum line display length */
#define SER_OUTPUT_TIME 1000
#define SER_INPUT_TIME 6000

/* JTAG/Code Protect/Write Protect/Clip-on Emulation mode
Watchdog Timer/ICD pins select */
_CONFIG1(JTAGEN_OFF & GCP_OFF & GWRP_OFF & COE_OFF & FWDTEN_OFF & ICS_PGx1) 
/* Enable CLK switch, Disable CLK monitor, OSCO or Fosc/2, 
Primary Oscillator Mode: Disabled, Internal Fast RC oscillator */
_CONFIG2(FCKSM_CSDCMD & OSCIOFNC_OFF & POSCMOD_XT & FNOSC_PRI)
/* Disable CLK switch and CLK monitor, OSCO or Fosc/2, HS oscillator,
Primary oscillator */



long alt[1024]__attribute__((space(auto_psv)))=
{ -9999,-1200,-1000,-1100,-800,-9999,-900,-9999,-9999,
    -300,-500,-400,-700,-9999,-600,-9999,-9999,700,500,600,300,-9999,400,-9999,
    -9999,-200,0,-100,200,-9999,100,-9999,-9999,2700,2500,2600,2300,-9999,2400,
    -9999,-9999,1800,2000,1900,2200,-9999,2100,-9999,-9999,800,1000,900,1200,
    -9999,1100,-9999,-9999,1700,1500,1600,1300,-9999,1400,-9999,-9999,6700,6500,
    6600,6300,-9999,6400,-9999,-9999,5800,6000,5900,6200,-9999,6100,-9999,
    -9999,4800,5000,4900,5200,-9999,5100,-9999,-9999,5700,5500,5600,5300,
    -9999,5400,-9999,-9999,2800,3000,2900,3200,-9999,3100,-9999,-9999,3700,
    3500,3600,3300,-9999,3400,-9999,-9999,4700,4500,4600,4300,-9999,4400,
    -9999,-9999,3800,4000,3900,4200,-9999,4100,-9999,-9999,14700,14500,14600,
    14300,-9999,14400,-9999,-9999,13800,14000,13900,14200,-9999,14100,-9999,-9999,
    12800,13000,12900,13200,-9999,13100,-9999,-9999,13700,13500,13600,13300,-9999,
    13400,-9999,-9999,10800,11000,10900,11200,-9999,11100,-9999,-9999,11700,11500,
    11600,11300,-9999,11400,-9999,-9999,12700,12500,12600,12300,-9999,12400,-9999,
    -9999,11800,12000,11900,12200,-9999,12100,-9999,-9999,6800,7000,6900,7200,
    -9999,7100,-9999,-9999,7700,7500,7600,7300,-9999,7400,-9999,-9999,8700,
    8500,8600,8300,-9999,8400,-9999,-9999,7800,8000,7900,8200,-9999,8100,
    -9999,-9999,10700,10500,10600,10300,-9999,10400,-9999,-9999,9800,10000,9900,
    10200,-9999,10100,-9999,-9999,8800,9000,8900,9200,-9999,9100,-9999,-9999,
    9700,9500,9600,9300,-9999,9400,-9999,-9999,30700,30500,30600,30300,-9999,
    30400,-9999,-9999,29800,30000,29900,30200,-9999,30100,-9999,-9999,28800,29000,
    28900,29200,-9999,29100,-9999,-9999,29700,29500,29600,29300,-9999,29400,-9999,
    -9999,26800,27000,26900,27200,-9999,27100,-9999,-9999,27700,27500,27600,27300,
    -9999,27400,-9999,-9999,28700,28500,28600,28300,-9999,28400,-9999,-9999,27800,
    28000,27900,28200,-9999,28100,-9999,-9999,22800,23000,22900,23200,-9999,23100,
    -9999,-9999,23700,23500,23600,23300,-9999,23400,-9999,-9999,24700,24500,24600,
    24300,-9999,24400,-9999,-9999,23800,24000,23900,24200,-9999,24100,-9999,-9999,
    26700,26500,26600,26300,-9999,26400,-9999,-9999,25800,26000,25900,26200,-9999,
    26100,-9999,-9999,24800,25000,24900,25200,-9999,25100,-9999,-9999,25700,25500,
    25600,25300,-9999,25400,-9999,-9999,14800,15000,14900,15200,-9999,15100,-9999,
    -9999,15700,15500,15600,15300,-9999,15400,-9999,-9999,16700,16500,16600,16300,
    -9999,16400,-9999,-9999,15800,16000,15900,16200,-9999,16100,-9999,-9999,18700,
    18500,18600,18300,-9999,18400,-9999,-9999,17800,18000,17900,18200,-9999,18100,
    -9999,-9999,16800,17000,16900,17200,-9999,17100,-9999,-9999,17700,17500,17600,
    17300,-9999,17400,-9999,-9999,22700,22500,22600,22300,-9999,22400,-9999,-9999,
    21800,22000,21900,22200,-9999,22100,-9999,-9999,20800,21000,20900,21200,-9999,
    21100,-9999,-9999,21700,21500,21600,21300,-9999,21400,-9999,-9999,18800,19000,
    18900,19200,-9999,19100,-9999,-9999,19700,19500,19600,19300,-9999,19400,-9999,
    -9999,20700,20500,20600,20300,-9999,20400,-9999,-9999,19800,20000,19900,20200,
    -9999,20100,-9999,-9999,62700,62500,62600,62300,-9999,62400,-9999,-9999,61800,
    62000,61900,62200,-9999,62100,-9999,-9999,60800,61000,60900,61200,-9999,61100,
    -9999,-9999,61700,61500,61600,61300,-9999,61400,-9999,-9999,58800,59000,58900,
    59200,-9999,59100,-9999,-9999,59700,59500,59600,59300,-9999,59400,-9999,-9999,
    60700,60500,60600,60300,-9999,60400,-9999,-9999,59800,60000,59900,60200,-9999,
    60100,-9999,-9999,54800,55000,54900,55200,-9999,55100,-9999,-9999,55700,55500,
    55600,55300,-9999,55400,-9999,-9999,56700,56500,56600,56300,-9999,56400,-9999,
    -9999,55800,56000,55900,56200,-9999,56100,-9999,-9999,58700,58500,58600,58300,
    -9999,58400,-9999,-9999,57800,58000,57900,58200,-9999,58100,-9999,-9999,56800,
    57000,56900,57200,-9999,57100,-9999,-9999,57700,57500,57600,57300,-9999,57400,
    -9999,-9999,46800,47000,46900,47200,-9999,47100,-9999,-9999,47700,47500,47600,
    47300,-9999,47400,-9999,-9999,48700,48500,48600,48300,-9999,48400,-9999,-9999,
    47800,48000,47900,48200,-9999,48100,-9999,-9999,50700,50500,50600,50300,-9999,
    50400,-9999,-9999,49800,50000,49900,50200,-9999,50100,-9999,-9999,48800,49000,
    48900,49200,-9999,49100,-9999,-9999,49700,49500,49600,49300,-9999,49400,-9999,
    -9999,54700,54500,54600,54300,-9999,54400,-9999,-9999,53800,54000,53900,54200,
    -9999,54100,-9999,-9999,52800,53000,52900,53200,-9999,53100,-9999,-9999,53700,
    53500,53600,53300,-9999,53400,-9999,-9999,50800,51000,50900,51200,-9999,51100,
    -9999,-9999,51700,51500,51600,51300,-9999,51400,-9999,-9999,52700,52500,52600,
    52300,-9999,52400,-9999,-9999,51800,52000,51900,52200,-9999,52100,-9999,-9999,
    30800,31000,30900,31200,-9999,31100,-9999,-9999,31700,31500,31600,31300,-9999,
    31400,-9999,-9999,32700,32500,32600,32300,-9999,32400,-9999,-9999,31800,32000,
    31900,32200,-9999,32100,-9999,-9999,34700,34500,34600,34300,-9999,34400,-9999,
    -9999,33800,34000,33900,34200,-9999,34100,-9999,-9999,32800,33000,32900,33200,
    -9999,33100,-9999,-9999,33700,33500,33600,33300,-9999,33400,-9999,-9999,38700,
    38500,38600,38300,-9999,38400,-9999,-9999,37800,38000,37900,38200,-9999,38100,
    -9999,-9999,36800,37000,36900,37200,-9999,37100,-9999,-9999,37700,37500,37600,
    37300,-9999,37400,-9999,-9999,34800,35000,34900,35200,-9999,35100,-9999,-9999,
    35700,35500,35600,35300,-9999,35400,-9999,-9999,36700,36500,36600,36300,-9999,
    36400,-9999,-9999,35800,36000,35900,36200,-9999,36100,-9999,-9999,46700,46500,
    46600,46300,-9999,46400,-9999,-9999,45800,46000,45900,46200,-9999,46100,-9999,
    -9999,44800,45000,44900,45200,-9999,45100,-9999,-9999,45700,45500,45600,45300,
    -9999,45400,-9999,-9999,42800,43000,42900,43200,-9999,43100,-9999,-9999,43700,
    43500,43600,43300,-9999,43400,-9999,-9999,44700,44500,44600,44300,-9999,44400,
    -9999,-9999,43800,44000,43900,44200,-9999,44100,-9999,-9999,38800,39000,38900,
    39200,-9999,39100,-9999,-9999,39700,39500,39600,39300,-9999,39400,-9999,-9999,
    40700,40500,40600,40300,-9999,40400,-9999,-9999,39800,40000,39900,40200,-9999,
    40100,-9999,-9999,42700,42500,42600,42300,-9999,42400,-9999,-9999,41800,42000,
    41900,42200,-9999,42100,-9999,-9999,40800,41000,40900,41200,-9999,41100,-9999,
    -9999,41700,41500,41600,41300,-9999,41400,-9999};

void digInit()
{
    /* set outputs here */
    TRISBbits.TRISB12 = 0;
    TRISBbits.TRISB13 = 0;
    TRISBbits.TRISB14 = 0;
    TRISBbits.TRISB15 = 0;
    TRISBbits.TRISB11 = 0;
    TRISBbits.TRISB10 = 0;
//  TRISBbits.TRISB4 = 0;
    TRISBbits.TRISB0 = 0;
    TRISAbits.TRISA4 = 1; //Set Input here
//  TRISAbits.TRISA0 = 0;
//  TRISAbits.TRISA1 = 0;
}

/**
 Functions above this line must be redefined for
 your particular PICmicro-to-LCD interface
*/

//Configure 4-bit data bus for output
/*void configBusAsOutLCD(void) {
  RW_LOW();                  //RW=0 to stop LCD from driving pins
 
}

//Configure 4-bit data bus for input
void configBusAsInLCD(void) {
 
  RW_HIGH();                   // R/W = 1, for read
}*/

//Output lower 4-bits of u8_c to LCD data lines
void outputToBusLCD(int u8_c)
{
    LCD4 = u8_c & 0x01;          //D4
    LCD5 = (u8_c >> 1)& 0x01;    //D5
    LCD6 = (u8_c >> 2)& 0x01;    //D6
    LCD7 = (u8_c >> 3)& 0x01;    //D7
}

//Configure the control lines for the LCD
void configControlLCD(void) 
{

    //RW_LOW();
    Nop();
    Nop();
    Nop();
    Nop();
    E_LOW();
    Nop();
    Nop();
    Nop();
    Nop();
    RS_LOW();
    Nop();
    Nop();
    Nop();
    Nop();
}

//Pulse the E clock, 1 us delay around edges for
//setup/hold times
void pulseE(void) 
{
    Nop();
    E_HIGH();
    Nop();
    Nop();
    E_LOW();
    Nop();
}

/* Write a byte (u8_Cmd) to the LCD.
u8_DataFlag is '1' if data byte, '0' if command byte
u8_Send8Bits is '1' if must send all 8 bits, else send only upper 4-bits
*/
void writeLCD(int u8_Cmd, int u8_DataFlag, int u8_Send8Bits) 
{
    delay_ms(1); // don't use busy, just delay

    //configBusAsOutLCD();
    if (u8_DataFlag) RS_HIGH();   // RS=1, data byte
    else    RS_LOW();             // RS=0, command byte
    outputToBusLCD(u8_Cmd >> 4);  // send upper 4 bits
    pulseE();
    if (u8_Send8Bits)
    {
        outputToBusLCD(u8_Cmd);     // send lower 4 bits
        pulseE();
    }
}

// Initialize the LCD, modify to suit your application and LCD
void initLCD() 
{
    outputToBusLCD(0x00);
    delay_ms(500);          //wait for device to settle
    writeLCD(0x30,0,1); // command 0x30 = Wake up
    delay_ms(350);
    writeLCD(0x30,0,1); // command 0x30 = Wake up
    delay_us(260);
    writeLCD(0x30,0,1); // command 0x30 = Wake up
    delay_us(260);
    writeLCD(0x20,0,1); // 4 bit interface
    delay_us(160);
    writeLCD(0x20,0,1); // 4 bit interface
    delay_us(160);

    writeLCD(0x28,0,1); // Function set: 4-bit/2-line
    Nop();
    writeLCD(0x01,0,1); // Clear
    Nop();
    writeLCD(0x10,0,1); // Set cursor
    Nop();
    writeLCD(0x0C,0,1); // Display ON; Blinking cursor off
    Nop();
    writeLCD(0x06,0,1); // Entry Mode set

    delay_ms(1);
}

//Output a string to the LCD
void outStringLCD(char *psz_s) 
{
    int i = 0;

    while ((*psz_s) && (++i < 50))
    {
        writeLCD(*psz_s, 1,1);
        psz_s++;
    }
}
/***************End of LCD Write**************/

/***************Serial IN**************/
int getLine(char* cmd)
{
    static int char_count = 0;
    static char line[MAX_CHARS] = "";
    const unsigned char terminator = '\r';
    int got_line;
    unsigned char b;
    int i;

    got_line = FALSE;

    while ( serGetByte(SER_IN, &b) )
    {

        if ( b != terminator )
        {
            if ( char_count < MAX_CHARS )
                line[char_count++] = b;

            cmd[0] = '\0';
        } 
        else
        {
            got_line = TRUE;
            line[char_count] = '\0';
            for (i = 0; i <= char_count; i++)
                cmd[i] = line[i];
            char_count = 0;
            break;
        }
    }

    return got_line;
}

/***************End of Serial IN**************/

int main(void)
{
    unsigned int a=1;
    long altout = alt[a];
// int seralt;
// int ret_val;
    unsigned char encode = 0;
    unsigned char encode1 = 0;
    unsigned int ensum = 0;
    char alt_s[MAX_CHARS];
    char alt_data[MAX_CHARS];
    Timer serInTimer;
    Timer serOutTimer;

    // char err_buff[32];
    digInit();
    configControlLCD();      //configure the LCD control lines
    initLCD();               //initialize the LCD 


/* Map UARTs to pins */
    RPINR18bits.U1RXR = 9;  /* Make Pin RP9 U1RX */
    RPOR4bits.RP8R = 3;     /* Make Pin RP8 U1TX */

    RPINR19bits.U2RXR = 3;  /* Make Pin RP3 U2RX */
    RPOR1bits.RP2R = 5;     /* Make Pin RP2 U2TX */

    /* map SPI bus pins */
    RPOR3bits.RP7R = 7;    /* Make Pin RP7 SPI1 SDO */
    RPINR20bits.SDI1R = 6; /* Make Pin RP6 SPI1 SDI */
    RPOR2bits.RP5R = 8;     /* Make Pin RP5  SP11 SCK */


    /* initialize I/O modules here */
    serInit();
    spiInit();
    MCP_Init();
    tmrInit();
    tmrCreate(&serInTimer);
    tmrCreate(&serOutTimer);


    /* Welcome Screen */
    outStringLCD("    NorCal Avionics    ");
    writeLCD(0x02,0,1); // Move cursor Home
    outStringLCD("    NorCal Avionics    ");
    writeLCD(0xC0,0,1);  // cursor to 2nd line
    outStringLCD("    Copyright  2011     "); 
    delay_ms(500);
    delay_ms(500);
    delay_ms(500);
    delay_ms(500);
    writeLCD(0x02,0,1); // Move cursor Home


    /* flush serial port before entering main loop */
    serRxFlush(SER_IN);

    /* start the serial output timer */
    tmrStart(&serInTimer);
    tmrStart(&serOutTimer);

#if 0 //for testing

    for (;;)
    {

        tmrTask();
//spiCS3(0);
LATBbits.LATB4 = 1;
        for (a = 0; a < 10; ++a)
            Nop();

//        delay_ms(10);
//        delay_us(10);
LATBbits.LATB4 = 0;

//spiCS3(1);


//        serRxFlush(SER_IN);


        if ( serGetRxOverFlow(SER_IN) )
        {
            serRxFlush(SER_IN);
            serClrRxOverFlow(SER_IN);
            serPutString(SER_OUT, "buffer overflow\r\n");
        }


    }

#else
    /* read inputs in a loop */
    for (;;)
    {


        tmrTask();
        /*****************************/        
        /* read GPIOB reg */
        /* This Reads Mode C Switches */

        encode1 = 0;
        encode = 0;
        spiCS2(1);   /* assert chip select */
        spiReadWrite(RD_OPCODE); /* write device opcode */
        spiReadWrite(0x13); /* wrtie reg address */
        encode1 = spiReadWrite(0xFF);  /* wrtie reg data */
        spiCS2(0);   /* deassert chip select */


        /* read GPIOA reg inputs from the MCP23S17 */
        spiCS2(1);   /* assert chip select */
        spiReadWrite(RD_OPCODE); /* write device opcode */
        spiReadWrite(0x12); /* wrtie reg address */
        encode = spiReadWrite(0xFF);  /* wrtie reg data */
        spiCS2(0);   /* deassert chip select */
        ensum = encode1 << 8;
        ensum = ensum | encode;

        /*****************************/ 
        /* This Wirtes Mode C SW date to line1 of LCD */

        a = ensum;
        altout = alt[a];
        //writeLCD(0x01,0,0); // Clear
        //writeLCD(0xC0,0,1);  // cursor to 2nd line

        if (altout == -9999)
        {
            sprintf(alt_data, "Switch Setting Invalid ");
            outStringLCD(alt_data);
            // delay_ms(500);
        } 
        else
        {
        sprintf(alt_data, "Mode C Alt %ld          ",altout);
        outStringLCD(alt_data);

            if ( tmrRead(&serOutTimer) > SER_OUTPUT_TIME)
            {
                tmrClear(&serOutTimer);
                sprintf(alt_data, "ALT %ld\r", altout); //write out Serial 1 ModeC SW
                serPutString(SER_OUT, alt_data);
            }

            //delay_ms(500);
        }
        /*****************************/ 
        if (DSW == FALSE) // Read Switch to set display for line2 LCD 
        {
            /*****************************/ 
            /*  This write out Serial 1 Mode C SW */ 
            /*****************************/  

            /* get seralt */
            writeLCD(0xC0,0,1);  // cursor to 2nd line
            if (getLine(alt_s))
            {
                tmrClear(&serInTimer);
                sprintf(alt_data, "Serial IN: %s           ", alt_s);
                outStringLCD(alt_data);

                if ( serGetRxOverFlow(SER_IN) )
                {
                    serRxFlush(SER_IN);
                    serClrRxOverFlow(SER_IN);
                    /* serPutString(SER_OUT, "buffer overflow\r\n");*/
                }
            }

    // #define SER_INPUT_TIME 8000
            if ( tmrRead(&serInTimer) > SER_INPUT_TIME)
            {
                tmrClear(&serInTimer);
                outStringLCD("Serial IN: NO DATA      ");
            }

            writeLCD(0x02,0,1); // Move cursor Home
            //  serRxFlush(SER_IN); //This is needed to clear FIFO when not reading port
            //  delay_ms(150); 
        } 
        else
        {
            /*****************************/     
            /*****************************/
            /* read GPIOB reg */
            /* This reads Encoder Port */
            encode1 = 0;
            encode = 0;
            a=0;  // clear Mode C data
            spiCS(1);   /* assert chip select */
            spiReadWrite(RD_OPCODE); /* write device opcode */
            spiReadWrite(0x13); /* wrtie reg address */
            encode1 = spiReadWrite(0xFF);  /* wrtie reg data */
            spiCS(0);   /* deassert chip select */

            /* read GPIOA reg inputs from the MCP23S17 */
            spiCS(1);   /* assert chip select */
            spiReadWrite(RD_OPCODE); /* write device opcode */
            spiReadWrite(0x12); /* wrtie reg address */
            encode = spiReadWrite(0xFF);  /* wrtie reg data */
            spiCS(0);   /* deassert chip select */
            ensum = encode1 << 8;
            ensum = ensum | encode;

            /*****************************/
            /*****************************/
            /* This Wirtes Encoder date to line2 of LCD */
            a = ensum;
            altout = alt[a];
            //writeLCD(0x01,0,0); // Clear
            writeLCD(0xC0,0,1);  // cursor to 2nd line
            if (altout == -9999)
            {
                sprintf(alt_data, "Encoder Input Invalid");
                outStringLCD(alt_data);
                writeLCD(0x02,0,1); // Move cursor Home
                // delay_ms(500);
            } 
            else
            {
                sprintf(alt_data, "Ecoder Alt %ld         ", altout);
                outStringLCD(alt_data);
                writeLCD(0x02,0,1); // Move cursor Home
                // delay_ms(500);
            }
            serRxFlush(SER_IN); //This is needed to clear FIFO when not reading port
            /*****************************/ 
        }
    }

#endif

    return 0;
}

