/*
 * File:   pluviometro.c
 * Author: Corrado
 *
 * Created on 28 novembre 2016, 9.59
 */


#include <xc.h>

char pioggia_on;
int valore_timer;
float livello_serbatoio, dimensione_goccia;

#define PERIOD_LOW  6250
#define PERIOD_HIGH 50000

#define GOCCIA_MIN 0.2
#define GOCCIA_MAX 5.0

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;
}

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
    
    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 interrupt isr(void)
{
    if (INTCONbits.T0IF == 1) {
        INTCONbits.T0IF = 0;
        TMR0H = valore_timer >> 8;
        TMR0L = valore_timer & 0xff;        
        if (pioggia_on == 1) {
            LATBbits.LATB5 = !LATBbits.LATB5;
            livello_serbatoio += dimensione_goccia;
            if (livello_serbatoio > 30) {
                livello_serbatoio = 0;
            }
        }
    }
}

void show_tank_level(void)
{
    if (livello_serbatoio < 10) {
        LATBbits.LATB0 = 1;
        LATBbits.LATB1 = 1;
        LATBbits.LATB2 = 1;
        LATBbits.LATB3 = 1;
    }
    else if (livello_serbatoio >= 10 && livello_serbatoio < 15) {
        LATBbits.LATB0 = 1;
        LATBbits.LATB1 = 1;
        LATBbits.LATB2 = 1;
        LATBbits.LATB3 = 0;        
    }
    else if (livello_serbatoio >= 15 && livello_serbatoio < 20) {
        LATBbits.LATB0 = 1;
        LATBbits.LATB1 = 1;
        LATBbits.LATB2 = 0;
        LATBbits.LATB3 = 0;        
    }
    else if (livello_serbatoio >= 20 && livello_serbatoio < 25) {
        LATBbits.LATB0 = 1;
        LATBbits.LATB1 = 0;
        LATBbits.LATB2 = 0;
        LATBbits.LATB3 = 0;        
    }
    else {
        LATBbits.LATB0 = 0;
        LATBbits.LATB1 = 0;
        LATBbits.LATB2 = 0;
        LATBbits.LATB3 = 0;                
    }
}

void main(void) 
{
    int current_adc_channel;
    
    setup_digital();
    setup_timer();
    setup_adc();
    
    RCONbits.IPEN = 0;  // no priorities
    INTCONbits.GIE = 1; // global interrupt enable
    INTCONbits.PEIE = 1; // interrupt enable from peripherals

    pioggia_on = 0;
    livello_serbatoio = 0;
    dimensione_goccia = 0.2;

    ADCON0bits.CHS = 0;
    current_adc_channel = 0;
    
    ADCON0bits.GODONE = 1;
    for (;;) {
    
        show_tank_level();
        
        if (PORTAbits.RA3 == 0) {
            pioggia_on = !pioggia_on;
            while (PORTAbits.RA3 == 0) {}
        }
        
        if (ADCON0bits.GODONE == 0) {
            if (current_adc_channel == 0) {
                int adc_value = ADRES;
                int period = PERIOD_LOW + adc_value * ((PERIOD_HIGH - PERIOD_LOW) / 1024);
                valore_timer = -period;
                current_adc_channel = 1;
            }
            else { // channel 1
                // gestiamo la dimensione della pioggia
                int adc_value = ADRES;
                dimensione_goccia = GOCCIA_MIN + adc_value * ((GOCCIA_MAX - GOCCIA_MIN) / 1024);
                current_adc_channel = 0;
            }
            ADCON0bits.CHS = current_adc_channel;
            ADCON0bits.GODONE = 1;
        }
    }
            
    return;
}
