/*
 * Digital Capacitor ESR Tester V4.0
 * Copyright (c) 2009, Regulus Berdin
 * All rights reserved. 
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT.  IN NO EVENT SHALL REGULUS BERDIN BE LIABLE FOR
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
*/ 

//Comment next line for actual hardware
//#define SIMULATION


#define R1_VALUE            (6.8)
#define SIM_ZERO_READING    (2329.0)
#define ROW_ESR             3


#include <16F876.h>

#device adc=10

#FUSES NOWDT, HS, NOPUT, NOPROTECT, NOBROWNOUT, NOLVP, NOCPD, NOWRT, NODEBUG
#use delay(clock=20M)

#use fast_io(a)
#use fast_io(b)
#use fast_io(c)


#define BUZZERP_MASK    (1<<0)
#define BUZZERN_MASK    (1<<1)


#define nok_sclk  pin_b4
#define nok_sda   pin_b2
#define nok_dc    pin_b3
#define nok_cs    pin_b1
#define nok_res   pin_b0

#include "3310_2.c"

float rx, fvo;
float curr = SIM_ZERO_READING/R1_VALUE;
unsigned int8 digit[3], dp, beep=0, buz_pol=0, portc_sh=0, bad_blink=0;


#int_timer0
void tmr0_isr(void)
{
    set_timer0(255 - 155);  //4khz

    if (beep)
    {
        buz_pol ^= 1;
        portc_sh = ~(BUZZERP_MASK | BUZZERN_MASK);
        if (buz_pol)
        {
            portc_sh |= BUZZERP_MASK;
        }
        else
        {
            portc_sh |= BUZZERN_MASK;
        }
        output_c(portc_sh);        
    }
    else
    {
        portc_sh = ~(BUZZERP_MASK | BUZZERN_MASK);
        output_c(portc_sh);
    }
}


void show_status(void)
{
    nokia_gotoxy(18,5);
    printf(nokia_printchar, "        ");
    
    if (rx < 1.05)
    {
        nokia_gotoxy(30,5);
        printf(nokia_printchar, "GOOD");
        beep = 1;
        bad_blink = 0;
    }
    else if (rx < 5.05)
    {
        nokia_gotoxy(30,5);
        printf(nokia_printchar, "GOOD");
        beep = 0;
        bad_blink = 0;
    }
    else if (rx < 15.05)
    {
        if (bad_blink<2)
        {
            nokia_gotoxy(18,5);
            printf(nokia_printchar, "CRITICAL");
        }
        beep = 0;
        ++bad_blink;
        bad_blink &= 3;
    }
    else
    {
        if (bad_blink<2)
        {
            nokia_gotoxy(33,5);
            printf(nokia_printchar, "BAD");
        }
        beep = 0;
        ++bad_blink;
        bad_blink &= 3;
    }
}



unsigned int16 get_sample(void)
{
    unsigned int16 t = 0;
    unsigned int8 i;
    
    for (i=0;i<64;++i)
    {
        delay_us(25);
        t+=read_adc();
    }
    return t;
}


void show_esr(void)
{
    unsigned int8 i, col;
    unsigned int16 c1;
    float t;

    if (rx>=99.0)
    {
        digit[0] = 9;
        digit[1] = 9;
        digit[2] = 9;
        dp = 1;
    }
    else if (rx<0.0)
    {
        digit[0] = 0;
        digit[1] = 0;
        digit[2] = 0;
        dp = 0;
    }
    else if (rx<10.0)
    {
        t = (rx + 0.005) * 100.0; //round
        c1 = t;
        
        digit[2] = c1 % 10;
        c1 -= digit[2];
        
        c1 /= 10;
        digit[1] = c1 % 10;
        c1 -= digit[1];
        
        c1 /= 10;
        digit[0] = c1;
        
        dp = 0;
    }
    else
    {
        t = (rx + 0.05) * 10.0; //round
        c1 = t;
        
        digit[2] = c1 % 10;
        c1 -= digit[2];
        
        c1 /= 10;
        digit[1] = c1 % 10;
        c1 -= digit[1];
        
        c1 /= 10;
        digit[0] = c1;
        
        dp = 1;
    }

    //erase
    for (i=0;i<2;++i)
    {
        nokia_gotoxy(20, i + ROW_ESR-1);
        printf(nokia_printchar, "       ");
    }

    col = 20;
    for (i=0;i<3;++i)
    {
        display_digit(ROW_ESR, col, digit[i]);
        col += 14;
        if (i==dp)
        {
            col -= 3;
            nokia_gotoxy(col++,ROW_ESR);
            nokia_write_data(0xE0);
            nokia_gotoxy(col++,ROW_ESR);
            nokia_write_data(0xE0);
            nokia_gotoxy(col++,ROW_ESR);
            nokia_write_data(0xE0);
            col+=4;
        }
    }
}


void main(void)
{
    unsigned int8 i;
    
    port_b_pullups(0);
    set_tris_b(0x00);
    output_b(0xFF);
    
    set_tris_c(0x00);
    portc_sh = 0;
    output_c(portc_sh);
    
    set_tris_a(0x01 | (1<<3));
    output_a(0);

    setup_adc_ports(AN0_AN1_VSS_VREF);
    setup_adc(ADC_CLOCK_DIV_32);
    set_adc_channel(0);
    
    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_4);
    set_timer0(255 - 155);  //8KHz
   
    nokia_init();

    nokia_gotoxy(3,0); printf(nokia_printchar, "DigiESR Meter");
    nokia_gotoxy(0,1); printf(nokia_printchar, " by: zer0w1ng ");
    nokia_gotoxy(0,2); printf(nokia_printchar, "   and Rafft  ");
    nokia_gotoxy(0,3); printf(nokia_printchar, "--------------");
    nokia_gotoxy(3,4); printf(nokia_printchar, "Short circuit");
    nokia_gotoxy(3,5); printf(nokia_printchar, " probes now. ");

    delay_ms(5000);

    nokia_clear_screen();
    nokia_gotoxy(3,0); printf(nokia_printchar, "DigiESR Meter");
    nokia_gotoxy(9,2); printf(nokia_printchar, "CALIBRATING");
    nokia_gotoxy(6,4); printf(nokia_printchar, "Please wait.");

    enable_interrupts(INT_TIMER0);
    enable_interrupts(GLOBAL);

#ifndef SIMULATION    

    setup_ccp1(CCP_PWM);
    set_pwm1_duty(5);
    setup_timer_2(T2_DIV_BY_1, 10, 1);


    //initial settling delay before calibration
    delay_ms(3000);

    /* Calibration */
    fvo = 0;
    for (i=0;i<128;++i)
    {
        fvo += get_sample();
    }
    curr = fvo/R1_VALUE/128.0;
    //printf("Cal vo=%g curr=%g\r\n", fvo, curr);

#else

    delay_ms(3000);

    setup_ccp1(CCP_PWM);
    set_pwm1_duty(50);
    setup_timer_2(T2_DIV_BY_1, 100, 1);

#endif    

    nokia_clear_screen();
    
    nokia_gotoxy(3,0);
    printf(nokia_printchar, "DigiESR Meter");
    
    //rx = -1.0;
    
    for(;;)
    {
        fvo = get_sample();
        rx = fvo/curr - R1_VALUE;
        
        //rx = 6.51;

        show_esr();
        show_status();
        
#ifndef SIMULATION    
        delay_ms(200);
#else
        delay_ms(10);
#endif
        
    }
}