// digi3c.c

// The following are known only to the functions in this file.
// They can't be modified or even accessed by anything outside this
// file except through funtions in this file designed to provide access.
unsigned base;
unsigned switch_port;
unsigned ppi_porta;
unsigned ppi_portb;
unsigned ppi_portc;

int porta_val;
int porta_mask;

int portb_val;
int portb_mask;

int portc_val;
int portc_mask;


// ================================================================
//                         is_closure
// 1. Return -1 error indicator if the input
//    is less than 1 or greater than 67.
//
// 2. If there is a fall-through from the above and the input
//    is less than 4, return the status based on switch_port.
//
// 3. If there is a fall-through from both of the above, then
//    return the status based on the matrix:

//             |-----------------------|
// Port A bit 0| 4| 5| 6| 7| 8| 9|10|11|
// Port A bit 1|12|13|14|15|16|17|18|19|
// Port A bit 2|20|21|22|23|24|25|26|27|
// Port A bit 3|28|29|30|31|32|33|34|35|
// Port A bit 4|36|37|38|39|40|41|42|43|
// Port A bit 5|44|45|46|47|48|49|50|51|
// Port A bit 6|52|53|54|55|56|57|58|59|
// Port A bit 7|60|61|62|63|64|65|66|67|
//             |-----------------------|
//  Port B bits  0  1  2  3  4  5  6  7

// ================================================================
int is_closure(int input)
{

  if(input < 1 || input > 67) // if the input is less than 1 or greater
    return -1;                // than 67, then return -1 showing an error

  // we fell through the above so see if input is less than 4
  if(input < 4)
    return ((inp(switch_port) >> (input + 3)) & 1) ^ 1; // yes, return using switch_port

  // input is >= 4 so look at the matrix
  // by first setting up Port A to take the appropriate row bit low
  porta_val = (~(1 << ( (input - 4) / 8) )) & 0xff;

  // clear the appropriate Port A bit 
  outp(ppi_porta, porta_val);

  // determine what column bit to look at for this input
  portb_mask = (1 << ((input - 4) % 8)) & 0xff;

  // a closure will cause a low, so invert the return 
  if(!(inp(ppi_portb) & portb_mask))
    return 1;

  return 0;

}// end is_closure()


// set up the ppi according to the dictates of the mode argument
void set_up_ppi(int mode)
{
  unsigned control = base + 0x23;
  int command;

  command = (mode & 0x0c) << 1; // shift bits 2 and 3 into positions 3 and 4
  command += (mode & 3); // add in bits 0 and 1
  command |= 0x80; // OR in bit 7 for PPI set up

  outp(control, command); // set according to mode command

} // end set_up_ppi()


// get the port -- this will grow into an auto-detect function in the future 
void get_port(void)
{
  base = 0x300;
  switch_port = base + 0x18;
  ppi_porta = base + 0x20;
  ppi_portb = base + 0x21;
  ppi_portc = base + 0x22;

} // end get_port()

// end digi3c.c


