/* 
 * File:   dimmer_led_3_interrupt_uart_2.c
 * Author: corrado
 */

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

unsigned char TIME_ON[] =  { 5,   10,  20,  50, 100, 250};
unsigned char TIME_OFF[] = {250, 245, 235, 205, 155,   5};

#define OFF   0
#define ON    1

#define FLASH_INTERVAL  -15625

char pwm_state, led_state, flashing_state, duty;

void interrupt isr()
{
    if (PIR1bits.TMR2IF == 1) { // period match
        if (led_state == ON) {
            if (pwm_state == OFF) {
                LATBbits.LATB0 = 0; // led on
                PR2 = TIME_ON[duty]; // load period register
                pwm_state = ON;
            }
            else {
                LATBbits.LATB0 = 1; // led off
                PR2 = TIME_OFF[duty]; // load period register
                pwm_state = OFF;
            }
        }
        else {
            LATBbits.LATB0 = 1; // led off
            PR2 = TIME_OFF[duty]; // load period register
            pwm_state = OFF;
        }
        PIR1bits.TMR2IF = 0; // reset interrupt flag
    }
    if (INTCONbits.T0IF == 1) {
        TMR0 = FLASH_INTERVAL;
        if (flashing_state == ON)
            led_state = !led_state;
        else
            led_state = ON;
        INTCONbits.T0IF = 0;
    }
}

void putch(char c) {
    // wait the end of transmission
    while (TXSTA1bits.TRMT == 0) {};
    TXREG1 = c; // send the new byte
}

char read_char(void)
{
    while (PIR1bits.RC1IF == 0) {
        if (RCSTA1bits.OERR == 1) {
            RCSTA1bits.OERR = 0;
            RCSTA1bits.CREN = 0;
            RCSTA1bits.CREN = 1;
        }
    }
    return RCREG1;
}

void read_line(char * s, int max_len)
{
    int i = 0;
    for(;;) {
        char c = read_char();
        if (c == 13) {
            putchar(c);
            putchar(10);
            s[i] = 0;
            return;
        }
        else if (c == 8) {
            if (i > 0) {
                putchar(c);
                putchar(' ');
                putchar(c);
                --i;
            }
        }
        else if (c >= 32) {
            if (i < max_len) {
                putchar(c);
                s[i] = c;
                ++i;
            }
        }
    }
}

#define MAX_TOKENS  20

int main(int argc, char** argv) {

    char line[81];
    int num_of_tokens;
    char *tokens[MAX_TOKENS];

    TRISAbits.RA3 = 1;
    TRISAbits.RA2 = 1;

    TRISBbits.TRISB0 = 0; // output
    TRISBbits.TRISB1 = 0; // output
    TRISBbits.TRISB2 = 0; // output
    TRISBbits.TRISB3 = 0; // output
    TRISBbits.TRISB4 = 0; // output
    TRISBbits.TRISB5 = 0; // output

    duty = 0;
    led_state = OFF;
    flashing_state = OFF;

    // 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.RC9 = 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

    PIE1bits.TX1IE = 0; // disable TX hardware interrupt
    PIE1bits.RC1IE = 0; // disable RX hardware interrupt
    
    T2CONbits.TMR2ON = 0; // stop the timer
    T2CONbits.T2CKPS = 0b10; // 1:16 prescaler
    T2CONbits.T2OUTPS = 0b0000; // no postscaler
    TMR2 = 0; // reset timer
    PR2 = TIME_OFF[duty]; // load period register
    PIR1bits.TMR2IF = 0; // reset interrupt flag
    pwm_state = OFF;

    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)
    TMR0 = FLASH_INTERVAL; // initial timer value
    INTCONbits.T0IF = 0; // clear the overflow bit initially


    INTCONbits.GIE = 1; // global enable interrupts
    INTCONbits.PEIE = 1; // peripheral enable interrupts
    RCONbits.IPEN = 0; // no priorities

    INTCONbits.T0IE = 1; // enable interrupt on TMR0
    PIE1bits.TMR2IE = 1; // enable interrupt on TMR2

    T0CONbits.TMR0ON = 1; // start the timer 0
    T2CONbits.TMR2ON = 1; // start the timer 2

    LATB = 0xff; // all leds off

    for (;;) {
        printf("LED>");
        read_line(line, 80);

        num_of_tokens = 0;
        tokens[num_of_tokens] = strtok(line, " ");
        while (tokens[num_of_tokens] != NULL) {
            ++num_of_tokens;
            tokens[num_of_tokens] = strtok(NULL, " ");
        }

        if (num_of_tokens == 0)
            continue;

        if (!strcmp(tokens[0],"flash")) {
            if (num_of_tokens >= 2) {
                if (!strcmp(tokens[1], "on")) {
                    flashing_state = 1;
                    printf("Activating flash\n\r");
                }
                else if (!strcmp(tokens[1], "off")) {
                    flashing_state = 0;
                    printf("Deactivating flash\n\r");
                }
                else
                    printf("flash: invalid parameter\n\r");
            }
            else
                printf("flash: invalid parameter\n\r");
        }
        else if (!strcmp(tokens[0],"up")) {
            if (duty < 5)
                duty++;
            printf("Duty set at %d\n\r", duty);
        }
        else if (!strcmp(tokens[0],"down")) {
            if (duty > 0)
                duty--;
            printf("Duty set at %d\n\r", duty);
        }
        else if (!strcmp(tokens[0],"show")) {
            if (num_of_tokens >= 2) {
                int index = atoi(tokens[1]);
                if (index >= 0 && index <= 5)
                    printf("INDEX %d, TIME_ON %d, TIME_OFF %d\n\r",
                            index, TIME_ON[index], TIME_OFF[index]);
                else
                    printf("show: invalid parameter range\n\r");
            }
            else
                printf("show: invalid parameter\n\r");
        }
        else {
            printf("Invalid command\n\r");
        }
    }
    return (EXIT_SUCCESS);
}

