Nisarg Sheth / ADMX2001

ADMX2001.cpp

Committer:
nsheth
Date:
2021-11-02
Revision:
10:49537b1dbbd7
Parent:
9:f286301109fb
Child:
11:071709f5f7d4

File content as of revision 10:49537b1dbbd7:

/* Copyright (c) 2021 Analog Devices, Inc.  All rights reserved.

Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:
  - Redistributions of source code must retain the above copyright notice, 
  this list of conditions and the following disclaimer.
  - Redistributions in binary form must reproduce the above copyright notice, 
  this list of conditions and the following disclaimer in the documentation 
  and/or other materials provided with the distribution.  
  - Modified versions of the software must be conspicuously marked as such.
  - This software is licensed solely and exclusively for use with processors/products 
  manufactured by or for Analog Devices, Inc.
  - This software may not be combined or merged with other code in any manner 
  that would cause the software to become subject to terms and conditions which 
  differ from those listed here.
  - Neither the name of Analog Devices, Inc. nor the names of its contributors 
  may be used to endorse or promote products derived from this software without 
  specific prior written permission.
  - The use of this software may or may not infringe the patent rights of one or 
  more patent holders.  This license does not release you from the requirement 
  that you obtain separate licenses from these patent holders to use this software.

THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. AND CONTRIBUTORS "AS IS" AND 
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, 
TITLE, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 
NO EVENT SHALL ANALOG DEVICES, INC. OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE OR CONSEQUENTIAL DAMAGES 
(INCLUDING, BUT NOT LIMITED TO, DAMAGES ARISING OUT OF CLAIMS OF INTELLECTUAL 
PROPERTY RIGHTS INFRINGEMENT; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

2021-01-10-7CBSD SLA
*/

/**
 * @file     ADMX2001.cpp
 * @brief    This file contains admx200x APIs for sdpk1 host
 * @addtogroup SDPK1
 * @{
 */
/*=============  I N C L U D E S   =============*/
#include "ADMX2001.h"
#include "ADMX2001_commands.h"
#include "message.h"
#include <stdlib.h>
#include <string.h>

static uint32_t SwapEndian(uint32_t *pData);
/** milli second delay**/
static void Admx200xDelay(uint32_t msec);

/**
 * Swaps endian of a 32 bit number
 * @param data  - 32 bit number
 * @return
 */
uint32_t SwapEndian(uint32_t *pData)
{
    uint8_t *pDataU8 = (uint8_t *)pData;

    return (uint32_t)pDataU8[0] << 24 | (uint32_t)pDataU8[1] << 16 |
           (uint32_t)pDataU8[2] << 8 | (uint32_t)pDataU8[3];
}

/**
 * @brief Initializes the ADMX200X.
 *
 * @param pDevice     - The device structure.
 * @param pSpiDesc    - Pointer to spi device
 * @return Returns 0 for success or negative error code.
 */
int32_t Admx200xInit(Admx200xDev *pDevice, spi_desc *pSpiDesc)
{
    int32_t ret = 0;

    pDevice->pSpiDesc = pSpiDesc;

    return ret;
}

/**
 * Wrapper fro delay
 * @param msecs  - delay in milliseconds
 */
void Admx200xDelay(uint32_t msecs)
{
    mdelay(msecs);
}

/**
 * @brief Create a command payload in buffer with inputs.
 *
 * @param pCmdId - Command ID.
 * @param pAddr - Sub commands addresses.
 * @param pData - Data to wildcat.
 * @param pBuffer - Data to wildcat.
 *
 * @return Returns 0 for success or negative error code.
 */
int32_t Admx200xCreateCmdPayload(uint8_t *pCmdId, uint16_t *pAddr,
                                 uint32_t *pData, uint8_t *pBuffer)
{
    int32_t ret = 0;
    //DEBUG_MSG("cmd:%d,addr:%d, data: 0x%x\n\r", *pCmdId, *pAddr, *pData);
    pBuffer[0] = pCmdId[0];
    pBuffer[1] = ((uint8_t *)pAddr)[1];
    pBuffer[2] = ((uint8_t *)pAddr)[0];
    pBuffer[3] = ((uint8_t *)pData)[3];
    pBuffer[4] = ((uint8_t *)pData)[2];
    pBuffer[5] = ((uint8_t *)pData)[1];
    pBuffer[6] = ((uint8_t *)pData)[0];

    return ret;
}

