/*********************************************************************
 *
 *  RTCC test
 *
 *********************************************************************
 * Bruce Land Cornell University
 * November 2015
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

////////////////////////////////////
// clock AND protoThreads configure!
// You MUST check this file!
#include "config.h"
// threading library
#include "pt_cornell_1_2.h"

#include "tft_master.h"
#include "tft_gfx.h"

////////////////////////////////////

#include <math.h>
#include "dsplib_dsp.h"
#include "fftc.h"
#include <GenericTypeDefs.h>

#define LOG2N 8
#define N_WAVE (1 << LOG2N)
#define twiddles fft16c256
#define N_CYCLES 32
#define f (float)((float)Fs/(float)N_WAVE)
#define NOISE_FLOOR 10

UINT16 window[N_WAVE];
int16c x_t[N_WAVE];
int16c X_f[N_WAVE];
int16c scratch[N_WAVE];


/* Demo code for interfacing TFT (ILI9340 controller) to PIC32
 * The library has been modified from a similar Adafruit library
 */
// Adafruit data:
/***************************************************
  This is an example sketch for the Adafruit 2.2" SPI display.
  This library works with the Adafruit 2.2" TFT Breakout w/SD card
  ----> http://www.adafruit.com/products/1480

  Check out the links above for our tutorials and wiring diagrams
  These displays use SPI to communicate, 4 or 5 pins are required to
  interface (RST is optional)
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.
  MIT license, all text above must be included in any redistribution
 ****************************************************/

#define SYS_FREQ 40000000 // frequency we're running at

// string buffer
#define MAXINDEX 256
char buffer[60];
int waveform[MAXINDEX];
int index = 0;
int state = 0;
int scroll = 0;
int choice = 1;
// === thread structures ============================================
// thread control structs
// note that UART input and output are threads
static struct pt pt_cmd, pt_tick, pt_button, pt_fft;
// uart control threads
static struct pt pt_input, pt_output, pt_DMA_output ;

// system 1 second interval tick
int sys_time_seconds ;
// RTCC time, date
rtccTime	tm, tAlrm ;			// time structure BCD!!!
rtccDate	dt, dAlrm ;			// date structure
int yesterday;

int alarm = 0;
int freqCount = 0;
int timeCount = 0;
//int alarmMax[5] = {153, 136, 121, 115, 102};
int freqMax[] = {153, 136, 121, 136, 153, 182, 182, 204, 136, 153, 162, 153, 136,136,
153, 136, 121, 136, 153, 182, 182, 204, 136, 121, 115, 162, 153,153};
//int freqMax[] = {121, 136, 153, 136, 121, 121, 121, 136, 136, 136, 121, 102, 102, 7000};
int timeMax[] = {12000, 6000, 12000, 6000, 12000, 8000, 8000, 12000, 12000, 6000,
12000, 6000, 12000,12000, 12000, 6000, 12000, 6000, 12000, 8000, 8000, 12000, 12000, 6000,
12000, 6000, 12000,12000};
int alarmIndx = 0;
#define NOTEMAX 28
// G     A      B       C       D       E       F       G
// 98.00 110.0  123.5   130.8   146.8   164.8   174.6   196.0
// 204   182    162     153     136     121,    115,    102

#define alarmTIME 8000

int btnUp = 1;

int runfft = 0;

char buffer[60];

// === the RTCC uses BCD ==================================================
#define BCD2int(bcd) (bcd&0xf)+((bcd>>4)*10)

// === to set the RTCC in BCD =============================================
#define int2BCD(int) (int/10)<<4 | (int%10)


int feature = 0;
//for SH, look at 15 < i < 28 and 229 < i < 245
#define SHWIND 5
int shlowsum = 0;
int shhighsum = 0;
//stop shlowTH = 4 shhightTH =15    
#define shlowTH 23
#define shhighTH 17 
int sslowsum = 0;
int sshighsum = 0;
int ssemptysum = 0;
// low 4 high 15
#define sslowTH 4
#define sshighTH 15
#define ssemptyTH 5

int ahSum = 0;
#define ahTH 6
 
//for UH, look at 0 < i < 7
int uhSum = 0;
#define uhTH 20
int uhemptySum = 0;
#define uhemptyTH 3

int oohSum = 0;
#define oohTH 8

int oohemptySum = 0;
#define oohemptyTH 3

int zahlowSum = 0;
#define zahlowTH 20

int zahhighSum = 0;
#define zahhighTH 8

int zahemptylow = 0;
#define zahemptylowTH 2

int zahemptyhigh = 0;
#define zahemptyhighTH 2

int tempty = 0;
int tlength = 0;
#define temptyTH 10
#define tlengthTH 10
 
