Ross O'Halloran / Mbed OS AdiSense1000_SmartBabySeat

Fork of AdiSense1000_SmartBabySeat by SDMP_IOT

common/utils.c

Committer:
giancarloDotta
Date:
2018-07-18
Branch:
gd_dbg2142
Revision:
32:119f86d3d9ed
Parent:
31:de49744b57a6

File content as of revision 32:119f86d3d9ed:

#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_WARN("\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_ERROR("\tActive Errors - RESET REQUIRED");
        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_FIFO_ERROR)
            ADI_SENSE_LOG_WARN("\tActive FIFO Errors - ATTENTION REQUIRED");
        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_CONFIG_ERROR)
            ADI_SENSE_LOG_ERROR("\tActive Configuration Errors - ATTENTION REQUIRED");
        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_LUT_ERROR)
            ADI_SENSE_LOG_ERROR("\tActive Look-Up Table Errors - ATTENTION REQUIRED");
        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_EXT_FLASH_ERROR)
            ADI_SENSE_LOG_ERROR("\tActive External Flash Errors - ATTENTION REQUIRED");

        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_ERROR) {
            ADI_SENSE_LOG_ERROR("\tActive Errors - ATTENTION REQUIRED");
            ADI_SENSE_LOG_ERROR("\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_ERROR("\t\tActive diagnostics faults:");

                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_CHECKSUM_ERROR)
                    ADI_SENSE_LOG_ERROR("\t\t\tInternal Checksum fault detected");
                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_COMMS_ERROR)
                    ADI_SENSE_LOG_WARN("\t\t\tInternal Communications fault detected");
                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_SUPPLY_MONITOR_ERROR)
                    ADI_SENSE_LOG_WARN("\t\t\tSupply Monitor fault detected");
                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_SUPPLY_CAP_ERROR)
                    ADI_SENSE_LOG_WARN("\t\t\tSupply Regulator Capacitor fault detected");
                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_CONVERSION_ERROR)
                    ADI_SENSE_LOG_WARN("\t\t\tInternal ADC Conversions fault detected");
                if (pStatus->diagnosticsStatus & ADI_SENSE_DIAGNOSTICS_STATUS_CALIBRATION_ERROR)
                    ADI_SENSE_LOG_WARN("\t\t\tInternal Device Calibrations fault detected");
            }
        }

        if (pStatus->deviceStatus & ADI_SENSE_DEVICE_STATUS_ALERT) {
            ADI_SENSE_LOG_WARN("\tActive Alerts - ATTENTION REQUIRED:");
            ADI_SENSE_LOG_WARN("\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",
            ADI_SENSE_LOG_INFO("%3d %2d %06x %f F: %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" : "");
        }
    }
}

