// timer9c.c

#include "timer9c.h"
#include <math.h>

// save the old vector, set up new vector, zero out counter
// set up timer rate
int set_up_new_timer(double freq)
{
  unsigned ms,ls;
  double divideby;

  if(freq < (1193180.0/65536.0))
    return 0;  // can't go below this

  if(freq > 1193180.0)
    return 0;  // or above this

  divideby = 1193180.0/freq;

  divideby+=0.5; // causes a round above .5

  ms = (unsigned)divideby >> 8; // get upper 8 for ms
  ls = (unsigned)divideby & 0xff; // mask off lower 8 for ls

  frequency = 1193180.0/(double)((ms << 8) + ls);

  oldfreq = 1193180.0/65536.0;

  MinTime = 1.0/frequency;
  MaxTime = (pow(2.0, 32.0)/2.0)/frequency;

  minpulse = 1e-2; // minimum pulse is 10ms - change if desired
                   // Reeder's H-Bridge and 754410 run well at 2.5ms

  timer_counter = 0L;

  disable(); // turn off interrupts

  outp(0x40, ls); // least significant byte of timer count
  outp(0x40, ms);  // most significant byte of timer count

  old_timer = getvect(0x1c);

  setvect(0x1c, new_timer);

  enable(); // turn interrupts back on

  return 1;
}

// restore former table entry and rate
void restore_old_timer()
{
  disable();

  outp(0x40, 0); // least significant byte of timer count
  outp(0x40, 0);  // most significant byte of timer count

  setvect(0x1c, old_timer);

  enable();
}

