/****************************************************************************/
/* Copyright 1992 MBARI                                                     */
/****************************************************************************/
/* Summary  : Datel 612 A to D board Driver for vxWorks                     */
/* Filename : datel612.c                                                    */
/* Author   : Andrew Pearce                                                 */
/* Project  : New ROV                                                       */
/* Version  : Version 1.0                                                   */
/* Created  : 11/13/92                                                      */
/* Modified : 11/13/92                                                      */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/* $Header: $
 * $Log:    $
 */
/****************************************************************************/

#include <vxWorks.h>                /* vxWorks system declarations          */
#include <stdioLib.h>               /* vxWorks standard IO libarary         */
#include <strLib.h>                 /* vxWorks string library functions     */

#include <mbariTypes.h>             /* MBARI style guide type declarations  */
#include <datel612.h>               /* Datel 612 card definitions           */

                                    /* data structure for card register map */
MLocal __volatile__
         datelCardRegs *datelCard = ( datelCardRegs *) DATEL_612_VME_ADDR;

/*****************************************************************************/
/*                                                                           */
/*      a2d_init:  initialized DATEL VME-612 a2d converter to given mode     */
/*                      and with given input gain.                           */
/*                                                                           */
/*                                                                           */
/*****************************************************************************/

    STATUS
datel612CardInit(Int16 mode, Int16 gain)
{
    const __volatile__ Byte cardIdent[] = "VMEIDDATdVME-612";
    Word  command;
    Int32 byte;

    Word probeVal;                   /* location used by vxMemProbe          */

    if (vxMemProbe ( (Char *) datelCard, READ, sizeof(probeVal),
            &probeVal) != OK)
    {
        logMsg("datel612BoardInit: Datel 612 A to D card not found.\n");
        return(ERROR);
    } /* if */

    for (byte = 0; byte < strlen((char *) cardIdent); byte++)
    {
        if (cardIdent[byte] != (datelCard->boardId[byte] & 0x00ff))
        {
            logMsg("datel612BoardInit: Datel 612 A to D card not found.\n");
            return(ERROR);
        }  /* if */
    } /* for */

    switch (gain)
    {
      case 1:
        datelCard->pgaGain = 0;
        break;

      case 2:
        datelCard->pgaGain = 1;
        break;

      case 4:
        datelCard->pgaGain = 2;
        break;

      case 8:
        datelCard->pgaGain = 3;
        break;

      case 16:
        datelCard->pgaGain = 4;
        break;

      case 32:
        datelCard->pgaGain = 5;
        break;

      case 64:
        datelCard->pgaGain = 6;
        break;

      case 128:
        datelCard->pgaGain = 7;
        break;

      default:
        logMsg("datel612BoardInit: invalid gain %d.\n", gain);
        return(ERROR);
        break;
    } /* switch */

    switch (mode) {
      case A2D_MODE_SINGLE :
        command = (Word) ( A2D_CNTRL_ENABLE | A2D_CNTRL_SINGLE);
        break;

      case A2D_MODE_SCAN :
        command = (Word) ( A2D_CNTRL_ENABLE | A2D_CNTRL_SCAN);
        break;

      default:
        logMsg("datel612BoardInit: unknown mode %d.\n", mode);
        return(ERROR);
        break;
    } /* switch */

    datelCard->command = command;

    if ((datelCard->boardStatus & 0x0007) != (command & 0x0007))
    {
        logMsg("datel612BoardInit: problem setting mode: Status = %x\n",
                datelCard->boardStatus);
        return(ERROR);
    } /* if */

    return(OK);
} /* datel612CardInit */


/*****************************************************************************/
/*                                                                           */
/*      datelCard:  reads given channel of datelCard and stores it into value.      */
/*                                                                           */
/*****************************************************************************/

    STATUS
