/*
 * File:   semaforo.c
 * Author: Corrado
 *
 * Created on 12 dicembre 2016, 9.28
 */


#include <xc.h>
#include <stdio.h>

#define TIME_1_SECONDO  -62500

#define VERDE   0
#define GIALLO  1
#define ROSSO   2
#define ATTESA  3

#define TG      3
char TR = 8;
char TS = 5;
char counter;

char stato;
char prenotazione = 0;

const char *nomi_stato[] = { "VERDE", "GIALLO", "ROSSO", "ATTESA" };

void setup_digital(void)
{
    // led ports as outputs
    TRISBbits.TRISB0 = 0;
    TRISBbits.TRISB1 = 0;
    TRISBbits.TRISB2 = 0;
    TRISBbits.TRISB3 = 0;
    TRISBbits.TRISB4 = 0;
    TRISBbits.TRISB5 = 0;
    
    // pushbutton pin as input
    TRISAbits.TRISA3 = 1;
    TRISAbits.TRISA2 = 1;
    TRISCbits.TRISC2 = 1;
}

void setup_timer(void)
{
    T0CONbits.TMR0ON = 0; // stop the timer
    T0CONbits.T08BIT = 0; // timer configured as 16-bit
    T0CONbits.T0CS = 0; // use system clock
    T0CONbits.PSA = 0; // use prescaler
    T0CONbits.T0PS = 0b111; // prescaler 1:256 ('0b' is a prefix for binary)    

    INTCONbits.T0IF = 0;
    INTCONbits.T0IE = 1;  // enable TMR0 interrupt generation
    
    TMR0 = TIME_1_SECONDO;
    
    T0CONbits.TMR0ON = 1; // start the timer    
}

void setup_adc(void)
{
    ANSELAbits.ANSA0 = 1; // RA0 = analog input --> AN0
    ANSELAbits.ANSA1 = 1; // RA1 = analog input --> AN1
    ADCON1bits.PVCFG = 0b00; // Positive reference = +VDD
    ADCON1bits.NVCFG = 0b00; // Negative reference = GND
    ADCON2bits.ADFM = 1; // format = right justified
    ADCON2bits.ACQT = 0b111; // acquisition time = 20*TAD
    ADCON2bits.ADCS = 0b110; // conversion clock = FOSC/64
    ADCON0bits.ADON = 1; // turn on ADC    
}

void setup_uart(void)
{
    // setup UART
    TRISCbits.TRISC6 = 0; // TX as output
    TRISCbits.TRISC7 = 1; // RX as input
    TXSTA1bits.SYNC = 0; // Async operation
    TXSTA1bits.TX9 = 0; // No tx of 9th bit
    TXSTA1bits.TXEN = 1; // Enable transmitter
    RCSTA1bits.RX9 = 0; // No rx of 9th bit
    RCSTA1bits.CREN = 1; // Enable receiver
    RCSTA1bits.SPEN = 1; // Enable serial port
    // Setting for 19200 BPS
    BAUDCON1bits.BRG16 = 0; // Divisor at 8 bit
    TXSTA1bits.BRGH = 0; // No high-speed baudrate
    SPBRG1 = 51; // divisor value for 19200
}

void putch(char c)
{
    while (TXSTA1bits.TRMT == 0) {}
    TXREG1 = c;
}


void interrupt isr(void)
{
    if (INTCONbits.T0IF == 1) {
        TMR0 = TIME_1_SECONDO;
        INTCONbits.T0IF = 0;
        
        ++counter;
        
        switch(stato) {
            case GIALLO:
                if (counter >= TG) {
                    counter = 0;
                    stato = ROSSO;
                }
                break;
            case ROSSO:
                if (counter >= TR) {
                    counter = 0;
                    stato = ATTESA;
                }
                break;
            case ATTESA:
                if (counter >= TS) {
                    counter = 0;
                    stato = VERDE;
                }
                break;
        }
        
    }
}

void display_leds(void)
{
    switch(stato) {
        case ATTESA:
        case VERDE:
            LATBbits.LATB4 = 0;
            LATBbits.LATB2 = 1;
            LATBbits.LATB0 = 1;
            break;
        case GIALLO:
            LATBbits.LATB4 = 1;
            LATBbits.LATB2 = 0;
            LATBbits.LATB0 = 1;
            break;
        case ROSSO:
            LATBbits.LATB4 = 1;
            LATBbits.LATB2 = 1;
            LATBbits.LATB0 = 0;
            break;
    }
}

void configurazione(void)
{
    for (;;) {
        if (PORTCbits.RC2 == 0)
            break;
        
        // lettura AN0
        ADCON0bits.CHS = 0;
        ADCON0bits.GODONE = 1;
        while (ADCON0bits.GODONE == 1) {}
        
        TR = 8 + ((20 - 8)*ADRES) / 1023;
        
        // lettura AN1
        ADCON0bits.CHS = 1;
        ADCON0bits.GODONE = 1;
        while (ADCON0bits.GODONE == 1) {}
        
        TS = (15*ADRES) / 1023;
        
        printf("TR = %d, TS = %d\n\r", TR, TS);
    }
    while (PORTCbits.RC2 == 0) {}
}

void main(void)
{
    setup_digital();
    setup_timer();
    setup_adc();
    setup_uart();

    RCONbits.IPEN = 0;  // no priorities
    INTCONbits.GIE = 1; // global interrupt enable
    INTCONbits.PEIE = 1; // interrupt enable from peripherals
    
    stato = VERDE;
    
    for (;;) {
        display_leds();
        printf("stato=%-6s, tempo=%2d\r", nomi_stato[stato], counter);
        if (stato == VERDE) {
            if (prenotazione == 1) {
                stato = GIALLO;
                counter = 0;
                prenotazione = 0;
            }
            else if (PORTAbits.RA3 == 0) {
                stato = GIALLO;
                counter = 0;
                while (PORTAbits.RA3 == 0) {}
            }
            else if (PORTAbits.RA2 == 0) {
                stato = GIALLO;
                counter = 0;
                while (PORTAbits.RA2 == 0) {}
            }
            else if (PORTCbits.RC2 == 0) {
                while (PORTCbits.RC2 == 0) {}
                configurazione();
            }
        }
        else if (stato == ATTESA) {
            if (PORTAbits.RA3 == 0) {
                prenotazione = 1;
                while (PORTAbits.RA3 == 0) {}
            }
            else if (PORTAbits.RA2 == 0) {
                prenotazione = 1;
                while (PORTAbits.RA2 == 0) {}
            }            
        }
    }

    return;
}
