/****************************************************************************/
/* Copyright 1992, 1993 MBARI                                               */
/****************************************************************************/
/* Summary  : IBC Parallel Input/Output Board Functions                     */
/* Filename : pio.c                                                         */
/* Author   : Andrew Pearce                                                 */
/* Project  : New ROV IBC Based Data Concentrator                           */
/* Version  : 1.0                                                           */
/* Created  : 10/09/92                                                      */
/* Modified : 04/01/93                                                      */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/* $Header: /usr/tiburon/.cvsroot/micro/ibc/boards/pio/pio.c,v 1.2 1997/05/07 15:32:49 pean Exp $
 * $Log: pio.c,v $
 * Revision 1.2  1997/05/07 15:32:49  pean
 * Cleaned up Include files and makefile for new directory structure.
 *
 * Revision 1.1.1.1  1997/05/02 18:51:32  pean
 * Initial check in of IBC microcontroller software
 *
 * Revision 1.1  93/07/02  09:37:42  09:37:42  pean (Andrew Pearce)
 * Initial revision
 *
*/
/****************************************************************************/

#pragma model(196)
#pragma nosignedchar

#include "C:/C96/include/stddef.h"      /* C Standard Definitions           */
#include "const.h"                      /* Misc. constants - TRUE/FALSE etc */
#include "types.h"                      /* MBARI style guide declarations   */
#include "malloc.h"                     /* Malloc support routines          */
#include "microdef.h"                   /* Microcontroller definitions      */
#include "microCmd.h"                   /* microcontroller commands         */
#include "microlib.h"                   /* Microcontroller Library decls.   */
#include "applay.h"                     /* Application layer funcitions     */

#include "ibc_card.h"                   /* IBC Board Types and Addresses    */
#include "ibc_cmd.h"                    /* Core IBC application definitions */
#include "ibc_asm.h"                    /* IBC Assembly Language Functions  */

#include "pio.h"                        /* Parallel IO Board Definituions   */

/****************************************************************************/
/* Function    : PIO_BoardSearch                                            */
/* Purpose     : Scans IBC backplane looking for Parallel IO Boards         */
/* Inputs      : Pointer to IBC Board Entry Table and maximum table size    */
/* Outputs     : Returns number of boards found                             */
/****************************************************************************/
    Int16
PIO_BoardSearch( IBC_BoardEntry *IBC_Boards[], Int16 maxCards )
{
    Byte  *addr;                        /* Parallel IO Board base address   */
    Int16 board;                        /* Counts number of PIO board found */
    IBC_BoardEntry *boardEntry;         /* Pointer to PIO board data struct */

    board = 0;                          /* Set board count to zero          */
    if (maxCards > 0)                   /* Check for space in IBC Card Table*/
    {
                                        /* Search for Parallel IO Boards    */
        for (addr =  (Byte *) PARALLEL_IO_0_ADDR;
             addr <= (Byte *) PARALLEL_IO_1_ADDR;
             addr+= (PARALLEL_IO_1_ADDR - PARALLEL_IO_0_ADDR) )
        {                               /* NULL boardEntry if board missing */
            if ((boardEntry = (IBC_BoardEntry *) PIO_BoardInit(addr)) !=NULL)
            {                           /* Add PIO data struct to IBC Table */
                IBC_Boards[board++] = boardEntry;
                if (board == maxCards)  /* Check if IBC Card Table is full  */
                    return(board);      /* Return number of PIO boards found*/
            } /* if */
        } /* for */
    } /* if */

    return(board);                      /* Return number of PIO boards found*/
} /* PIO_BoardSearch() */

/****************************************************************************/
/* Function    : PIO_BoardInit                                              */
/* Purpose     : Parallel IO Board Initialization routine                   */
/* Inputs      : Base address of Parallel IO board                          */
/* Outputs     : Returns pointer to IBC board data structure                */
/****************************************************************************/
    PIO_BoardEntry*
