www.pudn.com > ucosii_block.rar > DIO.C


/* 
********************************************************************************************************* 
*                                   Embedded Systems Building Blocks 
*                                Complete and Ready-to-Use Modules in C 
* 
*                                         Discrete I/O Module 
* 
*                            (c) Copyright 1999, Jean J. Labrosse, Weston, FL 
*                                          All Rights Reserved 
* 
* Filename   : DIO.C 
* Programmer : Jean J. Labrosse 
********************************************************************************************************* 
*/ 
 
/* 
********************************************************************************************************* 
*                                           INCLUDE FILES 
********************************************************************************************************* 
*/ 
 
#define  DIO_GLOBALS 
#include "includes.h" 
 
/* 
********************************************************************************************************* 
*                                          LOCAL VARIABLES 
********************************************************************************************************* 
*/ 
 
static  OS_STK      DIOTaskStk[DIO_TASK_STK_SIZE]; 
 
/* 
********************************************************************************************************* 
*                                      LOCAL FUNCTION PROTOTYPES 
********************************************************************************************************* 
*/ 
 
 
static  void        DIIsTrig(DIO_DI *pdi); 
 
static  void        DIOTask(void *data); 
 
static  void        DIUpdate(void); 
 
static  BOOLEAN     DOIsBlinkEn(DIO_DO *pdo); 
static  void        DOUpdate(void); 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                               CONFIGURE DISCRETE INPUT EDGE DETECTION 
* 
* Description : This function is used to configure the edge detection capability of the discrete input 
*               channel. 
* Arguments   : n     is the discrete input channel to configure (0..DIO_MAX_DI-1). 
*               fnct  is a pointer to a function that will be executed if the desired edge has been 
*                     detected. 
*               arg   is a pointer to arguments that are passed to the function called. 
* Returns     : None. 
********************************************************************************************************* 
*/ 
 
#if  DI_EDGE_EN 
void  DICfgEdgeDetectFnct (INT8U n, void (*fnct)(void *), void *arg) 
{ 
    DIO_DI  *pdi; 
 
 
    if (n < DIO_MAX_DI) { 
        pdi                = &DITbl[n]; 
        OS_ENTER_CRITICAL(); 
        pdi->DITrigFnct    = fnct; 
        pdi->DITrigFnctArg = arg; 
        OS_EXIT_CRITICAL(); 
    } 
} 
#endif 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                   CONFIGURE DISCRETE INPUT MODE 
* 
* Description : This function is used to configure the mode of a discrete input channel. 
* Arguments   : n     is the discrete input channel to configure (0..DIO_MAX_DI-1). 
*               mode  is the desired mode and can be: 
*                     DI_MODE_LOW               input is forced LOW 
*                     DI_MODE_HIGH              input is forced HIGH 
*                     DI_MODE_DIRECT            input is based on state of physical sensor (default) 
*                     DI_MODE_INV               input is based on the complement of physical sensor 
*                     DI_MODE_EDGE_LOW_GOING    a LOW-going  transition is detected 
*                     DI_MODE_EDGE_HIGH_GOING   a HIGH-going transition is detected 
*                     DI_MODE_EDGE_BOTH         both a LOW-going and a HIGH-going transition are detected 
*                     DI_MODE_TOGGLE_LOW_GOING  a LOW-going  transition is detected in toggle mode 
*                     DI_MODE_TOGGLE_HIGH_GOING a HIGH-going transition is detected in toggle mode 
* Returns     : None. 
* Notes       : Edge detection is only available if the configuration constant DI_EDGE_EN is set to 1. 
********************************************************************************************************* 
*/ 
 
void  DICfgMode (INT8U n, INT8U mode) 
{ 
    if (n < DIO_MAX_DI) { 
        OS_ENTER_CRITICAL(); 
        DITbl[n].DIModeSel = mode; 
        OS_EXIT_CRITICAL(); 
    } 
} 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                     CLEAR A DISCRETE INPUT CHANNEL 
* 
* Description : This function clears the number of edges detected if the discrete input channel is 
*               configured to count edges. 
* Arguments   : n     is the discrete input channel (0..DIO_MAX_DI-1) to clear. 
* Returns     : none 
********************************************************************************************************* 
*/ 
 
