blob: 56e827f02898410e977ce6a2fa6e061f06518797 [file] [log] [blame]
/******************************************************************************
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 */