datel612Read(int channel, Int16* value)
{
    Word input;
    int voltage;
    int timeout = 0;

    if ((channel < 0) || channel > A2D_MAXCHANNEL)
    {
        logMsg("datel612Read: Channel %d out of range.\n", channel);
        return(ERROR);
    } /* if */

    datelCard->startChannel = (Word) channel;       /* write to start channel*/
    datelCard->analogData = 0;                      /* start A/D conversion  */

    while (!(datelCard->boardStatus & A2D_CONVERSION_DONE) &&
         (++timeout < A2D_TIMEOUT));
                                          /* wait for conversion to complete */

    if (((datelCard->boardStatus & A2D_CONVERSION_DONE) != A2D_CONVERSION_DONE)
                 || (timeout >= A2D_TIMEOUT))
    {
        if (timeout >= A2D_TIMEOUT)
            logMsg("datel612Read: timeout.\n");
        else
            logMsg("datel612Read: problem in conversion, status = %x.\n",
                 datelCard->boardStatus);
        return(ERROR);
    } /* if */

                                        /* verify the channel number  */
    if ((datelCard->startChannel & A2D_CHANNEL_BITS) == channel)
    {
        input = datelCard->analogData;         /* read data from card        */

        /* data is the upper 12 of 16 bits so discard the
             lower bits and sign extend                               */

        if (input & 0x8000)             /* check sign of the value    */
                                        /* neg so sign extend         */
            voltage = (int) ((input >> 4) | 0xfffff000);
        else
                                        /* pos so discard low nibble  */
            voltage = (int) (input >> 4);

        *value = voltage;
        return(OK);

    } /* if */
    else
    {
        logMsg("datelCard: bad channel number after conversion\n");
        return(ERROR);                   /* wrong channel so return 0 */
    } /* else */
} /* datel612Read() */

/*****************************************************************************/
/*                                                                           */
/*  datel612ScanChannels: reads multiple channels given starting and ending  */
/*                 channel stores it into the given structure.               */
/*                                                                           */
/*****************************************************************************/

    STATUS
datel612ScanChannels(int start_channel, int end_channel, Int16 *value)
{
    Word input;
    Word status;

    int voltage;
    int timeout = 0;
    int i = 0;

    if (end_channel < start_channel)
    {
        logMsg("datel612ScanChannels: Start channel must be < end channel\n");
        return(ERROR);
    } /* if */

    if ((start_channel < 0) || start_channel > A2D_MAXCHANNEL)
    {
        logMsg("datel612ScanChannels: Start channel %d out of range.\n",
             start_channel);
        return(ERROR);
    } /* if */

    if ((end_channel < 0) || end_channel > A2D_MAXCHANNEL)
    {
        logMsg("datel612ScanChannels: End channel %d out of range.\n",
             end_channel);
        return(ERROR);
    } /* if */

    datelCard->startChannel = (Word) start_channel;/* write to start channel */
    datelCard->finalChannel = (Word) end_channel;  /* write to final channel */
    datelCard->analogData = 0;                     /* start A/D conversion   */
    for (i = 0; i <= (end_channel-start_channel); i++)
    {
        timeout = 0;

        while (! ((status = datelCard->boardStatus) & A2D_CONVERSION_DONE) &&
                          (++timeout < A2D_TIMEOUT));
                                          /* wait for conversion to complete */

        if (((status & A2D_CONVERSION_DONE) != A2D_CONVERSION_DONE) ||
            (timeout >= A2D_TIMEOUT))
        {
            if (timeout >= A2D_TIMEOUT)
                logMsg("datel612ScanChannels: timeout.\n");
            else
                logMsg("datelCard: problem in conversion, status = %x.\n",
                     status);
            return(ERROR);
        } /* if */
                                         /* verify the channel number        */
                                         /* or check if end of scan          */
        if ( ( ((datelCard->startChannel & A2D_CHANNEL_BITS) - 1) ==
             (start_channel + i) ) ||
             ((status & A2D_END_OF_SCAN) == A2D_END_OF_SCAN) )
        {
            input = datelCard->analogData;/* read data from card which       */
                                          /* also initiates next datelCard   */
                                          /* conversion automatically        */
                           /* data is the upper 12 of 16 bits so discard the */
                           /* lower bits and sign extend                     */

            if (input & 0x8000)          /* check sign of the value          */
                                         /* neg so sign extend               */
                voltage = (int) ((input >> 4) | 0xfffff000);
            else
                                         /* pos so discard low nibble        */
                voltage = (int) (input >> 4);

            value[i] = voltage;

        } /* if */

        else
        {
            logMsg("datelCard: bad channel number after conversion\n");
            return(ERROR);               /* wrong channel so return 0  */
        }  /* else */
    } /* if */

    datelCard->reset_eoc_eos = 0;             /* reset end of scan flag */
    return(OK);

} /* datel612ScanChannels */