// the timer interrupt handler
// pwm type:
// 0 = unidirctional, no brake
// 1 = unidirectional with brake
// 2 = pwm line, directional line, no brake
// 3 = pwm line, directional line, with brake
// 4 = dual pwm lines -- both high = brake
// 5 = pwm line and two direction lines as for L298
// 255 = last slot -- leave
interrupt new_timer()
{
  int x;

  disable();

  timer_counter++;

  if(DA_Enabled) // is DA section enabled?
  {
    // look for start conversion or data ready status
    while(!AnnalogChannel[CurrentChannel].status)
    {
      CurrentChannel++;
      if(CurrentChannel > 7)
        CurrentChannel = 0;
    }

    switch(AnnalogChannel[CurrentChannel].status)
    {
      case START_CONVERSION:
        // will be ready at next interrupt, so say so
        AnnalogChannel[CurrentChannel].status = DATA_READY;
      break;

      case DATA_READY:
        // check eoc even though it's probably already ready
        while(!(inp(eoc) & 0x80));

        // load data into structure
        AnnalogChannel[CurrentChannel].data = inp(base);

        // set up for next
        AnnalogChannel[CurrentChannel].status = START_CONVERSION;

        CurrentChannel++; // bump up to next channel
        if(CurrentChannel > 7)
          CurrentChannel = 0;

        // this will find a channel that needs
        // a start even if it's just the above
        while(AnnalogChannel[CurrentChannel].status != START_CONVERSION)
        {
          CurrentChannel++; // get away from above channel
          if(CurrentChannel > 7)
            CurrentChannel = 0;
        }

      break;

    } // end switch(AnnalogChannel[CurrentChannel].status)

    // start a conversion - either the one designated
    // or the next one found after a data load
    outp(base + CurrentChannel, 0);

  } // end if(DA_Enabled)

  if(OutputControlActive)
  {
    for(x=0; x<24; x++)
    {
      if(OutputControl[x] == NULL // not set up or off
        || !OutputControl[x]->direction) 
            continue;
  
      if(OutputControl[x]->type == 255) // last slot
            break;
  
      if(OutputControl[x]->direction == 1
        || OutputControl[x]->type < 2)
      {
        if(OutputControl[x]->ForwardOnCount > 0L)
        {
          OutputControl[x]->ForwardOnCount--;
  
          if(!OutputControl[x]->ForwardOnCount)
          {
            // keep existing bits but remove this one
            *OutputControl[x]->ForwardPortData 
              &= OutputControl[x]->ForwardOffMask;
  
            // put the result in this node's port register
            outp(OutputControl[x]->ForwardPortAddress, 
              *OutputControl[x]->ForwardPortData);
    
            OutputControl[x]->ForwardOffCount = 
              OutputControl[x]->ForwardSetOff;
          }
        }
  
        // note that this will not decrement as soon as set
        // above, but will wait until the next interrupt
        else if(OutputControl[x]->ForwardOffCount > 0L)
        {
          OutputControl[x]->ForwardOffCount--;
  
          if(!OutputControl[x]->ForwardOffCount)
          {
            // keep existing bits and OR this one in
            *OutputControl[x]->ForwardPortData |= 
              OutputControl[x]->ForwardOnMask;
  
            // put the result in this node's port register
            outp(OutputControl[x]->ForwardPortAddress, 
              *OutputControl[x]->ForwardPortData);
    
            OutputControl[x]->ForwardOnCount = 
              OutputControl[x]->ForwardSetOn;
  
          }
  
        }
  
      } // end if(OutputControl[x]->direction == 1 
        // || OutputControl[x]->type < 2)
  
      else if(OutputControl[x]->direction == 2
          && OutputControl[x]->type > 1) // types 2,3 and 4 can have reverse
      {
        if(OutputControl[x]->ReverseOnCount > 0L)
        {
          OutputControl[x]->ReverseOnCount--;
  
          if(!OutputControl[x]->ReverseOnCount)
          {
            // keep existing bits but remove this one
            *OutputControl[x]->ReversePortData 
              &= OutputControl[x]->ReverseOffMask;
  
            // put the result in this node's port register
            outp(OutputControl[x]->ReversePortAddress, 
              *OutputControl[x]->ReversePortData);
    
            OutputControl[x]->ReverseOffCount = 
              OutputControl[x]->ReverseSetOff;
          }
  
        } // end if(OutputControl[x]->ReverseOnCount > 0L)
  
        // note that this will not decrement as soon as set
        // above, but will wait until the next interrupt
        else if(OutputControl[x]->ReverseOffCount > 0L)
        {
          OutputControl[x]->ReverseOffCount--;
  
          if(!OutputControl[x]->ReverseOffCount)
          {
            // keep existing bits and OR this one in
            *OutputControl[x]->ReversePortData |= 
              OutputControl[x]->ReverseOnMask;
  
            // put the result in this node's port register
            outp(OutputControl[x]->ReversePortAddress, 
              *OutputControl[x]->ReversePortData);
    
            OutputControl[x]->ReverseOnCount = 
              OutputControl[x]->ReverseSetOn;
          }
  
        } // end else if(OutputControl[x]->ReverseOffCount > 0L)
  
      } // end else if(OutputControl[x]->direction == 2
        // && OutputControl[x]->type > 1)
  
    } // end for(x=0; x<24; x++)

  } // end if(OutputControlActive)

  enable();
}

