Host API Example for the ADMW1001

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers utils.c Source File

utils.c

Go to the documentation of this file.
00001 /*
00002 Copyright 2019 (c) Analog Devices, Inc.
00003 
00004 All rights reserved.
00005 
00006 Redistribution and use in source and binary forms, with or without
00007 modification, are permitted provided that the following conditions are met:
00008   - Redistributions of source code must retain the above copyright
00009     notice, this list of conditions and the following disclaimer.
00010   - Redistributions in binary form must reproduce the above copyright
00011     notice, this list of conditions and the following disclaimer in
00012     the documentation and/or other materials provided with the
00013     distribution.
00014   - Neither the name of Analog Devices, Inc. nor the names of its
00015     contributors may be used to endorse or promote products derived
00016     from this software without specific prior written permission.
00017   - The use of this software may or may not infringe the patent rights
00018     of one or more patent holders. This license does not release you
00019     from the requirement that you obtain separate licenses from these
00020     patent holders to use this software.
00021   - Use of the software either in source or binary form, must be run
00022     on or directly connected to an Analog Devices Inc. component.
00023 
00024 THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
00025 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
00026 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00027 IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
00028 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00029 LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
00030 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00031 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00032 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00033 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034  */
00035 
00036 /*!
00037  ******************************************************************************
00038  * @file:  utils.c
00039  * @brief: Interface Utilities for ADMW1001
00040  *-----------------------------------------------------------------------------
00041  */
00042 #include <stdlib.h>
00043 
00044 #include "utils.h"
00045 #include "admw_log.h"
00046 
00047 void utils_printStatus(
00048     ADMW_STATUS  *pStatus)
00049 {
00050     ADMW_LOG_INFO("Status Summary:");
00051 
00052     if (pStatus->deviceStatus  == 0) {
00053         ADMW_LOG_INFO("\tNo errors detected");
00054     } else {
00055         if (pStatus->deviceStatus  & ADMW_DEVICE_STATUS_BUSY )
00056             ADMW_LOG_INFO("\tCommand running");
00057         if (pStatus->deviceStatus  & ADMW_DEVICE_STATUS_DATAREADY )
00058             ADMW_LOG_INFO("\tData ready");
00059         if (pStatus->deviceStatus  & ADMW_DEVICE_STATUS_ERROR )
00060             ADMW_LOG_INFO("\tActive Errors - RESET REQUIRED");
00061         if (pStatus->deviceStatus  & ADMW_DEVICE_STATUS_FIFO_ERROR )
00062             ADMW_LOG_INFO("\tActive FIFO Errors - ATTENTION REQUIRED");
00063         if (pStatus->deviceStatus  & ADMW_DEVICE_STATUS_CONFIG_ERROR )
00064             ADMW_LOG_INFO("\tActive Configuration Errors - ATTENTION REQUIRED");
00065         if (pStatus->deviceStatus  & ADMW_DEVICE_STATUS_LUT_ERROR )
00066             ADMW_LOG_INFO("\tActive Look-Up Table Errors - ATTENTION REQUIRED");
00067 
00068 
00069         if (pStatus->deviceStatus  & ADMW_DEVICE_STATUS_ERROR ) {
00070             ADMW_LOG_INFO("\tActive Errors - ATTENTION REQUIRED");
00071             ADMW_LOG_INFO("\t\tLast Error Code: %u (0x%X)",
00072                           pStatus->errorCode , pStatus->errorCode );
00073 
00074             if (pStatus->diagnosticsStatus  == 0) {
00075                 ADMW_LOG_INFO("\t\tNo diagnostics faults detected");
00076             } else {
00077                 ADMW_LOG_INFO("\t\tActive diagnostics faults:");
00078 
00079                 if (pStatus->diagnosticsStatus  & ADMW_DIAGNOSTICS_STATUS_CHECKSUM_ERROR )
00080                     ADMW_LOG_INFO("\t\t\tInternal Checksum fault detected");
00081 
00082 
00083 
00084                 if (pStatus->diagnosticsStatus  & ADMW_DIAGNOSTICS_STATUS_CONVERSION_ERROR )
00085                     ADMW_LOG_INFO("\t\t\tInternal ADC Conversions fault detected");
00086                 if (pStatus->diagnosticsStatus  & ADMW_DIAGNOSTICS_STATUS_CALIBRATION_ERROR )
00087                     ADMW_LOG_INFO("\t\t\tInternal Device Calibrations fault detected");
00088             }
00089         }
00090 
00091         if (pStatus->deviceStatus  & ADMW_DEVICE_STATUS_ALERT ) {
00092             ADMW_LOG_INFO("\tActive Alerts - ATTENTION REQUIRED:");
00093             ADMW_LOG_INFO("\t\tLast Alert Code: %u (0x%X)",
00094                           pStatus->alertCode , pStatus->alertCode );
00095 
00096             for (unsigned i = 0; i < ADMW1001_MAX_CHANNELS ; i++) {
00097                 if (pStatus->channelAlerts [i] == 0)
00098                     continue;
00099 
00100                 ADMW_LOG_INFO("\t\tChannel #%u:", i);
00101                 ADMW_LOG_INFO("\t\t\tLast Alert Code: %u (0x%X)",
00102                               pStatus->channelAlertCodes [i],
00103                               pStatus->channelAlertCodes [i]);
00104                 if (pStatus->channelAlerts [i] & ADMW_CHANNEL_ALERT_TIMEOUT )
00105                     ADMW_LOG_INFO("\t\t\tTimeout alert detected");
00106                 if (pStatus->channelAlerts [i] & ADMW_CHANNEL_ALERT_UNDER_RANGE )
00107                     ADMW_LOG_INFO("\t\t\tUnder Range alert detected");
00108                 if (pStatus->channelAlerts [i] & ADMW_CHANNEL_ALERT_OVER_RANGE )
00109                     ADMW_LOG_INFO("\t\t\tOver Range alert detected");
00110                 if (pStatus->channelAlerts [i] & ADMW_CHANNEL_ALERT_LOW_LIMIT )
00111                     ADMW_LOG_INFO("\t\t\tLow limit alert detected");
00112                 if (pStatus->channelAlerts [i] & ADMW_CHANNEL_ALERT_HIGH_LIMIT )
00113                     ADMW_LOG_INFO("\t\t\tHigh Limit alert detected");
00114                 if (pStatus->channelAlerts [i] & ADMW_CHANNEL_ALERT_SENSOR_OPEN )
00115                     ADMW_LOG_INFO("\t\t\tSensor Fault alert detected");
00116                 if (pStatus->channelAlerts [i] & ADMW_CHANNEL_ALERT_REF_DETECT )
00117                     ADMW_LOG_INFO("\t\t\tReference Detection alert detected");
00118                 if (pStatus->channelAlerts [i] & ADMW_CHANNEL_ALERT_CONFIG_ERR )
00119                     ADMW_LOG_INFO("\t\t\tConfiguration Error alert detected");
00120                 if (pStatus->channelAlerts [i] & ADMW_CHANNEL_ALERT_LUT_ERR )
00121                     ADMW_LOG_INFO("\t\t\tLook-Up Table Error alert detected");
00122                 if (pStatus->channelAlerts [i] & ADMW_CHANNEL_ALERT_SENSOR_NOT_READY )
00123                     ADMW_LOG_INFO("\t\t\tSensor Not Ready alert detected");
00124                 if (pStatus->channelAlerts [i] & ADMW_CHANNEL_ALERT_COMP_NOT_READY )
00125                     ADMW_LOG_INFO("\t\t\tCompensation Channel Not Ready alert detected");
00126                 if (pStatus->channelAlerts [i] & ADMW_CHANNEL_ALERT_LUT_UNDER_RANGE )
00127                     ADMW_LOG_INFO("\t\t\tUnder Look-Up Table Range alert detected");
00128                 if (pStatus->channelAlerts [i] & ADMW_CHANNEL_ALERT_LUT_OVER_RANGE )
00129                     ADMW_LOG_INFO("\t\t\tOver Look-Up Table Range alert detected");
00130             }
00131         }
00132 
00133         if ((pStatus->deviceStatus  & ADMW_DEVICE_STATUS_ERROR ) ||
00134                 (pStatus->deviceStatus  & ADMW_DEVICE_STATUS_ALERT )) {
00135             ADMW_LOG_INFO("\t\tLast Debug Code: %u-%u",
00136                           (pStatus->debugCode  >> 16) & 0xFFFF,
00137                           (pStatus->debugCode  >> 0) & 0xFFFF);
00138         }
00139     }
00140 }
00141 
00142 void utils_printSamples(
00143     ADMW_DATA_SAMPLE  *pSampleBuffer,
00144     uint32_t nNumSamples,
00145     ADMW_MEASUREMENT_MODE  eMeasurementMode)
00146 {
00147 
00148     for (uint32_t i = 0; i < nNumSamples; i++) {
00149         ADMW_LOG_INFO("Sample # %2d Channel # %2d :: Raw %0X %f :: Processed %f :: flags:%s%s",
00150                       i+1,
00151                       pSampleBuffer[i].channelId,
00152                       pSampleBuffer[i].rawValue, (pSampleBuffer[i].rawValue/1024.0),
00153                       pSampleBuffer[i].processedValue,
00154                       pSampleBuffer[i].status & ADMW_DEVICE_STATUS_ERROR  ? " ERROR" : "",
00155                       pSampleBuffer[i].status & ADMW_DEVICE_STATUS_ALERT  ? " ALERT" : "");
00156     }
00157 }
00158 
00159 static void gpioCallbackFn(ADMW_GPIO_PIN  ePinId, void * pArg)
00160 {
00161     volatile bool *pbFlag = (volatile bool *)pArg;
00162     *pbFlag = true;
00163 }
00164 
00165 ADMW_RESULT  utils_registerCallbacks(
00166     ADMW_DEVICE_HANDLE  hDevice,
00167     volatile bool *pbDataReady,
00168     volatile bool *pbError,
00169     volatile bool *pbAlert)
00170 {
00171     ADMW_RESULT  res;
00172     bool state;
00173 
00174     res = admw_RegisterGpioCallback(hDevice, ADMW_GPIO_PIN_DATAREADY ,
00175                                     gpioCallbackFn, (void *)pbDataReady);
00176     if (res != ADMW_SUCCESS ) {
00177         ADMW_LOG_ERROR("Failed to register DATAREADY callback");
00178         return res;
00179     }
00180 
00181     res = admw_GetGpioState(hDevice, ADMW_GPIO_PIN_ALERT_ERROR , &state);
00182     if (res != ADMW_SUCCESS ) {
00183         ADMW_LOG_ERROR("Failed to get current ERROR state");
00184         return res;
00185     }
00186     if (state) {
00187         ADMW_LOG_ERROR("ERROR signal already asserted");
00188         return ADMW_FAILURE ;
00189     }
00190     res = admw_RegisterGpioCallback(hDevice, ADMW_GPIO_PIN_ALERT_ERROR ,
00191                                     gpioCallbackFn, (void *)pbError);
00192     if (res != ADMW_SUCCESS ) {
00193         ADMW_LOG_ERROR("Failed to register ERROR callback");
00194         return res;
00195     }
00196 
00197     /*res = admw_GetGpioState(hDevice, ADMW_GPIO_PIN_ALERT, &state);
00198     if (res != ADMW_SUCCESS)
00199     {
00200         ADMW_LOG_ERROR("Failed to get current ALERT state");
00201         return res;
00202     }
00203     if (state)
00204     {
00205         ADMW_LOG_ERROR("ALERT signal already asserted");
00206         return ADMW_FAILURE;
00207     }*/
00208     res = admw_RegisterGpioCallback(hDevice, ADMW_GPIO_PIN_ALERT_ERROR ,
00209                                     gpioCallbackFn, (void *)pbAlert);
00210     if (res != ADMW_SUCCESS ) {
00211         ADMW_LOG_ERROR("Failed to register ALERT callback");
00212         return res;
00213     }
00214 
00215     return ADMW_SUCCESS ;
00216 }
00217 
00218 ADMW_RESULT  utils_deregisterCallbacks(
00219     ADMW_DEVICE_HANDLE  hDevice)
00220 {
00221     ADMW_RESULT  res;
00222 
00223     res = admw_RegisterGpioCallback(hDevice, ADMW_GPIO_PIN_DATAREADY ,
00224                                     NULL, NULL);
00225     if (res != ADMW_SUCCESS ) {
00226         ADMW_LOG_ERROR("Failed to deregister DATAREADY callback");
00227         return res;
00228     }
00229 
00230     res = admw_RegisterGpioCallback(hDevice, ADMW_GPIO_PIN_ALERT_ERROR ,
00231                                     NULL, NULL);
00232     if (res != ADMW_SUCCESS ) {
00233         ADMW_LOG_ERROR("Failed to deregister ERROR callback");
00234         return res;
00235     }
00236 
00237     res = admw_RegisterGpioCallback(hDevice, ADMW_GPIO_PIN_ALERT_ERROR ,
00238                                     NULL, NULL);
00239     if (res != ADMW_SUCCESS ) {
00240         ADMW_LOG_INFO("Failed to deregister ALERT callback");
00241         return res;
00242     }
00243 
00244     return ADMW_SUCCESS ;
00245 }
00246 
00247 ADMW_RESULT  utils_runMeasurement(
00248     ADMW_DEVICE_HANDLE  hDevice,
00249     ADMW_MEASUREMENT_MODE  eMeasurementMode)
00250 {
00251     ADMW_RESULT  res;
00252 
00253     volatile bool bDataReady = false;
00254     volatile bool bError = false;
00255     volatile bool bAlert = false;
00256     res = utils_registerCallbacks(hDevice, &bDataReady, &bError, &bAlert);
00257     if (res != ADMW_SUCCESS )
00258         return res;
00259 
00260     /*
00261      * Retrieve the number of samples per cycle, per DATAREADY pulse, etc. for
00262      * this configuration.
00263      */
00264     ADMW1001_OPERATING_MODE  eOperatingMode;
00265     ADMW1001_DATAREADY_MODE  eDataReadyMode;
00266     uint32_t nSamplesPerDataready;
00267     uint32_t nSamplesPerCycle;
00268     uint8_t nBytesPerSample;
00269     res = admw1001_GetDataReadyModeInfo(hDevice,
00270                                         eMeasurementMode,
00271                                         &eOperatingMode,
00272                                         &eDataReadyMode,
00273                                         &nSamplesPerDataready,
00274                                         &nSamplesPerCycle,
00275                                         &nBytesPerSample);
00276     if (res != ADMW_SUCCESS )
00277         return res;
00278 
00279     /*
00280      * Allocate a buffer to store the samples retrieved on each DATAREADY pulse
00281      */
00282     ADMW_DATA_SAMPLE  *pSampleBuffer;
00283     pSampleBuffer = malloc(sizeof(ADMW_DATA_SAMPLE ) *
00284                            nSamplesPerDataready);
00285     if (pSampleBuffer == NULL) {
00286         ADMW_LOG_ERROR("Failed to allocate sample buffer");
00287         return ADMW_NO_MEM ;
00288     }
00289 
00290     /*
00291      * Kick off the measurement cycle(s) here
00292      */
00293     ADMW_LOG_INFO("Starting measurement");
00294     res = admw_StartMeasurement(hDevice, eMeasurementMode);
00295     if (res != ADMW_SUCCESS ) {
00296         ADMW_LOG_ERROR("Failed to start measurement");
00297         return res;
00298     }
00299 
00300     /*
00301      * Loop continuously unless operating mode is single-cycle
00302      */
00303     uint32_t nSampleCount = 0;
00304     uint32_t nReturned;
00305     while (true) {
00306         ADMW_STATUS  status;
00307 
00308         /*
00309          * Wait until the next batch of 1 or more samples is ready, continuously
00310          * checking DATAREADY until it is asserted
00311          */
00312         while (! (bDataReady || bError))
00313             ;
00314 
00315         if (!bError) {
00316             /*
00317              * Get data samples from the measurement cycle, if no error has occurred
00318              */
00319             bDataReady = false;
00320             res = admw_GetData(hDevice, eMeasurementMode, pSampleBuffer,
00321                                nBytesPerSample, nSamplesPerDataready,
00322                                &nReturned);
00323             if (res != ADMW_SUCCESS ) {
00324                 if (res == ADMW_INCOMPLETE ) {
00325                     /*
00326                      * This is expected in cases where cycleSkipCount may
00327                      * be non-zero for some channels, resulting in
00328                      * variable-length sequences
00329                      */
00330                     ADMW_LOG_DEBUG("Retrieved %u of %u requested data samples",
00331                                    nReturned, nSamplesPerDataready);
00332                 } else {
00333                     ADMW_LOG_WARN("Failed to get data samples from device");
00334                     return res;
00335                 }
00336             }
00337 
00338             /*
00339              * Display the data samples.
00340              *
00341              * NOTE: this requires a sufficient idle time between subsequent
00342              * DATAREADY pulses to allow printing to occur.  Otherwise,
00343              * subsequent samples may be missed if not retrieved promptly when
00344              * the next DATAREADY assertion occurs.
00345              */
00346             utils_printSamples(pSampleBuffer, nReturned, eMeasurementMode);
00347             nSampleCount += nReturned;
00348         }
00349 
00350         /*
00351          * Check and print device status if errors/alerts have been triggered
00352          */
00353         if (bError || bAlert) {
00354             res = admw_GetStatus(hDevice, &status);
00355             if (res != ADMW_SUCCESS ) {
00356                 ADMW_LOG_ERROR("Failed to retrieve device status");
00357                 return res;
00358             }
00359 
00360             if (status.deviceStatus  &
00361                     (ADMW_DEVICE_STATUS_ERROR  | ADMW_DEVICE_STATUS_ALERT )) {
00362                 utils_printStatus(&status);
00363 
00364                 /* Break out of the loop if any errors are raised */
00365                 if (bError)
00366                     break;
00367             }
00368         }
00369 
00370         if (eOperatingMode == ADMW1001_OPERATING_MODE_SINGLECYCLE ) {
00371             /*
00372              * In this mode, break out of the loop when the measurement command
00373              * has completed.
00374              *
00375              * One option is to check for the expected number of samples to be
00376              * returned for the cycle.  However, cycles may have variable-length
00377              * sequences if the cycleSkipCount option is non-zero for any of the
00378              * channels.
00379              *
00380              * So, instead, we check for the command-running status, which
00381              * will de-assert in this mode when the measurement command has
00382              * completed a single cycle.
00383              */
00384             bool bCommandRunning;
00385             res = admw_GetCommandRunningState(hDevice, &bCommandRunning);
00386             if (res != ADMW_SUCCESS ) {
00387                 ADMW_LOG_ERROR("Failed to get command-running status");
00388                 return res;
00389             }
00390 
00391             if (!bCommandRunning && !bDataReady)
00392                 break;
00393         }
00394     }
00395 
00396     ADMW_LOG_INFO("Stopping measurement");
00397     res = admw_StopMeasurement(hDevice);
00398     if (res != ADMW_SUCCESS ) {
00399         ADMW_LOG_ERROR("Failed to send stop measurement");
00400         return res;
00401     }
00402 
00403     free(pSampleBuffer);
00404 
00405     res = utils_deregisterCallbacks(hDevice);
00406     if (res != ADMW_SUCCESS )
00407         return res;
00408 
00409     return ADMW_SUCCESS ;
00410 }
00411