SDMP_IOT / Mbed OS AdiSense1000_SmartBabySeat

Fork of Babyseat_NewFirmware_copy_sean by Ross O'Halloran

Revision:
2:625a45555a85
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/adisense1000.cpp	Fri Aug 25 11:17:37 2017 +0000
@@ -0,0 +1,633 @@
+/*!
+ ******************************************************************************
+ * @file:   adisense1000.cpp
+ * @brief:
+ *-----------------------------------------------------------------------------
+ *
+Copyright (c) 2017 Emutex Ltd. / 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
+    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.
+ *
+ *****************************************************************************/
+/******************************************************************************/
+/* Include Files                                                              */
+/******************************************************************************/
+
+#include "mbed.h"
+#include "inc/spi_nucleo.h"
+#include "inc/gpio_nucleo.h"
+#include "inc/adisense1000.h"
+
+#define BIT(n)  (1 << (n))
+#define BIT_MASK(len)   (BIT(len)-1)
+
+#define MAX_RCV_BYTES (100)
+#define MAX_REG_SIZE (4)
+
+#define GET_SAMPLE_TIMEOUT (1)
+
+extern Serial pc;
+Timer readTimeout;
+
+uint8_t rcvBuff[MAX_RCV_BYTES] = {0};
+uint8_t txdBuff[MAX_REG_SIZE]  = {0};
+
+/*
+  For v0.1 we pass this into ADISense1000_HostGpioOpen but it is not being used.
+  This is because the os dependant wrapper for the nucleo is using classes which
+  are hardcoded globally. We should probally wrap the os layer in a c wrapper
+  so these c++ functions are hidden from the user
+ */
+gpioSettings gpioConfig[HOST_GPIO_COUNT] =
+{
+    {D2, OUTPUT, HIGH},
+    {D3, INPUT,  LOW},
+    {D4, INPUT,  LOW},
+    {D5, INPUT,  LOW}
+};
+
+/* Same as mentioned for gpioConfig applies here */
+spiSettings spiConfigure;
+
+/*!
+ * @brief Init SPI and GPIO for ADISense1000.
+ *
+ * @param[in]  void
+ *
+ * @return Status
+ *         - #ADI_SENSE_SUCCESS Call completed successfully.
+ *         - #ADI_SENSE_FAILURE If GPIO open failed.
+ *         - #ADI_SENSE_FAILURE If SPI open failed.
+ *
+ * @details Configure GPIO for ADISense1000 module and open
+ *          SPI communications to ADISense1000 module.
+ */
+ADI_SENSE_RESULT ADISense1000_Open(void)
+{
+    if (ADISense1000_HostGpioOpen(gpioConfig) != ADI_SENSE_SUCCESS)
+    {
+        return ADI_SENSE_FAILURE;
+    }
+
+    if (ADISense1000_HostSpiOpen(spiConfigure) != ADI_SENSE_SUCCESS)
+    {
+        return ADI_SENSE_FAILURE;
+    }
+
+    return ADI_SENSE_SUCCESS;
+}
+
+
+/*!
+ * @brief Get the product ID for Module
+ *
+ * @param[in]
+ * @param[out] pProductID : Pointer to uint16_t for Product ID.
+ *
+ * @return Status
+ *         - #ADI_SENSE_SUCCESS Call completed successfully.
+ *         - #ADI_SENSE_FAILURE If receive product ID fails.
+ *
+ * @details Read the product ID for ADISense1000 module.
+ *
+ */
+ADI_SENSE_RESULT ADISense1000_GetID(uint16_t *pProductID)
+{
+    ADI_SENSE_RESULT eRet;
+    uint8_t id_l, id_h;
+
+    eRet = ADISense1000_RegRead(regMap[SPI_PRODUCT_ID_L].addr,
+                                    regMap[SPI_PRODUCT_ID_L].size,
+                                    rcvBuff);
+    if (eRet != ADI_SENSE_SUCCESS)
+    {
+        return eRet;
+    }
+
+    id_l = rcvBuff[0];
+
+    eRet = ADISense1000_RegRead(regMap[SPI_PRODUCT_ID_H].addr,
+                                    regMap[SPI_PRODUCT_ID_H].size,
+                                    rcvBuff);
+    if (eRet != ADI_SENSE_SUCCESS)
+    {
+        return eRet;
+    }
+
+    id_h = rcvBuff[0];
+    *pProductID  = ((id_h << 8)&0xff00)|id_l;
+
+    return ADI_SENSE_SUCCESS;
+}
+
+/*!
+ * @brief Basic configuration of module for V0.1
+ *
+ * @param[in]  void
+ * @param[out]
+ *
+ * @return Status
+ *         - #ADI_SENSE_SUCCESS Call completed successfully.
+ *         - #ADI_SENSE_FAILURE If write module config fails.
+ *
+ * @details Basic function to set a fixed configuration.
+ */
+ADI_SENSE_RESULT ADISense1000_ConfigureModule(void)
+{
+    ADI_SENSE_RESULT eRet;
+    ADI_CORE_Mode_t modeReg;
+
+    modeReg.Conversion_Mode = CORE_MODE_SINGLECYCLE;
+    modeReg.Drdy_Mode       = CORE_MODE_DRDY_PER_CYCLE;
+
+    eRet = ADISense1000_RegWrite(regMap[CORE_MODE].addr,
+                                    regMap[CORE_MODE].size,
+                                        (uint8_t*)&modeReg);
+
+    if (eRet != ADI_SENSE_SUCCESS)
+    {
+        return eRet;
+    }
+
+    return ADI_SENSE_SUCCESS;
+}
+
+/*!
+ * @brief Get general status of ADISense1000 module.
+ *
+ * @param[in]
+ * @param[out] pStatus : Pointer to CORE Status struct.
+ *
+ * @return Status
+ *         - #ADI_SENSE_SUCCESS Call completed successfully.
+ *         - #ADI_SENSE_FAILURE If status register read fails.
+ *
+ * @details Read the general status register for the ADISense1000
+ *          module. Indicates Error, Alert conditions, data ready
+ *          and command running.
+ *
+ */
+ADI_SENSE_RESULT ADISense1000_GetStatus(ADI_CORE_Status_t *pStatus)
+{
+    ADI_SENSE_RESULT eRet;
+
+    pStatus->VALUE8 = 0;
+    eRet = ADISense1000_RegRead(regMap[CORE_STATUS].addr,
+                                    regMap[CORE_STATUS].size,
+                                    rcvBuff);
+    if (eRet != ADI_SENSE_SUCCESS)
+    {
+        return eRet;
+    }
+
+    pStatus->VALUE8 = rcvBuff[0];
+
+    return ADI_SENSE_SUCCESS;
+}
+
+/*!
+ * @brief Get a list of channels with alerts.
+ *
+ * @param[in]
+ * @param[out] pStatus : List of Channel detailed alerts.
+ *
+ * @return Status
+ *         - #ADI_SENSE_SUCCESS Call completed successfully.
+ *         - #ADI_SENSE_FAILURE If request for channel alerts fails.
+ *
+ * @details Read the channel alert register. If channel alert register
+ *          indicates alert on a channel, process the channel detailed
+ *          alert register.
+ */
+ADI_SENSE_RESULT ADISense1000_GetChannelAlert(ADI_Channel_Alert_t pAlerts)
+{
+    ADI_SENSE_RESULT eRet;
+    uint8_t i;
+    uint8_t chAlertReg;
+    uint16_t n;
+
+    memset(pAlerts, 0, sizeof(ADI_Channel_Alert_t));
+
+    eRet = ADISense1000_RegRead(regMap[CORE_CHANNEL_ALERT_STATUS].addr,
+                                regMap[CORE_CHANNEL_ALERT_STATUS].size,
+                                    rcvBuff);
+    if (eRet != ADI_SENSE_SUCCESS)
+    {
+        return eRet;
+    }
+
+    n = ((rcvBuff[1] << 8)&0xff00) | rcvBuff[0];
+    for (i=0; i<ADI_SENSE_NUM_CHANNELS; i++)
+    {
+        if ((n >> i)&0x1)
+        {
+            chAlertReg = baseAlertReg[i];
+            eRet = ADISense1000_RegRead(regMap[chAlertReg].addr,
+                                        regMap[chAlertReg].size,
+                                            rcvBuff);
+            if (eRet != ADI_SENSE_SUCCESS)
+            {
+                return eRet;
+            }
+
+            pAlerts[i].VALUE8 = rcvBuff[0];
+         }
+
+    }
+
+    return ADI_SENSE_SUCCESS;
+}
+
+/*!
+ * @brief Send a configuration to one channel.
+ *
+ * @param[in] ADI_Channel_ID_t : Channel Identifier.
+ * @param[in] ADI_Channel_Config_t : Pointer to channel config data.
+ * @param[out]
+ * @return Status
+ *         - #ADI_SENSE_SUCCESS Call completed successfully.
+ *         - #ADI_SENSE_FAILURE If set channel config fails.
+ *
+ * @details Sends the entire configuration to the select channel during a
+ *          single transfer.
+ */
+ADI_SENSE_RESULT ADISense1000_ConfigureChannel(ADI_Channel_ID_t eChannel,
+                                                ADI_Channel_Config_t *pConfig)
+{
+    ADI_SENSE_RESULT eRet;
+    uint8_t chBaseReg;
+
+    chBaseReg = baseReg[eChannel];
+    eRet = ADISense1000_RegWrite(regMap[chBaseReg].addr,
+                                       sizeof(ADI_Channel_Config_t),
+                                                   (uint8_t*)pConfig);
+
+    if (eRet != ADI_SENSE_SUCCESS)
+    {
+        return eRet;
+    }
+
+    return ADI_SENSE_SUCCESS;
+}
+
+/*!
+ * @brief Start a measurement cycle.
+ *
+ * @param[in] ADI_CORE_Command_Special_Command : Conversion result format.
+ * @param[out]
+ *
+ * @return Status
+ *         - #ADI_SENSE_SUCCESS Call completed successfully.
+ *         - #ADI_SENSE_FAILURE
+ *
+ * @details Sends the latch config command. Configuration for channels in
+ *          conversion cycle should be completed before this function.
+ *          Channel enabled bit should be set before this function.
+ *          Starts a conversion and configures the format of the sample.
+ *
+ */
+ADI_SENSE_RESULT ADISense1000_StartMeasurement(
+                                        ADI_CORE_Command_Special_Command cmd)
+{
+    ADI_SENSE_RESULT eRet;
+    ADI_CORE_Command_t command;
+    ADI_CORE_Status_t *statusreg = (ADI_CORE_Status_t *)rcvBuff;
+
+    /* Send the latch command */
+    command.Special_Command = CORE_COMMAND_LATCH_CONFIG;
+    eRet = ADISense1000_RegWrite(regMap[CORE_COMMAND].addr,
+                                    regMap[CORE_COMMAND].size,
+                                            (uint8_t*)&command);
+    if (eRet != ADI_SENSE_SUCCESS)
+    {
+        return eRet;
+    }
+
+    /* Wait for command to finish */
+    statusreg->Cmd_Running = true;
+    while (statusreg->Cmd_Running)
+    {
+        wait_ms(10);
+        eRet = ADISense1000_RegRead(regMap[CORE_STATUS].addr,
+                                        regMap[CORE_STATUS].size,
+                                        rcvBuff);
+        if (eRet != ADI_SENSE_SUCCESS)
+        {
+            return eRet;
+        }
+    }
+
+    /* Send the user command */
+    command.Special_Command = cmd;
+    eRet = ADISense1000_RegWrite(regMap[CORE_COMMAND].addr,
+                                    regMap[CORE_COMMAND].size,
+                                            (uint8_t*)&command);
+
+    if (eRet != ADI_SENSE_SUCCESS)
+    {
+        return eRet;
+    }
+
+
+    /* Wait for command to finish */
+    statusreg->Cmd_Running = true;
+    while (statusreg->Cmd_Running)
+    {
+        wait_ms(10);
+        eRet = ADISense1000_RegRead(regMap[CORE_STATUS].addr,
+                                        regMap[CORE_STATUS].size,
+                                        rcvBuff);
+        if (eRet != ADI_SENSE_SUCCESS)
+        {
+            return eRet;
+        }
+    }
+
+    return ADI_SENSE_SUCCESS;
+}
+
+/*!
+ * @brief Stop measurement on selected channel.
+ *
+ * @param[in] ADI_Channel_ID_t : Channel identifier.
+ * @param[out]
+ *
+ * @return Status
+ *         - #ADI_SENSE_SUCCESS Call completed successfully.
+ *         - #ADI_SENSE_FAILURE
+ *
+ * @details Un-sets the channel enable bit in the selected channel
+ *          count register. Retains the cycle count in the channel
+ *          count register.
+ *
+ */
+ADI_SENSE_RESULT ADISense1000_StopMeasurement(ADI_Channel_ID_t eChannel)
+{
+    ADI_SENSE_RESULT eRet;
+    uint8_t setValue;
+    uint8_t chBaseReg;
+    ADI_CORE_Command_t command;
+    ADI_CORE_Status_t *statusreg = (ADI_CORE_Status_t *)rcvBuff;
+
+    /* Read back the count register to store the cycle count for this
+     * channel.
+     */
+    chBaseReg = baseReg[eChannel];
+    eRet = ADISense1000_RegRead(regMap[chBaseReg].addr,
+                                regMap[chBaseReg].size, rcvBuff);
+    if (eRet != ADI_SENSE_SUCCESS)
+    {
+        return eRet;
+    }
+
+    /* Zero the enable bit of the count register */
+    setValue = rcvBuff[0] & 0x7f;
+    eRet = ADISense1000_RegWrite(regMap[chBaseReg].addr,
+                                    regMap[chBaseReg].size,
+                                        &setValue);
+    if (eRet != ADI_SENSE_SUCCESS)
+    {
+        return eRet;
+    }
+
+    /* Send the latch command */
+    command.Special_Command = CORE_COMMAND_LATCH_CONFIG;
+    eRet = ADISense1000_RegWrite(regMap[CORE_COMMAND].addr,
+                                    regMap[CORE_COMMAND].size,
+                                            (uint8_t*)&command);
+    if (eRet != ADI_SENSE_SUCCESS)
+    {
+        return eRet;
+    }
+
+    /* Wait for command to finish */
+    statusreg->Cmd_Running = true;
+    while (statusreg->Cmd_Running)
+    {
+        wait_ms(10);
+        eRet = ADISense1000_RegRead(regMap[CORE_STATUS].addr,
+                                        regMap[CORE_STATUS].size,
+                                        rcvBuff);
+        if (eRet != ADI_SENSE_SUCCESS)
+        {
+            return eRet;
+        }
+    }
+
+    return ADI_SENSE_SUCCESS;
+}
+
+/*!
+ * @brief Get input status of data ready gpio
+ *
+ * @param[in] void
+ * @param[out]
+ *
+ * @return Status
+ *         - #bool State of the data ready pin.
+ *
+ *
+ */
+bool ADISense1000_SampleReady(void)
+{
+    bool bDrdy=false;
+
+    ADISense1000_HostGpioGet(HOST_READY, &bDrdy);
+    return bDrdy;
+}
+
+/*!
+ * @brief Request sample for a selected channel.
+ *
+ * @param[in] ADI_Channel_ID_t : Channel identifier.
+ * @param[out] uint32_t : Pointer to raw ADC sample for channel.
+ * @param[out] float : Pointer to linearised ADC sample for channel.
+ * @param[out] uint8_t : Pointer to channel status.
+ *
+ * @return Status
+ *         - #ADI_SENSE_SUCCESS Call completed successfully.
+ *         - #ADI_SENSE_FAILURE
+ *
+ * @details Reads Data FIFO until a sample for the requested channel is
+ *          received.
+ *
+ */
+ADI_SENSE_RESULT ADISense1000_GetData(uint32_t *pRaw, float *pSample,
+                                                        uint8_t *pStatus)
+{
+    ADI_SENSE_RESULT eRet;
+    ADI_CORE_Data_FIFO_t *pChSample = (ADI_CORE_Data_FIFO_t *)rcvBuff;
+    bool bTimeOut = false;
+    uint32_t timeNow;
+    uint32_t runTime;
+
+    /* Read Data FIFO buffer until sample for channel is read */
+    readTimeout.reset();
+    readTimeout.start();
+    timeNow = readTimeout.read();
+    do {
+        eRet = ADISense1000_RegRead(regMap[CORE_DATA_FIFO].addr,
+                                        regMap[CORE_DATA_FIFO].size,
+                                                    rcvBuff);
+        runTime = (readTimeout.read() - timeNow);
+        if (runTime > GET_SAMPLE_TIMEOUT)
+        {
+            bTimeOut = true;
+        }
+    wait_ms(10);
+    }
+    while ((pChSample->Ch_Valid != 1) && eRet == ADI_SENSE_SUCCESS &&
+                                        !(bTimeOut));
+
+    readTimeout.stop();
+
+    if (eRet != ADI_SENSE_SUCCESS)
+    {
+        pChSample->Raw_Sample = 0;
+        pChSample->Sensor_Result = 0;
+        *pRaw = pChSample->Raw_Sample;
+        *pSample = pChSample->Sensor_Result;
+        *pStatus = (pChSample->Channel_ID)|((pChSample->Ch_Error << 4))|
+                    ((pChSample->Ch_Alert << 5))|((pChSample->Ch_Raw << 6))|
+                                        ((pChSample->Ch_Valid << 7));
+
+       return eRet;
+    }
+
+    if (bTimeOut == true)
+    {
+        pChSample->Raw_Sample = 0;
+        pChSample->Sensor_Result = 0;
+        *pRaw = pChSample->Raw_Sample;
+        *pSample = pChSample->Sensor_Result;
+        *pStatus = (pChSample->Channel_ID)|((pChSample->Ch_Error << 4))|
+                    ((pChSample->Ch_Alert << 5))|((pChSample->Ch_Raw << 6))|
+                                        ((pChSample->Ch_Valid << 7));
+
+       return ADI_SENSE_NO_DATA;
+    }
+
+    *pRaw = pChSample->Raw_Sample;
+    *pSample = pChSample->Sensor_Result;
+    *pStatus = (pChSample->Channel_ID)|((pChSample->Ch_Error << 4))|
+                    ((pChSample->Ch_Alert << 5))|((pChSample->Ch_Raw << 6))|
+                                        ((pChSample->Ch_Valid << 7));
+
+    return ADI_SENSE_SUCCESS;
+}
+
+/*!
+ * @brief Get register value from ADISense1000 Module
+ *
+ * @param[in] uint16_t : Register Identifier
+ * @param[out] uint32_t : Pointer to the register value.
+ *
+ * @return Status
+ *         - #ADI_SENSE_SUCCESS Call completed successfully.
+ *         - #ADI_SENSE_FAILURE
+ *         - #ADI_SENSE_INVALID_OPERATION Invalid register identifier.
+ *
+ * @details Will return the value for any of the ADISense modules
+ *          1 byte to 4 byte size. Data FIFO register is not available to
+ *          this function.
+ */
+ADI_SENSE_RESULT ADISense1000_GetRegister(uint16_t reg, uint32_t *pRegValue)
+{
+    ADI_SENSE_RESULT eRet;
+    uint8_t i;
+    uint32_t n;
+
+    if (regMap[reg].rw == WRITE_ONLY || reg > REGISTER_MAP_COUNT
+                || regMap[reg].size > 4)
+    {
+        return ADI_SENSE_INVALID_OPERATION;
+    }
+
+    eRet = ADISense1000_RegRead(regMap[reg].addr, regMap[reg].size, rcvBuff);
+
+    if(eRet != ADI_SENSE_SUCCESS)
+    {
+        return eRet;
+    }
+
+    n=0;
+    for (i=0; i<regMap[reg].size; i++)
+    {
+        n = n | (rcvBuff[i] << (i*8));
+    }
+
+    *pRegValue = n & BIT_MASK((regMap[reg].size*8));
+
+    return ADI_SENSE_SUCCESS;
+}
+
+
+/*!
+ * @brief Set register value to ADISense1000 Module
+ *
+ * @param[in] uint16_t : Register Identifier.
+ * @param[in] uint32_t : Value to write to register.
+ *
+ * @return Status
+ *         - #ADI_SENSE_SUCCESS Call completed successfully.
+ *         - #ADI_SENSE_FAILURE
+ *         - #ADI_SENSE_INVALID_OPERATION Invalid register identifier.
+ *
+ * @details Will write a value to any of the writable ADISense modules
+ *          regiters from 1 byte to 4 byte size.
+ *
+ */
+ADI_SENSE_RESULT ADISense1000_SetRegister(uint16_t reg, uint32_t regValue)
+{
+    ADI_SENSE_RESULT eRet;
+
+    if (regMap[reg].rw == READ_ONLY || reg > REGISTER_MAP_COUNT
+                || regMap[reg].size > 4)
+    {
+            return ADI_SENSE_INVALID_OPERATION;
+    }
+
+    eRet = ADISense1000_RegWrite(regMap[reg].addr, regMap[reg].size,
+                                            (uint8_t*)(&regValue));
+
+    if(eRet != ADI_SENSE_SUCCESS)
+    {
+        return eRet;
+    }
+
+    return ADI_SENSE_SUCCESS;
+}
+