#if defined(__PCM__)
#include <16f877.h>
#device ICD=TRUE
#device ADC=10
#fuses XT,NOWDT,NOPROTECT,PUT,BROWNOUT
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#endif
            
/********************************** GLOBS ***********************************/


int32 motor_position;

/*
   The motor_moving var is set to true if at least one encoder count was
   read at sample time, otherwise it is false.
*/

int motor_moving;

int dir_state = 0;
int pwm_state = 0;
int run_state = 0;

//temp var for int_rtcc status
int status_bit = 0;

byte clock_ticks = 0;
byte seconds = 0;

//#define TICKS_PER_SEC   61
#define TICKS_PER_SEC   244

/********************************** GLOBS ***********************************/

int read_encoder()
{
    int encoder_val;    
    //assert read signal
    output_bit(PIN_E0, 0);
    //read encoder
    encoder_val = input_d();
    //de-assert read signal
    output_bit(PIN_E0, 1);
    return encoder_val;    
}

void clear_encoder()
{
    //use PSP CS for now
    
    //assert clear signal
    output_bit(PIN_E2, 0);
    //de-assert clear signal
    output_bit(PIN_E2, 1);
}

#INT_RTCC
clock_isr() 
{
    // Update the actual position. This assumes that the position sensor is
    // an 8 bit device and the actual position is 32 bits. The following
    // code converts from 8 bit to 32 bit and handles roll-overs.
/*    
    motor_position += (read_encoder() - ((int8)motor_position));
*/
    int8 old_encoder;
    int8 cur_encoder;
    int8 encoder_delta;

    cur_encoder = read_encoder();
    old_encoder = (int8)motor_position; // get the lower 8 bits of the motor position
    encoder_delta = cur_encoder - old_encoder;
    
    if ( encoder_delta & 0xFF )
        motor_moving = TRUE;
    else
        motor_moving = FALSE;
    
    //compiler is having trouble mixing 8 and 32 bit types
    if ( encoder_delta & 0x80 )
        motor_position -= (~encoder_delta + 0x01);
    else
        motor_position += encoder_delta;
    
    if ( (--clock_ticks) == 0 ) 
    {
        ++seconds;
        //debug toggle of pin C0 for int_rtcc status
        status_bit = !status_bit;
        output_bit(PIN_C0, status_bit);

        clock_ticks = TICKS_PER_SEC;
    }
}

void clear_timer()
{
    set_rtcc(0);
    clock_ticks = TICKS_PER_SEC;    
    seconds = 0;
}

void show_version()
{
    printf("Smart Shutter v 0.4\r\n");
    printf("built on ");
    printf(__DATE__);
    printf("\r\n\n");
}

void get_motor_pos()
{
    long value = 0;
    
    value = read_adc();
    printf("adc value = %ld\r\n", value);
}

void toggle_direction()
{
    dir_state = !dir_state;
    output_bit(PIN_B5, dir_state);
}

void toggle_pwm()
{
    pwm_state = !pwm_state;
    output_bit(PIN_C2, pwm_state);
}

void toggle_run_sense()
{
    run_state = !run_state;
    output_bit(PIN_B4, run_state);
}

void show_io_state()
{
    printf("--------------\r\n");
    printf("dir_state = %d\r\n", dir_state);
    printf("pwm_state = %d\r\n", pwm_state);
    printf("run_state = %d\r\n", run_state);
    printf("--------------\r\n");
}

#define OPEN_POS 800
#define CLOSE_POS 200
#define TIME_OUT 4

void run_shutter(int val)
{
    if ( val == 0 )
    {
        /* if shutter is closed get out */
        if ( read_adc() < CLOSE_POS )
            return;
        
        /* set direction to close */
        dir_state = 0;
        output_bit(PIN_B5, dir_state);
        /* start shutter motor */
        output_bit(PIN_B4, 1);
        delay_ms(20);
        output_float(PIN_B4);
        
        /* clear system timer as shutter open and close is timed */
        clear_timer();

        while (read_adc() > CLOSE_POS)
        {
            /*wait for shutter to close*/
            if ( seconds > (TIME_OUT - 1) )
            {
                printf("\r\n_err shutter close timed out\r\n");
                /* stop shutter motor */
                output_bit(PIN_B4, 0);
                break;
            }

            if ( !input(PIN_B4) )
            {
                /* set run_sense low */
                output_bit(PIN_B4, 0);
                printf("\r\n_err shutter close current trip\r\n");
                break;
            }
        }
        
        /* stop shutter motor */
        output_bit(PIN_B4, 0);

    }
    else
    {
        
        /* if shutter is opened get out */
        if ( read_adc() > OPEN_POS )
            return;
        
        /* set direction to open */
        dir_state = 1;
        output_bit(PIN_B5, dir_state);
        /* start shutter motor */
        output_bit(PIN_B4, 1);
        delay_ms(20);
        output_float(PIN_B4);
        
        /* clear system timer as shutter open and close is timed */
        clear_timer();
        
        while (read_adc() < OPEN_POS)
        {
            /*wait for shutter to close*/
            if ( seconds > (TIME_OUT - 1) )
            {
                printf("\r\n_err shutter open timed out\r\n");
                /* stop shutter motor */
                output_bit(PIN_B4, 0);
                break;
            }

            if ( !input(PIN_B4) )
            {
                /* set run_sense low */
                output_bit(PIN_B4, 0);
                printf("\r\n_err shutter open current trip\r\n");
                break;
            }

        }
        
        /* stop shutter motor */
        output_bit(PIN_B4, 0);
    }
}

