/*
	SCAN.C

   PK21xx/Rugged Giant (only) Sample Program that illustrates using scan block or
   gate programming for control and monitor of i/o.
   
   Runs on Z-World's DEMO UNIT TWO.
*/

#use "default.h"
#use cplc.lib
#use 5key.lib
#use 5keyextd.lib
#use rtk.lib
#use gate_p.lib

#if !(BOARD_TYPE==CPLC_BOARD)
#fatal "This program only runs on a PK21xx/Rugged Giant"
#endif

/***Begin Globals real_time_kernel  */
int task0(void), task1(void), task2(void), task3(void), task4(void), 
    task5(void), backgnd(void);

int (*Ftask[])() =
{
    task0, task1, task2, task3, task4, task5, backgnd
};

#define NTASKS 7

#define TASK0 0
#define TASK1 1
#define TASK2 2
#define TASK3 3
#define TASK4 4
#define TASK5 5

/***End Globals real_time_kernel */


#define AND &&
#define OR  ||
#define NOT !


#define RUNKERNEL 1
char time0[15];
char *time0_help[] =
     {
         "Set system time,",
         "use field, up &",
         "down key to chng"
     };
char date0[15];
char *date0_help[] =
     {
         "Set system date,",
         "use field, up &",
         "down key to chng"
     };


char cntrl_on_off;
char *cntrl_help[] =
     {
         "on/off restart",
         "for gate program"
     };
char reset_on_off;
char *reset_help[] =
     {
         "reset digital",
         "out to off,also",
         "null the gates"
     };

char single_step;
char *single_help[] =
     {
         "on/off single",
         "stepping for",
         "gate program"
     };

char scanblk_on_off;
char *scanblk_help[] =
     {
         "software switch",
         "for scan blocks"
     };

void input_output_menu(void);// IO menu
void time_date_menu(void);   // time date menu
int gate_server(void);       // gate program menu
void dcmotor_demo(void);     // scan block demo for DEMO UNIT TWO
void cwrelay(void);          // clock wise direction for the DC motor
void ccwrelay(void);         // counter clockwise direction for DC motor
void relay_off(void);        // turn DC motor off
void gate_sample(void);      // initialize gate program for DEMO UNIT TWO
indirect int testF4(void);   // gate program service for key F3
indirect int testF3(void);   // gate program service for key F4
void demo_scan(void);        // scan block for DEMO UNIT ONE, not used
void traffic_demo(void);     // scan block for traffic/pedestrian light, not used
void pump_motor_demo(void);  // scan block for motor pump control, not used

main()
{
    uplc_init();
    reset_pbus();            // reset PLC bus

    cntrl_on_off   = 0;
    reset_on_off   = 0;
    single_step    = 0;
    scanblk_on_off = 1;

    _5key_setfunc(f1press, f2press, testF3, testF4);
    reset_p_gates();         // reset gate_points to none
    gate_sample();           // initialize the gates for this example
    backgnd();               // background task for the RTK
}

indirect task0(void)
{
    if (cntrl_on_off && !scanblk_on_off)
    {
        find_fkey_press();   // evaluate function keys
        evaluate_counter();  // evaluate virtual counters
        evaluate_gates();    // gate program
        evaluate_dac();      // evaluate discrete DACS
        reset_fkey_press();  // reset function keys
    }
}

indirect task3(void)
{
                             // task not used
}

indirect task1()
{
                             // task not used
}

indirect task2(void)
{
                             // task not used
}

// task server for menu
indirect task4(void)
{
    while (1)
    {
        time_date_menu();    // time date menu
        input_output_menu(); // input output menu
        timer_menu();        // virtual timer menu
        counter_menu();      // virtual counter menu
        uset_menu();         // universal input level menu
        dac_menu();          // discrete DAC menu
        gate_server();       // gate programmer
    }
}

indirect task5(void)
{
                             // task not used
}

indirect backgnd(void)
{
    request(TASK4);
    run_every(TASK0, 1);
    dcmotor_demo();          // run scan blocks
}                            // end of background

