#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
            
#include <stdlib.h>
#include <string.h>
#include "shutter.h"


/********************************** GLOBS ***********************************/


int32 motor_position;
int echo = 1;

//temp var for int_rtcc status
int status_bit = 0;

byte clock_ticks = 0;
byte seconds = 0;

#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;
    
    //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 clear_pos()
{
    clear_encoder();
    motor_position = 0;
}

void get_string(char* s, int max) 
{
    int len;
    char c;

    max--;
    len = 0;
    do 
    {
        c = getc();
        
        if (c == 8) // Backspace
        {  
            if (len > 0) 
            {
                len--;
                if (echo)
                {
                    putc(c);
                    putc(' ');
                    putc(c);
                }
            }
        } 
        else if ((c >= ' ') && (c <= '~'))
        {
            if (len < max) 
            {
                s[len++] = c;
                if (echo)
                    putc(c);
            }
        }
   } while(c != 13);
   
   s[len] = 0;

   if (echo)
       puts("\r\n");
}

void open_shutter()
{
    printf("open shutter\r\n");
    return;
}

void close_shutter()
{
    printf("close shutter\r\n");
    return;
}

int is_number(char* num_str)
{
    int is_num = 1;
    int i = 0;

    while (num_str[i] != 0)
    {
        if (!isamoung(num_str[i++],"+-0123456789"))
            is_num = 0;
    }

    return is_num;
}

void put_err(int err)
{
    
    //any action function should call put_err(0) upon success
    //or put_err(ERR_CODE) if there has been some sort of failure
    
    //if error is zero and there is no water alarm do nothing
    //if there is a water alarm and/or and error showit
    int flags;
    //have echo mode that adds LF    
    flags = 0;//get_flags();
    printf("_ERR %2X%2X\r\n", flags, err);
    return;

}


byte get_io_flags()
{
    return 0;
}


void toggle_echo()
{
    echo = !echo;
    return;
}

void move_shutter(char* param)
{
    long dist;

    
    if ( !is_number(param))
    {
        put_err(1);
        return;
    }

    if ( strlen(param) > 5)
    {
        put_err(2);
        return;
    }
    
    if ( param == 0 )
    {
        put_err(3);
        return;
    }

    dist = atol(param);
    
    printf("move shutter %ld\r\n", dist);
    return;
}

void set_stop_pos(char* param)
{
    long pos;
    
    if ( !is_number(param))
    {
        put_err(1);
        return;
    }

    if ( strlen(param) > 5)
    {
        put_err(2);
        return;
    }
    
    if ( param == 0 )
    {
        puts("using current position\r\n");
        return;
    }

    pos = atol(param);
    
    printf("setting stop to %ld\r\n", pos);
    return;
}


void get_stop_pos()
{
    puts("getting stop val\r\n");
    return;
}


#define CLOSE   0
#define OPEN    1

void jog_shutter(int dir)
{
    
    clear_pos();
    
    if ( dir == OPEN )
    {
        puts("jog open\r\n");
        //check for halt
        while (TRUE)
        {
            if ( kbhit() )
            {
                put_err(10);
                getc();
                break;
            }
            
            if ( motor_position != 0)
            {
                puts("stop due to encoder change\r\n");
                break;
            }
        }
    }
    else
    {
        puts("jog close\r\n");
        delay_ms(1500);
    }

    puts("done with jog\r\n");

    return;
}

void get_motor_pos()
{
    printf("motor_position = %ld\r\n", motor_position);
    return;
}

void show_io_flags()
{
    puts("show io flags\r\n");
    return;
}

void process_cmds()
{
    char *token; 
    char string[30];
    char cmd_str[15];
    char delim[2];

    strcpy(delim, " ");

    get_string(string, 30);
    
    if ( string[0] == 0 )
        return;
    
    //grab first token
    token = strtok(string, delim);
    
    /******************************** OPEN **********************************/
    strcpy(cmd_str, "OPEN");

    if ( stricmp(token, cmd_str) == 0 )
    {
        open_shutter();
        return;
    }
    
    /******************************** CLOSE *********************************/
    strcpy(cmd_str, "CLOSE");

    if ( stricmp(token, cmd_str) == 0 )
    {
        close_shutter();
        return;
    }
    
    /******************************** MOVE **********************************/
    strcpy(cmd_str, "MOVE");

    if ( stricmp(token, cmd_str) == 0 )
    {
        token = strtok(0, delim);
        //takes param
        move_shutter(token);
        return;
    }
    
    /****************************** SET_STOP ********************************/
    strcpy(cmd_str, "SET_STOP");

    if ( stricmp(token, cmd_str) == 0 )
    {
        token = strtok(0, delim);
        //takes param
        set_stop_pos(token);
        return;
    }
    
    /****************************** GET_STOP ********************************/
    strcpy(cmd_str, "GET_STOP");

    if ( stricmp(token, cmd_str) == 0 )
    {
        get_stop_pos();
        return;
    }
    
    /******************************** JOG_O *********************************/
    strcpy(cmd_str, "JOG_O");

    if ( stricmp(token, cmd_str) == 0 )
    {
        jog_shutter(OPEN);
        return;
    }

    /******************************** JOG_C *********************************/
    strcpy(cmd_str, "JOG_C");

    if ( stricmp(token, cmd_str) == 0 )
    {
        jog_shutter(CLOSE);
        return;
    }

    /******************************* GET_POS ********************************/
    strcpy(cmd_str, "GET_POS");

    if ( stricmp(token, cmd_str) == 0 )
    {
        get_motor_pos();
        return;
    }
    
    /***************************** GET_FLAGS ********************************/
    strcpy(cmd_str, "GET_FLAGS");

    if ( stricmp(token, cmd_str) == 0 )
    {
        show_io_flags();
        return;
    }
    
    /******************************** ECHO **********************************/
    strcpy(cmd_str, "ECHO");

    if ( stricmp(token, cmd_str) == 0 )
    {
        toggle_echo();
        return;
    }
    /****************************** END CMDS ********************************/

    printf("_ERR no command match\r\n");
    
    return;

}

main()   
{
    
    /* clear the motor position */
    clear_pos();
    /* 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);
        
    /* main loop */
    while(TRUE)
    {
        process_cmds();
        puts("RDY\r\n");
    }

}
