diff options
Diffstat (limited to 'software/octdeviceapi/oct6100api/oct6100_api/oct6100_events.c')
-rw-r--r-- | software/octdeviceapi/oct6100api/oct6100_api/oct6100_events.c | 1326 |
1 files changed, 1326 insertions, 0 deletions
diff --git a/software/octdeviceapi/oct6100api/oct6100_api/oct6100_events.c b/software/octdeviceapi/oct6100api/oct6100_api/oct6100_events.c new file mode 100644 index 0000000..6a672cf --- /dev/null +++ b/software/octdeviceapi/oct6100api/oct6100_api/oct6100_events.c @@ -0,0 +1,1326 @@ +#ifndef cOCT6100_REMOVE_EVENTS +/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ + +File: oct6100_events.c + + Copyright (c) 2001-2005 Octasic Inc. + +Description: + + This file contains functions used to retrieve tone and playout events. + +This file is part of the Octasic OCT6100 GPL API . The OCT6100 GPL API is +free software; you can redistribute it and/or modify it under the terms of +the GNU General Public License as published by the Free Software Foundation; +either version 2 of the License, or (at your option) any later version. + +The OCT6100 GPL API is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with the OCT6100 GPL API; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + +$Octasic_Release: OCT612xAPI-01.00-PR38 $ + +$Octasic_Revision: 79 $ + +\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ + + +/***************************** INCLUDE FILES *******************************/ + +#include "octdef.h" + +#include "oct6100api/oct6100_defines.h" +#include "oct6100api/oct6100_errors.h" +#include "oct6100api/oct6100_apiud.h" + +#include "apilib/octapi_llman.h" + +#include "oct6100api/oct6100_tlv_inst.h" +#include "oct6100api/oct6100_chip_open_inst.h" +#include "oct6100api/oct6100_chip_stats_inst.h" +#include "oct6100api/oct6100_interrupts_inst.h" +#include "oct6100api/oct6100_remote_debug_inst.h" +#include "oct6100api/oct6100_debug_inst.h" +#include "oct6100api/oct6100_api_inst.h" +#include "oct6100api/oct6100_channel_inst.h" +#include "oct6100api/oct6100_events_inst.h" +#include "oct6100api/oct6100_tone_detection_inst.h" +#include "oct6100api/oct6100_playout_buf_inst.h" + +#include "oct6100api/oct6100_interrupts_pub.h" +#include "oct6100api/oct6100_chip_open_pub.h" +#include "oct6100api/oct6100_channel_pub.h" +#include "oct6100api/oct6100_events_pub.h" +#include "oct6100api/oct6100_tone_detection_pub.h" +#include "oct6100api/oct6100_playout_buf_pub.h" + +#include "oct6100_chip_open_priv.h" +#include "oct6100_miscellaneous_priv.h" +#include "oct6100_channel_priv.h" +#include "oct6100_events_priv.h" +#include "oct6100_tone_detection_priv.h" +#include "oct6100_playout_buf_priv.h" + +/**************************** PUBLIC FUNCTIONS *****************************/ + +/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ + +Function: Oct6100EventGetTone + +Description: Retreives an array of tone events. + +------------------------------------------------------------------------------- +| Argument | Description +------------------------------------------------------------------------------- +f_pApiInstance Pointer to API instance. This memory is used to keep + the present state of the chip and all its resources. + +f_pEventGetTone Pointer to structure used to store the Tone events. + +\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +UINT32 Oct6100EventGetToneDef( + tPOCT6100_EVENT_GET_TONE f_pEventGetTone ) +{ + f_pEventGetTone->pToneEvent = NULL; + f_pEventGetTone->ulMaxToneEvent = 1; + f_pEventGetTone->ulNumValidToneEvent = cOCT6100_INVALID_VALUE; + f_pEventGetTone->fMoreEvents = FALSE; + f_pEventGetTone->fResetBufs = FALSE; + + return cOCT6100_ERR_OK; +} + + +UINT32 Oct6100EventGetTone( + tPOCT6100_INSTANCE_API f_pApiInstance, + tPOCT6100_EVENT_GET_TONE f_pEventGetTone ) +{ + tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; + tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; + UINT32 ulSerRes = cOCT6100_ERR_OK; + UINT32 ulFncRes = cOCT6100_ERR_OK; + + /* Set the process context of the serialize structure. */ + SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; + ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; + + /* Seize all list semaphores needed by this function. */ + SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; + SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; + ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); + if ( ulSerRes == cOCT6100_ERR_OK ) + { + /* Call the serialized function. */ + ulFncRes = Oct6100EventGetToneSer( f_pApiInstance, f_pEventGetTone ); + } + else + { + return ulSerRes; + } + + /* Release the seized semaphores. */ + ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; + ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); + + /* If an error occured then return the error code. */ + if ( ulSerRes != cOCT6100_ERR_OK ) + return ulSerRes; + if ( ulFncRes != cOCT6100_ERR_OK ) + return ulFncRes; + + return cOCT6100_ERR_OK; +} + + +/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ + +Function: Oct6100BufferPlayoutGetEvent + +Description: Retrieves an array of playout stop events. + +------------------------------------------------------------------------------- +| Argument | Description +------------------------------------------------------------------------------- +f_pApiInstance Pointer to API instance. This memory is used to keep + the present state of the chip and all its resources. + +f_pBufPlayoutGetEvent Pointer to structure used to store the playout events. + +\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +UINT32 Oct6100BufferPlayoutGetEventDef( + tPOCT6100_BUFFER_PLAYOUT_GET_EVENT f_pBufPlayoutGetEvent ) +{ + f_pBufPlayoutGetEvent->pBufferPlayoutEvent = NULL; + f_pBufPlayoutGetEvent->ulMaxEvent = 1; + f_pBufPlayoutGetEvent->ulNumValidEvent = cOCT6100_INVALID_VALUE; + f_pBufPlayoutGetEvent->fMoreEvents = FALSE; + f_pBufPlayoutGetEvent->fResetBufs = FALSE; + + return cOCT6100_ERR_OK; +} + + +UINT32 Oct6100BufferPlayoutGetEvent( + tPOCT6100_INSTANCE_API f_pApiInstance, + tPOCT6100_BUFFER_PLAYOUT_GET_EVENT f_pBufPlayoutGetEvent ) +{ + tOCT6100_SEIZE_SERIALIZE_OBJECT SeizeSerObj; + tOCT6100_RELEASE_SERIALIZE_OBJECT ReleaseSerObj; + UINT32 ulSerRes = cOCT6100_ERR_OK; + UINT32 ulFncRes = cOCT6100_ERR_OK; + + /* Set the process context of the serialize structure. */ + SeizeSerObj.pProcessContext = f_pApiInstance->pProcessContext; + ReleaseSerObj.pProcessContext = f_pApiInstance->pProcessContext; + + /* Seize all list semaphores needed by this function. */ + SeizeSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; + SeizeSerObj.ulTryTimeMs = cOCT6100_WAIT_INFINITELY; + ulSerRes = Oct6100UserSeizeSerializeObject( &SeizeSerObj ); + if ( ulSerRes == cOCT6100_ERR_OK ) + { + /* Call the serialized function. */ + ulFncRes = Oct6100BufferPlayoutGetEventSer( f_pApiInstance, f_pBufPlayoutGetEvent ); + } + else + { + return ulSerRes; + } + + /* Release the seized semaphores. */ + ReleaseSerObj.ulSerialObjHndl = f_pApiInstance->ulApiSerObj; + ulSerRes = Oct6100UserReleaseSerializeObject( &ReleaseSerObj ); + + /* If an error occured then return the error code. */ + if ( ulSerRes != cOCT6100_ERR_OK ) + return ulSerRes; + if ( ulFncRes != cOCT6100_ERR_OK ) + return ulFncRes; + + return cOCT6100_ERR_OK; +} + + +/**************************** PRIVATE FUNCTIONS ****************************/ + +/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ + +Function: Oct6100ApiGetEventsSwSizes + +Description: Gets the sizes of all portions of the API instance pertinent + to the management of the tone events and playout events + software buffers. + +------------------------------------------------------------------------------- +| Argument | Description +------------------------------------------------------------------------------- +f_pOpenChip Pointer to chip configuration struct. +f_pInstSizes Pointer to struct containing instance sizes. + +\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +UINT32 Oct6100ApiGetEventsSwSizes( + IN tPOCT6100_CHIP_OPEN f_pOpenChip, + OUT tPOCT6100_API_INSTANCE_SIZES f_pInstSizes ) +{ + + { + UINT32 ulTempVar; + + /* Memory needed by soft tone event buffers. */ + + /* Add 1 to the circular buffer such that all user requested events can fit in the circular queue. */ + f_pInstSizes->ulSoftToneEventsBuffer = ( f_pOpenChip->ulSoftToneEventsBufSize + 1 ) * sizeof( tOCT6100_API_TONE_EVENT ); + + /* Round off the sizes of the soft buffers above. */ + mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulSoftToneEventsBuffer, ulTempVar ) + } + + { + UINT32 ulTempVar; + + /* Memory needed by soft playout stop event buffers. */ + if ( f_pOpenChip->ulSoftBufferPlayoutEventsBufSize != cOCT6100_INVALID_VALUE ) + { + f_pInstSizes->ulSoftBufPlayoutEventsBuffer = ( f_pOpenChip->ulSoftBufferPlayoutEventsBufSize + 1 ) * sizeof( tOCT6100_API_BUFFER_PLAYOUT_EVENT ); + + /* Round off the sizes of the soft buffers above. */ + mOCT6100_ROUND_MEMORY_SIZE( f_pInstSizes->ulSoftBufPlayoutEventsBuffer, ulTempVar ) + } + else /* if ( f_pInstSizes->ulSoftBufferPlayoutEventsBufSize == cOCT6100_INVALID_VALUE ) */ + { + f_pInstSizes->ulSoftBufPlayoutEventsBuffer = 0; + } + } + + return cOCT6100_ERR_OK; +} + + +/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ + +Function: Oct6100EventGetToneSer + +Description: Retreives an array of tone event from the software event buffer. + +------------------------------------------------------------------------------- +| Argument | Description +------------------------------------------------------------------------------- +f_pApiInstance Pointer to API instance. This memory is used to keep + the present state of the chip and all its resources. + +f_pEventGetTone Pointer to structure which will contain the retreived + events. + +\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +UINT32 Oct6100EventGetToneSer( + IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, + IN OUT tPOCT6100_EVENT_GET_TONE f_pEventGetTone ) +{ + tPOCT6100_SHARED_INFO pSharedInfo; + tPOCT6100_API_TONE_EVENT pSoftEvent; + UINT32 ulSoftReadPnt; + UINT32 ulSoftWritePnt; + UINT32 ulSoftBufSize; + UINT32 ulNumEventsReturned; + UINT32 ulResult; + + /* Get local pointer(s). */ + pSharedInfo = f_pApiInstance->pSharedInfo; + + /* Check the parameters given by the user. */ + if ( f_pEventGetTone->fResetBufs != TRUE && + f_pEventGetTone->fResetBufs != FALSE ) + return cOCT6100_ERR_EVENTS_GET_TONE_RESET_BUFS; + + /* Check max tones. */ + if ( f_pEventGetTone->ulMaxToneEvent > pSharedInfo->ChipConfig.ulSoftToneEventsBufSize ) + return cOCT6100_ERR_EVENTS_MAX_TONES; + + if ( f_pEventGetTone->fResetBufs == FALSE ) + { + /* Check if the events need to be fetched from the chip buffer. */ + ulSoftReadPnt = pSharedInfo->SoftBufs.ulToneEventBufferReadPtr; + ulSoftWritePnt = pSharedInfo->SoftBufs.ulToneEventBufferWritePtr; + + if ( ulSoftReadPnt == ulSoftWritePnt ) + { + ulResult = Oct6100ApiTransferToneEvents( f_pApiInstance, f_pEventGetTone->fResetBufs ); + if ( ulResult != cOCT6100_ERR_OK ) + return ulResult; + } + + /* If there are no events in the soft buffer then there are none in the chip */ + /* either, so return the empty case. Else, return the events in the buffer. */ + ulSoftReadPnt = pSharedInfo->SoftBufs.ulToneEventBufferReadPtr; + ulSoftWritePnt = pSharedInfo->SoftBufs.ulToneEventBufferWritePtr; + ulSoftBufSize = pSharedInfo->SoftBufs.ulToneEventBufferSize; + + if ( ulSoftReadPnt != ulSoftWritePnt ) + { + ulNumEventsReturned = 0; + + while( (ulSoftReadPnt != ulSoftWritePnt) && ( ulNumEventsReturned != f_pEventGetTone->ulMaxToneEvent) ) + { + /* Get a pointer to the first event in the buffer. */ + mOCT6100_GET_TONE_EVENT_BUF_PNT( pSharedInfo, pSoftEvent ) + pSoftEvent += ulSoftReadPnt; + + f_pEventGetTone->pToneEvent[ ulNumEventsReturned ].ulChannelHndl = pSoftEvent->ulChannelHandle; + f_pEventGetTone->pToneEvent[ ulNumEventsReturned ].ulUserChanId = pSoftEvent->ulUserChanId; + f_pEventGetTone->pToneEvent[ ulNumEventsReturned ].ulTimestamp = pSoftEvent->ulTimestamp; + f_pEventGetTone->pToneEvent[ ulNumEventsReturned ].ulEventType = pSoftEvent->ulEventType; + f_pEventGetTone->pToneEvent[ ulNumEventsReturned ].ulToneDetected = pSoftEvent->ulToneDetected; + f_pEventGetTone->pToneEvent[ ulNumEventsReturned ].ulExtToneDetectionPort = pSoftEvent->ulExtToneDetectionPort; + + /* Update the pointers of the soft buffer. */ + ulSoftReadPnt++; + if ( ulSoftReadPnt == ulSoftBufSize ) + ulSoftReadPnt = 0; + + ulNumEventsReturned++; + } + + pSharedInfo->SoftBufs.ulToneEventBufferReadPtr = ulSoftReadPnt; + + /* Detemine if there are more events pending in the soft buffer. */ + if ( ulSoftReadPnt != ulSoftWritePnt ) + f_pEventGetTone->fMoreEvents = TRUE; + else /* ( ulSoftReadPnt == ulSoftWritePnt ) */ + { + f_pEventGetTone->fMoreEvents = FALSE; + + /* Remember this state in the interrupt manager. */ + pSharedInfo->IntrptManage.fToneEventsPending = FALSE; + } + + f_pEventGetTone->ulNumValidToneEvent = ulNumEventsReturned; + } + else + { + /* No valid tone.*/ + f_pEventGetTone->ulNumValidToneEvent = 0; + f_pEventGetTone->fMoreEvents = FALSE; + + /* Remember this state in the interrupt manager. */ + pSharedInfo->IntrptManage.fToneEventsPending = FALSE; + + return cOCT6100_ERR_EVENTS_TONE_BUF_EMPTY; + } + } + else /* ( f_pEventGetTone->fResetBufs == TRUE ) */ + { + /* Empty the hardware buffer. */ + ulResult = Oct6100ApiTransferToneEvents( f_pApiInstance, f_pEventGetTone->fResetBufs ); + if ( ulResult != cOCT6100_ERR_OK ) + return ulResult; + + /* If the buffers are to be reset then update the pointers and full flag. */ + pSharedInfo->SoftBufs.ulToneEventBufferReadPtr = 0; + pSharedInfo->SoftBufs.ulToneEventBufferWritePtr = 0; + + f_pEventGetTone->fMoreEvents = FALSE; + f_pEventGetTone->ulNumValidToneEvent = 0; + + /* Remember this state in the interrupt manager. */ + pSharedInfo->IntrptManage.fToneEventsPending = FALSE; + } + + return cOCT6100_ERR_OK; +} + + +/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ + +Function: Oct6100ApiTransferToneEvents + +Description: Transfers all tone events from the PGSP event out chip buffer + to the soft buffer. + +------------------------------------------------------------------------------- +| Argument | Description +------------------------------------------------------------------------------- +f_pApiInstance Pointer to API instance. This memory is used to keep + the present state of the chip and all its resources. + +f_ulResetBuf Reset flag. + +\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +UINT32 Oct6100ApiTransferToneEvents( + IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, + IN UINT32 f_ulResetBuf ) +{ + tPOCT6100_SHARED_INFO pSharedInfo; + tPOCT6100_API_TONE_EVENT pSoftEvent; + tPOCT6100_API_CHANNEL pEchoChannel; + tOCT6100_WRITE_PARAMS WriteParams; + tOCT6100_READ_PARAMS ReadParams; + tOCT6100_READ_BURST_PARAMS BurstParams; + UINT32 ulChipBufFill; + UINT32 ulChipWritePtr = 0; + UINT32 ulChipReadPtr = 0; + + UINT32 usChannelIndex; + UINT32 ulBaseTimestamp; + UINT32 ulToneCnt; + UINT32 ulNumWordsToRead; + + UINT32 ulResult; + UINT32 i, j; + UINT16 usReadData; + UINT16 ausReadData[ cOCT6100_NUM_WORDS_PER_TONE_EVENT ]; + + UINT32 ulExtToneDetectionPort; + + /* Get local pointer(s). */ + pSharedInfo = f_pApiInstance->pSharedInfo; + + /* If the buffer is to be reset then clear the overflow flag. */ + if ( f_ulResetBuf == TRUE ) + { + pSharedInfo->SoftBufs.ulToneEventBufferOverflowCnt = 0; + } + + /* Set some parameters of read struct. */ + ReadParams.pProcessContext = f_pApiInstance->pProcessContext; + + ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; + ReadParams.pusReadData = &usReadData; + + /* Get the current read pointer of the chip buffer. */ + ReadParams.ulReadAddress = cOCT6100_TONE_EVENT_READ_PTR_REG; + mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) + if ( ulResult != cOCT6100_ERR_OK ) + return ulResult; + + ulChipReadPtr = usReadData; + + /* Now get the current write pointer. */ + ReadParams.ulReadAddress = cOCT6100_TONE_EVENT_WRITE_PTR_REG; + mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) + if ( ulResult != cOCT6100_ERR_OK ) + return ulResult; + + ulChipWritePtr = usReadData; + + ulChipBufFill = (( ulChipWritePtr - ulChipReadPtr ) & ( cOCT6100_NUM_PGSP_EVENT_OUT - 1 )); + + /* Set some parameters of write structs. */ + WriteParams.pProcessContext = f_pApiInstance->pProcessContext; + + WriteParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; + + BurstParams.pProcessContext = f_pApiInstance->pProcessContext; + + BurstParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; + + /* Read in the tone event one at a time. */ + for ( i = 0; i < ulChipBufFill; i++ ) + { + /* Skip the event processing if the buffer is to be reset. */ + if ( f_ulResetBuf == TRUE ) + { + /* Update the control variables of the buffer. */ + ulChipReadPtr++; + if ( cOCT6100_NUM_PGSP_EVENT_OUT == ulChipReadPtr ) + ulChipReadPtr = 0; + } + else + { + /* Read in the event only if there's enough room in the soft buffer, and */ + /* the chip buffer is NOT to be reset. */ + if ( ((pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1) != pSharedInfo->SoftBufs.ulToneEventBufferReadPtr) && + ((pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1) != pSharedInfo->SoftBufs.ulToneEventBufferSize || pSharedInfo->SoftBufs.ulToneEventBufferReadPtr != 0) ) + { + BurstParams.ulReadAddress = cOCT6100_PGSP_EVENT_OUT_BASE + ( ulChipReadPtr * cOCT6100_PGSP_TONE_EVENT_SIZE ); + BurstParams.pusReadData = ausReadData; + + ulNumWordsToRead = cOCT6100_PGSP_TONE_EVENT_SIZE / 2; + + while ( ulNumWordsToRead > 0 ) + { + if ( ulNumWordsToRead > pSharedInfo->ChipConfig.usMaxRwAccesses ) + { + BurstParams.ulReadLength = pSharedInfo->ChipConfig.usMaxRwAccesses; + } + else + { + BurstParams.ulReadLength = ulNumWordsToRead; + } + + mOCT6100_DRIVER_READ_BURST_API( BurstParams, ulResult ); + if ( ulResult != cOCT6100_ERR_OK ) + return ulResult; + + BurstParams.pusReadData += BurstParams.ulReadLength; + BurstParams.ulReadAddress += BurstParams.ulReadLength * 2; + + ulNumWordsToRead -= BurstParams.ulReadLength; + } + + /* Verify if the event is valid. */ + if ( ( ausReadData[ 0 ] & cOCT6100_VALID_TONE_EVENT ) == 0x0 ) + return cOCT6100_ERR_FATAL_2D; + + /* First extract the channel number of the tone event. */ + usChannelIndex = ausReadData[ 1 ] & 0x3FF; + + /* Now the timestamp. */ + ulBaseTimestamp = ausReadData[ 2 ] << 16; + ulBaseTimestamp |= ausReadData[ 3 ]; + + /* This timestamp is 256 in adwance, must remove 256 frames. */ + ulBaseTimestamp -= 256; + + /* Fetch the channel stucture to validate which event can be reported. */ + mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChannel, usChannelIndex ); + + if ( pEchoChannel->fReserved != TRUE ) + { + /* Update the control variables of the buffer. */ + ulChipReadPtr++; + if ( ulChipReadPtr == cOCT6100_NUM_PGSP_EVENT_OUT ) + ulChipReadPtr = 0; + + /* This channel has been closed since the generation of the event. */ + continue; + } + + /* Extract the extended tone detection port if available. */ + if ( pEchoChannel->ulExtToneChanMode == cOCT6100_API_EXT_TONE_SIN_PORT_MODE ) + { + ulExtToneDetectionPort = cOCT6100_CHANNEL_PORT_SIN; + } + else if ( pEchoChannel->ulExtToneChanMode == cOCT6100_API_EXT_TONE_RIN_PORT_MODE ) + { + ulExtToneDetectionPort = cOCT6100_CHANNEL_PORT_RIN; + + /* Modify the channel index. */ + usChannelIndex = pEchoChannel->usExtToneChanIndex; + + /* Change the channel entry to the original one for statistical purposes. */ + mOCT6100_GET_CHANNEL_ENTRY_PNT( f_pApiInstance->pSharedInfo, pEchoChannel, usChannelIndex ); + + } + else /* pEchoChannel->ulExtToneChanMode == cOCT6100_API_EXT_TONE_DISABLED */ + { + ulExtToneDetectionPort = cOCT6100_INVALID_VALUE; + } + + ulToneCnt = 0; + /* Verify all the possible events that might have been detected. */ + for ( j = 4; j < cOCT6100_NUM_WORDS_PER_TONE_EVENT; j++ ) + { + if ( (( ausReadData[ j ] >> 8 ) & 0x7 ) != 0x0 ) + { + /* This tone generated an event, now check if event is masked for the channel. */ + if ((( pEchoChannel->aulToneConf[ ulToneCnt / 32 ] >> ( 31 - ( ulToneCnt % 32 ))) & 0x1) == 1 ) + { + /* If enough space. */ + if ( ((pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1) != pSharedInfo->SoftBufs.ulToneEventBufferReadPtr) && + ((pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1) != pSharedInfo->SoftBufs.ulToneEventBufferSize || pSharedInfo->SoftBufs.ulToneEventBufferReadPtr != 0) ) + { + /* The tone event is not masked, The API can create a soft tone event. */ + mOCT6100_GET_TONE_EVENT_BUF_PNT( pSharedInfo, pSoftEvent ) + pSoftEvent += pSharedInfo->SoftBufs.ulToneEventBufferWritePtr; + + /* Decode the event type. */ + switch(( ausReadData[ j ] >> 8 ) & 0x7 ) + { + case 1: + pSoftEvent->ulEventType = cOCT6100_TONE_PRESENT; + break; + case 2: + pSoftEvent->ulEventType = cOCT6100_TONE_STOP; + break; + case 3: + /* This one is a little tricky. We first */ + /* generate the "PRESENT" event and then generate the "STOP" event. */ + + pSoftEvent->ulEventType = cOCT6100_TONE_PRESENT; + pSoftEvent->ulChannelHandle = cOCT6100_HNDL_TAG_CHANNEL | (pEchoChannel->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | usChannelIndex; + pSoftEvent->ulUserChanId = pEchoChannel->ulUserChanId; + pSoftEvent->ulToneDetected = pSharedInfo->ImageInfo.aToneInfo[ ulToneCnt ].ulToneID; + /* We want the timestamp not to be equal to the "STOP" event, so we subtract one to the detector's value. */ + pSoftEvent->ulTimestamp = ( ulBaseTimestamp + ((( ausReadData[ j ] >> 13 ) & 0x7) * cOCT6100_LOCAL_TIMESTAMP_INCREMENT ) ) - 1; + pSoftEvent->ulExtToneDetectionPort = ulExtToneDetectionPort; + + /* Update the control variables of the buffer. */ + pSharedInfo->SoftBufs.ulToneEventBufferWritePtr++; + if ( pSharedInfo->SoftBufs.ulToneEventBufferWritePtr == pSharedInfo->SoftBufs.ulToneEventBufferSize ) + pSharedInfo->SoftBufs.ulToneEventBufferWritePtr = 0; + + /* If enough space for the "STOP" event. */ + if ( ((pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1) != pSharedInfo->SoftBufs.ulToneEventBufferReadPtr) && + ((pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1) != pSharedInfo->SoftBufs.ulToneEventBufferSize || pSharedInfo->SoftBufs.ulToneEventBufferReadPtr != 0) ) + { + mOCT6100_GET_TONE_EVENT_BUF_PNT( pSharedInfo, pSoftEvent ) + pSoftEvent += pSharedInfo->SoftBufs.ulToneEventBufferWritePtr; + + pSoftEvent->ulEventType = cOCT6100_TONE_STOP; + } + else + { + /* Set the overflow flag of the buffer. */ + pSharedInfo->SoftBufs.ulToneEventBufferOverflowCnt++; + + /* We continue in the loop in order to empty the hardware buffer. */ + continue; + } + + break; + case 4: + pSoftEvent->ulEventType = cOCT6100_TONE_PRESENT; + break; + default: + pSharedInfo->ErrorStats.ulToneDetectorErrorCnt++; + /* do not process this packet*/ + continue; + } + + pSoftEvent->ulChannelHandle = cOCT6100_HNDL_TAG_CHANNEL | (pEchoChannel->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | usChannelIndex; + pSoftEvent->ulUserChanId = pEchoChannel->ulUserChanId; + pSoftEvent->ulToneDetected = pSharedInfo->ImageInfo.aToneInfo[ ulToneCnt ].ulToneID; + pSoftEvent->ulTimestamp = ulBaseTimestamp + ((( ausReadData[ j ] >> 13 ) & 0x7) * cOCT6100_LOCAL_TIMESTAMP_INCREMENT ); + pSoftEvent->ulExtToneDetectionPort = ulExtToneDetectionPort; + + /* Update the control variables of the buffer. */ + pSharedInfo->SoftBufs.ulToneEventBufferWritePtr++; + if ( pSharedInfo->SoftBufs.ulToneEventBufferWritePtr == pSharedInfo->SoftBufs.ulToneEventBufferSize ) + pSharedInfo->SoftBufs.ulToneEventBufferWritePtr = 0; + + /* Set the interrupt manager such that the user knows that some tone events */ + /* are pending in the software Q. */ + pSharedInfo->IntrptManage.fToneEventsPending = TRUE; + } + else + { + /* Set the overflow flag of the buffer. */ + pSharedInfo->SoftBufs.ulToneEventBufferOverflowCnt++; + + /* We continue in the loop in order to empty the hardware buffer. */ + } + } + else + { + BOOL fSSTone; + + ulResult = Oct6100ApiIsSSTone( + f_pApiInstance, + pSharedInfo->ImageInfo.aToneInfo[ ulToneCnt ].ulToneID, + &fSSTone ); + if ( ulResult != cOCT6100_ERR_OK ) + return ulResult; + + if ( fSSTone == TRUE ) + { + /* Check if this is a "PRESENT" or "STOP" event */ + switch( ( ( ausReadData[ j ] >> 8 ) & 0x7 ) ) + { + case 1: + /* This is a signaling system present event. Keep this in the instance memory. */ + pEchoChannel->ulLastSSToneDetected = pSharedInfo->ImageInfo.aToneInfo[ ulToneCnt ].ulToneID; + pEchoChannel->ulLastSSToneTimestamp = ulBaseTimestamp + ((( ausReadData[ j ] >> 13 ) & 0x7) * cOCT6100_LOCAL_TIMESTAMP_INCREMENT ); + break; + case 2: + /* This is the "STOP" event, invalidate the last value. The user does not want to know about this. */ + pEchoChannel->ulLastSSToneDetected = cOCT6100_INVALID_VALUE; + pEchoChannel->ulLastSSToneTimestamp = cOCT6100_INVALID_VALUE; + break; + default: + break; + } + } + } + } + ulToneCnt++; + + /* Check the other tone of this word. */ + if ( ( ausReadData[ j ] & 0x7 ) != 0x0 ) + { + if ((( pEchoChannel->aulToneConf[ ulToneCnt / 32 ] >> ( 31 - ( ulToneCnt % 32 ))) & 0x1) == 1 ) + { + /* If enough space. */ + if ( ((pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1) != pSharedInfo->SoftBufs.ulToneEventBufferReadPtr) && + ((pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1) != pSharedInfo->SoftBufs.ulToneEventBufferSize || pSharedInfo->SoftBufs.ulToneEventBufferReadPtr != 0) ) + { + /* The tone event is not masked, The API can create a soft tone event. */ + mOCT6100_GET_TONE_EVENT_BUF_PNT( pSharedInfo, pSoftEvent ) + pSoftEvent += pSharedInfo->SoftBufs.ulToneEventBufferWritePtr; + + /* Decode the event type. */ + switch(( ausReadData[ j ] ) & 0x7 ) + { + case 1: + pSoftEvent->ulEventType = cOCT6100_TONE_PRESENT; + break; + case 2: + pSoftEvent->ulEventType = cOCT6100_TONE_STOP; + break; + case 3: + /* This one is a little tricky. We first */ + /* generate the "PRESENT" event and then generate the "STOP" event. */ + + pSoftEvent->ulEventType = cOCT6100_TONE_PRESENT; + pSoftEvent->ulChannelHandle = cOCT6100_HNDL_TAG_CHANNEL | (pEchoChannel->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | usChannelIndex; + pSoftEvent->ulUserChanId = pEchoChannel->ulUserChanId; + pSoftEvent->ulToneDetected = pSharedInfo->ImageInfo.aToneInfo[ ulToneCnt ].ulToneID; + /* We want the timestamp not to be equal to the "STOP" event, so we subtract one to the detector's value. */ + pSoftEvent->ulTimestamp = ( ulBaseTimestamp + ((( ausReadData[ j ] >> 5 ) & 0x7) * cOCT6100_LOCAL_TIMESTAMP_INCREMENT ) ) - 1; + pSoftEvent->ulExtToneDetectionPort = ulExtToneDetectionPort; + + /* Update the control variables of the buffer. */ + pSharedInfo->SoftBufs.ulToneEventBufferWritePtr++; + if ( pSharedInfo->SoftBufs.ulToneEventBufferWritePtr == pSharedInfo->SoftBufs.ulToneEventBufferSize ) + pSharedInfo->SoftBufs.ulToneEventBufferWritePtr = 0; + + /* If enough space for the "STOP" event. */ + if ( ((pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1) != pSharedInfo->SoftBufs.ulToneEventBufferReadPtr) && + ((pSharedInfo->SoftBufs.ulToneEventBufferWritePtr + 1) != pSharedInfo->SoftBufs.ulToneEventBufferSize || pSharedInfo->SoftBufs.ulToneEventBufferReadPtr != 0) ) + { + mOCT6100_GET_TONE_EVENT_BUF_PNT( pSharedInfo, pSoftEvent ) + pSoftEvent += pSharedInfo->SoftBufs.ulToneEventBufferWritePtr; + + pSoftEvent->ulEventType = cOCT6100_TONE_STOP; + } + else + { + /* Set the overflow flag of the buffer. */ + pSharedInfo->SoftBufs.ulToneEventBufferOverflowCnt++; + + /* We continue in the loop in order to empty the hardware buffer. */ + continue; + } + + break; + case 4: + pSoftEvent->ulEventType = cOCT6100_TONE_PRESENT; + break; + default: + pSharedInfo->ErrorStats.ulToneDetectorErrorCnt++; + /* Do not process this packet. */ + continue; + } + + pSoftEvent->ulChannelHandle = cOCT6100_HNDL_TAG_CHANNEL | (pEchoChannel->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | usChannelIndex; + pSoftEvent->ulUserChanId = pEchoChannel->ulUserChanId; + pSoftEvent->ulToneDetected = pSharedInfo->ImageInfo.aToneInfo[ ulToneCnt ].ulToneID; + pSoftEvent->ulTimestamp = ulBaseTimestamp + ((( ausReadData[ j ] >> 5 ) & 0x7) * cOCT6100_LOCAL_TIMESTAMP_INCREMENT ); + pSoftEvent->ulExtToneDetectionPort = ulExtToneDetectionPort; + + /* Update the control variables of the buffer. */ + pSharedInfo->SoftBufs.ulToneEventBufferWritePtr++; + if ( pSharedInfo->SoftBufs.ulToneEventBufferWritePtr == pSharedInfo->SoftBufs.ulToneEventBufferSize ) + pSharedInfo->SoftBufs.ulToneEventBufferWritePtr = 0; + + /* Set the interrupt manager such that the user knows that some tone events */ + /* are pending in the software Q. */ + pSharedInfo->IntrptManage.fToneEventsPending = TRUE; + + } + else + { + /* Set the overflow flag of the buffer. */ + pSharedInfo->SoftBufs.ulToneEventBufferOverflowCnt++; + + /* We continue in the loop in order to empty the hardware buffer. */ + } + } + else + { + BOOL fSSTone; + + ulResult = Oct6100ApiIsSSTone( + f_pApiInstance, + pSharedInfo->ImageInfo.aToneInfo[ ulToneCnt ].ulToneID, + &fSSTone ); + if ( ulResult != cOCT6100_ERR_OK ) + return ulResult; + + if ( fSSTone == TRUE ) + { + /* Check if this is a "PRESENT" event. */ + switch ( ( ausReadData[ j ] ) & 0x7 ) + { + case 1: + /* This is a signaling system present event. Keep this in the instance memory. */ + pEchoChannel->ulLastSSToneDetected = pSharedInfo->ImageInfo.aToneInfo[ ulToneCnt ].ulToneID; + pEchoChannel->ulLastSSToneTimestamp = ulBaseTimestamp + ((( ausReadData[ j ] >> 5 ) & 0x7) * cOCT6100_LOCAL_TIMESTAMP_INCREMENT ); + break; + case 2: + /* This is the "STOP" event, invalidate the last value. The user does not want to know about this. */ + pEchoChannel->ulLastSSToneDetected = cOCT6100_INVALID_VALUE; + pEchoChannel->ulLastSSToneTimestamp = cOCT6100_INVALID_VALUE; + break; + default: + break; + } + } + } + } + ulToneCnt++; + } + } + else + { + /* Set the overflow flag of the buffer. */ + pSharedInfo->SoftBufs.ulToneEventBufferOverflowCnt++; + + /* We continue in the loop in order to empty the hardware buffer. */ + } + + /* Update the control variables of the buffer. */ + ulChipReadPtr++; + if ( ulChipReadPtr == cOCT6100_NUM_PGSP_EVENT_OUT ) + ulChipReadPtr = 0; + } + } + + /* Write the value of the new Read pointer.*/ + WriteParams.ulWriteAddress = cOCT6100_TONE_EVENT_READ_PTR_REG; + WriteParams.usWriteData = (UINT16)( ulChipReadPtr ); + mOCT6100_DRIVER_WRITE_API( WriteParams, ulResult ) + if ( ulResult != cOCT6100_ERR_OK ) + return ulResult; + + + + return cOCT6100_ERR_OK; +} + + + + + +/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ + +Function: Oct6100BufferPlayoutGetEventSer + +Description: Retreives an array of buffer playout event from the software + event buffer. + +------------------------------------------------------------------------------- +| Argument | Description +------------------------------------------------------------------------------- +f_pApiInstance Pointer to API instance. This memory is used to keep + the present state of the chip and all its resources. + +f_pEventGetPlayoutStop Pointer to structure which will contain the retreived + events. + +\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +UINT32 Oct6100BufferPlayoutGetEventSer( + IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, + IN OUT tPOCT6100_BUFFER_PLAYOUT_GET_EVENT f_pBufPlayoutGetEvent ) +{ + tPOCT6100_SHARED_INFO pSharedInfo; + tPOCT6100_API_BUFFER_PLAYOUT_EVENT pSoftEvent; + UINT32 ulSoftReadPnt; + UINT32 ulSoftWritePnt; + UINT32 ulSoftBufSize; + UINT32 ulNumEventsReturned; + UINT32 ulResult; + + /* Get local pointer(s). */ + pSharedInfo = f_pApiInstance->pSharedInfo; + + /* Check the parameters past by the user. */ + if ( f_pBufPlayoutGetEvent->fResetBufs != TRUE && + f_pBufPlayoutGetEvent->fResetBufs != FALSE ) + return cOCT6100_ERR_BUFFER_PLAYOUT_EVENT_RESET; + + /* Check if software buffer has been allocated and thus enabled. */ + if ( pSharedInfo->ChipConfig.ulSoftBufPlayoutEventsBufSize == 0 ) + return cOCT6100_ERR_BUFFER_PLAYOUT_EVENT_DISABLED; + + /* Checking max playout events. */ + if ( f_pBufPlayoutGetEvent->ulMaxEvent > pSharedInfo->ChipConfig.ulSoftBufPlayoutEventsBufSize ) + return cOCT6100_ERR_BUFFER_PLAYOUT_MAX_EVENT; + + if ( f_pBufPlayoutGetEvent->fResetBufs == FALSE ) + { + /* Check if events need to be fetched from the chip. */ + ulSoftReadPnt = pSharedInfo->SoftBufs.ulBufPlayoutEventBufferReadPtr; + ulSoftWritePnt = pSharedInfo->SoftBufs.ulBufPlayoutEventBufferWritePtr; + + if ( ulSoftReadPnt == ulSoftWritePnt ) + { + ulResult = Oct6100BufferPlayoutTransferEvents( f_pApiInstance, f_pBufPlayoutGetEvent->fResetBufs ); + if ( ulResult != cOCT6100_ERR_OK ) + return ulResult; + } + + /* If there are no events in the soft buffer then there are none in the chip */ + /* either, so return the empty case. Else, return the events in the buffer. */ + ulSoftReadPnt = pSharedInfo->SoftBufs.ulBufPlayoutEventBufferReadPtr; + ulSoftWritePnt = pSharedInfo->SoftBufs.ulBufPlayoutEventBufferWritePtr; + ulSoftBufSize = pSharedInfo->SoftBufs.ulBufPlayoutEventBufferSize; + + if ( ulSoftReadPnt != ulSoftWritePnt ) + { + ulNumEventsReturned = 0; + + while( (ulSoftReadPnt != ulSoftWritePnt) && ( ulNumEventsReturned != f_pBufPlayoutGetEvent->ulMaxEvent) ) + { + /* Get a pointer to the first event in the buffer. */ + mOCT6100_GET_BUFFER_PLAYOUT_EVENT_BUF_PNT( pSharedInfo, pSoftEvent ) + pSoftEvent += ulSoftReadPnt; + + f_pBufPlayoutGetEvent->pBufferPlayoutEvent[ ulNumEventsReturned ].ulChannelHndl = pSoftEvent->ulChannelHandle; + f_pBufPlayoutGetEvent->pBufferPlayoutEvent[ ulNumEventsReturned ].ulUserChanId = pSoftEvent->ulUserChanId; + f_pBufPlayoutGetEvent->pBufferPlayoutEvent[ ulNumEventsReturned ].ulChannelPort = pSoftEvent->ulChannelPort; + f_pBufPlayoutGetEvent->pBufferPlayoutEvent[ ulNumEventsReturned ].ulUserEventId = pSoftEvent->ulUserEventId; + f_pBufPlayoutGetEvent->pBufferPlayoutEvent[ ulNumEventsReturned ].ulEventType = pSoftEvent->ulEventType; + f_pBufPlayoutGetEvent->pBufferPlayoutEvent[ ulNumEventsReturned ].ulTimestamp = pSoftEvent->ulTimestamp; + + /* Update the pointers of the soft buffer. */ + ulSoftReadPnt++; + if ( ulSoftReadPnt == ulSoftBufSize ) + ulSoftReadPnt = 0; + + ulNumEventsReturned++; + } + + pSharedInfo->SoftBufs.ulBufPlayoutEventBufferReadPtr = ulSoftReadPnt; + + /* Detemine if there are more events pending in the soft buffer. */ + if ( ulSoftReadPnt != ulSoftWritePnt ) + f_pBufPlayoutGetEvent->fMoreEvents = TRUE; + else /* ( ulSoftReadPnt == ulSoftWritePnt ) */ + { + f_pBufPlayoutGetEvent->fMoreEvents = FALSE; + + /* Remember this state in the interrupt manager. */ + pSharedInfo->IntrptManage.fBufferPlayoutEventsPending = FALSE; + } + + f_pBufPlayoutGetEvent->ulNumValidEvent = ulNumEventsReturned; + } + else /* if ( ulSoftReadPnt == ulSoftWritePnt ) */ + { + /* No valid buffer playout events. */ + f_pBufPlayoutGetEvent->ulNumValidEvent = 0; + f_pBufPlayoutGetEvent->fMoreEvents = FALSE; + + /* Remember this state in the interrupt manager. */ + pSharedInfo->IntrptManage.fBufferPlayoutEventsPending = FALSE; + + return cOCT6100_ERR_BUFFER_PLAYOUT_EVENT_BUF_EMPTY; + } + } + else /* ( f_pEventGetPlayoutStop->fResetBufs == TRUE ) */ + { + /* Check with the hardware first. */ + ulResult = Oct6100BufferPlayoutTransferEvents( f_pApiInstance, f_pBufPlayoutGetEvent->fResetBufs ); + if ( ulResult != cOCT6100_ERR_OK ) + return ulResult; + + /* If the buffers are to be reset, then update the pointers and full flag. */ + pSharedInfo->SoftBufs.ulBufPlayoutEventBufferReadPtr = 0; + pSharedInfo->SoftBufs.ulBufPlayoutEventBufferWritePtr = 0; + + f_pBufPlayoutGetEvent->fMoreEvents = FALSE; + f_pBufPlayoutGetEvent->ulNumValidEvent = 0; + + /* Remember this state in the interrupt manager. */ + pSharedInfo->IntrptManage.fBufferPlayoutEventsPending = FALSE; + } + + return cOCT6100_ERR_OK; +} + + +/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ + +Function: Oct6100BufferPlayoutTransferEvents + +Description: Check all channels that are currently playing a buffer and + generate an event if a buffer has stopped playing. + +------------------------------------------------------------------------------- +| Argument | Description +------------------------------------------------------------------------------- +f_pApiInstance Pointer to API instance. This memory is used to keep + the present state of the chip and all its resources. + +f_ulResetBuf Reset flag. + +\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +UINT32 Oct6100BufferPlayoutTransferEvents( + IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, + IN UINT32 f_ulResetBuf ) +{ + tPOCT6100_SHARED_INFO pSharedInfo; + tPOCT6100_API_CHANNEL pEchoChannel; + + UINT32 ulChannelIndex; + UINT32 ulResult; + UINT32 ulLastBufPlayoutEventBufferOverflowCnt; + + /* Get local pointer(s). */ + pSharedInfo = f_pApiInstance->pSharedInfo; + + /* If the buffer is to be reset then clear the overflow flag. */ + if ( f_ulResetBuf == TRUE ) + { + pSharedInfo->SoftBufs.ulBufPlayoutEventBufferOverflowCnt = 0; + /* We are done for now. */ + /* No need to check for new events since the user requested to empty the soft buffer. */ + return cOCT6100_ERR_OK; + } + + /* Check if buffer playout has been activated on some ports. */ + if ( pSharedInfo->ChipStats.usNumberActiveBufPlayoutPorts == 0 ) + { + /* Buffer playout has not been activated on any channel, */ + /* let's not waste time here. */ + return cOCT6100_ERR_OK; + } + + /* Save the current overflow count. We want to know if an overflow occured to get out of the loop. */ + ulLastBufPlayoutEventBufferOverflowCnt = pSharedInfo->SoftBufs.ulBufPlayoutEventBufferOverflowCnt; + + /* Search through the list of API channel entry for the ones that need playout event checking. */ + for ( ulChannelIndex = 0; ulChannelIndex < pSharedInfo->ChipConfig.usMaxChannels; ulChannelIndex++ ) + { + mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChannel, ulChannelIndex ); + + /* Check if buffer playout is active on this channel, using the optimization flag. */ + /* This flag is redundant of other flags used for playout, but will make the above loop */ + /* much faster. This is needed since this function is called very frequently on systems */ + /* which use buffer playout stop events. */ + if ( pEchoChannel->fBufPlayoutActive == TRUE ) + { + /* Read in the event only if there's enough room in the soft buffer. */ + if ( ulLastBufPlayoutEventBufferOverflowCnt == pSharedInfo->SoftBufs.ulBufPlayoutEventBufferOverflowCnt ) + { + /* Check Rout buffer playout first. */ + if ( ( pEchoChannel->fRinBufPlayoutNotifyOnStop == TRUE ) + && ( pEchoChannel->fRinBufPlaying == TRUE ) ) + { + ulResult = Oct6100BufferPlayoutCheckForSpecificEvent( f_pApiInstance, ulChannelIndex, cOCT6100_CHANNEL_PORT_ROUT, TRUE, NULL ); + if ( ulResult != cOCT6100_ERR_OK ) + return ulResult; + } + } + else /* if ( ulLastBufPlayoutEventBufferOverflowCnt != pSharedInfo->SoftBufs.ulBufPlayoutEventBufferOverflowCnt ) */ + { + /* Get out of the loop, no more events can be inserted in the soft buffer. */ + break; + } + + /* An overflow might have been detected in the lower level function. */ + /* Check the overflow count once again to make sure there might be room for a next event. */ + if ( ulLastBufPlayoutEventBufferOverflowCnt == pSharedInfo->SoftBufs.ulBufPlayoutEventBufferOverflowCnt ) + { + /* Check Sout buffer playout. */ + if ( ( pEchoChannel->fSoutBufPlayoutNotifyOnStop == TRUE ) + && ( pEchoChannel->fSoutBufPlaying == TRUE ) ) + { + ulResult = Oct6100BufferPlayoutCheckForSpecificEvent( f_pApiInstance, ulChannelIndex, cOCT6100_CHANNEL_PORT_SOUT, TRUE, NULL ); + if ( ulResult != cOCT6100_ERR_OK ) + return ulResult; + } + } + else /* if ( ulLastBufPlayoutEventBufferOverflowCnt != pSharedInfo->SoftBufs.ulBufPlayoutEventBufferOverflowCnt ) */ + { + /* Get out of the loop, no more events can be inserted in the soft buffer. */ + break; + } + } + } + + return cOCT6100_ERR_OK; +} + + +/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*\ + +Function: Oct6100BufferPlayoutCheckForSpecificEvent + +Description: Check a specific channel/port for playout buffer events. + If asked to, save this event to the software event buffer. + Return a flag specifying whether the event was detected or not. + +------------------------------------------------------------------------------- +| Argument | Description +------------------------------------------------------------------------------- +f_pApiInstance Pointer to API instance. This memory is used to keep + the present state of the chip and all its resources. + +f_ulChannelIndex Index of the channel to be checked. +f_ulChannelPort Port of the channel to be checked. +f_fSaveToSoftBuffer Save event to software buffer. +f_pfEventDetected Whether or not an event was detected. + +\*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/ +UINT32 Oct6100BufferPlayoutCheckForSpecificEvent( + IN OUT tPOCT6100_INSTANCE_API f_pApiInstance, + IN UINT32 f_ulChannelIndex, + IN UINT32 f_ulChannelPort, + IN BOOL f_fSaveToSoftBuffer, + OUT PBOOL f_pfEventDetected ) +{ + tPOCT6100_SHARED_INFO pSharedInfo; + tPOCT6100_API_BUFFER_PLAYOUT_EVENT pSoftEvent; + tPOCT6100_API_CHANNEL pEchoChannel; + tOCT6100_READ_PARAMS ReadParams; + tOCT6100_GET_TIME GetTimeParms; + + UINT32 ulResult; + UINT16 usReadData; + UINT32 ulReadPtrBytesOfst; + UINT32 ulReadPtrBitOfst; + UINT32 ulReadPtrFieldSize; + + UINT32 ulWritePtrBytesOfst; + UINT32 ulWritePtrBitOfst; + UINT32 ulWritePtrFieldSize; + + UINT32 ulPlayoutBaseAddress; + UINT32 ulTempData; + UINT32 ulReadPtr; + UINT32 ulMask; + UINT32 ulWritePtr; + UINT32 ulUserEventId; + UINT32 ulEventType; + + /* Get local pointer(s). */ + pSharedInfo = f_pApiInstance->pSharedInfo; + + /* Compare the read and write pointers for matching. If they matched, playout stopped. */ + mOCT6100_GET_CHANNEL_ENTRY_PNT( pSharedInfo, pEchoChannel, f_ulChannelIndex ); + + /* Set the playout feature base address. */ + ulPlayoutBaseAddress = cOCT6100_CHANNEL_ROOT_BASE + ( f_ulChannelIndex * cOCT6100_CHANNEL_ROOT_SIZE ) + pSharedInfo->MemoryMap.ulChanRootConfOfst; + + if ( f_ulChannelPort == cOCT6100_CHANNEL_PORT_ROUT ) + { + /* Check on the Rout port. */ + ulUserEventId = pEchoChannel->ulRinUserBufPlayoutEventId; + ulEventType = pEchoChannel->byRinPlayoutStopEventType; + + ulWritePtrBytesOfst = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.usDwordOffset * 4; + ulWritePtrBitOfst = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.byBitOffset; + ulWritePtrFieldSize = pSharedInfo->MemoryMap.PlayoutRinWritePtrOfst.byFieldSize; + + ulReadPtrBytesOfst = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.usDwordOffset * 4; + ulReadPtrBitOfst = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.byBitOffset; + ulReadPtrFieldSize = pSharedInfo->MemoryMap.PlayoutRinReadPtrOfst.byFieldSize; + } + else /* if ( f_ulChannelPort == cOCT6100_CHANNEL_PORT_SOUT ) */ + { + /* Check on the Sout port. */ + ulUserEventId = pEchoChannel->ulSoutUserBufPlayoutEventId; + ulEventType = pEchoChannel->bySoutPlayoutStopEventType; + + ulWritePtrBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.usDwordOffset * 4; + ulWritePtrBitOfst = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.byBitOffset; + ulWritePtrFieldSize = pSharedInfo->MemoryMap.PlayoutSoutWritePtrOfst.byFieldSize; + + ulReadPtrBytesOfst = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.usDwordOffset * 4; + ulReadPtrBitOfst = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.byBitOffset; + ulReadPtrFieldSize = pSharedInfo->MemoryMap.PlayoutSoutReadPtrOfst.byFieldSize; + } + + /* Retrieve the current write pointer. */ + mOCT6100_RETRIEVE_NLP_CONF_DWORD( f_pApiInstance, + pEchoChannel, + ulPlayoutBaseAddress + ulWritePtrBytesOfst, + &ulTempData, + ulResult ); + if ( ulResult != cOCT6100_ERR_OK ) + return ulResult; + + mOCT6100_CREATE_FEATURE_MASK( ulWritePtrFieldSize, ulWritePtrBitOfst, &ulMask ); + + /* Store the write pointer.*/ + ulWritePtr = ( ulTempData & ulMask ) >> ulWritePtrBitOfst; + + /* Read the read pointer.*/ + ReadParams.pProcessContext = f_pApiInstance->pProcessContext; + + ReadParams.ulUserChipId = pSharedInfo->ChipConfig.ulUserChipId; + ReadParams.pusReadData = &usReadData; + ReadParams.ulReadAddress = ulPlayoutBaseAddress + ulReadPtrBytesOfst; + + /* Optimize this access by only reading the word we are interested in. */ + if ( ulReadPtrBitOfst < 16 ) + ReadParams.ulReadAddress += 2; + + /* Must read in memory directly since this value is changed by hardware */ + mOCT6100_DRIVER_READ_API( ReadParams, ulResult ) + if ( ulResult != cOCT6100_ERR_OK ) + return ulResult; + + /* Move data at correct position according to what was read. */ + if ( ulReadPtrBitOfst < 16 ) + ulTempData = usReadData; + else + ulTempData = usReadData << 16; + + mOCT6100_CREATE_FEATURE_MASK( ulReadPtrFieldSize, ulReadPtrBitOfst, &ulMask ); + + /* Store the read pointer. */ + ulReadPtr = ( ulTempData & ulMask ) >> ulReadPtrBitOfst; + + /* Playout has finished when the read pointer reaches the write pointer. */ + if ( ulReadPtr != ulWritePtr ) + { + /* Still playing -- do not generate an event. */ + if ( f_pfEventDetected != NULL ) + *f_pfEventDetected = FALSE; + } + else + { + /* Buffer stopped playing, generate an event here, if asked. */ + if ( ( f_fSaveToSoftBuffer == TRUE ) + && ( ( pSharedInfo->SoftBufs.ulBufPlayoutEventBufferWritePtr + 1 ) != pSharedInfo->SoftBufs.ulBufPlayoutEventBufferReadPtr ) + && ( ( pSharedInfo->SoftBufs.ulBufPlayoutEventBufferWritePtr + 1 ) != pSharedInfo->SoftBufs.ulBufPlayoutEventBufferSize || pSharedInfo->SoftBufs.ulBufPlayoutEventBufferReadPtr != 0 ) ) + { + /* The API can create a soft buffer playout event. */ + mOCT6100_GET_BUFFER_PLAYOUT_EVENT_BUF_PNT( pSharedInfo, pSoftEvent ) + pSoftEvent += pSharedInfo->SoftBufs.ulBufPlayoutEventBufferWritePtr; + + pSoftEvent->ulChannelHandle = cOCT6100_HNDL_TAG_CHANNEL | (pEchoChannel->byEntryOpenCnt << cOCT6100_ENTRY_OPEN_CNT_SHIFT) | f_ulChannelIndex; + pSoftEvent->ulUserChanId = pEchoChannel->ulUserChanId; + pSoftEvent->ulUserEventId = ulUserEventId; + pSoftEvent->ulChannelPort = f_ulChannelPort; + /* For now, only this type of event is available. */ + pSoftEvent->ulEventType = ulEventType; + + /* Generate millisecond timestamp. */ + GetTimeParms.pProcessContext = f_pApiInstance->pProcessContext; + ulResult = Oct6100UserGetTime( &GetTimeParms ); + if ( ulResult != cOCT6100_ERR_OK ) + return ulResult; + + pSoftEvent->ulTimestamp = ( GetTimeParms.aulWallTimeUs[ 0 ] / 1000 ); + pSoftEvent->ulTimestamp += ( GetTimeParms.aulWallTimeUs[ 1 ] ) * ( 0xFFFFFFFF / 1000 ); + + /* Update the control variables of the buffer. */ + pSharedInfo->SoftBufs.ulBufPlayoutEventBufferWritePtr++; + if ( pSharedInfo->SoftBufs.ulBufPlayoutEventBufferWritePtr == pSharedInfo->SoftBufs.ulBufPlayoutEventBufferSize ) + pSharedInfo->SoftBufs.ulBufPlayoutEventBufferWritePtr = 0; + + /* Set the interrupt manager such that the user knows that some playout events */ + /* are pending in the software Q. */ + pSharedInfo->IntrptManage.fBufferPlayoutEventsPending = TRUE; + } + else if ( f_fSaveToSoftBuffer == TRUE ) + { + /* Set the overflow flag of the buffer. */ + pSharedInfo->SoftBufs.ulBufPlayoutEventBufferOverflowCnt++; + } + + /* Update the channel entry to set the playing flag to FALSE. */ + + /* Select the port of interest. */ + if ( f_ulChannelPort == cOCT6100_CHANNEL_PORT_ROUT ) + { + /* Decrement the number of active buffer playout ports. */ + /* No need to check anything here, it's been done in the calling function. */ + pSharedInfo->ChipStats.usNumberActiveBufPlayoutPorts--; + + pEchoChannel->fRinBufPlaying = FALSE; + pEchoChannel->fRinBufPlayoutNotifyOnStop = FALSE; + + /* Clear optimization flag if possible. */ + if ( ( pEchoChannel->fSoutBufPlaying == FALSE ) + && ( pEchoChannel->fSoutBufPlayoutNotifyOnStop == FALSE ) ) + { + /* Buffer playout is no more active on this channel. */ + pEchoChannel->fBufPlayoutActive = FALSE; + } + } + else /* f_ulChannelPort == cOCT6100_CHANNEL_PORT_SOUT */ + { + /* Decrement the number of active buffer playout ports. */ + /* No need to check anything here, it's been done in the calling function. */ + pSharedInfo->ChipStats.usNumberActiveBufPlayoutPorts--; + + pEchoChannel->fSoutBufPlaying = FALSE; + pEchoChannel->fSoutBufPlayoutNotifyOnStop = FALSE; + + /* Clear optimization flag if possible. */ + if ( ( pEchoChannel->fRinBufPlaying == FALSE ) + && ( pEchoChannel->fRinBufPlayoutNotifyOnStop == FALSE ) ) + { + /* Buffer playout is no more active on this channel. */ + pEchoChannel->fBufPlayoutActive = FALSE; + } + } + + /* Return that an event was detected. */ + if ( f_pfEventDetected != NULL ) + *f_pfEventDetected = TRUE; + } + + return cOCT6100_ERR_OK; +} + +#endif /* cOCT6100_REMOVE_EVENTS */ |