//// for SH, look at 15 < i < 28 and 229 < i < 245
//#define SHWIND 5
//int shlowsum = 0;
//int shhighsum = 0;
//#define shlowTH 23
//#define shhighTH 17
//
//// for IH, look at 1 < i < 5 and 12 < i < 28
//int ihfstSum = 0;
//int ihsecSum = 0;
//#define ihfstTH 1
//#define ihsecTH 0
//
//// for B, look for aspiration
//int fullsum = 0;
//int emptyTime = 0;
//#define fullTH 60
//#define emptyTH 7
//
//// for OH, look at 1 < i < 10
//int ohSum = 0;
//#define ohTH 40
//
//// for EL, look at emptiness of 9 < i < 20
//int elsum = 0;
//int eltime = 0;
//#define elTH 40
//#define elemptyTH 7
//
//// for EH, look at 1 < i < 5 and 9 < i < 20
//int ehlowsum = 0;
//int ehhighsum = 0;
//#define ehlowTH 3
//#define ehhighTH 3


//red yellow green blue white
int colors[] = {
0x0000,
0x001F,
0xF800,
0x07E0,
0x07FF,
0xF81F,
0xFFE0,
0xFFFF
};

void __ISR(_RTCC_VECTOR, IPL4SOFT) RtccIsr(void)
{
	// once we get in the RTCC ISR we have to clear the RTCC int flag
	INTClearFlag(INT_RTCC);

	alarm = 1;

}