// 5key system IO menu
void input_output_menu(void)
{
    lcd_server(3, 0x00000000L, "Input Output Set");
    while (1)
    {
        if (_5key_uinput() == MENU) 
            return;
        if (_5key_diginput() == MENU) 
            return;
        if (_5key_12out() == MENU) 
            return;
        if (_5key_dacout() == MENU) 
            return;
    }
}

// 5key system time date menu
void time_date_menu(void)
{
    lcd_server(3, 0L, "Time Date Set");
    while (1)
    {
        if (_5key_time("time   ", time0, time0_help, 
        sizeof(time0_help), 1, 1, 10) == MENU) 
            return;

        if (_5key_date("date   ", date0, date0_help, 
        sizeof(date0_help), 1, 1, 10) == MENU) 
            return;
    }
}

// 5key system gate programmer
int gate_server(void)
{
    int  i, j, k;
    char old_on_off;

    while (1)
    {
        lcd_server(3, 0L, "GATE PROGRAMMER");
        
        if ((k = _5key_boolean("SCANBLK", &scanblk_on_off, 
        scanblk_help, sizeof(scanblk_help), 1, 10) == MENU)) 
            return k;

        old_on_off = cntrl_on_off;
        
        k = _5key_boolean("ON_OFF ", &cntrl_on_off, cntrl_help, 
        sizeof(cntrl_help), 1, 10);

        if (old_on_off == 1 && cntrl_on_off == 0)
        {
            for (i = 0; i < 12; i++) 
                *(&OUT1 + i) = 0; // make sure all out's zero
            up_dacout(0);         // make sure dacout is zero
            reset_timers();
            reset_cntrs();
            reset_latch();
            reset_fkeys();
            reset_ddacs();
        }
        if (k == MENU) 
            return k;

        if ((k = _5key_boolean("STEP   ", &single_step, single_help,
        sizeof(single_help), 1, 10) == MENU)) 
            return k;

        k = _5key_boolean("RESET  ", &reset_on_off, reset_help,
        sizeof(reset_help), 1, 10);

        if (reset_on_off == 1)
        {
            reset_on_off = 0;
            cntrl_on_off = 0;
            suspend(5);                 // make sure everything is run out
            for (i = 0; i < 12; i++)
                *(&OUT1 + i) = 0;
            reset_p_gates();            // reset gate_points to none
            init_gate(IL1, 1, 1, 1, 1); // init one dummy gate, gate_points=1
        }
        if (k == MENU) 
            return k;
        if ((k = do_the_gates(single_step)) == MENU) 
            return k;
    }
}

//  Scan block demo for Demo Unit Two
#define DCSTART   F1PRESS
#define DCSTOP    F2PRESS
#define ONSWITCH  DIGIN1
#define LITESTART DIGIN3
#define LITESTOP  NOT DIGIN2

#define DLITE1 OUT1
#define DLITE2 OUT2
#define DLITE3 OUT3
#define DLITE4 OUT8
#define DLITE5 OUT9
#define DLITE6 OUT10