#if  DI_EDGE_EN 
void  DIClr (INT8U n) 
{ 
    DIO_DI  *pdi; 
 
 
    if (n < DIO_MAX_DI) { 
        pdi = &DITbl[n]; 
        OS_ENTER_CRITICAL(); 
        if (pdi->DIModeSel == DI_MODE_EDGE_LOW_GOING  ||        /* See if edge detection mode selected */ 
            pdi->DIModeSel == DI_MODE_EDGE_HIGH_GOING || 
            pdi->DIModeSel == DI_MODE_EDGE_BOTH) { 
            pdi->DIVal = 0;                                     /* Clear the number of edges detected  */ 
        } 
        OS_EXIT_CRITICAL(); 
    } 
} 
#endif 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                GET THE STATE OF A DISCRETE INPUT CHANNEL 
* 
* Description : This function is used to get the current state of a discrete input channel.  If the input 
*               mode is set to one of the edge detection modes, the number of edges detected is returned. 
* Arguments   : n     is the discrete input channel (0..DIO_MAX_DI-1). 
* Returns     : 0     if the discrete input is negated  or, if an edge has not been detected 
*               1     if the discrete input is asserted 
*               > 0   if edges have been detected 
********************************************************************************************************* 
*/ 
 
INT16U  DIGet (INT8U n) 
{ 
    INT16U  val; 
 
 
    if (n < DIO_MAX_DI) { 
        OS_ENTER_CRITICAL(); 
        val = DITbl[n].DIVal;                              /* Get state of DI channel                  */ 
        OS_EXIT_CRITICAL(); 
        return (val); 
    } else { 
        return (0);                                        /* Return negated for invalid channel       */ 
    } 
} 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                         DETECT EDGE ON INPUT 
* 
* Description : This function is called to detect an edge (low-going, high-going or both) on the selected 
*               discrete input. 
* Arguments   : pdi    is a pointer to the discrete input data structure. 
* Returns     : none 
********************************************************************************************************* 
*/ 
 
#if DI_EDGE_EN 
static  void  DIIsTrig (DIO_DI *pdi) 
{ 
    BOOLEAN  trig; 
 
 
    trig = FALSE; 
    switch (pdi->DIModeSel) { 
        case DI_MODE_EDGE_LOW_GOING:                       /* Negative going edge                      */ 
             if (pdi->DIPrev == 1 && pdi->DIIn == 0) { 
                 trig = TRUE; 
             } 
             break; 
 
        case DI_MODE_EDGE_HIGH_GOING:                      /* Positive going edge                      */ 
             if (pdi->DIPrev == 0 && pdi->DIIn == 1) { 
                 trig = TRUE; 
             } 
             break; 
 
        case DI_MODE_EDGE_BOTH:                            /* Both positive and negative going         */ 
             if ((pdi->DIPrev == 1 && pdi->DIIn == 0) || 
                 (pdi->DIPrev == 0 && pdi->DIIn == 1)) { 
                 trig = TRUE; 
             } 
             break; 
    } 
    if (trig == TRUE) {                                    /* See if edge detected                     */ 
        if (pdi->DITrigFnct != NULL) {                     /* Yes, see used defined a function         */ 
            (*pdi->DITrigFnct)(pdi->DITrigFnctArg);        /* Yes, execute the user function           */ 
        } 
        if (pdi->DIVal < 255) {                            /* Increment number of edges counted        */ 
            pdi->DIVal++; 
        } 
    } 
    pdi->DIPrev = pdi->DIIn;                               /* Memorize previous input state            */ 
} 
#endif 
 
/*$PAGE*/ 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                    UPDATE DISCRETE IN CHANNELS 
* 
* Description : This function processes all of the discrete input channels. 
* Arguments   : None. 
* Returns     : None. 
********************************************************************************************************* 
*/ 
 
