| /****************************************************************************** |
| |
| Copyright (c) 2014-2015 Lantiq Deutschland GmbH |
| Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG |
| Copyright 2016, Intel Corporation. |
| |
| For licensing information, see the file 'LICENSE' in the root folder of |
| this software module. |
| |
| ******************************************************************************/ |
| |
| /** |
| \file dxs_hsm.c |
| |
| */ |
| |
| /* ========================================================================== */ |
| /* Includes */ |
| /* ========================================================================== */ |
| #include "dxs_config.h" |
| #include "dxs_lib.h" |
| #include "dxs.h" |
| #include "dxs_error.h" |
| #include "dxs_timer.h" |
| #include "dxs_event.h" |
| |
| /* ============================= */ |
| /* Configuration */ |
| /* ============================= */ |
| /* Scatter the times used for timeout over the given period with the given |
| increment between each timer start. This can help to distribute the load |
| in systems with multiple devices when hook events happen on all lines in |
| parallel. The increment must be smaller than half the maximum time. |
| To use this option set DXS_DIAL_SCATTER_MAX to a positive time in ms and |
| DXS_DIAL_SCATTER_INC to a positive time in ms of maximum half the max time. |
| Using this option degrades the precision of the timeouts for the on-hook, |
| off-hook, flash-holdoff and interdigit. The precision of the times for |
| flash and pulse detection will stay unaffected. */ |
| #define DXS_DIAL_SCATTER_MAX 0 /* ms */ |
| #define DXS_DIAL_SCATTER_INC 0 /* ms */ |
| #if (DXS_DIAL_SCATTER_MAX / 2) < DXS_DIAL_SCATTER_INC |
| #error Configuration of DIAL_SCATTER incorrect |
| #endif |
| |
| /* ========================================================================== */ |
| /* Macro definitions */ |
| /* ========================================================================== */ |
| |
| #if (DXS_DIAL_SCATTER_MAX > 0) |
| #define DXS_DIAL_SCATTER_INCREASE \ |
| do { \ |
| nScatter += DXS_DIAL_SCATTER_INC; \ |
| if (nScatter > DXS_DIAL_SCATTER_MAX) \ |
| nScatter = 0; \ |
| } while (0) |
| #else |
| #define DXS_DIAL_SCATTER_INCREASE |
| #endif |
| |
| #if 0 |
| //origin code |
| #define DXS_MIN_FLASH 80 |
| #define DXS_MAX_FLASH 400 |
| #define DXS_MIN_FLASH_MAKE 200 |
| #define DXS_MIN_DIGIT_LOW 30 |
| #define DXS_MAX_DIGIT_LOW 80 |
| #define DXS_MIN_DIGIT_HIGH 30 |
| #define DXS_MAX_DIGIT_HIGH 80 |
| #define DXS_MIN_OFF_HOOK 40 |
| #define DXS_MIN_ON_HOOK 400 |
| #define DXS_MIN_INTERDIGIT 300 |
| #else |
| #define DXS_MIN_FLASH 150 |
| #define DXS_MAX_FLASH 700 |
| #define DXS_MIN_FLASH_MAKE 400 |
| #define DXS_MIN_DIGIT_LOW 30 |
| #define DXS_MAX_DIGIT_LOW 80 |
| #define DXS_MIN_DIGIT_HIGH 30 |
| #define DXS_MAX_DIGIT_HIGH 80 |
| #define DXS_MIN_OFF_HOOK 40 |
| #define DXS_MIN_ON_HOOK 710 |
| #define DXS_MIN_INTERDIGIT 300 |
| #endif |
| /* ========================================================================== */ |
| /* Type definitions */ |
| /* ========================================================================== */ |
| |
| /* ========================================================================== */ |
| /* Global variables */ |
| /* ========================================================================== */ |
| |
| /* ========================================================================== */ |
| /* Function prototypes */ |
| /* ========================================================================== */ |
| |
| /* ========================================================================== */ |
| /* Function implementation */ |
| /* ========================================================================== */ |
| |
| #ifdef DXS_FEAT_HSM |
| |
| /** |
| Process an action in the state machines. |
| |
| In this function the hook, digit and flash state machines are all handled |
| one after the other. The hook state machine needs to be the first because it |
| directly changes the on-hook/off-hook states of the other state machines. |
| This reduces the complexity of code of the other state machines. |
| |
| \param pChannel Pointer to DXS channel structure. |
| \param nAction Action to be executed. |
| \param nTime If action is make or break this parameter holds the |
| duration since the last hook event in milliseconds. |
| If the action is timeout this parameter is unused. |
| */ |
| static void dxs_dial_Action(DXS_CHANNEL_t * pChannel, |
| enum ACTION nAction, |
| uint16_t nTime) |
| { |
| DXS_DIAL_DATA_t *pDXS_DialData = &pChannel->DXS_DialData; |
| DXS_DEVICE_t *pDev = pChannel->pParent; |
| DXS_Event_t dxs_event; |
| int32_t bSendPulseEvent; |
| static uint32_t nScatter = 0; /* library global */ |
| |
| #if 0 /* hook state machine tracing */ |
| printf(" ACTION: %d (hook %d, digit %d, flash %d) time %d\n", nAction, |
| pDXS_DialData->nHookState, |
| pDXS_DialData->nDigitState, |
| pDXS_DialData->nFlashState, |
| nTime); |
| #endif |
| |
| /* Handle the hook-state detection finite state machine. */ |
| switch (pDXS_DialData->nHookState) |
| { |
| case HOOK_STATE_ONHOOK: |
| if (nAction == ACTION_MAKE) |
| { |
| pDXS_DialData->nHookState = HOOK_STATE_VALIDATE_OFFHOOK; |
| DXS_TimerSet(pDXS_DialData->HookTimerID, |
| pDXS_DialData->nTimeOffhook + nScatter, 0, 1); |
| DXS_DIAL_SCATTER_INCREASE; |
| } |
| break; |
| |
| case HOOK_STATE_OFFHOOK: |
| if (nAction == ACTION_BREAK) |
| { |
| pDXS_DialData->nHookState = HOOK_STATE_VALIDATE_ONHOOK; |
| DXS_TimerSet(pDXS_DialData->HookTimerID, |
| pDXS_DialData->nTimeOnhook + nScatter, 0, 1); |
| DXS_DIAL_SCATTER_INCREASE; |
| } |
| break; |
| |
| case HOOK_STATE_VALIDATE_OFFHOOK: |
| if (nAction == ACTION_BREAK) |
| { |
| pDXS_DialData->nHookState = HOOK_STATE_ONHOOK; |
| DXS_TimerStop(pDXS_DialData->HookTimerID); |
| } |
| else |
| if (nAction == ACTION_TIMEOUT_HOOK) |
| { |
| pDXS_DialData->nHookState = HOOK_STATE_OFFHOOK; |
| /* Attention: change of the digit and flash state machine data! */ |
| pDXS_DialData->nDigitState = DIGIT_STATE_OFFHOOK; |
| pDXS_DialData->nFlashState = FLASH_STATE_OFFHOOK; |
| pDXS_DialData->nPulseDigit = 0; |
| pDXS_DialData->bPulseStartSent = 0; |
| /* DXS event: off-hook */ |
| dxs_event.dev = pDev->nDevNum; |
| dxs_event.ch = pChannel->nCh; |
| dxs_event.id = DXS_EVENT_FXS_OFFHOOK; |
| DXS_EventDispatch(pDev, &dxs_event); |
| } |
| break; |
| |
| case HOOK_STATE_VALIDATE_ONHOOK: |
| if (nAction == ACTION_MAKE) |
| { |
| pDXS_DialData->nHookState = HOOK_STATE_OFFHOOK; |
| DXS_TimerStop(pDXS_DialData->HookTimerID); |
| } |
| else |
| if (nAction == ACTION_TIMEOUT_HOOK) |
| { |
| pDXS_DialData->nHookState = HOOK_STATE_ONHOOK; |
| /* Attention: change of the digit and flash state machine data! */ |
| pDXS_DialData->nDigitState = DIGIT_STATE_ONHOOK; |
| pDXS_DialData->nFlashState = FLASH_STATE_ONHOOK; |
| /* TAPI event: on-hook */ |
| dxs_event.dev = pDev->nDevNum; |
| dxs_event.ch = pChannel->nCh; |
| dxs_event.id = DXS_EVENT_FXS_ONHOOK; |
| DXS_EventDispatch(pDev, &dxs_event); |
| } |
| break; |
| } |
| |
| /* Handle the pulse dialing detection finite state machine. */ |
| /* Attention: the hook state machine above will do the transitions into and |
| out of the off-hook state. */ |
| switch (pDXS_DialData->nDigitState) |
| { |
| case DIGIT_STATE_ONHOOK: |
| /* ignore all */ |
| break; |
| |
| case DIGIT_STATE_OFFHOOK: |
| if (nAction == ACTION_BREAK) |
| pDXS_DialData->nDigitState = DIGIT_STATE_VALIDATE_DIGIT_BREAK; |
| break; |
| |
| case DIGIT_STATE_VALIDATE_DIGIT_BREAK: |
| if (nAction == ACTION_MAKE) |
| { |
| if ((nTime >= pDXS_DialData->nTimeDigitBreakMin) && |
| (nTime <= pDXS_DialData->nTimeDigitBreakMax)) |
| { |
| pDXS_DialData->nDigitState = DIGIT_STATE_VALIDATE_DIGIT_MAKE; |
| pDXS_DialData->nPulseDigit += 1; |
| DXS_TimerSet(pDXS_DialData->InterdigitTimerID, |
| pDXS_DialData->nTimeInterdigit + nScatter, 0, 1); |
| DXS_DIAL_SCATTER_INCREASE; |
| if ((pDXS_DialData->nPulseDigit == 1) && |
| (pDXS_DialData->bPulseStartSent == 0)) |
| { |
| /* report the first validated pulse dial break */ |
| /* Use this to stop a dial tone right after the first pulse. */ |
| dxs_event.dev = pDev->nDevNum; |
| dxs_event.ch = pChannel->nCh; |
| dxs_event.id = DXS_EVENT_PULSE_START; |
| DXS_EventDispatch(pDev, &dxs_event); |
| /* Do this only for the first pulse after off-hook or flash. */ |
| pDXS_DialData->bPulseStartSent = 1; |
| } |
| } |
| else |
| { |
| pDXS_DialData->nDigitState = DIGIT_STATE_OFFHOOK; |
| pDXS_DialData->nPulseDigit = 0; |
| } |
| } |
| break; |
| |
| case DIGIT_STATE_VALIDATE_DIGIT_MAKE: |
| bSendPulseEvent = 0; |
| if (nAction == ACTION_BREAK) |
| { |
| pDXS_DialData->nDigitState = DIGIT_STATE_VALIDATE_DIGIT_BREAK; |
| DXS_TimerStop(pDXS_DialData->InterdigitTimerID); |
| if (nTime >= pDXS_DialData->nTimeInterdigit) |
| { |
| /* Accept also the time from the hook event for the inter-digit |
| timeout condition. */ |
| bSendPulseEvent = 1; |
| } |
| else |
| if ((nTime < pDXS_DialData->nTimeDigitMakeMin) || |
| (nTime > pDXS_DialData->nTimeDigitMakeMax)) |
| { |
| pDXS_DialData->nPulseDigit = 0; |
| } |
| } |
| else |
| if (nAction == ACTION_TIMEOUT_INTERDIGIT) |
| { |
| pDXS_DialData->nDigitState = DIGIT_STATE_OFFHOOK; |
| bSendPulseEvent = 1; |
| } |
| /* _no_ else here */ |
| if (bSendPulseEvent) |
| { |
| if (pDXS_DialData->nPulseDigit <= 10) |
| { |
| /* TAPI event: digit */ |
| dxs_event.dev = pDev->nDevNum; |
| dxs_event.ch = pChannel->nCh; |
| dxs_event.id = DXS_EVENT_PULSE_DIGIT; |
| dxs_event.data.pulse.digit = pDXS_DialData->nPulseDigit; |
| /* 10 pulses represent digit 0 which has TAPI code 0xB */ |
| if (dxs_event.data.pulse.digit == 10) |
| dxs_event.data.pulse.digit = 0x0B; |
| DXS_EventDispatch(pDev, &dxs_event); |
| } |
| pDXS_DialData->nPulseDigit = 0; |
| } |
| break; |
| } |
| |
| /* Handle the flash hook detection finite state machine. */ |
| /* Attention: the hook state machine above will do the transitions into and |
| out of the off-hook state. */ |
| switch (pDXS_DialData->nFlashState) |
| { |
| case FLASH_STATE_ONHOOK: |
| /* ignore all */ |
| break; |
| |
| case FLASH_STATE_OFFHOOK: |
| if (nAction == ACTION_BREAK) |
| pDXS_DialData->nFlashState = FLASH_STATE_VALIDATE_FLASH_BREAK; |
| break; |
| |
| case FLASH_STATE_VALIDATE_FLASH_BREAK: |
| if (nAction == ACTION_MAKE) |
| { |
| if ((nTime >= pDXS_DialData->nTimeFlashBreakMin) && |
| (nTime <= pDXS_DialData->nTimeFlashBreakMax)) |
| { |
| pDXS_DialData->nFlashState = FLASH_STATE_VALIDATE_FLASH_HOLDOFF; |
| DXS_TimerSet(pDXS_DialData->FlashHoldoffTimerID, |
| pDXS_DialData->nTimeFlashHoldoff + nScatter, 0, 1); |
| DXS_DIAL_SCATTER_INCREASE; |
| } |
| else |
| { |
| pDXS_DialData->nFlashState = FLASH_STATE_OFFHOOK; |
| } |
| } |
| break; |
| |
| case FLASH_STATE_VALIDATE_FLASH_HOLDOFF: |
| if (nAction == ACTION_BREAK) |
| { |
| pDXS_DialData->nFlashState = FLASH_STATE_VALIDATE_FLASH_BREAK; |
| DXS_TimerStop(pDXS_DialData->FlashHoldoffTimerID); |
| } |
| else |
| if (nAction == ACTION_TIMEOUT_FLASHHOLDOFF) |
| { |
| pDXS_DialData->nFlashState = FLASH_STATE_OFFHOOK; |
| pDXS_DialData->bPulseStartSent = 0; |
| /* TAPI event: flash */ |
| dxs_event.dev = pDev->nDevNum; |
| dxs_event.ch = pChannel->nCh; |
| dxs_event.id = DXS_EVENT_FXS_FLASH; |
| DXS_EventDispatch(pDev, &dxs_event); |
| } |
| break; |
| } |
| |
| #if 0 /* hook state machine tracing */ |
| printf(" (hook %d, digit %d, flash %d) digit %d\n", |
| pDXS_DialData->nHookState, |
| pDXS_DialData->nDigitState, |
| pDXS_DialData->nFlashState, |
| pDXS_DialData->nPulseDigit); |
| #endif |
| } |
| |
| |
| /** |
| Hook state machine timer callback function. |
| |
| \param nArg Argument of timer. This argument is a pointer to the |
| DXS_CHANNEL_t structure. |
| */ |
| void dxs_dial_OnHookTimer(Timer_ID tm, void *arg) |
| { |
| DXS_CHANNEL_t *pChannel = (DXS_CHANNEL_t *)arg; |
| |
| dxs_dial_Action(pChannel, ACTION_TIMEOUT_HOOK, /*dummy*/0); |
| return; |
| } |
| |
| |
| /** |
| Inter-digit timer callback function. |
| |
| \param nArg Argument of timer. This argument is a pointer to the |
| DXS_CHANNEL_t structure. |
| */ |
| void dxs_dial_OnInterdigitTimer(Timer_ID tm, void *arg) |
| { |
| DXS_CHANNEL_t *pChannel = (DXS_CHANNEL_t *)arg; |
| |
| dxs_dial_Action(pChannel, ACTION_TIMEOUT_INTERDIGIT, /*dummy*/0); |
| return; |
| } |
| |
| /** |
| Flash holdoff timer callback function. |
| |
| \param nArg Argument of timer. This argument is a pointer to the |
| DXS_CHANNEL_t structure. |
| */ |
| void dxs_dial_OnFlashHoldoffTimer(Timer_ID tm, void *arg) |
| { |
| DXS_CHANNEL_t *pChannel = (DXS_CHANNEL_t *)arg; |
| |
| dxs_dial_Action(pChannel, ACTION_TIMEOUT_FLASHHOLDOFF, /*dummy*/0); |
| return; |
| } |
| |
| |
| /** |
| Flash holdoff timer callback function. |
| |
| \param nArg Argument of timer. This argument is a pointer to the |
| DXS_CHANNEL_t structure. |
| */ |
| void dxs_dial_OnHookWindowTimer(Timer_ID tm, void *arg) |
| { |
| DXS_CHANNEL_t *pChannel = (DXS_CHANNEL_t *)arg; |
| DXS_DIAL_DATA_t *pDXS_DialData = &pChannel->DXS_DialData; |
| |
| pDXS_DialData->bHookWindow = 0; |
| return; |
| } |
| |
| /** |
| Initialize the analog line state machines on the given channel. |
| Initialize the data structures and resources needed for the |
| hook state machine. |
| |
| \param pChannel Pointer to DXS_CHANNEL_t structure. |
| |
| \return |
| DXS_statusOk - if successful |
| DXS_statusTimerCreateError - timer creation failed |
| |
| \remarks This function is not protected. |
| */ |
| int32_t DXS_Dial_Initialise_Unprot (DXS_CHANNEL_t *pChannel) |
| { |
| DXS_DIAL_DATA_t *pDXS_DialData = &pChannel->DXS_DialData; |
| DXS_status_t ret = DXS_statusError; |
| |
| if (pChannel->flags & DXS_CH_DIAL_DATA_INITIALIZED) |
| return DXS_statusOk; |
| |
| /* set default values for the validation times */ |
| pDXS_DialData->nTimeOnhook = DXS_MIN_ON_HOOK; |
| pDXS_DialData->nTimeOffhook = DXS_MIN_OFF_HOOK; |
| pDXS_DialData->nTimeInterdigit = DXS_MIN_INTERDIGIT; |
| pDXS_DialData->nTimeFlashHoldoff = DXS_MIN_FLASH_MAKE; |
| pDXS_DialData->nTimeDigitMakeMin = DXS_MIN_DIGIT_HIGH; |
| pDXS_DialData->nTimeDigitMakeMax = DXS_MAX_DIGIT_HIGH; |
| pDXS_DialData->nTimeDigitBreakMin = DXS_MIN_DIGIT_LOW; |
| pDXS_DialData->nTimeDigitBreakMax = DXS_MAX_DIGIT_LOW; |
| pDXS_DialData->nTimeFlashBreakMin = DXS_MIN_FLASH; |
| pDXS_DialData->nTimeFlashBreakMax = DXS_MAX_FLASH; |
| |
| /* start all three HSMs in on-hook state */ |
| pDXS_DialData->nHookState = HOOK_STATE_ONHOOK; |
| pDXS_DialData->nDigitState = DIGIT_STATE_ONHOOK; |
| pDXS_DialData->nFlashState = FLASH_STATE_ONHOOK; |
| pDXS_DialData->nPulseDigit = 0; |
| pDXS_DialData->bPulseStartSent = 0; |
| |
| /* create hook-state-machine validation timer */ |
| pDXS_DialData->HookTimerID = |
| DXS_TimerCreate(dxs_dial_OnHookTimer, (void *)pChannel); |
| if (NULL == pDXS_DialData->HookTimerID) |
| { |
| perror("ERROR: Creation of hook-state-machine validation timer failed"); |
| DXS_RETURN(ret); |
| } |
| /* create inter-digit timer */ |
| pDXS_DialData->InterdigitTimerID = |
| DXS_TimerCreate(dxs_dial_OnInterdigitTimer, (void *)pChannel); |
| if (NULL == pDXS_DialData->InterdigitTimerID) |
| { |
| perror("ERROR: Creation of inter-digit timer failed"); |
| DXS_Dial_Cleanup(pChannel); |
| DXS_RETURN(ret); |
| } |
| /* create flash holdoff timer */ |
| pDXS_DialData->FlashHoldoffTimerID = |
| DXS_TimerCreate(dxs_dial_OnFlashHoldoffTimer, (void *)pChannel); |
| if (NULL == pDXS_DialData->FlashHoldoffTimerID) |
| { |
| perror("ERROR: Creation of flash holdoff timer failed"); |
| DXS_Dial_Cleanup(pChannel); |
| DXS_RETURN(ret); |
| } |
| /* create hook event timestamp wraparound timer */ |
| pDXS_DialData->HookWindowTimerId = |
| DXS_TimerCreate(dxs_dial_OnHookWindowTimer, (void *)pChannel); |
| if (NULL == pDXS_DialData->HookWindowTimerId) |
| { |
| perror("ERROR: Creation of hook event timestamp wraparound timer failed"); |
| DXS_Dial_Cleanup(pChannel); |
| DXS_RETURN(ret); |
| } |
| |
| pDXS_DialData->bHookWindow = 0; |
| pDXS_DialData->nLastHookEvtTimestamp = 0; |
| pDXS_DialData->nTimeOffhookBackup = 0; |
| |
| pChannel->flags |= DXS_CH_DIAL_DATA_INITIALIZED; |
| return DXS_statusOk; |
| } |
| |
| |
| /** |
| Cleanup the analog line state machines on the given channel. |
| |
| Free the resources needed for the hook state machine and |
| the ground-key state machine. |
| |
| \param pChannel Pointer to DXS_CHANNEL_t structure. |
| */ |
| void DXS_Dial_Cleanup(DXS_CHANNEL_t *pChannel) |
| { |
| DXS_DIAL_DATA_t *pDXS_DialData = &pChannel->DXS_DialData; |
| |
| if (!(pChannel->flags & DXS_CH_DIAL_DATA_INITIALIZED)) |
| return; |
| /* unconditionally delete all timers */ |
| DXS_TimerDestroy(pDXS_DialData->HookTimerID); |
| DXS_TimerDestroy(pDXS_DialData->InterdigitTimerID); |
| DXS_TimerDestroy(pDXS_DialData->FlashHoldoffTimerID); |
| DXS_TimerDestroy(pDXS_DialData->HookWindowTimerId); |
| pChannel->flags &= ~DXS_CH_DIAL_DATA_INITIALIZED; |
| } |
| |
| |
| /** |
| Process hook events in the state machines. |
| |
| \param pChannel Pointer to DXS_CHANNEL_t structure. |
| \param bHookState - 1: make (off-hook), |
| - 0: break (on-hook) |
| \param nTime Duration since the last hook event in ms. |
| */ |
| void DXS_Dial_HookEvent (DXS_CHANNEL_t* pChannel, |
| uint32_t bHookState, |
| uint16_t nTime) |
| { |
| /* make sure dial is initialised on this channel */ |
| if (!(pChannel->flags & DXS_CH_DIAL_DATA_INITIALIZED)) |
| { |
| /* silently ignore event - this case can happen during startup or |
| shutdown when an interrupt occurs but DXS_DialData is not initialized. |
| */ |
| return; |
| } |
| |
| nTime = DXS_Dial_ElapsedTimeSinceLastHook(pChannel, nTime); |
| |
| /* Note: The hook events actually report a change between the make and break |
| status of the line. The action reports the new line status. This implies |
| that before this event the opposite line status was present and that the |
| time that is reported is the duration that this status was present. |
| Here make and break is used to make it clear that this is not the hook |
| status of the phone but the line state which will also change from |
| pulse dialing and flash hook. */ |
| dxs_dial_Action(pChannel, bHookState ? ACTION_MAKE : ACTION_BREAK, nTime); |
| |
| return; |
| } |
| |
| |
| /** |
| Set the given hook state unconditionally. |
| |
| This is used after certain CID sequences which use hook for signaling |
| purposes. There the hook is not given to this state machine and so the |
| state needs to be corrected in case of an abort. |
| |
| \param pChannel Pointer to DXS_CHANNEL_t structure. |
| \param bHookState - 1: make (off-hook), |
| - 0: break (on-hook) |
| */ |
| void DXS_Dial_HookSet (DXS_CHANNEL_t *pChannel, int32_t bHookState) |
| { |
| DXS_DIAL_DATA_t *pDXS_DialData = &pChannel->DXS_DialData; |
| |
| /* make sure dial is initialised on this channel */ |
| if (!(pChannel->flags & DXS_CH_DIAL_DATA_INITIALIZED)) |
| { |
| /* silently ignore */ |
| return; |
| } |
| |
| /* Handle the hook-state detection finite state machine. */ |
| switch(pDXS_DialData->nHookState) |
| { |
| case HOOK_STATE_OFFHOOK: |
| if (bHookState == 0) |
| { |
| pDXS_DialData->nHookState = HOOK_STATE_ONHOOK; |
| pDXS_DialData->nDigitState = DIGIT_STATE_ONHOOK; |
| pDXS_DialData->nFlashState = FLASH_STATE_ONHOOK; |
| /* Do not send a TAPI event here. */ |
| } |
| break; |
| |
| case HOOK_STATE_ONHOOK: |
| if (bHookState == 1) |
| { |
| pDXS_DialData->nHookState = HOOK_STATE_OFFHOOK; |
| pDXS_DialData->nDigitState = DIGIT_STATE_OFFHOOK; |
| pDXS_DialData->nFlashState = FLASH_STATE_OFFHOOK; |
| pDXS_DialData->nPulseDigit = 0; |
| pDXS_DialData->bPulseStartSent = 0; |
| /* Do not send a TAPI event here. */ |
| } |
| break; |
| |
| default: |
| /* Do nothing in the validation states. */ |
| break; |
| } |
| |
| return; |
| } |
| |
| |
| /** |
| Overrides the user configured off-hook time. |
| |
| This is used by the phone detection to set an off-hook time to suppress |
| transient hook events that can occur in the off-hook detection state. |
| |
| \param pChannel Pointer to DXS_CHANNEL_t structure. |
| \param nTime DXS_DIAL_TIME_NORMAL for normal user configured |
| value. All other values are used as off-hook time |
| in milliseconds. |
| \remarks |
| The value 0 is invalid for the off-hook time. Here it is used as a marker. |
| */ |
| void DXS_Dial_OffhookTime_Override(DXS_CHANNEL_t *pChannel, |
| uint32_t const nTime) |
| { |
| DXS_DIAL_DATA_t *pDXS_DialData = &pChannel->DXS_DialData; |
| |
| /* make sure that dial is initialised on this channel */ |
| if (pChannel->flags & DXS_CH_DIAL_DATA_INITIALIZED) |
| { |
| if (nTime == DXS_DIAL_TIME_NORMAL) |
| { |
| if (pDXS_DialData->nTimeOffhookBackup != 0) |
| { |
| /* Restore the backed up time value. */ |
| pDXS_DialData->nTimeOffhook = pDXS_DialData->nTimeOffhookBackup; |
| pDXS_DialData->nTimeOffhookBackup = 0; |
| } |
| } |
| else |
| { |
| /* Switch to override - backup time value and set from parameter. */ |
| if (pDXS_DialData->nTimeOffhookBackup == 0) |
| { |
| pDXS_DialData->nTimeOffhookBackup = pDXS_DialData->nTimeOffhook; |
| } |
| pDXS_DialData->nTimeOffhook = nTime; |
| } |
| } |
| } |
| |
| /** |
| Calculate the elapsed time since the last hook event. |
| |
| This function is to be called with each hook event. It calculates the |
| elapsed time since the last hook event. |
| |
| The DxS provides a timestamp with each FW event. However, this timestamp |
| has a wraparound after ~66 seconds. So an addtional timer is used to prevent |
| calculation after a wraparound. This function wraps the calculation and |
| also restarts the timer. |
| |
| \param pCh Pointer to DxS channel structure. |
| \param nCurrentTimestamp Current timestamp value from the FW event. |
| |
| \return |
| Elapsed time since the last hook event in 1 ms steps. |
| If the last event happened too long ago or dial is not initialised 0xFFFF is |
| returned. |
| */ |
| uint16_t DXS_Dial_ElapsedTimeSinceLastHook(DXS_CHANNEL_t *pChannel, |
| uint16_t nCurrentTimestamp) |
| { |
| DXS_DIAL_DATA_t *pDXS_DialData = &pChannel->DXS_DialData; |
| uint16_t elapsedTime; |
| |
| if (pDXS_DialData->bHookWindow) |
| { |
| /* Calculate elapsed time since the saved timestamp. In case the 16-bit |
| counter had a wraparound since the saved timestamp the calculation |
| will still be correct because the calculation is done with 16-bit |
| unsigned data type. This will always result in the positive distance |
| between the two timestamps. */ |
| elapsedTime = nCurrentTimestamp - pDXS_DialData->nLastHookEvtTimestamp; |
| } |
| else |
| { |
| elapsedTime = 0xFFFF; |
| } |
| |
| /* Start timer, length of timer nominal 65000 ms. A random component is |
| added to distribute the expiration of the timers in systems with multiple |
| devices using polling where a lot of timers might be started in parallel. |
| This time needs to be below the wraparound of the HW timestamp. */ |
| pDXS_DialData->bHookWindow = 1; |
| DXS_TimerSet(pDXS_DialData->HookWindowTimerId, |
| 65000 + (nCurrentTimestamp & 0x00FF), 0, 1); |
| /* store the timestamp from this event */ |
| pDXS_DialData->nLastHookEvtTimestamp = nCurrentTimestamp; |
| |
| return elapsedTime; |
| } |
| |
| |
| /** |
| Sets the validation times for hook, pulse digit and flashhook. |
| |
| \param pChannel - pointer to DXS channel structure |
| \param pTime - type of validation setting, min and max time in |
| milliseconds. |
| |
| \return |
| - DXS_status_t |
| */ |
| int32_t DXS_Dial_HookValTimeSet(DXS_CHANNEL_t *pChannel, |
| DXS_HookValTime_t *pTime) |
| { |
| DXS_DIAL_DATA_t *pDXS_DialData = &pChannel->DXS_DialData; |
| |
| /* zero timer value is not allowed -- except for the flash holdoff time */ |
| if ((pTime->nMinTime == 0) && |
| (pTime->nType != DXS_HOOK_VT_FLASH_HOLDOFF_TIME)) |
| { |
| DXS_RETURN(DXS_statusDialZeroParam); |
| } |
| |
| /* For the times hook-off, hook-on, interdigit and flash holdoff just |
| the minimum time is relevant. So do not check the maximum time. */ |
| if ((pTime->nType != DXS_HOOK_VT_HOOKOFF_TIME) && |
| (pTime->nType != DXS_HOOK_VT_HOOKON_TIME) && |
| (pTime->nType != DXS_HOOK_VT_INTERDIGIT_TIME) && |
| (pTime->nType != DXS_HOOK_VT_FLASH_HOLDOFF_TIME)) |
| { |
| /* check whether min timer value > max timer value */ |
| if (pTime->nMinTime > pTime->nMaxTime) |
| { |
| DXS_RETURN(DXS_statusDialMaxMinParam); |
| } |
| /* Note: the max timer value cannot be 0 because min > 0 and |
| min <= max entails that max > 0. */ |
| } |
| |
| /* set the validation times */ |
| switch (pTime->nType) |
| { |
| case DXS_HOOK_VT_HOOKOFF_TIME: |
| if (pDXS_DialData->nTimeOffhookBackup == 0) |
| pDXS_DialData->nTimeOffhook = pTime->nMinTime; |
| else |
| pDXS_DialData->nTimeOffhookBackup= pTime->nMinTime; |
| break; |
| |
| case DXS_HOOK_VT_HOOKON_TIME: |
| pDXS_DialData->nTimeOnhook = pTime->nMinTime; |
| break; |
| |
| case DXS_HOOK_VT_HOOKFLASH_TIME: |
| pDXS_DialData->nTimeFlashBreakMin = pTime->nMinTime; |
| pDXS_DialData->nTimeFlashBreakMax = pTime->nMaxTime; |
| break; |
| |
| case DXS_HOOK_VT_DIGITLOW_TIME: |
| pDXS_DialData->nTimeDigitBreakMin = pTime->nMinTime; |
| pDXS_DialData->nTimeDigitBreakMax = pTime->nMaxTime; |
| break; |
| |
| case DXS_HOOK_VT_DIGITHIGH_TIME: |
| pDXS_DialData->nTimeDigitMakeMin = pTime->nMinTime; |
| pDXS_DialData->nTimeDigitMakeMax = pTime->nMaxTime; |
| break; |
| |
| case DXS_HOOK_VT_INTERDIGIT_TIME: |
| pDXS_DialData->nTimeInterdigit = pTime->nMinTime; |
| break; |
| |
| case DXS_HOOK_VT_FLASH_HOLDOFF_TIME: |
| pDXS_DialData->nTimeFlashHoldoff = pTime->nMinTime; |
| break; |
| } |
| |
| return DXS_statusOk; |
| } |
| |
| /** |
| Sets the nHookState to HOOK_STATE_ONHOOK. |
| |
| \param pChannel - pointer to DXS channel structure |
| |
| */ |
| extern void DXS_Dial_HookStateSetOnhook(DXS_CHANNEL_t *pChannel) |
| { |
| DXS_DIAL_DATA_t *pDXS_DialData; |
| |
| if (pChannel != NULL) |
| { |
| pDXS_DialData = &pChannel->DXS_DialData; |
| pDXS_DialData->nHookState = HOOK_STATE_ONHOOK; |
| } |
| } |
| #endif /* DXS_FEAT_HSM */ |