| /****************************************************************************** |
| |
| 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_sig.c |
| Implementation of signalling channel functions. |
| */ |
| |
| /* ========================================================================== */ |
| /* Includes */ |
| /* ========================================================================== */ |
| #include "dxs.h" |
| #include "dxs_config.h" |
| #include "dxs_lib.h" |
| #include "dxs_fw_cmd.h" |
| #include "dxs_errno.h" |
| #include "dxs_error.h" |
| #include "dxs_misc.h" |
| #include "dxs_init.h" |
| #include "dxs_access.h" |
| #include "dxs_sdd.h" |
| |
| /* ========================================================================== */ |
| /* Macro definitions */ |
| /* ========================================================================== */ |
| /** Maximum number of CID data bytes sent via one message */ |
| #define DXS_CID_GEN_DATA_MAX 27 |
| #define DXS_CID_V23_BEL202 0 |
| #define DXS_CID_V23_ITU_T 1 |
| #define DXS_CID_AUTODEACT_OFF 0 |
| #define DXS_CID_AUTODEACT_ON 1 |
| #define DXS_CID_HLEV_HIGH 1 |
| #define DXS_CID_MAX_SEIZURE 32767 |
| #define DXS_CID_MAX_MARK 32767 |
| #define DXS_CID_MAX_LEVEL 31 |
| #define DXS_CID_MIN_LEVEL -929 |
| |
| /** Maximum number of tones in UTD table */ |
| #define UTD_COEF_TABLE_MAX 5 |
| |
| /* ========================================================================== */ |
| /* Type definitions */ |
| /* ========================================================================== */ |
| /** Data structure for DTMF receiver coefficients firmware command */ |
| typedef struct |
| { |
| #if __BYTE_ORDER == __BIG_ENDIAN |
| CMD_HEAD_BE; |
| /** Minimum Signal Level */ |
| uint32_t LEVEL : 16; |
| /** Maximal Allowed Signal Twist */ |
| uint32_t TWIST : 16; |
| #else |
| CMD_HEAD_LE; |
| /** Maximal Allowed Signal Twist */ |
| uint32_t TWIST : 16; |
| /** Minimum Signal Level */ |
| uint32_t LEVEL : 16; |
| #endif |
| } __attribute__ ((packed)) DXS_FW_DTMF_RecCoeff_t; |
| #define DXS_FW_DTMF_RecCoeff_ECMD 12 |
| #define DXS_FW_DTMF_RecCoeff_LENGTH 4 |
| |
| /** Data structure for DTMF receiver control firmware command */ |
| typedef struct |
| { |
| #if __BYTE_ORDER == __BIG_ENDIAN |
| CMD_HEAD_BE; |
| /** Enable */ |
| uint32_t EN : 1; |
| /** Reserved */ |
| uint32_t Res02 : 31; |
| #else |
| CMD_HEAD_LE; |
| /** Reserved */ |
| uint32_t Res02 : 31; |
| /** Enable */ |
| uint32_t EN : 1; |
| #endif |
| } __attribute__ ((packed)) DXS_FW_DTMF_RecCtrl_t; |
| #define DXS_FW_DTMF_RecCtrl_ECMD 4 |
| #define DXS_FW_DTMF_RecCtrl_LENGTH 4 |
| |
| /** Data structure for DTMF generator coefficients firmware command */ |
| typedef struct |
| { |
| #if __BYTE_ORDER == __BIG_ENDIAN |
| CMD_HEAD_BE; |
| /** Level for Frequency 1 (Lower Frequency) */ |
| uint32_t LEVEL1 : 16; |
| /** Level for Frequency 2 (Higher Frequency) */ |
| uint32_t LEVEL2 : 16; |
| /** Frequency 1 of Tone */ |
| uint32_t FREQ1 : 16; |
| /** Frequency 2 of Tone */ |
| uint32_t FREQ2 : 16; |
| #else |
| CMD_HEAD_LE; |
| /** Level for Frequency 2 (Higher Frequency) */ |
| uint32_t LEVEL2 : 16; |
| /** Level for Frequency 1 (Lower Frequency) */ |
| uint32_t LEVEL1 : 16; |
| /** Frequency 2 of Tone */ |
| uint32_t FREQ2 : 16; |
| /** Frequency 1 of Tone */ |
| uint32_t FREQ1 : 16; |
| #endif |
| } __attribute__ ((packed)) DXS_FW_DTMF_AT_GenCoeff_t; |
| #define DXS_FW_DTMF_AT_GenCoeff_ECMD 10 |
| #define DXS_FW_DTMF_AT_GenCoeff_LENGTH 8 |
| |
| /** Data structure for DTMF generator control firmware command */ |
| typedef struct |
| { |
| #if __BYTE_ORDER == __BIG_ENDIAN |
| CMD_HEAD_BE; |
| /** Status of DTMF/AT Generator */ |
| uint32_t EN : 1; |
| /** Reserved */ |
| uint32_t Res02 : 14; |
| /** Amplitude Modulation */ |
| uint32_t AM : 1; |
| /** Reserved */ |
| uint32_t Res03 : 16; |
| #else |
| CMD_HEAD_LE; |
| /** Reserved */ |
| uint32_t Res03 : 16; |
| /** Amplitude Modulation */ |
| uint32_t AM : 1; |
| /** Reserved */ |
| uint32_t Res02 : 14; |
| /** Status of DTMF/AT Generator */ |
| uint32_t EN : 1; |
| #endif |
| } __attribute__ ((packed)) DXS_FW_DTMF_AT_GenCtrl_t; |
| #define DXS_FW_DTMF_AT_GenCtrl_ECMD 3 |
| #define DXS_FW_DTMF_AT_GenCtrl_LENGTH 4 |
| |
| /** Data structure for FSK generator control firmware command */ |
| typedef struct |
| { |
| #if __BYTE_ORDER == __BIG_ENDIAN |
| CMD_HEAD_BE; |
| /** Status of CID sender */ |
| uint32_t EN : 1; |
| /** Reserved */ |
| uint32_t Res02 : 1; |
| /** Auto Deactivation */ |
| uint32_t AD : 1; |
| /** High Level CID Generation Mode */ |
| uint32_t HLEV : 1; |
| /** CID Specification */ |
| uint32_t V23 : 1; |
| /** Reserved */ |
| uint32_t Res03 : 27; |
| #else |
| CMD_HEAD_LE; |
| /** Reserved */ |
| uint32_t Res02 : 27; |
| /** CID Specification */ |
| uint32_t V23 : 1; |
| /** High Level CID Generation Mode */ |
| uint32_t HLEV : 1; |
| /** Auto Deactivation */ |
| uint32_t AD : 1; |
| /** Reserved */ |
| uint32_t Res03 : 1; |
| /** Status of CID sender */ |
| uint32_t EN : 1; |
| #endif |
| } __attribute__ ((packed)) DXS_FW_FSK_GenCtrl_t; |
| #define DXS_FW_FSK_GenCtrl_ECMD 2 |
| #define DXS_FW_FSK_GenCtrl_LENGTH 4 |
| |
| /** Data structure for FSK generator coefficients firmware command */ |
| typedef struct |
| { |
| #if __BYTE_ORDER == __BIG_ENDIAN |
| CMD_HEAD_BE; |
| /** CID Send Level */ |
| uint32_t LEVEL : 16; |
| /** Number of Seizure Bits */ |
| uint32_t SEIZURE : 16; |
| /** Number of Mark Bits */ |
| uint32_t MARK : 16; |
| /** Reserved */ |
| uint32_t Res02 : 16; |
| #else |
| CMD_HEAD_LE; |
| /** Number of Seizure Bits */ |
| uint32_t SEIZURE : 16; |
| /** CID Send Level */ |
| uint32_t LEVEL : 16; |
| /** Reserved */ |
| uint32_t Res02 : 16; |
| /** Number of Mark Bits */ |
| uint32_t MARK : 16; |
| |
| #endif |
| } __attribute__ ((packed)) DXS_FW_FSK_GenCoeff_t; |
| #define DXS_FW_FSK_GenCoeff_ECMD 8 |
| #define DXS_FW_FSK_GenCoeff_LENGTH 8 |
| |
| /** Data structure for FSK generator data firmware command */ |
| typedef struct |
| { |
| #if __BYTE_ORDER == __BIG_ENDIAN |
| CMD_HEAD_BE; |
| /** Number of Data Bytes following */ |
| uint32_t NRDATA : 8; |
| /** Data Byte 0 */ |
| uint32_t DATA0 : 8; |
| /** Data Byte 1 */ |
| uint32_t DATA1 : 8; |
| /** Data Byte 2 */ |
| uint32_t DATA2 : 8; |
| #else |
| CMD_HEAD_LE; |
| /** Data Byte 2 */ |
| uint32_t DATA2 : 8; |
| /** Data Byte 1 */ |
| uint32_t DATA1 : 8; |
| /** Data Byte 0 */ |
| uint32_t DATA0 : 8; |
| /** Number of Data Bytes following */ |
| uint32_t NRDATA : 8; |
| #endif |
| /** Data Bytes 3-26 */ |
| uint32_t DATA[DXS_CID_GEN_DATA_MAX >> 2]; |
| } __attribute__ ((packed)) DXS_FW_FSK_GenData_t; |
| #define DXS_FW_FSK_GenData_ECMD 9 |
| #define DXS_FW_FSK_GenData_LENGTH 28 |
| |
| /** Data structure for metering pulse control firmware command */ |
| typedef struct |
| { |
| #if __BYTE_ORDER == __BIG_ENDIAN |
| CMD_HEAD_BE; |
| /** Bit to start or stop the metering pulse */ |
| uint32_t EN : 1; |
| /** Reserved */ |
| uint32_t Res02 : 31; |
| #else |
| CMD_HEAD_LE; |
| /** Reserved */ |
| uint32_t Res02 : 31; |
| /** Bit to start or stop the metering pulse */ |
| uint32_t EN : 1; |
| #endif |
| } __attribute__ ((packed)) DXS_FW_MeterPulseCtrl_t; |
| #define DXS_FW_MeterPulseCtrl_ECMD 4 |
| #define DXS_FW_MeterPulseCtrl_LENGTH 4 |
| |
| /** Data structure for UTD coefficients firmware command */ |
| typedef struct |
| { |
| struct DXS_FW_Cmd_Header hdr; |
| struct DXS_FW_SIG_UtdCoeff content; |
| } __attribute__ ((packed)) DXS_FW_SIG_UtdCoeff_t; |
| #define DXS_FW_SIG_UtdCoeff_ECMD 18 |
| #define DXS_FW_SIG_UtdCoeff_LENGTH 16 |
| |
| /** Data structure for UTD control firmware command */ |
| typedef struct |
| { |
| #if __BYTE_ORDER == __BIG_ENDIAN |
| CMD_HEAD_BE; |
| /** Bit to enable or disable universal tone detector */ |
| uint32_t EN : 1; |
| /** Reserved */ |
| uint32_t Res02 : 14; |
| /** With this bit the UTD direction can be configured */ |
| uint32_t DIR : 1; |
| /** Reserved */ |
| uint32_t Res03 : 16; |
| #else |
| CMD_HEAD_LE; |
| /** Reserved */ |
| uint32_t Res03 : 16; |
| /** With this bit the UTD direction can be configured */ |
| uint32_t DIR : 1; |
| /** Reserved */ |
| uint32_t Res02 : 14; |
| /** Bit to enable or disable universal tone detector */ |
| uint32_t EN : 1; |
| #endif |
| } __attribute__ ((packed)) DXS_FW_SIG_UtdCtrl_t; |
| #define DXS_FW_SIG_UtdCtrl_ECMD 17 |
| #define DXS_FW_SIG_UtdCtrl_LENGTH 4 |
| |
| /** Data structure for signalling channel resource */ |
| typedef struct |
| { |
| /** status flag */ |
| uint32_t flag; |
| #define SIG_CH_INITIALIZED 0x00000001 |
| |
| #ifdef DXS_FEAT_DTMFD |
| /** DTMF Receiver Coefficients */ |
| DXS_FW_DTMF_RecCoeff_t dtmf_rec_coef; |
| /** DTMF Receiver Control */ |
| DXS_FW_DTMF_RecCtrl_t dtmf_rec_ctrl; |
| #endif /* DXS_FEAT_DTMFD */ |
| |
| #ifdef DXS_FEAT_TG |
| /** DTMF and AT Generator Coefficients */ |
| DXS_FW_DTMF_AT_GenCoeff_t dtmf_at_gen_coef; |
| /** DTMF and AT Generator Control */ |
| DXS_FW_DTMF_AT_GenCtrl_t dtmf_at_gen_ctrl; |
| #endif /* DXS_FEAT_TG */ |
| |
| #ifdef DXS_FEAT_FSK |
| /** Caller ID Control */ |
| DXS_FW_FSK_GenCtrl_t fsk_ctrl; |
| /** Caller ID Coefficients */ |
| DXS_FW_FSK_GenCoeff_t fsk_coef; |
| /** Caller ID Data */ |
| DXS_FW_FSK_GenData_t fsk_data; |
| #endif /* DXS_FEAT_FSK */ |
| |
| #ifdef DXS_FEAT_METERING |
| /** Metering pulse current status */ |
| uint8_t bMeterPulse; |
| /** Metering Pulse Control */ |
| DXS_FW_MeterPulseCtrl_t meter_ctrl; |
| #endif /* DXS_FEAT_METERING */ |
| |
| #ifdef DXS_FEAT_UTD |
| /** UTD Control */ |
| DXS_FW_SIG_UtdCtrl_t utd_ctrl; |
| /** UTD coefficients */ |
| DXS_FW_SIG_UtdCoeff_t utd_coeff; |
| /** Tone index of last active UTD */ |
| uint16_t utd_tone_idx; |
| #endif /* DXS_FEAT_UTD */ |
| |
| } DXS_SIG_Ch_Resource_t; |
| |
| /* ========================================================================== */ |
| /* Global variables */ |
| /* ========================================================================== */ |
| static DXS_SIG_Ch_Resource_t sig_chan[DXS_MAX_DEVICES * CH_PER_DEVICE] = {0}; |
| |
| static uint16_t dBm0_level_tbl[] = { |
| /* 0.0 dBm0 */ 0x592a, |
| /* 0.1 dBm0 */ 0x5a32, |
| /* 0.2 dBm0 */ 0x5b3e, |
| /* 0.3 dBm0 */ 0x5c4c, |
| /* 0.4 dBm0 */ 0x5d5e, |
| /* 0.5 dBm0 */ 0x5e73, |
| /* 0.6 dBm0 */ 0x5f8b, |
| /* 0.7 dBm0 */ 0x60a6, |
| /* 0.8 dBm0 */ 0x61c4, |
| /* 0.9 dBm0 */ 0x62e6, |
| /* 1.0 dBm0 */ 0x640b, |
| /* 1.1 dBm0 */ 0x6534, |
| /* 1.2 dBm0 */ 0x6660, |
| /* 1.3 dBm0 */ 0x678f, |
| /* 1.4 dBm0 */ 0x68c2, |
| /* 1.5 dBm0 */ 0x69f9, |
| /* 1.6 dBm0 */ 0x6b33, |
| /* 1.7 dBm0 */ 0x6c71, |
| /* 1.8 dBm0 */ 0x6db2, |
| /* 1.9 dBm0 */ 0x6ef7, |
| /* 2.0 dBm0 */ 0x7040, |
| /* 2.1 dBm0 */ 0x718d, |
| /* 2.2 dBm0 */ 0x72de, |
| /* 2.3 dBm0 */ 0x7432, |
| /* 2.4 dBm0 */ 0x758b, |
| /* 2.5 dBm0 */ 0x76e7, |
| /* 2.6 dBm0 */ 0x7847, |
| /* 2.7 dBm0 */ 0x79ac, |
| /* 2.8 dBm0 */ 0x7b15, |
| /* 2.9 dBm0 */ 0x7c82, |
| /* 3.0 dBm0 */ 0x7df3, |
| /* 3.1 dBm0 */ 0x7f68 |
| }; |
| |
| #ifdef DXS_FEAT_UTD |
| static uint32_t uiUtdMtxInit = 0; |
| static pthread_mutex_t utd_tone_mtx; |
| static uint8_t UtdTonesNum = 0; |
| static struct DXS_SIG_UtdCoefEntry |
| { |
| uint16_t unToneIdx; |
| struct DXS_FW_SIG_UtdCoeff coef_data; |
| } utd_coef_tbl[UTD_COEF_TABLE_MAX] = {0}; |
| #endif /* DXS_FEAT_UTD */ |
| |
| /* ========================================================================== */ |
| /* Function prototypes */ |
| /* ========================================================================== */ |
| |
| /* ========================================================================== */ |
| /* Function implementation */ |
| /* ========================================================================== */ |
| |
| /** |
| Function dxs_sig_ch_init |
| |
| \param dev - device number |
| \param ch - channel number |
| \param nBytes - size of the buffer |
| |
| */ |
| void *dxs_sig_ch_init(uint8_t dev, uint8_t ch) |
| { |
| DXS_SIG_Ch_Resource_t *p; |
| |
| if (dev >= DXS_MAX_DEVICES || ch >= CH_PER_DEVICE) |
| return (void *)NULL; |
| |
| p = &sig_chan[dev * CH_PER_DEVICE + ch]; |
| |
| p->flag = 0; |
| |
| #ifdef DXS_FEAT_DTMFD |
| p->dtmf_rec_coef.CMD = CMD_EOP; |
| p->dtmf_rec_coef.MOD = MOD_SIG_DET; |
| p->dtmf_rec_coef.ECMD = DXS_FW_DTMF_RecCoeff_ECMD; |
| p->dtmf_rec_coef.LENGTH = DXS_FW_DTMF_RecCoeff_LENGTH; |
| p->dtmf_rec_coef.CHAN = ch; |
| |
| p->dtmf_rec_ctrl.CMD = CMD_EOP; |
| p->dtmf_rec_ctrl.MOD = MOD_SIG_DET; |
| p->dtmf_rec_ctrl.ECMD = DXS_FW_DTMF_RecCtrl_ECMD; |
| p->dtmf_rec_ctrl.LENGTH = DXS_FW_DTMF_RecCtrl_LENGTH; |
| p->dtmf_rec_ctrl.CHAN = ch; |
| #endif /* DXS_FEAT_DTMFD */ |
| |
| #ifdef DXS_FEAT_TG |
| p->dtmf_at_gen_coef.CMD = CMD_EOP; |
| p->dtmf_at_gen_coef.MOD = MOD_SIG_GEN; |
| p->dtmf_at_gen_coef.ECMD = DXS_FW_DTMF_AT_GenCoeff_ECMD; |
| p->dtmf_at_gen_coef.LENGTH = DXS_FW_DTMF_AT_GenCoeff_LENGTH; |
| p->dtmf_at_gen_coef.CHAN = ch; |
| |
| p->dtmf_at_gen_ctrl.CMD = CMD_EOP; |
| p->dtmf_at_gen_ctrl.MOD = MOD_SIG_GEN; |
| p->dtmf_at_gen_ctrl.ECMD = DXS_FW_DTMF_AT_GenCtrl_ECMD; |
| p->dtmf_at_gen_ctrl.LENGTH = DXS_FW_DTMF_AT_GenCtrl_LENGTH; |
| p->dtmf_at_gen_ctrl.CHAN = ch; |
| #endif /* DXS_FEAT_TG */ |
| |
| #ifdef DXS_FEAT_FSK |
| p->fsk_ctrl.CMD = CMD_EOP; |
| p->fsk_ctrl.MOD = MOD_SIG_GEN; |
| p->fsk_ctrl.ECMD = DXS_FW_FSK_GenCtrl_ECMD; |
| p->fsk_ctrl.LENGTH = DXS_FW_FSK_GenCtrl_LENGTH; |
| p->fsk_ctrl.CHAN = ch; |
| /* Only high level is supported. */ |
| p->fsk_ctrl.HLEV = DXS_CID_HLEV_HIGH; |
| |
| p->fsk_coef.CMD = CMD_EOP; |
| p->fsk_coef.MOD = MOD_SIG_GEN; |
| p->fsk_coef.ECMD = DXS_FW_FSK_GenCoeff_ECMD; |
| p->fsk_coef.LENGTH = DXS_FW_FSK_GenCoeff_LENGTH; |
| p->fsk_coef.CHAN = ch; |
| |
| p->fsk_data.CMD = CMD_EOP; |
| p->fsk_data.MOD = MOD_SIG_GEN; |
| p->fsk_data.ECMD = DXS_FW_FSK_GenData_ECMD; |
| p->fsk_data.LENGTH = DXS_FW_FSK_GenData_LENGTH; |
| p->fsk_data.CHAN = ch; |
| #endif /* DXS_FEAT_FSK */ |
| |
| #ifdef DXS_FEAT_METERING |
| p->bMeterPulse = 0; |
| p->meter_ctrl.CMD = CMD_EOP; |
| p->meter_ctrl.MOD = MOD_SIG_GEN; |
| p->meter_ctrl.ECMD = DXS_FW_MeterPulseCtrl_ECMD; |
| p->meter_ctrl.LENGTH = DXS_FW_MeterPulseCtrl_LENGTH; |
| p->meter_ctrl.CHAN = ch; |
| #endif /* DXS_FEAT_METERING */ |
| |
| #ifdef DXS_FEAT_UTD |
| p->utd_tone_idx = 0; |
| |
| p->utd_coeff.hdr.CMD = CMD_EOP; |
| p->utd_coeff.hdr.MOD = MOD_SIG_DET; |
| p->utd_coeff.hdr.ECMD = DXS_FW_SIG_UtdCoeff_ECMD; |
| p->utd_coeff.hdr.LENGTH = DXS_FW_SIG_UtdCoeff_LENGTH; |
| p->utd_coeff.hdr.CHAN = ch; |
| |
| p->utd_ctrl.CMD = CMD_EOP; |
| p->utd_ctrl.MOD = MOD_SIG_DET; |
| p->utd_ctrl.ECMD = DXS_FW_SIG_UtdCtrl_ECMD; |
| p->utd_ctrl.LENGTH = DXS_FW_SIG_UtdCtrl_LENGTH; |
| p->utd_ctrl.CHAN = ch; |
| #endif /* DXS_FEAT_UTD */ |
| |
| p->flag |= SIG_CH_INITIALIZED; |
| |
| return (void *)p; |
| } |
| |
| #ifdef DXS_FEAT_UTD |
| /** |
| Function to initialize UTD mutex |
| |
| */ |
| void dxs_sig_utd_mtx_init() |
| { |
| if (!uiUtdMtxInit) |
| pthread_mutex_init(&utd_tone_mtx, NULL); |
| |
| uiUtdMtxInit++; |
| } |
| |
| /** |
| Function to destroy UTD mutex and reset UTD tone table |
| |
| */ |
| void dxs_sig_utd_mtx_destroy() |
| { |
| int err; |
| if (uiUtdMtxInit) |
| uiUtdMtxInit--; |
| |
| if (!uiUtdMtxInit) |
| { |
| err = pthread_mutex_unlock(&utd_tone_mtx); |
| if (err != 0) |
| DXS_ERROR_PUSH(err); |
| err = pthread_mutex_destroy(&utd_tone_mtx); |
| if (err != 0) |
| DXS_ERROR_PUSH(err); |
| UtdTonesNum = 0; |
| } |
| } |
| #endif /* DXS_FEAT_UTD */ |
| |
| #ifdef DXS_FEAT_DTMFD |
| |
| /* ============================ DTMF Detection ============================== */ |
| |
| #define DXS_SIG_DTMF_LEVEL_MIN (-369) /* in units of 0.1 dBm0 */ |
| #define DXS_SIG_DTMF_LEVEL_MAX (-29) /* in units of 0.1 dBm0 */ |
| |
| #define DXS_SIG_DTMF_TWIST_MIN 10 /* in units of 0.1 dB */ |
| #define DXS_SIG_DTMF_TWIST_MAX 120 /* in units of 0.1 dB */ |
| |
| /** |
| Function dxs_dtmf_config |
| |
| \param pCh - pointer to DXS channel structure |
| \param level - minimum signal level |
| \param twist - maximum allowed twist |
| |
| \return |
| - DXS_status_t |
| */ |
| int32_t dxs_dtmf_config(DXS_CHANNEL_t *pCh, int16_t level, int16_t twist) |
| { |
| DXS_SIG_Ch_Resource_t *p; |
| uint16_t new_LEVEL, new_TWIST; |
| int32_t ret = DXS_statusOk; |
| |
| if (pCh == NULL) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| p = (DXS_SIG_Ch_Resource_t *)pCh->sig; |
| |
| if (!(p->flag & SIG_CH_INITIALIZED)) |
| { |
| DXS_RETURN(DXS_statusNotInitResource); |
| } |
| |
| if (level < DXS_SIG_DTMF_LEVEL_MIN || level > DXS_SIG_DTMF_LEVEL_MAX) |
| { |
| DXS_RETURN(DXS_statusParamsOutRange); |
| } |
| |
| if (twist < DXS_SIG_DTMF_TWIST_MIN || twist > DXS_SIG_DTMF_TWIST_MAX) |
| { |
| DXS_RETURN(DXS_statusParamsOutRange); |
| } |
| |
| /* calculate new values */ |
| new_LEVEL = DXS_Misc_MulQ15(DXS_Misc_PowerdB_to_Factor(level), 14173); |
| new_TWIST = DXS_Misc_MulQ15(DXS_Misc_PowerdB_to_Factor(-twist), 29205); |
| |
| if (new_LEVEL != p->dtmf_rec_coef.LEVEL || |
| new_TWIST != p->dtmf_rec_coef.TWIST) |
| { |
| /* write new values */ |
| p->dtmf_rec_coef.LEVEL = new_LEVEL; |
| p->dtmf_rec_coef.TWIST = new_TWIST; |
| ret = CmdWrite(pCh->pParent, (uint32_t *)&p->dtmf_rec_coef); |
| } |
| |
| return ret; |
| } |
| |
| /** |
| Function dxs_dtmf_enable |
| |
| \param pCh - pointer to DXS channel structure |
| \param action - action enable/disable |
| |
| \return |
| - DXS_status_t |
| */ |
| int32_t dxs_dtmf_enable(DXS_CHANNEL_t *pCh, uint8_t action) |
| { |
| DXS_SIG_Ch_Resource_t *p; |
| int32_t ret = DXS_statusOk; |
| |
| if (pCh == NULL) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| p = (DXS_SIG_Ch_Resource_t *)pCh->sig; |
| |
| if (!(p->flag & SIG_CH_INITIALIZED)) |
| { |
| DXS_RETURN(DXS_statusNotInitResource); |
| } |
| |
| if (p->dtmf_rec_ctrl.EN != action) |
| { |
| p->dtmf_rec_ctrl.EN = action; |
| ret = CmdWrite(pCh->pParent, (uint32_t *)&p->dtmf_rec_ctrl); |
| } |
| |
| return ret; |
| } |
| |
| #endif /* DXS_FEAT_DTMFD */ |
| |
| #ifdef DXS_FEAT_TG |
| |
| #define TG_LEVEL_MIN (-869) /* in units of 0.1 dBm0 */ |
| #define TG_LEVEL_MIN_API (-169) /* in units of 0.1 dBm0 */ |
| #define TG_LEVEL_MAX 31 /* in units of 0.1 dBm0 */ |
| |
| #define TG_FREQ_MAX 4000 /* Hz */ |
| |
| /** |
| Function dxs_tone_config |
| |
| \param pCh - pointer to DXS channel structure |
| \param level1 - level for frequency 1 |
| \param level2 - level for frequency 2 |
| \param freq1 - tone frequency 1 |
| \param freq2 - tone frequency 2 |
| \param am - amplitude modulation flag |
| |
| \return |
| - DXS_status_t |
| */ |
| int32_t dxs_tone_config(DXS_CHANNEL_t *pCh, |
| int16_t level1, int16_t level2, uint16_t freq1, |
| uint16_t freq2, uint8_t am, uint8_t called_from_api) |
| { |
| DXS_SIG_Ch_Resource_t *p; |
| uint16_t new_level1, new_level2, new_freq1, new_freq2; |
| unsigned long temp; |
| int32_t ret = DXS_statusOk; |
| int16_t tg_level_min = (called_from_api == 0) ? TG_LEVEL_MIN : TG_LEVEL_MIN_API; |
| |
| if (pCh == NULL) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| p = (DXS_SIG_Ch_Resource_t *)pCh->sig; |
| |
| if (!(p->flag & SIG_CH_INITIALIZED)) |
| { |
| DXS_RETURN(DXS_statusNotInitResource); |
| } |
| |
| if (level1 < tg_level_min || level1 > TG_LEVEL_MAX) |
| { |
| DXS_RETURN(DXS_statusParamsOutRange); |
| } |
| if (level2 < tg_level_min || level2 > TG_LEVEL_MAX) |
| { |
| DXS_RETURN(DXS_statusParamsOutRange); |
| } |
| if (freq1 >= TG_FREQ_MAX || freq2 >= TG_FREQ_MAX) |
| { |
| DXS_RETURN(DXS_statusParamsOutRange); |
| } |
| if (am > 1) |
| { |
| DXS_RETURN(DXS_statusParamsOutRange); |
| } |
| |
| /* calculate new values */ |
| if (level1 >= 0) |
| { |
| new_level1 = dBm0_level_tbl[level1]; |
| } |
| else |
| { |
| new_level1 = DXS_Misc_MulQ15(22826, DXS_Misc_LeveldB_to_Factor(level1)); |
| } |
| |
| if (level2 >= 0) |
| { |
| new_level2 = dBm0_level_tbl[level2]; |
| } |
| else |
| { |
| new_level2 = DXS_Misc_MulQ15(22826, DXS_Misc_LeveldB_to_Factor(level2)); |
| } |
| |
| temp = 8192 * (unsigned long)freq1 / 1000; |
| new_freq1 = (uint16_t)temp; |
| temp = 8192 * (unsigned long)freq2 / 1000; |
| new_freq2 = (uint16_t)temp; |
| |
| if (new_level1 != p->dtmf_at_gen_coef.LEVEL1 || |
| new_level2 != p->dtmf_at_gen_coef.LEVEL2 || |
| new_freq1 != p->dtmf_at_gen_coef.FREQ1 || |
| new_freq2 != p->dtmf_at_gen_coef.FREQ2) |
| { |
| /* write new values */ |
| p->dtmf_at_gen_coef.LEVEL1 = new_level1; |
| p->dtmf_at_gen_coef.LEVEL2 = new_level2; |
| p->dtmf_at_gen_coef.FREQ1 = new_freq1; |
| p->dtmf_at_gen_coef.FREQ2 = new_freq2; |
| ret = CmdWrite(pCh->pParent, (uint32_t *)&p->dtmf_at_gen_coef); |
| } |
| |
| if (ret == DXS_statusOk) |
| { |
| p->dtmf_at_gen_ctrl.AM = am; |
| } |
| |
| return ret; |
| } |
| |
| /** |
| Function dxs_tone_start |
| |
| \param pCh - pointer to DXS channel structure |
| |
| \return |
| - DXS_status_t |
| */ |
| int32_t dxs_tone_start(DXS_CHANNEL_t *pCh) |
| { |
| DXS_SIG_Ch_Resource_t *p; |
| |
| if (pCh == NULL) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| p = (DXS_SIG_Ch_Resource_t *)pCh->sig; |
| |
| if (!(p->flag & SIG_CH_INITIALIZED)) |
| { |
| DXS_RETURN(DXS_statusNotInitResource); |
| } |
| |
| if (p->dtmf_at_gen_ctrl.EN == 1) |
| { |
| /* parameters aren't changed */ |
| return DXS_statusOk; |
| } |
| |
| /* AM field is already set by dxs_tone_config() */ |
| |
| p->dtmf_at_gen_ctrl.EN = 1; |
| |
| return CmdWrite(pCh->pParent, (uint32_t *)&p->dtmf_at_gen_ctrl); |
| } |
| |
| /** |
| Function dxs_tone_stop |
| |
| \param pCh - pointer to DXS channel structure |
| |
| \return |
| - DXS_status_t |
| */ |
| int32_t dxs_tone_stop(DXS_CHANNEL_t *pCh) |
| { |
| DXS_SIG_Ch_Resource_t *p; |
| |
| if (pCh == NULL) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| p = (DXS_SIG_Ch_Resource_t *)pCh->sig; |
| |
| if (!(p->flag & SIG_CH_INITIALIZED)) |
| { |
| DXS_RETURN(DXS_statusNotInitResource); |
| } |
| |
| if (p->dtmf_at_gen_ctrl.EN == 0) |
| { |
| /* parameters aren't changed */ |
| return DXS_statusOk; |
| } |
| |
| p->dtmf_at_gen_ctrl.EN = 0; |
| |
| return CmdWrite(pCh->pParent, (uint32_t *)&p->dtmf_at_gen_ctrl); |
| } |
| #endif /* DXS_FEAT_TG */ |
| |
| |
| #ifdef DXS_FEAT_UTD |
| |
| /** |
| Get current tone index |
| |
| \param pCh - pointer to DXS channel structure |
| |
| \return |
| - tone index, uint8_t |
| */ |
| uint8_t DXS_UTD_ToneIdxGet(DXS_CHANNEL_t *pCh) |
| { |
| DXS_SIG_Ch_Resource_t *p; |
| |
| if (pCh == NULL) |
| { |
| return 0; |
| } |
| p = (DXS_SIG_Ch_Resource_t *)pCh->sig; |
| |
| return (uint8_t) p->utd_tone_idx; |
| } |
| |
| #endif /* DXS_FEAT_UTD */ |
| |
| #ifdef DXS_FEAT_METERING |
| /** |
| Function to enable metering pulse |
| |
| \param pCh - pointer to DXS channel structure |
| |
| \return |
| - DXS_status_t |
| */ |
| int32_t DXS_SIG_MeterPulseEnable(DXS_CHANNEL_t *pCh) |
| { |
| int32_t err = DXS_statusOk; |
| DXS_SIG_Ch_Resource_t *p; |
| int line_mode; |
| |
| if (pCh == NULL) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| p = (DXS_SIG_Ch_Resource_t *)pCh->sig; |
| |
| if (!(p->flag & SIG_CH_INITIALIZED)) |
| { |
| DXS_RETURN(DXS_statusNotInitResource); |
| } |
| |
| /* check if TTX feature is supported */ |
| if (!DXS_IsFeatureSupported(pCh->pParent, dxs_cap_ttx)) |
| { |
| DXS_RETURN(DXS_statusFeatNotSupportedCaps); |
| } |
| |
| /* Verify that line mode is set to Active (normal or reversed) */ |
| line_mode = 0; |
| err = DXS_SDD_LineModeGet(pCh, &line_mode); |
| if (err != DXS_statusOk) |
| { |
| DXS_RETURN(err); |
| } |
| if ((line_mode != DXS_LINE_FEED_ACTIVE_REVPOL) && |
| (line_mode != DXS_LINE_FEED_ACTIVE)) |
| { |
| DXS_RETURN(DXS_statusMeteringLineModeNotActive); |
| } |
| |
| /* Check if metering pulse is already enabled */ |
| if (p->bMeterPulse) |
| { |
| DXS_RETURN(DXS_statusMeteringPreviousPulseNotFinished); |
| } |
| |
| /* Enable metering pulse */ |
| p->meter_ctrl.EN = 1; |
| err = CmdWrite(pCh->pParent, (uint32_t *)&p->meter_ctrl); |
| if (err == DXS_statusOk) |
| p->bMeterPulse = 1; |
| |
| DXS_RETURN(err); |
| } |
| |
| /** |
| Function to disable metering pulse |
| |
| \param pCh - pointer to DXS channel structure |
| |
| \return |
| - DXS_status_t |
| */ |
| int32_t DXS_SIG_MeterPulseDisable(DXS_CHANNEL_t *pCh) |
| { |
| int32_t err = DXS_statusOk; |
| DXS_SIG_Ch_Resource_t *p; |
| int line_mode; |
| |
| if (pCh == NULL) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| p = (DXS_SIG_Ch_Resource_t *)pCh->sig; |
| |
| if (!(p->flag & SIG_CH_INITIALIZED)) |
| { |
| DXS_RETURN(DXS_statusNotInitResource); |
| } |
| |
| /* check if TTX feature is supported */ |
| if (!DXS_IsFeatureSupported(pCh->pParent, dxs_cap_ttx)) |
| { |
| DXS_RETURN(DXS_statusFeatNotSupportedCaps); |
| } |
| |
| /* Verify that line mode is set to Active (normal or reversed) */ |
| line_mode = 0; |
| err = DXS_SDD_LineModeGet(pCh, &line_mode); |
| if (err != DXS_statusOk) |
| { |
| DXS_RETURN(err); |
| } |
| if ((line_mode != DXS_LINE_FEED_ACTIVE_REVPOL) && |
| (line_mode != DXS_LINE_FEED_ACTIVE)) |
| { |
| /* If line mode is not active then meterig pulse should be disabled already, |
| therefore success can be returned without cmd_read and cmd_write */ |
| DXS_RETURN(err); |
| } |
| |
| /* Disable metering pulse if it is enabled */ |
| if (p->bMeterPulse) |
| { |
| p->meter_ctrl.EN = 0; |
| err = CmdWrite(pCh->pParent, (uint32_t *)&p->meter_ctrl); |
| if (err == DXS_statusOk) |
| p->bMeterPulse = 0; |
| } |
| |
| DXS_RETURN(err); |
| } |
| |
| /** |
| Function to clear metering pulse status |
| |
| \param pCh - pointer to DXS channel structure |
| |
| \return |
| - DXS_statusOk or DXS_statusInvalidParam |
| */ |
| int32_t obx_DXS_SIG_MeterPulseStatusClear(DXS_CHANNEL_t *pCh) |
| { |
| int32_t err = DXS_statusOk; |
| DXS_SIG_Ch_Resource_t *p; |
| |
| if (pCh == NULL) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| p = (DXS_SIG_Ch_Resource_t *)pCh->sig; |
| |
| p->bMeterPulse = 0; |
| |
| DXS_RETURN(err); |
| } |
| #endif /* DXS_FEAT_METERING */ |
| |
| #ifdef DXS_FEAT_FSK |
| /** |
| CID Generator Coefficients update |
| |
| \param pCh - pointer to DXS channel structure |
| \param level - FSK send level |
| \param seizure - number of seizure bytes |
| \param mark - number of mark bits |
| |
| \return |
| - DXS_status_t |
| */ |
| int32_t DXS_FSK_Configure(DXS_CHANNEL_t *pCh, int16_t level, uint16_t seizure, |
| uint16_t mark) |
| { |
| DXS_SIG_Ch_Resource_t *p; |
| |
| if (pCh == NULL) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| p = (DXS_SIG_Ch_Resource_t *)pCh->sig; |
| |
| if (!(p->flag & SIG_CH_INITIALIZED)) |
| { |
| DXS_RETURN(DXS_statusNotInitResource); |
| } |
| |
| /* check if CID/FSK feature is supported */ |
| if (!DXS_IsFeatureSupported(pCh->pParent, dxs_cap_cid)) |
| { |
| DXS_RETURN(DXS_statusFeatNotSupportedCaps); |
| } |
| |
| if (seizure > DXS_CID_MAX_SEIZURE) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| |
| if (mark > DXS_CID_MAX_MARK) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| |
| if ((level < DXS_CID_MIN_LEVEL) || (level > DXS_CID_MAX_LEVEL)) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| |
| /* calculate new values */ |
| if (level >= 0) |
| { |
| p->fsk_coef.LEVEL = dBm0_level_tbl[level]; |
| } |
| else |
| { |
| p->fsk_coef.LEVEL = DXS_Misc_MulQ15(22826, DXS_Misc_LeveldB_to_Factor(level)); |
| } |
| |
| p->fsk_coef.SEIZURE = seizure; |
| p->fsk_coef.MARK = mark; |
| |
| return CmdWrite(pCh->pParent, (uint32_t *)&p->fsk_coef); |
| } |
| |
| /** |
| CID Generator Enable |
| |
| \param pCh - pointer to DXS channel structure |
| \param standard - CID standard |
| \param autodeact - auto deactivation |
| |
| \return |
| - DXS_status_t |
| */ |
| int32_t DXS_FSK_Enable(DXS_CHANNEL_t *pCh, uint8_t standard, uint8_t autodeact) |
| { |
| DXS_SIG_Ch_Resource_t *p; |
| |
| if (pCh == NULL) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| p = (DXS_SIG_Ch_Resource_t *)pCh->sig; |
| |
| if (!(p->flag & SIG_CH_INITIALIZED)) |
| { |
| DXS_RETURN(DXS_statusNotInitResource); |
| } |
| |
| /* check if CID/FSK feature is supported */ |
| if (!DXS_IsFeatureSupported(pCh->pParent, dxs_cap_cid)) |
| { |
| DXS_RETURN(DXS_statusFeatNotSupportedCaps); |
| } |
| |
| if ((standard != DXS_CID_V23_BEL202) && (standard != DXS_CID_V23_ITU_T)) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| |
| if ((autodeact != DXS_CID_AUTODEACT_ON) && |
| (autodeact != DXS_CID_AUTODEACT_OFF)) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| |
| /* The DTMF and the CID generator should not be enabled at the same time. */ |
| if (p->dtmf_at_gen_ctrl.EN == 1) |
| { |
| DXS_RETURN(DXS_statusFskEnableNotAllowed); |
| } |
| |
| /* CID Specification can only be changed if the EN bit is set to 0. */ |
| if ((p->fsk_ctrl.V23 != standard) && (p->fsk_ctrl.EN == 1)) |
| { |
| DXS_RETURN(DXS_statusFskStandardChangeNotAllowed); |
| } |
| |
| p->fsk_ctrl.EN = 1; |
| p->fsk_ctrl.AD = autodeact; |
| p->fsk_ctrl.V23 = standard; |
| |
| return CmdWrite(pCh->pParent, (uint32_t *)&p->fsk_ctrl); |
| } |
| |
| /** |
| CID Generator Disable |
| |
| \param pCh - pointer to DXS channel structure |
| \param autodeact - auto deactivation |
| |
| \return |
| - DXS_status_t |
| */ |
| int32_t DXS_FSK_Disable(DXS_CHANNEL_t *pCh, uint8_t autodeact) |
| { |
| DXS_SIG_Ch_Resource_t *p; |
| |
| if (pCh == NULL) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| p = (DXS_SIG_Ch_Resource_t *)pCh->sig; |
| |
| if (!(p->flag & SIG_CH_INITIALIZED)) |
| { |
| DXS_RETURN(DXS_statusNotInitResource); |
| } |
| |
| /* check if CID/FSK feature is supported */ |
| if (!DXS_IsFeatureSupported(pCh->pParent, dxs_cap_cid)) |
| { |
| DXS_RETURN(DXS_statusFeatNotSupportedCaps); |
| } |
| |
| if (p->fsk_ctrl.EN == 0) |
| { |
| /* parameters aren't changed */ |
| return DXS_statusOk; |
| } |
| |
| p->fsk_ctrl.EN = 0; |
| p->fsk_ctrl.AD = autodeact; |
| |
| return CmdWrite(pCh->pParent, (uint32_t *)&p->fsk_ctrl); |
| } |
| |
| /** |
| Send new data to the CID sender |
| |
| \param pCh - pointer to DXS channel structure |
| \param nByte - data buffer size |
| \param pByte - pointer to data buffer |
| |
| \return |
| - DXS_status_t |
| */ |
| int32_t DXS_FSK_Data(DXS_CHANNEL_t *pCh, uint8_t nByte, uint8_t *pByte) |
| { |
| DXS_SIG_Ch_Resource_t *p = NULL; |
| |
| if (pCh == NULL) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| p = (DXS_SIG_Ch_Resource_t *)pCh->sig; |
| |
| if (!(p->flag & SIG_CH_INITIALIZED)) |
| { |
| DXS_RETURN(DXS_statusNotInitResource); |
| } |
| |
| /* check if CID/FSK feature is supported */ |
| if (!DXS_IsFeatureSupported(pCh->pParent, dxs_cap_cid)) |
| { |
| DXS_RETURN(DXS_statusFeatNotSupportedCaps); |
| } |
| |
| if (nByte > DXS_CID_GEN_DATA_MAX) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| |
| if (pByte == NULL) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| |
| /* Fill first 3 bytes of data */ |
| if (nByte > 0) |
| { |
| p->fsk_data.DATA0 = pByte[0]; |
| } |
| |
| if (nByte > 1) |
| { |
| p->fsk_data.DATA1 = pByte[1]; |
| } |
| |
| if (nByte > 2) |
| { |
| p->fsk_data.DATA2 = pByte[2]; |
| } |
| |
| if (nByte > 3) |
| { |
| /* Copy the data with endianess respecting. */ |
| DXS_cpb2dw(p->fsk_data.DATA, pByte + 3, nByte - 3); |
| } |
| |
| /* Set the number of CID bytes to be transmitted. */ |
| p->fsk_data.NRDATA = nByte; |
| |
| return CmdWrite(pCh->pParent, (uint32_t *)&p->fsk_data); |
| } |
| #endif /* DXS_FEAT_FSK */ |
| |
| #ifdef DXS_FEAT_UTD |
| /** |
| Update tone coefficients in the tone table |
| |
| \param pCh - pointer to DXS channel structure |
| \param unToneIdx - tone index |
| \param pUtdCoeff - pointer to UTD coefficients |
| |
| \return |
| - DXS_status_t |
| */ |
| int32_t DXS_SIG_UtdCoeffUpdate(DXS_CHANNEL_t *pCh, uint16_t unToneIdx, |
| struct DXS_FW_SIG_UtdCoeff *pUtdCoeff) |
| { |
| int32_t ret = DXS_statusOk, err; |
| uint32_t i; |
| |
| if (pUtdCoeff == NULL) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| |
| err = pthread_mutex_lock(&utd_tone_mtx); |
| if (err != 0) |
| DXS_ERROR_PUSH(err); |
| |
| for (i = 0; i < UtdTonesNum; i++) |
| { |
| if (utd_coef_tbl[i].unToneIdx == unToneIdx) |
| break; |
| } |
| |
| if (i < UTD_COEF_TABLE_MAX) |
| { |
| /* Tone index or empty record found */ |
| if (i >= UtdTonesNum) |
| { |
| utd_coef_tbl[i].unToneIdx = unToneIdx; |
| UtdTonesNum++; |
| } |
| utd_coef_tbl[i].coef_data.BW = pUtdCoeff->BW; |
| utd_coef_tbl[i].coef_data.CF = pUtdCoeff->CF; |
| utd_coef_tbl[i].coef_data.NLEV = pUtdCoeff->NLEV; |
| utd_coef_tbl[i].coef_data.SLEV = pUtdCoeff->SLEV; |
| utd_coef_tbl[i].coef_data.DLEV = pUtdCoeff->DLEV; |
| utd_coef_tbl[i].coef_data.LPCOEFF = pUtdCoeff->LPCOEFF; |
| utd_coef_tbl[i].coef_data.DUP = pUtdCoeff->DUP; |
| } |
| else |
| { |
| /* Tone table is full */ |
| ret = DXS_statusError; |
| } |
| err = pthread_mutex_unlock(&utd_tone_mtx); |
| if (err != 0) |
| DXS_ERROR_PUSH(err); |
| |
| DXS_RETURN(ret); |
| } |
| |
| /** |
| Function to enable UTD |
| |
| \param pCh - pointer to DXS channel structure |
| \param unToneIdx - tone index |
| \param unDirection - direction |
| |
| \return |
| - DXS_status_t |
| */ |
| int32_t DXS_SIG_UtdEnable(DXS_CHANNEL_t *pCh, uint16_t unToneIdx, |
| uint8_t unDirection) |
| { |
| int32_t ret = DXS_statusOk, err; |
| DXS_SIG_Ch_Resource_t *p; |
| uint32_t i; |
| |
| if (pCh == NULL) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| p = (DXS_SIG_Ch_Resource_t *)pCh->sig; |
| |
| if (!(p->flag & SIG_CH_INITIALIZED)) |
| { |
| DXS_RETURN(DXS_statusNotInitResource); |
| } |
| |
| /* check if UTD feature is supported */ |
| if (!DXS_IsFeatureSupported(pCh->pParent, dxs_cap_utd)) |
| { |
| DXS_RETURN(DXS_statusFeatNotSupportedCaps); |
| } |
| |
| /* Disable UTD if it is enabled */ |
| if (p->utd_ctrl.EN) |
| { |
| p->utd_ctrl.EN = 0; |
| ret = CmdWrite(pCh->pParent, (uint32_t *)&p->utd_ctrl); |
| if (ret != DXS_statusOk) |
| { |
| p->utd_ctrl.EN = 1; |
| DXS_RETURN(ret); |
| } |
| } |
| |
| err = pthread_mutex_lock(&utd_tone_mtx); |
| if (err != 0) |
| DXS_ERROR_PUSH(err); |
| |
| /* Get UTD coefficients */ |
| for (i = 0; i < UtdTonesNum; i++) |
| { |
| if (unToneIdx == utd_coef_tbl[i].unToneIdx) |
| break; |
| } |
| if (i >= UtdTonesNum) |
| { |
| /* Tone with the specified index was not loaded into the tone table */ |
| ret = DXS_statusUtdToneIdxMissing; |
| } |
| else |
| { |
| /* Write UTD coefficients to the firmware */ |
| p->utd_coeff.content = utd_coef_tbl[i].coef_data; |
| ret = CmdWrite(pCh->pParent, (uint32_t *)&p->utd_coeff); |
| } |
| |
| err = pthread_mutex_unlock(&utd_tone_mtx); |
| if (err != 0) |
| DXS_ERROR_PUSH(err); |
| |
| if (ret != DXS_statusOk) |
| { |
| DXS_RETURN(ret); |
| } |
| |
| /* Enable UTD */ |
| p->utd_ctrl.EN = 1; |
| p->utd_ctrl.DIR = unDirection ? 0 : 1; |
| ret = CmdWrite(pCh->pParent, (uint32_t *)&p->utd_ctrl); |
| if (ret != DXS_statusOk) |
| { |
| p->utd_ctrl.EN = 0; |
| DXS_RETURN(ret); |
| } |
| |
| /* Update tone index */ |
| p->utd_tone_idx = unToneIdx; |
| |
| DXS_RETURN(ret); |
| } |
| |
| /** |
| Function to disable UTD |
| |
| \param pCh - pointer to DXS channel structure |
| |
| \return |
| - DXS_status_t |
| */ |
| int32_t DXS_SIG_UtdDisable(DXS_CHANNEL_t *pCh) |
| { |
| int32_t err = DXS_statusOk; |
| DXS_SIG_Ch_Resource_t *p; |
| |
| if (pCh == NULL) |
| { |
| DXS_RETURN(DXS_statusInvalidParam); |
| } |
| p = (DXS_SIG_Ch_Resource_t *)pCh->sig; |
| |
| if (!(p->flag & SIG_CH_INITIALIZED)) |
| { |
| DXS_RETURN(DXS_statusNotInitResource); |
| } |
| |
| /* check if UTD feature is supported */ |
| if (!DXS_IsFeatureSupported(pCh->pParent, dxs_cap_utd)) |
| { |
| DXS_RETURN(DXS_statusFeatNotSupportedCaps); |
| } |
| |
| /* Disable UTD if it is enabled */ |
| if (p->utd_ctrl.EN) |
| { |
| p->utd_ctrl.EN = 0; |
| err = CmdWrite(pCh->pParent, (uint32_t *)&p->utd_ctrl); |
| if (err != DXS_statusOk) |
| p->utd_ctrl.EN = 1; |
| } |
| |
| DXS_RETURN(err); |
| } |
| #endif /* DXS_FEAT_UTD */ |
| |