PIO_BoardInit( Byte *boardBaseAddr )
{
     PIO_BoardEntry  *PIO_Board;         /* Pointer to board entry          */

                                         /* Check if board exists by reading*/
                                         /* IO port A register              */
                                         /* Returns OK if board asserts xack*/
    if ( ibcBusReadByte( boardBaseAddr + PIO_PORTA_REG) == ERROR )
        return(( PIO_BoardEntry *) NULL);
                                        /* Board doesn't exist return NULL  */

                                        /* Configure Port A Output, Port B  */
                                        /* Input and Port C Output          */
    if ( ibcBusWriteByte( boardBaseAddr + PIO_CMD_REG, PIO_MODE_REG_SELECT |
             PIO_PORTC_LOWER_OUT | PIO_PORTC_UPPER_OUT |
             PIO_PORTB_IN        | PIO_PORTB_BASIC_IO  |
             PIO_PORTA_OUT       | PIO_PORTA_BASIC_IO ) != OK)
                                        /* IBC Bus timeout so return NULL   */
        return( ( PIO_BoardEntry *) NULL);

                                        /* Allocate space for board entry   */
    PIO_Board = (PIO_BoardEntry *) malloc( sizeof (PIO_BoardEntry) );
    if (PIO_Board == (PIO_BoardEntry *) NULL )
        return( (PIO_BoardEntry *) NULL);
                                        /* Insufficient memory return ERROR */

                                        /* Fill out board entry structure   */
    PIO_Board->IBC_Board.baseAddress = boardBaseAddr;
    PIO_Board->IBC_Board.boardType   = PARALLEL_IO;
    PIO_Board->IBC_Board.intrLevel   = IBC_INT_LVL_OFF;

    PIO_Board->ioportCopy[0] = 0;       /* Clear copies of IO Port values   */
    PIO_Board->ioportCopy[1] = 0;
    PIO_Board->ioportCopy[2] = 0;

    return (PIO_Board);                 /* Return pointer to PIO data struct*/
} /* PIO_BoardInit() */

/****************************************************************************/
/* Function    : PIO_BoardInterruptOn                                       */
/* Purpose     : Generate Interrupt from Parallel IO Board                  */
/* Inputs      : Pointer to PIO board data structure                        */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
PIO_BoardInterruptOn( PIO_BoardEntry *PIO_Board )
{                                       /* Set Control Port bit 0 = TRUE    */
    PIO_writePortBit( PIO_Board, PIO_PORTC_REG, 0, TRUE );
} /* PIO_BoardInterruptOn() */

/****************************************************************************/
/* Function    : PIO_BoardInterruptOff                                      */
/* Purpose     : Clear Interrupt from Parallel IO Board                     */
/* Inputs      : Pointer to PIO board data structure                        */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
PIO_BoardInterruptOff( PIO_BoardEntry *PIO_Board )
{                                       /* Set Control Port bit 0 = FALSE   */
    PIO_writePortBit( PIO_Board, PIO_PORTC_REG, 0, FALSE );
} /* PIO_BoardInterruptOff() */

/****************************************************************************/
/* Function    : PIO_BoardIsr                                               */
/* Purpose     : Parallel IO Board Interrupt Service Routine                */
/* Inputs      : Pointer to PIO board data structure                        */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
PIO_BoardIsr( PIO_BoardEntry *PIO_Board )
{                                       /* Null routine at this point       */
} /* PIO_BoardIsr() */

/****************************************************************************/
/* Function    : PIO_readPort                                               */
/* Purpose     : Read byte from Parallel IO Board Port A, B or C            */
/* Inputs      : Pointer to PIO board data structure, Port Address          */
/* Outputs     : Returns result of ibcBusReadByte                           */
/****************************************************************************/
   Int16
PIO_readPort( PIO_BoardEntry *PIO_Board, Byte portAddr )
{
    return (IBCBusReadByte( PIO_Board->IBC_Board.baseAddress + portAddr ));
} /* PIO_readPort */

/****************************************************************************/
/* Function    : PIO_readPortCopy                                           */
/* Purpose     : Read internal port copy from Parallel IO Board Port A, B, C*/
/* Inputs      : Pointer to PIO board data structure, Port Address          */
/* Outputs     : Returns result of ibcBusReadByte                           */
/****************************************************************************/
   Int16
PIO_readPortCopy( PIO_BoardEntry *PIO_Board, Byte port )
{
    if (port >= PIO_NUM_PORTS)
        return (ERROR);

    return (PIO_Board->ioportCopy[port]);
} /* PIO_readPortCopy */