void dofft(int num){
    if(num == 1){
            int i;
    for(i=0; i<N_WAVE; i++){
        x_t[i].re = waveform[i];
        x_t[i].im = 0;
    }
    mips_fft16(X_f, x_t, twiddles, scratch, LOG2N);
        shlowsum = 0;
        shhighsum = 0;
        uhSum = 0;
        uhemptySum = 0;

        for (i=0; i<MAXINDEX; i++){
            //35 to 55
            if (15 < i && i < 28) {
                shlowsum += X_f[i].re;
            }
            //205 to 224
            if (229 < i && i < 245) {
               shhighsum += X_f[i].re;
            }
            // 0 to 10
            if (0 < i && i < 7) {
                uhSum += X_f[i].re;
            }
            if (20 < i && i < 120){
                uhemptySum += X_f[i].re;
            }


            if (i < 240){
                if (X_f[i].re/2 > 7){
                    X_f[i].re = 14;
                }
                tft_drawPixel(scroll, i, colors[X_f[i].re/2]);
            }
        }
        tft_drawPixel(scroll, 20, ILI9340_MAGENTA);
        tft_drawPixel(scroll, 120, ILI9340_MAGENTA);
        tft_drawPixel(scroll, 235, ILI9340_MAGENTA);
        tft_drawPixel(scroll, 245, ILI9340_MAGENTA);
        if (shlowsum > shlowTH && shhighsum > shhighTH &&  feature == 0){
       
            feature = 1;
        }
//        tft_drawPixel(scroll, 15, ILI9340_MAGENTA);
//        tft_drawPixel(scroll, 25, ILI9340_MAGENTA);
//        tft_drawPixel(scroll, 229, ILI9340_MAGENTA);
        
        
        if (uhSum > uhTH && uhemptySum < uhemptyTH && feature == 1) {
          //  feature = 2;
          //tft_fillRoundRect(0, 0, 10, 10, 1, ILI9340_YELLOW);
            feature = 2;
          //  alarm = 0;
        }
//        tft_drawPixel(scroll, 0, ILI9340_MAGENTA);
//        tft_drawPixel(scroll, 5, ILI9340_MAGENTA);
//        tft_drawPixel(scroll, 12, ILI9340_MAGENTA);
//        tft_drawPixel(scroll, 28, ILI9340_MAGENTA);
        
        

        
        
        if (shlowsum > shlowTH && shhighsum > shhighTH  && feature == 2) {
            tft_fillRoundRect(0, 0, 10, 10, 1, ILI9340_YELLOW);
            feature = 0;
            alarm = 0;
        }

        
        
                // write feature index
        tft_fillRoundRect(0,220, 10, 10, 1, ILI9340_BLACK);// x,y,w,h,radius,color
        tft_setCursor(0, 220);
        tft_setTextColor(ILI9340_YELLOW); tft_setTextSize(1);
        sprintf(buffer,"%d", feature);
        tft_writeString(buffer);
            
            
        scroll++;
        if(scroll == 320){
            scroll = 0;
        }
        //mPORTBToggleBits(BIT_8);
        
        index = 0;
        runfft = 0;
    }
    else if(num == 2){
             int i;
    for(i=0; i<N_WAVE; i++){
        x_t[i].re = waveform[i];
        x_t[i].im = 0;
    }
    mips_fft16(X_f, x_t, twiddles, scratch, LOG2N);
        sslowsum = 0;
        sshighsum = 0;
        ssemptysum = 0;
        ahSum = 0;

        for (i=0; i<MAXINDEX; i++){
            //35 to 55
            if (35 < i && i < 55) {
                sslowsum += X_f[i].re;
            }
            //205 to 224
            if (205 < i && i < 224) {
               sshighsum += X_f[i].re;
            }
            if (100 < i && i < 160) {
                ssemptysum += X_f[i].re;
            }
            // 0 to 10
            if (0 < i && i < 10) {
                ahSum += X_f[i].re;
            }

            if (i < 240){
                if (X_f[i].re/2 > 7){
                    X_f[i].re = 14;
                }
                tft_drawPixel(scroll, i, colors[X_f[i].re/2]);
            }
        }
        tft_drawPixel(scroll, 100, ILI9340_MAGENTA);
        tft_drawPixel(scroll, 160, ILI9340_MAGENTA);
        tft_drawPixel(scroll, 205, ILI9340_MAGENTA);
        tft_drawPixel(scroll, 224, ILI9340_MAGENTA);
        if (sslowsum > sslowTH && sshighsum > sshighTH && ssemptysum < ssemptyTH &&  feature == 0){
       
            feature = 1;
        }
//        tft_drawPixel(scroll, 15, ILI9340_MAGENTA);
//        tft_drawPixel(scroll, 25, ILI9340_MAGENTA);
//        tft_drawPixel(scroll, 229, ILI9340_MAGENTA);
        
        
        if (ahSum > ahTH && feature == 1) {
          //  feature = 2;
            feature = 0;
                        alarm = 0;
            tft_fillRoundRect(0, 0, 10, 10, 1, ILI9340_YELLOW);
        }

                // write feature index
        tft_fillRoundRect(0,220, 10, 10, 1, ILI9340_BLACK);// x,y,w,h,radius,color
        tft_setCursor(0, 220); 
        tft_setTextColor(ILI9340_YELLOW); tft_setTextSize(1);
        sprintf(buffer,"%d", feature);
        tft_writeString(buffer);
            
        scroll++;
        if(scroll == 320){
            scroll = 0;
        }
        //mPORTBToggleBits(BIT_8);
        
        index = 0;
        runfft = 0;   
    }
    else if(num == 3){
             int i;
    for(i=0; i<N_WAVE; i++){
        x_t[i].re = waveform[i];
        x_t[i].im = 0;
    }
    mips_fft16(X_f, x_t, twiddles, scratch, LOG2N);
        sslowsum = 0;
        sshighsum = 0;
        ssemptysum = 0;
        oohSum = 0;
        oohemptySum = 0;
        zahlowSum = 0;
        zahhighSum = 0;
        zahemptylow = 0;
        zahemptyhigh = 0;

        for (i=0; i<MAXINDEX; i++){
            //35 to 55
            if (35 < i && i < 55) {
                sslowsum += X_f[i].re;
            }
            //205 to 224
            if (205 < i && i < 224) {
               sshighsum += X_f[i].re;
            }
            if (100 < i && i < 160) {
                ssemptysum += X_f[i].re;
            }
            // 0 to 10
            if (0 < i && i < 15) {
                oohSum += X_f[i].re;
            }
            if (20 < i && i < 125){
                oohemptySum += X_f[i].re;
            }
            if (35 < i && i < 50) {
                zahlowSum += X_f[i].re;
            }
            if (205 < i && i < 220) {
                zahhighSum += X_f[i].re;
            }
            if (0 < i && i < 20) {
                zahemptylow += X_f[i].re;
            }
            if (40 < i && i < 125){
                zahemptyhigh += X_f[i].re;
            }
            if (i < 240){
                if (X_f[i].re/2 > 7){
                    X_f[i].re = 14;
                }
                tft_drawPixel(scroll, i, colors[X_f[i].re/2]);
            }
        }
        tft_drawPixel(scroll, 0, ILI9340_MAGENTA);
        tft_drawPixel(scroll, 40, ILI9340_MAGENTA);
        tft_drawPixel(scroll, 125, ILI9340_MAGENTA);
        tft_drawPixel(scroll, 150, ILI9340_MAGENTA);
        if (sslowsum > sslowTH && sshighsum > sshighTH && ssemptysum < ssemptyTH && feature == 0){
       
            feature = 1;
        }
//        tft_drawPixel(scroll, 15, ILI9340_MAGENTA);
//        tft_drawPixel(scroll, 25, ILI9340_MAGENTA);
//        tft_drawPixel(scroll, 229, ILI9340_MAGENTA);
        
        
        if (oohSum > oohTH && oohemptySum < oohemptyTH && feature == 1) {
            feature = 2;
        }
        if (zahhighSum > zahhighTH && zahlowSum > zahlowTH && zahemptylow < zahemptylowTH && zahemptylow < zahemptyhighTH && oohSum < oohTH && feature == 2) {
            alarm = 0;
            tft_fillRoundRect(0, 0, 10, 10, 1, ILI9340_YELLOW);
            int alarmmin = BCD2int(tAlrm.min) + 10;
            if (alarmmin > 59){
                alarmmin -= 60;
                int alarmhour = BCD2int(tAlrm.hour) + 1;
                if (alarmhour == 24){
                    alarmhour = 0;
                }
                tAlrm.hour = int2BCD(alarmhour);
            }
            tAlrm.min = int2BCD(alarmmin);
            RtccSetAlarmTimeDate(tAlrm.l, dAlrm.l);
            feature = 0;
        }
                // write feature index
        tft_fillRoundRect(0,220, 10, 10, 1, ILI9340_BLACK);// x,y,w,h,radius,color
        tft_setCursor(0, 220);
        tft_setTextColor(ILI9340_YELLOW); tft_setTextSize(1);
        sprintf(buffer,"%d", feature);
        tft_writeString(buffer);
            
        scroll++;
        if(scroll == 320){
            scroll = 0;
        }
        //mPORTBToggleBits(BIT_8);
        
        index = 0;
        runfft = 0;   
    }
    else if(num == 4){
            int i;
    for(i=0; i<N_WAVE; i++){
        x_t[i].re = waveform[i];
        x_t[i].im = 0;
    }
    mips_fft16(X_f, x_t, twiddles, scratch, LOG2N);
        shlowsum = 0;
        shhighsum = 0;
        uhSum = 0;
        uhemptySum = 0;
        ahSum = 0;
        tempty = 0;

        for (i=0; i<MAXINDEX; i++){
            //35 to 55
            if (15 < i && i < 28) {
                shlowsum += X_f[i].re;
            }
            //205 to 224
            if (229 < i && i < 245) {
               shhighsum += X_f[i].re;
            }
            // 0 to 10
            if (0 < i && i < 7) {
                uhSum += X_f[i].re;
            }
            if (i != 0){
                tempty += X_f[i].re;
            }
            if (20 < i && i < 120){
                uhemptySum += X_f[i].re;
            }
            if (0 < i && i < 10) {
                ahSum += X_f[i].re;
            }
            
            if (i < 240){
                if (X_f[i].re/2 > 7){
                    X_f[i].re = 14;
                }
                tft_drawPixel(scroll, i, colors[X_f[i].re/2]);
            }
        }
        tft_drawPixel(scroll, 20, ILI9340_MAGENTA);
        tft_drawPixel(scroll, 120, ILI9340_MAGENTA);
        tft_drawPixel(scroll, 235, ILI9340_MAGENTA);
        tft_drawPixel(scroll, 245, ILI9340_MAGENTA);
        if (shlowsum > shlowTH && shhighsum > shhighTH &&  feature == 0){
       
            feature = 1;
        }
//        tft_drawPixel(scroll, 15, ILI9340_MAGENTA);
//        tft_drawPixel(scroll, 25, ILI9340_MAGENTA);
//        tft_drawPixel(scroll, 229, ILI9340_MAGENTA);
        
        if (uhSum > uhTH && uhemptySum < uhemptyTH && feature == 1) {
          //  feature = 2;
          //tft_fillRoundRect(0, 0, 10, 10, 1, ILI9340_YELLOW);
            feature = 2;
          //  alarm = 0;
        }
//        tft_drawPixel(scroll, 0, ILI9340_MAGENTA);
//        tft_drawPixel(scroll, 5, ILI9340_MAGENTA);
//        tft_drawPixel(scroll, 12, ILI9340_MAGENTA);
//        tft_drawPixel(scroll, 28, ILI9340_MAGENTA);
        
        if (tempty < temptyTH && feature == 2) {
            tlength++;
            if(tlength == tlengthTH){
                tlength = 0;
                feature = 3;
            }
          //tft_fillRoundRect(0, 0, 10, 10, 1, ILI9340_YELLOW);
        }
        
        if (ahSum > ahTH && feature == 3) {
          //  feature = 2;
            feature = 0;
            alarm = 0;
            tft_fillRoundRect(0, 0, 10, 10, 1, ILI9340_YELLOW);
        }
                // write feature index
        tft_fillRoundRect(0,220, 10, 10, 1, ILI9340_BLACK);// x,y,w,h,radius,color
        tft_setCursor(0, 220);
        tft_setTextColor(ILI9340_YELLOW); tft_setTextSize(1);
        sprintf(buffer,"%d", feature);
        tft_writeString(buffer);
            
        scroll++;
        if(scroll == 320){
            scroll = 0;
        }
        //mPORTBToggleBits(BIT_8);
        
        index = 0;
        runfft = 0;
    }
}