static  void  DIUpdate (void) 
{ 
    INT8U    i; 
    DIO_DI  *pdi; 
 
 
    pdi = &DITbl[0]; 
    for (i = 0; i < DIO_MAX_DI; i++) { 
        if (pdi->DIBypassEn == FALSE) {          /* See if discrete input channel is bypassed          */ 
            switch (pdi->DIModeSel) {            /* No, process channel                                */ 
                case DI_MODE_LOW:                /* Input is forced low                                */ 
                     pdi->DIVal = 0; 
                     break; 
 
                case DI_MODE_HIGH:               /* Input is forced high                               */ 
                     pdi->DIVal = 1; 
                     break; 
 
                case DI_MODE_DIRECT:                  /* Input is based on state of physical input     */ 
                     pdi->DIVal = (INT8U)pdi->DIIn;   /* Obtain the state of the sensor                */ 
                     break; 
 
                case DI_MODE_INV:                /* Input is based on the complement state of input    */ 
                     pdi->DIVal = (INT8U)(pdi->DIIn ? 0 : 1); 
                     break; 
 
#if DI_EDGE_EN 
                case DI_MODE_EDGE_LOW_GOING: 
                case DI_MODE_EDGE_HIGH_GOING: 
                case DI_MODE_EDGE_BOTH: 
                     DIIsTrig(pdi);              /* Handle edge triggered mode                         */ 
                     break; 
#endif 
/*$PAGE*/ 
                case DI_MODE_TOGGLE_LOW_GOING: 
                     if (pdi->DIPrev == 1 && pdi->DIIn == 0) { 
                         pdi->DIVal = pdi->DIVal ? 0 : 1; 
                     } 
                     pdi->DIPrev = pdi->DIIn; 
                     break; 
 
                case DI_MODE_TOGGLE_HIGH_GOING: 
                     if (pdi->DIPrev == 0 && pdi->DIIn == 1) { 
                         pdi->DIVal = pdi->DIVal ? 0 : 1; 
                     } 
                     pdi->DIPrev = pdi->DIIn; 
                     break; 
            } 
        } 
        pdi++;                                   /* Point to next DIO_DO element                       */ 
    } 
} 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                  DISCRETE I/O MANAGER INITIALIZATION 
* 
* Description : This function initializes the discrete I/O manager module. 
* Arguments   : None 
* Returns     : None. 
********************************************************************************************************* 
*/ 
 
void  DIOInit (void) 
{ 
    INT8U    err; 
    INT8U    i; 
    DIO_DI  *pdi; 
    DIO_DO  *pdo; 
 
 
    pdi = &DITbl[0]; 
    for (i = 0; i < DIO_MAX_DI; i++) { 
        pdi->DIVal         = 0; 
        pdi->DIBypassEn    = FALSE; 
        pdi->DIModeSel     = DI_MODE_DIRECT;     /* Set the default mode to direct input               */ 
#if DI_EDGE_EN 
        pdi->DITrigFnct    = (void *)0;          /* No function to execute when transition detected    */ 
        pdi->DITrigFnctArg = (void *)0; 
#endif 
        pdi++; 
    } 
    pdo = &DOTbl[0]; 
    for (i = 0; i < DIO_MAX_DO; i++) { 
        pdo->DOOut        = 0; 
        pdo->DOBypassEn   = FALSE; 
        pdo->DOModeSel    = DO_MODE_DIRECT;      /* Set the default mode to direct output              */ 
        pdo->DOInv        = FALSE; 
#if DO_BLINK_MODE_EN 
        pdo->DOBlinkEnSel = DO_BLINK_EN_NORMAL;  /* Blinking is enabled by direct user request         */ 
        pdo->DOA          = 1; 
        pdo->DOB          = 2; 
        pdo->DOBCtr       = 2; 
#endif 
        pdo++; 
    } 
#if DO_BLINK_MODE_EN 
    DOSyncCtrMax = 100; 
#endif 
    DIOInitIO(); 
    OSTaskCreate(DIOTask, (void *)0, &DIOTaskStk[DIO_TASK_STK_SIZE], DIO_TASK_PRIO); 
} 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                    DISCRETE I/O MANAGER TASK 
* 
* Description : This task is created by DIOInit() and is responsible for updating the discrete inputs and 
*               discrete outputs. 
*               DIOTask() executes every DIO_TASK_DLY_TICKS. 
* Arguments   : None. 
* Returns     : None. 
********************************************************************************************************* 
*/ 
 
