Diaz George / Mbed OS EV-PRO-MW1001_EXTVLTG-Dec18
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_ALERT_DETAIL_CH_ADC_NEAR_OVERRANGE )
00105                     ADMW_LOG_INFO("\t\t\ADC near overrange detected");
00106                 if (pStatus->channelAlerts [i] & ADMW_ALERT_DETAIL_CH_SENSOR_UNDERRANGE )
00107                     ADMW_LOG_INFO("\t\t\tSensor underrange detected");
00108                 if (pStatus->channelAlerts [i] & ADMW_ALERT_DETAIL_CH_SENSOR_OVERRANGE )
00109                     ADMW_LOG_INFO("\t\t\tSensor overrange detected");
00110                 if (pStatus->channelAlerts [i] & ADMW_ALERT_DETAIL_CH_CJ_SOFT_FAULT )
00111                     ADMW_LOG_INFO("\t\t\tCJC soft fault alert detected");
00112                 if (pStatus->channelAlerts [i] & ADMW_ALERT_DETAIL_CH_CJ_HARD_FAULT )
00113                     ADMW_LOG_INFO("\t\t\tCJC hard fault alert detected");
00114                 if (pStatus->channelAlerts [i] & ADMW_ALERT_DETAIL_CH_ADC_INPUT_OVERRANGE )
00115                     ADMW_LOG_INFO("\t\t\tADC input overranage alert detected");
00116                 if (pStatus->channelAlerts [i] & ADMW_ALERT_DETAIL_CH_SENSOR_HARDFAULT )
00117                     ADMW_LOG_INFO("\t\t\tChannel sensor hardfault alert detected");
00118             }
00119         }
00120 
00121         if ((pStatus->deviceStatus  & ADMW_DEVICE_STATUS_ERROR ) ||
00122                 (pStatus->deviceStatus  & ADMW_DEVICE_STATUS_ALERT )) {
00123             ADMW_LOG_INFO("\t\tLast Debug Code: %u-%u",
00124                           (pStatus->debugCode  >> 16) & 0xFFFF,
00125                           (pStatus->debugCode  >> 0) & 0xFFFF);
00126         }
00127     }
00128 }
00129 
00130 void utils_printSamples(
00131     ADMW_DATA_SAMPLE  *pSampleBuffer,
00132     uint32_t nNumSamples,
00133     ADMW_MEASUREMENT_MODE  eMeasurementMode)
00134 {
00135 
00136     for (uint32_t i = 0; i < nNumSamples; i++) {
00137         ADMW_LOG_INFO("Sample # %2d Channel # %2d :: Raw %0X %f :: Processed %f :: flags:%s%s",
00138                       i+1,
00139                       pSampleBuffer[i].channelId,
00140                       pSampleBuffer[i].rawValue, (pSampleBuffer[i].rawValue/1024.0),
00141                       pSampleBuffer[i].processedValue,
00142                       pSampleBuffer[i].status & ADMW_DEVICE_STATUS_ERROR  ? " ERROR" : "",
00143                       pSampleBuffer[i].status & ADMW_DEVICE_STATUS_ALERT  ? " ALERT" : "");
00144     }
00145 }
00146 
00147 static void gpioCallbackFn(ADMW_GPIO_PIN  ePinId, void * pArg)
00148 {
00149     volatile bool *pbFlag = (volatile bool *)pArg;
00150     *pbFlag = true;
00151 }
00152 
00153 ADMW_RESULT  utils_registerCallbacks(
00154     ADMW_DEVICE_HANDLE  hDevice,
00155     volatile bool *pbDataReady,
00156     volatile bool *pbError,
00157     volatile bool *pbAlert)
00158 {
00159     ADMW_RESULT  res;
00160     bool state;
00161 
00162     res = admw_RegisterGpioCallback(hDevice, ADMW_GPIO_PIN_DATAREADY ,
00163                                     gpioCallbackFn, (void *)pbDataReady);
00164     if (res != ADMW_SUCCESS ) {
00165         ADMW_LOG_ERROR("Failed to register DATAREADY callback");
00166         return res;
00167     }
00168 
00169     res = admw_GetGpioState(hDevice, ADMW_GPIO_PIN_ALERT_ERROR , &state);
00170     if (res != ADMW_SUCCESS ) {
00171         ADMW_LOG_ERROR("Failed to get current ERROR state");
00172         return res;
00173     }
00174     if (state) {
00175         ADMW_LOG_ERROR("ERROR signal already asserted");
00176         return ADMW_FAILURE ;
00177     }
00178     res = admw_RegisterGpioCallback(hDevice, ADMW_GPIO_PIN_ALERT_ERROR ,
00179                                     gpioCallbackFn, (void *)pbError);
00180     if (res != ADMW_SUCCESS ) {
00181         ADMW_LOG_ERROR("Failed to register ERROR callback");
00182         return res;
00183     }
00184 
00185     /*res = admw_GetGpioState(hDevice, ADMW_GPIO_PIN_ALERT, &state);
00186     if (res != ADMW_SUCCESS)
00187     {
00188         ADMW_LOG_ERROR("Failed to get current ALERT state");
00189         return res;
00190     }
00191     if (state)
00192     {
00193         ADMW_LOG_ERROR("ALERT signal already asserted");
00194         return ADMW_FAILURE;
00195     }*/
00196     res = admw_RegisterGpioCallback(hDevice, ADMW_GPIO_PIN_ALERT_ERROR ,
00197                                     gpioCallbackFn, (void *)pbAlert);
00198     if (res != ADMW_SUCCESS ) {
00199         ADMW_LOG_ERROR("Failed to register ALERT callback");
00200         return res;
00201     }
00202 
00203     return ADMW_SUCCESS ;
00204 }
00205 
00206 ADMW_RESULT  utils_deregisterCallbacks(
00207     ADMW_DEVICE_HANDLE  hDevice)
00208 {
00209     ADMW_RESULT  res;
00210 
00211     res = admw_RegisterGpioCallback(hDevice, ADMW_GPIO_PIN_DATAREADY ,
00212                                     NULL, NULL);
00213     if (res != ADMW_SUCCESS ) {
00214         ADMW_LOG_ERROR("Failed to deregister DATAREADY callback");
00215         return res;
00216     }
00217 
00218     res = admw_RegisterGpioCallback(hDevice, ADMW_GPIO_PIN_ALERT_ERROR ,
00219                                     NULL, NULL);
00220     if (res != ADMW_SUCCESS ) {
00221         ADMW_LOG_ERROR("Failed to deregister ERROR callback");
00222         return res;
00223     }
00224 
00225     res = admw_RegisterGpioCallback(hDevice, ADMW_GPIO_PIN_ALERT_ERROR ,
00226                                     NULL, NULL);
00227     if (res != ADMW_SUCCESS ) {
00228         ADMW_LOG_INFO("Failed to deregister ALERT callback");
00229         return res;
00230     }
00231 
00232     return ADMW_SUCCESS ;
00233 }
00234 
00235 ADMW_RESULT  utils_runMeasurement(
00236     ADMW_DEVICE_HANDLE  hDevice,
00237     ADMW_MEASUREMENT_MODE  eMeasurementMode)
00238 {
00239     ADMW_RESULT  res;
00240 
00241     volatile bool bDataReady = false;
00242     volatile bool bError = false;
00243     volatile bool bAlert = false;
00244     res = utils_registerCallbacks(hDevice, &bDataReady, &bError, &bAlert);
00245     if (res != ADMW_SUCCESS )
00246         return res;
00247 
00248     /*
00249      * Retrieve the number of samples per cycle, per DATAREADY pulse, etc. for
00250      * this configuration.
00251      */
00252     ADMW1001_OPERATING_MODE  eOperatingMode;
00253     ADMW1001_DATAREADY_MODE  eDataReadyMode;
00254     uint32_t nSamplesPerDataready;
00255     uint32_t nSamplesPerCycle;
00256     uint8_t nBytesPerSample;
00257     res = admw1001_GetDataReadyModeInfo(hDevice,
00258                                         eMeasurementMode,
00259                                         &eOperatingMode,
00260                                         &eDataReadyMode,
00261                                         &nSamplesPerDataready,
00262                                         &nSamplesPerCycle,
00263                                         &nBytesPerSample);
00264     if (res != ADMW_SUCCESS )
00265         return res;
00266 
00267     /*
00268      * Allocate a buffer to store the samples retrieved on each DATAREADY pulse
00269      */
00270     ADMW_DATA_SAMPLE  *pSampleBuffer;
00271     pSampleBuffer = malloc(sizeof(ADMW_DATA_SAMPLE ) *
00272                            nSamplesPerDataready);
00273     if (pSampleBuffer == NULL) {
00274         ADMW_LOG_ERROR("Failed to allocate sample buffer");
00275         return ADMW_NO_MEM ;
00276     }
00277 
00278     /*
00279      * Kick off the measurement cycle(s) here
00280      */
00281     ADMW_LOG_INFO("Starting measurement");
00282     res = admw_StartMeasurement(hDevice, eMeasurementMode);
00283     if (res != ADMW_SUCCESS ) {
00284         ADMW_LOG_ERROR("Failed to start measurement");
00285         return res;
00286     }
00287 
00288     /*
00289      * Loop continuously unless operating mode is single-cycle
00290      */
00291     uint32_t nSampleCount = 0;
00292     uint32_t nReturned;
00293     while (true) {
00294         ADMW_STATUS  status;
00295 
00296         /*
00297          * Wait until the next batch of 1 or more samples is ready, continuously
00298          * checking DATAREADY until it is asserted
00299          */
00300         while (! (bDataReady || bError));
00301 
00302             if (!bError) {
00303                 /*
00304                  * Get data samples from the measurement cycle, if no error has occurred
00305                  */
00306                 bDataReady = false;
00307                 res = admw_GetData(hDevice, eMeasurementMode, pSampleBuffer,
00308                                    nBytesPerSample, nSamplesPerDataready,
00309                                    &nReturned);
00310                 if (res != ADMW_SUCCESS ) {
00311                     if (res == ADMW_INCOMPLETE ) {
00312                         /*
00313                          * This is expected in cases where cycleSkipCount may
00314                          * be non-zero for some channels, resulting in
00315                          * variable-length sequences
00316                          */
00317                         ADMW_LOG_DEBUG("Retrieved %u of %u requested data samples",
00318                                        nReturned, nSamplesPerDataready);
00319                         continue;
00320                     } else {
00321                         ADMW_LOG_WARN("Failed to get data samples from device");
00322                         return res;
00323                     }
00324                 }
00325 
00326                 /*
00327                  * Display the data samples.
00328                  *
00329                  * NOTE: this requires a sufficient idle time between subsequent
00330                  * DATAREADY pulses to allow printing to occur.  Otherwise,
00331                  * subsequent samples may be missed if not retrieved promptly when
00332                  * the next DATAREADY assertion occurs.
00333                  */
00334                 utils_printSamples(pSampleBuffer, nReturned, eMeasurementMode);
00335                 nSampleCount += nReturned;
00336             }
00337 
00338         /*
00339          * Check and print device status if errors/alerts have been triggered
00340          */
00341         if (bError || bAlert) {
00342             res = admw_GetStatus(hDevice, &status);
00343             if (res != ADMW_SUCCESS ) {
00344                 ADMW_LOG_ERROR("Failed to retrieve device status");
00345                 return res;
00346             }
00347 
00348             if (status.deviceStatus  &
00349                     (ADMW_DEVICE_STATUS_ERROR  | ADMW_DEVICE_STATUS_ALERT )) {
00350                 utils_printStatus(&status);
00351 
00352                 /* Break out of the loop if any errors are raised */
00353                 if (bError)
00354                     break;
00355             }
00356         }
00357 
00358         if (eOperatingMode == ADMW1001_OPERATING_MODE_SINGLECYCLE ) {
00359             /*
00360              * In this mode, break out of the loop when the measurement command
00361              * has completed.
00362              *
00363              * One option is to check for the expected number of samples to be
00364              * returned for the cycle.  However, cycles may have variable-length
00365              * sequences if the cycleSkipCount option is non-zero for any of the
00366              * channels.
00367              *
00368              * So, instead, we check for the command-running status, which
00369              * will de-assert in this mode when the measurement command has
00370              * completed a single cycle.
00371              */
00372             bool bCommandRunning;
00373             res = admw_GetCommandRunningState(hDevice, &bCommandRunning);
00374             if (res != ADMW_SUCCESS ) {
00375                 ADMW_LOG_ERROR("Failed to get command-running status");
00376                 return res;
00377             }
00378 
00379             if (!bCommandRunning && !bDataReady)
00380                 break;
00381         }
00382     }
00383 
00384     ADMW_LOG_INFO("Stopping measurement");
00385     res = admw_StopMeasurement(hDevice);
00386     if (res != ADMW_SUCCESS ) {
00387         ADMW_LOG_ERROR("Failed to send stop measurement");
00388         return res;
00389     }
00390 
00391     free(pSampleBuffer);
00392 
00393     res = utils_deregisterCallbacks(hDevice);
00394     if (res != ADMW_SUCCESS )
00395         return res;
00396 
00397     return ADMW_SUCCESS ;
00398 }
00399