// Set up Pulse Width Modulation for an output
//
// arraynumber is the position in the output control array
//
// type:
// 0 = unidirectional, no brake
// 1 = unidirectional with brake
// 2 = pwm line, directional line, no brake
// 3 = pwm line, directional line, with brake
// 4 = dual pwm lines -- both high = brake
// 5 = pwm line and two direction lines as for L298
// 255 = last slot -- leave
//
// Forward and Reverse port numbers are pwm lines for each
//
// The Direction port number is provided for bridges that have a reverse line
// Set to anything if not used
//
// The Brake port number is provided for circuits that have a brake line
// Set to anything if not used
//
int pwm(int arraynumber, int type,
    int ForwardPortNumber, int ReversePortNumber,
    int DirectionPortNumber, int BrakePortNumber,
    double ForwardOnTime, double ForwardOffTime,
    double ReverseOnTime, double ReverseOffTime,
    int StartDirection)
{
  if(StartDirection < 0 || StartDirection > 2)
      return 0;

  if(ForwardOnTime <= MinTime || ForwardOnTime >= MaxTime
    || ForwardOffTime <= MinTime || ForwardOffTime >= MaxTime)
      return 0;

  disable(); // no interrupts while setting up  

  if(!ConfigureOutput(arraynumber, type, 
                      ForwardPortNumber, 
                      ReversePortNumber,
                      DirectionPortNumber,
                      BrakePortNumber))
  {
    enable();
    return 0;
  }
  
  OutputControlActive = 1;

  OutputControl[arraynumber]->ForwardSetOn =
    (long)((frequency * ForwardOnTime) + 0.5); // round up at .5

  OutputControl[arraynumber]->ForwardSetOff 
    = (long)((frequency * ForwardOffTime) + 0.5);

  OutputControl[arraynumber]->ForwardOnCount
    = OutputControl[arraynumber]->ForwardSetOn;

  OutputControl[arraynumber]->ForwardOffCount
    = OutputControl[arraynumber]->ForwardSetOff;

  OutputControl[arraynumber]->direction = StartDirection;

  OutputControl[arraynumber]->type = type;

  if(!type) // uni directional
  {
    enable();
    return 1;
  }

  if(type == 1 || type == 3) // 1 and 3 have a brake
  {
    *OutputControl[arraynumber]->BrakePortData
      &= OutputControl[arraynumber]->BrakeOffMask; // turn off the brake

    outp(OutputControl[arraynumber]->BrakePortAddress, 
      *OutputControl[arraynumber]->BrakePortData);
  }

  if(type > 1) // 2,3,4,5 use reverse pwm line, 2,3,5 use direction line
  {
    if(ReverseOffTime <= MinTime || ReverseOffTime >= MaxTime
      || ReverseOffTime <= MinTime || ReverseOffTime >= MaxTime)
    {
      free(OutputControl[arraynumber]);
      OutputControl[arraynumber] = NULL;
      enable();
      return 0;
    }
  
    OutputControl[arraynumber]->ReverseSetOn =
      (long)((frequency * ReverseOnTime) + 0.5); // round up at .5

    OutputControl[arraynumber]->ReverseOnCount
      = OutputControl[arraynumber]->ReverseSetOn;

    OutputControl[arraynumber]->ReverseSetOff =
      (long)((frequency * ReverseOffTime) + 0.5);

    OutputControl[arraynumber]->ReverseOffCount
      = OutputControl[arraynumber]->ReverseSetOff;

    if(type == 2 || type == 3 || type == 5) // 2,3,5 use a direction line
    {
      if(StartDirection == 1)
      *OutputControl[arraynumber]->DirectionPortData
        != OutputControl[arraynumber]->DirectionOnMask; // set for forward

      else if(StartDirection == 2)
      *OutputControl[arraynumber]->DirectionPortData
        &= OutputControl[arraynumber]->DirectionOffMask; // clear for reverse

      outp(OutputControl[arraynumber]->DirectionPortAddress, 
        *OutputControl[arraynumber]->DirectionPortData);

      if(type == 5)
      {
        if(StartDirection == 1)
          *OutputControl[arraynumber]->BrakePortData
            &= OutputControl[arraynumber]->BrakeOffMask; // turn off the brake

        else if(StartDirection == 2)
          *OutputControl[arraynumber]->BrakePortData
            |= OutputControl[arraynumber]->BrakeOnMask; // turn on the brake

        outp(OutputControl[arraynumber]->BrakePortAddress, 
          *OutputControl[arraynumber]->BrakePortData);
      }
    }

  } // end if(type > 1)

  enable();

  return 1;

} // end int pwm(..)


// go forward
int Forward(arraynumber)
{
  if(OutputControl[arraynumber] == NULL)
    return 0;

  if(OutputControl[arraynumber]->type < 2)
    return 0; // < 2 is unidirectional

  if(OutputControl[arraynumber]->type == 255)
    return 0; // 255 is last node

  disable();

  OutputControl[arraynumber]->direction = 1;

  // 2,3 and 5 use the direction line
  if(OutputControl[arraynumber]->type == 2
  || OutputControl[arraynumber]->type == 3
  || OutputControl[arraynumber]->type == 5)
  {
    *OutputControl[arraynumber]->DirectionPortData
      |= OutputControl[arraynumber]->DirectionOnMask; // set for forward

    outp(OutputControl[arraynumber]->DirectionPortAddress, 
      *OutputControl[arraynumber]->DirectionPortData);

    if(OutputControl[arraynumber]->type == 5)
    {
      *OutputControl[arraynumber]->BrakePortData
        &= OutputControl[arraynumber]->BrakeOffMask; // turn off the brake line

      outp(OutputControl[arraynumber]->BrakePortAddress, 
        *OutputControl[arraynumber]->BrakePortData);
    }
  }

  // keep existing bits but remove this one
  *OutputControl[arraynumber]->ReversePortData 
  &= OutputControl[arraynumber]->ReverseOffMask;

  // put the result in this node's port register
  outp(OutputControl[arraynumber]->ReversePortAddress, 
  *OutputControl[arraynumber]->ReversePortData);

  enable();

  return 1;
}

