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