/* BCLIB.C */

#include "bcsys.h"


/************************************************
	 MOTOR FUNCTIONS
************************************************/

int move_purge_mot(char direction)  {

  switch(direction) {
    case 'o':
      TPUSetPin(7, 1);
      TPUSetPin(8, 0);
      break;
    case 'c':
      TPUSetPin(8, 1);
      TPUSetPin(7, 0);
      break;
    case 's':
      TPUSetPin(7, 0);
      TPUSetPin(8, 0);
      break;
  }
  return(0);
}

/*************************************/

int move_slide_mot(char direction)  {

  switch(direction) {
    case 'a':
      TPUSetPin(9, 1);
      TPUSetPin(10, 0);
      break;
    case 'c':
      TPUSetPin(10, 1);
      TPUSetPin(9, 0);
      break;
    case 's':
      TPUSetPin(9, 0);
      TPUSetPin(10, 0);
      break;
  }
  return(0);
}

/*************************************/

int purge_valve(char direction){
  int errcode = 0, last_purge_ticks = 0;
  long start_time, jam_time;

#ifdef __TURBOC__
  if(direction == OPEN)
    printf("\nPurge valve opening");
  else
    printf("\nPurge valve closing");
#endif

  SimSetFSys(16e6);
  SerSetBaud(9600, 0);
  sensor_pwr_on();
  delaysecs(1);

  start_time = MilliSecs();     /* Start time for timeout */
  jam_time = start_time;
  tpurupt(PURGE_TURNS_CHAN, ON);         /* Turn on interrupt */
  g_purge_ticks = 0;

#ifdef __TURBOC__
  g_purge_ticks++;  /* Avoids a jam error on first loop */
#endif

  if( direction == OPEN && !purge_limit() ) move_purge_mot('o');
  else if(direction == CLOSE) move_purge_mot('c');

	    /* Purge valve main loop */
  while(1){

	    /* Is the purge valve there? */
    if(direction == OPEN){
      if( purge_limit() ) break;
    }
    else{
      if( g_purge_ticks > PURGE_CLOSED_POS ) break;
    }

       /* Check for Jam Error */
    if( timer(jam_time, JAM_TIMEOUT) ){

      if( g_purge_ticks == last_purge_ticks ){   /* Leadscrew turning? */
	errcode = PURGE_JAM_ERR;
	break;
      }
      else last_purge_ticks = g_purge_ticks;     /* If yes, reset counters */
      jam_time = MilliSecs();

    }  /* End of jam IF statement */

#ifdef __TURBOC__
      g_purge_ticks += 10;   /* Simulate shaft turning */
#endif


	      /* Too much time? */
    if(timer_min(start_time, PURGE_TIMEOUT)){
      errcode = PURGE_TIMEOUT_ERR;
      break;
    }

  }   /* End of purge valve loop */

  move_purge_mot('s');              /* Purge valve is there--hopefully */
  tpurupt(PURGE_TURNS_CHAN, OFF);

  if(errcode){
    store_data(errcode); 
    printf("\nPurge valve error: %hd\n", errcode);
  }

  SimSetFSys(320000);
  SerSetBaud(9600, 0);
  sensor_pwr_off();


  return errcode;
}


/************************************************/