// go in reverse
int Reverse(arraynumber)
{
  if(OutputControl[arraynumber] == NULL)
    return 0;

  if(OutputControl[arraynumber]->type < 2)
    return 0; // < 2 is unidirectional

  if(OutputControl[arraynumber]->type == 255)
    return 0; // 255 is last node

  disable();

  OutputControl[arraynumber]->direction = 2;

  // 2,3 and 5 use the direction line
  if(OutputControl[arraynumber]->type == 2
  || OutputControl[arraynumber]->type == 3
  || OutputControl[arraynumber]->type == 5)
  {
    *OutputControl[arraynumber]->DirectionPortData
      &= OutputControl[arraynumber]->DirectionOffMask; // clear for reverse

    outp(OutputControl[arraynumber]->DirectionPortAddress, 
      *OutputControl[arraynumber]->DirectionPortData);

    if(OutputControl[arraynumber]->type == 5)
    {
      *OutputControl[arraynumber]->BrakePortData
        |= OutputControl[arraynumber]->BrakeOnMask; // turn on the brake line

      outp(OutputControl[arraynumber]->BrakePortAddress, 
        *OutputControl[arraynumber]->BrakePortData);
    }
  }

  // keep existing bits but remove this one
  *OutputControl[arraynumber]->ForwardPortData 
  &= OutputControl[arraynumber]->ForwardOffMask;

  // put the result in this node's port register
  outp(OutputControl[arraynumber]->ForwardPortAddress, 
  *OutputControl[arraynumber]->ForwardPortData);
  
  enable();

  return 1;
}

// stop a pwm channel
int Stop(int arraynumber)
{
  if(OutputControl[arraynumber] == NULL)
    return 0;

  disable();

  OutputControl[arraynumber]->direction = 0;

  // keep existing bits but remove this one for forward
  // for L289, this takes its enable line low
  *OutputControl[arraynumber]->ForwardPortData &=
    OutputControl[arraynumber]->ForwardOffMask;

  // put the result in this node's port register
  outp(OutputControl[arraynumber]->ForwardPortAddress, 
       *OutputControl[arraynumber]->ForwardPortData);

  // keep existing bits but remove this one for reverse
  *OutputControl[arraynumber]->ReversePortData &=
    OutputControl[arraynumber]->ReverseOffMask;

  // put the result in this node's port register reverse
  outp(OutputControl[arraynumber]->ReversePortAddress, 
       *OutputControl[arraynumber]->ReversePortData);

  enable();

  return 1;
}  


// apply brake for an L298
int BrakeL298(int arraynumber)
{
  if(OutputControl[arraynumber] == NULL)
    return 0;

  disable();

  OutputControl[arraynumber]->direction = 0;

  // make enable line high
  *OutputControl[arraynumber]->ForwardPortData 
    |= OutputControl[arraynumber]->ForwardOnMask;

  // put the result in this node's port register
  outp(OutputControl[arraynumber]->ForwardPortAddress, 
    *OutputControl[arraynumber]->ForwardPortData);

  // make direction and brake lines low for brake on bottom switches
  *OutputControl[arraynumber]->DirectionPortData
    &= OutputControl[arraynumber]->DirectionOffMask;

  outp(OutputControl[arraynumber]->DirectionPortAddress, 
    *OutputControl[arraynumber]->DirectionPortData);

  // make brake line low
  *OutputControl[arraynumber]->BrakePortData
    &= OutputControl[arraynumber]->BrakeOffMask;

  outp(OutputControl[arraynumber]->BrakePortAddress, 
   *OutputControl[arraynumber]->BrakePortData);

  enable();

  wait(0.1); // brake .1 sec

  // make enable line low
  *OutputControl[arraynumber]->ForwardPortData 
    &= OutputControl[arraynumber]->ForwardOffMask;

  return 1;
}