/**
 * @brief Parse the payload to get cmdID, addr and data.

 * @param[in] pBuffer - Data from wildcat.
 * @param[out] pCmdId  - Pointer to store Command ID.
 * @param[out]  pAddr   - Pointer to store addresses.
 * @param[out]  pData   -  Pointer to store Data
 *
 * @return Returns 0 for success or negative error code.
 */
int32_t Admx200xParseCmdPayload(uint8_t *pBuffer, uint8_t *pCmdId,
                                uint16_t *pAddr, uint32_t *pData)
{
    int32_t ret = 0;

    *pCmdId = pBuffer[0];
    *pAddr = ((uint16_t)pBuffer[1] << 8) | ((uint16_t)pBuffer[2]);

    *pData = SwapEndian((uint32_t *)&pBuffer[3]);

    return ret;
}

/**
 * @brief Waits till done bit is set in the status
 *
 * @param pDevice  - The handler of the instance of the driver.
 * @param timeout  - Count representing the number of polls to be done until the
 *                  function returns if no new data is available.
 * @param reqStatus - The status to be checked is passed via this argument.
 * @param pStatReg  - Get the status word in pStatReg.
 *
 * @return Returns 0 for success or negative error code.
 */
int32_t Admx200xWaitForStatus(Admx200xDev *pDevice, uint32_t timeout,
                              uint32_t reqStatus, uint32_t *pStatReg)
{
    int32_t status = ADMX_STATUS_SUCCESS;
    int8_t done = 0;
    uint8_t cmdId = CMD_STATUS_READ;

    if (pDevice != NULL)
    {
        while (!done && --timeout)
        {

            status = Admx200xReadData(pDevice, cmdId, pStatReg);

            if (status == 0)
            {
                /* Check the DONE bit in the Status Register */
                if (((*pStatReg) & reqStatus) == reqStatus)
                {
                    done = 1;
                    if (*pStatReg & ADMX200X_STATUS_ERROR_BITM)
                    {
                        status = *pStatReg & ADMX200X_STATUS_CODE_BITM;
                        if (status & ADMX_STATUS_LOG_ZERO_ERROR)
                        {
                            ERROR_MSG("sweep_start/sweep_end cannot be zero "
                                      "for logarithmic sweep");
                            status &= (~ADMX_STATUS_LOG_ZERO_ERROR);
                        }
                        if (status & ADMX_STATUS_LOG_SIGN_ERROR)
                        {
                            ERROR_MSG("sweep_start and sweep_end need to have "
                                      "the same sign "
                                      "for logarithmic sweep");
                            status &= (~ADMX_STATUS_LOG_SIGN_ERROR);
                        }
                        if (status & ADMX_STATUS_VOLT_ADC_ERROR)
                        {
                            ERROR_MSG("Voltage ADC Saturated\n");
                            status &= (~ADMX_STATUS_VOLT_ADC_ERROR);
                        }
                        if (status & ADMX_STATUS_CURR_ADC_ERROR)
                        {
                            ERROR_MSG("Current ADC Saturated\n");
                            status &= (~ADMX_STATUS_CURR_ADC_ERROR);
                        }
                        if (status & ADMX_STATUS_FIFO_ERROR)
                        {
                            ERROR_MSG(
                                "FIFO either Overflowed or Underflowed\n");
                            status &= (~ADMX_STATUS_FIFO_ERROR);
                        }
                        if (status & ADMX_STATUS_COUNT_EXCEEDED)
                        {
                            ERROR_MSG("Sweep count exceeded maximum value");
                            status &= (~ADMX_STATUS_COUNT_EXCEEDED);
                        }
                    }
                }
            }
        }

        if (!timeout)
        {
            status = ADMX_STATUS_TIMEOUT;
        }
    }
    else
    {
        status = ADMX_STATUS_FAILED;
    }
    return status;
}

/**
 * @brief Sends teh command to ADMX200x and wait till done bit is set
 * @param pDevice  - Device Handle
 * @param pCmdId   - The command ID
 * @param pAddr    - Address
 * @param pData    - Data
 * @param pStatReg - Status register info
 * @return Returns 0 for success or negative error code.
 */