void __ISR(_TIMER_2_VECTOR, ipl2) Timer2Handler(void)
{
    mT2ClearIntFlag();
    if(alarm){
        timeCount++;
        freqCount++;
        if(freqCount == freqMax[alarmIndx]){
            freqCount = 0;
            mPORTBToggleBits(BIT_8);
        }
        if(timeCount == timeMax[alarmIndx]){
            timeCount = 0;
            freqCount = 0;
            alarmIndx++;
            if(alarmIndx == NOTEMAX){
                alarmIndx = 0;
            }
        }
    }
    if(btnUp){
        return;
    }
    if(runfft == 0){
        static unsigned int adc_9;
        // read the ADC from pin 26 (AN9)
        // read the first buffer position
        adc_9 = ReadADC10(0);   // read the result of channel 9 conversion from the idle buffer
        AcquireADC10(); // not needed if ADC_AUTO_SAMPLING_ON below

        waveform[index] = adc_9;
        index++;

        if(index == MAXINDEX){
            runfft = 1;
        }
    }
}

// === Display Thread =====================================================
static PT_THREAD (protothread_button(struct pt *pt))
{
	PT_BEGIN(pt);
	
	while(1) {
        PT_YIELD_TIME_msec(30);
          if(mPORTBReadBits(BIT_14)){
              if(btnUp == 0){
                  feature = 0;
                  btnUp = 1;
                  scroll = 0;
                  tft_fillScreen(ILI9340_BLACK);
              }
          }else{
              if(btnUp){
                  btnUp = 0;
                  tft_fillScreen(ILI9340_BLACK);
              }
          }
	}
	
	PT_END(pt);
}