static  void  DIOTask (void *data) 
{ 
    data = data;                                      /* Avoid compiler warning (uC/OS requirement)    */ 
    for (;;) { 
        OSTimeDly(DIO_TASK_DLY_TICKS);                /* Delay between execution of DIO manager        */ 
        DIRd();                                       /* Read physical inputs and map to DI channels   */ 
        DIUpdate();                                   /* Update all DI channels                        */ 
        DOUpdate();                                   /* Update all DO channels                        */ 
        DOWr();                                       /* Map DO channels to physical outputs           */ 
    } 
} 
/*$PAGE*/ 
 
/* 
********************************************************************************************************* 
*                                  SET THE STATE OF THE BYPASSED SENSOR 
* 
* Description : This function is used to set the state of the bypassed sensor.  This function is used to 
*               simulate the presence of the sensor.  This function is only valid if the bypass 'switch' 
*               is open. 
* Arguments   : n     is the discrete input channel (0..DIO_MAX_DI-1). 
*               val   is the state of the bypassed sensor: 
*                         0     indicates a  negated  sensor 
*                         1     indicates an asserted sensor 
*                         > 0   indicates the number of edges detected in edge mode 
* Returns     : None. 
********************************************************************************************************* 
*/ 
 
void  DISetBypass (INT8U n, INT16U val) 
{ 
    DIO_DI  *pdi; 
 
 
    if (n < DIO_MAX_DI) { 
        pdi = &DITbl[n]; 
        OS_ENTER_CRITICAL(); 
        if (pdi->DIBypassEn == TRUE) {           /* See if sensor is bypassed                          */ 
            pdi->DIVal = val;                    /* Yes, then set the new state of the DI channel      */ 
        } 
        OS_EXIT_CRITICAL(); 
    } 
} 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                               SET THE STATE OF THE SENSOR BYPASS SWITCH 
* 
* Description : This function is used to set the state of the sensor bypass switch.  The sensor is 
*               bypassed when the 'switch' is open (i.e. DIBypassEn is set to TRUE). 
* Arguments   : n     is the discrete input channel (0..DIO_MAX_DI-1). 
*               state is the state of the bypass switch: 
*                         FALSE disables sensor bypass (i.e. the bypass 'switch' is closed) 
*                         TRUE  enables  sensor bypass (i.e. the bypass 'switch' is open) 
* Returns     : None. 
********************************************************************************************************* 
*/ 
 
void  DISetBypassEn (INT8U n, BOOLEAN state) 
{ 
    if (n < DIO_MAX_DI) { 
        OS_ENTER_CRITICAL(); 
        DITbl[n].DIBypassEn = state; 
        OS_EXIT_CRITICAL(); 
    } 
} 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                             CONFIGURE THE DISCRETE OUTPUT BLINK MODE 
* 
* Description : This function is used to configure the blink mode of the discrete output channel. 
* Arguments   : n     is the discrete output channel (0..DIO_MAX_DO-1). 
*               mode  is the desired blink mode: 
*                     DO_BLINK_EN         Blink is always enabled 
*                     DO_BLINK_EN_NORMAL  Blink depends on user request's state 
*                     DO_BLINK_EN_INV     Blink depends on the complemented user request's state 
*               a     is the ON  time relative to how often the DIO task executes  (1..250) 
*               b     is the period (in DO_MODE_BLINK_ASYNC mode) (1..250) 
* Returns     : None. 
********************************************************************************************************* 
*/ 
 