// brake a dual pwm channel
// taking both lines high brakes
int BrakeDualPwm(int arraynumber)
{
  if(OutputControl[arraynumber] == NULL)
    return 0;

  disable();

  OutputControl[arraynumber]->direction = 0;

  // keep existing bits but remove this one for forward
  *OutputControl[arraynumber]->ForwardPortData |=
    OutputControl[arraynumber]->ForwardOnMask;

  // put the result in this node's port register
  outp(OutputControl[arraynumber]->ForwardPortAddress, 
       *OutputControl[arraynumber]->ForwardPortData);

  // keep existing bits but remove this one
  *OutputControl[arraynumber]->ReversePortData |=
    OutputControl[arraynumber]->ReverseOnMask;

  // put the result in this node's port register reverse
  outp(OutputControl[arraynumber]->ReversePortAddress, 
       *OutputControl[arraynumber]->ReversePortData);

  enable();

  wait(0.1); // brake .1 sec

  Stop(arraynumber); // release lines

  return 1;
}  

// ========================== Short Cut PWM Routines ==========================

// set up an L289
int L289PwmDuty(int arraynumber, int StartDirection,
    int PwmPortNumber, double ForwardDutycycle,
    double ReverseDutycycle, int Direction1Port, int Direction2Port)
{
  double ForwardOnTime,ForwardOffTime;
  double ReverseOnTime,ReverseOffTime;
  
  if(ForwardDutycycle > 1.0)
    ForwardDutycycle/=100.0;

  if(ForwardDutycycle > 1.0)
    ForwardDutycycle = 1.0;

  if(ForwardDutycycle <= 0.5)
  {
    ForwardOnTime = minpulse;
    ForwardOffTime = ((1.0 - ForwardDutycycle)/ForwardDutycycle) * ForwardOnTime;
  }

  else
  {
    ForwardDutycycle = 1.0 - ForwardDutycycle;
    ForwardOffTime = minpulse;
    ForwardOnTime = ((1.0 - ForwardDutycycle)/ForwardDutycycle) * ForwardOffTime;
  }

  if(ReverseDutycycle > 1.0)
    ReverseDutycycle/=100.0;

  if(ReverseDutycycle > 1.0)
    ReverseDutycycle = 1.0;

  if(ReverseDutycycle <= 0.5)
  {
    ReverseOnTime = minpulse;
    ReverseOffTime = ((1.0 - ReverseDutycycle)/ReverseDutycycle) * ReverseOnTime;
  }

  else
  {
    ReverseDutycycle = 1.0 - ReverseDutycycle;
    ReverseOffTime = minpulse;
    ReverseOnTime = ((1.0 - ReverseDutycycle)/ReverseDutycycle) * ReverseOffTime;
  }

  return pwm(arraynumber, 5,
    PwmPortNumber, PwmPortNumber, // frwrd & rev same = pwm/enable line
    Direction1Port, Direction2Port, // direction gets dir1, brake dir2
    ForwardOnTime, ForwardOffTime,
    ReverseOnTime, ReverseOffTime,
    StartDirection);
}

// start a blinker
Blink(int arraynumber, int BlinkPort, double BlinkOnTime, double BlinkOffTime)
{
  return pwm(arraynumber, 0, // arraynum, type 0
          BlinkPort, 0, // forward port, no rev port
          0, 0, BlinkOnTime,  // no direction, no brake, forward on time
          BlinkOffTime, 0, 0, 1); // fwd off time, no rev on/off, fwd start
}

// set up a uni-directioanl pwm channel
int UniPwm(int arraynumber, int ForwardPortNumber,
    double ForwardOnTime, double ForwardOffTime)
{
  return pwm(arraynumber, 0, // arraynum, type 0
          ForwardPortNumber, 0, // forward port, no rev port
          0, 0, ForwardOnTime,  // no direction, no brake, forward on time
          ForwardOffTime, 0, 0, 1); // fwd off time, no rev on/off, fwd start
}