// === fft Thread =====================================================
static PT_THREAD (protothread_fft(struct pt *pt))
{
	PT_BEGIN(pt);
	
	while(1) {
        PT_YIELD_TIME_msec(1);
        if(runfft){
            dofft(choice);
        }
	}
	
	PT_END(pt);
}


// === Serial Thread ======================================================
static PT_THREAD (protothread_cmd(struct pt *pt))
{
    // The serial interface
    static char cmd[16]; 
    static int hour, min, sec, mon, day, year;
   
    PT_BEGIN(pt);
    
    // clear port used by thread 4
    mPORTBClearBits(BIT_0);
   
      while(1) {
            // send the prompt via DMA to serial
            sprintf(PT_send_buffer,"cmd>");
            // by spawning a print thread
            PT_SPAWN(pt, &pt_DMA_output, PT_DMA_PutSerialBuffer(&pt_DMA_output) );
 
          //spawn a thread to handle terminal input
            // the input thread waits for input
            // -- BUT does NOT block other threads
            // string is returned in "PT_term_buffer"
            PT_SPAWN(pt, &pt_input, PT_GetSerialBuffer(&pt_input) );
            // returns when the theard dies
            // in this case, when <enter> is pushed
            // now parse the string
             sscanf(PT_term_buffer, "%s %d %d %d", cmd, &hour, &min, &sec);

             switch(cmd[0]){
                 case 'o':
                     choice = hour;
                     sprintf(PT_send_buffer, "Choice selected.\n\r");
                     PT_SPAWN(pt, &pt_DMA_output, PT_DMA_PutSerialBuffer(&pt_DMA_output) );
                     break;
                 case 'x': // clear the RTC
                    RtccSetTimeDate(0x0, 0x0);
                    break;
                case 't': // attack rate constant  1=FM 2=main
                    tm.l=RtccGetTime();
                    sprintf(PT_send_buffer, "RTCC hr:min:sec=%d %d %d\n\r",
                            BCD2int(tm.hour), BCD2int(tm.min), BCD2int(tm.sec));
                    PT_SPAWN(pt, &pt_DMA_output, PT_DMA_PutSerialBuffer(&pt_DMA_output) );
                    break;
                case 'r':
                    dt.l=RtccGetDate();
                    sprintf(PT_send_buffer, "RTCC year:month:day=%d %d %d\n\r",
                            BCD2int(dt.year), BCD2int(dt.mon), BCD2int(dt.mday));
                    PT_SPAWN(pt, &pt_DMA_output, PT_DMA_PutSerialBuffer(&pt_DMA_output) );
                    break;
                case 'a':
                    if(hour > 23 || hour < 0) {
                            sprintf(PT_send_buffer, "Not a valid hour time.\n\r");
                            PT_SPAWN(pt, &pt_DMA_output, PT_DMA_PutSerialBuffer(&pt_DMA_output) );
                            break;
                    }
                    if(min > 59 || min < 0) {
							sprintf(PT_send_buffer, "Not a valid minute time.\n\r");
                            PT_SPAWN(pt, &pt_DMA_output, PT_DMA_PutSerialBuffer(&pt_DMA_output) );
							break;
					}
                    if(sec > 59 || sec < 0) {
							sprintf(PT_send_buffer, "Not a valid second time.\n\r");
                            PT_SPAWN(pt, &pt_DMA_output, PT_DMA_PutSerialBuffer(&pt_DMA_output) );
							break;
					}
                    tAlrm.hour = int2BCD(hour); tAlrm.min = int2BCD(min); tAlrm.sec = int2BCD(sec);
                    RtccSetAlarmTimeDate(tAlrm.l, dAlrm.l);
                    sprintf(PT_send_buffer, "Alarm Time Set. \n\r");
                    PT_SPAWN(pt, &pt_DMA_output, PT_DMA_PutSerialBuffer(&pt_DMA_output) );
                    RTCALRMSET=0x8000; // re-enable the alarm, set alarm mask at once per day
					break;
				case 'c':
                   if(hour > 23 || hour < 0) {
                            sprintf(PT_send_buffer, "Not a valid hour time.\n\r");
                            PT_SPAWN(pt, &pt_DMA_output, PT_DMA_PutSerialBuffer(&pt_DMA_output) );
                            break;
                    }
                    if(min > 59 || min < 0) {
							sprintf(PT_send_buffer, "Not a valid minute time.\n\r");
                            PT_SPAWN(pt, &pt_DMA_output, PT_DMA_PutSerialBuffer(&pt_DMA_output) );
							break;
					}
                    if(sec > 59 || sec < 0) {
							sprintf(PT_send_buffer, "Not a valid second time.\n\r");
                            PT_SPAWN(pt, &pt_DMA_output, PT_DMA_PutSerialBuffer(&pt_DMA_output) );
							break;
					}
                    tm.hour = int2BCD(hour); tm.min = int2BCD(min); tm.sec = int2BCD(sec);
                    RtccSetTimeDate(tm.l, dt.l);
                    sprintf(PT_send_buffer, "Current Time Set. \n\r");
                    PT_SPAWN(pt, &pt_DMA_output, PT_DMA_PutSerialBuffer(&pt_DMA_output) );
					break;
                 case 'd':
                     if(hour > 12 || hour < 0) {
                         sprintf(PT_send_buffer, "Not a valid month.\n\r");
                            PT_SPAWN(pt, &pt_DMA_output, PT_DMA_PutSerialBuffer(&pt_DMA_output) );
							break;
                     }
                     int maxdays = 30;
                     if((hour < 8 && hour%2==1) || (hour > 7 && hour%2==0)){
                         maxdays = 31;
                     }
                     if(hour == 2){
                         maxdays = 29;
                     }
                     if(min > maxdays || min < 0) {
                         sprintf(PT_send_buffer, "Not a valid day for this month.\n\r");
                            PT_SPAWN(pt, &pt_DMA_output, PT_DMA_PutSerialBuffer(&pt_DMA_output) );
							break;
                     }
                     if(sec > 99 || sec < 15) {
                         sprintf(PT_send_buffer, "Not a valid year.\n\r");
                            PT_SPAWN(pt, &pt_DMA_output, PT_DMA_PutSerialBuffer(&pt_DMA_output) );
							break;
                     }
                     yesterday = BCD2int(dt.mday);
                     dt.year = int2BCD(sec); dt.mon = int2BCD(hour); dt.mday = int2BCD(min);
                     RtccSetTimeDate(tm.l, dt.l);
                     sprintf(PT_send_buffer, "Today's date set. \n\r");
                     PT_SPAWN(pt, &pt_DMA_output, PT_DMA_PutSerialBuffer(&pt_DMA_output) );
					break;
            }
            // never exit while
      } // END WHILE(1)
  PT_END(pt);
} // thread 3