extern FuncBlk count_lo2hi;
void dcmotor_demo(void)
{
    char  counter;

    counter = 0;
    while (1)
    {
        funcblk dcmotor always_on
        {
            DLITE4 = 1;
            waitfor(ONSWITCH AND scanblk_on_off);
            DCSTART = 0;     // make sure no key was latch while off
            waitfor(DCSTART);
            DCSTART = 0;
            DLITE4 = 0;
            while (1)
            {
                counter = 0;
                CoBegin(&count_lo2hi);
                cwrelay();
                RELAY1 = 1;
                
                waitfor(counter >= 10 OR DCSTOP OR NOT ONSWITCH OR 
                NOT scanblk_on_off);

                RELAY1 = 0;
                if (DCSTOP OR NOT ONSWITCH OR NOT scanblk_on_off)
                {
                    DCSTOP = 0;
                    relay_off();
                    break;
                }
                counter = 0;
                CoBegin(&count_lo2hi);
                ccwrelay();
                RELAY1 = 1;
                
                waitfor(counter >= 10 OR DCSTOP OR NOT ONSWITCH OR 
                NOT scanblk_on_off);
                
                RELAY1 = 0;
                if (DCSTOP OR NOT ONSWITCH OR NOT scanblk_on_off)
                {
                    DCSTOP = 0;
                    relay_off();
                    break;
                }
            }
        }

        funcblk count_lo2hi
        {
            counter = 0;
            do
            {
                DLITE6 = DIGIN4;
                DLITE5 = NOT DIGIN4;
                waitfor(! DIGIN4 OR NOT ONSWITCH OR NOT scanblk_on_off);
                if (NOT ONSWITCH OR NOT scanblk_on_off) 
                    break;
                DLITE6 = DIGIN4;
                DLITE5 = NOT DIGIN4;
                waitfor(DIGIN4 OR NOT ONSWITCH OR NOT scanblk_on_off);
                if (NOT ONSWITCH OR NOT scanblk_on_off) 
                    break;
            } while (++counter < 10 AND ONSWITCH AND scanblk_on_off);
            DLITE5 = DLITE6 = 0;
        }

        funcblk cycle_lite always_on
        {
            waitfor(LITESTART AND ONSWITCH AND scanblk_on_off);
            while (NOT LITESTOP AND ONSWITCH AND scanblk_on_off)
            {
                DLITE1 = 1;
                
                waitfor(DelayMs(400L) OR LITESTOP OR NOT ONSWITCH
                OR NOT scanblk_on_off);
                
                DLITE1 = 0;
                DLITE2 = 1;
                if (LITESTOP OR NOT ONSWITCH OR NOT scanblk_on_off) 
                    break;
                
                waitfor(DelayMs(200L) OR LITESTOP OR NOT ONSWITCH
                OR NOT scanblk_on_off);
                
                DLITE2 = 0;
                DLITE3 = 1;
                if (LITESTOP OR NOT ONSWITCH OR NOT scanblk_on_off) 
                    break;
                
                waitfor(DelayMs(100L) OR LITESTOP OR NOT ONSWITCH
                OR NOT scanblk_on_off);
                
                DLITE3 = 0;
                if (LITESTOP OR NOT ONSWITCH OR NOT scanblk_on_off) 
                    break;
            }
            DLITE1 = DLITE2 = DLITE3 = 0;
        }
    }                        // end of big while loop
}

// relay clock wise direction for DC motor
void cwrelay(void)
{
    plc_set_relay(0, 2, 0);
    plc_set_relay(0, 3, 0);
    plc_set_relay(0, 0, 1);
    plc_set_relay(0, 1, 1);
}

// relay counter clockwise direction for DC motor
void ccwrelay(void)
{
    plc_set_relay(0, 0, 0);
    plc_set_relay(0, 1, 0);
    plc_set_relay(0, 2, 1);
    plc_set_relay(0, 3, 1);
}

// DC motor is off.
void relay_off(void)
{
    plc_set_relay(0, 0, 0);
    plc_set_relay(0, 1, 0);
    plc_set_relay(0, 2, 0);
    plc_set_relay(0, 3, 0);
}