void utils_printSamplesSummary(
    ADI_SENSE_DATA_SAMPLE *pSampleBuffer,
    uint32_t nNumSamples,
    ADI_SENSE_MEASUREMENT_MODE eMeasurementMode)
{
    bool fftMode = (eMeasurementMode == ADI_SENSE_MEASUREMENT_MODE_FFT);
    if (fftMode) {
        ADI_SENSE_LOG_ERROR("FUNCTION NOT FOR FFT!");
        return;
    }

    unsigned random = 1;
    for (int ch = 0; ch < 13; ++ch) {
        float accum = 0.0;
        int accumR = 0;
        int count = 0;
        int countAlerts = 0;
        int countErrors = 0;
        for (uint32_t i = 0; i < nNumSamples; i++) {

            if (pSampleBuffer[i].channelId == ch) {
                count++;
                accum += pSampleBuffer[i].processedValue;
                accumR += pSampleBuffer[i].rawValue;
                if (pSampleBuffer[i].status & ADI_SENSE_DEVICE_STATUS_ALERT)
                    countAlerts++;
                if (pSampleBuffer[i].status & ADI_SENSE_DEVICE_STATUS_ERROR)
                    countErrors++;
            }
        }

        if (count > 0)
            ADI_SENSE_LOG_INFO("Ch-%d: Samples %4d, Raw: 0x%06x, Meas: %f, alerts: %d, errors: %d",
                               ch, count, accumR/count, accum/count, countAlerts, countErrors);
        random ^= accumR;
    }
    srand(random);
}

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 kickOffMeasurementCycle(
    ADI_SENSE_DEVICE_HANDLE    const hDevice,
    ADI_SENSE_MEASUREMENT_MODE const eMeasurementMode,
    volatile bool *bDataReady,
    volatile bool *bError,
    volatile bool *bAlert,
    ADI_SENSE_1000_OPERATING_MODE eOperatingMode,
    ADI_SENSE_1000_DATAREADY_MODE eDataReadyMode,
    uint32_t nSamplesPerDataready,
    uint32_t nSamplesPerCycle,
    uint8_t nBytesPerSample,
    ADI_SENSE_DATA_SAMPLE *pSampleBuffer    )
{
    ADI_SENSE_RESULT res;

    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
         */
        int count = 0;
        ADI_SENSE_LOG_INFO("Waiting up to 300.... (%d|%d)", *bDataReady, *bError);
        const unsigned int period = 10000000/2;
        while (! (*bDataReady || *bError)) {
            if (++count % period == 0)
                adi_sense_Print("%d ", count /period );
            if (count >= 600*period) {
                ADI_SENSE_LOG_ERROR("Timeout");
                return 1;
            }
        }
        ADI_SENSE_LOG_INFO("Waiting is over.");
        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_WARN("Retrieved %u of %u requested data samples",
                                       nReturned, nSamplesPerDataready);
                } else {
                    ADI_SENSE_LOG_ERROR("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.
             */
            ADI_SENSE_LOG_INFO("Sample summary:");
            if (nReturned <= 0) {
                ADI_SENSE_LOG_ERROR("NO SAMPLES AT ALL");
                return 1;
            }
            utils_printSamplesSummary(pSampleBuffer, nReturned, eMeasurementMode);
            nSampleCount += nReturned;
            ADI_SENSE_LOG_INFO("Total samples: %d (%d)", nReturned, nSampleCount);
        }

        /*
         * 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);

                if (status.errorCode) {
                    ADI_SENSE_LOG_ERROR("GD error=%d and alert=%d", status.errorCode,
                                        status.alertCode);
                    return status.errorCode;
                }
                if (status.alertCode) {
                    ADI_SENSE_LOG_ERROR("GD alert=%d", status.alertCode);
                    return status.alertCode;
                }

                /* Break out of the loop if any errors are raised */
                if (*bError) {
                    ADI_SENSE_LOG_ERROR("Failed bError");
                    break;
                }
            }
            ADI_SENSE_LOG_INFO("End of status print");
        }

        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)) {
                ADI_SENSE_LOG_INFO("block done.");
                break;
            }
            ADI_SENSE_LOG_INFO("End of single Cycle");
        }
    }

    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;
    }

    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) {
        ADI_SENSE_LOG_ERROR("Failed utils_registerCallbacks");
        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) {
        ADI_SENSE_LOG_ERROR("Failed GetDataReadyModeInfo");
        return res;
    }
    ADI_SENSE_LOG_INFO("mMode %d, oMode %d, drMode %d, nsDrdy=%d, nsCyc=%d, bytesPS=%d",
                       eMeasurementMode, eOperatingMode, eDataReadyMode, nSamplesPerDataready,
                       nSamplesPerCycle, nBytesPerSample);
    /*
     * Allocate a buffer to store the samples retrieved on each DATAREADY pulse
     */
    ADI_SENSE_DATA_SAMPLE *pSampleBuffer = NULL;
    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;
    }

    res = kickOffMeasurementCycle( hDevice, eMeasurementMode, &bDataReady, &bError,
                                   &bAlert, eOperatingMode, eDataReadyMode, nSamplesPerDataready,
                                   nSamplesPerCycle, nBytesPerSample, pSampleBuffer);


    free(pSampleBuffer);

    ADI_SENSE_RESULT res2 = utils_deregisterCallbacks(hDevice);
    if (res2 != ADI_SENSE_SUCCESS)
        return res2;

    return res;
}