void store_position()
{
    long value;

    value = read_adc();
//    value = read_encoder();
    printf("storing adc value = %ld\r\n", value);

    /* store MSB of value */
    write_eeprom(0, make8(value, 1));
    /* store LSB of value */
    write_eeprom(1, make8(value, 0));
}

void read_position()
{
    long value;

    value = make16(read_eeprom(0), read_eeprom(1));
    
    printf("read value = %ld from eeprom\r\n", value);
}

void motor_pos()
{
    // Update the actual position. This assumes that the position sensor is
    // an 8 bit device and the actual position is 32 bits. The following
    // code converts from 8 bit to 32 bit and handles roll-overs.
/*    
    motor_position += (read_encoder() - ((int8)motor_position));
*/

/*
    int8 old_encoder;
    int8 cur_encoder;
    int8 encoder_delta;

    cur_encoder = read_encoder();
    old_encoder = (int8)motor_position; // get the lower 8 bits of the motor position
    encoder_delta = cur_encoder - old_encoder;
    
    puts("------------------------------------- 4\r\n");
    printf("cur_encoder   = %X %d\r\n", cur_encoder, cur_encoder);
    printf("old_encoder   = %X %d\r\n", old_encoder, old_encoder);
    printf("encoder_delta = %X %d\r\n", encoder_delta, encoder_delta);

    //compiler is having trouble mixing 8 and 32 bit types
    if (encoder_delta & 0x80)
    {
        puts("encoder_delta minus\r\n");
        motor_position -= (~encoder_delta + 0x01);

    }
    else
    {
        puts("encoder_delta plus\r\n");
        motor_position += encoder_delta;

    }

*/
    printf("motor_position = %ld\r\n", motor_position);
}

void encoder_pos()
{
    printf("encoder position = %u\r\n", read_encoder());
}

void clear_pos()
{
    clear_encoder();
    motor_position = 0;
}

void loop_read_pos()
{
    while ( !kbhit() )
    {
        printf("motor_position = 0x%Lx\r", motor_position);
        delay_ms(200);
    }
}

void calc_encoder_cps()
{
    int32 encoder_cps;
    
    /* start motor */
    dir_state = 0;
    run_state = 1;
    output_bit(PIN_B5, dir_state);
    output_bit(PIN_B4, run_state);

    /* delay for a bit to let motor reach slew */
    delay_ms(500);

    /* clear the encoder */
    clear_pos();

    /* sample for 1 sec */
    delay_ms(1000);

    /* read motor position */
    encoder_cps = motor_position;

    /* stop the motor */
    run_state = 0;
    output_bit(PIN_B4, run_state);
    
    /* display results */
    printf("encoder cps = %ld\r\n", encoder_cps);

}

void get_motor_moving()
{
    if ( motor_moving )
        puts("motor moving : true");
    else
        puts("motor moving : false");
}

void show_help()
{
    printf("1 - get the motor position\r\n");
    printf("2 - toggle pwm (RC2)\r\n");
    printf("3 - toggle direction (RB5)\r\n");
    printf("4 - toggle run/sense (RB4)\r\n");
    printf("5 - show I/O state\r\n");
    printf("6 - open shutter\r\n");
    printf("7 - close shutter\r\n");
    printf("8 - store position\r\n");
    printf("9 - read position\r\n");
    printf("0 - motor position\r\n");
    printf("a - encoder position\r\n");
    printf("b - clear encoder\r\n");
    printf("c - loopenzy read motor\r\n");
    printf("d - calc encoder cps\r\n");
    printf("e - is motor moving\r\n");
    printf("? - show this menu\r\n");
}

main()   
{
    char c;
    
    /* initialize I/O */
    dir_state = 0;
    pwm_state = 0;
    run_state = 0;
    
    /* clear the motor position */
    clear_pos();

    output_bit(PIN_B5, dir_state);
    output_bit(PIN_C2, pwm_state);
    output_bit(PIN_B4, run_state);
    
    /* initialize RTCC */
    clock_ticks = TICKS_PER_SEC;    
    set_rtcc(0);
//    setup_counters( RTCC_INTERNAL, RTCC_DIV_64);
    setup_counters( RTCC_INTERNAL, RTCC_DIV_16);
    enable_interrupts(INT_RTCC);
    enable_interrupts(GLOBAL);
    
    /* initialize A2D */
    setup_port_a(RA0_RA1_RA3_ANALOG);
    setup_adc(ADC_CLOCK_INTERNAL);
    set_adc_channel(0);
       
    /* show version and help menu */
    show_version();
    show_help();
    /* main loop */
    while(TRUE)
    {
        c = getc();

        switch (c)
        {
            case '1' : get_motor_pos();     break;
            case '2' : toggle_pwm();        break;
            case '3' : toggle_direction();  break;
            case '4' : toggle_run_sense();  break;
            case '5' : show_io_state();     break;
            case '6' : run_shutter(1);      break;
            case '7' : run_shutter(0);      break;
            case '8' : store_position();    break;
            case '9' : read_position();     break;
            case '0' : motor_pos();         break;
            case 'a' : encoder_pos();       break;
            case 'b' : clear_pos();         break;
            case 'c' : loop_read_pos();     break;
            case 'd' : calc_encoder_cps();  break;
            case 'e' : get_motor_moving();  break;
            case '?' : show_help();         break;
            default: printf("invalid selection\r\n");
        }
    }
}