// Initialize gates for implementation of gate program for Demo Unit Two.
// Same functionality as that implemented by scan block.
// Turn scanblk to OFF.
// Turn on gate_program on_off to ON.
void gate_sample(void)
{
    init_gate(IL9,  INOT, IT5O, IONE, IONE);
    init_gate(IL10, IOR,  IT5I, ID3,  ITAO);
    init_gate(IT5I, IAND, IL9,  IL10, ID2);
    init_gate(IO1,  IAND, IT5I, IONE, IONE);

    init_gate(IL9,  INOT, IT6O, IONE, IONE);
    init_gate(IL10, IOR,  IT6I, IT5O, IZERO);
    init_gate(IT6I, IAND, IL9,  IL10, ID2);
    init_gate(IO2,  IAND, IT6I, IONE, IONE);

    init_gate(IL9,  INOT, IT7O, IONE, IONE);
    init_gate(IL10, IOR,  IT7I, IT6O, IZERO);
    init_gate(IT7I, IAND, IL9,  IL10, ID2);
    init_gate(IO3,  IAND, IT7I, IONE, IONE);

    init_gate(IL9,  INOT, IT8O, IONE, IONE);
    init_gate(IL10, IOR,  IT8I, IT7O, IZERO);
    init_gate(IT8I, IAND, IL9,  IL10, ID2);
    init_gate(IO8,  IAND, IT8I, IONE, IONE);

    init_gate(IL9,  INOT, IT9O, IONE, IONE);
    init_gate(IL10, IOR,  IT9I, IT8O, IZERO);
    init_gate(IT9I, IAND, IL9,  IL10, ID2);
    init_gate(IO9,  IAND, IT9I, IONE, IONE);

    init_gate(IL9,  INOT, ITAO, IONE, IONE);
    init_gate(IL10, IOR,  ITAI, IT9O, IZERO);
    init_gate(ITAI, IAND, IL9,  IL10, ID2);
    init_gate(IO10, IAND, ITAI, IONE, IONE);

    init_gate(IL10, INOT, IR1, IONE,  IONE);
    init_gate(IL9,  IAND, IL10,ITAO,  IONE);
    init_gate(IL8,  IOR,  IL9, IR1,   IZERO);
    init_gate(IR1,  IAND, IL8, ID2,   IONE);
}

// stop DC motor for gate programming
indirect testF4(void)
{
    if (cntrl_on_off && !scanblk_on_off)
    {
        plc_set_relay(0, 0, 0);
        plc_set_relay(0, 1, 0);
        plc_set_relay(0, 2, 0);
        plc_set_relay(0, 3, 0);
    }
    F4PRESS = 1;
}

// change direction of DC motor
// also start DC motor if off
// used by gate programming
indirect testF3(void)
{
    char direction;

    if (cntrl_on_off && !scanblk_on_off)
    {
        if (direction != 0)
        {
            direction = 0;
            plc_set_relay(0, 0, 0);
            plc_set_relay(0, 1, 0);
            plc_set_relay(0, 2, 1);
            plc_set_relay(0, 3, 1);
        }
        else
        {
            direction = 1;
            plc_set_relay(0, 2, 0);
            plc_set_relay(0, 3, 0);
            plc_set_relay(0, 0, 1);
            plc_set_relay(0, 1, 1);
        }
    }
    F3PRESS = 1;
}