int slide_valve(char direction){
  int errcode = 0, last_slide_ticks = 0;
  long start_time, jam_time;

#ifdef __TURBOC__
  if(direction == AMBIENT)
    printf("\nSlide valve to ambient");
  else
    printf("\nSlide valve to chamber");
#endif
  SimSetFSys(16e6);
  SerSetBaud(9600, 0);
  sensor_pwr_on();
  delaysecs(1);

  start_time = MilliSecs();     /* Start time for timeout */
  jam_time = start_time;
  tpurupt(SLIDE_TURNS_CHAN, ON);         /* Turn on interrupt */
  g_slide_ticks = 0;

#ifdef __TURBOC__
  g_slide_ticks++;  /* Avoids a jam error on first loop */
#endif

  if( direction == AMBIENT && !slide_limit() ) move_slide_mot('a');
  else if(direction == CHAMBER) move_slide_mot('c');

  while(1){        /* Main loop */

	    /* Is the slide valve there? */
    if(direction == AMBIENT){
      if( slide_limit() ) break;
    }
    else{
      if( g_slide_ticks > SLIDE_CHAMBER_POS ) break;
    }

	    /* Check for Jam Error */
    if( timer(jam_time, JAM_TIMEOUT) ){
	    
      if( g_slide_ticks == last_slide_ticks ){  /* Leadscrew turning? */
	errcode = SLIDE_JAM_ERR;
	break;
      }
      else last_slide_ticks = g_slide_ticks;    /* If so, reset counters */
      jam_time = MilliSecs();
    }

#ifdef __TURBOC__
    g_slide_ticks += 10;   /* Simulate shaft turning */
#endif

	      /* Too much time? */
    if(timer_min(start_time, SLIDE_TIMEOUT)){
      errcode = SLIDE_TIMEOUT_ERR;
      break;
    }

  }   /* End of Slide Valve loop */

  move_slide_mot('s');              /* Slide valve is there--hopefully */
  tpurupt(SLIDE_TURNS_CHAN, OFF);

  if(errcode){
    store_data(errcode);          
    printf("\nSlide valve error: %hd\n", errcode);
  }

  SimSetFSys(320000);
  SerSetBaud(9600, 0);
  sensor_pwr_off();


  return errcode;
}

/****************************************************/

void stir_motor(char on_off){
  unsigned stir_period;

  if(g_stir_speed == 0){                 /* Avoids a divide-by-zero error */
    printf("\nStir speed = 0. Changed to 10 RPM\n");
    g_stir_speed = 10;
  }

  if(on_off == ON){
    stir_period = TPUGetTCR1()/(g_stir_speed*200/60);   /* Convert to TCR counts */
    PClear(E,5);                    /* Stir motor power on */

#ifdef AZTEC_C
    TPUSetupPWM(STIR_SPEED_CHAN, stir_period/2, stir_period, LowPrior);
#endif

    tpurupt(STIR_TURNS_CHAN, ON);
  }
  else if(on_off == OFF){
    TPUSetPin(0, 1);
    tpurupt(STIR_TURNS_CHAN, OFF);
    PSet(E,5);                      /* Stir motor power off */
  }
  else printf("\nStir motor command error\n");
}

/*********************************************
	    Misc. Functions
*********************************************/

int timer(ulong starttime, ulong maxtime){
  ulong timediff;

/*
*   starttime is absolute time from RTC in milliseconds.
*   maxtime is the timeout period in milliseconds.
*   Function returns 1 upon timeout.  This function used with
*   the Model 8 rolls over in about 49 days.
*/
  timediff = MilliSecs() - starttime;
//  printf("\ntimediff: %lu", timediff);
  if(timediff >= maxtime) return 1;
    else return 0;
}

/*********************************************/

int timer_min(ulong starttime, ulong maxtime){
  ulong timediff;

/*
*   starttime is absolute time from RTC in milliseconds.
*   maxtime is the timeout period in minutes.
*   Function returns 1 upon timeout.  This function used with
*   the Model 8 rolls over in about 49 days.
*/
  maxtime *= 60000;                   /* Convert mins to millisecs */
  timediff = MilliSecs() - starttime;
//  printf("\ntimediff: %lu", timediff);
  if(timediff >= maxtime) return 1;
    else return 0;
}

/*********************************************/

void delaysecs(unsigned long delay_time){

  delay_time *= 1000;
  DelayMilliSecs(delay_time);
  return;
}

/*********************************************/

void delaymins(unsigned long delay_time){

  delay_time *= 60000;
  DelayMilliSecs(delay_time);
  return;
}


/*********************************************
	 A/D Converter Functions
*********************************************/