// === Thread 5 ======================================================
// update a 1 second tick counter
static PT_THREAD (protothread_tick(struct pt *pt))
{
    PT_BEGIN(pt);
//    tft_fillRoundRect(0,90, 300, 30, 1, ILI9340_YELLOW);// x,y,w,h,radius,color
//    tft_fillRoundRect(0,190, 300, 30, 1, ILI9340_YELLOW);// x,y,w,h,radius,color
      while(1) {
            // yield time 1 second
            PT_YIELD_TIME_msec(20) ;
            sys_time_seconds++ ;
            // NEVER exit while
            
             tm.l = RtccGetTime(); dt.l = RtccGetDate();
             tAlrm.l = RtccGetAlarmTime();
             if(btnUp){
                tft_setCursor(0, 50);
                tft_setTextColor(ILI9340_WHITE); tft_setTextSize(2);
                sprintf(buffer, "Today is %02d/%02d/%d\n",
                        BCD2int(dt.mon), BCD2int(dt.mday), BCD2int(dt.year));
                tft_writeString(buffer);
                if(yesterday != dt.mday) {
                    tft_fillRoundRect(105, 45, 100, 25, 1, ILI9340_BLACK);
                    tft_setCursor(0, 50);
                    tft_setTextColor(ILI9340_WHITE); tft_setTextSize(2);
                    sprintf(buffer, "Today is %02d/%02d/%d\n",
                        BCD2int(dt.mon), BCD2int(dt.mday), BCD2int(dt.year));
                tft_writeString(buffer);
                yesterday = BCD2int(dt.mday);
                }
                tft_fillRoundRect(155,90, 100, 30, 1, ILI9340_BLACK);// x,y,w,h,radius,color
                tft_setCursor(0, 100);
                tft_setTextColor(ILI9340_WHITE); tft_setTextSize(2);
                sprintf(buffer, "Current Time %02d:%02d:%02d\n",
                BCD2int(tm.hour), BCD2int(tm.min), BCD2int(tm.sec) );
                tft_writeString(buffer);
                tft_fillRoundRect(130,190, 100, 30, 1, ILI9340_BLACK);// x,y,w,h,radius,color
                tft_setCursor(0, 200);
                tft_setTextColor(ILI9340_WHITE); tft_setTextSize(2);
                sprintf(buffer, "Alarm Time %02d:%02d:%02d\n\r",
                BCD2int(tAlrm.hour), BCD2int(tAlrm.min), BCD2int(tAlrm.sec)      );
                tft_writeString(buffer);
             }
      } // END WHILE(1)
  PT_END(pt);
} // thread 4