/**********************************************************************
scanblk demo for DEMO UNIT ONE
refer to gater.c
#define  START       DIGIN1
#define  STOP        !DIGIN2
#define  SYSTEM_ON   OUT9
#define  SYSTEM_OFF  OUT10

#define  LITE1  OUT5
#define  LITE2  OUT6
#define  LITE3  OUT7

#define  HEATER_ON_OFF  RELAY1
#define  HEATER_LITE    OUT8
#define  TEMP_HIGH      NOT U1IN // U1IN 0, TEMP_HIGH 1
                                 // U1IN 1, TEMP_HIGH 0

#define  COIL1  OUT1
#define  COIL2  OUT2
#define  COIL3  OUT3
#define  COIL4  OUT4

#define  REV_SWITCH DIGIN3
#define  PHOTOCELL  U2IN     // if photocell blocked, U2IN is 1
                             // if photocell not blocked, U2IN is 0

extern FuncBlk Sequence_Lite;
extern FuncBlk Stepper;
extern FuncBlk Count_Rev;
extern FuncBlk Cool_Down;

void demo_scan(void)
{
   char  which_step;
   char  first_time;
   int   pulse_counter;
   char  cooled_down;
   char  count_done;

   which_step  = 0;
   cooled_down = 0;
   count_done  = 0;
   SYSTEM_ON   = 0; 
   SYSTEM_OFF  = 1;          // system is off at power up
   
   while(1)
   {
       funcblk Start_On always_on // detect on off condition
       {
           waitfor(START);
           SYSTEM_ON  = 1;
           SYSTEM_OFF = 0;
           CoBegin(&Cool_Down);   // cool down if hot
           waitfor(cooled_down);
           do
           {
               CoBegin(&Sequence_Lite);
               waitfor(STOP OR (count_done AND cooled_down));
               if(STOP)
               { 
                   SYSTEM_ON = 0;  
                   SYSTEM_OFF = 1; 
                   break;
               }
               else 
               {  
                   count_done  = 0; 
                   cooled_down = 0; 
               }
           } while(1);
       }

       funcblk Cool_Down     // cool down with the fan
       {
             cooled_down = 0;
             if(TEMP_HIGH)   // make sure temperature is high
             {
             up_dacout(9000);
             waitfor(NOT TEMP_HIGH); // fan is always cooling
             up_dacout(0);   // turn fan off
             }
             cooled_down = 1;
       }

       funcblk Sequence_Lite // sequence the lights and
                             // turn on the heaters
       {
           first_time = 0;
           do
           {
               LITE1 = 1;
               waitfor(DelaySec(1L) OR SYSTEM_OFF OR TEMP_HIGH);
               if(SYSTEM_OFF OR TEMP_HIGH)
                   break;
               LITE1 = 0; LITE2 = 1;
               waitfor(DelayMs(500L) OR SYSTEM_OFF OR TEMP_HIGH);
               if(SYSTEM_OFF OR TEMP_HIGH)
                   break;
               LITE2 = 0;LITE3 = 1;
               waitfor(DelayMs(250L) OR SYSTEM_OFF OR TEMP_HIGH);
               if(SYSTEM_OFF OR TEMP_HIGH)
                   break;
               LITE3 = 0;
               if(first_time == 0)
               {
                   first_time = 1;
                   HEATER_ON_OFF=1; // turn heater on
                   HEATER_LITE = 1; // and heater light
               }
           } while(1);
           HEATER_ON_OFF = 0;
           HEATER_LITE = 0;
           LITE1 = LITE2 = LITE3 = 0;
           if(TEMP_HIGH AND SYSTEM_ON) // if temp high and system on
           { 
               CoBegin(&Count_Rev);
               CoBegin(&Stepper);
               waitfor(SYSTEM_OFF OR PHOTOCELL);
               if(PHOTOCELL) 
                   CoBegin(&Cool_Down);
           }
           else if(TEMP_HIGH AND SYSTEM_OFF)
           {
               CoBegin(&Cool_Down);
           }
       }

       funcblk Count_Rev     // detect rising edges for 3 times
       {
           pulse_counter = 0;
           do
           {
               waitfor(NOT REV_SWITCH OR SYSTEM_OFF);
               if(SYSTEM_OFF)
                   break;
                             // wait for a low state
               waitfor(REV_SWITCH OR SYSTEM_OFF);
               if(SYSTEM_OFF)
                   break;
                             //  wait for low to high transition
               pulse_counter++;
               if(pulse_counter>=3) 
                   break;
           } while(1);
       }

       funcblk Stepper       // sequence the stepper motor
       {
           do
           {
               which_step++;
               if(which_step>4)
               which_step=1;
               switch(which_step)
               {
                   case 1:
                       COIL1=1; COIL2=COIL3=COIL4=0;
                       break;
                   case 2:
                       COIL2=1; COIL1=COIL3=COIL4=0;
                       break;
                   case 3:
                       COIL3=1; COIL1=COIL2=COIL4=0;
                       break;
                   case 4:
                       COIL4=1; COIL1=COIL2=COIL3=0;
                       break;
               }
               waitfor(DelayMs(20L) OR SYSTEM_OFF OR (pulse_counter>=3));
               if(pulse_counter>=3) 
                   count_done=1;
               if(SYSTEM_OFF OR (pulse_counter>=3))
               { 
                   COIL1 = COIL2 = COIL3 = COIL4 =0;
                   break;
               }
           } while(1);
       }
   }                         // end of big while
}
***********************************************************************/

