Vybhav Kadaba
/
EV-PRO-MW1001_Development_20April
Code clean up and handling FIFO errors
Diff: common/utils.c
- 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; +} +