#if  DO_BLINK_MODE_EN 
void  DOCfgBlink (INT8U n, INT8U mode, INT8U a, INT8U b) 
{ 
    DIO_DO  *pdo; 
 
 
    if (n < DIO_MAX_DO) { 
        pdo               = &DOTbl[n]; 
        OS_ENTER_CRITICAL(); 
        pdo->DOBlinkEnSel = mode; 
        pdo->DOA          = a; 
        pdo->DOB          = b; 
        pdo->DOBCtr       = 0; 
        OS_EXIT_CRITICAL(); 
    } 
} 
#endif 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                   CONFIGURE DISCRETE OUTPUT MODE 
* 
* Description : This function is used to configure the mode of a discrete output channel. 
* Arguments   : n     is the discrete output channel to configure (0..DIO_MAX_DO-1). 
*               mode  is the desired mode and can be: 
*                     DO_MODE_LOW              output is forced LOW 
*                     DO_MODE_HIGH             output is forced HIGH 
*                     DO_MODE_DIRECT           output is based on state of DOBypass 
*                     DO_MODE_BLINK_SYNC       output will be blinking synchronously with DOSyncCtr 
*                     DO_MODE_BLINK_ASYNC      output will be blinking based on DOA and DOB 
*               inv   indicates whether the output will be inverted: 
*                     TRUE   forces the output to be inverted 
*                     FALSE  does not cause any inversion 
* Returns     : None. 
********************************************************************************************************* 
*/ 
 
void  DOCfgMode (INT8U n, INT8U mode, BOOLEAN inv) 
{ 
    DIO_DO  *pdo; 
     
     
    if (n < DIO_MAX_DO) { 
        pdo            = &DOTbl[n]; 
        OS_ENTER_CRITICAL(); 
        pdo->DOModeSel = mode; 
        pdo->DOInv     = inv; 
        OS_EXIT_CRITICAL(); 
    } 
} 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                 GET THE STATE OF THE DISCRETE OUTPUT 
* 
* Description : This function is used to obtain the state of the discrete output. 
* Arguments   : n     is the discrete output channel (0..DIO_MAX_DO-1). 
* Returns     : TRUE  if the output is asserted. 
*               FALSE if the output is negated. 
********************************************************************************************************* 
*/ 
 
BOOLEAN  DOGet (INT8U n) 
{ 
    BOOLEAN  out; 
 
 
    if (n < DIO_MAX_DO) { 
        OS_ENTER_CRITICAL(); 
        out = DOTbl[n].DOOut; 
        OS_EXIT_CRITICAL(); 
        return (out); 
    } else { 
        return (FALSE); 
    } 
} 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                         SEE IF BLINK IS ENABLED 
* 
* Description : See if blink mode is enabled. 
* Arguments   : pdo    is a pointer to the discrete output data structure. 
* Returns     : TRUE   if blinking is enabled 
*               FALSE  otherwise 
********************************************************************************************************* 
*/ 
 
#if DO_BLINK_MODE_EN 
static  BOOLEAN  DOIsBlinkEn (DIO_DO *pdo) 
{ 
    BOOLEAN  en; 
 
 
    en = FALSE; 
    switch (pdo->DOBlinkEnSel) { 
        case DO_BLINK_EN:                   /* Blink is always enabled                                 */ 
             en = TRUE; 
             break; 
 
        case DO_BLINK_EN_NORMAL:            /* Blink depends on user request's state                   */ 
             en = pdo->DOBypass; 
             break; 
 
        case DO_BLINK_EN_INV:               /* Blink depends on the complemented user request's state  */ 
             en = pdo->DOBypass ? FALSE : TRUE; 
             break; 
    } 
    return (en); 
} 
#endif 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                 SET THE STATE OF THE DISCRETE OUTPUT 
* 
* Description : This function is used to set the state of the discrete output. 
* Arguments   : n     is the discrete output channel (0..DIO_MAX_DO-1). 
*               state is the desired state of the output: 
*                         FALSE indicates a  negated  output 
*                         TRUE  indicates an asserted output 
* Returns     : None. 
* Notes       : The actual output will be complemented if 'DIInv' is set to TRUE. 
********************************************************************************************************* 
*/ 
 
void  DOSet (INT8U n, BOOLEAN state) 
{ 
    if (n < DIO_MAX_DO) { 
        OS_ENTER_CRITICAL(); 
        DOTbl[n].DOCtrl = state; 
        OS_EXIT_CRITICAL(); 
    } 
} 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                  SET THE STATE OF THE BYPASSED OUTPUT 
* 
* Description : This function is used to set the state of the bypassed output.  This function is used to 
*               override (or bypass) the application software and allow the output to be controlled 
*               directly.  This function is only valid if the bypass switch is open. 
* Arguments   : n       is the discrete output channel (0..DIO_MAX_DO-1). 
*               state   is the desired state of the output: 
*                         FALSE indicates a  negated  output 
*                         TRUE  indicates an asserted output 
* Returns     : None. 
* Notes       : 1) The actual output will be complemented if 'DIInv' is set to TRUE. 
*               2) In blink mode, this allows blinking to be enabled or not. 
********************************************************************************************************* 
*/ 
 