/****************************************************************************/
/* Function    : PIO_writePort                                              */
/* Purpose     : Write byte to Parallel IO Board Port A B or C              */
/* Inputs      : Pointer to PIO data struct, Port Address, value to write   */
/* Outputs     : Returns result of ibcBusWriteByte                          */
/****************************************************************************/
   Int16
PIO_writePort( PIO_BoardEntry *PIO_Board, Byte port, Byte value, Word action )
{
    if (port >= PIO_NUM_PORTS)
        return (ERROR);

    if (action == OR_PORT)
        PIO_Board->ioportCopy[port] |= value;   /* OR value with port copy  */

    else if (action == AND_PORT)
        PIO_Board->ioportCopy[port] &= value;   /* AND value with port copy */

    else if (action == SET_PORT)
        PIO_Board->ioportCopy[port] = value;    /* SET port copy to value   */

    return (IBCBusWriteByte( PIO_Board->IBC_Board.baseAddress + port,
         PIO_Board->ioportCopy[port] ));
} /* PIO_writePort */

/****************************************************************************/
/* Function    : PIO_writePortBit                                           */
/* Purpose     : Set or Clear Parallel IO Board Port bit                    */
/* Inputs      : Base address of PIO board, bit to select, desired state    */
/* Outputs     : None                                                       */
/****************************************************************************/
   Int16
PIO_writePortBit( PIO_BoardEntry *PIO_Board, Byte port, Byte bit,
   Boolean state )
{
    if (state)                          /* If desired state is ON then      */
        PIO_writePort(PIO_Board, port,  (1 << (bit & 0x07)), OR_PORT);
    else
        PIO_writePort(PIO_Board, port, ~(1 << (bit & 0x07)), AND_PORT);
} /* PIO_writePortBit */

/****************************************************************************/
/* Function    : PIO_ReadPortCmd                                            */
/* Purpose     : Process command to read PIO board input port               */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
PIO_ReadPortCmd( IBC_BoardEntry* IBC_CardTable[], Int16 IBC_CardCount,
    Byte *commandBuf )
{
    Nat16   card;               /* Card index into Card Table               */
    Word    command;            /* Serial command - discarded               */
    Word    port;               /* PIO Board port to read                   */
    Byte    *boardAddr;         /* PIO Board base address from command buf  */

                                /* Extract command and arguments from buffer*/
    wordsFromBuf(commandBuf, 3, &command, &boardAddr, &port);

                                /* Find card table index for this address   */
    if ( (card = ibcBoardTableIndex(IBC_CardTable, IBC_CardCount,
                 boardAddr, PARALLEL_IO) ) == ERROR)
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */

    replyToCommand(2, CMD_OK,
        PIO_readPort( (PIO_BoardEntry *) IBC_CardTable[card], port) );
} /* PIO_ReadPortCmd() */

/****************************************************************************/
/* Function    : PIO_WritePortCmd                                           */
/* Purpose     : Process command to write PIO board output port             */
/* Inputs      : IBC Card Table, Number of cards & serial command buffer    */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
PIO_WritePortCmd( IBC_BoardEntry* IBC_CardTable[], Int16 IBC_CardCount,
    Byte *commandBuf )
{
    Nat16   card;               /* Card index into Card Table               */
    Word    command;            /* Serial command - discarded               */
    Word    port;               /* PIO Board port to write                  */
    Word    value;              /* PIO Board port value to write            */
    Byte    *boardAddr;         /* PIO Board base address from command buf  */

                                /* Extract command and arguments from buffer*/
    wordsFromBuf(commandBuf, 4, &command, &boardAddr, &port, &value);

                                /* Find card table index for this address   */
    if ( (card = ibcBoardTableIndex(IBC_CardTable, IBC_CardCount,
                 boardAddr, PARALLEL_IO) ) == ERROR)
    {                           /* Card not present so return error         */
        replyToCommand(1, EARGUMENT);
        return;
    } /* if */

    if ( PIO_writePort( (PIO_BoardEntry *) IBC_CardTable[card], (Byte) port,
        (Byte) value, SET_PORT ) != ERROR)
        replyToCommand(1, CMD_OK);
    else
        replyToCommand(1, CMD_ERROR);
} /* PIO_WritePortCmd() */
