//                FEEDER CONTROL PROGRAM
//
//  Program name: feeder3.c
//  Latest revision date: December 8, 1997
//  Test results: works just fine 
//
//  This program controls the monkey feeder.  The feeder drops food pellets
//  upon request (parallel port input).  In addition, color LEDs can be turned
//  on/off.  The feeder is equiped with an infrared sensor which can detect
//  whether monkey hand is in/out (proximity detector).  Moreover, the feeder can
//  eat its own food either upon request or when the monkey sticks in the hand,
//  but this is not allowed.
//
//  Programmer: 
//  Mikhail Lebedev
//  301-496-4991
//  lebedev@lnp.nimh.nih.gov
//
//  Project director:
//  Andrew Mitz
//  301-496-4991
//  arm@lnp.nimh.nih.gov  
//
//  Technical details
//  Controller name: Z-World controller "Little G"
//  Parallel port inputs:
//    DIGIN1 - if this bit is set to 1, monkey is not allowed to grab food
//    DIGIN2 - 1/0 red LED off/on, respectively
//    DIGIN3 - 1/0 green LED off/on, respectively
//    DIGIN4 - 1/0 blue LED off/on, respectively
//    DIGIN9 - 1-->0 pulse evokes food presentation
//    DIGIN10 - 1-->0 pulse evokes food dump
//    DIGIN12 - proximity sensor 1/0 - out/in (internal connection)
//  High-current outputs (set bit to 1 to activate an output):
//    HC1 - feeder valve
//    HC2 - trap door valve (feeder "mouth")
//    HC4 - red LED
//    HC5 - green LED
//    HC6 - blue LED
//  Parallel port outputs:
//    OUTB2 - proximity sensor 1 - hand is out, 0 - in
//    OUTB3 - trap door state 1 - closed, 0 - open
//
//  Brief description of how the program works
//  To change the feeder attitude set DIGIN1 (0/1 - waiter/monster)
//  To turn on/off LEDs, set the corresponding bits (DIGIN2 - 4) to 0/1
//  To present food, send a 1-->0 pulse to DIGIN9.  The feeder valve will stay
//    active for 1500 ms (FEED_DELAY).
//  To dump food, send a 1-->0 pulse to DIGIN10.  Trap door (feeder mouth) will
//    open for 900 ms (DUMP_DELAY).  Then, the feeder will wait for the monkey
//    to remove the hand for a minimum 200 ms (HAND_OUT_DELAY).  Then, the trap
//    door will be closed.  Additional 400 ms (PROTECTION_DELAY) will be devoted
//    to making sure that the monkey does not stick the hand back.  If the monkey
//    does stick the hand back, the trap door is immediately open again, and a new
//    dump will be sequence initiated.

// ------------------------- The program itself ---------------------------------

//Delay settings (ms)
#define DUMP_DELAY			900L
#define HAND_OUT_DELAY		200L
#define PROTECT_DELAY		400L	
#define FEED_DELAY			1500L

#use DEFAULT.H                   //Necessary libraries
#use VDRIVER.LIB

shared unsigned char dump_flag,      //dump control (1-dump)
                     protect_flag,   //protect control (1-protect)
                     feed_flag,      //feed control (1-feed)
                     proximity_flag, //used in hand out check (1-hand out)
                     dump_trace,     //keeps track of dump control input
                     feed_trace;     //keeps track of feed control input

main () {

  dump_flag = 0;       //inactivate control flags
  protect_flag = 0;
  feed_flag = 0;

  VdInit();     //Initialization stuff

  VIODrvr();    //Refresh inputs and outputs
  
  HC1 = 0;      //Feeder valve deactivated
  HC2 = 0;      //Trap door valve deactivated
  HC4 = 0;      //Red light off
  HC5 = 0;      //Green light off
  HC6 = 0;      //Blue light off

  OUTB2 = 1;    //Hand is out (proximity bit)
  OUTB3 = 1;    //Trap door is closed ("safe door" bit)

  dump_trace = 1;  //Traces start at one
  feed_trace = 1;
  
  VIODrvr();    //Put in the initial values
  
  while(1) {

    // Update proximity task
    costate {

      VIODrvr();
      if (DIGIN12) OUTB2=1; else OUTB2=0;   //Update proximity information
      VIODrvr();

      proximity_flag = proximity_flag && DIGIN12; //Flag initialized during dump
      
    }  											     

    // Wait for a command task
    costate{
    
      VIODrvr();
      
      if (((!DIGIN10)&&(dump_trace != DIGIN10)) //Evoke DUMP on 1-->0 pulse
         || ((!DIGIN12) && DIGIN1)) {           //or hand entering the feeder
                                                //when this is not allowed
        dump_trace = DIGIN10;  //update the trace        
        dump_flag = 1;         //new job: DUMP
        abort;                 //abort because DUMP has a high priority
      }
      dump_trace = DIGIN10;    //update the trace

      if ((!DIGIN9)&&(feed_trace != DIGIN9)) {  //Evoke FEED on 1-->0 pulse
        feed_flag = 1;        //new job: FEED
      }
      feed_trace = DIGIN9;    //update the trace      

      if (DIGIN2) HC4=0; else HC4=1;  //Red LED
      if (DIGIN3) HC5=0; else HC5=1;  //Green LED
      if (DIGIN4) HC6=0; else HC6=1;  //Blue LED
            
      VIODrvr();              //refresh inputs and outputs  
    }

    // DUMP
    costate {

      if (!dump_flag) abort;
           
      HC2 = 1;                              //Open trap door
      VIODrvr();
      OUTB3 = 0;  //Inform the "safe door" bit that the trap door is open      
      waitfor(DelayMs(DUMP_DELAY));         //Delay

      proximity_flag = 0;
      while( !proximity_flag ) {       //The hand should stay out for
        proximity_flag = DIGIN12;                    //HAND_OUT_DELAY ms
        waitfor(DelayMs(HAND_OUT_DELAY));
      }

      HC2 = 0;                              //Close trap door
      VIODrvr();
      
      dump_flag = 0;
      protect_flag = 1;                  //New job: PROTECT

      waitfor(DelayMs(PROTECT_DELAY));      //Delay
      protect_flag = 0;
      
      if (!dump_flag)           //During PROTECT dump_flag may be set
        OUTB3 = 1;              //"Safe door" is closed
       
    }

    // PROTECT (protect monkey finger from being caught)
    costate {
      if (!protect_flag) abort;
      if (!DIGIN12) {           //If the hand is in   
        HC2 = 1;                //Open trap door
        VIODrvr();
        dump_flag = 1;          //Force a new DUMP
      }
    }

    // FEED
    costate {
      if (!feed_flag) abort;
      
      HC1 = 1;                  //Activate feeder valve
      VIODrvr();     
      waitfor(DelayMs(FEED_DELAY));  //Stir delay
      HC1 = 0;                  //Deactivate feeder valve
      VIODrvr();        

      feed_flag = 0;            //FEED is finished
    }     

  }
}