short read_max186(short chan, short reads){
  short x;
  long outval = 0;

  for(x=0; x<reads; x++){
    outval += AtoDReadWord(chan);
  }

  outval /= reads;
  return (short)outval;
}

/*********************************************/

short read_max132(short chan)
{
   int x, val;
   uchar cnt;
   long voltage = 0;

   shift_atod((chan<<4)|1);

   for (cnt = 0; cnt < VOLTAGE_AVERAGE; ++cnt) /*LOOP FOUR TIMES */
   {

      shift_atod(0x84);  /*start convert to read voltage SEND BACK HIGH*/
			 /*BYTE NEXT TIME.*/
      DelayMilliSecs(70);
      val = shift_atod(0x00); /*SAME ROUTINE AS ZERO ABOVE*/
      val  <<= 8;
      val |= shift_atod(0x00);
      voltage += val;
   }
   voltage =(voltage / VOLTAGE_AVERAGE);
#ifdef __TURBOC__
   voltage = 16383;
#endif

   return (short)voltage;

}

/************************************************************************/
/*                      SHIFT_ATOD                                      */
/* This function serves as a driver for clocking data in and out of the */
/*  atod converter.  It accepts a hexidecimal value which controls the  */
/*  atod functions.  It also returns the atod output value (8bits).     */
/************************************************************************/

uchar shift_atod(uchar input_val)
{
    uchar cnt;
    uchar out_val = 0;
    PSet(E,3); /*CLOCK LOW*/
    PSet(E,0); /*SELECTS MAX132 FOR COMMUNICATION WITH MICROPROCESSOR*/

    for (cnt = 0; cnt < 8; cnt++)  /*LOOP 8 TIMES*/
    { 
       if (input_val & 0x80) /*MSB set ???*/
	  PClear(E,1);           /*YES, SET DIN */
       else
	  PSet(E,1);           /*NO, CLEAR IT*/
       PClear(E,3);             /*CLOCK HIGH*/
       out_val <<= 1;        /*SHIFT IN ATOD VALUE*/
       if (!Pin(E,2))             /*IF DOUT HIGH, OR 1 WITH OUT_VAL*/
	  out_val |= 1;      /*IF DOUT LOW SIMPLY BRING CLOCK LOW*/
       PSet(E,3);
       input_val <<= 1;      /*SHIFT LEFT 1 IN ORDER TO READ NEXT BIT*/
    }
    
    PClear(E,0); /*TERMINATES COMMUNICATION WITH MICRPROCESSOR*/
    PClear(E,1); /* Reduce power consumption on iso. side */
    PClear(E,3); /* Ditto */
    return out_val;

}

/*************************** Reset *****************************/

void bc_reset(void){

#ifdef __TURBOC__
  exit(0);
#endif

#ifdef AZTEC_C
  ResetToMon();
#endif

}

/****************************************************/

void SetDateTime(void)
	{
	struct tm 	t;

	printf("\nSet Current Date and Time (Alt-D from CrossCut)");
	if (! QueryDateTime("\n<return> for default", TRUE, &t))
		return;
	SetTimeTM(&t, NULL);

	}	/* SetDateTime() */


/******************* Interrupt Functions **************/

void tpurupt(char chan, char on_off){

#ifdef AZTEC_C

  TPUClearInterrupt(chan);
  if(on_off == ON) TPUInterruptEnable(chan);
  else TPUInterruptDisable(chan);

#endif
}

/****************************************************************/

void stir_turns(void){
  g_stir_ticks++;
  TPUClearInterrupt(STIR_TURNS_CHAN);  /* Acknowledge interrupt */
  return;
}

/****************************************************************/

void purge_turns(void){
  g_purge_ticks++;
  TPUClearInterrupt(PURGE_TURNS_CHAN);  /* Acknowledge interrupt */
  return;
}

/****************************************************************/

void slide_turns(void){
  g_slide_ticks++;
  TPUClearInterrupt(SLIDE_TURNS_CHAN);  /* Acknowledge interrupt */
  return;
}
