| /** \file vp_api_common.c |
| * vp_api_common.c |
| * |
| * This file contains functions that are common to more than one device type |
| * but not accessible to the user |
| * |
| * Copyright (c) 2011, Microsemi |
| * |
| * $Revision: 9321 $ |
| * $LastChangedDate: 2012-01-05 17:23:13 -0600 (Thu, 05 Jan 2012) $ |
| */ |
| |
| #include "../../api_lib/includes/vp_api_cfg.h" |
| |
| /* INCLUDES */ |
| #include "../../api_lib/includes/vp_api.h" /* Typedefs and function prototypes for API */ |
| #include "../../api_lib/includes/vp_api_int.h" /* Device specific typedefs and function prototypes */ |
| #include "../../arch/uvb/sys_service.h" |
| |
| #include "../../arch/uvb/vp_hal.h" |
| |
| #if defined (VP_CC_880_SERIES) |
| #include "../../api_lib/vp880_api/vp880_api_int.h" |
| #endif |
| |
| static VpProfileType |
| ConvertPrfWizPrfType2ApiType( |
| const VpProfileWizProfileType type); |
| |
| |
| #if (defined(VP_CC_790_SERIES) || defined(VP_CC_880_SERIES) \ |
| || defined(VP_CC_890_SERIES) || defined(VP_CC_580_SERIES)) |
| |
| #undef MPI_CMD_SEARCH |
| #undef MPI_SHORT_FORMAT |
| #define MPI_LONG_FORMAT |
| |
| #if (VP_CC_DEBUG_SELECT & VP_DBG_HAL) |
| #if defined(MPI_CMD_SEARCH) |
| |
| #define MPI_CMD_TO_FIND (0xD2u) |
| |
| static int16 |
| VpMpiFindCmd( |
| uint8 byteMatch, |
| uint8 mpiCmd, |
| uint8 mpiCmdLen, |
| uint8 *dataBuffer); |
| |
| #endif /* MPI_CMD_SEARCH */ |
| #endif /* (VP_CC_DEBUG_SELECT & VP_DBG_HAL) */ |
| #endif /* (790 | 880 | 890 | 580) */ |
| |
| /** |
| * ConvertPrfWizPrfType2ApiType() |
| * This function converts from Profile Wizard profile type to VP-API specific |
| * profile type. |
| * |
| * Preconditions: |
| * None |
| * |
| * Postconditions: |
| * None |
| */ |
| VpProfileType |
| ConvertPrfWizPrfType2ApiType( |
| const VpProfileWizProfileType type) /* Profile to be converted */ |
| { |
| switch (type) { |
| case VP_PRFWZ_PROFILE_AC: return VP_PROFILE_AC; |
| case VP_PRFWZ_PROFILE_DC: return VP_PROFILE_DC; |
| case VP_PRFWZ_PROFILE_TONE: return VP_PROFILE_TONE; |
| case VP_PRFWZ_PROFILE_TONECAD: return VP_PROFILE_TONECAD; |
| case VP_PRFWZ_PROFILE_RING: return VP_PROFILE_RING; |
| case VP_PRFWZ_PROFILE_CID_TYPE1: return VP_PROFILE_CID; |
| case VP_PRFWZ_PROFILE_CID_TYPE2: return VP_PROFILE_CID; |
| case VP_PRFWZ_PROFILE_METER: return VP_PROFILE_METER; |
| case VP_PRFWZ_PROFILE_RINGCAD: return VP_PROFILE_RINGCAD; |
| case VP_PRFWZ_PROFILE_DEVICE: return VP_PROFILE_DEVICE; |
| case VP_PRFWZ_PROFILE_FXO_CONFIG: return VP_PROFILE_FXO_CONFIG; |
| case VP_PRFWZ_PROFILE_FXS_CTRL: return VP_PROFILE_CUSTOM_TERM; |
| case VP_PRFWZ_PROFILE_CAL: return VP_PROFILE_CAL; |
| default: return VP_NUM_PROFILE_TYPES; |
| } |
| } /* ConvertPrfWizPrfType2ApiType() */ |
| |
| /** |
| * VpGetProfileIndex() |
| * This function returns TRUE if the passed profile pointer is an index or just |
| * a normal pointer. If the passed profile pointer is an index then the index is |
| * also returned. |
| * |
| * Preconditions: |
| * None |
| * |
| * Postconditions: |
| * None |
| */ |
| int |
| VpGetProfileIndex ( |
| const VpProfilePtrType pProfile) /* Given Profile pointer */ |
| { |
| if((pProfile >= VP_PTABLE_INDEX1) && (pProfile <= VP_PTABLE_INDEX15)){ |
| if(pProfile == VP_PTABLE_INDEX1) {return 0;} |
| else if(pProfile == VP_PTABLE_INDEX2) {return 1;} |
| else if(pProfile == VP_PTABLE_INDEX3) {return 2;} |
| else if(pProfile == VP_PTABLE_INDEX4) {return 3;} |
| else if(pProfile == VP_PTABLE_INDEX5) {return 4;} |
| else if(pProfile == VP_PTABLE_INDEX6) {return 5;} |
| else if(pProfile == VP_PTABLE_INDEX7) {return 6;} |
| else if(pProfile == VP_PTABLE_INDEX8) {return 7;} |
| else if(pProfile == VP_PTABLE_INDEX9) {return 8;} |
| else if(pProfile == VP_PTABLE_INDEX10) {return 9;} |
| else if(pProfile == VP_PTABLE_INDEX11) {return 10;} |
| else if(pProfile == VP_PTABLE_INDEX12) {return 11;} |
| else if(pProfile == VP_PTABLE_INDEX13) {return 12;} |
| else if(pProfile == VP_PTABLE_INDEX14) {return 13;} |
| else if(pProfile == VP_PTABLE_INDEX15) {return 14;} |
| } |
| return -1; |
| } /* VpGetProfileIndex() */ |
| |
| /** |
| * VpVerifyProfileType() |
| * This function verifies that the profile pointer passed matches the type of |
| * profile being passed. |
| * |
| * Preconditions: |
| * None |
| * |
| * Postconditions: |
| * Returns TRUE if the profile type and profile match. Otherwise returns |
| * FALSE. Note that a NULL profile is valid and has specific meanings in the |
| * API-II depending on the profile. |
| */ |
| bool |
| VpVerifyProfileType( |
| VpProfileType type, |
| VpProfilePtrType pProfile) |
| { |
| if (pProfile == VP_PTABLE_NULL) { |
| return TRUE; |
| } else if ((pProfile >= VP_PTABLE_INDEX1) |
| && (pProfile <= VP_PTABLE_INDEX15)){ |
| /* This function does not expect to see profile indexes */ |
| return FALSE; |
| } |
| |
| if (ConvertPrfWizPrfType2ApiType((VpProfileWizProfileType)pProfile[VP_PROFILE_TYPE_LSB]) != type) { |
| return FALSE; |
| } else { |
| return TRUE; |
| } |
| } |
| |
| /** |
| * VpIsDigit() |
| * This function returns TRUE if the digit passed is a valid VpDigitType, |
| * otherwise returns FALSE. Utility function for the API-II. |
| */ |
| bool |
| VpIsDigit( |
| VpDigitType digit) |
| { |
| if ((digit >= 0) && (digit <= 9)) { |
| return TRUE; |
| } |
| |
| switch(digit) { |
| case VP_DIG_ZERO: |
| case VP_DIG_ASTER: |
| case VP_DIG_POUND: |
| case VP_DIG_A: |
| case VP_DIG_B: |
| case VP_DIG_C: |
| case VP_DIG_D: |
| case VP_DIG_NONE: |
| return TRUE; |
| default: |
| return FALSE; |
| } |
| } |
| |
| #if defined(VP_CC_880_SERIES) || defined(VP_CC_890_SERIES) |
| VpStatusType |
| VpCSLACSetDTMFGenValues( |
| uint8 *sigGenABParams, |
| VpDigitType digit) |
| { |
| uint8 columnFreqs[] = { |
| 0x0C, 0xE5, /* 1209Hz (1, 4, 7, *) */ |
| 0x0E, 0x40, /* 1336Hz (2, 5, 8, 0) */ |
| 0x0F, 0xC1, /* 1477Hz (3, 6, 9, #) */ |
| 0x11, 0x6B /* 1633Hz (A, B, C, D) */ |
| }; |
| |
| uint8 rowFreqs[] = { |
| 0x07, 0x6F, /* 697Hz (1, 2, 3, A) */ |
| 0x08, 0x36, /* 770Hz (4, 5, 6, B) */ |
| 0x09, 0x16, /* 852Hz (7, 8, 9, C) */ |
| 0x0A, 0x09 /* 941Hz (*, 0, #, D) */ |
| }; |
| |
| /* Set the Column Freqs first */ |
| switch(digit) { |
| case 1: |
| case 4: |
| case 7: |
| case VP_DIG_ASTER: |
| sigGenABParams[0] = columnFreqs[0]; |
| sigGenABParams[1] = columnFreqs[1]; |
| break; |
| |
| case 2: |
| case 5: |
| case 8: |
| case VP_DIG_ZERO: |
| sigGenABParams[0] = columnFreqs[2]; |
| sigGenABParams[1] = columnFreqs[3]; |
| break; |
| |
| case 3: |
| case 6: |
| case 9: |
| case VP_DIG_POUND: |
| sigGenABParams[0] = columnFreqs[4]; |
| sigGenABParams[1] = columnFreqs[5]; |
| break; |
| |
| case VP_DIG_A: |
| case VP_DIG_B: |
| case VP_DIG_C: |
| case VP_DIG_D: |
| sigGenABParams[0] = columnFreqs[6]; |
| sigGenABParams[1] = columnFreqs[7]; |
| break; |
| |
| /* |
| * Digit None will generally be accompanied by EOT. But we need to cover this digit |
| * case anyway (to proceed with this function), and technically speaking the device can |
| * be programmed to generate "No" digit while the generators are enabled. |
| */ |
| case VP_DIG_NONE: |
| sigGenABParams[0] = 0; |
| sigGenABParams[1] = 0; |
| break; |
| |
| default: |
| VP_ERROR(None, NULL, |
| ("Inivalid Digit (0x%02X) passed : VpCSLACSetDTMFGenValues-", digit)); |
| VP_API_FUNC_INT(None, VP_NULL, ("VpCSLACSetDTMFGenValues-")); |
| return VP_STATUS_INVALID_ARG; |
| } |
| |
| /* Now set the row freqs */ |
| switch(digit) { |
| case 1: |
| case 2: |
| case 3: |
| case VP_DIG_A: |
| sigGenABParams[4] = rowFreqs[0]; |
| sigGenABParams[5] = rowFreqs[1]; |
| break; |
| |
| case 4: |
| case 5: |
| case 6: |
| case VP_DIG_B: |
| sigGenABParams[4] = rowFreqs[2]; |
| sigGenABParams[5] = rowFreqs[3]; |
| break; |
| |
| case 7: |
| case 8: |
| case 9: |
| case VP_DIG_C: |
| sigGenABParams[4] = rowFreqs[4]; |
| sigGenABParams[5] = rowFreqs[5]; |
| break; |
| |
| case VP_DIG_ASTER: |
| case VP_DIG_ZERO: |
| case VP_DIG_POUND: |
| case VP_DIG_D: |
| sigGenABParams[4] = rowFreqs[6]; |
| sigGenABParams[5] = rowFreqs[7]; |
| break; |
| |
| /* Digit None - same comments as above */ |
| case VP_DIG_NONE: |
| sigGenABParams[4] = 0; |
| sigGenABParams[5] = 0; |
| break; |
| |
| default: |
| VP_ERROR(None, NULL, |
| ("Inivalid Digit (0x%02X) passed : VpCSLACSetDTMFGenValues-", digit)); |
| VP_API_FUNC_INT(None, VP_NULL, ("VpCSLACSetDTMFGenValues-")); |
| return VP_STATUS_INVALID_ARG; |
| } |
| VP_API_FUNC_INT(None, VP_NULL, ("VpCSLACSetDTMFGenValues-")); |
| return VP_STATUS_SUCCESS; |
| } |
| |
| /**< |
| * VpCSLACHookMaskEnabled() |
| * This function is used by VE880 and VE890 API to determine if any of the line times that |
| * affect hook detect mask are enabled. Return TRUE if hook masking is enabled, FALSE otherwise. |
| */ |
| bool |
| VpCSLACHookMaskEnabled( |
| uint16 fxsTimers[VP_LINE_TIMER_LAST]) |
| { |
| if ((fxsTimers[VP_LINE_RING_EXIT_PROCESS] & VP_ACTIVATE_TIMER) |
| || (fxsTimers[VP_LINE_HOOK_FREEZE] & VP_ACTIVATE_TIMER) |
| || (fxsTimers[VP_LINE_DISCONNECT_EXIT] & VP_ACTIVATE_TIMER) |
| #ifdef VP_CSLAC_RUNTIME_CAL_ENABLED |
| || (fxsTimers[VP_LINE_CAL_LINE_TIMER] & VP_ACTIVATE_TIMER) |
| #endif |
| || (fxsTimers[VP_LINE_TRACKER_DISABLE] & VP_ACTIVATE_TIMER) |
| || (fxsTimers[VP_LINE_GND_START_TIMER] & VP_ACTIVATE_TIMER) |
| #ifdef VP_CSLAC_SEQ_EN |
| || (fxsTimers[VP_LINE_CID_DEBOUNCE] & VP_ACTIVATE_TIMER) |
| #endif /* VP_CSLAC_SEQ_EN */ |
| ) { |
| return TRUE; |
| } |
| return FALSE; |
| } |
| |
| #endif |
| |
| /* Code used for CSLAC & 792 */ |
| #if defined(VP_CC_790_SERIES) || defined(VP_CC_880_SERIES) \ |
| || defined(VP_CC_890_SERIES) || defined(VP_CC_792_SERIES) \ |
| || defined(VP_CC_580_SERIES) |
| |
| |
| /** COMMON INITIALIZATION FUNCTIONS */ |
| /** |
| * VpImplementNonMaskEvents() |
| * This function modifies the line and device event structures with the API |
| * standard non-masking event bits. A non-masked event bit is 0. |
| * |
| * Preconditions: |
| * None |
| * |
| * Postconditions: |
| * The event structures passed are modified by the non-masked event bits. |
| */ |
| void |
| VpImplementNonMaskEvents( |
| VpOptionEventMaskType *pLineEventsMask, /**< Line Events Mask to modify for |
| * non-masking |
| */ |
| VpOptionEventMaskType *pDevEventsMask) /**< Device Events Mask to modify |
| * for non-masking |
| */ |
| { |
| pLineEventsMask->faults &= ~VP_API_NONMASK_FAULT_EVENTS; |
| pLineEventsMask->signaling &= ~VP_API_NONMASK_SIGNALING_EVENTS; |
| pLineEventsMask->response &= ~VP_API_NONMASK_RESPONSE_EVENTS; |
| pLineEventsMask->test &= ~VP_API_NONMASK_TEST_EVENTS; |
| pLineEventsMask->process &= ~VP_API_NONMASK_PROCESS_EVENTS; |
| pLineEventsMask->fxo &= ~VP_API_NONMASK_FXO_EVENTS; |
| pLineEventsMask->packet &= ~VP_API_NONMASK_PACKET_EVENTS; |
| |
| pDevEventsMask->faults &= ~VP_API_NONMASK_FAULT_EVENTS; |
| pDevEventsMask->signaling &= ~VP_API_NONMASK_SIGNALING_EVENTS; |
| pDevEventsMask->response &= ~VP_API_NONMASK_RESPONSE_EVENTS; |
| pDevEventsMask->test &= ~VP_API_NONMASK_TEST_EVENTS; |
| pDevEventsMask->process &= ~VP_API_NONMASK_PROCESS_EVENTS; |
| pDevEventsMask->fxo &= ~VP_API_NONMASK_FXO_EVENTS; |
| pDevEventsMask->packet &= ~VP_API_NONMASK_PACKET_EVENTS; |
| |
| return; |
| } |
| |
| /** |
| * VpImplementDefaultSettings() |
| * This function executes the options to set the device/lines to API-II |
| * standard default settings. It may be passed a valid device context, or a |
| * valid line context. The device and line context do not need to be associated |
| * with each other. This is a convenient function for the API itself to use |
| * when a device or line is initialized. |
| * |
| * Note: This function doesn't set the VP_OPTION_ID_EVENT_MASK option if passed |
| * a Line Context. This is because doing so would affect the device-specific |
| * event masks for all lines on the same device. Therefore, special separate |
| * handling of the VP_OPTION_ID_EVENT_MASK option is required outside this |
| * function when applying line-specific defaults. |
| * |
| * Preconditions: |
| * None |
| * |
| * Postconditions: |
| * The device and line associated with this device is initialized with default |
| * values. |
| */ |
| VpStatusType |
| VpImplementDefaultSettings( |
| VpDevCtxType *pDevCtx, /**< Device to implement for default API-II |
| * options |
| */ |
| VpLineCtxType *pLineCtx) /**< Line to implement for default API-II |
| * options |
| */ |
| { |
| VpStatusType status = VP_STATUS_SUCCESS; |
| |
| VpSetOptionFuncPtrType pSetOption = VP_NULL; |
| VpOptionPulseType pulseSpec; |
| VpOptionLinePulseType linePulseSpec; |
| VpOptionPulseType pulseSpec2; |
| VpOptionCriticalFltType criticalFault; |
| VpOptionZeroCrossType zeroCross; |
| VpOptionPulseModeType pulseMode; |
| VpOptionCodecType codec; |
| VpOptionPcmHwyType pcmHwy; |
| VpOptionLoopbackType loopBack; |
| VpOptionLineStateType lineState; |
| VpOptionRingControlType ringCtrl; |
| VpOptionPcmTxRxCntrlType pcmTxRxCtrl; |
| VpOptionDtmfSpecType dtmfSpec; |
| VpOptionParkModeType parkMode; |
| VpOptionEventMaskType eventMask; |
| uint16 slopeRate = VP_OPTION_DEFAULT_DCFEED_SLOPE; |
| VpOptionPcmSigCtlType pcmSigCtl; |
| VpOptionLinestateCtlModeType linestateCtlMode = VP_OPTION_DEFAULT_LINESTATE_CTL_MODE; |
| VpOptionHookDetectModeType hookDetectMode = VP_OPTION_DEFAULT_HOOK_DETECT_MODE; |
| VpOptionAutoLoopCondType autoLoopCond; |
| |
| if ((pDevCtx == VP_NULL) && (pLineCtx == VP_NULL)) { |
| return VP_STATUS_INVALID_ARG; |
| } |
| |
| if(pDevCtx != VP_NULL) { |
| pSetOption = pDevCtx->funPtrsToApiFuncs.SetOption; |
| } else { |
| pSetOption = pLineCtx->pDevCtx->funPtrsToApiFuncs.SetOption; |
| } |
| |
| if (pSetOption == VP_NULL) { |
| return VP_STATUS_FUNC_NOT_SUPPORTED; |
| } |
| |
| linePulseSpec.breakMin = pulseSpec.breakMin = VP_OPTION_DEFAULT_DP_BREAK_MIN; |
| linePulseSpec.breakMax = pulseSpec.breakMax = VP_OPTION_DEFAULT_DP_BREAK_MAX; |
| linePulseSpec.makeMin = pulseSpec.makeMin = VP_OPTION_DEFAULT_DP_MAKE_MIN; |
| linePulseSpec.makeMax = pulseSpec.makeMax = VP_OPTION_DEFAULT_DP_MAKE_MAX; |
| linePulseSpec.interDigitMin = pulseSpec.interDigitMin = VP_OPTION_DEFAULT_DP_INTER_DIG_MIN; |
| linePulseSpec.flashMin = pulseSpec.flashMin = VP_OPTION_DEFAULT_DP_FLASH_MIN; |
| linePulseSpec.flashMax = pulseSpec.flashMax = VP_OPTION_DEFAULT_DP_FLASH_MAX; |
| linePulseSpec.onHookMin = VP_OPTION_DEFAULT_DP_ON_HOOK_MIN; |
| linePulseSpec.offHookMin = VP_OPTION_DEFAULT_DP_OFF_HOOK_MIN; |
| |
| pulseSpec2.breakMin = VP_OPTION_DEFAULT_DP_BREAK_MIN2; |
| pulseSpec2.breakMax = VP_OPTION_DEFAULT_DP_BREAK_MAX2; |
| pulseSpec2.makeMin = VP_OPTION_DEFAULT_DP_MAKE_MIN2; |
| pulseSpec2.makeMax = VP_OPTION_DEFAULT_DP_MAKE_MAX2; |
| pulseSpec2.interDigitMin = VP_OPTION_DEFAULT_DP_INTER_DIG_MIN2; |
| pulseSpec2.flashMin = VP_OPTION_DEFAULT_DP_FLASH_MIN2; |
| pulseSpec2.flashMax = VP_OPTION_DEFAULT_DP_FLASH_MAX2; |
| |
| #ifdef EXTENDED_FLASH_HOOK |
| pulseSpec.onHookMin = VP_OPTION_DEFAULT_DP_ON_HOOK_MIN; |
| pulseSpec2.onHookMin = VP_OPTION_DEFAULT_DP_ON_HOOK_MIN2; |
| #endif |
| |
| pulseMode = VP_OPTION_DEFAULT_PULSE_MODE; |
| |
| criticalFault.acFltDiscEn = VP_OPTION_DEFAULT_CF_AC_DIS_EN; |
| criticalFault.dcFltDiscEn = VP_OPTION_DEFAULT_CF_DC_DIS_EN; |
| criticalFault.thermFltDiscEn = VP_OPTION_DEFAULT_CF_THERMAL_DIS_EN; |
| |
| zeroCross = VP_OPTION_DEFAULT_ZERO_CROSS; |
| |
| codec = VP_OPTION_DEFAULT_CODEC_MODE; |
| pcmHwy = VP_OPTION_DEFAULT_PCM_HWY; |
| |
| pcmTxRxCtrl = VP_OPTION_DEFAULT_PCM_TXRX_CNTRL; |
| |
| loopBack = VP_OPTION_DEFAULT_LOOP_BACK; |
| lineState.bat = VP_OPTION_DEFAULT_LS_BAT; |
| lineState.battRev = VP_OPTION_DEFAULT_LS_BAT_REV; |
| |
| eventMask.faults = (uint16)VP_OPTION_DEFAULT_FAULT_EVENT_MASK; |
| eventMask.signaling = (uint16)VP_OPTION_DEFAULT_SIGNALING_EVENT_MASK; |
| eventMask.response = (uint16)VP_OPTION_DEFAULT_RESPONSE_EVENT_MASK; |
| eventMask.test = (uint16)VP_OPTION_DEFAULT_TEST_EVENT_MASK; |
| eventMask.process = (uint16)VP_OPTION_DEFAULT_PROCESS_EVENT_MASK; |
| eventMask.fxo = (uint16)VP_OPTION_DEFAULT_FXO_EVENT_MASK; |
| eventMask.packet = (uint16)VP_OPTION_DEFAULT_PACKET_EVENT_MASK; |
| |
| ringCtrl.ringExitDbncDur = VP_OPTION_DEFAULT_RC_RING_EXIT_DBNC_VAL; |
| ringCtrl.ringTripExitSt = VP_OPTION_DEFAULT_RC_RING_EXIT_STATE; |
| ringCtrl.zeroCross = VP_OPTION_DEFAULT_RC_ZERO_CROSS; |
| |
| pcmTxRxCtrl = VP_OPTION_DEFAULT_PCM_TXRX_CNTRL; |
| |
| dtmfSpec = VP_OPTION_DEFAULT_DTMF_SPEC; |
| |
| parkMode.discTime = VP_OPTION_DEFAULT_PARK_MODE_DISC; |
| parkMode.standbyTime = VP_OPTION_DEFAULT_PARK_MODE_STANDBY; |
| |
| pcmSigCtl.enable = VP_OPTION_DEFAULT_PCM_SIG_CTL_ENABLE; |
| pcmSigCtl.ctlTimeslot = VP_OPTION_DEFAULT_PCM_SIG_CTL_CTLTS; |
| pcmSigCtl.sigTimeslot = VP_OPTION_DEFAULT_PCM_SIG_CTL_SIGTS; |
| |
| autoLoopCond.select = VP_OPTION_DEFAULT_AUTO_LOOP_COND_SELECT; |
| autoLoopCond.delay = VP_OPTION_DEFAULT_AUTO_LOOP_COND_DELAY; |
| |
| if (pDevCtx != VP_NULL) { |
| status = pSetOption(VP_NULL, pDevCtx, VP_DEVICE_OPTION_ID_PULSE, |
| &pulseSpec); |
| if (status == VP_STATUS_OPTION_NOT_SUPPORTED) { |
| /* This device only supports VP_OPTION_ID_PULSE. */ |
| status = pSetOption(VP_NULL, pDevCtx, VP_OPTION_ID_PULSE, |
| &linePulseSpec); |
| } |
| if ((status != VP_STATUS_SUCCESS) && |
| (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(VP_NULL, pDevCtx, VP_DEVICE_OPTION_ID_PULSE2, |
| &pulseSpec2); |
| if ((status != VP_STATUS_SUCCESS) && |
| (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| /* |
| * Some devices do not support AC/DC Fault detection, so setting the |
| * critical fault may not be successful. However, all devices (known) |
| * support thermal fault detection, so set that to the default |
| */ |
| status = pSetOption(VP_NULL, pDevCtx, VP_DEVICE_OPTION_ID_CRITICAL_FLT, |
| &criticalFault); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| criticalFault.acFltDiscEn = FALSE; |
| criticalFault.dcFltDiscEn = FALSE; |
| status = pSetOption(VP_NULL, pDevCtx, |
| VP_DEVICE_OPTION_ID_CRITICAL_FLT, &criticalFault); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| } |
| |
| status = pSetOption(VP_NULL, pDevCtx, VP_OPTION_ID_PULSE_MODE, |
| &pulseMode); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(VP_NULL, pDevCtx, VP_OPTION_ID_CODEC, &codec); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(VP_NULL, pDevCtx, VP_OPTION_ID_PCM_HWY, &pcmHwy); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(VP_NULL, pDevCtx, VP_OPTION_ID_LOOPBACK, &loopBack); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(VP_NULL, pDevCtx, VP_OPTION_ID_LINE_STATE, |
| &lineState); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(VP_NULL, pDevCtx, VP_OPTION_ID_EVENT_MASK, |
| &eventMask); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(VP_NULL, pDevCtx, VP_OPTION_ID_RING_CNTRL, |
| &ringCtrl); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(VP_NULL, pDevCtx, VP_OPTION_ID_ZERO_CROSS, |
| &zeroCross); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| |
| status = pSetOption(VP_NULL, pDevCtx, VP_OPTION_ID_PCM_TXRX_CNTRL, |
| &pcmTxRxCtrl); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(VP_NULL, pDevCtx, VP_OPTION_ID_DTMF_SPEC, &dtmfSpec); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(VP_NULL, pDevCtx, VP_DEVICE_OPTION_ID_PARK_MODE, &parkMode); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(VP_NULL, pDevCtx, VP_OPTION_ID_DCFEED_SLOPE, &slopeRate); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(VP_NULL, pDevCtx, VP_DEVICE_OPTION_ID_PCM_SIG_CTL, &pcmSigCtl); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(VP_NULL, pDevCtx, VP_OPTION_ID_LINESTATE_CTL_MODE, &linestateCtlMode); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(VP_NULL, pDevCtx, VP_OPTION_ID_HOOK_DETECT_MODE, &hookDetectMode); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(VP_NULL, pDevCtx, VP_OPTION_ID_AUTO_LOOP_COND, &autoLoopCond); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| } |
| |
| if (pLineCtx != VP_NULL) { |
| /* Init only line level options */ |
| status = pSetOption(pLineCtx, VP_NULL, VP_OPTION_ID_PULSE, &linePulseSpec); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(pLineCtx, VP_NULL, VP_OPTION_ID_PULSE_MODE, |
| &pulseMode); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(pLineCtx, VP_NULL, VP_OPTION_ID_CODEC, &codec); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(pLineCtx, VP_NULL, VP_OPTION_ID_PCM_HWY, &pcmHwy); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(pLineCtx, VP_NULL, VP_OPTION_ID_LOOPBACK, |
| &loopBack); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(pLineCtx, VP_NULL, VP_OPTION_ID_LINE_STATE, |
| &lineState); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(pLineCtx, VP_NULL, VP_OPTION_ID_RING_CNTRL, |
| &ringCtrl); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(pLineCtx, VP_NULL, VP_OPTION_ID_PCM_TXRX_CNTRL, |
| &pcmTxRxCtrl); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(pLineCtx, VP_NULL, VP_OPTION_ID_DTMF_SPEC, &dtmfSpec); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(pLineCtx, VP_NULL, VP_OPTION_ID_DCFEED_SLOPE, &slopeRate); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(pLineCtx, VP_NULL, VP_OPTION_ID_LINESTATE_CTL_MODE, &linestateCtlMode); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(pLineCtx, VP_NULL, VP_OPTION_ID_HOOK_DETECT_MODE, &hookDetectMode); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| |
| status = pSetOption(pLineCtx, VP_NULL, VP_OPTION_ID_AUTO_LOOP_COND, &autoLoopCond); |
| if ((status != VP_STATUS_SUCCESS) && (status != VP_STATUS_OPTION_NOT_SUPPORTED)) { |
| return status; |
| } |
| } |
| |
| return VP_STATUS_SUCCESS; |
| } |
| #endif /* 790 | 880 | 890 | 792 | 580 */ |
| |
| /* Code used for CSLAC only */ |
| #if defined(VP_CC_790_SERIES) || defined(VP_CC_880_SERIES) \ |
| || defined(VP_CC_890_SERIES) || defined(VP_CC_580_SERIES) |
| |
| /******************************************************************************* |
| * VpIsLowPowerTermType() |
| * Return TRUE for any VP-API-II Low Power Termination type passed. |
| * |
| * Preconditions: |
| * |
| * Postconditions: |
| ******************************************************************************/ |
| bool |
| VpIsLowPowerTermType( |
| VpTermType termType) |
| { |
| if ((termType == VP_TERM_FXS_LOW_PWR) || |
| (termType == VP_TERM_FXS_ISOLATE_LP) || |
| (termType == VP_TERM_FXS_SPLITTER_LP)) { |
| return TRUE; |
| } |
| return FALSE; |
| } |
| |
| /******************************************************************************* |
| * VpCSLACClearMPIBuffer() |
| * This function clears the CSLAC MPI Buffer by writing 16 NO-Ops |
| * |
| * Preconditions: |
| * |
| * Postconditions: |
| ******************************************************************************/ |
| #define VP_CSLAC_NO_OP_WRT 0x06 |
| #define VP_CSLAC_EC1 0x01 |
| void |
| VpCSLACClearMPIBuffer( |
| VpDeviceIdType deviceId) |
| { |
| uint8 mpiData[] = { |
| VP_CSLAC_NO_OP_WRT, VP_CSLAC_NO_OP_WRT, VP_CSLAC_NO_OP_WRT, VP_CSLAC_NO_OP_WRT, |
| VP_CSLAC_NO_OP_WRT, VP_CSLAC_NO_OP_WRT, VP_CSLAC_NO_OP_WRT, VP_CSLAC_NO_OP_WRT, |
| VP_CSLAC_NO_OP_WRT, VP_CSLAC_NO_OP_WRT, VP_CSLAC_NO_OP_WRT, VP_CSLAC_NO_OP_WRT, |
| VP_CSLAC_NO_OP_WRT, VP_CSLAC_NO_OP_WRT, VP_CSLAC_NO_OP_WRT, VP_CSLAC_NO_OP_WRT |
| }; |
| |
| /* Perform NO_OPS to clear the MPI buffers */ |
| VpMpiCmdWrapper(deviceId, VP_CSLAC_EC1, VP_CSLAC_NO_OP_WRT, 16, mpiData); |
| } |
| |
| /******************************************************************************* |
| * VpCSLACIsProfileValid() |
| * This function checks the validity of a profile passed into the API via |
| * a pointer or an index. |
| * |
| * Arguments: |
| * tableSize - size of the profile table being checked |
| * profEntry - value of the profile entry being checked |
| * profType - type of profile that is being checked |
| * pProfTable - pointer to profile table pointers profType |
| * pProfileInput - pointer to the profile being checked |
| * pProfileRslt - pointer to the resulting profile |
| * |
| * Preconditions: |
| * |
| * Postconditions: |
| ******************************************************************************/ |
| bool |
| VpCSLACIsProfileValid( |
| VpProfileType profType, |
| int16 tableSize, |
| uint16 profEntry, |
| VpProfilePtrType *pProfTable, |
| VpProfilePtrType pProfileInput, |
| VpProfilePtrType *pProfileRslt) |
| { |
| int profIndex = VpGetProfileIndex(pProfileInput); |
| |
| /* Fail if profile index is beyond legal table size */ |
| if (profIndex >= tableSize) { |
| VP_ERROR(None, VP_NULL, ("IsProfileValid() - profIndex exceeds table size")); |
| return FALSE; |
| } |
| |
| /* Input profile is null, -- NULL is legal */ |
| if (pProfileInput == VP_PTABLE_NULL) { |
| *pProfileRslt = VP_PTABLE_NULL; |
| return TRUE; |
| } |
| |
| if (profIndex < 0) { |
| /* Is the input profile a vaild profile type? */ |
| if ( VpVerifyProfileType(profType, pProfileInput)) { |
| *pProfileRslt = pProfileInput; |
| return TRUE; |
| } |
| } else if (profIndex < tableSize) { |
| /* Does the profile table contain a profile at the requested index? */ |
| if ((profEntry & (0x01 << profIndex))) { |
| *pProfileRslt = pProfTable[profIndex]; |
| return TRUE; |
| } |
| } |
| |
| VP_ERROR(None, VP_NULL, ("IsProfileValid() - invalid profile")); |
| return FALSE; |
| } /* VpCSLACIsProfileValid */ |
| |
| bool |
| VpCSLACSetTimer( |
| uint16 *pTimer, |
| uint16 newValue) |
| { |
| if ((*pTimer & VP_ACTIVATE_TIMER) && ((*pTimer & ~VP_ACTIVATE_TIMER) >= newValue)) { |
| /* Timer is already active and longer than new time. Do nothing. */ |
| return FALSE; |
| } |
| |
| *pTimer = (newValue | VP_ACTIVATE_TIMER); |
| return TRUE; |
| } |
| #endif |
| |
| #if defined(VP_CC_880_SERIES) || defined(VP_CC_890_SERIES) |
| int16 |
| VpConvertToInt16( |
| uint8 *dataPtr) |
| { |
| return (int16)((((uint16)dataPtr[0] << 8) & 0xFF00) | (dataPtr[1] & 0xFF)); |
| } |
| |
| int32 |
| VpConvertToInt32( |
| uint8 *dataPtr) |
| { |
| return (int32)((((uint32)dataPtr[0] << 24) & 0xFF000000) |
| | (((uint32)dataPtr[1] << 16) & 0x00FF0000) |
| | (((uint32)dataPtr[2] << 8) & 0x0000FF00) |
| | ((uint32)dataPtr[3] & 0xFF)); |
| } |
| |
| #if defined (VP880_FXS_SUPPORT) || defined (VP890_FXS_SUPPORT) |
| #ifdef VP_HIGH_GAIN_MODE_SUPPORTED |
| /** |
| * VpCLSACHighGainMode() |
| * This function puts the line into and takes it out of High Gain mode for VE880 and VE890 |
| * devices. It is used to generate Special Howler Tones. |
| * |
| * High Gain mode is done by forcing the Signal Generator to output at Ringing Levels. Since DC |
| * feed does not operate normally in this condition we also have to force Tip/Ring bias (ICR1). |
| * The maximum output level with the coefficients provided here is ~15dBm into 600ohm load (target |
| * is 14.7dBm just to allow for some tolerance while still ensuring < 15dBm max output per UK |
| * Howler Tone Specifications). |
| * |
| * When entering High Gain Mode, this function saves off the cached register values in the line |
| * object for those registers modified in the High Gain Setting procedure. Values that are not |
| * already cached in the line objects are (and must be) read in this function. When exiting High |
| * Gain Mode this function writes back the previously saved values, regardless of whether or not |
| * these same values have been changed in the meantime. THIS MEANS that when exiting High Gain |
| * mode, the very last thing that must have been set on the line is to Enter High Gain Mode. There |
| * can be no other state changes in-between. |
| */ |
| /************************************************************************************************** |
| * IMPORTANT!!!! The device level access required to Enter/Exit High Gain conditions must be 100% |
| * complete when this function returns. This function is called in context of "Set Line State" |
| * function which itself may start state one more more state machine/timer procedures. In case of |
| * parallel procedurs running that affect the same registers/bits, the timer management code will |
| * have to be made much more complex. In the current version of the API, there is no need to delay |
| * Howler configuration (enter or exit) write operations. |
| **************************************************************************************************/ |
| void |
| VpCLSACHighGainMode( |
| VpLineCtxType *pLineCtx, |
| bool highGainMode) |
| { |
| void *pLineObj = pLineCtx->pLineObj; |
| |
| VpDevCtxType *pDevCtx = pLineCtx->pDevCtx; |
| VpDeviceType deviceType = pDevCtx->deviceType; |
| void *pDevObj = pDevCtx->pDevObj; |
| |
| VpDeviceIdType deviceId; |
| uint8 ecVal; |
| |
| /* In case cadencing is not supported, initialize this to a non-Howler Tone value */ |
| uint8 toneType = 0; |
| |
| VpHowlerModeCachedValues *pHowlerModeCache; |
| |
| uint8 mpiIndex = 0; |
| uint8 mpiBuffer[11 + VP_CSLAC_DC_FEED_LEN + VP_CSLAC_ICR1_LEN + VP_CSLAC_ICR4_LEN |
| + VP_CSLAC_ICR2_LEN + VP_CSLAC_ICR3_LEN + VP_CSLAC_VP_GAIN_LEN |
| + VP_CSLAC_GR_LEN + VP_CSLAC_DISN_LEN + VP_CSLAC_R_LEN |
| + VP_CSLAC_OP_FUNC_LEN + VP_CSLAC_SW_REG_LEN]; |
| |
| /* |
| * These are write only. Values in register currently will be overwritten when entering |
| * High Gain Mode |
| */ |
| uint8 dcFeedData[VP_CSLAC_DC_FEED_LEN] = {0x49, 0x16}; |
| uint8 vpGainData[VP_CSLAC_VP_GAIN_LEN] = {0x18}; |
| uint8 disnData[VP_CSLAC_DISN_LEN] = {0x00}; |
| |
| /* |
| * With flat R-Filter coefficients, provides 14.5dBm max signal on the line. Used for UK |
| * BTRN Version 15, NTT, and normal High Gain mode. All other modes when detected will modify |
| * the content of grData |
| */ |
| uint8 grData[VP_CSLAC_GR_LEN] = {0x9F, 0xA1}; |
| |
| /* |
| * UK Draft 960-G has a non-flat Holwer Tone Frequency response. All other types of Howler Tone, |
| * including UK Version 15, is a flat frequency response. |
| * |
| * In case of non-flat response, the loss at 800Hz is 3dB more than the loss at 2500Hz |
| */ |
| #if (VP_UK_HOWLER_IN_USE == VP_UK_HOWLER_BTNR_VER15) |
| /* These set of coefficients with GR = [0x26, 0x32] provides 12dBm signal on the line */ |
| uint8 rValueUk[VP_CSLAC_R_LEN] = {0x7D, 0xD0, 0x01, 0x11, 0x01, 0x90, 0x01, 0x90, 0x01, 0x90, |
| 0x01, 0x90, 0x01, 0x90}; |
| #else |
| /* These set of coefficients with GR = [0x26, 0x32] provides ~14.5dBm signal on the line */ |
| uint8 rValueUk[VP_CSLAC_R_LEN] = {0x2D, 0xC0, 0x22, 0xC0, 0x43, 0x61, 0xBD, 0xA8, 0x3A, 0xA1, |
| 0x43, 0x2A, 0x22, 0x24}; |
| #endif |
| uint8 rValue[VP_CSLAC_R_LEN] = {0x7D, 0xD0, 0x01, 0x11, 0x01, 0x90, 0x01, 0x90, 0x01, 0x90, |
| 0x01, 0x90, 0x01, 0x90}; |
| |
| /* These are read/modify/write */ |
| uint8 icr1Data[VP_CSLAC_ICR1_LEN]; |
| uint8 icr4Data[VP_CSLAC_ICR4_LEN]; |
| uint8 icr2Data[VP_CSLAC_ICR2_LEN]; |
| uint8 icr3Data[VP_CSLAC_ICR3_LEN]; |
| uint8 opFunc[VP_CSLAC_OP_FUNC_LEN]; /* Only to disable Z and B Filters */ |
| uint8 swReg[VP_CSLAC_SW_REG_LEN]; /* Used to set Tracking floor voltage to -30V */ |
| |
| bool isAbs = FALSE; |
| bool rFilterChangeOnly = FALSE; |
| |
| /* |
| * Hopefully, these names and comments provide enough description as to what |
| * this function is trying to accomplish at the register level. |
| * See the VoicePort Command Set for more details of these registers and bits. |
| */ |
| #define VP_CSLAC_ICR1_WRT (0xEC) |
| #define VP_CSLAC_ICR1_TIP_BIAS_OVERRIDE (0xF0) |
| #define VP_CSLAC_ICR1_RING_BIAS_OVERRIDE (0x0F) |
| #define VP_CSLAC_ICR1_TIP_BIAS_CTRL_INDEX (0x00) |
| #define VP_CSLAC_ICR1_RING_BIAS_CTRL_INDEX (0x02) |
| #define VP_CSLAC_ICR1_BATTERY_CTRL_INDEX (0x02) |
| #define VP_CSLAC_ICR1_BATTERY_CTRL_MASK (0x30) |
| |
| #define VP_CSLAC_ICR2_WRT (0xEE) |
| #define VP_CSLAC_ICR2_DAC_CTRL_INDEX (0x00) |
| #define VP_CSLAC_ICR2_DAC_RING_LEVELS (0x10) |
| #define VP_CSLAC_ICR2_SPEEDUP_INDEX (0x02) |
| #define VP_CSLAC_ICR2_METALLIC_SPEEDUP (0x80) |
| #define VP_CSLAC_ICR2_RINGING_TC (0x01) |
| |
| #define VP_CSLAC_ICR3_WRT (0xF2) |
| #define VP_CSLAC_ICR3_LINE_CTRL_INDEX (0x00) |
| #define VP_CSLAC_ICR3_25V_LOOP_LIMIT (0x10) |
| #define VP_CSLAC_ICR3_VP_CFG_INDEX (0x02) |
| #define VP_CSLAC_ICR3_DC_FEED_CONNECT (0x02) |
| |
| #define VP_CSLAC_ICR4_WRT (0xF4) |
| #define VP_CSLAC_ICR4_SMALL_SIGNAL_CTRL (0x80) |
| #define VP_CSLAC_ICR4_AISN_CTRL (0x10) |
| |
| #define VP_CSLAC_RD_BIT (0x01) |
| |
| #define VP_CSLAC_DC_FEED_WRT (0xC6) |
| #define VP_CSLAC_DC_FEED_RD (VP_CSLAC_DC_FEED_WRT | VP_CSLAC_RD_BIT) |
| |
| #define VP_CSLAC_VP_GAIN_WRT (0x50) |
| #define VP_CSLAC_VP_GAIN_RD (VP_CSLAC_VP_GAIN_WRT | VP_CSLAC_RD_BIT) |
| |
| #define VP_CSLAC_GR_WRT (0x82) |
| #define VP_CSLAC_GR_RD (VP_CSLAC_GR_WRT | VP_CSLAC_RD_BIT) |
| |
| #define VP_CSLAC_R_WRT (0x8A) |
| #define VP_CSLAC_R_RD (VP_CSLAC_R_WRT | VP_CSLAC_RD_BIT) |
| |
| #define VP_CSLAC_DISN_WRT (0xCA) |
| #define VP_CSLAC_DISN_RD (VP_CSLAC_DISN_WRT | VP_CSLAC_RD_BIT) |
| |
| #define VP_CSLAC_OP_FUNCT_WRT (0x60) |
| #define VP_CSLAC_OP_FUNCT_RD (VP_CSLAC_OP_FUNCT_WRT | VP_CSLAC_RD_BIT) |
| |
| /**< VP_CSLAC_OP_FUNCT_Z_B_DISABLE |
| * Lower 2-bits are used for Z-Filters (0x02) and B-Filters (0x01). When = '0' will disable |
| * these filters. This should be used as 'AND' operation to disable Z/B-Filters. |
| */ |
| #define VP_CSLAC_OP_FUNCT_Z_ENABLE (0x02) |
| #define VP_CSLAC_OP_FUNCT_B_ENABLE (0x01) |
| #define VP_CSLAC_OP_FUNCT_Z_B_ENABLE (VP_CSLAC_OP_FUNCT_Z_ENABLE | VP_CSLAC_OP_FUNCT_B_ENABLE) |
| |
| #define VP_CSLAC_SW_REG_WRT (0xE4) |
| #define VP_CSLAC_SW_REG_RD (VP_CSLAC_SW_REG_WRT | VP_CSLAC_RD_BIT) |
| #define VP_CSLAC_FLOOR_VOLTAGE_MASK 0x1F |
| |
| switch (deviceType) { |
| #if defined (VP_CC_880_SERIES) && defined (VP880_FXS_SUPPORT) |
| case VP_DEV_880_SERIES: |
| deviceId = ((Vp880DeviceObjectType *)pDevObj)->deviceId; |
| ecVal = ((Vp880LineObjectType *)pLineObj)->ecVal; |
| pHowlerModeCache = &((Vp880LineObjectType *)pLineObj)->howlerModeCache; |
| #ifdef VP_CSLAC_SEQ_EN |
| toneType = ((Vp880LineObjectType *)pLineObj)->cadence.toneType; |
| #endif |
| |
| /* Cache the ICR values if entering High Gain mode and not already in High Gain Mode */ |
| if ((highGainMode) && (!(pHowlerModeCache->isInHowlerMode))) { |
| /**************************************************************************** |
| * Register Cache Process >> START * |
| * - Copy directly from the line object what we can. This keeps MPI * |
| * access to a minimum. We'll read from the silicon for those registers * |
| * that are not maintained in the line object. * |
| ****************************************************************************/ |
| VpMemCpy(pHowlerModeCache->icr1Reg, |
| ((Vp880LineObjectType *)pLineObj)->icr1Values, VP_CSLAC_ICR1_LEN); |
| VpMemCpy(pHowlerModeCache->icr2Reg, |
| ((Vp880LineObjectType *)pLineObj)->icr2Values, VP_CSLAC_ICR2_LEN); |
| VpMemCpy(pHowlerModeCache->icr3Reg, |
| ((Vp880LineObjectType *)pLineObj)->icr3Values, VP_CSLAC_ICR3_LEN); |
| VpMemCpy(pHowlerModeCache->icr4Reg, |
| ((Vp880LineObjectType *)pLineObj)->icr4Values, VP_CSLAC_ICR4_LEN); |
| #ifdef VP880_TRACKER_SUPPORT |
| VpMemCpy(pHowlerModeCache->swReg, |
| ((Vp880DeviceObjectType *)pDevObj)->swParamsCache, VP_CSLAC_SW_REG_LEN); |
| #endif |
| } |
| #ifdef VP880_ABS_SUPPORT |
| if (((((Vp880DeviceObjectType *)pDevObj)->stateInt) & VP880_IS_ABS) == VP880_IS_ABS) { |
| isAbs = TRUE; |
| } |
| #endif |
| break; |
| #endif |
| |
| #if defined (VP_CC_890_SERIES) && defined (VP890_FXS_SUPPORT) |
| case VP_DEV_890_SERIES: |
| deviceId = ((Vp890DeviceObjectType *)pDevObj)->deviceId; |
| ecVal = ((Vp890LineObjectType *)pLineObj)->ecVal; |
| pHowlerModeCache = &((Vp890LineObjectType *)pLineObj)->howlerModeCache; |
| #ifdef VP_CSLAC_SEQ_EN |
| toneType = ((Vp890LineObjectType *)pLineObj)->cadence.toneType; |
| #endif |
| |
| /* Cache the ICR values if entering High Gain mode and not already in High Gain Mode */ |
| if ((highGainMode) && (!(pHowlerModeCache->isInHowlerMode))) { |
| /**************************************************************************** |
| * Register Cache Process >> START * |
| * - Copy directly from the line object what we can. This keeps MPI * |
| * access to a minimum. We'll read from the silicon for those registers * |
| * that are not maintained in the line object. * |
| ****************************************************************************/ |
| VpMemCpy(pHowlerModeCache->icr1Reg, |
| ((Vp890LineObjectType *)pLineObj)->icr1Values, VP_CSLAC_ICR1_LEN); |
| VpMemCpy(pHowlerModeCache->icr2Reg, |
| ((Vp890LineObjectType *)pLineObj)->icr2Values, VP_CSLAC_ICR2_LEN); |
| VpMemCpy(pHowlerModeCache->icr3Reg, |
| ((Vp890LineObjectType *)pLineObj)->icr3Values, VP_CSLAC_ICR3_LEN); |
| VpMemCpy(pHowlerModeCache->icr4Reg, |
| ((Vp890LineObjectType *)pLineObj)->icr4Values, VP_CSLAC_ICR4_LEN); |
| VpMemCpy(pHowlerModeCache->swReg, |
| ((Vp890DeviceObjectType *)pDevObj)->swParamsCache, VP_CSLAC_SW_REG_LEN); |
| } |
| break; |
| #endif |
| |
| default: |
| return; |
| } |
| |
| if (highGainMode) { /* Entering High Gain Mode */ |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, ("Entering High Gain State")); |
| |
| /* If not already in High Gain Mode cache content of all registers being modified */ |
| if (!(pHowlerModeCache->isInHowlerMode)) { |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, ("Not Previously in High Gain State")); |
| |
| /* |
| * Set the flag that tells the API the line is in High Gain state. Doing this |
| * prevents incorrectly reading/caching register values used for High Gain mode. |
| */ |
| pHowlerModeCache->isInHowlerMode = TRUE; |
| |
| /**************************************************************************** |
| * Register Cache Process >> CONTINUED * |
| * - Continue from where we left off above. Read/cache the registers that * |
| * are not maintained in the line object. * |
| ****************************************************************************/ |
| VpMpiCmdWrapper(deviceId, ecVal, VP_CSLAC_DC_FEED_RD, VP_CSLAC_DC_FEED_LEN, |
| pHowlerModeCache->dcFeed); |
| |
| VpMpiCmdWrapper(deviceId, ecVal, VP_CSLAC_VP_GAIN_RD, VP_CSLAC_VP_GAIN_LEN, |
| pHowlerModeCache->digitalRxLoss); |
| |
| VpMpiCmdWrapper(deviceId, ecVal, VP_CSLAC_GR_RD, VP_CSLAC_GR_LEN, |
| pHowlerModeCache->grValue); |
| |
| VpMpiCmdWrapper(deviceId, ecVal, VP_CSLAC_DISN_RD, VP_CSLAC_DISN_LEN, |
| pHowlerModeCache->disn); |
| |
| VpMpiCmdWrapper(deviceId, ecVal, VP_CSLAC_R_RD, VP_CSLAC_R_LEN, |
| pHowlerModeCache->rValue); |
| |
| VpMpiCmdWrapper(deviceId, ecVal, VP_CSLAC_OP_FUNCT_RD, VP_CSLAC_OP_FUNC_LEN, |
| pHowlerModeCache->opFunc); |
| /**************************************************************************** |
| * Register Cache Process >> END * |
| * - At this point, all registers that need to be restored when exiting * |
| * High Gain State have been cached. Start configuring for new values * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * High Gain Configuration Process >> START * |
| * - Prepare the stack values with content to write to the silicon to put * |
| * the line in the desired High Gain Mode. * |
| * - All registers except R Filter and GR are set here. The R/GR values * |
| * are treated differently because they are set based on the type of * |
| * Howler Tone (if any) being generated. * |
| ****************************************************************************/ |
| /* Force Tracker Floor Voltage to -30V */ |
| if (!(isAbs)) { |
| VpMemCpy(swReg, pHowlerModeCache->swReg, VP_CSLAC_SW_REG_LEN); |
| swReg[1] &= ~VP_CSLAC_FLOOR_VOLTAGE_MASK; |
| swReg[1] |= 0x05; |
| } |
| |
| /* Force Line Bias control and set bias values. */ |
| VpMemCpy(icr1Data, pHowlerModeCache->icr1Reg, VP_CSLAC_ICR1_LEN); |
| |
| icr1Data[VP_CSLAC_ICR1_TIP_BIAS_CTRL_INDEX] |= VP_CSLAC_ICR1_TIP_BIAS_OVERRIDE; |
| icr1Data[VP_CSLAC_ICR1_TIP_BIAS_CTRL_INDEX+1] &= ~VP_CSLAC_ICR1_TIP_BIAS_OVERRIDE; |
| icr1Data[VP_CSLAC_ICR1_TIP_BIAS_CTRL_INDEX+1] |= 0xC0; |
| |
| icr1Data[VP_CSLAC_ICR1_RING_BIAS_CTRL_INDEX] |= VP_CSLAC_ICR1_RING_BIAS_OVERRIDE; |
| icr1Data[VP_CSLAC_ICR1_RING_BIAS_CTRL_INDEX+1] &= ~VP_CSLAC_ICR1_RING_BIAS_OVERRIDE; |
| icr1Data[VP_CSLAC_ICR1_RING_BIAS_CTRL_INDEX+1] |= 0x0C; |
| |
| /* Force VBL for ABS only. */ |
| if (isAbs) { |
| icr1Data[VP_CSLAC_ICR1_BATTERY_CTRL_INDEX] |= VP_CSLAC_ICR1_BATTERY_CTRL_MASK; |
| icr1Data[VP_CSLAC_ICR1_BATTERY_CTRL_INDEX+1] &= ~VP_CSLAC_ICR1_BATTERY_CTRL_MASK; |
| } |
| |
| /* Enable ringing current limit range */ |
| VpMemCpy(icr2Data, pHowlerModeCache->icr2Reg, VP_CSLAC_ICR2_LEN); |
| icr2Data[VP_CSLAC_ICR2_DAC_CTRL_INDEX] |= VP_CSLAC_ICR2_DAC_RING_LEVELS; |
| icr2Data[VP_CSLAC_ICR2_DAC_CTRL_INDEX+1] |= VP_CSLAC_ICR2_DAC_RING_LEVELS; |
| |
| /* Enable Metallic Speedup and set for Ringing Time Constant */ |
| icr2Data[VP_CSLAC_ICR2_SPEEDUP_INDEX] |= |
| (VP_CSLAC_ICR2_METALLIC_SPEEDUP | VP_CSLAC_ICR2_RINGING_TC); |
| icr2Data[VP_CSLAC_ICR2_SPEEDUP_INDEX+1] |= |
| (VP_CSLAC_ICR2_METALLIC_SPEEDUP | VP_CSLAC_ICR2_RINGING_TC); |
| |
| /* The following steps on ICR3 Enable Signal Generator via DC Feed (Ringing Mode) */ |
| VpMemCpy(icr3Data, pHowlerModeCache->icr3Reg, VP_CSLAC_ICR3_LEN); |
| /* Force Saturation Limit of the Longitudinal loop to -30V */ |
| icr3Data[VP_CSLAC_ICR3_LINE_CTRL_INDEX] |= VP_CSLAC_ICR3_25V_LOOP_LIMIT; |
| icr3Data[VP_CSLAC_ICR3_LINE_CTRL_INDEX+1] &= ~VP_CSLAC_ICR3_25V_LOOP_LIMIT; |
| |
| /* Connect the Voice Path output to the DC Feed Path */ |
| icr3Data[VP_CSLAC_ICR3_VP_CFG_INDEX] |= VP_CSLAC_ICR3_DC_FEED_CONNECT; |
| icr3Data[VP_CSLAC_ICR3_VP_CFG_INDEX+1] |= VP_CSLAC_ICR3_DC_FEED_CONNECT; |
| |
| /* Turn off AISN and Metallic Feed */ |
| VpMemCpy(icr4Data, pHowlerModeCache->icr4Reg, VP_CSLAC_ICR4_LEN); |
| icr4Data[0] |= (VP_CSLAC_ICR4_SMALL_SIGNAL_CTRL | VP_CSLAC_ICR4_AISN_CTRL); |
| icr4Data[1] &= (uint8)(~(VP_CSLAC_ICR4_SMALL_SIGNAL_CTRL | VP_CSLAC_ICR4_AISN_CTRL)); |
| |
| /* |
| * Disable the Z and B Filters. If this isn't done, the AC loop could oscillate and |
| * cause significant Tip/Ring noise to the point of hook detection instability. |
| * |
| * Typecasting is being done only to avoid compiler warnings. Some compilers would |
| * convert a bit-wise inversion of multiple string constants to int which could then |
| * generate a compiler warning. |
| */ |
| opFunc[0] = pHowlerModeCache->opFunc[0]; |
| opFunc[0] &= (uint8)(~VP_CSLAC_OP_FUNCT_Z_B_ENABLE); |
| |
| /* DC Feed is being completely changed. No need to read from the silicon */ |
| /* GR is being completely changed. No need to read from the silicon */ |
| /* R FIlter is being completely changed. No need to read from the silicon */ |
| /* DISN is being completely changed. No need to read from the silicon */ |
| /* Voice Path Gain is being completely changed. No need to read from the silicon */ |
| } else { |
| /* |
| * Already in High Gain Mode. We may only change the Rx Path frequency response |
| * and/or Gain. |
| */ |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, ("Previously in High Gain State")); |
| |
| /* |
| * Set this flag in order to minimize MPI traffic. This condition occurs when the |
| * application calls VpSetLineTone() first (with a special Howler Tone enabled) and |
| * then sets the line to High Gain state. |
| */ |
| rFilterChangeOnly = TRUE; |
| } |
| |
| /**************************************************************************** |
| * High Gain Configuration Process >> CONTINUED * |
| * - Prepare the R/GR values as mentioned above (in >> START comments) * |
| * - If nothing is changed, the total D-A gain is ~14dB and the frequency * |
| * response is flat. This has to change for UK Draft 960-G (non-flat * |
| * frequency response) and AUS (lower D-A gain to ~10dB) * |
| ****************************************************************************/ |
| if (toneType == VP_CSLAC_HOWLER_TONE) { |
| #if (VP_UK_HOWLER_IN_USE == VP_UK_HOWLER_BTNR_DRAFT_G) |
| /* |
| * With sloped R-Filter coefficients, gr has to be adjusted from normal values in |
| * order to compensate for the gain at the high frequencies. The overall level of |
| * gr is reduced by approximately 2.5dB |
| */ |
| grData[0] = 0x26; |
| grData[1] = 0x32; |
| #endif |
| /* UK Frequency Response Specific R-Filter. */ |
| VpMemCpy(rValue, rValueUk, VP_CSLAC_R_LEN); |
| } else if (toneType == VP_CSLAC_AUS_HOWLER_TONE) { |
| /* |
| * With flat R-Filter coefficients the standard gr coefficients provides 14.5dBm on the |
| * line. Australia Howler is nominal +10dBm maximum. So we have to reduce gr by ~4.5dB. |
| */ |
| grData[0] = 0xAB; |
| grData[1] = 0xB2; |
| } else { |
| /* |
| * All other conditions where flat frequency response and 14.5dBm maximum signal on |
| * the line is acceptable. Since the stack variables are initialized with these |
| * settings, there's nothing else to do in most cases. |
| */ |
| } |
| |
| /**************************************************************************** |
| * High Gain Configuration Process >> END * |
| * - At this point the following is TRUE: * |
| * IF (line was not previously in High Gain Mode) * |
| * THEN (all variables on the stack are programmed with desired * |
| * values for putting the line in High Gain Mode) * |
| * ELSE (line was previously in High Gain Mode) * |
| * THEN (only R and GR variables on the stack are programmed with * |
| * desired values for adjusting the current High Gain mode to * |
| * the High Gain mode specified by toneType value in the line * |
| * object cadence member). * |
| * * |
| * NOTE: The cadence memeber exists only in the line object if the API * |
| * is compiled with VP_CSLAC_SEQ_EN set to #define. This function will * |
| * set the default values (if cadence member doesn't exist) to provde * |
| * +14dBm level and flat frequency response. * |
| ****************************************************************************/ |
| } else { /* Exiting High Gain Mode */ |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, ("Exiting High Gain State")); |
| if (!(pHowlerModeCache->isInHowlerMode)) { |
| /* Already out of High Gain Mode (or never entered). Nothing else to do */ |
| return; |
| } |
| /* |
| * Clear the flag that tells the API the line is in High Gain state. Doing this |
| * allows future entrance into High Gain mode to cache and modify all of the |
| * registers needed to implement High Gain mode. |
| */ |
| pHowlerModeCache->isInHowlerMode = FALSE; |
| |
| /**************************************************************************** |
| * Non-High Gain Configuration Process >> START * |
| * - Prepare the stack variables with content from the silicon and line * |
| * object as it was prior to entering High Gain Mode. * |
| * * |
| * NOTE: VpMemCpy() is not used in cases where only one byte is being * |
| * copied. Done purely from an efficiencly perspective, no other reason. * |
| ****************************************************************************/ |
| VpMemCpy(swReg, pHowlerModeCache->swReg, VP_CSLAC_SW_REG_LEN); |
| VpMemCpy(icr1Data, pHowlerModeCache->icr1Reg, VP_CSLAC_ICR1_LEN); |
| VpMemCpy(icr2Data, pHowlerModeCache->icr2Reg, VP_CSLAC_ICR2_LEN); |
| VpMemCpy(icr3Data, pHowlerModeCache->icr3Reg, VP_CSLAC_ICR3_LEN); |
| VpMemCpy(icr4Data, pHowlerModeCache->icr4Reg, VP_CSLAC_ICR4_LEN); |
| VpMemCpy(dcFeedData, pHowlerModeCache->dcFeed, VP_CSLAC_DC_FEED_LEN); |
| vpGainData[0] = pHowlerModeCache->digitalRxLoss[0]; |
| VpMemCpy(grData, pHowlerModeCache->grValue, VP_CSLAC_GR_LEN); |
| VpMemCpy(rValue, pHowlerModeCache->rValue, VP_CSLAC_R_LEN); |
| disnData[0] = pHowlerModeCache->disn[0]; |
| opFunc[0] = pHowlerModeCache->opFunc[0]; |
| } |
| |
| /**************************************************************************** |
| * MPI Buffer Build Process >> START * |
| * - Prepare the MPI Buffer to reconfigure the line. The order should be * |
| * such that the gain at any point in time does not exceed the final * |
| * high gain conditions. This means: * |
| * * |
| * - When entering High Gain Mode, set the filters first in order * |
| * to pre-reduce the D-A gain. * |
| * - When exiting High Gain Mode, set the filters last in order to * |
| * avoid having the line in the high gain conditions with normal * |
| * (higher gain) coefficients. We also don't want to create the * |
| * oscillation scenario where the line is in a non-normal AC * |
| * impedance mode with normal impedance setting coefficients * |
| * enabled. * |
| ****************************************************************************/ |
| /* If Entering High Gain Mode, program the filter coefficients first */ |
| if (highGainMode) { |
| /* Set the supply only if Tracker AND if we were not previously in High Gain Mode */ |
| if((!(isAbs)) && (!(rFilterChangeOnly))) { |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, |
| ("Howler Mode %d: SW Wrt 0x%02X 0x%02X 0x%02X to EC 0x%02X", |
| highGainMode, swReg[0], swReg[1], swReg[2], ecVal)); |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP_CSLAC_SW_REG_WRT, |
| VP_CSLAC_SW_REG_LEN, swReg); |
| } |
| |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, ("Howler Mode %d:GR Wrt 0x%02X 0x%02X to EC 0x%02X", |
| highGainMode, grData[0], grData[1], ecVal)); |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP_CSLAC_GR_WRT, |
| VP_CSLAC_GR_LEN, grData); |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP_CSLAC_R_WRT, |
| VP_CSLAC_R_LEN, rValue); |
| } |
| |
| if (!(rFilterChangeOnly)) { |
| /* If Entering High Gain Mode, continue with filter coefficients first */ |
| if (highGainMode) { |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, |
| ("Howler Mode %d: VP Gain Wrt 0x%02X to EC 0x%02X", |
| highGainMode, vpGainData[0], ecVal)); |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP_CSLAC_VP_GAIN_WRT, |
| VP_CSLAC_VP_GAIN_LEN, vpGainData); |
| |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, |
| ("Howler Mode %d:DISN Wrt 0x%02X to EC 0x%02X", highGainMode, disnData[0], ecVal)); |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP_CSLAC_DISN_WRT, |
| VP_CSLAC_DISN_LEN, disnData); |
| |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP_CSLAC_OP_FUNCT_WRT, |
| VP_CSLAC_OP_FUNC_LEN, opFunc); |
| } |
| |
| /* Fill in the control bits that set the line to High Gain Mode */ |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, |
| ("Howler Mode %d: DC Feed Wrt 0x%02X 0x%02X to EC 0x%02X", |
| highGainMode, dcFeedData[0], dcFeedData[1], ecVal)); |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP_CSLAC_DC_FEED_WRT, |
| VP_CSLAC_DC_FEED_LEN, dcFeedData); |
| |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, |
| ("Howler Mode %d: ICR1 Wrt 0x%02X 0x%02X 0x%02X 0x%02X to EC 0x%02X", |
| highGainMode, icr1Data[0], icr1Data[1], icr1Data[2], icr1Data[3], ecVal)); |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP_CSLAC_ICR1_WRT, |
| VP_CSLAC_ICR1_LEN, icr1Data); |
| |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, |
| ("Howler Mode %d: ICR4 Wrt 0x%02X 0x%02X 0x%02X 0x%02X to EC 0x%02X", |
| highGainMode, icr4Data[0], icr4Data[1], icr4Data[2], icr4Data[3], ecVal)); |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP_CSLAC_ICR4_WRT, |
| VP_CSLAC_ICR4_LEN, icr4Data); |
| |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, |
| ("Howler Mode %d: ICR2 Wrt 0x%02X 0x%02X 0x%02X 0x%02X to EC 0x%02X", |
| highGainMode, icr2Data[0], icr2Data[1], icr2Data[2], icr2Data[3], ecVal)); |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP_CSLAC_ICR2_WRT, |
| VP_CSLAC_ICR2_LEN, icr2Data); |
| |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, |
| ("Howler Mode %d: ICR3 Wrt 0x%02X 0x%02X 0x%02X 0x%02X to EC 0x%02X", |
| highGainMode, icr3Data[0], icr3Data[1], icr3Data[2], icr3Data[3], ecVal)); |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP_CSLAC_ICR3_WRT, |
| VP_CSLAC_ICR3_LEN, icr3Data); |
| |
| /* If Exiting High Gain Mode, filter coefficients are programmed last */ |
| if (!(highGainMode)) { |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, |
| ("Howler Mode %d: VP Gain Wrt 0x%02X to EC 0x%02X", |
| highGainMode, vpGainData[0], ecVal)); |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP_CSLAC_VP_GAIN_WRT, |
| VP_CSLAC_VP_GAIN_LEN, vpGainData); |
| |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, |
| ("Howler Mode %d:DISN Wrt 0x%02X to EC 0x%02X", highGainMode, disnData[0], ecVal)); |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP_CSLAC_DISN_WRT, |
| VP_CSLAC_DISN_LEN, disnData); |
| |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP_CSLAC_OP_FUNCT_WRT, |
| VP_CSLAC_OP_FUNC_LEN, opFunc); |
| } |
| } |
| |
| /* If Exiting High Gain Mode, program the filter coefficients last */ |
| if (!(highGainMode)) { |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, ("Howler Mode %d:GR Wrt 0x%02X 0x%02X to EC 0x%02X", |
| highGainMode, grData[0], grData[1], ecVal)); |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP_CSLAC_GR_WRT, |
| VP_CSLAC_GR_LEN, grData); |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP_CSLAC_R_WRT, |
| VP_CSLAC_R_LEN, rValue); |
| |
| if(!(isAbs)) { |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, |
| ("Howler Mode %d: SW Wrt 0x%02X 0x%02X 0x%02X to EC 0x%02X", |
| highGainMode, swReg[0], swReg[1], swReg[2], ecVal)); |
| mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP_CSLAC_SW_REG_WRT, |
| VP_CSLAC_SW_REG_LEN, swReg); |
| } |
| } |
| /**************************************************************************** |
| * MPI Buffer Build Process >> END * |
| * - The mpiBuffer[] is not configured with the data required to change * |
| * to or from the High Gain mode with specific command order as needed * |
| * Only the MPI write operation is needed. * |
| ****************************************************************************/ |
| VpMpiCmdWrapper(deviceId, ecVal, mpiBuffer[0], mpiIndex-1, &mpiBuffer[1]); |
| return; |
| } |
| |
| /** |
| * VpCSLACHowlerStateMgmt() |
| * This function supports transitions into and out of VP_LINE_HOWLER and VP_LINE_HOWLER_POLREV |
| * line states for the VE880 and VE890 API. It only performs the necessary error checking for the |
| * state the line is currently in prior to entering Howler state, but will modify the device |
| * when exiting Howler state. |
| * |
| * To minimize the complexity of the API, in particular Low Power Mode, this implementation |
| * requires the line to be in a normal off-hook state (VP_LINE_ACTIVE, VP_LINE_TALK, or the PolRev |
| * conditions of those states) prior to entering Howler State. It is too complex and should not |
| * be necessary to support entering Howler state from an on-hook condition/state such as Standby |
| * or Disconnect (since Howler Tones are used to notify a customer of a constant off-hook line). |
| * |
| * When entering Howler State (or Howler PolRev), the calling "Set Line State" function checks |
| * the return value from this function to be sure the transition is legal. If it is, then all other |
| * line register values will be modified first before changing the line to the High Gain Mode. |
| * |
| * When exiting Howler State (or Howler PolRev), the calling "Set Line State" function calls this |
| * function first before setting the line (immediately) to the target state. |
| */ |
| /************************************************************************************************* |
| * IMPORTANT!!!! The operations required to exit Howler conditions must be done immediately. |
| * Adding delay to these operations (i.e., implementing as a state machine managed by timers) can |
| * cause undesireble values being programmed in the device. This is due in large part to the use |
| * of state machines in handling of certain API line state transitions. These state machines keep |
| * line and battery transients to a minimum, but can be negatively affected if parallel timers are |
| * running that affect the same registers. |
| *************************************************************************************************/ |
| VpStatusType |
| VpCSLACHowlerStateMgmt( |
| VpLineCtxType *pLineCtx, |
| VpLineStateType fromState, |
| VpLineStateType toState, |
| VpLineStateType statePriorToHowler) |
| { |
| /* If going to the Howler State, make sure it's from a legal current state */ |
| if ((toState == VP_LINE_HOWLER) || (toState == VP_LINE_HOWLER_POLREV)) { |
| /* |
| * Don't allow repeated calls to Howler State or Howler State PolRev. It complicates |
| * the code because it allows SetLineState to operate with a from/to state that is |
| * both howler (not as designed). Upper level code will allow same state changes |
| * because it then has nothing to do and allows that as success, so this needs to |
| * only catch polarity reversals between howler states and treat it as an illegal |
| * state change. |
| */ |
| switch (fromState) { |
| case VP_LINE_ACTIVE: |
| case VP_LINE_TALK: |
| case VP_LINE_ACTIVE_POLREV: |
| case VP_LINE_TALK_POLREV: |
| break; |
| |
| /* Note in the default case included are VP_LINE_HOWLER and VP_LINE_HOWLER_POLREV */ |
| default: |
| return VP_STATUS_INVALID_ARG; |
| } |
| } else { /* Going to a non-Howler state. This is more restrictive than going to Howler */ |
| /* |
| * If coming from Howler State it must be to the state prior to entering Howler. The "to" |
| * condition for trying to enter from/to any combination of Howler States is taken care of |
| * above. This only needs to verify that if we're in a Howler State already that we're |
| * going back to the state we were in prior to entering Howler state. |
| */ |
| if ((fromState == VP_LINE_HOWLER) || (fromState == VP_LINE_HOWLER_POLREV)) { |
| if (toState != statePriorToHowler) { |
| return VP_STATUS_INVALID_ARG; |
| } |
| VpCLSACHighGainMode(pLineCtx, FALSE); |
| } |
| } |
| return VP_STATUS_SUCCESS; |
| } |
| #endif |
| |
| /** |
| * VpCSLACIsSupportedFxsState() |
| * This function checks to see if the state passed is a supproted FXS state of |
| * the VE880 and VE890 API |
| * |
| * Preconditions: |
| * None. |
| * |
| * Postconditions: |
| * None. |
| */ |
| bool |
| VpCSLACIsSupportedFxsState( |
| VpDeviceType deviceType, |
| VpLineStateType state) |
| { |
| switch (state) { |
| case VP_LINE_STANDBY: |
| case VP_LINE_ACTIVE: |
| case VP_LINE_ACTIVE_POLREV: |
| #ifdef VP_HIGH_GAIN_MODE_SUPPORTED |
| case VP_LINE_HOWLER: |
| case VP_LINE_HOWLER_POLREV: |
| #endif |
| case VP_LINE_TALK: |
| case VP_LINE_TALK_POLREV: |
| case VP_LINE_OHT: |
| case VP_LINE_OHT_POLREV: |
| case VP_LINE_DISCONNECT: |
| case VP_LINE_RINGING: |
| case VP_LINE_RINGING_POLREV: |
| case VP_LINE_STANDBY_POLREV: |
| return TRUE; |
| case VP_LINE_TIP_OPEN: |
| if (deviceType == VP_DEV_890_SERIES) { |
| return FALSE; |
| } else { |
| return TRUE; |
| } |
| default: |
| return FALSE; |
| } |
| } |
| #endif /* defined (VP880_FXS_SUPPORT) || defined (VP890_FXS_SUPPORT) */ |
| |
| /** |
| * VpCSLACSetAbsGain() |
| * |
| * This function implements VP_OPTION_ID_ABS_GAIN for 880 and 890 devices. |
| * |
| * Preconditions: |
| * None |
| * |
| * Postconditions: |
| * None |
| */ |
| #ifdef CSLAC_GAIN_ABS |
| VpStatusType |
| VpCSLACSetAbsGain( |
| VpLineCtxType *pLineCtx, |
| VpOptionAbsGainType *gains) |
| { |
| VpDevCtxType *pDevCtx = pLineCtx->pDevCtx; |
| VpDeviceType deviceType = pDevCtx->deviceType; |
| VpDeviceIdType deviceId; |
| void *pLineObj = pLineCtx->pLineObj; |
| void *pDevObj = pDevCtx->pDevObj; |
| VpStatusType status = VP_STATUS_SUCCESS; |
| |
| uint8 ecVal, gxCmd, grCmd, grCmdLen, gxCmdLen; |
| |
| int16 grMaxGain; |
| int16 grMinGain; |
| |
| int16 gxMaxGain; |
| int16 gxMinGain; |
| |
| int16 *pGxAbsGain, *pGrAbsGain; |
| |
| bool updateGr = FALSE; |
| bool updateGx = FALSE; |
| |
| #define VP_GX_TABLE_SIZE (50) |
| /* This is the quiet value. Overwrite if a non-quiet level is specified. */ |
| uint8 gxValue[] = {0xF8, 0xF8}; |
| |
| uint8 gxGainLookup[VP_GX_TABLE_SIZE] = { |
| /* GX Setting ABS: FXS 880/890-FXO */ |
| /* ---------------------------------- */ |
| 0x01, 0x90, /* -6dB 0dB */ |
| 0xAA, 0xC4, /* -5.5dB 0.5dB */ |
| 0xCA, 0xD3, /* -5dB +1.0dB */ |
| 0x5E, 0xA2, /* -4.5dB +1.5dB */ |
| 0x33, 0x52, /* -4dB +2.0dB */ |
| 0x22, 0xA1, /* -3.5dB +2.5dB */ |
| 0x2A, 0xA1, /* -3dB +3.0dB */ |
| 0x3D, 0xF1, /* -2.5dB +3.5dB */ |
| 0x2A, 0x21, /* -2dB +4.0dB */ |
| 0x32, 0xA0, /* -1.5dB +4.5dB */ |
| 0xBB, 0xA0, /* -1dB +5.0dB */ |
| 0x3C, 0xB0, /* -0.5dB +5.5dB */ |
| 0xA9, 0xF0, /* 0dB +6.0dB */ |
| 0xAB, 0x30, /* +0.5dB +6.5dB */ |
| 0xAC, 0x20, /* +1dB +7.0dB */ |
| 0x5A, 0x10, /* +1.5dB +7.5dB */ |
| 0xA5, 0x10, /* +2dB +8.0dB */ |
| 0x22, 0x10, /* +2.5dB +8.5dB */ |
| 0xAA, 0x00, /* +3dB +9.0dB */ |
| 0xCE, 0x00, /* +3.5dB +9.5dB */ |
| 0x23, 0x00, /* +4dB +10.0dB */ |
| 0xA1, 0x00, /* +4.5dB +10.5dB */ |
| 0x31, 0x00, /* +5dB +11.0dB */ |
| 0xA0, 0x00, /* +5.5dB +11.5dB */ |
| 0xE0, 0x00 /* +6dB +12.0dB */ |
| }; |
| |
| #define VP_GR_TABLE_SIZE (50) |
| /* This is the quiet value. Overwrite if a non-quiet level is specified. */ |
| uint8 grValue[] = {0x8F, 0x87}; |
| |
| uint8 grGainLookup[VP_GR_TABLE_SIZE] = { |
| /* GR Setting ABS: FXS 880/890-FXO */ |
| /* -----------------------------------*/ |
| 0xA9, 0x72, /* -12dB -9dB */ |
| 0xB5, 0x42, /* -11.5dB -8.5dB */ |
| 0x87, 0x32, /* -11dB -8dB */ |
| 0xBA, 0x22, /* -10.5dB -7.5dB */ |
| 0xC4, 0x22, /* -10dB -7dB */ |
| 0x22, 0xA1, /* -9.5dB -6.5dB */ |
| 0x23, 0xA1, /* -9dB -6dB */ |
| 0xBF, 0xA1, /* -8.5dB -5.5dB */ |
| 0xAA, 0xA1, /* -8dB -5dB */ |
| 0x62, 0xB1, /* -7.5dB -4.5dB */ |
| 0x2B, 0xB1, /* -7dB -4dB */ |
| 0x3B, 0xC1, /* -6.5dB -3.5dB */ |
| 0xA8, 0x71, /* -6dB -3dB */ |
| 0xAE, 0x41, /* -5.5dB -2.5dB */ |
| 0x8F, 0x31, /* -5dB -2dB */ |
| 0xCA, 0x21, /* -4.5dB -1.5dB */ |
| 0xA4, 0x21, /* -4dB -1dB */ |
| 0x22, 0xA0, /* -3.5dB -0.5dB */ |
| 0xA2, 0xA0, /* -3dB 0dB */ |
| 0x87, 0xA0, /* -2.5dB +0.5dB */ |
| 0xAA, 0xA0, /* -2dB +1dB */ |
| 0x42, 0xB0, /* -1.5dB +1.5dB */ |
| 0x5B, 0xB0, /* -1dB +2dB */ |
| 0xBB, 0xC0, /* -0.5dB +2.5dB */ |
| 0xA8, 0xF0 /* 0dB +3dB */ |
| }; |
| |
| switch (deviceType) { |
| #ifdef VP_CC_880_SERIES |
| case VP_DEV_880_SERIES: |
| gxCmd = VP880_GX_GAIN_WRT; |
| grCmd = VP880_GR_GAIN_WRT; |
| grCmdLen = VP880_GR_GAIN_LEN; |
| gxCmdLen = VP880_GX_GAIN_LEN; |
| ecVal = ((Vp880LineObjectType *)pLineObj)->ecVal; |
| deviceId = ((Vp880DeviceObjectType *)pDevObj)->deviceId; |
| pGxAbsGain = &((Vp880LineObjectType *)pLineObj)->gain.absGxGain; |
| pGrAbsGain = &((Vp880LineObjectType *)pLineObj)->gain.absGrGain; |
| |
| if (((Vp880LineObjectType *)pLineObj)->status & VP880_IS_FXO) { |
| gxMaxGain = 120; |
| gxMinGain = 0; |
| |
| grMaxGain = 30; |
| grMinGain = -90; |
| } else { |
| gxMaxGain = 60; |
| gxMinGain = -60; |
| |
| grMaxGain = 0; |
| grMinGain = -120; |
| } |
| break; |
| #endif |
| |
| default: |
| return VP_STATUS_INVALID_ARG; |
| } |
| |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, ("AToD: %d - DToA: %d", |
| gains->gain_AToD, gains->gain_DToA)); |
| |
| if (gains->gain_AToD != VP_OPTION_ABS_GAIN_NO_CHANGE) { |
| if (gains->gain_AToD != VP_OPTION_ABS_GAIN_QUIET) { |
| /* Roundoff to nearest 0.5dB step */ |
| int16 tempGain = ABS(gains->gain_AToD); |
| int16 gainRound = tempGain % 5; |
| tempGain += ((gainRound < 3) ? (-gainRound) : (5 - gainRound)); |
| tempGain = ((gains->gain_AToD < 0) ? -tempGain : tempGain); |
| |
| /* Limit the gain to device/line specific ranges */ |
| if (tempGain > gxMaxGain) { |
| tempGain = gxMaxGain; |
| status = VP_STATUS_INPUT_PARAM_OOR; |
| } else if (tempGain < gxMinGain) { |
| status = VP_STATUS_INPUT_PARAM_OOR; |
| tempGain = gxMinGain; |
| } |
| |
| /* Save the actual gain being applied before converting to index */ |
| *pGxAbsGain = tempGain; |
| |
| /* Convert to index */ |
| tempGain = (tempGain - gxMinGain); |
| tempGain = tempGain / 5; |
| |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, ("Final AToD Value: %d", |
| *pGxAbsGain)); |
| |
| gxValue[0] = gxGainLookup[(uint8)tempGain * 2]; |
| gxValue[1] = gxGainLookup[(uint8)tempGain * 2 + 1]; |
| } |
| VpMpiCmdWrapper(deviceId, ecVal, gxCmd, gxCmdLen, gxValue); |
| updateGx = TRUE; |
| } |
| |
| if (gains->gain_DToA != VP_OPTION_ABS_GAIN_NO_CHANGE) { |
| if (gains->gain_DToA != VP_OPTION_ABS_GAIN_QUIET) { |
| /* Roundoff to nearest 0.5dB step */ |
| int16 tempGain = ABS(gains->gain_DToA); |
| int16 gainRound = tempGain % 5; |
| tempGain += ((gainRound < 3) ? (-gainRound) : (5 - gainRound)); |
| tempGain = ((gains->gain_DToA < 0) ? -tempGain : tempGain); |
| |
| /* Limit the gain to device/line specific ranges */ |
| if (tempGain > grMaxGain) { |
| status = VP_STATUS_INPUT_PARAM_OOR; |
| tempGain = grMaxGain; |
| } else if (tempGain < grMinGain) { |
| status = VP_STATUS_INPUT_PARAM_OOR; |
| tempGain = grMinGain; |
| } |
| |
| /* Save the actual gain being applied before converting to index */ |
| *pGrAbsGain = tempGain; |
| |
| /* Convert to index */ |
| tempGain = (tempGain - grMinGain); |
| tempGain = tempGain / 5; |
| |
| VP_LINE_STATE(VpLineCtxType, pLineCtx, ("Final DToA Value: %d", |
| *pGrAbsGain)); |
| |
| grValue[0] = grGainLookup[(uint8)tempGain * 2]; |
| grValue[1] = grGainLookup[(uint8)tempGain * 2 + 1]; |
| } |
| VpMpiCmdWrapper(deviceId, ecVal, grCmd, grCmdLen, grValue); |
| updateGr = TRUE; |
| } |
| |
| #ifdef CSLAC_GAIN_RELATIVE |
| /* Update cached transmit and receive gains for SetRelGain */ |
| switch (deviceType) { |
| #ifdef VP_CC_880_SERIES |
| case VP_DEV_880_SERIES: |
| if (updateGx == TRUE) { |
| ((Vp880LineObjectType *)pLineObj)->gain.gxInt = |
| 0x4000 + VpConvertCsd2Fixed(gxValue); |
| } |
| if (updateGr == TRUE) { |
| ((Vp880LineObjectType *)pLineObj)->gain.grInt = |
| VpConvertCsd2Fixed(grValue); |
| } |
| break; |
| #endif |
| #ifdef VP_CC_890_SERIES |
| case VP_DEV_890_SERIES: |
| if (updateGx == TRUE) { |
| ((Vp890LineObjectType *)pLineObj)->gxBase = |
| 0x4000 + VpConvertCsd2Fixed(gxValue); |
| } |
| if (updateGr == TRUE) { |
| ((Vp890LineObjectType *)pLineObj)->grBase = |
| VpConvertCsd2Fixed(grValue); |
| } |
| break; |
| #endif |
| default: |
| break; |
| } |
| #endif |
| |
| return status; |
| } |
| #endif /* #ifdef CSLAC_GAIN_ABS */ |
| #endif /* defined(VP_CC_880_SERIES) || defined(VP_CC_890_SERIES) */ |
| |
| /** |
| * ConvertApiState2PrfWizState() |
| * |
| * Maps an API-II line state into the equivelent state value used in cadence |
| * profiles. This function is used by the internal API functions when creating an internal |
| * cadence. Rather than use a state machine in some cases, it's easier to build a profile |
| * cadence type sequence and run that. |
| * |
| * Preconditions: |
| * None |
| * |
| * Postconditions: |
| * None |
| */ |
| VpProfileCadencerStateTypes |
| ConvertApiState2PrfWizState( |
| const VpLineStateType state) |
| { |
| switch(state) { |
| case VP_LINE_STANDBY: return VP_PROFILE_CADENCE_STATE_STANDBY; |
| case VP_LINE_TIP_OPEN: return VP_PROFILE_CADENCE_STATE_TIP_OPEN; |
| case VP_LINE_ACTIVE: return VP_PROFILE_CADENCE_STATE_ACTIVE; |
| case VP_LINE_ACTIVE_POLREV: return VP_PROFILE_CADENCE_STATE_POLREV_ACTIVE; |
| |
| /* Don't support cadencing in/out of Howler State in this release */ |
| case VP_LINE_HOWLER: return VP_PROFILE_CADENCE_STATE_ACTIVE; |
| case VP_LINE_HOWLER_POLREV: return VP_PROFILE_CADENCE_STATE_POLREV_ACTIVE; |
| |
| case VP_LINE_TALK: return VP_PROFILE_CADENCE_STATE_TALK; |
| case VP_LINE_TALK_POLREV: return VP_PROFILE_CADENCE_STATE_POLREV_TALK; |
| case VP_LINE_OHT: return VP_PROFILE_CADENCE_STATE_OHT; |
| case VP_LINE_OHT_POLREV: return VP_PROFILE_CADENCE_STATE_POLREV_OHT; |
| case VP_LINE_DISCONNECT: return VP_PROFILE_CADENCE_STATE_DISCONNECT; |
| case VP_LINE_RINGING: return VP_PROFILE_CADENCE_STATE_RINGING; |
| case VP_LINE_RINGING_POLREV: return VP_PROFILE_CADENCE_STATE_POLREV_RINGING; |
| case VP_LINE_STANDBY_POLREV: return VP_PROFILE_CADENCE_STATE_POLREV_STANDBY; |
| |
| case VP_LINE_FXO_OHT: return VP_PROFILE_CADENCE_STATE_FXO_OHT; |
| case VP_LINE_FXO_LOOP_OPEN: return VP_PROFILE_CADENCE_STATE_FXO_LOOP_OPEN; |
| case VP_LINE_FXO_LOOP_CLOSE: return VP_PROFILE_CADENCE_STATE_FXO_LOOP_CLOSE; |
| case VP_LINE_FXO_TALK: return VP_PROFILE_CADENCE_STATE_FXO_LOOP_TALK; |
| |
| /**< The calling function should check this is NOT returned */ |
| default: return VP_PROFILE_CADENCE_STATE_UNKNOWN; |
| }; |
| } /* ConvertApiState2PrfWizState() */ |
| |
| /** |
| * ConvertPrfWizState2ApiState() |
| * |
| * Maps a Profile Wizard State to the equivelent VP-API-II state |
| * |
| * Preconditions: |
| * None |
| * |
| * Postconditions: |
| * None |
| */ |
| VpLineStateType |
| ConvertPrfWizState2ApiState( |
| uint8 state) |
| { |
| switch(state) { |
| case VP_PROFILE_CADENCE_STATE_STANDBY: return VP_LINE_STANDBY; |
| case VP_PROFILE_CADENCE_STATE_TIP_OPEN: return VP_LINE_TIP_OPEN; |
| case VP_PROFILE_CADENCE_STATE_ACTIVE: return VP_LINE_ACTIVE; |
| case VP_PROFILE_CADENCE_STATE_POLREV_ACTIVE: return VP_LINE_ACTIVE_POLREV; |
| case VP_PROFILE_CADENCE_STATE_TALK: return VP_LINE_TALK; |
| case VP_PROFILE_CADENCE_STATE_POLREV_TALK: return VP_LINE_TALK_POLREV; |
| case VP_PROFILE_CADENCE_STATE_OHT: return VP_LINE_OHT; |
| case VP_PROFILE_CADENCE_STATE_POLREV_OHT: return VP_LINE_OHT_POLREV; |
| case VP_PROFILE_CADENCE_STATE_DISCONNECT: return VP_LINE_DISCONNECT; |
| case VP_PROFILE_CADENCE_STATE_RINGING: return VP_LINE_RINGING; |
| case VP_PROFILE_CADENCE_STATE_POLREV_RINGING: return VP_LINE_RINGING_POLREV; |
| case VP_PROFILE_CADENCE_STATE_POLREV_STANDBY: return VP_LINE_STANDBY_POLREV; |
| |
| case VP_PROFILE_CADENCE_STATE_FXO_OHT: return VP_LINE_FXO_OHT; |
| case VP_PROFILE_CADENCE_STATE_FXO_LOOP_OPEN: return VP_LINE_FXO_LOOP_OPEN; |
| case VP_PROFILE_CADENCE_STATE_FXO_LOOP_CLOSE: return VP_LINE_FXO_LOOP_CLOSE; |
| case VP_PROFILE_CADENCE_STATE_FXO_LOOP_TALK: return VP_LINE_FXO_TALK; |
| |
| default: return VP_LINE_STANDBY; |
| }; |
| } /* ConvertPrfWizState2ApiState() */ |
| |
| /** |
| * InitTimerVars() |
| * This function initializes the Cadence (sequencer) Variables in the line |
| * object associated with the line context passed. |
| * |
| * Preconditions: |
| * None |
| * |
| * Postconditions: |
| * The VpSeqDataType structure variables passed in the line context are |
| * initialized to pre-determined values. |
| */ |
| void |
| InitTimerVars( |
| VpLineCtxType *pLineCtx) /**< Line to initialize API Timer (internal) |
| * Variables for |
| */ |
| { |
| VpDeviceType deviceType = pLineCtx->pDevCtx->deviceType; |
| void *pLineObj = pLineCtx->pLineObj; |
| VpCslacTimerStruct *pTimer; |
| |
| switch(deviceType) { |
| #if defined (VP_CC_790_SERIES) |
| case VP_DEV_790_SERIES: |
| pTimer = &((Vp790LineObjectType *)pLineObj)->lineTimers; |
| break; |
| #endif |
| |
| #if defined (VP_CC_880_SERIES) |
| case VP_DEV_880_SERIES: |
| pTimer = &((Vp880LineObjectType *)pLineObj)->lineTimers; |
| break; |
| #endif |
| |
| #if defined (VP_CC_890_SERIES) |
| case VP_DEV_890_SERIES: |
| pTimer = &((Vp890LineObjectType *)pLineObj)->lineTimers; |
| break; |
| #endif |
| |
| #if defined (VP_CC_580_SERIES) |
| case VP_DEV_580_SERIES: |
| pTimer = &((Vp580LineObjectType *)pLineObj)->lineTimers; |
| break; |
| #endif |
| default: |
| /* Nothing known to initialize */ |
| return; |
| } |
| |
| VpMemSet(pTimer, 0x00, sizeof(VpCslacTimerStruct)); |
| |
| if (pTimer->type == VP_CSLAC_FXO_TIMER) { |
| #if (defined(VP_CC_880_SERIES) && defined (VP880_FXO_SUPPORT)) || \ |
| (defined(VP_CC_890_SERIES) && defined (VP890_FXO_SUPPORT)) || defined(VP_CC_580_SERIES) |
| /* Iniialize non-zero initial values */ |
| pTimer->timers.fxoTimer.prevHighToLowTime = 0x7FFF; |
| pTimer->timers.fxoTimer.noCount = TRUE; |
| pTimer->timers.fxoTimer.timeLastPolRev = 0x7FFF; |
| pTimer->timers.fxoTimer.timePrevPolRev = 0x7FFF; |
| pTimer->timers.fxoTimer.disconnectDebounce = 0xFFFF; |
| pTimer->timers.fxoTimer.liuDebounce = 0xFF; |
| pTimer->timers.fxoTimer.bCalTimer = 0xFF; |
| #endif |
| } |
| } |
| |
| #if (defined(VP_CC_880_SERIES) && defined (VP880_FXS_SUPPORT)) || \ |
| (defined(VP_CC_890_SERIES) && defined (VP890_FXS_SUPPORT)) || \ |
| defined(VP_CC_580_SERIES) || defined(VP_CC_790_SERIES) |
| |
| /** |
| * VpUpdateDP() |
| * This function measures the timing of the on/off-hook conditions for Dial |
| * Pulsing and Flash Hook events (as well as the immediate Off-Hook, and long |
| * On-Hook events). |
| * |
| * Preconditions: |
| * The pointers passed (Dial Pulse specifications, Dial Pulse data structure, |
| * and Line Events structure) cannot be VP_NULL. |
| * |
| * Postconditions: |
| * The line events structure is updated with an event if the on/off-hook |
| * variables provided in the dial pulse structure meet the specifications |
| * provided in the dial pulse specification structure. Note: This function has |
| * no knowledge of line context/objects, so it can be used for any type of |
| * line. |
| */ |
| bool |
| VpUpdateDP( |
| uint16 tickRate, /**< Device API Tickrate used to measure real |
| * on/off-hook time |
| */ |
| |
| VpOptionPulseType *pPulseSpecs, /**< Dial Pulse specifications to apply |
| * to on/off-hooks |
| */ |
| VpDialPulseDetectType *pDpStruct, /**< Structure used to maintain dial |
| * pulse status |
| */ |
| VpOptionEventMaskType *pLineEvents) /**< Line event structure to be modified |
| * if an event is detected (and needs to |
| * be reported). |
| */ |
| { |
| bool eventStatus = FALSE; |
| uint16 break_min, break_max; |
| uint16 make_min, make_max; |
| uint16 flash_min, flash_max; |
| uint16 interDigitMin, conversionFactor; |
| uint16 onHook_min; |
| |
| if ((pPulseSpecs == VP_NULL) |
| || (pDpStruct == VP_NULL) |
| || (pLineEvents == VP_NULL)) { |
| return FALSE; |
| } |
| |
| /* Get the specs in 125us units */ |
| break_min = pPulseSpecs->breakMin; |
| break_max= pPulseSpecs->breakMax; |
| make_min = pPulseSpecs->makeMin; |
| make_max = pPulseSpecs->makeMax; |
| flash_min = pPulseSpecs->flashMin; |
| flash_max = pPulseSpecs->flashMax; |
| |
| #ifdef EXTENDED_FLASH_HOOK |
| onHook_min = pPulseSpecs->onHookMin; |
| #else |
| onHook_min = flash_max; |
| #endif |
| |
| interDigitMin = pPulseSpecs->interDigitMin; |
| #define VP_API_TICKRATE_CONVERSION (32) |
| conversionFactor = (tickRate / VP_API_TICKRATE_CONVERSION); |
| |
| switch(pDpStruct->state) { |
| case VP_DP_DETECT_STATE_IDLE: |
| if(pDpStruct->hookSt) { |
| /* |
| * We are off-hook after being on-hook for a "long time". Start |
| * dial pulsing |
| */ |
| pDpStruct->state = VP_DP_DETECT_STATE_LOOP_CLOSE; |
| pDpStruct->lc_time = 0; |
| eventStatus = TRUE; |
| pLineEvents->signaling &= ~VP_LINE_EVID_PULSE_DIG; |
| pLineEvents->signaling &= ~VP_LINE_EVID_HOOK_ON; |
| pLineEvents->signaling &= ~VP_LINE_EVID_FLASH; |
| pLineEvents->signaling &= ~VP_LINE_EVID_BREAK_MAX; |
| pLineEvents->signaling &= ~VP_LINE_EVID_EXTD_FLASH; |
| pLineEvents->signaling |= VP_LINE_EVID_HOOK_OFF; |
| |
| VP_HOOK(None, NULL, ("VP_DP_DETECT_STATE_IDLE: DP Off-Hook")); |
| } |
| break; |
| |
| case VP_DP_DETECT_STATE_LOOP_OPEN: |
| pDpStruct->lo_time += conversionFactor; |
| |
| if(pDpStruct->hookSt) { |
| /* Detected off-hook */ |
| |
| if ((pDpStruct->lo_time >= break_min) && (pDpStruct->lo_time <= break_max)) { |
| /* |
| * We think we just dialed a pulse, but don't count it if |
| * this sequence of on/off hooks has already been marked |
| * as invalid (-1) |
| */ |
| if (pDpStruct->digits != -1) { |
| pDpStruct->digits++; |
| } |
| |
| VP_HOOK(None, NULL, |
| ("1. VP_DP_DETECT_STATE_LOOP_OPEN going to VP_DP_DETECT_STATE_LOOP_CLOSE: With Loop Open Time %d", |
| pDpStruct->lo_time)); |
| |
| pDpStruct->state = VP_DP_DETECT_STATE_LOOP_CLOSE; |
| } else if ((pDpStruct->lo_time >= flash_min) && (pDpStruct->lo_time <= flash_max)) { |
| /* We did a hook flash */ |
| pDpStruct->signalingData = pDpStruct->lo_time * (tickRate >> 8); |
| |
| eventStatus = TRUE; |
| pLineEvents->signaling &= ~VP_LINE_EVID_HOOK_ON; |
| pLineEvents->signaling &= ~VP_LINE_EVID_PULSE_DIG; |
| pLineEvents->signaling &= ~VP_LINE_EVID_HOOK_OFF; |
| pLineEvents->signaling &= ~VP_LINE_EVID_BREAK_MAX; |
| pLineEvents->signaling &= ~VP_LINE_EVID_EXTD_FLASH; |
| pLineEvents->signaling |= VP_LINE_EVID_FLASH; |
| |
| VpInitDP(pDpStruct); |
| pDpStruct->state = VP_DP_DETECT_STATE_LOOP_CLOSE; |
| pDpStruct->lo_time = flash_max-1; |
| |
| VP_HOOK(None, NULL, |
| ("2. VP_DP_DETECT_STATE_LOOP_OPEN going to VP_DP_DETECT_STATE_LOOP_CLOSE: With Loop Open Time %d", |
| pDpStruct->lo_time)); |
| } else if ((pDpStruct->lo_time > flash_max) && (pDpStruct->lo_time <= onHook_min)) { |
| /* |
| * We did something between hook flash and on-hook. This is |
| * defined as a "new call" event. |
| */ |
| pDpStruct->signalingData = pDpStruct->lo_time * (tickRate >> 8); |
| |
| eventStatus = TRUE; |
| pLineEvents->signaling &= ~VP_LINE_EVID_HOOK_ON; |
| pLineEvents->signaling &= ~VP_LINE_EVID_PULSE_DIG; |
| pLineEvents->signaling &= ~VP_LINE_EVID_HOOK_OFF; |
| pLineEvents->signaling &= ~VP_LINE_EVID_BREAK_MAX; |
| pLineEvents->signaling |= VP_LINE_EVID_EXTD_FLASH; |
| pLineEvents->signaling &= ~VP_LINE_EVID_FLASH; |
| |
| VpInitDP(pDpStruct); |
| pDpStruct->state = VP_DP_DETECT_STATE_LOOP_CLOSE; |
| pDpStruct->lo_time = onHook_min-1; |
| |
| VP_HOOK(None, NULL, |
| ("3. VP_DP_DETECT_STATE_LOOP_OPEN going to VP_DP_DETECT_STATE_LOOP_CLOSE: With Loop Open Time %d", |
| pDpStruct->lo_time)); |
| } else { |
| /* This occurs for invalid digits */ |
| pDpStruct->state = VP_DP_DETECT_STATE_LOOP_CLOSE; |
| |
| /* Mark this sequence of digits invalid */ |
| pDpStruct->digits = -1; |
| |
| VP_HOOK(None, NULL, |
| ("INVALID_DIGIT!! VP_DP_DETECT_STATE_LOOP_OPEN going to VP_DP_DETECT_STATE_LOOP_CLOSE: With Loop Open Time %d", |
| pDpStruct->lo_time)); |
| } |
| pDpStruct->lc_time = 0; |
| } else { |
| if (pDpStruct->lo_time > onHook_min) { |
| VP_HOOK(None, NULL, |
| ("HOOK_ON: VP_DP_DETECT_STATE_LOOP_OPEN going to VP_DP_DETECT_STATE_IDLE: With Loop Open Time %d", |
| pDpStruct->lo_time)); |
| |
| /* We're on-hook, report and start over */ |
| VpInitDP(pDpStruct); |
| eventStatus = TRUE; |
| pLineEvents->signaling &= ~VP_LINE_EVID_HOOK_OFF; |
| pLineEvents->signaling &= ~VP_LINE_EVID_PULSE_DIG; |
| pLineEvents->signaling &= ~VP_LINE_EVID_FLASH; |
| pLineEvents->signaling &= ~VP_LINE_EVID_BREAK_MAX; |
| pLineEvents->signaling |= VP_LINE_EVID_HOOK_ON; |
| pLineEvents->signaling &= ~VP_LINE_EVID_EXTD_FLASH; |
| } |
| } |
| break; |
| |
| case VP_DP_DETECT_STATE_LOOP_CLOSE: |
| /* Limit the value lc_time can reach so we don't overflow */ |
| if(pDpStruct->lc_time < (0xFFFF - conversionFactor)) { |
| pDpStruct->lc_time += conversionFactor; |
| } |
| |
| /* Check to see if we're still off-hook */ |
| if(pDpStruct->hookSt) { |
| /* We're still off-hook. Did we reach the interdigit time? */ |
| if (pDpStruct->lc_time >= interDigitMin && |
| pDpStruct->lc_time < interDigitMin + conversionFactor) { |
| /* Interdigit time reached. Report digits collected */ |
| if (pDpStruct->digits > 0) { |
| /* We have dialed digits */ |
| eventStatus = TRUE; |
| pLineEvents->signaling &= ~VP_LINE_EVID_HOOK_ON; |
| pLineEvents->signaling &= ~VP_LINE_EVID_HOOK_OFF; |
| pLineEvents->signaling &= ~VP_LINE_EVID_FLASH; |
| pLineEvents->signaling &= ~VP_LINE_EVID_BREAK_MAX; |
| pLineEvents->signaling |= VP_LINE_EVID_PULSE_DIG; |
| pDpStruct->signalingData = pDpStruct->digits; |
| pLineEvents->signaling &= ~VP_LINE_EVID_EXTD_FLASH; |
| } else { |
| /* |
| * If we're still off-hook, we either didn't collect |
| * digits, the digits were invalid, this was an initial |
| * off-hook or a Hook Flash. If the digits were not |
| * invalid, the event has been reported. Only report an |
| * event for invalid digits. |
| */ |
| if (pDpStruct->digits < 0) { |
| eventStatus = TRUE; |
| pLineEvents->signaling &= ~VP_LINE_EVID_HOOK_ON; |
| pLineEvents->signaling &= ~VP_LINE_EVID_HOOK_OFF; |
| pLineEvents->signaling &= ~VP_LINE_EVID_FLASH; |
| pLineEvents->signaling &= ~VP_LINE_EVID_BREAK_MAX; |
| pLineEvents->signaling |= VP_LINE_EVID_PULSE_DIG; |
| pLineEvents->signaling &= ~VP_LINE_EVID_EXTD_FLASH; |
| pDpStruct->signalingData = VP_DIG_NONE; |
| } |
| } |
| } |
| } else { |
| /* Detected on-hook. */ |
| |
| /* If the interdigit time has passed or there are no digits |
| * counted yet, this is a new pulse sequence */ |
| if (pDpStruct->lc_time >= interDigitMin || pDpStruct->digits == 0) { |
| eventStatus = TRUE; |
| pLineEvents->signaling |= VP_LINE_EVID_STARTPULSE; |
| VpInitDP(pDpStruct); |
| } else if (pDpStruct->lc_time > make_max || pDpStruct->lc_time < make_min) { |
| /* If this isn't the beginning of a pulse sequence and we're |
| * outside of the make min/max, mark this sequence invalid */ |
| pDpStruct->digits = -1; |
| } |
| |
| VP_HOOK(None, NULL, |
| ("VP_DP_DETECT_STATE_LOOP_CLOSE going to VP_DP_DETECT_STATE_LOOP_OPEN: Digit Close (%d) Open (%d)", |
| pDpStruct->lc_time, pDpStruct->lo_time)); |
| |
| pDpStruct->state = VP_DP_DETECT_STATE_LOOP_OPEN; |
| pDpStruct->lo_time = 0; |
| } |
| break; |
| |
| default: |
| return FALSE; |
| } |
| |
| return eventStatus; |
| } |
| |
| /** |
| * VpInitDP() |
| * Initializes the dial pulse structure variable passed to values required by |
| * VpUpdateDP. |
| * |
| * Preconditions: |
| * The pointer passed (Dial data structure) cannot be VP_NULL. |
| * |
| * Postconditions: |
| * The data passed in the dial pulse data structure is initialized. |
| */ |
| void |
| VpInitDP( |
| VpDialPulseDetectType *pDpStruct) /**< Dial pulse structure to init */ |
| { |
| if (pDpStruct != VP_NULL) { |
| pDpStruct->digits = 0; |
| |
| if (pDpStruct->hookSt == FALSE) { |
| pDpStruct->state = VP_DP_DETECT_STATE_IDLE; |
| pDpStruct->lo_time = 0xFFFF; |
| pDpStruct->lc_time = 0; |
| } else { |
| pDpStruct->state = VP_DP_DETECT_STATE_LOOP_CLOSE; |
| pDpStruct->lo_time = 0; |
| pDpStruct->lc_time = 0xFFFF; |
| } |
| } |
| return; |
| } |
| #endif |
| |
| /** |
| * VpCSLACGetLineStatus() |
| * This function returns the status of the type being request for the line |
| * (context) being passed. |
| * |
| * Preconditions: |
| * The line context pointer passed must be valid. |
| * |
| * Postconditions: |
| * The location pointed to by the boolean pointer passed is set to either TRUE |
| * or FALSE depending on the status of the line for the type of input requested. |
| * This function returns the success status code if the information requested |
| * is valid for the line type (FXO/FXS) being passed. |
| */ |
| VpStatusType |
| VpCSLACGetLineStatus( |
| VpLineCtxType *pLineCtx, |
| VpInputType input, |
| bool *pStatus) |
| { |
| VpDevCtxType *pDevCtx = pLineCtx->pDevCtx; |
| VpDeviceType deviceType = pDevCtx->deviceType; |
| |
| #if defined (VP_CC_580_SERIES) || \ |
| (defined (VP_CC_890_SERIES) && defined (VP890_FXS_SUPPORT)) || \ |
| defined (VP_CC_790_SERIES) || \ |
| (defined (VP_CC_880_SERIES) && defined (VP880_FXS_SUPPORT)) |
| VpDialPulseDetectType *pDpStruct = VP_NULL; |
| bool resLeak = FALSE; |
| VpOptionPulseModeType pulseMode = VP_OPTION_PULSE_DECODE_OFF; |
| #endif |
| |
| VpApiIntLineStateType *pLineState; |
| VpDeviceDynamicInfoType *pDynamicInfo; |
| bool fxo; |
| |
| void *pLineObj = pLineCtx->pLineObj; |
| void *pDevObj = pDevCtx->pDevObj; |
| |
| switch (deviceType) { |
| #if defined (VP_CC_790_SERIES) |
| case VP_DEV_790_SERIES: |
| pDpStruct = &((Vp790LineObjectType *)pLineObj)->dpStruct; |
| pLineState = &((Vp790LineObjectType *)pLineObj)->lineState; |
| pDynamicInfo = &((Vp790DeviceObjectType *)pDevObj)->dynamicInfo; |
| fxo = FALSE; |
| pulseMode = ((Vp790LineObjectType *)pLineObj)->pulseMode; |
| break; |
| #endif |
| |
| #if defined (VP_CC_880_SERIES) |
| case VP_DEV_880_SERIES: |
| #ifdef VP880_FXS_SUPPORT |
| pDpStruct = &((Vp880LineObjectType *)pLineObj)->dpStruct; |
| pulseMode = ((Vp880LineObjectType *)pLineObj)->pulseMode; |
| resLeak = ((((Vp880LineObjectType *)pLineObj)->status) & VP880_LINE_LEAK) |
| ? TRUE : FALSE; |
| #endif |
| |
| pLineState = &((Vp880LineObjectType *)pLineObj)->lineState; |
| pDynamicInfo = &((Vp880DeviceObjectType *)pDevObj)->dynamicInfo; |
| if (((Vp880LineObjectType *)pLineObj)->status & VP880_IS_FXO) { |
| fxo = TRUE; |
| } else { |
| fxo = FALSE; |
| } |
| break; |
| #endif |
| |
| #if defined (VP_CC_890_SERIES) |
| case VP_DEV_890_SERIES: |
| pLineState = &((Vp890LineObjectType *)pLineObj)->lineState; |
| pDynamicInfo = &((Vp890DeviceObjectType *)pDevObj)->dynamicInfo; |
| if (((Vp890LineObjectType *)pLineObj)->status & VP890_IS_FXO) { |
| fxo = TRUE; |
| } else { |
| fxo = FALSE; |
| } |
| break; |
| |
| #if defined (VP_CC_580_SERIES) |
| case VP_DEV_580_SERIES: |
| pDpStruct = &((Vp580LineObjectType *)pLineObj)->dpStruct; |
| pLineState = &((Vp580LineObjectType *)pLineObj)->lineState; |
| pDynamicInfo = &((Vp580DeviceObjectType *)pDevObj)->dynamicInfo; |
| if (((Vp580LineObjectType *)pLineObj)->status & VP580_IS_FXO) { |
| fxo = TRUE; |
| } else { |
| fxo = FALSE; |
| } |
| pulseMode = ((Vp580LineObjectType *)pLineObj)->pulseMode; |
| break; |
| #endif |
| |
| default: |
| return VP_STATUS_INVALID_ARG; |
| } |
| |
| if (fxo == FALSE) { |
| switch(input) { |
| #if defined (VP_CC_580_SERIES) || \ |
| (defined (VP_CC_890_SERIES) && defined (VP890_FXS_SUPPORT)) || \ |
| defined (VP_CC_790_SERIES) || \ |
| (defined (VP_CC_880_SERIES) && defined (VP880_FXS_SUPPORT)) |
| case VP_INPUT_HOOK: |
| if(pulseMode == VP_OPTION_PULSE_DECODE_ON) { |
| if ((pDpStruct != VP_NULL) && (pDpStruct->state == VP_DP_DETECT_STATE_IDLE)) { |
| *pStatus = FALSE; |
| } else { |
| *pStatus = TRUE; |
| } |
| } else { |
| if ((pLineState->condition & VP_CSLAC_HOOK) |
| && (!(pLineState->condition & VP_CSLAC_LINE_LEAK_TEST))) { |
| *pStatus = TRUE; |
| } else { |
| *pStatus = FALSE; |
| } |
| } |
| break; |
| |
| case VP_INPUT_RAW_HOOK: |
| if ((pLineState->condition & VP_CSLAC_HOOK) |
| && (!(pLineState->condition & VP_CSLAC_LINE_LEAK_TEST))) { |
| *pStatus = TRUE; |
| } else { |
| *pStatus = FALSE; |
| } |
| break; |
| |
| case VP_INPUT_GKEY: |
| *pStatus = (pLineState->condition & VP_CSLAC_GKEY) |
| ? TRUE : FALSE; |
| break; |
| |
| case VP_INPUT_CLK_FLT: |
| *pStatus = (pDynamicInfo->clkFault) ? TRUE : FALSE; |
| break; |
| |
| case VP_INPUT_THERM_FLT: |
| *pStatus = (pLineState->condition & VP_CSLAC_THERM_FLT) |
| ? TRUE : FALSE; |
| break; |
| |
| case VP_INPUT_AC_FLT: |
| *pStatus = (pLineState->condition & VP_CSLAC_AC_FLT) |
| ? TRUE : FALSE; |
| break; |
| |
| case VP_INPUT_DC_FLT: |
| *pStatus = (pLineState->condition & VP_CSLAC_DC_FLT) |
| ? TRUE : FALSE; |
| break; |
| |
| case VP_INPUT_BAT1_FLT: |
| *pStatus = (pDynamicInfo->bat1Fault) ? TRUE : FALSE; |
| break; |
| |
| case VP_INPUT_BAT2_FLT: |
| *pStatus = (pDynamicInfo->bat2Fault) ? TRUE : FALSE; |
| break; |
| |
| case VP_INPUT_BAT3_FLT: |
| *pStatus = (pDynamicInfo->bat3Fault) ? TRUE : FALSE; |
| break; |
| |
| case VP_INPUT_RES_LEAK: |
| *pStatus = resLeak; |
| break; |
| #endif |
| default: |
| return VP_STATUS_INVALID_ARG; |
| } |
| } else { |
| switch(input) { |
| case VP_INPUT_CLK_FLT: |
| *pStatus = (pDynamicInfo->clkFault) ? TRUE : FALSE; |
| break; |
| |
| /* DC Fault is possible from the FXO line on VE890 only */ |
| case VP_INPUT_DC_FLT: |
| if (deviceType == VP_DEV_890_SERIES) { |
| *pStatus = (pLineState->condition & VP_CSLAC_DC_FLT) ? TRUE : FALSE; |
| } else { |
| return VP_STATUS_INVALID_ARG; |
| } |
| break; |
| |
| |
| case VP_INPUT_RINGING: |
| *pStatus = (pLineState->condition & VP_CSLAC_RINGING) ? TRUE : FALSE; |
| break; |
| |
| case VP_INPUT_POLREV: |
| *pStatus = (pLineState->condition & VP_CSLAC_POLREV) ? TRUE : FALSE; |
| break; |
| |
| case VP_INPUT_LIU: |
| *pStatus = (pLineState->condition & VP_CSLAC_LIU) ? TRUE : FALSE; |
| break; |
| |
| case VP_INPUT_FEED_DIS: |
| case VP_INPUT_DISCONNECT: |
| *pStatus = (pLineState->condition & VP_CSLAC_DISC) ? TRUE : FALSE; |
| break; |
| |
| case VP_INPUT_FEED_EN: |
| case VP_INPUT_CONNECT: |
| *pStatus = (pLineState->condition & VP_CSLAC_DISC) ? FALSE : TRUE; |
| break; |
| |
| default: |
| return VP_STATUS_INVALID_ARG; |
| } |
| } |
| return VP_STATUS_SUCCESS; |
| } |
| |
| #if !defined(VP_REDUCED_API_IF) |
| /** |
| * VpCSLACClearResults() |
| * This function clears the device read events so that normal read operations |
| * may occur. It is done by the application when the device is busy (in read |
| * moode) and the application does not know what to read. |
| * |
| * Preconditions: |
| * Device/Line context should be created and initialized. |
| * |
| * Postconditions: |
| * Device is no longer busy with read status. |
| */ |
| VpStatusType |
| VpCSLACClearResults( |
| VpDevCtxType *pDevCtx) |
| { |
| VpDeviceType deviceType = pDevCtx->deviceType; |
| VpDeviceIdType deviceId; |
| VpOptionEventMaskType *pDeviceEvents; |
| |
| void *pDevObj = pDevCtx->pDevObj; |
| |
| switch (deviceType) { |
| #if defined (VP_CC_790_SERIES) |
| case VP_DEV_790_SERIES: |
| pDeviceEvents = &((Vp790DeviceObjectType *)pDevObj)->deviceEvents; |
| deviceId = ((Vp790DeviceObjectType *)pDevObj)->deviceId; |
| break; |
| #endif |
| |
| #if defined (VP_CC_880_SERIES) |
| case VP_DEV_880_SERIES: |
| pDeviceEvents = &((Vp880DeviceObjectType *)pDevObj)->deviceEvents; |
| deviceId = ((Vp880DeviceObjectType *)pDevObj)->deviceId; |
| break; |
| #endif |
| |
| #if defined (VP_CC_890_SERIES) |
| case VP_DEV_890_SERIES: |
| pDeviceEvents = &((Vp890DeviceObjectType *)pDevObj)->deviceEvents; |
| deviceId = ((Vp890DeviceObjectType *)pDevObj)->deviceId; |
| break; |
| #endif |
| |
| #if defined (VP_CC_580_SERIES) |
| case VP_DEV_580_SERIES: |
| pDeviceEvents = &((Vp580DeviceObjectType *)pDevObj)->deviceEvents; |
| deviceId = ((Vp580DeviceObjectType *)pDevObj)->deviceId; |
| break; |
| #endif |
| |
| default: |
| return VP_STATUS_INVALID_ARG; |
| } |
| |
| VpSysEnterCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| pDeviceEvents->response &= (~VP_CSLAC_READ_RESPONSE_MASK); |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| |
| return VP_STATUS_SUCCESS; |
| } |
| #endif |
| |
| /** |
| * VpCSLACDtmfDigitDetected() |
| * This function is used to set a value in the API-II CSLAC library (where |
| * applicable) indicating that a DTMF digit was detected in an external |
| * application/process. |
| * |
| * Preconditions: |
| * Device/Line context should be created and initialized. For applicable |
| * devices bootload should be performed before calling the function. |
| * |
| * Postconditions: |
| * A value in the API-II is set which indicates the digit detected. The most |
| * recent value is stored. |
| */ |
| #if defined (VP_CC_880_SERIES) || defined (VP_CC_890_SERIES) || defined (VP_CC_790_SERIES) |
| VpStatusType |
| VpCSLACDtmfDigitDetected( |
| VpLineCtxType *pLineCtx, |
| VpDigitType digit, |
| VpDigitSenseType sense) |
| { |
| VpDevCtxType *pDevCtx = pLineCtx->pDevCtx; |
| VpDeviceIdType deviceId; |
| VpDeviceType deviceType = pDevCtx->deviceType; |
| #ifdef VP_CSLAC_SEQ_EN |
| #if (defined (VP_CC_880_SERIES) && defined (VP880_FXS_SUPPORT)) || \ |
| (defined (VP_CC_890_SERIES) && defined (VP890_FXS_SUPPORT)) || \ |
| defined (VP_CC_790_SERIES) |
| VpCallerIdType *pCidStruct = VP_NULL; |
| #endif |
| #endif |
| VpOptionEventMaskType *pLineEvents; |
| uint16p pDtmfDigitSense; |
| |
| void *pLineObj = pLineCtx->pLineObj; |
| void *pDevObj = pDevCtx->pDevObj; |
| |
| switch (deviceType) { |
| #if defined (VP_CC_790_SERIES) |
| case VP_DEV_790_SERIES: |
| #ifdef VP_CSLAC_SEQ_EN |
| pCidStruct = &((Vp790LineObjectType *)pLineObj)->callerId; |
| #endif |
| deviceId = ((Vp790DeviceObjectType *)pDevObj)->deviceId; |
| pLineEvents = &((Vp790LineObjectType *)pLineObj)->lineEvents; |
| pDtmfDigitSense = &((Vp790LineObjectType *)pLineObj)->dtmfDigitSense; |
| break; |
| #endif |
| |
| #if defined (VP_CC_880_SERIES) |
| case VP_DEV_880_SERIES: |
| #if defined (VP_CSLAC_SEQ_EN) && defined (VP880_FXS_SUPPORT) |
| pCidStruct = &((Vp880LineObjectType *)pLineObj)->callerId; |
| #endif |
| deviceId = ((Vp880DeviceObjectType *)pDevObj)->deviceId; |
| pLineEvents = &((Vp880LineObjectType *)pLineObj)->lineEvents; |
| pDtmfDigitSense = &((Vp880LineObjectType *)pLineObj)->dtmfDigitSense; |
| break; |
| #endif |
| |
| #if defined (VP_CC_890_SERIES) |
| case VP_DEV_890_SERIES: |
| #if defined (VP_CSLAC_SEQ_EN) && defined (VP890_FXS_SUPPORT) |
| pCidStruct = &((Vp890LineObjectType *)pLineObj)->callerId; |
| #endif |
| deviceId = ((Vp890DeviceObjectType *)pDevObj)->deviceId; |
| pLineEvents = &((Vp890LineObjectType *)pLineObj)->lineEvents; |
| pDtmfDigitSense = &((Vp890LineObjectType *)pLineObj)->dtmfDigitSense; |
| break; |
| #endif |
| |
| default: |
| return VP_STATUS_INVALID_ARG; |
| } |
| |
| switch (sense) { |
| case VP_DIG_SENSE_BREAK: |
| case VP_DIG_SENSE_MAKE: |
| #ifdef VP_CSLAC_SEQ_EN |
| #if (defined (VP_CC_880_SERIES) && defined (VP880_FXS_SUPPORT)) || \ |
| (defined (VP_CC_790_SERIES)) || \ |
| (defined (VP_CC_890_SERIES) && defined (VP890_FXS_SUPPORT)) |
| /* |
| * If the CID sequencer is waiting for a CPE ACK tone, report |
| * the DTMF event to the CID sequencer, but mask it from the |
| * application. |
| */ |
| if ((pCidStruct != VP_NULL) && ((pCidStruct->status & VP_CID_AWAIT_TONE) != 0)) { |
| VpSysEnterCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| pCidStruct->digitDet = digit; |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| return VP_STATUS_SUCCESS; |
| } |
| #endif |
| #endif |
| break; |
| |
| default: |
| return VP_STATUS_INVALID_ARG; |
| } |
| |
| /* Toggle the DTMF_DIG event. If two DTMF_DIG events are received within |
| * the same API tick period, report neither. */ |
| VpSysEnterCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| pLineEvents->signaling ^= VP_LINE_EVID_DTMF_DIG; |
| *pDtmfDigitSense = digit | sense; |
| VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC); |
| |
| return VP_STATUS_SUCCESS; |
| } |
| #endif |
| |
| /** |
| * VpGetReverseState() |
| * This function returns the polarity inverted API-II state from the state |
| * passed. |
| * |
| * Preconditions: |
| * None. Helper function only. |
| * |
| * Postconditions: |
| * None. Helper function only. |
| */ |
| VpLineStateType |
| VpGetReverseState( |
| VpLineStateType currentState) |
| { |
| switch(currentState) { |
| case VP_LINE_STANDBY: |
| return VP_LINE_STANDBY_POLREV; |
| |
| case VP_LINE_ACTIVE: |
| return VP_LINE_ACTIVE_POLREV; |
| |
| #ifdef VP_HIGH_GAIN_MODE_SUPPORTED |
| case VP_LINE_HOWLER: |
| return VP_LINE_HOWLER_POLREV; |
| |
| case VP_LINE_HOWLER_POLREV: |
| return VP_LINE_HOWLER; |
| #endif |
| |
| case VP_LINE_ACTIVE_POLREV: |
| return VP_LINE_ACTIVE; |
| |
| |
| case VP_LINE_TALK: |
| return VP_LINE_TALK_POLREV; |
| |
| case VP_LINE_TALK_POLREV: |
| return VP_LINE_TALK; |
| |
| case VP_LINE_OHT: |
| return VP_LINE_OHT_POLREV; |
| |
| case VP_LINE_OHT_POLREV: |
| return VP_LINE_OHT; |
| |
| case VP_LINE_RINGING: |
| return VP_LINE_RINGING_POLREV; |
| |
| case VP_LINE_RINGING_POLREV: |
| return VP_LINE_RINGING; |
| |
| case VP_LINE_STANDBY_POLREV: |
| return VP_LINE_STANDBY; |
| |
| default: |
| return currentState; |
| } |
| } |
| |
| /** |
| * VpCSLACSetVas() |
| * This function sets the VAS values in dcFeed as specified by the device |
| * dc feed register, with VAS value passed. It does not actually access the |
| * device, just simply computes the correct hex values for the dc feed reg. |
| * |
| * Preconditions: |
| * None. Helper function only. |
| * |
| * Postconditions: |
| * Line not affected. Values in dcFeed contain the VAS values passed. |
| */ |
| void |
| VpCSLACSetVas( |
| uint8 *dcFeed, |
| uint16 vasValue) |
| { |
| uint16 regValue = 0; |
| |
| if (vasValue >= 3000) { |
| regValue = (vasValue - 3000) / 750; |
| } |
| |
| dcFeed[0] &= 0xFC; |
| dcFeed[1] &= 0x3F; |
| |
| dcFeed[0] |= ((uint8)(regValue & 0xC) >> 2); |
| dcFeed[1] |= ((uint8)(regValue & 0x3) << 6); |
| } |
| |
| #ifdef CSLAC_GAIN_RELATIVE |
| /** |
| * VpConvertCsd2Fixed() |
| * This function returns a 2.14 fixed-point number whose value matches (as |
| * nearly as possible) the value of a given CSD (canonical signed digit) |
| * number. |
| * |
| * Preconditions: |
| * The CSD number must be split into a two-byte array consisting of the high |
| * byte followed by the low byte. Its value must be between 0 and 4.0. |
| * |
| * Postconditions: |
| * If the value of the passed CSD number is less than 0, 0 will be returned. |
| * If the value is greater than or equal to 4.0, 65535 will be returned, |
| * which means 3.99994 in 2.14 representation. |
| */ |
| uint16 |
| VpConvertCsd2Fixed( |
| uint8 *csdBuf) |
| { |
| uint16 csd = (csdBuf[0] << 8) + csdBuf[1]; |
| int32 result; |
| int8 bitPos, C, m; |
| |
| /* 2.14 fixed-point format has values ranging from 0 to 3.999.... The bits |
| * have the following values: |
| * |
| * bit 15 14 13 12 2 1 0 |
| * +-----+-----+-----+-----+ +-----+-----+-----+ |
| * value | 2^1 | 2^0 | 2^-1| 2^-2| ... |2^-12|2^-13|2^-14| |
| * +-----+-----+-----+-----+ +-----+-----+-----+ |
| */ |
| |
| /* |
| * CSD format is as follows: |
| * |
| * bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |
| * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ |
| * field |C40| m40 |C30| m30 |C20| m20 |C10| m10 | |
| * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ |
| * |
| * where the represented value is calculated as follows (Cxy = 0 or 1 |
| * above corresponds to Cxy = 1 or -1, respectively, below): |
| * |
| * C10 * 2^-m10 * ( |
| * 1 + C20 * 2^-m20 * ( |
| * 1 + C30 * 2^-m30 * ( |
| * 1 + C40 * 2^-m40 ))) |
| */ |
| |
| /* |
| * Alternate formula which can be computed with unsigned ints: |
| * |
| * C10 * 2^-m10 |
| * + C10 * C20 * 2^(-m10-m20) |
| * + C10 * C20 * C30 * 2^(-m10-m20-m30) |
| * + C10 * C20 * C30 * C40 * 2^(-m10-m20-m30-m40) |
| */ |
| |
| C = m = result = 0; |
| for (bitPos = 0; bitPos < 16; bitPos += 4) { |
| C ^= (csd >> (bitPos + 3)) & 1; |
| m += (csd >> bitPos) & 7; |
| if (C == 0) { |
| result += 0x4000 >> m; |
| } else { |
| result -= 0x4000 >> m; |
| } |
| } |
| |
| /* Ensure that the result can be stored in a uint16. */ |
| if (result > 0xFFFF) { |
| result = 0xFFFF; |
| } else if (result < 0) { |
| result = 0; |
| } |
| |
| return result; |
| } /* VpConvertCsd2Fixed() */ |
| |
| /** |
| * VpConvertFixed2Csd() |
| * This function returns a four-nibble CSD (canonical signed digit) number |
| * whose value matches (as nearly as possible) the supplied 2.14 fixed-point |
| * number. |
| * |
| * Preconditions: |
| * |
| * Postconditions: |
| * The CSD number will be placed into a two-byte array (high byte first) at |
| * the address specified in the csdBuf parameter. |
| */ |
| void |
| VpConvertFixed2Csd( |
| uint16 fixed, |
| uint8 *csdBuf) |
| { |
| #define CSD_NIBBLES 4 |
| uint16 error, power, greaterPower, smallerPower, distGreater, distSmaller; |
| uint16 C, m, result, sum = 0; |
| int8 n, gp, sp; |
| |
| /* Data structure for holding the four terms composing the CSD number. */ |
| typedef struct { |
| bool sign; |
| int power; |
| } term; |
| term t[CSD_NIBBLES + 1]; |
| t[0].power = 0; |
| t[0].sign = 0; |
| |
| /* |
| * Split the 2.14 value into a sum of powers of 2, |
| * s1 * 2^p1 + s2 * 2^p2 + s3 * 2^p3 + s4 * 2^p4 |
| * where for term x, |
| * sx = 1 or -1, |
| * px <= 0. |
| */ |
| for (n = 1; n <= CSD_NIBBLES; n++) { |
| |
| if (sum == fixed) break; |
| |
| /* |
| * If current sum is less than actual value, then the next term |
| * should be added; otherwise the next term should be |
| * subtracted. |
| */ |
| if (sum < fixed) { |
| t[n].sign = 0; |
| error = fixed - sum; |
| } else { |
| t[n].sign = 1; |
| error = sum - fixed; |
| } |
| |
| /* If error > 1, then term = +/-1. */ |
| if (error > 0x4000) { |
| t[n].power = 0; |
| } else { |
| |
| /* |
| * Calculate greaterPower = the smallest power of 2 greater |
| * than error. Calculate smallerPower = the largest power |
| * of 2 less than error. |
| */ |
| greaterPower = 0x4000; gp = 0; |
| for (power = 0x2000; power > error; power >>= 1) { |
| greaterPower >>= 1; gp--; |
| } |
| smallerPower = greaterPower >> 1; sp = gp - 1; |
| |
| /* |
| * Is error closer to greaterPower or smallerPower? |
| * Whichever is closer, choose that for the value of the |
| * next term. |
| */ |
| distGreater = greaterPower - error; |
| distSmaller = error - smallerPower; |
| if (distGreater < distSmaller) { |
| t[n].power = gp; |
| } else { |
| t[n].power = sp; |
| } |
| |
| /* |
| * The power of this term can differ from the power of the |
| * previous term by no more than 7. |
| */ |
| if (t[n - 1].power - t[n].power > 7) { |
| t[n].power = t[n - 1].power - 7; |
| } |
| } |
| |
| /* Add or subtract the term to the sum, depending on sign. */ |
| if (t[n].sign == 0) { |
| sum += (uint16)1 << (14 + t[n].power); |
| } else { |
| sum -= (uint16)1 << (14 + t[n].power); |
| } |
| } |
| |
| /* |
| * If we reached the exact value with terms left over, fill these |
| * extra terms with dummy values which don't affect the CSD value. |
| */ |
| while (n <= CSD_NIBBLES) { |
| if (n == 1) { |
| t[1] = t[0]; |
| t[2].power = 0; |
| t[2].sign = 1; |
| n += 2; |
| } else { |
| /* |
| * Increase the number of terms by replacing the last term |
| * with two new terms whose sum is the old term. |
| */ |
| if (t[n - 1].power == t[n - 2].power) { |
| t[n - 1].power--; |
| t[n] = t[n - 1]; |
| } else { |
| t[n] = t[n - 1]; |
| t[n - 1].power++; |
| t[n].sign = !(t[n - 1].sign); |
| } |
| n++; |
| } |
| } |
| |
| /* Compute nibble values from the terms. */ |
| result = 0; |
| for (n = 1; n <= CSD_NIBBLES; n++) { |
| int8 bitPos = (n - 1) * 4; |
| C = (t[n].sign != t[n - 1].sign); |
| m = -(t[n].power - t[n - 1].power); |
| result |= (C << (bitPos + 3)) | (m << bitPos); |
| } |
| |
| /* Split the uint16 result into high and low bytes. */ |
| csdBuf[0] = (uint8)(result >> 8); |
| csdBuf[1] = (uint8)(result & 0xFF); |
| } /* VpConvertFixed2Csd() */ |
| #endif |
| #endif |
| |
| #if (defined(VP_CC_890_SERIES) && defined(VP890_INCLUDE_TESTLINE_CODE)) \ |
| || (defined(VP_CC_880_SERIES) && defined(VP880_INCLUDE_TESTLINE_CODE)) \ |
| || defined(VP_CC_792_SERIES) |
| uint16 |
| VpComputeSquareRoot( |
| uint32 number) |
| { |
| uint8 iteration; |
| int32 sqrtEst = 2; |
| const int32 sqrtShift = number / 2; |
| const uint8 newtonItt = 3; |
| |
| /* |
| * Find an estimate of the result in the correct octave |
| * (approximately 1.5 bits of accuracy) |
| */ |
| while ((sqrtEst * sqrtEst) < sqrtShift) { |
| sqrtEst *= 2; |
| } |
| |
| /* |
| * Use Newton's iteration to improve the estimate of the square root |
| * If the accuracy is N bits, on Newton's iteration increase the accuracy |
| * to 2N+1 bits. |
| */ |
| for (iteration = 0; iteration < newtonItt; iteration++) { |
| if (0 == sqrtEst) { |
| break; |
| } else { |
| sqrtEst = (sqrtEst + (number / sqrtEst)) / 2 ; |
| } |
| } |
| |
| return (uint16)sqrtEst; |
| } |
| #endif |
| |
| /** |
| * VpMemCpyCheck - Copy one area of memory to another while checking if any of |
| * the data changed. |
| * |
| * @dest: Where to copy to |
| * @src: Where to copy from |
| * @count: The size of the area. |
| * |
| * Return: TRUE if any of the data from-to was different. |
| */ |
| EXTERN bool |
| VpMemCpyCheck( |
| uint8 *dest, |
| uint8 *src, |
| uint16 count) |
| { |
| bool dataChange = FALSE; |
| uint16 currentIndex = 0; |
| |
| while (currentIndex < count) { |
| currentIndex++; |
| if (dest[currentIndex] != src[currentIndex]) { |
| dataChange = TRUE; |
| dest[currentIndex] = src[currentIndex]; |
| } |
| } |
| return dataChange; |
| } |
| |
| /** |
| * memcpy - Copy one area of memory to another |
| * @dest: Where to copy to |
| * @src: Where to copy from |
| * @count: The size of the area. |
| * |
| */ |
| EXTERN void * |
| VpMemCpy( |
| void * dest, |
| const void *src, |
| uint16 count) |
| { |
| char *tmp = (char *) dest, *s = (char *) src; |
| |
| while (count--) |
| *tmp++ = *s++; |
| |
| return dest; |
| } |
| |
| /** |
| * memset - Fill a region of memory with the given value |
| * @s: Pointer to the start of the area. |
| * @c: The byte to fill the area with |
| * @count: The size of the area. |
| */ |
| EXTERN void * |
| VpMemSet( |
| void * s, |
| int c, |
| uint16 count) |
| { |
| char *xs = (char *) s; |
| |
| while (count--) |
| *xs++ = (char)c; |
| |
| return s; |
| } |
| |
| #if defined(VP_CC_790_SERIES) || defined(VP_CC_880_SERIES) \ |
| || defined(VP_CC_890_SERIES) || defined(VP_CC_580_SERIES) |
| /** |
| * Wrapper for VpMpiCmd() for purposes of providing VP_DBG_HAL output |
| */ |
| void |
| VpMpiCmdWrapper( |
| VpDeviceIdType deviceId, |
| uint8 ecVal, |
| uint8 mpiCmd, |
| uint8 mpiCmdLen, |
| uint8 *dataBuffer) |
| { |
| VpMpiCmd(deviceId, ecVal, mpiCmd, mpiCmdLen, dataBuffer); |
| |
| #if (VP_CC_DEBUG_SELECT & VP_DBG_HAL) |
| |
| #ifdef MPI_SHORT_FORMAT |
| if (mpiCmd == 0xCF) { |
| VP_HAL(None, NULL, ("Total Length: 17")); |
| } else { |
| VP_HAL(None, NULL, ("EC Value: 0x%02X Type: %s Cmd: 0x%02X Total Length: %d", |
| ecVal, ((mpiCmd & 0x1) ? "READ" : "WRITE"), mpiCmd, (3 + mpiCmdLen))); |
| } |
| #endif |
| #ifdef MPI_LONG_FORMAT |
| { |
| uint8 cmdIndex; |
| |
| if (mpiCmd == 0xCF) { |
| VP_HAL(None, NULL, ("Cmd 0xCF - Read Length: 17")); |
| } else if (mpiCmd == 0xCD) { |
| } else { |
| VP_HAL(None, NULL, ("EC 0x%02X %s Cmd 0x%02X", ecVal, ((mpiCmd & 0x1) ? "READ" : "WRITE"), mpiCmd)); |
| for (cmdIndex = 0; cmdIndex < mpiCmdLen; cmdIndex++) { |
| VP_HAL(None, NULL, (" 0x%02X", dataBuffer[cmdIndex])); |
| } |
| } |
| } |
| #endif |
| #ifdef MPI_CMD_SEARCH |
| { |
| int16 cmdIndex = VpMpiFindCmd(MPI_CMD_TO_FIND, mpiCmd, mpiCmdLen, dataBuffer); |
| |
| if (cmdIndex >= 0) { |
| VP_HAL(None, NULL, ("%s Cmd 0x%02X", ((mpiCmd & 0x1) ? "READ" : "WRITE"), MPI_CMD_TO_FIND)); |
| cmdIndex = ((mpiCmd == MPI_CMD_TO_FIND) ? 0 : 1); |
| for (; cmdIndex < mpiCmdLen; cmdIndex++) { |
| VP_HAL(None, NULL, (" 0x%02X", dataBuffer[cmdIndex])); |
| } |
| } |
| } |
| #endif |
| #endif |
| } |
| |
| #if (VP_CC_DEBUG_SELECT & VP_DBG_HAL) && defined (MPI_CMD_SEARCH) |
| /** |
| * Function primarily used to find a specific write command that is part of the |
| * MPI data buffer. A simple implementation looks just through the data buffer |
| * for a raw match, which could come from MPI data rather than command. A more |
| * complex implementation could use known commands+cmd_len to match for commands |
| * only. |
| */ |
| int16 |
| VpMpiFindCmd( |
| uint8 byteMatch, |
| uint8 mpiCmd, |
| uint8 mpiCmdLen, |
| uint8 *dataBuffer) |
| { |
| int16 indexCnt = 0; |
| if (mpiCmd == byteMatch) { |
| return 0; |
| } |
| |
| for (indexCnt = 0; indexCnt < mpiCmdLen; indexCnt++) { |
| if (dataBuffer[indexCnt] == byteMatch) { |
| return indexCnt; |
| } |
| } |
| return -1; |
| } |
| #endif |
| |
| /* Used for buffering MPI data to reduce MPI traffic */ |
| uint8 |
| VpCSLACBuildMpiBuffer( |
| uint8 index, |
| uint8 *mpiBuffer, |
| uint8 mpiCmd, |
| uint8 mpiCmdLen, |
| uint8 *mpiData) |
| { |
| mpiBuffer[index++] = mpiCmd; |
| VpMemCpy(&mpiBuffer[index], mpiData, (uint16)mpiCmdLen); |
| |
| return (index + mpiCmdLen); |
| } |
| #endif |