| /****************************************************************************** |
| |
| 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 */ |