blob: 777a9c09a382985ee1014011c616a4b9f21f73f2 [file] [log] [blame]
/** \file vp880_query.c
* vp880_query.c
*
* This file contains the query functions used in the Vp880 device API.
*
* Copyright (c) 2011, Microsemi
*
* $Revision: 1.1.2.1.8.3 $
* $LastChangedDate: 2011-12-08 18:46:59 -0600 (Thu, 08 Dec 2011) $
*/
#include "../includes/vp_api_cfg.h"
#if defined (VP_CC_880_SERIES)
/* Project Includes */
#include "../../arch/uvb/vp_api_types.h"
#include "../../arch/uvb/sys_service.h"
#include "../../arch/uvb/vp_hal.h"
#include "../includes/vp_api_int.h"
#include "../includes/vp880_api.h"
#include "../vp880_api/vp880_api_int.h"
#ifdef VP880_INCLUDE_TESTLINE_CODE
#include "../includes/vp_api_test.h"
#endif
/* Private Functions */
static uint16 Vp880CheckLineEvent(uint16 event, uint16 eventMask,
VpEventCategoryType eventCat, Vp880LineObjectType *pLineObj);
static uint16 Vp880CheckDevEvent(uint16 event, uint16 eventMask,
VpEventCategoryType eventCat, Vp880DeviceObjectType *pDevObj);
#ifdef VP880_ABS_SUPPORT
static void Vp880DevRingExitTimerHandler(VpDevCtxType *pDevCtx);
#endif
#ifdef VP880_FXS_SUPPORT
static void Vp880ServiceFxsTimers(VpLineCtxType *pLineCtx);
#ifdef VP880_LP_SUPPORT
static void Vp880UpdateHookInfo(Vp880LineObjectType *pLineObj, Vp880DeviceObjectType *pDevObj);
static void Vp880ServiceLpChangeTimer(VpDevCtxType *pDevCtx);
#endif /* VP880_LP_SUPPORT */
static void Vp880ServiceGroundStartTimer(VpLineCtxType *pLineCtx);
#endif /* VP880_FXS_SUPPORT */
#ifdef VP880_FXO_SUPPORT
static void Vp880ServiceFxoTimers(VpLineCtxType *pLineCtx);
#endif /* VP880_FXO_SUPPORT */
static VpStatusType
Vp880GetDeviceOption(VpDevCtxType *pDevCtx, VpOptionIdType option,
uint16 handle);
#if (VP_CC_DEBUG_SELECT & VP_DBG_ERROR)
static void
VpPrint880CalLineData(
Vp880CalLineData *calLineData);
#endif
/**
* Vp880FindSoftwareInterrupts()
* This function checks for active non-masked device and line events.
*
* Preconditions:
* None.
*
* Postconditions:
* Returns true if there is an active, non-masked event on either the device
* or on a line associated with the device.
*/
bool
Vp880FindSoftwareInterrupts(
VpDevCtxType *pDevCtx)
{
Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj;
Vp880LineObjectType *pLineObj;
VpLineCtxType *pLineCtx;
uint8 channelId;
uint8 maxChan = pDevObj->staticInfo.maxChannels;
VpOptionEventMaskType eventsMask = pDevObj->deviceEventsMask;
VpOptionEventMaskType *pEvents = &(pDevObj->deviceEvents);
/* First clear all device events that are masked */
pEvents->faults &= ~(eventsMask.faults);
pEvents->signaling &= ~(eventsMask.signaling);
pEvents->response &= ~(eventsMask.response);
pEvents->process &= ~(eventsMask.process);
pEvents->test &= ~(eventsMask.test);
pEvents->fxo &= ~(eventsMask.fxo);
/* Evaluate if any events remain */
if((pEvents->faults) || (pEvents->signaling) || (pEvents->response)
|| (pEvents->process) || (pEvents->test) || (pEvents->fxo)) {
return TRUE;
}
for (channelId = 0; channelId < maxChan; channelId++) {
pLineCtx = pDevCtx->pLineCtx[channelId];
if(pLineCtx != VP_NULL) {
pLineObj = pLineCtx->pLineObj;
eventsMask = pLineObj->lineEventsMask;
pEvents = &(pLineObj->lineEvents);
/* Clear the line events that are masked */
pEvents->faults &= ~(eventsMask.faults);
pEvents->signaling &= ~(eventsMask.signaling);
pEvents->response &= ~(eventsMask.response);
pEvents->process &= ~(eventsMask.process);
pEvents->test &= ~(eventsMask.test);
pEvents->fxo &= ~(eventsMask.fxo);
/* Evaluate if any events remain */
if(pEvents->faults || pEvents->signaling || pEvents->response
|| pEvents->process || pEvents->test || pEvents->fxo) {
return TRUE;
}
}
}
return FALSE;
}
/**
* Vp880GetEvent()
* This function reports new events that occured on the device. This function
* returns one event for each call to it. It should be called repeatedly until
* no more events are reported for a specific device. This function does not
* access the device, it returns status from the phantom registers that are
* maintained by the API tick routine.
*
* Preconditions:
* None. All error checking required is assumed to exist in common interface
* file.
*
* Postconditions:
* Returns true if there is an active event for the device.
*/
bool
Vp880GetEvent(
VpDevCtxType *pDevCtx,
VpEventType *pEvent) /**< Pointer to the results event structure */
{
Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj;
Vp880LineObjectType *pLineObj;
VpLineCtxType *pLineCtx;
VpDeviceIdType deviceId = pDevObj->deviceId;
uint8 i, eventCatLoop;
uint8 chan, chanNum;
uint8 maxChan = pDevObj->staticInfo.maxChannels;
#if defined (VP880_INCLUDE_TESTLINE_CODE) && defined (VP880_FXO_SUPPORT)
#define EVENT_ARRAY_SIZE 6
#elif defined (VP880_INCLUDE_TESTLINE_CODE) || defined (VP880_FXO_SUPPORT)
#define EVENT_ARRAY_SIZE 5
#else
#define EVENT_ARRAY_SIZE 4
#endif
uint16 eventArray[EVENT_ARRAY_SIZE];
uint16 eventMaskArray[EVENT_ARRAY_SIZE];
VpEventCategoryType eventCat[EVENT_ARRAY_SIZE] = {
VP_EVCAT_FAULT,
VP_EVCAT_SIGNALING,
VP_EVCAT_RESPONSE,
VP_EVCAT_PROCESS
#ifdef VP880_FXO_SUPPORT
,VP_EVCAT_FXO
#endif
#ifdef VP880_INCLUDE_TESTLINE_CODE
,VP_EVCAT_TEST
#endif
};
VP_API_FUNC(VpDevCtxType, pDevCtx, ("Vp880GetEvent+"));
pEvent->status = VP_STATUS_SUCCESS;
pEvent->hasResults = FALSE;
/* Initialize the arrays for device events */
for (i = 0; i < EVENT_ARRAY_SIZE; i++) {
switch(eventCat[i]) {
case VP_EVCAT_FAULT:
eventArray[i] = pDevObj->deviceEvents.faults;
eventMaskArray[i] = pDevObj->deviceEventsMask.faults;
break;
case VP_EVCAT_SIGNALING:
eventArray[i] = pDevObj->deviceEvents.signaling;
eventMaskArray[i] = pDevObj->deviceEventsMask.signaling;
break;
case VP_EVCAT_RESPONSE:
eventArray[i] = pDevObj->deviceEvents.response;
eventMaskArray[i] = pDevObj->deviceEventsMask.response;
break;
case VP_EVCAT_PROCESS:
eventArray[i] = pDevObj->deviceEvents.process;
eventMaskArray[i] = pDevObj->deviceEventsMask.process;
break;
#ifdef VP880_FXO_SUPPORT
case VP_EVCAT_FXO:
eventArray[i] = pDevObj->deviceEvents.fxo;
eventMaskArray[i] = pDevObj->deviceEventsMask.fxo;
break;
#endif
#ifdef VP880_INCLUDE_TESTLINE_CODE
case VP_EVCAT_TEST:
eventArray[i] = pDevObj->deviceEvents.test;
eventMaskArray[i] = pDevObj->deviceEventsMask.test;
break;
#endif
default:
/*
* This can only occur if there's a bug in this code. Get out
* since we don't know how to handle it.
*/
return FALSE;
}
}
VpSysEnterCritical(deviceId, VP_CODE_CRITICAL_SEC);
/* Look for active device events first */
for (eventCatLoop = 0; eventCatLoop < EVENT_ARRAY_SIZE; eventCatLoop++) {
pEvent->eventId = Vp880CheckDevEvent(eventArray[eventCatLoop],
eventMaskArray[eventCatLoop], eventCat[eventCatLoop], pDevObj);
if (pEvent->eventId != 0x0000) {
pEvent->deviceId = deviceId;
pEvent->channelId = 0;
pEvent->eventCategory = eventCat[eventCatLoop];
pEvent->pDevCtx = pDevCtx;
pEvent->pLineCtx = VP_NULL;
pEvent->parmHandle = pDevObj->eventHandle;
pEvent->hasResults = FALSE;
if (pEvent->eventCategory == VP_EVCAT_RESPONSE) {
/*
* For the events that require a read operation, set the has
* results indicator in the event structure
*/
switch (pEvent->eventId) {
case VP_LINE_EVID_RD_OPTION:
pEvent->channelId = pDevObj->getResultsOption.chanId;
pEvent->pLineCtx = pDevCtx->pLineCtx[pEvent->channelId];
if (pEvent->pLineCtx != VP_NULL) {
Vp880LineObjectType *pLineObjLocal = pEvent->pLineCtx->pLineObj;
pEvent->lineId = pLineObjLocal->lineId;
}
pEvent->hasResults = TRUE;
pEvent->eventData = pDevObj->getResultsOption.optionType;
break;
case VP_DEV_EVID_IO_ACCESS_CMP:
pEvent->eventData =
(uint16)(pDevObj->getResultsOption.optionData.deviceIoData.accessType);
if (pEvent->eventData == VP_DEVICE_IO_READ) {
pEvent->hasResults = TRUE;
} else {
pEvent->hasResults = FALSE;
}
break;
case VP_DEV_EVID_DEV_INIT_CMP:
pEvent->eventData = 1;
break;
case VP_EVID_CAL_CMP:
pEvent->eventData = (uint16)pDevObj->responseData;
break;
default:
break;
}
}
if (pEvent->eventCategory == VP_EVCAT_FAULT) {
switch(pEvent->eventId) {
case VP_DEV_EVID_CLK_FLT:
pEvent->eventData =
(pDevObj->dynamicInfo.clkFault ? TRUE : FALSE);
break;
case VP_DEV_EVID_BAT_FLT:
if ((pDevObj->dynamicInfo.bat1Fault == TRUE)
|| (pDevObj->dynamicInfo.bat2Fault == TRUE)
|| (pDevObj->dynamicInfo.bat3Fault == TRUE)) {
pEvent->eventData = TRUE;
} else {
pEvent->eventData = FALSE;
}
break;
default:
break;
}
}
/*
* "Some" device event needs to be generated. Don't proceed with
* line event processing.
*/
VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC);
return TRUE;
}
}
/*
* No device events, now look for Line events -- but make sure the line
* context is valid before looking for a line object
*/
if (pDevObj->dynamicInfo.lastChan >= maxChan) {
pDevObj->dynamicInfo.lastChan = 0;
}
chanNum = pDevObj->dynamicInfo.lastChan;
for(chan = 0; chan < maxChan; chan++) {
pLineCtx = pDevCtx->pLineCtx[chanNum];
if (pLineCtx != VP_NULL) {
pLineObj = pLineCtx->pLineObj;
/* The line context is valid, create a line object and initialize
* the event arrays for this line
*/
for (i = 0; i < EVENT_ARRAY_SIZE; i++) {
switch(eventCat[i]) {
case VP_EVCAT_FAULT:
eventArray[i] = pLineObj->lineEvents.faults;
eventMaskArray[i] = pLineObj->lineEventsMask.faults;
break;
case VP_EVCAT_SIGNALING:
eventArray[i] = pLineObj->lineEvents.signaling;
eventMaskArray[i] = pLineObj->lineEventsMask.signaling;
break;
case VP_EVCAT_RESPONSE:
eventArray[i] = pLineObj->lineEvents.response;
eventMaskArray[i] = pLineObj->lineEventsMask.response;
break;
case VP_EVCAT_PROCESS:
eventArray[i] = pLineObj->lineEvents.process;
eventMaskArray[i] = pLineObj->lineEventsMask.process;
break;
#ifdef VP880_FXO_SUPPORT
case VP_EVCAT_FXO:
eventArray[i] = pLineObj->lineEvents.fxo;
eventMaskArray[i] = pLineObj->lineEventsMask.fxo;
break;
#endif
#ifdef VP880_INCLUDE_TESTLINE_CODE
case VP_EVCAT_TEST:
eventArray[i] = pLineObj->lineEvents.test;
eventMaskArray[i] = pLineObj->lineEventsMask.test;
break;
#endif
default:
/*
* This can only occur if there's a bug in this code. Get out
* since we don't know how to handle it.
*/
VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC);
return FALSE;
}
}
/* Check this line events */
for (eventCatLoop = 0;
eventCatLoop < EVENT_ARRAY_SIZE;
eventCatLoop++) {
pEvent->eventId = Vp880CheckLineEvent(eventArray[eventCatLoop],
eventMaskArray[eventCatLoop], eventCat[eventCatLoop],
pLineObj);
if (pEvent->eventId != 0x0000) {
pEvent->deviceId = deviceId;
pEvent->channelId = chanNum;
pEvent->pLineCtx = pDevCtx->pLineCtx[chanNum];
pEvent->pDevCtx = pDevCtx;
pEvent->eventCategory = eventCat[eventCatLoop];
pEvent->parmHandle = pLineObj->lineEventHandle;
pEvent->lineId = pLineObj->lineId;
pEvent->hasResults = FALSE;
switch(pEvent->eventCategory) {
case VP_EVCAT_RESPONSE:
pEvent->eventData = (uint16)pLineObj->responseData;
switch(pEvent->eventId) {
#if !defined(VP_REDUCED_API_IF) || defined(ZARLINK_CFG_INTERNAL)
case VP_LINE_EVID_LLCMD_RX_CMP:
pEvent->eventData = pDevObj->mpiLen;
#endif
case VP_LINE_EVID_GAIN_CMP:
case VP_LINE_EVID_RD_LOOP:
pEvent->hasResults = TRUE;
break;
case VP_EVID_CAL_CMP:
if (pLineObj->responseData == (uint8)VP_CAL_GET_SYSTEM_COEFF) {
pEvent->eventData = pDevObj->mpiLen;
pEvent->hasResults = TRUE;
/*
* Prevent future cal complete events from being
* indicated as having results data.
*/
pLineObj->responseData = (uint8)VP_CAL_ENUM_SIZE;
}
break;
default:
break;
}
break;
case VP_EVCAT_SIGNALING:
if (pEvent->eventId == VP_LINE_EVID_DTMF_DIG) {
/*
* Upper bits are used for the timestamp.
* Lower bits are used for the digit and the
* make/break bit.
*/
pEvent->eventData = (pDevObj->timeStamp << 5)
| pLineObj->dtmfDigitSense;
} else {
pEvent->eventData = pLineObj->signalingData;
if (pEvent->eventId == VP_LINE_EVID_HOOK_OFF) {
pLineObj->status |= VP880_PREVIOUS_HOOK;
} else if (pEvent->eventId == VP_LINE_EVID_HOOK_ON) {
pLineObj->status &= ~VP880_PREVIOUS_HOOK;
}
}
break;
#ifdef VP880_FXO_SUPPORT
case VP_EVCAT_FXO:
pEvent->eventData = pLineObj->fxoData;
break;
#endif
case VP_EVCAT_PROCESS:
pEvent->eventData = pLineObj->processData;
break;
case VP_EVCAT_FAULT:
if (pEvent->eventId == VP_LINE_EVID_THERM_FLT) {
if ((pDevObj->intReg2[chanNum] & VP880_TEMPA1_MASK) !=
(pDevObj->intReg[chanNum] & VP880_TEMPA1_MASK)) {
pEvent->eventData = (pDevObj->intReg2[chanNum] & VP880_TEMPA1_MASK)
? TRUE : FALSE;
pLineObj->lineEvents.faults |= VP_LINE_EVID_THERM_FLT;
pDevObj->intReg2[chanNum] &= ~VP880_TEMPA1_MASK;
pDevObj->intReg2[chanNum] |= (pDevObj->intReg[chanNum] & VP880_TEMPA1_MASK);
} else {
pEvent->eventData = (pDevObj->intReg[chanNum] & VP880_TEMPA1_MASK)
? TRUE : FALSE;
}
}
break;
#if defined (VP880_INCLUDE_TESTLINE_CODE)
case VP_EVCAT_TEST:
if ( VP_LINE_EVID_TEST_CMP == pEvent->eventId) {
pEvent->eventData = pDevObj->testResults.testId;
pEvent->hasResults = TRUE;
}
break;
#endif
default:
/*
* This can only occur if there's a bug in this code. Get out
* since we don't know how to handle it.
*/
VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC);
VP_API_FUNC(VpDevCtxType, pDevCtx, ("Vp880GetEvent Error - Unknown Line Event Category"));
return FALSE;
}
VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC);
return TRUE;
}
}
}
/* We're done with this channel, start on next */
chanNum = ((chanNum == 0) ? 1 : 0);
pDevObj->dynamicInfo.lastChan = chanNum;
}
/* Actually, should never reach here. Just cleanup and exit quietly. */
VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC);
VP_API_FUNC(VpDevCtxType, pDevCtx, ("Vp880GetEvent-"));
return FALSE;
} /* End Vp880GetEvent */
/**
* Vp880CheckDevEvent()
* This function performs a check on active device events and compares the
* event with the event mask. The event is cleared, and if the event is
* unmasked it gets returned to the calling function via the return value.
*
* Preconditions:
* None. This is an internal API function call only and it is assumed all error
* checking necessary is performed by higher level functions.
*
* Postconditions:
* If the returned value is other than 0x0000, the event being returned is
* cleared in the device object.
*/
uint16
Vp880CheckDevEvent(
uint16 event,
uint16 eventMask,
VpEventCategoryType eventCat,
Vp880DeviceObjectType *pDevObj)
{
uint8 i;
uint16 mask;
VP_API_FUNC_INT(None, NULL, ("Vp880CheckDevEvent+"));
for (i = 0, mask = 0x0001; i < 16; i++, (mask = mask << 1)) {
/* Check to see if an event MAY be reported */
if ((mask & event) != 0) {
/*
* Have to clear the device event so we don't report this event
* again
*/
switch(eventCat) {
case VP_EVCAT_FAULT:
pDevObj->deviceEvents.faults &= (~mask);
break;
case VP_EVCAT_SIGNALING:
pDevObj->deviceEvents.signaling &= (~mask);
break;
case VP_EVCAT_RESPONSE:
pDevObj->deviceEvents.response &= (~mask);
break;
case VP_EVCAT_PROCESS:
pDevObj->deviceEvents.process &= (~mask);
break;
case VP_EVCAT_FXO:
pDevObj->deviceEvents.fxo &= (~mask);
break;
#ifdef VP880_INCLUDE_TESTLINE_CODE
case VP_EVCAT_TEST:
pDevObj->deviceEvents.test &= (~mask);
break;
#endif
default:
break;
}
/* If the event is not masked, return the event */
if ((mask & eventMask) == 0) {
VP_API_FUNC_INT(None, NULL, ("Vp880CheckDevEvent-"));
return mask;
}
}
}
VP_API_FUNC_INT(None, NULL, ("Vp880CheckDevEvent-"));
return 0x0000;
}
/**
* Vp880CheckLineEvent()
* This function performs a check on active line events and compares the
* event with the event mask. The event is cleared, and if the event is
* unmasked it gets returned to the calling function via the return value.
*
* Preconditions:
* None. This is an internal API function call only and it is assumed all error
* checking necessary is performed by higher level functions.
*
* Postconditions:
* If the returned value is other than 0x0000, the event being returned is
* cleared in the line object.
*/
uint16
Vp880CheckLineEvent(
uint16 event,
uint16 eventMask,
VpEventCategoryType eventCat,
Vp880LineObjectType *pLineObj)
{
uint8 i;
uint16 mask;
VP_API_FUNC_INT(None, NULL, ("Vp880CheckLineEvent+"));
for (i = 0, mask = 0x0001; i < 16; i++, (mask = mask << 1)) {
/* Check to see if an event MAY be reported */
if ((mask & event) != 0) {
/*
* Have to clear the line event so we don't report this event
* again
*/
switch(eventCat) {
case VP_EVCAT_FAULT:
pLineObj->lineEvents.faults &= (~mask);
break;
case VP_EVCAT_SIGNALING:
pLineObj->lineEvents.signaling &= (~mask);
break;
case VP_EVCAT_RESPONSE:
pLineObj->lineEvents.response &= (~mask);
break;
case VP_EVCAT_PROCESS:
pLineObj->lineEvents.process &= (~mask);
break;
case VP_EVCAT_FXO:
pLineObj->lineEvents.fxo &= (~mask);
break;
#ifdef VP880_INCLUDE_TESTLINE_CODE
case VP_EVCAT_TEST:
pLineObj->lineEvents.test &= (~mask);
break;
#endif
default:
break;
}
/* If the event is not masked, return the event */
if ((mask & eventMask) == 0) {
VP_API_FUNC_INT(None, NULL, ("Vp880CheckLineEvent-"));
return mask;
}
}
}
VP_API_FUNC_INT(None, NULL, ("Vp880CheckLineEvent-"));
return 0x0000;
}
/**
* Vp880GetOption()
* This function accesses the option being requested, fills the device object
* with the data to be returned, and sets the Read Option complete event.
*
* Preconditions:
* None. All error checking required is assumed to exist in common interface
* file.
*
* Postconditions:
* The device object is filled with the results of the option type being
* requested and the Read Option Event flag is set. This function returns the
* success code if the option type being requested is supported.
*/
VpStatusType
Vp880GetOption(
VpLineCtxType *pLineCtx,
VpDevCtxType *pDevCtx,
VpOptionIdType option,
uint16 handle)
{
Vp880LineObjectType *pLineObj;
Vp880DeviceObjectType *pDevObj;
VpStatusType status = VP_STATUS_SUCCESS;
VpGetResultsOptionsDataType *pOptionData;
uint8 channelId, txSlot, rxSlot, pcn;
VpDeviceIdType deviceId;
#ifdef VP880_FXS_SUPPORT
uint8 tempSysConfig;
#endif
uint8 ecVal;
if (pLineCtx != VP_NULL) {
VpDevCtxType *pDevCtxLocal = pLineCtx->pDevCtx;
pDevObj = pDevCtxLocal->pDevObj;
pcn = pDevObj->staticInfo.rcnPcn[VP880_PCN_LOCATION];
deviceId = pDevObj->deviceId;
pLineObj = pLineCtx->pLineObj;
ecVal = pLineObj->ecVal;
channelId = pLineObj->channelId;
pOptionData = &(pDevObj->getResultsOption.optionData);
VP_API_FUNC(None, NULL, ("Vp880GetOption (Line)+"));
if (pDevObj->deviceEvents.response & VP880_READ_RESPONSE_MASK) {
VP_API_FUNC(VpLineCtxType, pLineCtx, ("Vp880GetOption (Line) Error - VP_STATUS_DEVICE_BUSY"));
return VP_STATUS_DEVICE_BUSY;
}
/* Do not allow FXS specific options on an FXO line */
if (pLineObj->status & VP880_IS_FXO) {
switch(option) {
case VP_OPTION_ID_ZERO_CROSS:
case VP_OPTION_ID_PULSE_MODE:
case VP_OPTION_ID_LINE_STATE:
case VP_OPTION_ID_RING_CNTRL:
VP_API_FUNC(VpLineCtxType, pLineCtx, ("Vp880GetOption (Line) Error - VP_STATUS_INVALID_ARG"));
return VP_STATUS_INVALID_ARG;
default:
break;
}
}
/*
* If this function can be executed, we will either access the MPI
* and/or shared data. So it is best to label the entire function as
* Code Critical so the data being accessed cannot be changed while
* trying to be accessed
*/
VpSysEnterCritical(deviceId, VP_CODE_CRITICAL_SEC);
pDevObj->getResultsOption.chanId = channelId;
switch (option) {
/* Line Options */
#ifdef CSLAC_GAIN_ABS
case VP_OPTION_ID_ABS_GAIN:
pOptionData->absGain.gain_AToD = pLineObj->gain.absGxGain;
pOptionData->absGain.gain_DToA = pLineObj->gain.absGrGain;
VP_LINE_STATE(VpLineCtxType, pLineCtx, ("Posting absGxGain = 0x%02X, absGrGain = 0x%02X",
(uint8)pOptionData->absGain.gain_AToD, (uint8)pOptionData->absGain.gain_DToA));
break;
#endif
#ifdef VP880_FXS_SUPPORT
case VP_OPTION_ID_PULSE_MODE:
pOptionData->pulseModeOption = pLineObj->pulseMode;
break;
#endif
case VP_OPTION_ID_TIMESLOT:
VpMpiCmdWrapper(deviceId, ecVal, VP880_TX_TS_RD,
VP880_TX_TS_LEN, &txSlot);
VpMpiCmdWrapper(deviceId, ecVal, VP880_RX_TS_RD,
VP880_RX_TS_LEN, &rxSlot);
pOptionData->timeSlotOption.tx = (txSlot & VP880_TX_TS_MASK);
if ((pcn == VP880_DEV_PCN_88536) || (pcn == VP880_DEV_PCN_88264)) {
pOptionData->timeSlotOption.tx++;
}
pOptionData->timeSlotOption.rx = (rxSlot & VP880_RX_TS_MASK);
break;
case VP_OPTION_ID_CODEC:
pOptionData->codecOption = pLineObj->codec;
break;
case VP_OPTION_ID_PCM_HWY:
pOptionData->pcmHwyOption = VP_OPTION_HWY_A;
break;
case VP_OPTION_ID_LOOPBACK:
/* Timeslot loopback via loopback register */
if ((pLineObj->opCond[0] & VP880_INTERFACE_LOOPBACK_EN) ==
VP880_INTERFACE_LOOPBACK_EN) {
pOptionData->loopBackOption = VP_OPTION_LB_TIMESLOT;
} else {
pOptionData->loopBackOption = VP_OPTION_LB_OFF;
}
break;
#ifdef VP880_FXS_SUPPORT
case VP_OPTION_ID_LINE_STATE:
/* Battery control is automatic, so force it */
pOptionData->lineStateOption.bat = VP_OPTION_BAT_AUTO;
/* Smooth/Abrupt PolRev is controlled in the device */
VpMpiCmdWrapper(deviceId, ecVal, VP880_SS_CONFIG_RD,
VP880_SS_CONFIG_LEN, &tempSysConfig);
if (tempSysConfig & VP880_SMOOTH_PR_EN) {
pOptionData->lineStateOption.battRev = FALSE;
} else {
pOptionData->lineStateOption.battRev = TRUE;
}
break;
#endif
case VP_OPTION_ID_EVENT_MASK:
/*
* In SetOption(), we force all line-specific bits in the
* deviceEventsMask to zero. Likewise, we force all device-
* specific bits in the lineEventsMask to zero. This allows
* us to simply OR the two together here.
*/
pOptionData->eventMaskOption.faults =
pLineObj->lineEventsMask.faults |
pDevObj->deviceEventsMask.faults;
pOptionData->eventMaskOption.signaling =
pLineObj->lineEventsMask.signaling |
pDevObj->deviceEventsMask.signaling;
pOptionData->eventMaskOption.response =
pLineObj->lineEventsMask.response |
pDevObj->deviceEventsMask.response;
pOptionData->eventMaskOption.test =
pLineObj->lineEventsMask.test |
pDevObj->deviceEventsMask.test;
pOptionData->eventMaskOption.process =
pLineObj->lineEventsMask.process |
pDevObj->deviceEventsMask.process;
pOptionData->eventMaskOption.fxo =
pLineObj->lineEventsMask.fxo |
pDevObj->deviceEventsMask.fxo;
break;
#ifdef VP880_FXS_SUPPORT
case VP_OPTION_ID_ZERO_CROSS:
pOptionData->zeroCross = pLineObj->ringCtrl.zeroCross;
break;
case VP_OPTION_ID_RING_CNTRL:
pOptionData->ringControlOption = pLineObj->ringCtrl;
break;
#endif
case VP_OPTION_ID_PCM_TXRX_CNTRL:
pOptionData->pcmTxRxCtrl = pLineObj->pcmTxRxCtrl;
break;
#ifdef VP880_FXS_SUPPORT
case VP_DEVICE_OPTION_ID_PULSE:
case VP_DEVICE_OPTION_ID_PULSE2:
case VP_DEVICE_OPTION_ID_CRITICAL_FLT:
#endif
case VP_DEVICE_OPTION_ID_DEVICE_IO:
status = Vp880GetDeviceOption(pDevCtxLocal, option, handle);
break;
default:
status = VP_STATUS_OPTION_NOT_SUPPORTED;
break;
}
VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC);
VP_API_FUNC(VpLineCtxType, pLineCtx, ("Vp880GetOption (Line)-"));
} else {
pDevObj = pDevCtx->pDevObj;
deviceId = pDevObj->deviceId;
VpSysEnterCritical(deviceId, VP_CODE_CRITICAL_SEC);
status = Vp880GetDeviceOption(pDevCtx, option, handle);
VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC);
}
if (status == VP_STATUS_SUCCESS) {
VpSysEnterCritical(deviceId, VP_CODE_CRITICAL_SEC);
pDevObj->getResultsOption.optionType = option;
pDevObj->deviceEvents.response |= VP_LINE_EVID_RD_OPTION;
pDevObj->eventHandle = handle;
VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC);
}
return status;
}
/**
* Vp880GetDeviceOption()
* This function accesses the option being requested, fills the device object
* with the data to be returned, and sets the Read Option complete event.
*
* Functions calling this function have to make sure Enter/Exit critical are
* called around this function.
*
* Preconditions:
* None. All error checking required is assumed to exist in common interface
* file.
*
* Postconditions:
* The device object is filled with the results of the option type being
* requested and the Read Option Event flag is set. This function returns the
* success code if the option type being requested is supported.
*/
VpStatusType
Vp880GetDeviceOption(
VpDevCtxType *pDevCtx,
VpOptionIdType option,
uint16 handle)
{
VpStatusType status = VP_STATUS_SUCCESS;
Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj;
VpGetResultsOptionsDataType *pOptionData;
VpDeviceIdType deviceId;
uint8 maxChan = pDevObj->staticInfo.maxChannels;
uint8 channelId;
uint8 ecVal = pDevObj->ecVal;
uint8 ioDirection[2] = {0x00, 0x00};
VP_API_FUNC(VpDevCtxType, pDevCtx, ("Vp880GetOption (Device)+"));
/*
* Upper layer checks to be sure that either device context or line
* context pointers are not null -- so the device context is not null
* in this case.
*/
pDevObj = pDevCtx->pDevObj;
deviceId = pDevObj->deviceId;
pOptionData = &(pDevObj->getResultsOption.optionData);
if (pDevObj->deviceEvents.response & VP880_READ_RESPONSE_MASK) {
VP_API_FUNC(VpDevCtxType, pDevCtx, ("Vp880GetOption (Device) Error - VP_STATUS_DEVICE_BUSY"));
return VP_STATUS_DEVICE_BUSY;
}
switch (option) {
#ifdef VP880_FXS_SUPPORT
case VP_DEVICE_OPTION_ID_PULSE:
pOptionData->pulseTypeOption = pDevObj->pulseSpecs;
break;
case VP_DEVICE_OPTION_ID_PULSE2:
pOptionData->pulseTypeOption = pDevObj->pulseSpecs2;
break;
case VP_DEVICE_OPTION_ID_CRITICAL_FLT:
pOptionData->criticalFaultOption = pDevObj->criticalFault;
break;
#endif
case VP_DEVICE_OPTION_ID_DEVICE_IO: {
uint8 pinCnt;
uint16 bitMask;
uint8 ecValMod[] = {VP880_EC_CH1, VP880_EC_CH2};
uint8 regMask[VP880_MAX_PINS_PER_LINE] = {0x00,
VP880_IODIR_IO2_OUTPUT, /* 0x04 */
VP880_IODIR_IO3_OUTPUT, /* 0x08 */
VP880_IODIR_IO4_OUTPUT, /* 0x10 */
VP880_IODIR_IO5_OUTPUT, /* 0x20 */
VP880_IODIR_IO6_OUTPUT, /* 0x40 */
};
ecVal = pDevObj->ecVal;
/*
* Preclear so only 'OR' operation for output and open drain
* indications are set.
*/
pOptionData->deviceIo.outputTypePins_63_32 = 0;
pOptionData->deviceIo.directionPins_63_32 = 0;
pOptionData->deviceIo.outputTypePins_31_0 = 0;
pOptionData->deviceIo.directionPins_31_0 = 0;
/* Get the current device IO control information */
for (channelId = 0; channelId < maxChan; channelId++) {
VpMpiCmdWrapper(deviceId, (ecVal | ecValMod[channelId]),
VP880_IODIR_REG_RD, VP880_IODIR_REG_LEN,
&ioDirection[channelId]);
}
for (channelId = 0; channelId < maxChan; channelId++) {
for (pinCnt = 0; pinCnt < VP880_MAX_PINS_PER_LINE; pinCnt++) {
bitMask = (1 << (channelId + 2 * pinCnt));
if (pinCnt == 0) {
/* I/O-1 has a "type" of output to be determined. */
if (ioDirection[channelId] & VP880_IODIR_IO1_OPEN_DRAIN) {
pOptionData->deviceIo.outputTypePins_31_0 |= bitMask;
pOptionData->deviceIo.directionPins_31_0 |= bitMask;
} else if (ioDirection[channelId] & VP880_IODIR_IO1_OUTPUT) {
pOptionData->deviceIo.directionPins_31_0 |= bitMask;
}
} else {
/*
* All other pins are driven output only. Just need
* to determine IF they are configured for output.
*/
if (ioDirection[channelId] & regMask[pinCnt]) {
pOptionData->deviceIo.directionPins_31_0 |= bitMask;
}
}
}
}
}
break;
#ifdef VP880_FXS_SUPPORT
case VP_OPTION_ID_PULSE_MODE:
case VP_OPTION_ID_LINE_STATE:
case VP_OPTION_ID_ZERO_CROSS:
case VP_OPTION_ID_RING_CNTRL:
#endif
case VP_OPTION_ID_TIMESLOT:
case VP_OPTION_ID_CODEC:
case VP_OPTION_ID_PCM_HWY:
case VP_OPTION_ID_LOOPBACK:
case VP_OPTION_ID_PCM_TXRX_CNTRL:
case VP_OPTION_ID_EVENT_MASK:
#ifdef CSLAC_GAIN_ABS
case VP_OPTION_ID_ABS_GAIN:
#endif
status = VP_STATUS_INVALID_ARG;
VP_API_FUNC(VpDevCtxType, pDevCtx, ("Vp880GetOption (Device) Error - VP_STATUS_INVALID_ARG"));
break;
default:
status = VP_STATUS_OPTION_NOT_SUPPORTED;
VP_API_FUNC(VpDevCtxType, pDevCtx, ("Vp880GetOption (Device) Error - VP_STATUS_OPTION_NOT_SUPPORTED"));
break;
}
VP_API_FUNC(VpDevCtxType, pDevCtx, ("Vp880GetOption (Device)-"));
return status;
}
/**
* Vp880GetDeviceStatus()
* This function returns the status of all lines on a device for the type being
* requested.
*
* Preconditions:
* None. All error checking required is assumed to exist in common interface
* file.
*
* Postconditions:
* The location pointed to by the uint32 pointer passed is set (on a per line
* basis) to either '1' if the status if TRUE on the given line, or '0' if the
* status is FALSE on the given line for the status being requested.
*/
VpStatusType
Vp880GetDeviceStatus(
VpDevCtxType *pDevCtx,
VpInputType input,
uint32 *pDeviceStatus)
{
Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj;
uint8 maxChan = pDevObj->staticInfo.maxChannels;
uint8 channelId;
bool status = FALSE;
VpLineCtxType *pLineCtx;
VP_API_FUNC(VpDevCtxType, pDevCtx, ("Vp880GetDeviceStatus+"));
*pDeviceStatus = 0;
for (channelId = 0; channelId < maxChan; channelId++) {
pLineCtx = pDevCtx->pLineCtx[channelId];
if(pLineCtx != VP_NULL) {
VpCSLACGetLineStatus(pLineCtx, input, &status);
} else {
status = FALSE;
}
*pDeviceStatus |= (((status == TRUE) ? 1 : 0) << channelId);
}
VP_API_FUNC(VpDevCtxType, pDevCtx, ("Vp880GetDeviceStatus-"));
return VP_STATUS_SUCCESS;
}
/**
* Vp880FlushEvents()
* This function clears out all events on the device and all events on all
* lines associated with the device passed.
*
* Preconditions:
* None. All error checking required is assumed to exist in common interface
* file.
*
* Postconditions:
* All active device events are cleared, and all active line events associated
* with this device are cleared.
*/
VpStatusType
Vp880FlushEvents(
VpDevCtxType *pDevCtx)
{
Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj;
VpDeviceIdType deviceId = pDevObj->deviceId;
VpLineCtxType *pLineCtx;
Vp880LineObjectType *pLineObj;
uint8 channelId;
uint8 maxChan = pDevObj->staticInfo.maxChannels;
VP_API_FUNC(VpDevCtxType, pDevCtx, ("Vp880FlushEvents+"));
VpSysEnterCritical(deviceId, VP_CODE_CRITICAL_SEC);
VpMemSet(&pDevObj->deviceEvents, 0, sizeof(VpOptionEventMaskType));
for (channelId = 0; channelId < maxChan; channelId++) {
pLineCtx = pDevCtx->pLineCtx[channelId];
if(pLineCtx != VP_NULL) {
pLineObj = pLineCtx->pLineObj;
VpMemSet(&pLineObj->lineEvents, 0, sizeof(VpOptionEventMaskType));
}
}
VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC);
VP_API_FUNC(VpDevCtxType, pDevCtx, ("Vp880FlushEvents"));
return VP_STATUS_SUCCESS;
}
/**
* Vp880GetResults()
* This function fills the results structure passed with the results data found
* from the event that caused new results.
*
* Preconditions:
* None. All error checking required is assumed to exist in common interface
* file.
*
* Postconditions:
* If the event structure passed provides the event catagory and ID for a valid
* results type to read, then the structure passed is filled with the results
* data. This function returns the success code if the event catagory and ID is
* supported by the device.
*/
VpStatusType
Vp880GetResults(
VpEventType *pEvent,
void *pResults)
{
VpDevCtxType *pDevCtx = pEvent->pDevCtx;
Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj;
VpDeviceIdType deviceId = pDevObj->deviceId;
VpStatusType status = VP_STATUS_SUCCESS;
#if !defined(VP_REDUCED_API_IF) || defined(ZARLINK_CFG_INTERNAL)
uint8 mpiDataLen = pDevObj->mpiLen;
#endif
uint8 commandByte;
uint8 *pMpiData;
VpGetResultsOptionsDataType *pOptionData =
&(pDevObj->getResultsOption.optionData);
VP_API_FUNC(VpDevCtxType, pDevCtx, ("Vp880GetResults+"));
VpSysEnterCritical(deviceId, VP_CODE_CRITICAL_SEC);
switch(pEvent->eventCategory) {
case VP_EVCAT_RESPONSE:
switch (pEvent->eventId) {
#if !defined(VP_REDUCED_API_IF) || defined(ZARLINK_CFG_INTERNAL)
case VP_LINE_EVID_LLCMD_RX_CMP:
pMpiData = (uint8 *)pResults;
VpMemCpy(pMpiData, pDevObj->mpiData, mpiDataLen);
break;
#endif
case VP_LINE_EVID_GAIN_CMP:
*(VpRelGainResultsType *)pResults =
pDevObj->relGainResults;
break;
case VP_DEV_EVID_IO_ACCESS_CMP:
*((VpDeviceIoAccessDataType *)pResults) =
pOptionData->deviceIoData;
break;
case VP_LINE_EVID_RD_OPTION:
switch(pDevObj->getResultsOption.optionType) {
case VP_DEVICE_OPTION_ID_PULSE:
*(VpOptionPulseType *)pResults =
pDevObj->pulseSpecs;
break;
case VP_DEVICE_OPTION_ID_PULSE2:
*(VpOptionPulseType *)pResults =
pDevObj->pulseSpecs2;
break;
case VP_DEVICE_OPTION_ID_CRITICAL_FLT:
*(VpOptionCriticalFltType *)pResults =
pOptionData->criticalFaultOption;
break;
case VP_DEVICE_OPTION_ID_DEVICE_IO:
*(VpOptionDeviceIoType *)pResults =
pOptionData->deviceIo;
break;
case VP_OPTION_ID_RING_CNTRL:
*(VpOptionRingControlType *)pResults =
pOptionData->ringControlOption;
break;
case VP_OPTION_ID_ZERO_CROSS:
*(VpOptionZeroCrossType *)pResults =
pOptionData->zeroCross;
break;
case VP_OPTION_ID_PULSE_MODE:
*((VpOptionPulseModeType *)pResults) =
pOptionData->pulseModeOption;
break;
case VP_OPTION_ID_TIMESLOT:
*(VpOptionTimeslotType *)pResults =
pOptionData->timeSlotOption;
break;
case VP_OPTION_ID_CODEC:
*((VpOptionCodecType *)pResults) =
pOptionData->codecOption;
break;
case VP_OPTION_ID_PCM_HWY:
*((VpOptionPcmHwyType *)pResults) =
pOptionData->pcmHwyOption;
break;
case VP_OPTION_ID_LOOPBACK:
*((VpOptionLoopbackType *)pResults) =
pOptionData->loopBackOption;
break;
case VP_OPTION_ID_LINE_STATE:
*((VpOptionLineStateType *)pResults) =
pOptionData->lineStateOption;
break;
case VP_OPTION_ID_EVENT_MASK:
*((VpOptionEventMaskType *)pResults) =
pOptionData->eventMaskOption;
break;
case VP_OPTION_ID_PCM_TXRX_CNTRL:
*((VpOptionPcmTxRxCntrlType *)pResults) =
pOptionData->pcmTxRxCtrl;
break;
#ifdef CSLAC_GAIN_ABS
case VP_OPTION_ID_ABS_GAIN:
*(VpOptionAbsGainType *)pResults =
pOptionData->absGain;
break;
#endif
default:
status = VP_STATUS_INVALID_ARG;
break;
}
break;
case VP_EVID_CAL_CMP:
if (pResults == VP_NULL) {
status = VP_STATUS_INVALID_ARG;
} else {
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("Vp880GetResults - VP_EVID_CAL_CMP"));
pMpiData = (uint8 *)pResults;
pMpiData[VP_PROFILE_TYPE_MSB] = VP_DEV_880_SERIES;
pMpiData[VP_PROFILE_TYPE_LSB] = VP_PRFWZ_PROFILE_CAL;
pMpiData[VP_PROFILE_INDEX] = 0;
pMpiData[VP_PROFILE_LENGTH] = VP880_CAL_STRUCT_SIZE + 2;
pMpiData[VP_PROFILE_VERSION] = 0;
pMpiData[VP_PROFILE_MPI_LEN] = 0;
commandByte = VP_PROFILE_DATA_START;
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("ABV Y Error %d Size %d",
pDevObj->vp880SysCalData.abvError[0], sizeof(pDevObj->vp880SysCalData.abvError[0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.abvError[0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.abvError[0]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("ABV Z Error %d Size %d",
pDevObj->vp880SysCalData.abvError[1], sizeof(pDevObj->vp880SysCalData.abvError[1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.abvError[1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.abvError[1]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("VOC Offset Norm Ch 0 %d Size %d",
pDevObj->vp880SysCalData.vocOffset[0][0], sizeof(pDevObj->vp880SysCalData.vocOffset[0][0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vocOffset[0][0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vocOffset[0][0]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("VOC Error Norm Ch 0 %d Size %d",
pDevObj->vp880SysCalData.vocError[0][0], sizeof(pDevObj->vp880SysCalData.vocError[0][0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vocError[0][0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vocError[0][0]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("VOC Offset Rev Ch 0 %d Size %d",
pDevObj->vp880SysCalData.vocOffset[0][1], sizeof(pDevObj->vp880SysCalData.vocOffset[0][1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vocOffset[0][1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vocOffset[0][1]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("VOC Error Rev Ch 0 %d Size %d",
pDevObj->vp880SysCalData.vocError[0][1], sizeof(pDevObj->vp880SysCalData.vocError[0][1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vocError[0][1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vocError[0][1]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("VOC Offset Norm Ch 1 %d Size %d",
pDevObj->vp880SysCalData.vocOffset[1][0], sizeof(pDevObj->vp880SysCalData.vocOffset[1][0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vocOffset[1][0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vocOffset[1][0]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("VOC Error Norm Ch 1 %d Size %d",
pDevObj->vp880SysCalData.vocError[1][0], sizeof(pDevObj->vp880SysCalData.vocError[1][0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vocError[1][0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vocError[1][0]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("VOC Offset Rev Ch 1 %d Size %d",
pDevObj->vp880SysCalData.vocOffset[1][1], sizeof(pDevObj->vp880SysCalData.vocOffset[1][1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vocOffset[1][1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vocOffset[1][1]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("VOC Error Rev Ch 1 %d Size %d",
pDevObj->vp880SysCalData.vocError[1][1], sizeof(pDevObj->vp880SysCalData.vocError[1][1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vocError[1][1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vocError[1][1]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("SigGenA Norm Error Ch 0 %d Size %d",
pDevObj->vp880SysCalData.sigGenAError[0][0], sizeof(pDevObj->vp880SysCalData.sigGenAError[0][0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.sigGenAError[0][0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.sigGenAError[0][0]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("SigGenA Rev Error Ch 0 %d Size %d",
pDevObj->vp880SysCalData.sigGenAError[0][1], sizeof(pDevObj->vp880SysCalData.sigGenAError[0][1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.sigGenAError[0][1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.sigGenAError[0][1]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("SigGenA Norm Error Ch 1 %d Size %d",
pDevObj->vp880SysCalData.sigGenAError[1][0], sizeof(pDevObj->vp880SysCalData.sigGenAError[1][0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.sigGenAError[1][0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.sigGenAError[1][0]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("SigGenA Rev Error Ch 1 %d Size %d",
pDevObj->vp880SysCalData.sigGenAError[1][1], sizeof(pDevObj->vp880SysCalData.sigGenAError[1][1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.sigGenAError[1][1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.sigGenAError[1][1]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("ILA-20mA Ch 0 %d Size %d",
pDevObj->vp880SysCalData.ila20[0], sizeof(pDevObj->vp880SysCalData.ila20[0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ila20[0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ila20[0]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("ILA-20mA Ch 1 %d Size %d",
pDevObj->vp880SysCalData.ila20[1], sizeof(pDevObj->vp880SysCalData.ila20[1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ila20[1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ila20[1]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("ILA-25mA Ch 0 %d Size %d",
pDevObj->vp880SysCalData.ila25[0], sizeof(pDevObj->vp880SysCalData.ila25[0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ila25[0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ila25[0]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("ILA-25mA Ch 1 %d Size %d",
pDevObj->vp880SysCalData.ila25[1], sizeof(pDevObj->vp880SysCalData.ila25[1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ila25[1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ila25[1]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("ILA-32mA Ch 0 %d Size %d",
pDevObj->vp880SysCalData.ila32[0], sizeof(pDevObj->vp880SysCalData.ila32[0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ila32[0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ila32[0]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("ILA-32mA Ch 1 %d Size %d",
pDevObj->vp880SysCalData.ila32[1], sizeof(pDevObj->vp880SysCalData.ila32[1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ila32[1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ila32[1]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("ILA-40mA Ch 0 %d Size %d",
pDevObj->vp880SysCalData.ila40[0], sizeof(pDevObj->vp880SysCalData.ila40[0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ila40[0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ila40[0]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("ILA-40mA Ch 1 %d Size %d",
pDevObj->vp880SysCalData.ila40[1], sizeof(pDevObj->vp880SysCalData.ila40[1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ila40[1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ila40[1]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("ILA Offset Norm Ch 0 %d Size %d",
pDevObj->vp880SysCalData.ilaOffsetNorm[0], sizeof(pDevObj->vp880SysCalData.ilaOffsetNorm[0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ilaOffsetNorm[0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ilaOffsetNorm[0]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("ILA Offset Norm Ch 1 %d Size %d",
pDevObj->vp880SysCalData.ilaOffsetNorm[1], sizeof(pDevObj->vp880SysCalData.ilaOffsetNorm[1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ilaOffsetNorm[1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ilaOffsetNorm[1]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("ILG Offset Norm Ch 0 %d Size %d",
pDevObj->vp880SysCalData.ilgOffsetNorm[0], sizeof(pDevObj->vp880SysCalData.ilgOffsetNorm[0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ilgOffsetNorm[0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ilgOffsetNorm[0]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("ILG Offset Norm Ch 1 %d Size %d",
pDevObj->vp880SysCalData.ilgOffsetNorm[1], sizeof(pDevObj->vp880SysCalData.ilgOffsetNorm[1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ilgOffsetNorm[1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ilgOffsetNorm[1]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("VAS Norm Ch 0 %d Size %d",
pDevObj->vp880SysCalData.vas[0][0], sizeof(pDevObj->vp880SysCalData.vas[0][0])));
pMpiData[commandByte++] = pDevObj->vp880SysCalData.vas[0][0];
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("VAS Rev Ch 0 %d Size %d",
pDevObj->vp880SysCalData.vas[0][1], sizeof(pDevObj->vp880SysCalData.vas[0][1])));
pMpiData[commandByte++] = pDevObj->vp880SysCalData.vas[0][1];
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("VAS Norm Ch 1 %d Size %d",
pDevObj->vp880SysCalData.vas[1][0], sizeof(pDevObj->vp880SysCalData.vas[1][0])));
pMpiData[commandByte++] = pDevObj->vp880SysCalData.vas[1][0];
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("VAS Rev Ch 1 %d Size %d",
pDevObj->vp880SysCalData.vas[1][1], sizeof(pDevObj->vp880SysCalData.vas[1][1])));
pMpiData[commandByte++] = pDevObj->vp880SysCalData.vas[1][1];
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("VAG Offset Norm Ch 0 %d Size %d",
pDevObj->vp880SysCalData.vagOffsetNorm[0], sizeof(pDevObj->vp880SysCalData.vagOffsetNorm[0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vagOffsetNorm[0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vagOffsetNorm[0]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("VAG Offset Norm Ch 1 %d Size %d",
pDevObj->vp880SysCalData.vagOffsetNorm[1], sizeof(pDevObj->vp880SysCalData.vagOffsetNorm[1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vagOffsetNorm[1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vagOffsetNorm[1]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("VAG Offset Rev Ch 0 %d Size %d",
pDevObj->vp880SysCalData.vagOffsetRev[0], sizeof(pDevObj->vp880SysCalData.vagOffsetRev[0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vagOffsetRev[0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vagOffsetRev[0]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("VAG Offset Rev Ch 1 %d Size %d",
pDevObj->vp880SysCalData.vagOffsetRev[1], sizeof(pDevObj->vp880SysCalData.vagOffsetRev[1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vagOffsetRev[1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vagOffsetRev[1]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("VBG Offset Norm Ch 0 %d Size %d",
pDevObj->vp880SysCalData.vbgOffsetNorm[0], sizeof(pDevObj->vp880SysCalData.vbgOffsetNorm[0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vbgOffsetNorm[0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vbgOffsetNorm[0]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("VBG Offset Norm Ch 1 %d Size %d",
pDevObj->vp880SysCalData.vbgOffsetNorm[1], sizeof(pDevObj->vp880SysCalData.vbgOffsetNorm[1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vbgOffsetNorm[1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vbgOffsetNorm[1]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("VBG Offset Rev Ch 0 %d Size %d",
pDevObj->vp880SysCalData.vbgOffsetRev[0], sizeof(pDevObj->vp880SysCalData.vbgOffsetRev[0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vbgOffsetRev[0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vbgOffsetRev[0]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("VBG Offset Rev Ch 1 %d Size %d",
pDevObj->vp880SysCalData.vbgOffsetRev[1], sizeof(pDevObj->vp880SysCalData.vbgOffsetRev[1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vbgOffsetRev[1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.vbgOffsetRev[1]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("Auto-Bat Switch Normal Ch 0 %d Size %d",
pDevObj->vp880SysCalData.absNormCal[0], sizeof(pDevObj->vp880SysCalData.absNormCal[0])));
pMpiData[commandByte++] = pDevObj->vp880SysCalData.absNormCal[0];
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("Auto-Bat Switch Rev Ch 0 %d Size %d",
pDevObj->vp880SysCalData.absPolRevCal[0], sizeof(pDevObj->vp880SysCalData.absPolRevCal[0])));
pMpiData[commandByte++] = pDevObj->vp880SysCalData.absPolRevCal[0];
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("Auto-Bat Switch Normal Ch 1 %d Size %d",
pDevObj->vp880SysCalData.absNormCal[1], sizeof(pDevObj->vp880SysCalData.absNormCal[1])));
pMpiData[commandByte++] = pDevObj->vp880SysCalData.absNormCal[1];
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("Auto-Bat Switch Rev Ch 1 %d Size %d",
pDevObj->vp880SysCalData.absPolRevCal[1], sizeof(pDevObj->vp880SysCalData.absPolRevCal[1])));
pMpiData[commandByte++] = pDevObj->vp880SysCalData.absPolRevCal[1];
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("SWY Offset Ch 0 %d Size %d",
pDevObj->vp880SysCalData.swyOffset[0], sizeof(pDevObj->vp880SysCalData.swyOffset[0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.swyOffset[0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.swyOffset[0]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("SWY Offset Ch 1 %d Size %d",
pDevObj->vp880SysCalData.swyOffset[1], sizeof(pDevObj->vp880SysCalData.swyOffset[1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.swyOffset[1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.swyOffset[1]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("SWZ Offset Ch 0 %d Size %d",
pDevObj->vp880SysCalData.swzOffset[0], sizeof(pDevObj->vp880SysCalData.swzOffset[0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.swzOffset[0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.swzOffset[0]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("SWZ Offset Ch 1 %d Size %d",
pDevObj->vp880SysCalData.swzOffset[1], sizeof(pDevObj->vp880SysCalData.swzOffset[1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.swzOffset[1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.swzOffset[1]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("XB Offset Ch 0 %d Size %d",
pDevObj->vp880SysCalData.swxbOffset[0], sizeof(pDevObj->vp880SysCalData.swxbOffset[0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.swxbOffset[0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.swxbOffset[0]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("XB Offset Ch 1 %d Size %d",
pDevObj->vp880SysCalData.swxbOffset[1], sizeof(pDevObj->vp880SysCalData.swxbOffset[1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.swxbOffset[1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.swxbOffset[1]) & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("Tip Cap Ch 0 %li Size %d",
pDevObj->vp880SysCalData.tipCapCal[0], sizeof(pDevObj->vp880SysCalData.tipCapCal[0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.tipCapCal[0] >> 24) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.tipCapCal[0] >> 16) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.tipCapCal[0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)(pDevObj->vp880SysCalData.tipCapCal[0] & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("Tip Cap Ch 1 %li Size %d",
pDevObj->vp880SysCalData.tipCapCal[1], sizeof(pDevObj->vp880SysCalData.tipCapCal[1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.tipCapCal[1] >> 24) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.tipCapCal[1] >> 16) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.tipCapCal[1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)(pDevObj->vp880SysCalData.tipCapCal[1] & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("Ring Cap Ch 0 %li Size %d",
pDevObj->vp880SysCalData.ringCapCal[0], sizeof(pDevObj->vp880SysCalData.ringCapCal[0])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ringCapCal[0] >> 24) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ringCapCal[0] >> 16) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ringCapCal[0] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)(pDevObj->vp880SysCalData.ringCapCal[0] & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("Ring Cap Ch 1 %li Size %d",
pDevObj->vp880SysCalData.ringCapCal[1], sizeof(pDevObj->vp880SysCalData.ringCapCal[1])));
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ringCapCal[1] >> 24) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ringCapCal[1] >> 16) & 0xFF);
pMpiData[commandByte++] = (uint8)((pDevObj->vp880SysCalData.ringCapCal[1] >> 8) & 0xFF);
pMpiData[commandByte++] = (uint8)(pDevObj->vp880SysCalData.ringCapCal[1] & 0xFF);
VP_CALIBRATION(VpDevCtxType, pDevCtx, ("Final Command Byte Value %d", commandByte));
}
break;
default:
status = VP_STATUS_INVALID_ARG;
break;
}
break;
#ifdef VP880_INCLUDE_TESTLINE_CODE
case VP_EVCAT_TEST:
switch (pEvent->eventId) {
case VP_LINE_EVID_TEST_CMP:
*((VpTestResultType *)pResults) = pDevObj->testResults;
break;
default:
break;
}
#endif
break;
default:
status = VP_STATUS_INVALID_ARG;
break;
}
VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC);
VP_API_FUNC(VpDevCtxType, pDevCtx, ("Vp880GetResults-"));
return status;
}
/**
* Vp880ServiceTimers()
* This function services active API timers on all channels of deviceId.
*
* Preconditions:
* This Function must be called from the ApiTick function once per device.
*
* Postconditions:
* All Active Timers have been serviced.
*/
bool
Vp880ServiceTimers(
VpDevCtxType *pDevCtx)
{
VpLineCtxType *pLineCtx;
Vp880LineObjectType *pLineObj;
Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj;
uint16 tempTimer;
uint8 devTimerType;
uint8 channelId;
uint8 maxChan = pDevObj->staticInfo.maxChannels;
bool retFlag = FALSE;
for (devTimerType = 0; devTimerType < VP_DEV_TIMER_LAST; devTimerType++) {
if (pDevObj->devTimer[devTimerType] & VP_ACTIVATE_TIMER) {
/* get the bits associated with the timer into a temp variable */
tempTimer = (pDevObj->devTimer[devTimerType] & VP_TIMER_TIME_MASK);
/* decrement the timer */
if (tempTimer > 0) {
tempTimer--;
}
/* reset the device timer to the new value*/
pDevObj->devTimer[devTimerType] = tempTimer;
/* if the timer has expired then run the timer code */
if (pDevObj->devTimer[devTimerType] == 0) {
switch(devTimerType) {
#ifdef VP880_ABS_SUPPORT
case VP_DEV_TIMER_EXIT_RINGING:
Vp880DevRingExitTimerHandler(pDevCtx);
break;
#endif /* VP880_ABS_SUPPORT */
#ifdef VP880_LP_SUPPORT
case VP_DEV_TIMER_LP_CHANGE:
VP_LINE_STATE(VpDevCtxType, pDevCtx, ("VP_DEV_TIMER_LP_CHANGE Expired at %d",
pDevObj->timeStamp));
Vp880ServiceLpChangeTimer(pDevCtx);
break;
#endif /* VP880_LP_SUPPORT */
#ifdef VP880_INCLUDE_TESTLINE_CODE
case VP_DEV_TIMER_TESTLINE:
{
const void *pTestArgs =
(const void*)&pDevObj->currentTest.pTestHeap->testArgs;
uint8 testChanId = pDevObj->currentTest.channelId;
VpTestLineIntFuncPtrType testline =
pDevCtx->funPtrsToApiFuncs.TestLineInt;
VP_LINE_STATE(VpDevCtxType, pDevCtx,
("VP_DEV_TIMER_TESTLINE Expired at %d", pDevObj->timeStamp));
if ((testline != VP_NULL) && (pDevObj->currentTest.testState != -1)) {
/*
* if the TestLineInt function exists and the current test state
* has not been set back to -1 by test conclude before the timer
* expired then run the call back
*/
testline(
pDevCtx->pLineCtx[testChanId],
pDevObj->currentTest.testId,
pTestArgs,
pDevObj->currentTest.handle,
TRUE);
}
}
break;
#endif /* VP880_INCLUDE_TESTLINE_CODE */
#ifdef VP_CSLAC_RUNTIME_CAL_ENABLED
case VP_DEV_TIMER_ABV_CAL:
VP_LINE_STATE(VpDevCtxType, pDevCtx, ("VP_DEV_TIMER_ABV_CAL Expired at %d",
pDevObj->timeStamp));
if (pDevObj->stateInt & VP880_IS_ABS) {
#ifdef VP880_ABS_SUPPORT
Vp880CalAbvAbsDev(pDevCtx);
#endif /* VP880_ABS_SUPPORT */
} else {
#ifdef VP880_TRACKER_SUPPORT
Vp880CalAbv(pDevCtx);
#endif /* VP880_TRACKER_SUPPORT */
}
break;
#ifdef VP880_ABS_SUPPORT
case VP_DEV_TIMER_ABSCAL:
VP_LINE_STATE(VpDevCtxType, pDevCtx, ("VP_DEV_TIMER_ABSCAL Expired at %d",
pDevObj->timeStamp));
Vp880AbsCalibration(pDevCtx);
break;
#endif /* VP880_ABS_SUPPORT */
#endif /* VP_CSLAC_RUNTIME_CAL_ENABLED */
#if defined (VP880_TRACKER_SUPPORT) && defined (VP880_FXS_SUPPORT)
case VP_DEV_TIMER_ENTER_RINGING:
VP_LINE_STATE(VpDevCtxType, pDevCtx, ("VP_DEV_TIMER_ENTER_RINGING Expired at %d",
pDevObj->timeStamp));
Vp880LimitInRushCurrent(pDevObj, pDevObj->ecVal, TRUE);
break;
#endif
default:
break;
} /* Switch (timerType) */
/*
* This is a check to make sure that one of the call back
* functions has not reset the value of the devTimer. If
* the call back function has not then just clear the timer bits
* if it has then we need to enable the activate mask.
*/
if (pDevObj->devTimer[devTimerType] == 0) {
pDevObj->devTimer[devTimerType] &= ~(VP_ACTIVATE_TIMER);
} else {
pDevObj->devTimer[devTimerType] |= VP_ACTIVATE_TIMER;
}
} else { /* If timer has not expired */
pDevObj->devTimer[devTimerType] |= VP_ACTIVATE_TIMER;
}
} /* if timerType is active */
} /* Loop through all device timers */
/* Iterate through the channels until all timers are serviced */
for(channelId=0; channelId < maxChan; channelId++ ) {
pLineCtx = pDevCtx->pLineCtx[channelId];
if (pLineCtx != VP_NULL) {
pLineObj = pLineCtx->pLineObj;
if (!(pLineObj->status & VP880_IS_FXO)) {
#ifdef VP880_FXS_SUPPORT
Vp880ServiceFxsTimers(pLineCtx);
#endif
} else {
#ifdef VP880_FXO_SUPPORT
Vp880ServiceFxoTimers(pLineCtx);
#endif
}
} /* Line Context Check */
} /* Loop through channels until no more tests */
return retFlag;
} /* Vp880ServiceTimers() */
#ifdef VP880_ABS_SUPPORT
/**
* Vp880DevRingExitTimerHandler()
* This function services the Device Level Ringing Exit Timer. It is used only for ABS.
*
* Preconditions:
* This Function should be called only when VP_DEV_TIMER_EXIT_RINGING exipres. The device must
* already be in HP state when entering this function since this function does not set it to HP
* mode if it determines the device cannot (yet) be taken out of HP mode.
*
* Postconditions:
*/
void
Vp880DevRingExitTimerHandler(
VpDevCtxType *pDevCtx)
{
Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj;
VpDeviceIdType deviceId = pDevObj->deviceId;
uint8 maxChan = pDevObj->staticInfo.maxChannels;
VpLineCtxType *pLineCtx = VP_NULL;
Vp880LineObjectType *pLineObj = VP_NULL;
uint8 channelId;
uint8 lineState[VP880_SYS_STATE_LEN];
/*
* Default is to keep the supply in high powered mode because setting it to medium power has
* some negative consequences if incorrect. So we want to design the algorithm to change to
* medium power for only those conditions we're currently aware of. If new conditions later
* exist that would also allow transition to low power mode and this algorithm is not updated,
* this will still work correctly - but perhaps not optimally.
*/
bool disableHpm = FALSE;
VP_LINE_STATE(VpDevCtxType, pDevCtx,
("VP_DEV_TIMER_EXIT_RINGING Expired at %d", pDevObj->timeStamp));
for (channelId = 0; channelId < maxChan; channelId++) {
pLineCtx = pDevCtx->pLineCtx[channelId];
if (pLineCtx != VP_NULL) {
pLineObj = pLineCtx->pLineObj;
/*
* Since FXO is not supported on ABS devices, this check should not be needed. But
* we just want to be 100% certain not to incorrectly mis-interpret register content
* from an FXO line type
*/
if (!(pLineObj->status & VP880_IS_FXO)) { /* Line type is FXS */
switch (pLineObj->slicValueCache & VP880_SS_LINE_FEED_MASK) {
case VP880_SS_FEED_BALANCED_RINGING:
case VP880_SS_FEED_UNBALANCED_RINGING:
break;
default:
/*
* The SLIC is not in Ringing at least. But since the SLIC waits for zero
* crossing to disable ringing, we now have to check it's sub-states. If
* the sub-states ALSO indicate the line is not in Ringing (Ringing Exit),
* then we can start to consider disabling High Power Mode
*/
VpMpiCmdWrapper(deviceId, pLineObj->ecVal,
VP880_SYS_STATE_RD, VP880_SYS_STATE_LEN, lineState);
/* We're completely out of Ringing if the Ring Exit bit is cleared */
if (!(lineState[0] & VP880_SS_RING_EXIT_MASK)) {
disableHpm = TRUE;
}
break;
}
}
}
}
if (disableHpm == TRUE) {
uint8 regCtrl = VP880_SWY_MP | VP880_SWZ_MP;
VpMpiCmdWrapper(deviceId, pDevObj->ecVal, VP880_REGULATOR_CTRL_WRT,
VP880_REGULATOR_CTRL_LEN, &regCtrl);
} else {
pDevObj->devTimer[VP_DEV_TIMER_EXIT_RINGING] =
(MS_TO_TICKRATE(VP_DEV_TIMER_EXIT_RINGING_SAMPLE,
pDevObj->devProfileData.tickRate)) | VP_ACTIVATE_TIMER;
}
}
#endif
#if defined (VP880_FXS_SUPPORT) && defined (VP880_LP_SUPPORT)
/**
* Vp880ServiceLpChangeTimer()
* This function services the active Low Power Change Device timer.
*
* Preconditions:
* This Function must be called from the ApiTick function once per device.
*
* Postconditions:
* The LP Change timer has been serviced.
*/
void
Vp880ServiceLpChangeTimer(
VpDevCtxType *pDevCtx)
{
Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj;
uint8 channelId;
uint8 maxChan = pDevObj->staticInfo.maxChannels;
VpDeviceIdType deviceId = pDevObj->deviceId;
Vp880LineObjectType *pLineObj;
VpLineCtxType *pLineCtx;
uint8 ecVal;
for (channelId = 0; channelId < maxChan; channelId++) {
pLineCtx = pDevCtx->pLineCtx[channelId];
if (pLineCtx != VP_NULL) {
bool failureMode = FALSE;
pLineObj = pLineCtx->pLineObj;
ecVal = pLineObj->ecVal;
if ((pLineObj->lineState.currentState != VP_LINE_DISCONNECT) &&
(pLineObj->lineState.currentState != VP_LINE_TIP_OPEN) &&
(pLineObj->lineState.currentState != VP_LINE_RINGING) &&
(!(pLineObj->status & VP880_LINE_IN_CAL))) {
VP_HOOK(VpLineCtxType, pLineCtx, ("Signaling 0x%02X 0x%02X",
pDevObj->intReg[0], pDevObj->intReg[1]));
VP_HOOK(VpLineCtxType, pLineCtx,
("Last Hook State on line %d = %d LP Mode %d UserState %d",
channelId, (pLineObj->lineState.condition & VP_CSLAC_HOOK),
(pLineObj->status & VP880_LOW_POWER_EN), pLineObj->lineState.usrCurrent));
if (pLineObj->status & VP880_LOW_POWER_EN) {
/*
* If we're in LP Mode, then the line should be detecting
* on-hook. All other conditions mean there could be a leaky
* line.
*/
if ((pLineObj->lineState.condition & VP_CSLAC_HOOK)
&& (!(pDevObj->intReg[channelId]) & VP880_HOOK1_MASK)) {
failureMode = TRUE;
}
} else {
/*
* If we're not in LP Mode, then the line should be
* detecting off-hook unless just recovered from Disconnect.
* If not just from Disconnect, and looking for off-hook,
* the signaling bit should be high. Otherwise, error.
*/
if ((pLineObj->lineState.condition & VP_CSLAC_HOOK)
&& (!(pDevObj->intReg[channelId]) & VP880_HOOK1_MASK)) {
failureMode = TRUE;
pLineObj->leakyLineCnt++;
}
}
}
/*
* If the line was last seen off-hook and is now on-hook as a result
* of exiting LP Mode, it could be a leaky line.
*/
if (failureMode == TRUE) {
if (pLineObj->leakyLineCnt >= VE8XX_LPM_LEAKY_LINE_CNT) {
/*
* After determining the line is leaky the lines are taken
* out of LPM causing this timer to complete (one last time)
* so if the Leaky Line Flag/Event is already complete, we
* can skip this step and just clean up.
*/
if (!(pLineObj->status & VP880_LINE_LEAK)) {
VP_HOOK(VpLineCtxType, pLineCtx,
("Flag Channel %d for Leaky Line at time %d Signaling 0x%02X LineState %d",
channelId, pDevObj->timeStamp,
(pDevObj->intReg[channelId] & VP880_HOOK1_MASK),
pLineObj->lineState.usrCurrent));
pLineObj->status |= VP880_LINE_LEAK;
pDevObj->stateInt &=
((channelId == 0) ? ~VP880_LINE0_LP : ~VP880_LINE1_LP);
pLineObj->lineEvents.faults |= VP_LINE_EVID_RES_LEAK_FLT;
/* Leak test is complete */
pLineObj->lineState.condition &= ~VP_CSLAC_LINE_LEAK_TEST;
}
} else {
uint16 deviceTimer;
VP_HOOK(VpLineCtxType, pLineCtx,
("Potential Leaky Line %d at time %d count (%d) ...retry",
channelId, pDevObj->timeStamp, pLineObj->leakyLineCnt));
/* Leak test is still in progress */
/*
* Make sure timer is restarted. This may occur as a result
* of SetLineState(), but it may not.
*/
if (pDevObj->swParams[VP880_REGULATOR_TRACK_INDEX] & VP880_REGULATOR_FIXED_RING_SWY) {
/*
* Longest is using "fixed" ringing mode because the external
* capacitors are generally very large.
*/
deviceTimer = VP880_PWR_SWITCH_DEBOUNCE_FXT;
} else {
deviceTimer = VP880_PWR_SWITCH_DEBOUNCE_FUT;
}
VpCSLACSetTimer(&pDevObj->devTimer[VP_DEV_TIMER_LP_CHANGE],
(MS_TO_TICKRATE(deviceTimer, pDevObj->devProfileData.tickRate)));
VP_LINE_STATE(VpDevCtxType, pDevCtx,
("Vp880ServiceLpChangeTimer() Channel %d: Starting VP_DEV_TIMER_LP_CHANGE with (%d) ms at time %d",
pLineObj->channelId, deviceTimer, pDevObj->timeStamp));
}
/* Update the line state */
for (channelId = 0;
channelId < pDevObj->staticInfo.maxChannels;
channelId++) {
Vp880LineObjectType *pLineObjInt;
pLineCtx = pDevCtx->pLineCtx[channelId];
if (pLineCtx != VP_NULL) {
pLineObjInt = pLineCtx->pLineObj;
VP_HOOK(VpLineCtxType, pLineCtx,
("1. Channel %d Current Linestate %d Current User Linestate %d",
channelId, pLineObjInt->lineState.currentState,
pLineObjInt->lineState.usrCurrent));
if (pLineObj->status & VP880_LOW_POWER_EN) {
/* Force line to feed state */
pLineObj->lineState.currentState = VP_LINE_OHT;
pDevObj->stateInt &= ~((channelId == 0) ? VP880_LINE0_LP : VP880_LINE1_LP);
} else {
Vp880SetLineStateInt(pLineCtx, pLineObjInt->lineState.usrCurrent);
}
}
}
} else {
/*
* No failure. Recover all hook status, line states, and clear
* Leaky Line Test Flag
*/
/* Leak test is complete */
pLineObj->lineState.condition &= ~VP_CSLAC_LINE_LEAK_TEST;
/*
* Low Power Mode exit simply sets the line to Active in order
* to maintain smooth line transients. This step is done to
* put the line into the user (API-II) defined state.
*/
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("LPM Timer: Current %d, User Current %d Channel %d",
pLineObj->lineState.currentState, pLineObj->lineState.usrCurrent,
channelId));
if ((pLineObj->lineState.usrCurrent == VP_LINE_STANDBY)
&& (!(pLineObj->status & VP880_LOW_POWER_EN))
&& (pLineObj->calLineData.calDone == TRUE)) { /* Must not occur during the calibration */
uint8 lineState[1] = {VP880_SS_IDLE};
#ifdef VP_CSLAC_SEQ_EN
if ((pLineObj->cadence.status & (VP_CADENCE_STATUS_ACTIVE | VP_CADENCE_STATUS_SENDSIG)) !=
(VP_CADENCE_STATUS_ACTIVE | VP_CADENCE_STATUS_SENDSIG)) {
#endif
Vp880UpdateBufferChanSel(pDevObj, channelId, lineState[0], TRUE);
if (pLineObj->slicValueCache != lineState[0]) {
pLineObj->slicValueCache = lineState[0];
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("Setting Channel %d to 0x%02X State at time %d",
channelId, lineState[0], pDevObj->timeStamp));
VpMpiCmdWrapper(deviceId, ecVal, VP880_SYS_STATE_WRT,
VP880_SYS_STATE_LEN, &pLineObj->slicValueCache);
}
#ifdef VP_CSLAC_SEQ_EN
}
#endif
}
if ((pLineObj->lineState.condition & VP_CSLAC_HOOK)
&& (pDevObj->intReg[channelId]) & VP880_HOOK1_MASK) {
if ((pLineObj->lineState.condition & VP_CSLAC_HOOK) &&
(pLineObj->status & VP880_LOW_POWER_EN)) {
/* Valid on-hook */
VP_HOOK(VpLineCtxType, pLineCtx, ("Valid On-Hook on line %d at time %d",
channelId, pDevObj->timeStamp));
pLineObj->lineState.condition &= ~VP_CSLAC_HOOK;
Vp880UpdateHookInfo(pLineObj, pDevObj);
} else {
/* Valid off-hook */
VP_HOOK(VpLineCtxType, pLineCtx, ("Valid Off-Hook on line %d at time %d",
channelId, pDevObj->timeStamp));
pLineObj->leakyLineCnt = 0;
pLineObj->status &= ~VP880_LINE_LEAK;
pLineObj->lineState.condition |= VP_CSLAC_HOOK;
Vp880UpdateHookInfo(pLineObj, pDevObj);
}
}
}
}
}
}
#endif /* defined (VP880_FXS_SUPPORT) && defined (VP880_LP_SUPPORT) */
#ifdef VP880_FXS_SUPPORT
/**
* Vp880ServiceFxsTimers()
* This function services active FXS API timers.
*
* Preconditions:
* This Function must be called from the ApiTick function once per device.
*
* Postconditions:
* All Active FXS Timers for the current line have been serviced.
*/
void
Vp880ServiceFxsTimers(
VpLineCtxType *pLineCtx)
{
Vp880LineObjectType *pLineObj = pLineCtx->pLineObj;
VpDevCtxType *pDevCtx = pLineCtx->pDevCtx;
Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj;
VpDeviceIdType deviceId = pDevObj->deviceId;
#ifdef VP880_LP_SUPPORT
uint8 channelId = pLineObj->channelId;
#endif
uint8 ecVal = pLineObj->ecVal;
uint8 lineTimerType;
uint16 tempTimer;
VpCslacTimers *fxsTimers = &pLineObj->lineTimers.timers;
for (lineTimerType = 0; lineTimerType < VP_LINE_TIMER_LAST; lineTimerType++) {
if (fxsTimers->timer[lineTimerType] & VP_ACTIVATE_TIMER) {
tempTimer = (fxsTimers->timer[lineTimerType] & VP_TIMER_TIME_MASK);
if (tempTimer > 0) {
tempTimer--;
}
fxsTimers->timer[lineTimerType] = tempTimer;
if (tempTimer == 0) {
fxsTimers->timer[lineTimerType] &= ~(VP_ACTIVATE_TIMER);
/* Perform appropriate action based on timerType */
switch (lineTimerType) {
case VP_LINE_RING_EXIT_PROCESS: {
/*
* There are two reasons to delay ringing exit - 1. in LPM to correct for
* the initial delay when entering ringing, and 2. to delay a polarity
* reversal change when exiting ringing to prevent the polarity reversal
* from occurring during the ringing cycle.
*/
uint8 ringExitSt[VP880_SYS_STATE_LEN];
uint8 slicState = (pLineObj->slicValueCache & VP880_SS_LINE_FEED_MASK);
bool exitRinging = FALSE;
VpMpiCmdWrapper(deviceId, ecVal, VP880_SYS_STATE_RD,
VP880_SYS_STATE_LEN, ringExitSt);
/*
* Check to see if we're completely out of ringing. Although the SLIC state
* should have already been modified prior to this point and therefore NOT
* indicate Ringing State, it's possible in theory that the time between
* changing the SLIC to a non-Ringing state to the point the register is
* read could be too fast for the silicon state machine to update. It's
* just theory...but we want to be 100% sure not to change register settings
* until we're really out of Ringing.
*/
if ((ringExitSt[0] & VP880_SS_RING_EXIT_MASK) ||
(slicState == VP880_SS_FEED_BALANCED_RINGING) ||
(slicState == VP880_SS_FEED_UNBALANCED_RINGING)) {
/*
* If any of the conditions are TRUE, it means Ringing is still on
* Tip/Ring. Ringing should be removed in <= 100ms from the time the
* new SLIC state is programmed, so keep track how long we're in this
* condition to eventually force stop it
*/
if (fxsTimers->trackingTime < VP_CSLAC_RINGING_EXIT_MAX) {
/*
* We haven't exceeded our maximum allowable ringing exit time,
* so just restart this timer to run as soon as possible and update
* the trackingTime (note: tracking time is in ms).
*/
fxsTimers->timer[VP_LINE_RING_EXIT_PROCESS] =
(1 | VP_ACTIVATE_TIMER);
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("Ringing still present on the line. RING_EXIT_TIMER restart Ch %d at time %d",
pLineObj->channelId, pDevObj->timeStamp));
/*
* Keep track of how long we've been in this condition so we don't
* repeat this forever.
*/
fxsTimers->trackingTime +=
TICKS_TO_MS(1, pDevObj->devProfileData.tickRate);
} else {
/*
* Ringing is still on the line, but we've run out of patience.
* Time to just force ringing removal
*/
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("Forced Ring Exit after (%d) on Ch %d at time %d",
fxsTimers->trackingTime, pLineObj->channelId,
pDevObj->timeStamp));
exitRinging = TRUE;
}
} else {
/*
* Ringing is totally removed from the line. It's now ok to change to
* the final line state and re-disable the Auto-State Transitions of
* the silicon.
*/
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("Normal Ring Exit after (%d) on Ch %d at time %d",
fxsTimers->trackingTime, pLineObj->channelId,
pDevObj->timeStamp));
exitRinging = TRUE;
}
if (exitRinging) {
#ifdef VP_CSLAC_SEQ_EN
bool resetTimer = FALSE;
uint16 timeRemain = 0;
#endif
/*
* Even though the MPI read will initialize this value, some compilers
* may not be that smart and can generate a warning if this isn't done.
*/
uint8 ssCfg[VP880_SS_CONFIG_LEN] = {0x00};
/*
* Before doing anything, disable the silicon auto-system state control
* mechanism. This can interfere with Low Power Mode and/or other
* API line state managed changes
*/
VpMpiCmdWrapper(deviceId, ecVal, VP880_SS_CONFIG_RD,
VP880_SS_CONFIG_LEN, ssCfg);
ssCfg[0] |= VP880_AUTO_SSC_DIS;
VpMpiCmdWrapper(deviceId, ecVal, VP880_SS_CONFIG_WRT,
VP880_SS_CONFIG_LEN, ssCfg);
#ifdef VP_CSLAC_SEQ_EN
/*
* Calling Vp880SetLineStateInt() will reset the timer if in the proces
* of Ringing Cadence. Save the timeRemain value and write it back after
* calling Vp880SetLineStateInt() if necessary.
*/
if (pLineObj->cadence.status & VP_CADENCE_STATUS_MID_TIMER) {
resetTimer = TRUE;
timeRemain = pLineObj->cadence.timeRemain;
}
#endif /* VP_CSLAC_SEQ_EN */
/*
* If performing a polarity reversal this will start the Hook Freeze
* timer based on polarity reversal hook activity. So we won't need to
* account for this again when modifying the same timer for ring trip
* or user specified ringing exit
*/
Vp880SetLineStateInt(pLineCtx, pLineObj->lineState.currentState);
#ifdef VP_CSLAC_SEQ_EN
/*
* Restore the cadence timer status and timer if set prior to calling
* Vp880SetLineStateInt(). This occurs during Ringing Cadence.
*/
if (resetTimer) {
pLineObj->cadence.status |= VP_CADENCE_STATUS_MID_TIMER;
pLineObj->cadence.timeRemain = timeRemain;
}
#endif /* VP_CSLAC_SEQ_EN */
/*
* Start the hook switch debounce timer based on conditions of ringing
* exit - either debounce for internally known continued hook activity
* up a ring trip or debounce for normal ringing exit if on-hook. For
* polarity reversal, Vp880SetLineState() will set the Hook Freeze
* timer to the correct value. The VpCSLACSetTimer() just updates the
* timer if the new value is longer than the previously set value.
*/
if (pLineObj->status & VP_CSLAC_HOOK) { /* Ring Trip */
VpCSLACSetTimer(&fxsTimers->timer[VP_LINE_HOOK_FREEZE],
MS_TO_TICKRATE(VP880_RING_TRIP_DEBOUNCE,
pDevObj->devProfileData.tickRate));
} else { /* On-Hook Ringing Exit */
#ifdef VP_CSLAC_SEQ_EN
/*
* Generate the Ringing Cadence Off Event now that ringing is
* removed from the line or now that we've given up on trying. Only
* do this if Cadence is supported in the API and if we're exiting
* ringing while running a ringing cadence.
*/
if (pLineObj->cadence.status & VP_CADENCE_STATUS_ACTIVE) {
VpProfilePtrType pProfile = pLineObj->cadence.pActiveCadence;
if ((pProfile != VP_NULL) && (pProfile[VP_PROFILE_TYPE_LSB]
== VP_PRFWZ_PROFILE_RINGCAD)) {
pLineObj->lineEvents.process |= VP_LINE_EVID_RING_CAD;
pLineObj->processData = VP_RING_CAD_BREAK;
}
}
#endif /* VP_CSLAC_SEQ_EN */
/* Note the "/8" conversion from 125us to ms */
VpCSLACSetTimer(&fxsTimers->timer[VP_LINE_HOOK_FREEZE],
MS_TO_TICKRATE((pLineObj->ringCtrl.ringExitDbncDur / 8),
pDevObj->devProfileData.tickRate));
}
}
}
/* May not be ready for this, but it doesn't hurt */
pDevObj->state |= VP_DEV_PENDING_INT;
break;
case VP_LINE_HOOK_FREEZE:
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("VP_LINE_HOOK_FREEZE Expired on Ch %d at time %d",
pLineObj->channelId, pDevObj->timeStamp));
pDevObj->state |= VP_DEV_PENDING_INT;
break;
case VP_LINE_DISCONNECT_EXIT:
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("VP_LINE_DISCONNECT_EXIT Expired on Ch %d at time %d",
pLineObj->channelId, pDevObj->timeStamp));
/*
* If we're in calibration, don't do anything. The device/line has to first
* be restored from calibration conditions before proceeding with normal
* control. Note that this flag can only be set and not cleared. That's
* because the sequence of starting disconnect and calibration occurs in
* VpInitDevice() (i.e., normal) but then once calibration is in process,
* additional line state changes by the application are not allowed.
*/
if (pDevObj->state & VP_DEV_IN_CAL) {
pDevObj->state |= VP_DEV_DISC_PENDING;
} else {
/*
* The Service Disconnect Exit Timer management function will determine
* if the device interrupt should be read. So don't assume that to be
* the case here.
*/
Vp880ServiceDiscExitTimer(pLineCtx);
}
break;
case VP_LINE_GND_START_TIMER:
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("VP_LINE_GND_START_TIMER Expired on Ch %d at time %d",
pLineObj->channelId, pDevObj->timeStamp));
Vp880ServiceGroundStartTimer(pLineCtx);
break;
#ifdef VP_CSLAC_RUNTIME_CAL_ENABLED
case VP_LINE_CAL_LINE_TIMER:
VP_CALIBRATION(VpLineCtxType, pLineCtx,
("VP_LINE_CAL_LINE_TIMER Expired on Ch %d at time %d",
pLineObj->channelId, pDevObj->timeStamp));
Vp880CalLineInt(pLineCtx);
break;
#endif
case VP_LINE_PING_TIMER: /* Set only for VC silicon */
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("VP_LINE_PING_TIMER Expired on Ch %d at time %d",
pLineObj->channelId, pDevObj->timeStamp));
if (((pDevObj->stateInt & (VP880_LINE0_LP | VP880_LINE1_LP))
== (VP880_LINE0_LP | VP880_LINE1_LP))
&& (!(pLineObj->status & VP880_LINE_LEAK))
&& (pLineObj->lineState.usrCurrent == VP_LINE_STANDBY)) {
pLineObj->nextSlicValue = VP880_SS_DISCONNECT;
}
if (pLineObj->slicValueCache != pLineObj->nextSlicValue) {
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("VP_LINE_PING_TIMER: Setting Chan %d to Value 0x%02X at Time %d",
pLineObj->channelId, pLineObj->nextSlicValue, pDevObj->timeStamp));
pLineObj->slicValueCache = pLineObj->nextSlicValue;
VpMpiCmdWrapper(deviceId, ecVal, VP880_SYS_STATE_WRT,
VP880_SYS_STATE_LEN, &pLineObj->slicValueCache);
}
break;
#ifdef VP880_LP_SUPPORT
case VP_LINE_TRACKER_DISABLE:
if (!(pLineObj->lineState.condition & VP_CSLAC_LINE_LEAK_TEST)) {
uint8 sysState[VP880_SYS_STATE_LEN] = {VP880_SS_DISCONNECT};
uint8 icr2Temp[VP880_ICR2_LEN];
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("VP_LINE_TRACKER_DISABLE Expired on Ch %d at time %d",
pLineObj->channelId, pDevObj->timeStamp));
Vp880UpdateBufferChanSel(pDevObj, channelId, sysState[0], TRUE);
if (pLineObj->slicValueCache != sysState[0]) {
/* Set line to Disconnect if not already there */
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("Tracker Disable: Setting Ch %d to State 0x%02X at time %d",
pLineObj->channelId, sysState[0], pDevObj->timeStamp));
pLineObj->slicValueCache = sysState[0];
VpMpiCmdWrapper(deviceId, ecVal, VP880_SYS_STATE_WRT,
VP880_SYS_STATE_LEN, &pLineObj->slicValueCache);
}
VpMemCpy(icr2Temp, pLineObj->icr2Values, VP880_ICR2_LEN);
pLineObj->icr2Values[VP880_ICR2_VOC_DAC_INDEX] |= VP880_ICR2_ILA_DAC;
pLineObj->icr2Values[VP880_ICR2_VOC_DAC_INDEX] &= ~VP880_ICR2_VOC_DAC_SENSE;
pLineObj->icr2Values[VP880_ICR2_VOC_DAC_INDEX+1] &= ~VP880_ICR2_ILA_DAC;
if ((icr2Temp[VP880_ICR2_VOC_DAC_INDEX] != pLineObj->icr2Values[VP880_ICR2_VOC_DAC_INDEX]) ||
(icr2Temp[VP880_ICR2_VOC_DAC_INDEX+1] != pLineObj->icr2Values[VP880_ICR2_VOC_DAC_INDEX+1])) {
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("Tracker Disable Update Required: ICR2 0x%02X 0x%02X 0x%02X 0x%02X Ch %d time %d",
pLineObj->icr2Values[0], pLineObj->icr2Values[1],
pLineObj->icr2Values[2], pLineObj->icr2Values[3],
pLineObj->channelId, pDevObj->timeStamp));
VpMpiCmdWrapper(deviceId, ecVal, VP880_ICR2_WRT,
VP880_ICR2_LEN, pLineObj->icr2Values);
}
}
break;
#endif
case VP_LINE_INTERNAL_TESTTERM_TIMER: {
/* Apply new bias settings to keep tip/ring near battery. */
/* While the internal test termination is applied, the
* line object ICR1 cache is used to keep track of what
* ICR1 needs to be once the internal test termination
* is removed. It will not match the actual register
* value. This is part of the internal test termination
* ICR1 override, so don't copy it to the line object */
uint8 icr1Reg[VP880_ICR1_LEN];
icr1Reg[0] = 0xFF;
icr1Reg[1] = 0x18;
icr1Reg[2] = 0xFF;
icr1Reg[3] = 0x04;
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("VP_LINE_INTERNAL_TESTTERM_TIMER Expired on Ch %d at time %d ICR1 Write: 0x%02X 0x%02X 0x%02X 0x%02X",
pLineObj->channelId, pDevObj->timeStamp,
icr1Reg[0], icr1Reg[1], icr1Reg[2], icr1Reg[3]));
VpMpiCmdWrapper(deviceId, ecVal, VP880_ICR1_WRT, VP880_ICR1_LEN, icr1Reg);
break;
}
#ifdef VP880_LP_SUPPORT
case VP_LINE_SPEEDUP_RECOVERY_TIMER:
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("VP_LINE_SPEEDUP_RECOVERY_TIMER Expired on Ch %d at time %d",
pLineObj->channelId, pDevObj->timeStamp));
pLineObj->icr2Values[VP880_ICR2_SPEEDUP_INDEX] &=
(uint8)(~(VP880_ICR2_MET_SPEED_CTRL | VP880_ICR2_BAT_SPEED_CTRL));
VpMpiCmdWrapper(deviceId, ecVal, VP880_ICR2_WRT,
VP880_ICR2_LEN, pLineObj->icr2Values);
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("ICR2_WRT 0x%02X 0x%02X 0x%02X 0x%02X",
pLineObj->icr2Values[0], pLineObj->icr2Values[1],
pLineObj->icr2Values[2], pLineObj->icr2Values[3]));
break;
#endif
default:
/*
* If we don't know what the timer is most likely it was masking hook or
* some other line detect activity. It can't hurt to force a signaling
* register read. If there are pending masks, the device specific API will
* freeze whatever status is necessary regardless of whether the signaling
* register is read or not.
*/
pDevObj->state |= VP_DEV_PENDING_INT;
break;
} /* Switch (timerType) */
} else { /* If timer has not expired, keep it going */
fxsTimers->timer[lineTimerType] |= VP_ACTIVATE_TIMER;
}
} /* if timerType is active */
} /* Loop through all timerTypes for chanID */
return;
}
/**
* Vp880ServiceDiscExitTimer()
* This function services active Disconnect Exit API timers.
*
* Preconditions:
* This Function must be called from the ApiTick function once per device.
*
* Postconditions:
* Active Disconnect Exit Timers for the current line have been serviced.
*/
void
Vp880ServiceDiscExitTimer(
VpLineCtxType *pLineCtx)
{
VpDevCtxType *pDevCtx = pLineCtx->pDevCtx;
Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj;
VpDeviceIdType deviceId = pDevObj->deviceId;
Vp880LineObjectType *pLineObj = pLineCtx->pLineObj;
uint8 ecVal = pLineObj->ecVal;
#ifdef VP880_LP_SUPPORT
uint8 channelId = pLineObj->channelId;
#endif
uint8 mpiBuffer[6 + VP880_REGULATOR_PARAM_LEN + VP880_ICR2_LEN + VP880_ICR3_LEN
+ VP880_ICR1_LEN + VP880_SYS_STATE_LEN + VP880_ICR4_LEN];
uint8 mpiIndex = 0;
uint8 speedUpByte;
bool stateChange = FALSE;
if (pLineObj->status & VP880_IS_FXO) {
return;
}
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("Disconnect Exit Timer State %d: Line Status 0x%04X on Ch %d time %d",
pLineObj->discTimerExitState, pLineObj->status, pLineObj->channelId, pDevObj->timeStamp));
if (pLineObj->discTimerExitState == 0) {
if (VpIsLowPowerTermType(pLineObj->termType)) {
#ifdef VP880_LP_SUPPORT
bool lpExit = FALSE;
#define ICR1_WRT_MASK (0x1)
#define ICR2_WRT_MASK (0x2)
#define ICR3_WRT_MASK (0x4)
#define ICR4_WRT_MASK (0x8)
#define SYS_STATE_WRT_MASK (0x10)
uint8 mpiCmdBitMask = ICR2_WRT_MASK; /* No matter what, ICR2 is being modified */
if(pLineObj->lineState.calType != VP_CSLAC_CAL_NONE) {
pLineObj->nextSlicValue &= VP880_SS_POLARITY_MASK;
pLineObj->nextSlicValue |= VP880_SS_ACTIVE;
}
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("LPM Disconnect Timer at time %d: currentState %d nextSlicValue 0x%02X usrState %d",
pDevObj->timeStamp, pLineObj->lineState.currentState,
pLineObj->nextSlicValue, pLineObj->lineState.usrCurrent));
/*
* If we're in Disconnect when this timer expires (entering Disconnect)
* need to correct ICR bits set to force feed toward ground and minimize
* power.
*/
if (pLineObj->lineState.currentState == VP_LINE_DISCONNECT) {
/* Entering VP_LINE_DISCONNECT... */
pLineObj->icr2Values[VP880_ICR2_VOC_DAC_INDEX] |= VP880_ICR2_ILA_DAC;
pLineObj->icr2Values[VP880_ICR2_VOC_DAC_INDEX] &= ~VP880_ICR2_VOC_DAC_SENSE;
pLineObj->icr2Values[VP880_ICR2_VOC_DAC_INDEX+1] &= ~VP880_ICR2_ILA_DAC;
/* Disable Line Control if in Disconnect */
pLineObj->icr3Values[VP880_ICR3_LINE_CTRL_INDEX+1] &= ~VP880_ICR3_LINE_CTRL;
mpiCmdBitMask |= (ICR2_WRT_MASK | ICR3_WRT_MASK);
} else if (pLineObj->nextSlicValue == VP880_SS_DISCONNECT) {
/* Entering Low Power Mode VP_LINE_STANDBY... */
if ((pDevObj->swParamsCache[VP880_FLOOR_VOLTAGE_BYTE] & 0x0D) != 0x0D) {
pDevObj->swParamsCache[VP880_FLOOR_VOLTAGE_BYTE] &= ~VP880_FLOOR_VOLTAGE_MASK;
pDevObj->swParamsCache[VP880_FLOOR_VOLTAGE_BYTE] |= 0x0D; /* 70V */
mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP880_REGULATOR_PARAM_WRT,
VP880_REGULATOR_PARAM_LEN, pDevObj->swParamsCache);
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("Line Entering LPM Standby Switcher Programming: 0x%02X 0x%02X 0x%02X time %d",
pDevObj->swParamsCache[0], pDevObj->swParamsCache[1], pDevObj->swParamsCache[2],
pDevObj->timeStamp));
}
pLineObj->icr2Values[VP880_ICR2_SENSE_INDEX] =
(VP880_ICR2_TIP_SENSE | VP880_ICR2_RING_SENSE |
VP880_ICR2_ILA_DAC | VP880_ICR2_FEED_SENSE);
pLineObj->icr2Values[VP880_ICR2_SENSE_INDEX+1] =
(VP880_ICR2_TIP_SENSE | VP880_ICR2_RING_SENSE | VP880_ICR2_FEED_SENSE);
mpiCmdBitMask |= ICR2_WRT_MASK;
} else {
/*
* Entering a non-LPM state. Make sure all ICR values are correct. These are
* slightly modified below to handle Disconnect Exit (Tip, Ring, Line Bias). But
* most important here is to reconfingure the SLIC to provide battery and work in
* (normal) current monitoring mode.
*/
Vp880SetLPRegisters(pLineObj, FALSE);
mpiCmdBitMask |= (ICR1_WRT_MASK | ICR2_WRT_MASK | ICR3_WRT_MASK | ICR4_WRT_MASK);
lpExit = TRUE;
/*
* The settings from calling Vp880SetLPRegisters(pLineObj, FALSE) are:
*
* pLineObj->icr3Values[VP880_ICR3_LINE_CTRL_INDEX] &= ~VP880_ICR3_LINE_CTRL;
*
* pLineObj->icr4Values[VP880_ICR4_SUP_INDEX] &=
* (uint8)(~(VP880_ICR4_SUP_DAC_CTRL | VP880_ICR4_SUP_DET_CTRL |
* VP880_ICR4_SUP_POL_CTRL));
*
* - Remove previously set SW control of ICR1 -
* pLineObj->icr1Values[VP880_ICR1_BIAS_OVERRIDE_LOCATION] &=
* ~VP880_ICR1_LINE_BIAS_OVERRIDE;
*
* pLineObj->icr2Values[VP880_ICR2_SENSE_INDEX] &=
* (uint8)(~(VP880_ICR2_RING_SENSE | VP880_ICR2_TIP_SENSE |
* VP880_ICR2_DAC_SENSE | VP880_ICR2_FEED_SENSE));
*/
}
if (pLineObj->nextSlicValue == VP880_SS_TIP_OPEN) {
/*
* This already occurred if we exited into Tip Open from Disconnect
* when the other line was in a LPM state (because setting to Tip
* Open takes the lines out of LPM). Lower level code will check
* to make sure this isn't redundant.
*/
Vp880GroundStartProc(TRUE, pLineCtx, 0x00, pLineObj->nextSlicValue);
} else {
/*
* Release Tip Bias Override and clear Line Bias values. If we're in a normal
* feed state (see next "if ()" condition) the Line Bias will be set back to
* normal values.
*/
pLineObj->icr1Values[VP880_ICR1_BIAS_OVERRIDE_LOCATION] &=
~VP880_ICR1_TIP_BIAS_OVERRIDE;
pLineObj->icr1Values[VP880_ICR1_BIAS_OVERRIDE_LOCATION+1] &=
(uint8)(~(VP880_ICR1_TIP_BIAS_OVERRIDE | VP880_ICR1_LINE_BIAS_OVERRIDE));
/*
* Restore Normal SLIC Bias if NOT in Disconnect. Otherwise the SLIC bias remains
* set to drive T/R near 0V
*/
if (pLineObj->lineState.currentState != VP_LINE_DISCONNECT) {
pLineObj->icr1Values[VP880_ICR1_BIAS_OVERRIDE_LOCATION+1] |=
VP880_ICR1_LINE_BIAS_OVERRIDE_NORM;
}
/* Release Ring Bias Override. */
pLineObj->icr1Values[VP880_ICR1_RING_BIAS_OVERRIDE_LOCATION] &=
~VP880_ICR1_RING_BIAS_OVERRIDE;
mpiCmdBitMask |= ICR1_WRT_MASK;
Vp880UpdateBufferChanSel(pDevObj, channelId, pLineObj->nextSlicValue, TRUE);
if (pLineObj->slicValueCache != pLineObj->nextSlicValue) {
mpiCmdBitMask |= SYS_STATE_WRT_MASK;
stateChange = TRUE;
}
}
/* Check if the sequence order is LPM Exit or same as previous API Releases */
if (lpExit) {
/* This just writes ICR[1:4] and the SLIC State Register in a specific order that
* works well for LPM Exit. Otherwise, there's nothing special about this function.
* We're only checking for lpExit because don't want to write values that have not
* been set above.
*/
Vp880WriteLPExitRegisters(pLineCtx, deviceId, ecVal, &pLineObj->nextSlicValue);
} else {
if (mpiCmdBitMask & ICR2_WRT_MASK) {
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("Disconnect Exit Timer: ICR2 0x%02X 0x%02X 0x%02X 0x%02X Ch %d time %d",
pLineObj->icr2Values[0], pLineObj->icr2Values[1],
pLineObj->icr2Values[2], pLineObj->icr2Values[3],
pLineObj->channelId, pDevObj->timeStamp));
mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP880_ICR2_WRT,
VP880_ICR2_LEN, pLineObj->icr2Values);
}
if (mpiCmdBitMask & ICR1_WRT_MASK) {
mpiIndex = Vp880ProtectedWriteICR1(pLineObj, mpiIndex, mpiBuffer);
}
if (mpiCmdBitMask & ICR3_WRT_MASK) {
mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP880_ICR3_WRT,
VP880_ICR3_LEN, pLineObj->icr3Values);
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("Disconnect Exit Timer: ICR3 0x%02X 0x%02X 0x%02X 0x%02X Ch %d time %d",
pLineObj->icr3Values[0], pLineObj->icr3Values[1],
pLineObj->icr3Values[2], pLineObj->icr3Values[3],
pLineObj->channelId, pDevObj->timeStamp));
}
if (mpiCmdBitMask & SYS_STATE_WRT_MASK) {
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("LPM Disconnect Exit Timer: Setting Ch %d to State 0x%02X from 0x%02X at time %d",
channelId, pLineObj->nextSlicValue, pLineObj->slicValueCache, pDevObj->timeStamp));
pLineObj->slicValueCache = pLineObj->nextSlicValue;
mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP880_SYS_STATE_WRT,
VP880_SYS_STATE_LEN, &pLineObj->slicValueCache);
}
/*
* Technically possible that mpiIndex = 0, but it shouldn't happen. This is
* just a safety net to prevent sending garbage to the device.
*/
if (mpiIndex > 0) {
VpMpiCmdWrapper(deviceId, ecVal, mpiBuffer[0], mpiIndex-1, &mpiBuffer[1]);
}
}
#endif /* VP880_LP_SUPPORT */
} else {
/* Non-LPM Disconnect Enter/Exit Additional Handling */
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("Disconnect Exit Timer for Non-LPM Termination Type Ch %d at time %d",
pLineObj->channelId, pDevObj->timeStamp));
/*
* Battery Speedup Control makes sense only on ABS and could be
* damaging if set.
*/
if (pDevObj->stateInt & VP880_IS_ABS) { /* ABS */
speedUpByte = VP880_ICR2_MET_SPEED_CTRL;
} else { /* other = Tracker */
speedUpByte = (VP880_ICR2_MET_SPEED_CTRL | VP880_ICR2_BAT_SPEED_CTRL);
}
if (pLineObj->lineState.currentState == VP_LINE_DISCONNECT) {
/* Line is in Disconnect */
/*
* Line State is already set, need to disable SLIC Bias in ICR1 and
* disable DC Feed/Battery Hold Speed in preperation for Disconnect
* exit.
*/
pLineObj->icr1Values[VP880_ICR1_BIAS_OVERRIDE_LOCATION+1] &=
~(VP880_ICR1_LINE_BIAS_OVERRIDE);
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("Non-LPM Disconnect Exit Timer: ICR1 0x%02X 0x%02X 0x%02X 0x%02X Ch %d at time %d",
pLineObj->icr1Values[0], pLineObj->icr1Values[1],
pLineObj->icr1Values[2], pLineObj->icr1Values[3],
pLineObj->channelId, pDevObj->timeStamp));
mpiIndex = Vp880ProtectedWriteICR1(pLineObj, mpiIndex, mpiBuffer);
pLineObj->icr2Values[VP880_ICR2_SPEEDUP_INDEX] |= speedUpByte;
pLineObj->icr2Values[VP880_ICR2_SPEEDUP_INDEX+1] |= speedUpByte;
} else {
/* Line is exiting Disconnect */
/* Line State needs to be corrected. SLIC Bias is already set */
if (pLineObj->slicValueCache != pLineObj->nextSlicValue) {
pLineObj->slicValueCache = pLineObj->nextSlicValue;
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("Non-LPM Disconnect Exit Timer: Setting Ch %d to State 0x%02X at time %d",
pLineObj->channelId, pLineObj->slicValueCache, pDevObj->timeStamp));
mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer,
VP880_SYS_STATE_WRT, VP880_SYS_STATE_LEN, &pLineObj->slicValueCache);
stateChange = TRUE;
}
/* Restore DC Feed and Battery Speedup Hold Times */
pLineObj->icr2Values[VP880_ICR2_SPEEDUP_INDEX] &= ~speedUpByte;
}
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("Non-LPM Disconnect Exit Timer: ICR2 0x%02X 0x%02X 0x%02X 0x%02X Ch %d at time %d",
pLineObj->icr2Values[0], pLineObj->icr2Values[1],
pLineObj->icr2Values[2], pLineObj->icr2Values[3],
pLineObj->channelId, pDevObj->timeStamp));
mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP880_ICR2_WRT,
VP880_ICR2_LEN, pLineObj->icr2Values);
VpMpiCmdWrapper(deviceId, ecVal, mpiBuffer[0], mpiIndex-1, &mpiBuffer[1]);
}
} else { /* Disconnect Exit State = 1 (all state changes done, end of debounce time */
/*
* Reset Disconnect Exit State for next use, although this should be set in the API where
* the Disconnect Timer is being set.
*/
pLineObj->discTimerExitState = 0;
}
#ifdef VP880_LP_SUPPORT
if(stateChange) {
/*
* If a state change was just made, we need to re-enable the Disconnect Hook/Groundkey
* debounce mask because line conditions are not immediatly stable.
*/
pLineObj->lineTimers.timers.timer[VP_LINE_DISCONNECT_EXIT] =
MS_TO_TICKRATE(VP_DISCONNECT_RECOVERY_TIME,
pDevObj->devProfileData.tickRate) | VP_ACTIVATE_TIMER;
pLineObj->discTimerExitState = 1;
} else {
if (VpIsLowPowerTermType(pLineObj->termType)) {
VpCslacLineCondType tempHookSt =
(VpCslacLineCondType)(pLineObj->lineState.condition & VP_CSLAC_HOOK);
/*
* Resolve hook state to avoid false leaky line test. Normal termination
* types ok since they don't run leaky line test.
*/
if ((pLineObj->lineState.currentState != VP_LINE_DISCONNECT)
&& (pLineObj->lineState.currentState != VP_LINE_TIP_OPEN)) {
if (!(pLineObj->status & VP880_LOW_POWER_EN)) {
if (!(pDevObj->intReg[channelId]) & VP880_HOOK1_MASK) {
if (tempHookSt != 0) {
VP_HOOK(VpLineCtxType, pLineCtx,
("Ch %d updating to On-Hook in non-LPM State at time %d",
channelId, pDevObj->timeStamp));
pLineObj->lineState.condition &= ~VP_CSLAC_HOOK;
Vp880UpdateHookInfo(pLineObj, pDevObj);
}
} else {
if (tempHookSt != VP_CSLAC_HOOK) {
VP_HOOK(VpLineCtxType, pLineCtx,
("Ch %d updating to Off-Hook in non-LPM State at time %d",
channelId, pDevObj->timeStamp));
pLineObj->lineState.condition |= VP_CSLAC_HOOK;
Vp880UpdateHookInfo(pLineObj, pDevObj);
}
}
} else {
if (pDevObj->intReg[channelId] & VP880_HOOK1_MASK) {
if (tempHookSt != 0) {
VP_HOOK(VpLineCtxType, pLineCtx,
("Ch %d updating to On-Hook in LPM State at time %d",
channelId, pDevObj->timeStamp));
pLineObj->lineState.condition &= ~VP_CSLAC_HOOK;
Vp880UpdateHookInfo(pLineObj, pDevObj);
}
} else {
if (tempHookSt != VP_CSLAC_HOOK) {
VP_HOOK(VpLineCtxType, pLineCtx,
("Ch %d updating to Off-Hook in LPM State at time %d",
channelId, pDevObj->timeStamp));
pLineObj->lineState.condition |= VP_CSLAC_HOOK;
Vp880UpdateHookInfo(pLineObj, pDevObj);
}
}
}
}
}
}
#endif /* VP880_LP_SUPPORT */
/*
* Force an interrupt read in all cases, just to update the signaling information in the
* device object. If we don't do this for polling methods other than Simple Polled, the
* interrupt and signaling information will not get properly serviced.
*/
pDevObj->state |= VP_DEV_PENDING_INT;
}
#ifdef VP880_LP_SUPPORT
/**
* Vp880UpdateHookInfo()
* This function updates the line object event and dial pulse data based on
* hook and DP Detection status. It is a helper function only for the VP880
* API used at the end of Disconnect Exit and Low Power Mode changes. It is not
* used in mid-DP detection.
*
* Preconditions:
* None. Helper function only.
*
* Postconditions:
* Line object data is updated. Event is generated IF Dial Pulse detection is
* disabled. If DP Detection is enabled, Dial Pulse state machine is updated.
*/
void
Vp880UpdateHookInfo(
Vp880LineObjectType *pLineObj,
Vp880DeviceObjectType *pDevObj)
{
VP_HOOK(None, VP_NULL, ("Vp880UpdateHookInfo()+"));
if (pLineObj->lineState.condition & VP_CSLAC_HOOK) {
/*
* Only post the off-hook event if it was NOT the last event posted
* w.r.t. on-hook.
*
* Generate the event whether running API DP Detection or Not (because
* initial off-hook is not a DP dependant parameter)
*/
if (!(pLineObj->status & VP880_PREVIOUS_HOOK)) {
VP_HOOK(None, VP_NULL,
("Generating Off-Hook Event Ch %d at time %d",
pLineObj->channelId, pDevObj->timeStamp));
pLineObj->lineEvents.signaling |= VP_LINE_EVID_HOOK_OFF;
}
/*
* If using the VP-API-II Dial Pulse Detection, need to also update
* the Dial Pulse State machine.
*/
if (pLineObj->pulseMode == VP_OPTION_PULSE_DECODE_ON) {
VP_HOOK(None, VP_NULL,
("Feeding Off-Hook information Ch %d to Dial Pulse State machine at time %d",
pLineObj->channelId, pDevObj->timeStamp));
pLineObj->dpStruct.hookSt = TRUE;
pLineObj->dpStruct2.hookSt = TRUE;
/*
* Init prevents DP detection in this pass, but this update is
* happening because the hook state is different after a major
* transition. So not in the middle if DP detection.
*/
VpInitDP(&pLineObj->dpStruct);
VpInitDP(&pLineObj->dpStruct);
pLineObj->lineEventHandle = VP_DP_PARAM1;
}
} else {
if (pLineObj->pulseMode == VP_OPTION_PULSE_DECODE_OFF) {
/* VP-API-II NOT doing Dial Pulse Detection, generate event here. */
VP_HOOK(None, VP_NULL,
("Generating On-Hook Event Ch %d at time %d",
pLineObj->channelId, pDevObj->timeStamp));
/*
* Only post the on-hook event if it was NOT the last event posted
* w.r.t. off-hook
*/
if (pLineObj->status & VP880_PREVIOUS_HOOK) {
pLineObj->lineEvents.signaling |= VP_LINE_EVID_HOOK_ON;
}
} else {
/*
* VP-API-II doing Dial Pulse Detection, update the Dial Pulse State
* machines and generate the Start Pulse Event. The normal API FXS
* processing and DP State Machine will continue to handle on-hook
* for the on-hook event.
*/
VP_HOOK(None, VP_NULL,
("Feeding On-Hook information Ch %d to Dial Pulse State machine at time %d",
pLineObj->channelId, pDevObj->timeStamp));
/*
* Note that this is not treated the same way as off-hook, because
* in this case we want to generate the "Start Pulse" event first
* before the on-hook event. State Machines using VP-API-II DP
* Detection will generally be looking for both events.
*/
pLineObj->dpStruct.hookSt = FALSE;
pLineObj->dpStruct.lo_time = 0;
pLineObj->dpStruct.lc_time = 0xFFFF;
pLineObj->dpStruct2.hookSt = FALSE;
pLineObj->dpStruct2.lo_time = 0;
pLineObj->dpStruct2.lc_time = 0xFFFF;
pLineObj->lineEventHandle = VP_DP_PARAM1;
/* This event should not be generated if we just completed a Leaky Line Test and
* "simply" determined that the line is still on-hook. This can occur for leaky line
* conditions that cause long detection of loop close in the LPM condition. The
* last hook event reported will have been on-hook, so we can easily check for this
*/
if (pLineObj->status & VP880_PREVIOUS_HOOK) { /* Last reported event was off-hook */
pLineObj->lineEvents.signaling |= VP_LINE_EVID_STARTPULSE;
}
}
}
pLineObj->lineEventHandle = pDevObj->timeStamp;
}
#endif
/**
* Vp880ServiceGroundStartTimer()
* This function services active Ground Start API timers.
*
* Preconditions:
* This Function must be called from the ApiTick function once per device.
*
* Postconditions:
* Active Ground Start Timers for the current line have been serviced.
*/
void
Vp880ServiceGroundStartTimer(
VpLineCtxType *pLineCtx)
{
Vp880LineObjectType *pLineObj = pLineCtx->pLineObj;
VpDevCtxType *pDevCtx = pLineCtx->pDevCtx;
Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj;
VpDeviceIdType deviceId = pDevObj->deviceId;
uint8 ecVal = pLineObj->ecVal;
uint8 mpiBuffer[2 * (2 + VP880_ICR3_LEN + VP880_ICR4_LEN)
+ 3 + VP880_ICR1_LEN + VP880_ICR2_LEN + VP880_SYS_STATE_LEN];
uint8 mpiIndex = 0;
if (pLineObj->lineState.currentState != VP_LINE_TIP_OPEN) {
if (pLineObj->gsTimerExitState == 0) {
pLineObj->icr3Values[VP880_ICR3_LONG_LOOP_CTRL_LOCATION] &=
~VP880_ICR3_LONG_LOOP_CONTROL;
VP_LINE_STATE(VpLineCtxType, pLineCtx, ("Ground Key Timer: Write ICR3 0x%02X 0x%02X 0x%02X 0x%02X Ch %d Time %d",
pLineObj->icr3Values[0], pLineObj->icr3Values[1],
pLineObj->icr3Values[2], pLineObj->icr3Values[3],
pLineObj->channelId, pDevObj->timeStamp));
mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP880_ICR3_WRT,
VP880_ICR3_LEN, pLineObj->icr3Values);
pLineObj->icr4Values[VP880_ICR4_GKEY_DET_LOCATION] &= ~VP880_ICR4_GKEY_DET;
VP_LINE_STATE(VpLineCtxType, pLineCtx, ("Ground Key Timer: Write ICR4 0x%02X 0x%02X 0x%02X 0x%02X Ch %d Time %d",
pLineObj->icr4Values[0], pLineObj->icr4Values[1],
pLineObj->icr4Values[2], pLineObj->icr4Values[3],
pLineObj->channelId, pDevObj->timeStamp));
mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP880_ICR4_WRT,
VP880_ICR4_LEN, pLineObj->icr4Values);
if ((pLineObj->lineState.currentState == VP_LINE_RINGING)
|| (pLineObj->lineState.currentState == VP_LINE_RINGING_POLREV)) {
Vp880UpdateBufferChanSel(pDevObj, pLineObj->channelId,
pLineObj->nextSlicValue, TRUE);
pLineObj->slicValueCache = pLineObj->nextSlicValue;
VP_LINE_STATE(VpLineCtxType, pLineCtx,
("Ground Key Timer: Setting Ch %d to State 0x%02X at time %d",
pLineObj->channelId, pLineObj->nextSlicValue, pDevObj->timeStamp));
mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer,
VP880_SYS_STATE_WRT, VP880_SYS_STATE_LEN, &pLineObj->slicValueCache);
}
VpMpiCmdWrapper(deviceId, ecVal, mpiBuffer[0], mpiIndex-1, &mpiBuffer[1]);
/* Final debounce to prevent spurious ground key events. */
pLineObj->lineTimers.timers.timer[VP_LINE_GND_START_TIMER] =
(MS_TO_TICKRATE(VP880_GND_START_DEBOUNCE,
pDevObj->devProfileData.tickRate)) | VP_ACTIVATE_TIMER;
/* Advance to next ground start exit timer state */
pLineObj->gsTimerExitState = 1;
} else {
/*
* Reset ground start exit timer state. This step should be unnecessary - done by
* functions that start the Ground Start Exit timer
*/
pLineObj->gsTimerExitState = 0;
}
} else {
/*
* Line State is TIP_OPEN. Set ICR registers accordingly (NOTE: Some
* will have been set prior to this point, but doesn't hurt to be
* sure).
*/
/*
* These bits are set for LPM Standby and Disconnect. Clear just in case
* we're coming from either of those states.
*/
pLineObj->icr1Values[VP880_ICR1_BIAS_OVERRIDE_LOCATION] &=
~(VP880_ICR1_LINE_BIAS_OVERRIDE);
mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP880_ICR1_WRT,
VP880_ICR1_LEN, pLineObj->icr1Values);
pLineObj->icr2Values[VP880_ICR2_SENSE_INDEX] &=
~(VP880_ICR2_DAC_SENSE | VP880_ICR2_FEED_SENSE |
VP880_ICR2_TIP_SENSE | VP880_ICR2_RING_SENSE);
mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP880_ICR2_WRT,
VP880_ICR2_LEN, pLineObj->icr2Values);
pLineObj->icr3Values[VP880_ICR3_LINE_CTRL_INDEX] &= ~VP880_ICR3_LINE_CTRL;
mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP880_ICR3_WRT,
VP880_ICR3_LEN, pLineObj->icr3Values);
pLineObj->icr4Values[VP880_ICR4_SUP_INDEX] &=
~(VP880_ICR4_SUP_DAC_CTRL | VP880_ICR4_SUP_DET_CTRL | VP880_ICR4_SUP_POL_CTRL);
mpiIndex = VpCSLACBuildMpiBuffer(mpiIndex, mpiBuffer, VP880_ICR4_WRT,
VP880_ICR4_LEN, pLineObj->icr4Values);
VpMpiCmdWrapper(deviceId, ecVal, mpiBuffer[0], mpiIndex-1, &mpiBuffer[1]);
}
}
#endif
#ifdef VP880_FXO_SUPPORT
/**
* Vp880ServiceFxoTimers()
* This function services active FXO API timers.
*
* Preconditions:
* This Function must be called from the ApiTick function once per device.
*
* Postconditions:
* All Active FXO Timers for the current line have been serviced.
*/
void
Vp880ServiceFxoTimers(
VpLineCtxType *pLineCtx)
{
Vp880LineObjectType *pLineObj = pLineCtx->pLineObj;
VpDevCtxType *pDevCtx = pLineCtx->pDevCtx;
Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj;
VpFXOTimerType *pFxoTimer = &pLineObj->lineTimers.timers.fxoTimer;
uint16 tickAdder =
pDevObj->devProfileData.tickRate / (VP_CSLAC_TICKSTEP_0_5MS / 2);
/* Increment the time since polrev was observed */
if (pFxoTimer->timeLastPolRev < (0x7FFF - tickAdder)) {
/*
* The time is in 0.25mS increments, but the device
* tickrate is something else. Increment by the scaled
* amount.
*/
pFxoTimer->timeLastPolRev += tickAdder;
} else {
/* Max limit the value of last polrev value */
pFxoTimer->timeLastPolRev = 0x7FFF;
}
/* Set tick adder for 1ms increments */
tickAdder =
pDevObj->devProfileData.tickRate / (VP_CSLAC_TICKSTEP_0_5MS * 2);
if (((uint16)pFxoTimer->lastStateChange + tickAdder) > 255) {
pFxoTimer->lastStateChange = 255;
} else {
pFxoTimer->lastStateChange += tickAdder;
}
if (((uint16)pFxoTimer->lastNotLiu - tickAdder) <= 0) {
pFxoTimer->lastNotLiu = 0;
} else {
pFxoTimer->lastNotLiu-=tickAdder;
}
if (((uint16)pFxoTimer->fxoDiscIO2Change - tickAdder) <= 0) {
pFxoTimer->fxoDiscIO2Change = 0;
} else {
pFxoTimer->fxoDiscIO2Change -= tickAdder;
}
if (pFxoTimer->disconnectDebounce >= tickAdder) {
pFxoTimer->disconnectDebounce -= tickAdder;
if (pFxoTimer->disconnectDebounce ==0) {
if (pLineObj->preDisconnect ==
(VpCslacLineCondType)(pLineObj->lineState.condition & VP_CSLAC_RAW_DISC)) {
/*
* There is a change that persisted longer than the
* debounce interval. Evaluate and generate event
*/
pLineObj->lineEventHandle = pDevObj->timeStamp;
switch(pLineObj->lineState.usrCurrent) {
case VP_LINE_FXO_TALK:
case VP_LINE_FXO_LOOP_CLOSE:
if (pLineObj->preDisconnect == VP_CSLAC_RAW_DISC) {
if (!(pLineObj->lineState.condition & VP_CSLAC_DISC)) {
pLineObj->lineState.condition |= VP_CSLAC_DISC;
pLineObj->lineEvents.fxo |= VP_LINE_EVID_DISCONNECT;
}
} else {
if (pLineObj->lineState.condition & VP_CSLAC_DISC) {
pLineObj->lineState.condition &= ~VP_CSLAC_DISC;
pLineObj->lineEvents.fxo |= VP_LINE_EVID_RECONNECT;
}
}
break;
default:
if (pLineObj->preDisconnect == VP_CSLAC_RAW_DISC) {
if (!(pLineObj->lineState.condition & VP_CSLAC_DISC)) {
pLineObj->lineState.condition |= VP_CSLAC_DISC;
pLineObj->lineEvents.fxo |= VP_LINE_EVID_FEED_DIS;
}
} else {
if (pLineObj->lineState.condition & VP_CSLAC_DISC) {
pLineObj->lineState.condition &= ~VP_CSLAC_DISC;
pLineObj->lineEvents.fxo |= VP_LINE_EVID_FEED_EN;
}
}
break;
}
}
}
}
}
#endif
#ifdef VP880_INCLUDE_TESTLINE_CODE
/**
* Vp880GetRelayState()
* This function returns the current relay state of VP880 device.
*
* Preconditions:
* Device/Line context should be created and initialized.
*
* Postconditions:
* The indicated relay state is returned for the given line.
*/
VpStatusType
Vp880GetRelayState(
VpLineCtxType *pLineCtx,
VpRelayControlType *pRstate)
{
VpDevCtxType *pDevCtx;
Vp880DeviceObjectType *pDevObj;
Vp880LineObjectType *pLineObj;
VpDeviceIdType deviceId;
if(pLineCtx == VP_NULL) {
return VP_STATUS_INVALID_ARG;
}
pDevCtx = pLineCtx->pDevCtx;
pLineObj = pLineCtx->pLineObj;
pDevObj = pDevCtx->pDevObj;
deviceId = pDevObj->deviceId;
VpSysEnterCritical(deviceId, VP_CODE_CRITICAL_SEC);
*pRstate = pLineObj->relayState;
VpSysExitCritical(deviceId, VP_CODE_CRITICAL_SEC);
return VP_STATUS_SUCCESS;
}
#endif
#if (VP_CC_DEBUG_SELECT & VP_DBG_ERROR)
/**
* Vp880RegisterDump()
* Dump all known 880 device and line specific registers (for debug purposes).
*
* Returns:
*/
VpStatusType
Vp880RegisterDump(
VpDevCtxType *pDevCtx)
{
Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj;
VpDeviceIdType deviceId = pDevObj->deviceId;
uint8 channelId, ecVal, registerIndex, registerNumber;
/* Sufficient size to hold a single MPI Read is all that is needed. */
uint8 registerBuffer[20];
#define VP880_DEVICE_REGISTER_COUNT 13
uint8 deviceRegs[VP880_DEVICE_REGISTER_COUNT][2] = {
{VP880_DEVTYPE_RD, VP880_DEVTYPE_LEN},
{VP880_DEV_MODE_RD, VP880_DEV_MODE_LEN},
{VP880_TEST_REG1_RD, VP880_TEST_REG1_LEN},
{VP880_TEST_REG2_RD, VP880_TEST_REG2_LEN},
{VP880_DCR_RD, VP880_DCR_LEN},
{VP880_OP_MODE_RD, VP880_OP_MODE_LEN},
{VP880_XR_CS_RD, VP880_XR_CS_LEN},
{VP880_NO_UL_SIGREG_RD, VP880_NO_UL_SIGREG_LEN},
{VP880_INT_MASK_RD, VP880_INT_MASK_LEN},
{VP880_REV_INFO_RD, VP880_REV_INFO_LEN},
{VP880_REGULATOR_PARAM_RD, VP880_REGULATOR_PARAM_LEN},
{VP880_REGULATOR_CTRL_RD, VP880_REGULATOR_CTRL_LEN},
{VP880_INT_SWREG_PARAM_RD, VP880_INT_SWREG_PARAM_LEN}
};
char *deviceRegsName[VP880_DEVICE_REGISTER_COUNT] = {
"VP880_DEVTYPE_RD", "VP880_DEV_MODE_RD", "VP880_TEST_REG1_RD",
"VP880_TEST_REG2_RD", "VP880_DCR_RD", "VP880_OP_MODE_RD",
"VP880_XR_CS_RD", "VP880_NO_UL_SIGREG_RD", "VP880_INT_MASK_RD",
"VP880_REV_INFO_RD", "VP880_REGULATOR_PARAM_RD", "VP880_REGULATOR_CTRL_RD",
"VP880_INT_SWREG_PARAM_RD"
};
VP_ERROR(VpDevCtxType, pDevCtx,("Device Registers:"));
ecVal = pDevObj->ecVal;
for (registerNumber = 0; registerNumber < VP880_DEVICE_REGISTER_COUNT; registerNumber++) {
VpMpiCmdWrapper(deviceId, ecVal,
deviceRegs[registerNumber][0], deviceRegs[registerNumber][1],
registerBuffer);
VpSysDebugPrintf("\n\r%s (0x%02X) ",
deviceRegsName[registerNumber], deviceRegs[registerNumber][0]);
for (registerIndex = 0;
registerIndex < deviceRegs[registerNumber][1];
registerIndex++) {
VpSysDebugPrintf("0x%02X ", registerBuffer[registerIndex]);
}
}
for (channelId = 0; channelId < pDevObj->staticInfo.maxChannels; channelId++) {
#define VP880_CHANNEL_REGISTER_COUNT 33
uint8 channelRegs[VP880_CHANNEL_REGISTER_COUNT][2] = {
{VP880_SYS_STATE_RD, VP880_SYS_STATE_LEN},
{VP880_SS_CONFIG_RD, VP880_SS_CONFIG_LEN},
{VP880_CONV_CFG_RD, VP880_CONV_CFG_LEN},
{VP880_ICR1_RD, VP880_ICR1_LEN},
{VP880_ICR2_RD, VP880_ICR2_LEN},
{VP880_ICR3_RD, VP880_ICR3_LEN},
{VP880_ICR4_RD, VP880_ICR4_LEN},
{VP880_ICR5_RD, VP880_ICR5_LEN},
{VP880_ICR6_RD, VP880_ICR6_LEN},
{VP880_DISN_RD, VP880_DISN_LEN},
{VP880_VP_GAIN_RD, VP880_VP_GAIN_LEN},
{VP880_GR_GAIN_RD, VP880_GR_GAIN_LEN},
{VP880_GX_GAIN_RD, VP880_GX_GAIN_LEN},
{VP880_X_FILTER_RD, VP880_X_FILTER_LEN},
{VP880_R_FILTER_RD, VP880_R_FILTER_LEN},
{VP880_B1_FILTER_RD, VP880_B1_FILTER_LEN},
{VP880_B2_FILTER_RD, VP880_B2_FILTER_LEN},
{VP880_Z1_FILTER_RD, VP880_Z1_FILTER_LEN},
{VP880_Z2_FILTER_RD, VP880_Z2_FILTER_LEN},
{VP880_OP_FUNC_RD, VP880_OP_FUNC_LEN},
{VP880_OP_COND_RD, VP880_OP_COND_LEN},
{VP880_IODATA_REG_RD, VP880_IODATA_REG_LEN},
{VP880_IODIR_REG_RD, VP880_IODIR_REG_LEN},
{VP880_BAT_CALIBRATION_RD, VP880_BAT_CALIBRATION_LEN},
{VP880_TX_TS_RD, VP880_TX_TS_LEN},
{VP880_RX_TS_RD, VP880_RX_TS_LEN},
{VP880_DC_FEED_RD, VP880_DC_FEED_LEN},
{VP880_LOOP_SUP_RD, VP880_LOOP_SUP_LEN},
{VP880_SIGA_PARAMS_RD, VP880_SIGA_PARAMS_LEN},
{VP880_SIGCD_PARAMS_RD, VP880_SIGCD_PARAMS_LEN},
{VP880_CADENCE_TIMER_RD, VP880_CADENCE_TIMER_LEN},
{VP880_CID_PARAM_RD, VP880_CID_PARAM_LEN},
{VP880_METERING_PARAM_RD, VP880_METERING_PARAM_LEN}
};
char *registerName[VP880_CHANNEL_REGISTER_COUNT] = {
"VP880_SYS_STATE_RD", "VP880_SS_CONFIG_RD", "VP880_CONV_CFG_RD",
"VP880_ICR1_RD", "VP880_ICR2_RD", "VP880_ICR3_RD",
"VP880_ICR4_RD", "VP880_ICR5_RD", "VP880_ICR6_RD",
"VP880_DISN_RD", "VP880_VP_GAIN_RD", "VP880_GR_GAIN_RD",
"VP880_GX_GAIN_RD", "VP880_X_FILTER_RD", "VP880_R_FILTER_RD",
"VP880_B1_FILTER_RD", "VP880_B2_FILTER_RD", "VP880_Z1_FILTER_RD",
"VP880_Z2_FILTER_RD", "VP880_OP_FUNC_RD", "VP880_OP_COND_RD",
"VP880_IODATA_REG_RD", "VP880_IODIR_REG_RD", "VP880_BAT_CALIBRATION_RD",
"VP880_TX_TS_RD", "VP880_RX_TS_RD", "VP880_DC_FEED_RD",
"VP880_LOOP_SUP_RD", "VP880_SIGA_PARAMS_RD", "VP880_SIGCD_PARAMS_RD",
"VP880_CADENCE_TIMER_RD", "VP880_CID_PARAM_RD", "VP880_METERING_PARAM_RD"
};
ecVal = (channelId == 0) ? VP880_EC_CH1 : VP880_EC_CH2;
ecVal |= pDevObj->ecVal;
VpSysDebugPrintf("\n\rCHANNEL %d", channelId);
for (registerNumber = 0; registerNumber < VP880_CHANNEL_REGISTER_COUNT; registerNumber++) {
VpMpiCmdWrapper(deviceId, ecVal,
channelRegs[registerNumber][0], channelRegs[registerNumber][1],
registerBuffer);
VpSysDebugPrintf("\n\r%s (0x%02X) ",
registerName[registerNumber], channelRegs[registerNumber][0]);
for (registerIndex = 0;
registerIndex < channelRegs[registerNumber][1];
registerIndex++) {
VpSysDebugPrintf("0x%02X ", registerBuffer[registerIndex]);
}
}
}
VpSysDebugPrintf("\n\r");
return VP_STATUS_SUCCESS;
}
/**
* Vp880ObjectDump()
* Dump 880 device and line object data. Upper level calls may limit this to
* device object OR line object, but there's no reason we need to enforce that.
*
* This function is for SW Apps debug purposes only. Not to be documented for
* customer purposes. It will significantly increase the driver size, implement
* so as totally removed when Debug Error is not enabled.
*
* Returns: VP_STATUS_SUCCESS
*/
VpStatusType
Vp880ObjectDump(
VpLineCtxType *pLineCtx,
VpDevCtxType *pDevCtx)
{
if (pDevCtx != VP_NULL) {
Vp880DeviceObjectType *pDevObj = pDevCtx->pDevObj;
VP_PRINT_DEVICE_ID(pDevObj->deviceId);
VpPrintStaticInfoStruct(&pDevObj->staticInfo);
VpPrintDynamicInfoStruct(&pDevObj->dynamicInfo);
VpPrintStateInformation(pDevObj->state);
VpSysDebugPrintf("\n\rpDevObj->stateInt = 0x%08lX", pDevObj->stateInt);
VpPrintDeviceProfileStruct(VP_DEV_880_SERIES, &pDevObj->devProfileData);
VpPrintEventMaskStruct(TRUE, TRUE, &pDevObj->deviceEventsMask);
VpPrintEventMaskStruct(TRUE, FALSE, &pDevObj->deviceEvents);
VpPrintEventHandle(pDevObj->eventHandle);
VpPrintTimeStamp(pDevObj->timeStamp);
VpPrintGetResultsOptionStruct(&pDevObj->getResultsOption);
VpPrintCriticalFltStruct(&pDevObj->criticalFault);
VpPrintRelGainResultsStruct(&pDevObj->relGainResults);
#ifdef VP880_FXS_SUPPORT
VpSysDebugPrintf("\n\n\rpDevObj->swParams = 0x%02X 0x%02X 0x%02X",
pDevObj->swParams[0], pDevObj->swParams[1], pDevObj->swParams[2]);
VpSysDebugPrintf("\n\n\rpDevObj->swParamsCache = 0x%02X 0x%02X 0x%02X",
pDevObj->swParamsCache[0], pDevObj->swParamsCache[1],
pDevObj->swParamsCache[2]);
{
uint8 byteCount;
VpSysDebugPrintf("\n\rpDevObj->intSwParams =");
for (byteCount = 0; byteCount < VP880_INT_SWREG_PARAM_LEN; byteCount++) {
VpSysDebugPrintf(" 0x%02X", pDevObj->intSwParams[byteCount]);
}
}
{
uint8 byteCount;
VpSysDebugPrintf("\n\rpDevObj->intSwParamsFR =");
for (byteCount = 0; byteCount < VP880_INT_SWREG_PARAM_LEN; byteCount++) {
VpSysDebugPrintf(" 0x%02X", pDevObj->intSwParamsFR[byteCount]);
}
}
#endif
VpSysDebugPrintf("\n\n\rpDevObj->devMode = 0x%02X", pDevObj->devMode[0]);
VpPrintDeviceTimers(pDevObj->devTimer);
VpPrintDeviceProfileTable(&pDevObj->devProfileTable);
VpPrintProfileTableEntry(&pDevObj->profEntry);
VpSysDebugPrintf("\n\n\rpDevObj->intReg = 0x%02X 0x%02X",
pDevObj->intReg[0], pDevObj->intReg[1]);
VpSysDebugPrintf("\n\rpDevObj->intReg2 = 0x%02X 0x%02X",
pDevObj->intReg2[0], pDevObj->intReg2[1]);
VpPrintResponseData(pDevObj->responseData);
VpPrintTxBufferRate(pDevObj->txBufferDataRate);
VpSysDebugPrintf("\n\n\rpDevObj->mpiLen = %d", pDevObj->mpiLen);
#if !defined(VP_REDUCED_API_IF) || defined(ZARLINK_CFG_INTERNAL)
{
uint8 byteCount;
VpSysDebugPrintf("\n\rpDevObj->mpiData =");
for (byteCount = 0; byteCount < VP880_MAX_MPI_DATA; byteCount++) {
VpSysDebugPrintf(" 0x%02X", pDevObj->mpiData[byteCount]);
}
}
#endif
#ifdef VP880_FXS_SUPPORT
VpPrintPulseSpecs(0, &pDevObj->pulseSpecs);
VpPrintPulseSpecs(1, &pDevObj->pulseSpecs2);
#endif
VpSysDebugPrintf("\n\n\rpDevObj->debugSelectMask = 0x%08lX",
pDevObj->debugSelectMask);
VpSysDebugPrintf("\n\n\rpDevObj->ecVal = 0x%02X", pDevObj->ecVal);
VpSysDebugPrintf("\n\n\rpDevObj->lastCodecChange = %d",
pDevObj->lastCodecChange);
}
if (pLineCtx != VP_NULL) {
Vp880LineObjectType *pLineObj = pLineCtx->pLineObj;
VP_PRINT_LINE_ID(pLineObj->lineId);
VpSysDebugPrintf("\n\n\rpLineObj->channelId = %d\npLineObj->ecVal = 0x%02X",
pLineObj->channelId, pLineObj->ecVal);
VpPrintTermType(pLineObj->termType);
VpSysDebugPrintf("\n\rpLineObj->status = 0x%04X ", pLineObj->status);
VpSysDebugPrintf("\n\rpLineObj->debugSelectMask = 0x%08lX ", pLineObj->debugSelectMask);
VpPrintEventMaskStruct(FALSE, TRUE, &pLineObj->lineEventsMask);
VpPrintEventMaskStruct(FALSE, FALSE, &pLineObj->lineEvents);
#ifdef VP880_FXS_SUPPORT
VpSysDebugPrintf("\n\n\rpLineObj->pulseMode = %s",
((pLineObj->pulseMode == VP_OPTION_PULSE_DECODE_ON) ?
"VP_OPTION_PULSE_DECODE_ON" : "VP_OPTION_PULSE_DECODE_OFF"));
VpPrintDPStateMachine(0, &pLineObj->dpStruct);
VpPrintDPStateMachine(1, &pLineObj->dpStruct2);
#endif
VpSysDebugPrintf("\n\n\rpLineObj->slicValueCache = 0x%02X", pLineObj->slicValueCache);
VpSysDebugPrintf("\n\rpLineObj->nextSlicValue = 0x%02X", pLineObj->nextSlicValue);
VpPrintApiIntLineState(&pLineObj->lineState);
VpSysDebugPrintf("\n\rpLineObj->opCond = 0x%02X", pLineObj->opCond[0]);
VpSysDebugPrintf("\n\rpLineObj->loopSup = 0x%02X 0x%02X 0x%02X 0x%02X",
pLineObj->loopSup[0], pLineObj->loopSup[1],
pLineObj->loopSup[2], pLineObj->loopSup[3]);
#ifdef VP880_FXS_SUPPORT
VpSysDebugPrintf("\n\n\rpLineObj->icr1 = 0x%02X 0x%02X 0x%02X 0x%02X",
pLineObj->icr1Values[0], pLineObj->icr1Values[1],
pLineObj->icr1Values[2], pLineObj->icr1Values[3]);
VpSysDebugPrintf("\n\rpLineObj->icr2 = 0x%02X 0x%02X 0x%02X 0x%02X",
pLineObj->icr2Values[0], pLineObj->icr2Values[1],
pLineObj->icr2Values[2], pLineObj->icr2Values[3]);
VpSysDebugPrintf("\n\rpLineObj->icr3 = 0x%02X 0x%02X 0x%02X 0x%02X",
pLineObj->icr3Values[0], pLineObj->icr3Values[1],
pLineObj->icr3Values[2], pLineObj->icr3Values[3]);
VpSysDebugPrintf("\n\rpLineObj->icr4 = 0x%02X 0x%02X 0x%02X 0x%02X",
pLineObj->icr4Values[0], pLineObj->icr4Values[1],
pLineObj->icr4Values[2], pLineObj->icr4Values[3]);
#endif
VpSysDebugPrintf("\n\rpLineObj->sigGenCtrl = 0x%02X", pLineObj->sigGenCtrl[0]);
VpSysDebugPrintf("\n\n\rpLineObj->gain.gxInt = 0x%04X", pLineObj->gain.gxInt);
VpSysDebugPrintf("\n\rpLineObj->gain.grInt = 0x%04X", pLineObj->gain.grInt);
VpSysDebugPrintf("\n\rpLineObj->gain.absGxGain = %d", pLineObj->gain.absGxGain);
VpSysDebugPrintf("\n\rpLineObj->gain.absGrGain = %d", pLineObj->gain.absGrGain);
VpSysDebugPrintf("\n\n\rpLineObj->lineEventHandle = 0x%02X", pLineObj->lineEventHandle);
VpSysDebugPrintf("\n\rpLineObj->signaling1 = 0x%04X", pLineObj->signaling1);
VpSysDebugPrintf("\n\rpLineObj->signaling2 = 0x%04X", pLineObj->signaling2);
VpSysDebugPrintf("\n\rpLineObj->signalingData = 0x%02X", pLineObj->signalingData);
VpSysDebugPrintf("\n\rpLineObj->processData = 0x%04X", pLineObj->processData);
VpSysDebugPrintf("\n\rpLineObj->responseData = 0x%04X", pLineObj->responseData);
VpSysDebugPrintf("\n\rpLineObj->dtmfDigitSense = 0x%04X", pLineObj->dtmfDigitSense);
VpPrintOptionCodecType(pLineObj->codec);
VpPrintOptionPcmTxRxCntrlType(pLineObj->pcmTxRxCtrl);
#ifdef VP_CSLAC_SEQ_EN
{
uint8 intSeqData;
VpSysDebugPrintf("\npLineObj->intSequence =");
for (intSeqData = 0; intSeqData < VP880_INT_SEQ_LEN; intSeqData++) {
VpSysDebugPrintf(" 0x%02X", pLineObj->intSequence[intSeqData]);
}
}
VpPrintSeqDataType(&pLineObj->cadence);
#endif
VpPrint880CalLineData(&pLineObj->calLineData);
VpPrintVpCslacTimerStruct(&pLineObj->lineTimers);
#ifdef VP880_FXS_SUPPORT
VpSysDebugPrintf("\n\nFXS ONLY DATA:");
#ifdef VP880_LP_SUPPORT
VpSysDebugPrintf("\n\rpLineObj->leakyLineCnt = %d", pLineObj->leakyLineCnt);
#endif
VpSysDebugPrintf("\n\rpLineObj->ringingParams = 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
pLineObj->ringingParams[0], pLineObj->ringingParams[1],
pLineObj->ringingParams[2], pLineObj->ringingParams[3],
pLineObj->ringingParams[4], pLineObj->ringingParams[5],
pLineObj->ringingParams[6], pLineObj->ringingParams[7],
pLineObj->ringingParams[8], pLineObj->ringingParams[9],
pLineObj->ringingParams[10]);
VpSysDebugPrintf("\n\rpLineObj->hookHysteresis = %d", pLineObj->hookHysteresis);
VpSysDebugPrintf("\n\rpLineObj->internalTestTermApplied = %s",
((pLineObj->internalTestTermApplied == TRUE) ? "TRUE" : "FALSE"));
VpPrintOptionRingControlType(&pLineObj->ringCtrl);
VpPrintRelayControlType(pLineObj->relayState);
#ifdef VP_CSLAC_SEQ_EN
VpSysDebugPrintf("\n\rpLineObj->pRingingCadence = %p", pLineObj->pRingingCadence);
VpSysDebugPrintf("\n\rpLineObj->pCidProfileType1 = %p", pLineObj->pCidProfileType1);
VpSysDebugPrintf("\n\rpLineObj->suspendCid = %s",
((pLineObj->suspendCid == TRUE) ? "TRUE" : "FALSE"));
VpSysDebugPrintf("\n\rpLineObj->tickBeginState = 0x%02X ", pLineObj->tickBeginState[0]);
VpPrintCallerIdType(&pLineObj->callerId);
VpPrintCidSeqDataType(&pLineObj->cidSeq);
#endif
#endif
}
return VP_STATUS_SUCCESS;
}
void
VpPrint880CalLineData(
Vp880CalLineData *calLineData)
{
VpSysDebugPrintf("\n\n\rpLineObj->calLineData.calDone = %s",
((calLineData->calDone == TRUE) ? "TRUE" : "FALSE"));
VpSysDebugPrintf("\n\rpLineObj->calLineData.reversePol = %s",
((calLineData->reversePol == TRUE) ? "TRUE" : "FALSE"));
VpSysDebugPrintf("\n\rpLineObj->calLineData.forceCalDataWrite = %s",
((calLineData->forceCalDataWrite == TRUE) ? "TRUE" : "FALSE"));
{
uint8 dcFeedIndex;
VpSysDebugPrintf("\npLineObj->calLineData.dcFeedRef =");
for (dcFeedIndex = 0; dcFeedIndex < VP880_DC_FEED_LEN; dcFeedIndex++) {
VpSysDebugPrintf(" 0x%02X", calLineData->dcFeedRef[dcFeedIndex]);
}
VpSysDebugPrintf("\npLineObj->calLineData.dcFeed =");
for (dcFeedIndex = 0; dcFeedIndex < VP880_DC_FEED_LEN; dcFeedIndex++) {
VpSysDebugPrintf(" 0x%02X", calLineData->dcFeed[dcFeedIndex]);
}
VpSysDebugPrintf("\npLineObj->calLineData.dcFeedPr =");
for (dcFeedIndex = 0; dcFeedIndex < VP880_DC_FEED_LEN; dcFeedIndex++) {
VpSysDebugPrintf(" 0x%02X", calLineData->dcFeedPr[dcFeedIndex]);
}
}
{
uint8 icr2Index;
VpSysDebugPrintf("\npLineObj->calLineData.icr2 =");
for (icr2Index = 0; icr2Index < VP880_ICR2_LEN; icr2Index++) {
VpSysDebugPrintf(" 0x%02X", calLineData->icr2[icr2Index]);
}
}
{
uint8 disnIndex;
VpSysDebugPrintf("\npLineObj->calLineData.disnVal =");
for (disnIndex = 0; disnIndex < VP880_DISN_LEN; disnIndex++) {
VpSysDebugPrintf(" 0x%02X", calLineData->disnVal[disnIndex]);
}
}
{
uint8 vpGainIndex;
VpSysDebugPrintf("\npLineObj->calLineData.vpGain =");
for (vpGainIndex = 0; vpGainIndex < VP880_VP_GAIN_LEN; vpGainIndex++) {
VpSysDebugPrintf(" 0x%02X", calLineData->vpGain[vpGainIndex]);
}
}
{
uint8 loopSupIndex;
VpSysDebugPrintf("\npLineObj->calLineData.loopSup =");
for (loopSupIndex = 0; loopSupIndex < VP880_LOOP_SUP_LEN; loopSupIndex++) {
VpSysDebugPrintf(" 0x%02X", calLineData->loopSup[loopSupIndex]);
}
}
{
uint8 sigGenAIndex;
VpSysDebugPrintf("\npLineObj->calLineData.sigGenA =");
for (sigGenAIndex = 0; sigGenAIndex < VP880_SIGA_PARAMS_LEN; sigGenAIndex++) {
VpSysDebugPrintf(" 0x%02X", calLineData->sigGenA[sigGenAIndex]);
}
}
{
uint8 calRegIndex;
VpSysDebugPrintf("\npLineObj->calLineData.calReg =");
for (calRegIndex = 0; calRegIndex < VP880_ICR6_LEN; calRegIndex++) {
VpSysDebugPrintf(" 0x%02X", calLineData->calReg[calRegIndex]);
}
}
{
uint8 typeDataIndex;
uint8 *pTypeData = (uint8 *)(&calLineData->typeData);
uint8 typeDataSize = sizeof(Vp880CalTypeData);
VpSysDebugPrintf("\npLineObj->calLineData.typeData =");
for (typeDataIndex = 0; typeDataIndex < typeDataSize; typeDataIndex++) {
if (!(typeDataIndex % 10)) {
VpSysDebugPrintf("\n\t");
}
VpSysDebugPrintf(" 0x%02X", *pTypeData);
pTypeData++;
}
}
VpSysDebugPrintf("\npLineObj->calLineData.codecReg = 0x%02X", calLineData->codecReg);
VpSysDebugPrintf("\npLineObj->calLineData.calState = 0x%04X", calLineData->calLineState);
VpSysDebugPrintf("\npLineObj->calLineData.sysState = 0x%02X", calLineData->sysState);
VpSysDebugPrintf("\npLineObj->calLineData.vasStart = %d", calLineData->vasStart);
VpSysDebugPrintf("\npLineObj->calLineData.minVas = %d\n", calLineData->minVas);
}
#endif
#endif