void  DOSetBypass (INT8U n, BOOLEAN state) 
{ 
    DIO_DO  *pdo; 
     
     
    if (n < DIO_MAX_DO) { 
        pdo = &DOTbl[n]; 
        OS_ENTER_CRITICAL(); 
        if (pdo->DOBypassEn == TRUE) { 
            pdo->DOBypass = state; 
        } 
        OS_EXIT_CRITICAL(); 
    } 
} 
 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                  SET THE STATE OF THE OUTPUT BYPASS 
* 
* Description : This function is used to set the state of the output bypass switch.  The output is 
*               bypassed when the 'switch' is open (i.e. DOBypassEn is set to TRUE). 
* Arguments   : n     is the discrete output channel (0..DIO_MAX_DO-1). 
*               state is the state of the bypass switch: 
*                         FALSE disables output bypass (i.e. the switch is closed) 
*                         TRUE  enables  output bypass (i.e. the switch is open) 
* Returns     : None. 
********************************************************************************************************* 
*/ 
 
void  DOSetBypassEn (INT8U n, BOOLEAN state) 
{ 
    if (n < DIO_MAX_DO) { 
        OS_ENTER_CRITICAL(); 
        DOTbl[n].DOBypassEn = state; 
        OS_EXIT_CRITICAL(); 
    } 
} 
 
/*$PAGE*/ 
 
/* 
********************************************************************************************************* 
*                            SET THE MAXIMUM VALUE FOR THE SYNCHRONOUS COUNTER 
* 
* Description : This function is used to set the maximum value taken by the synchronous counter which is 
*               used in the synchronous blink mode. 
* Arguments   : val   is the maximum value for the counter (1..255) 
* Returns     : None. 
********************************************************************************************************* 
*/ 
 
#if  DO_BLINK_MODE_EN 
void  DOSetSyncCtrMax (INT8U val) 
{ 
    OS_ENTER_CRITICAL(); 
    DOSyncCtrMax = val; 
    DOSyncCtr    = val; 
    OS_EXIT_CRITICAL(); 
} 
#endif 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                    UPDATE DISCRETE OUT CHANNELS 
* 
* Description : This function is called to process all of the discrete output channels. 
* Arguments   : None. 
* Returns     : None. 
********************************************************************************************************* 
*/ 
 
