blob: d75214114d43a291769d5bf3aab91840faf3ede5 [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_cid.c
Implementation of Caller ID functions.
*/
/* ========================================================================== */
/* Includes */
/* ========================================================================== */
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include "dxs.h"
#include "dxs_config.h"
#include "dxs_lib.h"
#include "dxs_errno.h"
#include "dxs_error.h"
#include "dxs_sdd.h"
#include "dxs_sig.h"
#include "dxs_event.h"
#include "dxs_cid_fsk.h"
#include "dxs_pcm.h"
#include "dxs_cid.h"
#include "dxs_ring.h"
#ifdef DXS_FEAT_CID
/* ========================================================================== */
/* Macro definitions */
/* ========================================================================== */
#define DXS_CID_CTX_MAGIC 0x58434944 /* "XCID" */
/* default FSK configuration */
#define DXS_CID_FSK_LEVEL_DEFAULT (-69) /* -6.9 dBm0 */
#define DXS_CID_FSK_SEIZURE_DEFAULT 300
#define DXS_CID_FSK_MARK_DEFAULT 180
#define DXS_CID_FSK_AD_DEFAULT 1
/* default SIN BT FSK mark bits */
#define DXS_CID_FSK_BT_MARK_DEFAULT 80
/* default ETSI type2 FSK mark bits */
#define DXS_CID_FSK_ETSI_TYPE2_MARK_DEFAULT 80
/* default TG configuration for DTAS */
#define DXS_CID_DTAS_LEVEL1 (-138) /* -13.8 dBm0 */
#define DXS_CID_DTAS_LEVEL2 (-138) /* -13.8 dBm0 */
#define DXS_CID_DTAS_FREQ1 2130
#define DXS_CID_DTAS_FREQ2 2750
/* default ETSI timers */
#define DXS_CID_ETSI_LONG_RING_MS 1000
#define DXS_CID_ETSI_DTAS_MS 100
#define DXS_CID_ETSI_RPAS_MS 200
#define DXS_CID_ETSI_T0_DEFAULT 200
#define DXS_CID_ETSI_T1_DEFAULT 200
#define DXS_CID_ETSI_T2_DEFAULT 350
#define DXS_CID_ETSI_T3_DEFAULT 650
#define DXS_CID_ETSI_T4_DEFAULT 300
#define DXS_CID_ETSI_T5_DEFAULT 700
#define DXS_CID_ETSI_T6_DEFAULT 500
#define DXS_CID_ETSI_T7_MAX 700
#define DXS_CID_ETSI_TYPE2_DTAS_MS 80
#define DXS_CID_ETSI_TYPE2_T14_DEFAULT 160
#define DXS_CID_ETSI_TYPE2_T10_DEFAULT 50
#define DXS_CID_ETSI_TYPE2_T12_DEFAULT 100
#define DXS_CID_ETSI_TYPE2_T13_DEFAULT 50
#define DXS_CID_ETSI_TYPE2_T9_DEFAULT 50
#define DXS_CID_ETSI_T0dtmf_DEFAULT 300
#define DXS_CID_ETSI_Tdtmf_DEFAULT 60
#define DXS_CID_ETSI_T2dtmf_DEFAULT 300
/* default Telcordia timers */
#define DXS_CID_TELCORDIA_LONG_RING_MS 2000
#define DXS_CID_TELCORDIA_OSI_MS 250
#define DXS_CID_TELCORDIA_T0_DEFAULT 700
#define DXS_CID_TELCORDIA_T1_DEFAULT 400
#define DXS_CID_TELCORDIA_T2_DEFAULT 300
#define DXS_CID_TELCORDIA_TYPE2_OSI_MS 0
#define DXS_CID_TELCORDIA_TYPE2_W_MS 60
#define DXS_CID_TELCORDIA_TYPE2_X_MS 0
#define DXS_CID_TELCORDIA_TYPE2_X1_MS 40
#define DXS_CID_TELCORDIA_TYPE2_Y_MS 85
#define DXS_CID_TELCORDIA_TYPE2_T1_MS 165
#define DXS_CID_TELCORDIA_TYPE2_Q_MS 100
#define DXS_CID_TELCORDIA_TYPE2_S_MS 80
#define DXS_CID_TELCORDIA_T0dtmf_DEFAULT 300
#define DXS_CID_TELCORDIA_Tdtmf_DEFAULT 60
#define DXS_CID_TELCORDIA_T2dtmf_DEFAULT 300
/* default SIN BT timers */
#define DXS_CID_BT_DTAS_MS 100
#define DXS_CID_BT_T0_DEFAULT 120
#define DXS_CID_BT_T1_DEFAULT 55
#define DXS_CID_BT_T2_DEFAULT 220
#define DXS_CID_BT_TYPE2_DTAS_MS 85
#define DXS_CID_BT_TYPE2_ACK_MS 150
#define DXS_CID_BT_TYPE2_T0_DEFAULT 45
#define DXS_CID_BT_TYPE2_T1_DEFAULT 80
#define DXS_CID_BT_TYPE2_T2_DEFAULT 50
/* default NTT timers */
#define DXS_CID_NTT_CARON_MS 500
#define DXS_CID_NTT_CAROFF_MS 500
#define DXS_CID_NTT_T0_DEFAULT 100
#define DXS_CID_NTT_T1_DEFAULT 6000
#define DXS_CID_NTT_T2_DEFAULT 400
#define DXS_CID_NTT_T3_DEFAULT 7000
#define DXS_CID_NTT_T4_DEFAULT 300
#define DXS_CID_NTT_TYPE2_AS1_MS 100
#define DXS_CID_NTT_TYPE2_AS2_MS 100
#define DXS_CID_NTT_TYPE2_AS_PAUSE_MS 50
#define DXS_CID_NTT_TYPE2_T0_DEFAULT 45
#define DXS_CID_NTT_TYPE2_T1_DEFAULT 80
#define DXS_CID_NTT_TYPE2_T2_DEFAULT 50
/* length of each CID message parameter */
#define DXS_CID_MSG_PARAM_DATE_TIME_FIXLEN 8
#define DXS_CID_MSG_PARAM_CALLING_LINE_ID_MAXLEN 20
#define DXS_CID_MSG_PARAM_CALLED_LINE_ID_MAXLEN 20
#define DXS_CID_MSG_PARAM_RA_CALLING_LINE_ID_FIXLEN 1
#define DXS_CID_MSG_PARAM_CALLING_PARTY_NAME_MAXLEN 50
#define DXS_CID_MSG_PARAM_RA_CALLING_PARTY_NAME_FIXLEN 1
#define DXS_CID_MSG_PARAM_VI_FIXLEN 1
#define DXS_CID_MSG_PARAM_MSG_ID_FIXLEN 3
#define DXS_CID_MSG_PARAM_LM_CLI_MAXLEN 20
#define DXS_CID_MSG_PARAM_COMP_DATE_TIME_FIXLEN1 8
#define DXS_CID_MSG_PARAM_COMP_DATE_TIME_FIXLEN2 10
#define DXS_CID_MSG_PARAM_COMP_CALLING_LINE_ID_MAXLEN 20
#define DXS_CID_MSG_PARAM_CALL_TYPE_FIXLEN 1
#define DXS_CID_MSG_PARAM_FIRST_CALLED_LINE_ID_MAXLEN 20
#define DXS_CID_MSG_PARAM_NUM_MESSAGES_FIXLEN 1
#define DXS_CID_MSG_PARAM_TYPE_FWD_CALL_FIXLEN 1
#define DXS_CID_MSG_PARAM_TYPE_CALLING_USER_FIXLEN 1
#define DXS_CID_MSG_PARAM_REDIR_NUM_MAXLEN 20
#define DXS_CID_MSG_PARAM_CHARGE_FIXLEN 14
#define DXS_CID_MSG_PARAM_ADDON_CHARGE_FIXLEN 14
#define DXS_CID_MSG_PARAM_DURA_CALL_FIXLEN 6
#define DXS_CID_MSG_PARAM_NET_PROV_ID_MAXLEN 20
#define DXS_CID_MSG_PARAM_CARRIER_ID_MAXLEN 20
#define DXS_CID_MSG_PARAM_SEL_TERMINAL_FUNC_MAXLEN 21
#define DXS_CID_MSG_PARAM_DISP_INFO_MAXLEN 253
#define DXS_CID_MSG_PARAM_SERV_INFO_FIXLEN 1
#define DXS_CID_MSG_PARAM_EXTENSION_FIXLEN 10
/* length of SIN BT CID message parameter */
#define DXS_CID_BT_MSG_PARAM_CALL_TYPE_FIXLEN 1
#define DXS_CID_BT_MSG_PARAM_DATE_TIME_FIXLEN 8
#define DXS_CID_BT_MSG_PARAM_CALLING_LINE_ID_MAXLEN 18
#define DXS_CID_BT_MSG_PARAM_RA_CALLING_LINE_ID_FIXLEN 1
#define DXS_CID_BT_MSG_PARAM_CALLED_LINE_ID_MAXLEN 18
#define DXS_CID_BT_MSG_PARAM_RA_CALLING_PARTY_NAME_FIXLEN 1
#define DXS_CID_BT_MSG_PARAM_CALLING_PARTY_NAME_MAXLEN 20
#define DXS_CID_BT_MSG_PARAM_NUM_MESSAGES_FIXLEN 1
/* length of NTT CID message parameter */
#define DXS_CID_NTT_MSG_PARAM_CALLING_LINE_ID_MAXLEN 20
#define DXS_CID_NTT_MSG_PARAM_RA_CALLING_LINE_ID_FIXLEN 1
#define DXS_CID_NTT_MSG_PARAM_EXP_SIGNAL_FIXLEN 3
/* reversed polarity flag */
#define DXS_CID_LINE_MODE_POLARITY_FLAG_NORMAL 0x00
#define DXS_CID_LINE_MODE_POLARITY_FLAG_REVERSED 0x10
/* offhook/onhook state */
#define DXS_CID_HOOK_STATE_ONHOOK 0x1
#define DXS_CID_HOOK_STATE_OFFHOOK 0x2
/* default TG configuration for NTT type2 alert tone */
#define DXS_CID_NTT_TYPE2_ATONE_LEVEL1 (-138) /* -13.8 dBm0 */
#define DXS_CID_NTT_TYPE2_ATONE_LEVEL2 (-138) /* -13.8 dBm0 */
#define DXS_CID_NTT_TYPE2_ATONE_FREQ1 852
#define DXS_CID_NTT_TYPE2_ATONE_FREQ2 1633
#define DXS_CID_NTT_TYPE2_ATONE_FREQ3 941
/* CID FSK messsage buffer's size */
#define DXS_CID_FSK_MSG_BUF_MAX_LEN 258
#define DXS_CID_FSK_BITS_PER_SEC 1200
/* ========================================================================== */
/* Type definitions */
/* ========================================================================== */
struct __cid_msg_elem
{
/* message type */
DXS_CID_MsgParam_t type;
/* message data */
char *data;
/* length of message data */
uint16_t len;
/* next message */
struct __cid_msg_elem *next;
};
typedef struct __cid_msg_elem dxs_cid_message_t;
/* CID resource context */
typedef struct
{
/* magic code */
uint32_t magic;
/* CID standard */
DXS_CID_Std_t std;
/* alert signal */
DXS_CID_AS_t as;
/* data format */
DXS_CID_DATA_FMT_t df;
/* DTMF index for acknowledgment (type2 only) */
uint8_t dtmf_ack_idx;
/* timers ETSI */
DXS_CID_ETSI_Timers_t tm_etsi;
/* timers Telcordia */
DXS_CID_TELCORDIA_Timers_t tm_tc;
/* timers BT */
DXS_CID_BT_Timers_t tm_bt;
/* timers NTT */
DXS_CID_NTT_Timers_t tm_ntt;
/* Call Set-up message */
dxs_cid_message_t *msg_cs;
/* Message Waiting Indicator message */
dxs_cid_message_t *msg_mwi;
/* Advice of Charge message */
dxs_cid_message_t *msg_aoc;
/* Short Message Service */
dxs_cid_message_t *msg_sms;
/* Number Display service */
dxs_cid_message_t *msg_nd;
/* transmit data buffer */
uint8_t xmit_buffer[DXS_CID_FSK_MSG_BUF_MAX_LEN];
/* transmit data buffer length */
uint16_t xmit_length;
/* thread ID */
pthread_t thrd;
/* sem ID */
sem_t sema;
/* thread status */
volatile uint32_t complete;
/* thread return code */
int32_t ret;
/* CID SM */
int32_t (*cid_state)(void *arg);
/* timeout value for CID SM */
uint32_t timeout;
/* parameter's length depends on CID standard */
uint8_t (*len_check) (DXS_CID_MsgParam_t param, uint8_t length);
/* initial polarity before starting CID */
uint8_t polarity_initial;
/* expected hook state flag for CID SM state */
uint8_t hook_state_exp;
/* hook state */
volatile uint8_t hook_state;
/* timestamp of onhook/offhook */
uint8_t hook_timestamp;
/* hide off-hook during OSI for CID type2 */
volatile uint8_t hook_block;
/* ACK detection for CID SM Type2 */
volatile uint8_t ack_detect;
/* Unmute channel */
uint8_t need_unmute;
/* supervisory timeout for CID NTT SM */
uint16_t ntt_timeout;
/* calling instance (user API or Ringing SM) */
uint8_t calling_instance;
} DXS_CID_Ctx_t;
/* CID resource array */
static DXS_CID_Ctx_t cid_res[DXS_MAX_DEVICES * CH_PER_DEVICE] = {0};
/* 0-9, * 10, # 11, A-D(a-d) 12-15 */
typedef struct
{
int16_t level1;
int16_t level2;
uint16_t freq1;
uint16_t freq2;
} dtmf_t;
static dtmf_t dtmf[16] = {{-9, -7, 941, 1336}, {-9, -7, 697, 1209}, {-9, -7, 697, 1336}, {-9, -7, 697, 1477},
{-9, -7, 770, 1209}, {-9, -7, 770, 1336}, {-9, -7, 770, 1477}, {-9, -7, 852, 1209},
{-9, -7, 852, 1336}, {-9, -7, 852, 1477}, {-9, -7, 941, 1209}, {-9, -7, 941, 1477},
{-9, -7, 697, 1633}, {-9, -7, 770, 1633}, {-9, -7, 852, 1633}, {-9, -7, 941, 1633},
};
/* ========================================================================== */
/* Function implementation */
/* ========================================================================== */
/**
Get the message of a type
\param pCid - pointer to \ref DXS_CID_Ctx_t structure
\param type - message type
\return
- message pointer
*/
static dxs_cid_message_t *dxs_cid_message_get(DXS_CID_Ctx_t *pCid,
DXS_CID_MsgType_t type)
{
dxs_cid_message_t *pMsg = NULL;
if (type == DXS_CID_MSG_TYPE_CS)
pMsg = pCid->msg_cs;
else if (type == DXS_CID_MSG_TYPE_MWI)
pMsg = pCid->msg_mwi;
else if (type == DXS_CID_MSG_TYPE_AOC)
pMsg = pCid->msg_aoc;
else if (type == DXS_CID_MSG_TYPE_SMS)
pMsg = pCid->msg_sms;
else if (type == DXS_CID_MSG_TYPE_ND)
pMsg = pCid->msg_nd;
/* other message types are not supported */
return pMsg;
}
/**
Set the message of a type
\param pCid - pointer to \ref DXS_CID_Ctx_t structure
\param type - message type
\param pMsg - message
\return
- none
*/
static void dxs_cid_message_set(DXS_CID_Ctx_t *pCid, DXS_CID_MsgType_t type,
dxs_cid_message_t *pMsg)
{
if (type == DXS_CID_MSG_TYPE_CS)
pCid->msg_cs = pMsg;
else if (type == DXS_CID_MSG_TYPE_MWI)
pCid->msg_mwi = pMsg;
else if (type == DXS_CID_MSG_TYPE_AOC)
pCid->msg_aoc = pMsg;
else if (type == DXS_CID_MSG_TYPE_SMS)
pCid->msg_sms = pMsg;
else if (type == DXS_CID_MSG_TYPE_ND)
pCid->msg_nd = pMsg;
/* other message types are not supported */
}
/**
Vipe a CID message from CID context
\param pCid - pointer to \ref DXS_CID_Ctx_t structure
\param type - message type \ref DXS_CID_MsgType_t
\return
- DXS_status_t
*/
static void dxs_cid_msg_clear (DXS_CID_Ctx_t *pCid, DXS_CID_MsgType_t type)
{
dxs_cid_message_t *pMsg = dxs_cid_message_get(pCid, type);
while (pMsg != NULL)
{
dxs_cid_message_t *p = pMsg;
/* free parameter value */
free(pMsg->data);
/* take next message */
pMsg = pMsg->next;
dxs_cid_message_set(pCid, type, pMsg);
/* free parameter */
free (p);
}
}
/**
Vipe all CID messages from CID context
\param pCid - pointer to \ref DXS_CID_Ctx_t structure
\return
- DXS_status_t
*/
static void dxs_cid_msg_clearall (DXS_CID_Ctx_t *pCid)
{
dxs_cid_msg_clear (pCid, DXS_CID_MSG_TYPE_CS);
dxs_cid_msg_clear (pCid, DXS_CID_MSG_TYPE_MWI);
dxs_cid_msg_clear (pCid, DXS_CID_MSG_TYPE_AOC);
dxs_cid_msg_clear (pCid, DXS_CID_MSG_TYPE_SMS);
dxs_cid_msg_clear (pCid, DXS_CID_MSG_TYPE_ND);
}
/**
Function to set parity bit
\param data_byte - source data
\return
- uint8_t
*/
static uint8_t dxs_cid_parity_set(uint8_t data_byte)
{
uint8_t i, ones_num = 0, tmpByte = data_byte;
/* check even parity for b7...b1 */
for (i = 0; i < 7; i++)
{
/* count number of ones */
if (tmpByte & 0x1)
ones_num ++;
tmpByte >>= 1;
}
/* set parity bit as MSB in case of odd num (i.e. lowest bit is set) */
if (ones_num & 0x1)
data_byte |= 0x80;
return data_byte;
}
/**
Calculate CRC for NTT FSK encoding.
\param pCidBuf CID data buffer.
\param len Buffer size in octets.
\return calculated CRC
\remarks
\verbatim
1- The CRC16 for NTT FSK Buffer is generated with the polynom
X^16 + X^12 + X^5 + X^2 + X^0 (Hexadecimal: 0x8408)
2- The algorithm is:
a)initial value of CRC = 0x0000.
b)for each byte (from header to ETX)
compute the CRC with G(x) (CRC1)
CRC= CRC + CRC1
\endverbatim
*/
static uint16_t dxs_cid_crc_ntt(uint8_t *pCidBuf, uint8_t len)
{
uint16_t crc = 0, tmp;
uint8_t i, j, byte;
for (i = 0; i < len; i++)
{
/* get reversed data byte */
byte = pCidBuf [i];
tmp = (byte << 1);
for (j = 8; j > 0; j--)
{
tmp >>= 1;
if ((tmp ^ crc) & 0x0001)
crc = (crc >> 1) ^ 0x8408;
else
crc >>= 1;
}
}
return crc;
}
/**
Prepare data buffer for DTMF transmit
\param pCid - pointer to \ref DXS_CID_Ctx_t structure
\param
\return
- DXS_status_t
*/
static int32_t dxs_cid_dtmf_buffer_prepare(DXS_CID_Ctx_t *pCid,
DXS_CID_MsgType_t msg_type)
{
/* prepare buffer for sending in DTMF */
dxs_cid_message_t *p, *pMsg = dxs_cid_message_get(pCid, msg_type);
uint16_t buffer_length = 0, pos = 2;
if (pMsg == NULL)
{
/* uninitialized message, return error */
DXS_RETURN(DXS_statusCidMsgNotInit);
}
p = pMsg;
/* calculate total length for an DTMF buffer */
while (p != NULL)
{
buffer_length += (p->len);
p = p->next;
}
buffer_length += 2; /* length + pos in the head */
if (buffer_length > DXS_CID_FSK_MSG_BUF_MAX_LEN)
{
/* Message length is too high, return error */
DXS_RETURN(DXS_statusCidMsgLenWrong);
}
p = pMsg;
/* copy the parameters */
while (p != NULL)
{
uint8_t i;
{
for (i=0; i<p->len; i++)
{
/* 0-9, * 10, # 11, A-D(a-d) 12-15 */
if ((p->data[i] >= 0x30) && (p->data[i] <= 0x39))
pCid->xmit_buffer[pos++] = p->data[i] - 0x30;
else if (p->data[i] == 0x2A) /* * */
pCid->xmit_buffer[pos++] = 10;
else if (p->data[i] == 0x23) /* # */
pCid->xmit_buffer[pos++] = 11;
else if ((p->data[i] >= 0x41) && (p->data[i] <= 0x44)) /* A-D */
pCid->xmit_buffer[pos++] = p->data[i] - 0x35;
else if ((p->data[i] >= 0x61) && (p->data[i] <= 0x64)) /* a-d */
pCid->xmit_buffer[pos++] = p->data[i] - 0x55;
}
}
p = p->next;
}
/* set buffer length */
pCid->xmit_buffer[0] = pos - 2; /* length of data */
pCid->xmit_buffer[1] = 2; /* next data position, used when transmitting */
pCid->xmit_length = pos; /* total length includes the headerr */
/* printf("cid_prepare %d, %d, %d, %d, %d\n", pCid->xmit_length, pCid->xmit_buffer[0], pCid->xmit_buffer[1], pCid->xmit_buffer[2], pCid->xmit_buffer[3]); */
return DXS_statusOk;
}
/**
Prepare data buffer for FSK transmit
\param pCid - pointer to \ref DXS_CID_Ctx_t structure
\param
\return
- DXS_status_t
*/
static int32_t dxs_cid_fsk_buffer_prepare(DXS_CID_Ctx_t *pCid,
DXS_CID_MsgType_t msg_type)
{
dxs_cid_message_t *p, *pMsg = dxs_cid_message_get(pCid, msg_type);
uint16_t buffer_length = 0, pos = 2, i;
uint8_t fsk_data_cksum = 0;
if (pMsg == NULL)
{
/* uninitialized message, return error */
DXS_RETURN(DXS_statusCidMsgNotInit);
}
p = pMsg;
/* calculate total length for an FSK buffer */
while (p != NULL)
{
buffer_length += (p->len + 2); /* + parameter code + length byte */
p = p->next;
}
buffer_length += 3; /* + message type code + total length byte + checksum */
if (buffer_length > DXS_CID_FSK_MSG_BUF_MAX_LEN)
{
/* Message length is too high, return error */
DXS_RETURN(DXS_statusCidMsgLenWrong);
}
pCid->xmit_buffer[0] = msg_type;
pCid->xmit_buffer[1] = buffer_length - 3;
p = pMsg;
/* copy the parameters */
while (p != NULL)
{
uint8_t i;
pCid->xmit_buffer[pos++] = p->type;
pCid->xmit_buffer[pos++] = p->len;
#if 0
/* update date/time */
if (p->type == DXS_CID_MSG_PARAM_DATE_TIME)
{
struct tm tms = {0};
time_t rawtime = time(NULL);
localtime_r(&rawtime, &tms);
/* month */
pCid->xmit_buffer[pos++] = (tms.tm_mon + 1) / 10 + '0';
pCid->xmit_buffer[pos++] = (tms.tm_mon + 1) % 10 + '0';
/* day */
pCid->xmit_buffer[pos++] = tms.tm_mday / 10 + '0';
pCid->xmit_buffer[pos++] = tms.tm_mday % 10 + '0';
/* hour */
pCid->xmit_buffer[pos++] = tms.tm_hour / 10 + '0';
pCid->xmit_buffer[pos++] = tms.tm_hour % 10 + '0';
/* minute */
pCid->xmit_buffer[pos++] = tms.tm_min / 10 + '0';
pCid->xmit_buffer[pos++] = tms.tm_min % 10 + '0';
}
else
#endif
{
for (i=0; i<p->len; i++)
pCid->xmit_buffer[pos++] = p->data[i];
}
p = p->next;
}
/* calculate checksum */
for (i=0; i<pos; i++)
fsk_data_cksum += pCid->xmit_buffer[i];
pCid->xmit_buffer[pos] = ~(fsk_data_cksum & 0xFF) + 1;
/* set buffer length */
pCid->xmit_length = buffer_length;
return DXS_statusOk;
}
/**
Prepare data buffer for FSK transmit (NTT standard)
\param pCid - pointer to \ref DXS_CID_Ctx_t structure
\param
\return
- DXS_status_t
*/
static int32_t dxs_cid_fsk_buffer_prepare_ntt(DXS_CID_Ctx_t *pCid,
DXS_CID_MsgType_t msg_type)
{
dxs_cid_message_t *p, *pMsg = dxs_cid_message_get(pCid, msg_type);
uint16_t buffer_length = 0, pos = 6, crc;
if (pMsg == NULL)
{
/* uninitialized message, return error */
DXS_RETURN(DXS_statusCidMsgNotInit);
}
p = pMsg;
/* calculate total length for an FSK buffer */
while (p != NULL)
{
buffer_length += (p->len + 2); /* + parameter code + length byte */
/* Increase buffer's size for DLE insertion */
if (p->len == 16)
buffer_length++;
p = p->next;
}
/* Increase buffer's size for DLE insertion */
if (buffer_length == 16)
buffer_length++;
/* + DLE+SOH+Header+DLE+STX+ServiceType+MessageLength+DLE+ETX+CRC(2) */
buffer_length += 11;
if (buffer_length > 128)
{
/* Message length is too high, return error */
DXS_RETURN(DXS_statusCidMsgLenWrong);
}
pCid->xmit_buffer[0] = 0x90; /* DLE (w parity)*/
pCid->xmit_buffer[1] = 0x81; /* SOH (w parity) */
pCid->xmit_buffer[2] = 0x87; /* Header (w parity) */
pCid->xmit_buffer[3] = 0x90; /* DLE (w parity)*/
pCid->xmit_buffer[4] = 0x82; /* STX (w parity)*/
pCid->xmit_buffer[5] = dxs_cid_parity_set(msg_type);
if (buffer_length == 28)
{
pCid->xmit_buffer[pos++] = 0x90; /* DLE (w parity)*/
pCid->xmit_buffer[pos++] = 0x90;
}
else
pCid->xmit_buffer[pos++] = dxs_cid_parity_set(buffer_length - 11);
p = pMsg;
/* copy the parameters */
while (p != NULL)
{
uint8_t i;
pCid->xmit_buffer[pos++] = dxs_cid_parity_set(p->type);
if (p->len == 16)
pCid->xmit_buffer[pos++] = 0x90; /* DLE (w parity)*/
pCid->xmit_buffer[pos++] = dxs_cid_parity_set(p->len);
for (i=0; i<p->len; i++)
pCid->xmit_buffer[pos++] = dxs_cid_parity_set(p->data[i]);
p = p->next;
}
/* Add control fields */
pCid->xmit_buffer[pos++] = 0x90; /* DLE (w parity)*/
pCid->xmit_buffer[pos++] = 0x03; /* ETX (w parity)*/
/* Add CRC (from HEADER to ETX) */
crc = dxs_cid_crc_ntt(&pCid->xmit_buffer[2], (uint8_t) pos - 2);
pCid->xmit_buffer[pos++] = (uint8_t) (crc & 0xFF);
pCid->xmit_buffer[pos] = (uint8_t) ((crc >> 8) & 0xFF);
/* set buffer length */
pCid->xmit_length = buffer_length;
return DXS_statusOk;
}
/**
Check ETSI message parameter length
\param param - message parameter
\param length - message length
\return
- updated length
*/
static uint8_t dxs_cid_param_length_check_etsi(DXS_CID_MsgParam_t param,
uint8_t length)
{
uint8_t updated_length = length;
switch (param)
{
case DXS_CID_MSG_PARAM_DATE_TIME:
updated_length = DXS_CID_MSG_PARAM_DATE_TIME_FIXLEN;
break;
case DXS_CID_MSG_PARAM_CALLING_LINE_ID:
if (updated_length > DXS_CID_MSG_PARAM_CALLING_LINE_ID_MAXLEN)
updated_length = DXS_CID_MSG_PARAM_CALLING_LINE_ID_MAXLEN;
break;
case DXS_CID_MSG_PARAM_CALLED_LINE_ID:
if (updated_length > DXS_CID_MSG_PARAM_CALLED_LINE_ID_MAXLEN)
updated_length = DXS_CID_MSG_PARAM_CALLED_LINE_ID_MAXLEN;
break;
case DXS_CID_MSG_PARAM_RA_CALLING_LINE_ID:
updated_length = DXS_CID_MSG_PARAM_RA_CALLING_LINE_ID_FIXLEN;
break;
case DXS_CID_MSG_PARAM_CALLING_PARTY_NAME:
if (updated_length > DXS_CID_MSG_PARAM_CALLING_PARTY_NAME_MAXLEN)
updated_length = DXS_CID_MSG_PARAM_CALLING_PARTY_NAME_MAXLEN;
break;
case DXS_CID_MSG_PARAM_RA_CALLING_PARTY_NAME:
updated_length = DXS_CID_MSG_PARAM_RA_CALLING_PARTY_NAME_FIXLEN;
break;
case DXS_CID_MSG_PARAM_VI:
updated_length = DXS_CID_MSG_PARAM_VI_FIXLEN;
break;
case DXS_CID_MSG_PARAM_MSG_ID:
updated_length = DXS_CID_MSG_PARAM_MSG_ID_FIXLEN;
break;
case DXS_CID_MSG_PARAM_LM_CLI:
if (updated_length > DXS_CID_MSG_PARAM_LM_CLI_MAXLEN)
updated_length = DXS_CID_MSG_PARAM_LM_CLI_MAXLEN;
break;
case DXS_CID_MSG_PARAM_COMP_DATE_TIME:
if (updated_length != DXS_CID_MSG_PARAM_COMP_DATE_TIME_FIXLEN1 &&
updated_length != DXS_CID_MSG_PARAM_COMP_DATE_TIME_FIXLEN2)
updated_length = DXS_CID_MSG_PARAM_COMP_DATE_TIME_FIXLEN2;
break;
case DXS_CID_MSG_PARAM_COMP_CALLING_LINE_ID:
if (updated_length > DXS_CID_MSG_PARAM_COMP_CALLING_LINE_ID_MAXLEN)
updated_length = DXS_CID_MSG_PARAM_COMP_CALLING_LINE_ID_MAXLEN;
break;
case DXS_CID_MSG_PARAM_CALL_TYPE:
updated_length = DXS_CID_MSG_PARAM_CALL_TYPE_FIXLEN;
break;
case DXS_CID_MSG_PARAM_FIRST_CALLED_LINE_ID:
if (updated_length > DXS_CID_MSG_PARAM_FIRST_CALLED_LINE_ID_MAXLEN)
updated_length = DXS_CID_MSG_PARAM_FIRST_CALLED_LINE_ID_MAXLEN;
break;
case DXS_CID_MSG_PARAM_NUM_MESSAGES:
updated_length = DXS_CID_MSG_PARAM_NUM_MESSAGES_FIXLEN;
break;
case DXS_CID_MSG_PARAM_TYPE_FWD_CALL:
updated_length = DXS_CID_MSG_PARAM_TYPE_FWD_CALL_FIXLEN;
break;
case DXS_CID_MSG_PARAM_TYPE_CALLING_USER:
updated_length = DXS_CID_MSG_PARAM_TYPE_CALLING_USER_FIXLEN;
break;
case DXS_CID_MSG_PARAM_REDIR_NUM:
if (updated_length > DXS_CID_MSG_PARAM_REDIR_NUM_MAXLEN)
updated_length = DXS_CID_MSG_PARAM_REDIR_NUM_MAXLEN;
break;
case DXS_CID_MSG_PARAM_CHARGE:
updated_length = DXS_CID_MSG_PARAM_CHARGE_FIXLEN;
break;
case DXS_CID_MSG_PARAM_ADDON_CHARGE:
updated_length = DXS_CID_MSG_PARAM_ADDON_CHARGE_FIXLEN;
break;
case DXS_CID_MSG_PARAM_DURA_CALL:
updated_length = DXS_CID_MSG_PARAM_DURA_CALL_FIXLEN;
break;
case DXS_CID_MSG_PARAM_NET_PROV_ID:
if (updated_length > DXS_CID_MSG_PARAM_NET_PROV_ID_MAXLEN)
updated_length = DXS_CID_MSG_PARAM_NET_PROV_ID_MAXLEN;
break;
case DXS_CID_MSG_PARAM_CARRIER_ID:
if (updated_length > DXS_CID_MSG_PARAM_CARRIER_ID_MAXLEN)
updated_length = DXS_CID_MSG_PARAM_CARRIER_ID_MAXLEN;
break;
case DXS_CID_MSG_PARAM_SEL_TERMINAL_FUNC:
if (updated_length > DXS_CID_MSG_PARAM_SEL_TERMINAL_FUNC_MAXLEN)
updated_length = DXS_CID_MSG_PARAM_SEL_TERMINAL_FUNC_MAXLEN;
break;
case DXS_CID_MSG_PARAM_DISP_INFO:
if (updated_length > DXS_CID_MSG_PARAM_DISP_INFO_MAXLEN)
updated_length = DXS_CID_MSG_PARAM_DISP_INFO_MAXLEN;
break;
case DXS_CID_MSG_PARAM_SERV_INFO:
updated_length = DXS_CID_MSG_PARAM_SERV_INFO_FIXLEN;
break;
case DXS_CID_MSG_PARAM_EXTENSION:
updated_length = DXS_CID_MSG_PARAM_EXTENSION_FIXLEN;
break;
default:
break;
}
return updated_length;
}
/**
Check SIN BT message parameter length
\param param - message parameter
\param length - message length
\return
- updated length
*/
static uint8_t dxs_cid_param_length_check_bt(DXS_CID_MsgParam_t param,
uint8_t length)
{
uint8_t updated_length = length;
switch (param)
{
case DXS_CID_MSG_PARAM_DATE_TIME:
updated_length = DXS_CID_BT_MSG_PARAM_DATE_TIME_FIXLEN;
break;
case DXS_CID_MSG_PARAM_CALLING_LINE_ID:
if (updated_length > DXS_CID_BT_MSG_PARAM_CALLING_LINE_ID_MAXLEN)
updated_length = DXS_CID_BT_MSG_PARAM_CALLING_LINE_ID_MAXLEN;
break;
case DXS_CID_MSG_PARAM_CALLED_LINE_ID:
if (updated_length > DXS_CID_BT_MSG_PARAM_CALLED_LINE_ID_MAXLEN)
updated_length = DXS_CID_BT_MSG_PARAM_CALLED_LINE_ID_MAXLEN;
break;
case DXS_CID_MSG_PARAM_RA_CALLING_LINE_ID:
updated_length = DXS_CID_BT_MSG_PARAM_RA_CALLING_LINE_ID_FIXLEN;
break;
case DXS_CID_MSG_PARAM_CALLING_PARTY_NAME:
if (updated_length > DXS_CID_BT_MSG_PARAM_CALLING_PARTY_NAME_MAXLEN)
updated_length = DXS_CID_BT_MSG_PARAM_CALLING_PARTY_NAME_MAXLEN;
break;
case DXS_CID_MSG_PARAM_RA_CALLING_PARTY_NAME:
updated_length = DXS_CID_BT_MSG_PARAM_RA_CALLING_PARTY_NAME_FIXLEN;
break;
case DXS_CID_MSG_PARAM_CALL_TYPE:
updated_length = DXS_CID_BT_MSG_PARAM_CALL_TYPE_FIXLEN;
break;
case DXS_CID_MSG_PARAM_NUM_MESSAGES:
updated_length = DXS_CID_BT_MSG_PARAM_NUM_MESSAGES_FIXLEN;
break;
default:
break;
}
return updated_length;
}
/**
Check NTT message parameter length
\param param - message parameter
\param length - message length
\return
- updated length
*/
static uint8_t dxs_cid_param_length_check_ntt(DXS_CID_MsgParam_t param,
uint8_t length)
{
uint8_t updated_length = length;
switch (param)
{
case DXS_CID_MSG_PARAM_CALLING_LINE_ID:
if (updated_length > DXS_CID_NTT_MSG_PARAM_CALLING_LINE_ID_MAXLEN)
updated_length = DXS_CID_NTT_MSG_PARAM_CALLING_LINE_ID_MAXLEN;
break;
case DXS_CID_MSG_PARAM_RA_CALLING_LINE_ID:
updated_length = DXS_CID_NTT_MSG_PARAM_RA_CALLING_LINE_ID_FIXLEN;
break;
case DXS_CID_MSG_NTT_EXP_SIGNAL:
updated_length = DXS_CID_NTT_MSG_PARAM_EXP_SIGNAL_FIXLEN;
break;
default:
break;
}
return updated_length;
}
/**
Check Telcordia message parameter length
\param param - message parameter
\param length - message length
\return
- updated length
*/
static uint8_t dxs_cid_param_length_check_tc(DXS_CID_MsgParam_t param,
uint8_t length)
{
uint8_t updated_length = length;
switch (param)
{
/* TODO */
default:
break;
}
return updated_length;
}
/**
Waiting function for a state machine
\param pCid - pointer to \ref DXS_CID_Ctx_t structure
\return
- DXS_status_t
*/
static void dxs_cid_wait (DXS_CID_Ctx_t *pCid)
{
struct timespec ts = {0};
if (pCid->timeout == 0)
return;
/* wait */
clock_gettime (CLOCK_REALTIME, &ts);
if (!(pCid->timeout % 1000))
{
ts.tv_sec += pCid->timeout / 1000;
}
else
{
unsigned long ns;
ns = ts.tv_nsec + pCid->timeout * 1000 * 1000;
ts.tv_nsec = ns % (1000 * 1000 * 1000);
ts.tv_sec += ns / (1000 * 1000 * 1000);
}
sem_timedwait(&pCid->sema, &ts);
}
/* ========================================================================== */
/* CID SM */
/* ========================================================================== */
/* CID SM final state (success) */
/**
dxs_cid_sm_fin
\param arg
\return
- none
*/
static int32_t dxs_cid_sm_fin(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
DXS_Event_t dxs_event = {0};
pCid->complete = 1;
/* Unmute channel */
if (pCid->need_unmute)
{
if (dxs_pcm_ch_mute(pCh, 0) == DXS_statusOk)
pCid->need_unmute = 0;
}
/* if called from ring SM, inform ring SM */
if (pCid->calling_instance == DXS_CID_CALL_FROM_RING_SM)
{
DXS_Ring_CidFinished(pCh);
}
else
{
/* inform the application */
dxs_event.dev = pCh->pParent->nDevNum;
dxs_event.ch = pCh->nCh;
dxs_event.id = DXS_EVENT_CID_SEQ_END;
DXS_EventDispatch(pCh->pParent, &dxs_event);
}
pthread_detach(pCid->thrd);
sem_post(&pCid->sema);
return DXS_statusOk;
}
/* CID SM final state (timeout) */
/**
dxs_cid_sm_err_timeout
\param arg
\return
- none
*/
static int32_t dxs_cid_sm_err_timeout(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
DXS_Event_t dxs_event = {0};
pCid->complete = 1;
/* Unmute channel */
if (pCid->need_unmute)
{
if (dxs_pcm_ch_mute(pCh, 0) == DXS_statusOk)
pCid->need_unmute = 0;
}
/* inform application */
dxs_event.dev = pCh->pParent->nDevNum;
dxs_event.ch = pCh->nCh;
dxs_event.id = DXS_EVENT_CID_SEQ_ERROR;
dxs_event.data.cid_err = DXS_EVENT_CID_TIMEOUT;
DXS_EventDispatch(pCh->pParent, &dxs_event);
pthread_detach(pCid->thrd);
sem_post(&pCid->sema);
return DXS_statusOk;
}
/* CID SM final state (incorrect hook state) */
/**
dxs_cid_sm_err_hook
\param arg
\return
- none
*/
static int32_t dxs_cid_sm_err_hook(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
DXS_Event_t dxs_event = {0};
pCid->complete = 1;
/* Attempt to stop FSK transmitter */
if (pCid->df == DXS_CID_DATA_FSK)
DXS_CID_FSK_Stop(pCh);
/* Attempt to stop tone */
dxs_tone_stop(pCh);
/* Restore active line mode */
DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
/* Unmute channel */
if (pCid->need_unmute)
{
if (dxs_pcm_ch_mute(pCh, 0) == DXS_statusOk)
pCid->need_unmute = 0;
}
/* inform application */
dxs_event.dev = pCh->pParent->nDevNum;
dxs_event.ch = pCh->nCh;
dxs_event.id = DXS_EVENT_CID_SEQ_ERROR;
dxs_event.data.cid_err = DXS_EVENT_CID_HOOK_STATE;
DXS_EventDispatch(pCh->pParent, &dxs_event);
pthread_detach(pCid->thrd);
sem_post(&pCid->sema);
return DXS_statusOk;
}
/* ========================================================================== */
/* ETSI protocol */
/* ========================================================================== */
/* CID SM states - ETSI */
static int32_t dxs_cid_etsi_init(void *arg);
static int32_t dxs_cid_etsi_dtas(void *arg);
static int32_t dxs_cid_etsi_ring(void *arg);
static int32_t dxs_cid_etsi_after_lr(void *arg);
static int32_t dxs_cid_dtmf_off(void *arg);
static int32_t dxs_cid_dtmf_on(void *arg);
static int32_t dxs_cid_etsi_after_alert(void *arg);
static int32_t dxs_cid_etsi_data_xmit(void *arg);
static int32_t dxs_cid_etsi_after_data_xmit(void *arg);
/**
dxs_cid_etsi_init
\param arg
\return
- none
*/
static int32_t dxs_cid_etsi_init(void *arg)
{
int32_t ret = DXS_statusOk;
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
if (pCid->as == DXS_CID_AS_DTAS || pCid->as == DXS_CID_AS_LR_DTAS)
{
dxs_tone_config(pCh, DXS_CID_DTAS_LEVEL1,
DXS_CID_DTAS_LEVEL2,
DXS_CID_DTAS_FREQ1,
DXS_CID_DTAS_FREQ2, 0, 0);
}
if (pCid->as == DXS_CID_AS_NONE)
{
ret = DXS_SDD_LineModeSet(pCh,
DXS_LINE_FEED_RING_BURST ^ pCid->polarity_initial);
pCid->timeout = pCid->tm_etsi.lring;
pCid->cid_state = dxs_cid_etsi_ring;
}
else if (pCid->as == DXS_CID_AS_DTAS)
{
dxs_tone_start(pCh);
pCid->timeout = pCid->tm_etsi.dtas;
pCid->cid_state = dxs_cid_etsi_dtas;
}
else if (pCid->as == DXS_CID_AS_LR_DTAS)
{
DXS_SDD_LineModeSet(pCh,
DXS_LINE_FEED_ACTIVE_REVPOL ^ pCid->polarity_initial);
pCid->timeout = pCid->tm_etsi.T0;
pCid->cid_state = dxs_cid_etsi_after_lr;
}
else if (pCid->as == DXS_CID_AS_ETSI_DTMF)
{
DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE_REVPOL ^ pCid->polarity_initial);
pCid->timeout = pCid->tm_etsi.T0dtmf;
pCid->cid_state = dxs_cid_etsi_after_alert;
}
else if (pCid->as == DXS_CID_AS_RPAS)
{
ret = DXS_SDD_LineModeSet(pCh,
DXS_LINE_FEED_RING_BURST ^ pCid->polarity_initial);
pCid->timeout = pCid->tm_etsi.rpas;
pCid->cid_state = dxs_cid_etsi_ring;
}
return ret;
}
/**
dxs_cid_etsi_dtas
\param arg
\return
- none
*/
static int32_t dxs_cid_etsi_dtas(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
dxs_tone_stop(pCh);
if (pCid->as == DXS_CID_AS_DTAS)
pCid->timeout = pCid->tm_etsi.T4;
else if (pCid->as == DXS_CID_AS_LR_DTAS)
pCid->timeout = pCid->tm_etsi.T1;
pCid->cid_state = dxs_cid_etsi_after_alert;
return DXS_statusOk;
}
/**
dxs_cid_etsi_ring
\param arg
\return
- none
*/
static int32_t dxs_cid_etsi_ring(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
if (pCid->as == DXS_CID_AS_NONE)
pCid->timeout = pCid->tm_etsi.T5;
else if (pCid->as == DXS_CID_AS_RPAS)
pCid->timeout = pCid->tm_etsi.T3;
pCid->cid_state = dxs_cid_etsi_after_alert;
return DXS_statusOk;
}
/**
dxs_cid_etsi_after_lr
\param arg
\return
- none
*/
static int32_t dxs_cid_etsi_after_lr(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
dxs_tone_start(pCh);
pCid->timeout = pCid->tm_etsi.dtas;
pCid->cid_state = dxs_cid_etsi_dtas;
return DXS_statusOk;
}
/**
Silent betwee 2 DTMF digits
\param arg
\return
- DXS_status_t
*/
int32_t dxs_cid_dtmf_off(void *arg) //YanJC
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
/* stop DTMF tone */
dxs_tone_stop(pCh);
pCid->timeout = pCid->tm_etsi.Tdtmf; /* */
pCid->cid_state = dxs_cid_dtmf_on;
return DXS_statusOk;
}
/**
Send next DTMF digit
\param arg
\return
- DXS_status_t
*/
int32_t dxs_cid_dtmf_on(void *arg) //YanJC
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
uint8_t digi = pCid->xmit_buffer[pCid->xmit_buffer[1]];
if (pCid->xmit_length > pCid->xmit_buffer[1])
{
pCid->xmit_buffer[1] += 1;
/* send one digit */
dxs_tone_config(pCh, dtmf[digi].level1, dtmf[digi].level2, dtmf[digi].freq1, dtmf[digi].freq2, 0, 0);
dxs_tone_start(pCh);
pCid->timeout = pCid->tm_etsi.Tdtmf; /* */
pCid->cid_state = dxs_cid_dtmf_off;
}
else
{
DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
/* all digits over. */
pCid->timeout = pCid->tm_etsi.T2dtmf;
pCid->cid_state = dxs_cid_etsi_after_data_xmit;
}
return DXS_statusOk;
}
/**
dxs_cid_etsi_after_alert
\param arg
\return
- none
*/
static int32_t dxs_cid_etsi_after_alert(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
if (pCid->df == DXS_CID_DATA_FSK)
{
/* call FSK transmitter */
DXS_CID_FSK_Start(pCh, DXS_CID_FSK_V23_ITU_T, 1, pCid->xmit_buffer,
pCid->xmit_length);
pCid->timeout = 6000; /* just some big value, TODO: reconfirm */
pCid->cid_state = dxs_cid_etsi_data_xmit;
}
else if (pCid->df == DXS_CID_DATA_DTMF)
{
/* call DTMF transmitter */
dxs_cid_dtmf_on((void *)pCh);
}
return DXS_statusOk;
}
/**
dxs_cid_etsi_data_xmit
\param arg
\return
- none
*/
static int32_t dxs_cid_etsi_data_xmit(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
if (pCid->as == DXS_CID_AS_NONE)
pCid->timeout = pCid->tm_etsi.T6;
else
pCid->timeout = pCid->tm_etsi.T2;
pCid->cid_state = dxs_cid_etsi_after_data_xmit;
return DXS_statusOk;
}
/**
dxs_cid_etsi_after_data_xmit
\param arg
\return
- none
*/
static int32_t dxs_cid_etsi_after_data_xmit(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
if (pCid->as == DXS_CID_AS_LR_DTAS)
{
/* restore line polarity */
DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
}
pCid->timeout = 0;
pCid->cid_state = dxs_cid_sm_fin;
return DXS_statusOk;
}
/* CID type2 SM states - ETSI */
static int32_t dxs_cid_etsi_type2_init(void *arg);
static int32_t dxs_cid_etsi_type2_silence(void *arg);
static int32_t dxs_cid_etsi_type2_as(void *arg);
static int32_t dxs_cid_etsi_type2_wait_ack(void *arg);
static int32_t dxs_cid_etsi_type2_before_data_xmit(void *arg);
static int32_t dxs_cid_etsi_type2_data_xmit(void *arg);
/**
dxs_cid_etsi_type2_init
\param arg
\return
- none
*/
static int32_t dxs_cid_etsi_type2_init(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
dxs_tone_config(pCh, DXS_CID_DTAS_LEVEL1,
DXS_CID_DTAS_LEVEL2,
DXS_CID_DTAS_FREQ1,
DXS_CID_DTAS_FREQ2, 0, 0);
pCid->timeout = pCid->tm_etsi.t2_T10;
pCid->cid_state = dxs_cid_etsi_type2_silence;
return DXS_statusOk;
}
/**
dxs_cid_etsi_type2_silence
\param arg
\return
- none
*/
static int32_t dxs_cid_etsi_type2_silence(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
dxs_tone_start(pCh);
pCid->timeout = pCid->tm_etsi.t2_dtas;
pCid->cid_state = dxs_cid_etsi_type2_as;
return DXS_statusOk;
}
/**
dxs_cid_etsi_type2_as
\param arg
\return
- none
*/
static int32_t dxs_cid_etsi_type2_as(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
dxs_tone_stop(pCh);
pCid->timeout = pCid->tm_etsi.t2_T14;
pCid->cid_state = dxs_cid_etsi_type2_wait_ack;
return DXS_statusOk;
}
/**
dxs_cid_etsi_type2_wait_ack
\param arg
\return
- none
*/
static int32_t dxs_cid_etsi_type2_wait_ack(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
if (pCid->ack_detect)
{
pCid->ack_detect = 0;
pCid->timeout = pCid->tm_etsi.t2_T12;
pCid->cid_state = dxs_cid_etsi_type2_before_data_xmit;
}
else
{
/* Go to timeout state */
pCid->timeout = pCid->tm_etsi.t2_T9;
pCid->cid_state = dxs_cid_sm_err_timeout;
}
return DXS_statusOk;
}
/**
dxs_cid_etsi_type2_before_data_xmit
\param arg
\return
- none
*/
static int32_t dxs_cid_etsi_type2_before_data_xmit(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
/* call FSK transmitter */
DXS_CID_FSK_Start(pCh, DXS_CID_FSK_V23_ITU_T, 1, pCid->xmit_buffer,
pCid->xmit_length);
pCid->timeout = 6000; /* just some big value, TODO: reconfirm */
pCid->cid_state = dxs_cid_etsi_type2_data_xmit;
return DXS_statusOk;
}
/**
dxs_cid_etsi_type2_data_xmit
\param arg
\return
- none
*/
static int32_t dxs_cid_etsi_type2_data_xmit(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
pCid->timeout = pCid->tm_etsi.t2_T13;
pCid->cid_state = dxs_cid_sm_fin;
return DXS_statusOk;
}
/* ========================================================================== */
/* ========================================================================== */
/* TELCORDIA protocol */
/* ========================================================================== */
/* CID SM states - Telcordia */
static int32_t dxs_cid_tc_init(void *arg);
static int32_t dxs_cid_tc_alert(void *arg);
static int32_t dxs_cid_tc_after_alert(void *arg);
static int32_t dxs_cid_tc_data_xmit(void *arg);
static int32_t dxs_cid_dtmf_off_tc(void *arg);
static int32_t dxs_cid_dtmf_on_tc(void *arg);
/**
dxs_cid_tc_init
\param arg
\return
- none
*/
static int32_t dxs_cid_tc_init(void *arg)
{
int32_t ret = DXS_statusOk;
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
if (pCid->as == DXS_CID_AS_OSI)
{
DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_DISABLED);
pCid->timeout = pCid->tm_tc.osi;
}
else if (pCid->as == DXS_CID_AS_TELCORDIA_DTMF)
{
DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE_REVPOL ^ pCid->polarity_initial);
pCid->timeout = pCid->tm_tc.T0dtmf;
pCid->cid_state = dxs_cid_tc_after_alert;
}
else /* DXS_CID_AS_NONE */
{
ret = DXS_SDD_LineModeSet(pCh,
DXS_LINE_FEED_RING_BURST ^ pCid->polarity_initial);
pCid->timeout = pCid->tm_tc.lring;
}
pCid->cid_state = dxs_cid_tc_alert;
return ret;
}
/**
Silent betwee 2 DTMF digits
\param arg
\return
- DXS_status_t
*/
int32_t dxs_cid_dtmf_off_tc(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
/* stop DTMF tone */
dxs_tone_stop(pCh);
pCid->timeout = pCid->tm_tc.Tdtmf;
pCid->cid_state = dxs_cid_dtmf_on_tc;
return DXS_statusOk;
}
/**
Send next DTMF digit
\param arg
\return
- DXS_status_t
*/
int32_t dxs_cid_dtmf_on_tc(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
uint8_t digi = pCid->xmit_buffer[pCid->xmit_buffer[1]];
if (pCid->xmit_length > pCid->xmit_buffer[1])
{
pCid->xmit_buffer[1] += 1;
/* send one digit */
dxs_tone_config(pCh, dtmf[digi].level1, dtmf[digi].level2, dtmf[digi].freq1, dtmf[digi].freq2, 0, 0);
dxs_tone_start(pCh);
pCid->timeout = pCid->tm_tc.Tdtmf;
pCid->cid_state = dxs_cid_dtmf_off_tc;
}
else
{
DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
/* all digits over. */
pCid->timeout = pCid->tm_tc.T2dtmf;
pCid->cid_state = dxs_cid_etsi_after_data_xmit;
}
return DXS_statusOk;
}
/**
dxs_cid_tc_alert
\param arg
\return
- none
*/
static int32_t dxs_cid_tc_alert(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
if (pCid->as == DXS_CID_AS_OSI)
pCid->timeout = pCid->tm_tc.T1;
else /* DXS_CID_AS_NONE */
pCid->timeout = pCid->tm_tc.T0;
pCid->cid_state = dxs_cid_tc_after_alert;
return DXS_statusOk;
}
/**
dxs_cid_tc_after_alert
\param arg
\return
- none
*/
static int32_t dxs_cid_tc_after_alert(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
if (pCid->df == DXS_CID_DATA_FSK)
{
/* call FSK transmitter */
DXS_CID_FSK_Start(pCh, DXS_CID_FSK_V23_BEL202, 1, pCid->xmit_buffer,
pCid->xmit_length);
pCid->timeout = 6000; /* just some big value, TODO: reconfirm */
pCid->cid_state = dxs_cid_tc_data_xmit;
}
else if (pCid->df == DXS_CID_DATA_DTMF)
{
/* call DTMF transmitter */
dxs_cid_dtmf_on_tc((void *)pCh);
}
return DXS_statusOk;
}
/**
dxs_cid_tc_data_xmit
\param arg
\return
- none
*/
static int32_t dxs_cid_tc_data_xmit(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
pCid->timeout = pCid->tm_tc.T2;
pCid->cid_state = dxs_cid_sm_fin;
return DXS_statusOk;
}
/* CID type2 SM states - Telcordia */
static int32_t dxs_cid_tc_type2_init(void *arg);
static int32_t dxs_cid_tc_type2_osi_first(void *arg);
static int32_t dxs_cid_tc_type2_silence(void *arg);
static int32_t dxs_cid_tc_type2_sas(void *arg);
static int32_t dxs_cid_tc_type2_as_transition(void *arg);
static int32_t dxs_cid_tc_type2_cas(void *arg);
static int32_t dxs_cid_tc_type2_wait_ack(void *arg);
static int32_t dxs_cid_tc_type2_before_data_xmit(void *arg);
static int32_t dxs_cid_tc_type2_data_xmit(void *arg);
static int32_t dxs_cid_tc_type2_osi_last(void *arg);
/**
dxs_cid_tc_type2_init
\param arg
\return
- none
*/
static int32_t dxs_cid_tc_type2_init(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
if (pCid->tm_tc.t2_osi)
{
DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_DISABLED);
pCid->timeout = pCid->tm_tc.t2_osi;
pCid->cid_state = dxs_cid_tc_type2_osi_first;
}
else
{
pCid->timeout = pCid->tm_tc.t2_W;
pCid->cid_state = dxs_cid_tc_type2_silence;
}
return DXS_statusOk;
}
/**
dxs_cid_tc_type2_osi_first
\param arg
\return
- none
*/
static int32_t dxs_cid_tc_type2_osi_first(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
pCid->hook_block = 1;
DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
pCid->timeout = pCid->tm_tc.t2_W;
pCid->cid_state = dxs_cid_tc_type2_silence;
return DXS_statusOk;
}
/**
dxs_cid_tc_type2_silence
\param arg
\return
- none
*/
static int32_t dxs_cid_tc_type2_silence(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
pCid->hook_block = 0;
if (pCid->tm_tc.t2_X)
dxs_tone_start(pCh);
pCid->timeout = pCid->tm_tc.t2_X;
pCid->cid_state = dxs_cid_tc_type2_sas;
return DXS_statusOk;
}
/**
dxs_cid_tc_type2_sas
\param arg
\return
- none
*/
static int32_t dxs_cid_tc_type2_sas(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
if (pCid->tm_tc.t2_X)
dxs_tone_stop(pCh);
pCid->timeout = pCid->tm_tc.t2_X1;
pCid->cid_state = dxs_cid_tc_type2_as_transition;
return DXS_statusOk;
}
/**
dxs_cid_tc_type2_as_transition
\param arg
\return
- none
*/
static int32_t dxs_cid_tc_type2_as_transition(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
dxs_tone_config(pCh, DXS_CID_DTAS_LEVEL1,
DXS_CID_DTAS_LEVEL2,
DXS_CID_DTAS_FREQ1,
DXS_CID_DTAS_FREQ2, 0, 0);
dxs_tone_start(pCh);
pCid->timeout = pCid->tm_tc.t2_Y;
pCid->cid_state = dxs_cid_tc_type2_cas;
return DXS_statusOk;
}
/**
dxs_cid_tc_type2_cas
\param arg
\return
- none
*/
static int32_t dxs_cid_tc_type2_cas(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
dxs_tone_stop(pCh);
pCid->timeout = pCid->tm_tc.t2_T1;
pCid->cid_state = dxs_cid_tc_type2_wait_ack;
return DXS_statusOk;
}
/**
dxs_cid_tc_type2_wait_ack
\param arg
\return
- none
*/
static int32_t dxs_cid_tc_type2_wait_ack(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
if (pCid->ack_detect)
{
pCid->ack_detect = 0;
pCid->timeout = pCid->tm_tc.t2_Q;
pCid->cid_state = dxs_cid_tc_type2_before_data_xmit;
}
else
{
/* Go to timeout state */
pCid->timeout = 0;
pCid->cid_state = dxs_cid_sm_err_timeout;
}
return DXS_statusOk;
}
/**
dxs_cid_tc_type2_before_data_xmit
\param arg
\return
- none
*/
static int32_t dxs_cid_tc_type2_before_data_xmit(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
/* call FSK transmitter */
DXS_CID_FSK_Start(pCh, DXS_CID_FSK_V23_BEL202, 1, pCid->xmit_buffer,
pCid->xmit_length);
pCid->timeout = 6000; /* just some big value, TODO: reconfirm */
pCid->cid_state = dxs_cid_tc_type2_data_xmit;
return DXS_statusOk;
}
/**
dxs_cid_tc_type2_data_xmit
\param arg
\return
- none
*/
static int32_t dxs_cid_tc_type2_data_xmit(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
if (pCid->tm_tc.t2_osi)
{
DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_DISABLED);
pCid->timeout = pCid->tm_tc.t2_osi;
pCid->cid_state = dxs_cid_tc_type2_osi_last;
}
else
{
pCid->timeout = pCid->tm_tc.t2_S;
pCid->cid_state = dxs_cid_sm_fin;
}
return DXS_statusOk;
}
/**
dxs_cid_tc_type2_osi_last
\param arg
\return
- none
*/
static int32_t dxs_cid_tc_type2_osi_last(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
pCid->hook_block = 1;
DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
pCid->timeout = pCid->tm_tc.t2_S;
pCid->cid_state = dxs_cid_sm_fin;
return DXS_statusOk;
}
/* ========================================================================== */
/* ========================================================================== */
/* BT protocol */
/* ========================================================================== */
/* CID SM states - BT */
static int32_t dxs_cid_bt_init(void *arg);
static int32_t dxs_cid_bt_after_lr(void *arg);
static int32_t dxs_cid_bt_dtas(void *arg);
static int32_t dxs_cid_bt_after_alert(void *arg);
static int32_t dxs_cid_bt_data_xmit(void *arg);
static int32_t dxs_cid_bt_after_data_xmit(void *arg);
/**
dxs_cid_bt_init
\param arg
\return
- none
*/
static int32_t dxs_cid_bt_init(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
dxs_tone_config(pCh, DXS_CID_DTAS_LEVEL1,
DXS_CID_DTAS_LEVEL2,
DXS_CID_DTAS_FREQ1,
DXS_CID_DTAS_FREQ2, 0, 0);
DXS_SDD_LineModeSet(pCh,
DXS_LINE_FEED_ACTIVE_REVPOL ^ pCid->polarity_initial);
pCid->timeout = pCid->tm_bt.T0;
pCid->cid_state = dxs_cid_bt_after_lr;
return DXS_statusOk;
}
/**
dxs_cid_bt_after_lr
\param arg
\return
- none
*/
static int32_t dxs_cid_bt_after_lr(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
dxs_tone_start(pCh);
pCid->timeout = pCid->tm_bt.dtas;
pCid->cid_state = dxs_cid_bt_dtas;
return DXS_statusOk;
}
/**
dxs_cid_bt_dtas
\param arg
\return
- none
*/
static int32_t dxs_cid_bt_dtas(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
dxs_tone_stop(pCh);
pCid->timeout = pCid->tm_bt.T1;
pCid->cid_state = dxs_cid_bt_after_alert;
return DXS_statusOk;
}
/**
dxs_cid_bt_after_alert
\param arg
\return
- none
*/
static int32_t dxs_cid_bt_after_alert(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
/* call FSK transmitter */
DXS_CID_FSK_Start(pCh, DXS_CID_FSK_V23_ITU_T, 1, pCid->xmit_buffer,
pCid->xmit_length);
pCid->timeout = 6000; /* just some big value, TODO: reconfirm */
pCid->cid_state = dxs_cid_bt_data_xmit;
return DXS_statusOk;
}
/**
dxs_cid_bt_data_xmit
\param arg
\return
- none
*/
static int32_t dxs_cid_bt_data_xmit(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
pCid->timeout = pCid->tm_bt.T2;
pCid->cid_state = dxs_cid_bt_after_data_xmit;
return DXS_statusOk;
}
/**
dxs_cid_bt_after_data_xmit
\param arg
\return
- none
*/
static int32_t dxs_cid_bt_after_data_xmit(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
/* restore line polarity */
DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
pCid->timeout = 0;
pCid->cid_state = dxs_cid_sm_fin;
return DXS_statusOk;
}
/* CID type2 SM states - BT */
static int32_t dxs_cid_bt_type2_init(void *arg);
static int32_t dxs_cid_bt_type2_silence(void *arg);
static int32_t dxs_cid_bt_type2_as(void *arg);
static int32_t dxs_cid_bt_type2_wait_ack(void *arg);
static int32_t dxs_cid_bt_type2_before_data_xmit(void *arg);
static int32_t dxs_cid_bt_type2_data_xmit(void *arg);
/**
dxs_cid_bt_type2_init
\param arg
\return
- none
*/
static int32_t dxs_cid_bt_type2_init(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
dxs_tone_config(pCh, DXS_CID_DTAS_LEVEL1,
DXS_CID_DTAS_LEVEL2,
DXS_CID_DTAS_FREQ1,
DXS_CID_DTAS_FREQ2, 0, 0);
pCid->timeout = pCid->tm_bt.t2_T0;
pCid->cid_state = dxs_cid_bt_type2_silence;
return DXS_statusOk;
}
/**
dxs_cid_bt_type2_silence
\param arg
\return
- none
*/
static int32_t dxs_cid_bt_type2_silence(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
dxs_tone_start(pCh);
pCid->timeout = pCid->tm_bt.t2_dtas;
pCid->cid_state = dxs_cid_bt_type2_as;
return DXS_statusOk;
}
/**
dxs_cid_bt_type2_as
\param arg
\return
- none
*/
static int32_t dxs_cid_bt_type2_as(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
dxs_tone_stop(pCh);
pCid->timeout = pCid->tm_bt.t2_ack;
pCid->cid_state = dxs_cid_bt_type2_wait_ack;
return DXS_statusOk;
}
/**
dxs_cid_bt_type2_wait_ack
\param arg
\return
- none
*/
static int32_t dxs_cid_bt_type2_wait_ack(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
if (pCid->ack_detect)
{
pCid->ack_detect = 0;
pCid->timeout = pCid->tm_bt.t2_T1;
pCid->cid_state = dxs_cid_bt_type2_before_data_xmit;
}
else
{
/* Go to timeout state */
pCid->timeout = 0;
pCid->cid_state = dxs_cid_sm_err_timeout;
}
return DXS_statusOk;
}
/**
dxs_cid_bt_type2_before_data_xmit
\param arg
\return
- none
*/
static int32_t dxs_cid_bt_type2_before_data_xmit(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
/* call FSK transmitter */
DXS_CID_FSK_Start(pCh, DXS_CID_FSK_V23_ITU_T, 1, pCid->xmit_buffer,
pCid->xmit_length);
pCid->timeout = 6000; /* just some big value, TODO: reconfirm */
pCid->cid_state = dxs_cid_bt_type2_data_xmit;
return DXS_statusOk;
}
/**
dxs_cid_bt_type2_data_xmit
\param arg
\return
- none
*/
static int32_t dxs_cid_bt_type2_data_xmit(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
pCid->timeout = pCid->tm_bt.t2_T2;
pCid->cid_state = dxs_cid_sm_fin;
return DXS_statusOk;
}
/* ========================================================================== */
/* ========================================================================== */
/* NTT protocol */
/* ========================================================================== */
/* CID SM states - NTT */
static int32_t dxs_cid_ntt_init(void *arg);
static int32_t dxs_cid_ntt_car_off(void *arg);
static int32_t dxs_cid_ntt_car_on(void *arg);
static int32_t dxs_cid_ntt_timeout(void *arg);
static int32_t dxs_cid_ntt_after_offhook(void *arg);
static int32_t dxs_cid_ntt_data_xmit(void *arg);
static int32_t dxs_cid_ntt_wait_onhook(void *arg);
static int32_t dxs_cid_ntt_after_onhook(void *arg);
/**
dxs_cid_ntt_init
\param arg
\return
- none
*/
static int32_t dxs_cid_ntt_init(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
/* set line feeding modes and proceed with SM */
DXS_SDD_LineModeSet(pCh,
DXS_LINE_FEED_ACTIVE_REVPOL ^ pCid->polarity_initial);
pCid->ntt_timeout = pCid->tm_ntt.T1;
pCid->timeout = pCid->tm_ntt.T0;
pCid->cid_state = dxs_cid_ntt_car_off;
return DXS_statusOk;
}
/**
dxs_cid_ntt_car_off
\param arg
\return
- none
*/
static int32_t dxs_cid_ntt_car_off(void *arg)
{
int32_t ret = DXS_statusOk;
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
if (pCid->hook_state == DXS_CID_HOOK_STATE_OFFHOOK)
{
pCid->hook_state_exp = DXS_CID_HOOK_STATE_OFFHOOK;
pCid->cid_state = dxs_cid_ntt_after_offhook;
pCid->timeout = pCid->tm_ntt.T2;
}
else
{
pCid->hook_state_exp =
(DXS_CID_HOOK_STATE_OFFHOOK | DXS_CID_HOOK_STATE_ONHOOK);
if (pCid->ntt_timeout <= pCid->tm_ntt.CARon)
{
/* Timeout - terminate CID */
pCid->timeout = 0;
pCid->cid_state = dxs_cid_ntt_timeout;
}
else
{
ret = DXS_SDD_LineModeSet(pCh,
DXS_LINE_FEED_RINGING_REVPOL ^ pCid->polarity_initial);
pCid->ntt_timeout -= pCid->timeout;
pCid->timeout = pCid->tm_ntt.CARon;
pCid->cid_state = dxs_cid_ntt_car_on;
}
}
return ret;
}
/**
dxs_cid_ntt_car_on
\param arg
\return
- none
*/
static int32_t dxs_cid_ntt_car_on(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
if (pCid->hook_state == DXS_CID_HOOK_STATE_OFFHOOK)
{
pCid->hook_state_exp = DXS_CID_HOOK_STATE_OFFHOOK;
pCid->cid_state = dxs_cid_ntt_after_offhook;
pCid->timeout = pCid->tm_ntt.T2;
}
else
{
DXS_SDD_LineModeSet(pCh,
DXS_LINE_FEED_ACTIVE_REVPOL ^ pCid->polarity_initial);
if (pCid->ntt_timeout <= pCid->tm_ntt.CARoff)
{
/* Timeout - terminate CID */
pCid->timeout = 0;
pCid->cid_state = dxs_cid_ntt_timeout;
}
else
{
pCid->ntt_timeout -= pCid->timeout;
pCid->timeout = pCid->tm_ntt.CARoff;
pCid->cid_state = dxs_cid_ntt_car_off;
}
}
return DXS_statusOk;
}
/**
dxs_cid_ntt_timeout
\param arg
\return
- none
*/
static int32_t dxs_cid_ntt_timeout(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
pCid->timeout = 0;
pCid->cid_state = dxs_cid_sm_err_timeout;
return DXS_statusOk;
}
/**
dxs_cid_ntt_after_offhook
\param arg
\return
- none
*/
static int32_t dxs_cid_ntt_after_offhook(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
DXS_CID_FSK_Start(pCh, DXS_CID_FSK_V23_ITU_T, 1, pCid->xmit_buffer,
pCid->xmit_length);
pCid->timeout = 6000; /* just some big value, TODO: reconfirm */
pCid->cid_state = dxs_cid_ntt_data_xmit;
return DXS_statusOk;
}
/**
dxs_cid_ntt_data_xmit
\param arg
\return
- none
*/
static int32_t dxs_cid_ntt_data_xmit(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
/* set any expected hook state to be able to report timeout if it occurs */
pCid->hook_state_exp =
(DXS_CID_HOOK_STATE_OFFHOOK | DXS_CID_HOOK_STATE_ONHOOK);
pCid->timeout = pCid->tm_ntt.T3;
pCid->cid_state = dxs_cid_ntt_wait_onhook;
return DXS_statusOk;
}
/**
dxs_cid_ntt_wait_onhook
\param arg
\return
- none
*/
static int32_t dxs_cid_ntt_wait_onhook(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
if (pCid->hook_state == DXS_CID_HOOK_STATE_ONHOOK)
{
pCid->timeout = pCid->tm_ntt.T4;
pCid->cid_state = dxs_cid_ntt_after_onhook;
}
else
{
/* Report previous off-hook event which was hidden by CID NTT */
#ifndef DXS_FEAT_HSM
DXS_Event_t dxs_event = {0};
dxs_event.dev = pCh->pParent->nDevNum;
dxs_event.ch = pCh->nCh;
dxs_event.id = DXS_EVENT_FXS_OFFHOOK;
DXS_EventDispatch(pCh->pParent, &dxs_event);
#else
DXS_Dial_HookEvent(pCh, 1, pCid->hook_timestamp);
#endif
/* Go to timeout state */
pCid->timeout = 0;
pCid->cid_state = dxs_cid_ntt_timeout;
}
return DXS_statusOk;
}
/**
dxs_cid_ntt_after_onhook
\param arg
\return
- none
*/
static int32_t dxs_cid_ntt_after_onhook(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
/* NTT defines that line polarity should be restored after real off-hook,
however we restore polarity right here so the demo application can switch to
RING_BURST without errors. This is the only purpose of this state -
restore polarity, otherwise this state can be removed. */
DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
pCid->timeout = 0;
pCid->cid_state = dxs_cid_sm_fin;
return DXS_statusOk;
}
/* CID type2 SM states - NTT */
static int32_t dxs_cid_ntt_type2_init(void *arg);
static int32_t dxs_cid_ntt_type2_silence(void *arg);
static int32_t dxs_cid_ntt_type2_as_first(void *arg);
static int32_t dxs_cid_ntt_type2_as_pause(void *arg);
static int32_t dxs_cid_ntt_type2_as_second(void *arg);
static int32_t dxs_cid_ntt_type2_before_data_xmit(void *arg);
static int32_t dxs_cid_ntt_type2_data_xmit(void *arg);
/**
dxs_cid_ntt_type2_init
\param arg
\return
- none
*/
static int32_t dxs_cid_ntt_type2_init(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
pCid->timeout = pCid->tm_ntt.t2_T0;
pCid->cid_state = dxs_cid_ntt_type2_silence;
return DXS_statusOk;
}
/**
dxs_cid_ntt_type2_silence
\param arg
\return
- none
*/
static int32_t dxs_cid_ntt_type2_silence(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
dxs_tone_config(pCh, DXS_CID_NTT_TYPE2_ATONE_LEVEL1,
DXS_CID_NTT_TYPE2_ATONE_LEVEL2,
DXS_CID_NTT_TYPE2_ATONE_FREQ1,
DXS_CID_NTT_TYPE2_ATONE_FREQ2, 0, 0);
dxs_tone_start(pCh);
pCid->timeout = pCid->tm_ntt.t2_as_first;
pCid->cid_state = dxs_cid_ntt_type2_as_first;
return DXS_statusOk;
}
/**
dxs_cid_ntt_type2_as_first
\param arg
\return
- none
*/
static int32_t dxs_cid_ntt_type2_as_first(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
dxs_tone_stop(pCh);
pCid->timeout = pCid->tm_ntt.t2_as_pause;
pCid->cid_state = dxs_cid_ntt_type2_as_pause;
return DXS_statusOk;
}
/**
dxs_cid_ntt_type2_as_pause
\param arg
\return
- none
*/
static int32_t dxs_cid_ntt_type2_as_pause(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
dxs_tone_config(pCh, DXS_CID_NTT_TYPE2_ATONE_LEVEL1,
DXS_CID_NTT_TYPE2_ATONE_LEVEL2,
DXS_CID_NTT_TYPE2_ATONE_FREQ3,
DXS_CID_NTT_TYPE2_ATONE_FREQ2, 0, 0);
dxs_tone_start(pCh);
pCid->timeout = pCid->tm_ntt.t2_as_second;
pCid->cid_state = dxs_cid_ntt_type2_as_second;
return DXS_statusOk;
}
/**
dxs_cid_ntt_type2_as_second
\param arg
\return
- none
*/
static int32_t dxs_cid_ntt_type2_as_second(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
dxs_tone_stop(pCh);
pCid->timeout = pCid->tm_ntt.t2_T1;
pCid->cid_state = dxs_cid_ntt_type2_before_data_xmit;
return DXS_statusOk;
}
/**
dxs_cid_ntt_type2_before_data_xmit
\param arg
\return
- none
*/
static int32_t dxs_cid_ntt_type2_before_data_xmit(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
/* call FSK transmitter */
DXS_CID_FSK_Start(pCh, DXS_CID_FSK_V23_ITU_T, 1, pCid->xmit_buffer,
pCid->xmit_length);
pCid->timeout = 6000; /* just some big value, TODO: reconfirm */
pCid->cid_state = dxs_cid_ntt_type2_data_xmit;
return DXS_statusOk;
}
/**
dxs_cid_ntt_type2_data_xmit
\param arg
\return
- none
*/
static int32_t dxs_cid_ntt_type2_data_xmit(void *arg)
{
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
pCid->timeout = pCid->tm_ntt.t2_T2;
pCid->cid_state = dxs_cid_sm_fin;
return DXS_statusOk;
}
/* ========================================================================== */
/**
CID state machine execution thread
\param arg
\return
- none
*/
static void *dxs_cid_thread (void *arg)
{
int32_t err;
DXS_CHANNEL_t *pCh = (DXS_CHANNEL_t *)arg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
sem_init(&pCid->sema, 0, 0);
pCid->complete = 0;
pCid->ret = DXS_statusOk;
while (!pCid->complete)
{
/* check hook state */
if (!(pCid->hook_state & pCid->hook_state_exp))
pCid->cid_state = dxs_cid_sm_err_hook;
/* action */
if ((err = pCid->cid_state((void *)pCh)) != DXS_statusOk)
{
pCid->complete = 1;
pCid->ret = err;
/* inform application on this particular error */
if (err == DXS_statusDcDcRingCapsExceeded)
{
DXS_Event_t dxs_event =
{
.dev = pCh->pParent->nDevNum,
.ch = pCh->nCh,
.id = DXS_EVENT_CID_SEQ_ERROR,
.data.cid_err = DXS_EVENT_CID_HW_RING_LIMIT
};
DXS_EventDispatch(pCh->pParent, &dxs_event);
}
/* Restore active line mode */
DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
/* Unmute channel */
if (pCid->need_unmute)
{
if (dxs_pcm_ch_mute(pCh, 0) == DXS_statusOk)
pCid->need_unmute = 0;
}
pthread_detach(pCid->thrd);
break;
}
/* waiting */
dxs_cid_wait(pCid);
}
sem_destroy(&pCid->sema);
pthread_exit((void *)(&pCid->ret));
}
/**
Initialize CID context
\param pCh - pointer to \ref DXS_CHANNEL_t
\param std - CID standard \ref DXS_CID_Std_t
\param as - alert signal \ref DXS_CID_AS_t
\param fmt - data format \ref DXS_CID_DATA_FMT_t
\param dtmf_ack_idx - dtmf index for acknowledgment (type2 only)
\return
- DXS_status_t
*/
int32_t DXS_CID_Init(DXS_CHANNEL_t *pCh, DXS_CID_Std_t std, DXS_CID_AS_t as,
DXS_CID_DATA_FMT_t fmt, uint8_t dtmf_ack_idx)
{
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
/* Block if CID SM is running already */
if ((pCid->magic == DXS_CID_CTX_MAGIC) && (!pCid->complete))
{
DXS_RETURN(DXS_statusCidInProgress);
}
switch (std)
{
case DXS_CID_STD_BT:
{
if (as != DXS_CID_AS_LR_DTAS)
{
DXS_RETURN(DXS_statusCidInvalidAlertSignal);
}
pCid->len_check = dxs_cid_param_length_check_bt;
break;
}
case DXS_CID_STD_NTT:
{
if (as != DXS_CID_AS_CAR)
{
DXS_RETURN(DXS_statusCidInvalidAlertSignal);
}
pCid->len_check = dxs_cid_param_length_check_ntt;
break;
}
case DXS_CID_STD_ETSI:
{
if ((as == DXS_CID_AS_CAR) || (as == DXS_CID_AS_OSI))
{
DXS_RETURN(DXS_statusCidInvalidAlertSignal);
}
pCid->len_check = dxs_cid_param_length_check_etsi;
break;
}
case DXS_CID_STD_TELCORDIA:
{
if ((as != DXS_CID_AS_NONE) && (as != DXS_CID_AS_OSI))
{
DXS_RETURN(DXS_statusCidInvalidAlertSignal);
}
pCid->len_check = dxs_cid_param_length_check_tc;
break;
}
default:
{
DXS_RETURN(DXS_statusCidStdNotSupported);
}
}
switch (fmt)
{
case DXS_CID_DATA_FSK:
case DXS_CID_DATA_DTMF:
break;
default:
{
DXS_RETURN(DXS_statusInvalidParam);
}
}
/* refresh message containers */
dxs_cid_msg_clearall(pCid);
pCid->magic = DXS_CID_CTX_MAGIC;
pCid->complete = 1;
pCid->std = std;
pCid->as = as;
pCid->df = fmt;
pCid->dtmf_ack_idx = dtmf_ack_idx;
/* default timers for ETSI */
pCid->tm_etsi.lring = DXS_CID_ETSI_LONG_RING_MS;
pCid->tm_etsi.dtas = DXS_CID_ETSI_DTAS_MS;
pCid->tm_etsi.rpas = DXS_CID_ETSI_RPAS_MS;
pCid->tm_etsi.T0 = DXS_CID_ETSI_T0_DEFAULT;
pCid->tm_etsi.T1 = DXS_CID_ETSI_T1_DEFAULT;
pCid->tm_etsi.T2 = DXS_CID_ETSI_T2_DEFAULT;
pCid->tm_etsi.T3 = DXS_CID_ETSI_T3_DEFAULT;
pCid->tm_etsi.T4 = DXS_CID_ETSI_T4_DEFAULT;
pCid->tm_etsi.T5 = DXS_CID_ETSI_T5_DEFAULT;
pCid->tm_etsi.T6 = DXS_CID_ETSI_T6_DEFAULT;
pCid->tm_etsi.t2_dtas = DXS_CID_ETSI_TYPE2_DTAS_MS;
pCid->tm_etsi.t2_T14 = DXS_CID_ETSI_TYPE2_T14_DEFAULT;
pCid->tm_etsi.t2_T10 = DXS_CID_ETSI_TYPE2_T10_DEFAULT;
pCid->tm_etsi.t2_T12 = DXS_CID_ETSI_TYPE2_T12_DEFAULT;
pCid->tm_etsi.t2_T13 = DXS_CID_ETSI_TYPE2_T13_DEFAULT;
pCid->tm_etsi.t2_T9 = DXS_CID_ETSI_TYPE2_T9_DEFAULT;
pCid->tm_etsi.T0dtmf = DXS_CID_ETSI_T0dtmf_DEFAULT;
pCid->tm_etsi.Tdtmf = DXS_CID_ETSI_Tdtmf_DEFAULT;
pCid->tm_etsi.T2dtmf = DXS_CID_ETSI_T2dtmf_DEFAULT;
/* default timers for Telcordia */
pCid->tm_tc.lring = DXS_CID_TELCORDIA_LONG_RING_MS;
pCid->tm_tc.osi = DXS_CID_TELCORDIA_OSI_MS;
pCid->tm_tc.T0 = DXS_CID_TELCORDIA_T0_DEFAULT;
pCid->tm_tc.T1 = DXS_CID_TELCORDIA_T1_DEFAULT;
pCid->tm_tc.T2 = DXS_CID_TELCORDIA_T2_DEFAULT;
pCid->tm_tc.t2_osi = DXS_CID_TELCORDIA_TYPE2_OSI_MS;
pCid->tm_tc.t2_W = DXS_CID_TELCORDIA_TYPE2_W_MS;
pCid->tm_tc.t2_X = DXS_CID_TELCORDIA_TYPE2_X_MS;
pCid->tm_tc.t2_X1 = DXS_CID_TELCORDIA_TYPE2_X1_MS;
pCid->tm_tc.t2_Y = DXS_CID_TELCORDIA_TYPE2_Y_MS;
pCid->tm_tc.t2_T1 = DXS_CID_TELCORDIA_TYPE2_T1_MS;
pCid->tm_tc.t2_Q = DXS_CID_TELCORDIA_TYPE2_Q_MS;
pCid->tm_tc.t2_S = DXS_CID_TELCORDIA_TYPE2_S_MS;
pCid->tm_tc.T0dtmf = DXS_CID_TELCORDIA_T0dtmf_DEFAULT;
pCid->tm_tc.Tdtmf = DXS_CID_TELCORDIA_Tdtmf_DEFAULT;
pCid->tm_tc.T2dtmf = DXS_CID_TELCORDIA_T2dtmf_DEFAULT;
/* default timers for BT */
pCid->tm_bt.dtas = DXS_CID_BT_DTAS_MS;
pCid->tm_bt.T0 = DXS_CID_BT_T0_DEFAULT;
pCid->tm_bt.T1 = DXS_CID_BT_T1_DEFAULT;
pCid->tm_bt.T2 = DXS_CID_BT_T2_DEFAULT;
pCid->tm_bt.t2_dtas = DXS_CID_BT_TYPE2_DTAS_MS;
pCid->tm_bt.t2_ack = DXS_CID_BT_TYPE2_ACK_MS;
pCid->tm_bt.t2_T0 = DXS_CID_BT_TYPE2_T0_DEFAULT;
pCid->tm_bt.t2_T1 = DXS_CID_BT_TYPE2_T1_DEFAULT;
pCid->tm_bt.t2_T2 = DXS_CID_BT_TYPE2_T2_DEFAULT;
/* default timers for NTT */
pCid->tm_ntt.CARon = DXS_CID_NTT_CARON_MS;
pCid->tm_ntt.CARoff = DXS_CID_NTT_CAROFF_MS;
pCid->tm_ntt.T0 = DXS_CID_NTT_T0_DEFAULT;
pCid->tm_ntt.T1 = DXS_CID_NTT_T1_DEFAULT;
pCid->tm_ntt.T2 = DXS_CID_NTT_T2_DEFAULT;
pCid->tm_ntt.T3 = DXS_CID_NTT_T3_DEFAULT;
pCid->tm_ntt.T4 = DXS_CID_NTT_T4_DEFAULT;
pCid->tm_ntt.t2_as_first = DXS_CID_NTT_TYPE2_AS1_MS;
pCid->tm_ntt.t2_as_pause = DXS_CID_NTT_TYPE2_AS_PAUSE_MS;
pCid->tm_ntt.t2_as_second = DXS_CID_NTT_TYPE2_AS2_MS;
pCid->tm_ntt.t2_T0 = DXS_CID_NTT_TYPE2_T0_DEFAULT;
pCid->tm_ntt.t2_T1 = DXS_CID_NTT_TYPE2_T1_DEFAULT;
pCid->tm_ntt.t2_T2 = DXS_CID_NTT_TYPE2_T2_DEFAULT;
return DXS_statusOk;
}
/**
Timers configuration
\param pCh - pointer to \ref DXS_CHANNEL_t
\param std - CID standard \ref DXS_CID_Std_t
\param pTimers - timer configuration \ref DXS_CID_Timers_t
\return
- DXS_status_t
*/
int32_t DXS_CID_TimerConfig(DXS_CHANNEL_t *pCh,
DXS_CID_Std_t std, DXS_CID_Timers_t *pTimers)
{
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
/* check if pCid is initialized */
if (pCid->magic != DXS_CID_CTX_MAGIC)
{
DXS_RETURN(DXS_statusNotInitResource);
}
if (std == DXS_CID_STD_ETSI)
{
pCid->tm_etsi.lring = pTimers->etsi.lring;
pCid->tm_etsi.dtas = pTimers->etsi.dtas;
pCid->tm_etsi.rpas = pTimers->etsi.rpas;
pCid->tm_etsi.T0 = pTimers->etsi.T0;
pCid->tm_etsi.T1 = pTimers->etsi.T1;
pCid->tm_etsi.T2 = pTimers->etsi.T2;
pCid->tm_etsi.T3 = pTimers->etsi.T3;
pCid->tm_etsi.T4 = pTimers->etsi.T4;
pCid->tm_etsi.T5 = pTimers->etsi.T5;
pCid->tm_etsi.T6 = pTimers->etsi.T6;
pCid->tm_etsi.t2_dtas = pTimers->etsi.t2_dtas;
pCid->tm_etsi.t2_T14 = pTimers->etsi.t2_T14;
pCid->tm_etsi.t2_T10 = pTimers->etsi.t2_T10;
pCid->tm_etsi.t2_T12 = pTimers->etsi.t2_T12;
pCid->tm_etsi.t2_T13 = pTimers->etsi.t2_T13;
pCid->tm_etsi.t2_T9 = pTimers->etsi.t2_T9;
}
else if (std == DXS_CID_STD_TELCORDIA)
{
pCid->tm_tc.lring = pTimers->tc.lring;
pCid->tm_tc.osi = pTimers->tc.osi;
pCid->tm_tc.T0 = pTimers->tc.T0;
pCid->tm_tc.T1 = pTimers->tc.T1;
pCid->tm_tc.T2 = pTimers->tc.T2;
pCid->tm_tc.t2_osi = pTimers->tc.t2_osi;
pCid->tm_tc.t2_W = pTimers->tc.t2_W;
pCid->tm_tc.t2_X = pTimers->tc.t2_X;
pCid->tm_tc.t2_X1 = pTimers->tc.t2_X1;
pCid->tm_tc.t2_Y = pTimers->tc.t2_Y;
pCid->tm_tc.t2_T1 = pTimers->tc.t2_T1;
pCid->tm_tc.t2_Q = pTimers->tc.t2_Q;
pCid->tm_tc.t2_S = pTimers->tc.t2_S;
}
else if (std == DXS_CID_STD_BT)
{
pCid->tm_bt.dtas = pTimers->bt.dtas;
pCid->tm_bt.T0 = pTimers->bt.T0;
pCid->tm_bt.T1 = pTimers->bt.T1;
pCid->tm_bt.T2 = pTimers->bt.T2;
pCid->tm_bt.t2_dtas = pTimers->bt.t2_dtas;
pCid->tm_bt.t2_ack = pTimers->bt.t2_ack;
pCid->tm_bt.t2_T0 = pTimers->bt.t2_T0;
pCid->tm_bt.t2_T1 = pTimers->bt.t2_T1;
pCid->tm_bt.t2_T2 = pTimers->bt.t2_T2;
}
else if (std == DXS_CID_STD_NTT)
{
pCid->tm_ntt.CARon = pTimers->ntt.CARon;
pCid->tm_ntt.CARoff = pTimers->ntt.CARoff;
pCid->tm_ntt.T0 = pTimers->ntt.T0;
pCid->tm_ntt.T1 = pTimers->ntt.T1;
pCid->tm_ntt.T2 = pTimers->ntt.T2;
pCid->tm_ntt.T3 = pTimers->ntt.T3;
pCid->tm_ntt.T4 = pTimers->ntt.T4;
pCid->tm_ntt.t2_as_first = pTimers->ntt.t2_as_first;
pCid->tm_ntt.t2_as_pause = pTimers->ntt.t2_as_pause;
pCid->tm_ntt.t2_as_second = pTimers->ntt.t2_as_second;
pCid->tm_ntt.t2_T0 = pTimers->ntt.t2_T0;
pCid->tm_ntt.t2_T1 = pTimers->ntt.t2_T1;
pCid->tm_ntt.t2_T2 = pTimers->ntt.t2_T2;
}
return DXS_statusOk;
}
/**
Update CId message
\param pCh - pointer to \ref DXS_CHANNEL_t
\param msg_type - message type \ref DXS_CID_MsgType_t
\param param - message parameter \ref DXS_CID_MsgParam_t
\param pData - message parameter data
\param length - message parameter data length
\return
- DXS_status_t
*/
int32_t DXS_CID_MsgUpdate(DXS_CHANNEL_t *pCh, DXS_CID_MsgType_t msg_type,
DXS_CID_MsgParam_t param, char *pData, uint8_t length)
{
uint32_t i, found = 0;
dxs_cid_message_t *pMsg, *p;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
/* check if pCid is initialized */
if (pCid->magic != DXS_CID_CTX_MAGIC)
{
DXS_RETURN(DXS_statusNotInitResource);
}
pMsg = dxs_cid_message_get(pCid, msg_type);
p = pMsg;
/* check if message parameter already exists */
while (p != NULL)
{
if (p->type == param)
{
found = 1;
break;
}
p = p->next;
}
if (found)
{
if (p->len != length)
{
p->data = realloc(p->data, length);
p->len = length;
}
if (pData != NULL)
{
for (i=0; i<length; i++)
{
if (p->data)
p->data[i] = *pData++;
}
}
}
else
{
dxs_cid_message_t *pMsgElem;
uint8_t updated_len = pCid->len_check(param, length);
/* allocate memory for the new element */
pMsgElem = calloc(1, sizeof(*pMsgElem));
if (pMsgElem == NULL)
return DXS_statusError;
pMsgElem->type = param;
/* update the length for malloc */
pMsgElem->data = malloc(updated_len);
if (pMsgElem->data == NULL)
{
free(pMsgElem);
return DXS_statusError;
}
if (pData != NULL)
{
for (i=0; i<updated_len; i++)
pMsgElem->data[i] = *pData++;
}
pMsgElem->len = updated_len;
pMsgElem->next = NULL;
/* add the new element to the bottom */
if (pMsg == NULL)
{
dxs_cid_message_set(pCid, msg_type, pMsgElem);
}
else
{
p = pMsg;
while (p->next != NULL)
p = p->next;
p->next = pMsgElem;
}
}
return DXS_statusOk;
}
/**
Clean all messages in CID context
\param pCh - pointer to \ref DXS_CHANNEL_t
\return
- DXS_status_t
*/
int32_t DXS_CID_MsgCleanup(DXS_CHANNEL_t *pCh)
{
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
/* check if pCid is initialized */
if (pCid->magic != DXS_CID_CTX_MAGIC)
{
DXS_RETURN(DXS_statusNotInitResource);
}
/* vipe all configured messages (if any) */
dxs_cid_msg_clearall(pCid);
return DXS_statusOk;
}
/**
Start CID TypeI message playout
\param pCh - pointer to \ref DXS_CHANNEL_t
\param msg_type - type of message to play \ref DXS_CID_MsgType_t
\return
- DXS_status_t
*/
int32_t DXS_CID_TypeI_Play(DXS_CHANNEL_t *pCh, DXS_CID_MsgType_t msg_type,
uint8_t calling_instance)
{
int32_t ret, line_mode = 0;
pthread_attr_t cid_thread_attr;
struct sched_param cid_thread_param;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
uint16_t unMarkBits, unSeizureBits;
if (pCid->magic != DXS_CID_CTX_MAGIC)
{
DXS_RETURN(DXS_statusNotInitResource);
}
if (!pCid->complete)
{
DXS_RETURN(DXS_statusCidInProgress);
}
pCid->calling_instance = calling_instance;
switch (pCid->std)
{
case DXS_CID_STD_BT:
{
if (pCid->as != DXS_CID_AS_LR_DTAS)
{
DXS_RETURN(DXS_statusCidInvalidAlertSignal);
}
unMarkBits = DXS_CID_FSK_BT_MARK_DEFAULT;
unSeizureBits = DXS_CID_FSK_SEIZURE_DEFAULT;
pCid->cid_state = dxs_cid_bt_init;
break;
}
case DXS_CID_STD_NTT:
{
if (pCid->as != DXS_CID_AS_CAR)
{
DXS_RETURN(DXS_statusCidInvalidAlertSignal);
}
unMarkBits = DXS_CID_FSK_MARK_DEFAULT;
unSeizureBits = 0;
pCid->cid_state = dxs_cid_ntt_init;
break;
}
case DXS_CID_STD_ETSI:
{
if ((pCid->as == DXS_CID_AS_CAR) || (pCid->as == DXS_CID_AS_OSI))
{
DXS_RETURN(DXS_statusCidInvalidAlertSignal);
}
unMarkBits = DXS_CID_FSK_MARK_DEFAULT;
unSeizureBits = DXS_CID_FSK_SEIZURE_DEFAULT;
if (pCid->calling_instance == DXS_CID_CALL_FROM_RING_SM &&
pCid->as == DXS_CID_AS_NONE)
{
pCid->cid_state = dxs_cid_etsi_ring;
}
else
{
pCid->cid_state = dxs_cid_etsi_init;
}
break;
}
case DXS_CID_STD_TELCORDIA:
{
if ((pCid->as != DXS_CID_AS_NONE) && (pCid->as != DXS_CID_AS_OSI))
{
DXS_RETURN(DXS_statusCidInvalidAlertSignal);
}
unMarkBits = DXS_CID_FSK_MARK_DEFAULT;
unSeizureBits = DXS_CID_FSK_SEIZURE_DEFAULT;
if (pCid->calling_instance == DXS_CID_CALL_FROM_RING_SM &&
pCid->as == DXS_CID_AS_NONE)
{
pCid->cid_state = dxs_cid_tc_alert;
}
else
{
pCid->cid_state = dxs_cid_tc_init;
}
break;
}
default:
{
DXS_RETURN(DXS_statusCidStdNotSupported);
}
}
/* set expected hook state */
pCid->hook_state_exp = DXS_CID_HOOK_STATE_ONHOOK;
/* do not block off-hook events */
pCid->hook_block = 0;
/* prepare message for transmission */
if (pCid->df == DXS_CID_DATA_FSK)
{
if (pCid->std == DXS_CID_STD_NTT)
ret = dxs_cid_fsk_buffer_prepare_ntt(pCid, msg_type);
else
ret = dxs_cid_fsk_buffer_prepare(pCid, msg_type);
if (ret)
{
DXS_RETURN(ret);
}
DXS_FSK_Configure(pCh, DXS_CID_FSK_LEVEL_DEFAULT,
unSeizureBits, unMarkBits);
}
else
{
dxs_cid_dtmf_buffer_prepare(pCid, msg_type);
}
/* Verify line mode and store the polarity */
ret = DXS_SDD_LineModeGet(pCh, &line_mode);
if (ret == DXS_statusOk)
{
switch (line_mode)
{
case DXS_LINE_FEED_STANDBY:
DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE);
pCid->polarity_initial = DXS_CID_LINE_MODE_POLARITY_FLAG_NORMAL;
break;
case DXS_LINE_FEED_ACTIVE:
pCid->polarity_initial = DXS_CID_LINE_MODE_POLARITY_FLAG_NORMAL;
break;
case DXS_LINE_FEED_ACTIVE_REVPOL:
pCid->polarity_initial = DXS_CID_LINE_MODE_POLARITY_FLAG_REVERSED;
break;
default:
/* Incorrect line feed mode */
DXS_RETURN(DXS_statusCidInvalidLineMode);
break;
}
/* TODO: verify that a telephone is on-hook */
/* Set on-hook */
pCid->hook_state = DXS_CID_HOOK_STATE_ONHOOK;
/* Set highest priority for CID thread handling */
pthread_attr_init(&cid_thread_attr);
cid_thread_param.sched_priority = sched_get_priority_max(SCHED_RR);
pthread_attr_setschedparam(&cid_thread_attr, &cid_thread_param);
pthread_attr_setschedpolicy(&cid_thread_attr, SCHED_RR);
/* roll it */
if (pthread_create(&pCid->thrd, &cid_thread_attr, dxs_cid_thread, (void *)pCh))
{
pthread_attr_destroy(&cid_thread_attr);
DXS_RETURN(DXS_statusThreadCreatError);
}
pthread_attr_destroy(&cid_thread_attr);
}
DXS_RETURN(ret);
}
/**
Start CID TypeII message playout
\param pCh - pointer to \ref DXS_CHANNEL_t
\param msg_type - type of message to play \ref DXS_CID_MsgType_t
\return
- DXS_status_t
*/
int32_t DXS_CID_TypeII_Play(DXS_CHANNEL_t *pCh, DXS_CID_MsgType_t msg_type)
{
int32_t ret, line_mode = 0;
pthread_attr_t cid_thread_attr;
struct sched_param cid_thread_param;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
uint16_t unMarkBits, unSeizureBits;
if (pCid->magic != DXS_CID_CTX_MAGIC)
{
DXS_RETURN(DXS_statusNotInitResource);
}
if (!pCid->complete)
{
DXS_RETURN(DXS_statusCidInProgress);
}
switch (pCid->std)
{
case DXS_CID_STD_BT:
{
unMarkBits = DXS_CID_FSK_BT_MARK_DEFAULT;
unSeizureBits = 0;
pCid->cid_state = dxs_cid_bt_type2_init;
break;
}
case DXS_CID_STD_NTT:
{
unMarkBits = DXS_CID_FSK_MARK_DEFAULT;
unSeizureBits = 0;
pCid->cid_state = dxs_cid_ntt_type2_init;
break;
}
case DXS_CID_STD_ETSI:
{
unMarkBits = DXS_CID_FSK_ETSI_TYPE2_MARK_DEFAULT;
unSeizureBits = 0;
pCid->cid_state = dxs_cid_etsi_type2_init;
break;
}
case DXS_CID_STD_TELCORDIA:
{
unMarkBits = DXS_CID_FSK_MARK_DEFAULT;
unSeizureBits = 0;
pCid->cid_state = dxs_cid_tc_type2_init;
break;
}
default:
{
DXS_RETURN(DXS_statusCidStdNotSupported);
}
}
/* set expected hook state */
pCid->hook_state_exp = DXS_CID_HOOK_STATE_OFFHOOK;
/* clear ACK detection */
pCid->ack_detect = 0;
/* do not block off-hook events */
pCid->hook_block = 0;
/* prepare message for transmission */
if (pCid->df == DXS_CID_DATA_FSK)
{
if (pCid->std == DXS_CID_STD_NTT)
ret = dxs_cid_fsk_buffer_prepare_ntt(pCid, msg_type);
else
ret = dxs_cid_fsk_buffer_prepare(pCid, msg_type);
if (ret)
{
DXS_RETURN(ret);
}
DXS_FSK_Configure(pCh, DXS_CID_FSK_LEVEL_DEFAULT,
unSeizureBits, unMarkBits);
}
else
{
dxs_cid_dtmf_buffer_prepare(pCid, msg_type);
}
/* Verify line mode and store the polarity */
ret = DXS_SDD_LineModeGet(pCh, &line_mode);
if (ret == DXS_statusOk)
{
switch (line_mode)
{
case DXS_LINE_FEED_ACTIVE:
pCid->polarity_initial = DXS_CID_LINE_MODE_POLARITY_FLAG_NORMAL;
break;
case DXS_LINE_FEED_ACTIVE_REVPOL:
pCid->polarity_initial = DXS_CID_LINE_MODE_POLARITY_FLAG_REVERSED;
break;
default:
/* Incorrect line feed mode */
DXS_RETURN(DXS_statusCidInvalidLineMode);
break;
}
/* TODO: verify that a telephone is off-hook */
/* Set off-hook flag */
pCid->hook_state = DXS_CID_HOOK_STATE_OFFHOOK;
/* Mute PCM channel */
if (dxs_pcm_ch_mute(pCh, 1) == DXS_statusOk)
pCid->need_unmute = 1;
/* Set highest priority for CID thread handling */
pthread_attr_init(&cid_thread_attr);
cid_thread_param.sched_priority = sched_get_priority_max(SCHED_RR);
pthread_attr_setschedparam(&cid_thread_attr, &cid_thread_param);
pthread_attr_setschedpolicy(&cid_thread_attr, SCHED_RR);
/* roll it */
if (pthread_create(&pCid->thrd, &cid_thread_attr, dxs_cid_thread, (void *)pCh))
{
pthread_attr_destroy(&cid_thread_attr);
DXS_RETURN(DXS_statusThreadCreatError);
}
pthread_attr_destroy(&cid_thread_attr);
}
DXS_RETURN(ret);
}
/**
Stop CID state machine
\param pCh - pointer to \ref DXS_CHANNEL_t
\return
- DXS_status_t
*/
int32_t DXS_CID_Stop(DXS_CHANNEL_t *pCh)
{
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
void *ret_status;
int32_t err;
if (!pCid->complete)
{
pCid->complete = 1;
/* attempt to terminate all possible states of CID sequence */
if (pCid->cid_state == dxs_cid_ntt_car_on)
{
/* Special case, need to stop ringing with the corresponded polarity */
DXS_SDD_LineModeSet(pCh,
DXS_LINE_FEED_ACTIVE_REVPOL ^ pCid->polarity_initial);
}
DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
DXS_CID_FSK_Stop(pCh);
dxs_tone_stop(pCh);
if (pCid->need_unmute)
dxs_pcm_ch_mute(pCh, 0);
sem_post(&pCid->sema);
/* wait for the thread to exit */
err = pthread_join (pCid->thrd, &ret_status);
if (err)
{
DXS_RETURN(DXS_statusThreadStopError);
}
}
return DXS_statusOk;
}
/**
Handle DTMF tone
\param pCh - pointer to \ref DXS_CHANNEL_t
\param pEvent - DXS_event_t data
\return
- uint_8
*/
uint8_t DXS_CID_EventDtmf(DXS_CHANNEL_t *pCh, DXS_Event_t *pEvent)
{
uint8_t ret = 1;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
if (!pCid->complete)
{
if (pCid->std == DXS_CID_STD_BT)
{
/* Check if dtmf event should not be reported to the app */
if (pCid->cid_state == dxs_cid_bt_type2_wait_ack)
{
if (pEvent->data.dtmf.digit == pCid->dtmf_ack_idx)
{
/* Set ack flag and wake up */
pCid->ack_detect = 1;
sem_post(&pCid->sema);
ret = 0;
}
}
}
else if (pCid->std == DXS_CID_STD_TELCORDIA)
{
/* Check if dtmf event should not be reported to the app */
if (pCid->cid_state == dxs_cid_tc_type2_wait_ack)
{
if (pEvent->data.dtmf.digit == pCid->dtmf_ack_idx)
{
/* Set ack flag and wake up */
pCid->ack_detect = 1;
sem_post(&pCid->sema);
ret = 0;
}
}
}
else if (pCid->std == DXS_CID_STD_ETSI)
{
/* Check if dtmf event should not be reported to the app */
if (pCid->cid_state == dxs_cid_etsi_type2_wait_ack)
{
if (pEvent->data.dtmf.digit == pCid->dtmf_ack_idx)
{
/* Set ack flag and wake up */
pCid->ack_detect = 1;
sem_post(&pCid->sema);
ret = 0;
}
}
}
}
return ret;
}
/**
Handle off-hook
\param pCh - pointer to \ref DXS_CHANNEL_t
\param timestamp - FW timestamp of hook event
\return
- uint_8
*/
uint8_t DXS_CID_EventOffhook(DXS_CHANNEL_t *pCh, uint16_t timestamp)
{
uint8_t ret = 1;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
if ((pCid->magic == DXS_CID_CTX_MAGIC) && (!pCid->complete))
{
if ((pCid->std == DXS_CID_STD_TELCORDIA) && (pCid->hook_block))
{
/* Hide first off-hook event at the end of OSI */
pCid->hook_block = 0;
ret = 0;
}
else
{
if (pCid->std == DXS_CID_STD_NTT)
{
/* Check if off-hook event should not be reported to the app */
if ((pCid->cid_state == dxs_cid_ntt_car_off) ||
(pCid->cid_state == dxs_cid_ntt_car_on))
ret = 0;
}
/* Set off-hook and wake up */
pCid->hook_state = DXS_CID_HOOK_STATE_OFFHOOK;
pCid->hook_timestamp = timestamp;
sem_post(&pCid->sema);
}
}
return ret;
}
#ifdef DXS_FEAT_HSM
/**
Handle OPC for disabled
\param pCh - pointer to \ref DXS_CHANNEL_t
\return
- uint_8
*/
uint8_t DXS_CID_EventOpcDisabled(DXS_CHANNEL_t *pCh)
{
uint8_t ret = 1;
DXS_CID_Ctx_t *pCid;
if (pCh != NULL)
{
if (pCh->pParent != NULL)
{
pCid = &cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
if ((pCid->magic == DXS_CID_CTX_MAGIC) && (!pCid->complete))
{
if ((pCid->std == DXS_CID_STD_TELCORDIA) &&
((pCid->cid_state == dxs_cid_tc_type2_osi_first) ||
(pCid->cid_state == dxs_cid_tc_type2_osi_last)))
{
/* Do not report OPC to HSM */
ret = 0;
}
}
}
}
return ret;
}
#endif
/**
Handle on-hook
\param pCh - pointer to \ref DXS_CHANNEL_t
\param timestamp - FW timestamp of hook event
\return
- uint_8
*/
uint8_t DXS_CID_EventOnhook(DXS_CHANNEL_t *pCh, uint16_t timestamp)
{
uint8_t ret = 1;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
if ((pCid->magic == DXS_CID_CTX_MAGIC) && (!pCid->complete))
{
if (pCid->std == DXS_CID_STD_NTT)
{
/* Check if on-hook event should not be reported to the app */
if (pCid->cid_state == dxs_cid_ntt_wait_onhook)
ret = 0;
}
/* Set on-hook and wake up */
pCid->hook_state = DXS_CID_HOOK_STATE_ONHOOK;
pCid->hook_timestamp = timestamp;
sem_post(&pCid->sema);
}
return ret;
}
/**
Handle FSK transmit complete
\param pCh - pointer to \ref DXS_CHANNEL_t
\return
- none
*/
void DXS_CID_FSK_SendComplete(DXS_CHANNEL_t *pCh)
{
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
sem_post(&pCid->sema);
}
/**
Handle FSK transmit error
\param pCh - pointer to \ref DXS_CHANNEL_t
\return
- none
*/
void DXS_CID_FSK_SendError(DXS_CHANNEL_t *pCh)
{
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
DXS_Event_t dxs_event = {0};
void *ret_status;
if (!pCid->complete)
{
pCid->complete = 1;
/* attempt to terminate all possible states of CID sequence */
DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_ACTIVE ^ pCid->polarity_initial);
DXS_CID_FSK_Stop(pCh);
dxs_tone_stop(pCh);
if (pCid->need_unmute)
dxs_pcm_ch_mute(pCh, 0);
sem_post(&pCid->sema);
/* wait for the thread to exit */
pthread_join (pCid->thrd, &ret_status);
}
/* inform application */
dxs_event.dev = pCh->pParent->nDevNum;
dxs_event.ch = pCh->nCh;
dxs_event.id = DXS_EVENT_CID_SEQ_ERROR;
dxs_event.data.cid_err = DXS_EVENT_CID_FSK_BUF;
DXS_EventDispatch(pCh->pParent, &dxs_event);
}
/**
Cleanup CID context
\param pCh - pointer to \ref DXS_CHANNEL_t
\return
- none
*/
void DXS_CID_Cleanup(DXS_CHANNEL_t *pCh)
{
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
pCid->magic = 0;
}
/**
Get CID sequence length in units of 50ms
\param pCh - pointer to \ref DXS_CHANNEL_t
\param pLen - pointer to CID sequence length (output)
\return
- DXS_status_t
*/
int32_t DXS_CID_LengthBitsGet(DXS_CHANNEL_t *pCh, int32_t *pLen)
{
int32_t cid_len_ms;
uint16_t fsk_buffer_bytes = 0;
dxs_cid_message_t *p, *pMsg;
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
/* check if pCid is initialized */
if (pCid->magic != DXS_CID_CTX_MAGIC)
{
DXS_RETURN(DXS_statusNotInitResource);
}
pMsg = dxs_cid_message_get(pCid, DXS_CID_MSG_TYPE_CS);
p = pMsg;
/* calculate total length for an FSK buffer */
while (p != NULL)
{
fsk_buffer_bytes += (p->len + 2); /* + parameter code + length byte */
p = p->next;
}
fsk_buffer_bytes += 3; /* + message type code + total length byte + checksum */
if (pCid->std == DXS_CID_STD_ETSI && pCid->as == DXS_CID_AS_NONE)
{
/* T5 + SEIZURE + MARK + FSK + T6 */
cid_len_ms = pCid->tm_etsi.T5 + pCid->tm_etsi.T6 +
(DXS_CID_FSK_SEIZURE_DEFAULT + DXS_CID_FSK_MARK_DEFAULT +
(fsk_buffer_bytes << 3)) * 1000 / DXS_CID_FSK_BITS_PER_SEC;
}
else if (pCid->std == DXS_CID_STD_ETSI && pCid->as == DXS_CID_AS_DTAS)
{
/* DTAS + T4 + SEIZ + MARK + FSK + T2 */
cid_len_ms = pCid->tm_etsi.dtas + pCid->tm_etsi.T4 + pCid->tm_etsi.T2 +
(DXS_CID_FSK_SEIZURE_DEFAULT + DXS_CID_FSK_MARK_DEFAULT +
(fsk_buffer_bytes << 3)) * 1000 / DXS_CID_FSK_BITS_PER_SEC;
}
else if (pCid->std == DXS_CID_STD_ETSI && pCid->as == DXS_CID_AS_RPAS)
{
/* RPAS + T3 + SEIZ + MARK + FSK + T2 */
cid_len_ms = pCid->tm_etsi.rpas + pCid->tm_etsi.T3 + pCid->tm_etsi.T2 +
(DXS_CID_FSK_SEIZURE_DEFAULT + DXS_CID_FSK_MARK_DEFAULT +
(fsk_buffer_bytes << 3)) * 1000 / DXS_CID_FSK_BITS_PER_SEC;
}
else if (pCid->std == DXS_CID_STD_ETSI && pCid->as == DXS_CID_AS_LR_DTAS)
{
/* assume LR=0 + T0 + DTAS + T1 + SEIZ + MARK + FSK + T2 */
cid_len_ms = pCid->tm_etsi.dtas +
pCid->tm_etsi.T0 + pCid->tm_etsi.T1 + pCid->tm_etsi.T2 +
(DXS_CID_FSK_SEIZURE_DEFAULT + DXS_CID_FSK_MARK_DEFAULT +
(fsk_buffer_bytes << 3)) * 1000 / DXS_CID_FSK_BITS_PER_SEC;
}
else if (pCid->std == DXS_CID_STD_TELCORDIA && pCid->as == DXS_CID_AS_NONE)
{
/* T0 + SEIZURE + MARK + FSK + T2 */
cid_len_ms = pCid->tm_tc.T0 + pCid->tm_tc.T2 +
(DXS_CID_FSK_SEIZURE_DEFAULT + DXS_CID_FSK_MARK_DEFAULT +
(fsk_buffer_bytes << 3)) * 1000 / DXS_CID_FSK_BITS_PER_SEC;
}
else if (pCid->std == DXS_CID_STD_TELCORDIA && pCid->as == DXS_CID_AS_OSI)
{
/* assume DISABLED=0 + timer OSI + T1 + SEIZ + MARK + FSK + T2 */
cid_len_ms = pCid->tm_tc.osi + pCid->tm_tc.T1 + pCid->tm_tc.T2 +
(DXS_CID_FSK_SEIZURE_DEFAULT + DXS_CID_FSK_MARK_DEFAULT +
(fsk_buffer_bytes << 3)) * 1000 / DXS_CID_FSK_BITS_PER_SEC;
}
else if (pCid->std == DXS_CID_STD_BT && pCid->as == DXS_CID_AS_LR_DTAS)
{
/* assume LR=0 + T0 + DTAS + T1 + SEIZ + MARK + FSK + T2 */
cid_len_ms = pCid->tm_bt.T0 + pCid->tm_bt.dtas + pCid->tm_bt.T1 +
pCid->tm_bt.T2 +
(DXS_CID_FSK_SEIZURE_DEFAULT + DXS_CID_FSK_BT_MARK_DEFAULT +
(fsk_buffer_bytes << 3)) * 1000 / DXS_CID_FSK_BITS_PER_SEC;
}
else
{
/* FIXME: NTT standard is
temporarily not supported */
*pLen = -1;
return DXS_statusOk;
}
*pLen = ((cid_len_ms + 25) / 50);
return DXS_statusOk;
}
/**
Get CID standard
\param pCh - pointer to \ref DXS_CHANNEL_t
\param pStd - pointer to CID standard (output)
\return
- DXS_status_t
*/
int32_t DXS_CID_StandardGet (DXS_CHANNEL_t *pCh, DXS_CID_Std_t *pStd)
{
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
/* check if pCid is initialized */
if (pCid->magic != DXS_CID_CTX_MAGIC)
{
DXS_RETURN(DXS_statusNotInitResource);
}
*pStd = pCid->std;
return DXS_statusOk;
}
/**
Get CID alert signal
\param pCh - pointer to \ref DXS_CHANNEL_t
\param pAsig - pointer to CID alert signal (output)
\return
- DXS_status_t
*/
int32_t DXS_CID_AlertSigGet (DXS_CHANNEL_t *pCh, DXS_CID_AS_t *pAsig)
{
DXS_CID_Ctx_t *pCid =
&cid_res[pCh->pParent->nDevNum * CH_PER_DEVICE + pCh->nCh];
/* check if pCid is initialized */
if (pCid->magic != DXS_CID_CTX_MAGIC)
{
DXS_RETURN(DXS_statusNotInitResource);
}
*pAsig = pCid->as;
return DXS_statusOk;
}
extern int SLICAPP_CID_Std;
int32_t dxsapi_cid_fsk_etsi_type2 (uint8_t dxs, uint8_t line, char *cid_cli)
{
int32_t ret = 0;
DXS_CID_Std_t std;
DXS_CID_AS_t as;
DXS_CID_DATA_FMT_t fmt;
uint8_t dtmf_ack_idx = 0;
struct tm tms = {0};
time_t rawtime;
uint8_t i = 0;
char timedate_buffer[8];
char cid_party_name[] = "CALLING";
/* select STD, format, ack DTMF digit */
std = SLICAPP_CID_Std;
fmt = DXS_CID_DATA_FSK;
as = DXS_CID_AS_NONE;
dtmf_ack_idx = 31; /* index DTMF digit */
ret = DxsCidInit(dxs, line, std, as, fmt, dtmf_ack_idx);
/* Prepare Call Setup message for device dev, channel line:
1) Add Calling Line ID parameter
2) Add Calling Party Name parameter
3) Add Date Time parameter */
ret = DxsCidMsgSetup(dxs, line,
DXS_CID_MSG_TYPE_CS,
DXS_CID_MSG_PARAM_CALLING_LINE_ID,
cid_cli,
strlen(cid_cli));
ret = DxsCidMsgSetup(dxs, line,
DXS_CID_MSG_TYPE_CS,
DXS_CID_MSG_PARAM_CALLING_PARTY_NAME,
cid_party_name,
strlen(cid_party_name));
/* Date and time */
rawtime = time(NULL);
localtime_r(&rawtime, &tms);
/* month */
timedate_buffer[i++] = (tms.tm_mon + 1) / 10 + '0';
timedate_buffer[i++] = (tms.tm_mon + 1) % 10 + '0';
/* day */
timedate_buffer[i++] = tms.tm_mday / 10 + '0';
timedate_buffer[i++] = tms.tm_mday % 10 + '0';
/* hour */
timedate_buffer[i++] = tms.tm_hour / 10 + '0';
timedate_buffer[i++] = tms.tm_hour % 10 + '0';
/* minute */
timedate_buffer[i++] = tms.tm_min / 10 + '0';
timedate_buffer[i++] = tms.tm_min % 10 + '0';
ret = DxsCidMsgSetup(dxs, line,
DXS_CID_MSG_TYPE_CS,
DXS_CID_MSG_PARAM_DATE_TIME,
timedate_buffer,
sizeof(timedate_buffer));
/* Transmit Type2 Call Setup message */
ret = DxsCidTypeIIMsgStart(dxs, line, DXS_CID_MSG_TYPE_CS);
return ret;
}
#endif /* DXS_FEAT_CID */