// === Main  ======================================================
// set up UART, timer2, threads, display
// then schedule them as fast as possible

int main(void)
{
    
	// === config the uart, DMA, vref, timer5 ISR =============
	PT_setup();

	// === setup system wide interrupts  ====================
	INTEnableSystemMultiVectoredInt();
    
      // the ADC ///////////////////////////////////////
        // configure and enable the ADC
	CloseADC10();	// ensure the ADC is off before setting the configuration

	// define setup parameters for OpenADC10
	// Turn module on | ouput in integer | trigger mode auto | enable autosample
        // ADC_CLK_AUTO -- Internal counter ends sampling and starts conversion (Auto convert)
        // ADC_AUTO_SAMPLING_ON -- Sampling begins immediately after last conversion completes; SAMP bit is automatically set
        // ADC_AUTO_SAMPLING_OFF -- Sampling begins with AcquireADC10();
        #define PARAM1  ADC_FORMAT_INTG16 | ADC_CLK_AUTO | ADC_AUTO_SAMPLING_OFF //

	// define setup parameters for OpenADC10
	// ADC ref external  | disable offset test | disable scan mode | do 1 sample | use single buf | alternate mode off
	#define PARAM2  ADC_VREF_AVDD_AVSS | ADC_OFFSET_CAL_DISABLE | ADC_SCAN_OFF | ADC_SAMPLES_PER_INT_1 | ADC_ALT_BUF_OFF | ADC_ALT_INPUT_OFF
        //
	// Define setup parameters for OpenADC10
        // use peripherial bus clock | set sample time | set ADC clock divider
        // ADC_CONV_CLK_Tcy2 means divide CLK_PB by 2 (max speed)
        // ADC_SAMPLE_TIME_5 seems to work with a source resistance < 1kohm
        #define PARAM3 ADC_CONV_CLK_PB | ADC_SAMPLE_TIME_5 | ADC_CONV_CLK_Tcy2 //ADC_SAMPLE_TIME_15| ADC_CONV_CLK_Tcy2

	// define setup parameters for OpenADC10
	// set AN11 and  as analog inputs
	#define PARAM4	ENABLE_AN0_ANA // pin 24

	// define setup parameters for OpenADC10
	// do not assign channels to scan
	#define PARAM5	SKIP_SCAN_ALL

	// use ground as neg ref for A | use AN11 for input A     
	// configure to sample AN11 
	SetChanADC10( ADC_CH0_NEG_SAMPLEA_NVREF | ADC_CH0_POS_SAMPLEA_AN0 ); // configure to sample AN4 
	OpenADC10( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5 ); // configure ADC using the parameters defined above

	EnableADC10(); // Enable the ADC
    
        // timer interrupt //////////////////////////
    OpenTimer2(T2_ON | T2_SOURCE_INT | T2_PS_1_1, 1000); //T2_PS_1_32: 32 clocks = one timer tick
    // set up the timer interrupt with a priority of 2
    ConfigIntTimer2(T2_INT_ON | T2_INT_PRIOR_2);
    
    //RTCCONSET = 1 << 15 | ; 
    
    mPORTBSetPinsDigitalIn(BIT_14);
    
//    int generate_period = 363636;
//    OpenTimer3(T3_ON | T3_SOURCE_INT | T3_PS_1_1, generate_period);
//      OpenOC3(OC_ON | OC_TIMER3_SRC | OC_CONTINUE_PULSE , (generate_period>>1), 0);
//      PPSOutput(4, RPB9, OC3); //pin18
    
    ///////////////////////////////////////////////////////
    
	// init the display
	tft_init_hw();
	tft_begin();
	tft_fillScreen(ILI9340_BLACK);
	//240x320 vertical display
	tft_setRotation(1); // Use tft_setRotation(1) for 320x240
    
    PPSOutput(2, RPA1, SDO2);
	
	// === now the clock ====================
	// init the clock  -- IN BCD format!!! 
	tm.hour = 0;    tAlrm.hour = 0;
	tm.min = 0;     tAlrm.min = 0x01;
	tm.sec = 0;     tAlrm.sec = 0x02;
	dt.mday = 0x08; dAlrm.mday = 0x08;
	dt.mon = 0x12;  dAlrm.mon = 0x12;
	dt.year = 0x2015; dAlrm.year = 0x2015;
    yesterday = BCD2int(dt.mday);

	RtccInit();
    //while(RtccGetClkStat()!=RTCC_CLK_ON);	// wait for the SOSC to be actually running and RTCC to have its clock source
							// could wait here at most 32ms
	RtccSetTimeDate(tm.l, dt.l) ;
	RtccSelectPulseOutput(1);		// select the seconds clock pulse as the function of the RTCC output pin
	RtccOutputEnable(1);			// enable the Output pin of the RTCC (PIN 7 on 28 pin PDIP)
    
    RtccChimeDisable();							// don't want rollover
//	RtccSetAlarmRptCount(0);					// one alarm will do
//	RtccSetAlarmRpt(RTCC_RPT_TEN_SEC);			// enable repeat rate, check the second field
	RtccSetAlarmTimeDate(tAlrm.l, dAlrm.l);		// set the alarm time
	RtccAlarmEnable();							// enable the alarm
   
    // enabling/disabling the RTCC alarm interrupts
                
        INTSetVectorPriority(INT_RTCC_VECTOR, INT_PRIORITY_LEVEL_4);			// set the RTCC priority in the INT controller
		INTSetVectorSubPriority(INT_RTCC_VECTOR, INT_SUB_PRIORITY_LEVEL_1);		// set the RTCC sub-priority in the INT controller
		INTEnable(INT_RTCC, INT_ENABLED);					// enable the RTCC event interrupts in the INT controller.

    
    /*
The following code example illustrates an RTCC initialization with interrupts enabled.
When the RTCC alarm interrupt is generated, the cpu will jump to the vector assigned to
RTCC interrupt.
*/
/*// assume RTCC write is enabled i.e. RTCWREN (RTCCON<3>) =1;*/
IEC1CLR=0x00008000; // disable RTCC interrupts
RTCCONCLR=0x8000; // turn off the RTCC
while(RTCCON&0x40); // wait for clock to be turned off
IFS1CLR=0x00008000; // clear RTCC existing event
IPC8CLR=0x1f000000; // clear the priority
IPC8SET=0x0d000000; // Set IPL=3, subpriority 1
IEC1SET=0x00008000; // Enable RTCC interrupts
RTCTIME=0x16153300; // safe to update time to 16 hr, 15 min, 33 sec
RTCDATE=0x06102705; // update the date to Friday 27 Oct 2006
RTCALRMCLR=0xCFFF; // clear ALRMEN, CHIME, AMASK and ARPT;
ALRMDATE=0x06102705; // set alarm date to Friday 27 Oct 2006
RTCALRMSET=0x8000|0x00000600; // re-enable the alarm, set alarm mask at once per day
RTCCONSET=0x8000; // turn on the RTCC
while(!(RTCCON&0x40)); // wait for clock to be turned on
        
        
    mPORTBSetPinsDigitalOut(BIT_8);
    
	// === init the threads ===================
	PT_INIT(&pt_cmd);
	PT_INIT(&pt_tick);
	PT_INIT(&pt_button);
    PT_INIT(&pt_fft);
  
  
	// schedule the threads
	while(1) {
    // round robin
        if(btnUp){
            PT_SCHEDULE(protothread_cmd(&pt_cmd));
            PT_SCHEDULE(protothread_tick(&pt_tick));
        }
	PT_SCHEDULE(protothread_button(&pt_button));
    PT_SCHEDULE(protothread_fft(&pt_fft));
	}
} // main