// set up a uni-directioanl pwm channel using duty cycle
int UniPwmDuty(int arraynumber, int ForwardPortNumber,
    double ForwardDutycycle)
{
  int x;
  double ForwardOnTime,ForwardOffTime;
  
  if(ForwardDutycycle > 1.0)
    ForwardDutycycle/=100.0;

  if(ForwardDutycycle > 1.0)
    ForwardDutycycle = 1.0;

  if(ForwardDutycycle <= 0.5)
  {
    ForwardOnTime = minpulse;
    ForwardOffTime = ((1.0 - ForwardDutycycle)/ForwardDutycycle) * ForwardOnTime;
  }

  else
  {
    ForwardDutycycle = 1.0 - ForwardDutycycle;
    ForwardOffTime = minpulse;
    ForwardOnTime = ((1.0 - ForwardDutycycle)/ForwardDutycycle) * ForwardOffTime;
  }

  return UniPwm(arraynumber, ForwardPortNumber,
    ForwardOnTime, ForwardOffTime);
}

// set up a dual pwm channel using duty cycle
int DualPwmDuty(int arraynumber, int StartDirection,
    int ForwardPortNumber, double ForwardDutycycle,
    int ReversePortNumber, double ReverseDutycycle)
{
  double ForwardOnTime,ForwardOffTime;
  double ReverseOnTime,ReverseOffTime;
  
  if(ForwardDutycycle > 1.0)
    ForwardDutycycle/=100.0;

  if(ForwardDutycycle > 1.0)
    ForwardDutycycle = 1.0;

  if(ForwardDutycycle <= 0.5)
  {
    ForwardOnTime = minpulse;
    ForwardOffTime = ((1.0 - ForwardDutycycle)/ForwardDutycycle) * ForwardOnTime;
  }

  else
  {
    ForwardDutycycle = 1.0 - ForwardDutycycle;
    ForwardOffTime = minpulse;
    ForwardOnTime = ((1.0 - ForwardDutycycle)/ForwardDutycycle) * ForwardOffTime;
  }

  if(ReverseDutycycle > 1.0)
    ReverseDutycycle/=100.0;

  if(ReverseDutycycle > 1.0)
    ReverseDutycycle = 1.0;

  if(ReverseDutycycle <= 0.5)
  {
    ReverseOnTime = minpulse;
    ReverseOffTime = ((1.0 - ReverseDutycycle)/ReverseDutycycle) * ReverseOnTime;
  }

  else
  {
    ReverseDutycycle = 1.0 - ReverseDutycycle;
    ReverseOffTime = minpulse;
    ReverseOnTime = ((1.0 - ReverseDutycycle)/ReverseDutycycle) * ReverseOffTime;
  }

  return pwm(arraynumber, 4, // type 4 is dual pwm
    ForwardPortNumber, ReversePortNumber,
    0,0, // no direction or brake port numbers
    ForwardOnTime, ForwardOffTime,
    ReverseOnTime, ReverseOffTime,
    StartDirection);
}

// set up a channel with a pwm line and a direction line -- no brake
// using duty cycle
int PwmAndDirectionDuty(int arraynumber, int StartDirection,
                        int PwmPortNumber,
                        int DirectionPortNumber,
                        double ForwardDutycycle,
                        double ReverseDutycycle)
{
 double ForwardOnTime,ForwardOffTime;
  double ReverseOnTime,ReverseOffTime;

  if(ForwardDutycycle > 1.0)
    ForwardDutycycle/=100.0;

  if(ForwardDutycycle > 1.0)
    ForwardDutycycle = 1.0;

  if(ForwardDutycycle <= 0.5)
  {
    ForwardOnTime = minpulse;
    ForwardOffTime = ((1.0 - ForwardDutycycle)/ForwardDutycycle) * ForwardOnTime;
  }

  else
  {
    ForwardDutycycle = 1.0 - ForwardDutycycle;
    ForwardOffTime = minpulse;
    ForwardOnTime = ((1.0 - ForwardDutycycle)/ForwardDutycycle) * ForwardOffTime;
  }

  if(ReverseDutycycle > 1.0)
    ReverseDutycycle/=100.0;

  if(ReverseDutycycle > 1.0)
    ReverseDutycycle = 1.0;

  if(ReverseDutycycle <= 0.5)
  {
    ReverseOnTime = minpulse;
    ReverseOffTime = ((1.0 - ReverseDutycycle)/ReverseDutycycle) * ReverseOnTime;
  }

  else
  {
    ReverseDutycycle = 1.0 - ReverseDutycycle;
    ReverseOffTime = minpulse;
    ReverseOnTime = ((1.0 - ReverseDutycycle)/ReverseDutycycle) * ReverseOffTime;
  }

  return pwm(arraynumber, 2, // type 2 = pwm, direction, no brake
    PwmPortNumber, PwmPortNumber, // forward and reverse are same
    DirectionPortNumber, 0, // no brake
    ForwardOnTime, ForwardOffTime,
    ReverseOnTime, ReverseOffTime,
    StartDirection);
}