static  void  DOUpdate (void) 
{ 
    INT8U     i; 
    BOOLEAN   out; 
    DIO_DO   *pdo; 
 
 
    pdo = &DOTbl[0]; 
    for (i = 0; i < DIO_MAX_DO; i++) {           /* Process all discrete output channels               */ 
        if (pdo->DOBypassEn == FALSE) {          /* See if DO channel is enabled                       */ 
            pdo->DOBypass = pdo->DOCtrl;         /* Obtain control state from application              */ 
        } 
        out = FALSE;                             /* Assume that the output will be low unless changed  */ 
        switch (pdo->DOModeSel) { 
            case DO_MODE_LOW:                    /* Output will in fact be low                         */ 
                 break; 
 
            case DO_MODE_HIGH:                   /* Output will be high                                */ 
                 out = TRUE; 
                 break; 
 
            case DO_MODE_DIRECT:                 /* Output is based on state of user supplied state    */ 
                 out = pdo->DOBypass; 
                 break; 
/*$PAGE*/ 
#if DO_BLINK_MODE_EN 
            case DO_MODE_BLINK_SYNC:                       /* Sync. Blink mode                         */ 
                 if (DOIsBlinkEn(pdo)) {                   /* See if Blink is enabled ...              */ 
                     if (pdo->DOA >= DOSyncCtr) {          /* ... yes, High when below threshold       */ 
                         out = TRUE; 
                     } 
                 } 
                 break; 
 
            case DO_MODE_BLINK_ASYNC:                      /* Async. Blink mode                        */ 
                 if (DOIsBlinkEn(pdo)) {                   /* See if Blink is enabled ...              */ 
                     if (pdo->DOA >= pdo->DOBCtr) {        /* ... yes, High when below threshold       */ 
                         out = TRUE; 
                     } 
                 } 
                 if (pdo->DOBCtr < pdo->DOB) {             /* Update the threshold counter             */ 
                     pdo->DOBCtr++; 
                 } else { 
                     pdo->DOBCtr = 0; 
                 } 
                 break; 
#endif 
        } 
        if (pdo->DOInv == TRUE) {                          /* See if output needs to be inverted ...   */ 
            pdo->DOOut = out ? FALSE : TRUE;               /* ... yes, complement output               */ 
        } else { 
            pdo->DOOut = out;                              /* ... no,  no inversion!                   */ 
        } 
        pdo++;                                             /* Point to next DIO_DO element             */ 
    } 
#if DO_BLINK_MODE_EN 
    if (DOSyncCtr < DOSyncCtrMax) {                        /* Update the synchronous free running ctr  */ 
        DOSyncCtr++; 
    } else { 
        DOSyncCtr = 0; 
    } 
#endif 
} 
/*$PAGE*/ 
#ifndef CFG_C 
/* 
********************************************************************************************************* 
*                                      INITIALIZE PHYSICAL I/Os 
* 
* Description : This function is by DIOInit() to initialze the physical I/O used by the DIO driver. 
* Arguments   : None. 
* Returns     : None. 
* Notes       : The physical I/O is assumed to be an 82C55 chip initialized as follows: 
*                   Port A = OUT  (Discrete outputs) 
*                   Port B = IN   (Discrete inputs) 
*                   Port C = OUT  (not used) 
********************************************************************************************************* 
*/ 
 
void  DIOInitIO (void) 
{ 
    outp(0x0303, 0x82);                          /* Port A = OUT, Port B = IN, Port C = OUT            */ 
} 
 
/* 
********************************************************************************************************* 
*                                         READ PHYSICAL INPUTS 
* 
* Description : This function is called to read and map all of the physical inputs used for discrete 
*               inputs and map these inputs to their appropriate discrete input data structure. 
* Arguments   : None. 
* Returns     : None. 
********************************************************************************************************* 
*/ 
 
void  DIRd (void) 
{ 
    DIO_DI  *pdi; 
    INT8U    i; 
    INT8U    in; 
    INT8U    msk; 
 
 
    pdi = &DITbl[0];                                       /* Point at beginning of discrete inputs    */ 
    msk = 0x01;                                            /* Set mask to extract bit 0                */ 
    in  = inp(0x0301);                                     /* Read the physical port (8 bits)          */ 
    for (i = 0; i < 8; i++) {                              /* Map all 8 bits to first 8 DI channels    */ 
        pdi->DIIn   = (BOOLEAN)(in & msk) ? 1 : 0; 
        msk       <<= 1; 
        pdi++; 
    } 
} 
/*$PAGE*/ 
/* 
********************************************************************************************************* 
*                                       UPDATE PHYSICAL OUTPUTS 
* 
* Description : This function is called to map all of the discrete output channels to their appropriate 
*               physical destinations. 
* Arguments   : None. 
* Returns     : None. 
********************************************************************************************************* 
*/ 
 
void  DOWr (void) 
{ 
    DIO_DO  *pdo; 
    INT8U    i; 
    INT8U    out; 
    INT8U    msk; 
 
 
    pdo = &DOTbl[0];                        /* Point at first discrete output channel                  */ 
    msk = 0x01;                             /* First DO will be mapped to bit 0                        */ 
    out = 0x00;                             /* Local 8 bit port image                                  */ 
    for (i = 0; i < 8; i++) {               /* Map first 8 DO to 8 bit port image                      */ 
        if (pdo->DOOut == TRUE) { 
            out |= msk; 
        } 
        msk <<= 1; 
        pdo++; 
    } 
    outp(0x0300, out);                      /* Output port image to physical port                      */ 
} 
#endif