Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
admw_1001.c
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: 00039 * @brief: API implementation for ADMW1001 00040 *----------------------------------------------------------------------------- 00041 */ 00042 00043 #include <float.h> 00044 #include <math.h> 00045 #include <string.h> 00046 00047 #include "admw_platform.h" 00048 #include "admw_api.h" 00049 #include "admw1001/admw1001_api.h" 00050 00051 #include "admw1001/ADMW1001_REGISTERS_typedefs.h" 00052 #include "admw1001/ADMW1001_REGISTERS.h" 00053 #include "admw1001/admw1001_lut_data.h" 00054 #include "admw1001/admw1001_host_comms.h" 00055 00056 #include "crc16.h" 00057 #define VERSIONID_MAJOR 2 00058 #define VERSIONID_MINOR 0 00059 00060 uint32_t getDataCnt = 0; 00061 #define ADMW_VERSION_REG_VAL_SIZE 4u 00062 #define ADMW_FORMATTED_VERSION_SIZE 11u 00063 00064 #define ADMW_SFL_READ_STATUS_SIZE 42u 00065 /* 00066 * The following macros are used to encapsulate the register access code 00067 * to improve readability in the functions further below in this file 00068 */ 00069 #define STRINGIFY(name) #name 00070 00071 /* Expand the full name of the reset value macro for the specified register */ 00072 #define REG_RESET_VAL(_name) REG_##_name##_RESET 00073 00074 /* Checks if a value is outside the bounds of the specified register field */ 00075 #define CHECK_REG_FIELD_VAL(_field, _val) \ 00076 do { \ 00077 uint32_t _mask = BITM_##_field; \ 00078 uint32_t _shift = BITP_##_field; \ 00079 if ((((_val) << _shift) & ~(_mask)) != 0) { \ 00080 ADMW_LOG_ERROR("Value 0x%08X invalid for register field %s",\ 00081 (uint32_t)(_val), \ 00082 STRINGIFY(ADMW_##_field)); \ 00083 return ADMW_INVALID_PARAM; \ 00084 } \ 00085 } while(false) 00086 00087 /* 00088 * Encapsulates the write to a specified register 00089 * NOTE - this will cause the calling function to return on error 00090 */ 00091 #define WRITE_REG(_hdev, _val, _name, _type) \ 00092 do { \ 00093 ADMW_RESULT _res; \ 00094 _type _regval = _val; \ 00095 _res = admw1001_WriteRegister((_hdev), \ 00096 REG_##_name, \ 00097 &_regval, sizeof(_regval)); \ 00098 if (_res != ADMW_SUCCESS) \ 00099 return _res; \ 00100 } while(false) 00101 00102 /* Wrapper macro to write a value to a uint32_t register */ 00103 #define WRITE_REG_U32(_hdev, _val, _name) \ 00104 WRITE_REG(_hdev, _val, _name, uint32_t) 00105 /* Wrapper macro to write a value to a uint16_t register */ 00106 #define WRITE_REG_U16(_hdev, _val, _name) \ 00107 WRITE_REG(_hdev, _val, _name, uint16_t) 00108 /* Wrapper macro to write a value to a uint8_t register */ 00109 #define WRITE_REG_U8(_hdev, _val, _name) \ 00110 WRITE_REG(_hdev, _val, _name, uint8_t) 00111 /* Wrapper macro to write a value to a float32_t register */ 00112 #define WRITE_REG_FLOAT(_hdev, _val, _name) \ 00113 WRITE_REG(_hdev, _val, _name, float32_t) 00114 00115 /* 00116 * Encapsulates the read from a specified register 00117 * NOTE - this will cause the calling function to return on error 00118 */ 00119 #define READ_REG(_hdev, _val, _name, _type) \ 00120 do { \ 00121 ADMW_RESULT _res; \ 00122 _type _regval; \ 00123 _res = admw1001_ReadRegister((_hdev), \ 00124 REG_##_name, \ 00125 &_regval, sizeof(_regval)); \ 00126 if (_res != ADMW_SUCCESS) \ 00127 return _res; \ 00128 _val = _regval; \ 00129 } while(false) 00130 00131 /* Wrapper macro to read a value from a uint32_t register */ 00132 #define READ_REG_U32(_hdev, _val, _name) \ 00133 READ_REG(_hdev, _val, _name, uint32_t) 00134 /* Wrapper macro to read a value from a uint16_t register */ 00135 #define READ_REG_U16(_hdev, _val, _name) \ 00136 READ_REG(_hdev, _val, _name, uint16_t) 00137 /* Wrapper macro to read a value from a uint8_t register */ 00138 #define READ_REG_U8(_hdev, _val, _name) \ 00139 READ_REG(_hdev, _val, _name, uint8_t) 00140 /* Wrapper macro to read a value from a float32_t register */ 00141 #define READ_REG_FLOAT(_hdev, _val, _name) \ 00142 READ_REG(_hdev, _val, _name, float32_t) 00143 00144 /* 00145 * Wrapper macro to write an array of values to a uint8_t register 00146 * NOTE - this is intended only for writing to a keyhole data register 00147 */ 00148 #define WRITE_REG_U8_ARRAY(_hdev, _arr, _len, _name) \ 00149 do { \ 00150 ADMW_RESULT _res; \ 00151 _res = admw1001_WriteRegister(_hdev, \ 00152 REG_##_name, \ 00153 _arr, _len); \ 00154 if (_res != ADMW_SUCCESS) \ 00155 return _res; \ 00156 } while(false) 00157 00158 /* 00159 * Wrapper macro to read an array of values from a uint8_t register 00160 * NOTE - this is intended only for reading from a keyhole data register 00161 */ 00162 #define READ_REG_U8_ARRAY(_hdev, _arr, _len, _name) \ 00163 do { \ 00164 ADMW_RESULT _res; \ 00165 _res = admw1001_ReadRegister((_hdev), \ 00166 REG##_name, \ 00167 _arr, _len); \ 00168 if (_res != ADMW_SUCCESS) \ 00169 return _res; \ 00170 } while(false) 00171 00172 #define ADMW1001_CHANNEL_IS_ADC(c) \ 00173 ((c) >= ADMW1001_CH_ID_ANLG_1_UNIVERSAL && (c) <= ADMW1001_CH_ID_ANLG_2_DIFFERENTIAL) 00174 00175 #define ADMW1001_CHANNEL_IS_ADC_CJC(c) \ 00176 ((c) >= ADMW1001_CH_ID_ANLG_1_UNIVERSAL && (c) <= ADMW1001_CH_ID_ANLG_2_UNIVERSAL) 00177 00178 #define ADMW1001_CHANNEL_IS_ADC_SENSOR(c) \ 00179 ((c) >= ADMW1001_CH_ID_ANLG_1_UNIVERSAL && (c) <= ADMW1001_CH_ID_ANLG_2_UNIVERSAL) 00180 00181 #define ADMW1001_CHANNEL_IS_ADC_VOLTAGE(c) \ 00182 ((c) == ADMW1001_CH_ID_ANLG_1_DIFFERENTIAL || ADMW1001_CH_ID_ANLG_2_DIFFERENTIAL) 00183 00184 #define ADMW1001_CHANNEL_IS_ADC_CURRENT(c) \ 00185 ((c) == ADMW1001_CH_ID_ANLG_1_UNIVERSAL || (c) == ADMW1001_CH_ID_ANLG_2_UNIVERSAL) 00186 00187 #define ADMW1001_CHANNEL_IS_VIRTUAL(c) \ 00188 ((c) == ADMW1001_CH_ID_DIG_SPI_1 || (c) == ADMW1001_CH_ID_DIG_SPI_2) 00189 00190 //typedef struct { 00191 // unsigned nDeviceIndex; 00192 // ADMW_SPI_HANDLE hSpi; 00193 // ADMW_GPIO_HANDLE hGpio; 00194 // 00195 //} ADMW_DEVICE_CONTEXT; 00196 00197 static ADMW_DEVICE_CONTEXT gDeviceCtx[ADMW_PLATFORM_MAX_DEVICES]; 00198 00199 /* 00200 * Open an ADMW device instance. 00201 */ 00202 ADMW_RESULT admw_Open( 00203 unsigned const nDeviceIndex, 00204 ADMW_CONNECTION * const pConnectionInfo, 00205 ADMW_DEVICE_HANDLE * const phDevice) 00206 { 00207 ADMW_DEVICE_CONTEXT *pCtx; 00208 ADMW_RESULT eRet; 00209 00210 if (nDeviceIndex >= ADMW_PLATFORM_MAX_DEVICES) 00211 return ADMW_INVALID_DEVICE_NUM ; 00212 00213 pCtx = &gDeviceCtx[nDeviceIndex]; 00214 pCtx->nDeviceIndex = nDeviceIndex; 00215 00216 eRet = admw_LogOpen(&pConnectionInfo->log ); 00217 if (eRet != ADMW_SUCCESS ) 00218 return eRet; 00219 00220 eRet = admw_GpioOpen(&pConnectionInfo->gpio , &pCtx->hGpio); 00221 if (eRet != ADMW_SUCCESS ) 00222 return eRet; 00223 00224 eRet = admw_SpiOpen(&pConnectionInfo->spi , &pCtx->hSpi); 00225 if (eRet != ADMW_SUCCESS ) 00226 return eRet; 00227 00228 *phDevice = pCtx; 00229 return ADMW_SUCCESS ; 00230 } 00231 00232 /* 00233 * Get the current state of the specified GPIO input signal. 00234 */ 00235 ADMW_RESULT admw_GetGpioState( 00236 ADMW_DEVICE_HANDLE const hDevice, 00237 ADMW_GPIO_PIN const ePinId, 00238 bool * const pbAsserted) 00239 { 00240 ADMW_DEVICE_CONTEXT *pCtx = hDevice; 00241 00242 return admw_GpioGet(pCtx->hGpio, ePinId, pbAsserted); 00243 } 00244 00245 /* 00246 * Register an application-defined callback function for GPIO interrupts. 00247 */ 00248 ADMW_RESULT admw_RegisterGpioCallback( 00249 ADMW_DEVICE_HANDLE const hDevice, 00250 ADMW_GPIO_PIN const ePinId, 00251 ADMW_GPIO_CALLBACK const callbackFunction, 00252 void * const pCallbackParam) 00253 { 00254 ADMW_DEVICE_CONTEXT *pCtx = hDevice; 00255 00256 if (callbackFunction) { 00257 return admw_GpioIrqEnable(pCtx->hGpio, ePinId, callbackFunction, 00258 pCallbackParam); 00259 } else { 00260 return admw_GpioIrqDisable(pCtx->hGpio, ePinId); 00261 } 00262 } 00263 00264 /*! 00265 * @brief Reset the specified ADMW device. 00266 * 00267 * @param[in] hDevice - handle of ADMW device to reset. 00268 * 00269 * @return Status 00270 * - #ADMW_SUCCESS Call completed successfully. 00271 * - #ADMW_FAILURE If reseet faisl 00272 * 00273 * @details Toggle reset pin of the ADMW device low for a 00274 * minimum of 4 usec. 00275 * 00276 */ 00277 ADMW_RESULT admw_Reset(ADMW_DEVICE_HANDLE const hDevice) 00278 { 00279 ADMW_DEVICE_CONTEXT *pCtx = hDevice; 00280 ADMW_RESULT eRet; 00281 00282 /* Pulse the Reset GPIO pin low for a minimum of 4 microseconds */ 00283 eRet = admw_GpioSet(pCtx->hGpio, ADMW_GPIO_PIN_RESET , false); 00284 if (eRet != ADMW_SUCCESS ) 00285 return eRet; 00286 00287 admw_TimeDelayUsec(4); 00288 00289 eRet = admw_GpioSet(pCtx->hGpio, ADMW_GPIO_PIN_RESET , true); 00290 if (eRet != ADMW_SUCCESS ) 00291 return eRet; 00292 00293 return ADMW_SUCCESS ; 00294 } 00295 00296 /*! 00297 * @brief Get general status of ADMW module. 00298 * 00299 * @param[in] 00300 * @param[out] pStatus : Pointer to CORE Status struct. 00301 * 00302 * @return Status 00303 * - #ADMW_SUCCESS Call completed successfully. 00304 * - #ADMW_FAILURE If status register read fails. 00305 * 00306 * @details Read the general status register for the ADMW 00307 * module. Indicates Error, Alert conditions, data ready 00308 * and command running. 00309 * 00310 */ 00311 ADMW_RESULT admw_GetStatus( 00312 ADMW_DEVICE_HANDLE const hDevice, 00313 ADMW_STATUS * const pStatus) 00314 { 00315 ADMW_CORE_Status_t statusReg; 00316 READ_REG_U8(hDevice, statusReg.VALUE8, CORE_STATUS); 00317 00318 memset(pStatus, 0, sizeof(*pStatus)); 00319 00320 if (!statusReg.Cmd_Running) /* Active-low, so invert it */ 00321 pStatus->deviceStatus |= ADMW_DEVICE_STATUS_BUSY ; 00322 if (statusReg.Drdy) 00323 pStatus->deviceStatus |= ADMW_DEVICE_STATUS_DATAREADY ; 00324 if (statusReg.FIFO_Error) 00325 pStatus->deviceStatus |= ADMW_DEVICE_STATUS_FIFO_ERROR ; 00326 if (statusReg.Alert_Active) { 00327 pStatus->deviceStatus |= ADMW_DEVICE_STATUS_ALERT ; 00328 00329 ADMW_CORE_Channel_Alert_Status_t channelAlertStatusReg; 00330 READ_REG_U16(hDevice, channelAlertStatusReg.VALUE16, 00331 CORE_CHANNEL_ALERT_STATUS); 00332 00333 for (unsigned i = 0; i < ADMW1001_MAX_CHANNELS ; i++) { 00334 if (channelAlertStatusReg.VALUE16 & (1 << i)) { 00335 ADMW_CORE_Alert_Detail_Ch_t alertDetailReg; 00336 READ_REG_U16(hDevice, alertDetailReg.VALUE16, 00337 CORE_ALERT_DETAIL_CHn(i)); 00338 00339 if (alertDetailReg.ADC_Near_Overrange) 00340 pStatus->channelAlerts [i] |= ADMW_ALERT_DETAIL_CH_ADC_NEAR_OVERRANGE ; 00341 if (alertDetailReg.Sensor_UnderRange) 00342 pStatus->channelAlerts [i] |= ADMW_ALERT_DETAIL_CH_SENSOR_UNDERRANGE ; 00343 if (alertDetailReg.Sensor_OverRange) 00344 pStatus->channelAlerts [i] |= ADMW_ALERT_DETAIL_CH_SENSOR_OVERRANGE ; 00345 if (alertDetailReg.CJ_Soft_Fault) 00346 pStatus->channelAlerts [i] |= ADMW_ALERT_DETAIL_CH_CJ_SOFT_FAULT ; 00347 if (alertDetailReg.CJ_Hard_Fault) 00348 pStatus->channelAlerts [i] |= ADMW_ALERT_DETAIL_CH_CJ_HARD_FAULT ; 00349 if (alertDetailReg.ADC_Input_OverRange) 00350 pStatus->channelAlerts [i] |= ADMW_ALERT_DETAIL_CH_ADC_INPUT_OVERRANGE ; 00351 if (alertDetailReg.Sensor_HardFault) 00352 pStatus->channelAlerts [i] |= ADMW_ALERT_DETAIL_CH_SENSOR_HARDFAULT ; 00353 00354 } 00355 } 00356 00357 if (statusReg.Configuration_Error) 00358 pStatus->deviceStatus |= ADMW_DEVICE_STATUS_CONFIG_ERROR ; 00359 if (statusReg.LUT_Error) 00360 pStatus->deviceStatus |= ADMW_DEVICE_STATUS_LUT_ERROR ; 00361 } 00362 00363 if (statusReg.Error) { 00364 pStatus->deviceStatus |= ADMW_DEVICE_STATUS_ERROR ; 00365 00366 ADMW_CORE_Error_Code_t errorCodeReg; 00367 READ_REG_U16(hDevice, errorCodeReg.VALUE16, CORE_ERROR_CODE); 00368 pStatus->errorCode = errorCodeReg.Error_Code; 00369 00370 } 00371 return ADMW_SUCCESS ; 00372 } 00373 00374 ADMW_RESULT admw_GetCommandRunningState( 00375 ADMW_DEVICE_HANDLE hDevice, 00376 bool *pbCommandRunning) 00377 { 00378 ADMW_CORE_Status_t statusReg; 00379 00380 READ_REG_U8(hDevice, statusReg.VALUE8, CORE_STATUS); 00381 00382 /* We should never normally see 0xFF here if the module is operational */ 00383 if (statusReg.VALUE8 == 0xFF) 00384 return ADMW_ERR_NOT_INITIALIZED ; 00385 00386 *pbCommandRunning = !statusReg.Cmd_Running; /* Active-low, so invert it */ 00387 00388 return ADMW_SUCCESS ; 00389 } 00390 00391 ADMW_RESULT deviceInformation(ADMW_DEVICE_HANDLE hDevice) 00392 { 00393 uint16_t nAddress = REG_CORE_REVISION; 00394 char nData[ADMW_VERSION_REG_VAL_SIZE]; //4 Bytes of version register data 00395 ADMW_RESULT res; 00396 res=admw1001_ReadRegister(hDevice,nAddress,nData,sizeof(nData)); 00397 if(res != ADMW_SUCCESS ) { 00398 //if reading version register failed, sending 00.00.0000 as ADMW1001 firmware version 00399 //strcat(nData, ADMW1001_FIRMWARE_VERSION_DEFAULT); 00400 ADMW_LOG_INFO("Firmware Version Id is %X.%X",nData[2],nData[0]); 00401 } else { 00402 char buffer[ADMW_FORMATTED_VERSION_SIZE]; //00.00.0000 8 digits + 2 Bytes "." + one null character at the end 00403 strcat(nData, buffer); 00404 ADMW_LOG_INFO("Firmware Version Id is %X.%X",nData[2],nData[0]); 00405 } 00406 return ADMW_SUCCESS ; 00407 } 00408 static ADMW_RESULT executeCommand( 00409 ADMW_DEVICE_HANDLE const hDevice, 00410 ADMW_CORE_Command_Special_Command const command, 00411 bool const bWaitForCompletion) 00412 { 00413 ADMW_CORE_Command_t commandReg; 00414 bool bCommandRunning; 00415 ADMW_RESULT eRet; 00416 00417 /* 00418 * Don't allow another command to be issued if one is already running, but 00419 * make an exception for ENUM_CORE_COMMAND_NOP which can be used to 00420 * request a running command to be stopped (e.g. continuous measurement) 00421 */ 00422 if (command != ENUM_CORE_COMMAND_NOP) { 00423 eRet = admw_GetCommandRunningState(hDevice, &bCommandRunning); 00424 if (eRet) 00425 return eRet; 00426 00427 if (bCommandRunning) 00428 return ADMW_IN_USE ; 00429 } 00430 00431 commandReg.Special_Command = command; 00432 WRITE_REG_U8(hDevice, commandReg.VALUE8, CORE_COMMAND); 00433 00434 if (bWaitForCompletion) { 00435 do { 00436 /* Allow a minimum 50usec delay for status update before checking */ 00437 admw_TimeDelayUsec(50); 00438 00439 eRet = admw_GetCommandRunningState(hDevice, &bCommandRunning); 00440 if (eRet) 00441 return eRet; 00442 } while (bCommandRunning); 00443 } 00444 00445 return ADMW_SUCCESS ; 00446 } 00447 00448 ADMW_RESULT admw_ApplyConfigUpdates( 00449 ADMW_DEVICE_HANDLE const hDevice) 00450 { 00451 return executeCommand(hDevice, CORE_COMMAND_LATCH_CONFIG, true); 00452 } 00453 00454 /*! 00455 * @brief Start a measurement cycle. 00456 * 00457 * @param[out] 00458 * 00459 * @return Status 00460 * - #ADMW_SUCCESS Call completed successfully. 00461 * - #ADMW_FAILURE 00462 * 00463 * @details Sends the latch config command. Configuration for channels in 00464 * conversion cycle should be completed before this function. 00465 * Channel enabled bit should be set before this function. 00466 * Starts a conversion and configures the format of the sample. 00467 * 00468 */ 00469 ADMW_RESULT admw_StartMeasurement( 00470 ADMW_DEVICE_HANDLE const hDevice, 00471 ADMW_MEASUREMENT_MODE const eMeasurementMode) 00472 { 00473 switch (eMeasurementMode) { 00474 case ADMW_MEASUREMENT_MODE_NORMAL : 00475 return executeCommand(hDevice, CORE_COMMAND_CONVERT_WITH_RAW, false); 00476 case ADMW_MEASUREMENT_MODE_OMIT_RAW : 00477 return executeCommand(hDevice, CORE_COMMAND_CONVERT, false); 00478 default: 00479 ADMW_LOG_ERROR("Invalid measurement mode %d specified", 00480 eMeasurementMode); 00481 return ADMW_INVALID_PARAM ; 00482 } 00483 } 00484 00485 /* 00486 * Store the configuration settings to persistent memory on the device. 00487 * The settings can be saved to 4 different flash memory areas (slots). 00488 * No other command must be running when this is called. 00489 * Do not power down the device while this command is running. 00490 */ 00491 ADMW_RESULT admw_SaveConfig( 00492 ADMW_DEVICE_HANDLE const hDevice, 00493 ADMW_USER_CONFIG_SLOT const eSlotId) 00494 { 00495 switch (eSlotId) { 00496 case ADMW_FLASH_CONFIG_1: 00497 return executeCommand(hDevice, CORE_COMMAND_SAVE_CONFIG_1, true); 00498 default: 00499 ADMW_LOG_ERROR("Invalid user config target slot %d specified", 00500 eSlotId); 00501 return ADMW_INVALID_PARAM ; 00502 } 00503 } 00504 00505 /* 00506 * Restore the configuration settings from persistent memory on the device. 00507 * No other command must be running when this is called. 00508 */ 00509 ADMW_RESULT admw_RestoreConfig( 00510 ADMW_DEVICE_HANDLE const hDevice, 00511 ADMW_USER_CONFIG_SLOT const eSlotId) 00512 { 00513 switch (eSlotId) { 00514 case ADMW_FLASH_CONFIG_1: 00515 return executeCommand(hDevice, CORE_COMMAND_LOAD_CONFIG_1, true); 00516 default: 00517 ADMW_LOG_ERROR("Invalid user config source slot %d specified", 00518 eSlotId); 00519 return ADMW_INVALID_PARAM ; 00520 } 00521 } 00522 00523 /* 00524 * Store the LUT data to persistent memory on the device. 00525 * No other command must be running when this is called. 00526 * Do not power down the device while this command is running. 00527 */ 00528 ADMW_RESULT admw_SaveLutData( 00529 ADMW_DEVICE_HANDLE const hDevice) 00530 { 00531 return executeCommand(hDevice, CORE_COMMAND_SAVE_LUT, true); 00532 } 00533 00534 /* 00535 * Restore the LUT data from persistent memory on the device. 00536 * No other command must be running when this is called. 00537 */ 00538 ADMW_RESULT admw_RestoreLutData( 00539 ADMW_DEVICE_HANDLE const hDevice) 00540 { 00541 return executeCommand(hDevice, CORE_COMMAND_LOAD_LUT, true); 00542 } 00543 00544 /* 00545 * Stop the measurement cycles on the device. 00546 * To be used only if a measurement command is currently running. 00547 */ 00548 ADMW_RESULT admw_StopMeasurement( 00549 ADMW_DEVICE_HANDLE const hDevice) 00550 { 00551 return executeCommand(hDevice, CORE_COMMAND_NOP, true); 00552 } 00553 00554 /* 00555 * 00556 */ 00557 ADMW_RESULT admw1001_sendRun( ADMW_DEVICE_HANDLE const hDevice) 00558 { 00559 bool bitCommand; 00560 ADMW_RESULT eRet; 00561 uint8_t pinreg = 0x1; 00562 00563 ADMW_DEVICE_CONTEXT *pCtx = hDevice; 00564 static uint8_t DataBuffer[SPI_BUFFER_SIZE] = {0}; 00565 uint16_t nSize; 00566 00567 //Construct Read Status command 00568 DataBuffer[0] = 0x07; 00569 DataBuffer[1] = 0x0E; //Packet ID 00570 00571 DataBuffer[2] = 0x00; 00572 DataBuffer[3] = 0x00; //Data words 00573 00574 DataBuffer[4] = 0x45; 00575 DataBuffer[5] = 0x00; //Command ID 00576 00577 DataBuffer[6] = 0x00; 00578 DataBuffer[7] = 0x50; 00579 DataBuffer[8] = 0x00; 00580 DataBuffer[9] = 0x00; //Address 00581 00582 DataBuffer[10] = 0x95; 00583 DataBuffer[11] = 0x00; 00584 DataBuffer[12] = 0x00; 00585 DataBuffer[13] = 0x00; //Checksum 00586 00587 nSize = SFL_READ_STATUS_HDR_SIZE; 00588 00589 do { 00590 // Get the SFL command irq pin to check if SFL is ready to receive commands 00591 // Status pin is not checked since SFL is just booted, there should not be any issue with SFL 00592 eRet = admw_GetGpioState( hDevice, ADMW_GPIO_PIN_DATAREADY , &bitCommand ); 00593 if( eRet != ADMW_SUCCESS ) { 00594 return eRet; 00595 } 00596 00597 // Command IRQ pin should be low and Status IRQ pin should be high for SFL to be in good state and ready to recieve commands 00598 // pinreg == '0x00' - Error occured in SFL 00599 // pinreg == '0x01' - SFL is ready to recieve commands 00600 // pinreg == '0x02' - Error occured in handling any commands in SFL 00601 // pinreg == '0x03' - SFL not booted 00602 00603 pinreg = (bitCommand); 00604 00605 } while(pinreg != 0x0u); 00606 00607 eRet = admw_SpiTransfer(pCtx->hSpi, DataBuffer, NULL, 00608 nSize, false); 00609 00610 return eRet; 00611 } 00612 00613 /* 00614 * Read a set of data samples from the device. 00615 * This may be called at any time. 00616 */ 00617 00618 ADMW_RESULT admw_GetData( 00619 ADMW_DEVICE_HANDLE const hDevice, 00620 ADMW_MEASUREMENT_MODE const eMeasurementMode, 00621 ADMW_DATA_SAMPLE * const pSamples, 00622 uint8_t const nBytesPerSample, 00623 uint32_t const nRequested, 00624 uint32_t * const pnReturned) 00625 { 00626 ADMW1001_Sensor_Result_t sensorResult; 00627 ADMW_DEVICE_CONTEXT *pCtx = hDevice; 00628 uint16_t command = ADMW1001_HOST_COMMS_READ_CMD | 00629 (REG_CORE_DATA_FIFO & ADMW1001_HOST_COMMS_ADR_MASK); 00630 uint8_t commandData[2] = { 00631 command >> 8, 00632 command & 0xFF 00633 }; 00634 uint8_t commandResponse[2]; 00635 unsigned nValidSamples = 0; 00636 ADMW_RESULT eRet = ADMW_SUCCESS ; 00637 00638 do { 00639 eRet = admw_SpiTransfer(pCtx->hSpi, commandData, commandResponse, 00640 sizeof(command), false); 00641 if (eRet) { 00642 ADMW_LOG_ERROR("Failed to send read command for FIFO register"); 00643 return eRet; 00644 } 00645 admw_TimeDelayUsec(ADMW1001_HOST_COMMS_XFER_DELAY); 00646 } while ((commandResponse[0] != ADMW1001_HOST_COMMS_CMD_RESP_0) || 00647 (commandResponse[1] != ADMW1001_HOST_COMMS_CMD_RESP_1)); 00648 00649 for (unsigned i = 0; i < nRequested; i++) { 00650 bool bHoldCs = true; 00651 00652 /* Keep the CS signal asserted for all but the last sample */ 00653 if ((i + 1) == nRequested) 00654 bHoldCs = false; 00655 00656 getDataCnt++; 00657 00658 eRet = admw_SpiTransfer(pCtx->hSpi, NULL, &sensorResult, 00659 nBytesPerSample, bHoldCs); 00660 if (eRet) { 00661 ADMW_LOG_ERROR("Failed to read data from FIFO register"); 00662 return eRet; 00663 } 00664 00665 if (! sensorResult.Ch_Valid) { 00666 /* 00667 * Reading an invalid sample indicates that there are no 00668 * more samples available or we've lost sync with the device. 00669 * In the latter case, it might be recoverable, but return here 00670 * to let the application check the device status and decide itself. 00671 */ 00672 eRet = ADMW_INCOMPLETE ; 00673 break; 00674 } 00675 00676 ADMW_DATA_SAMPLE *pSample = &pSamples[nValidSamples]; 00677 00678 pSample->status = (ADMW_DEVICE_STATUS_FLAGS )0; 00679 if (sensorResult.Ch_Error) 00680 pSample->status |= ADMW_DEVICE_STATUS_ERROR ; 00681 if (sensorResult.Ch_Alert) 00682 pSample->status |= ADMW_DEVICE_STATUS_ALERT ; 00683 00684 if (sensorResult.Ch_Raw) 00685 pSample->rawValue = sensorResult.Raw_Sample; 00686 else 00687 pSample->rawValue = 0; 00688 00689 pSample->channelId = sensorResult.Channel_ID; 00690 pSample->processedValue = sensorResult.Sensor_Result; 00691 00692 nValidSamples++; 00693 00694 admw_TimeDelayUsec(ADMW1001_HOST_COMMS_XFER_DELAY); 00695 } 00696 *pnReturned = nValidSamples; 00697 00698 return eRet; 00699 } 00700 00701 /* 00702 * Close the given ADMW device. 00703 */ 00704 ADMW_RESULT admw_Close( 00705 ADMW_DEVICE_HANDLE const hDevice) 00706 { 00707 ADMW_DEVICE_CONTEXT *pCtx = hDevice; 00708 00709 admw_GpioClose(pCtx->hGpio); 00710 admw_SpiClose(pCtx->hSpi); 00711 admw_LogClose(); 00712 00713 return ADMW_SUCCESS ; 00714 } 00715 00716 ADMW_RESULT admw1001_WriteRegister( 00717 ADMW_DEVICE_HANDLE hDevice, 00718 uint16_t nAddress, 00719 void *pData, 00720 unsigned nLength) 00721 { 00722 ADMW_RESULT eRet; 00723 ADMW_DEVICE_CONTEXT *pCtx = hDevice; 00724 uint16_t command = ADMW1001_HOST_COMMS_WRITE_CMD | 00725 (nAddress & ADMW1001_HOST_COMMS_ADR_MASK); 00726 uint8_t commandData[2] = { 00727 command >> 8, 00728 command & 0xFF 00729 }; 00730 uint8_t commandResponse[2]; 00731 00732 do { 00733 eRet = admw_SpiTransfer(pCtx->hSpi, commandData, commandResponse, 00734 sizeof(command), false); 00735 if (eRet) { 00736 ADMW_LOG_ERROR("Failed to send write command for register %u", 00737 nAddress); 00738 return eRet; 00739 } 00740 00741 admw_TimeDelayUsec(ADMW1001_HOST_COMMS_XFER_DELAY); 00742 } while ((commandResponse[0] != ADMW1001_HOST_COMMS_CMD_RESP_0) || 00743 (commandResponse[1] != ADMW1001_HOST_COMMS_CMD_RESP_1)); 00744 00745 eRet = admw_SpiTransfer(pCtx->hSpi, pData, NULL, nLength, false); 00746 if (eRet) { 00747 ADMW_LOG_ERROR("Failed to write data (%dB) to register %u", 00748 nLength, nAddress); 00749 return eRet; 00750 } 00751 00752 admw_TimeDelayUsec(ADMW1001_HOST_COMMS_XFER_DELAY); 00753 00754 return ADMW_SUCCESS ; 00755 } 00756 00757 ADMW_RESULT admw1001_Write_Debug_Register( 00758 ADMW_DEVICE_HANDLE hDevice, 00759 uint16_t nAddress, 00760 void *pData, 00761 unsigned nLength) 00762 { 00763 ADMW_RESULT eRet; 00764 ADMW_DEVICE_CONTEXT *pCtx = hDevice; 00765 uint16_t command = ADMW1001_HOST_COMMS_DEBUG_WRITE_CMD | 00766 (nAddress & ADMW1001_HOST_COMMS_ADR_MASK); 00767 uint8_t commandData[2] = { 00768 command >> 8, 00769 command & 0xFF 00770 }; 00771 uint8_t commandResponse[2]; 00772 00773 do { 00774 eRet = admw_SpiTransfer(pCtx->hSpi, commandData, commandResponse, 00775 sizeof(command), false); 00776 if (eRet) { 00777 ADMW_LOG_ERROR("Failed to send write command for register %u", 00778 nAddress); 00779 return eRet; 00780 } 00781 00782 admw_TimeDelayUsec(ADMW1001_HOST_COMMS_XFER_DELAY); 00783 } while ((commandResponse[0] != ADMW1001_HOST_COMMS_CMD_RESP_0) || 00784 (commandResponse[1] != ADMW1001_HOST_COMMS_CMD_RESP_1)); 00785 00786 eRet = admw_SpiTransfer(pCtx->hSpi, pData, NULL, nLength, false); 00787 if (eRet) { 00788 ADMW_LOG_ERROR("Failed to write data (%dB) to register %u", 00789 nLength, nAddress); 00790 return eRet; 00791 } 00792 00793 admw_TimeDelayUsec(ADMW1001_HOST_COMMS_XFER_DELAY); 00794 00795 return ADMW_SUCCESS ; 00796 } 00797 ADMW_RESULT admw1001_ReadRegister( 00798 ADMW_DEVICE_HANDLE hDevice, 00799 uint16_t nAddress, 00800 void *pData, 00801 unsigned nLength) 00802 { 00803 ADMW_RESULT eRet; 00804 ADMW_DEVICE_CONTEXT *pCtx = hDevice; 00805 uint16_t command = ADMW1001_HOST_COMMS_READ_CMD | 00806 (nAddress & ADMW1001_HOST_COMMS_ADR_MASK); 00807 uint8_t commandData[2] = { 00808 command >> 8, 00809 command & 0xFF 00810 }; 00811 uint8_t commandResponse[2]; 00812 00813 do { 00814 eRet = admw_SpiTransfer(pCtx->hSpi, commandData, commandResponse, 00815 sizeof(command), false); 00816 if (eRet) { 00817 ADMW_LOG_ERROR("Failed to send read command for register %u", 00818 nAddress); 00819 return eRet; 00820 } 00821 00822 admw_TimeDelayUsec(ADMW1001_HOST_COMMS_XFER_DELAY); 00823 } while ((commandResponse[0] != ADMW1001_HOST_COMMS_CMD_RESP_0) || 00824 (commandResponse[1] != ADMW1001_HOST_COMMS_CMD_RESP_1)); 00825 00826 eRet = admw_SpiTransfer(pCtx->hSpi, NULL, pData, nLength, false); 00827 if (eRet) { 00828 ADMW_LOG_ERROR("Failed to read data (%uB) from register %u", 00829 nLength, nAddress); 00830 return eRet; 00831 } 00832 00833 admw_TimeDelayUsec(ADMW1001_HOST_COMMS_XFER_DELAY); 00834 00835 return ADMW_SUCCESS ; 00836 } 00837 00838 ADMW_RESULT admw1001_Read_Debug_Register( 00839 ADMW_DEVICE_HANDLE hDevice, 00840 uint16_t nAddress, 00841 void *pData, 00842 unsigned nLength) 00843 { 00844 ADMW_RESULT eRet; 00845 ADMW_DEVICE_CONTEXT *pCtx = hDevice; 00846 uint16_t command = ADMW1001_HOST_COMMS_DEBUG_READ_CMD | 00847 (nAddress & ADMW1001_HOST_COMMS_ADR_MASK); 00848 uint8_t commandData[2] = { 00849 command >> 8, 00850 command & 0xFF 00851 }; 00852 uint8_t commandResponse[2]; 00853 00854 do { 00855 eRet = admw_SpiTransfer(pCtx->hSpi, commandData, commandResponse, 00856 sizeof(command), false); 00857 if (eRet) { 00858 ADMW_LOG_ERROR("Failed to send read command for register %u", 00859 nAddress); 00860 return eRet; 00861 } 00862 00863 admw_TimeDelayUsec(ADMW1001_HOST_COMMS_XFER_DELAY); 00864 } while ((commandResponse[0] != ADMW1001_HOST_COMMS_CMD_RESP_0) || 00865 (commandResponse[1] != ADMW1001_HOST_COMMS_CMD_RESP_1)); 00866 00867 eRet = admw_SpiTransfer(pCtx->hSpi, NULL, pData, nLength, false); 00868 if (eRet) { 00869 ADMW_LOG_ERROR("Failed to read data (%uB) from register %u", 00870 nLength, nAddress); 00871 return eRet; 00872 } 00873 00874 admw_TimeDelayUsec(ADMW1001_HOST_COMMS_XFER_DELAY); 00875 00876 return ADMW_SUCCESS ; 00877 } 00878 ADMW_RESULT admw_GetDeviceReadyState( 00879 ADMW_DEVICE_HANDLE const hDevice, 00880 bool * const bReady) 00881 { 00882 ADMW_SPI_Chip_Type_t chipTypeReg; 00883 00884 READ_REG_U8(hDevice, chipTypeReg.VALUE8, SPI_CHIP_TYPE); 00885 /* If we read this register successfully, assume the device is ready */ 00886 *bReady = (chipTypeReg.VALUE8 == REG_SPI_CHIP_TYPE_RESET); 00887 00888 return ADMW_SUCCESS ; 00889 } 00890 00891 ADMW_RESULT admw1001_GetDataReadyModeInfo( 00892 ADMW_DEVICE_HANDLE const hDevice, 00893 ADMW_MEASUREMENT_MODE const eMeasurementMode, 00894 ADMW1001_OPERATING_MODE * const peOperatingMode, 00895 ADMW1001_DATAREADY_MODE * const peDataReadyMode, 00896 uint32_t * const pnSamplesPerDataready, 00897 uint32_t * const pnSamplesPerCycle, 00898 uint8_t * const pnBytesPerSample) 00899 { 00900 unsigned nChannelsEnabled = 0; 00901 unsigned nSamplesPerCycle = 0; 00902 00903 ADMW_CORE_Mode_t modeReg; 00904 READ_REG_U8(hDevice, modeReg.VALUE8, CORE_MODE); 00905 00906 if (eMeasurementMode == (modeReg.Conversion_Mode == CORE_MODE_SINGLECYCLE)) 00907 *peOperatingMode = ADMW1001_OPERATING_MODE_SINGLECYCLE ; 00908 else 00909 *peOperatingMode = ADMW1001_OPERATING_MODE_CONTINUOUS ; 00910 00911 if (eMeasurementMode == ADMW_MEASUREMENT_MODE_OMIT_RAW ) { 00912 *pnBytesPerSample = 5; 00913 } else { 00914 *pnBytesPerSample = 8; 00915 } 00916 00917 for (ADMW1001_CH_ID chId = ADMW1001_CH_ID_ANLG_1_UNIVERSAL ; 00918 chId < ADMW1001_MAX_CHANNELS ; 00919 chId++) { 00920 ADMW_CORE_Sensor_Details_t sensorDetailsReg; 00921 ADMW_CORE_Channel_Count_t channelCountReg; 00922 00923 if (ADMW1001_CHANNEL_IS_VIRTUAL(chId)) 00924 continue; 00925 00926 READ_REG_U8(hDevice, channelCountReg.VALUE8, CORE_CHANNEL_COUNTn(chId)); 00927 READ_REG_U32(hDevice, sensorDetailsReg.VALUE32, CORE_SENSOR_DETAILSn(chId)); 00928 00929 if (channelCountReg.Channel_Enable && !sensorDetailsReg.Do_Not_Publish) 00930 { 00931 unsigned nActualChannels = 1; 00932 00933 if (chId == ADMW1001_CH_ID_DIG_SPI_0 ) 00934 { 00935 /* Some sensors automatically generate samples on additional 00936 * "virtual" channels so these channels must be counted as 00937 * active when those sensors are selected and we use the count 00938 * from the corresponding "physical" channel 00939 */ 00940 #if 0 /* SPI sensors arent supported at present to be added back once there is 00941 * support for these sensors 00942 */ 00943 ADMW_CORE_Sensor_Type_t sensorTypeReg; 00944 00945 READ_REG_U16(hDevice, sensorTypeReg.VALUE16, CORE_SENSOR_TYPEn(chId)); 00946 00947 if ((sensorTypeReg.Sensor_Type >= 00948 CORE_SENSOR_TYPE_SPI_ACCELEROMETER_A) && 00949 (sensorTypeReg.Sensor_Type <= 00950 CORE_SENSOR_TYPE_SPI_ACCELEROMETER_B)) 00951 { 00952 nActualChannels += 2; 00953 } 00954 #endif 00955 } 00956 00957 nChannelsEnabled += nActualChannels; 00958 00959 nSamplesPerCycle += nActualChannels * 00960 (channelCountReg.Channel_Count + 1); 00961 } 00962 } 00963 00964 if (nChannelsEnabled == 0) { 00965 *pnSamplesPerDataready = 0; 00966 *pnSamplesPerCycle = 0; 00967 return ADMW_SUCCESS ; 00968 } 00969 00970 *pnSamplesPerCycle = nSamplesPerCycle; 00971 00972 if (modeReg.Drdy_Mode == CORE_MODE_DRDY_PER_CONVERSION) { 00973 *pnSamplesPerDataready = 1; 00974 } else { 00975 *pnSamplesPerDataready = nSamplesPerCycle; 00976 } 00977 00978 if (modeReg.Drdy_Mode == CORE_MODE_DRDY_PER_CONVERSION) { 00979 *peDataReadyMode = ADMW1001_DATAREADY_PER_CONVERSION ; 00980 } else { 00981 *peDataReadyMode = ADMW1001_DATAREADY_PER_CYCLE ; 00982 } 00983 00984 return ADMW_SUCCESS ; 00985 } 00986 00987 ADMW_RESULT admw_GetProductID( 00988 ADMW_DEVICE_HANDLE hDevice, 00989 ADMW_PRODUCT_ID *pProductId) 00990 { 00991 ADMW_SPI_Product_ID_L_t productIdLoReg; 00992 ADMW_SPI_Product_ID_H_t productIdHiReg; 00993 00994 READ_REG_U8(hDevice, productIdLoReg.VALUE8, SPI_PRODUCT_ID_L); 00995 READ_REG_U8(hDevice, productIdHiReg.VALUE8, SPI_PRODUCT_ID_H); 00996 00997 *pProductId = (ADMW_PRODUCT_ID )((productIdHiReg.VALUE8 << 8) | 00998 productIdLoReg.VALUE8); 00999 return ADMW_SUCCESS ; 01000 } 01001 01002 static ADMW_RESULT admw_SetPowerMode( 01003 ADMW_DEVICE_HANDLE hDevice, 01004 ADMW1001_POWER_MODE powerMode) 01005 { 01006 ADMW_CORE_Power_Config_t powerConfigReg; 01007 01008 if (powerMode == ADMW1001_POWER_MODE_HIBERNATION ) { 01009 powerConfigReg.Power_Mode_MCU = CORE_POWER_CONFIG_HIBERNATION; 01010 } else if (powerMode == ADMW1001_POWER_MODE_ACTIVE ) { 01011 powerConfigReg.Power_Mode_MCU = CORE_POWER_CONFIG_ACTIVE_MODE; 01012 } else { 01013 ADMW_LOG_ERROR("Invalid power mode %d specified", powerMode); 01014 return ADMW_INVALID_PARAM ; 01015 } 01016 01017 WRITE_REG_U8(hDevice, powerConfigReg.VALUE8, CORE_POWER_CONFIG); 01018 01019 return ADMW_SUCCESS ; 01020 } 01021 01022 ADMW_RESULT admw1001_SetPowerConfig( 01023 ADMW_DEVICE_HANDLE hDevice, 01024 ADMW1001_POWER_CONFIG *pPowerConfig) 01025 { 01026 ADMW_RESULT eRet; 01027 01028 eRet = admw_SetPowerMode(hDevice, pPowerConfig->powerMode ); 01029 if (eRet != ADMW_SUCCESS ) { 01030 ADMW_LOG_ERROR("Failed to set power mode"); 01031 return eRet; 01032 } 01033 01034 return ADMW_SUCCESS ; 01035 } 01036 01037 static ADMW_RESULT admw_SetRSenseValue( 01038 ADMW_DEVICE_HANDLE hDevice, 01039 float32_t RSenseValue) 01040 { 01041 ADMW_CORE_External_Reference_Resistor_t RefResistorConfigReg; 01042 01043 RefResistorConfigReg.Ext_Refin1_Value = RSenseValue; 01044 01045 WRITE_REG_FLOAT(hDevice, RefResistorConfigReg.VALUE32, CORE_EXTERNAL_REFERENCE_RESISTOR); 01046 01047 return ADMW_SUCCESS ; 01048 01049 } 01050 static ADMW_RESULT admw_SetMode( 01051 ADMW_DEVICE_HANDLE hDevice, 01052 ADMW1001_OPERATING_MODE eOperatingMode, 01053 ADMW1001_DATAREADY_MODE eDataReadyMode) 01054 { 01055 ADMW_CORE_Mode_t modeReg; 01056 01057 modeReg.VALUE8 = REG_RESET_VAL(CORE_MODE); 01058 01059 if (eOperatingMode == ADMW1001_OPERATING_MODE_SINGLECYCLE ) { 01060 modeReg.Conversion_Mode = CORE_MODE_SINGLECYCLE; 01061 } else if (eOperatingMode == ADMW1001_OPERATING_MODE_CONTINUOUS ) { 01062 modeReg.Conversion_Mode = CORE_MODE_CONTINUOUS; 01063 } else { 01064 ADMW_LOG_ERROR("Invalid operating mode %d specified", 01065 eOperatingMode); 01066 return ADMW_INVALID_PARAM ; 01067 } 01068 01069 if (eDataReadyMode == ADMW1001_DATAREADY_PER_CONVERSION ) { 01070 modeReg.Drdy_Mode = CORE_MODE_DRDY_PER_CONVERSION; 01071 } else if (eDataReadyMode == ADMW1001_DATAREADY_PER_CYCLE ) { 01072 modeReg.Drdy_Mode = CORE_MODE_DRDY_PER_CYCLE; 01073 } else { 01074 ADMW_LOG_ERROR("Invalid data-ready mode %d specified", eDataReadyMode); 01075 return ADMW_INVALID_PARAM ; 01076 } 01077 01078 WRITE_REG_U8(hDevice, modeReg.VALUE8, CORE_MODE); 01079 01080 return ADMW_SUCCESS ; 01081 } 01082 01083 ADMW_RESULT admw_SetCycleControl(ADMW_DEVICE_HANDLE hDevice, 01084 uint32_t nCycleInterval, 01085 bool vBiasEnable) 01086 { 01087 ADMW_CORE_Cycle_Control_t cycleControlReg; 01088 01089 cycleControlReg.VALUE16 = REG_RESET_VAL(CORE_CYCLE_CONTROL); 01090 01091 if (nCycleInterval < (1000 * (1 << 12))) { 01092 cycleControlReg.Cycle_Time_Units = CORE_CYCLE_CONTROL_MILLISECONDS; 01093 nCycleInterval /= 1000; 01094 } else { 01095 cycleControlReg.Cycle_Time_Units = CORE_CYCLE_CONTROL_SECONDS; 01096 nCycleInterval /= 1000000; 01097 } 01098 01099 if (vBiasEnable == true) { 01100 cycleControlReg.Vbias = 1; 01101 } 01102 CHECK_REG_FIELD_VAL(CORE_CYCLE_CONTROL_CYCLE_TIME, nCycleInterval); 01103 cycleControlReg.Cycle_Time = nCycleInterval; 01104 01105 WRITE_REG_U16(hDevice, cycleControlReg.VALUE16, CORE_CYCLE_CONTROL); 01106 01107 return ADMW_SUCCESS ; 01108 } 01109 static ADMW_RESULT admw_SetExternalReferenceVoltage( 01110 ADMW_DEVICE_HANDLE hDevice, 01111 float32_t externalRefVoltage) 01112 { 01113 WRITE_REG_FLOAT(hDevice, externalRefVoltage, CORE_EXTERNAL_VOLTAGE_REFERENCE); 01114 01115 return ADMW_SUCCESS ; 01116 } 01117 01118 static ADMW_RESULT admw_SetExternalReferenceValues( 01119 ADMW_DEVICE_HANDLE hDevice, 01120 float32_t externalRef1Value) 01121 { 01122 WRITE_REG_FLOAT(hDevice, externalRef1Value, CORE_EXTERNAL_REFERENCE_RESISTOR); 01123 01124 return ADMW_SUCCESS ; 01125 } 01126 01127 ADMW_RESULT admw1001_SetMeasurementConfig( 01128 ADMW_DEVICE_HANDLE hDevice, 01129 ADMW1001_MEASUREMENT_CONFIG *pMeasConfig) 01130 { 01131 ADMW_RESULT eRet; 01132 01133 eRet = admw_SetMode(hDevice, 01134 pMeasConfig->operatingMode , 01135 pMeasConfig->dataReadyMode ); 01136 if (eRet != ADMW_SUCCESS ) { 01137 ADMW_LOG_ERROR("Failed to set operating mode"); 01138 return eRet; 01139 } 01140 01141 eRet = admw_SetCycleControl(hDevice, pMeasConfig->cycleInterval , 01142 pMeasConfig->vBiasEnable ); 01143 if (eRet != ADMW_SUCCESS ) { 01144 ADMW_LOG_ERROR("Failed to set cycle control"); 01145 return eRet; 01146 } 01147 01148 if(pMeasConfig->externalRef1Value >0) { 01149 eRet = admw_SetExternalReferenceValues(hDevice, 01150 pMeasConfig->externalRef1Value ); 01151 } 01152 01153 if (eRet != ADMW_SUCCESS ) { 01154 ADMW_LOG_ERROR("Failed to set external reference values"); 01155 return eRet; 01156 } 01157 01158 eRet = admw_SetRSenseValue(hDevice, pMeasConfig->RSenseValue ); 01159 if (eRet != ADMW_SUCCESS ) 01160 { 01161 ADMW_LOG_ERROR("Failed to set RSenseValue"); 01162 return eRet; 01163 } 01164 01165 eRet = admw_SetExternalReferenceVoltage(hDevice, pMeasConfig->externalRefVoltage ); 01166 if (eRet != ADMW_SUCCESS ) 01167 { 01168 ADMW_LOG_ERROR("Failed to set External reference Voltage"); 01169 return eRet; 01170 } 01171 01172 return ADMW_SUCCESS ; 01173 } 01174 01175 ADMW_RESULT admw1001_SetDiagnosticsConfig( 01176 ADMW_DEVICE_HANDLE hDevice, 01177 ADMW1001_DIAGNOSTICS_CONFIG *pDiagnosticsConfig) 01178 { 01179 ADMW_CORE_Diagnostics_Control_t diagnosticsControlReg; 01180 01181 diagnosticsControlReg.VALUE8 = REG_RESET_VAL(CORE_DIAGNOSTICS_CONTROL); 01182 01183 if (pDiagnosticsConfig->disableMeasurementDiag ) 01184 diagnosticsControlReg.Diag_Meas_En = 0; 01185 else 01186 diagnosticsControlReg.Diag_Meas_En = 1; 01187 01188 switch (pDiagnosticsConfig->osdFrequency ) 01189 { 01190 case ADMW1001_OPEN_SENSOR_DIAGNOSTICS_DISABLED : 01191 diagnosticsControlReg.Diag_OSD_Freq = CORE_DIAGNOSTICS_CONTROL_OCD_OFF; 01192 break; 01193 case ADMW1001_OPEN_SENSOR_DIAGNOSTICS_PER_CYCLE : 01194 diagnosticsControlReg.Diag_OSD_Freq = CORE_DIAGNOSTICS_CONTROL_OCD_PER_1_CYCLE; 01195 break; 01196 case ADMW1001_OPEN_SENSOR_DIAGNOSTICS_PER_100_CYCLES : 01197 diagnosticsControlReg.Diag_OSD_Freq = CORE_DIAGNOSTICS_CONTROL_OCD_PER_10_CYCLES; 01198 break; 01199 case ADMW1001_OPEN_SENSOR_DIAGNOSTICS_PER_1000_CYCLES : 01200 diagnosticsControlReg.Diag_OSD_Freq = CORE_DIAGNOSTICS_CONTROL_OCD_PER_100_CYCLES; 01201 break; 01202 default: 01203 ADMW_LOG_ERROR("Invalid open-sensor diagnostic frequency %d specified", 01204 pDiagnosticsConfig->osdFrequency ); 01205 return ADMW_INVALID_PARAM ; 01206 } 01207 01208 WRITE_REG_U8(hDevice, diagnosticsControlReg.VALUE8, CORE_DIAGNOSTICS_CONTROL); 01209 01210 return ADMW_SUCCESS ; 01211 } 01212 01213 ADMW_RESULT admw1001_SetChannelCount( 01214 ADMW_DEVICE_HANDLE hDevice, 01215 ADMW1001_CH_ID eChannelId, 01216 uint32_t nMeasurementsPerCycle) 01217 { 01218 ADMW_CORE_Channel_Count_t channelCountReg; 01219 01220 channelCountReg.VALUE8 = REG_RESET_VAL(CORE_CHANNEL_COUNTn); 01221 01222 if (nMeasurementsPerCycle > 0) { 01223 nMeasurementsPerCycle -= 1; 01224 01225 CHECK_REG_FIELD_VAL(CORE_CHANNEL_COUNT_CHANNEL_COUNT, 01226 nMeasurementsPerCycle); 01227 01228 channelCountReg.Channel_Enable = 1; 01229 channelCountReg.Channel_Count = nMeasurementsPerCycle; 01230 } else { 01231 channelCountReg.Channel_Enable = 0; 01232 } 01233 01234 WRITE_REG_U8(hDevice, channelCountReg.VALUE8, CORE_CHANNEL_COUNTn(eChannelId)); 01235 01236 return ADMW_SUCCESS ; 01237 } 01238 01239 ADMW_RESULT admw1001_SetChannelOptions( 01240 ADMW_DEVICE_HANDLE hDevice, 01241 ADMW1001_CH_ID eChannelId, 01242 ADMW1001_CHANNEL_PRIORITY ePriority) 01243 { 01244 ADMW_CORE_Channel_Options_t channelOptionsReg; 01245 01246 channelOptionsReg.VALUE8 = REG_RESET_VAL(CORE_CHANNEL_OPTIONSn); 01247 01248 CHECK_REG_FIELD_VAL(CORE_CHANNEL_OPTIONS_CHANNEL_PRIORITY, ePriority); 01249 channelOptionsReg.Channel_Priority = ePriority; 01250 01251 WRITE_REG_U8(hDevice, channelOptionsReg.VALUE8, CORE_CHANNEL_OPTIONSn(eChannelId)); 01252 01253 return ADMW_SUCCESS ; 01254 } 01255 01256 ADMW_RESULT admw1001_SetChannelSkipCount( 01257 ADMW_DEVICE_HANDLE hDevice, 01258 ADMW1001_CH_ID eChannelId, 01259 uint32_t nCycleSkipCount) 01260 { 01261 ADMW_CORE_Channel_Skip_t channelSkipReg; 01262 01263 channelSkipReg.VALUE16 = REG_RESET_VAL(CORE_CHANNEL_SKIPn); 01264 01265 CHECK_REG_FIELD_VAL(CORE_CHANNEL_SKIP_CHANNEL_SKIP, nCycleSkipCount); 01266 01267 channelSkipReg.Channel_Skip = nCycleSkipCount; 01268 01269 WRITE_REG_U16(hDevice, channelSkipReg.VALUE16, CORE_CHANNEL_SKIPn(eChannelId)); 01270 01271 return ADMW_SUCCESS ; 01272 } 01273 01274 static ADMW_RESULT admw_SetChannelAdcSensorType( 01275 ADMW_DEVICE_HANDLE hDevice, 01276 ADMW1001_CH_ID eChannelId, 01277 ADMW1001_ADC_SENSOR_TYPE sensorType) 01278 { 01279 ADMW_CORE_Sensor_Type_t sensorTypeReg; 01280 01281 sensorTypeReg.VALUE16 = REG_RESET_VAL(CORE_SENSOR_TYPEn); 01282 01283 /* Ensure that the sensor type is valid for this channel */ 01284 switch(sensorType) { 01285 case ADMW1001_ADC_SENSOR_RTD_3WIRE_PT100 : 01286 case ADMW1001_ADC_SENSOR_RTD_3WIRE_PT1000 : 01287 case ADMW1001_ADC_SENSOR_RTD_3WIRE_1 : 01288 case ADMW1001_ADC_SENSOR_RTD_3WIRE_2 : 01289 case ADMW1001_ADC_SENSOR_RTD_3WIRE_3 : 01290 case ADMW1001_ADC_SENSOR_RTD_3WIRE_4 : 01291 case ADMW1001_ADC_SENSOR_RTD_4WIRE_PT100 : 01292 case ADMW1001_ADC_SENSOR_RTD_4WIRE_PT1000 : 01293 case ADMW1001_ADC_SENSOR_RTD_4WIRE_1 : 01294 case ADMW1001_ADC_SENSOR_RTD_4WIRE_2 : 01295 case ADMW1001_ADC_SENSOR_RTD_4WIRE_3 : 01296 case ADMW1001_ADC_SENSOR_RTD_4WIRE_4 : 01297 case ADMW1001_ADC_SENSOR_BRIDGE_4WIRE_1 : 01298 case ADMW1001_ADC_SENSOR_BRIDGE_4WIRE_2 : 01299 case ADMW1001_ADC_SENSOR_BRIDGE_4WIRE_3 : 01300 case ADMW1001_ADC_SENSOR_BRIDGE_4WIRE_4 : 01301 case ADMW1001_ADC_SENSOR_BRIDGE_6WIRE_1 : 01302 case ADMW1001_ADC_SENSOR_BRIDGE_6WIRE_2 : 01303 case ADMW1001_ADC_SENSOR_BRIDGE_6WIRE_3 : 01304 case ADMW1001_ADC_SENSOR_BRIDGE_6WIRE_4 : 01305 case ADMW1001_ADC_SENSOR_RTD_2WIRE_PT100 : 01306 case ADMW1001_ADC_SENSOR_RTD_2WIRE_PT1000 : 01307 case ADMW1001_ADC_SENSOR_RTD_2WIRE_1 : 01308 case ADMW1001_ADC_SENSOR_RTD_2WIRE_2 : 01309 case ADMW1001_ADC_SENSOR_RTD_2WIRE_3 : 01310 case ADMW1001_ADC_SENSOR_RTD_2WIRE_4 : 01311 case ADMW1001_ADC_SENSOR_DIODE_2C_TYPEA : 01312 case ADMW1001_ADC_SENSOR_DIODE_3C_TYPEA : 01313 case ADMW1001_ADC_SENSOR_DIODE_2C_1 : 01314 case ADMW1001_ADC_SENSOR_DIODE_3C_1 : 01315 case ADMW1001_ADC_SENSOR_THERMISTOR_A_10K : 01316 case ADMW1001_ADC_SENSOR_THERMISTOR_B_10K : 01317 case ADMW1001_ADC_SENSOR_THERMISTOR_1 : 01318 case ADMW1001_ADC_SENSOR_THERMISTOR_2 : 01319 case ADMW1001_ADC_SENSOR_THERMISTOR_3 : 01320 case ADMW1001_ADC_SENSOR_THERMISTOR_4 : 01321 case ADMW1001_ADC_SENSOR_SINGLE_ENDED_ABSOLUTE : 01322 case ADMW1001_ADC_SENSOR_DIFFERENTIAL_ABSOLUTE : 01323 case ADMW1001_ADC_SENSOR_SINGLE_ENDED_RATIO : 01324 case ADMW1001_ADC_SENSOR_DIFFERENTIAL_RATIO : 01325 if (! (ADMW1001_CHANNEL_IS_ADC_SENSOR(eChannelId) || 01326 ADMW1001_CHANNEL_IS_ADC_CJC(eChannelId) || ADMW1001_CHANNEL_IS_ADC(eChannelId) )) 01327 { 01328 ADMW_LOG_ERROR( 01329 "Invalid ADC sensor type %d specified for channel %d", 01330 sensorType, eChannelId); 01331 return ADMW_INVALID_PARAM ; 01332 } 01333 break; 01334 case ADMW1001_ADC_SENSOR_VOLTAGE : 01335 case ADMW1001_ADC_SENSOR_VOLTAGE_PRESSURE_A : 01336 case ADMW1001_ADC_SENSOR_VOLTAGE_PRESSURE_B : 01337 case ADMW1001_ADC_SENSOR_VOLTAGE_PRESSURE_1 : 01338 case ADMW1001_ADC_SENSOR_VOLTAGE_PRESSURE_2 : 01339 case ADMW1001_ADC_SENSOR_THERMOCOUPLE_J : 01340 case ADMW1001_ADC_SENSOR_THERMOCOUPLE_K : 01341 case ADMW1001_ADC_SENSOR_THERMOCOUPLE_T : 01342 case ADMW1001_ADC_SENSOR_THERMOCOUPLE_1 : 01343 case ADMW1001_ADC_SENSOR_THERMOCOUPLE_2 : 01344 case ADMW1001_ADC_SENSOR_THERMOCOUPLE_3 : 01345 case ADMW1001_ADC_SENSOR_THERMOCOUPLE_4 : 01346 if (! ADMW1001_CHANNEL_IS_ADC_VOLTAGE(eChannelId)) { 01347 ADMW_LOG_ERROR( 01348 "Invalid ADC sensor type %d specified for channel %d", 01349 sensorType, eChannelId); 01350 return ADMW_INVALID_PARAM ; 01351 } 01352 break; 01353 case ADMW1001_ADC_SENSOR_CURRENT : 01354 case ADMW1001_ADC_SENSOR_CURRENT_PRESSURE_A : 01355 case ADMW1001_ADC_SENSOR_CURRENT_PRESSURE_1 : 01356 case ADMW1001_ADC_SENSOR_CURRENT_PRESSURE_2 : 01357 if (! ADMW1001_CHANNEL_IS_ADC_CURRENT(eChannelId)) { 01358 ADMW_LOG_ERROR( 01359 "Invalid ADC sensor type %d specified for channel %d", 01360 sensorType, eChannelId); 01361 return ADMW_INVALID_PARAM ; 01362 } 01363 break; 01364 default: 01365 ADMW_LOG_ERROR("Invalid/unsupported ADC sensor type %d specified", 01366 sensorType); 01367 return ADMW_INVALID_PARAM ; 01368 } 01369 01370 sensorTypeReg.Sensor_Type = sensorType; 01371 01372 WRITE_REG_U16(hDevice, sensorTypeReg.VALUE16, CORE_SENSOR_TYPEn(eChannelId)); 01373 01374 return ADMW_SUCCESS ; 01375 } 01376 01377 static ADMW_RESULT admw_SetChannelAdcSensorDetails( 01378 ADMW_DEVICE_HANDLE hDevice, 01379 ADMW1001_CH_ID eChannelId, 01380 ADMW1001_CHANNEL_CONFIG *pChannelConfig) 01381 /* 01382 * TODO - it would be nice if the general- vs. ADC-specific sensor details could be split into separate registers 01383 * General details: 01384 * - Measurement_Units 01385 * - Compensation_Channel 01386 * - CJC_Publish (if "CJC" was removed from the name) 01387 * ADC-specific details: 01388 * - PGA_Gain 01389 * - Reference_Select 01390 * - Reference_Buffer_Disable 01391 */ 01392 { 01393 ADMW1001_ADC_CHANNEL_CONFIG *pAdcChannelConfig = &pChannelConfig->adcChannelConfig ; 01394 ADMW1001_ADC_REFERENCE_TYPE refType = pAdcChannelConfig->reference; 01395 ADMW_CORE_Sensor_Details_t sensorDetailsReg; 01396 01397 sensorDetailsReg.VALUE32 = REG_RESET_VAL(CORE_SENSOR_DETAILSn); 01398 01399 switch(pChannelConfig->measurementUnit ) { 01400 case ADMW1001_MEASUREMENT_UNIT_FAHRENHEIT : 01401 sensorDetailsReg.Measurement_Units = CORE_SENSOR_DETAILS_UNITS_DEGF; 01402 break; 01403 case ADMW1001_MEASUREMENT_UNIT_CELSIUS : 01404 sensorDetailsReg.Measurement_Units = CORE_SENSOR_DETAILS_UNITS_DEGC; 01405 break; 01406 case ADMW1001_MEASUREMENT_UNIT_UNSPECIFIED : 01407 sensorDetailsReg.Measurement_Units = CORE_SENSOR_DETAILS_UNITS_UNSPECIFIED; 01408 break; 01409 default: 01410 ADMW_LOG_ERROR("Invalid measurement unit %d specified", 01411 pChannelConfig->measurementUnit ); 01412 return ADMW_INVALID_PARAM ; 01413 } 01414 01415 if (pChannelConfig->compensationChannel == ADMW1001_CH_ID_NONE ) { 01416 sensorDetailsReg.Compensation_Disable = 1; 01417 sensorDetailsReg.Compensation_Channel = 0; 01418 } else { 01419 sensorDetailsReg.Compensation_Disable = 0; 01420 sensorDetailsReg.Compensation_Channel = pChannelConfig->compensationChannel ; 01421 } 01422 01423 switch(refType) { 01424 case ADMW1001_ADC_REFERENCE_VOLTAGE_INTERNAL : 01425 sensorDetailsReg.Reference_Select = CORE_SENSOR_DETAILS_REF_VINT; 01426 break; 01427 case ADMW1001_ADC_REFERENCE_VOLTAGE_EXTERNAL_1 : 01428 sensorDetailsReg.Reference_Select = CORE_SENSOR_DETAILS_REF_VEXT1; 01429 break; 01430 case ADMW1001_ADC_REFERENCE_VOLTAGE_AVDD : 01431 sensorDetailsReg.Reference_Select = CORE_SENSOR_DETAILS_REF_AVDD; 01432 break; 01433 default: 01434 ADMW_LOG_ERROR("Invalid ADC reference type %d specified", refType); 01435 return ADMW_INVALID_PARAM ; 01436 } 01437 01438 switch(pAdcChannelConfig->gain ) { 01439 case ADMW1001_ADC_GAIN_1X : 01440 sensorDetailsReg.PGA_Gain = CORE_SENSOR_DETAILS_PGA_GAIN_1; 01441 break; 01442 case ADMW1001_ADC_GAIN_2X : 01443 sensorDetailsReg.PGA_Gain = CORE_SENSOR_DETAILS_PGA_GAIN_2; 01444 break; 01445 case ADMW1001_ADC_GAIN_4X : 01446 sensorDetailsReg.PGA_Gain = CORE_SENSOR_DETAILS_PGA_GAIN_4; 01447 break; 01448 case ADMW1001_ADC_GAIN_8X : 01449 sensorDetailsReg.PGA_Gain = CORE_SENSOR_DETAILS_PGA_GAIN_8; 01450 break; 01451 case ADMW1001_ADC_GAIN_16X : 01452 sensorDetailsReg.PGA_Gain = CORE_SENSOR_DETAILS_PGA_GAIN_16; 01453 break; 01454 case ADMW1001_ADC_GAIN_32X : 01455 sensorDetailsReg.PGA_Gain = CORE_SENSOR_DETAILS_PGA_GAIN_32; 01456 break; 01457 case ADMW1001_ADC_GAIN_64X : 01458 sensorDetailsReg.PGA_Gain = CORE_SENSOR_DETAILS_PGA_GAIN_64; 01459 break; 01460 case ADMW1001_ADC_GAIN_128X : 01461 sensorDetailsReg.PGA_Gain = CORE_SENSOR_DETAILS_PGA_GAIN_128; 01462 break; 01463 default: 01464 ADMW_LOG_ERROR("Invalid ADC gain %d specified", 01465 pAdcChannelConfig->gain ); 01466 return ADMW_INVALID_PARAM ; 01467 } 01468 01469 switch(pAdcChannelConfig->rtdCurve ) { 01470 case ADMW1001_ADC_RTD_CURVE_EUROPEAN : 01471 sensorDetailsReg.RTD_Curve = CORE_SENSOR_DETAILS_EUROPEAN_CURVE; 01472 break; 01473 case ADMW1001_ADC_RTD_CURVE_AMERICAN : 01474 sensorDetailsReg.RTD_Curve = CORE_SENSOR_DETAILS_AMERICAN_CURVE; 01475 break; 01476 case ADMW1001_ADC_RTD_CURVE_JAPANESE : 01477 sensorDetailsReg.RTD_Curve = CORE_SENSOR_DETAILS_JAPANESE_CURVE; 01478 break; 01479 case ADMW1001_ADC_RTD_CURVE_ITS90 : 01480 sensorDetailsReg.RTD_Curve = CORE_SENSOR_DETAILS_ITS90_CURVE; 01481 break; 01482 default: 01483 ADMW_LOG_ERROR("Invalid RTD Curve %d specified", 01484 pAdcChannelConfig->rtdCurve ); 01485 return ADMW_INVALID_PARAM ; 01486 } 01487 01488 if (pChannelConfig->disablePublishing ) { 01489 sensorDetailsReg.Do_Not_Publish = 1; 01490 } else { 01491 sensorDetailsReg.Do_Not_Publish = 0; 01492 } 01493 01494 switch (pChannelConfig->lutSelect ) { 01495 case ADMW1001_LUT_DEFAULT : 01496 case ADMW1001_LUT_UNITY : 01497 case ADMW1001_LUT_CUSTOM : 01498 sensorDetailsReg.LUT_Select = pChannelConfig->lutSelect ; 01499 break; 01500 default: 01501 ADMW_LOG_ERROR("Invalid LUT selection %d specified", 01502 pChannelConfig->lutSelect ); 01503 return ADMW_INVALID_PARAM ; 01504 } 01505 01506 WRITE_REG_U32(hDevice, sensorDetailsReg.VALUE32, CORE_SENSOR_DETAILSn(eChannelId)); 01507 01508 return ADMW_SUCCESS ; 01509 } 01510 01511 static ADMW_RESULT admw_SetChannelAdcMeasurementSetup( 01512 ADMW_DEVICE_HANDLE hDevice, 01513 ADMW1001_CH_ID eChannelId, 01514 ADMW1001_ADC_CHANNEL_CONFIG *pAdcChannelConfig) 01515 { 01516 ADMW_CORE_Measurement_Setup_t MeasSetupReg; 01517 ADMW1001_ADC_FILTER_CONFIG *pFilterConfig = &pAdcChannelConfig->filter ; 01518 MeasSetupReg.VALUE32 = REG_RESET_VAL(CORE_MEASUREMENT_SETUPn); 01519 MeasSetupReg.PST_MEAS_EXC_CTRL = pAdcChannelConfig->current .excitationState ; 01520 MeasSetupReg.Buffer_Bypass = pAdcChannelConfig->bufferBypass ; 01521 01522 if (pFilterConfig->type == ADMW1001_ADC_FILTER_SINC4 ) { 01523 MeasSetupReg.ADC_Filter_Type = CORE_MEASUREMENT_SETUP_ENABLE_SINC4; 01524 MeasSetupReg.ADC_SF = pFilterConfig->sf ; 01525 } else if (pFilterConfig->type == ADMW1001_ADC_FILTER_SINC3 ) { 01526 MeasSetupReg.ADC_Filter_Type = CORE_MEASUREMENT_SETUP_ENABLE_SINC3; 01527 MeasSetupReg.ADC_SF = pFilterConfig->sf ; 01528 } else { 01529 ADMW_LOG_ERROR("Invalid ADC filter type %d specified", 01530 pFilterConfig->type ); 01531 return ADMW_INVALID_PARAM ; 01532 } 01533 01534 /* chop mod ecan be 0 (none), 1 (HW, 2 (SW, 3 (HW+SW). */ 01535 MeasSetupReg.Chop_Mode = pFilterConfig->chopMode ; 01536 01537 if(pFilterConfig->notch1p2 ) 01538 MeasSetupReg.NOTCH_EN_2 = 1; 01539 else 01540 MeasSetupReg.NOTCH_EN_2 = 0; 01541 01542 switch(pFilterConfig->groundSwitch ) { 01543 case ADMW1001_ADC_GND_SW_OPEN : 01544 MeasSetupReg.GND_SW = CORE_MEASUREMENT_SETUP_GND_SW_OPEN; 01545 break; 01546 case ADMW1001_ADC_GND_SW_CLOSED : 01547 MeasSetupReg.GND_SW = CORE_MEASUREMENT_SETUP_GND_SW_CLOSED; 01548 break; 01549 default: 01550 ADMW_LOG_ERROR("Invalid ground switch state %d specified", 01551 pFilterConfig->groundSwitch ); 01552 return ADMW_INVALID_PARAM ; 01553 } 01554 01555 WRITE_REG_U32(hDevice, MeasSetupReg.VALUE32, CORE_MEASUREMENT_SETUPn(eChannelId)); 01556 01557 return ADMW_SUCCESS ; 01558 } 01559 01560 static ADMW_RESULT admw_SetChannelAdcCurrentConfig( 01561 ADMW_DEVICE_HANDLE hDevice, 01562 ADMW1001_CH_ID eChannelId, 01563 ADMW1001_ADC_EXC_CURRENT_CONFIG *pCurrentConfig) 01564 { 01565 ADMW_CORE_Channel_Excitation_t channelExcitationReg; 01566 01567 channelExcitationReg.VALUE16 = REG_RESET_VAL(CORE_CHANNEL_EXCITATIONn); 01568 01569 if (pCurrentConfig->outputLevel == ADMW1001_ADC_NO_EXTERNAL_EXC_CURRENT ) 01570 channelExcitationReg.IOUT_Excitation_Current = CORE_CHANNEL_EXCITATION_NONE; 01571 else if (pCurrentConfig->outputLevel == ADMW1001_ADC_EXC_CURRENT_EXTERNAL ) 01572 channelExcitationReg.IOUT_Excitation_Current = CORE_CHANNEL_EXCITATION_EXTERNAL; 01573 else if (pCurrentConfig->outputLevel == ADMW1001_ADC_EXC_CURRENT_50uA ) 01574 channelExcitationReg.IOUT_Excitation_Current = CORE_CHANNEL_EXCITATION_IEXC_50UA; 01575 else if (pCurrentConfig->outputLevel == ADMW1001_ADC_EXC_CURRENT_100uA ) 01576 channelExcitationReg.IOUT_Excitation_Current = CORE_CHANNEL_EXCITATION_IEXC_100UA; 01577 else if (pCurrentConfig->outputLevel == ADMW1001_ADC_EXC_CURRENT_250uA ) 01578 channelExcitationReg.IOUT_Excitation_Current = CORE_CHANNEL_EXCITATION_IEXC_250UA; 01579 else if (pCurrentConfig->outputLevel == ADMW1001_ADC_EXC_CURRENT_500uA ) 01580 channelExcitationReg.IOUT_Excitation_Current = CORE_CHANNEL_EXCITATION_IEXC_500UA; 01581 else if (pCurrentConfig->outputLevel == ADMW1001_ADC_EXC_CURRENT_1000uA ) 01582 channelExcitationReg.IOUT_Excitation_Current = CORE_CHANNEL_EXCITATION_IEXC_1000UA; 01583 else { 01584 ADMW_LOG_ERROR("Invalid ADC excitation current %d specified", 01585 pCurrentConfig->outputLevel ); 01586 return ADMW_INVALID_PARAM ; 01587 } 01588 01589 WRITE_REG_U16(hDevice, channelExcitationReg.VALUE16, CORE_CHANNEL_EXCITATIONn(eChannelId)); 01590 01591 return ADMW_SUCCESS ; 01592 } 01593 01594 ADMW_RESULT admw_SetAdcChannelConfig( 01595 ADMW_DEVICE_HANDLE hDevice, 01596 ADMW1001_CH_ID eChannelId, 01597 ADMW1001_CHANNEL_CONFIG *pChannelConfig) 01598 { 01599 ADMW_RESULT eRet; 01600 ADMW1001_ADC_CHANNEL_CONFIG *pAdcChannelConfig = 01601 &pChannelConfig->adcChannelConfig ; 01602 01603 eRet = admw_SetChannelAdcSensorType(hDevice, eChannelId, 01604 pAdcChannelConfig->sensor ); 01605 if (eRet != ADMW_SUCCESS ) { 01606 ADMW_LOG_ERROR("Failed to set ADC sensor type for channel %d", 01607 eChannelId); 01608 return eRet; 01609 } 01610 01611 eRet = admw_SetChannelAdcSensorDetails(hDevice, eChannelId, 01612 pChannelConfig); 01613 if (eRet != ADMW_SUCCESS ) { 01614 ADMW_LOG_ERROR("Failed to set ADC sensor details for channel %d", 01615 eChannelId); 01616 return eRet; 01617 } 01618 01619 eRet = admw_SetChannelAdcMeasurementSetup(hDevice, eChannelId, 01620 pAdcChannelConfig); 01621 if (eRet != ADMW_SUCCESS ) { 01622 ADMW_LOG_ERROR("Failed to set ADC filter for channel %d", 01623 eChannelId); 01624 return eRet; 01625 } 01626 01627 eRet = admw_SetChannelAdcCurrentConfig(hDevice, eChannelId, 01628 &pAdcChannelConfig->current ); 01629 if (eRet != ADMW_SUCCESS ) { 01630 ADMW_LOG_ERROR("Failed to set ADC current for channel %d", 01631 eChannelId); 01632 return eRet; 01633 } 01634 01635 return ADMW_SUCCESS ; 01636 } 01637 01638 static ADMW_RESULT admw_SetChannelDigitalSensorDetails( 01639 ADMW_DEVICE_HANDLE hDevice, 01640 ADMW1001_CH_ID eChannelId, 01641 ADMW1001_CHANNEL_CONFIG *pChannelConfig) 01642 { 01643 ADMW_CORE_Sensor_Details_t sensorDetailsReg; 01644 01645 sensorDetailsReg.VALUE32 = REG_RESET_VAL(CORE_SENSOR_DETAILSn); 01646 01647 if (pChannelConfig->compensationChannel == ADMW1001_CH_ID_NONE ) { 01648 sensorDetailsReg.Compensation_Disable = 1; 01649 sensorDetailsReg.Compensation_Channel = 0; 01650 } else { 01651 ADMW_LOG_ERROR("Invalid compensation channel specified for digital sensor"); 01652 return ADMW_INVALID_PARAM ; 01653 } 01654 01655 if (pChannelConfig->measurementUnit == ADMW1001_MEASUREMENT_UNIT_UNSPECIFIED ) { 01656 sensorDetailsReg.Measurement_Units = CORE_SENSOR_DETAILS_UNITS_UNSPECIFIED; 01657 } else { 01658 ADMW_LOG_ERROR("Invalid measurement unit specified for digital channel"); 01659 return ADMW_INVALID_PARAM ; 01660 } 01661 01662 if (pChannelConfig->disablePublishing ) 01663 sensorDetailsReg.Do_Not_Publish = 1; 01664 else 01665 sensorDetailsReg.Do_Not_Publish = 0; 01666 01667 WRITE_REG_U32(hDevice, sensorDetailsReg.VALUE32, CORE_SENSOR_DETAILSn(eChannelId)); 01668 01669 return ADMW_SUCCESS ; 01670 } 01671 01672 static ADMW_RESULT admw_SetDigitalSensorFormat( 01673 ADMW_DEVICE_HANDLE hDevice, 01674 ADMW1001_CH_ID eChannelId, 01675 ADMW1001_DIGITAL_SENSOR_DATA_FORMAT *pDataFormat) 01676 { 01677 ADMW_CORE_Digital_Sensor_Config_t sensorConfigReg; 01678 01679 sensorConfigReg.VALUE16 = REG_RESET_VAL(CORE_DIGITAL_SENSOR_CONFIGn); 01680 01681 if (pDataFormat->coding != ADMW1001_DIGITAL_SENSOR_DATA_CODING_NONE) { 01682 if (pDataFormat->frameLength == 0) { 01683 ADMW_LOG_ERROR("Invalid frame length specified for digital sensor data format"); 01684 return ADMW_INVALID_PARAM ; 01685 } 01686 if (pDataFormat->numDataBits == 0) { 01687 ADMW_LOG_ERROR("Invalid frame length specified for digital sensor data format"); 01688 return ADMW_INVALID_PARAM ; 01689 } 01690 01691 CHECK_REG_FIELD_VAL(CORE_DIGITAL_SENSOR_CONFIG_DIGITAL_SENSOR_READ_BYTES, 01692 pDataFormat->frameLength - 1); 01693 CHECK_REG_FIELD_VAL(CORE_DIGITAL_SENSOR_CONFIG_DIGITAL_SENSOR_DATA_BITS, 01694 pDataFormat->numDataBits - 1); 01695 CHECK_REG_FIELD_VAL(CORE_DIGITAL_SENSOR_CONFIG_DIGITAL_SENSOR_BIT_OFFSET, 01696 pDataFormat->bitOffset); 01697 01698 sensorConfigReg.Digital_Sensor_Read_Bytes = pDataFormat->frameLength - 1; 01699 sensorConfigReg.Digital_Sensor_Data_Bits = pDataFormat->numDataBits - 1; 01700 sensorConfigReg.Digital_Sensor_Bit_Offset = pDataFormat->bitOffset; 01701 sensorConfigReg.Digital_Sensor_Left_Aligned = pDataFormat->leftJustified ? 1 : 0; 01702 sensorConfigReg.Digital_Sensor_Little_Endian = pDataFormat->littleEndian ? 1 : 0; 01703 01704 switch (pDataFormat->coding) { 01705 case ADMW1001_DIGITAL_SENSOR_DATA_CODING_UNIPOLAR: 01706 sensorConfigReg.Digital_Sensor_Coding = CORE_DIGITAL_SENSOR_CONFIG_CODING_UNIPOLAR; 01707 break; 01708 case ADMW1001_DIGITAL_SENSOR_DATA_CODING_TWOS_COMPLEMENT: 01709 sensorConfigReg.Digital_Sensor_Coding = CORE_DIGITAL_SENSOR_CONFIG_CODING_TWOS_COMPL; 01710 break; 01711 case ADMW1001_DIGITAL_SENSOR_DATA_CODING_OFFSET_BINARY: 01712 sensorConfigReg.Digital_Sensor_Coding = CORE_DIGITAL_SENSOR_CONFIG_CODING_OFFSET_BINARY; 01713 break; 01714 default: 01715 ADMW_LOG_ERROR("Invalid coding specified for digital sensor data format"); 01716 return ADMW_INVALID_PARAM ; 01717 } 01718 } else { 01719 sensorConfigReg.Digital_Sensor_Coding = CORE_DIGITAL_SENSOR_CONFIG_CODING_NONE; 01720 } 01721 01722 WRITE_REG_U16(hDevice, sensorConfigReg.VALUE16, 01723 CORE_DIGITAL_SENSOR_CONFIGn(eChannelId)); 01724 01725 01726 return ADMW_SUCCESS ; 01727 } 01728 01729 static ADMW_RESULT admw_SetDigitalCalibrationParam( 01730 ADMW_DEVICE_HANDLE hDevice, 01731 ADMW1001_CH_ID eChannelId, 01732 ADMW1001_DIGITAL_CALIBRATION_COMMAND *pCalibrationParam) 01733 { 01734 // ADMW_CORE_Calibration_Parameter_t calibrationParamReg; 01735 // 01736 // calibrationParamReg.VALUE32 = REG_RESET_VAL(CORE_CALIBRATION_PARAMETERn); 01737 // 01738 // if (pCalibrationParam->enableCalibrationParam == false) 01739 // calibrationParamReg.Calibration_Parameter_Enable = 0; 01740 // else 01741 // calibrationParamReg.Calibration_Parameter_Enable = 1; 01742 // 01743 // CHECK_REG_FIELD_VAL(CORE_CALIBRATION_PARAMETER_CALIBRATION_PARAMETER, 01744 // pCalibrationParam->calibrationParam); 01745 // 01746 // calibrationParamReg.Calibration_Parameter = pCalibrationParam->calibrationParam; 01747 // 01748 // WRITE_REG_U32(hDevice, calibrationParamReg.VALUE32, 01749 // CORE_CALIBRATION_PARAMETERn(eChannelId)); 01750 // 01751 return ADMW_SUCCESS ; 01752 } 01753 01754 static ADMW_RESULT admw_SetChannelI2cSensorType( 01755 ADMW_DEVICE_HANDLE hDevice, 01756 ADMW1001_CH_ID eChannelId, 01757 ADMW1001_I2C_SENSOR_TYPE sensorType) 01758 { 01759 ADMW_CORE_Sensor_Type_t sensorTypeReg; 01760 01761 sensorTypeReg.VALUE16 = REG_RESET_VAL(CORE_SENSOR_TYPEn); 01762 01763 /* Ensure that the sensor type is valid for this channel */ 01764 switch(sensorType) { 01765 case ADMW1001_I2C_SENSOR_HUMIDITY_A : 01766 case ADMW1001_I2C_SENSOR_HUMIDITY_B : 01767 sensorTypeReg.Sensor_Type = sensorType; 01768 break; 01769 default: 01770 ADMW_LOG_ERROR("Unsupported I2C sensor type %d specified", sensorType); 01771 return ADMW_INVALID_PARAM ; 01772 } 01773 01774 WRITE_REG_U16(hDevice, sensorTypeReg.VALUE16, CORE_SENSOR_TYPEn(eChannelId)); 01775 01776 return ADMW_SUCCESS ; 01777 } 01778 01779 static ADMW_RESULT admw_SetChannelI2cSensorAddress( 01780 ADMW_DEVICE_HANDLE hDevice, 01781 ADMW1001_CH_ID eChannelId, 01782 uint32_t deviceAddress) 01783 { 01784 CHECK_REG_FIELD_VAL(CORE_DIGITAL_SENSOR_ADDRESS_DIGITAL_SENSOR_ADDRESS, deviceAddress); 01785 WRITE_REG_U8(hDevice, deviceAddress, CORE_DIGITAL_SENSOR_ADDRESSn(eChannelId)); 01786 01787 return ADMW_SUCCESS ; 01788 } 01789 01790 static ADMW_RESULT admw_SetDigitalChannelComms( 01791 ADMW_DEVICE_HANDLE hDevice, 01792 ADMW1001_CH_ID eChannelId, 01793 ADMW1001_DIGITAL_SENSOR_COMMS *pDigitalComms) 01794 { 01795 ADMW_CORE_Digital_Sensor_Comms_t digitalSensorComms; 01796 01797 digitalSensorComms.VALUE16 = REG_RESET_VAL(CORE_DIGITAL_SENSOR_COMMSn); 01798 01799 if(pDigitalComms->useCustomCommsConfig ) { 01800 digitalSensorComms.Digital_Sensor_Comms_En = 1; 01801 01802 if(pDigitalComms->i2cClockSpeed == ADMW1001_DIGITAL_SENSOR_COMMS_I2C_CLOCK_SPEED_100K ) { 01803 digitalSensorComms.I2C_Clock = CORE_DIGITAL_SENSOR_COMMS_I2C_100K; 01804 } else if(pDigitalComms->i2cClockSpeed == ADMW1001_DIGITAL_SENSOR_COMMS_I2C_CLOCK_SPEED_400K ) { 01805 digitalSensorComms.I2C_Clock = CORE_DIGITAL_SENSOR_COMMS_I2C_400K; 01806 } else { 01807 ADMW_LOG_ERROR("Invalid I2C clock speed %d specified", 01808 pDigitalComms->i2cClockSpeed ); 01809 return ADMW_INVALID_PARAM ; 01810 } 01811 01812 if(pDigitalComms->spiMode == ADMW1001_DIGITAL_SENSOR_COMMS_SPI_MODE_0 ) { 01813 digitalSensorComms.SPI_Mode = CORE_DIGITAL_SENSOR_COMMS_SPI_MODE_0; 01814 } else if(pDigitalComms->spiMode == ADMW1001_DIGITAL_SENSOR_COMMS_SPI_MODE_1 ) { 01815 digitalSensorComms.SPI_Mode = CORE_DIGITAL_SENSOR_COMMS_SPI_MODE_1; 01816 } else if(pDigitalComms->spiMode == ADMW1001_DIGITAL_SENSOR_COMMS_SPI_MODE_2 ) { 01817 digitalSensorComms.SPI_Mode = CORE_DIGITAL_SENSOR_COMMS_SPI_MODE_2; 01818 } else if(pDigitalComms->spiMode == ADMW1001_DIGITAL_SENSOR_COMMS_SPI_MODE_3 ) { 01819 digitalSensorComms.SPI_Mode = CORE_DIGITAL_SENSOR_COMMS_SPI_MODE_3; 01820 } else { 01821 ADMW_LOG_ERROR("Invalid SPI mode %d specified", 01822 pDigitalComms->spiMode ); 01823 return ADMW_INVALID_PARAM ; 01824 } 01825 01826 switch (pDigitalComms->spiClock ) { 01827 case ADMW1001_DIGITAL_SENSOR_COMMS_SPI_CLOCK_8MHZ : 01828 digitalSensorComms.SPI_Clock = CORE_DIGITAL_SENSOR_COMMS_SPI_8MHZ; 01829 break; 01830 case ADMW1001_DIGITAL_SENSOR_COMMS_SPI_CLOCK_4MHZ : 01831 digitalSensorComms.SPI_Clock = CORE_DIGITAL_SENSOR_COMMS_SPI_4MHZ; 01832 break; 01833 case ADMW1001_DIGITAL_SENSOR_COMMS_SPI_CLOCK_2MHZ : 01834 digitalSensorComms.SPI_Clock = CORE_DIGITAL_SENSOR_COMMS_SPI_2MHZ; 01835 break; 01836 case ADMW1001_DIGITAL_SENSOR_COMMS_SPI_CLOCK_1MHZ : 01837 digitalSensorComms.SPI_Clock = CORE_DIGITAL_SENSOR_COMMS_SPI_1MHZ; 01838 break; 01839 case ADMW1001_DIGITAL_SENSOR_COMMS_SPI_CLOCK_500KHZ : 01840 digitalSensorComms.SPI_Clock = CORE_DIGITAL_SENSOR_COMMS_SPI_500KHZ; 01841 break; 01842 case ADMW1001_DIGITAL_SENSOR_COMMS_SPI_CLOCK_250KHZ : 01843 digitalSensorComms.SPI_Clock = CORE_DIGITAL_SENSOR_COMMS_SPI_250KHZ; 01844 break; 01845 case ADMW1001_DIGITAL_SENSOR_COMMS_SPI_CLOCK_125KHZ : 01846 digitalSensorComms.SPI_Clock = CORE_DIGITAL_SENSOR_COMMS_SPI_125KHZ; 01847 break; 01848 case ADMW1001_DIGITAL_SENSOR_COMMS_SPI_CLOCK_62P5KHZ : 01849 digitalSensorComms.SPI_Clock = CORE_DIGITAL_SENSOR_COMMS_SPI_62P5KHZ; 01850 break; 01851 case ADMW1001_DIGITAL_SENSOR_COMMS_SPI_CLOCK_31P3KHZ : 01852 digitalSensorComms.SPI_Clock = CORE_DIGITAL_SENSOR_COMMS_SPI_31P3KHZ; 01853 break; 01854 case ADMW1001_DIGITAL_SENSOR_COMMS_SPI_CLOCK_15P6KHZ : 01855 digitalSensorComms.SPI_Clock = CORE_DIGITAL_SENSOR_COMMS_SPI_15P6KHZ; 01856 break; 01857 case ADMW1001_DIGITAL_SENSOR_COMMS_SPI_CLOCK_7P8KHZ : 01858 digitalSensorComms.SPI_Clock = CORE_DIGITAL_SENSOR_COMMS_SPI_7P8KHZ; 01859 break; 01860 case ADMW1001_DIGITAL_SENSOR_COMMS_SPI_CLOCK_3P9KHZ : 01861 digitalSensorComms.SPI_Clock = CORE_DIGITAL_SENSOR_COMMS_SPI_3P9KHZ; 01862 break; 01863 case ADMW1001_DIGITAL_SENSOR_COMMS_SPI_CLOCK_1P9KHZ : 01864 digitalSensorComms.SPI_Clock = CORE_DIGITAL_SENSOR_COMMS_SPI_1P9KHZ; 01865 break; 01866 case ADMW1001_DIGITAL_SENSOR_COMMS_SPI_CLOCK_977HZ : 01867 digitalSensorComms.SPI_Clock = CORE_DIGITAL_SENSOR_COMMS_SPI_977HZ; 01868 break; 01869 case ADMW1001_DIGITAL_SENSOR_COMMS_SPI_CLOCK_488HZ : 01870 digitalSensorComms.SPI_Clock = CORE_DIGITAL_SENSOR_COMMS_SPI_488HZ; 01871 break; 01872 case ADMW1001_DIGITAL_SENSOR_COMMS_SPI_CLOCK_244HZ : 01873 digitalSensorComms.SPI_Clock = CORE_DIGITAL_SENSOR_COMMS_SPI_244HZ; 01874 break; 01875 default: 01876 ADMW_LOG_ERROR("Invalid SPI clock %d specified", 01877 pDigitalComms->spiClock ); 01878 return ADMW_INVALID_PARAM ; 01879 } 01880 } else { 01881 digitalSensorComms.Digital_Sensor_Comms_En = 0; 01882 } 01883 01884 WRITE_REG_U16(hDevice, digitalSensorComms.VALUE16, CORE_DIGITAL_SENSOR_COMMSn(eChannelId)); 01885 01886 return ADMW_SUCCESS ; 01887 } 01888 01889 ADMW_RESULT admw_SetI2cChannelConfig( 01890 ADMW_DEVICE_HANDLE hDevice, 01891 ADMW1001_CH_ID eChannelId, 01892 ADMW1001_CHANNEL_CONFIG *pChannelConfig) 01893 { 01894 ADMW_RESULT eRet; 01895 ADMW1001_I2C_CHANNEL_CONFIG *pI2cChannelConfig = 01896 &pChannelConfig->i2cChannelConfig ; 01897 01898 eRet = admw_SetChannelI2cSensorType(hDevice, eChannelId, 01899 pI2cChannelConfig->sensor ); 01900 if (eRet != ADMW_SUCCESS ) { 01901 ADMW_LOG_ERROR("Failed to set I2C sensor type for channel %d", 01902 eChannelId); 01903 return eRet; 01904 } 01905 01906 eRet = admw_SetChannelI2cSensorAddress(hDevice, eChannelId, 01907 pI2cChannelConfig->deviceAddress ); 01908 if (eRet != ADMW_SUCCESS ) { 01909 ADMW_LOG_ERROR("Failed to set I2C sensor address for channel %d", 01910 eChannelId); 01911 return eRet; 01912 } 01913 01914 eRet = admw_SetChannelDigitalSensorDetails(hDevice, eChannelId, 01915 pChannelConfig); 01916 if (eRet != ADMW_SUCCESS ) { 01917 ADMW_LOG_ERROR("Failed to set I2C sensor details for channel %d", 01918 eChannelId); 01919 return eRet; 01920 } 01921 01922 eRet = admw_SetDigitalSensorFormat(hDevice, eChannelId, 01923 &pI2cChannelConfig->dataFormat ); 01924 if (eRet != ADMW_SUCCESS ) { 01925 ADMW_LOG_ERROR("Failed to set I2C sensor data format for channel %d", 01926 eChannelId); 01927 return eRet; 01928 } 01929 01930 eRet = admw_SetDigitalCalibrationParam(hDevice, eChannelId, 01931 &pI2cChannelConfig->digitalCalibrationParam ); 01932 if (eRet != ADMW_SUCCESS ) { 01933 ADMW_LOG_ERROR("Failed to set I2C digital calibration param for channel %d", 01934 eChannelId); 01935 return eRet; 01936 } 01937 01938 eRet = admw_SetDigitalChannelComms(hDevice, eChannelId, 01939 &pI2cChannelConfig->configureComms ); 01940 if (eRet != ADMW_SUCCESS ) { 01941 ADMW_LOG_ERROR("Failed to set I2C comms for channel %d", 01942 eChannelId); 01943 return eRet; 01944 } 01945 01946 return ADMW_SUCCESS ; 01947 } 01948 01949 static ADMW_RESULT admw_SetChannelSpiSensorType( 01950 ADMW_DEVICE_HANDLE hDevice, 01951 ADMW1001_CH_ID eChannelId, 01952 ADMW1001_SPI_SENSOR_TYPE sensorType) 01953 { 01954 ADMW_CORE_Sensor_Type_t sensorTypeReg; 01955 01956 sensorTypeReg.VALUE16 = REG_RESET_VAL(CORE_SENSOR_TYPEn); 01957 01958 /* Ensure that the sensor type is valid for this channel */ 01959 switch(sensorType) { 01960 case ADMW1001_SPI_SENSOR_PRESSURE_A : 01961 case ADMW1001_SPI_SENSOR_ACCELEROMETER_A : 01962 case ADMW1001_SPI_SENSOR_ACCELEROMETER_B : 01963 01964 sensorTypeReg.Sensor_Type = sensorType; 01965 break; 01966 default: 01967 ADMW_LOG_ERROR("Unsupported SPI sensor type %d specified", sensorType); 01968 return ADMW_INVALID_PARAM ; 01969 } 01970 01971 WRITE_REG_U16(hDevice, sensorTypeReg.VALUE16, CORE_SENSOR_TYPEn(eChannelId)); 01972 01973 return ADMW_SUCCESS ; 01974 } 01975 01976 ADMW_RESULT admw_SetSpiChannelConfig( 01977 ADMW_DEVICE_HANDLE hDevice, 01978 ADMW1001_CH_ID eChannelId, 01979 ADMW1001_CHANNEL_CONFIG *pChannelConfig) 01980 { 01981 ADMW_RESULT eRet; 01982 ADMW1001_SPI_CHANNEL_CONFIG *pSpiChannelConfig = 01983 &pChannelConfig->spiChannelConfig ; 01984 01985 eRet = admw_SetChannelSpiSensorType(hDevice, eChannelId, 01986 pSpiChannelConfig->sensor ); 01987 if (eRet != ADMW_SUCCESS ) { 01988 ADMW_LOG_ERROR("Failed to set SPI sensor type for channel %d", 01989 eChannelId); 01990 return eRet; 01991 } 01992 01993 eRet = admw_SetChannelDigitalSensorDetails(hDevice, eChannelId, 01994 pChannelConfig); 01995 if (eRet != ADMW_SUCCESS ) { 01996 ADMW_LOG_ERROR("Failed to set SPI sensor details for channel %d", 01997 eChannelId); 01998 return eRet; 01999 } 02000 02001 eRet = admw_SetDigitalSensorFormat(hDevice, eChannelId, 02002 &pSpiChannelConfig->dataFormat ); 02003 if (eRet != ADMW_SUCCESS ) { 02004 ADMW_LOG_ERROR("Failed to set SPI sensor data format for channel %d", 02005 eChannelId); 02006 return eRet; 02007 } 02008 02009 eRet = admw_SetDigitalCalibrationParam(hDevice, eChannelId, 02010 &pSpiChannelConfig->digitalCalibrationParam ); 02011 if (eRet != ADMW_SUCCESS ) { 02012 ADMW_LOG_ERROR("Failed to set SPI digital calibration param for channel %d", 02013 eChannelId); 02014 return eRet; 02015 } 02016 02017 eRet = admw_SetDigitalChannelComms(hDevice, eChannelId, 02018 &pSpiChannelConfig->configureComms ); 02019 if (eRet != ADMW_SUCCESS ) { 02020 ADMW_LOG_ERROR("Failed to set SPI comms for channel %d", 02021 eChannelId); 02022 return eRet; 02023 } 02024 02025 return ADMW_SUCCESS ; 02026 } 02027 02028 ADMW_RESULT admw1001_SetChannelThresholdLimits( 02029 ADMW_DEVICE_HANDLE hDevice, 02030 ADMW1001_CH_ID eChannelId, 02031 float32_t fHighThresholdLimit, 02032 float32_t fLowThresholdLimit) 02033 { 02034 /* 02035 * If the low/high limits are *both* set to 0 in memory, or NaNs, assume 02036 * that they are unset, or not required, and use infinity defaults instead 02037 */ 02038 if (fHighThresholdLimit == 0.0f && fLowThresholdLimit == 0.0f) { 02039 fHighThresholdLimit = INFINITY; 02040 fLowThresholdLimit = -INFINITY; 02041 } else { 02042 if (isnan(fHighThresholdLimit)) 02043 fHighThresholdLimit = INFINITY; 02044 if (isnan(fLowThresholdLimit)) 02045 fLowThresholdLimit = -INFINITY; 02046 } 02047 02048 WRITE_REG_FLOAT(hDevice, fHighThresholdLimit, 02049 CORE_HIGH_THRESHOLD_LIMITn(eChannelId)); 02050 WRITE_REG_FLOAT(hDevice, fLowThresholdLimit, 02051 CORE_LOW_THRESHOLD_LIMITn(eChannelId)); 02052 02053 return ADMW_SUCCESS ; 02054 } 02055 02056 ADMW_RESULT admw1001_SetOffsetGain( 02057 ADMW_DEVICE_HANDLE hDevice, 02058 ADMW1001_CH_ID eChannelId, 02059 float32_t fOffsetAdjustment, 02060 float32_t fGainAdjustment) 02061 { 02062 /* Replace with default values if NaNs are specified (or 0.0 for gain) */ 02063 if (isnan(fGainAdjustment) || (fGainAdjustment == 0.0f)) 02064 fGainAdjustment = 1.0f; 02065 if (isnan(fOffsetAdjustment)) 02066 fOffsetAdjustment = 0.0f; 02067 02068 WRITE_REG_FLOAT(hDevice, fGainAdjustment, CORE_SENSOR_GAINn(eChannelId)); 02069 WRITE_REG_FLOAT(hDevice, fOffsetAdjustment, CORE_SENSOR_OFFSETn(eChannelId)); 02070 02071 return ADMW_SUCCESS ; 02072 } 02073 02074 ADMW_RESULT admw1001_SetSensorParameter( 02075 ADMW_DEVICE_HANDLE hDevice, 02076 ADMW1001_CH_ID eChannelId, 02077 float32_t fSensorParam) 02078 { 02079 if (fSensorParam == 0.0f) 02080 fSensorParam = NAN; 02081 02082 //WRITE_REG_FLOAT(hDevice, fSensorParam, CORE_SENSOR_PARAMETERn(eChannelId)); 02083 02084 return ADMW_SUCCESS ; 02085 } 02086 02087 ADMW_RESULT admw1001_SetChannelSettlingTime( 02088 ADMW_DEVICE_HANDLE hDevice, 02089 ADMW1001_CH_ID eChannelId, 02090 uint32_t nSettlingTime) 02091 { 02092 ADMW_CORE_Settling_Time_t settlingTimeReg; 02093 02094 if (nSettlingTime < (1 << 12)) { 02095 settlingTimeReg.Settling_Time_Units = CORE_SETTLING_TIME_MICROSECONDS; 02096 } else if (nSettlingTime < (1000 * (1 << 12))) { 02097 settlingTimeReg.Settling_Time_Units = CORE_SETTLING_TIME_MILLISECONDS; 02098 nSettlingTime /= 1000; 02099 } else { 02100 settlingTimeReg.Settling_Time_Units = CORE_SETTLING_TIME_SECONDS; 02101 nSettlingTime /= 1000000; 02102 } 02103 02104 CHECK_REG_FIELD_VAL(CORE_SETTLING_TIME_SETTLING_TIME, nSettlingTime); 02105 settlingTimeReg.Settling_Time = nSettlingTime; 02106 02107 WRITE_REG_U16(hDevice, settlingTimeReg.VALUE16, CORE_SETTLING_TIMEn(eChannelId)); 02108 02109 return ADMW_SUCCESS ; 02110 } 02111 02112 ADMW_RESULT admw1001_SetChannelConfig( 02113 ADMW_DEVICE_HANDLE hDevice, 02114 ADMW1001_CH_ID eChannelId, 02115 ADMW1001_CHANNEL_CONFIG *pChannelConfig) 02116 { 02117 ADMW_RESULT eRet; 02118 02119 if (! ADMW1001_CHANNEL_IS_VIRTUAL(eChannelId)) { 02120 eRet = admw1001_SetChannelCount(hDevice, eChannelId, 02121 pChannelConfig->enableChannel ? 02122 pChannelConfig->measurementsPerCycle : 0); 02123 if (eRet != ADMW_SUCCESS ) { 02124 ADMW_LOG_ERROR("Failed to set measurement count for channel %d", 02125 eChannelId); 02126 return eRet; 02127 } 02128 02129 eRet = admw1001_SetChannelOptions(hDevice, eChannelId, 02130 pChannelConfig->priority ); 02131 if (eRet != ADMW_SUCCESS ) { 02132 ADMW_LOG_ERROR("Failed to set priority for channel %d", 02133 eChannelId); 02134 return eRet; 02135 } 02136 02137 /* If the channel is not enabled, we can skip the following steps */ 02138 if (pChannelConfig->enableChannel ) { 02139 eRet = admw1001_SetChannelSkipCount(hDevice, eChannelId, 02140 pChannelConfig->cycleSkipCount ); 02141 if (eRet != ADMW_SUCCESS ) { 02142 ADMW_LOG_ERROR("Failed to set cycle skip count for channel %d", 02143 eChannelId); 02144 return eRet; 02145 } 02146 02147 switch (eChannelId) { 02148 case ADMW1001_CH_ID_ANLG_1_UNIVERSAL : 02149 case ADMW1001_CH_ID_ANLG_2_UNIVERSAL : 02150 case ADMW1001_CH_ID_ANLG_1_DIFFERENTIAL : 02151 case ADMW1001_CH_ID_ANLG_2_DIFFERENTIAL : 02152 eRet = admw_SetAdcChannelConfig(hDevice, eChannelId, pChannelConfig); 02153 break; 02154 case ADMW1001_CH_ID_DIG_I2C_0 : 02155 case ADMW1001_CH_ID_DIG_I2C_1 : 02156 eRet = admw_SetI2cChannelConfig(hDevice, eChannelId, pChannelConfig); 02157 break; 02158 case ADMW1001_CH_ID_DIG_SPI_0 : 02159 eRet = admw_SetSpiChannelConfig(hDevice, eChannelId, pChannelConfig); 02160 break; 02161 default: 02162 ADMW_LOG_ERROR("Invalid channel ID %d specified", eChannelId); 02163 eRet = ADMW_INVALID_PARAM ; 02164 #if 0 02165 /* when using i2c sensors there is an error ( dataformat->length=0) 02166 the code below catches this error and this causes further problems.*/ 02167 break; 02168 } 02169 if (eRet != ADMW_SUCCESS ) { 02170 ADMW_LOG_ERROR("Failed to set config for channel %d", 02171 eChannelId); 02172 return eRet; 02173 #endif 02174 } 02175 02176 eRet = admw1001_SetChannelSettlingTime(hDevice, eChannelId, 02177 pChannelConfig->extraSettlingTime ); 02178 if (eRet != ADMW_SUCCESS ) { 02179 ADMW_LOG_ERROR("Failed to set settling time for channel %d", 02180 eChannelId); 02181 return eRet; 02182 } 02183 } 02184 } 02185 02186 if (pChannelConfig->enableChannel ) { 02187 /* Threshold limits can be configured individually for virtual channels */ 02188 eRet = admw1001_SetChannelThresholdLimits(hDevice, eChannelId, 02189 pChannelConfig->highThreshold , 02190 pChannelConfig->lowThreshold ); 02191 if (eRet != ADMW_SUCCESS ) { 02192 ADMW_LOG_ERROR("Failed to set threshold limits for channel %d", 02193 eChannelId); 02194 return eRet; 02195 } 02196 02197 /* Offset and gain can be configured individually for virtual channels */ 02198 eRet = admw1001_SetOffsetGain(hDevice, eChannelId, 02199 pChannelConfig->offsetAdjustment , 02200 pChannelConfig->gainAdjustment ); 02201 if (eRet != ADMW_SUCCESS ) { 02202 ADMW_LOG_ERROR("Failed to set offset/gain for channel %d", 02203 eChannelId); 02204 return eRet; 02205 } 02206 02207 /* Set sensor specific parameter */ 02208 eRet = admw1001_SetSensorParameter(hDevice, eChannelId, 02209 pChannelConfig->sensorParameter ); 02210 if (eRet != ADMW_SUCCESS ) { 02211 ADMW_LOG_ERROR("Failed to set sensor parameter for channel %d", 02212 eChannelId); 02213 return eRet; 02214 } 02215 } 02216 02217 return ADMW_SUCCESS ; 02218 } 02219 02220 ADMW_RESULT admw_SetConfig( 02221 ADMW_DEVICE_HANDLE const hDevice, 02222 ADMW_CONFIG * const pConfig) 02223 { 02224 ADMW1001_CONFIG *pDeviceConfig; 02225 ADMW_PRODUCT_ID productId; 02226 ADMW_RESULT eRet; 02227 02228 if (pConfig->productId != ADMW_PRODUCT_ID_ADMW1001 ) { 02229 ADMW_LOG_ERROR("Configuration Product ID (0x%X) is not supported (0x%0X)", 02230 pConfig->productId , ADMW_PRODUCT_ID_ADMW1001 ); 02231 return ADMW_INVALID_PARAM ; 02232 } 02233 02234 if (!((pConfig->versionId .major ==VERSIONID_MAJOR) && 02235 (pConfig->versionId .minor ==VERSIONID_MINOR))) { 02236 ADMW_LOG_ERROR("Configuration Version ID (0x%X) is not supported", 02237 pConfig->versionId ); 02238 return ADMW_INVALID_PARAM ; 02239 } 02240 02241 02242 /* Check that the actual Product ID is a match? */ 02243 eRet = admw_GetProductID(hDevice, &productId); 02244 if (eRet) { 02245 ADMW_LOG_ERROR("Failed to read device Product ID register"); 02246 return eRet; 02247 } 02248 if (pConfig->productId != productId) { 02249 ADMW_LOG_ERROR("Configuration Product ID (0x%X) does not match device (0x%0X)", 02250 pConfig->productId , productId); 02251 return ADMW_INVALID_PARAM ; 02252 } 02253 02254 pDeviceConfig = &pConfig->admw1001 ; 02255 02256 eRet = admw1001_SetPowerConfig(hDevice, &pDeviceConfig->power ); 02257 if (eRet) { 02258 ADMW_LOG_ERROR("Failed to set power configuration"); 02259 return eRet; 02260 } 02261 02262 eRet = admw1001_SetMeasurementConfig(hDevice, &pDeviceConfig->measurement ); 02263 if (eRet) { 02264 ADMW_LOG_ERROR("Failed to set measurement configuration"); 02265 return eRet; 02266 } 02267 02268 eRet = admw1001_SetDiagnosticsConfig(hDevice, &pDeviceConfig->diagnostics ); 02269 if (eRet) 02270 { 02271 ADMW_LOG_ERROR("Failed to set diagnostics configuration"); 02272 return eRet; 02273 } 02274 02275 for (ADMW1001_CH_ID id = ADMW1001_CH_ID_ANLG_1_UNIVERSAL ; 02276 id < ADMW1001_MAX_CHANNELS ; 02277 id++) { 02278 eRet = admw1001_SetChannelConfig(hDevice, id, 02279 &pDeviceConfig->channels [id]); 02280 if (eRet) { 02281 ADMW_LOG_ERROR("Failed to set channel %d configuration", id); 02282 return eRet; 02283 } 02284 } 02285 02286 return ADMW_SUCCESS ; 02287 } 02288 02289 ADMW_RESULT admw1001_SetLutData( 02290 ADMW_DEVICE_HANDLE const hDevice, 02291 ADMW1001_LUT * const pLutData) 02292 { 02293 ADMW1001_LUT_HEADER *pLutHeader = &pLutData->header; 02294 ADMW1001_LUT_TABLE *pLutTable = pLutData->tables; 02295 unsigned actualLength = 0; 02296 02297 if (pLutData->header.signature != ADMW_LUT_SIGNATURE) { 02298 ADMW_LOG_ERROR("LUT signature incorrect (expected 0x%X, actual 0x%X)", 02299 ADMW_LUT_SIGNATURE, pLutHeader->signature); 02300 return ADMW_INVALID_SIGNATURE ; 02301 } 02302 02303 for (unsigned i = 0; i < pLutHeader->numTables; i++) { 02304 ADMW1001_LUT_DESCRIPTOR *pDesc = &pLutTable->descriptor; 02305 ADMW1001_LUT_TABLE_DATA *pData = &pLutTable->data; 02306 unsigned short calculatedCrc; 02307 02308 switch (pDesc->geometry) { 02309 case ADMW1001_LUT_GEOMETRY_COEFFS: 02310 switch (pDesc->equation) { 02311 case ADMW1001_LUT_EQUATION_POLYN: 02312 case ADMW1001_LUT_EQUATION_POLYNEXP: 02313 case ADMW1001_LUT_EQUATION_QUADRATIC: 02314 case ADMW1001_LUT_EQUATION_STEINHART: 02315 case ADMW1001_LUT_EQUATION_LOGARITHMIC: 02316 case ADMW1001_LUT_EQUATION_BIVARIATE_POLYN: 02317 break; 02318 default: 02319 ADMW_LOG_ERROR("Invalid equation %u specified for LUT table %u", 02320 pDesc->equation, i); 02321 return ADMW_INVALID_PARAM ; 02322 } 02323 break; 02324 case ADMW1001_LUT_GEOMETRY_NES_1D: 02325 case ADMW1001_LUT_GEOMETRY_NES_2D: 02326 case ADMW1001_LUT_GEOMETRY_ES_1D: 02327 case ADMW1001_LUT_GEOMETRY_ES_2D: 02328 if (pDesc->equation != ADMW1001_LUT_EQUATION_LUT) { 02329 ADMW_LOG_ERROR("Invalid equation %u specified for LUT table %u", 02330 pDesc->equation, i); 02331 return ADMW_INVALID_PARAM ; 02332 } 02333 break; 02334 default: 02335 ADMW_LOG_ERROR("Invalid geometry %u specified for LUT table %u", 02336 pDesc->geometry, i); 02337 return ADMW_INVALID_PARAM ; 02338 } 02339 02340 switch (pDesc->dataType) { 02341 case ADMW1001_LUT_DATA_TYPE_FLOAT32: 02342 case ADMW1001_LUT_DATA_TYPE_FLOAT64: 02343 break; 02344 default: 02345 ADMW_LOG_ERROR("Invalid vector format %u specified for LUT table %u", 02346 pDesc->dataType, i); 02347 return ADMW_INVALID_PARAM ; 02348 } 02349 02350 calculatedCrc = admw_crc16_ccitt(pData, pDesc->length); 02351 if (calculatedCrc != pDesc->crc16) { 02352 ADMW_LOG_ERROR("CRC validation failed on LUT table %u (expected 0x%04X, actual 0x%04X)", 02353 i, pDesc->crc16, calculatedCrc); 02354 return ADMW_CRC_ERROR ; 02355 } 02356 02357 actualLength += sizeof(*pDesc) + pDesc->length; 02358 02359 /* Move to the next look-up table */ 02360 pLutTable = (ADMW1001_LUT_TABLE *)((uint8_t *)pLutTable + sizeof(*pDesc) + pDesc->length); 02361 } 02362 02363 if (actualLength != pLutHeader->totalLength) { 02364 ADMW_LOG_ERROR("LUT table length mismatch (expected %u, actual %u)", 02365 pLutHeader->totalLength, actualLength); 02366 return ADMW_WRONG_SIZE ; 02367 } 02368 02369 if (sizeof(*pLutHeader) + pLutHeader->totalLength > ADMW_LUT_MAX_SIZE) { 02370 ADMW_LOG_ERROR("Maximum LUT table length (%u bytes) exceeded", 02371 ADMW_LUT_MAX_SIZE); 02372 return ADMW_WRONG_SIZE ; 02373 } 02374 02375 /* Write the LUT data to the device */ 02376 unsigned lutSize = sizeof(*pLutHeader) + pLutHeader->totalLength; 02377 WRITE_REG_U16(hDevice, 0, CORE_LUT_OFFSET); 02378 WRITE_REG_U8_ARRAY(hDevice, (uint8_t *)pLutData, lutSize, CORE_LUT_DATA); 02379 02380 return ADMW_SUCCESS ; 02381 } 02382 02383 ADMW_RESULT admw1001_SetLutDataRaw( 02384 ADMW_DEVICE_HANDLE const hDevice, 02385 ADMW1001_LUT_RAW * const pLutData) 02386 { 02387 return admw1001_SetLutData(hDevice, 02388 (ADMW1001_LUT *)pLutData); 02389 } 02390 02391 static ADMW_RESULT getLutTableSize( 02392 ADMW1001_LUT_DESCRIPTOR * const pDesc, 02393 ADMW1001_LUT_TABLE_DATA * const pData, 02394 unsigned *pLength) 02395 { 02396 switch (pDesc->geometry) { 02397 case ADMW1001_LUT_GEOMETRY_COEFFS: 02398 if (pDesc->equation == ADMW1001_LUT_EQUATION_BIVARIATE_POLYN) 02399 *pLength = ADMW1001_LUT_2D_POLYN_COEFF_LIST_SIZE(pData->coeffList2d); 02400 else 02401 *pLength = ADMW1001_LUT_COEFF_LIST_SIZE(pData->coeffList); 02402 break; 02403 case ADMW1001_LUT_GEOMETRY_NES_1D: 02404 *pLength = ADMW1001_LUT_1D_NES_SIZE(pData->lut1dNes); 02405 break; 02406 case ADMW1001_LUT_GEOMETRY_NES_2D: 02407 *pLength = ADMW1001_LUT_2D_NES_SIZE(pData->lut2dNes); 02408 break; 02409 case ADMW1001_LUT_GEOMETRY_ES_1D: 02410 *pLength = ADMW1001_LUT_1D_ES_SIZE(pData->lut1dEs); 02411 break; 02412 case ADMW1001_LUT_GEOMETRY_ES_2D: 02413 *pLength = ADMW1001_LUT_2D_ES_SIZE(pData->lut2dEs); 02414 break; 02415 default: 02416 ADMW_LOG_ERROR("Invalid LUT table geometry %d specified\r\n", 02417 pDesc->geometry); 02418 return ADMW_INVALID_PARAM ; 02419 } 02420 02421 return ADMW_SUCCESS ; 02422 } 02423 02424 ADMW_RESULT admw1001_AssembleLutData( 02425 ADMW1001_LUT * pLutBuffer, 02426 unsigned nLutBufferSize, 02427 unsigned const nNumTables, 02428 ADMW1001_LUT_DESCRIPTOR * const ppDesc[], 02429 ADMW1001_LUT_TABLE_DATA * const ppData[]) 02430 { 02431 ADMW1001_LUT_HEADER *pHdr = &pLutBuffer->header; 02432 uint8_t *pLutTableData = (uint8_t *)pLutBuffer + sizeof(*pHdr); 02433 02434 if (sizeof(*pHdr) > nLutBufferSize) { 02435 ADMW_LOG_ERROR("Insufficient LUT buffer size provided"); 02436 return ADMW_INVALID_PARAM ; 02437 } 02438 02439 /* First initialise the top-level header */ 02440 pHdr->signature = ADMW_LUT_SIGNATURE; 02441 pHdr->version.major = 1; 02442 pHdr->version.minor = 0; 02443 pHdr->numTables = 0; 02444 pHdr->totalLength = 0; 02445 02446 /* 02447 * Walk through the list of table pointers provided, appending the table 02448 * descriptor+data from each one to the provided LUT buffer 02449 */ 02450 for (unsigned i = 0; i < nNumTables; i++) { 02451 ADMW1001_LUT_DESCRIPTOR * const pDesc = ppDesc[i]; 02452 ADMW1001_LUT_TABLE_DATA * const pData = ppData[i]; 02453 ADMW_RESULT res; 02454 unsigned dataLength = 0; 02455 02456 /* Calculate the length of the table data */ 02457 res = getLutTableSize(pDesc, pData, &dataLength); 02458 if (res != ADMW_SUCCESS ) 02459 return res; 02460 02461 /* Fill in the table descriptor length and CRC fields */ 02462 pDesc->length = dataLength; 02463 pDesc->crc16 = admw_crc16_ccitt(pData, dataLength); 02464 02465 if ((sizeof(*pHdr) + pHdr->totalLength + sizeof(*pDesc) + dataLength) > nLutBufferSize) { 02466 ADMW_LOG_ERROR("Insufficient LUT buffer size provided"); 02467 return ADMW_INVALID_PARAM ; 02468 } 02469 02470 /* Append the table to the LUT buffer (desc + data) */ 02471 memcpy(pLutTableData + pHdr->totalLength, pDesc, sizeof(*pDesc)); 02472 pHdr->totalLength += sizeof(*pDesc); 02473 memcpy(pLutTableData + pHdr->totalLength, pData, dataLength); 02474 pHdr->totalLength += dataLength; 02475 02476 pHdr->numTables++; 02477 } 02478 02479 return ADMW_SUCCESS ; 02480 }
Generated on Tue Jul 12 2022 19:30:04 by
1.7.2