// wait for seconds and/or fractions of a second
void wait(double seconds)
{
  long wait_count;

  if(seconds <= 0.0)
    return;

  if(timer_counter < 0L)
    return;

  wait_count = (long)((seconds * frequency) + 0.5); // round at .5

  timer_counter = 0L;

  while(timer_counter < wait_count);
}

// ================= Routines to Get Timer Information =================
// return the frequency to the caller
double get_frequency(void)
{
  return frequency;
}

// return the frequency to the caller
double get_mintime(void)
{
  return MinTime;
}

// return the frequency to the caller
double get_maxtime(void)
{
  return MaxTime;
}

// return the value of the counter to the caller
long get_timer_counter(void)
{
  return timer_counter;
}


// ======================= DA Routines ======================= 

unsigned InitializeAnalog(void)
{
  base = get_port();
  eoc = base + 0x18;

  if(!base)
    return 0;

  memset(&AnnalogChannel, 0, sizeof(AnnalogChannel));

  CurrentChannel = 0;

  return base;
}

int TurnOnAnalog(int channel)
{
  if(channel < 0 || channel > 7)
    return -1;

  AnnalogChannel[channel].status = START_CONVERSION;

  DA_Enabled = 1;

  return channel;
}

int TurnOffAnalog(int channel)
{
  int x;

  if(channel < 0 || channel > 7)
    return -1;

  AnnalogChannel[channel].status = INACTIVE;

  for(x=0; x<8; x++)
  {
    if(AnnalogChannel[channel].status != INACTIVE)
      break;
  }

  if(x == 8)  // all channels are inactive
    DA_Enabled = 0;

  return channel;
}

int GetChannelValue(int channel)
{
  if(channel < 0 || channel > 7)
    return -1;

  if(AnnalogChannel[channel].status == INACTIVE)
    return -1;

  return AnnalogChannel[channel].data;

  return channel;
}

// ======================= Test Routines =======================
void showall(void)
{
  int x;

  for(x=0; x<24; x++)
  {
    show(x);

    if(OutputControl[x]->type == 255)
      break;
  }
}

void show(int location)
{
  if(OutputControl[location] != NULL)
  {
    printf("Location %02d:\ntype=%d direction=%d "
    ,location,OutputControl[location]->type,OutputControl[location]->direction);

    if(OutputControl[location]->type != 255)
    {
      printf("Frwrd Port = %X Mask = %X Rev Port = %X Mask = %X\n"
        ,OutputControl[location]->ForwardPortAddress
        ,OutputControl[location]->ForwardOnMask
        ,OutputControl[location]->ReversePortAddress
        ,OutputControl[location]->ReverseOnMask);

      printf("Brk Port = %X Mask = %X Dir Port = %X Mask = %X\n"
        ,OutputControl[location]->BrakePortAddress
        ,OutputControl[location]->BrakeOnMask
        ,OutputControl[location]->DirectionPortAddress
        ,OutputControl[location]->DirectionOnMask);

      printf("Forward Set On=%ld Forward Set Off=%ld\n"
        ,OutputControl[location]->ForwardSetOn
        ,OutputControl[location]->ForwardSetOff);

      printf("Reverse Set On=%ld Reverse Set Off=%ld"
        ,OutputControl[location]->ReverseSetOn
        ,OutputControl[location]->ReverseSetOff);
    }
    printf("\n\n");
  }
}

// end timer9c.c



