// experi2.c

#include <stdio.h> // contains prototypes for printf() and puts()
#include <conio.h> // contains prototypes for inp() and kbhit()

// local prototypes
int is_switch(int input);
void get_port(void);
void set_up_ppi(void);

void main(void)
{
  int x,y;

  get_port(); // get the value of the base Port Address

  set_up_ppi(); // set up ppi_porta = out, ppi_portb = in, ppi_portc = out 

  switch_port = base + 0x18;

  while(1)
  {
    if(kbhit()) // "keyboard hit" -- a compiler function that sees if a key has been
      break;    // pressed.  We will break out of the while() loop if a key is pressed.

    puts(""); // puts("") will put a new line on the screen
    for(x=0; x<7; x++) // 0 through 6 -- purposely use 0 to produce an error
    {
      y = is_switch(x);
      printf("x=%02d y=%02d|",x,y); // don't print a new line yet
    }
    puts(""); // puts("") will put a new line on the screen
               // after all 7 items have been printed

    for(x=7; x<13; x++) // 7 through 12 -- purposely use 12 to produce an error
    {
      y = is_switch(x);
      printf("x=%02d y=%02d|",x,y); // don't print a new line yet
    }
    puts(""); // puts("") will put a new line on the screen
              // after all 6 items have been printed

    sleep(1); // sleep -- compiler function -- wait one second
              // so printed lines can be seen
              // remark sleep out or delete it for full speed

  } // end while(1)

} // end main()


/*
 The following are known only to the functions that follow. They
 can't be modified or even accessed by anything above this point.
 Their scope is from here to the end of the file.
*/
unsigned base;
unsigned switch_port;
unsigned ppi_porta;
unsigned ppi_portb;
unsigned ppi_portc;


// ================================================================
//                         is_switch
// 1. Return -1 error indicator if the input
//    is less than 1 or greater than 11.
//
// 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 ppi_portb.
// ================================================================
int is_switch(int input)
{
  if(input < 1 || input > 11) // if the input is less than 1 or greater
    return -1;                // than 11, then return -1 showing an error

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

  return ((inp(ppi_portb) >> (input - 4)) & 1) ^ 1; // fell through "if(input < 4)"
                                                    // so >= 4 (greater than or equal)
                                                    // so use PPI Port B

} // end is_switch()


// 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()


// Set up the ppi in mode 0.
// Make Port A an output, Port B an input and Port C an output.
void set_up_ppi(void)
{
  unsigned control = base + 0x23;

  outp(control, 0x82); // a = out, b = in, c = out 

} // end set_up_ppi()

// end experi2.c

