#if defined(__PCM__)
#include <16f877.h>
#device ICD=TRUE
#fuses XT,NOWDT,NOPROTECT,PUT,BROWNOUT
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use standard_io(A)
#use standard_io(B)
#use standard_io(D)
#use standard_io(E)

#endif

#include <stdlib.h>
#include <string.h>

/********************************** 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;

//#define TICKS_PER_SEC   61
#define TICKS_PER_SEC   244

int clock_ticks = TICKS_PER_SEC;
int seconds = 0;
int echo = 0;
/********************************** GLOBS ***********************************/

int read_encoder()
{
    int encoder_val;
    //assert read signal
    output_bit(PIN_E1, 0);
    //read encoder
    encoder_val = input_d();
    //de-assert read signal
    output_bit(PIN_E1, 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;
        clock_ticks = TICKS_PER_SEC;
    }
}

void clear_pos()
{
    clear_encoder();
    motor_position = 0;
}

void clear_timer()
{
    set_rtcc(0);
    clock_ticks = TICKS_PER_SEC;
    seconds = 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 read_in_ports()
{
   int line_count = 0;

   puts("start reading ports\r\n");
   //check for halt
   while (TRUE)
   {
      if ( kbhit() )
      {
         getc();
         break;
      }

      printf("port b = 0x%02X    port d = 0x%02X ", input_b(), input_d());
      if ( !(++line_count%10) )
         puts(" +");
      else
         puts(" ");

      delay_ms(200);
   }

    puts("done reading ports\r\n");

    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)
{

   if ( dir == OPEN )
   {

      output_bit(PIN_C1, 1);
      output_bit(PIN_A4, 1);
      output_bit(PIN_C2, 0);
      output_bit(PIN_A5, 0);
   }
   else
   {
      output_bit(PIN_C1, 0);
      output_bit(PIN_A4, 0);
      output_bit(PIN_C2, 1);
      output_bit(PIN_A5, 1);
   }

   while (TRUE)
   {
      if ( kbhit() )
      {
         getc();
         printf("halted by keystroke\r\n");
         break;
      }

      if ( !input(PIN_B4) || !input(PIN_B5) )
      {
         printf("halted by hall sensor\r\n");
         break;
      }

      printf("motor_position = %ld\r\n", motor_position);

   }

      output_bit(PIN_C1, 0);
      output_bit(PIN_A4, 0);
      output_bit(PIN_C2, 0);
      output_bit(PIN_A5, 0);

    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;
    }


    /******************************* CLR_POS ********************************/
    strcpy(cmd_str, "CLR_POS");

    if ( stricmp(token, cmd_str) == 0 )
    {
        clear_pos();
        printf("position cleared\r\n");
        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;
    }
    /******************************** IN_PORTS ******************************/
    strcpy(cmd_str, "IN_PORTS");

    if ( stricmp(token, cmd_str) == 0 )
    {
        read_in_ports();
        return;
    }
    /****************************** END CMDS ********************************/

    printf("_ERR no command match\r\n");

    return;

}

main()
{
    /* clear the motor position */
    clear_pos();

    /* for jog function */
    output_bit(PIN_C1, 0);
    output_bit(PIN_A4, 0);
    output_bit(PIN_C2, 0);
    output_bit(PIN_A5, 0);


//    set_tris_a(0x00);
//    write_bank(1,0x9F, 0xFF);


    /* initialize RTCC */
    clock_ticks = TICKS_PER_SEC;
    set_rtcc(0);
    setup_counters( RTCC_INTERNAL, RTCC_DIV_16);
    enable_interrupts(INT_RTCC);
    enable_interrupts(GLOBAL);

//    setup_adc_ports(NO_ANALOGS);

    /* main loop */
    while(TRUE)
    {
        process_cmds();
        puts("RDY\r\n");
    }
}