int32_t Admx200xSendCmd(Admx200xDev *pDevice, uint8_t *pCmdId, uint16_t *pAddr,
                        uint32_t *pData, uint32_t *pStatReg)
{

    int32_t status = ADMX_STATUS_SUCCESS;
    uint8_t cmdPayload[ADMX200X_CMD_LENGTH];

    Admx200xCreateCmdPayload(pCmdId, pAddr, pData, &cmdPayload[0]);

    status = spi_write_and_read(pDevice->pSpiDesc, &cmdPayload[0],
                                ADMX200X_CMD_LENGTH);
    Admx200xDelay(100);
    // printf("CMD :%02x ADDR: %04x DATA: %08x\n\r",*pCmdId, *pAddr, *pData);
    if (!status)
    {
        /** Wait for status done = 1,Warn/error/command result = 0 from result
         */
        status = Admx200xWaitForStatus(pDevice, SPI_TIMEOUT,
                                       ADMX200X_STATUS_DONE_BITM, pStatReg);

        //printf("Stat Reg: %08x\n\r", *pStatReg);
        if (status == ADMX_STATUS_SUCCESS)
        {
            status = *pStatReg & ADMX200X_STATUS_CODE_BITM;
        }
    }
    if (status == ADMX_STATUS_TIMEOUT)
    {
        ERROR_MSG("SPI interface timed out : Not responding");
    }
    return status;
}

/**
 * @brief Read result register from the WILDCAT
 * @param pDevice  - Device Handle
 * @param cmdId   - This determines where the data is read from - result
 *                  register, status register or Fifo
 * @param pResult - The data in the result register
 * @return Returns 0 for success or negative error code.
 */
int32_t Admx200xReadData(Admx200xDev *pDevice, uint8_t cmdId, uint32_t *pResult)
{
    int32_t ret = ADMX_STATUS_SUCCESS;
    uint8_t cmdTemp;
    uint16_t addrTemp;
    uint16_t addr;
    uint32_t data;
    uint8_t cmdPayload[ADMX200X_CMD_LENGTH];

    /*FIXME: Insert checks here. Not all command IDs are accepted here */
    addr = 0;
    data = 0;

    Admx200xCreateCmdPayload(&cmdId, &addr, &data, &cmdPayload[0]);

    /* Send command and Read response from the slave */
    ret = spi_write_and_read(pDevice->pSpiDesc, &cmdPayload[0],
                             ADMX200X_CMD_LENGTH);
    Admx200xDelay(100);
    Admx200xParseCmdPayload(&cmdPayload[0], &cmdTemp, &addrTemp, pResult);

    return ret;
}

/**
 * @brief Read array of datatype doube from the fifo of the WILDCAT
 * @param pDevice  - Device Handle
 * @param pFifo - Double array that stores the data
 * @param pCount - Stores the number of double values stored in the pFifo array
 */
int32_t Admx200xReadFifo(Admx200xDev *pDevice, double *pFifo, int32_t *pCount)
{
    int32_t status = ADMX_STATUS_SUCCESS;
    int32_t i;
    uint32_t *pData = (uint32_t *)pFifo;
    uint8_t cmdId = CMD_STATUS_READ;
    uint32_t statusReg;
    int32_t numDoublesInFifo;

    status = Admx200xReadData(pDevice, cmdId, &statusReg);

    /* Fifo depth in doubles */
    numDoublesInFifo = (statusReg & ADMX200X_STATUS_FIFO_DEPTH_BITM) >> 17;

    if (numDoublesInFifo < *pCount)
    {
        *pCount = numDoublesInFifo;
    }

    for (i = 0; i < *pCount; i++)
    {
        /* Read a double  -- Split it into two reads for redability*/
        Admx200xReadData(pDevice, CMD_FIFO_READ, &pData[2 * i]);
        Admx200xReadData(pDevice, CMD_FIFO_READ, &pData[2 * i + 1]);
    }
    return status;
}

/**
 * @brief Clears the Admx2001 SPI FIFO & errors
 *
 * @param pDevice - Device Handle
 * @return Returns 0 for success or error code.
 */
int32_t Admx200xClearSPI(Admx200xDev *pDevice)
{
    int32_t status = ADMX_STATUS_SUCCESS;
    uint8_t cmdID;
    uint16_t addr = 0;
    uint32_t statReg = 0;
    uint32_t data = 0;

    cmdID = CMD_CLEAR_ERROR;
    status = Admx200xSendCmd(pDevice, &cmdID, &addr, &data, &statReg);

    return status;
}

/**
 * @}
 */