| /******************************************************************************* |
| |
| Copyright (c) 2014-2015 Lantiq Deutschland GmbH |
| Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG |
| Copyright 2016, 2017, 2018 Intel Corporation. |
| |
| For licensing information, see the file 'LICENSE' in the root folder of |
| this software module. |
| |
| *******************************************************************************/ |
| |
| /** |
| \file dxs_ring.c |
| Function implementation for cadenced ringing. |
| */ |
| |
| /* ========================================================================== */ |
| /* Includes */ |
| /* ========================================================================== */ |
| #include <time.h> |
| #include <errno.h> |
| #include "dxs_config.h" |
| #include "dxs_lib.h" |
| #include "dxs_sdd.h" |
| #include "dxs_errno.h" |
| #include "dxs_error.h" |
| #include "dxs_misc.h" |
| #include "dxs_ring.h" |
| #include "dxs_dcdc_hw.h" |
| #include "dxs_cid.h" |
| |
| /* ========================================================================== */ |
| /* Macro definitions */ |
| /* ========================================================================== */ |
| |
| /* total channel count */ |
| #define DXS_RING_CHANNELS (DXS_MAX_DEVICES * CH_PER_DEVICE) |
| #define RING_TIMER_INTERVAL_MS 50 |
| |
| /* ========================================================================== */ |
| /* Type definitions */ |
| /* ========================================================================== */ |
| typedef struct |
| { |
| #define RING_TIMER_STOPPED 0 |
| #define RING_TIMER_RUNNING 1 |
| int32_t state; |
| sem_t sem; |
| pthread_t thr; |
| int32_t ret_val; |
| int32_t current_bit; |
| int32_t reset_bits; |
| } dxs_ring_timer_t; |
| |
| typedef struct |
| { |
| #define RING_CADENCE_NOT_INIT 0 |
| #define RING_CADENCE_INIT 1 |
| #define RING_CADENCE_CID_ACT 2 |
| int32_t flag; |
| DXS_CHANNEL_t *pCh; |
| #define RING_POLARITY_NORMAL 0 |
| #define RING_POLARITY_REVERSE 1 |
| int32_t polarity; |
| #define RING_CAD_STATE_IDLE 0 |
| #define RING_CAD_STATE_RINGING 1 |
| #define RING_CAD_STATE_CID_DURING_RINGING 2 |
| #define RING_CAD_STATE_CID_PRIOR_TO_RINGING 3 |
| volatile int32_t ring_cadence_state; |
| #define RINGER_STATE_PAUSE 0 |
| #define RINGER_STATE_RINGING 1 |
| int32_t ringer_state; |
| DXS_RingCadence_t cadence; |
| /* used only for |
| prior to ringing CID standards */ |
| int32_t wait_counter; |
| int32_t current_bit; |
| } dxs_ring_res_t; |
| |
| /* ========================================================================== */ |
| /* Global variables */ |
| /* ========================================================================== */ |
| |
| static dxs_ring_timer_t reft = {0}; |
| static dxs_ring_res_t ring_cadence[DXS_RING_CHANNELS] = {0}; |
| |
| /* ========================================================================== */ |
| /* Function implementation */ |
| /* ========================================================================== */ |
| |
| /** |
| Return the bit position of the ringing pulse number in a cadence |
| |
| \param pRes - pointer to ringing cadence resource |
| \param ring - ringing pulse number starting from 0 |
| |
| \return |
| - bit position of the ringing pulse |
| */ |
| static int32_t dxs_ring_next_pos_get (dxs_ring_res_t *pRes, int32_t ring) |
| { |
| int32_t bit=0, i=0, rpulse=0, ring_phase=0; |
| |
| /* TODO: protection against infinite loop */ |
| |
| while (1) |
| { |
| if ((pRes->cadence.data[i >> 3] >> (7-(i%8))) & 1) |
| { |
| ring_phase = 1; |
| if (rpulse == ring) |
| break; |
| } |
| else |
| { |
| if (ring_phase) |
| { |
| ring_phase = 0; |
| ++rpulse; |
| } |
| } |
| ++bit; |
| if (++i == pRes->cadence.valid_bits) |
| i = 0; |
| } |
| return bit; |
| } |
| |
| /** |
| Return the ringing cadence initial state; decision point |
| whether the CID sequence shall be used in the ringing cadence. |
| |
| \param pCh - pointer to \ref DXS_CHANNEL_t |
| |
| \return |
| - RING_CAD_STATE_CID_DURING_RINGING |
| - RING_CAD_STATE_CID_PRIOR_TO_RINGING |
| - RING_CAD_STATE_RINGING |
| */ |
| static int32_t dxs_ring_cad_initial_state (DXS_CHANNEL_t *pCh) |
| { |
| int32_t err, ret = RING_CAD_STATE_RINGING; |
| DXS_CID_Std_t cid_std; |
| DXS_CID_AS_t cid_as; |
| |
| err = DXS_CID_StandardGet(pCh, &cid_std); |
| if (err == DXS_statusOk) |
| { |
| err = DXS_CID_AlertSigGet(pCh, &cid_as); |
| } |
| |
| if (err == DXS_statusOk) |
| { |
| if (cid_as == DXS_CID_AS_NONE && |
| (cid_std == DXS_CID_STD_TELCORDIA || cid_std == DXS_CID_STD_ETSI)) |
| { |
| ret = RING_CAD_STATE_CID_DURING_RINGING; |
| } |
| else if (cid_as != DXS_CID_AS_NONE && cid_std != DXS_CID_STD_UNDEF) |
| { |
| ret = RING_CAD_STATE_CID_PRIOR_TO_RINGING; |
| } |
| } |
| return ret; |
| } |
| |
| /** |
| Attempt to shift the ringing cadence so that the new cadence |
| fits into the limitation of IFB12CH8 HW - only two ring bursts |
| are possible at a time per DCDC. |
| 1) The first available bit position for a cadence is searched - |
| where less than two rings are programmed for parallel channels. |
| 2) The new cadence is bit shifted to the found position. |
| 3) The new shifted cadence is checked from shift position to the |
| end if there is no conflict of two parallel rings. |
| If step 1) or 3) fails, than the new cadence does not fit into |
| the ring matrix of a DCDC and an error will be returned. |
| |
| \param pointer to ringing resource context |
| \param ringing cadence length in bytes |
| \return |
| the code from \ref DXS_status_t list |
| */ |
| static int32_t dxs_ifb12ch8_shift_cadence (dxs_ring_res_t *pRes, int32_t len) |
| { |
| int i, pos=0, conflict=0, dcdc; |
| unsigned int max_bits; |
| uint8_t channels_per_dcdc; |
| |
| dcdc = DXS_DCDC_HW_SharedDcDcNumberGet(pRes->pCh); |
| channels_per_dcdc = DXS_DCDC_HW_SharedDcDcChannelNumGet(pRes->pCh); |
| |
| /* get maximum cadence length for a DCDC */ |
| for (i=0, max_bits=0; i<channels_per_dcdc; i++) |
| { |
| DXS_CHANNEL_t *pCh = DXS_DCDC_HW_SharedDcDcChannelGet(dcdc, i); |
| |
| if (pCh != NULL) |
| { |
| dxs_ring_res_t *p = (dxs_ring_res_t *)pCh->ring; |
| |
| if (p->cadence.valid_bits > max_bits) |
| max_bits = p->cadence.valid_bits; |
| } |
| } |
| |
| /* find the first available bit position for the cadence */ |
| for (i=0; i<max_bits; i++) |
| { |
| int c = 0; |
| uint8_t bits=0, |
| my_bit = (pRes->cadence.data[i >> 3] >> (7-(i % 8))) & 1; |
| |
| while (c < channels_per_dcdc) |
| { |
| DXS_CHANNEL_t *pCh = DXS_DCDC_HW_SharedDcDcChannelGet(dcdc, c); |
| |
| if (pCh != NULL && pCh != pRes->pCh) |
| { |
| dxs_ring_res_t *p = (dxs_ring_res_t *)pCh->ring; |
| |
| uint8_t bit = (p->cadence.data[i >> 3] >> (7-(i % 8))) & 1; |
| if (bit) ++bits; |
| } |
| ++c; |
| } |
| if (bits >= 2 && my_bit && !conflict) |
| { |
| conflict = 1; |
| } |
| else if (conflict && bits < 2) |
| { |
| pos = i; |
| conflict = 0; |
| break; |
| } |
| } |
| |
| if (conflict) |
| { |
| DXS_RETURN(DXS_statusRingCadConfInvalid); |
| } |
| |
| DXS_Misc_DataBlkRor(pRes->cadence.data, len, pos); |
| |
| /* position for a cadence start is found, now check the rest |
| of the cadence for possible conflicts */ |
| i = pos; |
| do |
| { |
| int c = 0; |
| uint8_t bits=0, |
| my_bit = (pRes->cadence.data[i >> 3] >> (7-(i % 8))) & 1; |
| |
| while (c < channels_per_dcdc) |
| { |
| DXS_CHANNEL_t *pCh = DXS_DCDC_HW_SharedDcDcChannelGet(dcdc, c); |
| |
| if (pCh != NULL && pCh != pRes->pCh) |
| { |
| dxs_ring_res_t *p = (dxs_ring_res_t *)pCh->ring; |
| |
| uint8_t bit = (p->cadence.data[i >> 3] >> (7-(i % 8))) & 1; |
| if (bit) ++bits; |
| } |
| ++c; |
| } |
| |
| if (bits >= 2 && my_bit) |
| { |
| DXS_RETURN(DXS_statusRingCadConfInvalid); |
| } |
| |
| if (++i == pRes->cadence.valid_bits) |
| i = 0; |
| } while (i != pos); |
| return DXS_statusOk; |
| } |
| |
| /** |
| Start the ringing pulse |
| |
| \param pointer to ringing resource context |
| \return |
| the code from \ref DXS_status_t list |
| */ |
| static int32_t dxs_ring_pulse_start (dxs_ring_res_t *pRes) |
| { |
| int32_t ret = DXS_statusOk; |
| |
| if (pRes->ring_cadence_state == RING_CAD_STATE_RINGING || |
| pRes->ring_cadence_state == RING_CAD_STATE_CID_DURING_RINGING) |
| { |
| DXS_CHANNEL_t *pCh = pRes->pCh; |
| |
| ret = DXS_SDD_LineModeSet(pCh, pRes->polarity ? |
| DXS_LINE_FEED_RINGING_REVPOL : |
| DXS_LINE_FEED_RING_BURST |
| ); |
| pRes->ringer_state = (DXS_statusOk == ret) ? |
| RINGER_STATE_RINGING : RINGER_STATE_PAUSE; |
| } |
| return ret; |
| } |
| |
| /** |
| Stop the ringing pulse |
| |
| \param pointer to ringing resource context |
| \return |
| the code from \ref DXS_status_t list |
| */ |
| static int32_t dxs_ring_pulse_stop (dxs_ring_res_t *pRes) |
| { |
| int32_t ret = DXS_statusOk; |
| |
| if (pRes->ring_cadence_state == RING_CAD_STATE_RINGING || |
| pRes->ring_cadence_state == RING_CAD_STATE_CID_DURING_RINGING) |
| { |
| DXS_CHANNEL_t *pCh = pRes->pCh; |
| |
| ret = DXS_SDD_LineModeSet(pCh, pRes->polarity ? |
| DXS_LINE_FEED_ACTIVE_REVPOL : |
| DXS_LINE_FEED_ACTIVE |
| ); |
| pRes->ringer_state = (DXS_statusOk == ret) ? |
| RINGER_STATE_PAUSE : RINGER_STATE_RINGING; |
| } |
| return ret; |
| } |
| |
| /** |
| Get current bit position for the ringing cadence |
| |
| \param pointer to ringing cadence resource context |
| \return bit position |
| */ |
| static int32_t dxs_ring_cad_bit_position_get (dxs_ring_res_t *pRes) |
| { |
| int32_t bit_pos; |
| |
| if (pRes->pCh->pParent->dcdcType == DXS_DCDC_IFB12CH8) |
| { |
| /* cadence bit position is global for all channels |
| in case of IFB12CH8 */ |
| bit_pos = reft.current_bit; |
| } |
| else |
| { |
| /* cadence bit position is individual for each |
| channel in case of HW without ringing limitations */ |
| bit_pos = pRes->current_bit; |
| } |
| return bit_pos; |
| } |
| |
| /** |
| Ringing timer thread function |
| |
| \param pointer to ringing timer context |
| \return none |
| */ |
| static void *ring_timer_thread (void *arg) |
| { |
| int err; |
| dxs_ring_timer_t *p = (dxs_ring_timer_t *)arg; |
| struct timespec ts = {0}; |
| unsigned long ns; |
| |
| while (p->state == RING_TIMER_RUNNING) |
| { |
| int32_t i, bit_position = -1; |
| |
| /* run through all channels, get ring cadence bit value for |
| each channel and execute appropriate action */ |
| for (i=0; i<DXS_RING_CHANNELS; i++) |
| { |
| dxs_ring_res_t *pRes = &ring_cadence[i]; |
| uint8_t *cad, ring; |
| |
| if (!(pRes->flag & RING_CADENCE_INIT)) |
| continue; |
| |
| cad = pRes->cadence.data; |
| bit_position = dxs_ring_cad_bit_position_get(pRes); |
| /* get ring cadence bit value */ |
| ring = (cad[bit_position >> 3] >> (7-(bit_position % 8))) & 1; |
| |
| /* handle CID prior to ringing */ |
| if (pRes->ring_cadence_state == RING_CAD_STATE_CID_PRIOR_TO_RINGING) |
| { |
| if (!pRes->wait_counter && !(pRes->flag & RING_CADENCE_CID_ACT)) |
| { |
| pRes->flag |= RING_CADENCE_CID_ACT; |
| err = DXS_CID_TypeI_Play(pRes->pCh, DXS_CID_MSG_TYPE_CS, |
| DXS_CID_CALL_FROM_RING_SM); |
| if (err) |
| { |
| DXS_ERROR_PUSH(err); |
| } |
| } |
| else |
| pRes->wait_counter--; |
| } |
| |
| if (!ring && pRes->ringer_state == RINGER_STATE_RINGING) |
| { |
| /* RING OFF */ |
| err = dxs_ring_pulse_stop(pRes); |
| if (err) |
| { |
| DXS_ERROR_PUSH(err); |
| } |
| |
| /* handle CID during ringing */ |
| if (pRes->ring_cadence_state == RING_CAD_STATE_CID_DURING_RINGING) |
| { |
| pRes->flag |= RING_CADENCE_CID_ACT; |
| err = DXS_CID_TypeI_Play(pRes->pCh, DXS_CID_MSG_TYPE_CS, |
| DXS_CID_CALL_FROM_RING_SM); |
| if (err) |
| { |
| DXS_ERROR_PUSH(err); |
| } |
| } |
| } |
| } |
| |
| if (bit_position == -1) |
| { |
| DXS_ERROR_PUSH(-1); |
| continue; |
| } |
| |
| for (i=0; i<DXS_RING_CHANNELS; i++) |
| { |
| dxs_ring_res_t *pRes = &ring_cadence[i]; |
| uint8_t *cad, ring; |
| |
| if (!(pRes->flag & RING_CADENCE_INIT)) |
| continue; |
| |
| cad = pRes->cadence.data; |
| bit_position = dxs_ring_cad_bit_position_get(pRes); |
| /* get ring cadence bit value */ |
| ring = (cad[bit_position >> 3] >> (7-(bit_position % 8))) & 1; |
| |
| if (ring && pRes->ringer_state == RINGER_STATE_PAUSE) |
| { |
| int32_t reset_bits = (pRes->pCh->pParent->dcdcType == DXS_DCDC_IFB12CH8) ? |
| p->reset_bits : pRes->cadence.valid_bits; |
| int32_t pos = ((bit_position + 1) >= reset_bits) ? |
| 0 : (bit_position + 1); |
| int32_t ring_bits = 0; |
| uint8_t bit_val = ring; |
| |
| /* skip execution of "short ring pulses", |
| ensure that ring pulse is at least 500ms long */ |
| while (bit_val) |
| { |
| bit_val = (cad[pos >> 3] >> (7-(pos % 8))) & 1; |
| if (bit_val) |
| ++ring_bits; |
| |
| if (++pos == reset_bits) |
| pos = 0; |
| } |
| |
| if (ring_bits >= 10) |
| { |
| /* RING ON */ |
| err = dxs_ring_pulse_start(pRes); |
| if (err) |
| { |
| DXS_ERROR_PUSH(err); |
| } |
| } |
| } |
| } |
| |
| /* wait 50ms */ |
| clock_gettime (CLOCK_REALTIME, &ts); |
| ns = ts.tv_nsec + RING_TIMER_INTERVAL_MS * 1000 * 1000; |
| ts.tv_nsec = ns % (1000 * 1000 * 1000); |
| ts.tv_sec += ns / (1000 * 1000 * 1000); |
| while ((err = sem_timedwait(&p->sem, &ts)) == -1 && errno == EINTR) |
| continue; |
| if (err == -1 && errno != ETIMEDOUT) |
| { |
| p->ret_val = errno; |
| break; |
| } |
| |
| /* update global bit position */ |
| if (++p->current_bit == p->reset_bits) |
| p->current_bit = 0; |
| |
| /* update individual bit positions per channel */ |
| for (i=0; i<DXS_RING_CHANNELS; i++) |
| { |
| dxs_ring_res_t *pRes = &ring_cadence[i]; |
| |
| if (!(pRes->flag & RING_CADENCE_INIT)) |
| continue; |
| |
| if (pRes->ring_cadence_state != RING_CAD_STATE_CID_PRIOR_TO_RINGING) |
| { |
| if (++pRes->current_bit == pRes->cadence.valid_bits) |
| pRes->current_bit = 0; |
| } |
| } |
| } |
| pthread_exit((void *)(&p->ret_val)); |
| } |
| |
| /** |
| Start the ringing timer |
| |
| \param none |
| \return |
| the code from \ref DXS_status_t list |
| */ |
| static int32_t ring_timer_start (void) |
| { |
| int32_t ret = DXS_statusOk; |
| |
| if (reft.state == RING_TIMER_STOPPED) |
| { |
| int32_t i; |
| |
| reft.state = RING_TIMER_RUNNING; |
| sem_init(&reft.sem, 0, 0); |
| reft.current_bit = 0; |
| reft.reset_bits = 0; |
| |
| for (i=0; i<DXS_RING_CHANNELS; i++) |
| { |
| dxs_ring_res_t *pRes = &ring_cadence[i]; |
| /* reset_bits is the maximum cadence length */ |
| if ((pRes->flag & RING_CADENCE_INIT) && |
| reft.reset_bits < pRes->cadence.valid_bits) |
| { |
| reft.reset_bits = pRes->cadence.valid_bits; |
| } |
| } |
| |
| if (0 != pthread_create(&reft.thr, NULL, ring_timer_thread, (void *)&reft)) |
| ret = DXS_statusThreadCreatError; |
| } |
| return ret; |
| } |
| |
| /** |
| Stop the ringing timer |
| |
| \param none |
| \return none |
| */ |
| static void ring_timer_stop (void) |
| { |
| int i; |
| |
| for (i=0; i<DXS_RING_CHANNELS; i++) |
| { |
| dxs_ring_res_t *pRes = &ring_cadence[i]; |
| |
| if (pRes->ring_cadence_state != RING_CAD_STATE_IDLE) |
| return; |
| } |
| |
| if (reft.state != RING_TIMER_STOPPED) |
| { |
| reft.state = RING_TIMER_STOPPED; |
| sem_post(&reft.sem); |
| pthread_join(reft.thr, NULL); |
| sem_destroy(&reft.sem); |
| } |
| } |
| |
| /** |
| Inform ringing SM about finished CID sequence |
| |
| \param pCh - pointer to DXS channel structure |
| \return |
| - none |
| */ |
| void DXS_Ring_CidFinished (DXS_CHANNEL_t *pCh) |
| { |
| dxs_ring_res_t *pRes = |
| &ring_cadence[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh]; |
| |
| if (pRes->ring_cadence_state == RING_CAD_STATE_CID_DURING_RINGING || |
| pRes->ring_cadence_state == RING_CAD_STATE_CID_PRIOR_TO_RINGING) |
| { |
| pRes->ring_cadence_state = RING_CAD_STATE_RINGING; |
| } |
| pRes->flag &= ~RING_CADENCE_CID_ACT; |
| } |
| |
| /** |
| Initialize ringing resource and link it |
| with the \ref DXS_CHANNEL_t structure |
| |
| \param pCh - pointer to DXS channel structure |
| \return |
| pointer to ringing resource |
| */ |
| void *DXS_Ring_ResInit(DXS_CHANNEL_t *pCh) |
| { |
| dxs_ring_res_t *pRes = |
| &ring_cadence[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh]; |
| |
| pRes->pCh = pCh; |
| pRes->flag = RING_CADENCE_NOT_INIT; |
| |
| return (void *)pRes; |
| } |
| |
| /** |
| Initialize ringing cadence |
| |
| \param pCh - pointer to DXS channel structure |
| \param pConf - pointer to \ref DXS_RingCadence_t structure |
| \return |
| the code from \ref DXS_status_t list |
| */ |
| int32_t DXS_RING_CadenceInit (DXS_CHANNEL_t *pCh, DXS_RingCadence_t *pConf) |
| { |
| int32_t ret = DXS_statusOk; |
| dxs_ring_res_t *pRes = (dxs_ring_res_t *)pCh->ring; |
| int32_t bytes, bytes_to_copy, extra_bits; |
| |
| POINTER_ASSERT(pConf); |
| |
| if (pRes->ring_cadence_state != RING_CAD_STATE_IDLE) |
| { |
| DXS_RETURN(DXS_statusRingCadConfNotPossible); |
| } |
| |
| bytes = pConf->valid_bits >> 3; |
| extra_bits = pConf->valid_bits % 8; |
| bytes_to_copy = bytes + (extra_bits ? 1 : 0); |
| |
| if (bytes_to_copy > DXS_RING_CADENCE_MAX_LEN_BYTES) |
| { |
| DXS_RETURN(DXS_statusRingCadConfInvalid); |
| } |
| |
| pRes->flag &= ~RING_CADENCE_INIT; |
| |
| /* copy cadence data and valid bits */ |
| pRes->cadence = *pConf; |
| if (extra_bits) |
| pRes->cadence.data[bytes] &= (0xff & (0xff << (8 - extra_bits))); |
| |
| /* special arrangements for IFB12CH8 HW */ |
| if (pCh->pParent->dcdcType == DXS_DCDC_IFB12CH8) |
| { |
| ret = dxs_ifb12ch8_shift_cadence(pRes, bytes_to_copy); |
| } |
| |
| if (ret == DXS_statusOk) |
| { |
| pRes->ring_cadence_state = RING_CAD_STATE_IDLE; |
| pRes->ringer_state = RINGER_STATE_PAUSE; |
| pRes->flag |= RING_CADENCE_INIT; |
| } |
| DXS_RETURN(ret); |
| } |
| |
| /** |
| Start ringing cadence |
| |
| \param pCh - pointer to DXS channel structure |
| \return |
| the code from \ref DXS_status_t list |
| */ |
| int32_t DXS_RING_CadenceStart (DXS_CHANNEL_t *pCh) |
| { |
| dxs_ring_res_t *pRes = (dxs_ring_res_t *)pCh->ring; |
| int32_t ret; |
| int opmode; |
| |
| if (!(pRes->flag & RING_CADENCE_INIT)) |
| { |
| DXS_RETURN(DXS_statusRingCadStartNotConf); |
| } |
| |
| ret = DXS_SDD_LineModeGet(pCh, &opmode); |
| if (ret == DXS_statusOk && opmode == DXS_LINE_FEED_ACTIVE_REVPOL) |
| pRes->polarity = RING_POLARITY_REVERSE; |
| |
| if (ret == DXS_statusOk) |
| { |
| pRes->current_bit = 0; |
| pRes->ring_cadence_state = dxs_ring_cad_initial_state(pCh); |
| pRes->ringer_state = RINGER_STATE_PAUSE; |
| pRes->wait_counter = 0; |
| if (pRes->pCh->pParent->dcdcType == DXS_DCDC_IFB12CH8 && |
| pRes->ring_cadence_state == RING_CAD_STATE_CID_PRIOR_TO_RINGING) |
| { |
| int32_t next_ring_bit_pos, cid_len_bits, ring_pulse=0; |
| |
| DXS_CID_LengthBitsGet(pCh, &cid_len_bits); |
| if (cid_len_bits > 0) |
| { |
| /* set the wait_counter */ |
| do |
| { |
| next_ring_bit_pos = dxs_ring_next_pos_get(pRes, ring_pulse++); |
| pRes->wait_counter = next_ring_bit_pos - cid_len_bits; |
| } while (pRes->wait_counter < 0); |
| } |
| else |
| { |
| /* zero or negative CID length means no CID */ |
| pRes->ring_cadence_state = RING_CAD_STATE_RINGING; |
| } |
| } |
| ret = ring_timer_start(); |
| } |
| DXS_RETURN(ret); |
| } |
| |
| /** |
| Stop ringing cadence |
| |
| \param pCh - pointer to DXS channel structure |
| \return |
| DXS_statusOk |
| */ |
| int32_t DXS_RING_CadenceStop (DXS_CHANNEL_t *pCh) |
| { |
| int32_t ret = DXS_statusOk; |
| dxs_ring_res_t *pRes = (dxs_ring_res_t *)pCh->ring; |
| |
| if (pRes->ringer_state == RINGER_STATE_RINGING) |
| { |
| ret = dxs_ring_pulse_stop(pRes); |
| } |
| |
| if (pRes->ring_cadence_state == RING_CAD_STATE_CID_DURING_RINGING || |
| pRes->ring_cadence_state == RING_CAD_STATE_CID_PRIOR_TO_RINGING) |
| { |
| DXS_CID_Stop(pCh); |
| } |
| |
| if (ret == DXS_statusOk) |
| { |
| pRes->ring_cadence_state = RING_CAD_STATE_IDLE; |
| ring_timer_stop(); |
| } |
| DXS_RETURN(ret); |
| } |