initial commit

Revision:
0:85855ecd3257
Child:
1:63dd03580de4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/utils.c	Mon Apr 01 11:09:52 2019 +0000
@@ -0,0 +1,421 @@
+#include <stdlib.h>
+
+#include "utils.h"
+#include "adi_sense_log.h"
+
+void utils_printStatus(
+    ADI_SENSE_STATUS *pStatus)
+{
+    ADI_SENSE_LOG_INFO("Status Summary:");
+
+    if (pStatus->deviceStatus == 0)
+    {
+        ADI_SENSE_LOG_INFO("\tNo errors detected");
+    }
+    else
+    {
+        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_BUSY)
+            ADI_SENSE_LOG_INFO("\tCommand running");
+        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_DATAREADY)
+            ADI_SENSE_LOG_INFO("\tData ready");
+        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_ERROR)
+            ADI_SENSE_LOG_INFO("\tActive Errors - RESET REQUIRED");
+        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_FIFO_ERROR)
+            ADI_SENSE_LOG_INFO("\tActive FIFO Errors - ATTENTION REQUIRED");
+        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_CONFIG_ERROR)
+            ADI_SENSE_LOG_INFO("\tActive Configuration Errors - ATTENTION REQUIRED");
+        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_LUT_ERROR)
+            ADI_SENSE_LOG_INFO("\tActive Look-Up Table Errors - ATTENTION REQUIRED");
+        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_EXT_FLASH_ERROR)
+            ADI_SENSE_LOG_INFO("\tActive External Flash Errors - ATTENTION REQUIRED");
+
+        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_ERROR)
+        {
+            ADI_SENSE_LOG_INFO("\tActive Errors - ATTENTION REQUIRED");
+            ADI_SENSE_LOG_INFO("\t\tLast Error Code: %u (0x%X)",
+                               pStatus->errorCode, pStatus->errorCode);
+
+            if (pStatus->diagnosticsStatus == 0)
+            {
+                ADI_SENSE_LOG_INFO("\t\tNo diagnostics faults detected");
+            }
+            else
+            {
+                ADI_SENSE_LOG_INFO("\t\tActive diagnostics faults:");
+
+                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_CHECKSUM_ERROR)
+                    ADI_SENSE_LOG_INFO("\t\t\tInternal Checksum fault detected");
+                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_COMMS_ERROR)
+                    ADI_SENSE_LOG_INFO("\t\t\tInternal Communications fault detected");
+                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_SUPPLY_MONITOR_ERROR)
+                    ADI_SENSE_LOG_INFO("\t\t\tSupply Monitor fault detected");
+                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_SUPPLY_CAP_ERROR)
+                    ADI_SENSE_LOG_INFO("\t\t\tSupply Regulator Capacitor fault detected");
+                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_CONVERSION_ERROR)
+                    ADI_SENSE_LOG_INFO("\t\t\tInternal ADC Conversions fault detected");
+                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_CALIBRATION_ERROR)
+                    ADI_SENSE_LOG_INFO("\t\t\tInternal Device Calibrations fault detected");
+            }
+        }
+
+        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_ALERT)
+        {
+            ADI_SENSE_LOG_INFO("\tActive Alerts - ATTENTION REQUIRED:");
+            ADI_SENSE_LOG_INFO("\t\tLast Alert Code: %u (0x%X)",
+                               pStatus->alertCode, pStatus->alertCode);
+
+            for (unsigned i = 0; i < ADI_SENSE_1000_MAX_CHANNELS; i++)
+            {
+                if (pStatus->channelAlerts[i] == 0)
+                    continue;
+
+                ADI_SENSE_LOG_INFO("\t\tChannel #%u:", i);
+                ADI_SENSE_LOG_INFO("\t\t\tLast Alert Code: %u (0x%X)",
+                                   pStatus->channelAlertCodes[i],
+                                   pStatus->channelAlertCodes[i]);
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_TIMEOUT)
+                    ADI_SENSE_LOG_INFO("\t\t\tTimeout alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_UNDER_RANGE)
+                    ADI_SENSE_LOG_INFO("\t\t\tUnder Range alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_OVER_RANGE)
+                    ADI_SENSE_LOG_INFO("\t\t\tOver Range alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_LOW_LIMIT)
+                    ADI_SENSE_LOG_INFO("\t\t\tLow limit alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_HIGH_LIMIT)
+                    ADI_SENSE_LOG_INFO("\t\t\tHigh Limit alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_SENSOR_OPEN)
+                    ADI_SENSE_LOG_INFO("\t\t\tSensor Fault alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_REF_DETECT)
+                    ADI_SENSE_LOG_INFO("\t\t\tReference Detection alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_CONFIG_ERR)
+                    ADI_SENSE_LOG_INFO("\t\t\tConfiguration Error alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_LUT_ERR)
+                    ADI_SENSE_LOG_INFO("\t\t\tLook-Up Table Error alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_SENSOR_NOT_READY)
+                    ADI_SENSE_LOG_INFO("\t\t\tSensor Not Ready alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_COMP_NOT_READY)
+                    ADI_SENSE_LOG_INFO("\t\t\tCompensation Channel Not Ready alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_LUT_UNDER_RANGE)
+                    ADI_SENSE_LOG_INFO("\t\t\tUnder Look-Up Table Range alert detected");
+                if (pStatus->channelAlerts[i] & ADI_SENSE_CHANNEL_ALERT_LUT_OVER_RANGE)
+                    ADI_SENSE_LOG_INFO("\t\t\tOver Look-Up Table Range alert detected");
+            }
+        }
+
+        if ((pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_ERROR) ||
+            (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_ALERT))
+        {
+            ADI_SENSE_LOG_INFO("\t\tLast Debug Code: %u-%u",
+                               (pStatus->debugCode >> 16) & 0xFFFF,
+                               (pStatus->debugCode >> 0) & 0xFFFF);
+        }
+    }
+}
+
+void utils_printSamples(
+    ADI_SENSE_DATA_SAMPLE *pSampleBuffer,
+    uint32_t nNumSamples,
+    ADI_SENSE_MEASUREMENT_MODE eMeasurementMode)
+{
+    bool fftMode = (eMeasurementMode == ADI_SENSE_MEASUREMENT_MODE_FFT);
+
+    for (uint32_t i = 0; i < nNumSamples; i++)
+    {
+        if (fftMode)
+        {
+            ADI_SENSE_LOG_INFO("Sample # %2d Channel # %2d :: Bin/Raw %8d  :: Magnitude %e :: flags:%s%s",
+                               i+1,
+                               pSampleBuffer[i].channelId,
+                               pSampleBuffer[i].rawValue,
+                               pSampleBuffer[i].processedValue,
+                               pSampleBuffer[i].status & ADI_SENSE_DEVICE_STATUS_ERROR ? " ERROR" : "",
+                               pSampleBuffer[i].status & ADI_SENSE_DEVICE_STATUS_ALERT ? " ALERT" : "");
+        }
+        else
+        {
+            ADI_SENSE_LOG_INFO("Sample # %2d Channel # %2d :: Raw %8d  :: Processed %f :: flags:%s%s",
+                               i+1,
+                               pSampleBuffer[i].channelId,
+                               pSampleBuffer[i].rawValue,
+                               pSampleBuffer[i].processedValue,
+                               pSampleBuffer[i].status & ADI_SENSE_DEVICE_STATUS_ERROR ? " ERROR" : "",
+                               pSampleBuffer[i].status & ADI_SENSE_DEVICE_STATUS_ALERT ? " ALERT" : "");
+        }
+    }
+}
+
+static void gpioCallbackFn(ADI_SENSE_GPIO_PIN ePinId, void * pArg)
+{
+    volatile bool *pbFlag = (volatile bool *)pArg;
+    *pbFlag = true;
+}
+
+ADI_SENSE_RESULT utils_registerCallbacks(
+    ADI_SENSE_DEVICE_HANDLE hDevice,
+    volatile bool *pbDataReady,
+    volatile bool *pbError,
+    volatile bool *pbAlert)
+{
+    ADI_SENSE_RESULT res;
+    bool state;
+
+    res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_DATAREADY,
+                                         gpioCallbackFn, (void *)pbDataReady);
+    if (res != ADI_SENSE_SUCCESS)
+    {
+        ADI_SENSE_LOG_ERROR("Failed to register DATAREADY callback");
+        return res;
+    }
+
+    res = adi_sense_GetGpioState(hDevice, ADI_SENSE_GPIO_PIN_ERROR, &state);
+    if (res != ADI_SENSE_SUCCESS)
+    {
+        ADI_SENSE_LOG_ERROR("Failed to get current ERROR state");
+        return res;
+    }
+    if (state)
+    {
+        ADI_SENSE_LOG_ERROR("ERROR signal already asserted");
+        return ADI_SENSE_FAILURE;
+    }
+    res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_ERROR,
+                                         gpioCallbackFn, (void *)pbError);
+    if (res != ADI_SENSE_SUCCESS)
+    {
+        ADI_SENSE_LOG_ERROR("Failed to register ERROR callback");
+        return res;
+    }
+
+    res = adi_sense_GetGpioState(hDevice, ADI_SENSE_GPIO_PIN_ALERT, &state);
+    if (res != ADI_SENSE_SUCCESS)
+    {
+        ADI_SENSE_LOG_ERROR("Failed to get current ALERT state");
+        return res;
+    }
+    if (state)
+    {
+        ADI_SENSE_LOG_ERROR("ALERT signal already asserted");
+        return ADI_SENSE_FAILURE;
+    }
+    res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_ALERT,
+                                         gpioCallbackFn, (void *)pbAlert);
+    if (res != ADI_SENSE_SUCCESS)
+    {
+        ADI_SENSE_LOG_ERROR("Failed to register ALERT callback");
+        return res;
+    }
+
+    return ADI_SENSE_SUCCESS;
+}
+
+ADI_SENSE_RESULT utils_deregisterCallbacks(
+    ADI_SENSE_DEVICE_HANDLE hDevice)
+{
+    ADI_SENSE_RESULT res;
+
+    res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_DATAREADY,
+                                         NULL, NULL);
+    if (res != ADI_SENSE_SUCCESS)
+    {
+        ADI_SENSE_LOG_ERROR("Failed to deregister DATAREADY callback");
+        return res;
+    }
+
+    res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_ERROR,
+                                         NULL, NULL);
+    if (res != ADI_SENSE_SUCCESS)
+    {
+        ADI_SENSE_LOG_ERROR("Failed to deregister ERROR callback");
+        return res;
+    }
+
+    res = adi_sense_RegisterGpioCallback(hDevice, ADI_SENSE_GPIO_PIN_ALERT,
+                                         NULL, NULL);
+    if (res != ADI_SENSE_SUCCESS)
+    {
+        ADI_SENSE_LOG_INFO("Failed to deregister ALERT callback");
+        return res;
+    }
+
+    return ADI_SENSE_SUCCESS;
+}
+
+ADI_SENSE_RESULT utils_runMeasurement(
+    ADI_SENSE_DEVICE_HANDLE hDevice,
+    ADI_SENSE_MEASUREMENT_MODE eMeasurementMode)
+{
+    ADI_SENSE_RESULT res;
+
+    volatile bool bDataReady = false;
+    volatile bool bError = false;
+    volatile bool bAlert = false;
+    res = utils_registerCallbacks(hDevice, &bDataReady, &bError, &bAlert);
+    if (res != ADI_SENSE_SUCCESS)
+        return res;
+
+    /*
+     * Retrieve the number of samples per cycle, per DATAREADY pulse, etc. for
+     * this configuration.
+     */
+    ADI_SENSE_1000_OPERATING_MODE eOperatingMode;
+    ADI_SENSE_1000_DATAREADY_MODE eDataReadyMode;
+    uint32_t nSamplesPerDataready;
+    uint32_t nSamplesPerCycle;
+    uint8_t nBytesPerSample;
+    res = adi_sense_1000_GetDataReadyModeInfo(hDevice,
+                                              eMeasurementMode,
+                                              &eOperatingMode,
+                                              &eDataReadyMode,
+                                              &nSamplesPerDataready,
+                                              &nSamplesPerCycle,
+                                              &nBytesPerSample);
+    if (res != ADI_SENSE_SUCCESS)
+        return res;
+
+    /*
+     * Allocate a buffer to store the samples retrieved on each DATAREADY pulse
+     */
+    ADI_SENSE_DATA_SAMPLE *pSampleBuffer;
+    pSampleBuffer = malloc(sizeof(ADI_SENSE_DATA_SAMPLE) *
+                           nSamplesPerDataready);
+    if (pSampleBuffer == NULL)
+    {
+        ADI_SENSE_LOG_ERROR("Failed to allocate sample buffer");
+        return ADI_SENSE_NO_MEM;
+    }
+
+    /*
+     * Kick off the measurement cycle(s) here
+     */
+    ADI_SENSE_LOG_INFO("Starting measurement");
+    res = adi_sense_StartMeasurement(hDevice, eMeasurementMode);
+    if (res != ADI_SENSE_SUCCESS)
+    {
+        ADI_SENSE_LOG_ERROR("Failed to start measurement");
+        return res;
+    }
+
+    /*
+     * Loop continuously unless operating mode is single-cycle
+     */
+    uint32_t nSampleCount = 0;
+    uint32_t nReturned;
+    while (true)
+    {
+        ADI_SENSE_STATUS status;
+
+        /*
+         * Wait until the next batch of 1 or more samples is ready, continuously
+         * checking DATAREADY until it is asserted
+         */
+        while (! (bDataReady || bError))
+            ;
+
+        if (!bError)
+        {
+            /*
+             * Get data samples from the measurement cycle, if no error has occurred
+             */
+            bDataReady = false;
+            res = adi_sense_GetData(hDevice, eMeasurementMode, pSampleBuffer,
+                                    nBytesPerSample, nSamplesPerDataready,
+                                    &nReturned);
+            if (res != ADI_SENSE_SUCCESS)
+            {
+                if (res == ADI_SENSE_INCOMPLETE)
+                {
+                    /*
+                     * This is expected in cases where cycleSkipCount may
+                     * be non-zero for some channels, resulting in
+                     * variable-length sequences
+                     */
+                    ADI_SENSE_LOG_DEBUG("Retrieved %u of %u requested data samples",
+                                        nReturned, nSamplesPerDataready);
+                }
+                else
+                {
+                    ADI_SENSE_LOG_WARN("Failed to get data samples from device");
+                    return res;
+                }
+            }
+
+            /*
+             * Display the data samples.
+             *
+             * NOTE: this requires a sufficient idle time between subsequent
+             * DATAREADY pulses to allow printing to occur.  Otherwise,
+             * subsequent samples may be missed if not retrieved promptly when
+             * the next DATAREADY assertion occurs.
+             */
+            utils_printSamples(pSampleBuffer, nReturned, eMeasurementMode);
+            nSampleCount += nReturned;
+        }
+
+        /*
+         * Check and print device status if errors/alerts have been triggered
+         */
+        if (bError || bAlert)
+        {
+            res = adi_sense_GetStatus(hDevice, &status);
+            if (res != ADI_SENSE_SUCCESS)
+            {
+                ADI_SENSE_LOG_ERROR("Failed to retrieve device status");
+                return res;
+            }
+
+            if (status.deviceStatus &
+                (ADI_SENSE_DEVICE_STATUS_ERROR | ADI_SENSE_DEVICE_STATUS_ALERT))
+            {
+                utils_printStatus(&status);
+
+                /* Break out of the loop if any errors are raised */
+                if (bError)
+                    break;
+            }
+        }
+
+        if (eOperatingMode == ADI_SENSE_1000_OPERATING_MODE_SINGLECYCLE)
+        {
+            /*
+             * In this mode, break out of the loop when the measurement command
+             * has completed.
+             *
+             * One option is to check for the expected number of samples to be
+             * returned for the cycle.  However, cycles may have variable-length
+             * sequences if the cycleSkipCount option is non-zero for any of the
+             * channels.
+             *
+             * So, instead, we check for the command-running status, which
+             * will de-assert in this mode when the measurement command has
+             * completed a single cycle.
+             */
+            bool bCommandRunning;
+            res = adi_sense_GetCommandRunningState(hDevice, &bCommandRunning);
+            if (res != ADI_SENSE_SUCCESS)
+            {
+                ADI_SENSE_LOG_ERROR("Failed to get command-running status");
+                return res;
+            }
+
+            if (!bCommandRunning && !bDataReady)
+                break;
+        }
+    }
+
+    ADI_SENSE_LOG_INFO("Stopping measurement");
+    res = adi_sense_StopMeasurement(hDevice);
+    if (res != ADI_SENSE_SUCCESS)
+    {
+        ADI_SENSE_LOG_ERROR("Failed to send stop measurement");
+        return res;
+    }
+
+    free(pSampleBuffer);
+
+    res = utils_deregisterCallbacks(hDevice);
+    if (res != ADI_SENSE_SUCCESS)
+        return res;
+
+    return ADI_SENSE_SUCCESS;
+}
+