/**********************************************************************
scanblk demo for traffic/pedestrian light system

#define ON_TRAFFIC  DIGIN1
#define CROSS  NOT DIGIN2
#define TRAFFIC_RED OUT1
#define TRAFFIC_GREEN OUT3
#define TRAFFIC_YELLOW OUT2
#define WALK_GREEN OUT10
#define WALK_RED  OUT8
#define WALK_YELLOW OUT9

extern FuncBlk traffic_lite;

void traffic_demo(void)
{
     char cycle_lites;
     while(1)
     {
     funcblk Wait_to_Cross  always_on
     {
       waitfor(ON_TRAFFIC);
       TRAFFIC_GREEN=1;
       WALK_RED = 1;
       while(1)
       {
       waitfor(CROSS);
       CoBegin(&traffic_lite);
       }
     }

    funcblk traffic_lite
     {
       cycle_lites = 5;
       waitfor(DelaySec(1L)); // wait for 1 sec
       TRAFFIC_YELLOW = 1;   // 
       TRAFFIC_GREEN = 0;
       waitfor(DelaySec(1L));
       TRAFFIC_YELLOW=0;
       TRAFFIC_RED=1;
       waitfor(DelaySec(1L));
       WALK_RED=0;
       WALK_GREEN=1;

       waitfor(DelaySec(2L));
       do
       {
       WALK_GREEN=0;
       waitfor(DelayMs(500L));
       WALK_GREEN=1;
       waitfor(DelayMs(500L));
       }while(--cycle_lites>0);

       WALK_GREEN = 0;
       WALK_RED = 1;
       waitfor(DelaySec(2L));
       TRAFFIC_RED=0;
       TRAFFIC_GREEN=1;
       }
    }
}
***********************************************************************/

/************************************************************************
scanblk demo for motor pump system

#define START_MACHINE  DIGIN1
#define STOP_MACHINE NOT DIGIN2
#define MCOIL1      OUT1
#define MCOIL2      OUT2
#define MCOIL3      OUT3
#define MCOIL4      OUT4
#define OFF_MACHINE OUT10
#define ON_MACHINE  OUT9
#define PUMP_ON     OUT5

extern FuncBlk motor;

void pump_motor_demo(void)
{
    char which_step;
    which_step = 0;

    ON_MACHINE=0;
    OFF_MACHINE=1;
    PUMP_ON=0;

    while(1)
    {
       funcblk check_for_start  always_on
       {
         waitfor(START_MACHINE);
           {
             ON_MACHINE=1;
             OFF_MACHINE=0;
             PUMP_ON = 1;
             up_dacout(9000);
             waitfor(DelaySec(2L));
             CoBegin(&motor);
           }
          waitfor(STOP_MACHINE);
           {
             OFF_MACHINE=1;
             ON_MACHINE=0;
             waitfor(DelaySec(5L));
             up_dacout(0);
             PUMP_ON=0;
           }
       }

       funcblk motor         // sequence the stepper motor
         {
         do
         {
         which_step++;
         if(which_step>4)
             which_step=1;
         switch(which_step)
         {
           case 1:
               MCOIL1=1; MCOIL2=MCOIL3=MCOIL4=0;
                   break;
           case 2:
               MCOIL2=1; MCOIL1=MCOIL3=MCOIL4=0;
                   break;
           case 3:
               MCOIL3=1; MCOIL1=MCOIL2=MCOIL4=0;
                    break;
           case 4:
               MCOIL4=1; MCOIL1=MCOIL2=MCOIL3=0;
                    break;
           }
           waitfor(DelayMs(20L) OR OFF_MACHINE);
           if(OFF_MACHINE)
                 { MCOIL1 = MCOIL2 = MCOIL3 = MCOIL4 =0;
                   break;
                 }
          }while(1);
        }

    }                        // end of big while
}
***************************************************************************/




